mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
Integrated into release/v3.8.17
This commit is contained in:
@@ -4318,6 +4318,92 @@ const _REGISTRY_EAGER: Record<string, RegistryEntry> = {
|
||||
],
|
||||
},
|
||||
|
||||
zenmux: {
|
||||
id: "zenmux",
|
||||
alias: "zm",
|
||||
format: "openai",
|
||||
executor: "default",
|
||||
baseUrl: "https://zenmux.ai/api/v1/chat/completions",
|
||||
modelsUrl: "https://zenmux.ai/api/v1/models",
|
||||
authType: "apikey",
|
||||
authHeader: "bearer",
|
||||
defaultContextLength: 128000,
|
||||
models: [
|
||||
{
|
||||
id: "google/gemini-3.1-pro-preview",
|
||||
name: "Gemini 3.1 Pro Preview (ZenMux)",
|
||||
contextLength: 1048576,
|
||||
supportsVision: true,
|
||||
toolCalling: true,
|
||||
supportsReasoning: true,
|
||||
},
|
||||
{
|
||||
id: "google/gemini-3-flash-preview",
|
||||
name: "Gemini 3 Flash Preview (ZenMux)",
|
||||
contextLength: 1048576,
|
||||
supportsVision: true,
|
||||
toolCalling: true,
|
||||
supportsReasoning: true,
|
||||
},
|
||||
{
|
||||
id: "openai/gpt-5",
|
||||
name: "GPT-5 (ZenMux)",
|
||||
contextLength: 400000,
|
||||
supportsVision: true,
|
||||
toolCalling: true,
|
||||
supportsReasoning: true,
|
||||
},
|
||||
{
|
||||
id: "anthropic/claude-sonnet-4.5",
|
||||
name: "Claude Sonnet 4.5 (ZenMux)",
|
||||
contextLength: 200000,
|
||||
supportsVision: true,
|
||||
toolCalling: true,
|
||||
supportsReasoning: true,
|
||||
},
|
||||
{
|
||||
id: "anthropic/claude-opus-4.5",
|
||||
name: "Claude Opus 4.5 (ZenMux)",
|
||||
contextLength: 200000,
|
||||
supportsVision: true,
|
||||
toolCalling: true,
|
||||
supportsReasoning: true,
|
||||
},
|
||||
{
|
||||
id: "deepseek/deepseek-chat",
|
||||
name: "DeepSeek V3.2 Chat (ZenMux)",
|
||||
contextLength: 128000,
|
||||
supportsVision: false,
|
||||
toolCalling: true,
|
||||
supportsReasoning: false,
|
||||
},
|
||||
{
|
||||
id: "x-ai/grok-4.1-fast",
|
||||
name: "Grok 4.1 Fast (ZenMux)",
|
||||
contextLength: 131072,
|
||||
supportsVision: false,
|
||||
toolCalling: true,
|
||||
supportsReasoning: true,
|
||||
},
|
||||
{
|
||||
id: "mistralai/mistral-large-2512",
|
||||
name: "Mistral Large 2512 (ZenMux)",
|
||||
contextLength: 128000,
|
||||
supportsVision: true,
|
||||
toolCalling: true,
|
||||
supportsReasoning: false,
|
||||
},
|
||||
{
|
||||
id: "z-ai/glm-4.6v-flash",
|
||||
name: "GLM 4.6V Flash (ZenMux)",
|
||||
contextLength: 128000,
|
||||
supportsVision: true,
|
||||
toolCalling: true,
|
||||
supportsReasoning: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
theoldllm: {
|
||||
id: "theoldllm",
|
||||
alias: "tllm",
|
||||
|
||||
@@ -29,6 +29,7 @@ export const PROVIDER_ENDPOINTS = {
|
||||
minimax: "https://api.minimax.io/anthropic/v1/messages",
|
||||
"minimax-cn": "https://api.minimaxi.com/anthropic/v1/messages",
|
||||
crof: "https://crof.ai/v1/chat/completions",
|
||||
zenmux: "https://zenmux.ai/api/v1/chat/completions",
|
||||
openai: "https://api.openai.com/v1/chat/completions",
|
||||
anthropic: "https://api.anthropic.com/v1/messages",
|
||||
gemini: "https://generativelanguage.googleapis.com/v1beta/models",
|
||||
|
||||
@@ -2284,6 +2284,22 @@ export const APIKEY_PROVIDERS = {
|
||||
apiHint:
|
||||
"Discounted API proxy for 40+ models including GPT-5, Claude Opus 4.6, Claude Sonnet 4.6, Qwen 3.5. Get your API key at https://freeaiapikey.com/dashboard. Base URL: https://freeaiapikey.com/v1.",
|
||||
},
|
||||
zenmux: {
|
||||
id: "zenmux",
|
||||
alias: "zm",
|
||||
name: "ZenMux",
|
||||
icon: "neurology",
|
||||
color: "#7C3AED",
|
||||
textIcon: "ZM",
|
||||
website: "https://zenmux.ai",
|
||||
hasFree: true,
|
||||
freeNote:
|
||||
"Free tier includes access to Gemini 3 Flash, DeepSeek V3.2, Grok 4.1 Fast, Mistral Large, and more. Get your API key at https://zenmux.ai.",
|
||||
authHint:
|
||||
"Use your ZenMux API key in Authorization: Bearer <key>. ZenMux is fully OpenAI-compatible. Base URL: https://zenmux.ai/api/v1.",
|
||||
apiHint:
|
||||
"ZenMux exposes an OpenAI-compatible chat completions endpoint at /api/v1/chat/completions, plus Anthropic Messages (/api/anthropic/v1/messages) and Google Gemini (/api/vertex-ai) protocol surfaces. OmniRoute uses the OpenAI protocol.",
|
||||
},
|
||||
};
|
||||
|
||||
// Sub-categories within APIKEY_PROVIDERS (used by dashboard and catalog views).
|
||||
|
||||
67
tests/unit/zenmux-provider.test.ts
Normal file
67
tests/unit/zenmux-provider.test.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers.ts");
|
||||
const { PROVIDER_ENDPOINTS } = await import("../../src/shared/constants/config.ts");
|
||||
const { REGISTRY: providerRegistry } = await import("../../open-sse/config/providerRegistry.ts");
|
||||
|
||||
test("ZenMux is registered as an API-key provider with the canonical identity", () => {
|
||||
const zenmux = APIKEY_PROVIDERS.zenmux;
|
||||
assert.ok(zenmux, "APIKEY_PROVIDERS.zenmux must be defined");
|
||||
assert.equal(zenmux.id, "zenmux");
|
||||
assert.equal(zenmux.alias, "zm");
|
||||
assert.equal(zenmux.name, "ZenMux");
|
||||
assert.equal(zenmux.website, "https://zenmux.ai");
|
||||
assert.equal(typeof zenmux.textIcon, "string");
|
||||
assert.equal(zenmux.hasFree, true);
|
||||
});
|
||||
|
||||
test("ZenMux exposes the OpenAI-compatible chat completions URL", () => {
|
||||
assert.equal(
|
||||
PROVIDER_ENDPOINTS.zenmux,
|
||||
"https://zenmux.ai/api/v1/chat/completions"
|
||||
);
|
||||
});
|
||||
|
||||
test("ZenMux registry entry uses OpenAI format with bearer apikey auth", () => {
|
||||
const entry = providerRegistry.zenmux;
|
||||
assert.ok(entry, "providerRegistry.zenmux must be defined");
|
||||
assert.equal(entry.id, "zenmux");
|
||||
assert.equal(entry.alias, "zm");
|
||||
assert.equal(entry.format, "openai");
|
||||
assert.equal(entry.executor, "default");
|
||||
assert.equal(entry.authType, "apikey");
|
||||
assert.equal(entry.authHeader, "bearer");
|
||||
assert.equal(entry.baseUrl, "https://zenmux.ai/api/v1/chat/completions");
|
||||
assert.equal(entry.modelsUrl, "https://zenmux.ai/api/v1/models");
|
||||
});
|
||||
|
||||
test("ZenMux seed model list includes the headline families and unique ids", () => {
|
||||
const models = providerRegistry.zenmux.models;
|
||||
const ids = models.map((m: { id: string }) => m.id);
|
||||
assert.ok(ids.length >= 8, "expect a non-trivial seed list of 8+ models");
|
||||
assert.equal(new Set(ids).size, ids.length, "model ids must be unique");
|
||||
// Provider-prefixed family coverage matching ZenMux's multi-protocol router
|
||||
for (const family of [
|
||||
"google/gemini-3",
|
||||
"openai/gpt-5",
|
||||
"anthropic/claude-sonnet",
|
||||
"deepseek/deepseek",
|
||||
"x-ai/grok-",
|
||||
"mistralai/mistral",
|
||||
]) {
|
||||
assert.ok(
|
||||
ids.some((id: string) => id.startsWith(family)),
|
||||
`seed list must include ${family}* model`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("ZenMux models use provider/model naming convention", () => {
|
||||
for (const model of providerRegistry.zenmux.models) {
|
||||
assert.ok(
|
||||
model.id.includes("/"),
|
||||
`model id "${model.id}" must follow provider/model format (e.g. google/gemini-3.1-pro-preview)`
|
||||
);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user