Full code on GitHub
A hotel front desk agent with two tools, ElevenLabs speech, and a scripted caller that runs a whole call, barge-in included.
What you’ll build
- A front desk agent for a fictional hotel with two tools: one looks up a booking, the other changes its checkout time.
- An
AgentSessionthat uses Dialog-RSN-1 as the model and ElevenLabs as the voice. Dialog-RSN-1 replaces the speech-to-text plugin, the turn detector and the LLM. - Barge-in. Talk over the agent and it stops, and the model’s history keeps only the words the caller heard.
- A scripted caller that joins the room and runs a whole call, barge-in included, so you can test without a microphone.
What changes from a standard LiveKit pipeline
A standard LiveKit pipeline chains speech-to-text, an LLM and text-to-speech, with a turn detector deciding when the caller has finished. Dialog-RSN-1 takes the caller’s audio and handles every job except the voice:
Dialog-RSN-1 plugs into LiveKit through its own plugin,
livekit-plugins-polyai. Dialog-RSN-1 speaks the OpenAI Realtime protocol, but LiveKit’s OpenAI plugin isn’t built for it. Why not the OpenAI plugin explains the difference.
Before you begin
- A Dialog-RSN-1 API key. Sign up or log in at studio.poly.ai and create one in the API Keys tab. The quickstart walks through it.
- An ElevenLabs API key. The free tier works.
- Python 3.10 or later, and uv.
- The LiveKit CLI:
brew install livekit-cli. - For Step 6: a LiveKit Cloud project, or a local server (
brew install livekit).
Step 1: Get the code
Step 2: Configure your environment
.env and set two keys:
ELEVEN_API_KEY, not ELEVENLABS_API_KEY. Leave the LIVEKIT_* values alone until Step 6.
Step 3: Point the session at Dialog-RSN-1
agent.py builds the whole session in a few lines:
- No
stt. Dialog-RSN-1 takes the room’s audio as it arrives. You still see the caller’s transcript in LiveKit, because Dialog-RSN-1 sends it with each reply. It comes at the end of a completed reply, so a turn whose reply is cancelled before it finishes generating has no transcript. - No
turn_handling. You have no turn detector to configure. Dialog-RSN-1 judges each pause in the context of the conversation. To make it more or less patient, say so in the instructions. The prompt guide shows how. - No instructions on
generate_reply(). The plugin drops per-reply instructions with a warning, so the greeting lives in the agent’s main instructions.
polyai.realtime.RealtimeModel() reads POLY_API_KEY and connects to wss://api.studio.poly.ai/v1/realtime. To use a different endpoint, set DIALOG_REALTIME_URL. It asks Dialog-RSN-1 for text, and the TTS plugin speaks each reply as the text streams in.
The two tools are ordinary LiveKit function tools:
Step 4: Run the agent
--text. Text mode skips TTS and runs only Dialog-RSN-1 and the tools:
Step 5: Test the conversation
The agent greets you with “Hello, Grand Meridian Hotel. How can I help you today?” Then try four things:- Say “Can you look up booking GM40912?” The agent calls
look_up_reservationand reads back the booking. - Say “Could I check out at two instead?” The agent tells you whether there’s a fee and asks you to confirm before it calls
change_checkout_time. - Ask something with a long answer, then talk over the reply. The agent stops and answers your new question.
- Pause mid-sentence, for example while you read out the booking code. The agent should wait for you to finish.
Step 6: Run it in a LiveKit room
To use LiveKit Cloud, put your project’s URL, API key and secret in.env. To stay on your machine, start a local server and keep the defaults from .env.example:
call.wav so you can listen back.
Add Dialog-RSN-1 to an existing LiveKit agent
-
Install the plugin from GitHub. It isn’t on PyPI yet:
-
Import it:
from livekit.plugins import polyai. -
Add
POLY_API_KEYto your environment. -
In your
AgentSession, setllm=polyai.realtime.RealtimeModel(). Removesttandturn_handling, and keep yourtts. -
Move any instructions you pass to
generate_reply()into the agent’s main instructions.
Why not the OpenAI plugin
You can point LiveKit’sopenai.realtime.RealtimeModel at Dialog-RSN-1 by changing base_url and the key, but it’s built for OpenAI’s models. livekit-plugins-polyai is built for Dialog-RSN-1:
The plugin implements LiveKit’s realtime model interface directly instead of patching another plugin, so a LiveKit upgrade is less likely to break it. Found a bug, or want a feature? Open an issue or send a pull request.
Choose a different voice
To change the ElevenLabs voice, pass a differentvoice_id. The repo uses Sarah, which works on the free tier. Some library voices, such as Rachel, don’t.
To switch provider, swap the plugin. For Cartesia, install its plugin:
CARTESIA_API_KEY to .env, then change the tts line:
agent.py changes. LiveKit’s TTS models page lists every provider it supports.
Troubleshooting
What doesn’t carry over
- Turn-handling options. LiveKit’s turn detector, endpointing delays and preemptive generation don’t apply, because Dialog-RSN-1 decides when the turn ends.
- Per-reply instructions.
generate_reply(instructions=...)has no effect, because the plugin doesn’t send them. Put the behavior in the agent’s instructions. - STT features. With no STT plugin, options such as keyterm prompting have nothing to configure. Dialog-RSN-1 transcribes the caller as part of each turn.
- Playback reports. The plugin doesn’t send Dialog-RSN-1’s
poly.output_audio.*events yet. The streaming text-to-speech guide explains what they add.
Where to go next
- The OpenAI Realtime migration guide lists every field Dialog-RSN-1 accepts and rejects.
- The prompt guide covers turn-taking instructions in depth.
- The API reference lists every client and server event.
- The
livekit-plugins-polyaiREADME lists every option and how each LiveKit feature maps to Dialog-RSN-1. - LiveKit’s Agents docs cover deployment, telephony and the rest of the framework.

