"""Define domain ports for conversation.""" from __future__ import annotations from abc import ABC, abstractmethod from typing import Generator from app.domain.retrieval.models import RetrievedChunk from .models import AnswerResult, ConversationSession # Keep domain contracts explicit so adapters can swap implementations cleanly. class AnswerGenerator(ABC): """Represent the Answer Generator type.""" @abstractmethod def generate( self, *, query: str, retrieved_chunks: list[RetrievedChunk], history: list[dict[str, str]] | None = None, provider: str | None = None, model: str | None = None, prompt_template: str | None = None, ) -> AnswerResult: """Handle generate for the Answer Generator instance.""" pass @abstractmethod def stream_generate( self, *, query: str, retrieved_chunks: list[RetrievedChunk], history: list[dict[str, str]] | None = None, provider: str | None = None, model: str | None = None, prompt_template: str | None = None, ) -> Generator[dict, None, AnswerResult]: """Stream generate for the Answer Generator instance.""" pass class ConversationStore(ABC): """Provide the Conversation Store store implementation.""" @abstractmethod def create_session(self, metadata: dict | None = None) -> ConversationSession: """Create session for the Conversation Store instance.""" pass @abstractmethod def get_session(self, session_id: str) -> ConversationSession | None: """Return session for the Conversation Store instance.""" pass @abstractmethod def save_message( self, session_id: str, *, role: str, content: str, sources: list[dict] | None = None, ) -> ConversationSession | None: """Save message for the Conversation Store instance.""" pass @abstractmethod def delete_session(self, session_id: str) -> bool: """Delete session for the Conversation Store instance.""" pass @abstractmethod def list_sessions(self) -> list[dict]: """List sessions for the Conversation Store instance.""" pass