Skip to main content
Move the concierge from the quickstart onto LiveKit Agents in two prompts. Dialog-RSN-1 stays the model: it hears the caller, decides when they’ve finished, and writes the reply. LiveKit carries the audio and ElevenLabs speaks the reply. What you’ll build:
  1. agent.py: a LiveKit Agents worker with the concierge’s instructions and the check_availability tool, Dialog-RSN-1 as the model and ElevenLabs as the voice.
  2. A text test your coding agent runs itself, and a voice session you run in your terminal with lk agent console.
  3. The agent in a room on a local LiveKit server, with a scripted caller that asks about the spa, talks over a long reply, and saves the agent’s side of the call to call.wav.
Before you start:
  • Your coding agent set up as in the quickstart’s Set up your agent section: skill installed, POLY_API_KEY set, connection check passing.
  • The quickstart’s voice_agent.py, with the check_availability tool, in the folder you build in. Continue in the same agent session if you can, so it already knows the code.
  • An ElevenLabs API key in .env as ELEVEN_API_KEY. LiveKit’s ElevenLabs plugin reads that name, not ELEVENLABS_API_KEY. The free tier works while it has credits.
  • Python 3.10 or later with uv, as in the quickstart.
  • The LiveKit CLI: brew install livekit-cli. It gives you lk.
  • For Step 2, a LiveKit server. This page runs one on your machine with brew install livekit, which needs no account. To use a LiveKit Cloud project instead, put its URL, API key and secret in .env in place of the local ones.
If you’d rather write the code yourself, follow the LiveKit guide instead.

Step 1: make it a LiveKit agent

Prompt
The plugin isn’t on PyPI yet, so the prompt says where to get it. What it should build. A pyproject.toml with livekit-agents[elevenlabs], python-dotenv (the worker reads .env with it), and livekit-plugins-polyai installed from GitHub (livekit-plugins-polyai @ git+https://github.com/PolyAI-LDN/livekit-plugins-polyai). In agent.py, an Agent subclass with the concierge’s instructions, and check_availability as a @function_tool method that returns its result as a JSON string. The session takes two arguments:
There’s no stt and no turn detector: Dialog-RSN-1 does both jobs. There’s no WebSocket code either. The plugin opens the Dialog-RSN-1 session, streams the room’s audio in, and hands each tool call to your function. It asks Dialog-RSN-1 for text, so ElevenLabs speaks every reply and the voice changes from the quickstart’s server voice to an ElevenLabs one. The greeting comes from the instructions and a plain session.generate_reply(), because the plugin drops per-reply instructions. Your agent may also move the instructions and check_availability into a shared module, so voice_agent.py and agent.py stay in step. That’s fine. Check it. lk agent console runs the agent on your machine and connects it to your microphone and speakers. It needs no LiveKit server. It does need a real terminal, which is why your coding agent tests with lk agent debugger, the same text mode driven from a script. Start in text mode, which turns ElevenLabs off:
The concierge greets you. Type “Is the spa free on Friday?” The console shows the check_availability call and its result, then the concierge offers the slots. Then run lk agent console agent.py with headphones on, and talk to it. If it goes wrong:

Step 2: run it in a LiveKit room

Prompt
What it should build. Three lines in .env for the local server, which runs in dev mode with fixed credentials:
The agent runs as a worker with uv run agent.py dev, which registers it with the server and sends it into every new room. caller.py uses LiveKit’s Python SDK, not Dialog-RSN-1 directly. It signs a token with the same key and secret, joins a new room, and publishes a microphone track that streams generated speech in real time, with silence between lines. It records the agent’s audio track to call.wav and prints the transcript LiveKit publishes on the lk.transcription text stream. To know when to speak, it watches the agent’s lk.agent.state attribute, which goes from speaking to listening when a reply has played. For the barge-in, it starts the next line a second or two into the long reply instead of waiting. Check it. To run the call yourself, start each command in its own terminal, in this order:
You should see something like this, though the wording and the slots vary:
output
The long reply stops mid-sentence, within about a second of the caller cutting in. LiveKit stops the audio, and the plugin cuts the reply in the model’s history back to about the words the caller heard, so the next answer builds on what was actually said. The Caller lines are what Dialog-RSN-1 heard, sent with each reply. Play call.wav to hear the agent’s side, cut-off included. Some log noise is harmless. The worker may log that dev mode is deprecated in favor of lk agent dev: it still works. Both programs may print an InsecureKeyLengthWarning, because the dev server’s secret is short. And caller.py may print AssertionError lines from FfiHandle.__del__ as it exits, after it has saved call.wav: that’s LiveKit’s Python SDK cleaning up. If it goes wrong:

Troubleshooting

For key and connection errors, see the quickstart’s troubleshooting. The LiveKit guide’s troubleshooting covers the plugin’s other errors, and why not the OpenAI plugin explains the difference between the two.

Where to go next

LiveKit guide

The same agent, step by step, with what carries over from a standard LiveKit pipeline.

livekit-plugins-polyai

The plugin’s options and how each LiveKit feature maps to Dialog-RSN-1.

Prompt guide

Instructions for speech, including how patient the agent is before it replies.

LiveKit Agents docs

Deployment, telephony and the rest of the framework.
Last modified on October 21, 2026