@qvac/sdk 0.8.0 → 0.8.2

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 (60) hide show
  1. package/NOTICE +337 -0
  2. package/README.md +58 -294
  3. package/dist/client/api/cancel.d.ts +9 -0
  4. package/dist/client/api/cancel.js +9 -0
  5. package/dist/client/api/heartbeat.d.ts +30 -0
  6. package/dist/client/api/heartbeat.js +38 -0
  7. package/dist/client/api/index.d.ts +1 -1
  8. package/dist/client/api/index.js +1 -1
  9. package/dist/examples/embed-p2p.d.ts +2 -0
  10. package/dist/examples/llamacpp-p2p.d.ts +2 -0
  11. package/dist/examples/seed-p2p.d.ts +2 -0
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/models/registry/models.d.ts +64 -64
  15. package/dist/models/registry/models.js +108 -108
  16. package/dist/schemas/cancel.d.ts +12 -0
  17. package/dist/schemas/cancel.js +2 -0
  18. package/dist/schemas/common.d.ts +39 -2
  19. package/dist/schemas/common.js +4 -3
  20. package/dist/schemas/delegate.d.ts +8 -0
  21. package/dist/schemas/delegate.js +5 -2
  22. package/dist/schemas/heartbeat.d.ts +17 -0
  23. package/dist/schemas/heartbeat.js +10 -0
  24. package/dist/schemas/index.d.ts +1 -1
  25. package/dist/schemas/index.js +1 -1
  26. package/dist/schemas/load-model.d.ts +113 -0
  27. package/dist/server/bare/delegate-rpc-client.js +42 -11
  28. package/dist/server/bare/plugins/nmtcpp-translation/plugin.js +1 -4
  29. package/dist/server/bare/registry/model-registry.d.ts +2 -0
  30. package/dist/server/bare/registry/model-registry.js +2 -1
  31. package/dist/server/rpc/delegate-transport.js +65 -44
  32. package/dist/server/rpc/delegate-utils.d.ts +2 -0
  33. package/dist/server/rpc/delegate-utils.js +5 -0
  34. package/dist/server/rpc/handler-registry.js +26 -3
  35. package/dist/server/rpc/handler-utils.js +43 -1
  36. package/dist/server/rpc/handlers/cancel-delegated.d.ts +4 -0
  37. package/dist/server/rpc/handlers/cancel-delegated.js +71 -0
  38. package/dist/server/rpc/handlers/completion-stream-delegated.js +2 -2
  39. package/dist/server/rpc/handlers/heartbeat-delegated.d.ts +4 -0
  40. package/dist/server/rpc/handlers/heartbeat-delegated.js +32 -0
  41. package/dist/server/rpc/handlers/heartbeat.d.ts +3 -0
  42. package/dist/server/rpc/handlers/heartbeat.js +3 -0
  43. package/dist/server/rpc/handlers/index.d.ts +2 -2
  44. package/dist/server/rpc/handlers/index.js +2 -2
  45. package/dist/server/rpc/handlers/load-model/registry.js +25 -41
  46. package/dist/server/rpc/handlers/load-model-delegated.js +6 -4
  47. package/dist/server/rpc/handlers/unload-model-delegated.js +3 -3
  48. package/package.json +10 -3
  49. package/dist/client/api/ping.d.ts +0 -11
  50. package/dist/client/api/ping.js +0 -19
  51. package/dist/examples/embed-hyperdrive.d.ts +0 -2
  52. package/dist/examples/llamacpp-hyperdrive.d.ts +0 -2
  53. package/dist/examples/seed-hyperdrive.d.ts +0 -2
  54. package/dist/schemas/ping.d.ts +0 -11
  55. package/dist/schemas/ping.js +0 -8
  56. package/dist/server/rpc/handlers/ping.d.ts +0 -3
  57. package/dist/server/rpc/handlers/ping.js +0 -3
  58. /package/dist/examples/{embed-hyperdrive.js → embed-p2p.js} +0 -0
  59. /package/dist/examples/{llamacpp-hyperdrive.js → llamacpp-p2p.js} +0 -0
  60. /package/dist/examples/{seed-hyperdrive.js → seed-p2p.js} +0 -0
