Pair force-completed text with a progress frame, drop unmatched buffered words - #5681
Open
dakshdua wants to merge 2 commits into
Open
Pair force-completed text with a progress frame, drop unmatched buffered words#5681dakshdua wants to merge 2 commits into
dakshdua wants to merge 2 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests.
... and 64 files with indirect coverage changes 🚀 New features to boost your workflow:
|
filipi87
reviewed
Sep 10, 2026
filipi87
reviewed
Sep 10, 2026
filipi87
reviewed
Sep 10, 2026
filipi87
reviewed
Sep 10, 2026
dakshdua
force-pushed
the
daksh/force-complete-word-stream
branch
2 times, most recently
from
September 10, 2026 23:03
a18c13a to
a17acaf
Compare
dakshdua
force-pushed
the
daksh/force-complete-word-stream
branch
from
September 10, 2026 23:12
a17acaf to
184d3e8
Compare
`force_complete` left a turn's word tracking in two inconsistent states, both of which showed up as the progress view and the `TTSTextFrame`s disagreeing about what the turn said. A slot force-completed with text still to speak emitted the remainder as a word frame, but nothing moved the cursors, so the progress view stopped where the provider stopped reporting. The tracker now takes that remainder as spoken and a progress frame goes out alongside the word frame. In streaming mode a word that matches no slot is buffered, waiting for a slot to be promoted to match it against. `_drain_buffered_words` runs only on promotion, so at the end of a turn the event stayed buffered and was discarded at the next reset, with nothing said about it. A context that ends now reports what it leaves behind, the way sentence mode already reports a word it cannot place, and drops it. Another context's buffered words are left for their own turn.
dakshdua
force-pushed
the
daksh/force-complete-word-stream
branch
from
September 11, 2026 17:18
184d3e8 to
ba65228
Compare
dakshdua
force-pushed
the
daksh/force-complete-word-stream
branch
from
September 11, 2026 21:03
ba65228 to
d55d5b0
Compare
dakshdua
force-pushed
the
daksh/force-complete-word-stream
branch
from
September 11, 2026 21:07
d55d5b0 to
5a76501
Compare
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.
Changes
force_completeleaves a turn's word tracking in two inconsistent states, both of which surface as the progress view and theTTSTextFrames disagreeing about what the turn said.A force-completed slot's remainder goes out with no progress frame
The remaining text is emitted as a word frame, but nothing moves the cursors, so the progress view stops where the provider stopped reporting. On a turn whose word stream is cut partway, the word frames cover the full text while the progress transcript ends mid-sentence.
WordCompletionTracker.take_remaining_as_spoken()moves the user-facing and LLM cursors to the end — the same thing the tracker already does when a word completes a slot — and a progress frame goes out alongside the word frame.A word that matches no slot stays buffered forever
In streaming mode a word event that no slot matches is buffered, waiting for a slot to be promoted to match it against (
aggregated_frame_sequencer.py:522-526)._drain_buffered_wordsruns only on promotion, so at the end of a turn the event stayed buffered and was discarded at the next reset, with nothing logged. Driving您好。as three tokens through a streaming sequencer:A context that ends now reports what it leaves behind — a warning naming the word, the way sentence mode already reports one it cannot place — and drops it. No frame is emitted: a word no slot matched has no place in the turn's text. Another context's buffered words are left alone for their own turn.
Both are gated on
self._streaming, since sentence mode never buffers a word in the first place.Testing
tests/test_aggregated_frame_sequencer.pyaddsTestForceCompleteWordStream: a buffered word is reported and dropped when its context ends, another context's buffered word is left alone, and a forced tail reports progress to the end.599 tests pass across the word-timestamp and text-tracking files (
test_aggregated_frame_sequencer,test_word_completion_tracker,test_text_segment_map,test_cartesia_tts, the ElevenLabs/Inworld/Soniox TTS files, the context aggregators andtest_tts_zero_audio_contexts).End to end, driving
CartesiaTTSServiceagainst the live Cartesia websocket withsonic-3.6, comparingmainagainst this branch over seven Chinese and Japanese scenarios on both the streamed-LLM andTTSSpeakFrameroutes, the progress-frame half fixes four cases and regresses none:'確認いたします…ゼ'<speed>,<emotion>,<break>and<spell>markup now reproduce the whole turn, markup included, in the progress transcriptReviewing
uv run pytest tests/test_aggregated_frame_sequencer.py. Either half is reachable from any provider that reports punctuation as its own word-timestamp entry, or that stops reporting entries mid-turn.