@qvac/sdk 0.15.0 → 0.16.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 (102) hide show
  1. package/NOTICE +31 -45
  2. package/dist/client/api/ocr.d.ts +9 -0
  3. package/dist/client/api/ocr.js +9 -0
  4. package/dist/client/api/translate.js +6 -17
  5. package/dist/client/api/video.d.ts +7 -4
  6. package/dist/client/api/video.js +7 -4
  7. package/dist/client/api/vla.d.ts +14 -10
  8. package/dist/client/api/vla.js +14 -10
  9. package/dist/client/rpc/rpc-error.js +7 -1
  10. package/dist/examples/diffusion-ideogram.d.ts +2 -0
  11. package/dist/examples/diffusion-ideogram.js +108 -0
  12. package/dist/examples/diffusion-img2vid-ltx.d.ts +2 -0
  13. package/dist/examples/diffusion-img2vid-ltx.js +98 -0
  14. package/dist/examples/diffusion-txt2vid-ltx.d.ts +2 -0
  15. package/dist/examples/diffusion-txt2vid-ltx.js +92 -0
  16. package/dist/examples/logging-streaming.js +5 -1
  17. package/dist/examples/transcription/parakeet-tdt-filesystem-chunked.d.ts +2 -0
  18. package/dist/examples/transcription/parakeet-tdt-filesystem-chunked.js +203 -0
  19. package/dist/examples/vla-groot.d.ts +2 -0
  20. package/dist/examples/vla-groot.js +118 -0
  21. package/dist/models/registry/models.d.ts +5711 -9637
  22. package/dist/models/registry/models.js +2747 -6886
  23. package/dist/models/update-models/naming.js +5 -1
  24. package/dist/schemas/batch-completion-stream.d.ts +4 -4
  25. package/dist/schemas/common.d.ts +385 -4
  26. package/dist/schemas/common.js +3 -1
  27. package/dist/schemas/completion-stream.d.ts +186 -2
  28. package/dist/schemas/completion-stream.js +67 -0
  29. package/dist/schemas/constants-registry.d.ts +67 -0
  30. package/dist/schemas/constants-registry.js +51 -0
  31. package/dist/schemas/delete-cache.js +7 -3
  32. package/dist/schemas/engine-addon-map.d.ts +1 -0
  33. package/dist/schemas/engine-addon-map.js +1 -1
  34. package/dist/schemas/finetune.js +6 -3
  35. package/dist/schemas/get-loaded-model-info.d.ts +16 -0
  36. package/dist/schemas/get-loaded-model-info.js +14 -6
  37. package/dist/schemas/llamacpp-config.d.ts +24 -4
  38. package/dist/schemas/llamacpp-config.js +1 -6
  39. package/dist/schemas/load-model.d.ts +1380 -60
  40. package/dist/schemas/load-model.js +6 -3
  41. package/dist/schemas/plugin.d.ts +4 -4
  42. package/dist/schemas/plugin.js +4 -4
  43. package/dist/schemas/reload-config.js +3 -1
  44. package/dist/schemas/sdcpp-config.d.ts +239 -0
  45. package/dist/schemas/sdcpp-config.js +116 -10
  46. package/dist/schemas/sdk-config.d.ts +790 -40
  47. package/dist/schemas/sdk-errors-server.js +3 -1
  48. package/dist/schemas/text-to-speech.d.ts +14 -0
  49. package/dist/schemas/text-to-speech.js +10 -4
  50. package/dist/schemas/tools.d.ts +1 -1
  51. package/dist/schemas/tools.js +2 -1
  52. package/dist/schemas/translate.js +12 -6
  53. package/dist/schemas/vla.d.ts +10 -0
  54. package/dist/schemas/vla.js +31 -11
  55. package/dist/scripts/contract/build-contract.d.ts +38 -0
  56. package/dist/scripts/contract/build-contract.js +620 -0
  57. package/dist/scripts/contract/build-error-codes.d.ts +17 -0
  58. package/dist/scripts/contract/build-error-codes.js +17 -0
  59. package/dist/scripts/contract/build-model-type-maps.d.ts +22 -0
  60. package/dist/scripts/contract/build-model-type-maps.js +16 -0
  61. package/dist/scripts/contract/build-models-registry.d.ts +17 -0
  62. package/dist/scripts/contract/build-models-registry.js +31 -0
  63. package/dist/scripts/contract/plugin-contract.d.ts +23 -0
  64. package/dist/scripts/contract/plugin-contract.js +28 -0
  65. package/dist/scripts/export-contract.d.ts +2 -0
  66. package/dist/scripts/export-contract.js +27 -0
  67. package/dist/scripts/export-plugin-contract.d.ts +2 -0
  68. package/dist/scripts/export-plugin-contract.js +18 -0
  69. package/dist/server/bare/ops/translate.js +16 -3
  70. package/dist/server/bare/plugins/bci-whispercpp-transcription/plugin.d.ts +2 -1
  71. package/dist/server/bare/plugins/ggml-ocr/plugin.js +2 -23
  72. package/dist/server/bare/plugins/ggml-ocr/resolve-config.d.ts +6 -0
  73. package/dist/server/bare/plugins/ggml-ocr/resolve-config.js +73 -0
  74. package/dist/server/bare/plugins/ggml-vla/plugin.d.ts +5 -0
  75. package/dist/server/bare/plugins/ggml-vla/plugin.js +1 -1
  76. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +11 -22
  77. package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.d.ts +8 -0
  78. package/dist/server/bare/plugins/llamacpp-completion/ops/kv-cache-state.js +8 -0
  79. package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +8 -3
  80. package/dist/server/bare/plugins/llamacpp-embedding/plugin.d.ts +6 -1
  81. package/dist/server/bare/plugins/sdcpp-generation/ops/video.d.ts +3 -1
  82. package/dist/server/bare/plugins/sdcpp-generation/ops/video.js +31 -2
  83. package/dist/server/bare/plugins/sdcpp-generation/plugin.d.ts +129 -1
  84. package/dist/server/bare/plugins/sdcpp-generation/plugin.js +94 -22
  85. package/dist/server/bare/plugins/tts-ggml/ops/text-to-speech.js +2 -16
  86. package/dist/server/bare/plugins/tts-ggml/plugin.d.ts +6 -0
  87. package/dist/server/bare/plugins/tts-ggml/plugin.js +3 -1
  88. package/dist/server/bare/types/addon-responses.d.ts +2 -0
  89. package/dist/server/bare/utils/tts-stats.d.ts +8 -4
  90. package/dist/server/bare/utils/tts-stats.js +6 -0
  91. package/dist/server/rpc/create-server.js +23 -1
  92. package/dist/server/rpc/handler-registry.js +5 -0
  93. package/dist/server/rpc/handlers/completion-orchestrate.d.ts +42 -0
  94. package/dist/server/rpc/handlers/completion-orchestrate.js +190 -0
  95. package/dist/server/rpc/handlers/get-loaded-model-info.js +8 -2
  96. package/dist/server/rpc/handlers/index.d.ts +2 -0
  97. package/dist/server/rpc/handlers/index.js +2 -0
  98. package/dist/server/rpc/method-shapes.d.ts +51 -0
  99. package/dist/server/rpc/method-shapes.js +48 -0
  100. package/dist/server/rpc/profiling/operation-metrics.js +20 -0
  101. package/dist/server/utils/cache/auto-history.js +13 -9
  102. package/package.json +16 -13
