mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 02:42:24 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
202 lines
8.5 KiB
TypeScript
202 lines
8.5 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { getModelsByProviderId } from "../../open-sse/config/providerModels.ts";
|
|
import { resolveCanonicalProviderModel } from "../../open-sse/services/model.ts";
|
|
import { getStaticModelsForProvider } from "../../src/lib/providers/staticModels.ts";
|
|
import { DEFAULT_PRICING } from "../../src/shared/constants/pricing.ts";
|
|
|
|
test("Pollinations catalog mirrors the current public text model lineup", () => {
|
|
const models = getModelsByProviderId("pollinations");
|
|
const ids = new Set(models.map((model) => model.id));
|
|
const names = models.map((model) => model.name);
|
|
|
|
assert.ok(ids.has("openai-fast"));
|
|
assert.ok(ids.has("openai-large"));
|
|
assert.ok(ids.has("perplexity-fast"));
|
|
assert.ok(ids.has("qwen-coder-large"));
|
|
assert.ok(ids.has("claude-large"));
|
|
assert.equal(ids.has("llama"), false);
|
|
assert.equal(
|
|
names.some((name) => /GPT-5 via Pollinations/i.test(name)),
|
|
false
|
|
);
|
|
});
|
|
|
|
test("NVIDIA catalog includes the verified 2026 additions and GPT OSS 20B alias resolution", () => {
|
|
const ids = new Set(getModelsByProviderId("nvidia").map((model) => model.id));
|
|
|
|
assert.ok(ids.has("openai/gpt-oss-20b"));
|
|
assert.ok(ids.has("nvidia/nemotron-3-super-120b-a12b"));
|
|
assert.ok(ids.has("mistralai/mistral-large-3-675b-instruct-2512"));
|
|
assert.ok(ids.has("qwen/qwen3.5-397b-a17b"));
|
|
assert.ok(ids.has("mistralai/devstral-2-123b-instruct-2512"));
|
|
|
|
assert.deepEqual(resolveCanonicalProviderModel("nvidia", "gpt-oss-20b"), {
|
|
provider: "nvidia",
|
|
model: "openai/gpt-oss-20b",
|
|
});
|
|
});
|
|
|
|
test("Fable 5 catalog exposes claude-fable-5 in cc — but NOT via Kiro (fabricated)", () => {
|
|
// claude-fable-5 is a real Claude flagship served by the Claude Code (cc) channel,
|
|
// but Kiro's upstream never served it — it had been copied verbatim into the Kiro
|
|
// registry from OmniRoute's own Anthropic catalog and returned upstream 400
|
|
// "Invalid model". #6170 removed the fabricated Kiro copy.
|
|
const ccIds = new Set(getModelsByProviderId("cc").map((m) => m.id));
|
|
assert.ok(ccIds.has("claude-fable-5"), "cc must expose claude-fable-5");
|
|
|
|
const ccPricing = (DEFAULT_PRICING as Record<string, Record<string, unknown>>).cc;
|
|
assert.ok(ccPricing["claude-fable-5"], "cc pricing must include claude-fable-5");
|
|
|
|
const kiroIds = new Set(getModelsByProviderId("kiro").map((m) => m.id));
|
|
assert.equal(
|
|
kiroIds.has("claude-fable-5"),
|
|
false,
|
|
"kiro must NOT expose claude-fable-5 (fabricated)"
|
|
);
|
|
});
|
|
|
|
test("Opus 5 catalog is limited to verified first-party, web, and Copilot providers", () => {
|
|
for (const providerId of ["claude", "github", "claude-web", "anthropic"]) {
|
|
const model = getModelsByProviderId(providerId).find((entry) => entry.id === "claude-opus-5");
|
|
assert.ok(model, `${providerId} must expose claude-opus-5`);
|
|
}
|
|
|
|
const claude = getModelsByProviderId("claude").find((entry) => entry.id === "claude-opus-5");
|
|
assert.equal(claude?.contextLength, 1000000);
|
|
assert.equal(claude?.maxOutputTokens, 128000);
|
|
assert.ok(
|
|
getStaticModelsForProvider("claude")?.some((entry) => entry.id === "claude-opus-5"),
|
|
"claude OAuth discovery must expose claude-opus-5"
|
|
);
|
|
|
|
const github = getModelsByProviderId("github").find((entry) => entry.id === "claude-opus-5");
|
|
assert.equal(github?.targetFormat, "claude");
|
|
|
|
const kiroIds = new Set(getModelsByProviderId("kiro").map((entry) => entry.id));
|
|
assert.equal(kiroIds.has("claude-opus-5"), false, "do not fabricate Kiro availability");
|
|
|
|
const pricing = DEFAULT_PRICING as Record<string, Record<string, unknown>>;
|
|
for (const providerId of ["cc", "gh", "anthropic"]) {
|
|
const price = pricing[providerId]["claude-opus-5"] as { input: number; output: number };
|
|
assert.equal(price.input, 5.0, `${providerId} Opus 5 input price`);
|
|
assert.equal(price.output, 25.0, `${providerId} Opus 5 output price`);
|
|
}
|
|
});
|
|
|
|
test("Sonnet 5 catalog exposes claude-sonnet-5 across cc/kiro/anthropic/blackbox with Sonnet-tier pricing", () => {
|
|
// Sonnet 5 must be wired everywhere the last flagship (Fable 5) was — but as a
|
|
// Sonnet-tier model: $3/$15 pricing (NOT the Opus/Fable $15/$75), 1M ctx / 128K out.
|
|
for (const providerId of ["cc", "kiro", "anthropic", "blackbox"]) {
|
|
const ids = new Set(getModelsByProviderId(providerId).map((m) => m.id));
|
|
assert.ok(ids.has("claude-sonnet-5"), `${providerId} must expose claude-sonnet-5`);
|
|
}
|
|
|
|
const kiroSonnet5 = getModelsByProviderId("kiro").find((m) => m.id === "claude-sonnet-5");
|
|
assert.equal(kiroSonnet5?.contextLength, 1000000);
|
|
assert.equal(kiroSonnet5?.maxOutputTokens, 128000);
|
|
|
|
const ccPricing = (DEFAULT_PRICING as Record<string, Record<string, unknown>>).cc;
|
|
assert.ok(ccPricing["claude-sonnet-5"], "cc pricing must include claude-sonnet-5");
|
|
|
|
const kiroPricing = (DEFAULT_PRICING as Record<string, Record<string, unknown>>).kiro;
|
|
const kiroSonnet5Price = kiroPricing["claude-sonnet-5"] as { input: number; output: number };
|
|
assert.ok(kiroSonnet5Price, "kiro pricing must include claude-sonnet-5");
|
|
// Sonnet-tier, not Opus-tier — guards against copying Fable 5's $15/$75.
|
|
assert.equal(kiroSonnet5Price.input, 3.0);
|
|
assert.equal(kiroSonnet5Price.output, 15.0);
|
|
});
|
|
|
|
test("Kiro catalog does NOT expose Claude Opus (fabricated — Kiro upstream has no Opus)", () => {
|
|
// Kiro's real upstream never served any Opus model; the Opus 4.8/4.7/4.6 ids had been
|
|
// copied into the Kiro registry from OmniRoute's Anthropic catalog and returned upstream
|
|
// 400 "Invalid model. Please select a different model". #6170 removed them.
|
|
const ids = new Set(getModelsByProviderId("kiro").map((model) => model.id));
|
|
|
|
assert.equal(
|
|
ids.has("claude-opus-4.8"),
|
|
false,
|
|
"kiro must NOT expose claude-opus-4.8 (fabricated)"
|
|
);
|
|
assert.equal(
|
|
ids.has("claude-opus-4.7"),
|
|
false,
|
|
"kiro must NOT expose claude-opus-4.7 (fabricated)"
|
|
);
|
|
assert.equal(
|
|
ids.has("claude-opus-4.6"),
|
|
false,
|
|
"kiro must NOT expose claude-opus-4.6 (fabricated)"
|
|
);
|
|
});
|
|
|
|
test("Every Kiro registry model resolves a non-zero pricing row (no $0.00 usage)", async () => {
|
|
const { getPricingForModel } = await import("../../src/shared/constants/pricing.ts");
|
|
const models = getModelsByProviderId("kiro");
|
|
|
|
assert.ok(models.length > 0, "kiro must expose models");
|
|
|
|
for (const model of models) {
|
|
const pricing = getPricingForModel("kiro", model.id) as {
|
|
input?: number;
|
|
output?: number;
|
|
} | null;
|
|
assert.ok(pricing, `kiro pricing must include "${model.id}"`);
|
|
assert.equal(
|
|
typeof pricing?.input === "number" && typeof pricing?.output === "number",
|
|
true,
|
|
`kiro pricing for "${model.id}" must have numeric input/output`
|
|
);
|
|
}
|
|
|
|
// Regression guard: Kiro's real Sonnet is 4.5 (the "4.6" id was fabricated — #6170) and
|
|
// must carry Sonnet-tier pricing ($3/$15).
|
|
const sonnet45 = getPricingForModel("kiro", "claude-sonnet-4.5") as {
|
|
input: number;
|
|
output: number;
|
|
} | null;
|
|
assert.ok(sonnet45, "kiro pricing must include claude-sonnet-4.5");
|
|
assert.equal(sonnet45?.input, 3.0);
|
|
assert.equal(sonnet45?.output, 15.0);
|
|
});
|
|
|
|
test("Every OpenAI registry model resolves a non-zero pricing row (alias: openai)", async () => {
|
|
const { getPricingForModel } = await import("../../src/shared/constants/pricing.ts");
|
|
const models = getModelsByProviderId("openai");
|
|
assert.ok(models.length > 0, "openai must expose models");
|
|
|
|
for (const model of models) {
|
|
const pricing = getPricingForModel("openai", model.id) as {
|
|
input?: number;
|
|
output?: number;
|
|
} | null;
|
|
assert.ok(pricing, `openai pricing must include "${model.id}"`);
|
|
assert.equal(
|
|
typeof pricing?.input === "number" && typeof pricing?.output === "number",
|
|
true,
|
|
`openai pricing for "${model.id}" must have numeric input/output`
|
|
);
|
|
}
|
|
});
|
|
|
|
test("Every Codex registry model resolves a non-zero pricing row (alias: cx)", async () => {
|
|
const { getPricingForModel } = await import("../../src/shared/constants/pricing.ts");
|
|
const models = getModelsByProviderId("codex");
|
|
assert.ok(models.length > 0, "codex must expose models");
|
|
|
|
for (const model of models) {
|
|
// Codex pricing lives under the "cx" alias (its DEFAULT_PRICING key).
|
|
const pricing = getPricingForModel("cx", model.id) as {
|
|
input?: number;
|
|
output?: number;
|
|
} | null;
|
|
assert.ok(pricing, `cx pricing must include codex model "${model.id}"`);
|
|
assert.equal(
|
|
typeof pricing?.input === "number" && typeof pricing?.output === "number",
|
|
true,
|
|
`cx pricing for "${model.id}" must have numeric input/output`
|
|
);
|
|
}
|
|
});
|