mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-11 17:52:31 +03:00
feat(providers): integrate wave4 free-tier gateways
This commit is contained in:
@@ -254,6 +254,8 @@ 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";
|
||||
import { freeinferenceProvider } from "./registry/freeinference/index.ts";
|
||||
import { freeAiProvider } from "./registry/free-ai/index.ts";
|
||||
|
||||
export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
aimlapi: aimlapiProvider,
|
||||
@@ -509,4 +511,6 @@ export const REGISTRY: Record<string, RegistryEntry> = {
|
||||
"poixe-ai": poixeAiProvider,
|
||||
"naga-ai": nagaAiProvider,
|
||||
"chat-oripe": chatOripeProvider,
|
||||
freeinference: freeinferenceProvider,
|
||||
"free-ai": freeAiProvider,
|
||||
};
|
||||
|
||||
@@ -32,6 +32,8 @@ export const PROVIDER_ENDPOINTS = {
|
||||
"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",
|
||||
freeinference: "https://freeinference.org/v1/chat/completions",
|
||||
"free-ai": "https://api.free.ai/v1/chat/",
|
||||
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",
|
||||
|
||||
@@ -117,6 +117,8 @@ export const AGGREGATOR_PROVIDER_IDS = new Set([
|
||||
"poixe-ai",
|
||||
"naga-ai",
|
||||
"chat-oripe",
|
||||
"freeinference",
|
||||
"free-ai",
|
||||
]);
|
||||
|
||||
export const ENTERPRISE_CLOUD_PROVIDER_IDS = new Set([
|
||||
|
||||
@@ -454,6 +454,36 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
|
||||
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.",
|
||||
},
|
||||
freeinference: {
|
||||
id: "freeinference",
|
||||
alias: "freeinference",
|
||||
name: "FreeInference",
|
||||
icon: "science",
|
||||
color: "#8B5CF6",
|
||||
textIcon: "FI",
|
||||
passthroughModels: true,
|
||||
website: "https://freeinference.org",
|
||||
hasFree: true,
|
||||
freeNote:
|
||||
"Free research access without a card; non-Harvard applicants require manual approval and no numeric quota is publicly guaranteed.",
|
||||
apiHint:
|
||||
"Apply for a FreeInference key, then use https://freeinference.org/v1 as the OpenAI-compatible base URL. Terms allow prompt/response logging and possible publication of anonymized research data; never send sensitive or production data.",
|
||||
},
|
||||
"free-ai": {
|
||||
id: "free-ai",
|
||||
alias: "free-ai",
|
||||
name: "Free.ai",
|
||||
icon: "hub",
|
||||
color: "#16A34A",
|
||||
textIcon: "FA",
|
||||
passthroughModels: true,
|
||||
website: "https://free.ai",
|
||||
hasFree: true,
|
||||
freeNote:
|
||||
"30,000 tokens/day cover self-hosted models after email verification. Usage beyond the pool can bill at raw cost, and premium external models are paid.",
|
||||
apiHint:
|
||||
"Create an sk-free- key, then use the nonstandard but OpenAI-shaped https://api.free.ai/v1/chat/ endpoint. Select a self-hosted zero-price model to stay within the free pool.",
|
||||
},
|
||||
dgrid: {
|
||||
id: "dgrid",
|
||||
alias: "dgrid",
|
||||
|
||||
64
tests/unit/free-tier-providers-wave4-integration.test.ts
Normal file
64
tests/unit/free-tier-providers-wave4-integration.test.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import { deriveConfigFromRegistryModelsUrl } from "../../src/app/api/providers/[id]/models/discoveryConfig.ts";
|
||||
|
||||
const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts");
|
||||
const { DefaultExecutor, getExecutor, hasSpecializedExecutor } =
|
||||
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 = [
|
||||
["freeinference", "https://freeinference.org/v1/chat/completions"],
|
||||
["free-ai", "https://api.free.ai/v1/chat/"],
|
||||
] as const;
|
||||
|
||||
for (const [id, endpoint] of providers) {
|
||||
test(`${id} is fully wired without a specialized 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.equal(AGGREGATOR_PROVIDER_IDS.has(id), true);
|
||||
assert.equal(hasSpecializedExecutor(id), false);
|
||||
const executor = getExecutor(id);
|
||||
assert.ok(executor instanceof DefaultExecutor);
|
||||
assert.equal(executor.buildUrl("live-model", false), endpoint);
|
||||
assert.equal(isValidModel(id, "future/live-catalog-model"), true);
|
||||
assert.deepEqual(registry.models, []);
|
||||
});
|
||||
}
|
||||
|
||||
test("Wave 4 model discovery accepts both public catalog response envelopes", () => {
|
||||
const freeInferenceDiscovery = deriveConfigFromRegistryModelsUrl("freeinference");
|
||||
const freeAiDiscovery = deriveConfigFromRegistryModelsUrl("free-ai");
|
||||
|
||||
assert.ok(freeInferenceDiscovery);
|
||||
assert.ok(freeAiDiscovery);
|
||||
assert.deepEqual(freeInferenceDiscovery.parseResponse({ data: [{ id: "glm-5.1" }] }), [
|
||||
{ id: "glm-5.1" },
|
||||
]);
|
||||
assert.deepEqual(freeAiDiscovery.parseResponse({ models: [{ id: "qwen7b" }] }), [
|
||||
{ id: "qwen7b" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("Wave 4 metadata preserves approval, logging and overage warnings", () => {
|
||||
assert.match(APIKEY_PROVIDERS.freeinference.freeNote ?? "", /manual approval/i);
|
||||
assert.match(APIKEY_PROVIDERS.freeinference.apiHint ?? "", /logging/i);
|
||||
assert.match(APIKEY_PROVIDERS["free-ai"].freeNote ?? "", /30,000 tokens\/day/i);
|
||||
assert.match(APIKEY_PROVIDERS["free-ai"].freeNote ?? "", /premium external models are paid/i);
|
||||
assert.match(APIKEY_PROVIDERS["free-ai"].apiHint ?? "", /\/v1\/chat\//i);
|
||||
});
|
||||
Reference in New Issue
Block a user