@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/sdk/documents.ts
CHANGED
|
@@ -24,6 +24,11 @@ import type {
|
|
|
24
24
|
|
|
25
25
|
import { getDocumentCapabilities } from "../core/document-capabilities";
|
|
26
26
|
import { isGlobPattern, parseRef, splitRefs } from "../core/ref-parser";
|
|
27
|
+
import {
|
|
28
|
+
attachRetrievalTraceMetadata,
|
|
29
|
+
evidenceFromExactDocument,
|
|
30
|
+
RetrievalTraceSession,
|
|
31
|
+
} from "../core/retrieval-trace-session";
|
|
27
32
|
import { sdkError } from "./errors";
|
|
28
33
|
|
|
29
34
|
const URI_PREFIX_PATTERN = /^gno:\/\/[^/]+\//;
|
|
@@ -72,7 +77,7 @@ function buildConversionMeta(
|
|
|
72
77
|
};
|
|
73
78
|
}
|
|
74
79
|
|
|
75
|
-
|
|
80
|
+
async function getDocumentByRefUntraced(
|
|
76
81
|
store: StorePort,
|
|
77
82
|
config: Config,
|
|
78
83
|
ref: string,
|
|
@@ -159,6 +164,48 @@ export async function getDocumentByRef(
|
|
|
159
164
|
};
|
|
160
165
|
}
|
|
161
166
|
|
|
167
|
+
export async function getDocumentByRef(
|
|
168
|
+
store: StorePort,
|
|
169
|
+
config: Config,
|
|
170
|
+
ref: string,
|
|
171
|
+
options: GnoGetOptions = {}
|
|
172
|
+
): Promise<GetResponse> {
|
|
173
|
+
const response = await getDocumentByRefUntraced(store, config, ref, options);
|
|
174
|
+
if (!options.traceId) return response;
|
|
175
|
+
const resumed = await RetrievalTraceSession.resume({
|
|
176
|
+
store,
|
|
177
|
+
config: config.retrievalTraces,
|
|
178
|
+
traceId: options.traceId,
|
|
179
|
+
});
|
|
180
|
+
if (!resumed.ok) {
|
|
181
|
+
throw sdkError("STORE", resumed.error.message, {
|
|
182
|
+
cause: resumed.error.cause,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
const traceSession = resumed.value;
|
|
186
|
+
if (!traceSession) return response;
|
|
187
|
+
const lines = response.returnedLines ?? {
|
|
188
|
+
start: 1,
|
|
189
|
+
end: response.totalLines,
|
|
190
|
+
};
|
|
191
|
+
const evidence = evidenceFromExactDocument({
|
|
192
|
+
docid: response.docid,
|
|
193
|
+
uri: response.uri,
|
|
194
|
+
sourceHash: response.source.sourceHash,
|
|
195
|
+
mirrorHash: response.conversion?.mirrorHash,
|
|
196
|
+
content: response.content,
|
|
197
|
+
startLine: lines.start,
|
|
198
|
+
endLine: lines.end,
|
|
199
|
+
});
|
|
200
|
+
if (evidence) {
|
|
201
|
+
const got = await traceSession.recordEvidence("get", [evidence]);
|
|
202
|
+
if (!got.ok) throw sdkError("STORE", got.error.message);
|
|
203
|
+
const opened = await traceSession.recordEvidence("open", [evidence]);
|
|
204
|
+
if (!opened.ok) throw sdkError("STORE", opened.error.message);
|
|
205
|
+
}
|
|
206
|
+
return attachRetrievalTraceMetadata(response, traceSession);
|
|
207
|
+
}
|
|
208
|
+
|
|
162
209
|
function truncateContent(
|
|
163
210
|
content: string,
|
|
164
211
|
maxBytes: number
|
package/src/sdk/index.ts
CHANGED
|
@@ -72,3 +72,20 @@ export {
|
|
|
72
72
|
ContextRuntimeError,
|
|
73
73
|
type ContextRuntimeErrorCode,
|
|
74
74
|
} from "../app/context-runtime";
|
|
75
|
+
export {
|
|
76
|
+
getRetrievalTraceMetadata,
|
|
77
|
+
RETRIEVAL_TRACE_METADATA,
|
|
78
|
+
type RetrievalTraceSurfaceMetadata,
|
|
79
|
+
} from "../core/retrieval-trace-session";
|
|
80
|
+
export type {
|
|
81
|
+
RetrievalTraceDeleteResult,
|
|
82
|
+
RetrievalTraceDetail,
|
|
83
|
+
RetrievalTraceExportRequest,
|
|
84
|
+
RetrievalTraceExportResult,
|
|
85
|
+
RetrievalTraceLabelRequest,
|
|
86
|
+
RetrievalTraceLabelResult,
|
|
87
|
+
RetrievalTraceListRequest,
|
|
88
|
+
RetrievalTraceListResult,
|
|
89
|
+
RetrievalTracePurgeResult,
|
|
90
|
+
RetrievalTraceSummary,
|
|
91
|
+
} from "../core/retrieval-trace-management";
|
package/src/sdk/types.ts
CHANGED
|
@@ -19,6 +19,17 @@ import type { ContextEvidenceErrorCode } from "../core/context-evidence";
|
|
|
19
19
|
import type { ContextVerifierErrorCode } from "../core/context-verifier";
|
|
20
20
|
import type { NoteCollisionPolicy } from "../core/note-creation";
|
|
21
21
|
import type { NotePresetId } from "../core/note-presets";
|
|
22
|
+
import type {
|
|
23
|
+
RetrievalTraceDeleteResult,
|
|
24
|
+
RetrievalTraceDetail,
|
|
25
|
+
RetrievalTraceExportRequest,
|
|
26
|
+
RetrievalTraceExportResult,
|
|
27
|
+
RetrievalTraceLabelRequest,
|
|
28
|
+
RetrievalTraceLabelResult,
|
|
29
|
+
RetrievalTraceListRequest,
|
|
30
|
+
RetrievalTraceListResult,
|
|
31
|
+
RetrievalTracePurgeResult as RetrievalTraceManagementPurgeResult,
|
|
32
|
+
} from "../core/retrieval-trace-management";
|
|
22
33
|
import type { DocumentSection } from "../core/sections";
|
|
23
34
|
import type { SyncResult } from "../ingestion";
|
|
24
35
|
import type { DownloadPolicy } from "../llm/policy";
|
|
@@ -88,6 +99,8 @@ export type GnoContextErrorCode =
|
|
|
88
99
|
export interface GnoGetOptions {
|
|
89
100
|
from?: number;
|
|
90
101
|
limit?: number;
|
|
102
|
+
/** Continue an open retrieval trace returned by search/query. */
|
|
103
|
+
traceId?: string;
|
|
91
104
|
}
|
|
92
105
|
|
|
93
106
|
export interface GnoMultiGetOptions {
|
|
@@ -221,6 +234,21 @@ export interface GnoClient {
|
|
|
221
234
|
options?: GnoListOptions
|
|
222
235
|
): Promise<import("../cli/commands/ls").LsResponse>;
|
|
223
236
|
status(): Promise<IndexStatus>;
|
|
237
|
+
listRetrievalTraces(
|
|
238
|
+
options?: RetrievalTraceListRequest
|
|
239
|
+
): Promise<RetrievalTraceListResult>;
|
|
240
|
+
getRetrievalTrace(
|
|
241
|
+
traceId: string,
|
|
242
|
+
options?: { detailLimit?: number }
|
|
243
|
+
): Promise<RetrievalTraceDetail>;
|
|
244
|
+
labelRetrievalTrace(
|
|
245
|
+
input: RetrievalTraceLabelRequest
|
|
246
|
+
): Promise<RetrievalTraceLabelResult>;
|
|
247
|
+
exportRetrievalTraces(
|
|
248
|
+
input: RetrievalTraceExportRequest
|
|
249
|
+
): Promise<RetrievalTraceExportResult>;
|
|
250
|
+
deleteRetrievalTrace(traceId: string): Promise<RetrievalTraceDeleteResult>;
|
|
251
|
+
purgeRetrievalTraces(): Promise<RetrievalTraceManagementPurgeResult>;
|
|
224
252
|
update(options?: GnoUpdateOptions): Promise<SyncResult>;
|
|
225
253
|
embed(options?: GnoEmbedOptions): Promise<GnoEmbedResult>;
|
|
226
254
|
index(options?: GnoIndexOptions): Promise<GnoIndexResult>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** REST adapters for the shared Context Capsule application boundary. */
|
|
2
2
|
|
|
3
|
+
import type { RetrievalTraceSession } from "../core/retrieval-trace-session";
|
|
3
4
|
import type { GnoContextErrorCode } from "../sdk/types";
|
|
4
5
|
import type { ServerContext } from "./context";
|
|
5
6
|
|
|
@@ -20,6 +21,8 @@ import {
|
|
|
20
21
|
parseContextVerifySurfaceInput,
|
|
21
22
|
} from "../app/context-surface";
|
|
22
23
|
import { ContextCapsuleContractError } from "../core/context-capsule";
|
|
24
|
+
import { startRetrievalTraceRequest } from "../core/retrieval-trace-request";
|
|
25
|
+
import { withRetrievalTraceHeader } from "./retrieval-trace";
|
|
23
26
|
|
|
24
27
|
const JSON_HEADERS = { "content-type": "application/json; charset=utf-8" };
|
|
25
28
|
const MARKDOWN_HEADERS = {
|
|
@@ -80,6 +83,7 @@ export const handleContextBuild = async (
|
|
|
80
83
|
context: ServerContext,
|
|
81
84
|
request: Request
|
|
82
85
|
): Promise<Response> => {
|
|
86
|
+
let traceSession: RetrievalTraceSession | null = null;
|
|
83
87
|
try {
|
|
84
88
|
const { input, format } = parseContextBuildSurfaceInput(
|
|
85
89
|
await parseJsonBody(request),
|
|
@@ -90,6 +94,42 @@ export const handleContextBuild = async (
|
|
|
90
94
|
context.indexName,
|
|
91
95
|
context.config.collections.map((collection) => collection.name)
|
|
92
96
|
);
|
|
97
|
+
const started = await startRetrievalTraceRequest({
|
|
98
|
+
store: context.store,
|
|
99
|
+
config: context.config,
|
|
100
|
+
query: input.query ?? input.goal,
|
|
101
|
+
goal: input.goal,
|
|
102
|
+
filters: {
|
|
103
|
+
limit: input.limit,
|
|
104
|
+
collection:
|
|
105
|
+
input.collections?.length === 1 ? input.collections[0] : undefined,
|
|
106
|
+
collections: [...(input.collections ?? [])].sort(),
|
|
107
|
+
lang: input.lang,
|
|
108
|
+
tagsAll: input.tagsAll,
|
|
109
|
+
tagsAny: input.tagsAny,
|
|
110
|
+
since: input.since,
|
|
111
|
+
until: input.until,
|
|
112
|
+
categories: input.categories,
|
|
113
|
+
author: input.author,
|
|
114
|
+
graph: input.graph,
|
|
115
|
+
candidateLimit: input.candidateLimit,
|
|
116
|
+
queryModes: input.queryModes,
|
|
117
|
+
uriPrefix: input.uriPrefix ?? undefined,
|
|
118
|
+
},
|
|
119
|
+
pipeline: "context",
|
|
120
|
+
indexName: context.indexName,
|
|
121
|
+
modelUris: [
|
|
122
|
+
context.embedPort?.modelUri,
|
|
123
|
+
context.rerankPort?.modelUri,
|
|
124
|
+
].filter((value): value is string => Boolean(value)),
|
|
125
|
+
});
|
|
126
|
+
if (!started.ok) {
|
|
127
|
+
throw Object.assign(
|
|
128
|
+
new Error(`Retrieval trace start failed: ${started.error.message}`),
|
|
129
|
+
{ code: "retrieval_failed" }
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
traceSession = started.value;
|
|
93
133
|
const capsule = await buildContextCapsule(input, {
|
|
94
134
|
store: context.store,
|
|
95
135
|
config: context.config,
|
|
@@ -97,16 +137,35 @@ export const handleContextBuild = async (
|
|
|
97
137
|
vectorIndex: context.vectorIndex,
|
|
98
138
|
embedPort: context.embedPort,
|
|
99
139
|
rerankPort: context.rerankPort,
|
|
140
|
+
traceSession: traceSession ?? undefined,
|
|
100
141
|
});
|
|
101
|
-
|
|
102
|
-
?
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
142
|
+
const finished = await traceSession?.finish(
|
|
143
|
+
request.signal.aborted ? "cancelled" : "completed"
|
|
144
|
+
);
|
|
145
|
+
if (finished && !finished.ok) {
|
|
146
|
+
throw Object.assign(
|
|
147
|
+
new Error(
|
|
148
|
+
`Retrieval trace finalization failed: ${finished.error.message}`
|
|
149
|
+
),
|
|
150
|
+
{ code: "retrieval_failed" }
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
const response =
|
|
154
|
+
format === "md"
|
|
155
|
+
? new Response(formatContextCapsuleMarkdown(capsule), {
|
|
156
|
+
headers: MARKDOWN_HEADERS,
|
|
157
|
+
})
|
|
158
|
+
: new Response(canonicalBuiltContextCapsuleJson(capsule), {
|
|
159
|
+
headers: JSON_HEADERS,
|
|
160
|
+
});
|
|
161
|
+
return withRetrievalTraceHeader(response, traceSession);
|
|
108
162
|
} catch (error) {
|
|
109
|
-
|
|
163
|
+
if (traceSession) {
|
|
164
|
+
await traceSession.finish(
|
|
165
|
+
request.signal.aborted ? "cancelled" : "failed"
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
return withRetrievalTraceHeader(errorResponse(error), traceSession);
|
|
110
169
|
}
|
|
111
170
|
};
|
|
112
171
|
|
package/src/serve/public/app.tsx
CHANGED
|
@@ -29,6 +29,7 @@ import DocumentEditor from "./pages/DocumentEditor";
|
|
|
29
29
|
import DocView from "./pages/DocView";
|
|
30
30
|
import GraphView from "./pages/GraphView";
|
|
31
31
|
import Search from "./pages/Search";
|
|
32
|
+
import TraceHistory from "./pages/TraceHistory";
|
|
32
33
|
|
|
33
34
|
type Route =
|
|
34
35
|
| "/"
|
|
@@ -39,7 +40,8 @@ type Route =
|
|
|
39
40
|
| "/edit"
|
|
40
41
|
| "/collections"
|
|
41
42
|
| "/graph"
|
|
42
|
-
| "/connectors"
|
|
43
|
+
| "/connectors"
|
|
44
|
+
| "/traces";
|
|
43
45
|
type Navigate = (to: string | number) => void;
|
|
44
46
|
|
|
45
47
|
interface RoutePageProps {
|
|
@@ -57,6 +59,7 @@ const routes: Record<Route, React.ComponentType<RoutePageProps>> = {
|
|
|
57
59
|
"/connectors": Connectors,
|
|
58
60
|
"/ask": Ask,
|
|
59
61
|
"/graph": GraphView,
|
|
62
|
+
"/traces": TraceHistory,
|
|
60
63
|
};
|
|
61
64
|
|
|
62
65
|
interface AppContentProps {
|
|
@@ -165,6 +168,14 @@ function AppContent({
|
|
|
165
168
|
Collections
|
|
166
169
|
</button>
|
|
167
170
|
<span className="text-border/30">—</span>
|
|
171
|
+
<button
|
|
172
|
+
className="transition-colors duration-300 hover:text-primary"
|
|
173
|
+
onClick={() => navigate("/traces")}
|
|
174
|
+
type="button"
|
|
175
|
+
>
|
|
176
|
+
Trace history
|
|
177
|
+
</button>
|
|
178
|
+
<span className="text-border/30">—</span>
|
|
168
179
|
<a
|
|
169
180
|
className="transition-colors duration-300 hover:text-primary"
|
|
170
181
|
href="https://github.com/gmickel/gno"
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { AlertTriangle, CheckCircle2, CircleHelp, ShieldX } from "lucide-react";
|
|
2
|
+
|
|
3
|
+
import type { AskResult } from "../../../pipeline/types";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../lib/utils";
|
|
6
|
+
import { Badge } from "./ui/badge";
|
|
7
|
+
|
|
8
|
+
export type AskVerification = NonNullable<AskResult["verification"]>;
|
|
9
|
+
|
|
10
|
+
interface AskVerificationPanelProps {
|
|
11
|
+
navigate: (to: string) => void;
|
|
12
|
+
verification: AskVerification;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const STATUS_PRESENTATION = {
|
|
16
|
+
supported: {
|
|
17
|
+
label: "supported",
|
|
18
|
+
icon: CheckCircle2,
|
|
19
|
+
className: "border-emerald-500/30 bg-emerald-500/10 text-emerald-300",
|
|
20
|
+
},
|
|
21
|
+
contradicted: {
|
|
22
|
+
label: "contradicted",
|
|
23
|
+
icon: ShieldX,
|
|
24
|
+
className: "border-destructive/40 bg-destructive/10 text-destructive",
|
|
25
|
+
},
|
|
26
|
+
insufficient: {
|
|
27
|
+
label: "insufficient",
|
|
28
|
+
icon: AlertTriangle,
|
|
29
|
+
className: "border-amber-500/30 bg-amber-500/10 text-amber-300",
|
|
30
|
+
},
|
|
31
|
+
uncertain: {
|
|
32
|
+
label: "uncertain",
|
|
33
|
+
icon: CircleHelp,
|
|
34
|
+
className: "border-sky-500/30 bg-sky-500/10 text-sky-300",
|
|
35
|
+
},
|
|
36
|
+
} as const;
|
|
37
|
+
|
|
38
|
+
const evidenceLabel = (uri: string, startLine: number, endLine: number) =>
|
|
39
|
+
`${uri}:L${startLine}${startLine === endLine ? "" : `-L${endLine}`}`;
|
|
40
|
+
|
|
41
|
+
export function AskVerificationPanel({
|
|
42
|
+
navigate,
|
|
43
|
+
verification,
|
|
44
|
+
}: AskVerificationPanelProps) {
|
|
45
|
+
const { claims, capsule, semantic } = verification;
|
|
46
|
+
const degradedCapabilities = Object.entries(
|
|
47
|
+
capsule.retrieval.capabilityStates
|
|
48
|
+
).filter(([, state]) => state.requested && state.outcome !== "used");
|
|
49
|
+
const gaps = capsule.coverage.gaps;
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<details className="group rounded-lg border border-border/50 bg-card/55">
|
|
53
|
+
<summary className="flex cursor-pointer list-none items-center justify-between gap-3 px-4 py-3">
|
|
54
|
+
<div className="min-w-0">
|
|
55
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
56
|
+
<span className="font-medium text-sm">
|
|
57
|
+
{claims.answerStatus === "verified"
|
|
58
|
+
? "All claims verified"
|
|
59
|
+
: "Answer withheld"}
|
|
60
|
+
</span>
|
|
61
|
+
<Badge
|
|
62
|
+
className="font-mono text-[9px]"
|
|
63
|
+
variant={
|
|
64
|
+
claims.answerStatus === "verified" ? "default" : "outline"
|
|
65
|
+
}
|
|
66
|
+
>
|
|
67
|
+
{claims.coverage.supportedClaims}/{claims.coverage.totalClaims}{" "}
|
|
68
|
+
supported
|
|
69
|
+
</Badge>
|
|
70
|
+
</div>
|
|
71
|
+
<p className="mt-1 text-muted-foreground text-xs">
|
|
72
|
+
{claims.abstentionReason ??
|
|
73
|
+
`${claims.coverage.supportedRatio * 100}% support coverage`}
|
|
74
|
+
</p>
|
|
75
|
+
</div>
|
|
76
|
+
<span className="shrink-0 font-mono text-[10px] text-muted-foreground group-open:hidden">
|
|
77
|
+
details
|
|
78
|
+
</span>
|
|
79
|
+
</summary>
|
|
80
|
+
|
|
81
|
+
<div className="space-y-4 border-border/40 border-t px-4 py-4">
|
|
82
|
+
<div className="flex flex-wrap gap-2">
|
|
83
|
+
<Badge className="font-mono text-[9px]" variant="outline">
|
|
84
|
+
semantic: {semantic.status}/{semantic.reason}
|
|
85
|
+
</Badge>
|
|
86
|
+
{degradedCapabilities.map(([name, state]) => (
|
|
87
|
+
<Badge
|
|
88
|
+
className="font-mono text-[9px]"
|
|
89
|
+
key={name}
|
|
90
|
+
variant="outline"
|
|
91
|
+
>
|
|
92
|
+
{name}: {state.outcome}
|
|
93
|
+
{state.fallbackReasons.length > 0
|
|
94
|
+
? ` (${state.fallbackReasons.join(", ")})`
|
|
95
|
+
: ""}
|
|
96
|
+
</Badge>
|
|
97
|
+
))}
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div className="grid grid-cols-2 gap-2 font-mono text-[10px] text-muted-foreground sm:grid-cols-4">
|
|
101
|
+
<span>{claims.coverage.supportedClaims} supported</span>
|
|
102
|
+
<span>{claims.coverage.contradictedClaims} contradicted</span>
|
|
103
|
+
<span>{claims.coverage.insufficientClaims} insufficient</span>
|
|
104
|
+
<span>{claims.coverage.uncertainClaims} uncertain</span>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div className="space-y-2">
|
|
108
|
+
{claims.claims.map((claim) => {
|
|
109
|
+
const presentation = STATUS_PRESENTATION[claim.status];
|
|
110
|
+
const StatusIcon = presentation.icon;
|
|
111
|
+
return (
|
|
112
|
+
<details
|
|
113
|
+
className="rounded-md border border-border/35 bg-background/20"
|
|
114
|
+
key={claim.claimId}
|
|
115
|
+
>
|
|
116
|
+
<summary className="flex cursor-pointer list-none items-start gap-2 px-3 py-2">
|
|
117
|
+
<StatusIcon className="mt-0.5 size-3.5 shrink-0" />
|
|
118
|
+
<span className="min-w-0 flex-1 text-xs">{claim.text}</span>
|
|
119
|
+
<Badge
|
|
120
|
+
className={cn(
|
|
121
|
+
"shrink-0 font-mono text-[9px]",
|
|
122
|
+
presentation.className
|
|
123
|
+
)}
|
|
124
|
+
variant="outline"
|
|
125
|
+
>
|
|
126
|
+
{presentation.label}
|
|
127
|
+
</Badge>
|
|
128
|
+
</summary>
|
|
129
|
+
<div className="space-y-2 border-border/30 border-t px-3 py-2">
|
|
130
|
+
{claim.evidence.length > 0 ? (
|
|
131
|
+
claim.evidence.map((evidence) => (
|
|
132
|
+
<button
|
|
133
|
+
className="block w-full truncate text-left font-mono text-[10px] text-primary hover:underline"
|
|
134
|
+
key={evidence.evidenceId}
|
|
135
|
+
onClick={() =>
|
|
136
|
+
navigate(
|
|
137
|
+
`/doc?uri=${encodeURIComponent(evidence.uri)}`
|
|
138
|
+
)
|
|
139
|
+
}
|
|
140
|
+
title={evidenceLabel(
|
|
141
|
+
evidence.uri,
|
|
142
|
+
evidence.startLine,
|
|
143
|
+
evidence.endLine
|
|
144
|
+
)}
|
|
145
|
+
type="button"
|
|
146
|
+
>
|
|
147
|
+
{evidenceLabel(
|
|
148
|
+
evidence.uri,
|
|
149
|
+
evidence.startLine,
|
|
150
|
+
evidence.endLine
|
|
151
|
+
)}
|
|
152
|
+
</button>
|
|
153
|
+
))
|
|
154
|
+
) : (
|
|
155
|
+
<p className="text-muted-foreground text-xs">
|
|
156
|
+
No retained evidence span.
|
|
157
|
+
</p>
|
|
158
|
+
)}
|
|
159
|
+
<p className="font-mono text-[10px] text-muted-foreground">
|
|
160
|
+
{claim.rationaleCode}
|
|
161
|
+
{claim.confidence === null
|
|
162
|
+
? ""
|
|
163
|
+
: ` · confidence ${claim.confidence.toFixed(2)}`}
|
|
164
|
+
</p>
|
|
165
|
+
</div>
|
|
166
|
+
</details>
|
|
167
|
+
);
|
|
168
|
+
})}
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
{(capsule.coverage.unresolvedFacets.length > 0 || gaps.length > 0) && (
|
|
172
|
+
<div className="rounded-md border border-amber-500/25 bg-amber-500/5 px-3 py-2">
|
|
173
|
+
<p className="font-medium text-amber-200 text-xs">Evidence gaps</p>
|
|
174
|
+
<ul className="mt-1 space-y-1 font-mono text-[10px] text-muted-foreground">
|
|
175
|
+
{capsule.coverage.unresolvedFacets.map((facet) => (
|
|
176
|
+
<li key={`facet:${facet}`}>unresolved facet: {facet}</li>
|
|
177
|
+
))}
|
|
178
|
+
{gaps.map((gap) => (
|
|
179
|
+
<li key={`${gap.facet}:${gap.code}`}>
|
|
180
|
+
{gap.facet}: {gap.code}
|
|
181
|
+
</li>
|
|
182
|
+
))}
|
|
183
|
+
</ul>
|
|
184
|
+
</div>
|
|
185
|
+
)}
|
|
186
|
+
</div>
|
|
187
|
+
</details>
|
|
188
|
+
);
|
|
189
|
+
}
|