Skip to main content
livekit-plugins-slng adds STT and TTS adapters for LiveKit Agents. It connects through SLNG’s Unmute Bridge, so models on the SLNG platform work with the same code: pass a model identifier and the plugin builds the endpoint itself. The plugin is realtime WebSocket only. Models that expose only HTTP endpoints (for example batch STT models such as sarvam/saaras:v3 or slng/speechmatics/batch) are not available through it; check the Models catalog for streaming support.
This page documents plugin version 1.6.7 and later, a major rewrite distributed through the official LiveKit Agents repository. If you are upgrading from 1.6.6 or earlier, read Migrating from earlier versions first: several parameters changed or were removed.

Prerequisites

Installation

Credentials

The plugin reads your SLNG key from the SLNG_API_KEY environment variable automatically:
You can also pass it explicitly via api_key:
slng.STT also accepts a legacy api_token= alias, but it is deprecated. Use api_key in new code.

Quickstart

Create an STT and TTS instance, then pass them to your LiveKit agent session:
A model identifier is all that is needed: the plugin builds the Unmute Bridge endpoint (wss://api.slng.ai/v1/bridges/unmute/{stt|tts}/<model>) by itself.
Language codes are sent verbatim, without client-side normalization. Use the exact value the selected model expects: for example Sarvam Bulbul takes BCP-47 codes such as hi-IN, not hi.

Lower STT turn latency

For the lowest end-of-turn latency, let the plugin know when the user stops speaking. The plugin then sends a finalize signal so the provider returns the final transcript immediately instead of waiting for its own endpointing:
Or wire it manually:
Without this hook the plugin still works, but end-of-turn detection relies entirely on the provider’s endpointing, which typically adds a few hundred milliseconds per turn.

Full voice agent example

This example wires up STT, TTS, and VAD into a complete LiveKit agent that greets the user on join:

Model identifiers

Models follow the format provider/model:variant. Prefix with slng/ to target an SLNG-hosted instance:
Examples:
See the Models page for the full list of available models.

STT reference

slng.STT streams speech-to-text over WebSocket through the Unmute Bridge.

Constructor

Either model or connections must be provided; there is no default model. Any additional keyword argument is forwarded to the bridge init payload; the bridge applies the options the selected model’s catalog declares and ignores the rest, so option names must match that model’s contract (for example Deepgram consumes endpointing and smart_format). The generic VAD and diarization options apply only to models that declare those fields.
Only 16-bit PCM (pcm_s16le) input audio is supported, and batch recognize() is not available: the bridge is WebSocket-only, so use stream().

TTS reference

slng.TTS streams text-to-speech over WebSocket through the Unmute Bridge.

Constructor

voice is required and passed verbatim as the provider’s voice identifier (use the provider’s voice ID, not a display name). Additional keyword arguments are forwarded to the bridge init payload according to the selected model’s contract, for example Rime Arcana speakingStyle, Sarvam Bulbul pace, or Cartesia Sonic emotion. You can also pass pronunciation={"mode": "rewrite", "name": "my-dictionary"} to apply a pronunciation dictionary. You can change voice, language, and speed at runtime with tts.update_options(...); the change propagates to failover candidates and safely replaces any pre-opened standby connection. runtime_init is an advanced option for integrations that drive the bridge session themselves: when set, it is sent as the init payload instead of the one the plugin builds from model, voice, language, and the other options. Most clients can ignore it.

Text chunking

text_chunking controls how streamed text is sent to the provider. The default "auto" batches words into phrases (flushing at punctuation or phrase_max_chars), which avoids the choppy audio and slow completions that word-by-word streaming causes on some providers. Set "word" only if you specifically need per-word forwarding.

Warm standby connections

By default, each spoken turn opens a fresh connection, which adds connection setup time to the first audio of every turn. With warm_standby_enabled=True, the plugin pre-opens the next connection in the background while the current turn is playing, so the next turn starts on a connection that is already open all the way to the provider. Time-to-first-audio then drops to roughly the provider’s generation time:
Notes:
  • The standby is a single connection per TTS instance (it never accumulates), and it counts toward your concurrency limit while it waits.
  • If the prepared connection expires during a long user silence, the plugin automatically reconnects for that turn at regular latency. No error surfaces.
  • Some providers close idle connections after a short window, which limits how long a prepared connection survives silence. Where the provider exposes an inactivity option in its model contract, pass it as a model option to keep the standby alive through natural pauses in conversation.

Streaming vs batch

  • tts.stream() streams text and returns audio chunks in real time. Use this for voice agents.
  • tts.synthesize(text) does one-shot synthesis over the same bridge connection. Works well for previews and static prompts.

Voice selection

Pick a voice that matches your chosen model. See the Voices pages for what’s available per provider.

Failover

Both STT and TTS accept connections=[...], an ordered list of candidates. Candidates may be model identifiers, Unmute Bridge endpoint URLs, or typed connection configurations. A model is not needed when connections supplies the complete list:
How it behaves:
  • Each candidate gets APIConnectOptions.max_retry attempts before the next candidate is selected.
  • Deterministic client errors (most 4xx statuses) skip the retries and advance to the next candidate immediately.
  • HTTP 413 (payload too large) is terminal: every candidate would reject the same oversized request, so the error surfaces without walking the chain.
  • STT fails over at safe stream boundaries and replays buffered audio (including a pending finalize) onto the new connection, so no speech is lost mid-utterance.
  • TTS switches only before its first audio. All TTS candidates must use the same sample rate and channel count.
  • After fallback_recovery_cooldown_s (60 seconds by default), the primary is tried again on the next request or utterance.
  • With a single candidate, a transient mid-utterance connection drop reconnects the same endpoint and replays the buffered audio instead of ending the stream.
STTConnectionConfig and TTSConnectionConfig keep endpoint-specific headers, init payloads, and voices together:
Global settings are inherited by simple fallback candidates.

Bring your own key (BYOK)

Pass provider_api_key to use your own provider credential. The plugin sends it as the X-Slng-Provider-Key header, and the gateway forwards it to the upstream provider. External (third-party) models only; see BYOK for details:

Region override

Both STT and TTS accept region_override, which maps to the gateway’s X-Region-Override header. Pass a single region or a list of preferred regions in priority order:
To constrain routing to a broad geographic zone instead of a specific region, use world_part_override (for example "eu"), which maps to the gateway’s X-World-Part-Override header. region_override takes precedence when both are set. See Region override for accepted values.

Tracking IDs

external_agent_id and external_session_id attach your own identifiers to SLNG usage events (as the X-SLNG-Agent-Id and X-SLNG-Session-Id headers), so you can correlate gateway usage with your own analytics. Both are optional, max 128 characters.

Plugin events

Subscribe to slng_event for typed events covering gateway session identifiers and failover activity:
Events include gateway.session (the gateway request and session IDs for each connection) and fallback.attempt_failed, fallback.switch_succeeded, fallback.primary_recovered, and fallback.exhausted for failover monitoring.

Migrating from earlier versions

Version 1.6.7 is a breaking rewrite of the plugin:
  • All traffic goes through the Unmute Bridge. model_endpoint and model_endpoints were removed and now raise an error; pass a model identifier (model="deepgram/nova:3") or connections=[...] instead.
  • STT no longer defaults to model="deepgram/nova:3"; pass a model (or connections) explicitly.
  • TTS voice is required and passed verbatim as the provider’s voice identifier (use the provider’s voice ID, not a display name).
  • Language codes are no longer normalized client-side; send the value the model expects (for example BCP-47 hi-IN for Sarvam Bulbul, not hi).
  • STT recognize() (HTTP batch) is no longer supported; use stream(). Only pcm_s16le input audio is supported.
  • api_token still works on STT but is deprecated; use api_key.
  • Provider-specific defaults (voice normalization, implicit fallbacks) were removed; configure candidates explicitly via connections.
The plugin registers itself with LiveKit on import and outputs linear16 PCM audio. Both STT and TTS authenticate with api_key.

Next steps

  • Browse available Models for STT and TTS
  • Check the Voices pages for voice options per provider
  • See Voice Agents for the SLNG-managed agents API