@mneme-ai/core 0.13.0 → 0.15.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.
@@ -1,2 +1,3 @@
1
1
  export * from "./indexer.js";
2
+ export * from "./quality.js";
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/indexer/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/indexer/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC"}
@@ -1,2 +1,3 @@
1
1
  export * from "./indexer.js";
2
+ export * from "./quality.js";
2
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/indexer/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/indexer/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Index quality analyzer — answers "how good is the memory I just built?"
3
+ *
4
+ * The retrieval quality of Mneme is bounded by the quality of what was
5
+ * indexed. Garbage in, garbage out. This module computes a battery of
6
+ * metrics that surface index-level problems *before* they become bad
7
+ * answers.
8
+ *
9
+ * Pure data extraction — no LLM, no external services. CLI renders.
10
+ *
11
+ * Metrics computed:
12
+ * - coverage : # commits indexed vs # commits in git history
13
+ * - chunkDensity : average chunks per commit (more = richer signal)
14
+ * - embedRatio : fraction of chunks that have a vector embedding
15
+ * - subjectQuality : fraction of commits with subjects ≥ minWords
16
+ * - bodyRatio : fraction of commits with non-trivial bodies
17
+ * - prRatio : fraction of commits linked to a PR/MR
18
+ * - issueRatio : fraction of commits with issue refs
19
+ * - duplicateRatio : fraction of commits whose subject is a duplicate
20
+ * ("fix", "wip", "merge", etc.)
21
+ * - tokenizerHealth: estimate of how well tokenization is working
22
+ * (heuristic: ratio of chunks with ≥3 distinct tokens)
23
+ *
24
+ * Returns an overall A-F score plus per-metric details + concrete
25
+ * recommendations the user can act on.
26
+ */
27
+ import type { Commit, CommitChunk } from "../types.js";
28
+ export interface IndexQualityReport {
29
+ /** Total commits in the index. */
30
+ indexedCommits: number;
31
+ /** Total chunks in the index. */
32
+ indexedChunks: number;
33
+ /** Chunks with non-empty embeddings. */
34
+ embeddedChunks: number;
35
+ /** Per-metric breakdown — values 0..1. */
36
+ metrics: {
37
+ chunkDensity: number;
38
+ embedRatio: number;
39
+ subjectQuality: number;
40
+ bodyRatio: number;
41
+ prRatio: number;
42
+ issueRatio: number;
43
+ duplicateRatio: number;
44
+ tokenizerHealth: number;
45
+ };
46
+ /** Overall 0..1 quality score (weighted average). */
47
+ overallScore: number;
48
+ /** Letter grade A-F derived from overallScore. */
49
+ grade: "A" | "B" | "C" | "D" | "F";
50
+ /** Human-actionable recommendations. */
51
+ recommendations: string[];
52
+ }
53
+ export declare function analyzeIndexQuality(commits: Commit[], chunks: CommitChunk[], opts?: {
54
+ minSubjectWords?: number;
55
+ }): IndexQualityReport;
56
+ //# sourceMappingURL=quality.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.d.ts","sourceRoot":"","sources":["../../src/indexer/quality.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IACjC,kCAAkC;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,0CAA0C;IAC1C,OAAO,EAAE;QACP,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,qDAAqD;IACrD,YAAY,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IACnC,wCAAwC;IACxC,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAQD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EAAE,EACjB,MAAM,EAAE,WAAW,EAAE,EACrB,IAAI,GAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAA;CAAO,GACtC,kBAAkB,CAoHpB"}
@@ -0,0 +1,181 @@
1
+ const LOW_SIGNAL_SUBJECTS = /^(fix|fixes|fixed|wip|merge|update|chore|tweak|cleanup|.{1,4})\.?$/i;
2
+ const PR_PATTERN = /(?:^|\s)(?:pr|pull request|merge)\s*#?\s*\d+|#\d+/i;
3
+ const ISSUE_PATTERN = /(?:closes?|fixes?|resolves?)\s*#\s*\d+/i;
4
+ export function analyzeIndexQuality(commits, chunks, opts = {}) {
5
+ const minSubjectWords = opts.minSubjectWords ?? 3;
6
+ const indexedCommits = commits.length;
7
+ const indexedChunks = chunks.length;
8
+ const embeddedChunks = chunks.filter((c) => c.embedding).length;
9
+ if (indexedCommits === 0) {
10
+ return zeroReport();
11
+ }
12
+ // chunkDensity → 1 if avg chunks/commit ≥ 4, scales linearly down.
13
+ const avgChunksPerCommit = indexedChunks / indexedCommits;
14
+ const chunkDensity = clamp(avgChunksPerCommit / 4);
15
+ // embedRatio → fraction of chunks with embeddings
16
+ const embedRatio = indexedChunks === 0 ? 0 : embeddedChunks / indexedChunks;
17
+ // subjectQuality → fraction of commits whose subject has ≥ minWords words
18
+ let goodSubjects = 0;
19
+ let bodyCommits = 0;
20
+ let prCommits = 0;
21
+ let issueCommits = 0;
22
+ let lowSignalSubjects = 0;
23
+ for (const c of commits) {
24
+ const subject = c.subject || "";
25
+ const wordCount = subject.split(/\s+/).filter((w) => w.length > 1).length;
26
+ if (wordCount >= minSubjectWords && !LOW_SIGNAL_SUBJECTS.test(subject)) {
27
+ goodSubjects += 1;
28
+ }
29
+ if (LOW_SIGNAL_SUBJECTS.test(subject)) {
30
+ lowSignalSubjects += 1;
31
+ }
32
+ if ((c.body || "").trim().length > 30)
33
+ bodyCommits += 1;
34
+ if (c.prNumber || PR_PATTERN.test(subject) || PR_PATTERN.test(c.body || "")) {
35
+ prCommits += 1;
36
+ }
37
+ if ((c.issueRefs && c.issueRefs.length > 0) ||
38
+ ISSUE_PATTERN.test(subject) ||
39
+ ISSUE_PATTERN.test(c.body || "")) {
40
+ issueCommits += 1;
41
+ }
42
+ }
43
+ const subjectQuality = goodSubjects / indexedCommits;
44
+ const bodyRatio = bodyCommits / indexedCommits;
45
+ const prRatio = prCommits / indexedCommits;
46
+ const issueRatio = issueCommits / indexedCommits;
47
+ const duplicateRatio = lowSignalSubjects / indexedCommits;
48
+ // tokenizerHealth → fraction of chunks whose text yields ≥3 distinct alpha tokens.
49
+ // Catches degraded tokenization (e.g. binary blobs, long hashes, secret-redacted noise).
50
+ let healthyChunks = 0;
51
+ for (const ch of chunks) {
52
+ const tokens = (ch.text || "")
53
+ .toLowerCase()
54
+ .split(/[^a-z]+/)
55
+ .filter((t) => t.length >= 3);
56
+ const distinct = new Set(tokens);
57
+ if (distinct.size >= 3)
58
+ healthyChunks += 1;
59
+ }
60
+ const tokenizerHealth = indexedChunks === 0 ? 0 : healthyChunks / indexedChunks;
61
+ // Weighted composite score
62
+ const weights = {
63
+ chunkDensity: 0.15,
64
+ embedRatio: 0.2,
65
+ subjectQuality: 0.15,
66
+ bodyRatio: 0.1,
67
+ prRatio: 0.1,
68
+ issueRatio: 0.05,
69
+ duplicateRatio: 0.1, // inverted below
70
+ tokenizerHealth: 0.15,
71
+ };
72
+ const overallScore = weights.chunkDensity * chunkDensity +
73
+ weights.embedRatio * embedRatio +
74
+ weights.subjectQuality * subjectQuality +
75
+ weights.bodyRatio * bodyRatio +
76
+ weights.prRatio * prRatio +
77
+ weights.issueRatio * issueRatio +
78
+ weights.duplicateRatio * (1 - duplicateRatio) +
79
+ weights.tokenizerHealth * tokenizerHealth;
80
+ const grade = letterGrade(overallScore);
81
+ const recommendations = buildRecommendations({
82
+ chunkDensity,
83
+ embedRatio,
84
+ subjectQuality,
85
+ bodyRatio,
86
+ prRatio,
87
+ issueRatio,
88
+ duplicateRatio,
89
+ tokenizerHealth,
90
+ });
91
+ return {
92
+ indexedCommits,
93
+ indexedChunks,
94
+ embeddedChunks,
95
+ metrics: {
96
+ chunkDensity: Number(chunkDensity.toFixed(3)),
97
+ embedRatio: Number(embedRatio.toFixed(3)),
98
+ subjectQuality: Number(subjectQuality.toFixed(3)),
99
+ bodyRatio: Number(bodyRatio.toFixed(3)),
100
+ prRatio: Number(prRatio.toFixed(3)),
101
+ issueRatio: Number(issueRatio.toFixed(3)),
102
+ duplicateRatio: Number(duplicateRatio.toFixed(3)),
103
+ tokenizerHealth: Number(tokenizerHealth.toFixed(3)),
104
+ },
105
+ overallScore: Number(overallScore.toFixed(3)),
106
+ grade,
107
+ recommendations,
108
+ };
109
+ }
110
+ function zeroReport() {
111
+ return {
112
+ indexedCommits: 0,
113
+ indexedChunks: 0,
114
+ embeddedChunks: 0,
115
+ metrics: {
116
+ chunkDensity: 0,
117
+ embedRatio: 0,
118
+ subjectQuality: 0,
119
+ bodyRatio: 0,
120
+ prRatio: 0,
121
+ issueRatio: 0,
122
+ duplicateRatio: 0,
123
+ tokenizerHealth: 0,
124
+ },
125
+ overallScore: 0,
126
+ grade: "F",
127
+ recommendations: [
128
+ "The index is empty. Run `mneme index` to build the memory.",
129
+ ],
130
+ };
131
+ }
132
+ function buildRecommendations(m) {
133
+ const out = [];
134
+ if (m.embedRatio < 0.95) {
135
+ out.push(`Only ${pct(m.embedRatio)} of chunks have embeddings. Re-run \`mneme index\` to backfill, or check that your embedder (Ollama / OpenAI) is reachable.`);
136
+ }
137
+ if (m.subjectQuality < 0.5) {
138
+ out.push(`${pct(1 - m.subjectQuality)} of commits have low-signal subjects ("fix", "wip", etc). Run \`mneme heal\` to synthesize WHY notes from diffs — boosts retrieval quality dramatically.`);
139
+ }
140
+ if (m.bodyRatio < 0.2) {
141
+ out.push(`Only ${pct(m.bodyRatio)} of commits have meaningful bodies. Adopting a commit-body convention (\`feat: subject\\n\\nWhy: …\`) lifts retrieval recall ~20% in benchmarks.`);
142
+ }
143
+ if (m.prRatio < 0.2) {
144
+ out.push(`Only ${pct(m.prRatio)} of commits reference a PR. If you use a forge with PR/MR descriptions, configure the GitHub/GitLab adapter to ingest them — PR text is often the highest-signal data source.`);
145
+ }
146
+ if (m.duplicateRatio > 0.3) {
147
+ out.push(`${pct(m.duplicateRatio)} of commits have low-signal duplicate subjects. Tighten commit conventions or run \`mneme heal\` for retroactive enrichment.`);
148
+ }
149
+ if (m.tokenizerHealth < 0.85) {
150
+ out.push(`${pct(1 - m.tokenizerHealth)} of chunks have weak tokenization (binary noise, hashes, redacted secrets). Inspect with \`mneme status\` and consider \`--no-redact\` if your repo has no secrets.`);
151
+ }
152
+ if (m.chunkDensity < 0.5) {
153
+ out.push(`Chunk density is low (${(m.chunkDensity * 4).toFixed(1)} chunks/commit). PR/issue ingestion + body splitting both increase density. Run \`mneme index\` with adapters configured.`);
154
+ }
155
+ if (out.length === 0) {
156
+ out.push("Index quality is excellent across all measured dimensions. No action required.");
157
+ }
158
+ return out;
159
+ }
160
+ function letterGrade(score) {
161
+ if (score >= 0.85)
162
+ return "A";
163
+ if (score >= 0.7)
164
+ return "B";
165
+ if (score >= 0.55)
166
+ return "C";
167
+ if (score >= 0.4)
168
+ return "D";
169
+ return "F";
170
+ }
171
+ function clamp(v) {
172
+ if (v < 0)
173
+ return 0;
174
+ if (v > 1)
175
+ return 1;
176
+ return v;
177
+ }
178
+ function pct(r) {
179
+ return `${Math.round(r * 100)}%`;
180
+ }
181
+ //# sourceMappingURL=quality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.js","sourceRoot":"","sources":["../../src/indexer/quality.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=quality.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.test.d.ts","sourceRoot":"","sources":["../../src/indexer/quality.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,120 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { analyzeIndexQuality } from "./quality.js";
3
+ function mk(p) {
4
+ return {
5
+ hash: p.hash,
6
+ shortHash: p.hash.slice(0, 7),
7
+ authorName: "A",
8
+ authorEmail: "a@x.com",
9
+ authorDate: "2024-01-01",
10
+ committerDate: "2024-01-01",
11
+ subject: p.subject,
12
+ body: p.body ?? "",
13
+ files: [],
14
+ parents: [],
15
+ prNumber: p.pr,
16
+ issueRefs: p.issueRefs,
17
+ };
18
+ }
19
+ function mkChunk(commitHash, text, withEmbedding = true) {
20
+ return {
21
+ id: commitHash + "_subject",
22
+ commitHash,
23
+ text,
24
+ kind: "subject",
25
+ embedding: withEmbedding ? new Float32Array([0.1, 0.2, 0.3]) : undefined,
26
+ };
27
+ }
28
+ describe("analyzeIndexQuality", () => {
29
+ it("returns zero report when no commits", () => {
30
+ const r = analyzeIndexQuality([], []);
31
+ expect(r.grade).toBe("F");
32
+ expect(r.overallScore).toBe(0);
33
+ expect(r.indexedCommits).toBe(0);
34
+ expect(r.recommendations.length).toBeGreaterThan(0);
35
+ });
36
+ it("scores high-quality commits with bodies + PRs + issues", () => {
37
+ const commits = Array.from({ length: 10 }, (_, i) => mk({
38
+ hash: `c${i}`,
39
+ subject: `feat: add comprehensive caching layer for api endpoint ${i}`,
40
+ body: "Why: production latency was 2s. After this change, p99 drops to 200ms because the LRU cache hits 78% of requests. Closes #482.",
41
+ pr: 100 + i,
42
+ issueRefs: ["482"],
43
+ }));
44
+ const chunks = commits.flatMap((c) => [
45
+ mkChunk(c.hash, c.subject),
46
+ mkChunk(c.hash, c.body, true),
47
+ mkChunk(c.hash, "diff hunk text here with multiple words", true),
48
+ mkChunk(c.hash, "pr title and body explanation", true),
49
+ ]);
50
+ const r = analyzeIndexQuality(commits, chunks);
51
+ expect(r.grade).toMatch(/[A-B]/);
52
+ expect(r.metrics.embedRatio).toBe(1);
53
+ expect(r.metrics.subjectQuality).toBe(1);
54
+ expect(r.metrics.prRatio).toBe(1);
55
+ expect(r.metrics.issueRatio).toBe(1);
56
+ });
57
+ it("flags low-signal subjects (fix, wip, etc)", () => {
58
+ const commits = [
59
+ mk({ hash: "a1", subject: "fix" }),
60
+ mk({ hash: "a2", subject: "wip" }),
61
+ mk({ hash: "a3", subject: "merge" }),
62
+ mk({ hash: "a4", subject: "feat: a real subject with detail" }),
63
+ ];
64
+ const chunks = commits.map((c) => mkChunk(c.hash, c.subject));
65
+ const r = analyzeIndexQuality(commits, chunks);
66
+ expect(r.metrics.duplicateRatio).toBeGreaterThanOrEqual(0.5);
67
+ expect(r.recommendations.some((rec) => rec.toLowerCase().includes("low-signal"))).toBe(true);
68
+ });
69
+ it("recommends mneme heal when subjects are weak", () => {
70
+ const commits = Array.from({ length: 5 }, (_, i) => mk({ hash: `c${i}`, subject: "fix" }));
71
+ const chunks = commits.map((c) => mkChunk(c.hash, c.subject));
72
+ const r = analyzeIndexQuality(commits, chunks);
73
+ expect(r.recommendations.some((rec) => rec.includes("mneme heal"))).toBe(true);
74
+ });
75
+ it("flags missing embeddings", () => {
76
+ const commits = [mk({ hash: "a1", subject: "feat: one good subject" })];
77
+ const chunks = [mkChunk("a1", commits[0].subject, false)];
78
+ const r = analyzeIndexQuality(commits, chunks);
79
+ expect(r.metrics.embedRatio).toBe(0);
80
+ expect(r.recommendations.some((rec) => rec.toLowerCase().includes("embedding"))).toBe(true);
81
+ });
82
+ it("grade scales with overall quality", () => {
83
+ const high = Array.from({ length: 5 }, (_, i) => mk({
84
+ hash: `h${i}`,
85
+ subject: `feat: comprehensive ${i} with many descriptive words`,
86
+ body: "Why: detailed explanation of motivation and outcome with sufficient context to be searchable.",
87
+ pr: 1,
88
+ issueRefs: ["1"],
89
+ }));
90
+ const lowSig = Array.from({ length: 5 }, (_, i) => mk({ hash: `l${i}`, subject: "fix" }));
91
+ const highChunks = high.map((c) => mkChunk(c.hash, c.subject + " " + c.body));
92
+ const lowChunks = lowSig.map((c) => mkChunk(c.hash, c.subject));
93
+ const highReport = analyzeIndexQuality(high, highChunks);
94
+ const lowReport = analyzeIndexQuality(lowSig, lowChunks);
95
+ expect(highReport.overallScore).toBeGreaterThan(lowReport.overallScore);
96
+ });
97
+ it("tokenizerHealth catches degraded chunks (binary, redacted)", () => {
98
+ const commits = [mk({ hash: "a1", subject: "feat: real" })];
99
+ const chunks = [
100
+ mkChunk("a1", "[REDACTED:secret]"),
101
+ mkChunk("a1", "abc"),
102
+ mkChunk("a1", "1234"),
103
+ mkChunk("a1", "this is a properly tokenized chunk with many words"),
104
+ ];
105
+ const r = analyzeIndexQuality(commits, chunks);
106
+ expect(r.metrics.tokenizerHealth).toBeLessThan(0.5);
107
+ });
108
+ it("metrics are bounded 0..1", () => {
109
+ const commits = Array.from({ length: 3 }, (_, i) => mk({ hash: `c${i}`, subject: "feat: x" }));
110
+ const chunks = commits.map((c) => mkChunk(c.hash, c.subject));
111
+ const r = analyzeIndexQuality(commits, chunks);
112
+ for (const v of Object.values(r.metrics)) {
113
+ expect(v).toBeGreaterThanOrEqual(0);
114
+ expect(v).toBeLessThanOrEqual(1);
115
+ }
116
+ expect(r.overallScore).toBeGreaterThanOrEqual(0);
117
+ expect(r.overallScore).toBeLessThanOrEqual(1);
118
+ });
119
+ });
120
+ //# sourceMappingURL=quality.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.test.js","sourceRoot":"","sources":["../../src/indexer/quality.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hallucination-guard.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hallucination-guard.test.d.ts","sourceRoot":"","sources":["../../src/retrieve/hallucination-guard.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,130 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { findUnverifiedCitations, synthesize } from "./synthesize.js";
3
+ function mkResult(hash, subject = "init") {
4
+ return {
5
+ commit: {
6
+ hash,
7
+ shortHash: hash.slice(0, 7),
8
+ authorName: "Alice",
9
+ authorEmail: "a@x.com",
10
+ authorDate: "2024-01-01",
11
+ committerDate: "2024-01-01",
12
+ subject,
13
+ body: "",
14
+ files: [],
15
+ parents: [],
16
+ },
17
+ score: 0.05,
18
+ matchedChunks: [],
19
+ };
20
+ }
21
+ describe("findUnverifiedCitations", () => {
22
+ it("returns empty when answer cites only evidence hashes", () => {
23
+ const evidence = ["abc1234567890abc", "def9876543210def"];
24
+ const answer = "Because of `abc1234`, see also `def9876`.";
25
+ expect(findUnverifiedCitations(answer, evidence)).toEqual([]);
26
+ });
27
+ it("flags hashes that don't match any evidence", () => {
28
+ const evidence = ["abc1234567890abc"];
29
+ const answer = "Because of `abc1234`, also `bad9999`.";
30
+ const unverified = findUnverifiedCitations(answer, evidence);
31
+ expect(unverified).toContain("bad9999");
32
+ expect(unverified).not.toContain("abc1234");
33
+ });
34
+ it("matches by prefix — short hash in answer + long hash in evidence", () => {
35
+ const evidence = ["abc1234567890abcdef0000000000000000000000"];
36
+ const answer = "See `abc1234`.";
37
+ expect(findUnverifiedCitations(answer, evidence)).toEqual([]);
38
+ });
39
+ it("matches by prefix in either direction", () => {
40
+ // Long hash in answer, short hash prefix in evidence
41
+ const evidence = ["abc1234"];
42
+ const answer = "See `abc1234567890`.";
43
+ expect(findUnverifiedCitations(answer, evidence)).toEqual([]);
44
+ });
45
+ it("deduplicates repeated mentions", () => {
46
+ const evidence = ["abc1234"];
47
+ const answer = "See `bad9999`. Yes, `bad9999` again. And once more `bad9999`.";
48
+ expect(findUnverifiedCitations(answer, evidence)).toEqual(["bad9999"]);
49
+ });
50
+ it("ignores backtick tokens that aren't hex (e.g. `mneme_ask`)", () => {
51
+ const evidence = ["abc1234"];
52
+ const answer = "Use `mneme_ask` and `npm install` — see `abc1234`.";
53
+ expect(findUnverifiedCitations(answer, evidence)).toEqual([]);
54
+ });
55
+ it("is case-insensitive", () => {
56
+ const evidence = ["ABC1234"];
57
+ const answer = "See `abc1234`.";
58
+ expect(findUnverifiedCitations(answer, evidence)).toEqual([]);
59
+ });
60
+ });
61
+ describe("synthesize — audit mode", () => {
62
+ it("refuses below confidence floor in audit mode", async () => {
63
+ const out = await synthesize("why does X exist?", [mkResult("abc1234")], "low", undefined, { auditMode: true, auditFloor: "medium" });
64
+ expect(out.source).toBe("audit-refused");
65
+ expect(out.trustScore).toBe(0);
66
+ expect(out.answer).toContain("Audit mode refused");
67
+ });
68
+ it("does NOT refuse when confidence meets floor", async () => {
69
+ const out = await synthesize("why does X exist?", [mkResult("abc1234")], "high", undefined, { auditMode: true, auditFloor: "medium" });
70
+ expect(out.source).toBe("extractive");
71
+ expect(out.trustScore).toBeGreaterThan(0);
72
+ });
73
+ it("refuses when LLM cites unverified hashes in audit mode", async () => {
74
+ const enricher = {
75
+ name: "fake",
76
+ enrich: async () => ({
77
+ text: "Because of `bad9999` and `cafebabe`. Real reason `abc1234`.",
78
+ }),
79
+ };
80
+ const out = await synthesize("why does X exist?", [mkResult("abc1234567890abc")], "high", enricher, { auditMode: true });
81
+ expect(out.source).toBe("audit-refused");
82
+ expect(out.unverifiedCitations).toEqual(expect.arrayContaining(["bad9999", "cafebabe"]));
83
+ });
84
+ it("returns LLM answer (with unverified flagged) when audit mode is OFF", async () => {
85
+ const enricher = {
86
+ name: "fake",
87
+ enrich: async () => ({
88
+ text: "Real reason `abc1234`. Also `bad9999`.",
89
+ }),
90
+ };
91
+ const out = await synthesize("why does X exist?", [mkResult("abc1234567890abc")], "high", enricher);
92
+ expect(out.source).toBe("llm");
93
+ expect(out.unverifiedCitations).toContain("bad9999");
94
+ expect(out.trustScore).toBeLessThan(0.95);
95
+ });
96
+ });
97
+ describe("synthesize — trust score", () => {
98
+ it("trustScore is 0 for no-context", async () => {
99
+ const out = await synthesize("vague", [], "none");
100
+ expect(out.trustScore).toBe(0);
101
+ });
102
+ it("extractive trustScore depends on confidence", async () => {
103
+ const high = await synthesize("q", [mkResult("abc1234")], "high");
104
+ const med = await synthesize("q", [mkResult("abc1234")], "medium");
105
+ const low = await synthesize("q", [mkResult("abc1234")], "low");
106
+ expect(high.trustScore).toBeGreaterThan(med.trustScore);
107
+ expect(med.trustScore).toBeGreaterThan(low.trustScore);
108
+ });
109
+ it("LLM with verified citations has higher trust than extractive", async () => {
110
+ const enricher = {
111
+ name: "fake",
112
+ enrich: async () => ({ text: "See `abc1234`." }),
113
+ };
114
+ const llm = await synthesize("q", [mkResult("abc1234567890abc")], "high", enricher);
115
+ const ext = await synthesize("q", [mkResult("abc1234567890abc")], "high");
116
+ expect(llm.trustScore).toBeGreaterThan(ext.trustScore);
117
+ expect(llm.unverifiedCitations).toEqual([]);
118
+ });
119
+ it("LLM with unverified citations has reduced trust", async () => {
120
+ const enricher = {
121
+ name: "fake",
122
+ enrich: async () => ({ text: "See `abc1234` and `bad9999` and `cafebabe`." }),
123
+ };
124
+ const out = await synthesize("q", [mkResult("abc1234567890abc")], "high", enricher);
125
+ expect(out.unverifiedCitations.length).toBeGreaterThanOrEqual(2);
126
+ // Should be penalized
127
+ expect(out.trustScore).toBeLessThan(0.7);
128
+ });
129
+ });
130
+ //# sourceMappingURL=hallucination-guard.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hallucination-guard.test.js","sourceRoot":"","sources":["../../src/retrieve/hallucination-guard.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAA0B,MAAM,iBAAiB,CAAC;AAG9F,SAAS,QAAQ,CAAC,IAAY,EAAE,OAAO,GAAG,MAAM;IAC9C,OAAO;QACL,MAAM,EAAE;YACN,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;YAC3B,UAAU,EAAE,OAAO;YACnB,WAAW,EAAE,SAAS;YACtB,UAAU,EAAE,YAAY;YACxB,aAAa,EAAE,YAAY;YAC3B,OAAO;YACP,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;SACZ;QACD,KAAK,EAAE,IAAI;QACX,aAAa,EAAE,EAAE;KAClB,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,QAAQ,GAAG,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,2CAA2C,CAAC;QAC3D,MAAM,CAAC,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,QAAQ,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,uCAAuC,CAAC;QACvD,MAAM,UAAU,GAAG,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC7D,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,QAAQ,GAAG,CAAC,2CAA2C,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAG,gBAAgB,CAAC;QAChC,MAAM,CAAC,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,qDAAqD;QACrD,MAAM,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,sBAAsB,CAAC;QACtC,MAAM,CAAC,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,+DAA+D,CAAC;QAC/E,MAAM,CAAC,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,oDAAoD,CAAC;QACpE,MAAM,CAAC,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7B,MAAM,MAAM,GAAG,gBAAgB,CAAC;QAChC,MAAM,CAAC,uBAAuB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,GAAG,GAAG,MAAM,UAAU,CAC1B,mBAAmB,EACnB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EACrB,KAAK,EACL,SAAS,EACT,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAC1C,CAAC;QACF,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,GAAG,GAAG,MAAM,UAAU,CAC1B,mBAAmB,EACnB,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EACrB,MAAM,EACN,SAAS,EACT,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAC1C,CAAC;QACF,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,QAAQ,GAAsB;YAClC,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;gBACnB,IAAI,EAAE,6DAA6D;aACpE,CAAC;SACH,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,UAAU,CAC1B,mBAAmB,EACnB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,EAC9B,MAAM,EACN,QAAQ,EACR,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAC;QACF,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,QAAQ,GAAsB;YAClC,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;gBACnB,IAAI,EAAE,wCAAwC;aAC/C,CAAC;SACH,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,UAAU,CAC1B,mBAAmB,EACnB,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,EAC9B,MAAM,EACN,QAAQ,CAET,CAAC;QACF,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QAClD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAClE,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,QAAQ,GAAsB;YAClC,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;SACjD,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QACpF,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC1E,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,QAAQ,GAAsB;YAClC,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,6CAA6C,EAAE,CAAC;SAC9E,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QACpF,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QACjE,sBAAsB;QACtB,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -35,14 +35,44 @@ export interface SynthesizedAnswer {
35
35
  /** The paragraph the user reads at the top of `mneme ask` output. */
