@simulatte/doppler 0.1.5 → 0.1.7

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 (392) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/README.md +25 -17
  3. package/package.json +20 -4
  4. package/src/adapters/adapter-registry.js +12 -1
  5. package/src/adapters/lora-loader.js +23 -6
  6. package/src/bridge/extension-client.d.ts +5 -0
  7. package/src/bridge/extension-client.js +40 -0
  8. package/src/bridge/index.d.ts +2 -1
  9. package/src/bridge/index.js +6 -4
  10. package/src/browser/browser-converter.js +26 -1
  11. package/src/browser/file-picker.js +6 -0
  12. package/src/browser/safetensors-parser-browser.js +84 -1
  13. package/src/browser/shard-io-browser.js +2 -2
  14. package/src/browser/tensor-source-download.js +8 -2
  15. package/src/browser/tensor-source-http.d.ts +1 -0
  16. package/src/browser/tensor-source-http.js +5 -1
  17. package/src/client/doppler-api.browser.js +20 -4
  18. package/src/client/doppler-api.js +19 -3
  19. package/src/client/doppler-provider/generation.js +12 -0
  20. package/src/client/doppler-provider/model-manager.d.ts +10 -0
  21. package/src/client/doppler-provider/model-manager.js +91 -19
  22. package/src/client/doppler-provider/source-runtime.d.ts +2 -1
  23. package/src/client/doppler-provider/source-runtime.js +132 -13
  24. package/src/client/doppler-registry.json +8 -7
  25. package/src/config/backward-registry-loader.js +17 -2
  26. package/src/config/execution-v0-contract-check.js +113 -15
  27. package/src/config/kernel-path-contract-check.js +57 -29
  28. package/src/config/kernel-path-loader.js +5 -36
  29. package/src/config/kernels/kernel-ref-digests.js +39 -39
  30. package/src/config/kernels/registry.js +14 -1
  31. package/src/config/kernels/registry.json +49 -7
  32. package/src/config/loader.d.ts +1 -1
  33. package/src/config/loader.js +43 -4
  34. package/src/config/merge-contract-check.js +59 -4
  35. package/src/config/merge-helpers.js +128 -7
  36. package/src/config/merge.d.ts +1 -0
  37. package/src/config/merge.js +28 -0
  38. package/src/config/param-validator.js +47 -2
  39. package/src/config/presets/kernel-paths/{gemma2-q4k-dequant-f32a.json → gemma2-q4k-dequant-f32a-nosubgroups.json} +3 -3
  40. package/src/config/presets/kernel-paths/gemma3-f16-fused-f32a-online-streamingprefill.json +223 -0
  41. package/src/config/presets/kernel-paths/{gemma3-q4k-dequant-f32a.json → gemma3-q4k-dequant-f32a-nosubgroups.json} +3 -3
  42. package/src/config/presets/kernel-paths/registry.json +29 -8
  43. package/src/config/presets/models/gemma2.json +2 -2
  44. package/src/config/presets/models/qwen3.json +9 -2
  45. package/src/config/presets/models/transformer.json +5 -0
  46. package/src/config/presets/runtime/experiments/bench/gemma3-bench-q4k.json +1 -1
  47. package/src/config/presets/runtime/experiments/debug/gemma3-debug-q4k.json +1 -1
  48. package/src/config/presets/runtime/experiments/verify/gemma3-verify.json +1 -1
  49. package/src/config/presets/runtime/kernels/dequant-f16-q4k.json +6 -13
  50. package/src/config/presets/runtime/kernels/dequant-f32-q4k.json +6 -13
  51. package/src/config/presets/runtime/kernels/embeddinggemma-q4k-dequant-f32a.json +37 -0
  52. package/src/config/presets/runtime/kernels/fused-q4k.json +6 -13
  53. package/src/config/presets/runtime/kernels/gemma2-q4k-dequant-f16a.json +33 -0
  54. package/src/config/presets/runtime/kernels/gemma2-q4k-dequant-f32a-nosubgroups.json +33 -0
  55. package/src/config/presets/runtime/kernels/gemma2-q4k-fused-f32a.json +33 -0
  56. package/src/config/presets/runtime/kernels/safe-q4k.json +6 -13
  57. package/src/config/presets/runtime/platform/metal-apple-q4k.json +1 -1
  58. package/src/config/required-inference-fields-contract-check.js +6 -0
  59. package/src/config/runtime.js +6 -1
  60. package/src/config/schema/debug.schema.d.ts +5 -0
  61. package/src/config/schema/doppler.schema.js +16 -21
  62. package/src/config/schema/inference-defaults.schema.js +6 -3
  63. package/src/config/schema/inference.schema.d.ts +9 -0
  64. package/src/config/schema/kernel-path.schema.d.ts +11 -1
  65. package/src/config/schema/kernel-thresholds.schema.js +12 -4
  66. package/src/config/schema/manifest.schema.d.ts +8 -1
  67. package/src/config/schema/manifest.schema.js +19 -3
  68. package/src/config/training-defaults.js +30 -22
  69. package/src/converter/conversion-plan.js +94 -9
  70. package/src/converter/core.d.ts +7 -0
  71. package/src/converter/core.js +14 -9
  72. package/src/converter/execution-v0-manifest.js +4 -1
  73. package/src/converter/index.d.ts +1 -0
  74. package/src/converter/index.js +1 -0
  75. package/src/converter/manifest-inference.js +43 -12
  76. package/src/converter/parsers/diffusion.js +0 -3
  77. package/src/converter/quantization-info.js +35 -15
  78. package/src/converter/rope-config.js +42 -0
  79. package/src/converter/shard-packer.d.ts +1 -1
  80. package/src/converter/shard-packer.js +4 -1
  81. package/src/debug/config.js +123 -11
  82. package/src/debug/signals.js +7 -1
  83. package/src/debug/tensor.d.ts +2 -0
  84. package/src/debug/tensor.js +13 -2
  85. package/src/distribution/p2p-control-plane.js +52 -12
  86. package/src/distribution/p2p-observability.js +43 -7
  87. package/src/distribution/p2p-webrtc-browser.js +20 -0
  88. package/src/distribution/shard-delivery.js +77 -26
  89. package/src/formats/gguf/types.js +33 -16
  90. package/src/formats/rdrr/groups.d.ts +12 -4
  91. package/src/formats/rdrr/groups.js +3 -6
  92. package/src/formats/rdrr/parsing.js +39 -2
  93. package/src/formats/rdrr/types.d.ts +2 -1
  94. package/src/gpu/command-recorder.js +86 -61
  95. package/src/gpu/device.d.ts +1 -0
  96. package/src/gpu/device.js +131 -19
  97. package/src/gpu/kernel-tuner/benchmarks.js +326 -316
  98. package/src/gpu/kernel-tuner/cache.js +71 -4
  99. package/src/gpu/kernel-tuner/tuner.js +22 -4
  100. package/src/gpu/kernels/attention.js +113 -34
  101. package/src/gpu/kernels/backward/adam.js +62 -58
  102. package/src/gpu/kernels/backward/attention_backward.js +257 -169
  103. package/src/gpu/kernels/backward/conv2d_backward.js +14 -1
  104. package/src/gpu/kernels/bias_add.wgsl +8 -6
  105. package/src/gpu/kernels/bias_add_f16.wgsl +8 -5
  106. package/src/gpu/kernels/cast.js +191 -149
  107. package/src/gpu/kernels/check-stop.js +33 -44
  108. package/src/gpu/kernels/conv2d.js +27 -17
  109. package/src/gpu/kernels/conv2d.wgsl +7 -8
  110. package/src/gpu/kernels/conv2d_f16.wgsl +7 -8
  111. package/src/gpu/kernels/cross_entropy_loss.js +21 -15
  112. package/src/gpu/kernels/depthwise_conv2d.js +37 -26
  113. package/src/gpu/kernels/depthwise_conv2d.wgsl +6 -9
  114. package/src/gpu/kernels/depthwise_conv2d_f16.wgsl +6 -9
  115. package/src/gpu/kernels/dequant.js +178 -126
  116. package/src/gpu/kernels/energy.d.ts +3 -21
  117. package/src/gpu/kernels/energy.js +111 -88
  118. package/src/gpu/kernels/feature-check.js +1 -1
  119. package/src/gpu/kernels/fused_ffn.js +84 -65
  120. package/src/gpu/kernels/fused_matmul_residual.js +56 -33
  121. package/src/gpu/kernels/fused_matmul_rmsnorm.js +62 -45
  122. package/src/gpu/kernels/gather.js +33 -15
  123. package/src/gpu/kernels/gelu.js +19 -11
  124. package/src/gpu/kernels/grouped_pointwise_conv2d.js +34 -23
  125. package/src/gpu/kernels/grouped_pointwise_conv2d.wgsl +6 -9
  126. package/src/gpu/kernels/grouped_pointwise_conv2d_f16.wgsl +6 -9
  127. package/src/gpu/kernels/groupnorm.js +34 -23
  128. package/src/gpu/kernels/kv-quantize.js +5 -2
  129. package/src/gpu/kernels/layernorm.js +35 -19
  130. package/src/gpu/kernels/logit-merge.js +5 -3
  131. package/src/gpu/kernels/matmul.js +83 -39
  132. package/src/gpu/kernels/modulate.js +23 -15
  133. package/src/gpu/kernels/moe.js +221 -175
  134. package/src/gpu/kernels/pixel_shuffle.js +22 -14
  135. package/src/gpu/kernels/pixel_shuffle.wgsl +4 -5
  136. package/src/gpu/kernels/pixel_shuffle_f16.wgsl +4 -5
  137. package/src/gpu/kernels/relu.js +31 -10
  138. package/src/gpu/kernels/relu.wgsl +2 -1
  139. package/src/gpu/kernels/relu_f16.wgsl +2 -1
  140. package/src/gpu/kernels/repeat_channels.js +25 -17
  141. package/src/gpu/kernels/repeat_channels.wgsl +4 -5
  142. package/src/gpu/kernels/repeat_channels_f16.wgsl +4 -5
  143. package/src/gpu/kernels/residual.js +69 -23
  144. package/src/gpu/kernels/residual.wgsl +6 -3
  145. package/src/gpu/kernels/residual_f16.wgsl +2 -1
  146. package/src/gpu/kernels/residual_f16_vec4.wgsl +2 -1
  147. package/src/gpu/kernels/residual_vec4.wgsl +2 -1
  148. package/src/gpu/kernels/rmsnorm.js +96 -28
  149. package/src/gpu/kernels/rmsnorm.wgsl +14 -6
  150. package/src/gpu/kernels/rmsnorm_f16.wgsl +10 -2
  151. package/src/gpu/kernels/rope.d.ts +2 -0
  152. package/src/gpu/kernels/rope.js +14 -1
  153. package/src/gpu/kernels/rope.wgsl +56 -40
  154. package/src/gpu/kernels/sample.js +27 -38
  155. package/src/gpu/kernels/sana_linear_attention.js +19 -12
  156. package/src/gpu/kernels/sana_linear_attention_apply.wgsl +4 -5
  157. package/src/gpu/kernels/sana_linear_attention_apply_f16.wgsl +4 -5
  158. package/src/gpu/kernels/sana_linear_attention_summary.wgsl +4 -0
  159. package/src/gpu/kernels/sana_linear_attention_summary_f16.wgsl +4 -0
  160. package/src/gpu/kernels/scale.js +18 -11
  161. package/src/gpu/kernels/shader-cache.js +4 -2
  162. package/src/gpu/kernels/silu.d.ts +1 -0
  163. package/src/gpu/kernels/silu.js +148 -82
  164. package/src/gpu/kernels/silu.wgsl +19 -9
  165. package/src/gpu/kernels/silu_f16.wgsl +19 -9
  166. package/src/gpu/kernels/softmax.js +44 -25
  167. package/src/gpu/kernels/split_qkv.js +23 -13
  168. package/src/gpu/kernels/transpose.js +31 -10
  169. package/src/gpu/kernels/transpose.wgsl +6 -5
  170. package/src/gpu/kernels/upsample2d.js +22 -13
  171. package/src/gpu/kernels/upsample2d.wgsl +6 -9
  172. package/src/gpu/kernels/upsample2d_f16.wgsl +6 -9
  173. package/src/gpu/kernels/utils.js +35 -13
  174. package/src/gpu/partitioned-buffer-pool.js +10 -2
  175. package/src/gpu/perf-guards.js +2 -9
  176. package/src/gpu/profiler.js +27 -22
  177. package/src/gpu/readback-utils.d.ts +16 -0
  178. package/src/gpu/readback-utils.js +41 -0
  179. package/src/gpu/submit-tracker.js +13 -0
  180. package/src/gpu/uniform-cache.d.ts +1 -0
  181. package/src/gpu/uniform-cache.js +30 -9
  182. package/src/hotswap/intent-bundle.js +6 -0
  183. package/src/hotswap/manifest.d.ts +10 -1
  184. package/src/hotswap/manifest.js +12 -2
  185. package/src/hotswap/runtime.js +30 -8
  186. package/src/index-browser.d.ts +44 -0
  187. package/src/index-browser.js +14 -0
  188. package/src/inference/browser-harness-contract-helpers.d.ts +5 -0
  189. package/src/inference/browser-harness-contract-helpers.js +28 -0
  190. package/src/inference/browser-harness-diffusion-energy-suites.d.ts +2 -0
  191. package/src/inference/browser-harness-diffusion-energy-suites.js +269 -0
  192. package/src/inference/browser-harness-model-helpers.d.ts +16 -0
  193. package/src/inference/browser-harness-model-helpers.js +217 -0
  194. package/src/inference/browser-harness-report-helpers.d.ts +7 -0
  195. package/src/inference/browser-harness-report-helpers.js +42 -0
  196. package/src/inference/browser-harness-runtime-helpers.d.ts +61 -0
  197. package/src/inference/browser-harness-runtime-helpers.js +415 -0
  198. package/src/inference/browser-harness-suite-helpers.d.ts +28 -0
  199. package/src/inference/browser-harness-suite-helpers.js +268 -0
  200. package/src/inference/browser-harness-text-helpers.d.ts +27 -0
  201. package/src/inference/browser-harness-text-helpers.js +788 -0
  202. package/src/inference/browser-harness.d.ts +6 -0
  203. package/src/inference/browser-harness.js +130 -1950
  204. package/src/inference/kv-cache/base.js +140 -94
  205. package/src/inference/kv-cache/tiered.js +5 -3
  206. package/src/inference/moe-router.js +88 -56
  207. package/src/inference/multi-model-network.js +5 -3
  208. package/src/inference/network-evolution.d.ts +11 -2
  209. package/src/inference/network-evolution.js +20 -21
  210. package/src/inference/pipelines/context.d.ts +3 -0
  211. package/src/inference/pipelines/context.js +142 -2
  212. package/src/inference/pipelines/diffusion/helpers.js +7 -2
  213. package/src/inference/pipelines/diffusion/pipeline.js +17 -7
  214. package/src/inference/pipelines/diffusion/sd3-transformer.js +10 -10
  215. package/src/inference/pipelines/diffusion/text-encoder-gpu.d.ts +5 -0
  216. package/src/inference/pipelines/diffusion/text-encoder-gpu.js +27 -15
  217. package/src/inference/pipelines/diffusion/vae.js +3 -7
  218. package/src/inference/pipelines/energy/pipeline.js +27 -21
  219. package/src/inference/pipelines/energy/quintel.d.ts +5 -0
  220. package/src/inference/pipelines/energy/quintel.js +11 -0
  221. package/src/inference/pipelines/energy-head/row-head-pipeline.js +17 -13
  222. package/src/inference/pipelines/structured/json-head-pipeline.js +26 -11
  223. package/src/inference/pipelines/text/attention/projections.js +151 -101
  224. package/src/inference/pipelines/text/attention/record.js +73 -10
  225. package/src/inference/pipelines/text/attention/run.js +73 -10
  226. package/src/inference/pipelines/text/chat-format.js +25 -1
  227. package/src/inference/pipelines/text/config.d.ts +4 -0
  228. package/src/inference/pipelines/text/config.js +71 -5
  229. package/src/inference/pipelines/text/embed.js +2 -8
  230. package/src/inference/pipelines/text/execution-plan.js +64 -50
  231. package/src/inference/pipelines/text/execution-v0-contract-helpers.d.ts +59 -0
  232. package/src/inference/pipelines/text/execution-v0-contract-helpers.js +937 -0
  233. package/src/inference/pipelines/text/execution-v0-runtime-builders.d.ts +15 -0
  234. package/src/inference/pipelines/text/execution-v0-runtime-builders.js +279 -0
  235. package/src/inference/pipelines/text/execution-v0.js +78 -1002
  236. package/src/inference/pipelines/text/ffn/standard.js +3 -0
  237. package/src/inference/pipelines/text/generator-steps.d.ts +46 -0
  238. package/src/inference/pipelines/text/generator-steps.js +298 -207
  239. package/src/inference/pipelines/text/generator.js +6 -23
  240. package/src/inference/pipelines/text/init.d.ts +4 -0
  241. package/src/inference/pipelines/text/init.js +134 -29
  242. package/src/inference/pipelines/text/kernel-path-auto-select.js +2 -0
  243. package/src/inference/pipelines/text/kernel-trace.d.ts +2 -0
  244. package/src/inference/pipelines/text/kernel-trace.js +6 -0
  245. package/src/inference/pipelines/text/layer.js +14 -9
  246. package/src/inference/pipelines/text/linear-attention.d.ts +10 -0
  247. package/src/inference/pipelines/text/linear-attention.js +80 -6
  248. package/src/inference/pipelines/text/logits/gpu.js +10 -5
  249. package/src/inference/pipelines/text/logits/index.js +10 -11
  250. package/src/inference/pipelines/text/logits/utils.d.ts +7 -0
  251. package/src/inference/pipelines/text/logits/utils.js +9 -0
  252. package/src/inference/pipelines/text/lora-apply.js +50 -32
  253. package/src/inference/pipelines/text/model-load.js +279 -104
  254. package/src/inference/pipelines/text/moe-cache.js +5 -4
  255. package/src/inference/pipelines/text/moe-cpu-gptoss.js +74 -69
  256. package/src/inference/pipelines/text/moe-cpu.js +42 -38
  257. package/src/inference/pipelines/text/moe-gpu.js +110 -86
  258. package/src/inference/pipelines/text/ops.js +90 -90
  259. package/src/inference/pipelines/text/probes.js +9 -9
  260. package/src/inference/pipelines/text/weights.js +17 -7
  261. package/src/inference/pipelines/text.js +17 -1
  262. package/src/inference/speculative.d.ts +2 -2
  263. package/src/inference/speculative.js +4 -18
  264. package/src/inference/test-harness.d.ts +1 -1
  265. package/src/inference/test-harness.js +15 -5
  266. package/src/inference/tokenizer.d.ts +0 -5
  267. package/src/inference/tokenizer.js +4 -23
  268. package/src/inference/tokenizers/bpe.js +9 -0
  269. package/src/inference/tokenizers/bundled.js +176 -33
  270. package/src/inference/tokenizers/sentencepiece.js +12 -0
  271. package/src/loader/doppler-loader.js +38 -22
  272. package/src/loader/dtype-utils.js +3 -44
  273. package/src/loader/embedding-loader.js +7 -3
  274. package/src/loader/experts/expert-cache.js +13 -6
  275. package/src/loader/experts/expert-loader.js +10 -6
  276. package/src/loader/final-weights-loader.js +8 -4
  277. package/src/loader/layer-loader.js +2 -1
  278. package/src/loader/loader-state.js +2 -2
  279. package/src/loader/memory-monitor.js +8 -0
  280. package/src/loader/multi-model-loader.d.ts +14 -0
  281. package/src/loader/multi-model-loader.js +70 -24
  282. package/src/loader/shard-cache.js +81 -12
  283. package/src/loader/shard-resolver.js +25 -3
  284. package/src/loader/tensors/tensor-loader.js +209 -144
  285. package/src/loader/tensors/tensor-reader.js +76 -19
  286. package/src/loader/weight-downcast.js +1 -1
  287. package/src/memory/buffer-pool.d.ts +9 -1
  288. package/src/memory/buffer-pool.js +109 -44
  289. package/src/memory/unified-detect.js +1 -1
  290. package/src/rules/inference/kernel-path.rules.json +24 -8
  291. package/src/rules/rule-registry.js +25 -1
  292. package/src/rules/tooling/command-runtime.rules.json +18 -0
  293. package/src/storage/backends/opfs-store.js +68 -24
  294. package/src/storage/downloader.js +364 -83
  295. package/src/storage/index.d.ts +3 -0
  296. package/src/storage/index.js +3 -0
  297. package/src/storage/preflight.d.ts +2 -2
  298. package/src/storage/preflight.js +24 -2
  299. package/src/storage/quickstart-downloader.js +11 -5
  300. package/src/storage/registry.js +10 -4
  301. package/src/storage/reports.js +1 -1
  302. package/src/storage/shard-manager.d.ts +15 -1
  303. package/src/storage/shard-manager.js +51 -3
  304. package/src/storage/source-artifact-store.d.ts +52 -0
  305. package/src/storage/source-artifact-store.js +234 -0
  306. package/src/tooling/command-api-constants.d.ts +9 -0
  307. package/src/tooling/command-api-constants.js +9 -0
  308. package/src/tooling/command-api-family-normalizers.d.ts +9 -0
  309. package/src/tooling/command-api-family-normalizers.js +343 -0
  310. package/src/tooling/command-api-helpers.d.ts +25 -0
  311. package/src/tooling/command-api-helpers.js +262 -0
  312. package/src/tooling/command-api.d.ts +27 -1
  313. package/src/tooling/command-api.js +26 -473
  314. package/src/tooling/command-envelope.js +4 -1
  315. package/src/tooling/command-runner-shared.js +52 -18
  316. package/src/tooling/lean-execution-contract.js +150 -3
  317. package/src/tooling/node-browser-command-runner.d.ts +4 -0
  318. package/src/tooling/node-browser-command-runner.js +218 -273
  319. package/src/tooling/node-command-runner.js +44 -3
  320. package/src/tooling/node-converter.js +27 -1
  321. package/src/tooling/node-source-runtime.d.ts +1 -1
  322. package/src/tooling/node-source-runtime.js +84 -3
  323. package/src/tooling/node-webgpu.js +30 -105
  324. package/src/tooling/opfs-cache.js +21 -4
  325. package/src/tooling/runtime-input-composition.d.ts +38 -0
  326. package/src/tooling/runtime-input-composition.js +86 -0
  327. package/src/tooling/source-runtime-bundle.d.ts +40 -5
  328. package/src/tooling/source-runtime-bundle.js +261 -34
  329. package/src/tooling/source-runtime-materializer.d.ts +6 -0
  330. package/src/tooling/source-runtime-materializer.js +93 -0
  331. package/src/training/attention-backward.js +32 -17
  332. package/src/training/autograd.js +80 -52
  333. package/src/training/checkpoint-watch.d.ts +8 -0
  334. package/src/training/checkpoint-watch.js +139 -0
  335. package/src/training/checkpoint.d.ts +6 -1
  336. package/src/training/checkpoint.js +46 -7
  337. package/src/training/clip.js +2 -1
  338. package/src/training/datasets/token-batch.js +20 -8
  339. package/src/training/distillation/artifacts.d.ts +71 -0
  340. package/src/training/distillation/artifacts.js +132 -0
  341. package/src/training/distillation/checkpoint-watch.d.ts +10 -0
  342. package/src/training/distillation/checkpoint-watch.js +58 -0
  343. package/src/training/distillation/dataset.d.ts +59 -0
  344. package/src/training/distillation/dataset.js +337 -0
  345. package/src/training/distillation/eval.d.ts +34 -0
  346. package/src/training/distillation/eval.js +310 -0
  347. package/src/training/distillation/index.d.ts +29 -0
  348. package/src/training/distillation/index.js +29 -0
  349. package/src/training/distillation/runtime.d.ts +20 -0
  350. package/src/training/distillation/runtime.js +121 -0
  351. package/src/training/distillation/scoreboard.d.ts +6 -0
  352. package/src/training/distillation/scoreboard.js +8 -0
  353. package/src/training/distillation/stage-a.d.ts +45 -0
  354. package/src/training/distillation/stage-a.js +338 -0
  355. package/src/training/distillation/stage-b.d.ts +24 -0
  356. package/src/training/distillation/stage-b.js +20 -0
  357. package/src/training/distillation/student-fixture.d.ts +22 -0
  358. package/src/training/distillation/student-fixture.js +846 -0
  359. package/src/training/distillation/suite-data.d.ts +45 -0
  360. package/src/training/distillation/suite-data.js +189 -0
  361. package/src/training/index.d.ts +10 -0
  362. package/src/training/index.js +10 -0
  363. package/src/training/lora-pipeline.d.ts +40 -0
  364. package/src/training/lora-pipeline.js +793 -0
  365. package/src/training/lora.js +26 -12
  366. package/src/training/loss.js +5 -6
  367. package/src/training/objectives/cross_entropy.js +2 -5
  368. package/src/training/objectives/distill_kd.js +4 -8
  369. package/src/training/objectives/distill_triplet.js +4 -8
  370. package/src/training/objectives/ul_stage2_base.js +4 -8
  371. package/src/training/operator-artifacts.d.ts +62 -0
  372. package/src/training/operator-artifacts.js +140 -0
  373. package/src/training/operator-command.d.ts +5 -0
  374. package/src/training/operator-command.js +455 -0
  375. package/src/training/operator-eval.d.ts +48 -0
  376. package/src/training/operator-eval.js +230 -0
  377. package/src/training/operator-scoreboard.d.ts +5 -0
  378. package/src/training/operator-scoreboard.js +44 -0
  379. package/src/training/optimizer.js +19 -7
  380. package/src/training/runner.d.ts +52 -0
  381. package/src/training/runner.js +31 -5
  382. package/src/training/suite.d.ts +112 -0
  383. package/src/training/suite.js +24 -984
  384. package/src/training/tensor-factory.d.ts +9 -0
  385. package/src/training/tensor-factory.js +13 -0
  386. package/src/training/trainer.js +3 -5
  387. package/src/training/ul_dataset.js +3 -5
  388. package/src/training/workloads.d.ts +164 -0
  389. package/src/training/workloads.js +530 -0
  390. package/src/version.js +1 -1
  391. package/tools/convert-safetensors-node.js +22 -16
  392. package/tools/doppler-cli.js +179 -63
