{"version":3,"file":"multi-query.mjs","names":[],"sources":["../../../../../../../../ai/src/rag/transforms/multi-query.ts"],"sourcesContent":["import type { ModelContract } from \"../../contracts/model.contract\";\n\n/** Options for {@link multiQuery}. */\nexport type MultiQueryOptions = {\n  /** How many alternative phrasings to request. Default 3. */\n  n?: number;\n  /** Include the original query in the returned list. Default true. */\n  includeOriginal?: boolean;\n};\n\n/**\n * Multi-query expansion (A4) — ask a model for several alternative\n * phrasings of `query`, so retrieval covers vocabulary the original\n * wording missed (synonyms, specificity, rephrasings). Pair the variants\n * with {@link hybridRank} / a vector search and fuse the per-variant hits.\n *\n * Deterministic, dependency-light parsing: the model is asked for one\n * query per line; bullets / numbering are stripped, blanks dropped, and\n * the set is de-duplicated. Returns the original (unless opted out) plus\n * up to `n` variants.\n *\n * @example\n * const queries = await multiQuery(model, \"how do I cancel?\", { n: 3 });\n * // → [\"how do I cancel?\", \"cancel my subscription\", \"end my plan\", ...]\n */\nexport async function multiQuery(\n  model: ModelContract,\n  query: string,\n  options: MultiQueryOptions = {},\n): Promise<string[]> {\n  const n = options.n ?? 3;\n  const includeOriginal = options.includeOriginal ?? true;\n\n  const prompt =\n    `Rewrite the following search query into ${n} alternative phrasings that would ` +\n    `retrieve relevant documents. Output ONE query per line, no numbering or commentary.\\n\\n` +\n    `Query: ${query}`;\n\n  const response = await model.complete([{ role: \"user\", content: prompt }]);\n\n  const variants = response.content\n    .split(\"\\n\")\n    .map(line => line.replace(/^\\s*(?:[-*•]|\\d+[.)])\\s*/, \"\").trim())\n    .filter(Boolean);\n\n  const seen = new Set<string>();\n  const out: string[] = [];\n\n  const add = (q: string) => {\n    const key = q.toLowerCase();\n    if (!seen.has(key)) {\n      seen.add(key);\n      out.push(q);\n    }\n  };\n\n  if (includeOriginal) add(query);\n  for (const variant of variants.slice(0, n)) add(variant);\n\n  return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAyBA,eAAsB,WACpB,OACA,OACA,UAA6B,CAAC,GACX;CACnB,MAAM,IAAI,QAAQ,KAAK;CACvB,MAAM,kBAAkB,QAAQ,mBAAmB;CAEnD,MAAM,SACJ,2CAA2C,EAAE,kIAEnC;CAIZ,MAAM,YAAW,MAFM,MAAM,SAAS,CAAC;EAAE,MAAM;EAAQ,SAAS;CAAO,CAAC,CAAC,EAEhD,CAAC,QACvB,MAAM,IAAI,CAAC,CACX,KAAI,SAAQ,KAAK,QAAQ,4BAA4B,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAChE,OAAO,OAAO;CAEjB,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,MAAgB,CAAC;CAEvB,MAAM,OAAO,MAAc;EACzB,MAAM,MAAM,EAAE,YAAY;EAC1B,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG;GAClB,KAAK,IAAI,GAAG;GACZ,IAAI,KAAK,CAAC;EACZ;CACF;CAEA,IAAI,iBAAiB,IAAI,KAAK;CAC9B,KAAK,MAAM,WAAW,SAAS,MAAM,GAAG,CAAC,GAAG,IAAI,OAAO;CAEvD,OAAO;AACT"}