"""Formal platform adapter contracts for acquisition.""" from __future__ import annotations from typing import Any, Iterable, Protocol from pydantic import BaseModel, ConfigDict, Field from core.config import Settings class PlatformCandidate(BaseModel): model_config = ConfigDict(extra="forbid") rank: int platform: str provider: str = "" source_id: str = "" url: str = "" title: str = "" author: str = "" cover_url: str = "" raw: dict[str, Any] = Field(default_factory=dict) class PlatformItem(BaseModel): model_config = ConfigDict(extra="forbid") platform: str provider: str = "" source_id: str = "" url: str = "" content_type: str = "" content_mode: str = "" title: str = "" author: str = "" body_text: str = "" image_urls: list[str] = Field(default_factory=list) video_urls: list[str] = Field(default_factory=list) raw: dict[str, Any] = Field(default_factory=dict) class PlatformSearchPage(BaseModel): model_config = ConfigDict(extra="forbid") page_index: int candidates: list[PlatformCandidate] = Field(default_factory=list) raw_count: int = 0 cursor: str = "" next_cursor: str = "" has_more: bool = False provider: str = "" request_payload: dict[str, Any] = Field(default_factory=dict) raw_metadata: dict[str, Any] = Field(default_factory=dict) class PlatformAdapter(Protocol): platform: str def search_pages( self, query: str, *, settings: Settings, limit: int, rate_limiter: Any, max_pages: int = 2, ) -> Iterable[PlatformSearchPage]: ... def search( self, query: str, *, settings: Settings, limit: int, rate_limiter: Any, ) -> list[PlatformCandidate]: ... def fetch_detail( self, candidate: PlatformCandidate, *, settings: Settings, rate_limiter: Any, ) -> PlatformItem: ...