aiAgentstableAI receptionist
Hands the caller to an AI voice receptionist — a natural, speech-to-speech agent that greets the caller, answers questions from its knowledge base, runs t…
What it does
Hands the live caller to an AI voice receptionist — a natural, speech-to-speech agent that greets the caller, answers questions from its knowledge base, runs tools (look up a contact, take a message, check business hours, send an SMS, transfer, escalate), and decides how the call should end.
Under the hood the node emits the Jambonz llm verb and breaks out of the
flow for the entire conversation (just like dial waits for a bridge). When the
session ends, the node resumes and routes on how the conversation ended —
the receptionist's terminal outcome, stamped onto vars.agentOutcome by the
tool the model called (or derived from the session-end reason when no tool
stamped one).
You build the receptionist once — persona, tools, knowledge base, business
hours, and the voice + model — in the dedicated AI receptionist builder, then
point this node at it with agentId. The node is the in-flow handoff; the
builder is where the brain is configured. The same receptionist can also be
bound directly to a phone number ("point this number at the receptionist")
without a flow at all; use this node when the receptionist is one step inside a
larger call flow (e.g. after an IVR menu, or as the after-hours branch).
The override fields (greeting, instructions, voice, model, vendor) are
escape hatches: leave them blank to run the receptionist exactly as saved, or
set one when a single flow needs to differ (a different greeting for the
after-hours line, say). instructions is kept as a stable, cacheable prompt
prefix — caller-specific data is injected by the runtime as conversation
items, never string-interpolated into the prompt.
When to use it
- Replace a phone-tree IVR with a conversational front door: callers say what they want instead of pressing 1-2-3.
- After-hours / overflow: route to the receptionist when no agent is available,
let it take a structured message (emailed to the owner) and end on
voicemail. - A self-serve tier in front of a queue: the receptionist answers FAQs from the
knowledge base and only
transfers /escalates the calls a human needs. - A specific sub-flow: drop it after a
gatherDigitsmenu so one menu option ("press 4 to talk to our assistant") reaches the AI while the others route normally.
Configuration
Hands the caller to an AI voice receptionist — a natural, speech-to-speech agent that greets the caller, answers questions from its knowledge base, runs tools (look up a contact, take a message, check hours, send an SMS), and decides how the call should end. Build the receptionist (persona, tools, knowledge base, business hours, voice + model) under AI receptionist, then point this node at it. The node waits for the whole conversation, then branches on how it ended: Transfer, Voicemail, Completed, Escalate, or Error. Override the greeting/instructions/voice/model here only when one flow needs to differ from the saved receptionist.
| Field | Label | Type | Required | Default | Notes |
|---|---|---|---|---|---|
agentId | Receptionist | text | Optional | "" | The published AI receptionist to run, by id. Manage receptionists under AI receptionist. Leave blank only when overriding everything inline below (instructions + voice + model) for a one-off agent. |
greeting | Greeting override | textarea | Optional | Thanks for calling Acme — how can I help today? | Optional. The first line the receptionist speaks. Overrides the saved receptionist's greeting for this flow only. Supports {{vars.x}} / {{caller.x}} / {{config.x}} templates. |
instructions | Instructions override | textarea | Optional | You are the receptionist for Acme Plumbing. Be warm and concise. Book callbacks, never quote prices. | Optional. Replaces the saved receptionist's system prompt for this flow only. Kept as a stable, cacheable prefix — caller-specific data is injected by the runtime, not interpolated here. Leave blank to use the receptionist as configured. |
voice | Voice override | text | Optional | Puck | Optional. Overrides the voice from the receptionist. Pick a voice id from the model picker in the receptionist builder (the available voices depend on the provider/model). |
model | Model override | text | Optional | gemini-2.5-flash-native-audio | Optional. Overrides the speech-to-speech model. Leave blank to use the receptionist (and the org default provider/model). Set the vendor below if you override this. |
vendor | Provider override | select | Optional | "" | Options: ``, google, openai. Optional. The speech-to-speech provider for the model override above. Only set this alongside a Model override. |
silenceMs | End-of-turn silence (ms) | number | Optional | 500 | How long the caller can pause before the receptionist treats them as done speaking and replies. Higher tolerates mid-sentence pauses; lower is snappier. Default 500ms. |
maxSessionSecs | Max session (seconds) | number | Optional | 600 | Hard cap on the AI conversation. When it elapses the session ends and the flow follows the Completed outcome. Backstop for runaway calls (and Gemini’s ~15-minute session limit). Clamped to 30–3600. Default 600 (10 minutes). |
Outcomes
Routing is only the five terminal outcomes — there is no plain "next" edge.
Each outcome is a canonical case on vars.agentOutcome, so you can also branch
on {{vars.agentOutcome}} in a downstream node. Wire every outcome you care
about; an unwired outcome simply ends the flow.
| Outcome | Fires when | Typical wiring |
|---|---|---|
Transfer (transfer) | The receptionist chose to hand off to a human / extension / number. The chosen target is in vars.agentTransferTarget. | A Dial/Transfer node using {{vars.agentTransferTarget}}, or a requestAgent. |
Voicemail (voicemail) | The receptionist took (or routed to) a message. With the default structured take_message, the owner is emailed; route to a goodbye + hangup. | A goodbye say → hangup, or a record node for a spoken voicemail. |
Completed (completed) | The conversation finished normally — caller satisfied, end_call, caller hangup, or the maxSessionSecs cap elapsed. | hangup, or a wrap-up side-chain. |
Escalate (escalate) | The receptionist escalated to a queue / on-call human. | enqueue into the right skill queue. |
Error (error) | The session failed — provider error, missing key, or an unrecoverable tool failure. | A safety net: a human-transfer or a "sorry, please hold" + enqueue. |
vars.agentTranscript holds the running conversation transcript for logging or
post-processing downstream.
Examples
Self-serve receptionist, then transfer or take a message
The receptionist answers from its knowledge base. If the caller asks for a person it transfers; if it takes a message it ends on voicemail; otherwise it wraps up.
{
"id": "reception-ai",
"type": "aiAgent",
"config": {
"agentId": "{{config.agentId}}",
"greeting": "Thanks for calling Acme — I'm the front desk assistant. How can I help?",
"silenceMs": 500,
"maxSessionSecs": 600
},
"on": {
"outcome-transfer": "dial-target",
"outcome-voicemail": "goodbye",
"outcome-completed": "goodbye",
"outcome-escalate": "sales-queue",
"outcome-error": "human-fallback"
}
}
The matching transfer leg reads the target the receptionist picked:
{
"id": "dial-target",
"type": "dial",
"config": { "to": "{{vars.agentTransferTarget}}", "timeoutSecs": 30 },
"on": { "call.bridged": "end", "call.hangup": "goodbye" }
}
Gotchas
- It auto-answers if needed. The realtime session needs media, so the node
answers the caller leg first when the call isn't already answered — the same
thing
gather/recorddo. You don't need a separateAnswernode before it. - No "next" edge — wire the outcomes. Unlike
say/gather, this node never takes a plain forward transition. Route at leastcompleted(and ideallyerror) so the call doesn't dead-end when the conversation finishes. - The overrides are for one-off divergence, not primary config. Persona,
tools, knowledge base, and business hours live on the receptionist entity
(
agentId). The inlineinstructions/voice/modelfields override the saved receptionist for this flow only; leave them blank to inherit. maxSessionSecsis a hard backstop. When it elapses the session ends and the flow follows the Completed outcome — it is the floor that fires regardless of what the model is doing (and covers the provider's own session limit). It is clamped to 30–3600 seconds.- Transfer target comes from the tool, not the node. The receptionist
decides where to transfer at conversation time; the destination lands in
vars.agentTransferTarget. Reference that in the downstreamDial/Transfer— don't hard-code a number on the node and expect the AI to use it. - Overrides render once, at entry.
{{vars.x}}ingreeting/instructionsresolves when the node is entered; mutating those vars mid-conversation has no effect on the already-open session.
