Skip to content

(phonic) Faster handoffs#1221

Merged
toubatbrian merged 5 commits intolivekit:tina/rm-phonic-sayfrom
Phonic-Co:qiong/faster-handoffs
Apr 9, 2026
Merged

(phonic) Faster handoffs#1221
toubatbrian merged 5 commits intolivekit:tina/rm-phonic-sayfrom
Phonic-Co:qiong/faster-handoffs

Conversation

@qionghuang6
Copy link
Copy Markdown
Contributor

@qionghuang6 qionghuang6 commented Apr 9, 2026

Description

Adds logic for handling handoffs in the phonic plugin by implementing _updateSession, which sends a reset message to Phonic.

Demo video
https://screen.studio/share/Lg5fpdh0?state=uploading

Changes Made

Pre-Review Checklist

  • Build passes: All builds (lint, typecheck, tests) pass locally
  • AI-generated code reviewed: Removed unnecessary comments and ensured code quality
  • Changes explained: All changes are properly documented and justified above
  • Scope appropriate: All changes relate to the PR title, or explanations provided for why they're included
  • Video demo: A small video demo showing changes works as expected and did not break any existing functionality using Agent Playground (if applicable)

Testing

  • Automated tests added/updated (if applicable)
  • All tests pass
  • Make sure both restaurant_agent.ts and realtime_agent.ts work properly (for major changes)

Additional Notes


Note to reviewers: Please ensure the pre-review checklist is completed before starting your review.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 9, 2026

🦋 Changeset detected

Latest commit: 3d9a6c5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 22 packages
Name Type
@livekit/agents-plugin-phonic Patch
@livekit/agents Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-cartesia Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hedra Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-lemonslice Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugin-trugen Patch
@livekit/agents-plugin-xai Patch
@livekit/agents-plugins-test Patch

Not sure what this means? Click here to learn what changesets are.

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

@qionghuang6 qionghuang6 changed the base branch from main to tina/rm-phonic-say April 9, 2026 21:30
@qionghuang6 qionghuang6 force-pushed the qiong/faster-handoffs branch from 8c37282 to 343baa0 Compare April 9, 2026 21:34
Comment thread agents/src/voice/agent_activity.ts Outdated
// this means the content is the same as the previous session
const capabilities = this.llm.capabilities;
if (!rtReused && this.realtimeSession?.realtimeModel.provider == 'phonic') {
if (this.realtimeSession?.realtimeModel.provider == 'phonic') {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

responseId,
};

if (this.pendingGenerateReplyFut && !this.pendingGenerateReplyFut.done) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brought over from the Python SDK, was never implemented here.

@qionghuang6 qionghuang6 marked this pull request as ready for review April 9, 2026 21:42
devin-ai-integration[bot]

This comment was marked as resolved.

chatCtx?: llm.ChatContext,
tools?: llm.ToolContext,
): Promise<void> {
if (!this.configSent) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i just made an update in my PR, the changes should handle a fresh session and call update* functions in the framework

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, just replaced this check with await this.readyToStart.await; instead

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

View 8 additional findings in Devin Review.

Open in Devin Review

this.readyToStart.resolve();
this.closeCurrentGeneration({ interrupted: false });
this.rejectPendingGenerateReply();
this.inputResampler = undefined;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Missing inputResampler.close() in session close() causes resource leak

In the close() method at line 517, this.inputResampler is set to undefined without first calling .close() on it. The PR itself demonstrates awareness of this requirement: in resampleAudio() at line 868, this.inputResampler.close() is correctly called before nullifying the reference when the sample rate changes. The same cleanup is missing in the session teardown path, leaking the native resampler resource.

Suggested change
this.inputResampler = undefined;
this.inputResampler?.close();
this.inputResampler = undefined;
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

this.closeCurrentGeneration({ interrupted: false });
return this.startNewAssistantTurn({ userInitiated: true });
this.pendingGenerateReplyFut = new Future<llm.GenerationCreatedEvent>();
this.sendGenerateReply(instructions);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Fire-and-forget sendGenerateReply can leave pendingGenerateReplyFut unresolved and cause unhandled rejection

In generateReply() at line 477, this.sendGenerateReply(instructions) is called without await or .catch(). If this.socket.sendGenerateReply(...) at line 489 throws (e.g., WebSocket in an unexpected state), the error propagates as an unhandled promise rejection, and pendingGenerateReplyFut is never resolved or rejected — causing the caller (agent_activity.ts:2924) to hang indefinitely. The codebase's own convention for fire-and-forget async calls adds .catch() (see this.connectTask at plugins/phonic/src/realtime/realtime_model.ts:268).

Suggested change
this.sendGenerateReply(instructions);
this.sendGenerateReply(instructions).catch((error: unknown) => {
if (this.pendingGenerateReplyFut && !this.pendingGenerateReplyFut.done) {
this.pendingGenerateReplyFut.reject(
error instanceof Error ? error : new Error(String(error)),
);
this.pendingGenerateReplyFut = undefined;
}
});
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@toubatbrian toubatbrian merged commit c09cce3 into livekit:tina/rm-phonic-say Apr 9, 2026
2 checks passed
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.

3 participants