mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
fix(kiro): add Claude Sonnet 5 model support (#2264)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
decolua
co-authored by
Cursor
parent
b08751c4ea
commit
a5363b83b5
@@ -78,6 +78,7 @@ const PROVIDER_MODELS = {
|
|||||||
{ id: "grok-code-fast-1" },
|
{ id: "grok-code-fast-1" },
|
||||||
],
|
],
|
||||||
kr: [
|
kr: [
|
||||||
|
{ id: "claude-sonnet-5" },
|
||||||
{ id: "claude-sonnet-4.5" },
|
{ id: "claude-sonnet-4.5" },
|
||||||
{ id: "claude-haiku-4.5" },
|
{ id: "claude-haiku-4.5" },
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export function capabilitiesFromServiceKind(kind) {
|
|||||||
* otherwise mis-match. Only declare deltas vs DEFAULT.
|
* otherwise mis-match. Only declare deltas vs DEFAULT.
|
||||||
*/
|
*/
|
||||||
export const MODEL_CAPABILITIES = {
|
export const MODEL_CAPABILITIES = {
|
||||||
// Claude 4.6/4.7/4.8 have 1M context + adaptive thinking (override generic claude pattern)
|
// Claude 4.6/4.7/4.8 and Kiro Sonnet 5 have 1M context + adaptive thinking (override generic claude pattern)
|
||||||
"claude-opus-4.6": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
"claude-opus-4.6": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||||
"claude-opus-4.7": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
"claude-opus-4.7": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||||
"claude-opus-4-7": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
"claude-opus-4-7": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||||
@@ -82,6 +82,10 @@ export const MODEL_CAPABILITIES = {
|
|||||||
"claude-opus-4-8-thinking": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
"claude-opus-4-8-thinking": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||||
"claude-sonnet-4.6": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
"claude-sonnet-4.6": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||||
"claude-sonnet-4-6": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
"claude-sonnet-4-6": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||||
|
"claude-sonnet-5": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||||
|
"claude-sonnet-5-thinking": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||||
|
"claude-sonnet-5-agentic": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||||
|
"claude-sonnet-5-thinking-agentic": { vision: true, reasoning: true, search: true, thinkingFormat: "claude-adaptive", contextWindow: 1000000, maxOutput: 128000 },
|
||||||
|
|
||||||
// Gemini image-gen / OpenAI image / xai image variants
|
// Gemini image-gen / OpenAI image / xai image variants
|
||||||
"gpt-image-1": { imageOutput: true, tools: false },
|
"gpt-image-1": { imageOutput: true, tools: false },
|
||||||
|
|||||||
@@ -42,16 +42,20 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
models: [
|
models: [
|
||||||
|
{ id: "claude-sonnet-5", name: "Claude Sonnet 5" },
|
||||||
{ id: "claude-sonnet-4.5", name: "Claude Sonnet 4.5" },
|
{ id: "claude-sonnet-4.5", name: "Claude Sonnet 4.5" },
|
||||||
{ id: "claude-haiku-4.5", name: "Claude Haiku 4.5" },
|
{ id: "claude-haiku-4.5", name: "Claude Haiku 4.5" },
|
||||||
{ id: "deepseek-3.2", name: "DeepSeek 3.2", strip: ["image","audio"] },
|
{ id: "deepseek-3.2", name: "DeepSeek 3.2", strip: ["image","audio"] },
|
||||||
{ id: "qwen3-coder-next", name: "Qwen3 Coder Next", strip: ["image","audio"] },
|
{ id: "qwen3-coder-next", name: "Qwen3 Coder Next", strip: ["image","audio"] },
|
||||||
{ id: "glm-5", name: "GLM 5" },
|
{ id: "glm-5", name: "GLM 5" },
|
||||||
{ id: "MiniMax-M2.5", name: "MiniMax M2.5" },
|
{ id: "MiniMax-M2.5", name: "MiniMax M2.5" },
|
||||||
|
{ id: "claude-sonnet-5-thinking", name: "Claude Sonnet 5 (Thinking)" },
|
||||||
{ id: "claude-sonnet-4.5-thinking", name: "Claude Sonnet 4.5 (Thinking)" },
|
{ id: "claude-sonnet-4.5-thinking", name: "Claude Sonnet 4.5 (Thinking)" },
|
||||||
{ id: "claude-haiku-4.5-thinking", name: "Claude Haiku 4.5 (Thinking)" },
|
{ id: "claude-haiku-4.5-thinking", name: "Claude Haiku 4.5 (Thinking)" },
|
||||||
|
{ id: "claude-sonnet-5-agentic", name: "Claude Sonnet 5 (Agentic)" },
|
||||||
{ id: "claude-sonnet-4.5-agentic", name: "Claude Sonnet 4.5 (Agentic)" },
|
{ id: "claude-sonnet-4.5-agentic", name: "Claude Sonnet 4.5 (Agentic)" },
|
||||||
{ id: "claude-haiku-4.5-agentic", name: "Claude Haiku 4.5 (Agentic)" },
|
{ id: "claude-haiku-4.5-agentic", name: "Claude Haiku 4.5 (Agentic)" },
|
||||||
|
{ id: "claude-sonnet-5-thinking-agentic", name: "Claude Sonnet 5 (Thinking + Agentic)" },
|
||||||
{ id: "claude-sonnet-4.5-thinking-agentic", name: "Claude Sonnet 4.5 (Thinking + Agentic)" },
|
{ id: "claude-sonnet-4.5-thinking-agentic", name: "Claude Sonnet 4.5 (Thinking + Agentic)" },
|
||||||
{ id: "claude-haiku-4.5-thinking-agentic", name: "Claude Haiku 4.5 (Thinking + Agentic)" },
|
{ id: "claude-haiku-4.5-thinking-agentic", name: "Claude Haiku 4.5 (Thinking + Agentic)" },
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ export const MITM_TOOLS = {
|
|||||||
configType: "mitm",
|
configType: "mitm",
|
||||||
mitmDomain: "q.us-east-1.amazonaws.com",
|
mitmDomain: "q.us-east-1.amazonaws.com",
|
||||||
defaultModels: [
|
defaultModels: [
|
||||||
|
{ id: "claude-sonnet-5", name: "Claude Sonnet 5", alias: "claude-sonnet-5" },
|
||||||
{ id: "claude-sonnet-4.5", name: "Claude Sonnet 4.5", alias: "claude-sonnet-4.5" },
|
{ id: "claude-sonnet-4.5", name: "Claude Sonnet 4.5", alias: "claude-sonnet-4.5" },
|
||||||
{ id: "claude-sonnet-4", name: "Claude Sonnet 4", alias: "claude-sonnet-4" },
|
{ id: "claude-sonnet-4", name: "Claude Sonnet 4", alias: "claude-sonnet-4" },
|
||||||
{ id: "claude-haiku-4.5", name: "Claude Haiku 4.5", alias: "claude-haiku-4.5" },
|
{ id: "claude-haiku-4.5", name: "Claude Haiku 4.5", alias: "claude-haiku-4.5" },
|
||||||
@@ -391,4 +392,3 @@ export const getProviderModelsForMapping = (providers) => {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
tests/unit/antigravity-mitm.test.js :: Antigravity MITM model handling flags the out-of-box agent/Default model mandatory
|
tests/unit/antigravity-mitm.test.js :: Antigravity MITM model handling flags the out-of-box agent/Default model mandatory
|
||||||
tests/unit/claude-header-forwarding.test.js :: proxyAwareFetch — api.anthropic.com routing routes api.anthropic.com to gotScraping (non-streaming) and returns ok response
|
tests/unit/claude-header-forwarding.test.js :: proxyAwareFetch — api.anthropic.com routing routes api.anthropic.com to gotScraping (non-streaming) and returns ok response
|
||||||
tests/unit/kiro-model-slots.test.js :: Kiro MITM model slots offers a mappable slot for the agent default model id 'auto'
|
|
||||||
tests/unit/oauth-cursor-auto-import.test.js :: GET /api/oauth/cursor/auto-import extracts tokens using exact keys
|
tests/unit/oauth-cursor-auto-import.test.js :: GET /api/oauth/cursor/auto-import extracts tokens using exact keys
|
||||||
tests/unit/oauth-cursor-auto-import.test.js :: GET /api/oauth/cursor/auto-import falls back to fuzzy key matching on macOS when exact keys are missing
|
tests/unit/oauth-cursor-auto-import.test.js :: GET /api/oauth/cursor/auto-import falls back to fuzzy key matching on macOS when exact keys are missing
|
||||||
tests/unit/oauth-cursor-auto-import.test.js :: GET /api/oauth/cursor/auto-import linux uses single hardcoded path and original error message
|
tests/unit/oauth-cursor-auto-import.test.js :: GET /api/oauth/cursor/auto-import linux uses single hardcoded path and original error message
|
||||||
@@ -23,4 +22,4 @@ tests/unit/rtk.test.js :: compressMessages (enabled) skips when body has no mess
|
|||||||
tests/unit/translator-request-normalization.test.js :: request normalization claudeToOpenAIRequest flattens text-only content arrays into string
|
tests/unit/translator-request-normalization.test.js :: request normalization claudeToOpenAIRequest flattens text-only content arrays into string
|
||||||
tests/unit/translator-request-normalization.test.js :: request normalization filterToOpenAIFormat flattens text-only arrays to string
|
tests/unit/translator-request-normalization.test.js :: request normalization filterToOpenAIFormat flattens text-only arrays to string
|
||||||
tests/unit/translator-request-normalization.test.js :: request normalization parseSSELine supports provider raw NDJSON stream lines
|
tests/unit/translator-request-normalization.test.js :: request normalization parseSSELine supports provider raw NDJSON stream lines
|
||||||
tests/unit/translator-request-normalization.test.js :: request normalization translateRequest keeps /v1/messages Claude->OpenAI text payloads string-safe
|
tests/unit/translator-request-normalization.test.js :: request normalization translateRequest keeps /v1/messages Claude->OpenAI text payloads string-safe
|
||||||
|
|||||||
@@ -2,6 +2,15 @@ import { describe, expect, it } from "vitest";
|
|||||||
import { getCapabilitiesForModel } from "../../open-sse/providers/capabilities.js";
|
import { getCapabilitiesForModel } from "../../open-sse/providers/capabilities.js";
|
||||||
|
|
||||||
describe("getCapabilitiesForModel", () => {
|
describe("getCapabilitiesForModel", () => {
|
||||||
|
const claudeSonnet5Expected = {
|
||||||
|
contextWindow: 1000000,
|
||||||
|
maxOutput: 128000,
|
||||||
|
thinkingFormat: "claude-adaptive",
|
||||||
|
reasoning: true,
|
||||||
|
vision: true,
|
||||||
|
search: true,
|
||||||
|
};
|
||||||
|
|
||||||
it("reports Kiro Claude Opus 4.8 as a 1M context model", () => {
|
it("reports Kiro Claude Opus 4.8 as a 1M context model", () => {
|
||||||
expect(getCapabilitiesForModel("kiro", "claude-opus-4.8").contextWindow).toBe(1000000);
|
expect(getCapabilitiesForModel("kiro", "claude-opus-4.8").contextWindow).toBe(1000000);
|
||||||
expect(getCapabilitiesForModel("kiro", "anthropic/claude-opus-4.8").contextWindow).toBe(1000000);
|
expect(getCapabilitiesForModel("kiro", "anthropic/claude-opus-4.8").contextWindow).toBe(1000000);
|
||||||
@@ -9,4 +18,12 @@ describe("getCapabilitiesForModel", () => {
|
|||||||
expect(getCapabilitiesForModel("kiro", "claude-opus-4.8-thinking").contextWindow).toBe(1000000);
|
expect(getCapabilitiesForModel("kiro", "claude-opus-4.8-thinking").contextWindow).toBe(1000000);
|
||||||
expect(getCapabilitiesForModel("kiro", "claude-opus-4-8-thinking").contextWindow).toBe(1000000);
|
expect(getCapabilitiesForModel("kiro", "claude-opus-4-8-thinking").contextWindow).toBe(1000000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("reports Kiro Claude Sonnet 5 as a 1M adaptive-thinking model", () => {
|
||||||
|
expect(getCapabilitiesForModel("kiro", "claude-sonnet-5")).toMatchObject(claudeSonnet5Expected);
|
||||||
|
expect(getCapabilitiesForModel("kiro", "anthropic/claude-sonnet-5")).toMatchObject(claudeSonnet5Expected);
|
||||||
|
expect(getCapabilitiesForModel("kiro", "claude-sonnet-5-thinking")).toMatchObject(claudeSonnet5Expected);
|
||||||
|
expect(getCapabilitiesForModel("kiro", "claude-sonnet-5-agentic")).toMatchObject(claudeSonnet5Expected);
|
||||||
|
expect(getCapabilitiesForModel("kiro", "claude-sonnet-5-thinking-agentic")).toMatchObject(claudeSonnet5Expected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { PROVIDER_MODELS } from "../../open-sse/config/providerModels.js";
|
||||||
import { MITM_TOOLS } from "../../src/shared/constants/cliTools.js";
|
import { MITM_TOOLS } from "../../src/shared/constants/cliTools.js";
|
||||||
|
|
||||||
// Guards the fix in commit 356607c: Kiro's agent/"vibe" mode sends modelId
|
// Guards Kiro model ids that still need mappable defaultModels slots. Without
|
||||||
// "auto" for the main turn and "simple-task" for background sub-tasks. Both
|
// a slot, getMappedModel (src/mitm/server.js) returns null and the request is
|
||||||
// need a mappable defaultModels slot — otherwise getMappedModel (src/mitm/server.js)
|
// passed through to AWS instead of being routed to the user's chosen provider.
|
||||||
// returns null and the /generateAssistantResponse call is passed through to AWS
|
|
||||||
// instead of being routed to the user's chosen provider (surfacing as Kiro's
|
|
||||||
// "monthly usage limit" once the AWS quota is gone).
|
|
||||||
describe("Kiro MITM model slots", () => {
|
describe("Kiro MITM model slots", () => {
|
||||||
const kiro = MITM_TOOLS.kiro;
|
const kiro = MITM_TOOLS.kiro;
|
||||||
|
|
||||||
@@ -16,10 +14,10 @@ describe("Kiro MITM model slots", () => {
|
|||||||
expect(Array.isArray(kiro.defaultModels)).toBe(true);
|
expect(Array.isArray(kiro.defaultModels)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("offers a mappable slot for the agent default model id 'auto'", () => {
|
it("offers a mappable slot for Claude Sonnet 5", () => {
|
||||||
const auto = kiro.defaultModels.find((m) => m.id === "auto");
|
const sonnet5 = kiro.defaultModels.find((m) => m.id === "claude-sonnet-5");
|
||||||
expect(auto).toBeTruthy();
|
expect(sonnet5).toBeTruthy();
|
||||||
expect(auto.alias).toBe("auto");
|
expect(sonnet5.alias).toBe("claude-sonnet-5");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("offers a mappable slot for the background sub-task model id 'simple-task'", () => {
|
it("offers a mappable slot for the background sub-task model id 'simple-task'", () => {
|
||||||
@@ -28,3 +26,15 @@ describe("Kiro MITM model slots", () => {
|
|||||||
expect(simpleTask.alias).toBe("simple-task");
|
expect(simpleTask.alias).toBe("simple-task");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Kiro static provider models", () => {
|
||||||
|
it("includes Claude Sonnet 5 and its synthetic Kiro variants", () => {
|
||||||
|
const ids = (PROVIDER_MODELS.kr || []).map((model) => model.id);
|
||||||
|
expect(ids).toEqual(expect.arrayContaining([
|
||||||
|
"claude-sonnet-5",
|
||||||
|
"claude-sonnet-5-thinking",
|
||||||
|
"claude-sonnet-5-agentic",
|
||||||
|
"claude-sonnet-5-thinking-agentic",
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user