"""Protocols for dependency injection — LLM and Embedding providers.

Consumers implement these protocols to plug any LLM/embedding backend
into the memory system. Uses typing.Protocol for structural subtyping
(duck typing) — no inheritance required.
"""

from typing import Protocol, runtime_checkable


@runtime_checkable
class LLMProvider(Protocol):
    """Protocol for LLM completion calls."""

    async def complete(
        self,
        messages: list[dict],
        temperature: float = 0,
        response_format: dict | None = None,
        max_tokens: int | None = None,
    ) -> str:
        """Send a chat completion request and return the response text.

        Args:
            messages: List of message dicts with 'role' and 'content' keys.
            temperature: Sampling temperature (0 = deterministic).
            response_format: Optional format spec (e.g. {"type": "json_object"}).
            max_tokens: Optional max tokens for the response.

        Returns:
            The assistant's response text.
        """
        ...


@runtime_checkable
class EmbeddingProvider(Protocol):
    """Protocol for text embedding generation."""

    async def embed(self, texts: list[str]) -> list[list[float]]:
        """Generate embeddings for a batch of texts.

        Args:
            texts: List of text strings to embed.

        Returns:
            List of embedding vectors (one per input text).
        """
        ...

    async def embed_one(self, text: str) -> list[float] | None:
        """Generate an embedding for a single text.

        Args:
            text: Text string to embed.

        Returns:
            Embedding vector, or None if the text is empty/invalid.
        """
        ...
