livekit-plugins-tts-cache-router
LiveKit Agents plugin for tts-cache-router: Sarvam, Raya, ElevenLabs, OpenAI, Deepgram, xAI, Soniox, Smallest AI and Cartesia text-to-speech, with every sentence your agent has said before served from a per-account cache.
Same output whether you call the provider directly or through the router: each sentence reaches the provider verbatim with your exact settings, and a cache hit replays a real provider take for that exact request.
Full documentation: docs.ttscacherouter.dev/livekit. For LLMs and coding agents: llms.txt, and this page as Markdown at livekit.md.
Install
pip install livekit-plugins-tts-cache-router
Usage
from livekit.plugins import tts_cache_router as tcr
tts = tcr.TTS(
provider=tcr.Sarvam(model="bulbul:v3", speaker="shubh", language="hi-IN"),
)
# or
tts = tcr.TTS(
provider=tcr.Raya(
model="standard", voice_id="d6a002d0-230c-49b1-a137-b8a7d564b1ae", language="hi"
),
)
# or
tts = tcr.TTS(
provider=tcr.ElevenLabs(voice_id="JBFqnCBsd6RMkjVDRZzb", model="eleven_flash_v2_5"),
)
# or
tts = tcr.TTS(
provider=tcr.OpenAI(model="gpt-4o-mini-tts", voice="ash", instructions="Speak warmly."),
)
# or
tts = tcr.TTS(
provider=tcr.Deepgram(model="aura-2", voice="thalia-en"),
)
# or
tts = tcr.TTS(
provider=tcr.XAI(voice="ara", language="auto"),
)
# or
tts = tcr.TTS(
provider=tcr.Soniox(voice="Adrian", language="en"),
)
# or
tts = tcr.TTS(
provider=tcr.SmallestAI(model="lightning_v3.1_pro", voice_id="meher", language="en"),
)
# or
tts = tcr.TTS(
provider=tcr.Cartesia(model="sonic-3", voice="f786b574-daa5-4673-aa0c-cbe3e8534c02", language="en"),
)
session = AgentSession(tts=tts, ...)
Before the first request, store your Sarvam, Raya, ElevenLabs, OpenAI, Deepgram, xAI, Soniox, Smallest AI or Cartesia API key in the dashboard at ttscacherouter.dev. The router keeps it encrypted and uses it only to call that provider for your requests.
Set TTS_CACHE_ROUTER_API_KEY to your router API key, from the same dashboard (or pass
api_key=).
TTS(...)
| Argument | Default | |
|---|---|---|
provider |
required, or model |
Sarvam(...), Raya(...), ElevenLabs(...), OpenAI(...), Deepgram(...), XAI(...), Soniox(...), SmallestAI(...) or Cartesia(...) |
model, voice, language, speed, options |
instead of provider: see From a model string |
|
api_key |
$TTS_CACHE_ROUTER_API_KEY |
router API key |
base_url |
wss://api.ttscacherouter.dev |
set to your own router when self-hosting |
sample_rate |
24000 |
8000, 16000, 22050 or 24000; ElevenLabs also 32000, 44100 or 48000; OpenAI 24000 only; Deepgram 8000, 16000, 24000, 32000, 44100 or 48000; xAI 8000, 16000, 22050, 24000, 44100 or 48000; Soniox 8000, 16000, 24000, 44100 or 48000; Smallest AI 8000, 16000, 24000 or 44100; Cartesia 8000, 16000, 22050, 24000, 44100 or 48000 |
How long cached audio is kept is your org's retention setting, in the dashboard.
From a model string
Instead of provider, give model as "<provider>/<model>", with the voice and settings in the
router's own names (those of /v1/audio/speech and GET /v1/models):
tts = tcr.TTS(
model="elevenlabs/eleven_flash_v2_5",
voice="JBFqnCBsd6RMkjVDRZzb",
language="en",
options={"voice_settings": {"stability": 0.5, "similarity_boost": 0.75}},
)
voice is required (GET /v1/voices lists them, your account's own included); language and
speed where the provider takes them; options holds the provider's other settings. The router
checks them when a reply starts: a wrong one fails that reply with APIStatusError
(bad_request). update_options(model=..., voice=..., options=...) changes them.
Sarvam(...)
model ("bulbul:v3" or "bulbul:v4-flash"), speaker, language (e.g. "hi-IN"),
pace (0.5–2.0, default 1.0), temperature (0.01–1.0, default 0.6), dict_id, and for
bulbul:v4-flash only: pitch (-0.5–0.5), loudness (0.1–2.5), enable_preprocessing;
min_buffer_size (30–200) and max_chunk_length (50–500; by default each sentence is
synthesized whole).
Raya(...)
model ("standard" or "m1"), voice_id, language (e.g. "hi"), speed (0.5–1.5,
default 1.0).
ElevenLabs(...)
The settings of ElevenLabs' own LiveKit plugin: voice_id, model (default
"eleven_turbo_v2_5"; eleven_v3 and eleven_v4 models go through ElevenLabs' text-to-dialogue
API), language (optional; "en-US" or "english" is sent as "en", as ElevenLabs' plugin
sends it), voice_settings (VoiceSettings(stability=None, similarity_boost=None, style=None, speed=None, use_speaker_boost=None); a setting left as None, or voice_settings
omitted, keeps the voice's stored setting),
apply_text_normalization ("auto", "on" or "off"), apply_language_text_normalization,
enable_ssml_parsing, enable_logging, pronunciation_dictionary_locators
(PronunciationDictionaryLocator(pronunciation_dictionary_id, version_id), up to 3),
sync_alignment (default True: word-level timed transcripts) and preferred_alignment
("normalized" or "original").
OpenAI(...)
The settings of OpenAI's own LiveKit plugin: model (default "gpt-4o-mini-tts"; also
"gpt-4o-mini-tts-2025-12-15", "tts-1" and "tts-1-hd"), voice (default "ash"), speed
(0.25–4.0, default 1.0) and instructions (how to speak; gpt-4o-mini-tts follows them, tts-1
and tts-1-hd ignore them). OpenAI speaks the language of the text, at 24000 Hz only.
Deepgram(...)
The settings of LiveKit's Deepgram plugin (TTS for Aura, TTSv2 for Flux): model ("aura-2",
the default, "aura-1" or "flux"), voice (default "andromeda-en"; Deepgram's model id is the
two joined, so model="aura-2", voice="thalia-en" is aura-2-thalia-en), speed (0.7–1.5,
aura-2 only; default None, Deepgram's own) and mip_opt_out (default False). With Aura, the
first sentence of a reply after a pause of about five seconds or more takes about 0.7–1.2 s longer
to start than with LiveKit's Deepgram plugin; sentences from the cache, and Flux, are unaffected.
XAI(...)
The settings of LiveKit's xAI plugin: voice (default "ara", or a custom voice id), language
(default "auto": xAI detects it; or a code such as "en", "hi", "pt-BR"), speed (0.7–1.5;
default None, xAI's own), optimize_streaming_latency (0, 1 or 2; default None) and
text_normalization (default None, xAI's own: off). Each sentence is synthesized on its own.
Soniox(...)
The settings of LiveKit's Soniox plugin: language (required, e.g. "en"; Soniox reads the text
through this language's phonetics, so set it to the language of the reply), model
("tts-rt-v2"), voice (default "Adrian", or a cloned voice's id) and speed (0.7–1.3, default
1.0), plus Soniox's reduce_silence (default None, Soniox's own: off). Each sentence is
synthesized on its own, so the pauses between sentences are a little shorter (about 0.2 s) than
in one Soniox stream (about 0.5 s).
SmallestAI(...)
The settings of LiveKit's Smallest AI plugin: model ("lightning_v3.1_pro", the default, or
"lightning_v3.1"), voice_id (each model has its own voices; default None: "meher" for
lightning_v3.1_pro, "sophia" for lightning_v3.1), language (default "en", e.g. "hi", or
"auto"; "en-US" or "english" is sent as "en", as Smallest AI's plugin sends it) and speed
(0.5–2.0, default 1.0). Each sentence is synthesized on its own, so a reply isn't primed sentence
to sentence as in one Smallest AI continuation. word_timestamps is not served.
Cartesia(...)
The settings of LiveKit's Cartesia plugin: model ("sonic-3", the default, "sonic-3.5" or
"sonic-3.6", or a dated snapshot of one such as "sonic-3.6-2026-08-27"), voice (a Cartesia
voice id; default Katie, as Cartesia's plugin), language (default "en"; "en-US" is sent as
"en", as Cartesia's plugin sends it), speed (0.6–1.5), emotion (e.g. "calm"; a list uses
its first), volume (0.5–2.0), pronunciation_dict_id and word_timestamps (default True:
word-level timed transcripts). Each sentence is synthesized on its own, so the pauses between
sentences are a little shorter than in one Cartesia context, and a sentence doesn't carry the
prosody of the one before it.
Changing settings mid-session
tts.update_options(speaker="priya", pace=1.1) # the current provider's settings, by name
tts.update_options(provider=tcr.Raya(...)) # or another provider
Replies that start afterwards use the new settings.
Connections
When an AgentSession starts, it calls tts.prewarm(): the plugin connects to the router, and
the router connects to your provider with the current settings at once, so the first reply
doesn't wait for either. Idle connections stay open between replies, for up to about 30 minutes.
Interruptions
When the agent is interrupted, the plugin cancels the router segment and keeps the connection open, so the next reply starts on a warm connection.
Metrics
TTSMetrics.characters_count counts only characters the provider synthesized (and billed) for
the request; sentences served from the cache count zero. provider and model report the
underlying provider, so usage dashboards attribute cost correctly.
Once a reply is all sent, the plugin also emits cache_stats, a CacheStats with the reply's
request_id, segment_id (when streamed), sentences, cached_sentences, characters and
billed_characters (and cached_characters, the difference):
tts.on("cache_stats", lambda stats: print(stats.cached_sentences, "of", stats.sentences, "cached"))
Metadata
Release files for livekit-plugins-tts-cache-router 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| livekit_plugins_tts_cache_router-0.3.1.tar.gz | 23.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| livekit_plugins_tts_cache_router-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 50.4 kB
Release files / livekit_plugins_tts_cache_router-0.3.1.tar.gz
| Download URL | livekit_plugins_tts_cache_router-0.3.1.tar.gz |
|---|---|
| Size | 23.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cfc337ee5369028b200e13c9cb23e9a8eab94e34f25cf65390a3a2ca0136fe06
|
|
BLAKE2b-256 checksum How to use checksums |
6d77536af228f1ab370ec5034823b25f7b2750809251d172832fb4173db9290b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / livekit_plugins_tts_cache_router-0.3.1-py3-none-any.whl
| Download URL | livekit_plugins_tts_cache_router-0.3.1-py3-none-any.whl |
|---|---|
| Size | 27.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
035422e034fb634df5b5c3972cc53557f5772ed43fc6a5c8b860f06bb40ac387
|
|
BLAKE2b-256 checksum How to use checksums |
69dc0072f04e683d3849ff899d6881a4586385df482cc74fe129479eb33a7146
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|