@simulatte/doppler 0.1.6 → 0.1.8
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/CHANGELOG.md +145 -0
- package/README.md +16 -23
- package/package.json +30 -32
- package/src/adapters/adapter-registry.js +12 -1
- package/src/adapters/lora-loader.js +23 -6
- package/src/bridge/extension-client.d.ts +5 -0
- package/src/bridge/extension-client.js +40 -0
- package/src/bridge/index.d.ts +2 -1
- package/src/bridge/index.js +6 -4
- package/src/browser/browser-converter.js +31 -1
- package/src/browser/file-picker.js +6 -0
- package/src/browser/safetensors-parser-browser.js +84 -1
- package/src/browser/shard-io-browser.js +2 -2
- package/src/browser/tensor-source-download.js +8 -2
- package/src/browser/tensor-source-http.d.ts +1 -0
- package/src/browser/tensor-source-http.js +5 -1
- package/src/client/doppler-api.browser.js +20 -4
- package/src/client/doppler-api.js +19 -3
- package/src/client/doppler-provider/generation.js +12 -0
- package/src/client/doppler-provider/model-manager.d.ts +10 -0
- package/src/client/doppler-provider/model-manager.js +91 -19
- package/src/client/doppler-provider/source-runtime.d.ts +2 -1
- package/src/client/doppler-provider/source-runtime.js +132 -13
- package/src/client/doppler-registry.json +5 -20
- package/src/config/backward-registry-loader.js +17 -2
- package/src/config/execution-v0-contract-check.js +113 -15
- package/src/config/kernel-path-contract-check.js +57 -29
- package/src/config/kernel-path-loader.d.ts +5 -0
- package/src/config/kernel-path-loader.js +18 -36
- package/src/config/kernels/kernel-ref-digests.js +1 -1
- package/src/config/kernels/registry.js +14 -1
- package/src/config/kernels/registry.json +81 -5
- package/src/config/loader.d.ts +1 -1
- package/src/config/loader.js +15 -2
- package/src/config/merge-contract-check.js +66 -4
- package/src/config/merge-helpers.js +128 -7
- package/src/config/merge.d.ts +1 -0
- package/src/config/merge.js +10 -0
- package/src/config/param-validator.js +47 -2
- package/src/config/presets/kernel-paths/{gemma2-q4k-dequant-f32a.json → gemma2-q4k-dequant-f32a-nosubgroups.json} +3 -3
- package/src/config/presets/kernel-paths/gemma3-f16-fused-f32a-online-streamingprefill.json +223 -0
- package/src/config/presets/kernel-paths/{gemma3-q4k-dequant-f32a.json → gemma3-q4k-dequant-f32a-nosubgroups.json} +3 -3
- package/src/config/presets/kernel-paths/gemma3-q4k-dequant-f32w-f32a-online.json +56 -0
- package/src/config/presets/kernel-paths/lfm2-q4k-dequant-f32a-nosubgroups.json +61 -0
- package/src/config/presets/kernel-paths/registry.json +43 -8
- package/src/config/presets/models/gemma2.json +3 -2
- package/src/config/presets/models/gemma3.json +2 -0
- package/src/config/presets/models/qwen3.json +4 -3
- package/src/config/presets/models/qwen3_5.json +16 -0
- package/src/config/presets/runtime/experiments/bench/gemma3-bench-q4k.json +1 -1
- package/src/config/presets/runtime/experiments/debug/gemma3-debug-q4k.json +1 -1
- package/src/config/presets/runtime/experiments/verify/gemma3-verify.json +1 -1
- package/src/config/presets/runtime/kernels/dequant-f16-q4k.json +6 -13
- package/src/config/presets/runtime/kernels/dequant-f32-q4k.json +6 -13
- package/src/config/presets/runtime/kernels/embeddinggemma-q4k-dequant-f32a.json +37 -0
- package/src/config/presets/runtime/kernels/fused-q4k.json +6 -13
- package/src/config/presets/runtime/kernels/gemma2-q4k-dequant-f16a.json +33 -0
- package/src/config/presets/runtime/kernels/gemma2-q4k-dequant-f32a-nosubgroups.json +33 -0
- package/src/config/presets/runtime/kernels/gemma2-q4k-fused-f32a.json +33 -0
- package/src/config/presets/runtime/kernels/safe-q4k.json +6 -13
- package/src/config/presets/runtime/model/qwen3-5-layer-probe.json +52 -0
- package/src/config/presets/runtime/model/qwen3-5-linear-attn-debug.json +90 -0
- package/src/config/presets/runtime/platform/metal-apple-q4k.json +1 -1
- package/src/config/runtime.js +6 -1
- package/src/config/schema/conversion.schema.d.ts +1 -0
- package/src/config/schema/debug.schema.d.ts +5 -0
- package/src/config/schema/doppler.schema.js +16 -21
- package/src/config/schema/inference-defaults.schema.js +3 -3
- package/src/config/schema/kernel-path.schema.d.ts +5 -1
- package/src/config/schema/kernel-thresholds.schema.js +12 -4
- package/src/config/schema/manifest.schema.d.ts +3 -2
- package/src/config/schema/manifest.schema.js +17 -4
- package/src/config/schema/storage.schema.js +1 -1
- package/src/config/training-defaults.js +30 -22
- package/src/converter/conversion-plan.js +104 -11
- package/src/converter/core.d.ts +7 -0
- package/src/converter/core.js +16 -9
- package/src/converter/execution-v0-manifest.js +4 -1
- package/src/converter/index.d.ts +1 -0
- package/src/converter/index.js +1 -0
- package/src/converter/manifest-inference.js +50 -29
- package/src/converter/parsers/diffusion.js +0 -3
- package/src/converter/parsers/transformer.js +4 -0
- package/src/converter/quantization-info.js +40 -16
- package/src/converter/quantizer.js +19 -12
- package/src/converter/rope-config.js +8 -6
- package/src/converter/shard-packer.d.ts +1 -1
- package/src/converter/shard-packer.js +4 -1
- package/src/converter/tokenizer-utils.d.ts +1 -0
- package/src/converter/tokenizer-utils.js +4 -1
- package/src/debug/config.js +123 -11
- package/src/debug/reference/hf_qwen35_linear_attn_debug.py +268 -0
- package/src/debug/signals.js +7 -1
- package/src/debug/tensor.d.ts +2 -0
- package/src/debug/tensor.js +13 -2
- package/src/distribution/p2p-control-plane.js +52 -12
- package/src/distribution/p2p-observability.js +43 -7
- package/src/distribution/p2p-webrtc-browser.js +20 -0
- package/src/distribution/shard-delivery.js +83 -27
- package/src/formats/gguf/types.js +33 -16
- package/src/formats/rdrr/groups.d.ts +12 -4
- package/src/formats/rdrr/groups.js +3 -6
- package/src/formats/rdrr/parsing.d.ts +4 -0
- package/src/formats/rdrr/parsing.js +53 -3
- package/src/formats/rdrr/types.d.ts +2 -1
- package/src/gpu/command-recorder.js +86 -61
- package/src/gpu/device.d.ts +1 -0
- package/src/gpu/device.js +73 -19
- package/src/gpu/kernel-tuner/benchmarks.js +326 -316
- package/src/gpu/kernel-tuner/cache.js +71 -4
- package/src/gpu/kernel-tuner/tuner.js +22 -4
- package/src/gpu/kernels/attention.js +15 -34
- package/src/gpu/kernels/backward/adam.js +62 -58
- package/src/gpu/kernels/backward/attention_backward.js +257 -169
- package/src/gpu/kernels/backward/conv2d_backward.js +14 -1
- package/src/gpu/kernels/cast.js +191 -149
- package/src/gpu/kernels/check-stop.js +33 -44
- package/src/gpu/kernels/conv2d.js +27 -17
- package/src/gpu/kernels/cross_entropy_loss.js +21 -15
- package/src/gpu/kernels/depthwise_conv2d.js +36 -26
- package/src/gpu/kernels/dequant.js +178 -126
- package/src/gpu/kernels/energy.d.ts +3 -21
- package/src/gpu/kernels/energy.js +111 -88
- package/src/gpu/kernels/feature-check.js +1 -1
- package/src/gpu/kernels/fused_ffn.js +84 -65
- package/src/gpu/kernels/fused_matmul_residual.js +56 -33
- package/src/gpu/kernels/fused_matmul_rmsnorm.js +62 -45
- package/src/gpu/kernels/gather.js +33 -15
- package/src/gpu/kernels/gelu.js +19 -11
- package/src/gpu/kernels/grouped_pointwise_conv2d.js +33 -23
- package/src/gpu/kernels/groupnorm.js +34 -23
- package/src/gpu/kernels/index.d.ts +8 -0
- package/src/gpu/kernels/index.js +6 -0
- package/src/gpu/kernels/kv-quantize.js +5 -2
- package/src/gpu/kernels/layernorm.js +35 -19
- package/src/gpu/kernels/logit-merge.js +5 -3
- package/src/gpu/kernels/matmul-selection.js +47 -4
- package/src/gpu/kernels/matmul.d.ts +2 -0
- package/src/gpu/kernels/matmul.js +59 -40
- package/src/gpu/kernels/modulate.js +23 -15
- package/src/gpu/kernels/moe.js +221 -175
- package/src/gpu/kernels/pixel_shuffle.js +22 -14
- package/src/gpu/kernels/relu.js +18 -10
- package/src/gpu/kernels/repeat_channels.js +25 -17
- package/src/gpu/kernels/residual.js +37 -27
- package/src/gpu/kernels/rmsnorm.js +66 -43
- package/src/gpu/kernels/rope.js +3 -0
- package/src/gpu/kernels/sample.js +27 -38
- package/src/gpu/kernels/sana_linear_attention.js +18 -10
- package/src/gpu/kernels/scale.js +18 -11
- package/src/gpu/kernels/shader-cache.js +4 -2
- package/src/gpu/kernels/silu.js +120 -72
- package/src/gpu/kernels/softmax.js +44 -25
- package/src/gpu/kernels/split_qg.d.ts +50 -0
- package/src/gpu/kernels/split_qg.js +46 -0
- package/src/gpu/kernels/split_qg.wgsl +58 -0
- package/src/gpu/kernels/split_qg_f16.wgsl +62 -0
- package/src/gpu/kernels/split_qkv.js +23 -13
- package/src/gpu/kernels/transpose.js +18 -10
- package/src/gpu/kernels/transpose.wgsl +5 -3
- package/src/gpu/kernels/upsample2d.js +21 -13
- package/src/gpu/kernels/utils.js +20 -13
- package/src/gpu/partitioned-buffer-pool.js +10 -2
- package/src/gpu/perf-guards.js +2 -9
- package/src/gpu/profiler.js +27 -22
- package/src/gpu/readback-utils.d.ts +16 -0
- package/src/gpu/readback-utils.js +41 -0
- package/src/gpu/submit-tracker.js +13 -0
- package/src/gpu/uniform-cache.d.ts +1 -0
- package/src/gpu/uniform-cache.js +30 -9
- package/src/gpu/weight-buffer.d.ts +1 -1
- package/src/gpu/weight-buffer.js +1 -1
- package/src/hotswap/intent-bundle.js +6 -0
- package/src/hotswap/manifest.d.ts +10 -1
- package/src/hotswap/manifest.js +12 -2
- package/src/hotswap/runtime.js +30 -8
- package/src/index-browser.d.ts +44 -0
- package/src/index-browser.js +14 -0
- package/src/inference/browser-harness-contract-helpers.d.ts +5 -0
- package/src/inference/browser-harness-contract-helpers.js +28 -0
- package/src/inference/browser-harness-diffusion-energy-suites.d.ts +2 -0
- package/src/inference/browser-harness-diffusion-energy-suites.js +269 -0
- package/src/inference/browser-harness-model-helpers.d.ts +16 -0
- package/src/inference/browser-harness-model-helpers.js +217 -0
- package/src/inference/browser-harness-report-helpers.d.ts +7 -0
- package/src/inference/browser-harness-report-helpers.js +42 -0
- package/src/inference/browser-harness-runtime-helpers.d.ts +61 -0
- package/src/inference/browser-harness-runtime-helpers.js +415 -0
- package/src/inference/browser-harness-suite-helpers.d.ts +28 -0
- package/src/inference/browser-harness-suite-helpers.js +268 -0
- package/src/inference/browser-harness-text-helpers.d.ts +27 -0
- package/src/inference/browser-harness-text-helpers.js +788 -0
- package/src/inference/browser-harness.d.ts +8 -0
- package/src/inference/browser-harness.js +149 -1996
- package/src/inference/kv-cache/base.js +140 -94
- package/src/inference/kv-cache/tiered.js +5 -3
- package/src/inference/moe-router.js +88 -56
- package/src/inference/multi-model-network.js +5 -3
- package/src/inference/network-evolution.d.ts +11 -2
- package/src/inference/network-evolution.js +20 -21
- package/src/inference/pipelines/context.d.ts +3 -0
- package/src/inference/pipelines/context.js +142 -2
- package/src/inference/pipelines/diffusion/helpers.js +10 -2
- package/src/inference/pipelines/diffusion/pipeline.js +2 -1
- package/src/inference/pipelines/diffusion/sd3-transformer.js +10 -10
- package/src/inference/pipelines/diffusion/text-encoder-gpu.js +8 -2
- package/src/inference/pipelines/diffusion/vae.js +3 -7
- package/src/inference/pipelines/energy/pipeline.js +27 -21
- package/src/inference/pipelines/energy/quintel.d.ts +5 -0
- package/src/inference/pipelines/energy/quintel.js +11 -0
- package/src/inference/pipelines/energy-head/row-head-pipeline.js +17 -13
- package/src/inference/pipelines/structured/json-head-pipeline.js +26 -11
- package/src/inference/pipelines/text/attention/output-projection.d.ts +12 -0
- package/src/inference/pipelines/text/attention/output-projection.js +8 -0
- package/src/inference/pipelines/text/attention/projections.d.ts +10 -1
- package/src/inference/pipelines/text/attention/projections.js +192 -112
- package/src/inference/pipelines/text/attention/record.js +77 -14
- package/src/inference/pipelines/text/attention/run.js +112 -14
- package/src/inference/pipelines/text/config.js +17 -4
- package/src/inference/pipelines/text/embed.js +2 -8
- package/src/inference/pipelines/text/execution-plan.js +46 -23
- package/src/inference/pipelines/text/execution-v0-contract-helpers.d.ts +59 -0
- package/src/inference/pipelines/text/execution-v0-contract-helpers.js +937 -0
- package/src/inference/pipelines/text/execution-v0-runtime-builders.d.ts +15 -0
- package/src/inference/pipelines/text/execution-v0-runtime-builders.js +279 -0
- package/src/inference/pipelines/text/execution-v0.js +62 -1013
- package/src/inference/pipelines/text/generator-runtime.js +5 -0
- package/src/inference/pipelines/text/generator-steps.d.ts +52 -0
- package/src/inference/pipelines/text/generator-steps.js +340 -221
- package/src/inference/pipelines/text/generator.js +56 -40
- package/src/inference/pipelines/text/init.d.ts +13 -0
- package/src/inference/pipelines/text/init.js +94 -25
- package/src/inference/pipelines/text/kernel-path-auto-select.js +2 -0
- package/src/inference/pipelines/text/kernel-trace.d.ts +2 -0
- package/src/inference/pipelines/text/kernel-trace.js +6 -0
- package/src/inference/pipelines/text/layer.js +4 -9
- package/src/inference/pipelines/text/linear-attention.d.ts +15 -0
- package/src/inference/pipelines/text/linear-attention.js +113 -9
- package/src/inference/pipelines/text/logits/gpu.js +12 -7
- package/src/inference/pipelines/text/logits/index.d.ts +6 -1
- package/src/inference/pipelines/text/logits/index.js +13 -12
- package/src/inference/pipelines/text/logits/utils.d.ts +7 -0
- package/src/inference/pipelines/text/logits/utils.js +9 -0
- package/src/inference/pipelines/text/lora-apply.js +50 -32
- package/src/inference/pipelines/text/model-load.js +282 -104
- package/src/inference/pipelines/text/moe-cache.js +5 -4
- package/src/inference/pipelines/text/moe-cpu-gptoss.js +74 -69
- package/src/inference/pipelines/text/moe-cpu.js +42 -38
- package/src/inference/pipelines/text/moe-gpu.js +110 -86
- package/src/inference/pipelines/text/ops.js +90 -90
- package/src/inference/pipelines/text/probes.js +9 -9
- package/src/inference/pipelines/text/sampling.js +52 -6
- package/src/inference/pipelines/text/weights.js +17 -7
- package/src/inference/pipelines/text.js +13 -1
- package/src/inference/speculative.d.ts +2 -2
- package/src/inference/speculative.js +4 -18
- package/src/inference/test-harness.d.ts +1 -1
- package/src/inference/test-harness.js +17 -7
- package/src/inference/tokenizer.d.ts +0 -5
- package/src/inference/tokenizer.js +4 -23
- package/src/inference/tokenizers/bpe.js +9 -0
- package/src/inference/tokenizers/bundled.js +20 -0
- package/src/inference/tokenizers/sentencepiece.js +12 -0
- package/src/loader/doppler-loader.js +38 -22
- package/src/loader/dtype-utils.js +3 -44
- package/src/loader/embedding-loader.js +7 -3
- package/src/loader/experts/expert-cache.js +13 -6
- package/src/loader/experts/expert-loader.js +10 -6
- package/src/loader/final-weights-loader.js +10 -4
- package/src/loader/layer-loader.js +2 -1
- package/src/loader/loader-state.js +2 -2
- package/src/loader/memory-monitor.js +8 -0
- package/src/loader/multi-model-loader.d.ts +14 -0
- package/src/loader/multi-model-loader.js +70 -24
- package/src/loader/shard-cache.js +84 -14
- package/src/loader/shard-resolver.js +25 -3
- package/src/loader/tensors/tensor-loader.js +214 -144
- package/src/loader/tensors/tensor-reader.js +76 -19
- package/src/loader/weight-downcast.js +1 -1
- package/src/memory/buffer-pool.d.ts +9 -1
- package/src/memory/buffer-pool.js +109 -44
- package/src/memory/unified-detect.js +1 -1
- package/src/rules/inference/dtype.rules.json +5 -0
- package/src/rules/inference/kernel-path.rules.json +24 -8
- package/src/rules/kernels/split-qg.rules.json +6 -0
- package/src/rules/rule-registry.js +27 -1
- package/src/storage/backends/opfs-store.js +68 -24
- package/src/storage/downloader.js +365 -83
- package/src/storage/index.d.ts +3 -0
- package/src/storage/index.js +3 -0
- package/src/storage/preflight.d.ts +2 -2
- package/src/storage/preflight.js +24 -2
- package/src/storage/quickstart-downloader.js +11 -5
- package/src/storage/registry.js +10 -4
- package/src/storage/reports.js +1 -1
- package/src/storage/shard-manager.d.ts +15 -1
- package/src/storage/shard-manager.js +55 -6
- package/src/storage/source-artifact-store.d.ts +52 -0
- package/src/storage/source-artifact-store.js +234 -0
- package/src/tooling/command-api-constants.d.ts +9 -0
- package/src/tooling/command-api-constants.js +9 -0
- package/src/tooling/command-api-family-normalizers.d.ts +9 -0
- package/src/tooling/command-api-family-normalizers.js +343 -0
- package/src/tooling/command-api-helpers.d.ts +25 -0
- package/src/tooling/command-api-helpers.js +262 -0
- package/src/tooling/command-api.js +16 -602
- package/src/tooling/command-envelope.js +4 -1
- package/src/tooling/command-runner-shared.js +52 -18
- package/src/tooling/conversion-config-materializer.js +3 -5
- package/src/tooling/lean-execution-contract.js +150 -3
- package/src/tooling/node-browser-command-runner.js +161 -271
- package/src/tooling/node-command-runner.js +29 -3
- package/src/tooling/node-converter.js +30 -1
- package/src/tooling/node-source-runtime.d.ts +1 -1
- package/src/tooling/node-source-runtime.js +120 -3
- package/src/tooling/node-webgpu.js +24 -21
- package/src/tooling/opfs-cache.js +21 -4
- package/src/tooling/runtime-input-composition.d.ts +38 -0
- package/src/tooling/runtime-input-composition.js +86 -0
- package/src/tooling/source-runtime-bundle.d.ts +40 -5
- package/src/tooling/source-runtime-bundle.js +261 -34
- package/src/tooling/source-runtime-materializer.d.ts +6 -0
- package/src/tooling/source-runtime-materializer.js +93 -0
- package/src/training/attention-backward.js +32 -17
- package/src/training/autograd.js +80 -52
- package/src/training/checkpoint-watch.d.ts +2 -1
- package/src/training/checkpoint-watch.js +39 -6
- package/src/training/checkpoint.js +40 -11
- package/src/training/clip.js +2 -1
- package/src/training/datasets/token-batch.js +20 -8
- package/src/training/distillation/checkpoint-watch.js +1 -0
- package/src/training/distillation/student-fixture.d.ts +22 -0
- package/src/training/distillation/student-fixture.js +846 -0
- package/src/training/distillation/suite-data.d.ts +45 -0
- package/src/training/distillation/suite-data.js +189 -0
- package/src/training/lora-pipeline.js +4 -7
- package/src/training/lora.js +26 -12
- package/src/training/loss.js +5 -6
- package/src/training/objectives/cross_entropy.js +2 -5
- package/src/training/objectives/distill_kd.js +4 -8
- package/src/training/objectives/distill_triplet.js +4 -8
- package/src/training/objectives/ul_stage2_base.js +4 -8
- package/src/training/operator-command.js +2 -0
- package/src/training/optimizer.js +19 -7
- package/src/training/runner.js +2 -1
- package/src/training/suite.js +18 -978
- package/src/training/tensor-factory.d.ts +9 -0
- package/src/training/tensor-factory.js +13 -0
- package/src/training/trainer.js +3 -5
- package/src/training/ul_dataset.js +3 -5
- package/src/training/workloads.js +70 -79
- package/src/types/model.d.ts +5 -0
- package/src/version.js +1 -1
- package/tools/convert-safetensors-node.js +22 -16
- package/tools/doppler-cli.js +50 -26
|
@@ -9,7 +9,10 @@ import {
|
|
|
9
9
|
ensureCommandSupportedOnSurface,
|
|
10
10
|
normalizeToolingCommandRequest,
|
|
11
11
|
} from './command-api.js';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
isToolingSuccessEnvelope,
|
|
14
|
+
normalizeToToolingCommandError,
|
|
15
|
+
} from './command-envelope.js';
|
|
13
16
|
|
|
14
17
|
const DEFAULT_HOST = '127.0.0.1';
|
|
15
18
|
const DEFAULT_RUNNER_PATH = '/src/tooling/command-runner.html';
|
|
@@ -359,6 +362,26 @@ function asNonEmptyString(value) {
|
|
|
359
362
|
return normalized === '' ? null : normalized;
|
|
360
363
|
}
|
|
361
364
|
|
|
365
|
+
function createPersistentContextRequiredError(requestedLoadMode, cause = null) {
|
|
366
|
+
const baseMessage = requestedLoadMode === 'opfs'
|
|
367
|
+
? 'browser command: loadMode=opfs requires persistent browser context; persistent launch failed.'
|
|
368
|
+
: 'browser command: persistent browser context is required when OPFS cache is enabled; persistent launch failed.';
|
|
369
|
+
const causeMessage = asNonEmptyString(cause?.message || cause);
|
|
370
|
+
return new Error(
|
|
371
|
+
`${baseMessage} Re-run with run.browser.opfsCache=false to use a non-persistent browser session.${causeMessage ? ` (${causeMessage})` : ''}`
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export function finalizeBrowserRelayResponse(response, request) {
|
|
376
|
+
if (!isToolingSuccessEnvelope(response)) {
|
|
377
|
+
throw new Error('browser command: runner returned an invalid success envelope.');
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
...response,
|
|
381
|
+
request,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
362
385
|
function normalizeWebgpuBackend(value) {
|
|
363
386
|
const raw = asNonEmptyString(value);
|
|
364
387
|
if (!raw) return null;
|
|
@@ -570,8 +593,10 @@ async function launchPersistentBrowser(chromium, userDataDir, launchOptions, opt
|
|
|
570
593
|
|
|
571
594
|
export async function runBrowserCommandInNode(commandRequest, options = {}) {
|
|
572
595
|
let request = null;
|
|
596
|
+
let sourceRequest = null;
|
|
573
597
|
try {
|
|
574
598
|
({ request } = ensureCommandSupportedOnSurface(commandRequest, 'browser'));
|
|
599
|
+
sourceRequest = request;
|
|
575
600
|
|
|
576
601
|
if (request.keepPipeline) {
|
|
577
602
|
throw new Error(
|
|
@@ -583,321 +608,186 @@ export async function runBrowserCommandInNode(commandRequest, options = {}) {
|
|
|
583
608
|
throw new Error('browser command relay does not support convert. Use --surface node for convert commands.');
|
|
584
609
|
}
|
|
585
610
|
|
|
586
|
-
|
|
587
|
-
|
|
611
|
+
let useOpfsCache = options.opfsCache !== false;
|
|
612
|
+
let relayRequest = request;
|
|
613
|
+
const userDataDir = options.userDataDir || DEFAULT_OPFS_CACHE_DIR;
|
|
588
614
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
615
|
+
if (options.wipeCacheBeforeLaunch && useOpfsCache) {
|
|
616
|
+
await fs.rm(userDataDir, { recursive: true, force: true }).catch(() => {});
|
|
617
|
+
}
|
|
592
618
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
619
|
+
const { chromium } = await import('playwright');
|
|
620
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl);
|
|
621
|
+
// When OPFS caching is enabled, use a fixed port so the browser origin stays the same
|
|
622
|
+
// across runs (OPFS is origin-scoped). Without this, random ports create new origins.
|
|
623
|
+
const serverPort = options.port ?? (useOpfsCache ? DEFAULT_OPFS_CACHE_PORT : 0);
|
|
624
|
+
const server = baseUrl
|
|
625
|
+
? null
|
|
626
|
+
: await createStaticFileServer({
|
|
627
|
+
rootDir: options.staticRootDir,
|
|
628
|
+
staticMounts: options.staticMounts,
|
|
629
|
+
host: options.host,
|
|
630
|
+
port: serverPort,
|
|
631
|
+
}).catch((error) => {
|
|
632
|
+
const message = error?.message || String(error);
|
|
633
|
+
throw new Error(
|
|
634
|
+
`browser command: failed to start static server (${message}). Pass --browser-base-url to reuse an existing server.`
|
|
635
|
+
);
|
|
636
|
+
});
|
|
611
637
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
638
|
+
const launchOptions = {
|
|
639
|
+
headless: normalizeHeadless(options.headless),
|
|
640
|
+
args: browserLaunchArgs(normalizeBrowserArgs(options.browserArgs)),
|
|
641
|
+
};
|
|
616
642
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
643
|
+
if (options.channel) {
|
|
644
|
+
launchOptions.channel = String(options.channel);
|
|
645
|
+
}
|
|
646
|
+
if (options.executablePath) {
|
|
647
|
+
launchOptions.executablePath = String(options.executablePath);
|
|
648
|
+
}
|
|
623
649
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
}
|
|
637
|
-
}
|
|
650
|
+
const timeoutMs = normalizeTimeoutMs(options.timeoutMs);
|
|
651
|
+
const runnerPath = normalizeRunnerPath(options.runnerPath);
|
|
652
|
+
const resolvedBaseUrl = baseUrl || server.baseUrl;
|
|
653
|
+
const requestedLoadMode = sourceRequest.loadMode;
|
|
654
|
+
const requireOpfsLoad = requestedLoadMode === 'opfs';
|
|
655
|
+
if (requireOpfsLoad && useOpfsCache === false) {
|
|
656
|
+
throw new Error('browser command: loadMode=opfs requires OPFS cache support (remove --no-opfs-cache).');
|
|
657
|
+
}
|
|
658
|
+
if (requireOpfsLoad && sourceRequest.modelUrl && !sourceRequest.modelId) {
|
|
659
|
+
throw new Error(
|
|
660
|
+
'browser command: loadMode=opfs requires modelId when modelUrl is provided so the relay can verify and load the cached OPFS artifact.'
|
|
661
|
+
);
|
|
662
|
+
}
|
|
638
663
|
|
|
639
664
|
let browser = null;
|
|
640
665
|
let context = null;
|
|
641
666
|
try {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
try {
|
|
646
|
-
context = await launchPersistentBrowser(chromium, userDataDir, launchOptions, {
|
|
647
|
-
explicitChannel: Boolean(options.channel),
|
|
648
|
-
explicitExecutablePath: Boolean(options.executablePath),
|
|
649
|
-
});
|
|
650
|
-
} catch (error) {
|
|
651
|
-
if (!isRecoverablePersistentLaunchError(error)) {
|
|
652
|
-
throw error;
|
|
653
|
-
}
|
|
654
|
-
if (typeof options.onConsole === 'function') {
|
|
655
|
-
options.onConsole({
|
|
656
|
-
type: 'warning',
|
|
657
|
-
text: '[browser] Persistent browser launch failed; retrying with a clean OPFS profile.',
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
await fs.rm(userDataDir, { recursive: true, force: true }).catch(() => {});
|
|
667
|
+
if (useOpfsCache) {
|
|
668
|
+
// Persistent context: OPFS data survives between runs.
|
|
669
|
+
// launchPersistentContext returns a BrowserContext directly (no separate Browser).
|
|
661
670
|
try {
|
|
662
671
|
context = await launchPersistentBrowser(chromium, userDataDir, launchOptions, {
|
|
663
672
|
explicitChannel: Boolean(options.channel),
|
|
664
673
|
explicitExecutablePath: Boolean(options.executablePath),
|
|
665
674
|
});
|
|
666
|
-
} catch (
|
|
667
|
-
if (!isRecoverablePersistentLaunchError(
|
|
668
|
-
throw
|
|
675
|
+
} catch (error) {
|
|
676
|
+
if (!isRecoverablePersistentLaunchError(error)) {
|
|
677
|
+
throw error;
|
|
669
678
|
}
|
|
670
679
|
if (typeof options.onConsole === 'function') {
|
|
671
680
|
options.onConsole({
|
|
672
681
|
type: 'warning',
|
|
673
|
-
text: '[browser] Persistent launch
|
|
682
|
+
text: '[browser] Persistent browser launch failed; retrying with a clean OPFS profile.',
|
|
674
683
|
});
|
|
675
684
|
}
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
685
|
+
await fs.rm(userDataDir, { recursive: true, force: true }).catch(() => {});
|
|
686
|
+
try {
|
|
687
|
+
context = await launchPersistentBrowser(chromium, userDataDir, launchOptions, {
|
|
688
|
+
explicitChannel: Boolean(options.channel),
|
|
689
|
+
explicitExecutablePath: Boolean(options.executablePath),
|
|
690
|
+
});
|
|
691
|
+
} catch (retryError) {
|
|
692
|
+
if (!isRecoverablePersistentLaunchError(retryError)) {
|
|
693
|
+
throw retryError;
|
|
694
|
+
}
|
|
695
|
+
throw createPersistentContextRequiredError(requestedLoadMode, retryError);
|
|
687
696
|
}
|
|
688
|
-
browser = await launchBrowser(chromium, launchOptions, {
|
|
689
|
-
explicitChannel: Boolean(options.channel),
|
|
690
|
-
explicitExecutablePath: Boolean(options.executablePath),
|
|
691
|
-
});
|
|
692
|
-
context = await browser.newContext();
|
|
693
697
|
}
|
|
698
|
+
} else {
|
|
699
|
+
browser = await launchBrowser(chromium, launchOptions, {
|
|
700
|
+
explicitChannel: Boolean(options.channel),
|
|
701
|
+
explicitExecutablePath: Boolean(options.executablePath),
|
|
702
|
+
});
|
|
703
|
+
context = await browser.newContext();
|
|
694
704
|
}
|
|
695
|
-
} else {
|
|
696
|
-
browser = await launchBrowser(chromium, launchOptions, {
|
|
697
|
-
explicitChannel: Boolean(options.channel),
|
|
698
|
-
explicitExecutablePath: Boolean(options.executablePath),
|
|
699
|
-
});
|
|
700
|
-
context = await browser.newContext();
|
|
701
|
-
}
|
|
702
705
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
+
const page = await context.newPage();
|
|
707
|
+
page.setDefaultTimeout(timeoutMs);
|
|
708
|
+
const pageDiagnostics = [];
|
|
706
709
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
710
|
+
if (typeof options.onConsole === 'function') {
|
|
711
|
+
page.on('console', (message) => {
|
|
712
|
+
options.onConsole({
|
|
713
|
+
type: message.type(),
|
|
714
|
+
text: message.text(),
|
|
715
|
+
});
|
|
712
716
|
});
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
page.on('pageerror', (error) => {
|
|
717
|
-
pageDiagnostics.push(`pageerror: ${error?.message || String(error)}`);
|
|
718
|
-
});
|
|
719
|
-
page.on('requestfailed', (request) => {
|
|
720
|
-
const failure = request.failure();
|
|
721
|
-
pageDiagnostics.push(
|
|
722
|
-
`requestfailed: ${request.url()} (${failure?.errorText || 'unknown error'})`
|
|
723
|
-
);
|
|
724
|
-
});
|
|
717
|
+
}
|
|
725
718
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
719
|
+
page.on('pageerror', (error) => {
|
|
720
|
+
pageDiagnostics.push(`pageerror: ${error?.message || String(error)}`);
|
|
721
|
+
});
|
|
722
|
+
page.on('requestfailed', (request) => {
|
|
723
|
+
const failure = request.failure();
|
|
724
|
+
pageDiagnostics.push(
|
|
725
|
+
`requestfailed: ${request.url()} (${failure?.errorText || 'unknown error'})`
|
|
726
|
+
);
|
|
732
727
|
});
|
|
733
|
-
} catch (error) {
|
|
734
|
-
const diagnostics = pageDiagnostics.length
|
|
735
|
-
? pageDiagnostics.slice(0, 10).join(' | ')
|
|
736
|
-
: 'no page diagnostics captured';
|
|
737
|
-
throw new Error(
|
|
738
|
-
`browser command: runner did not become ready within ${timeoutMs}ms (${diagnostics}).`
|
|
739
|
-
);
|
|
740
|
-
}
|
|
741
728
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
729
|
+
const runnerUrl = new URL(runnerPath, resolvedBaseUrl);
|
|
730
|
+
runnerUrl.searchParams.set('_dopplerRunner', String(Date.now()));
|
|
731
|
+
await page.goto(runnerUrl.toString(), { waitUntil: 'load' });
|
|
745
732
|
try {
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
return { cached: false, error: '__dopplerEnsureCached not available' };
|
|
749
|
-
}
|
|
750
|
-
return globalThis.__dopplerEnsureCached(payload.modelId, payload.modelBaseUrl);
|
|
751
|
-
}, {
|
|
752
|
-
modelId: request.modelId,
|
|
753
|
-
modelBaseUrl: request.modelUrl,
|
|
733
|
+
await page.waitForFunction(() => globalThis.__dopplerRunnerReady === true, null, {
|
|
734
|
+
timeout: timeoutMs,
|
|
754
735
|
});
|
|
736
|
+
} catch (error) {
|
|
737
|
+
const diagnostics = pageDiagnostics.length
|
|
738
|
+
? pageDiagnostics.slice(0, 10).join(' | ')
|
|
739
|
+
: 'no page diagnostics captured';
|
|
740
|
+
throw new Error(
|
|
741
|
+
`browser command: runner did not become ready within ${timeoutMs}ms (${diagnostics}).`
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Explicit loadMode=opfs must be satisfied without rewriting the shared request contract.
|
|
746
|
+
if (useOpfsCache && requireOpfsLoad && relayRequest.modelId && relayRequest.modelUrl) {
|
|
747
|
+
try {
|
|
748
|
+
const cacheResult = await page.evaluate(async (payload) => {
|
|
749
|
+
if (typeof globalThis.__dopplerEnsureCached !== 'function') {
|
|
750
|
+
return { cached: false, error: '__dopplerEnsureCached not available' };
|
|
751
|
+
}
|
|
752
|
+
return globalThis.__dopplerEnsureCached(payload.modelId, payload.modelBaseUrl);
|
|
753
|
+
}, {
|
|
754
|
+
modelId: relayRequest.modelId,
|
|
755
|
+
modelBaseUrl: relayRequest.modelUrl,
|
|
756
|
+
});
|
|
755
757
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
request.loadMode = 'opfs';
|
|
761
|
-
} else {
|
|
762
|
-
if (requireOpfsLoad) {
|
|
758
|
+
if (cacheResult.cached) {
|
|
759
|
+
relayRequest = { ...relayRequest };
|
|
760
|
+
delete relayRequest.modelUrl;
|
|
761
|
+
} else {
|
|
763
762
|
const cacheError = cacheResult?.error || 'model not cached';
|
|
764
763
|
throw new Error(
|
|
765
|
-
`[opfs-cache]
|
|
764
|
+
`[opfs-cache] model cache is unavailable for "${relayRequest.modelId || 'unknown-model'}": ${cacheError}.`
|
|
766
765
|
);
|
|
767
766
|
}
|
|
768
|
-
|
|
769
|
-
request = { ...request, loadMode: 'http' };
|
|
770
|
-
}
|
|
771
|
-
if (cacheResult.error) {
|
|
772
|
-
if (typeof options.onConsole === 'function') {
|
|
773
|
-
options.onConsole({
|
|
774
|
-
type: 'warning',
|
|
775
|
-
text: `[opfs-cache] Cache check failed (${cacheResult.error}), falling back to HTTP`,
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
} catch (error) {
|
|
781
|
-
if (requireOpfsLoad) {
|
|
767
|
+
} catch (error) {
|
|
782
768
|
throw new Error(
|
|
783
|
-
`[opfs-cache]
|
|
769
|
+
`[opfs-cache] cache priming failed: ${error?.message || error}.`
|
|
784
770
|
);
|
|
785
771
|
}
|
|
786
|
-
if (!requestedLoadMode && request.modelUrl) {
|
|
787
|
-
request = { ...request, loadMode: 'http' };
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// OPFS cache is best-effort; fall back to HTTP on any error.
|
|
791
|
-
if (typeof options.onConsole === 'function') {
|
|
792
|
-
options.onConsole({
|
|
793
|
-
type: 'warning',
|
|
794
|
-
text: `[opfs-cache] Error (${error?.message || error}), falling back to HTTP`,
|
|
795
|
-
});
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
const response = await page.evaluate(async (payload) => {
|
|
801
|
-
if (typeof globalThis.__dopplerRunBrowserCommand !== 'function') {
|
|
802
|
-
throw new Error('browser command runner is missing globalThis.__dopplerRunBrowserCommand');
|
|
803
772
|
}
|
|
804
|
-
return globalThis.__dopplerRunBrowserCommand(payload.request, payload.options || {});
|
|
805
|
-
}, {
|
|
806
|
-
request,
|
|
807
|
-
options: {
|
|
808
|
-
runtimeLoadOptions: options.runtimeLoadOptions || {},
|
|
809
|
-
},
|
|
810
|
-
});
|
|
811
773
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
};
|
|
822
|
-
const webgpuBackend = inferWebgpuBackendFromArgs(launchOptions.args, hostEnvironment.platform);
|
|
823
|
-
const env = result.env && typeof result.env === 'object' ? result.env : {};
|
|
824
|
-
const deviceInfo = result.deviceInfo && typeof result.deviceInfo === 'object'
|
|
825
|
-
? result.deviceInfo
|
|
826
|
-
: {};
|
|
827
|
-
result.env = {
|
|
828
|
-
...env,
|
|
829
|
-
webgpuBackend: normalizeWebgpuBackend(env.webgpuBackend)
|
|
830
|
-
|| normalizeWebgpuBackend(env.gpuBackend)
|
|
831
|
-
|| normalizeWebgpuBackend(env.graphicsBackend)
|
|
832
|
-
|| webgpuBackend,
|
|
833
|
-
};
|
|
834
|
-
const existingEnvironment = result.environment && typeof result.environment === 'object'
|
|
835
|
-
? result.environment
|
|
836
|
-
: {};
|
|
837
|
-
result.environment = {
|
|
838
|
-
...existingEnvironment,
|
|
839
|
-
host: {
|
|
840
|
-
...(existingEnvironment.host && typeof existingEnvironment.host === 'object' ? existingEnvironment.host : {}),
|
|
841
|
-
platform: asNonEmptyString(existingEnvironment?.host?.platform) || hostEnvironment.platform,
|
|
842
|
-
arch: asNonEmptyString(existingEnvironment?.host?.arch) || hostEnvironment.arch,
|
|
843
|
-
nodeVersion: asNonEmptyString(existingEnvironment?.host?.nodeVersion) || hostEnvironment.nodeVersion,
|
|
844
|
-
osRelease: asNonEmptyString(existingEnvironment?.host?.osRelease) || hostEnvironment.osRelease,
|
|
845
|
-
cpuModel: asNonEmptyString(existingEnvironment?.host?.cpuModel) || hostEnvironment.cpuModel,
|
|
846
|
-
},
|
|
847
|
-
browser: {
|
|
848
|
-
...(existingEnvironment.browser && typeof existingEnvironment.browser === 'object' ? existingEnvironment.browser : {}),
|
|
849
|
-
userAgent: asNonEmptyString(existingEnvironment?.browser?.userAgent) || asNonEmptyString(env.browserUserAgent),
|
|
850
|
-
platform: asNonEmptyString(existingEnvironment?.browser?.platform) || asNonEmptyString(env.browserPlatform),
|
|
851
|
-
language: asNonEmptyString(existingEnvironment?.browser?.language) || asNonEmptyString(env.browserLanguage),
|
|
852
|
-
vendor: asNonEmptyString(existingEnvironment?.browser?.vendor) || asNonEmptyString(env.browserVendor),
|
|
853
|
-
executable: asNonEmptyString(existingEnvironment?.browser?.executable) || asNonEmptyString(options.executablePath),
|
|
854
|
-
channel: asNonEmptyString(existingEnvironment?.browser?.channel) || asNonEmptyString(options.channel),
|
|
855
|
-
},
|
|
856
|
-
gpu: {
|
|
857
|
-
...(existingEnvironment.gpu && typeof existingEnvironment.gpu === 'object' ? existingEnvironment.gpu : {}),
|
|
858
|
-
api: asNonEmptyString(existingEnvironment?.gpu?.api) || 'webgpu',
|
|
859
|
-
backend: normalizeWebgpuBackend(existingEnvironment?.gpu?.backend)
|
|
860
|
-
|| normalizeWebgpuBackend(env.webgpuBackend)
|
|
861
|
-
|| webgpuBackend,
|
|
862
|
-
vendor: asNonEmptyString(existingEnvironment?.gpu?.vendor) || asNonEmptyString(deviceInfo.vendor),
|
|
863
|
-
architecture: asNonEmptyString(existingEnvironment?.gpu?.architecture) || asNonEmptyString(deviceInfo.architecture),
|
|
864
|
-
device: asNonEmptyString(existingEnvironment?.gpu?.device) || asNonEmptyString(deviceInfo.device),
|
|
865
|
-
description: asNonEmptyString(existingEnvironment?.gpu?.description) || asNonEmptyString(deviceInfo.description),
|
|
866
|
-
hasF16: typeof existingEnvironment?.gpu?.hasF16 === 'boolean'
|
|
867
|
-
? existingEnvironment.gpu.hasF16
|
|
868
|
-
: (typeof deviceInfo.hasF16 === 'boolean' ? deviceInfo.hasF16 : null),
|
|
869
|
-
hasSubgroups: typeof existingEnvironment?.gpu?.hasSubgroups === 'boolean'
|
|
870
|
-
? existingEnvironment.gpu.hasSubgroups
|
|
871
|
-
: (typeof deviceInfo.hasSubgroups === 'boolean' ? deviceInfo.hasSubgroups : null),
|
|
872
|
-
hasTimestampQuery: typeof existingEnvironment?.gpu?.hasTimestampQuery === 'boolean'
|
|
873
|
-
? existingEnvironment.gpu.hasTimestampQuery
|
|
874
|
-
: (typeof deviceInfo.hasTimestampQuery === 'boolean' ? deviceInfo.hasTimestampQuery : null),
|
|
875
|
-
},
|
|
876
|
-
runtime: {
|
|
877
|
-
...(existingEnvironment.runtime && typeof existingEnvironment.runtime === 'object' ? existingEnvironment.runtime : {}),
|
|
878
|
-
library: asNonEmptyString(existingEnvironment?.runtime?.library) || asNonEmptyString(env.library) || 'doppler',
|
|
879
|
-
version: asNonEmptyString(existingEnvironment?.runtime?.version) || asNonEmptyString(env.version),
|
|
880
|
-
surface: asNonEmptyString(existingEnvironment?.runtime?.surface) || asNonEmptyString(env.runtime) || 'browser',
|
|
881
|
-
device: asNonEmptyString(existingEnvironment?.runtime?.device) || asNonEmptyString(env.device),
|
|
882
|
-
dtype: asNonEmptyString(existingEnvironment?.runtime?.dtype) || asNonEmptyString(env.dtype),
|
|
883
|
-
requestedDtype: asNonEmptyString(existingEnvironment?.runtime?.requestedDtype) || asNonEmptyString(env.requestedDtype),
|
|
884
|
-
executionProviderMode: asNonEmptyString(existingEnvironment?.runtime?.executionProviderMode)
|
|
885
|
-
|| asNonEmptyString(env.executionProviderMode),
|
|
886
|
-
cacheMode: asNonEmptyString(existingEnvironment?.runtime?.cacheMode)
|
|
887
|
-
|| asNonEmptyString(result.cacheMode)
|
|
888
|
-
|| asNonEmptyString(result?.timing?.cacheMode),
|
|
889
|
-
loadMode: asNonEmptyString(existingEnvironment?.runtime?.loadMode)
|
|
890
|
-
|| asNonEmptyString(result.loadMode)
|
|
891
|
-
|| asNonEmptyString(result?.timing?.loadMode),
|
|
774
|
+
const response = await page.evaluate(async (payload) => {
|
|
775
|
+
if (typeof globalThis.__dopplerRunBrowserCommand !== 'function') {
|
|
776
|
+
throw new Error('browser command runner is missing globalThis.__dopplerRunBrowserCommand');
|
|
777
|
+
}
|
|
778
|
+
return globalThis.__dopplerRunBrowserCommand(payload.request, payload.options || {});
|
|
779
|
+
}, {
|
|
780
|
+
request: relayRequest,
|
|
781
|
+
options: {
|
|
782
|
+
runtimeLoadOptions: options.runtimeLoadOptions || {},
|
|
892
783
|
},
|
|
893
|
-
};
|
|
894
|
-
}
|
|
784
|
+
});
|
|
895
785
|
|
|
896
|
-
return response;
|
|
786
|
+
return finalizeBrowserRelayResponse(response, sourceRequest);
|
|
897
787
|
} catch (error) {
|
|
898
788
|
throw normalizeToToolingCommandError(error, {
|
|
899
789
|
surface: 'browser',
|
|
900
|
-
request,
|
|
790
|
+
request: sourceRequest,
|
|
901
791
|
});
|
|
902
792
|
} finally {
|
|
903
793
|
if (context) {
|
|
@@ -913,7 +803,7 @@ export async function runBrowserCommandInNode(commandRequest, options = {}) {
|
|
|
913
803
|
} catch (error) {
|
|
914
804
|
throw normalizeToToolingCommandError(error, {
|
|
915
805
|
surface: 'browser',
|
|
916
|
-
request,
|
|
806
|
+
request: sourceRequest,
|
|
917
807
|
});
|
|
918
808
|
}
|
|
919
809
|
}
|
|
@@ -28,6 +28,28 @@ function asOptionalPlainObject(value, label) {
|
|
|
28
28
|
return value;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
function assertNoUnsupportedRuntimeInputs(request) {
|
|
32
|
+
const runtimeFields = [];
|
|
33
|
+
if (Array.isArray(request?.configChain) && request.configChain.length > 0) {
|
|
34
|
+
runtimeFields.push('configChain');
|
|
35
|
+
}
|
|
36
|
+
if (typeof request?.runtimePreset === 'string' && request.runtimePreset.trim()) {
|
|
37
|
+
runtimeFields.push('runtimePreset');
|
|
38
|
+
}
|
|
39
|
+
if (typeof request?.runtimeConfigUrl === 'string' && request.runtimeConfigUrl.trim()) {
|
|
40
|
+
runtimeFields.push('runtimeConfigUrl');
|
|
41
|
+
}
|
|
42
|
+
if (request?.runtimeConfig != null) {
|
|
43
|
+
runtimeFields.push('runtimeConfig');
|
|
44
|
+
}
|
|
45
|
+
if (runtimeFields.length > 0) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`${request.command} does not support runtime input fields on the node operator surface: ` +
|
|
48
|
+
`${runtimeFields.join(', ')}. Put those settings into the workload/config asset instead.`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
31
53
|
let runtimeModulesPromise = null;
|
|
32
54
|
|
|
33
55
|
async function loadRuntimeModules() {
|
|
@@ -51,16 +73,19 @@ export function hasNodeWebGPUSupport() {
|
|
|
51
73
|
}
|
|
52
74
|
|
|
53
75
|
async function assertNodeWebGPUSupport() {
|
|
76
|
+
let bootstrapProvider = null;
|
|
54
77
|
if (!hasNodeWebGPUSupport()) {
|
|
55
78
|
const bootstrap = await bootstrapNodeWebGPU();
|
|
56
|
-
if (bootstrap.
|
|
57
|
-
|
|
79
|
+
if (bootstrap.provider) {
|
|
80
|
+
bootstrapProvider = bootstrap.provider;
|
|
58
81
|
}
|
|
59
82
|
}
|
|
60
83
|
|
|
61
84
|
if (hasNodeWebGPUSupport()) return;
|
|
62
85
|
throw new Error(
|
|
63
|
-
'node command: WebGPU runtime is incomplete in Node.
|
|
86
|
+
'node command: WebGPU runtime is incomplete in Node.' +
|
|
87
|
+
(bootstrapProvider ? ` Provider resolution stopped at "${bootstrapProvider}".` : '') +
|
|
88
|
+
' Run in browser relay, or run under a WebGPU-enabled Node build.'
|
|
64
89
|
);
|
|
65
90
|
}
|
|
66
91
|
|
|
@@ -94,6 +119,7 @@ export async function runNodeCommand(commandRequest, options = {}) {
|
|
|
94
119
|
if (request.command === 'lora' || request.command === 'distill') {
|
|
95
120
|
const gpuOptionalActions = new Set(['compare', 'quality-gate', 'subsets']);
|
|
96
121
|
installNodeFileFetchShim();
|
|
122
|
+
assertNoUnsupportedRuntimeInputs(request);
|
|
97
123
|
if (!gpuOptionalActions.has(request.action)) {
|
|
98
124
|
await assertNodeWebGPUSupport();
|
|
99
125
|
}
|