feat(providers): integrate wave2 free-tier gateways

This commit is contained in:
diegosouzapw
2026-08-02 01:52:26 -03:00
parent 8b55e61bdb
commit e7b5e1870f
5 changed files with 241 additions and 10 deletions

View File

@@ -229,6 +229,15 @@ import { anyapiProvider } from "./registry/anyapi/index.ts";
import { electronhubProvider } from "./registry/electronhub/index.ts";
import { llmgatewayProvider } from "./registry/llmgateway/index.ts";
import { llmKiwiProvider } from "./registry/llm-kiwi/index.ts";
import { literouterProvider } from "./registry/literouter/index.ts";
import { mnnAiProvider } from "./registry/mnn-ai/index.ts";
import { meganovaAiProvider } from "./registry/meganova-ai/index.ts";
import { mixlayerProvider } from "./registry/mixlayer/index.ts";
import { spekaProvider } from "./registry/speka/index.ts";
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";
export const REGISTRY: Record<string, RegistryEntry> = {
aimlapi: aimlapiProvider,
@@ -460,4 +469,13 @@ export const REGISTRY: Record<string, RegistryEntry> = {
electronhub: electronhubProvider,
llmgateway: llmgatewayProvider,
"llm-kiwi": llmKiwiProvider,
literouter: literouterProvider,
"mnn-ai": mnnAiProvider,
"meganova-ai": meganovaAiProvider,
mixlayer: mixlayerProvider,
speka: spekaProvider,
tokenreply: tokenreplyProvider,
"yolo-auto": yoloAutoProvider,
dxnt: dxntProvider,
"cloudcode-one": cloudcodeOneProvider,
};

View File

@@ -15,6 +15,15 @@ export const PROVIDER_ENDPOINTS = {
electronhub: "https://api.electronhub.ai/v1/chat/completions",
llmgateway: "https://api.llmgateway.io/v1/chat/completions",
"llm-kiwi": "https://api.llm.kiwi/v1/chat/completions",
literouter: "https://api.literouter.com/v1/chat/completions",
"mnn-ai": "https://api.mnnai.ru/v1/chat/completions",
"meganova-ai": "https://api.meganova.ai/v1/chat/completions",
mixlayer: "https://models.mixlayer.ai/v1/chat/completions",
speka: "https://speka.me/v1/chat/completions",
tokenreply: "https://api.tokenreply.com/v1/chat/completions",
"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",
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",

View File

@@ -94,6 +94,15 @@ export const AGGREGATOR_PROVIDER_IDS = new Set([
"electronhub",
"llmgateway",
"llm-kiwi",
"literouter",
"mnn-ai",
"meganova-ai",
"mixlayer",
"speka",
"tokenreply",
"yolo-auto",
"dxnt",
"cloudcode-one",
]);
export const ENTERPRISE_CLOUD_PROVIDER_IDS = new Set([

View File

@@ -189,6 +189,140 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
apiHint:
"Create a free LLM.Kiwi key, then use https://api.llm.kiwi/v1 as the OpenAI-compatible base URL.",
},
literouter: {
id: "literouter",
alias: "literouter",
name: "LiteRouter",
icon: "router",
color: "#2563EB",
textIcon: "LR",
passthroughModels: true,
website: "https://literouter.com",
hasFree: true,
freeNote:
"Free model variants use the :free suffix; daily credit limits vary by model and free input is capped at 5,000 tokens.",
apiHint:
"Create a LiteRouter API key, then use https://api.literouter.com/v1 as the OpenAI-compatible base URL.",
},
"mnn-ai": {
id: "mnn-ai",
alias: "mnn-ai",
name: "MNN AI",
icon: "hub",
color: "#0F766E",
textIcon: "MNN",
passthroughModels: true,
website: "https://mnnai.ru",
hasFree: true,
freeNote: "Free plan: $1 monthly credits, 10 RPM and access only to models marked Free.",
apiHint:
"Create an MNN AI API key, then use the primary https://api.mnnai.ru/v1 OpenAI-compatible endpoint. Review jurisdiction, privacy and regional data-transfer requirements before use.",
},
"meganova-ai": {
id: "meganova-ai",
alias: "meganova-ai",
name: "MegaNova AI",
icon: "router",
color: "#7C3AED",
textIcon: "MN",
passthroughModels: true,
website: "https://meganova.ai",
hasFree: true,
freeNote:
"Free signup without a card. Published Tier 1 per-model quotas total 550 requests/day; they are not a shared global pool, and paid overage can apply if enabled.",
apiHint:
"Create a MegaNova API key, then use https://api.meganova.ai/v1 as the OpenAI-compatible base URL.",
},
mixlayer: {
id: "mixlayer",
alias: "mixlayer",
name: "Mixlayer",
icon: "router",
color: "#0EA5E9",
textIcon: "MX",
passthroughModels: true,
website: "https://www.mixlayer.com",
hasFree: true,
freeNote:
"The qwen/qwen3.5-4b-free model is free for prototyping and rate-limited; no fixed public RPM or daily quota is confirmed.",
apiHint:
"Create a Mixlayer API key, then use https://models.mixlayer.ai/v1 as the OpenAI-compatible base URL.",
},
speka: {
id: "speka",
alias: "speka",
name: "Speka AI",
icon: "router",
color: "#DB2777",
textIcon: "SP",
passthroughModels: true,
website: "https://speka.me",
hasFree: true,
freeNote:
"Free plan: $1 monthly usage, 10 RPM, one API key and access to open models and the playground; no card required.",
apiHint:
"Create a Speka API key, then use https://speka.me/v1 as the OpenAI-compatible base URL. Confirm current model availability and overage settings before use.",
},
tokenreply: {
id: "tokenreply",
alias: "tokenreply",
name: "TokenReply",
icon: "router",
color: "#3B82F6",
textIcon: "TR",
passthroughModels: true,
website: "https://www.tokenreply.com",
hasFree: true,
freeNote:
"Free-tagged models have model- and campaign-specific daily limits; no fixed global free quota is published.",
apiHint:
"Create a TokenReply token, then use https://api.tokenreply.com/v1 as the OpenAI-compatible base URL and confirm the selected model's current limit.",
},
"yolo-auto": {
id: "yolo-auto",
alias: "yolo-auto",
name: "Yolo-Auto",
icon: "auto_awesome",
color: "#F59E0B",
textIcon: "YA",
passthroughModels: true,
website: "https://yolo-auto.com",
hasFree: true,
freeNote:
"Free API access is request-limited and intended for testing; no numeric daily quota is published and free access is not promised indefinitely.",
apiHint:
"Create a yolo_ API key, then use https://yolo-auto.com/v1 as the OpenAI-compatible base URL.",
},
dxnt: {
id: "dxnt",
alias: "dxnt",
name: "DXNT / DX Token",
icon: "hub",
color: "#111827",
textIcon: "DX",
passthroughModels: true,
website: "https://www.dxnt.com",
hasFree: true,
freeNote:
"Free accounts are documented at 100 calls/day; the quota may increase through invitations and can vary by account.",
apiHint:
"Create a DXNT API key, then use https://www.dxnt.com/v1 as the OpenAI-compatible base URL.",
},
"cloudcode-one": {
id: "cloudcode-one",
alias: "cloudcode-one",
name: "CloudCode.ONE",
icon: "router",
color: "#6366F1",
textIcon: "CC",
passthroughModels: true,
website: "https://cloudcode.one",
hasFree: true,
freeNote:
"Published free models include glm-4.7-flash and glm-4.6v-flash; no numeric quota is published, and key creation may require credit or a coupon.",
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.",
},
dgrid: {
id: "dgrid",
alias: "dgrid",
@@ -400,8 +534,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
textIcon: "G4F",
website: "https://g4f.space",
hasFree: true,
freeNote:
"Free no-key reverse proxy to Groq (gpt4free project) — rate-limited to 5 req/min.",
freeNote: "Free no-key reverse proxy to Groq (gpt4free project) — rate-limited to 5 req/min.",
passthroughModels: true,
authHint:
"No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits.",
@@ -415,8 +548,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
textIcon: "G4F",
website: "https://g4f.space",
hasFree: true,
freeNote:
"Free no-key reverse proxy to Gemini (gpt4free project) — rate-limited to 5 req/min.",
freeNote: "Free no-key reverse proxy to Gemini (gpt4free project) — rate-limited to 5 req/min.",
passthroughModels: true,
authHint:
"No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits.",
@@ -445,8 +577,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
textIcon: "G4F",
website: "https://g4f.space",
hasFree: true,
freeNote:
"Free no-key hosted Ollama gateway (gpt4free project) — rate-limited to 5 req/min.",
freeNote: "Free no-key hosted Ollama gateway (gpt4free project) — rate-limited to 5 req/min.",
passthroughModels: true,
authHint:
"No auth required. Free tier is limited to 5 requests/minute — sign up at g4f.dev/members.html for higher limits.",
@@ -864,7 +995,8 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
website: "https://ainative.studio",
hasFree: true,
freeNote: "Free tier ~10M tokens/month (claimed) across Qwen3, Llama 4, DeepSeek R1 and more.",
authHint: "Create a free API key at ainative.studio (no card), then paste it here as a Bearer token.",
authHint:
"Create a free API key at ainative.studio (no card), then paste it here as a Bearer token.",
apiHint:
"OpenAI-compatible endpoint at https://api.ainative.studio/api/v1 with a public /models catalog (84 models). OmniRoute lists models via passthrough.",
},
@@ -879,7 +1011,8 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
website: "https://www.aionlabs.ai",
hasFree: true,
freeNote: "Free tier ~20k tokens/day across the Aion reasoning models.",
authHint: "Create a free API key at aionlabs.ai (no card), then paste it here as a Bearer token.",
authHint:
"Create a free API key at aionlabs.ai (no card), then paste it here as a Bearer token.",
apiHint:
"OpenAI-compatible endpoint at https://api.aionlabs.ai/v1 with a public /models catalog carrying context and pricing.",
},
@@ -893,7 +1026,8 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
passthroughModels: true,
website: "https://routeway.ai",
hasFree: true,
freeNote: "Free models (:free suffix) at ~5 RPM / 200 RPD across Llama, Nemotron, Step and Laguna.",
freeNote:
"Free models (:free suffix) at ~5 RPM / 200 RPD across Llama, Nemotron, Step and Laguna.",
authHint: "Create a free API key at routeway.ai, then paste it here as a Bearer token.",
apiHint:
"OpenAI-compatible endpoint at https://api.routeway.ai/v1 with a public /models catalog (236 models). Cloudflare fronts the API and requires a browser-style User-Agent.",
@@ -909,7 +1043,8 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
website: "https://bynara.id",
hasFree: true,
freeNote: "Free tier is a shared 5M tokens/day pool; some models are gated behind credit/plan.",
authHint: "Get a free API key via NaraRouter's Telegram channel, then paste it here as a Bearer token.",
authHint:
"Get a free API key via NaraRouter's Telegram channel, then paste it here as a Bearer token.",
apiHint:
"OpenAI-compatible endpoint at https://router.bynara.id/v1. Free-tier models are pinned; others need credit.",
},

View File

@@ -0,0 +1,60 @@
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 = [
["literouter", "https://api.literouter.com/v1/chat/completions", []],
["mnn-ai", "https://api.mnnai.ru/v1/chat/completions", []],
["meganova-ai", "https://api.meganova.ai/v1/chat/completions", []],
["mixlayer", "https://models.mixlayer.ai/v1/chat/completions", ["qwen/qwen3.5-4b-free"]],
["speka", "https://speka.me/v1/chat/completions", []],
["tokenreply", "https://api.tokenreply.com/v1/chat/completions", []],
["yolo-auto", "https://yolo-auto.com/v1/chat/completions", ["qwen3.6-35b-a3b"]],
["dxnt", "https://www.dxnt.com/v1/chat/completions", []],
[
"cloudcode-one",
"https://api.cloudcode.one/v1/chat/completions",
["glm-4.7-flash", "glm-4.6v-flash"],
],
] as const;
for (const [id, endpoint, modelIds] 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.map((model) => model.id),
modelIds
);
});
}
test("risk-sensitive metadata preserves the audited quota qualifications", () => {
assert.match(APIKEY_PROVIDERS["mnn-ai"].apiHint ?? "", /jurisdiction.*privacy/i);
assert.match(APIKEY_PROVIDERS["meganova-ai"].freeNote ?? "", /per-model quotas/i);
assert.match(APIKEY_PROVIDERS["meganova-ai"].freeNote ?? "", /paid overage/i);
assert.match(APIKEY_PROVIDERS.tokenreply.freeNote ?? "", /no fixed global free quota/i);
assert.match(APIKEY_PROVIDERS["yolo-auto"].freeNote ?? "", /no numeric daily quota/i);
assert.match(APIKEY_PROVIDERS["cloudcode-one"].freeNote ?? "", /credit or a coupon/i);
});