diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index 5e46b8103c0..a37c7a72452 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -527,8 +527,12 @@ class AmazonConverseConfig(BaseConfig): ## Filter out 'cross-region' from model name base_model = BedrockModelInfo.get_base_model(model) + is_anthropic_model = base_model.startswith("anthropic") or base_model.startswith( + "claude-" + ) + if ( - base_model.startswith("anthropic") + is_anthropic_model or base_model.startswith("mistral") or base_model.startswith("cohere") or base_model.startswith("meta.llama3-1") @@ -546,10 +550,14 @@ class AmazonConverseConfig(BaseConfig): if base_model.startswith("amazon.nova"): supported_params.append("web_search_options") - if litellm.utils.supports_tool_choice( - model=model, custom_llm_provider=self.custom_llm_provider - ) or litellm.utils.supports_tool_choice( - model=base_model, custom_llm_provider=self.custom_llm_provider + if ( + is_anthropic_model + or litellm.utils.supports_tool_choice( + model=model, custom_llm_provider=self.custom_llm_provider + ) + or litellm.utils.supports_tool_choice( + model=base_model, custom_llm_provider=self.custom_llm_provider + ) ): # only anthropic and mistral support tool choice config. otherwise (E.g. cohere) will fail the call - https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolChoice.html supported_params.append("tool_choice") @@ -1852,6 +1860,7 @@ class AmazonConverseConfig(BaseConfig): } tool_name = ( params.pop("command", None) + or params.pop("tool_name", None) or params.pop("name", None) or params.pop("tool", None) ) @@ -2258,12 +2267,25 @@ class AmazonConverseConfig(BaseConfig): if json_mode and not filtered_tools and tools: initial_finish_reason = "stop" + text_tool_call_tools = optional_params.get("tools") + if text_tool_call_tools is None: + request_data = data + if isinstance(data, str): + try: + request_data = json.loads(data) + except Exception: + request_data = None + if isinstance(request_data, dict): + tool_config = request_data.get("toolConfig") + if isinstance(tool_config, dict): + text_tool_call_tools = tool_config.get("tools") + ( returned_message, returned_finish_reason, ) = self.apply_tool_call_transformation_if_needed( message=_message, - tools=optional_params.get("tools"), + tools=text_tool_call_tools, initial_finish_reason=initial_finish_reason, ) model_response.choices = [ 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 ba81d90ca0c..797f58b4a67 100644 --- a/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py +++ b/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py @@ -348,6 +348,65 @@ def test_apply_tool_call_transformation_ignores_text_for_unknown_tool_name(): assert transformed_message.tool_calls is None +def test_transform_response_uses_bedrock_tool_config_for_text_tool_calls(): + import httpx + + config = AmazonConverseConfig() + raw_response = httpx.Response( + status_code=200, + json={ + "output": { + "message": { + "role": "assistant", + "content": [ + { + "text": ( + "\n\n" + 'read_file\n' + 'C:\\Projects\\redaigo\\scripts\\run_etf_v13.py\n' + '0\n' + '3000\n' + "" + ) + } + ], + } + }, + "stopReason": "end_turn", + "usage": {"inputTokens": 1, "outputTokens": 1, "totalTokens": 2}, + }, + ) + + model_response = config._transform_response( + model="bedrock/converse/claude-opus-4.6", + response=raw_response, + model_response=ModelResponse(), + stream=False, + logging_obj=None, + optional_params={}, + api_key=None, + data=json.dumps( + { + "toolConfig": { + "tools": [ + { + "toolSpec": { + "name": "read_file", + "inputSchema": {"json": {}}, + } + } + ] + } + } + ), + messages=[], + encoding=None, + ) + + choice = model_response.choices[0] + _assert_read_file_tool_call(choice.message, choice.finish_reason) + + def test_transform_tool_call_with_cache_control(): from litellm.llms.bedrock.chat.converse_transformation import AmazonConverseConfig @@ -568,6 +627,17 @@ def test_get_supported_openai_params(): assert "reasoning_effort" in supported_params +@pytest.mark.parametrize( + "model", + ["claude-opus-4.6", "claude-sonnet-4.6", "claude-haiku-4.5"], +) +def test_get_supported_openai_params_for_nexus_claude_aliases(model): + config = AmazonConverseConfig() + supported_params = config.get_supported_openai_params(model=model) + assert "tools" in supported_params + assert "tool_choice" in supported_params + + def test_get_supported_openai_params_bedrock_converse(): """ Test that all documented bedrock converse models have the same set of supported openai params when using