Skip to content

fix(lemonslice): bind avatar audio output before session start#1593

Open
rosetta-livekit-bot[bot] wants to merge 1 commit into
mainfrom
glares-glazier-sixths
Open

fix(lemonslice): bind avatar audio output before session start#1593
rosetta-livekit-bot[bot] wants to merge 1 commit into
mainfrom
glares-glazier-sixths

Conversation

@rosetta-livekit-bot
Copy link
Copy Markdown
Contributor

@rosetta-livekit-bot rosetta-livekit-bot Bot commented May 25, 2026

Summary

Rebind agent_session.output.audio to the avatar-bound DataStreamAudioOutput before the LemonSlice session-creation HTTP call instead of after. The call is on the order of a second, and during a mid-session avatar swap any generate_reply triggered in that gap stays routed to the previous audio destination. wait_remote_track=KIND_VIDEO buffers frames until the new video track actually shows up, so binding early doesn't drop audio.

Test plan

  • Confirm mid-session persona swaps in the LemonSlice avatar example route their first post-swap utterance to the new avatar's audio path.
  • First-time avatar bring-up still works (no regression: wait_remote_track keeps frames buffered until the video track arrives).

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 25, 2026

🦋 Changeset detected

Latest commit: 2c03b52

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

This PR includes changesets to release 33 packages
Name Type
@livekit/agents-plugin-lemonslice Patch
@livekit/agents Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-assemblyai Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-cartesia Patch
@livekit/agents-plugin-cerebras Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-fishaudio Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hedra Patch
@livekit/agents-plugin-hume Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-liveavatar Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-minimax Patch
@livekit/agents-plugin-mistral Patch
@livekit/agents-plugin-mistralai Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-perplexity Patch
@livekit/agents-plugin-phonic Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-runway Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugin-tavus 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

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 1 potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment on lines 259 to +263
waitPlaybackStart: true,
});

this.#logger.debug('starting avatar session');
const sessionId = await this.startAgent(livekitUrl, livekitToken);
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.

🔴 Audio output left in broken state if startAgent HTTP call fails

The reordering sets agentSession.output.audio to a new DataStreamAudioOutput (line 254) before the startAgent HTTP call (line 263). If startAgent throws — either an APIStatusError for non-retryable errors (line 319) or an APIConnectionError after all retries are exhausted (line 336) — the exception propagates out of start(), but agentSession.output.audio has already been permanently replaced with a DataStreamAudioOutput targeting an avatar participant that will never join the room. The DataStreamAudioOutput will then wait indefinitely in waitForParticipant (agents/src/voice/avatar/datastream_io.ts:128) for a participant that never connects, effectively making all subsequent audio output hang. The previous code (and all other avatar plugins — hedra, trugen, bey, anam, tavus, runway) set the audio output only after the upstream session creation succeeds, avoiding this corrupted-state-on-failure issue.

(Refers to lines 254-263)

Prompt for agents
The audio output is assigned before startAgent, so if startAgent throws, agentSession.output.audio is left pointing to a DataStreamAudioOutput for a non-existent avatar participant. The fix should save the original audio output before the assignment and restore it in a catch/finally block if startAgent fails. Something like:

const previousAudio = agentSession.output.audio;
agentSession.output.audio = new voice.DataStreamAudioOutput({...});
try {
  const sessionId = await this.startAgent(livekitUrl, livekitToken);
  return sessionId;
} catch (e) {
  agentSession.output.audio = previousAudio;
  throw e;
}

Relevant files: plugins/lemonslice/src/avatar.ts (start method, lines 198-266), agents/src/voice/avatar/datastream_io.ts (DataStreamAudioOutput constructor and _start method).
Open in Devin Review

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

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.

0 participants