Summary
Related to #5196 (duplicate finals). The ElevenLabs Scribe v2 realtime server re-sends partial_transcript messages that carry no new information, and ElevenLabsRealtimeSTTService pushes each one as a fresh InterimTranscriptionFrame. With the default user-turn start chain (TranscriptionUserTurnStartStrategy(use_interim=True)), a stale repeat arriving while the bot is speaking opens a phantom user turn and cancels the in-flight bot reply mid-sentence.
Server behavior (probed against the live API, 2026-08-02)
wss://api.elevenlabs.io/v1/speech-to-text/realtime, model_id=scribe_v2_realtime, commit_strategy=manual:
- Shortly after a commit, the server re-sends a
partial_transcript repeating the text that was just committed.
- The last uncommitted partial is re-emitted roughly every 1s indefinitely — even when the subsequent input audio is pure silence (all-zero PCM).
Observed timeline (audio with speech, commit at 1.70s, silence streamed afterwards):
[1.31s] partial_transcript "Hello. How's your day going?"
[1.41s] partial_transcript "Hello. How's your day going?" <- identical repeat
[1.70s] >> commit
[1.81s] partial_transcript "Hello. How's your day going?" <- post-commit echo of committed text
[1.81s] committed_transcript
[1.91s] committed_transcript_with_timestamps
[2.92s] partial_transcript "Good." <- uncommitted tail
[3.82s] partial_transcript "Good." <- 1s-cadence refresh, input is silence
[4.83s] partial_transcript "Good."
...
Impact
In a voice pipeline, the post-commit echo partial lands ~0.1-1s after the final — right as the bot starts answering — and triggers an interruption. In our production-like testing every bot reply was cut off within ~1s.
Suggested fix
Dedupe in _on_partial_transcript: drop a partial whose text equals the previous partial's text (refresh, no new info) or the last committed text (post-commit echo), clearing the committed-echo suppression once genuinely new text arrives. Genuine partial progression (text grows/changes) passes through, preserving the soft-speech turn-start fallback.
Affects at least 1.6.0 and 1.7.0.
Summary
Related to #5196 (duplicate finals). The ElevenLabs Scribe v2 realtime server re-sends
partial_transcriptmessages that carry no new information, andElevenLabsRealtimeSTTServicepushes each one as a freshInterimTranscriptionFrame. With the default user-turn start chain (TranscriptionUserTurnStartStrategy(use_interim=True)), a stale repeat arriving while the bot is speaking opens a phantom user turn and cancels the in-flight bot reply mid-sentence.Server behavior (probed against the live API, 2026-08-02)
wss://api.elevenlabs.io/v1/speech-to-text/realtime,model_id=scribe_v2_realtime,commit_strategy=manual:partial_transcriptrepeating the text that was just committed.Observed timeline (audio with speech, commit at 1.70s, silence streamed afterwards):
Impact
In a voice pipeline, the post-commit echo partial lands ~0.1-1s after the final — right as the bot starts answering — and triggers an interruption. In our production-like testing every bot reply was cut off within ~1s.
Suggested fix
Dedupe in
_on_partial_transcript: drop a partial whose text equals the previous partial's text (refresh, no new info) or the last committed text (post-commit echo), clearing the committed-echo suppression once genuinely new text arrives. Genuine partial progression (text grows/changes) passes through, preserving the soft-speech turn-start fallback.Affects at least 1.6.0 and 1.7.0.