You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(call): coalesce fragmented transcript finals in TTY display
Chunked TTS providers like Cartesia Sonic stream each assistant
utterance as 2-4 separate `transcript` events with `transcriptType:
"final"`, often split mid-sentence at punctuation. Before this change,
each fragment rendered on its own `🤖 Assistant:` line, so a single
turn like "Hi {seller}, this is William. This call may be recorded
for quality purposes. Is now a good time for a quick two-minute chat?"
displayed as three separate lines.
Introduce a time-based coalescing buffer keyed by role. Consecutive
finals from the same speaker are appended to a `FinalBuffer` and a
flush timer is reset on each arrival. Once `COALESCE_TIMEOUT_MS`
(600ms) passes without a new final, the fragments join into one line
and print with a single `🤖 Assistant:` / `🎤 You:` prefix.
Flush points cover the natural boundaries:
- Role change on a new `final` (e.g. user barges in mid-assistant
response) flushes the held buffer before starting the new one.
- `speech-update` with status `started` from the opposite role flushes
before announcing the new speaker, so the banner doesn't appear
above still-pending transcript from the last turn.
- `call-ended` and WebSocket `onclose` flush before printing the
ended line, so the final words match what the speaker actually said.
- `cleanup` (SIGINT/SIGTERM) flushes so Ctrl+C doesn't swallow the
last utterance.
Refactor the `lastTranscript` + `setLastTranscript` setter pair into a
single mutable `CallDisplayState` object shared between
`handleControlMessage` and the outer WebSocket closure. This keeps
the coalescing timer and partial-clearing state consistent in one
place instead of threading multiple getters/setters.
No network or agent behavior changes. Regression-safe: short
single-fragment finals print as before (one fragment → flush → one
line). Non-TTY output (CI logs, file redirects) still skips the live
partial overwrite but now also benefits from coalesced finals.
0 commit comments