LiveKit Agents

Gemini with LiveKit

Gemini in a LiveKit agent: through our plugin, or through LiveKit's Gemini plugin pointed at the router.

View as Markdown

With our plugin#

Gemini’s speech models with every setting of LiveKit’s Gemini plugin, from version 0.5.0 of our plugin. Gemini speaks the language of the text, at 24000 Hz, and takes no language or speed: ask for a pace or a tone in instructions. The 3.8 and 3.1 models stream a sentence’s audio as they make it; the 2.5 models send it once it is complete, so their first audio takes a few seconds longer.

pip install livekit-plugins-tts-cache-router
agent.py
from livekit.plugins import tts_cache_router as tcr# The API key comes from TTS_CACHE_ROUTER_API_KEY.tts = tcr.TTS(    model="gemini/gemini-3.8-flash-tts",    voice="Kore",)

Pass tts to AgentSession(tts=tts). Set TTS_CACHE_ROUTER_API_KEY in the agent’s environment, and store your Gemini key under Provider keys. TTS’s own arguments are on the plugin’s page.

Options#

tcr.TTS(...)’s settings for Gemini, in the router’s names: model, voice, language and speed as arguments, and the rest in the options dict (options={"name": value}). The router checks them; the languages per model are in Models and options.

modelstringRequired

One of gemini/gemini-3.8-flash-tts, gemini/gemini-3.8-flash-lite-tts, gemini/gemini-3.1-flash-tts-preview, gemini/gemini-2.5-flash-preview-tts, gemini/gemini-2.5-pro-preview-tts

Which model synthesizes the replies, with its provider.
voicestr | NoneRequired, unless options.speakers
A voice of the chosen model, passed to Gemini as given. See models and voices. With options.speakers, None.
sample_rateintDefault 24000

One of 24000

Of the audio you receive, in Hz.
options.instructionsstring | nullDefault null
How to speak: style, tone, accent, pace. Null: for gemini-2.5 and gemini-3.1, LiveKit's plugin's default ("Say the text with a proper tone, don't omit or add any words"), which keeps them reading the text; for gemini-3.8, none.
options.speakersobject | nullgemini-3.8-flash-tts, gemini-3.8-flash-lite-tts only. Default null
Two speakers' names, each with a voice (a multi-speaker voice config); replaces voice. Requires speaker.
options.speakerstring | nullgemini-3.8-flash-tts, gemini-3.8-flash-lite-tts only. Default null
Which of speakers voices this request.

Changing settings#

Replies that start afterwards use the new settings:

Python
tts.update_options(options={"instructions": "Speak calmly and slowly."})# Two speakers (the 3.8 models): no voice, and the speaker of each reply in options.tts = tcr.TTS(    model="gemini/gemini-3.8-flash-tts",    voice=None,    options={"speakers": {"Joe": "Kore", "Jane": "Puck"}, "speaker": "Jane"},)tts.update_options(options={"speakers": {"Joe": "Kore", "Jane": "Puck"}, "speaker": "Joe"})

With LiveKit's Gemini plugin#

Keep livekit-plugins-google and point it at the router: your router API key in place of your Gemini key, and the router’s address.

pip install livekit-plugins-google
agent.py
import osfrom livekit.plugins import googleos.environ["GOOGLE_GEMINI_BASE_URL"] = "https://api.ttscacherouter.dev/gemini"tts = google.beta.GeminiTTS(    model="gemini-3.8-flash-tts",    voice_name="Kore",    api_key=os.environ["TTS_CACHE_ROUTER_API_KEY"],)

The plugin has no base_url: Google’s GenAI SDK reads GOOGLE_GEMINI_BASE_URL when the plugin creates its client, so set it before creating the TTS, in code as above or in the agent’s environment. It applies to every Gemini API client the process creates, so in an agent that also uses Gemini as its LLM, use our plugin instead. Vertex AI (vertexai=True) doesn’t go through the router.

The plugin doesn’t stream text, so an AgentSession sends it one sentence at a time, and each sentence is cached on its own. With the 3.8 models, its requests are the ones our plugin makes, so the two share cached sentences. The other differences from calling Google are on Gemini API drop-in.

Requests, responses and errors keep Gemini’s own shape; the endpoints are on Gemini API drop-in.

Which to choose#

Both use your org's cache and your stored provider key, and sound the same.

  • Our plugin reports only the characters Gemini billed in TTSMetrics (cache hits count zero), and switches provider with update_options.
  • Gemini’s plugin is the smallest change to an agent that already uses it. Its metrics count every character, cached or not; Usage has the real split.