@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
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,46 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
import { resolve } from "node:path";
|
|
1
|
+
/** Backwards-compatible entrypoint for the shared resident runtime. */
|
|
3
2
|
|
|
4
3
|
import type { Config } from "../config/types";
|
|
5
4
|
import type { SyncResult } from "../ingestion";
|
|
6
|
-
import type {
|
|
5
|
+
import type { SqliteAdapter } from "../store/sqlite/adapter";
|
|
7
6
|
import type { EmbedResult, EmbedScheduler } from "./embed-scheduler";
|
|
8
7
|
import type { ContextHolder } from "./routes/api";
|
|
9
|
-
import type {
|
|
10
|
-
CollectionWatchCallbacks,
|
|
11
|
-
CollectionWatchService,
|
|
12
|
-
} from "./watch-service";
|
|
8
|
+
import type { CollectionWatchService } from "./watch-service";
|
|
13
9
|
|
|
14
|
-
import { getIndexDbPath } from "../app/constants";
|
|
15
|
-
import { INDEX_NAME_REQUIREMENTS, isValidIndexName } from "../app/index-name";
|
|
16
10
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
loadConfig,
|
|
22
|
-
} from "../config";
|
|
23
|
-
import { defaultSyncService } from "../ingestion";
|
|
24
|
-
import { withContentTypeRules } from "../ingestion";
|
|
25
|
-
import { getActivePreset } from "../llm/registry";
|
|
26
|
-
import { SqliteAdapter } from "../store/sqlite/adapter";
|
|
27
|
-
import {
|
|
28
|
-
createServerContext,
|
|
29
|
-
type CreateServerContextOptions,
|
|
30
|
-
disposeServerContext,
|
|
31
|
-
type ServerContext,
|
|
32
|
-
} from "./context";
|
|
33
|
-
import { createEmbedScheduler } from "./embed-scheduler";
|
|
34
|
-
import { CollectionWatchService as DefaultCollectionWatchService } from "./watch-service";
|
|
11
|
+
startResidentRuntime,
|
|
12
|
+
type ResidentRuntimeDeps,
|
|
13
|
+
type ResidentRuntimeOptions,
|
|
14
|
+
} from "./resident-runtime";
|
|
35
15
|
|
|
36
|
-
export
|
|
37
|
-
|
|
38
|
-
index?: string;
|
|
39
|
-
requireCollections?: boolean;
|
|
40
|
-
offline?: boolean;
|
|
41
|
-
eventBus?: DocumentEventBus | null;
|
|
42
|
-
watchCallbacks?: CollectionWatchCallbacks;
|
|
43
|
-
}
|
|
16
|
+
export type BackgroundRuntimeOptions = ResidentRuntimeOptions;
|
|
17
|
+
export type BackgroundRuntimeDeps = ResidentRuntimeDeps;
|
|
44
18
|
|
|
45
19
|
export interface BackgroundRuntime {
|
|
46
20
|
store: SqliteAdapter;
|
|
@@ -48,16 +22,13 @@ export interface BackgroundRuntime {
|
|
|
48
22
|
actualConfigPath: string;
|
|
49
23
|
ctxHolder: ContextHolder;
|
|
50
24
|
scheduler: EmbedScheduler;
|
|
51
|
-
eventBus: DocumentEventBus | null;
|
|
25
|
+
eventBus: import("./doc-events").DocumentEventBus | null;
|
|
52
26
|
watchService: CollectionWatchService;
|
|
53
27
|
syncAll(options?: {
|
|
54
28
|
gitPull?: boolean;
|
|
55
29
|
runUpdateCmd?: boolean;
|
|
56
30
|
triggerEmbed?: boolean;
|
|
57
|
-
}): Promise<{
|
|
58
|
-
syncResult: SyncResult;
|
|
59
|
-
embedResult: EmbedResult | null;
|
|
60
|
-
}>;
|
|
31
|
+
}): Promise<{ syncResult: SyncResult; embedResult: EmbedResult | null }>;
|
|
61
32
|
dispose(): Promise<void>;
|
|
62
33
|
}
|
|
63
34
|
|
|
@@ -65,180 +36,9 @@ export type BackgroundRuntimeResult =
|
|
|
65
36
|
| { success: true; runtime: BackgroundRuntime }
|
|
66
37
|
| { success: false; error: string };
|
|
67
38
|
|
|
68
|
-
type BackgroundRuntimeDeps = {
|
|
69
|
-
isInitialized?: typeof isInitialized;
|
|
70
|
-
loadConfig?: typeof loadConfig;
|
|
71
|
-
getConfigPaths?: typeof getConfigPaths;
|
|
72
|
-
ensureDirectories?: typeof ensureDirectories;
|
|
73
|
-
storeFactory?: () => SqliteAdapter;
|
|
74
|
-
createServerContext?: (
|
|
75
|
-
store: SqliteAdapter,
|
|
76
|
-
config: Config,
|
|
77
|
-
options?: CreateServerContextOptions
|
|
78
|
-
) => Promise<ServerContext>;
|
|
79
|
-
disposeServerContext?: (ctx: ServerContext) => Promise<void>;
|
|
80
|
-
createEmbedScheduler?: typeof createEmbedScheduler;
|
|
81
|
-
syncAllService?: typeof defaultSyncService.syncAll;
|
|
82
|
-
watchServiceFactory?: (options: {
|
|
83
|
-
collections: Config["collections"];
|
|
84
|
-
store: SqliteAdapter;
|
|
85
|
-
scheduler: EmbedScheduler | null;
|
|
86
|
-
eventBus?: DocumentEventBus | null;
|
|
87
|
-
callbacks?: CollectionWatchCallbacks;
|
|
88
|
-
syncOptions?: Parameters<typeof withContentTypeRules>[0];
|
|
89
|
-
}) => CollectionWatchService;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
39
|
export async function startBackgroundRuntime(
|
|
93
40
|
options: BackgroundRuntimeOptions = {},
|
|
94
41
|
deps: BackgroundRuntimeDeps = {}
|
|
95
42
|
): Promise<BackgroundRuntimeResult> {
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
success: false,
|
|
99
|
-
error: `Invalid index name: ${INDEX_NAME_REQUIREMENTS}.`,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
const syncAllService = deps.syncAllService
|
|
103
|
-
? (...args: Parameters<typeof defaultSyncService.syncAll>) =>
|
|
104
|
-
deps.syncAllService!(...args)
|
|
105
|
-
: defaultSyncService.syncAll.bind(defaultSyncService);
|
|
106
|
-
const initialized = await (deps.isInitialized ?? isInitialized)(
|
|
107
|
-
options.configPath
|
|
108
|
-
);
|
|
109
|
-
if (!initialized) {
|
|
110
|
-
return { success: false, error: "GNO not initialized. Run: gno init" };
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const configResult = await (deps.loadConfig ?? loadConfig)(
|
|
114
|
-
options.configPath
|
|
115
|
-
);
|
|
116
|
-
if (!configResult.ok) {
|
|
117
|
-
return { success: false, error: configResult.error.message };
|
|
118
|
-
}
|
|
119
|
-
for (const warning of formatConfigWarnings(configResult.warnings)) {
|
|
120
|
-
console.warn(warning);
|
|
121
|
-
}
|
|
122
|
-
const config = configResult.value;
|
|
123
|
-
|
|
124
|
-
if (options.requireCollections && config.collections.length === 0) {
|
|
125
|
-
return {
|
|
126
|
-
success: false,
|
|
127
|
-
error: "No collections configured. Run: gno collection add <path>",
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
await (deps.ensureDirectories ?? ensureDirectories)();
|
|
132
|
-
|
|
133
|
-
const store = deps.storeFactory ? deps.storeFactory() : new SqliteAdapter();
|
|
134
|
-
const dbPath = getIndexDbPath(options.index);
|
|
135
|
-
const paths = (deps.getConfigPaths ?? getConfigPaths)();
|
|
136
|
-
const actualConfigPath = resolve(options.configPath ?? paths.configFile);
|
|
137
|
-
store.setConfigPath(actualConfigPath);
|
|
138
|
-
|
|
139
|
-
const openResult = await store.open(dbPath, config.ftsTokenizer);
|
|
140
|
-
if (!openResult.ok) {
|
|
141
|
-
return { success: false, error: openResult.error.message };
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const syncCollResult = await store.syncCollections(config.collections);
|
|
145
|
-
if (!syncCollResult.ok) {
|
|
146
|
-
await store.close();
|
|
147
|
-
return { success: false, error: syncCollResult.error.message };
|
|
148
|
-
}
|
|
149
|
-
const syncCtxResult = await store.syncContexts(config.contexts ?? []);
|
|
150
|
-
if (!syncCtxResult.ok) {
|
|
151
|
-
await store.close();
|
|
152
|
-
return { success: false, error: syncCtxResult.error.message };
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const ctx = await (deps.createServerContext ?? createServerContext)(
|
|
156
|
-
store,
|
|
157
|
-
config,
|
|
158
|
-
{
|
|
159
|
-
offline: options.offline ?? false,
|
|
160
|
-
indexName: options.index,
|
|
161
|
-
}
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
const ctxHolder: ContextHolder = {
|
|
165
|
-
current: ctx,
|
|
166
|
-
config,
|
|
167
|
-
scheduler: null,
|
|
168
|
-
eventBus: options.eventBus ?? null,
|
|
169
|
-
watchService: null,
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
const scheduler = (deps.createEmbedScheduler ?? createEmbedScheduler)({
|
|
173
|
-
db: store.getRawDb(),
|
|
174
|
-
getEmbedPort: () => ctxHolder.current.embedPort,
|
|
175
|
-
getVectorIndex: () => ctxHolder.current.vectorIndex,
|
|
176
|
-
getModelUri: () => getActivePreset(ctxHolder.config).embed,
|
|
177
|
-
});
|
|
178
|
-
ctxHolder.scheduler = scheduler;
|
|
179
|
-
ctxHolder.current.scheduler = scheduler;
|
|
180
|
-
ctxHolder.current.eventBus = options.eventBus ?? null;
|
|
181
|
-
|
|
182
|
-
const watchService = (
|
|
183
|
-
deps.watchServiceFactory ??
|
|
184
|
-
((watchOptions) => new DefaultCollectionWatchService(watchOptions))
|
|
185
|
-
)({
|
|
186
|
-
collections: config.collections,
|
|
187
|
-
store,
|
|
188
|
-
scheduler,
|
|
189
|
-
eventBus: options.eventBus ?? null,
|
|
190
|
-
callbacks: options.watchCallbacks,
|
|
191
|
-
syncOptions: withContentTypeRules({}, config),
|
|
192
|
-
});
|
|
193
|
-
watchService.start();
|
|
194
|
-
ctxHolder.watchService = watchService;
|
|
195
|
-
ctxHolder.current.watchService = watchService;
|
|
196
|
-
|
|
197
|
-
let disposed = false;
|
|
198
|
-
|
|
199
|
-
return {
|
|
200
|
-
success: true,
|
|
201
|
-
runtime: {
|
|
202
|
-
store,
|
|
203
|
-
config,
|
|
204
|
-
actualConfigPath,
|
|
205
|
-
ctxHolder,
|
|
206
|
-
scheduler,
|
|
207
|
-
eventBus: options.eventBus ?? null,
|
|
208
|
-
watchService,
|
|
209
|
-
async syncAll(syncOptions = {}) {
|
|
210
|
-
const syncResult = await syncAllService(
|
|
211
|
-
config.collections,
|
|
212
|
-
store,
|
|
213
|
-
withContentTypeRules(
|
|
214
|
-
{
|
|
215
|
-
gitPull: syncOptions.gitPull,
|
|
216
|
-
runUpdateCmd: syncOptions.runUpdateCmd,
|
|
217
|
-
},
|
|
218
|
-
config
|
|
219
|
-
)
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
let embedResult: EmbedResult | null = null;
|
|
223
|
-
if (syncOptions.triggerEmbed !== false) {
|
|
224
|
-
embedResult = await scheduler.triggerNow();
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
return { syncResult, embedResult };
|
|
228
|
-
},
|
|
229
|
-
async dispose() {
|
|
230
|
-
if (disposed) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
disposed = true;
|
|
234
|
-
await Promise.resolve(watchService.dispose());
|
|
235
|
-
options.eventBus?.close();
|
|
236
|
-
scheduler.dispose();
|
|
237
|
-
await (deps.disposeServerContext ?? disposeServerContext)(
|
|
238
|
-
ctxHolder.current
|
|
239
|
-
);
|
|
240
|
-
await store.close();
|
|
241
|
-
},
|
|
242
|
-
},
|
|
243
|
-
};
|
|
43
|
+
return startResidentRuntime(options, deps);
|
|
244
44
|
}
|
|
@@ -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
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import type { Database } from "bun:sqlite";
|
|
9
9
|
|
|
10
|
+
import type { ModelLease } from "../llm/nodeLlamaCpp/lifecycle";
|
|
10
11
|
import type { EmbeddingPort } from "../llm/types";
|
|
11
12
|
import type { VectorIndexPort } from "../store/vector";
|
|
12
13
|
|
|
@@ -46,6 +47,9 @@ export interface EmbedSchedulerDeps {
|
|
|
46
47
|
getVectorIndex: () => VectorIndexPort | null;
|
|
47
48
|
/** Getter for current model URI (survives preset changes) */
|
|
48
49
|
getModelUri: () => string;
|
|
50
|
+
acquireModelLease?: () => ModelLease;
|
|
51
|
+
onEmbedded?: (result: EmbedResult) => void;
|
|
52
|
+
embedBacklogFn?: typeof embedBacklog;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -63,7 +67,7 @@ export interface EmbedScheduler {
|
|
|
63
67
|
getState(): EmbedSchedulerState;
|
|
64
68
|
|
|
65
69
|
/** Cleanup on server shutdown */
|
|
66
|
-
dispose(): void
|
|
70
|
+
dispose(): Promise<void>;
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
/**
|
|
@@ -71,7 +75,15 @@ export interface EmbedScheduler {
|
|
|
71
75
|
* Uses getters to resolve dependencies at execution time (survives context reloads).
|
|
72
76
|
*/
|
|
73
77
|
export function createEmbedScheduler(deps: EmbedSchedulerDeps): EmbedScheduler {
|
|
74
|
-
const {
|
|
78
|
+
const {
|
|
79
|
+
db,
|
|
80
|
+
getEmbedPort,
|
|
81
|
+
getVectorIndex,
|
|
82
|
+
getModelUri,
|
|
83
|
+
acquireModelLease,
|
|
84
|
+
onEmbedded,
|
|
85
|
+
embedBacklogFn = embedBacklog,
|
|
86
|
+
} = deps;
|
|
75
87
|
|
|
76
88
|
// State
|
|
77
89
|
let pendingCount = 0; // Track pending triggers (not actual docIds - we embed full backlog)
|
|
@@ -81,6 +93,7 @@ export function createEmbedScheduler(deps: EmbedSchedulerDeps): EmbedScheduler {
|
|
|
81
93
|
let firstPendingAt: number | null = null;
|
|
82
94
|
let nextRunAt: number | null = null; // Accurate timer due time
|
|
83
95
|
let disposed = false;
|
|
96
|
+
let currentRun: Promise<EmbedResult | null> | null = null;
|
|
84
97
|
let lastRunAt: number | null = null;
|
|
85
98
|
let lastResult: EmbedResult | null = null;
|
|
86
99
|
|
|
@@ -103,20 +116,25 @@ export function createEmbedScheduler(deps: EmbedSchedulerDeps): EmbedScheduler {
|
|
|
103
116
|
return { embedded: 0, errors: 0 };
|
|
104
117
|
}
|
|
105
118
|
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
const lease = acquireModelLease?.();
|
|
120
|
+
try {
|
|
121
|
+
const result = await embedBacklogFn({
|
|
122
|
+
statsPort: stats,
|
|
123
|
+
embedPort,
|
|
124
|
+
vectorIndex,
|
|
125
|
+
modelUri,
|
|
126
|
+
batchSize: BATCH_SIZE,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (!result.ok) {
|
|
130
|
+
console.error("[embed-scheduler] Embed failed:", result.error.message);
|
|
131
|
+
return { embedded: 0, errors: 0 };
|
|
132
|
+
}
|
|
133
|
+
if (result.value.embedded > 0) onEmbedded?.(result.value);
|
|
134
|
+
return result.value;
|
|
135
|
+
} finally {
|
|
136
|
+
lease?.release();
|
|
117
137
|
}
|
|
118
|
-
|
|
119
|
-
return result.value;
|
|
120
138
|
}
|
|
121
139
|
|
|
122
140
|
/**
|
|
@@ -166,41 +184,53 @@ export function createEmbedScheduler(deps: EmbedSchedulerDeps): EmbedScheduler {
|
|
|
166
184
|
/**
|
|
167
185
|
* Execute the embed run with concurrency guard.
|
|
168
186
|
*/
|
|
169
|
-
|
|
187
|
+
function executeRun(): Promise<EmbedResult | null> {
|
|
170
188
|
if (disposed || running) {
|
|
171
189
|
needsRerun = true;
|
|
172
|
-
return null;
|
|
190
|
+
return Promise.resolve(null);
|
|
173
191
|
}
|
|
174
192
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
// Clear pending state at START so new notifications accumulate
|
|
180
|
-
pendingCount = 0;
|
|
181
|
-
firstPendingAt = null;
|
|
193
|
+
const operation = (async (): Promise<EmbedResult | null> => {
|
|
194
|
+
running = true;
|
|
195
|
+
timer = null;
|
|
196
|
+
nextRunAt = null;
|
|
182
197
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
198
|
+
// Clear pending state at START so new notifications accumulate
|
|
199
|
+
pendingCount = 0;
|
|
200
|
+
firstPendingAt = null;
|
|
201
|
+
|
|
202
|
+
let result: EmbedResult;
|
|
203
|
+
try {
|
|
204
|
+
result = await runEmbed();
|
|
205
|
+
lastRunAt = Date.now();
|
|
206
|
+
lastResult = result;
|
|
207
|
+
} finally {
|
|
208
|
+
running = false;
|
|
209
|
+
}
|
|
191
210
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
211
|
+
// Check if we need to rerun (notifications arrived while running)
|
|
212
|
+
// Must be AFTER running=false so scheduleRun() actually schedules
|
|
213
|
+
if ((needsRerun || pendingCount > 0) && !disposed) {
|
|
214
|
+
needsRerun = false;
|
|
215
|
+
// Set firstPendingAt if we have pending work
|
|
216
|
+
if (pendingCount > 0 && firstPendingAt === null) {
|
|
217
|
+
firstPendingAt = Date.now();
|
|
218
|
+
}
|
|
219
|
+
scheduleRun();
|
|
199
220
|
}
|
|
200
|
-
scheduleRun();
|
|
201
|
-
}
|
|
202
221
|
|
|
203
|
-
|
|
222
|
+
return result;
|
|
223
|
+
})();
|
|
224
|
+
currentRun = operation;
|
|
225
|
+
void operation.then(
|
|
226
|
+
() => {
|
|
227
|
+
if (currentRun === operation) currentRun = null;
|
|
228
|
+
},
|
|
229
|
+
() => {
|
|
230
|
+
if (currentRun === operation) currentRun = null;
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
return operation;
|
|
204
234
|
}
|
|
205
235
|
|
|
206
236
|
return {
|
|
@@ -263,13 +293,14 @@ export function createEmbedScheduler(deps: EmbedSchedulerDeps): EmbedScheduler {
|
|
|
263
293
|
return state;
|
|
264
294
|
},
|
|
265
295
|
|
|
266
|
-
dispose(): void {
|
|
296
|
+
async dispose(): Promise<void> {
|
|
267
297
|
disposed = true;
|
|
268
298
|
if (timer) {
|
|
269
299
|
clearTimeout(timer);
|
|
270
300
|
timer = null;
|
|
271
301
|
nextRunAt = null;
|
|
272
302
|
}
|
|
303
|
+
await currentRun;
|
|
273
304
|
},
|
|
274
305
|
};
|
|
275
306
|
}
|
package/src/serve/index.ts
CHANGED
|
@@ -11,3 +11,12 @@ export {
|
|
|
11
11
|
type BackgroundRuntimeResult,
|
|
12
12
|
startBackgroundRuntime,
|
|
13
13
|
} from "./background-runtime";
|
|
14
|
+
export {
|
|
15
|
+
type ResidentGeneration,
|
|
16
|
+
type ResidentMode,
|
|
17
|
+
type ResidentRequestHandle,
|
|
18
|
+
type ResidentRuntime,
|
|
19
|
+
type ResidentRuntimeOptions,
|
|
20
|
+
type ResidentRuntimeResult,
|
|
21
|
+
startResidentRuntime,
|
|
22
|
+
} from "./resident-runtime";
|