Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(tts): restart ChunkedStream retries under a fresh request_id#6346

Merged
u9g merged 1 commit into
mainfrom
fix/tts-chunked-partial-retry
Jul 8, 2026
Merged

fix(tts): restart ChunkedStream retries under a fresh request_id#6346
u9g merged 1 commit into
mainfrom
fix/tts-chunked-partial-retry

Conversation

@u9g

@u9g u9g commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

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.

A transient mid-synthesis failure could leave frames from the failed
attempt and its retry interleaved under mixed request_ids (flaky
test_tts_synthesize failures). Now ChunkedStream settles the emitter
before retrying so no stale frames are delivered after the retry
starts, skips retries for non-retryable errors, and the retry's new
request_id signals downstream that partial audio from the failed
attempt is stale. Tests accept a request_id restart and validate the
final attempt's audio.
@u9g u9g requested a review from a team as a code owner July 7, 2026 20:11

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

Open in Devin Review

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.

🔍 Metrics accumulate audio duration from all attempts including failed ones

The _metrics_monitor_task at livekit-agents/livekit/agents/tts/tts.py:356-396 iterates over the shared _event_ch tee and accumulates audio_duration from every frame it sees. With this PR, partial audio from a failed attempt now flows through _event_ch before the emitter is closed, so the metrics will report an inflated audio_duration (sum of all attempts) and a ttfb measured from the very first attempt's start time. The request_id in the metrics will be from the last event (the successful attempt), which is correct, but the duration figures will be inaccurate after a retry with partial audio. This is a pre-existing design limitation that becomes more visible now that partial frames are intentionally delivered. The new test test_tts_synthesize_retry_after_partial_audio checks metrics_collected_events.count == 1 but does not assert on the audio_duration value.

(Refers to lines 356-396)

Open in Devin Review

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

@longcw longcw 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.

lgtm!

@u9g u9g merged commit 7c963b8 into main Jul 8, 2026
26 checks passed
@u9g u9g deleted the fix/tts-chunked-partial-retry branch July 8, 2026 11:05
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