Skip to content

fix: early return after agent handoff in realtime pipeline#1035

Open
randombet wants to merge 1 commit intolivekit:mainfrom
randombet:fix/realtime-handoff-early-return
Open

fix: early return after agent handoff in realtime pipeline#1035
randombet wants to merge 1 commit intolivekit:mainfrom
randombet:fix/realtime-handoff-early-return

Conversation

@randombet
Copy link

@randombet randombet commented Feb 6, 2026

Summary

  • After updateAgent() triggers activity transition in the realtime tool output handler, the old code continued using this.realtimeSession for chat context updates and reply generation. Since updateAgent() calls drain() and close() on the old activity (including its realtime session), this caused errors and broken agent transfers (e.g. transferring back from a specialist agent to the main agent would fail silently).
  • Added early return to skip post-handoff processing in the realtime pipeline, matching the equivalent fix in the Python agents SDK (fix: realtime agent handoff race conditions agents#4746).

Context

The bug manifests when using multi-agent handoff with Gemini Realtime models:

  1. A handoff tool returns llm.handoff({ agent }), triggering updateAgent()
  2. updateAgent() starts updateActivity() which calls drain() and close() on the old AgentActivity
  3. But the realtime tool output handler continues past the handoff, trying to call this.realtimeSession.updateChatCtx() on the closing session
  4. This causes the transfer to hang or error out

The STT-LLM-TTS pipeline (agent_activity.ts:1691) is not affected — it uses a local chatCtx variable and creates a new pipelineReplyTask, never touching this.realtimeSession.

Test plan

  • Verify bidirectional agent transfer works with Gemini realtime (main → specialist → main)
  • Verify single-agent Gemini realtime sessions work normally (no regression)
  • Verify STT-LLM-TTS pipeline agent transfer is unaffected

Summary by CodeRabbit

  • Bug Fixes
    • Improved agent handoff behavior to prevent the current agent from continuing to process after transitioning to a successor agent, ensuring more reliable multi-agent interactions in realtime sessions.

After updateAgent() triggers activity transition in the realtime tool
output handler, the old code continued using this.realtimeSession for
chat context updates and reply generation. Since updateAgent() calls
drain() and close() on the old activity (including its realtime session),
this caused errors and broken agent transfers.

Added early return to skip post-handoff processing in the realtime
pipeline, matching the equivalent fix in the Python agents SDK.

The STT-LLM-TTS pipeline (line 1691) is unaffected - it uses a local
chatCtx variable and does not reference this.realtimeSession.
@changeset-bot
Copy link

changeset-bot bot commented Feb 6, 2026

⚠️ No Changeset found

Latest commit: 33e25c7

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

When a tool execution produces a new agent task, the code now sets a draining flag and returns early, preventing further updates to the chat context and reply creation. This defers subsequent processing to the new agent instead of the current realtime session.

Changes

Cohort / File(s) Summary
Realtime Tool-Execution Flow
agents/src/voice/agent_activity.ts
Added early return logic when tool output yields a new agent task: sets draining = true and exits to hand off processing to the successor agent, preventing subsequent chat context updates within the current session.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • toubatbrian
  • theomonnom

Poem

🐰 A tool speaks of tasks yet to be,
"New agent takes the wheel!" says he,
We drain and bow out gracefully,
Handing forward the baton, wild and free,
The relay race continues, wait and see! 🏃‍♂️✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main fix: adding an early return after agent handoff in the realtime pipeline to prevent post-handoff processing errors.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering the problem, fix, context, and test plan. However, the pre-review checklist items are not marked as completed by the author.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8310f8 and 33e25c7.

📒 Files selected for processing (1)
  • agents/src/voice/agent_activity.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/agent-core.mdc)

Add SPDX-FileCopyrightText and SPDX-License-Identifier headers to all newly added files with '// SPDX-FileCopyrightText: 2025 LiveKit, Inc.' and '// SPDX-License-Identifier: Apache-2.0'

Files:

  • agents/src/voice/agent_activity.ts
**/*.{ts,tsx}?(test|example|spec)

📄 CodeRabbit inference engine (.cursor/rules/agent-core.mdc)

When testing inference LLM, always use full model names from agents/src/inference/models.ts (e.g., 'openai/gpt-4o-mini' instead of 'gpt-4o-mini')

Files:

  • agents/src/voice/agent_activity.ts
**/*.{ts,tsx}?(test|example)

📄 CodeRabbit inference engine (.cursor/rules/agent-core.mdc)

Initialize logger before using any LLM functionality with initializeLogger({ pretty: true }) from '@livekit/agents'

Files:

  • agents/src/voice/agent_activity.ts
🔇 Additional comments (1)
agents/src/voice/agent_activity.ts (1)

2182-2189: LGTM — correct early return after agent handoff.

This prevents the handler from calling this.realtimeSession.updateChatCtx() and generateReply() on a session that is being closed by updateAgent(). The fix is well-scoped to the realtime path, and the STT-LLM-TTS pipeline path (lines 1690–1694) is correctly unaffected since it operates on local variables.

Minor note: the draining = true assignment on line 2185 is now effectively dead code (since line 2189 returns immediately), but it's harmless and documents intent — no action needed.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@toubatbrian
Copy link
Contributor

Verify bidirectional agent transfer works with Gemini realtime (main → specialist → main)
Verify single-agent Gemini realtime sessions work normally (no regression)
Verify STT-LLM-TTS pipeline agent transfer is unaffected

Hey @randombet, thanks for the bug fix! Have you tested with above items?

@randombet
Copy link
Author

@toubatbrian Please check #1053 for the example to reproduce.

@toubatbrian
Copy link
Contributor

Just curious, what are the exact error message you got. I can't seems to reproduce the error behavior consistently

@randombet
Copy link
Author

randombet commented Feb 14, 2026

Just curious, what are the exact error message you got. I can't seems to reproduce the error behavior consistently

@toubatbrian I don't get the error message. I can handoff from main assistant to math expert, but can't handoff back to the main assistant from math expert. Transfer just hangs there

Sign up for free to 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.

2 participants

Comments