@qvac/sdk 0.7.0 → 0.8.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 (218) hide show
  1. package/NOTICE +57 -331
  2. package/README.md +2 -2
  3. package/bare-imports.json +9 -0
  4. package/dist/client/api/completion-stream.d.ts +2 -1
  5. package/dist/client/api/completion-stream.js +2 -1
  6. package/dist/client/api/download-asset.d.ts +3 -2
  7. package/dist/client/api/download-asset.js +4 -3
  8. package/dist/client/api/embed.d.ts +5 -2
  9. package/dist/client/api/embed.js +2 -2
  10. package/dist/client/api/get-model-info.d.ts +1 -1
  11. package/dist/client/api/invoke-plugin.d.ts +3 -2
  12. package/dist/client/api/invoke-plugin.js +4 -4
  13. package/dist/client/api/load-model.d.ts +12 -10
  14. package/dist/client/api/load-model.js +3 -3
  15. package/dist/client/api/rag.d.ts +10 -10
  16. package/dist/client/api/rag.js +21 -21
  17. package/dist/client/api/text-to-speech.d.ts +2 -2
  18. package/dist/client/api/text-to-speech.js +3 -3
  19. package/dist/client/api/transcribe.d.ts +5 -3
  20. package/dist/client/api/transcribe.js +6 -4
  21. package/dist/client/api/translate.d.ts +2 -2
  22. package/dist/client/api/translate.js +3 -3
  23. package/dist/client/rpc/node-rpc-client.d.ts +2 -7
  24. package/dist/client/rpc/node-rpc-client.js +2 -39
  25. package/dist/client/rpc/profiling/index.d.ts +2 -0
  26. package/dist/client/rpc/profiling/index.js +1 -0
  27. package/dist/client/rpc/profiling/profiler.d.ts +27 -0
  28. package/dist/client/rpc/profiling/profiler.js +139 -0
  29. package/dist/client/rpc/rpc-client.d.ts +2 -2
  30. package/dist/client/rpc/rpc-client.js +174 -12
  31. package/dist/examples/delegated-inference/consumer-profiled.d.ts +2 -0
  32. package/dist/examples/delegated-inference/consumer-profiled.js +67 -0
  33. package/dist/examples/llamacpp-multimodal.js +1 -1
  34. package/dist/examples/parallel-download.js +45 -13
  35. package/dist/examples/profiling/basic.d.ts +2 -0
  36. package/dist/examples/profiling/basic.js +71 -0
  37. package/dist/examples/profiling/per-call.d.ts +2 -0
  38. package/dist/examples/profiling/per-call.js +30 -0
  39. package/dist/examples/transcription/parakeet-ctc-filesystem.d.ts +2 -0
  40. package/dist/examples/transcription/parakeet-ctc-filesystem.js +40 -0
  41. package/dist/examples/transcription/parakeet-microphone-record.d.ts +2 -0
  42. package/dist/examples/transcription/parakeet-microphone-record.js +95 -0
  43. package/dist/examples/transcription/parakeet-sortformer.d.ts +2 -0
  44. package/dist/examples/transcription/parakeet-sortformer.js +115 -0
  45. package/dist/examples/transcription/parakeet-tdt-filesystem.d.ts +2 -0
  46. package/dist/examples/transcription/parakeet-tdt-filesystem.js +44 -0
  47. package/dist/examples/translation/translation-bergamot-pivot.d.ts +2 -0
  48. package/dist/examples/translation/translation-bergamot-pivot.js +73 -0
  49. package/dist/examples/translation/translation-llm-afriquegemma.d.ts +2 -0
  50. package/dist/examples/translation/translation-llm-afriquegemma.js +39 -0
  51. package/dist/index.d.ts +3 -1
  52. package/dist/index.js +2 -0
  53. package/dist/logging/index.d.ts +1 -1
  54. package/dist/logging/index.js +1 -1
  55. package/dist/logging/namespaces.d.ts +3 -9
  56. package/dist/logging/namespaces.js +2 -8
  57. package/dist/logging/registry.js +15 -1
  58. package/dist/models/registry/models.d.ts +1606 -245
  59. package/dist/models/registry/models.js +2127 -721
  60. package/dist/models/update-models/codegen.js +2 -2
  61. package/dist/models/update-models/history.d.ts +11 -0
  62. package/dist/models/update-models/history.js +24 -5
  63. package/dist/models/update-models/index.js +17 -16
  64. package/dist/models/update-models/naming.js +56 -0
  65. package/dist/profiling/aggregator.d.ts +15 -0
  66. package/dist/profiling/aggregator.js +100 -0
  67. package/dist/profiling/clock.d.ts +12 -0
  68. package/dist/profiling/clock.js +51 -0
  69. package/dist/profiling/controller.d.ts +33 -0
  70. package/dist/profiling/controller.js +123 -0
  71. package/dist/profiling/envelope.d.ts +10 -0
  72. package/dist/profiling/envelope.js +36 -0
  73. package/dist/profiling/events.d.ts +20 -0
  74. package/dist/profiling/events.js +37 -0
  75. package/dist/profiling/exporters.d.ts +10 -0
  76. package/dist/profiling/exporters.js +236 -0
  77. package/dist/profiling/index.d.ts +36 -0
  78. package/dist/profiling/index.js +31 -0
  79. package/dist/profiling/ring-buffer.d.ts +19 -0
  80. package/dist/profiling/ring-buffer.js +83 -0
  81. package/dist/profiling/types.d.ts +47 -0
  82. package/dist/profiling/types.js +1 -0
  83. package/dist/schemas/common.d.ts +1888 -133
  84. package/dist/schemas/common.js +2 -0
  85. package/dist/schemas/completion-stream.d.ts +31 -0
  86. package/dist/schemas/completion-stream.js +13 -0
  87. package/dist/schemas/download-asset.d.ts +14 -3
  88. package/dist/schemas/download-asset.js +3 -1
  89. package/dist/schemas/engine-addon-map.js +9 -6
  90. package/dist/schemas/get-model-info.d.ts +2 -0
  91. package/dist/schemas/get-model-info.js +1 -0
  92. package/dist/schemas/index.d.ts +2 -1
  93. package/dist/schemas/index.js +2 -1
  94. package/dist/schemas/llamacpp-config.d.ts +140 -14
  95. package/dist/schemas/llamacpp-config.js +11 -7
  96. package/dist/schemas/load-model.d.ts +9649 -2515
  97. package/dist/schemas/load-model.js +142 -182
  98. package/dist/schemas/model-src-utils.d.ts +10 -2
  99. package/dist/schemas/model-types.d.ts +19 -1
  100. package/dist/schemas/model-types.js +11 -0
  101. package/dist/schemas/ocr.d.ts +37 -0
  102. package/dist/schemas/ocr.js +5 -0
  103. package/dist/schemas/plugin.d.ts +51 -5
  104. package/dist/schemas/plugin.js +26 -0
  105. package/dist/schemas/profiling.d.ts +105 -0
  106. package/dist/schemas/profiling.js +66 -0
  107. package/dist/schemas/registry.d.ts +18 -0
  108. package/dist/schemas/registry.js +2 -0
  109. package/dist/schemas/reload-config.d.ts +126 -6
  110. package/dist/schemas/reload-config.js +1 -1
  111. package/dist/schemas/sdk-config.d.ts +2280 -24
  112. package/dist/schemas/sdk-config.js +6 -1
  113. package/dist/schemas/sdk-errors-client.d.ts +1 -0
  114. package/dist/schemas/sdk-errors-client.js +7 -0
  115. package/dist/schemas/sdk-errors-server.d.ts +3 -0
  116. package/dist/schemas/sdk-errors-server.js +15 -0
  117. package/dist/schemas/text-to-speech.d.ts +90 -68
  118. package/dist/schemas/text-to-speech.js +16 -33
  119. package/dist/schemas/transcription-config.d.ts +383 -0
  120. package/dist/schemas/{whispercpp-config.js → transcription-config.js} +29 -1
  121. package/dist/schemas/translation-config.d.ts +463 -8
  122. package/dist/schemas/translation-config.js +35 -2
  123. package/dist/server/bare/delegate-rpc-client.js +11 -1
  124. package/dist/server/bare/ops/load-model.d.ts +7 -1
  125. package/dist/server/bare/ops/load-model.js +41 -42
  126. package/dist/server/bare/ops/transcribe.d.ts +3 -0
  127. package/dist/server/bare/ops/transcribe.js +75 -0
  128. package/dist/server/bare/ops/translate.d.ts +2 -0
  129. package/dist/server/bare/ops/translate.js +12 -4
  130. package/dist/server/bare/plugins/index.d.ts +1 -0
  131. package/dist/server/bare/plugins/index.js +1 -0
  132. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.d.ts +2 -1
  133. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +8 -6
  134. package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +108 -3
  135. package/dist/server/bare/plugins/llamacpp-completion/plugin.js +19 -6
  136. package/dist/server/bare/plugins/llamacpp-embedding/plugin.d.ts +32 -2
  137. package/dist/server/bare/plugins/llamacpp-embedding/plugin.js +31 -17
  138. package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +325 -3
  139. package/dist/server/bare/plugins/nmtcpp-translation/plugin.js +117 -10
  140. package/dist/server/bare/plugins/onnx-ocr/plugin.d.ts +50 -2
  141. package/dist/server/bare/plugins/onnx-ocr/plugin.js +46 -5
  142. package/dist/server/bare/plugins/onnx-tts/plugin.d.ts +351 -4
  143. package/dist/server/bare/plugins/onnx-tts/plugin.js +81 -61
  144. package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +317 -0
  145. package/dist/server/bare/plugins/parakeet-transcription/plugin.js +154 -0
  146. package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +209 -3
  147. package/dist/server/bare/plugins/whispercpp-transcription/plugin.js +21 -9
  148. package/dist/server/bare/rag-hyperdb/rag-workspace-manager.js +2 -2
  149. package/dist/server/bare/registry/model-config-utils.js +3 -1
  150. package/dist/server/bare/utils/audio-input.d.ts +10 -0
  151. package/dist/server/bare/utils/audio-input.js +33 -0
  152. package/dist/server/error-handlers.d.ts +3 -2
  153. package/dist/server/error-handlers.js +11 -8
  154. package/dist/server/plugins/registry.js +5 -1
  155. package/dist/server/rpc/delegate-transport.d.ts +11 -3
  156. package/dist/server/rpc/delegate-transport.js +158 -3
  157. package/dist/server/rpc/handle-request.js +43 -4
  158. package/dist/server/rpc/handler-registry.js +7 -1
  159. package/dist/server/rpc/handler-utils.d.ts +5 -4
  160. package/dist/server/rpc/handler-utils.js +72 -31
  161. package/dist/server/rpc/handlers/completion-stream-delegated.d.ts +3 -1
  162. package/dist/server/rpc/handlers/completion-stream-delegated.js +11 -2
  163. package/dist/server/rpc/handlers/download-asset.js +55 -3
  164. package/dist/server/rpc/handlers/load-model/download-stats.d.ts +6 -0
  165. package/dist/server/rpc/handlers/load-model/download-stats.js +87 -0
  166. package/dist/server/rpc/handlers/load-model/handler.js +108 -123
  167. package/dist/server/rpc/handlers/load-model/http.d.ts +2 -1
  168. package/dist/server/rpc/handlers/load-model/http.js +21 -5
  169. package/dist/server/rpc/handlers/load-model/hyperdrive.d.ts +2 -1
  170. package/dist/server/rpc/handlers/load-model/hyperdrive.js +19 -14
  171. package/dist/server/rpc/handlers/load-model/registry.d.ts +2 -1
  172. package/dist/server/rpc/handlers/load-model/registry.js +123 -130
  173. package/dist/server/rpc/handlers/load-model/resolve.d.ts +2 -0
  174. package/dist/server/rpc/handlers/load-model/resolve.js +55 -22
  175. package/dist/server/rpc/handlers/load-model/types.d.ts +29 -0
  176. package/dist/server/rpc/handlers/load-model/types.js +1 -0
  177. package/dist/server/rpc/handlers/load-model-delegated.d.ts +5 -1
  178. package/dist/server/rpc/handlers/load-model-delegated.js +35 -7
  179. package/dist/server/rpc/handlers/plugin-dispatch.js +15 -10
  180. package/dist/server/rpc/handlers/plugin-invoke.js +56 -51
  181. package/dist/server/rpc/handlers/rag.js +24 -0
  182. package/dist/server/rpc/handlers/unload-model-delegated.d.ts +3 -0
  183. package/dist/server/rpc/handlers/unload-model-delegated.js +32 -0
  184. package/dist/server/rpc/profiling/context.d.ts +18 -0
  185. package/dist/server/rpc/profiling/context.js +38 -0
  186. package/dist/server/rpc/profiling/delegation-profiler.d.ts +32 -0
  187. package/dist/server/rpc/profiling/delegation-profiler.js +154 -0
  188. package/dist/server/rpc/profiling/index.d.ts +5 -0
  189. package/dist/server/rpc/profiling/index.js +4 -0
  190. package/dist/server/rpc/profiling/operation-metrics.d.ts +25 -0
  191. package/dist/server/rpc/profiling/operation-metrics.js +199 -0
  192. package/dist/server/rpc/profiling/operation-wrappers.d.ts +18 -0
  193. package/dist/server/rpc/profiling/operation-wrappers.js +124 -0
  194. package/dist/server/rpc/profiling/profiler.d.ts +13 -0
  195. package/dist/server/rpc/profiling/profiler.js +97 -0
  196. package/dist/server/utils/cache.d.ts +2 -1
  197. package/dist/server/utils/cache.js +5 -1
  198. package/dist/server/utils/checksum.d.ts +2 -0
  199. package/dist/server/utils/checksum.js +7 -0
  200. package/dist/server/utils/formatting.d.ts +6 -0
  201. package/dist/server/utils/formatting.js +35 -0
  202. package/dist/server/worker.js +2 -1
  203. package/dist/utils/errors-client.d.ts +3 -0
  204. package/dist/utils/errors-client.js +6 -0
  205. package/dist/utils/errors-server.d.ts +9 -0
  206. package/dist/utils/errors-server.js +15 -0
  207. package/dist/utils/global-singleton.d.ts +2 -0
  208. package/dist/utils/global-singleton.js +10 -0
  209. package/package.json +14 -17
  210. package/dist/schemas/whispercpp-config.d.ts +0 -70
  211. package/dist/server/bare/plugins/whispercpp-transcription/ops/transcribe-stream.d.ts +0 -3
  212. package/dist/server/bare/plugins/whispercpp-transcription/ops/transcribe-stream.js +0 -81
  213. /package/dist/examples/{whispercpp-filesystem.d.ts → transcription/whispercpp-filesystem.d.ts} +0 -0
  214. /package/dist/examples/{whispercpp-filesystem.js → transcription/whispercpp-filesystem.js} +0 -0
  215. /package/dist/examples/{whispercpp-microphone-record.d.ts → transcription/whispercpp-microphone-record.d.ts} +0 -0
  216. /package/dist/examples/{whispercpp-microphone-record.js → transcription/whispercpp-microphone-record.js} +0 -0
  217. /package/dist/examples/{whispercpp-prompt.d.ts → transcription/whispercpp-prompt.d.ts} +0 -0
  218. /package/dist/examples/{whispercpp-prompt.js → transcription/whispercpp-prompt.js} +0 -0
