from datetime import datetime from typing import Literal from uuid import UUID from pydantic import BaseModel, ConfigDict, Field from app.schemas.catalog import Category, Input from app.schemas.indexing import TimestampRead from app.schemas.retrieval import RetrievalHit class EmbeddingSpecRead(BaseModel): model: str revision: str dimension: int token_limit: int query_instruction: str implementation: str checkpoint_format: str class SpaceRead(BaseModel): model_config = ConfigDict(from_attributes=True) id: str dimension: int spec: EmbeddingSpecRead class BuildVectors(Input): text_index_version_id: UUID class VectorRead(TimestampRead): id: UUID text_index_version_id: UUID space_id: str dimension: int chunk_count: int status: Literal["ready", "published", "superseded"] created_by: int created_at: datetime published_at: datetime | None class ActiveVectors(BaseModel): generation: int text_generation: int catalog_revision: int is_current: bool active_version: VectorRead | None class VectorRequest(Input): query: str = Field(min_length=1, max_length=500) mode: Literal["vector"] = "vector" top_k: int = Field(5, ge=1, le=20) category: Category | None = None class VectorHit(RetrievalHit): chunk_id: UUID chunk_ordinal: int class VectorRetrievalConfig(BaseModel): scorer: Literal["pgvector-cosine-exact-v1"] = "pgvector-cosine-exact-v1" ranking_unit: Literal["chunk"] = "chunk" space: SpaceRead class VectorRetrievalResponse(BaseModel): run_id: UUID query: str mode: Literal["vector"] = "vector" status: Literal["ok", "no_evidence"] top_k: int category: str | None vector_version_id: UUID text_index_version_id: UUID generation: int text_generation: int corpus_fingerprint: str corpus_size: int total_hits: int results: list[VectorHit] elapsed_ms: float created_at: datetime config: VectorRetrievalConfig