veriquote 0.1.1

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.
Files changed (49) hide show
  1. package/CITATION.cff +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +223 -0
  4. package/dist/index.d.ts +20 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +20 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/judge/chat-judge.d.ts +53 -0
  9. package/dist/judge/chat-judge.d.ts.map +1 -0
  10. package/dist/judge/chat-judge.js +205 -0
  11. package/dist/judge/chat-judge.js.map +1 -0
  12. package/dist/judge/json-extract.d.ts +21 -0
  13. package/dist/judge/json-extract.d.ts.map +1 -0
  14. package/dist/judge/json-extract.js +117 -0
  15. package/dist/judge/json-extract.js.map +1 -0
  16. package/dist/match/fuzzy.d.ts +46 -0
  17. package/dist/match/fuzzy.d.ts.map +1 -0
  18. package/dist/match/fuzzy.js +210 -0
  19. package/dist/match/fuzzy.js.map +1 -0
  20. package/dist/match/normalize.d.ts +26 -0
  21. package/dist/match/normalize.d.ts.map +1 -0
  22. package/dist/match/normalize.js +0 -0
  23. package/dist/match/normalize.js.map +1 -0
  24. package/dist/protocol/evi1.d.ts +51 -0
  25. package/dist/protocol/evi1.d.ts.map +1 -0
  26. package/dist/protocol/evi1.js +179 -0
  27. package/dist/protocol/evi1.js.map +1 -0
  28. package/dist/protocol/prompt.d.ts +18 -0
  29. package/dist/protocol/prompt.d.ts.map +1 -0
  30. package/dist/protocol/prompt.js +82 -0
  31. package/dist/protocol/prompt.js.map +1 -0
  32. package/dist/report.d.ts +24 -0
  33. package/dist/report.d.ts.map +1 -0
  34. package/dist/report.js +106 -0
  35. package/dist/report.js.map +1 -0
  36. package/dist/types.d.ts +141 -0
  37. package/dist/types.d.ts.map +1 -0
  38. package/dist/types.js +5 -0
  39. package/dist/types.js.map +1 -0
  40. package/package.json +54 -0
  41. package/src/index.ts +45 -0
  42. package/src/judge/chat-judge.ts +258 -0
  43. package/src/judge/json-extract.ts +103 -0
  44. package/src/match/fuzzy.ts +253 -0
  45. package/src/match/normalize.ts +0 -0
  46. package/src/protocol/evi1.ts +206 -0
  47. package/src/protocol/prompt.ts +99 -0
  48. package/src/report.ts +152 -0
  49. package/src/types.ts +156 -0
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Tolerant JSON recovery for LLM output. Small models occasionally emit
3
+ * truncated or slightly broken top-level JSON; these helpers recover as many
4
+ * well-formed item objects as possible without ever evaluating code.
5
+ */
6
+ /** Return the first balanced `{...}` object in `s`, or `null`. String-aware. */
7
+ export function extractFirstJsonObject(s) {
8
+ let depth = 0;
9
+ let start = -1;
10
+ let inString = false;
11
+ let escaped = false;
12
+ for (let i = 0; i < s.length; i++) {
13
+ const c = s[i];
14
+ if (start === -1) {
15
+ if (c === '{') {
16
+ start = i;
17
+ depth = 1;
18
+ }
19
+ continue;
20
+ }
21
+ if (inString) {
22
+ if (escaped)
23
+ escaped = false;
24
+ else if (c === '\\')
25
+ escaped = true;
26
+ else if (c === '"')
27
+ inString = false;
28
+ continue;
29
+ }
30
+ if (c === '"')
31
+ inString = true;
32
+ else if (c === '{')
33
+ depth++;
34
+ else if (c === '}' && --depth === 0)
35
+ return s.slice(start, i + 1);
36
+ }
37
+ return null;
38
+ }
39
+ /**
40
+ * Return the raw `[...]` array value of `"key"` in possibly-broken JSON text.
41
+ * Falls back to the unterminated tail when the closing bracket is missing.
42
+ */
43
+ export function extractArrayByKey(raw, key) {
44
+ const pos = raw.indexOf(`"${key}"`);
45
+ if (pos === -1)
46
+ return null;
47
+ const lb = raw.indexOf('[', pos);
48
+ if (lb === -1)
49
+ return null;
50
+ let depth = 0;
51
+ let inString = false;
52
+ let escaped = false;
53
+ for (let i = lb; i < raw.length; i++) {
54
+ const c = raw[i];
55
+ if (inString) {
56
+ if (escaped)
57
+ escaped = false;
58
+ else if (c === '\\')
59
+ escaped = true;
60
+ else if (c === '"')
61
+ inString = false;
62
+ continue;
63
+ }
64
+ if (c === '"')
65
+ inString = true;
66
+ else if (c === '[')
67
+ depth++;
68
+ else if (c === ']' && --depth === 0)
69
+ return raw.slice(lb, i + 1);
70
+ }
71
+ return raw.slice(lb); // unterminated array: tolerate the tail
72
+ }
73
+ /** Extract every balanced top-level `{...}` object, skipping junk in between. */
74
+ export function extractAllJsonObjects(s) {
75
+ const out = [];
76
+ let rest = s;
77
+ for (;;) {
78
+ const obj = extractFirstJsonObject(rest);
79
+ if (obj === null)
80
+ return out;
81
+ out.push(obj);
82
+ rest = rest.slice(rest.indexOf(obj) + obj.length);
83
+ }
84
+ }
85
+ /**
86
+ * Parse `content` (raw LLM output) into an array of item objects.
87
+ * Tries strict parsing of the first JSON object first, then recovers
88
+ * individual items from the `items` array of broken JSON.
89
+ */
90
+ export function parseItemsArray(content, key = 'items') {
91
+ const objStr = extractFirstJsonObject(content);
92
+ if (objStr) {
93
+ try {
94
+ const parsed = JSON.parse(objStr);
95
+ const items = parsed?.[key];
96
+ if (Array.isArray(items))
97
+ return items;
98
+ }
99
+ catch {
100
+ // fall through to tolerant recovery
101
+ }
102
+ }
103
+ const arrStr = extractArrayByKey(content, key);
104
+ if (!arrStr)
105
+ return [];
106
+ const recovered = [];
107
+ for (const one of extractAllJsonObjects(arrStr)) {
108
+ try {
109
+ recovered.push(JSON.parse(one));
110
+ }
111
+ catch {
112
+ // skip the individual broken item
113
+ }
114
+ }
115
+ return recovered;
116
+ }
117
+ //# sourceMappingURL=json-extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-extract.js","sourceRoot":"","sources":["../../src/judge/json-extract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Deterministic fuzzy quote matching.
3
+ *
4
+ * Strategy, in order of preference:
5
+ * 1. exact raw substring,
6
+ * 2. exact substring after normalization (quotes, dashes, case, whitespace),
7
+ * 3. best sliding window by character-trigram Dice similarity, with a
8
+ * coarse scan followed by a fine refinement around the best offset.
9
+ *
10
+ * Everything here is pure and deterministic: same inputs, same result.
11
+ */
12
+ import type { QuoteMatch, SourceDocument } from '../types.js';
13
+ export interface MatchOptions {
14
+ /** Source fields shorter than this are skipped (too little signal). Default 40. */
15
+ minSourceLength?: number;
16
+ /**
17
+ * Quotes shorter than this get a proportional score penalty, because short
18
+ * strings produce spuriously high trigram similarity. Default 90.
19
+ */
20
+ shortQuoteLength?: number;
21
+ /** Fuzzy score below this yields method `"not_found"`. Default 0.4. */
22
+ fuzzyThreshold?: number;
23
+ /** Window sizes to try, as multiples of the quote length. Default [0.85, 1, 1.15]. */
24
+ windowScales?: number[];
25
+ }
26
+ /** Multiset of character trigrams of `s` as gram -> count. */
27
+ export declare function trigramCounts(s: string): Map<string, number>;
28
+ /** Sørensen–Dice similarity between two trigram multisets. */
29
+ export declare function diceSimilarity(a: Map<string, number>, b: Map<string, number>): number;
30
+ interface WindowHit {
31
+ score: number;
32
+ /** Start offset in the scanned text; -1 when nothing scored above 0. */
33
+ offset: number;
34
+ windowLength: number;
35
+ }
36
+ /** Best fuzzy window of `text` for `quote` (both already normalized). */
37
+ export declare function bestFuzzyWindow(quote: string, text: string, scales: number[]): WindowHit;
38
+ /** Match `quote` against a single text field. Offsets refer to `text` as given. */
39
+ export declare function matchQuoteAgainstText(quote: string, text: string, options?: MatchOptions): QuoteMatch;
40
+ /**
41
+ * Match `quote` against all text fields of a source document and return the
42
+ * best result. Stops early on the first perfect hit.
43
+ */
44
+ export declare function matchQuoteAgainstSource(quote: string, source: SourceDocument, options?: MatchOptions): QuoteMatch;
45
+ export {};
46
+ //# sourceMappingURL=fuzzy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzzy.d.ts","sourceRoot":"","sources":["../../src/match/fuzzy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG9D,MAAM,WAAW,YAAY;IAC3B,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AASD,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAO5D;AAED,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAarF;AAED,UAAU,SAAS;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAsED,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CA4BxF;AAED,mFAAmF;AACnF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,YAAY,GACrB,UAAU,CA8CZ;AAUD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,cAAc,EACtB,OAAO,CAAC,EAAE,YAAY,GACrB,UAAU,CAeZ"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Deterministic fuzzy quote matching.
3
+ *
4
+ * Strategy, in order of preference:
5
+ * 1. exact raw substring,
6
+ * 2. exact substring after normalization (quotes, dashes, case, whitespace),
7
+ * 3. best sliding window by character-trigram Dice similarity, with a
8
+ * coarse scan followed by a fine refinement around the best offset.
9
+ *
10
+ * Everything here is pure and deterministic: same inputs, same result.
11
+ */
12
+ import { normalizeForMatch } from './normalize.js';
13
+ const DEFAULTS = {
14
+ minSourceLength: 40,
15
+ shortQuoteLength: 90,
16
+ fuzzyThreshold: 0.4,
17
+ windowScales: [0.85, 1, 1.15],
18
+ };
19
+ /** Multiset of character trigrams of `s` as gram -> count. */
20
+ export function trigramCounts(s) {
21
+ const out = new Map();
22
+ for (let i = 0; i + 3 <= s.length; i++) {
23
+ const g = s.slice(i, i + 3);
24
+ out.set(g, (out.get(g) ?? 0) + 1);
25
+ }
26
+ return out;
27
+ }
28
+ /** Sørensen–Dice similarity between two trigram multisets. */
29
+ export function diceSimilarity(a, b) {
30
+ let aTotal = 0;
31
+ let bTotal = 0;
32
+ for (const v of a.values())
33
+ aTotal += v;
34
+ for (const v of b.values())
35
+ bTotal += v;
36
+ if (!aTotal || !bTotal)
37
+ return 0;
38
+ let inter = 0;
39
+ const [small, large] = a.size <= b.size ? [a, b] : [b, a];
40
+ for (const [g, v] of small) {
41
+ const w = large.get(g);
42
+ if (w)
43
+ inter += Math.min(v, w);
44
+ }
45
+ return (2 * inter) / (aTotal + bTotal);
46
+ }
47
+ /**
48
+ * Rolling-window Dice scan: slides a window of `windowLength` over `text` in
49
+ * steps of `step`, keeping trigram counts and the multiset intersection with
50
+ * the quote incrementally updated — O(text length) per window size instead of
51
+ * O(text length x window length).
52
+ */
53
+ function scanWindows(quoteGrams, quoteTotal, text, windowLength, step, from, to) {
54
+ const best = { score: 0, offset: -1, windowLength };
55
+ if (quoteTotal === 0)
56
+ return best;
57
+ const gramsInWindow = windowLength - 2;
58
+ if (gramsInWindow <= 0 || windowLength > text.length) {
59
+ const d = diceSimilarity(quoteGrams, trigramCounts(text));
60
+ if (d > best.score) {
61
+ best.score = d;
62
+ best.offset = 0;
63
+ best.windowLength = text.length;
64
+ }
65
+ return best;
66
+ }
67
+ const start = Math.max(0, from);
68
+ const end = Math.min(to, text.length - windowLength);
69
+ if (start > end)
70
+ return best;
71
+ // Initialize counts/intersection for the window at `start`.
72
+ const counts = new Map();
73
+ let inter = 0;
74
+ const add = (g) => {
75
+ const c = (counts.get(g) ?? 0) + 1;
76
+ counts.set(g, c);
77
+ if (c <= (quoteGrams.get(g) ?? 0))
78
+ inter++;
79
+ };
80
+ const remove = (g) => {
81
+ const c = (counts.get(g) ?? 1) - 1;
82
+ if (c === 0)
83
+ counts.delete(g);
84
+ else
85
+ counts.set(g, c);
86
+ if (c < (quoteGrams.get(g) ?? 0))
87
+ inter--;
88
+ };
89
+ for (let i = start; i < start + gramsInWindow; i++)
90
+ add(text.slice(i, i + 3));
91
+ const denom = quoteTotal + gramsInWindow;
92
+ for (let pos = start;; pos += step) {
93
+ const d = (2 * inter) / denom;
94
+ if (d > best.score) {
95
+ best.score = d;
96
+ best.offset = pos;
97
+ }
98
+ if (best.score >= 0.995 || pos + step > end)
99
+ break;
100
+ // Slide by `step`: retire grams starting in [pos, pos+step),
101
+ // admit grams starting in [pos+gramsInWindow, pos+gramsInWindow+step).
102
+ for (let i = pos; i < pos + step; i++)
103
+ remove(text.slice(i, i + 3));
104
+ for (let i = pos + gramsInWindow; i < pos + gramsInWindow + step; i++) {
105
+ add(text.slice(i, i + 3));
106
+ }
107
+ }
108
+ return best;
109
+ }
110
+ /** Best fuzzy window of `text` for `quote` (both already normalized). */
111
+ export function bestFuzzyWindow(quote, text, scales) {
112
+ const qLen = quote.length;
113
+ if (!qLen || !text.length)
114
+ return { score: 0, offset: -1, windowLength: 0 };
115
+ const quoteGrams = trigramCounts(quote);
116
+ let quoteTotal = 0;
117
+ for (const v of quoteGrams.values())
118
+ quoteTotal += v;
119
+ const coarseStep = Math.max(10, Math.min(80, Math.round(qLen / 8)));
120
+ let best = { score: 0, offset: -1, windowLength: 0 };
121
+ for (const scale of scales) {
122
+ const w = Math.max(40, Math.round(qLen * scale));
123
+ const hit = scanWindows(quoteGrams, quoteTotal, text, w, coarseStep, 0, text.length);
124
+ if (hit.score > best.score)
125
+ best = hit;
126
+ }
127
+ if (best.offset >= 0 && coarseStep > 1) {
128
+ // Fine pass: re-scan around the coarse optimum with step 1.
129
+ const refined = scanWindows(quoteGrams, quoteTotal, text, best.windowLength, 1, best.offset - coarseStep, best.offset + coarseStep);
130
+ if (refined.score > best.score)
131
+ best = refined;
132
+ }
133
+ return best;
134
+ }
135
+ /** Match `quote` against a single text field. Offsets refer to `text` as given. */
136
+ export function matchQuoteAgainstText(quote, text, options) {
137
+ const opts = { ...DEFAULTS, ...options };
138
+ const quoteRaw = quote.trim();
139
+ const empty = { method: 'not_found', score: 0, field: 'text' };
140
+ if (!quoteRaw || !text)
141
+ return empty;
142
+ const rawIndex = text.indexOf(quoteRaw);
143
+ if (rawIndex !== -1) {
144
+ return {
145
+ method: 'exact',
146
+ score: 1,
147
+ start: rawIndex,
148
+ end: rawIndex + quoteRaw.length,
149
+ field: 'text',
150
+ };
151
+ }
152
+ const q = normalizeForMatch(quoteRaw);
153
+ const t = normalizeForMatch(text);
154
+ if (!q.text || !t.text)
155
+ return empty;
156
+ const normIndex = t.text.indexOf(q.text);
157
+ if (normIndex !== -1) {
158
+ return {
159
+ method: 'normalized',
160
+ score: 1,
161
+ start: t.map[normIndex],
162
+ end: mapEndOffset(t.map, normIndex + q.text.length - 1, text),
163
+ field: 'text',
164
+ };
165
+ }
166
+ const hit = bestFuzzyWindow(q.text, t.text, opts.windowScales);
167
+ const lengthPenalty = Math.min(1, q.text.length / opts.shortQuoteLength);
168
+ const score = Math.max(0, Math.min(0.99, hit.score * lengthPenalty));
169
+ if (hit.offset < 0 || score < opts.fuzzyThreshold) {
170
+ return { ...empty, score };
171
+ }
172
+ const lastNormIndex = Math.min(hit.offset + hit.windowLength - 1, t.map.length - 1);
173
+ return {
174
+ method: 'fuzzy',
175
+ score,
176
+ start: t.map[hit.offset],
177
+ end: mapEndOffset(t.map, lastNormIndex, text),
178
+ field: 'text',
179
+ };
180
+ }
181
+ /** Exclusive end offset in the original text for the normalized char at `lastIndex`. */
182
+ function mapEndOffset(map, lastIndex, original) {
183
+ const srcIndex = map[Math.max(0, Math.min(lastIndex, map.length - 1))];
184
+ // Advance past the full code point at srcIndex.
185
+ const cp = original.codePointAt(srcIndex);
186
+ return srcIndex + (cp !== undefined && cp > 0xffff ? 2 : 1);
187
+ }
188
+ /**
189
+ * Match `quote` against all text fields of a source document and return the
190
+ * best result. Stops early on the first perfect hit.
191
+ */
192
+ export function matchQuoteAgainstSource(quote, source, options) {
193
+ const opts = { ...DEFAULTS, ...options };
194
+ const fields = [
195
+ { name: 'text', text: source.text ?? '' },
196
+ ];
197
+ (source.extraTexts ?? []).forEach((t, i) => fields.push({ name: `extraTexts[${i}]`, text: t }));
198
+ let best = { method: 'not_found', score: 0, field: 'text' };
199
+ for (const field of fields) {
200
+ if (field.text.trim().length < opts.minSourceLength)
201
+ continue;
202
+ const r = matchQuoteAgainstText(quote, field.text, opts);
203
+ if (r.score > best.score)
204
+ best = { ...r, field: field.name };
205
+ if (best.score === 1)
206
+ break;
207
+ }
208
+ return best;
209
+ }
210
+ //# sourceMappingURL=fuzzy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzzy.js","sourceRoot":"","sources":["../../src/match/fuzzy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Unicode/typography normalization with an offset map back to the original
3
+ * string, so fuzzy-match positions can be reported in raw-source coordinates.
4
+ */
5
+ export interface NormalizedText {
6
+ /** Normalized text: NFKC, unified quotes/dashes, case-folded, collapsed whitespace. */
7
+ text: string;
8
+ /** For every char in `text`, the index of the originating char in the input. */
9
+ map: Int32Array;
10
+ }
11
+ /**
12
+ * Normalize `input` for matching while recording, for each output character,
13
+ * the index of the input character it came from.
14
+ *
15
+ * Normalization is applied per code point so the offset map stays exact even
16
+ * when NFKC or case folding expands a character (e.g. ligatures): every
17
+ * expanded output character maps to the same input index.
18
+ */
19
+ export declare function normalizeForMatch(input: string): NormalizedText;
20
+ /** Strip C0/C1 control characters (except `\n` and `\t`) from a string. */
21
+ export declare function stripControlChars(s: string): string;
22
+ /** Remove HTML/XML tags. Used to clean noisy scraped context for the judge. */
23
+ export declare function stripHtmlTags(s: string): string;
24
+ /** Collapse whitespace and trim. */
25
+ export declare function collapseWhitespace(s: string): string;
26
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/match/normalize.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,cAAc;IAC7B,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,GAAG,EAAE,UAAU,CAAC;CACjB;AASD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAoC/D;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,oCAAoC;AACpC,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpD"}
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/match/normalize.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,kDAAkD;AAClD,MAAM,UAAU,GAAG,kCAAkC,CAAC;AACtD,MAAM,aAAa,GAAG,wCAAwC,CAAC;AAC/D,MAAM,aAAa,GAAG,4BAA4B,CAAC;AACnD,qEAAqE;AACrE,MAAM,MAAM,GAAG,uBAAuB,CAAC;AAEvC;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,UAAU,GAAG,KAAK,CAAC;IAEvB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,KAAK,CAAC;QACvB,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC;QAEnB,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,SAAS;QAElC,IAAI,KAAa,CAAC;QAClB,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,KAAK,GAAG,GAAG,CAAC;aACnC,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,KAAK,GAAG,GAAG,CAAC;aACxC,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,KAAK,GAAG,GAAG,CAAC;;YACjC,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAEhD,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;YACvB,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;gBAClB,YAAY,GAAG,UAAU,CAAC,CAAC,yCAAyC;gBACpE,SAAS;YACX,CAAC;YACD,IAAI,YAAY,EAAE,CAAC;gBACjB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACnB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACtB,YAAY,GAAG,KAAK,CAAC;YACvB,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtB,UAAU,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,iBAAiB,CAAC,CAAS;IACzC,4CAA4C;IAC5C,OAAO,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,aAAa,CAAC,CAAS;IACrC,OAAO,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,kBAAkB,CAAC,CAAS;IAC1C,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACvC,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The EVI1 protocol: a plain-text convention that lets an LLM attach
3
+ * verifiable evidence to its answer.
4
+ *
5
+ * In the answer body, every cited sentence ends with citation markers and a
6
+ * claim marker, e.g. `...water expands when freezing.[2][5]{c1}`. After the
7
+ * answer, the model appends:
8
+ *
9
+ * EVI1
10
+ * c1|2|"verbatim quote from source 2"
11
+ * c1|5|"verbatim quote from source 5"
12
+ * END_EVI1
13
+ *
14
+ * Quotes are single-line, with `\n`, `\"` and `\\` escapes.
15
+ */
16
+ import type { Claim, EvidenceItem, ParsedAnswer } from '../types.js';
17
+ export declare const EVI1_START = "EVI1";
18
+ export declare const EVI1_END = "END_EVI1";
19
+ /**
20
+ * Parse the EVI1 appendix of a raw model answer.
21
+ * Returns the evidence items plus warnings for malformed lines;
22
+ * `null` when no complete appendix is present.
23
+ */
24
+ export declare function parseEvi1Appendix(answer: string): {
25
+ items: EvidenceItem[];
26
+ warnings: string[];
27
+ } | null;
28
+ /** Remove the EVI1 appendix from a raw answer; returns the answer body. */
29
+ export declare function stripEvi1Appendix(answer: string): string;
30
+ /** Serialize evidence items into an EVI1 appendix block. */
31
+ export declare function serializeEvi1Appendix(items: EvidenceItem[]): string;
32
+ /**
33
+ * Extract cited claims from an answer body (appendix already stripped).
34
+ *
35
+ * A claim is the text segment ending at a `{cX}` marker, bounded by the start
36
+ * of its line/block or the previous claim marker. Its cited sources are the
37
+ * contiguous `[n]` group immediately preceding the marker, per protocol.
38
+ */
39
+ export declare function extractClaims(body: string): {
40
+ claims: Claim[];
41
+ warnings: string[];
42
+ };
43
+ /** Remove all `{cX}` claim markers from a text. */
44
+ export declare function stripClaimMarkers(text: string): string;
45
+ /**
46
+ * Parse a raw model answer end-to-end: strip the appendix, extract claims and
47
+ * evidence, and cross-check completeness (every cited (claim, source) pair
48
+ * should have exactly one evidence item, and vice versa).
49
+ */
50
+ export declare function parseAnswer(answer: string): ParsedAnswer;
51
+ //# sourceMappingURL=evi1.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evi1.d.ts","sourceRoot":"","sources":["../../src/protocol/evi1.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGrE,eAAO,MAAM,UAAU,SAAS,CAAC;AACjC,eAAO,MAAM,QAAQ,aAAa,CAAC;AAmCnC;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,GACb;IAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAuBtD;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CASxD;AAED,4DAA4D;AAC5D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,CAKnE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAmCnF;AAOD,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAmCxD"}