What you’ll build
Nexus greets the caller, asks whether they’re on Mac or Windows, and walks them through Level 1 troubleshooting steps. By the end of this guide you’ll have:- a saved agent on the Lyzr Voice API (reusable across sessions),
- a Python script that starts and ends sessions,
- a React component that connects a browser microphone to a live session,
- a script that pulls the transcript and latency metrics for any past call.
Prerequisites
- A Lyzr API key. Set it as
LYZR_API_KEYfor the Python scripts. - Python with
requests(pip install requests). - For the browser section: a React app that can install npm/pnpm packages.
1. Pick your models and a voice
Pipeline mode runs three separate models — STT, LLM, TTS — plus a TTS voice. Before creating the agent, ask the API which options are available so you can pick concrete values for each.engine.voice_id in the next step.
This script takes the happy path: the first configured provider, the first model in each list, the first voice. In production code, handle empty results explicitly and let users pick a voice rather than auto-selecting one.
2. Create the Nexus agent
POST /agents saves an agent definition so you don’t have to send the whole config on every session. The response includes agent.id — store it; the rest of this cookbook references it.
Only
agent_name, prompt, and engine are strictly required. Everything below the second comment in the payload is polish — drop it for a stripped-down agent and add it back as you need it.3. Start and end a session
Starting a session dispatches the Python worker, creates a LiveKit room, and returns the credentials your client needs to join. Request toPOST /sessions/start:
livekitUrl and userToken into the LiveKit client in the next step. When the call is done, call POST /sessions/end with either roomName or sessionId.
The Python script below handles only the lifecycle — it doesn’t publish a microphone or play audio. On its own it just opens an empty room and waits. You’ll connect a real microphone in step 4.
POST /sessions/end returns immediately and marks the session as ended on the API side. The transcript becomes available once the worker flushes its buffers and observability data arrives — typically a few seconds after the LiveKit room closes.4. Connect from the browser
The REST API has done its job; from here, all the audio plumbing belongs to the LiveKit SDK. We’ll build two files:voice-api.ts— a thin wrapper around/v1/sessions/startand/v1/sessions/end.NexusVoiceWidget.tsx— a React component that joins the room and renders the agent’s audio.
voice-api.ts
NexusVoiceWidget.tsx
The widget renders two audio sinks inside <LiveKitRoom>:
RoomAudioRenderer— plays the agent’s voice. This is the one you actually hear Nexus through.BackgroundAudioRenderer— a small custom renderer that attaches the optionalbackground_audiotrack (office ambience, keyboard sounds during tool calls). It’s separate because the default renderer doesn’t surface non-voice tracks.
<NexusVoiceWidget apiKey={...} agentId={...} /> somewhere in your app, click Start call, grant microphone permission, and you should hear Nexus’s greeting within a second or two.
In a real app, never pass
apiKey straight to the browser. Proxy /v1/sessions/start through your own backend so the key stays on the server.5. Read transcripts and metrics
Once a call has ended and the worker has flushed, you can pull aggregate stats for the agent and a per-session transcript with latency metrics on each turn.llm_node_ttft is the time from the user finishing their turn to the first LLM token; tts_node_ttfb is the time from that first token to the first byte of synthesized audio. Together they’re the dominant contributors to perceived latency.
Where to go next
- Swap
engine.kindfrom"pipeline"to"realtime"to use a single multimodal model instead of three. - Add tools to the agent payload so Nexus can look up tickets, reset passwords, or hand off to a human.
- Stream transcripts in realtime by subscribing to LiveKit data tracks instead of polling
/transcripts/{sessionId}afterward.