diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index aa97a6b7f..f757493c8 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed Claude Fable 5 thinking-off requests to omit Anthropic's unsupported `thinking.type: "disabled"` payload ([#5567](https://github.com/earendil-works/pi/pull/5567) by [@tmustier](https://github.com/tmustier)). + ## [0.79.1] - 2026-06-09 ### Added diff --git a/packages/ai/scripts/generate-models.ts b/packages/ai/scripts/generate-models.ts index 3253de64a..5e5fff94d 100644 --- a/packages/ai/scripts/generate-models.ts +++ b/packages/ai/scripts/generate-models.ts @@ -299,7 +299,7 @@ function applyThinkingLevelMetadata(model: Model): void { (model.api === "anthropic-messages" || model.api === "bedrock-converse-stream") && model.id.includes("fable-5") ) { - mergeThinkingLevelMap(model, { xhigh: "xhigh" }); + mergeThinkingLevelMap(model, { off: null, xhigh: "xhigh" }); } if (model.api === "anthropic-messages" && isAnthropicAdaptiveThinkingModel(model.id)) { mergeAnthropicMessagesCompat(model, { forceAdaptiveThinking: true }); diff --git a/packages/ai/src/providers/anthropic.ts b/packages/ai/src/providers/anthropic.ts index 158311b07..efe4bd757 100644 --- a/packages/ai/src/providers/anthropic.ts +++ b/packages/ai/src/providers/anthropic.ts @@ -972,7 +972,7 @@ function buildParams( display, }; } - } else if (options?.thinkingEnabled === false) { + } else if (options?.thinkingEnabled === false && model.thinkingLevelMap?.off !== null) { params.thinking = { type: "disabled" }; } } diff --git a/packages/ai/test/anthropic-thinking-disable.test.ts b/packages/ai/test/anthropic-thinking-disable.test.ts index 5ee89b1ef..13d333e57 100644 --- a/packages/ai/test/anthropic-thinking-disable.test.ts +++ b/packages/ai/test/anthropic-thinking-disable.test.ts @@ -132,6 +132,13 @@ describe("Anthropic thinking disable payload", () => { expect(payload.output_config).toBeUndefined(); }); + it("omits thinking.type=disabled for Claude Fable 5 when thinking is off", async () => { + const payload = await capturePayload(getModel("anthropic", "claude-fable-5")); + + expect(payload.thinking).toBeUndefined(); + expect(payload.output_config).toBeUndefined(); + }); + it("uses adaptive thinking for Claude Opus 4.8 when reasoning is enabled", async () => { const payload = await capturePayload(getModel("anthropic", "claude-opus-4-8"), { reasoning: "high" }); diff --git a/packages/ai/test/supports-xhigh.test.ts b/packages/ai/test/supports-xhigh.test.ts index 80b3e683c..ec6dc87b5 100644 --- a/packages/ai/test/supports-xhigh.test.ts +++ b/packages/ai/test/supports-xhigh.test.ts @@ -20,10 +20,11 @@ describe("getSupportedThinkingLevels", () => { expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); }); - it("includes xhigh for Anthropic Claude Fable 5 on anthropic-messages API", () => { + it("includes xhigh but not off for Anthropic Claude Fable 5 on anthropic-messages API", () => { const model = getModel("anthropic", "claude-fable-5"); expect(model).toBeDefined(); expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); + expect(getSupportedThinkingLevels(model!)).not.toContain("off"); }); it("does not include xhigh for Claude Sonnet 4.5", () => { @@ -86,9 +87,10 @@ describe("getSupportedThinkingLevels", () => { expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); }); - it("includes xhigh for Bedrock Claude Fable 5", () => { + it("includes xhigh but not off for Bedrock Claude Fable 5", () => { const model = getModel("amazon-bedrock", "global.anthropic.claude-fable-5"); expect(model).toBeDefined(); expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); + expect(getSupportedThinkingLevels(model!)).not.toContain("off"); }); });