@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
package/src/cli/commands/ask.ts
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* @module src/cli/commands/ask
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type { RetrievalTraceSurfaceMetadata } from "../../core/retrieval-trace-session";
|
|
9
|
+
import type { RetrievalTraceSession } from "../../core/retrieval-trace-session";
|
|
8
10
|
import type {
|
|
9
11
|
EmbeddingPort,
|
|
10
12
|
GenerationPort,
|
|
@@ -12,12 +14,19 @@ import type {
|
|
|
12
14
|
} from "../../llm/types";
|
|
13
15
|
import type { AskOptions, AskResult, Citation } from "../../pipeline/types";
|
|
14
16
|
|
|
17
|
+
import { buildVerifiedAsk } from "../../app/verified-ask";
|
|
18
|
+
import {
|
|
19
|
+
finishRetrievalTraceAfterError,
|
|
20
|
+
retrievalTraceFilters,
|
|
21
|
+
startRetrievalTraceRequest,
|
|
22
|
+
} from "../../core/retrieval-trace-request";
|
|
15
23
|
import { LlmAdapter } from "../../llm/nodeLlamaCpp/adapter";
|
|
16
24
|
import { resolveDownloadPolicy } from "../../llm/policy";
|
|
17
25
|
import { resolveModelUri } from "../../llm/registry";
|
|
18
26
|
import {
|
|
27
|
+
answerTraceTerminalStatus,
|
|
19
28
|
generateGroundedAnswer,
|
|
20
|
-
|
|
29
|
+
processAnswerResultWithTrace,
|
|
21
30
|
} from "../../pipeline/answer";
|
|
22
31
|
import { type HybridSearchDeps, searchHybrid } from "../../pipeline/hybrid";
|
|
23
32
|
import {
|
|
@@ -31,6 +40,8 @@ import {
|
|
|
31
40
|
} from "../progress";
|
|
32
41
|
import { initStore } from "./shared";
|
|
33
42
|
|
|
43
|
+
export { formatAsk } from "./ask-format";
|
|
44
|
+
|
|
34
45
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
35
46
|
// Types
|
|
36
47
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -55,7 +66,11 @@ export type AskCommandOptions = AskOptions & {
|
|
|
55
66
|
};
|
|
56
67
|
|
|
57
68
|
export type AskCommandResult =
|
|
58
|
-
| {
|
|
69
|
+
| {
|
|
70
|
+
success: true;
|
|
71
|
+
data: AskResult;
|
|
72
|
+
metadata?: RetrievalTraceSurfaceMetadata;
|
|
73
|
+
}
|
|
59
74
|
| { success: false; error: string };
|
|
60
75
|
|
|
61
76
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -71,9 +86,11 @@ export async function ask(
|
|
|
71
86
|
options: AskCommandOptions = {}
|
|
72
87
|
): Promise<AskCommandResult> {
|
|
73
88
|
const limit = options.limit ?? 5;
|
|
89
|
+
const globals = getGlobals();
|
|
74
90
|
|
|
75
91
|
const initResult = await initStore({
|
|
76
92
|
configPath: options.configPath,
|
|
93
|
+
indexName: globals.index,
|
|
77
94
|
collection: options.collection,
|
|
78
95
|
syncConfig: false,
|
|
79
96
|
});
|
|
@@ -88,12 +105,56 @@ export async function ask(
|
|
|
88
105
|
let expandPort: GenerationPort | null = null;
|
|
89
106
|
let answerPort: GenerationPort | null = null;
|
|
90
107
|
let rerankPort: RerankPort | null = null;
|
|
108
|
+
let traceSession: RetrievalTraceSession | undefined;
|
|
91
109
|
|
|
92
110
|
try {
|
|
111
|
+
const verificationRequested = options.verify === true;
|
|
112
|
+
const answerRequested =
|
|
113
|
+
verificationRequested || Boolean(options.answer && !options.noAnswer);
|
|
114
|
+
const embedUri = resolveModelUri(
|
|
115
|
+
config,
|
|
116
|
+
"embed",
|
|
117
|
+
options.embedModel,
|
|
118
|
+
options.collection
|
|
119
|
+
);
|
|
120
|
+
const expandUri =
|
|
121
|
+
!verificationRequested && !options.noExpand && !options.queryModes?.length
|
|
122
|
+
? resolveModelUri(
|
|
123
|
+
config,
|
|
124
|
+
"expand",
|
|
125
|
+
options.expandModel ?? options.genModel,
|
|
126
|
+
options.collection
|
|
127
|
+
)
|
|
128
|
+
: undefined;
|
|
129
|
+
const answerUri = answerRequested
|
|
130
|
+
? resolveModelUri(config, "gen", options.genModel, options.collection)
|
|
131
|
+
: undefined;
|
|
132
|
+
const rerankUri = !options.noRerank
|
|
133
|
+
? resolveModelUri(
|
|
134
|
+
config,
|
|
135
|
+
"rerank",
|
|
136
|
+
options.rerankModel,
|
|
137
|
+
options.collection
|
|
138
|
+
)
|
|
139
|
+
: undefined;
|
|
140
|
+
const traceStart = await startRetrievalTraceRequest({
|
|
141
|
+
store,
|
|
142
|
+
config,
|
|
143
|
+
query,
|
|
144
|
+
filters: retrievalTraceFilters({ ...options, limit }),
|
|
145
|
+
pipeline: "ask",
|
|
146
|
+
indexName: globals.index,
|
|
147
|
+
modelUris: [embedUri, expandUri, answerUri, rerankUri].filter(
|
|
148
|
+
(value): value is string => Boolean(value)
|
|
149
|
+
),
|
|
150
|
+
});
|
|
151
|
+
if (!traceStart.ok) {
|
|
152
|
+
return { success: false, error: traceStart.error.message };
|
|
153
|
+
}
|
|
154
|
+
traceSession = traceStart.value ?? undefined;
|
|
93
155
|
const llm = new LlmAdapter(config);
|
|
94
156
|
|
|
95
157
|
// Resolve download policy from env/flags
|
|
96
|
-
const globals = getGlobals();
|
|
97
158
|
const policy = resolveDownloadPolicy(process.env, {
|
|
98
159
|
offline: globals.offline,
|
|
99
160
|
});
|
|
@@ -105,12 +166,6 @@ export async function ask(
|
|
|
105
166
|
: undefined;
|
|
106
167
|
|
|
107
168
|
// Create embedding port
|
|
108
|
-
const embedUri = resolveModelUri(
|
|
109
|
-
config,
|
|
110
|
-
"embed",
|
|
111
|
-
options.embedModel,
|
|
112
|
-
options.collection
|
|
113
|
-
);
|
|
114
169
|
const embedResult = await llm.createEmbeddingPort(embedUri, {
|
|
115
170
|
policy,
|
|
116
171
|
onProgress: downloadProgress
|
|
@@ -122,13 +177,7 @@ export async function ask(
|
|
|
122
177
|
}
|
|
123
178
|
|
|
124
179
|
// Create expansion port when expansion is enabled.
|
|
125
|
-
if (
|
|
126
|
-
const expandUri = resolveModelUri(
|
|
127
|
-
config,
|
|
128
|
-
"expand",
|
|
129
|
-
options.expandModel ?? options.genModel,
|
|
130
|
-
options.collection
|
|
131
|
-
);
|
|
180
|
+
if (expandUri) {
|
|
132
181
|
const genResult = await llm.createExpansionPort(expandUri, {
|
|
133
182
|
policy,
|
|
134
183
|
onProgress: downloadProgress
|
|
@@ -141,14 +190,8 @@ export async function ask(
|
|
|
141
190
|
}
|
|
142
191
|
|
|
143
192
|
// Create answer generation port when answers are requested.
|
|
144
|
-
if (
|
|
145
|
-
const
|
|
146
|
-
config,
|
|
147
|
-
"gen",
|
|
148
|
-
options.genModel,
|
|
149
|
-
options.collection
|
|
150
|
-
);
|
|
151
|
-
const genResult = await llm.createGenerationPort(genUri, {
|
|
193
|
+
if (answerUri) {
|
|
194
|
+
const genResult = await llm.createGenerationPort(answerUri, {
|
|
152
195
|
policy,
|
|
153
196
|
onProgress: downloadProgress
|
|
154
197
|
? (progress) => downloadProgress("gen", progress)
|
|
@@ -160,13 +203,7 @@ export async function ask(
|
|
|
160
203
|
}
|
|
161
204
|
|
|
162
205
|
// Create rerank port (unless --fast or --no-rerank)
|
|
163
|
-
if (
|
|
164
|
-
const rerankUri = resolveModelUri(
|
|
165
|
-
config,
|
|
166
|
-
"rerank",
|
|
167
|
-
options.rerankModel,
|
|
168
|
-
options.collection
|
|
169
|
-
);
|
|
206
|
+
if (rerankUri) {
|
|
170
207
|
const rerankResult = await llm.createRerankPort(rerankUri, {
|
|
171
208
|
policy,
|
|
172
209
|
onProgress: downloadProgress
|
|
@@ -208,12 +245,14 @@ export async function ask(
|
|
|
208
245
|
expandPort,
|
|
209
246
|
rerankPort,
|
|
210
247
|
};
|
|
211
|
-
|
|
212
|
-
// Check if answer generation is explicitly requested
|
|
213
|
-
const answerRequested = options.answer && !options.noAnswer;
|
|
214
|
-
|
|
215
248
|
// Fail early if --answer is requested but no generation model available
|
|
216
249
|
if (answerRequested && answerPort === null) {
|
|
250
|
+
await traceSession?.recordCapability(
|
|
251
|
+
"answer_generation",
|
|
252
|
+
"unavailable",
|
|
253
|
+
"model_unavailable"
|
|
254
|
+
);
|
|
255
|
+
await traceSession?.finish("failed");
|
|
217
256
|
return {
|
|
218
257
|
success: false,
|
|
219
258
|
error:
|
|
@@ -222,6 +261,34 @@ export async function ask(
|
|
|
222
261
|
};
|
|
223
262
|
}
|
|
224
263
|
|
|
264
|
+
if (verificationRequested && answerPort) {
|
|
265
|
+
const verified = await buildVerifiedAsk(
|
|
266
|
+
query,
|
|
267
|
+
{ ...options, limit },
|
|
268
|
+
{
|
|
269
|
+
store,
|
|
270
|
+
config,
|
|
271
|
+
indexName: globals.index,
|
|
272
|
+
vectorIndex,
|
|
273
|
+
embedPort,
|
|
274
|
+
rerankPort,
|
|
275
|
+
genPort: answerPort,
|
|
276
|
+
traceSession,
|
|
277
|
+
}
|
|
278
|
+
);
|
|
279
|
+
const finalized = await traceSession?.finish(
|
|
280
|
+
answerTraceTerminalStatus(verified.citations)
|
|
281
|
+
);
|
|
282
|
+
if (finalized && !finalized.ok) {
|
|
283
|
+
return { success: false, error: finalized.error.message };
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
success: true,
|
|
287
|
+
data: verified,
|
|
288
|
+
metadata: traceSession?.metadata(),
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
225
292
|
// Run hybrid search
|
|
226
293
|
const searchResult = await searchHybrid(deps, query, {
|
|
227
294
|
limit,
|
|
@@ -235,13 +302,17 @@ export async function ask(
|
|
|
235
302
|
tagsAll: options.tagsAll,
|
|
236
303
|
tagsAny: options.tagsAny,
|
|
237
304
|
exclude: options.exclude,
|
|
305
|
+
minScore: options.minScore,
|
|
306
|
+
graph: options.graph,
|
|
238
307
|
queryModes: options.queryModes,
|
|
239
308
|
noExpand: options.noExpand,
|
|
240
309
|
noRerank: options.noRerank,
|
|
241
310
|
candidateLimit: options.candidateLimit,
|
|
311
|
+
traceSession,
|
|
242
312
|
});
|
|
243
313
|
|
|
244
314
|
if (!searchResult.ok) {
|
|
315
|
+
await traceSession?.finish("failed");
|
|
245
316
|
return { success: false, error: searchResult.error.message };
|
|
246
317
|
}
|
|
247
318
|
|
|
@@ -261,6 +332,7 @@ export async function ask(
|
|
|
261
332
|
answerRequested && answerPort !== null && results.length > 0;
|
|
262
333
|
|
|
263
334
|
if (shouldGenerateAnswer && answerPort) {
|
|
335
|
+
await traceSession?.recordCapability("answer_generation", "attempted");
|
|
264
336
|
const maxTokens = options.maxAnswerTokens ?? 512;
|
|
265
337
|
const rawResult = await generateGroundedAnswer(
|
|
266
338
|
{ genPort: answerPort, store },
|
|
@@ -271,15 +343,25 @@ export async function ask(
|
|
|
271
343
|
|
|
272
344
|
// Fail loudly if generation was requested but failed
|
|
273
345
|
if (!rawResult) {
|
|
346
|
+
await traceSession?.recordCapability(
|
|
347
|
+
"answer_generation",
|
|
348
|
+
"failed",
|
|
349
|
+
"generation_failed"
|
|
350
|
+
);
|
|
351
|
+
await traceSession?.finish("failed");
|
|
274
352
|
return {
|
|
275
353
|
success: false,
|
|
276
354
|
error:
|
|
277
355
|
"Answer generation failed. The generation model may have encountered an error.",
|
|
278
356
|
};
|
|
279
357
|
}
|
|
358
|
+
await traceSession?.recordCapability("answer_generation", "used");
|
|
280
359
|
|
|
281
360
|
// Process answer: extract valid citations, filter, renumber
|
|
282
|
-
const processed =
|
|
361
|
+
const processed = await processAnswerResultWithTrace(
|
|
362
|
+
rawResult,
|
|
363
|
+
traceSession
|
|
364
|
+
);
|
|
283
365
|
answer = processed.answer;
|
|
284
366
|
citations = processed.citations;
|
|
285
367
|
answerContext = processed.answerContext;
|
|
@@ -307,7 +389,32 @@ export async function ask(
|
|
|
307
389
|
},
|
|
308
390
|
};
|
|
309
391
|
|
|
310
|
-
|
|
392
|
+
if (answerRequested) {
|
|
393
|
+
if (!answerGenerated) {
|
|
394
|
+
await traceSession?.recordCapability(
|
|
395
|
+
"answer_generation",
|
|
396
|
+
"unavailable",
|
|
397
|
+
"no_evidence"
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
const finalized = await traceSession?.finish(
|
|
401
|
+
answerTraceTerminalStatus(citations)
|
|
402
|
+
);
|
|
403
|
+
if (finalized && !finalized.ok) {
|
|
404
|
+
return { success: false, error: finalized.error.message };
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
success: true,
|
|
409
|
+
data: askResult,
|
|
410
|
+
metadata: traceSession?.metadata(),
|
|
411
|
+
};
|
|
412
|
+
} catch (cause) {
|
|
413
|
+
await finishRetrievalTraceAfterError(traceSession, cause);
|
|
414
|
+
return {
|
|
415
|
+
success: false,
|
|
416
|
+
error: cause instanceof Error ? cause.message : "Ask failed",
|
|
417
|
+
};
|
|
311
418
|
} finally {
|
|
312
419
|
if (embedPort) {
|
|
313
420
|
await embedPort.dispose();
|
|
@@ -324,149 +431,3 @@ export async function ask(
|
|
|
324
431
|
await store.close();
|
|
325
432
|
}
|
|
326
433
|
}
|
|
327
|
-
|
|
328
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
329
|
-
// Formatters
|
|
330
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
331
|
-
|
|
332
|
-
interface FormatOptions {
|
|
333
|
-
showSources?: boolean;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// oxlint-disable-next-line max-lines-per-function -- terminal formatting with conditional sections
|
|
337
|
-
function formatTerminal(data: AskResult, opts: FormatOptions = {}): string {
|
|
338
|
-
const lines: string[] = [];
|
|
339
|
-
const hasAnswer = Boolean(data.answer);
|
|
340
|
-
|
|
341
|
-
// Show answer if present
|
|
342
|
-
if (data.answer) {
|
|
343
|
-
lines.push("Answer:");
|
|
344
|
-
lines.push(data.answer);
|
|
345
|
-
lines.push("");
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// Show cited sources (only sources actually referenced in answer)
|
|
349
|
-
if (data.citations && data.citations.length > 0) {
|
|
350
|
-
lines.push("Cited Sources:");
|
|
351
|
-
for (let i = 0; i < data.citations.length; i++) {
|
|
352
|
-
const c = data.citations[i];
|
|
353
|
-
if (c) {
|
|
354
|
-
lines.push(` [${i + 1}] ${c.uri}`);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
lines.push("");
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Show all retrieved sources if:
|
|
361
|
-
// - No answer was generated (retrieval-only mode)
|
|
362
|
-
// - User explicitly requested with --show-sources
|
|
363
|
-
const showAllSources = !hasAnswer || opts.showSources;
|
|
364
|
-
if (showAllSources && data.results.length > 0) {
|
|
365
|
-
lines.push(hasAnswer ? "All Retrieved Sources:" : "Sources:");
|
|
366
|
-
for (const r of data.results) {
|
|
367
|
-
lines.push(` [${r.docid}] ${r.uri}`);
|
|
368
|
-
if (r.title) {
|
|
369
|
-
lines.push(` ${r.title}`);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
} else if (hasAnswer && data.results.length > 0) {
|
|
373
|
-
// Hint about --show-sources when we have more sources
|
|
374
|
-
const citedCount = data.citations?.length ?? 0;
|
|
375
|
-
if (data.results.length > citedCount) {
|
|
376
|
-
lines.push(
|
|
377
|
-
`(${data.results.length} sources retrieved, use --show-sources to list all)`
|
|
378
|
-
);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
if (!data.answer && data.results.length === 0) {
|
|
383
|
-
lines.push("No relevant sources found.");
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
return lines.join("\n");
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
function formatMarkdown(data: AskResult, opts: FormatOptions = {}): string {
|
|
390
|
-
const lines: string[] = [];
|
|
391
|
-
const hasAnswer = Boolean(data.answer);
|
|
392
|
-
|
|
393
|
-
lines.push(`# Question: ${data.query}`);
|
|
394
|
-
lines.push("");
|
|
395
|
-
|
|
396
|
-
if (data.answer) {
|
|
397
|
-
lines.push("## Answer");
|
|
398
|
-
lines.push("");
|
|
399
|
-
lines.push(data.answer);
|
|
400
|
-
lines.push("");
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// Show cited sources (only sources actually referenced in answer)
|
|
404
|
-
if (data.citations && data.citations.length > 0) {
|
|
405
|
-
lines.push("## Cited Sources");
|
|
406
|
-
lines.push("");
|
|
407
|
-
for (let i = 0; i < data.citations.length; i++) {
|
|
408
|
-
const c = data.citations[i];
|
|
409
|
-
if (c) {
|
|
410
|
-
lines.push(`**[${i + 1}]** \`${c.uri}\``);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
lines.push("");
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// Show all retrieved sources if no answer or --show-sources
|
|
417
|
-
const showAllSources = !hasAnswer || opts.showSources;
|
|
418
|
-
if (showAllSources) {
|
|
419
|
-
lines.push(hasAnswer ? "## All Retrieved Sources" : "## Sources");
|
|
420
|
-
lines.push("");
|
|
421
|
-
|
|
422
|
-
for (let i = 0; i < data.results.length; i++) {
|
|
423
|
-
const r = data.results[i];
|
|
424
|
-
if (!r) {
|
|
425
|
-
continue;
|
|
426
|
-
}
|
|
427
|
-
lines.push(`${i + 1}. **${r.title || r.source.relPath}**`);
|
|
428
|
-
lines.push(` - URI: \`${r.uri}\``);
|
|
429
|
-
lines.push(` - Score: ${r.score.toFixed(2)}`);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
if (data.results.length === 0) {
|
|
433
|
-
lines.push("*No relevant sources found.*");
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
lines.push("");
|
|
438
|
-
lines.push("---");
|
|
439
|
-
lines.push(
|
|
440
|
-
`*Mode: ${data.mode} | Expanded: ${data.meta.expanded} | Reranked: ${data.meta.reranked}*`
|
|
441
|
-
);
|
|
442
|
-
|
|
443
|
-
return lines.join("\n");
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/**
|
|
447
|
-
* Format ask result for output.
|
|
448
|
-
*/
|
|
449
|
-
export function formatAsk(
|
|
450
|
-
result: AskCommandResult,
|
|
451
|
-
options: AskCommandOptions
|
|
452
|
-
): string {
|
|
453
|
-
if (!result.success) {
|
|
454
|
-
return options.json
|
|
455
|
-
? JSON.stringify({
|
|
456
|
-
error: { code: "ASK_FAILED", message: result.error },
|
|
457
|
-
})
|
|
458
|
-
: `Error: ${result.error}`;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
const formatOpts: FormatOptions = { showSources: options.showSources };
|
|
462
|
-
|
|
463
|
-
if (options.json) {
|
|
464
|
-
return JSON.stringify(result.data, null, 2);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
if (options.md) {
|
|
468
|
-
return formatMarkdown(result.data, formatOpts);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
return formatTerminal(result.data, formatOpts);
|
|
472
|
-
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Context Capsule build command over the shared application runtime. */
|
|
2
2
|
|
|
3
3
|
import type { ContextCapsuleBuildInput } from "../../app/context-runtime";
|
|
4
|
+
import type { RetrievalTraceSession } from "../../core/retrieval-trace-session";
|
|
4
5
|
import type { EmbeddingPort, RerankPort } from "../../llm/types";
|
|
5
6
|
import type { VectorIndexPort } from "../../store/vector";
|
|
6
7
|
|
|
@@ -10,6 +11,10 @@ import {
|
|
|
10
11
|
canonicalBuiltContextCapsuleJson,
|
|
11
12
|
validateContextCapsuleBuildInput,
|
|
12
13
|
} from "../../app/context-runtime";
|
|
14
|
+
import {
|
|
15
|
+
finishRetrievalTraceAfterError,
|
|
16
|
+
startRetrievalTraceRequest,
|
|
17
|
+
} from "../../core/retrieval-trace-request";
|
|
13
18
|
import { LlmAdapter } from "../../llm/nodeLlamaCpp/adapter";
|
|
14
19
|
import { resolveDownloadPolicy } from "../../llm/policy";
|
|
15
20
|
import { resolveModelUri } from "../../llm/registry";
|
|
@@ -77,13 +82,56 @@ export const contextBuild = async (
|
|
|
77
82
|
let embedPort: EmbeddingPort | null = null;
|
|
78
83
|
let rerankPort: RerankPort | null = null;
|
|
79
84
|
let vectorIndex: VectorIndexPort | null = null;
|
|
85
|
+
let traceSession: RetrievalTraceSession | undefined;
|
|
80
86
|
try {
|
|
81
87
|
validateContextCapsuleBuildInput(
|
|
82
88
|
{ goal, ...options },
|
|
83
89
|
options.indexName,
|
|
84
90
|
config.collections.map((collection) => collection.name)
|
|
85
91
|
);
|
|
92
|
+
const collection =
|
|
93
|
+
options.collections?.length === 1 ? options.collections[0] : undefined;
|
|
94
|
+
const embedUri =
|
|
95
|
+
options.depthPolicy === "fast"
|
|
96
|
+
? undefined
|
|
97
|
+
: resolveModelUri(config, "embed", undefined, collection);
|
|
98
|
+
const rerankUri =
|
|
99
|
+
options.depthPolicy === "fast"
|
|
100
|
+
? undefined
|
|
101
|
+
: resolveModelUri(config, "rerank", undefined, collection);
|
|
102
|
+
const traceStart = await startRetrievalTraceRequest({
|
|
103
|
+
store,
|
|
104
|
+
config,
|
|
105
|
+
query: options.query ?? goal,
|
|
106
|
+
goal,
|
|
107
|
+
filters: {
|
|
108
|
+
limit: options.limit,
|
|
109
|
+
collection,
|
|
110
|
+
collections: [...(options.collections ?? [])].sort(),
|
|
111
|
+
lang: options.lang,
|
|
112
|
+
tagsAll: options.tagsAll,
|
|
113
|
+
tagsAny: options.tagsAny,
|
|
114
|
+
since: options.since,
|
|
115
|
+
until: options.until,
|
|
116
|
+
categories: options.categories,
|
|
117
|
+
author: options.author,
|
|
118
|
+
graph: options.graph,
|
|
119
|
+
candidateLimit: options.candidateLimit,
|
|
120
|
+
queryModes: options.queryModes,
|
|
121
|
+
uriPrefix: options.uriPrefix ?? undefined,
|
|
122
|
+
},
|
|
123
|
+
pipeline: "context",
|
|
124
|
+
indexName: options.indexName,
|
|
125
|
+
modelUris: [embedUri, rerankUri].filter((value): value is string =>
|
|
126
|
+
Boolean(value)
|
|
127
|
+
),
|
|
128
|
+
});
|
|
129
|
+
if (!traceStart.ok) throw new Error(traceStart.error.message);
|
|
130
|
+
traceSession = traceStart.value ?? undefined;
|
|
86
131
|
if (options.depthPolicy !== "fast") {
|
|
132
|
+
if (!(embedUri && rerankUri)) {
|
|
133
|
+
throw new Error("Context model identities could not be resolved");
|
|
134
|
+
}
|
|
87
135
|
const globals = getGlobals();
|
|
88
136
|
const policy = resolveDownloadPolicy(process.env, {
|
|
89
137
|
offline: globals.offline,
|
|
@@ -92,9 +140,6 @@ export const contextBuild = async (
|
|
|
92
140
|
const progress = showProgress
|
|
93
141
|
? createThrottledProgressRenderer(createProgressRenderer())
|
|
94
142
|
: undefined;
|
|
95
|
-
const collection =
|
|
96
|
-
options.collections?.length === 1 ? options.collections[0] : undefined;
|
|
97
|
-
const embedUri = resolveModelUri(config, "embed", undefined, collection);
|
|
98
143
|
const embedResult = await llm.createEmbeddingPort(embedUri, {
|
|
99
144
|
policy,
|
|
100
145
|
onProgress: progress ? (value) => progress("embed", value) : undefined,
|
|
@@ -110,12 +155,6 @@ export const contextBuild = async (
|
|
|
110
155
|
if (vectorResult.ok) vectorIndex = vectorResult.value;
|
|
111
156
|
}
|
|
112
157
|
}
|
|
113
|
-
const rerankUri = resolveModelUri(
|
|
114
|
-
config,
|
|
115
|
-
"rerank",
|
|
116
|
-
undefined,
|
|
117
|
-
collection
|
|
118
|
-
);
|
|
119
158
|
const rerankResult = await llm.createRerankPort(rerankUri, {
|
|
120
159
|
policy,
|
|
121
160
|
onProgress: progress ? (value) => progress("rerank", value) : undefined,
|
|
@@ -132,12 +171,20 @@ export const contextBuild = async (
|
|
|
132
171
|
vectorIndex,
|
|
133
172
|
embedPort,
|
|
134
173
|
rerankPort,
|
|
174
|
+
traceSession,
|
|
135
175
|
}
|
|
136
176
|
);
|
|
177
|
+
const finished = await traceSession?.finish("completed");
|
|
178
|
+
if (finished && !finished.ok) throw new Error(finished.error.message);
|
|
179
|
+
const traceMetadata = traceSession?.metadata();
|
|
180
|
+
if (traceMetadata) {
|
|
181
|
+
process.stderr.write(`Trace: ${traceMetadata.traceId}\n`);
|
|
182
|
+
}
|
|
137
183
|
return options.format === "md"
|
|
138
184
|
? formatContextCapsuleMarkdown(capsule)
|
|
139
185
|
: canonicalBuiltContextCapsuleJson(capsule);
|
|
140
186
|
} catch (error) {
|
|
187
|
+
await finishRetrievalTraceAfterError(traceSession, error);
|
|
141
188
|
if (error instanceof CliError) throw error;
|
|
142
189
|
throw contextCliError(error);
|
|
143
190
|
} finally {
|
package/src/cli/commands/get.ts
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* @module src/cli/commands/get
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type {
|
|
9
|
+
RetrievalTraceSession,
|
|
10
|
+
RetrievalTraceSurfaceMetadata,
|
|
11
|
+
} from "../../core/retrieval-trace-session";
|
|
8
12
|
import type { DocumentRow, StorePort, StoreResult } from "../../store/types";
|
|
9
13
|
import type { ParsedRef } from "./ref-parser";
|
|
10
14
|
|
|
@@ -17,6 +21,10 @@ import {
|
|
|
17
21
|
getDocumentCapabilities,
|
|
18
22
|
type DocumentCapabilities,
|
|
19
23
|
} from "../../core/document-capabilities";
|
|
24
|
+
import {
|
|
25
|
+
evidenceFromExactDocument,
|
|
26
|
+
RetrievalTraceSession as TraceSession,
|
|
27
|
+
} from "../../core/retrieval-trace-session";
|
|
20
28
|
import { parseRef } from "./ref-parser";
|
|
21
29
|
import { initStore } from "./shared";
|
|
22
30
|
|
|
@@ -41,10 +49,18 @@ export interface GetCommandOptions {
|
|
|
41
49
|
json?: boolean;
|
|
42
50
|
/** Markdown output */
|
|
43
51
|
md?: boolean;
|
|
52
|
+
/** Continue an open retrieval receipt returned by a prior query. */
|
|
53
|
+
traceId?: string;
|
|
54
|
+
/** Internal shared-session seam for in-process callers. */
|
|
55
|
+
traceSession?: RetrievalTraceSession;
|
|
44
56
|
}
|
|
45
57
|
|
|
46
58
|
export type GetResult =
|
|
47
|
-
| {
|
|
59
|
+
| {
|
|
60
|
+
success: true;
|
|
61
|
+
data: GetResponse;
|
|
62
|
+
metadata?: RetrievalTraceSurfaceMetadata;
|
|
63
|
+
}
|
|
48
64
|
| { success: false; error: string; isValidation?: boolean };
|
|
49
65
|
|
|
50
66
|
export interface GetResponse {
|
|
@@ -138,7 +154,53 @@ export async function get(
|
|
|
138
154
|
const { store, config } = initResult;
|
|
139
155
|
|
|
140
156
|
try {
|
|
141
|
-
|
|
157
|
+
let traceSession = options.traceSession;
|
|
158
|
+
if (!traceSession && options.traceId) {
|
|
159
|
+
const resumed = await TraceSession.resume({
|
|
160
|
+
store,
|
|
161
|
+
config: config.retrievalTraces,
|
|
162
|
+
traceId: options.traceId,
|
|
163
|
+
});
|
|
164
|
+
if (!resumed.ok) {
|
|
165
|
+
return { success: false, error: resumed.error.message };
|
|
166
|
+
}
|
|
167
|
+
traceSession = resumed.value ?? undefined;
|
|
168
|
+
}
|
|
169
|
+
const result = await fetchDocument(
|
|
170
|
+
store,
|
|
171
|
+
parsed,
|
|
172
|
+
options,
|
|
173
|
+
config,
|
|
174
|
+
indexName
|
|
175
|
+
);
|
|
176
|
+
if (!result.success || !traceSession) return result;
|
|
177
|
+
const lines = result.data.returnedLines ?? {
|
|
178
|
+
start: 1,
|
|
179
|
+
end: result.data.totalLines,
|
|
180
|
+
};
|
|
181
|
+
const evidence = evidenceFromExactDocument({
|
|
182
|
+
docid: result.data.docid,
|
|
183
|
+
uri: result.data.uri,
|
|
184
|
+
sourceHash: result.data.source.sourceHash,
|
|
185
|
+
mirrorHash: result.data.conversion?.mirrorHash,
|
|
186
|
+
content: result.data.content,
|
|
187
|
+
startLine: lines.start,
|
|
188
|
+
endLine: lines.end,
|
|
189
|
+
});
|
|
190
|
+
if (evidence) {
|
|
191
|
+
const getEvent = await traceSession.recordEvidence("get", [evidence]);
|
|
192
|
+
if (!getEvent.ok) {
|
|
193
|
+
return { success: false, error: getEvent.error.message };
|
|
194
|
+
}
|
|
195
|
+
const openEvent = await traceSession.recordEvidence("open", [evidence]);
|
|
196
|
+
if (!openEvent.ok) {
|
|
197
|
+
return { success: false, error: openEvent.error.message };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
...result,
|
|
202
|
+
metadata: traceSession.metadata(),
|
|
203
|
+
};
|
|
142
204
|
} finally {
|
|
143
205
|
await store.close();
|
|
144
206
|
}
|
|
@@ -375,7 +437,6 @@ export function formatGet(
|
|
|
375
437
|
}
|
|
376
438
|
return `Error: ${result.error}`;
|
|
377
439
|
}
|
|
378
|
-
|
|
379
440
|
const { data } = result;
|
|
380
441
|
|
|
381
442
|
if (options.json) {
|