@qvac/sdk 0.12.1 → 0.13.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 +55 -1225
  2. package/README.md +12 -0
  3. package/dist/client/api/bci-transcribe.d.ts +57 -0
  4. package/dist/client/api/bci-transcribe.js +172 -0
  5. package/dist/client/api/get-model-info.d.ts +1 -1
  6. package/dist/client/api/index.d.ts +1 -0
  7. package/dist/client/api/index.js +1 -0
  8. package/dist/client/api/video.d.ts +26 -6
  9. package/dist/client/api/video.js +30 -7
  10. package/dist/client/api/vla.d.ts +11 -7
  11. package/dist/client/api/vla.js +11 -7
  12. package/dist/client/config-loader/resolve-config.bare.d.ts +1 -1
  13. package/dist/client/config-loader/resolve-config.bare.js +21 -35
  14. package/dist/client/rpc/bare-client.js +2 -2
  15. package/dist/commands/bundle/constants.js +2 -0
  16. package/dist/examples/bci/bci-filesystem-streaming.d.ts +2 -0
  17. package/dist/examples/bci/bci-filesystem-streaming.js +77 -0
  18. package/dist/examples/bci/bci-filesystem.d.ts +2 -0
  19. package/dist/examples/bci/bci-filesystem.js +63 -0
  20. package/dist/examples/cache-management.js +0 -1
  21. package/dist/examples/cancel-by-request-id.js +0 -1
  22. package/dist/examples/classification/classify-image.js +1 -1
  23. package/dist/examples/completion-events.js +6 -2
  24. package/dist/examples/completion-stop-reason.d.ts +25 -0
  25. package/dist/examples/completion-stop-reason.js +65 -0
  26. package/dist/examples/concurrent-completion-collision.d.ts +2 -0
  27. package/dist/examples/concurrent-completion-collision.js +98 -0
  28. package/dist/examples/config-reload.js +1 -2
  29. package/dist/examples/default-config-usage.js +0 -1
  30. package/dist/examples/delegated-inference/composite.js +0 -1
  31. package/dist/examples/delegated-inference/consumer-profiled.js +0 -1
  32. package/dist/examples/delegated-inference/consumer.js +0 -1
  33. package/dist/examples/diffusion-esrgan-upscale.js +1 -3
  34. package/dist/examples/diffusion-flux2-klein-img2img.js +1 -1
  35. package/dist/examples/diffusion-flux2-klein.js +2 -2
  36. package/dist/examples/diffusion-img2img.js +1 -1
  37. package/dist/examples/diffusion-img2vid.d.ts +2 -0
  38. package/dist/examples/diffusion-img2vid.js +78 -0
  39. package/dist/examples/diffusion-simple.js +1 -1
  40. package/dist/examples/diffusion-txt2img.js +8 -3
  41. package/dist/examples/diffusion-txt2vid.js +2 -3
  42. package/dist/examples/download-with-blind-relays.js +0 -1
  43. package/dist/examples/embed-multi-gpu.js +1 -2
  44. package/dist/examples/embed-p2p.js +4 -2
  45. package/dist/examples/finetune/llamacpp-finetune.js +5 -3
  46. package/dist/examples/kv-cache-cleanup.js +0 -1
  47. package/dist/examples/kv-cache-custom-key.js +0 -1
  48. package/dist/examples/kv-cache-example.js +4 -2
  49. package/dist/examples/llamacpp-cache.js +0 -1
  50. package/dist/examples/llamacpp-dynamic-tools.js +4 -2
  51. package/dist/examples/llamacpp-filesystem.js +1 -1
  52. package/dist/examples/llamacpp-http.js +1 -1
  53. package/dist/examples/llamacpp-multi-gpu.js +2 -2
  54. package/dist/examples/llamacpp-multimodal.js +0 -1
  55. package/dist/examples/llamacpp-p2p.js +0 -1
  56. package/dist/examples/llamacpp-sharded.js +1 -1
  57. package/dist/examples/llamacpp-structured-output.js +0 -1
  58. package/dist/examples/logging-file-transport.js +0 -1
  59. package/dist/examples/logging-streaming.js +0 -2
  60. package/dist/examples/mcp-websearch.js +0 -1
  61. package/dist/examples/multi-model-demo.js +0 -2
  62. package/dist/examples/ocr-fasttext.js +0 -1
  63. package/dist/examples/plugins.js +1 -4
  64. package/dist/examples/profiling/basic.js +3 -2
  65. package/dist/examples/profiling/per-call.js +0 -1
  66. package/dist/examples/quickstart.js +0 -1
  67. package/dist/examples/rag/rag-chromadb.js +0 -1
  68. package/dist/examples/rag/rag-hyperdb/cancellation.js +0 -1
  69. package/dist/examples/rag/rag-hyperdb/ingest.js +0 -1
  70. package/dist/examples/rag/rag-hyperdb/pipeline.js +0 -1
  71. package/dist/examples/rag/rag-hyperdb/workspaces.js +0 -1
  72. package/dist/examples/rag/rag-lancedb.js +0 -1
  73. package/dist/examples/rag/rag-sqlite.js +0 -1
  74. package/dist/examples/suspend-resume.js +0 -1
  75. package/dist/examples/tools/llamacpp-native-tools.js +0 -1
  76. package/dist/examples/tools/llamacpp-tools-gemma4.js +1 -1
  77. package/dist/examples/tools/llamacpp-tools-pythonic.js +2 -2
  78. package/dist/examples/tools/llamacpp-tools-qwen35.js +1 -1
  79. package/dist/examples/transcription/parakeet-ctc-filesystem.js +1 -1
  80. package/dist/examples/transcription/parakeet-microphone-record.js +0 -1
  81. package/dist/examples/transcription/parakeet-microphone-stream.js +0 -1
  82. package/dist/examples/transcription/parakeet-sortformer.js +1 -2
  83. package/dist/examples/transcription/parakeet-tdt-filesystem.js +1 -1
  84. package/dist/examples/transcription/whispercpp-filesystem-streaming.js +10 -6
  85. package/dist/examples/transcription/whispercpp-filesystem.js +4 -2
  86. package/dist/examples/transcription/whispercpp-microphone-conversation.js +0 -1
  87. package/dist/examples/transcription/whispercpp-microphone-record.js +0 -1
  88. package/dist/examples/transcription/whispercpp-prompt.js +0 -1
  89. package/dist/examples/translation/translation-bergamot-batch.js +1 -2
  90. package/dist/examples/translation/translation-bergamot-pivot.js +3 -4
  91. package/dist/examples/translation/translation-bergamot.js +1 -2
  92. package/dist/examples/translation/translation-indic.js +1 -2
  93. package/dist/examples/translation/translation-llm-afriquegemma.js +3 -4
  94. package/dist/examples/translation/translation-llm-context.js +1 -2
  95. package/dist/examples/translation/translation-llm.js +2 -3
  96. package/dist/examples/translation/translation-stream.js +2 -3
  97. package/dist/examples/tts/chatterbox.js +1 -2
  98. package/dist/examples/tts/llm-to-tts-streaming.js +2 -4
  99. package/dist/examples/tts/supertonic-multilingual.js +1 -2
  100. package/dist/examples/tts/supertonic.js +1 -2
  101. package/dist/examples/vla-pi05.d.ts +2 -0
  102. package/dist/examples/vla-pi05.js +84 -0
  103. package/dist/examples/vla-smolvla.js +1 -1
  104. package/dist/examples/voice-assistant/voice-assistant.js +1 -4
  105. package/dist/index.d.ts +2 -2
  106. package/dist/index.js +9 -7
  107. package/dist/models/registry/models.d.ts +869 -186
  108. package/dist/models/registry/models.js +3160 -2453
  109. package/dist/models/update-models/companions.d.ts +7 -0
  110. package/dist/models/update-models/companions.js +56 -0
  111. package/dist/models/update-models/naming.js +10 -0
  112. package/dist/pear/pre.js +2 -0
  113. package/dist/schemas/bci-config.d.ts +36 -0
  114. package/dist/schemas/bci-config.js +56 -0
  115. package/dist/schemas/bci.d.ts +177 -0
  116. package/dist/schemas/bci.js +95 -0
  117. package/dist/schemas/common.d.ts +395 -51
  118. package/dist/schemas/common.js +5 -0
  119. package/dist/schemas/completion-event.d.ts +1 -0
  120. package/dist/schemas/download-asset.d.ts +7 -3
  121. package/dist/schemas/embed.d.ts +2 -0
  122. package/dist/schemas/embed.js +1 -0
  123. package/dist/schemas/engine-addon-map.d.ts +1 -0
  124. package/dist/schemas/engine-addon-map.js +4 -1
  125. package/dist/schemas/get-model-info.d.ts +2 -0
  126. package/dist/schemas/get-model-info.js +1 -0
  127. package/dist/schemas/index.d.ts +2 -0
  128. package/dist/schemas/index.js +2 -0
  129. package/dist/schemas/llamacpp-config.d.ts +6 -2
  130. package/dist/schemas/load-model.d.ts +1841 -267
  131. package/dist/schemas/load-model.js +34 -1
  132. package/dist/schemas/model-src-utils.d.ts +10 -2
  133. package/dist/schemas/model-types.d.ts +19 -1
  134. package/dist/schemas/model-types.js +11 -0
  135. package/dist/schemas/ocr.d.ts +2 -0
  136. package/dist/schemas/plugin.d.ts +13 -5
  137. package/dist/schemas/plugin.js +13 -4
  138. package/dist/schemas/registry.d.ts +18 -0
  139. package/dist/schemas/registry.js +2 -0
  140. package/dist/schemas/reload-config.d.ts +10 -2
  141. package/dist/schemas/sdcpp-config.d.ts +75 -8
  142. package/dist/schemas/sdcpp-config.js +56 -10
  143. package/dist/schemas/sdk-config.d.ts +342 -0
  144. package/dist/schemas/text-to-speech.d.ts +8 -0
  145. package/dist/schemas/transcription-config.d.ts +2 -0
  146. package/dist/schemas/transcription.d.ts +12 -0
  147. package/dist/schemas/transcription.js +8 -0
  148. package/dist/schemas/translation-config.d.ts +44 -16
  149. package/dist/schemas/translation-config.js +2 -0
  150. package/dist/schemas/vla.d.ts +14 -0
  151. package/dist/schemas/vla.js +26 -3
  152. package/dist/server/bare/delegate-connect-diagnostics.d.ts +9 -0
  153. package/dist/server/bare/delegate-connect-diagnostics.js +44 -0
  154. package/dist/server/bare/delegate-rpc-client.js +10 -12
  155. package/dist/server/bare/hyperswarm.js +1 -0
  156. package/dist/server/bare/ops/bci-transcribe.d.ts +13 -0
  157. package/dist/server/bare/ops/bci-transcribe.js +248 -0
  158. package/dist/server/bare/ops/embed.js +2 -1
  159. package/dist/server/bare/ops/kv-cache-utils.js +4 -3
  160. package/dist/server/bare/ops/transcribe.js +6 -2
  161. package/dist/server/bare/ops/translate.js +1 -1
  162. package/dist/server/bare/plugins/bci-whispercpp-transcription/plugin.d.ts +130 -0
  163. package/dist/server/bare/plugins/bci-whispercpp-transcription/plugin.js +116 -0
  164. package/dist/server/bare/plugins/ggml-vla/ops/vla-run.js +4 -0
  165. package/dist/server/bare/plugins/ggml-vla/plugin.d.ts +7 -0
  166. package/dist/server/bare/plugins/ggml-vla/plugin.js +1 -1
  167. package/dist/server/bare/plugins/index.d.ts +1 -0
  168. package/dist/server/bare/plugins/index.js +1 -0
  169. package/dist/server/bare/plugins/llamacpp-completion/ops/finetune.js +22 -29
  170. package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +2 -0
  171. package/dist/server/bare/plugins/llamacpp-completion/plugin.js +38 -7
  172. package/dist/server/bare/plugins/llamacpp-embedding/plugin.d.ts +1 -0
  173. package/dist/server/bare/plugins/llamacpp-embedding/plugin.js +9 -1
  174. package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +14 -0
  175. package/dist/server/bare/plugins/onnx-ocr/plugin.d.ts +2 -0
  176. package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +8 -0
  177. package/dist/server/bare/plugins/sdcpp-generation/ops/video.js +7 -1
  178. package/dist/server/bare/plugins/sdcpp-generation/plugin.d.ts +58 -4
  179. package/dist/server/bare/plugins/sdcpp-generation/plugin.js +9 -4
  180. package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +10 -0
  181. package/dist/server/bare/registry/model-config-utils.js +3 -0
  182. package/dist/server/bare/runtime/request-registry-singleton.js +11 -4
  183. package/dist/server/bare/runtime/request-registry.d.ts +60 -16
  184. package/dist/server/bare/runtime/request-registry.js +258 -15
  185. package/dist/server/bare/runtime/with-request-context.d.ts +1 -1
  186. package/dist/server/bare/runtime/with-request-context.js +1 -1
  187. package/dist/server/bare/types/addon-responses.d.ts +5 -0
  188. package/dist/server/rpc/handler-registry.js +4 -0
  189. package/dist/server/rpc/handlers/bci-transcribe-stream.d.ts +3 -0
  190. package/dist/server/rpc/handlers/bci-transcribe-stream.js +4 -0
  191. package/dist/server/rpc/handlers/bci-transcribe.d.ts +3 -0
  192. package/dist/server/rpc/handlers/bci-transcribe.js +4 -0
  193. package/dist/server/rpc/handlers/download-asset.js +1 -1
  194. package/dist/server/rpc/handlers/get-model-info.js +3 -3
  195. package/dist/server/rpc/handlers/index.d.ts +4 -0
  196. package/dist/server/rpc/handlers/index.js +4 -0
  197. package/dist/server/rpc/handlers/load-model/download-manager.d.ts +1 -1
  198. package/dist/server/rpc/handlers/load-model/handler.js +1 -1
  199. package/dist/server/rpc/handlers/load-model/http.js +6 -6
  200. package/dist/server/rpc/handlers/load-model/hyperdrive.js +1 -0
  201. package/dist/server/rpc/handlers/load-model/registry-companion-set.d.ts +1 -0
  202. package/dist/server/rpc/handlers/load-model/registry-companion-set.js +2 -2
  203. package/dist/server/rpc/handlers/load-model/registry.js +1 -0
  204. package/dist/server/rpc/handlers/load-model/resolve-session.d.ts +1 -1
  205. package/dist/server/rpc/handlers/rag.js +5 -5
  206. package/dist/server/utils/checksum.js +2 -1
  207. package/dist/server/utils/formatting.js +2 -1
  208. package/dist/server/utils/multi-gpu-mobile.d.ts +5 -0
  209. package/dist/server/utils/multi-gpu-mobile.js +10 -0
  210. package/dist/server/worker.js +2 -1
  211. package/dist/utils/aggregate-events.d.ts +2 -1
  212. package/dist/utils/aggregate-events.js +11 -3
  213. package/dist/utils/errors-server.d.ts +6 -4
  214. package/dist/utils/errors-server.js +6 -4
  215. package/electron-forge/index.cjs +820 -0
  216. package/package.json +73 -35
  217. package/dist/scripts/run-security-tests-bare.d.ts +0 -2
  218. package/dist/scripts/run-security-tests-bare.js +0 -78
