@qvac/sdk 0.9.2 → 0.10.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 +42 -95
- package/dist/client/api/cancel.d.ts +1 -1
- package/dist/client/api/cancel.js +1 -1
- package/dist/client/api/completion-stream.d.ts +51 -12
- package/dist/client/api/completion-stream.js +129 -56
- package/dist/client/api/delete-cache.d.ts +1 -0
- package/dist/client/api/delete-cache.js +1 -0
- package/dist/client/api/diffusion.d.ts +17 -2
- package/dist/client/api/diffusion.js +21 -4
- package/dist/client/api/embed.d.ts +4 -0
- package/dist/client/api/finetune.d.ts +21 -0
- package/dist/client/api/get-loaded-model-info.d.ts +25 -0
- package/dist/client/api/get-loaded-model-info.js +36 -0
- package/dist/client/api/get-model-info.d.ts +9 -1
- package/dist/client/api/get-model-info.js +8 -0
- package/dist/client/api/heartbeat.d.ts +2 -2
- package/dist/client/api/heartbeat.js +2 -2
- package/dist/client/api/index.d.ts +3 -1
- package/dist/client/api/index.js +3 -1
- package/dist/client/api/invoke-plugin.d.ts +16 -0
- package/dist/client/api/invoke-plugin.js +16 -0
- package/dist/client/api/load-model.d.ts +36 -3
- package/dist/client/api/load-model.js +31 -10
- package/dist/client/api/provide.d.ts +11 -5
- package/dist/client/api/provide.js +11 -6
- package/dist/client/api/rag.d.ts +9 -0
- package/dist/client/api/rag.js +9 -0
- package/dist/client/api/registry.d.ts +26 -0
- package/dist/client/api/registry.js +26 -0
- package/dist/client/api/resume.d.ts +20 -4
- package/dist/client/api/resume.js +20 -4
- package/dist/client/api/state.d.ts +23 -0
- package/dist/client/api/state.js +29 -0
- package/dist/client/api/stop-provider.d.ts +11 -5
- package/dist/client/api/stop-provider.js +11 -5
- package/dist/client/api/suspend.d.ts +21 -3
- package/dist/client/api/suspend.js +21 -3
- package/dist/client/api/text-to-speech.d.ts +64 -6
- package/dist/client/api/text-to-speech.js +423 -47
- package/dist/client/api/transcribe.d.ts +29 -4
- package/dist/client/api/transcribe.js +86 -28
- package/dist/client/api/translate.d.ts +1 -0
- package/dist/client/api/translate.js +1 -0
- package/dist/client/rpc/bare-client.js +22 -1
- package/dist/client/rpc/expo-rpc-client.d.ts +1 -1
- package/dist/client/rpc/expo-rpc-client.js +96 -4
- package/dist/client/rpc/node-rpc-client.js +36 -0
- package/dist/examples/audio/mic-input.d.ts +9 -0
- package/dist/examples/audio/mic-input.js +111 -0
- package/dist/examples/completion-events.d.ts +18 -0
- package/dist/examples/completion-events.js +79 -0
- package/dist/examples/delegated-inference/composite.js +12 -18
- package/dist/examples/delegated-inference/consumer-profiled.js +4 -11
- package/dist/examples/delegated-inference/consumer.js +8 -13
- package/dist/examples/delegated-inference/provider.js +11 -16
- package/dist/examples/diffusion-flux2-klein-img2img.d.ts +2 -0
- package/dist/examples/diffusion-flux2-klein-img2img.js +60 -0
- package/dist/examples/diffusion-flux2-klein.js +1 -0
- package/dist/examples/diffusion-img2img.d.ts +2 -0
- package/dist/examples/diffusion-img2img.js +49 -0
- package/dist/examples/diffusion-txt2img.js +2 -1
- package/dist/examples/kv-cache-example.js +11 -12
- package/dist/examples/llamacpp-cache.d.ts +2 -0
- package/dist/examples/llamacpp-cache.js +107 -0
- package/dist/examples/llamacpp-dynamic-tools.d.ts +2 -0
- package/dist/examples/llamacpp-dynamic-tools.js +144 -0
- package/dist/examples/llamacpp-structured-output.d.ts +2 -0
- package/dist/examples/llamacpp-structured-output.js +106 -0
- package/dist/examples/plugins.js +4 -4
- package/dist/examples/suspend-resume.js +21 -4
- package/dist/examples/{llamacpp-native-tools.js → tools/llamacpp-native-tools.js} +6 -55
- package/dist/examples/tools/llamacpp-tools-harmony-multiturn.d.ts +2 -0
- package/dist/examples/tools/llamacpp-tools-harmony-multiturn.js +81 -0
- package/dist/examples/tools/llamacpp-tools-pythonic.d.ts +2 -0
- package/dist/examples/tools/llamacpp-tools-pythonic.js +50 -0
- package/dist/examples/tools/shared.d.ts +21 -0
- package/dist/examples/tools/shared.js +42 -0
- package/dist/examples/transcription/parakeet-microphone-record.js +6 -33
- package/dist/examples/transcription/whispercpp-filesystem-streaming.js +7 -5
- package/dist/examples/transcription/whispercpp-filesystem.js +12 -3
- package/dist/examples/transcription/whispercpp-microphone-record.js +6 -29
- package/dist/examples/translation/translation-stream.js +5 -5
- package/dist/examples/tts/llm-to-tts-streaming.d.ts +16 -0
- package/dist/examples/tts/llm-to-tts-streaming.js +143 -0
- package/dist/examples/tts/supertonic-multilingual.js +3 -3
- package/dist/examples/tts/supertonic.js +3 -3
- package/dist/examples/tts/utils.d.ts +11 -1
- package/dist/examples/tts/utils.js +70 -17
- package/dist/examples/voice-assistant/voice-assistant.d.ts +2 -0
- package/dist/examples/voice-assistant/voice-assistant.js +207 -0
- package/dist/expo/plugins/withMobileBundle.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/logging/logger.d.ts +11 -0
- package/dist/logging/logger.js +11 -0
- package/dist/logging/types.d.ts +18 -0
- package/dist/models/registry/models.d.ts +6973 -7457
- package/dist/models/registry/models.js +6889 -6855
- package/dist/models/update-models/codegen.js +84 -23
- package/dist/models/update-models/companions.d.ts +18 -0
- package/dist/models/update-models/companions.js +175 -0
- package/dist/models/update-models/naming.js +0 -25
- package/dist/models/update-models/registry.d.ts +1 -0
- package/dist/models/update-models/registry.js +23 -3
- package/dist/models/update-models/types.d.ts +37 -9
- package/dist/profiling/index.d.ts +49 -0
- package/dist/profiling/index.js +49 -0
- package/dist/schemas/cancel.d.ts +6 -2
- package/dist/schemas/cancel.js +14 -7
- package/dist/schemas/common.d.ts +354 -271
- package/dist/schemas/common.js +26 -5
- package/dist/schemas/completion-event.d.ts +225 -0
- package/dist/schemas/completion-event.js +79 -0
- package/dist/schemas/completion-stream.d.ts +126 -31
- package/dist/schemas/completion-stream.js +138 -36
- package/dist/schemas/delegate.d.ts +0 -2
- package/dist/schemas/delegate.js +25 -6
- package/dist/schemas/download-asset.d.ts +5 -5
- package/dist/schemas/embed.js +21 -9
- package/dist/schemas/engine-addon-map.d.ts +11 -1
- package/dist/schemas/engine-addon-map.js +2 -2
- package/dist/schemas/get-loaded-model-info.d.ts +52 -0
- package/dist/schemas/get-loaded-model-info.js +44 -0
- package/dist/schemas/get-model-info.d.ts +2 -2
- package/dist/schemas/get-model-info.js +103 -32
- package/dist/schemas/heartbeat.d.ts +0 -1
- package/dist/schemas/index.d.ts +4 -1
- package/dist/schemas/index.js +4 -1
- package/dist/schemas/llamacpp-config.d.ts +14 -4
- package/dist/schemas/llamacpp-config.js +5 -0
- package/dist/schemas/load-model.d.ts +3233 -1260
- package/dist/schemas/load-model.js +23 -16
- package/dist/schemas/model-src-utils.d.ts +7 -6
- package/dist/schemas/model-src-utils.js +27 -1
- package/dist/schemas/model-types.d.ts +4 -4
- package/dist/schemas/ocr.d.ts +1 -1
- package/dist/schemas/plugin.d.ts +27 -3
- package/dist/schemas/plugin.js +27 -2
- package/dist/schemas/profiling.js +11 -3
- package/dist/schemas/provide.d.ts +1 -3
- package/dist/schemas/provide.js +0 -3
- package/dist/schemas/rag.d.ts +4 -4
- package/dist/schemas/registry.d.ts +10 -10
- package/dist/schemas/registry.js +36 -14
- package/dist/schemas/reload-config.d.ts +73 -7
- package/dist/schemas/sdcpp-config.d.ts +16 -8
- package/dist/schemas/sdcpp-config.js +118 -25
- package/dist/schemas/sdk-config.d.ts +116 -90
- package/dist/schemas/sdk-config.js +16 -0
- package/dist/schemas/sdk-errors-client.d.ts +3 -0
- package/dist/schemas/sdk-errors-client.js +16 -1
- package/dist/schemas/sdk-errors-server.d.ts +3 -0
- package/dist/schemas/sdk-errors-server.js +23 -0
- package/dist/schemas/state.d.ts +23 -0
- package/dist/schemas/state.js +14 -0
- package/dist/schemas/stop-provide.d.ts +0 -5
- package/dist/schemas/stop-provide.js +2 -6
- package/dist/schemas/text-to-speech.d.ts +93 -27
- package/dist/schemas/text-to-speech.js +27 -0
- package/dist/schemas/tools.d.ts +16 -0
- package/dist/schemas/tools.js +15 -0
- package/dist/schemas/transcription-config.d.ts +8 -8
- package/dist/schemas/transcription.d.ts +33 -0
- package/dist/schemas/transcription.js +9 -0
- package/dist/schemas/translate.js +59 -19
- package/dist/schemas/translation-config.d.ts +157 -133
- package/dist/schemas/translation-config.js +34 -11
- package/dist/server/bare/delegate-rpc-client.d.ts +1 -1
- package/dist/server/bare/delegate-rpc-client.js +131 -122
- package/dist/server/bare/hyperswarm.d.ts +2 -2
- package/dist/server/bare/hyperswarm.js +12 -7
- package/dist/server/bare/ops/cancel.js +7 -0
- package/dist/server/bare/ops/kv-cache-utils.d.ts +7 -10
- package/dist/server/bare/ops/kv-cache-utils.js +31 -40
- package/dist/server/bare/ops/load-model.js +0 -1
- package/dist/server/bare/ops/transcribe.d.ts +11 -4
- package/dist/server/bare/ops/transcribe.js +25 -4
- package/dist/server/bare/ops/translate.js +42 -4
- package/dist/server/bare/ops/unload-model.js +21 -19
- package/dist/server/bare/plugins/llamacpp-completion/ops/cache-logger.js +1 -2
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.d.ts +13 -8
- package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +257 -85
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.d.ts +101 -0
- package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.js +135 -0
- package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +80 -22
- package/dist/server/bare/plugins/llamacpp-completion/plugin.js +57 -32
- package/dist/server/bare/plugins/llamacpp-embedding/plugin.js +10 -16
- package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +69 -44
- package/dist/server/bare/plugins/nmtcpp-translation/plugin.js +54 -116
- package/dist/server/bare/plugins/nmtcpp-translation/resolve-vocab.d.ts +32 -0
- package/dist/server/bare/plugins/nmtcpp-translation/resolve-vocab.js +117 -0
- package/dist/server/bare/plugins/onnx-ocr/plugin.d.ts +1 -1
- package/dist/server/bare/plugins/onnx-ocr/plugin.js +1 -2
- package/dist/server/bare/plugins/onnx-tts/ops/text-to-speech-stream.d.ts +7 -0
- package/dist/server/bare/plugins/onnx-tts/ops/text-to-speech-stream.js +116 -0
- package/dist/server/bare/plugins/onnx-tts/ops/text-to-speech.d.ts +2 -3
- package/dist/server/bare/plugins/onnx-tts/ops/text-to-speech.js +71 -9
- package/dist/server/bare/plugins/onnx-tts/plugin.d.ts +41 -13
- package/dist/server/bare/plugins/onnx-tts/plugin.js +48 -3
- package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +15 -7
- package/dist/server/bare/plugins/parakeet-transcription/plugin.js +5 -6
- package/dist/server/bare/plugins/sdcpp-generation/ops/diffusion.js +6 -0
- package/dist/server/bare/plugins/sdcpp-generation/plugin.d.ts +8 -5
- package/dist/server/bare/plugins/sdcpp-generation/plugin.js +13 -13
- package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +17 -1
- package/dist/server/bare/plugins/whispercpp-transcription/plugin.js +40 -17
- package/dist/server/bare/registry/config-registry.js +14 -3
- package/dist/server/bare/registry/model-registry.d.ts +8 -10
- package/dist/server/bare/registry/model-registry.js +17 -12
- package/dist/server/bare/registry/registry-client.js +79 -19
- package/dist/server/bare/runtime-lifecycle.d.ts +2 -1
- package/dist/server/bare/runtime-lifecycle.js +13 -2
- package/dist/server/bare/types/addon-responses.d.ts +8 -3
- package/dist/server/bare/utils/transcribe-metadata.d.ts +21 -0
- package/dist/server/bare/utils/transcribe-metadata.js +28 -0
- package/dist/server/bare/utils/tts-stats.d.ts +22 -0
- package/dist/server/bare/utils/tts-stats.js +10 -0
- package/dist/server/rpc/create-server.d.ts +4 -1
- package/dist/server/rpc/create-server.js +5 -1
- package/dist/server/rpc/delegate-transport.js +36 -29
- package/dist/server/rpc/handle-request.js +28 -3
- package/dist/server/rpc/handler-registry.js +7 -1
- package/dist/server/rpc/handler-utils.d.ts +5 -0
- package/dist/server/rpc/handler-utils.js +22 -0
- package/dist/server/rpc/handlers/cancel-delegated.js +3 -5
- package/dist/server/rpc/handlers/cancelHandler.js +4 -5
- package/dist/server/rpc/handlers/completion-stream-delegated.js +14 -5
- package/dist/server/rpc/handlers/delete-cache.js +8 -3
- package/dist/server/rpc/handlers/download-asset.js +3 -24
- package/dist/server/rpc/handlers/get-loaded-model-info.d.ts +3 -0
- package/dist/server/rpc/handlers/get-loaded-model-info.js +39 -0
- package/dist/server/rpc/handlers/get-model-info.js +93 -84
- package/dist/server/rpc/handlers/heartbeat-delegated.js +2 -2
- package/dist/server/rpc/handlers/index.d.ts +6 -0
- package/dist/server/rpc/handlers/index.js +6 -0
- package/dist/server/rpc/handlers/load-model/download-manager.d.ts +35 -9
- package/dist/server/rpc/handlers/load-model/download-manager.js +142 -38
- package/dist/server/rpc/handlers/load-model/download-stats.d.ts +5 -4
- package/dist/server/rpc/handlers/load-model/download-stats.js +49 -8
- package/dist/server/rpc/handlers/load-model/handler.js +31 -50
- package/dist/server/rpc/handlers/load-model/http.d.ts +2 -2
- package/dist/server/rpc/handlers/load-model/http.js +97 -142
- package/dist/server/rpc/handlers/load-model/hyperdrive.d.ts +2 -2
- package/dist/server/rpc/handlers/load-model/hyperdrive.js +55 -74
- package/dist/server/rpc/handlers/load-model/index.d.ts +0 -1
- package/dist/server/rpc/handlers/load-model/index.js +0 -1
- package/dist/server/rpc/handlers/load-model/registry-client-options.d.ts +27 -0
- package/dist/server/rpc/handlers/load-model/registry-client-options.js +19 -0
- package/dist/server/rpc/handlers/load-model/registry-companion-set.d.ts +22 -0
- package/dist/server/rpc/handlers/load-model/registry-companion-set.js +208 -0
- package/dist/server/rpc/handlers/load-model/registry-download-utils.d.ts +24 -0
- package/dist/server/rpc/handlers/load-model/registry-download-utils.js +114 -0
- package/dist/server/rpc/handlers/load-model/registry.d.ts +2 -20
- package/dist/server/rpc/handlers/load-model/registry.js +109 -381
- package/dist/server/rpc/handlers/load-model/resolve-session.d.ts +15 -0
- package/dist/server/rpc/handlers/load-model/resolve-session.js +61 -0
- package/dist/server/rpc/handlers/load-model/resolve.d.ts +3 -3
- package/dist/server/rpc/handlers/load-model/resolve.js +14 -23
- package/dist/server/rpc/handlers/load-model/types.d.ts +11 -4
- package/dist/server/rpc/handlers/load-model/types.js +28 -1
- package/dist/server/rpc/handlers/load-model-delegated.js +2 -4
- package/dist/server/rpc/handlers/plugin-dispatch.js +9 -5
- package/dist/server/rpc/handlers/plugin-invoke.js +1 -1
- package/dist/server/rpc/handlers/provideHandler/connection.js +13 -2
- package/dist/server/rpc/handlers/provideHandler/handler.js +42 -29
- package/dist/server/rpc/handlers/state.d.ts +3 -0
- package/dist/server/rpc/handlers/state.js +7 -0
- package/dist/server/rpc/handlers/stopProvideHandler.d.ts +2 -2
- package/dist/server/rpc/handlers/stopProvideHandler.js +12 -7
- package/dist/server/rpc/handlers/text-to-speech-stream.d.ts +3 -0
- package/dist/server/rpc/handlers/text-to-speech-stream.js +4 -0
- package/dist/server/rpc/handlers/unload-model-delegated.js +3 -3
- package/dist/server/rpc/profiling/operation-metrics.js +20 -0
- package/dist/server/rpc/rpc-utils.js +1 -1
- package/dist/server/rpc/transport-selector.d.ts +3 -0
- package/dist/server/rpc/transport-selector.js +18 -0
- package/dist/server/utils/cache/auto-history.d.ts +4 -0
- package/dist/server/utils/cache/auto-history.js +22 -0
- package/dist/server/utils/{cache.d.ts → cache/paths.d.ts} +22 -5
- package/dist/server/utils/{cache.js → cache/paths.js} +36 -20
- package/dist/server/utils/cache/types.d.ts +8 -0
- package/dist/server/utils/cache/types.js +1 -0
- package/dist/server/utils/checksum.d.ts +2 -2
- package/dist/server/utils/checksum.js +1 -1
- package/dist/server/utils/clear-storage.d.ts +5 -0
- package/dist/server/utils/clear-storage.js +17 -0
- package/dist/server/utils/completion-normalizer.d.ts +17 -0
- package/dist/server/utils/completion-normalizer.js +413 -0
- package/dist/server/utils/expand-gguf-shards.d.ts +3 -0
- package/dist/server/utils/expand-gguf-shards.js +22 -0
- package/dist/server/utils/formatting.js +1 -1
- package/dist/server/utils/index.d.ts +4 -2
- package/dist/server/utils/index.js +4 -2
- package/dist/server/utils/qvac-paths.d.ts +2 -0
- package/dist/server/utils/qvac-paths.js +5 -0
- package/dist/server/utils/response-format.d.ts +3 -0
- package/dist/server/utils/response-format.js +20 -0
- package/dist/server/utils/tool-integration.d.ts +15 -4
- package/dist/server/utils/tool-integration.js +21 -41
- package/dist/server/utils/tools/dialect.d.ts +8 -0
- package/dist/server/utils/tools/dialect.js +14 -0
- package/dist/server/utils/tools/index.d.ts +3 -0
- package/dist/server/utils/tools/index.js +2 -0
- package/dist/server/utils/tools/parser.d.ts +6 -0
- package/dist/server/utils/tools/parser.js +46 -0
- package/dist/server/utils/tools/parsers/harmony.d.ts +4 -0
- package/dist/server/utils/tools/parsers/harmony.js +59 -0
- package/dist/server/utils/tools/parsers/hermes.d.ts +4 -0
- package/dist/server/utils/tools/parsers/hermes.js +100 -0
- package/dist/server/utils/tools/parsers/json.d.ts +6 -0
- package/dist/server/utils/tools/parsers/json.js +115 -0
- package/dist/server/utils/tools/parsers/pythonic.d.ts +4 -0
- package/dist/server/utils/tools/parsers/pythonic.js +267 -0
- package/dist/server/utils/tools/shared.d.ts +18 -0
- package/dist/server/utils/tools/shared.js +54 -0
- package/dist/server/utils/worker-lock.d.ts +3 -0
- package/dist/server/utils/worker-lock.js +67 -0
- package/dist/server/worker-core.d.ts +16 -1
- package/dist/server/worker-core.js +114 -14
- package/dist/utils/aggregate-events.d.ts +16 -0
- package/dist/utils/aggregate-events.js +52 -0
- package/dist/utils/cache-normalize.d.ts +10 -0
- package/dist/utils/cache-normalize.js +23 -0
- package/dist/utils/encoding.d.ts +8 -0
- package/dist/utils/encoding.js +13 -0
- package/dist/utils/errors-client.d.ts +12 -0
- package/dist/utils/errors-client.js +20 -0
- package/dist/utils/errors-server.d.ts +14 -0
- package/dist/utils/errors-server.js +31 -0
- package/dist/utils/load-model-validation.d.ts +7 -0
- package/dist/utils/load-model-validation.js +18 -0
- package/expo/plugins/patches/android-link.mjs +1 -1
- package/expo/plugins/patches/ios-link.mjs +1 -1
- package/package.json +14 -18
- package/dist/examples/translation/translation-opus.d.ts +0 -2
- package/dist/examples/translation/translation-opus.js +0 -33
- package/dist/server/bare/utils/loader-adapter.d.ts +0 -7
- package/dist/server/bare/utils/loader-adapter.js +0 -9
- package/dist/server/utils/model-path.d.ts +0 -5
- package/dist/server/utils/model-path.js +0 -7
- package/dist/server/utils/tool-parser.d.ts +0 -7
- package/dist/server/utils/tool-parser.js +0 -248
- /package/dist/examples/{llamacpp-native-tools.d.ts → tools/llamacpp-native-tools.d.ts} +0 -0
|
@@ -2,11 +2,10 @@ import fs, { promises as fsPromises } from "bare-fs";
|
|
|
2
2
|
import path from "bare-path";
|
|
3
3
|
import { Readable } from "bare-stream";
|
|
4
4
|
import fetch from "bare-fetch";
|
|
5
|
-
import { AbortController } from "bare-abort-controller";
|
|
6
5
|
import { withTimeout } from "../../../../utils/withTimeout.js";
|
|
7
6
|
import { getModelsCacheDir, getShardedModelCacheDir, generateShortHash, detectShardedModel, parsePatternBasedShardUrl, extractTensorsFromShards, calculatePercentage, isArchiveUrl, sanitizePathComponent, extractAndValidateShardedArchive, validateShardedModelCache, checkAllShardsExist, generateShardFilenames, hasValidGGUFHeader, } from "../../../utils/index.js";
|
|
8
7
|
import { getSDKConfig } from "../../../bare/registry/config-registry.js";
|
|
9
|
-
import {
|
|
8
|
+
import { createHttpDownloadKey, startOrJoinDownload, applyJoinedDownloadStats, } from "./download-manager.js";
|
|
10
9
|
import { DownloadCancelledError, HTTPError, NoResponseBodyError, PartialDownloadOfflineError, ResponseBodyNotReadableError, } from "../../../../utils/errors-server.js";
|
|
11
10
|
import { getServerLogger } from "../../../../logging/index.js";
|
|
12
11
|
const logger = getServerLogger();
|
|
@@ -200,7 +199,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
200
199
|
await new Promise((resolve, reject) => {
|
|
201
200
|
// Handle abort signal
|
|
202
201
|
const abortHandler = () => {
|
|
203
|
-
const error = new
|
|
202
|
+
const error = new DownloadCancelledError();
|
|
204
203
|
body.destroy();
|
|
205
204
|
writeStream.destroy();
|
|
206
205
|
reject(error);
|
|
@@ -324,51 +323,20 @@ export async function downloadModelFromHttp(url, progressCallback, hooks) {
|
|
|
324
323
|
return downloadShardedModelFromHttp(url, progressCallback, hooks);
|
|
325
324
|
}
|
|
326
325
|
const downloadKey = createHttpDownloadKey(url);
|
|
327
|
-
|
|
328
|
-
if (existing) {
|
|
329
|
-
logger.info(`📥 Reusing existing download for: ${downloadKey}`);
|
|
330
|
-
hooks?.markCacheMiss();
|
|
331
|
-
return existing.promise;
|
|
332
|
-
}
|
|
326
|
+
hooks?.onDownloadKey?.(downloadKey);
|
|
333
327
|
const cacheDir = getModelsCacheDir();
|
|
334
328
|
const sourceHash = generateShortHash(url);
|
|
335
329
|
const modelPath = `${cacheDir}/${sourceHash}_${filename}`;
|
|
336
|
-
|
|
337
|
-
const abortController = new AbortController();
|
|
338
|
-
const downloadPromise = (async () => {
|
|
330
|
+
const result = startOrJoinDownload(downloadKey, async (ctx) => {
|
|
339
331
|
try {
|
|
340
332
|
// Check if already cached
|
|
341
|
-
const cachedPath = await validateCachedFile(modelPath, url,
|
|
333
|
+
const cachedPath = await validateCachedFile(modelPath, url, ctx.signal);
|
|
342
334
|
if (cachedPath) {
|
|
343
|
-
hooks?.markCacheHit();
|
|
344
|
-
|
|
345
|
-
try {
|
|
346
|
-
const stats = await fsPromises.stat(cachedPath);
|
|
347
|
-
progressCallback({
|
|
348
|
-
type: "modelProgress",
|
|
349
|
-
downloaded: stats.size,
|
|
350
|
-
total: stats.size,
|
|
351
|
-
percentage: 100,
|
|
352
|
-
downloadKey,
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
catch (error) {
|
|
356
|
-
logger.debug("Failed to get file stats for progress callback", {
|
|
357
|
-
path: cachedPath,
|
|
358
|
-
error,
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
return cachedPath;
|
|
363
|
-
}
|
|
364
|
-
// Download the file
|
|
365
|
-
hooks?.markCacheMiss();
|
|
366
|
-
await performHttpDownload(url, modelPath, downloadKey, progressCallback, abortController.signal);
|
|
367
|
-
// Send final 100% progress update
|
|
368
|
-
if (progressCallback) {
|
|
335
|
+
hooks?.markCacheHit?.();
|
|
336
|
+
ctx.setCacheHit(true);
|
|
369
337
|
try {
|
|
370
|
-
const stats = await fsPromises.stat(
|
|
371
|
-
|
|
338
|
+
const stats = await fsPromises.stat(cachedPath);
|
|
339
|
+
ctx.broadcastProgress({
|
|
372
340
|
type: "modelProgress",
|
|
373
341
|
downloaded: stats.size,
|
|
374
342
|
total: stats.size,
|
|
@@ -377,19 +345,40 @@ export async function downloadModelFromHttp(url, progressCallback, hooks) {
|
|
|
377
345
|
});
|
|
378
346
|
}
|
|
379
347
|
catch (error) {
|
|
380
|
-
logger.debug("Failed to get file stats for
|
|
381
|
-
path:
|
|
348
|
+
logger.debug("Failed to get file stats for progress callback", {
|
|
349
|
+
path: cachedPath,
|
|
382
350
|
error,
|
|
383
351
|
});
|
|
384
352
|
}
|
|
353
|
+
return cachedPath;
|
|
354
|
+
}
|
|
355
|
+
// Download the file
|
|
356
|
+
hooks?.markCacheMiss?.();
|
|
357
|
+
ctx.setCacheHit(false);
|
|
358
|
+
await performHttpDownload(url, modelPath, downloadKey, ctx.broadcastProgress, ctx.signal);
|
|
359
|
+
try {
|
|
360
|
+
const stats = await fsPromises.stat(modelPath);
|
|
361
|
+
ctx.broadcastProgress({
|
|
362
|
+
type: "modelProgress",
|
|
363
|
+
downloaded: stats.size,
|
|
364
|
+
total: stats.size,
|
|
365
|
+
percentage: 100,
|
|
366
|
+
downloadKey,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
logger.debug("Failed to get file stats for final progress update", {
|
|
371
|
+
path: modelPath,
|
|
372
|
+
error,
|
|
373
|
+
});
|
|
385
374
|
}
|
|
386
375
|
return modelPath;
|
|
387
376
|
}
|
|
388
377
|
catch (error) {
|
|
389
378
|
logger.error("❌ Error downloading model:", error instanceof Error ? error.message : String(error));
|
|
390
379
|
// Check if we should delete the partial file (clearCache was requested)
|
|
391
|
-
if (error instanceof
|
|
392
|
-
if (shouldClearCache(
|
|
380
|
+
if (error instanceof DownloadCancelledError) {
|
|
381
|
+
if (ctx.shouldClearCache()) {
|
|
393
382
|
logger.info("🗑️ Clearing cache - deleting partial file");
|
|
394
383
|
try {
|
|
395
384
|
await fsPromises.unlink(modelPath);
|
|
@@ -405,45 +394,22 @@ export async function downloadModelFromHttp(url, progressCallback, hooks) {
|
|
|
405
394
|
else {
|
|
406
395
|
logger.info("📥 Download paused - partial file preserved for resume");
|
|
407
396
|
}
|
|
408
|
-
clearClearCacheFlag(downloadKey);
|
|
409
397
|
}
|
|
410
398
|
const errorToThrow = error instanceof Error ? error : new Error(String(error));
|
|
411
399
|
throw errorToThrow;
|
|
412
400
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
unregisterDownload(downloadKey);
|
|
416
|
-
}
|
|
417
|
-
})();
|
|
418
|
-
// Register download
|
|
419
|
-
const downloadEntry = {
|
|
420
|
-
key: downloadKey,
|
|
421
|
-
promise: downloadPromise,
|
|
422
|
-
abortController,
|
|
423
|
-
startTime: Date.now(),
|
|
424
|
-
type: "http",
|
|
425
|
-
url,
|
|
426
|
-
modelPath,
|
|
427
|
-
...(progressCallback && { onProgress: progressCallback }),
|
|
428
|
-
};
|
|
429
|
-
registerDownload(downloadKey, downloadEntry);
|
|
430
|
-
return downloadPromise;
|
|
401
|
+
}, progressCallback);
|
|
402
|
+
return applyJoinedDownloadStats(result, hooks);
|
|
431
403
|
}
|
|
432
404
|
async function downloadShardedModelFromHttp(shardUrl, progressCallback, hooks) {
|
|
433
405
|
const config = getSDKConfig();
|
|
434
406
|
const concurrency = config.httpDownloadConcurrency ?? DEFAULT_CONCURRENCY;
|
|
435
407
|
const { shardUrls: shardInfos, cacheKey } = parsePatternBasedShardUrl(shardUrl);
|
|
436
408
|
const downloadKey = `http-sharded:${cacheKey}`;
|
|
409
|
+
hooks?.onDownloadKey?.(downloadKey);
|
|
437
410
|
logger.info(`📥 HTTP sharded download: ${shardInfos.length} shards detected from ${shardUrl}`);
|
|
438
|
-
const existing = getActiveDownload(downloadKey);
|
|
439
|
-
if (existing) {
|
|
440
|
-
logger.info(`📥 Reusing existing sharded download for: ${downloadKey}`);
|
|
441
|
-
hooks?.markCacheMiss();
|
|
442
|
-
return existing.promise;
|
|
443
|
-
}
|
|
444
|
-
const abortController = new AbortController();
|
|
445
411
|
const shardDir = getShardedModelCacheDir(cacheKey);
|
|
446
|
-
const
|
|
412
|
+
const result = startOrJoinDownload(downloadKey, async (ctx) => {
|
|
447
413
|
try {
|
|
448
414
|
const shardStates = await Promise.all(shardInfos.map(async (shard, index) => {
|
|
449
415
|
const shardPath = path.join(shardDir, shard.filename);
|
|
@@ -451,7 +417,7 @@ async function downloadShardedModelFromHttp(shardUrl, progressCallback, hooks) {
|
|
|
451
417
|
try {
|
|
452
418
|
const response = await fetch(shard.url, {
|
|
453
419
|
method: "HEAD",
|
|
454
|
-
signal:
|
|
420
|
+
signal: ctx.signal,
|
|
455
421
|
});
|
|
456
422
|
expectedSize = parseInt(response.headers.get("content-length") || "0");
|
|
457
423
|
}
|
|
@@ -460,7 +426,6 @@ async function downloadShardedModelFromHttp(shardUrl, progressCallback, hooks) {
|
|
|
460
426
|
url: shard.url,
|
|
461
427
|
error,
|
|
462
428
|
});
|
|
463
|
-
// expectedSize remains 0, progress percentage will be 0
|
|
464
429
|
}
|
|
465
430
|
return {
|
|
466
431
|
index,
|
|
@@ -474,7 +439,7 @@ async function downloadShardedModelFromHttp(shardUrl, progressCallback, hooks) {
|
|
|
474
439
|
const overallTotal = shardStates.reduce((sum, s) => sum + s.expectedSize, 0);
|
|
475
440
|
logger.info(`📏 Total size: ${overallTotal} bytes (${(overallTotal / 1024 / 1024).toFixed(2)} MB)`);
|
|
476
441
|
const cacheChecks = await Promise.all(shardStates.map(async (state) => {
|
|
477
|
-
const cached = await validateCachedFile(state.shardPath, state.shard.url,
|
|
442
|
+
const cached = await validateCachedFile(state.shardPath, state.shard.url, ctx.signal);
|
|
478
443
|
return { state, isCached: cached !== null };
|
|
479
444
|
}));
|
|
480
445
|
const shardsToDownload = cacheChecks
|
|
@@ -488,20 +453,22 @@ async function downloadShardedModelFromHttp(shardUrl, progressCallback, hooks) {
|
|
|
488
453
|
}
|
|
489
454
|
logger.info(`📥 ${shardsToDownload.length} of ${shardInfos.length} shards need downloading`);
|
|
490
455
|
if (shardsToDownload.length === 0) {
|
|
491
|
-
hooks?.markCacheHit();
|
|
456
|
+
hooks?.markCacheHit?.();
|
|
457
|
+
ctx.setCacheHit(true);
|
|
492
458
|
}
|
|
493
459
|
else {
|
|
494
|
-
hooks?.markCacheMiss();
|
|
460
|
+
hooks?.markCacheMiss?.();
|
|
461
|
+
ctx.setCacheHit(false);
|
|
495
462
|
}
|
|
496
|
-
await downloadShardsWithConcurrency(shardsToDownload, shardStates, concurrency,
|
|
463
|
+
await downloadShardsWithConcurrency(shardsToDownload, shardStates, concurrency, ctx.signal, downloadKey, overallTotal, ctx.broadcastProgress);
|
|
497
464
|
logger.info(`✅ All ${shardInfos.length} shards downloaded successfully`);
|
|
498
465
|
await extractTensorsFromShards(shardDir, shardInfos[0].filename);
|
|
499
466
|
return path.join(shardDir, shardInfos[0].filename);
|
|
500
467
|
}
|
|
501
468
|
catch (error) {
|
|
502
469
|
logger.error("❌ Error during sharded download:", error instanceof Error ? error.message : String(error));
|
|
503
|
-
if (error instanceof
|
|
504
|
-
if (shouldClearCache(
|
|
470
|
+
if (error instanceof DownloadCancelledError) {
|
|
471
|
+
if (ctx.shouldClearCache()) {
|
|
505
472
|
logger.info("🗑️ Clearing cache - deleting partial shard files");
|
|
506
473
|
try {
|
|
507
474
|
await fsPromises.rm(shardDir, { recursive: true, force: true });
|
|
@@ -517,50 +484,33 @@ async function downloadShardedModelFromHttp(shardUrl, progressCallback, hooks) {
|
|
|
517
484
|
}
|
|
518
485
|
throw error;
|
|
519
486
|
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
clearClearCacheFlag(downloadKey);
|
|
523
|
-
}
|
|
524
|
-
})();
|
|
525
|
-
registerDownload(downloadKey, {
|
|
526
|
-
key: downloadKey,
|
|
527
|
-
promise: downloadPromise,
|
|
528
|
-
abortController,
|
|
529
|
-
startTime: Date.now(),
|
|
530
|
-
type: "http",
|
|
531
|
-
url: shardUrl,
|
|
532
|
-
modelPath: shardDir,
|
|
533
|
-
});
|
|
534
|
-
return downloadPromise;
|
|
487
|
+
}, progressCallback);
|
|
488
|
+
return applyJoinedDownloadStats(result, hooks);
|
|
535
489
|
}
|
|
536
490
|
async function downloadShardedModelFromArchive(archiveUrl, progressCallback, hooks) {
|
|
537
491
|
const filename = extractFilenameFromUrl(archiveUrl);
|
|
538
492
|
const sourceHash = generateShortHash(archiveUrl);
|
|
539
493
|
const downloadKey = `http-archive:${sourceHash}`;
|
|
494
|
+
hooks?.onDownloadKey?.(downloadKey);
|
|
540
495
|
logger.info(`📦 HTTP archive download: ${filename}`);
|
|
541
|
-
const existing = getActiveDownload(downloadKey);
|
|
542
|
-
if (existing) {
|
|
543
|
-
logger.info(`📥 Reusing existing archive download for: ${downloadKey}`);
|
|
544
|
-
hooks?.markCacheMiss();
|
|
545
|
-
return existing.promise;
|
|
546
|
-
}
|
|
547
|
-
const abortController = new AbortController();
|
|
548
496
|
const extractDir = getShardedModelCacheDir(sourceHash);
|
|
549
497
|
const archivePath = path.join(extractDir, `${sourceHash}_${filename}`);
|
|
550
|
-
const
|
|
498
|
+
const result = startOrJoinDownload(downloadKey, async (ctx) => {
|
|
551
499
|
try {
|
|
552
500
|
await fsPromises.mkdir(extractDir, { recursive: true });
|
|
553
501
|
const files = await fsPromises.readdir(extractDir);
|
|
554
502
|
const shardedFile = files.find((f) => detectShardedModel(String(f)).isSharded);
|
|
555
503
|
if (!shardedFile) {
|
|
556
|
-
hooks?.markCacheMiss();
|
|
504
|
+
hooks?.markCacheMiss?.();
|
|
505
|
+
ctx.setCacheHit(false);
|
|
557
506
|
return downloadAndExtractArchive();
|
|
558
507
|
}
|
|
559
508
|
const shardFilename = String(shardedFile);
|
|
560
509
|
const allShardsExist = await checkAllShardsExist(extractDir, shardFilename);
|
|
561
510
|
if (!allShardsExist) {
|
|
562
511
|
logger.warn(`⚠️ Incomplete shards found, re-downloading archive`);
|
|
563
|
-
hooks?.markCacheMiss();
|
|
512
|
+
hooks?.markCacheMiss?.();
|
|
513
|
+
ctx.setCacheHit(false);
|
|
564
514
|
return downloadAndExtractArchive();
|
|
565
515
|
}
|
|
566
516
|
const shardFilenames = generateShardFilenames(shardFilename);
|
|
@@ -568,53 +518,67 @@ async function downloadShardedModelFromArchive(archiveUrl, progressCallback, hoo
|
|
|
568
518
|
const isComplete = await validateShardedModelCache(extractDir, shardFilename);
|
|
569
519
|
if (isComplete) {
|
|
570
520
|
logger.info(`✅ Archive already extracted: ${extractDir}`);
|
|
571
|
-
hooks?.markCacheHit();
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
}
|
|
521
|
+
hooks?.markCacheHit?.();
|
|
522
|
+
ctx.setCacheHit(true);
|
|
523
|
+
ctx.broadcastProgress({
|
|
524
|
+
type: "modelProgress",
|
|
525
|
+
downloaded: 1,
|
|
526
|
+
total: 1,
|
|
527
|
+
percentage: 100,
|
|
528
|
+
downloadKey,
|
|
529
|
+
});
|
|
581
530
|
return firstShard;
|
|
582
531
|
}
|
|
583
532
|
logger.info(`📝 All shards present but tensors.txt missing, extracting tensors...`);
|
|
584
533
|
try {
|
|
585
534
|
await extractTensorsFromShards(extractDir, shardFilename);
|
|
586
535
|
logger.info(`✅ Tensors extracted successfully`);
|
|
587
|
-
hooks?.markCacheHit();
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
}
|
|
536
|
+
hooks?.markCacheHit?.();
|
|
537
|
+
ctx.setCacheHit(true);
|
|
538
|
+
ctx.broadcastProgress({
|
|
539
|
+
type: "modelProgress",
|
|
540
|
+
downloaded: 1,
|
|
541
|
+
total: 1,
|
|
542
|
+
percentage: 100,
|
|
543
|
+
downloadKey,
|
|
544
|
+
});
|
|
597
545
|
return firstShard;
|
|
598
546
|
}
|
|
599
547
|
catch (error) {
|
|
600
548
|
logger.warn(`Failed to extract tensors, will re-download archive`, {
|
|
601
549
|
error,
|
|
602
550
|
});
|
|
603
|
-
hooks?.markCacheMiss();
|
|
551
|
+
hooks?.markCacheMiss?.();
|
|
552
|
+
ctx.setCacheHit(false);
|
|
604
553
|
return downloadAndExtractArchive();
|
|
605
554
|
}
|
|
606
555
|
}
|
|
607
556
|
catch (error) {
|
|
608
557
|
logger.error("❌ Error downloading/extracting archive:", error);
|
|
558
|
+
if (error instanceof DownloadCancelledError) {
|
|
559
|
+
if (ctx.shouldClearCache()) {
|
|
560
|
+
logger.info("🗑️ Clearing cache - deleting archive extract directory");
|
|
561
|
+
try {
|
|
562
|
+
await fsPromises.rm(extractDir, {
|
|
563
|
+
recursive: true,
|
|
564
|
+
force: true,
|
|
565
|
+
});
|
|
566
|
+
logger.info(`✅ Deleted extract directory: ${extractDir}`);
|
|
567
|
+
}
|
|
568
|
+
catch (cleanupError) {
|
|
569
|
+
logger.debug("Failed to delete extract directory during cleanup", {
|
|
570
|
+
path: extractDir,
|
|
571
|
+
error: cleanupError,
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
609
576
|
throw error;
|
|
610
577
|
}
|
|
611
|
-
finally {
|
|
612
|
-
unregisterDownload(downloadKey);
|
|
613
|
-
}
|
|
614
578
|
async function downloadAndExtractArchive() {
|
|
615
|
-
await performHttpDownload(archiveUrl, archivePath, downloadKey,
|
|
579
|
+
await performHttpDownload(archiveUrl, archivePath, downloadKey, ctx.broadcastProgress, ctx.signal);
|
|
616
580
|
logger.info(`✅ Archive downloaded, extracting to: ${extractDir}`);
|
|
617
|
-
const firstShardPath = await extractAndValidateShardedArchive(archivePath, extractDir,
|
|
581
|
+
const firstShardPath = await extractAndValidateShardedArchive(archivePath, extractDir, ctx.signal);
|
|
618
582
|
try {
|
|
619
583
|
await fsPromises.unlink(archivePath);
|
|
620
584
|
logger.info(`🗑️ Cleaned up archive file: ${archivePath}`);
|
|
@@ -627,17 +591,8 @@ async function downloadShardedModelFromArchive(archiveUrl, progressCallback, hoo
|
|
|
627
591
|
}
|
|
628
592
|
return firstShardPath;
|
|
629
593
|
}
|
|
630
|
-
})
|
|
631
|
-
|
|
632
|
-
key: downloadKey,
|
|
633
|
-
promise: downloadPromise,
|
|
634
|
-
abortController,
|
|
635
|
-
startTime: Date.now(),
|
|
636
|
-
type: "http",
|
|
637
|
-
url: archiveUrl,
|
|
638
|
-
modelPath: archivePath,
|
|
639
|
-
});
|
|
640
|
-
return downloadPromise;
|
|
594
|
+
}, progressCallback);
|
|
595
|
+
return applyJoinedDownloadStats(result, hooks);
|
|
641
596
|
}
|
|
642
597
|
async function downloadShardsWithConcurrency(shardsToDownload, allShards, concurrency, signal, downloadKey, overallTotal, progressCallback) {
|
|
643
598
|
const queue = [...shardsToDownload];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ModelProgressUpdate } from "../../../../schemas/index";
|
|
2
|
-
import type {
|
|
2
|
+
import type { DownloadHooks } from "./types";
|
|
3
3
|
export declare function deleteCorestoreDirectory(corestoreDir: string): Promise<void>;
|
|
4
|
-
export declare function downloadModelFromHyperdrive(hyperdriveKey: string, modelFileName: string, seed?: boolean, progressCallback?: (progress: ModelProgressUpdate) => void, hooks?:
|
|
4
|
+
export declare function downloadModelFromHyperdrive(hyperdriveKey: string, modelFileName: string, seed?: boolean, progressCallback?: (progress: ModelProgressUpdate) => void, hooks?: DownloadHooks, expectedChecksum?: string): Promise<string>;
|
|
5
5
|
//# sourceMappingURL=hyperdrive.d.ts.map
|
|
@@ -4,18 +4,17 @@ import Corestore from "corestore";
|
|
|
4
4
|
import Hyperswarm, {} from "hyperswarm";
|
|
5
5
|
import Hyperdrive from "hyperdrive";
|
|
6
6
|
import {} from "bare-stream";
|
|
7
|
-
import {
|
|
8
|
-
import { getEnv } from "../../../env.js";
|
|
7
|
+
import { getQvacPath } from "../../../utils/qvac-paths.js";
|
|
9
8
|
import { getModelsCacheDir, generateShortHash, detectShardedModel, getShardedModelCacheDir, getShardPath, checkShardCompleteness, measureChecksum, extractTensorsFromShards, calculatePercentage, } from "../../../utils/index.js";
|
|
10
9
|
import { getModelBySrc } from "../../../../models/registry/index.js";
|
|
11
|
-
import {
|
|
10
|
+
import { createHyperdriveDownloadKey, startOrJoinDownload, applyJoinedDownloadStats, } from "./download-manager.js";
|
|
12
11
|
import { getSDKConfig } from "../../../bare/registry/config-registry.js";
|
|
13
12
|
import { FileNotFoundError, ChecksumValidationFailedError, DownloadCancelledError, HyperdriveDownloadFailedError, ModelLoadFailedError, NoBlobFoundError, } from "../../../../utils/errors-server.js";
|
|
14
13
|
import { getServerLogger } from "../../../../logging/index.js";
|
|
15
14
|
import { registerSwarm, unregisterSwarm, registerCorestore, unregisterCorestore, } from "../../../bare/runtime-lifecycle.js";
|
|
16
15
|
const logger = getServerLogger();
|
|
17
16
|
function getCorestoreDir(hyperdriveKey) {
|
|
18
|
-
return
|
|
17
|
+
return getQvacPath("corestore", hyperdriveKey);
|
|
19
18
|
}
|
|
20
19
|
async function setupHyperdrive(hyperdriveKey, corestoreDir) {
|
|
21
20
|
const corestore = new Corestore(corestoreDir);
|
|
@@ -185,7 +184,7 @@ async function validateCachedFile(modelPath, modelFileName, expectedSize, expect
|
|
|
185
184
|
return null;
|
|
186
185
|
}
|
|
187
186
|
}
|
|
188
|
-
async function downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdriveKey, corestoreDir, downloadKey, expectedChecksum, progressCallback, seed, signal, hooks) {
|
|
187
|
+
async function downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdriveKey, corestoreDir, downloadKey, expectedChecksum, progressCallback, seed, signal, hooks, shouldClearCache) {
|
|
189
188
|
// Check if already aborted
|
|
190
189
|
if (signal?.aborted) {
|
|
191
190
|
throw new DownloadCancelledError();
|
|
@@ -231,8 +230,7 @@ async function downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdri
|
|
|
231
230
|
}
|
|
232
231
|
catch (error) {
|
|
233
232
|
logger.error("❌ Error during hyperdrive download:", error instanceof Error ? error.message : String(error));
|
|
234
|
-
|
|
235
|
-
if (error instanceof Error && error.message === "Download cancelled") {
|
|
233
|
+
if (error instanceof DownloadCancelledError) {
|
|
236
234
|
throw error;
|
|
237
235
|
}
|
|
238
236
|
throw new HyperdriveDownloadFailedError(`Download failed for ${modelFileName} from hyperdrive: ${hyperdriveKey}`, error);
|
|
@@ -247,16 +245,18 @@ async function downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdri
|
|
|
247
245
|
}
|
|
248
246
|
}
|
|
249
247
|
// Only delete corestore and partial file if user explicitly requested clearCache
|
|
250
|
-
if (signal?.aborted && shouldClearCache(
|
|
248
|
+
if (signal?.aborted && shouldClearCache?.()) {
|
|
251
249
|
try {
|
|
252
250
|
await fsPromises.unlink(modelPath);
|
|
253
251
|
}
|
|
254
|
-
catch {
|
|
255
|
-
|
|
252
|
+
catch (cleanupError) {
|
|
253
|
+
logger.debug("Failed to delete partial model file during cleanup", {
|
|
254
|
+
path: modelPath,
|
|
255
|
+
error: cleanupError,
|
|
256
|
+
});
|
|
256
257
|
}
|
|
257
258
|
await deleteCorestoreDirectory(corestoreDir);
|
|
258
259
|
}
|
|
259
|
-
clearClearCacheFlag(downloadKey);
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
async function downloadAndValidateFile(drive, sourceFileName, targetFilePath, expectedSize, expectedChecksum, progressContext, signal, hooks) {
|
|
@@ -321,7 +321,7 @@ async function downloadAndValidateFile(drive, sourceFileName, targetFilePath, ex
|
|
|
321
321
|
writeStream.on("finish", resolve);
|
|
322
322
|
writeStream.on("error", reject);
|
|
323
323
|
readStream.on("error", reject);
|
|
324
|
-
signal?.addEventListener("abort", () => reject(new
|
|
324
|
+
signal?.addEventListener("abort", () => reject(new DownloadCancelledError()), { once: true });
|
|
325
325
|
});
|
|
326
326
|
blobs.core.off("download", progressHandler);
|
|
327
327
|
// Validate file size
|
|
@@ -352,31 +352,7 @@ async function downloadAndValidateFile(drive, sourceFileName, targetFilePath, ex
|
|
|
352
352
|
throw error;
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
|
-
function
|
|
356
|
-
const abortController = new AbortController();
|
|
357
|
-
const downloadPromise = (async () => {
|
|
358
|
-
try {
|
|
359
|
-
return await downloadFn(abortController.signal);
|
|
360
|
-
}
|
|
361
|
-
finally {
|
|
362
|
-
unregisterDownload(downloadKey);
|
|
363
|
-
clearClearCacheFlag(downloadKey);
|
|
364
|
-
}
|
|
365
|
-
})();
|
|
366
|
-
const downloadEntry = {
|
|
367
|
-
key: downloadKey,
|
|
368
|
-
promise: downloadPromise,
|
|
369
|
-
abortController,
|
|
370
|
-
startTime: Date.now(),
|
|
371
|
-
type: "hyperdrive",
|
|
372
|
-
hyperdriveKey,
|
|
373
|
-
modelFileName,
|
|
374
|
-
...(progressCallback && { onProgress: progressCallback }),
|
|
375
|
-
};
|
|
376
|
-
registerDownload(downloadKey, downloadEntry);
|
|
377
|
-
return downloadPromise;
|
|
378
|
-
}
|
|
379
|
-
async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileName, shardMetadata, progressCallback, seed, signal, hooks) {
|
|
355
|
+
async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileName, shardMetadata, progressCallback, seed, signal, hooks, shouldClearCache) {
|
|
380
356
|
if (signal?.aborted) {
|
|
381
357
|
throw new DownloadCancelledError();
|
|
382
358
|
}
|
|
@@ -389,10 +365,10 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
389
365
|
const numberedShardCount = shardInfo.totalShards;
|
|
390
366
|
logger.info(`Downloading sharded model with ${numberedShardCount} numbered shards + ${allFiles.length - numberedShardCount} companion files to ${shardDir}`);
|
|
391
367
|
// Check which files need to be downloaded
|
|
392
|
-
const invalidIndices = await checkShardCompleteness(hyperdriveKey, allFiles, shardMetadata, hooks ? (ms) => hooks.addChecksumValidationTimeMs(ms) : undefined);
|
|
368
|
+
const invalidIndices = await checkShardCompleteness(hyperdriveKey, allFiles, shardMetadata, hooks?.addChecksumValidationTimeMs ? (ms) => hooks.addChecksumValidationTimeMs(ms) : undefined);
|
|
393
369
|
if (invalidIndices.length === 0) {
|
|
394
370
|
logger.info(`✅ All ${allFiles.length} files already downloaded and validated`);
|
|
395
|
-
hooks?.markCacheHit();
|
|
371
|
+
hooks?.markCacheHit?.();
|
|
396
372
|
if (progressCallback) {
|
|
397
373
|
const overallTotal = shardMetadata.reduce((sum, shard) => sum + shard.expectedSize, 0);
|
|
398
374
|
const lastFile = allFiles[allFiles.length - 1];
|
|
@@ -416,7 +392,7 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
416
392
|
return getShardPath(hyperdriveKey, allFiles[0]);
|
|
417
393
|
}
|
|
418
394
|
logger.info(`📥 Need to download ${invalidIndices.length} of ${allFiles.length} files`);
|
|
419
|
-
hooks?.markCacheMiss();
|
|
395
|
+
hooks?.markCacheMiss?.();
|
|
420
396
|
// Setup hyperdrive once for all shards
|
|
421
397
|
const corestoreDir = getCorestoreDir(hyperdriveKey);
|
|
422
398
|
const setup = await setupHyperdrive(hyperdriveKey, corestoreDir);
|
|
@@ -510,7 +486,7 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
510
486
|
catch (error) {
|
|
511
487
|
logger.error("❌ Error during sharded hyperdrive download:", error instanceof Error ? error.message : String(error));
|
|
512
488
|
// Preserve cancellation errors
|
|
513
|
-
if (error instanceof
|
|
489
|
+
if (error instanceof DownloadCancelledError) {
|
|
514
490
|
throw error;
|
|
515
491
|
}
|
|
516
492
|
throw new HyperdriveDownloadFailedError(`Sharded download failed for ${firstShardFileName} from hyperdrive: ${hyperdriveKey}`, error);
|
|
@@ -525,57 +501,62 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
525
501
|
}
|
|
526
502
|
}
|
|
527
503
|
// Only delete corestore and partial files if user explicitly requested clearCache
|
|
528
|
-
|
|
529
|
-
if (signal?.aborted && shouldClearCache(downloadKey)) {
|
|
504
|
+
if (signal?.aborted && shouldClearCache?.()) {
|
|
530
505
|
await deleteCorestoreDirectory(corestoreDir);
|
|
531
506
|
}
|
|
532
|
-
clearClearCacheFlag(downloadKey);
|
|
533
507
|
}
|
|
534
508
|
return getShardPath(hyperdriveKey, allFiles[0]);
|
|
535
509
|
}
|
|
536
510
|
export async function downloadModelFromHyperdrive(hyperdriveKey, modelFileName, seed, progressCallback, hooks, expectedChecksum) {
|
|
537
511
|
const downloadKey = createHyperdriveDownloadKey(hyperdriveKey, modelFileName);
|
|
538
|
-
|
|
539
|
-
const existing = getActiveDownload(downloadKey);
|
|
540
|
-
if (existing) {
|
|
541
|
-
hooks?.markCacheMiss();
|
|
542
|
-
return existing.promise;
|
|
543
|
-
}
|
|
512
|
+
hooks?.onDownloadKey?.(downloadKey);
|
|
544
513
|
const shardInfo = detectShardedModel(modelFileName);
|
|
545
514
|
const model = getModelBySrc(modelFileName, hyperdriveKey);
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
515
|
+
const result = startOrJoinDownload(downloadKey, async (ctx) => {
|
|
516
|
+
if (shardInfo.isSharded && model?.shardMetadata) {
|
|
517
|
+
const hooksWithCacheHit = {
|
|
518
|
+
...hooks,
|
|
519
|
+
markCacheHit: () => {
|
|
520
|
+
hooks?.markCacheHit?.();
|
|
521
|
+
ctx.setCacheHit(true);
|
|
522
|
+
},
|
|
523
|
+
markCacheMiss: () => {
|
|
524
|
+
hooks?.markCacheMiss?.();
|
|
525
|
+
ctx.setCacheHit(false);
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
|
+
return downloadShardedFilesToFilesystem(hyperdriveKey, modelFileName, model.shardMetadata, ctx.broadcastProgress, seed, ctx.signal, hooksWithCacheHit, ctx.shouldClearCache);
|
|
529
|
+
}
|
|
530
|
+
// Non-sharded model download
|
|
531
|
+
const corestoreDir = getCorestoreDir(hyperdriveKey);
|
|
532
|
+
const cacheDir = getModelsCacheDir();
|
|
533
|
+
const sourceHash = generateShortHash(`${hyperdriveKey}/${modelFileName}`);
|
|
534
|
+
const modelPath = path.join(cacheDir, `${sourceHash}_${modelFileName}`);
|
|
535
|
+
// First, check if we already have a valid cached file (only if we have model metadata)
|
|
536
|
+
if (model) {
|
|
537
|
+
const cachedPath = await validateCachedFile(modelPath, modelFileName, model.expectedSize, expectedChecksum || model.sha256Checksum, hooks);
|
|
538
|
+
if (cachedPath) {
|
|
539
|
+
hooks?.markCacheHit?.();
|
|
540
|
+
ctx.setCacheHit(true);
|
|
541
|
+
ctx.broadcastProgress({
|
|
561
542
|
type: "modelProgress",
|
|
562
543
|
downloaded: model.expectedSize,
|
|
563
544
|
total: model.expectedSize,
|
|
564
545
|
percentage: 100,
|
|
565
546
|
downloadKey,
|
|
566
547
|
});
|
|
548
|
+
// Delete any leftover corestore directory from previous runs (only when not seeding)
|
|
549
|
+
if (!seed) {
|
|
550
|
+
await deleteCorestoreDirectory(corestoreDir);
|
|
551
|
+
}
|
|
552
|
+
return cachedPath;
|
|
567
553
|
}
|
|
568
|
-
// Delete any leftover corestore directory from previous runs (only when not seeding)
|
|
569
|
-
if (!seed) {
|
|
570
|
-
await deleteCorestoreDirectory(corestoreDir);
|
|
571
|
-
}
|
|
572
|
-
return cachedPath;
|
|
573
554
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
return createManagedDownload(downloadKey, hyperdriveKey, modelFileName, async (signal) => {
|
|
555
|
+
hooks?.markCacheMiss?.();
|
|
556
|
+
ctx.setCacheHit(false);
|
|
577
557
|
const checksumToValidate = expectedChecksum || model?.sha256Checksum || "";
|
|
578
|
-
await downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdriveKey, corestoreDir, downloadKey, checksumToValidate,
|
|
558
|
+
await downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdriveKey, corestoreDir, downloadKey, checksumToValidate, ctx.broadcastProgress, seed, ctx.signal, hooks, ctx.shouldClearCache);
|
|
579
559
|
return modelPath;
|
|
580
560
|
}, progressCallback);
|
|
561
|
+
return applyJoinedDownloadStats(result, hooks);
|
|
581
562
|
}
|