@simulatte/doppler 0.1.4 → 0.1.6

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 (199) hide show
  1. package/README.md +26 -10
  2. package/package.json +30 -6
  3. package/src/client/doppler-api.browser.d.ts +1 -0
  4. package/src/client/doppler-api.browser.js +288 -0
  5. package/src/client/doppler-api.js +1 -1
  6. package/src/client/doppler-provider/types.js +1 -1
  7. package/src/config/execution-contract-check.d.ts +33 -0
  8. package/src/config/execution-contract-check.js +72 -0
  9. package/src/config/execution-v0-contract-check.d.ts +94 -0
  10. package/src/config/execution-v0-contract-check.js +251 -0
  11. package/src/config/execution-v0-graph-contract-check.d.ts +20 -0
  12. package/src/config/execution-v0-graph-contract-check.js +64 -0
  13. package/src/config/kernel-path-contract-check.d.ts +76 -0
  14. package/src/config/kernel-path-contract-check.js +479 -0
  15. package/src/config/kernel-path-loader.d.ts +16 -0
  16. package/src/config/kernel-path-loader.js +54 -0
  17. package/src/config/kernels/kernel-ref-digests.js +39 -27
  18. package/src/config/kernels/registry.json +598 -2
  19. package/src/config/loader.js +81 -48
  20. package/src/config/merge-contract-check.d.ts +16 -0
  21. package/src/config/merge-contract-check.js +321 -0
  22. package/src/config/merge-helpers.d.ts +58 -0
  23. package/src/config/merge-helpers.js +54 -0
  24. package/src/config/merge.js +21 -6
  25. package/src/config/presets/models/janus-text.json +2 -0
  26. package/src/config/presets/models/qwen3.json +9 -2
  27. package/src/config/presets/models/transformer.json +5 -0
  28. package/src/config/quantization-contract-check.d.ts +12 -0
  29. package/src/config/quantization-contract-check.js +91 -0
  30. package/src/config/required-inference-fields-contract-check.d.ts +24 -0
  31. package/src/config/required-inference-fields-contract-check.js +237 -0
  32. package/src/config/schema/browser-suite-metrics.schema.d.ts +17 -0
  33. package/src/config/schema/browser-suite-metrics.schema.js +46 -0
  34. package/src/config/schema/conversion-report.schema.d.ts +40 -0
  35. package/src/config/schema/conversion-report.schema.js +108 -0
  36. package/src/config/schema/doppler.schema.js +12 -18
  37. package/src/config/schema/index.d.ts +22 -0
  38. package/src/config/schema/index.js +18 -0
  39. package/src/config/schema/inference-defaults.schema.js +3 -0
  40. package/src/config/schema/inference.schema.d.ts +9 -0
  41. package/src/config/schema/kernel-path.schema.d.ts +6 -0
  42. package/src/config/schema/manifest.schema.d.ts +6 -0
  43. package/src/config/schema/manifest.schema.js +3 -0
  44. package/src/converter/core.d.ts +10 -0
  45. package/src/converter/core.js +27 -2
  46. package/src/converter/parsers/diffusion.js +63 -3
  47. package/src/converter/rope-config.js +42 -0
  48. package/src/gpu/device.js +58 -0
  49. package/src/gpu/kernels/attention.js +98 -0
  50. package/src/gpu/kernels/bias_add.wgsl +8 -6
  51. package/src/gpu/kernels/bias_add_f16.wgsl +8 -5
  52. package/src/gpu/kernels/conv2d.js +1 -1
  53. package/src/gpu/kernels/conv2d.wgsl +7 -8
  54. package/src/gpu/kernels/conv2d_f16.wgsl +7 -8
  55. package/src/gpu/kernels/depthwise_conv2d.d.ts +29 -0
  56. package/src/gpu/kernels/depthwise_conv2d.js +99 -0
  57. package/src/gpu/kernels/depthwise_conv2d.wgsl +55 -0
  58. package/src/gpu/kernels/depthwise_conv2d_f16.wgsl +59 -0
  59. package/src/gpu/kernels/grouped_pointwise_conv2d.d.ts +27 -0
  60. package/src/gpu/kernels/grouped_pointwise_conv2d.js +93 -0
  61. package/src/gpu/kernels/grouped_pointwise_conv2d.wgsl +44 -0
  62. package/src/gpu/kernels/grouped_pointwise_conv2d_f16.wgsl +48 -0
  63. package/src/gpu/kernels/index.d.ts +30 -0
  64. package/src/gpu/kernels/index.js +25 -0
  65. package/src/gpu/kernels/matmul.js +25 -0
  66. package/src/gpu/kernels/pixel_shuffle.js +1 -1
  67. package/src/gpu/kernels/pixel_shuffle.wgsl +4 -5
  68. package/src/gpu/kernels/pixel_shuffle_f16.wgsl +4 -5
  69. package/src/gpu/kernels/relu.d.ts +18 -0
  70. package/src/gpu/kernels/relu.js +58 -0
  71. package/src/gpu/kernels/relu.wgsl +22 -0
  72. package/src/gpu/kernels/relu_f16.wgsl +24 -0
  73. package/src/gpu/kernels/repeat_channels.d.ts +21 -0
  74. package/src/gpu/kernels/repeat_channels.js +60 -0
  75. package/src/gpu/kernels/repeat_channels.wgsl +28 -0
  76. package/src/gpu/kernels/repeat_channels_f16.wgsl +30 -0
  77. package/src/gpu/kernels/residual.js +44 -8
  78. package/src/gpu/kernels/residual.wgsl +6 -3
  79. package/src/gpu/kernels/residual_f16.wgsl +2 -1
  80. package/src/gpu/kernels/residual_f16_vec4.wgsl +2 -1
  81. package/src/gpu/kernels/residual_vec4.wgsl +2 -1
  82. package/src/gpu/kernels/rmsnorm.js +58 -6
  83. package/src/gpu/kernels/rmsnorm.wgsl +14 -6
  84. package/src/gpu/kernels/rmsnorm_f16.wgsl +10 -2
  85. package/src/gpu/kernels/rope.d.ts +2 -0
  86. package/src/gpu/kernels/rope.js +11 -1
  87. package/src/gpu/kernels/rope.wgsl +56 -40
  88. package/src/gpu/kernels/sana_linear_attention.d.ts +27 -0
  89. package/src/gpu/kernels/sana_linear_attention.js +121 -0
  90. package/src/gpu/kernels/sana_linear_attention_apply.wgsl +43 -0
  91. package/src/gpu/kernels/sana_linear_attention_apply_f16.wgsl +46 -0
  92. package/src/gpu/kernels/sana_linear_attention_summary.wgsl +51 -0
  93. package/src/gpu/kernels/sana_linear_attention_summary_f16.wgsl +53 -0
  94. package/src/gpu/kernels/silu.d.ts +1 -0
  95. package/src/gpu/kernels/silu.js +32 -14
  96. package/src/gpu/kernels/silu.wgsl +19 -9
  97. package/src/gpu/kernels/silu_f16.wgsl +19 -9
  98. package/src/gpu/kernels/transpose.js +15 -2
  99. package/src/gpu/kernels/transpose.wgsl +5 -6
  100. package/src/gpu/kernels/upsample2d.js +2 -1
  101. package/src/gpu/kernels/upsample2d.wgsl +6 -9
  102. package/src/gpu/kernels/upsample2d_f16.wgsl +6 -9
  103. package/src/gpu/kernels/utils.js +16 -1
  104. package/src/index-browser.d.ts +1 -1
  105. package/src/index-browser.js +2 -2
  106. package/src/index.js +1 -1
  107. package/src/inference/browser-harness.js +109 -23
  108. package/src/inference/pipelines/diffusion/init.js +14 -0
  109. package/src/inference/pipelines/diffusion/pipeline.js +215 -77
  110. package/src/inference/pipelines/diffusion/sana-transformer.d.ts +53 -0
  111. package/src/inference/pipelines/diffusion/sana-transformer.js +738 -0
  112. package/src/inference/pipelines/diffusion/scheduler.d.ts +17 -1
  113. package/src/inference/pipelines/diffusion/scheduler.js +91 -3
  114. package/src/inference/pipelines/diffusion/text-encoder-gpu.d.ts +11 -4
  115. package/src/inference/pipelines/diffusion/text-encoder-gpu.js +282 -0
  116. package/src/inference/pipelines/diffusion/text-encoder.js +18 -1
  117. package/src/inference/pipelines/diffusion/types.d.ts +4 -0
  118. package/src/inference/pipelines/diffusion/vae.js +782 -78
  119. package/src/inference/pipelines/text/attention/record.js +11 -2
  120. package/src/inference/pipelines/text/attention/run.js +11 -2
  121. package/src/inference/pipelines/text/chat-format.js +25 -1
  122. package/src/inference/pipelines/text/config.d.ts +9 -0
  123. package/src/inference/pipelines/text/config.js +69 -2
  124. package/src/inference/pipelines/text/execution-plan.js +23 -31
  125. package/src/inference/pipelines/text/execution-v0.js +43 -95
  126. package/src/inference/pipelines/text/ffn/standard.js +3 -0
  127. package/src/inference/pipelines/text/init.d.ts +4 -0
  128. package/src/inference/pipelines/text/init.js +56 -9
  129. package/src/inference/pipelines/text/layer.js +11 -0
  130. package/src/inference/pipelines/text.js +4 -0
  131. package/src/inference/tokenizers/bundled.js +156 -33
  132. package/src/rules/execution-rules-contract-check.d.ts +17 -0
  133. package/src/rules/execution-rules-contract-check.js +245 -0
  134. package/src/rules/kernels/depthwise-conv2d.rules.json +6 -0
  135. package/src/rules/kernels/grouped-pointwise-conv2d.rules.json +6 -0
  136. package/src/rules/kernels/relu.rules.json +6 -0
  137. package/src/rules/kernels/repeat-channels.rules.json +6 -0
  138. package/src/rules/kernels/sana-linear-attention.rules.json +6 -0
  139. package/src/rules/layer-pattern-contract-check.d.ts +17 -0
  140. package/src/rules/layer-pattern-contract-check.js +231 -0
  141. package/src/rules/rule-registry.d.ts +28 -0
  142. package/src/rules/rule-registry.js +38 -0
  143. package/src/rules/tooling/command-runtime.rules.json +18 -0
  144. package/src/tooling/command-api.d.ts +27 -1
  145. package/src/tooling/command-api.js +142 -3
  146. package/src/tooling/conversion-config-materializer.d.ts +24 -0
  147. package/src/tooling/conversion-config-materializer.js +99 -0
  148. package/src/tooling/lean-execution-contract-runner.d.ts +43 -0
  149. package/src/tooling/lean-execution-contract-runner.js +158 -0
  150. package/src/tooling/node-browser-command-runner.d.ts +4 -0
  151. package/src/tooling/node-browser-command-runner.js +58 -3
  152. package/src/tooling/node-command-runner.js +15 -0
  153. package/src/tooling/node-convert.d.ts +10 -0
  154. package/src/tooling/node-converter.js +59 -0
  155. package/src/tooling/node-webgpu.js +11 -89
  156. package/src/training/checkpoint-watch.d.ts +7 -0
  157. package/src/training/checkpoint-watch.js +106 -0
  158. package/src/training/checkpoint.d.ts +6 -1
  159. package/src/training/checkpoint.js +12 -2
  160. package/src/training/distillation/artifacts.d.ts +71 -0
  161. package/src/training/distillation/artifacts.js +132 -0
  162. package/src/training/distillation/checkpoint-watch.d.ts +10 -0
  163. package/src/training/distillation/checkpoint-watch.js +57 -0
  164. package/src/training/distillation/dataset.d.ts +59 -0
  165. package/src/training/distillation/dataset.js +337 -0
  166. package/src/training/distillation/eval.d.ts +34 -0
  167. package/src/training/distillation/eval.js +310 -0
  168. package/src/training/distillation/index.d.ts +29 -0
  169. package/src/training/distillation/index.js +29 -0
  170. package/src/training/distillation/runtime.d.ts +20 -0
  171. package/src/training/distillation/runtime.js +121 -0
  172. package/src/training/distillation/scoreboard.d.ts +6 -0
  173. package/src/training/distillation/scoreboard.js +8 -0
  174. package/src/training/distillation/stage-a.d.ts +45 -0
  175. package/src/training/distillation/stage-a.js +338 -0
  176. package/src/training/distillation/stage-b.d.ts +24 -0
  177. package/src/training/distillation/stage-b.js +20 -0
  178. package/src/training/index.d.ts +10 -0
  179. package/src/training/index.js +10 -0
  180. package/src/training/lora-pipeline.d.ts +40 -0
  181. package/src/training/lora-pipeline.js +796 -0
  182. package/src/training/operator-artifacts.d.ts +62 -0
  183. package/src/training/operator-artifacts.js +140 -0
  184. package/src/training/operator-command.d.ts +5 -0
  185. package/src/training/operator-command.js +453 -0
  186. package/src/training/operator-eval.d.ts +48 -0
  187. package/src/training/operator-eval.js +230 -0
  188. package/src/training/operator-scoreboard.d.ts +5 -0
  189. package/src/training/operator-scoreboard.js +44 -0
  190. package/src/training/runner.d.ts +52 -0
  191. package/src/training/runner.js +29 -4
  192. package/src/training/suite.d.ts +112 -0
  193. package/src/training/suite.js +9 -9
  194. package/src/training/workloads.d.ts +164 -0
  195. package/src/training/workloads.js +539 -0
  196. package/src/version.d.ts +2 -0
  197. package/src/version.js +2 -0
  198. package/tools/convert-safetensors-node.js +47 -0
  199. package/tools/doppler-cli.js +252 -41
