"""Abstraction des moteurs LLM (backend pluggable). Calque du pattern TTS (`tts/base.py`) : un backend ne fait *qu'une* chose, transformer une liste de messages (role/content) en texte brut. Toute la logique agnostique (calcul des parametres depuis les Settings, retrait de la pensee, extraction JSON tolerante, retries) vit dans la facade `client.LLM`, jamais dupliquee par backend. """ from __future__ import annotations from abc import ABC, abstractmethod from typing import Callable, Optional class LLMBackend(ABC): """Interface commune a tous les moteurs LLM.""" name: str = "base" def __init__(self, model_ref: str): # Reference du modele, interpretee par le backend : id mlx-community # (mlx) ou nom du modele charge dans LM Studio (lmstudio, vide -> actif). self.model_ref = model_ref @abstractmethod def complete( self, messages: list[dict], *, max_tokens: int, temperature: float, reasoning: bool, token_sink: Optional[Callable[[str], None]] = None, ) -> str: """Genere et renvoie le texte BRUT (chaine de pensee incluse). - `messages` : liste {role, content} (system optionnel + user). - `reasoning` : si vrai, le modele peut emettre une chaine de pensee ; le backend peut s'arreter des que le JSON post-pensee est complet. La facade retire la pensee en aval (`_strip_reasoning`). - `token_sink` : si fourni, appele avec chaque morceau de texte au fil de la generation (streaming pour `inkflow benchmark --stream`). """