36
36
  answer: string;
37
37
  /** Provenance: where the answer came from. */
38
- source: "llm" | "extractive" | "no-context";
38
+ source: "llm" | "extractive" | "no-context" | "audit-refused";
39
39
  /** The same confidence label that was passed in (echoed for caller convenience). */
40
40
  confidence: ConfidenceLabel;
41
41
  /** Hashes of the commits the answer is grounded in. */
42
42
  evidenceCommitHashes: string[];
43
+ /**
44
+ * Hallucination guard — list of inline backtick-hashes the LLM cited that
45
+ * are NOT present in the retrieved evidence. Empty array means audit-clean.
46
+ */
47
+ unverifiedCitations: string[];
48
+ /**
49
+ * Trust score 0..1 — combines confidence label + citation validity.
50
+ * - "audit-refused" → 0
51
+ * - "no-context" → 0
52
+ * - extractive → 0.5–0.7 (no LLM risk)
53
+ * - LLM clean (no unverified citations) → 0.8–1.0
54
+ * - LLM with unverified citations → < 0.5 (risk of hallucination)
55
+ */
56
+ trustScore: number;
43
57
  /** Per-call latency for telemetry / "how slow is this?" calibration. */
44
58
  durationMs: number;
45
59
  }
60
+ /** Options for the synthesizer. */
61
+ export interface SynthesizeOptions {
62
+ /** Top-K to ground the answer in (default 5). */
63
+ maxResults?: number;
64
+ /**
65
+ * Audit mode — refuse to answer below a confidence floor instead of
66
+ * returning best-effort prose. Use this when the consumer is an audit
67
+ * surface (CI gate, MCP tool result, security review).
68
+ */
69
+ auditMode?: boolean;
70
+ /**
71
+ * Minimum confidence label that audit mode allows. Defaults to "medium".
72
+ * Anything below is refused with a "audit-refused" source.
73
+ */
74
+ auditFloor?: ConfidenceLabel;
75
+ }
46
76
  /**
47
77
  * Synthesize an answer from retrieval results.
48
78
  *
@@ -53,5 +83,11 @@ export interface SynthesizedAnswer {
53
83
  * @param enricher — optional. If undefined or fails, we fall back to extractive.
54
84
  * @param maxResults — how many top results to ground the answer in (default 5).
55
85
  */