@@ -0,0 +1,116 @@
1
+ import bciAddonLogging from "@qvac/bci-whispercpp/addonLogging.js";
2
+ import BCIWhispercpp, {} from "@qvac/bci-whispercpp";
3
+ import { definePlugin, defineHandler, defineDuplexHandler, bciTranscribeRequestSchema, bciTranscribeResponseSchema, bciTranscribeStreamRequestSchema, bciTranscribeStreamResponseSchema, ModelType, bciConfigSchema, ADDON_BCI, } from "../../../../schemas/index.js";
4
+ import { createStreamLogger, registerAddonLogger } from "../../../../logging/index.js";
5
+ import { bciTranscribe, bciTranscribeStream, } from "../../ops/bci-transcribe.js";
6
+ import { attachModelExecutionMs } from "../../../../profiling/model-execution.js";
7
+ function createBciModel(modelId, modelPath, bciConfig) {
8
+ const logger = createStreamLogger(modelId, ModelType.bciWhispercppTranscription);
9
+ registerAddonLogger(modelId, ModelType.bciWhispercppTranscription, logger);
10
+ const args = {
11
+ files: {
12
+ model: modelPath,
13
+ },
14
+ logger,
15
+ opts: {
16
+ stats: true,
17
+ },
18
+ };
19
+ const model = new BCIWhispercpp(args, bciConfig);
20
+ return { model };
21
+ }
22
+ export const bciPlugin = definePlugin({
23
+ modelType: ModelType.bciWhispercppTranscription,
24
+ displayName: "BCI (whisper.cpp)",
25
+ addonPackage: ADDON_BCI,
26
+ loadConfigSchema: bciConfigSchema,
27
+ createModel(params) {
28
+ const bciConfig = (params.modelConfig ?? {});
29
+ const { model } = createBciModel(params.modelId, params.modelPath, bciConfig);
30
+ return { model };
31
+ },
32
+ handlers: {
33
+ bciTranscribe: defineHandler({
34
+ requestSchema: bciTranscribeRequestSchema,
35
+ responseSchema: bciTranscribeResponseSchema,
36
+ streaming: true,
37
+ // The BCI addon exposes a model-wide hard cancel — the running
38
+ // neural-signal job is interrupted on `cancel()`.
39
+ cancel: { scope: "model", hard: true },
40
+ handler: async function* (request) {
41
+ const metadata = request.metadata === true;
42
+ const stream = metadata
43
+ ? bciTranscribe({
44
+ modelId: request.modelId,
45
+ neuralData: request.neuralData,
46
+ metadata: true,
47
+ }, request.requestId)
48
+ : bciTranscribe({
49
+ modelId: request.modelId,
50
+ neuralData: request.neuralData,
51
+ }, request.requestId);
52
+ try {
53
+ let result = await stream.next();
54
+ while (!result.done) {
55
+ yield metadata
56
+ ? {
57
+ type: "bciTranscribe",
58
+ segment: result.value,
59
+ }
60
+ : {
61
+ type: "bciTranscribe",
62
+ text: result.value,
63
+ };
64
+ result = await stream.next();
65
+ }
66
+ const { modelExecutionMs, stats } = result.value;
67
+ yield attachModelExecutionMs({
68
+ type: "bciTranscribe",
69
+ text: "",
70
+ done: true,
71
+ ...(stats && { stats }),
72
+ }, modelExecutionMs);
73
+ }
74
+ finally {
75
+ await stream.return?.(undefined);
76
+ }
77
+ },
78
+ }),
79
+ bciTranscribeStream: defineDuplexHandler({
80
+ requestSchema: bciTranscribeStreamRequestSchema,
81
+ responseSchema: bciTranscribeStreamResponseSchema,
82
+ streaming: true,
83
+ duplex: true,
84
+ // Same model-wide hard cancel surface as `bciTranscribe` — the BCI
85
+ // addon's `cancel()` tears down the active stream and interrupts the
86
+ // running window job.
87
+ cancel: { scope: "model", hard: true },
88
+ handler: async function* (request, inputStream) {
89
+ const metadata = request.metadata === true;
90
+ const iterator = metadata
91
+ ? bciTranscribeStream(request.modelId, inputStream, true, request.streamOpts, request.requestId)
92
+ : bciTranscribeStream(request.modelId, inputStream, false, request.streamOpts, request.requestId);
93
+ for await (const value of iterator) {
94
+ yield metadata
95
+ ? {
96
+ type: "bciTranscribeStream",
97
+ segment: value,
98
+ }
99
+ : {
100
+ type: "bciTranscribeStream",
101
+ text: value,
102
+ };
103
+ }
104
+ yield {
105
+ type: "bciTranscribeStream",
106
+ text: "",
107
+ done: true,
108
+ };
109
+ },
110
+ }),
111
+ },
112
+ logging: {
113
+ module: bciAddonLogging,
114
+ namespace: ModelType.bciWhispercppTranscription,
115
+ },
116
+ });
@@ -33,6 +33,10 @@ function pickStats(raw) {
33
33
  const out = {};
34
34
  if (typeof r["vision_ms"] === "number")
35
35
  out.vision_ms = r["vision_ms"];
36
+ if (typeof r["prefill_compute_ms"] === "number")
37
+ out.prefill_compute_ms = r["prefill_compute_ms"];
38
+ if (typeof r["prefill_total_ms"] === "number")
39
+ out.prefill_total_ms = r["prefill_total_ms"];
36
40
  if (typeof r["smollm2_compute_ms"] === "number")
37
41
  out.smollm2_compute_ms = r["smollm2_compute_ms"];
38
42
  if (typeof r["smollm2_total_ms"] === "number")
@@ -28,6 +28,8 @@ export declare const vlaPlugin: {
28
28
  chunkSize: import("zod").ZodNumber;
29
29
  stats: import("zod").ZodOptional<import("zod").ZodObject<{
30
30
  vision_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
31
+ prefill_compute_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
32
+ prefill_total_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
31
33
  smollm2_compute_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
32
34
  smollm2_total_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
33
35
  ode_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
@@ -46,6 +48,11 @@ export declare const vlaPlugin: {
46
48
  maxStateDim: import("zod").ZodNumber;
47
49
  tokenizerMaxLength: import("zod").ZodNumber;
48
50
  visionImageSize: import("zod").ZodNumber;
51
+ numCameras: import("zod").ZodOptional<import("zod").ZodNumber>;
52
+ stateInputMode: import("zod").ZodOptional<import("zod").ZodEnum<{
53
+ discrete: "discrete";
54
+ continuous: "continuous";
55
+ }>>;
49
56
  }, import("zod/v4/core").$strip>;
50
57
  backendName: import("zod").ZodNullable<import("zod").ZodString>;
51
58
  }, import("zod/v4/core").$strip>>;
@@ -16,7 +16,7 @@ function wrapVlaModel(inner, loadOpts) {
16
16
  }
17
17
  export const vlaPlugin = definePlugin({
18
18
  modelType: ModelType.ggmlVla,
19
- displayName: "VLA (SmolVLA ggml)",
19
+ displayName: "VLA (SmolVLA / π₀.₅ ggml)",
20
20
  addonPackage: ADDON_VLA,
21
21
  loadConfigSchema: vlaConfigSchema,
22
22
  createModel(params) {
@@ -1,6 +1,7 @@
1
1
  export { llmPlugin } from "./llamacpp-completion/plugin";
2
2
  export { embeddingsPlugin } from "./llamacpp-embedding/plugin";
3
3
  export { whisperPlugin } from "./whispercpp-transcription/plugin";
4
+ export { bciPlugin } from "./bci-whispercpp-transcription/plugin";
4
5
  export { parakeetPlugin } from "./parakeet-transcription/plugin";
5
6
  export { nmtPlugin } from "./nmtcpp-translation/plugin";
6
7
  export { ttsPlugin } from "./tts-ggml/plugin";
@@ -1,6 +1,7 @@
1
1
  export { llmPlugin } from "./llamacpp-completion/plugin.js";
2
2
  export { embeddingsPlugin } from "./llamacpp-embedding/plugin.js";
3
3
  export { whisperPlugin } from "./whispercpp-transcription/plugin.js";
4
+ export { bciPlugin } from "./bci-whispercpp-transcription/plugin.js";
4
5
  export { parakeetPlugin } from "./parakeet-transcription/plugin.js";
5
6
  export { nmtPlugin } from "./nmtcpp-translation/plugin.js";
6
7
  export { ttsPlugin } from "./tts-ggml/plugin.js";
@@ -105,27 +105,29 @@ export async function startFinetune(request, onProgress) {
105
105
  try {
106
106
  const model = getModel(request.modelId);
107
107
  validateExplicitFinetuneOperation(request);
108
- // Open a request-scoped lifecycle so finetune slots into the same
109
- // registry-driven cancel surface as the streaming inference kinds.
110
- // `cancel({ requestId })` and broad `cancel({ modelId, kind: "finetune" })`
111
- // both route through this context's signal — the `onAbort` listener
112
- // forwards to `model.cancel()` to match the plugin's
113
- // `cancel: { scope: "model", hard: true }` declaration. The legacy
114
- // `cancelFinetune(modelId)` wrapper below now goes through the
115
- // registry instead of touching the addon directly.
116
- const ctx = __addDisposableResource(env_1, getRequestRegistry().begin({
108
+ // Mark RUNNING before the async begin() so an immediate getFinetuneState()
109
+ // poll observes RUNNING, not IDLE. register is a no-op when a finetune is
110
+ // already running on this model, so only clear on a failed begin() if this
111
+ // call actually set the flag.
112
+ const wasRunning = getRunningFinetuneState(request.modelId);
113
+ registerRunningFinetune(request.modelId);
114
+ // Scope the run into the registry so cancel({ requestId }) and
115
+ // cancel({ modelId, kind: "finetune" }) reach it; onAbort forwards to
116
+ // model.cancel().
117
+ const ctx = __addDisposableResource(env_1, await getRequestRegistry()
118
+ .begin({
117
119
  requestId: request.requestId ?? generateServerRequestId(),
118
120
  kind: "finetune",
119
121
  modelId: request.modelId,
122
+ })
123
+ .catch((err) => {
124
+ if (!wasRunning)
125
+ clearFinetuneRuntimeState(request.modelId);
126
+ throw err;
120
127
  }), true);
121
128
  const requestLogger = withRequestContext(getServerLogger(), ctx);
122
- registerRunningFinetune(request.modelId);
123
- // Two-level try/finally collapses into a pair of `scope.defer`
124
- // registrations. LIFO order — the listener-detach defer is
125
- // registered after `clearFinetuneRuntimeState`, so on scope unwind
126
- // the listener is removed first, then the runtime-state flag is
127
- // cleared. This mirrors the legacy `finally` nesting where the inner
128
- // `removeListener` ran before the outer `clearFinetuneRuntimeState`.
129
+ // Cleared on scope unwind; deferred before the listener detach so LIFO
130
+ // removes the listener first.
129
131
  ctx.scope.defer(() => {
130
132
  clearFinetuneRuntimeState(request.modelId);
131
133
  });
@@ -172,20 +174,11 @@ export async function pauseFinetune(modelId) {
172
174
  status: "PAUSED",
173
175
  };
174
176
  }
175
- // Thin compat wrapper over the request registry. The in-flight
176
- // finetune is tracked by a `RequestContext` (kind `"finetune"`), and
177
- // the registry owns the broadcast to its `AbortSignal`. `startFinetune`
178
- // installs the addon-level `model.cancel()` listener tied to that
179
- // signal, so callers see the same observable effect as a direct
180
- // `model.cancel()` call. The addon-call wiring is centralised there —
181
- // never invoke `model.cancel()` here.
177
+ // Routes cancellation through the registry; the model.cancel() forward is
178
+ // installed by startFinetune, so never call model.cancel() here.
182
179
  export function cancelFinetune(modelId) {
183
- // `registry.cancel(...)` is synchronous — it triggers the matching
184
- // requests' abort signals and returns the cancelled count. Scope
185
- // unwinding (and the `model.cancel()` forward installed by
186
- // `startFinetune`) happens on the handler's own dispose path. The
187
- // outer `Promise.resolve(...)` keeps the legacy `cancelFinetune`
188
- // return shape (`Promise<FinetuneResult>`) intact for callers.
180
+ // cancel() is synchronous; Promise.resolve keeps the Promise<FinetuneResult>
181
+ // return shape.
189
182
  getRequestRegistry().cancel({ modelId, kind: "finetune" });
190
183
  return Promise.resolve({
191
184
  type: "finetune",
@@ -59,6 +59,7 @@ export declare const llmPlugin: {
59
59
  vla: "vla";
60
60
  "llamacpp-completion": "llamacpp-completion";
61
61
  "whispercpp-transcription": "whispercpp-transcription";
62
+ "bci-whispercpp-transcription": "bci-whispercpp-transcription";
62
63
  "llamacpp-embedding": "llamacpp-embedding";
63
64
  "nmtcpp-translation": "nmtcpp-translation";
64
65
  "onnx-tts": "onnx-tts";
@@ -70,6 +71,7 @@ export declare const llmPlugin: {
70
71
  "ggml-classification": "ggml-classification";
71
72
  llm: "llm";
72
73
  whisper: "whisper";
74
+ bci: "bci";
73
75
  nmt: "nmt";
74
76
  parakeet: "parakeet";
75
77
  classification: "classification";
@@ -68,10 +68,18 @@ import { generateServerRequestId } from "../../runtime/request-id.js";
68
68
  import { getServerLogger } from "../../../../logging/index.js";
69
69
  import { ContextOverflowError } from "../../../../utils/errors-server.js";
70
70
  import { isAddonContextOverflowError, parseContextOverflowMessage, } from "./ops/context-overflow.js";
71
+ import { isMobile } from "../../registry/runtime-context-registry.js";
72
+ import { stripMultiGpuKeys } from "../../../utils/multi-gpu-mobile.js";
71
73
  function createLlmModel(modelId, modelPath, llmConfig, projectionModelPath) {
72
74
  const logger = createStreamLogger(modelId, ModelType.llamacppCompletion);
73
75
  registerAddonLogger(modelId, ModelType.llamacppCompletion, logger);
74
76
  const llmConfigStrings = transformLlmConfig(llmConfig);
77
+ if (isMobile()) {
78
+ const stripped = stripMultiGpuKeys(llmConfigStrings);
79
+ if (stripped.length > 0) {
80
+ getServerLogger().warn(`[${ModelType.llamacppCompletion}:${modelId}] Multi-GPU parameters (${stripped.join(", ")}) are not supported on mobile (single-GPU device) — removing from config; model will load with single-GPU defaults`);
81
+ }
82
+ }
75
83
  const modelFiles = expandGGUFIntoShards(modelPath);
76
84
  const model = new LlmLlamacpp({
77
85
  files: {
@@ -142,12 +150,26 @@ export const llmPlugin = definePlugin({
142
150
  // client can target this run with `cancel({ requestId })`.
143
151
  // Falls back to a server-generated id if the client (e.g. an
144
152
  // older release) didn't send one.
145
- const ctx = __addDisposableResource(env_1, getRequestRegistry().begin({
153
+ const ctx = __addDisposableResource(env_1, await getRequestRegistry().begin({
146
154
  requestId: request.requestId ?? generateServerRequestId(),
147
155
  kind: "completion",
148
156
  modelId: request.modelId,
149
157
  }), true);
150
158
  const requestLogger = withRequestContext(getServerLogger(), ctx);
159
+ // begin() can return already-aborted when the client cancels while
160
+ // this completion is queued behind another same-model one. It never
161
+ // decoded, so it must not touch the shared native context — emit a
162
+ // cancelled terminal and return. Boolean(...) keeps ctx.signal.aborted
163
+ // a boolean so the mid-stream check below isn't narrowed to false.
164
+ const abortedBeforeRun = Boolean(ctx.signal.aborted);
165
+ if (abortedBeforeRun) {
166
+ yield {
167
+ type: "completionStream",
168
+ done: true,
169
+ events: normalizer.finish({ stopReason: "cancelled" }),
170
+ };
171
+ return;
172
+ }
151
173
  const stream = completion({
152
174
  history: filteredHistory,
153
175
  modelId: request.modelId,
@@ -174,17 +196,26 @@ export const llmPlugin = definePlugin({
174
196
  result = await stream.next();
175
197
  }
176
198
  const { modelExecutionMs, stats, toolCalls } = result.value;
177
- // `stopReason: "cancelled"` rides the success-done path: the
178
- // events stream ends normally, the cancellation is observable
179
- // via the last event's `stopReason`, and the client-side
180
- // `CompletionRun` aggregates (`final` / `text` / `toolCalls` /
181
- // `stats`) reject with `InferenceCancelledError` carrying the
182
- // partial state.
199
+ // Cancellation rides the done path: observable via the last event's
200
+ // stopReason; client aggregates reject with InferenceCancelledError.
183
201
  const cancelled = ctx.signal.aborted;
202
+ // EOS tokens are not decoded by llama_decode, so n_eval (and
203
+ // therefore stats.generatedTokens) counts only real decode calls.
204
+ // When generatedTokens >= effectivePredict the run exhausted its
205
+ // token budget without hitting EOS — emit stopReason "length".
206
+ // -1 (unlimited) and -2 (context fill) must never trigger this.
207
+ const effectivePredict = request.generationParams?.predict ??
208
+ modelCfg.predict;
209
+ const stoppedByBudget = !cancelled &&
210
+ effectivePredict !== undefined &&
211
+ effectivePredict > 0 &&
212
+ stats?.generatedTokens !== undefined &&
213
+ stats.generatedTokens >= effectivePredict;
184
214
  const terminalEvents = normalizer.finish({
185
215
  ...(stats && { stats }),
186
216
  ...(toolCalls.length > 0 && { toolCalls }),
187
217
  ...(cancelled && { stopReason: "cancelled" }),
218
+ ...(stoppedByBudget && { stopReason: "length" }),
188
219
  });
189
220
  if (!request.stream) {
190
221
  batchedEvents.push(...terminalEvents);
@@ -59,6 +59,7 @@ export declare const embeddingsPlugin: {
59
59
  cpu: "cpu";
60
60
  gpu: "gpu";
61
61
  }>>;
62
+ contextSize: import("zod").ZodOptional<import("zod").ZodNumber>;
62
63
  }, import("zod/v4/core").$strip>>;
63
64
  error: import("zod").ZodOptional<import("zod").ZodString>;
64
65
  }, import("zod/v4/core").$strip>>;
@@ -1,10 +1,12 @@
1
1
  import EmbedLlamacpp, {} from "@qvac/embed-llamacpp";
2
2
  import embedAddonLogging from "@qvac/embed-llamacpp/addonLogging.js";
3
3
  import { definePlugin, defineHandler, embedRequestSchema, embedResponseSchema, ModelType, embedConfigBaseSchema, ADDON_EMBEDDING, } from "../../../../schemas/index.js";
4
- import { createStreamLogger, registerAddonLogger } from "../../../../logging/index.js";
4
+ import { createStreamLogger, registerAddonLogger, getServerLogger } from "../../../../logging/index.js";
5
5
  import { expandGGUFIntoShards } from "../../../utils/index.js";
6
6
  import { embed } from "../../ops/embed.js";
7
7
  import { forwardModelExecution } from "../../../../profiling/model-execution.js";
8
+ import { isMobile } from "../../registry/runtime-context-registry.js";
9
+ import { stripMultiGpuKeys } from "../../../utils/multi-gpu-mobile.js";
8
10
  function transformEmbedConfig(embedConfig) {
9
11
  const config = {
10
12
  device: embedConfig.device,
@@ -47,6 +49,12 @@ function createEmbeddingsModel(modelId, modelPath, embedConfig) {
47
49
  const logger = createStreamLogger(modelId, ModelType.llamacppEmbedding);
48
50
  registerAddonLogger(modelId, ModelType.llamacppEmbedding, logger);
49
51
  const config = transformEmbedConfig(embedConfig);
52
+ if (isMobile()) {
53
+ const stripped = stripMultiGpuKeys(config);
54
+ if (stripped.length > 0) {
55
+ getServerLogger().warn(`[${ModelType.llamacppEmbedding}:${modelId}] Multi-GPU parameters (${stripped.join(", ")}) are not supported on mobile (single-GPU device) — removing from config; model will load with single-GPU defaults`);
56
+ }
57
+ }
50
58
  const modelFiles = expandGGUFIntoShards(modelPath);
51
59
  const model = new EmbedLlamacpp({
52
60
  files: { model: modelFiles },
@@ -60,6 +60,7 @@ export declare const nmtPlugin: {
60
60
  mt: "mt";
61
61
  nb: "nb";
62
62
  nn: "nn";
63
+ no: "no";
63
64
  re: "re";
64
65
  ro: "ro";
65
66
  sq: "sq";
@@ -67,6 +68,7 @@ export declare const nmtPlugin: {
67
68
  sv: "sv";
68
69
  ta: "ta";
69
70
  te: "te";
71
+ th: "th";
70
72
  tr: "tr";
71
73
  vi: "vi";
72
74
  }>;
@@ -114,6 +116,7 @@ export declare const nmtPlugin: {
114
116
  mt: "mt";
115
117
  nb: "nb";
116
118
  nn: "nn";
119
+ no: "no";
117
120
  re: "re";
118
121
  ro: "ro";
119
122
  sq: "sq";
@@ -121,6 +124,7 @@ export declare const nmtPlugin: {
121
124
  sv: "sv";
122
125
  ta: "ta";
123
126
  te: "te";
127
+ th: "th";
124
128
  tr: "tr";
125
129
  vi: "vi";
126
130
  }>;
@@ -143,6 +147,7 @@ export declare const nmtPlugin: {
143
147
  vla: "vla";
144
148
  "llamacpp-completion": "llamacpp-completion";
145
149
  "whispercpp-transcription": "whispercpp-transcription";
150
+ "bci-whispercpp-transcription": "bci-whispercpp-transcription";
146
151
  "llamacpp-embedding": "llamacpp-embedding";
147
152
  "nmtcpp-translation": "nmtcpp-translation";
148
153
  "onnx-tts": "onnx-tts";
@@ -154,6 +159,7 @@ export declare const nmtPlugin: {
154
159
  "ggml-classification": "ggml-classification";
155
160
  llm: "llm";
156
161
  whisper: "whisper";
162
+ bci: "bci";
157
163
  nmt: "nmt";
158
164
  parakeet: "parakeet";
159
165
  classification: "classification";
@@ -178,6 +184,7 @@ export declare const nmtPlugin: {
178
184
  vla: "vla";
179
185
  "llamacpp-completion": "llamacpp-completion";
180
186
  "whispercpp-transcription": "whispercpp-transcription";
187
+ "bci-whispercpp-transcription": "bci-whispercpp-transcription";
181
188
  "llamacpp-embedding": "llamacpp-embedding";
182
189
  "nmtcpp-translation": "nmtcpp-translation";
183
190
  "onnx-tts": "onnx-tts";
@@ -189,6 +196,7 @@ export declare const nmtPlugin: {
189
196
  "ggml-classification": "ggml-classification";
190
197
  llm: "llm";
191
198
  whisper: "whisper";
199
+ bci: "bci";
192
200
  nmt: "nmt";
193
201
  parakeet: "parakeet";
194
202
  classification: "classification";
@@ -226,6 +234,7 @@ export declare const nmtPlugin: {
226
234
  vla: "vla";
227
235
  "llamacpp-completion": "llamacpp-completion";
228
236
  "whispercpp-transcription": "whispercpp-transcription";
237
+ "bci-whispercpp-transcription": "bci-whispercpp-transcription";
229
238
  "llamacpp-embedding": "llamacpp-embedding";
230
239
  "nmtcpp-translation": "nmtcpp-translation";
231
240
  "onnx-tts": "onnx-tts";
@@ -237,6 +246,7 @@ export declare const nmtPlugin: {
237
246
  "ggml-classification": "ggml-classification";
238
247
  llm: "llm";
239
248
  whisper: "whisper";
249
+ bci: "bci";
240
250
  nmt: "nmt";
241
251
  parakeet: "parakeet";
242
252
  classification: "classification";
@@ -261,6 +271,7 @@ export declare const nmtPlugin: {
261
271
  vla: "vla";
262
272
  "llamacpp-completion": "llamacpp-completion";
263
273
  "whispercpp-transcription": "whispercpp-transcription";
274
+ "bci-whispercpp-transcription": "bci-whispercpp-transcription";
264
275
  "llamacpp-embedding": "llamacpp-embedding";
265
276
  "nmtcpp-translation": "nmtcpp-translation";
266
277
  "onnx-tts": "onnx-tts";
@@ -272,6 +283,7 @@ export declare const nmtPlugin: {
272
283
  "ggml-classification": "ggml-classification";
273
284
  llm: "llm";
274
285
  whisper: "whisper";
286
+ bci: "bci";
275
287
  nmt: "nmt";
276
288
  parakeet: "parakeet";
277
289
  classification: "classification";
@@ -296,6 +308,7 @@ export declare const nmtPlugin: {
296
308
  vla: "vla";
297
309
  "llamacpp-completion": "llamacpp-completion";
298
310
  "whispercpp-transcription": "whispercpp-transcription";
311
+ "bci-whispercpp-transcription": "bci-whispercpp-transcription";
299
312
  "llamacpp-embedding": "llamacpp-embedding";
300
313
  "nmtcpp-translation": "nmtcpp-translation";
301
314
  "onnx-tts": "onnx-tts";
@@ -307,6 +320,7 @@ export declare const nmtPlugin: {
307
320
  "ggml-classification": "ggml-classification";
308
321
  llm: "llm";
309
322
  whisper: "whisper";
323
+ bci: "bci";
310
324
  nmt: "nmt";
311
325
  parakeet: "parakeet";
312
326
  classification: "classification";
@@ -40,6 +40,7 @@ export declare const ocrPlugin: {
40
40
  vla: "vla";
41
41
  "llamacpp-completion": "llamacpp-completion";
42
42
  "whispercpp-transcription": "whispercpp-transcription";
43
+ "bci-whispercpp-transcription": "bci-whispercpp-transcription";
43
44
  "llamacpp-embedding": "llamacpp-embedding";
44
45
  "nmtcpp-translation": "nmtcpp-translation";
45
46
  "onnx-tts": "onnx-tts";
@@ -51,6 +52,7 @@ export declare const ocrPlugin: {
51
52
  "ggml-classification": "ggml-classification";
52
53
  llm: "llm";
53
54
  whisper: "whisper";
55
+ bci: "bci";
54
56
  nmt: "nmt";
55
57
  parakeet: "parakeet";
56
58
  classification: "classification";
@@ -36,6 +36,10 @@ export declare const parakeetPlugin: {
36
36
  encoderTime: import("zod").ZodOptional<import("zod").ZodNumber>;
37
37
  decoderTime: import("zod").ZodOptional<import("zod").ZodNumber>;
38
38
  melSpecTime: import("zod").ZodOptional<import("zod").ZodNumber>;
39
+ backendDevice: import("zod").ZodOptional<import("zod").ZodNumber>;
40
+ backendId: import("zod").ZodOptional<import("zod").ZodNumber>;
41
+ gpuMemTotalMb: import("zod").ZodOptional<import("zod").ZodNumber>;
42
+ gpuMemFreeMb: import("zod").ZodOptional<import("zod").ZodNumber>;
39
43
  }, import("zod/v4/core").$strip>>;
40
44
  error: import("zod").ZodOptional<import("zod").ZodString>;
41
45
  segment: import("zod").ZodOptional<import("zod").ZodObject<{
@@ -94,6 +98,10 @@ export declare const parakeetPlugin: {
94
98
  encoderTime: import("zod").ZodOptional<import("zod").ZodNumber>;
95
99
  decoderTime: import("zod").ZodOptional<import("zod").ZodNumber>;
96
100
  melSpecTime: import("zod").ZodOptional<import("zod").ZodNumber>;
101
+ backendDevice: import("zod").ZodOptional<import("zod").ZodNumber>;
102
+ backendId: import("zod").ZodOptional<import("zod").ZodNumber>;
103
+ gpuMemTotalMb: import("zod").ZodOptional<import("zod").ZodNumber>;
104
+ gpuMemFreeMb: import("zod").ZodOptional<import("zod").ZodNumber>;
97
105
  }, import("zod/v4/core").$strip>>;
98
106
  error: import("zod").ZodOptional<import("zod").ZodString>;
99
107
  segment: import("zod").ZodOptional<import("zod").ZodObject<{
@@ -75,7 +75,7 @@ function asVideoModel(model, modelId) {
75
75
  export async function* video(request) {
76
76
  const env_1 = { stack: [], error: void 0, hasError: false };
77
77
  try {
78
- const ctx = __addDisposableResource(env_1, getRequestRegistry().begin({
78
+ const ctx = __addDisposableResource(env_1, await getRequestRegistry().begin({
79
79
  requestId: request.requestId ?? generateServerRequestId(),
80
80
  kind: "diffusion",
81
81
  modelId: request.modelId,
@@ -134,6 +134,12 @@ export async function* video(request) {
134
134
  ...(request.vace_strength !== undefined && {
135
135
  vace_strength: request.vace_strength,
136
136
  }),
137
+ ...(request.init_image !== undefined && {
138
+ init_image: Buffer.from(request.init_image, "base64"),
139
+ }),
140
+ ...(request.strength !== undefined && {
141
+ strength: request.strength,
142
+ }),
137
143
  ...(request.control_frames !== undefined && {
138
144
  control_frames: request.control_frames.map((b64) => Buffer.from(b64, "base64")),
139
145
  }),