VoiceGateway // DOCS

Provider Abstraction

All 11 providers in VoiceGateway implement the same abstract base class, giving the core layer a uniform interface regardless of whether the underlying service is a cloud API or a local model.

Provider Abstraction

All 11 providers in VoiceGateway implement the same abstract base class, giving the core layer a uniform interface regardless of whether the underlying service is a cloud API or a local model.

BaseProvider ABC

File: src/voicegateway/providers/base.py

Python
class BaseProvider(ABC):

    @abstractmethod
    def create_stt(self, model: str, **kwargs: Any) -> Any:
        """Create an STT instance."""
        ...

    @abstractmethod
    def create_llm(self, model: str, **kwargs: Any) -> Any:
        """Create an LLM instance."""
        ...

    @abstractmethod
    def create_tts(self, model: str, voice: str | None = None, **kwargs: Any) -> Any:
        """Create a TTS instance."""
        ...

    @abstractmethod
    async def health_check(self) -> bool:
        """Check if the provider is reachable."""
        ...

    def _unsupported(self, modality: str) -> None:
        """Raise NotImplementedError for unsupported modalities."""
        raise NotImplementedError(
            f"{self.__class__.__name__} does not support {modality}"
        )

Method Contracts

MethodReturnsUnsupported Behavior
create_stt(model, **kwargs)LiveKit-compatible STT instanceCall self._unsupported("stt")
create_llm(model, **kwargs)LiveKit-compatible LLM instanceCall self._unsupported("llm")
create_tts(model, voice, **kwargs)LiveKit-compatible TTS instanceCall self._unsupported("tts")
health_check()True if reachable, False otherwiseMust always be implemented

Pricing is no longer a provider-level concern. Rates for all three modalities (LLM, STT, and TTS) resolve via voice-prices (see the wrapper modules src/voicegateway/inference/pricing/{llm,stt,tts}.py, which call voice_prices.calc_price). Use voicegateway.inference.pricing.catalog.calculate_cost(modality, model, ...) from anywhere that needs a per-request cost.

Argument order trap. voicegateway.pricing.catalog.calculate_cost(modality, model, ...) takes modality first; the legacy CostTracker.calculate_cost(model_id, modality, ...) on voicegateway.middleware.cost_tracker takes model_id first. The two helpers serve different layers (catalog is the pricing facade; CostTracker bridges to the storage record), but the reversed positional order is easy to transpose. When in doubt, use keyword arguments or call the catalog directly.

Provider Registry

All 11 providers are registered in src/voicegateway/core/registry.py as (module_path, class_name) tuples. The Registry uses importlib.import_module() for lazy loading -- a provider's SDK is only imported when that provider is first used.

Cloud Providers Local Providers BaseProvider ABC OpenAISTT + LLM + TTS DeepgramSTT CartesiaTTS AnthropicLLM GroqSTT + LLM ElevenLabsTTS AssemblyAISTT OllamaLLM WhisperSTT KokoroTTS PiperTTS

Modality Support Matrix

ProviderSTTLLMTTSInstall Extra
OpenAIYesYesYesopenai
DeepgramYes----deepgram
Cartesia----Yescartesia
Anthropic--Yes--anthropic
GroqYesYes--groq
ElevenLabs----Yeselevenlabs
AssemblyAIYes----assemblyai
Ollama--Yes--ollama
WhisperYes----whisper
Kokoro----Yeskokoro
Piper----Yespiper

When a provider does not support a modality, its create_* method calls self._unsupported(), which raises NotImplementedError. This propagates cleanly through the Router and Gateway layers.

Implementation Pattern

Every provider follows the same structure:

Python
class DeepgramProvider(BaseProvider):
    """Deepgram STT provider."""

    def __init__(self, config: dict[str, Any]):
        self._api_key = config.get("api_key") or os.environ.get("DEEPGRAM_API_KEY", "")
        # Provider-specific initialization

    def create_stt(self, model: str, **kwargs: Any) -> Any:
        from livekit.plugins.deepgram import STT
        return STT(model=model, api_key=self._api_key, **kwargs)

    def create_llm(self, model: str, **kwargs: Any) -> Any:
        self._unsupported("llm")

    def create_tts(self, model: str, voice: str | None = None, **kwargs: Any) -> Any:
        self._unsupported("tts")

    async def health_check(self) -> bool:
        # Lightweight API call to verify credentials
        ...

Key patterns:

  1. API key resolution: config.get("api_key") first (from YAML or managed providers), then fall back to the standard environment variable (DEEPGRAM_API_KEY, OPENAI_API_KEY, etc.).

  2. LiveKit plugin wrapping: each create_* method returns a LiveKit Agents plugin instance (livekit.plugins.deepgram.STT, livekit.plugins.openai.LLM, etc.), making VoiceGateway a drop-in replacement for direct LiveKit plugin usage.

  3. Lazy SDK import: the from livekit.plugins.deepgram import STT happens inside the method, not at module level. This allows installing only the providers you need.

Modular Installation

Each provider is an optional dependency:

Shell
# Install only what you need
pip install voicegateway[openai,deepgram,cartesia]

# Install everything
pip install voicegateway[all]

# Local-only stack (no cloud SDKs needed)
pip install voicegateway[whisper,kokoro]

If a provider's SDK is missing, the Registry raises a clear ImportError:

Plain text
Could not import provider 'deepgram': No module named 'deepgram'.
Install with: pip install voicegateway[deepgram]

Adding a New Provider

  1. Create src/voicegateway/providers/myprovider_provider.py extending BaseProvider
  2. Implement the five abstract methods (use _unsupported() for unsupported modalities)
  3. Register it in src/voicegateway/core/registry.py:
    Python
    "myprovider": ("voicegateway.providers.myprovider_provider", "MyProviderProvider"),
  4. Add pricing data to src/voicegateway/pricing/catalog.py
  5. Add the optional dependency to pyproject.toml

On this page