Skip to content

fix(bedrock): preserve output_config.effort for Claude 4.6 on Invoke API#23971

Open
KevinZhao wants to merge 1 commit intoBerriAI:mainfrom
KevinZhao:fix/bedrock-invoke-output-config-effort-4-6
Open

fix(bedrock): preserve output_config.effort for Claude 4.6 on Invoke API#23971
KevinZhao wants to merge 1 commit intoBerriAI:mainfrom
KevinZhao:fix/bedrock-invoke-output-config-effort-4-6

Conversation

@KevinZhao
Copy link

Summary

Bedrock Invoke API previously stripped output_config unconditionally for all models (#22797). However, Claude 4.6 models (Opus 4.6 and Sonnet 4.6) support output_config.effort as a stable API parameter for controlling adaptive thinking effort level.

This PR makes the stripping conditional:

  • Claude 4.6+ models: preserve output_config so effort (low/medium/high/max) is forwarded to Bedrock
  • Older models: continue stripping output_config to avoid request rejection

Changes

  • litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py — conditional output_config pop for /v1/chat/completions → Bedrock Invoke path
  • litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py — same for /v1/messages → Bedrock Invoke path
  • litellm/types/llms/anthropic.py — add "max" to AnthropicOutputConfig.effort Literal type (Opus 4.6 exclusive)
  • Added tests for both preservation (4.6) and stripping (pre-4.6) scenarios on both paths

Test plan

  • test_bedrock_chat_invoke_preserves_output_config_for_claude_4_6 — Sonnet 4.6 effort=high, Opus 4.6 effort=max
  • test_bedrock_chat_invoke_strips_output_config_for_pre_4_6 — Sonnet 4.5, Opus 4.5
  • test_bedrock_messages_preserves_output_config_for_claude_4_6 — Opus 4.6 effort=max, Sonnet 4.6 effort=high
  • test_bedrock_messages_strips_output_config_for_pre_4_6 — Claude 3 Haiku, Sonnet 4, Opus 4.5
  • Existing test_output_config_removed_from_bedrock_chat_invoke_request still passes (regression)
pytest tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py -v
pytest tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py -v

…Invoke API

Bedrock Invoke previously stripped `output_config` unconditionally for all
models. Claude 4.6 (Opus/Sonnet) supports `output_config.effort` as a
stable API parameter for controlling adaptive thinking effort level.

This change makes the stripping conditional: preserve `output_config` for
Claude 4.6+ models, continue stripping for older models to avoid request
rejection.

Fixes both entry points:
- /v1/chat/completions → Bedrock Invoke (chat path)
- /v1/messages → Bedrock Invoke (messages path)

Also adds "max" to the AnthropicOutputConfig effort Literal type, as
effort="max" is supported by Claude Opus 4.6.
@vercel
Copy link

vercel bot commented Mar 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
litellm Ready Ready Preview, Comment Mar 18, 2026 7:33am

Request Review

@CLAassistant
Copy link

CLAassistant commented Mar 18, 2026

CLA assistant check
All committers have signed the CLA.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 18, 2026

Greptile Summary

This PR makes the Bedrock Invoke API's output_config stripping conditional: Claude 4.6+ models (Opus 4.6, Sonnet 4.6) preserve output_config.effort so it is forwarded to Bedrock, while pre-4.6 models continue to have it stripped to avoid request rejection. It also expands the AnthropicOutputConfig.effort Literal type to include "max" (Opus 4.6 exclusive).

Key changes:

  • litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.pyoutput_config pop is now conditional on AnthropicConfig._is_claude_4_6_model(model)
  • litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py — same conditional guard via AnthropicModelInfo._is_claude_4_6_model(model)
  • litellm/types/llms/anthropic.py — adds "max" to the effort Literal
  • Tests added for both paths (preserve for 4.6, strip for pre-4.6)

Concern:

  • Both transformation files use _is_claude_4_6_model, a hardcoded model-name string check. Per AGENTS.md §8 and the project's custom instruction, model capability flags must live in model_prices_and_context_window.json and be read via get_model_info (or an existing helper like supports_reasoning). Claude 4.6 models already carry "supports_reasoning": true in that JSON, so a data-driven guard is achievable today without adding new fields. Future models that gain output_config.effort support on Bedrock will require a code change here before users benefit, unless this is refactored to be config-driven.

Confidence Score: 2/5

  • The fix is functionally correct but relies on a hardcoded model-name check that violates the project's own architectural rule — future models won't benefit automatically.
  • The core logic (conditional strip vs preserve) is sound and the tests are thorough mock-only unit tests. However, _is_claude_4_6_model is a hardcoded string-matching function, which directly contradicts AGENTS.md §8 and custom rule 2605a1b1. The rule exists to prevent exactly this: users having to wait for a LiteLLM upgrade when a future model gains output_config.effort support on Bedrock Invoke. A data-driven approach using supports_reasoning (already true for all 4.6 models in the JSON) or a new supports_output_config_effort field would be compliant and more future-proof.
  • Both transformation files need attention: litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py (line 113) and litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py (line 425).

Important Files Changed

Filename Overview
litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py Conditionally preserves output_config for Claude 4.6 models using _is_claude_4_6_model — a hardcoded string check that violates the project rule against model-specific flags outside model_prices_and_context_window.json.
litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py Same hardcoded _is_claude_4_6_model violation as the chat path; additionally the comment numbering (5b appears before 5a) is inverted.
litellm/types/llms/anthropic.py Adds "max" to the AnthropicOutputConfig.effort Literal — a straightforward type-system fix that is accurate and non-breaking.
tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py Adds well-structured unit tests for both preservation and stripping paths; all calls are mocked (no real network calls).
tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py Adds equivalent coverage for the messages Invoke path; tests are mock-only and complete.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["litellm /v1/chat/completions or /v1/messages\n(with output_config.effort)"] --> B{Bedrock Invoke\ntransformation}

    B --> C{_is_claude_4_6_model?}

    C -- "Yes (Opus/Sonnet 4.6)" --> D["Keep output_config\nin request body"]
    C -- "No (pre-4.6)" --> E["Pop output_config\nfrom request body"]

    D --> F["Bedrock Invoke API\n→ effort forwarded"]
    E --> G["Bedrock Invoke API\n→ effort stripped"]

    style D fill:#c8f7c5,stroke:#27ae60
    style E fill:#fdecea,stroke:#e74c3c
    style C fill:#fef9e7,stroke:#f39c12
Loading

Last reviewed commit: "fix(bedrock): preser..."

Comment on lines +113 to +114
if not AnthropicConfig._is_claude_4_6_model(model):
_anthropic_request.pop("output_config", None)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Hardcoded model check violates AGENTS.md rule #8

_is_claude_4_6_model is a hardcoded string-match check. Per the project's custom rule and AGENTS.md §8 ("Do not hardcode model-specific flags"), model capability decisions must be driven by model_prices_and_context_window.json read via get_model_info (or an existing helper like supports_reasoning). Without this, any future model that gains output_config.effort support on Bedrock Invoke requires a code change here before users benefit — exactly the problem the rule was written to avoid.

All Claude 4.6 models already carry "supports_reasoning": true in the model-prices JSON, so supports_reasoning (or a new supports_output_config_effort flag added to the JSON) could drive this decision without touching the code for future models.

# Option A — reuse existing supports_reasoning helper (reads from model_prices_and_context_window.json)
from litellm.utils import supports_reasoning

if not (AnthropicConfig._is_claude_4_6_model(model) or supports_reasoning(model=model, custom_llm_provider=self.custom_llm_provider)):
    _anthropic_request.pop("output_config", None)

This same violation also exists at litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py:425.

Rule Used: What: Do not hardcode model-specific flags in the ... (source)

if not AnthropicModelInfo._is_claude_4_6_model(model):
anthropic_messages_request.pop("output_config", None)

# 5a. Remove `custom` field from tools (Bedrock doesn't support it)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Comment numbering out of order (5b before 5a)

The comment label # 5b. on line 422 appears in the file before # 5a. on line 428, which reverses the expected ordering and makes the numbering misleading when reading the code sequentially.

Suggested change
# 5a. Remove `custom` field from tools (Bedrock doesn't support it)
# 5a. Remove `custom` field from tools (Bedrock doesn't support it)

@codspeed-hq
Copy link
Contributor

codspeed-hq bot commented Mar 18, 2026

Merging this PR will not alter performance

✅ 16 untouched benchmarks


Comparing KevinZhao:fix/bedrock-invoke-output-config-effort-4-6 (34587d5) with main (cec3e9e)

Open in CodSpeed

@KevinZhao
Copy link
Author

CLA signed

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.

2 participants