/**
 * `HybridQuery` — translates a `SearchQuery` into LanceDB's built-in
 * hybrid (vector ∪ FTS) search, then applies the post-rank weight
 * multiplier, the parent_id collapse, and the `<b>`-wrapping snippet
 * highlighter.
 *
 * Design reference: docs/design/semantic-search.md §3 (query surface),
 * §7 (query assembly, RRF, weight multiplier, collapse), §12
 * (test coverage).
 *
 * Contract for callers (search-service):
 *   const hq = new HybridQuery({ lance, embedder });
 *   const results = await hq.search({ q: "story", limit: 20 });
 *
 * This module owns no state beyond its construction args. Errors from
 * the native binary / embedder propagate — the service layer maps them
 * to graceful-degradation responses per §11.
 */
import type { Embedder, Indexable, SearchQuery, SearchResult, SearchResults } from "./types.js";
import type { LanceStore } from "./lance-store.js";
/**
 * Shape of a single row returned from the hybrid `.toArray()`. Mirrors
 * the `content` table Arrow schema (§3) plus Lance-injected scoring
 * columns (`_score`, `_relevance_score`).
 *
 * We deliberately accept `unknown`-flavoured fields for robustness: the
 * native binary can surface `bigint` timestamps, nullable scalars, and
 * embedding arrays as proxies. Normalisation happens in `toSearchResult`.
 */
interface RawHybridRow {
    id: string;
    source_id: Indexable["sourceId"];
    project_id: string;
    entity_type?: string | null;
    parent_id?: string | null;
    archived?: boolean | null;
    timestamp?: number | bigint | null;
    weight: number;
    role?: string | null;
    title?: string | null;
    text: string;
    goal_id?: string | null;
    session_id?: string | null;
    session_title?: string | null;
    file_path?: string | null;
    start_line?: number | null;
    end_line?: number | null;
    /** Lance hybrid rank-fusion score (post-RRF). */
    _relevance_score?: number;
    /** Lance raw FTS score (BM25-like). Kept for completeness. */
    _score?: number;
    [key: string]: unknown;
}
export interface HybridQueryOptions {
    lance: LanceStore;
    embedder: Embedder;
}
/**
 * Build an SQL-ish filter string for the Lance query's `.where(...)`.
 *
 * Exported as a pure function so tests can lock in each combination
 * without touching the native binary. All inputs are controlled
 * internals (project ids and a fixed `sourceId` enum), so a simple
 * single-quote escape is sufficient — but we apply it consistently so
 * stray apostrophes in future ids do not break the SQL.
 *
 * Contract:
 *   - No `projectId` + archived-excluded (default) + no `types` → `"archived = false"`
 *   - `includeArchived: true` and no other filters → `"TRUE"`
 *   - Combined filters are joined with ` AND `.
 */
export declare function buildFilter(q: SearchQuery): string;
/**
 * Render a single LanceDB hybrid-result row into the `SearchResult`
 * shape consumed by the UI. `query` is forwarded to
 * `snippet.highlight` to produce the `<b>`-wrapped snippet.
 *
 * Exported for tests and for future reuse by a hypothetical
 * per-source result mapper.
 */
export declare function toSearchResult(row: RawHybridRow, query: string, finalScore: number): SearchResult;
/**
 * Stateless-ish hybrid query executor. Instances are cheap to hold onto
 * — one per `SearchService`.
 */
export declare class HybridQuery {
    private readonly _lance;
    private readonly _embedder;
    private _reranker;
    constructor(opts: HybridQueryOptions);
    /**
     * Execute a hybrid (vector ∪ FTS + RRF) search.
     *
     * Steps (§7):
     *   1. Empty query → empty results (short-circuit before embedding).
     *   2. Embed query with `search_query: ` prefix.
     *   3. Build SQL filter via `buildFilter`.
     *   4. Chain `.fullTextSearch(...).nearestTo(vec).where(filter)
     *       .rerank(rrf).limit(... * 3).toArray()`.
     *   5. Multiply `_relevance_score` by row.weight → final score.
     *   6. Sort desc by final score.
     *   7. Collapse by `parent_id ?? id` (keep best chunk).
     *   8. Slice with offset/limit window.
     *   9. Map each survivor to `SearchResult` (with highlighted snippet).
     */
    search(q: SearchQuery): Promise<SearchResults>;
    private _getReranker;
}
export {};
//# sourceMappingURL=hybrid-query.d.ts.map