@@ -1,5 +1,5 @@
1
1
  import { type CreateModelParams, type PluginModelResult, type ResolveContext, type ResolveResult, type SdcppConfig } from '../../../../schemas/index';
2
- type DiffusionArtifactKey = 'clipLModelPath' | 'clipGModelPath' | 'clipVisionModelPath' | 't5XxlModelPath' | 'llmModelPath' | 'vaeModelPath' | 'highNoiseDiffusionModelPath' | 'esrganModelPath';
2
+ type DiffusionArtifactKey = 'clipLModelPath' | 'clipGModelPath' | 'clipVisionModelPath' | 't5XxlModelPath' | 'llmModelPath' | 'vaeModelPath' | 'highNoiseDiffusionModelPath' | 'uncondModelPath' | 'audioVaeModelPath' | 'embeddingsConnectorsModelPath' | 'esrganModelPath';
3
3
  /**
4
4
  * Stable-diffusion.cpp plugin for image diffusion, upscaling, and Wan video.
5
5
  *
@@ -23,6 +23,10 @@ export declare const diffusionPlugin: {
23
23
  gpu: "gpu";
24
24
  cpu: "cpu";
25
25
  }>>;
26
+ 'main-gpu': import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodNumber, import("zod").ZodEnum<{
27
+ integrated: "integrated";
28
+ dedicated: "dedicated";
29
+ }>]>>;
26
30
  prediction: import("zod").ZodOptional<import("zod").ZodEnum<{
27
31
  auto: "auto";
28
32
  eps: "eps";
@@ -291,6 +295,43 @@ export declare const diffusionPlugin: {
291
295
  classification: "classification";
292
296
  }>, import("zod").ZodLiteral<"vad">]>>;
293
297
  }, import("zod/v4/core").$strip>]>>;
298
+ uncondModelSrc: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodObject<{
299
+ src: import("zod").ZodString;
300
+ name: import("zod").ZodOptional<import("zod").ZodString>;
301
+ modelId: import("zod").ZodOptional<import("zod").ZodString>;
302
+ registryPath: import("zod").ZodOptional<import("zod").ZodString>;
303
+ registrySource: import("zod").ZodOptional<import("zod").ZodString>;
304
+ blobCoreKey: import("zod").ZodOptional<import("zod").ZodString>;
305
+ blobIndex: import("zod").ZodOptional<import("zod").ZodNumber>;
306
+ engine: import("zod").ZodOptional<import("zod").ZodString>;
307
+ expectedSize: import("zod").ZodOptional<import("zod").ZodNumber>;
308
+ sha256Checksum: import("zod").ZodOptional<import("zod").ZodString>;
309
+ addon: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodEnum<{
310
+ embeddings: "embeddings";
311
+ diffusion: "diffusion";
312
+ tts: "tts";
313
+ ocr: "ocr";
314
+ vla: "vla";
315
+ "llamacpp-completion": "llamacpp-completion";
316
+ "whispercpp-transcription": "whispercpp-transcription";
317
+ "bci-whispercpp-transcription": "bci-whispercpp-transcription";
318
+ "llamacpp-embedding": "llamacpp-embedding";
319
+ "nmtcpp-translation": "nmtcpp-translation";
320
+ "onnx-tts": "onnx-tts";
321
+ "tts-ggml": "tts-ggml";
322
+ "parakeet-transcription": "parakeet-transcription";
323
+ "ggml-ocr": "ggml-ocr";
324
+ "sdcpp-generation": "sdcpp-generation";
325
+ "ggml-vla": "ggml-vla";
326
+ "ggml-classification": "ggml-classification";
327
+ llm: "llm";
328
+ whisper: "whisper";
329
+ bci: "bci";
330
+ nmt: "nmt";
331
+ parakeet: "parakeet";
332
+ classification: "classification";
333
+ }>, import("zod").ZodLiteral<"vad">]>>;
334
+ }, import("zod/v4/core").$strip>]>>;
294
335
  clipVisionModelSrc: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodObject<{
295
336
  src: import("zod").ZodString;
296
337
  name: import("zod").ZodOptional<import("zod").ZodString>;
@@ -328,6 +369,80 @@ export declare const diffusionPlugin: {
328
369
  classification: "classification";
329
370
  }>, import("zod").ZodLiteral<"vad">]>>;
330
371
  }, import("zod/v4/core").$strip>]>>;
372
+ audioVaeModelSrc: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodObject<{
373
+ src: import("zod").ZodString;
374
+ name: import("zod").ZodOptional<import("zod").ZodString>;
375
+ modelId: import("zod").ZodOptional<import("zod").ZodString>;
376
+ registryPath: import("zod").ZodOptional<import("zod").ZodString>;
377
+ registrySource: import("zod").ZodOptional<import("zod").ZodString>;
378
+ blobCoreKey: import("zod").ZodOptional<import("zod").ZodString>;
379
+ blobIndex: import("zod").ZodOptional<import("zod").ZodNumber>;
380
+ engine: import("zod").ZodOptional<import("zod").ZodString>;
381
+ expectedSize: import("zod").ZodOptional<import("zod").ZodNumber>;
382
+ sha256Checksum: import("zod").ZodOptional<import("zod").ZodString>;
383
+ addon: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodEnum<{
384
+ embeddings: "embeddings";
385
+ diffusion: "diffusion";
386
+ tts: "tts";
387
+ ocr: "ocr";
388
+ vla: "vla";
389
+ "llamacpp-completion": "llamacpp-completion";
390
+ "whispercpp-transcription": "whispercpp-transcription";
391
+ "bci-whispercpp-transcription": "bci-whispercpp-transcription";
392
+ "llamacpp-embedding": "llamacpp-embedding";
393
+ "nmtcpp-translation": "nmtcpp-translation";
394
+ "onnx-tts": "onnx-tts";
395
+ "tts-ggml": "tts-ggml";
396
+ "parakeet-transcription": "parakeet-transcription";
397
+ "ggml-ocr": "ggml-ocr";
398
+ "sdcpp-generation": "sdcpp-generation";
399
+ "ggml-vla": "ggml-vla";
400
+ "ggml-classification": "ggml-classification";
401
+ llm: "llm";
402
+ whisper: "whisper";
403
+ bci: "bci";
404
+ nmt: "nmt";
405
+ parakeet: "parakeet";
406
+ classification: "classification";
407
+ }>, import("zod").ZodLiteral<"vad">]>>;
408
+ }, import("zod/v4/core").$strip>]>>;
409
+ embeddingsConnectorsModelSrc: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodObject<{
410
+ src: import("zod").ZodString;
411
+ name: import("zod").ZodOptional<import("zod").ZodString>;
412
+ modelId: import("zod").ZodOptional<import("zod").ZodString>;
413
+ registryPath: import("zod").ZodOptional<import("zod").ZodString>;
414
+ registrySource: import("zod").ZodOptional<import("zod").ZodString>;
415
+ blobCoreKey: import("zod").ZodOptional<import("zod").ZodString>;
416
+ blobIndex: import("zod").ZodOptional<import("zod").ZodNumber>;
417
+ engine: import("zod").ZodOptional<import("zod").ZodString>;
418
+ expectedSize: import("zod").ZodOptional<import("zod").ZodNumber>;
419
+ sha256Checksum: import("zod").ZodOptional<import("zod").ZodString>;
420
+ addon: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodEnum<{
421
+ embeddings: "embeddings";
422
+ diffusion: "diffusion";
423
+ tts: "tts";
424
+ ocr: "ocr";
425
+ vla: "vla";
426
+ "llamacpp-completion": "llamacpp-completion";
427
+ "whispercpp-transcription": "whispercpp-transcription";
428
+ "bci-whispercpp-transcription": "bci-whispercpp-transcription";
429
+ "llamacpp-embedding": "llamacpp-embedding";
430
+ "nmtcpp-translation": "nmtcpp-translation";
431
+ "onnx-tts": "onnx-tts";
432
+ "tts-ggml": "tts-ggml";
433
+ "parakeet-transcription": "parakeet-transcription";
434
+ "ggml-ocr": "ggml-ocr";
435
+ "sdcpp-generation": "sdcpp-generation";
436
+ "ggml-vla": "ggml-vla";
437
+ "ggml-classification": "ggml-classification";
438
+ llm: "llm";
439
+ whisper: "whisper";
440
+ bci: "bci";
441
+ nmt: "nmt";
442
+ parakeet: "parakeet";
443
+ classification: "classification";
444
+ }>, import("zod").ZodLiteral<"vad">]>>;
445
+ }, import("zod/v4/core").$strip>]>>;
331
446
  upscaler: import("zod").ZodOptional<import("zod").ZodObject<{
332
447
  type: import("zod").ZodOptional<import("zod").ZodLiteral<"esrgan">>;
333
448
  model_src: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodObject<{
@@ -439,6 +554,11 @@ export declare const diffusionPlugin: {
439
554
  stats: import("zod").ZodOptional<import("zod").ZodObject<{
440
555
  modelLoadMs: import("zod").ZodOptional<import("zod").ZodNumber>;
441
556
  generationMs: import("zod").ZodOptional<import("zod").ZodNumber>;
557
+ conditionerMs: import("zod").ZodOptional<import("zod").ZodNumber>;
558
+ denoiseMs: import("zod").ZodOptional<import("zod").ZodNumber>;
559
+ vaeMs: import("zod").ZodOptional<import("zod").ZodNumber>;
560
+ postProcessMs: import("zod").ZodOptional<import("zod").ZodNumber>;
561
+ stepsPerSecond: import("zod").ZodOptional<import("zod").ZodNumber>;
442
562
  totalGenerationMs: import("zod").ZodOptional<import("zod").ZodNumber>;
443
563
  totalWallMs: import("zod").ZodOptional<import("zod").ZodNumber>;
444
564
  totalSteps: import("zod").ZodOptional<import("zod").ZodNumber>;
@@ -530,6 +650,7 @@ export declare const diffusionPlugin: {
530
650
  vae_tiling: import("zod").ZodOptional<import("zod").ZodBoolean>;
531
651
  vae_tile_size: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodNumber, import("zod").ZodString]>>;
532
652
  vae_tile_overlap: import("zod").ZodOptional<import("zod").ZodNumber>;
653
+ temporal_tiling: import("zod").ZodOptional<import("zod").ZodBoolean>;
533
654
  cache_mode: import("zod").ZodOptional<import("zod").ZodEnum<{
534
655
  disabled: "disabled";
535
656
  easycache: "easycache";
@@ -560,6 +681,11 @@ export declare const diffusionPlugin: {
560
681
  height: import("zod").ZodOptional<import("zod").ZodNumber>;
561
682
  modelLoadMs: import("zod").ZodOptional<import("zod").ZodNumber>;
562
683
  generationMs: import("zod").ZodOptional<import("zod").ZodNumber>;
684
+ conditionerMs: import("zod").ZodOptional<import("zod").ZodNumber>;
685
+ denoiseMs: import("zod").ZodOptional<import("zod").ZodNumber>;
686
+ vaeMs: import("zod").ZodOptional<import("zod").ZodNumber>;
687
+ postProcessMs: import("zod").ZodOptional<import("zod").ZodNumber>;
688
+ stepsPerSecond: import("zod").ZodOptional<import("zod").ZodNumber>;
563
689
  totalGenerationMs: import("zod").ZodOptional<import("zod").ZodNumber>;
564
690
  totalWallMs: import("zod").ZodOptional<import("zod").ZodNumber>;
565
691
  totalSteps: import("zod").ZodOptional<import("zod").ZodNumber>;
@@ -570,6 +696,8 @@ export declare const diffusionPlugin: {
570
696
  totalVideoFrames: import("zod").ZodOptional<import("zod").ZodNumber>;
571
697
  videoFrames: import("zod").ZodOptional<import("zod").ZodNumber>;
572
698
  fps: import("zod").ZodOptional<import("zod").ZodNumber>;
699
+ hasAudio: import("zod").ZodOptional<import("zod").ZodBoolean>;
700
+ audioSampleRate: import("zod").ZodOptional<import("zod").ZodNumber>;
573
701
  }, import("zod/v4/core").$strip>>;
574
702
  }, import("zod/v4/core").$strip>>;
575
703
  upscaleStream: import("../../../../schemas/index").PluginHandlerDefinition<import("zod").ZodObject<{
@@ -1,10 +1,12 @@
1
1
  import ImgStableDiffusion, { EsrganUpscaler, VideoStableDiffusion } from '@qvac/diffusion-cpp';
2
2
  import addonLogging from '@qvac/diffusion-cpp/addonLogging.js';
3
3
  import { definePlugin, defineHandler, sdcppConfigSchema, diffusionRequestSchema, diffusionStreamResponseSchema, videoRequestSchema, videoStreamResponseSchema, upscaleRequestSchema, upscaleStreamResponseSchema, ModelType, ADDON_DIFFUSION } from '../../../../schemas/index.js';
4
- import { createStreamLogger, registerAddonLogger } from '../../../../logging/index.js';
4
+ import { createStreamLogger, registerAddonLogger, getServerLogger } from '../../../../logging/index.js';
5
5
  import { ModelLoadFailedError } from '../../../../utils/errors-server.js';
6
+ import { isMobile } from '../../registry/runtime-context-registry.js';
7
+ import { stripMultiGpuKeys } from '../../../utils/multi-gpu-mobile.js';
6
8
  import { diffusion } from './ops/diffusion.js';
7
- import { video } from './ops/video.js';
9
+ import { markLtxVideoModel, video } from './ops/video.js';
8
10
  import { upscale } from './ops/upscale.js';
9
11
  // Single source of truth for `SdcppConfig.upscaler.*` → addon-config key
10
12
  // mapping. Used by both the diffusion-mode (post-generation upscaler) and the
@@ -52,13 +54,36 @@ export const diffusionPlugin = definePlugin({
52
54
  addonPackage: ADDON_DIFFUSION,
53
55
  loadConfigSchema: sdcppConfigSchema,
54
56
  async resolveConfig(cfg, ctx) {
57
+ if (cfg.uncondModelSrc && cfg.mode !== 'diffusion') {
58
+ throw new ModelLoadFailedError('modelConfig.uncondModelSrc is Ideogram 4 diffusion only. ' +
59
+ "Use mode: 'diffusion' or remove uncondModelSrc.");
60
+ }
61
+ if (cfg.uncondModelSrc && (!cfg.llmModelSrc || !cfg.vaeModelSrc)) {
62
+ throw new ModelLoadFailedError('modelConfig.uncondModelSrc selects the Ideogram 4 layout and requires ' +
63
+ 'modelConfig.llmModelSrc (Qwen3-VL) and modelConfig.vaeModelSrc.');
64
+ }
55
65
  // Standalone-upscaler mode never references auxiliary models: the primary
56
66
  // modelSrc IS the ESRGAN file. Skip resolution to avoid downloading
57
67
  // unused encoders/VAEs and to keep load fast.
58
68
  if (cfg.mode === 'upscale') {
59
69
  return { config: cfg };
60
70
  }
61
- const { clipLModelSrc, clipGModelSrc, clipVisionModelSrc, t5XxlModelSrc, llmModelSrc, vaeModelSrc, highNoiseDiffusionModelSrc, upscaler, ...rest } = cfg;
71
+ const { clipLModelSrc, clipGModelSrc, clipVisionModelSrc, t5XxlModelSrc, llmModelSrc, vaeModelSrc, highNoiseDiffusionModelSrc, uncondModelSrc, audioVaeModelSrc, embeddingsConnectorsModelSrc, upscaler, ...rest } = cfg;
72
+ // audioVae / embeddingsConnectors are LTX-2 video companions. Reject them
73
+ // up front — before any companion download — when the selected layout
74
+ // can't consume them, instead of silently resolving the file and then
75
+ // dropping it in createModel. Both fields are new, so this cannot break
76
+ // existing callers.
77
+ if (embeddingsConnectorsModelSrc && cfg.mode !== 'video') {
78
+ throw new ModelLoadFailedError('modelConfig.embeddingsConnectorsModelSrc selects the LTX-2 video ' +
79
+ "layout and is only valid with mode: 'video'.");
80
+ }
81
+ if (audioVaeModelSrc && !(cfg.mode === 'video' && embeddingsConnectorsModelSrc)) {
82
+ throw new ModelLoadFailedError('modelConfig.audioVaeModelSrc is LTX-2 video only. It requires ' +
83
+ "mode: 'video' together with modelConfig.embeddingsConnectorsModelSrc " +
84
+ '(which selects the LTX-2 layout). Add embeddingsConnectorsModelSrc ' +
85
+ 'or remove audioVaeModelSrc.');
86
+ }
62
87
  // Video jobs do not apply ESRGAN so we drop the whole `upscaler` object.
63
88
  const effectiveUpscaler = cfg.mode === 'video' ? undefined : upscaler;
64
89
  const { model_src: esrganModelSrc, ...upscalerRuntime } = effectiveUpscaler ?? {};
@@ -74,6 +99,9 @@ export const diffusionPlugin = definePlugin({
74
99
  llmModelSrc,
75
100
  vaeModelSrc,
76
101
  highNoiseDiffusionModelSrc,
102
+ uncondModelSrc,
103
+ audioVaeModelSrc,
104
+ embeddingsConnectorsModelSrc,
77
105
  esrganModelSrc
78
106
  };
79
107
  const hasSources = Object.values(sources).some(Boolean);
@@ -81,7 +109,7 @@ export const diffusionPlugin = definePlugin({
81
109
  return { config: runtimeConfig };
82
110
  }
83
111
  const resolve = ctx.resolveModelPath;
84
- const [clipLModelPath, clipGModelPath, clipVisionModelPath, t5XxlModelPath, llmModelPath, vaeModelPath, highNoiseDiffusionModelPath, esrganModelPath] = await Promise.all([
112
+ const [clipLModelPath, clipGModelPath, clipVisionModelPath, t5XxlModelPath, llmModelPath, vaeModelPath, highNoiseDiffusionModelPath, uncondModelPath, audioVaeModelPath, embeddingsConnectorsModelPath, esrganModelPath] = await Promise.all([
85
113
  clipLModelSrc ? resolve(clipLModelSrc) : undefined,
86
114
  clipGModelSrc ? resolve(clipGModelSrc) : undefined,
87
115
  clipVisionModelSrc ? resolve(clipVisionModelSrc) : undefined,
@@ -89,6 +117,9 @@ export const diffusionPlugin = definePlugin({
89
117
  llmModelSrc ? resolve(llmModelSrc) : undefined,
90
118
  vaeModelSrc ? resolve(vaeModelSrc) : undefined,
91
119
  highNoiseDiffusionModelSrc ? resolve(highNoiseDiffusionModelSrc) : undefined,
120
+ uncondModelSrc ? resolve(uncondModelSrc) : undefined,
121
+ audioVaeModelSrc ? resolve(audioVaeModelSrc) : undefined,
122
+ embeddingsConnectorsModelSrc ? resolve(embeddingsConnectorsModelSrc) : undefined,
92
123
  esrganModelSrc ? resolve(esrganModelSrc) : undefined
93
124
  ]);
94
125
  return {
@@ -101,6 +132,9 @@ export const diffusionPlugin = definePlugin({
101
132
  ...(llmModelPath && { llmModelPath }),
102
133
  ...(vaeModelPath && { vaeModelPath }),
103
134
  ...(highNoiseDiffusionModelPath && { highNoiseDiffusionModelPath }),
135
+ ...(uncondModelPath && { uncondModelPath }),
136
+ ...(audioVaeModelPath && { audioVaeModelPath }),
137
+ ...(embeddingsConnectorsModelPath && { embeddingsConnectorsModelPath }),
104
138
  ...(esrganModelPath && { esrganModelPath })
105
139
  }
106
140
  };
@@ -108,6 +142,13 @@ export const diffusionPlugin = definePlugin({
108
142
  createModel(params) {
109
143
  const { modelId, modelPath, modelConfig, artifacts } = params;
110
144
  const config = (modelConfig ?? {});
145
+ // no multi-gpu on mobile
146
+ if (isMobile()) {
147
+ const stripped = stripMultiGpuKeys(config);
148
+ if (stripped.length > 0) {
149
+ getServerLogger().warn(`[${ModelType.sdcppGeneration}:${modelId}] Multi-GPU parameters (${stripped.join(', ')}) are not supported on mobile (single-GPU device) — removing from config; model will load with single-GPU defaults`);
150
+ }
151
+ }
111
152
  // In diffusion mode the ESRGAN file (when post-generation upscale is
112
153
  // wanted) must come from upscaler.model_src — the primary modelPath is
113
154
  // the main diffusion checkpoint. Reject early with a clear error
@@ -133,28 +174,54 @@ export const diffusionPlugin = definePlugin({
133
174
  return { model };
134
175
  }
135
176
  if (config.mode === 'video') {
136
- if (!artifacts?.['t5XxlModelPath']) {
137
- throw new ModelLoadFailedError('modelConfig.t5XxlModelSrc is required in video mode. ' +
138
- 'Provide the Wan text encoder model before loading the video pipeline.');
139
- }
177
+ // Layout is selected the same way the addon self-detects it: the
178
+ // presence of the LTX-2 text-embedding connectors switches from the
179
+ // Wan layout (UMT5 via t5Xxl) to the LTX-2 layout (Gemma via llm +
180
+ // video VAE + connectors, optional audio VAE). Mirrors
181
+ // `SdModel::isLtxModel_ = !embeddingsConnectorsPath.empty()`.
182
+ const embeddingsConnectorsModelPath = artifacts?.['embeddingsConnectorsModelPath'];
140
183
  if (!artifacts?.['vaeModelPath']) {
141
184
  throw new ModelLoadFailedError('modelConfig.vaeModelSrc is required in video mode. ' +
142
- 'Provide the Wan VAE model before loading the video pipeline.');
185
+ 'Provide the Wan or LTX-2 video VAE model before loading the video pipeline.');
186
+ }
187
+ const vaeModelPath = artifacts['vaeModelPath'];
188
+ let files;
189
+ if (embeddingsConnectorsModelPath) {
190
+ if (!artifacts['llmModelPath']) {
191
+ throw new ModelLoadFailedError('modelConfig.llmModelSrc is required for LTX-2 video. ' +
192
+ 'Provide the Gemma text encoder model before loading the LTX-2 pipeline.');
193
+ }
194
+ files = {
195
+ model: modelPath,
196
+ vae: vaeModelPath,
197
+ llm: artifacts['llmModelPath'],
198
+ embeddingsConnectors: embeddingsConnectorsModelPath,
199
+ ...(artifacts['audioVaeModelPath'] && {
200
+ audioVae: artifacts['audioVaeModelPath']
201
+ }),
202
+ ...(artifacts['esrganModelPath'] && { esrgan: artifacts['esrganModelPath'] })
203
+ };
204
+ }
205
+ else {
206
+ if (!artifacts['t5XxlModelPath']) {
207
+ throw new ModelLoadFailedError('modelConfig.t5XxlModelSrc is required in video mode. ' +
208
+ 'Provide the Wan text encoder model before loading the video pipeline.');
209
+ }
210
+ files = {
211
+ model: modelPath,
212
+ vae: vaeModelPath,
213
+ t5Xxl: artifacts['t5XxlModelPath'],
214
+ ...(artifacts['highNoiseDiffusionModelPath'] && {
215
+ highNoiseDiffusionModel: artifacts['highNoiseDiffusionModelPath']
216
+ }),
217
+ ...(artifacts['clipVisionModelPath'] && {
218
+ clipVision: artifacts['clipVisionModelPath']
219
+ }),
220
+ ...(artifacts['esrganModelPath'] && { esrgan: artifacts['esrganModelPath'] })
221
+ };
143
222
  }
144
- const files = {
145
- model: modelPath,
146
- t5Xxl: artifacts['t5XxlModelPath'],
147
- vae: artifacts['vaeModelPath'],
148
- ...(artifacts?.['highNoiseDiffusionModelPath'] && {
149
- highNoiseDiffusionModel: artifacts['highNoiseDiffusionModelPath']
150
- }),
151
- ...(artifacts?.['clipVisionModelPath'] && {
152
- clipVision: artifacts['clipVisionModelPath']
153
- }),
154
- ...(artifacts?.['esrganModelPath'] && { esrgan: artifacts['esrganModelPath'] })
155
- };
156
223
  /* eslint-disable @typescript-eslint/no-unused-vars */
