fix(auxiliary): pass reasoning_config and extra_body through to auxiliary Anthropic calls - #37217
fix(auxiliary): pass reasoning_config and extra_body through to auxiliary Anthropic calls#37217dorokuma wants to merge 1 commit into
Conversation
…iary Anthropic calls
Two related bugs in _AnthropicCompletionsAdapter.create() in
agent/auxiliary_client.py silently discard caller-supplied
reasoning_config and extra_body on the Anthropic-Messages
auxiliary-protocol path:
* Bug A: reasoning_config=None was hardcoded at L1000, so the
reasoning_config parameter on build_anthropic_kwargs was
unreachable for any auxiliary task. The main agent path
(agent/transports/anthropic.py) already reads
reasoning_config from caller params; this PR aligns the
auxiliary adapter with the same pattern.
* Bug B: create(**kwargs) accepts an OpenAI-style kwargs
payload from the caller but only forwards a hand-picked
subset to self._client.messages.create(). Any caller-supplied
extra_body (e.g. thinking control, metadata, service_tier,
vendor-specific fields) was dropped on the floor. The
codex/responses transport in the same file already merges
extra_body; the Anthropic branch is the gap.
This unlocks the caller-supplied extra_body path so auxiliary
callers can set per-vendor request fields (including
thinking: {type: "disabled"} for Anthropic-compatible vendors
that require an explicit disable on the wire), and lets the
reasoning_config kwarg flow into build_anthropic_kwargs like the
main agent does. Both changes are backward-compatible for
callers that don't pass the affected kwargs.
Affected providers (all routed through _AnthropicCompletionsAdapter
via _maybe_wrap_anthropic): anthropic (native), minimax /
minimax-cn, kimi-coding / kimi-coding-cn, z.ai / GLM, and any
custom /anthropic-suffixed endpoint. See PR description for
related issues (#35566, #7209, #16533, #32813, #29248).
|
Thanks for identifying the auxiliary Anthropic parity gap. It still exists on current main: Problems
Suggested changes
Automated hermes-sweeper review. |
…sions) Five tests for the salvaged #37217 Bug B fix: vendor-field passthrough, reasoning-key + private-key exclusion, merge-over-existing (fast-mode speed), no-extra_body regression guard, reasoning-only adds nothing. Live probes against api.anthropic.com informed the exclusion design: Anthropic strictly validates the request body (unknown keys 400 with 'Extra inputs are not permitted'), so the passthrough forwards only caller-configured fields and never the OpenAI-shaped reasoning dict (translated natively) or _-private plumbing keys.
|
Both halves of this PR are now on main — closing with full credit, @dorokuma. Your diagnosis was exactly right on both counts: Bug A ( Bug B ( One scoping change on top of your merge block, informed by live probes against api.anthropic.com: the Messages API strictly rejects unknown body keys (400 "Extra inputs are not permitted"), including the OpenAI-shaped Thanks for the precise two-bug analysis — the PR body's line-level diagnosis made this salvage straightforward. |
|
Appreciate the thorough follow-up and the credit — glad the analysis helped make the fix straightforward. |
…sions) Five tests for the salvaged NousResearch#37217 Bug B fix: vendor-field passthrough, reasoning-key + private-key exclusion, merge-over-existing (fast-mode speed), no-extra_body regression guard, reasoning-only adds nothing. Live probes against api.anthropic.com informed the exclusion design: Anthropic strictly validates the request body (unknown keys 400 with 'Extra inputs are not permitted'), so the passthrough forwards only caller-configured fields and never the OpenAI-shaped reasoning dict (translated natively) or _-private plumbing keys.
…sions) Five tests for the salvaged NousResearch#37217 Bug B fix: vendor-field passthrough, reasoning-key + private-key exclusion, merge-over-existing (fast-mode speed), no-extra_body regression guard, reasoning-only adds nothing. Live probes against api.anthropic.com informed the exclusion design: Anthropic strictly validates the request body (unknown keys 400 with 'Extra inputs are not permitted'), so the passthrough forwards only caller-configured fields and never the OpenAI-shaped reasoning dict (translated natively) or _-private plumbing keys.
…sions) Five tests for the salvaged NousResearch#37217 Bug B fix: vendor-field passthrough, reasoning-key + private-key exclusion, merge-over-existing (fast-mode speed), no-extra_body regression guard, reasoning-only adds nothing. Live probes against api.anthropic.com informed the exclusion design: Anthropic strictly validates the request body (unknown keys 400 with 'Extra inputs are not permitted'), so the passthrough forwards only caller-configured fields and never the OpenAI-shaped reasoning dict (translated natively) or _-private plumbing keys.
Summary
_AnthropicCompletionsAdapter.create()inagent/auxiliary_client.pysilently discards caller-suppliedreasoning_configandextra_bodyfor every auxiliary task routed through the Anthropic-Messages protocol (anthropic, minimax, kimi-coding, z.ai, any custom/anthropic-suffixed endpoint). The main agent path (agent/transports/anthropic.py) already handles these correctly; this PR aligns the auxiliary adapter with the same pattern.Two bugs, one root cause
Bug A —
reasoning_confighardcoded toNone(L1000)The main agent path already does this right:
Bug B —
extra_bodydropped between caller and SDK (L1012)create(**kwargs)accepts the caller's OpenAI-style kwargs but only forwards a hand-picked subset toself._client.messages.create(**anthropic_kwargs).extra_body(and any other caller-supplied field) never reaches the wire. The codex/responses transport in the same file already mergesextra_body; the Anthropic branch is the gap.Fix
Behavior
reasoning_configorextra_bodysee no change.extra_bodyfor the auxiliary path. Callers can now passextra_body={"thinking": {"type": "disabled"}}(or any vendor field) via the standard OpenAI-style kwarg and have it reach the Anthropic SDK.reasoning_configkwarg now flows intobuild_anthropic_kwargslike the main agent does, instead of being silently replaced withNone.Tests
Add a unit test under
tests/agent/mockingself._client.messages.create()and asserting:reasoning_config={"enabled": True, "effort": "medium"}from the caller →build_anthropic_kwargsis invoked with that value.extra_body={"thinking": {"type": "disabled"}}from the caller → kwargs tomessages.create()include the merged dict underextra_body.messages.create()are byte-identical to today (no regression).Related issues
Same family of issue, different surfaces — flagging for reviewers:
extra_bodyignored from config.yamlzaiprovider never returns reasoning_content — Hermes sendsextra_body.reasoning(OpenRouter-style) but Z.AI expectsextra_body.thinking={"type":"enabled"}#16533 — Z.AI/GLMreasoning_contentnever returned (root cause: extra_body shape)/reasoning maxrejected by frontend even though Anthropic adapter already supports it end-to-end #29248 —/reasoning maxrejected by frontend