@simulatte/doppler 0.1.6 → 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 (316) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/README.md +16 -23
  3. package/package.json +14 -1
  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 +1 -1
  30. package/src/config/kernels/registry.js +14 -1
  31. package/src/config/kernels/registry.json +7 -5
  32. package/src/config/loader.d.ts +1 -1
  33. package/src/config/loader.js +12 -2
  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 +10 -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/runtime/experiments/bench/gemma3-bench-q4k.json +1 -1
  45. package/src/config/presets/runtime/experiments/debug/gemma3-debug-q4k.json +1 -1
  46. package/src/config/presets/runtime/experiments/verify/gemma3-verify.json +1 -1
  47. package/src/config/presets/runtime/kernels/dequant-f16-q4k.json +6 -13
  48. package/src/config/presets/runtime/kernels/dequant-f32-q4k.json +6 -13
  49. package/src/config/presets/runtime/kernels/embeddinggemma-q4k-dequant-f32a.json +37 -0
  50. package/src/config/presets/runtime/kernels/fused-q4k.json +6 -13
  51. package/src/config/presets/runtime/kernels/gemma2-q4k-dequant-f16a.json +33 -0
  52. package/src/config/presets/runtime/kernels/gemma2-q4k-dequant-f32a-nosubgroups.json +33 -0
  53. package/src/config/presets/runtime/kernels/gemma2-q4k-fused-f32a.json +33 -0
  54. package/src/config/presets/runtime/kernels/safe-q4k.json +6 -13
  55. package/src/config/presets/runtime/platform/metal-apple-q4k.json +1 -1
  56. package/src/config/runtime.js +6 -1
  57. package/src/config/schema/debug.schema.d.ts +5 -0
  58. package/src/config/schema/doppler.schema.js +16 -21
  59. package/src/config/schema/inference-defaults.schema.js +3 -3
  60. package/src/config/schema/kernel-path.schema.d.ts +5 -1
  61. package/src/config/schema/kernel-thresholds.schema.js +12 -4
  62. package/src/config/schema/manifest.schema.d.ts +2 -1
  63. package/src/config/schema/manifest.schema.js +16 -3
  64. package/src/config/training-defaults.js +30 -22
  65. package/src/converter/conversion-plan.js +94 -9
  66. package/src/converter/core.d.ts +7 -0
  67. package/src/converter/core.js +14 -9
  68. package/src/converter/execution-v0-manifest.js +4 -1
  69. package/src/converter/index.d.ts +1 -0
  70. package/src/converter/index.js +1 -0
  71. package/src/converter/manifest-inference.js +43 -12
  72. package/src/converter/parsers/diffusion.js +0 -3
  73. package/src/converter/quantization-info.js +35 -15
  74. package/src/converter/shard-packer.d.ts +1 -1
  75. package/src/converter/shard-packer.js +4 -1
  76. package/src/debug/config.js +123 -11
  77. package/src/debug/signals.js +7 -1
  78. package/src/debug/tensor.d.ts +2 -0
  79. package/src/debug/tensor.js +13 -2
  80. package/src/distribution/p2p-control-plane.js +52 -12
  81. package/src/distribution/p2p-observability.js +43 -7
  82. package/src/distribution/p2p-webrtc-browser.js +20 -0
  83. package/src/distribution/shard-delivery.js +77 -26
  84. package/src/formats/gguf/types.js +33 -16
  85. package/src/formats/rdrr/groups.d.ts +12 -4
  86. package/src/formats/rdrr/groups.js +3 -6
  87. package/src/formats/rdrr/parsing.js +39 -2
  88. package/src/formats/rdrr/types.d.ts +2 -1
  89. package/src/gpu/command-recorder.js +86 -61
  90. package/src/gpu/device.d.ts +1 -0
  91. package/src/gpu/device.js +73 -19
  92. package/src/gpu/kernel-tuner/benchmarks.js +326 -316
  93. package/src/gpu/kernel-tuner/cache.js +71 -4
  94. package/src/gpu/kernel-tuner/tuner.js +22 -4
  95. package/src/gpu/kernels/attention.js +15 -34
  96. package/src/gpu/kernels/backward/adam.js +62 -58
  97. package/src/gpu/kernels/backward/attention_backward.js +257 -169
  98. package/src/gpu/kernels/backward/conv2d_backward.js +14 -1
  99. package/src/gpu/kernels/cast.js +191 -149
  100. package/src/gpu/kernels/check-stop.js +33 -44
  101. package/src/gpu/kernels/conv2d.js +27 -17
  102. package/src/gpu/kernels/cross_entropy_loss.js +21 -15
  103. package/src/gpu/kernels/depthwise_conv2d.js +36 -26
  104. package/src/gpu/kernels/dequant.js +178 -126
  105. package/src/gpu/kernels/energy.d.ts +3 -21
  106. package/src/gpu/kernels/energy.js +111 -88
  107. package/src/gpu/kernels/feature-check.js +1 -1
  108. package/src/gpu/kernels/fused_ffn.js +84 -65
  109. package/src/gpu/kernels/fused_matmul_residual.js +56 -33
  110. package/src/gpu/kernels/fused_matmul_rmsnorm.js +62 -45
  111. package/src/gpu/kernels/gather.js +33 -15
  112. package/src/gpu/kernels/gelu.js +19 -11
  113. package/src/gpu/kernels/grouped_pointwise_conv2d.js +33 -23
  114. package/src/gpu/kernels/groupnorm.js +34 -23
  115. package/src/gpu/kernels/kv-quantize.js +5 -2
  116. package/src/gpu/kernels/layernorm.js +35 -19
  117. package/src/gpu/kernels/logit-merge.js +5 -3
  118. package/src/gpu/kernels/matmul.js +58 -39
  119. package/src/gpu/kernels/modulate.js +23 -15
  120. package/src/gpu/kernels/moe.js +221 -175
  121. package/src/gpu/kernels/pixel_shuffle.js +22 -14
  122. package/src/gpu/kernels/relu.js +18 -10
  123. package/src/gpu/kernels/repeat_channels.js +25 -17
  124. package/src/gpu/kernels/residual.js +37 -27
  125. package/src/gpu/kernels/rmsnorm.js +57 -41
  126. package/src/gpu/kernels/rope.js +3 -0
  127. package/src/gpu/kernels/sample.js +27 -38
  128. package/src/gpu/kernels/sana_linear_attention.js +18 -10
  129. package/src/gpu/kernels/scale.js +18 -11
  130. package/src/gpu/kernels/shader-cache.js +4 -2
  131. package/src/gpu/kernels/silu.js +120 -72
  132. package/src/gpu/kernels/softmax.js +44 -25
  133. package/src/gpu/kernels/split_qkv.js +23 -13
  134. package/src/gpu/kernels/transpose.js +18 -10
  135. package/src/gpu/kernels/transpose.wgsl +5 -3
  136. package/src/gpu/kernels/upsample2d.js +21 -13
  137. package/src/gpu/kernels/utils.js +20 -13
  138. package/src/gpu/partitioned-buffer-pool.js +10 -2
  139. package/src/gpu/perf-guards.js +2 -9
  140. package/src/gpu/profiler.js +27 -22
  141. package/src/gpu/readback-utils.d.ts +16 -0
  142. package/src/gpu/readback-utils.js +41 -0
  143. package/src/gpu/submit-tracker.js +13 -0
  144. package/src/gpu/uniform-cache.d.ts +1 -0
  145. package/src/gpu/uniform-cache.js +30 -9
  146. package/src/hotswap/intent-bundle.js +6 -0
  147. package/src/hotswap/manifest.d.ts +10 -1
  148. package/src/hotswap/manifest.js +12 -2
  149. package/src/hotswap/runtime.js +30 -8
  150. package/src/index-browser.d.ts +44 -0
  151. package/src/index-browser.js +14 -0
  152. package/src/inference/browser-harness-contract-helpers.d.ts +5 -0
  153. package/src/inference/browser-harness-contract-helpers.js +28 -0
  154. package/src/inference/browser-harness-diffusion-energy-suites.d.ts +2 -0
  155. package/src/inference/browser-harness-diffusion-energy-suites.js +269 -0
  156. package/src/inference/browser-harness-model-helpers.d.ts +16 -0
  157. package/src/inference/browser-harness-model-helpers.js +217 -0
  158. package/src/inference/browser-harness-report-helpers.d.ts +7 -0
  159. package/src/inference/browser-harness-report-helpers.js +42 -0
  160. package/src/inference/browser-harness-runtime-helpers.d.ts +61 -0
  161. package/src/inference/browser-harness-runtime-helpers.js +415 -0
  162. package/src/inference/browser-harness-suite-helpers.d.ts +28 -0
  163. package/src/inference/browser-harness-suite-helpers.js +268 -0
  164. package/src/inference/browser-harness-text-helpers.d.ts +27 -0
  165. package/src/inference/browser-harness-text-helpers.js +788 -0
  166. package/src/inference/browser-harness.d.ts +6 -0
  167. package/src/inference/browser-harness.js +130 -1996
  168. package/src/inference/kv-cache/base.js +140 -94
  169. package/src/inference/kv-cache/tiered.js +5 -3
  170. package/src/inference/moe-router.js +88 -56
  171. package/src/inference/multi-model-network.js +5 -3
  172. package/src/inference/network-evolution.d.ts +11 -2
  173. package/src/inference/network-evolution.js +20 -21
  174. package/src/inference/pipelines/context.d.ts +3 -0
  175. package/src/inference/pipelines/context.js +142 -2
  176. package/src/inference/pipelines/diffusion/helpers.js +7 -2
  177. package/src/inference/pipelines/diffusion/pipeline.js +2 -1
  178. package/src/inference/pipelines/diffusion/sd3-transformer.js +10 -10
  179. package/src/inference/pipelines/diffusion/vae.js +3 -7
  180. package/src/inference/pipelines/energy/pipeline.js +27 -21
  181. package/src/inference/pipelines/energy/quintel.d.ts +5 -0
  182. package/src/inference/pipelines/energy/quintel.js +11 -0
  183. package/src/inference/pipelines/energy-head/row-head-pipeline.js +17 -13
  184. package/src/inference/pipelines/structured/json-head-pipeline.js +26 -11
  185. package/src/inference/pipelines/text/attention/projections.js +151 -101
  186. package/src/inference/pipelines/text/attention/record.js +62 -8
  187. package/src/inference/pipelines/text/attention/run.js +62 -8
  188. package/src/inference/pipelines/text/config.js +3 -4
  189. package/src/inference/pipelines/text/embed.js +2 -8
  190. package/src/inference/pipelines/text/execution-plan.js +41 -19
  191. package/src/inference/pipelines/text/execution-v0-contract-helpers.d.ts +59 -0
  192. package/src/inference/pipelines/text/execution-v0-contract-helpers.js +937 -0
  193. package/src/inference/pipelines/text/execution-v0-runtime-builders.d.ts +15 -0
  194. package/src/inference/pipelines/text/execution-v0-runtime-builders.js +279 -0
  195. package/src/inference/pipelines/text/execution-v0.js +62 -1013
  196. package/src/inference/pipelines/text/generator-steps.d.ts +46 -0
  197. package/src/inference/pipelines/text/generator-steps.js +298 -207
  198. package/src/inference/pipelines/text/generator.js +6 -23
  199. package/src/inference/pipelines/text/init.js +78 -20
  200. package/src/inference/pipelines/text/kernel-path-auto-select.js +2 -0
  201. package/src/inference/pipelines/text/kernel-trace.d.ts +2 -0
  202. package/src/inference/pipelines/text/kernel-trace.js +6 -0
  203. package/src/inference/pipelines/text/layer.js +3 -9
  204. package/src/inference/pipelines/text/linear-attention.d.ts +10 -0
  205. package/src/inference/pipelines/text/linear-attention.js +80 -6
  206. package/src/inference/pipelines/text/logits/gpu.js +10 -5
  207. package/src/inference/pipelines/text/logits/index.js +10 -11
  208. package/src/inference/pipelines/text/logits/utils.d.ts +7 -0
  209. package/src/inference/pipelines/text/logits/utils.js +9 -0
  210. package/src/inference/pipelines/text/lora-apply.js +50 -32
  211. package/src/inference/pipelines/text/model-load.js +279 -104
  212. package/src/inference/pipelines/text/moe-cache.js +5 -4
  213. package/src/inference/pipelines/text/moe-cpu-gptoss.js +74 -69
  214. package/src/inference/pipelines/text/moe-cpu.js +42 -38
  215. package/src/inference/pipelines/text/moe-gpu.js +110 -86
  216. package/src/inference/pipelines/text/ops.js +90 -90
  217. package/src/inference/pipelines/text/probes.js +9 -9
  218. package/src/inference/pipelines/text/weights.js +17 -7
  219. package/src/inference/pipelines/text.js +13 -1
  220. package/src/inference/speculative.d.ts +2 -2
  221. package/src/inference/speculative.js +4 -18
  222. package/src/inference/test-harness.d.ts +1 -1
  223. package/src/inference/test-harness.js +15 -5
  224. package/src/inference/tokenizer.d.ts +0 -5
  225. package/src/inference/tokenizer.js +4 -23
  226. package/src/inference/tokenizers/bpe.js +9 -0
  227. package/src/inference/tokenizers/bundled.js +20 -0
  228. package/src/inference/tokenizers/sentencepiece.js +12 -0
  229. package/src/loader/doppler-loader.js +38 -22
  230. package/src/loader/dtype-utils.js +3 -44
  231. package/src/loader/embedding-loader.js +7 -3
  232. package/src/loader/experts/expert-cache.js +13 -6
  233. package/src/loader/experts/expert-loader.js +10 -6
  234. package/src/loader/final-weights-loader.js +8 -4
  235. package/src/loader/layer-loader.js +2 -1
  236. package/src/loader/loader-state.js +2 -2
  237. package/src/loader/memory-monitor.js +8 -0
  238. package/src/loader/multi-model-loader.d.ts +14 -0
  239. package/src/loader/multi-model-loader.js +70 -24
  240. package/src/loader/shard-cache.js +81 -12
  241. package/src/loader/shard-resolver.js +25 -3
  242. package/src/loader/tensors/tensor-loader.js +209 -144
  243. package/src/loader/tensors/tensor-reader.js +76 -19
  244. package/src/loader/weight-downcast.js +1 -1
  245. package/src/memory/buffer-pool.d.ts +9 -1
  246. package/src/memory/buffer-pool.js +109 -44
  247. package/src/memory/unified-detect.js +1 -1
  248. package/src/rules/inference/kernel-path.rules.json +24 -8
  249. package/src/rules/rule-registry.js +25 -1
  250. package/src/storage/backends/opfs-store.js +68 -24
  251. package/src/storage/downloader.js +364 -83
  252. package/src/storage/index.d.ts +3 -0
  253. package/src/storage/index.js +3 -0
  254. package/src/storage/preflight.d.ts +2 -2
  255. package/src/storage/preflight.js +24 -2
  256. package/src/storage/quickstart-downloader.js +11 -5
  257. package/src/storage/registry.js +10 -4
  258. package/src/storage/reports.js +1 -1
  259. package/src/storage/shard-manager.d.ts +15 -1
  260. package/src/storage/shard-manager.js +51 -3
  261. package/src/storage/source-artifact-store.d.ts +52 -0
  262. package/src/storage/source-artifact-store.js +234 -0
  263. package/src/tooling/command-api-constants.d.ts +9 -0
  264. package/src/tooling/command-api-constants.js +9 -0
  265. package/src/tooling/command-api-family-normalizers.d.ts +9 -0
  266. package/src/tooling/command-api-family-normalizers.js +343 -0
  267. package/src/tooling/command-api-helpers.d.ts +25 -0
  268. package/src/tooling/command-api-helpers.js +262 -0
  269. package/src/tooling/command-api.js +16 -602
  270. package/src/tooling/command-envelope.js +4 -1
  271. package/src/tooling/command-runner-shared.js +52 -18
  272. package/src/tooling/lean-execution-contract.js +150 -3
  273. package/src/tooling/node-browser-command-runner.js +161 -271
  274. package/src/tooling/node-command-runner.js +29 -3
  275. package/src/tooling/node-converter.js +27 -1
  276. package/src/tooling/node-source-runtime.d.ts +1 -1
  277. package/src/tooling/node-source-runtime.js +84 -3
  278. package/src/tooling/node-webgpu.js +24 -21
  279. package/src/tooling/opfs-cache.js +21 -4
  280. package/src/tooling/runtime-input-composition.d.ts +38 -0
  281. package/src/tooling/runtime-input-composition.js +86 -0
  282. package/src/tooling/source-runtime-bundle.d.ts +40 -5
  283. package/src/tooling/source-runtime-bundle.js +261 -34
  284. package/src/tooling/source-runtime-materializer.d.ts +6 -0
  285. package/src/tooling/source-runtime-materializer.js +93 -0
  286. package/src/training/attention-backward.js +32 -17
  287. package/src/training/autograd.js +80 -52
  288. package/src/training/checkpoint-watch.d.ts +2 -1
  289. package/src/training/checkpoint-watch.js +39 -6
  290. package/src/training/checkpoint.js +40 -11
  291. package/src/training/clip.js +2 -1
  292. package/src/training/datasets/token-batch.js +20 -8
  293. package/src/training/distillation/checkpoint-watch.js +1 -0
  294. package/src/training/distillation/student-fixture.d.ts +22 -0
  295. package/src/training/distillation/student-fixture.js +846 -0
  296. package/src/training/distillation/suite-data.d.ts +45 -0
  297. package/src/training/distillation/suite-data.js +189 -0
  298. package/src/training/lora-pipeline.js +4 -7
  299. package/src/training/lora.js +26 -12
  300. package/src/training/loss.js +5 -6
  301. package/src/training/objectives/cross_entropy.js +2 -5
  302. package/src/training/objectives/distill_kd.js +4 -8
  303. package/src/training/objectives/distill_triplet.js +4 -8
  304. package/src/training/objectives/ul_stage2_base.js +4 -8
  305. package/src/training/operator-command.js +2 -0
  306. package/src/training/optimizer.js +19 -7
  307. package/src/training/runner.js +2 -1
  308. package/src/training/suite.js +18 -978
  309. package/src/training/tensor-factory.d.ts +9 -0
  310. package/src/training/tensor-factory.js +13 -0
  311. package/src/training/trainer.js +3 -5
  312. package/src/training/ul_dataset.js +3 -5
  313. package/src/training/workloads.js +70 -79
  314. package/src/version.js +1 -1
  315. package/tools/convert-safetensors-node.js +22 -16
  316. package/tools/doppler-cli.js +44 -25
