@gmickel/gno 2.5.1 → 2.7.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 +60 -5
- package/assets/skill/README.md +5 -1
- package/assets/skill/SKILL.md +80 -4
- package/assets/skill/cli-reference.md +132 -2
- package/assets/skill/examples.md +30 -0
- package/assets/skill/mcp-reference.md +54 -1
- package/assets/skill/recipes/capture-and-file.md +6 -0
- package/assets/skill/recipes/memory-file-decision.md +6 -0
- package/assets/skill/recipes/memory-supersede-fact.md +5 -0
- package/assets/skill/recipes/session-evidence-lookup.md +98 -0
- package/assets/spa-production.json.gz +0 -0
- package/browser-extension/artifacts/{gno-browser-clipper-v2.5.1.zip → gno-browser-clipper-v2.7.0.zip} +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.7.0.zip.sha256 +1 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/package.json +2 -1
- package/spec/cli.md +449 -35
- package/spec/mcp.md +234 -4
- package/spec/output-schemas/ask.schema.json +1 -1
- package/spec/output-schemas/capture-receipt.schema.json +4 -1
- package/spec/output-schemas/doctor.schema.json +88 -0
- package/spec/output-schemas/error.schema.json +11 -2
- package/spec/output-schemas/get.schema.json +1 -1
- package/spec/output-schemas/mcp-capture-result.schema.json +4 -2
- package/spec/output-schemas/memory-remember.schema.json +10 -4
- package/spec/output-schemas/multi-get.schema.json +4 -1
- package/spec/output-schemas/peek.schema.json +2 -9
- package/spec/output-schemas/request-status.schema.json +113 -0
- package/spec/output-schemas/resident-status.schema.json +22 -0
- package/spec/output-schemas/search-result.schema.json +1 -1
- package/spec/output-schemas/search-results.schema.json +1 -1
- package/spec/output-schemas/sessions-automation-run.schema.json +46 -0
- package/spec/output-schemas/sessions-discovery.schema.json +38 -0
- package/spec/output-schemas/sessions-import-receipt.schema.json +156 -0
- package/spec/output-schemas/sessions-status.schema.json +432 -0
- package/spec/output-schemas/status.schema.json +98 -0
- package/src/cli/commands/ask.ts +14 -2
- package/src/cli/commands/capture.ts +55 -96
- package/src/cli/commands/daemon.ts +41 -0
- package/src/cli/commands/doctor.ts +54 -20
- package/src/cli/commands/embed.ts +41 -3
- package/src/cli/commands/ls.ts +3 -0
- package/src/cli/commands/memory.ts +12 -3
- package/src/cli/commands/query.ts +5 -0
- package/src/cli/commands/request-status.ts +59 -0
- package/src/cli/commands/reset.ts +39 -5
- package/src/cli/commands/sessions.ts +713 -0
- package/src/cli/commands/shared.ts +14 -1
- package/src/cli/commands/status.ts +63 -5
- package/src/cli/commands/vec.ts +54 -0
- package/src/cli/detach.ts +29 -1
- package/src/cli/errors.ts +13 -9
- package/src/cli/program.ts +441 -2
- package/src/cli/session-binding.ts +49 -0
- package/src/config/types.ts +8 -0
- package/src/core/capture-publish.ts +239 -0
- package/src/core/capture-sync.ts +12 -2
- package/src/core/host-paths.ts +31 -0
- package/src/core/memory-remember.ts +234 -122
- package/src/core/memory-types.ts +11 -0
- package/src/core/network-boundary-inventory.ts +8 -0
- package/src/core/request-receipts.ts +671 -0
- package/src/core/shutdown-budget.ts +6 -0
- package/src/core/vector-partition-status.ts +52 -0
- package/src/embed/backlog.ts +124 -18
- package/src/embed/fingerprint.ts +6 -3
- package/src/embed/retry.ts +66 -27
- package/src/embed/variant-backlog.ts +15 -10
- package/src/embed/variant-retry.ts +31 -22
- package/src/index.ts +30 -2
- package/src/llm/native-worker/dispatcher.ts +2 -0
- package/src/llm/native-worker/embedding-identity.ts +42 -0
- package/src/llm/native-worker/protocol.ts +1 -0
- package/src/llm/types.ts +3 -0
- package/src/mcp/context.ts +17 -0
- package/src/mcp/http-egress.ts +4 -0
- package/src/mcp/http-transport.ts +2 -0
- package/src/mcp/resources/index.ts +6 -5
- package/src/mcp/tool-descriptions-core.ts +1 -1
- package/src/mcp/tools/capture.ts +87 -85
- package/src/mcp/tools/index.ts +77 -4
- package/src/mcp/tools/memory-remember.ts +8 -1
- package/src/mcp/tools/memory-shared.ts +7 -1
- package/src/mcp/tools/request-status.ts +73 -0
- package/src/mcp/tools/sessions.ts +208 -0
- package/src/mcp/tools/status.ts +4 -0
- package/src/pipeline/hybrid.ts +37 -7
- package/src/pipeline/vsearch.ts +14 -2
- package/src/sdk/client.ts +180 -84
- package/src/sdk/index.ts +6 -0
- package/src/sdk/types.ts +54 -2
- package/src/serve/capture-service.ts +98 -32
- package/src/serve/config-sync.ts +3 -2
- package/src/serve/embed-scheduler.ts +133 -19
- package/src/serve/host-path-redaction.ts +79 -0
- package/src/serve/public/app.tsx +4 -1
- package/src/serve/public/components/CaptureModal.tsx +26 -8
- package/src/serve/public/components/sessions/AutomationPanel.tsx +800 -0
- package/src/serve/public/components/sessions/ImportReceipt.tsx +238 -0
- package/src/serve/public/components/sessions/SessionSearch.tsx +286 -0
- package/src/serve/public/components/sessions/SourcesPanel.tsx +541 -0
- package/src/serve/public/components/sessions/api.ts +40 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/hooks/use-api.ts +26 -3
- package/src/serve/public/lib/request-intent.ts +77 -0
- package/src/serve/public/lib/snippet.tsx +52 -0
- package/src/serve/public/lib/workspace-actions.ts +12 -1
- package/src/serve/public/lib/workspace-tabs.ts +2 -0
- package/src/serve/public/pages/Dashboard.tsx +22 -9
- package/src/serve/public/pages/DocView.tsx +25 -6
- package/src/serve/public/pages/DocumentEditor.tsx +224 -104
- package/src/serve/public/pages/Search.tsx +1 -41
- package/src/serve/public/pages/Sessions.tsx +350 -0
- package/src/serve/resident-runtime.ts +69 -4
- package/src/serve/resident-status.ts +13 -1
- package/src/serve/routes/api.ts +476 -147
- package/src/serve/routes/sessions.ts +766 -0
- package/src/serve/security.ts +9 -0
- package/src/serve/server.ts +215 -10
- package/src/serve/session-automation.ts +146 -0
- package/src/serve/status-model.ts +16 -0
- package/src/serve/status.ts +2 -0
- package/src/serve/watch-reconciliation-shared.ts +3 -0
- package/src/serve/watch-service-events.ts +3 -2
- package/src/serve/watch-service-run-flush.ts +35 -2
- package/src/serve/watch-service.ts +5 -0
- package/src/sessions/archive.ts +348 -0
- package/src/sessions/automation-state.ts +444 -0
- package/src/sessions/automation-status.ts +239 -0
- package/src/sessions/automation.ts +1169 -0
- package/src/sessions/binding.ts +105 -0
- package/src/sessions/claude-hook.ts +240 -0
- package/src/sessions/config.ts +176 -0
- package/src/sessions/format.ts +191 -0
- package/src/sessions/import-child-env.ts +8 -0
- package/src/sessions/import-child.ts +152 -0
- package/src/sessions/parsers/claude-code.ts +259 -0
- package/src/sessions/parsers/codex.ts +303 -0
- package/src/sessions/parsers/hermes.ts +248 -0
- package/src/sessions/parsers/openclaw.ts +496 -0
- package/src/sessions/parsers/shared.ts +184 -0
- package/src/sessions/sanitize.ts +222 -0
- package/src/sessions/service.ts +1533 -0
- package/src/sessions/setup.ts +477 -0
- package/src/sessions/sources.ts +518 -0
- package/src/sessions/state.ts +118 -0
- package/src/sessions/types.ts +457 -0
- package/src/store/migrations/031-runtime-independent-vectors.ts +29 -0
- package/src/store/migrations/032-vector-runtime-callers.ts +17 -0
- package/src/store/migrations/index.ts +4 -0
- package/src/store/sqlite/adapter.ts +76 -16
- package/src/store/sqlite/scoped-index.ts +9 -0
- package/src/store/types.ts +11 -1
- package/src/store/vector/lazy.ts +46 -43
- package/src/store/vector/runtime-compat.ts +651 -0
- package/src/store/vector/sqlite-vec.ts +20 -2
- package/src/store/vector/status.ts +276 -35
- package/src/store/vector/types.ts +2 -0
- package/src/store/vector/variant-search.ts +71 -23
- package/src/store/vector/variants.ts +49 -14
- package/browser-extension/artifacts/gno-browser-clipper-v2.5.1.zip.sha256 +0 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP request receipts: the caller's namespace, error rethrow, and the
|
|
3
|
+
* bounded `gno_request_status` lookup.
|
|
4
|
+
*
|
|
5
|
+
* @module src/mcp/tools/request-status
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
|
|
10
|
+
import type { ToolContext } from "../server";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
formatRequestStatus,
|
|
14
|
+
LOCAL_OWNER_NAMESPACE,
|
|
15
|
+
readRequestStatus,
|
|
16
|
+
RequestReceiptError,
|
|
17
|
+
requestLedgerPath,
|
|
18
|
+
} from "../../core/request-receipts";
|
|
19
|
+
import { runTool, type ToolResult } from "./index";
|
|
20
|
+
|
|
21
|
+
export const REQUEST_STATUS_MCP_ANNOTATIONS = {
|
|
22
|
+
readOnlyHint: true,
|
|
23
|
+
destructiveHint: false,
|
|
24
|
+
idempotentHint: true,
|
|
25
|
+
openWorldHint: false,
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
export const requestIdInputSchema = z
|
|
29
|
+
.string()
|
|
30
|
+
.describe(
|
|
31
|
+
"Optional caller request ID (1-128 of A-Z a-z 0-9 . _ : -). Reuse the same ID when retrying the same write after a lost response; a new intent needs a new ID"
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
export const requestStatusInputSchema = z.object({
|
|
35
|
+
requestId: z
|
|
36
|
+
.string()
|
|
37
|
+
.describe("Request ID previously sent with gno_capture or gno_remember"),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/** HTTP callers get their authorized identity's namespace; stdio is the local owner. */
|
|
41
|
+
export function mcpRequestNamespace(ctx: ToolContext): string {
|
|
42
|
+
return ctx.getRequestNamespace?.() ?? LOCAL_OWNER_NAMESPACE;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Re-throw a request receipt error in the `CODE: message` shape runTool parses. */
|
|
46
|
+
export function rethrowRequestError(error: unknown): never {
|
|
47
|
+
if (error instanceof RequestReceiptError) {
|
|
48
|
+
throw new Error(`${error.code}: ${error.message}`);
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function handleRequestStatus(
|
|
54
|
+
args: z.infer<typeof requestStatusInputSchema>,
|
|
55
|
+
ctx: ToolContext
|
|
56
|
+
): Promise<ToolResult> {
|
|
57
|
+
return runTool(
|
|
58
|
+
ctx,
|
|
59
|
+
"gno_request_status",
|
|
60
|
+
async () => {
|
|
61
|
+
try {
|
|
62
|
+
return await readRequestStatus({
|
|
63
|
+
ledgerPath: requestLedgerPath(ctx.store.getDbPath()),
|
|
64
|
+
namespace: mcpRequestNamespace(ctx),
|
|
65
|
+
requestId: args.requestId,
|
|
66
|
+
});
|
|
67
|
+
} catch (error) {
|
|
68
|
+
return rethrowRequestError(error);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
formatRequestStatus
|
|
72
|
+
);
|
|
73
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP session-archive tools: bounded status (including opt-in automation),
|
|
3
|
+
* import of owner-registered sources, and a run request for a configured
|
|
4
|
+
* automation profile. Thin adapters over the core sessions services. Hooks,
|
|
5
|
+
* schedules and source access are managed only by the local owner.
|
|
6
|
+
*
|
|
7
|
+
* Remote callers never discover host directories and never name paths:
|
|
8
|
+
* import accepts a registered source ID only. Import is registered only with
|
|
9
|
+
* `--enable-write`, and neither tool is part of the core profile.
|
|
10
|
+
*
|
|
11
|
+
* @module src/mcp/tools/sessions
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
|
|
16
|
+
import type { ToolContext } from "../server";
|
|
17
|
+
|
|
18
|
+
import { runAutomationProfile } from "../../sessions/automation";
|
|
19
|
+
import {
|
|
20
|
+
formatAutomationRunText,
|
|
21
|
+
formatImportReceiptText,
|
|
22
|
+
formatStatusText,
|
|
23
|
+
} from "../../sessions/format";
|
|
24
|
+
import { importInChildProcess } from "../../sessions/import-child";
|
|
25
|
+
import { SessionsService } from "../../sessions/service";
|
|
26
|
+
import {
|
|
27
|
+
MAX_IMPORT_LIMIT,
|
|
28
|
+
type SessionAutomationRunResult,
|
|
29
|
+
type SessionImportReceipt,
|
|
30
|
+
remoteSafeSessionsError,
|
|
31
|
+
} from "../../sessions/types";
|
|
32
|
+
import { runTool, type ToolResult } from "./index";
|
|
33
|
+
|
|
34
|
+
export const sessionsStatusInputSchema = z.object({});
|
|
35
|
+
|
|
36
|
+
export const sessionsImportInputSchema = z
|
|
37
|
+
.object({
|
|
38
|
+
sourceId: z
|
|
39
|
+
.string()
|
|
40
|
+
.trim()
|
|
41
|
+
.min(1)
|
|
42
|
+
.max(64)
|
|
43
|
+
.describe(
|
|
44
|
+
"ID of an owner-registered session source (see gno_sessions_status)"
|
|
45
|
+
),
|
|
46
|
+
dryRun: z
|
|
47
|
+
.boolean()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe("Parse and report without writing archive or index state"),
|
|
50
|
+
limit: z
|
|
51
|
+
.number()
|
|
52
|
+
.int()
|
|
53
|
+
.min(1)
|
|
54
|
+
.max(MAX_IMPORT_LIMIT)
|
|
55
|
+
.optional()
|
|
56
|
+
.describe(
|
|
57
|
+
"Maximum changed units processed this call; the rest are deferred"
|
|
58
|
+
),
|
|
59
|
+
})
|
|
60
|
+
.strict();
|
|
61
|
+
|
|
62
|
+
export type SessionsImportToolInput = z.infer<typeof sessionsImportInputSchema>;
|
|
63
|
+
|
|
64
|
+
export const sessionsAutomationRunInputSchema = z
|
|
65
|
+
.object({
|
|
66
|
+
profileId: z
|
|
67
|
+
.string()
|
|
68
|
+
.trim()
|
|
69
|
+
.min(1)
|
|
70
|
+
.max(64)
|
|
71
|
+
.describe(
|
|
72
|
+
"ID of an owner-configured automation profile (see gno_sessions_status)"
|
|
73
|
+
),
|
|
74
|
+
})
|
|
75
|
+
.strict();
|
|
76
|
+
|
|
77
|
+
export type SessionsAutomationRunToolInput = z.infer<
|
|
78
|
+
typeof sessionsAutomationRunInputSchema
|
|
79
|
+
>;
|
|
80
|
+
|
|
81
|
+
export const SESSIONS_AUTOMATION_RUN_MCP_ANNOTATIONS = {
|
|
82
|
+
readOnlyHint: false,
|
|
83
|
+
destructiveHint: false,
|
|
84
|
+
idempotentHint: true,
|
|
85
|
+
openWorldHint: false,
|
|
86
|
+
} as const;
|
|
87
|
+
|
|
88
|
+
export const SESSIONS_STATUS_MCP_ANNOTATIONS = {
|
|
89
|
+
readOnlyHint: true,
|
|
90
|
+
destructiveHint: false,
|
|
91
|
+
idempotentHint: true,
|
|
92
|
+
openWorldHint: false,
|
|
93
|
+
} as const;
|
|
94
|
+
|
|
95
|
+
export const SESSIONS_IMPORT_MCP_ANNOTATIONS = {
|
|
96
|
+
readOnlyHint: false,
|
|
97
|
+
destructiveHint: false,
|
|
98
|
+
idempotentHint: true,
|
|
99
|
+
openWorldHint: false,
|
|
100
|
+
} as const;
|
|
101
|
+
|
|
102
|
+
function service(ctx: ToolContext): SessionsService {
|
|
103
|
+
return new SessionsService({
|
|
104
|
+
config: ctx.config,
|
|
105
|
+
configPath: ctx.actualConfigPath,
|
|
106
|
+
indexName: ctx.indexName,
|
|
107
|
+
store: ctx.store,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Re-throw as `CODE: message` (the shape runTool parses), never with host paths. */
|
|
112
|
+
function rethrowSessionsError(error: unknown): never {
|
|
113
|
+
const typed = remoteSafeSessionsError(error);
|
|
114
|
+
throw new Error(`${typed.code}: ${typed.message}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function handleSessionsStatus(ctx: ToolContext): Promise<ToolResult> {
|
|
118
|
+
return runTool(
|
|
119
|
+
ctx,
|
|
120
|
+
"gno_sessions_status",
|
|
121
|
+
async () => {
|
|
122
|
+
try {
|
|
123
|
+
return await service(ctx).status();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
return rethrowSessionsError(error);
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
formatStatusText
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function handleSessionsImport(
|
|
133
|
+
args: SessionsImportToolInput,
|
|
134
|
+
ctx: ToolContext
|
|
135
|
+
): Promise<ToolResult> {
|
|
136
|
+
return runTool(
|
|
137
|
+
ctx,
|
|
138
|
+
"gno_sessions_import",
|
|
139
|
+
async () => {
|
|
140
|
+
if (!ctx.enableWrite) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
"WRITE_DISABLED: gno_sessions_import requires --enable-write or GNO_MCP_ENABLE_WRITE=1"
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
let receipt: SessionImportReceipt;
|
|
146
|
+
try {
|
|
147
|
+
// A child process keeps this server answering during a long import.
|
|
148
|
+
receipt = await importInChildProcess({
|
|
149
|
+
config: ctx.config,
|
|
150
|
+
configPath: ctx.actualConfigPath,
|
|
151
|
+
indexName: ctx.indexName,
|
|
152
|
+
sourceId: args.sourceId,
|
|
153
|
+
dryRun: args.dryRun === true,
|
|
154
|
+
limit: args.limit,
|
|
155
|
+
});
|
|
156
|
+
} catch (error) {
|
|
157
|
+
return rethrowSessionsError(error);
|
|
158
|
+
}
|
|
159
|
+
if (!receipt.dryRun && receipt.lexical.collections.length > 0) {
|
|
160
|
+
ctx.markContentMutation?.();
|
|
161
|
+
ctx.markIndexMutation?.();
|
|
162
|
+
}
|
|
163
|
+
return receipt;
|
|
164
|
+
},
|
|
165
|
+
formatImportReceiptText
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function handleSessionsAutomationRun(
|
|
170
|
+
args: SessionsAutomationRunToolInput,
|
|
171
|
+
ctx: ToolContext
|
|
172
|
+
): Promise<ToolResult> {
|
|
173
|
+
return runTool(
|
|
174
|
+
ctx,
|
|
175
|
+
"gno_sessions_automation_run",
|
|
176
|
+
async () => {
|
|
177
|
+
if (!ctx.enableWrite) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
"WRITE_DISABLED: gno_sessions_automation_run requires --enable-write or GNO_MCP_ENABLE_WRITE=1"
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
let result: SessionAutomationRunResult;
|
|
183
|
+
try {
|
|
184
|
+
result = await runAutomationProfile(
|
|
185
|
+
{
|
|
186
|
+
configPath: ctx.actualConfigPath,
|
|
187
|
+
indexName: ctx.indexName,
|
|
188
|
+
store: ctx.store,
|
|
189
|
+
// A child process keeps this server answering during the run.
|
|
190
|
+
inChildProcess: true,
|
|
191
|
+
},
|
|
192
|
+
args.profileId,
|
|
193
|
+
{ trigger: "manual" }
|
|
194
|
+
);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
return rethrowSessionsError(error);
|
|
197
|
+
}
|
|
198
|
+
if (
|
|
199
|
+
result.receipts.some((receipt) => receipt.lexical.collections.length)
|
|
200
|
+
) {
|
|
201
|
+
ctx.markContentMutation?.();
|
|
202
|
+
ctx.markIndexMutation?.();
|
|
203
|
+
}
|
|
204
|
+
return result;
|
|
205
|
+
},
|
|
206
|
+
formatAutomationRunText
|
|
207
|
+
);
|
|
208
|
+
}
|
package/src/mcp/tools/status.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { ToolContext } from "../server";
|
|
|
9
9
|
|
|
10
10
|
import { buildContentTypeBoostStatus } from "../../config/content-types";
|
|
11
11
|
import { formatChunkingStatus } from "../../core/chunking-status";
|
|
12
|
+
import { formatVectorPartitionLines } from "../../core/vector-partition-status";
|
|
12
13
|
import { resolveModelUri } from "../../llm/registry";
|
|
13
14
|
import { createStandaloneResidentStatus } from "../../serve/resident-status";
|
|
14
15
|
import { runTool, type ToolResult } from "./index";
|
|
@@ -59,6 +60,9 @@ function formatStatus(status: IndexStatus): string {
|
|
|
59
60
|
if (status.embeddingBacklog > 0) {
|
|
60
61
|
lines.push(`Embedding backlog: ${status.embeddingBacklog} chunks`);
|
|
61
62
|
}
|
|
63
|
+
lines.push(
|
|
64
|
+
...formatVectorPartitionLines(status.vectorPartitions, status.vectorRuntime)
|
|
65
|
+
);
|
|
62
66
|
|
|
63
67
|
const chunking = formatChunkingStatus(status.chunking);
|
|
64
68
|
if (chunking) lines.push(chunking);
|
package/src/pipeline/hybrid.ts
CHANGED
|
@@ -33,7 +33,11 @@ import {
|
|
|
33
33
|
withInferenceScope,
|
|
34
34
|
} from "../llm/inference-scope";
|
|
35
35
|
import { err, ok } from "../store/types";
|
|
36
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
lexicalFallbackNotice,
|
|
38
|
+
resolveVectorSearchIdentity,
|
|
39
|
+
VECTOR_RUNTIME_INCOMPATIBLE,
|
|
40
|
+
} from "../store/vector/variant-search";
|
|
37
41
|
import { createChunkLookup } from "./chunk-lookup";
|
|
38
42
|
import {
|
|
39
43
|
attachAuxiliaryScoreMetadata,
|
|
@@ -284,7 +288,10 @@ async function searchVectorChunks(
|
|
|
284
288
|
allowedMirrorHashes?: string[];
|
|
285
289
|
eligibility?: VectorSearchOptions["eligibility"];
|
|
286
290
|
}
|
|
287
|
-
): Promise<
|
|
291
|
+
): Promise<
|
|
292
|
+
| { ok: true; chunks: ChunkId[] }
|
|
293
|
+
| { ok: false; reason: string; notice?: string }
|
|
294
|
+
> {
|
|
288
295
|
if (!vectorIndex.searchAvailable) {
|
|
289
296
|
return { ok: false, reason: "vector_unavailable" };
|
|
290
297
|
}
|
|
@@ -298,12 +305,19 @@ async function searchVectorChunks(
|
|
|
298
305
|
return { ok: false, reason: "vector_embed_error" };
|
|
299
306
|
}
|
|
300
307
|
|
|
308
|
+
const partition = await resolveVectorSearchIdentity(embedPort, vectorIndex);
|
|
309
|
+
if (partition.unavailable)
|
|
310
|
+
return {
|
|
311
|
+
ok: false,
|
|
312
|
+
reason: VECTOR_RUNTIME_INCOMPATIBLE,
|
|
313
|
+
notice: lexicalFallbackNotice(partition.unavailable),
|
|
314
|
+
};
|
|
301
315
|
const queryEmbedding = new Float32Array(embedResult.value);
|
|
302
316
|
const searchResult = await vectorIndex.searchNearest(
|
|
303
317
|
queryEmbedding,
|
|
304
318
|
options.limit,
|
|
305
319
|
{
|
|
306
|
-
embeddingIdentity:
|
|
320
|
+
embeddingIdentity: partition.identity,
|
|
307
321
|
minScore: options.minScore,
|
|
308
322
|
allowedMirrorHashes: options.allowedMirrorHashes,
|
|
309
323
|
eligibility: options.eligibility,
|
|
@@ -630,6 +644,7 @@ async function searchHybridWithHydration(
|
|
|
630
644
|
// Vector search
|
|
631
645
|
let vecCount = 0;
|
|
632
646
|
let vectorsUsed = false;
|
|
647
|
+
let vectorNotice: string | undefined;
|
|
633
648
|
const vectorAvailable =
|
|
634
649
|
(vectorIndex?.searchAvailable && embedPort !== null) ?? false;
|
|
635
650
|
if (!vectorAvailable) {
|
|
@@ -662,8 +677,10 @@ async function searchHybridWithHydration(
|
|
|
662
677
|
}
|
|
663
678
|
);
|
|
664
679
|
|
|
665
|
-
if (!vectorResult.ok)
|
|
666
|
-
|
|
680
|
+
if (!vectorResult.ok) {
|
|
681
|
+
counters.fallbackEvents.push(vectorResult.reason);
|
|
682
|
+
vectorNotice = vectorResult.notice;
|
|
683
|
+
} else vectorsUsed = true;
|
|
667
684
|
const vecChunks = vectorResult.ok ? vectorResult.chunks : [];
|
|
668
685
|
vecCount = vecChunks.length;
|
|
669
686
|
vectorTraceChunks.push(...vecChunks);
|
|
@@ -691,8 +708,14 @@ async function searchHybridWithHydration(
|
|
|
691
708
|
);
|
|
692
709
|
|
|
693
710
|
assertInferenceResult(embedResult);
|
|
711
|
+
const partition = embedResult.ok
|
|
712
|
+
? await resolveVectorSearchIdentity(embedPort, vectorIndex)
|
|
713
|
+
: undefined;
|
|
694
714
|
if (!embedResult.ok) {
|
|
695
715
|
counters.fallbackEvents.push("vector_embed_error");
|
|
716
|
+
} else if (partition?.unavailable) {
|
|
717
|
+
counters.fallbackEvents.push(VECTOR_RUNTIME_INCOMPATIBLE);
|
|
718
|
+
vectorNotice = lexicalFallbackNotice(partition.unavailable);
|
|
696
719
|
} else {
|
|
697
720
|
if (embedResult.value.batchFailed) {
|
|
698
721
|
counters.fallbackEvents.push("vector_embed_batch_fallback");
|
|
@@ -709,7 +732,7 @@ async function searchHybridWithHydration(
|
|
|
709
732
|
new Float32Array(embedding),
|
|
710
733
|
variant.limit,
|
|
711
734
|
{
|
|
712
|
-
embeddingIdentity:
|
|
735
|
+
embeddingIdentity: partition?.identity,
|
|
713
736
|
allowedMirrorHashes: options.retrievalScope?.allowedMirrorHashes,
|
|
714
737
|
eligibility: vectorEligibility,
|
|
715
738
|
}
|
|
@@ -1390,6 +1413,11 @@ async function searchHybridWithHydration(
|
|
|
1390
1413
|
trace: diagnoseTrace,
|
|
1391
1414
|
},
|
|
1392
1415
|
};
|
|
1416
|
+
if (vectorNotice)
|
|
1417
|
+
output.meta.warnings = [
|
|
1418
|
+
...(output.meta.warnings ?? []),
|
|
1419
|
+
{ code: VECTOR_RUNTIME_INCOMPATIBLE, message: vectorNotice },
|
|
1420
|
+
];
|
|
1393
1421
|
const fallbackCodes = [...new Set(counters.fallbackEvents)].sort();
|
|
1394
1422
|
const capabilityOutcomes = [
|
|
1395
1423
|
{ capability: "lexical_search", status: "used" as const },
|
|
@@ -1400,7 +1428,9 @@ async function searchHybridWithHydration(
|
|
|
1400
1428
|
status: "failed" as const,
|
|
1401
1429
|
reasonCode: fallbackCodes.includes("vector_embed_error")
|
|
1402
1430
|
? "vector_embed_error"
|
|
1403
|
-
:
|
|
1431
|
+
: vectorNotice
|
|
1432
|
+
? VECTOR_RUNTIME_INCOMPATIBLE
|
|
1433
|
+
: "vector_search_error",
|
|
1404
1434
|
}
|
|
1405
1435
|
: { capability: "semantic_search", status: "used" as const }
|
|
1406
1436
|
: {
|
package/src/pipeline/vsearch.ts
CHANGED
|
@@ -21,7 +21,10 @@ import {
|
|
|
21
21
|
} from "../llm/inference-scope";
|
|
22
22
|
import { getContentBatch } from "../store/content-batch";
|
|
23
23
|
import { err, ok } from "../store/types";
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
resolveVectorSearchIdentity,
|
|
26
|
+
vectorSearchUnavailableMessage,
|
|
27
|
+
} from "../store/vector/variant-search";
|
|
25
28
|
import { createChunkLookup } from "./chunk-lookup";
|
|
26
29
|
import {
|
|
27
30
|
applyContentTypeBoost,
|
|
@@ -144,7 +147,16 @@ async function searchVectorWithEmbeddingOwned(
|
|
|
144
147
|
|
|
145
148
|
let embeddingIdentity;
|
|
146
149
|
try {
|
|
147
|
-
|
|
150
|
+
const partition = await resolveVectorSearchIdentity(
|
|
151
|
+
deps.embedPort,
|
|
152
|
+
vectorIndex
|
|
153
|
+
);
|
|
154
|
+
if (partition.unavailable)
|
|
155
|
+
return err(
|
|
156
|
+
"VEC_SEARCH_UNAVAILABLE",
|
|
157
|
+
vectorSearchUnavailableMessage(partition.unavailable)
|
|
158
|
+
);
|
|
159
|
+
embeddingIdentity = partition.identity;
|
|
148
160
|
} catch (cause) {
|
|
149
161
|
return err(
|
|
150
162
|
"QUERY_FAILED",
|