@@ -1,32 +1,71 @@
1
- import { requestSchema, normalizeModelType, } from "../../schemas/index.js";
1
+ import { requestSchema, normalizeModelType, PROFILING_KEY, } from "../../schemas/index.js";
2
+ import { nowMs } from "../../profiling/index.js";
2
3
  import { resolveModelConfig } from "../bare/registry/model-config-registry.js";
3
4
  import { sendErrorResponse } from "../error-handlers.js";
4
5
  import { RPCNoDataReceivedError, RPCUnknownRequestTypeError, } from "../../utils/errors-server.js";
5
6
  import { registry } from "./handler-registry.js";
6
7
  import { executeHandler, handleInitConfig, isInitConfigMessage, } from "./handler-utils.js";
8
+ import { createServerProfiler } from "./profiling/index.js";
7
9
  export async function handleRequest(req) {
10
+ let profiler;
11
+ let validationStart = 0;
8
12
  try {
9
13
  const rawData = req.data?.toString();
10
14
  if (!rawData) {
11
15
  throw new RPCNoDataReceivedError();
12
16
  }
17
+ // Timing runs unconditionally since we can't know if client
18
+ // requested profiling until after parsing.
19
+ const parseStart = nowMs();
13
20
  const jsonData = JSON.parse(rawData);
21
+ const jsonParseMs = nowMs() - parseStart;
14
22
  // Handle internal config initialization (bypasses schema)
15
23
  if (isInitConfigMessage(jsonData)) {
16
24
  handleInitConfig(req, jsonData);
17
25
  return;
18
26
  }
19
- const processedData = applyDeviceDefaultsToRequest(jsonData);
27
+ const { data: cleanData, profilingMeta } = extractProfilingMeta(jsonData);
28
+ profiler = createServerProfiler(profilingMeta);
29
+ profiler.markRequestParsed(jsonParseMs);
30
+ validationStart = nowMs();
31
+ const processedData = applyDeviceDefaultsToRequest(cleanData);
20
32
  const request = requestSchema.parse(processedData);
33
+ attachProfilingMetaToRequest(request, profilingMeta);
34
+ profiler.markRequestValidated(nowMs() - validationStart);
35
+ validationStart = 0;
21
36
  const entry = registry[request.type];
22
37
  if (!entry) {
23
38
  throw new RPCUnknownRequestTypeError(request.type);
24
39
  }
25
- await executeHandler(req, request, entry);
40
+ await executeHandler(req, request, entry, profiler);
26
41
  }
27
42
  catch (error) {
28
- sendErrorResponse(req, error);
43
+ if (profiler && validationStart > 0) {
44
+ profiler.markRequestValidated(nowMs() - validationStart);
45
+ }
46
+ sendErrorResponse(req, error, profiler);
47
+ }
48
+ }
49
+ function attachProfilingMetaToRequest(request, profilingMeta) {
50
+ if (!profilingMeta)
51
+ return;
52
+ Object.defineProperty(request, PROFILING_KEY, {
53
+ value: profilingMeta,
54
+ enumerable: false,
55
+ configurable: true,
56
+ writable: false,
57
+ });
58
+ }
59
+ function extractProfilingMeta(data) {
60
+ if (!data || typeof data !== "object" || !(PROFILING_KEY in data)) {
61
+ return { data, profilingMeta: undefined };
29
62
  }
63
+ const obj = data;
64
+ const { [PROFILING_KEY]: meta, ...rest } = obj;
65
+ return {
66
+ data: rest,
67
+ profilingMeta: meta,
68
+ };
30
69
  }