@@ -1,15 +1,20 @@
1
1
  import { isPlainObject } from '../utils/plain-object.js';
2
- import { selectRuleValue } from '../rules/rule-registry.js';
3
-
4
- const TOOLING_COMMAND_SET = ['convert', 'debug', 'bench', 'verify', 'lora', 'distill'];
5
- const TOOLING_SURFACE_SET = ['browser', 'node'];
6
- const TOOLING_SUITE_SET = ['kernels', 'inference', 'training', 'bench', 'debug', 'diffusion', 'energy'];
7
- const TOOLING_INTENT_SET = ['verify', 'investigate', 'calibrate'];
8
- const VERIFY_SUITES = ['kernels', 'inference', 'training', 'diffusion', 'energy'];
9
- const TRAINING_STAGE_SET = ['stage1_joint', 'stage2_base', 'stage_a', 'stage_b'];
10
- const DISTILL_ACTION_SET = ['run', 'stage-a', 'stage-b', 'eval', 'watch', 'compare', 'quality-gate', 'subsets'];
11
- const LORA_ACTION_SET = ['run', 'eval', 'watch', 'export', 'compare', 'quality-gate', 'activate'];
12
- const TRAINING_COMMAND_SCHEMA_VERSION = 1;
2
+ import {
3
+ TOOLING_COMMAND_SET,
4
+ TOOLING_SURFACE_SET,
5
+ TOOLING_SUITE_SET,
6
+ VERIFY_SUITES,
7
+ TRAINING_COMMAND_SCHEMA_VERSION,
8
+ } from './command-api-constants.js';
9
+ import {
10
+ asOptionalString,
11
+ assertCommand,
12
+ } from './command-api-helpers.js';
13
+ import {
14
+ normalizeConvert,
15
+ normalizeTrainingOperatorCommand,
16
+ normalizeSuiteCommand,
17
+ } from './command-api-family-normalizers.js';
13
18
 
