Source code for yoker.tools.web_types

"""Web search types: SearchResult dataclass and WebSearchError exception.

Provides structured result types for web search operations.
"""

from dataclasses import dataclass, field
from typing import Any


[docs] @dataclass(frozen=True) class SearchResult: """A single web search result. Attributes: title: Page title. url: Result URL. snippet: Short text snippet/summary. source: Backend that produced this result (e.g., "ollama", "duckduckgo"). """ title: str url: str snippet: str source: str = "unknown"
[docs] def to_dict(self) -> dict[str, str]: """Convert SearchResult to dictionary. Returns: Dictionary with all fields. """ return { "title": self.title, "url": self.url, "snippet": self.snippet, "source": self.source, }
[docs] @classmethod def from_dict(cls, data: dict[str, Any]) -> "SearchResult": """Create SearchResult from dictionary. Args: data: Dictionary with result fields. Returns: SearchResult instance. """ return cls( title=str(data.get("title", "")), url=str(data.get("url", "")), snippet=str(data.get("snippet", "")), source=str(data.get("source", "unknown")), )
[docs] class WebSearchError(Exception): """Base exception for web search errors. Attributes: message: Human-readable error message. backend: Backend that raised the error. cause: Original exception if wrapped. """ def __init__( self, message: str, backend: str = "unknown", cause: Exception | None = None, ) -> None: """Initialize error with context. Args: message: Human-readable error message. backend: Backend identifier (e.g., "ollama"). cause: Original exception if wrapping another error. """ self.message = message self.backend = backend self.cause = cause super().__init__(message) def __str__(self) -> str: """Return readable string representation. Returns: Error message with backend context. """ if self.backend != "unknown": return f"[{self.backend}] {self.message}" return self.message
[docs] @dataclass(frozen=True) class FetchedContent: """Content fetched from a web URL. Attributes: url: The URL that was fetched. title: Page title (extracted or derived). content: Fetched content (markdown, text, or original). content_type: Content format ("markdown", "text", "html"). source: Backend that fetched this content ("ollama", "local"). metadata: Additional metadata (e.g., links, images, word_count). """ url: str title: str content: str content_type: str = "markdown" source: str = "unknown" metadata: dict[str, Any] = field(default_factory=dict)
[docs] def to_dict(self) -> dict[str, Any]: """Convert to dictionary for ToolResult. Returns: Dictionary with all fields. """ return { "url": self.url, "title": self.title, "content": self.content, "content_type": self.content_type, "source": self.source, "metadata": self.metadata, }
[docs] @classmethod def from_dict(cls, data: dict[str, Any]) -> "FetchedContent": """Create from dictionary. Args: data: Dictionary with content fields. Returns: FetchedContent instance. """ return cls( url=str(data.get("url", "")), title=str(data.get("title", "")), content=str(data.get("content", "")), content_type=str(data.get("content_type", "markdown")), source=str(data.get("source", "unknown")), metadata=dict(data.get("metadata", {})), )
[docs] class WebFetchError(Exception): """Exception for web fetch errors. Attributes: message: Human-readable error message. url: URL that failed (if applicable). backend: Backend that raised the error. cause: Original exception if wrapped. error_type: Type of error (ssrf, timeout, size, invalid_url, etc.). """ def __init__( self, message: str, url: str = "", backend: str = "unknown", cause: Exception | None = None, error_type: str = "unknown", ) -> None: """Initialize error with context. Args: message: Human-readable error message. url: URL that failed. backend: Backend identifier (e.g., "ollama"). cause: Original exception if wrapping another error. error_type: Error type (e.g., "timeout", "size_limit", "ssrf"). """ self.message = message self.url = url self.backend = backend self.cause = cause self.error_type = error_type super().__init__(message) def __str__(self) -> str: """Return readable string representation. Returns: Error message with backend context. """ if self.backend != "unknown": return f"[{self.backend}] {self.message}" return self.message
__all__ = [ "SearchResult", "WebSearchError", "FetchedContent", "WebFetchError", ]