@gmickel/gno 1.17.0 → 1.19.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 +18 -4
- package/assets/skill/SKILL.md +44 -1
- package/assets/skill/mcp-reference.md +21 -0
- package/package.json +3 -2
- package/spec/AGENTS.md +83 -0
- package/spec/CLAUDE.md +83 -0
- package/spec/bench-fixture.schema.json +137 -0
- package/spec/cli.md +2894 -0
- package/spec/db/schema.sql +442 -0
- package/spec/evals-agentic.md +510 -0
- package/spec/evals.md +1106 -0
- package/spec/mcp.md +2229 -0
- package/spec/output-schemas/activation-verification.schema.json +515 -0
- package/spec/output-schemas/ask.schema.json +366 -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/collection-list.schema.json +45 -0
- package/spec/output-schemas/context-capsule-v1.schema.json +691 -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-types.ts +3 -0
- package/src/app/context-runtime.ts +15 -1
- package/src/cli/commands/ask.ts +106 -36
- package/src/cli/commands/context-build.ts +56 -9
- package/src/cli/commands/daemon.ts +69 -2
- package/src/cli/commands/get.ts +64 -3
- package/src/cli/commands/models/pull.ts +13 -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/status.ts +2 -0
- package/src/cli/commands/trace.ts +200 -0
- package/src/cli/commands/vsearch.ts +75 -53
- package/src/cli/detach.ts +37 -20
- package/src/cli/program.ts +329 -27
- package/src/config/index.ts +12 -0
- package/src/config/retrieval-traces.ts +56 -0
- package/src/config/types.ts +41 -0
- package/src/core/context-compiler.ts +11 -4
- package/src/core/job-manager.ts +19 -0
- package/src/core/mutation-generations.ts +33 -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 +175 -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 +494 -0
- package/src/core/retrieval-trace.ts +472 -0
- package/src/llm/cache.ts +13 -3
- package/src/llm/nodeLlamaCpp/adapter.ts +10 -1
- package/src/llm/nodeLlamaCpp/lifecycle.ts +71 -0
- package/src/mcp/context.ts +161 -0
- package/src/mcp/http-security.ts +477 -0
- package/src/mcp/http-session.ts +272 -0
- package/src/mcp/http-transport.ts +370 -0
- package/src/mcp/resources/index.ts +141 -134
- package/src/mcp/server.ts +19 -79
- package/src/mcp/tools/add-collection.ts +3 -1
- package/src/mcp/tools/capture.ts +3 -0
- package/src/mcp/tools/clear-collection-embeddings.ts +2 -0
- package/src/mcp/tools/context.ts +68 -16
- package/src/mcp/tools/embed.ts +62 -52
- package/src/mcp/tools/get.ts +35 -1
- package/src/mcp/tools/index-cmd.ts +88 -74
- package/src/mcp/tools/index.ts +96 -2
- package/src/mcp/tools/query.ts +95 -64
- package/src/mcp/tools/remove-collection.ts +2 -0
- package/src/mcp/tools/search.ts +36 -13
- package/src/mcp/tools/status.ts +11 -0
- package/src/mcp/tools/sync.ts +16 -14
- package/src/mcp/tools/trace.ts +143 -0
- package/src/mcp/tools/vsearch.ts +71 -38
- package/src/mcp/tools/workspace-write.ts +7 -3
- package/src/pipeline/answer.ts +167 -26
- 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 +43 -0
- package/src/pipeline/vsearch.ts +101 -38
- package/src/sdk/client.ts +380 -71
- package/src/sdk/documents.ts +48 -1
- package/src/sdk/index.ts +17 -0
- package/src/sdk/types.ts +28 -0
- package/src/serve/background-runtime.ts +12 -212
- package/src/serve/context-capsule.ts +67 -8
- package/src/serve/embed-scheduler.ts +74 -43
- package/src/serve/index.ts +9 -0
- package/src/serve/jobs.ts +78 -80
- package/src/serve/public/app.tsx +12 -1
- package/src/serve/public/components/HealthCenter.tsx +74 -1
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/lib/workspace-tabs.ts +2 -0
- package/src/serve/public/pages/Dashboard.tsx +11 -0
- package/src/serve/public/pages/TraceHistory.tsx +478 -0
- package/src/serve/public/pages/trace-history-detail.tsx +224 -0
- package/src/serve/resident-admission.ts +159 -0
- package/src/serve/resident-background-work.ts +39 -0
- package/src/serve/resident-request.ts +55 -0
- package/src/serve/resident-runtime.ts +490 -0
- package/src/serve/resident-status.ts +96 -0
- package/src/serve/retrieval-trace.ts +28 -0
- package/src/serve/routes/api.ts +629 -239
- package/src/serve/routes/mcp.ts +69 -0
- package/src/serve/routes/traces.ts +156 -0
- package/src/serve/server.ts +276 -37
- package/src/serve/status-model.ts +51 -0
- package/src/serve/status.ts +5 -0
- 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 +179 -10
- 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
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gno://schemas/tags-list@1.0",
|
|
4
|
+
"title": "GNO Tags List",
|
|
5
|
+
"description": "List of tags with document counts",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["tags", "meta"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"tags": {
|
|
10
|
+
"type": "array",
|
|
11
|
+
"description": "List of tags with counts",
|
|
12
|
+
"items": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"required": ["tag", "count"],
|
|
15
|
+
"properties": {
|
|
16
|
+
"tag": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "Tag name (lowercase, alphanumeric with hyphens/dots/slashes)"
|
|
19
|
+
},
|
|
20
|
+
"count": {
|
|
21
|
+
"type": "integer",
|
|
22
|
+
"description": "Number of documents with this tag",
|
|
23
|
+
"minimum": 1
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"meta": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"required": ["totalTags"],
|
|
31
|
+
"properties": {
|
|
32
|
+
"totalTags": {
|
|
33
|
+
"type": "integer",
|
|
34
|
+
"description": "Total number of unique tags",
|
|
35
|
+
"minimum": 0
|
|
36
|
+
},
|
|
37
|
+
"collection": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"description": "Collection filter applied"
|
|
40
|
+
},
|
|
41
|
+
"prefix": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"description": "Prefix filter applied"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { Config } from "../config/types";
|
|
|
2
2
|
import type { ContextCapsuleV1 } from "../core/context-capsule";
|
|
3
3
|
import type { ContextEvidenceCompilerDeps } from "../core/context-evidence";
|
|
4
4
|
import type { ContextVerifierDeps } from "../core/context-verifier";
|
|
5
|
+
import type { RetrievalTraceSession } from "../core/retrieval-trace-session";
|
|
5
6
|
import type { EmbeddingPort, RerankPort } from "../llm/types";
|
|
6
7
|
import type { QueryModeInput } from "../pipeline/types";
|
|
7
8
|
import type { StorePort } from "../store/types";
|
|
@@ -45,6 +46,8 @@ export interface ContextCapsuleRuntimeDeps {
|
|
|
45
46
|
countTokens?: (accountingJson: string) => number;
|
|
46
47
|
tokenizerFingerprint?: string | null;
|
|
47
48
|
resolveCurrentRanks?: ContextVerifierDeps["resolveCurrentRanks"];
|
|
49
|
+
/** Optional non-canonical receipt session owned by the calling surface. */
|
|
50
|
+
traceSession?: RetrievalTraceSession;
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
export type ContextRuntimeErrorCode =
|
|
@@ -89,7 +89,11 @@ export const buildContextCapsule = async (
|
|
|
89
89
|
rerankPort: requestNoRerank ? null : (deps.rerankPort ?? null),
|
|
90
90
|
},
|
|
91
91
|
request.query,
|
|
92
|
-
{
|
|
92
|
+
{
|
|
93
|
+
...request,
|
|
94
|
+
noRerank: requestNoRerank,
|
|
95
|
+
traceSession: deps.traceSession,
|
|
96
|
+
}
|
|
93
97
|
);
|
|
94
98
|
if (!result.ok) {
|
|
95
99
|
throw new ContextRuntimeError(
|
|
@@ -115,6 +119,16 @@ export const buildContextCapsule = async (
|
|
|
115
119
|
: "No in-scope evidence was available for the Context Capsule"
|
|
116
120
|
);
|
|
117
121
|
}
|
|
122
|
+
const traceResult = await deps.traceSession?.recordContext(
|
|
123
|
+
plan.projection.value
|
|
124
|
+
);
|
|
125
|
+
if (traceResult && !traceResult.ok) {
|
|
126
|
+
throw new ContextRuntimeError(
|
|
127
|
+
"retrieval_failed",
|
|
128
|
+
`Trace recording failed: ${traceResult.error.message}`,
|
|
129
|
+
traceResult.error.cause
|
|
130
|
+
);
|
|
131
|
+
}
|
|
118
132
|
return plan.projection.value;
|
|
119
133
|
};
|
|
120
134
|
|
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,18 @@ import type {
|
|
|
12
14
|
} from "../../llm/types";
|
|
13
15
|
import type { AskOptions, AskResult, Citation } from "../../pipeline/types";
|
|
14
16
|
|
|
17
|
+
import {
|
|
18
|
+
finishRetrievalTraceAfterError,
|
|
19
|
+
retrievalTraceFilters,
|
|
20
|
+
startRetrievalTraceRequest,
|
|
21
|
+
} from "../../core/retrieval-trace-request";
|
|
15
22
|
import { LlmAdapter } from "../../llm/nodeLlamaCpp/adapter";
|
|
16
23
|
import { resolveDownloadPolicy } from "../../llm/policy";
|
|
17
24
|
import { resolveModelUri } from "../../llm/registry";
|
|
18
25
|
import {
|
|
26
|
+
answerTraceTerminalStatus,
|
|
19
27
|
generateGroundedAnswer,
|
|
20
|
-
|
|
28
|
+
processAnswerResultWithTrace,
|
|
21
29
|
} from "../../pipeline/answer";
|
|
22
30
|
import { type HybridSearchDeps, searchHybrid } from "../../pipeline/hybrid";
|
|
23
31
|
import {
|
|
@@ -55,7 +63,11 @@ export type AskCommandOptions = AskOptions & {
|
|
|
55
63
|
};
|
|
56
64
|
|
|
57
65
|
export type AskCommandResult =
|
|
58
|
-
| {
|
|
66
|
+
| {
|
|
67
|
+
success: true;
|
|
68
|
+
data: AskResult;
|
|
69
|
+
metadata?: RetrievalTraceSurfaceMetadata;
|
|
70
|
+
}
|
|
59
71
|
| { success: false; error: string };
|
|
60
72
|
|
|
61
73
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -88,8 +100,50 @@ export async function ask(
|
|
|
88
100
|
let expandPort: GenerationPort | null = null;
|
|
89
101
|
let answerPort: GenerationPort | null = null;
|
|
90
102
|
let rerankPort: RerankPort | null = null;
|
|
103
|
+
let traceSession: RetrievalTraceSession | undefined;
|
|
91
104
|
|
|
92
105
|
try {
|
|
106
|
+
const answerRequested = Boolean(options.answer && !options.noAnswer);
|
|
107
|
+
const embedUri = resolveModelUri(
|
|
108
|
+
config,
|
|
109
|
+
"embed",
|
|
110
|
+
options.embedModel,
|
|
111
|
+
options.collection
|
|
112
|
+
);
|
|
113
|
+
const expandUri =
|
|
114
|
+
!options.noExpand && !options.queryModes?.length
|
|
115
|
+
? resolveModelUri(
|
|
116
|
+
config,
|
|
117
|
+
"expand",
|
|
118
|
+
options.expandModel ?? options.genModel,
|
|
119
|
+
options.collection
|
|
120
|
+
)
|
|
121
|
+
: undefined;
|
|
122
|
+
const answerUri = answerRequested
|
|
123
|
+
? resolveModelUri(config, "gen", options.genModel, options.collection)
|
|
124
|
+
: undefined;
|
|
125
|
+
const rerankUri = !options.noRerank
|
|
126
|
+
? resolveModelUri(
|
|
127
|
+
config,
|
|
128
|
+
"rerank",
|
|
129
|
+
options.rerankModel,
|
|
130
|
+
options.collection
|
|
131
|
+
)
|
|
132
|
+
: undefined;
|
|
133
|
+
const traceStart = await startRetrievalTraceRequest({
|
|
134
|
+
store,
|
|
135
|
+
config,
|
|
136
|
+
query,
|
|
137
|
+
filters: retrievalTraceFilters({ ...options, limit }),
|
|
138
|
+
pipeline: "ask",
|
|
139
|
+
modelUris: [embedUri, expandUri, answerUri, rerankUri].filter(
|
|
140
|
+
(value): value is string => Boolean(value)
|
|
141
|
+
),
|
|
142
|
+
});
|
|
143
|
+
if (!traceStart.ok) {
|
|
144
|
+
return { success: false, error: traceStart.error.message };
|
|
145
|
+
}
|
|
146
|
+
traceSession = traceStart.value ?? undefined;
|
|
93
147
|
const llm = new LlmAdapter(config);
|
|
94
148
|
|
|
95
149
|
// Resolve download policy from env/flags
|
|
@@ -105,12 +159,6 @@ export async function ask(
|
|
|
105
159
|
: undefined;
|
|
106
160
|
|
|
107
161
|
// Create embedding port
|
|
108
|
-
const embedUri = resolveModelUri(
|
|
109
|
-
config,
|
|
110
|
-
"embed",
|
|
111
|
-
options.embedModel,
|
|
112
|
-
options.collection
|
|
113
|
-
);
|
|
114
162
|
const embedResult = await llm.createEmbeddingPort(embedUri, {
|
|
115
163
|
policy,
|
|
116
164
|
onProgress: downloadProgress
|
|
@@ -122,13 +170,7 @@ export async function ask(
|
|
|
122
170
|
}
|
|
123
171
|
|
|
124
172
|
// 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
|
-
);
|
|
173
|
+
if (expandUri) {
|
|
132
174
|
const genResult = await llm.createExpansionPort(expandUri, {
|
|
133
175
|
policy,
|
|
134
176
|
onProgress: downloadProgress
|
|
@@ -141,14 +183,8 @@ export async function ask(
|
|
|
141
183
|
}
|
|
142
184
|
|
|
143
185
|
// 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, {
|
|
186
|
+
if (answerUri) {
|
|
187
|
+
const genResult = await llm.createGenerationPort(answerUri, {
|
|
152
188
|
policy,
|
|
153
189
|
onProgress: downloadProgress
|
|
154
190
|
? (progress) => downloadProgress("gen", progress)
|
|
@@ -160,13 +196,7 @@ export async function ask(
|
|
|
160
196
|
}
|
|
161
197
|
|
|
162
198
|
// 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
|
-
);
|
|
199
|
+
if (rerankUri) {
|
|
170
200
|
const rerankResult = await llm.createRerankPort(rerankUri, {
|
|
171
201
|
policy,
|
|
172
202
|
onProgress: downloadProgress
|
|
@@ -208,12 +238,14 @@ export async function ask(
|
|
|
208
238
|
expandPort,
|
|
209
239
|
rerankPort,
|
|
210
240
|
};
|
|
211
|
-
|
|
212
|
-
// Check if answer generation is explicitly requested
|
|
213
|
-
const answerRequested = options.answer && !options.noAnswer;
|
|
214
|
-
|
|
215
241
|
// Fail early if --answer is requested but no generation model available
|
|
216
242
|
if (answerRequested && answerPort === null) {
|
|
243
|
+
await traceSession?.recordCapability(
|
|
244
|
+
"answer_generation",
|
|
245
|
+
"unavailable",
|
|
246
|
+
"model_unavailable"
|
|
247
|
+
);
|
|
248
|
+
await traceSession?.finish("failed");
|
|
217
249
|
return {
|
|
218
250
|
success: false,
|
|
219
251
|
error:
|
|
@@ -239,9 +271,11 @@ export async function ask(
|
|
|
239
271
|
noExpand: options.noExpand,
|
|
240
272
|
noRerank: options.noRerank,
|
|
241
273
|
candidateLimit: options.candidateLimit,
|
|
274
|
+
traceSession,
|
|
242
275
|
});
|
|
243
276
|
|
|
244
277
|
if (!searchResult.ok) {
|
|
278
|
+
await traceSession?.finish("failed");
|
|
245
279
|
return { success: false, error: searchResult.error.message };
|
|
246
280
|
}
|
|
247
281
|
|
|
@@ -261,6 +295,7 @@ export async function ask(
|
|
|
261
295
|
answerRequested && answerPort !== null && results.length > 0;
|
|
262
296
|
|
|
263
297
|
if (shouldGenerateAnswer && answerPort) {
|
|
298
|
+
await traceSession?.recordCapability("answer_generation", "attempted");
|
|
264
299
|
const maxTokens = options.maxAnswerTokens ?? 512;
|
|
265
300
|
const rawResult = await generateGroundedAnswer(
|
|
266
301
|
{ genPort: answerPort, store },
|
|
@@ -271,15 +306,25 @@ export async function ask(
|
|
|
271
306
|
|
|
272
307
|
// Fail loudly if generation was requested but failed
|
|
273
308
|
if (!rawResult) {
|
|
309
|
+
await traceSession?.recordCapability(
|
|
310
|
+
"answer_generation",
|
|
311
|
+
"failed",
|
|
312
|
+
"generation_failed"
|
|
313
|
+
);
|
|
314
|
+
await traceSession?.finish("failed");
|
|
274
315
|
return {
|
|
275
316
|
success: false,
|
|
276
317
|
error:
|
|
277
318
|
"Answer generation failed. The generation model may have encountered an error.",
|
|
278
319
|
};
|
|
279
320
|
}
|
|
321
|
+
await traceSession?.recordCapability("answer_generation", "used");
|
|
280
322
|
|
|
281
323
|
// Process answer: extract valid citations, filter, renumber
|
|
282
|
-
const processed =
|
|
324
|
+
const processed = await processAnswerResultWithTrace(
|
|
325
|
+
rawResult,
|
|
326
|
+
traceSession
|
|
327
|
+
);
|
|
283
328
|
answer = processed.answer;
|
|
284
329
|
citations = processed.citations;
|
|
285
330
|
answerContext = processed.answerContext;
|
|
@@ -307,7 +352,32 @@ export async function ask(
|
|
|
307
352
|
},
|
|
308
353
|
};
|
|
309
354
|
|
|
310
|
-
|
|
355
|
+
if (answerRequested) {
|
|
356
|
+
if (!answerGenerated) {
|
|
357
|
+
await traceSession?.recordCapability(
|
|
358
|
+
"answer_generation",
|
|
359
|
+
"unavailable",
|
|
360
|
+
"no_evidence"
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
const finalized = await traceSession?.finish(
|
|
364
|
+
answerTraceTerminalStatus(citations)
|
|
365
|
+
);
|
|
366
|
+
if (finalized && !finalized.ok) {
|
|
367
|
+
return { success: false, error: finalized.error.message };
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
success: true,
|
|
372
|
+
data: askResult,
|
|
373
|
+
metadata: traceSession?.metadata(),
|
|
374
|
+
};
|
|
375
|
+
} catch (cause) {
|
|
376
|
+
await finishRetrievalTraceAfterError(traceSession, cause);
|
|
377
|
+
return {
|
|
378
|
+
success: false,
|
|
379
|
+
error: cause instanceof Error ? cause.message : "Ask failed",
|
|
380
|
+
};
|
|
311
381
|
} finally {
|
|
312
382
|
if (embedPort) {
|
|
313
383
|
await embedPort.dispose();
|
|
@@ -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 {
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import type { CollectionSyncResult } from "../../ingestion";
|
|
2
|
+
import type { HttpGatewayOverrides } from "../../mcp/http-security";
|
|
2
3
|
import type { BackgroundRuntimeResult } from "../../serve/background-runtime";
|
|
4
|
+
import type { ResidentRuntime } from "../../serve/resident-runtime";
|
|
3
5
|
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_HTTP_GATEWAY_PORT,
|
|
8
|
+
isHttpGatewayLoopbackBind,
|
|
9
|
+
resolveHttpGatewayConfig,
|
|
10
|
+
} from "../../mcp/http-security";
|
|
4
11
|
import { startBackgroundRuntime } from "../../serve/background-runtime";
|
|
12
|
+
import { handleResidentStatus, handleStatus } from "../../serve/routes/api";
|
|
13
|
+
import { createMcpHttpGateway } from "../../serve/routes/mcp";
|
|
5
14
|
|
|
6
|
-
export interface DaemonOptions {
|
|
15
|
+
export interface DaemonOptions extends HttpGatewayOverrides {
|
|
7
16
|
configPath?: string;
|
|
8
17
|
index?: string;
|
|
9
18
|
offline?: boolean;
|
|
@@ -24,6 +33,8 @@ type DaemonLogger = {
|
|
|
24
33
|
|
|
25
34
|
type DaemonDeps = {
|
|
26
35
|
startBackgroundRuntime?: typeof startBackgroundRuntime;
|
|
36
|
+
createMcpHttpGateway?: typeof createMcpHttpGateway;
|
|
37
|
+
serve?: typeof Bun.serve;
|
|
27
38
|
logger?: DaemonLogger;
|
|
28
39
|
};
|
|
29
40
|
|
|
@@ -31,6 +42,18 @@ function formatCollectionSyncSummary(result: CollectionSyncResult): string {
|
|
|
31
42
|
return `${result.collection}: ${result.filesAdded} added, ${result.filesUpdated} updated, ${result.filesUnchanged} unchanged, ${result.filesErrored} errors`;
|
|
32
43
|
}
|
|
33
44
|
|
|
45
|
+
export function handleDaemonAppStatus(
|
|
46
|
+
runtime: ResidentRuntime,
|
|
47
|
+
host: string
|
|
48
|
+
): Promise<Response> | Response {
|
|
49
|
+
if (!isHttpGatewayLoopbackBind(host)) {
|
|
50
|
+
return new Response(null, { status: 404 });
|
|
51
|
+
}
|
|
52
|
+
return handleStatus(runtime.ctxHolder.current, {
|
|
53
|
+
getResidentStatus: () => runtime.getStatus(),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
34
57
|
function createSignalPromise(
|
|
35
58
|
signal: AbortSignal | undefined,
|
|
36
59
|
logger: DaemonLogger,
|
|
@@ -79,6 +102,7 @@ export async function daemon(
|
|
|
79
102
|
const runtimeResult: BackgroundRuntimeResult = await (
|
|
80
103
|
deps.startBackgroundRuntime ?? startBackgroundRuntime
|
|
81
104
|
)({
|
|
105
|
+
mode: "daemon",
|
|
82
106
|
configPath: options.configPath,
|
|
83
107
|
index: options.index,
|
|
84
108
|
requireCollections: true,
|
|
@@ -108,11 +132,52 @@ export async function daemon(
|
|
|
108
132
|
}
|
|
109
133
|
|
|
110
134
|
const { runtime } = runtimeResult;
|
|
135
|
+
const gatewayConfig = resolveHttpGatewayConfig(runtime.config.gateway, {
|
|
136
|
+
host: options.host,
|
|
137
|
+
port: options.port ?? DEFAULT_HTTP_GATEWAY_PORT,
|
|
138
|
+
tokenFile: options.tokenFile,
|
|
139
|
+
allowedHosts: options.allowedHosts,
|
|
140
|
+
allowedOrigins: options.allowedOrigins,
|
|
141
|
+
enableWrite: options.enableWrite,
|
|
142
|
+
});
|
|
143
|
+
let gateway: Awaited<ReturnType<typeof createMcpHttpGateway>> | undefined;
|
|
144
|
+
let server: ReturnType<typeof Bun.serve> | undefined;
|
|
111
145
|
try {
|
|
146
|
+
gateway = await (deps.createMcpHttpGateway ?? createMcpHttpGateway)(
|
|
147
|
+
runtime as ResidentRuntime,
|
|
148
|
+
gatewayConfig
|
|
149
|
+
);
|
|
150
|
+
server = (deps.serve ?? Bun.serve)({
|
|
151
|
+
port: gatewayConfig.port,
|
|
152
|
+
hostname: gatewayConfig.host,
|
|
153
|
+
development: false,
|
|
154
|
+
routes: {
|
|
155
|
+
"/mcp": gateway.route,
|
|
156
|
+
"/api/status": {
|
|
157
|
+
GET: () =>
|
|
158
|
+
handleDaemonAppStatus(
|
|
159
|
+
runtime as ResidentRuntime,
|
|
160
|
+
gatewayConfig.host
|
|
161
|
+
),
|
|
162
|
+
},
|
|
163
|
+
"/api/resident/status": {
|
|
164
|
+
GET: () =>
|
|
165
|
+
handleResidentStatus(() =>
|
|
166
|
+
(runtime as ResidentRuntime).getStatus()
|
|
167
|
+
),
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
(runtime as Partial<ResidentRuntime>).setListenerPort?.(
|
|
172
|
+
server.port ?? gatewayConfig.port
|
|
173
|
+
);
|
|
112
174
|
if (!options.quiet) {
|
|
113
175
|
logger.log(
|
|
114
176
|
`GNO daemon started for index "${options.index ?? "default"}" using ${runtime.config.collections.length} collection${runtime.config.collections.length === 1 ? "" : "s"}.`
|
|
115
177
|
);
|
|
178
|
+
logger.log(
|
|
179
|
+
`MCP gateway listening at http://${gatewayConfig.host}:${server.port}/mcp`
|
|
180
|
+
);
|
|
116
181
|
const watchState = runtime.watchService.getState();
|
|
117
182
|
if (watchState.activeCollections.length > 0) {
|
|
118
183
|
logger.log(`watching: ${watchState.activeCollections.join(", ")}`);
|
|
@@ -154,6 +219,8 @@ export async function daemon(
|
|
|
154
219
|
error: error instanceof Error ? error.message : String(error),
|
|
155
220
|
};
|
|
156
221
|
} finally {
|
|
157
|
-
await
|
|
222
|
+
await Promise.allSettled([server?.stop(true)]);
|
|
223
|
+
await Promise.allSettled([gateway?.close()]);
|
|
224
|
+
await Promise.allSettled([runtime.dispose()]);
|
|
158
225
|
}
|
|
159
226
|
}
|
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) {
|