@@ -0,0 +1,343 @@
1
+ import {
2
+ DISTILL_ACTION_SET,
3
+ LORA_ACTION_SET,
4
+ TRAINING_COMMAND_SCHEMA_VERSION,
5
+ VERIFY_SUITES,
6
+ } from './command-api-constants.js';
7
+ import {
8
+ asOptionalAction,
9
+ asOptionalBoolean,
10
+ asOptionalForceResumeReason,
11
+ asOptionalObject,
12
+ asOptionalPositiveInteger,
13
+ asOptionalString,
14
+ asOptionalStringArray,
15
+ asOptionalTrainingStage,
16
+ assertForbiddenConfigChainField,
17
+ assertForbiddenObjectField,
18
+ assertForbiddenStringField,
19
+ assertModelId,
20
+ createCommandRequestBase,
21
+ resolveCommandRuntimeContract,
22
+ resolveSuiteForCommand,
23
+ } from './command-api-helpers.js';
24
+
25
+ function normalizeConvertExecution(value) {
26
+ const execution = asOptionalObject(value, 'convertPayload.execution');
27
+ if (!execution) return null;
28
+
29
+ const workerCountPolicy = asOptionalString(
30
+ execution.workerCountPolicy,
31
+ 'convertPayload.execution.workerCountPolicy'
32
+ );
33
+ if (workerCountPolicy && workerCountPolicy !== 'cap' && workerCountPolicy !== 'error') {
34
+ throw new Error(
35
+ 'tooling command: convertPayload.execution.workerCountPolicy must be "cap" or "error" when provided.'
36
+ );
37
+ }
38
+
39
+ return {
40
+ ...execution,
41
+ workers: asOptionalPositiveInteger(
42
+ execution.workers,
43
+ 'convertPayload.execution.workers'
44
+ ),
45
+ workerCountPolicy,
46
+ maxInFlightJobs: asOptionalPositiveInteger(
47
+ execution.maxInFlightJobs,
48
+ 'convertPayload.execution.maxInFlightJobs'
49
+ ),
50
+ rowChunkRows: asOptionalPositiveInteger(
51
+ execution.rowChunkRows,
52
+ 'convertPayload.execution.rowChunkRows'
53
+ ),
54
+ rowChunkMinTensorBytes: asOptionalPositiveInteger(
55
+ execution.rowChunkMinTensorBytes,
56
+ 'convertPayload.execution.rowChunkMinTensorBytes'
57
+ ),
58
+ useGpuCast: asOptionalBoolean(
59
+ execution.useGpuCast,
60
+ 'convertPayload.execution.useGpuCast'
61
+ ),
62
+ gpuCastMinTensorBytes: asOptionalPositiveInteger(
63
+ execution.gpuCastMinTensorBytes,
64
+ 'convertPayload.execution.gpuCastMinTensorBytes'
65
+ ),
66
+ };
67
+ }
68
+
69
+ function normalizeConvertPayload(value) {
70
+ const payload = asOptionalObject(value, 'convertPayload');
71
+ if (!payload) {
72
+ throw new Error(
73
+ 'tooling command: convert requires convertPayload.converterConfig.'
74
+ );
75
+ }
76
+ const converterConfig = asOptionalObject(
77
+ payload.converterConfig,
78
+ 'convertPayload.converterConfig'
79
+ );
80
+ if (!converterConfig) {
81
+ throw new Error(
82
+ 'tooling command: convert requires convertPayload.converterConfig.'
83
+ );
84
+ }
85
+ return {
86
+ ...payload,
87
+ converterConfig,
88
+ execution: normalizeConvertExecution(payload.execution),
89
+ };
90
+ }
91
+
92
+ export function normalizeConvert(raw) {
93
+ const inputDir = asOptionalString(raw.inputDir, 'inputDir');
94
+ const outputDir = asOptionalString(raw.outputDir, 'outputDir');
95
+ const modelId = asOptionalString(raw.modelId, 'modelId');
96
+ const payload = normalizeConvertPayload(raw.convertPayload);
97
+
98
+ if (!inputDir) {
99
+ throw new Error(
100
+ 'tooling command: convert requires inputDir.'
101
+ );
102
+ }
103
+ if (modelId) {
104
+ throw new Error(
105
+ 'tooling command: convert does not accept modelId. Set convertPayload.converterConfig.output.modelBaseId.'
106
+ );
107
+ }
108
+ assertForbiddenStringField(raw, 'runtimePreset', 'convert');
109
+ assertForbiddenStringField(raw, 'runtimeConfigUrl', 'convert');
110
+ assertForbiddenObjectField(raw, 'runtimeConfig', 'convert');
111
+ assertForbiddenConfigChainField(raw, 'convert');
112
+
113
+ return {
114
+ ...createCommandRequestBase(raw, 'convert'),
115
+ inputDir,
116
+ outputDir,
117
+ convertPayload: payload,
118
+ };
119
+ }
120
+
121
+ export function normalizeTrainingOperatorCommand(raw, command) {
122
+ assertForbiddenConfigChainField(raw, command);
123
+ const allowedActions = command === 'distill' ? DISTILL_ACTION_SET : LORA_ACTION_SET;
124
+ const action = asOptionalAction(raw.action, 'action', allowedActions);
125
+ if (!action) {
126
+ throw new Error(`tooling command: ${command} requires action.`);
127
+ }
128
+ const workloadPath = asOptionalString(raw.workloadPath, 'workloadPath');
129
+ const runRoot = asOptionalString(raw.runRoot, 'runRoot');
130
+ const checkpointPath = asOptionalString(raw.checkpointPath, 'checkpointPath');
131
+ const checkpointId = asOptionalString(raw.checkpointId, 'checkpointId');
132
+ const checkpointStep = asOptionalPositiveInteger(raw.checkpointStep, 'checkpointStep');
133
+ const stageId = asOptionalString(raw.stageId, 'stageId');
134
+ const stageArtifact = asOptionalString(raw.stageArtifact, 'stageArtifact');
135
+ const subsetManifest = asOptionalString(raw.subsetManifest, 'subsetManifest');
136
+ const evalDatasetId = asOptionalString(raw.evalDatasetId, 'evalDatasetId');
137
+ const pollIntervalMs = asOptionalPositiveInteger(raw.pollIntervalMs, 'pollIntervalMs');
138
+ const stopWhenIdle = asOptionalBoolean(raw.stopWhenIdle, 'stopWhenIdle');
139
+ if (!workloadPath && !runRoot) {
140
+ throw new Error(`tooling command: ${command} requires workloadPath or runRoot.`);
141
+ }
142
+ if ((action === 'eval' || action === 'export') && !checkpointPath && !runRoot) {
143
+ throw new Error(`tooling command: ${command} ${action} requires checkpointPath or runRoot.`);
144
+ }
145
+ if (action === 'watch' && !runRoot) {
146
+ throw new Error(`tooling command: ${command} watch requires runRoot.`);
147
+ }
148
+ if ((action === 'compare' || action === 'quality-gate') && !runRoot) {
149
+ throw new Error(`tooling command: ${command} ${action} requires runRoot.`);
150
+ }
151
+ if (command === 'distill' && action === 'stage-b' && !stageArtifact && !runRoot) {
152
+ throw new Error('tooling command: distill stage-b requires stageArtifact or runRoot.');
153
+ }
154
+
155
+ return {
156
+ ...createCommandRequestBase(raw, command),
157
+ action,
158
+ workloadType: 'training',
159
+ modelUrl: null,
160
+ workloadPath,
161
+ runRoot,
162
+ checkpointPath,
163
+ checkpointId,
164
+ checkpointStep,
165
+ stageId,
166
+ stageArtifact,
167
+ subsetManifest,
168
+ evalDatasetId,
169
+ pollIntervalMs,
170
+ stopWhenIdle,
171
+ };
172
+ }
173
+
174
+ export function normalizeSuiteCommand(raw, command) {
175
+ assertForbiddenConfigChainField(raw, command);
176
+ const runtimeContract = resolveCommandRuntimeContract(command);
177
+ const suite = resolveSuiteForCommand(raw, command, runtimeContract);
178
+ if (!runtimeContract.suite && !VERIFY_SUITES.includes(suite)) {
179
+ throw new Error(
180
+ `tooling command: "${command}" suite must be one of ${VERIFY_SUITES.join(', ')}.`
181
+ );
182
+ }
183
+
184
+ const modelUrl = asOptionalString(raw.modelUrl, 'modelUrl');
185
+ const trainingTests = asOptionalStringArray(raw.trainingTests, 'trainingTests');
186
+ const trainingStage = asOptionalTrainingStage(raw.trainingStage, 'trainingStage');
187
+ const trainingConfig = asOptionalObject(raw.trainingConfig, 'trainingConfig');
188
+ const stage1Artifact = asOptionalString(raw.stage1Artifact, 'stage1Artifact');
189
+ const stage1ArtifactHash = asOptionalString(raw.stage1ArtifactHash, 'stage1ArtifactHash');
190
+ const ulArtifactDir = asOptionalString(raw.ulArtifactDir, 'ulArtifactDir');
191
+ const stageAArtifact = asOptionalString(raw.stageAArtifact, 'stageAArtifact');
192
+ const stageAArtifactHash = asOptionalString(raw.stageAArtifactHash, 'stageAArtifactHash');
193
+ const distillArtifactDir = asOptionalString(raw.distillArtifactDir, 'distillArtifactDir');
194
+ const teacherModelId = asOptionalString(raw.teacherModelId, 'teacherModelId');
195
+ const studentModelId = asOptionalString(raw.studentModelId, 'studentModelId');
196
+ const distillDatasetId = asOptionalString(raw.distillDatasetId, 'distillDatasetId');
197
+ const distillDatasetPath = asOptionalString(raw.distillDatasetPath, 'distillDatasetPath');
198
+ const distillLanguagePair = asOptionalString(raw.distillLanguagePair, 'distillLanguagePair');
199
+ const distillSourceLangs = asOptionalStringArray(raw.distillSourceLangs, 'distillSourceLangs');
200
+ const distillTargetLangs = asOptionalStringArray(raw.distillTargetLangs, 'distillTargetLangs');
201
+ const distillPairAllowlist = asOptionalStringArray(raw.distillPairAllowlist, 'distillPairAllowlist');
202
+ const strictPairContract = asOptionalBoolean(raw.strictPairContract, 'strictPairContract');
203
+ const distillShardIndex = asOptionalPositiveInteger(raw.distillShardIndex, 'distillShardIndex');
204
+ const distillShardCount = asOptionalPositiveInteger(raw.distillShardCount, 'distillShardCount');
205
+ const resumeFrom = asOptionalString(raw.resumeFrom, 'resumeFrom');
206
+ const forceResume = asOptionalBoolean(raw.forceResume, 'forceResume');
207
+ const forceResumeReason = asOptionalForceResumeReason(raw.forceResumeReason, 'forceResumeReason');
208
+ const forceResumeSource = asOptionalString(raw.forceResumeSource, 'forceResumeSource');
209
+ const checkpointOperator = asOptionalString(raw.checkpointOperator, 'checkpointOperator');
210
+ const trainingSchemaVersionInput = asOptionalPositiveInteger(
211
+ raw.trainingSchemaVersion,
212
+ 'trainingSchemaVersion'
213
+ );
214
+ const trainingBenchSteps = asOptionalPositiveInteger(raw.trainingBenchSteps, 'trainingBenchSteps');
215
+ const checkpointEvery = asOptionalPositiveInteger(raw.checkpointEvery, 'checkpointEvery');
216
+ const workloadType = asOptionalString(raw.workloadType, 'workloadType');
217
+ const isTrainingBenchWorkload = command === 'bench' && suite === 'bench' && workloadType === 'training';
218
+ const allowsTrainingFields = suite === 'training' || isTrainingBenchWorkload;
219
+ if (!allowsTrainingFields && (
220
+ trainingTests
221
+ || trainingStage
222
+ || trainingConfig
223
+ || stage1Artifact
224
+ || stage1ArtifactHash
225
+ || ulArtifactDir
226
+ || stageAArtifact
227
+ || stageAArtifactHash
228
+ || distillArtifactDir
229
+ || teacherModelId
230
+ || studentModelId
231
+ || distillDatasetId
232
+ || distillDatasetPath
233
+ || distillLanguagePair
234
+ || distillSourceLangs
235
+ || distillTargetLangs
236
+ || distillPairAllowlist
237
+ || strictPairContract !== null
238
+ || distillShardIndex
239
+ || distillShardCount
240
+ || resumeFrom
241
+ || forceResume !== null
242
+ || forceResumeReason
243
+ || forceResumeSource
244
+ || checkpointOperator
245
+ || trainingSchemaVersionInput
246
+ || trainingBenchSteps
247
+ || checkpointEvery
248
+ )) {
249
+ throw new Error(
250
+ 'tooling command: training-only fields require suite="training" or bench workloadType="training".'
251
+ );
252
+ }
253
+ if (forceResumeReason && forceResume !== true) {
254
+ throw new Error(
255
+ 'tooling command: forceResumeReason requires forceResume=true.'
256
+ );
257
+ }
258
+ if (forceResumeSource && forceResume !== true) {
259
+ throw new Error(
260
+ 'tooling command: forceResumeSource requires forceResume=true.'
261
+ );
262
+ }
263
+ if (checkpointOperator && forceResume !== true) {
264
+ throw new Error(
265
+ 'tooling command: checkpointOperator requires forceResume=true.'
266
+ );
267
+ }
268
+ const trainingSchemaVersion = allowsTrainingFields
269
+ ? (trainingSchemaVersionInput ?? TRAINING_COMMAND_SCHEMA_VERSION)
270
+ : null;
271
+ if (trainingSchemaVersionInput != null && trainingSchemaVersionInput !== TRAINING_COMMAND_SCHEMA_VERSION) {
272
+ throw new Error(
273
+ `tooling command: trainingSchemaVersion must be ${TRAINING_COMMAND_SCHEMA_VERSION}.`
274
+ );
275
+ }
276
+ if (
277
+ distillShardIndex != null
278
+ && distillShardCount != null
279
+ && distillShardIndex > distillShardCount
280
+ ) {
281
+ throw new Error('tooling command: distillShardIndex must be <= distillShardCount.');
282
+ }
283
+
284
+ const requiresModel = suite !== 'kernels' && !isTrainingBenchWorkload;
285
+ const hasTrainingSource = allowsTrainingFields && (
286
+ !!modelUrl
287
+ || !!trainingStage
288
+ || !!stage1Artifact
289
+ || !!stageAArtifact
290
+ || !!trainingConfig?.ul?.stage
291
+ || !!trainingConfig?.distill?.stage
292
+ || !!trainingConfig?.dataset
293
+ || !!trainingConfig?.distill?.datasetId
294
+ || !!trainingConfig?.distill?.datasetPath
295
+ || !!teacherModelId
296
+ || !!studentModelId
297
+ || !!distillDatasetPath
298
+ );
299
+ const modelId = (requiresModel && !hasTrainingSource)
300
+ ? assertModelId(raw.modelId, command, suite)
301
+ : asOptionalString(raw.modelId, 'modelId');
302
+
303
+ return {
304
+ ...createCommandRequestBase(raw, command),
305
+ suite,
306
+ intent: runtimeContract.intent,
307
+ modelId,
308
+ trainingTests,
309
+ trainingStage,
310
+ trainingConfig,
311
+ stage1Artifact,
312
+ stage1ArtifactHash,
313
+ ulArtifactDir,
314
+ stageAArtifact,
315
+ stageAArtifactHash,
316
+ distillArtifactDir,
317
+ teacherModelId,
318
+ studentModelId,
319
+ distillDatasetId,
320
+ distillDatasetPath,
321
+ distillLanguagePair,
322
+ distillSourceLangs,
323
+ distillTargetLangs,
324
+ distillPairAllowlist,
325
+ strictPairContract: allowsTrainingFields ? strictPairContract : null,
326
+ distillShardIndex,
327
+ distillShardCount,
328
+ resumeFrom,
329
+ forceResume: allowsTrainingFields
330
+ ? (forceResume == null ? null : forceResume === true)
331
+ : null,
332
+ forceResumeReason: allowsTrainingFields ? forceResumeReason : null,
333
+ forceResumeSource: allowsTrainingFields ? forceResumeSource : null,
334
+ checkpointOperator: allowsTrainingFields ? checkpointOperator : null,
335
+ trainingSchemaVersion,
336
+ trainingBenchSteps,
337
+ checkpointEvery: allowsTrainingFields ? checkpointEvery : null,
338
+ workloadType,
339
+ modelUrl,
340
+ captureOutput: asOptionalBoolean(raw.captureOutput, 'captureOutput') ?? false,
341
+ keepPipeline: asOptionalBoolean(raw.keepPipeline, 'keepPipeline') ?? false,
342
+ };
343
+ }
@@ -0,0 +1,25 @@
1
+ export declare function asOptionalString(value: unknown, label: string): string | null;
2
+ export declare function asOptionalBoolean(value: unknown, label: string): boolean | null;
3
+ export declare function asOptionalObject(value: unknown, label: string): Record<string, unknown> | null;
4
+ export declare function asOptionalStringArray(value: unknown, label: string): string[] | null;
5
+ export declare function asOptionalPositiveInteger(value: unknown, label: string): number | null;
6
+ export declare function asOptionalTrainingStage(value: unknown, label: string): string | null;
7
+ export declare function asOptionalForceResumeReason(value: unknown, label: string): string | null;
8
+ export declare function asOptionalAction(value: unknown, label: string, allowed: string[]): string | null;
9
+ export declare function assertCommand(value: unknown): string;
10
+ export declare function resolveCommandRuntimeContract(command: string): { suite: string | null; intent: string | null };
11
+ export declare function asOptionalCacheMode(value: unknown, label: string): 'cold' | 'warm' | null;
12
+ export declare function asOptionalLoadMode(value: unknown, label: string): 'opfs' | 'http' | 'memory' | null;
13
+ export declare function assertModelId(value: unknown, command: string, suite: string): string;
14
+ export declare function assertForbiddenStringField(raw: Record<string, unknown>, fieldName: string, command: string): void;
15
+ export declare function assertForbiddenObjectField(raw: Record<string, unknown>, fieldName: string, command: string): void;
16
+ export declare function assertForbiddenConfigChainField(raw: Record<string, unknown>, command: string): void;
17
+ export declare function resolveSuiteForCommand(
18
+ raw: Record<string, unknown>,
19
+ command: string,
20
+ runtimeContract: { suite: string | null; intent: string | null }
21
+ ): string;
22
+ export declare function createCommandRequestBase(
23
+ raw: Record<string, unknown>,
24
+ command: string
25
+ ): Record<string, unknown>;
@@ -0,0 +1,262 @@
1
+ import { isPlainObject } from '../utils/plain-object.js';
2
+ import { selectRuleValue } from '../rules/rule-registry.js';
3
+ import {
4
+ TOOLING_COMMAND_SET,
5
+ TOOLING_INTENT_SET,
6
+ TOOLING_SUITE_SET,
7
+ TRAINING_STAGE_SET,
8
+ } from './command-api-constants.js';
9
+
10
+ export function asOptionalString(value, label) {
11
+ if (value === undefined || value === null || value === '') return null;
12
+ if (typeof value !== 'string') {
13
+ throw new Error(`tooling command: ${label} must be a string when provided.`);
14
+ }
15
+ const trimmed = value.trim();
16
+ return trimmed || null;
17
+ }
18
+
19
+ export function asOptionalBoolean(value, label) {
20
+ if (value === undefined || value === null) return null;
21
+ if (typeof value !== 'boolean') {
22
+ throw new Error(`tooling command: ${label} must be a boolean when provided.`);
23
+ }
24
+ return value;
25
+ }
26
+
27
+ export function asOptionalObject(value, label) {
28
+ if (value === undefined || value === null) return null;
29
+ if (!isPlainObject(value)) {
30
+ throw new Error(`tooling command: ${label} must be an object when provided.`);
31
+ }
32
+ return value;
33
+ }
34
+
35
+ export function asOptionalStringArray(value, label) {
36
+ if (value === undefined || value === null) return null;
37
+ if (!Array.isArray(value)) {
38
+ throw new Error(`tooling command: ${label} must be an array of strings when provided.`);
39
+ }
40
+ const normalized = value.map((entry, index) => {
41
+ if (typeof entry !== 'string') {
42
+ throw new Error(`tooling command: ${label}[${index}] must be a string.`);
43
+ }
44
+ const trimmed = entry.trim();
45
+ if (!trimmed) {
46
+ throw new Error(`tooling command: ${label}[${index}] must not be empty.`);
47
+ }
48
+ return trimmed;
49
+ });
50
+ return normalized.length > 0 ? normalized : null;
51
+ }
52
+
53
+ export function asOptionalPositiveInteger(value, label) {
54
+ if (value === undefined || value === null || value === '') return null;
55
+ const parsed = Number(value);
56
+ if (!Number.isInteger(parsed) || parsed < 1) {
57
+ throw new Error(`tooling command: ${label} must be a positive integer when provided.`);
58
+ }
59
+ return parsed;
60
+ }
61
+
62
+ export function asOptionalTrainingStage(value, label) {
63
+ const stage = asOptionalString(value, label);
64
+ if (!stage) return null;
65
+ if (!TRAINING_STAGE_SET.includes(stage)) {
66
+ throw new Error(`tooling command: ${label} must be one of ${TRAINING_STAGE_SET.join(', ')}.`);
67
+ }
68
+ return stage;
69
+ }
70
+
71
+ export function asOptionalForceResumeReason(value, label) {
72
+ const reason = asOptionalString(value, label);
73
+ if (!reason) return null;
74
+ return reason;
75
+ }
76
+
77
+ export function asOptionalAction(value, label, allowed) {
78
+ const action = asOptionalString(value, label);
79
+ if (!action) return null;
80
+ if (!allowed.includes(action)) {
81
+ throw new Error(`tooling command: ${label} must be one of ${allowed.join(', ')}.`);
82
+ }
83
+ return action;
84
+ }
85
+
86
+ export function assertCommand(value) {
87
+ const command = asOptionalString(value, 'command');
88
+ if (!command) {
89
+ throw new Error('tooling command: command is required.');
90
+ }
91
+ if (!TOOLING_COMMAND_SET.includes(command)) {
92
+ throw new Error(`tooling command: unsupported command "${command}".`);
93
+ }
94
+ return command;
95
+ }
96
+
97
+ export function resolveCommandRuntimeContract(command) {
98
+ const runtimeContract = selectRuleValue('tooling', 'commandRuntime', 'runtimeContract', { command });
99
+ if (!isPlainObject(runtimeContract)) {
100
+ throw new Error(`tooling command: missing runtime contract metadata for "${command}".`);
101
+ }
102
+
103
+ const suite = runtimeContract.suite == null
104
+ ? null
105
+ : asOptionalString(runtimeContract.suite, `runtime contract suite for "${command}"`);
106
+ if (suite && !TOOLING_SUITE_SET.includes(suite)) {
107
+ throw new Error(`tooling command: runtime contract suite "${suite}" is not supported.`);
108
+ }
109
+
110
+ const intent = runtimeContract.intent == null
111
+ ? null
112
+ : asOptionalString(runtimeContract.intent, `runtime contract intent for "${command}"`);
113
+ if (intent && !TOOLING_INTENT_SET.includes(intent)) {
114
+ throw new Error(`tooling command: runtime contract intent "${intent}" is not supported.`);
115
+ }
116
+
117
+ return {
118
+ suite,
119
+ intent,
120
+ };
121
+ }
122
+
123
+ export function asOptionalCacheMode(value, label) {
124
+ const cacheMode = asOptionalString(value, label);
125
+ if (!cacheMode) return null;
126
+ if (cacheMode !== 'cold' && cacheMode !== 'warm') {
127
+ throw new Error(`${label} must be "cold" or "warm"`);
128
+ }
129
+ return cacheMode;
130
+ }
131
+
132
+ export function asOptionalLoadMode(value, label) {
133
+ const loadMode = asOptionalString(value, label);
134
+ if (!loadMode) return null;
135
+ if (loadMode !== 'opfs' && loadMode !== 'http' && loadMode !== 'memory') {
136
+ throw new Error(`${label} must be "opfs", "http", or "memory"`);
137
+ }
138
+ return loadMode;
139
+ }
140
+
141
+ export function assertModelId(value, command, suite) {
142
+ const modelId = asOptionalString(value, 'modelId');
143
+ if (!modelId) {
144
+ throw new Error(
145
+ `tooling command: modelId is required for command "${command}" (suite "${suite}").`
146
+ );
147
+ }
148
+ return modelId;
149
+ }
150
+
151
+ export function assertForbiddenStringField(raw, fieldName, command) {
152
+ const value = asOptionalString(raw[fieldName], fieldName);
153
+ if (value) {
154
+ throw new Error(
155
+ `tooling command: ${command} does not accept ${fieldName}.`
156
+ );
157
+ }
158
+ }
159
+
160
+ export function assertForbiddenObjectField(raw, fieldName, command) {
161
+ const value = asOptionalObject(raw[fieldName], fieldName);
162
+ if (value) {
163
+ throw new Error(
164
+ `tooling command: ${command} does not accept ${fieldName}.`
165
+ );
166
+ }
167
+ }
168
+
169
+ export function assertForbiddenConfigChainField(raw, command) {
170
+ const value = asOptionalStringArray(raw.configChain, 'configChain');
171
+ if (value) {
172
+ throw new Error(
173
+ `tooling command: ${command} does not accept configChain. ` +
174
+ 'configChain is only supported by harness/browser-manifest runtime composition.'
175
+ );
176
+ }
177
+ }
178
+
179
+ export function resolveSuiteForCommand(raw, command, runtimeContract) {
180
+ const inputSuite = asOptionalString(raw.suite, 'suite');
181
+ if (runtimeContract.suite) {
182
+ if (inputSuite && inputSuite !== runtimeContract.suite) {
183
+ throw new Error(
184
+ `tooling command: "${command}" requires suite "${runtimeContract.suite}" and does not accept "${inputSuite}".`
185
+ );
186
+ }
187
+ return runtimeContract.suite;
188
+ }
189
+
190
+ const suite = inputSuite;
191
+ if (!suite) {
192
+ throw new Error(`tooling command: suite is required for "${command}".`);
193
+ }
194
+ if (!TOOLING_SUITE_SET.includes(suite)) {
195
+ throw new Error(`tooling command: unsupported suite "${suite}".`);
196
+ }
197
+ return suite;
198
+ }
199
+
200
+ export function createCommandRequestBase(raw, command) {
201
+ return {
202
+ command,
203
+ suite: null,
204
+ intent: null,
205
+ action: null,
206
+ modelId: null,
207
+ trainingTests: null,
208
+ trainingStage: null,
209
+ trainingConfig: null,
210
+ stage1Artifact: null,
211
+ stage1ArtifactHash: null,
212
+ ulArtifactDir: null,
213
+ stageAArtifact: null,
214
+ stageAArtifactHash: null,
215
+ distillArtifactDir: null,
216
+ teacherModelId: null,
217
+ studentModelId: null,
218
+ distillDatasetId: null,
219
+ distillDatasetPath: null,
220
+ distillLanguagePair: null,
221
+ distillSourceLangs: null,
222
+ distillTargetLangs: null,
223
+ distillPairAllowlist: null,
224
+ strictPairContract: null,
225
+ distillShardIndex: null,
226
+ distillShardCount: null,
227
+ resumeFrom: null,
228
+ forceResume: null,
229
+ forceResumeReason: null,
230
+ forceResumeSource: null,
231
+ checkpointOperator: null,
232
+ trainingSchemaVersion: null,
233
+ trainingBenchSteps: null,
234
+ checkpointEvery: null,
235
+ workloadType: asOptionalString(raw.workloadType, 'workloadType'),
236
+ modelUrl: asOptionalString(raw.modelUrl, 'modelUrl'),
237
+ cacheMode: asOptionalCacheMode(raw.cacheMode, 'cacheMode'),
238
+ loadMode: asOptionalLoadMode(raw.loadMode, 'loadMode'),
239
+ runtimePreset: asOptionalString(raw.runtimePreset, 'runtimePreset'),
240
+ runtimeConfigUrl: asOptionalString(raw.runtimeConfigUrl, 'runtimeConfigUrl'),
241
+ runtimeConfig: asOptionalObject(raw.runtimeConfig, 'runtimeConfig'),
242
+ inputDir: null,
243
+ outputDir: null,
244
+ convertPayload: null,
245
+ workloadPath: null,
246
+ runRoot: null,
247
+ checkpointPath: null,
248
+ checkpointId: null,
249
+ checkpointStep: null,
250
+ stageId: null,
251
+ stageArtifact: null,
252
+ subsetManifest: null,
253
+ evalDatasetId: null,
254
+ pollIntervalMs: null,
255
+ stopWhenIdle: null,
256
+ captureOutput: false,
257
+ keepPipeline: false,
258
+ report: asOptionalObject(raw.report, 'report'),
259
+ timestamp: raw.timestamp ?? null,
260
+ searchParams: raw.searchParams ?? null,
261
+ };
262
+ }
@@ -1,10 +1,12 @@
1
1
  import type { ConverterConfigSchema } from '../config/schema/converter.schema.js';
