@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,77 @@
1
+ /**
2
+ * Streaming BCI transcription from a neural-signal file.
3
+ *
4
+ * Reads a raw neural-signal `.bin` file and feeds it to the BCI
5
+ * (whisper.cpp) addon chunk-by-chunk through a duplex `bciTranscribeStream`
6
+ * session, printing transcript text as the sliding window decodes
7
+ * successive windows.
8
+ *
9
+ * Usage: bun run examples/bci/bci-filesystem-streaming.ts <neural-bin-file-path>
10
+ */
11
+ import { loadModel, unloadModel, bciTranscribeStream, BCI_WINDOWED, } from "@qvac/sdk";
12
+ import { readFileSync } from "fs";
13
+ const args = process.argv.slice(2);
14
+ if (!args[0]) {
15
+ console.error("Usage: bun run examples/bci/bci-filesystem-streaming.ts <neural-bin-file-path>");
16
+ process.exit(1);
17
+ }
18
+ const neuralFilePath = args[0];
19
+ // Feed the neural buffer in fixed-size chunks to simulate a live stream.
20
+ const CHUNK_SIZE = 64 * 1024;
21
+ try {
22
+ console.log("=== BCI transcribeStream file test ===");
23
+ console.log(`File: ${neuralFilePath}`);
24
+ console.log(`Chunk size: ${CHUNK_SIZE} bytes\n`);
25
+ console.log("Loading model...");
26
+ const modelId = await loadModel({
27
+ modelSrc: BCI_WINDOWED,
28
+ modelConfig: {
29
+ whisperConfig: {
30
+ language: "en",
31
+ n_threads: 4,
32
+ temperature: 0.0,
33
+ },
34
+ // Session day index selects the day-specific projection matrices.
35
+ // Set this to match the recording session your neural file came from.
36
+ bciConfig: {
37
+ day_idx: 1,
38
+ },
39
+ },
40
+ });
41
+ console.log(`Model loaded: ${modelId}\n`);
42
+ console.log("Opening live session...");
43
+ const session = await bciTranscribeStream({ modelId, emit: "delta" });
44
+ console.log("Session open. Streaming neural signal...\n");
45
+ // Drain the session concurrently with writing so the sliding-window
46
+ // decode can make progress as chunks arrive instead of stalling.
47
+ const consume = (async () => {
48
+ let transcript = "";
49
+ for await (const text of session) {
50
+ transcript += text;
51
+ process.stdout.write(text);
52
+ }
53
+ return transcript;
54
+ })();
55
+ const data = readFileSync(neuralFilePath);
56
+ let totalBytes = 0;
57
+ for (let offset = 0; offset < data.length; offset += CHUNK_SIZE) {
58
+ const chunk = data.subarray(offset, offset + CHUNK_SIZE);
59
+ session.write(chunk);
60
+ totalBytes += chunk.length;
61
+ await new Promise((resolve) => setTimeout(resolve, 10));
62
+ }
63
+ console.log(`\n\nNeural signal streamed: ${totalBytes} bytes`);
64
+ console.log("Waiting for transcription to finish...\n");
65
+ session.end();
66
+ const transcript = await consume;
67
+ console.log("\n=== Results ===");
68
+ console.log(`Transcript: ${transcript.trim() || "(no text received)"}`);
69
+ console.log("\nUnloading model...");
70
+ await unloadModel({ modelId });
71
+ console.log("Done.");
72
+ process.exit(0);
73
+ }
74
+ catch (error) {
75
+ console.error("❌ Error:", error);
76
+ process.exit(1);
77
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bci-filesystem.d.ts.map
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Batch BCI transcription from a neural-signal file.
3
+ *
4
+ * Reads a raw neural-signal `.bin` file, runs it through the BCI
5
+ * (whisper.cpp) addon in one shot via `bciTranscribe`, and prints the
6
+ * decoded transcript.
7
+ *
8
+ * Usage: bun run examples/bci/bci-filesystem.ts <neural-bin-file-path>
9
+ */
10
+ import { loadModel, unloadModel, bciTranscribe, BCI_WINDOWED } from "@qvac/sdk";
11
+ const args = process.argv.slice(2);
12
+ if (!args[0]) {
13
+ console.error("Usage: bun run examples/bci/bci-filesystem.ts <neural-bin-file-path>");
14
+ process.exit(1);
15
+ }
16
+ const neuralFilePath = args[0];
17
+ try {
18
+ console.log("🧠 Starting BCI transcription example...");
19
+ console.log("📥 Loading BCI model...");
20
+ const modelId = await loadModel({
21
+ modelSrc: BCI_WINDOWED,
22
+ modelConfig: {
23
+ whisperConfig: {
24
+ language: "en",
25
+ n_threads: 4,
26
+ temperature: 0.0,
27
+ },
28
+ // Session day index selects the day-specific projection matrices.
29
+ // Set this to match the recording session your neural file came from.
30
+ bciConfig: {
31
+ day_idx: 1,
32
+ },
33
+ },
34
+ onProgress: (progress) => {
35
+ console.log(progress);
36
+ },
37
+ });
38
+ console.log(`✅ BCI model loaded with ID: ${modelId}`);
39
+ console.log("🧠 Transcribing neural signal...");
40
+ const segments = await bciTranscribe({
41
+ modelId,
42
+ neuralData: neuralFilePath,
43
+ metadata: true,
44
+ });
45
+ console.log("📝 Transcription result:");
46
+ for (const segment of segments) {
47
+ const start = (segment.startMs / 1000).toFixed(2);
48
+ const end = (segment.endMs / 1000).toFixed(2);
49
+ console.log(` [${start}s → ${end}s] (id=${segment.id}, append=${segment.append}) ${segment.text}`);
50
+ }
51
+ console.log(`\nFull transcript: ${segments
52
+ .map((s) => s.text)
53
+ .join("")
54
+ .trim()}`);
55
+ console.log("🧹 Unloading BCI model...");
56
+ await unloadModel({ modelId });
57
+ console.log("✅ BCI model unloaded successfully");
58
+ process.exit(0);
59
+ }
60
+ catch (error) {
61
+ console.error("❌ Error:", error);
62
+ process.exit(1);
63
+ }
@@ -56,7 +56,6 @@ try {
56
56
  console.log(" Loading model into memory...");
57
57
  modelId = await loadModel({
58
58
  modelSrc: WHISPER_TINY,
59
- modelType: "whisper",
60
59
  });
61
60
  console.log(` ✅ Model loaded! ID: ${modelId}`);
62
61
  const afterLoad = await getModelInfo(WHISPER_TINY);
@@ -38,7 +38,6 @@ import { cancel, completion, loadModel, unloadModel, InferenceCancelledError, QW
38
38
  try {
39
39
  const modelId = await loadModel({
40
40
  modelSrc: QWEN3_600M_INST_Q4,
41
- modelType: "llm",
42
41
  modelConfig: { ctx_size: 4096 },
43
42
  });
44
43
  const run = completion({
@@ -1,5 +1,5 @@
1
1
  import fs from "fs";
2
- import { startQVACProvider, stopQVACProvider, loadModel, classify, unloadModel } from "@qvac/sdk";
2
+ import { startQVACProvider, stopQVACProvider, loadModel, classify, unloadModel, } from "@qvac/sdk";
3
3
  /**
4
4
  * Classify an image using the bundled MobileNetV3-Small model.
5
5
  *
@@ -18,14 +18,15 @@ import { completion, loadModel, unloadModel, QWEN3_600M_INST_Q4, } from "@qvac/s
18
18
  try {
19
19
  const modelId = await loadModel({
20
20
  modelSrc: QWEN3_600M_INST_Q4,
21
- modelType: "llm",
22
21
  modelConfig: { ctx_size: 4096 },
23
22
  onProgress: (p) => console.log(`Loading: ${p.percentage.toFixed(1)}%`),
24
23
  });
25
24
  console.log(`✅ Model loaded: ${modelId}\n`);
26
25
  const result = completion({
27
26
  modelId,
28
- history: [{ role: "user", content: "Explain quantum computing in 2 sentences" }],
27
+ history: [
28
+ { role: "user", content: "Explain quantum computing in 2 sentences" },
29
+ ],
29
30
  stream: true,
30
31
  captureThinking: true,
31
32
  });
@@ -44,6 +45,9 @@ try {
44
45
  if (final.toolCalls.length > 0) {
45
46
  console.log(`Tool calls: ${final.toolCalls.map((c) => c.name).join(", ")}`);
46
47
  }
48
+ if (final.stopReason) {
49
+ console.log(`Stop reason: ${final.stopReason}`);
50
+ }
47
51
  console.log(`Raw output length: ${final.raw.fullText.length} chars`);
48
52
  await unloadModel({ modelId, clearStorage: false });
49
53
  }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Demonstrates `stopReason` on `CompletionFinal`.
3
+ *
4
+ * `completion()` sets `stopReason` on the aggregated `final` promise to
5
+ * indicate why the model stopped generating:
6
+ *
7
+ * - `undefined` — natural end-of-sequence (EOS). The model finished on
8
+ * its own. This is the common case and the backwards-
9
+ * compatible default.
10
+ * - `"length"` — the `predict` token budget was exhausted. Output is
11
+ * truncated; the model did not reach a natural stopping
12
+ * point.
13
+ * - `"cancelled"` — the request was cancelled via `cancel({ requestId })`.
14
+ * See `cancel-by-request-id.ts` for the full cancel flow.
15
+ *
16
+ * This example shows the two non-cancel cases back-to-back on the same model:
17
+ *
18
+ * 1. Natural EOS — no `generationParams`, model stops on its own.
19
+ * 2. Budget hit — `predict: 10` forces truncation mid-output.
20
+ *
21
+ * The same `stopReason` is also available on the terminal `completionDone`
22
+ * event in the `events` stream.
23
+ */
24
+ export {};
25
+ //# sourceMappingURL=completion-stop-reason.d.ts.map
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Demonstrates `stopReason` on `CompletionFinal`.
3
+ *
4
+ * `completion()` sets `stopReason` on the aggregated `final` promise to
5
+ * indicate why the model stopped generating:
6
+ *
7
+ * - `undefined` — natural end-of-sequence (EOS). The model finished on
8
+ * its own. This is the common case and the backwards-
9
+ * compatible default.
10
+ * - `"length"` — the `predict` token budget was exhausted. Output is
11
+ * truncated; the model did not reach a natural stopping
12
+ * point.
13
+ * - `"cancelled"` — the request was cancelled via `cancel({ requestId })`.
14
+ * See `cancel-by-request-id.ts` for the full cancel flow.
15
+ *
16
+ * This example shows the two non-cancel cases back-to-back on the same model:
17
+ *
18
+ * 1. Natural EOS — no `generationParams`, model stops on its own.
19
+ * 2. Budget hit — `predict: 10` forces truncation mid-output.
20
+ *
21
+ * The same `stopReason` is also available on the terminal `completionDone`
22
+ * event in the `events` stream.
23
+ */
24
+ import { completion, loadModel, unloadModel, QWEN3_600M_INST_Q4, } from "@qvac/sdk";
25
+ try {
26
+ const modelId = await loadModel({
27
+ modelSrc: QWEN3_600M_INST_Q4,
28
+ modelConfig: { ctx_size: 4096 },
29
+ onProgress: (p) => console.log(`Loading: ${p.percentage.toFixed(1)}%`),
30
+ });
31
+ console.log(`✅ Model loaded: ${modelId}\n`);
32
+ // --- Case 1: natural EOS ---
33
+ console.log("=== Case 1: natural EOS (no predict limit) ===");
34
+ const run1 = completion({
35
+ modelId,
36
+ history: [{ role: "user", content: "Say hi in one word." }],
37
+ stream: true,
38
+ });
39
+ for await (const event of run1.events) {
40
+ if (event.type === "contentDelta")
41
+ process.stdout.write(event.text);
42
+ }
43
+ const final1 = await run1.final;
44
+ console.log(`\nstopReason: ${final1.stopReason ?? "(undefined — natural EOS)"}`);
45
+ // --- Case 2: predict budget exhausted → stopReason = "length" ---
46
+ console.log("\n=== Case 2: predict budget hit (predict: 10) ===");
47
+ const run2 = completion({
48
+ modelId,
49
+ history: [{ role: "user", content: "Count from 1 to 100, one number per line." }],
50
+ generationParams: { predict: 10 },
51
+ stream: true,
52
+ });
53
+ for await (const event of run2.events) {
54
+ if (event.type === "contentDelta")
55
+ process.stdout.write(event.text);
56
+ }
57
+ const final2 = await run2.final;
58
+ console.log(`\nstopReason: ${final2.stopReason}`);
59
+ await unloadModel({ modelId, clearStorage: false });
60
+ process.exit(0);
61
+ }
62
+ catch (error) {
63
+ console.error("❌ Error:", error);
64
+ process.exit(1);
65
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=concurrent-completion-collision.d.ts.map
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Demonstrates how `qvac serve` handles a coding agent firing two completions
3
+ * at the SAME loaded model at once (e.g. a chat completion plus a
4
+ * title/summary call) — the workload that used to break it.
5
+ *
6
+ * Background: a loaded llama.cpp model is one native context (one KV-cache,
7
+ * one decode loop), so two completions on it cannot truly run in parallel.
8
+ * The SDK worker installs a per-`(kind, modelId)` FIFO admission queue for
9
+ * the `completion` kind (`maxConcurrentPerModel: 1`, `onOverflow: "queue"`).
10
+ * A second concurrent completion on the same model now WAITS its turn and
11
+ * then runs, instead of being rejected with `RequestRejectedByPolicyError`
12
+ * (code 52420) or colliding at the addon with "Cannot set new job".
13
+ *
14
+ * Part 1 — two concurrent completions on the SAME model → both succeed,
15
+ * serialized by the queue (the bug this fixes: previously one was
16
+ * rejected/collided).
17
+ * Part 2 — two concurrent completions on DIFFERENT models → both succeed and
18
+ * run in parallel (the queue is keyed per `(kind, modelId)`, so
19
+ * distinct models never block each other).
20
+ *
21
+ * Run from packages/sdk:
22
+ * bun run examples/concurrent-completion-collision.ts
23
+ */
24
+ import { completion, loadModel, unloadModel, QWEN3_1_7B_INST_Q4, LLAMA_3_2_1B_INST_Q4_0, RequestRejectedByPolicyError, } from "@qvac/sdk";
25
+ async function runCompletion(label, modelId, prompt) {
26
+ try {
27
+ // `completion()` starts the request synchronously, so calling this for two
28
+ // tasks in the same tick puts both "in flight" before either is awaited.
29
+ const result = completion({
30
+ modelId,
31
+ history: [{ role: "user", content: prompt }],
32
+ stream: false,
33
+ });
34
+ const text = await result.text;
35
+ return { label, ok: true, text };
36
+ }
37
+ catch (error) {
38
+ const code = typeof error === "object" && error !== null && "code" in error
39
+ ? error.code
40
+ : undefined;
41
+ const base = {
42
+ label,
43
+ ok: false,
44
+ errorName: error instanceof Error ? error.constructor.name : typeof error,
45
+ message: error instanceof Error ? error.message : String(error),
46
+ };
47
+ return code !== undefined ? { ...base, code } : base;
48
+ }
49
+ }
50
+ function report(title, outcomes) {
51
+ console.log(`\n${title}`);
52
+ for (const o of outcomes) {
53
+ if (o.ok) {
54
+ const preview = o.text.replace(/\s+/g, " ").slice(0, 70);
55
+ console.log(` ✅ ${o.label}: ${preview}${o.text.length > 70 ? "…" : ""}`);
56
+ }
57
+ else {
58
+ const policy = o.code === 52420 ? " (rejected by policy)" : "";
59
+ console.log(` ❌ ${o.label}: ${o.errorName}${o.code !== undefined ? ` [${o.code}]` : ""}${policy} — ${o.message}`);
60
+ }
61
+ }
62
+ }
63
+ try {
64
+ const modelA = await loadModel({
65
+ modelSrc: QWEN3_1_7B_INST_Q4,
66
+ modelConfig: { ctx_size: 4096 },
67
+ });
68
+ // Part 1 — same model, two concurrent completions.
69
+ const sameModel = await Promise.all([
70
+ runCompletion("req-A1", modelA, "What is Bitcoin? One sentence."),
71
+ runCompletion("req-A2", modelA, "What is a hash function? One sentence."),
72
+ ]);
73
+ report("Part 1 — two concurrent completions on the SAME model (expect both to succeed, serialized):", sameModel);
74
+ const rejected = sameModel.filter((o) => !o.ok).length;
75
+ if (rejected === 0) {
76
+ console.log(" → Both succeeded: the second was queued behind the first and ran when the slot freed (no 52420, no addon collision).");
77
+ }
78
+ else {
79
+ console.log(` ⚠️ ${rejected}/2 failed — the FIFO admission queue should have serialized these. Check the completion policy.`);
80
+ }
81
+ // Part 2 — different models, two concurrent completions (the "parallel that works").
82
+ const modelB = await loadModel({
83
+ modelSrc: LLAMA_3_2_1B_INST_Q4_0,
84
+ modelConfig: { ctx_size: 4096 },
85
+ });
86
+ const differentModels = await Promise.all([
87
+ runCompletion("req-A", modelA, "Name one use of Bitcoin. One sentence."),
88
+ runCompletion("req-B", modelB, "Name one use of Ethereum. One sentence."),
89
+ ]);
90
+ report("Part 2 — two concurrent completions on DIFFERENT models (expect both succeed):", differentModels);
91
+ await unloadModel({ modelId: modelA, clearStorage: false });
92
+ await unloadModel({ modelId: modelB, clearStorage: false });
93
+ console.log(`\nrejected-by-policy error available for instanceof checks: ${typeof RequestRejectedByPolicyError === "function"}`);
94
+ }
95
+ catch (error) {
96
+ console.error("❌ Error:", error);
97
+ process.exit(1);
98
+ }
@@ -11,7 +11,6 @@ try {
11
11
  console.log("Loading Whisper model with English config...");
12
12
  const modelId = await loadModel({
13
13
  modelSrc: WHISPER_TINY,
14
- modelType: "whisper",
15
14
  modelConfig: {
16
15
  language: "en",
17
16
  },
@@ -28,7 +27,7 @@ try {
28
27
  console.log("Hot reloading config (changing language and temperature)...");
29
28
  const reloadedId = await loadModel({
30
29
  modelId,
31
- modelType: "whisper",
30
+ modelType: "whispercpp-transcription",
32
31
  modelConfig: {
33
32
  language: "es", // Change to Spanish
34
33
  },
@@ -24,7 +24,6 @@ try {
24
24
  console.log("🚀 Loading model with configured settings...\n");
25
25
  const modelId = await loadModel({
26
26
  modelSrc: LLAMA_3_2_1B_INST_Q4_0,
27
- modelType: "llm",
28
27
  });
29
28
  console.log("\n💬 Running completion...\n");
30
29
  const result = completion({
@@ -56,7 +56,6 @@ async function runDelegatedCompletion(providerPublicKey) {
56
56
  console.log("→ Loading model via delegation...");
57
57
  const modelId = await loadModel({
58
58
  modelSrc: LLAMA_3_2_1B_INST_Q4_0,
59
- modelType: "llm",
60
59
  delegate: {
61
60
  providerPublicKey,
62
61
  timeout: 30_000,
@@ -11,7 +11,6 @@ try {
11
11
  console.log("→ Loading model (delegated, unary)...");
12
12
  const modelId = await loadModel({
13
13
  modelSrc: LLAMA_3_2_1B_INST_Q4_0,
14
- modelType: "llm",
15
14
  delegate: {
16
15
  providerPublicKey,
17
16
  timeout: 60_000,
@@ -18,7 +18,6 @@ try {
18
18
  }
19
19
  const modelId = await loadModel({
20
20
  modelSrc: LLAMA_3_2_1B_INST_Q4_0,
21
- modelType: "llm",
22
21
  delegate: {
23
22
  providerPublicKey,
24
23
  // Generous timeout for the first call on a cold DHT: bootstrapping
@@ -8,8 +8,7 @@ import path from "path";
8
8
  const esrganArg = process.argv[2];
9
9
  const promptArg = process.argv[3];
10
10
  const outputDirArg = process.argv[4];
11
- const esrganModelSrc = esrganArg ??
12
- REALESRGAN_X4PLUS_ANIME_6B;
11
+ const esrganModelSrc = esrganArg ?? REALESRGAN_X4PLUS_ANIME_6B;
13
12
  const prompt = promptArg ??
14
13
  "an illustrated red fox portrait, clean line art, soft watercolor background, detailed fur, crisp eyes";
15
14
  const negative_prompt = "blurry, low quality, watermark, text";
@@ -19,7 +18,6 @@ try {
19
18
  console.log("Loading SD 2.1 + ESRGAN upscaler...");
20
19
  const modelId = await loadModel({
21
20
  modelSrc: SD_V2_1_1B_Q8_0,
22
- modelType: "diffusion",
23
21
  modelConfig: {
24
22
  prediction: "v",
25
23
  upscaler: {
@@ -17,7 +17,7 @@ try {
17
17
  console.log("Loading FLUX.2 [klein] split-layout model...");
18
18
  const modelId = await loadModel({
19
19
  modelSrc: diffusionModelSrc,
20
- modelType: "diffusion",
20
+ modelType: "sdcpp-generation",
21
21
  modelConfig: {
22
22
  device: "gpu",
23
23
  threads: 4,
@@ -1,4 +1,4 @@
1
- import { loadModel, unloadModel, diffusion, FLUX_2_KLEIN_4B_Q4_0, FLUX_2_KLEIN_4B_VAE, QWEN3_4B_Q4_K_M } from "@qvac/sdk";
1
+ import { loadModel, unloadModel, diffusion, FLUX_2_KLEIN_4B_Q4_0, FLUX_2_KLEIN_4B_VAE, QWEN3_4B_Q4_K_M, } from "@qvac/sdk";
2
2
  import fs from "fs";
3
3
  import path from "path";
4
4
  // FLUX.2 [klein] uses a split-layout: separate diffusion model + LLM text encoder + VAE
@@ -10,7 +10,7 @@ const outputDir = process.argv[6] || ".";
10
10
  console.log("Loading FLUX.2 [klein] split-layout model...");
11
11
  const modelId = await loadModel({
12
12
  modelSrc: diffusionModelSrc,
13
- modelType: "diffusion",
13
+ modelType: "sdcpp-generation",
14
14
  modelConfig: {
15
15
  device: "gpu",
16
16
  threads: 4,
@@ -15,7 +15,7 @@ try {
15
15
  console.log("Loading diffusion model...");
16
16
  const modelId = await loadModel({
17
17
  modelSrc,
18
- modelType: "diffusion",
18
+ modelType: "sdcpp-generation",
19
19
  });
20
20
  console.log(`Model loaded: ${modelId}`);
21
21
  const init_image = new Uint8Array(fs.readFileSync(inputPath));
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=diffusion-img2vid.d.ts.map
@@ -0,0 +1,78 @@
1
+ import { loadModel, unloadModel, video, WAN2_1_I2V_14B_Q4_K_M, CLIP_VISION_H, UMT5_XXL_FP16, WAN_2_1_COMFYUI_REPACKAGED_VAE, } from "@qvac/sdk";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ // Image-to-video with Wan 2.1 I2V. Requires a Wan I2V diffusion checkpoint (GGUF
5
+ // recommended), plus UMT5-XXL, Wan VAE, and CLIP vision weights. The model
6
+ // sources default to the bundled registry constants, so the common case is just
7
+ // an init image path.
8
+ const initImagePath = process.argv[2];
9
+ const prompt = process.argv[3] ||
10
+ "the subject slowly turns and smiles, soft natural lighting, cinematic";
11
+ const outputDir = process.argv[4] || ".";
12
+ const diffusionModelSrc = process.argv[5] || WAN2_1_I2V_14B_Q4_K_M;
13
+ const t5XxlModelSrc = process.argv[6] || UMT5_XXL_FP16;
14
+ const vaeModelSrc = process.argv[7] || WAN_2_1_COMFYUI_REPACKAGED_VAE;
15
+ const clipVisionModelSrc = process.argv[8] || CLIP_VISION_H;
16
+ if (!initImagePath) {
17
+ console.error("❌ Error: init image path is required");
18
+ console.error("Usage: bun run bare:example dist/examples/diffusion-img2vid.js " +
19
+ "<initImagePath> [prompt] [outputDir] " +
20
+ "[i2vModelSrc] [t5XxlModelSrc] [vaeModelSrc] [clipVisionModelSrc]");
21
+ process.exit(1);
22
+ }
23
+ try {
24
+ console.log("Loading Wan 2.1 I2V model (diffusion + UMT5-XXL + VAE + CLIP vision)...");
25
+ const modelId = await loadModel({
26
+ modelSrc: diffusionModelSrc,
27
+ modelType: "diffusion",
28
+ modelConfig: {
29
+ mode: "video",
30
+ device: "gpu",
31
+ threads: 4,
32
+ t5XxlModelSrc,
33
+ vaeModelSrc,
34
+ clipVisionModelSrc,
35
+ diffusion_fa: true,
36
+ offload_to_cpu: true,
37
+ vae_on_cpu: true,
38
+ vae_tiling: true,
39
+ },
40
+ onProgress: (p) => console.log(`Loading: ${p.percentage.toFixed(1)}%`),
41
+ });
42
+ console.log(`Model loaded: ${modelId}`);
43
+ const init_image = new Uint8Array(fs.readFileSync(initImagePath));
44
+ console.log(`\nGenerating video for: "${prompt}"`);
45
+ const { progressStream, outputs, stats } = video({
46
+ modelId,
47
+ mode: "img2vid",
48
+ prompt,
49
+ init_image,
50
+ negative_prompt: "blurry, distorted, low quality, jittery, static, frozen",
51
+ strength: 0.85,
52
+ flow_shift: 3.0,
53
+ video_frames: 33,
54
+ fps: 16,
55
+ steps: 30,
56
+ cfg_scale: 6.0,
57
+ seed: 42,
58
+ vae_tiling: true,
59
+ });
60
+ for await (const { step, totalSteps } of progressStream) {
61
+ process.stdout.write(`\rStep ${step}/${totalSteps}`);
62
+ }
63
+ console.log();
64
+ const buffers = await outputs;
65
+ for (let i = 0; i < buffers.length; i++) {
66
+ const outputPath = path.join(outputDir, `wan_i2v_${i}.avi`);
67
+ fs.writeFileSync(outputPath, buffers[i]);
68
+ console.log(`Saved: ${outputPath}`);
69
+ }
70
+ console.log("\nStats:", await stats);
71
+ await unloadModel({ modelId, clearStorage: false });
72
+ console.log("Done.");
73
+ process.exit(0);
74
+ }
75
+ catch (error) {
76
+ console.error("❌ Error:", error);
77
+ process.exit(1);
78
+ }
@@ -6,7 +6,7 @@ const modelSrc = process.argv[2] || SD_V2_1_1B_Q8_0;
6
6
  const prompt = process.argv[3] || "a photo of a cat sitting on a windowsill";
7
7
  const modelId = await loadModel({
8
8
  modelSrc,
9
- modelType: "diffusion",
9
+ modelType: "sdcpp-generation",
10
10
  modelConfig: { prediction: "v" },
11
11
  });
12
12
  const { outputs } = diffusion({ modelId, prompt });
@@ -1,4 +1,4 @@
1
- import { loadModel, unloadModel, diffusion, FLUX_2_KLEIN_4B_Q4_0, FLUX_2_KLEIN_4B_VAE, QWEN3_4B_Q4_K_M } from "@qvac/sdk";
1
+ import { loadModel, unloadModel, diffusion, FLUX_2_KLEIN_4B_Q4_0, FLUX_2_KLEIN_4B_VAE, QWEN3_4B_Q4_K_M, } from "@qvac/sdk";
2
2
  import fs from "fs";
3
3
  import path from "path";
4
4
  const modelSrc = process.argv[2] || FLUX_2_KLEIN_4B_Q4_0;
@@ -9,8 +9,13 @@ console.log(`Loading diffusion model...`);
9
9
  // FLUX.2 models require companion LLM + VAE models
10
10
  const modelId = await loadModel({
11
11
  modelSrc,
12
- modelType: "diffusion",
13
- modelConfig: { device: "gpu", threads: 4, llmModelSrc: QWEN3_4B_Q4_K_M, vaeModelSrc: FLUX_2_KLEIN_4B_VAE },
12
+ modelType: "sdcpp-generation",
13
+ modelConfig: {
14
+ device: "gpu",
15
+ threads: 4,
16
+ llmModelSrc: QWEN3_4B_Q4_K_M,
17
+ vaeModelSrc: FLUX_2_KLEIN_4B_VAE,
18
+ },
14
19
  onProgress: (p) => console.log(`Loading: ${p.percentage.toFixed(1)}%`),
15
20
  });
16
21
  console.log(`Model loaded: ${modelId}`);
@@ -11,14 +11,13 @@ const vaeModelSrc = process.argv[4] || WAN_2_1_COMFYUI_REPACKAGED_VAE;
11
11
  // Prompt tip: Wan 1.3B is small and has weak temporal priors. Use motion-
12
12
  // explicit verbs and avoid static framing words like "standing", "still",
13
13
  // or "portrait" in the positive prompt.
14
- const prompt = process.argv[5] ||
15
- "a colorful bird flapping its wings";
14
+ const prompt = process.argv[5] || "a colorful bird flapping its wings";
16
15
  const outputDir = process.argv[6] || ".";
17
16
  try {
18
17
  console.log("Loading Wan 2.1 T2V model (diffusion + UMT5-XXL + VAE)...");
19
18
  const modelId = await loadModel({
20
19
  modelSrc: diffusionModelSrc,
21
- modelType: "diffusion",
20
+ modelType: "sdcpp-generation",
22
21
  modelConfig: {
23
22
  mode: "video",
24
23
  device: "gpu",
@@ -15,7 +15,6 @@ try {
15
15
  const startTime = Date.now();
16
16
  const modelId = await loadModel({
17
17
  modelSrc: LLAMA_3_2_1B_INST_Q4_0,
18
- modelType: "llm",
19
18
  });
20
19
  console.log(`Model loaded with ID: ${modelId}`);
21
20
  const firstStatus = await getModelInfo(LLAMA_3_2_1B_INST_Q4_0);
@@ -1,4 +1,4 @@
1
- import { loadModel, embed, unloadModel, EMBEDDINGGEMMA_300M_Q8_0 } from "@qvac/sdk";
1
+ import { loadModel, embed, unloadModel, EMBEDDINGGEMMA_300M_Q8_0, } from "@qvac/sdk";
2
2
  // Multi-GPU embedding distributes model layers across multiple GPUs using
3
3
  // llama.cpp's built-in split modes. Two strategies are available:
4
4
  //
@@ -15,7 +15,6 @@ import { loadModel, embed, unloadModel, EMBEDDINGGEMMA_300M_Q8_0 } from "@qvac/s
15
15
  try {
16
16
  const modelId = await loadModel({
17
17
  modelSrc: EMBEDDINGGEMMA_300M_Q8_0,
18
- modelType: "llamacpp-embedding",
19
18
  modelConfig: {
20
19
  splitMode: "layer",
21
20
  tensorSplit: "1,1",