@mneme-ai/core 0.13.0 → 0.14.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/retrieve/hallucination-guard.test.d.ts +2 -0
- package/dist/retrieve/hallucination-guard.test.d.ts.map +1 -0
- package/dist/retrieve/hallucination-guard.test.js +130 -0
- package/dist/retrieve/hallucination-guard.test.js.map +1 -0
- package/dist/retrieve/synthesize.d.ts +38 -2
- package/dist/retrieve/synthesize.d.ts.map +1 -1
- package/dist/retrieve/synthesize.js +135 -5
- package/dist/retrieve/synthesize.js.map +1 -1
- package/package.json +1 -1
|
@@ -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":"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"}
|
|
@@ -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,
|
|
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;
|
|
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,
|
|
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:
|
|
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
|
|
76
|
-
source:
|
|
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:
|
|
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;
|
|
1
|
+
{"version":3,"file":"synthesize.js","sourceRoot":"","sources":["../../src/retrieve/synthesize.ts"],"names":[],"mappings":"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"}
|