diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index 497020c2836..2315243b10f 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -508,7 +508,9 @@ class AmazonConverseConfig(BaseConfig): } } - def _handle_reasoning_effort_parameter(self, model: str, reasoning_effort: str, optional_params: dict) -> None: + def _handle_reasoning_effort_parameter( + self, model: str, reasoning_effort: str, optional_params: dict, max_tokens: int | None = None + ) -> None: """ Handle the reasoning_effort parameter based on the model type. @@ -527,12 +529,14 @@ class AmazonConverseConfig(BaseConfig): reasoning_config: Final = self._transform_reasoning_effort_to_reasoning_config(reasoning_effort) optional_params.update(reasoning_config) else: - mapped_thinking: Final = AnthropicConfig._map_reasoning_effort( + mapped_thinking = AnthropicConfig._map_reasoning_effort( reasoning_effort=reasoning_effort, model=model, custom_llm_provider="bedrock", llm_provider="bedrock_converse", ) + if mapped_thinking is not None: + mapped_thinking = AnthropicConfig.cap_thinking_budget_to_max_tokens(mapped_thinking, max_tokens) if mapped_thinking is None: optional_params.pop("thinking", None) optional_params.pop("output_config", None) @@ -1113,7 +1117,10 @@ class AmazonConverseConfig(BaseConfig): ) elif param == "reasoning_effort" and isinstance(value, str): self._handle_reasoning_effort_parameter( - model=model, reasoning_effort=value, optional_params=optional_params + model=model, + reasoning_effort=value, + optional_params=optional_params, + max_tokens=non_default_params.get("max_completion_tokens") or non_default_params.get("max_tokens"), ) elif param == "output_config" and isinstance(value, dict): mapped_output_config = dict(value) diff --git a/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py b/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py index ad77f9d4d1b..6dbf09217d9 100644 --- a/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py +++ b/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py @@ -575,6 +575,36 @@ def test_reasoning_effort_none_omits_thinking_for_anthropic_converse(model): assert "thinking" not in optional_params +@pytest.mark.parametrize( + "max_tokens,expect_thinking,expect_budget_below_max_tokens", + [ + (1024, False, None), + (2048, True, True), + (4096, True, False), + ], +) +def test_reasoning_effort_thinking_budget_clamped_to_max_tokens_converse( + max_tokens: int, expect_thinking: bool, expect_budget_below_max_tokens: bool | None +) -> None: + """Regression #39627.""" + config = AmazonConverseConfig() + + optional_params = config.map_openai_params( + non_default_params={"max_tokens": max_tokens, "reasoning_effort": "medium"}, + optional_params={}, + model="us.anthropic.claude-haiku-4-5-20251001-v1:0", + drop_params=False, + ) + + if not expect_thinking: + assert optional_params.get("thinking") is None + return + + thinking = optional_params["thinking"] + budget = thinking["budget_tokens"] + assert budget < max_tokens if expect_budget_below_max_tokens else budget == 2048 + + @pytest.mark.parametrize( "model,effort,expected_effort", [