@simulatte/doppler 0.1.4 → 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.
- package/README.md +4 -3
- package/package.json +25 -4
- package/src/client/doppler-api.browser.d.ts +1 -0
- package/src/client/doppler-api.browser.js +288 -0
- package/src/client/doppler-api.js +1 -1
- package/src/client/doppler-provider/types.js +1 -1
- package/src/config/execution-contract-check.d.ts +33 -0
- package/src/config/execution-contract-check.js +72 -0
- package/src/config/execution-v0-contract-check.d.ts +94 -0
- package/src/config/execution-v0-contract-check.js +251 -0
- package/src/config/execution-v0-graph-contract-check.d.ts +20 -0
- package/src/config/execution-v0-graph-contract-check.js +64 -0
- package/src/config/kernel-path-contract-check.d.ts +76 -0
- package/src/config/kernel-path-contract-check.js +479 -0
- package/src/config/kernel-path-loader.d.ts +16 -0
- package/src/config/kernel-path-loader.js +54 -0
- package/src/config/kernels/kernel-ref-digests.js +12 -0
- package/src/config/kernels/registry.json +556 -0
- package/src/config/loader.js +50 -46
- package/src/config/merge-contract-check.d.ts +16 -0
- package/src/config/merge-contract-check.js +321 -0
- package/src/config/merge-helpers.d.ts +58 -0
- package/src/config/merge-helpers.js +54 -0
- package/src/config/merge.js +3 -6
- package/src/config/presets/models/janus-text.json +2 -0
- package/src/config/quantization-contract-check.d.ts +12 -0
- package/src/config/quantization-contract-check.js +91 -0
- package/src/config/required-inference-fields-contract-check.d.ts +24 -0
- package/src/config/required-inference-fields-contract-check.js +231 -0
- package/src/config/schema/browser-suite-metrics.schema.d.ts +17 -0
- package/src/config/schema/browser-suite-metrics.schema.js +46 -0
- package/src/config/schema/conversion-report.schema.d.ts +40 -0
- package/src/config/schema/conversion-report.schema.js +108 -0
- package/src/config/schema/doppler.schema.js +12 -18
- package/src/config/schema/index.d.ts +22 -0
- package/src/config/schema/index.js +18 -0
- package/src/converter/core.d.ts +10 -0
- package/src/converter/core.js +27 -2
- package/src/converter/parsers/diffusion.js +63 -3
- package/src/gpu/kernels/depthwise_conv2d.d.ts +29 -0
- package/src/gpu/kernels/depthwise_conv2d.js +98 -0
- package/src/gpu/kernels/depthwise_conv2d.wgsl +58 -0
- package/src/gpu/kernels/depthwise_conv2d_f16.wgsl +62 -0
- package/src/gpu/kernels/grouped_pointwise_conv2d.d.ts +27 -0
- package/src/gpu/kernels/grouped_pointwise_conv2d.js +92 -0
- package/src/gpu/kernels/grouped_pointwise_conv2d.wgsl +47 -0
- package/src/gpu/kernels/grouped_pointwise_conv2d_f16.wgsl +51 -0
- package/src/gpu/kernels/index.d.ts +30 -0
- package/src/gpu/kernels/index.js +25 -0
- package/src/gpu/kernels/relu.d.ts +18 -0
- package/src/gpu/kernels/relu.js +45 -0
- package/src/gpu/kernels/relu.wgsl +21 -0
- package/src/gpu/kernels/relu_f16.wgsl +23 -0
- package/src/gpu/kernels/repeat_channels.d.ts +21 -0
- package/src/gpu/kernels/repeat_channels.js +60 -0
- package/src/gpu/kernels/repeat_channels.wgsl +29 -0
- package/src/gpu/kernels/repeat_channels_f16.wgsl +31 -0
- package/src/gpu/kernels/sana_linear_attention.d.ts +27 -0
- package/src/gpu/kernels/sana_linear_attention.js +122 -0
- package/src/gpu/kernels/sana_linear_attention_apply.wgsl +44 -0
- package/src/gpu/kernels/sana_linear_attention_apply_f16.wgsl +47 -0
- package/src/gpu/kernels/sana_linear_attention_summary.wgsl +47 -0
- package/src/gpu/kernels/sana_linear_attention_summary_f16.wgsl +49 -0
- package/src/index-browser.d.ts +1 -1
- package/src/index-browser.js +2 -2
- package/src/index.js +1 -1
- package/src/inference/browser-harness.js +62 -22
- package/src/inference/pipelines/diffusion/init.js +14 -0
- package/src/inference/pipelines/diffusion/pipeline.js +206 -77
- package/src/inference/pipelines/diffusion/sana-transformer.d.ts +53 -0
- package/src/inference/pipelines/diffusion/sana-transformer.js +738 -0
- package/src/inference/pipelines/diffusion/scheduler.d.ts +17 -1
- package/src/inference/pipelines/diffusion/scheduler.js +91 -3
- package/src/inference/pipelines/diffusion/text-encoder-gpu.d.ts +6 -4
- package/src/inference/pipelines/diffusion/text-encoder-gpu.js +270 -0
- package/src/inference/pipelines/diffusion/text-encoder.js +18 -1
- package/src/inference/pipelines/diffusion/types.d.ts +4 -0
- package/src/inference/pipelines/diffusion/vae.js +782 -78
- package/src/inference/pipelines/text/config.d.ts +5 -0
- package/src/inference/pipelines/text/config.js +1 -1
- package/src/inference/pipelines/text/execution-v0.js +14 -93
- package/src/rules/execution-rules-contract-check.d.ts +17 -0
- package/src/rules/execution-rules-contract-check.js +245 -0
- package/src/rules/kernels/depthwise-conv2d.rules.json +6 -0
- package/src/rules/kernels/grouped-pointwise-conv2d.rules.json +6 -0
- package/src/rules/kernels/relu.rules.json +6 -0
- package/src/rules/kernels/repeat-channels.rules.json +6 -0
- package/src/rules/kernels/sana-linear-attention.rules.json +6 -0
- package/src/rules/layer-pattern-contract-check.d.ts +17 -0
- package/src/rules/layer-pattern-contract-check.js +231 -0
- package/src/rules/rule-registry.d.ts +28 -0
- package/src/rules/rule-registry.js +38 -0
- package/src/tooling/conversion-config-materializer.d.ts +24 -0
- package/src/tooling/conversion-config-materializer.js +99 -0
- package/src/tooling/lean-execution-contract-runner.d.ts +43 -0
- package/src/tooling/lean-execution-contract-runner.js +158 -0
- package/src/tooling/node-convert.d.ts +10 -0
- package/src/tooling/node-converter.js +59 -0
- package/src/tooling/node-webgpu.js +9 -9
- package/src/version.d.ts +2 -0
- package/src/version.js +2 -0
- package/tools/convert-safetensors-node.js +47 -0
- package/tools/doppler-cli.js +115 -1
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { validateRequiredInferenceFields } from '../inference/pipelines/text/config.js';
|
|
2
|
+
|
|
3
|
+
function cloneJson(value) {
|
|
4
|
+
if (typeof structuredClone === 'function') {
|
|
5
|
+
return structuredClone(value);
|
|
6
|
+
}
|
|
7
|
+
return JSON.parse(JSON.stringify(value));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function setPath(root, path, value) {
|
|
11
|
+
let current = root;
|
|
12
|
+
for (let i = 0; i < path.length - 1; i += 1) {
|
|
13
|
+
current = current[path[i]];
|
|
14
|
+
}
|
|
15
|
+
current[path[path.length - 1]] = value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function deletePath(root, path) {
|
|
19
|
+
let current = root;
|
|
20
|
+
for (let i = 0; i < path.length - 1; i += 1) {
|
|
21
|
+
current = current[path[i]];
|
|
22
|
+
}
|
|
23
|
+
delete current[path[path.length - 1]];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function createValidInferenceFixture() {
|
|
27
|
+
return {
|
|
28
|
+
attention: {
|
|
29
|
+
queryPreAttnScalar: 256,
|
|
30
|
+
queryKeyNorm: true,
|
|
31
|
+
attentionBias: false,
|
|
32
|
+
causal: true,
|
|
33
|
+
slidingWindow: null,
|
|
34
|
+
attnLogitSoftcapping: null,
|
|
35
|
+
},
|
|
36
|
+
normalization: {
|
|
37
|
+
rmsNormWeightOffset: true,
|
|
38
|
+
rmsNormEps: 1e-6,
|
|
39
|
+
postAttentionNorm: true,
|
|
40
|
+
preFeedforwardNorm: true,
|
|
41
|
+
postFeedforwardNorm: true,
|
|
42
|
+
},
|
|
43
|
+
ffn: {
|
|
44
|
+
activation: 'gelu',
|
|
45
|
+
gatedActivation: true,
|
|
46
|
+
swigluLimit: null,
|
|
47
|
+
},
|
|
48
|
+
rope: {
|
|
49
|
+
ropeTheta: 1000000,
|
|
50
|
+
ropeScalingFactor: 1.0,
|
|
51
|
+
ropeScalingType: null,
|
|
52
|
+
ropeLocalTheta: null,
|
|
53
|
+
yarnBetaFast: null,
|
|
54
|
+
yarnBetaSlow: null,
|
|
55
|
+
yarnOriginalMaxPos: null,
|
|
56
|
+
},
|
|
57
|
+
output: {
|
|
58
|
+
tieWordEmbeddings: true,
|
|
59
|
+
scaleEmbeddings: true,
|
|
60
|
+
embeddingTranspose: false,
|
|
61
|
+
finalLogitSoftcapping: null,
|
|
62
|
+
embeddingVocabSize: null,
|
|
63
|
+
},
|
|
64
|
+
layerPattern: {
|
|
65
|
+
type: 'every_n',
|
|
66
|
+
globalPattern: null,
|
|
67
|
+
period: 6,
|
|
68
|
+
offset: 0,
|
|
69
|
+
},
|
|
70
|
+
chatTemplate: {
|
|
71
|
+
type: null,
|
|
72
|
+
enabled: true,
|
|
73
|
+
},
|
|
74
|
+
defaultKernelPath: 'unit-test',
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const FIELD_CASES = Object.freeze([
|
|
79
|
+
{ kind: 'nonNullable', path: ['attention', 'queryPreAttnScalar'], message: 'attention.queryPreAttnScalar is required' },
|
|
80
|
+
{ kind: 'nonNullable', path: ['attention', 'queryKeyNorm'], message: 'attention.queryKeyNorm is required' },
|
|
81
|
+
{ kind: 'nonNullable', path: ['attention', 'attentionBias'], message: 'attention.attentionBias is required' },
|
|
82
|
+
{ kind: 'nonNullable', path: ['attention', 'causal'], message: 'attention.causal is required' },
|
|
83
|
+
{ kind: 'nullable', path: ['attention', 'slidingWindow'], message: 'attention.slidingWindow must be explicitly set' },
|
|
84
|
+
{ kind: 'nullable', path: ['attention', 'attnLogitSoftcapping'], message: 'attention.attnLogitSoftcapping must be explicitly set' },
|
|
85
|
+
{ kind: 'nonNullable', path: ['normalization', 'rmsNormWeightOffset'], message: 'normalization.rmsNormWeightOffset is required' },
|
|
86
|
+
{ kind: 'nonNullable', path: ['normalization', 'rmsNormEps'], message: 'normalization.rmsNormEps is required' },
|
|
87
|
+
{ kind: 'nonNullable', path: ['normalization', 'postAttentionNorm'], message: 'normalization.postAttentionNorm is required' },
|
|
88
|
+
{ kind: 'nonNullable', path: ['normalization', 'preFeedforwardNorm'], message: 'normalization.preFeedforwardNorm is required' },
|
|
89
|
+
{ kind: 'nonNullable', path: ['normalization', 'postFeedforwardNorm'], message: 'normalization.postFeedforwardNorm is required' },
|
|
90
|
+
{ kind: 'nonNullable', path: ['ffn', 'activation'], message: 'ffn.activation is required' },
|
|
91
|
+
{ kind: 'nonNullable', path: ['ffn', 'gatedActivation'], message: 'ffn.gatedActivation is required' },
|
|
92
|
+
{ kind: 'nullable', path: ['ffn', 'swigluLimit'], message: 'ffn.swigluLimit must be explicitly set' },
|
|
93
|
+
{ kind: 'nonNullable', path: ['rope', 'ropeTheta'], message: 'rope.ropeTheta is required' },
|
|
94
|
+
{ kind: 'nonNullable', path: ['rope', 'ropeScalingFactor'], message: 'rope.ropeScalingFactor is required' },
|
|
95
|
+
{ kind: 'nullable', path: ['rope', 'ropeScalingType'], message: 'rope.ropeScalingType must be explicitly set' },
|
|
96
|
+
{ kind: 'nullable', path: ['rope', 'ropeLocalTheta'], message: 'rope.ropeLocalTheta must be explicitly set' },
|
|
97
|
+
{ kind: 'nullable', path: ['rope', 'yarnBetaFast'], message: 'rope.yarnBetaFast must be explicitly set' },
|
|
98
|
+
{ kind: 'nullable', path: ['rope', 'yarnBetaSlow'], message: 'rope.yarnBetaSlow must be explicitly set' },
|
|
99
|
+
{ kind: 'nullable', path: ['rope', 'yarnOriginalMaxPos'], message: 'rope.yarnOriginalMaxPos must be explicitly set' },
|
|
100
|
+
{ kind: 'nonNullable', path: ['output', 'tieWordEmbeddings'], message: 'output.tieWordEmbeddings is required' },
|
|
101
|
+
{ kind: 'nonNullable', path: ['output', 'scaleEmbeddings'], message: 'output.scaleEmbeddings is required' },
|
|
102
|
+
{ kind: 'nonNullable', path: ['output', 'embeddingTranspose'], message: 'output.embeddingTranspose is required' },
|
|
103
|
+
{ kind: 'nullable', path: ['output', 'finalLogitSoftcapping'], message: 'output.finalLogitSoftcapping must be explicitly set' },
|
|
104
|
+
{ kind: 'nullable', path: ['output', 'embeddingVocabSize'], message: 'output.embeddingVocabSize must be explicitly set' },
|
|
105
|
+
{ kind: 'nonNullable', path: ['layerPattern', 'type'], message: 'layerPattern.type is required' },
|
|
106
|
+
{ kind: 'nullable', path: ['layerPattern', 'globalPattern'], message: 'layerPattern.globalPattern must be explicitly set' },
|
|
107
|
+
{ kind: 'nullable', path: ['layerPattern', 'period'], message: 'layerPattern.period must be explicitly set' },
|
|
108
|
+
{ kind: 'nullable', path: ['layerPattern', 'offset'], message: 'layerPattern.offset must be explicitly set' },
|
|
109
|
+
{ kind: 'nullable', path: ['chatTemplate', 'type'], message: 'chatTemplate.type must be explicitly set' },
|
|
110
|
+
{ kind: 'nonNullable', path: ['chatTemplate', 'enabled'], message: 'chatTemplate.enabled is required' },
|
|
111
|
+
]);
|
|
112
|
+
|
|
113
|
+
export function buildRequiredInferenceFieldsContractArtifact() {
|
|
114
|
+
const errors = [];
|
|
115
|
+
const checks = [];
|
|
116
|
+
const baseInference = createValidInferenceFixture();
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
validateRequiredInferenceFields(cloneJson(baseInference), 'required-fields-contract');
|
|
120
|
+
checks.push({ id: 'requiredInferenceFields.validFixture', ok: true });
|
|
121
|
+
} catch (error) {
|
|
122
|
+
errors.push(error instanceof Error ? error.message : String(error));
|
|
123
|
+
checks.push({ id: 'requiredInferenceFields.validFixture', ok: false });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for (const field of FIELD_CASES) {
|
|
127
|
+
const missingInference = cloneJson(baseInference);
|
|
128
|
+
if (field.kind === 'nonNullable') {
|
|
129
|
+
setPath(missingInference, field.path, null);
|
|
130
|
+
} else {
|
|
131
|
+
deletePath(missingInference, field.path);
|
|
132
|
+
}
|
|
133
|
+
let rejectsAsExpected = false;
|
|
134
|
+
try {
|
|
135
|
+
validateRequiredInferenceFields(missingInference, 'required-fields-contract');
|
|
136
|
+
} catch (error) {
|
|
137
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
138
|
+
rejectsAsExpected = message.includes(field.message);
|
|
139
|
+
}
|
|
140
|
+
if (!rejectsAsExpected) {
|
|
141
|
+
errors.push(
|
|
142
|
+
`[RequiredInferenceFieldsContract] ${field.path.join('.')} did not produce the expected required-field failure.`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
checks.push({
|
|
146
|
+
id: `requiredInferenceFields.${field.path.join('.')}.rejectsInvalid`,
|
|
147
|
+
ok: rejectsAsExpected,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
if (field.kind === 'nullable') {
|
|
151
|
+
const nullableInference = cloneJson(baseInference);
|
|
152
|
+
setPath(nullableInference, field.path, null);
|
|
153
|
+
let nullableAccepted = true;
|
|
154
|
+
try {
|
|
155
|
+
validateRequiredInferenceFields(nullableInference, 'required-fields-contract');
|
|
156
|
+
} catch {
|
|
157
|
+
nullableAccepted = false;
|
|
158
|
+
}
|
|
159
|
+
if (!nullableAccepted) {
|
|
160
|
+
errors.push(
|
|
161
|
+
`[RequiredInferenceFieldsContract] ${field.path.join('.')} should allow explicit null but was rejected.`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
checks.push({
|
|
165
|
+
id: `requiredInferenceFields.${field.path.join('.')}.acceptsNull`,
|
|
166
|
+
ok: nullableAccepted,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const customInference = cloneJson(baseInference);
|
|
172
|
+
customInference.layerPattern.type = 'custom';
|
|
173
|
+
delete customInference.layerPattern.layerTypes;
|
|
174
|
+
let customLayerTypesRejected = false;
|
|
175
|
+
try {
|
|
176
|
+
validateRequiredInferenceFields(customInference, 'required-fields-contract');
|
|
177
|
+
} catch (error) {
|
|
178
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
179
|
+
customLayerTypesRejected = message.includes('layerPattern.layerTypes must be explicitly set for custom patterns');
|
|
180
|
+
}
|
|
181
|
+
if (!customLayerTypesRejected) {
|
|
182
|
+
errors.push('[RequiredInferenceFieldsContract] custom layerPattern without layerTypes was not rejected.');
|
|
183
|
+
}
|
|
184
|
+
checks.push({
|
|
185
|
+
id: 'requiredInferenceFields.layerPattern.layerTypes.rejectsMissingForCustom',
|
|
186
|
+
ok: customLayerTypesRejected,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
schemaVersion: 1,
|
|
191
|
+
source: 'doppler',
|
|
192
|
+
ok: errors.length === 0,
|
|
193
|
+
checks,
|
|
194
|
+
errors,
|
|
195
|
+
stats: {
|
|
196
|
+
fieldCases: FIELD_CASES.length,
|
|
197
|
+
nullableCases: FIELD_CASES.filter((field) => field.kind === 'nullable').length,
|
|
198
|
+
nonNullableCases: FIELD_CASES.filter((field) => field.kind === 'nonNullable').length,
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function buildManifestRequiredInferenceFieldsArtifact(inference, label = 'manifest.inference') {
|
|
204
|
+
const errors = [];
|
|
205
|
+
const checks = [];
|
|
206
|
+
let ok = true;
|
|
207
|
+
try {
|
|
208
|
+
validateRequiredInferenceFields(cloneJson(inference), label);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
ok = false;
|
|
211
|
+
errors.push(error instanceof Error ? error.message : String(error));
|
|
212
|
+
}
|
|
213
|
+
checks.push({
|
|
214
|
+
id: `${label}.requiredInferenceFields`,
|
|
215
|
+
ok,
|
|
216
|
+
});
|
|
217
|
+
return {
|
|
218
|
+
schemaVersion: 1,
|
|
219
|
+
source: 'doppler',
|
|
220
|
+
scope: 'manifest',
|
|
221
|
+
label,
|
|
222
|
+
ok,
|
|
223
|
+
checks,
|
|
224
|
+
errors,
|
|
225
|
+
stats: {
|
|
226
|
+
fieldCases: FIELD_CASES.length,
|
|
227
|
+
nullableCases: FIELD_CASES.filter((field) => field.kind === 'nullable').length,
|
|
228
|
+
nonNullableCases: FIELD_CASES.filter((field) => field.kind === 'nonNullable').length,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface BrowserSuiteMetricsSchema {
|
|
2
|
+
schemaVersion: 1;
|
|
3
|
+
source: 'doppler';
|
|
4
|
+
suite: string;
|
|
5
|
+
executionContractArtifact: Record<string, unknown> | null;
|
|
6
|
+
executionV0GraphContractArtifact: Record<string, unknown> | null;
|
|
7
|
+
layerPatternContractArtifact: Record<string, unknown> | null;
|
|
8
|
+
requiredInferenceFieldsArtifact: Record<string, unknown> | null;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export declare const BROWSER_SUITE_METRICS_SCHEMA_VERSION: 1;
|
|
13
|
+
export declare const DEFAULT_BROWSER_SUITE_METRICS: Readonly<BrowserSuiteMetricsSchema>;
|
|
14
|
+
|
|
15
|
+
export declare function validateBrowserSuiteMetrics(
|
|
16
|
+
metrics: Record<string, unknown>
|
|
17
|
+
): BrowserSuiteMetricsSchema;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
function assertPlainObject(value, label) {
|
|
2
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
3
|
+
throw new Error(`browser suite metrics: ${label} must be an object.`);
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function assertString(value, label) {
|
|
8
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
9
|
+
throw new Error(`browser suite metrics: ${label} must be a non-empty string.`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function assertNullablePlainObject(value, label) {
|
|
14
|
+
if (value == null) return;
|
|
15
|
+
assertPlainObject(value, label);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const BROWSER_SUITE_METRICS_SCHEMA_VERSION = 1;
|
|
19
|
+
|
|
20
|
+
export const DEFAULT_BROWSER_SUITE_METRICS = Object.freeze({
|
|
21
|
+
schemaVersion: BROWSER_SUITE_METRICS_SCHEMA_VERSION,
|
|
22
|
+
source: 'doppler',
|
|
23
|
+
suite: 'inference',
|
|
24
|
+
executionContractArtifact: null,
|
|
25
|
+
executionV0GraphContractArtifact: null,
|
|
26
|
+
layerPatternContractArtifact: null,
|
|
27
|
+
requiredInferenceFieldsArtifact: null,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export function validateBrowserSuiteMetrics(metrics) {
|
|
31
|
+
assertPlainObject(metrics, 'metrics');
|
|
32
|
+
if (metrics.schemaVersion !== BROWSER_SUITE_METRICS_SCHEMA_VERSION) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`browser suite metrics: schemaVersion must be ${BROWSER_SUITE_METRICS_SCHEMA_VERSION}.`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
if (metrics.source !== 'doppler') {
|
|
38
|
+
throw new Error('browser suite metrics: source must be "doppler".');
|
|
39
|
+
}
|
|
40
|
+
assertString(metrics.suite, 'suite');
|
|
41
|
+
assertNullablePlainObject(metrics.executionContractArtifact, 'executionContractArtifact');
|
|
42
|
+
assertNullablePlainObject(metrics.executionV0GraphContractArtifact, 'executionV0GraphContractArtifact');
|
|
43
|
+
assertNullablePlainObject(metrics.layerPatternContractArtifact, 'layerPatternContractArtifact');
|
|
44
|
+
assertNullablePlainObject(metrics.requiredInferenceFieldsArtifact, 'requiredInferenceFieldsArtifact');
|
|
45
|
+
return metrics;
|
|
46
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface ConversionReportResultSchema {
|
|
2
|
+
presetId: string | null;
|
|
3
|
+
modelType: string | null;
|
|
4
|
+
outputDir: string | null;
|
|
5
|
+
shardCount: number | null;
|
|
6
|
+
tensorCount: number | null;
|
|
7
|
+
totalSize: number | null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ConversionReportManifestSchema {
|
|
11
|
+
quantization: string | null;
|
|
12
|
+
quantizationInfo: Record<string, unknown> | null;
|
|
13
|
+
inference: {
|
|
14
|
+
presetId: string | null;
|
|
15
|
+
schema: string | null;
|
|
16
|
+
defaultKernelPath: string | null;
|
|
17
|
+
} | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ConversionReportSchema {
|
|
21
|
+
schemaVersion: 1;
|
|
22
|
+
suite: 'convert';
|
|
23
|
+
command: 'convert';
|
|
24
|
+
modelId: string;
|
|
25
|
+
timestamp: string;
|
|
26
|
+
source: 'doppler';
|
|
27
|
+
result: ConversionReportResultSchema;
|
|
28
|
+
manifest: ConversionReportManifestSchema | null;
|
|
29
|
+
executionContractArtifact: Record<string, unknown> | null;
|
|
30
|
+
executionV0GraphContractArtifact: Record<string, unknown> | null;
|
|
31
|
+
layerPatternContractArtifact: Record<string, unknown> | null;
|
|
32
|
+
requiredInferenceFieldsArtifact: Record<string, unknown> | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export declare const CONVERSION_REPORT_SCHEMA_VERSION: 1;
|
|
36
|
+
export declare const DEFAULT_CONVERSION_REPORT: ConversionReportSchema;
|
|
37
|
+
|
|
38
|
+
export declare function validateConversionReport(
|
|
39
|
+
report: Record<string, unknown>
|
|
40
|
+
): ConversionReportSchema;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
function assertPlainObject(value, label) {
|
|
2
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
3
|
+
throw new Error(`conversion report: ${label} must be an object.`);
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function assertString(value, label) {
|
|
8
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
9
|
+
throw new Error(`conversion report: ${label} must be a non-empty string.`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function assertNullableString(value, label) {
|
|
14
|
+
if (value === null || value === undefined) return;
|
|
15
|
+
assertString(value, label);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function assertNullableFiniteNumber(value, label) {
|
|
19
|
+
if (value === null || value === undefined) return;
|
|
20
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
21
|
+
throw new Error(`conversion report: ${label} must be a finite number when provided.`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function assertNullablePlainObject(value, label) {
|
|
26
|
+
if (value === null || value === undefined) return;
|
|
27
|
+
assertPlainObject(value, label);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const CONVERSION_REPORT_SCHEMA_VERSION = 1;
|
|
31
|
+
|
|
32
|
+
export const DEFAULT_CONVERSION_REPORT = Object.freeze({
|
|
33
|
+
schemaVersion: CONVERSION_REPORT_SCHEMA_VERSION,
|
|
34
|
+
suite: 'convert',
|
|
35
|
+
command: 'convert',
|
|
36
|
+
modelId: 'unknown',
|
|
37
|
+
timestamp: '1970-01-01T00:00:00.000Z',
|
|
38
|
+
source: 'doppler',
|
|
39
|
+
result: {
|
|
40
|
+
presetId: null,
|
|
41
|
+
modelType: null,
|
|
42
|
+
outputDir: null,
|
|
43
|
+
shardCount: null,
|
|
44
|
+
tensorCount: null,
|
|
45
|
+
totalSize: null,
|
|
46
|
+
},
|
|
47
|
+
manifest: {
|
|
48
|
+
quantization: null,
|
|
49
|
+
quantizationInfo: null,
|
|
50
|
+
inference: {
|
|
51
|
+
presetId: null,
|
|
52
|
+
schema: null,
|
|
53
|
+
defaultKernelPath: null,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
executionContractArtifact: null,
|
|
57
|
+
executionV0GraphContractArtifact: null,
|
|
58
|
+
layerPatternContractArtifact: null,
|
|
59
|
+
requiredInferenceFieldsArtifact: null,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export function validateConversionReport(report) {
|
|
63
|
+
assertPlainObject(report, 'report');
|
|
64
|
+
if (report.schemaVersion !== CONVERSION_REPORT_SCHEMA_VERSION) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`conversion report: schemaVersion must be ${CONVERSION_REPORT_SCHEMA_VERSION}.`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (report.suite !== 'convert') {
|
|
70
|
+
throw new Error('conversion report: suite must be "convert".');
|
|
71
|
+
}
|
|
72
|
+
if (report.command !== 'convert') {
|
|
73
|
+
throw new Error('conversion report: command must be "convert".');
|
|
74
|
+
}
|
|
75
|
+
if (report.source !== 'doppler') {
|
|
76
|
+
throw new Error('conversion report: source must be "doppler".');
|
|
77
|
+
}
|
|
78
|
+
assertString(report.modelId, 'modelId');
|
|
79
|
+
assertString(report.timestamp, 'timestamp');
|
|
80
|
+
assertPlainObject(report.result, 'result');
|
|
81
|
+
assertNullableString(report.result.presetId, 'result.presetId');
|
|
82
|
+
assertNullableString(report.result.modelType, 'result.modelType');
|
|
83
|
+
assertNullableString(report.result.outputDir, 'result.outputDir');
|
|
84
|
+
assertNullableFiniteNumber(report.result.shardCount, 'result.shardCount');
|
|
85
|
+
assertNullableFiniteNumber(report.result.tensorCount, 'result.tensorCount');
|
|
86
|
+
assertNullableFiniteNumber(report.result.totalSize, 'result.totalSize');
|
|
87
|
+
|
|
88
|
+
assertNullablePlainObject(report.manifest, 'manifest');
|
|
89
|
+
if (report.manifest) {
|
|
90
|
+
assertNullableString(report.manifest.quantization, 'manifest.quantization');
|
|
91
|
+
assertNullablePlainObject(report.manifest.quantizationInfo, 'manifest.quantizationInfo');
|
|
92
|
+
assertNullablePlainObject(report.manifest.inference, 'manifest.inference');
|
|
93
|
+
if (report.manifest.inference) {
|
|
94
|
+
assertNullableString(report.manifest.inference.presetId, 'manifest.inference.presetId');
|
|
95
|
+
assertNullableString(report.manifest.inference.schema, 'manifest.inference.schema');
|
|
96
|
+
assertNullableString(
|
|
97
|
+
report.manifest.inference.defaultKernelPath,
|
|
98
|
+
'manifest.inference.defaultKernelPath'
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
assertNullablePlainObject(report.executionContractArtifact, 'executionContractArtifact');
|
|
104
|
+
assertNullablePlainObject(report.executionV0GraphContractArtifact, 'executionV0GraphContractArtifact');
|
|
105
|
+
assertNullablePlainObject(report.layerPatternContractArtifact, 'layerPatternContractArtifact');
|
|
106
|
+
assertNullablePlainObject(report.requiredInferenceFieldsArtifact, 'requiredInferenceFieldsArtifact');
|
|
107
|
+
return report;
|
|
108
|
+
}
|
|
@@ -3,6 +3,13 @@ import { DEFAULT_INFERENCE_DEFAULTS_CONFIG } from './inference-defaults.schema.j
|
|
|
3
3
|
import { DEFAULT_SHARED_RUNTIME_CONFIG } from './shared-runtime.schema.js';
|
|
4
4
|
import { DEFAULT_EMULATION_CONFIG, createEmulationConfig } from './emulation.schema.js';
|
|
5
5
|
import { mergeEcosystemConfig } from './ecosystem.schema.js';
|
|
6
|
+
import {
|
|
7
|
+
chooseNullish,
|
|
8
|
+
mergeExecutionPatchLists,
|
|
9
|
+
mergeKernelPathPolicy,
|
|
10
|
+
mergeShallowObject,
|
|
11
|
+
replaceSubtree,
|
|
12
|
+
} from '../merge-helpers.js';
|
|
6
13
|
|
|
7
14
|
// =============================================================================
|
|
8
15
|
// Runtime Config (all non-model-specific settings)
|
|
@@ -172,8 +179,6 @@ function mergeInferenceConfig(
|
|
|
172
179
|
const overrideExecutionPatch = overrides.executionPatch ?? {};
|
|
173
180
|
const baseKernelPathPolicy = base.kernelPathPolicy ?? {};
|
|
174
181
|
const overrideKernelPathPolicy = overrides.kernelPathPolicy ?? {};
|
|
175
|
-
const baseKernelPathSourceScope = baseKernelPathPolicy.sourceScope ?? baseKernelPathPolicy.allowSources;
|
|
176
|
-
const overrideKernelPathSourceScope = overrideKernelPathPolicy.sourceScope ?? overrideKernelPathPolicy.allowSources;
|
|
177
182
|
const hasRuntimeKernelProfiles = Object.prototype.hasOwnProperty.call(
|
|
178
183
|
overrideSessionCompute,
|
|
179
184
|
'kernelProfiles'
|
|
@@ -236,15 +241,8 @@ function mergeInferenceConfig(
|
|
|
236
241
|
pipeline: overrides.pipeline ?? base.pipeline,
|
|
237
242
|
kernelPath: overrides.kernelPath ?? base.kernelPath,
|
|
238
243
|
kernelPathSource: overrides.kernelPathSource ?? base.kernelPathSource,
|
|
239
|
-
kernelPathPolicy:
|
|
240
|
-
|
|
241
|
-
sourceScope: overrideKernelPathSourceScope ?? baseKernelPathSourceScope,
|
|
242
|
-
allowSources: overrideKernelPathSourceScope ?? baseKernelPathSourceScope,
|
|
243
|
-
onIncompatible: overrideKernelPathPolicy.onIncompatible ?? baseKernelPathPolicy.onIncompatible,
|
|
244
|
-
},
|
|
245
|
-
chatTemplate: overrides.chatTemplate
|
|
246
|
-
? { ...base.chatTemplate, ...overrides.chatTemplate }
|
|
247
|
-
: base.chatTemplate,
|
|
244
|
+
kernelPathPolicy: mergeKernelPathPolicy(baseKernelPathPolicy, overrideKernelPathPolicy),
|
|
245
|
+
chatTemplate: mergeShallowObject(base.chatTemplate, overrides.chatTemplate),
|
|
248
246
|
session: {
|
|
249
247
|
...baseSession,
|
|
250
248
|
...overrideSession,
|
|
@@ -259,14 +257,10 @@ function mergeInferenceConfig(
|
|
|
259
257
|
? { kernelProfiles: overrideSessionCompute.kernelProfiles }
|
|
260
258
|
: { kernelProfiles: baseSessionCompute.kernelProfiles }),
|
|
261
259
|
},
|
|
262
|
-
kvcache: overrideSession.kvcache
|
|
263
|
-
decodeLoop: overrideSession.decodeLoop
|
|
264
|
-
},
|
|
265
|
-
executionPatch: {
|
|
266
|
-
set: overrideExecutionPatch.set ?? baseExecutionPatch.set ?? [],
|
|
267
|
-
remove: overrideExecutionPatch.remove ?? baseExecutionPatch.remove ?? [],
|
|
268
|
-
add: overrideExecutionPatch.add ?? baseExecutionPatch.add ?? [],
|
|
260
|
+
kvcache: replaceSubtree(overrideSession.kvcache, baseSession.kvcache),
|
|
261
|
+
decodeLoop: replaceSubtree(overrideSession.decodeLoop, baseSession.decodeLoop),
|
|
269
262
|
},
|
|
263
|
+
executionPatch: mergeExecutionPatchLists(baseExecutionPatch, overrideExecutionPatch),
|
|
270
264
|
// Model-specific inference overrides (merged with manifest.inference at load time)
|
|
271
265
|
modelOverrides: overrides.modelOverrides ?? base.modelOverrides,
|
|
272
266
|
};
|
|
@@ -225,6 +225,28 @@ export {
|
|
|
225
225
|
type ConversionIOSchema,
|
|
226
226
|
} from './conversion.schema.js';
|
|
227
227
|
|
|
228
|
+
// =============================================================================
|
|
229
|
+
// Browser Suite Metrics Schema
|
|
230
|
+
// =============================================================================
|
|
231
|
+
export {
|
|
232
|
+
type BrowserSuiteMetricsSchema,
|
|
233
|
+
BROWSER_SUITE_METRICS_SCHEMA_VERSION,
|
|
234
|
+
DEFAULT_BROWSER_SUITE_METRICS,
|
|
235
|
+
validateBrowserSuiteMetrics,
|
|
236
|
+
} from './browser-suite-metrics.schema.js';
|
|
237
|
+
|
|
238
|
+
// =============================================================================
|
|
239
|
+
// Conversion Report Schema
|
|
240
|
+
// =============================================================================
|
|
241
|
+
export {
|
|
242
|
+
type ConversionReportResultSchema,
|
|
243
|
+
type ConversionReportManifestSchema,
|
|
244
|
+
type ConversionReportSchema,
|
|
245
|
+
CONVERSION_REPORT_SCHEMA_VERSION,
|
|
246
|
+
DEFAULT_CONVERSION_REPORT,
|
|
247
|
+
validateConversionReport,
|
|
248
|
+
} from './conversion-report.schema.js';
|
|
249
|
+
|
|
228
250
|
// =============================================================================
|
|
229
251
|
// Converter Schema
|
|
230
252
|
// =============================================================================
|
|
@@ -55,6 +55,24 @@ export {
|
|
|
55
55
|
ConversionStage,
|
|
56
56
|
} from './conversion.schema.js';
|
|
57
57
|
|
|
58
|
+
// =============================================================================
|
|
59
|
+
// Browser Suite Metrics Schema
|
|
60
|
+
// =============================================================================
|
|
61
|
+
export {
|
|
62
|
+
BROWSER_SUITE_METRICS_SCHEMA_VERSION,
|
|
63
|
+
DEFAULT_BROWSER_SUITE_METRICS,
|
|
64
|
+
validateBrowserSuiteMetrics,
|
|
65
|
+
} from './browser-suite-metrics.schema.js';
|
|
66
|
+
|
|
67
|
+
// =============================================================================
|
|
68
|
+
// Conversion Report Schema
|
|
69
|
+
// =============================================================================
|
|
70
|
+
export {
|
|
71
|
+
CONVERSION_REPORT_SCHEMA_VERSION,
|
|
72
|
+
DEFAULT_CONVERSION_REPORT,
|
|
73
|
+
validateConversionReport,
|
|
74
|
+
} from './conversion-report.schema.js';
|
|
75
|
+
|
|
58
76
|
// =============================================================================
|
|
59
77
|
// Converter Schema
|
|
60
78
|
// =============================================================================
|
package/src/converter/core.d.ts
CHANGED
|
@@ -27,6 +27,12 @@ import type {
|
|
|
27
27
|
MoEConfigSchema,
|
|
28
28
|
ConversionInfoSchema,
|
|
29
29
|
} from '../config/schema/index.js';
|
|
30
|
+
import type { ExecutionContractArtifact } from '../config/execution-contract-check.js';
|
|
31
|
+
import type { ExecutionV0GraphContractArtifact } from '../config/execution-v0-graph-contract-check.js';
|
|
32
|
+
import type {
|
|
33
|
+
ManifestRequiredInferenceFieldsArtifact,
|
|
34
|
+
RequiredInferenceFieldsContractArtifact,
|
|
35
|
+
} from '../config/required-inference-fields-contract-check.js';
|
|
30
36
|
|
|
31
37
|
export { generateShardFilename } from '../formats/rdrr/index.js';
|
|
32
38
|
|
|
@@ -144,6 +150,10 @@ export interface ConvertResult {
|
|
|
144
150
|
shardCount: number;
|
|
145
151
|
tensorCount: number;
|
|
146
152
|
totalSize: number;
|
|
153
|
+
executionContractArtifact: ExecutionContractArtifact | null;
|
|
154
|
+
executionV0GraphContractArtifact: ExecutionV0GraphContractArtifact | null;
|
|
155
|
+
layerPatternContractArtifact: Record<string, unknown> | null;
|
|
156
|
+
requiredInferenceFieldsArtifact: ManifestRequiredInferenceFieldsArtifact | RequiredInferenceFieldsContractArtifact | null;
|
|
147
157
|
}
|
|
148
158
|
|
|
149
159
|
/** @deprecated Use ConversionIOSchema from config/schema */
|
package/src/converter/core.js
CHANGED
|
@@ -9,15 +9,20 @@ import {
|
|
|
9
9
|
formatBytes,
|
|
10
10
|
} from '../config/schema/index.js';
|
|
11
11
|
|
|
12
|
-
import { classifyTensorRole, generateShardFilename } from '../formats/rdrr/index.js';
|
|
12
|
+
import { classifyTensor, classifyTensorRole, generateShardFilename } from '../formats/rdrr/index.js';
|
|
13
13
|
import { log } from '../debug/index.js';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
getInferenceLayerPatternContractArtifact,
|
|
16
|
+
selectRuleValue,
|
|
17
|
+
} from '../rules/rule-registry.js';
|
|
15
18
|
import {
|
|
16
19
|
createConverterConfig,
|
|
17
20
|
detectPreset,
|
|
18
21
|
listPresets,
|
|
19
22
|
resolvePreset,
|
|
20
23
|
} from '../config/index.js';
|
|
24
|
+
import { buildExecutionContractArtifact } from '../config/execution-contract-check.js';
|
|
25
|
+
import { buildManifestRequiredInferenceFieldsArtifact } from '../config/required-inference-fields-contract-check.js';
|
|
21
26
|
import { buildManifestInference, inferEmbeddingOutputConfig } from './manifest-inference.js';
|
|
22
27
|
import { resolveEosTokenId } from './tokenizer-utils.js';
|
|
23
28
|
import {
|
|
@@ -1128,6 +1133,7 @@ export async function convertModel(model, io, options = {}) {
|
|
|
1128
1133
|
}
|
|
1129
1134
|
const totalTensors = tensors.length;
|
|
1130
1135
|
const targetQuant = String(options.quantization ?? model.quantization ?? '').trim().toLowerCase();
|
|
1136
|
+
const tensorGroupModelType = String(options.modelType ?? model.modelType ?? 'transformer');
|
|
1131
1137
|
const q4kLayout = normalizeQ4KLayout(options.quantizationInfo?.layout);
|
|
1132
1138
|
const quantizeEmbeddings = resolveQuantizeEmbeddings(
|
|
1133
1139
|
options.quantizationInfo ?? null,
|
|
@@ -1251,6 +1257,7 @@ export async function convertModel(model, io, options = {}) {
|
|
|
1251
1257
|
|
|
1252
1258
|
// Record tensor location
|
|
1253
1259
|
const role = classifyTensorRole(tensor.name);
|
|
1260
|
+
const group = classifyTensor(tensor.name, tensorGroupModelType);
|
|
1254
1261
|
|
|
1255
1262
|
if (tensorSpans.length === 1) {
|
|
1256
1263
|
tensorLocations[tensor.name] = {
|
|
@@ -1260,6 +1267,7 @@ export async function convertModel(model, io, options = {}) {
|
|
|
1260
1267
|
shape: tensor.shape,
|
|
1261
1268
|
dtype: outDtype,
|
|
1262
1269
|
role,
|
|
1270
|
+
group,
|
|
1263
1271
|
...(outLayout ? { layout: outLayout } : {}),
|
|
1264
1272
|
};
|
|
1265
1273
|
} else {
|
|
@@ -1269,6 +1277,7 @@ export async function convertModel(model, io, options = {}) {
|
|
|
1269
1277
|
shape: tensor.shape,
|
|
1270
1278
|
dtype: outDtype,
|
|
1271
1279
|
role,
|
|
1280
|
+
group,
|
|
1272
1281
|
...(outLayout ? { layout: outLayout } : {}),
|
|
1273
1282
|
};
|
|
1274
1283
|
}
|
|
@@ -1327,11 +1336,27 @@ export async function convertModel(model, io, options = {}) {
|
|
|
1327
1336
|
totalSize: formatBytes(totalSize),
|
|
1328
1337
|
});
|
|
1329
1338
|
|
|
1339
|
+
const executionContractArtifact = buildExecutionContractArtifact(manifest);
|
|
1340
|
+
const layerPatternContractArtifact = getInferenceLayerPatternContractArtifact();
|
|
1341
|
+
const requiredInferenceFieldsArtifact = manifest?.modelType === 'transformer'
|
|
1342
|
+
&& manifest?.inference
|
|
1343
|
+
&& typeof manifest.inference === 'object'
|
|
1344
|
+
&& manifest.inference.attention
|
|
1345
|
+
&& typeof manifest.inference.attention === 'object'
|
|
1346
|
+
? buildManifestRequiredInferenceFieldsArtifact(
|
|
1347
|
+
manifest?.inference ?? null,
|
|
1348
|
+
`${manifest?.modelId ?? modelId}.inference`
|
|
1349
|
+
)
|
|
1350
|
+
: null;
|
|
1330
1351
|
return {
|
|
1331
1352
|
manifest,
|
|
1332
1353
|
shardCount: shards.length,
|
|
1333
1354
|
tensorCount: tensors.length,
|
|
1334
1355
|
totalSize,
|
|
1356
|
+
executionContractArtifact,
|
|
1357
|
+
executionV0GraphContractArtifact: executionContractArtifact?.executionV0?.graph ?? null,
|
|
1358
|
+
layerPatternContractArtifact,
|
|
1359
|
+
requiredInferenceFieldsArtifact,
|
|
1335
1360
|
};
|
|
1336
1361
|
}
|
|
1337
1362
|
|