"""Adapter registry — resolves the active TTS / LLM / Guardrail from env. Centralizes the D-014 (TTS swap), D-020 (LLM swap), D-019 (guardrail plug) wiring so the Pipecat pipeline never imports a concrete adapter directly. """ from __future__ import annotations import os from functools import lru_cache def _require(key: str, *, default: str | None = None) -> str: val = os.environ.get(key, default or "").strip() if not val: raise RuntimeError( f"Required env var {key} is not set. See .env.example." ) return val @lru_cache(maxsize=1) def get_tts() -> "TTSProvider": # type: ignore[name-defined] """Return the active TTSProvider based on PRAXIS_TTS (D-014).""" # Imported lazily so importing the registry doesn't drag in Pipecat/TTS deps # for tools that only need the interfaces. choice = os.environ.get("PRAXIS_TTS", "cartesia").strip().lower() if choice == "piper": from server.tts.piper_tts import PiperTTS return PiperTTS() if choice == "cartesia": from server.tts.cartesia_tts import CartesiaTTS return CartesiaTTS() raise RuntimeError( f"Unknown PRAXIS_TTS={choice!r}; expected 'cartesia' or 'piper'." ) @lru_cache(maxsize=1) def get_llm() -> "LLMProvider": # type: ignore[name-defined] """Return the active LLMProvider (Ollama Cloud direct API, D-020).""" from server.llm.ollama_cloud import OllamaCloudLLM return OllamaCloudLLM() @lru_cache(maxsize=1) def get_guardrail() -> "Guardrail": # type: ignore[name-defined] """Return the active Guardrail (D-019). v0.1 SLICE-02 returns NoOpGuardrail; SLICE-03 swaps in CustomerServiceGuardrail. Selection via PRAXIS_GUARDRAIL=none|customer_service (default: customer_service once implemented; falls back to none if the ruleset isn't importable yet). """ choice = os.environ.get("PRAXIS_GUARDRAIL", "customer_service").strip().lower() if choice == "none": from server.guardrails.noop import NoOpGuardrail return NoOpGuardrail() if choice == "customer_service": try: from server.guardrails.customer_service import CustomerServiceGuardrail return CustomerServiceGuardrail() except ImportError: # SLICE-02 fallback — real ruleset arrives in SLICE-03. from server.guardrails.noop import NoOpGuardrail return NoOpGuardrail() raise RuntimeError( f"Unknown PRAXIS_GUARDRAIL={choice!r}; expected 'none' or 'customer_service'." )