""" Knowledge Consolidation models for Librarian processing. Used by the consolidation endpoint to process SearchQuery nodes and consolidate knowledge into wiki pages. """ from pydantic import BaseModel, Field from typing import List, Optional, Dict, Any class ConsolidationRequest(BaseModel): """Request for knowledge consolidation from search results.""" process_limit: int = Field(default=10, ge=1, le=100, description="Max searches to process") lookback_days: int = Field(default=7, ge=1, le=90, description="Process searches from last N days") min_web_results: int = Field(default=2, ge=1, le=20, description="Minimum web results needed") dry_run: bool = Field(default=False, description="If true, analyze but don't create pages") class SearchQueryInfo(BaseModel): """Information about a search query to process.""" id: str query: str user: str timestamp: str total_results: int web_count: int keywords: List[str] = [] class ConsolidationResult(BaseModel): """Result of processing a single search query.""" search_id: str query: str pages_created: int = 0 pages_updated: int = 0 entities_added: int = 0 volatile_cached: int = 0 files_queued: int = 0 prefetch_registered: int = 0 error: Optional[str] = None class ConsolidationResponse(BaseModel): """Response from knowledge consolidation.""" total_found: int = Field(description="Total unprocessed searches found") processed_count: int = Field(description="Successfully processed searches") pages_created: int = Field(description="New wiki pages created") pages_updated: int = Field(description="Existing pages updated") entities_added: int = Field(description="New entities added to graph") volatile_cached: int = Field(default=0, description="Items cached to volatile storage") files_queued: int = Field(default=0, description="Files queued for Paperless") prefetch_registered: int = Field(default=0, description="Prefetch patterns registered") searches_deferred: int = Field( default=0, description="Searches left unprocessed for the next run because the generation LLM was unavailable" ) errors: List[str] = Field(default=[], description="Error messages") results: List[ConsolidationResult] = Field(description="Per-search results") dry_run: bool = Field(description="Whether this was a dry run") duration_ms: float = Field(default=0.0, description="Run duration in milliseconds") class MemoryRouteClassification(BaseModel): """ Unified classification of a web result for memory routing. Route types: - wiki: Stable reference content → wiki page creation/update - volatile: Ephemeral data (weather, news, prices) → volatile cache - file: Downloadable file (PDF, doc, xls, images) → Paperless ingestion - prefetch: Regularly updated source → scheduler registration - skip: Low value, ads, errors → discard """ url: str title: str route_type: str = Field(description="One of: wiki, volatile, file, prefetch, skip") # Wiki routing fields wiki_action: Optional[str] = Field(default=None, description="create or update") wiki_path: Optional[str] = Field(default=None, description="Wiki path for page") wiki_summary: Optional[str] = Field(default=None, description="Summary for wiki page") # Volatile routing fields volatile_namespace: Optional[str] = Field(default=None, description="weather, news, financial, etc.") volatile_key: Optional[str] = Field(default=None, description="Cache key") volatile_ttl_hours: Optional[int] = Field(default=None, description="TTL in hours") # Prefetch routing fields prefetch_cron: Optional[str] = Field(default=None, description="Cron expression for refresh") prefetch_endpoint: Optional[str] = Field(default=None, description="API endpoint to call") # Classification metadata confidence: float = Field(default=0.0, ge=0.0, le=1.0) reason: str = Field(default="") class MemoryRoutingResult(BaseModel): """Aggregated result of memory routing for a search.""" wiki_routed: int = 0 volatile_cached: int = 0 files_queued: int = 0 prefetch_registered: int = 0 skipped: int = 0 classifications: List[MemoryRouteClassification] = []