diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 74aa15c4d..30b17a788 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixed - Fixed Claude models that accept mid-conversation system messages rejecting a session with a 400 (`role 'system' must precede an 'assistant' message`) when a system update was followed by an assistant reply with nothing to send to Anthropic, such as an empty reply or another model's reasoning-only reply ([#11091](https://github.com/earendil-works/pi/issues/11091)) +- Fixed Claude models with mid-conversation effort failing with `Invalid effort level` on accounts whose organization caps effort below `high`, even at `low` or `medium` thinking, by sending a fixed `low` top-level effort ([#10063](https://github.com/earendil-works/pi/issues/10063)) ## [1.4.0] - 2026-10-21 diff --git a/packages/ai/src/api/anthropic-messages.ts b/packages/ai/src/api/anthropic-messages.ts index b43b11c0e..00d820341 100644 --- a/packages/ai/src/api/anthropic-messages.ts +++ b/packages/ai/src/api/anthropic-messages.ts @@ -1300,7 +1300,10 @@ function buildParams( display: options?.thinkingDisplay ?? "summarized", block_binding: { prefix_mismatch_behavior: "drop_block" }, }; - params.output_config = { effort: "high" }; + // Effort markers set the level for every reply. The top-level effort is part of the cached + // prompt, so it stays fixed. It is "low" because organizations can cap effort and reject + // requests containing any level above the cap. + params.output_config = { effort: "low" }; } else if (model.reasoning && options?.thinkingEnabled) { // Default to "summarized" so Opus 4.7 and Mythos Preview behave like // older Claude 4 models (whose API default is also "summarized"). diff --git a/packages/ai/test/anthropic-mid-conversation-effort.test.ts b/packages/ai/test/anthropic-mid-conversation-effort.test.ts index 3ba1fb2bc..54dad1d95 100644 --- a/packages/ai/test/anthropic-mid-conversation-effort.test.ts +++ b/packages/ai/test/anthropic-mid-conversation-effort.test.ts @@ -108,8 +108,8 @@ describe("Anthropic mid-conversation effort", () => { content: [], output_config: { effort: "high" }, }); - expect(first.payload.output_config).toEqual({ effort: "high" }); - expect(second.payload.output_config).toEqual({ effort: "high" }); + expect(first.payload.output_config).toEqual({ effort: "low" }); + expect(second.payload.output_config).toEqual({ effort: "low" }); expect(second.payload.thinking).toEqual({ type: "adaptive", display: "summarized",