Skip to content

fix(compat): convert OpenAI reasoning effort to each Claude model's own contract - #227

Merged
HTExplicit merged 2 commits into
mainfrom
fix/claude-effort-conversion
Oct 2, 2026
Merged

HTExplicit merged 2 commits into
mainfrom
fix/claude-effort-conversion

Conversation

@HTExplicit

Copy link
Copy Markdown
Owner

Problem

OpenAI-format requests forwarded to Claude models other than Opus/Sonnet 5.5 mapped every reasoning effort the same way. This covers Responses and Chat Completions, including the native Anthropic-protocol paths. The single mapping was xhigh → max, plus thinking {type: enabled, budget_tokens} for every effort except low, with a default max_tokens of 8192.

Per the official Messages contract (checked 2026-10-02), that produces 400s:

Models Rejected because
Opus 4.7/4.8/5, Sonnet 5, Fable/Mythos 5.x budget_tokens
Opus 4.6, Sonnet 4.6, Opus 4.5, Mythos Preview at high and above budget ≥ max_tokens
Opus 4.5 max is not a valid level
Haiku/Sonnet 4.5 output_config.effort not supported
none/minimal on every non-5.5 model invalid effort sent

A read-only check of production found no such traffic in the last 30 days, so the bug is latent.

Change

One conversion (applyReasoningEffort) is driven by the effort catalog for the resolved upstream model. All call sites use it: ForwardAsResponses, ForwardAsChatCompletions, and the two native Anthropic-protocol paths.

  • Adaptive families:
    • thinking: adaptive at the requested level, or the nearest level the family lists (deeper first). xhigh stays native where listed and becomes max on Opus 4.6 / Sonnet 4.6.
    • none/minimal → lowest level with adaptive thinking. Anthropic recommends this over disabling thinking on Opus 5 and 4.8.
  • Budget families and Claude models without effort levels:
    • Budget thinking from medium up, with 1024 ≤ budget < max_tokens guaranteed. A client max_output_tokens is kept and the budget shrinks to fit; the default max_tokens grows by the budget, capped at 32000.
    • No budget thinking when a tool call is forced.
    • No output_config.effort for models without levels.
  • Sampling: a request that thinks drops temperature ≠ 1 and top_p < 0.95.
  • Model IDs: dotted OpenRouter IDs (claude-opus-4.7) normalise to their catalog family. The 5.5 checks stay exact.
  • Unchanged: the 5.5 branch and non-Claude upstreams (GLM/Kimi/DeepSeek behind Anthropic-compatible endpoints).
  • Usage log and billing read the effort that is actually forwarded.

Known and deferred: the Antigravity transformer ignores output_config.effort for native and compat traffic alike. There are 0 Antigravity accounts in production.

Verification

  • TestResponsesToAnthropicReasoningEffortByModelFamily (table across families, including sampling and forced-tool cases, plus the Chat Completions chain);
  • the 5.5 regression tests;
  • the effort catalog tests;
  • the compat pricing test;
  • gofmt, go build ./..., and go vet on the changed packages.

Not run: real model calls.

🤖 Generated with Claude Code

Codex and others added 2 commits October 2, 2026 21:27
…wn contract

OpenAI-format requests (Responses and Chat Completions, including the native
Anthropic-protocol paths) forwarded to Claude models other than Opus/Sonnet
5.5 mapped every reasoning effort the same way: xhigh became max and every
effort but low sent thinking {type:enabled, budget_tokens} against a default
max_tokens of 8192. That is rejected by Opus 4.7/4.8/5, Sonnet 5 and Fable
(budget_tokens), by Opus 4.6/Sonnet 4.6/Opus 4.5 at high and above (budget >=
max_tokens), by Opus 4.5 at max, and by Haiku/Sonnet 4.5 (no effort).

The effort is now converted with the effort catalog of the upstream model:
- adaptive families think adaptively at the requested level or the nearest
  level they list (xhigh stays xhigh where listed, becomes max on 4.6);
  none/minimal use the lowest level with adaptive thinking, as Anthropic
  recommends over disabling it;
- budget families (Opus 4.5, Mythos Preview) and Claude models without
  effort levels think on a budget from medium up, with 1024 <= budget <
  max_tokens guaranteed: a client max_tokens is kept and the budget shrinks,
  the default grows by the budget up to 32000; no budget thinking with a
  forced tool choice; models without levels never get output_config.effort;
- a request that thinks drops temperature != 1 and top_p < 0.95;
- dotted OpenRouter IDs (claude-opus-4.7) normalise to their family;
- non-Claude upstreams and the 5.5 branch are unchanged.

Production had no such traffic in the last 30 days (read-only ops check).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@HTExplicit
HTExplicit merged commit d81cd8b into main Oct 2, 2026
18 checks passed
@HTExplicit
HTExplicit deleted the fix/claude-effort-conversion branch October 2, 2026 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant