/** * The single lexical retrieval service for the monograph knowledge graph. * * Every adapter — the package-level `monograph_query` MCP tool, the * CLI-hosted `monograph_query` MCP tool, `augmentContext`, the eval server — * calls {@link searchGraph} rather than assembling its own BM25/LIKE/fuzzy * combination. Two adapters answering the same query differently was a real * bug, not a hypothetical one. * * SCORE CONVENTION — higher is better, always non-negative. * SQLite FTS5's `rank` is the opposite (negative, more negative = better). * That inversion is resolved in exactly one place, * {@link relevanceFromFtsRank} in `../storage/fts-store.js`, at the boundary * where a rank enters the system. Nothing downstream ever sees a raw rank, so * the sign cannot be forwarded into a ranker again. * * Monograph search is lexical-only. The former embedding/vector branch * (gated on MONOGRAPH_EMBEDDINGS=true) was removed — it was never run in * practice (the embeddings table stayed empty) and did a JS cosine full scan. */ import type Database from 'better-sqlite3'; import type { RankedResult } from './rrf.js'; /** * Retrieval strategies, named for what they actually do. * * - `hybrid` — FTS5 BM25 + LIKE fallback + in-memory fuzzy + node-type bonus. * The default: it degrades gracefully on short identifiers, where bare BM25 * over a trigram index returns nothing. * - `bm25` — FTS5 BM25 only. Narrower, but predictable; used where a caller * wants pure lexical ranking with no heuristic bonuses. */ export type RetrievalMode = 'bm25' | 'hybrid'; /** * Which part of the graph a search covers. * * - `code` — symbols, files, routes and tools. * - `docs` — markdown sections, documents and concepts. * - `agents` — agent and skill definitions. * - `all` — everything, ranked purely by relevance. * - `auto` (default) — code first, with documentation filling any slots the * code left empty; a query that is plainly about documentation flips that * order. Doc sections outnumber code symbols roughly 1:2 in this repo, so * without this an abstract task query is answered entirely by headings. */ export type SearchScope = 'code' | 'docs' | 'agents' | 'all' | 'auto'; export declare const CODE_SCOPE_LABELS: readonly string[]; export declare const DOC_SCOPE_LABELS: readonly string[]; export declare const AGENT_SCOPE_LABELS: readonly string[]; /** True when the query is asking which agent or skill to use. */ export declare function hasAgentIntent(query: string): boolean; /** True when the query is plainly asking about documentation rather than code. */ export declare function hasDocIntent(query: string): boolean; export interface GraphSearchOptions { limit?: number; /** Exact node label (or labels). Overrides `scope`. */ label?: string | readonly string[]; /** Part of the graph to search (default: `auto`). */ scope?: SearchScope; /** Retrieval strategy (default: `hybrid`). */ mode?: RetrievalMode; } export interface GraphSearchResult { id: string; name: string; normLabel: string; filePath: string | null; label: string; /** Higher is better, always ≥ 0. See the score-convention note above. */ relevance: number; /** First line of the symbol in its source file (1-based, null if unknown). */ startLine: number | null; /** Last line of the symbol in its source file (1-based, null if unknown). */ endLine: number | null; /** Which retrieval strategy surfaced this row. */ matchStrategy: 'fts' | 'like' | 'fuzzy' | 'semantic'; } /** * Run a lexical search over the graph and return results under the * higher-is-better score convention. * * The query is prepared identically for every mode so that two adapters * asking the same question in the same mode get the same answer. * * Preparation is `trim()` only, deliberately. The FTS5 index uses the trigram * tokenizer, which folds ASCII case but does NOT fold diacritics, and the * index stores `name`/`norm_label` verbatim. Stripping diacritics from the * query (as the old `bm25Query` did) therefore could never *gain* a match — * it only stopped `naïveResolver` from finding the symbol literally named * `naïveResolver`. Lowercasing is likewise skipped: it is a no-op for ASCII * under both the trigram tokenizer and SQLite's LIKE, and for non-ASCII it * would break the LIKE fallback against a capitalized name. */ export declare function searchGraph(db: Database.Database, query: string, options?: GraphSearchOptions): GraphSearchResult[]; /** Tests restate the code they exercise; they rank below it unless asked for. */ export declare const TEST_PATH: RegExp; export declare const TEST_INTENT: RegExp; export declare const TEST_FACTOR = 0.6; export interface BM25QueryOptions { limit?: number; label?: string; /** @deprecated Embeddings are disabled — this option is ignored; search is lexical-only. Will be removed in the next major version. */ embedder?: unknown; } /** @deprecated Use {@link GraphSearchOptions} — this alias will be removed in the next major version. */ export type HybridQueryOptions = BM25QueryOptions; export interface BM25Result extends RankedResult { id: string; name: string; normLabel: string; filePath: string | null; label: string; /** Higher is better, always ≥ 0 — see the score-convention note above. */ score: number; /** First line of the symbol in its source file (1-based, null if unknown). */ startLine?: number | null; /** Last line of the symbol in its source file (1-based, null if unknown). */ endLine?: number | null; } /** @deprecated Use {@link GraphSearchResult} — this alias will be removed in the next major version. */ export type HybridResult = BM25Result; /** * @deprecated Use {@link searchGraph} with `mode: 'bm25'`. Retained as a thin * wrapper so existing callers keep working; it now reports the same * higher-is-better `score` as every other path (it used to forward FTS5's * raw negative `rank`, which inverted ranking for anything downstream that * compared or propagated scores). */ export declare function bm25Query(db: Database.Database, query: string, options?: BM25QueryOptions): Promise; /** * @deprecated Use {@link searchGraph} instead — this is a misleading name * (search here is lexical-only, not a hybrid of multiple retrieval * *modalities*). `hybridQuery` remains as an alias for backward compatibility * and will be removed in the next major version. */ export declare const hybridQuery: typeof bm25Query; //# sourceMappingURL=hybrid-query.d.ts.map