From 7e5a39aaeb42b73a4ddcba7e5104bffba771dd84 Mon Sep 17 00:00:00 2001 From: ly-wang19 Date: Mon, 22 Jun 2026 13:30:08 +0800 Subject: [PATCH] fix(ollama): don't crash ollama_pt on an assistant tool call with empty arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ollama_pt rebuilt prior assistant tool calls with a bare json.loads(call["function"]["arguments"]). A no-argument function call carries arguments="" (or None), so json.loads("") raises JSONDecodeError and aborts the whole completion during prompt construction — before any network call — for any multi-turn ollama conversation that includes such a tool call. Use the shared parse_tool_call_arguments helper (already used by the other tool-call sites in this module), which returns {} for empty/None and repairs truncated JSON. --- .../prompt_templates/factory.py | 10 ++++++- ...llm_core_utils_prompt_templates_factory.py | 27 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/litellm/litellm_core_utils/prompt_templates/factory.py b/litellm/litellm_core_utils/prompt_templates/factory.py index b95b73398ac..5c520eb079f 100644 --- a/litellm/litellm_core_utils/prompt_templates/factory.py +++ b/litellm/litellm_core_utils/prompt_templates/factory.py @@ -251,7 +251,15 @@ def ollama_pt( for call in tool_calls: call_id: str = call["id"] function_name: str = call["function"]["name"] - arguments = json.loads(call["function"]["arguments"]) + # Use the shared safe parser (mirrors the other tool-call + # sites in this module): a no-argument function call carries + # arguments="" / None, on which a bare json.loads raises + # JSONDecodeError and aborts the whole request during prompt + # construction. parse_tool_call_arguments returns {} for + # empty/None and repairs truncated JSON. + arguments = parse_tool_call_arguments( + call["function"]["arguments"], tool_name=function_name + ) ollama_tool_calls.append( { diff --git a/tests/test_litellm/litellm_core_utils/prompt_templates/test_litellm_core_utils_prompt_templates_factory.py b/tests/test_litellm/litellm_core_utils/prompt_templates/test_litellm_core_utils_prompt_templates_factory.py index ed2dfc9440e..1dc3ad9884d 100644 --- a/tests/test_litellm/litellm_core_utils/prompt_templates/test_litellm_core_utils_prompt_templates_factory.py +++ b/tests/test_litellm/litellm_core_utils/prompt_templates/test_litellm_core_utils_prompt_templates_factory.py @@ -51,6 +51,33 @@ def test_ollama_pt_simple_messages(): assert result["images"] == [] +def test_ollama_pt_assistant_tool_call_with_empty_arguments(): + """A prior assistant tool call for a no-argument function carries + arguments="" (or None). ollama_pt must not abort the request with a + JSONDecodeError while rebuilding the prompt; empty arguments parse to {}.""" + messages = [ + {"role": "user", "content": "What time is it?"}, + { + "role": "assistant", + "content": "", + "tool_calls": [ + { + "id": "call_1", + "type": "function", + "function": {"name": "get_current_time", "arguments": ""}, + } + ], + }, + {"role": "tool", "content": "12:00", "tool_call_id": "call_1"}, + ] + + result = ollama_pt(model="llama2", messages=messages) # must not raise + + assert isinstance(result, dict) + assert "get_current_time" in result["prompt"] + assert '"arguments": {}' in result["prompt"] + + def test_ollama_pt_consecutive_user_messages(): """Test handling consecutive user messages""" messages = [