@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.
Files changed (207) hide show
  1. package/README.md +22 -0
  2. package/dist/client/api/cancel.d.ts +1 -1
  3. package/dist/client/api/cancel.js +4 -3
  4. package/dist/client/api/completion-stream.d.ts +24 -32
  5. package/dist/client/api/completion-stream.js +142 -50
  6. package/dist/client/api/delete-cache.js +3 -2
  7. package/dist/client/api/download-asset.d.ts +3 -3
  8. package/dist/client/api/download-asset.js +12 -17
  9. package/dist/client/api/embed.d.ts +1 -1
  10. package/dist/client/api/embed.js +4 -3
  11. package/dist/client/api/get-model-info.d.ts +29 -0
  12. package/dist/client/api/get-model-info.js +14 -0
  13. package/dist/client/api/index.d.ts +3 -0
  14. package/dist/client/api/index.js +3 -0
  15. package/dist/client/api/load-model.d.ts +3 -3
  16. package/dist/client/api/load-model.js +13 -22
  17. package/dist/client/api/logging-stream.d.ts +1 -1
  18. package/dist/client/api/logging-stream.js +3 -2
  19. package/dist/client/api/ping.d.ts +1 -1
  20. package/dist/client/api/ping.js +3 -2
  21. package/dist/client/api/provide.d.ts +1 -1
  22. package/dist/client/api/provide.js +4 -3
  23. package/dist/client/api/rag.d.ts +3 -3
  24. package/dist/client/api/rag.js +13 -12
  25. package/dist/client/api/set-config.d.ts +7 -0
  26. package/dist/client/api/set-config.js +20 -0
  27. package/dist/client/api/stop-provider.d.ts +1 -1
  28. package/dist/client/api/stop-provider.js +4 -3
  29. package/dist/client/api/text-to-speech.d.ts +7 -0
  30. package/dist/client/api/text-to-speech.js +58 -0
  31. package/dist/client/api/transcribe.d.ts +4 -2
  32. package/dist/client/api/transcribe.js +9 -5
  33. package/dist/client/api/translate.d.ts +1 -1
  34. package/dist/client/api/translate.js +3 -2
  35. package/dist/client/api/unload-model.d.ts +5 -1
  36. package/dist/client/api/unload-model.js +14 -4
  37. package/dist/client/config-manager.d.ts +4 -0
  38. package/dist/client/config-manager.js +8 -0
  39. package/dist/client/index.d.ts +1 -1
  40. package/dist/client/index.js +1 -1
  41. package/dist/client/init-hooks.d.ts +6 -0
  42. package/dist/client/init-hooks.js +37 -0
  43. package/dist/client/rpc/bare-client.d.ts +69 -0
  44. package/dist/client/rpc/bare-client.js +5 -4
  45. package/dist/client/rpc/bare-rpc-client.js +7 -3
  46. package/dist/client/rpc/expo-rpc-client.d.ts +1 -0
  47. package/dist/client/rpc/expo-rpc-client.js +9 -1
  48. package/dist/client/rpc/node-rpc-client.d.ts +1 -1
  49. package/dist/client/rpc/node-rpc-client.js +22 -9
  50. package/dist/client/rpc/rpc-client.d.ts +1 -0
  51. package/dist/client/rpc/rpc-client.js +20 -1
  52. package/dist/examples/cache-management.d.ts +2 -0
  53. package/dist/examples/cache-management.js +97 -0
  54. package/dist/examples/delegated-inference/consumer.js +2 -2
  55. package/dist/examples/download-with-blind-relays.d.ts +2 -0
  56. package/dist/examples/download-with-blind-relays.js +48 -0
  57. package/dist/examples/download-with-cancel.js +3 -4
  58. package/dist/examples/embed-hyperdrive.js +0 -1
  59. package/dist/examples/kv-cache-cleanup.js +0 -1
  60. package/dist/examples/kv-cache-custom-key.js +0 -1
  61. package/dist/examples/kv-cache-example.js +0 -1
  62. package/dist/examples/llamacpp-file-logging.js +0 -1
  63. package/dist/examples/llamacpp-filesystem.js +2 -2
  64. package/dist/examples/llamacpp-http.js +0 -1
  65. package/dist/examples/llamacpp-hyperdrive.js +0 -1
  66. package/dist/examples/llamacpp-multimodal.js +0 -1
  67. package/dist/examples/llamacpp-native-tools.js +118 -36
  68. package/dist/examples/llamacpp-sharded.d.ts +2 -0
  69. package/dist/examples/llamacpp-sharded.js +44 -0
  70. package/dist/examples/multi-model-demo.js +0 -1
  71. package/dist/examples/parallel-download.js +2 -2
  72. package/dist/examples/rag/rag-chromadb.js +0 -1
  73. package/dist/examples/rag/rag-hyperdb-workspaces.js +0 -1
  74. package/dist/examples/rag/rag-hyperdb.js +0 -1
  75. package/dist/examples/rag/rag-lancedb.js +0 -1
  76. package/dist/examples/rag/rag-sqlite.js +0 -1
  77. package/dist/examples/text-to-speech.d.ts +3 -0
  78. package/dist/examples/text-to-speech.js +137 -0
  79. package/dist/examples/translation/translation-indic.js +3 -1
  80. package/dist/examples/translation/translation-llm-context.js +0 -1
  81. package/dist/examples/translation/translation-llm.js +2 -2
  82. package/dist/examples/translation/translation-opus.js +3 -1
  83. package/dist/examples/translation/translation-stream.js +0 -1
  84. package/dist/examples/whispercpp-filesystem.js +32 -5
  85. package/dist/examples/whispercpp-microphone-record.js +9 -9
  86. package/dist/examples/whispercpp-prompt.d.ts +2 -0
  87. package/dist/examples/whispercpp-prompt.js +68 -0
  88. package/dist/expo/plugins/withMobileBundle.js +9 -3
  89. package/dist/index.d.ts +4 -2
  90. package/dist/index.js +4 -2
  91. package/dist/models/hyperdrive/models.d.ts +1916 -100
  92. package/dist/models/hyperdrive/models.js +2042 -102
  93. package/dist/schemas/common.d.ts +413 -58
  94. package/dist/schemas/common.js +9 -0
  95. package/dist/schemas/completion-stream.d.ts +26 -22
  96. package/dist/schemas/completion-stream.js +9 -23
  97. package/dist/schemas/download-asset.d.ts +77 -2
  98. package/dist/schemas/download-asset.js +15 -4
  99. package/dist/schemas/get-model-info.d.ts +100 -0
  100. package/dist/schemas/get-model-info.js +40 -0
  101. package/dist/schemas/index.d.ts +7 -0
  102. package/dist/schemas/index.js +7 -0
  103. package/dist/schemas/llamacpp-config.d.ts +2 -1
  104. package/dist/schemas/llamacpp-config.js +3 -4
  105. package/dist/schemas/load-model.d.ts +2316 -266
  106. package/dist/schemas/load-model.js +157 -10
  107. package/dist/schemas/model-src-utils.d.ts +98 -0
  108. package/dist/schemas/model-src-utils.js +31 -0
  109. package/dist/schemas/sdk-errors-client.d.ts +25 -0
  110. package/dist/schemas/sdk-errors-client.js +111 -0
  111. package/dist/schemas/sdk-errors-server.d.ts +55 -0
  112. package/dist/schemas/sdk-errors-server.js +271 -0
  113. package/dist/schemas/set-config.d.ts +21 -0
  114. package/dist/schemas/set-config.js +14 -0
  115. package/dist/schemas/text-to-speech.d.ts +34 -0
  116. package/dist/schemas/text-to-speech.js +25 -0
  117. package/dist/schemas/tools.d.ts +62 -0
  118. package/dist/schemas/tools.js +43 -0
  119. package/dist/schemas/transcription.d.ts +25 -2
  120. package/dist/schemas/transcription.js +12 -1
  121. package/dist/schemas/translation-config.d.ts +33 -5
  122. package/dist/schemas/translation-config.js +18 -1
  123. package/dist/schemas/unload-model.d.ts +2 -0
  124. package/dist/schemas/unload-model.js +2 -0
  125. package/dist/schemas/whispercpp-config.d.ts +55 -18
  126. package/dist/schemas/whispercpp-config.js +63 -15
  127. package/dist/server/bare/addons/cancel.js +2 -1
  128. package/dist/server/bare/addons/llamacpp/create-model.d.ts +9 -2
  129. package/dist/server/bare/addons/llamacpp/create-model.js +23 -23
  130. package/dist/server/bare/addons/llamacpp/handlers/completion-stream.d.ts +10 -2
  131. package/dist/server/bare/addons/llamacpp/handlers/completion-stream.js +62 -43
  132. package/dist/server/bare/addons/llamacpp/handlers/embed.js +3 -2
  133. package/dist/server/bare/addons/llamacpp/kv-cache-utils.d.ts +1 -1
  134. package/dist/server/bare/addons/llamacpp/kv-cache-utils.js +6 -2
  135. package/dist/server/bare/addons/load-model.js +59 -28
  136. package/dist/server/bare/addons/translation/create-model.d.ts +5 -1
  137. package/dist/server/bare/addons/translation/create-model.js +17 -25
  138. package/dist/server/bare/addons/translation/handlers/translate.js +10 -1
  139. package/dist/server/bare/addons/tts/create-model.d.ts +10 -0
  140. package/dist/server/bare/addons/tts/create-model.js +25 -0
  141. package/dist/server/bare/addons/tts/handlers/text-to-speech.d.ts +3 -0
  142. package/dist/server/bare/addons/tts/handlers/text-to-speech.js +87 -0
  143. package/dist/server/bare/addons/tts/index.d.ts +3 -0
  144. package/dist/server/bare/addons/tts/index.js +2 -0
  145. package/dist/server/bare/addons/unload-model.js +21 -3
  146. package/dist/server/bare/addons/whispercpp/create-model.d.ts +5 -1
  147. package/dist/server/bare/addons/whispercpp/create-model.js +13 -32
  148. package/dist/server/bare/addons/whispercpp/handlers/transcribe-stream.js +41 -20
  149. package/dist/server/bare/delegate-rpc-client.js +3 -2
  150. package/dist/server/bare/hyperswarm.d.ts +3 -0
  151. package/dist/server/bare/hyperswarm.js +22 -1
  152. package/dist/server/bare/rag-hyperdb/rag-manager.js +2 -3
  153. package/dist/server/bare/registry/config-registry.d.ts +5 -0
  154. package/dist/server/bare/registry/config-registry.js +39 -0
  155. package/dist/server/bare/registry/model-registry.d.ts +13 -0
  156. package/dist/server/bare/registry/model-registry.js +24 -7
  157. package/dist/server/rpc/handle-request.js +42 -3
  158. package/dist/server/rpc/handlers/completion-stream-delegated.js +2 -1
  159. package/dist/server/rpc/handlers/completion-stream.js +11 -4
  160. package/dist/server/rpc/handlers/download-asset.js +2 -3
  161. package/dist/server/rpc/handlers/get-model-info.d.ts +3 -0
  162. package/dist/server/rpc/handlers/get-model-info.js +148 -0
  163. package/dist/server/rpc/handlers/index.d.ts +4 -0
  164. package/dist/server/rpc/handlers/index.js +6 -0
  165. package/dist/server/rpc/handlers/load-model/http.js +51 -10
  166. package/dist/server/rpc/handlers/load-model/hyperdrive.js +336 -156
  167. package/dist/server/rpc/handlers/load-model/index.js +1 -1
  168. package/dist/server/rpc/handlers/load-model/resolve.d.ts +1 -1
  169. package/dist/server/rpc/handlers/load-model/resolve.js +10 -6
  170. package/dist/server/rpc/handlers/load-model-delegated.js +7 -4
  171. package/dist/server/rpc/handlers/load-model.js +19 -1
  172. package/dist/server/rpc/handlers/provideHandler/handler.js +2 -1
  173. package/dist/server/rpc/handlers/rag.js +0 -3
  174. package/dist/server/rpc/handlers/set-config.d.ts +3 -0
  175. package/dist/server/rpc/handlers/set-config.js +18 -0
  176. package/dist/server/rpc/handlers/stopProvideHandler.js +3 -1
  177. package/dist/server/rpc/handlers/text-to-speech.d.ts +3 -0
  178. package/dist/server/rpc/handlers/text-to-speech.js +7 -0
  179. package/dist/server/rpc/handlers/transcribe-stream.js +6 -2
  180. package/dist/server/rpc/handlers/unload-model.js +7 -0
  181. package/dist/server/utils/cache.d.ts +13 -8
  182. package/dist/server/utils/cache.js +69 -14
  183. package/dist/server/utils/checksum.d.ts +2 -0
  184. package/dist/server/utils/checksum.js +24 -0
  185. package/dist/server/utils/index.d.ts +2 -0
  186. package/dist/server/utils/index.js +2 -0
  187. package/dist/server/utils/shard-utils.d.ts +22 -0
  188. package/dist/server/utils/shard-utils.js +37 -0
  189. package/dist/server/utils/tool-integration.d.ts +13 -0
  190. package/dist/server/utils/tool-integration.js +43 -0
  191. package/dist/server/utils/tool-parser.d.ts +7 -0
  192. package/dist/server/utils/tool-parser.js +244 -0
  193. package/dist/utils/errors-base.d.ts +3 -0
  194. package/dist/utils/errors-base.js +13 -0
  195. package/dist/utils/errors-client.d.ts +107 -0
  196. package/dist/utils/errors-client.js +186 -0
  197. package/dist/utils/errors-server.d.ts +146 -0
  198. package/dist/utils/errors-server.js +253 -0
  199. package/dist/utils/tool-helpers.d.ts +17 -0
  200. package/dist/utils/tool-helpers.js +99 -0
  201. package/package.json +12 -8
  202. package/dist/examples/llamacpp-tools-routing.d.ts +0 -2
  203. package/dist/examples/llamacpp-tools-routing.js +0 -364
  204. package/dist/examples/llamacpp-tools.d.ts +0 -2
  205. package/dist/examples/llamacpp-tools.js +0 -81
  206. package/dist/server/http-server.d.ts +0 -2
  207. 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 Error(`Model with ID "${id}" is already registered`);
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
- console.log(`Local model registered: ${id} -> ${options.path}`);
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
- const availableIds = Array.from(modelRegistry.keys());
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 Error(`Model with ID "${id}" is delegated and cannot be accessed as a local model`);
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
- return {
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 Error(`Model with ID "${id}" not found or is delegated`);
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 { sendErrorResponse, sendStreamErrorResponse } from "../error-handlers";
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 Error("No data received");
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 Error(`Unknown request type`);
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 Error(`Model ${request.modelId} is not a delegated model`);
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
- const assetPath = await resolveModelPath(assetSrc, progressCallback, seed);
5
+ await resolveModelPath(assetSrc, progressCallback, seed);
7
6
  return {
8
7
  type: "downloadAsset",
9
8
  success: true,
10
- assetId: path.basename(assetPath),
9
+ assetId: assetSrc,
11
10
  };
12
11
  }
13
12
  catch (error) {
@@ -0,0 +1,3 @@
1
+ import type { GetModelInfoRequest, GetModelInfoResponse } from "../../../schemas/index";
2
+ export declare const handleGetModelInfo: (request: GetModelInfoRequest) => Promise<GetModelInfoResponse>;
3
+ //# sourceMappingURL=get-model-info.d.ts.map
@@ -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
- console.log(`✅ Using cached HTTP model: ${modelPath}`);
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 (expectedSize > 0 && localSize !== expectedSize) {
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 Error("Download cancelled");
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 Error(`HTTP error: ${freshResponse.status} ${freshResponse.statusText}`);
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 Error(`HTTP error: ${response.status} ${response.statusText}`);
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 Error("No response body received");
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 Error("Download cancelled");
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 Error("Response body is not readable");
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) {