Files
OmniRoute/tests/unit/provider-models-config.test.ts
Armin Anton” ∴ 10276821cd Integration: security tier + self-hosted operator blockers (rebased onto v3.8.51) (#10952)
Validated on the resolved merge against the current tip (527da656 + the post-#11281 rebaseline): the single conflict was a comment-only collision in providers/[id]/models/route.ts (kept the tip's #10828-ordering note). Focused suites 125/125 across all 13 touched test files (build-sqlite-stub, cc-compatible, copilot-claude-messages, copilot-gemini-route, executor-github, ghe-copilot, github-copilot-discovery-token, github-copilot-model-discovery, noauth-sibling-7620, provider-header-profiles, provider-models-config, request-log-payloads, upstream-error-passthrough), typecheck:core clean, file-size/changelog-integrity OK. Merged --admin over the inherited 2026-08-23 base-red cluster (#9985) — the reds are proven tip failures (CLI catalog cluster + @testing-library allowlist, being drained by #11280), not from this diff. Note: the rebase means several items the body listed (relay x-relay-path SSRF, /v1/search blocked-providers, #10736 rotation fence, #10903, #10865, #10899, #10916) already landed upstream and are NOT in this delta — the delta is: better-sqlite3 build guard + build heap/worker caps + telemetry-off (#10060 re-derived), credential-echo passthrough refusal + OCR/moderation redaction + call-log key redaction, Copilot CLI 1.0.81-6 wire identity + Claude→/v1/messages name-matched routing + discovery token fix, CC model_not_found 400, compat overrides for no-auth aliases (#7620-pinned). The Copilot wire-identity change is the one to watch in production. Thank you @arminanton — and the ported-author credits in the commit history (@rqzbeh, yidecode, the #10899/#10916 authors) are preserved. Your config-posture finding (REQUIRE_API_KEY default vs 0.0.0.0) is noted for a maintainer decision, as you scoped it.
2026-08-23 16:51:25 -03:00

254 lines
11 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import {
PROVIDER_ID_TO_ALIAS,
PROVIDER_MODELS,
findModelName,
getDefaultModel,
getModelTargetFormat,
getModelsByProviderId,
getProviderModels,
isValidModel,
supportsClaudeMaxEffort,
supportsXHighEffort,
supportsXHighEffortForMaxNormalization,
} from "../../open-sse/config/providerModels.ts";
// GITHUB_COPILOT_MODEL_ALLOWLIST is no longer used to gate the registry — the
// registry and the discovery fallback are asserted independently below.
test("provider models helpers expose model lists and defaults", () => {
const openaiModels = getProviderModels("openai");
assert.ok(Array.isArray(openaiModels));
assert.ok(openaiModels.length > 0);
assert.equal(getProviderModels("provider-that-does-not-exist").length, 0);
assert.equal(getDefaultModel("openai"), openaiModels[0].id);
assert.equal(getDefaultModel("provider-that-does-not-exist"), null);
});
test("provider models helpers validate and resolve model metadata", () => {
const openaiModels = PROVIDER_MODELS.openai;
const firstModel = openaiModels[0];
assert.equal(isValidModel("openai", firstModel.id), true);
assert.equal(isValidModel("openai", "missing-model"), false);
assert.equal(
isValidModel("passthrough-provider", "anything-goes", new Set(["passthrough-provider"])),
true
);
assert.equal(findModelName("openai", firstModel.id), firstModel.name);
assert.equal(findModelName("openai", "missing-model"), "missing-model");
assert.equal(findModelName("missing-provider", "missing-model"), "missing-model");
assert.equal(getModelTargetFormat("openai", firstModel.id), firstModel.targetFormat || null);
assert.equal(getModelTargetFormat("openai", "missing-model"), null);
assert.equal(getModelTargetFormat("missing-provider", "missing-model"), null);
});
test("provider models helpers resolve provider IDs through aliases", () => {
const firstProviderId = Object.keys(PROVIDER_ID_TO_ALIAS)[0];
const alias = PROVIDER_ID_TO_ALIAS[firstProviderId] || firstProviderId;
assert.deepEqual(getModelsByProviderId(firstProviderId), PROVIDER_MODELS[alias] || []);
assert.deepEqual(getModelsByProviderId("provider-that-does-not-exist"), []);
});
test("getProviderModels returns models for both the alias and the raw provider id", () => {
// Pick a provider whose alias differs from its id (e.g. "github" → "gh").
const aliased = Object.entries(PROVIDER_ID_TO_ALIAS).find(([id, a]) => id !== a) as
[string, string] | undefined;
if (!aliased) return; // no aliased providers → trivially satisfied
const [rawId, alias] = aliased;
const byAlias = getProviderModels(alias);
const byRawId = getProviderModels(rawId);
assert.ok(byAlias.length > 0, `expected models under alias "${alias}"`);
assert.deepEqual(
byRawId,
byAlias,
`getProviderModels("${rawId}") should return the same models as getProviderModels("${alias}")`
);
});
test("Reka registry exposes preset models", () => {
const rekaModels = getModelsByProviderId("reka");
const ids = rekaModels.map((model) => model.id);
assert.equal(PROVIDER_ID_TO_ALIAS.reka, "reka");
assert.equal(getDefaultModel("reka"), "reka-flash-3");
assert.deepEqual(ids, ["reka-flash-3", "reka-flash", "reka-edge-2603"]);
assert.equal(isValidModel("reka", "reka-edge-2603"), true);
assert.equal(isValidModel("reka", "reka-flash"), true);
});
test("GitHub Copilot registry reflects the current supported model lineup", () => {
const githubModels = getProviderModels("gh");
const ids: string[] = githubModels.map((model) => model.id);
// The static registry and the live-discovery fallback catalog are DIFFERENT
// lists by design (the registry drives routing/targetFormat; the fallback is a
// discovery safety net), so we assert the registry's real membership directly
// rather than pinning it to GITHUB_COPILOT_MODEL_ALLOWLIST.
for (const expected of [
"claude-opus-5",
"claude-opus-4.8",
"claude-opus-4.8-fast",
"claude-opus-4.7",
"claude-opus-4.6",
"claude-sonnet-4.6",
"gemini-3.7-flash",
"gemini-3.6-flash",
"gemini-3.5-flash",
"gpt-5.5",
"gpt-5.4",
"gpt-5.4-mini",
"gpt-5.4-nano",
"gpt-5.3-codex",
"grok-4.6",
"grok-4.5",
"mai-code-1-flash",
"mai-code-1.1-flash",
"mai-code-1-flash-picker",
]) {
assert.ok(ids.includes(expected), `github registry must include ${expected}`);
}
assert.equal(getModelTargetFormat("gh", "claude-opus-5"), "claude");
assert.equal(getModelTargetFormat("gh", "gpt-5.3-codex"), "openai-responses");
// claude-opus-4.6 IS a real Copilot model id (live /models confirms it, ctx 1M);
// it now appears in the registry and routes through the claude target format.
assert.equal(getModelTargetFormat("gh", "claude-opus-4.6"), "claude");
// Claude models route through Copilot's Anthropic-native /v1/messages shim
// (executors/github.ts) — the only endpoint that surfaces prompt-cache token
// counts for Claude and avoids a lossy tool_use/tool_result round-trip through
// the OpenAI shape. Port of decolua/9router#2608.
assert.equal(getModelTargetFormat("gh", "claude-opus-4.8-fast"), "claude");
assert.equal(getModelTargetFormat("gh", "claude-sonnet-4.6"), "claude");
// grok/mai on Copilot are /responses-only (400 on /chat/completions).
assert.equal(getModelTargetFormat("gh", "grok-4.6"), "openai-responses");
assert.equal(getModelTargetFormat("gh", "mai-code-1.1-flash"), "openai-responses");
assert.equal(getModelTargetFormat("gh", "gpt-5.4-nano"), "openai-responses");
assert.equal(getModelTargetFormat("gh", "gemini-3.7-flash"), null);
assert.equal(getModelTargetFormat("gh", "kimi-k2.7-code"), null);
assert.equal(ids.includes("gpt-4"), false);
assert.equal(ids.includes("gpt-5.1"), false);
assert.equal(ids.includes("gpt-5.1-codex"), false);
assert.equal(ids.includes("claude-opus-4.1"), false);
assert.equal(ids.includes("claude-opus-4-5-20251101"), false);
assert.equal(ids.includes("gemini-3-flash-preview"), false);
});
test("Claude flagship catalogs keep Fable 5 first", () => {
for (const provider of ["anthropic", "cc", "cw", "gh", "ghe-copilot"]) {
assert.equal(
getProviderModels(provider)[0]?.id,
"claude-fable-5",
`${provider} must list the strongest Claude model first`
);
}
});
test("Kiro registry exposes the current CLI model lineup with context windows", () => {
const kiroModels = getProviderModels("kr");
const byId = new Map(kiroModels.map((model) => [model.id, model]));
// Kiro's real upstream Claude lineup (#6170): Sonnet 5 / Sonnet 4.5 / Haiku 4.5.
// The Opus 4.x and Sonnet 4.6 ids were fabricated (copied from the Anthropic
// catalog) and returned upstream 400 "Invalid model" — removed.
assert.ok(byId.has("claude-sonnet-5"));
assert.equal(byId.get("claude-sonnet-5")?.contextLength, 1000000);
assert.ok(byId.has("claude-sonnet-4.5"));
assert.ok(byId.has("claude-haiku-4.5"));
assert.equal(byId.has("claude-opus-4.7"), false);
assert.equal(byId.has("claude-sonnet-4.6"), false);
assert.equal(byId.has("claude-sonnet-4-6"), false);
assert.equal(byId.has("claude-haiku-4-5"), false);
});
test("Claude max effort support excludes Haiku family and non-Claude IDs", () => {
assert.equal(supportsClaudeMaxEffort("claude-opus-4-7"), true);
assert.equal(supportsClaudeMaxEffort("claude-opus-4-6"), true);
assert.equal(supportsClaudeMaxEffort("claude-sonnet-4-6"), true);
assert.equal(supportsClaudeMaxEffort("claude-sonnet-4-5-20250929"), true);
assert.equal(supportsClaudeMaxEffort("claude-haiku-4-5-20251001"), false);
assert.equal(supportsClaudeMaxEffort("claude-3-5-haiku-20241022"), false);
assert.equal(supportsClaudeMaxEffort("anthropic/claude-haiku-4.5"), false);
assert.equal(supportsClaudeMaxEffort("vendor/haiku-compatible-claude-sonnet-4-6"), true);
assert.equal(supportsClaudeMaxEffort("gpt-5"), false);
assert.equal(supportsClaudeMaxEffort("claude-future-5-0"), true);
});
test("xhigh effort support defaults to pass-through and opts out explicit false models", () => {
const claudeModels = new Set(getModelsByProviderId("claude").map((model) => model.id));
assert.ok(claudeModels.has("claude-opus-5"));
assert.equal(supportsXHighEffort("claude", "claude-opus-5"), true);
assert.ok(claudeModels.has("claude-opus-4-8"));
assert.equal(supportsXHighEffort("claude", "claude-opus-4-8"), true);
assert.equal(supportsXHighEffort("claude", "claude-opus-4-7"), true);
assert.equal(supportsXHighEffort("claude", "claude-opus-4-6"), false);
assert.equal(supportsXHighEffort("claude", "claude-sonnet-4-6"), false);
assert.equal(supportsXHighEffort("claude", "claude-future-5-0"), true);
assert.equal(supportsXHighEffort("anthropic-compatible-test", "claude-opus-4-6"), false);
assert.equal(supportsXHighEffort("anthropic-compatible-test", "claude-opus-4-7"), true);
assert.equal(supportsXHighEffort("anthropic-compatible-cc-test", "claude-opus-4-6"), false);
assert.equal(supportsXHighEffort("anthropic-compatible-cc-test", "claude-opus-4-7"), true);
assert.equal(supportsXHighEffort("openrouter", "deepseek/deepseek-v4-pro"), true);
assert.equal(supportsXHighEffort("openrouter", "anthropic/claude-opus-4.6"), false);
assert.equal(supportsXHighEffort("openrouter", "anthropic/claude-opus-4.7"), true);
assert.equal(supportsXHighEffort("openrouter", "anthropic/claude-opus-4.5"), false);
assert.equal(supportsXHighEffort("bedrock", "anthropic.claude-opus-4-6"), false);
assert.equal(supportsXHighEffort("bedrock", "anthropic.claude-opus-4-7"), true);
assert.equal(supportsXHighEffort("github", "claude-opus-4.6"), false);
assert.equal(supportsXHighEffort("github", "claude-opus-4.7"), true);
assert.equal(supportsXHighEffort("unknown-provider", "vendor/claude-opus-4.6"), false);
assert.equal(
supportsXHighEffort("openrouter", "anthropic/claude-opus-4.6-thinking-xhigh"),
false
);
assert.equal(supportsXHighEffort("deepseek", "deepseek-v4-pro"), true);
});
test("max normalization follows xhigh opt-out behavior", () => {
assert.equal(
supportsXHighEffortForMaxNormalization("openai-compatible-free1", "gemini-3.1-pro-preview"),
true
);
assert.equal(supportsXHighEffortForMaxNormalization("xiaomi-mimo", "mimo-v2.5-pro"), true);
assert.equal(
supportsXHighEffortForMaxNormalization("anthropic-compatible-cc-test", "claude-opus-4-6"),
false
);
assert.equal(
supportsXHighEffortForMaxNormalization("anthropic-compatible-cc-test", "claude-opus-4-7"),
true
);
assert.equal(
supportsXHighEffortForMaxNormalization("anthropic-compatible-test", "claude-opus-4-6"),
false
);
assert.equal(
supportsXHighEffortForMaxNormalization("anthropic-compatible-test", "claude-opus-4-7"),
true
);
assert.equal(
supportsXHighEffortForMaxNormalization("openrouter", "deepseek/deepseek-v4-pro"),
true
);
assert.equal(
supportsXHighEffortForMaxNormalization("openrouter", "anthropic/claude-opus-4.6"),
false
);
assert.equal(
supportsXHighEffortForMaxNormalization("openrouter", "anthropic/claude-opus-4.7"),
true
);
assert.equal(
supportsXHighEffortForMaxNormalization("bedrock", "anthropic.claude-opus-4-6"),
false
);
});