14
19
  export const TOOLING_COMMANDS = Object.freeze([...TOOLING_COMMAND_SET]);
15
20
  export const TOOLING_SURFACES = Object.freeze([...TOOLING_SURFACE_SET]);
@@ -17,597 +22,6 @@ export const TOOLING_SUITES = Object.freeze([...TOOLING_SUITE_SET]);
17
22
  export const TOOLING_VERIFY_SUITES = Object.freeze([...VERIFY_SUITES]);
18
23
  export const TOOLING_TRAINING_COMMAND_SCHEMA_VERSION = TRAINING_COMMAND_SCHEMA_VERSION;
19
24
 
20
- function asOptionalString(value, label) {
21
- if (value === undefined || value === null || value === '') return null;
22
- if (typeof value !== 'string') {
23
- throw new Error(`tooling command: ${label} must be a string when provided.`);
24
- }
25
- const trimmed = value.trim();
26
- return trimmed || null;
27
- }
28
-
29
- function asOptionalBoolean(value, label) {
30
- if (value === undefined || value === null) return null;
31
- if (typeof value !== 'boolean') {
32
- throw new Error(`tooling command: ${label} must be a boolean when provided.`);
33
- }
34
- return value;
35
- }
36
-
37
- function asOptionalObject(value, label) {
38
- if (value === undefined || value === null) return null;
39
- if (!isPlainObject(value)) {
40
- throw new Error(`tooling command: ${label} must be an object when provided.`);
41
- }
42
- return value;
43
- }
44
-
45
- function asOptionalStringArray(value, label) {
46
- if (value === undefined || value === null) return null;
47
- if (!Array.isArray(value)) {
48
- throw new Error(`tooling command: ${label} must be an array of strings when provided.`);
49
- }
50
- const normalized = value.map((entry, index) => {
51
- if (typeof entry !== 'string') {
52
- throw new Error(`tooling command: ${label}[${index}] must be a string.`);
53
- }
54
- const trimmed = entry.trim();
55
- if (!trimmed) {
56
- throw new Error(`tooling command: ${label}[${index}] must not be empty.`);
57
- }
58
- return trimmed;
59
- });
60
- return normalized.length > 0 ? normalized : null;
61
- }
62
-
63
- function asOptionalPositiveInteger(value, label) {
64
- if (value === undefined || value === null || value === '') return null;
65
- const parsed = Number(value);
66
- if (!Number.isInteger(parsed) || parsed < 1) {
67
- throw new Error(`tooling command: ${label} must be a positive integer when provided.`);
68
- }
69
- return parsed;
70
- }
71
-
72
- function asOptionalTrainingStage(value, label) {
73
- const stage = asOptionalString(value, label);
74
- if (!stage) return null;
75
- if (!TRAINING_STAGE_SET.includes(stage)) {
76
- throw new Error(`tooling command: ${label} must be one of ${TRAINING_STAGE_SET.join(', ')}.`);
77
- }
78
- return stage;
79
- }
80
-
81
- function asOptionalForceResumeReason(value, label) {
82
- const reason = asOptionalString(value, label);
83
- if (!reason) return null;
84
- return reason;
85
- }
86
-
87
- function asOptionalAction(value, label, allowed) {
88
- const action = asOptionalString(value, label);
89
- if (!action) return null;
90
- if (!allowed.includes(action)) {
91
- throw new Error(`tooling command: ${label} must be one of ${allowed.join(', ')}.`);
92
- }
93
- return action;
94
- }
95
-
96
- function assertCommand(value) {
97
- const command = asOptionalString(value, 'command');
98
- if (!command) {
99
- throw new Error('tooling command: command is required.');
100
- }
101
- if (!TOOLING_COMMAND_SET.includes(command)) {
102
- throw new Error(`tooling command: unsupported command "${command}".`);
103
- }
104
- return command;
105
- }
106
-
107
- function assertSuite(value, command) {
108
- const suite = asOptionalString(value, 'suite');
109
- if (!suite) {
110
- throw new Error(`tooling command: suite is required for "${command}".`);
111
- }
112
- if (!TOOLING_SUITE_SET.includes(suite)) {
113
- throw new Error(`tooling command: unsupported suite "${suite}".`);
114
- }
115
- return suite;
116
- }
117
-
118
- function resolveCommandRuntimeContract(command) {
119
- const runtimeContract = selectRuleValue('tooling', 'commandRuntime', 'runtimeContract', { command });
120
- if (!isPlainObject(runtimeContract)) {
121
- throw new Error(`tooling command: missing runtime contract metadata for "${command}".`);
122
- }
123
-
124
- const suite = runtimeContract.suite == null
125
- ? null
126
- : asOptionalString(runtimeContract.suite, `runtime contract suite for "${command}"`);
127
- if (suite && !TOOLING_SUITE_SET.includes(suite)) {
128
- throw new Error(`tooling command: runtime contract suite "${suite}" is not supported.`);
129
- }
130
-
131
- const intent = runtimeContract.intent == null
132
- ? null
133
- : asOptionalString(runtimeContract.intent, `runtime contract intent for "${command}"`);
134
- if (intent && !TOOLING_INTENT_SET.includes(intent)) {
135
- throw new Error(`tooling command: runtime contract intent "${intent}" is not supported.`);
136
- }
137
-
138
- return {
139
- suite,
140
- intent,
141
- };
142
- }
143
-
144
- function asOptionalCacheMode(value, label) {
145
- const cacheMode = asOptionalString(value, label);
146
- if (!cacheMode) return null;
147
- if (cacheMode !== 'cold' && cacheMode !== 'warm') {
148
- throw new Error(`${label} must be "cold" or "warm"`);
149
- }
150
- return cacheMode;
151
- }
152
-
153
- function asOptionalLoadMode(value, label) {
154
- const loadMode = asOptionalString(value, label);
155
- if (!loadMode) return null;
156
- if (loadMode !== 'opfs' && loadMode !== 'http' && loadMode !== 'memory') {
157
- throw new Error(`${label} must be "opfs", "http", or "memory"`);
158
- }
159
- return loadMode;
160
- }
161
-
162
- function assertModelId(value, command, suite) {
163
- const modelId = asOptionalString(value, 'modelId');
164
- if (!modelId) {
165
- throw new Error(
166
- `tooling command: modelId is required for command "${command}" (suite "${suite}").`
167
- );
168
- }
169
- return modelId;
170
- }
171
-
172
- function normalizeConvertExecution(value) {
173
- const execution = asOptionalObject(value, 'convertPayload.execution');
174
- if (!execution) return null;
175
-
176
- const workerCountPolicy = asOptionalString(
177
- execution.workerCountPolicy,
178
- 'convertPayload.execution.workerCountPolicy'
179
- );
180
- if (workerCountPolicy && workerCountPolicy !== 'cap' && workerCountPolicy !== 'error') {
181
- throw new Error(
182
- 'tooling command: convertPayload.execution.workerCountPolicy must be "cap" or "error" when provided.'
183
- );
184
- }
185
-
186
- return {
187
- ...execution,
188
- workers: asOptionalPositiveInteger(
189
- execution.workers,
190
- 'convertPayload.execution.workers'
191
- ),
192
- workerCountPolicy,
193
- maxInFlightJobs: asOptionalPositiveInteger(
194
- execution.maxInFlightJobs,
195
- 'convertPayload.execution.maxInFlightJobs'
196
- ),
197
- rowChunkRows: asOptionalPositiveInteger(
198
- execution.rowChunkRows,
199
- 'convertPayload.execution.rowChunkRows'
200
- ),
201
- rowChunkMinTensorBytes: asOptionalPositiveInteger(
202
- execution.rowChunkMinTensorBytes,
203
- 'convertPayload.execution.rowChunkMinTensorBytes'
204
- ),
205
- useGpuCast: asOptionalBoolean(
206
- execution.useGpuCast,
207
- 'convertPayload.execution.useGpuCast'
208
- ),
209
- gpuCastMinTensorBytes: asOptionalPositiveInteger(
210
- execution.gpuCastMinTensorBytes,
211
- 'convertPayload.execution.gpuCastMinTensorBytes'
212
- ),
213
- };
214
- }
215
-
216
- function normalizeConvertPayload(value) {
217
- const payload = asOptionalObject(value, 'convertPayload');
218
- if (!payload) {
219
- throw new Error(
220
- 'tooling command: convert requires convertPayload.converterConfig.'
221
- );
222
- }
223
- const converterConfig = asOptionalObject(
224
- payload.converterConfig,
225
- 'convertPayload.converterConfig'
226
- );
227
- if (!converterConfig) {
228
- throw new Error(
229
- 'tooling command: convert requires convertPayload.converterConfig.'
230
- );
231
- }
232
- return {
233
- ...payload,
234
- converterConfig,
235
- execution: normalizeConvertExecution(payload.execution),
236
- };
237
- }
238
-
239
- function normalizeConvert(raw) {
240
- const inputDir = asOptionalString(raw.inputDir, 'inputDir');
241
- const outputDir = asOptionalString(raw.outputDir, 'outputDir');
242
- const modelId = asOptionalString(raw.modelId, 'modelId');
243
- const payload = normalizeConvertPayload(raw.convertPayload);
244
-
245
- if (!inputDir) {
246
- throw new Error(
247
- 'tooling command: convert requires inputDir.'
248
- );
249
- }
250
- if (modelId) {
251
- throw new Error(
252
- 'tooling command: convert does not accept modelId. Set convertPayload.converterConfig.output.modelBaseId.'
253
- );
254
- }
255
-
256
- return {
257
- command: 'convert',
258
- suite: null,
259
- intent: null,
260
- action: null,
261
- modelId: null,
262
- trainingTests: null,
263
- trainingStage: null,
264
- trainingConfig: null,
265
- stage1Artifact: null,
266
- stage1ArtifactHash: null,
267
- ulArtifactDir: null,
268
- stageAArtifact: null,
269
- stageAArtifactHash: null,
270
- distillArtifactDir: null,
271
- teacherModelId: null,
272
- studentModelId: null,
273
- distillDatasetId: null,
274
- distillDatasetPath: null,
275
- distillLanguagePair: null,
276
- distillSourceLangs: null,
277
- distillTargetLangs: null,
278
- distillPairAllowlist: null,
279
- strictPairContract: null,
280
- distillShardIndex: null,
281
- distillShardCount: null,
282
- resumeFrom: null,
283
- forceResume: null,
284
- forceResumeReason: null,
285
- forceResumeSource: null,
286
- checkpointOperator: null,
287
- trainingSchemaVersion: null,
288
- trainingBenchSteps: null,
289
- checkpointEvery: null,
290
- workloadType: asOptionalString(raw.workloadType, 'workloadType'),
291
- modelUrl: asOptionalString(raw.modelUrl, 'modelUrl'),
292
- cacheMode: asOptionalCacheMode(raw.cacheMode, 'cacheMode'),
293
- loadMode: asOptionalLoadMode(raw.loadMode, 'loadMode'),
294
- runtimePreset: asOptionalString(raw.runtimePreset, 'runtimePreset'),
295
- runtimeConfigUrl: asOptionalString(raw.runtimeConfigUrl, 'runtimeConfigUrl'),
296
- runtimeConfig: asOptionalObject(raw.runtimeConfig, 'runtimeConfig'),
297
- inputDir,
298
- outputDir,
299
- convertPayload: payload,
300
- workloadPath: null,
301
- runRoot: null,
302
- checkpointPath: null,
303
- checkpointId: null,
304
- checkpointStep: null,
305
- stageId: null,
306
- stageArtifact: null,
307
- subsetManifest: null,
308
- evalDatasetId: null,
309
- pollIntervalMs: null,
310
- stopWhenIdle: null,
311
- captureOutput: false,
312
- keepPipeline: false,
313
- report: asOptionalObject(raw.report, 'report'),
314
- timestamp: raw.timestamp ?? null,
315
- searchParams: raw.searchParams ?? null,
316
- };
317
- }
318
-
319
- function normalizeTrainingOperatorCommand(raw, command) {
320
- const allowedActions = command === 'distill' ? DISTILL_ACTION_SET : LORA_ACTION_SET;
321
- const action = asOptionalAction(raw.action, 'action', allowedActions);
322
- if (!action) {
323
- throw new Error(`tooling command: ${command} requires action.`);
324
- }
325
- const workloadPath = asOptionalString(raw.workloadPath, 'workloadPath');
326
- const runRoot = asOptionalString(raw.runRoot, 'runRoot');
327
- const checkpointPath = asOptionalString(raw.checkpointPath, 'checkpointPath');
328
- const checkpointId = asOptionalString(raw.checkpointId, 'checkpointId');
329
- const checkpointStep = asOptionalPositiveInteger(raw.checkpointStep, 'checkpointStep');
330
- const stageId = asOptionalString(raw.stageId, 'stageId');
331
- const stageArtifact = asOptionalString(raw.stageArtifact, 'stageArtifact');
332
- const subsetManifest = asOptionalString(raw.subsetManifest, 'subsetManifest');
333
- const evalDatasetId = asOptionalString(raw.evalDatasetId, 'evalDatasetId');
334
- const pollIntervalMs = asOptionalPositiveInteger(raw.pollIntervalMs, 'pollIntervalMs');
335
- const stopWhenIdle = asOptionalBoolean(raw.stopWhenIdle, 'stopWhenIdle');
336
- if (!workloadPath && !runRoot) {
337
- throw new Error(`tooling command: ${command} requires workloadPath or runRoot.`);
338
- }
339
- if ((action === 'eval' || action === 'export') && !checkpointPath && !runRoot) {
340
- throw new Error(`tooling command: ${command} ${action} requires checkpointPath or runRoot.`);
341
- }
342
- if (action === 'watch' && !runRoot) {
343
- throw new Error(`tooling command: ${command} watch requires runRoot.`);
344
- }
345
- if ((action === 'compare' || action === 'quality-gate') && !runRoot) {
346
- throw new Error(`tooling command: ${command} ${action} requires runRoot.`);
347
- }
348
- if (command === 'distill' && action === 'stage-b' && !stageArtifact && !runRoot) {
349
- throw new Error('tooling command: distill stage-b requires stageArtifact or runRoot.');
350
- }
351
-
352
- return {
353
- command,
354
- suite: null,
355
- intent: null,
356
- action,
357
- modelId: null,
358
- trainingTests: null,
359
- trainingStage: null,
360
- trainingConfig: null,
361
- stage1Artifact: null,
362
- stage1ArtifactHash: null,
363
- ulArtifactDir: null,
364
- stageAArtifact: null,
365
- stageAArtifactHash: null,
366
- distillArtifactDir: null,
367
- teacherModelId: null,
368
- studentModelId: null,
369
- distillDatasetId: null,
370
- distillDatasetPath: null,
371
- distillLanguagePair: null,
372
- distillSourceLangs: null,
373
- distillTargetLangs: null,
374
- distillPairAllowlist: null,
375
- strictPairContract: null,
376
- distillShardIndex: null,
377
- distillShardCount: null,
378
- resumeFrom: null,
379
- forceResume: null,
380
- forceResumeReason: null,
381
- forceResumeSource: null,
382
- checkpointOperator: null,
383
- trainingSchemaVersion: null,
384
- trainingBenchSteps: null,
385
- checkpointEvery: null,
386
- workloadType: 'training',
387
- modelUrl: null,
388
- cacheMode: asOptionalCacheMode(raw.cacheMode, 'cacheMode'),
389
- loadMode: asOptionalLoadMode(raw.loadMode, 'loadMode'),
390
- runtimePreset: asOptionalString(raw.runtimePreset, 'runtimePreset'),
391
- runtimeConfigUrl: asOptionalString(raw.runtimeConfigUrl, 'runtimeConfigUrl'),
392
- runtimeConfig: asOptionalObject(raw.runtimeConfig, 'runtimeConfig'),
393
- inputDir: null,
394
- outputDir: null,
395
- convertPayload: null,
396
- workloadPath,
397
- runRoot,
398
- checkpointPath,
399
- checkpointId,
400
- checkpointStep,
401
- stageId,
402
- stageArtifact,
403
- subsetManifest,
404
- evalDatasetId,
405
- pollIntervalMs,
406
- stopWhenIdle,
407
- captureOutput: false,
408
- keepPipeline: false,
409
- report: asOptionalObject(raw.report, 'report'),
410
- timestamp: raw.timestamp ?? null,
411
- searchParams: raw.searchParams ?? null,
412
- };
413
- }
414
-
415
- function normalizeSuiteCommand(raw, command) {
416
- const runtimeContract = resolveCommandRuntimeContract(command);
417
- let suite = runtimeContract.suite;
418
- if (!suite) {
419
- suite = assertSuite(raw.suite, command);
420
- if (!VERIFY_SUITES.includes(suite)) {
421
- throw new Error(
422
- `tooling command: "${command}" suite must be one of ${VERIFY_SUITES.join(', ')}.`
423
- );
424
- }
425
- }
426
-
427
- const modelUrl = asOptionalString(raw.modelUrl, 'modelUrl');
428
- const trainingTests = asOptionalStringArray(raw.trainingTests, 'trainingTests');
429
- const trainingStage = asOptionalTrainingStage(raw.trainingStage, 'trainingStage');
430
- const trainingConfig = asOptionalObject(raw.trainingConfig, 'trainingConfig');
431
- const stage1Artifact = asOptionalString(raw.stage1Artifact, 'stage1Artifact');
432
- const stage1ArtifactHash = asOptionalString(raw.stage1ArtifactHash, 'stage1ArtifactHash');
433
- const ulArtifactDir = asOptionalString(raw.ulArtifactDir, 'ulArtifactDir');
434
- const stageAArtifact = asOptionalString(raw.stageAArtifact, 'stageAArtifact');
435
- const stageAArtifactHash = asOptionalString(raw.stageAArtifactHash, 'stageAArtifactHash');
436
- const distillArtifactDir = asOptionalString(raw.distillArtifactDir, 'distillArtifactDir');
437
- const teacherModelId = asOptionalString(raw.teacherModelId, 'teacherModelId');
438
- const studentModelId = asOptionalString(raw.studentModelId, 'studentModelId');
439
- const distillDatasetId = asOptionalString(raw.distillDatasetId, 'distillDatasetId');
440
- const distillDatasetPath = asOptionalString(raw.distillDatasetPath, 'distillDatasetPath');
441
- const distillLanguagePair = asOptionalString(raw.distillLanguagePair, 'distillLanguagePair');
442
- const distillSourceLangs = asOptionalStringArray(raw.distillSourceLangs, 'distillSourceLangs');
443
- const distillTargetLangs = asOptionalStringArray(raw.distillTargetLangs, 'distillTargetLangs');
444
- const distillPairAllowlist = asOptionalStringArray(raw.distillPairAllowlist, 'distillPairAllowlist');
445
- const strictPairContract = asOptionalBoolean(raw.strictPairContract, 'strictPairContract');
446
- const distillShardIndex = asOptionalPositiveInteger(raw.distillShardIndex, 'distillShardIndex');
447
- const distillShardCount = asOptionalPositiveInteger(raw.distillShardCount, 'distillShardCount');
448
- const resumeFrom = asOptionalString(raw.resumeFrom, 'resumeFrom');
449
- const forceResume = asOptionalBoolean(raw.forceResume, 'forceResume');
450
- const forceResumeReason = asOptionalForceResumeReason(raw.forceResumeReason, 'forceResumeReason');
451
- const forceResumeSource = asOptionalString(raw.forceResumeSource, 'forceResumeSource');
452
- const checkpointOperator = asOptionalString(raw.checkpointOperator, 'checkpointOperator');
453
- const trainingSchemaVersionInput = asOptionalPositiveInteger(
454
- raw.trainingSchemaVersion,
455
- 'trainingSchemaVersion'
456
- );
457
- const trainingBenchSteps = asOptionalPositiveInteger(raw.trainingBenchSteps, 'trainingBenchSteps');
458
- const checkpointEvery = asOptionalPositiveInteger(raw.checkpointEvery, 'checkpointEvery');
459
- const workloadType = asOptionalString(raw.workloadType, 'workloadType');
460
- const isTrainingBenchWorkload = command === 'bench' && suite === 'bench' && workloadType === 'training';
461
- const allowsTrainingFields = suite === 'training' || isTrainingBenchWorkload;
462
- if (!allowsTrainingFields && (
463
- trainingTests
464
- || trainingStage
465
- || trainingConfig
466
- || stage1Artifact
467
- || stage1ArtifactHash
468
- || ulArtifactDir
469
- || stageAArtifact
470
- || stageAArtifactHash
471
- || distillArtifactDir
472
- || teacherModelId
473
- || studentModelId
474
- || distillDatasetId
475
- || distillDatasetPath
476
- || distillLanguagePair
477
- || distillSourceLangs
478
- || distillTargetLangs
479
- || distillPairAllowlist
480
- || strictPairContract !== null
481
- || distillShardIndex
482
- || distillShardCount
483
- || resumeFrom
484
- || forceResume !== null
485
- || forceResumeReason
486
- || forceResumeSource
487
- || checkpointOperator
488
- || trainingSchemaVersionInput
489
- || trainingBenchSteps
490
- || checkpointEvery
491
- )) {
492
- throw new Error(
493
- 'tooling command: training-only fields require suite="training" or bench workloadType="training".'
494
- );
495
- }
496
- if (forceResumeReason && forceResume !== true) {
497
- throw new Error(
498
- 'tooling command: forceResumeReason requires forceResume=true.'
499
- );
500
- }
501
- if (forceResumeSource && forceResume !== true) {
502
- throw new Error(
503
- 'tooling command: forceResumeSource requires forceResume=true.'
504
- );
505
- }
506
- if (checkpointOperator && forceResume !== true) {
507
- throw new Error(
508
- 'tooling command: checkpointOperator requires forceResume=true.'
509
- );
510
- }
511
- const trainingSchemaVersion = allowsTrainingFields
512
- ? (trainingSchemaVersionInput ?? TRAINING_COMMAND_SCHEMA_VERSION)
513
- : null;
514
- if (trainingSchemaVersionInput != null && trainingSchemaVersionInput !== TRAINING_COMMAND_SCHEMA_VERSION) {
515
- throw new Error(
516
- `tooling command: trainingSchemaVersion must be ${TRAINING_COMMAND_SCHEMA_VERSION}.`
517
- );
518
- }
519
- if (
520
- distillShardIndex != null
521
- && distillShardCount != null
522
- && distillShardIndex > distillShardCount
523
- ) {
524
- throw new Error('tooling command: distillShardIndex must be <= distillShardCount.');
525
- }
526
-
527
- const requiresModel = suite !== 'kernels' && !isTrainingBenchWorkload;
528
- const hasTrainingSource = allowsTrainingFields && (
529
- !!modelUrl
530
- || !!trainingStage
531
- || !!stage1Artifact
532
- || !!stageAArtifact
533
- || !!trainingConfig?.ul?.stage
534
- || !!trainingConfig?.distill?.stage
535
- || !!trainingConfig?.dataset
536
- || !!trainingConfig?.distill?.datasetId
537
- || !!trainingConfig?.distill?.datasetPath
538
- || !!teacherModelId
539
- || !!studentModelId
540
- || !!distillDatasetPath
541
- );
542
- const modelId = (requiresModel && !hasTrainingSource)
543
- ? assertModelId(raw.modelId, command, suite)
544
- : asOptionalString(raw.modelId, 'modelId');
545
-
546
- return {
547
- command,
548
- suite,
549
- intent: runtimeContract.intent,
550
- action: null,
551
- modelId,
552
- trainingTests,
553
- trainingStage,
554
- trainingConfig,
555
- stage1Artifact,
556
- stage1ArtifactHash,
557
- ulArtifactDir,
558
- stageAArtifact,
559
- stageAArtifactHash,
560
- distillArtifactDir,
561
- teacherModelId,
562
- studentModelId,
563
- distillDatasetId,
564
- distillDatasetPath,
565
- distillLanguagePair,
566
- distillSourceLangs,
567
- distillTargetLangs,
568
- distillPairAllowlist,
569
- strictPairContract: allowsTrainingFields ? strictPairContract : null,
570
- distillShardIndex,
571
- distillShardCount,
572
- resumeFrom,
573
- forceResume: allowsTrainingFields
574
- ? (forceResume == null ? null : forceResume === true)
575
- : null,
576
- forceResumeReason: allowsTrainingFields ? forceResumeReason : null,
577
- forceResumeSource: allowsTrainingFields ? forceResumeSource : null,
578
- checkpointOperator: allowsTrainingFields ? checkpointOperator : null,
579
- trainingSchemaVersion,
580
- trainingBenchSteps,
581
- checkpointEvery: allowsTrainingFields ? checkpointEvery : null,
582
- workloadType,
583
- modelUrl,
584
- cacheMode: asOptionalCacheMode(raw.cacheMode, 'cacheMode'),
585
- loadMode: asOptionalLoadMode(raw.loadMode, 'loadMode'),
586
- runtimePreset: asOptionalString(raw.runtimePreset, 'runtimePreset'),
587
- runtimeConfigUrl: asOptionalString(raw.runtimeConfigUrl, 'runtimeConfigUrl'),
588
- runtimeConfig: asOptionalObject(raw.runtimeConfig, 'runtimeConfig'),
589
- inputDir: null,
590
- outputDir: null,
591
- convertPayload: null,
592
- workloadPath: null,
593
- runRoot: null,
594
- checkpointPath: null,
595
- checkpointId: null,
596
- checkpointStep: null,
597
- stageId: null,
598
- stageArtifact: null,
599
- subsetManifest: null,
600
- evalDatasetId: null,
601
- pollIntervalMs: null,
602
- stopWhenIdle: null,
603
- captureOutput: asOptionalBoolean(raw.captureOutput, 'captureOutput') ?? false,
604
- keepPipeline: asOptionalBoolean(raw.keepPipeline, 'keepPipeline') ?? false,
605
- report: asOptionalObject(raw.report, 'report'),
606
- timestamp: raw.timestamp ?? null,
607
- searchParams: raw.searchParams ?? null,
608
- };
609
- }
610
-
611
25
  export function normalizeToolingCommandRequest(input) {
612
26
  if (!isPlainObject(input)) {
613
27
  throw new Error('tooling command: request must be an object.');
@@ -146,7 +146,10 @@ export function createToolingSuccessEnvelope({
146
146
 
147
147
  export function createToolingErrorEnvelope(error, context = {}) {
148
148
  const normalized = normalizeToToolingCommandError(error, context);
149
- const surface = asNonEmptyString(context?.surface);
149
+ const surface = asNonEmptyString(context?.surface)
150
+ || asNonEmptyString(normalized?.details?.surface)
151
+ || asNonEmptyString(error?.surface)
152
+ || null;
150
153
  const request = isPlainObject(context?.request) ? context.request : null;
151
154
  return {
152
155
  ok: false,