"""Base protocols and shared types for orchestrators. This module defines the interfaces that orchestrators depend on, following the Interface Segregation Principle (ISP) and Dependency Inversion Principle (DIP). """ from collections.abc import AsyncGenerator from typing import Protocol, runtime_checkable from src.utils.models import AgentEvent, Evidence, JudgeAssessment, SearchResult class SearchHandlerProtocol(Protocol): """Protocol for search handler. Defines the interface for executing searches across biomedical databases. Implementations include SearchHandler (scatter-gather across PubMed, ClinicalTrials.gov, Europe PMC). """ async def execute(self, query: str, max_results_per_tool: int = 10) -> SearchResult: """Execute a search query. Args: query: The search query string max_results_per_tool: Maximum results to fetch per search tool Returns: SearchResult containing evidence and metadata """ ... class JudgeHandlerProtocol(Protocol): """Protocol for judge handler. Defines the interface for assessing evidence quality and sufficiency. Implementations include JudgeHandler (pydantic-ai), HFInferenceJudgeHandler, and MockJudgeHandler. """ async def assess( self, question: str, evidence: list[Evidence], iteration: int = 0, max_iterations: int = 10, ) -> JudgeAssessment: """Assess whether collected evidence is sufficient. Args: question: The original research question evidence: List of evidence items to assess iteration: Current iteration number max_iterations: Maximum allowed iterations Returns: JudgeAssessment with sufficiency determination and next steps """ ... @runtime_checkable class SynthesizableJudge(Protocol): """Protocol for judge handlers that support free-tier synthesis. This protocol enables type-safe tier detection using isinstance() instead of hasattr(), following the recommendation from CodeRabbit review. Implementations: HFInferenceJudgeHandler Raises: SynthesisError: If all models fail (with context about what was tried) """ async def synthesize(self, system_prompt: str, user_prompt: str) -> str: """Generate synthesis using free-tier resources. Args: system_prompt: System context for synthesis user_prompt: User prompt with evidence to synthesize Returns: Synthesized narrative text. Raises: SynthesisError: If all models fail, with attempted_models and errors context. """ ... @runtime_checkable class OrchestratorProtocol(Protocol): """Protocol for orchestrators. All orchestrators (Simple, Advanced, Hierarchical) implement this interface, allowing them to be used interchangeably by the factory and UI. """ def run(self, query: str) -> AsyncGenerator[AgentEvent, None]: """Run the orchestrator workflow. Args: query: User's research question Yields: AgentEvent objects for real-time UI updates """ ...