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
package/src/prompt-cache.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { type CheckpointAttachment, materializeCheckpoint, attachmentBytes, cloneAttachments, disposeAttachments } from "./backends/mlx/checkpoint-state";
|
|
2
|
+
import { leaseCacheState, minimumReusableOffset } from "./backends/mlx/state-views";
|
|
3
|
+
import { withResource, cleanupFailure, disposeResources, ownResource } from "./engine/resources";
|
|
1
4
|
// Byte-capped LRU prompt cache — the RAM tier of the Layer-0 KV store.
|
|
2
5
|
//
|
|
3
6
|
// The mlx-lm lesson (PLAN.md): a count-capped cache of multi-GB KV
|
|
@@ -5,14 +8,12 @@
|
|
|
5
8
|
// per entry) and evicts least-recently-used until under the cap.
|
|
6
9
|
//
|
|
7
10
|
// Usage pattern (single generation queue, so take/put is race-free):
|
|
8
|
-
// const hit = cache.take(promptIds); // longest-prefix match
|
|
11
|
+
// const hit = cache.take(promptIds); // longest-prefix match
|
|
9
12
|
// generate(model, promptIds, { cache: hit?.caches ?? fresh })
|
|
10
13
|
// cache.put([...promptIds, ...generated], caches, ns, hit?.retain);
|
|
11
|
-
// take()
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// prefix-ancestors (when the new entry is trimmable) so a conversation
|
|
15
|
-
// stays one entry, not one per turn.
|
|
14
|
+
// take() lends zero-copy views and leaves every RAM donor in place, including
|
|
15
|
+
// recurrent and method state. SSD persistence runs independently of RAM reuse.
|
|
16
|
+
// put() supersedes same-ns prefix-ancestors when the new entry is trimmable.
|
|
16
17
|
//
|
|
17
18
|
// TIERING (Layer 0, unified-engine plan): when a ColdTier is attached,
|
|
18
19
|
// take() itself runs the two-tier dance — RAM peek vs cold find, restore
|
|
@@ -25,6 +26,7 @@
|
|
|
25
26
|
// snapshot for both lanes.
|
|
26
27
|
|
|
27
28
|
import type { Cache } from "./model/gemma4";
|
|
29
|
+
import type { PrefixCache, PrefixCacheHit } from "./contracts/prefix-cache";
|
|
28
30
|
import { cloneKvCaches } from "./kv-store";
|
|
29
31
|
|
|
30
32
|
/** Reference-counted release: wraps an entry's `retain` (e.g. an mmap
|
|
@@ -55,8 +57,9 @@ function makeSharedRetain(retain: (() => void) | undefined): { acquire(): () =>
|
|
|
55
57
|
|
|
56
58
|
/** The cold (SSD) tier the RAM cache tiers over. Structural — this module
|
|
57
59
|
* never imports ssd-cache (which imports us); the server binds
|
|
58
|
-
* SsdCacheStore + the model into this shape (src/server.ts).
|
|
59
|
-
*
|
|
60
|
+
* SsdCacheStore + the model into this shape (src/server.ts). Lookup and
|
|
61
|
+
* restore failures return null; store returns false on failure. Operations
|
|
62
|
+
* that require persistence retain their donor if storing fails. */
|
|
60
63
|
export interface ColdTier {
|
|
61
64
|
/** Longest stored usable prefix for prompt/ns — index-only, no I/O.
|
|
62
65
|
* `handle` is the tier's opaque entry token, passed back to restore. */
|
|
@@ -64,8 +67,10 @@ export interface ColdTier {
|
|
|
64
67
|
/** Materialize a found entry as GPU-visible caches (zero-copy COW mmap;
|
|
65
68
|
* pages fault in lazily). `retain` must run after the caches are
|
|
66
69
|
* disposed (it unmaps the backing file). Null on any failure. */
|
|
67
|
-
restore(handle: unknown): { tokens: number[]; caches: Cache[]; retain: () => void } | null;
|
|
68
|
-
|
|
70
|
+
restore(handle: unknown): { tokens: number[]; caches: Cache[]; attachments?: CheckpointAttachment[]; retain: () => void } | null;
|
|
71
|
+
/** Borrow live caches and finish persistence before returning. A false
|
|
72
|
+
* result prevents a required demotion. */
|
|
73
|
+
store(tokens: number[], caches: Cache[], ns: string, attachments?: CheckpointAttachment[]): boolean | void;
|
|
69
74
|
}
|
|
70
75
|
|
|
71
76
|
/** Spill sink for eviction/demotion (write-behind, 2026-07-06).
|
|
@@ -89,9 +94,7 @@ export interface SpillSink {
|
|
|
89
94
|
spillSync?: (entry: PromptCacheEntry) => void;
|
|
90
95
|
}
|
|
91
96
|
|
|
92
|
-
export interface PromptCacheEntry {
|
|
93
|
-
tokens: number[];
|
|
94
|
-
caches: Cache[];
|
|
97
|
+
export interface PromptCacheEntry extends PrefixCacheHit<Cache[], CheckpointAttachment[]> {
|
|
95
98
|
/** Namespace key — adapter spec for LoRA requests ("" = base model).
|
|
96
99
|
* KV computed under one adapter must never seed another's prefill. */
|
|
97
100
|
ns: string;
|
|
@@ -105,14 +108,7 @@ export interface PromptCacheEntry {
|
|
|
105
108
|
export function cacheBytes(caches: Cache[]): number {
|
|
106
109
|
let total = 0;
|
|
107
110
|
for (const c of caches) {
|
|
108
|
-
|
|
109
|
-
for (const a of state) total += a.nbytes;
|
|
110
|
-
// Most Cache kinds' state() returns their own live-owned arrays (safe
|
|
111
|
-
// to just read), but TurboQuantKVCache allocates fresh trimmed slice
|
|
112
|
-
// views per call (kv-store.ts snapshotCache/cloneKvCaches contract) —
|
|
113
|
-
// those must be disposed here or they leak (see generate.ts
|
|
114
|
-
// evalCacheState for the same hazard on the prefill path).
|
|
115
|
-
if (c.stateNeedsDispose) for (const a of state) a.dispose();
|
|
111
|
+
total += withResource(leaseCacheState(c), (state) => state.reduce((bytes, a) => bytes + a.nbytes, 0));
|
|
116
112
|
}
|
|
117
113
|
return total;
|
|
118
114
|
}
|
|
@@ -135,7 +131,7 @@ interface EntryRecord {
|
|
|
135
131
|
share: { acquire(): () => void };
|
|
136
132
|
}
|
|
137
133
|
|
|
138
|
-
export class PromptCache {
|
|
134
|
+
export class PromptCache implements PrefixCache<Cache[], CheckpointAttachment[]> {
|
|
139
135
|
readonly maxBytes: number;
|
|
140
136
|
#entries: EntryRecord[] = [];
|
|
141
137
|
#clock = 0;
|
|
@@ -162,6 +158,7 @@ export class PromptCache {
|
|
|
162
158
|
spill: SpillSink | ((entry: PromptCacheEntry) => void) | null = null,
|
|
163
159
|
cold: ColdTier | null = null,
|
|
164
160
|
clone: (caches: Cache[]) => Cache[] = cloneKvCaches,
|
|
161
|
+
private readonly materialize: (caches: Cache[], attachments?: CheckpointAttachment[]) => void = materializeCheckpoint,
|
|
165
162
|
) {
|
|
166
163
|
this.maxBytes = maxBytes;
|
|
167
164
|
this.#spillOwned = typeof spill === "function" ? null : spill?.spillOwned ?? null;
|
|
@@ -186,24 +183,27 @@ export class PromptCache {
|
|
|
186
183
|
// no backing mmap for retain to unmap, so nothing the clones
|
|
187
184
|
// could alias goes away.
|
|
188
185
|
let clones: Cache[] | null = null;
|
|
186
|
+
let attachments: CheckpointAttachment[] | undefined;
|
|
189
187
|
try {
|
|
190
188
|
clones = this.#clone(entry.caches);
|
|
191
|
-
|
|
189
|
+
attachments = cloneAttachments(entry.attachments);
|
|
190
|
+
this.#spillOwned({ tokens: [...entry.tokens], caches: clones, ns: entry.ns, attachments });
|
|
192
191
|
} catch {
|
|
193
192
|
// Failure degrades to no-spill; eviction/demotion never unwinds.
|
|
194
193
|
if (clones) for (const c of clones) try { c.dispose(); } catch {}
|
|
194
|
+
try { disposeAttachments(attachments); } catch {}
|
|
195
195
|
}
|
|
196
196
|
} else {
|
|
197
197
|
const spill =
|
|
198
198
|
this.#spillSync ??
|
|
199
199
|
(this.#cold
|
|
200
|
-
? (e: PromptCacheEntry) => this.#cold!.store(e.tokens, e.caches, e.ns)
|
|
200
|
+
? (e: PromptCacheEntry) => this.#cold!.store(e.tokens, e.caches, e.ns, e.attachments)
|
|
201
201
|
: null);
|
|
202
202
|
if (spill) try { spill(entry); } catch {}
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
|
-
|
|
206
|
-
entry.retain?.();
|
|
205
|
+
disposeResources([...entry.caches, { dispose: () => disposeAttachments(entry.attachments) }]);
|
|
206
|
+
entry.retain?.(); // backing release requires successful cache disposal
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
get totalBytes(): number {
|
|
@@ -214,14 +214,36 @@ export class PromptCache {
|
|
|
214
214
|
return this.#entries.length;
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
/** Release LRU entries until the caller's live-memory check is satisfied.
|
|
218
|
+
* Unlike background eviction, pressure relief must finish the SSD write
|
|
219
|
+
* and release the buffers now, not enqueue clones that keep them alive.
|
|
220
|
+
* Call under the engine lock, after taking the request's reusable prefix. */
|
|
221
|
+
relievePressure(overBudget: () => boolean): number {
|
|
222
|
+
let count = 0;
|
|
223
|
+
while (this.#entries.length && overBudget()) {
|
|
224
|
+
let oldest = 0;
|
|
225
|
+
for (let i = 1; i < this.#entries.length; i++)
|
|
226
|
+
if (this.#entries[i]!.lastUsed < this.#entries[oldest]!.lastUsed) oldest = i;
|
|
227
|
+
const { entry } = this.#entries[oldest]!;
|
|
228
|
+
// Keep the entry resident if persistence throws. A failed SSD write
|
|
229
|
+
// must not be presented as a successful demotion.
|
|
230
|
+
if (this.#cold) {
|
|
231
|
+
if (this.#cold.store(entry.tokens, entry.caches, entry.ns, entry.attachments) === false) break;
|
|
232
|
+
}
|
|
233
|
+
else this.#spillSync?.(entry);
|
|
234
|
+
this.#entries.splice(oldest, 1);
|
|
235
|
+
this.#disposeEntry(entry, false);
|
|
236
|
+
this.demotions++;
|
|
237
|
+
count++;
|
|
238
|
+
}
|
|
239
|
+
return count;
|
|
240
|
+
}
|
|
241
|
+
|
|
217
242
|
/** Find the entry with the longest usable common prefix of `prompt`
|
|
218
|
-
* across BOTH tiers
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* prefix. The caller owns the returned caches — dispose them or put()
|
|
223
|
-
* an extended entry (which supersedes prefix-ancestors), honoring
|
|
224
|
-
* `retain` either way.
|
|
243
|
+
* across BOTH tiers. Every RAM entry lends zero-copy views and retains its
|
|
244
|
+
* donor, including exact-boundary recurrent state and method attachments.
|
|
245
|
+
* The caller owns the returned views —
|
|
246
|
+
* dispose them or put() an extended entry, honoring `retain` either way.
|
|
225
247
|
*
|
|
226
248
|
* Usable prefix = common prefix capped at prompt.length - 1 (at least
|
|
227
249
|
* one token must be forwarded to produce logits). Entries longer than
|
|
@@ -241,9 +263,9 @@ export class PromptCache {
|
|
|
241
263
|
const e = this.#entries[i]!.entry;
|
|
242
264
|
if (e.ns !== ns) continue;
|
|
243
265
|
const p = Math.min(commonPrefixLength(e.tokens, prompt), prompt.length - 1);
|
|
244
|
-
if (p <= bestLen) continue;
|
|
266
|
+
if (p <= bestLen || p < minimumReusableOffset(e.caches)) continue;
|
|
245
267
|
const trimNeeded = e.tokens.length - p;
|
|
246
|
-
if (trimNeeded > 0 && !e.caches.every((c) => c.isTrimmable())) continue;
|
|
268
|
+
if (trimNeeded > 0 && (!!e.attachments?.length || !e.caches.every((c) => c.isTrimmable()))) continue;
|
|
247
269
|
bestLen = p;
|
|
248
270
|
bestIdx = i;
|
|
249
271
|
}
|
|
@@ -258,27 +280,23 @@ export class PromptCache {
|
|
|
258
280
|
if (hit && hit.prefixLen > bestLen) {
|
|
259
281
|
const loaded = this.#cold.restore(hit.handle);
|
|
260
282
|
if (loaded) {
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
ns,
|
|
279
|
-
retain: loaded.retain,
|
|
280
|
-
};
|
|
281
|
-
}
|
|
283
|
+
const owner = ownResource(loaded, (entry) =>
|
|
284
|
+
this.#disposeEntry({ ...entry, ns }, false));
|
|
285
|
+
const result = withResource(owner, (entry) => {
|
|
286
|
+
const trimNeeded = entry.tokens.length - hit.prefixLen;
|
|
287
|
+
if (hit.prefixLen < minimumReusableOffset(entry.caches)) return null;
|
|
288
|
+
if (trimNeeded > 0 && (!!entry.attachments?.length || !entry.caches.every((cache) => cache.isTrimmable()))) {
|
|
289
|
+
console.warn(
|
|
290
|
+
`[prompt-cache] cold entry unusable: ${entry.tokens.length} tokens, ` +
|
|
291
|
+
`needs trim ${trimNeeded} but untrimmable (wrapped ring/SSM) — re-prefilling`,
|
|
292
|
+
);
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
if (trimNeeded > 0) for (const cache of entry.caches) cache.trim(trimNeeded);
|
|
296
|
+
const tokens = entry.tokens.slice(0, hit.prefixLen);
|
|
297
|
+
return { ...owner.transfer(), tokens, ns };
|
|
298
|
+
});
|
|
299
|
+
if (result) return result;
|
|
282
300
|
}
|
|
283
301
|
}
|
|
284
302
|
}
|
|
@@ -296,12 +314,22 @@ export class PromptCache {
|
|
|
296
314
|
const rec = this.#entries[bestIdx]!;
|
|
297
315
|
rec.lastUsed = ++this.#clock;
|
|
298
316
|
rec.lastUsedMs = Date.now();
|
|
317
|
+
// Lend immutable views for every backend state. RAM retention and SSD
|
|
318
|
+
// durability remain cache responsibilities while the caller extends its
|
|
319
|
+
// own views. This keeps synchronous persistence out of a RAM hit.
|
|
299
320
|
const clones = this.#clone(rec.entry.caches);
|
|
321
|
+
let attachments: CheckpointAttachment[] | undefined;
|
|
300
322
|
const trimNeeded = rec.entry.tokens.length - bestLen;
|
|
301
|
-
|
|
323
|
+
try {
|
|
324
|
+
attachments = cloneAttachments(rec.entry.attachments);
|
|
325
|
+
if (trimNeeded > 0) for (const c of clones) c.trim(trimNeeded);
|
|
326
|
+
} catch (error) {
|
|
327
|
+
cleanupFailure(error, () => disposeResources([...clones, { dispose: () => disposeAttachments(attachments) }]));
|
|
328
|
+
}
|
|
302
329
|
return {
|
|
303
330
|
tokens: rec.entry.tokens.slice(0, bestLen),
|
|
304
331
|
caches: clones,
|
|
332
|
+
attachments,
|
|
305
333
|
ns,
|
|
306
334
|
retain: rec.share.acquire(),
|
|
307
335
|
};
|
|
@@ -314,9 +342,9 @@ export class PromptCache {
|
|
|
314
342
|
for (const { entry: e } of this.#entries) {
|
|
315
343
|
if (e.ns !== ns) continue;
|
|
316
344
|
const p = Math.min(commonPrefixLength(e.tokens, prompt), prompt.length - 1);
|
|
317
|
-
if (p <= best) continue;
|
|
345
|
+
if (p <= best || p < minimumReusableOffset(e.caches)) continue;
|
|
318
346
|
const trimNeeded = e.tokens.length - p; // same usability rule as take()
|
|
319
|
-
if (trimNeeded > 0 && !e.caches.every((c) => c.isTrimmable())) continue;
|
|
347
|
+
if (trimNeeded > 0 && (!!e.attachments?.length || !e.caches.every((c) => c.isTrimmable()))) continue;
|
|
320
348
|
best = p;
|
|
321
349
|
}
|
|
322
350
|
return best;
|
|
@@ -336,11 +364,23 @@ export class PromptCache {
|
|
|
336
364
|
/** Insert (or reinsert) an entry; evicts LRU entries over the byte cap
|
|
337
365
|
* (spilling each to the cold tier first, when one is attached). If the
|
|
338
366
|
* entry itself exceeds the cap it is spilled + disposed, not stored. */
|
|
339
|
-
put(tokens: number[], caches: Cache[], ns = "", retain?: () => void): void {
|
|
340
|
-
|
|
341
|
-
const
|
|
367
|
+
put(tokens: number[], caches: Cache[], ns = "", retain?: () => void, attachments?: CheckpointAttachment[]): void {
|
|
368
|
+
// All cache-provided validation runs before ownership is adopted.
|
|
369
|
+
const bytes = cacheBytes(caches) + attachmentBytes(attachments);
|
|
370
|
+
const trimmable = !attachments?.length && caches.every((cache) => cache.isTrimmable());
|
|
371
|
+
// Storage takes resolved snapshots, independently of their producer.
|
|
372
|
+
this.materialize(caches, attachments);
|
|
373
|
+
const discard = (entry: PromptCacheEntry, spill: boolean) => {
|
|
374
|
+
try { this.#disposeEntry(entry, spill); }
|
|
375
|
+
catch (error) {
|
|
376
|
+
// The new entry is already owned here. Throwing back to its previous
|
|
377
|
+
// owner would invite disposal of state still held by this store.
|
|
378
|
+
console.warn(`[prompt-cache] entry cleanup failed: ${error}`);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
const entry: PromptCacheEntry = { tokens, caches, ns, retain, attachments };
|
|
342
382
|
if (bytes > this.maxBytes) {
|
|
343
|
-
|
|
383
|
+
discard(entry, true);
|
|
344
384
|
return;
|
|
345
385
|
}
|
|
346
386
|
// The donor's retain becomes ref-counted so take()'s clones can hold
|
|
@@ -359,7 +399,7 @@ export class PromptCache {
|
|
|
359
399
|
if (old.entry.tokens.length !== tokens.length) continue;
|
|
360
400
|
if (commonPrefixLength(old.entry.tokens, tokens) !== tokens.length) continue;
|
|
361
401
|
this.#entries = this.#entries.filter((r) => r !== old);
|
|
362
|
-
|
|
402
|
+
discard(old.entry, false);
|
|
363
403
|
}
|
|
364
404
|
// SUPERSEDE strict prefix-ancestors (the SSD store's rule, brought to
|
|
365
405
|
// RAM — prefix sharing would otherwise grow an entry per turn): same-ns
|
|
@@ -370,13 +410,13 @@ export class PromptCache {
|
|
|
370
410
|
// can only serve exact-length matches, so shorter ancestors — e.g.
|
|
371
411
|
// the prompt-boundary snapshot that makes drifted multi-turn agents
|
|
372
412
|
// hit — must survive.
|
|
373
|
-
if (
|
|
413
|
+
if (trimmable) {
|
|
374
414
|
for (const old of [...this.#entries]) {
|
|
375
415
|
if (old === rec || old.entry.ns !== ns) continue;
|
|
376
|
-
if (old.entry.tokens.length >= tokens.length) continue;
|
|
416
|
+
if (old.entry.tokens.length >= tokens.length || old.entry.tokens.length < minimumReusableOffset(caches)) continue;
|
|
377
417
|
if (commonPrefixLength(old.entry.tokens, tokens) !== old.entry.tokens.length) continue;
|
|
378
418
|
this.#entries = this.#entries.filter((r) => r !== old);
|
|
379
|
-
|
|
419
|
+
discard(old.entry, false);
|
|
380
420
|
}
|
|
381
421
|
}
|
|
382
422
|
while (this.totalBytes > this.maxBytes && this.#entries.length > 1) {
|
|
@@ -384,7 +424,7 @@ export class PromptCache {
|
|
|
384
424
|
for (let i = 1; i < this.#entries.length; i++)
|
|
385
425
|
if (this.#entries[i]!.lastUsed < this.#entries[lruIdx]!.lastUsed) lruIdx = i;
|
|
386
426
|
const [evicted] = this.#entries.splice(lruIdx, 1);
|
|
387
|
-
|
|
427
|
+
discard(evicted!.entry, true);
|
|
388
428
|
}
|
|
389
429
|
try { this.onPut?.(tokens, ns); } catch {}
|
|
390
430
|
}
|
|
@@ -413,7 +453,8 @@ export class PromptCache {
|
|
|
413
453
|
}
|
|
414
454
|
|
|
415
455
|
clear(): void {
|
|
416
|
-
|
|
456
|
+
const entries = this.#entries;
|
|
417
457
|
this.#entries = [];
|
|
458
|
+
disposeResources(entries.map(({ entry }) => ({ dispose: () => this.#disposeEntry(entry, false) })));
|
|
418
459
|
}
|
|
419
460
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// - NaN-sensitivity handling (treat as maximally sensitive)
|
|
12
12
|
// - post-greedy block-run guard
|
|
13
13
|
//
|
|
14
|
-
// Verified bit-for-bit against the Python via tests/quantize-allocator.test.ts.
|
|
14
|
+
// Verified bit-for-bit against the Python via tests/parity/quantize-allocator.test.ts.
|
|
15
15
|
//
|
|
16
16
|
// The latency-aware variants (`optimize_latency_aware`,
|
|
17
17
|
// `optimize_for_latency_budget`) are intentionally NOT ported — they pull in
|
|
@@ -13,7 +13,9 @@ import { existsSync } from "node:fs";
|
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
|
|
15
15
|
/** A per-module quantization override. `false` means "left unquantized". */
|
|
16
|
-
export type PerLayerEntry =
|
|
16
|
+
export type PerLayerEntry =
|
|
17
|
+
| { bits: number; groupSize: number; mode?: string; trellis?: { L: number; code: string; axis: 0 | 1 } }
|
|
18
|
+
| false;
|
|
17
19
|
|
|
18
20
|
/** The default quantization definition for the model. */
|
|
19
21
|
export interface QuantDef {
|
|
@@ -28,7 +30,7 @@ export interface QuantizationBlock {
|
|
|
28
30
|
bits: number;
|
|
29
31
|
mode: string;
|
|
30
32
|
// plus per-module entries: { [modulePath]: {bits, group_size} | false }
|
|
31
|
-
[modulePath: string]: number | string | { bits: number; group_size: number } | false;
|
|
33
|
+
[modulePath: string]: number | string | { bits: number; group_size: number; mode?: string; trellis?: { L: number; code: string; axis: 0 | 1 } } | false;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
/**
|
|
@@ -47,7 +49,12 @@ export function buildQuantizationBlock(
|
|
|
47
49
|
mode: def.mode ?? "affine",
|
|
48
50
|
};
|
|
49
51
|
for (const [path, entry] of perLayer) {
|
|
50
|
-
|
|
52
|
+
if (entry === false) { block[path] = false; continue; }
|
|
53
|
+
const v: { bits: number; group_size: number; mode?: string; trellis?: { L: number; code: string; axis: 0 | 1 } } =
|
|
54
|
+
{ bits: entry.bits, group_size: entry.groupSize };
|
|
55
|
+
if (entry.mode) v.mode = entry.mode;
|
|
56
|
+
if (entry.trellis) v.trellis = entry.trellis;
|
|
57
|
+
block[path] = v;
|
|
51
58
|
}
|
|
52
59
|
return block;
|
|
53
60
|
}
|
package/src/quantize/rotate.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Folds an orthogonal rotation offline into producer/consumer weight pairs so
|
|
4
4
|
// weights are quantized in a basis where outlier channels are smeared into
|
|
5
5
|
// near-Gaussian marginals. Recipe, fold table, and the decided deviations from
|
|
6
|
-
// the QuaRot/SpinQuant references live in docs/design/turboquant
|
|
6
|
+
// the QuaRot/SpinQuant references live in docs/design/turboquant.md —
|
|
7
7
|
// notably: γ-fold FIRST (R1 only commutes with gain-free RMSNorm), SpinQuant's
|
|
8
8
|
// fully-offline per-head R2 (NOT QuaRot's, which needs a runtime op), NO R4
|
|
9
9
|
// half-fold on down_proj's input, NO embedding mean-centering (not an exact
|
|
@@ -47,7 +47,7 @@ function assertPow2(n: number, what: string): void {
|
|
|
47
47
|
if (n < 2 || (n & (n - 1)) !== 0)
|
|
48
48
|
throw new Error(
|
|
49
49
|
`rotation fold: ${what}=${n} is not a power of two — the Kronecker ` +
|
|
50
|
-
`Hadamard path is not implemented (docs/design/turboquant
|
|
50
|
+
`Hadamard path is not implemented (docs/design/turboquant.md)`,
|
|
51
51
|
);
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -323,7 +323,7 @@ export function foldLlamaWeights(
|
|
|
323
323
|
// elementwise in head space) does not commute with a per-head rotation, so R2
|
|
324
324
|
// is architecturally off for this family — recorded in the design doc.
|
|
325
325
|
//
|
|
326
|
-
// Residual corridors (docs/design/turboquant
|
|
326
|
+
// Residual corridors (docs/design/turboquant.md, W1 map):
|
|
327
327
|
// readers (@R1 input dim, γ premultiplied): q/k/v_proj,
|
|
328
328
|
// linear_attn.in_proj_{qkv,z,b,a}, mlp.gate/up_proj, lm_head
|
|
329
329
|
// writers (R1ᵀ output dim): self_attn.o_proj, linear_attn.out_proj,
|
|
@@ -370,7 +370,7 @@ export interface QwenFoldPlan {
|
|
|
370
370
|
* FoldOp — pure name analysis, no arrays. R1-ONLY (+γ): the attention output
|
|
371
371
|
* gate (`o_proj(out · σ(gate))`, elementwise in head space) does not commute
|
|
372
372
|
* with a per-head rotation, so R2 is architecturally off for this family.
|
|
373
|
-
* Corridor map: docs/design/turboquant
|
|
373
|
+
* Corridor map: docs/design/turboquant.md §W1.
|
|
374
374
|
*/
|
|
375
375
|
export function planQwen35Fold(names: readonly string[], prefix = "language_model."): QwenFoldPlan {
|
|
376
376
|
const P = prefix;
|