@gmickel/gno 1.45.1 → 2.0.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 +1 -1
- package/THIRD_PARTY_NOTICES.md +46 -0
- package/assets/skill/SKILL.md +7 -6
- package/assets/skill/cli-reference.md +14 -6
- package/assets/skill/mcp-reference.md +4 -1
- package/assets/spa-production.json.gz +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip.sha256 +1 -0
- package/browser-extension/dist/chunk-4tc9v0ja.js +74 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/browser-extension/dist/preview.html +1 -1
- package/browser-extension/dist/service-worker.js +32 -33
- package/bunfig.toml +2 -0
- package/package.json +40 -26
- package/spec/cli.md +30 -11
- package/spec/db/schema.sql +146 -1
- package/spec/mcp.md +26 -0
- package/src/app/context-runtime-types.ts +3 -0
- package/src/app/context-runtime.ts +2 -0
- package/src/cli/commands/ask.ts +6 -1
- package/src/cli/commands/daemon.ts +21 -8
- package/src/cli/commands/embed.ts +77 -41
- package/src/cli/commands/mcp/install.ts +20 -0
- package/src/cli/commands/mcp/paths.ts +25 -0
- package/src/cli/commands/mcp/status.ts +6 -0
- package/src/cli/detach.ts +3 -2
- package/src/cli/program.ts +6 -0
- package/src/config/types.ts +3 -3
- package/src/converters/adapters/markitdownTs/adapter.ts +1 -2
- package/src/converters/adapters/officeparser/adapter.ts +1 -2
- package/src/converters/versions.ts +6 -8
- package/src/core/context-evidence.ts +8 -4
- package/src/core/job-manager.ts +95 -13
- package/src/core/network-boundary-inventory.ts +10 -0
- package/src/core/shutdown-budget.ts +45 -0
- package/src/embed/backlog.ts +107 -4
- package/src/embed/batch.ts +42 -2
- package/src/embed/fingerprint.ts +16 -0
- package/src/embed/retry.ts +113 -5
- package/src/embed/variant-backlog.ts +105 -0
- package/src/embed/variant-plan.ts +62 -0
- package/src/embed/variant-retry.ts +113 -0
- package/src/ingestion/graph-reconciliation.ts +327 -0
- package/src/ingestion/sync.ts +9 -272
- package/src/llm/http-inference.ts +6 -0
- package/src/llm/httpEmbedding.ts +37 -6
- package/src/llm/httpGeneration.ts +18 -3
- package/src/llm/httpRerank.ts +23 -5
- package/src/llm/inference-cancellation.ts +168 -0
- package/src/llm/inference-scope.ts +202 -0
- package/src/llm/lazy-ports.ts +115 -0
- package/src/llm/native-worker/client.ts +541 -0
- package/src/llm/native-worker/dispatcher.ts +228 -0
- package/src/llm/native-worker/embedding-identity.ts +33 -0
- package/src/llm/native-worker/entry.ts +173 -0
- package/src/llm/native-worker/errors.ts +32 -0
- package/src/llm/native-worker/evaluation.ts +16 -0
- package/src/llm/native-worker/owned-exit.ts +108 -0
- package/src/llm/native-worker/owner.ts +141 -0
- package/src/llm/native-worker/ports.ts +317 -0
- package/src/llm/native-worker/protocol.ts +442 -0
- package/src/llm/native-worker/runtime-config.ts +92 -0
- package/src/llm/nodeLlamaCpp/adapter.ts +77 -20
- package/src/llm/nodeLlamaCpp/embedding.ts +130 -46
- package/src/llm/nodeLlamaCpp/generation.ts +34 -5
- package/src/llm/nodeLlamaCpp/lifecycle-options.ts +99 -0
- package/src/llm/nodeLlamaCpp/lifecycle.ts +209 -204
- package/src/llm/nodeLlamaCpp/rerank-capacity.ts +111 -0
- package/src/llm/nodeLlamaCpp/rerank.ts +118 -27
- package/src/llm/nodeLlamaCpp/simulator-handle.ts +73 -0
- package/src/llm/nodeLlamaCpp/simulator-install.ts +124 -0
- package/src/llm/nodeLlamaCpp/simulator-session.ts +240 -0
- package/src/llm/nodeLlamaCpp/simulator-types.ts +80 -0
- package/src/llm/types.ts +35 -5
- package/src/mcp/context.ts +27 -0
- package/src/mcp/http-transport.ts +12 -10
- package/src/mcp/server.ts +3 -0
- package/src/mcp/tool-profile.ts +30 -8
- package/src/mcp/tools/context.ts +8 -11
- package/src/mcp/tools/embed.ts +1 -1
- package/src/mcp/tools/index-cmd.ts +1 -1
- package/src/mcp/tools/index.ts +10 -8
- package/src/mcp/tools/query.ts +14 -30
- package/src/mcp/tools/vsearch.ts +1 -1
- package/src/pipeline/answer.ts +23 -3
- package/src/pipeline/claim-verifier.ts +6 -0
- package/src/pipeline/expansion.ts +43 -40
- package/src/pipeline/explain.ts +6 -2
- package/src/pipeline/filters.ts +63 -0
- package/src/pipeline/fusion.ts +29 -9
- package/src/pipeline/graph-retrieval.ts +29 -9
- package/src/pipeline/hybrid.ts +198 -55
- package/src/pipeline/hydration.ts +161 -0
- package/src/pipeline/owner-fusion.ts +87 -0
- package/src/pipeline/rerank.ts +35 -11
- package/src/pipeline/search.ts +13 -2
- package/src/pipeline/types.ts +5 -3
- package/src/pipeline/vsearch.ts +87 -7
- package/src/sdk/client.ts +47 -3
- package/src/sdk/embed.ts +63 -39
- package/src/serve/background-runtime.ts +1 -1
- package/src/serve/context.ts +41 -56
- package/src/serve/embed-scheduler.ts +58 -35
- package/src/serve/public/components/IndexingProgress.tsx +46 -60
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/lib/shiki-language-ids.ts +14 -0
- package/src/serve/resident-admission.ts +36 -36
- package/src/serve/resident-background-work.ts +20 -2
- package/src/serve/resident-request.ts +11 -5
- package/src/serve/resident-runtime.ts +97 -61
- package/src/serve/resident-shutdown.ts +153 -0
- package/src/serve/routes/api.ts +3 -1
- package/src/serve/server.ts +47 -26
- package/src/store/migrations/028-vector-variants.ts +54 -0
- package/src/store/migrations/029-graph-reference-state.ts +77 -0
- package/src/store/migrations/index.ts +4 -0
- package/src/store/sqlite/adapter.ts +251 -183
- package/src/store/sqlite/eligibility.ts +174 -0
- package/src/store/sqlite/graph-edge-application.ts +66 -0
- package/src/store/sqlite/graph-reference-state.ts +194 -0
- package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
- package/src/store/types.ts +80 -12
- package/src/store/vector/eligibility.ts +36 -0
- package/src/store/vector/freshness.ts +33 -6
- package/src/store/vector/lazy.ts +81 -0
- package/src/store/vector/sqlite-vec.ts +106 -54
- package/src/store/vector/stats.ts +14 -3
- package/src/store/vector/types.ts +35 -2
- package/src/store/vector/variant-search.ts +192 -0
- package/src/store/vector/variants.ts +451 -0
- package/vendor/converters/markitdown-ts/LICENSE +21 -0
- package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
- package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
- package/vendor/converters/markitdown-ts/package.json +77 -0
- package/vendor/converters/officeparser/LICENSE +21 -0
- package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
- package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
- package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
- package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
- package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
- package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
- package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
- package/vendor/converters/officeparser/dist/cli.js +381 -0
- package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
- package/vendor/converters/officeparser/dist/defaults.js +218 -0
- package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
- package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
- package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
- package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
- package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
- package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
- package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
- package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
- package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
- package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
- package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
- package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
- package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
- package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
- package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
- package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
- package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
- package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
- package/vendor/converters/officeparser/dist/index.d.ts +60 -0
- package/vendor/converters/officeparser/dist/index.js +72 -0
- package/vendor/converters/officeparser/dist/index.mjs +18 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
- package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
- package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
- package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
- package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
- package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
- package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
- package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
- package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
- package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
- package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
- package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
- package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
- package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
- package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
- package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
- package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
- package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
- package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
- package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
- package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
- package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
- package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
- package/vendor/converters/officeparser/dist/types.js +107 -0
- package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
- package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
- package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
- package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
- package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
- package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
- package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
- package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
- package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
- package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
- package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
- package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
- package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
- package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
- package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
- package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
- package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
- package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
- package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
- package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
- package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
- package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
- package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
- package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
- package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
- package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
- package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
- package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
- package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
- package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
- package/vendor/converters/officeparser/package.json +147 -0
- package/vendor/converters/upstream-manifest.json +124 -0
- package/vendor/dependency-fixes/README.md +77 -0
- package/vendor/dependency-fixes/vendor-converters.py +83 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip.sha256 +0 -1
- package/browser-extension/dist/chunk-627emwpj.js +0 -75
- /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
package/src/core/job-manager.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import type { SyncResult } from "../ingestion";
|
|
1
2
|
/**
|
|
2
3
|
* Background job manager for MCP write operations.
|
|
3
4
|
*
|
|
4
5
|
* @module src/core/job-manager
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
|
-
import
|
|
8
|
-
|
|
8
|
+
import {
|
|
9
|
+
assertInferenceActive,
|
|
10
|
+
withOwnedInferenceScope,
|
|
11
|
+
withBackgroundInference,
|
|
12
|
+
} from "../llm/inference-scope";
|
|
9
13
|
import { MCP_ERRORS } from "./errors";
|
|
10
14
|
import { acquireWriteLock, type WriteLockHandle } from "./file-lock";
|
|
11
15
|
|
|
@@ -78,7 +82,10 @@ export class JobManager {
|
|
|
78
82
|
#jobs = new Map<string, JobRecord>();
|
|
79
83
|
#jobAuthorizationEpochs = new Map<string, string>();
|
|
80
84
|
#activeJobs = new Set<Promise<void>>();
|
|
85
|
+
#jobControllers = new Map<string, AbortController>();
|
|
81
86
|
#authorizationEpoch = "egress-epoch-uninitialized";
|
|
87
|
+
#accepting = true;
|
|
88
|
+
#releaseJobLocks = new Map<string, () => Promise<void>>();
|
|
82
89
|
|
|
83
90
|
constructor(options: JobManagerOptions) {
|
|
84
91
|
this.#lockPath = options.lockPath;
|
|
@@ -89,8 +96,10 @@ export class JobManager {
|
|
|
89
96
|
|
|
90
97
|
async startJob(
|
|
91
98
|
type: JobType,
|
|
92
|
-
fn: () => Promise<SyncResult>
|
|
99
|
+
fn: (signal: AbortSignal) => Promise<SyncResult>
|
|
93
100
|
): Promise<string> {
|
|
101
|
+
assertInferenceActive();
|
|
102
|
+
this.#assertAccepting();
|
|
94
103
|
this.#cleanupExpiredJobs();
|
|
95
104
|
|
|
96
105
|
if (this.#activeJobId) {
|
|
@@ -105,14 +114,21 @@ export class JobManager {
|
|
|
105
114
|
throw new JobError("LOCKED", MCP_ERRORS.LOCKED.message);
|
|
106
115
|
}
|
|
107
116
|
|
|
117
|
+
if (!this.#accepting) {
|
|
118
|
+
await lock.release();
|
|
119
|
+
this.#assertAccepting();
|
|
120
|
+
}
|
|
121
|
+
|
|
108
122
|
return this.#startJobWithLock(type, fn, lock);
|
|
109
123
|
}
|
|
110
124
|
|
|
111
125
|
async startJobWithLock(
|
|
112
126
|
type: JobType,
|
|
113
127
|
lock: WriteLockHandle,
|
|
114
|
-
fn: () => Promise<SyncResult>
|
|
128
|
+
fn: (signal: AbortSignal) => Promise<SyncResult>
|
|
115
129
|
): Promise<string> {
|
|
130
|
+
assertInferenceActive();
|
|
131
|
+
this.#assertAccepting();
|
|
116
132
|
this.#cleanupExpiredJobs();
|
|
117
133
|
|
|
118
134
|
if (this.#activeJobId) {
|
|
@@ -132,8 +148,10 @@ export class JobManager {
|
|
|
132
148
|
async startTypedJobWithLock(
|
|
133
149
|
type: JobType,
|
|
134
150
|
lock: WriteLockHandle,
|
|
135
|
-
fn: () => Promise<JobResult>
|
|
151
|
+
fn: (signal: AbortSignal) => Promise<JobResult>
|
|
136
152
|
): Promise<string> {
|
|
153
|
+
assertInferenceActive();
|
|
154
|
+
this.#assertAccepting();
|
|
137
155
|
this.#cleanupExpiredJobs();
|
|
138
156
|
|
|
139
157
|
if (this.#activeJobId) {
|
|
@@ -205,10 +223,56 @@ export class JobManager {
|
|
|
205
223
|
return { active, recent };
|
|
206
224
|
}
|
|
207
225
|
|
|
226
|
+
/** Internal owner control; cancellation retains the existing failed job schema. */
|
|
227
|
+
cancelJob(jobId: string): boolean {
|
|
228
|
+
const controller = this.#jobControllers.get(jobId);
|
|
229
|
+
if (!controller) return false;
|
|
230
|
+
controller.abort();
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
|
|
208
234
|
async shutdown(): Promise<void> {
|
|
235
|
+
this.stop();
|
|
209
236
|
await Promise.allSettled(this.#activeJobs);
|
|
210
237
|
}
|
|
211
238
|
|
|
239
|
+
stop(): void {
|
|
240
|
+
this.#accepting = false;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
cancel(): void {
|
|
244
|
+
this.stop();
|
|
245
|
+
for (const controller of this.#jobControllers.values()) controller.abort();
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** Call only after the shared shutdown budget; late callbacks stay canceled. */
|
|
249
|
+
async failUnfinished(): Promise<void> {
|
|
250
|
+
this.cancel();
|
|
251
|
+
for (const job of this.#jobs.values()) {
|
|
252
|
+
if (job.status !== "running") continue;
|
|
253
|
+
job.status = "failed";
|
|
254
|
+
job.error = "Resident shutdown deadline exceeded";
|
|
255
|
+
job.completedAt = Date.now();
|
|
256
|
+
}
|
|
257
|
+
await Promise.allSettled(
|
|
258
|
+
Array.from(this.#releaseJobLocks.values(), (release) => release())
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
#assertAccepting(): void {
|
|
263
|
+
if (!this.#accepting) throw new Error("Resident runtime is shutting down");
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
#ownLock(jobId: string, lock: WriteLockHandle): WriteLockHandle {
|
|
267
|
+
let releasing: Promise<void> | undefined;
|
|
268
|
+
const owned = {
|
|
269
|
+
release: () =>
|
|
270
|
+
(releasing ??= Promise.resolve().then(() => lock.release())),
|
|
271
|
+
};
|
|
272
|
+
this.#releaseJobLocks.set(jobId, owned.release);
|
|
273
|
+
return owned;
|
|
274
|
+
}
|
|
275
|
+
|
|
212
276
|
#track(jobPromise: Promise<void>): void {
|
|
213
277
|
const tracked = jobPromise.catch(() => undefined);
|
|
214
278
|
this.#activeJobs.add(tracked);
|
|
@@ -219,14 +283,16 @@ export class JobManager {
|
|
|
219
283
|
|
|
220
284
|
async #runJob(
|
|
221
285
|
job: JobRecord,
|
|
222
|
-
fn: () => Promise<SyncResult>,
|
|
286
|
+
fn: (signal: AbortSignal) => Promise<SyncResult>,
|
|
223
287
|
lock: { release: () => Promise<void> }
|
|
224
288
|
): Promise<void> {
|
|
225
289
|
try {
|
|
226
290
|
const release = await this.#toolMutex.acquire();
|
|
227
291
|
try {
|
|
228
292
|
this.#assertAuthorizationEpoch(job);
|
|
229
|
-
|
|
293
|
+
assertInferenceActive();
|
|
294
|
+
const result = await fn(this.#jobControllers.get(job.id)!.signal);
|
|
295
|
+
assertInferenceActive();
|
|
230
296
|
job.status = "completed";
|
|
231
297
|
job.result = result;
|
|
232
298
|
} catch (e) {
|
|
@@ -239,6 +305,8 @@ export class JobManager {
|
|
|
239
305
|
job.status = "failed";
|
|
240
306
|
job.error = e instanceof Error ? e.message : String(e);
|
|
241
307
|
} finally {
|
|
308
|
+
this.#releaseJobLocks.delete(job.id);
|
|
309
|
+
this.#jobControllers.delete(job.id);
|
|
242
310
|
job.completedAt = Date.now();
|
|
243
311
|
this.#activeJobId = null;
|
|
244
312
|
await lock.release().catch(() => undefined);
|
|
@@ -248,10 +316,11 @@ export class JobManager {
|
|
|
248
316
|
|
|
249
317
|
#startJobWithLock(
|
|
250
318
|
type: JobType,
|
|
251
|
-
fn: () => Promise<SyncResult>,
|
|
319
|
+
fn: (signal: AbortSignal) => Promise<SyncResult>,
|
|
252
320
|
lock: WriteLockHandle
|
|
253
321
|
): string {
|
|
254
322
|
const jobId = crypto.randomUUID();
|
|
323
|
+
const ownedLock = this.#ownLock(jobId, lock);
|
|
255
324
|
const job: JobRecord = {
|
|
256
325
|
id: jobId,
|
|
257
326
|
type,
|
|
@@ -260,11 +329,15 @@ export class JobManager {
|
|
|
260
329
|
serverInstanceId: this.#serverInstanceId,
|
|
261
330
|
};
|
|
262
331
|
|
|
332
|
+
this.#jobControllers.set(jobId, new AbortController());
|
|
263
333
|
this.#jobs.set(jobId, job);
|
|
264
334
|
this.#jobAuthorizationEpochs.set(jobId, this.#authorizationEpoch);
|
|
265
335
|
this.#activeJobId = jobId;
|
|
266
336
|
|
|
267
|
-
const jobPromise =
|
|
337
|
+
const jobPromise = withOwnedInferenceScope(
|
|
338
|
+
{ signal: this.#jobControllers.get(jobId)!.signal },
|
|
339
|
+
() => withBackgroundInference(() => this.#runJob(job, fn, ownedLock))
|
|
340
|
+
);
|
|
268
341
|
this.#track(jobPromise);
|
|
269
342
|
|
|
270
343
|
return jobId;
|
|
@@ -272,10 +345,11 @@ export class JobManager {
|
|
|
272
345
|
|
|
273
346
|
#startTypedJobWithLock(
|
|
274
347
|
type: JobType,
|
|
275
|
-
fn: () => Promise<JobResult>,
|
|
348
|
+
fn: (signal: AbortSignal) => Promise<JobResult>,
|
|
276
349
|
lock: WriteLockHandle
|
|
277
350
|
): string {
|
|
278
351
|
const jobId = crypto.randomUUID();
|
|
352
|
+
const ownedLock = this.#ownLock(jobId, lock);
|
|
279
353
|
const job: JobRecord = {
|
|
280
354
|
id: jobId,
|
|
281
355
|
type,
|
|
@@ -284,11 +358,15 @@ export class JobManager {
|
|
|
284
358
|
serverInstanceId: this.#serverInstanceId,
|
|
285
359
|
};
|
|
286
360
|
|
|
361
|
+
this.#jobControllers.set(jobId, new AbortController());
|
|
287
362
|
this.#jobs.set(jobId, job);
|
|
288
363
|
this.#jobAuthorizationEpochs.set(jobId, this.#authorizationEpoch);
|
|
289
364
|
this.#activeJobId = jobId;
|
|
290
365
|
|
|
291
|
-
const jobPromise =
|
|
366
|
+
const jobPromise = withOwnedInferenceScope(
|
|
367
|
+
{ signal: this.#jobControllers.get(jobId)!.signal },
|
|
368
|
+
() => withBackgroundInference(() => this.#runTypedJob(job, fn, ownedLock))
|
|
369
|
+
);
|
|
292
370
|
this.#track(jobPromise);
|
|
293
371
|
|
|
294
372
|
return jobId;
|
|
@@ -296,14 +374,16 @@ export class JobManager {
|
|
|
296
374
|
|
|
297
375
|
async #runTypedJob(
|
|
298
376
|
job: JobRecord,
|
|
299
|
-
fn: () => Promise<JobResult>,
|
|
377
|
+
fn: (signal: AbortSignal) => Promise<JobResult>,
|
|
300
378
|
lock: { release: () => Promise<void> }
|
|
301
379
|
): Promise<void> {
|
|
302
380
|
try {
|
|
303
381
|
const release = await this.#toolMutex.acquire();
|
|
304
382
|
try {
|
|
305
383
|
this.#assertAuthorizationEpoch(job);
|
|
306
|
-
|
|
384
|
+
assertInferenceActive();
|
|
385
|
+
const result = await fn(this.#jobControllers.get(job.id)!.signal);
|
|
386
|
+
assertInferenceActive();
|
|
307
387
|
job.status = "completed";
|
|
308
388
|
job.typedResult = result;
|
|
309
389
|
} catch (e) {
|
|
@@ -316,6 +396,8 @@ export class JobManager {
|
|
|
316
396
|
job.status = "failed";
|
|
317
397
|
job.error = e instanceof Error ? e.message : String(e);
|
|
318
398
|
} finally {
|
|
399
|
+
this.#releaseJobLocks.delete(job.id);
|
|
400
|
+
this.#jobControllers.delete(job.id);
|
|
319
401
|
job.completedAt = Date.now();
|
|
320
402
|
this.#activeJobId = null;
|
|
321
403
|
await lock.release().catch(() => undefined);
|
|
@@ -149,6 +149,16 @@ export const NETWORK_BOUNDARY_INVENTORY = [
|
|
|
149
149
|
action: "remote_inference",
|
|
150
150
|
enforcement: "collection_policy",
|
|
151
151
|
},
|
|
152
|
+
{
|
|
153
|
+
// Collection text crosses owned local IPC only. The child receives approved
|
|
154
|
+
// model paths and a restricted environment with downloads/builds disabled.
|
|
155
|
+
id: "native-inference-worker",
|
|
156
|
+
key: "src/llm/native-worker/client.ts::child_process#1",
|
|
157
|
+
path: "src/llm/native-worker/client.ts",
|
|
158
|
+
primitive: "child_process",
|
|
159
|
+
action: null,
|
|
160
|
+
enforcement: "local_process_only",
|
|
161
|
+
},
|
|
152
162
|
{
|
|
153
163
|
id: "pinned-http-fetch",
|
|
154
164
|
key: "src/llm/pinned-http-connection.ts::fetch#1",
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Internal resident shutdown clock. Every participant shares these deadlines. */
|
|
2
|
+
export const SHUTDOWN_DRAIN_MS = 5_000;
|
|
3
|
+
export const SHUTDOWN_ABORT_MS = 5_000;
|
|
4
|
+
export const SHUTDOWN_EXIT_MS = 1_000;
|
|
5
|
+
// The detached parent must not be killed before it can reap its native child.
|
|
6
|
+
export const RESIDENT_STOP_GRACE_MS = 12_000;
|
|
7
|
+
|
|
8
|
+
/** Observe settlement without abandoning rejection handling or retaining a timer. */
|
|
9
|
+
export async function settlesBy(
|
|
10
|
+
work: Promise<unknown>,
|
|
11
|
+
deadline: number,
|
|
12
|
+
interrupt?: AbortSignal
|
|
13
|
+
): Promise<boolean> {
|
|
14
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
15
|
+
let interrupted: (() => void) | undefined;
|
|
16
|
+
try {
|
|
17
|
+
return await Promise.race([
|
|
18
|
+
work.then(() => true),
|
|
19
|
+
new Promise<false>((resolve) => {
|
|
20
|
+
interrupted = () => resolve(false);
|
|
21
|
+
interrupt?.addEventListener("abort", interrupted, { once: true });
|
|
22
|
+
if (interrupt?.aborted) resolve(false);
|
|
23
|
+
timer = setTimeout(
|
|
24
|
+
() => resolve(false),
|
|
25
|
+
Math.max(0, deadline - performance.now())
|
|
26
|
+
);
|
|
27
|
+
}),
|
|
28
|
+
]);
|
|
29
|
+
} finally {
|
|
30
|
+
clearTimeout(timer);
|
|
31
|
+
if (interrupted) interrupt?.removeEventListener("abort", interrupted);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function shutdownDuration(
|
|
36
|
+
value: number | undefined,
|
|
37
|
+
fallback: number
|
|
38
|
+
): number {
|
|
39
|
+
const duration = value ?? fallback;
|
|
40
|
+
if (!Number.isSafeInteger(duration) || duration < 0)
|
|
41
|
+
throw new RangeError(
|
|
42
|
+
"Shutdown duration must be a nonnegative finite integer"
|
|
43
|
+
);
|
|
44
|
+
return duration;
|
|
45
|
+
}
|
package/src/embed/backlog.ts
CHANGED
|
@@ -1,25 +1,35 @@
|
|
|
1
|
+
import type { EmbeddingPort } from "../llm/types";
|
|
1
2
|
/**
|
|
2
3
|
* Shared embedding backlog processor.
|
|
3
4
|
* Used by CLI embed, Web scheduler, and MCP tools.
|
|
4
5
|
*
|
|
5
6
|
* @module src/embed/backlog
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
-
import type { EmbeddingPort } from "../llm/types";
|
|
9
8
|
import type { StoreResult } from "../store/types";
|
|
10
9
|
import type {
|
|
11
10
|
BacklogItem,
|
|
12
11
|
VectorIndexPort,
|
|
13
12
|
VectorStatsPort,
|
|
14
13
|
} from "../store/vector";
|
|
14
|
+
import type { VectorVariantStore } from "../store/vector/variants";
|
|
15
15
|
|
|
16
|
+
import {
|
|
17
|
+
assertInferenceActive,
|
|
18
|
+
isBackgroundInference,
|
|
19
|
+
} from "../llm/inference-scope";
|
|
16
20
|
import { err, ok } from "../store/types";
|
|
17
|
-
import {
|
|
21
|
+
import { getVectorStatsDatabase } from "../store/vector/stats";
|
|
22
|
+
import { createVectorVariantStore } from "../store/vector/variants";
|
|
23
|
+
import {
|
|
24
|
+
getEmbeddingFingerprint,
|
|
25
|
+
getVariantModelFingerprint,
|
|
26
|
+
} from "./fingerprint";
|
|
18
27
|
import {
|
|
19
28
|
chunkRetryKey,
|
|
20
29
|
embedAndStoreBatch,
|
|
21
30
|
MAX_EMBED_CHUNK_ATTEMPTS,
|
|
22
31
|
} from "./retry";
|
|
32
|
+
import { embedVariantBacklog } from "./variant-backlog";
|
|
23
33
|
|
|
24
34
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
25
35
|
// Types
|
|
@@ -32,6 +42,11 @@ export interface EmbedBacklogDeps {
|
|
|
32
42
|
collection?: string;
|
|
33
43
|
modelUri: string;
|
|
34
44
|
batchSize?: number;
|
|
45
|
+
force?: boolean;
|
|
46
|
+
onProgress?: (embedded: number, errors: number) => void;
|
|
47
|
+
variantStore?: VectorVariantStore;
|
|
48
|
+
/** Recheck the effective runtime identity after asynchronous inference. */
|
|
49
|
+
identityStillCurrent?: () => boolean;
|
|
35
50
|
}
|
|
36
51
|
|
|
37
52
|
export interface EmbedBacklogResult {
|
|
@@ -62,8 +77,16 @@ interface Cursor {
|
|
|
62
77
|
export async function embedBacklog(
|
|
63
78
|
deps: EmbedBacklogDeps
|
|
64
79
|
): Promise<StoreResult<EmbedBacklogResult>> {
|
|
80
|
+
assertInferenceActive();
|
|
81
|
+
const prepared = await prepareEmbeddingBacklog(deps);
|
|
82
|
+
if (!prepared.ok) return prepared;
|
|
83
|
+
deps = prepared.value;
|
|
84
|
+
if (deps.variantStore) return embedVariantBacklog(deps, deps.variantStore);
|
|
65
85
|
const { statsPort, embedPort, vectorIndex, modelUri, collection } = deps;
|
|
66
|
-
const
|
|
86
|
+
const background = isBackgroundInference();
|
|
87
|
+
const batchSize = background
|
|
88
|
+
? Math.min(deps.batchSize ?? 32, 32)
|
|
89
|
+
: (deps.batchSize ?? 32);
|
|
67
90
|
const embedFingerprint = getEmbeddingFingerprint({
|
|
68
91
|
modelUri,
|
|
69
92
|
dimensions: vectorIndex.dimensions,
|
|
@@ -77,6 +100,7 @@ export async function embedBacklog(
|
|
|
77
100
|
|
|
78
101
|
const enqueueRetryItems = (items: BacklogItem[], attempts: number): void => {
|
|
79
102
|
for (const item of items) {
|
|
103
|
+
assertInferenceActive();
|
|
80
104
|
const key = chunkRetryKey(item);
|
|
81
105
|
const existing = retryQueue.get(key);
|
|
82
106
|
retryQueue.set(key, {
|
|
@@ -97,8 +121,10 @@ export async function embedBacklog(
|
|
|
97
121
|
);
|
|
98
122
|
|
|
99
123
|
for (let idx = 0; idx < entries.length; idx += batchSize) {
|
|
124
|
+
assertInferenceActive();
|
|
100
125
|
const slice = entries.slice(idx, idx + batchSize);
|
|
101
126
|
for (const entry of slice) {
|
|
127
|
+
assertInferenceActive();
|
|
102
128
|
retryQueue.delete(chunkRetryKey(entry.item));
|
|
103
129
|
entry.attempts += 1;
|
|
104
130
|
}
|
|
@@ -109,6 +135,8 @@ export async function embedBacklog(
|
|
|
109
135
|
items: slice.map((entry) => entry.item),
|
|
110
136
|
modelUri,
|
|
111
137
|
embedFingerprint,
|
|
138
|
+
identityStillCurrent: deps.identityStillCurrent,
|
|
139
|
+
statsPort,
|
|
112
140
|
});
|
|
113
141
|
|
|
114
142
|
embedded += retryResult.embedded;
|
|
@@ -120,6 +148,7 @@ export async function embedBacklog(
|
|
|
120
148
|
retryResult.retryItems.map((item) => chunkRetryKey(item))
|
|
121
149
|
);
|
|
122
150
|
for (const entry of slice) {
|
|
151
|
+
assertInferenceActive();
|
|
123
152
|
if (!retryByKey.has(chunkRetryKey(entry.item))) {
|
|
124
153
|
continue;
|
|
125
154
|
}
|
|
@@ -136,6 +165,7 @@ export async function embedBacklog(
|
|
|
136
165
|
|
|
137
166
|
try {
|
|
138
167
|
while (true) {
|
|
168
|
+
assertInferenceActive();
|
|
139
169
|
// Get next batch using seek pagination
|
|
140
170
|
const batchResult = await statsPort.getBacklog(
|
|
141
171
|
modelUri,
|
|
@@ -169,10 +199,20 @@ export async function embedBacklog(
|
|
|
169
199
|
items: batch,
|
|
170
200
|
modelUri,
|
|
171
201
|
embedFingerprint,
|
|
202
|
+
identityStillCurrent: deps.identityStillCurrent,
|
|
203
|
+
statsPort,
|
|
172
204
|
});
|
|
173
205
|
embedded += batchStoreResult.embedded;
|
|
174
206
|
errors += batchStoreResult.errors;
|
|
175
207
|
contentionErrors += batchStoreResult.contentionErrors;
|
|
208
|
+
if (background) {
|
|
209
|
+
errors += batchStoreResult.retryItems.length;
|
|
210
|
+
deps.onProgress?.(embedded, errors);
|
|
211
|
+
// Each cursor page is a turn. Failed early pages cannot starve later work.
|
|
212
|
+
await Bun.sleep(0);
|
|
213
|
+
if (deps.identityStillCurrent && !deps.identityStillCurrent()) break;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
176
216
|
enqueueRetryItems(batchStoreResult.retryItems, 1);
|
|
177
217
|
|
|
178
218
|
if (embedded > beforeEmbedded) {
|
|
@@ -198,6 +238,7 @@ export async function embedBacklog(
|
|
|
198
238
|
}
|
|
199
239
|
}
|
|
200
240
|
|
|
241
|
+
assertInferenceActive();
|
|
201
242
|
return ok({ embedded, errors, contentionErrors, syncError });
|
|
202
243
|
} catch (e) {
|
|
203
244
|
return err(
|
|
@@ -206,3 +247,65 @@ export async function embedBacklog(
|
|
|
206
247
|
);
|
|
207
248
|
}
|
|
208
249
|
}
|
|
250
|
+
|
|
251
|
+
/** Resolve authority before counts, dry runs, forced work, or early returns. */
|
|
252
|
+
export async function prepareEmbeddingBacklog(
|
|
253
|
+
deps: EmbedBacklogDeps
|
|
254
|
+
): Promise<StoreResult<EmbedBacklogDeps>> {
|
|
255
|
+
if (deps.variantStore) return ok(deps);
|
|
256
|
+
const db = getVectorStatsDatabase(deps.statsPort);
|
|
257
|
+
if (db) {
|
|
258
|
+
try {
|
|
259
|
+
const initialized = await deps.embedPort.init();
|
|
260
|
+
if (!initialized.ok) return err("INTERNAL", initialized.error.message);
|
|
261
|
+
const identity = deps.embedPort.getIdentity?.();
|
|
262
|
+
if (identity) {
|
|
263
|
+
const identitySnapshot = JSON.stringify(identity);
|
|
264
|
+
const dimensions = deps.embedPort.dimensions();
|
|
265
|
+
const variantStore = await createVectorVariantStore(db, {
|
|
266
|
+
model: deps.modelUri,
|
|
267
|
+
modelFingerprint: getVariantModelFingerprint(
|
|
268
|
+
{ modelUri: deps.modelUri, dimensions },
|
|
269
|
+
identity
|
|
270
|
+
),
|
|
271
|
+
contextSize: identity.contextSize,
|
|
272
|
+
truncationPolicy: identity.truncationPolicy,
|
|
273
|
+
dimensions,
|
|
274
|
+
});
|
|
275
|
+
return ok({
|
|
276
|
+
...deps,
|
|
277
|
+
variantStore,
|
|
278
|
+
identityStillCurrent: () =>
|
|
279
|
+
(deps.identityStillCurrent?.() ?? true) &&
|
|
280
|
+
deps.embedPort.modelUri === deps.modelUri &&
|
|
281
|
+
deps.embedPort.dimensions() === dimensions &&
|
|
282
|
+
JSON.stringify(deps.embedPort.getIdentity?.()) === identitySnapshot,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
// Unverified/HTTP ports retain legacy behavior until variant authority exists.
|
|
286
|
+
if (
|
|
287
|
+
db
|
|
288
|
+
.query(
|
|
289
|
+
"SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'vector_partitions'"
|
|
290
|
+
)
|
|
291
|
+
.get() &&
|
|
292
|
+
db
|
|
293
|
+
.query(
|
|
294
|
+
"SELECT 1 FROM vector_partitions WHERE model = ? AND state = ? AND activated_epoch IS NOT NULL LIMIT 1"
|
|
295
|
+
)
|
|
296
|
+
.get(deps.modelUri, "active")
|
|
297
|
+
) {
|
|
298
|
+
return err(
|
|
299
|
+
"INVALID_INPUT",
|
|
300
|
+
"Effective embedding identity unavailable after variant activation"
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
} catch (cause) {
|
|
304
|
+
return err(
|
|
305
|
+
"QUERY_FAILED",
|
|
306
|
+
cause instanceof Error ? cause.message : String(cause)
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return ok(deps);
|
|
311
|
+
}
|
package/src/embed/batch.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import type { EmbeddingPort, LlmResult } from "../llm/types";
|
|
1
2
|
/**
|
|
2
3
|
* Shared embedding batch helpers.
|
|
3
4
|
*
|
|
4
5
|
* @module src/embed/batch
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
|
-
import type { EmbeddingPort, LlmResult } from "../llm/types";
|
|
8
|
-
|
|
9
8
|
import { getEmbeddingCompatibilityProfile } from "../llm/embedding-compatibility";
|
|
10
9
|
import { inferenceFailedError } from "../llm/errors";
|
|
10
|
+
import {
|
|
11
|
+
assertInferenceActive,
|
|
12
|
+
assertInferenceResult,
|
|
13
|
+
isBackgroundInference,
|
|
14
|
+
} from "../llm/inference-scope";
|
|
11
15
|
|
|
12
16
|
export interface EmbedBatchRecoveryResult {
|
|
13
17
|
vectors: Array<number[] | null>;
|
|
@@ -70,8 +74,26 @@ export async function embedTextsWithRecovery(
|
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
const profile = getEmbeddingCompatibilityProfile(embedPort.modelUri);
|
|
77
|
+
// A background page gets one provider attempt. Recovery remains durable for
|
|
78
|
+
// the next pass instead of expanding the current native scheduling turn.
|
|
79
|
+
if (isBackgroundInference() && profile.batchEmbeddingTrusted) {
|
|
80
|
+
const result = await embedPort.embedBatch(texts);
|
|
81
|
+
assertInferenceResult(result);
|
|
82
|
+
if (!result.ok) return result;
|
|
83
|
+
const complete = result.value.length === texts.length;
|
|
84
|
+
return {
|
|
85
|
+
ok: true,
|
|
86
|
+
value: {
|
|
87
|
+
vectors: complete ? result.value : texts.map(() => null),
|
|
88
|
+
batchFailed: !complete,
|
|
89
|
+
fallbackErrors: complete ? 0 : texts.length,
|
|
90
|
+
failureSamples: complete ? [] : ["Embedding count mismatch"],
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
73
94
|
if (profile.batchEmbeddingTrusted) {
|
|
74
95
|
let batchResult = await embedPort.embedBatch(texts);
|
|
96
|
+
assertInferenceResult(batchResult);
|
|
75
97
|
if (!batchResult.ok) {
|
|
76
98
|
const formattedBatchError = formatFailureMessage(batchResult.error);
|
|
77
99
|
if (isDisposedFailure(formattedBatchError)) {
|
|
@@ -80,6 +102,7 @@ export async function embedTextsWithRecovery(
|
|
|
80
102
|
return reset;
|
|
81
103
|
}
|
|
82
104
|
batchResult = await embedPort.embedBatch(texts);
|
|
105
|
+
assertInferenceResult(batchResult);
|
|
83
106
|
}
|
|
84
107
|
}
|
|
85
108
|
if (batchResult.ok && batchResult.value.length === texts.length) {
|
|
@@ -166,6 +189,7 @@ async function recoverWithAdaptiveBatches(
|
|
|
166
189
|
|
|
167
190
|
if (rangeTexts.length === 1) {
|
|
168
191
|
const result = await embedPort.embed(rangeTexts[0] ?? "");
|
|
192
|
+
assertInferenceResult(result);
|
|
169
193
|
if (result.ok) {
|
|
170
194
|
vectors[offset] = result.value;
|
|
171
195
|
return;
|
|
@@ -179,6 +203,7 @@ async function recoverWithAdaptiveBatches(
|
|
|
179
203
|
null;
|
|
180
204
|
if (!batchAlreadyFailed) {
|
|
181
205
|
batchResult = await embedPort.embedBatch(rangeTexts);
|
|
206
|
+
assertInferenceResult(batchResult);
|
|
182
207
|
}
|
|
183
208
|
if (
|
|
184
209
|
batchResult &&
|
|
@@ -186,6 +211,7 @@ async function recoverWithAdaptiveBatches(
|
|
|
186
211
|
batchResult.value.length === rangeTexts.length
|
|
187
212
|
) {
|
|
188
213
|
for (const [index, vector] of batchResult.value.entries()) {
|
|
214
|
+
assertInferenceActive();
|
|
189
215
|
vectors[offset + index] = vector;
|
|
190
216
|
}
|
|
191
217
|
return;
|
|
@@ -223,6 +249,12 @@ async function recoverWithAdaptiveBatches(
|
|
|
223
249
|
},
|
|
224
250
|
};
|
|
225
251
|
} catch (error) {
|
|
252
|
+
assertInferenceActive();
|
|
253
|
+
if (
|
|
254
|
+
error instanceof Error &&
|
|
255
|
+
["AbortError", "TimeoutError"].includes(error.name)
|
|
256
|
+
)
|
|
257
|
+
throw error;
|
|
226
258
|
return {
|
|
227
259
|
ok: false,
|
|
228
260
|
error: inferenceFailedError(
|
|
@@ -245,7 +277,9 @@ async function recoverIndividually(
|
|
|
245
277
|
let fallbackErrors = 0;
|
|
246
278
|
|
|
247
279
|
for (const text of texts) {
|
|
280
|
+
assertInferenceActive();
|
|
248
281
|
const result = await embedPort.embed(text);
|
|
282
|
+
assertInferenceResult(result);
|
|
249
283
|
if (result.ok) {
|
|
250
284
|
vectors.push(result.value);
|
|
251
285
|
} else {
|
|
@@ -266,6 +300,12 @@ async function recoverIndividually(
|
|
|
266
300
|
},
|
|
267
301
|
};
|
|
268
302
|
} catch (error) {
|
|
303
|
+
assertInferenceActive();
|
|
304
|
+
if (
|
|
305
|
+
error instanceof Error &&
|
|
306
|
+
["AbortError", "TimeoutError"].includes(error.name)
|
|
307
|
+
)
|
|
308
|
+
throw error;
|
|
269
309
|
return {
|
|
270
310
|
ok: false,
|
|
271
311
|
error: inferenceFailedError(
|
package/src/embed/fingerprint.ts
CHANGED
|
@@ -35,3 +35,19 @@ export function getEmbeddingFingerprint(
|
|
|
35
35
|
.update(JSON.stringify(payload))
|
|
36
36
|
.digest("hex");
|
|
37
37
|
}
|
|
38
|
+
|
|
39
|
+
/** Partition provenance combines actual weights/runtime with the unchanged formatter policy. */
|
|
40
|
+
export function getVariantModelFingerprint(
|
|
41
|
+
input: EmbeddingFingerprintInput,
|
|
42
|
+
identity: { modelFingerprint: string; runtimeFingerprint: string }
|
|
43
|
+
): string {
|
|
44
|
+
return new Bun.CryptoHasher("sha256")
|
|
45
|
+
.update(
|
|
46
|
+
JSON.stringify([
|
|
47
|
+
identity.modelFingerprint,
|
|
48
|
+
identity.runtimeFingerprint,
|
|
49
|
+
getEmbeddingFingerprint(input),
|
|
50
|
+
])
|
|
51
|
+
)
|
|
52
|
+
.digest("hex");
|
|
53
|
+
}
|