Typed chats pick About-FAQ lines with Jev. Talk to Z is one live conversation with the whole About-FAQ in the opening prompt.
A product question does not carry the whole About-FAQ. The list is the 90
questions in packages/z-agent/srv/src/faq.ts. On each question, Jev picks
up to three. Only those answers go into that reply.
Typed chats use that picker (ZLY-2018, ZLY-2021, ZLY-2060). Talk to Z
(/dashboard/z-voice, ZLY-2051) does not. It is one Gemini Live session
with the whole About-FAQ already in the opening prompt.
selectFaqEntries runs when the person's message is in. It waits up to 2.5
seconds. composeFaqTurn folds any answers already used in this chat into
the same block. The model writes the reply with that block, and nothing else
from the list.
A scripted replay never calls Jev. A turn that only stores the person's message never starts the lookup.
Opening the page calls POST /api/z-agent/voice/session. That mints one
live token. It does not open an agent room and it does not attach tools or
home-room memory. The first session-update carries the persona and the
whole About-FAQ. The model is google/gemini-3.8-live through the AI Gateway,
tagged agent:z-voice plus the environment tag. The gateway key stays on
the server.
The same socket stays open until the person ends the conversation. The mic does not inject an About-FAQ note and does not cancel the model's reply. A chip sends that question into the same session and asks it to speak once. The mic is muted while Z is speaking so the speaker does not start another turn.
When the person ends the conversation, POST /api/z-agent/voice/turn saves
the transcript. The live model never reads that record, and the lines are
not distilled.
Jev does not choose the face. Gemini does not either. The page does, from
Jon's HTML, in z-voice-cues.ts. There are two clocks, and neither one
calls the About-FAQ picker.
The mouth follows the sound that is playing. Each frame measures the voice:
how loud it is, how open it is, and where the energy sits. visemeFor picks
one of eight mouth drawings. Silence closes the mouth. A bright hiss (f, v,
s, sh) uses the fricative mouth. A vowel becomes ah, oh, oo, ee, or eh from
the formant. The drawing stays up for about 65 milliseconds so the mouth
does not flicker.
Eyes, pose, and a laugh follow the words, not the sound. When a sentence
ends, cuesFromText matches a few phrases:
| What Z said | What the face does |
|---|---|
| sorry, can't, don't have | concerned eyes, a shrug |
| free, yes, of course | happy eyes, a thumbs-up |
| never, always, you sign, the key | confident eyes, a raised finger |
| a sentence with ! | excited eyes |
| great, love, welcome | happy eyes |
| a sentence that ends in ? | surprised eyes, pointing, and it holds |
| haha, lol | a laugh |
The transcript arrives before the voice. The cue waits at a character position and fires when the speech reaches it, about 15 characters a second. Arms stay crossed when nothing in the sentence matched.
| Rule | Value |
|---|---|
| New matches on one question | at most 3 |
| Score | strictly above 0.1 |
| "None of these" | never injected |
| Time limit | 2.5 seconds, then no new About-FAQ text |
| Jev down | Gemini 3.1 Flash Lite, inside that same limit |
Chip markers such as [Chip: Personalize my agent] | stripped before the model sees them |
| Answers kept for later questions | at most 8, this person's side only |
The kept ids travel on the typed reply. Talk to Z does not call this picker.
The page does not show a cost box. When the spoken reply finishes, the
journey event z_voice_reply_completed records that reply's reported usage
once. Silence does not add a guess.
Prices are the Gemini 3.8 Live list, October 2026, US dollars per 1 million tokens. Audio is about 25 tokens a second.
| Per 1M tokens | About one minute of audio | |
|---|---|---|
| Text in | $0.75 | |
| Audio in | $3.00 | $0.0045 |
| Text out | $4.50 | |
| Audio out | $12.00 | $0.018 |
On Talk to Z the About-FAQ is text in the opening prompt, so it is billed with that session's text input. Typed chats still pay for the Jev lookup separately.
| Area | File |
|---|---|
| The 90 questions and the picker | packages/z-agent/srv/src/faq.ts |
| Typed reply waits for the About-FAQ block | packages/z-agent/srv/src/rooms.ts |
| Opening prompt with the whole About-FAQ | packages/z-agent/srv/src/z-voice-session.ts |
| Transcript saved when the talk ends | packages/z-agent/srv/src/z-voice-room.ts |
| The spoken page | packages/z-agent/client/src/components/z-voice/ZVoicePage.tsx |
| Mouth, eyes, and pose | packages/z-agent/client/src/components/z-voice/z-voice-cues.ts |
| Open the live session | apps/zooly-app/app/api/z-agent/voice/session/route.ts |
| Save the transcript | apps/zooly-app/app/api/z-agent/voice/turn/route.ts |
packages/z-agent/srv/src/faq.test.ts checks the 90 entries, the score
cutoff, the time limit, and which answers stay.z-voice-session.test.ts checks that the opening instructions contain
the whole About-FAQ and tell Z to remember the conversation.z-voice-cues.test.ts checks the word-to-face rules and the mouth
choice. Jev is not in that test.