@qvac/sdk 0.13.5 → 0.14.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 (221) hide show
  1. package/NOTICE +95 -1151
  2. package/README.md +1 -2
  3. package/bare-imports.json +0 -5
  4. package/dist/client/api/bci-transcribe.js +2 -1
  5. package/dist/client/api/download-asset.js +2 -1
  6. package/dist/client/api/finetune.js +6 -5
  7. package/dist/client/api/index.d.ts +1 -0
  8. package/dist/client/api/index.js +1 -0
  9. package/dist/client/api/load-model.d.ts +11 -8
  10. package/dist/client/api/load-model.js +6 -6
  11. package/dist/client/api/subscribe-logs.d.ts +28 -0
  12. package/dist/client/api/subscribe-logs.js +43 -0
  13. package/dist/client/api/text-to-speech.js +2 -1
  14. package/dist/client/config-loader/config-utils.js +2 -4
  15. package/dist/client/config-loader/resolve-config.bare.js +4 -3
  16. package/dist/client/parse-input.d.ts +3 -0
  17. package/dist/client/parse-input.js +14 -0
  18. package/dist/client/rpc/expo-rpc-client.js +2 -11
  19. package/dist/client/rpc/node-rpc-client.js +8 -2
  20. package/dist/client/rpc/rpc-client.js +39 -7
  21. package/dist/commands/bundle/constants.js +2 -1
  22. package/dist/examples/bci/bci-filesystem-streaming.js +14 -14
  23. package/dist/examples/bci/bci-filesystem.js +17 -13
  24. package/dist/examples/cache-management.js +38 -38
  25. package/dist/examples/cancel-by-request-id.js +9 -9
  26. package/dist/examples/completion-events.js +20 -14
  27. package/dist/examples/completion-stop-reason.js +13 -7
  28. package/dist/examples/concurrent-completion-collision.js +7 -7
  29. package/dist/examples/config-reload.js +7 -8
  30. package/dist/examples/default-config-usage.js +4 -4
  31. package/dist/examples/delegated-inference/composite.js +14 -10
  32. package/dist/examples/delegated-inference/consumer-profiled.js +13 -13
  33. package/dist/examples/delegated-inference/consumer.js +16 -12
  34. package/dist/examples/delegated-inference/provider.js +12 -12
  35. package/dist/examples/diffusion-esrgan-upscale.js +19 -15
  36. package/dist/examples/diffusion-flux2-klein-img2img.js +16 -11
  37. package/dist/examples/diffusion-flux2-klein.js +14 -9
  38. package/dist/examples/diffusion-img2img.js +9 -10
  39. package/dist/examples/diffusion-img2vid.js +17 -12
  40. package/dist/examples/diffusion-simple.js +1 -1
  41. package/dist/examples/diffusion-txt2img.js +14 -9
  42. package/dist/examples/diffusion-txt2vid.js +15 -10
  43. package/dist/examples/download-with-blind-relays.js +16 -21
  44. package/dist/examples/download-with-cancel.js +15 -16
  45. package/dist/examples/embed-multi-gpu.js +3 -4
  46. package/dist/examples/embed-p2p.js +11 -7
  47. package/dist/examples/finetune/llamacpp-finetune.js +7 -7
  48. package/dist/examples/kv-cache-cleanup.js +35 -35
  49. package/dist/examples/kv-cache-custom-key.js +24 -24
  50. package/dist/examples/kv-cache-example.js +9 -9
  51. package/dist/examples/llamacpp-cache.js +18 -14
  52. package/dist/examples/llamacpp-dynamic-tools.js +15 -9
  53. package/dist/examples/llamacpp-filesystem.js +15 -9
  54. package/dist/examples/llamacpp-http.js +12 -10
  55. package/dist/examples/llamacpp-multi-gpu.js +4 -4
  56. package/dist/examples/llamacpp-multimodal.js +13 -9
  57. package/dist/examples/llamacpp-p2p.js +8 -4
  58. package/dist/examples/llamacpp-sharded.js +5 -5
  59. package/dist/examples/llamacpp-structured-output.js +15 -9
  60. package/dist/examples/logging-file-transport.js +3 -3
  61. package/dist/examples/logging-global.d.ts +2 -0
  62. package/dist/examples/logging-global.js +34 -0
  63. package/dist/examples/logging-streaming.js +7 -10
  64. package/dist/examples/mcp-websearch.js +24 -18
  65. package/dist/examples/multi-model-demo.js +17 -11
  66. package/dist/examples/ocr-fasttext.js +14 -16
  67. package/dist/examples/parallel-download.js +7 -7
  68. package/dist/examples/plugins.js +40 -28
  69. package/dist/examples/profiling/basic.js +16 -10
  70. package/dist/examples/profiling/per-call.js +17 -11
  71. package/dist/examples/quickstart.bare.d.ts +2 -0
  72. package/dist/examples/quickstart.bare.js +18 -0
  73. package/dist/examples/quickstart.js +10 -3
  74. package/dist/examples/rag/rag-chromadb.js +18 -14
  75. package/dist/examples/rag/rag-hyperdb/cancellation.js +17 -14
  76. package/dist/examples/rag/rag-hyperdb/ingest.js +14 -12
  77. package/dist/examples/rag/rag-hyperdb/pipeline.js +19 -17
  78. package/dist/examples/rag/rag-hyperdb/workspaces.js +31 -27
  79. package/dist/examples/rag/rag-lancedb.js +12 -8
  80. package/dist/examples/rag/rag-sqlite.js +11 -7
  81. package/dist/examples/registry-query.js +17 -17
  82. package/dist/examples/seed-p2p.js +10 -6
  83. package/dist/examples/suspend-resume.js +20 -16
  84. package/dist/examples/tools/llamacpp-native-tools.js +24 -18
  85. package/dist/examples/tools/llamacpp-tools-gemma4.js +14 -8
  86. package/dist/examples/tools/llamacpp-tools-harmony-multiturn.js +20 -14
  87. package/dist/examples/tools/llamacpp-tools-pythonic.js +14 -8
  88. package/dist/examples/tools/llamacpp-tools-qwen35.js +14 -8
  89. package/dist/examples/transcription/parakeet-ctc-filesystem.js +12 -9
  90. package/dist/examples/transcription/parakeet-microphone-record.js +15 -9
  91. package/dist/examples/transcription/parakeet-microphone-stream.js +15 -9
  92. package/dist/examples/transcription/parakeet-sortformer-streaming.js +12 -6
  93. package/dist/examples/transcription/parakeet-sortformer.js +3 -5
  94. package/dist/examples/transcription/parakeet-tdt-filesystem.js +13 -10
  95. package/dist/examples/transcription/whispercpp-filesystem-streaming.js +16 -17
  96. package/dist/examples/transcription/whispercpp-filesystem.js +14 -10
  97. package/dist/examples/transcription/whispercpp-microphone-conversation.js +10 -10
  98. package/dist/examples/transcription/whispercpp-microphone-record.js +6 -6
  99. package/dist/examples/transcription/whispercpp-prompt.js +14 -10
  100. package/dist/examples/translation/translation-bergamot-batch.js +11 -7
  101. package/dist/examples/translation/translation-bergamot-pivot.js +13 -9
  102. package/dist/examples/translation/translation-bergamot.js +8 -4
  103. package/dist/examples/translation/translation-indic.js +8 -4
  104. package/dist/examples/translation/translation-llm-afriquegemma.js +7 -3
  105. package/dist/examples/translation/translation-llm-context.js +8 -4
  106. package/dist/examples/translation/translation-llm.js +7 -3
  107. package/dist/examples/translation/translation-stream.js +4 -4
  108. package/dist/examples/tts/chatterbox.js +19 -11
  109. package/dist/examples/tts/llm-to-tts-streaming.js +27 -14
  110. package/dist/examples/tts/supertonic-multilingual.js +18 -14
  111. package/dist/examples/tts/supertonic.js +19 -15
  112. package/dist/examples/tts/utils.js +1 -1
  113. package/dist/examples/vla-pi05.js +18 -14
  114. package/dist/examples/vla-smolvla.js +18 -14
  115. package/dist/examples/voice-assistant/voice-assistant.js +12 -12
  116. package/dist/index.d.ts +3 -4
  117. package/dist/index.js +3 -4
  118. package/dist/logging/client-logger.js +2 -1
  119. package/dist/logging/index.d.ts +1 -1
  120. package/dist/logging/index.js +1 -1
  121. package/dist/logging/namespaces.d.ts +1 -0
  122. package/dist/logging/namespaces.js +2 -0
  123. package/dist/logging/server-logger.js +1 -4
  124. package/dist/logging/utils.js +6 -1
  125. package/dist/models/registry/index.d.ts +17 -0
  126. package/dist/models/registry/index.js +20 -1
  127. package/dist/models/registry/models.d.ts +1062 -38
  128. package/dist/models/registry/models.js +3546 -2490
  129. package/dist/pear/pre.js +2 -2
  130. package/dist/schemas/bci-config.d.ts +37 -0
  131. package/dist/schemas/bci-config.js +2 -0
  132. package/dist/schemas/bci.d.ts +2 -0
  133. package/dist/schemas/common.d.ts +171 -94
  134. package/dist/schemas/completion-stream.d.ts +6 -3
  135. package/dist/schemas/completion-stream.js +10 -2
  136. package/dist/schemas/download-asset.d.ts +5 -5
  137. package/dist/schemas/engine-addon-map.d.ts +1 -1
  138. package/dist/schemas/engine-addon-map.js +6 -3
  139. package/dist/schemas/error.js +6 -1
  140. package/dist/schemas/llamacpp-config.d.ts +27 -8
  141. package/dist/schemas/llamacpp-config.js +19 -2
  142. package/dist/schemas/load-model.d.ts +4170 -570
  143. package/dist/schemas/load-model.js +85 -26
  144. package/dist/schemas/logging-stream.js +7 -1
  145. package/dist/schemas/model-src-utils.d.ts +6 -6
  146. package/dist/schemas/model-types.d.ts +14 -15
  147. package/dist/schemas/model-types.js +10 -11
  148. package/dist/schemas/ocr.d.ts +10 -8
  149. package/dist/schemas/ocr.js +8 -6
  150. package/dist/schemas/plugin.d.ts +6 -5
  151. package/dist/schemas/plugin.js +4 -4
  152. package/dist/schemas/rag.d.ts +4 -4
  153. package/dist/schemas/registry.d.ts +8 -8
  154. package/dist/schemas/registry.js +1 -1
  155. package/dist/schemas/reload-config.d.ts +6 -6
  156. package/dist/schemas/sdcpp-config.d.ts +12 -12
  157. package/dist/schemas/sdk-config.d.ts +171 -117
  158. package/dist/schemas/sdk-config.js +5 -5
  159. package/dist/schemas/sdk-errors-client.d.ts +1 -0
  160. package/dist/schemas/sdk-errors-client.js +7 -2
  161. package/dist/schemas/text-to-speech.d.ts +157 -13
  162. package/dist/schemas/text-to-speech.js +70 -7
  163. package/dist/schemas/transcription-config.d.ts +5 -1
  164. package/dist/schemas/transcription-config.js +2 -0
  165. package/dist/schemas/transcription.d.ts +3 -0
  166. package/dist/schemas/transcription.js +2 -1
  167. package/dist/schemas/translate.d.ts +6 -6
  168. package/dist/schemas/translate.js +2 -3
  169. package/dist/schemas/translation-config.d.ts +20 -20
  170. package/dist/server/bare/hyperswarm.js +3 -3
  171. package/dist/server/bare/ops/transcribe.js +46 -15
  172. package/dist/server/bare/plugins/bci-whispercpp-transcription/args.d.ts +3 -0
  173. package/dist/server/bare/plugins/bci-whispercpp-transcription/args.js +13 -0
  174. package/dist/server/bare/plugins/bci-whispercpp-transcription/plugin.d.ts +41 -0
  175. package/dist/server/bare/plugins/bci-whispercpp-transcription/plugin.js +6 -11
  176. package/dist/server/bare/plugins/bci-whispercpp-transcription/resolve-config.d.ts +75 -0
  177. package/dist/server/bare/plugins/bci-whispercpp-transcription/resolve-config.js +11 -0
  178. package/dist/server/bare/plugins/{onnx-ocr → ggml-ocr}/plugin.d.ts +16 -10
  179. package/dist/server/bare/plugins/{onnx-ocr → ggml-ocr}/plugin.js +25 -18
  180. package/dist/server/bare/plugins/index.d.ts +1 -1
  181. package/dist/server/bare/plugins/index.js +1 -1
  182. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stats.d.ts +10 -0
  183. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stats.js +29 -0
  184. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +4 -22
  185. package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +15 -7
  186. package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +7 -7
  187. package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +2 -0
  188. package/dist/server/bare/plugins/sdcpp-generation/plugin.d.ts +10 -10
  189. package/dist/server/bare/plugins/tts-ggml/plugin.d.ts +14 -8
  190. package/dist/server/bare/plugins/tts-ggml/plugin.js +12 -0
  191. package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +3 -1
  192. package/dist/server/bare/registry/logging-stream-registry.d.ts +4 -2
  193. package/dist/server/bare/registry/logging-stream-registry.js +12 -7
  194. package/dist/server/bare/registry/model-config-utils.js +2 -2
  195. package/dist/server/bare/registry/registry-client.js +1 -1
  196. package/dist/server/bare/runtime-lifecycle.d.ts +9 -0
  197. package/dist/server/bare/runtime-lifecycle.js +24 -0
  198. package/dist/server/bare/types/addon-responses.d.ts +1 -0
  199. package/dist/server/env.js +7 -10
  200. package/dist/server/plugins/registry.js +2 -4
  201. package/dist/server/rpc/handlers/load-model/handler.js +2 -4
  202. package/dist/server/rpc/handlers/load-model/http.js +253 -51
  203. package/dist/server/rpc/handlers/logging-stream.js +4 -2
  204. package/dist/server/rpc/handlers/plugin-invoke.js +5 -16
  205. package/dist/server/utils/completion-normalizer.js +13 -4
  206. package/dist/server/utils/worker-lock.js +5 -5
  207. package/dist/server/worker-core.d.ts +1 -1
  208. package/dist/server/worker-core.js +28 -18
  209. package/dist/utils/errors-client.d.ts +3 -0
  210. package/dist/utils/errors-client.js +5 -0
  211. package/dist/utils/errors-server.d.ts +2 -0
  212. package/dist/utils/errors-server.js +3 -0
  213. package/dist/utils/zod-error.d.ts +3 -0
  214. package/dist/utils/zod-error.js +4 -0
  215. package/package.json +21 -24
  216. package/dist/polyfills/bare-globals.d.ts +0 -2
  217. package/dist/polyfills/bare-globals.js +0 -4
  218. package/dist/polyfills/bare-globals.noop.d.ts +0 -2
  219. package/dist/polyfills/bare-globals.noop.js +0 -1
  220. /package/dist/server/bare/plugins/{onnx-ocr → ggml-ocr}/ops/ocr-stream.d.ts +0 -0
  221. /package/dist/server/bare/plugins/{onnx-ocr → ggml-ocr}/ops/ocr-stream.js +0 -0
