@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.
- package/README.md +26 -10
- package/package.json +30 -6
- 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 +39 -27
- package/src/config/kernels/registry.json +598 -2
- package/src/config/loader.js +81 -48
- 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 +21 -6
- package/src/config/presets/models/janus-text.json +2 -0
- package/src/config/presets/models/qwen3.json +9 -2
- package/src/config/presets/models/transformer.json +5 -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 +237 -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/config/schema/inference-defaults.schema.js +3 -0
- package/src/config/schema/inference.schema.d.ts +9 -0
- package/src/config/schema/kernel-path.schema.d.ts +6 -0
- package/src/config/schema/manifest.schema.d.ts +6 -0
- package/src/config/schema/manifest.schema.js +3 -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/converter/rope-config.js +42 -0
- package/src/gpu/device.js +58 -0
- package/src/gpu/kernels/attention.js +98 -0
- package/src/gpu/kernels/bias_add.wgsl +8 -6
- package/src/gpu/kernels/bias_add_f16.wgsl +8 -5
- package/src/gpu/kernels/conv2d.js +1 -1
- package/src/gpu/kernels/conv2d.wgsl +7 -8
- package/src/gpu/kernels/conv2d_f16.wgsl +7 -8
- package/src/gpu/kernels/depthwise_conv2d.d.ts +29 -0
- package/src/gpu/kernels/depthwise_conv2d.js +99 -0
- package/src/gpu/kernels/depthwise_conv2d.wgsl +55 -0
- package/src/gpu/kernels/depthwise_conv2d_f16.wgsl +59 -0
- package/src/gpu/kernels/grouped_pointwise_conv2d.d.ts +27 -0
- package/src/gpu/kernels/grouped_pointwise_conv2d.js +93 -0
- package/src/gpu/kernels/grouped_pointwise_conv2d.wgsl +44 -0
- package/src/gpu/kernels/grouped_pointwise_conv2d_f16.wgsl +48 -0
- package/src/gpu/kernels/index.d.ts +30 -0
- package/src/gpu/kernels/index.js +25 -0
- package/src/gpu/kernels/matmul.js +25 -0
- package/src/gpu/kernels/pixel_shuffle.js +1 -1
- package/src/gpu/kernels/pixel_shuffle.wgsl +4 -5
- package/src/gpu/kernels/pixel_shuffle_f16.wgsl +4 -5
- package/src/gpu/kernels/relu.d.ts +18 -0
- package/src/gpu/kernels/relu.js +58 -0
- package/src/gpu/kernels/relu.wgsl +22 -0
- package/src/gpu/kernels/relu_f16.wgsl +24 -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 +28 -0
- package/src/gpu/kernels/repeat_channels_f16.wgsl +30 -0
- package/src/gpu/kernels/residual.js +44 -8
- package/src/gpu/kernels/residual.wgsl +6 -3
- package/src/gpu/kernels/residual_f16.wgsl +2 -1
- package/src/gpu/kernels/residual_f16_vec4.wgsl +2 -1
- package/src/gpu/kernels/residual_vec4.wgsl +2 -1
- package/src/gpu/kernels/rmsnorm.js +58 -6
- package/src/gpu/kernels/rmsnorm.wgsl +14 -6
- package/src/gpu/kernels/rmsnorm_f16.wgsl +10 -2
- package/src/gpu/kernels/rope.d.ts +2 -0
- package/src/gpu/kernels/rope.js +11 -1
- package/src/gpu/kernels/rope.wgsl +56 -40
- package/src/gpu/kernels/sana_linear_attention.d.ts +27 -0
- package/src/gpu/kernels/sana_linear_attention.js +121 -0
- package/src/gpu/kernels/sana_linear_attention_apply.wgsl +43 -0
- package/src/gpu/kernels/sana_linear_attention_apply_f16.wgsl +46 -0
- package/src/gpu/kernels/sana_linear_attention_summary.wgsl +51 -0
- package/src/gpu/kernels/sana_linear_attention_summary_f16.wgsl +53 -0
- package/src/gpu/kernels/silu.d.ts +1 -0
- package/src/gpu/kernels/silu.js +32 -14
- package/src/gpu/kernels/silu.wgsl +19 -9
- package/src/gpu/kernels/silu_f16.wgsl +19 -9
- package/src/gpu/kernels/transpose.js +15 -2
- package/src/gpu/kernels/transpose.wgsl +5 -6
- package/src/gpu/kernels/upsample2d.js +2 -1
- package/src/gpu/kernels/upsample2d.wgsl +6 -9
- package/src/gpu/kernels/upsample2d_f16.wgsl +6 -9
- package/src/gpu/kernels/utils.js +16 -1
- 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 +109 -23
- package/src/inference/pipelines/diffusion/init.js +14 -0
- package/src/inference/pipelines/diffusion/pipeline.js +215 -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 +11 -4
- package/src/inference/pipelines/diffusion/text-encoder-gpu.js +282 -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/attention/record.js +11 -2
- package/src/inference/pipelines/text/attention/run.js +11 -2
- package/src/inference/pipelines/text/chat-format.js +25 -1
- package/src/inference/pipelines/text/config.d.ts +9 -0
- package/src/inference/pipelines/text/config.js +69 -2
- package/src/inference/pipelines/text/execution-plan.js +23 -31
- package/src/inference/pipelines/text/execution-v0.js +43 -95
- package/src/inference/pipelines/text/ffn/standard.js +3 -0
- package/src/inference/pipelines/text/init.d.ts +4 -0
- package/src/inference/pipelines/text/init.js +56 -9
- package/src/inference/pipelines/text/layer.js +11 -0
- package/src/inference/pipelines/text.js +4 -0
- package/src/inference/tokenizers/bundled.js +156 -33
- 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/rules/tooling/command-runtime.rules.json +18 -0
- package/src/tooling/command-api.d.ts +27 -1
- package/src/tooling/command-api.js +142 -3
- 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-browser-command-runner.d.ts +4 -0
- package/src/tooling/node-browser-command-runner.js +58 -3
- package/src/tooling/node-command-runner.js +15 -0
- package/src/tooling/node-convert.d.ts +10 -0
- package/src/tooling/node-converter.js +59 -0
- package/src/tooling/node-webgpu.js +11 -89
- package/src/training/checkpoint-watch.d.ts +7 -0
- package/src/training/checkpoint-watch.js +106 -0
- package/src/training/checkpoint.d.ts +6 -1
- package/src/training/checkpoint.js +12 -2
- package/src/training/distillation/artifacts.d.ts +71 -0
- package/src/training/distillation/artifacts.js +132 -0
- package/src/training/distillation/checkpoint-watch.d.ts +10 -0
- package/src/training/distillation/checkpoint-watch.js +57 -0
- package/src/training/distillation/dataset.d.ts +59 -0
- package/src/training/distillation/dataset.js +337 -0
- package/src/training/distillation/eval.d.ts +34 -0
- package/src/training/distillation/eval.js +310 -0
- package/src/training/distillation/index.d.ts +29 -0
- package/src/training/distillation/index.js +29 -0
- package/src/training/distillation/runtime.d.ts +20 -0
- package/src/training/distillation/runtime.js +121 -0
- package/src/training/distillation/scoreboard.d.ts +6 -0
- package/src/training/distillation/scoreboard.js +8 -0
- package/src/training/distillation/stage-a.d.ts +45 -0
- package/src/training/distillation/stage-a.js +338 -0
- package/src/training/distillation/stage-b.d.ts +24 -0
- package/src/training/distillation/stage-b.js +20 -0
- package/src/training/index.d.ts +10 -0
- package/src/training/index.js +10 -0
- package/src/training/lora-pipeline.d.ts +40 -0
- package/src/training/lora-pipeline.js +796 -0
- package/src/training/operator-artifacts.d.ts +62 -0
- package/src/training/operator-artifacts.js +140 -0
- package/src/training/operator-command.d.ts +5 -0
- package/src/training/operator-command.js +453 -0
- package/src/training/operator-eval.d.ts +48 -0
- package/src/training/operator-eval.js +230 -0
- package/src/training/operator-scoreboard.d.ts +5 -0
- package/src/training/operator-scoreboard.js +44 -0
- package/src/training/runner.d.ts +52 -0
- package/src/training/runner.js +29 -4
- package/src/training/suite.d.ts +112 -0
- package/src/training/suite.js +9 -9
- package/src/training/workloads.d.ts +164 -0
- package/src/training/workloads.js +539 -0
- 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 +252 -41
package/src/version.js
ADDED
|
@@ -126,6 +126,51 @@ function normalizeExecutionConfig(rawExecution) {
|
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
function printConvertContractSummary(result) {
|
|
130
|
+
const artifact = result?.executionContractArtifact;
|
|
131
|
+
if (!artifact || typeof artifact !== 'object') return;
|
|
132
|
+
const checks = Array.isArray(artifact.checks) ? artifact.checks : [];
|
|
133
|
+
const passedChecks = checks.filter((entry) => entry?.ok === true).length;
|
|
134
|
+
const layout = artifact.session?.layout ?? 'n/a';
|
|
135
|
+
console.log(
|
|
136
|
+
`[contract] status=${artifact.ok === true ? 'pass' : 'fail'} ` +
|
|
137
|
+
`checks=${checks.length > 0 ? `${passedChecks}/${checks.length}` : 'n/a'} layout=${layout}`
|
|
138
|
+
);
|
|
139
|
+
if (artifact.ok !== true && Array.isArray(artifact.errors)) {
|
|
140
|
+
for (const error of artifact.errors.slice(0, 3)) {
|
|
141
|
+
console.log(`[contract] error=${String(error)}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const graphArtifact = result?.executionV0GraphContractArtifact;
|
|
145
|
+
if (graphArtifact && typeof graphArtifact === 'object') {
|
|
146
|
+
const checks = Array.isArray(graphArtifact.checks) ? graphArtifact.checks : [];
|
|
147
|
+
const passedChecks = checks.filter((entry) => entry?.ok === true).length;
|
|
148
|
+
console.log(
|
|
149
|
+
`[graph] status=${graphArtifact.ok === true ? 'pass' : 'fail'} ` +
|
|
150
|
+
`checks=${checks.length > 0 ? `${passedChecks}/${checks.length}` : 'n/a'}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
for (const [label, extraArtifact] of [
|
|
154
|
+
['layer-pattern', result?.layerPatternContractArtifact],
|
|
155
|
+
['required-inference', result?.requiredInferenceFieldsArtifact],
|
|
156
|
+
]) {
|
|
157
|
+
if (!extraArtifact || typeof extraArtifact !== 'object') continue;
|
|
158
|
+
const checks = Array.isArray(extraArtifact.checks) ? extraArtifact.checks : [];
|
|
159
|
+
const passedChecks = checks.filter((entry) => entry?.ok === true).length;
|
|
160
|
+
console.log(
|
|
161
|
+
`[${label}] status=${extraArtifact.ok === true ? 'pass' : 'fail'} ` +
|
|
162
|
+
`checks=${checks.length > 0 ? `${passedChecks}/${checks.length}` : 'n/a'}`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function printConvertReportSummary(result) {
|
|
168
|
+
const reportInfo = result?.reportInfo;
|
|
169
|
+
if (!reportInfo || typeof reportInfo !== 'object') return;
|
|
170
|
+
if (typeof reportInfo.path !== 'string' || reportInfo.path.length === 0) return;
|
|
171
|
+
console.log(`[report] ${reportInfo.path}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
129
174
|
async function readJsonFile(filePath) {
|
|
130
175
|
if (!filePath) return null;
|
|
131
176
|
const raw = await fs.readFile(filePath, 'utf8');
|
|
@@ -172,6 +217,8 @@ async function main() {
|
|
|
172
217
|
console.log(
|
|
173
218
|
`[done] modelId=${result.manifest?.modelId ?? 'unknown'} preset=${result.presetId} modelType=${result.modelType} shards=${result.shardCount} tensors=${result.tensorCount}`
|
|
174
219
|
);
|
|
220
|
+
printConvertContractSummary(result);
|
|
221
|
+
printConvertReportSummary(result);
|
|
175
222
|
}
|
|
176
223
|
|
|
177
224
|
main().catch((err) => {
|
package/tools/doppler-cli.js
CHANGED
|
@@ -66,6 +66,8 @@ function usage() {
|
|
|
66
66
|
' doppler debug --config <path.json|json> [--runtime-config <path|url|json>] [--surface auto|node|browser]',
|
|
67
67
|
' doppler bench --config <path.json|json> [--runtime-config <path|url|json>] [--surface auto|node|browser]',
|
|
68
68
|
' doppler verify --config <path.json|json> [--runtime-config <path|url|json>] [--surface auto|node|browser]',
|
|
69
|
+
' doppler lora --config <path.json|json> [--surface auto|node]',
|
|
70
|
+
' doppler distill --config <path.json|json> [--surface auto|node]',
|
|
69
71
|
'',
|
|
70
72
|
'Flags:',
|
|
71
73
|
' --config <path|json> Required command config payload (file path or JSON object string).',
|
|
@@ -337,7 +339,89 @@ function resolveStaticRootDir(browserOptions = {}) {
|
|
|
337
339
|
return process.cwd();
|
|
338
340
|
}
|
|
339
341
|
|
|
340
|
-
|
|
342
|
+
function resolveRdrrRoot(options = {}) {
|
|
343
|
+
return path.resolve(asStringOrNull(options.rdrrRoot) || DEFAULT_EXTERNAL_RDRR_ROOT);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
async function findResolvableModelCandidate(candidates) {
|
|
347
|
+
const discoveredManifestCandidates = [];
|
|
348
|
+
|
|
349
|
+
for (const candidate of candidates) {
|
|
350
|
+
if (!await pathExists(candidate.manifestPath)) {
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
discoveredManifestCandidates.push(candidate);
|
|
354
|
+
|
|
355
|
+
const modelDir = path.dirname(candidate.manifestPath);
|
|
356
|
+
try {
|
|
357
|
+
const files = await fs.readdir(modelDir, { withFileTypes: true });
|
|
358
|
+
const hasShards = files.some((entry) =>
|
|
359
|
+
entry.isFile() && /^shard_\d+\.bin$/u.test(entry.name)
|
|
360
|
+
);
|
|
361
|
+
if (hasShards) {
|
|
362
|
+
return { candidate, discoveredManifestCandidates };
|
|
363
|
+
}
|
|
364
|
+
} catch {
|
|
365
|
+
return { candidate, discoveredManifestCandidates };
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return { candidate: null, discoveredManifestCandidates };
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async function resolveExternalModelDirectory(rdrrRoot, modelId) {
|
|
373
|
+
const directModelDir = path.join(rdrrRoot, modelId);
|
|
374
|
+
const directManifestPath = path.join(directModelDir, 'manifest.json');
|
|
375
|
+
if (await pathExists(directManifestPath)) {
|
|
376
|
+
return {
|
|
377
|
+
modelDir: directModelDir,
|
|
378
|
+
manifestPath: directManifestPath,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
let entries = [];
|
|
383
|
+
try {
|
|
384
|
+
entries = await fs.readdir(rdrrRoot, { withFileTypes: true });
|
|
385
|
+
} catch {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const matches = [];
|
|
390
|
+
for (const entry of entries) {
|
|
391
|
+
if (!entry.isDirectory()) {
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
const manifestPath = path.join(rdrrRoot, entry.name, 'manifest.json');
|
|
395
|
+
if (!await pathExists(manifestPath)) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
let manifest = null;
|
|
399
|
+
try {
|
|
400
|
+
manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
|
|
401
|
+
} catch {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
if (manifest?.modelId !== modelId) {
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
matches.push({
|
|
408
|
+
modelDir: path.join(rdrrRoot, entry.name),
|
|
409
|
+
manifestPath,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (matches.length > 1) {
|
|
414
|
+
const matchPaths = matches.map((match) => match.modelDir).join(', ');
|
|
415
|
+
throw new Error(
|
|
416
|
+
`Model "${modelId}" matched multiple external directories. ` +
|
|
417
|
+
`Disambiguate by setting request.modelUrl in --config. Matches: ${matchPaths}`
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return matches[0] || null;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export async function resolveBrowserModelUrl(request, browserOptions = {}) {
|
|
341
425
|
if (request.modelUrl || !request.modelId) {
|
|
342
426
|
return request;
|
|
343
427
|
}
|
|
@@ -353,49 +437,32 @@ async function resolveBrowserModelUrl(request, browserOptions = {}) {
|
|
|
353
437
|
}
|
|
354
438
|
|
|
355
439
|
const staticRootDir = resolveStaticRootDir(browserOptions);
|
|
356
|
-
const
|
|
440
|
+
const externalModel = await resolveExternalModelDirectory(resolveRdrrRoot(browserOptions), modelId);
|
|
441
|
+
const candidates = [
|
|
442
|
+
{
|
|
357
443
|
modelUrl: `/models/curated/${encodedModelId}`,
|
|
358
444
|
manifestPath: path.join(staticRootDir, 'models', 'curated', modelId, 'manifest.json'),
|
|
359
|
-
|
|
360
|
-
|
|
445
|
+
},
|
|
446
|
+
{
|
|
361
447
|
modelUrl: `/models/local/${encodedModelId}`,
|
|
362
448
|
manifestPath: path.join(staticRootDir, 'models', 'local', modelId, 'manifest.json'),
|
|
363
|
-
|
|
364
|
-
|
|
449
|
+
},
|
|
450
|
+
{
|
|
365
451
|
modelUrl: `/models/${encodedModelId}`,
|
|
366
452
|
manifestPath: path.join(staticRootDir, 'models', modelId, 'manifest.json'),
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
modelUrl: `/models/external/${encodeURIComponent(path.basename(externalModel?.modelDir || modelId))}`,
|
|
456
|
+
manifestPath: externalModel?.manifestPath || path.join(resolveRdrrRoot(browserOptions), modelId, 'manifest.json'),
|
|
457
|
+
},
|
|
372
458
|
];
|
|
373
|
-
const discoveredManifestCandidates = [];
|
|
374
459
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const modelDir = path.dirname(candidate.manifestPath);
|
|
382
|
-
try {
|
|
383
|
-
const files = await fs.readdir(modelDir, { withFileTypes: true });
|
|
384
|
-
const hasShards = files.some((entry) =>
|
|
385
|
-
entry.isFile() && /^shard_\d+\.bin$/u.test(entry.name)
|
|
386
|
-
);
|
|
387
|
-
if (hasShards) {
|
|
388
|
-
return {
|
|
389
|
-
...request,
|
|
390
|
-
modelUrl: candidate.modelUrl,
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
} catch {
|
|
394
|
-
return {
|
|
395
|
-
...request,
|
|
396
|
-
modelUrl: candidate.modelUrl,
|
|
397
|
-
};
|
|
398
|
-
}
|
|
460
|
+
const { candidate, discoveredManifestCandidates } = await findResolvableModelCandidate(candidates);
|
|
461
|
+
if (candidate) {
|
|
462
|
+
return {
|
|
463
|
+
...request,
|
|
464
|
+
modelUrl: candidate.modelUrl,
|
|
465
|
+
};
|
|
399
466
|
}
|
|
400
467
|
|
|
401
468
|
if (discoveredManifestCandidates.length > 0) {
|
|
@@ -421,13 +488,13 @@ export async function resolveNodeModelUrl(request, options = {}) {
|
|
|
421
488
|
}
|
|
422
489
|
|
|
423
490
|
const modelId = String(request.modelId);
|
|
424
|
-
const rdrrRoot =
|
|
425
|
-
const
|
|
426
|
-
if (!
|
|
491
|
+
const rdrrRoot = resolveRdrrRoot(options);
|
|
492
|
+
const externalModel = await resolveExternalModelDirectory(rdrrRoot, modelId);
|
|
493
|
+
if (!externalModel) {
|
|
427
494
|
return request;
|
|
428
495
|
}
|
|
429
496
|
|
|
430
|
-
const modelDir =
|
|
497
|
+
const modelDir = externalModel.modelDir;
|
|
431
498
|
try {
|
|
432
499
|
const files = await fs.readdir(modelDir, { withFileTypes: true });
|
|
433
500
|
const hasShards = files.some((entry) =>
|
|
@@ -593,10 +660,18 @@ function buildBrowserRunOptions(runConfig, jsonOutput, request = {}) {
|
|
|
593
660
|
executablePath: asStringOrNull(browser.executablePath),
|
|
594
661
|
runnerPath: asStringOrNull(browser.runnerPath),
|
|
595
662
|
staticRootDir: asStringOrNull(browser.staticRootDir),
|
|
663
|
+
rdrrRoot: asStringOrNull(browser.rdrrRoot),
|
|
596
664
|
baseUrl: asStringOrNull(browser.baseUrl),
|
|
597
665
|
browserArgs: parseBrowserArgs(browser.browserArgs),
|
|
598
666
|
headless: headed ? false : (explicitHeadless ?? true),
|
|
599
667
|
};
|
|
668
|
+
const rdrrRoot = resolveRdrrRoot(options);
|
|
669
|
+
options.staticMounts = [
|
|
670
|
+
{
|
|
671
|
+
urlPrefix: '/models/external',
|
|
672
|
+
rootDir: rdrrRoot,
|
|
673
|
+
},
|
|
674
|
+
];
|
|
600
675
|
|
|
601
676
|
const port = parseNumberFlag(browser.port, 'run.browser.port');
|
|
602
677
|
if (port !== null) {
|
|
@@ -644,6 +719,7 @@ function isNodeWebGPUFallbackCandidate(error, fallbackPolicy = DEFAULT_CLI_POLIC
|
|
|
644
719
|
function isTrainingCommandFlow(request) {
|
|
645
720
|
if (!request || typeof request !== 'object') return false;
|
|
646
721
|
if (request.suite === 'training') return true;
|
|
722
|
+
if (request.command === 'lora' || request.command === 'distill') return true;
|
|
647
723
|
return request.command === 'bench' && request.workloadType === 'training';
|
|
648
724
|
}
|
|
649
725
|
|
|
@@ -713,7 +789,24 @@ function toSummary(result) {
|
|
|
713
789
|
}
|
|
714
790
|
|
|
715
791
|
if (result.manifest?.modelId) {
|
|
716
|
-
|
|
792
|
+
const contractStatus = result.executionContractArtifact?.ok === true
|
|
793
|
+
? ' contract=pass'
|
|
794
|
+
: result.executionContractArtifact
|
|
795
|
+
? ' contract=fail'
|
|
796
|
+
: '';
|
|
797
|
+
const graphStatus = result.executionV0GraphContractArtifact?.ok === true
|
|
798
|
+
? ' graph=pass'
|
|
799
|
+
: result.executionV0GraphContractArtifact
|
|
800
|
+
? ' graph=fail'
|
|
801
|
+
: '';
|
|
802
|
+
return `converted ${result.manifest.modelId} (${result.tensorCount} tensors, ${result.shardCount} shards)${contractStatus}${graphStatus}`;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
if (result.kind === 'lora' || result.kind === 'distill') {
|
|
806
|
+
const workloadId = result.workloadId || 'unknown';
|
|
807
|
+
const action = result.action || 'run';
|
|
808
|
+
const runRoot = result.runRoot || 'n/a';
|
|
809
|
+
return `${result.kind} ${action} workload=${workloadId} runRoot=${runRoot}`;
|
|
717
810
|
}
|
|
718
811
|
|
|
719
812
|
const suite = result.suite || result.report?.suite || 'suite';
|
|
@@ -1014,8 +1107,118 @@ function printMemoryReport(result) {
|
|
|
1014
1107
|
console.log(`[memory] ${parts.join(' ')}`);
|
|
1015
1108
|
}
|
|
1016
1109
|
|
|
1110
|
+
function printExecutionContractSummary(result) {
|
|
1111
|
+
const artifact = result?.metrics?.executionContractArtifact;
|
|
1112
|
+
if (!artifact || typeof artifact !== 'object') return;
|
|
1113
|
+
const checks = Array.isArray(artifact.checks) ? artifact.checks : [];
|
|
1114
|
+
const passedChecks = checks.filter((entry) => entry?.ok === true).length;
|
|
1115
|
+
const session = artifact.session && typeof artifact.session === 'object'
|
|
1116
|
+
? artifact.session
|
|
1117
|
+
: null;
|
|
1118
|
+
const attentionPhases = artifact.steps?.attentionPhases && typeof artifact.steps.attentionPhases === 'object'
|
|
1119
|
+
? artifact.steps.attentionPhases
|
|
1120
|
+
: null;
|
|
1121
|
+
const parts = [
|
|
1122
|
+
`status=${artifact.ok === true ? 'pass' : 'fail'}`,
|
|
1123
|
+
checks.length > 0 ? `checks=${passedChecks}/${checks.length}` : 'checks=n/a',
|
|
1124
|
+
];
|
|
1125
|
+
if (session?.layout) {
|
|
1126
|
+
parts.push(`layout=${session.layout}`);
|
|
1127
|
+
}
|
|
1128
|
+
if (attentionPhases) {
|
|
1129
|
+
parts.push(
|
|
1130
|
+
`attn(prefill=${attentionPhases.prefill ?? 'n/a'},decode=${attentionPhases.decode ?? 'n/a'},both=${attentionPhases.both ?? 'n/a'})`
|
|
1131
|
+
);
|
|
1132
|
+
}
|
|
1133
|
+
console.log(`[contract] ${parts.join(' ')}`);
|
|
1134
|
+
if (artifact.ok !== true && Array.isArray(artifact.errors)) {
|
|
1135
|
+
for (const error of artifact.errors.slice(0, 3)) {
|
|
1136
|
+
console.log(`[contract] error=${quoteOneLine(error)}`);
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
function printExecutionV0GraphSummary(artifact) {
|
|
1142
|
+
if (!artifact || typeof artifact !== 'object') return;
|
|
1143
|
+
const checks = Array.isArray(artifact.checks) ? artifact.checks : [];
|
|
1144
|
+
const passedChecks = checks.filter((entry) => entry?.ok === true).length;
|
|
1145
|
+
const stats = artifact.stats && typeof artifact.stats === 'object' ? artifact.stats : null;
|
|
1146
|
+
const parts = [
|
|
1147
|
+
`status=${artifact.ok === true ? 'pass' : 'fail'}`,
|
|
1148
|
+
checks.length > 0 ? `checks=${passedChecks}/${checks.length}` : 'checks=n/a',
|
|
1149
|
+
];
|
|
1150
|
+
if (Number.isFinite(stats?.prefillSteps) || Number.isFinite(stats?.decodeSteps)) {
|
|
1151
|
+
parts.push(`steps(prefill=${stats?.prefillSteps ?? 'n/a'},decode=${stats?.decodeSteps ?? 'n/a'})`);
|
|
1152
|
+
}
|
|
1153
|
+
console.log(`[graph] ${parts.join(' ')}`);
|
|
1154
|
+
if (artifact.ok !== true && Array.isArray(artifact.errors)) {
|
|
1155
|
+
for (const error of artifact.errors.slice(0, 3)) {
|
|
1156
|
+
console.log(`[graph] error=${quoteOneLine(error)}`);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
function printSimpleArtifactSummary(label, artifact) {
|
|
1162
|
+
if (!artifact || typeof artifact !== 'object') return;
|
|
1163
|
+
const checks = Array.isArray(artifact.checks) ? artifact.checks : [];
|
|
1164
|
+
const passedChecks = checks.filter((entry) => entry?.ok === true).length;
|
|
1165
|
+
console.log(
|
|
1166
|
+
`[${label}] status=${artifact.ok === true ? 'pass' : 'fail'} ` +
|
|
1167
|
+
`checks=${checks.length > 0 ? `${passedChecks}/${checks.length}` : 'n/a'}`
|
|
1168
|
+
);
|
|
1169
|
+
if (artifact.ok !== true && Array.isArray(artifact.errors)) {
|
|
1170
|
+
for (const error of artifact.errors.slice(0, 2)) {
|
|
1171
|
+
console.log(`[${label}] error=${quoteOneLine(error)}`);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
function printConvertContractSummary(result) {
|
|
1177
|
+
const artifact = result?.executionContractArtifact;
|
|
1178
|
+
if (!artifact || typeof artifact !== 'object') return;
|
|
1179
|
+
const checks = Array.isArray(artifact.checks) ? artifact.checks : [];
|
|
1180
|
+
const passedChecks = checks.filter((entry) => entry?.ok === true).length;
|
|
1181
|
+
const session = artifact.session && typeof artifact.session === 'object'
|
|
1182
|
+
? artifact.session
|
|
1183
|
+
: null;
|
|
1184
|
+
console.log(
|
|
1185
|
+
`[contract] status=${artifact.ok === true ? 'pass' : 'fail'} ` +
|
|
1186
|
+
`checks=${checks.length > 0 ? `${passedChecks}/${checks.length}` : 'n/a'} ` +
|
|
1187
|
+
`layout=${session?.layout ?? 'n/a'}`
|
|
1188
|
+
);
|
|
1189
|
+
if (artifact.ok !== true && Array.isArray(artifact.errors)) {
|
|
1190
|
+
for (const error of artifact.errors.slice(0, 3)) {
|
|
1191
|
+
console.log(`[contract] error=${quoteOneLine(error)}`);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
printExecutionV0GraphSummary(result?.executionV0GraphContractArtifact);
|
|
1195
|
+
printSimpleArtifactSummary('layer-pattern', result?.layerPatternContractArtifact);
|
|
1196
|
+
printSimpleArtifactSummary('required-inference', result?.requiredInferenceFieldsArtifact);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
function printConvertReportSummary(result) {
|
|
1200
|
+
const reportInfo = result?.reportInfo;
|
|
1201
|
+
if (!reportInfo || typeof reportInfo !== 'object') return;
|
|
1202
|
+
if (typeof reportInfo.path !== 'string' || reportInfo.path.length === 0) return;
|
|
1203
|
+
console.log(`[report] ${reportInfo.path}`);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1017
1206
|
function printMetricsSummary(result) {
|
|
1018
1207
|
if (!result || typeof result !== 'object') return;
|
|
1208
|
+
if (result.kind === 'distill') {
|
|
1209
|
+
const stageCount = Array.isArray(result.stageResults) ? result.stageResults.length : 0;
|
|
1210
|
+
console.log(
|
|
1211
|
+
`[metrics] kind=distill action=${result.action || 'run'} stages=${stageCount} runRoot=${quoteOneLine(result.runRoot)}`
|
|
1212
|
+
);
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
if (result.kind === 'lora') {
|
|
1216
|
+
const exportCount = Array.isArray(result.exports) ? result.exports.length : 0;
|
|
1217
|
+
console.log(
|
|
1218
|
+
`[metrics] kind=lora action=${result.action || 'run'} exports=${exportCount} runRoot=${quoteOneLine(result.runRoot)}`
|
|
1219
|
+
);
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1019
1222
|
const suite = String(result.suite || '');
|
|
1020
1223
|
const metrics = result.metrics;
|
|
1021
1224
|
if (!metrics || typeof metrics !== 'object') return;
|
|
@@ -1038,6 +1241,8 @@ function printMetricsSummary(result) {
|
|
|
1038
1241
|
`prefill=${formatNumber(metrics.prefillTokensPerSec)} ` +
|
|
1039
1242
|
`decode=${formatNumber(metrics.decodeTokensPerSec)}`
|
|
1040
1243
|
);
|
|
1244
|
+
printExecutionContractSummary(result);
|
|
1245
|
+
printExecutionV0GraphSummary(metrics.executionV0GraphContractArtifact);
|
|
1041
1246
|
return;
|
|
1042
1247
|
}
|
|
1043
1248
|
|
|
@@ -1052,6 +1257,8 @@ function printMetricsSummary(result) {
|
|
|
1052
1257
|
`median=${formatMs(metrics.medianEmbeddingMs)} avg=${formatMs(metrics.avgEmbeddingMs)} ` +
|
|
1053
1258
|
`eps=${formatNumber(metrics.avgEmbeddingsPerSec)}`
|
|
1054
1259
|
);
|
|
1260
|
+
printExecutionContractSummary(result);
|
|
1261
|
+
printExecutionV0GraphSummary(metrics.executionV0GraphContractArtifact);
|
|
1055
1262
|
return;
|
|
1056
1263
|
}
|
|
1057
1264
|
|
|
@@ -1073,6 +1280,8 @@ function printMetricsSummary(result) {
|
|
|
1073
1280
|
`[metrics] latency first=${formatMs(metrics.firstTokenMs)} ` +
|
|
1074
1281
|
`prefill=${formatMs(metrics.prefillMs)} decode=${formatMs(metrics.decodeMs)}`
|
|
1075
1282
|
);
|
|
1283
|
+
printExecutionContractSummary(result);
|
|
1284
|
+
printExecutionV0GraphSummary(metrics.executionV0GraphContractArtifact);
|
|
1076
1285
|
printDeviceInfo(result);
|
|
1077
1286
|
printGpuPhases(metrics);
|
|
1078
1287
|
printMemoryReport(result);
|
|
@@ -1190,6 +1399,8 @@ async function main() {
|
|
|
1190
1399
|
}
|
|
1191
1400
|
|
|
1192
1401
|
console.log(`[ok] ${toSummary(response.result)}`);
|
|
1402
|
+
printConvertContractSummary(response.result);
|
|
1403
|
+
printConvertReportSummary(response.result);
|
|
1193
1404
|
printMetricsSummary(response.result);
|
|
1194
1405
|
} catch (error) {
|
|
1195
1406
|
if (jsonOutputRequested) {
|