Part 1
The call as a state machine
A voice call is 4 states and 6 events. Model who is speaking as a pure reducer, testable without a microphone.
Study first
- The pipeline the curriculum describes: microphone, speech-to-text, the model, text-to-speech, speaker. A production line streams at every stage and starts speaking before the model has finished; this build keeps replies short (300 characters at most) and speaks each whole.
- Interruption and turn-taking: the caller may speak while the assistant does. The assistant must stop speaking and listen.
Build
src/lib/voice-model.ts:Voiceis{ state, turns, interim }with statesidle,listening,thinking,speaking; eventsstart,stop,heard(text and whether it is final),reply,spoken.next(voice, event): a final transcript while listening appends a caller turn and moves to thinking; a reply appends a WorkBot turn and moves to speaking;spokenreturns to listening.- The interruption rule in one branch:
heardwhile speaking moves to listening, with the words as the interim text. Everything heard while idle or thinking is ignored. - Tests: a full turn, the interruption, and what is ignored.
Done when
pnpm test src/lib/voice-modelpasses 3 tests, and the interruption test ends inlisteningwithinterimset, fromspeaking.
Technical notes
- The reducer holds no browser objects, so the component is the only place that touches the microphone, the recognizer and the synthesizer.
- Ignoring words heard while thinking is a choice: the model is already answering what was said. A final transcript at that moment would otherwise start a second request in parallel.
interimis the caller's words so far, shown in italics; it is cleared when a final transcript arrives or the call stops.

