fix(tts): restart ChunkedStream retries under fresh request IDs#1994
Merged
Conversation
🦋 Changeset detectedLatest commit: d7698f6 The changes in this PR will be included in the next version bump. This PR includes changesets to release 36 packages
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 |
Close the retry metrics queue during shutdown so buffered attempt audio cannot race a closed output, with regression coverage for retry identity and close behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep ChunkedStream output open while buffered metrics drain so close cannot race the monitor's final output write. Co-authored-by: Cursor <cursoragent@cursor.com>
toubatbrian
approved these changes
Jul 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Testing
pnpm build:agentspnpm test -- agents/src/ttspnpm exec prettier --check agents/src/tts/tts.ts .changeset/fresh-tts-chunked-retries.mdPorted from livekit/agents#6346
Original PR description
Problem
test_tts_synthesize[deepgram]failed on main (run): a transient connection error mid-response causedChunkedStreamto retry after partial audio had already been emitted, so the consumer received frames from two attempts with mixedrequest_ids — and frames from the failed attempt could still trickle out after the retry started, interleaving the two attempts.Changes
ChunkedStream._main_task: settle the emitter (aclose) before retrying, so no stale frames from the failed attempt are delivered once the retry begins. The retry restarts synthesis under a freshrequest_id, signaling downstream that any partial audio from the failed attempt is stale. Also skip retries for non-retryable errors (matchingSynthesizeStream).tests/test_tts.py:_do_synthesisnow accepts a request_id restart — it asserts request_ids don't interleave between attempts and validates completeness/audio on the final attempt's frames. New testtest_tts_synthesize_retry_after_partial_audiocovers fail-once-then-succeed: exactly one retry, recoverable error event, two non-interleaved request_ids, full audio from the retry, one metrics event.tests/fake_tts.py:fake_exception_countoption to fail the first N attempts, and yield control between pushes so partial audio reaches the consumer like a real provider streaming over the network.Notes
SynthesizeStreamstill refuses to retry after partial audio (#5242); making it restart under a fresh request_id like this would be a follow-up.Cue voice E2E
d7698f69db7b54722fa8399fdfdd1e5f2f711490.sid_5daa00ab12cain voice mode.debug_message(.payload.path="chunked_retry_shutdown_playout_complete",.payload.retry_verified=true,.payload.cleanup_verified=true,.payload.playout_complete=true).cue-request-1thencue-request-2, one directly observed metrics event, and cleanup closed attempt/output queues and signaled abort/stream closure.events.jsonl,recordings/001_run/result.json, session WAV SHA-256eb7124bd3ee80877beb598627012ef88a88f9bd81293e4cc98b56dc45e83e3db, command WAV SHA-2566ab6732f8cac8b89fb922ea4884decf1f499b5619d69b6566bad58364181f1c9.