Files
odysseus/src
jagadish-zentiti 890d6a0220 fix(agent): cancel orphaned tool task when SSE client disconnects mid-call (#5106)
stream_agent_loop's per-tool drain loop had no cleanup path for early
generator close. Starlette throws GeneratorExit into the generator at
whatever await point it's suspended on when the SSE client disconnects
(aclose()) - here that's 'await _progress_q.get()' inside the drain
loop, before the final 'await _tool_task' line ever runs. The task,
which wraps execute_tool_block, was left running unawaited and
uncancelled.

For bash/python tools this orphans the underlying subprocess:
subprocess_tools.py already has correct CancelledError handling that
kills the child process, but only runs if the task is actually
cancelled. A client disconnecting mid long-running command left that
subprocess running server-side for its full duration with nothing
left to reap it.

Wrap the drain loop in try/finally: on early exit, cancel _tool_task
(if not already done) and await it so the existing subprocess-kill
path runs.

Adds a regression test that drives the real stream_agent_loop with a
fake tool handler, closes the generator mid tool-call (mirroring what
Starlette does on disconnect), and asserts the handler observed
cancellation immediately - not merely via asyncio.run()'s own
end-of-run task cleanup, which would mask the bug.

Fixes #5105
2026-07-11 13:44:06 +01:00
..
2026-05-31 23:58:26 +09:00
2026-06-21 11:08:50 +00:00
2026-05-31 23:58:26 +09:00
2026-07-07 00:50:07 +00:00
2026-05-31 23:58:26 +09:00
2026-05-31 23:58:26 +09:00
2026-05-31 23:58:26 +09:00
2026-07-07 00:50:07 +00:00