"""Kontrakt dostawcy modelu językowego (LOG-31). Analogicznie do `EphemerisEngine` (LOG-24): prezentacja i reszta logiki nie wiedzą, kto pisze tekst — lokalny model na naszym sprzęcie czy dostawca w chmurze. Kluczowa własność dla bezpieczeństwa baz (LOG-32): każdy dostawca deklaruje `leaves_lan`. Prompt niesie ORYGINALNE opisy z baz, więc interfejs musi jawnie mówić, czy ta treść opuszcza naszą sieć — UI ma na tej podstawie ostrzegać. """ from __future__ import annotations from abc import ABC, abstractmethod from dataclasses import dataclass, field @dataclass class Completion: """Wynik generowania — tekst + metryki do rozliczenia i podglądu.""" text: str model: str provider: str leaves_lan: bool usage: dict = field(default_factory=dict) # prompt_tokens / completion_tokens class LLMError(RuntimeError): """Błąd wołania modelu — z komunikatem nadającym się do pokazania użytkownikowi.""" class LLMProvider(ABC): name: str = "?" #: czy treść promptu (a więc opisy z baz) opuszcza naszą sieć leaves_lan: bool = True @abstractmethod def generate(self, prompt: str, max_tokens: int) -> Completion: """Zwraca gotowy tekst. Rzuca LLMError przy niepowodzeniu.""" @abstractmethod def health(self) -> dict: """Czy dostawca jest osiągalny i skonfigurowany."""