@gmickel/gno 1.18.0 → 1.20.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 +14 -7
- package/assets/skill/SKILL.md +54 -12
- package/assets/skill/mcp-reference.md +7 -2
- package/assets/skill/recipes/citation-and-provenance.md +32 -9
- package/package.json +2 -1
- package/spec/AGENTS.md +83 -0
- package/spec/CLAUDE.md +83 -0
- package/spec/bench-fixture.schema.json +137 -0
- package/spec/cli.md +2919 -0
- package/spec/db/schema.sql +442 -0
- package/spec/evals-agentic.md +592 -0
- package/spec/evals.md +1106 -0
- package/spec/mcp.md +2279 -0
- package/spec/output-schemas/activation-verification.schema.json +515 -0
- package/spec/output-schemas/ask.schema.json +564 -0
- package/spec/output-schemas/backlinks.schema.json +131 -0
- package/spec/output-schemas/bench-result.schema.json +120 -0
- package/spec/output-schemas/capture-receipt.schema.json +143 -0
- package/spec/output-schemas/claim-verification.schema.json +291 -0
- package/spec/output-schemas/collection-list.schema.json +45 -0
- package/spec/output-schemas/context-capsule-v1.schema.json +726 -0
- package/spec/output-schemas/context-capsule-verification.schema.json +1338 -0
- package/spec/output-schemas/context-list.schema.json +21 -0
- package/spec/output-schemas/doctor.schema.json +313 -0
- package/spec/output-schemas/error.schema.json +30 -0
- package/spec/output-schemas/expansion.schema.json +37 -0
- package/spec/output-schemas/get.schema.json +140 -0
- package/spec/output-schemas/graph-query.schema.json +99 -0
- package/spec/output-schemas/graph.schema.json +371 -0
- package/spec/output-schemas/links-list.schema.json +186 -0
- package/spec/output-schemas/mcp-add-collection-result.schema.json +23 -0
- package/spec/output-schemas/mcp-capture-result.schema.json +152 -0
- package/spec/output-schemas/mcp-http-error.schema.json +30 -0
- package/spec/output-schemas/mcp-job-list.schema.json +58 -0
- package/spec/output-schemas/mcp-job-status.schema.json +224 -0
- package/spec/output-schemas/mcp-remove-result.schema.json +39 -0
- package/spec/output-schemas/mcp-sync-result.schema.json +41 -0
- package/spec/output-schemas/mcp-tag-result.schema.json +33 -0
- package/spec/output-schemas/models-list.schema.json +93 -0
- package/spec/output-schemas/multi-get.schema.json +103 -0
- package/spec/output-schemas/process-status.schema.json +119 -0
- package/spec/output-schemas/query-diagnose.schema.json +123 -0
- package/spec/output-schemas/resident-status.schema.json +154 -0
- package/spec/output-schemas/retrieval-trace-common.schema.json +492 -0
- package/spec/output-schemas/retrieval-trace-delete.schema.json +16 -0
- package/spec/output-schemas/retrieval-trace-export.schema.json +61 -0
- package/spec/output-schemas/retrieval-trace-filters.schema.json +139 -0
- package/spec/output-schemas/retrieval-trace-judgment.schema.json +15 -0
- package/spec/output-schemas/retrieval-trace-list.schema.json +18 -0
- package/spec/output-schemas/retrieval-trace-payloads.schema.json +178 -0
- package/spec/output-schemas/retrieval-trace-purge.schema.json +31 -0
- package/spec/output-schemas/retrieval-trace-qrels.schema.json +303 -0
- package/spec/output-schemas/retrieval-trace-replay.schema.json +286 -0
- package/spec/output-schemas/retrieval-trace-show.schema.json +69 -0
- package/spec/output-schemas/retrieval-trace-summary.schema.json +65 -0
- package/spec/output-schemas/search-result.schema.json +154 -0
- package/spec/output-schemas/search-results.schema.json +338 -0
- package/spec/output-schemas/similar.schema.json +84 -0
- package/spec/output-schemas/status.schema.json +676 -0
- package/spec/output-schemas/tags-list.schema.json +48 -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 +7 -0
- package/src/app/context-runtime.ts +20 -2
- 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 +144 -183
- package/src/cli/commands/context-build.ts +56 -9
- package/src/cli/commands/get.ts +64 -3
- package/src/cli/commands/query.ts +62 -23
- package/src/cli/commands/replay.ts +140 -0
- package/src/cli/commands/search.ts +48 -3
- package/src/cli/commands/shared.ts +3 -1
- package/src/cli/commands/trace.ts +200 -0
- package/src/cli/commands/vsearch.ts +75 -53
- package/src/cli/program.ts +287 -1
- package/src/config/index.ts +9 -0
- package/src/config/retrieval-traces.ts +56 -0
- package/src/config/types.ts +4 -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 +44 -25
- package/src/core/context-evidence.ts +6 -0
- package/src/core/retrieval-qrels.ts +405 -0
- package/src/core/retrieval-replay-candidate.ts +368 -0
- package/src/core/retrieval-replay-types.ts +109 -0
- package/src/core/retrieval-replay-validation.ts +89 -0
- package/src/core/retrieval-replay.ts +441 -0
- package/src/core/retrieval-trace-evidence-origin.ts +178 -0
- package/src/core/retrieval-trace-export.ts +113 -0
- package/src/core/retrieval-trace-filter-normalization.ts +27 -0
- package/src/core/retrieval-trace-filters.ts +19 -0
- package/src/core/retrieval-trace-management-helpers.ts +247 -0
- package/src/core/retrieval-trace-management-types.ts +132 -0
- package/src/core/retrieval-trace-management.ts +422 -0
- package/src/core/retrieval-trace-request.ts +141 -0
- package/src/core/retrieval-trace-session.ts +507 -0
- package/src/core/retrieval-trace.ts +472 -0
- 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/context.ts +87 -15
- package/src/mcp/tools/get.ts +35 -1
- package/src/mcp/tools/index.ts +83 -0
- package/src/mcp/tools/query.ts +95 -64
- package/src/mcp/tools/search.ts +36 -13
- package/src/mcp/tools/trace.ts +143 -0
- package/src/mcp/tools/vsearch.ts +71 -38
- package/src/pipeline/answer.ts +167 -26
- 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/graph-retrieval.ts +15 -1
- package/src/pipeline/hybrid.ts +151 -43
- package/src/pipeline/search.ts +36 -3
- package/src/pipeline/trace-metadata.ts +47 -0
- package/src/pipeline/types.ts +68 -0
- package/src/pipeline/vsearch.ts +101 -38
- package/src/sdk/client.ts +415 -73
- package/src/sdk/documents.ts +48 -1
- package/src/sdk/index.ts +17 -0
- package/src/sdk/types.ts +28 -0
- package/src/serve/context-capsule.ts +67 -8
- package/src/serve/public/app.tsx +12 -1
- package/src/serve/public/components/AskVerificationPanel.tsx +189 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/lib/workspace-tabs.ts +2 -0
- package/src/serve/public/pages/Ask.tsx +42 -4
- package/src/serve/public/pages/Dashboard.tsx +10 -0
- package/src/serve/public/pages/TraceHistory.tsx +478 -0
- package/src/serve/public/pages/trace-history-detail.tsx +224 -0
- package/src/serve/retrieval-trace.ts +28 -0
- package/src/serve/routes/api.ts +508 -68
- package/src/serve/routes/traces.ts +156 -0
- package/src/serve/server.ts +87 -2
- package/src/store/index.ts +31 -0
- package/src/store/migrations/014-retrieval-traces.ts +303 -0
- package/src/store/migrations/index.ts +2 -0
- package/src/store/retrieval-trace-codec.ts +384 -0
- package/src/store/sqlite/adapter.ts +153 -1
- package/src/store/sqlite/retrieval-trace-management-store.ts +341 -0
- package/src/store/sqlite/retrieval-trace-retention.ts +349 -0
- package/src/store/sqlite/retrieval-trace-rows.ts +267 -0
- package/src/store/sqlite/retrieval-trace-store.ts +515 -0
- package/src/store/types.ts +297 -0
- package/src/store/vector/sqlite-vec.ts +76 -1
- package/src/store/vector/types.ts +1 -1
|
@@ -5,8 +5,18 @@
|
|
|
5
5
|
* @module src/cli/commands/vsearch
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type {
|
|
9
|
+
RetrievalTraceSession,
|
|
10
|
+
RetrievalTraceSurfaceMetadata,
|
|
11
|
+
} from "../../core/retrieval-trace-session";
|
|
12
|
+
import type { EmbeddingPort } from "../../llm/types";
|
|
8
13
|
import type { SearchOptions, SearchResults } from "../../pipeline/types";
|
|
9
14
|
|
|
15
|
+
import {
|
|
16
|
+
finishRetrievalTraceAfterError,
|
|
17
|
+
retrievalTraceFilters,
|
|
18
|
+
startRetrievalTraceRequest,
|
|
19
|
+
} from "../../core/retrieval-trace-request";
|
|
10
20
|
import { LlmAdapter } from "../../llm/nodeLlamaCpp/adapter";
|
|
11
21
|
import { resolveModelUri } from "../../llm/registry";
|
|
12
22
|
import { formatQueryForEmbedding } from "../../pipeline/contextual";
|
|
@@ -47,7 +57,11 @@ export type VsearchCommandOptions = SearchOptions & {
|
|
|
47
57
|
};
|
|
48
58
|
|
|
49
59
|
export type VsearchResult =
|
|
50
|
-
| {
|
|
60
|
+
| {
|
|
61
|
+
success: true;
|
|
62
|
+
data: SearchResults;
|
|
63
|
+
metadata?: RetrievalTraceSurfaceMetadata;
|
|
64
|
+
}
|
|
51
65
|
| { success: false; error: string };
|
|
52
66
|
|
|
53
67
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -78,6 +92,8 @@ export async function vsearch(
|
|
|
78
92
|
}
|
|
79
93
|
|
|
80
94
|
const { store, config } = initResult;
|
|
95
|
+
let embedPort: EmbeddingPort | null = null;
|
|
96
|
+
let traceSession: RetrievalTraceSession | undefined;
|
|
81
97
|
|
|
82
98
|
try {
|
|
83
99
|
// Get model URI from preset
|
|
@@ -87,67 +103,74 @@ export async function vsearch(
|
|
|
87
103
|
options.model,
|
|
88
104
|
options.collection
|
|
89
105
|
);
|
|
106
|
+
const traceStart = await startRetrievalTraceRequest({
|
|
107
|
+
store,
|
|
108
|
+
config,
|
|
109
|
+
query,
|
|
110
|
+
filters: retrievalTraceFilters({ ...options, limit }),
|
|
111
|
+
pipeline: "vector",
|
|
112
|
+
indexName: options.indexName,
|
|
113
|
+
modelUris: [modelUri],
|
|
114
|
+
});
|
|
115
|
+
if (!traceStart.ok) {
|
|
116
|
+
return { success: false, error: traceStart.error.message };
|
|
117
|
+
}
|
|
118
|
+
traceSession = traceStart.value ?? undefined;
|
|
90
119
|
|
|
91
120
|
// Create LLM adapter for embeddings
|
|
92
121
|
const llm = new LlmAdapter(config);
|
|
93
122
|
const embedResult = await llm.createEmbeddingPort(modelUri);
|
|
94
123
|
if (!embedResult.ok) {
|
|
124
|
+
await traceSession?.finish("failed");
|
|
95
125
|
return { success: false, error: embedResult.error.message };
|
|
96
126
|
}
|
|
97
127
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (!queryEmbedResult.ok) {
|
|
106
|
-
return { success: false, error: queryEmbedResult.error.message };
|
|
107
|
-
}
|
|
108
|
-
const queryEmbedding = new Float32Array(queryEmbedResult.value);
|
|
109
|
-
const dimensions = queryEmbedding.length;
|
|
110
|
-
|
|
111
|
-
// Create vector index port
|
|
112
|
-
const db = store.getRawDb();
|
|
113
|
-
const vectorResult = await createVectorIndexPort(db, {
|
|
114
|
-
model: modelUri,
|
|
115
|
-
dimensions,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
if (!vectorResult.ok) {
|
|
119
|
-
return { success: false, error: vectorResult.error.message };
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const vectorIndex = vectorResult.value;
|
|
123
|
-
|
|
124
|
-
const deps: VectorSearchDeps = {
|
|
125
|
-
store,
|
|
126
|
-
vectorIndex,
|
|
127
|
-
embedPort,
|
|
128
|
-
config,
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
// Pass pre-computed embedding to avoid double-embed
|
|
132
|
-
const result = await searchVectorWithEmbedding(
|
|
133
|
-
deps,
|
|
134
|
-
query,
|
|
135
|
-
queryEmbedding,
|
|
136
|
-
{ ...options, limit }
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
if (!result.ok) {
|
|
140
|
-
return { success: false, error: result.error.message };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
success: true,
|
|
145
|
-
data: decorateSearchResultsForIndex(result.value, options.indexName),
|
|
146
|
-
};
|
|
147
|
-
} finally {
|
|
148
|
-
await embedPort.dispose();
|
|
128
|
+
embedPort = embedResult.value;
|
|
129
|
+
const queryEmbedResult = await embedPort.embed(
|
|
130
|
+
formatQueryForEmbedding(query, embedPort.modelUri)
|
|
131
|
+
);
|
|
132
|
+
if (!queryEmbedResult.ok) {
|
|
133
|
+
await traceSession?.finish("failed");
|
|
134
|
+
return { success: false, error: queryEmbedResult.error.message };
|
|
149
135
|
}
|
|
136
|
+
const queryEmbedding = new Float32Array(queryEmbedResult.value);
|
|
137
|
+
const vectorResult = await createVectorIndexPort(store.getRawDb(), {
|
|
138
|
+
model: modelUri,
|
|
139
|
+
dimensions: queryEmbedding.length,
|
|
140
|
+
});
|
|
141
|
+
if (!vectorResult.ok) {
|
|
142
|
+
await traceSession?.finish("failed");
|
|
143
|
+
return { success: false, error: vectorResult.error.message };
|
|
144
|
+
}
|
|
145
|
+
const deps: VectorSearchDeps = {
|
|
146
|
+
store,
|
|
147
|
+
vectorIndex: vectorResult.value,
|
|
148
|
+
embedPort,
|
|
149
|
+
config,
|
|
150
|
+
};
|
|
151
|
+
const result = await searchVectorWithEmbedding(
|
|
152
|
+
deps,
|
|
153
|
+
query,
|
|
154
|
+
queryEmbedding,
|
|
155
|
+
{ ...options, limit, traceSession }
|
|
156
|
+
);
|
|
157
|
+
if (!result.ok) {
|
|
158
|
+
await traceSession?.finish("failed");
|
|
159
|
+
return { success: false, error: result.error.message };
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
data: decorateSearchResultsForIndex(result.value, options.indexName),
|
|
164
|
+
metadata: traceSession?.metadata(),
|
|
165
|
+
};
|
|
166
|
+
} catch (cause) {
|
|
167
|
+
await finishRetrievalTraceAfterError(traceSession, cause);
|
|
168
|
+
return {
|
|
169
|
+
success: false,
|
|
170
|
+
error: cause instanceof Error ? cause.message : "Vector search failed",
|
|
171
|
+
};
|
|
150
172
|
} finally {
|
|
173
|
+
await embedPort?.dispose();
|
|
151
174
|
await store.close();
|
|
152
175
|
}
|
|
153
176
|
}
|
|
@@ -194,7 +217,6 @@ export function formatVsearch(
|
|
|
194
217
|
})
|
|
195
218
|
: `Error: ${result.error}`;
|
|
196
219
|
}
|
|
197
|
-
|
|
198
220
|
const formatOpts: FormatOptions = {
|
|
199
221
|
format: getFormatType(options),
|
|
200
222
|
full: options.full,
|
package/src/cli/program.ts
CHANGED
|
@@ -164,6 +164,15 @@ async function writeOutput(
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
/** Emit opt-in trace identity without changing command stdout payloads. */
|
|
168
|
+
export function writeRetrievalTraceReceipt(
|
|
169
|
+
metadata: { traceId: string } | undefined
|
|
170
|
+
): void {
|
|
171
|
+
if (metadata) {
|
|
172
|
+
process.stderr.write(`Trace: ${metadata.traceId}\n`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
167
176
|
async function resolveTerminalLinkPolicy(
|
|
168
177
|
format: "terminal" | "json" | "files" | "csv" | "md" | "xml"
|
|
169
178
|
): Promise<
|
|
@@ -292,6 +301,7 @@ export function createProgram(): Command {
|
|
|
292
301
|
wireOnboardingCommands(program);
|
|
293
302
|
wireCaptureCommand(program);
|
|
294
303
|
wireManagementCommands(program);
|
|
304
|
+
wireTraceCommands(program);
|
|
295
305
|
wirePublishCommand(program);
|
|
296
306
|
wireVecCommands(program);
|
|
297
307
|
wireRetrievalCommands(program);
|
|
@@ -315,6 +325,244 @@ Report issues: ${ISSUES_URL}`
|
|
|
315
325
|
return program;
|
|
316
326
|
}
|
|
317
327
|
|
|
328
|
+
function wireTraceCommands(program: Command): void {
|
|
329
|
+
const traceCmd = program
|
|
330
|
+
.command("trace")
|
|
331
|
+
.description("Inspect and manage private local retrieval traces");
|
|
332
|
+
|
|
333
|
+
const outputFormat = (options: Record<string, unknown>): "json" | "md" =>
|
|
334
|
+
getFormat(options) === "json" ? "json" : "md";
|
|
335
|
+
|
|
336
|
+
traceCmd
|
|
337
|
+
.command("list")
|
|
338
|
+
.description("List bounded, redacted retrieval trace summaries")
|
|
339
|
+
.option("-n, --limit <num>", "maximum traces", "50")
|
|
340
|
+
.option("--cursor <cursor>", "continue from a previous list receipt")
|
|
341
|
+
.option("--json", "JSON output")
|
|
342
|
+
.option("--md", "Markdown output")
|
|
343
|
+
.action(async (cmdOpts: Record<string, unknown>) => {
|
|
344
|
+
const globals = getGlobals();
|
|
345
|
+
const { traceList } = await import("./commands/trace");
|
|
346
|
+
const output = await traceList(
|
|
347
|
+
{
|
|
348
|
+
limit: parsePositiveInt("limit", cmdOpts.limit),
|
|
349
|
+
cursor: cmdOpts.cursor as string | undefined,
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
configPath: globals.config,
|
|
353
|
+
indexName: globals.index,
|
|
354
|
+
format: outputFormat(cmdOpts),
|
|
355
|
+
}
|
|
356
|
+
);
|
|
357
|
+
process.stdout.write(output);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
traceCmd
|
|
361
|
+
.command("show <trace-id>")
|
|
362
|
+
.description("Inspect one bounded retrieval trace receipt")
|
|
363
|
+
.option("--detail-limit <num>", "maximum records per detail section", "500")
|
|
364
|
+
.option("--json", "JSON output")
|
|
365
|
+
.option("--md", "Markdown output")
|
|
366
|
+
.action(async (traceId: string, cmdOpts: Record<string, unknown>) => {
|
|
367
|
+
const globals = getGlobals();
|
|
368
|
+
const { traceShow } = await import("./commands/trace");
|
|
369
|
+
const output = await traceShow(
|
|
370
|
+
traceId,
|
|
371
|
+
{
|
|
372
|
+
detailLimit: parsePositiveInt("detail-limit", cmdOpts.detailLimit),
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
configPath: globals.config,
|
|
376
|
+
indexName: globals.index,
|
|
377
|
+
format: outputFormat(cmdOpts),
|
|
378
|
+
}
|
|
379
|
+
);
|
|
380
|
+
process.stdout.write(output);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
traceCmd
|
|
384
|
+
.command("label <trace-id>")
|
|
385
|
+
.description("Append an explicit retrieval relevance judgment")
|
|
386
|
+
.requiredOption(
|
|
387
|
+
"--label <label>",
|
|
388
|
+
"relevant, irrelevant, or missing-expected"
|
|
389
|
+
)
|
|
390
|
+
.requiredOption("--target <ref>", "evidence or expected-document reference")
|
|
391
|
+
.option("--target-kind <kind>", "document, chunk, or span")
|
|
392
|
+
.option("--from-line <num>", "exact evidence start line")
|
|
393
|
+
.option("--to-line <num>", "exact evidence end line")
|
|
394
|
+
.option("--source-hash <sha256>", "expected immutable source hash")
|
|
395
|
+
.option("--docid <docid>", "expected document ID")
|
|
396
|
+
.option("--idempotency-key <key>", "caller retry key")
|
|
397
|
+
.option("--json", "JSON output")
|
|
398
|
+
.option("--md", "Markdown output")
|
|
399
|
+
.action(async (traceId: string, cmdOpts: Record<string, unknown>) => {
|
|
400
|
+
const globals = getGlobals();
|
|
401
|
+
const rawLabel = String(cmdOpts.label).replace("-", "_");
|
|
402
|
+
if (!["relevant", "irrelevant", "missing_expected"].includes(rawLabel)) {
|
|
403
|
+
throw new CliError(
|
|
404
|
+
"VALIDATION",
|
|
405
|
+
"--label must be relevant, irrelevant, or missing-expected"
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
const rawTargetKind = cmdOpts.targetKind;
|
|
409
|
+
if (
|
|
410
|
+
rawTargetKind !== undefined &&
|
|
411
|
+
(typeof rawTargetKind !== "string" ||
|
|
412
|
+
!["document", "chunk", "span"].includes(rawTargetKind))
|
|
413
|
+
) {
|
|
414
|
+
throw new CliError(
|
|
415
|
+
"VALIDATION",
|
|
416
|
+
"--target-kind must be document, chunk, or span"
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
const { traceLabel } = await import("./commands/trace");
|
|
420
|
+
const output = await traceLabel(
|
|
421
|
+
{
|
|
422
|
+
traceId,
|
|
423
|
+
label: rawLabel as "relevant" | "irrelevant" | "missing_expected",
|
|
424
|
+
targetRef: String(cmdOpts.target),
|
|
425
|
+
targetKind: rawTargetKind as
|
|
426
|
+
| "document"
|
|
427
|
+
| "chunk"
|
|
428
|
+
| "span"
|
|
429
|
+
| undefined,
|
|
430
|
+
startLine:
|
|
431
|
+
cmdOpts.fromLine === undefined
|
|
432
|
+
? undefined
|
|
433
|
+
: parsePositiveInt("from-line", cmdOpts.fromLine),
|
|
434
|
+
endLine:
|
|
435
|
+
cmdOpts.toLine === undefined
|
|
436
|
+
? undefined
|
|
437
|
+
: parsePositiveInt("to-line", cmdOpts.toLine),
|
|
438
|
+
sourceHash: cmdOpts.sourceHash as string | undefined,
|
|
439
|
+
docid: cmdOpts.docid as string | undefined,
|
|
440
|
+
idempotencyKey: cmdOpts.idempotencyKey as string | undefined,
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
configPath: globals.config,
|
|
444
|
+
indexName: globals.index,
|
|
445
|
+
format: outputFormat(cmdOpts),
|
|
446
|
+
}
|
|
447
|
+
);
|
|
448
|
+
process.stdout.write(output);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
traceCmd
|
|
452
|
+
.command("export <trace-ids...>")
|
|
453
|
+
.description("Export immutable terminal traces as one local receipt")
|
|
454
|
+
.option("--format <format>", "agentic-receipt or qrels", "agentic-receipt")
|
|
455
|
+
.option("--output <path>", "write canonical artifact atomically")
|
|
456
|
+
.option("--json", "JSON output")
|
|
457
|
+
.action(async (traceIds: string[], cmdOpts: Record<string, unknown>) => {
|
|
458
|
+
const globals = getGlobals();
|
|
459
|
+
const exportFormat = String(cmdOpts.format);
|
|
460
|
+
if (!["agentic-receipt", "qrels"].includes(exportFormat)) {
|
|
461
|
+
throw new CliError(
|
|
462
|
+
"VALIDATION",
|
|
463
|
+
"--format must be agentic-receipt or qrels"
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
const { traceExport } = await import("./commands/trace");
|
|
467
|
+
process.stdout.write(
|
|
468
|
+
await traceExport(traceIds, {
|
|
469
|
+
configPath: globals.config,
|
|
470
|
+
indexName: globals.index,
|
|
471
|
+
format: "json",
|
|
472
|
+
output: cmdOpts.output as string | undefined,
|
|
473
|
+
exportFormat: exportFormat as "agentic-receipt" | "qrels",
|
|
474
|
+
})
|
|
475
|
+
);
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
traceCmd
|
|
479
|
+
.command("replay <export-id>")
|
|
480
|
+
.description("Compare one immutable qrels baseline with a candidate")
|
|
481
|
+
.requiredOption("--candidate <type>", "bm25, vector, or hybrid")
|
|
482
|
+
.option("-n, --limit <num>", "result cutoff")
|
|
483
|
+
.option("--candidate-limit <num>", "candidate pool size")
|
|
484
|
+
.option("--no-expand", "disable query expansion")
|
|
485
|
+
.option("--no-rerank", "disable reranking")
|
|
486
|
+
.option("--json", "JSON output")
|
|
487
|
+
.option("--md", "Markdown output")
|
|
488
|
+
.action(async (exportId: string, cmdOpts: Record<string, unknown>) => {
|
|
489
|
+
const globals = getGlobals();
|
|
490
|
+
const candidateType = String(cmdOpts.candidate);
|
|
491
|
+
if (!["bm25", "vector", "hybrid"].includes(candidateType)) {
|
|
492
|
+
throw new CliError(
|
|
493
|
+
"VALIDATION",
|
|
494
|
+
"--candidate must be bm25, vector, or hybrid"
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
const { traceReplay } = await import("./commands/replay");
|
|
498
|
+
process.stdout.write(
|
|
499
|
+
await traceReplay(
|
|
500
|
+
exportId,
|
|
501
|
+
{
|
|
502
|
+
id: `cli-${candidateType}`,
|
|
503
|
+
type: candidateType as "bm25" | "vector" | "hybrid",
|
|
504
|
+
limit:
|
|
505
|
+
cmdOpts.limit === undefined
|
|
506
|
+
? undefined
|
|
507
|
+
: parsePositiveInt("limit", cmdOpts.limit),
|
|
508
|
+
candidateLimit:
|
|
509
|
+
cmdOpts.candidateLimit === undefined
|
|
510
|
+
? undefined
|
|
511
|
+
: parsePositiveInt("candidate-limit", cmdOpts.candidateLimit),
|
|
512
|
+
noExpand: cmdOpts.expand === false,
|
|
513
|
+
noRerank: cmdOpts.rerank === false,
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
configPath: globals.config,
|
|
517
|
+
indexName: globals.index,
|
|
518
|
+
format: outputFormat(cmdOpts),
|
|
519
|
+
offline: globals.offline,
|
|
520
|
+
}
|
|
521
|
+
)
|
|
522
|
+
);
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
traceCmd
|
|
526
|
+
.command("delete <trace-id>")
|
|
527
|
+
.description("Delete one trace and every owned local record")
|
|
528
|
+
.option("--json", "JSON output")
|
|
529
|
+
.option("--md", "Markdown output")
|
|
530
|
+
.action(async (traceId: string, cmdOpts: Record<string, unknown>) => {
|
|
531
|
+
const globals = getGlobals();
|
|
532
|
+
const { traceDelete } = await import("./commands/trace");
|
|
533
|
+
process.stdout.write(
|
|
534
|
+
await traceDelete(traceId, {
|
|
535
|
+
configPath: globals.config,
|
|
536
|
+
indexName: globals.index,
|
|
537
|
+
format: outputFormat(cmdOpts),
|
|
538
|
+
})
|
|
539
|
+
);
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
traceCmd
|
|
543
|
+
.command("purge")
|
|
544
|
+
.description("Delete every local retrieval trace receipt")
|
|
545
|
+
.option("--json", "JSON output")
|
|
546
|
+
.option("--md", "Markdown output")
|
|
547
|
+
.action(async (cmdOpts: Record<string, unknown>) => {
|
|
548
|
+
const globals = getGlobals();
|
|
549
|
+
if (!globals.yes) {
|
|
550
|
+
throw new CliError(
|
|
551
|
+
"VALIDATION",
|
|
552
|
+
"Trace purge requires the global --yes confirmation"
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
const { tracePurge } = await import("./commands/trace");
|
|
556
|
+
process.stdout.write(
|
|
557
|
+
await tracePurge({
|
|
558
|
+
configPath: globals.config,
|
|
559
|
+
indexName: globals.index,
|
|
560
|
+
format: outputFormat(cmdOpts),
|
|
561
|
+
})
|
|
562
|
+
);
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
318
566
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
319
567
|
// Search Commands (search, vsearch, query, ask)
|
|
320
568
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -387,7 +635,9 @@ function wireSearchCommands(program: Command): void {
|
|
|
387
635
|
|
|
388
636
|
const limit = cmdOpts.limit
|
|
389
637
|
? parsePositiveInt("limit", cmdOpts.limit)
|
|
390
|
-
:
|
|
638
|
+
: cmdOpts.verify
|
|
639
|
+
? 5
|
|
640
|
+
: getDefaultLimit(format);
|
|
391
641
|
const categories = parseCsvValues(cmdOpts.category);
|
|
392
642
|
const exclude = parseCsvValues(cmdOpts.exclude);
|
|
393
643
|
|
|
@@ -435,6 +685,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
435
685
|
terminalLinks: await resolveTerminalLinkPolicy(format),
|
|
436
686
|
});
|
|
437
687
|
await writeOutput(output, format);
|
|
688
|
+
writeRetrievalTraceReceipt(result.metadata);
|
|
438
689
|
});
|
|
439
690
|
|
|
440
691
|
// vsearch - Vector similarity search
|
|
@@ -547,6 +798,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
547
798
|
terminalLinks: await resolveTerminalLinkPolicy(format),
|
|
548
799
|
});
|
|
549
800
|
await writeOutput(output, format);
|
|
801
|
+
writeRetrievalTraceReceipt(result.metadata);
|
|
550
802
|
});
|
|
551
803
|
|
|
552
804
|
// query - Hybrid search with expansion and reranking
|
|
@@ -768,6 +1020,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
768
1020
|
terminalLinks: await resolveTerminalLinkPolicy(format),
|
|
769
1021
|
});
|
|
770
1022
|
await writeOutput(output, format);
|
|
1023
|
+
writeRetrievalTraceReceipt(result.metadata);
|
|
771
1024
|
});
|
|
772
1025
|
|
|
773
1026
|
// bench - Retrieval benchmark fixture runner
|
|
@@ -857,8 +1110,16 @@ function wireSearchCommands(program: Command): void {
|
|
|
857
1110
|
)
|
|
858
1111
|
.option("-C, --candidate-limit <num>", "max candidates passed to reranking")
|
|
859
1112
|
.option("--answer", "generate short grounded answer")
|
|
1113
|
+
.option(
|
|
1114
|
+
"--verify",
|
|
1115
|
+
"generate and verify every claim against a closed Context Capsule"
|
|
1116
|
+
)
|
|
860
1117
|
.option("--no-answer", "force retrieval-only output")
|
|
861
1118
|
.option("--max-answer-tokens <num>", "max answer tokens")
|
|
1119
|
+
.option("--context-budget-tokens <num>", "verified Context token budget")
|
|
1120
|
+
.option("--context-budget-bytes <num>", "verified Context byte budget")
|
|
1121
|
+
.option("--min-score <score>", "minimum retrieval score (0-1)")
|
|
1122
|
+
.option("--graph", "include bounded graph expansion")
|
|
862
1123
|
.option("--show-sources", "show all retrieved sources (not just cited)")
|
|
863
1124
|
.option("--json", "JSON output")
|
|
864
1125
|
.option("--md", "Markdown output")
|
|
@@ -889,6 +1150,22 @@ function wireSearchCommands(program: Command): void {
|
|
|
889
1150
|
const maxAnswerTokens = cmdOpts.maxAnswerTokens
|
|
890
1151
|
? parsePositiveInt("max-answer-tokens", cmdOpts.maxAnswerTokens)
|
|
891
1152
|
: undefined;
|
|
1153
|
+
const contextBudgetTokens = cmdOpts.contextBudgetTokens
|
|
1154
|
+
? parsePositiveInt("context-budget-tokens", cmdOpts.contextBudgetTokens)
|
|
1155
|
+
: undefined;
|
|
1156
|
+
const contextBudgetBytes = cmdOpts.contextBudgetBytes
|
|
1157
|
+
? parsePositiveInt("context-budget-bytes", cmdOpts.contextBudgetBytes)
|
|
1158
|
+
: undefined;
|
|
1159
|
+
const minScore = parseOptionalFloat("min-score", cmdOpts.minScore);
|
|
1160
|
+
if (minScore !== undefined && (minScore < 0 || minScore > 1)) {
|
|
1161
|
+
throw new CliError("VALIDATION", "min-score must be between 0 and 1");
|
|
1162
|
+
}
|
|
1163
|
+
if (cmdOpts.verify && cmdOpts.noAnswer) {
|
|
1164
|
+
throw new CliError(
|
|
1165
|
+
"VALIDATION",
|
|
1166
|
+
"--verify cannot be combined with --no-answer"
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
892
1169
|
const categories = parseCsvValues(cmdOpts.category);
|
|
893
1170
|
const exclude = parseCsvValues(cmdOpts.exclude);
|
|
894
1171
|
|
|
@@ -937,6 +1214,8 @@ function wireSearchCommands(program: Command): void {
|
|
|
937
1214
|
author: cmdOpts.author as string | undefined,
|
|
938
1215
|
intent: cmdOpts.intent as string | undefined,
|
|
939
1216
|
exclude,
|
|
1217
|
+
minScore,
|
|
1218
|
+
graph: Boolean(cmdOpts.graph),
|
|
940
1219
|
queryModes,
|
|
941
1220
|
noExpand: depthPolicy.noExpand,
|
|
942
1221
|
noRerank: depthPolicy.noRerank,
|
|
@@ -945,7 +1224,10 @@ function wireSearchCommands(program: Command): void {
|
|
|
945
1224
|
// Commander creates separate cmdOpts.noAnswer for --no-answer flag
|
|
946
1225
|
answer: Boolean(cmdOpts.answer),
|
|
947
1226
|
noAnswer: Boolean(cmdOpts.noAnswer),
|
|
1227
|
+
verify: Boolean(cmdOpts.verify),
|
|
948
1228
|
maxAnswerTokens,
|
|
1229
|
+
contextBudgetTokens,
|
|
1230
|
+
contextBudgetBytes,
|
|
949
1231
|
showSources,
|
|
950
1232
|
json: format === "json",
|
|
951
1233
|
md: format === "md",
|
|
@@ -960,6 +1242,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
960
1242
|
showSources,
|
|
961
1243
|
});
|
|
962
1244
|
await writeOutput(output, format);
|
|
1245
|
+
writeRetrievalTraceReceipt(result.metadata);
|
|
963
1246
|
});
|
|
964
1247
|
}
|
|
965
1248
|
|
|
@@ -1191,6 +1474,7 @@ function wireRetrievalCommands(program: Command): void {
|
|
|
1191
1474
|
parsePositiveInt.bind(null, "limit")
|
|
1192
1475
|
)
|
|
1193
1476
|
.option("--line-numbers", "Prefix lines with numbers")
|
|
1477
|
+
.option("--trace-id <id>", "Continue an open retrieval trace")
|
|
1194
1478
|
.option("--source", "Include source metadata")
|
|
1195
1479
|
.option("--json", "JSON output")
|
|
1196
1480
|
.option("--md", "Markdown output")
|
|
@@ -1209,6 +1493,7 @@ function wireRetrievalCommands(program: Command): void {
|
|
|
1209
1493
|
source: Boolean(cmdOpts.source),
|
|
1210
1494
|
json: format === "json",
|
|
1211
1495
|
md: format === "md",
|
|
1496
|
+
traceId: cmdOpts.traceId as string | undefined,
|
|
1212
1497
|
});
|
|
1213
1498
|
|
|
1214
1499
|
if (!result.success) {
|
|
@@ -1225,6 +1510,7 @@ function wireRetrievalCommands(program: Command): void {
|
|
|
1225
1510
|
md: format === "md",
|
|
1226
1511
|
})}\n`
|
|
1227
1512
|
);
|
|
1513
|
+
writeRetrievalTraceReceipt(result.metadata);
|
|
1228
1514
|
});
|
|
1229
1515
|
|
|
1230
1516
|
// multi-get - Retrieve multiple documents
|
package/src/config/index.ts
CHANGED
|
@@ -70,3 +70,12 @@ export {
|
|
|
70
70
|
ScopeTypeSchema,
|
|
71
71
|
} from "./types";
|
|
72
72
|
export type { HttpGatewayConfig } from "./types";
|
|
73
|
+
export {
|
|
74
|
+
RETRIEVAL_TRACE_DEFAULT_RETENTION,
|
|
75
|
+
type RetrievalTraceConfig,
|
|
76
|
+
RetrievalTraceConfigSchema,
|
|
77
|
+
type RetrievalTraceRedactionMode,
|
|
78
|
+
RetrievalTraceRedactionModeSchema,
|
|
79
|
+
type RetrievalTraceRetention,
|
|
80
|
+
RetrievalTraceRetentionSchema,
|
|
81
|
+
} from "./retrieval-traces";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** Opt-in retrieval trace configuration and bounded-retention defaults. */
|
|
2
|
+
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
export const RETRIEVAL_TRACE_DEFAULT_RETENTION = {
|
|
6
|
+
maxAgeDays: 30,
|
|
7
|
+
maxTraces: 1_000,
|
|
8
|
+
maxRecordsPerTrace: 10_000,
|
|
9
|
+
maxBytes: 16 * 1024 * 1024,
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
export const RetrievalTraceRetentionSchema = z
|
|
13
|
+
.object({
|
|
14
|
+
maxAgeDays: z.number().int().min(1).max(3_650),
|
|
15
|
+
maxTraces: z.number().int().min(1).max(1_000_000),
|
|
16
|
+
maxRecordsPerTrace: z.number().int().min(1).max(100_000),
|
|
17
|
+
maxBytes: z
|
|
18
|
+
.number()
|
|
19
|
+
.int()
|
|
20
|
+
.min(64 * 1024)
|
|
21
|
+
.max(1024 * 1024 * 1024),
|
|
22
|
+
})
|
|
23
|
+
.strict();
|
|
24
|
+
|
|
25
|
+
export const RetrievalTraceRedactionModeSchema = z.enum(["metadata", "replay"]);
|
|
26
|
+
|
|
27
|
+
const DisabledRetrievalTraceConfigSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
enabled: z.literal(false),
|
|
30
|
+
})
|
|
31
|
+
.strict();
|
|
32
|
+
|
|
33
|
+
const EnabledRetrievalTraceConfigSchema = z
|
|
34
|
+
.object({
|
|
35
|
+
enabled: z.literal(true),
|
|
36
|
+
/**
|
|
37
|
+
* `replay` stores replay inputs such as the raw query and filters. Choosing
|
|
38
|
+
* it is explicit consent; the safer metadata-only projection is recommended.
|
|
39
|
+
*/
|
|
40
|
+
redactionMode: RetrievalTraceRedactionModeSchema,
|
|
41
|
+
retention: RetrievalTraceRetentionSchema,
|
|
42
|
+
})
|
|
43
|
+
.strict();
|
|
44
|
+
|
|
45
|
+
export const RetrievalTraceConfigSchema = z.discriminatedUnion("enabled", [
|
|
46
|
+
DisabledRetrievalTraceConfigSchema,
|
|
47
|
+
EnabledRetrievalTraceConfigSchema,
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
export type RetrievalTraceConfig = z.infer<typeof RetrievalTraceConfigSchema>;
|
|
51
|
+
export type RetrievalTraceRetention = z.infer<
|
|
52
|
+
typeof RetrievalTraceRetentionSchema
|
|
53
|
+
>;
|
|
54
|
+
export type RetrievalTraceRedactionMode = z.infer<
|
|
55
|
+
typeof RetrievalTraceRedactionModeSchema
|
|
56
|
+
>;
|
package/src/config/types.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
10
|
import { URI_PREFIX } from "../app/constants";
|
|
11
|
+
import { RetrievalTraceConfigSchema } from "./retrieval-traces";
|
|
11
12
|
|
|
12
13
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
13
14
|
// Constants
|
|
@@ -338,6 +339,9 @@ export const ConfigSchema = z.object({
|
|
|
338
339
|
|
|
339
340
|
/** Resident Streamable HTTP MCP gateway configuration */
|
|
340
341
|
gateway: HttpGatewayConfigSchema.optional(),
|
|
342
|
+
|
|
343
|
+
/** Private local retrieval trace recording. Absent means recording off. */
|
|
344
|
+
retrievalTraces: RetrievalTraceConfigSchema.optional(),
|
|
341
345
|
});
|
|
342
346
|
|
|
343
347
|
export type Config = Omit<z.infer<typeof ConfigSchema>, "contentTypes"> & {
|
|
@@ -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
|