feat(ai): allow custom Anthropic-compatible providers to opt into adaptive thinking#4797
Closed
mbazso wants to merge 2 commits into
Closed
feat(ai): allow custom Anthropic-compatible providers to opt into adaptive thinking#4797mbazso wants to merge 2 commits into
mbazso wants to merge 2 commits into
Conversation
…ptive thinking
Adaptive thinking ("thinking.type": "adaptive" plus output_config.effort) was
previously selected only when the model id matched a hardcoded substring list
(opus-4-6, opus-4-7, sonnet-4-6). Custom Anthropic-compatible providers that
expose Opus 4.7 / Sonnet 4.6 under their own id schemes (e.g. corporate proxies
serving "anthropic--claude-opus-latest") fell back to the legacy
"thinking.type": "enabled" payload, which the upstream now rejects with:
"thinking.type.enabled" is not supported for this model. Use
"thinking.type.adaptive" and "output_config.effort" to control thinking
behavior.
Add an optional compat.forceAdaptiveThinking boolean on Anthropic Messages
models. When set, supportsAdaptiveThinking returns the override; otherwise the
existing id-based detection is used. Built-in Anthropic models are unchanged.
Capture-payload tests against a custom anthropic-messages model whose id does not match any built-in adaptive substring (mirroring corporate proxy schemes such as anthropic--claude-opus-latest): - Default (no override) sends the legacy thinking.type=enabled payload, which reproduces the upstream 400 in production. - compat.forceAdaptiveThinking=true sends thinking.type=adaptive plus output_config.effort. - compat.forceAdaptiveThinking=false forces the legacy payload (explicit opt-out). - Reasoning off keeps thinking.type=disabled regardless of the override.
bb8990e to
81f4bec
Compare
Collaborator
|
Reworked this locally in the maintainer branch. Changes from the original PR shape:
This comment is AI-generated by |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
closes #4790
I use the pi agent against a corporate proxy that exposes a custom
anthropic-messagesprovider. After a new Anthropic model rolled out on the proxy, every request started failing with:My config refers to the latest model through an alias like
anthropic--claude-opus-latest.supportsAdaptiveThinking()only flips to the new payload format when the id containsopus-4-6,opus-4-7, orsonnet-4-6, so the alias misses every check and pi sends the legacy payload.thinkingLevelMapdoesn't help — that branch is decided before the map is consulted.This adds an opt-in
compat.forceAdaptiveThinking?: booleanonAnthropicMessagesCompat. When set,supportsAdaptiveThinking()uses the override; otherwise the existing id detection runs unchanged. Built-in Anthropic models behave exactly as before.Files touched:
packages/ai/src/types.ts— new fieldpackages/ai/src/providers/anthropic.ts—supportsAdaptiveThinking()takes the model and consults the override first;getAnthropicCompat()excludes the new field from theRequired<>shape becauseundefinedcarries meaning here (= use id-based detection)packages/ai/test/anthropic-force-adaptive-thinking.test.ts— regression test covering legacy default, explicittrue, explicitfalse, and reasoning-offpackages/ai/CHANGELOG.mdVerification
npm run checkpassesanthropic-thinking-disableandanthropic-opus-4-7-smoketests still pass./test.shhit pre-existingspawn ENOEXECfailures inpackages/coding-agentgrep tooltests on my Mac — reproduces onmainwithout this change, unrelated