diff --git a/open-sse/config/providers/index.ts b/open-sse/config/providers/index.ts index 21977d2585..5b4f77f311 100644 --- a/open-sse/config/providers/index.ts +++ b/open-sse/config/providers/index.ts @@ -245,6 +245,14 @@ import { tokenreplyProvider } from "./registry/tokenreply/index.ts"; import { yoloAutoProvider } from "./registry/yolo-auto/index.ts"; import { dxntProvider } from "./registry/dxnt/index.ts"; import { cloudcodeOneProvider } from "./registry/cloudcode-one/index.ts"; +import { ofoxaiProvider } from "./registry/ofoxai/index.ts"; +import { zerolimitaiProvider } from "./registry/zerolimitai/index.ts"; +import { chatanywhereProvider } from "./registry/chatanywhere/index.ts"; +import { helyxaiProvider } from "./registry/helyxai/index.ts"; +import { aurikoProvider } from "./registry/auriko/index.ts"; +import { poixeAiProvider } from "./registry/poixe-ai/index.ts"; +import { nagaAiProvider } from "./registry/naga-ai/index.ts"; +import { chatOripeProvider } from "./registry/chat-oripe/index.ts"; export const REGISTRY: Record = { aimlapi: aimlapiProvider, @@ -492,4 +500,12 @@ export const REGISTRY: Record = { "yolo-auto": yoloAutoProvider, dxnt: dxntProvider, "cloudcode-one": cloudcodeOneProvider, + ofoxai: ofoxaiProvider, + zerolimitai: zerolimitaiProvider, + chatanywhere: chatanywhereProvider, + helyxai: helyxaiProvider, + auriko: aurikoProvider, + "poixe-ai": poixeAiProvider, + "naga-ai": nagaAiProvider, + "chat-oripe": chatOripeProvider, }; diff --git a/src/shared/constants/config.ts b/src/shared/constants/config.ts index 0b5a7c4b14..935820b9ff 100644 --- a/src/shared/constants/config.ts +++ b/src/shared/constants/config.ts @@ -24,6 +24,14 @@ export const PROVIDER_ENDPOINTS = { "yolo-auto": "https://yolo-auto.com/v1/chat/completions", dxnt: "https://www.dxnt.com/v1/chat/completions", "cloudcode-one": "https://api.cloudcode.one/v1/chat/completions", + ofoxai: "https://api.ofox.ai/v1/chat/completions", + zerolimitai: "https://www.zerolimitai.com/api/v1/chat/completions", + chatanywhere: "https://api.chatanywhere.org/v1/chat/completions", + helyxai: "https://helyxai.space/v1/chat/completions", + auriko: "https://api.auriko.ai/v1/chat/completions", + "poixe-ai": "https://api.poixe.com/v1/chat/completions", + "naga-ai": "https://api.naga.ac/v1/chat/completions", + "chat-oripe": "https://api.oriper.com/v1/chat/completions", glm: "https://api.z.ai/api/anthropic/v1/messages", glmt: "https://api.z.ai/api/anthropic/v1/messages", "bailian-coding-plan": "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1/messages", diff --git a/src/shared/constants/providers.ts b/src/shared/constants/providers.ts index 8a6cc6decf..5fc2cb7721 100644 --- a/src/shared/constants/providers.ts +++ b/src/shared/constants/providers.ts @@ -109,6 +109,14 @@ export const AGGREGATOR_PROVIDER_IDS = new Set([ "yolo-auto", "dxnt", "cloudcode-one", + "ofoxai", + "zerolimitai", + "chatanywhere", + "helyxai", + "auriko", + "poixe-ai", + "naga-ai", + "chat-oripe", ]); export const ENTERPRISE_CLOUD_PROVIDER_IDS = new Set([ diff --git a/src/shared/constants/providers/apikey/gateways.ts b/src/shared/constants/providers/apikey/gateways.ts index f3121a67d9..181f995357 100644 --- a/src/shared/constants/providers/apikey/gateways.ts +++ b/src/shared/constants/providers/apikey/gateways.ts @@ -334,6 +334,126 @@ export const APIKEY_PROVIDERS_GATEWAYS = { apiHint: "Create a CloudCode.ONE key, then use https://api.cloudcode.one/v1 as the OpenAI-compatible base URL. Key issuance may require credit or a coupon.", }, + ofoxai: { + id: "ofoxai", + alias: "ofoxai", + name: "OfoxAI", + icon: "router", + color: "#0F766E", + textIcon: "OF", + passthroughModels: true, + website: "https://ofox.ai", + hasFree: true, + freeNote: + "The current catalog advertises 10+ free models without a public numeric quota; review upstream provenance, retention and training terms before production use.", + apiHint: + "Create an OfoxAI Bearer key, then use https://api.ofox.ai/v1 as the OpenAI-compatible base URL. This integration covers the OpenAI surface only.", + }, + zerolimitai: { + id: "zerolimitai", + alias: "zerolimitai", + name: "ZeroLimitAI", + icon: "router", + color: "#475569", + textIcon: "ZL", + passthroughModels: true, + website: "https://www.zerolimitai.com", + hasFree: true, + freeNote: + "Temporary free trial is advertised, but official pages conflict between 3 and 7 days; a 100-calls/day claim is not treated as permanent.", + apiHint: + "Create a ZeroLimitAI Bearer token, then use https://www.zerolimitai.com/api/v1 as the OpenAI-compatible base URL.", + }, + chatanywhere: { + id: "chatanywhere", + alias: "chatanywhere", + name: "ChatAnywhere", + icon: "router", + color: "#2563EB", + textIcon: "CA", + passthroughModels: true, + website: "https://chatanywhere.tech", + hasFree: true, + freeNote: + "Personal, educational or research use only: public documentation cites 10,000 points/day and 200 requests/day per IP/key; do not use for commercial traffic.", + apiHint: + "Create a ChatAnywhere key linked to GitHub, then use https://api.chatanywhere.org/v1 outside China. Review the non-commercial terms before enabling it.", + }, + helyxai: { + id: "helyxai", + alias: "helyxai", + name: "Helyx AI", + icon: "hub", + color: "#7C3AED", + textIcon: "HX", + passthroughModels: true, + website: "https://helyxai.space", + hasFree: true, + freeNote: + "Operational Free plan documents 100,000 tokens/day; the site's separate 2M+ marketing claim conflicts and is not treated as a quota guarantee.", + apiHint: + "Create a Helyx AI Bearer key, then use https://helyxai.space/v1 as the OpenAI-compatible base URL. Review terms and data retention first.", + }, + auriko: { + id: "auriko", + alias: "auriko", + name: "Auriko", + icon: "hub", + color: "#0891B2", + textIcon: "AU", + passthroughModels: true, + website: "https://www.auriko.ai", + hasFree: true, + freeNote: + "Free plan publishes 1,000 Platform RPM and 10,000 BYOK RPM. Platform inference still passes through provider cost; this is not a free-token pool or unlimited free inference.", + apiHint: + "Create an Auriko key with the ak_ prefix, then use https://api.auriko.ai/v1 as the OpenAI-compatible base URL. BYOK and platform credits have different cost semantics.", + }, + "poixe-ai": { + id: "poixe-ai", + alias: "poixe-ai", + name: "Poixe AI", + icon: "router", + color: "#EA580C", + textIcon: "PX", + passthroughModels: true, + website: "https://poixe.com", + hasFree: true, + freeNote: + "Current public free limits are small and model-group specific: 2 RPM/5 RPD for large-cup models and 20 RPM/50 RPD for small-cup models.", + apiHint: + "Create a Poixe Bearer key, then use https://api.poixe.com/v1 as the OpenAI-compatible base URL. Treat free model provenance and regional availability as experimental.", + }, + "naga-ai": { + id: "naga-ai", + alias: "naga-ai", + name: "Naga AI", + icon: "router", + color: "#059669", + textIcon: "NA", + passthroughModels: true, + website: "https://naga.ac", + hasFree: true, + freeNote: + "Models marked :free are publicly listed, but no numeric quota is confirmed. Naga's policy warns that free-tier prompts and outputs may be collected or used for training.", + apiHint: + "Create a Naga AI Bearer key, then use https://api.naga.ac/v1 as the OpenAI-compatible base URL. Never send sensitive data to the free tier without accepting its training policy.", + }, + "chat-oripe": { + id: "chat-oripe", + alias: "chat-oripe", + name: "Chat Oripe", + icon: "router", + color: "#64748B", + textIcon: "CO", + passthroughModels: true, + website: "https://api.oriper.com", + hasFree: true, + freeNote: + "Official metadata advertises 2M tokens/month, but the public site and documentation were blocked during audit; treat the quota and brand mapping as unconfirmed.", + apiHint: + "Use https://api.oriper.com/v1 only after confirming the provider's current documentation, terms and key issuance. No quota is guaranteed by this catalog.", + }, dgrid: { id: "dgrid", alias: "dgrid", diff --git a/tests/unit/free-tier-providers-wave3-integration.test.ts b/tests/unit/free-tier-providers-wave3-integration.test.ts new file mode 100644 index 0000000000..ec8ae79cf3 --- /dev/null +++ b/tests/unit/free-tier-providers-wave3-integration.test.ts @@ -0,0 +1,53 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts"); +const { DefaultExecutor, getExecutor } = await import("../../open-sse/executors/index.ts"); +const { PROVIDER_ENDPOINTS } = await import("../../src/shared/constants/config.ts"); +const { isValidModel } = await import("../../src/shared/constants/models.ts"); +const { AGGREGATOR_PROVIDER_IDS } = await import("../../src/shared/constants/providers.ts"); +const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers/apikey/index.ts"); + +const providers = [ + ["ofoxai", "https://api.ofox.ai/v1/chat/completions"], + ["zerolimitai", "https://www.zerolimitai.com/api/v1/chat/completions"], + ["chatanywhere", "https://api.chatanywhere.org/v1/chat/completions"], + ["helyxai", "https://helyxai.space/v1/chat/completions"], + ["auriko", "https://api.auriko.ai/v1/chat/completions"], + ["poixe-ai", "https://api.poixe.com/v1/chat/completions"], + ["naga-ai", "https://api.naga.ac/v1/chat/completions"], + ["chat-oripe", "https://api.oriper.com/v1/chat/completions"], +] as const; + +for (const [id, endpoint] of providers) { + test(`${id} is wired through registry, metadata, endpoint and default executor`, () => { + const registry = REGISTRY[id]; + const metadata = APIKEY_PROVIDERS[id]; + + assert.ok(registry); + assert.ok(metadata); + assert.equal(registry.id, id); + assert.equal(registry.alias, id); + assert.equal(registry.baseUrl, endpoint); + assert.equal(PROVIDER_ENDPOINTS[id], endpoint); + assert.equal(metadata.id, id); + assert.equal(metadata.alias, id); + assert.equal(metadata.hasFree, true); + assert.equal(metadata.passthroughModels, true); + assert.ok(typeof metadata.freeNote === "string" && metadata.freeNote.length > 0); + assert.equal(AGGREGATOR_PROVIDER_IDS.has(id), true); + assert.ok(getExecutor(id) instanceof DefaultExecutor); + assert.equal(isValidModel(id, "future/live-catalog-model"), true); + assert.deepEqual(registry.models, []); + }); +} + +test("Wave 3 metadata preserves the audited legal, quota and privacy warnings", () => { + assert.match(APIKEY_PROVIDERS.chatanywhere.freeNote ?? "", /commercial traffic/i); + assert.match(APIKEY_PROVIDERS.zerolimitai.freeNote ?? "", /3 and 7 days/i); + assert.match(APIKEY_PROVIDERS.helyxai.freeNote ?? "", /100,000 tokens\/day/i); + assert.match(APIKEY_PROVIDERS.auriko.freeNote ?? "", /not a free-token pool/i); + assert.match(APIKEY_PROVIDERS["poixe-ai"].freeNote ?? "", /2 RPM\/5 RPD/i); + assert.match(APIKEY_PROVIDERS["naga-ai"].freeNote ?? "", /training/i); + assert.match(APIKEY_PROVIDERS["chat-oripe"].freeNote ?? "", /unconfirmed/i); +});