From b94685b80dbdd911c16d45690cc06900fb72defd Mon Sep 17 00:00:00 2001 From: Edison42 Date: Thu, 16 Jul 2026 14:37:08 +0700 Subject: [PATCH] feat(kiro): add GPT-5.6 model family (#2596) Add GPT-5.6 Sol/Terra/Luna and their synthetic thinking/agentic/ thinking-agentic variants to the Kiro static catalog with the observed 272k context window and credit multipliers (2.4/1.2/0.6), register MITM mapping slots for the new base ids, and override runtime capabilities so the GPT-5.6 family reports the 272k window instead of the generic GPT-5 profile. --- open-sse/providers/capabilities.js | 28 +++++++++++++--- open-sse/providers/registry/kiro.js | 12 +++++++ src/shared/constants/cliTools.js | 3 ++ tests/unit/capabilities.test.js | 17 ++++++++++ tests/unit/kiro-model-slots.test.js | 50 +++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 4 deletions(-) diff --git a/open-sse/providers/capabilities.js b/open-sse/providers/capabilities.js index 3d302628..6e54a683 100644 --- a/open-sse/providers/capabilities.js +++ b/open-sse/providers/capabilities.js @@ -98,6 +98,8 @@ export const MODEL_CAPABILITIES = { "coder-model": { reasoning: true, thinkingFormat: "qwen", contextWindow: 1000000 }, }; +const KIRO_GPT_5_6_CAPABILITIES = { vision: true, reasoning: true, search: true, thinkingFormat: "openai", contextWindow: 272000, maxOutput: 128000 }; + /** * Provider-specific capability overrides. Keyed by provider alias/id. */ @@ -111,6 +113,20 @@ export const PROVIDER_CAPABILITIES = { "deepseek-ai/deepseek-v4-pro": { reasoning: true, thinkingFormat: "openai", contextWindow: 1000000, maxOutput: 65536 }, "deepseek-ai/deepseek-v4-flash": { reasoning: true, thinkingFormat: "openai", contextWindow: 1000000, maxOutput: 65536 }, }, + "kiro": { + "gpt-5.6-sol": KIRO_GPT_5_6_CAPABILITIES, + "gpt-5.6-terra": KIRO_GPT_5_6_CAPABILITIES, + "gpt-5.6-luna": KIRO_GPT_5_6_CAPABILITIES, + "gpt-5.6-sol-thinking": KIRO_GPT_5_6_CAPABILITIES, + "gpt-5.6-terra-thinking": KIRO_GPT_5_6_CAPABILITIES, + "gpt-5.6-luna-thinking": KIRO_GPT_5_6_CAPABILITIES, + "gpt-5.6-sol-agentic": KIRO_GPT_5_6_CAPABILITIES, + "gpt-5.6-terra-agentic": KIRO_GPT_5_6_CAPABILITIES, + "gpt-5.6-luna-agentic": KIRO_GPT_5_6_CAPABILITIES, + "gpt-5.6-sol-thinking-agentic": KIRO_GPT_5_6_CAPABILITIES, + "gpt-5.6-terra-thinking-agentic": KIRO_GPT_5_6_CAPABILITIES, + "gpt-5.6-luna-thinking-agentic": KIRO_GPT_5_6_CAPABILITIES, + }, // CodeBuddy.cn — authoritative per-model metadata from the gateway's model // config (contextWindow=maxInputTokens, maxOutput=maxOutputTokens, vision= // supportsImages). Every model reasons via OpenAI-style reasoning_effort @@ -271,13 +287,17 @@ export const PATTERN_CAPABILITIES = [ export function getCapabilitiesForModel(provider, model) { if (!model) return { ...DEFAULT_CAPABILITIES }; + // Canonical exact lookup strips vendor prefix: "anthropic/claude-opus-4.7" -> "claude-opus-4.7". + const baseModel = model.includes("/") ? model.split("/").pop() : model; + // 1. Provider-specific override - if (provider && PROVIDER_CAPABILITIES[provider]?.[model]) { - return { ...DEFAULT_CAPABILITIES, ...PROVIDER_CAPABILITIES[provider][model] }; + if (provider) { + const providerCaps = PROVIDER_CAPABILITIES[provider]; + if (providerCaps?.[model]) return { ...DEFAULT_CAPABILITIES, ...providerCaps[model] }; + if (providerCaps?.[baseModel]) return { ...DEFAULT_CAPABILITIES, ...providerCaps[baseModel] }; } - // 2. Canonical exact (strip vendor prefix: "anthropic/claude-opus-4.7" -> "claude-opus-4.7") - const baseModel = model.includes("/") ? model.split("/").pop() : model; + // 2. Canonical exact if (MODEL_CAPABILITIES[baseModel]) return { ...DEFAULT_CAPABILITIES, ...MODEL_CAPABILITIES[baseModel] }; if (MODEL_CAPABILITIES[model]) return { ...DEFAULT_CAPABILITIES, ...MODEL_CAPABILITIES[model] }; diff --git a/open-sse/providers/registry/kiro.js b/open-sse/providers/registry/kiro.js index dab23a3f..1a47adaa 100644 --- a/open-sse/providers/registry/kiro.js +++ b/open-sse/providers/registry/kiro.js @@ -65,18 +65,30 @@ export default { { id: "qwen3-coder-next", name: "Qwen3 Coder Next", strip: ["image","audio"] }, { id: "glm-5", name: "GLM 5" }, { id: "MiniMax-M2.5", name: "MiniMax M2.5" }, + { id: "gpt-5.6-sol", name: "GPT 5.6 Sol", contextLength: 272000, rateMultiplier: 2.4, upstreamModelId: "gpt-5.6-sol", description: "Experimental preview of OpenAI GPT 5.6 Sol with 272k context window" }, + { id: "gpt-5.6-terra", name: "GPT 5.6 Terra", contextLength: 272000, rateMultiplier: 1.2, upstreamModelId: "gpt-5.6-terra", description: "Experimental preview of OpenAI GPT 5.6 Terra with 272k context window" }, + { id: "gpt-5.6-luna", name: "GPT 5.6 Luna", contextLength: 272000, rateMultiplier: 0.6, upstreamModelId: "gpt-5.6-luna", description: "Experimental preview of OpenAI GPT 5.6 Luna with 272k context window" }, // Thinking variants { id: "claude-sonnet-5-thinking", name: "Claude Sonnet 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: "gpt-5.6-sol-thinking", name: "GPT 5.6 Sol (Thinking)", contextLength: 272000, rateMultiplier: 2.4, upstreamModelId: "gpt-5.6-sol", description: "Experimental preview of OpenAI GPT 5.6 Sol with 272k context window" }, + { id: "gpt-5.6-terra-thinking", name: "GPT 5.6 Terra (Thinking)", contextLength: 272000, rateMultiplier: 1.2, upstreamModelId: "gpt-5.6-terra", description: "Experimental preview of OpenAI GPT 5.6 Terra with 272k context window" }, + { id: "gpt-5.6-luna-thinking", name: "GPT 5.6 Luna (Thinking)", contextLength: 272000, rateMultiplier: 0.6, upstreamModelId: "gpt-5.6-luna", description: "Experimental preview of OpenAI GPT 5.6 Luna with 272k context window" }, // Agentic variants { id: "claude-sonnet-5-agentic", name: "Claude Sonnet 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: "gpt-5.6-sol-agentic", name: "GPT 5.6 Sol (Agentic)", contextLength: 272000, rateMultiplier: 2.4, upstreamModelId: "gpt-5.6-sol", description: "Experimental preview of OpenAI GPT 5.6 Sol with 272k context window" }, + { id: "gpt-5.6-terra-agentic", name: "GPT 5.6 Terra (Agentic)", contextLength: 272000, rateMultiplier: 1.2, upstreamModelId: "gpt-5.6-terra", description: "Experimental preview of OpenAI GPT 5.6 Terra with 272k context window" }, + { id: "gpt-5.6-luna-agentic", name: "GPT 5.6 Luna (Agentic)", contextLength: 272000, rateMultiplier: 0.6, upstreamModelId: "gpt-5.6-luna", description: "Experimental preview of OpenAI GPT 5.6 Luna with 272k context window" }, // Thinking + Agentic variants { 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-haiku-4.5-thinking-agentic", name: "Claude Haiku 4.5 (Thinking + Agentic)" }, + { id: "gpt-5.6-sol-thinking-agentic", name: "GPT 5.6 Sol (Thinking + Agentic)", contextLength: 272000, rateMultiplier: 2.4, upstreamModelId: "gpt-5.6-sol", description: "Experimental preview of OpenAI GPT 5.6 Sol with 272k context window" }, + { id: "gpt-5.6-terra-thinking-agentic", name: "GPT 5.6 Terra (Thinking + Agentic)", contextLength: 272000, rateMultiplier: 1.2, upstreamModelId: "gpt-5.6-terra", description: "Experimental preview of OpenAI GPT 5.6 Terra with 272k context window" }, + { id: "gpt-5.6-luna-thinking-agentic", name: "GPT 5.6 Luna (Thinking + Agentic)", contextLength: 272000, rateMultiplier: 0.6, upstreamModelId: "gpt-5.6-luna", description: "Experimental preview of OpenAI GPT 5.6 Luna with 272k context window" }, ], oauth: { ssoOidcEndpoint: "https://oidc.us-east-1.amazonaws.com", diff --git a/src/shared/constants/cliTools.js b/src/shared/constants/cliTools.js index b9d000ca..685d2bc6 100644 --- a/src/shared/constants/cliTools.js +++ b/src/shared/constants/cliTools.js @@ -62,6 +62,9 @@ export const MITM_TOOLS = { { id: "claude-haiku-4.5", name: "Claude Haiku 4.5", alias: "claude-haiku-4.5" }, { id: "deepseek-3.2", name: "DeepSeek 3.2", alias: "deepseek-3.2" }, { id: "minimax-m2.1", name: "MiniMax M2.1", alias: "minimax-m2.1" }, + { id: "gpt-5.6-sol", name: "GPT 5.6 Sol", alias: "gpt-5.6-sol", contextLength: 272000, rateMultiplier: 2.4 }, + { id: "gpt-5.6-terra", name: "GPT 5.6 Terra", alias: "gpt-5.6-terra", contextLength: 272000, rateMultiplier: 1.2 }, + { id: "gpt-5.6-luna", name: "GPT 5.6 Luna", alias: "gpt-5.6-luna", contextLength: 272000, rateMultiplier: 0.6 }, { id: "simple-task", name: "Qwen3 Coder Next", alias: "simple-task" }, ], }, diff --git a/tests/unit/capabilities.test.js b/tests/unit/capabilities.test.js index 31512e9a..ccfddfa5 100644 --- a/tests/unit/capabilities.test.js +++ b/tests/unit/capabilities.test.js @@ -11,6 +11,15 @@ describe("getCapabilitiesForModel", () => { search: true, }; + const kiroGpt56Expected = { + contextWindow: 272000, + maxOutput: 128000, + thinkingFormat: "openai", + reasoning: true, + vision: true, + search: true, + }; + 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", "anthropic/claude-opus-4.8").contextWindow).toBe(1000000); @@ -26,4 +35,12 @@ describe("getCapabilitiesForModel", () => { expect(getCapabilitiesForModel("kiro", "claude-sonnet-5-agentic")).toMatchObject(claudeSonnet5Expected); expect(getCapabilitiesForModel("kiro", "claude-sonnet-5-thinking-agentic")).toMatchObject(claudeSonnet5Expected); }); + + it("reports Kiro GPT 5.6 models with the Kiro 272k context window", () => { + expect(getCapabilitiesForModel("kiro", "gpt-5.6-sol")).toMatchObject(kiroGpt56Expected); + expect(getCapabilitiesForModel("kiro", "openai/gpt-5.6-sol")).toMatchObject(kiroGpt56Expected); + expect(getCapabilitiesForModel("kiro", "gpt-5.6-terra-thinking")).toMatchObject(kiroGpt56Expected); + expect(getCapabilitiesForModel("kiro", "gpt-5.6-luna-agentic")).toMatchObject(kiroGpt56Expected); + expect(getCapabilitiesForModel("kiro", "gpt-5.6-sol-thinking-agentic")).toMatchObject(kiroGpt56Expected); + }); }); diff --git a/tests/unit/kiro-model-slots.test.js b/tests/unit/kiro-model-slots.test.js index ffc3e382..8bb1afab 100644 --- a/tests/unit/kiro-model-slots.test.js +++ b/tests/unit/kiro-model-slots.test.js @@ -25,6 +25,13 @@ describe("Kiro MITM model slots", () => { expect(simpleTask).toBeTruthy(); expect(simpleTask.alias).toBe("simple-task"); }); + + it("offers mappable slots for GPT-5.6 family models", () => { + const models = new Map(kiro.defaultModels.map((m) => [m.id, m])); + expect(models.get("gpt-5.6-sol")).toMatchObject({ alias: "gpt-5.6-sol", contextLength: 272000, rateMultiplier: 2.4 }); + expect(models.get("gpt-5.6-terra")).toMatchObject({ alias: "gpt-5.6-terra", contextLength: 272000, rateMultiplier: 1.2 }); + expect(models.get("gpt-5.6-luna")).toMatchObject({ alias: "gpt-5.6-luna", contextLength: 272000, rateMultiplier: 0.6 }); + }); }); describe("Kiro static provider models", () => { @@ -37,4 +44,47 @@ describe("Kiro static provider models", () => { "claude-sonnet-5-thinking-agentic", ])); }); + + it("includes GPT-5.6 family and synthetic Kiro variants", () => { + const models = new Map((PROVIDER_MODELS.kr || []).map((model) => [model.id, model])); + const ids = [...models.keys()]; + expect(ids).toEqual(expect.arrayContaining([ + "gpt-5.6-sol", + "gpt-5.6-sol-thinking", + "gpt-5.6-sol-agentic", + "gpt-5.6-sol-thinking-agentic", + "gpt-5.6-terra", + "gpt-5.6-terra-thinking", + "gpt-5.6-terra-agentic", + "gpt-5.6-terra-thinking-agentic", + "gpt-5.6-luna", + "gpt-5.6-luna-thinking", + "gpt-5.6-luna-agentic", + "gpt-5.6-luna-thinking-agentic", + ])); + + for (const [id, rateMultiplier] of [ + ["gpt-5.6-sol", 2.4], + ["gpt-5.6-sol-thinking", 2.4], + ["gpt-5.6-sol-agentic", 2.4], + ["gpt-5.6-sol-thinking-agentic", 2.4], + ["gpt-5.6-terra", 1.2], + ["gpt-5.6-terra-thinking", 1.2], + ["gpt-5.6-terra-agentic", 1.2], + ["gpt-5.6-terra-thinking-agentic", 1.2], + ["gpt-5.6-luna", 0.6], + ["gpt-5.6-luna-thinking", 0.6], + ["gpt-5.6-luna-agentic", 0.6], + ["gpt-5.6-luna-thinking-agentic", 0.6], + ]) { + const model = models.get(id); + const upstreamModelId = id.replace(/-(thinking-agentic|thinking|agentic)$/, ""); + expect(model).toMatchObject({ + contextLength: 272000, + rateMultiplier, + upstreamModelId, + }); + expect(model.description).toContain("272k context window"); + } + }); });