Source code for p2p.backends.base

"""Provider-neutral backend contracts."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Protocol, runtime_checkable


[docs] @dataclass(frozen=True, slots=True) class TokenUsage: """Normalized token counts returned by every backend.""" input_tokens: int = 0 output_tokens: int = 0 cached_input_tokens: int = 0 reasoning_tokens: int = 0 def __post_init__(self) -> None: for field_name in ( "input_tokens", "output_tokens", "cached_input_tokens", "reasoning_tokens", ): value = getattr(self, field_name) if isinstance(value, bool) or not isinstance(value, int): raise TypeError(f"{field_name} must be an integer") if value < 0: raise ValueError(f"{field_name} must be nonnegative") if self.cached_input_tokens > self.input_tokens: raise ValueError( "cached_input_tokens cannot exceed input_tokens" ) if self.reasoning_tokens > self.output_tokens: raise ValueError( "reasoning_tokens cannot exceed output_tokens" )
[docs] @dataclass(frozen=True, slots=True) class BackendResponse: """Normalized response returned by every backend adapter.""" answer_text: str usage: TokenUsage = field(default_factory=TokenUsage) def __post_init__(self) -> None: if not isinstance(self.answer_text, str): raise TypeError("answer_text must be a string") if not isinstance(self.usage, TokenUsage): raise TypeError("usage must be TokenUsage")
[docs] class NoAnswerTextError(RuntimeError): """The provider returned no answer text: a refusal, block, or filter. The message names the provider's stated reason so that it survives into the recorded ``[ERROR]`` answer when every retry fails. """
[docs] @runtime_checkable class Backend(Protocol): """Minimal interface implemented by backend adapters.""" model_name: str
[docs] def chat(self, *, system: str, user: str) -> BackendResponse: """Return normalized text and token usage.""" ...
__all__ = [ "Backend", "BackendResponse", "NoAnswerTextError", "TokenUsage", ]