Skip to main content

Overview

LiveKit Agents is an open-source framework for building real-time voice agents. Your agent joins a LiveKit room as a participant and exchanges audio with users over WebRTC or SIP telephony. An AgentSession wires together speech-to-text, LLM, and text-to-speech plugins and handles the orchestration, including turn detection and interruptions. The AssemblyAI plugin, livekit-plugins-assemblyai, provides assemblyai.TTS, which speaks your agent’s replies with the Streaming TTS API. Use it with the plugin’s assemblyai.STT and the LLM Gateway, and every model in the agent runs on one AssemblyAI API key.
assemblyai.TTS is available in livekit-plugins-assemblyai 1.8.9+.
What the plugin handles for you:
  • Streaming by sentence. Each sentence of the LLM’s reply is its own request, so the agent starts speaking after the first sentence rather than after the whole reply.
  • One session for many replies. The plugin keeps its WebSocket session open and reuses it for every reply, instead of opening a new one per reply.
  • Barge-in without reconnecting. When the user interrupts, the plugin cancels the audio still in flight and keeps the session.
  • Word-aligned transcripts. Per-word timings let LiveKit record an interrupted reply up to the word the user heard.

Quickstart

1

Install the packages

Install LiveKit Agents with the AssemblyAI, OpenAI, and Silero plugins. The OpenAI plugin connects the agent to the LLM Gateway, which speaks the OpenAI Chat Completions API.
2

Set your API keys

Set your API keys in a .env file:
You can get an AssemblyAI API key by signing up for a free account and going to the API Keys tab of the dashboard.
3

Build the agent

Save this as agent.py. It uses AssemblyAI for speech-to-text, the LLM, and text-to-speech:
4

Talk to it

Run the agent in console mode, which uses your computer’s microphone and speakers and needs only your AssemblyAI API key:
Recent livekit-agents releases print a deprecation notice for console and point at lk agent console, which runs the same mode through the LiveKit CLI. On a machine without a microphone, python agent.py console --text takes typed turns instead.Use headphones, so the agent doesn’t hear its own voice. To connect the agent to LiveKit for a web or phone frontend, run python agent.py dev with your LiveKit credentials set.
For the speech-to-text settings in this example, such as mode and vad_threshold, see Universal-3.6 Pro on LiveKit.

Reference agent

AssemblyAI reference voice agent for LiveKit

A complete starter agent that runs every model on AssemblyAI: a medical receptionist that takes a new patient’s intake details or looks up a returning patient, then books an appointment. It uses Universal-3.6 Pro with Medical Mode, the LLM Gateway, and Streaming TTS, and comes with tests and a Dockerfile for deploying to LiveKit Cloud. Fork it and make it yours.

Parameters reference

Choose a voice

Pass a voice to voice by its ID, a UUID. The default is Keegan, 987db62e-a2c2-569a-9c4d-82460cdea1bd, which differs from the API’s own default, aai-jane. voice takes any voice your account can use:
  • One of the AssemblyAI voices, each of which speaks the language it was recorded in.
  • A voice from the AssemblyAI voice library. These speak one language, the language of their recording.
  • A voice you cloned in the AssemblyAI dashboard.
The voice catalog in the AssemblyAI dashboard has a Copy voice ID action for each voice, and Voices lists good voices to start with. A slug such as aai-anna works too, but a voice’s ID never changes. A cloned voice works only on the host of the data zone it was created in.

Set the language

Set language to the language of the text your LLM writes:
language takes a language code ("es", "es-MX") or the language’s English name ("spanish"). The plugin sends the server the English name the API expects, so you can use the same codes you pass to assemblyai.STT. See Languages for the six supported languages. Choose a voice that speaks the language. Every voice, AssemblyAI, library or cloned, speaks only the language it was recorded in: leave language unset and the session speaks the voice’s language. The API doesn’t detect language, so an AssemblyAI voice speaks English unless you set language.

Keep data in the EU

base_url sets the data zone. It defaults to the US, wss://tts.us.assemblyai.com. To keep text and audio in the EU, point the TTS at the EU host, and the STT and LLM Gateway at theirs:
The EU LLM Gateway serves a different set of models; see Cloud endpoints and data residency. For the TTS endpoints, see Endpoints and data zones.

Interruptions and transcripts

When the user interrupts, the plugin sends Cancel on the open session and drops the audio of the interrupted reply that is still in flight. The session stays open, so the next reply doesn’t wait for a new handshake. The plugin requests word boundaries by default (word_timestamps=True) and publishes them to LiveKit as an aligned transcript. Set use_tts_aligned_transcript=True on the AgentSession to use them:
  • The transcript your frontend shows follows the agent’s speech word by word.
  • When the user cuts the agent off, the chat history keeps the reply only up to the word the user heard, so the LLM doesn’t think it said things it didn’t.

Latency

  • Call tts.prewarm() when the call starts, as in the quickstart. It opens the session before the first reply, so the greeting doesn’t wait on the handshake.
  • Greet with session.say(). A fixed greeting in on_enter is spoken as soon as the user joins, without waiting for the LLM.
  • Keep replies short. The agent speaks after the first sentence, so a short first sentence starts the audio sooner.

Sessions and rate limits

AssemblyAI counts TTS sessions per account by new sessions per minute, not by sessions open at once. Because the plugin reuses one session for many replies, a call usually opens one session. A session lasts at most an hour. The plugin doesn’t start a reply on a session that is about to expire: it opens a new one instead. The plugin retries a failed request when the server marks the error as retryable, and waits as long as the server’s retry_after_seconds asks before opening another session. If that wait is longer than the connection timeout, the plugin stops retrying, so a LiveKit tts.FallbackAdapter can move on to another TTS. See Error handling for the error codes.

Change the voice during a call

update_options changes the voice, language, or model:
The API fixes a session’s voice, language, and model when it opens, so the next reply opens a new session with the new options. A reply already playing keeps its voice until it finishes. Each new session counts toward your new sessions per minute.