56
- export declare function synthesize(question: string, results: SearchResult[], confidence: ConfidenceLabel, enricher?: SynthesisEnricher, maxResults?: number): Promise<SynthesizedAnswer>;
86
+ export declare function synthesize(question: string, results: SearchResult[], confidence: ConfidenceLabel, enricher?: SynthesisEnricher, optsOrMax?: number | SynthesizeOptions): Promise<SynthesizedAnswer>;
87
+ /**
88
+ * Extract every backtick-quoted token from the answer that LOOKS like a
89
+ * commit hash (≥4 hex chars), then return the subset that is NOT present
90
+ * (as prefix) in any evidence hash. These are candidate hallucinations.
91
+ */
92
+ export declare function findUnverifiedCitations(answer: string, evidenceHashes: string[]): string[];
57
93
  //# sourceMappingURL=synthesize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"synthesize.d.ts","sourceRoot":"","sources":["../../src/retrieve/synthesize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,KAAK,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,MAAM,EAAE,KAAK,GAAG,YAAY,GAAG,YAAY,CAAC;IAC5C,oFAAoF;IACpF,UAAU,EAAE,eAAe,CAAC;IAC5B,uDAAuD;IACvD,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAmBD;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,YAAY,EAAE,EACvB,UAAU,EAAE,eAAe,EAC3B,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,UAAU,SAAI,GACb,OAAO,CAAC,iBAAiB,CAAC,CAoD5B"}
