What do you want to change?
Add an opt-in flag on Anthropic Messages model configs so custom Anthropic-compatible providers can declare that a model requires the adaptive thinking payload (thinking.type: "adaptive" plus output_config.effort) regardless of the model id.
In a code: an optional compat.forceAdaptiveThinking?: boolean on AnthropicMessagesCompat. When set, supportsAdaptiveThinking() returns the override, otherwise the existing id substring detection is used. Built-in Anthropic models are unchanged.
Why?
I use the pi agent with a corporate proxy that exposes a custom Anthropic-compatible provider, and I ran into an error after a new Anthropic model was released:
400 "thinking.type.enabled" is not supported for this model. Use "thinking.type.adaptive" and "output_config.effort" to control thinking behavior.
When I drilled into it, I found that my config refers to the newest model through the alias anthropic--claude-opus-latest, which the proxy resolves to whatever the latest available model is in the company tenant. pi sends
the legacy thinking payload for that id, and the upstream rejects it.
packages/ai/src/providers/anthropic.ts:supportsAdaptiveThinking() decides whether to send thinking.type: "adaptive" + output_config.effort (new) or thinking.type: "enabled" + budget_tokens (legacy) by substring-matching the model id against opus-4-6, opus-4-7, sonnet-4-6. Custom proxies that expose those models under their own id schemes never match, and thinkingLevelMap does not help because that branch is decided before the map is consulted.
Repro: in ~/.pi/agent/models.json, add a custom anthropic-messages provider with a model id like anthropic--claude-opus-latest and reasoning: true, set defaultThinkingLevel: "medium", and send any prompt against a proxy that requires the adaptive payload. The 400 above is returned. Built-in Anthropic models are unaffected.
How? (optional)
I have a patch on a fork: https://github.com/mbazso/pi/tree/feat/anthropic-adaptive-thinking-override
- Adds
forceAdaptiveThinking?: boolean to AnthropicMessagesCompat in packages/ai/src/types.ts.
supportsAdaptiveThinking() in packages/ai/src/providers/anthropic.ts now takes the model and checks model.compat?.forceAdaptiveThinking first, if not set falls back to the existing id-based detection.
getAnthropicCompat() returns Required<Omit<AnthropicMessagesCompat, "forceAdaptiveThinking">> because undefined carries meaning here (= use id-based detection).
- CHANGELOG entry under
### Added in packages/ai/CHANGELOG.md.
npm run check passes; existing anthropic-thinking-disable and anthropic-opus-4-7-smoke tests pass.
Happy to open a PR with a regression test under packages/ai/test/ if this looks reasonable.
What do you want to change?
Add an opt-in flag on Anthropic Messages model configs so custom Anthropic-compatible providers can declare that a model requires the adaptive thinking payload (
thinking.type: "adaptive"plusoutput_config.effort) regardless of the model id.In a code: an optional
compat.forceAdaptiveThinking?: booleanonAnthropicMessagesCompat. When set,supportsAdaptiveThinking()returns the override, otherwise the existing id substring detection is used. Built-in Anthropic models are unchanged.Why?
I use the pi agent with a corporate proxy that exposes a custom Anthropic-compatible provider, and I ran into an error after a new Anthropic model was released:
When I drilled into it, I found that my config refers to the newest model through the alias
anthropic--claude-opus-latest, which the proxy resolves to whatever the latest available model is in the company tenant. pi sendsthe legacy thinking payload for that id, and the upstream rejects it.
packages/ai/src/providers/anthropic.ts:supportsAdaptiveThinking()decides whether to sendthinking.type: "adaptive"+output_config.effort(new) orthinking.type: "enabled"+budget_tokens(legacy) by substring-matching the model id againstopus-4-6,opus-4-7,sonnet-4-6. Custom proxies that expose those models under their own id schemes never match, andthinkingLevelMapdoes not help because that branch is decided before the map is consulted.Repro: in
~/.pi/agent/models.json, add a customanthropic-messagesprovider with a model id likeanthropic--claude-opus-latestandreasoning: true, setdefaultThinkingLevel: "medium", and send any prompt against a proxy that requires the adaptive payload. The 400 above is returned. Built-in Anthropic models are unaffected.How? (optional)
I have a patch on a fork: https://github.com/mbazso/pi/tree/feat/anthropic-adaptive-thinking-override
forceAdaptiveThinking?: booleantoAnthropicMessagesCompatinpackages/ai/src/types.ts.supportsAdaptiveThinking()inpackages/ai/src/providers/anthropic.tsnow takes the model and checksmodel.compat?.forceAdaptiveThinkingfirst, if not set falls back to the existing id-based detection.getAnthropicCompat()returnsRequired<Omit<AnthropicMessagesCompat, "forceAdaptiveThinking">>becauseundefinedcarries meaning here (= use id-based detection).### Addedinpackages/ai/CHANGELOG.md.npm run checkpasses; existinganthropic-thinking-disableandanthropic-opus-4-7-smoketests pass.Happy to open a PR with a regression test under
packages/ai/test/if this looks reasonable.