@qvac/sdk 0.7.1 → 0.8.1
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 +73 -10
- package/README.md +4 -4
- package/bare-imports.json +9 -0
- package/dist/client/api/cancel.d.ts +9 -0
- package/dist/client/api/cancel.js +9 -0
- package/dist/client/api/completion-stream.d.ts +2 -1
- package/dist/client/api/completion-stream.js +2 -1
- package/dist/client/api/download-asset.d.ts +3 -2
- package/dist/client/api/download-asset.js +4 -3
- package/dist/client/api/embed.d.ts +5 -2
- package/dist/client/api/embed.js +2 -2
- package/dist/client/api/get-model-info.d.ts +1 -1
- package/dist/client/api/heartbeat.d.ts +30 -0
- package/dist/client/api/heartbeat.js +38 -0
- package/dist/client/api/index.d.ts +1 -1
- package/dist/client/api/index.js +1 -1
- package/dist/client/api/invoke-plugin.d.ts +3 -2
- package/dist/client/api/invoke-plugin.js +4 -4
- package/dist/client/api/load-model.d.ts +12 -10
- package/dist/client/api/load-model.js +3 -3
- package/dist/client/api/rag.d.ts +10 -10
- package/dist/client/api/rag.js +21 -21
- package/dist/client/api/text-to-speech.d.ts +2 -2
- package/dist/client/api/text-to-speech.js +3 -3
- package/dist/client/api/transcribe.d.ts +5 -3
- package/dist/client/api/transcribe.js +6 -4
- package/dist/client/api/translate.d.ts +2 -2
- package/dist/client/api/translate.js +3 -3
- package/dist/client/rpc/node-rpc-client.d.ts +2 -7
- package/dist/client/rpc/node-rpc-client.js +2 -39
- package/dist/client/rpc/profiling/index.d.ts +2 -0
- package/dist/client/rpc/profiling/index.js +1 -0
- package/dist/client/rpc/profiling/profiler.d.ts +27 -0
- package/dist/client/rpc/profiling/profiler.js +139 -0
- package/dist/client/rpc/rpc-client.d.ts +2 -2
- package/dist/client/rpc/rpc-client.js +174 -12
- package/dist/examples/delegated-inference/consumer-profiled.d.ts +2 -0
- package/dist/examples/delegated-inference/consumer-profiled.js +67 -0
- package/dist/examples/embed-p2p.d.ts +2 -0
- package/dist/examples/llamacpp-multimodal.js +1 -1
- package/dist/examples/llamacpp-p2p.d.ts +2 -0
- package/dist/examples/parallel-download.js +45 -13
- package/dist/examples/profiling/basic.d.ts +2 -0
- package/dist/examples/profiling/basic.js +71 -0
- package/dist/examples/profiling/per-call.d.ts +2 -0
- package/dist/examples/profiling/per-call.js +30 -0
- package/dist/examples/seed-p2p.d.ts +2 -0
- package/dist/examples/transcription/parakeet-ctc-filesystem.d.ts +2 -0
- package/dist/examples/transcription/parakeet-ctc-filesystem.js +40 -0
- package/dist/examples/transcription/parakeet-microphone-record.d.ts +2 -0
- package/dist/examples/transcription/parakeet-microphone-record.js +95 -0
- package/dist/examples/transcription/parakeet-sortformer.d.ts +2 -0
- package/dist/examples/transcription/parakeet-sortformer.js +115 -0
- package/dist/examples/transcription/parakeet-tdt-filesystem.d.ts +2 -0
- package/dist/examples/transcription/parakeet-tdt-filesystem.js +44 -0
- package/dist/examples/translation/translation-bergamot-pivot.d.ts +2 -0
- package/dist/examples/translation/translation-bergamot-pivot.js +73 -0
- package/dist/examples/translation/translation-llm-afriquegemma.d.ts +2 -0
- package/dist/examples/translation/translation-llm-afriquegemma.js +39 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -1
- package/dist/logging/index.d.ts +1 -1
- package/dist/logging/index.js +1 -1
- package/dist/logging/namespaces.d.ts +3 -9
- package/dist/logging/namespaces.js +2 -8
- package/dist/logging/registry.js +15 -1
- package/dist/models/registry/models.d.ts +1671 -310
- package/dist/models/registry/models.js +2116 -710
- package/dist/models/update-models/codegen.js +2 -2
- package/dist/models/update-models/history.d.ts +11 -0
- package/dist/models/update-models/history.js +24 -5
- package/dist/models/update-models/index.js +17 -16
- package/dist/models/update-models/naming.js +56 -0
- package/dist/profiling/aggregator.d.ts +15 -0
- package/dist/profiling/aggregator.js +100 -0
- package/dist/profiling/clock.d.ts +12 -0
- package/dist/profiling/clock.js +51 -0
- package/dist/profiling/controller.d.ts +33 -0
- package/dist/profiling/controller.js +123 -0
- package/dist/profiling/envelope.d.ts +10 -0
- package/dist/profiling/envelope.js +36 -0
- package/dist/profiling/events.d.ts +20 -0
- package/dist/profiling/events.js +37 -0
- package/dist/profiling/exporters.d.ts +10 -0
- package/dist/profiling/exporters.js +236 -0
- package/dist/profiling/index.d.ts +36 -0
- package/dist/profiling/index.js +31 -0
- package/dist/profiling/ring-buffer.d.ts +19 -0
- package/dist/profiling/ring-buffer.js +83 -0
- package/dist/profiling/types.d.ts +47 -0
- package/dist/profiling/types.js +1 -0
- package/dist/schemas/cancel.d.ts +12 -0
- package/dist/schemas/cancel.js +2 -0
- package/dist/schemas/common.d.ts +1927 -135
- package/dist/schemas/common.js +6 -3
- package/dist/schemas/completion-stream.d.ts +31 -0
- package/dist/schemas/completion-stream.js +13 -0
- package/dist/schemas/delegate.d.ts +8 -0
- package/dist/schemas/delegate.js +5 -2
- package/dist/schemas/download-asset.d.ts +14 -3
- package/dist/schemas/download-asset.js +3 -1
- package/dist/schemas/engine-addon-map.js +9 -6
- package/dist/schemas/get-model-info.d.ts +2 -0
- package/dist/schemas/get-model-info.js +1 -0
- package/dist/schemas/heartbeat.d.ts +17 -0
- package/dist/schemas/heartbeat.js +10 -0
- package/dist/schemas/index.d.ts +3 -2
- package/dist/schemas/index.js +3 -2
- package/dist/schemas/llamacpp-config.d.ts +140 -14
- package/dist/schemas/llamacpp-config.js +11 -7
- package/dist/schemas/load-model.d.ts +9762 -2515
- package/dist/schemas/load-model.js +142 -182
- package/dist/schemas/model-src-utils.d.ts +10 -2
- package/dist/schemas/model-types.d.ts +19 -1
- package/dist/schemas/model-types.js +11 -0
- package/dist/schemas/ocr.d.ts +37 -0
- package/dist/schemas/ocr.js +5 -0
- package/dist/schemas/plugin.d.ts +51 -5
- package/dist/schemas/plugin.js +26 -0
- package/dist/schemas/profiling.d.ts +105 -0
- package/dist/schemas/profiling.js +66 -0
- package/dist/schemas/registry.d.ts +18 -0
- package/dist/schemas/registry.js +2 -0
- package/dist/schemas/reload-config.d.ts +126 -6
- package/dist/schemas/reload-config.js +1 -1
- package/dist/schemas/sdk-config.d.ts +2280 -24
- package/dist/schemas/sdk-config.js +6 -1
- package/dist/schemas/sdk-errors-client.d.ts +1 -0
- package/dist/schemas/sdk-errors-client.js +7 -0
- package/dist/schemas/sdk-errors-server.d.ts +3 -0
- package/dist/schemas/sdk-errors-server.js +15 -0
- package/dist/schemas/text-to-speech.d.ts +90 -68
- package/dist/schemas/text-to-speech.js +16 -33
- package/dist/schemas/transcription-config.d.ts +383 -0
- package/dist/schemas/{whispercpp-config.js → transcription-config.js} +29 -1
- package/dist/schemas/translation-config.d.ts +463 -8
- package/dist/schemas/translation-config.js +35 -2
- package/dist/server/bare/delegate-rpc-client.js +52 -11
- package/dist/server/bare/ops/load-model.d.ts +7 -1
- package/dist/server/bare/ops/load-model.js +41 -42
- package/dist/server/bare/ops/transcribe.d.ts +3 -0
- package/dist/server/bare/ops/transcribe.js +75 -0
- package/dist/server/bare/ops/translate.d.ts +2 -0
- package/dist/server/bare/ops/translate.js +12 -4
- package/dist/server/bare/plugins/index.d.ts +1 -0
- package/dist/server/bare/plugins/index.js +1 -0
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.d.ts +2 -1
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +8 -6
- package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +108 -3
- package/dist/server/bare/plugins/llamacpp-completion/plugin.js +19 -6
- package/dist/server/bare/plugins/llamacpp-embedding/plugin.d.ts +32 -2
- package/dist/server/bare/plugins/llamacpp-embedding/plugin.js +31 -17
- package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +325 -3
- package/dist/server/bare/plugins/nmtcpp-translation/plugin.js +117 -13
- package/dist/server/bare/plugins/onnx-ocr/plugin.d.ts +50 -2
- package/dist/server/bare/plugins/onnx-ocr/plugin.js +46 -5
- package/dist/server/bare/plugins/onnx-tts/plugin.d.ts +351 -4
- package/dist/server/bare/plugins/onnx-tts/plugin.js +81 -61
- package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +317 -0
- package/dist/server/bare/plugins/parakeet-transcription/plugin.js +154 -0
- package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +209 -3
- package/dist/server/bare/plugins/whispercpp-transcription/plugin.js +21 -9
- package/dist/server/bare/rag-hyperdb/rag-workspace-manager.js +2 -2
- package/dist/server/bare/registry/model-config-utils.js +3 -1
- package/dist/server/bare/registry/model-registry.d.ts +2 -0
- package/dist/server/bare/registry/model-registry.js +2 -1
- package/dist/server/bare/utils/audio-input.d.ts +10 -0
- package/dist/server/bare/utils/audio-input.js +33 -0
- package/dist/server/error-handlers.d.ts +3 -2
- package/dist/server/error-handlers.js +11 -8
- package/dist/server/plugins/registry.js +5 -1
- package/dist/server/rpc/delegate-transport.d.ts +11 -3
- package/dist/server/rpc/delegate-transport.js +214 -38
- package/dist/server/rpc/delegate-utils.d.ts +2 -0
- package/dist/server/rpc/delegate-utils.js +5 -0
- package/dist/server/rpc/handle-request.js +43 -4
- package/dist/server/rpc/handler-registry.js +33 -4
- package/dist/server/rpc/handler-utils.d.ts +5 -4
- package/dist/server/rpc/handler-utils.js +114 -31
- package/dist/server/rpc/handlers/cancel-delegated.d.ts +4 -0
- package/dist/server/rpc/handlers/cancel-delegated.js +71 -0
- package/dist/server/rpc/handlers/completion-stream-delegated.d.ts +3 -1
- package/dist/server/rpc/handlers/completion-stream-delegated.js +13 -4
- package/dist/server/rpc/handlers/download-asset.js +55 -3
- package/dist/server/rpc/handlers/heartbeat-delegated.d.ts +4 -0
- package/dist/server/rpc/handlers/heartbeat-delegated.js +32 -0
- package/dist/server/rpc/handlers/heartbeat.d.ts +3 -0
- package/dist/server/rpc/handlers/heartbeat.js +3 -0
- package/dist/server/rpc/handlers/index.d.ts +2 -2
- package/dist/server/rpc/handlers/index.js +2 -2
- package/dist/server/rpc/handlers/load-model/download-stats.d.ts +6 -0
- package/dist/server/rpc/handlers/load-model/download-stats.js +87 -0
- package/dist/server/rpc/handlers/load-model/handler.js +108 -123
- package/dist/server/rpc/handlers/load-model/http.d.ts +2 -1
- package/dist/server/rpc/handlers/load-model/http.js +21 -5
- package/dist/server/rpc/handlers/load-model/hyperdrive.d.ts +2 -1
- package/dist/server/rpc/handlers/load-model/hyperdrive.js +19 -14
- package/dist/server/rpc/handlers/load-model/registry.d.ts +2 -1
- package/dist/server/rpc/handlers/load-model/registry.js +113 -136
- package/dist/server/rpc/handlers/load-model/resolve.d.ts +2 -0
- package/dist/server/rpc/handlers/load-model/resolve.js +55 -22
- package/dist/server/rpc/handlers/load-model/types.d.ts +29 -0
- package/dist/server/rpc/handlers/load-model/types.js +1 -0
- package/dist/server/rpc/handlers/load-model-delegated.d.ts +5 -1
- package/dist/server/rpc/handlers/load-model-delegated.js +41 -11
- package/dist/server/rpc/handlers/plugin-dispatch.js +15 -10
- package/dist/server/rpc/handlers/plugin-invoke.js +56 -51
- package/dist/server/rpc/handlers/rag.js +24 -0
- package/dist/server/rpc/handlers/unload-model-delegated.d.ts +3 -0
- package/dist/server/rpc/handlers/unload-model-delegated.js +32 -0
- package/dist/server/rpc/profiling/context.d.ts +18 -0
- package/dist/server/rpc/profiling/context.js +38 -0
- package/dist/server/rpc/profiling/delegation-profiler.d.ts +32 -0
- package/dist/server/rpc/profiling/delegation-profiler.js +154 -0
- package/dist/server/rpc/profiling/index.d.ts +5 -0
- package/dist/server/rpc/profiling/index.js +4 -0
- package/dist/server/rpc/profiling/operation-metrics.d.ts +25 -0
- package/dist/server/rpc/profiling/operation-metrics.js +199 -0
- package/dist/server/rpc/profiling/operation-wrappers.d.ts +18 -0
- package/dist/server/rpc/profiling/operation-wrappers.js +124 -0
- package/dist/server/rpc/profiling/profiler.d.ts +13 -0
- package/dist/server/rpc/profiling/profiler.js +97 -0
- package/dist/server/utils/cache.d.ts +2 -1
- package/dist/server/utils/cache.js +5 -1
- package/dist/server/utils/checksum.d.ts +2 -0
- package/dist/server/utils/checksum.js +7 -0
- package/dist/server/utils/formatting.d.ts +6 -0
- package/dist/server/utils/formatting.js +35 -0
- package/dist/server/worker.js +2 -1
- package/dist/utils/errors-client.d.ts +3 -0
- package/dist/utils/errors-client.js +6 -0
- package/dist/utils/errors-server.d.ts +9 -0
- package/dist/utils/errors-server.js +15 -0
- package/dist/utils/global-singleton.d.ts +2 -0
- package/dist/utils/global-singleton.js +10 -0
- package/package.json +22 -18
- package/dist/client/api/ping.d.ts +0 -11
- package/dist/client/api/ping.js +0 -19
- package/dist/examples/embed-hyperdrive.d.ts +0 -2
- package/dist/examples/llamacpp-hyperdrive.d.ts +0 -2
- package/dist/examples/seed-hyperdrive.d.ts +0 -2
- package/dist/schemas/ping.d.ts +0 -11
- package/dist/schemas/ping.js +0 -8
- package/dist/schemas/whispercpp-config.d.ts +0 -70
- package/dist/server/bare/plugins/whispercpp-transcription/ops/transcribe-stream.d.ts +0 -3
- package/dist/server/bare/plugins/whispercpp-transcription/ops/transcribe-stream.js +0 -81
- package/dist/server/rpc/handlers/ping.d.ts +0 -3
- package/dist/server/rpc/handlers/ping.js +0 -3
- /package/dist/examples/{embed-hyperdrive.js → embed-p2p.js} +0 -0
- /package/dist/examples/{llamacpp-hyperdrive.js → llamacpp-p2p.js} +0 -0
- /package/dist/examples/{seed-hyperdrive.js → seed-p2p.js} +0 -0
- /package/dist/examples/{whispercpp-filesystem.d.ts → transcription/whispercpp-filesystem.d.ts} +0 -0
- /package/dist/examples/{whispercpp-filesystem.js → transcription/whispercpp-filesystem.js} +0 -0
- /package/dist/examples/{whispercpp-microphone-record.d.ts → transcription/whispercpp-microphone-record.d.ts} +0 -0
- /package/dist/examples/{whispercpp-microphone-record.js → transcription/whispercpp-microphone-record.js} +0 -0
- /package/dist/examples/{whispercpp-prompt.d.ts → transcription/whispercpp-prompt.d.ts} +0 -0
- /package/dist/examples/{whispercpp-prompt.js → transcription/whispercpp-prompt.js} +0 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { promises as fsPromises } from "bare-fs";
|
|
2
2
|
import path from "bare-path";
|
|
3
|
-
import {} from "bare-stream";
|
|
4
3
|
import { AbortController } from "bare-abort-controller";
|
|
5
|
-
import { getModelsCacheDir, generateShortHash, detectShardedModel, getShardedModelCacheDir, getShardPath, getOnnxModelPath,
|
|
4
|
+
import { getModelsCacheDir, generateShortHash, detectShardedModel, getShardedModelCacheDir, getShardPath, getOnnxModelPath, measureChecksum, extractTensorsFromShards, calculatePercentage, } from "../../../utils/index.js";
|
|
6
5
|
import { getModelByPath } from "../../../../models/registry/index.js";
|
|
7
|
-
import { getRegistryClient
|
|
6
|
+
import { getRegistryClient } from "../../../bare/registry/registry-client.js";
|
|
8
7
|
import { getActiveDownload, registerDownload, unregisterDownload, createRegistryDownloadKey, clearClearCacheFlag, } from "./download-manager.js";
|
|
9
8
|
import { ChecksumValidationFailedError, DownloadCancelledError, ModelNotFoundError, RegistryDownloadFailedError, } from "../../../../utils/errors-server.js";
|
|
10
9
|
import { getServerLogger } from "../../../../logging/index.js";
|
|
@@ -22,7 +21,7 @@ function buildBlobBinding(meta) {
|
|
|
22
21
|
/**
|
|
23
22
|
* Validate a cached file against expected size and checksum.
|
|
24
23
|
*/
|
|
25
|
-
async function validateCachedFile(modelPath, modelFileName, expectedSize, expectedChecksum) {
|
|
24
|
+
async function validateCachedFile(modelPath, modelFileName, expectedSize, expectedChecksum, hooks) {
|
|
26
25
|
try {
|
|
27
26
|
await fsPromises.access(modelPath);
|
|
28
27
|
const localStats = await fsPromises.stat(modelPath);
|
|
@@ -31,7 +30,7 @@ async function validateCachedFile(modelPath, modelFileName, expectedSize, expect
|
|
|
31
30
|
logger.info(`✅ Model cached with correct size: ${modelPath}`);
|
|
32
31
|
// Validate checksum if provided
|
|
33
32
|
if (expectedChecksum && expectedChecksum.length === 64) {
|
|
34
|
-
const checksum = await
|
|
33
|
+
const checksum = await measureChecksum(modelPath, hooks);
|
|
35
34
|
if (checksum !== expectedChecksum) {
|
|
36
35
|
throw new ChecksumValidationFailedError(`${modelFileName}. Expected: ${expectedChecksum}. Actual: ${checksum}. File may be corrupted`);
|
|
37
36
|
}
|
|
@@ -59,89 +58,65 @@ async function validateCachedFile(modelPath, modelFileName, expectedSize, expect
|
|
|
59
58
|
* When blobBinding is provided, uses direct blob download (skips metadata sync).
|
|
60
59
|
* Otherwise falls back to metadata-based downloadModel.
|
|
61
60
|
*/
|
|
62
|
-
async function downloadSingleFileFromRegistry(registryPath, registrySource, modelPath, modelFileName, downloadKey, expectedSize, expectedChecksum, progressCallback, signal, blobBinding) {
|
|
61
|
+
async function downloadSingleFileFromRegistry(registryPath, registrySource, modelPath, modelFileName, downloadKey, expectedSize, expectedChecksum, progressCallback, signal, blobBinding, hooks) {
|
|
63
62
|
if (signal?.aborted) {
|
|
64
63
|
throw new DownloadCancelledError();
|
|
65
64
|
}
|
|
66
65
|
const client = await getRegistryClient();
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
readStream = result.artifact.stream;
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
logger.info(`📥 Downloading from registry: ${registryPath}`);
|
|
79
|
-
const result = await client.downloadModel(registryPath, registrySource, {
|
|
80
|
-
timeout: REGISTRY_STREAM_TIMEOUT_MS,
|
|
81
|
-
});
|
|
82
|
-
if (!("stream" in result.artifact)) {
|
|
83
|
-
throw new RegistryDownloadFailedError(`No stream returned for ${registryPath}`);
|
|
84
|
-
}
|
|
85
|
-
readStream = result.artifact.stream;
|
|
86
|
-
}
|
|
87
|
-
const dir = path.dirname(modelPath);
|
|
88
|
-
await fsPromises.mkdir(dir, { recursive: true });
|
|
89
|
-
const writeStream = fs.createWriteStream(modelPath);
|
|
90
|
-
// Track progress
|
|
91
|
-
let downloadedBytes = 0;
|
|
92
|
-
readStream.on("data", (chunk) => {
|
|
93
|
-
const buffer = chunk;
|
|
94
|
-
downloadedBytes += buffer.length;
|
|
95
|
-
if (progressCallback) {
|
|
96
|
-
progressCallback({
|
|
97
|
-
type: "modelProgress",
|
|
98
|
-
downloaded: downloadedBytes,
|
|
99
|
-
total: expectedSize || downloadedBytes,
|
|
100
|
-
percentage: expectedSize
|
|
101
|
-
? calculatePercentage(downloadedBytes, expectedSize)
|
|
102
|
-
: 0,
|
|
103
|
-
downloadKey,
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
// Pipe stream to file
|
|
108
|
-
readStream.pipe(writeStream);
|
|
109
|
-
// Wait for download to complete
|
|
110
|
-
await new Promise((resolve, reject) => {
|
|
111
|
-
writeStream.on("finish", resolve);
|
|
112
|
-
writeStream.on("error", reject);
|
|
113
|
-
readStream.on("error", reject);
|
|
114
|
-
signal?.addEventListener("abort", () => reject(new Error("Download cancelled")), { once: true });
|
|
115
|
-
});
|
|
116
|
-
logger.info(`✅ Downloaded to ${modelPath}`);
|
|
117
|
-
// Validate file size
|
|
118
|
-
const stats = await fsPromises.stat(modelPath);
|
|
119
|
-
if (expectedSize && stats.size !== expectedSize) {
|
|
120
|
-
await fsPromises.unlink(modelPath).catch(() => { });
|
|
121
|
-
throw new ChecksumValidationFailedError(`${modelFileName}. File size mismatch: expected ${expectedSize}, got ${stats.size}`);
|
|
122
|
-
}
|
|
123
|
-
// Validate checksum
|
|
124
|
-
if (expectedChecksum && expectedChecksum.length === 64) {
|
|
125
|
-
const checksum = await calculateFileChecksum(modelPath);
|
|
126
|
-
if (checksum !== expectedChecksum) {
|
|
127
|
-
await fsPromises.unlink(modelPath);
|
|
128
|
-
throw new ChecksumValidationFailedError(`${modelFileName}. Expected: ${expectedChecksum}. Actual: ${checksum}`);
|
|
129
|
-
}
|
|
130
|
-
logger.info(`✅ Checksum validated for ${modelFileName}`);
|
|
131
|
-
}
|
|
132
|
-
// Send final 100% progress
|
|
133
|
-
if (progressCallback) {
|
|
66
|
+
const dir = path.dirname(modelPath);
|
|
67
|
+
await fsPromises.mkdir(dir, { recursive: true });
|
|
68
|
+
// Adapt registry client's core.on("download") progress to SDK ModelProgressUpdate.
|
|
69
|
+
// This reports network-layer bytes, decoupled from disk I/O backpressure.
|
|
70
|
+
const onProgress = progressCallback
|
|
71
|
+
? (progress) => {
|
|
72
|
+
const total = progress.total || expectedSize || progress.downloaded;
|
|
134
73
|
progressCallback({
|
|
135
74
|
type: "modelProgress",
|
|
136
|
-
downloaded:
|
|
137
|
-
total
|
|
138
|
-
percentage:
|
|
75
|
+
downloaded: progress.downloaded,
|
|
76
|
+
total,
|
|
77
|
+
percentage: total > 0
|
|
78
|
+
? calculatePercentage(progress.downloaded, total)
|
|
79
|
+
: 0,
|
|
139
80
|
downloadKey,
|
|
140
81
|
});
|
|
141
82
|
}
|
|
83
|
+
: undefined;
|
|
84
|
+
const clientOptions = {
|
|
85
|
+
timeout: REGISTRY_STREAM_TIMEOUT_MS,
|
|
86
|
+
outputFile: modelPath,
|
|
87
|
+
...(onProgress && { onProgress }),
|
|
88
|
+
...(signal && { signal: signal }),
|
|
89
|
+
};
|
|
90
|
+
if (blobBinding) {
|
|
91
|
+
logger.info(`📥 Downloading blob directly: ${modelFileName}`);
|
|
92
|
+
await client.downloadBlob(blobBinding, clientOptions);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
logger.info(`📥 Downloading from registry: ${registryPath}`);
|
|
96
|
+
await client.downloadModel(registryPath, registrySource, clientOptions);
|
|
97
|
+
}
|
|
98
|
+
logger.info(`✅ Downloaded to ${modelPath}`);
|
|
99
|
+
const stats = await fsPromises.stat(modelPath);
|
|
100
|
+
if (expectedSize && stats.size !== expectedSize) {
|
|
101
|
+
await fsPromises.unlink(modelPath).catch(() => { });
|
|
102
|
+
throw new ChecksumValidationFailedError(`${modelFileName}. File size mismatch: expected ${expectedSize}, got ${stats.size}`);
|
|
103
|
+
}
|
|
104
|
+
if (expectedChecksum && expectedChecksum.length === 64) {
|
|
105
|
+
const checksum = await measureChecksum(modelPath, hooks);
|
|
106
|
+
if (checksum !== expectedChecksum) {
|
|
107
|
+
await fsPromises.unlink(modelPath);
|
|
108
|
+
throw new ChecksumValidationFailedError(`${modelFileName}. Expected: ${expectedChecksum}. Actual: ${checksum}`);
|
|
109
|
+
}
|
|
110
|
+
logger.info(`✅ Checksum validated for ${modelFileName}`);
|
|
142
111
|
}
|
|
143
|
-
|
|
144
|
-
|
|
112
|
+
if (progressCallback) {
|
|
113
|
+
progressCallback({
|
|
114
|
+
type: "modelProgress",
|
|
115
|
+
downloaded: stats.size,
|
|
116
|
+
total: stats.size,
|
|
117
|
+
percentage: 100,
|
|
118
|
+
downloadKey,
|
|
119
|
+
});
|
|
145
120
|
}
|
|
146
121
|
}
|
|
147
122
|
/**
|
|
@@ -149,53 +124,44 @@ async function downloadSingleFileFromRegistry(registryPath, registrySource, mode
|
|
|
149
124
|
*/
|
|
150
125
|
async function findModelShards(registryPath) {
|
|
151
126
|
const client = await getRegistryClient();
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (!shardInfo.isSharded) {
|
|
156
|
-
throw new Error(`Not a sharded model path: ${registryPath}`);
|
|
157
|
-
}
|
|
158
|
-
// Get path prefix by removing the shard suffix
|
|
159
|
-
const pathPrefix = registryPath.replace(/-\d{5}-of-\d{5}\./, ".");
|
|
160
|
-
const basePath = pathPrefix.substring(0, pathPrefix.lastIndexOf("."));
|
|
161
|
-
logger.info(`🔍 Finding shards with prefix: ${basePath}`);
|
|
162
|
-
// Use indexed path range query instead of fetching all models
|
|
163
|
-
const shards = await client.findModels({
|
|
164
|
-
gte: { path: basePath },
|
|
165
|
-
lte: { path: basePath + "\uffff" },
|
|
166
|
-
});
|
|
167
|
-
// Sort shards by shard number
|
|
168
|
-
const sortedShards = shards
|
|
169
|
-
.filter((s) => {
|
|
170
|
-
const info = detectShardedModel(s.path.split("/").pop() || "");
|
|
171
|
-
return info.isSharded;
|
|
172
|
-
})
|
|
173
|
-
.sort((a, b) => {
|
|
174
|
-
const aInfo = detectShardedModel(a.path.split("/").pop() || "");
|
|
175
|
-
const bInfo = detectShardedModel(b.path.split("/").pop() || "");
|
|
176
|
-
return (aInfo.currentShard || 0) - (bInfo.currentShard || 0);
|
|
177
|
-
})
|
|
178
|
-
.map((s) => ({
|
|
179
|
-
path: s.path,
|
|
180
|
-
source: s.source,
|
|
181
|
-
size: s.blobBinding?.byteLength || 0,
|
|
182
|
-
checksum: s.blobBinding?.["sha256"] ||
|
|
183
|
-
s.sha256 ||
|
|
184
|
-
"",
|
|
185
|
-
}));
|
|
186
|
-
logger.info(`📦 Found ${sortedShards.length} shards`);
|
|
187
|
-
return sortedShards;
|
|
188
|
-
}
|
|
189
|
-
finally {
|
|
190
|
-
await closeRegistryClient();
|
|
127
|
+
const shardInfo = detectShardedModel(registryPath.split("/").pop() || "");
|
|
128
|
+
if (!shardInfo.isSharded) {
|
|
129
|
+
throw new Error(`Not a sharded model path: ${registryPath}`);
|
|
191
130
|
}
|
|
131
|
+
const pathPrefix = registryPath.replace(/-\d{5}-of-\d{5}\./, ".");
|
|
132
|
+
const basePath = pathPrefix.substring(0, pathPrefix.lastIndexOf("."));
|
|
133
|
+
logger.info(`🔍 Finding shards with prefix: ${basePath}`);
|
|
134
|
+
const shards = await client.findModels({
|
|
135
|
+
gte: { path: basePath },
|
|
136
|
+
lte: { path: basePath + "\uffff" },
|
|
137
|
+
});
|
|
138
|
+
const sortedShards = shards
|
|
139
|
+
.filter((s) => {
|
|
140
|
+
const info = detectShardedModel(s.path.split("/").pop() || "");
|
|
141
|
+
return info.isSharded;
|
|
142
|
+
})
|
|
143
|
+
.sort((a, b) => {
|
|
144
|
+
const aInfo = detectShardedModel(a.path.split("/").pop() || "");
|
|
145
|
+
const bInfo = detectShardedModel(b.path.split("/").pop() || "");
|
|
146
|
+
return (aInfo.currentShard || 0) - (bInfo.currentShard || 0);
|
|
147
|
+
})
|
|
148
|
+
.map((s) => ({
|
|
149
|
+
path: s.path,
|
|
150
|
+
source: s.source,
|
|
151
|
+
size: s.blobBinding?.byteLength || 0,
|
|
152
|
+
checksum: s.blobBinding?.["sha256"] ||
|
|
153
|
+
s.sha256 ||
|
|
154
|
+
"",
|
|
155
|
+
}));
|
|
156
|
+
logger.info(`📦 Found ${sortedShards.length} shards`);
|
|
157
|
+
return sortedShards;
|
|
192
158
|
}
|
|
193
159
|
/**
|
|
194
160
|
* Download sharded model files from registry.
|
|
195
161
|
* When localShardMetadata is provided, uses pre-computed metadata + blob direct download
|
|
196
162
|
* instead of querying the registry for shard info.
|
|
197
163
|
*/
|
|
198
|
-
async function downloadShardedFilesFromRegistry(registryPath, registrySource, cacheKey, progressCallback, signal, localShardMetadata) {
|
|
164
|
+
async function downloadShardedFilesFromRegistry(registryPath, registrySource, cacheKey, progressCallback, signal, localShardMetadata, hooks) {
|
|
199
165
|
if (signal?.aborted) {
|
|
200
166
|
throw new DownloadCancelledError();
|
|
201
167
|
}
|
|
@@ -242,7 +208,7 @@ async function downloadShardedFilesFromRegistry(registryPath, registrySource, ca
|
|
|
242
208
|
}
|
|
243
209
|
const shard = shards[i];
|
|
244
210
|
const shardPath = getShardPath(cacheKey, shard.filename);
|
|
245
|
-
const cachedPath = await validateCachedFile(shardPath, shard.filename, shard.size, shard.checksum);
|
|
211
|
+
const cachedPath = await validateCachedFile(shardPath, shard.filename, shard.size, shard.checksum, hooks);
|
|
246
212
|
if (cachedPath) {
|
|
247
213
|
logger.debug(`✅ Shard ${i + 1}/${shards.length} already cached`);
|
|
248
214
|
overallDownloaded += shard.size;
|
|
@@ -283,7 +249,7 @@ async function downloadShardedFilesFromRegistry(registryPath, registrySource, ca
|
|
|
283
249
|
});
|
|
284
250
|
}
|
|
285
251
|
: undefined;
|
|
286
|
-
await downloadSingleFileFromRegistry(shard.path, shard.source, shardPath, shard.filename, downloadKey, shard.size, shard.checksum, shardProgressCallback, signal, shard.blobBinding);
|
|
252
|
+
await downloadSingleFileFromRegistry(shard.path, shard.source, shardPath, shard.filename, downloadKey, shard.size, shard.checksum, shardProgressCallback, signal, shard.blobBinding, hooks);
|
|
287
253
|
overallDownloaded += shard.size;
|
|
288
254
|
logger.info(`✅ Shard ${i + 1}/${shards.length} downloaded`);
|
|
289
255
|
}
|
|
@@ -324,7 +290,7 @@ function findOnnxCompanionDataFile(registryPath) {
|
|
|
324
290
|
* Both files are placed in the same directory to satisfy ONNX Runtime requirements.
|
|
325
291
|
* When blob bindings are provided, uses direct blob download (skips metadata sync).
|
|
326
292
|
*/
|
|
327
|
-
async function downloadOnnxWithDataFromRegistry(registryPath, registrySource, companionDataFile, cacheKey, progressCallback, signal, mainBlobBinding, dataBlobBinding) {
|
|
293
|
+
async function downloadOnnxWithDataFromRegistry(registryPath, registrySource, companionDataFile, cacheKey, progressCallback, signal, mainBlobBinding, dataBlobBinding, hooks) {
|
|
328
294
|
if (signal?.aborted) {
|
|
329
295
|
throw new DownloadCancelledError();
|
|
330
296
|
}
|
|
@@ -342,7 +308,7 @@ async function downloadOnnxWithDataFromRegistry(registryPath, registrySource, co
|
|
|
342
308
|
const overallTotal = mainExpectedSize + dataExpectedSize;
|
|
343
309
|
let overallDownloaded = 0;
|
|
344
310
|
// Check if main file already cached
|
|
345
|
-
const cachedMainPath = await validateCachedFile(mainPath, mainFilename, mainExpectedSize, mainChecksum);
|
|
311
|
+
const cachedMainPath = await validateCachedFile(mainPath, mainFilename, mainExpectedSize, mainChecksum, hooks);
|
|
346
312
|
if (cachedMainPath) {
|
|
347
313
|
logger.info(`✅ Main ONNX file already cached: ${mainFilename}`);
|
|
348
314
|
overallDownloaded += mainExpectedSize;
|
|
@@ -366,12 +332,12 @@ async function downloadOnnxWithDataFromRegistry(registryPath, registrySource, co
|
|
|
366
332
|
});
|
|
367
333
|
}
|
|
368
334
|
: undefined;
|
|
369
|
-
await downloadSingleFileFromRegistry(registryPath, registrySource, mainPath, mainFilename, downloadKey, mainExpectedSize, mainChecksum, mainProgressCallback, signal, mainBlobBinding);
|
|
335
|
+
await downloadSingleFileFromRegistry(registryPath, registrySource, mainPath, mainFilename, downloadKey, mainExpectedSize, mainChecksum, mainProgressCallback, signal, mainBlobBinding, hooks);
|
|
370
336
|
overallDownloaded += mainExpectedSize;
|
|
371
337
|
logger.info(`✅ Main ONNX file downloaded: ${mainFilename}`);
|
|
372
338
|
}
|
|
373
339
|
// Check if data file already cached
|
|
374
|
-
const cachedDataPath = await validateCachedFile(dataPath, dataFilename, dataExpectedSize, dataChecksum);
|
|
340
|
+
const cachedDataPath = await validateCachedFile(dataPath, dataFilename, dataExpectedSize, dataChecksum, hooks);
|
|
375
341
|
if (cachedDataPath) {
|
|
376
342
|
logger.info(`✅ ONNX data file already cached: ${dataFilename}`);
|
|
377
343
|
overallDownloaded = overallTotal;
|
|
@@ -395,7 +361,7 @@ async function downloadOnnxWithDataFromRegistry(registryPath, registrySource, co
|
|
|
395
361
|
});
|
|
396
362
|
}
|
|
397
363
|
: undefined;
|
|
398
|
-
await downloadSingleFileFromRegistry(companionDataFile.registryPath, companionDataFile.registrySource, dataPath, dataFilename, downloadKey, dataExpectedSize, dataChecksum, dataProgressCallback, signal, dataBlobBinding);
|
|
364
|
+
await downloadSingleFileFromRegistry(companionDataFile.registryPath, companionDataFile.registrySource, dataPath, dataFilename, downloadKey, dataExpectedSize, dataChecksum, dataProgressCallback, signal, dataBlobBinding, hooks);
|
|
399
365
|
logger.info(`✅ ONNX data file downloaded: ${dataFilename}`);
|
|
400
366
|
}
|
|
401
367
|
// Send final 100% progress
|
|
@@ -451,12 +417,13 @@ function createManagedDownload(downloadKey, registryPath, downloadFn, progressCa
|
|
|
451
417
|
* skips the registry metadata sync entirely. Falls back to metadata-based
|
|
452
418
|
* download for unknown models.
|
|
453
419
|
*/
|
|
454
|
-
export async function downloadModelFromRegistry(registryPath, registrySource, progressCallback, expectedChecksum) {
|
|
420
|
+
export async function downloadModelFromRegistry(registryPath, registrySource, progressCallback, expectedChecksum, hooks) {
|
|
455
421
|
const downloadKey = createRegistryDownloadKey(registryPath);
|
|
456
422
|
// Check if already downloading
|
|
457
423
|
const existing = getActiveDownload(downloadKey);
|
|
458
424
|
if (existing) {
|
|
459
425
|
logger.info(`📥 Reusing existing download for: ${downloadKey}`);
|
|
426
|
+
hooks?.markCacheMiss();
|
|
460
427
|
return existing.promise;
|
|
461
428
|
}
|
|
462
429
|
const filename = registryPath.split("/").pop() || registryPath;
|
|
@@ -471,7 +438,7 @@ export async function downloadModelFromRegistry(registryPath, registrySource, pr
|
|
|
471
438
|
let allCached = true;
|
|
472
439
|
for (const shard of localShardMeta) {
|
|
473
440
|
const shardPath = getShardPath(cacheKey, shard.filename);
|
|
474
|
-
const cached = await validateCachedFile(shardPath, shard.filename, shard.expectedSize, shard.sha256Checksum);
|
|
441
|
+
const cached = await validateCachedFile(shardPath, shard.filename, shard.expectedSize, shard.sha256Checksum, hooks);
|
|
475
442
|
if (!cached) {
|
|
476
443
|
allCached = false;
|
|
477
444
|
break;
|
|
@@ -480,6 +447,7 @@ export async function downloadModelFromRegistry(registryPath, registrySource, pr
|
|
|
480
447
|
if (allCached) {
|
|
481
448
|
const firstShardFilename = localShardMeta[0].filename;
|
|
482
449
|
logger.info(`✅ All ${localShardMeta.length} shards cached`);
|
|
450
|
+
hooks?.markCacheHit();
|
|
483
451
|
if (progressCallback) {
|
|
484
452
|
const overallTotal = localShardMeta.reduce((sum, s) => sum + s.expectedSize, 0);
|
|
485
453
|
progressCallback({
|
|
@@ -501,7 +469,8 @@ export async function downloadModelFromRegistry(registryPath, registrySource, pr
|
|
|
501
469
|
return getShardPath(cacheKey, firstShardFilename);
|
|
502
470
|
}
|
|
503
471
|
}
|
|
504
|
-
|
|
472
|
+
hooks?.markCacheMiss();
|
|
473
|
+
return createManagedDownload(downloadKey, registryPath, (signal) => downloadShardedFilesFromRegistry(registryPath, registrySource, cacheKey, progressCallback, signal, localShardMeta, hooks), progressCallback);
|
|
505
474
|
}
|
|
506
475
|
// Check for ONNX with companion data file
|
|
507
476
|
const companionDataFile = findOnnxCompanionDataFile(registryPath);
|
|
@@ -512,10 +481,11 @@ export async function downloadModelFromRegistry(registryPath, registrySource, pr
|
|
|
512
481
|
const dataFilename = companionDataFile.registryPath.split("/").pop() || "";
|
|
513
482
|
const mainPath = getOnnxModelPath(cacheKey, mainFilename);
|
|
514
483
|
const dataPath = getOnnxModelPath(cacheKey, dataFilename);
|
|
515
|
-
const mainCached = await validateCachedFile(mainPath, mainFilename, modelMetadata?.expectedSize || 0, modelMetadata?.sha256Checksum);
|
|
516
|
-
const dataCached = await validateCachedFile(dataPath, dataFilename, companionDataFile.expectedSize, companionDataFile.sha256Checksum);
|
|
484
|
+
const mainCached = await validateCachedFile(mainPath, mainFilename, modelMetadata?.expectedSize || 0, modelMetadata?.sha256Checksum, hooks);
|
|
485
|
+
const dataCached = await validateCachedFile(dataPath, dataFilename, companionDataFile.expectedSize, companionDataFile.sha256Checksum, hooks);
|
|
517
486
|
if (mainCached && dataCached) {
|
|
518
487
|
logger.info(`✅ ONNX model and data file both cached`);
|
|
488
|
+
hooks?.markCacheHit();
|
|
519
489
|
if (progressCallback) {
|
|
520
490
|
const total = (modelMetadata?.expectedSize || 0) + companionDataFile.expectedSize;
|
|
521
491
|
progressCallback({
|
|
@@ -536,11 +506,14 @@ export async function downloadModelFromRegistry(registryPath, registrySource, pr
|
|
|
536
506
|
}
|
|
537
507
|
return mainCached;
|
|
538
508
|
}
|
|
539
|
-
const mainBlobBinding = modelMetadata
|
|
509
|
+
const mainBlobBinding = modelMetadata
|
|
510
|
+
? buildBlobBinding(modelMetadata)
|
|
511
|
+
: undefined;
|
|
540
512
|
const dataBlobBinding = companionDataFile.blobCoreKey
|
|
541
513
|
? buildBlobBinding(companionDataFile)
|
|
542
514
|
: undefined;
|
|
543
|
-
|
|
515
|
+
hooks?.markCacheMiss();
|
|
516
|
+
return createManagedDownload(downloadKey, registryPath, (signal) => downloadOnnxWithDataFromRegistry(registryPath, registrySource, companionDataFile, cacheKey, progressCallback, signal, mainBlobBinding, dataBlobBinding, hooks), progressCallback);
|
|
544
517
|
}
|
|
545
518
|
// Single file download
|
|
546
519
|
const cacheDir = getModelsCacheDir();
|
|
@@ -549,9 +522,10 @@ export async function downloadModelFromRegistry(registryPath, registrySource, pr
|
|
|
549
522
|
// Check if already cached
|
|
550
523
|
const expectedSize = modelMetadata?.expectedSize || 0;
|
|
551
524
|
const checksum = expectedChecksum || modelMetadata?.sha256Checksum || "";
|
|
552
|
-
const cachedPath = await validateCachedFile(modelPath, filename, expectedSize, checksum);
|
|
525
|
+
const cachedPath = await validateCachedFile(modelPath, filename, expectedSize, checksum, hooks);
|
|
553
526
|
if (cachedPath) {
|
|
554
527
|
logger.info(`✅ Using cached model: ${cachedPath}`);
|
|
528
|
+
hooks?.markCacheHit();
|
|
555
529
|
if (progressCallback) {
|
|
556
530
|
progressCallback({
|
|
557
531
|
type: "modelProgress",
|
|
@@ -563,9 +537,12 @@ export async function downloadModelFromRegistry(registryPath, registrySource, pr
|
|
|
563
537
|
}
|
|
564
538
|
return cachedPath;
|
|
565
539
|
}
|
|
566
|
-
const blobBinding = modelMetadata
|
|
540
|
+
const blobBinding = modelMetadata
|
|
541
|
+
? buildBlobBinding(modelMetadata)
|
|
542
|
+
: undefined;
|
|
543
|
+
hooks?.markCacheMiss();
|
|
567
544
|
return createManagedDownload(downloadKey, registryPath, async (signal) => {
|
|
568
|
-
await downloadSingleFileFromRegistry(registryPath, registrySource, modelPath, filename, downloadKey, expectedSize, checksum, progressCallback, signal, blobBinding);
|
|
545
|
+
await downloadSingleFileFromRegistry(registryPath, registrySource, modelPath, filename, downloadKey, expectedSize, checksum, progressCallback, signal, blobBinding, hooks);
|
|
569
546
|
return modelPath;
|
|
570
547
|
}, progressCallback);
|
|
571
548
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { type ModelProgressUpdate } from "../../../../schemas/index";
|
|
2
|
+
import type { ResolveResult } from "./types";
|
|
2
3
|
export declare function resolveModelPath(modelSrc: unknown, progressCallback?: (progress: ModelProgressUpdate) => void, seed?: boolean): Promise<string>;
|
|
4
|
+
export declare function resolveModelPathWithStats(modelSrc: unknown, progressCallback?: (progress: ModelProgressUpdate) => void, seed?: boolean): Promise<ResolveResult>;
|
|
3
5
|
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -6,9 +6,11 @@ import path from "bare-path";
|
|
|
6
6
|
import { downloadModelFromHttp } from "./http.js";
|
|
7
7
|
import { downloadModelFromHyperdrive } from "./hyperdrive.js";
|
|
8
8
|
import { downloadModelFromRegistry } from "./registry.js";
|
|
9
|
+
import { downloadModelFromHttpWithStats, downloadModelFromHyperdriveWithStats, downloadModelFromRegistryWithStats, } from "./download-stats.js";
|
|
9
10
|
import { ModelLoadFailedError, ModelNotFoundError, SeedingNotSupportedError, } from "../../../../utils/errors-server.js";
|
|
10
11
|
import { validateAndJoinPath } from "../../../utils/path-security.js";
|
|
11
12
|
import { getServerLogger } from "../../../../logging/index.js";
|
|
13
|
+
import { modelInputToSrcSchema } from "../../../../schemas/index.js";
|
|
12
14
|
const logger = getServerLogger();
|
|
13
15
|
function isArchivePath(filePath) {
|
|
14
16
|
const filename = path.basename(filePath).toLowerCase();
|
|
@@ -61,10 +63,34 @@ async function resolveLocalOrCachedFile(modelIdOrPath) {
|
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
function selectDownloaders(mode) {
|
|
67
|
+
if (mode === "stats") {
|
|
68
|
+
return {
|
|
69
|
+
http: downloadModelFromHttpWithStats,
|
|
70
|
+
registry: downloadModelFromRegistryWithStats,
|
|
71
|
+
hyperdrive: downloadModelFromHyperdriveWithStats,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
http: downloadModelFromHttp,
|
|
76
|
+
registry: downloadModelFromRegistry,
|
|
77
|
+
hyperdrive: downloadModelFromHyperdrive,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function isDownloadResult(value) {
|
|
81
|
+
return value !== null && typeof value === "object" && "path" in value;
|
|
82
|
+
}
|
|
83
|
+
function buildResult(pathOrResult, sourceType) {
|
|
84
|
+
if (isDownloadResult(pathOrResult)) {
|
|
85
|
+
return pathOrResult.stats
|
|
86
|
+
? { path: pathOrResult.path, sourceType, downloadStats: pathOrResult.stats }
|
|
87
|
+
: { path: pathOrResult.path, sourceType };
|
|
88
|
+
}
|
|
89
|
+
return { path: pathOrResult, sourceType };
|
|
90
|
+
}
|
|
91
|
+
async function resolveModelPathCore(modelSrc, progressCallback, seed, mode) {
|
|
67
92
|
const srcString = modelInputToSrcSchema.parse(modelSrc);
|
|
93
|
+
const downloaders = selectDownloaders(mode);
|
|
68
94
|
// Parse hyperdrive URLs if present
|
|
69
95
|
let hyperdriveKey;
|
|
70
96
|
let actualModelSrc = srcString;
|
|
@@ -73,50 +99,57 @@ export async function resolveModelPath(modelSrc, progressCallback, seed) {
|
|
|
73
99
|
hyperdriveKey = key;
|
|
74
100
|
actualModelSrc = pathValue;
|
|
75
101
|
}
|
|
76
|
-
//
|
|
102
|
+
// Registry source
|
|
77
103
|
if (srcString.startsWith("registry://")) {
|
|
78
104
|
const { registryPath, registrySource } = registryUrlSchema.parse(srcString);
|
|
79
105
|
logger.info(`Loading from registry: ${registryPath}`);
|
|
80
106
|
// Look up model metadata for checksum validation
|
|
81
107
|
const modelMetadata = getModelByPath(registryPath);
|
|
82
108
|
const expectedChecksum = modelMetadata?.sha256Checksum;
|
|
83
|
-
const
|
|
84
|
-
logger.info(`Loaded Model to ${
|
|
85
|
-
return
|
|
109
|
+
const result = await downloaders.registry(registryPath, registrySource, progressCallback, expectedChecksum);
|
|
110
|
+
logger.info(`Loaded Model to ${isDownloadResult(result) ? result.path : result}`);
|
|
111
|
+
return buildResult(result, "registry");
|
|
86
112
|
}
|
|
87
|
-
let actualPath;
|
|
88
113
|
// Validate seeding is only used with hyperdrive models
|
|
89
114
|
if (seed && !hyperdriveKey) {
|
|
90
115
|
throw new SeedingNotSupportedError();
|
|
91
116
|
}
|
|
92
|
-
//
|
|
117
|
+
// HTTP source
|
|
93
118
|
if (actualModelSrc.startsWith("http://") ||
|
|
94
119
|
actualModelSrc.startsWith("https://")) {
|
|
95
120
|
logger.info(`Loading from HTTP URL: ${actualModelSrc}`);
|
|
96
|
-
|
|
97
|
-
logger.info(`Loaded Model to ${
|
|
121
|
+
const result = await downloaders.http(actualModelSrc, progressCallback);
|
|
122
|
+
logger.info(`Loaded Model to ${isDownloadResult(result) ? result.path : result}`);
|
|
123
|
+
return buildResult(result, "http");
|
|
98
124
|
}
|
|
99
|
-
|
|
100
|
-
|
|
125
|
+
// Hyperdrive source
|
|
126
|
+
if (hyperdriveKey) {
|
|
101
127
|
logger.info(`Loading from hyperdrive: ${hyperdriveKey}`);
|
|
102
|
-
|
|
128
|
+
const result = await downloaders.hyperdrive(hyperdriveKey, actualModelSrc, seed, progressCallback);
|
|
129
|
+
return buildResult(result, "hyperdrive");
|
|
103
130
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
131
|
+
// Filesystem source (local files, cached files)
|
|
132
|
+
let resolvedPath;
|
|
133
|
+
if (actualModelSrc.includes("/") || actualModelSrc.includes("\\")) {
|
|
107
134
|
if (isArchivePath(actualModelSrc)) {
|
|
108
135
|
logger.info(`Extracting local archive: ${actualModelSrc}`);
|
|
109
136
|
const archiveHash = generateShortHash(actualModelSrc);
|
|
110
137
|
const extractDir = getShardedModelCacheDir(archiveHash);
|
|
111
|
-
|
|
138
|
+
resolvedPath = await extractAndValidateShardedArchive(actualModelSrc, extractDir);
|
|
112
139
|
}
|
|
113
140
|
else {
|
|
114
|
-
|
|
141
|
+
resolvedPath = actualModelSrc;
|
|
115
142
|
}
|
|
116
143
|
}
|
|
117
144
|
else {
|
|
118
|
-
|
|
119
|
-
actualPath = await resolveLocalOrCachedFile(actualModelSrc);
|
|
145
|
+
resolvedPath = await resolveLocalOrCachedFile(actualModelSrc);
|
|
120
146
|
}
|
|
121
|
-
return
|
|
147
|
+
return { path: resolvedPath, sourceType: "filesystem" };
|
|
148
|
+
}
|
|
149
|
+
export async function resolveModelPath(modelSrc, progressCallback, seed) {
|
|
150
|
+
const result = await resolveModelPathCore(modelSrc, progressCallback, seed, "base");
|
|
151
|
+
return result.path;
|
|
152
|
+
}
|
|
153
|
+
export async function resolveModelPathWithStats(modelSrc, progressCallback, seed) {
|
|
154
|
+
return resolveModelPathCore(modelSrc, progressCallback, seed, "stats");
|
|
122
155
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SourceType } from "../../../../schemas/index";
|
|
2
|
+
export interface DownloadStats {
|
|
3
|
+
downloadTimeMs?: number;
|
|
4
|
+
totalBytesDownloaded?: number;
|
|
5
|
+
downloadSpeedBps?: number;
|
|
6
|
+
checksumValidationTimeMs?: number;
|
|
7
|
+
cacheHit?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface ResolveResult {
|
|
10
|
+
path: string;
|
|
11
|
+
sourceType: SourceType;
|
|
12
|
+
downloadStats?: DownloadStats;
|
|
13
|
+
}
|
|
14
|
+
export interface DownloadResult {
|
|
15
|
+
path: string;
|
|
16
|
+
stats?: DownloadStats;
|
|
17
|
+
}
|
|
18
|
+
export interface DownloadMetricsHooks {
|
|
19
|
+
markCacheHit: () => void;
|
|
20
|
+
markCacheMiss: () => void;
|
|
21
|
+
addChecksumValidationTimeMs: (durationMs: number) => void;
|
|
22
|
+
}
|
|
23
|
+
export interface LoadModelProfilingMeta {
|
|
24
|
+
sourceType?: string;
|
|
25
|
+
downloadStats?: DownloadStats;
|
|
26
|
+
modelInitializationTimeMs?: number;
|
|
27
|
+
totalLoadTimeMs?: number;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import type { LoadModelSrcRequest, LoadModelResponse, ModelProgressUpdate } from "../../../schemas/index";
|
|
2
|
-
|
|
2
|
+
import type { DelegatedHandlerOptions } from "../profiling/index";
|
|
3
|
+
export interface HandleLoadModelDelegatedOptions extends DelegatedHandlerOptions {
|
|
4
|
+
progressCallback?: (update: ModelProgressUpdate) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare function handleLoadModelDelegated(request: LoadModelSrcRequest, options?: HandleLoadModelDelegatedOptions): Promise<LoadModelResponse>;
|
|
3
7
|
//# sourceMappingURL=load-model-delegated.d.ts.map
|