Anatomy of a voice agent
From the microphone to the agent's reply: what each part does, and what breaks without it.
A voice agent is a loop: a microphone, something that understands, something that answers, a speaker. Between the microphone and speech-to-text sit the parts that decide what the agent actually hears.
A basic voice agent
Start without Alkove. A microphone, speech-to-text, a model that answers, a voice, a speaker. The agent's voice comes out of the speaker, and some of it comes back into the microphone.
Speech-to-text gets everything the microphone takes: the user, but also the TV, a colleague across the room, someone beside the user. Words nobody said to the agent end up in the transcript, and a laugh from the TV can open a turn.
Focus: only the user gets through
Alkove goes between the microphone and speech-to-text, on the device, one brick at a time. The first, Focus, keeps the closest voice and removes the rest: noise, music, the TV, voices further away. What comes out is the user's voice, leveled, as plain audio that any speech-to-text or realtime model takes.
The person beside the user is about as close as the user, so their voice stays for now. The print, further down, settles it.
DocsFocus
Cue: when the user speaks, and when they are done
Cue tells, every 30 ms, whether someone speaks. On an agent input it gives speechstart and speechend, one utterance per sentence with the syllables just before it, and turnend when the user is done.
A pause in the middle of a sentence does not end the turn: turnend comes from Cue's end-of-turn head, read during each pause, so the agent answers when the user has finished, not when they breathe.
Cue hears every voice Focus lets through: the person beside the user, and the user's short "mm" while the agent talks. The next sections sort them out.
Spot: a word to start
An agent does not have to take every sentence: it can wait for its name. Spot hears a word typed as text, in 7 languages, with no training and no recording session.
input.spot() reads Focus's output in the same worker, so one microphone feeds both, and the app sends on only the sentence the word opened, word included.
DocsSpotWake words
Timbre: whose voice it is
Timbre makes a voiceprint, a small vector that stands for one voice. With a print, Focus keeps only that person, even when someone else is closer or louder: the voice beside the user goes, and it no longer interrupts the agent.
No enrollment screen is needed. With learn: true, the input learns the print from the user's own speech, about 6 s of it, and switches to it at the next pause. The same print makes Spot wake only on the user's voice.
The agent hears itself: farEnd
The agent's voice comes back into the microphone. The browser's echo cancellation takes most of it out. farEnd tells the input when the agent talks, so the print never learns the agent's voice, and speech over the agent is read as a possible interruption, in three steps.
interruptstart when the user starts talking over the agent: lower its volume. interruptcancel if it was only a "mm". interrupt once the speech lasts 0.7 s: stop the agent. Alkove does not stop the text-to-speech itself, it tells the app when to.
Putting it together
One input carries the whole chain. Each line lights its part of the scene.
const word = await Spot.compile('Nova', { lang: 'en' })const input = await createAgentInput({ near: true, learn: true, farEnd: 'manual' })input.spot([word], { context: 'pause' }).on('wake', open)input.on('utterance', ({ pcm }) => transcribe(pcm))input.on('turnend', () => llm.respond())input.on('interrupt', () => player.stop())player.onplay = () => input.farEndActive(true)The rest is the app's choice: any speech-to-text, any model, any voice, or a realtime model in place of the three. The whole guide is in the docs, and the demo runs these models on your own voice.