@mneme-ai/core 0.8.4 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entities/go-parser.d.ts +47 -0
- package/dist/entities/go-parser.d.ts.map +1 -0
- package/dist/entities/go-parser.js +315 -0
- package/dist/entities/go-parser.js.map +1 -0
- package/dist/entities/go-parser.test.d.ts +2 -0
- package/dist/entities/go-parser.test.d.ts.map +1 -0
- package/dist/entities/go-parser.test.js +147 -0
- package/dist/entities/go-parser.test.js.map +1 -0
- package/dist/entities/index.d.ts +1 -0
- package/dist/entities/index.d.ts.map +1 -1
- package/dist/entities/index.js +1 -0
- package/dist/entities/index.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/indexer/indexer.d.ts +12 -0
- package/dist/indexer/indexer.d.ts.map +1 -1
- package/dist/indexer/indexer.js +28 -1
- package/dist/indexer/indexer.js.map +1 -1
- package/dist/insights/bus-factor.d.ts +58 -0
- package/dist/insights/bus-factor.d.ts.map +1 -0
- package/dist/insights/bus-factor.js +117 -0
- package/dist/insights/bus-factor.js.map +1 -0
- package/dist/insights/bus-factor.test.d.ts +2 -0
- package/dist/insights/bus-factor.test.d.ts.map +1 -0
- package/dist/insights/bus-factor.test.js +149 -0
- package/dist/insights/bus-factor.test.js.map +1 -0
- package/dist/insights/commit-coach.d.ts +80 -0
- package/dist/insights/commit-coach.d.ts.map +1 -0
- package/dist/insights/commit-coach.js +230 -0
- package/dist/insights/commit-coach.js.map +1 -0
- package/dist/insights/commit-coach.test.d.ts +2 -0
- package/dist/insights/commit-coach.test.d.ts.map +1 -0
- package/dist/insights/commit-coach.test.js +163 -0
- package/dist/insights/commit-coach.test.js.map +1 -0
- package/dist/insights/crystal-ball.d.ts +76 -0
- package/dist/insights/crystal-ball.d.ts.map +1 -0
- package/dist/insights/crystal-ball.js +219 -0
- package/dist/insights/crystal-ball.js.map +1 -0
- package/dist/insights/crystal-ball.test.d.ts +2 -0
- package/dist/insights/crystal-ball.test.d.ts.map +1 -0
- package/dist/insights/crystal-ball.test.js +157 -0
- package/dist/insights/crystal-ball.test.js.map +1 -0
- package/dist/insights/decisions.d.ts +38 -0
- package/dist/insights/decisions.d.ts.map +1 -0
- package/dist/insights/decisions.js +125 -0
- package/dist/insights/decisions.js.map +1 -0
- package/dist/insights/decisions.test.d.ts +2 -0
- package/dist/insights/decisions.test.d.ts.map +1 -0
- package/dist/insights/decisions.test.js +141 -0
- package/dist/insights/decisions.test.js.map +1 -0
- package/dist/insights/dream.d.ts +71 -0
- package/dist/insights/dream.d.ts.map +1 -0
- package/dist/insights/dream.js +235 -0
- package/dist/insights/dream.js.map +1 -0
- package/dist/insights/dream.test.d.ts +2 -0
- package/dist/insights/dream.test.d.ts.map +1 -0
- package/dist/insights/dream.test.js +127 -0
- package/dist/insights/dream.test.js.map +1 -0
- package/dist/insights/index.d.ts +21 -0
- package/dist/insights/index.d.ts.map +1 -0
- package/dist/insights/index.js +21 -0
- package/dist/insights/index.js.map +1 -0
- package/dist/insights/obsidian.d.ts +42 -0
- package/dist/insights/obsidian.d.ts.map +1 -0
- package/dist/insights/obsidian.js +263 -0
- package/dist/insights/obsidian.js.map +1 -0
- package/dist/insights/obsidian.test.d.ts +2 -0
- package/dist/insights/obsidian.test.d.ts.map +1 -0
- package/dist/insights/obsidian.test.js +241 -0
- package/dist/insights/obsidian.test.js.map +1 -0
- package/dist/insights/paradox.d.ts +36 -0
- package/dist/insights/paradox.d.ts.map +1 -0
- package/dist/insights/paradox.js +201 -0
- package/dist/insights/paradox.js.map +1 -0
- package/dist/insights/paradox.test.d.ts +2 -0
- package/dist/insights/paradox.test.d.ts.map +1 -0
- package/dist/insights/paradox.test.js +88 -0
- package/dist/insights/paradox.test.js.map +1 -0
- package/dist/insights/regret.d.ts +57 -0
- package/dist/insights/regret.d.ts.map +1 -0
- package/dist/insights/regret.js +137 -0
- package/dist/insights/regret.js.map +1 -0
- package/dist/insights/regret.test.d.ts +2 -0
- package/dist/insights/regret.test.d.ts.map +1 -0
- package/dist/insights/regret.test.js +153 -0
- package/dist/insights/regret.test.js.map +1 -0
- package/dist/insights/stack-trace.d.ts +40 -0
- package/dist/insights/stack-trace.d.ts.map +1 -0
- package/dist/insights/stack-trace.js +127 -0
- package/dist/insights/stack-trace.js.map +1 -0
- package/dist/insights/stack-trace.test.d.ts +2 -0
- package/dist/insights/stack-trace.test.d.ts.map +1 -0
- package/dist/insights/stack-trace.test.js +103 -0
- package/dist/insights/stack-trace.test.js.map +1 -0
- package/dist/insights/story.d.ts +34 -0
- package/dist/insights/story.d.ts.map +1 -0
- package/dist/insights/story.js +100 -0
- package/dist/insights/story.js.map +1 -0
- package/dist/insights/story.test.d.ts +2 -0
- package/dist/insights/story.test.d.ts.map +1 -0
- package/dist/insights/story.test.js +99 -0
- package/dist/insights/story.test.js.map +1 -0
- package/dist/insights/suggest.d.ts +29 -0
- package/dist/insights/suggest.d.ts.map +1 -0
- package/dist/insights/suggest.js +93 -0
- package/dist/insights/suggest.js.map +1 -0
- package/dist/insights/suggest.test.d.ts +2 -0
- package/dist/insights/suggest.test.d.ts.map +1 -0
- package/dist/insights/suggest.test.js +71 -0
- package/dist/insights/suggest.test.js.map +1 -0
- package/dist/insights/who-knows.d.ts +66 -0
- package/dist/insights/who-knows.d.ts.map +1 -0
- package/dist/insights/who-knows.js +125 -0
- package/dist/insights/who-knows.js.map +1 -0
- package/dist/insights/who-knows.test.d.ts +2 -0
- package/dist/insights/who-knows.test.d.ts.map +1 -0
- package/dist/insights/who-knows.test.js +109 -0
- package/dist/insights/who-knows.test.js.map +1 -0
- package/dist/quant/alpha.d.ts +87 -0
- package/dist/quant/alpha.d.ts.map +1 -0
- package/dist/quant/alpha.js +103 -0
- package/dist/quant/alpha.js.map +1 -0
- package/dist/quant/alpha.test.d.ts +2 -0
- package/dist/quant/alpha.test.d.ts.map +1 -0
- package/dist/quant/alpha.test.js +147 -0
- package/dist/quant/alpha.test.js.map +1 -0
- package/dist/quant/backtest.d.ts +57 -0
- package/dist/quant/backtest.d.ts.map +1 -0
- package/dist/quant/backtest.js +90 -0
- package/dist/quant/backtest.js.map +1 -0
- package/dist/quant/backtest.test.d.ts +2 -0
- package/dist/quant/backtest.test.d.ts.map +1 -0
- package/dist/quant/backtest.test.js +133 -0
- package/dist/quant/backtest.test.js.map +1 -0
- package/dist/quant/black-swan.d.ts +45 -0
- package/dist/quant/black-swan.d.ts.map +1 -0
- package/dist/quant/black-swan.js +112 -0
- package/dist/quant/black-swan.js.map +1 -0
- package/dist/quant/black-swan.test.d.ts +2 -0
- package/dist/quant/black-swan.test.d.ts.map +1 -0
- package/dist/quant/black-swan.test.js +131 -0
- package/dist/quant/black-swan.test.js.map +1 -0
- package/dist/quant/correlation-matrix.d.ts +54 -0
- package/dist/quant/correlation-matrix.d.ts.map +1 -0
- package/dist/quant/correlation-matrix.js +103 -0
- package/dist/quant/correlation-matrix.js.map +1 -0
- package/dist/quant/correlation-matrix.test.d.ts +2 -0
- package/dist/quant/correlation-matrix.test.d.ts.map +1 -0
- package/dist/quant/correlation-matrix.test.js +118 -0
- package/dist/quant/correlation-matrix.test.js.map +1 -0
- package/dist/quant/drawdown.d.ts +51 -0
- package/dist/quant/drawdown.d.ts.map +1 -0
- package/dist/quant/drawdown.js +96 -0
- package/dist/quant/drawdown.js.map +1 -0
- package/dist/quant/drawdown.test.d.ts +2 -0
- package/dist/quant/drawdown.test.d.ts.map +1 -0
- package/dist/quant/drawdown.test.js +166 -0
- package/dist/quant/drawdown.test.js.map +1 -0
- package/dist/quant/greek.d.ts +55 -0
- package/dist/quant/greek.d.ts.map +1 -0
- package/dist/quant/greek.js +157 -0
- package/dist/quant/greek.js.map +1 -0
- package/dist/quant/greek.test.d.ts +2 -0
- package/dist/quant/greek.test.d.ts.map +1 -0
- package/dist/quant/greek.test.js +138 -0
- package/dist/quant/greek.test.js.map +1 -0
- package/dist/quant/implied-volatility.d.ts +65 -0
- package/dist/quant/implied-volatility.d.ts.map +1 -0
- package/dist/quant/implied-volatility.js +149 -0
- package/dist/quant/implied-volatility.js.map +1 -0
- package/dist/quant/implied-volatility.test.d.ts +2 -0
- package/dist/quant/implied-volatility.test.d.ts.map +1 -0
- package/dist/quant/implied-volatility.test.js +127 -0
- package/dist/quant/implied-volatility.test.js.map +1 -0
- package/dist/quant/index.d.ts +28 -0
- package/dist/quant/index.d.ts.map +1 -0
- package/dist/quant/index.js +28 -0
- package/dist/quant/index.js.map +1 -0
- package/dist/quant/insider-trading.d.ts +56 -0
- package/dist/quant/insider-trading.d.ts.map +1 -0
- package/dist/quant/insider-trading.js +129 -0
- package/dist/quant/insider-trading.js.map +1 -0
- package/dist/quant/insider-trading.test.d.ts +2 -0
- package/dist/quant/insider-trading.test.d.ts.map +1 -0
- package/dist/quant/insider-trading.test.js +130 -0
- package/dist/quant/insider-trading.test.js.map +1 -0
- package/dist/quant/moneyball.d.ts +48 -0
- package/dist/quant/moneyball.d.ts.map +1 -0
- package/dist/quant/moneyball.js +110 -0
- package/dist/quant/moneyball.js.map +1 -0
- package/dist/quant/moneyball.test.d.ts +2 -0
- package/dist/quant/moneyball.test.d.ts.map +1 -0
- package/dist/quant/moneyball.test.js +137 -0
- package/dist/quant/moneyball.test.js.map +1 -0
- package/dist/quant/tax-loss-harvest.d.ts +59 -0
- package/dist/quant/tax-loss-harvest.d.ts.map +1 -0
- package/dist/quant/tax-loss-harvest.js +126 -0
- package/dist/quant/tax-loss-harvest.js.map +1 -0
- package/dist/quant/tax-loss-harvest.test.d.ts +2 -0
- package/dist/quant/tax-loss-harvest.test.d.ts.map +1 -0
- package/dist/quant/tax-loss-harvest.test.js +126 -0
- package/dist/quant/tax-loss-harvest.test.js.map +1 -0
- package/dist/retrieve/index.d.ts +2 -0
- package/dist/retrieve/index.d.ts.map +1 -1
- package/dist/retrieve/index.js +2 -0
- package/dist/retrieve/index.js.map +1 -1
- package/dist/retrieve/intent.d.ts +32 -0
- package/dist/retrieve/intent.d.ts.map +1 -0
- package/dist/retrieve/intent.js +104 -0
- package/dist/retrieve/intent.js.map +1 -0
- package/dist/retrieve/intent.test.d.ts +2 -0
- package/dist/retrieve/intent.test.d.ts.map +1 -0
- package/dist/retrieve/intent.test.js +106 -0
- package/dist/retrieve/intent.test.js.map +1 -0
- package/dist/retrieve/search.d.ts +30 -0
- package/dist/retrieve/search.d.ts.map +1 -1
- package/dist/retrieve/search.js +48 -0
- package/dist/retrieve/search.js.map +1 -1
- package/dist/retrieve/search.test.js +84 -1
- package/dist/retrieve/search.test.js.map +1 -1
- package/dist/retrieve/synthesize.d.ts +57 -0
- package/dist/retrieve/synthesize.d.ts.map +1 -0
- package/dist/retrieve/synthesize.js +191 -0
- package/dist/retrieve/synthesize.js.map +1 -0
- package/dist/retrieve/synthesize.test.d.ts +2 -0
- package/dist/retrieve/synthesize.test.d.ts.map +1 -0
- package/dist/retrieve/synthesize.test.js +127 -0
- package/dist/retrieve/synthesize.test.js.map +1 -0
- package/dist/store/schema.d.ts +2 -2
- package/dist/store/schema.d.ts.map +1 -1
- package/dist/store/schema.js +60 -2
- package/dist/store/schema.js.map +1 -1
- package/dist/store/sqlite.d.ts +2 -0
- package/dist/store/sqlite.d.ts.map +1 -1
- package/dist/store/sqlite.js +24 -0
- package/dist/store/sqlite.js.map +1 -1
- package/dist/store/sqlite.test.js +1 -1
- package/dist/util/index.d.ts +2 -0
- package/dist/util/index.d.ts.map +1 -1
- package/dist/util/index.js +2 -1
- package/dist/util/index.js.map +1 -1
- package/dist/util/redact.d.ts +58 -0
- package/dist/util/redact.d.ts.map +1 -0
- package/dist/util/redact.js +129 -0
- package/dist/util/redact.js.map +1 -0
- package/dist/util/redact.test.d.ts +2 -0
- package/dist/util/redact.test.d.ts.map +1 -0
- package/dist/util/redact.test.js +148 -0
- package/dist/util/redact.test.js.map +1 -0
- package/dist/wisdom/calibrator.d.ts +43 -0
- package/dist/wisdom/calibrator.d.ts.map +1 -0
- package/dist/wisdom/calibrator.js +120 -0
- package/dist/wisdom/calibrator.js.map +1 -0
- package/dist/wisdom/feedback.d.ts +45 -0
- package/dist/wisdom/feedback.d.ts.map +1 -0
- package/dist/wisdom/feedback.js +116 -0
- package/dist/wisdom/feedback.js.map +1 -0
- package/dist/wisdom/index.d.ts +15 -0
- package/dist/wisdom/index.d.ts.map +1 -0
- package/dist/wisdom/index.js +15 -0
- package/dist/wisdom/index.js.map +1 -0
- package/dist/wisdom/types.d.ts +67 -0
- package/dist/wisdom/types.d.ts.map +1 -0
- package/dist/wisdom/types.js +20 -0
- package/dist/wisdom/types.js.map +1 -0
- package/dist/wisdom/wisdom.test.d.ts +2 -0
- package/dist/wisdom/wisdom.test.d.ts.map +1 -0
- package/dist/wisdom/wisdom.test.js +144 -0
- package/dist/wisdom/wisdom.test.js.map +1 -0
- package/package.json +1 -1
package/dist/retrieve/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/retrieve/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/retrieve/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query intent classifier.
|
|
3
|
+
*
|
|
4
|
+
* Mneme is designed for SPECIFIC questions ("why does X exist?", "when did Y
|
|
5
|
+
* change?"). It's not a code-review oracle and not a general-purpose chatbot.
|
|
6
|
+
* When users ask vague questions ("how to improve my code", "what's wrong"),
|
|
7
|
+
* the right move is to redirect them BEFORE retrieval — pretending to answer
|
|
8
|
+
* with low-confidence results is dishonest.
|
|
9
|
+
*
|
|
10
|
+
* Classification is regex-based on purpose:
|
|
11
|
+
* - Deterministic, runs in microseconds, no LLM needed
|
|
12
|
+
* - User-overridable: flags exist for "trust me, just retrieve"
|
|
13
|
+
* - Falsifiable: every signal is a documented heuristic, not a black box
|
|
14
|
+
*/
|
|
15
|
+
export type Intent = "specific" | "lookup" | "temporal" | "vague";
|
|
16
|
+
export interface IntentResult {
|
|
17
|
+
intent: Intent;
|
|
18
|
+
/** Why this classification was chosen — for transparency / debugging. */
|
|
19
|
+
reason: string;
|
|
20
|
+
/**
|
|
21
|
+
* If intent === "vague", a redirect message to show the user instead of
|
|
22
|
+
* running retrieval. Empty for other intents.
|
|
23
|
+
*/
|
|
24
|
+
redirect?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Classify a query's intent. Order matters: lookup and temporal patterns are
|
|
28
|
+
* checked BEFORE vague patterns, so "who wrote how-to-do-x.md" is classified
|
|
29
|
+
* as a lookup, not a vague query.
|
|
30
|
+
*/
|
|
31
|
+
export declare function classifyIntent(query: string): IntentResult;
|
|
32
|
+
//# sourceMappingURL=intent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../../src/retrieve/intent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,MAAM,GACd,UAAU,GACV,QAAQ,GACR,UAAU,GACV,OAAO,CAAC;AAEZ,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAoDD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAwC1D"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query intent classifier.
|
|
3
|
+
*
|
|
4
|
+
* Mneme is designed for SPECIFIC questions ("why does X exist?", "when did Y
|
|
5
|
+
* change?"). It's not a code-review oracle and not a general-purpose chatbot.
|
|
6
|
+
* When users ask vague questions ("how to improve my code", "what's wrong"),
|
|
7
|
+
* the right move is to redirect them BEFORE retrieval — pretending to answer
|
|
8
|
+
* with low-confidence results is dishonest.
|
|
9
|
+
*
|
|
10
|
+
* Classification is regex-based on purpose:
|
|
11
|
+
* - Deterministic, runs in microseconds, no LLM needed
|
|
12
|
+
* - User-overridable: flags exist for "trust me, just retrieve"
|
|
13
|
+
* - Falsifiable: every signal is a documented heuristic, not a black box
|
|
14
|
+
*/
|
|
15
|
+
/** Trigger phrases for vague queries. Listed by frequency in real misuse. */
|
|
16
|
+
const VAGUE_PATTERNS = [
|
|
17
|
+
{ re: /\bhow\s+to\b/i, reason: '"how to" — Mneme indexes history, not best-practices' },
|
|
18
|
+
{ re: /\b(best|good)\s+(practice|practices|way)s?\b/i, reason: 'asks for best practice — not a history question' },
|
|
19
|
+
{ re: /\b(improve|optimize|refactor|review)\s+(my|the|this)\s+code\b/i, reason: 'general code-improvement request' },
|
|
20
|
+
{ re: /\bshould\s+i\b/i, reason: '"should I" — opinion, not memory' },
|
|
21
|
+
{ re: /\bcan\s+you\s+(write|generate|create)\b/i, reason: 'asks Mneme to generate code — out of scope' },
|
|
22
|
+
{ re: /^(help|hello|hi|test)\s*$/i, reason: 'greeting / smoke-test, not a real question' },
|
|
23
|
+
{ re: /\bwhat\s+is\s+(the\s+)?(meaning|point)\s+of\s+(life|this)\b/i, reason: 'philosophical' },
|
|
24
|
+
];
|
|
25
|
+
/** Lookup: question is about a specific person, hash, or PR number. */
|
|
26
|
+
const LOOKUP_PATTERNS = [
|
|
27
|
+
{ re: /\bwho\s+(wrote|made|created|authored|added)\b/i, reason: 'who-question — author lookup' },
|
|
28
|
+
{ re: /\bwhat\s+did\s+\S+\s+(do|change|commit|write)\b/i, reason: 'asks what a person did — author lookup' },
|
|
29
|
+
{ re: /\bPR\s*#?\d+\b/i, reason: 'specific PR reference' },
|
|
30
|
+
{ re: /\b[a-f0-9]{7,40}\b/, reason: 'commit hash reference' },
|
|
31
|
+
];
|
|
32
|
+
/** Temporal: question asks about time, dates, or change-over-time. */
|
|
33
|
+
const TEMPORAL_PATTERNS = [
|
|
34
|
+
{ re: /\bwhen\s+(did|was|will)\b/i, reason: 'when-question — timeline query' },
|
|
35
|
+
{ re: /\b(last|recent|latest|previous|first|earliest)\s+(commit|change|update|time)\b/i, reason: 'temporal modifier' },
|
|
36
|
+
{ re: /\b(yesterday|today|last\s+(week|month|year|quarter))\b/i, reason: 'relative time reference' },
|
|
37
|
+
{ re: /\b(20\d{2})-(0[1-9]|1[0-2])\b/, reason: 'absolute date reference (YYYY-MM)' },
|
|
38
|
+
];
|
|
39
|
+
/** Specific: WHY/WHAT/HOW questions about a concrete thing. */
|
|
40
|
+
const SPECIFIC_PATTERNS = [
|
|
41
|
+
{ re: /\bwhy\s+(does|did|do|is|are|was|were)\b/i, reason: 'why-question with concrete subject' },
|
|
42
|
+
{ re: /\bwhat\s+(does|did|do|is|are)\b/i, reason: 'what-question (concrete)' },
|
|
43
|
+
{ re: /\bhow\s+(does|did|do|is|are)\b/i, reason: 'how-question (about behavior, not advice)' },
|
|
44
|
+
];
|
|
45
|
+
/** Words that, if PRESENT, suggest concreteness even for "how to" patterns. */
|
|
46
|
+
const CONCRETE_HINTS = /(\.[a-z]+\b|::|\bsrc\/|\b[A-Z][a-zA-Z]{2,}[A-Z][a-z]|\bfunction\s+\w+|\bclass\s+\w+|\bmodule\s+\w+|\bPR\s*#?\d+)/;
|
|
47
|
+
const VAGUE_REDIRECT_TEMPLATE = [
|
|
48
|
+
'I work best with specific questions about your repo\'s history.',
|
|
49
|
+
'Try one of these instead:',
|
|
50
|
+
'',
|
|
51
|
+
' • "why does <function or pattern> exist?"',
|
|
52
|
+
' • "when did we change <module>?"',
|
|
53
|
+
' • "who wrote <file>?"',
|
|
54
|
+
' • "what does <commit hash> do?"',
|
|
55
|
+
'',
|
|
56
|
+
'For general code improvement advice, use a chat assistant — Mneme is the',
|
|
57
|
+
'memory layer that feeds those tools, not a substitute for them.',
|
|
58
|
+
].join('\n');
|
|
59
|
+
/**
|
|
60
|
+
* Classify a query's intent. Order matters: lookup and temporal patterns are
|
|
61
|
+
* checked BEFORE vague patterns, so "who wrote how-to-do-x.md" is classified
|
|
62
|
+
* as a lookup, not a vague query.
|
|
63
|
+
*/
|
|
64
|
+
export function classifyIntent(query) {
|
|
65
|
+
const q = query.trim();
|
|
66
|
+
if (!q) {
|
|
67
|
+
return { intent: "vague", reason: "empty query", redirect: VAGUE_REDIRECT_TEMPLATE };
|
|
68
|
+
}
|
|
69
|
+
// 1. Lookup patterns win — questions about a specific person/hash/PR are
|
|
70
|
+
// always specific enough to retrieve.
|
|
71
|
+
for (const p of LOOKUP_PATTERNS) {
|
|
72
|
+
if (p.re.test(q))
|
|
73
|
+
return { intent: "lookup", reason: p.reason };
|
|
74
|
+
}
|
|
75
|
+
// 2. Temporal patterns — when-questions and date references.
|
|
76
|
+
for (const p of TEMPORAL_PATTERNS) {
|
|
77
|
+
if (p.re.test(q))
|
|
78
|
+
return { intent: "temporal", reason: p.reason };
|
|
79
|
+
}
|
|
80
|
+
// 3. Vague patterns — but only fire if the query has NO concrete hint.
|
|
81
|
+
for (const p of VAGUE_PATTERNS) {
|
|
82
|
+
if (p.re.test(q) && !CONCRETE_HINTS.test(q)) {
|
|
83
|
+
return { intent: "vague", reason: p.reason, redirect: VAGUE_REDIRECT_TEMPLATE };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// 4. Specific question patterns.
|
|
87
|
+
for (const p of SPECIFIC_PATTERNS) {
|
|
88
|
+
if (p.re.test(q))
|
|
89
|
+
return { intent: "specific", reason: p.reason };
|
|
90
|
+
}
|
|
91
|
+
// 5. Default: short queries (< 4 words) treated as keyword search → specific;
|
|
92
|
+
// long unstructured queries → vague.
|
|
93
|
+
const wordCount = q.split(/\s+/).length;
|
|
94
|
+
if (wordCount <= 6)
|
|
95
|
+
return { intent: "specific", reason: "short keyword-style query" };
|
|
96
|
+
if (CONCRETE_HINTS.test(q))
|
|
97
|
+
return { intent: "specific", reason: "contains concrete identifier (file, class, PR)" };
|
|
98
|
+
return {
|
|
99
|
+
intent: "vague",
|
|
100
|
+
reason: "long query with no concrete identifier or specific question pattern",
|
|
101
|
+
redirect: VAGUE_REDIRECT_TEMPLATE,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=intent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent.js","sourceRoot":"","sources":["../../src/retrieve/intent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent.test.d.ts","sourceRoot":"","sources":["../../src/retrieve/intent.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { classifyIntent } from "./intent.js";
|
|
3
|
+
describe("classifyIntent — vague queries (the regression we are fixing)", () => {
|
|
4
|
+
it('classifies "how to improve my code" as vague', () => {
|
|
5
|
+
const r = classifyIntent("how to improve my code");
|
|
6
|
+
expect(r.intent).toBe("vague");
|
|
7
|
+
expect(r.redirect).toBeDefined();
|
|
8
|
+
expect(r.redirect).toContain("specific");
|
|
9
|
+
});
|
|
10
|
+
it('classifies "best practice for X" as vague when X is generic', () => {
|
|
11
|
+
expect(classifyIntent("best practice for naming things").intent).toBe("vague");
|
|
12
|
+
expect(classifyIntent("what is a good way to write tests").intent).toBe("vague");
|
|
13
|
+
});
|
|
14
|
+
it('classifies "should I X" as vague (opinion request)', () => {
|
|
15
|
+
expect(classifyIntent("should I refactor this module").intent).toBe("vague");
|
|
16
|
+
});
|
|
17
|
+
it("classifies greetings and smoke tests as vague", () => {
|
|
18
|
+
expect(classifyIntent("hello").intent).toBe("vague");
|
|
19
|
+
expect(classifyIntent("test").intent).toBe("vague");
|
|
20
|
+
expect(classifyIntent("help").intent).toBe("vague");
|
|
21
|
+
});
|
|
22
|
+
it("classifies empty string as vague", () => {
|
|
23
|
+
expect(classifyIntent("").intent).toBe("vague");
|
|
24
|
+
expect(classifyIntent(" ").intent).toBe("vague");
|
|
25
|
+
});
|
|
26
|
+
it("vague results include a redirect message that mentions specific question forms", () => {
|
|
27
|
+
const r = classifyIntent("how to write good code");
|
|
28
|
+
expect(r.redirect).toMatch(/why does/);
|
|
29
|
+
expect(r.redirect).toMatch(/when did/);
|
|
30
|
+
expect(r.redirect).toMatch(/who wrote/);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe("classifyIntent — specific (the happy path)", () => {
|
|
34
|
+
it('classifies "why does X exist?" as specific', () => {
|
|
35
|
+
expect(classifyIntent("why does parseAmount use try/catch?").intent).toBe("specific");
|
|
36
|
+
});
|
|
37
|
+
it('classifies "what does X do?" as specific', () => {
|
|
38
|
+
expect(classifyIntent("what does the OrderQueue worker do?").intent).toBe("specific");
|
|
39
|
+
});
|
|
40
|
+
it('classifies "how does X work?" as specific (behavior question)', () => {
|
|
41
|
+
expect(classifyIntent("how does the auth middleware work?").intent).toBe("specific");
|
|
42
|
+
});
|
|
43
|
+
it("classifies short keyword queries as specific", () => {
|
|
44
|
+
expect(classifyIntent("stripe webhook bigint").intent).toBe("specific");
|
|
45
|
+
expect(classifyIntent("auth jwt").intent).toBe("specific");
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe("classifyIntent — lookup (author / hash / PR queries)", () => {
|
|
49
|
+
it('classifies "who wrote X" as lookup', () => {
|
|
50
|
+
expect(classifyIntent("who wrote the OrderQueue worker?").intent).toBe("lookup");
|
|
51
|
+
expect(classifyIntent("who created src/payment.ts").intent).toBe("lookup");
|
|
52
|
+
});
|
|
53
|
+
it("classifies PR-number references as lookup", () => {
|
|
54
|
+
expect(classifyIntent("PR #482").intent).toBe("lookup");
|
|
55
|
+
expect(classifyIntent("explain pr #1234").intent).toBe("lookup");
|
|
56
|
+
});
|
|
57
|
+
it("classifies commit-hash references as lookup", () => {
|
|
58
|
+
expect(classifyIntent("a1b2c3d4 what did this do").intent).toBe("lookup");
|
|
59
|
+
expect(classifyIntent("abcdef1 changes").intent).toBe("lookup");
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe("classifyIntent — temporal (timeline / date queries)", () => {
|
|
63
|
+
it('classifies "when did X" as temporal', () => {
|
|
64
|
+
expect(classifyIntent("when did we change the auth middleware?").intent).toBe("temporal");
|
|
65
|
+
});
|
|
66
|
+
it('classifies relative-time queries as temporal', () => {
|
|
67
|
+
expect(classifyIntent("what changed last week").intent).toBe("temporal");
|
|
68
|
+
expect(classifyIntent("commits from last month on payment").intent).toBe("temporal");
|
|
69
|
+
});
|
|
70
|
+
it('classifies absolute YYYY-MM dates as temporal', () => {
|
|
71
|
+
expect(classifyIntent("auth changes in 2024-09").intent).toBe("temporal");
|
|
72
|
+
});
|
|
73
|
+
it("classifies superlative-time queries as temporal", () => {
|
|
74
|
+
expect(classifyIntent("latest commit on stripe").intent).toBe("temporal");
|
|
75
|
+
expect(classifyIntent("first time we used JWT").intent).toBe("temporal");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe("classifyIntent — concrete-hint override (vague pattern + concrete identifier)", () => {
|
|
79
|
+
it('"how to refactor src/payment.ts" is specific despite "how to" (has file path)', () => {
|
|
80
|
+
expect(classifyIntent("how to refactor src/payment.ts").intent).toBe("specific");
|
|
81
|
+
});
|
|
82
|
+
it("'best way to call PaymentService' is specific (CamelCase identifier)", () => {
|
|
83
|
+
expect(classifyIntent("best way to call PaymentService").intent).toBe("specific");
|
|
84
|
+
});
|
|
85
|
+
it("'how to use PR #482' is lookup (PR reference takes priority)", () => {
|
|
86
|
+
expect(classifyIntent("how to use PR #482").intent).toBe("lookup");
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe("classifyIntent — every result has a non-empty reason for transparency", () => {
|
|
90
|
+
it("returns a reason string for every intent class", () => {
|
|
91
|
+
const samples = [
|
|
92
|
+
"how to improve",
|
|
93
|
+
"why does X exist",
|
|
94
|
+
"who wrote Y",
|
|
95
|
+
"when did Z change",
|
|
96
|
+
"stripe bigint webhook",
|
|
97
|
+
"",
|
|
98
|
+
];
|
|
99
|
+
for (const q of samples) {
|
|
100
|
+
const r = classifyIntent(q);
|
|
101
|
+
expect(typeof r.reason).toBe("string");
|
|
102
|
+
expect(r.reason.length).toBeGreaterThan(5);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
//# sourceMappingURL=intent.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent.test.js","sourceRoot":"","sources":["../../src/retrieve/intent.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,7 +7,37 @@ export interface SearchOptions {
|
|
|
7
7
|
topK?: number;
|
|
8
8
|
/** Weight for semantic vs lexical (0 = pure lexical, 1 = pure semantic). */
|
|
9
9
|
semanticWeight?: number;
|
|
10
|
+
/**
|
|
11
|
+
* Confidence floor — return [] instead of low-confidence guesses when the
|
|
12
|
+
* query has no real signal in the corpus. Critical for honest "no context
|
|
13
|
+
* found" answers on gibberish/out-of-distribution queries.
|
|
14
|
+
*
|
|
15
|
+
* "auto" (default) — empty if (no FTS hits) AND (top semantic cosine < 0.4)
|
|
16
|
+
* "off" — never filter; return whatever fusion produced
|
|
17
|
+
* { ... } — explicit thresholds
|
|
18
|
+
*/
|
|
19
|
+
confidenceFloor?: "auto" | "off" | {
|
|
20
|
+
minFtsHits: number;
|
|
21
|
+
minSemCosine: number;
|
|
22
|
+
};
|
|
10
23
|
}
|
|
24
|
+
/** Thresholds used when confidenceFloor === "auto". Calibrated from the eval set. */
|
|
25
|
+
export declare const DEFAULT_CONFIDENCE: {
|
|
26
|
+
minFtsHits: number;
|
|
27
|
+
minSemCosine: number;
|
|
28
|
+
};
|
|
29
|
+
/** Confidence label assigned to a result set based on score distribution. */
|
|
30
|
+
export type ConfidenceLabel = "high" | "medium" | "low" | "none";
|
|
31
|
+
/**
|
|
32
|
+
* Adaptive confidence — looks at the score gap between top-1 and top-3 in
|
|
33
|
+
* addition to the absolute top score. Hard thresholds alone are misleading:
|
|
34
|
+
* - "stripe bigint" returns one strong match (top=0.025, second=0.005) → high
|
|
35
|
+
* - "how to improve code" returns 8 ties (all ≈ 0.016) → low
|
|
36
|
+
*
|
|
37
|
+
* Calibrated empirically on the 50-question eval set + the production query
|
|
38
|
+
* "how to improve my code" that exposed the original regression.
|
|
39
|
+
*/
|
|
40
|
+
export declare function classifyConfidence(results: SearchResult[]): ConfidenceLabel;
|
|
11
41
|
/**
|
|
12
42
|
* Hybrid retrieval: combine FTS (BM25) with vector cosine, fuse with weighted RRF.
|
|
13
43
|
* Falls back to FTS-only if no embedder is configured or no embeddings exist.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/retrieve/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAGT,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/retrieve/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EAGT,WAAW,EACX,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;CACjF;AAED,qFAAqF;AACrF,eAAO,MAAM,kBAAkB,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAG1E,CAAC;AAEF,6EAA6E;AAC7E,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEjE;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,eAAe,CAmB3E;AAED;;;GAGG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA6ExF;AAED,wBAAsB,GAAG,CACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,SAAS,CAAC,CAQpB;AAiDD,wBAAgB,MAAM,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAc/D;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,QAAQ,EAAE,EACf,GAAG,EAAE,QAAQ,EAAE,EACf,GAAG,EAAE;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE,KAAK,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAW9C"}
|
package/dist/retrieve/search.js
CHANGED
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
/** Thresholds used when confidenceFloor === "auto". Calibrated from the eval set. */
|
|
2
|
+
export const DEFAULT_CONFIDENCE = {
|
|
3
|
+
minFtsHits: 1,
|
|
4
|
+
minSemCosine: 0.4,
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Adaptive confidence — looks at the score gap between top-1 and top-3 in
|
|
8
|
+
* addition to the absolute top score. Hard thresholds alone are misleading:
|
|
9
|
+
* - "stripe bigint" returns one strong match (top=0.025, second=0.005) → high
|
|
10
|
+
* - "how to improve code" returns 8 ties (all ≈ 0.016) → low
|
|
11
|
+
*
|
|
12
|
+
* Calibrated empirically on the 50-question eval set + the production query
|
|
13
|
+
* "how to improve my code" that exposed the original regression.
|
|
14
|
+
*/
|
|
15
|
+
export function classifyConfidence(results) {
|
|
16
|
+
if (results.length === 0)
|
|
17
|
+
return "none";
|
|
18
|
+
const top = results[0].score;
|
|
19
|
+
// Absolute floor — anything below this is noise regardless of gap.
|
|
20
|
+
if (top < 0.005)
|
|
21
|
+
return "none";
|
|
22
|
+
// Gap-based: if top is much higher than the average of the next 2-4
|
|
23
|
+
// results, the system has a clear winner. If results are tied (small gap),
|
|
24
|
+
// confidence drops even when top is decent.
|
|
25
|
+
const tail = results.slice(1, 5);
|
|
26
|
+
const tailMean = tail.length > 0 ? tail.reduce((s, r) => s + r.score, 0) / tail.length : 0;
|
|
27
|
+
const gap = top - tailMean;
|
|
28
|
+
const ratio = tailMean === 0 ? Infinity : top / tailMean;
|
|
29
|
+
if (top >= 0.025 && (ratio >= 1.4 || gap >= 0.005))
|
|
30
|
+
return "high";
|
|
31
|
+
if (top >= 0.012 && (ratio >= 1.2 || gap >= 0.002))
|
|
32
|
+
return "medium";
|
|
33
|
+
if (top >= 0.005)
|
|
34
|
+
return "low";
|
|
35
|
+
return "none";
|
|
36
|
+
}
|
|
1
37
|
/**
|
|
2
38
|
* Hybrid retrieval: combine FTS (BM25) with vector cosine, fuse with weighted RRF.
|
|
3
39
|
* Falls back to FTS-only if no embedder is configured or no embeddings exist.
|
|
@@ -12,6 +48,7 @@ export async function search(query, opts) {
|
|
|
12
48
|
raw: h.bm25,
|
|
13
49
|
}));
|
|
14
50
|
let semanticScored = [];
|
|
51
|
+
let topSemCosine = 0;
|
|
15
52
|
if (opts.embedder && opts.store.countChunksWithEmbedding() > 0) {
|
|
16
53
|
try {
|
|
17
54
|
const [qvec] = await opts.embedder.embed([query]);
|
|
@@ -31,6 +68,7 @@ export async function search(query, opts) {
|
|
|
31
68
|
});
|
|
32
69
|
}
|
|
33
70
|
sims.sort((a, b) => b.sim - a.sim);
|
|
71
|
+
topSemCosine = sims[0]?.sim ?? 0;
|
|
34
72
|
semanticScored = sims.slice(0, topK * 4).map((s, i) => ({ chunk: s.chunk, rank: i + 1, raw: s.sim }));
|
|
35
73
|
}
|
|
36
74
|
}
|
|
@@ -40,6 +78,16 @@ export async function search(query, opts) {
|
|
|
40
78
|
semanticScored = [];
|
|
41
79
|
}
|
|
42
80
|
}
|
|
81
|
+
// Honest "no context found" — block low-confidence guesses on gibberish queries.
|
|
82
|
+
// This is the difference between an AI tool and a slot machine.
|
|
83
|
+
const floor = opts.confidenceFloor ?? "auto";
|
|
84
|
+
if (floor !== "off") {
|
|
85
|
+
const cfg = floor === "auto" ? DEFAULT_CONFIDENCE : floor;
|
|
86
|
+
const noLex = ftsScored.length < cfg.minFtsHits;
|
|
87
|
+
const noSem = topSemCosine < cfg.minSemCosine;
|
|
88
|
+
if (noLex && noSem)
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
43
91
|
const fused = reciprocalRankFusion(ftsScored, semanticScored, {
|
|
44
92
|
lexicalWeight: 1 - semanticWeight,
|
|
45
93
|
semanticWeight,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/retrieve/search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/retrieve/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { cosine, reciprocalRankFusion } from "./search.js";
|
|
2
|
+
import { cosine, reciprocalRankFusion, search, DEFAULT_CONFIDENCE } from "./search.js";
|
|
3
3
|
const chunk = (id, hash = "h") => ({
|
|
4
4
|
id,
|
|
5
5
|
commitHash: hash,
|
|
@@ -102,4 +102,87 @@ describe("reciprocalRankFusion", () => {
|
|
|
102
102
|
expect(out[0].score).toBeCloseTo(1 / 61, 6);
|
|
103
103
|
});
|
|
104
104
|
});
|
|
105
|
+
function makeStore(opts) {
|
|
106
|
+
const ftsHits = opts.ftsHits ?? [];
|
|
107
|
+
const chunks = opts.embeddedChunks ?? [];
|
|
108
|
+
return {
|
|
109
|
+
ftsSearch: () => ftsHits,
|
|
110
|
+
countChunksWithEmbedding: () => chunks.length,
|
|
111
|
+
iterEmbeddedChunks: function* () { for (const c of chunks)
|
|
112
|
+
yield c; },
|
|
113
|
+
getCommit: (hash) => ({
|
|
114
|
+
hash,
|
|
115
|
+
shortHash: hash.slice(0, 7),
|
|
116
|
+
subject: `commit ${hash}`,
|
|
117
|
+
authorName: "test",
|
|
118
|
+
authorDate: "2024-01-01",
|
|
119
|
+
body: "",
|
|
120
|
+
}),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const fakeEmbedder = (vec) => ({
|
|
124
|
+
name: "fake",
|
|
125
|
+
dimensions: vec.length,
|
|
126
|
+
embed: async (texts) => texts.map(() => vec),
|
|
127
|
+
});
|
|
128
|
+
describe("search — confidence floor", () => {
|
|
129
|
+
it("returns [] for gibberish (no FTS hits + low semantic similarity)", async () => {
|
|
130
|
+
const queryVec = Float32Array.from([1, 0, 0, 0]);
|
|
131
|
+
const orthogonalVec = Float32Array.from([0, 1, 0, 0]); // cosine = 0, well below 0.4
|
|
132
|
+
const store = makeStore({
|
|
133
|
+
ftsHits: [],
|
|
134
|
+
embeddedChunks: [{ id: 1, commitHash: "abc", kind: "subject", text: "x", vec: orthogonalVec }],
|
|
135
|
+
});
|
|
136
|
+
const results = await search("xyzzyplugh meaningless gibberish", {
|
|
137
|
+
store,
|
|
138
|
+
embedder: fakeEmbedder(queryVec),
|
|
139
|
+
});
|
|
140
|
+
expect(results).toEqual([]);
|
|
141
|
+
});
|
|
142
|
+
it("returns results when FTS has hits even if semantic is weak", async () => {
|
|
143
|
+
const queryVec = Float32Array.from([1, 0, 0, 0]);
|
|
144
|
+
const weakSemVec = Float32Array.from([0.2, 0, 0, 0]); // cosine = 1.0 normalized — actually high
|
|
145
|
+
const store = makeStore({
|
|
146
|
+
ftsHits: [{ id: 1, commitHash: "abc", kind: "subject", text: "real match", bm25: 5.0 }],
|
|
147
|
+
embeddedChunks: [{ id: 1, commitHash: "abc", kind: "subject", text: "real match", vec: weakSemVec }],
|
|
148
|
+
});
|
|
149
|
+
const results = await search("real query with token matches", {
|
|
150
|
+
store,
|
|
151
|
+
embedder: fakeEmbedder(queryVec),
|
|
152
|
+
});
|
|
153
|
+
expect(results.length).toBeGreaterThan(0);
|
|
154
|
+
});
|
|
155
|
+
it("returns results when semantic is strong even if FTS is empty", async () => {
|
|
156
|
+
const queryVec = Float32Array.from([1, 0, 0, 0]);
|
|
157
|
+
const strongSemVec = Float32Array.from([0.95, 0.05, 0, 0]); // cosine ≈ 0.998
|
|
158
|
+
const store = makeStore({
|
|
159
|
+
ftsHits: [],
|
|
160
|
+
embeddedChunks: [{ id: 1, commitHash: "abc", kind: "subject", text: "semantically related", vec: strongSemVec }],
|
|
161
|
+
});
|
|
162
|
+
const results = await search("paraphrased query", {
|
|
163
|
+
store,
|
|
164
|
+
embedder: fakeEmbedder(queryVec),
|
|
165
|
+
});
|
|
166
|
+
expect(results.length).toBeGreaterThan(0);
|
|
167
|
+
});
|
|
168
|
+
it('confidenceFloor: "off" disables the filter (returns whatever fusion produced)', async () => {
|
|
169
|
+
const queryVec = Float32Array.from([1, 0, 0, 0]);
|
|
170
|
+
const orthogonalVec = Float32Array.from([0, 1, 0, 0]);
|
|
171
|
+
const store = makeStore({
|
|
172
|
+
ftsHits: [],
|
|
173
|
+
embeddedChunks: [{ id: 1, commitHash: "abc", kind: "subject", text: "x", vec: orthogonalVec }],
|
|
174
|
+
});
|
|
175
|
+
const results = await search("xyzzyplugh", {
|
|
176
|
+
store,
|
|
177
|
+
embedder: fakeEmbedder(queryVec),
|
|
178
|
+
confidenceFloor: "off",
|
|
179
|
+
});
|
|
180
|
+
// With floor disabled, semantic still produces a (low-quality) hit
|
|
181
|
+
expect(results.length).toBeGreaterThan(0);
|
|
182
|
+
});
|
|
183
|
+
it("DEFAULT_CONFIDENCE thresholds are exposed for tuning", () => {
|
|
184
|
+
expect(DEFAULT_CONFIDENCE.minFtsHits).toBe(1);
|
|
185
|
+
expect(DEFAULT_CONFIDENCE.minSemCosine).toBe(0.4);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
105
188
|
//# sourceMappingURL=search.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.test.js","sourceRoot":"","sources":["../../src/retrieve/search.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"search.test.js","sourceRoot":"","sources":["../../src/retrieve/search.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM synthesis layer — turns retrieval results into a paragraph answer.
|
|
3
|
+
*
|
|
4
|
+
* Without this, `mneme ask` returns a list of commits and lets the user piece
|
|
5
|
+
* together the answer themselves. With this, the answer reads like a brief
|
|
6
|
+
* from a senior dev: "X exists because Y; here are the commits that prove it."
|
|
7
|
+
*
|
|
8
|
+
* The synthesizer is *grounded* — it MUST cite commit hashes and MUST refuse
|
|
9
|
+
* to invent claims not present in the retrieved evidence. The prompt enforces
|
|
10
|
+
* this; the temperature is low (0.2). On hallucination risk, we err on the
|
|
11
|
+
* side of saying "the evidence is mixed" rather than fabricating a thesis.
|
|
12
|
+
*
|
|
13
|
+
* Falls back to an extractive answer (template over top-3 commits) when no
|
|
14
|
+
* LLM is reachable. The extractive path is itself good enough for most
|
|
15
|
+
* keyword queries — the LLM is the polish.
|
|
16
|
+
*/
|
|
17
|
+
import type { SearchResult } from "../types.js";
|
|
18
|
+
import type { ConfidenceLabel } from "./search.js";
|
|
19
|
+
/**
|
|
20
|
+
* Subset of EnricherProvider needed here. We avoid a hard dependency on
|
|
21
|
+
* @mneme-ai/embeddings to keep core dep-free; callers pass an enricher in.
|
|
22
|
+
*/
|
|
23
|
+
export interface SynthesisEnricher {
|
|
24
|
+
readonly name: string;
|
|
25
|
+
enrich(input: {
|
|
26
|
+
system: string;
|
|
27
|
+
user: string;
|
|
28
|
+
temperature?: number;
|
|
29
|
+
maxTokens?: number;
|
|
30
|
+
}): Promise<{
|
|
31
|
+
text: string;
|
|
32
|
+
}>;
|
|
33
|
+
}
|
|
34
|
+
export interface SynthesizedAnswer {
|
|
35
|
+
/** The paragraph the user reads at the top of `mneme ask` output. */
|
|
36
|
+
answer: string;
|
|
37
|
+
/** Provenance: where the answer came from. */
|
|
38
|
+
source: "llm" | "extractive" | "no-context";
|
|
39
|
+
/** The same confidence label that was passed in (echoed for caller convenience). */
|
|
40
|
+
confidence: ConfidenceLabel;
|
|
41
|
+
/** Hashes of the commits the answer is grounded in. */
|
|
42
|
+
evidenceCommitHashes: string[];
|
|
43
|
+
/** Per-call latency for telemetry / "how slow is this?" calibration. */
|
|
44
|
+
durationMs: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Synthesize an answer from retrieval results.
|
|
48
|
+
*
|
|
49
|
+
* @param question — the user's original query (already classified as 'specific'
|
|
50
|
+
* or 'lookup' by `classifyIntent`).
|
|
51
|
+
* @param results — top-K SearchResult, ordered by score.
|
|
52
|
+
* @param confidence — pre-computed by `classifyConfidence(results)`.
|
|
53
|
+
* @param enricher — optional. If undefined or fails, we fall back to extractive.
|
|
54
|
+
* @param maxResults — how many top results to ground the answer in (default 5).
|
|
55
|
+
*/
|
|
56
|
+
export declare function synthesize(question: string, results: SearchResult[], confidence: ConfidenceLabel, enricher?: SynthesisEnricher, maxResults?: number): Promise<SynthesizedAnswer>;
|
|
57
|
+
//# sourceMappingURL=synthesize.d.ts.map
|