Skip to content

fix: attribute playback evidence to its own segment on shared audio outputs#2055

Closed
chenghao-mou wants to merge 5 commits into
mainfrom
chenghao/fix/AGT-3148-own-segment-index
Closed

fix: attribute playback evidence to its own segment on shared audio outputs#2055
chenghao-mou wants to merge 5 commits into
mainfrom
chenghao/fix/AGT-3148-own-segment-index

Conversation

@chenghao-mou

Copy link
Copy Markdown
Member

Stacked on #1966; hardens its playback-evidence logic with per-segment attribution. Fixes AGT-3148.

Gate: the playedOwnFrame counter-delta could be satisfied by a straggler frame from the previous interrupted speech (JS can't cancel an in-flight reader.read(), so a late frame bumps the shared counter after the next speech snapshots), committing a never-played reply as partial with full-text fallback. The gate now requires ownSegmentIndex, the segment count read after the first of this segment's frames was actually accepted by captureFrame. Both mirrored gate sites now share hasOwnPlaybackEvidence.

Listener: PLAYBACK_STARTED carries no segment identity and the listener outlives forwarding (by design, per #1966), so a stale event from an overlapping segment (avatar's late lk.playback_started RPC, or the next speech starting during this one's teardown) could resolve the wrong segment's firstFrameFut: spurious speaking state, foreign timestamps in metrics, unheard text committed. The listener now only honors an event while the output's segment counter still points at its own segment, failing closed on ambiguity (genuine partial playback still commits via the position evidence).

Known residual: a stale avatar RPC arriving while the counter still points at this segment is locally indistinguishable from the segment's own event; the full fix needs a segment id in the RPC protocol. Python counterpart: livekit/agents#6470.

🤖 Generated with Claude Code

toubatbrian and others added 4 commits July 6, 2026 15:42
…warding completes

Combines #1910 (false-interruption pause before first frame, #1909) and
#1960 (deferred lk.playback_started from DataStream avatar outputs) into a
single change: the PLAYBACK_STARTED listener moves to performAudioForwarding
so it outlives the forwarding task, forwardAudio no longer settles
firstFrameFut, and all reply paths (pipeline, realtime, and say()) settle a
still-pending future via settleFirstFrameFut once the playout window ends. A
reported non-zero playback position on interruption is also honored as
evidence of partial playback.

Co-authored-by: enrique <enrique.espaillat@gydehealth.ai>
Co-authored-by: Jared Friedman <jared@ycombinator.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…ment count

startedForwardingAt is set before AudioOutput.captureFrame resolves, so a frame
that bails at a pause/interrupt gate (e.g. ParticipantAudioOutput while paused)
still looked like playback evidence, letting a stale playback position from a
previous segment commit a never-heard reply. Record the output's
capturedPlayoutSegments when forwarding is set up and only trust a non-zero
playback position when the count has since increased — the same condition under
which waitForPlayout returns this segment's event rather than a stale one.

Suggested by @chenghao-mou in #1966 review.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…audio outputs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3201100

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

This PR includes changesets to release 35 packages
Name Type
@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-did 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-lemonslice 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-soniox Patch
@livekit/agents-plugin-tavus Patch
@livekit/agents-plugins-test Patch
@livekit/agents-plugin-trugen Patch
@livekit/agents-plugin-xai 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

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

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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Base automatically changed from fix/late-playback-started-dropped-turns to main July 17, 2026 21:35
@toubatbrian
toubatbrian requested a review from a team as a code owner July 17, 2026 21:35
@toubatbrian

Copy link
Copy Markdown
Contributor

Could you resolve the conflicts from base branch?

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