@qvac/sdk 0.11.0 → 0.12.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 (205) hide show
  1. package/NOTICE +1427 -39
  2. package/README.md +2 -0
  3. package/dist/client/api/classify.d.ts +23 -0
  4. package/dist/client/api/classify.js +43 -0
  5. package/dist/client/api/get-model-info.d.ts +1 -1
  6. package/dist/client/api/index.d.ts +4 -0
  7. package/dist/client/api/index.js +4 -0
  8. package/dist/client/api/load-model.js +24 -1
  9. package/dist/client/api/transcribe.d.ts +3 -0
  10. package/dist/client/api/transcribe.js +13 -2
  11. package/dist/client/api/video.d.ts +64 -0
  12. package/dist/client/api/video.js +147 -0
  13. package/dist/client/api/vla-helpers.d.ts +45 -0
  14. package/dist/client/api/vla-helpers.js +130 -0
  15. package/dist/client/api/vla.d.ts +65 -0
  16. package/dist/client/api/vla.js +109 -0
  17. package/dist/client/config-loader/resolve-config.node.d.ts +16 -0
  18. package/dist/client/config-loader/resolve-config.node.js +77 -23
  19. package/dist/client/plugins-factory.d.ts +8 -0
  20. package/dist/client/plugins-factory.js +10 -0
  21. package/dist/client/rpc/bare-client.js +62 -66
  22. package/dist/client/rpc/ensure-worker-ready.d.ts +9 -0
  23. package/dist/client/rpc/ensure-worker-ready.js +17 -0
  24. package/dist/client/rpc/node-rpc-client.js +4 -1
  25. package/dist/client/rpc/rpc-error.js +14 -1
  26. package/dist/commands/bundle/bare-pack.d.ts +13 -0
  27. package/dist/commands/bundle/bare-pack.js +54 -0
  28. package/dist/commands/bundle/constants.d.ts +7 -0
  29. package/dist/commands/bundle/constants.js +23 -0
  30. package/dist/commands/bundle/entry-gen.d.ts +2 -0
  31. package/dist/commands/bundle/entry-gen.js +48 -0
  32. package/dist/commands/bundle/index.d.ts +20 -0
  33. package/dist/commands/bundle/index.js +141 -0
  34. package/dist/commands/bundle/manifest.d.ts +21 -0
  35. package/dist/commands/bundle/manifest.js +193 -0
  36. package/dist/commands/bundle/plugins.d.ts +9 -0
  37. package/dist/commands/bundle/plugins.js +51 -0
  38. package/dist/commands/index.d.ts +5 -0
  39. package/dist/commands/index.js +2 -0
  40. package/dist/commands/verify/abi.d.ts +52 -0
  41. package/dist/commands/verify/abi.js +125 -0
  42. package/dist/commands/verify/addon-source.d.ts +43 -0
  43. package/dist/commands/verify/addon-source.js +75 -0
  44. package/dist/commands/verify/bundle-source.d.ts +12 -0
  45. package/dist/commands/verify/bundle-source.js +53 -0
  46. package/dist/commands/verify/index.d.ts +59 -0
  47. package/dist/commands/verify/index.js +371 -0
  48. package/dist/commands/verify/node-modules-source.d.ts +11 -0
  49. package/dist/commands/verify/node-modules-source.js +76 -0
  50. package/dist/commands/verify/prebuilds.d.ts +15 -0
  51. package/dist/commands/verify/prebuilds.js +39 -0
  52. package/dist/examples/classification/classify-image.d.ts +2 -0
  53. package/dist/examples/classification/classify-image.js +23 -0
  54. package/dist/examples/diffusion-txt2vid.d.ts +2 -0
  55. package/dist/examples/diffusion-txt2vid.js +81 -0
  56. package/dist/examples/plugins.js +3 -7
  57. package/dist/examples/tools/llamacpp-tools-gemma4.js +2 -5
  58. package/dist/examples/tools/llamacpp-tools-qwen35.js +2 -3
  59. package/dist/examples/transcription/parakeet-ctc-filesystem.js +18 -12
  60. package/dist/examples/transcription/parakeet-microphone-record.js +7 -12
  61. package/dist/examples/transcription/parakeet-microphone-stream.d.ts +2 -0
  62. package/dist/examples/transcription/parakeet-microphone-stream.js +79 -0
  63. package/dist/examples/transcription/parakeet-sortformer-streaming.d.ts +2 -0
  64. package/dist/examples/transcription/parakeet-sortformer-streaming.js +121 -0
  65. package/dist/examples/transcription/parakeet-sortformer.js +58 -55
  66. package/dist/examples/transcription/parakeet-tdt-filesystem.js +18 -15
  67. package/dist/examples/transcription/whispercpp-microphone-conversation.js +6 -1
  68. package/dist/examples/tts/chatterbox.js +7 -16
  69. package/dist/examples/tts/llm-to-tts-streaming.js +3 -10
  70. package/dist/examples/tts/supertonic-multilingual.js +4 -12
  71. package/dist/examples/tts/supertonic.js +5 -12
  72. package/dist/examples/vla-smolvla.d.ts +2 -0
  73. package/dist/examples/vla-smolvla.js +75 -0
  74. package/dist/examples/voice-assistant/voice-assistant.js +3 -10
  75. package/dist/expo/plugins/find-in-ancestor-node-modules.d.ts +14 -0
  76. package/dist/expo/plugins/find-in-ancestor-node-modules.js +24 -0
  77. package/dist/expo/plugins/get-project-root.d.ts +22 -0
  78. package/dist/expo/plugins/get-project-root.js +23 -0
  79. package/dist/expo/plugins/index.d.ts +4 -0
  80. package/dist/expo/plugins/index.js +4 -0
  81. package/dist/expo/plugins/resolve-sdk-package-dir.d.ts +9 -2
  82. package/dist/expo/plugins/resolve-sdk-package-dir.js +38 -11
  83. package/dist/expo/plugins/withDeviceInfo.js +2 -1
  84. package/dist/expo/plugins/withMobileBundle.d.ts +2 -17
  85. package/dist/expo/plugins/withMobileBundle.js +31 -85
  86. package/dist/index.d.ts +4 -3
  87. package/dist/index.js +4 -3
  88. package/dist/models/registry/models.d.ts +3711 -368
  89. package/dist/models/registry/models.js +7066 -3562
  90. package/dist/models/update-models/naming.js +22 -8
  91. package/dist/pear/pre.js +6 -2
  92. package/dist/schemas/cancel.d.ts +5 -0
  93. package/dist/schemas/cancel.js +1 -0
  94. package/dist/schemas/classification.d.ts +53 -0
  95. package/dist/schemas/classification.js +33 -0
  96. package/dist/schemas/common.d.ts +1001 -1739
  97. package/dist/schemas/common.js +6 -1
  98. package/dist/schemas/completion-event.d.ts +3 -0
  99. package/dist/schemas/completion-event.js +1 -0
  100. package/dist/schemas/completion-stream.d.ts +1 -0
  101. package/dist/schemas/download-asset.d.ts +13 -3
  102. package/dist/schemas/engine-addon-map.d.ts +3 -0
  103. package/dist/schemas/engine-addon-map.js +18 -5
  104. package/dist/schemas/get-model-info.d.ts +4 -0
  105. package/dist/schemas/get-model-info.js +2 -0
  106. package/dist/schemas/index.d.ts +3 -0
  107. package/dist/schemas/index.js +3 -0
  108. package/dist/schemas/llamacpp-config.d.ts +12 -2
  109. package/dist/schemas/load-model.d.ts +6152 -10764
  110. package/dist/schemas/load-model.js +75 -7
  111. package/dist/schemas/model-src-utils.d.ts +22 -2
  112. package/dist/schemas/model-types.d.ts +46 -6
  113. package/dist/schemas/model-types.js +28 -5
  114. package/dist/schemas/ocr.d.ts +5 -0
  115. package/dist/schemas/plugin.d.ts +20 -5
  116. package/dist/schemas/plugin.js +21 -4
  117. package/dist/schemas/registry.d.ts +44 -0
  118. package/dist/schemas/registry.js +5 -0
  119. package/dist/schemas/reload-config.d.ts +22 -2
  120. package/dist/schemas/sdcpp-config.d.ts +316 -1
  121. package/dist/schemas/sdcpp-config.js +232 -33
  122. package/dist/schemas/sdk-config.d.ts +654 -1324
  123. package/dist/schemas/sdk-config.js +16 -1
  124. package/dist/schemas/sdk-errors-client.d.ts +5 -0
  125. package/dist/schemas/sdk-errors-client.js +26 -1
  126. package/dist/schemas/sdk-errors-server.d.ts +3 -1
  127. package/dist/schemas/sdk-errors-server.js +20 -5
  128. package/dist/schemas/text-to-speech.d.ts +79 -696
  129. package/dist/schemas/text-to-speech.js +46 -19
  130. package/dist/schemas/transcription-config.d.ts +37 -226
  131. package/dist/schemas/transcription-config.js +76 -15
  132. package/dist/schemas/transcription.d.ts +63 -11
  133. package/dist/schemas/transcription.js +56 -2
  134. package/dist/schemas/translation-config.d.ts +60 -10
  135. package/dist/schemas/vla.d.ts +87 -0
  136. package/dist/schemas/vla.js +108 -0
  137. package/dist/scripts/run-unit-tests.js +8 -2
  138. package/dist/server/bare/ops/transcribe.d.ts +2 -1
  139. package/dist/server/bare/ops/transcribe.js +59 -34
  140. package/dist/server/bare/plugins/ggml-classification/ops/classify.d.ts +6 -0
  141. package/dist/server/bare/plugins/ggml-classification/ops/classify.js +30 -0
  142. package/dist/server/bare/plugins/ggml-classification/plugin.d.ts +32 -0
  143. package/dist/server/bare/plugins/ggml-classification/plugin.js +55 -0
  144. package/dist/server/bare/plugins/ggml-vla/ops/vla-hparams.d.ts +3 -0
  145. package/dist/server/bare/plugins/ggml-vla/ops/vla-hparams.js +12 -0
  146. package/dist/server/bare/plugins/ggml-vla/ops/vla-run.d.ts +3 -0
  147. package/dist/server/bare/plugins/ggml-vla/ops/vla-run.js +75 -0
  148. package/dist/server/bare/plugins/ggml-vla/plugin.d.ts +54 -0
  149. package/dist/server/bare/plugins/ggml-vla/plugin.js +57 -0
  150. package/dist/server/bare/plugins/index.d.ts +3 -1
  151. package/dist/server/bare/plugins/index.js +3 -1
  152. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +3 -0
  153. package/dist/server/bare/plugins/llamacpp-completion/ops/context-overflow.d.ts +29 -0
  154. package/dist/server/bare/plugins/llamacpp-completion/ops/context-overflow.js +65 -0
  155. package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +6 -0
  156. package/dist/server/bare/plugins/llamacpp-completion/plugin.js +26 -0
  157. package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +25 -0
  158. package/dist/server/bare/plugins/onnx-ocr/plugin.d.ts +5 -0
  159. package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +67 -246
  160. package/dist/server/bare/plugins/parakeet-transcription/plugin.js +66 -97
  161. package/dist/server/bare/plugins/sdcpp-generation/ops/video.d.ts +3 -0
  162. package/dist/server/bare/plugins/sdcpp-generation/ops/video.js +199 -0
  163. package/dist/server/bare/plugins/sdcpp-generation/plugin.d.ts +200 -2
  164. package/dist/server/bare/plugins/sdcpp-generation/plugin.js +61 -8
  165. package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech-stream.js +2 -15
  166. package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech.js +2 -1
  167. package/dist/server/bare/plugins/tts-ggml/plugin.d.ts +75 -0
  168. package/dist/server/bare/plugins/tts-ggml/plugin.js +189 -0
  169. package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +29 -4
  170. package/dist/server/bare/plugins/whispercpp-transcription/plugin.js +12 -1
  171. package/dist/server/bare/registry/model-config-utils.js +7 -0
  172. package/dist/server/bare/runtime/request-context.d.ts +1 -1
  173. package/dist/server/bare/runtime-lifecycle.js +9 -9
  174. package/dist/server/bare/types/addon-responses.d.ts +1 -0
  175. package/dist/server/env.js +4 -1
  176. package/dist/server/plugins/index.d.ts +1 -1
  177. package/dist/server/plugins/index.js +1 -1
  178. package/dist/server/plugins/registry.d.ts +1 -0
  179. package/dist/server/plugins/registry.js +5 -0
  180. package/dist/server/rpc/handler-registry.js +4 -0
  181. package/dist/server/rpc/handler-selection.d.ts +9 -0
  182. package/dist/server/rpc/handler-selection.js +14 -0
  183. package/dist/server/rpc/handler-utils.js +5 -13
  184. package/dist/server/rpc/handlers/classify.d.ts +3 -0
  185. package/dist/server/rpc/handlers/classify.js +4 -0
  186. package/dist/server/rpc/handlers/index.d.ts +2 -0
  187. package/dist/server/rpc/handlers/index.js +2 -0
  188. package/dist/server/rpc/handlers/load-model/handler.js +4 -1
  189. package/dist/server/rpc/handlers/load-model/resolve.js +9 -0
  190. package/dist/server/rpc/handlers/video-stream.d.ts +3 -0
  191. package/dist/server/rpc/handlers/video-stream.js +4 -0
  192. package/dist/server/rpc/profiling/operation-metrics.js +23 -0
  193. package/dist/server/utils/config-transform.js +1 -1
  194. package/dist/server/worker.js +14 -11
  195. package/dist/utils/errors-client.d.ts +15 -0
  196. package/dist/utils/errors-client.js +26 -0
  197. package/dist/utils/errors-server.d.ts +30 -2
  198. package/dist/utils/errors-server.js +51 -3
  199. package/package.json +66 -80
  200. package/dist/server/bare/plugins/onnx-tts/plugin.d.ts +0 -490
  201. package/dist/server/bare/plugins/onnx-tts/plugin.js +0 -272
  202. package/dist/server/bare/plugins/onnx-tts/wav-helper.d.ts +0 -14
  203. package/dist/server/bare/plugins/onnx-tts/wav-helper.js +0 -107
  204. /package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech-stream.d.ts +0 -0
  205. /package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech.d.ts +0 -0
