""" LLM provider interface. The rest of the application (router, chat endpoints, evaluation) must NEVER call a specific model directly. Everything goes through generate(prompt) on whatever provider is configured via config.LLM_PROVIDER. Switching from local Mistral to Groq or OpenAI later should require changing config only — no changes to callers. """ from abc import ABC, abstractmethod class LLMProvider(ABC): """Base interface every provider (local, groq, openai, ...) must implement.""" @abstractmethod def generate(self, prompt: str, stream: bool = False): """ Args: prompt: the fully-constructed prompt string (see llm/prompts.py). stream: if True, returns a generator yielding text chunks as they're produced, instead of a single string. Providers that can't stream should fall back to yielding the full response once. Returns: str if stream=False, otherwise a generator[str]. """ raise NotImplementedError def name(self) -> str: return self.__class__.__name__