agent_search_gateway.models
Side-effect-free domain and protocol data models.
1"""Side-effect-free domain and protocol data models.""" 2 3from __future__ import annotations 4 5from collections.abc import Mapping 6from dataclasses import dataclass, field 7from datetime import date 8from typing import TYPE_CHECKING, Literal, TypeAlias 9 10from .errors import ErrorCode, ExecutionFailure 11from .url_normalization import NormalizedURL 12 13if TYPE_CHECKING: 14 from .providers.contracts import URLFetchCandidate 15 16 17@dataclass(frozen=True, slots=True) 18class URLRecord: 19 url: NormalizedURL 20 raw_content: str = "" 21 content: str = "" 22 abstract: str = "" 23 available: bool = True 24 25 26@dataclass(frozen=True, slots=True) 27class SearchRecord: 28 url: NormalizedURL 29 abstract: str 30 31 32@dataclass(frozen=True, slots=True) 33class PaperIdentifiers: 34 doi: str = "" 35 arxiv_id: str = "" 36 semantic_scholar_id: str = "" 37 openalex_id: str = "" 38 dblp_key: str = "" 39 core_id: str = "" 40 41 42@dataclass(frozen=True, slots=True) 43class PaperRecord: 44 title: str 45 authors: tuple[str, ...] 46 abstract: str 47 identifiers: PaperIdentifiers 48 published_date: date | None 49 updated_date: date | None 50 url: NormalizedURL 51 pdf_url: NormalizedURL | None 52 venue: str 53 topics: tuple[str, ...] 54 citation_counts: Mapping[str, int] 55 is_open_access: bool | None 56 oa_status: str 57 license: str 58 sources: tuple[str, ...] 59 60 61@dataclass(frozen=True, slots=True) 62class OAResolution: 63 landing_url: NormalizedURL | None 64 pdf_url: NormalizedURL | None 65 is_open_access: bool 66 oa_status: str = "" 67 license: str = "" 68 69 70@dataclass(frozen=True, slots=True) 71class LLMInvocation: 72 provider: str 73 model: str 74 extra_body: Mapping[str, object] = field(default_factory=dict) 75 76 77@dataclass(frozen=True, slots=True) 78class RetryPolicy: 79 max_attempts: int 80 base_delay_seconds: float 81 max_delay_seconds: float 82 request_timeout_seconds: float 83 84 85@dataclass(frozen=True, slots=True) 86class StageDecision: 87 ok: bool 88 reason: str = "" 89 90 91@dataclass(frozen=True, slots=True) 92class KeywordSearchRequest: 93 query: str 94 95 96@dataclass(frozen=True, slots=True) 97class PaperSearchRequest: 98 query: str 99 100 101LLMSearchScope = Literal["web", "paper", "all"] 102 103 104@dataclass(frozen=True, slots=True) 105class LLMSearchRequest: 106 prompt: str 107 scope: LLMSearchScope = "web" 108 109 110@dataclass(frozen=True, slots=True) 111class URLFetchRequest: 112 url: str 113 focus: str | None = None 114 115 116@dataclass(frozen=True, slots=True) 117class ShutdownRequest: 118 pass 119 120 121Request: TypeAlias = ( 122 KeywordSearchRequest | PaperSearchRequest | LLMSearchRequest | URLFetchRequest | ShutdownRequest 123) 124 125 126@dataclass(frozen=True, slots=True) 127class SuccessResponse: 128 text: str 129 ok: bool = field(default=True, init=False) 130 131 132@dataclass(frozen=True, slots=True) 133class ErrorResponse: 134 error: ErrorCode 135 message: str 136 ok: bool = field(default=False, init=False) 137 138 139Response: TypeAlias = SuccessResponse | ErrorResponse 140 141 142@dataclass(frozen=True, slots=True) 143class FetchOutcome: 144 kind: Literal["accepted", "semantic_failure", "execution_failure"] 145 candidate: URLFetchCandidate | None = None 146 failures: tuple[ExecutionFailure, ...] = ()
@dataclass(frozen=True, slots=True)
class
URLRecord:
18@dataclass(frozen=True, slots=True) 19class URLRecord: 20 url: NormalizedURL 21 raw_content: str = "" 22 content: str = "" 23 abstract: str = "" 24 available: bool = True
URLRecord( url: agent_search_gateway.url_normalization.NormalizedURL, raw_content: str = '', content: str = '', abstract: str = '', available: bool = True)
@dataclass(frozen=True, slots=True)
class
SearchRecord:
SearchRecord( url: agent_search_gateway.url_normalization.NormalizedURL, abstract: str)
@dataclass(frozen=True, slots=True)
class
PaperIdentifiers:
33@dataclass(frozen=True, slots=True) 34class PaperIdentifiers: 35 doi: str = "" 36 arxiv_id: str = "" 37 semantic_scholar_id: str = "" 38 openalex_id: str = "" 39 dblp_key: str = "" 40 core_id: str = ""
@dataclass(frozen=True, slots=True)
class
PaperRecord:
43@dataclass(frozen=True, slots=True) 44class PaperRecord: 45 title: str 46 authors: tuple[str, ...] 47 abstract: str 48 identifiers: PaperIdentifiers 49 published_date: date | None 50 updated_date: date | None 51 url: NormalizedURL 52 pdf_url: NormalizedURL | None 53 venue: str 54 topics: tuple[str, ...] 55 citation_counts: Mapping[str, int] 56 is_open_access: bool | None 57 oa_status: str 58 license: str 59 sources: tuple[str, ...]
PaperRecord( title: str, authors: tuple[str, ...], abstract: str, identifiers: PaperIdentifiers, published_date: datetime.date | None, updated_date: datetime.date | None, url: agent_search_gateway.url_normalization.NormalizedURL, pdf_url: Optional[agent_search_gateway.url_normalization.NormalizedURL], venue: str, topics: tuple[str, ...], citation_counts: Mapping[str, int], is_open_access: bool | None, oa_status: str, license: str, sources: tuple[str, ...])
identifiers: PaperIdentifiers
pdf_url: Optional[agent_search_gateway.url_normalization.NormalizedURL]
@dataclass(frozen=True, slots=True)
class
OAResolution:
62@dataclass(frozen=True, slots=True) 63class OAResolution: 64 landing_url: NormalizedURL | None 65 pdf_url: NormalizedURL | None 66 is_open_access: bool 67 oa_status: str = "" 68 license: str = ""
OAResolution( landing_url: Optional[agent_search_gateway.url_normalization.NormalizedURL], pdf_url: Optional[agent_search_gateway.url_normalization.NormalizedURL], is_open_access: bool, oa_status: str = '', license: str = '')
landing_url: Optional[agent_search_gateway.url_normalization.NormalizedURL]
pdf_url: Optional[agent_search_gateway.url_normalization.NormalizedURL]
@dataclass(frozen=True, slots=True)
class
LLMInvocation:
@dataclass(frozen=True, slots=True)
class
RetryPolicy:
78@dataclass(frozen=True, slots=True) 79class RetryPolicy: 80 max_attempts: int 81 base_delay_seconds: float 82 max_delay_seconds: float 83 request_timeout_seconds: float
@dataclass(frozen=True, slots=True)
class
StageDecision:
@dataclass(frozen=True, slots=True)
class
KeywordSearchRequest:
@dataclass(frozen=True, slots=True)
class
PaperSearchRequest:
LLMSearchScope =
typing.Literal['web', 'paper', 'all']
@dataclass(frozen=True, slots=True)
class
LLMSearchRequest:
@dataclass(frozen=True, slots=True)
class
URLFetchRequest:
@dataclass(frozen=True, slots=True)
class
ShutdownRequest:
Request: TypeAlias =
KeywordSearchRequest | PaperSearchRequest | LLMSearchRequest | URLFetchRequest | ShutdownRequest
@dataclass(frozen=True, slots=True)
class
SuccessResponse:
@dataclass(frozen=True, slots=True)
class
ErrorResponse:
133@dataclass(frozen=True, slots=True) 134class ErrorResponse: 135 error: ErrorCode 136 message: str 137 ok: bool = field(default=False, init=False)
ErrorResponse(error: agent_search_gateway.errors.ErrorCode, message: str)
@dataclass(frozen=True, slots=True)
class
FetchOutcome:
143@dataclass(frozen=True, slots=True) 144class FetchOutcome: 145 kind: Literal["accepted", "semantic_failure", "execution_failure"] 146 candidate: URLFetchCandidate | None = None 147 failures: tuple[ExecutionFailure, ...] = ()
FetchOutcome( kind: Literal['accepted', 'semantic_failure', 'execution_failure'], candidate: agent_search_gateway.providers.contracts.URLFetchCandidate | None = None, failures: tuple[agent_search_gateway.errors.ExecutionFailure, ...] = ())
candidate: agent_search_gateway.providers.contracts.URLFetchCandidate | None
failures: tuple[agent_search_gateway.errors.ExecutionFailure, ...]