Skip to content

feat(ai): allow custom Anthropic-compatible providers to opt into adaptive thinking#4797

Closed
mbazso wants to merge 2 commits into
earendil-works:mainfrom
mbazso:feat/anthropic-adaptive-thinking-override
Closed

feat(ai): allow custom Anthropic-compatible providers to opt into adaptive thinking#4797
mbazso wants to merge 2 commits into
earendil-works:mainfrom
mbazso:feat/anthropic-adaptive-thinking-override

Conversation

@mbazso

@mbazso mbazso commented May 20, 2026

Copy link
Copy Markdown

closes #4790

I use the pi agent against a corporate proxy that exposes a custom anthropic-messages provider. After a new Anthropic model rolled out on the proxy, every request started failing with:

400 "thinking.type.enabled" is not supported for this model. Use
"thinking.type.adaptive" and "output_config.effort" to control thinking behavior.

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 contains opus-4-6, opus-4-7, or sonnet-4-6, so the alias misses every check and pi sends the legacy payload. thinkingLevelMap doesn't help — that branch is decided before the map is consulted.

This adds an opt-in compat.forceAdaptiveThinking?: boolean on AnthropicMessagesCompat. 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 field
  • packages/ai/src/providers/anthropic.tssupportsAdaptiveThinking() takes the model and consults the override first; getAnthropicCompat() excludes the new field from the Required<> shape because undefined carries meaning here (= use id-based detection)
  • packages/ai/test/anthropic-force-adaptive-thinking.test.ts — regression test covering legacy default, explicit true, explicit false, and reasoning-off
  • packages/ai/CHANGELOG.md

Verification

  • npm run check passes
  • New regression test passes (4/4)
  • Existing anthropic-thinking-disable and anthropic-opus-4-7-smoke tests still pass
  • ./test.sh hit pre-existing spawn ENOEXEC failures in packages/coding-agent grep tool tests on my Mac — reproduces on main without this change, unrelated

mbazso added 2 commits May 20, 2026 13:36
…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.
@mbazso mbazso force-pushed the feat/anthropic-adaptive-thinking-override branch from bb8990e to 81f4bec Compare May 20, 2026 11:37
@badlogic badlogic added the inprogress Issue is being worked on label May 22, 2026
@badlogic

Copy link
Copy Markdown
Collaborator

Reworked this locally in the maintainer branch.

Changes from the original PR shape:

  • Built-in adaptive Claude models now carry compat.forceAdaptiveThinking in generated model metadata instead of relying on request-time id substring checks.
  • The Anthropic provider reads that compat flag directly and custom Anthropic-compatible providers can set it for proxy aliases.
  • Added regression coverage for custom opt-in behavior and a guard test that asserts the exact built-in adaptive model set stays flagged.
  • Updated models.json validation and custom provider docs.

This comment is AI-generated by /wr

@badlogic badlogic closed this May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

inprogress Issue is being worked on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow custom Anthropic-compatible providers to opt into adaptive thinking

2 participants