diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index 395d99a4caa..4076f95bdaf 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -599,7 +599,7 @@ class AmazonConverseConfig(BaseConfig): message=f"Bedrock doesn't support tool_choice={tool_choice}. To drop it from the call, set `litellm.drop_params = True.", status_code=400, ) - elif tool_choice == "required": + elif tool_choice == "required" or tool_choice == "any": return ToolChoiceValuesBlock(any={}) elif tool_choice == "auto": return ToolChoiceValuesBlock(auto={}) @@ -611,7 +611,7 @@ class AmazonConverseConfig(BaseConfig): return ToolChoiceValuesBlock(tool=specific_tool) else: raise litellm.utils.UnsupportedParamsError( - message=f"Bedrock doesn't support tool_choice={tool_choice}. Supported tool_choice values=['auto', 'required', json object]. To drop it from the call, set `litellm.drop_params = True.", + message=f"Bedrock doesn't support tool_choice={tool_choice}. Supported tool_choice values=['auto', 'required', 'any', json object]. To drop it from the call, set `litellm.drop_params = True.", status_code=400, ) 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 63f895e1819..4ee7845b495 100644 --- a/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py +++ b/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py @@ -375,6 +375,82 @@ def test_reasoning_with_forced_tool_choice_switches_to_auto(): assert optional_params["tool_choice"] == {"auto": {}} +def test_tool_choice_any_maps_to_any_block(): + """`tool_choice="any"` should map to Bedrock's ToolChoiceValuesBlock(any={}), same as "required". + + Regression test for https://github.com/BerriAI/litellm/issues/37980: "any" previously + fell through to the UnsupportedParamsError branch even though Bedrock's Converse API + natively supports the any block. + """ + config = AmazonConverseConfig() + + non_default_params = { + "tools": [ + { + "type": "function", + "function": {"name": "get_current_weather", "parameters": {}}, + } + ], + "tool_choice": "any", + } + + optional_params = config.map_openai_params( + model="bedrock/converse/us.anthropic.claude-sonnet-4-5-20250929-v1:0", + non_default_params=non_default_params, + optional_params={}, + drop_params=False, + ) + + assert optional_params["tool_choice"] == {"any": {}} + + +def test_tool_choice_required_maps_to_any_block(): + """`tool_choice="required"` (and now "any") both map to Bedrock's native {any:{}} block.""" + config = AmazonConverseConfig() + + non_default_params = { + "tools": [ + { + "type": "function", + "function": {"name": "get_current_weather", "parameters": {}}, + } + ], + "tool_choice": "required", + } + + optional_params = config.map_openai_params( + model="bedrock/converse/us.anthropic.claude-sonnet-4-5-20250929-v1:0", + non_default_params=non_default_params, + optional_params={}, + drop_params=False, + ) + + assert optional_params["tool_choice"] == {"any": {}} + + +def test_tool_choice_none_still_raises(): + """Values outside auto/required/any/json-object must still raise UnsupportedParamsError.""" + config = AmazonConverseConfig() + + non_default_params = { + "tools": [ + { + "type": "function", + "function": {"name": "get_current_weather", "parameters": {}}, + } + ], + "tool_choice": "none", + } + + with pytest.raises(litellm.UnsupportedParamsError): + config.map_openai_params( + model="bedrock/converse/us.anthropic.claude-sonnet-4-5-20250929-v1:0", + non_default_params=non_default_params, + optional_params={}, + drop_params=False, + ) + + @pytest.mark.parametrize( "model", [