Files
OmniRoute/tests/unit/model-family-fallback-notation.test.ts
Diego Rodrigues de Sa e Souza b3a2cfe0ea fix(providers): correct Kiro model catalog to real upstream ids (#6170)
* fix(providers): correct Kiro model catalog to real upstream ids

Kiro's API (generateAssistantResponse) returns 400 "Invalid model. Please
select a different model" for any id it does not recognize. The registry
exposed fabricated ids (copied from OmniRoute's own Anthropic catalog) that
Kiro never serves, so every call to them 400'd. Live-verified on the VPS:

  Removed (400 Invalid model):
    - auto-kiro       (no "auto" model id — was sent verbatim upstream)
    - claude-fable-5  (Kiro offers no Fable)
    - claude-opus-4.8/4.7/4.6 (Kiro offers no Opus)
  Corrected:
    - claude-sonnet-4.6 -> claude-sonnet-4.5 (Kiro's Sonnet is 4.5; 4.5 -> 200)
  Kept:
    - claude-sonnet-5 (real Kiro model, plan-gated per account)
    - claude-haiku-4.5, deepseek-3.2, glm-5, minimax-m2.5/m2.1,
      qwen3-coder-next (all proven 200 on the VPS)

Aligns the free-model catalog and drops the orphaned auto-kiro price key.
Regression guard: tests/unit/kiro-catalog-real-models.test.ts (3/3).
Kiro cluster #6112/#6113/#6099.

* test(providers): align stale Kiro-catalog tests to the corrected upstream ids

The fabricated Kiro ids removed in the parent commit (claude-fable-5,
claude-opus-4.8/4.7/4.6, claude-sonnet-4.6) were still asserted as present by
three pre-existing tests, which encoded the bug:
- catalog-updates-v3x: now asserts Kiro does NOT expose Fable 5 / Opus (kept the
  legit cc exposure) and guards the real claude-sonnet-4.5 pricing.
- model-family-fallback-notation: the dot-notation example moves from kiro/ to
  anthropic/ (which genuinely serves Opus/Fable in dot notation) — coverage kept.
- provider-models-route: the Kiro local-catalog assertion now expects the real
  Sonnet 5 / Sonnet 4.5 set and negatively guards the fabricated ids.

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
2026-07-05 02:29:32 -03:00

42 lines
2.0 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
// Covers getNextFamilyFallback's dot-vs-hyphen notation resolution (the hunk
// added alongside Claude Fable 5 in #3524 that affects ALL families): the
// lookup normalizes dots→hyphens, and each candidate is resolved to the
// notation the provider's registry actually exposes (anthropic uses dot notation
// `claude-opus-4.8`, cc uses hyphen `claude-opus-4-8`). Kiro is NOT used as the
// dot-notation example any more — its upstream never served Opus/Fable and #6170
// removed the fabricated ids; `anthropic` genuinely serves them in dot notation.
const { getNextFamilyFallback } = await import("../../open-sse/services/modelFamilyFallback.ts");
test("Fable 5 falls back to the next-best Opus tier first (not Sonnet) — cc→claude", () => {
// `cc` is an alias parseModel normalizes to the `claude` provider.
const next = getNextFamilyFallback("cc/claude-fable-5", new Set(["cc/claude-fable-5"]));
assert.equal(next, "claude/claude-opus-4-8");
});
test("Fable 5 fallback resolves to anthropic's dot-notation model id", () => {
// anthropic registry exposes `claude-opus-4.8` (dot), not `claude-opus-4-8`.
const next = getNextFamilyFallback("anthropic/claude-fable-5", new Set(["anthropic/claude-fable-5"]));
assert.equal(next, "anthropic/claude-opus-4.8");
});
test("dot-notation current model is normalized for the family lookup", () => {
// anthropic/claude-opus-4.8 must find the claude-opus-4-8 family entry.
const next = getNextFamilyFallback("anthropic/claude-opus-4.8", new Set(["anthropic/claude-opus-4.8"]));
assert.equal(next, "anthropic/claude-opus-4.7");
});
test("skips already-tried candidates and advances down the Fable chain", () => {
const next = getNextFamilyFallback(
"cc/claude-fable-5",
new Set(["cc/claude-fable-5", "claude/claude-opus-4-8"])
);
assert.equal(next, "claude/claude-opus-4-7");
});
test("returns null for an unknown family", () => {
assert.equal(getNextFamilyFallback("cc/not-a-real-model", new Set()), null);
});