Two specialist voice agents. One continuous call.
A working blueprint for the agent hand-off pattern. Aria takes the inbound dispatch call. Shipment status, carrier dialling, multilingual replies. The moment the caller asks about pricing, Aria hands the live audio to Theo, the rate negotiator, with the full conversation already loaded. The caller hears one voice change, never a hold-and-transfer. Two personas, one WebSocket, zero lost context.
No black box. Each step is a typed-frame node you can edit, monitor, and replace.
Aria takes the call. Inbound dispatcher conversation: shipment status, customer profile lookups, outbound calls to drivers. Multilingual, warm, brisk. Switches language automatically when the caller does.
Caller asks about rates. Aria recognises the topic, summarises what she's captured so far, and calls a single hand-off tool. The streaming runtime opens Theo's vendor session in parallel. Caller never hears hold music.
Theo activates with full context. Aria's conversation history flows into Theo's session prompt. No re-asking "what was your name again?". The verified caller, the shipment, the lane, the asked-for rate are all already loaded.
Theo negotiates, stays in lane. Rate discussion only. Anything outside pricing (billing, new shipments, account changes) gets persona-redirected back to dispatch. Same call, specialist voice, no scope creep.
Streaming graph contract, observability, and cost discipline come standard. The agent ships with a full test suite that runs in CI on every node version bump.
Replaces VAD + STT + LLM + TTS with one realtime model. Lower latency, fewer billing lines, fewer integration points. The standard chain stays available for mix-and-match deployments.
SteerFrame on steer_in mutates the live session via session.update. Voice + instructions swaps defer until response.done so providers don't reject mid-response changes; temperature + turn-detection swaps apply immediately.
modalities config swaps between audio (no transcript-delta emission) and audio_text (transcript on text_out). Saves provider tokens when no downstream node consumes the transcript.
OpenAI Realtime + Gemini Live both supported through the same node via STRONGLY_SERVICES routing. Provider_param_overrides escape-hatch for new provider knobs without forking the node.
Per-frame spans land in workflow_spans (Mongo), same path the batch runtime uses, same canvas viewer. No Prometheus, no Grafana, no external tracing.
RealtimeAuthError, RealtimeProtocolError, RealtimeAudioFormatError, RealtimeProviderError, RealtimeReadTimeout. Routed to the auto-injected streaming-errors sink so provider failures never block the voice loop.
Every dependency is a registered Strongly service or a model you control. Swap any one of them in the install wizard. The graph stays intact.
The marketplace template is the graph. Every customisation below is a config change or a single-node addition - never a rewrite.
Edit rt.config.voice or send a SteerFrame mid-session. Voice swaps defer until the current response finishes.
rt.config.system_prompt sets the initial instructions. Use SteerFrame.instructions for runtime mutations.
Set rt.config.modalities to audio to skip transcript-delta emission and save tokens.
Default is pcm16_16k on both sides. Switch to pcm16_24k for higher fidelity, or g711_mulaw for telephony bridges.
rt.config.provider_param_overrides is a dict merged into the initial session.update for OpenAI-Realtime-specific knobs (max_response_output_tokens, etc.).
Built for production, not demos. Schedule a demo and we'll get started deploying Realtime Voice Agent into your environment with your STT, your LLM, your TTS, your data.
Schedule a Demo