mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
Add built-in provider registry entry for Agnes AI (agnes-ai.com), a permanently free OpenAI-compatible API by Sapiens AI. Models: - agnes-2.0-flash: 256K context, 64K output, thinking mode (reasoning_content), vision, tool calling - agnes-1.5-flash: 256K context, 64K output, vision The baseUrl uses the full /v1/chat/completions path. This is the standard pattern for registry entries (115 built-in providers use the same convention). The default executor's buildUrl() routes registry entries through normalizeOpenAIChatUrl(), which detects the existing /chat/completions suffix and returns the URL as-is without appending. Only openai-compatible-* connections (dashboard- added custom providers) unconditionally append the path. Specs verified against MODEL_CATALOG.md v2026.06.28 (github.com/AgnesAI-Labs/AgnesAI-Models) and live API testing at apihub.agnes-ai.com/v1 (2026-07-13). Fixes #5580 Signed-off-by: Minxi Hou <houminxi@gmail.com>
71 lines
2.9 KiB
TypeScript
71 lines
2.9 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
|
|
const { REGISTRY: providerRegistry } = await import("../../open-sse/config/providerRegistry.ts");
|
|
|
|
const AGNES_CHAT_URL = "https://apihub.agnes-ai.com/v1/chat/completions";
|
|
|
|
test("agnes is registered as an API-key provider with complete metadata", () => {
|
|
const entry = APIKEY_PROVIDERS.agnes;
|
|
assert.ok(entry, "APIKEY_PROVIDERS.agnes must be defined");
|
|
assert.equal(entry.id, "agnes");
|
|
assert.equal(entry.alias, "agnes");
|
|
assert.equal(entry.name, "Agnes AI");
|
|
assert.equal(entry.icon, "auto_awesome");
|
|
assert.equal(entry.color, "#10B981");
|
|
assert.equal(entry.textIcon, "AG");
|
|
assert.equal(entry.website, "https://agnes-ai.com");
|
|
assert.equal(entry.hasFree, true);
|
|
assert.ok(entry.freeNote, "freeNote must be defined");
|
|
assert.ok(entry.authHint, "authHint must be defined");
|
|
});
|
|
|
|
test("agnes registry entry uses OpenAI format with bearer API-key auth", () => {
|
|
const entry = providerRegistry.agnes;
|
|
assert.ok(entry, "providerRegistry.agnes must be defined");
|
|
assert.equal(entry.id, "agnes");
|
|
assert.equal(entry.format, "openai");
|
|
assert.equal(entry.executor, "default");
|
|
assert.equal(entry.authType, "apikey");
|
|
assert.equal(entry.authHeader, "bearer");
|
|
assert.equal(entry.baseUrl, AGNES_CHAT_URL);
|
|
});
|
|
|
|
test("agnes ships two models with correct capabilities", () => {
|
|
const entry = providerRegistry.agnes;
|
|
assert.equal(entry.models.length, 2, "must have 2 models");
|
|
|
|
const flash2 = entry.models.find((m) => m.id === "agnes-2.0-flash");
|
|
assert.ok(flash2, "agnes-2.0-flash must be defined");
|
|
assert.equal(flash2.contextLength, 524288);
|
|
assert.equal(flash2.maxOutputTokens, 65536);
|
|
assert.equal(flash2.supportsReasoning, true);
|
|
assert.equal(flash2.supportsVision, true);
|
|
assert.equal(flash2.toolCalling, true);
|
|
assert.equal(flash2.interleavedField, "reasoning_content");
|
|
|
|
const flash15 = entry.models.find((m) => m.id === "agnes-1.5-flash");
|
|
assert.ok(flash15, "agnes-1.5-flash must be defined");
|
|
assert.equal(flash15.contextLength, 262144);
|
|
assert.equal(flash15.maxOutputTokens, 65536);
|
|
assert.equal(flash15.supportsVision, true);
|
|
assert.equal(flash15.supportsReasoning, undefined, "1.5-flash has no thinking mode");
|
|
assert.equal(flash15.toolCalling, undefined, "1.5-flash has no documented tool calling");
|
|
});
|
|
|
|
test("agnes has no collision with zenmux-free sapiens-ai prefixed models", (t) => {
|
|
const zenmux = providerRegistry["zenmux-free"];
|
|
if (!zenmux) {
|
|
t.skip("zenmux-free not registered in this environment");
|
|
return;
|
|
}
|
|
const agnesInZenmux = zenmux.models.filter((m) => m.id.includes("agnes"));
|
|
for (const m of agnesInZenmux) {
|
|
assert.ok(
|
|
m.id.startsWith("sapiens-ai/"),
|
|
`zenmux agnes model ${m.id} must use sapiens-ai/ prefix to avoid collision`
|
|
);
|
|
}
|
|
});
|