@simulatte/doppler 0.1.3 → 0.1.5

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 (114) hide show
  1. package/README.md +11 -5
  2. package/package.json +27 -4
  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.d.ts +80 -0
  6. package/src/client/doppler-api.js +298 -0
  7. package/src/client/doppler-provider/types.js +1 -1
  8. package/src/client/doppler-registry.d.ts +23 -0
  9. package/src/client/doppler-registry.js +88 -0
  10. package/src/client/doppler-registry.json +39 -0
  11. package/src/config/execution-contract-check.d.ts +82 -0
  12. package/src/config/execution-contract-check.js +317 -0
  13. package/src/config/execution-v0-contract-check.d.ts +94 -0
  14. package/src/config/execution-v0-contract-check.js +251 -0
  15. package/src/config/execution-v0-graph-contract-check.d.ts +20 -0
  16. package/src/config/execution-v0-graph-contract-check.js +64 -0
  17. package/src/config/kernel-path-contract-check.d.ts +76 -0
  18. package/src/config/kernel-path-contract-check.js +479 -0
  19. package/src/config/kernel-path-loader.d.ts +16 -0
  20. package/src/config/kernel-path-loader.js +54 -0
  21. package/src/config/kernels/kernel-ref-digests.js +12 -0
  22. package/src/config/kernels/registry.json +556 -0
  23. package/src/config/loader.js +90 -67
  24. package/src/config/merge-contract-check.d.ts +16 -0
  25. package/src/config/merge-contract-check.js +321 -0
  26. package/src/config/merge-helpers.d.ts +58 -0
  27. package/src/config/merge-helpers.js +54 -0
  28. package/src/config/merge.js +3 -6
  29. package/src/config/presets/models/janus-text.json +27 -0
  30. package/src/config/quantization-contract-check.d.ts +12 -0
  31. package/src/config/quantization-contract-check.js +91 -0
  32. package/src/config/required-inference-fields-contract-check.d.ts +24 -0
  33. package/src/config/required-inference-fields-contract-check.js +231 -0
  34. package/src/config/schema/browser-suite-metrics.schema.d.ts +17 -0
  35. package/src/config/schema/browser-suite-metrics.schema.js +46 -0
  36. package/src/config/schema/conversion-report.schema.d.ts +40 -0
  37. package/src/config/schema/conversion-report.schema.js +108 -0
  38. package/src/config/schema/doppler.schema.js +12 -18
  39. package/src/config/schema/index.d.ts +22 -0
  40. package/src/config/schema/index.js +18 -0
  41. package/src/converter/core.d.ts +10 -0
  42. package/src/converter/core.js +49 -11
  43. package/src/converter/parsers/diffusion.js +63 -3
  44. package/src/converter/tokenizer-utils.js +17 -3
  45. package/src/formats/rdrr/validation.js +13 -0
  46. package/src/gpu/kernels/depthwise_conv2d.d.ts +29 -0
  47. package/src/gpu/kernels/depthwise_conv2d.js +98 -0
  48. package/src/gpu/kernels/depthwise_conv2d.wgsl +58 -0
  49. package/src/gpu/kernels/depthwise_conv2d_f16.wgsl +62 -0
  50. package/src/gpu/kernels/grouped_pointwise_conv2d.d.ts +27 -0
  51. package/src/gpu/kernels/grouped_pointwise_conv2d.js +92 -0
  52. package/src/gpu/kernels/grouped_pointwise_conv2d.wgsl +47 -0
  53. package/src/gpu/kernels/grouped_pointwise_conv2d_f16.wgsl +51 -0
  54. package/src/gpu/kernels/index.d.ts +30 -0
  55. package/src/gpu/kernels/index.js +25 -0
  56. package/src/gpu/kernels/relu.d.ts +18 -0
  57. package/src/gpu/kernels/relu.js +45 -0
  58. package/src/gpu/kernels/relu.wgsl +21 -0
  59. package/src/gpu/kernels/relu_f16.wgsl +23 -0
  60. package/src/gpu/kernels/repeat_channels.d.ts +21 -0
  61. package/src/gpu/kernels/repeat_channels.js +60 -0
  62. package/src/gpu/kernels/repeat_channels.wgsl +29 -0
  63. package/src/gpu/kernels/repeat_channels_f16.wgsl +31 -0
  64. package/src/gpu/kernels/sana_linear_attention.d.ts +27 -0
  65. package/src/gpu/kernels/sana_linear_attention.js +122 -0
  66. package/src/gpu/kernels/sana_linear_attention_apply.wgsl +44 -0
  67. package/src/gpu/kernels/sana_linear_attention_apply_f16.wgsl +47 -0
  68. package/src/gpu/kernels/sana_linear_attention_summary.wgsl +47 -0
  69. package/src/gpu/kernels/sana_linear_attention_summary_f16.wgsl +49 -0
  70. package/src/index-browser.d.ts +1 -0
  71. package/src/index-browser.js +2 -1
  72. package/src/index.d.ts +1 -0
  73. package/src/index.js +2 -1
  74. package/src/inference/browser-harness.js +164 -38
  75. package/src/inference/pipelines/diffusion/init.js +14 -0
  76. package/src/inference/pipelines/diffusion/pipeline.js +206 -77
  77. package/src/inference/pipelines/diffusion/sana-transformer.d.ts +53 -0
  78. package/src/inference/pipelines/diffusion/sana-transformer.js +738 -0
  79. package/src/inference/pipelines/diffusion/scheduler.d.ts +17 -1
  80. package/src/inference/pipelines/diffusion/scheduler.js +91 -3
  81. package/src/inference/pipelines/diffusion/text-encoder-gpu.d.ts +6 -4
  82. package/src/inference/pipelines/diffusion/text-encoder-gpu.js +270 -0
  83. package/src/inference/pipelines/diffusion/text-encoder.js +18 -1
  84. package/src/inference/pipelines/diffusion/types.d.ts +4 -0
  85. package/src/inference/pipelines/diffusion/vae.js +782 -78
  86. package/src/inference/pipelines/text/config.d.ts +5 -0
  87. package/src/inference/pipelines/text/config.js +1 -1
  88. package/src/inference/pipelines/text/execution-v0.js +141 -101
  89. package/src/inference/pipelines/text/init.js +41 -10
  90. package/src/inference/pipelines/text.js +7 -1
  91. package/src/rules/execution-rules-contract-check.d.ts +17 -0
  92. package/src/rules/execution-rules-contract-check.js +245 -0
  93. package/src/rules/kernels/depthwise-conv2d.rules.json +6 -0
  94. package/src/rules/kernels/grouped-pointwise-conv2d.rules.json +6 -0
  95. package/src/rules/kernels/relu.rules.json +6 -0
  96. package/src/rules/kernels/repeat-channels.rules.json +6 -0
  97. package/src/rules/kernels/sana-linear-attention.rules.json +6 -0
  98. package/src/rules/layer-pattern-contract-check.d.ts +17 -0
  99. package/src/rules/layer-pattern-contract-check.js +231 -0
  100. package/src/rules/rule-registry.d.ts +28 -0
  101. package/src/rules/rule-registry.js +38 -0
  102. package/src/tooling/conversion-config-materializer.d.ts +24 -0
  103. package/src/tooling/conversion-config-materializer.js +99 -0
  104. package/src/tooling/lean-execution-contract-runner.d.ts +43 -0
  105. package/src/tooling/lean-execution-contract-runner.js +158 -0
  106. package/src/tooling/lean-execution-contract.d.ts +16 -0
  107. package/src/tooling/lean-execution-contract.js +81 -0
  108. package/src/tooling/node-convert.d.ts +10 -0
  109. package/src/tooling/node-converter.js +59 -0
  110. package/src/tooling/node-webgpu.js +30 -9
  111. package/src/version.d.ts +2 -0
  112. package/src/version.js +2 -0
  113. package/tools/convert-safetensors-node.js +47 -0
  114. package/tools/doppler-cli.js +167 -6
