/** * Full-text search across BRAIN memory using SQLite FTS5. * Uses raw SQL via nativeDb because drizzle doesn't support FTS5 virtual tables. * * Falls back to LIKE queries if FTS5 is not available (some SQLite builds lack it). * * @task T5130 * @epic T5149 */ import type { DatabaseSync } from 'node:sqlite'; import type { BrainDecisionRow, BrainLearningRow, BrainObservationRow, BrainPatternRow } from '../store/schema/memory-schema.js'; /** Search result grouped by backing memory table. */ export interface BrainMemorySearchResult { decisions: BrainDecisionRow[]; patterns: BrainPatternRow[]; learnings: BrainLearningRow[]; observations: BrainObservationRow[]; } /** Search options. */ export interface BrainSearchOptions { /** Max results per table. Default 10. */ limit?: number; /** Which tables to search. Default: all four. */ tables?: Array<'decisions' | 'patterns' | 'learnings' | 'observations'>; /** * T1085: Peer ID filter for CANT agent memory isolation (PSYCHE Wave 2). * * When provided, search results are scoped to entries where: * `peer_id = peerId OR peer_id = 'global'` * * This ensures a peer always sees its own memories plus the global pool, * but never sees another peer's private memories. * * When omitted (undefined), all entries are returned regardless of peer_id — * preserving backward-compatible behavior for callers that predate Wave 2. */ peerId?: string; /** * T1085: When true (default when peerId is provided), include entries with * `peer_id = 'global'` in addition to `peer_id = peerId`. * * Set to false for strict per-peer isolation (no global pool bleed-through). * Defaults to true — omitting this is equivalent to `includeGlobal: true`. */ includeGlobal?: boolean; } /** * Create FTS5 virtual tables and content-sync triggers if they don't exist. * * Uses content= to sync from main tables, so inserts to main tables * auto-populate FTS. UPDATE/DELETE require triggers. * * @task T5130 */ export declare function ensureFts5Tables(nativeDb: DatabaseSync): boolean; /** * Rebuild FTS5 indexes from the content tables. * Useful after bulk inserts that bypass triggers. * * @task T5130 */ export declare function rebuildFts5Index(nativeDb: DatabaseSync): void; /** * Unified search across all BRAIN memory tables. * * Uses FTS5 MATCH for full-text search with BM25 ranking when available, * falls back to LIKE queries otherwise. * * @task T5130 */ export declare function searchBrain(projectRoot: string, query: string, options?: BrainSearchOptions): Promise; /** * Reset the cached FTS5 availability flag. * Used in tests to force re-detection. */ export declare function resetFts5Cache(): void; /** * The RRF smoothing constant (research-proven at 60). * * Balances noise vs. signal: small values amplify top-rank differences; * large values compress ranks toward a flat distribution. 60 is the * standard value from Cormack, Clarke & Buettcher (SIGIR 2009). */ export declare const RRF_K = 60; /** A single ranked hit from one retrieval source before fusion. */ export interface RrfHit { id: string; type: string; title: string; text: string; } /** Fused result produced by reciprocalRankFusion. */ export interface RrfResult { id: string; /** Combined RRF score: sum of 1/(rank+RRF_K) across all source lists. */ rrfScore: number; type: string; title: string; text: string; /** Which retrieval sources contributed to this result. */ sources: Array<'fts' | 'vec' | 'graph' | 'code'>; /** BM25-derived FTS rank (0-based) — undefined if not in FTS results. */ ftsRank?: number; /** Vector distance rank (0-based) — undefined if not in vector results. */ vecRank?: number; } /** * Fuse ranked lists from multiple retrieval sources using Reciprocal Rank Fusion. * * Implements the RRF algorithm from Cormack, Clarke & Buettcher (SIGIR 2009): * * score(d) = Σ 1 / (k + rank(d, list)) for each list containing d * * where k=60 is the research-proven smoothing constant. * * Properties: * - Rank-based: actual scores from each source are ignored (only rank matters). * - Additive: items appearing in multiple lists accumulate higher scores. * - Robust: the +60 constant prevents rank-1 items from dominating. * * @param sources - Named arrays of ranked hits (order = rank, index 0 = best) * @param k - RRF smoothing constant (default: RRF_K = 60) * @returns Array of fused results sorted by rrfScore descending * * @example * ```ts * const fused = reciprocalRankFusion([ * { source: 'fts', hits: ftsHits }, * { source: 'vec', hits: vecHits }, * ]); * ``` */ export declare function reciprocalRankFusion(sources: Array<{ source: 'fts' | 'vec' | 'graph' | 'code'; hits: RrfHit[]; }>, k?: number): RrfResult[]; /** Result from hybridSearch combining multiple search signals. */ export interface HybridResult { id: string; /** RRF-fused score: sum of 1/(rank+60) across all source lists. */ score: number; type: string; title: string; text: string; sources: Array<'fts' | 'vec' | 'graph' | 'code'>; /** Raw FTS rank (0-based) for transparency — undefined if FTS did not return this item. */ ftsRank?: number; /** Raw vector rank (0-based) for transparency — undefined if vector did not return this item. */ vecRank?: number; } /** Options for hybridSearch. */ export interface HybridSearchOptions { limit?: number; /** * RRF smoothing constant k. Default: 60 (research-proven). * Larger k flattens rank differences; smaller k amplifies top-rank advantage. */ rrfK?: number; /** * When true, also search code symbols via @cleocode/nexus smartSearch. * Default: false. Code symbol hits are mapped to memory-compatible type/title. * * @task T1058 */ includeCode?: boolean; } /** * Hybrid search across FTS5, vector similarity, graph neighbors, and optionally code symbols. * Uses Reciprocal Rank Fusion (RRF) for result combination. * * Algorithm: * 1. Run FTS5 search, vector similarity search, and optionally code symbol search in parallel. * 2. Optionally expand via graph neighbors (best-effort). * 3. Fuse all ranked lists with RRF: score = Σ 1/(rank+rrfK). * 4. Return top-N sorted by fused RRF score. * * Graceful degradation: vector, graph, and code sources are silently skipped when * unavailable — RRF naturally handles partial source lists. * * @param query - Search query text * @param projectRoot - Project root directory * @param options - Limit, RRF tuning, and includeCode flag for code symbol search * @returns Array of hybrid results ranked by RRF score descending * * @task T5130 (hybrid search), T1058 (code symbol integration) */ export declare function hybridSearch(query: string, projectRoot: string, options?: HybridSearchOptions): Promise; //# sourceMappingURL=brain-search.d.ts.map