diff --git a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py index 7936b6ea644..d175dcbfda4 100644 --- a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py @@ -107,9 +107,11 @@ def transform_request( _anthropic_request.pop("stream", None) # Bedrock Invoke doesn't support output_format parameter _anthropic_request.pop("output_format", None) - # Bedrock Invoke doesn't support output_config parameter - # Fixes: https://github.com/BerriAI/litellm/issues/22797 - _anthropic_request.pop("output_config", None) + # Bedrock Invoke supports output_config (effort) for Claude 4.6+ models, + # but older models do not — strip it to avoid request rejection. + # Ref: https://github.com/BerriAI/litellm/issues/22797 + if not AnthropicConfig._is_claude_4_6_model(model): + _anthropic_request.pop("output_config", None) if "anthropic_version" not in _anthropic_request: _anthropic_request["anthropic_version"] = self.anthropic_version diff --git a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py index e31820d7631..0cdebfb9611 100644 --- a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py @@ -419,9 +419,11 @@ def transform_anthropic_messages_request( anthropic_messages_request=anthropic_messages_request, ) - # 5b. Strip `output_config` — Bedrock Invoke doesn't support it - # Fixes: https://github.com/BerriAI/litellm/issues/22797 - anthropic_messages_request.pop("output_config", None) + # 5b. Bedrock Invoke supports output_config (effort) for Claude 4.6+ models, + # but older models do not — strip it to avoid request rejection. + # Ref: https://github.com/BerriAI/litellm/issues/22797 + 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) # Claude Code sends `custom: {defer_loading: true}` on tool definitions, diff --git a/litellm/types/llms/anthropic.py b/litellm/types/llms/anthropic.py index 37044c2b4f5..e23f3f3a866 100644 --- a/litellm/types/llms/anthropic.py +++ b/litellm/types/llms/anthropic.py @@ -39,7 +39,7 @@ class AnthropicOutputSchema(TypedDict, total=False): class AnthropicOutputConfig(TypedDict, total=False): """Configuration for controlling Claude's output behavior.""" - effort: Literal["high", "medium", "low"] + effort: Literal["high", "medium", "low", "max"] class AnthropicMessagesTool(TypedDict, total=False): diff --git a/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py b/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py index cb05531c2f8..4452bc2f17f 100644 --- a/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py +++ b/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py @@ -420,6 +420,82 @@ def test_output_config_removed_from_bedrock_chat_invoke_request(): assert result["max_tokens"] == 100 +def test_bedrock_chat_invoke_preserves_output_config_for_claude_4_6(): + """ + Claude 4.6 models support output_config.effort on Bedrock Invoke. + Verify that output_config is preserved (not stripped) for these models + on the /v1/chat/completions -> Bedrock Invoke path. + """ + config = AmazonAnthropicClaudeConfig() + messages = [{"role": "user", "content": "test"}] + + # Sonnet 4.6 supports effort=high (not max) + optional_params = { + "max_tokens": 128000, + "thinking": {"type": "adaptive"}, + "output_config": {"effort": "high"}, + } + result = config.transform_request( + model="global.anthropic.claude-sonnet-4-6", + messages=messages, + optional_params=optional_params, + litellm_params={}, + headers={}, + ) + assert "output_config" in result, ( + "output_config should be preserved for Claude Sonnet 4.6" + ) + assert result["output_config"]["effort"] == "high" + + # Opus 4.6 supports effort=max + optional_params = { + "max_tokens": 128000, + "thinking": {"type": "adaptive"}, + "output_config": {"effort": "max"}, + } + result = config.transform_request( + model="global.anthropic.claude-opus-4-6-v1", + messages=messages, + optional_params=optional_params, + litellm_params={}, + headers={}, + ) + assert "output_config" in result, ( + "output_config should be preserved for Claude Opus 4.6" + ) + assert result["output_config"]["effort"] == "max" + + +def test_bedrock_chat_invoke_strips_output_config_for_pre_4_6(): + """ + Pre-4.6 models do not support output_config on Bedrock Invoke. + Verify that output_config is still stripped for these models. + """ + config = AmazonAnthropicClaudeConfig() + messages = [{"role": "user", "content": "test"}] + + for model_id in [ + "anthropic.claude-sonnet-4-20250514-v1:0", + "global.anthropic.claude-opus-4-5-20251101-v1:0", + ]: + optional_params = { + "max_tokens": 100, + "output_config": {"effort": "high"}, + } + + result = config.transform_request( + model=model_id, + messages=messages, + optional_params=optional_params, + litellm_params={}, + headers={}, + ) + + assert "output_config" not in result, ( + f"output_config should be stripped for pre-4.6 model {model_id}" + ) + + def test_output_format_removed_from_bedrock_invoke_request(): """ Test that output_format parameter is removed from Bedrock Invoke requests. diff --git a/tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py b/tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py index f69f478278f..119ce883161 100644 --- a/tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py +++ b/tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py @@ -342,3 +342,90 @@ def test_bedrock_messages_strips_output_config_with_output_format(): assert "output_config" not in result assert "output_format" not in result + + +def test_bedrock_messages_preserves_output_config_for_claude_4_6(): + """ + Claude 4.6 models support output_config.effort on Bedrock Invoke. + Verify that output_config is preserved (not stripped) for these models. + """ + from litellm.types.router import GenericLiteLLMParams + + cfg = AmazonAnthropicClaudeMessagesConfig() + messages = [{"role": "user", "content": [{"type": "text", "text": "Hello"}]}] + + # Opus 4.6 supports effort=max + for model_id in [ + "global.anthropic.claude-opus-4-6-v1", + "anthropic.claude-opus-4-6-v1:0", + ]: + optional_params = { + "max_tokens": 128000, + "thinking": {"type": "adaptive"}, + "output_config": {"effort": "max"}, + } + + result = cfg.transform_anthropic_messages_request( + model=model_id, + messages=messages, + anthropic_messages_optional_request_params=optional_params, + litellm_params=GenericLiteLLMParams(), + headers={}, + ) + + assert "output_config" in result, ( + f"output_config should be preserved for Claude 4.6 model {model_id}" + ) + assert result["output_config"]["effort"] == "max" + assert result["thinking"]["type"] == "adaptive" + + # Sonnet 4.6 supports effort=high (not max) + optional_params = { + "max_tokens": 128000, + "thinking": {"type": "adaptive"}, + "output_config": {"effort": "high"}, + } + result = cfg.transform_anthropic_messages_request( + model="global.anthropic.claude-sonnet-4-6", + messages=messages, + anthropic_messages_optional_request_params=optional_params, + litellm_params=GenericLiteLLMParams(), + headers={}, + ) + assert "output_config" in result, ( + "output_config should be preserved for Claude Sonnet 4.6" + ) + assert result["output_config"]["effort"] == "high" + + +def test_bedrock_messages_strips_output_config_for_pre_4_6(): + """ + Pre-4.6 models do not support output_config on Bedrock Invoke. + Verify that output_config is stripped for these models. + """ + from litellm.types.router import GenericLiteLLMParams + + cfg = AmazonAnthropicClaudeMessagesConfig() + messages = [{"role": "user", "content": [{"type": "text", "text": "Hello"}]}] + + for model_id in [ + "anthropic.claude-3-haiku-20240307-v1:0", + "anthropic.claude-sonnet-4-20250514-v1:0", + "global.anthropic.claude-opus-4-5-20251101-v1:0", + ]: + optional_params = { + "max_tokens": 4096, + "output_config": {"effort": "high"}, + } + + result = cfg.transform_anthropic_messages_request( + model=model_id, + messages=messages, + anthropic_messages_optional_request_params=optional_params, + litellm_params=GenericLiteLLMParams(), + headers={}, + ) + + assert "output_config" not in result, ( + f"output_config should be stripped for pre-4.6 model {model_id}" + )