157
- const { clipLModelSrc, clipGModelSrc, clipVisionModelSrc, t5XxlModelSrc, llmModelSrc, vaeModelSrc, highNoiseDiffusionModelSrc, upscaler, mode, ...rest } = config;
224
+ const { clipLModelSrc, clipGModelSrc, clipVisionModelSrc, t5XxlModelSrc, llmModelSrc, vaeModelSrc, highNoiseDiffusionModelSrc, uncondModelSrc, audioVaeModelSrc, embeddingsConnectorsModelSrc, upscaler, mode, ...rest } = config;
158
225
  /* eslint-enable @typescript-eslint/no-unused-vars */
159
226
  const model = new VideoStableDiffusion({
160
227
  files,
@@ -162,6 +229,8 @@ export const diffusionPlugin = definePlugin({
162
229
  logger,
163
230
  opts: { stats: true }
164
231
  });
232
+ if (embeddingsConnectorsModelPath)
233
+ markLtxVideoModel(model);
165
234
  return { model };
166
235
  }
167
236
  const files = {
@@ -171,6 +240,9 @@ export const diffusionPlugin = definePlugin({
171
240
  ...(artifacts?.['t5XxlModelPath'] && { t5Xxl: artifacts['t5XxlModelPath'] }),
172
241
  ...(artifacts?.['llmModelPath'] && { llm: artifacts['llmModelPath'] }),
173
242
  ...(artifacts?.['vaeModelPath'] && { vae: artifacts['vaeModelPath'] }),
243
+ ...(artifacts?.['uncondModelPath'] && {
244
+ uncondModel: artifacts['uncondModelPath']
245
+ }),
174
246
  ...(artifacts?.['esrganModelPath'] && { esrgan: artifacts['esrganModelPath'] })
175
247
  };
176
248
  // `mode` is consumed by this plugin to select the model class above; the
@@ -68,14 +68,7 @@ export async function* textToSpeech(params) {
68
68
  completeBuffer = completeBuffer.concat(Array.from(data.outputArray));
69
69
  }
70
70
  const modelExecutionMs = nowMs() - modelStart;
71
- const stats = {
72
- ...(response.stats?.audioDurationMs !== undefined && {
73
- audioDuration: response.stats.audioDurationMs
74
- }),
75
- ...(response.stats?.totalSamples !== undefined && {
76
- totalSamples: response.stats.totalSamples
77
- })
78
- };
71
+ const stats = collectTtsStats(response);
79
72
  yield { buffer: completeBuffer };
80
73
  return buildStreamResult(modelExecutionMs, hasDefinedValues(stats) ? stats : undefined);
81
74
  }
@@ -83,13 +76,6 @@ export async function* textToSpeech(params) {
83
76
  yield { buffer: Array.from(data.outputArray) };
84
77
  }
85
78
  const modelExecutionMs = nowMs() - modelStart;
86
- const stats = {
87
- ...(response.stats?.audioDurationMs !== undefined && {
88
- audioDuration: response.stats.audioDurationMs
89
- }),
90
- ...(response.stats?.totalSamples !== undefined && {
91
- totalSamples: response.stats.totalSamples
92
- })
93
- };
79
+ const stats = collectTtsStats(response);
94
80
  return buildStreamResult(modelExecutionMs, hasDefinedValues(stats) ? stats : undefined);
95
81
  }
@@ -16,6 +16,7 @@ export declare const ttsPlugin: {
16
16
  streamChunkTokens?: number | undefined;
17
17
  streamFirstChunkTokens?: number | undefined;
18
18
  cfmSteps?: number | undefined;
19
+ cfgRate?: number | undefined;
19
20
  threads?: number | undefined;
20
21
  nGpuLayers?: number | undefined;
21
22
  seed?: number | undefined;
@@ -27,6 +28,7 @@ export declare const ttsPlugin: {
27
28
  ttsNumInferenceSteps?: number | undefined;
28
29
  useGPU?: boolean | undefined;
29
30
  outputSampleRate?: number | undefined;
31
+ vulkanCacheDir?: string | undefined;
30
32
  }, string>>;
31
33
  createModel(params: CreateModelParams): PluginModelResult;
32
34
  handlers: {
@@ -46,6 +48,8 @@ export declare const ttsPlugin: {
46
48
  stats: import("zod").ZodOptional<import("zod").ZodObject<{
47
49
  audioDuration: import("zod").ZodOptional<import("zod").ZodNumber>;
48
50
  totalSamples: import("zod").ZodOptional<import("zod").ZodNumber>;
51
+ enhancerBackendDevice: import("zod").ZodOptional<import("zod").ZodNumber>;
52
+ enhancerBackendId: import("zod").ZodOptional<import("zod").ZodNumber>;
49
53
  }, import("zod/v4/core").$strip>>;
50
54
  chunkIndex: import("zod").ZodOptional<import("zod").ZodNumber>;
51
55
  sentenceChunk: import("zod").ZodOptional<import("zod").ZodString>;
@@ -69,6 +73,8 @@ export declare const ttsPlugin: {
69
73
  stats: import("zod").ZodOptional<import("zod").ZodObject<{
70
74
  audioDuration: import("zod").ZodOptional<import("zod").ZodNumber>;
71
75
  totalSamples: import("zod").ZodOptional<import("zod").ZodNumber>;
76
+ enhancerBackendDevice: import("zod").ZodOptional<import("zod").ZodNumber>;
77
+ enhancerBackendId: import("zod").ZodOptional<import("zod").ZodNumber>;
72
78
  }, import("zod/v4/core").$strip>>;
73
79
  chunkIndex: import("zod").ZodOptional<import("zod").ZodNumber>;
74
80
  sentenceChunk: import("zod").ZodOptional<import("zod").ZodString>;
@@ -101,6 +101,7 @@ function createChatterboxModel(modelId, config, params, artifacts) {
101
101
  ? { streamFirstChunkTokens: config.streamFirstChunkTokens }
102
102
  : {}),
103
103
  ...(config.cfmSteps !== undefined ? { cfmSteps: config.cfmSteps } : {}),
104
+ ...(config.cfgRate !== undefined ? { cfgRate: config.cfgRate } : {}),
104
105
  ...(config.threads !== undefined ? { threads: config.threads } : {}),
105
106
  ...(config.nGpuLayers !== undefined ? { nGpuLayers: config.nGpuLayers } : {}),
106
107
  ...(config.seed !== undefined ? { seed: config.seed } : {}),
@@ -134,7 +135,8 @@ function createSupertonicModel(modelId, config, params, artifacts) {
134
135
  useGPU: config.useGPU ?? false,
135
136
  ...(config.outputSampleRate !== undefined
136
137
  ? { outputSampleRate: config.outputSampleRate }
137
- : {})
138
+ : {}),
139
+ ...(config.vulkanCacheDir !== undefined ? { vulkanCacheDir: config.vulkanCacheDir } : {})
138
140
  },
139
141
  logger,
140
142
  opts: { stats: true },
@@ -26,6 +26,8 @@ export interface NmtResponse {
26
26
  export interface TtsStats {
27
27
  audioDurationMs?: number;
28
28
  totalSamples?: number;
29
+ enhancerBackendDevice?: number;
30
+ enhancerBackendId?: number;
29
31
  }
30
32
  export interface TtsResponse {
31
33
  stats?: TtsStats;
@@ -13,10 +13,14 @@ export type TtsOpYield = {
13
13
  chunkIndex?: number;
14
14
  sentenceChunk?: string;
15
15
  };
16
+ type AddonTtsStats = {
17
+ audioDurationMs?: number;
18
+ totalSamples?: number;
19
+ enhancerBackendDevice?: number;
20
+ enhancerBackendId?: number;
21
+ };
16
22
  export declare function collectTtsStats(response: {
17
- stats?: {
18
- audioDurationMs?: number;
19
- totalSamples?: number;
20
- };
23
+ stats?: AddonTtsStats;
21
24
  }): TtsStats;
25
+ export {};
22
26
  //# sourceMappingURL=tts-stats.d.ts.map
@@ -5,6 +5,12 @@ export function collectTtsStats(response) {
5
5
  }),
6
6
  ...(response.stats?.totalSamples !== undefined && {
7
7
  totalSamples: response.stats.totalSamples
8
+ }),
9
+ ...(response.stats?.enhancerBackendDevice !== undefined && {
10
+ enhancerBackendDevice: response.stats.enhancerBackendDevice
11
+ }),
12
+ ...(response.stats?.enhancerBackendId !== undefined && {
13
+ enhancerBackendId: response.stats.enhancerBackendId
8
14
  })
9
15
  };
10
16
  }
@@ -7,9 +7,31 @@ export function createBareKitRPCServer() {
7
7
  const { IPC } = globalThis.BareKit;
8
8
  return new RPC(IPC, handleRequest);
9
9
  }
10
+ /**
11
+ * Dial the client's IPC endpoint. Two encodings cross the handshake:
12
+ *
13
+ * - `tcp://host:port` — a loopback TCP endpoint. Used by clients whose
14
+ * runtime has no portable server for filesystem sockets, notably the
15
+ * Python `asyncio` transport (`start_unix_server` is Unix-only, and
16
+ * asyncio has no cross-platform named-pipe server). One code path on
17
+ * every OS, so Windows dials the same way Linux/macOS do.
18
+ * - anything else — a filesystem path: a Unix domain socket, or a
19
+ * `\\.\pipe\...` named pipe on Windows, as the Node client (`node:net`)
20
+ * creates.
21
+ */
22
+ function connectToEndpoint(endpoint) {
23
+ if (endpoint.startsWith('tcp://')) {
24
+ const hostPort = endpoint.slice('tcp://'.length);
25
+ const sep = hostPort.lastIndexOf(':');
26
+ const host = hostPort.slice(0, sep);
27
+ const port = Number(hostPort.slice(sep + 1));
28
+ return connect(port, host);
29
+ }
30
+ return connect(endpoint);
31
+ }
10
32
  export function createIPCClient(socketPath, options) {
11
33
  logger.info(`Connecting to IPC socket at ${socketPath}`);
12
- const socket = connect(socketPath);
34
+ const socket = connectToEndpoint(socketPath);
13
35
  socket.on('connect', () => {
14
36
  logger.info('Connected to IPC server');
15
37
  });
@@ -1,5 +1,6 @@
1
1
  import {} from '../../schemas/index.js';
2
2
  import { handleBatchCompletionStream } from './handlers/batch-completion-stream.js';
3
+ import { handleCompletionOrchestrate } from './handlers/completion-orchestrate.js';
3
4
  import { handleCompletionStream } from './handlers/completion-stream.js';
4
5
  import { handleDownloadAsset } from './handlers/download-asset.js';
5
6
  import { handleLoadModel } from './handlers/load-model/index.js';
@@ -147,6 +148,10 @@ export const registry = {
147
148
  delegatedHandler: handleCompletionStreamDelegated,
148
149
  isDelegated: isModelDelegated
149
150
  },
151
+ // Deliberately no delegated handler: tool callbacks execute code on the
152
+ // client machine, so only the user's own local worker may orchestrate
153
+ // (see completionOrchestrateResponseSchema's contract note).
154
+ completionOrchestrate: { type: 'duplex', handler: handleCompletionOrchestrate },
150
155
  batchCompletionStream: {
151
156
  type: 'stream',
152
157
  handler: handleBatchCompletionStream
@@ -0,0 +1,42 @@
1
+ import type { CompletionOrchestrateRequest, CompletionOrchestrateResponse, CompletionStreamRequest, CompletionStreamResponse } from '../../../schemas/index';
2
+ import { type ToolCallbackResult } from '../../../schemas/completion-stream';
3
+ /**
4
+ * Reads newline-delimited JSON tool results off the duplex request stream
5
+ * and resolves per-callId waiters. Chunk boundaries don't align with lines,
6
+ * so a partial tail is buffered until its newline arrives.
7
+ *
8
+ * The pump is torn down by `close()` (called from a `finally` when
9
+ * orchestration ends, however it ends) so the upstream iterator is returned
10
+ * and the reader stops holding the request stream open.
11
+ */
12
+ export declare class ToolResultReader {
13
+ private buffer;
14
+ private readonly results;
15
+ private readonly waiters;
16
+ private failed;
17
+ private closed;
18
+ private readonly iterator;
19
+ constructor(inputStream: AsyncIterable<Buffer>);
20
+ private pump;
21
+ private failWaiters;
22
+ private accept;
23
+ waitFor(callId: string, timeoutMs?: number): Promise<ToolCallbackResult>;
24
+ /**
25
+ * Stop the pump and release the upstream iterator. Idempotent. Pending
26
+ * waiters are failed so a caller blocked in `waitFor` can't hang after the
27
+ * stream is torn down.
28
+ */
29
+ close(): void;
30
+ }
31
+ type RunTurn = (request: CompletionStreamRequest) => AsyncGenerator<CompletionStreamResponse, void, unknown>;
32
+ /**
33
+ * The orchestration core, pure over its collaborators so it unit-tests
34
+ * without the plugin registry: runs completion turns, forwards their events
35
+ * downstream, and when a turn requests tool calls, emits `toolCallback`
36
+ * frames and blocks on the client's results before starting the next turn
37
+ * with the extended history.
38
+ */
39
+ export declare function orchestrateCompletion(request: CompletionOrchestrateRequest, runTurn: RunTurn, reader: Pick<ToolResultReader, 'waitFor'>): AsyncGenerator<CompletionOrchestrateResponse>;
40
+ export declare function handleCompletionOrchestrate(request: CompletionOrchestrateRequest, inputStream: AsyncIterable<Buffer>): AsyncGenerator<CompletionOrchestrateResponse>;
41
+ export {};
42
+ //# sourceMappingURL=completion-orchestrate.d.ts.map