Repository navigation
Conversation
_on_done() stringified the raw task result, so the documented `return (agent, ToolResult(...))` handoff surfaced a Python repr (including the Agent's memory address) in the public tool_execution_updated event, while dispatch recorded the sanitized text in chat history. Derive the terminal message through the same make_tool_output sanitizer used by dispatch, so container results report their recorded output instead of a repr.
_on_done() unwrapped ToolResult before deriving the terminal text, so a
ToolResult(("a", "b")) payload reached the sanitizer as a bare tuple
and was reported as ['a', 'b'], while dispatch recorded ('a', 'b').
Derive the message from the raw return value, matching the shape dispatch
gives make_tool_output, and add a regression test for the tuple case.
|
Addressed the Devin finding about Confirmed: The terminal message is now derived from the raw return value, so the sanitizer sees the same shape dispatch sees on every path. The earlier handoff case still reports Added Verification:
|
fix(tools): sanitize the ToolCallEnded message for handoff results
What breaks
For the documented handoff form
return (agent, ToolResult(...)), the publicToolCallEnded.messageevent exposed a raw Python repr — including the non-deterministicAgentmemory address:_ToolExecutor._on_done()(livekit-agents/livekit/agents/voice/tool_executor.py) unwrapped only a bareToolResultand mapped a bareAgent/None/StopResponsetomessage=None; every other result — handoff tuples included — fell through tostr(output).Dispatch sanitizes the same result through
generation.make_tool_output()(output.agent_task+fnc_call_out.output), so chat history andFunctionToolsExecutedEventcorrectly recorded"Transferred"while the publictool_execution_updatedevent — forwarded verbatim to remote clients — carried the repr and the address. Two views of the same call disagreed, and the address changed every run.Fix
Derive the success-path message through the same sanitizer dispatch uses (
run_ctx._make_update_output(output), i.e.make_tool_output), takingfnc_call_out.output(orNone). The error, cancellation,StopResponse, bare-AgentandNonebranches are untouched.Behavior
Every success result shape now yields the same message as dispatch/chat history:
str/int/dictoutputs, bareToolResult,(agent, ToolResult(...)),(agent, str), list handoffs, tuples/sets,Agentobjects, and invalid/multi-Agent outputs. Empty-string output maps toNone(consistent with the event docs andremote_session.py).Tests
New test in
tests/test_tools.pyreturns(Agent(...), ToolResult("Transferred", reply_required=False))through a real_ToolExecutorand assertsToolCallEnded(message="Transferred", status="done"), with parity againstmake_tool_output(...).fnc_call_out.output.tests/test_tools.py142 passed, plus the tool-output/lifecycle/session-host neighbors (72) — 227 passed total across the suite set, no deviations at base apart from the one new test. Ruff clean.