diff --git a/open-sse/config/kiroConstants.js b/open-sse/config/kiroConstants.js
index 93b8f4569e..120b5e38df 100644
--- a/open-sse/config/kiroConstants.js
+++ b/open-sse/config/kiroConstants.js
@@ -144,9 +144,13 @@ export function extractKiroEffortLevel(body) {
return null;
}
-export function buildKiroAdditionalModelRequestFields(body) {
+export function buildKiroAdditionalModelRequestFields(body, effortPath = "output_config") {
const effort = extractKiroEffortLevel(body);
if (!effort) return undefined;
+ if (effortPath === "reasoning") {
+ // Mirrors Kiro CLI/KAS buildEffortRequestFields("reasoning") for GPT.
+ return { reasoning: { effort } };
+ }
// Mirrors Kiro CLI/KAS buildEffortRequestFields("output_config").
return {
thinking: { type: "adaptive", display: "summarized" },
@@ -154,12 +158,15 @@ export function buildKiroAdditionalModelRequestFields(body) {
};
}
-export function supportsKiroAdditionalModelRequestFields(model) {
- if (typeof model !== "string") return false;
+export function resolveKiroEffortPath(model) {
+ if (typeof model !== "string") return null;
const normalized = model.toLowerCase().replace(/-/g, ".");
- if (!normalized.includes("claude")) return false;
+ if (/(?:^|[/.])gpt[/.]5[/.]6(?:[/.]|$)/.test(normalized)) {
+ return "reasoning";
+ }
+ if (!normalized.includes("claude")) return null;
const match = normalized.match(/(?:^|[/.])claude(?:[/.][a-z]+)*[/.](\d+)(?:[/.](\d+))?(?:[/.]|$)/);
- if (!match) return false;
+ if (!match) return null;
const [, majorText, minorText] = match;
const major = Number(majorText);
const minor = minorText === undefined ? null : Number(minorText);
@@ -167,12 +174,19 @@ export function supportsKiroAdditionalModelRequestFields(model) {
// Kiro rejected additionalModelRequestFields on legacy 4.5 models in live smoke.
// Default future Claude/Kiro models to supported so new model releases do not
// need a code allowlist update.
- return !(major < 4 || (major === 4 && (minor === null || minor <= 5 || dateSuffixMinor)));
+ return major < 4 || (major === 4 && (minor === null || minor <= 5 || dateSuffixMinor))
+ ? null
+ : "output_config";
+}
+
+export function supportsKiroAdditionalModelRequestFields(model) {
+ return resolveKiroEffortPath(model) !== null;
}
export function buildKiroAdditionalModelRequestFieldsForModel(body, model) {
- if (!supportsKiroAdditionalModelRequestFields(model)) return undefined;
- return buildKiroAdditionalModelRequestFields(body);
+ const effortPath = resolveKiroEffortPath(model);
+ if (!effortPath) return undefined;
+ return buildKiroAdditionalModelRequestFields(body, effortPath);
}
/**
diff --git a/open-sse/translator/request/openai-to-kiro.js b/open-sse/translator/request/openai-to-kiro.js
index a2681b5a7d..b49185374b 100644
--- a/open-sse/translator/request/openai-to-kiro.js
+++ b/open-sse/translator/request/openai-to-kiro.js
@@ -511,12 +511,10 @@ function convertMessages(messages, tools, model) {
* Kiro's 2-3 minute server timeout. The suffix is stripped before being
* sent upstream.
*
- * 2. Thinking / reasoning. Kiro does not accept `thinking.type` or
- * `reasoning_effort` natively. The only way to enable reasoning is to
- * inject `enabled` into the user content
- * sent upstream. Detection covers Anthropic-Beta header, Claude API
+ * 2. Thinking / reasoning. Detection covers Anthropic-Beta header, Claude API
* `thinking`, OpenAI `reasoning_effort`, AMP/Cursor magic tags, and model
- * name hints.
+ * name hints. Kiro's prompt tags remain for compatibility, while supported
+ * models also receive the same schema-specific effort fields as Kiro CLI.
*/
export function openaiToKiroRequest(model, body, stream, credentials) {
const messages = body.messages || [];
diff --git a/tests/translator/claude-kiro-direct.test.js b/tests/translator/claude-kiro-direct.test.js
index 01e217092a..00d7745621 100644
--- a/tests/translator/claude-kiro-direct.test.js
+++ b/tests/translator/claude-kiro-direct.test.js
@@ -112,6 +112,17 @@ describe("Claude → Kiro (direct route)", () => {
expect(out.systemPrompt).toContain("24576");
});
+ it("maps Claude-format effort to GPT-5.6 Kiro CLI reasoning fields", () => {
+ const out = C2K({
+ output_config: { effort: "low" },
+ messages: [{ role: "user", content: "think lightly" }],
+ }, null, "gpt-5.6-sol");
+
+ expect(out.additionalModelRequestFields).toEqual({
+ reasoning: { effort: "low" },
+ });
+ });
+
it("sends Claude system as top-level systemPrompt and keeps a user-content fallback", () => {
const out = C2K({
system: "system-only instruction",
diff --git a/tests/unit/openai-to-kiro.test.js b/tests/unit/openai-to-kiro.test.js
index 8b1c97e868..13f67bef72 100644
--- a/tests/unit/openai-to-kiro.test.js
+++ b/tests/unit/openai-to-kiro.test.js
@@ -316,6 +316,44 @@ describe("openaiToKiroRequest", () => {
});
});
+ it("maps GPT-5.6 reasoning.effort high to Kiro CLI reasoning fields", () => {
+ const body = {
+ reasoning: { effort: "high" },
+ messages: [{ role: "user", content: "Think deeply" }]
+ };
+
+ const result = openaiToKiroRequest("gpt-5.6-sol", body, true, {});
+
+ expect(systemPromptOf(result)).toContain("24576");
+ expect(result.additionalModelRequestFields).toEqual({
+ reasoning: { effort: "high" },
+ });
+ });
+
+ it("maps prefixed GPT-5.6 reasoning_effort medium to Kiro CLI reasoning fields", () => {
+ const body = {
+ reasoning_effort: "medium",
+ messages: [{ role: "user", content: "Think normally" }]
+ };
+
+ const result = openaiToKiroRequest("kiro/gpt-5.6-terra", body, true, {});
+
+ expect(result.additionalModelRequestFields).toEqual({
+ reasoning: { effort: "medium" },
+ });
+ });
+
+ it("does not forward unsupported GPT-5.6 effort values", () => {
+ const body = {
+ reasoning: { effort: "ultra" },
+ messages: [{ role: "user", content: "Unknown effort" }]
+ };
+
+ const result = openaiToKiroRequest("gpt-5.6-luna", body, true, {});
+
+ expect(result.additionalModelRequestFields).toBeUndefined();
+ });
+
it("does not send additionalModelRequestFields for legacy Kiro model ids", () => {
const body = {
reasoning_effort: "high",