Skip to content

fix(tts): restart ChunkedStream retries under fresh request IDs#1994

Merged
toubatbrian merged 3 commits into
mainfrom
labia-costed-meres
Jul 15, 2026
Merged

fix(tts): restart ChunkedStream retries under fresh request IDs#1994
toubatbrian merged 3 commits into
mainfrom
labia-costed-meres

Conversation

@rosetta-livekit-bot

@rosetta-livekit-bot rosetta-livekit-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Testing

  • pnpm build:agents
  • pnpm test -- agents/src/tts
  • pnpm exec prettier --check agents/src/tts/tts.ts .changeset/fresh-tts-chunked-retries.md
  • Focused retry and close-race regressions: 8 tests passing.

Ported from livekit/agents#6346

Original PR description

Problem

test_tts_synthesize[deepgram] failed on main (run): a transient connection error mid-response caused ChunkedStream to retry after partial audio had already been emitted, so the consumer received frames from two attempts with mixed request_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 fresh request_id, signaling downstream that any partial audio from the failed attempt is stale. Also skip retries for non-retryable errors (matching SynthesizeStream).
  • tests/test_tts.py: _do_synthesis now 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 test test_tts_synthesize_retry_after_partial_audio covers 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_count option 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

SynthesizeStream still 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

  • Exact verified head: d7698f69db7b54722fa8399fdfdd1e5f2f711490.
  • Session: sid_5daa00ab12ca in voice mode.
  • Predicate: debug_message(.payload.path="chunked_retry_shutdown_playout_complete",.payload.retry_verified=true,.payload.cleanup_verified=true,.payload.playout_complete=true).
  • Result: resolved in 1,633 ms after playout completed and state returned from speaking to listening; exactly two ordered retry attempts used cue-request-1 then cue-request-2, one directly observed metrics event, and cleanup closed attempt/output queues and signaled abort/stream closure.
  • Persisted evidence: events.jsonl, recordings/001_run/result.json, session WAV SHA-256 eb7124bd3ee80877beb598627012ef88a88f9bd81293e4cc98b56dc45e83e3db, command WAV SHA-256 6ab6732f8cac8b89fb922ea4884decf1f499b5619d69b6566bad58364181f1c9.
  • Provider boundary: deterministic local ChunkedStream/TTS boundary exercising retry, playout, and shutdown; this was not a production provider call.

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from a team as a code owner July 8, 2026 11:11
@changeset-bot

changeset-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d7698f6

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

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

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from u9g July 8, 2026 11:12
devin-ai-integration[bot]

This comment was marked as resolved.

toubatbrian and others added 2 commits July 14, 2026 17:40
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>

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

View 1 additional finding in Devin Review.

Open in Devin Review

Comment thread agents/src/tts/tts.ts
@toubatbrian
toubatbrian merged commit b9d8e95 into main Jul 15, 2026
9 checks passed
@toubatbrian
toubatbrian deleted the labia-costed-meres branch July 15, 2026 20:58
@github-actions github-actions Bot mentioned this pull request Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant