@qvac/sdk 0.10.2 → 0.11.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/NOTICE +92 -54
- package/dist/client/api/cancel.d.ts +24 -32
- package/dist/client/api/cancel.js +58 -31
- package/dist/client/api/client-request-id.d.ts +17 -0
- package/dist/client/api/client-request-id.js +27 -0
- package/dist/client/api/completion-stream.d.ts +1 -1
- package/dist/client/api/completion-stream.js +34 -3
- package/dist/client/api/diffusion.d.ts +46 -0
- package/dist/client/api/diffusion.js +50 -1
- package/dist/client/api/download-asset.d.ts +12 -2
- package/dist/client/api/download-asset.js +21 -3
- package/dist/client/api/embed.d.ts +8 -4
- package/dist/client/api/embed.js +14 -1
- package/dist/client/api/get-model-info.d.ts +1 -1
- package/dist/client/api/index.d.ts +1 -0
- package/dist/client/api/index.js +1 -0
- package/dist/client/api/load-model.d.ts +12 -4
- package/dist/client/api/load-model.js +25 -1
- package/dist/client/api/rag.d.ts +9 -3
- package/dist/client/api/rag.js +23 -3
- package/dist/client/api/transcribe.d.ts +20 -8
- package/dist/client/api/transcribe.js +58 -4
- package/dist/client/api/unload-model.d.ts +5 -2
- package/dist/client/api/unload-model.js +9 -4
- package/dist/client/api/upscale.d.ts +45 -0
- package/dist/client/api/upscale.js +99 -0
- package/dist/client/rpc/expo-rpc-client.js +2 -1
- package/dist/client/rpc/node-rpc-client.js +18 -7
- package/dist/client/rpc/rpc-client.d.ts +2 -2
- package/dist/client/rpc/rpc-client.js +10 -4
- package/dist/client/rpc/rpc-error.d.ts +9 -0
- package/dist/client/rpc/rpc-error.js +92 -0
- package/dist/examples/cancel-by-request-id.d.ts +38 -0
- package/dist/examples/cancel-by-request-id.js +103 -0
- package/dist/examples/diffusion-esrgan-upscale.d.ts +2 -0
- package/dist/examples/diffusion-esrgan-upscale.js +78 -0
- package/dist/examples/download-with-cancel.js +10 -10
- package/dist/examples/embed-multi-gpu.d.ts +2 -0
- package/dist/examples/embed-multi-gpu.js +46 -0
- package/dist/examples/llamacpp-multi-gpu.d.ts +2 -0
- package/dist/examples/llamacpp-multi-gpu.js +57 -0
- package/dist/examples/rag/rag-hyperdb/cancellation.js +20 -17
- package/dist/examples/tools/llamacpp-tools-gemma4.d.ts +2 -0
- package/dist/examples/tools/llamacpp-tools-gemma4.js +76 -0
- package/dist/examples/tools/llamacpp-tools-qwen35.d.ts +2 -0
- package/dist/examples/tools/llamacpp-tools-qwen35.js +70 -0
- package/dist/examples/transcription/whispercpp-microphone-conversation.d.ts +2 -0
- package/dist/examples/transcription/whispercpp-microphone-conversation.js +102 -0
- package/dist/examples/tts/supertonic.js +1 -1
- package/dist/expo/plugins/withMobileBundle.d.ts +20 -4
- package/dist/expo/plugins/withMobileBundle.js +44 -6
- package/dist/index.d.ts +5 -2
- package/dist/index.js +21 -1
- package/dist/models/registry/models.d.ts +186 -318
- package/dist/models/registry/models.js +1522 -1667
- package/dist/pear/pre.d.ts +3 -0
- package/dist/pear/pre.js +3 -0
- package/dist/schemas/cancel.d.ts +167 -28
- package/dist/schemas/cancel.js +119 -19
- package/dist/schemas/common.d.ts +427 -208
- package/dist/schemas/common.js +3 -1
- package/dist/schemas/completion-event.d.ts +14 -0
- package/dist/schemas/completion-event.js +11 -1
- package/dist/schemas/completion-stream.d.ts +15 -1
- package/dist/schemas/completion-stream.js +25 -7
- package/dist/schemas/download-asset.d.ts +15 -9
- package/dist/schemas/download-asset.js +17 -6
- package/dist/schemas/embed.d.ts +1 -0
- package/dist/schemas/embed.js +5 -0
- package/dist/schemas/error.d.ts +31 -0
- package/dist/schemas/error.js +29 -1
- package/dist/schemas/finetune.d.ts +2 -0
- package/dist/schemas/finetune.js +5 -0
- package/dist/schemas/get-model-info.d.ts +6 -6
- package/dist/schemas/llamacpp-config.d.ts +54 -8
- package/dist/schemas/llamacpp-config.js +12 -0
- package/dist/schemas/load-model.d.ts +1911 -1260
- package/dist/schemas/load-model.js +15 -0
- package/dist/schemas/model-src-utils.d.ts +14 -14
- package/dist/schemas/model-types.d.ts +10 -10
- package/dist/schemas/ocr.d.ts +3 -3
- package/dist/schemas/plugin.d.ts +40 -1
- package/dist/schemas/plugin.js +10 -1
- package/dist/schemas/rag.d.ts +9 -0
- package/dist/schemas/rag.js +17 -9
- package/dist/schemas/registry.d.ts +30 -30
- package/dist/schemas/reload-config.d.ts +14 -14
- package/dist/schemas/sdcpp-config.d.ts +131 -17
- package/dist/schemas/sdcpp-config.js +163 -1
- package/dist/schemas/sdk-config.d.ts +649 -271
- package/dist/schemas/sdk-errors-client.d.ts +1 -0
- package/dist/schemas/sdk-errors-client.js +5 -0
- package/dist/schemas/sdk-errors-server.d.ts +5 -0
- package/dist/schemas/sdk-errors-server.js +25 -0
- package/dist/schemas/text-to-speech.d.ts +78 -78
- package/dist/schemas/transcription-config.d.ts +24 -24
- package/dist/schemas/transcription.d.ts +56 -2
- package/dist/schemas/transcription.js +27 -0
- package/dist/schemas/translate.d.ts +2 -0
- package/dist/schemas/translate.js +13 -2
- package/dist/schemas/translation-config.d.ts +40 -40
- package/dist/schemas/unload-model.d.ts +2 -1
- package/dist/schemas/unload-model.js +4 -1
- package/dist/scripts/run-unit-tests.js +15 -2
- package/dist/server/bare/ops/cancel.d.ts +27 -1
- package/dist/server/bare/ops/cancel.js +36 -10
- package/dist/server/bare/ops/embed.d.ts +3 -3
- package/dist/server/bare/ops/embed.js +144 -28
- package/dist/server/bare/ops/kv-cache-utils.d.ts +0 -7
- package/dist/server/bare/ops/kv-cache-utils.js +8 -47
- package/dist/server/bare/ops/transcribe.d.ts +10 -5
- package/dist/server/bare/ops/transcribe.js +196 -41
- package/dist/server/bare/ops/translate.d.ts +1 -1
- package/dist/server/bare/ops/translate.js +197 -88
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.d.ts +12 -3
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +170 -172
- package/dist/server/bare/plugins/llamacpp-completion/ops/finetune.js +125 -21
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-session.d.ts +154 -0
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-session.js +448 -0
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.d.ts +21 -73
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.js +18 -101
- package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +30 -3
- package/dist/server/bare/plugins/llamacpp-completion/plugin.js +157 -85
- package/dist/server/bare/plugins/llamacpp-completion/transform.d.ts +10 -0
- package/dist/server/bare/plugins/llamacpp-completion/transform.js +34 -0
- package/dist/server/bare/plugins/llamacpp-embedding/plugin.d.ts +7 -0
- package/dist/server/bare/plugins/llamacpp-embedding/plugin.js +10 -1
- package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +17 -15
- package/dist/server/bare/plugins/nmtcpp-translation/plugin.js +5 -1
- package/dist/server/bare/plugins/onnx-ocr/plugin.d.ts +3 -3
- package/dist/server/bare/plugins/onnx-ocr/plugin.js +3 -0
- package/dist/server/bare/plugins/onnx-tts/plugin.d.ts +39 -39
- package/dist/server/bare/plugins/onnx-tts/plugin.js +6 -0
- package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +29 -21
- package/dist/server/bare/plugins/parakeet-transcription/plugin.js +4 -1
- package/dist/server/bare/plugins/sdcpp-generation/ops/diffusion.js +8 -0
- package/dist/server/bare/plugins/sdcpp-generation/ops/upscale.d.ts +3 -0
- package/dist/server/bare/plugins/sdcpp-generation/ops/upscale.js +40 -0
- package/dist/server/bare/plugins/sdcpp-generation/plugin.d.ts +91 -16
- package/dist/server/bare/plugins/sdcpp-generation/plugin.js +97 -7
- package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +22 -3
- package/dist/server/bare/plugins/whispercpp-transcription/plugin.js +50 -14
- package/dist/server/bare/rag-hyperdb/index.d.ts +1 -1
- package/dist/server/bare/rag-hyperdb/index.js +1 -1
- package/dist/server/bare/rag-hyperdb/rag-operation-manager.d.ts +26 -4
- package/dist/server/bare/rag-hyperdb/rag-operation-manager.js +65 -28
- package/dist/server/bare/runtime/disposable-scope.d.ts +36 -0
- package/dist/server/bare/runtime/disposable-scope.js +69 -0
- package/dist/server/bare/runtime/index.d.ts +8 -0
- package/dist/server/bare/runtime/index.js +3 -0
- package/dist/server/bare/runtime/request-context.d.ts +49 -0
- package/dist/server/bare/runtime/request-context.js +1 -0
- package/dist/server/bare/runtime/request-id.d.ts +12 -0
- package/dist/server/bare/runtime/request-id.js +14 -0
- package/dist/server/bare/runtime/request-registry-singleton.d.ts +4 -0
- package/dist/server/bare/runtime/request-registry-singleton.js +27 -0
- package/dist/server/bare/runtime/request-registry.d.ts +136 -0
- package/dist/server/bare/runtime/request-registry.js +297 -0
- package/dist/server/bare/runtime/with-request-context.d.ts +22 -0
- package/dist/server/bare/runtime/with-request-context.js +53 -0
- package/dist/server/bare/types/addon-responses.d.ts +11 -1
- package/dist/server/rpc/handler-registry.js +26 -7
- package/dist/server/rpc/handlers/cancel-delegated.js +28 -31
- package/dist/server/rpc/handlers/cancelHandler.d.ts +30 -1
- package/dist/server/rpc/handlers/cancelHandler.js +54 -22
- package/dist/server/rpc/handlers/delete-cache.d.ts +9 -0
- package/dist/server/rpc/handlers/delete-cache.js +13 -15
- package/dist/server/rpc/handlers/download-asset.js +133 -40
- package/dist/server/rpc/handlers/index.d.ts +2 -0
- package/dist/server/rpc/handlers/index.js +2 -0
- package/dist/server/rpc/handlers/load-model/download-manager.d.ts +60 -2
- package/dist/server/rpc/handlers/load-model/download-manager.js +141 -8
- package/dist/server/rpc/handlers/load-model/handler.js +213 -98
- package/dist/server/rpc/handlers/load-model/http.js +3 -3
- package/dist/server/rpc/handlers/load-model/hyperdrive.js +1 -1
- package/dist/server/rpc/handlers/load-model/registry.js +1 -1
- package/dist/server/rpc/handlers/load-model/resolve-session.d.ts +20 -1
- package/dist/server/rpc/handlers/load-model/resolve-session.js +6 -5
- package/dist/server/rpc/handlers/load-model/resolve.d.ts +3 -2
- package/dist/server/rpc/handlers/load-model/resolve.js +9 -6
- package/dist/server/rpc/handlers/load-model/types.d.ts +24 -0
- package/dist/server/rpc/handlers/rag.js +133 -15
- package/dist/server/rpc/handlers/upscale-stream.d.ts +3 -0
- package/dist/server/rpc/handlers/upscale-stream.js +4 -0
- package/dist/server/utils/completion-normalizer.js +8 -0
- package/dist/server/utils/tools/dialect.js +4 -0
- package/dist/server/utils/tools/parser.js +16 -1
- package/dist/server/utils/tools/parsers/gemma4native.d.ts +4 -0
- package/dist/server/utils/tools/parsers/gemma4native.js +60 -0
- package/dist/server/utils/tools/parsers/qwen35.d.ts +4 -0
- package/dist/server/utils/tools/parsers/qwen35.js +120 -0
- package/dist/utils/aggregate-events.d.ts +9 -0
- package/dist/utils/aggregate-events.js +18 -3
- package/dist/utils/decorate-promise.d.ts +34 -0
- package/dist/utils/decorate-promise.js +35 -0
- package/dist/utils/errors-client.d.ts +3 -0
- package/dist/utils/errors-client.js +5 -0
- package/dist/utils/errors-server.d.ts +85 -0
- package/dist/utils/errors-server.js +97 -0
- package/package.json +20 -15
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { AbortController } from "bare-abort-controller";
|
|
2
|
-
import { DownloadCancelledError } from "../../../../utils/errors-server.js";
|
|
2
|
+
import { DownloadCancelledError, InferenceCancelledError, } from "../../../../utils/errors-server.js";
|
|
3
3
|
import { getServerLogger } from "../../../../logging/index.js";
|
|
4
|
+
import { getRequestRegistry } from "../../../bare/runtime/index.js";
|
|
4
5
|
const logger = getServerLogger();
|
|
5
6
|
const activeTransfers = new Map();
|
|
6
7
|
let nextSubscriberId = 0;
|
|
7
|
-
function createSubscriber(onProgress) {
|
|
8
|
+
function createSubscriber(onProgress, requestId) {
|
|
8
9
|
let resolve;
|
|
9
10
|
let reject;
|
|
10
11
|
const promise = new Promise((res, rej) => {
|
|
@@ -18,6 +19,7 @@ function createSubscriber(onProgress) {
|
|
|
18
19
|
resolve,
|
|
19
20
|
reject,
|
|
20
21
|
promise,
|
|
22
|
+
requestId,
|
|
21
23
|
};
|
|
22
24
|
}
|
|
23
25
|
function settleSubscriber(subscriber, result) {
|
|
@@ -45,7 +47,7 @@ function deliverProgress(transfer, subscriber, progress) {
|
|
|
45
47
|
error,
|
|
46
48
|
});
|
|
47
49
|
settleSubscriber(subscriber, error);
|
|
48
|
-
transfer
|
|
50
|
+
removeSubscriber(transfer, subscriber.id);
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
function broadcastTransferProgress(transfer, progress) {
|
|
@@ -54,12 +56,76 @@ function broadcastTransferProgress(transfer, progress) {
|
|
|
54
56
|
deliverProgress(transfer, sub, progress);
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Idempotent: remove the subscriber from the transfer's roster and tear
|
|
61
|
+
* the transfer down iff no subscribers remain. Wired from two places per
|
|
62
|
+
* subscriber:
|
|
63
|
+
*
|
|
64
|
+
* - the `request.signal.addEventListener("abort", ...)` listener that
|
|
65
|
+
* fires when `registry.cancel({ requestId })` aborts the request's
|
|
66
|
+
* context — this is the "user clicked Stop" cancel path;
|
|
67
|
+
* - `request.scope.defer(...)` which runs at request scope unwind —
|
|
68
|
+
* the safety net catching every other unwind path (handler returns,
|
|
69
|
+
* handler throws for a non-cancel reason, awaited promise settled
|
|
70
|
+
* and the `await using` falls out of scope on the success path).
|
|
71
|
+
*
|
|
72
|
+
* Both ends call this helper so an already-cleaned-up subscriber is a
|
|
73
|
+
* no-op the second time around.
|
|
74
|
+
*/
|
|
75
|
+
function removeSubscriber(transfer, subscriberId) {
|
|
76
|
+
if (!transfer.subscribers.has(subscriberId))
|
|
77
|
+
return;
|
|
78
|
+
transfer.subscribers.delete(subscriberId);
|
|
79
|
+
maybeCancelTransfer(transfer);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Last-subscriber rule: when every caller has detached (cancel or
|
|
83
|
+
* progress-callback throw), abort the shared transfer so the underlying
|
|
84
|
+
* HTTP / hyperdrive download tears down. Until then the transfer keeps
|
|
85
|
+
* running for the remaining subscribers — the content-addressed dedup
|
|
86
|
+
* semantics callers rely on.
|
|
87
|
+
*/
|
|
88
|
+
function maybeCancelTransfer(transfer) {
|
|
89
|
+
if (transfer.subscribers.size > 0)
|
|
90
|
+
return;
|
|
91
|
+
if (transfer.abortController.signal.aborted)
|
|
92
|
+
return;
|
|
93
|
+
logger.debug(`[download-manager] last subscriber left, aborting transfer ${transfer.downloadKey}`);
|
|
94
|
+
transfer.abortController.abort();
|
|
95
|
+
}
|
|
96
|
+
function attachRequestBinding(transfer, subscriber, request) {
|
|
97
|
+
const onAbort = () => {
|
|
98
|
+
if (!subscriber.settled) {
|
|
99
|
+
settleSubscriber(subscriber, new InferenceCancelledError(request.requestId));
|
|
100
|
+
}
|
|
101
|
+
removeSubscriber(transfer, subscriber.id);
|
|
102
|
+
};
|
|
103
|
+
if (request.signal.aborted) {
|
|
104
|
+
onAbort();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
request.signal.addEventListener("abort", onAbort, { once: true });
|
|
108
|
+
// Safety net: scope unwind on any handler exit path triggers the same
|
|
109
|
+
// cleanup. If the abort listener already ran it's a no-op. Cleaning
|
|
110
|
+
// up the abort listener here keeps the parent signal from carrying a
|
|
111
|
+
// dangling reference into the next request.
|
|
112
|
+
request.scope.defer(() => {
|
|
113
|
+
request.signal.removeEventListener("abort", onAbort);
|
|
114
|
+
if (!subscriber.settled) {
|
|
115
|
+
settleSubscriber(subscriber, new InferenceCancelledError(request.requestId));
|
|
116
|
+
}
|
|
117
|
+
removeSubscriber(transfer, subscriber.id);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
export function startOrJoinDownload(downloadKey, startDownload, onProgress, request) {
|
|
58
121
|
const existing = activeTransfers.get(downloadKey);
|
|
59
122
|
if (existing && !existing.abortController.signal.aborted) {
|
|
60
123
|
logger.info(`📥 Reusing existing download for: ${downloadKey}`);
|
|
61
|
-
const subscriber = createSubscriber(onProgress);
|
|
124
|
+
const subscriber = createSubscriber(onProgress, request?.requestId);
|
|
62
125
|
existing.subscribers.set(subscriber.id, subscriber);
|
|
126
|
+
if (request) {
|
|
127
|
+
attachRequestBinding(existing, subscriber, request);
|
|
128
|
+
}
|
|
63
129
|
if (existing.lastProgress) {
|
|
64
130
|
deliverProgress(existing, subscriber, existing.lastProgress);
|
|
65
131
|
}
|
|
@@ -76,9 +142,12 @@ export function startOrJoinDownload(downloadKey, startDownload, onProgress) {
|
|
|
76
142
|
subscribers: new Map(),
|
|
77
143
|
clearCache: false,
|
|
78
144
|
};
|
|
79
|
-
const initialSubscriber = createSubscriber(onProgress);
|
|
145
|
+
const initialSubscriber = createSubscriber(onProgress, request?.requestId);
|
|
80
146
|
transfer.subscribers.set(initialSubscriber.id, initialSubscriber);
|
|
81
147
|
activeTransfers.set(downloadKey, transfer);
|
|
148
|
+
if (request) {
|
|
149
|
+
attachRequestBinding(transfer, initialSubscriber, request);
|
|
150
|
+
}
|
|
82
151
|
const downloadPromise = startDownload({
|
|
83
152
|
broadcastProgress: (progress) => {
|
|
84
153
|
broadcastTransferProgress(transfer, progress);
|
|
@@ -110,14 +179,78 @@ export function startOrJoinDownload(downloadKey, startDownload, onProgress) {
|
|
|
110
179
|
getCacheHit: () => transfer.cacheHit,
|
|
111
180
|
};
|
|
112
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Legacy cancel entry point. Callers (`cancelHandler`'s deprecated
|
|
184
|
+
* `case "downloadAsset"` arm, the shutdown sweep, intra-resolve
|
|
185
|
+
* cleanup) call this with a `downloadKey`. The single source of cancel
|
|
186
|
+
* routing is the request registry, so this function resolves each
|
|
187
|
+
* subscriber's request via `registry.cancel({ requestId })`.
|
|
188
|
+
*
|
|
189
|
+
* Subscribers without a `requestId` (legacy callers that didn't pass a
|
|
190
|
+
* registry binding) are settled directly with `DownloadCancelledError`
|
|
191
|
+
* so we don't leak the transfer if a legacy code path holds the only
|
|
192
|
+
* reference.
|
|
193
|
+
*/
|
|
194
|
+
/**
|
|
195
|
+
* Set `clearCache=true` on the transfer that owns the subscriber bound
|
|
196
|
+
* to `requestId`, so when the registry's targeted cancel removes that
|
|
197
|
+
* subscriber and we reach last-subscriber teardown, the partial
|
|
198
|
+
* download file is deleted instead of preserved for automatic resume.
|
|
199
|
+
*
|
|
200
|
+
* Lookup is O(transfers * subscribers); transfers are short-lived and
|
|
201
|
+
* subscriber counts per transfer are tiny in practice, so this is
|
|
202
|
+
* fine. Returns `true` if a matching subscriber was found, `false`
|
|
203
|
+
* otherwise — the cancel handler treats both cases identically (the
|
|
204
|
+
* registry cancel still fires) and the return value is informational.
|
|
205
|
+
*
|
|
206
|
+
* Added in 0.11.0 to support `cancel({ requestId, clearCache: true })`
|
|
207
|
+
* for download requests after the wire schema collapse removed the
|
|
208
|
+
* `{ operation: "downloadAsset", downloadKey, clearCache }` arm. The
|
|
209
|
+
* subscriber is the unit of `clearCache` even though the flag lives on
|
|
210
|
+
* the shared transfer: if any subscriber on the transfer asks for
|
|
211
|
+
* clearCache, the partial file is deleted when the last subscriber
|
|
212
|
+
* leaves, matching the pre-collapse behaviour.
|
|
213
|
+
*/
|
|
214
|
+
export function markClearCacheForRequest(requestId) {
|
|
215
|
+
for (const transfer of activeTransfers.values()) {
|
|
216
|
+
for (const sub of transfer.subscribers.values()) {
|
|
217
|
+
if (sub.requestId === requestId) {
|
|
218
|
+
transfer.clearCache = true;
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
113
225
|
export function cancelTransfer(downloadKey, clearCache = false) {
|
|
114
226
|
const transfer = activeTransfers.get(downloadKey);
|
|
115
227
|
if (!transfer)
|
|
116
228
|
return;
|
|
117
229
|
transfer.clearCache = clearCache;
|
|
118
|
-
|
|
119
|
-
|
|
230
|
+
const registry = getRequestRegistry();
|
|
231
|
+
const orphanSubs = [];
|
|
232
|
+
for (const sub of Array.from(transfer.subscribers.values())) {
|
|
233
|
+
if (sub.requestId !== undefined) {
|
|
234
|
+
registry.cancel({
|
|
235
|
+
requestId: sub.requestId,
|
|
236
|
+
reason: "download-transfer-cancel",
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
orphanSubs.push(sub);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (orphanSubs.length === 0) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
// Legacy subscribers (no registry binding): settle each with
|
|
247
|
+
// `DownloadCancelledError` and route removal through the
|
|
248
|
+
// `removeSubscriber` helper so the last-subscriber teardown rule is
|
|
249
|
+
// enforced in one place. Registry-bound subscribers are handled by
|
|
250
|
+
// their `attachRequestBinding` listener triggered above.
|
|
251
|
+
for (const sub of orphanSubs) {
|
|
120
252
|
settleSubscriber(sub, new DownloadCancelledError());
|
|
253
|
+
removeSubscriber(transfer, sub.id);
|
|
121
254
|
}
|
|
122
255
|
}
|
|
123
256
|
export function createHyperdriveDownloadKey(hyperdriveKey, modelFileName) {
|
|
@@ -1,3 +1,55 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
48
|
+
};
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
1
53
|
import { normalizeModelType, PROFILING_KEY, OPERATION_EVENT_KEY, } from "../../../../schemas/index.js";
|
|
2
54
|
import { loadModel } from "../../../bare/ops/load-model.js";
|
|
3
55
|
import { createResolveSession } from "./resolve-session.js";
|
|
@@ -5,120 +57,183 @@ import { nowMs, generateProfileId } from "../../../../profiling/clock.js";
|
|
|
5
57
|
import { getModelEntry, updateModelConfig, } from "../../../bare/registry/model-registry.js";
|
|
6
58
|
import { generateShortHash, canonicalConfigString, transformConfigForReload, } from "../../../utils/index.js";
|
|
7
59
|
import { buildDownloadProfilingFields } from "./types.js";
|
|
8
|
-
import { ConfigReloadNotSupportedError, ModelTypeMismatchError, ModelIsDelegatedError, ModelNotFoundError, ModelLoadFailedError, PluginLoadConfigValidationFailedError, PluginNotFoundError, } from "../../../../utils/errors-server.js";
|
|
60
|
+
import { ConfigReloadNotSupportedError, InferenceCancelledError, ModelTypeMismatchError, ModelIsDelegatedError, ModelNotFoundError, ModelLoadFailedError, PluginLoadConfigValidationFailedError, PluginNotFoundError, } from "../../../../utils/errors-server.js";
|
|
9
61
|
import { getServerLogger } from "../../../../logging/index.js";
|
|
10
62
|
import { getPlugin } from "../../../plugins/index.js";
|
|
63
|
+
import { getRequestRegistry, withRequestContext, } from "../../../bare/runtime/index.js";
|
|
64
|
+
import { generateServerRequestId } from "../../../bare/runtime/request-id.js";
|
|
11
65
|
const logger = getServerLogger();
|
|
12
66
|
// ---------------------------------------------------------------------------
|
|
13
67
|
// Handler
|
|
14
68
|
// ---------------------------------------------------------------------------
|
|
15
69
|
export async function handleLoadModel(request, progressCallback) {
|
|
16
|
-
|
|
17
|
-
return handleConfigReload(request);
|
|
18
|
-
}
|
|
19
|
-
const { modelSrc, modelName, seed } = request;
|
|
20
|
-
const canonicalModelType = normalizeModelType(request.modelType);
|
|
21
|
-
const profilingMeta = request[PROFILING_KEY];
|
|
22
|
-
const profilingEnabled = profilingMeta?.enabled !== false && !!profilingMeta;
|
|
70
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
23
71
|
try {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
throw new PluginNotFoundError(canonicalModelType);
|
|
72
|
+
if (isReloadConfigRequest(request)) {
|
|
73
|
+
return handleConfigReload(request);
|
|
27
74
|
}
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
let resolvedModelPath;
|
|
45
|
-
let pluginResolveResult;
|
|
75
|
+
const { modelSrc, modelName, seed } = request;
|
|
76
|
+
const canonicalModelType = normalizeModelType(request.modelType);
|
|
77
|
+
const profilingMeta = request[PROFILING_KEY];
|
|
78
|
+
const profilingEnabled = profilingMeta?.enabled !== false && !!profilingMeta;
|
|
79
|
+
const requestId = request.requestId ?? generateServerRequestId();
|
|
80
|
+
// The handler `modelId` is derived from the config hash below — it
|
|
81
|
+
// isn't known until after `resolveConfig` runs. The registry context
|
|
82
|
+
// is opened with `modelId: undefined` so a cancel-by-modelId fired
|
|
83
|
+
// before the load completes is a clean no-op (rather than matching a
|
|
84
|
+
// half-built entry). Cancel-by-`requestId` works from `begin(...)` on.
|
|
85
|
+
const ctx = __addDisposableResource(env_1, getRequestRegistry().begin({
|
|
86
|
+
requestId,
|
|
87
|
+
kind: "loadModel",
|
|
88
|
+
}), true);
|
|
89
|
+
const log = withRequestContext(getServerLogger(), ctx);
|
|
90
|
+
log.debug(`loadModel start modelSrc=${String(modelSrc ?? "")}`);
|
|
46
91
|
try {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
[resolvedModelPath, pluginResolveResult] = pluginResolve
|
|
51
|
-
? await Promise.all([primaryResolve, pluginResolve])
|
|
52
|
-
: [await primaryResolve, undefined];
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
session.cancelAll();
|
|
56
|
-
throw error;
|
|
57
|
-
}
|
|
58
|
-
const configStr = canonicalConfigString(request.modelConfig);
|
|
59
|
-
const modelHashInput = `${request.modelType}:${modelSrc}:${configStr}`;
|
|
60
|
-
const modelId = generateShortHash(modelHashInput);
|
|
61
|
-
let pluginArtifacts = {};
|
|
62
|
-
if (pluginResolveResult) {
|
|
63
|
-
resolvedModelConfig = pluginResolveResult.config;
|
|
64
|
-
if (pluginResolveResult.artifacts) {
|
|
65
|
-
pluginArtifacts = pluginResolveResult.artifacts;
|
|
92
|
+
const plugin = getPlugin(canonicalModelType);
|
|
93
|
+
if (!plugin) {
|
|
94
|
+
throw new PluginNotFoundError(canonicalModelType);
|
|
66
95
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
let resolvedModelConfig = (request.modelConfig ?? {});
|
|
97
|
+
const parseResult = plugin.loadConfigSchema.safeParse(resolvedModelConfig);
|
|
98
|
+
if (!parseResult.success) {
|
|
99
|
+
const details = parseResult.error.issues
|
|
100
|
+
.map((i) => `${String(i.path.join("."))}: ${i.message}`)
|
|
101
|
+
.join(", ");
|
|
102
|
+
throw new PluginLoadConfigValidationFailedError(canonicalModelType, details);
|
|
103
|
+
}
|
|
104
|
+
resolvedModelConfig = parseResult.data;
|
|
105
|
+
const totalLoadStart = profilingEnabled ? nowMs() : 0;
|
|
106
|
+
const session = createResolveSession({
|
|
107
|
+
progressCallback,
|
|
108
|
+
seed,
|
|
109
|
+
profilingEnabled,
|
|
110
|
+
signal: ctx.signal,
|
|
111
|
+
requestBinding: {
|
|
112
|
+
signal: ctx.signal,
|
|
113
|
+
scope: ctx.scope,
|
|
114
|
+
requestId,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
const primaryResolve = session.resolvePrimaryModelPath(modelSrc);
|
|
118
|
+
let resolvedModelPath;
|
|
119
|
+
let pluginResolveResult;
|
|
120
|
+
try {
|
|
121
|
+
const pluginResolve = plugin.resolveConfig
|
|
122
|
+
? Promise.resolve().then(() => plugin.resolveConfig(resolvedModelConfig, session.createResolveContext(modelSrc, canonicalModelType, modelName)))
|
|
123
|
+
: undefined;
|
|
124
|
+
[resolvedModelPath, pluginResolveResult] = pluginResolve
|
|
125
|
+
? await Promise.all([primaryResolve, pluginResolve])
|
|
126
|
+
: [await primaryResolve, undefined];
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
session.cancelAll();
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
// Phase boundary between download and load. The bare load path
|
|
133
|
+
// (`plugin.createModel(...)` / `model.load(false)`) does not accept
|
|
134
|
+
// an abort signal today, so the only honest cancel hook here is the
|
|
135
|
+
// pre-load gate: if cancel arrived during download / resolveConfig,
|
|
136
|
+
// surface `InferenceCancelledError` before sinking time into the
|
|
137
|
+
// addon work.
|
|
138
|
+
if (ctx.signal.aborted) {
|
|
139
|
+
throw new InferenceCancelledError(requestId);
|
|
140
|
+
}
|
|
141
|
+
const configStr = canonicalConfigString(request.modelConfig);
|
|
142
|
+
const modelHashInput = `${request.modelType}:${modelSrc}:${configStr}`;
|
|
143
|
+
const modelId = generateShortHash(modelHashInput);
|
|
144
|
+
let pluginArtifacts = {};
|
|
145
|
+
if (pluginResolveResult) {
|
|
146
|
+
resolvedModelConfig = pluginResolveResult.config;
|
|
147
|
+
if (pluginResolveResult.artifacts) {
|
|
148
|
+
pluginArtifacts = pluginResolveResult.artifacts;
|
|
149
|
+
}
|
|
99
150
|
}
|
|
100
|
-
if (
|
|
101
|
-
|
|
151
|
+
if ("modelPath" in pluginArtifacts) {
|
|
152
|
+
throw new ModelLoadFailedError("Plugin returned reserved key \"modelPath\" in artifacts; primary model resolution is core-owned");
|
|
102
153
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
154
|
+
if (!resolvedModelPath) {
|
|
155
|
+
throw new ModelLoadFailedError("modelPath resolution failed");
|
|
156
|
+
}
|
|
157
|
+
const loadResult = await loadModel({
|
|
158
|
+
modelId,
|
|
159
|
+
modelPath: resolvedModelPath,
|
|
160
|
+
options: {
|
|
161
|
+
...request,
|
|
162
|
+
modelType: canonicalModelType,
|
|
163
|
+
modelConfig: resolvedModelConfig,
|
|
164
|
+
},
|
|
165
|
+
artifacts: Object.keys(pluginArtifacts).length > 0 ? pluginArtifacts : undefined,
|
|
166
|
+
modelName,
|
|
167
|
+
}, profilingEnabled ? { collectTiming: true } : undefined);
|
|
168
|
+
// Load phase soft-cancel limitation: `plugin.createModel(...)` and
|
|
169
|
+
// `model.load(false)` ran without a signal. A cancel that arrived
|
|
170
|
+
// during the load phase has just landed in the registry but the
|
|
171
|
+
// model is now loaded and registered. Surface
|
|
172
|
+
// `InferenceCancelledError` so the caller's promise rejects
|
|
173
|
+
// consistently — even though the model state is the "loaded"
|
|
174
|
+
// post-condition. The orphan-model edge case is a known
|
|
175
|
+
// limitation that requires a per-load cancel surface on the addon
|
|
176
|
+
// to fix end-to-end.
|
|
177
|
+
if (ctx.signal.aborted) {
|
|
178
|
+
throw new InferenceCancelledError(requestId);
|
|
179
|
+
}
|
|
180
|
+
const response = {
|
|
181
|
+
type: "loadModel",
|
|
182
|
+
success: true,
|
|
183
|
+
modelId,
|
|
184
|
+
};
|
|
185
|
+
if (profilingEnabled) {
|
|
186
|
+
const totalLoadTimeMs = nowMs() - totalLoadStart;
|
|
187
|
+
const profileId = profilingMeta?.id ?? generateProfileId();
|
|
188
|
+
const resolveResult = session.getAggregateResult();
|
|
189
|
+
const { gauges, tags } = buildDownloadProfilingFields(resolveResult?.downloadStats, resolveResult?.sourceType);
|
|
190
|
+
gauges["totalLoadTime"] = totalLoadTimeMs;
|
|
191
|
+
if (loadResult.timing?.modelInitializationTimeMs !== undefined) {
|
|
192
|
+
gauges["modelInitializationTime"] =
|
|
193
|
+
loadResult.timing.modelInitializationTimeMs;
|
|
194
|
+
}
|
|
195
|
+
if (canonicalModelType) {
|
|
196
|
+
tags["modelType"] = canonicalModelType;
|
|
197
|
+
}
|
|
198
|
+
const operationEvent = {
|
|
199
|
+
op: "loadModel",
|
|
200
|
+
kind: "handler",
|
|
201
|
+
ms: totalLoadTimeMs,
|
|
202
|
+
profileId,
|
|
203
|
+
gauges: Object.keys(gauges).length > 0 ? gauges : undefined,
|
|
204
|
+
tags: Object.keys(tags).length > 0 ? tags : undefined,
|
|
205
|
+
};
|
|
206
|
+
response[OPERATION_EVENT_KEY] = operationEvent;
|
|
207
|
+
}
|
|
208
|
+
return response;
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
// `InferenceCancelledError` rides the rejection path verbatim: the
|
|
212
|
+
// client side wants a typed cancel error on the promise it `await`s,
|
|
213
|
+
// not a `{ success: false, error }` envelope that surfaces as a
|
|
214
|
+
// generic `ModelLoadFailedError`. Every other error keeps the
|
|
215
|
+
// legacy `success: false` shape for backward compat with consumers
|
|
216
|
+
// that switch on the envelope.
|
|
217
|
+
if (error instanceof InferenceCancelledError) {
|
|
218
|
+
log.info(`loadModel cancelled requestId=${requestId}`);
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
221
|
+
logger.error("Error loading model:", error);
|
|
222
|
+
return {
|
|
223
|
+
type: "loadModel",
|
|
224
|
+
success: false,
|
|
225
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
110
226
|
};
|
|
111
|
-
response[OPERATION_EVENT_KEY] = operationEvent;
|
|
112
227
|
}
|
|
113
|
-
return response;
|
|
114
228
|
}
|
|
115
|
-
catch (
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
229
|
+
catch (e_1) {
|
|
230
|
+
env_1.error = e_1;
|
|
231
|
+
env_1.hasError = true;
|
|
232
|
+
}
|
|
233
|
+
finally {
|
|
234
|
+
const result_1 = __disposeResources(env_1);
|
|
235
|
+
if (result_1)
|
|
236
|
+
await result_1;
|
|
122
237
|
}
|
|
123
238
|
}
|
|
124
239
|
async function handleConfigReload(request) {
|
|
@@ -398,7 +398,7 @@ export async function downloadModelFromHttp(url, progressCallback, hooks) {
|
|
|
398
398
|
const errorToThrow = error instanceof Error ? error : new Error(String(error));
|
|
399
399
|
throw errorToThrow;
|
|
400
400
|
}
|
|
401
|
-
}, progressCallback);
|
|
401
|
+
}, progressCallback, hooks?.requestBinding);
|
|
402
402
|
return applyJoinedDownloadStats(result, hooks);
|
|
403
403
|
}
|
|
404
404
|
async function downloadShardedModelFromHttp(shardUrl, progressCallback, hooks) {
|
|
@@ -484,7 +484,7 @@ async function downloadShardedModelFromHttp(shardUrl, progressCallback, hooks) {
|
|
|
484
484
|
}
|
|
485
485
|
throw error;
|
|
486
486
|
}
|
|
487
|
-
}, progressCallback);
|
|
487
|
+
}, progressCallback, hooks?.requestBinding);
|
|
488
488
|
return applyJoinedDownloadStats(result, hooks);
|
|
489
489
|
}
|
|
490
490
|
async function downloadShardedModelFromArchive(archiveUrl, progressCallback, hooks) {
|
|
@@ -591,7 +591,7 @@ async function downloadShardedModelFromArchive(archiveUrl, progressCallback, hoo
|
|
|
591
591
|
}
|
|
592
592
|
return firstShardPath;
|
|
593
593
|
}
|
|
594
|
-
}, progressCallback);
|
|
594
|
+
}, progressCallback, hooks?.requestBinding);
|
|
595
595
|
return applyJoinedDownloadStats(result, hooks);
|
|
596
596
|
}
|
|
597
597
|
async function downloadShardsWithConcurrency(shardsToDownload, allShards, concurrency, signal, downloadKey, overallTotal, progressCallback) {
|
|
@@ -557,6 +557,6 @@ export async function downloadModelFromHyperdrive(hyperdriveKey, modelFileName,
|
|
|
557
557
|
const checksumToValidate = expectedChecksum || model?.sha256Checksum || "";
|
|
558
558
|
await downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdriveKey, corestoreDir, downloadKey, checksumToValidate, ctx.broadcastProgress, seed, ctx.signal, hooks, ctx.shouldClearCache);
|
|
559
559
|
return modelPath;
|
|
560
|
-
}, progressCallback);
|
|
560
|
+
}, progressCallback, hooks?.requestBinding);
|
|
561
561
|
return applyJoinedDownloadStats(result, hooks);
|
|
562
562
|
}
|
|
@@ -298,6 +298,6 @@ export async function downloadModelFromRegistry(registryPath, registrySource, pr
|
|
|
298
298
|
throw error;
|
|
299
299
|
}
|
|
300
300
|
return modelPath;
|
|
301
|
-
}, progressCallback);
|
|
301
|
+
}, progressCallback, hooks?.requestBinding);
|
|
302
302
|
return applyJoinedDownloadStats(result, hooks);
|
|
303
303
|
}
|
|
@@ -1,9 +1,28 @@
|
|
|
1
|
+
import type { AbortSignal } from "bare-abort-controller";
|
|
1
2
|
import type { ModelProgressUpdate, ResolveContext } from "../../../../schemas/index";
|
|
2
|
-
import type { ResolveResult } from "./types";
|
|
3
|
+
import type { DownloadRequestBinding, ResolveResult } from "./types";
|
|
3
4
|
export interface ResolveSessionOptions {
|
|
4
5
|
progressCallback?: ((update: ModelProgressUpdate) => void) | undefined;
|
|
5
6
|
seed?: boolean | undefined;
|
|
6
7
|
profilingEnabled: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Optional cancel signal — typically `ctx.signal` from the surrounding
|
|
10
|
+
* `await using ctx = registry.begin(...)` block. When provided,
|
|
11
|
+
* `resolveModelPath` short-circuits with `InferenceCancelledError` if the
|
|
12
|
+
* signal is already aborted on entry; the same signal also propagates
|
|
13
|
+
* to in-progress transfers via the request binding below so cancel
|
|
14
|
+
* tears them down end-to-end.
|
|
15
|
+
*/
|
|
16
|
+
signal?: AbortSignal | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Optional per-request binding threaded into every `startOrJoinDownload`
|
|
19
|
+
* call. The download manager wires a per-subscriber abort listener
|
|
20
|
+
* against `binding.signal`, registers a scope-defer cleanup, and stamps
|
|
21
|
+
* the subscriber with `binding.requestId` so the legacy
|
|
22
|
+
* `cancelTransfer(downloadKey)` path can route through
|
|
23
|
+
* `registry.cancel({ requestId })`.
|
|
24
|
+
*/
|
|
25
|
+
requestBinding?: DownloadRequestBinding | undefined;
|
|
7
26
|
}
|
|
8
27
|
export interface ResolveSession {
|
|
9
28
|
resolvePrimaryModelPath(modelSrc: unknown): Promise<string>;
|
|
@@ -2,7 +2,7 @@ import { resolveModelPath, resolveModelPathWithStats, } from "./resolve.js";
|
|
|
2
2
|
import { cancelTransfer } from "./download-manager.js";
|
|
3
3
|
import { mergeDownloadStats } from "./download-stats.js";
|
|
4
4
|
export function createResolveSession(options) {
|
|
5
|
-
const { progressCallback, seed, profilingEnabled } = options;
|
|
5
|
+
const { progressCallback, seed, profilingEnabled, signal, requestBinding } = options;
|
|
6
6
|
let primaryResult;
|
|
7
7
|
const resolveResults = [];
|
|
8
8
|
const activeDownloadKeys = new Set();
|
|
@@ -10,23 +10,24 @@ export function createResolveSession(options) {
|
|
|
10
10
|
onDownloadKey(key) {
|
|
11
11
|
activeDownloadKeys.add(key);
|
|
12
12
|
},
|
|
13
|
+
...(requestBinding !== undefined && { requestBinding }),
|
|
13
14
|
};
|
|
14
15
|
async function resolvePrimaryModelPath(modelSrc) {
|
|
15
16
|
if (profilingEnabled) {
|
|
16
|
-
const result = await resolveModelPathWithStats(modelSrc, progressCallback, seed, downloadHooks);
|
|
17
|
+
const result = await resolveModelPathWithStats(modelSrc, progressCallback, seed, signal, downloadHooks);
|
|
17
18
|
primaryResult = result;
|
|
18
19
|
resolveResults.push(result);
|
|
19
20
|
return result.path;
|
|
20
21
|
}
|
|
21
|
-
return resolveModelPath(modelSrc, progressCallback, seed, downloadHooks);
|
|
22
|
+
return resolveModelPath(modelSrc, progressCallback, seed, signal, downloadHooks);
|
|
22
23
|
}
|
|
23
24
|
async function resolveForPlugin(src) {
|
|
24
25
|
if (profilingEnabled) {
|
|
25
|
-
const result = await resolveModelPathWithStats(src, progressCallback, seed, downloadHooks);
|
|
26
|
+
const result = await resolveModelPathWithStats(src, progressCallback, seed, signal, downloadHooks);
|
|
26
27
|
resolveResults.push(result);
|
|
27
28
|
return result.path;
|
|
28
29
|
}
|
|
29
|
-
return resolveModelPath(src, progressCallback, seed, downloadHooks);
|
|
30
|
+
return resolveModelPath(src, progressCallback, seed, signal, downloadHooks);
|
|
30
31
|
}
|
|
31
32
|
function createResolveContext(modelSrc, modelType, modelName) {
|
|
32
33
|
return {
|