@qvac/sdk 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +328 -200
- package/dist/client/api/completion-stream.d.ts +15 -5
- package/dist/client/api/completion-stream.js +50 -14
- package/dist/client/api/embed.d.ts +17 -3
- package/dist/client/api/embed.js +0 -8
- package/dist/client/api/get-model-info.d.ts +1 -1
- package/dist/client/api/index.d.ts +0 -1
- package/dist/client/api/index.js +0 -1
- package/dist/client/api/load-model.d.ts +37 -11
- package/dist/client/api/load-model.js +29 -117
- package/dist/client/api/logging-stream.d.ts +6 -3
- package/dist/client/api/logging-stream.js +6 -3
- package/dist/client/api/unload-model.js +5 -2
- package/dist/client/config-loader/config-utils.d.ts +5 -0
- package/dist/client/config-loader/config-utils.js +20 -0
- package/dist/client/config-loader/resolve-config.bare.d.ts +9 -0
- package/dist/client/config-loader/resolve-config.bare.js +87 -0
- package/dist/client/config-loader/resolve-config.expo.d.ts +11 -0
- package/dist/client/config-loader/resolve-config.expo.js +62 -0
- package/dist/client/config-loader/resolve-config.node.d.ts +9 -0
- package/dist/client/config-loader/resolve-config.node.js +118 -0
- package/dist/client/init-hooks.d.ts +17 -3
- package/dist/client/init-hooks.js +37 -18
- package/dist/client/logging-stream-registry.d.ts +1 -1
- package/dist/client/logging-stream-registry.js +14 -13
- package/dist/client/rpc/bare-client.d.ts +10 -14
- package/dist/client/rpc/bare-client.js +28 -2
- package/dist/client/rpc/bare-rpc-client.d.ts +1 -1
- package/dist/client/rpc/bare-rpc-client.js +16 -13
- package/dist/client/rpc/expo-rpc-client.d.ts +2 -2
- package/dist/client/rpc/expo-rpc-client.js +15 -12
- package/dist/client/rpc/node-rpc-client.d.ts +1 -1
- package/dist/client/rpc/node-rpc-client.js +10 -7
- package/dist/client/rpc/rpc-client.js +16 -15
- package/dist/constants/audio.d.ts +1 -2
- package/dist/constants/audio.js +1 -17
- package/dist/examples/config/config-path.d.ts +8 -0
- package/dist/examples/config/config-path.js +13 -0
- package/dist/examples/config-reload.d.ts +2 -0
- package/dist/examples/config-reload.js +49 -0
- package/dist/examples/download-with-blind-relays.js +20 -20
- package/dist/examples/embed-hyperdrive.js +35 -3
- package/dist/examples/kv-cache-cleanup.js +1 -1
- package/dist/examples/kv-cache-custom-key.js +1 -1
- package/dist/examples/kv-cache-example.js +1 -1
- package/dist/examples/llamacpp-hyperdrive.js +1 -1
- package/dist/examples/llamacpp-sharded.js +1 -1
- package/dist/examples/logging-file-transport.d.ts +2 -0
- package/dist/examples/{llamacpp-file-logging.js → logging-file-transport.js} +3 -7
- package/dist/examples/logging-streaming.d.ts +2 -0
- package/dist/examples/logging-streaming.js +75 -0
- package/dist/examples/mcp-websearch.d.ts +13 -0
- package/dist/examples/mcp-websearch.js +176 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/logging/addon.d.ts +6 -0
- package/dist/logging/addon.js +59 -0
- package/dist/logging/base-logger.js +24 -14
- package/dist/logging/client-logger.d.ts +3 -0
- package/dist/logging/client-logger.js +13 -0
- package/dist/logging/index.d.ts +6 -1
- package/dist/logging/index.js +6 -1
- package/dist/logging/logger.d.ts +0 -2
- package/dist/logging/logger.js +0 -3
- package/dist/logging/namespaces.d.ts +11 -0
- package/dist/logging/namespaces.js +11 -0
- package/dist/logging/registry.d.ts +26 -0
- package/dist/logging/registry.js +36 -0
- package/dist/logging/server-logger.d.ts +3 -0
- package/dist/logging/server-logger.js +16 -0
- package/dist/logging/stream-logger.d.ts +1 -1
- package/dist/logging/stream-logger.js +6 -3
- package/dist/logging/types.d.ts +2 -0
- package/dist/models/hyperdrive/models.d.ts +789 -51
- package/dist/models/hyperdrive/models.js +979 -200
- package/dist/schemas/common.d.ts +86 -23
- package/dist/schemas/common.js +0 -3
- package/dist/schemas/download-asset.d.ts +5 -5
- package/dist/schemas/embed.d.ts +3 -3
- package/dist/schemas/embed.js +9 -2
- package/dist/schemas/get-model-info.d.ts +2 -2
- package/dist/schemas/index.d.ts +5 -1
- package/dist/schemas/index.js +5 -1
- package/dist/schemas/json-schema.d.ts +16 -0
- package/dist/schemas/json-schema.js +2 -0
- package/dist/schemas/llamacpp-config.d.ts +5 -4
- package/dist/schemas/llamacpp-config.js +7 -5
- package/dist/schemas/load-model.d.ts +931 -211
- package/dist/schemas/load-model.js +7 -1
- package/dist/schemas/logging-stream.d.ts +10 -3
- package/dist/schemas/logging-stream.js +4 -3
- package/dist/schemas/mcp-adapter.d.ts +47 -0
- package/dist/schemas/mcp-adapter.js +1 -0
- package/dist/schemas/model-src-utils.d.ts +8 -6
- package/dist/schemas/model-src-utils.js +8 -3
- package/dist/schemas/reload-config.d.ts +344 -0
- package/dist/schemas/reload-config.js +42 -0
- package/dist/schemas/sdk-config.d.ts +22 -0
- package/dist/schemas/sdk-config.js +33 -0
- package/dist/schemas/sdk-errors-client.d.ts +4 -0
- package/dist/schemas/sdk-errors-client.js +20 -0
- package/dist/schemas/sdk-errors-server.d.ts +3 -0
- package/dist/schemas/sdk-errors-server.js +15 -0
- package/dist/schemas/tools.d.ts +3 -0
- package/dist/schemas/translation-config.d.ts +81 -0
- package/dist/schemas/translation-config.js +3 -4
- package/dist/schemas/whispercpp-config.d.ts +9 -1
- package/dist/schemas/whispercpp-config.js +2 -1
- package/dist/server/bare/addons/llamacpp/create-model.js +13 -4
- package/dist/server/bare/addons/llamacpp/handlers/embed.d.ts +9 -1
- package/dist/server/bare/addons/llamacpp/handlers/embed.js +18 -4
- package/dist/server/bare/addons/llamacpp/kv-cache-utils.js +6 -4
- package/dist/server/bare/addons/load-model.js +10 -4
- package/dist/server/bare/addons/unload-model.js +6 -3
- package/dist/server/bare/addons/whispercpp/handlers/transcribe-stream.js +56 -37
- package/dist/server/bare/delegate-rpc-client.js +12 -10
- package/dist/server/bare/hyperswarm.js +7 -5
- package/dist/server/bare/rag-hyperdb/rag-manager.js +3 -1
- package/dist/server/bare/registry/config-registry.d.ts +13 -4
- package/dist/server/bare/registry/config-registry.js +42 -10
- package/dist/server/bare/registry/logging-stream-registry.d.ts +24 -7
- package/dist/server/bare/registry/logging-stream-registry.js +99 -20
- package/dist/server/bare/registry/model-registry.d.ts +3 -0
- package/dist/server/bare/registry/model-registry.js +9 -6
- package/dist/server/rpc/create-server.js +5 -3
- package/dist/server/rpc/handle-request.js +30 -16
- package/dist/server/rpc/handlers/cancelHandler.js +3 -1
- package/dist/server/rpc/handlers/completion-stream-delegated.js +4 -2
- package/dist/server/rpc/handlers/delete-cache.js +3 -1
- package/dist/server/rpc/handlers/download-asset.js +3 -1
- package/dist/server/rpc/handlers/embed.js +3 -1
- package/dist/server/rpc/handlers/index.d.ts +0 -1
- package/dist/server/rpc/handlers/index.js +0 -2
- package/dist/server/rpc/handlers/load-model/download-manager.js +4 -2
- package/dist/server/rpc/handlers/load-model/http.js +20 -18
- package/dist/server/rpc/handlers/load-model/hyperdrive.js +21 -19
- package/dist/server/rpc/handlers/load-model/resolve.js +7 -5
- package/dist/server/rpc/handlers/load-model-delegated.d.ts +2 -2
- package/dist/server/rpc/handlers/load-model-delegated.js +10 -8
- package/dist/server/rpc/handlers/load-model.js +55 -3
- package/dist/server/rpc/handlers/logging-stream.js +4 -4
- package/dist/server/rpc/handlers/provideHandler/connection.js +12 -10
- package/dist/server/rpc/handlers/provideHandler/handler.js +18 -16
- package/dist/server/rpc/handlers/provideHandler/proxy.js +8 -6
- package/dist/server/rpc/handlers/rag.js +3 -1
- package/dist/server/rpc/handlers/stopProvideHandler.js +3 -1
- package/dist/server/rpc/handlers/transcribe-stream.js +3 -1
- package/dist/server/rpc/handlers/translate.js +3 -1
- package/dist/server/rpc/handlers/unload-model.js +4 -2
- package/dist/server/utils/audio/decoder.d.ts +2 -1
- package/dist/server/utils/audio/decoder.js +49 -12
- package/dist/server/utils/cache.js +7 -5
- package/dist/server/utils/config-transform.d.ts +3 -0
- package/dist/server/utils/config-transform.js +21 -0
- package/dist/server/utils/index.d.ts +1 -0
- package/dist/server/utils/index.js +1 -0
- package/dist/server/worker.js +41 -16
- package/dist/utils/errors-client.d.ts +12 -0
- package/dist/utils/errors-client.js +20 -0
- package/dist/utils/errors-server.d.ts +9 -0
- package/dist/utils/errors-server.js +16 -0
- package/dist/utils/getProcessSafe.d.ts +7 -0
- package/dist/utils/getProcessSafe.js +17 -0
- package/dist/utils/mcp-adapter.d.ts +12 -0
- package/dist/utils/mcp-adapter.js +103 -0
- package/dist/utils/object.d.ts +2 -0
- package/dist/utils/object.js +3 -0
- package/dist/utils/runtime.d.ts +30 -0
- package/dist/utils/runtime.js +48 -0
- package/dist/utils/tool-helpers.d.ts +10 -2
- package/dist/utils/tool-helpers.js +24 -11
- package/package.json +47 -34
- package/dist/client/api/set-config.d.ts +0 -7
- package/dist/client/api/set-config.js +0 -20
- package/dist/client/config-manager.d.ts +0 -4
- package/dist/client/config-manager.js +0 -8
- package/dist/examples/llamacpp-file-logging.d.ts +0 -2
- package/dist/schemas/set-config.d.ts +0 -21
- package/dist/schemas/set-config.js +0 -14
- package/dist/server/rpc/handlers/set-config.d.ts +0 -3
- package/dist/server/rpc/handlers/set-config.js +0 -18
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {} from "../../../../schemas/index.js";
|
|
2
|
+
import { getServerLogger } from "../../../../logging/index.js";
|
|
3
|
+
const logger = getServerLogger();
|
|
2
4
|
const activeDownloads = new Map();
|
|
3
5
|
const clearCacheFlags = new Map();
|
|
4
6
|
export const getActiveDownload = (key) => activeDownloads.get(key);
|
|
@@ -33,7 +35,7 @@ export const createCancelFunction = (downloadKey, clearCache = false) => () => {
|
|
|
33
35
|
unregisterDownload(downloadKey);
|
|
34
36
|
};
|
|
35
37
|
export const cancelAllDownloads = () => {
|
|
36
|
-
|
|
38
|
+
logger.info(`🧹 Cancelling ${activeDownloads.size} active downloads`);
|
|
37
39
|
Array.from(activeDownloads.keys()).forEach((key) => createCancelFunction(key)());
|
|
38
40
|
};
|
|
39
41
|
let isCleaningUp = false;
|
|
@@ -49,6 +51,6 @@ export const cleanupDownloads = async () => {
|
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
catch (error) {
|
|
52
|
-
|
|
54
|
+
logger.error("❌ Error during download cleanup:", error);
|
|
53
55
|
}
|
|
54
56
|
};
|
|
@@ -5,6 +5,8 @@ import { AbortController } from "bare-abort-controller";
|
|
|
5
5
|
import { getModelsCacheDir, generateShortHash } from "../../../utils/index.js";
|
|
6
6
|
import { getActiveDownload, registerDownload, unregisterDownload, createHttpDownloadKey, shouldClearCache, clearClearCacheFlag, } from "./download-manager.js";
|
|
7
7
|
import { DownloadCancelledError, HTTPError, NoResponseBodyError, ResponseBodyNotReadableError, } from "../../../../utils/errors-server.js";
|
|
8
|
+
import { getServerLogger } from "../../../../logging/index.js";
|
|
9
|
+
const logger = getServerLogger();
|
|
8
10
|
function extractFilenameFromUrl(url) {
|
|
9
11
|
// Parse URL to get the filename from the path
|
|
10
12
|
const urlParts = url.split("/");
|
|
@@ -28,14 +30,14 @@ async function validateCachedFile(modelPath, url, signal) {
|
|
|
28
30
|
expectedSize = parseInt(response.headers.get("content-length") || "0");
|
|
29
31
|
}
|
|
30
32
|
catch (error) {
|
|
31
|
-
|
|
33
|
+
logger.warn(`⚠️ Could not get expected file size from HEAD request, will re-download: ${String(error)}`);
|
|
32
34
|
return null;
|
|
33
35
|
}
|
|
34
36
|
if (localSize !== expectedSize) {
|
|
35
|
-
|
|
37
|
+
logger.info(`📥 Cached file size mismatch. Expected: ${expectedSize}, Found: ${localSize}. Re-downloading...`);
|
|
36
38
|
return null;
|
|
37
39
|
}
|
|
38
|
-
|
|
40
|
+
logger.info(`✅ Using cached HTTP model: ${modelPath}`);
|
|
39
41
|
return modelPath;
|
|
40
42
|
}
|
|
41
43
|
catch {
|
|
@@ -47,7 +49,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
47
49
|
if (signal?.aborted) {
|
|
48
50
|
throw new DownloadCancelledError();
|
|
49
51
|
}
|
|
50
|
-
|
|
52
|
+
logger.info(`📥 Downloading model from HTTP: ${url}`);
|
|
51
53
|
// Check if file exists for resuming
|
|
52
54
|
let startOffset = 0;
|
|
53
55
|
let downloadedBytes = 0;
|
|
@@ -55,10 +57,10 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
55
57
|
const existingStats = await fsPromises.stat(modelPath);
|
|
56
58
|
startOffset = existingStats.size;
|
|
57
59
|
downloadedBytes = startOffset;
|
|
58
|
-
|
|
60
|
+
logger.info(`📥 Resuming download from byte ${startOffset}`);
|
|
59
61
|
}
|
|
60
62
|
catch {
|
|
61
|
-
|
|
63
|
+
logger.info(`📥 Starting fresh download`);
|
|
62
64
|
}
|
|
63
65
|
// Prepare headers for resume if needed
|
|
64
66
|
const headers = {
|
|
@@ -77,7 +79,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
77
79
|
if (!response.ok) {
|
|
78
80
|
// Check if it's a 416 (Range Not Satisfiable) - file already complete
|
|
79
81
|
if (response.status === 416 && startOffset > 0) {
|
|
80
|
-
|
|
82
|
+
logger.info(`✅ File already completely downloaded`);
|
|
81
83
|
// Send 100% progress for already complete file
|
|
82
84
|
if (progressCallback) {
|
|
83
85
|
progressCallback({
|
|
@@ -92,7 +94,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
92
94
|
}
|
|
93
95
|
// Check if server doesn't support range requests
|
|
94
96
|
if (response.status === 200 && startOffset > 0) {
|
|
95
|
-
|
|
97
|
+
logger.warn(`⚠️ Server doesn't support resume, starting fresh download`);
|
|
96
98
|
startOffset = 0;
|
|
97
99
|
downloadedBytes = 0;
|
|
98
100
|
// Retry without Range header
|
|
@@ -131,7 +133,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
131
133
|
// For fresh downloads
|
|
132
134
|
totalBytes = contentLength ? parseInt(contentLength) : 0;
|
|
133
135
|
}
|
|
134
|
-
|
|
136
|
+
logger.info(`📏 Total size: ${totalBytes} bytes (${(totalBytes / 1024 / 1024).toFixed(2)} MB)`);
|
|
135
137
|
// Create write stream (append if resuming)
|
|
136
138
|
const writeStreamOptions = startOffset > 0 && response.status === 206 ? { flags: "a" } : {};
|
|
137
139
|
const writeStream = fs.createWriteStream(modelPath, writeStreamOptions);
|
|
@@ -174,7 +176,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
174
176
|
signal.addEventListener("abort", abortHandler);
|
|
175
177
|
}
|
|
176
178
|
writeStream.on("finish", () => {
|
|
177
|
-
|
|
179
|
+
logger.info(`✅ Model downloaded successfully to ${modelPath}`);
|
|
178
180
|
if (signal) {
|
|
179
181
|
signal.removeEventListener("abort", abortHandler);
|
|
180
182
|
}
|
|
@@ -216,7 +218,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
216
218
|
// Close the write stream
|
|
217
219
|
await new Promise((resolve, reject) => {
|
|
218
220
|
writeStream.end(() => {
|
|
219
|
-
|
|
221
|
+
logger.info(`✅ Model downloaded successfully to ${modelPath}`);
|
|
220
222
|
resolve();
|
|
221
223
|
});
|
|
222
224
|
writeStream.on("error", reject);
|
|
@@ -262,7 +264,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
262
264
|
// Close the write stream
|
|
263
265
|
await new Promise((resolve, reject) => {
|
|
264
266
|
writeStream.end(() => {
|
|
265
|
-
|
|
267
|
+
logger.info(`✅ Model downloaded successfully to ${modelPath}`);
|
|
266
268
|
resolve();
|
|
267
269
|
});
|
|
268
270
|
writeStream.on("error", reject);
|
|
@@ -275,7 +277,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
275
277
|
}
|
|
276
278
|
catch (error) {
|
|
277
279
|
writeStream.destroy();
|
|
278
|
-
|
|
280
|
+
logger.error("Error during download:", error instanceof Error ? error.message : String(error));
|
|
279
281
|
throw error instanceof Error ? error : new Error(String(error));
|
|
280
282
|
}
|
|
281
283
|
}
|
|
@@ -284,7 +286,7 @@ export async function downloadModelFromHttp(url, progressCallback) {
|
|
|
284
286
|
// Check if already downloading
|
|
285
287
|
const existing = getActiveDownload(downloadKey);
|
|
286
288
|
if (existing) {
|
|
287
|
-
|
|
289
|
+
logger.info(`📥 Reusing existing download for: ${downloadKey}`);
|
|
288
290
|
return existing.promise;
|
|
289
291
|
}
|
|
290
292
|
const cacheDir = getModelsCacheDir();
|
|
@@ -336,21 +338,21 @@ export async function downloadModelFromHttp(url, progressCallback) {
|
|
|
336
338
|
return modelPath;
|
|
337
339
|
}
|
|
338
340
|
catch (error) {
|
|
339
|
-
|
|
341
|
+
logger.error("❌ Error downloading model:", error instanceof Error ? error.message : String(error));
|
|
340
342
|
// Check if we should delete the partial file (clearCache was requested)
|
|
341
343
|
if (error instanceof Error && error.message === "Download cancelled") {
|
|
342
344
|
if (shouldClearCache(downloadKey)) {
|
|
343
|
-
|
|
345
|
+
logger.info("🗑️ Clearing cache - deleting partial file");
|
|
344
346
|
try {
|
|
345
347
|
await fsPromises.unlink(modelPath);
|
|
346
|
-
|
|
348
|
+
logger.info(`✅ Deleted partial file: ${modelPath}`);
|
|
347
349
|
}
|
|
348
350
|
catch {
|
|
349
351
|
// Ignore cleanup errors
|
|
350
352
|
}
|
|
351
353
|
}
|
|
352
354
|
else {
|
|
353
|
-
|
|
355
|
+
logger.info("📥 Download paused - partial file preserved for resume");
|
|
354
356
|
}
|
|
355
357
|
clearClearCacheFlag(downloadKey);
|
|
356
358
|
}
|
|
@@ -11,6 +11,8 @@ import { getModelBySrc } from "../../../../models/hyperdrive/index.js";
|
|
|
11
11
|
import { getActiveDownload, registerDownload, unregisterDownload, createHyperdriveDownloadKey, shouldClearCache, clearClearCacheFlag, } from "./download-manager.js";
|
|
12
12
|
import { getSDKConfig } from "../../../bare/registry/config-registry.js";
|
|
13
13
|
import { FileNotFoundError, ChecksumValidationFailedError, DownloadCancelledError, HyperdriveDownloadFailedError, ModelLoadFailedError, NoBlobFoundError, } from "../../../../utils/errors-server.js";
|
|
14
|
+
import { getServerLogger } from "../../../../logging/index.js";
|
|
15
|
+
const logger = getServerLogger();
|
|
14
16
|
function getCorestoreDir(hyperdriveKey) {
|
|
15
17
|
return path.join(getEnv().HOME_DIR, ".qvac", "corestore", hyperdriveKey);
|
|
16
18
|
}
|
|
@@ -33,7 +35,7 @@ async function setupHyperdrive(hyperdriveKey, corestoreDir) {
|
|
|
33
35
|
const swarm = new Hyperswarm(swarmOptions);
|
|
34
36
|
const doneFindingPeers = drive.findingPeers();
|
|
35
37
|
swarm.on("connection", (connection) => {
|
|
36
|
-
|
|
38
|
+
logger.debug(`🤝 Connected to peer for hyperdrive download`);
|
|
37
39
|
drive.replicate(connection);
|
|
38
40
|
});
|
|
39
41
|
swarm.join(drive.discoveryKey, { server: false, client: true });
|
|
@@ -41,7 +43,7 @@ async function setupHyperdrive(hyperdriveKey, corestoreDir) {
|
|
|
41
43
|
return { corestore, drive, swarm, corestoreDir };
|
|
42
44
|
}
|
|
43
45
|
async function cleanupHyperdrive(setup) {
|
|
44
|
-
|
|
46
|
+
logger.debug("🧹 Cleaning up hyperdrive setup");
|
|
45
47
|
if (!setup.swarm.suspended) {
|
|
46
48
|
try {
|
|
47
49
|
await setup.swarm.suspend();
|
|
@@ -55,12 +57,12 @@ async function cleanupHyperdrive(setup) {
|
|
|
55
57
|
await setup.corestore.close();
|
|
56
58
|
}
|
|
57
59
|
export async function deleteCorestoreDirectory(corestoreDir) {
|
|
58
|
-
|
|
60
|
+
logger.info(`🗑️ DELETING corestore directory... ${corestoreDir}`);
|
|
59
61
|
try {
|
|
60
62
|
await fsPromises.rm(corestoreDir, { recursive: true, force: true });
|
|
61
63
|
}
|
|
62
64
|
catch (e) {
|
|
63
|
-
|
|
65
|
+
logger.error(`Error deleting corestore directory: ${e instanceof Error ? e.message : String(e)}`);
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
async function findFileInHyperdrive(drive, modelFileName) {
|
|
@@ -148,7 +150,7 @@ async function validateCachedFile(modelPath, modelFileName, expectedSize, expect
|
|
|
148
150
|
// For hyperdrive: only validate if file is complete
|
|
149
151
|
// Partial files are ignored - corestore state is the source of truth for resume
|
|
150
152
|
if (localSize === expectedSize) {
|
|
151
|
-
|
|
153
|
+
logger.info(`✅ Model cached with correct size: ${modelPath}`);
|
|
152
154
|
// Always validate checksum if provided, even when size matches
|
|
153
155
|
if (expectedChecksum && expectedChecksum.length === 64) {
|
|
154
156
|
const checksum = await calculateFileChecksum(modelPath);
|
|
@@ -156,7 +158,7 @@ async function validateCachedFile(modelPath, modelFileName, expectedSize, expect
|
|
|
156
158
|
throw new ChecksumValidationFailedError(`${modelFileName}. Expected: ${expectedChecksum}. Actual: ${checksum}. File may be corrupted`);
|
|
157
159
|
}
|
|
158
160
|
}
|
|
159
|
-
|
|
161
|
+
logger.info(`✅ Model already cached and size validated: ${modelPath}`);
|
|
160
162
|
return modelPath;
|
|
161
163
|
}
|
|
162
164
|
// File exists but incomplete - will be overwritten during download
|
|
@@ -173,10 +175,10 @@ async function downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdri
|
|
|
173
175
|
if (signal?.aborted) {
|
|
174
176
|
throw new DownloadCancelledError();
|
|
175
177
|
}
|
|
176
|
-
|
|
178
|
+
logger.info(`Downloading model from hyperdrive ${hyperdriveKey} to ${modelPath}`);
|
|
177
179
|
const setup = await setupHyperdrive(hyperdriveKey, corestoreDir);
|
|
178
180
|
const cleanup = () => {
|
|
179
|
-
|
|
181
|
+
logger.info("🛑 Aborting hyperdrive download...");
|
|
180
182
|
setup.swarm.suspended = true;
|
|
181
183
|
setup.swarm.suspend().catch(() => {
|
|
182
184
|
// Ignore errors during emergency suspend
|
|
@@ -192,7 +194,7 @@ async function downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdri
|
|
|
192
194
|
: undefined;
|
|
193
195
|
await downloadAndValidateFile(setup.drive, modelFileName, modelPath, 0, // Size will be determined from drive
|
|
194
196
|
expectedChecksum, progressContext, signal);
|
|
195
|
-
|
|
197
|
+
logger.info(`✅ Model downloaded successfully to ${modelPath}`);
|
|
196
198
|
// Send final 100% progress update
|
|
197
199
|
if (progressCallback) {
|
|
198
200
|
try {
|
|
@@ -215,7 +217,7 @@ async function downloadSingleFileToFilesystem(modelPath, modelFileName, hyperdri
|
|
|
215
217
|
}
|
|
216
218
|
}
|
|
217
219
|
catch (error) {
|
|
218
|
-
|
|
220
|
+
logger.error("❌ Error during hyperdrive download:", error instanceof Error ? error.message : String(error));
|
|
219
221
|
// Preserve cancellation errors
|
|
220
222
|
if (error instanceof Error && error.message === "Download cancelled") {
|
|
221
223
|
throw error;
|
|
@@ -319,7 +321,7 @@ async function downloadAndValidateFile(drive, sourceFileName, targetFilePath, ex
|
|
|
319
321
|
}
|
|
320
322
|
}
|
|
321
323
|
else if (!expectedChecksum) {
|
|
322
|
-
|
|
324
|
+
logger.warn(`⚠️ No checksum available for validation`);
|
|
323
325
|
}
|
|
324
326
|
}
|
|
325
327
|
catch (error) {
|
|
@@ -368,11 +370,11 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
368
370
|
const shardDir = getShardedModelCacheDir(hyperdriveKey);
|
|
369
371
|
const allFiles = shardMetadata.map((s) => s.filename);
|
|
370
372
|
const numberedShardCount = shardInfo.totalShards;
|
|
371
|
-
|
|
373
|
+
logger.info(`Downloading sharded model with ${numberedShardCount} numbered shards + ${allFiles.length - numberedShardCount} companion files to ${shardDir}`);
|
|
372
374
|
// Check which files need to be downloaded
|
|
373
375
|
const invalidIndices = await checkShardCompleteness(hyperdriveKey, allFiles, shardMetadata);
|
|
374
376
|
if (invalidIndices.length === 0) {
|
|
375
|
-
|
|
377
|
+
logger.info(`✅ All ${allFiles.length} files already downloaded and validated`);
|
|
376
378
|
if (progressCallback) {
|
|
377
379
|
const overallTotal = shardMetadata.reduce((sum, shard) => sum + shard.expectedSize, 0);
|
|
378
380
|
const lastFile = allFiles[allFiles.length - 1];
|
|
@@ -394,12 +396,12 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
394
396
|
}
|
|
395
397
|
return getShardPath(hyperdriveKey, allFiles[0]);
|
|
396
398
|
}
|
|
397
|
-
|
|
399
|
+
logger.info(`📥 Need to download ${invalidIndices.length} of ${allFiles.length} files`);
|
|
398
400
|
// Setup hyperdrive once for all shards
|
|
399
401
|
const corestoreDir = getCorestoreDir(hyperdriveKey);
|
|
400
402
|
const setup = await setupHyperdrive(hyperdriveKey, corestoreDir);
|
|
401
403
|
const cleanup = () => {
|
|
402
|
-
|
|
404
|
+
logger.info("🛑 Aborting sharded hyperdrive download...");
|
|
403
405
|
setup.swarm.suspended = true;
|
|
404
406
|
setup.swarm.suspend().catch(() => {
|
|
405
407
|
// Ignore errors during emergency suspend
|
|
@@ -420,7 +422,7 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
420
422
|
const filePath = getShardPath(hyperdriveKey, file);
|
|
421
423
|
// Skip if already valid
|
|
422
424
|
if (!invalidIndices.includes(i)) {
|
|
423
|
-
|
|
425
|
+
logger.debug(`✅ File ${i + 1}/${allFiles.length} already valid: ${file}`);
|
|
424
426
|
overallDownloaded += fileMeta.expectedSize;
|
|
425
427
|
// Report progress for skipped files
|
|
426
428
|
if (progressCallback) {
|
|
@@ -442,7 +444,7 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
442
444
|
}
|
|
443
445
|
continue;
|
|
444
446
|
}
|
|
445
|
-
|
|
447
|
+
logger.info(`📥 Downloading file ${i + 1}/${allFiles.length}: ${file}`);
|
|
446
448
|
const progressContext = progressCallback
|
|
447
449
|
? {
|
|
448
450
|
downloadKey: createHyperdriveDownloadKey(hyperdriveKey, firstShardFileName),
|
|
@@ -460,7 +462,7 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
460
462
|
if (signal?.aborted) {
|
|
461
463
|
throw new DownloadCancelledError();
|
|
462
464
|
}
|
|
463
|
-
|
|
465
|
+
logger.info(`✅ File ${i + 1}/${allFiles.length} downloaded and validated`);
|
|
464
466
|
overallDownloaded += fileMeta.expectedSize;
|
|
465
467
|
}
|
|
466
468
|
if (progressCallback && overallDownloaded === overallTotal) {
|
|
@@ -487,7 +489,7 @@ async function downloadShardedFilesToFilesystem(hyperdriveKey, firstShardFileNam
|
|
|
487
489
|
}
|
|
488
490
|
}
|
|
489
491
|
catch (error) {
|
|
490
|
-
|
|
492
|
+
logger.error("❌ Error during sharded hyperdrive download:", error instanceof Error ? error.message : String(error));
|
|
491
493
|
// Preserve cancellation errors
|
|
492
494
|
if (error instanceof Error && error.message === "Download cancelled") {
|
|
493
495
|
throw error;
|
|
@@ -6,6 +6,8 @@ import path from "bare-path";
|
|
|
6
6
|
import { downloadModelFromHttp } from "./http.js";
|
|
7
7
|
import { downloadModelFromHyperdrive } from "./hyperdrive.js";
|
|
8
8
|
import { ModelLoadFailedError, ModelNotFoundError, SeedingNotSupportedError, } from "../../../../utils/errors-server.js";
|
|
9
|
+
import { getServerLogger } from "../../../../logging/index.js";
|
|
10
|
+
const logger = getServerLogger();
|
|
9
11
|
/**
|
|
10
12
|
* Resolves a local file path or cached file
|
|
11
13
|
*/
|
|
@@ -20,14 +22,14 @@ async function resolveLocalOrCachedFile(modelIdOrPath) {
|
|
|
20
22
|
const cachedPath = path.join(cacheDir, modelIdOrPath);
|
|
21
23
|
try {
|
|
22
24
|
await fsPromises.access(cachedPath);
|
|
23
|
-
|
|
25
|
+
logger.info(`Loading cached model: ${cachedPath}`);
|
|
24
26
|
return cachedPath;
|
|
25
27
|
}
|
|
26
28
|
catch {
|
|
27
29
|
// Try as local file in current directory
|
|
28
30
|
try {
|
|
29
31
|
await fsPromises.access(modelIdOrPath);
|
|
30
|
-
|
|
32
|
+
logger.info(`Loading local file: ${modelIdOrPath}`);
|
|
31
33
|
return modelIdOrPath;
|
|
32
34
|
}
|
|
33
35
|
catch {
|
|
@@ -57,13 +59,13 @@ export async function resolveModelPath(modelSrc, progressCallback, seed) {
|
|
|
57
59
|
// Check if it's an HTTP/HTTPS URL
|
|
58
60
|
if (actualModelSrc.startsWith("http://") ||
|
|
59
61
|
actualModelSrc.startsWith("https://")) {
|
|
60
|
-
|
|
62
|
+
logger.info(`Loading from HTTP URL: ${actualModelSrc}`);
|
|
61
63
|
actualPath = await downloadModelFromHttp(actualModelSrc, progressCallback);
|
|
62
|
-
|
|
64
|
+
logger.info(`Loaded Model to ${actualPath}`);
|
|
63
65
|
}
|
|
64
66
|
else if (hyperdriveKey) {
|
|
65
67
|
// Direct hyperdrive loading
|
|
66
|
-
|
|
68
|
+
logger.info(`Loading from hyperdrive: ${hyperdriveKey}`);
|
|
67
69
|
actualPath = await downloadModelFromHyperdrive(hyperdriveKey, actualModelSrc, seed, progressCallback);
|
|
68
70
|
}
|
|
69
71
|
else if (actualModelSrc.includes("/") || actualModelSrc.includes("\\")) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function handleLoadModelDelegated(request:
|
|
1
|
+
import type { LoadModelSrcRequest, LoadModelResponse, ModelProgressUpdate } from "../../../schemas/index";
|
|
2
|
+
export declare function handleLoadModelDelegated(request: LoadModelSrcRequest, progressCallback?: (update: ModelProgressUpdate) => void): Promise<LoadModelResponse>;
|
|
3
3
|
//# sourceMappingURL=load-model-delegated.d.ts.map
|
|
@@ -4,6 +4,8 @@ import { getRPC } from "../../bare/delegate-rpc-client.js";
|
|
|
4
4
|
import { send, stream } from "../../../client/rpc/rpc-client.js";
|
|
5
5
|
import { handleLoadModel } from "./load-model/index.js";
|
|
6
6
|
import { ModelLoadFailedError, DelegateNoFinalResponseError, } from "../../../utils/errors-server.js";
|
|
7
|
+
import { getServerLogger } from "../../../logging/index.js";
|
|
8
|
+
const logger = getServerLogger();
|
|
7
9
|
export async function handleLoadModelDelegated(request, progressCallback) {
|
|
8
10
|
if (!request.delegate) {
|
|
9
11
|
throw new ModelLoadFailedError("Delegate information is required for delegated load model");
|
|
@@ -11,7 +13,7 @@ export async function handleLoadModelDelegated(request, progressCallback) {
|
|
|
11
13
|
const { delegate } = request;
|
|
12
14
|
const { topic, providerPublicKey, timeout, fallbackToLocal } = delegate;
|
|
13
15
|
try {
|
|
14
|
-
|
|
16
|
+
logger.info(`📤 Sending delegated loadModel request to provider: ${providerPublicKey}${timeout ? `, timeout: ${timeout}ms` : ""}`);
|
|
15
17
|
// Create RPC instance for this HyperSwarm peer
|
|
16
18
|
const rpc = await getRPC(topic, providerPublicKey, { timeout });
|
|
17
19
|
// Strip out the delegate field to avoid infinite delegation
|
|
@@ -20,7 +22,7 @@ export async function handleLoadModelDelegated(request, progressCallback) {
|
|
|
20
22
|
let finalResponse;
|
|
21
23
|
if (request.withProgress) {
|
|
22
24
|
// Use streaming for progress updates
|
|
23
|
-
|
|
25
|
+
logger.debug("📊 Using streaming mode for loadModel with progress");
|
|
24
26
|
const responseStream = stream(providerRequest, rpc, timeout ? { timeout } : {});
|
|
25
27
|
for await (const response of responseStream) {
|
|
26
28
|
if (response.type === "modelProgress") {
|
|
@@ -40,11 +42,11 @@ export async function handleLoadModelDelegated(request, progressCallback) {
|
|
|
40
42
|
}
|
|
41
43
|
else {
|
|
42
44
|
// Use simple send for non-progress requests
|
|
43
|
-
|
|
45
|
+
logger.debug("📤 Using simple send mode for loadModel");
|
|
44
46
|
finalResponse = (await send(providerRequest, rpc, timeout ? { timeout } : {}));
|
|
45
47
|
}
|
|
46
48
|
if (!finalResponse || !finalResponse.success) {
|
|
47
|
-
|
|
49
|
+
logger.error("Provider failed to load model:", finalResponse?.error);
|
|
48
50
|
return {
|
|
49
51
|
type: "loadModel",
|
|
50
52
|
success: false,
|
|
@@ -62,7 +64,7 @@ export async function handleLoadModelDelegated(request, progressCallback) {
|
|
|
62
64
|
delegateOptions.timeout = timeout;
|
|
63
65
|
}
|
|
64
66
|
registerModel(modelId, delegateOptions);
|
|
65
|
-
|
|
67
|
+
logger.info(`✅ Delegated model registered: ${modelId} -> provider: ${providerPublicKey}`);
|
|
66
68
|
return {
|
|
67
69
|
type: "loadModel",
|
|
68
70
|
success: true,
|
|
@@ -70,16 +72,16 @@ export async function handleLoadModelDelegated(request, progressCallback) {
|
|
|
70
72
|
};
|
|
71
73
|
}
|
|
72
74
|
catch (error) {
|
|
73
|
-
|
|
75
|
+
logger.error("Error in delegated load model:", error);
|
|
74
76
|
if (fallbackToLocal) {
|
|
75
|
-
|
|
77
|
+
logger.info("🔄 Fallback to local model loading enabled, attempting local load...");
|
|
76
78
|
try {
|
|
77
79
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
78
80
|
const { delegate: _, ...localRequest } = request;
|
|
79
81
|
return await handleLoadModel(localRequest, progressCallback);
|
|
80
82
|
}
|
|
81
83
|
catch (localError) {
|
|
82
|
-
|
|
84
|
+
logger.error("❌ Local fallback also failed:", localError);
|
|
83
85
|
return {
|
|
84
86
|
type: "loadModel",
|
|
85
87
|
success: false,
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { loadModel } from "../../bare/addons/index.js";
|
|
2
2
|
import { resolveModelPath } from "./load-model/resolve.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { getModelEntry, updateModelConfig, } from "../../bare/registry/model-registry.js";
|
|
4
|
+
import { generateShortHash, transformConfigForReload } from "../../utils/index.js";
|
|
5
|
+
import { TTSConfigModelRequiredError, ESpeakDataPathRequiredError, ConfigReloadNotSupportedError, ModelTypeMismatchError, ModelIsDelegatedError, ModelNotFoundError, } from "../../../utils/errors-server.js";
|
|
6
|
+
import { getServerLogger } from "../../../logging/index.js";
|
|
7
|
+
const logger = getServerLogger();
|
|
5
8
|
export async function handleLoadModel(request, progressCallback) {
|
|
9
|
+
// Handle reload config
|
|
10
|
+
if (isReloadConfigRequest(request)) {
|
|
11
|
+
return handleConfigReload(request);
|
|
12
|
+
}
|
|
13
|
+
// Handle load new model from source
|
|
6
14
|
const { modelSrc, modelName, seed, projectionModelSrc, vadModelSrc, configSrc, } = request;
|
|
7
15
|
const eSpeakDataPath = request.modelType === "tts"
|
|
8
16
|
? request.eSpeakDataPath
|
|
@@ -49,7 +57,48 @@ export async function handleLoadModel(request, progressCallback) {
|
|
|
49
57
|
};
|
|
50
58
|
}
|
|
51
59
|
catch (error) {
|
|
52
|
-
|
|
60
|
+
logger.error("Error loading model:", error);
|
|
61
|
+
return {
|
|
62
|
+
type: "loadModel",
|
|
63
|
+
success: false,
|
|
64
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function handleConfigReload(request) {
|
|
69
|
+
const { modelId, modelType, modelConfig } = request;
|
|
70
|
+
try {
|
|
71
|
+
const entry = getModelEntry(modelId);
|
|
72
|
+
if (!entry) {
|
|
73
|
+
throw new ModelNotFoundError(modelId);
|
|
74
|
+
}
|
|
75
|
+
if (entry.isDelegated) {
|
|
76
|
+
throw new ModelIsDelegatedError(modelId);
|
|
77
|
+
}
|
|
78
|
+
const storedModelType = entry.local.modelType;
|
|
79
|
+
if (storedModelType !== modelType) {
|
|
80
|
+
throw new ModelTypeMismatchError(storedModelType, modelType);
|
|
81
|
+
}
|
|
82
|
+
const model = entry.local.model;
|
|
83
|
+
const currentConfig = entry.local.config;
|
|
84
|
+
if (typeof model.reload !== "function") {
|
|
85
|
+
throw new ConfigReloadNotSupportedError(modelId);
|
|
86
|
+
}
|
|
87
|
+
const mergedConfig = {
|
|
88
|
+
...currentConfig,
|
|
89
|
+
...modelConfig,
|
|
90
|
+
};
|
|
91
|
+
const reloadConfig = transformConfigForReload(storedModelType, mergedConfig);
|
|
92
|
+
await model.reload(reloadConfig);
|
|
93
|
+
updateModelConfig(modelId, mergedConfig);
|
|
94
|
+
return {
|
|
95
|
+
type: "loadModel",
|
|
96
|
+
success: true,
|
|
97
|
+
modelId,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
logger.error("Error reloading config:", error);
|
|
53
102
|
return {
|
|
54
103
|
type: "loadModel",
|
|
55
104
|
success: false,
|
|
@@ -57,3 +106,6 @@ export async function handleLoadModel(request, progressCallback) {
|
|
|
57
106
|
};
|
|
58
107
|
}
|
|
59
108
|
}
|
|
109
|
+
function isReloadConfigRequest(request) {
|
|
110
|
+
return "modelId" in request && !("modelSrc" in request);
|
|
111
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { registerLoggingStream, unregisterLoggingStream, } from "../../bare/registry/logging-stream-registry.js";
|
|
2
2
|
export async function* handleLoggingStream(request) {
|
|
3
|
-
const {
|
|
3
|
+
const { id } = request;
|
|
4
4
|
const logQueue = [];
|
|
5
5
|
let pendingResolve = null;
|
|
6
6
|
const streamHandler = (level, namespace, message) => {
|
|
7
7
|
const logResponse = {
|
|
8
8
|
type: "loggingStream",
|
|
9
|
-
|
|
9
|
+
id,
|
|
10
10
|
level: level,
|
|
11
11
|
namespace,
|
|
12
12
|
message,
|
|
@@ -19,7 +19,7 @@ export async function* handleLoggingStream(request) {
|
|
|
19
19
|
resolve();
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
|
-
registerLoggingStream(
|
|
22
|
+
registerLoggingStream(id, streamHandler);
|
|
23
23
|
try {
|
|
24
24
|
while (true) {
|
|
25
25
|
while (logQueue.length > 0) {
|
|
@@ -32,6 +32,6 @@ export async function* handleLoggingStream(request) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
finally {
|
|
35
|
-
unregisterLoggingStream(
|
|
35
|
+
unregisterLoggingStream(id, streamHandler);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import RPC from "bare-rpc";
|
|
2
2
|
import { createRpcProxy } from "./proxy.js";
|
|
3
|
+
import { getServerLogger } from "../../../../logging/index.js";
|
|
4
|
+
const logger = getServerLogger();
|
|
3
5
|
export function setupConnectionHandlers(swarm) {
|
|
4
|
-
|
|
6
|
+
logger.debug("👂 Setting up connection listener...");
|
|
5
7
|
swarm.on("close", () => {
|
|
6
|
-
|
|
8
|
+
logger.debug("🔗 Connection closed!");
|
|
7
9
|
});
|
|
8
10
|
swarm.on("connection", (conn) => {
|
|
9
|
-
|
|
11
|
+
logger.debug("🔗 Connection event triggered!");
|
|
10
12
|
const peerPubkey = conn.remotePublicKey?.toString("hex");
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
logger.info(`📡 New connection established from: ${peerPubkey?.substring(0, 16)}...`);
|
|
14
|
+
logger.debug("🔐 Full peer public key:", peerPubkey);
|
|
13
15
|
// Create RPC instance for this connection (as server)
|
|
14
|
-
|
|
16
|
+
logger.debug("⚙️ Creating RPC instance for connection...");
|
|
15
17
|
new RPC(conn, createRpcProxy());
|
|
16
|
-
|
|
18
|
+
logger.debug("✅ RPC instance created successfully");
|
|
17
19
|
conn.on("close", () => {
|
|
18
|
-
|
|
20
|
+
logger.debug(`🔌 Connection closed for peer: ${peerPubkey?.substring(0, 16)}`);
|
|
19
21
|
});
|
|
20
22
|
conn.on("error", (err) => {
|
|
21
|
-
|
|
23
|
+
logger.error(`❌ Connection error for peer ${peerPubkey?.substring(0, 16)}:`, err);
|
|
22
24
|
});
|
|
23
25
|
});
|
|
24
|
-
|
|
26
|
+
logger.debug("✅ Connection listener set up");
|
|
25
27
|
}
|