diff --git a/litellm/llms/ollama/chat/transformation.py b/litellm/llms/ollama/chat/transformation.py index d6aa1f1743b..2fdf58ac1ec 100644 --- a/litellm/llms/ollama/chat/transformation.py +++ b/litellm/llms/ollama/chat/transformation.py @@ -234,13 +234,16 @@ class OllamaChatConfig(BaseConfig): litellm_params: dict, headers: dict, ) -> dict: - stream: Final = optional_params.pop("stream", False) - format: Final = optional_params.pop("format", None) - keep_alive: Final = optional_params.pop("keep_alive", None) - think: Final = optional_params.pop("think", None) - function_name: Final = optional_params.pop("function_name", None) + request_params: Final = ( + optional_params.copy() + ) # mutable-ok: request-local copy protects caller-owned logging data + stream: Final = request_params.pop("stream", False) + format: Final = request_params.pop("format", None) + keep_alive: Final = request_params.pop("keep_alive", None) + think: Final = request_params.pop("think", None) + function_name: Final = request_params.pop("function_name", None) litellm_params["function_name"] = function_name - tools: Final = optional_params.pop("tools", None) + tools: Final = request_params.pop("tools", None) new_messages: Final = [] for m in messages: @@ -289,13 +292,13 @@ class OllamaChatConfig(BaseConfig): # Load Config config: Final = self.get_config() for k, v in config.items(): - if k not in optional_params: - optional_params[k] = v + if k not in request_params: + request_params[k] = v data: Final = { "model": model, "messages": new_messages, - "options": optional_params, + "options": request_params, "stream": stream, } if format is not None: diff --git a/tests/test_litellm/llms/ollama/test_ollama_chat_transformation.py b/tests/test_litellm/llms/ollama/test_ollama_chat_transformation.py index 8f3dbf7b0d9..ccb4f6fd1e2 100644 --- a/tests/test_litellm/llms/ollama/test_ollama_chat_transformation.py +++ b/tests/test_litellm/llms/ollama/test_ollama_chat_transformation.py @@ -812,6 +812,38 @@ class TestOllamaReasoningContentStreaming: class TestOllamaToolCallTransformation: + def test_transform_request_preserves_logged_tool_schema(self): + config = OllamaChatConfig() + tools = [ + { + "type": "function", + "function": { + "name": "get_weather", + "description": "Get weather for a location", + "parameters": { + "type": "object", + "properties": {"location": {"type": "string"}}, + "required": ["location"], + }, + }, + } + ] + optional_params = {"tools": tools, "stream": False, "num_ctx": 262144} + + result = config.transform_request( + model="gemma4:27b", + messages=cast( + list[AllMessageValues], + [{"role": "user", "content": "Weather in London?"}], + ), + optional_params=optional_params, + litellm_params={}, + headers={}, + ) + + assert result["tools"] == tools + assert optional_params == {"tools": tools, "stream": False, "num_ctx": 262144} + def test_transform_request_preserves_tool_calls(self): """ tool_calls on assistant messages must survive transform_request.