You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[bug] Anthropic thinking block is forwarded to openai_responses clients as reasoning.type (OpenAI 400) #1012
When an Anthropic Messages request that carries a thinking block is routed to an openai_responses client, the translator copies the Anthropic thinking object verbatim into the Responses reasoning field. OpenAI rejects the request:
This breaks every Claude Agent SDK / Claude Code session pointed at an OpenAI reasoning model through Switchyard 0.3.0, because the SDK sends thinking ({"type":"adaptive"} on current models, {"type":"enabled","budget_tokens":N} on older ones) on every turn.
Where
switchyard-translation/src/codecs/anthropic/buffered.rs:80 — ReasoningParams.raw is set to body.get("thinking").cloned() (the Anthropic-shaped object).
switchyard-translation/src/codecs/responses/buffered.rs:260-270 — the encoder starts from request.reasoning.raw, inserts effort, and emits the result as reasoning. The Anthropic keys (type, budget_tokens) survive.
The openai_chat encoder only emits reasoning_effort from request.reasoning.effort, so chat clients are unaffected.
Reproduce (0.3.0, switchyard-server, route → openai_responses client, model gpt-5.5)
→ 400 Unknown parameter: 'reasoning.type'. The same request with "output_config": {"effort": "medium"} instead of thinking succeeds (the effort is mapped to reasoning.effort correctly). thinking: {"type":"enabled","budget_tokens":2000} fails the same way.
Expected
raw from a different wire format should not be replayed into the Responses reasoning object. Either carry raw only when the source format was already openai_responses, or build the Responses reasoning from the normalized fields (effort; optionally summary) and drop unknown keys. Mapping Anthropic budget_tokens to a Responses effort tier would be a bonus but is not needed to unbreak clients.
Workaround we use
Set MAX_THINKING_TOKENS=0 on the Claude Agent SDK subprocess for routes that terminate on openai_responses, so the SDK omits the thinking block; the model still reasons at the effort passed through output_config.effort.
This looks fixed on current main, so it may be closable.
The Responses encoder no longer replays an Anthropic thinking object into reasoning. In crates/switchyard-translation/src/codecs/responses/buffered.rs, the Anthropic branch now builds reasoning from the normalized fields only: effort from output_config, and effort: "none" when thinking is disabled. The Anthropic keys (type, budget_tokens) are dropped rather than forwarded, so there is no reasoning.type for OpenAI to reject.
That landed in #840 (merged 2026-09-23), which also added the test anthropic_thinking_to_responses_uses_normalized_effort covering adaptive, enabled with a budget_tokens, and disabled thinking. I re-ran that test against current main (4cbb2d1) and it passes.
This report was against the 0.3.0 release build, which predates the fix. One residual from the same area is tracked separately: open PR #856 reports the dropped budget_tokens as a lossy conversion.
Happy to be corrected if a route still reproduces the 400 on current main.
Thanks — confirmed against main: the Anthropic branch in codecs/responses/buffered.rs now keeps only the disabled → effort: "none" mapping, so the reasoning.type leak is gone. Our report was indeed against the v0.3.0 release build (cargo install --locked switchyard-server --version 0.3.0), and #840 landed the day after that tag.
Since v0.3.0 is still the latest release on crates.io, every Claude Agent SDK / Claude Code user who installs the released server hits this on their first turn against an OpenAI reasoning model. Is a 0.3.1 patch release (or a 0.4.0) planned? Until one exists we're keeping a client-side workaround (MAX_THINKING_TOKENS=0 on the SDK subprocess for Responses routes). Fine to close from our side once the release question is answered.
Activity
joshuacox commentedon Oct 16, 2026
This looks fixed on current
main, so it may be closable.The Responses encoder no longer replays an Anthropic
thinkingobject intoreasoning. Incrates/switchyard-translation/src/codecs/responses/buffered.rs, the Anthropic branch now buildsreasoningfrom the normalized fields only:effortfromoutput_config, andeffort: "none"when thinking is disabled. The Anthropic keys (type,budget_tokens) are dropped rather than forwarded, so there is noreasoning.typefor OpenAI to reject.That landed in #840 (merged 2026-09-23), which also added the test
anthropic_thinking_to_responses_uses_normalized_effortcoveringadaptive,enabledwith abudget_tokens, anddisabledthinking. I re-ran that test against currentmain(4cbb2d1) and it passes.This report was against the 0.3.0 release build, which predates the fix. One residual from the same area is tracked separately: open PR #856 reports the dropped
budget_tokensas a lossy conversion.Happy to be corrected if a route still reproduces the 400 on current
main.shakhal commentedon Oct 16, 2026
Thanks — confirmed against main: the Anthropic branch in
codecs/responses/buffered.rsnow keeps only the disabled →effort: "none"mapping, so thereasoning.typeleak is gone. Our report was indeed against the v0.3.0 release build (cargo install --locked switchyard-server --version 0.3.0), and #840 landed the day after that tag.Since v0.3.0 is still the latest release on crates.io, every Claude Agent SDK / Claude Code user who installs the released server hits this on their first turn against an OpenAI reasoning model. Is a 0.3.1 patch release (or a 0.4.0) planned? Until one exists we're keeping a client-side workaround (
MAX_THINKING_TOKENS=0on the SDK subprocess for Responses routes). Fine to close from our side once the release question is answered.