From 5104b83b1da5e65b2aeaa93efce0a9309de5ddae Mon Sep 17 00:00:00 2001 From: KXH Date: Thu, 13 Aug 2026 15:05:11 +0800 Subject: [PATCH 1/3] fix(ollama): preserve logged tool schema Signed-off-by: KXH --- litellm/llms/ollama/chat/transformation.py | 1 + .../ollama/test_ollama_chat_transformation.py | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/litellm/llms/ollama/chat/transformation.py b/litellm/llms/ollama/chat/transformation.py index d6aa1f1743b..e000650fb1f 100644 --- a/litellm/llms/ollama/chat/transformation.py +++ b/litellm/llms/ollama/chat/transformation.py @@ -234,6 +234,7 @@ class OllamaChatConfig(BaseConfig): litellm_params: dict, headers: dict, ) -> dict: + optional_params = optional_params.copy() stream: Final = optional_params.pop("stream", False) format: Final = optional_params.pop("format", None) keep_alive: Final = optional_params.pop("keep_alive", 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 906c51d8064..b56531006ce 100644 --- a/tests/test_litellm/llms/ollama/test_ollama_chat_transformation.py +++ b/tests/test_litellm/llms/ollama/test_ollama_chat_transformation.py @@ -814,6 +814,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. From c4bb4017b9160fa15308ac2e505f90cd6dbfe827 Mon Sep 17 00:00:00 2001 From: KXH Date: Thu, 13 Aug 2026 15:15:14 +0800 Subject: [PATCH 2/3] fix(ollama): document request-local mutable copy Signed-off-by: KXH --- litellm/llms/ollama/chat/transformation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litellm/llms/ollama/chat/transformation.py b/litellm/llms/ollama/chat/transformation.py index e000650fb1f..efa8f8f56f7 100644 --- a/litellm/llms/ollama/chat/transformation.py +++ b/litellm/llms/ollama/chat/transformation.py @@ -234,7 +234,7 @@ class OllamaChatConfig(BaseConfig): litellm_params: dict, headers: dict, ) -> dict: - optional_params = optional_params.copy() + optional_params = optional_params.copy() # mutable-ok: request-local copy protects caller-owned logging data stream: Final = optional_params.pop("stream", False) format: Final = optional_params.pop("format", None) keep_alive: Final = optional_params.pop("keep_alive", None) From 506a4d2bf4bcb1f6f5b19f9f0e04a439b0affd6b Mon Sep 17 00:00:00 2001 From: KXH Date: Thu, 13 Aug 2026 15:26:18 +0800 Subject: [PATCH 3/3] fix(ollama): avoid rebinding provider options Signed-off-by: KXH --- litellm/llms/ollama/chat/transformation.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/litellm/llms/ollama/chat/transformation.py b/litellm/llms/ollama/chat/transformation.py index efa8f8f56f7..2fdf58ac1ec 100644 --- a/litellm/llms/ollama/chat/transformation.py +++ b/litellm/llms/ollama/chat/transformation.py @@ -234,14 +234,16 @@ class OllamaChatConfig(BaseConfig): litellm_params: dict, headers: dict, ) -> dict: - optional_params = optional_params.copy() # mutable-ok: request-local copy protects caller-owned logging data - 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: @@ -290,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: