fix(providers/anthropic): convert reasoning effort to budget thinking on pre-4.6 models#47
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7b40c065b0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
7b40c06 to
ad7b86b
Compare
ad7b86b to
97d27c8
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 97d27c873f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…pic models A model config with reasoning_effort on a legacy Anthropic model such as claude-haiku-4-5 failed every generation with HTTP 400 "adaptive thinking is not supported on this model", because the fantasy Anthropic provider always serialized effort as adaptive thinking plus output_config.effort. Bump the coder/fantasy pin to coder/fantasy#47, which converts effort into enabled budget thinking (budget derived from max_tokens) on models older than Claude 4.6 and keeps the adaptive shape for newer ones. Effort values outside the API enum are normalized, and none now disables thinking entirely. Update the compaction override test to cover both the legacy and the adaptive-capable request shapes, and add a regression test asserting a claude-haiku-4-5 config with reasoning_effort produces enabled thinking with the derived budget and no output_config.
97d27c8 to
be69f8e
Compare
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: be69f8e870
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
be69f8e to
81ae747
Compare
|
@codex review |
…pic models A model config with reasoning_effort on a legacy Anthropic model such as claude-haiku-4-5 failed every generation with HTTP 400 "adaptive thinking is not supported on this model", because the fantasy Anthropic provider always serialized effort as adaptive thinking plus output_config.effort. Bump the coder/fantasy pin to coder/fantasy#47, which converts effort into enabled budget thinking (budget derived from max_tokens) on models older than Claude 4.6 and keeps the adaptive shape for newer ones. Effort values outside the API enum are normalized, and none now disables thinking entirely. Update the compaction override test to cover both the legacy and the adaptive-capable request shapes, and add a regression test asserting a claude-haiku-4-5 config with reasoning_effort produces enabled thinking with the derived budget and no output_config.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 81ae747916
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
81ae747 to
1118bd7
Compare
|
@codex review |
…pic models A model config with reasoning_effort on a legacy Anthropic model such as claude-haiku-4-5 failed every generation with HTTP 400 "adaptive thinking is not supported on this model", because the fantasy Anthropic provider always serialized effort as adaptive thinking plus output_config.effort. Bump the coder/fantasy pin to coder/fantasy#47, which converts effort into enabled budget thinking (budget derived from max_tokens) on models older than Claude 4.6 and keeps the adaptive shape for newer ones. Effort values outside the API enum are normalized, and none now disables thinking entirely. Update the compaction override test to cover both the legacy and the adaptive-capable request shapes, and add a regression test asserting a claude-haiku-4-5 config with reasoning_effort produces enabled thinking with the derived budget and no output_config.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1118bd7aef
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
1118bd7 to
01904cc
Compare
|
@codex review |
…pic models A model config with reasoning_effort on a legacy Anthropic model such as claude-haiku-4-5 failed every generation with HTTP 400 "adaptive thinking is not supported on this model", because the fantasy Anthropic provider always serialized effort as adaptive thinking plus output_config.effort. Bump the coder/fantasy pin to coder/fantasy#47, which converts effort into enabled budget thinking (budget derived from max_tokens) on models older than Claude 4.6 and keeps the adaptive shape for newer ones. Effort values outside the API enum are normalized, and none now disables thinking entirely. Update the compaction override test to cover both the legacy and the adaptive-capable request shapes, and add a regression test asserting a claude-haiku-4-5 config with reasoning_effort produces enabled thinking with the derived budget and no output_config.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 01904cc959
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… on pre-4.6 models
Effort previously always sent thinking type "adaptive" plus
output_config.effort, which models older than Claude 4.6 reject with
an HTTP 400 ("adaptive thinking is not supported on this model").
- Gate the adaptive path on supportsAdaptiveThinking (Claude >= 4.6,
parsed from the model ID, tolerant of Bedrock prefixes and both
name orders; unparseable names are treated as legacy).
- On legacy models, convert effort into enabled thinking with a
budget derived from max_tokens (ratios mirror the coder/aibridge
shim), omitting thinking when the budget would fall below the
API's 1024-token minimum.
- Normalize effort values outside the output_config.effort enum:
minimal maps to low, xhigh maps to max, and none disables thinking
entirely.
01904cc to
fdf4de1
Compare
|
@codex review |
…pic models A model config with reasoning_effort on a legacy Anthropic model such as claude-haiku-4-5 failed every generation with HTTP 400 "adaptive thinking is not supported on this model", because the fantasy Anthropic provider always serialized effort as adaptive thinking plus output_config.effort. Bump the coder/fantasy pin to coder/fantasy#47, which converts effort into enabled budget thinking (budget derived from max_tokens) on models older than Claude 4.6 and keeps the adaptive shape for newer ones. Effort values outside the API enum are normalized, and none now disables thinking entirely. Update the compaction override test to cover both the legacy and the adaptive-capable request shapes, and add a regression test asserting a claude-haiku-4-5 config with reasoning_effort produces enabled thinking with the derived budget and no output_config.
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Run the scanner with Go 1.26.5 so the stdlib crypto/tls finding (GO-2026-5856) is fixed, and bump golang.org/x/image to v0.43.0 for GO-2026-5061.
coder/fantasy#47 merged; replace the PR-head pseudo-version with the squash commit a63de4b40315 on coder_2_33 (identical tree).
## Problem
A chat model config with `reasoning_effort` set on a pre-4.6 Anthropic
model (for example `claude-haiku-4-5`) fails every generation with HTTP
400 `adaptive thinking is not supported on this model`, surfaced in chat
as "Anthropic returned an unexpected error." The fantasy Anthropic
provider always serialized effort as `thinking: {type: "adaptive"}` plus
`output_config.effort`, a shape only Claude 4.6+ accepts.
## Changes
- Bump the coder/fantasy pin to include coder/fantasy#47: the provider
now converts effort into `{type: "enabled", budget_tokens}` on models
older than Claude 4.6, with the budget derived from the call's
`max_tokens` (aibridge-mirroring ratios, 1024-token API floor; below the
floor thinking is omitted, which keeps small-budget calls like title
generation working). Adaptive-capable models keep the current shape, and
Opus 4.5 keeps `output_config.effort` alongside the derived budget since
it supports effort without adaptive thinking. Models older than Claude
3.7 predate extended thinking, so effort sends no thinking at all there.
`minimal` is normalized to `low`, `xhigh` falls back to `max` on
adaptive models that predate the xhigh tier (Claude 4.7+); effort `none`
disables thinking, including an explicit `thinking: {type: "disabled"}`
on Claude 5+ models that otherwise run adaptive thinking by default. The
Bedrock provider wraps the Anthropic one, so both are covered, and
Vertex-style `@date` model IDs parse correctly.
- `TestActiveServer_CompactionModelOverride` previously codified the
buggy shape (asserting `output_config.effort` sent to
`claude-3-5-haiku-latest`). The summary-routing subtest is now a
three-case table: pre-thinking override models (Claude 3.5) expect no
thinking, legacy budget-thinking ones (Haiku 4.5) expect enabled
thinking with the derived budget, adaptive-capable ones still expect
`output_config.effort`.
- New regression test `TestActiveServer_AnthropicModelReasoningEffort`:
a `claude-haiku-4-5` config with `reasoning_effort` produces enabled
thinking with the derived budget and no `output_config` on the wire, and
a `claude-sonnet-5` config with effort `none` sends an explicit thinking
disable.
- `chattest.AnthropicRequest` gains a `Thinking` field so tests can
assert the thinking config.
- One-sentence note in the chatd ARCHITECTURE reasoning-effort section.
No chatd production code changes: `ApplyReasoningEffort` keeps setting
`Effort`, which is now valid for every Anthropic model.
## Validation
- `go test ./coderd/x/chatd/...` passes (19 packages).
- Fork PR validated separately: full fantasy test suite plus new
provider unit tests (version gating incl. Vertex/Bedrock IDs, budget
derivation, floor behavior, normalization, effort `none` incl. Claude 5+
disable, Opus 4.5 effort preservation, sampling-param stripping),
golangci-lint clean.
Closes
[CODAGT-812](https://linear.app/codercom/issue/CODAGT-812/reasoning-effort-on-pre-46-anthropic-models-fails-generations-with).
> This PR was authored by Mux, an AI coding agent, acting on Mike's
behalf.
Problem
Setting
ProviderOptions.Effortalways sendsthinking: {type: "adaptive"}plusoutput_config.effort. Models older than Claude 4.6 (Haiku 4.5, Sonnet 4.5, all 3.x) reject that shape with HTTP 400adaptive thinking is not supported on this model, so any caller that applies an effort dial to a legacy Anthropic model gets a hard failure on every request.Related latent bug: the API's
output_config.effortenum islow|medium|high|max, but callers can pass wider scales (none,minimal,xhigh), which were forwarded raw.Changes
supportsAdaptiveThinking: Claude >= 4.6 parsed from the model ID, tolerant of Bedrock prefixes/suffixes (us.anthropic.claude-haiku-4-5-20251001-v1:0) and both name orders (claude-sonnet-4-6,claude-3-5-haiku). Unparseable names fail closed to legacy, so a bad parse degrades to the safe enabled shape, never a 400. Theclaude-mythos-previewallowlist is kept.{type: "enabled", budget_tokens}derived from the per-callmax_tokens(ratios mirror the coder/aibridge Anthropic shim: low .2, medium .5, high .8, xhigh .9, max .95, minimal = 1024 floor). If the derived budget would fall below the API's 1024-token minimum, thinking is omitted entirely (keeps small-max_tokens calls like title generation working). The derived budget wins over a configuredThinking.BudgetTokensso the effort dial stays live;Effort == nilbehavior is unchanged.thinking_displayand strippingtemperature/top_p/top_kwith warnings (extracted into a shared helper).minimal -> low,xhigh -> max. NewEffortNone(none) disables thinking entirely on any model.The Bedrock provider wraps this one, so the fix covers Bedrock model IDs too.
Validation
go test ./...passes.none, normalization on adaptive models, and sampling-param stripping with warnings.