From 9ce1ffc6c0f124b4656c608a9b9c5f945031676b Mon Sep 17 00:00:00 2001 From: Vidit Patankar Date: Mon, 1 Jun 2026 10:54:24 +0530 Subject: [PATCH] Fix empty list/tuple tool output being dropped via all([]) == True ItemHelpers._convert_tool_output stringifies a tool's list/tuple return value unless every element is a structured output type, gated on 'if all(maybe_converted_output_list)'. For an empty list/tuple the comprehension yields [] and all([]) is True, so the empty collection wrongly takes the structured-output branch and returns an empty ResponseFunctionCallOutputItemListParam. Sent to the Responses API as a function_call_output, that empty list drops the tool result entirely instead of producing the expected stringified '[]' / '()'. Guard the branch with a truthiness check so empty collections fall through to str(output). Non-empty lists were already stringified correctly; only the empty case is fixed. Adds regression tests for empty list and empty tuple. Signed-off-by: Vidit Patankar --- src/agents/items.py | 5 ++++- tests/test_tool_output_conversion.py | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/agents/items.py b/src/agents/items.py index c761cc221f..cb1d3ff115 100644 --- a/src/agents/items.py +++ b/src/agents/items.py @@ -801,7 +801,10 @@ def _convert_tool_output(cls, output: Any) -> str | ResponseFunctionCallOutputIt maybe_converted_output_list = [ cls._maybe_get_output_as_structured_function_output(item) for item in output ] - if all(maybe_converted_output_list): + # An empty list/tuple has no structured items; ``all([])`` is ``True``, + # so guard against it to avoid emitting an empty structured-output list + # (which would drop the tool result) and stringify instead. + if maybe_converted_output_list and all(maybe_converted_output_list): return [ cls._convert_single_tool_output_pydantic_model(item) for item in maybe_converted_output_list diff --git a/tests/test_tool_output_conversion.py b/tests/test_tool_output_conversion.py index cd3a2a11a2..292c7a0414 100644 --- a/tests/test_tool_output_conversion.py +++ b/tests/test_tool_output_conversion.py @@ -370,3 +370,26 @@ def test_tool_call_output_item_mixed_list_partial_invalid_not_converted() -> Non # All-or-nothing: if any item is invalid, convert entire list to string assert isinstance(payload["output"], str) assert payload["output"] == "[{'type': 'text', 'text': 'hello'}, {'msg': 'foobar'}]" + + +def test_tool_call_output_item_empty_list_not_converted() -> None: + """An empty list has no structured items, so it should stringify rather than + produce an empty structured-output list (which would drop the tool result).""" + call = _make_tool_call() + payload = ItemHelpers.tool_call_output_item(call, []) + + assert payload["type"] == "function_call_output" + assert payload["call_id"] == call.call_id + assert isinstance(payload["output"], str) + assert payload["output"] == "[]" + + +def test_tool_call_output_item_empty_tuple_not_converted() -> None: + """An empty tuple should stringify, mirroring the empty-list behavior.""" + call = _make_tool_call() + payload = ItemHelpers.tool_call_output_item(call, ()) + + assert payload["type"] == "function_call_output" + assert payload["call_id"] == call.call_id + assert isinstance(payload["output"], str) + assert payload["output"] == "()"