Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/agents/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -1391,6 +1391,13 @@ def _extract_tool_argument_json_error(error: Exception) -> json.JSONDecodeError
return _extract_json_decode_error(error)


def _is_tool_argument_input_error(error: Exception) -> bool:
"""Return True when an error represents an invalid-JSON-input failure for a function tool."""
return isinstance(error, ModelBehaviorError) and str(error).startswith(
"Invalid JSON input for tool"
)
Comment on lines +1396 to +1398
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Narrow argument-input detection to non-object parse failures

_is_tool_argument_input_error now matches every ModelBehaviorError whose text starts with Invalid JSON input for tool. Schema validation failures raised later use that same prefix, so wrong/missing fields are now reported as JSON parse errors with the JSON-input trace message, not the previous validation/non-fatal path. This goes beyond the non-object JSON case described by the change.

Useful? React with 👍 / 👎.



def _build_handled_function_tool_error_handler(
*,
span_message: str,
Expand All @@ -1411,6 +1418,11 @@ def _on_handled_error(
if json_decode_error is not None and span_message_for_json_decode_error is not None:
resolved_span_message = span_message_for_json_decode_error
span_error_detail = str(json_decode_error)
elif span_message_for_json_decode_error is not None and _is_tool_argument_input_error(
error
):
resolved_span_message = span_message_for_json_decode_error
span_error_detail = str(error)
else:
resolved_span_message = span_message
span_error_detail = str(error)
Expand Down Expand Up @@ -1481,6 +1493,12 @@ def default_tool_error_function(ctx: RunContextWrapper[Any], error: Exception) -
"Please try again with valid JSON. "
f"Error: {json_decode_error}"
)
if _is_tool_argument_input_error(error):
return (
"An error occurred while parsing tool arguments. "
"Please try again with valid JSON. "
f"Error: {error}"
)
return f"An error occurred while running the tool. Please try again. Error: {str(error)}"


Expand Down
25 changes: 25 additions & 0 deletions tests/test_function_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,31 @@ def echo(value: str) -> str:
)


@pytest.mark.asyncio
@pytest.mark.parametrize("input_json", ["[]", '"value"', "123", "null", "true"])
async def test_default_error_function_treats_non_object_input_as_json_error(
input_json: str,
) -> None:
def echo(value: str) -> str:
return value

tool = function_tool(echo, name_override="echo_tool")

result = await tool.on_invoke_tool(
ToolContext(
None,
tool_name="echo_tool",
tool_call_id="1",
tool_arguments=input_json,
),
input_json,
)

assert isinstance(result, str)
assert result.startswith("An error occurred while parsing tool arguments.")
assert "expected a JSON object" in result


@pytest.mark.asyncio
async def test_default_failure_error_function_survives_deepcopy() -> None:
def boom() -> None:
Expand Down
Loading