package/README.md CHANGED
@@ -16,7 +16,7 @@ See [https://docs.qvac.tether.io/sdk/getting-started](https://docs.qvac.tether.i
16
16
 
17
17
  For AI/LLM tools, use [https://docs.qvac.tether.io/llms-full.txt](https://docs.qvac.tether.io/llms-full.txt) as the consolidated plaintext documentation export.
18
18
 
19
- > **Assembling a custom worker on Bare?** See [`@qvac/bare-sdk`](../bare-sdk/README.md) — the same SDK surface with no built-in plugin addons, designed for consumers wiring their own worker entry (Pear apps, bare-expo apps, direct Bare scripts).
19
+ > **Running on Bare directly?** `@qvac/sdk` runs on Bare, but you must register the plugins you use explicitly before the first SDK call (Node and Expo do this automatically). For direct Bare usage we recommend [`@qvac/bare-sdk`](../bare-sdk/README.md) — the same SDK surface with no built-in plugin addons, designed for consumers wiring their own worker entry (Pear apps, bare-expo apps, direct Bare scripts).
20
20
 
21
21
  ## Supported environments and installation
22
22
 
@@ -46,7 +46,6 @@ try {
46
46
  // Load a model into memory
47
47
  const modelId = await loadModel({
48
48
  modelSrc: LLAMA_3_2_1B_INST_Q4_0,
49
- modelType: "llm",
50
49
  onProgress: (progress) => {
51
50
  console.log(progress);
52
51
  },
package/bare-imports.json CHANGED
@@ -24,10 +24,6 @@
24
24
  "bare": "bare-path",
25
25
  "default": "path"
26
26
  },
27
- "process": {
28
- "bare": "bare-process",
29
- "default": "process"
30
- },
31
27
  "readline": {
32
28
  "bare": "bare-readline",
33
29
  "default": "readline"
@@ -41,4 +37,3 @@
41
37
  "default": "node:url"
42
38
  }
43
39
  }
44
-
@@ -3,6 +3,7 @@ import { stream, duplex } from "../rpc/rpc-client.js";
3
3
  import { getClientLogger } from "../../logging/index.js";
4
4
  import { TranscriptionFailedError } from "../../utils/errors-client.js";
5
5
  import { decoratePromise } from "../../utils/decorate-promise.js";
6
+ import { parseClientInput } from "../parse-input.js";
6
7
  import { generateClientRequestId } from "./client-request-id.js";
7
8
  const logger = getClientLogger();
8
9
  function buildBciTranscribeRequest(params, requestId) {
@@ -20,7 +21,7 @@ function buildBciTranscribeRequest(params, requestId) {
20
21
  };
21
22
  }
22
23
  export function bciTranscribe(params, options) {
23
- const parsed = bciTranscribeClientParamsSchema.parse(params);
24
+ const parsed = parseClientInput(bciTranscribeClientParamsSchema, params);
24
25
  const requestId = generateClientRequestId();
25
26
  const inner = runBciTranscribe(parsed, requestId, options);
26
27
  return decoratePromise(inner, { requestId });
@@ -2,6 +2,7 @@ import { send, stream } from "../rpc/rpc-client.js";
2
2
  import { downloadAssetOptionsToRequestSchema, } from "../../schemas/index.js";
3
3
  import { DownloadAssetFailedError, StreamEndedError, InvalidResponseError, } from "../../utils/errors-client.js";
4
4
  import { decoratePromise } from "../../utils/decorate-promise.js";
5
+ import { parseClientInput } from "../parse-input.js";
5
6
  import { generateClientRequestId } from "./client-request-id.js";
6
7
  /**
7
8
  * Downloads an asset (model file) without loading it into memory.
@@ -53,7 +54,7 @@ export function downloadAsset(options, rpcOptions) {
53
54
  return decoratePromise(inner, { requestId });
54
55
  }
55
56
  async function runDownloadAsset(options, requestId, rpcOptions) {
56
- const request = downloadAssetOptionsToRequestSchema.parse({
57
+ const request = parseClientInput(downloadAssetOptionsToRequestSchema, {
57
58
  ...options,
58
59
  requestId,
59
60
  });
@@ -1,6 +1,7 @@
1
1
  import { send, stream as streamRpc } from "../rpc/rpc-client.js";
2
2
  import { finetuneRunParamsSchema, finetuneRunRequestSchema, finetuneStopRequestSchema, finetuneGetStateParamsSchema, finetuneGetStateRequestSchema, finetuneProgressResponseSchema, finetuneResponseSchema, } from "../../schemas/index.js";
3
3
  import { InvalidResponseError, StreamEndedError, } from "../../utils/errors-client.js";
4
+ import { parseClientInput } from "../parse-input.js";
4
5
  function isFinetuneReplyParams(params) {
5
6
  return (params.operation === "pause" ||
6
7
  params.operation === "cancel" ||
@@ -8,13 +9,13 @@ function isFinetuneReplyParams(params) {
8
9
  }
9
10
  function createFinetuneReplyRequest(params) {
10
11
  if (params.operation === "getState") {
11
- const getStateParams = finetuneGetStateParamsSchema.parse(params);
12
- return finetuneGetStateRequestSchema.parse({
12
+ const getStateParams = parseClientInput(finetuneGetStateParamsSchema, params);
13
+ return parseClientInput(finetuneGetStateRequestSchema, {
13
14
  type: "finetune",
14
15
  ...getStateParams,
15
16
  });
16
17
  }
17
- return finetuneStopRequestSchema.parse({
18
+ return parseClientInput(finetuneStopRequestSchema, {
18
19
  type: "finetune",
19
20
  modelId: params.modelId,
20
21
  operation: params.operation,
@@ -36,7 +37,7 @@ export function finetune(params, rpcOptions) {
36
37
  resultPromise.catch(() => { });
37
38
  return resultPromise;
38
39
  }
39
- const runParams = finetuneRunParamsSchema.parse(params);
40
+ const runParams = parseClientInput(finetuneRunParamsSchema, params);
40
41
  let resultResolver = () => { };
41
42
  let resultRejecter = () => { };
42
43
  const resultPromise = new Promise((resolve, reject) => {
@@ -51,7 +52,7 @@ export function finetune(params, rpcOptions) {
51
52
  const processResponses = async () => {
52
53
  try {
53
54
  let sawTerminalResponse = false;
54
- const request = finetuneRunRequestSchema.parse({
55
+ const request = parseClientInput(finetuneRunRequestSchema, {
55
56
  type: "finetune",
56
57
  ...runParams,
57
58
  withProgress: true,
@@ -4,6 +4,7 @@ export { completion } from "./completion-stream";
4
4
  export { deleteCache } from "./delete-cache";
5
5
  export { unloadModel } from "./unload-model";
6
6
  export { loggingStream } from "./logging-stream";
7
+ export { subscribeServerLogs, type ServerLogHandler } from "./subscribe-logs";
7
8
  export { heartbeat } from "./heartbeat";
8
9
  export { transcribe, transcribeStream } from "./transcribe";
9
10
  export { bciTranscribe, bciTranscribeStream } from "./bci-transcribe";
@@ -4,6 +4,7 @@ export { completion } from "./completion-stream.js";
4
4
  export { deleteCache } from "./delete-cache.js";
5
5
  export { unloadModel } from "./unload-model.js";
6
6
  export { loggingStream } from "./logging-stream.js";
7
+ export { subscribeServerLogs } from "./subscribe-logs.js";
7
8
  export { heartbeat } from "./heartbeat.js";
8
9
  export { transcribe, transcribeStream } from "./transcribe.js";
9
10
  export { bciTranscribe, bciTranscribeStream } from "./bci-transcribe.js";
@@ -32,7 +32,10 @@ export declare function loadModel<S extends ModelDescriptor>(options: LoadModelD
32
32
  * @overloadLabel "Load new model"
33
33
  * @param options - An object that defines all configuration parameters required for loading the model, including:
34
34
  * - modelSrc: The location from which the model weights are fetched (local path, remote URL, or Hyperdrive URL)
35
- * - modelType: The type of model ("llm", "whisper", "embeddings", "nmt", or "tts")
35
+ * - modelType: The canonical type of model ("llamacpp-completion",
36
+ * "whispercpp-transcription", "llamacpp-embedding", "nmtcpp-translation",
37
+ * "tts-ggml", ...). May be omitted when `modelSrc` is a registry descriptor
38
+ * that already carries the engine.
36
39
  * - modelConfig: Model-specific configuration options (companion sources, model parameters, etc.)
37
40
  * - onProgress: Callback for download progress updates
38
41
  * - logger: Logger instance for model operation logs
@@ -49,27 +52,27 @@ export declare function loadModel<S extends ModelDescriptor>(options: LoadModelD
49
52
  * // Local file path - absolute path
50
53
  * const localModelId = await loadModel({
51
54
  * modelSrc: "/home/user/models/llama-7b.gguf",
52
- * modelType: "llm",
55
+ * modelType: "llamacpp-completion",
53
56
  * modelConfig: { ctx_size: 2048 }
54
57
  * });
55
58
  *
56
59
  * // Local file path - relative path
57
60
  * const relativeModelId = await loadModel({
58
61
  * modelSrc: "./models/whisper-base.gguf",
59
- * modelType: "whisper"
62
+ * modelType: "whispercpp-transcription"
60
63
  * });
61
64
  *
62
65
  * // Hyperdrive URL with key and path
63
66
  * const hyperdriveId = await loadModel({
64
67
  * modelSrc: "pear://<hyperdrive-key>/llama-7b.gguf",
65
- * modelType: "llm",
68
+ * modelType: "llamacpp-completion",
66
69
  * modelConfig: { ctx_size: 2048 }
67
70
  * });
68
71
  *
69
72
  * // Remote HTTP/HTTPS URL with progress tracking
70
73
  * const remoteId = await loadModel({
71
74
  * modelSrc: "https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGUF/resolve/main/llama-2-7b-chat.Q4_K_M.gguf",
72
- * modelType: "llm",
75
+ * modelType: "llamacpp-completion",
73
76
  * onProgress: (progress) => {
74
77
  * console.log(`Downloaded: ${progress.percentage}%`);
75
78
  * }
@@ -78,7 +81,7 @@ export declare function loadModel<S extends ModelDescriptor>(options: LoadModelD
78
81
  * // Multimodal model with projection
79
82
  * const multimodalId = await loadModel({
80
83
  * modelSrc: "https://huggingface.co/.../main-model.gguf",
81
- * modelType: "llm",
84
+ * modelType: "llamacpp-completion",
82
85
  * modelConfig: {
83
86
  * ctx_size: 512,
84
87
  * projectionModelSrc: "https://huggingface.co/.../projection-model.gguf"
@@ -91,7 +94,7 @@ export declare function loadModel<S extends ModelDescriptor>(options: LoadModelD
91
94
  * // Whisper with VAD model
92
95
  * const whisperId = await loadModel({
93
96
  * modelSrc: "https://huggingface.co/.../whisper-model.gguf",
94
- * modelType: "whisper",
97
+ * modelType: "whispercpp-transcription",
95
98
  * modelConfig: {
96
99
  * mode: "caption",
97
100
  * output_format: "plaintext",
@@ -107,7 +110,7 @@ export declare function loadModel<S extends ModelDescriptor>(options: LoadModelD
107
110
  *
108
111
  * const modelId = await loadModel({
109
112
  * modelSrc: "/path/to/model.gguf",
110
- * modelType: "llm",
113
+ * modelType: "llamacpp-completion",
111
114
  * logger // Pass logger in options
112
115
  * });
113
116
  * ```
@@ -1,8 +1,9 @@
1
1
  import { send, stream } from "../rpc/rpc-client.js";
2
2
  import { startLoggingStreamForModel } from "../logging-stream-registry.js";
3
- import { loadModelOptionsToRequestSchema, reloadConfigOptionsToRequestSchema, isModelTypeAlias, normalizeModelType, inferModelTypeFromModelSrc, ModelType, } from "../../schemas/index.js";
3
+ import { loadBuiltinToRequestSchema, loadCustomPluginToRequestSchema, reloadConfigOptionsToRequestSchema, isBuiltInModelType, isModelTypeAlias, normalizeModelType, inferModelTypeFromModelSrc, ModelType, } from "../../schemas/index.js";
4
4
  import { ModelLoadFailedError, ModelTypeRequiredError, StreamEndedError, InvalidResponseError, } from "../../utils/errors-client.js";
5
5
  import { assertModelSrcMatchesModelType } from "../../utils/load-model-validation.js";
6
+ import { parseClientInput } from "../parse-input.js";
6
7
  import { getClientLogger } from "../../logging/index.js";
7
8
  import { decoratePromise } from "../../utils/decorate-promise.js";
8
9
  import { generateClientRequestId } from "./client-request-id.js";
@@ -64,9 +65,6 @@ async function runLoadModel(options, requestId, rpcOptions) {
64
65
  "on typical mobile devices. Pass a `delegate` to `loadModel(...)` to " +
65
66
  "run generation on a desktop peer instead.";
66
67
  logger.warn(message);
67
- // Surface via console too - if an RN host app doesn't wire getClientLogger()
68
- // to a visible transport, logger.warn alone won't reach the dev.
69
- console.warn(message);
70
68
  }
71
69
  }
72
70
  // Splice the client-generated `requestId` onto the resolved options so
@@ -76,8 +74,10 @@ async function runLoadModel(options, requestId, rpcOptions) {
76
74
  // and a precise abort when it does.
77
75
  resolvedOptions = { ...resolvedOptions, requestId };
78
76
  const request = isReloadConfig
79
- ? reloadConfigOptionsToRequestSchema.parse(resolvedOptions)
80
- : loadModelOptionsToRequestSchema.parse(resolvedOptions);
77
+ ? parseClientInput(reloadConfigOptionsToRequestSchema, resolvedOptions)
78
+ : isBuiltInModelType(resolvedOptions["modelType"])
79
+ ? parseClientInput(loadBuiltinToRequestSchema, resolvedOptions)
80
+ : parseClientInput(loadCustomPluginToRequestSchema, resolvedOptions);
81
81
  const modelLogger = isReloadConfig
82
82
  ? undefined
83
83
  : resolvedOptions["logger"];
@@ -0,0 +1,28 @@
1
+ import type { LoggingStreamResponse } from "../../schemas/logging-stream";
2
+ export type ServerLogHandler = (log: LoggingStreamResponse) => void;
3
+ /**
4
+ * Subscribes to every server-side log through a single stream: SDK server logs,
5
+ * per-model addon logs (llamacpp, whispercpp, …) for all loaded models, and RAG
6
+ * logs — without having to open a {@link loggingStream} per id.
7
+ *
8
+ * Each delivered log keeps its origin in `log.id`: `SDK_LOG_ID` for SDK server
9
+ * logs, the model id for model logs, or the RAG workspace key. Use it to tell the
10
+ * sources apart.
11
+ *
12
+ * Internally this opens a {@link loggingStream} on the reserved `SDK_ALL_LOG_ID`
13
+ * stream that the worker fans every log into.
14
+ *
15
+ * @param handler - called once per log line.
16
+ * @returns a function that stops the subscription.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const unsubscribe = subscribeServerLogs((log) => {
21
+ * console.log(`[${log.level}] ${log.id} ${log.namespace}: ${log.message}`);
22
+ * });
23
+ * // later
24
+ * unsubscribe();
25
+ * ```
26
+ */
27
+ export declare function subscribeServerLogs(handler: ServerLogHandler): () => void;
28
+ //# sourceMappingURL=subscribe-logs.d.ts.map
@@ -0,0 +1,43 @@
1
+ import { getClientLogger, SDK_ALL_LOG_ID } from "../../logging/index.js";
2
+ import { loggingStream } from "./logging-stream.js";
3
+ const logger = getClientLogger();
4
+ /**
5
+ * Subscribes to every server-side log through a single stream: SDK server logs,
6
+ * per-model addon logs (llamacpp, whispercpp, …) for all loaded models, and RAG
7
+ * logs — without having to open a {@link loggingStream} per id.
8
+ *
9
+ * Each delivered log keeps its origin in `log.id`: `SDK_LOG_ID` for SDK server
10
+ * logs, the model id for model logs, or the RAG workspace key. Use it to tell the
11
+ * sources apart.
12
+ *
13
+ * Internally this opens a {@link loggingStream} on the reserved `SDK_ALL_LOG_ID`
14
+ * stream that the worker fans every log into.
15
+ *
16
+ * @param handler - called once per log line.
17
+ * @returns a function that stops the subscription.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const unsubscribe = subscribeServerLogs((log) => {
22
+ * console.log(`[${log.level}] ${log.id} ${log.namespace}: ${log.message}`);
23
+ * });
24
+ * // later
25
+ * unsubscribe();
26
+ * ```
27
+ */
28
+ export function subscribeServerLogs(handler) {
29
+ const streamIterator = loggingStream({ id: SDK_ALL_LOG_ID });
30
+ void (async () => {
31
+ try {
32
+ for await (const log of streamIterator) {
33
+ handler(log);
34
+ }
35
+ }
36
+ catch (error) {
37
+ logger.error("Server log stream error:", error);
38
+ }
39
+ })();
40
+ return () => {
41
+ void streamIterator.return(undefined);
42
+ };
43
+ }
@@ -2,6 +2,7 @@ import { textToSpeechStreamResponseSchema, ttsClientParamsSchema, } from "../../
2
2
  import { stream as streamRpc, duplex } from "../rpc/rpc-client.js";
3
3
  import { getClientLogger } from "../../logging/index.js";
4
4
  import { TextToSpeechStreamFailedError } from "../../utils/errors-client.js";
5
+ import { parseClientInput } from "../parse-input.js";
5
6
  const logger = getClientLogger();
6
7
  /**
7
8
  * Fan-out queue that lets multiple consumers iterate the same TTS response
@@ -190,7 +191,7 @@ function buildTextToSpeechStreamRequest(params) {
190
191
  * with `stream: false`, or when the underlying RPC stream errors.
191
192
  */
192
193
  export function textToSpeech(params, options) {
193
- const parsed = ttsClientParamsSchema.parse(params);
194
+ const parsed = parseClientInput(ttsClientParamsSchema, params);
194
195
  if (parsed.sentenceStream && !parsed.stream) {
195
196
  throw new TextToSpeechStreamFailedError("textToSpeech: `sentenceStream: true` requires `stream: true`");
196
197
  }
@@ -1,12 +1,10 @@
1
1
  import { qvacConfigSchema } from "../../schemas/index.js";
2
2
  import { ConfigValidationFailedError } from "../../utils/errors-client.js";
3
+ import { formatZodError } from "../../utils/zod-error.js";
3
4
  export function validateConfig(config) {
4
5
  const result = qvacConfigSchema.safeParse(config);
5
6
  if (!result.success) {
6
- const errors = result.error.issues
7
- .map((e) => `${String(e.path.join("."))}: ${e.message}`)
8
- .join(", ");
9
- throw new ConfigValidationFailedError(errors);
7
+ throw new ConfigValidationFailedError(formatZodError(result.error));
10
8
  }
11
9
  return result.data;
12
10
  }
@@ -4,14 +4,15 @@
4
4
  */
5
5
  import fs from "bare-fs";
6
6
  import path from "bare-path";
7
- import process from "bare-process";
7
+ import os from "bare-os";
8
+ import env from "bare-env";
8
9
  import { validateConfig } from "./config-utils.js";
9
10
  import { ConfigFileInvalidError, ConfigFileParseFailedError, } from "../../utils/errors-client.js";
10
11
  import { getClientLogger } from "../../logging/index.js";
11
12
  const SUPPORTED_CONFIG_FILE_EXTS = [".js", ".json"];
12
13
  const logger = getClientLogger();
13
14
  function findProjectRoot() {
14
- return process.cwd();
15
+ return os.cwd();
15
16
  }
16
17
  function fileExists(filePath) {
17
18
  return fs.existsSync(filePath);
@@ -50,7 +51,7 @@ function findConfigFile(searchDir) {
50
51
  */
51
52
  // eslint-disable-next-line @typescript-eslint/require-await -- matches Node/Expo resolver signature
52
53
  export async function resolveConfig() {
53
- const configPath = process.env["QVAC_CONFIG_PATH"];
54
+ const configPath = env["QVAC_CONFIG_PATH"];
54
55
  if (configPath) {
55
56
  const normalizedPath = path.resolve(configPath);
56
57
  if (fileExists(normalizedPath)) {
@@ -0,0 +1,3 @@
1
+ import { z } from "zod";
2
+ export declare function parseClientInput<S extends z.ZodType>(schema: S, value: unknown): z.output<S>;
3
+ //# sourceMappingURL=parse-input.d.ts.map
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+ import { formatZodError } from "../utils/zod-error.js";
3
+ import { RequestValidationFailedError } from "../utils/errors-client.js";
4
+ export function parseClientInput(schema, value) {
5
+ try {
6
+ return schema.parse(value);
7
+ }
8
+ catch (error) {
9
+ if (error instanceof z.ZodError) {
10
+ throw new RequestValidationFailedError(formatZodError(error));
11
+ }
12
+ throw error;
13
+ }
14
+ }
@@ -151,11 +151,8 @@ export async function close() {
151
151
  logger.info("🧹 Closing RPC client (Expo)");
152
152
  // terminate() crashes on Android (addon dlclose leaves pthread_key_t
153
153
  // destructors dangling); iOS dyld no-ops dlclose so it's safe there.
154
- // Non-iOS: send the cleanup roundtrip, then drop refs without
155
- // terminating. Android cannot safely terminate/dlclose the worklet
156
- // here, but reset/reload still needs addon logger js_ref_t handles
157
- // released before a fresh worker registers plugins in the same app
158
- // process.
154
+ // Non-iOS: drop refs only -- sending __shutdown__ without a follow-up
155
+ // terminate would clear the worker plugin registry.
159
156
  let platform;
160
157
  try {
161
158
  platform = (await getRuntimeContext()).platform;
@@ -164,14 +161,8 @@ export async function close() {
164
161
  logger.debug("Failed to resolve runtime context for close()", { err });
165
162
  }
166
163
  if (platform !== "ios") {
167
- if (rpcInstance) {
168
- logger.info("🧹 Requesting worker cleanup");
169
- await sendShutdownMessage(rpcInstance);
170
- }
171
164
  rpcInstance = null;
172
165
  rpcPromise = null;
173
- workletInstance = null;
174
- workletInitialized = false;
175
166
  return;
176
167
  }
177
168
  // iOS: existing pre-terminate cleanup + terminate.
@@ -9,11 +9,14 @@ import path from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
10
  import { initializeConfig } from "../init-hooks.js";
11
11
  import { resolveConfig } from "../config-loader/resolve-config.node.js";
12
- import { getClientLogger } from "../../logging/index.js";
12
+ import { getClientLogger, getLogger, SDK_SERVER_NAMESPACE } from "../../logging/index.js";
13
13
  import { BareRuntimeBinaryNotFoundError, RPCInitTimeoutError, WorkerCrashedError, WorkerShutdownError, } from "../../utils/errors-client.js";
14
14
  const RPC_INIT_TIMEOUT_MS = 30_000;
15
15
  const WORKER_STDERR_TAIL_CHARS = 16_384;
16
16
  const logger = getClientLogger();
17
+ // Addons route real logs through their JS callback; anything written straight to the
18
+ // worker's stderr is treated as debug.
19
+ const workerLogger = getLogger(SDK_SERVER_NAMESPACE, { enableConsole: false });
17
20
  let rpcInstance = null;
18
21
  let rpcPromise = null;
19
22
  let bareWorkerProc = null;
@@ -339,7 +342,10 @@ async function ensureRPC() {
339
342
  getWorkerStderr(bareWorkerProc)?.on("data", (chunk) => {
340
343
  const text = chunk.toString();
341
344
  workerStderrTail = appendWorkerStderrTail(workerStderrTail, text);
342
- process.stderr.write(chunk);
345
+ for (const line of text.split("\n")) {
346
+ if (line.trim())
347
+ workerLogger.debug(line);
348
+ }
343
349
  });
344
350
  bareWorkerProc.on("exit", (code, exitSignal) => {
345
351
  if (settled) {
@@ -3,7 +3,9 @@ import { reconstructError } from "./rpc-error.js";
3
3
  import { withTimeout, withTimeoutStream } from "../../utils/withTimeout.js";
4
4
  import { getClientLogger, summarizeRequest } from "../../logging/index.js";
5
5
  import { getRPC, close as closeRPC, createDuplexSession, getWorkerLifeSignal, } from "#rpc";
6
- import { WorkerCrashedError } from "../../utils/errors-client.js";
6
+ import { WorkerCrashedError, RequestValidationFailedError, } from "../../utils/errors-client.js";
7
+ import { formatZodError } from "../../utils/zod-error.js";
8
+ import { z } from "zod";
7
9
  import { nowMs, shouldProfile, shouldIncludeServerBreakdown, generateId as createProfileId, createProfilingMeta, createProfilingDisabledMeta, injectProfilingMetaIntoObject, extractProfilingMeta, stripProfilingMeta, recordFailure, } from "../../profiling/index.js";
8
10
  import { createClientTimings, createClientStreamTimings, recordClientEvents, recordClientStreamEvents, cacheConnectionTime, flushConnectionTime, resetConnectionTracking, } from "./profiling/index.js";
9
11
  const logger = getClientLogger();
@@ -14,6 +16,36 @@ function getNextCommandId() {
14
16
  commandCounter = (commandCounter + 1) % Number.MAX_SAFE_INTEGER;
15
17
  return commandCounter;
16
18
  }
19
+ function memberDiscriminator(option) {
20
+ const direct = option.shape?.type?.value;
21
+ if (typeof direct === "string")
22
+ return direct;
23
+ const nested = option.options?.[0]?.shape?.type?.value;
24
+ return typeof nested === "string" ? nested : undefined;
25
+ }
26
+ function pinpointRequestError(request, fallback) {
27
+ const type = request?.type;
28
+ if (typeof type !== "string")
29
+ return fallback;
30
+ for (const option of requestSchema.options) {
31
+ if (memberDiscriminator(option) !== type)
32
+ continue;
33
+ const result = option.safeParse(request);
34
+ return result.success ? fallback : result.error;
35
+ }
36
+ return fallback;
37
+ }
38
+ function parseRequest(request) {
39
+ try {
40
+ return requestSchema.parse(request);
41
+ }
42
+ catch (error) {
43
+ if (error instanceof z.ZodError) {
44
+ throw new RequestValidationFailedError(formatZodError(pinpointRequestError(request, error)));
45
+ }
46
+ throw error;
47
+ }
48
+ }
17
49
  // Race in-flight reply/stream pulls against the worker-life signal —
18
50
  // bare-rpc's `_onerror` does not iterate `_outgoingRequests`, so without
19
51
  // this they hang on a dead socket.
@@ -164,7 +196,7 @@ export async function send(request, options, rpc) {
164
196
  return sendProfiled(request, ctx.rpc, options);
165
197
  }
166
198
  async function sendBase(request, rpc, options, signalDisable = false) {
167
- const parsedRequest = requestSchema.parse(request);
199
+ const parsedRequest = parseRequest(request);
168
200
  const req = rpc.request(getNextCommandId());
169
201
  logger.debug("RPC Client sending:", summarizeRequest(request));
170
202
  const payloadObj = signalDisable
@@ -185,7 +217,7 @@ async function sendProfiled(request, rpc, options) {
185
217
  const timings = createClientTimings(profileId, requestType);
186
218
  try {
187
219
  const zodStart = nowMs();
188
- const parsedRequest = requestSchema.parse(request);
220
+ const parsedRequest = parseRequest(request);
189
221
  timings.requestZodValidationMs = nowMs() - zodStart;
190
222
  const req = rpc.request(getNextCommandId());
191
223
  logger.debug("RPC Client sending:", summarizeRequest(request));
@@ -234,7 +266,7 @@ export async function* stream(request, options = {}, rpc) {
234
266
  yield* streamProfiled(request, ctx.rpc, options);
235
267
  }
236
268
  async function* streamBase(request, rpc, options = {}, signalDisable = false) {
237
- const parsedRequest = requestSchema.parse(request);
269
+ const parsedRequest = parseRequest(request);
238
270
  const req = rpc.request(getNextCommandId());
239
271
  logger.debug("RPC Client streaming:", summarizeRequest(request));
240
272
  const payloadObj = signalDisable
@@ -271,7 +303,7 @@ async function* streamProfiled(request, rpc, options = {}) {
271
303
  let profilingMeta = undefined;
272
304
  try {
273
305
  const zodStart = nowMs();
274
- const parsedRequest = requestSchema.parse(request);
306
+ const parsedRequest = parseRequest(request);
275
307
  timings.requestZodValidationMs = nowMs() - zodStart;
276
308
  const req = rpc.request(getNextCommandId());
277
309
  logger.debug("RPC Client streaming:", summarizeRequest(request));
@@ -344,7 +376,7 @@ export async function duplex(request, options) {
344
376
  return duplexProfiled(request, options);
345
377
  }
346
378
  async function duplexBase(request, signalDisable, timeout) {
347
- const parsedRequest = requestSchema.parse(request);
379
+ const parsedRequest = parseRequest(request);
348
380
  logger.debug("RPC Client duplex:", summarizeRequest(request));
349
381
  const payloadObj = signalDisable
350
382
  ? injectProfilingMetaIntoObject(parsedRequest, createProfilingDisabledMeta())
@@ -365,7 +397,7 @@ async function duplexProfiled(request, options = {}) {
365
397
  let session;
366
398
  try {
367
399
  const zodStart = nowMs();
368
- const parsedRequest = requestSchema.parse(request);
400
+ const parsedRequest = parseRequest(request);
369
401
  timings.requestZodValidationMs = nowMs() - zodStart;
370
402
  logger.debug("RPC Client duplex:", summarizeRequest(request));
371
403
  const requestMeta = createProfilingMeta(profileId, includeServer);
@@ -6,9 +6,10 @@ export const BUILTIN_PLUGINS = {
6
6
  "parakeet-transcription": { exportName: "parakeetPlugin" },
7
7
  "nmtcpp-translation": { exportName: "nmtPlugin" },
8
8
  "tts-ggml": { exportName: "ttsPlugin" },
9
- "onnx-ocr": { exportName: "ocrPlugin" },
9
+ "ggml-ocr": { exportName: "ocrPlugin" },
10
10
  "sdcpp-generation": { exportName: "diffusionPlugin" },
11
11
  "ggml-vla": { exportName: "vlaPlugin" },
12
+ "ggml-classification": { exportName: "classificationPlugin" },
12
13
  };
13
14
  export const BUILTIN_SUFFIXES = Object.keys(BUILTIN_PLUGINS);
14
15
  export const DEFAULT_HOSTS = [
@@ -19,10 +19,10 @@ const neuralFilePath = args[0];
19
19
  // Feed the neural buffer in fixed-size chunks to simulate a live stream.
20
20
  const CHUNK_SIZE = 64 * 1024;
21
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...");
22
+ console.log("▸ BCI transcribeStream file test");
23
+ console.log(`▸ File: ${neuralFilePath}`);
24
+ console.log(`▸ Chunk size: ${CHUNK_SIZE} bytes`);
25
+ console.log("▸ Loading model...");
26
26
  const modelId = await loadModel({
27
27
  modelSrc: BCI_WINDOWED,
28
28
  modelConfig: {
@@ -38,10 +38,10 @@ try {
38
38
  },
39
39
  },
40
40
  });
41
- console.log(`Model loaded: ${modelId}\n`);
42
- console.log("Opening live session...");
41
+ console.log(`▸ Model loaded: ${modelId}`);
42
+ console.log("▸ Opening live session...");
43
43
  const session = await bciTranscribeStream({ modelId, emit: "delta" });
44
- console.log("Session open. Streaming neural signal...\n");
44
+ console.log("▸ Session open. Streaming neural signal...");
45
45
  // Drain the session concurrently with writing so the sliding-window
46
46
  // decode can make progress as chunks arrive instead of stalling.
47
47
  const consume = (async () => {
@@ -60,18 +60,18 @@ try {
60
60
  totalBytes += chunk.length;
61
61
  await new Promise((resolve) => setTimeout(resolve, 10));
62
62
  }
63
- console.log(`\n\nNeural signal streamed: ${totalBytes} bytes`);
64
- console.log("Waiting for transcription to finish...\n");
63
+ console.log(`\n\n▸ Neural signal streamed: ${totalBytes} bytes`);
64
+ console.log("▸ Waiting for transcription to finish...");
65
65
  session.end();
66
66
  const transcript = await consume;
67
- console.log("\n=== Results ===");
68
- console.log(`Transcript: ${transcript.trim() || "(no text received)"}`);
69
- console.log("\nUnloading model...");
67
+ console.log("\n▸ Results");
68
+ console.log(transcript.trim() || "(no text received)");
69
+ console.log("▸ Unloading model...");
70
70
  await unloadModel({ modelId });
71
- console.log("Done.");
71
+ console.log("▸ Done.");
72
72
  process.exit(0);
73
73
  }
74
74
  catch (error) {
75
- console.error("❌ Error:", error);
75
+ console.error("✖", error);
76
76
  process.exit(1);
77
77
  }