Skip to content

fix(live): stop background tool tasks when a live agent run ends - #6769

Merged
wuliang229 merged 1 commit into
v1from
port-v1-live-tool-shutdown
Aug 17, 2026
Merged

fix(live): stop background tool tasks when a live agent run ends#6769
wuliang229 merged 1 commit into
v1from
port-v1-live-tool-shutdown

Conversation

@wuliang229

Copy link
Copy Markdown
Collaborator

Summary

Backport of commit 0088abb (fix(live): stop background tool tasks when a live agent run ends, PiperOrigin-RevId: 964915958) from main to v1.

Streaming tools and non-blocking tools run as background asyncio tasks that nothing owns: only an explicit stop_streaming call ever cancelled one. When a live agent run ended for any other reason -- a handoff to another agent, task_completed, the model closing the connection, the caller walking away -- its tools kept running, feeding function responses into a live request queue that by then belonged to another agent, which never made those calls, or to nobody at all. The tasks were never awaited either, so a failure in one surfaced only as a stray asyncio warning.

BaseLlmFlow.run_live now cancels the background tools its run started before it returns, and at a handoff it cancels them before the sub agent takes over the live request queue rather than when the enclosing run eventually finishes. Cancellation is best effort: a task that ignores it is logged instead of stalling the handoff or the caller's teardown.

Stopped tools also give up their registry entry. _send_to_model copies every live request into each registered stream, so a stream left behind by a tool that is no longer reading kept growing for the rest of the session, one entry per audio chunk the user speaks.

Testing Plan

  • pytest tests/unittests/streaming/test_live_tool_shutdown.py tests/unittests/streaming/test_streaming.py (24 passed)
  • pytest tests/unittests/flows/ (426 passed)
  • pyink and isort clean.

Streaming tools and non-blocking tools run as background asyncio tasks that
nothing owns: only an explicit `stop_streaming` call ever cancelled one. When
a live agent run ended for any other reason -- a handoff to another agent,
`task_completed`, the model closing the connection, the caller walking away --
its tools kept running, feeding function responses into a live request queue
that by then belonged to another agent, which never made those calls, or to
nobody at all. The tasks were never awaited either, so a failure in one
surfaced only as a stray asyncio warning.
`BaseLlmFlow.run_live` now cancels the background tools its run started before
it returns, and at a handoff it cancels them before the sub agent takes over
the live request queue rather than when the enclosing run eventually finishes.
Cancellation is best effort: a task that ignores it is logged instead of
stalling the handoff or the caller's teardown.
Stopped tools also give up their registry entry. `_send_to_model` copies every
live request into each registered stream, so a stream left behind by a tool
that is no longer reading kept growing for the rest of the session, one entry
per audio chunk the user spoke.
Co-authored-by: Liang Wu <wuliang@google.com>
PiperOrigin-RevId: 964915958
@wuliang229
wuliang229 merged commit 5fb5ff1 into v1Aug 17, 2026
14 checks passed
@wuliang229
wuliang229 deleted the port-v1-live-tool-shutdown branch August 17, 2026 19:06
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@wuliang229