From 5fe209dd1be82dfce0243d2788a13692e98ee6df Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza Date: Wed, 1 Jul 2026 04:34:05 -0300 Subject: [PATCH] fix(providers): add claude-sonnet-5 to Kiro model catalog (port from 9router#2267) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Kiro provider's model catalog (open-sse/config/providers/registry/kiro/index.ts models[]) was missing claude-sonnet-5, so the model could not be selected or routed on the Kiro provider even on accounts that already had access to it — surfacing as "claude-sonnet-5 is not supported". The registry models[] is both the model selector's source and the fallback for the live CodeWhisperer ListAvailableModels fetch, so the gap made the model invisible end-to-end. Added the single entry (1M context / 128K output, mirroring the existing Claude entries). Reported-by: openbioinfo (https://github.com/decolua/9router/issues/2267) --- CHANGELOG.md | 2 ++ .../config/providers/registry/kiro/index.ts | 6 ++++ tests/unit/kiro-claude-sonnet-5-2267.test.ts | 30 +++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 tests/unit/kiro-claude-sonnet-5-2267.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 9433791c6b..b07a421a26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ ### 🔧 Bug Fixes +- **providers (Kiro — Claude Sonnet 5):** the Kiro provider's model catalog was missing `claude-sonnet-5`, so the model could not be selected or routed even on accounts that already had access to it ("claude-sonnet-5 is not supported"). Added the model to the Kiro registry (`open-sse/config/providers/registry/kiro/index.ts`) as a 1M-context / 128K-output Claude model, mirroring the existing Claude entries; the registry `models[]` feeds both the model selector and the live CodeWhisperer `ListAvailableModels` fallback, so the model is now selectable and routable. Regression guard: `tests/unit/kiro-claude-sonnet-5-2267.test.ts`. (thanks [@openbioinfo](https://github.com/openbioinfo)) + - **settings (model aliases — self-heal after restart):** the Settings → Routing page showed "No exact-match aliases configured" after a server restart even though the aliases were persisted in the DB. Aliases are held in a module-local `_customAliases` map in `modelDeprecation.ts` that the boot path hydrates, but Next.js compiles the app-route module graph separately from the startup graph (the same webpack chunk-splitting class as #5312), so the `GET /api/settings/model-aliases` handler read a different, un-hydrated copy. The handler now self-heals: when its in-memory alias map is empty it reads `settings.modelAliases` from the DB (via the existing `getSettings()` db module — no raw SQL in the route) and repopulates the map, so the UI reflects the persisted aliases on the first GET after a restart. Regression guard: `tests/unit/model-aliases-settings-route-selfheal.test.ts`. ([#5777](https://github.com/diegosouzapw/OmniRoute/pull/5777) — thanks [@jleonar2](https://github.com/jleonar2)) - **providers (grok-cli token auto-refresh):** grok-cli OAuth tokens were never proactively refreshed before their real expiry. `mapTokens` hardcoded `expiresIn: 21600` (6 h) regardless of the token's actual lifetime, so the persisted `expiresAt` was always "now + 6 h" and the proactive `tokenHealthCheck` sweep (refresh when `expiresAt - now < 5 min`) fired 6 h after import instead of shortly before the token really expired. `mapTokens` now computes `expiresIn` from the authoritative `expires_at` field in `~/.grok/auth.json` (ISO → epoch-seconds) with a fallback to the JWT `exp` claim (payload-only decode, no signature trust); the hardcoded `21600` is kept only when neither is present. Regression guards: 3 new cases in `tests/unit/grok-cli-oauth.test.ts` (JWT `exp`, JSON `expires_at`, and the fallback). ([#5775](https://github.com/diegosouzapw/OmniRoute/pull/5775) — thanks [@Chewji9875](https://github.com/Chewji9875)) diff --git a/open-sse/config/providers/registry/kiro/index.ts b/open-sse/config/providers/registry/kiro/index.ts index b3a9792264..6c4d41cf6e 100644 --- a/open-sse/config/providers/registry/kiro/index.ts +++ b/open-sse/config/providers/registry/kiro/index.ts @@ -41,6 +41,12 @@ export const kiroProvider: RegistryEntry = { contextLength: 1000000, maxOutputTokens: 128000, }, + { + id: "claude-sonnet-5", + name: "Claude Sonnet 5", + contextLength: 1000000, + maxOutputTokens: 128000, + }, { id: "claude-sonnet-4.6", name: "Claude Sonnet 4.6", diff --git a/tests/unit/kiro-claude-sonnet-5-2267.test.ts b/tests/unit/kiro-claude-sonnet-5-2267.test.ts new file mode 100644 index 0000000000..ede4c805cc --- /dev/null +++ b/tests/unit/kiro-claude-sonnet-5-2267.test.ts @@ -0,0 +1,30 @@ +import test from "node:test"; +import assert from "node:assert/strict"; + +import { kiroProvider } from "../../open-sse/config/providers/registry/kiro/index.ts"; + +// Regression for the port of decolua/9router#2267 ("claude-sonnet-5 is not supported"). +// +// The Kiro provider's OAuth model catalog lives in `registry/kiro/index.ts` `models[]`. +// That list is both the model selector's source and the fallback for the live +// CodeWhisperer ListAvailableModels fetch (`kiroModels.ts::toFallbackResult`). Because +// `claude-sonnet-5` — a real, shipping Anthropic model already served by Kiro — was +// missing from it, the model could not be selected or routed on the Kiro provider even +// though the account had access. The fix adds the single model entry (mirroring the +// existing Claude entries), with the 1M-context / 128K-output capability Kiro serves it at. + +test("kiro registry exposes claude-sonnet-5", () => { + const ids = kiroProvider.models.map((m) => m.id); + assert.ok( + ids.includes("claude-sonnet-5"), + `expected kiro registry to include claude-sonnet-5, got: ${ids.join(", ")}` + ); +}); + +test("kiro claude-sonnet-5 declares the 1M-context / 128K-output capability", () => { + const sonnet5 = kiroProvider.models.find((m) => m.id === "claude-sonnet-5"); + assert.ok(sonnet5, "claude-sonnet-5 must be present in the kiro registry"); + assert.equal(sonnet5.name, "Claude Sonnet 5"); + assert.equal(sonnet5.contextLength, 1000000); + assert.equal(sonnet5.maxOutputTokens, 128000); +});