@@ -0,0 +1,317 @@
1
+ import { DEFAULT_BATCHING_DEFAULTS, DEFAULT_GENERATION_CONFIG } from './schema/inference-defaults.schema.js';
2
+ import { buildExecutionV0ContractArtifact } from './execution-v0-contract-check.js';
3
+ import { buildExecutionV0GraphContractArtifact } from './execution-v0-graph-contract-check.js';
4
+ import { EXECUTION_V0_SCHEMA_ID } from './schema/execution-v0.schema.js';
5
+ import { DEFAULT_KVCACHE_CONFIG } from './schema/kvcache.schema.js';
6
+
7
+ const KV_LAYOUTS = new Set(['contiguous', 'paged', 'tiered', 'bdpa']);
8
+ const PHASES = new Set(['prefill', 'decode', 'both']);
9
+ const COLD_QUANT_MODES = new Set(['none', 'int8', 'int4']);
10
+ const ATTENTION_OPS = new Set(['attention']);
11
+ const EMBED_OPS = new Set(['embed', 'gather']);
12
+ const SAMPLE_OPS = new Set(['sample']);
13
+ const BDPA_MAX_HEAD_DIM = 256;
14
+ const BDPA_MAX_KV_LEN = 2048;
15
+ const TIERED_MAX_QUANT_HEAD_DIM = 256;
16
+
17
+ function isPlainObject(value) {
18
+ return value != null && typeof value === 'object' && !Array.isArray(value);
19
+ }
20
+
21
+ function assertManifestObject(manifest) {
22
+ if (!isPlainObject(manifest)) {
23
+ throw new Error('execution contract: manifest must be an object.');
24
+ }
25
+ return manifest;
26
+ }
27
+
28
+ function assertPositiveInteger(value, label) {
29
+ if (!Number.isInteger(value) || value < 0) {
30
+ throw new Error(`execution contract: ${label} must be a non-negative integer.`);
31
+ }
32
+ return value;
33
+ }
34
+
35
+ function assertPositiveIntegerOrDefault(value, fallback, label) {
36
+ if (value == null) {
37
+ return assertPositiveInteger(fallback, `${label} fallback`);
38
+ }
39
+ return assertPositiveInteger(value, label);
40
+ }
41
+
42
+ function normalizeKVLayout(value) {
43
+ const normalized = String(value ?? DEFAULT_KVCACHE_CONFIG.layout).trim().toLowerCase();
44
+ if (!KV_LAYOUTS.has(normalized)) {
45
+ throw new Error(
46
+ `execution contract: unsupported KV layout "${value}". ` +
47
+ `Expected one of ${[...KV_LAYOUTS].join(', ')}.`
48
+ );
49
+ }
50
+ return normalized;
51
+ }
52
+
53
+ function normalizePhase(value, label) {
54
+ const normalized = String(value ?? '').trim().toLowerCase();
55
+ if (!PHASES.has(normalized)) {
56
+ throw new Error(
57
+ `execution contract: ${label} must be one of ${[...PHASES].join(', ')}.`
58
+ );
59
+ }
60
+ return normalized;
61
+ }
62
+
63
+ function normalizeColdQuantMode(kvcache) {
64
+ const tieringMode = String(
65
+ kvcache?.tiering?.mode
66
+ ?? DEFAULT_KVCACHE_CONFIG.tiering.mode
67
+ ).trim().toLowerCase();
68
+ if (tieringMode === 'off' || tieringMode === 'fp16') {
69
+ return 'none';
70
+ }
71
+ if (!COLD_QUANT_MODES.has(tieringMode)) {
72
+ throw new Error(
73
+ `execution contract: unsupported tiered cold quant mode "${tieringMode}".`
74
+ );
75
+ }
76
+ return tieringMode;
77
+ }
78
+
79
+ function classifyOp(op) {
80
+ const normalized = String(op ?? '').trim().toLowerCase();
81
+ if (!normalized) {
82
+ throw new Error('execution contract: execution step op is required.');
83
+ }
84
+ if (ATTENTION_OPS.has(normalized)) return 'attention';
85
+ if (EMBED_OPS.has(normalized)) return 'embed';
86
+ if (SAMPLE_OPS.has(normalized)) return 'sample';
87
+ if (normalized.includes('norm')) return 'norm';
88
+ if (normalized.includes('residual')) return 'residual';
89
+ if (normalized.endsWith('_proj') || normalized.startsWith('rope_') || normalized === 'activation') {
90
+ return 'projection';
91
+ }
92
+ return 'other';
93
+ }
94
+
95
+ export function sanitizeLeanModuleName(value) {
96
+ const raw = String(value ?? 'GeneratedExecutionContractCheck').trim();
97
+ const alnum = raw.replace(/[^A-Za-z0-9_]/g, '_');
98
+ if (!alnum) {
99
+ return 'GeneratedExecutionContractCheck';
100
+ }
101
+ if (/^[A-Za-z_]/.test(alnum)) {
102
+ return alnum;
103
+ }
104
+ return `Generated_${alnum}`;
105
+ }
106
+
107
+ export function extractExecutionContractFacts(manifest) {
108
+ const normalizedManifest = assertManifestObject(manifest);
109
+ const modelId = String(normalizedManifest.modelId ?? 'model').trim() || 'model';
110
+ const architecture = isPlainObject(normalizedManifest.architecture)
111
+ ? normalizedManifest.architecture
112
+ : {};
113
+ const inference = isPlainObject(normalizedManifest.inference)
114
+ ? normalizedManifest.inference
115
+ : {};
116
+ const sessionDefaults = isPlainObject(inference.sessionDefaults)
117
+ ? inference.sessionDefaults
118
+ : {};
119
+ const execution = isPlainObject(inference.execution)
120
+ ? inference.execution
121
+ : {};
122
+ const kvcache = isPlainObject(sessionDefaults.kvcache)
123
+ ? sessionDefaults.kvcache
124
+ : {};
125
+ const decodeLoop = isPlainObject(sessionDefaults.decodeLoop)
126
+ ? sessionDefaults.decodeLoop
127
+ : {};
128
+
129
+ const steps = Array.isArray(execution.steps)
130
+ ? execution.steps.map((step, index) => {
131
+ if (!isPlainObject(step)) {
132
+ throw new Error(`execution contract: execution.steps[${index}] must be an object.`);
133
+ }
134
+ const id = String(step.id ?? '').trim();
135
+ if (!id) {
136
+ throw new Error(`execution contract: execution.steps[${index}].id is required.`);
137
+ }
138
+ return {
139
+ id,
140
+ phase: normalizePhase(step.phase, `execution.steps[${index}].phase`),
141
+ opClass: classifyOp(step.op),
142
+ };
143
+ })
144
+ : [];
145
+
146
+ return {
147
+ modelId,
148
+ session: {
149
+ layout: normalizeKVLayout(kvcache.layout),
150
+ disableCommandBatching: decodeLoop.disableCommandBatching
151
+ ?? DEFAULT_GENERATION_CONFIG.disableCommandBatching,
152
+ decodeBatchSize: assertPositiveIntegerOrDefault(
153
+ decodeLoop.batchSize,
154
+ DEFAULT_BATCHING_DEFAULTS.batchSize,
155
+ 'sessionDefaults.decodeLoop.batchSize'
156
+ ),
157
+ headDim: assertPositiveInteger(architecture.headDim, 'architecture.headDim'),
158
+ kvLen: assertPositiveIntegerOrDefault(
159
+ architecture.maxSeqLen ?? kvcache.maxSeqLen,
160
+ DEFAULT_KVCACHE_CONFIG.maxSeqLen,
161
+ 'architecture.maxSeqLen'
162
+ ),
163
+ coldQuantMode: normalizeColdQuantMode(kvcache),
164
+ },
165
+ steps,
166
+ };
167
+ }
168
+
169
+ export function validateExecutionContractFacts(facts) {
170
+ const errors = [];
171
+ const checks = [];
172
+ const modelId = String(facts?.modelId ?? 'model');
173
+ const session = facts?.session ?? {};
174
+ const steps = Array.isArray(facts?.steps) ? facts.steps : [];
175
+
176
+ const incompatibleStep = session.layout === 'bdpa'
177
+ ? steps.find((step) => step.opClass === 'attention' && (step.phase === 'prefill' || step.phase === 'both'))
178
+ : null;
179
+ if (incompatibleStep) {
180
+ errors.push(
181
+ `[ExecutionContract] sessionDefaults.kvcache.layout="bdpa" is decode-only, ` +
182
+ `but step "${incompatibleStep.id}" declares ${incompatibleStep.phase} attention.`
183
+ );
184
+ }
185
+ checks.push({
186
+ id: `${modelId}.steps`,
187
+ ok: incompatibleStep == null,
188
+ });
189
+
190
+ const sessionErrorCount = errors.length;
191
+ if (session.layout === 'bdpa') {
192
+ if (session.disableCommandBatching !== true) {
193
+ errors.push(
194
+ '[ExecutionContract] sessionDefaults.kvcache.layout="bdpa" requires ' +
195
+ 'sessionDefaults.decodeLoop.disableCommandBatching=true.'
196
+ );
197
+ }
198
+ if (session.decodeBatchSize > 1) {
199
+ errors.push(
200
+ `[ExecutionContract] sessionDefaults.kvcache.layout="bdpa" requires ` +
201
+ `sessionDefaults.decodeLoop.batchSize <= 1; got ${session.decodeBatchSize}.`
202
+ );
203
+ }
204
+ if (session.headDim > BDPA_MAX_HEAD_DIM) {
205
+ errors.push(
206
+ `[ExecutionContract] sessionDefaults.kvcache.layout="bdpa" requires architecture.headDim <= ${BDPA_MAX_HEAD_DIM}; ` +
207
+ `got ${session.headDim}.`
208
+ );
209
+ }
210
+ if (session.kvLen > BDPA_MAX_KV_LEN) {
211
+ errors.push(
212
+ `[ExecutionContract] sessionDefaults.kvcache.layout="bdpa" requires architecture.maxSeqLen <= ${BDPA_MAX_KV_LEN}; ` +
213
+ `got ${session.kvLen}.`
214
+ );
215
+ }
216
+ }
217
+
218
+ if (
219
+ session.layout === 'tiered'
220
+ && session.coldQuantMode !== 'none'
221
+ && session.headDim > TIERED_MAX_QUANT_HEAD_DIM
222
+ ) {
223
+ errors.push(
224
+ `[ExecutionContract] sessionDefaults.kvcache.layout="tiered" with cold quantization requires ` +
225
+ `architecture.headDim <= ${TIERED_MAX_QUANT_HEAD_DIM}; got ${session.headDim}.`
226
+ );
227
+ }
228
+
229
+ checks.push({
230
+ id: `${modelId}.session`,
231
+ ok: errors.length === sessionErrorCount,
232
+ });
233
+
234
+ return {
235
+ ok: errors.length === 0,
236
+ errors,
237
+ checks,
238
+ };
239
+ }
240
+
241
+ export function validateManifestExecutionContract(manifest) {
242
+ const facts = extractExecutionContractFacts(manifest);
243
+ const evaluation = validateExecutionContractFacts(facts);
244
+ return {
245
+ ...evaluation,
246
+ facts,
247
+ };
248
+ }
249
+
250
+ export function buildExecutionContractArtifact(manifest) {
251
+ if (!manifest || typeof manifest !== 'object') {
252
+ return null;
253
+ }
254
+ if (manifest.modelType === 'diffusion' || manifest.modelType === 'energy') {
255
+ return null;
256
+ }
257
+ if (!manifest.architecture || !manifest.inference || typeof manifest.inference !== 'object') {
258
+ return null;
259
+ }
260
+ try {
261
+ const evaluation = validateManifestExecutionContract(manifest);
262
+ const attentionPhaseCounts = { prefill: 0, decode: 0, both: 0 };
263
+ for (const step of evaluation.facts.steps) {
264
+ if (step.opClass !== 'attention') continue;
265
+ if (Object.prototype.hasOwnProperty.call(attentionPhaseCounts, step.phase)) {
266
+ attentionPhaseCounts[step.phase] += 1;
267
+ }
268
+ }
269
+ const executionV0 =
270
+ manifest?.inference?.schema === EXECUTION_V0_SCHEMA_ID
271
+ ? {
272
+ kernelProfiles: buildExecutionV0ContractArtifact(manifest.inference, {
273
+ modelId: evaluation.facts.modelId,
274
+ }),
275
+ graph: buildExecutionV0GraphContractArtifact({
276
+ modelId: evaluation.facts.modelId,
277
+ numLayers: manifest?.architecture?.numLayers,
278
+ manifestInference: manifest.inference,
279
+ }),
280
+ }
281
+ : null;
282
+ const nestedChecks = [];
283
+ const nestedErrors = [];
284
+ if (executionV0?.kernelProfiles) {
285
+ nestedChecks.push(...executionV0.kernelProfiles.checks);
286
+ nestedErrors.push(...executionV0.kernelProfiles.errors);
287
+ }
288
+ if (executionV0?.graph) {
289
+ nestedChecks.push(...executionV0.graph.checks);
290
+ nestedErrors.push(...executionV0.graph.errors);
291
+ }
292
+ return {
293
+ schemaVersion: 1,
294
+ source: 'doppler',
295
+ ok: evaluation.ok && nestedErrors.length === 0,
296
+ checks: [...evaluation.checks, ...nestedChecks],
297
+ errors: [...evaluation.errors, ...nestedErrors],
298
+ session: evaluation.facts.session,
299
+ steps: {
300
+ total: evaluation.facts.steps.length,
301
+ attention: attentionPhaseCounts.prefill + attentionPhaseCounts.decode + attentionPhaseCounts.both,
302
+ attentionPhases: attentionPhaseCounts,
303
+ },
304
+ ...(executionV0 ? { executionV0 } : {}),
305
+ };
306
+ } catch (error) {
307
+ return {
308
+ schemaVersion: 1,
309
+ source: 'doppler',
310
+ ok: false,
311
+ checks: [],
312
+ errors: [error instanceof Error ? error.message : String(error)],
313
+ session: null,
314
+ steps: null,
315
+ };
316
+ }
317
+ }
@@ -0,0 +1,94 @@
1
+ import type {
2
+ ExecutionV0ComputeDefaultsSchema,
3
+ ExecutionV0KernelProfileSchema,
4
+ ExecutionV0KernelRefSchema,
5
+ ExecutionV0KVIO,
6
+ ExecutionV0PrecisionSchema,
7
+ ExecutionV0SessionDefaultsSchema,
8
+ ExecutionV0StepSchema,
9
+ } from './schema/execution-v0.schema.js';
10
+
11
+ export interface ExecutionV0ContractCheckResult {
12
+ id: string;
13
+ ok: boolean;
14
+ }
15
+
16
+ export interface ExecutionV0ContractPerStep {
17
+ precision: {
18
+ inputDtype: string | null;
19
+ mathDtype: string | null;
20
+ accumDtype: string | null;
21
+ outputDtype: string | null;
22
+ };
23
+ precisionSources: {
24
+ inputDtype: 'manifest' | 'kernelProfile' | 'sessionDefault' | 'derived';
25
+ mathDtype: 'manifest' | 'kernelProfile' | 'sessionDefault' | 'derived';
26
+ accumDtype: 'manifest' | 'kernelProfile' | 'sessionDefault' | 'derived';
27
+ outputDtype: 'manifest' | 'kernelProfile' | 'sessionDefault' | 'derived';
28
+ };
29
+ resolvedPrecision?: {
30
+ inputDtype: 'f16' | 'f32' | null;
31
+ mathDtype: 'f16' | 'f32';
32
+ accumDtype: 'f16' | 'f32';
33
+ outputDtype: 'f16' | 'f32';
34
+ };
35
+ kvIO?: ExecutionV0KVIO;
36
+ kvIOSource?: 'manifest' | 'kernelProfile' | 'sessionDefault';
37
+ }
38
+
39
+ export interface ExecutionV0ContractArtifact {
40
+ schemaVersion: 1;
41
+ source: 'doppler';
42
+ ok: boolean;
43
+ checks: ExecutionV0ContractCheckResult[];
44
+ errors: string[];
45
+ stats: {
46
+ kernelProfiles: number;
47
+ pinnedSteps: number;
48
+ };
49
+ perStep: Record<string, ExecutionV0ContractPerStep>;
50
+ }
51
+
52
+ export declare function normalizeExecutionV0Dtype(value: unknown, label: string): 'f16' | 'f32';
53
+ export declare function buildExecutionV0KernelProfileKey(
54
+ kernelRef: ExecutionV0KernelRefSchema | null | undefined
55
+ ): string | null;
56
+ export declare function indexExecutionV0KernelProfiles(
57
+ sessionDefaults?: Partial<ExecutionV0SessionDefaultsSchema> | null
58
+ ): Map<string, ExecutionV0KernelProfileSchema>;
59
+ export declare function resolveExecutionV0KernelProfile(
60
+ profileIndex: Map<string, ExecutionV0KernelProfileSchema>,
61
+ step: Partial<ExecutionV0StepSchema>
62
+ ): ExecutionV0KernelProfileSchema | null;
63
+ export declare function resolveExecutionV0Precision(
64
+ step: Partial<ExecutionV0StepSchema>,
65
+ profile: ExecutionV0KernelProfileSchema | null,
66
+ sessionDefaults?: Partial<ExecutionV0SessionDefaultsSchema> | null
67
+ ): {
68
+ precision: {
69
+ inputDtype: 'f16' | 'f32' | null;
70
+ mathDtype: 'f16' | 'f32';
71
+ accumDtype: 'f16' | 'f32';
72
+ outputDtype: 'f16' | 'f32';
73
+ };
74
+ sources: {
75
+ inputDtype: 'manifest' | 'kernelProfile' | 'sessionDefault' | 'derived';
76
+ mathDtype: 'manifest' | 'kernelProfile' | 'sessionDefault' | 'derived';
77
+ accumDtype: 'manifest' | 'kernelProfile' | 'sessionDefault' | 'derived';
78
+ outputDtype: 'manifest' | 'kernelProfile' | 'sessionDefault' | 'derived';
79
+ };
80
+ };
81
+ export declare function resolveExecutionV0KVIO(
82
+ step: Partial<ExecutionV0StepSchema>,
83
+ profile: ExecutionV0KernelProfileSchema | null,
84
+ sessionDefaults?: Partial<ExecutionV0SessionDefaultsSchema> | null
85
+ ): {
86
+ value: ExecutionV0KVIO;
87
+ source: 'manifest' | 'kernelProfile' | 'sessionDefault';
88
+ };
89
+ export declare function buildExecutionV0ContractArtifact(
90
+ manifestInference: Record<string, unknown> | null | undefined,
91
+ options?: {
92
+ modelId?: string;
93
+ }
94
+ ): ExecutionV0ContractArtifact | null;
@@ -0,0 +1,251 @@
1
+ import {
2
+ DEFAULT_EXECUTION_V0_COMPUTE_DEFAULTS,
3
+ isExecutionV0Digest,
4
+ isExecutionV0Semver,
5
+ } from './schema/execution-v0.schema.js';
6
+
7
+ function normalizeDtype(value, label) {
8
+ const normalized = String(value ?? '').trim().toLowerCase();
9
+ if (normalized !== 'f16' && normalized !== 'f32') {
10
+ throw new Error(`[ExecutionV0Contract] ${label} must be "f16" or "f32"; got "${value}"`);
11
+ }
12
+ return normalized;
13
+ }
14
+
15
+ function buildKernelProfileKey(kernelRef) {
16
+ if (!kernelRef) return null;
17
+ return `${kernelRef.id}|${kernelRef.version}|${kernelRef.digest}`;
18
+ }
19
+
20
+ function assertExecutionV0KernelRef(kernelRef, label) {
21
+ if (!kernelRef || typeof kernelRef !== 'object' || Array.isArray(kernelRef)) {
22
+ throw new Error(`[ExecutionV0Contract] ${label} is required.`);
23
+ }
24
+ if (typeof kernelRef.id !== 'string' || kernelRef.id.trim().length === 0) {
25
+ throw new Error(`[ExecutionV0Contract] ${label}.id is required.`);
26
+ }
27
+ if (!isExecutionV0Semver(kernelRef.version)) {
28
+ throw new Error(`[ExecutionV0Contract] ${label}.version must be semver.`);
29
+ }
30
+ if (!isExecutionV0Digest(kernelRef.digest)) {
31
+ throw new Error(`[ExecutionV0Contract] ${label}.digest must match sha256:<64-hex>.`);
32
+ }
33
+ }
34
+
35
+ function createPrecisionSources(step, profile) {
36
+ return {
37
+ inputDtype: step.precision?.inputDtype != null
38
+ ? 'manifest'
39
+ : profile?.precision?.inputDtype != null
40
+ ? 'kernelProfile'
41
+ : 'derived',
42
+ mathDtype: step.precision?.mathDtype != null
43
+ ? 'manifest'
44
+ : profile?.precision?.mathDtype != null
45
+ ? 'kernelProfile'
46
+ : 'sessionDefault',
47
+ accumDtype: step.precision?.accumDtype != null
48
+ ? 'manifest'
49
+ : profile?.precision?.accumDtype != null
50
+ ? 'kernelProfile'
51
+ : 'sessionDefault',
52
+ outputDtype: step.precision?.outputDtype != null
53
+ ? 'manifest'
54
+ : profile?.precision?.outputDtype != null
55
+ ? 'kernelProfile'
56
+ : 'sessionDefault',
57
+ };
58
+ }
59
+
60
+ export function normalizeExecutionV0Dtype(value, label) {
61
+ return normalizeDtype(value, label);
62
+ }
63
+
64
+ export function buildExecutionV0KernelProfileKey(kernelRef) {
65
+ return buildKernelProfileKey(kernelRef);
66
+ }
67
+
68
+ export function indexExecutionV0KernelProfiles(sessionDefaults = {}) {
69
+ const byKey = new Map();
70
+ const profiles = sessionDefaults?.compute?.kernelProfiles ?? [];
71
+ for (const profile of profiles) {
72
+ assertExecutionV0KernelRef(profile?.kernelRef, 'sessionDefaults.compute.kernelProfiles[].kernelRef');
73
+ const key = buildKernelProfileKey(profile?.kernelRef);
74
+ if (byKey.has(key)) {
75
+ throw new Error(
76
+ `[ExecutionV0Contract] duplicate kernel profile for ${profile.kernelRef.id}@${profile.kernelRef.version} ` +
77
+ `(${profile.kernelRef.digest}). Expected exactly one pinned profile per kernelRef.`
78
+ );
79
+ }
80
+ byKey.set(key, profile);
81
+ }
82
+ return byKey;
83
+ }
84
+
85
+ export function resolveExecutionV0KernelProfile(profileIndex, step) {
86
+ const key = buildKernelProfileKey(step?.kernelRef);
87
+ if (!key) return null;
88
+ return profileIndex.get(key) ?? null;
89
+ }
90
+
91
+ export function resolveExecutionV0Precision(step, profile, sessionDefaults = {}) {
92
+ const defaults = {
93
+ ...DEFAULT_EXECUTION_V0_COMPUTE_DEFAULTS,
94
+ ...(sessionDefaults?.compute?.defaults ?? {}),
95
+ };
96
+ const precision = {
97
+ inputDtype: step.precision?.inputDtype
98
+ ?? profile?.precision?.inputDtype
99
+ ?? null,
100
+ mathDtype: step.precision?.mathDtype
101
+ ?? profile?.precision?.mathDtype
102
+ ?? defaults.mathDtype,
103
+ accumDtype: step.precision?.accumDtype
104
+ ?? profile?.precision?.accumDtype
105
+ ?? defaults.accumDtype,
106
+ outputDtype: step.precision?.outputDtype
107
+ ?? profile?.precision?.outputDtype
108
+ ?? defaults.outputDtype,
109
+ };
110
+ return {
111
+ precision,
112
+ sources: createPrecisionSources(step, profile),
113
+ };
114
+ }
115
+
116
+ export function resolveExecutionV0KVIO(step, profile, sessionDefaults = {}) {
117
+ if (step.kvIO) {
118
+ return {
119
+ value: {
120
+ readDtype: normalizeDtype(step.kvIO.readDtype, `${step.id}.kvIO.readDtype`),
121
+ writeDtype: normalizeDtype(step.kvIO.writeDtype, `${step.id}.kvIO.writeDtype`),
122
+ },
123
+ source: 'manifest',
124
+ };
125
+ }
126
+ if (profile?.kvIO) {
127
+ return {
128
+ value: {
129
+ readDtype: normalizeDtype(profile.kvIO.readDtype, `${step.id}.profile.kvIO.readDtype`),
130
+ writeDtype: normalizeDtype(profile.kvIO.writeDtype, `${step.id}.profile.kvIO.writeDtype`),
131
+ },
132
+ source: 'kernelProfile',
133
+ };
134
+ }
135
+ const defaults = {
136
+ ...DEFAULT_EXECUTION_V0_COMPUTE_DEFAULTS,
137
+ ...(sessionDefaults?.compute?.defaults ?? {}),
138
+ };
139
+ const kvDtype = normalizeDtype(
140
+ sessionDefaults?.kvcache?.kvDtype ?? defaults.activationDtype,
141
+ `${step.id}.sessionDefaults.kvcache.kvDtype`
142
+ );
143
+ return {
144
+ value: { readDtype: kvDtype, writeDtype: kvDtype },
145
+ source: 'sessionDefault',
146
+ };
147
+ }
148
+
149
+ export function buildExecutionV0ContractArtifact(manifestInference, options = {}) {
150
+ if (!manifestInference?.execution || !Array.isArray(manifestInference.execution.steps)) {
151
+ return null;
152
+ }
153
+
154
+ const modelId = String(options.modelId ?? 'model');
155
+ const checks = [];
156
+ const errors = [];
157
+ const perStep = {};
158
+ const sessionDefaults = manifestInference.sessionDefaults ?? {};
159
+ let profileIndex;
160
+
161
+ try {
162
+ profileIndex = indexExecutionV0KernelProfiles(sessionDefaults);
163
+ } catch (error) {
164
+ errors.push(error instanceof Error ? error.message : String(error));
165
+ checks.push({ id: `${modelId}.kernelProfilePinning`, ok: false });
166
+ checks.push({ id: `${modelId}.precisionPrecedence`, ok: false });
167
+ checks.push({ id: `${modelId}.kvIOPrecedence`, ok: false });
168
+ return {
169
+ schemaVersion: 1,
170
+ source: 'doppler',
171
+ ok: false,
172
+ checks,
173
+ errors,
174
+ stats: {
175
+ kernelProfiles: sessionDefaults?.compute?.kernelProfiles?.length ?? 0,
176
+ pinnedSteps: 0,
177
+ },
178
+ perStep,
179
+ };
180
+ }
181
+
182
+ let pinningOk = true;
183
+ let precisionOk = true;
184
+ let kvOk = true;
185
+ let pinnedSteps = 0;
186
+
187
+ for (const step of manifestInference.execution.steps) {
188
+ if (!step || typeof step !== 'object') continue;
189
+ if (step.op === 'cast') continue;
190
+ if (!step.kernelRef) {
191
+ pinningOk = false;
192
+ precisionOk = false;
193
+ errors.push(`[ExecutionV0Contract] step "${step.id ?? 'unknown'}" requires kernelRef.`);
194
+ continue;
195
+ }
196
+ const profile = resolveExecutionV0KernelProfile(profileIndex, step);
197
+ if (!profile) {
198
+ pinningOk = false;
199
+ precisionOk = false;
200
+ errors.push(
201
+ `[ExecutionV0Contract] step "${step.id ?? 'unknown'}" kernelRef ` +
202
+ `${step.kernelRef.id}@${step.kernelRef.version} (${step.kernelRef.digest}) is unresolved.`
203
+ );
204
+ continue;
205
+ }
206
+ pinnedSteps += 1;
207
+ const { precision, sources } = resolveExecutionV0Precision(step, profile, sessionDefaults);
208
+ perStep[step.id] = {
209
+ precision,
210
+ precisionSources: sources,
211
+ };
212
+ try {
213
+ perStep[step.id].resolvedPrecision = {
214
+ inputDtype: precision.inputDtype == null ? null : normalizeDtype(precision.inputDtype, `${step.id}.precision.inputDtype`),
215
+ mathDtype: normalizeDtype(precision.mathDtype, `${step.id}.precision.mathDtype`),
216
+ accumDtype: normalizeDtype(precision.accumDtype, `${step.id}.precision.accumDtype`),
217
+ outputDtype: normalizeDtype(precision.outputDtype, `${step.id}.precision.outputDtype`),
218
+ };
219
+ } catch (error) {
220
+ precisionOk = false;
221
+ errors.push(error instanceof Error ? error.message : String(error));
222
+ }
223
+ if (step.op === 'attention') {
224
+ try {
225
+ const kvIO = resolveExecutionV0KVIO(step, profile, sessionDefaults);
226
+ perStep[step.id].kvIO = kvIO.value;
227
+ perStep[step.id].kvIOSource = kvIO.source;
228
+ } catch (error) {
229
+ kvOk = false;
230
+ errors.push(error instanceof Error ? error.message : String(error));
231
+ }
232
+ }
233
+ }
234
+
235
+ checks.push({ id: `${modelId}.kernelProfilePinning`, ok: pinningOk });
236
+ checks.push({ id: `${modelId}.precisionPrecedence`, ok: precisionOk });
237
+ checks.push({ id: `${modelId}.kvIOPrecedence`, ok: kvOk });
238
+
239
+ return {
240
+ schemaVersion: 1,
241
+ source: 'doppler',
242
+ ok: errors.length === 0,
243
+ checks,
244
+ errors,
245
+ stats: {
246
+ kernelProfiles: sessionDefaults?.compute?.kernelProfiles?.length ?? 0,
247
+ pinnedSteps,
248
+ },
249
+ perStep,
250
+ };
251
+ }
@@ -0,0 +1,20 @@
1
+ export interface ExecutionV0GraphContractCheckResult {
2
+ id: string;
3
+ ok: boolean;
4
+ }
5
+
6
+ export interface ExecutionV0GraphContractArtifact {
7
+ schemaVersion: 1;
8
+ source: 'doppler';
9
+ ok: boolean;
10
+ checks: ExecutionV0GraphContractCheckResult[];
11
+ errors: string[];
12
+ stats: {
13
+ prefillSteps: number;
14
+ decodeSteps: number;
15
+ };
16
+ }
17
+
18
+ export declare function buildExecutionV0GraphContractArtifact(
19
+ options?: Record<string, unknown>
20
+ ): ExecutionV0GraphContractArtifact | null;