"use strict";
/**
 * Multi-query expansion via Haiku (Task 308).
 *
 * Generates 3-5 paraphrases of the user query so the hybrid pipeline runs
 * each paraphrase against vector + BM25 in parallel and unions the
 * candidate sets before fusion. Recovers recall on terse queries where the
 * embedding's nearest-neighbour is unstable.
 *
 * The expansion runs through `@rubytech/oauth-llm` against Claude Haiku —
 * the same OAuth-bearer path the admin classifiers use; no new SDK
 * dependency and no Anthropic-API-key path. Cache is in-process, keyed by
 * (accountId, normalisedQuery, retrievalClass), with a 1-hour TTL.
 *
 * Graceful degrade: if the LLM call fails, returns just the original
 * query. The caller's hybrid pipeline still runs — just on one query
 * instead of N — so missing paraphrases are a recall regression, not a
 * fault.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.clearExpansionCache = clearExpansionCache;
exports.expandQuery = expandQuery;
const index_js_1 = require("../../oauth-llm/dist/index.js");
const CACHE_TTL_MS = 60 * 60 * 1000;
const HAIKU_MODEL = "claude-haiku-4-5";
const MAX_PARAPHRASES = 5;
const cache = new Map();
function clearExpansionCache() {
    cache.clear();
}
/**
 * Return `[query, ...paraphrases]` (original always first). On LLM
 * failure returns `[query]` only and writes a single stderr line so the
 * operator can see expansion is degrading without breaking search.
 */
async function expandQuery(params) {
    const { query, retrievalClass = "general", accountId = "", useCache = true } = params;
    const normalised = query.trim().toLowerCase();
    const cacheKey = `${accountId}::${retrievalClass}::${normalised}`;
    if (useCache) {
        const hit = cache.get(cacheKey);
        if (hit && hit.expiresAt > Date.now()) {
            return [query, ...hit.expansions];
        }
    }
    const systemPrompt = [
        "You generate paraphrases of a user query for hybrid graph search.",
        "Return 3-5 alternative phrasings that preserve the user's intent but vary the surface form (synonyms, word order, entity-vs-attribute framing).",
        "Do not change the entity names. Do not invent constraints the user did not state.",
        "Output ONLY a JSON object via the provided tool; never free text.",
    ].join("\n");
    const classHint = retrievalClass === "general"
        ? ""
        : `The retrieval class is '${retrievalClass}' — tailor paraphrases accordingly.`;
    const userMessage = [
        `Original query: ${query}`,
        classHint,
    ].filter((s) => s.length > 0).join("\n");
    const result = await (0, index_js_1.callOauthLlm)({
        model: HAIKU_MODEL,
        system: systemPrompt,
        userMessage,
        maxTokens: 512,
        timeoutMs: 15_000,
        tools: [
            {
                name: "emit_paraphrases",
                description: "Emit 3-5 paraphrases of the user query.",
                input_schema: {
                    type: "object",
                    properties: {
                        paraphrases: {
                            type: "array",
                            items: { type: "string" },
                            minItems: 3,
                            maxItems: MAX_PARAPHRASES,
                        },
                    },
                    required: ["paraphrases"],
                },
            },
        ],
        toolChoiceName: "emit_paraphrases",
    });
    if (result.kind !== "ok-tool") {
        process.stderr.write(`[graph-search:expansion-failed] cause=${result.kind === "fallback" ? result.cause : "unexpected"} query=${query.slice(0, 60).replace(/\s+/g, " ")}\n`);
        return [query];
    }
    const raw = result.input.paraphrases;
    if (!Array.isArray(raw))
        return [query];
    const expansions = raw
        .filter((p) => typeof p === "string" && p.trim().length > 0)
        .map((p) => p.trim())
        .slice(0, MAX_PARAPHRASES);
    if (useCache) {
        cache.set(cacheKey, { expansions, expiresAt: Date.now() + CACHE_TTL_MS });
    }
    return [query, ...expansions];
}
//# sourceMappingURL=query-expansion.js.map