fix: default empty Responses tool-call arguments to {}

Missing or empty Chat Completions tool-call arguments were forwarded
as an empty string, which is invalid JSON for Responses API
function_call items and breaks parse_tool_call_args. Normalize to
"{}" and cover the case in regression tests. Also assert a supplied
tool-call id is preserved as call_id.

Co-authored-by: Rip&Tear <theCyberTech@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-08-05 10:06:18 +00:00
parent ff47574a39
commit 4cbf7674cb
2 changed files with 39 additions and 7 deletions

View File

@@ -771,15 +771,17 @@ class OpenAICompletion(BaseLLM):
items.append({"role": "assistant", "content": content})
for call in message["tool_calls"]:
function = call.get("function", {})
args = function.get("arguments", "")
args = function.get("arguments")
if args is None or args == "":
args = "{}"
elif not isinstance(args, str):
args = json.dumps(args)
items.append(
{
"type": "function_call",
"call_id": call.get("id") or f"call_{id(call)}",
"name": function.get("name", ""),
"arguments": args
if isinstance(args, str)
else json.dumps(args),
"arguments": args,
}
)
return items
@@ -810,7 +812,7 @@ class OpenAICompletion(BaseLLM):
- Internally-tagged tool format (flat structure)
"""
instructions: str | None = self.instructions
input_messages: list[Any] = []
input_messages: list[dict[str, Any] | LLMMessage] = []
for message in messages:
if message.get("role") == "system":
@@ -824,7 +826,7 @@ class OpenAICompletion(BaseLLM):
input_messages.extend(self._to_responses_input(message))
# Prepend reasoning items for ZDR (zero-data-retention) chaining when configured
final_input: list[Any] = []
final_input: list[dict[str, Any] | LLMMessage] = []
if self.auto_chain_reasoning and self._last_reasoning_items:
final_input.extend(self._last_reasoning_items)
final_input.extend(input_messages if input_messages else messages)

View File

@@ -1017,6 +1017,7 @@ def test_openai_responses_api_preserves_assistant_content_with_tool_calls():
"tool_calls": [
{
"type": "function",
"id": "call_fetch_page",
"function": {
"name": "fetch_page",
"arguments": {"url": "https://example.com"},
@@ -1033,10 +1034,39 @@ def test_openai_responses_api_preserves_assistant_content_with_tool_calls():
"content": "I'll fetch that page now.",
}
assert params["input"][1]["type"] == "function_call"
assert params["input"][1]["call_id"].startswith("call_")
assert params["input"][1]["call_id"] == "call_fetch_page"
assert params["input"][1]["arguments"] == '{"url": "https://example.com"}'
def test_openai_responses_api_defaults_missing_tool_call_arguments():
"""Missing or empty tool-call arguments must become a valid JSON object."""
llm = OpenAICompletion(model="gpt-4o-mini", api="responses")
messages = [
{
"role": "assistant",
"content": None,
"tool_calls": [
{
"id": "call_no_args",
"type": "function",
"function": {"name": "ping"},
},
{
"id": "call_empty_args",
"type": "function",
"function": {"name": "ping", "arguments": ""},
},
],
}
]
params = llm._prepare_responses_params(messages)
assert params["input"][0]["arguments"] == "{}"
assert params["input"][1]["arguments"] == "{}"
def test_openai_responses_api_converts_tool_result_message():
"""Regression: tool-role messages (Chat-Completions shape) must become
function_call_output input items for the Responses API.