mlx-bun 0.2.0 → 0.4.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 +94 -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/archive/investigations/openjarvis-fit.md +198 -0
- package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
- package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +1092 -0
- package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
- package/docs/archive/planning/release-notes-v0.3.0.md +35 -0
- package/docs/design/batching.md +1841 -0
- package/docs/design/decode-speed-program.md +2346 -169
- package/docs/design/dreaming-nightly-pipeline.md +675 -282
- package/docs/design/generic-model-support.md +655 -334
- package/docs/design/kv-cache.md +824 -0
- package/docs/design/orpo-training.md +673 -1239
- package/docs/design/speculative-decoding.md +1990 -0
- package/docs/design/turboquant.md +2212 -0
- package/docs/design/unified-engine-frontier-plan.md +1833 -727
- package/docs/design/web-chat-redesign.md +666 -1083
- package/docs/planning/PRODUCT_ROADMAP.md +50 -1
- package/docs/planning/release-notes-v0.4.0.md +45 -0
- package/docs/planning/video-series.md +2 -2
- package/docs/reference/benchmarks.md +3613 -0
- package/docs/reference/cli.md +434 -160
- package/docs/reference/distribution.md +328 -182
- package/docs/reference/environment.md +398 -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 +113 -6
- package/docs/reference/server-api.md +944 -429
- package/docs/reference/server-config.md +740 -338
- package/docs/reference/training.md +393 -254
- package/docs/reference/troubleshooting.md +158 -0
- package/package.json +9 -4
- package/src/audio/decode.ts +2 -2
- package/src/audio/features.ts +2 -2
- package/src/backends/mlx/assistant-target.ts +46 -0
- package/src/backends/mlx/autoregressive-draft-rows.ts +120 -0
- package/src/backends/mlx/autoregressive.ts +108 -0
- package/src/backends/mlx/batch-group.ts +1790 -0
- package/src/backends/mlx/cache-attachment.ts +67 -0
- package/src/backends/mlx/cache-layout.ts +31 -0
- package/src/backends/mlx/checkpoint-state.ts +53 -0
- package/src/backends/mlx/continuation-persistence.ts +106 -0
- package/src/backends/mlx/continuation-request.ts +43 -0
- package/src/backends/mlx/continuation.ts +77 -0
- package/src/backends/mlx/diffusion.ts +39 -0
- package/src/backends/mlx/draft-target.ts +32 -0
- package/src/backends/mlx/evaluation.ts +105 -0
- package/src/backends/mlx/fill-append.ts +45 -0
- package/src/backends/mlx/full-kv-row-append.ts +32 -0
- package/src/backends/mlx/full-kv-row-donor.ts +54 -0
- package/src/backends/mlx/full-transitioning-kv-rows.ts +65 -0
- package/src/backends/mlx/gateway-binding.ts +130 -0
- package/src/backends/mlx/graph.ts +38 -0
- package/src/backends/mlx/kv-codec.ts +9 -0
- package/src/backends/mlx/kv-maintenance.ts +133 -0
- package/src/backends/mlx/kv-tensor-rows.ts +212 -0
- package/src/backends/mlx/memory-client.ts +189 -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-cohort.ts +89 -0
- package/src/backends/mlx/prefill-rows.ts +200 -0
- package/src/backends/mlx/prefill.ts +33 -0
- package/src/backends/mlx/projected-context-rows.ts +72 -0
- package/src/backends/mlx/request-policy.ts +20 -0
- package/src/backends/mlx/request-state-policy.ts +41 -0
- package/src/backends/mlx/rollback.ts +89 -0
- package/src/backends/mlx/row-sampling.ts +49 -0
- package/src/backends/mlx/serial-executor.ts +242 -0
- package/src/backends/mlx/speculative-group.ts +359 -0
- package/src/backends/mlx/speculative-round.ts +161 -0
- package/src/backends/mlx/speculative.ts +114 -0
- package/src/backends/mlx/state-rows.ts +104 -0
- package/src/backends/mlx/state-views.ts +46 -0
- package/src/backends/mlx/target-layout-capability.ts +35 -0
- package/src/backends/mlx/text-engine.ts +73 -0
- package/src/backends/mlx/transitioning-kv-rows.ts +165 -0
- package/src/cli.ts +66 -58
- package/src/client.ts +66 -0
- package/src/config.ts +21 -4
- package/src/contracts/completion.ts +16 -0
- package/src/contracts/execution.ts +60 -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/prefix-cache.ts +23 -0
- package/src/contracts/resources.ts +25 -0
- package/src/contracts/sampling.ts +23 -0
- package/src/contracts/scheduling.ts +45 -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 +53 -0
- package/src/engine/resources.ts +53 -0
- package/src/engine/scheduler.ts +72 -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 +30 -16
- package/src/generate.ts +709 -417
- 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/draft-acceptance.ts +41 -0
- package/src/inference/draft-output.ts +49 -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-scheme.ts +70 -12
- package/src/kv-store.ts +177 -63
- 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/lab/paged-kv/paged-kv-rows.ts +83 -0
- package/src/{model → lab/paged-kv}/paged-kv.ts +32 -15
- 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 +11 -11
- 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/artifact-identity.ts +73 -0
- package/src/model/batched-kv.ts +235 -0
- package/src/model/batched-mask.ts +20 -6
- package/src/model/batched-quant.ts +9 -3
- package/src/model/batched-quantized-kv.ts +144 -0
- package/src/model/batched-rotating-quant.ts +78 -17
- package/src/model/batched-rotating-state.ts +76 -0
- package/src/model/batched-rotating.ts +65 -23
- package/src/model/batched-row-storage.ts +52 -0
- package/src/model/batched-ssm.ts +52 -0
- package/src/model/batched-turboquant-kv.ts +93 -0
- package/src/model/compiled-decode.ts +8 -2
- package/src/model/decoded-kv-donor.ts +12 -0
- package/src/model/delayed-quantized-kv.ts +72 -0
- package/src/model/delayed-rotating-quantized-kv.ts +93 -0
- package/src/model/delayed-turboquant-kv.ts +55 -0
- 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/full-prefill-padding.ts +56 -0
- package/src/model/full-prefill-row.ts +105 -0
- package/src/model/gemma4-base.ts +179 -80
- package/src/model/gemma4.ts +40 -32
- package/src/model/generated/gemma4-12b.ts +6 -3
- package/src/model/generated/gemma4-26b.ts +6 -3
- package/src/model/generated/gemma4-e4b.ts +6 -3
- package/src/model/glm52-cache.ts +80 -4
- package/src/model/glm52-dsa.ts +13 -9
- package/src/model/glm52-memory.ts +1 -1
- package/src/model/glm52-mla.ts +12 -6
- package/src/model/glm52.ts +19 -40
- package/src/model/implementation.ts +69 -0
- package/src/model/kv-attention-view.ts +67 -0
- package/src/model/minicpm5.ts +17 -15
- 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-delta-state.ts +74 -0
- package/src/model/qwen3-delta.ts +59 -36
- package/src/model/qwen3_5-checkpoint.ts +164 -0
- package/src/model/qwen3_5.ts +202 -78
- package/src/model/rotating-kv-donor.ts +35 -0
- package/src/model/rotating-kv-layout.ts +262 -0
- package/src/model/rotating-row-transaction.ts +35 -0
- package/src/model/speculative-rotating-kv.ts +101 -0
- package/src/model/ssm-prefill-padding.ts +39 -0
- 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/turboquant-codec.ts +83 -0
- package/src/model/universal/dense.ts +15 -14
- 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/preflight.ts +31 -15
- package/src/prompt-cache.ts +110 -69
- 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 +40 -29
- 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 +183 -213
- 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 +511 -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 +23 -18
- package/src/serve/request-prep.ts +344 -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 +335 -2711
- package/src/spec/assistant-rows.ts +92 -0
- package/src/spec/assistant-source.ts +31 -55
- package/src/spec/cache-identity.ts +22 -0
- package/src/spec/deepspec-rows.ts +29 -0
- package/src/spec/deepspec-source.ts +16 -14
- package/src/spec/dflash-source.ts +36 -12
- package/src/spec/drafter.ts +153 -142
- package/src/spec/dspark/ab-stats.ts +3 -3
- package/src/spec/dspark/calibration.ts +2 -2
- package/src/spec/dspark/deepspec-module.ts +97 -122
- 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 +129 -172
- 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-graph.ts +29 -0
- package/src/spec/glm52-mtp-rows.ts +132 -0
- package/src/spec/glm52-mtp-source.ts +54 -137
- package/src/spec/glm52-mtp-state.ts +33 -0
- package/src/spec/ngram-source.ts +93 -21
- package/src/spec/projected-draft-rows.ts +73 -0
- package/src/spec/qwen-mtp-module.ts +171 -0
- package/src/spec/qwen-mtp-rows.ts +219 -0
- package/src/spec/qwen-mtp-source.ts +147 -195
- package/src/spec/qwen-mtp-state.ts +30 -0
- package/src/spec/serve-loop.ts +201 -201
- package/src/spec/source.ts +110 -13
- package/src/spec/two-model-rows.ts +61 -0
- package/src/spec/two-model.ts +44 -102
- package/src/ssd-cache.ts +99 -19
- package/src/ssd-durability.ts +36 -20
- 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 +62 -60
- 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
|
@@ -21,187 +21,49 @@
|
|
|
21
21
|
// (held over from the verify tap). Computationally identical to mlx-vlm's
|
|
22
22
|
// commit-time "seed" append, just performed at the top of the next round.
|
|
23
23
|
//
|
|
24
|
-
//
|
|
25
|
-
// already sanitized
|
|
24
|
+
// Companion projections may be dense or quantized according to their metadata.
|
|
25
|
+
// Published drafter norms are already sanitized to runtime layout; no +1.0 shift.
|
|
26
26
|
|
|
27
27
|
import { MlxArray } from "../mlx/array";
|
|
28
28
|
import * as ops from "../mlx/ops";
|
|
29
|
+
import { materializeCopy } from "../mlx/materialize";
|
|
29
30
|
import { toLogprobs } from "../sampler";
|
|
30
31
|
import { loadModelConfig, type ModelConfig } from "../config";
|
|
31
32
|
import { Weights } from "../weights";
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import
|
|
33
|
+
import { KVCache } from "../model/gemma4-base";
|
|
34
|
+
import { MtpModule } from "./qwen-mtp-module";
|
|
35
|
+
import type { DraftProvider, DraftSource, DraftRowCheckpoint, DraftRowGroup, DraftPrefillGroup, DraftRowSampling, GroupedDraftProvider, QwenMtpTarget, TargetView } from "./source";
|
|
36
|
+
import { QwenMtpRows, type MtpRowState } from "./qwen-mtp-rows";
|
|
37
|
+
import { captureQwenMtpState, restoreQwenMtpState } from "./qwen-mtp-state";
|
|
38
|
+
import type { Cache } from "../model/gemma4";
|
|
39
|
+
import { applyStateChanges, cleanupFailure, disposeResources } from "../engine/resources";
|
|
40
|
+
import { artifactIdentity } from "../model/artifact-identity";
|
|
41
|
+
import { configFingerprint } from "../model/fingerprint";
|
|
42
|
+
import type { PreparedStateChange } from "../contracts/resources";
|
|
36
43
|
|
|
37
44
|
type Sampler = (logprobs: MlxArray, step: number) => MlxArray;
|
|
38
45
|
|
|
39
46
|
const DRAFT_PREFILL_CHUNK = 2048;
|
|
40
47
|
|
|
41
|
-
/** Dense-weight clone of Qwen3Attention.forward (src/model/qwen3_5.ts —
|
|
42
|
-
* ops copied verbatim; only the projection flavor differs: the drafter is
|
|
43
|
-
* bf16, the target's class hardwires QuantizedLinear). */
|
|
44
|
-
class MtpAttention {
|
|
45
|
-
readonly qProj: DenseLinear;
|
|
46
|
-
readonly kProj: DenseLinear;
|
|
47
|
-
readonly vProj: DenseLinear;
|
|
48
|
-
readonly oProj: DenseLinear;
|
|
49
|
-
readonly qNorm: RMSNorm;
|
|
50
|
-
readonly kNorm: RMSNorm;
|
|
51
|
-
readonly nHeads: number;
|
|
52
|
-
readonly nKvHeads: number;
|
|
53
|
-
readonly headDim: number;
|
|
54
|
-
readonly scale: number;
|
|
55
|
-
readonly ropeDims: number;
|
|
56
|
-
readonly ropeBase: number;
|
|
57
|
-
|
|
58
|
-
constructor(weights: Weights, config: ModelConfig, prefix: string) {
|
|
59
|
-
const t = config.text;
|
|
60
|
-
this.nHeads = t.numAttentionHeads;
|
|
61
|
-
this.nKvHeads = t.numKeyValueHeads;
|
|
62
|
-
this.headDim = t.headDim;
|
|
63
|
-
this.scale = Math.pow(this.headDim, -0.5);
|
|
64
|
-
this.ropeDims = Math.trunc(this.headDim * t.partialRotaryFactor);
|
|
65
|
-
this.ropeBase = t.ropeParameters.full_attention?.ropeTheta ?? 10000;
|
|
66
|
-
const dense = (path: string): DenseLinear =>
|
|
67
|
-
new DenseLinear(weights.tensor(`${path}.weight`), null);
|
|
68
|
-
this.qProj = dense(`${prefix}.q_proj`);
|
|
69
|
-
this.kProj = dense(`${prefix}.k_proj`);
|
|
70
|
-
this.vProj = dense(`${prefix}.v_proj`);
|
|
71
|
-
this.oProj = dense(`${prefix}.o_proj`);
|
|
72
|
-
this.qNorm = new RMSNorm(weights.tensor(`${prefix}.q_norm.weight`), t.rmsNormEps);
|
|
73
|
-
this.kNorm = new RMSNorm(weights.tensor(`${prefix}.k_norm.weight`), t.rmsNormEps);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
forward(x: MlxArray, mask: Mask, cache: KVCache): MlxArray {
|
|
77
|
-
const [B, L] = x.shape as [number, number, number];
|
|
78
|
-
const qp = this.qProj.forward(x);
|
|
79
|
-
const qpr = disposing(qp, ops.reshape(qp, [B, L, this.nHeads, this.headDim * 2]));
|
|
80
|
-
const [qHeads, gateHeads] = ops.split(qpr, [this.headDim], -1) as [MlxArray, MlxArray];
|
|
81
|
-
qpr.dispose();
|
|
82
|
-
const gate = disposing(gateHeads, ops.reshape(gateHeads, [B, L, this.nHeads * this.headDim]));
|
|
83
|
-
|
|
84
|
-
let k = this.kProj.forward(x);
|
|
85
|
-
let v = this.vProj.forward(x);
|
|
86
|
-
|
|
87
|
-
let q = this.qNorm.forward(qHeads);
|
|
88
|
-
qHeads.dispose();
|
|
89
|
-
q = disposing(q, ops.transposeAxes(q, [0, 2, 1, 3]));
|
|
90
|
-
k = disposing(k, ops.reshape(k, [B, L, this.nKvHeads, this.headDim]));
|
|
91
|
-
k = disposing(k, this.kNorm.forward(k));
|
|
92
|
-
k = disposing(k, ops.transposeAxes(k, [0, 2, 1, 3]));
|
|
93
|
-
v = disposing(v, ops.reshape(v, [B, L, this.nKvHeads, this.headDim]));
|
|
94
|
-
v = disposing(v, ops.transposeAxes(v, [0, 2, 1, 3]));
|
|
95
|
-
|
|
96
|
-
q = disposing(q, ops.rope(q, this.ropeDims, this.ropeBase, cache.offset, null));
|
|
97
|
-
k = disposing(k, ops.rope(k, this.ropeDims, this.ropeBase, cache.offset, null));
|
|
98
|
-
|
|
99
|
-
const [keys, values] = cache.updateAndFetch(k, v);
|
|
100
|
-
k.dispose();
|
|
101
|
-
v.dispose();
|
|
102
|
-
const attn = ops.sdpa(q, keys, values, this.scale, mask.mode, mask.arr);
|
|
103
|
-
keys.dispose();
|
|
104
|
-
values.dispose();
|
|
105
|
-
q.dispose();
|
|
106
|
-
|
|
107
|
-
const attnT = ops.transposeAxes(attn, [0, 2, 1, 3]);
|
|
108
|
-
attn.dispose();
|
|
109
|
-
const merged = ops.reshape(attnT, [B, L, -1]);
|
|
110
|
-
attnT.dispose();
|
|
111
|
-
const sig = ops.sigmoid(gate);
|
|
112
|
-
gate.dispose();
|
|
113
|
-
const gated = ops.mul(merged, sig);
|
|
114
|
-
merged.dispose();
|
|
115
|
-
sig.dispose();
|
|
116
|
-
const out = this.oProj.forward(gated);
|
|
117
|
-
gated.dispose();
|
|
118
|
-
return out;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** The one MTP decoder block: fc-merge → attention → swiglu MLP → norm. */
|
|
123
|
-
class MtpModule {
|
|
124
|
-
readonly fc: DenseLinear;
|
|
125
|
-
readonly preFcNormEmbedding: RMSNorm;
|
|
126
|
-
readonly preFcNormHidden: RMSNorm;
|
|
127
|
-
readonly attn: MtpAttention;
|
|
128
|
-
readonly mlpGate: DenseLinear;
|
|
129
|
-
readonly mlpUp: DenseLinear;
|
|
130
|
-
readonly mlpDown: DenseLinear;
|
|
131
|
-
readonly inputNorm: RMSNorm;
|
|
132
|
-
readonly postAttnNorm: RMSNorm;
|
|
133
|
-
readonly finalNorm: RMSNorm;
|
|
134
|
-
|
|
135
|
-
constructor(weights: Weights, config: ModelConfig) {
|
|
136
|
-
const eps = config.text.rmsNormEps;
|
|
137
|
-
const dense = (path: string): DenseLinear =>
|
|
138
|
-
new DenseLinear(weights.tensor(`${path}.weight`), null);
|
|
139
|
-
this.fc = dense("fc");
|
|
140
|
-
this.preFcNormEmbedding = new RMSNorm(weights.tensor("pre_fc_norm_embedding.weight"), eps);
|
|
141
|
-
this.preFcNormHidden = new RMSNorm(weights.tensor("pre_fc_norm_hidden.weight"), eps);
|
|
142
|
-
this.attn = new MtpAttention(weights, config, "layers.0.self_attn");
|
|
143
|
-
this.mlpGate = dense("layers.0.mlp.gate_proj");
|
|
144
|
-
this.mlpUp = dense("layers.0.mlp.up_proj");
|
|
145
|
-
this.mlpDown = dense("layers.0.mlp.down_proj");
|
|
146
|
-
this.inputNorm = new RMSNorm(weights.tensor("layers.0.input_layernorm.weight"), eps);
|
|
147
|
-
this.postAttnNorm = new RMSNorm(weights.tensor("layers.0.post_attention_layernorm.weight"), eps);
|
|
148
|
-
this.finalNorm = new RMSNorm(weights.tensor("norm.weight"), eps);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/** One block forward over [1,S,·]: token embeddings ([1,S,H], target
|
|
152
|
-
* embed_tokens output) paired with hiddens ([1,S,H], target pre-final-norm
|
|
153
|
-
* or the module's own chained output). Appends S rows to `cache`; returns
|
|
154
|
-
* the module output [1,S,H] (post final norm — what the target lm_head
|
|
155
|
-
* consumes AND what chains into the next step's `hidden`). */
|
|
156
|
-
forward(tokenEmbeds: MlxArray, hiddens: MlxArray, cache: KVCache): MlxArray {
|
|
157
|
-
const embNorm = this.preFcNormEmbedding.forward(tokenEmbeds);
|
|
158
|
-
const hidNorm = this.preFcNormHidden.forward(hiddens);
|
|
159
|
-
const joined = ops.concatAxis([embNorm, hidNorm], 2);
|
|
160
|
-
embNorm.dispose();
|
|
161
|
-
hidNorm.dispose();
|
|
162
|
-
const x = this.fc.forward(joined);
|
|
163
|
-
joined.dispose();
|
|
164
|
-
|
|
165
|
-
// Decoder layer (Qwen3Layer.forward shape, dense weights).
|
|
166
|
-
const L = x.shape[1]!;
|
|
167
|
-
const mask = cache.makeMask(L, null);
|
|
168
|
-
const xn = this.inputNorm.forward(x);
|
|
169
|
-
const r = this.attn.forward(xn, mask, cache);
|
|
170
|
-
xn.dispose();
|
|
171
|
-
mask.arr?.dispose();
|
|
172
|
-
const h = ops.add(x, r);
|
|
173
|
-
x.dispose();
|
|
174
|
-
r.dispose();
|
|
175
|
-
const hn = this.postAttnNorm.forward(h);
|
|
176
|
-
const g = this.mlpGate.forward(hn);
|
|
177
|
-
const u = this.mlpUp.forward(hn);
|
|
178
|
-
hn.dispose();
|
|
179
|
-
const silu = ops.silu(g);
|
|
180
|
-
g.dispose();
|
|
181
|
-
const act = ops.mul(silu, u);
|
|
182
|
-
silu.dispose();
|
|
183
|
-
u.dispose();
|
|
184
|
-
const m = this.mlpDown.forward(act);
|
|
185
|
-
act.dispose();
|
|
186
|
-
const out = ops.add(h, m);
|
|
187
|
-
h.dispose();
|
|
188
|
-
m.dispose();
|
|
189
|
-
return disposing(out, this.finalNorm.forward(out));
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
48
|
export class QwenMtpProvider implements DraftProvider {
|
|
49
|
+
readonly grouped: GroupedDraftProvider = {
|
|
50
|
+
open: options => this.#openRows(options.target, options.sampling, options.checkpoints),
|
|
51
|
+
openPrefill: options => this.#openRows(options.target, null, options.checkpoints),
|
|
52
|
+
};
|
|
194
53
|
readonly id: string;
|
|
195
54
|
readonly weightsBytes: number;
|
|
196
55
|
readonly #module: MtpModule;
|
|
197
56
|
readonly #config: ModelConfig;
|
|
57
|
+
readonly #resources: DisposableStack;
|
|
58
|
+
readonly #checkpointNamespace: string;
|
|
198
59
|
|
|
199
|
-
private constructor(id: string, config: ModelConfig,
|
|
60
|
+
private constructor(id: string, config: ModelConfig, weightsBytes: number, module: MtpModule, resources: DisposableStack, checkpointNamespace: string) {
|
|
200
61
|
this.id = id;
|
|
201
62
|
this.#config = config;
|
|
202
63
|
this.#module = module;
|
|
203
|
-
this.weightsBytes =
|
|
204
|
-
|
|
64
|
+
this.weightsBytes = weightsBytes;
|
|
65
|
+
this.#resources = resources;
|
|
66
|
+
this.#checkpointNamespace = checkpointNamespace;
|
|
205
67
|
}
|
|
206
68
|
|
|
207
69
|
static async load(dir: string): Promise<QwenMtpProvider> {
|
|
@@ -209,28 +71,81 @@ export class QwenMtpProvider implements DraftProvider {
|
|
|
209
71
|
if (config.modelType !== "qwen3_5_mtp")
|
|
210
72
|
throw new Error(`${dir}: not a qwen3_5_mtp drafter (model_type ${config.modelType})`);
|
|
211
73
|
const weights = await Weights.open(dir);
|
|
74
|
+
using resources = new DisposableStack();
|
|
75
|
+
resources.defer(() => weights.dispose());
|
|
76
|
+
const weightsBytes = [...weights.shards.files.values()]
|
|
77
|
+
.reduce((a, f) => a + f.mmap.size, 0);
|
|
78
|
+
const module = new MtpModule(weights, config, resources);
|
|
79
|
+
// Stable across restarts and distinct for differently folded/quantized
|
|
80
|
+
// companions. Hash once at provider load, outside inference execution.
|
|
81
|
+
const identity = await artifactIdentity(configFingerprint(config),
|
|
82
|
+
[...weights.shards.files].map(([name, shard]) => ({ name, path: shard.path })));
|
|
212
83
|
return new QwenMtpProvider(
|
|
213
84
|
dir.split("/").filter(Boolean).at(-1) ?? "qwen-mtp",
|
|
214
|
-
config,
|
|
85
|
+
config, weightsBytes, module, resources.move(), `qwen-mtp-v1:${identity}`,
|
|
215
86
|
);
|
|
216
87
|
}
|
|
217
88
|
|
|
218
89
|
open(opts: Parameters<DraftProvider["open"]>[0]): DraftSource {
|
|
219
|
-
|
|
220
|
-
|
|
90
|
+
return new QwenMtpSource(this.#target(opts.target), this.#module, opts.sampler, this.#checkpointNamespace);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#target(view: TargetView): QwenMtpTarget {
|
|
94
|
+
if (this.#resources.disposed)
|
|
95
|
+
throw new Error("qwen MTP provider is disposed");
|
|
96
|
+
const target = view.qwenMtp;
|
|
97
|
+
if (!target)
|
|
221
98
|
throw new Error("qwen MTP drafting requires a qwen3_5-family target");
|
|
222
|
-
if (target.
|
|
99
|
+
if (target.hiddenSize !== this.#config.text.hiddenSize) {
|
|
223
100
|
throw new Error(
|
|
224
101
|
`qwen MTP drafter hidden ${this.#config.text.hiddenSize} != target ` +
|
|
225
|
-
`${target.
|
|
102
|
+
`${target.hiddenSize} — split from a different checkpoint?`,
|
|
226
103
|
);
|
|
227
104
|
}
|
|
228
|
-
return
|
|
105
|
+
return target;
|
|
229
106
|
}
|
|
230
107
|
|
|
108
|
+
#openRows(view: TargetView, sampling: DraftRowSampling | null,
|
|
109
|
+
checkpoints: readonly (DraftRowCheckpoint | null)[]): DraftRowGroup & DraftPrefillGroup {
|
|
110
|
+
const target = this.#target(view);
|
|
111
|
+
const rows = new QwenMtpRows(target, this.#module, sampling, []);
|
|
112
|
+
const prepareAppend = (checkpoints: readonly (DraftRowCheckpoint | null)[]) => {
|
|
113
|
+
const states: Array<MtpRowState | null> = [];
|
|
114
|
+
let change: PreparedStateChange | undefined;
|
|
115
|
+
try {
|
|
116
|
+
for (const checkpoint of checkpoints) states.push(checkpoint ? restoreQwenMtpState(checkpoint) : null);
|
|
117
|
+
change = rows.prepareAppend(states);
|
|
118
|
+
disposeResources(states.splice(0).flatMap(state => state ? [state.cache, state.hidden] : []));
|
|
119
|
+
return change;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return cleanupFailure(error, () => disposeResources([
|
|
122
|
+
...states.flatMap(state => state ? [state.cache, state.hidden] : []), ...(change ? [change] : []),
|
|
123
|
+
]));
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const append = (checkpoints: readonly (DraftRowCheckpoint | null)[]) => applyStateChanges([() => prepareAppend(checkpoints)]);
|
|
127
|
+
try { append(checkpoints); }
|
|
128
|
+
catch (error) { return cleanupFailure(error, () => rows.dispose()); }
|
|
129
|
+
return {
|
|
130
|
+
namespace: this.#checkpointNamespace, prefillMode: "full", tapLayers: [target.layerCount - 1],
|
|
131
|
+
get rowCount() { return rows.rowCount; },
|
|
132
|
+
append, prepareAppend, prefill: (tokens, context) => rows.prefill(tokens, context!), materialize: rows.materialize.bind(rows),
|
|
133
|
+
filterRows: rows.filterRows.bind(rows),
|
|
134
|
+
draft: rows.draft.bind(rows), commit: rows.commit.bind(rows),
|
|
135
|
+
capture(row) {
|
|
136
|
+
const state = rows.extractRow(row);
|
|
137
|
+
try { return captureQwenMtpState(state); }
|
|
138
|
+
finally { disposeResources([state.cache, state.hidden]); }
|
|
139
|
+
},
|
|
140
|
+
dispose: rows.dispose.bind(rows),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
|
|
231
145
|
dispose(): void {
|
|
232
|
-
//
|
|
233
|
-
//
|
|
146
|
+
// Release cached transpose views before their native weight maps. MLX
|
|
147
|
+
// retains buffers needed by outstanding GPU commands until completion.
|
|
148
|
+
this.#resources.dispose();
|
|
234
149
|
}
|
|
235
150
|
}
|
|
236
151
|
|
|
@@ -243,10 +158,13 @@ export class QwenMtpSource implements DraftSource {
|
|
|
243
158
|
* The seam's anchorHidden is post-final-norm and is deliberately unused. */
|
|
244
159
|
readonly tapLayers: number[];
|
|
245
160
|
|
|
246
|
-
readonly #target:
|
|
161
|
+
readonly #target: QwenMtpTarget;
|
|
247
162
|
readonly #module: MtpModule;
|
|
248
163
|
readonly #sampler: Sampler;
|
|
249
|
-
|
|
164
|
+
#cache = new KVCache();
|
|
165
|
+
readonly checkpoint: NonNullable<DraftSource["checkpoint"]>;
|
|
166
|
+
#prefilledTokens = 0;
|
|
167
|
+
#hasDrafted = false;
|
|
250
168
|
/** Target pre-norm hidden at the position preceding the next pending
|
|
251
169
|
* token: prefill's last tapped row, then each commit's vCtx row at the
|
|
252
170
|
* emitted position. draft() consumes it to build the pending row. [1,1,H] */
|
|
@@ -254,11 +172,32 @@ export class QwenMtpSource implements DraftSource {
|
|
|
254
172
|
#roundAppended = 0;
|
|
255
173
|
#closed = false;
|
|
256
174
|
|
|
257
|
-
constructor(target:
|
|
175
|
+
constructor(target: QwenMtpTarget, module: MtpModule, sampler: Sampler,
|
|
176
|
+
namespace = "qwen-mtp-v1") {
|
|
258
177
|
this.#target = target;
|
|
259
178
|
this.#module = module;
|
|
260
179
|
this.#sampler = sampler;
|
|
261
|
-
this.tapLayers = [target.
|
|
180
|
+
this.tapLayers = [target.layerCount - 1];
|
|
181
|
+
this.checkpoint = {
|
|
182
|
+
namespace,
|
|
183
|
+
restore: (tokens, attachment) => {
|
|
184
|
+
this.#checkOpen();
|
|
185
|
+
if (this.#prefilledTokens !== 0 || this.#hasDrafted)
|
|
186
|
+
throw new Error("Qwen MTP checkpoint restore requires a fresh source");
|
|
187
|
+
const state = restoreQwenMtpState({ processedTokens: tokens, attachment });
|
|
188
|
+
try { disposeResources([this.#cache, ...(this.#pendingTrueHidden ? [this.#pendingTrueHidden] : [])]); }
|
|
189
|
+
catch (error) { return cleanupFailure(error, () => disposeResources([state.cache, state.hidden])); }
|
|
190
|
+
this.#cache = state.cache;
|
|
191
|
+
this.#pendingTrueHidden = state.hidden;
|
|
192
|
+
this.#prefilledTokens = tokens;
|
|
193
|
+
},
|
|
194
|
+
capture: (tokens) => {
|
|
195
|
+
this.#checkOpen();
|
|
196
|
+
if (!this.#pendingTrueHidden || this.#cache.offset !== tokens - 1 || this.#roundAppended !== 0)
|
|
197
|
+
throw new Error("Qwen MTP snapshot requires an aligned committed boundary");
|
|
198
|
+
return captureQwenMtpState({ cache: this.#cache, hidden: this.#pendingTrueHidden }).attachment;
|
|
199
|
+
},
|
|
200
|
+
};
|
|
262
201
|
}
|
|
263
202
|
|
|
264
203
|
/** Drafter prefill: rows for positions 0..L-2, keyed (token_{p+1}, h_p) —
|
|
@@ -269,27 +208,43 @@ export class QwenMtpSource implements DraftSource {
|
|
|
269
208
|
if (!ctxML)
|
|
270
209
|
throw new Error("qwen MTP prefill requires the tapped pre-final-norm context");
|
|
271
210
|
try {
|
|
272
|
-
if (this.#
|
|
273
|
-
throw new Error("qwen MTP
|
|
211
|
+
if (this.#hasDrafted)
|
|
212
|
+
throw new Error("qwen MTP prefill cannot follow drafting");
|
|
274
213
|
const L = promptIds.length;
|
|
214
|
+
const start = this.#prefilledTokens;
|
|
275
215
|
const H = ctxML.shape[2]!;
|
|
276
|
-
if (ctxML.shape[1]! !== L)
|
|
277
|
-
throw new Error(`qwen MTP tap covered ${ctxML.shape[1]} of ${L} prompt positions`);
|
|
278
|
-
|
|
279
|
-
|
|
216
|
+
if (L <= start || ctxML.shape[1]! !== L - start)
|
|
217
|
+
throw new Error(`qwen MTP tap covered ${ctxML.shape[1]} of ${L - start} new prompt positions`);
|
|
218
|
+
if (start > 0) {
|
|
219
|
+
if (!this.#pendingTrueHidden || this.#cache.offset !== start - 1)
|
|
220
|
+
throw new Error("qwen MTP prefix state is not aligned");
|
|
221
|
+
this.#stepOne(promptIds[start]!, this.#pendingTrueHidden).dispose();
|
|
222
|
+
}
|
|
223
|
+
this.#pendingTrueHidden?.dispose();
|
|
224
|
+
// A slice would retain the complete prompt buffer in the saved prefix.
|
|
225
|
+
// Materialize this one row before handing off the prefill state.
|
|
226
|
+
using tail = ctxML.slice([0, L - start - 1, 0], [1, L - start, H]);
|
|
227
|
+
this.#pendingTrueHidden = materializeCopy(tail);
|
|
228
|
+
for (let pos = start; pos + 1 < L; pos += DRAFT_PREFILL_CHUNK) {
|
|
280
229
|
const n = Math.min(DRAFT_PREFILL_CHUNK, L - 1 - pos);
|
|
281
230
|
const shifted = promptIds.slice(pos + 1, pos + 1 + n);
|
|
282
231
|
const ids = ops.fromInt32(shifted, [1, n]);
|
|
283
|
-
const embeds = this.#target.embed
|
|
232
|
+
const embeds = this.#target.embed(ids);
|
|
284
233
|
ids.dispose();
|
|
285
|
-
const hiddens = ctxML.slice([0, pos, 0], [1, pos + n, H]);
|
|
234
|
+
const hiddens = ctxML.slice([0, pos - start, 0], [1, pos + n - start, H]);
|
|
286
235
|
const out = this.#module.forward(embeds, hiddens, this.#cache);
|
|
287
236
|
embeds.dispose();
|
|
288
237
|
hiddens.dispose();
|
|
289
238
|
out.dispose(); // prefill outputs are not seeds; only KV matters here
|
|
239
|
+
// Bound the lazy KV graph at each chunk. Evaluating the unused output
|
|
240
|
+
// would also execute attention and the MLP, which prefill does not need.
|
|
241
|
+
ops.evalAll(this.#cache.state());
|
|
290
242
|
}
|
|
291
243
|
if (this.#cache.offset !== L - 1)
|
|
292
244
|
throw new Error(`qwen MTP prefill offset ${this.#cache.offset}, expected ${L - 1}`);
|
|
245
|
+
// Also covers a restored-prefix bridge with no subsequent full chunk.
|
|
246
|
+
ops.evalAll([this.#pendingTrueHidden, ...this.#cache.state()]);
|
|
247
|
+
this.#prefilledTokens = L;
|
|
293
248
|
} finally {
|
|
294
249
|
ctxML?.dispose(); // ownership per the seam contract
|
|
295
250
|
}
|
|
@@ -297,6 +252,7 @@ export class QwenMtpSource implements DraftSource {
|
|
|
297
252
|
|
|
298
253
|
async draft(feed: number[], n: number, stepBase: number): Promise<number[]> {
|
|
299
254
|
this.#checkOpen();
|
|
255
|
+
this.#hasDrafted = true;
|
|
300
256
|
if (this.#roundAppended !== 0)
|
|
301
257
|
throw new Error("qwen MTP draft called before the prior round committed");
|
|
302
258
|
if (n <= 0) return [];
|
|
@@ -316,8 +272,8 @@ export class QwenMtpSource implements DraftSource {
|
|
|
316
272
|
this.#pendingTrueHidden.dispose();
|
|
317
273
|
this.#pendingTrueHidden = null;
|
|
318
274
|
this.#roundAppended++;
|
|
319
|
-
drafts.push(this.#sample(out, stepBase));
|
|
320
275
|
chained = out;
|
|
276
|
+
drafts.push(this.#sample(out, stepBase));
|
|
321
277
|
while (drafts.length < n) {
|
|
322
278
|
const out = this.#stepOne(drafts.at(-1)!, chained!);
|
|
323
279
|
chained!.dispose();
|
|
@@ -369,7 +325,7 @@ export class QwenMtpSource implements DraftSource {
|
|
|
369
325
|
const H = vCtxML.shape[2]!;
|
|
370
326
|
if (kAccept === d && d > 0) {
|
|
371
327
|
const ids = ops.fromInt32([acceptedTokens[kAccept - 1]!], [1, 1]);
|
|
372
|
-
const embeds = this.#target.embed
|
|
328
|
+
const embeds = this.#target.embed(ids);
|
|
373
329
|
ids.dispose();
|
|
374
330
|
const hidden = vCtxML.slice([0, d - 1, 0], [1, d, H]);
|
|
375
331
|
const out = this.#module.forward(embeds, hidden, this.#cache);
|
|
@@ -396,33 +352,29 @@ export class QwenMtpSource implements DraftSource {
|
|
|
396
352
|
|
|
397
353
|
/** One module forward for (token, hidden) — appends one KV row. */
|
|
398
354
|
#stepOne(token: number, hidden: MlxArray): MlxArray {
|
|
399
|
-
|
|
400
|
-
|
|
355
|
+
using ids = ops.fromInt32([token], [1, 1]);
|
|
356
|
+
using embed = this.#target.embed(ids);
|
|
401
357
|
ids.dispose();
|
|
402
|
-
|
|
403
|
-
embed.dispose();
|
|
404
|
-
return out;
|
|
358
|
+
return this.#module.forward(embed, hidden, this.#cache);
|
|
405
359
|
}
|
|
406
360
|
|
|
407
361
|
/** Sample a draft token from the module output via the TARGET's lm head
|
|
408
362
|
* and the request sampler (per-step RNG stream discipline). */
|
|
409
363
|
#sample(moduleOut: MlxArray, step: number): number {
|
|
410
|
-
|
|
364
|
+
using logits = this.#target.logitsFromHidden(moduleOut);
|
|
411
365
|
// Sampler contract is [1, V] (the main decode loop's shape). moduleOut
|
|
412
366
|
// is [1, 1, H] → logits [1, 1, V]; without this reshape any sampler
|
|
413
367
|
// that slices 2-D (top-k) throws "[slice] Invalid number of indices…
|
|
414
368
|
// dimension 3" — the serve-lane MTP 500 (chat defaults carry the
|
|
415
369
|
// model's top_k=20; the greedy bench harness never hit it).
|
|
416
370
|
const V = logits.shape[logits.shape.length - 1]!;
|
|
417
|
-
|
|
371
|
+
using flat = ops.reshape(logits, [1, V]);
|
|
418
372
|
logits.dispose();
|
|
419
|
-
|
|
373
|
+
using logprobs = toLogprobs(flat);
|
|
420
374
|
flat.dispose();
|
|
421
|
-
|
|
375
|
+
using tok = this.#sampler(logprobs, step);
|
|
422
376
|
logprobs.dispose();
|
|
423
|
-
|
|
424
|
-
tok.dispose();
|
|
425
|
-
return id;
|
|
377
|
+
return ops.itemUint32(tok);
|
|
426
378
|
}
|
|
427
379
|
|
|
428
380
|
#checkOpen(): void {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { MlxArray } from "../mlx/array";
|
|
2
|
+
import { KVCache } from "../model/gemma4-base";
|
|
3
|
+
import { cloneAttachments } from "../backends/mlx/checkpoint-state";
|
|
4
|
+
import { disposeResources } from "../engine/resources";
|
|
5
|
+
import type { MtpRowState } from "./qwen-mtp-rows";
|
|
6
|
+
import type { DraftRowCheckpoint } from "./source";
|
|
7
|
+
|
|
8
|
+
/** The existing Qwen companion attachment is also the state interchange
|
|
9
|
+
* between prepared requests and a group. Storage-tier policy stays outside. */
|
|
10
|
+
export function restoreQwenMtpState(checkpoint: DraftRowCheckpoint): MtpRowState {
|
|
11
|
+
const { processedTokens: tokens, attachment } = checkpoint;
|
|
12
|
+
if (attachment.schema !== "qwen-mtp-v1" || attachment.metadata.draftOffset !== tokens - 1)
|
|
13
|
+
throw new Error("invalid paired Qwen MTP checkpoint alignment");
|
|
14
|
+
const held = cloneAttachments([attachment])[0]!.tensors;
|
|
15
|
+
let cache: KVCache | null = new KVCache();
|
|
16
|
+
try {
|
|
17
|
+
if (tokens > 1) { cache.restoreState(held[0]!, held[1]!, tokens - 1); held.splice(0, 2); }
|
|
18
|
+
const state = { cache, hidden: held.pop()! }; cache = null; return state;
|
|
19
|
+
} finally { disposeResources([...held, ...(cache ? [cache] : [])]); }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function captureQwenMtpState(state: MtpRowState): DraftRowCheckpoint {
|
|
23
|
+
const held: MlxArray[] = [];
|
|
24
|
+
try {
|
|
25
|
+
if (state.cache.offset > 0) held.push(...state.cache.temporalView());
|
|
26
|
+
held.push(state.hidden.slice([0, 0, 0], [...state.hidden.shape]));
|
|
27
|
+
return { processedTokens: state.cache.offset + 1,
|
|
28
|
+
attachment: { schema: "qwen-mtp-v1", metadata: { draftOffset: state.cache.offset }, tensors: held.splice(0) } };
|
|
29
|
+
} finally { disposeResources(held); }
|
|
30
|
+
}
|