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
32 changes: 26 additions & 6 deletions src/agents/realtime/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -694,11 +694,21 @@ async def _handle_tool_call(
tool_arguments=event.arguments,
agent=agent,
)
result = await invoke_function_tool(
function_tool=func_tool,
context=tool_context,
arguments=event.arguments,
)
try:
result = await invoke_function_tool(
function_tool=func_tool,
context=tool_context,
arguments=event.arguments,
)
except Exception:
await self._model.send_event(
RealtimeModelSendToolOutput(
tool_call=event,
output=f"Tool '{event.name}' failed",
Comment on lines +703 to +707
start_response=True,
)
)
raise

await self._model.send_event(
RealtimeModelSendToolOutput(
Expand Down Expand Up @@ -729,7 +739,17 @@ async def _handle_tool_call(
)

# Execute the handoff to get the new agent
result = await handoff.on_invoke_handoff(self._context_wrapper, event.arguments)
try:
result = await handoff.on_invoke_handoff(self._context_wrapper, event.arguments)
except Exception:
await self._model.send_event(
RealtimeModelSendToolOutput(
tool_call=event,
output=f"Handoff '{event.name}' failed",
Comment on lines +744 to +748
start_response=True,
)
)
raise
if not isinstance(result, RealtimeAgent):
raise UserError(
f"Handoff {handoff.tool_name} returned invalid result: {type(result)}"
Expand Down
8 changes: 4 additions & 4 deletions tests/realtime/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,7 @@ async def invoke_slow_tool(_ctx: ToolContext[Any], _arguments: str) -> str:
with pytest.raises(ToolTimeoutError, match="timed out"):
await session._handle_tool_call(tool_call_event)

assert len(mock_model.sent_tool_outputs) == 0
assert len(mock_model.sent_tool_outputs) == 1
assert session._event_queue.qsize() == 1

tool_start_event = await session._event_queue.get()
Expand Down Expand Up @@ -1196,7 +1196,7 @@ async def invoke_slow_tool(_ctx: ToolContext[Any], _arguments: str) -> str:

assert isinstance(session._stored_exception, ToolTimeoutError)
assert session._stored_exception.tool_name == "slow_tool"
assert len(mock_model.sent_tool_outputs) == 0
assert len(mock_model.sent_tool_outputs) == 1

events = []
while True:
Expand Down Expand Up @@ -1626,8 +1626,8 @@ async def test_function_tool_exception_handling(
assert isinstance(tool_start_event, RealtimeToolStart)
assert tool_start_event.arguments == "{}"

# But no tool output should have been sent and no end event queued
assert len(mock_model.sent_tool_outputs) == 0
# An error tool output should be sent to the model before re-raising
assert len(mock_model.sent_tool_outputs) == 1

@pytest.mark.asyncio
async def test_tool_call_with_complex_arguments(
Expand Down