2
2
 
3
- export type ToolingCommand = 'convert' | 'debug' | 'bench' | 'verify';
3
+ export type ToolingCommand = 'convert' | 'debug' | 'bench' | 'verify' | 'lora' | 'distill';
4
4
  export type ToolingSurface = 'browser' | 'node';
5
5
  export type ToolingSuite = 'kernels' | 'inference' | 'training' | 'bench' | 'debug' | 'diffusion' | 'energy';
6
6
  export type ToolingIntent = 'verify' | 'investigate' | 'calibrate' | null;
7
7
  export type ToolingTrainingStage = 'stage1_joint' | 'stage2_base' | 'stage_a' | 'stage_b';
8
+ export type ToolingDistillAction = 'run' | 'stage-a' | 'stage-b' | 'eval' | 'watch' | 'compare' | 'quality-gate' | 'subsets';
9
+ export type ToolingLoraAction = 'run' | 'eval' | 'watch' | 'export' | 'compare' | 'quality-gate' | 'activate';
8
10
 
9
11
  export interface ToolingConvertExecutionPayload {
10
12
  workers?: number | null;
@@ -25,6 +27,7 @@ export interface ToolingConvertPayload {
25
27
 
26
28
  export interface ToolingCommandRequestInput {
27
29
  command: ToolingCommand;
30
+ action?: ToolingDistillAction | ToolingLoraAction;
28
31
  suite?: ToolingSuite;
29
32
  modelId?: string;
30
33
  trainingTests?: string[];
@@ -65,6 +68,17 @@ export interface ToolingCommandRequestInput {
65
68
  inputDir?: string;
66
69
  outputDir?: string;
67
70
  convertPayload?: ToolingConvertPayload;
71
+ workloadPath?: string;
72
+ runRoot?: string;
73
+ checkpointPath?: string;
74
+ checkpointId?: string;
75
+ checkpointStep?: number;
76
+ stageId?: string;
77
+ stageArtifact?: string;
78
+ subsetManifest?: string;
79
+ evalDatasetId?: string;
80
+ pollIntervalMs?: number;
81
+ stopWhenIdle?: boolean;
68
82
  captureOutput?: boolean;
69
83
  keepPipeline?: boolean;
70
84
  report?: Record<string, unknown> | null;
@@ -76,6 +90,7 @@ export interface ToolingCommandRequest {
76
90
  command: ToolingCommand;
77
91
  suite: ToolingSuite | null;
78
92
  intent: ToolingIntent;
93
+ action: ToolingDistillAction | ToolingLoraAction | null;
79
94
  modelId: string | null;
80
95
  trainingTests: string[] | null;
81
96
  trainingStage: ToolingTrainingStage | null;
@@ -115,6 +130,17 @@ export interface ToolingCommandRequest {
115
130
  inputDir: string | null;
116
131
  outputDir: string | null;
117
132
  convertPayload: ToolingConvertPayload | null;
133
+ workloadPath: string | null;
134
+ runRoot: string | null;
135
+ checkpointPath: string | null;
136
+ checkpointId: string | null;
137
+ checkpointStep: number | null;
138
+ stageId: string | null;
139
+ stageArtifact: string | null;
140
+ subsetManifest: string | null;
141
+ evalDatasetId: string | null;
142
+ pollIntervalMs: number | null;
143
+ stopWhenIdle: boolean | null;
118
144
  captureOutput: boolean;
119
145
  keepPipeline: boolean;
120
146
  report: Record<string, unknown> | null;