mlx-bun 0.0.13 → 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 -578
- package/bin/mlx-bun.mjs +1 -1
- package/docs/README.md +91 -0
- package/docs/{design → archive}/hlg-sampling.md +3 -3
- package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
- package/docs/{design → archive/investigations}/colibri-glm52-port.md +1 -1
- package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
- package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
- package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
- package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
- package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
- package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
- package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
- package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
- package/docs/{planning → archive/planning}/chunk-task-roadmap.md +1 -1
- package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +4 -4
- package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +1 -1
- package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
- package/docs/archive/planning/release-notes-v0.2.0.md +49 -0
- package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
- 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 +421 -0
- package/docs/reference/benchmarks.md +1162 -0
- package/docs/reference/cli.md +395 -149
- package/docs/reference/distribution.md +321 -181
- package/docs/reference/environment.md +348 -0
- package/docs/reference/glossary.md +39 -0
- package/docs/reference/library-api.md +580 -142
- package/docs/reference/memory.md +227 -64
- package/docs/reference/models.md +137 -6
- package/docs/reference/server-api.md +938 -422
- package/docs/reference/server-config.md +652 -320
- package/docs/reference/training.md +393 -254
- package/docs/reference/troubleshooting.md +166 -0
- package/package.json +10 -5
- package/src/admission-plan.ts +18 -0
- package/src/anthropic.ts +92 -3
- 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 +189 -61
- 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 +263 -23
- package/src/eval/reference-logits.ts +207 -0
- package/src/eval/runner.ts +10 -79
- package/src/eval/tasks/bfcl.ts +2 -1
- package/src/eval/tasks/gsm8k.ts +2 -1
- package/src/eval/tasks/hashhop.ts +2 -1
- package/src/eval/tasks/humaneval.ts +5 -4
- package/src/eval/tasks/ifeval.ts +2 -1
- package/src/eval/tasks/mmlu.ts +2 -1
- package/src/expert-io.ts +3 -1
- package/src/expert-offload.ts +3 -1
- 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 +24 -43
- package/src/generate.ts +740 -337
- package/src/grammar.ts +14 -8
- package/src/harness-pi.ts +15 -34
- package/src/hub-rest.ts +4 -4
- package/src/index.ts +27 -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 +15 -14
- 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-scheme.ts +199 -0
- package/src/kv-store.ts +459 -234
- 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} +7 -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 +20 -4
- package/src/memory/article.ts +1 -1
- package/src/memory/chunk.ts +1 -1
- package/src/memory/model.ts +32 -170
- 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 +3 -4
- package/src/mlx/array.ts +9 -10
- package/src/mlx/compile.ts +12 -2
- package/src/mlx/ffi.ts +66 -22
- package/src/mlx/materialize.ts +23 -0
- package/src/mlx/metal-kernel.ts +10 -11
- package/src/mlx/ops.ts +64 -19
- 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 +9 -3
- package/src/model/batched-quant.ts +2 -2
- package/src/model/batched-rotating-quant.ts +45 -99
- package/src/model/batched-rotating-state.ts +73 -0
- package/src/model/batched-rotating.ts +57 -106
- package/src/model/batched-row-storage.ts +127 -0
- package/src/model/compiled-decode.ts +4 -3
- package/src/model/diffusion-gemma.ts +8 -8
- package/src/model/factory.ts +87 -49
- package/src/model/fingerprint.ts +1 -1
- package/src/model/flash-attention.ts +3 -3
- package/src/model/gemma4-base.ts +187 -17
- package/src/model/gemma4.ts +6 -6
- package/src/model/generated/gemma4-12b.ts +52 -148
- package/src/model/generated/gemma4-26b.ts +34 -94
- package/src/model/generated/gemma4-e4b.ts +28 -76
- package/src/model/glm52-cache.ts +19 -9
- package/src/model/glm52-dsa.ts +13 -9
- package/src/model/glm52-memory.ts +28 -1
- package/src/model/implementation.ts +69 -0
- package/src/model/minicpm5.ts +7 -8
- package/src/model/profile.ts +443 -0
- package/src/model/qwen-append.ts +12 -0
- package/src/model/qwen-conv.ts +52 -0
- package/src/model/qwen3-delta.ts +98 -2
- package/src/model/qwen3-mrope.ts +252 -0
- package/src/model/qwen3_5-checkpoint.ts +164 -0
- package/src/model/qwen3_5.ts +336 -60
- 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/frame_extract.swift +140 -0
- package/src/native-pack.ts +15 -7
- package/src/pi-provider.ts +6 -64
- package/src/pi-web.ts +14 -320
- package/src/prompt-cache.ts +97 -54
- package/src/quantize/allocator.ts +1 -1
- package/src/quantize/atomic-output.ts +38 -0
- package/src/quantize/calibration.ts +2 -1
- package/src/quantize/config-writer.ts +16 -3
- package/src/quantize/index.ts +28 -1
- package/src/quantize/job.ts +11 -0
- package/src/quantize/quantizer.ts +265 -100
- package/src/quantize/rotate.ts +603 -0
- package/src/quantize/safetensors-writer.ts +79 -1
- package/src/quantize/sensitivity.ts +41 -59
- package/src/quantize/trellis.ts +586 -0
- package/src/quantize/weight-transform.ts +292 -0
- package/src/responses.ts +130 -3
- package/src/runtime-config.ts +81 -0
- package/src/sampler.ts +276 -4
- package/src/serve/admin-routes.ts +184 -0
- package/src/serve/aux-routes.ts +132 -0
- package/src/serve/batch-scheduler.ts +8 -1558
- 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 +354 -0
- package/src/serve/completion-sink.ts +157 -0
- package/src/serve/discovery-routes.ts +204 -0
- package/src/serve/generation-gateway.ts +211 -243
- 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/kv-budget.ts +14 -0
- package/src/serve/lab-routes.ts +341 -0
- package/src/serve/lane-registry.ts +2 -1
- package/src/serve/model-admin-routes.ts +155 -0
- 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/prompt-response-trace.ts +147 -0
- package/src/serve/request-plan.ts +162 -0
- 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 +101 -0
- package/src/serve/text-completion-stage.ts +104 -0
- package/src/serve/token-streams.ts +519 -0
- package/src/server.ts +523 -3551
- package/src/spec/assistant-source.ts +10 -44
- package/src/spec/deepspec-source.ts +6 -6
- package/src/spec/dflash-source.ts +9 -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 +5 -4
- 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 +9 -1
- package/src/spec/ngram-source.ts +1 -1
- package/src/spec/prefix-state.ts +45 -0
- package/src/spec/qwen-mtp-source.ts +528 -0
- package/src/spec/serve-loop.ts +179 -213
- package/src/spec/source.ts +42 -10
- package/src/spec/two-model.ts +1 -1
- package/src/ssd-cache.ts +95 -24
- package/src/ssd-durability.ts +207 -0
- package/src/tool-call.ts +51 -14
- package/src/train/flash-cce.ts +14 -13
- package/src/train/forward.ts +38 -1
- package/src/train/loss.ts +3 -2
- package/src/train/prefix-shared.ts +5 -1
- package/src/train/segmented.ts +9 -6
- package/src/train/trainer.ts +9 -8
- package/src/vision/preprocess.ts +1 -1
- package/src/vision/prompt.ts +48 -2
- package/src/vision/qwen3vl-preprocess.ts +409 -0
- package/src/vision/qwen3vl-prompt.ts +196 -0
- package/src/vision/qwen3vl-tower.ts +555 -0
- package/src/vision/video-frames.ts +148 -0
- package/src/web/app.html +1 -1
- package/src/web/app.js +15 -6
- package/src/web/src/adapters-panel.ts +3 -3
- package/src/web/src/assistant.ts +2 -36
- package/src/web/src/chat.ts +16 -9
- 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 +134 -33
- 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 -268
- 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-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 -189
- 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 -288
- 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/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/investigations/curve-runs/bisector-route.json +0 -98
- package/docs/investigations/curve-runs/bisector-trace.json +0 -1393
- package/docs/investigations/curve-runs/curve-terrain.json +0 -1179
- package/docs/investigations/curve-runs/curve-terrain.svg +0 -42
- package/docs/investigations/hlg-ab.html +0 -34
- package/docs/investigations/hlg-explorer.html +0 -238
- package/docs/investigations/hlg-figs/cliff.svg +0 -1
- package/docs/investigations/hlg-figs/cross.svg +0 -1
- package/docs/investigations/hlg-figs/edges.svg +0 -1
- package/docs/investigations/hlg-figs/k20-grids.svg +0 -1
- package/docs/investigations/hlg-figs/k20-peaks.svg +0 -1
- package/docs/investigations/hlg-figs/lw-curve.svg +0 -1
- package/docs/investigations/hlg-figs/terrain.svg +0 -1
- package/docs/investigations/hlg-report.html +0 -262
- package/docs/investigations/hlg-runs/hlg-ab.json +0 -149
- package/docs/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
- package/docs/investigations/hlg-runs/hlg-blind.json +0 -107
- package/docs/investigations/hlg-runs/hlg-cliff.json +0 -197
- package/docs/investigations/hlg-runs/hlg-cross.json +0 -505
- package/docs/investigations/hlg-runs/hlg-edge.json +0 -388
- package/docs/investigations/hlg-runs/hlg-eval1.json +0 -25
- package/docs/investigations/hlg-runs/hlg-frontier.json +0 -86
- package/docs/investigations/hlg-runs/hlg-grid.json +0 -242
- package/docs/investigations/hlg-runs/hlg-grid2.json +0 -343
- package/docs/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
- package/docs/investigations/hlg-runs/hlg-map.json +0 -383
- package/docs/investigations/hlg-runs/run0-original.log +0 -159
- package/docs/investigations/hlg-runs/runA-recommended.log +0 -131
- package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
- package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
- package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
- package/docs/investigations/hlg-runs/runAD-ab-samples.log +0 -8
- package/docs/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
- package/docs/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
- package/docs/investigations/hlg-runs/runAG-eval-config2.log +0 -16
- package/docs/investigations/hlg-runs/runB-gain-variants.log +0 -192
- package/docs/investigations/hlg-runs/runC-pivots.log +0 -162
- package/docs/investigations/hlg-runs/runD-oetf.log +0 -132
- package/docs/investigations/hlg-runs/runE-eotf.log +0 -162
- package/docs/investigations/hlg-runs/runF-shaper-working.log +0 -86
- package/docs/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
- package/docs/investigations/hlg-runs/runH-wsweep.log +0 -176
- package/docs/investigations/hlg-runs/runI-asweep.log +0 -176
- package/docs/investigations/hlg-runs/runJ-knobmap.log +0 -49
- package/docs/investigations/hlg-runs/runK-frontier.log +0 -19
- package/docs/investigations/hlg-runs/runL-widemap.log +0 -65
- package/docs/investigations/hlg-runs/runM-frontier-emb.log +0 -15
- package/docs/investigations/hlg-runs/runN-verify.log +0 -116
- package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
- package/docs/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
- package/docs/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
- package/docs/investigations/hlg-runs/runR-blind-transcript.log +0 -79
- package/docs/investigations/hlg-runs/runS-cross-coherence.log +0 -33
- package/docs/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
- package/docs/investigations/hlg-runs/runU-cross-12b.log +0 -33
- package/docs/investigations/hlg-runs/runV-lw-e4b.log +0 -22
- package/docs/investigations/hlg-runs/runW-lw-12b.log +0 -22
- package/docs/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
- package/docs/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
- package/docs/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
- package/docs/planning/IDEAS.md +0 -69
- package/docs/reference/embedding.md +0 -197
- package/docs/reference/features-matrix.md +0 -100
- package/docs/reference/orpo-quickstart.md +0 -135
- package/src/flags.ts +0 -13
- /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
- /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
- /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
- /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
- /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
- /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
- /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
- /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
- /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
- /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
- /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
- /package/docs/{planning → archive/planning}/journal.md +0 -0
- /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
- /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
- /package/{docs/investigations → src/serve/assets}/curve-terrain.html +0 -0
- /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import type { ModelConfig } from "../config";
|
|
2
|
+
import { configFingerprint } from "./fingerprint";
|
|
3
|
+
import {
|
|
4
|
+
isDiffusionGemmaConfig,
|
|
5
|
+
isGlm52Config,
|
|
6
|
+
isMiniCPM5Config,
|
|
7
|
+
isQwen35Config,
|
|
8
|
+
isQwen3Config,
|
|
9
|
+
isQwen3MoeConfig,
|
|
10
|
+
} from "./support";
|
|
11
|
+
import { GENERATED } from "./generated";
|
|
12
|
+
import { GENERIC_MODEL_TYPES, genericArgsFor, remapModelType } from "./universal/archs";
|
|
13
|
+
|
|
14
|
+
export const ENGINE_CAPABILITIES = Object.freeze([
|
|
15
|
+
"autoregressive",
|
|
16
|
+
"colibri-container",
|
|
17
|
+
"diffusion",
|
|
18
|
+
"diffusion-gemma-graph",
|
|
19
|
+
"gemma4-graph",
|
|
20
|
+
"generated-graph",
|
|
21
|
+
"glm5.2-graph",
|
|
22
|
+
"minicpm5-graph",
|
|
23
|
+
"mixed-precision-kv",
|
|
24
|
+
"native-mtp",
|
|
25
|
+
"qwen3-graph",
|
|
26
|
+
"qwen3-moe-graph",
|
|
27
|
+
"qwen3.5-graph",
|
|
28
|
+
"recurrent-state",
|
|
29
|
+
"safetensors",
|
|
30
|
+
"streamed-experts",
|
|
31
|
+
"universal-dense-graph",
|
|
32
|
+
"vision-sidecar",
|
|
33
|
+
] as const);
|
|
34
|
+
|
|
35
|
+
export type EngineCapability = typeof ENGINE_CAPABILITIES[number];
|
|
36
|
+
export type FidelityTier = "l1" | "l2" | "l3";
|
|
37
|
+
|
|
38
|
+
export type FidelityTarget =
|
|
39
|
+
| Readonly<{ tier: "l1"; oracle: "mlx-lm"; claim: "bit-exact" }>
|
|
40
|
+
| Readonly<{ tier: "l2"; oracle: "mlx-optiq"; claim: "bit-exact" }>
|
|
41
|
+
| Readonly<{ tier: "l3"; oracle: null; claim: "measured" }>;
|
|
42
|
+
|
|
43
|
+
export type ModelLoader = "safetensors" | "colibri";
|
|
44
|
+
export type ModelGraph =
|
|
45
|
+
| "gemma4"
|
|
46
|
+
| "minicpm5"
|
|
47
|
+
| "qwen3.5"
|
|
48
|
+
| "qwen3"
|
|
49
|
+
| "qwen3-moe"
|
|
50
|
+
| "diffusion-gemma"
|
|
51
|
+
| "glm5.2"
|
|
52
|
+
| "universal-dense";
|
|
53
|
+
export type GenerationLoop = "autoregressive" | "diffusion";
|
|
54
|
+
export type ModelSpecialization = "artifact" | "dedicated" | "generated" | "generic";
|
|
55
|
+
|
|
56
|
+
export interface ModelExecutionComposition {
|
|
57
|
+
readonly loader: ModelLoader;
|
|
58
|
+
readonly graph: ModelGraph;
|
|
59
|
+
readonly loop: GenerationLoop;
|
|
60
|
+
readonly specialization: ModelSpecialization;
|
|
61
|
+
/** Engine-owned code registration. Model files never supply executable code.
|
|
62
|
+
* Omit to retain the existing graph implementation. */
|
|
63
|
+
readonly implementation?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** A profile declares construction only. Request methods such as MTP, KV
|
|
67
|
+
* schemes, adapters, grammar, and sampling are resolved independently and
|
|
68
|
+
* cannot be rewritten by profile selection. */
|
|
69
|
+
export interface ModelProfile {
|
|
70
|
+
readonly id: string;
|
|
71
|
+
/** Exact external identity. Family profiles omit this field. */
|
|
72
|
+
readonly artifactFingerprint?: string;
|
|
73
|
+
/** Structural guard for an exact artifact declaration. */
|
|
74
|
+
readonly configFingerprint?: string;
|
|
75
|
+
readonly fidelity: FidelityTarget;
|
|
76
|
+
readonly requiredCapabilities: readonly EngineCapability[];
|
|
77
|
+
readonly execution: ModelExecutionComposition;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface ArtifactModelProfile extends ModelProfile {
|
|
81
|
+
readonly artifactFingerprint: string;
|
|
82
|
+
readonly configFingerprint: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface ModelArtifactIdentity {
|
|
86
|
+
readonly fingerprint: string | null;
|
|
87
|
+
readonly configFingerprint: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface ResolvedModelProfile {
|
|
91
|
+
readonly profile: ModelProfile;
|
|
92
|
+
readonly artifact: ModelArtifactIdentity;
|
|
93
|
+
readonly exactArtifact: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface ResolveModelProfileOptions {
|
|
97
|
+
/** Explicit identity for a non-Hugging-Face artifact. The caller owns its
|
|
98
|
+
* provenance; mlx-bun never mistakes a local path for a content identity. */
|
|
99
|
+
readonly artifactFingerprint?: string | null;
|
|
100
|
+
/** Additional exact declarations composed with the shipped profiles. */
|
|
101
|
+
readonly artifactProfiles?: readonly ArtifactModelProfile[];
|
|
102
|
+
readonly engineCapabilities?: readonly EngineCapability[];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const L1: FidelityTarget = Object.freeze({
|
|
106
|
+
tier: "l1", oracle: "mlx-lm", claim: "bit-exact",
|
|
107
|
+
});
|
|
108
|
+
const L2: FidelityTarget = Object.freeze({
|
|
109
|
+
tier: "l2", oracle: "mlx-optiq", claim: "bit-exact",
|
|
110
|
+
});
|
|
111
|
+
const L3: FidelityTarget = Object.freeze({
|
|
112
|
+
tier: "l3", oracle: null, claim: "measured",
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
function freezeProfile<T extends ModelProfile>(profile: T): T {
|
|
116
|
+
Object.freeze(profile.fidelity);
|
|
117
|
+
Object.freeze(profile.requiredCapabilities);
|
|
118
|
+
Object.freeze(profile.execution);
|
|
119
|
+
return Object.freeze(profile);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function snapshotProfile(profile: ModelProfile): ModelProfile {
|
|
123
|
+
return freezeProfile({
|
|
124
|
+
...profile,
|
|
125
|
+
fidelity: { ...profile.fidelity },
|
|
126
|
+
requiredCapabilities: [...profile.requiredCapabilities],
|
|
127
|
+
execution: { ...profile.execution },
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Exact artifact declarations already backed by this repository's parity or
|
|
132
|
+
* measured evidence. A new revision gets the family profile until it earns a
|
|
133
|
+
* declaration of its own. */
|
|
134
|
+
export const BUILTIN_ARTIFACT_PROFILES: readonly ArtifactModelProfile[] = Object.freeze([
|
|
135
|
+
freezeProfile({
|
|
136
|
+
id: "qwen3.8-27b-optiq-4bit",
|
|
137
|
+
artifactFingerprint:
|
|
138
|
+
"hf:mlx-community/Qwen3.8-27B-OptiQ-4bit@b04599de95d7a9bfbd7f208d347c0f10d9432a42",
|
|
139
|
+
configFingerprint: "50117975cb405944",
|
|
140
|
+
fidelity: L1,
|
|
141
|
+
requiredCapabilities: Object.freeze([
|
|
142
|
+
"safetensors", "autoregressive", "qwen3.5-graph", "recurrent-state", "vision-sidecar",
|
|
143
|
+
]),
|
|
144
|
+
execution: Object.freeze({
|
|
145
|
+
loader: "safetensors",
|
|
146
|
+
graph: "qwen3.5",
|
|
147
|
+
loop: "autoregressive",
|
|
148
|
+
specialization: "artifact",
|
|
149
|
+
}),
|
|
150
|
+
}),
|
|
151
|
+
freezeProfile({
|
|
152
|
+
id: "glm5.2-colibri-int4-int8-mtp",
|
|
153
|
+
artifactFingerprint:
|
|
154
|
+
"hf:mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp@3cc8db99b1b13fc79325d987ba3c1c430766b3b8",
|
|
155
|
+
configFingerprint: "8b49d0941e18f1b9",
|
|
156
|
+
fidelity: L3,
|
|
157
|
+
requiredCapabilities: Object.freeze([
|
|
158
|
+
"colibri-container", "autoregressive", "glm5.2-graph", "streamed-experts",
|
|
159
|
+
]),
|
|
160
|
+
execution: Object.freeze({
|
|
161
|
+
loader: "colibri",
|
|
162
|
+
graph: "glm5.2",
|
|
163
|
+
loop: "autoregressive",
|
|
164
|
+
specialization: "artifact",
|
|
165
|
+
}),
|
|
166
|
+
}),
|
|
167
|
+
]);
|
|
168
|
+
|
|
169
|
+
const FAMILY_PROFILES = {
|
|
170
|
+
gemma4Generated: freezeProfile({
|
|
171
|
+
id: "gemma4-generated",
|
|
172
|
+
fidelity: L1,
|
|
173
|
+
requiredCapabilities: ["safetensors", "autoregressive", "gemma4-graph", "generated-graph"],
|
|
174
|
+
execution: {
|
|
175
|
+
loader: "safetensors", graph: "gemma4", loop: "autoregressive", specialization: "generated",
|
|
176
|
+
},
|
|
177
|
+
}),
|
|
178
|
+
gemma4: freezeProfile({
|
|
179
|
+
id: "gemma4-dedicated",
|
|
180
|
+
fidelity: L1,
|
|
181
|
+
requiredCapabilities: ["safetensors", "autoregressive", "gemma4-graph"],
|
|
182
|
+
execution: {
|
|
183
|
+
loader: "safetensors", graph: "gemma4", loop: "autoregressive", specialization: "dedicated",
|
|
184
|
+
},
|
|
185
|
+
}),
|
|
186
|
+
minicpm5: freezeProfile({
|
|
187
|
+
id: "minicpm5-dedicated",
|
|
188
|
+
fidelity: L1,
|
|
189
|
+
requiredCapabilities: ["safetensors", "autoregressive", "minicpm5-graph"],
|
|
190
|
+
execution: {
|
|
191
|
+
loader: "safetensors", graph: "minicpm5", loop: "autoregressive", specialization: "dedicated",
|
|
192
|
+
},
|
|
193
|
+
}),
|
|
194
|
+
qwen35: freezeProfile({
|
|
195
|
+
id: "qwen3.5-dedicated",
|
|
196
|
+
fidelity: L1,
|
|
197
|
+
requiredCapabilities: ["safetensors", "autoregressive", "qwen3.5-graph", "recurrent-state"],
|
|
198
|
+
execution: {
|
|
199
|
+
loader: "safetensors", graph: "qwen3.5", loop: "autoregressive", specialization: "dedicated",
|
|
200
|
+
},
|
|
201
|
+
}),
|
|
202
|
+
qwen3: freezeProfile({
|
|
203
|
+
id: "qwen3-dedicated",
|
|
204
|
+
fidelity: L1,
|
|
205
|
+
requiredCapabilities: ["safetensors", "autoregressive", "qwen3-graph"],
|
|
206
|
+
execution: {
|
|
207
|
+
loader: "safetensors", graph: "qwen3", loop: "autoregressive", specialization: "dedicated",
|
|
208
|
+
},
|
|
209
|
+
}),
|
|
210
|
+
qwen3Moe: freezeProfile({
|
|
211
|
+
id: "qwen3-moe-dedicated",
|
|
212
|
+
fidelity: L1,
|
|
213
|
+
requiredCapabilities: ["safetensors", "autoregressive", "qwen3-moe-graph"],
|
|
214
|
+
execution: {
|
|
215
|
+
loader: "safetensors", graph: "qwen3-moe", loop: "autoregressive", specialization: "dedicated",
|
|
216
|
+
},
|
|
217
|
+
}),
|
|
218
|
+
diffusionGemma: freezeProfile({
|
|
219
|
+
id: "diffusion-gemma-dedicated",
|
|
220
|
+
fidelity: L2,
|
|
221
|
+
requiredCapabilities: ["safetensors", "diffusion", "diffusion-gemma-graph"],
|
|
222
|
+
execution: {
|
|
223
|
+
loader: "safetensors", graph: "diffusion-gemma", loop: "diffusion", specialization: "dedicated",
|
|
224
|
+
},
|
|
225
|
+
}),
|
|
226
|
+
glm52: freezeProfile({
|
|
227
|
+
id: "glm5.2-colibri",
|
|
228
|
+
fidelity: L3,
|
|
229
|
+
requiredCapabilities: ["colibri-container", "autoregressive", "glm5.2-graph", "streamed-experts"],
|
|
230
|
+
execution: {
|
|
231
|
+
loader: "colibri", graph: "glm5.2", loop: "autoregressive", specialization: "dedicated",
|
|
232
|
+
},
|
|
233
|
+
}),
|
|
234
|
+
universal: freezeProfile({
|
|
235
|
+
id: "universal-dense",
|
|
236
|
+
fidelity: L1,
|
|
237
|
+
requiredCapabilities: ["safetensors", "autoregressive", "universal-dense-graph"],
|
|
238
|
+
execution: {
|
|
239
|
+
loader: "safetensors", graph: "universal-dense", loop: "autoregressive", specialization: "generic",
|
|
240
|
+
},
|
|
241
|
+
}),
|
|
242
|
+
} satisfies Record<string, ModelProfile>;
|
|
243
|
+
|
|
244
|
+
/** Return a stable external fingerprint only when the directory is an exact HF
|
|
245
|
+
* snapshot revision. Relocation does not change the identity. Arbitrary local
|
|
246
|
+
* directories and mutable aliases intentionally return null. */
|
|
247
|
+
export function externalArtifactFingerprint(modelDir: string): string | null {
|
|
248
|
+
const match = modelDir.replaceAll("\\", "/").match(
|
|
249
|
+
/(?:^|\/)models--([^/]+)\/snapshots\/([0-9a-f]{40,64})(?:\/|$)/i,
|
|
250
|
+
);
|
|
251
|
+
if (!match) return null;
|
|
252
|
+
const encodedRepo = match[1]!;
|
|
253
|
+
const separator = encodedRepo.indexOf("--");
|
|
254
|
+
if (separator <= 0 || separator === encodedRepo.length - 2) return null;
|
|
255
|
+
const repo = `${encodedRepo.slice(0, separator)}/${encodedRepo.slice(separator + 2)}`;
|
|
256
|
+
return `hf:${repo}@${match[2]!.toLowerCase()}`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function familyProfile(config: ModelConfig, fingerprint: string): ModelProfile {
|
|
260
|
+
if (isGlm52Config(config)) return FAMILY_PROFILES.glm52;
|
|
261
|
+
if (isDiffusionGemmaConfig(config)) return FAMILY_PROFILES.diffusionGemma;
|
|
262
|
+
if (isMiniCPM5Config(config)) return FAMILY_PROFILES.minicpm5;
|
|
263
|
+
if (isQwen35Config(config)) return FAMILY_PROFILES.qwen35;
|
|
264
|
+
if (isQwen3MoeConfig(config)) return FAMILY_PROFILES.qwen3Moe;
|
|
265
|
+
if (isQwen3Config(config)) return FAMILY_PROFILES.qwen3;
|
|
266
|
+
if (config.modelType.startsWith("gemma4"))
|
|
267
|
+
return GENERATED.has(fingerprint) ? FAMILY_PROFILES.gemma4Generated : FAMILY_PROFILES.gemma4;
|
|
268
|
+
if (genericArgsFor(config)) return FAMILY_PROFILES.universal;
|
|
269
|
+
|
|
270
|
+
const arch = remapModelType(config.modelType);
|
|
271
|
+
throw new Error(
|
|
272
|
+
`unsupported model_type "${config.modelType}"` +
|
|
273
|
+
(arch !== config.modelType ? ` (mlx-lm remaps it to "${arch}")` : "") +
|
|
274
|
+
` — targeted: gemma4*, diffusion_gemma, glm_moe_dsa, qwen3_5, qwen3, qwen3_moe, MiniCPM5;` +
|
|
275
|
+
` generic (Tier-0): ${[...GENERIC_MODEL_TYPES].sort().join(", ")}`,
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
interface GraphMetadata {
|
|
280
|
+
readonly accepts: (config: ModelConfig) => boolean;
|
|
281
|
+
readonly capabilities: readonly EngineCapability[];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const GRAPH_METADATA: Readonly<Record<ModelGraph, GraphMetadata>> = Object.freeze({
|
|
285
|
+
"gemma4": {
|
|
286
|
+
accepts: (config) => config.modelType.startsWith("gemma4"),
|
|
287
|
+
capabilities: ["gemma4-graph"],
|
|
288
|
+
},
|
|
289
|
+
"minicpm5": { accepts: isMiniCPM5Config, capabilities: ["minicpm5-graph"] },
|
|
290
|
+
"qwen3.5": {
|
|
291
|
+
accepts: isQwen35Config,
|
|
292
|
+
capabilities: ["qwen3.5-graph", "recurrent-state"],
|
|
293
|
+
},
|
|
294
|
+
"qwen3": { accepts: isQwen3Config, capabilities: ["qwen3-graph"] },
|
|
295
|
+
"qwen3-moe": { accepts: isQwen3MoeConfig, capabilities: ["qwen3-moe-graph"] },
|
|
296
|
+
"diffusion-gemma": {
|
|
297
|
+
accepts: isDiffusionGemmaConfig,
|
|
298
|
+
capabilities: ["diffusion-gemma-graph"],
|
|
299
|
+
},
|
|
300
|
+
"glm5.2": {
|
|
301
|
+
accepts: isGlm52Config,
|
|
302
|
+
capabilities: ["glm5.2-graph", "streamed-experts"],
|
|
303
|
+
},
|
|
304
|
+
"universal-dense": {
|
|
305
|
+
accepts: (config) => {
|
|
306
|
+
try { return genericArgsFor(config) !== null; } catch { return false; }
|
|
307
|
+
},
|
|
308
|
+
capabilities: ["universal-dense-graph"],
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
function graphAccepts(profile: ModelProfile, config: ModelConfig): boolean {
|
|
313
|
+
return GRAPH_METADATA[profile.execution.graph].accepts(config);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function executionCapabilities(profile: ModelProfile): EngineCapability[] {
|
|
317
|
+
const required: EngineCapability[] = [profile.execution.loader === "colibri"
|
|
318
|
+
? "colibri-container"
|
|
319
|
+
: "safetensors"];
|
|
320
|
+
if (profile.execution.loop === "diffusion") required.push("diffusion");
|
|
321
|
+
else required.push("autoregressive");
|
|
322
|
+
required.push(...GRAPH_METADATA[profile.execution.graph].capabilities);
|
|
323
|
+
if (profile.execution.specialization === "generated") required.push("generated-graph");
|
|
324
|
+
return required;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function validateProfile(profile: ModelProfile): void {
|
|
328
|
+
if (!profile.id) throw new Error("model profile id must not be empty");
|
|
329
|
+
if (profile.execution.implementation !== undefined &&
|
|
330
|
+
(!profile.execution.implementation.trim() || !profile.artifactFingerprint ||
|
|
331
|
+
profile.execution.specialization !== "artifact"))
|
|
332
|
+
throw new Error(`model profile ${profile.id} must bind a named implementation to an exact artifact`);
|
|
333
|
+
if ((profile.artifactFingerprint === undefined) !== (profile.configFingerprint === undefined))
|
|
334
|
+
throw new Error(
|
|
335
|
+
`model profile ${profile.id} must declare artifactFingerprint and configFingerprint together`,
|
|
336
|
+
);
|
|
337
|
+
const fidelityOk =
|
|
338
|
+
(profile.fidelity.tier === "l1" && profile.fidelity.oracle === "mlx-lm" &&
|
|
339
|
+
profile.fidelity.claim === "bit-exact") ||
|
|
340
|
+
(profile.fidelity.tier === "l2" && profile.fidelity.oracle === "mlx-optiq" &&
|
|
341
|
+
profile.fidelity.claim === "bit-exact") ||
|
|
342
|
+
(profile.fidelity.tier === "l3" && profile.fidelity.oracle === null &&
|
|
343
|
+
profile.fidelity.claim === "measured");
|
|
344
|
+
if (!fidelityOk) throw new Error(`model profile ${profile.id} has an invalid fidelity contract`);
|
|
345
|
+
const expectedLoader = profile.execution.graph === "glm5.2" ? "colibri" : "safetensors";
|
|
346
|
+
const expectedLoop = profile.execution.graph === "diffusion-gemma"
|
|
347
|
+
? "diffusion"
|
|
348
|
+
: "autoregressive";
|
|
349
|
+
if (profile.execution.loader !== expectedLoader || profile.execution.loop !== expectedLoop)
|
|
350
|
+
throw new Error(
|
|
351
|
+
`model profile ${profile.id} has an invalid execution composition for ` +
|
|
352
|
+
`${profile.execution.graph}`,
|
|
353
|
+
);
|
|
354
|
+
const declared = new Set(profile.requiredCapabilities);
|
|
355
|
+
const underdeclared = executionCapabilities(profile).filter((capability) => !declared.has(capability));
|
|
356
|
+
if (underdeclared.length)
|
|
357
|
+
throw new Error(
|
|
358
|
+
`model profile ${profile.id} does not declare execution capabilities: ` +
|
|
359
|
+
`${underdeclared.join(", ")}`,
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export function resolveModelProfile(
|
|
364
|
+
config: ModelConfig,
|
|
365
|
+
options: ResolveModelProfileOptions = {},
|
|
366
|
+
): ResolvedModelProfile {
|
|
367
|
+
const fingerprint = configFingerprint(config);
|
|
368
|
+
const artifactFingerprint = options.artifactFingerprint === undefined
|
|
369
|
+
? externalArtifactFingerprint(config.modelDir)
|
|
370
|
+
: options.artifactFingerprint;
|
|
371
|
+
const artifactProfiles = options.artifactProfiles
|
|
372
|
+
? [...BUILTIN_ARTIFACT_PROFILES, ...options.artifactProfiles]
|
|
373
|
+
: BUILTIN_ARTIFACT_PROFILES;
|
|
374
|
+
const capabilities = new Set(options.engineCapabilities ?? ENGINE_CAPABILITIES);
|
|
375
|
+
|
|
376
|
+
let profile: ModelProfile | undefined;
|
|
377
|
+
let exactArtifact = false;
|
|
378
|
+
if (artifactFingerprint) {
|
|
379
|
+
const matches = artifactProfiles.filter((entry) => {
|
|
380
|
+
validateProfile(entry);
|
|
381
|
+
return entry.artifactFingerprint === artifactFingerprint;
|
|
382
|
+
});
|
|
383
|
+
if (matches.length > 1)
|
|
384
|
+
throw new Error(`multiple model profiles declare artifact ${artifactFingerprint}`);
|
|
385
|
+
profile = matches[0];
|
|
386
|
+
if (profile) {
|
|
387
|
+
exactArtifact = true;
|
|
388
|
+
if (profile.configFingerprint !== fingerprint)
|
|
389
|
+
throw new Error(
|
|
390
|
+
`model profile ${profile.id} matched artifact ${artifactFingerprint}, but config fingerprint ` +
|
|
391
|
+
`${fingerprint} != declared ${profile.configFingerprint}; refusing to fall back`,
|
|
392
|
+
);
|
|
393
|
+
if (!graphAccepts(profile, config))
|
|
394
|
+
throw new Error(
|
|
395
|
+
`model profile ${profile.id} selects ${profile.execution.graph}, which is incompatible with ` +
|
|
396
|
+
`${config.modelType}; refusing to fall back`,
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
profile ??= familyProfile(config, fingerprint);
|
|
401
|
+
validateProfile(profile);
|
|
402
|
+
profile = snapshotProfile(profile);
|
|
403
|
+
|
|
404
|
+
const missing = profile.requiredCapabilities.filter((capability) => !capabilities.has(capability));
|
|
405
|
+
if (missing.length)
|
|
406
|
+
throw new Error(
|
|
407
|
+
`model profile ${profile.id} requires missing engine capabilities: ${missing.join(", ")}; ` +
|
|
408
|
+
`refusing to fall back`,
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
return Object.freeze({
|
|
412
|
+
profile,
|
|
413
|
+
artifact: Object.freeze({ fingerprint: artifactFingerprint, configFingerprint: fingerprint }),
|
|
414
|
+
exactArtifact,
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** Guard the factory seam when a caller passes a previously resolved profile. */
|
|
419
|
+
export function assertResolvedModelProfile(
|
|
420
|
+
config: ModelConfig,
|
|
421
|
+
resolved: ResolvedModelProfile,
|
|
422
|
+
): void {
|
|
423
|
+
validateProfile(resolved.profile);
|
|
424
|
+
const fingerprint = configFingerprint(config);
|
|
425
|
+
if (resolved.artifact.configFingerprint !== fingerprint)
|
|
426
|
+
throw new Error(
|
|
427
|
+
`model profile ${resolved.profile.id} was resolved for config ` +
|
|
428
|
+
`${resolved.artifact.configFingerprint}, not ${fingerprint}`,
|
|
429
|
+
);
|
|
430
|
+
if (!graphAccepts(resolved.profile, config))
|
|
431
|
+
throw new Error(
|
|
432
|
+
`model profile ${resolved.profile.id} selects ${resolved.profile.execution.graph}, ` +
|
|
433
|
+
`which is incompatible with ${config.modelType}`,
|
|
434
|
+
);
|
|
435
|
+
if (resolved.exactArtifact !== (resolved.profile.artifactFingerprint !== undefined) ||
|
|
436
|
+
(resolved.exactArtifact &&
|
|
437
|
+
(resolved.profile.artifactFingerprint !== resolved.artifact.fingerprint ||
|
|
438
|
+
resolved.profile.configFingerprint !== fingerprint)))
|
|
439
|
+
throw new Error(
|
|
440
|
+
`model profile ${resolved.profile.id} does not match artifact ` +
|
|
441
|
+
`${resolved.artifact.fingerprint ?? "<unidentified>"}`,
|
|
442
|
+
);
|
|
443
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// MLX 0.32.2, mlx/backend/metal/scaled_dot_product_attention.cpp (MIT):
|
|
2
|
+
// https://github.com/ml-explore/mlx/blob/v0.32.2/mlx/backend/metal/scaled_dot_product_attention.cpp
|
|
3
|
+
// For the qualified Qwen GQA-6/D256 graph on applegpu_g16s, one-pass/vector
|
|
4
|
+
// selection and two-pass block counts change after these inclusive KV lengths.
|
|
5
|
+
// A committed span must stay within one arithmetic regime to match M=1.
|
|
6
|
+
const ATTENTION_BOUNDARIES = [1023, 1024, 8192, 32768, 65536];
|
|
7
|
+
|
|
8
|
+
export function qwenAppendChunkSize(cacheTokens: number): number {
|
|
9
|
+
for (const end of ATTENTION_BOUNDARIES)
|
|
10
|
+
if (cacheTokens < end) return Math.min(4, end - cacheTokens);
|
|
11
|
+
return 4;
|
|
12
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Experimental Qwen GDN convolution. Its two outputs are evaluated together:
|
|
2
|
+
// consuming the activation also materializes the small, independently owned
|
|
3
|
+
// state tail, without keeping a concatenated prefill buffer alive for it.
|
|
4
|
+
// Arithmetic follows MLX 0.31.2 depthwise_conv_1d and unary sigmoid (MIT,
|
|
5
|
+
// Copyright Apple Inc.), preserving the bf16 intermediate rounding.
|
|
6
|
+
import type { MlxArray } from "../mlx/array";
|
|
7
|
+
import { Dtype } from "../mlx/ffi";
|
|
8
|
+
import { MetalKernel } from "../mlx/metal-kernel";
|
|
9
|
+
|
|
10
|
+
/** Borrow all inputs; return owned activation and an independent state tail. */
|
|
11
|
+
export type QwenConvolution = (x: MlxArray, state: MlxArray, weight: MlxArray) => [MlxArray, MlxArray];
|
|
12
|
+
|
|
13
|
+
let kernel: MetalKernel | null = null;
|
|
14
|
+
export const fusedQwenConvolution: QwenConvolution = (x, state, weight) => {
|
|
15
|
+
const [B, M, D] = x.shape as [number, number, number];
|
|
16
|
+
const K = weight.shape[1]!;
|
|
17
|
+
if (x.shape.length !== 3 || weight.shape.length !== 3 || weight.shape[0] !== D ||
|
|
18
|
+
weight.shape[2] !== 1 || K !== 4 || state.shape.join() !== [B, K - 1, D].join() ||
|
|
19
|
+
![Dtype.bfloat16, Dtype.float32].includes(x.dtype) || state.dtype !== x.dtype || weight.dtype !== x.dtype)
|
|
20
|
+
throw new Error("fused Qwen convolution requires matching bf16/f32 inputs, [B,M,D], [B,3,D], [D,4,1]");
|
|
21
|
+
kernel ??= new MetalKernel({ name: "qwen_causal_conv_silu_tail",
|
|
22
|
+
inputNames: ["state", "x", "w"], outputNames: ["out", "tail"],
|
|
23
|
+
source: String.raw`
|
|
24
|
+
const uint c = thread_position_in_grid.x;
|
|
25
|
+
const uint t = thread_position_in_grid.y;
|
|
26
|
+
const uint b = thread_position_in_grid.z;
|
|
27
|
+
if (c >= D) return;
|
|
28
|
+
if (t < M) {
|
|
29
|
+
float acc = 0.0f;
|
|
30
|
+
for (uint i = 0; i < K; ++i) {
|
|
31
|
+
const uint row = t + i;
|
|
32
|
+
const T value = row < K-1 ? state[(b*(K-1)+row)*D+c] : x[(b*M+row-(K-1))*D+c];
|
|
33
|
+
acc += float(value) * float(w[c*K+i]);
|
|
34
|
+
}
|
|
35
|
+
const T conv = T(acc);
|
|
36
|
+
// Preserve the pinned MLX sigmoid's typed operations and bf16
|
|
37
|
+
// intermediate rounding. Promoting this expression to f32 differs.
|
|
38
|
+
const auto y = 1 / (1 + metal::exp(metal::abs(conv)));
|
|
39
|
+
const T sig = conv < 0 ? y : 1-y;
|
|
40
|
+
out[(b*M+t)*D+c] = conv * sig;
|
|
41
|
+
}
|
|
42
|
+
if (t < K-1) {
|
|
43
|
+
const uint row = M + t;
|
|
44
|
+
tail[(b*(K-1)+t)*D+c] = row < K-1 ? state[(b*(K-1)+row)*D+c] : x[(b*M+row-(K-1))*D+c];
|
|
45
|
+
}
|
|
46
|
+
` });
|
|
47
|
+
return kernel.apply([state, x, weight], {
|
|
48
|
+
outputs: [{ shape: [B, M, D], dtype: x.dtype }, { shape: [B, K - 1, D], dtype: x.dtype }],
|
|
49
|
+
grid: [D, Math.max(M, K - 1), B], threadGroup: [256, 1, 1],
|
|
50
|
+
templateDtypes: { T: x.dtype }, templateInts: { D, M, K },
|
|
51
|
+
}) as [MlxArray, MlxArray];
|
|
52
|
+
};
|
package/src/model/qwen3-delta.ts
CHANGED
|
@@ -194,10 +194,37 @@ export function gatedDeltaUpdate(
|
|
|
194
194
|
* and writes these slots directly; `advance(N)` only tracks token count for
|
|
195
195
|
* B=1 single-stream (lengths / left_padding are batched-decode concerns).
|
|
196
196
|
* Not a KVCache, so maybeQuantizeKv skips it. */
|
|
197
|
+
/** One armed speculative verify round on an SSMCache: the pre-round state
|
|
198
|
+
* snapshot (retained refs — MLX arrays are immutable, so this is free) plus
|
|
199
|
+
* the layer's recorded position-local kernel inputs, which make a partial
|
|
200
|
+
* reject bit-exactly replayable: state after the first `keep` window tokens
|
|
201
|
+
* is the same arithmetic prefix whether or not the rejected tail was ever
|
|
202
|
+
* processed. The replay is installed by the OWNING layer (it needs the conv
|
|
203
|
+
* weight / A_log / dt_bias); the cache only stores and frees. */
|
|
204
|
+
export interface SsmSpecRound {
|
|
205
|
+
/** True from specRoundBegin() until the layer's forward records. */
|
|
206
|
+
armed: boolean;
|
|
207
|
+
prevConv: MlxArray | null;
|
|
208
|
+
prevRecurrent: MlxArray | null;
|
|
209
|
+
prevOffset: number;
|
|
210
|
+
/** Pre-conv in_proj output [B,S,convDim] — position-local. */
|
|
211
|
+
qkv: MlxArray | null;
|
|
212
|
+
/** Gate/beta projections [B,S,Hv] — position-local. */
|
|
213
|
+
a: MlxArray | null;
|
|
214
|
+
b: MlxArray | null;
|
|
215
|
+
/** Window length S of the recorded verify forward. */
|
|
216
|
+
S: number;
|
|
217
|
+
/** Layer-bound prefix replay: called AFTER the snapshot is restored onto
|
|
218
|
+
* the cache; advances conv/recurrent/offset by `keep` tokens. */
|
|
219
|
+
replay: ((cache: SSMCache, keep: number) => void) | null;
|
|
220
|
+
}
|
|
221
|
+
|
|
197
222
|
export class SSMCache implements Cache {
|
|
198
223
|
conv: MlxArray | null = null;
|
|
199
224
|
recurrent: MlxArray | null = null;
|
|
200
225
|
offset = 0;
|
|
226
|
+
/** Live speculative verify round (serial spec lane only; null otherwise). */
|
|
227
|
+
specRound: SsmSpecRound | null = null;
|
|
201
228
|
/** Per-row token coverage (batch lane only; null on serial B=1 caches,
|
|
202
229
|
* where `offset` IS the row's count). mlx-lm's ArraysCache tracks no
|
|
203
230
|
* offset at all (cache.py:594-722) — per-sequence coverage is the
|
|
@@ -207,6 +234,10 @@ export class SSMCache implements Cache {
|
|
|
207
234
|
* lockstep by advance(), row-filtered by filter(). */
|
|
208
235
|
offsets: number[] | null = null;
|
|
209
236
|
|
|
237
|
+
signature(): string { return "ssm"; }
|
|
238
|
+
bytesPerToken(): number { return 0; }
|
|
239
|
+
get batchSize(): number { return this.offsets?.length ?? 1; }
|
|
240
|
+
|
|
210
241
|
/** Row `i`'s own token coverage (per-row when batched, `offset` serial). */
|
|
211
242
|
rowOffset(i: number): number {
|
|
212
243
|
return this.offsets ? this.offsets[i]! : this.offset;
|
|
@@ -241,14 +272,77 @@ export class SSMCache implements Cache {
|
|
|
241
272
|
}
|
|
242
273
|
|
|
243
274
|
isTrimmable(): boolean {
|
|
244
|
-
return false; // recurrent state can't be
|
|
275
|
+
return false; // recurrent state can't be trimmed per token — see specRound*
|
|
245
276
|
}
|
|
246
277
|
|
|
247
278
|
trim(_n: number): void {
|
|
248
279
|
throw new Error("SSMCache is not trimmable");
|
|
249
280
|
}
|
|
250
281
|
|
|
282
|
+
// --- speculative verify-round support (serial spec lane, B=1) ------------
|
|
283
|
+
// The serve loop arms a round before the verify forward and resolves it
|
|
284
|
+
// after the accept walk. The layer's forward, seeing an armed round, hands
|
|
285
|
+
// its replaced state slots to the round instead of disposing them, records
|
|
286
|
+
// qkv/a/b, and installs the replay. Cache/interface contract:
|
|
287
|
+
// rollback(keep) restores the snapshot then replays `keep` window tokens
|
|
288
|
+
// bit-exactly; commit frees the snapshot + recordings.
|
|
289
|
+
|
|
290
|
+
specRoundBegin(): void {
|
|
291
|
+
this.#dropSpecRound(); // defensive: a mid-round throw left a stale round
|
|
292
|
+
this.specRound = {
|
|
293
|
+
armed: true,
|
|
294
|
+
prevConv: null,
|
|
295
|
+
prevRecurrent: null,
|
|
296
|
+
prevOffset: this.offset,
|
|
297
|
+
qkv: null,
|
|
298
|
+
a: null,
|
|
299
|
+
b: null,
|
|
300
|
+
S: 0,
|
|
301
|
+
replay: null,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
specRoundCommit(): void {
|
|
306
|
+
this.#dropSpecRound();
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
specRoundRollback(keep: number): void {
|
|
310
|
+
const r = this.specRound;
|
|
311
|
+
if (!r) throw new Error("SSMCache.specRoundRollback without an armed round");
|
|
312
|
+
if (r.armed)
|
|
313
|
+
throw new Error("SSMCache.specRoundRollback before the verify forward recorded");
|
|
314
|
+
if (keep < 0 || keep > r.S)
|
|
315
|
+
throw new Error(`SSMCache.specRoundRollback keep=${keep} outside window S=${r.S}`);
|
|
316
|
+
// Restore the pre-round snapshot (ownership moves back to the cache).
|
|
317
|
+
this.conv?.dispose();
|
|
318
|
+
this.recurrent?.dispose();
|
|
319
|
+
this.conv = r.prevConv;
|
|
320
|
+
this.recurrent = r.prevRecurrent;
|
|
321
|
+
r.prevConv = null;
|
|
322
|
+
r.prevRecurrent = null;
|
|
323
|
+
this.offset = r.prevOffset;
|
|
324
|
+
if (this.offsets)
|
|
325
|
+
throw new Error("SSMCache.specRoundRollback on a batched cache (serial lane only)");
|
|
326
|
+
if (keep > 0) {
|
|
327
|
+
if (!r.replay) throw new Error("SSMCache.specRoundRollback with no recorded replay");
|
|
328
|
+
r.replay(this, keep); // advances conv/recurrent/offset by `keep`
|
|
329
|
+
}
|
|
330
|
+
this.#dropSpecRound();
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
#dropSpecRound(): void {
|
|
334
|
+
const r = this.specRound;
|
|
335
|
+
if (!r) return;
|
|
336
|
+
r.prevConv?.dispose();
|
|
337
|
+
r.prevRecurrent?.dispose();
|
|
338
|
+
r.qkv?.dispose();
|
|
339
|
+
r.a?.dispose();
|
|
340
|
+
r.b?.dispose();
|
|
341
|
+
this.specRound = null;
|
|
342
|
+
}
|
|
343
|
+
|
|
251
344
|
dispose(): void {
|
|
345
|
+
this.#dropSpecRound();
|
|
252
346
|
this.conv?.dispose();
|
|
253
347
|
this.recurrent?.dispose();
|
|
254
348
|
this.conv = null;
|
|
@@ -304,6 +398,8 @@ export class SSMCache implements Cache {
|
|
|
304
398
|
if (this.offsets) this.offsets = keep.map((i) => this.offsets![i]!);
|
|
305
399
|
}
|
|
306
400
|
|
|
401
|
+
filterRows(keep: readonly number[]): void { this.filter([...keep]); }
|
|
402
|
+
|
|
307
403
|
/** Row `i` as a fresh SERIAL cache — port of mlx-lm ArraysCache.extract
|
|
308
404
|
* (cache.py:673-676: `cache.cache = [c[idx : idx + 1] for c in self.cache]`,
|
|
309
405
|
* a B-axis slice of every state slot). Ours are OWNED contiguous copies
|
|
@@ -319,7 +415,7 @@ export class SSMCache implements Cache {
|
|
|
319
415
|
const hi = [...a.shape];
|
|
320
416
|
hi[0] = i + 1;
|
|
321
417
|
const view = a.slice(lo, hi);
|
|
322
|
-
const own = ops.contiguous(view)
|
|
418
|
+
const own = ops.copyOf(view); // TRUE copy: contiguous(view) is a no-op VIEW when already contiguous — pins the source buffer (2026-08-20 DeltaNet conv leak class)
|
|
323
419
|
view.dispose();
|
|
324
420
|
return own;
|
|
325
421
|
};
|