diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index fa18361e44c..0f4717ca5e9 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -1614,14 +1614,7 @@ class AmazonConverseConfig(BaseConfig): Bedrock doesn't support tool calling without `tools=` param specified. """ if "tools" not in optional_params and messages is not None and has_tool_call_blocks(messages): - if litellm.modify_params: - optional_params["tools"] = add_dummy_tool(custom_llm_provider="bedrock_converse") - else: - raise litellm.UnsupportedParamsError( - message="Bedrock doesn't support tool calling without `tools=` param specified. Pass `tools=` param OR set `litellm.modify_params = True` // `litellm_settings::modify_params: True` to add dummy tool to the request.", - model="", - llm_provider="bedrock", - ) + optional_params["tools"] = add_dummy_tool(custom_llm_provider="bedrock_converse") # Drop thinking param if thinking is enabled but thinking_blocks are missing # This prevents the error: "Expected thinking or redacted_thinking, but found tool_use" 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 2e9ea90f3b8..c05e74beddf 100644 --- a/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py +++ b/tests/test_litellm/llms/bedrock/chat/test_converse_transformation.py @@ -6953,3 +6953,53 @@ def test_transform_response_honors_json_mode_kwarg_when_optional_params_lack_it( ) assert result.choices[0].message.tool_calls is None assert json.loads(result.choices[0].message.content) == {"city": "Paris", "population": 2100000} + + +def test_transform_request_injects_dummy_tool_without_tools_param(): + """ + Bedrock Converse rejects requests with tool turns when toolConfig is omitted. + LiteLLM must inject a dummy tool without requiring litellm.modify_params. + """ + from litellm.llms.bedrock.chat.converse_transformation import AmazonConverseConfig + + config = AmazonConverseConfig() + prev_modify_params = litellm.modify_params + litellm.modify_params = False + try: + messages = [ + {"role": "user", "content": "Hello"}, + { + "role": "assistant", + "content": "Calling tool", + "tool_calls": [ + { + "id": "tooluse_test_dummy", + "type": "function", + "function": {"name": "get_x", "arguments": "{}"}, + } + ], + }, + { + "role": "tool", + "tool_call_id": "tooluse_test_dummy", + "content": "{}", + }, + ] + result = config.transform_request( + model="anthropic.claude-3-5-sonnet-20240620-v1:0", + messages=messages, + optional_params={}, + litellm_params={}, + headers={}, + ) + finally: + litellm.modify_params = prev_modify_params + + assert "toolConfig" in result + tools = result["toolConfig"].get("tools", []) + tool_names = [ + t.get("toolSpec", {}).get("name") + for t in tools + if isinstance(t, dict) and "toolSpec" in t + ] + assert "dummy_tool" in tool_names