@@ -1,5 +1,5 @@
1
- export const DOPPLER_VERSION = '0.1.0';
2
- export { doppler } from './client/doppler-api.js';
1
+ export { DOPPLER_VERSION } from './version.js';
2
+ export { doppler } from './client/doppler-api.browser.js';
3
3
 
4
4
  // Core loaders
5
5
  export {
package/src/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export const DOPPLER_VERSION = '0.1.0';
1
+ export { DOPPLER_VERSION } from './version.js';
2
2
  export { doppler } from './client/doppler-api.js';
3
3
 
4
4
  // Core loaders
@@ -15,10 +15,16 @@ import {
15
15
  getActiveKernelPathSource,
16
16
  getActiveKernelPathPolicy,
17
17
  } from '../config/kernel-path-loader.js';
18
- import { selectRuleValue } from '../rules/rule-registry.js';
18
+ import {
19
+ getInferenceLayerPatternContractArtifact,
20
+ selectRuleValue,
21
+ } from '../rules/rule-registry.js';
19
22
  import { mergeRuntimeValues } from '../config/runtime-merge.js';
20
23
  import { isPlainObject } from '../utils/plain-object.js';
24
+ import { validateBrowserSuiteMetrics } from '../config/schema/browser-suite-metrics.schema.js';
21
25
  import { validateTrainingMetricsReport } from '../config/schema/training-metrics.schema.js';
26
+ import { buildExecutionContractArtifact } from '../config/execution-contract-check.js';
27
+ import { buildManifestRequiredInferenceFieldsArtifact } from '../config/required-inference-fields-contract-check.js';
22
28
 
23
29
  const TRAINING_SUITE_MODULE_PATH = '../training/suite.js';
24
30
  const NODE_SOURCE_RUNTIME_MODULE_PATH = '../tooling/node-source-runtime.js';
@@ -41,6 +47,29 @@ async function runTrainingBenchSuite(options = {}) {
41
47
  return module.runTrainingBenchSuite(options);
42
48
  }
43
49
 
50
+ function buildSuiteContractMetrics(suite, baseMetrics, manifest) {
51
+ const executionContractArtifact = buildExecutionContractArtifact(manifest);
52
+ const executionV0GraphContractArtifact = executionContractArtifact?.executionV0?.graph ?? null;
53
+ const layerPatternContractArtifact = getInferenceLayerPatternContractArtifact();
54
+ const requiredInferenceFieldsArtifact = manifest?.modelType === 'transformer'
55
+ && isPlainObject(manifest?.inference?.attention)
56
+ ? buildManifestRequiredInferenceFieldsArtifact(
57
+ manifest?.inference ?? null,
58
+ `${manifest?.modelId ?? 'unknown'}.inference`
59
+ )
60
+ : null;
61
+ return validateBrowserSuiteMetrics({
62
+ ...baseMetrics,
63
+ schemaVersion: 1,
64
+ source: 'doppler',
65
+ suite,
66
+ ...(executionContractArtifact ? { executionContractArtifact } : {}),
67
+ executionV0GraphContractArtifact,
68
+ layerPatternContractArtifact,
69
+ requiredInferenceFieldsArtifact,
70
+ });
71
+ }
72
+
44
73
  function parseReportTimestamp(rawTimestamp, label = 'timestamp') {
45
74
  if (rawTimestamp == null) {
46
75
  return null;
@@ -900,6 +929,9 @@ async function resolveHarnessOverride(options = {}) {
900
929
 
901
930
  async function initializeSuiteModel(options = {}) {
902
931
  if (options.harnessOverride) {
932
+ if (options.runtime?.runtimeConfig) {
933
+ setRuntimeConfig(options.runtime.runtimeConfig);
934
+ }
903
935
  return resolveHarnessOverride(options);
904
936
  }
905
937
  const loadStart = performance.now();
@@ -959,6 +991,14 @@ async function runKernelSuite(options = {}) {
959
991
 
960
992
  const DEFAULT_HARNESS_PROMPT = 'Summarize this input in one sentence.';
961
993
  const DEFAULT_RUNTIME_PLACEHOLDER_PROMPT = 'Hello from Doppler.';
994
+ const DEFAULT_QWEN_PROMPT = Object.freeze({
995
+ messages: Object.freeze([
996
+ Object.freeze({
997
+ role: 'user',
998
+ content: 'Answer in one short sentence: What color is the sky on a clear day?',
999
+ }),
1000
+ ]),
1001
+ });
962
1002
  const DEFAULT_TRANSLATEGEMMA_PROMPT = Object.freeze({
963
1003
  messages: Object.freeze([
964
1004
  Object.freeze({
@@ -1244,6 +1284,9 @@ function resolvePromptTemplateType(source) {
1244
1284
  }
1245
1285
 
1246
1286
  function buildDefaultGenerationPrompt(templateType) {
1287
+ if (templateType === 'qwen') {
1288
+ return clonePromptInput(DEFAULT_QWEN_PROMPT);
1289
+ }
1247
1290
  if (templateType === 'translategemma') {
1248
1291
  return clonePromptInput(DEFAULT_TRANSLATEGEMMA_PROMPT);
1249
1292
  }
@@ -1251,7 +1294,7 @@ function buildDefaultGenerationPrompt(templateType) {
1251
1294
  }
1252
1295
 
1253
1296
  function shouldPreferModelDefaultPrompt(runtimePrompt, templateType) {
1254
- if (templateType !== 'translategemma') {
1297
+ if (templateType !== 'translategemma' && templateType !== 'qwen') {
1255
1298
  return false;
1256
1299
  }
1257
1300
  if (typeof runtimePrompt !== 'string') {
@@ -1260,6 +1303,31 @@ function shouldPreferModelDefaultPrompt(runtimePrompt, templateType) {
1260
1303
  return runtimePrompt.trim() === DEFAULT_RUNTIME_PLACEHOLDER_PROMPT;
1261
1304
  }
1262
1305
 
1306
+ function assertPromptContract(runtimePrompt, templateType, source = 'runtime.inference.prompt') {
1307
+ if (templateType !== 'translategemma') {
1308
+ return;
1309
+ }
1310
+ if (runtimePrompt === undefined || runtimePrompt === null) {
1311
+ return;
1312
+ }
1313
+ if (typeof runtimePrompt === 'string') {
1314
+ const trimmed = runtimePrompt.trim();
1315
+ if (!trimmed || trimmed === DEFAULT_RUNTIME_PLACEHOLDER_PROMPT) {
1316
+ return;
1317
+ }
1318
+ throw new Error(
1319
+ `TranslateGemma harness prompt contract violation: ${source} must be ` +
1320
+ '{ messages: [...] } with source_lang_code/target_lang_code blocks, not a plain string.'
1321
+ );
1322
+ }
1323
+ if (!isStructuredPromptInput(runtimePrompt)) {
1324
+ throw new Error(
1325
+ `TranslateGemma harness prompt contract violation: ${source} must be ` +
1326
+ '{ messages: [...] } with source_lang_code/target_lang_code blocks.'
1327
+ );
1328
+ }
1329
+ }
1330
+
1263
1331
  function describePromptInput(promptInput) {
1264
1332
  if (typeof promptInput === 'string') {
1265
1333
  return promptInput.trim() || DEFAULT_HARNESS_PROMPT;
@@ -1276,6 +1344,11 @@ function describePromptInput(promptInput) {
1276
1344
  if (sourceLang && targetLang) {
1277
1345
  return `${sourceLang} -> ${targetLang}: ${text || '[non-text request]'}`;
1278
1346
  }
1347
+ const stringContent = asText(firstMessage?.content);
1348
+ if (stringContent) {
1349
+ const role = asText(firstMessage?.role) || 'user';
1350
+ return `${role}: ${stringContent}`;
1351
+ }
1279
1352
  try {
1280
1353
  return JSON.stringify(promptInput);
1281
1354
  } catch {
@@ -1286,6 +1359,7 @@ function describePromptInput(promptInput) {
1286
1359
  function resolveGenerationPromptInput(runtimeConfig, runOverrides = null, source = null) {
1287
1360
  const templateType = resolvePromptTemplateType(source);
1288
1361
  const overridePrompt = runOverrides?.prompt;
1362
+ assertPromptContract(overridePrompt, templateType, 'runOverrides.prompt');
1289
1363
  if (typeof overridePrompt === 'string' && overridePrompt.trim()) {
1290
1364
  return overridePrompt.trim();
1291
1365
  }
@@ -1294,6 +1368,7 @@ function resolveGenerationPromptInput(runtimeConfig, runOverrides = null, source
1294
1368
  }
1295
1369
 
1296
1370
  const runtimePrompt = runtimeConfig?.inference?.prompt;
1371
+ assertPromptContract(runtimePrompt, templateType, 'runtimeConfig.inference.prompt');
1297
1372
  if (shouldPreferModelDefaultPrompt(runtimePrompt, templateType)) {
1298
1373
  return buildDefaultGenerationPrompt(templateType);
1299
1374
  }
@@ -1824,6 +1899,11 @@ async function runInferenceSuite(options = {}) {
1824
1899
  source: 'doppler',
1825
1900
  prefillSemantics: 'internal_prefill_phase',
1826
1901
  });
1902
+ const metricsWithContracts = buildSuiteContractMetrics(
1903
+ options.suiteName || 'inference',
1904
+ metrics,
1905
+ harness.manifest
1906
+ );
1827
1907
  return {
1828
1908
  ...summary,
1829
1909
  modelId: options.modelId || harness.manifest?.modelId || 'unknown',
@@ -1841,7 +1921,7 @@ async function runInferenceSuite(options = {}) {
1841
1921
  timing,
1842
1922
  timingDiagnostics,
1843
1923
  output,
1844
- metrics,
1924
+ metrics: metricsWithContracts,
1845
1925
  memoryStats,
1846
1926
  deviceInfo: resolveDeviceInfo(),
1847
1927
  pipeline: options.keepPipeline ? harness.pipeline : null,
@@ -2218,6 +2298,7 @@ async function runBenchSuite(options = {}) {
2218
2298
  source: 'doppler',
2219
2299
  prefillSemantics: 'internal_prefill_phase',
2220
2300
  });
2301
+ const metricsWithContracts = buildSuiteContractMetrics('bench', metrics, harness.manifest);
2221
2302
  return {
2222
2303
  ...summary,
2223
2304
  modelId: options.modelId || harness.manifest?.modelId || 'unknown',
@@ -2235,7 +2316,7 @@ async function runBenchSuite(options = {}) {
2235
2316
  timing,
2236
2317
  timingDiagnostics,
2237
2318
  output,
2238
- metrics,
2319
+ metrics: metricsWithContracts,
2239
2320
  memoryStats,
2240
2321
  deviceInfo: resolveDeviceInfo(),
2241
2322
  pipeline: options.keepPipeline ? harness.pipeline : null,
@@ -2396,25 +2477,9 @@ async function runDiffusionSuite(options = {}) {
2396
2477
  source: 'doppler',
2397
2478
  prefillSemantics: 'internal_prefill_phase',
2398
2479
  });
2399
-
2400
- return {
2401
- ...summary,
2402
- modelId: options.modelId || harness.manifest?.modelId || 'unknown',
2403
- cacheMode,
2404
- loadMode,
2405
- env: {
2406
- library: 'doppler',
2407
- runtime: 'browser',
2408
- device: 'webgpu',
2409
- browserUserAgent: typeof navigator !== 'undefined' ? (navigator.userAgent || null) : null,
2410
- browserPlatform: typeof navigator !== 'undefined' ? (navigator.platform || null) : null,
2411
- browserLanguage: typeof navigator !== 'undefined' ? (navigator.language || null) : null,
2412
- browserVendor: typeof navigator !== 'undefined' ? (navigator.vendor || null) : null,
2413
- },
2414
- timing,
2415
- timingDiagnostics,
2416
- output,
2417
- metrics: {
2480
+ const metricsWithContracts = buildSuiteContractMetrics(
2481
+ 'diffusion',
2482
+ {
2418
2483
  warmupRuns,
2419
2484
  timedRuns,
2420
2485
  width,
@@ -2439,6 +2504,27 @@ async function runDiffusionSuite(options = {}) {
2439
2504
  gpu: gpuStats,
2440
2505
  performanceArtifact: diffusionPerformanceArtifact,
2441
2506
  },
2507
+ harness.manifest
2508
+ );
2509
+
2510
+ return {
2511
+ ...summary,
2512
+ modelId: options.modelId || harness.manifest?.modelId || 'unknown',
2513
+ cacheMode,
2514
+ loadMode,
2515
+ env: {
2516
+ library: 'doppler',
2517
+ runtime: 'browser',
2518
+ device: 'webgpu',
2519
+ browserUserAgent: typeof navigator !== 'undefined' ? (navigator.userAgent || null) : null,
2520
+ browserPlatform: typeof navigator !== 'undefined' ? (navigator.platform || null) : null,
2521
+ browserLanguage: typeof navigator !== 'undefined' ? (navigator.language || null) : null,
2522
+ browserVendor: typeof navigator !== 'undefined' ? (navigator.vendor || null) : null,
2523
+ },
2524
+ timing,
2525
+ timingDiagnostics,
2526
+ output,
2527
+ metrics: metricsWithContracts,
2442
2528
  memoryStats,
2443
2529
  deviceInfo: resolveDeviceInfo(),
2444
2530
  pipeline: options.keepPipeline ? harness.pipeline : null,
@@ -1,5 +1,7 @@
1
1
  import { DEFAULT_DIFFUSION_CONFIG } from '../../../config/schema/index.js';
2
2
 
3
+ const SUPPORTED_DIFFUSION_RUNTIME_LAYOUTS = new Set(['sd3', 'flux', 'sana']);
4
+
3
5
  function mergeSection(base, override) {
4
6
  if (!override) return { ...base };
5
7
  return { ...base, ...override };
@@ -38,6 +40,9 @@ function resolveSchedulerType(modelScheduler, runtimeScheduler) {
38
40
  if (modelClass === 'FlowMatchEulerDiscreteScheduler') {
39
41
  return 'flowmatch_euler';
40
42
  }
43
+ if (modelClass === 'SCMScheduler') {
44
+ return 'scm';
45
+ }
41
46
  if (modelClass === 'EulerDiscreteScheduler') {
42
47
  return 'euler';
43
48
  }
@@ -58,6 +63,8 @@ function mergeSchedulerConfig(modelConfig, runtimeScheduler) {
58
63
  type,
59
64
  numTrainTimesteps: modelScheduler.num_train_timesteps ?? runtimeScheduler.numTrainTimesteps,
60
65
  shift: modelScheduler.shift ?? runtimeScheduler.shift,
66
+ predictionType: modelScheduler.prediction_type ?? runtimeScheduler.predictionType,
67
+ sigmaData: modelScheduler.sigma_data ?? runtimeScheduler.sigmaData,
61
68
  };
62
69
  }
63
70
 
@@ -95,6 +102,13 @@ export function initializeDiffusion(manifest, runtimeConfig) {
95
102
  }
96
103
  throw new Error('Diffusion manifest missing config.diffusion model contract.');
97
104
  }
105
+ const layout = modelConfig.layout;
106
+ if (layout && !SUPPORTED_DIFFUSION_RUNTIME_LAYOUTS.has(layout)) {
107
+ throw new Error(
108
+ `Diffusion layout "${layout}" is recognized in the manifest, but the GPU runtime is not implemented yet. ` +
109
+ 'Supported runtime layouts: sd3, flux, sana.'
110
+ );
111
+ }
98
112
 
99
113
  const runtimeBase = mergeDiffusionConfig(DEFAULT_DIFFUSION_CONFIG, runtimeConfig?.inference?.diffusion);
100
114
  const runtime = {