@@ -1,6 +1,5 @@
1
- import fs, { promises as fsPromises } from "bare-fs";
1
+ import { promises as fsPromises } from "bare-fs";
2
2
  import path from "bare-path";
3
- import {} from "bare-stream";
4
3
  import { AbortController } from "bare-abort-controller";
5
4
  import { getModelsCacheDir, generateShortHash, detectShardedModel, getShardedModelCacheDir, getShardPath, getOnnxModelPath, measureChecksum, extractTensorsFromShards, calculatePercentage, } from "../../../utils/index.js";
6
5
  import { getModelByPath } from "../../../../models/registry/index.js";
@@ -64,53 +63,38 @@ async function downloadSingleFileFromRegistry(registryPath, registrySource, mode
64
63
  throw new DownloadCancelledError();
65
64
  }
66
65
  const client = await getRegistryClient();
67
- let readStream;
68
- if (blobBinding) {
69
- logger.info(`📥 Downloading blob directly: ${modelFileName}`);
70
- const result = await client.downloadBlob(blobBinding, {
71
- timeout: REGISTRY_STREAM_TIMEOUT_MS,
72
- });
73
- if (!("stream" in result.artifact)) {
74
- throw new RegistryDownloadFailedError(`No stream returned for blob ${modelFileName}`);
75
- }
76
- readStream = result.artifact.stream;
77
- }
78
- else {
79
- logger.info(`📥 Downloading from registry: ${registryPath}`);
80
- const result = await client.downloadModel(registryPath, registrySource, {
81
- timeout: REGISTRY_STREAM_TIMEOUT_MS,
82
- });
83
- if (!("stream" in result.artifact)) {
84
- throw new RegistryDownloadFailedError(`No stream returned for ${registryPath}`);
85
- }
86
- readStream = result.artifact.stream;
87
- }
88
66
  const dir = path.dirname(modelPath);
89
67
  await fsPromises.mkdir(dir, { recursive: true });
