mlx-bun 0.2.0 → 0.3.0
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 +71 -588
- package/docs/README.md +91 -0
- package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
- package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
- package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
- package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
- package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
- package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
- package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
- package/docs/design/batching.md +569 -0
- package/docs/design/decode-speed-program.md +3178 -169
- package/docs/design/dreaming-nightly-pipeline.md +675 -282
- package/docs/design/generic-model-support.md +579 -334
- package/docs/design/kv-cache.md +680 -0
- package/docs/design/orpo-training.md +673 -1239
- package/docs/design/speculative-decoding.md +1627 -0
- package/docs/design/turboquant.md +2102 -0
- package/docs/design/unified-engine-frontier-plan.md +1831 -727
- package/docs/design/web-chat-redesign.md +666 -1083
- package/docs/planning/PRODUCT_ROADMAP.md +34 -1
- package/docs/planning/release-notes-v0.3.0.md +35 -0
- package/docs/planning/video-series.md +2 -2
- package/docs/reference/benchmarks.md +1162 -0
- package/docs/reference/cli.md +394 -159
- package/docs/reference/distribution.md +321 -182
- package/docs/reference/environment.md +348 -0
- package/docs/reference/glossary.md +39 -0
- package/docs/reference/library-api.md +566 -168
- package/docs/reference/memory.md +227 -64
- package/docs/reference/models.md +104 -6
- package/docs/reference/server-api.md +886 -425
- package/docs/reference/server-config.md +638 -330
- package/docs/reference/training.md +393 -254
- package/docs/reference/troubleshooting.md +166 -0
- package/package.json +9 -4
- package/src/audio/decode.ts +2 -2
- package/src/audio/features.ts +2 -2
- package/src/backends/mlx/autoregressive.ts +108 -0
- package/src/backends/mlx/batch-group.ts +1646 -0
- package/src/backends/mlx/diffusion.ts +39 -0
- package/src/backends/mlx/draft-target.ts +47 -0
- package/src/backends/mlx/evaluation.ts +105 -0
- package/src/backends/mlx/fill-append.ts +45 -0
- package/src/backends/mlx/gateway-binding.ts +71 -0
- package/src/backends/mlx/graph.ts +38 -0
- package/src/backends/mlx/memory-client.ts +189 -0
- package/src/backends/mlx/memory-guard.ts +40 -0
- package/src/backends/mlx/methods.ts +90 -0
- package/src/backends/mlx/model-prompt.ts +164 -0
- package/src/backends/mlx/model-serving.ts +79 -0
- package/src/backends/mlx/prefill.ts +33 -0
- package/src/backends/mlx/request-policy.ts +20 -0
- package/src/backends/mlx/rollback.ts +51 -0
- package/src/backends/mlx/serial-executor.ts +273 -0
- package/src/backends/mlx/speculative.ts +114 -0
- package/src/backends/mlx/state-views.ts +26 -0
- package/src/backends/mlx/text-engine.ts +73 -0
- package/src/cli.ts +58 -25
- package/src/client.ts +66 -0
- package/src/config.ts +21 -4
- package/src/contracts/completion.ts +16 -0
- package/src/contracts/execution.ts +49 -0
- package/src/contracts/generation.ts +103 -0
- package/src/contracts/host.ts +7 -0
- package/src/contracts/jobs.ts +66 -0
- package/src/contracts/pi-provider.ts +30 -0
- package/src/contracts/pi.ts +259 -0
- package/src/contracts/resources.ts +18 -0
- package/src/contracts/scheduling.ts +27 -0
- package/src/contracts/tsconfig.json +14 -0
- package/src/diffusion/diffusion-generate.ts +218 -153
- package/src/embed.ts +1 -1
- package/src/engine/admission.ts +59 -0
- package/src/engine/cancellation.ts +38 -0
- package/src/engine/engine.ts +56 -0
- package/src/engine/execution-coordinator.ts +70 -0
- package/src/engine/execution-plan.ts +51 -0
- package/src/engine/resources.ts +42 -0
- package/src/engine/scheduler.ts +67 -0
- package/src/engine/session.ts +247 -0
- package/src/eval/README.md +44 -1
- package/src/eval/kl.ts +236 -3
- package/src/eval/reference-logits.ts +207 -0
- package/src/eval/runner.ts +8 -96
- package/src/fill/echo-index.ts +188 -0
- package/src/fill/fill-session.ts +452 -0
- package/src/fill/proposal.ts +68 -0
- package/src/fill/schema-rows.ts +506 -0
- package/src/fill/tool-boundary.ts +103 -0
- package/src/fit.ts +1 -1
- package/src/generate.ts +656 -268
- package/src/grammar.ts +12 -7
- package/src/harness-pi.ts +14 -33
- package/src/hub-rest.ts +4 -4
- package/src/index.ts +7 -0
- package/src/inference/denoising.ts +17 -0
- package/src/inference/graph.ts +33 -0
- package/src/inference/prefill.ts +39 -0
- package/src/inference/rollback.ts +7 -0
- package/src/jobs/db.ts +4 -0
- package/src/jobs/index.ts +2 -0
- package/src/jobs/job-entry.ts +12 -12
- package/src/jobs/runner.ts +98 -13
- package/src/jobs/task-client.ts +19 -0
- package/src/jobs/types.ts +2 -58
- package/src/kv-store.ts +109 -49
- package/src/lab/README.md +18 -0
- package/src/{assets → lab/curve}/curve-designer.html +2 -2
- package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
- package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +5 -5
- package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
- package/src/library.ts +40 -0
- package/src/lora.ts +18 -0
- package/src/media-fetch.ts +1 -1
- package/src/memory/article.ts +1 -1
- package/src/memory/chunk.ts +1 -1
- package/src/memory/model.ts +30 -169
- package/src/memory/prompts.ts +1 -1
- package/src/memory/rest.ts +1 -1
- package/src/memory/schedule.ts +1 -1
- package/src/memory/stages.ts +4 -1
- package/src/memory/vault.ts +1 -3
- package/src/mlx/array.ts +9 -10
- package/src/mlx/compile.ts +12 -2
- package/src/mlx/ffi.ts +58 -11
- package/src/mlx/materialize.ts +23 -0
- package/src/mlx/metal-kernel.ts +10 -11
- package/src/mlx/ops.ts +33 -13
- package/src/mlx/quantized-rows.ts +36 -0
- package/src/mlx/token-bitmask.ts +52 -0
- package/src/mlx/turboquant-kv-decode.ts +82 -0
- package/src/mlx/turboquant-kv-inverse.ts +122 -0
- package/src/mlx/turboquant-ops.ts +33 -3
- package/src/mlx/turboquant-tables.ts +2 -2
- package/src/model/batched-mask.ts +8 -2
- package/src/model/batched-quant.ts +1 -1
- package/src/model/batched-rotating-quant.ts +2 -2
- package/src/model/batched-rotating.ts +1 -1
- package/src/model/compiled-decode.ts +1 -1
- package/src/model/diffusion-gemma.ts +8 -8
- package/src/model/factory.ts +76 -33
- package/src/model/fingerprint.ts +1 -1
- package/src/model/flash-attention.ts +3 -3
- package/src/model/gemma4-base.ts +26 -9
- package/src/model/gemma4.ts +6 -6
- package/src/model/generated/gemma4-12b.ts +2 -2
- package/src/model/generated/gemma4-26b.ts +2 -2
- package/src/model/generated/gemma4-e4b.ts +2 -2
- package/src/model/glm52-dsa.ts +13 -9
- package/src/model/glm52-memory.ts +1 -1
- package/src/model/implementation.ts +69 -0
- package/src/model/minicpm5.ts +6 -8
- package/src/model/profile.ts +12 -2
- package/src/model/qwen-append.ts +12 -0
- package/src/model/qwen-conv.ts +52 -0
- package/src/model/qwen3_5-checkpoint.ts +164 -0
- package/src/model/qwen3_5.ts +140 -56
- package/src/model/support.ts +1 -1
- package/src/model/trellis-balanced-scatter.ts +51 -0
- package/src/model/trellis-linear.ts +672 -0
- package/src/model/trellis-shared-m.ts +151 -0
- package/src/model/trellis-shared-scatter.ts +144 -0
- package/src/model/trellis-splitk-prefill.ts +158 -0
- package/src/model/trellis-tiled-prefill.ts +136 -0
- package/src/model/trellis-vector-expand.ts +62 -0
- package/src/model/trellis-wide-prefill.ts +94 -0
- package/src/model/universal/dense.ts +1 -1
- package/src/model/universal/modules.ts +8 -1
- package/src/native-pack.ts +6 -5
- package/src/pi-provider.ts +6 -64
- package/src/pi-web.ts +8 -315
- package/src/prompt-cache.ts +96 -53
- package/src/quantize/allocator.ts +1 -1
- package/src/quantize/config-writer.ts +10 -3
- package/src/quantize/rotate.ts +4 -4
- package/src/quantize/trellis.ts +586 -0
- package/src/responses.ts +28 -1
- package/src/runtime-config.ts +18 -4
- package/src/sampler.ts +4 -4
- package/src/serve/batch-scheduler.ts +8 -1671
- package/src/serve/chat-request.ts +391 -0
- package/src/serve/chat-stage.ts +195 -0
- package/src/serve/checkpoint-identity.ts +64 -0
- package/src/serve/completion-executor.ts +15 -7
- package/src/serve/discovery-routes.ts +12 -13
- package/src/serve/generation-gateway.ts +154 -193
- package/src/serve/http.ts +159 -0
- package/src/serve/inference-request.ts +79 -0
- package/src/serve/isolate.ts +297 -105
- package/src/serve/lab-routes.ts +3 -0
- package/src/serve/lane-registry.ts +2 -1
- package/src/serve/model-admin-routes.ts +7 -5
- package/src/serve/model-binding.ts +43 -0
- package/src/serve/model-host.ts +512 -0
- package/src/serve/openai-wire.ts +103 -0
- package/src/serve/parent-application.ts +56 -0
- package/src/serve/pipeline.ts +33 -0
- package/src/serve/preparation.ts +33 -0
- package/src/serve/request-plan.ts +19 -15
- package/src/serve/request-prep.ts +346 -0
- package/src/serve/response-lease.ts +24 -0
- package/src/serve/responses-client.ts +69 -0
- package/src/serve/session-completion-engine.ts +110 -0
- package/src/serve/session-search.ts +1 -1
- package/src/serve/static-routes.ts +5 -5
- package/src/serve/text-completion-stage.ts +104 -0
- package/src/serve/token-streams.ts +519 -0
- package/src/server.ts +317 -2649
- package/src/spec/assistant-source.ts +10 -44
- package/src/spec/deepspec-source.ts +6 -6
- package/src/spec/dflash-source.ts +8 -8
- package/src/spec/dspark/ab-stats.ts +3 -3
- package/src/spec/dspark/calibration.ts +2 -2
- package/src/spec/dspark/deepspec-module.ts +2 -2
- package/src/spec/dspark/generate-dflash.ts +2 -2
- package/src/spec/dspark/generate.ts +2 -2
- package/src/spec/dspark/loader.ts +1 -1
- package/src/spec/dspark/module-dflash.ts +4 -3
- package/src/spec/dspark/module.ts +3 -3
- package/src/spec/dspark/quantize-drafter.ts +1 -1
- package/src/spec/generate.ts +1 -1
- package/src/spec/glm52-mtp-source.ts +1 -1
- package/src/spec/ngram-source.ts +1 -1
- package/src/spec/prefix-state.ts +45 -0
- package/src/spec/qwen-mtp-source.ts +166 -69
- package/src/spec/serve-loop.ts +154 -156
- package/src/spec/source.ts +42 -10
- package/src/spec/two-model.ts +1 -1
- package/src/ssd-cache.ts +80 -12
- package/src/ssd-durability.ts +25 -13
- package/src/tool-call.ts +51 -14
- package/src/train/flash-cce.ts +2 -2
- package/src/train/forward.ts +6 -0
- package/src/train/loss.ts +1 -1
- package/src/train/prefix-shared.ts +5 -1
- package/src/train/segmented.ts +5 -3
- package/src/train/trainer.ts +6 -6
- package/src/vision/prompt.ts +1 -1
- package/src/vision/qwen3vl-tower.ts +52 -10
- package/src/web/app.html +1 -1
- package/src/web/app.js +5 -3
- package/src/web/src/adapters-panel.ts +3 -3
- package/src/web/src/assistant.ts +2 -36
- package/src/web/src/chat.ts +4 -4
- package/src/web/src/composer.ts +4 -4
- package/src/web/src/hub.ts +1 -1
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +1 -1
- package/src/web/src/model-picker.ts +1 -1
- package/src/web/src/palette.ts +1 -1
- package/src/web/src/protocol.ts +3 -39
- package/src/web/src/sessions.ts +1 -1
- package/src/web/src/ui-catalog.ts +4 -18
- package/src/web-assets.ts +47 -0
- package/src/weights.ts +55 -9
- package/docs/archive/investigations/curve-runs/bisector-route.json +0 -98
- package/docs/archive/investigations/curve-runs/bisector-trace.json +0 -1393
- package/docs/archive/investigations/curve-runs/curve-terrain.json +0 -1179
- package/docs/archive/investigations/curve-runs/curve-terrain.svg +0 -42
- package/docs/archive/investigations/hlg-ab.html +0 -34
- package/docs/archive/investigations/hlg-explorer.html +0 -238
- package/docs/archive/investigations/hlg-figs/cliff.svg +0 -1
- package/docs/archive/investigations/hlg-figs/cross.svg +0 -1
- package/docs/archive/investigations/hlg-figs/edges.svg +0 -1
- package/docs/archive/investigations/hlg-figs/k20-grids.svg +0 -1
- package/docs/archive/investigations/hlg-figs/k20-peaks.svg +0 -1
- package/docs/archive/investigations/hlg-figs/lw-curve.svg +0 -1
- package/docs/archive/investigations/hlg-figs/terrain.svg +0 -1
- package/docs/archive/investigations/hlg-report.html +0 -262
- package/docs/archive/investigations/hlg-runs/hlg-ab.json +0 -149
- package/docs/archive/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
- package/docs/archive/investigations/hlg-runs/hlg-blind.json +0 -107
- package/docs/archive/investigations/hlg-runs/hlg-cliff.json +0 -197
- package/docs/archive/investigations/hlg-runs/hlg-cross.json +0 -505
- package/docs/archive/investigations/hlg-runs/hlg-edge.json +0 -388
- package/docs/archive/investigations/hlg-runs/hlg-eval1.json +0 -25
- package/docs/archive/investigations/hlg-runs/hlg-frontier.json +0 -86
- package/docs/archive/investigations/hlg-runs/hlg-grid.json +0 -242
- package/docs/archive/investigations/hlg-runs/hlg-grid2.json +0 -343
- package/docs/archive/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
- package/docs/archive/investigations/hlg-runs/hlg-map.json +0 -383
- package/docs/archive/investigations/hlg-runs/run0-original.log +0 -159
- package/docs/archive/investigations/hlg-runs/runA-recommended.log +0 -131
- package/docs/archive/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
- package/docs/archive/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
- package/docs/archive/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
- package/docs/archive/investigations/hlg-runs/runAD-ab-samples.log +0 -8
- package/docs/archive/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
- package/docs/archive/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
- package/docs/archive/investigations/hlg-runs/runAG-eval-config2.log +0 -16
- package/docs/archive/investigations/hlg-runs/runB-gain-variants.log +0 -192
- package/docs/archive/investigations/hlg-runs/runC-pivots.log +0 -162
- package/docs/archive/investigations/hlg-runs/runD-oetf.log +0 -132
- package/docs/archive/investigations/hlg-runs/runE-eotf.log +0 -162
- package/docs/archive/investigations/hlg-runs/runF-shaper-working.log +0 -86
- package/docs/archive/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
- package/docs/archive/investigations/hlg-runs/runH-wsweep.log +0 -176
- package/docs/archive/investigations/hlg-runs/runI-asweep.log +0 -176
- package/docs/archive/investigations/hlg-runs/runJ-knobmap.log +0 -49
- package/docs/archive/investigations/hlg-runs/runK-frontier.log +0 -19
- package/docs/archive/investigations/hlg-runs/runL-widemap.log +0 -65
- package/docs/archive/investigations/hlg-runs/runM-frontier-emb.log +0 -15
- package/docs/archive/investigations/hlg-runs/runN-verify.log +0 -116
- package/docs/archive/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
- package/docs/archive/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
- package/docs/archive/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
- package/docs/archive/investigations/hlg-runs/runR-blind-transcript.log +0 -79
- package/docs/archive/investigations/hlg-runs/runS-cross-coherence.log +0 -33
- package/docs/archive/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
- package/docs/archive/investigations/hlg-runs/runU-cross-12b.log +0 -33
- package/docs/archive/investigations/hlg-runs/runV-lw-e4b.log +0 -22
- package/docs/archive/investigations/hlg-runs/runW-lw-12b.log +0 -22
- package/docs/archive/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
- package/docs/archive/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
- package/docs/archive/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
- package/docs/archive/mlx-bun-lab-report.html +0 -275
- package/docs/archive/wwdc-mlx-bun.html +0 -848
- package/docs/design/adapters-end-to-end.md +0 -205
- package/docs/design/batching-perf-path.md +0 -255
- package/docs/design/batching-v2-plan.md +0 -529
- package/docs/design/bucketing-stage.md +0 -197
- package/docs/design/compat-cli-surface-design.md +0 -230
- package/docs/design/docs-reorg-plan.md +0 -165
- package/docs/design/dspark-serving-program.md +0 -371
- package/docs/design/dspark-speculative-decoding.md +0 -318
- package/docs/design/grammar-spec-batching-integration.md +0 -301
- package/docs/design/memory-inference-path.md +0 -422
- package/docs/design/memory-synthesis.md +0 -287
- package/docs/design/memory-system.md +0 -237
- package/docs/design/mlx-lm-serving-execution-seam.md +0 -81
- package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
- package/docs/design/omlx-adoption-map.md +0 -98
- package/docs/design/orpo-dynamic-lambda.md +0 -220
- package/docs/design/orpo-future-enhancements.md +0 -340
- package/docs/design/paged-kv-cache.md +0 -214
- package/docs/design/parallel-slots.md +0 -567
- package/docs/design/parity-tier-dag.md +0 -161
- package/docs/design/repo-cleanup-plan.md +0 -231
- package/docs/design/runtime-isolation.md +0 -263
- package/docs/design/segmented-backward-training.md +0 -543
- package/docs/design/spec-decode-larger-targets.md +0 -229
- package/docs/design/ssd-kv-cold-tier.md +0 -415
- package/docs/design/structured-output.md +0 -484
- package/docs/design/tauri-desktop-app.md +0 -127
- package/docs/design/the-dreaming-master-plan.md +0 -445
- package/docs/design/turboquant-kv.md +0 -235
- package/docs/design/turboquant-weights.md +0 -467
- package/docs/design/w4a16-compute-precision-spike.md +0 -232
- package/docs/design/web-chat-beat-matrix.md +0 -315
- package/docs/design/write-pipeline-entity.md +0 -468
- package/docs/planning/IDEAS.md +0 -69
- package/docs/reference/embedding.md +0 -197
- package/docs/reference/features-matrix.md +0 -101
- package/docs/reference/orpo-quickstart.md +0 -135
- package/src/flags.ts +0 -11
- /package/docs/{design → archive/investigations}/colibri-glm52-port.md +0 -0
- /package/docs/{planning → archive/planning}/chunk-task-roadmap.md +0 -0
- /package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +0 -0
- /package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +0 -0
- /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.2.0.md +0 -0
- /package/src/{memory-plan.ts → admission-plan.ts} +0 -0
- /package/{docs/archive/investigations → src/serve/assets}/curve-terrain.html +0 -0
- /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
|
@@ -115,9 +115,42 @@ export class Qwen3VLVisionTower {
|
|
|
115
115
|
return names;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
/** Checkpoint-generation naming for the tower. Pre-5.8 artifacts store
|
|
119
|
+
* `vision_tower.*`; the transformers-5.8 export stores `model.visual.*`
|
|
120
|
+
* (mlx-lm's text-only qwen3_5 drops BOTH prefixes in `Model.sanitize`, so
|
|
121
|
+
* the mapping between them is ours). Verified 2026-09-01 across
|
|
122
|
+
* Qwen3.8-27B-tqalloc-norot vs the staged pre-5.8 artifact: 331/333
|
|
123
|
+
* tensors byte-identical under the rename, patch_embed.proj.weight
|
|
124
|
+
* identical under the layout permutation below, and merger.linear_fc2
|
|
125
|
+
* differs only because the staged artifact is rotation-folded. */
|
|
126
|
+
static #sourceName(canonical: string, prefix: string): string {
|
|
127
|
+
return prefix + canonical.slice("vision_tower.".length);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** HF stores the Conv3d patch embed as (out, in, kT, kH, kW); MLX (and this
|
|
131
|
+
* tower) want (out, kT, kH, kW, in). Proven a pure permutation on the
|
|
132
|
+
* artifacts above — transpose(0,2,3,4,1) of the 5.8 tensor is bit-equal to
|
|
133
|
+
* the pre-5.8 one. */
|
|
134
|
+
static #fixPatchEmbed(w: Map<string, MlxArray>): void {
|
|
135
|
+
const key = "vision_tower.patch_embed.proj.weight";
|
|
136
|
+
const a = w.get(key);
|
|
137
|
+
if (!a || a.shape.length !== 5) return;
|
|
138
|
+
if (a.shape[4] === 3) return; // already MLX layout
|
|
139
|
+
const t = ops.transposeAxes(a, [0, 2, 3, 4, 1]);
|
|
140
|
+
const c = ops.contiguous(t);
|
|
141
|
+
t.dispose();
|
|
142
|
+
a.dispose();
|
|
143
|
+
w.set(key, c);
|
|
144
|
+
}
|
|
145
|
+
|
|
118
146
|
/** Load one safetensors file's map and move `wanted` tensors into `out`
|
|
119
|
-
* (
|
|
120
|
-
|
|
147
|
+
* under their CANONICAL (`vision_tower.*`) names; `source` maps each
|
|
148
|
+
* canonical name to the stored one. Missing names are skipped; the map is
|
|
149
|
+
* always freed. */
|
|
150
|
+
static #takeFromFile(
|
|
151
|
+
path: string, wanted: string[], out: Map<string, MlxArray>,
|
|
152
|
+
source: (canonical: string) => string = (n) => n,
|
|
153
|
+
): void {
|
|
121
154
|
const arrMap = new BigUint64Array([C.mlx_map_string_to_array_new()]);
|
|
122
155
|
const metaMap = new BigUint64Array([C.mlx_map_string_to_string_new()]);
|
|
123
156
|
const arrMapPtr = ptr(arrMap);
|
|
@@ -136,7 +169,7 @@ export class Qwen3VLVisionTower {
|
|
|
136
169
|
if (out.has(name)) continue;
|
|
137
170
|
const slot = new BigUint64Array([C.mlx_array_new()]);
|
|
138
171
|
const slotPtr = ptr(slot);
|
|
139
|
-
if (C.mlx_map_string_to_array_get(slotPtr, handle, ptr(cstr(name))) !== 0) {
|
|
172
|
+
if (C.mlx_map_string_to_array_get(slotPtr, handle, ptr(cstr(source(name)))) !== 0) {
|
|
140
173
|
C.mlx_array_free(read.u64(slotPtr, 0));
|
|
141
174
|
continue;
|
|
142
175
|
}
|
|
@@ -156,28 +189,37 @@ export class Qwen3VLVisionTower {
|
|
|
156
189
|
// OptiQ-convention sidecar (their artifacts + ours pre-2026-08-18).
|
|
157
190
|
Qwen3VLVisionTower.#takeFromFile(sidecar, names, weights);
|
|
158
191
|
} else {
|
|
159
|
-
// In-main fallback: the bf16
|
|
192
|
+
// In-main fallback: the bf16 tower tensors live in the main
|
|
160
193
|
// safetensors shards (the mlx-vlm convention — one copy serves both
|
|
161
|
-
// ecosystems; sidecar duplication retired 2026-08-18).
|
|
194
|
+
// ecosystems; sidecar duplication retired 2026-08-18). The 5.8-family
|
|
195
|
+
// export names them `model.visual.*` instead of `vision_tower.*`.
|
|
162
196
|
const idxPath = `${modelDir}/model.safetensors.index.json`;
|
|
163
197
|
let files: string[];
|
|
198
|
+
let prefixes = ["vision_tower.", "model.visual."];
|
|
164
199
|
if (existsSync(idxPath)) {
|
|
165
200
|
const idx = JSON.parse(readFileSync(idxPath, "utf8")) as
|
|
166
201
|
{ weight_map: Record<string, string> };
|
|
167
|
-
|
|
168
|
-
names
|
|
169
|
-
)
|
|
202
|
+
prefixes = prefixes.filter((p) =>
|
|
203
|
+
Qwen3VLVisionTower.#sourceName(names[0]!, p) in idx.weight_map);
|
|
204
|
+
files = [...new Set(prefixes.flatMap((p) => names
|
|
205
|
+
.map((n) => idx.weight_map[Qwen3VLVisionTower.#sourceName(n, p)])
|
|
206
|
+
.filter((f): f is string => !!f)))];
|
|
170
207
|
if (files.length === 0)
|
|
171
|
-
throw new Error(`no
|
|
208
|
+
throw new Error(`no vision tower tensors in ${modelDir} (index has none)`);
|
|
172
209
|
} else {
|
|
173
210
|
files = ["model.safetensors"];
|
|
174
211
|
}
|
|
175
212
|
for (const f of files)
|
|
176
|
-
|
|
213
|
+
for (const p of prefixes)
|
|
214
|
+
Qwen3VLVisionTower.#takeFromFile(
|
|
215
|
+
`${modelDir}/${f}`, names, weights,
|
|
216
|
+
(n) => Qwen3VLVisionTower.#sourceName(n, p),
|
|
217
|
+
);
|
|
177
218
|
}
|
|
178
219
|
for (const name of names)
|
|
179
220
|
if (!weights.has(name))
|
|
180
221
|
throw new Error(`qwen vision weights missing tensor ${name} (sidecar or in-main)`);
|
|
222
|
+
Qwen3VLVisionTower.#fixPatchEmbed(weights);
|
|
181
223
|
} catch (e) {
|
|
182
224
|
for (const [, a] of weights) a.dispose();
|
|
183
225
|
throw e;
|
package/src/web/app.html
CHANGED
|
@@ -1216,7 +1216,7 @@
|
|
|
1216
1216
|
<!-- PWA installability (plan §9 Phase 3, beat-matrix Axis 10): manifest +
|
|
1217
1217
|
inline SVG icon (src/web/manifest.webmanifest, src/web/icon.svg — no
|
|
1218
1218
|
binary PNGs, per the hygiene gate; some browsers won't render an SVG
|
|
1219
|
-
app icon and that's an accepted tradeoff, see
|
|
1219
|
+
app icon and that's an accepted tradeoff, see docs/reference/server-config.md).
|
|
1220
1220
|
theme-color matches the app's --bg token so the OS chrome doesn't
|
|
1221
1221
|
flash a mismatched color on launch. -->
|
|
1222
1222
|
<link rel="manifest" href="/manifest.webmanifest">
|
package/src/web/app.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// GENERATED — do not edit by hand.
|
|
2
2
|
// Source: src/web/src/*.ts (entrypoint main.ts). To regenerate:
|
|
3
3
|
// bun scripts/build-web.ts
|
|
4
|
-
// tests/web-build.test.ts enforces that this file matches the source.
|
|
4
|
+
// tests/using/web-build.test.ts enforces that this file matches the source.
|
|
5
5
|
// src/web/src/api.ts
|
|
6
6
|
async function api(path, opts) {
|
|
7
7
|
const { body, ...rest } = opts || {};
|
|
@@ -2892,11 +2892,13 @@ function initMemoryPanel() {
|
|
|
2892
2892
|
maybeShowConsentCard();
|
|
2893
2893
|
}
|
|
2894
2894
|
|
|
2895
|
+
// src/contracts/pi.ts
|
|
2896
|
+
var APP_ROUTE_IDS = ["chat", "quantize", "finetune", "dataset", "status"];
|
|
2897
|
+
|
|
2895
2898
|
// src/web/src/ui-catalog.ts
|
|
2896
|
-
var ROUTE_IDS = ["chat", "quantize", "finetune", "dataset", "status"];
|
|
2897
2899
|
var VIEW_IDS = ["memory-panel", "hub-panel", "settings", "adapters-panel"];
|
|
2898
2900
|
function isRouteId(v) {
|
|
2899
|
-
return
|
|
2901
|
+
return APP_ROUTE_IDS.includes(v);
|
|
2900
2902
|
}
|
|
2901
2903
|
function isViewId(v) {
|
|
2902
2904
|
return VIEW_IDS.includes(v);
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
// docs/reference/server-api.md), with compatible-graying and a why-not
|
|
10
10
|
// tooltip. Actions: mount, select, unselect, and stack two compatible
|
|
11
11
|
// adapters as "a+b" — resolveSpec/injectAdapter already support composite
|
|
12
|
-
// ids end to end (proved in tests/pi-web.test.ts's stacking test; the
|
|
12
|
+
// ids end to end (proved in tests/research/pi-web.test.ts's stacking test; the
|
|
13
13
|
// shape-validated mount is proved against real weights in the
|
|
14
|
-
// MLX_BUN_TEST_LORA=1-gated tests/lora.test.ts).
|
|
14
|
+
// MLX_BUN_TEST_LORA=1-gated tests/parity/lora.test.ts).
|
|
15
15
|
//
|
|
16
16
|
// Single source of SELECTION state, not a single fetch: composer.ts's quick
|
|
17
17
|
// <select> and this table each hit /v1/adapters(+/available) independently
|
|
@@ -158,7 +158,7 @@ export function renderAdapterRow(
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
/** Full table body: a stack-mode toggle + composed-spec bar (when picks
|
|
161
|
-
* exist), then one section of rows. Exported so tests/web-app.test.ts can
|
|
161
|
+
* exist), then one section of rows. Exported so tests/using/web-app.test.ts can
|
|
162
162
|
* exercise esc() discipline without a live DOM/network. */
|
|
163
163
|
export function renderAdaptersBodyHtml(state: AdaptersPanelState): string {
|
|
164
164
|
if (!state.available.length) {
|
package/src/web/src/assistant.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { UiSnapshotElement, UiSnapshot, WizardStep } from "../../contracts/pi";
|
|
2
|
+
export type { UiSnapshotElement, UiSnapshot, WizardStep } from "../../contracts/pi";
|
|
1
3
|
// GENERATED-ADJACENT source module — part of the src/web/src/* split (plan
|
|
2
4
|
// §6.6 "the app-aware assistant", §9 Phase 3, beat matrix Axis 12). Built
|
|
3
5
|
// into src/web/app.js by scripts/build-web.ts.
|
|
@@ -26,42 +28,6 @@
|
|
|
26
28
|
|
|
27
29
|
import { getSpotlightTarget, isViewId, ROUTE_LABELS, type RouteId, type ViewId } from "./ui-catalog";
|
|
28
30
|
|
|
29
|
-
/* ────────────────────────────────────────────────────────────────────
|
|
30
|
-
1. SEE — the structured DOM snapshot
|
|
31
|
-
──────────────────────────────────────────────────────────────────── */
|
|
32
|
-
|
|
33
|
-
export interface UiSnapshotElement {
|
|
34
|
-
ref: string;
|
|
35
|
-
tag: string;
|
|
36
|
-
label: string;
|
|
37
|
-
kind: "interactive" | "region";
|
|
38
|
-
role?: string;
|
|
39
|
-
selector: string;
|
|
40
|
-
spotlightId?: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface UiSnapshot {
|
|
44
|
-
route: string;
|
|
45
|
-
capturedAt: string;
|
|
46
|
-
elements: UiSnapshotElement[];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** Process-state fields layered onto the snapshot (§6.6 "the snapshot
|
|
50
|
-
* carries process state, not just elements") — wizard step for the
|
|
51
|
-
* quantize/finetune/dataset wizards, when the current route has one.
|
|
52
|
-
* Derived by reading the DOM the step indicator already renders
|
|
53
|
-
* (markdown.ts's renderSteps into #q-steps/#f-steps/#d-steps + the
|
|
54
|
-
* [data-qstep]/[data-fstep]/[data-dstep] visibility toggle quantize.ts/
|
|
55
|
-
* finetune.ts/dataset.ts already do) rather than adding a callback hook to
|
|
56
|
-
* those three controllers — zero behavior change to files outside this
|
|
57
|
-
* wave's scope, and the DOM IS the source of truth those controllers
|
|
58
|
-
* already write to. */
|
|
59
|
-
export interface WizardStep {
|
|
60
|
-
index: number;
|
|
61
|
-
count: number;
|
|
62
|
-
label: string;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
31
|
const STEP_CONTAINER_BY_ROUTE: Partial<Record<RouteId, string>> = {
|
|
66
32
|
quantize: "q-steps",
|
|
67
33
|
finetune: "f-steps",
|
package/src/web/src/chat.ts
CHANGED
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
// typed, checkable seams between these concerns).
|
|
11
11
|
//
|
|
12
12
|
// Typed WS contract (plan §9 Phase 2 item 2): ClientMessage/ServerMessage
|
|
13
|
-
// and the history/session shapes are imported TYPE-ONLY from ../../pi
|
|
13
|
+
// and the history/session shapes are imported TYPE-ONLY from ../../contracts/pi
|
|
14
14
|
// so this module (and the whole bundle) contains zero server code — the
|
|
15
15
|
// bundler errors on bun:ffi if a value import ever sneaks in here, which is
|
|
16
16
|
// the intended guard (see scripts/build-web.ts).
|
|
17
17
|
|
|
18
18
|
import type {
|
|
19
19
|
ClientMessage, HistoryItem, ReadyGenDefaults, ServerMessage, SessionListItem,
|
|
20
|
-
} from "../../pi
|
|
21
|
-
import type { Lane } from "../../
|
|
20
|
+
} from "../../contracts/pi";
|
|
21
|
+
import type { Lane } from "../../contracts/pi";
|
|
22
22
|
import {
|
|
23
23
|
$, el, toast, currentRoute, closeDrawer,
|
|
24
24
|
storedCodingToolsPreference, renderCodingToolsState, renderToolApprovals,
|
|
@@ -44,7 +44,7 @@ import { isRouteId } from "./ui-catalog";
|
|
|
44
44
|
|
|
45
45
|
/* ────────────────────────────────────────────────────────────────────
|
|
46
46
|
Chat-with-files RAG v1 — Sources panel (plan §9 Phase 3, beat matrix
|
|
47
|
-
Axis 5). Pure HTML builder so tests/web-app.test.ts can exercise the
|
|
47
|
+
Axis 5). Pure HTML builder so tests/using/web-app.test.ts can exercise the
|
|
48
48
|
esc() discipline directly, same reasoning as renderAdapterOptionsHtml
|
|
49
49
|
etc. in composer.ts.
|
|
50
50
|
──────────────────────────────────────────────────────────────────── */
|
package/src/web/src/composer.ts
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
// the original single IIFE), but every WS send goes through a callback
|
|
11
11
|
// passed in from chat.ts, which owns the actual WebSocket.
|
|
12
12
|
|
|
13
|
-
import type { ReadyGenDefaults, SamplingOverrides } from "../../pi
|
|
14
|
-
import type { Lane } from "../../
|
|
13
|
+
import type { ReadyGenDefaults, SamplingOverrides } from "../../contracts/pi";
|
|
14
|
+
import type { Lane } from "../../contracts/pi";
|
|
15
15
|
import { api } from "./api";
|
|
16
16
|
import type { ApiEnvelope } from "./protocol";
|
|
17
17
|
import {
|
|
@@ -200,7 +200,7 @@ function escHtml(s: unknown): string {
|
|
|
200
200
|
|
|
201
201
|
/** Pure: builds the <option> markup for the adapter <select> from the
|
|
202
202
|
* /v1/adapters/available list. Split out from refreshAdapters() (which
|
|
203
|
-
* does the fetch + DOM write) so tests/web-app.test.ts can exercise the
|
|
203
|
+
* does the fetch + DOM write) so tests/using/web-app.test.ts can exercise the
|
|
204
204
|
* esc() discipline on this template directly without a DOM or network —
|
|
205
205
|
* every interpolated field (id, rank, path, base_model) must be escaped,
|
|
206
206
|
* since adapter ids/paths are user-controlled (on-disk directory names). */
|
|
@@ -719,7 +719,7 @@ export function renderLane(lane: Lane | undefined): void {
|
|
|
719
719
|
already resolves, so the agent's memory tools pick it up naturally, same
|
|
720
720
|
as in the vault's own prose). No vault -> files-only picker. Pure
|
|
721
721
|
query-detection/insertion helpers below are unit-tested directly
|
|
722
|
-
(tests/web-app.test.ts); DOM wiring (initMentionPicker) owns the
|
|
722
|
+
(tests/using/web-app.test.ts); DOM wiring (initMentionPicker) owns the
|
|
723
723
|
picker's open/close/keyboard-nav state.
|
|
724
724
|
──────────────────────────────────────────────────────────────────── */
|
|
725
725
|
|
package/src/web/src/hub.ts
CHANGED
|
@@ -119,7 +119,7 @@ function localRowHtml(m: HubLocalRow): string {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
/** Pure render, exported for esc()-discipline + empty-state tests
|
|
122
|
-
* (tests/web-app.test.ts, mirroring renderModelPopBodyHtml's pattern). */
|
|
122
|
+
* (tests/using/web-app.test.ts, mirroring renderModelPopBodyHtml's pattern). */
|
|
123
123
|
export function renderHubLocalHtml(models: HubLocalRow[]): string {
|
|
124
124
|
if (!models.length) {
|
|
125
125
|
return '<div class="hub-empty">No models downloaded yet — search Hugging Face below to get one.</div>';
|
package/src/web/src/markdown.ts
CHANGED
|
Binary file
|
|
@@ -394,7 +394,7 @@ export async function refreshSidebarEntry(): Promise<void> {
|
|
|
394
394
|
// by a literal list rather than an import: this module must stay
|
|
395
395
|
// server-code-free (bundler-enforced, see chat.ts's header comment), so it
|
|
396
396
|
// can't import a value from src/memory/tools.ts even though the identifiers
|
|
397
|
-
// are the same. tests/web-app.test.ts cross-checks this list against the
|
|
397
|
+
// are the same. tests/using/web-app.test.ts cross-checks this list against the
|
|
398
398
|
// real export so drift is caught at test time instead of silently.
|
|
399
399
|
export const MEMORY_CHIP_TOOL_NAMES = [
|
|
400
400
|
"memory_resolve", "memory_category", "memory_read", "memory_section",
|
|
@@ -85,7 +85,7 @@ function renderRow(m: LibraryRow): string {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/** Pure render of the popover body from a /library response. Exported for
|
|
88
|
-
* tests/web-app.test.ts's esc() discipline check (repo ids are
|
|
88
|
+
* tests/using/web-app.test.ts's esc() discipline check (repo ids are
|
|
89
89
|
* user-controlled HF strings — the same class of interpolation hazard
|
|
90
90
|
* finding #15 flagged for the adapter dropdown). */
|
|
91
91
|
export function renderModelPopBodyHtml(models: LibraryRow[]): string {
|
package/src/web/src/palette.ts
CHANGED
|
@@ -39,7 +39,7 @@ interface PaletteAction {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/** Pure: the static action list, independent of any live session data —
|
|
42
|
-
* independently testable (tests/web-app.test.ts asserts labels/ids without
|
|
42
|
+
* independently testable (tests/using/web-app.test.ts asserts labels/ids without
|
|
43
43
|
* needing a DOM). Session rows and message-search hits are appended
|
|
44
44
|
* dynamically in refreshResults() below, not part of this list. */
|
|
45
45
|
export function staticActions(): PaletteAction[] {
|
package/src/web/src/protocol.ts
CHANGED
|
@@ -1,47 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// ServerMessage / HistoryItem / SessionListItem / ReadyGenDefaults) is
|
|
4
|
-
// imported type-only from ../../pi-web — see chat.ts. This file only holds
|
|
5
|
-
// shapes with no server-side export to anchor to (e.g. the SSE job-stream
|
|
6
|
-
// events, which live as a doc-comment in app.html today, not a type).
|
|
7
|
-
//
|
|
8
|
-
// Pointer comment for the server side: src/web/src/protocol.ts mirrors the
|
|
9
|
-
// SSE line protocol documented at the jobStream() call site (api.ts) —
|
|
10
|
-
// keep the two adjacent if the job event shape changes server-side
|
|
11
|
-
// (scripts/ that emit `data:` lines for /api/jobs/:id/stream).
|
|
12
|
-
|
|
13
|
-
/** One line of the /api/jobs/:id/stream SSE protocol (JSON per `data:` line). */
|
|
14
|
-
export type JobEvent =
|
|
15
|
-
| { type: "log"; line: string }
|
|
16
|
-
| {
|
|
17
|
-
type: "stage";
|
|
18
|
-
stage: string;
|
|
19
|
-
progress?: number;
|
|
20
|
-
message?: string;
|
|
21
|
-
output_dir?: string;
|
|
22
|
-
adapter_path?: string;
|
|
23
|
-
// Dataset-generation-specific row counts (present on the dataset
|
|
24
|
-
// builder's job stream only; absent/ignored for quantize/finetune).
|
|
25
|
-
n_train?: number;
|
|
26
|
-
n_valid?: number;
|
|
27
|
-
}
|
|
28
|
-
| {
|
|
29
|
-
type: "metric";
|
|
30
|
-
kind: "train" | "val";
|
|
31
|
-
step: number;
|
|
32
|
-
loss: number;
|
|
33
|
-
learning_rate?: number;
|
|
34
|
-
tokens_per_sec?: number;
|
|
35
|
-
progress?: number;
|
|
36
|
-
message?: string;
|
|
37
|
-
}
|
|
38
|
-
| { type: "done"; n_train?: number; n_valid?: number }
|
|
39
|
-
| { type: "failed"; error?: string };
|
|
1
|
+
import type { JobEvent } from "../../contracts/jobs";
|
|
2
|
+
export type { JobEvent } from "../../contracts/jobs";
|
|
40
3
|
|
|
41
4
|
/** Handlers passed to jobStream(); each key is an optional callback for the
|
|
42
5
|
* matching JobEvent variant, plus an `error` callback for the EventSource's
|
|
43
6
|
* own onerror (transport failure, not a `failed` protocol event). */
|
|
44
7
|
export interface JobStreamHandlers {
|
|
8
|
+
started?: (e: Extract<JobEvent, { type: "started" }>) => void;
|
|
45
9
|
log?: (e: Extract<JobEvent, { type: "log" }>) => void;
|
|
46
10
|
stage?: (e: Extract<JobEvent, { type: "stage" }>) => void;
|
|
47
11
|
metric?: (e: Extract<JobEvent, { type: "metric" }>) => void;
|
package/src/web/src/sessions.ts
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
// wires each rendered `.sess` row's click to `onOpen` below — this just
|
|
21
21
|
// finds and clicks the right row instead of duplicating that send()).
|
|
22
22
|
|
|
23
|
-
import type { SessionListItem } from "../../pi
|
|
23
|
+
import type { SessionListItem } from "../../contracts/pi";
|
|
24
24
|
import { $, el, injectStyles } from "./shell";
|
|
25
25
|
import { api } from "./api";
|
|
26
26
|
|
|
@@ -2,28 +2,14 @@
|
|
|
2
2
|
// §7/§9 Phase 3, §6.6 "app-aware assistant"). Built into src/web/app.js by
|
|
3
3
|
// scripts/build-web.ts.
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// ui-catalog.ts + server/src/agent/ui-catalog.ts, read together with
|
|
8
|
-
// server/src/agent/portfolio-tools.ts as the reference implementation) but
|
|
9
|
-
// inlined as a TS module (not a shared JSON file) since mlx-bun's server and
|
|
10
|
-
// browser bundles are separate build outputs (scripts/build-web.ts vs bun's
|
|
11
|
-
// own TS execution) with no shared-JSON-import convention today — pi-web.ts
|
|
12
|
-
// mirrors ROUTE_IDS/SPOTLIGHT_TARGETS as plain string arrays for its own
|
|
13
|
-
// server-side validation (navigate_app/spotlight_ui reject anything not in
|
|
14
|
-
// that list BEFORE touching the browser) so route validity is checked at
|
|
15
|
-
// both ends without a build-time shared asset.
|
|
16
|
-
//
|
|
17
|
-
// Keep this list's ROUTE_IDS in sync with shell.ts's ROUTES tuple (chat,
|
|
18
|
-
// quantize, finetune, dataset, status) plus the Developer-only overlays that
|
|
19
|
-
// aren't hash-routes (memory panel, hub panel, settings) — those are
|
|
20
|
-
// `view`s, not `route`s (see UiContext.view below), reached by opening an
|
|
21
|
-
// overlay rather than changing the URL hash.
|
|
5
|
+
// Shared route IDs keep browser navigation and server validation in agreement.
|
|
6
|
+
// Spotlight selectors and overlay IDs belong to the browser.
|
|
22
7
|
|
|
23
8
|
/** A hash-routed page (shell.ts's Route union, minus "routes" — the DAG
|
|
24
9
|
* diagram tab isn't a useful assistant destination and is itself
|
|
25
10
|
* feature-detected/hidden when unavailable). */
|
|
26
|
-
|
|
11
|
+
import { APP_ROUTE_IDS as ROUTE_IDS } from "../../contracts/pi";
|
|
12
|
+
export { ROUTE_IDS };
|
|
27
13
|
export type RouteId = (typeof ROUTE_IDS)[number];
|
|
28
14
|
|
|
29
15
|
/** A non-route overlay/panel the assistant can navigate to or spotlight
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Embedded web app — the unified SPA (chat / quantize / finetune /
|
|
2
|
+
// dataset / status). `with { type: "text" }` inlines the file in both
|
|
3
|
+
// `bun run` and the compiled single binary. bun-types types *.html
|
|
4
|
+
// imports as HTMLBundle (the html loader), but the text attribute makes
|
|
5
|
+
// the runtime value a string — hence the double cast.
|
|
6
|
+
import appHtml from "./web/app.html" with { type: "text" };
|
|
7
|
+
import curveDesignerHtml from "./lab/curve/curve-designer.html" with { type: "text" };
|
|
8
|
+
// Vendored, no-CDN static assets referenced by app.html (convention: any
|
|
9
|
+
// self-contained JS/CSS too big to inline gets `with { type: "text" }`
|
|
10
|
+
// imported here and served under /assets/<name>; see src/web/vendor/README
|
|
11
|
+
// for how hljs.js was built). Add new vendored assets the same way.
|
|
12
|
+
import hljsJs from "./web/vendor/hljs.js" with { type: "text" };
|
|
13
|
+
import hljsCss from "./web/vendor/hljs-theme.css" with { type: "text" };
|
|
14
|
+
// The frontend bundle (plan §7/§9 Phase 2 module split): GENERATED from
|
|
15
|
+
// src/web/src/*.ts by `bun scripts/build-web.ts` — see that file's header
|
|
16
|
+
// and tests/using/web-build.test.ts (the freshness gate). Same
|
|
17
|
+
// with { type: "text" } + /assets/<name> pattern as the vendored assets
|
|
18
|
+
// above; app.html's <script defer src="/assets/app.js"> loads it.
|
|
19
|
+
import appJs from "./web/app.js" with { type: "text" };
|
|
20
|
+
// PWA installability (plan §9 Phase 3, beat-matrix Axis 10): a manifest +
|
|
21
|
+
// a single inline SVG icon (no binary PNGs — the hygiene gate forbids
|
|
22
|
+
// tracked binary files; some browsers won't show an SVG app icon, which is
|
|
23
|
+
// an accepted tradeoff, see docs/reference/server-config.md) + a shell-
|
|
24
|
+
// only service worker. Same with { type: "text" } + /assets/<name>-shaped
|
|
25
|
+
// pattern as the vendored assets above; see src/web/sw.js's header for why
|
|
26
|
+
// it deliberately does NOT cache API/WS traffic.
|
|
27
|
+
import manifestWebmanifest from "./web/manifest.webmanifest" with { type: "text" };
|
|
28
|
+
import iconSvg from "./web/icon.svg" with { type: "text" };
|
|
29
|
+
import swJs from "./web/sw.js" with { type: "text" };
|
|
30
|
+
const APP_PAGE = appHtml as unknown as string;
|
|
31
|
+
const HLJS_JS = hljsJs as unknown as string;
|
|
32
|
+
const HLJS_CSS = hljsCss as unknown as string;
|
|
33
|
+
const APP_JS = appJs as unknown as string;
|
|
34
|
+
const MANIFEST_WEBMANIFEST = manifestWebmanifest as unknown as string;
|
|
35
|
+
const ICON_SVG = iconSvg as unknown as string;
|
|
36
|
+
const SW_JS = swJs as unknown as string;
|
|
37
|
+
const CURVE_PAGE = curveDesignerHtml as unknown as string;
|
|
38
|
+
export const STATIC_ROUTE_ASSETS = {
|
|
39
|
+
appPage: APP_PAGE,
|
|
40
|
+
appJs: APP_JS,
|
|
41
|
+
hljsJs: HLJS_JS,
|
|
42
|
+
hljsCss: HLJS_CSS,
|
|
43
|
+
manifest: MANIFEST_WEBMANIFEST,
|
|
44
|
+
iconSvg: ICON_SVG,
|
|
45
|
+
serviceWorker: SW_JS,
|
|
46
|
+
curvePage: CURVE_PAGE,
|
|
47
|
+
};
|
package/src/weights.ts
CHANGED
|
@@ -59,12 +59,30 @@ const NATIVE_WEIGHTS: WeightsNativeBindings = {
|
|
|
59
59
|
),
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Checkpoint-generation normalization, installed once at load.
|
|
64
|
+
*
|
|
65
|
+
* `names` maps the GRAPH's canonical tensor name onto the name the artifact
|
|
66
|
+
* actually stores; a canonical name absent from the map does not exist (the
|
|
67
|
+
* same way a reference `sanitize()` drops a tensor). `fixup` is an optional
|
|
68
|
+
* lazy value repair applied to the loaded array — return null to keep it.
|
|
69
|
+
*
|
|
70
|
+
* Weights only APPLIES a view; the rules belong to the architecture that owns
|
|
71
|
+
* the naming (see `qwen35WeightsView` in model/qwen3_5-checkpoint.ts).
|
|
72
|
+
*/
|
|
73
|
+
export interface WeightsView {
|
|
74
|
+
readonly names: ReadonlyMap<string, string>;
|
|
75
|
+
fixup?(canonical: string, arr: MlxArray): MlxArray | null;
|
|
76
|
+
}
|
|
77
|
+
|
|
62
78
|
export class Weights {
|
|
63
79
|
readonly shards: ShardedSafetensors;
|
|
64
80
|
/** shard filename → native mlx map handle (string → lazy array). */
|
|
65
81
|
readonly #maps = new Map<string, bigint>();
|
|
82
|
+
/** Cached arrays, keyed by CANONICAL name (post-view). */
|
|
66
83
|
readonly #arrays = new Map<string, MlxArray>();
|
|
67
84
|
readonly #native: WeightsNativeBindings;
|
|
85
|
+
#view: WeightsView | null = null;
|
|
68
86
|
|
|
69
87
|
private constructor(
|
|
70
88
|
shards: ShardedSafetensors,
|
|
@@ -120,6 +138,19 @@ export class Weights {
|
|
|
120
138
|
}
|
|
121
139
|
}
|
|
122
140
|
|
|
141
|
+
/** Install the checkpoint normalization. Must precede the first tensor()
|
|
142
|
+
* call: the array cache and every shard lookup below are keyed through it. */
|
|
143
|
+
setView(view: WeightsView): void {
|
|
144
|
+
if (this.#arrays.size > 0)
|
|
145
|
+
throw new Error("Weights.setView after tensors were materialized");
|
|
146
|
+
this.#view = view;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Canonical name → the stored name (identity when no view is installed). */
|
|
150
|
+
#source(name: string): string {
|
|
151
|
+
return this.#view ? this.#view.names.get(name) ?? name : name;
|
|
152
|
+
}
|
|
153
|
+
|
|
123
154
|
/** Free one shard's native map AND every cached tensor from it, releasing
|
|
124
155
|
* all bytes materialized while consuming that shard. The shard transparently
|
|
125
156
|
* re-opens on the next tensor() touching it (header parse only — lazy).
|
|
@@ -130,7 +161,7 @@ export class Weights {
|
|
|
130
161
|
const sf = this.shards.files.get(file);
|
|
131
162
|
if (!sf) return;
|
|
132
163
|
for (const [name, arr] of this.#arrays) {
|
|
133
|
-
if (this.shards.tensorToFile.get(name) === sf) {
|
|
164
|
+
if (this.shards.tensorToFile.get(this.#source(name)) === sf) {
|
|
134
165
|
arr.dispose();
|
|
135
166
|
this.#arrays.delete(name);
|
|
136
167
|
}
|
|
@@ -144,29 +175,36 @@ export class Weights {
|
|
|
144
175
|
|
|
145
176
|
/** The shard filename holding `name` (for releaseShard scheduling). */
|
|
146
177
|
fileOf(name: string): string | undefined {
|
|
147
|
-
const sf = this.shards.tensorToFile.get(name);
|
|
178
|
+
const sf = this.shards.tensorToFile.get(this.#source(name));
|
|
148
179
|
if (!sf) return undefined;
|
|
149
180
|
for (const [file, cand] of this.shards.files) if (cand === sf) return file;
|
|
150
181
|
return undefined;
|
|
151
182
|
}
|
|
152
183
|
|
|
184
|
+
/** Canonical names — with a view installed, exactly the tensors the graph
|
|
185
|
+
* can ask for (renamed, drops excluded). */
|
|
153
186
|
get tensorNames(): string[] {
|
|
154
|
-
return this.shards.tensorNames;
|
|
187
|
+
return this.#view ? [...this.#view.names.keys()] : this.shards.tensorNames;
|
|
155
188
|
}
|
|
156
189
|
|
|
157
190
|
info(name: string): TensorInfo {
|
|
158
|
-
return this.shards.info(name);
|
|
191
|
+
return this.shards.info(this.#source(name));
|
|
159
192
|
}
|
|
160
193
|
|
|
161
194
|
has(name: string): boolean {
|
|
162
|
-
return this
|
|
195
|
+
return this.#view
|
|
196
|
+
? this.#view.names.has(name)
|
|
197
|
+
: this.shards.tensorToFile.has(name);
|
|
163
198
|
}
|
|
164
199
|
|
|
165
|
-
/** Lazy mlx array for a tensor; cached per name. */
|
|
200
|
+
/** Lazy mlx array for a tensor; cached per canonical name. */
|
|
166
201
|
tensor(name: string): MlxArray {
|
|
167
202
|
let arr = this.#arrays.get(name);
|
|
168
203
|
if (!arr) {
|
|
169
|
-
|
|
204
|
+
if (this.#view && !this.#view.names.has(name))
|
|
205
|
+
throw new Error(`no tensor named ${name}`);
|
|
206
|
+
const source = this.#source(name);
|
|
207
|
+
const sf = this.shards.tensorToFile.get(source);
|
|
170
208
|
if (!sf) throw new Error(`no tensor named ${name}`);
|
|
171
209
|
let entry = [...this.#maps.entries()]
|
|
172
210
|
.find(([file]) => this.shards.files.get(file) === sf);
|
|
@@ -179,9 +217,17 @@ export class Weights {
|
|
|
179
217
|
const mapHandle = entry[1];
|
|
180
218
|
const slot = new BigUint64Array([C.mlx_array_new()]);
|
|
181
219
|
const slotPtr = ptr(slot);
|
|
182
|
-
if (C.mlx_map_string_to_array_get(slotPtr, mapHandle, ptr(cstr(
|
|
183
|
-
throw new Error(`tensor ${
|
|
220
|
+
if (C.mlx_map_string_to_array_get(slotPtr, mapHandle, ptr(cstr(source))) !== 0)
|
|
221
|
+
throw new Error(`tensor ${source} missing from native map`);
|
|
184
222
|
arr = new MlxArray(read.u64(slotPtr, 0));
|
|
223
|
+
// Value repair (γ−1 → γ, conv layout): the fixed array is a lazy graph
|
|
224
|
+
// node over the source, so the raw handle is released immediately — the
|
|
225
|
+
// node keeps its own reference to the underlying data.
|
|
226
|
+
const fixed = this.#view?.fixup?.(name, arr) ?? null;
|
|
227
|
+
if (fixed) {
|
|
228
|
+
arr.dispose();
|
|
229
|
+
arr = fixed;
|
|
230
|
+
}
|
|
185
231
|
this.#arrays.set(name, arr);
|
|
186
232
|
}
|
|
187
233
|
return arr;
|