@@ -162,7 +162,7 @@ export async function* transcribe(params, requestId) {
162
162
  if (ctx.signal.aborted)
163
163
  break;
164
164
  requestLogger.debug("Streaming Transcription Update:", output);
165
- const chunks = output;
165
+ const chunks = (Array.isArray(output) ? output : [output]);
166
166
  if (metadata) {
167
167
  for (const chunk of chunks) {
168
168
  if (!chunk.text)
@@ -206,6 +206,21 @@ export async function* transcribe(params, requestId) {
206
206
  await result_1;
207
207
  }
208
208
  }
209
+ function buildRunStreamingOpts(engineType, opts) {
210
+ if (engineType === ModelType.parakeetTranscription) {
211
+ return opts?.parakeetStreamingConfig;
212
+ }
213
+ const runOpts = {};
214
+ if (opts?.emitVadEvents)
215
+ runOpts.emitVadEvents = true;
216
+ if (opts?.endOfTurnSilenceMs !== undefined) {
217
+ runOpts.endOfTurnSilenceMs = opts.endOfTurnSilenceMs;
218
+ }
219
+ if (opts?.vadRunIntervalMs !== undefined) {
220
+ runOpts.vadRunIntervalMs = opts.vadRunIntervalMs;
221
+ }
222
+ return runOpts;
223
+ }
209
224
  export async function* transcribeStream(modelId, audioInputStream, prompt, metadata, opts, requestId) {
210
225
  const env_2 = { stack: [], error: void 0, hasError: false };
211
226
  try {
@@ -244,50 +259,37 @@ export async function* transcribeStream(modelId, audioInputStream, prompt, metad
244
259
  ctx.scope.defer(() => {
245
260
  ctx.signal.removeEventListener("abort", onAbort);
246
261
  });
247
- const runOpts = {};
248
- if (opts?.emitVadEvents)
249
- runOpts.emitVadEvents = true;
250
- if (opts?.endOfTurnSilenceMs !== undefined) {
251
- runOpts.endOfTurnSilenceMs = opts.endOfTurnSilenceMs;
252
- }
253
- if (opts?.vadRunIntervalMs !== undefined) {
254
- runOpts.vadRunIntervalMs = opts.vadRunIntervalMs;
255
- }
262
+ const runOpts = buildRunStreamingOpts(engineType, opts);
256
263
  const response = await model.runStreaming(audioInputStream, runOpts);
257
264
  for await (const output of response.iterate()) {
258
265
  if (ctx.signal.aborted)
259
266
  break;
260
267
  requestLogger.debug("Live Transcription Update:", output);
261
268
  if (!Array.isArray(output)) {
262
- if (output.type === "vad") {
263
- yield {
264
- type: "vad",
265
- speaking: output.speaking,
266
- probability: output.probability,
267
- };
268
- continue;
269
- }
270
- if (output.type === "endOfTurn") {
271
- yield {
272
- type: "endOfTurn",
273
- silenceDurationMs: output.silenceDurationMs,
274
- };
269
+ if ("type" in output) {
270
+ if (output.type === "vad") {
271
+ yield {
272
+ type: "vad",
273
+ speaking: output.speaking,
274
+ probability: output.probability,
275
+ };
276
+ continue;
277
+ }
278
+ if (output.type === "endOfTurn") {
279
+ yield {
280
+ type: "endOfTurn",
281
+ source: "whisper",
282
+ silenceDurationMs: output.silenceDurationMs,
283
+ };
284
+ continue;
285
+ }
275
286
  continue;
276
287
  }
288
+ yield* emitSegment(output, metadata, silenceMarker);
277
289
  continue;
278
290
  }
279
291
  for (const segment of output) {
280
- if (!segment.text)
281
- continue;
282
- if (silenceMarker && segment.text.includes(silenceMarker))
283
- continue;
284
- if (metadata) {
285
- yield toTranscribeSegment(segment);
286
- continue;
287
- }
288
- if (segment.text.trim()) {
289
- yield segment.text;
290
- }
292
+ yield* emitSegment(segment, metadata, silenceMarker);
291
293
  }
292
294
  }
293
295
  }
@@ -301,3 +303,26 @@ export async function* transcribeStream(modelId, audioInputStream, prompt, metad
301
303
  await result_2;
302
304
  }
303
305
  }
306
+ function* emitSegment(segment, metadata, silenceMarker) {
307
+ if (!segment.text) {
308
+ if (segment.isEndOfTurn) {
309
+ yield { type: "endOfTurn", source: "parakeet" };
310
+ }
311
+ return;
312
+ }
313
+ if (silenceMarker && segment.text.includes(silenceMarker)) {
314
+ if (segment.isEndOfTurn) {
315
+ yield { type: "endOfTurn", source: "parakeet" };
316
+ }
317
+ return;
318
+ }
319
+ if (metadata) {
320
+ yield toTranscribeSegment(segment);
321
+ }
322
+ else if (segment.text.trim()) {
323
+ yield segment.text;
324
+ }
325
+ if (segment.isEndOfTurn) {
326
+ yield { type: "endOfTurn", source: "parakeet" };
327
+ }
328
+ }
@@ -0,0 +1,6 @@
1
+ import { type ClassifyRequest, type ClassificationResult } from "../../../../../schemas/index";
2
+ export declare function classify(params: ClassifyRequest): Promise<{
3
+ results: ClassificationResult[];
4
+ modelExecutionMs: number;
5
+ }>;
6
+ //# sourceMappingURL=classify.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { getModel } from "../../../registry/model-registry.js";
2
+ import { classifyRequestSchema } from "../../../../../schemas/index.js";
3
+ import { nowMs } from "../../../../../profiling/index.js";
4
+ function hasClassify(model) {
5
+ return (typeof model === "object" &&
6
+ model !== null &&
7
+ "classify" in model &&
8
+ typeof model.classify === "function");
9
+ }
10
+ export async function classify(params) {
11
+ const { modelId, image, topK, width, height, channels } = classifyRequestSchema.parse(params);
12
+ const model = getModel(modelId);
13
+ if (!hasClassify(model)) {
14
+ throw new Error("Loaded model does not support classify()");
15
+ }
16
+ const imageBytes = Buffer.from(image, "base64");
17
+ const opts = {};
18
+ if (topK !== undefined)
19
+ opts.topK = topK;
20
+ if (width !== undefined)
21
+ opts.width = width;
22
+ if (height !== undefined)
23
+ opts.height = height;
24
+ if (channels !== undefined)
25
+ opts.channels = channels;
26
+ const modelStart = nowMs();
27
+ const results = await model.classify(imageBytes, opts);
28
+ const modelExecutionMs = nowMs() - modelStart;
29
+ return { results, modelExecutionMs };
30
+ }
@@ -0,0 +1,32 @@
1
+ import { type CreateModelParams, type PluginModelResult } from "../../../../schemas/index";
2
+ export declare const classificationPlugin: {
3
+ modelType: "ggml-classification";
4
+ displayName: string;
5
+ addonPackage: "@qvac/classification-ggml";
6
+ loadConfigSchema: import("zod").ZodObject<{
7
+ modelPath: import("zod").ZodOptional<import("zod").ZodString>;
8
+ topK: import("zod").ZodOptional<import("zod").ZodNumber>;
9
+ nativeLogger: import("zod").ZodOptional<import("zod").ZodBoolean>;
10
+ }, import("zod/v4/core").$strip>;
11
+ skipPrimaryModelPathValidation: true;
12
+ createModel(params: CreateModelParams): PluginModelResult;
13
+ handlers: {
14
+ classify: import("../../../../schemas/index").PluginHandlerDefinition<import("zod").ZodObject<{
15
+ modelId: import("zod").ZodString;
16
+ image: import("zod").ZodString;
17
+ topK: import("zod").ZodOptional<import("zod").ZodNumber>;
18
+ width: import("zod").ZodOptional<import("zod").ZodNumber>;
19
+ height: import("zod").ZodOptional<import("zod").ZodNumber>;
20
+ channels: import("zod").ZodOptional<import("zod").ZodLiteral<3>>;
21
+ type: import("zod").ZodLiteral<"classify">;
22
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
23
+ type: import("zod").ZodLiteral<"classify">;
24
+ results: import("zod").ZodArray<import("zod").ZodObject<{
25
+ label: import("zod").ZodString;
26
+ confidence: import("zod").ZodNumber;
27
+ }, import("zod/v4/core").$strip>>;
28
+ done: import("zod").ZodOptional<import("zod").ZodBoolean>;
29
+ }, import("zod/v4/core").$strip>>;
30
+ };
31
+ };
32
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1,55 @@
1
+ import ImageClassifier from "@qvac/classification-ggml";
2
+ import { definePlugin, defineHandler, classifyRequestSchema, classifyResponseSchema, ModelType, classificationConfigSchema, ADDON_CLASSIFICATION, } from "../../../../schemas/index.js";
3
+ import { createStreamLogger, registerAddonLogger } from "../../../../logging/index.js";
4
+ import { classify } from "./ops/classify.js";
5
+ export const classificationPlugin = definePlugin({
6
+ modelType: ModelType.ggmlClassification,
7
+ displayName: "Image Classification (GGML)",
8
+ addonPackage: ADDON_CLASSIFICATION,
9
+ loadConfigSchema: classificationConfigSchema,
10
+ skipPrimaryModelPathValidation: true,
11
+ createModel(params) {
12
+ const config = (params.modelConfig ?? {});
13
+ const resolvedModelPath = config.modelPath ?? (params.modelPath || undefined);
14
+ const logger = createStreamLogger(params.modelId, ModelType.ggmlClassification);
15
+ registerAddonLogger(params.modelId, ModelType.ggmlClassification, logger);
16
+ const inner = new ImageClassifier({
17
+ ...(resolvedModelPath ? { modelPath: resolvedModelPath } : {}),
18
+ logger,
19
+ nativeLogger: config.nativeLogger ?? false,
20
+ });
21
+ // Apply the load-time `topK` as a default for classify() calls so the
22
+ // load-config field is not silently ignored. Per-request `topK` (passed
23
+ // in the second arg) wins via the `...opts` spread.
24
+ const defaultTopK = config.topK;
25
+ const model = {
26
+ load: () => inner.load(),
27
+ classify: (image, opts = {}) => inner.classify(image, {
28
+ ...(defaultTopK !== undefined && { topK: defaultTopK }),
29
+ ...opts,
30
+ }),
31
+ unload: () => inner.unload(),
32
+ };
33
+ return { model };
34
+ },
35
+ handlers: {
36
+ classify: defineHandler({
37
+ requestSchema: classifyRequestSchema,
38
+ responseSchema: classifyResponseSchema,
39
+ streaming: true,
40
+ // Classification is a single forward pass with no addon-side cancel
41
+ // surface — mirrors `ocr`/`tts`/`upscale`. The yield-once handler
42
+ // can't be interrupted partway, so we declare scope:"none".
43
+ cancel: { scope: "none" },
44
+ handler: async function* (request) {
45
+ const { results, modelExecutionMs } = await classify(request);
46
+ yield {
47
+ type: "classify",
48
+ results,
49
+ done: true,
50
+ modelExecutionMs,
51
+ };
52
+ },
53
+ }),
54
+ },
55
+ });
@@ -0,0 +1,3 @@
1
+ import { type VlaHparamsRequest, type VlaHparamsResponse } from "../../../../../schemas/index";
2
+ export declare function vlaGetHparams(request: VlaHparamsRequest): Promise<VlaHparamsResponse>;
3
+ //# sourceMappingURL=vla-hparams.d.ts.map
@@ -0,0 +1,12 @@
1
+ import { getModel } from "../../../registry/model-registry.js";
2
+ import { vlaHparamsSchema, } from "../../../../../schemas/index.js";
3
+ export function vlaGetHparams(request) {
4
+ const model = getModel(request.modelId);
5
+ // Validate the addon-reported hparams against our schema so the wire
6
+ // shape stays consistent even if the underlying addon changes.
7
+ const parsed = vlaHparamsSchema.parse(model.hparams);
8
+ return Promise.resolve({
9
+ hparams: parsed,
10
+ backendName: model.backendName ?? null,
11
+ });
12
+ }
@@ -0,0 +1,3 @@
1
+ import { type VlaRunRequest, type VlaRunResponse } from "../../../../../schemas/index";
2
+ export declare function vlaRun(request: VlaRunRequest): Promise<VlaRunResponse>;
3
+ //# sourceMappingURL=vla-run.d.ts.map
@@ -0,0 +1,75 @@
1
+ import { getModel } from "../../../registry/model-registry.js";
2
+ import {} from "../../../../../schemas/index.js";
3
+ import { decodeBase64, encodeBase64 } from "../../../../../utils/encoding.js";
4
+ function f32FromBase64(b64) {
5
+ const bytes = decodeBase64(b64);
6
+ // ArrayBuffer view must be aligned; copy if needed.
7
+ if (bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength) {
8
+ return new Float32Array(bytes.buffer);
9
+ }
10
+ const copy = new Uint8Array(bytes.byteLength);
11
+ copy.set(bytes);
12
+ return new Float32Array(copy.buffer);
13
+ }
14
+ function i32FromBase64(b64) {
15
+ const bytes = decodeBase64(b64);
16
+ if (bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength) {
17
+ return new Int32Array(bytes.buffer);
18
+ }
19
+ const copy = new Uint8Array(bytes.byteLength);
20
+ copy.set(bytes);
21
+ return new Int32Array(copy.buffer);
22
+ }
23
+ function u8FromBase64(b64) {
24
+ return decodeBase64(b64);
25
+ }
26
+ function f32ToBase64(arr) {
27
+ return encodeBase64(new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength));
28
+ }
29
+ function pickStats(raw) {
30
+ if (!raw || typeof raw !== "object")
31
+ return undefined;
32
+ const r = raw;
33
+ const out = {};
34
+ if (typeof r["vision_ms"] === "number")
35
+ out.vision_ms = r["vision_ms"];
36
+ if (typeof r["smollm2_compute_ms"] === "number")
37
+ out.smollm2_compute_ms = r["smollm2_compute_ms"];
38
+ if (typeof r["smollm2_total_ms"] === "number")
39
+ out.smollm2_total_ms = r["smollm2_total_ms"];
40
+ if (typeof r["ode_ms"] === "number")
41
+ out.ode_ms = r["ode_ms"];
42
+ if (typeof r["total_ms"] === "number")
43
+ out.total_ms = r["total_ms"];
44
+ if (typeof r["backendDevice"] === "number")
45
+ out.backendDevice = r["backendDevice"];
46
+ return Object.keys(out).length > 0 ? out : undefined;
47
+ }
48
+ export async function vlaRun(request) {
49
+ const model = getModel(request.modelId);
50
+ const images = request.images.map(f32FromBase64);
51
+ const state = f32FromBase64(request.state);
52
+ const tokens = i32FromBase64(request.tokens);
53
+ const mask = u8FromBase64(request.mask);
54
+ const noise = request.noise ? f32FromBase64(request.noise) : undefined;
55
+ const response = await model.run({
56
+ images,
57
+ imgWidth: request.imgWidth,
58
+ imgHeight: request.imgHeight,
59
+ state,
60
+ tokens,
61
+ mask,
62
+ ...(noise && { noise }),
63
+ });
64
+ const result = await response.await();
65
+ const hp = model.hparams;
66
+ if (!hp) {
67
+ throw new Error("VLA model hparams unavailable after run");
68
+ }
69
+ return {
70
+ actions: f32ToBase64(result.actions),
71
+ actionDim: hp.actionDim,
72
+ chunkSize: hp.chunkSize,
73
+ ...(pickStats(result.stats) && { stats: pickStats(result.stats) }),
74
+ };
75
+ }
@@ -0,0 +1,54 @@
1
+ import { type CreateModelParams, type PluginModelResult } from "../../../../schemas/index";
2
+ export declare const vlaPlugin: {
3
+ modelType: "ggml-vla";
4
+ displayName: string;
5
+ addonPackage: "@qvac/vla-ggml";
6
+ loadConfigSchema: import("zod").ZodObject<{
7
+ backend: import("zod").ZodOptional<import("zod").ZodEnum<{
8
+ cpu: "cpu";
9
+ auto: "auto";
10
+ }>>;
11
+ verbosity: import("zod").ZodOptional<import("zod").ZodNumber>;
12
+ }, import("zod/v4/core").$strip>;
13
+ createModel(params: CreateModelParams): PluginModelResult;
14
+ handlers: {
15
+ vlaRun: import("../../../../schemas/index").PluginHandlerDefinition<import("zod").ZodObject<{
16
+ type: import("zod").ZodLiteral<"vlaRun">;
17
+ modelId: import("zod").ZodString;
18
+ images: import("zod").ZodArray<import("zod").ZodString>;
19
+ imgWidth: import("zod").ZodNumber;
20
+ imgHeight: import("zod").ZodNumber;
21
+ state: import("zod").ZodString;
22
+ tokens: import("zod").ZodString;
23
+ mask: import("zod").ZodString;
24
+ noise: import("zod").ZodOptional<import("zod").ZodString>;
25
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
26
+ actions: import("zod").ZodString;
27
+ actionDim: import("zod").ZodNumber;
28
+ chunkSize: import("zod").ZodNumber;
29
+ stats: import("zod").ZodOptional<import("zod").ZodObject<{
30
+ vision_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
31
+ smollm2_compute_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
32
+ smollm2_total_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
33
+ ode_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
34
+ total_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
35
+ backendDevice: import("zod").ZodOptional<import("zod").ZodNumber>;
36
+ }, import("zod/v4/core").$strip>>;
37
+ }, import("zod/v4/core").$strip>>;
38
+ vlaHparams: import("../../../../schemas/index").PluginHandlerDefinition<import("zod").ZodObject<{
39
+ type: import("zod").ZodLiteral<"vlaHparams">;
40
+ modelId: import("zod").ZodString;
41
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
42
+ hparams: import("zod").ZodObject<{
43
+ chunkSize: import("zod").ZodNumber;
44
+ actionDim: import("zod").ZodNumber;
45
+ maxActionDim: import("zod").ZodNumber;
46
+ maxStateDim: import("zod").ZodNumber;
47
+ tokenizerMaxLength: import("zod").ZodNumber;
48
+ visionImageSize: import("zod").ZodNumber;
49
+ }, import("zod/v4/core").$strip>;
50
+ backendName: import("zod").ZodNullable<import("zod").ZodString>;
51
+ }, import("zod/v4/core").$strip>>;
52
+ };
53
+ };
54
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1,57 @@
1
+ import { VlaModel } from "@qvac/vla-ggml";
2
+ import { definePlugin, defineHandler, vlaConfigSchema, vlaRunRequestSchema, vlaRunResponseSchema, vlaHparamsRequestSchema, vlaHparamsResponseSchema, ModelType, ADDON_VLA, } from "../../../../schemas/index.js";
3
+ import { createStreamLogger, registerAddonLogger } from "../../../../logging/index.js";
4
+ import { vlaRun } from "./ops/vla-run.js";
5
+ import { vlaGetHparams } from "./ops/vla-hparams.js";
6
+ // The `@qvac/vla-ggml` VlaModel exposes `load({ backend })` rather than the
7
+ // `load(force?)` signature `PluginModel` expects. Wrap it so the plugin
8
+ // framework can call `load()` and have the configured backend flow through.
9
+ function wrapVlaModel(inner, loadOpts) {
10
+ const wrapper = inner;
11
+ const originalLoad = wrapper.load.bind(wrapper);
12
+ wrapper.load = function load() {
13
+ return originalLoad(loadOpts);
14
+ };
15
+ return wrapper;
16
+ }
17
+ export const vlaPlugin = definePlugin({
18
+ modelType: ModelType.ggmlVla,
19
+ displayName: "VLA (SmolVLA ggml)",
20
+ addonPackage: ADDON_VLA,
21
+ loadConfigSchema: vlaConfigSchema,
22
+ createModel(params) {
23
+ const config = (params.modelConfig ?? {});
24
+ const logger = createStreamLogger(params.modelId, ModelType.ggmlVla);
25
+ registerAddonLogger(params.modelId, ModelType.ggmlVla, logger);
26
+ const inner = new VlaModel({
27
+ files: { model: [params.modelPath] },
28
+ ...(config.verbosity !== undefined && {
29
+ config: { verbosity: config.verbosity },
30
+ }),
31
+ logger,
32
+ opts: { stats: true },
33
+ });
34
+ const backend = config.backend ?? "auto";
35
+ const model = wrapVlaModel(inner, { backend });
36
+ return { model };
37
+ },
38
+ handlers: {
39
+ vlaRun: defineHandler({
40
+ requestSchema: vlaRunRequestSchema,
41
+ responseSchema: vlaRunResponseSchema,
42
+ streaming: false,
43
+ // The vla-ggml addon exposes a model-wide cancel(): the running ODE /
44
+ // SmolLM2 prefill is interrupted. Mirrors the diffusion plugin's
45
+ // cancel surface.
46
+ cancel: { scope: "model", hard: true },
47
+ handler: vlaRun,
48
+ }),
49
+ vlaHparams: defineHandler({
50
+ requestSchema: vlaHparamsRequestSchema,
51
+ responseSchema: vlaHparamsResponseSchema,
52
+ streaming: false,
53
+ cancel: { scope: "none" },
54
+ handler: vlaGetHparams,
55
+ }),
56
+ },
57
+ });
@@ -3,7 +3,9 @@ export { embeddingsPlugin } from "./llamacpp-embedding/plugin";
3
3
  export { whisperPlugin } from "./whispercpp-transcription/plugin";
4
4
  export { parakeetPlugin } from "./parakeet-transcription/plugin";
5
5
  export { nmtPlugin } from "./nmtcpp-translation/plugin";
6
- export { ttsPlugin } from "./onnx-tts/plugin";
6
+ export { ttsPlugin } from "./tts-ggml/plugin";
7
7
  export { ocrPlugin } from "./onnx-ocr/plugin";
8
8
  export { diffusionPlugin } from "./sdcpp-generation/plugin";
9
+ export { vlaPlugin } from "./ggml-vla/plugin";
10
+ export { classificationPlugin } from "./ggml-classification/plugin";
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -3,6 +3,8 @@ export { embeddingsPlugin } from "./llamacpp-embedding/plugin.js";
3
3
  export { whisperPlugin } from "./whispercpp-transcription/plugin.js";
4
4
  export { parakeetPlugin } from "./parakeet-transcription/plugin.js";
5
5
  export { nmtPlugin } from "./nmtcpp-translation/plugin.js";
6
- export { ttsPlugin } from "./onnx-tts/plugin.js";
6
+ export { ttsPlugin } from "./tts-ggml/plugin.js";
7
7
  export { ocrPlugin } from "./onnx-ocr/plugin.js";
8
8
  export { diffusionPlugin } from "./sdcpp-generation/plugin.js";
9
+ export { vlaPlugin } from "./ggml-vla/plugin.js";
10
+ export { classificationPlugin } from "./ggml-classification/plugin.js";
@@ -205,6 +205,9 @@ async function* processModelResponse(model, messagesToSend, tools, generationPar
205
205
  ...(responseWithStats.stats?.CacheTokens !== undefined && {
206
206
  cacheTokens: responseWithStats.stats.CacheTokens,
207
207
  }),
208
+ ...(responseWithStats.stats?.promptTokens !== undefined && {
209
+ promptTokens: responseWithStats.stats.promptTokens,
210
+ }),
208
211
  ...(responseWithStats.stats?.generatedTokens !== undefined && {
209
212
  generatedTokens: responseWithStats.stats.generatedTokens,
210
213
  }),
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Helpers for detecting and parsing the llama.cpp addon's
3
+ * `ContextOverflow` status error (`LlmErrors.hpp::ContextOverflow = 14`).
4
+ *
5
+ * The addon's JS-facing throw goes through `js_throw_error(env, code,
6
+ * msg)` (see `JsUtils.hpp::JSCATCH`) where `code` comes from
7
+ * `qvac_errors::StatusError::codeString()` and formats as
8
+ * `"[ <addonId> :: ContextOverflow ]"`. The message carries the
9
+ * C++-formatted detail (which may include the prompt/ctx sizes).
10
+ *
11
+ * These helpers let the plugin handler convert that addon error into a
12
+ * typed `ContextOverflowError` and let unit tests assert the detection
13
+ * + extraction logic without a real model load.
14
+ */
15
+ export declare function isAddonContextOverflowError(err: unknown): boolean;
16
+ /**
17
+ * Best-effort extraction of `promptTokens` / `ctxSize` from the addon
18
+ * error message. The C++ paths in `TextLlmContext.cpp` and
19
+ * `MtmdLlmContext.cpp` format both numbers into the message; the
20
+ * `LlamaModel::processPromptImpl` fallback path emits a bare
21
+ * `"<func>: context overflow\n"` with neither number. Returning
22
+ * `undefined` for either field is fine — `ContextOverflowError` holds
23
+ * them as optional and the message factory degrades gracefully.
24
+ */
25
+ export declare function parseContextOverflowMessage(message: string): {
26
+ promptTokens?: number;
27
+ ctxSize?: number;
28
+ };
29
+ //# sourceMappingURL=context-overflow.d.ts.map
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Helpers for detecting and parsing the llama.cpp addon's
3
+ * `ContextOverflow` status error (`LlmErrors.hpp::ContextOverflow = 14`).
4
+ *
5
+ * The addon's JS-facing throw goes through `js_throw_error(env, code,
6
+ * msg)` (see `JsUtils.hpp::JSCATCH`) where `code` comes from
7
+ * `qvac_errors::StatusError::codeString()` and formats as
8
+ * `"[ <addonId> :: ContextOverflow ]"`. The message carries the
9
+ * C++-formatted detail (which may include the prompt/ctx sizes).
10
+ *
11
+ * These helpers let the plugin handler convert that addon error into a
12
+ * typed `ContextOverflowError` and let unit tests assert the detection
13
+ * + extraction logic without a real model load.
14
+ */
15
+ export function isAddonContextOverflowError(err) {
16
+ if (typeof err !== "object" || err === null)
17
+ return false;
18
+ const code = err.code;
19
+ // Anchor to the codeString tail (`[ <addonId> :: ContextOverflow ]`)
20
+ // so we don't false-positive on a hypothetical sibling like
21
+ // `ContextOverflowRecovered` or `PostContextOverflow` after an
22
+ // addon-side rename.
23
+ if (typeof code === "string" && /::\s*ContextOverflow\s*\]/.test(code)) {
24
+ return true;
25
+ }
26
+ // Message-substring fallback for the bare `LlamaModel::processPromptImpl`
27
+ // path, which doesn't go through `StatusError::codeString()`. Match the
28
+ // two known C++-emitted formats only — broader substring would catch
29
+ // wrapper / cause-chain text that mentions overflow without being one.
30
+ const message = err.message;
31
+ return (typeof message === "string" &&
32
+ /(?:context overflow at prefill step|processPromptImpl: context overflow)/i.test(message));
33
+ }
34
+ /**
35
+ * Best-effort extraction of `promptTokens` / `ctxSize` from the addon
36
+ * error message. The C++ paths in `TextLlmContext.cpp` and
37
+ * `MtmdLlmContext.cpp` format both numbers into the message; the
38
+ * `LlamaModel::processPromptImpl` fallback path emits a bare
39
+ * `"<func>: context overflow\n"` with neither number. Returning
40
+ * `undefined` for either field is fine — `ContextOverflowError` holds
41
+ * them as optional and the message factory degrades gracefully.
42
+ */
43
+ export function parseContextOverflowMessage(message) {
44
+ // "[TextLlm] context overflow at prefill step: prompt tokens N, max context tokens M\n"
45
+ // Same-clause separator (no `[^]*?` cross-newline walk) so a future
46
+ // wrapper that pastes overflow text alongside unrelated numbers can't
47
+ // produce a mismatched pair.
48
+ const longForm = message.match(/prompt tokens (\d+)[,\s]+max context tokens (\d+)/i);
49
+ if (longForm?.[1] && longForm[2]) {
50
+ return {
51
+ promptTokens: Number(longForm[1]),
52
+ ctxSize: Number(longForm[2]),
53
+ };
54
+ }
55
+ // "[TextLlm] context overflow at prefill step (N tokens, max M)\n"
56
+ // "[MtmdLlm] context overflow at prefill step (N tokens, max M)\n"
57
+ const shortForm = message.match(/\((\d+)\s+tokens,\s*max\s+(\d+)\)/i);
58
+ if (shortForm?.[1] && shortForm[2]) {
59
+ return {
60
+ promptTokens: Number(shortForm[1]),
61
+ ctxSize: Number(shortForm[2]),
62
+ };
63
+ }
64
+ return {};
65
+ }
@@ -56,18 +56,23 @@ export declare const llmPlugin: {
56
56
  diffusion: "diffusion";
57
57
  tts: "tts";
58
58
  ocr: "ocr";
59
+ vla: "vla";
59
60
  "llamacpp-completion": "llamacpp-completion";
60
61
  "whispercpp-transcription": "whispercpp-transcription";
61
62
  "llamacpp-embedding": "llamacpp-embedding";
62
63
  "nmtcpp-translation": "nmtcpp-translation";
63
64
  "onnx-tts": "onnx-tts";
65
+ "tts-ggml": "tts-ggml";
64
66
  "parakeet-transcription": "parakeet-transcription";
65
67
  "onnx-ocr": "onnx-ocr";
66
68
  "sdcpp-generation": "sdcpp-generation";
69
+ "ggml-vla": "ggml-vla";
70
+ "ggml-classification": "ggml-classification";
67
71
  llm: "llm";
68
72
  whisper: "whisper";
69
73
  nmt: "nmt";
70
74
  parakeet: "parakeet";
75
+ classification: "classification";
71
76
  }>, import("zod").ZodLiteral<"vad">]>>;
72
77
  }, import("zod/v4/core").$strip>]>>;
73
78
  }, import("zod/v4/core").$strip>;
@@ -247,6 +252,7 @@ export declare const llmPlugin: {
247
252
  timeToFirstToken: import("zod").ZodOptional<import("zod").ZodNumber>;
248
253
  tokensPerSecond: import("zod").ZodOptional<import("zod").ZodNumber>;
249
254
  cacheTokens: import("zod").ZodOptional<import("zod").ZodNumber>;
255
+ promptTokens: import("zod").ZodOptional<import("zod").ZodNumber>;
250
256
  generatedTokens: import("zod").ZodOptional<import("zod").ZodNumber>;
251
257
  backendDevice: import("zod").ZodOptional<import("zod").ZodEnum<{
252
258
  cpu: "cpu";