90
- const writeStream = fs.createWriteStream(modelPath);
91
- let downloadedBytes = 0;
92
- readStream.on("data", (chunk) => {
93
- const buffer = chunk;
94
- downloadedBytes += buffer.length;
95
- if (progressCallback) {
68
+ // Adapt registry client's core.on("download") progress to SDK ModelProgressUpdate.
69
+ // This reports network-layer bytes, decoupled from disk I/O backpressure.
70
+ const onProgress = progressCallback
71
+ ? (progress) => {
72
+ const total = progress.total || expectedSize || progress.downloaded;
96
73
  progressCallback({
97
74
  type: "modelProgress",
98
- downloaded: downloadedBytes,
99
- total: expectedSize || downloadedBytes,
100
- percentage: expectedSize
101
- ? calculatePercentage(downloadedBytes, expectedSize)
75
+ downloaded: progress.downloaded,
76
+ total,
77
+ percentage: total > 0
78
+ ? calculatePercentage(progress.downloaded, total)
102
79
  : 0,
103
80
  downloadKey,
104
81
  });
105
82
  }
106
- });
107
- readStream.pipe(writeStream);
108
- await new Promise((resolve, reject) => {
109
- writeStream.on("finish", resolve);
110
- writeStream.on("error", reject);
111
- readStream.on("error", reject);
112
- signal?.addEventListener("abort", () => reject(new Error("Download cancelled")), { once: true });
113
- });
83
+ : undefined;
84
+ const clientOptions = {
85
+ timeout: REGISTRY_STREAM_TIMEOUT_MS,
86
+ outputFile: modelPath,
87
+ ...(onProgress && { onProgress }),
88
+ ...(signal && { signal: signal }),
89
+ };
90
+ if (blobBinding) {
91
+ logger.info(`📥 Downloading blob directly: ${modelFileName}`);
92
+ await client.downloadBlob(blobBinding, clientOptions);
93
+ }
94
+ else {
95
+ logger.info(`📥 Downloading from registry: ${registryPath}`);
96
+ await client.downloadModel(registryPath, registrySource, clientOptions);
97
+ }
114
98
  logger.info(`✅ Downloaded to ${modelPath}`);
115
99
  const stats = await fsPromises.stat(modelPath);
116
100
  if (expectedSize && stats.size !== expectedSize) {
@@ -1,7 +1,7 @@
1
1
  import { DELEGATION_BREAKDOWN_KEY, OPERATION_EVENT_KEY, modelInputToSrcSchema } from "../../../schemas/index.js";
2
2
  import { registerModel, isModelLoaded, unregisterModel } from "../../bare/registry/model-registry.js";
3
3
  import { send, stream, } from "../delegate-transport.js";
4
- import { getRPC, cleanupStaleConnection, } from "../../bare/delegate-rpc-client.js";
4
+ import { getRPC } from "../../bare/delegate-rpc-client.js";
5
5
  import { handleLoadModel } from "./load-model/index.js";
6
6
  import { ModelLoadFailedError, DelegateNoFinalResponseError, } from "../../../utils/errors-server.js";
7
7
  import { getServerLogger } from "../../../logging/index.js";
@@ -12,12 +12,13 @@ export async function handleLoadModelDelegated(request, options) {
12
12
  throw new ModelLoadFailedError("Delegate information is required for delegated load model");
13
13
  }
14
14
  const { delegate } = request;
15
- const { topic, providerPublicKey, timeout, fallbackToLocal, forceNewConnection, } = delegate;
15
+ const { topic, providerPublicKey, timeout, healthCheckTimeout, fallbackToLocal, forceNewConnection, } = delegate;
16
16
  try {
17
17
  logger.info(`📤 Sending delegated loadModel request to provider: ${providerPublicKey}${timeout ? `, timeout: ${timeout}ms` : ""}${forceNewConnection ? " (forcing new connection)" : ""}`);
18
18
  // Create RPC instance for this HyperSwarm peer
19
19
  const rpc = await getRPC(topic, providerPublicKey, {
20
20
  timeout,
21
+ healthCheckTimeout,
21
22
  forceNewConnection,
22
23
  });
23
24
  // Strip out the delegate field to avoid infinite delegation
@@ -82,6 +83,9 @@ export async function handleLoadModelDelegated(request, options) {
82
83
  if (timeout !== undefined) {
83
84
  delegateOptions.timeout = timeout;
84
85
  }
86
+ if (healthCheckTimeout !== undefined) {
87
+ delegateOptions.healthCheckTimeout = healthCheckTimeout;
88
+ }
85
89
  if (isModelLoaded(modelId)) {
86
90
  logger.info(`Delegated model ${modelId} is already registered, replacing with new provider: ${providerPublicKey}`);
87
91
  unregisterModel(modelId);
@@ -104,8 +108,6 @@ export async function handleLoadModelDelegated(request, options) {
104
108
  }
105
109
  catch (error) {
106
110
  logger.error("Error in delegated load model:", error);
107
- // Clean up stale RPC so next attempt creates a fresh connection
108
- cleanupStaleConnection(providerPublicKey);
109
111
  if (fallbackToLocal) {
110
112
  logger.info("🔄 Fallback to local model loading enabled, attempting local load...");
111
113
  try {
@@ -11,12 +11,12 @@ export async function handleUnloadModelDelegated(request) {
11
11
  if (!entry?.isDelegated || !entry.delegated) {
12
12
  throw new ModelIsDelegatedError(request.modelId);
13
13
  }
14
- const { topic, providerPublicKey, timeout } = entry.delegated;
14
+ const { topic, providerPublicKey, timeout, healthCheckTimeout } = entry.delegated;
15
15
  unregisterModel(request.modelId);
16
16
  try {
17
17
  logger.info(`Sending delegated unload for model ${request.modelId} to provider: ${providerPublicKey}`);
18
- const rpc = await getRPC(topic, providerPublicKey, { timeout });
19
- await send({ type: "unloadModel", modelId: request.modelId, clearStorage: false }, rpc, { timeout });
18
+ const rpc = await getRPC(topic, providerPublicKey, { timeout, healthCheckTimeout });
19
+ await send({ type: "unloadModel", modelId: request.modelId, clearStorage: false }, rpc, { timeout, peerKey: providerPublicKey });
20
20
  logger.info(`Delegated model ${request.modelId} unloaded on provider`);
21
21
  }
22
22
  catch (error) {
package/package.json CHANGED
@@ -1,7 +1,14 @@
1
1
  {
2
2
  "name": "@qvac/sdk",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "license": "Apache-2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/tetherto/qvac.git",
8
+ "directory": "packages/sdk"
9
+ },
10
+ "bugs": "https://github.com/tetherto/qvac/issues",
11
+ "homepage": "https://github.com/tetherto/qvac/tree/main/packages/sdk#readme",
5
12
  "type": "module",
6
13
  "main": "./dist/index.js",
7
14
  "types": "./dist/index.d.ts",
@@ -133,7 +140,7 @@
133
140
  "@expo/config-plugins": "^54.0.1",
134
141
  "@lancedb/lancedb": "^0.21.3",
135
142
  "@modelcontextprotocol/sdk": "^1.12.1",
136
- "@qvac/cli": "^0.1.3",
143
+ "@qvac/cli": "^0.2.2",
137
144
  "@sqliteai/sqlite-wasm": "3.50.4-sync.0.8.30-vector.0.9.23",
138
145
  "@types/node": "^24.2.1",
139
146
  "@types/tar-stream": "^3.1.4",
@@ -164,7 +171,7 @@
164
171
  },
165
172
  "peerDependencies": {
166
173
  "@modelcontextprotocol/sdk": "^1.0.0",
167
- "@qvac/cli": "^0.1.2",
174
+ "@qvac/cli": "^0.2.2",
168
175
  "bare-abort-controller": "^1.0.0",
169
176
  "bare-buffer": "^3.4.2",
170
177
  "bare-crypto": "^1.11.2",
@@ -1,11 +0,0 @@
1
- /**
2
- * Sends a ping request to the server and returns the pong response.
3
- *
4
- * @returns A promise that resolves to a pong response containing a number.
5
- * @throws {QvacErrorBase} When the response type is not "pong".
6
- */
7
- export declare function ping(): Promise<{
8
- type: "pong";
9
- number: number;
10
- }>;
11
- //# sourceMappingURL=ping.d.ts.map
@@ -1,19 +0,0 @@
1
- import {} from "../../schemas/index.js";
2
- import { send } from "../rpc/rpc-client.js";
3
- import { InvalidResponseError } from "../../utils/errors-client.js";
4
- /**
5
- * Sends a ping request to the server and returns the pong response.
6
- *
7
- * @returns A promise that resolves to a pong response containing a number.
8
- * @throws {QvacErrorBase} When the response type is not "pong".
9
- */
10
- export async function ping() {
11
- const request = {
12
- type: "ping",
13
- };
14
- const response = await send(request);
15
- if (response.type !== "pong") {
16
- throw new InvalidResponseError("pong");
17
- }
18
- return response;
19
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=embed-hyperdrive.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=llamacpp-hyperdrive.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=seed-hyperdrive.d.ts.map
@@ -1,11 +0,0 @@
1
- import { z } from "zod";
2
- export declare const pingRequestSchema: z.ZodObject<{
3
- type: z.ZodLiteral<"ping">;
4
- }, z.core.$strip>;
5
- export declare const pingResponseSchema: z.ZodObject<{
6
- type: z.ZodLiteral<"pong">;
7
- number: z.ZodNumber;
8
- }, z.core.$strip>;
9
- export type PingRequest = z.infer<typeof pingRequestSchema>;
10
- export type PingResponse = z.infer<typeof pingResponseSchema>;
11
- //# sourceMappingURL=ping.d.ts.map
@@ -1,8 +0,0 @@
1
- import { z } from "zod";
2
- export const pingRequestSchema = z.object({
3
- type: z.literal("ping"),
4
- });
5
- export const pingResponseSchema = z.object({
6
- type: z.literal("pong"),
7
- number: z.number(),
8
- });
@@ -1,3 +0,0 @@
1
- import type { PingResponse } from "../../../schemas/index";
2
- export declare function handlePing(): PingResponse;
3
- //# sourceMappingURL=ping.d.ts.map
@@ -1,3 +0,0 @@
1
- export function handlePing() {
2
- return { type: "pong", number: Math.random() * 100 };
3
- }