@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
@@ -0,0 +1,269 @@
1
+ import { getRuntimeConfig } from '../config/runtime.js';
2
+ import { computeSampleStats } from '../debug/stats.js';
3
+ import { initializeSuiteModel, resolveDeviceInfo } from './browser-harness-model-helpers.js';
4
+ import { buildSuiteContractMetrics } from './browser-harness-contract-helpers.js';
5
+ import { resolvePrompt } from './browser-harness-text-helpers.js';
6
+ import {
7
+ buildSuiteSummary,
8
+ normalizeCacheMode,
9
+ normalizeLoadMode,
10
+ safeStatsValue,
11
+ buildDiffusionPerformanceArtifact,
12
+ buildCanonicalTiming,
13
+ buildTimingDiagnostics,
14
+ } from './browser-harness-suite-helpers.js';
15
+
16
+ export async function runDiffusionSuite(options = {}) {
17
+ const startTime = performance.now();
18
+ const runtimeConfig = getRuntimeConfig();
19
+ const captureOutput = options.captureOutput === true;
20
+ const cacheMode = normalizeCacheMode(options.cacheMode);
21
+ const loadMode = normalizeLoadMode(options.loadMode, !options.modelUrl);
22
+ const benchConfig = runtimeConfig.shared?.benchmark?.run || {};
23
+ const warmupRuns = Math.max(0, Math.floor(benchConfig.warmupRuns ?? 0));
24
+ const timedRuns = Math.max(1, Math.floor(benchConfig.timedRuns ?? 1));
25
+
26
+ const diffusionConfig = runtimeConfig.inference?.diffusion;
27
+ if (!diffusionConfig) {
28
+ throw new Error('runtime.inference.diffusion must be set for diffusion harness runs.');
29
+ }
30
+ const scheduler = diffusionConfig.scheduler;
31
+ const latent = diffusionConfig.latent;
32
+ const prompt = resolvePrompt(runtimeConfig);
33
+ const negativePrompt = diffusionConfig.negativePrompt ?? '';
34
+
35
+ const width = Math.floor(latent?.width);
36
+ const height = Math.floor(latent?.height);
37
+ const steps = Math.floor(scheduler?.numSteps);
38
+ const guidanceScale = scheduler?.guidanceScale;
39
+
40
+ if (!Number.isFinite(width) || width <= 0) {
41
+ throw new Error('runtime.inference.diffusion.latent.width must be set for diffusion harness runs.');
42
+ }
43
+ if (!Number.isFinite(height) || height <= 0) {
44
+ throw new Error('runtime.inference.diffusion.latent.height must be set for diffusion harness runs.');
45
+ }
46
+ if (!Number.isFinite(steps) || steps <= 0) {
47
+ throw new Error('runtime.inference.diffusion.scheduler.numSteps must be set for diffusion harness runs.');
48
+ }
49
+ if (!Number.isFinite(guidanceScale) || guidanceScale <= 0) {
50
+ throw new Error('runtime.inference.diffusion.scheduler.guidanceScale must be set for diffusion harness runs.');
51
+ }
52
+
53
+ const harness = await initializeSuiteModel(options);
54
+ const totalMs = [];
55
+ const prefillMs = [];
56
+ const denoiseMs = [];
57
+ const vaeMs = [];
58
+ const prefillTokens = [];
59
+ const decodeTokens = [];
60
+ const gpuTotalMs = [];
61
+ const gpuPrefillMs = [];
62
+ const gpuDenoiseMs = [];
63
+ const gpuVaeMs = [];
64
+ let output = null;
65
+
66
+ for (let i = 0; i < warmupRuns + timedRuns; i++) {
67
+ harness.pipeline.reset?.();
68
+ const result = await harness.pipeline.generate({
69
+ prompt,
70
+ negativePrompt,
71
+ steps,
72
+ guidanceScale,
73
+ width,
74
+ height,
75
+ });
76
+ if (captureOutput && i === warmupRuns + timedRuns - 1) {
77
+ output = result;
78
+ }
79
+
80
+ if (i < warmupRuns) continue;
81
+
82
+ const stats = harness.pipeline.getStats?.() ?? {};
83
+ if (Number.isFinite(stats.totalTimeMs)) totalMs.push(stats.totalTimeMs);
84
+ if (Number.isFinite(stats.prefillTimeMs)) prefillMs.push(stats.prefillTimeMs);
85
+ if (Number.isFinite(stats.decodeTimeMs)) denoiseMs.push(stats.decodeTimeMs);
86
+ if (Number.isFinite(stats.vaeTimeMs)) vaeMs.push(stats.vaeTimeMs);
87
+ if (Number.isFinite(stats.prefillTokens)) prefillTokens.push(stats.prefillTokens);
88
+ if (Number.isFinite(stats.decodeTokens)) decodeTokens.push(stats.decodeTokens);
89
+
90
+ const gpu = stats.gpu ?? null;
91
+ if (gpu?.available) {
92
+ if (Number.isFinite(gpu.totalMs)) gpuTotalMs.push(gpu.totalMs);
93
+ if (Number.isFinite(gpu.prefillMs)) gpuPrefillMs.push(gpu.prefillMs);
94
+ if (Number.isFinite(gpu.denoiseMs)) gpuDenoiseMs.push(gpu.denoiseMs);
95
+ if (Number.isFinite(gpu.vaeMs)) gpuVaeMs.push(gpu.vaeMs);
96
+ }
97
+ }
98
+
99
+ const memoryStats = typeof harness.pipeline?.getMemoryStats === 'function'
100
+ ? harness.pipeline.getMemoryStats()
101
+ : null;
102
+
103
+ if (typeof harness.pipeline.unload === 'function' && !options.keepPipeline) {
104
+ await harness.pipeline.unload();
105
+ }
106
+
107
+ const results = [
108
+ {
109
+ name: 'diffusion',
110
+ passed: totalMs.length > 0,
111
+ duration: totalMs.reduce((sum, value) => sum + value, 0),
112
+ error: totalMs.length > 0 ? undefined : 'No diffusion runs completed',
113
+ },
114
+ ];
115
+
116
+ const summary = buildSuiteSummary('diffusion', results, startTime);
117
+ const cpuStats = {
118
+ totalMs: computeSampleStats(totalMs),
119
+ prefillMs: computeSampleStats(prefillMs),
120
+ denoiseMs: computeSampleStats(denoiseMs),
121
+ vaeMs: computeSampleStats(vaeMs),
122
+ };
123
+ const gpuStats = gpuTotalMs.length > 0
124
+ ? {
125
+ available: true,
126
+ totalMs: computeSampleStats(gpuTotalMs),
127
+ prefillMs: computeSampleStats(gpuPrefillMs),
128
+ denoiseMs: computeSampleStats(gpuDenoiseMs),
129
+ vaeMs: computeSampleStats(gpuVaeMs),
130
+ }
131
+ : { available: false };
132
+
133
+ const avgPrefillTokens = prefillTokens.length
134
+ ? Math.round(prefillTokens.reduce((a, b) => a + b, 0) / prefillTokens.length)
135
+ : 0;
136
+ const avgDecodeTokens = decodeTokens.length
137
+ ? Math.round(decodeTokens.reduce((a, b) => a + b, 0) / decodeTokens.length)
138
+ : 0;
139
+ const prefillMsMedian = safeStatsValue(cpuStats.prefillMs?.median);
140
+ const denoiseMsMedian = safeStatsValue(cpuStats.denoiseMs?.median);
141
+ const totalMsMedian = safeStatsValue(cpuStats.totalMs?.median);
142
+ const diffusionPerformanceArtifact = buildDiffusionPerformanceArtifact({
143
+ warmupRuns,
144
+ timedRuns,
145
+ width,
146
+ height,
147
+ steps,
148
+ guidanceScale,
149
+ avgPrefillTokens,
150
+ avgDecodeTokens,
151
+ cpuStats,
152
+ gpuStats,
153
+ });
154
+ const timing = buildCanonicalTiming({
155
+ modelLoadMs: 0,
156
+ firstTokenMs: null,
157
+ firstResponseMs: null,
158
+ prefillMs: prefillMsMedian,
159
+ decodeMs: denoiseMsMedian,
160
+ totalRunMs: totalMsMedian,
161
+ prefillTokensPerSec: diffusionPerformanceArtifact.throughput.prefillTokensPerSec,
162
+ decodeTokensPerSec: diffusionPerformanceArtifact.throughput.decodeTokensPerSec,
163
+ cacheMode,
164
+ loadMode,
165
+ });
166
+ const timingDiagnostics = buildTimingDiagnostics(timing, {
167
+ source: 'doppler',
168
+ prefillSemantics: 'internal_prefill_phase',
169
+ });
170
+ const metricsWithContracts = buildSuiteContractMetrics(
171
+ 'diffusion',
172
+ {
173
+ warmupRuns,
174
+ timedRuns,
175
+ width,
176
+ height,
177
+ steps,
178
+ guidanceScale,
179
+ prompt,
180
+ avgPrefillTokens,
181
+ avgDecodeTokens,
182
+ latency: {
183
+ totalMs: cpuStats.totalMs,
184
+ prefillMs: cpuStats.prefillMs,
185
+ denoiseMs: cpuStats.denoiseMs,
186
+ vaeMs: cpuStats.vaeMs,
187
+ },
188
+ throughput: {
189
+ prefillTokensPerSec: diffusionPerformanceArtifact.throughput.prefillTokensPerSec,
190
+ decodeTokensPerSec: diffusionPerformanceArtifact.throughput.decodeTokensPerSec,
191
+ decodeStepsPerSec: diffusionPerformanceArtifact.throughput.decodeStepsPerSec,
192
+ },
193
+ cpu: cpuStats,
194
+ gpu: gpuStats,
195
+ performanceArtifact: diffusionPerformanceArtifact,
196
+ },
197
+ harness.manifest
198
+ );
199
+
200
+ return {
201
+ ...summary,
202
+ modelId: options.modelId || harness.manifest?.modelId || 'unknown',
203
+ cacheMode,
204
+ loadMode,
205
+ env: {
206
+ library: 'doppler',
207
+ runtime: 'browser',
208
+ device: 'webgpu',
209
+ browserUserAgent: typeof navigator !== 'undefined' ? (navigator.userAgent || null) : null,
210
+ browserPlatform: typeof navigator !== 'undefined' ? (navigator.platform || null) : null,
211
+ browserLanguage: typeof navigator !== 'undefined' ? (navigator.language || null) : null,
212
+ browserVendor: typeof navigator !== 'undefined' ? (navigator.vendor || null) : null,
213
+ },
214
+ timing,
215
+ timingDiagnostics,
216
+ output,
217
+ metrics: metricsWithContracts,
218
+ memoryStats,
219
+ deviceInfo: resolveDeviceInfo(),
220
+ pipeline: options.keepPipeline ? harness.pipeline : null,
221
+ };
222
+ }
223
+
224
+ export async function runEnergySuite(options = {}) {
225
+ const startTime = performance.now();
226
+ const harness = await initializeSuiteModel(options);
227
+ if (harness.manifest?.modelType !== 'energy') {
228
+ throw new Error('Energy suite requires an energy model manifest.');
229
+ }
230
+
231
+ const result = await harness.pipeline.generate();
232
+ const stats = harness.pipeline.getStats?.() ?? {};
233
+
234
+ const memoryStats = typeof harness.pipeline?.getMemoryStats === 'function'
235
+ ? harness.pipeline.getMemoryStats()
236
+ : null;
237
+
238
+ if (typeof harness.pipeline.unload === 'function' && !options.keepPipeline) {
239
+ await harness.pipeline.unload();
240
+ }
241
+
242
+ const results = [
243
+ {
244
+ name: 'energy',
245
+ passed: Number.isFinite(result.energy ?? NaN),
246
+ duration: result.totalTimeMs ?? Math.max(0, performance.now() - startTime),
247
+ error: Number.isFinite(result.energy ?? NaN) ? undefined : 'Energy did not converge',
248
+ },
249
+ ];
250
+
251
+ const summary = buildSuiteSummary('energy', results, startTime);
252
+ return {
253
+ ...summary,
254
+ modelId: options.modelId || harness.manifest?.modelId || 'unknown',
255
+ metrics: {
256
+ steps: result.steps,
257
+ energy: result.energy ?? null,
258
+ dtype: result.dtype,
259
+ shape: result.shape,
260
+ totalTimeMs: result.totalTimeMs ?? null,
261
+ energyHistory: result.energyHistory ?? [],
262
+ stateStats: result.stateStats ?? null,
263
+ readbackCount: stats.readbackCount ?? null,
264
+ },
265
+ memoryStats,
266
+ deviceInfo: resolveDeviceInfo(),
267
+ pipeline: options.keepPipeline ? harness.pipeline : null,
268
+ };
269
+ }
@@ -0,0 +1,16 @@
1
+ export declare function resolveDeviceInfo(): Record<string, unknown> | null;
2
+ export declare function resolveKernelPathForModel(options?: Record<string, unknown>): Promise<{
3
+ modelId: string | null;
4
+ kernelPath: unknown;
5
+ source: string | null;
6
+ } | null>;
7
+ export declare function initializeInferenceFromStorage(
8
+ modelId: string,
9
+ options?: Record<string, unknown>
10
+ ): Promise<Record<string, unknown>>;
11
+ export declare function initializeInferenceFromSourcePath(
12
+ sourcePath: string,
13
+ options?: Record<string, unknown>
14
+ ): Promise<Record<string, unknown>>;
15
+ export declare function resolveHarnessOverride(options?: Record<string, unknown>): Promise<Record<string, unknown>>;
16
+ export declare function initializeSuiteModel(options?: Record<string, unknown>): Promise<Record<string, unknown>>;
@@ -0,0 +1,217 @@
1
+ import { initializeInference } from './test-harness.js';
2
+ import { setRuntimeConfig } from '../config/runtime.js';
3
+ import { initDevice, getKernelCapabilities, getDevice } from '../gpu/device.js';
4
+ import { createPipeline } from './pipelines/text.js';
5
+ import { parseModelConfigFromManifest } from './pipelines/text/config.js';
6
+ import { resolveKernelPathState, activateKernelPathState } from './pipelines/text/model-load.js';
7
+ import { openModelStore, loadManifestFromStore } from '../storage/shard-manager.js';
8
+ import { parseManifest } from '../formats/rdrr/index.js';
9
+ import { resolveRuntime } from './browser-harness-runtime-helpers.js';
10
+ import { normalizeLoadMode } from './browser-harness-suite-helpers.js';
11
+ import { buildSourceArtifactFingerprint, createStoredSourceArtifactContext } from '../storage/source-artifact-store.js';
12
+
13
+ const NODE_SOURCE_RUNTIME_MODULE_PATH = '../tooling/node-source-runtime.js';
14
+
15
+ function isNodeRuntime() {
16
+ return typeof process !== 'undefined' && !!process.versions?.node;
17
+ }
18
+
19
+ function resolveSourceVerifyHashes(options = {}) {
20
+ const explicit = options?.runtime?.runtimeConfig?.loading?.shardCache?.verifyHashes;
21
+ if (explicit == null) {
22
+ return true;
23
+ }
24
+ return explicit === true;
25
+ }
26
+
27
+ export function resolveDeviceInfo() {
28
+ try {
29
+ return getKernelCapabilities();
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+
35
+ export async function resolveKernelPathForModel(options = {}) {
36
+ const runtimeConfig = options.runtime?.runtimeConfig ?? null;
37
+ let manifest = null;
38
+ let manifestModelId = options.modelId || null;
39
+
40
+ if (options.modelId) {
41
+ await openModelStore(options.modelId);
42
+ const manifestText = await loadManifestFromStore();
43
+ if (manifestText) {
44
+ manifest = parseManifest(manifestText);
45
+ manifestModelId = manifest.modelId ?? options.modelId;
46
+ }
47
+ }
48
+
49
+ if (!manifest) return null;
50
+
51
+ const modelConfig = parseModelConfigFromManifest(manifest, runtimeConfig);
52
+ const kernelPathState = resolveKernelPathState({
53
+ manifest,
54
+ runtimeConfig,
55
+ modelConfig,
56
+ });
57
+ activateKernelPathState(kernelPathState);
58
+ return {
59
+ modelId: manifestModelId,
60
+ kernelPath: kernelPathState.resolvedKernelPath,
61
+ source: kernelPathState.kernelPathSource,
62
+ };
63
+ }
64
+
65
+ export async function initializeInferenceFromStorage(modelId, options = {}) {
66
+ const { onProgress } = options;
67
+ if (!modelId) {
68
+ throw new Error('modelId is required');
69
+ }
70
+
71
+ if (options.runtime?.runtimeConfig) {
72
+ setRuntimeConfig(options.runtime.runtimeConfig);
73
+ }
74
+
75
+ onProgress?.('storage', 0.05, 'Opening model store...');
76
+ await openModelStore(modelId);
77
+
78
+ onProgress?.('manifest', 0.1, 'Loading manifest...');
79
+ const manifestText = await loadManifestFromStore();
80
+ if (!manifestText) {
81
+ throw new Error('Manifest not found in storage');
82
+ }
83
+ const manifest = parseManifest(manifestText);
84
+
85
+ onProgress?.('gpu', 0.2, 'Initializing WebGPU...');
86
+ await initDevice();
87
+ const device = getDevice();
88
+ const capabilities = getKernelCapabilities();
89
+
90
+ onProgress?.('pipeline', 0.3, 'Creating pipeline...');
91
+ const storage = buildSourceArtifactFingerprint(manifest)
92
+ ? createStoredSourceArtifactContext(manifest, { verifyHashes: true })
93
+ : null;
94
+ const pipeline = await createPipeline(manifest, {
95
+ gpu: { device },
96
+ runtime: options.runtime,
97
+ ...(storage ? { storage } : {}),
98
+ onProgress,
99
+ });
100
+
101
+ return { pipeline, manifest, capabilities };
102
+ }
103
+
104
+ export async function initializeInferenceFromSourcePath(sourcePath, options = {}) {
105
+ const { onProgress } = options;
106
+ if (!sourcePath || typeof sourcePath !== 'string') {
107
+ throw new Error('modelUrl is required for loadMode=memory.');
108
+ }
109
+ if (!isNodeRuntime()) {
110
+ throw new Error('loadMode=memory source runtime is currently supported on Node only.');
111
+ }
112
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(sourcePath)) {
113
+ throw new Error(
114
+ 'loadMode=memory expects a local filesystem path (Safetensors directory or .gguf file), not an URL.'
115
+ );
116
+ }
117
+
118
+ if (options.runtime?.runtimeConfig) {
119
+ setRuntimeConfig(options.runtime.runtimeConfig);
120
+ }
121
+
122
+ onProgress?.('source', 0.05, 'Preparing source runtime bundle...');
123
+ const { resolveNodeSourceRuntimeBundle } = await import(NODE_SOURCE_RUNTIME_MODULE_PATH);
124
+ const sourceBundle = await resolveNodeSourceRuntimeBundle({
125
+ inputPath: sourcePath,
126
+ modelId: options.modelId || null,
127
+ verifyHashes: resolveSourceVerifyHashes(options),
128
+ });
129
+ if (!sourceBundle) {
130
+ throw new Error(
131
+ `No source-runtime model detected at "${sourcePath}". ` +
132
+ 'Expected a Safetensors directory or a .gguf file path.'
133
+ );
134
+ }
135
+
136
+ onProgress?.('gpu', 0.2, 'Initializing WebGPU...');
137
+ await initDevice();
138
+ const device = getDevice();
139
+ const capabilities = getKernelCapabilities();
140
+
141
+ onProgress?.('pipeline', 0.3, 'Creating pipeline...');
142
+ const pipeline = await createPipeline(sourceBundle.manifest, {
143
+ gpu: { device },
144
+ runtime: options.runtime,
145
+ storage: sourceBundle.storageContext,
146
+ onProgress,
147
+ });
148
+
149
+ return {
150
+ pipeline,
151
+ manifest: sourceBundle.manifest,
152
+ capabilities,
153
+ };
154
+ }
155
+
156
+ export async function resolveHarnessOverride(options = {}) {
157
+ const input = typeof options.harnessOverride === 'function'
158
+ ? await options.harnessOverride(options)
159
+ : options.harnessOverride;
160
+
161
+ if (!input || typeof input !== 'object') {
162
+ throw new Error('harnessOverride must resolve to an object.');
163
+ }
164
+
165
+ if (!input.pipeline || typeof input.pipeline.generate !== 'function') {
166
+ throw new Error('harnessOverride.pipeline.generate(request) is required.');
167
+ }
168
+
169
+ const manifest = input.manifest && typeof input.manifest === 'object'
170
+ ? input.manifest
171
+ : {
172
+ modelId: options.modelId || 'diffusion-harness-override',
173
+ modelType: 'diffusion',
174
+ };
175
+
176
+ const modelLoadMs = Number.isFinite(input.modelLoadMs)
177
+ ? Math.max(0, input.modelLoadMs)
178
+ : 0;
179
+
180
+ return {
181
+ ...input,
182
+ manifest,
183
+ modelLoadMs,
184
+ };
185
+ }
186
+
187
+ export async function initializeSuiteModel(options = {}) {
188
+ if (options.harnessOverride) {
189
+ if (options.runtime?.runtimeConfig) {
190
+ setRuntimeConfig(options.runtime.runtimeConfig);
191
+ }
192
+ return resolveHarnessOverride(options);
193
+ }
194
+ const loadStart = performance.now();
195
+ const runtime = resolveRuntime(options);
196
+ const loadMode = normalizeLoadMode(options.loadMode, !options.modelUrl);
197
+ let harness;
198
+ if (loadMode === 'memory') {
199
+ if (!options.modelUrl) {
200
+ throw new Error('loadMode=memory requires modelUrl to be a local model path.');
201
+ }
202
+ harness = await initializeInferenceFromSourcePath(options.modelUrl, { ...options, runtime });
203
+ } else if (options.modelId && !options.modelUrl) {
204
+ harness = await initializeInferenceFromStorage(options.modelId, { ...options, runtime });
205
+ } else {
206
+ if (!options.modelUrl) {
207
+ throw new Error('modelUrl is required for this suite');
208
+ }
209
+ harness = await initializeInference(options.modelUrl, {
210
+ runtime,
211
+ onProgress: options.onProgress,
212
+ log: options.log,
213
+ });
214
+ }
215
+ const modelLoadMs = Math.max(0, performance.now() - loadStart);
216
+ return { ...harness, modelLoadMs };
217
+ }
@@ -0,0 +1,7 @@
1
+ export declare function collectTrainingArtifactsFromSuiteResult(
2
+ suiteResult: Record<string, unknown>
3
+ ): {
4
+ ulArtifacts: Array<Record<string, unknown>>;
5
+ distillArtifacts: Array<Record<string, unknown>>;
6
+ checkpointResumeTimeline: Array<Record<string, unknown>>;
7
+ };
@@ -0,0 +1,42 @@
1
+ export function collectTrainingArtifactsFromSuiteResult(suiteResult) {
2
+ const ulArtifacts = [];
3
+ const distillArtifacts = [];
4
+ const checkpointResumeTimeline = Array.isArray(suiteResult?.metrics?.checkpointResumeTimeline)
5
+ ? suiteResult.metrics.checkpointResumeTimeline
6
+ .filter((entry) => entry && typeof entry === 'object')
7
+ : [];
8
+ const addArtifact = (artifact, source = null) => {
9
+ if (!artifact || typeof artifact !== 'object' || typeof artifact.manifestPath !== 'string') {
10
+ return;
11
+ }
12
+ const stage = String(artifact.stage || '').trim();
13
+ const kind = String(artifact.kind || '').trim();
14
+ if (kind === 'distill' || stage === 'stage_a' || stage === 'stage_b') {
15
+ distillArtifacts.push(artifact);
16
+ return;
17
+ }
18
+ if (kind === 'ul' || stage === 'stage1_joint' || stage === 'stage2_base' || source === 'ul') {
19
+ ulArtifacts.push(artifact);
20
+ return;
21
+ }
22
+ ulArtifacts.push(artifact);
23
+ };
24
+
25
+ const metricUlArtifacts = Array.isArray(suiteResult?.metrics?.ulArtifacts)
26
+ ? suiteResult.metrics.ulArtifacts
27
+ : [];
28
+ for (const artifact of metricUlArtifacts) {
29
+ addArtifact(artifact, 'ul');
30
+ }
31
+ const metricDistillArtifacts = Array.isArray(suiteResult?.metrics?.distillArtifacts)
32
+ ? suiteResult.metrics.distillArtifacts
33
+ : [];
34
+ for (const artifact of metricDistillArtifacts) {
35
+ addArtifact(artifact, 'distill');
36
+ }
37
+ const resultEntries = Array.isArray(suiteResult?.results) ? suiteResult.results : [];
38
+ for (const entry of resultEntries) {
39
+ addArtifact(entry?.artifact, null);
40
+ }
41
+ return { ulArtifacts, distillArtifacts, checkpointResumeTimeline };
42
+ }
@@ -0,0 +1,61 @@
1
+ export declare function parseReportTimestamp(
2
+ rawTimestamp: string | number | Date | null | undefined,
3
+ label?: string
4
+ ): string | null;
5
+ export declare function resolveReportTimestamp(
6
+ rawTimestamp: string | number | Date | null | undefined,
7
+ label: string,
8
+ fallbackTimestamp?: string | null
9
+ ): string;
10
+ export declare function resolveRuntime(options: Record<string, unknown>): Record<string, unknown>;
11
+ export declare function cloneRuntimeConfig(runtimeConfig: Record<string, unknown> | null | undefined): Record<string, unknown> | null;
12
+ export declare function snapshotRuntimeState(): {
13
+ runtimeConfig: Record<string, unknown> | null;
14
+ activeKernelPath: unknown;
15
+ activeKernelPathSource: string | null;
16
+ activeKernelPathPolicy: unknown;
17
+ };
18
+ export declare function restoreRuntimeState(snapshot: Record<string, unknown> | null | undefined): void;
19
+ export declare function runWithRuntimeIsolationForSuite<T>(run: () => Promise<T>): Promise<T>;
20
+ export declare function sanitizeReportOutput(output: unknown): unknown;
21
+ export declare function loadRuntimeConfigFromRef(
22
+ ref: string,
23
+ context: Record<string, unknown>
24
+ ): Promise<{ config: Record<string, unknown>; runtime: Record<string, unknown> }>;
25
+ export declare function loadRuntimeConfigFromUrl(
26
+ url: string,
27
+ options?: Record<string, unknown>
28
+ ): Promise<{ config: Record<string, unknown>; runtime: Record<string, unknown> }>;
29
+ export declare function applyRuntimeConfigFromUrl(
30
+ url: string,
31
+ options?: Record<string, unknown>
32
+ ): Promise<Record<string, unknown>>;
33
+ export declare function loadRuntimePreset(
34
+ presetId: string,
35
+ options?: Record<string, unknown>
36
+ ): Promise<{ config: Record<string, unknown>; runtime: Record<string, unknown> }>;
37
+ export declare function applyRuntimePreset(
38
+ presetId: string,
39
+ options?: Record<string, unknown>
40
+ ): Promise<Record<string, unknown>>;
41
+ export declare function normalizeRuntimeConfigChain(value: unknown): string[];
42
+ export declare function applyRuntimeForRun(
43
+ run: Record<string, unknown>,
44
+ options?: Record<string, unknown>
45
+ ): Promise<void>;
46
+ export declare function normalizeManifest(manifest: Record<string, unknown>): {
47
+ defaults: Record<string, unknown>;
48
+ runs: Array<Record<string, unknown>>;
49
+ reportModelId: string;
50
+ report: Record<string, unknown> | null;
51
+ };
52
+ export declare function mergeRunDefaults(
53
+ defaults: Record<string, unknown>,
54
+ run: Record<string, unknown>
55
+ ): Record<string, unknown>;
56
+ export declare function summarizeManifestRuns(results: Array<Record<string, unknown>>): {
57
+ totalRuns: number;
58
+ passedRuns: number;
59
+ failedRuns: number;
60
+ durationMs: number;
61
+ };