@gmickel/gno 1.19.0 → 1.21.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/README.md +28 -8
- package/assets/skill/SKILL.md +73 -27
- package/assets/skill/mcp-reference.md +7 -2
- package/assets/skill/recipes/citation-and-provenance.md +32 -9
- package/package.json +1 -1
- package/spec/cli.md +142 -17
- package/spec/db/schema.sql +170 -0
- package/spec/evals-agentic.md +87 -5
- package/spec/mcp.md +75 -3
- package/spec/output-schemas/ask.schema.json +198 -0
- package/spec/output-schemas/capsule-reverified-event.schema.json +47 -0
- package/spec/output-schemas/changes.schema.json +280 -0
- package/spec/output-schemas/claim-verification.schema.json +291 -0
- package/spec/output-schemas/context-capsule-v1.schema.json +36 -1
- package/spec/output-schemas/document-diff.schema.json +185 -0
- package/spec/output-schemas/impact.schema.json +122 -0
- package/spec/output-schemas/saved-capsule-list.schema.json +16 -0
- package/spec/output-schemas/saved-capsule-registration.schema.json +172 -0
- package/spec/output-schemas/saved-capsule-reverification.schema.json +59 -0
- package/spec/output-schemas/saved-capsule-unwatch.schema.json +16 -0
- package/spec/output-schemas/saved-capsule-watch.schema.json +17 -0
- package/src/app/context-runtime-contract.ts +10 -5
- package/src/app/context-runtime-input.ts +29 -1
- package/src/app/context-runtime-types.ts +4 -0
- package/src/app/context-runtime.ts +5 -1
- package/src/app/context-surface.ts +4 -0
- package/src/app/verified-ask.ts +291 -0
- package/src/cli/commands/ask-format.ts +255 -0
- package/src/cli/commands/ask.ts +40 -149
- package/src/cli/commands/changes.ts +160 -0
- package/src/cli/commands/context-saved.ts +189 -0
- package/src/cli/options.ts +8 -0
- package/src/cli/program.ts +227 -1
- package/src/core/capsule-registry.ts +279 -0
- package/src/core/capsule-reverification-scheduler.ts +218 -0
- package/src/core/capsule-reverification.ts +289 -0
- package/src/core/change-diff.ts +182 -0
- package/src/core/change-journal.ts +228 -0
- package/src/core/context-budget.ts +6 -0
- package/src/core/context-capsule-retrieval-schema.ts +4 -0
- package/src/core/context-capsule-schema.ts +17 -0
- package/src/core/context-capsule-validation.ts +3 -2
- package/src/core/context-capsule.ts +18 -0
- package/src/core/context-compiler.ts +33 -21
- package/src/core/context-evidence.ts +6 -0
- package/src/core/knowledge-delta.ts +395 -0
- package/src/core/knowledge-impact.ts +202 -0
- package/src/core/retrieval-trace-evidence-origin.ts +3 -0
- package/src/core/retrieval-trace-session.ts +15 -2
- package/src/ingestion/sync.ts +214 -165
- package/src/llm/errors.ts +10 -1
- package/src/llm/httpGeneration.ts +11 -1
- package/src/llm/nodeLlamaCpp/generation.ts +54 -10
- package/src/llm/types.ts +6 -0
- package/src/mcp/tools/ask.ts +228 -0
- package/src/mcp/tools/changes.ts +80 -0
- package/src/mcp/tools/context.ts +28 -7
- package/src/mcp/tools/index.ts +38 -0
- package/src/pipeline/claim-verification-schema.ts +235 -0
- package/src/pipeline/claim-verification.ts +487 -0
- package/src/pipeline/claim-verifier.ts +474 -0
- package/src/pipeline/types.ts +25 -0
- package/src/sdk/client.ts +77 -2
- package/src/sdk/index.ts +7 -0
- package/src/sdk/types.ts +22 -0
- package/src/serve/doc-events.ts +12 -1
- package/src/serve/public/components/AskVerificationPanel.tsx +189 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Ask.tsx +42 -4
- package/src/serve/resident-runtime.ts +22 -0
- package/src/serve/routes/api.ts +162 -3
- package/src/serve/routes/changes.ts +102 -0
- package/src/serve/server.ts +34 -0
- package/src/serve/watch-service.ts +9 -0
- package/src/store/index.ts +21 -0
- package/src/store/migrations/015-document-change-journal.ts +85 -0
- package/src/store/migrations/016-saved-capsules.ts +131 -0
- package/src/store/migrations/017-document-change-retention-counters.ts +33 -0
- package/src/store/migrations/018-saved-capsule-registration-epoch.ts +24 -0
- package/src/store/migrations/019-saved-capsule-registration-generation.ts +53 -0
- package/src/store/migrations/index.ts +10 -0
- package/src/store/sqlite/adapter.ts +291 -7
- package/src/store/sqlite/capsule-registry-store.ts +534 -0
- package/src/store/sqlite/change-journal-store.ts +473 -0
- package/src/store/types.ts +262 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared, storage-agnostic contracts for the document change journal.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
DocumentChangeDateDelta,
|
|
7
|
+
DocumentChangeSet,
|
|
8
|
+
DocumentChangeStructureDelta,
|
|
9
|
+
DocumentChangeRetentionPolicy,
|
|
10
|
+
} from "../store/types";
|
|
11
|
+
|
|
12
|
+
const CURSOR_PREFIX = "gno-change-v1.";
|
|
13
|
+
const MAX_DELTA_ITEMS_PER_SIDE = 16;
|
|
14
|
+
const MAX_DELTA_VALUE_JSON_BYTES = 256;
|
|
15
|
+
export const MAX_DOCUMENT_CHANGE_DELTA_JSON_BYTES = 16 * 1024;
|
|
16
|
+
const UTF8_ENCODER = new TextEncoder();
|
|
17
|
+
|
|
18
|
+
export const DEFAULT_DOCUMENT_CHANGE_RETENTION: DocumentChangeRetentionPolicy =
|
|
19
|
+
{
|
|
20
|
+
maxAgeDays: 30,
|
|
21
|
+
maxEntries: 10_000,
|
|
22
|
+
maxBytes: 16 * 1024 * 1024,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const EMPTY_DOCUMENT_CHANGE_SET: DocumentChangeSet = {
|
|
26
|
+
added: [],
|
|
27
|
+
removed: [],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const EMPTY_DOCUMENT_CHANGE_DATE_DELTA: DocumentChangeDateDelta = {
|
|
31
|
+
added: [],
|
|
32
|
+
removed: [],
|
|
33
|
+
changed: [],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const EMPTY_DOCUMENT_CHANGE_STRUCTURE_DELTA: DocumentChangeStructureDelta =
|
|
37
|
+
{
|
|
38
|
+
headings: EMPTY_DOCUMENT_CHANGE_SET,
|
|
39
|
+
links: EMPTY_DOCUMENT_CHANGE_SET,
|
|
40
|
+
typedEdges: EMPTY_DOCUMENT_CHANGE_SET,
|
|
41
|
+
dates: EMPTY_DOCUMENT_CHANGE_DATE_DELTA,
|
|
42
|
+
truncated: false,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const normalizeValues = (
|
|
46
|
+
values: readonly string[] | undefined
|
|
47
|
+
): { values: string[]; truncated: boolean } => {
|
|
48
|
+
const unique = [
|
|
49
|
+
...new Set(
|
|
50
|
+
(values ?? [])
|
|
51
|
+
.map((value) => value.trim())
|
|
52
|
+
.filter((value) => value.length > 0)
|
|
53
|
+
),
|
|
54
|
+
].sort();
|
|
55
|
+
const selected: string[] = [];
|
|
56
|
+
const selectedValues = new Set<string>();
|
|
57
|
+
let truncated = false;
|
|
58
|
+
for (const value of unique) {
|
|
59
|
+
let normalized = "";
|
|
60
|
+
let jsonByteLength = 0;
|
|
61
|
+
for (const character of value) {
|
|
62
|
+
const escaped = JSON.stringify(character).slice(1, -1);
|
|
63
|
+
const characterBytes = UTF8_ENCODER.encode(escaped).byteLength;
|
|
64
|
+
if (jsonByteLength + characterBytes > MAX_DELTA_VALUE_JSON_BYTES) {
|
|
65
|
+
truncated = true;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
normalized += character;
|
|
69
|
+
jsonByteLength += characterBytes;
|
|
70
|
+
}
|
|
71
|
+
if (normalized !== value) {
|
|
72
|
+
truncated = true;
|
|
73
|
+
}
|
|
74
|
+
if (selectedValues.has(normalized)) {
|
|
75
|
+
truncated = true;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (selected.length === MAX_DELTA_ITEMS_PER_SIDE) {
|
|
79
|
+
truncated = true;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
selected.push(normalized);
|
|
83
|
+
selectedValues.add(normalized);
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
values: selected,
|
|
87
|
+
truncated,
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export interface SerializedDocumentChangeStructureDelta {
|
|
92
|
+
delta: DocumentChangeStructureDelta;
|
|
93
|
+
headingDeltaJson: string;
|
|
94
|
+
linkDeltaJson: string;
|
|
95
|
+
typedEdgeDeltaJson: string;
|
|
96
|
+
dateDeltaJson: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const normalizeSet = (
|
|
100
|
+
value: Partial<DocumentChangeSet> | undefined
|
|
101
|
+
): { value: DocumentChangeSet; truncated: boolean } => {
|
|
102
|
+
const added = normalizeValues(value?.added);
|
|
103
|
+
const removed = normalizeValues(value?.removed);
|
|
104
|
+
return {
|
|
105
|
+
value: { added: added.values, removed: removed.values },
|
|
106
|
+
truncated: added.truncated || removed.truncated,
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const normalizeDates = (
|
|
111
|
+
value: Partial<DocumentChangeDateDelta> | undefined
|
|
112
|
+
): { value: DocumentChangeDateDelta; truncated: boolean } => {
|
|
113
|
+
const added = normalizeValues(value?.added);
|
|
114
|
+
const removed = normalizeValues(value?.removed);
|
|
115
|
+
const changed = normalizeValues(value?.changed);
|
|
116
|
+
return {
|
|
117
|
+
value: {
|
|
118
|
+
added: added.values,
|
|
119
|
+
removed: removed.values,
|
|
120
|
+
changed: changed.values,
|
|
121
|
+
},
|
|
122
|
+
truncated: added.truncated || removed.truncated || changed.truncated,
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const normalizeDocumentChangeStructureDelta = (
|
|
127
|
+
value?: Partial<DocumentChangeStructureDelta>
|
|
128
|
+
): DocumentChangeStructureDelta => {
|
|
129
|
+
const headings = normalizeSet(value?.headings);
|
|
130
|
+
const links = normalizeSet(value?.links);
|
|
131
|
+
const typedEdges = normalizeSet(value?.typedEdges);
|
|
132
|
+
const dates = normalizeDates(value?.dates);
|
|
133
|
+
return {
|
|
134
|
+
headings: headings.value,
|
|
135
|
+
links: links.value,
|
|
136
|
+
typedEdges: typedEdges.value,
|
|
137
|
+
dates: dates.value,
|
|
138
|
+
truncated:
|
|
139
|
+
(value?.truncated ?? false) ||
|
|
140
|
+
headings.truncated ||
|
|
141
|
+
links.truncated ||
|
|
142
|
+
typedEdges.truncated ||
|
|
143
|
+
dates.truncated,
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Canonical storage projection for migration 015's UTF-8 byte constraints.
|
|
149
|
+
* Callers must use this instead of independently stringifying normalized deltas.
|
|
150
|
+
*/
|
|
151
|
+
export const serializeDocumentChangeStructureDelta = (
|
|
152
|
+
value?: Partial<DocumentChangeStructureDelta>
|
|
153
|
+
): SerializedDocumentChangeStructureDelta => {
|
|
154
|
+
const delta = normalizeDocumentChangeStructureDelta(value);
|
|
155
|
+
const serialized = {
|
|
156
|
+
headingDeltaJson: JSON.stringify(delta.headings),
|
|
157
|
+
linkDeltaJson: JSON.stringify(delta.links),
|
|
158
|
+
typedEdgeDeltaJson: JSON.stringify(delta.typedEdges),
|
|
159
|
+
dateDeltaJson: JSON.stringify(delta.dates),
|
|
160
|
+
};
|
|
161
|
+
for (const json of Object.values(serialized)) {
|
|
162
|
+
if (
|
|
163
|
+
UTF8_ENCODER.encode(json).byteLength >
|
|
164
|
+
MAX_DOCUMENT_CHANGE_DELTA_JSON_BYTES
|
|
165
|
+
) {
|
|
166
|
+
throw new RangeError(
|
|
167
|
+
"Normalized document change structure exceeds its UTF-8 storage limit"
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return { delta, ...serialized };
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export const encodeDocumentChangeCursor = (sequence: number): string => {
|
|
175
|
+
if (!Number.isSafeInteger(sequence) || sequence < 0) {
|
|
176
|
+
throw new RangeError(
|
|
177
|
+
"Document change cursor sequence must be non-negative"
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
return `${CURSOR_PREFIX}${btoa(JSON.stringify({ sequence }))}`;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export const decodeDocumentChangeCursor = (cursor: string): number => {
|
|
184
|
+
if (!cursor.startsWith(CURSOR_PREFIX)) {
|
|
185
|
+
throw new TypeError("Invalid document change cursor");
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const parsed: unknown = JSON.parse(
|
|
189
|
+
atob(cursor.slice(CURSOR_PREFIX.length))
|
|
190
|
+
);
|
|
191
|
+
if (
|
|
192
|
+
!parsed ||
|
|
193
|
+
typeof parsed !== "object" ||
|
|
194
|
+
!("sequence" in parsed) ||
|
|
195
|
+
!Number.isSafeInteger(parsed.sequence) ||
|
|
196
|
+
(parsed.sequence as number) < 0
|
|
197
|
+
) {
|
|
198
|
+
throw new TypeError("Invalid document change cursor");
|
|
199
|
+
}
|
|
200
|
+
return parsed.sequence as number;
|
|
201
|
+
} catch (cause) {
|
|
202
|
+
if (cause instanceof TypeError) {
|
|
203
|
+
throw cause;
|
|
204
|
+
}
|
|
205
|
+
throw new TypeError("Invalid document change cursor", { cause });
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export const validateDocumentChangeRetentionPolicy = (
|
|
210
|
+
policy: DocumentChangeRetentionPolicy,
|
|
211
|
+
nowMs: number
|
|
212
|
+
): void => {
|
|
213
|
+
if (
|
|
214
|
+
!Number.isSafeInteger(nowMs) ||
|
|
215
|
+
nowMs < 0 ||
|
|
216
|
+
!Number.isSafeInteger(policy.maxAgeDays) ||
|
|
217
|
+
policy.maxAgeDays < 1 ||
|
|
218
|
+
policy.maxAgeDays > 3650 ||
|
|
219
|
+
!Number.isSafeInteger(policy.maxEntries) ||
|
|
220
|
+
policy.maxEntries < 1 ||
|
|
221
|
+
policy.maxEntries > 1_000_000 ||
|
|
222
|
+
!Number.isSafeInteger(policy.maxBytes) ||
|
|
223
|
+
policy.maxBytes < 1 ||
|
|
224
|
+
policy.maxBytes > 1024 * 1024 * 1024
|
|
225
|
+
) {
|
|
226
|
+
throw new RangeError("Invalid document change retention policy");
|
|
227
|
+
}
|
|
228
|
+
};
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* canonical Capsule payload, including coverage, omissions, and guidance.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import type { FusionSource } from "../pipeline/types";
|
|
10
|
+
|
|
9
11
|
export const CONTEXT_OMISSION_REASONS = [
|
|
10
12
|
"duplicate",
|
|
11
13
|
"overlap",
|
|
@@ -43,6 +45,10 @@ export interface MaterializedContextCandidate<
|
|
|
43
45
|
text: string;
|
|
44
46
|
facets: string[];
|
|
45
47
|
retrievalRank: number;
|
|
48
|
+
/** Absent only for legacy results that predate planner provenance metadata. */
|
|
49
|
+
retrievalSources?: FusionSource[];
|
|
50
|
+
/** Absent only for legacy results that predate planner provenance metadata. */
|
|
51
|
+
graphExpanded?: boolean;
|
|
46
52
|
value: T;
|
|
47
53
|
}
|
|
48
54
|
|
|
@@ -59,10 +59,14 @@ export const contextCapsuleRetrievalSchema = z
|
|
|
59
59
|
.object({
|
|
60
60
|
author: z.string().min(1).max(256).nullable(),
|
|
61
61
|
lang: z.string().min(1).max(64).nullable(),
|
|
62
|
+
intent: z.string().min(1).max(16_384).nullable().optional(),
|
|
63
|
+
exclude: z.array(nonEmptyText.max(256)).max(128).optional(),
|
|
64
|
+
minScore: z.number().min(0).max(1).nullable().optional(),
|
|
62
65
|
queryModes: z.array(queryModeSchema).max(128),
|
|
63
66
|
limit: z.number().int().positive(),
|
|
64
67
|
candidateLimit: z.number().int().positive(),
|
|
65
68
|
graphRequested: z.boolean(),
|
|
69
|
+
rerankRequested: z.boolean().optional(),
|
|
66
70
|
})
|
|
67
71
|
.strict(),
|
|
68
72
|
capabilityStates: z
|
|
@@ -29,6 +29,14 @@ const positiveIntegerSchema = z.number().int().positive();
|
|
|
29
29
|
const nonNegativeIntegerSchema = z.number().int().nonnegative();
|
|
30
30
|
const COLLECTION_PATTERN = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
31
31
|
const collectionSchema = nonEmptyTextSchema.max(64).regex(COLLECTION_PATTERN);
|
|
32
|
+
const retrievalSourceSchema = z.enum([
|
|
33
|
+
"bm25",
|
|
34
|
+
"vector",
|
|
35
|
+
"bm25_variant",
|
|
36
|
+
"vector_variant",
|
|
37
|
+
"hyde",
|
|
38
|
+
"graph",
|
|
39
|
+
]);
|
|
32
40
|
const compareCodeUnits = (left: string, right: string): number =>
|
|
33
41
|
left < right ? -1 : left > right ? 1 : 0;
|
|
34
42
|
|
|
@@ -244,6 +252,15 @@ export const contextCapsuleEvidenceSchema = z
|
|
|
244
252
|
contextIds: z.array(sha256Schema).max(128),
|
|
245
253
|
retrievalRank: positiveIntegerSchema,
|
|
246
254
|
selectionRank: positiveIntegerSchema,
|
|
255
|
+
retrievalSources: z
|
|
256
|
+
.array(retrievalSourceSchema)
|
|
257
|
+
.min(1)
|
|
258
|
+
.max(6)
|
|
259
|
+
.refine((sources) => new Set(sources).size === sources.length, {
|
|
260
|
+
message: "retrievalSources must be unique",
|
|
261
|
+
})
|
|
262
|
+
.optional(),
|
|
263
|
+
graphExpanded: z.boolean().optional(),
|
|
247
264
|
facets: z.array(nonEmptyTextSchema.max(512)).max(128),
|
|
248
265
|
trust: z.literal("untrusted"),
|
|
249
266
|
egress: z.enum([
|
|
@@ -352,11 +352,12 @@ export const validateContextCapsulePayload = (
|
|
|
352
352
|
});
|
|
353
353
|
}
|
|
354
354
|
const semanticRequested = value.retrieval.depthPolicy !== "fast";
|
|
355
|
+
const rerankRequested =
|
|
356
|
+
value.retrieval.request.rerankRequested ?? semanticRequested;
|
|
355
357
|
if (
|
|
356
358
|
value.retrieval.capabilityStates.semanticSearch.requested !==
|
|
357
359
|
semanticRequested ||
|
|
358
|
-
value.retrieval.capabilityStates.reranking.requested !==
|
|
359
|
-
semanticRequested ||
|
|
360
|
+
value.retrieval.capabilityStates.reranking.requested !== rerankRequested ||
|
|
360
361
|
value.retrieval.capabilityStates.graphExpansion.requested !==
|
|
361
362
|
value.retrieval.request.graphRequested
|
|
362
363
|
) {
|
|
@@ -84,6 +84,17 @@ const normalizePayload = (
|
|
|
84
84
|
value.retrieval.request.lang === null
|
|
85
85
|
? null
|
|
86
86
|
: normalizeText(value.retrieval.request.lang),
|
|
87
|
+
...(value.retrieval.request.intent === undefined
|
|
88
|
+
? {}
|
|
89
|
+
: {
|
|
90
|
+
intent:
|
|
91
|
+
value.retrieval.request.intent === null
|
|
92
|
+
? null
|
|
93
|
+
: normalizeText(value.retrieval.request.intent),
|
|
94
|
+
}),
|
|
95
|
+
...(value.retrieval.request.exclude === undefined
|
|
96
|
+
? {}
|
|
97
|
+
: { exclude: normalizeSet(value.retrieval.request.exclude) }),
|
|
87
98
|
queryModes: value.retrieval.request.queryModes.map((mode) => ({
|
|
88
99
|
...mode,
|
|
89
100
|
text: normalizeText(mode.text),
|
|
@@ -110,6 +121,13 @@ const normalizePayload = (
|
|
|
110
121
|
documentDate: normalizeDocumentDate(item.documentDate),
|
|
111
122
|
observedAt: normalizeDate(item.observedAt),
|
|
112
123
|
contextIds: normalizeSet(item.contextIds),
|
|
124
|
+
...(item.retrievalSources === undefined
|
|
125
|
+
? {}
|
|
126
|
+
: {
|
|
127
|
+
retrievalSources: [...new Set(item.retrievalSources)].sort(
|
|
128
|
+
compareCodeUnits
|
|
129
|
+
),
|
|
130
|
+
}),
|
|
113
131
|
facets: normalizeSet(item.facets),
|
|
114
132
|
})),
|
|
115
133
|
guidance: {
|
|
@@ -64,8 +64,8 @@ export interface ContextRetrievalRequest extends HybridSearchOptions {
|
|
|
64
64
|
export interface ContextRetrievalCandidate {
|
|
65
65
|
result: SearchResult;
|
|
66
66
|
retrievalRank: number;
|
|
67
|
-
retrievalSources
|
|
68
|
-
graphExpanded
|
|
67
|
+
retrievalSources?: FusionSource[];
|
|
68
|
+
graphExpanded?: boolean;
|
|
69
69
|
contextIds: string[];
|
|
70
70
|
observedAt: string | null;
|
|
71
71
|
}
|
|
@@ -97,9 +97,13 @@ export interface ContextCompilerInput {
|
|
|
97
97
|
categories?: string[];
|
|
98
98
|
author?: string;
|
|
99
99
|
lang?: string;
|
|
100
|
+
intent?: string;
|
|
101
|
+
exclude?: string[];
|
|
102
|
+
minScore?: number;
|
|
100
103
|
since?: string;
|
|
101
104
|
until?: string;
|
|
102
105
|
graph?: boolean;
|
|
106
|
+
noRerank?: boolean;
|
|
103
107
|
limit?: number;
|
|
104
108
|
candidateLimit?: number;
|
|
105
109
|
/** Frozen once by the caller; never defaulted from wall-clock time. */
|
|
@@ -164,16 +168,9 @@ const compareCodeUnits = (left: string, right: string): number => {
|
|
|
164
168
|
};
|
|
165
169
|
|
|
166
170
|
const plannerMeta = (
|
|
167
|
-
result: SearchResult
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
result[SEARCH_RESULT_PLANNER_METADATA] ?? {
|
|
171
|
-
retrievalRank: fallbackRank,
|
|
172
|
-
mirrorHash: result.conversion?.mirrorHash ?? "",
|
|
173
|
-
seq: 0,
|
|
174
|
-
sources: [],
|
|
175
|
-
graphExpanded: false,
|
|
176
|
-
};
|
|
171
|
+
result: SearchResult
|
|
172
|
+
): SearchResultPlannerMetadata | undefined =>
|
|
173
|
+
result[SEARCH_RESULT_PLANNER_METADATA];
|
|
177
174
|
|
|
178
175
|
const compareSearchResults = (
|
|
179
176
|
left: SearchResult,
|
|
@@ -219,7 +216,9 @@ const referenceFromResult = (
|
|
|
219
216
|
const normalizeMaterialized = <T>(
|
|
220
217
|
draft: ContextMaterializedDraft<T>,
|
|
221
218
|
facets: string[],
|
|
222
|
-
retrievalRank: number
|
|
219
|
+
retrievalRank: number,
|
|
220
|
+
retrievalSources: FusionSource[] | undefined,
|
|
221
|
+
graphExpanded: boolean | undefined
|
|
223
222
|
): MaterializedContextCandidate<T> => {
|
|
224
223
|
const text = draft.text;
|
|
225
224
|
if (
|
|
@@ -250,6 +249,10 @@ const normalizeMaterialized = <T>(
|
|
|
250
249
|
text,
|
|
251
250
|
facets,
|
|
252
251
|
retrievalRank,
|
|
252
|
+
...(retrievalSources === undefined
|
|
253
|
+
? {}
|
|
254
|
+
: { retrievalSources: [...retrievalSources].sort(compareCodeUnits) }),
|
|
255
|
+
...(graphExpanded === undefined ? {} : { graphExpanded }),
|
|
253
256
|
value: draft.value,
|
|
254
257
|
};
|
|
255
258
|
};
|
|
@@ -352,10 +355,13 @@ export const planContextEvidence = async <T, P>(
|
|
|
352
355
|
categories: input.categories,
|
|
353
356
|
author: input.author,
|
|
354
357
|
lang: input.lang,
|
|
358
|
+
intent: input.intent,
|
|
359
|
+
exclude: input.exclude,
|
|
360
|
+
minScore: input.minScore,
|
|
355
361
|
since: temporalRange.since,
|
|
356
362
|
until: temporalRange.until,
|
|
357
363
|
graph: hasRerankBudget ? input.graph : false,
|
|
358
|
-
noRerank: hasRerankBudget ?
|
|
364
|
+
noRerank: input.noRerank || !hasRerankBudget ? true : undefined,
|
|
359
365
|
limit: resultLimit === undefined ? undefined : Math.max(1, resultLimit),
|
|
360
366
|
candidateLimit:
|
|
361
367
|
rerankLimit === undefined ? undefined : Math.max(1, rerankLimit),
|
|
@@ -377,7 +383,7 @@ export const planContextEvidence = async <T, P>(
|
|
|
377
383
|
const results = decoratedResults
|
|
378
384
|
.map((result, index) => ({
|
|
379
385
|
result,
|
|
380
|
-
retrievalRank: plannerMeta(result
|
|
386
|
+
retrievalRank: plannerMeta(result)?.retrievalRank ?? index + 1,
|
|
381
387
|
}))
|
|
382
388
|
.sort(
|
|
383
389
|
(left, right) =>
|
|
@@ -407,8 +413,8 @@ export const planContextEvidence = async <T, P>(
|
|
|
407
413
|
const referencesByCandidate: ContextCandidateReference[] = [];
|
|
408
414
|
|
|
409
415
|
for (const [index, result] of results.entries()) {
|
|
410
|
-
const meta = plannerMeta(result
|
|
411
|
-
for (const source of meta
|
|
416
|
+
const meta = plannerMeta(result);
|
|
417
|
+
for (const source of meta?.sources ?? []) retrievalSources.add(source);
|
|
412
418
|
const retrievalReference = referenceFromResult(result);
|
|
413
419
|
if (!isContextUriInScope(result.uri, indexName, collections, uriPrefix)) {
|
|
414
420
|
for (const facet of facetPlan) {
|
|
@@ -431,9 +437,13 @@ export const planContextEvidence = async <T, P>(
|
|
|
431
437
|
}
|
|
432
438
|
plannedCandidates.push({
|
|
433
439
|
result,
|
|
434
|
-
retrievalRank: meta
|
|
435
|
-
|
|
436
|
-
|
|
440
|
+
retrievalRank: meta?.retrievalRank ?? index + 1,
|
|
441
|
+
...(meta === undefined
|
|
442
|
+
? {}
|
|
443
|
+
: {
|
|
444
|
+
retrievalSources: [...meta.sources].sort(compareCodeUnits),
|
|
445
|
+
graphExpanded: meta.graphExpanded,
|
|
446
|
+
}),
|
|
437
447
|
contextIds:
|
|
438
448
|
guidance.idsByResultIdentity.get(
|
|
439
449
|
contextGuidanceResultIdentity(result)
|
|
@@ -486,7 +496,9 @@ export const planContextEvidence = async <T, P>(
|
|
|
486
496
|
normalizeMaterialized(
|
|
487
497
|
outcome.candidate,
|
|
488
498
|
matchedFacets,
|
|
489
|
-
plannedCandidate.retrievalRank
|
|
499
|
+
plannedCandidate.retrievalRank,
|
|
500
|
+
plannedCandidate.retrievalSources,
|
|
501
|
+
plannedCandidate.graphExpanded
|
|
490
502
|
)
|
|
491
503
|
);
|
|
492
504
|
}
|
|
@@ -490,6 +490,12 @@ export const toContextCapsuleEvidence = (
|
|
|
490
490
|
text: candidate.text,
|
|
491
491
|
retrievalRank: candidate.retrievalRank,
|
|
492
492
|
selectionRank,
|
|
493
|
+
...(candidate.retrievalSources === undefined
|
|
494
|
+
? {}
|
|
495
|
+
: { retrievalSources: [...candidate.retrievalSources] }),
|
|
496
|
+
...(candidate.graphExpanded === undefined
|
|
497
|
+
? {}
|
|
498
|
+
: { graphExpanded: candidate.graphExpanded }),
|
|
493
499
|
facets: [...candidate.facets],
|
|
494
500
|
};
|
|
495
501
|
};
|