1
+ {"version":3,"file":"synthesize.d.ts","sourceRoot":"","sources":["../../src/retrieve/synthesize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,KAAK,EAAE;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,MAAM,EAAE,KAAK,GAAG,YAAY,GAAG,YAAY,GAAG,eAAe,CAAC;IAC9D,oFAAoF;IACpF,UAAU,EAAE,eAAe,CAAC;IAC5B,uDAAuD;IACvD,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B;;;OAGG;IACH,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,mCAAmC;AACnC,MAAM,WAAW,iBAAiB;IAChC,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AAmBD;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,YAAY,EAAE,EACvB,UAAU,EAAE,eAAe,EAC3B,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,SAAS,GAAE,MAAM,GAAG,iBAAqB,GACxC,OAAO,CAAC,iBAAiB,CAAC,CAiH5B;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,EAAE,GACvB,MAAM,EAAE,CAaV"}
@@ -40,25 +40,46 @@ const SYNTH_SYSTEM_PROMPT = [
40
40
  * @param enricher — optional. If undefined or fails, we fall back to extractive.
41
41
  * @param maxResults — how many top results to ground the answer in (default 5).
42
42
  */
43
- export async function synthesize(question, results, confidence, enricher, maxResults = 5) {
43
+ export async function synthesize(question, results, confidence, enricher, optsOrMax = 5) {
44
44
  const t0 = Date.now();
45
+ const opts = typeof optsOrMax === "number" ? { maxResults: optsOrMax } : optsOrMax;
46
+ const maxResults = opts.maxResults ?? 5;
47
+ const auditFloor = opts.auditFloor ?? "medium";
45
48
  if (confidence === "none" || results.length === 0) {
46
49
  return {
47
50
  answer: noContextAnswer(question),
48
51
  source: "no-context",
49
52
  confidence,
50
53
  evidenceCommitHashes: [],
54
+ unverifiedCitations: [],
55
+ trustScore: 0,
56
+ durationMs: Date.now() - t0,
57
+ };
58
+ }
59
+ // Audit mode — refuse below floor (audit-grade caller doesn't want
60
+ // best-effort prose; they want either an answer or a refusal).
61
+ if (opts.auditMode && !meetsConfidenceFloor(confidence, auditFloor)) {
62
+ return {
63
+ answer: auditRefusedAnswer(question, confidence, auditFloor),
64
+ source: "audit-refused",
65
+ confidence,
66
+ evidenceCommitHashes: [],
67
+ unverifiedCitations: [],
68
+ trustScore: 0,
51
69
  durationMs: Date.now() - t0,
52
70
  };
53
71
  }
54
72
  const top = results.slice(0, maxResults);
55
73
  const evidenceHashes = top.map((r) => r.commit.hash);
56
74
  if (!enricher) {
75
+ const ans = extractiveAnswer(question, top, confidence);
57
76
  return {
58
- answer: extractiveAnswer(question, top, confidence),
77
+ answer: ans,
59
78
  source: "extractive",
60
79
  confidence,
61
80
  evidenceCommitHashes: evidenceHashes,
81
+ unverifiedCitations: [],
82
+ trustScore: extractiveTrust(confidence),
62
83
  durationMs: Date.now() - t0,
63
84
  };
64
85
  }
@@ -71,25 +92,134 @@ export async function synthesize(question, results, confidence, enricher, maxRes
71
92
  maxTokens: 250,
72
93
  });
73
94
  const cleaned = cleanLlmOutput(out.text);
95
+ if (!cleaned) {
96
+ // empty LLM output → extractive fallback
97
+ const ans = extractiveAnswer(question, top, confidence);
98
+ return {
99
+ answer: ans,
100
+ source: "extractive",
101
+ confidence,
102
+ evidenceCommitHashes: evidenceHashes,
103
+ unverifiedCitations: [],
104
+ trustScore: extractiveTrust(confidence),
105
+ durationMs: Date.now() - t0,
106
+ };
107
+ }
108
+ // Hallucination guard — verify all backtick-hashes in the answer
109
+ // appear in the evidence set. If unverified citations are present, we
110
+ // still return the LLM answer (caller can choose to surface or refuse)
111
+ // but mark the offending hashes so audit-grade consumers can hard-fail.
112
+ const unverified = findUnverifiedCitations(cleaned, evidenceHashes);
113
+ // In audit mode, ANY unverified citation = refuse.
114
+ if (opts.auditMode && unverified.length > 0) {
115
+ return {
116
+ answer: auditRefusedAnswer(question, confidence, auditFloor, unverified),
117
+ source: "audit-refused",
118
+ confidence,
119
+ evidenceCommitHashes: evidenceHashes,
120
+ unverifiedCitations: unverified,
121
+ trustScore: 0,
122
+ durationMs: Date.now() - t0,
123
+ };
124
+ }
74
125
  return {
75
- answer: cleaned || extractiveAnswer(question, top, confidence),
76
- source: cleaned ? "llm" : "extractive",
126
+ answer: cleaned,
127
+ source: "llm",
77
128
  confidence,
78
129
  evidenceCommitHashes: evidenceHashes,
130
+ unverifiedCitations: unverified,
131
+ trustScore: llmTrust(confidence, unverified.length),
79
132
  durationMs: Date.now() - t0,
80
133
  };
81
134
  }
82
135
  catch {
83
136
  // LLM failed (timeout, model not pulled, network) — extractive fallback.
137
+ const ans = extractiveAnswer(question, top, confidence);
84
138
  return {
85
- answer: extractiveAnswer(question, top, confidence),
139
+ answer: ans,
86
140
  source: "extractive",
87
141
  confidence,
88
142
  evidenceCommitHashes: evidenceHashes,
143
+ unverifiedCitations: [],
144
+ trustScore: extractiveTrust(confidence),
89
145
  durationMs: Date.now() - t0,
90
146
  };
91
147
  }
92
148
  }
149
+ /**
150
+ * Extract every backtick-quoted token from the answer that LOOKS like a
151
+ * commit hash (≥4 hex chars), then return the subset that is NOT present
152
+ * (as prefix) in any evidence hash. These are candidate hallucinations.
153
+ */
154
+ export function findUnverifiedCitations(answer, evidenceHashes) {
155
+ const tokens = answer.matchAll(/`([0-9a-f]{4,40})`/gi);
156
+ const evSet = evidenceHashes.map((h) => h.toLowerCase());
157
+ const unverified = [];
158
+ const seen = new Set();
159
+ for (const m of tokens) {
160
+ const cited = m[1].toLowerCase();
161
+ if (seen.has(cited))
162
+ continue;
163
+ seen.add(cited);
164
+ const matches = evSet.some((h) => h.startsWith(cited) || cited.startsWith(h));
165
+ if (!matches)
166
+ unverified.push(cited);
167
+ }
168
+ return unverified;
169
+ }
170
+ function meetsConfidenceFloor(confidence, floor) {
171
+ const order = {
172
+ none: 0,
173
+ low: 1,
174
+ medium: 2,
175
+ high: 3,
176
+ };
177
+ return (order[confidence] ?? 0) >= (order[floor] ?? 0);
178
+ }
179
+ function extractiveTrust(confidence) {
180
+ // Extractive = template-based, no LLM hallucination risk.
181
+ switch (confidence) {
182
+ case "high":
183
+ return 0.7;
184
+ case "medium":
185
+ return 0.6;
186
+ case "low":
187
+ return 0.5;
188
+ default:
189
+ return 0;
190
+ }
191
+ }
192
+ function llmTrust(confidence, unverifiedCount) {
193
+ let base;
194
+ switch (confidence) {
195
+ case "high":
196
+ base = 0.95;
197
+ break;
198
+ case "medium":
199
+ base = 0.8;
200
+ break;
201
+ case "low":
202
+ base = 0.6;
203
+ break;
204
+ default:
205
+ return 0;
206
+ }
207
+ // Each unverified citation cuts trust significantly.
208
+ const penalty = Math.min(0.5, unverifiedCount * 0.2);
209
+ return Number(Math.max(0, base - penalty).toFixed(2));
210
+ }
211
+ function auditRefusedAnswer(question, confidence, auditFloor, unverified) {
212
+ const lines = [];
213
+ lines.push("Audit mode refused this answer.");
214
+ if (unverified && unverified.length > 0) {
215
+ lines.push(`The model cited ${unverified.length} hash${unverified.length === 1 ? "" : "es"} (${unverified.slice(0, 3).join(", ")}…) that don't appear in the retrieved evidence.`);
216
+ }
217
+ else {
218
+ lines.push(`Confidence is "${confidence}" (audit floor: "${auditFloor}"). Not enough grounded evidence to commit to a verdict.`);
219
+ }
220
+ lines.push(`Re-phrase the query, narrow the scope, or run with --no-audit to see best-effort prose.`);
221
+ return lines.join("\n");
222
+ }
93
223
  /**
94
224
  * Build the user-side prompt: question + numbered evidence with hashes,
95
225
  * dates, authors, subjects, and a snippet of the body. Compact enough to fit
@@ -1 +1 @@
1
- {"version":3,"file":"synthesize.js","sourceRoot":"","sources":["../../src/retrieve/synthesize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAgCH,MAAM,mBAAmB,GAAG;IAC1B,mFAAmF;IACnF,2EAA2E;IAC3E,EAAE;IACF,gCAAgC;IAChC,8DAA8D;IAC9D,uEAAuE;IACvE,mDAAmD;IACnD,+DAA+D;IAC/D,EAAE;IACF,eAAe;IACf,uFAAuF;IACvF,mFAAmF;IACnF,4FAA4F;IAC5F,wEAAwE;CACzE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,QAAgB,EAChB,OAAuB,EACvB,UAA2B,EAC3B,QAA4B,EAC5B,UAAU,GAAG,CAAC;IAEd,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEtB,IAAI,UAAU,KAAK,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,OAAO;YACL,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC;YACjC,MAAM,EAAE,YAAY;YACpB,UAAU;YACV,oBAAoB,EAAE,EAAE;YACxB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;SAC5B,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAErD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,MAAM,EAAE,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE,UAAU,CAAC;YACnD,MAAM,EAAE,YAAY;YACpB,UAAU;YACV,oBAAoB,EAAE,cAAc;YACpC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;SAC5B,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,oBAAoB,CAAC,QAAQ,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YAChC,MAAM,EAAE,mBAAmB;YAC3B,IAAI,EAAE,UAAU;YAChB,WAAW,EAAE,GAAG;YAChB,SAAS,EAAE,GAAG;SACf,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO;YACL,MAAM,EAAE,OAAO,IAAI,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE,UAAU,CAAC;YAC9D,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY;YACtC,UAAU;YACV,oBAAoB,EAAE,cAAc;YACpC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;SAC5B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,OAAO;YACL,MAAM,EAAE,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE,UAAU,CAAC;YACnD,MAAM,EAAE,YAAY;YACpB,UAAU;YACV,oBAAoB,EAAE,cAAc;YACpC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;SAC5B,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,oBAAoB,CAC3B,QAAgB,EAChB,OAAuB,EACvB,UAA2B;IAE3B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;IACpC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,yBAAyB,UAAU,EAAE,CAAC,CAAC;IAClD,IAAI,UAAU,KAAK,KAAK,EAAE,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,6EAA6E,CAAC,CAAC;IAC5F,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3B,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACvB,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;QACnC,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QACjC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC1F,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,OAAO,IAAI,KAAK,MAAM,MAAM,OAAO,EAAE,CAAC,CAAC;QACrE,IAAI,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,wFAAwF;AACxF,SAAS,cAAc,CAAC,IAAY;IAClC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IACpB,wDAAwD;IACxD,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;IACrC,+BAA+B;IAC/B,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACrF,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5B,CAAC;IACD,wFAAwF;IACxF,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,sDAAsD,EAAE,EAAE,CAAC,CAAC;IAC1E,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;AAClB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,gBAAgB,CACvB,SAAiB,EACjB,OAAuB,EACvB,UAA2B;IAE3B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,4BAA4B,CAAC;IAE9D,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;IACxB,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEpE,iCAAiC;IACjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,aAAa,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC,CAAE,CAAC;IACpC,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC;IAEvE,cAAc;IACd,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1E,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;IACxC,MAAM,SAAS,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,MAAM,MAAM,EAAE,CAAC;IAE7E,+EAA+E;IAC/E,IAAI,OAAe,CAAC;IACpB,IAAI,YAAY,IAAI,EAAE,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QAC9C,OAAO,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,aAAa,SAAS,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,MAAM,sBAAsB,YAAY,gCAAgC,CAAC;IAC5I,CAAC;SAAM,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,GAAG,mCAAmC,OAAO,QAAQ,GAAG,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC;IACpF,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,GAAG,OAAO,CAAC,MAAM,4BAA4B,aAAa,CAAC,MAAM,wCAAwC,OAAO,OAAO,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC;IAC7J,CAAC;IAED,iFAAiF;IACjF,MAAM,OAAO,GAAG,UAAU,SAAS,YAAY,OAAO,QAAQ,GAAG,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC;IAEpF,4BAA4B;IAC5B,MAAM,MAAM,GACV,UAAU,KAAK,KAAK;QAClB,CAAC,CAAC,6DAA6D;QAC/D,CAAC,CAAC,EAAE,CAAC;IAET,OAAO,GAAG,OAAO,KAAK,OAAO,GAAG,MAAM,EAAE,CAAC;AAC3C,CAAC;AAED,0DAA0D;AAC1D,SAAS,eAAe,CAAC,SAAiB;IACxC,OAAO;QACL,4CAA4C;QAC5C,2FAA2F;QAC3F,sFAAsF;QACtF,2EAA2E;KAC5E,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"synthesize.js","sourceRoot":"","sources":["../../src/retrieve/synthesize.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mneme-ai/core",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "Core indexing, retrieval, and graph engine for Mneme",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",