@qvac/sdk 0.3.0 → 0.4.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 +22 -0
- package/dist/client/api/cancel.d.ts +1 -1
- package/dist/client/api/cancel.js +4 -3
- package/dist/client/api/completion-stream.d.ts +24 -32
- package/dist/client/api/completion-stream.js +142 -50
- package/dist/client/api/delete-cache.js +3 -2
- package/dist/client/api/download-asset.d.ts +3 -3
- package/dist/client/api/download-asset.js +12 -17
- package/dist/client/api/embed.d.ts +1 -1
- package/dist/client/api/embed.js +4 -3
- package/dist/client/api/get-model-info.d.ts +29 -0
- package/dist/client/api/get-model-info.js +14 -0
- package/dist/client/api/index.d.ts +3 -0
- package/dist/client/api/index.js +3 -0
- package/dist/client/api/load-model.d.ts +3 -3
- package/dist/client/api/load-model.js +13 -22
- package/dist/client/api/logging-stream.d.ts +1 -1
- package/dist/client/api/logging-stream.js +3 -2
- package/dist/client/api/ping.d.ts +1 -1
- package/dist/client/api/ping.js +3 -2
- package/dist/client/api/provide.d.ts +1 -1
- package/dist/client/api/provide.js +4 -3
- package/dist/client/api/rag.d.ts +3 -3
- package/dist/client/api/rag.js +13 -12
- package/dist/client/api/set-config.d.ts +7 -0
- package/dist/client/api/set-config.js +20 -0
- package/dist/client/api/stop-provider.d.ts +1 -1
- package/dist/client/api/stop-provider.js +4 -3
- package/dist/client/api/text-to-speech.d.ts +7 -0
- package/dist/client/api/text-to-speech.js +58 -0
- package/dist/client/api/transcribe.d.ts +4 -2
- package/dist/client/api/transcribe.js +9 -5
- package/dist/client/api/translate.d.ts +1 -1
- package/dist/client/api/translate.js +3 -2
- package/dist/client/api/unload-model.d.ts +5 -1
- package/dist/client/api/unload-model.js +14 -4
- package/dist/client/config-manager.d.ts +4 -0
- package/dist/client/config-manager.js +8 -0
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/init-hooks.d.ts +6 -0
- package/dist/client/init-hooks.js +37 -0
- package/dist/client/rpc/bare-client.d.ts +69 -0
- package/dist/client/rpc/bare-client.js +5 -4
- package/dist/client/rpc/bare-rpc-client.js +7 -3
- package/dist/client/rpc/expo-rpc-client.d.ts +1 -0
- package/dist/client/rpc/expo-rpc-client.js +9 -1
- package/dist/client/rpc/node-rpc-client.d.ts +1 -1
- package/dist/client/rpc/node-rpc-client.js +22 -9
- package/dist/client/rpc/rpc-client.d.ts +1 -0
- package/dist/client/rpc/rpc-client.js +20 -1
- package/dist/examples/cache-management.d.ts +2 -0
- package/dist/examples/cache-management.js +97 -0
- package/dist/examples/delegated-inference/consumer.js +2 -2
- package/dist/examples/download-with-blind-relays.d.ts +2 -0
- package/dist/examples/download-with-blind-relays.js +48 -0
- package/dist/examples/download-with-cancel.js +3 -4
- package/dist/examples/embed-hyperdrive.js +0 -1
- package/dist/examples/kv-cache-cleanup.js +0 -1
- package/dist/examples/kv-cache-custom-key.js +0 -1
- package/dist/examples/kv-cache-example.js +0 -1
- package/dist/examples/llamacpp-file-logging.js +0 -1
- package/dist/examples/llamacpp-filesystem.js +2 -2
- package/dist/examples/llamacpp-http.js +0 -1
- package/dist/examples/llamacpp-hyperdrive.js +0 -1
- package/dist/examples/llamacpp-multimodal.js +0 -1
- package/dist/examples/llamacpp-native-tools.js +118 -36
- package/dist/examples/llamacpp-sharded.d.ts +2 -0
- package/dist/examples/llamacpp-sharded.js +44 -0
- package/dist/examples/multi-model-demo.js +0 -1
- package/dist/examples/parallel-download.js +2 -2
- package/dist/examples/rag/rag-chromadb.js +0 -1
- package/dist/examples/rag/rag-hyperdb-workspaces.js +0 -1
- package/dist/examples/rag/rag-hyperdb.js +0 -1
- package/dist/examples/rag/rag-lancedb.js +0 -1
- package/dist/examples/rag/rag-sqlite.js +0 -1
- package/dist/examples/text-to-speech.d.ts +3 -0
- package/dist/examples/text-to-speech.js +137 -0
- package/dist/examples/translation/translation-indic.js +3 -1
- package/dist/examples/translation/translation-llm-context.js +0 -1
- package/dist/examples/translation/translation-llm.js +2 -2
- package/dist/examples/translation/translation-opus.js +3 -1
- package/dist/examples/translation/translation-stream.js +0 -1
- package/dist/examples/whispercpp-filesystem.js +32 -5
- package/dist/examples/whispercpp-microphone-record.js +9 -9
- package/dist/examples/whispercpp-prompt.d.ts +2 -0
- package/dist/examples/whispercpp-prompt.js +68 -0
- package/dist/expo/plugins/withMobileBundle.js +9 -3
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/dist/models/hyperdrive/models.d.ts +1916 -100
- package/dist/models/hyperdrive/models.js +2042 -102
- package/dist/schemas/common.d.ts +413 -58
- package/dist/schemas/common.js +9 -0
- package/dist/schemas/completion-stream.d.ts +26 -22
- package/dist/schemas/completion-stream.js +9 -23
- package/dist/schemas/download-asset.d.ts +77 -2
- package/dist/schemas/download-asset.js +15 -4
- package/dist/schemas/get-model-info.d.ts +100 -0
- package/dist/schemas/get-model-info.js +40 -0
- package/dist/schemas/index.d.ts +7 -0
- package/dist/schemas/index.js +7 -0
- package/dist/schemas/llamacpp-config.d.ts +2 -1
- package/dist/schemas/llamacpp-config.js +3 -4
- package/dist/schemas/load-model.d.ts +2316 -266
- package/dist/schemas/load-model.js +157 -10
- package/dist/schemas/model-src-utils.d.ts +98 -0
- package/dist/schemas/model-src-utils.js +31 -0
- package/dist/schemas/sdk-errors-client.d.ts +25 -0
- package/dist/schemas/sdk-errors-client.js +111 -0
- package/dist/schemas/sdk-errors-server.d.ts +55 -0
- package/dist/schemas/sdk-errors-server.js +271 -0
- package/dist/schemas/set-config.d.ts +21 -0
- package/dist/schemas/set-config.js +14 -0
- package/dist/schemas/text-to-speech.d.ts +34 -0
- package/dist/schemas/text-to-speech.js +25 -0
- package/dist/schemas/tools.d.ts +62 -0
- package/dist/schemas/tools.js +43 -0
- package/dist/schemas/transcription.d.ts +25 -2
- package/dist/schemas/transcription.js +12 -1
- package/dist/schemas/translation-config.d.ts +33 -5
- package/dist/schemas/translation-config.js +18 -1
- package/dist/schemas/unload-model.d.ts +2 -0
- package/dist/schemas/unload-model.js +2 -0
- package/dist/schemas/whispercpp-config.d.ts +55 -18
- package/dist/schemas/whispercpp-config.js +63 -15
- package/dist/server/bare/addons/cancel.js +2 -1
- package/dist/server/bare/addons/llamacpp/create-model.d.ts +9 -2
- package/dist/server/bare/addons/llamacpp/create-model.js +23 -23
- package/dist/server/bare/addons/llamacpp/handlers/completion-stream.d.ts +10 -2
- package/dist/server/bare/addons/llamacpp/handlers/completion-stream.js +62 -43
- package/dist/server/bare/addons/llamacpp/handlers/embed.js +3 -2
- package/dist/server/bare/addons/llamacpp/kv-cache-utils.d.ts +1 -1
- package/dist/server/bare/addons/llamacpp/kv-cache-utils.js +6 -2
- package/dist/server/bare/addons/load-model.js +59 -28
- package/dist/server/bare/addons/translation/create-model.d.ts +5 -1
- package/dist/server/bare/addons/translation/create-model.js +17 -25
- package/dist/server/bare/addons/translation/handlers/translate.js +10 -1
- package/dist/server/bare/addons/tts/create-model.d.ts +10 -0
- package/dist/server/bare/addons/tts/create-model.js +25 -0
- package/dist/server/bare/addons/tts/handlers/text-to-speech.d.ts +3 -0
- package/dist/server/bare/addons/tts/handlers/text-to-speech.js +87 -0
- package/dist/server/bare/addons/tts/index.d.ts +3 -0
- package/dist/server/bare/addons/tts/index.js +2 -0
- package/dist/server/bare/addons/unload-model.js +21 -3
- package/dist/server/bare/addons/whispercpp/create-model.d.ts +5 -1
- package/dist/server/bare/addons/whispercpp/create-model.js +13 -32
- package/dist/server/bare/addons/whispercpp/handlers/transcribe-stream.js +41 -20
- package/dist/server/bare/delegate-rpc-client.js +3 -2
- package/dist/server/bare/hyperswarm.d.ts +3 -0
- package/dist/server/bare/hyperswarm.js +22 -1
- package/dist/server/bare/rag-hyperdb/rag-manager.js +2 -3
- package/dist/server/bare/registry/config-registry.d.ts +5 -0
- package/dist/server/bare/registry/config-registry.js +39 -0
- package/dist/server/bare/registry/model-registry.d.ts +13 -0
- package/dist/server/bare/registry/model-registry.js +24 -7
- package/dist/server/rpc/handle-request.js +42 -3
- package/dist/server/rpc/handlers/completion-stream-delegated.js +2 -1
- package/dist/server/rpc/handlers/completion-stream.js +11 -4
- package/dist/server/rpc/handlers/download-asset.js +2 -3
- package/dist/server/rpc/handlers/get-model-info.d.ts +3 -0
- package/dist/server/rpc/handlers/get-model-info.js +148 -0
- package/dist/server/rpc/handlers/index.d.ts +4 -0
- package/dist/server/rpc/handlers/index.js +6 -0
- package/dist/server/rpc/handlers/load-model/http.js +51 -10
- package/dist/server/rpc/handlers/load-model/hyperdrive.js +336 -156
- package/dist/server/rpc/handlers/load-model/index.js +1 -1
- package/dist/server/rpc/handlers/load-model/resolve.d.ts +1 -1
- package/dist/server/rpc/handlers/load-model/resolve.js +10 -6
- package/dist/server/rpc/handlers/load-model-delegated.js +7 -4
- package/dist/server/rpc/handlers/load-model.js +19 -1
- package/dist/server/rpc/handlers/provideHandler/handler.js +2 -1
- package/dist/server/rpc/handlers/rag.js +0 -3
- package/dist/server/rpc/handlers/set-config.d.ts +3 -0
- package/dist/server/rpc/handlers/set-config.js +18 -0
- package/dist/server/rpc/handlers/stopProvideHandler.js +3 -1
- package/dist/server/rpc/handlers/text-to-speech.d.ts +3 -0
- package/dist/server/rpc/handlers/text-to-speech.js +7 -0
- package/dist/server/rpc/handlers/transcribe-stream.js +6 -2
- package/dist/server/rpc/handlers/unload-model.js +7 -0
- package/dist/server/utils/cache.d.ts +13 -8
- package/dist/server/utils/cache.js +69 -14
- package/dist/server/utils/checksum.d.ts +2 -0
- package/dist/server/utils/checksum.js +24 -0
- package/dist/server/utils/index.d.ts +2 -0
- package/dist/server/utils/index.js +2 -0
- package/dist/server/utils/shard-utils.d.ts +22 -0
- package/dist/server/utils/shard-utils.js +37 -0
- package/dist/server/utils/tool-integration.d.ts +13 -0
- package/dist/server/utils/tool-integration.js +43 -0
- package/dist/server/utils/tool-parser.d.ts +7 -0
- package/dist/server/utils/tool-parser.js +244 -0
- package/dist/utils/errors-base.d.ts +3 -0
- package/dist/utils/errors-base.js +13 -0
- package/dist/utils/errors-client.d.ts +107 -0
- package/dist/utils/errors-client.js +186 -0
- package/dist/utils/errors-server.d.ts +146 -0
- package/dist/utils/errors-server.js +253 -0
- package/dist/utils/tool-helpers.d.ts +17 -0
- package/dist/utils/tool-helpers.js +99 -0
- package/package.json +12 -8
- package/dist/examples/llamacpp-tools-routing.d.ts +0 -2
- package/dist/examples/llamacpp-tools-routing.js +0 -364
- package/dist/examples/llamacpp-tools.d.ts +0 -2
- package/dist/examples/llamacpp-tools.js +0 -81
- package/dist/server/http-server.d.ts +0 -2
- package/dist/server/http-server.js +0 -189
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { ModelAlreadyRegisteredError, ModelNotFoundError, ModelIsDelegatedError, } from "../../../utils/errors-server.js";
|
|
1
2
|
// Global registry state - using stateless functions to manage it
|
|
2
3
|
const modelRegistry = new Map();
|
|
3
4
|
export function registerModel(id, options) {
|
|
4
5
|
if (modelRegistry.has(id)) {
|
|
5
|
-
throw new
|
|
6
|
+
throw new ModelAlreadyRegisteredError(id);
|
|
6
7
|
}
|
|
7
8
|
const isDelegated = "topic" in options && "providerPublicKey" in options;
|
|
8
9
|
if (isDelegated) {
|
|
@@ -27,9 +28,12 @@ export function registerModel(id, options) {
|
|
|
27
28
|
path: options.path,
|
|
28
29
|
loadedAt: new Date(),
|
|
29
30
|
config: options.config,
|
|
31
|
+
loader: options.loader,
|
|
32
|
+
name: options.name,
|
|
30
33
|
},
|
|
31
34
|
});
|
|
32
|
-
|
|
35
|
+
const nameStr = options.name ? ` (${options.name})` : "";
|
|
36
|
+
console.log(`Local model registered: ${id}${nameStr} -> ${options.path}`);
|
|
33
37
|
}
|
|
34
38
|
}
|
|
35
39
|
export function getModelEntry(id) {
|
|
@@ -38,11 +42,10 @@ export function getModelEntry(id) {
|
|
|
38
42
|
export function getModel(id) {
|
|
39
43
|
const entry = modelRegistry.get(id);
|
|
40
44
|
if (!entry) {
|
|
41
|
-
|
|
42
|
-
throw new Error(`Model with ID "${id}" not found in registry. Available models: ${availableIds.join(", ")}`);
|
|
45
|
+
throw new ModelNotFoundError(id);
|
|
43
46
|
}
|
|
44
47
|
if (!entry.local) {
|
|
45
|
-
throw new
|
|
48
|
+
throw new ModelIsDelegatedError(id);
|
|
46
49
|
}
|
|
47
50
|
return entry.local.model;
|
|
48
51
|
}
|
|
@@ -66,20 +69,34 @@ export function getModelInfo(id) {
|
|
|
66
69
|
if (!entry || !entry.local) {
|
|
67
70
|
return null;
|
|
68
71
|
}
|
|
69
|
-
|
|
72
|
+
const result = {
|
|
70
73
|
id: entry.id,
|
|
71
74
|
path: entry.local.path,
|
|
72
75
|
loadedAt: entry.local.loadedAt,
|
|
73
76
|
config: entry.local.config,
|
|
74
77
|
};
|
|
78
|
+
if (entry.local.name) {
|
|
79
|
+
result.name = entry.local.name;
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
75
82
|
}
|
|
76
83
|
export function getModelConfig(id) {
|
|
77
84
|
const entry = modelRegistry.get(id);
|
|
78
85
|
if (!entry || !entry.local) {
|
|
79
|
-
throw new
|
|
86
|
+
throw new ModelNotFoundError(id);
|
|
80
87
|
}
|
|
81
88
|
return entry.local.config;
|
|
82
89
|
}
|
|
90
|
+
export function updateModelConfig(id, config) {
|
|
91
|
+
const entry = modelRegistry.get(id);
|
|
92
|
+
if (!entry) {
|
|
93
|
+
throw new ModelNotFoundError(id);
|
|
94
|
+
}
|
|
95
|
+
if (!entry.local) {
|
|
96
|
+
throw new ModelIsDelegatedError(id);
|
|
97
|
+
}
|
|
98
|
+
entry.local.config = config;
|
|
99
|
+
}
|
|
83
100
|
export function clearRegistry() {
|
|
84
101
|
modelRegistry.clear();
|
|
85
102
|
console.log("Model registry cleared");
|
|
@@ -15,12 +15,16 @@ import { provideHandler } from "./handlers/provideHandler.js";
|
|
|
15
15
|
import { stopProvideHandler } from "./handlers/stopProvideHandler.js";
|
|
16
16
|
import { handleRag } from "./handlers/rag.js";
|
|
17
17
|
import { handleDeleteCache } from "./handlers/delete-cache.js";
|
|
18
|
-
import {
|
|
18
|
+
import { handleTextToSpeech } from "./handlers/text-to-speech.js";
|
|
19
|
+
import { handleSetConfig } from "./handlers/set-config.js";
|
|
20
|
+
import { handleGetModelInfo } from "./handlers/get-model-info.js";
|
|
21
|
+
import { sendErrorResponse, sendStreamErrorResponse, } from "../error-handlers.js";
|
|
22
|
+
import { NoDataReceivedError, UnknownRequestTypeError, } from "../../utils/errors-client.js";
|
|
19
23
|
export async function handleRequest(req) {
|
|
20
24
|
try {
|
|
21
25
|
const rawData = req.data?.toString();
|
|
22
26
|
if (!rawData) {
|
|
23
|
-
throw new
|
|
27
|
+
throw new NoDataReceivedError();
|
|
24
28
|
}
|
|
25
29
|
const jsonData = JSON.parse(rawData);
|
|
26
30
|
const request = requestSchema.parse(jsonData);
|
|
@@ -226,8 +230,43 @@ export async function handleRequest(req) {
|
|
|
226
230
|
}
|
|
227
231
|
break;
|
|
228
232
|
}
|
|
233
|
+
case "textToSpeech": {
|
|
234
|
+
const stream = req.createResponseStream();
|
|
235
|
+
try {
|
|
236
|
+
for await (const response of handleTextToSpeech(request)) {
|
|
237
|
+
const validatedResponse = responseSchema.parse(response);
|
|
238
|
+
const data = JSON.stringify(validatedResponse);
|
|
239
|
+
stream.write(data + "\n", "utf-8");
|
|
240
|
+
}
|
|
241
|
+
stream.end();
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
sendStreamErrorResponse(stream, error);
|
|
245
|
+
}
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
case "setConfig": {
|
|
249
|
+
try {
|
|
250
|
+
const response = handleSetConfig(request);
|
|
251
|
+
req.reply(JSON.stringify(responseSchema.parse(response)), "utf-8");
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
sendErrorResponse(req, error);
|
|
255
|
+
}
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
case "getModelInfo": {
|
|
259
|
+
try {
|
|
260
|
+
const response = await handleGetModelInfo(request);
|
|
261
|
+
req.reply(JSON.stringify(responseSchema.parse(response)), "utf-8");
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
sendErrorResponse(req, error);
|
|
265
|
+
}
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
229
268
|
default: {
|
|
230
|
-
throw new
|
|
269
|
+
throw new UnknownRequestTypeError();
|
|
231
270
|
}
|
|
232
271
|
}
|
|
233
272
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { getModelEntry } from "../../bare/registry/model-registry.js";
|
|
2
2
|
import { getRPC } from "../../bare/delegate-rpc-client.js";
|
|
3
3
|
import { stream } from "../../../client/rpc/rpc-client.js";
|
|
4
|
+
import { ModelIsDelegatedError } from "../../../utils/errors-server.js";
|
|
4
5
|
export async function* handleCompletionStreamDelegated(request) {
|
|
5
6
|
// Get delegation info from model registry
|
|
6
7
|
const entry = getModelEntry(request.modelId);
|
|
7
8
|
if (!entry?.isDelegated || !entry.delegated) {
|
|
8
|
-
throw new
|
|
9
|
+
throw new ModelIsDelegatedError(request.modelId);
|
|
9
10
|
}
|
|
10
11
|
const { topic, providerPublicKey, timeout } = entry.delegated;
|
|
11
12
|
try {
|
|
@@ -9,30 +9,37 @@ export async function* handleCompletionStream(request) {
|
|
|
9
9
|
history: filteredHistory,
|
|
10
10
|
modelId: request.modelId,
|
|
11
11
|
kvCache: request.kvCache,
|
|
12
|
+
...(request.tools && { tools: request.tools }),
|
|
12
13
|
});
|
|
13
14
|
let stats;
|
|
15
|
+
let toolCalls = [];
|
|
14
16
|
let done = false;
|
|
15
17
|
let buffer = "";
|
|
16
18
|
while (!done) {
|
|
17
19
|
const result = await stream.next();
|
|
18
20
|
if (result.done) {
|
|
19
|
-
stats = result.value;
|
|
21
|
+
stats = result.value.stats;
|
|
22
|
+
toolCalls = result.value.toolCalls;
|
|
20
23
|
done = true;
|
|
21
24
|
}
|
|
22
25
|
else {
|
|
23
|
-
buffer += result.value;
|
|
24
26
|
if (request.stream) {
|
|
25
27
|
yield {
|
|
26
28
|
type: "completionStream",
|
|
27
|
-
token: result.value,
|
|
29
|
+
token: result.value.token,
|
|
30
|
+
toolCallEvent: result.value.toolCallEvent,
|
|
28
31
|
};
|
|
29
32
|
}
|
|
33
|
+
else {
|
|
34
|
+
buffer += result.value.token;
|
|
35
|
+
}
|
|
30
36
|
}
|
|
31
37
|
}
|
|
32
38
|
yield {
|
|
33
39
|
type: "completionStream",
|
|
34
|
-
token: buffer,
|
|
40
|
+
token: request.stream ? "" : buffer,
|
|
35
41
|
done: true,
|
|
36
42
|
stats,
|
|
43
|
+
toolCalls,
|
|
37
44
|
};
|
|
38
45
|
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { resolveModelPath } from "./load-model/resolve.js";
|
|
2
|
-
import path from "bare-path";
|
|
3
2
|
export async function handleDownloadAsset(request, progressCallback) {
|
|
4
3
|
const { assetSrc, seed } = request;
|
|
5
4
|
try {
|
|
6
|
-
|
|
5
|
+
await resolveModelPath(assetSrc, progressCallback, seed);
|
|
7
6
|
return {
|
|
8
7
|
type: "downloadAsset",
|
|
9
8
|
success: true,
|
|
10
|
-
assetId:
|
|
9
|
+
assetId: assetSrc,
|
|
11
10
|
};
|
|
12
11
|
}
|
|
13
12
|
catch (error) {
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { models } from "../../../models/hyperdrive/models.js";
|
|
2
|
+
import { getAllModelIds, getModelEntry, } from "../../bare/registry/model-registry.js";
|
|
3
|
+
import { getConfiguredCacheDir } from "../../bare/registry/config-registry.js";
|
|
4
|
+
import { generateShortHash } from "../../utils/index.js";
|
|
5
|
+
import { promises as fsPromises } from "bare-fs";
|
|
6
|
+
import path from "bare-path";
|
|
7
|
+
import { getShardPath } from "../../utils/cache.js";
|
|
8
|
+
import { ModelNotFoundError } from "../../../utils/errors-server.js";
|
|
9
|
+
export const handleGetModelInfo = async (request) => {
|
|
10
|
+
const { name } = request;
|
|
11
|
+
const catalogEntry = models.find((m) => m.name === name);
|
|
12
|
+
if (!catalogEntry) {
|
|
13
|
+
throw new ModelNotFoundError(`${name}" not found in catalog. Use model names from the catalog (e.g., "WHISPER_TINY", "EMBEDDINGGEMMA_300M_Q4_0")`);
|
|
14
|
+
}
|
|
15
|
+
const cacheStatus = catalogEntry.shardMetadata && catalogEntry.shardMetadata.length > 0
|
|
16
|
+
? await handleShardedModel(catalogEntry.hyperdriveKey, catalogEntry.shardMetadata)
|
|
17
|
+
: await handleSingleFileModel(catalogEntry.hyperdriveKey, catalogEntry.modelId, catalogEntry.expectedSize, catalogEntry.sha256Checksum);
|
|
18
|
+
const { cacheFiles, isCached, actualSize, cachedAt } = cacheStatus;
|
|
19
|
+
const loadedModelIds = getAllModelIds();
|
|
20
|
+
const loadedInstances = [];
|
|
21
|
+
for (const id of loadedModelIds) {
|
|
22
|
+
const entry = getModelEntry(id);
|
|
23
|
+
if (!entry?.local)
|
|
24
|
+
continue;
|
|
25
|
+
const matchesByName = entry.local.name && entry.local.name === name;
|
|
26
|
+
const matchesByPath = cacheFiles.length > 0 && entry.local.path === cacheFiles[0]?.path;
|
|
27
|
+
if (matchesByName || matchesByPath) {
|
|
28
|
+
const instance = {
|
|
29
|
+
registryId: id,
|
|
30
|
+
loadedAt: entry.local.loadedAt,
|
|
31
|
+
config: entry.local.config,
|
|
32
|
+
};
|
|
33
|
+
loadedInstances.push(instance);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const isLoaded = loadedInstances.length > 0;
|
|
37
|
+
const modelInfo = {
|
|
38
|
+
name: catalogEntry.name,
|
|
39
|
+
modelId: catalogEntry.modelId,
|
|
40
|
+
hyperdriveKey: catalogEntry.hyperdriveKey,
|
|
41
|
+
hyperbeeKey: catalogEntry.hyperbeeKey,
|
|
42
|
+
expectedSize: catalogEntry.expectedSize,
|
|
43
|
+
sha256Checksum: catalogEntry.sha256Checksum,
|
|
44
|
+
addon: catalogEntry.addon,
|
|
45
|
+
isCached,
|
|
46
|
+
isLoaded,
|
|
47
|
+
cacheFiles,
|
|
48
|
+
actualSize,
|
|
49
|
+
cachedAt,
|
|
50
|
+
loadedInstances: loadedInstances.length > 0 ? loadedInstances : undefined,
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
type: "getModelInfo",
|
|
54
|
+
modelInfo,
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
async function handleShardedModel(hyperdriveKey, shardMetadata) {
|
|
58
|
+
const cacheFiles = [];
|
|
59
|
+
let allShardsCached = true;
|
|
60
|
+
let totalActualSize = 0;
|
|
61
|
+
let latestCachedAt;
|
|
62
|
+
for (const shard of shardMetadata) {
|
|
63
|
+
const shardPath = getShardPath(hyperdriveKey, shard.filename);
|
|
64
|
+
let shardIsCached = false;
|
|
65
|
+
let shardActualSize;
|
|
66
|
+
let shardCachedAt;
|
|
67
|
+
try {
|
|
68
|
+
const stats = await fsPromises.stat(shardPath);
|
|
69
|
+
shardIsCached = stats.isFile();
|
|
70
|
+
if (shardIsCached) {
|
|
71
|
+
shardActualSize = stats.size;
|
|
72
|
+
shardCachedAt = stats.mtime;
|
|
73
|
+
totalActualSize += stats.size;
|
|
74
|
+
if (!latestCachedAt || stats.mtime > latestCachedAt) {
|
|
75
|
+
latestCachedAt = stats.mtime;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
allShardsCached = false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
shardIsCached = false;
|
|
84
|
+
allShardsCached = false;
|
|
85
|
+
}
|
|
86
|
+
cacheFiles.push({
|
|
87
|
+
filename: shard.filename,
|
|
88
|
+
path: shardPath,
|
|
89
|
+
expectedSize: shard.expectedSize,
|
|
90
|
+
sha256Checksum: shard.sha256Checksum,
|
|
91
|
+
isCached: shardIsCached,
|
|
92
|
+
actualSize: shardActualSize,
|
|
93
|
+
cachedAt: shardCachedAt,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const result = {
|
|
97
|
+
cacheFiles,
|
|
98
|
+
isCached: allShardsCached,
|
|
99
|
+
};
|
|
100
|
+
if (allShardsCached) {
|
|
101
|
+
result.actualSize = totalActualSize;
|
|
102
|
+
if (latestCachedAt) {
|
|
103
|
+
result.cachedAt = latestCachedAt;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
async function handleSingleFileModel(hyperdriveKey, modelId, expectedSize, sha256Checksum) {
|
|
109
|
+
const cacheDir = getConfiguredCacheDir();
|
|
110
|
+
const sourceHash = generateShortHash(`${hyperdriveKey}/${modelId}`);
|
|
111
|
+
const filePath = path.join(cacheDir, `${sourceHash}_${modelId}`);
|
|
112
|
+
let fileIsCached = false;
|
|
113
|
+
let fileActualSize;
|
|
114
|
+
let fileCachedAt;
|
|
115
|
+
try {
|
|
116
|
+
const stats = await fsPromises.stat(filePath);
|
|
117
|
+
fileIsCached = stats.isFile();
|
|
118
|
+
if (fileIsCached) {
|
|
119
|
+
fileActualSize = stats.size;
|
|
120
|
+
fileCachedAt = stats.mtime;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
fileIsCached = false;
|
|
125
|
+
}
|
|
126
|
+
const cacheFiles = [
|
|
127
|
+
{
|
|
128
|
+
filename: modelId,
|
|
129
|
+
path: filePath,
|
|
130
|
+
expectedSize,
|
|
131
|
+
sha256Checksum,
|
|
132
|
+
isCached: fileIsCached,
|
|
133
|
+
actualSize: fileActualSize,
|
|
134
|
+
cachedAt: fileCachedAt,
|
|
135
|
+
},
|
|
136
|
+
];
|
|
137
|
+
const result = {
|
|
138
|
+
cacheFiles,
|
|
139
|
+
isCached: fileIsCached,
|
|
140
|
+
};
|
|
141
|
+
if (fileActualSize !== undefined) {
|
|
142
|
+
result.actualSize = fileActualSize;
|
|
143
|
+
}
|
|
144
|
+
if (fileCachedAt !== undefined) {
|
|
145
|
+
result.cachedAt = fileCachedAt;
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
@@ -11,6 +11,7 @@ import { handleLoggingStream } from "./logging-stream";
|
|
|
11
11
|
import { handleRag } from "./rag";
|
|
12
12
|
import { cancelHandler } from "./cancelHandler";
|
|
13
13
|
import { handleDeleteCache } from "./delete-cache";
|
|
14
|
+
import { handleTextToSpeech } from "./text-to-speech";
|
|
14
15
|
export declare const handlers: {
|
|
15
16
|
completionStream: typeof handleCompletionStream;
|
|
16
17
|
downloadAsset: typeof handleDownloadAsset;
|
|
@@ -25,5 +26,8 @@ export declare const handlers: {
|
|
|
25
26
|
loggingStream: typeof handleLoggingStream;
|
|
26
27
|
rag: typeof handleRag;
|
|
27
28
|
cancel: typeof cancelHandler;
|
|
29
|
+
textToSpeech: typeof handleTextToSpeech;
|
|
30
|
+
setConfig: (request: import("../../../schemas").SetConfigRequest) => import("../../../schemas").SetConfigResponse;
|
|
31
|
+
getModelInfo: (request: import("../../../schemas").GetModelInfoRequest) => Promise<import("../../../schemas").GetModelInfoResponse>;
|
|
28
32
|
};
|
|
29
33
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -11,6 +11,9 @@ import { handleLoggingStream } from "./logging-stream.js";
|
|
|
11
11
|
import { handleRag } from "./rag.js";
|
|
12
12
|
import { cancelHandler } from "./cancelHandler.js";
|
|
13
13
|
import { handleDeleteCache } from "./delete-cache.js";
|
|
14
|
+
import { handleTextToSpeech } from "./text-to-speech.js";
|
|
15
|
+
import { handleSetConfig } from "./set-config.js";
|
|
16
|
+
import { handleGetModelInfo } from "./get-model-info.js";
|
|
14
17
|
export const handlers = {
|
|
15
18
|
completionStream: handleCompletionStream,
|
|
16
19
|
downloadAsset: handleDownloadAsset,
|
|
@@ -25,4 +28,7 @@ export const handlers = {
|
|
|
25
28
|
loggingStream: handleLoggingStream,
|
|
26
29
|
rag: handleRag,
|
|
27
30
|
cancel: cancelHandler,
|
|
31
|
+
textToSpeech: handleTextToSpeech,
|
|
32
|
+
setConfig: handleSetConfig,
|
|
33
|
+
getModelInfo: handleGetModelInfo,
|
|
28
34
|
};
|
|
@@ -4,6 +4,7 @@ import fetch from "bare-fetch";
|
|
|
4
4
|
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
|
+
import { DownloadCancelledError, HTTPError, NoResponseBodyError, ResponseBodyNotReadableError, } from "../../../../utils/errors-server.js";
|
|
7
8
|
function extractFilenameFromUrl(url) {
|
|
8
9
|
// Parse URL to get the filename from the path
|
|
9
10
|
const urlParts = url.split("/");
|
|
@@ -27,11 +28,10 @@ async function validateCachedFile(modelPath, url, signal) {
|
|
|
27
28
|
expectedSize = parseInt(response.headers.get("content-length") || "0");
|
|
28
29
|
}
|
|
29
30
|
catch (error) {
|
|
30
|
-
console.log(`⚠️ Could not get expected file size from HEAD request: ${String(error)}`);
|
|
31
|
-
|
|
32
|
-
return modelPath;
|
|
31
|
+
console.log(`⚠️ Could not get expected file size from HEAD request, will re-download: ${String(error)}`);
|
|
32
|
+
return null;
|
|
33
33
|
}
|
|
34
|
-
if (
|
|
34
|
+
if (localSize !== expectedSize) {
|
|
35
35
|
console.log(`📥 Cached file size mismatch. Expected: ${expectedSize}, Found: ${localSize}. Re-downloading...`);
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
@@ -45,7 +45,7 @@ async function validateCachedFile(modelPath, url, signal) {
|
|
|
45
45
|
}
|
|
46
46
|
async function performHttpDownload(url, modelPath, downloadKey, progressCallback, signal) {
|
|
47
47
|
if (signal?.aborted) {
|
|
48
|
-
throw new
|
|
48
|
+
throw new DownloadCancelledError();
|
|
49
49
|
}
|
|
50
50
|
console.log(`📥 Downloading model from HTTP: ${url}`);
|
|
51
51
|
// Check if file exists for resuming
|
|
@@ -78,6 +78,16 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
78
78
|
// Check if it's a 416 (Range Not Satisfiable) - file already complete
|
|
79
79
|
if (response.status === 416 && startOffset > 0) {
|
|
80
80
|
console.log(`✅ File already completely downloaded`);
|
|
81
|
+
// Send 100% progress for already complete file
|
|
82
|
+
if (progressCallback) {
|
|
83
|
+
progressCallback({
|
|
84
|
+
type: "modelProgress",
|
|
85
|
+
downloaded: startOffset,
|
|
86
|
+
total: startOffset,
|
|
87
|
+
percentage: 100,
|
|
88
|
+
downloadKey,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
81
91
|
return;
|
|
82
92
|
}
|
|
83
93
|
// Check if server doesn't support range requests
|
|
@@ -94,14 +104,14 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
94
104
|
...(signal && { signal }),
|
|
95
105
|
});
|
|
96
106
|
if (!freshResponse.ok) {
|
|
97
|
-
throw new
|
|
107
|
+
throw new HTTPError(freshResponse.status, freshResponse.statusText);
|
|
98
108
|
}
|
|
99
109
|
// Use the fresh response
|
|
100
110
|
Object.assign(response, freshResponse);
|
|
101
111
|
}
|
|
102
112
|
else if (response.status !== 206) {
|
|
103
113
|
// 206 is Partial Content (successful resume)
|
|
104
|
-
throw new
|
|
114
|
+
throw new HTTPError(response.status, response.statusText);
|
|
105
115
|
}
|
|
106
116
|
}
|
|
107
117
|
// Get total size from headers
|
|
@@ -128,7 +138,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
128
138
|
// Get the response body
|
|
129
139
|
const body = response.body;
|
|
130
140
|
if (!body) {
|
|
131
|
-
throw new
|
|
141
|
+
throw new NoResponseBodyError();
|
|
132
142
|
}
|
|
133
143
|
try {
|
|
134
144
|
// Check if body has pipe method (it's a Node/Bare stream)
|
|
@@ -180,7 +190,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
180
190
|
// Check if abort signal is triggered
|
|
181
191
|
if (signal && signal.aborted) {
|
|
182
192
|
writeStream.destroy();
|
|
183
|
-
throw new
|
|
193
|
+
throw new DownloadCancelledError();
|
|
184
194
|
}
|
|
185
195
|
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
186
196
|
downloadedBytes += buffer.length;
|
|
@@ -259,7 +269,7 @@ async function performHttpDownload(url, modelPath, downloadKey, progressCallback
|
|
|
259
269
|
});
|
|
260
270
|
}
|
|
261
271
|
else {
|
|
262
|
-
throw new
|
|
272
|
+
throw new ResponseBodyNotReadableError();
|
|
263
273
|
}
|
|
264
274
|
}
|
|
265
275
|
}
|
|
@@ -288,10 +298,41 @@ export async function downloadModelFromHttp(url, progressCallback) {
|
|
|
288
298
|
// Check if already cached
|
|
289
299
|
const cachedPath = await validateCachedFile(modelPath, url, abortController.signal);
|
|
290
300
|
if (cachedPath) {
|
|
301
|
+
if (progressCallback) {
|
|
302
|
+
try {
|
|
303
|
+
const stats = await fsPromises.stat(cachedPath);
|
|
304
|
+
progressCallback({
|
|
305
|
+
type: "modelProgress",
|
|
306
|
+
downloaded: stats.size,
|
|
307
|
+
total: stats.size,
|
|
308
|
+
percentage: 100,
|
|
309
|
+
downloadKey,
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
// Ignore stat errors, file exists but might not be readable
|
|
314
|
+
}
|
|
315
|
+
}
|
|
291
316
|
return cachedPath;
|
|
292
317
|
}
|
|
293
318
|
// Download the file
|
|
294
319
|
await performHttpDownload(url, modelPath, downloadKey, progressCallback, abortController.signal);
|
|
320
|
+
// Send final 100% progress update
|
|
321
|
+
if (progressCallback) {
|
|
322
|
+
try {
|
|
323
|
+
const stats = await fsPromises.stat(modelPath);
|
|
324
|
+
progressCallback({
|
|
325
|
+
type: "modelProgress",
|
|
326
|
+
downloaded: stats.size,
|
|
327
|
+
total: stats.size,
|
|
328
|
+
percentage: 100,
|
|
329
|
+
downloadKey,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// Ignore stat errors
|
|
334
|
+
}
|
|
335
|
+
}
|
|
295
336
|
return modelPath;
|
|
296
337
|
}
|
|
297
338
|
catch (error) {
|