from __future__ import annotations from typing import Any, Literal from pydantic import BaseModel, ConfigDict, Field ExternalQueryKind = Literal["weather", "news", "company", "model", "market", "generic_web", "unknown"] ExternalAnswerContract = Literal["direct_fact", "summary_with_sources", "compare_with_sources", "clarify"] class ExternalQueryPlan(BaseModel): model_config = ConfigDict(extra="ignore") plan_version: str = "v1" query_kind: ExternalQueryKind = "unknown" answer_contract: ExternalAnswerContract = "summary_with_sources" freshness_required: bool = False topic: str = "" subject_entities: list[str] = Field(default_factory=list) location_hint: str | None = None time_range_hint: str | None = None preferred_domains: list[str] = Field(default_factory=list) search_queries: list[str] = Field(default_factory=list) result_limit: int = Field(default=3, ge=1, le=5) requires_multi_source: bool = False clarify_on_ambiguity: bool = False class ExternalEvidenceItem(BaseModel): model_config = ConfigDict(extra="ignore") source_type: str = "url" source_label: str = "" title: str = "" target_url: str = "" snippet: str = "" retrieved_at: str | None = None freshness_score: float = 0.0 authority_score: float = 0.0 grounded_fields: list[str] = Field(default_factory=list) raw_metadata: dict[str, Any] = Field(default_factory=dict) class ExternalAdapterResult(BaseModel): model_config = ConfigDict(extra="ignore") adapter_name: str status: str = "empty" evidence: list[ExternalEvidenceItem] = Field(default_factory=list) meta: dict[str, Any] = Field(default_factory=dict) class ExternalQueryExecution(BaseModel): model_config = ConfigDict(extra="ignore") plan: ExternalQueryPlan adapter_name: str evidence: list[ExternalEvidenceItem] = Field(default_factory=list) verifier: dict[str, Any] = Field(default_factory=dict) planner_meta: dict[str, Any] = Field(default_factory=dict) meta: dict[str, Any] = Field(default_factory=dict)