Source code for rath.llm.base

"""Chat-client Protocols consumed by the session loop.

Two runtime-checkable Protocols define the contract every LLM adapter must
satisfy:

* :class:`ChatClient` — the minimum surface (``provider`` + blocking
  ``complete``). Sufficient for :class:`~rath.session.loop.run_session_loop`.
* :class:`StreamingChatClient` — extends :class:`ChatClient` with
  ``complete_stream``. :func:`~rath.session.loop.run_session_loop` switches to
  streaming when ``on_event`` is supplied and guards on this Protocol instead
  of inspecting :attr:`~rath.llm.Provider.provider_kind`, so any adapter that
  implements ``complete_stream`` gains streaming support automatically.
"""

from __future__ import annotations

from typing import Iterator, Protocol, runtime_checkable

from rath.llm.chat_request import RathLLMChatRequest
from rath.llm.chat_response import RathLLMChatResponse, RathLLMStreamDelta
from rath.llm.provider import Provider

__all__ = ["ChatClient", "StreamingChatClient"]


[docs] @runtime_checkable class ChatClient(Protocol): """Minimal synchronous chat-completion contract. Implementations must keep ``complete`` blocking and side-effect-free beyond the network call itself; retries / token accounting / budget handling are layered above in the session loop. """ @property def provider(self) -> Provider: ... def complete(self, req: RathLLMChatRequest) -> RathLLMChatResponse: ...
[docs] @runtime_checkable class StreamingChatClient(ChatClient, Protocol): """A :class:`ChatClient` that also supports streaming completions. :func:`~rath.session.loop.run_session_loop` accepts any object satisfying this Protocol when ``on_event`` is provided. Both OpenAI and Anthropic adapters implement it. """ def complete_stream( self, req: RathLLMChatRequest ) -> Iterator[RathLLMStreamDelta]: ...