31
70
  /**
32
71
  * Apply device-specific config defaults to loadModel requests before schema parsing.
@@ -6,6 +6,7 @@ import { handleLoadModelDelegated } from "./handlers/load-model-delegated.js";
6
6
  import { handleCompletionStreamDelegated } from "./handlers/completion-stream-delegated.js";
7
7
  import { getModelEntry } from "../bare/registry/model-registry.js";
8
8
  import { handleUnloadModel } from "./handlers/unload-model.js";
9
+ import { handleUnloadModelDelegated } from "./handlers/unload-model-delegated.js";
9
10
  import { handleTranscribeStream } from "./handlers/transcribe-stream.js";
10
11
  import { handleEmbed } from "./handlers/embed.js";
11
12
  import { handleTranslate } from "./handlers/translate.js";
@@ -35,7 +36,12 @@ function isModelDelegated(request) {
35
36
  export const registry = {
36
37
  // Simple Reply handlers
37
38
  ping: { type: "reply", handler: handlePing },
38
- unloadModel: { type: "reply", handler: handleUnloadModel },
39
+ unloadModel: {
40
+ type: "reply",
41
+ handler: handleUnloadModel,
42
+ delegatedHandler: handleUnloadModelDelegated,
43
+ isDelegated: isModelDelegated,
44
+ },
39
45
  embed: { type: "reply", handler: handleEmbed },
40
46
  cancel: { type: "reply", handler: cancelHandler },
41
47
  provide: { type: "reply", handler: provideHandler },
@@ -1,8 +1,9 @@
1
1
  import { type QvacConfig, type Request, type Response, type RuntimeContext } from "../../schemas/index";
2
2
  import type RPC from "bare-rpc";
3
- type ReplyHandler = (request: any) => Promise<Response> | Response;
4
- type StreamHandler = (request: any) => AsyncGenerator<Response>;
5
- type ProgressHandler = (request: any, onProgress?: (update: Response) => void) => Promise<Response>;
3
+ import { type ServerProfiler } from "./profiling/index";
4
+ type ReplyHandler = (request: any, ...args: any[]) => Promise<Response> | Response;
5
+ type StreamHandler = (request: any, ...args: any[]) => AsyncGenerator<Response>;
6
+ type ProgressHandler = (request: any, ...args: any[]) => Promise<Response>;
6
7
  export type HandlerEntry = {
7
8
  type: "reply" | "stream";
8
9
  handler: ReplyHandler | StreamHandler | ProgressHandler;
@@ -10,7 +11,7 @@ export type HandlerEntry = {
10
11
  isDelegated?: (request: Request) => boolean;
11
12
  supportsProgress?: boolean | ((request: Request) => boolean);
12
13
  };
13
- export declare function executeHandler(req: RPC.IncomingRequest, request: Request, entry: HandlerEntry): Promise<void>;
14
+ export declare function executeHandler(req: RPC.IncomingRequest, request: Request, entry: HandlerEntry, profiler: ServerProfiler): Promise<void>;
14
15
  type InitConfigMessage = {
15
16
  type: "__init_config";
16
17
  config: QvacConfig;
@@ -1,65 +1,106 @@
1
- import { responseSchema, } from "../../schemas/index.js";
1
+ import { PROFILING_KEY, } from "../../schemas/index.js";
2
2
  import { sendErrorResponse, sendStreamErrorResponse, } from "../error-handlers.js";
3
3
  import { setSDKConfig } from "../bare/registry/config-registry.js";
4
4
  import { setRuntimeContext } from "../bare/registry/runtime-context-registry.js";
5
- function writeToStream(stream, response) {
6
- stream.write(JSON.stringify(responseSchema.parse(response)) + "\n", "utf-8");
5
+ import {} from "./profiling/index.js";
6
+ function getProfilingMetaFromRequest(request) {
7
+ if (PROFILING_KEY in request) {
8
+ return request[PROFILING_KEY];
9
+ }
10
+ return undefined;
7
11
  }
8
- async function executeReplyHandler(req, request, handler) {
12
+ async function executeReplyHandler(req, request, handler, profiler, isDelegated) {
13
+ profiler.startHandler();
9
14
  try {
10
- const response = await handler(request);
11
- req.reply(JSON.stringify(responseSchema.parse(response)), "utf-8");
15
+ let response;
16
+ if (isDelegated) {
17
+ const profilingMeta = getProfilingMetaFromRequest(request);
18
+ response = await handler(request, profilingMeta ? { profilingMeta } : undefined);
19
+ }
20
+ else {
21
+ response = await handler(request);
22
+ }
23
+ profiler.endHandler();
24
+ req.reply(profiler.serialize(response, true), "utf-8");
12
25
  }
13
26
  catch (error) {
14
- sendErrorResponse(req, error);
27
+ profiler.endHandler();
28
+ sendErrorResponse(req, error, profiler);
15
29
  }
16
30
  }
17
- async function executeStreamHandler(req, request, handler) {
31
+ async function executeStreamHandler(req, request, handler, profiler, isDelegated) {
18
32
  const stream = req.createResponseStream();
33
+ profiler.startHandler();
19
34
  try {
20
- for await (const response of handler(request)) {
21
- stream.write(JSON.stringify(responseSchema.parse(response)) + "\n", "utf-8");
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ let generator;
37
+ if (isDelegated) {
38
+ const profilingMeta = getProfilingMetaFromRequest(request);
39
+ generator = handler(request, profilingMeta ? { profilingMeta } : undefined);
40
+ }
41
+ else {
42
+ generator = handler(request);
43
+ }
44
+ for await (const response of generator) {
45
+ stream.write(profiler.serialize(response, false) + "\n", "utf-8");
46
+ }
47
+ profiler.endHandler();
48
+ const trailer = profiler.serialize();
49
+ if (trailer) {
50
+ stream.write(trailer + "\n", "utf-8");
22
51
  }
23
52
  stream.end();
24
53
  }
25
54
  catch (error) {
26
- sendStreamErrorResponse(stream, error);
55
+ profiler.endHandler();
56
+ sendStreamErrorResponse(stream, error, profiler);
27
57
  }
28
58
  }
29
- async function executeProgressHandler(req, request, handler) {
59
+ async function executeProgressHandler(req, request, handler, profiler, isDelegated) {
30
60
  const stream = req.createResponseStream();
61
+ profiler.startHandler();
62
+ const progressCallback = (update) => {
63
+ stream.write(profiler.serialize(update, false) + "\n", "utf-8");
64
+ };
31
65
  try {
32
- const response = await handler(request, (update) => writeToStream(stream, update));
33
- writeToStream(stream, response);
66
+ let response;
67
+ if (isDelegated) {
68
+ const profilingMeta = getProfilingMetaFromRequest(request);
69
+ const options = { progressCallback };
70
+ if (profilingMeta) {
71
+ options.profilingMeta = profilingMeta;
72
+ }
73
+ response = await handler(request, options);
74
+ }
75
+ else {
76
+ response = await handler(request, progressCallback);
77
+ }
78
+ profiler.endHandler();
79
+ stream.write(profiler.serialize(response, true) + "\n", "utf-8");
34
80
  stream.end();
35
81
  }
36
82
  catch (error) {
37
- sendStreamErrorResponse(stream, error);
83
+ profiler.endHandler();
84
+ sendStreamErrorResponse(stream, error, profiler);
38
85
  }
39
86
  }
40
87
  // Unified handler executor with delegation and progress support
41
- export async function executeHandler(req, request, entry) {
42
- const handler = entry.delegatedHandler && entry.isDelegated?.(request)
43
- ? entry.delegatedHandler
44
- : entry.handler;
88
+ export async function executeHandler(req, request, entry, profiler) {
89
+ const isDelegated = !!(entry.delegatedHandler && entry.isDelegated?.(request));
90
+ const handler = isDelegated ? entry.delegatedHandler : entry.handler;
45
91
  const wantsProgress = "withProgress" in request &&
46
92
  request.withProgress &&
47
93
  (typeof entry.supportsProgress === "function"
48
94
  ? entry.supportsProgress(request)
49
95
  : entry.supportsProgress);
50
- try {
51
- if (entry.type === "stream") {
52
- await executeStreamHandler(req, request, handler);
53
- }
54
- else if (wantsProgress) {
55
- await executeProgressHandler(req, request, handler);
56
- }
57
- else {
58
- await executeReplyHandler(req, request, handler);
59
- }
96
+ if (entry.type === "stream") {
97
+ await executeStreamHandler(req, request, handler, profiler, isDelegated);
60
98
  }
61
- catch (error) {
62
- sendErrorResponse(req, error);
99
+ else if (wantsProgress) {
100
+ await executeProgressHandler(req, request, handler, profiler, isDelegated);
101
+ }
102
+ else {
103
+ await executeReplyHandler(req, request, handler, profiler, isDelegated);
63
104
  }
64
105
  }
65
106
  export function isInitConfigMessage(data) {
@@ -1,3 +1,5 @@
1
1
  import type { CompletionStreamRequest, CompletionStreamResponse } from "../../../schemas/index";
2
- export declare function handleCompletionStreamDelegated(request: CompletionStreamRequest): AsyncGenerator<CompletionStreamResponse>;
2
+ import type { DelegatedHandlerOptions } from "../profiling/index";
3
+ export type HandleCompletionStreamDelegatedOptions = DelegatedHandlerOptions;
4
+ export declare function handleCompletionStreamDelegated(request: CompletionStreamRequest, options?: HandleCompletionStreamDelegatedOptions): AsyncGenerator<CompletionStreamResponse>;
3
5
  //# sourceMappingURL=completion-stream-delegated.d.ts.map
@@ -4,7 +4,8 @@ import { stream } from "../delegate-transport.js";
4
4
  import { ModelIsDelegatedError } from "../../../utils/errors-server.js";
5
5
  import { getServerLogger } from "../../../logging/index.js";
6
6
  const logger = getServerLogger();
7
- export async function* handleCompletionStreamDelegated(request) {
7
+ export async function* handleCompletionStreamDelegated(request, options) {
8
+ const { profilingMeta } = options ?? {};
8
9
  // Get delegation info from model registry
9
10
  const entry = getModelEntry(request.modelId);
10
11
  if (!entry?.isDelegated || !entry.delegated) {
@@ -15,8 +16,16 @@ export async function* handleCompletionStreamDelegated(request) {
15
16
  logger.debug(`📤 Sending delegated completionStream request to provider: ${providerPublicKey}${timeout ? `, timeout: ${timeout}ms` : ""}`);
16
17
  // Create RPC instance for this HyperSwarm peer
17
18
  const rpc = await getRPC(topic, providerPublicKey, { timeout });
19
+ // Build delegate options with profiling metadata
20
+ const delegateOpts = { peerKey: providerPublicKey };
21
+ if (profilingMeta) {
22
+ delegateOpts.profilingMeta = profilingMeta;
23
+ }
24
+ if (timeout) {
25
+ delegateOpts.timeout = timeout;
26
+ }
18
27
  // Use the regular stream function with the HyperSwarm RPC instance
19
- const responseStream = stream(request, rpc, { timeout });
28
+ const responseStream = stream(request, rpc, delegateOpts);
20
29
  // Yield each response from the stream
21
30
  for await (const response of responseStream) {
22
31
  yield response;
@@ -1,15 +1,67 @@
1
- import { resolveModelPath } from "./load-model/resolve.js";
1
+ import { PROFILING_KEY, OPERATION_EVENT_KEY, } from "../../../schemas/index.js";
2
+ import { resolveModelPath, resolveModelPathWithStats, } from "./load-model/resolve.js";
3
+ import { nowMs, generateProfileId } from "../../../profiling/clock.js";
2
4
  import { getServerLogger } from "../../../logging/index.js";
3
5
  const logger = getServerLogger();
4
6
  export async function handleDownloadAsset(request, progressCallback) {
5
7
  const { assetSrc, seed } = request;
8
+ const profilingMeta = request[PROFILING_KEY];
9
+ const profilingEnabled = profilingMeta?.enabled !== false && !!profilingMeta;
6
10
  try {
7
- await resolveModelPath(assetSrc, progressCallback, seed);
8
- return {
11
+ const totalDownloadStart = profilingEnabled ? nowMs() : 0;
12
+ let sourceType;
13
+ let downloadStats;
14
+ if (profilingEnabled) {
15
+ const result = await resolveModelPathWithStats(assetSrc, progressCallback, seed);
16
+ sourceType = result.sourceType;
17
+ downloadStats = result.downloadStats;
18
+ }
19
+ else {
20
+ await resolveModelPath(assetSrc, progressCallback, seed);
21
+ }
22
+ const response = {
9
23
  type: "downloadAsset",
10
24
  success: true,
11
25
  assetId: assetSrc,
12
26
  };
27
+ if (profilingEnabled) {
28
+ const totalDownloadTimeMs = nowMs() - totalDownloadStart;
29
+ const profileId = profilingMeta?.id ?? generateProfileId();
30
+ const gauges = {
31
+ totalDownloadTime: totalDownloadTimeMs,
32
+ };
33
+ if (downloadStats) {
34
+ if (downloadStats.downloadTimeMs !== undefined) {
35
+ gauges["downloadTime"] = downloadStats.downloadTimeMs;
36
+ }
37
+ if (downloadStats.totalBytesDownloaded !== undefined) {
38
+ gauges["totalBytesDownloaded"] = downloadStats.totalBytesDownloaded;
39
+ }
40
+ if (downloadStats.downloadSpeedBps !== undefined) {
41
+ gauges["downloadSpeedBps"] = downloadStats.downloadSpeedBps;
42
+ }
43
+ if (downloadStats.checksumValidationTimeMs !== undefined) {
44
+ gauges["checksumValidationTime"] = downloadStats.checksumValidationTimeMs;
45
+ }
46
+ }
47
+ const tags = {};
48
+ if (sourceType) {
49
+ tags["sourceType"] = sourceType;
50
+ }
51
+ if (downloadStats?.cacheHit !== undefined) {
52
+ tags["cacheHit"] = downloadStats.cacheHit ? "true" : "false";
53
+ }
54
+ const operationEvent = {
55
+ op: "downloadAsset",
56
+ kind: "handler",
57
+ ms: totalDownloadTimeMs,
58
+ profileId,
59
+ gauges: Object.keys(gauges).length > 0 ? gauges : undefined,
60
+ tags: Object.keys(tags).length > 0 ? tags : undefined,
61
+ };
62
+ response[OPERATION_EVENT_KEY] = operationEvent;
63
+ }
64
+ return response;
13
65
  }
14
66
  catch (error) {
15
67
  logger.error("Error downloading asset:", error);
@@ -0,0 +1,6 @@
1
+ import type { ModelProgressUpdate } from "../../../../schemas/index";
2
+ import type { DownloadResult } from "./types";
3
+ export declare function downloadModelFromHttpWithStats(url: string, progressCallback?: (progress: ModelProgressUpdate) => void): Promise<DownloadResult>;
4
+ export declare function downloadModelFromRegistryWithStats(registryPath: string, registrySource: string, progressCallback?: (progress: ModelProgressUpdate) => void, expectedChecksum?: string): Promise<DownloadResult>;
5
+ export declare function downloadModelFromHyperdriveWithStats(hyperdriveKey: string, modelFileName: string, seed?: boolean, progressCallback?: (progress: ModelProgressUpdate) => void): Promise<DownloadResult>;
6
+ //# sourceMappingURL=download-stats.d.ts.map
@@ -0,0 +1,87 @@
1
+ import { downloadModelFromHttp } from "./http.js";
2
+ import { downloadModelFromRegistry } from "./registry.js";
3
+ import { downloadModelFromHyperdrive } from "./hyperdrive.js";
4
+ import { nowMs } from "../../../../profiling/index.js";
5
+ function createStatsCollector() {
6
+ return {
7
+ maxBytesDownloaded: 0,
8
+ startTimeMs: nowMs(),
9
+ cacheHit: undefined,
10
+ checksumValidationTimeMsTotal: 0,
11
+ };
12
+ }
13
+ function createHooks(collector) {
14
+ return {
15
+ markCacheHit: () => {
16
+ if (collector.cacheHit === undefined) {
17
+ collector.cacheHit = true;
18
+ collector.maxBytesDownloaded = 0;
19
+ }
20
+ },
21
+ markCacheMiss: () => {
22
+ collector.cacheHit = false;
23
+ },
24
+ addChecksumValidationTimeMs: (durationMs) => {
25
+ collector.checksumValidationTimeMsTotal += durationMs;
26
+ },
27
+ };
28
+ }
29
+ function wrapProgressCallback(collector, originalCallback) {
30
+ return (progress) => {
31
+ // Don't track bytes for cache hits (they're not real network transfer)
32
+ if (collector.cacheHit !== true) {
33
+ const downloaded = progress.onnxInfo?.overallDownloaded ??
34
+ progress.shardInfo?.overallDownloaded ??
35
+ progress.downloaded ??
36
+ 0;
37
+ collector.maxBytesDownloaded = Math.max(collector.maxBytesDownloaded, downloaded);
38
+ }
39
+ originalCallback?.(progress);
40
+ };
41
+ }
42
+ function computeStats(collector) {
43
+ const downloadTimeMs = nowMs() - collector.startTimeMs;
44
+ const totalBytesDownloaded = collector.maxBytesDownloaded;
45
+ const stats = {};
46
+ if (collector.cacheHit !== undefined) {
47
+ stats.cacheHit = collector.cacheHit;
48
+ }
49
+ if (collector.checksumValidationTimeMsTotal > 0) {
50
+ stats.checksumValidationTimeMs = collector.checksumValidationTimeMsTotal;
51
+ }
52
+ if (collector.cacheHit === true) {
53
+ return Object.keys(stats).length > 0 ? stats : undefined;
54
+ }
55
+ if (totalBytesDownloaded > 0) {
56
+ stats.downloadTimeMs = downloadTimeMs;
57
+ stats.totalBytesDownloaded = totalBytesDownloaded;
58
+ if (downloadTimeMs > 0) {
59
+ stats.downloadSpeedBps = (totalBytesDownloaded * 1000) / downloadTimeMs;
60
+ }
61
+ }
62
+ return Object.keys(stats).length > 0 ? stats : undefined;
63
+ }
64
+ export async function downloadModelFromHttpWithStats(url, progressCallback) {
65
+ const collector = createStatsCollector();
66
+ const hooks = createHooks(collector);
67
+ const wrappedCallback = wrapProgressCallback(collector, progressCallback);
68
+ const path = await downloadModelFromHttp(url, wrappedCallback, hooks);
69
+ const stats = computeStats(collector);
70
+ return stats ? { path, stats } : { path };
71
+ }
72
+ export async function downloadModelFromRegistryWithStats(registryPath, registrySource, progressCallback, expectedChecksum) {
73
+ const collector = createStatsCollector();
74
+ const hooks = createHooks(collector);
75
+ const wrappedCallback = wrapProgressCallback(collector, progressCallback);
76
+ const path = await downloadModelFromRegistry(registryPath, registrySource, wrappedCallback, expectedChecksum, hooks);
77
+ const stats = computeStats(collector);
78
+ return stats ? { path, stats } : { path };
79
+ }
80
+ export async function downloadModelFromHyperdriveWithStats(hyperdriveKey, modelFileName, seed, progressCallback) {
81
+ const collector = createStatsCollector();
82
+ const hooks = createHooks(collector);
83
+ const wrappedCallback = wrapProgressCallback(collector, progressCallback);
84
+ const path = await downloadModelFromHyperdrive(hyperdriveKey, modelFileName, seed, wrappedCallback, hooks);
85
+ const stats = computeStats(collector);
86
+ return stats ? { path, stats } : { path };
87
+ }