const MODEL_NAME = 'Xenova/ms-marco-MiniLM-L-6-v2';
// Use Function constructor to bypass TypeScript static module resolution
// for optional peer dependencies that may not be installed (mirrors the
// pattern in src/embeddings.ts).
const _dynImport = new Function('s', 'return import(s)');
let cachedPipeline = null;
let warnedOnFallback = false;
/**
 * True if @xenova/transformers is importable. Note: this does NOT confirm
 * that the model is downloadable from Hugging Face CDN — in sandboxed
 * environments the package may import but the model fetch may be blocked.
 * The reranker silently falls back to identity ordering in that case.
 */
export async function isCrossEncoderAvailable() {
    try {
        const t = (await _dynImport('@xenova/transformers'));
        return typeof t.pipeline === 'function';
    }
    catch {
        return false;
    }
}
async function loadPipeline() {
    if (cachedPipeline)
        return cachedPipeline;
    try {
        const mod = (await _dynImport('@xenova/transformers'));
        const p = (await mod.pipeline('text-classification', MODEL_NAME));
        cachedPipeline = async (query, candidate) => {
            const out = (await p(`${query} [SEP] ${candidate}`));
            return Array.isArray(out) ? out : [out];
        };
        return cachedPipeline;
    }
    catch {
        return null;
    }
}
/**
 * Track 2 reranker: MS-MARCO MiniLM cross-encoder.
 * Loads model on first call, then sub-100ms per query for top-K=50 candidates
 * on a typical developer laptop CPU. Falls back to identity ordering if the
 * model fails to load (no transformers, no network for first download, etc.).
 *
 * See docs/plans/2026-05-10-f6-reranker-hardening.md Task 6.
 */
export const crossEncoderReranker = async (query, results, options) => {
    const topK = options?.topK ?? 50;
    const head = results.slice(0, topK);
    const pipe = await loadPipeline();
    if (!pipe) {
        // Fallback: identity ordering with rerankScore = original score. Warn
        // once per process so a silent identity-fallback doesn't mislead users
        // into thinking the cross-encoder is doing work it isn't.
        if (!warnedOnFallback) {
            warnedOnFallback = true;
            // eslint-disable-next-line no-console
            console.warn('[hippo] cross-encoder reranker unavailable (no @xenova/transformers, or model fetch blocked); falling back to identity ordering. Subsequent calls will not repeat this warning.');
        }
        return head.map((r, i) => ({
            ...r,
            rerankScore: r.score,
            preRerankRank: r.preRerankRank ?? i + 1,
            postRerankRank: i + 1,
        }));
    }
    const scored = await Promise.all(head.map(async (r, i) => {
        let ceScore;
        try {
            const out = await pipe(query, r.entry.content);
            ceScore = Array.isArray(out) && out.length > 0 ? out[0].score : 0;
        }
        catch {
            // Per-call inference failure (transient tensor error, bad input,
            // etc.): fall back to original score for this candidate so a
            // single bad inference doesn't sink the whole rerank pass.
            ceScore = r.score;
        }
        return {
            ...r,
            rerankScore: ceScore,
            preRerankRank: r.preRerankRank ?? i + 1,
            postRerankRank: 0,
        };
    }));
    scored.sort((a, b) => b.rerankScore - a.rerankScore);
    scored.forEach((r, i) => (r.postRerankRank = i + 1));
    return scored;
};
//# sourceMappingURL=cross-encoder.js.map