Skip to content

fix(transcription): stop the synchronizer reporting the previous reply's transcript after an interrupt - #2141

Closed
toubatbrian wants to merge 1 commit into
mainfrom
brian/stale-synced-transcript
Closed

fix(transcription): stop the synchronizer reporting the previous reply's transcript after an interrupt#2141
toubatbrian wants to merge 1 commit into
mainfrom
brian/stale-synced-transcript

Conversation

@toubatbrian

@toubatbrian toubatbrian commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Problem

SegmentSynchronizer can get permanently stuck one segment behind. After an interrupt, every later reply is reported, committed to the chat context, and shown to the user with the previous reply's text while a different reply is the one actually being spoken; late in a session the reported text degrades further, to empty.

This is a text-path defect — the audio is correct throughout, only the transcript is wrong. It is not the production report of agent audio falling behind the transcript (see Scope).

Cause

On a barge-in a reply's playback_finished usually arrives before its text-forwarding task flushes. The finish rotates the segment, so the late flush() ends text input on the new impl instead. The next reply's first text chunk sees that impl marked textInputEnded and queues it in _pendingRotatedSegments, assuming its playback finish must still be in flight — but that impl never carried audio and is owed no finish, so nothing settles it. From then on each real finish is consumed settling the segment queued a turn earlier, which re-queues the current one and makes the off-by-one self-sustaining.

Fix

Add SegmentSynchronizerImpl.owesPlaybackFinished (carried audio downstream, not yet marked finished) and only enqueue a rotated-out segment when it is true. That is exactly the precondition the queue's own comment asserts, so the genuine interrupt-plus-fast-next-reply race it was built for still enqueues.

Testing

Two regression tests, red before / green after. Voice suite green at 566 tests. The three existing _pendingRotatedSegments tests pass unchanged — notably the one covering the case the queue was introduced for.

Scope — read this before merging

Written while investigating a live report of agent audio running behind the transcript after a barge-in. That report is now traced elsewhere: the gateway emits multiple done messages per session.flush on some TTS paths and the client returns on the first, truncating the reply and handing a still-streaming socket back to the pool. Fixes are in flight separately (#2144, #2146). The two defects share a vocabulary and are opposites: this one misreports text against correct audio, that one plays wrong audio against a correct transcript.

Also independent of the interruption stack (#2131#2142) — reproduces on main regardless of which of those is checked out. Python's _SyncedAudioOutput.on_playback_finished only ever reads the current impl and so cannot report another segment's text; this is a JS-only divergence.

…fter an interruption

An interrupted reply whose playback_finished arrives before its text forwarding flushes
leaves a rotated segment that looks text-ended while carrying no audio. The next reply's
first chunk mistook it for a segment awaiting an in-flight finish and queued it, but nothing
could ever settle an entry that owes no finish. From then on every real finish was consumed
to settle the segment queued a turn earlier, so each reply reported the previous reply's
transcript and the lag never recovered for the rest of the session.

Only queue a rotated-out segment when it genuinely still owes a playback finish.

Co-authored-by: Cursor <cursoragent@cursor.com>
@toubatbrian
toubatbrian requested a review from a team as a code owner July 28, 2026 00:54
@changeset-bot

changeset-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a136f8f

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

This PR includes changesets to release 39 packages
Name Type
@livekit/agents Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-anthropic Patch
@livekit/agents-plugin-assemblyai Patch
@livekit/agents-plugin-azure 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-krisp 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-protoface 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

@toubatbrian toubatbrian changed the title fix(voice): stop the agent transcript from running one reply behind after an interruption fix(transcription): stop the agent transcript from running one reply behind after a barge-in Jul 28, 2026
@toubatbrian toubatbrian changed the title fix(transcription): stop the agent transcript from running one reply behind after a barge-in fix(transcription): stop the synchronizer reporting the previous reply's transcript after an interrupt Jul 28, 2026
@toubatbrian

Copy link
Copy Markdown
Contributor Author

Closing: this came out of a misdiagnosis on my side.

The reported symptom — the agent's audio and its transcript disagreeing after a barge-in, with the lag compounding over a conversation — is caused by the inference gateway answering a single session.flush with several done events. That is fixed client-side in #2146 and server-side in agent-gateway#1105.

Measured on its own, #2146's branch contains only main + #2144 and none of this chain, and it already takes transcript-ahead windows from 3 to 0 and worst lag from 26.8s to 0 across 3 runs. So this PR is not needed for that bug.

The defect it fixes is real and has its own red/green test, and the branch is not deleted. If it ever shows up in practice it is worth reproposing on its own merit rather than as a barge-in fix.

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.

1 participant