From 6ad41d750c64003b57491a1868c38bae73f3c34e Mon Sep 17 00:00:00 2001 From: chaunceyjiang Date: Fri, 19 Sep 2025 02:47:07 +0000 Subject: [PATCH 1/5] [Bugfix] fix tool call arguments is empty Signed-off-by: chaunceyjiang Co-authored-by: xin.li --- vllm/entrypoints/chat_utils.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/vllm/entrypoints/chat_utils.py b/vllm/entrypoints/chat_utils.py index 00ef39f13465..006359de1d05 100644 --- a/vllm/entrypoints/chat_utils.py +++ b/vllm/entrypoints/chat_utils.py @@ -1450,9 +1450,13 @@ def _postprocess_messages(messages: list[ConversationMessage]) -> None: and isinstance(message["tool_calls"], list) ): for item in message["tool_calls"]: - item["function"]["arguments"] = json.loads( - item["function"]["arguments"] - ) + # if arguments is None or empty string, set to {} + if item["function"].get("arguments"): + item["function"]["arguments"] = json.loads( + item["function"]["arguments"] + ) + else: + item["function"]["arguments"] = {} def parse_chat_messages( From 0bab4b7c3419d815a9a5b895825e2a2e677912eb Mon Sep 17 00:00:00 2001 From: chaunceyjiang Date: Fri, 19 Sep 2025 03:58:11 +0000 Subject: [PATCH 2/5] [Bugfix] fix tool call arguments is empty Signed-off-by: chaunceyjiang --- .../test_completion_with_function_calling.py | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/entrypoints/openai/test_completion_with_function_calling.py b/tests/entrypoints/openai/test_completion_with_function_calling.py index 3649cefa9bf4..7d8980ef4d8c 100644 --- a/tests/entrypoints/openai/test_completion_with_function_calling.py +++ b/tests/entrypoints/openai/test_completion_with_function_calling.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project +import datetime from typing import Union import openai # use the official client for correctness check @@ -284,3 +285,62 @@ async def test_tool_id_kimi_k2(k2_client: openai.AsyncOpenAI, model_name: str, output.extend(chunk.choices[0].delta.tool_calls) for o in output: assert o.id is None or o.id == 'functions.get_current_weather:0' + + +@pytest.mark.asyncio +@pytest.mark.parametrize("model_name", [MODEL_NAME]) +@pytest.mark.parametrize("arguments", ["{}", '']) +async def test_no_args_tool_call(client: openai.AsyncOpenAI, model_name: str, + arguments: str): + # Step 1: Define a tool that requires no parameters + tools = [{ + "type": "function", + "function": { + "name": "get_current_time", + "description": + "Get the current date and time. No parameters needed.", + "parameters": { + "type": "object", + "properties": {}, # No parameters + "required": [] # No required fields + } + } + }] + messages = [{"role": "user", "content": "What time is it now?"}] + # Step 2: Send user message and let model decide whether to call the tool + response = client.chat.completions.create( + model=model_name, + messages=messages, + tools=tools, + tool_choice="auto" # Let model choose automatically + ) + + # Step 3: Check if model wants to call a tool + message = response.choices[0].message + if message.tool_calls: + # Get the first tool call + tool_call = message.tool_calls[0] + tool_name = tool_call.function.name + # Step 4: Execute the tool locally (no parameters) + if tool_name == "get_current_time": + # Test both empty string and "{}" for no-arg tool calls + tool_call.function.arguments = arguments + messages.append(message) + current_time = datetime.datetime.now(datetime.UTC) + result = current_time.isoformat() + "Z" + messages.append({ + "role": "tool", + "tool_call_id": tool_call.id, + "content": result, + }) + # Step 5: Send tool result back to model to continue conversation + final_response = client.chat.completions.create( + model=model_name, + messages=messages, + ) + # Output final natural language response + assert final_response.choices[0].message.content is not None + + else: + # No tool called — just print model's direct reply + assert message.content is not None From a5a50f5c35fb40890acfd234ad814dce8ee41087 Mon Sep 17 00:00:00 2001 From: chaunceyjiang Date: Fri, 19 Sep 2025 04:08:06 +0000 Subject: [PATCH 3/5] [Bugfix] fix tool call arguments is empty Signed-off-by: chaunceyjiang --- .../openai/test_completion_with_function_calling.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/entrypoints/openai/test_completion_with_function_calling.py b/tests/entrypoints/openai/test_completion_with_function_calling.py index 7d8980ef4d8c..6c1b49fc16ca 100644 --- a/tests/entrypoints/openai/test_completion_with_function_calling.py +++ b/tests/entrypoints/openai/test_completion_with_function_calling.py @@ -326,8 +326,8 @@ async def test_no_args_tool_call(client: openai.AsyncOpenAI, model_name: str, # Test both empty string and "{}" for no-arg tool calls tool_call.function.arguments = arguments messages.append(message) - current_time = datetime.datetime.now(datetime.UTC) - result = current_time.isoformat() + "Z" + current_time = datetime.datetime.now() + result = current_time.isoformat() messages.append({ "role": "tool", "tool_call_id": tool_call.id, From 4a08d9d01c573929e6f4c088b7535abb99225019 Mon Sep 17 00:00:00 2001 From: chaunceyjiang Date: Fri, 19 Sep 2025 04:26:04 +0000 Subject: [PATCH 4/5] [Bugfix] fix tool call arguments is empty Signed-off-by: chaunceyjiang --- vllm/entrypoints/chat_utils.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/vllm/entrypoints/chat_utils.py b/vllm/entrypoints/chat_utils.py index 006359de1d05..c2c0ad74ef43 100644 --- a/vllm/entrypoints/chat_utils.py +++ b/vllm/entrypoints/chat_utils.py @@ -1451,10 +1451,8 @@ def _postprocess_messages(messages: list[ConversationMessage]) -> None: ): for item in message["tool_calls"]: # if arguments is None or empty string, set to {} - if item["function"].get("arguments"): - item["function"]["arguments"] = json.loads( - item["function"]["arguments"] - ) + if content := item["function"].get("arguments"): + item["function"]["arguments"] = json.loads(content) else: item["function"]["arguments"] = {} From 8a3c375f8f9adcd7a959d87204f1fcdce2e7767a Mon Sep 17 00:00:00 2001 From: chaunceyjiang Date: Fri, 19 Sep 2025 05:49:24 +0000 Subject: [PATCH 5/5] [Bugfix] fix tool call arguments is empty Signed-off-by: chaunceyjiang --- .../openai/test_completion_with_function_calling.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/entrypoints/openai/test_completion_with_function_calling.py b/tests/entrypoints/openai/test_completion_with_function_calling.py index 6c1b49fc16ca..4355603fcd70 100644 --- a/tests/entrypoints/openai/test_completion_with_function_calling.py +++ b/tests/entrypoints/openai/test_completion_with_function_calling.py @@ -308,7 +308,7 @@ async def test_no_args_tool_call(client: openai.AsyncOpenAI, model_name: str, }] messages = [{"role": "user", "content": "What time is it now?"}] # Step 2: Send user message and let model decide whether to call the tool - response = client.chat.completions.create( + response = await client.chat.completions.create( model=model_name, messages=messages, tools=tools, @@ -334,7 +334,7 @@ async def test_no_args_tool_call(client: openai.AsyncOpenAI, model_name: str, "content": result, }) # Step 5: Send tool result back to model to continue conversation - final_response = client.chat.completions.create( + final_response = await client.chat.completions.create( model=model_name, messages=messages, )