diff --git a/dhar_repro/repro.ipynb b/dhar_repro/repro.ipynb new file mode 100644 index 00000000000..e69de29bb2d diff --git a/litellm/responses/litellm_completion_transformation/transformation.py b/litellm/responses/litellm_completion_transformation/transformation.py index 71fa88fb751..0eed4b18864 100644 --- a/litellm/responses/litellm_completion_transformation/transformation.py +++ b/litellm/responses/litellm_completion_transformation/transformation.py @@ -233,6 +233,13 @@ class LiteLLMCompletionResponsesConfig: litellm_completion_request = { k: v for k, v in litellm_completion_request.items() if v is not None } + + # Do not forward empty tool configuration to chat-completion providers. + # Providers like Ollama change behavior when they see `tools=[]`, even + # though the user did not actually request tool use. + if not tools: + litellm_completion_request.pop("tools", None) + litellm_completion_request.pop("tool_choice", None) return litellm_completion_request @staticmethod diff --git a/tests/test_litellm/responses/litellm_completion_transformation/test_litellm_completion_responses.py b/tests/test_litellm/responses/litellm_completion_transformation/test_litellm_completion_responses.py index a931a9bc93c..cae07e49c2e 100644 --- a/tests/test_litellm/responses/litellm_completion_transformation/test_litellm_completion_responses.py +++ b/tests/test_litellm/responses/litellm_completion_transformation/test_litellm_completion_responses.py @@ -26,6 +26,58 @@ from litellm.types.utils import ( class TestLiteLLMCompletionResponsesConfig: + def test_transform_responses_request_omits_empty_tools(self): + result = ( + LiteLLMCompletionResponsesConfig.transform_responses_api_request_to_chat_completion_request( + model="ollama/llama3.2:latest", + input="Reply with exactly: ok", + responses_api_request={ + "temperature": 0, + "tools": [], + "tool_choice": "auto", + }, + custom_llm_provider="ollama", + stream=False, + ) + ) + + assert "tools" not in result + assert "tool_choice" not in result + assert result["messages"] == [{"role": "user", "content": "Reply with exactly: ok"}] + assert result["model"] == "ollama/llama3.2:latest" + + def test_transform_responses_request_preserves_non_empty_tools(self): + result = ( + LiteLLMCompletionResponsesConfig.transform_responses_api_request_to_chat_completion_request( + model="ollama/llama3.2:latest", + input="Reply with exactly: ok", + responses_api_request={ + "temperature": 0, + "tools": [ + { + "type": "function", + "name": "echo", + "description": "Echo text", + "parameters": { + "type": "object", + "properties": {"text": {"type": "string"}}, + "required": ["text"], + }, + } + ], + "tool_choice": "auto", + }, + custom_llm_provider="ollama", + stream=False, + ) + ) + + assert "tools" in result + assert len(result["tools"]) == 1 + assert result["tools"][0]["type"] == "function" + assert result["tools"][0]["function"]["name"] == "echo" + assert result["tool_choice"] == "auto" + def test_transform_input_file_item_to_file_item_with_file_id(self): """Test transformation of input_file item with file_id to Chat Completion file format""" # Setup