"""Retrieval orchestrator: query string -> top-K RetrievalResult. Embedder is injected. Term extraction uses catalog.term_regex + catalog.registry. """ from __future__ import annotations from scripts.lib.catalog_loader import Catalog from scripts.lib.embedder import Embedder from scripts.lib.ranker import rank, RetrievalResult from scripts.lib.term_extraction import find_terms def retrieve( *, catalog: Catalog, query: str, embedder: Embedder, top_k: int = 5, semantic_weight: float = 1.0, structured_weight: float = 1.5, graph_weight: float = 0.7, authored_reference_forward_weight: float = 1.2, authored_reference_reverse_weight: float = 0.6, reverse_escort_top_n: int = 1, kind_quotas: dict[str, int] | None = None, kind_caps: dict[str, int] | None = None, score_penalties: dict[str, float] | None = None, ) -> list[RetrievalResult]: query_vec = embedder.embed_one(query) if len(query_vec) != catalog.embedding_dim: raise ValueError( f"embedder dimension {len(query_vec)} does not match " f"catalog.embedding_dim {catalog.embedding_dim}; " f"catalog was built with model={catalog.embedding_model}" ) matched_terms = find_terms(query, catalog.term_regex, catalog.registry) return rank( catalog, query_vec, matched_terms, top_k=top_k, semantic_weight=semantic_weight, structured_weight=structured_weight, graph_weight=graph_weight, authored_reference_forward_weight=authored_reference_forward_weight, authored_reference_reverse_weight=authored_reference_reverse_weight, reverse_escort_top_n=reverse_escort_top_n, kind_quotas=kind_quotas, kind_caps=kind_caps, score_penalties=score_penalties, )