fix(bedrock): preserve adaptive thinking effort through the /v1/messages bridge - #36507
Conversation
…ges bridge
Claude Code drives Opus 4.7 with thinking {"type": "adaptive"} plus
output_config {"effort": "max"}. The anthropic-to-openai adapter
forwarded thinking verbatim for Claude models but dropped output_config,
and Bedrock Converse streams zero reasoningContent blocks for adaptive
thinking without an effort tier. Forward the effort subset of
output_config for Bedrock targets, accept it in the converse supported
params, and map it with the model's effort ceiling applied. Re-enable
the skipped e2e compat cell that catches this
Greptile SummaryThis PR preserves adaptive-thinking effort across the Anthropic Messages to Bedrock Converse bridge, including opaque application inference profile ARNs
Confidence Score: 5/5The PR appears safe to merge The previously reported application inference profile issue is fixed: current serialization recognizes the opaque ARN and preserves effort in the additional Bedrock request fields, with focused regression coverage
|
| Filename | Overview |
|---|---|
| litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py | Forwards non-format output configuration only for Bedrock-bound Claude requests while retaining separate structured-output translation |
| litellm/llms/bedrock/chat/converse_transformation.py | Supports explicit output configuration, applies known model ceilings, and completes serialization for opaque application inference profile ARNs |
| litellm/types/llms/openai.py | Adds the bridged output configuration field to the chat completion request type |
| tests/e2e/claude_code/thinking/test_bedrock_converse.py | Re-enables the end-to-end compatibility case that verifies Bedrock Converse emits thinking content |
| tests/test_litellm/llms/anthropic/experimental_pass_through/adapters/test_anthropic_experimental_pass_through_adapters_transformation.py | Covers effort preservation, format separation, and exclusion for non-Bedrock providers |
| tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py | Covers supported-parameter mapping, effort ceilings, and application profile ARN request serialization |
Reviews (2): Last reviewed commit: "fix(bedrock): forward output_config effo..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 0f41365. Configure here.
TLDR
Problem this solves:
thinking: {"type": "adaptive"}but droppedoutput_config: {"effort": ...}reasoningContentfor adaptive thinking without an effort tierHow it solves it:
output_configfor Bedrock targetsoutput_configbecomes a supported openai param for reasoning Claude and ARN models on Conversemap_openai_paramscarries it through with the model's Bedrock effort ceiling appliedRCA doc: https://app.notion.com/p/3b943b8acdab8197b710e0da01ce3773
User Flow
Before: a Claude Code user on Opus 4.7 via Bedrock (Converse) never sees extended thinking
claude-opus-4-7-bedrock-converse,thinking: {"type": "adaptive"}andoutput_config: {"effort": "max"}(what--effort maxproduces)content_block_startof typetextand no thinking block at all, so the CLI renders a plain answer with no reasoningno thinking content block observed in stream-json eventsAfter: the same request streams a thinking block before the text
content_block_startindex 0 of typethinking(with its signature), then the text block at index 1Relevant issues
RCA doc: https://app.notion.com/p/3b943b8acdab8197b710e0da01ce3773
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Live proxy against real AWS Bedrock in us-east-1, booted with
litellm --config tests/e2e/claude_code/test_config.yaml --host 127.0.0.1 --port 4110. Same curl before and afterBefore, at commit d8762bf (base), the stream has no thinking block:
After, at commit 929ee52 (this PR), identical request:
The e2e compat cell this PR re-enables, driving the real
claudeCLI with--effort maxagainst that same proxy, goes from[claude-opus-4-7-bedrock-converse] no thinking content block observed in stream-json eventsat d8762bf to all green at 929ee52:The regression tests were verified in both directions: with the
litellm/changes stashed, the adapter effort-preservation test (both model shapes), both converse param-mapping cases, and the ARN supported-param test fail; with them restored, all 276 tests across the two touched files passCommit 0f41365 extends this to opaque application inference profile ARNs, which passed the new param mapping but were still dropped at request serialization because the alias cannot resolve to an anthropic base model. The new serialization test (thinking plus effort both landing in
additionalModelRequestFieldsfor a profile ARN) fails at 929ee52 and passes with the commitQA run at head 0f41365 (2026-08-11). Real Claude Code CLI v2.1.227 driven interactively under tmux, before leg proxied at the merge base d8762bf and after leg at 0f41365, each with its own worktree, venv, env file, and port, real AWS Bedrock traffic throughout. Both legs ran the identical session, differing only in the proxy's commit:
Before, proxy at d8762bf (port 24576): the answer streams with no thinking block anywhere. The client's own session transcript records the assistant message as a single text block
After, proxy at 0f41365 (port 35886): the thinking block arrives with its signature ahead of the text, on both turns of the session
Control on the already-green invoke cell (claude-opus-4-7-bedrock-invoke, same proxy build, port 44637), pinning what parity means for a real user:
QA caveats, all observed live and none caused or worsened by this PR: on both Bedrock routes Opus 4.7 adaptive thinking arrives signature-only, so the interactive TUI shows no visible reasoning text on Converse or on the reference-good Invoke column, and billed output_tokens exceed the delivered text on both; this PR brings Converse to exact parity with Invoke, which is what the matrix cell measures. Separately, every Converse turn produced a hidden 400 before the 200 (Bedrock rejects
output_config.formaton Claude Code's structured-output side request) identically at base and at head, and not at all on Invoke; that is the pre-existing follow-up already listed under CaveatsType
🐛 Bug Fix
Caveats (if any)
output_configforwarding is scoped to Bedrock-destined models: other bridged providers (e.g. openrouter) acceptthinkingbut reject the raw param when drop_params is offthinkingalready flows for them; a profile fronting a non-Anthropic model would get a loud provider error instead of a silent dropoutput_config.formaton Claude Code's title-generation side requestQA runbook
litellm --config tests/e2e/claude_code/test_config.yaml --port 4000claude-opus-4-7-bedrock-converse,thinking: {"type": "adaptive"}andoutput_config: {"effort": "max"}(exact body in Proof of Fix above)content_block_startof typethinkingbefore the text blockbedrock_converse pass=3Final Attestation