mlx-bun 0.5.0 → 1.0.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 +1449 -109
- package/THIRD_PARTY_NOTICES.md +882 -0
- package/bin/mlx-bun.convert.mjs +4 -0
- package/bin/mlx-bun.fuse.mjs +4 -0
- package/bin/mlx-bun.generate.mjs +4 -0
- package/bin/mlx-bun.lora.mjs +4 -0
- package/bin/mlx-bun.mjs +13 -21
- package/bin/mlx-bun.server.mjs +4 -0
- package/bin/mlx-bun.upload.mjs +4 -0
- package/dist/web/app.js +9584 -0
- package/package.json +50 -53
- package/src/cli/ane-install.ts +76 -0
- package/src/cli/args.ts +179 -0
- package/src/cli/engine-entry.ts +68 -0
- package/src/cli/inference.ts +214 -0
- package/src/cli/job-entry.ts +97 -0
- package/src/cli/library-host.ts +117 -0
- package/src/cli/main.ts +57 -0
- package/src/cli/memory-engine.ts +163 -0
- package/src/cli/memory.ts +36 -0
- package/src/cli/mlx-lm-aliases.ts +309 -0
- package/src/cli/model-choice.ts +33 -0
- package/src/cli/model-selection.ts +84 -0
- package/src/cli/module-host.ts +11 -0
- package/src/cli/module-verbs.ts +50 -0
- package/src/cli/numerical-policy.ts +12 -0
- package/src/cli/perplexity.ts +89 -0
- package/src/cli/serve-host.ts +423 -0
- package/src/cli/serve-isolated.ts +217 -0
- package/src/cli/serve-options.ts +106 -0
- package/src/cli/serve-state.ts +205 -0
- package/src/cli/serve.ts +500 -0
- package/src/cli/served-model-host.ts +102 -0
- package/src/cli/server-entry.ts +148 -0
- package/src/cli/serving-unit.ts +177 -0
- package/src/{tui.ts → cli/terminal.ts} +13 -8
- package/src/cli/worker-adapters.ts +34 -0
- package/src/cli/worker-entry.ts +272 -0
- package/src/cli/worker-unit.ts +179 -0
- package/src/engine/adapter-operation.ts +26 -0
- package/src/engine/cache-services.ts +114 -0
- package/src/engine/completion.ts +39 -0
- package/src/engine/generation-gateway.ts +358 -0
- package/src/engine/index.ts +59 -0
- package/src/engine/kv-budget.ts +120 -0
- package/src/engine/media-preparation.ts +232 -0
- package/src/engine/model-binding.ts +24 -0
- package/src/engine/model-host.ts +513 -0
- package/src/engine/model-serving.ts +89 -0
- package/src/{serve → engine}/preparation.ts +7 -5
- package/src/{serve → engine}/session-completion-engine.ts +6 -6
- package/src/engine/telemetry.ts +109 -0
- package/src/hub/downloads.ts +116 -0
- package/src/jobs/db.ts +16 -7
- package/src/jobs/events.ts +29 -0
- package/src/jobs/executable.ts +5 -0
- package/src/jobs/host.ts +51 -0
- package/src/jobs/in-process.ts +55 -0
- package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
- package/src/jobs/runner.ts +150 -231
- package/src/jobs/service.ts +75 -0
- package/src/jobs/sse.ts +59 -23
- package/src/jobs/worker-memory.ts +46 -0
- package/src/jobs/worker-process.ts +163 -0
- package/src/jobs/worker-supervisor.ts +258 -0
- package/src/modules.ts +58 -0
- package/src/publishing/catalog-hub.ts +18 -0
- package/src/publishing/credentials.ts +31 -0
- package/src/publishing/upload.ts +37 -0
- package/src/residency/leased-adapters.ts +21 -0
- package/src/residency/local-records.ts +16 -0
- package/src/residency/model-residency.ts +405 -0
- package/src/residency/record-index.ts +28 -0
- package/src/residency/resident-estimate.ts +50 -0
- package/src/{anthropic.ts → server/anthropic.ts} +3 -81
- package/src/server/cache-routes.ts +36 -0
- package/src/{serve → server}/chat-request.ts +10 -10
- package/src/{serve → server}/chat-stage.ts +14 -14
- package/src/{client.ts → server/client.ts} +28 -2
- package/src/{serve → server}/completion-executor.ts +33 -41
- package/src/server/decision-body.ts +55 -0
- package/src/server/decision-routes.ts +134 -0
- package/src/server/decision-wire.ts +228 -0
- package/src/{serve → server}/discovery-routes.ts +25 -82
- package/src/{serve → server}/http.ts +25 -13
- package/src/{serve → server}/inference-request.ts +5 -5
- package/src/server/job-routes.ts +20 -0
- package/src/server/media-prompt.ts +63 -0
- package/src/server/memory-completion-client.ts +46 -0
- package/src/server/model-routes.ts +192 -0
- package/src/{serve → server}/openai-wire.ts +3 -2
- package/src/{serve → server}/pipeline.ts +1 -1
- package/src/server/prompt-builder.ts +13 -0
- package/src/server/prompt-contracts.ts +17 -0
- package/src/server/proxy-routes.ts +187 -0
- package/src/server/publishing-routes.ts +41 -0
- package/src/{serve → server}/request-plan.ts +6 -8
- package/src/{serve → server}/request-prep.ts +47 -50
- package/src/{serve → server}/responses-client.ts +30 -13
- package/src/{responses.ts → server/responses.ts} +12 -93
- package/src/server/routes.ts +205 -0
- package/src/server/start.ts +72 -0
- package/src/server/status-routes.ts +108 -0
- package/src/{serve → server}/text-completion-stage.ts +25 -4
- package/src/server/text-prompt.ts +12 -0
- package/src/{serve → server}/token-streams.ts +36 -38
- package/src/server/worker-routes.ts +311 -0
- package/src/storage/paths.ts +61 -0
- package/src/web/assets.ts +37 -0
- package/src/web/{src → browser}/api.ts +5 -23
- package/src/web/browser/chat-host.ts +17 -0
- package/src/web/browser/installed-panels.ts +6 -0
- package/src/web/browser/main.ts +55 -0
- package/src/web/browser/markdown.ts +279 -0
- package/src/web/browser/memory-panel.ts +9 -0
- package/src/web/browser/palette.ts +64 -0
- package/src/web/browser/protocol.ts +13 -0
- package/src/web/browser/shell.ts +467 -0
- package/src/web/{src → browser}/status.ts +32 -36
- package/src/web/build.ts +51 -0
- package/src/web/public/app.html +1054 -0
- package/src/web/{sw.js → public/sw.js} +4 -3
- package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
- package/src/web/{vendor → public/vendor}/hljs.js +2 -2
- package/THIRD_PARTY_LICENSES.md +0 -51
- package/docs/README.md +0 -107
- package/docs/archive/hlg-sampling.md +0 -350
- package/docs/archive/investigations/audio-input-plan.md +0 -356
- package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
- package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
- package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
- package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
- package/docs/archive/investigations/curve-bisector-routing.md +0 -123
- package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
- package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
- package/docs/archive/investigations/dspark-handoff.md +0 -224
- package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
- package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
- package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
- package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
- package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
- package/docs/archive/investigations/lab-build-journal.md +0 -157
- package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
- package/docs/archive/investigations/openjarvis-fit.md +0 -198
- package/docs/archive/investigations/openwiki-evaluation.md +0 -249
- package/docs/archive/investigations/optimization_plan.md +0 -346
- package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
- package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
- package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
- package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
- package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
- package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
- package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
- package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
- package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
- package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
- package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
- package/docs/archive/planning/chat-ui-vision.md +0 -50
- package/docs/archive/planning/chunk-task-roadmap.md +0 -77
- package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
- package/docs/archive/planning/journal.md +0 -316
- package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
- package/docs/archive/planning/pi-integration-review.md +0 -178
- package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
- package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
- package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
- package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
- package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
- package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
- package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
- package/docs/archive/planning/release-notes-v0.4.0.md +0 -45
- package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
- package/docs/archive/planning/web-ui-pass-plan.md +0 -213
- package/docs/archive/planning/website-readme-pass-plan.md +0 -224
- package/docs/design/batching.md +0 -2054
- package/docs/design/decode-speed-program.md +0 -2404
- package/docs/design/dreaming-nightly-pipeline.md +0 -684
- package/docs/design/generic-model-support.md +0 -821
- package/docs/design/kv-cache.md +0 -993
- package/docs/design/orpo-training.md +0 -680
- package/docs/design/speculative-decoding.md +0 -2129
- package/docs/design/turboquant.md +0 -2225
- package/docs/design/unified-engine-frontier-plan.md +0 -1987
- package/docs/design/web-chat-redesign.md +0 -695
- package/docs/planning/PRODUCT_ROADMAP.md +0 -593
- package/docs/planning/ResearchTopics.md +0 -119
- package/docs/planning/public-readiness-handoff.md +0 -244
- package/docs/planning/public-readiness.md +0 -149
- package/docs/planning/video-series.md +0 -421
- package/docs/reference/benchmarks.md +0 -3587
- package/docs/reference/cli.md +0 -646
- package/docs/reference/distribution.md +0 -380
- package/docs/reference/environment.md +0 -494
- package/docs/reference/glossary.md +0 -39
- package/docs/reference/library-api.md +0 -688
- package/docs/reference/memory.md +0 -260
- package/docs/reference/models.md +0 -346
- package/docs/reference/server-api.md +0 -1945
- package/docs/reference/server-config.md +0 -973
- package/docs/reference/training.md +0 -462
- package/docs/reference/troubleshooting.md +0 -158
- package/src/admission-plan.ts +0 -18
- package/src/audio/audiotoolbox.ts +0 -112
- package/src/audio/conformer.ts +0 -655
- package/src/audio/decode.ts +0 -133
- package/src/audio/features.ts +0 -202
- package/src/audio/mic-capture.ts +0 -98
- package/src/audio/silero-vad.ts +0 -379
- package/src/audio/transcode.ts +0 -67
- package/src/audio/whisper-decode.ts +0 -774
- package/src/audio/whisper-fast.ts +0 -732
- package/src/audio/whisper-format.ts +0 -73
- package/src/audio/whisper-mel.ts +0 -185
- package/src/audio/whisper-timing.ts +0 -274
- package/src/audio/whisper-tokenizer.ts +0 -239
- package/src/audio/whisper-transcribe.ts +0 -410
- package/src/backends/mlx/assistant-target.ts +0 -46
- package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
- package/src/backends/mlx/autoregressive.ts +0 -129
- package/src/backends/mlx/batch-group.ts +0 -1874
- package/src/backends/mlx/cache-attachment.ts +0 -67
- package/src/backends/mlx/cache-layout.ts +0 -31
- package/src/backends/mlx/checkpoint-state.ts +0 -53
- package/src/backends/mlx/continuation-persistence.ts +0 -107
- package/src/backends/mlx/continuation-request.ts +0 -43
- package/src/backends/mlx/continuation.ts +0 -77
- package/src/backends/mlx/diffusion.ts +0 -39
- package/src/backends/mlx/draft-target.ts +0 -32
- package/src/backends/mlx/encoder-cache.ts +0 -25
- package/src/backends/mlx/evaluation.ts +0 -105
- package/src/backends/mlx/fill-append.ts +0 -58
- package/src/backends/mlx/fill-group.ts +0 -497
- package/src/backends/mlx/full-kv-row-append.ts +0 -32
- package/src/backends/mlx/full-kv-row-donor.ts +0 -54
- package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
- package/src/backends/mlx/gateway-binding.ts +0 -174
- package/src/backends/mlx/graph.ts +0 -38
- package/src/backends/mlx/kv-codec.ts +0 -9
- package/src/backends/mlx/kv-maintenance.ts +0 -161
- package/src/backends/mlx/kv-tensor-rows.ts +0 -212
- package/src/backends/mlx/memory-client.ts +0 -189
- package/src/backends/mlx/methods.ts +0 -90
- package/src/backends/mlx/mixed-iteration.ts +0 -62
- package/src/backends/mlx/model-prompt.ts +0 -178
- package/src/backends/mlx/model-serving.ts +0 -80
- package/src/backends/mlx/paged-cache-codec.ts +0 -27
- package/src/backends/mlx/prefill-cohort.ts +0 -100
- package/src/backends/mlx/prefill-policy.ts +0 -26
- package/src/backends/mlx/prefill-rows.ts +0 -244
- package/src/backends/mlx/prefill.ts +0 -33
- package/src/backends/mlx/projected-context-rows.ts +0 -72
- package/src/backends/mlx/prompt-input.ts +0 -29
- package/src/backends/mlx/qwen-prompt-input.ts +0 -40
- package/src/backends/mlx/request-policy.ts +0 -20
- package/src/backends/mlx/request-state-policy.ts +0 -54
- package/src/backends/mlx/rollback.ts +0 -92
- package/src/backends/mlx/row-sampling.ts +0 -49
- package/src/backends/mlx/serial-executor.ts +0 -251
- package/src/backends/mlx/speculative-group.ts +0 -438
- package/src/backends/mlx/speculative-round.ts +0 -161
- package/src/backends/mlx/speculative.ts +0 -131
- package/src/backends/mlx/state-rows.ts +0 -104
- package/src/backends/mlx/state-views.ts +0 -46
- package/src/backends/mlx/target-layout-capability.ts +0 -35
- package/src/backends/mlx/text-engine.ts +0 -73
- package/src/backends/mlx/transitioning-kv-rows.ts +0 -173
- package/src/chat-template.ts +0 -382
- package/src/cli.ts +0 -3490
- package/src/config.ts +0 -399
- package/src/contracts/completion.ts +0 -16
- package/src/contracts/execution.ts +0 -70
- package/src/contracts/generation.ts +0 -103
- package/src/contracts/host.ts +0 -7
- package/src/contracts/object-cache.ts +0 -8
- package/src/contracts/pi-provider.ts +0 -30
- package/src/contracts/pi.ts +0 -261
- package/src/contracts/prefix-cache.ts +0 -33
- package/src/contracts/resources.ts +0 -25
- package/src/contracts/sampling.ts +0 -23
- package/src/contracts/scheduling.ts +0 -54
- package/src/contracts/tsconfig.json +0 -14
- package/src/dataset/generators.ts +0 -1087
- package/src/dataset/index.ts +0 -12
- package/src/dataset/job.ts +0 -81
- package/src/dataset/llm.ts +0 -71
- package/src/dataset/registry.ts +0 -528
- package/src/diffusion/diffusion-generate.ts +0 -507
- package/src/download.ts +0 -505
- package/src/embed.ts +0 -77
- package/src/engine/admission.ts +0 -59
- package/src/engine/cancellation.ts +0 -38
- package/src/engine/engine.ts +0 -56
- package/src/engine/execution-coordinator.ts +0 -70
- package/src/engine/execution-plan.ts +0 -64
- package/src/engine/execution-tasks.ts +0 -44
- package/src/engine/namespaced-cache.ts +0 -13
- package/src/engine/resources.ts +0 -53
- package/src/engine/scheduler.ts +0 -92
- package/src/engine/session.ts +0 -247
- package/src/eval/README.md +0 -130
- package/src/eval/ifeval.ts +0 -81
- package/src/eval/kl-prompts.ts +0 -29
- package/src/eval/kl.ts +0 -590
- package/src/eval/perplexity.ts +0 -164
- package/src/eval/quality-db.ts +0 -92
- package/src/eval/reference-logits.ts +0 -207
- package/src/eval/runner.ts +0 -124
- package/src/eval/score.ts +0 -49
- package/src/eval/tasks/bfcl.ts +0 -535
- package/src/eval/tasks/gsm8k.ts +0 -98
- package/src/eval/tasks/hashhop.ts +0 -139
- package/src/eval/tasks/humaneval.ts +0 -275
- package/src/eval/tasks/ifeval.ts +0 -525
- package/src/eval/tasks/mmlu.ts +0 -157
- package/src/eval/ultrafeedback.ts +0 -60
- package/src/evaldb.ts +0 -199
- package/src/expert-io.ts +0 -393
- package/src/expert-offload-build.ts +0 -77
- package/src/expert-offload.ts +0 -76
- package/src/expert-residency.ts +0 -1134
- package/src/expert-usage.ts +0 -415
- package/src/fill/echo-index.ts +0 -188
- package/src/fill/fill-session.ts +0 -463
- package/src/fill/proposal.ts +0 -68
- package/src/fill/schema-rows.ts +0 -506
- package/src/fill/tool-boundary.ts +0 -103
- package/src/fit.ts +0 -249
- package/src/generate.ts +0 -1352
- package/src/grammar.ts +0 -604
- package/src/harness-pi.ts +0 -184
- package/src/hf-push.ts +0 -628
- package/src/hub-rest.ts +0 -242
- package/src/index.ts +0 -63
- package/src/inference/denoising.ts +0 -17
- package/src/inference/draft-acceptance.ts +0 -41
- package/src/inference/draft-output.ts +0 -49
- package/src/inference/graph.ts +0 -33
- package/src/inference/prefill.ts +0 -45
- package/src/inference/rollback.ts +0 -7
- package/src/jobs/index.ts +0 -31
- package/src/jobs/job-entry.ts +0 -107
- package/src/jobs/task-client.ts +0 -19
- package/src/jobs/types.ts +0 -2
- package/src/kv-scheme.ts +0 -279
- package/src/kv-store.ts +0 -1135
- package/src/lab/README.md +0 -22
- package/src/lab/curve/curve-designer.html +0 -303
- package/src/lab/curve/curve-sampler.ts +0 -122
- package/src/lab/expert-trace/expert-trace.ts +0 -69
- package/src/lab/paged-kv/paged-attention.ts +0 -117
- package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
- package/src/lab/paged-kv/paged-kv.ts +0 -336
- package/src/library.ts +0 -40
- package/src/lora.ts +0 -408
- package/src/md-modules.d.ts +0 -54
- package/src/media-fetch.ts +0 -442
- package/src/memory/article.ts +0 -558
- package/src/memory/chunk-validation.ts +0 -150
- package/src/memory/chunk.ts +0 -318
- package/src/memory/cluster.ts +0 -351
- package/src/memory/coverage.ts +0 -134
- package/src/memory/crosslink.ts +0 -0
- package/src/memory/db.ts +0 -253
- package/src/memory/entity.ts +0 -203
- package/src/memory/gate.ts +0 -187
- package/src/memory/history.ts +0 -152
- package/src/memory/ingest.ts +0 -335
- package/src/memory/model.ts +0 -183
- package/src/memory/normalize.ts +0 -671
- package/src/memory/parse.ts +0 -22
- package/src/memory/pipeline.ts +0 -275
- package/src/memory/prompts.ts +0 -65
- package/src/memory/query.ts +0 -334
- package/src/memory/reconcile.ts +0 -734
- package/src/memory/redirect.ts +0 -108
- package/src/memory/reindex.ts +0 -325
- package/src/memory/resolve.ts +0 -307
- package/src/memory/rest.ts +0 -245
- package/src/memory/route.ts +0 -272
- package/src/memory/schedule.ts +0 -165
- package/src/memory/stages.ts +0 -777
- package/src/memory/synthesize.ts +0 -1638
- package/src/memory/tools.ts +0 -749
- package/src/memory/vault.ts +0 -1194
- package/src/memory/wikify.ts +0 -1064
- package/src/mlx/array.ts +0 -425
- package/src/mlx/autograd.ts +0 -304
- package/src/mlx/checkpoint.ts +0 -149
- package/src/mlx/compile.ts +0 -168
- package/src/mlx/custom-vjp.ts +0 -188
- package/src/mlx/ffi.ts +0 -531
- package/src/mlx/materialize.ts +0 -23
- package/src/mlx/metal-kernel.ts +0 -159
- package/src/mlx/normalized-argmax.ts +0 -116
- package/src/mlx/ops.ts +0 -1108
- package/src/mlx/quantized-rows.ts +0 -36
- package/src/mlx/token-bitmask.ts +0 -52
- package/src/mlx/turboquant-kv-decode.ts +0 -82
- package/src/mlx/turboquant-kv-inverse.ts +0 -122
- package/src/mlx/turboquant-ops.ts +0 -861
- package/src/mlx/turboquant-tables.ts +0 -237
- package/src/mmap.ts +0 -90
- package/src/model/artifact-identity.ts +0 -73
- package/src/model/batched-kv.ts +0 -235
- package/src/model/batched-mask.ts +0 -279
- package/src/model/batched-quant.ts +0 -212
- package/src/model/batched-quantized-kv.ts +0 -144
- package/src/model/batched-rotating-quant.ts +0 -353
- package/src/model/batched-rotating-state.ts +0 -149
- package/src/model/batched-rotating.ts +0 -338
- package/src/model/batched-row-storage.ts +0 -179
- package/src/model/batched-ssm.ts +0 -52
- package/src/model/batched-turboquant-kv.ts +0 -94
- package/src/model/compiled-decode.ts +0 -712
- package/src/model/decoded-kv-donor.ts +0 -12
- package/src/model/delayed-quantized-kv.ts +0 -72
- package/src/model/delayed-rotating-quantized-kv.ts +0 -93
- package/src/model/delayed-turboquant-kv.ts +0 -57
- package/src/model/diffusion-gemma.ts +0 -1026
- package/src/model/factory.ts +0 -215
- package/src/model/fingerprint.ts +0 -45
- package/src/model/flash-attention.ts +0 -694
- package/src/model/full-prefill-padding.ts +0 -56
- package/src/model/full-prefill-row.ts +0 -105
- package/src/model/gemma4-base.ts +0 -2370
- package/src/model/gemma4.ts +0 -1395
- package/src/model/generated/gemma4-12b.ts +0 -429
- package/src/model/generated/gemma4-26b.ts +0 -448
- package/src/model/generated/gemma4-e4b.ts +0 -717
- package/src/model/generated/index.ts +0 -18
- package/src/model/glm52-atlas.ts +0 -511
- package/src/model/glm52-cache.ts +0 -792
- package/src/model/glm52-config.ts +0 -262
- package/src/model/glm52-container.ts +0 -305
- package/src/model/glm52-coupling.ts +0 -388
- package/src/model/glm52-dsa.ts +0 -606
- package/src/model/glm52-expert-layout.ts +0 -253
- package/src/model/glm52-layout.ts +0 -152
- package/src/model/glm52-memory.ts +0 -500
- package/src/model/glm52-mla.ts +0 -792
- package/src/model/glm52-moe.ts +0 -223
- package/src/model/glm52-pilot.ts +0 -537
- package/src/model/glm52-reference.ts +0 -445
- package/src/model/glm52-residency.ts +0 -557
- package/src/model/glm52-resident-weights.ts +0 -135
- package/src/model/glm52-streamed-experts.ts +0 -453
- package/src/model/glm52-streamed-metal.ts +0 -610
- package/src/model/glm52-weights.ts +0 -503
- package/src/model/glm52.ts +0 -1132
- package/src/model/implementation.ts +0 -69
- package/src/model/kv-attention-view.ts +0 -70
- package/src/model/minicpm5.ts +0 -376
- package/src/model/profile.ts +0 -468
- package/src/model/quantized-append-attention.ts +0 -31
- package/src/model/qwen-append.ts +0 -12
- package/src/model/qwen-conv.ts +0 -52
- package/src/model/qwen3-delta-state.ts +0 -74
- package/src/model/qwen3-delta.ts +0 -451
- package/src/model/qwen3-moe.ts +0 -404
- package/src/model/qwen3-mrope.ts +0 -250
- package/src/model/qwen3.ts +0 -277
- package/src/model/qwen3_5-checkpoint.ts +0 -164
- package/src/model/qwen3_5.ts +0 -881
- package/src/model/rotating-kv-donor.ts +0 -35
- package/src/model/rotating-kv-layout.ts +0 -262
- package/src/model/rotating-row-transaction.ts +0 -35
- package/src/model/speculative-rotating-kv.ts +0 -101
- package/src/model/ssm-prefill-padding.ts +0 -39
- package/src/model/support.ts +0 -110
- package/src/model/token-groups.ts +0 -66
- package/src/model/trellis-balanced-scatter.ts +0 -51
- package/src/model/trellis-linear.ts +0 -672
- package/src/model/trellis-shared-m.ts +0 -151
- package/src/model/trellis-shared-scatter.ts +0 -144
- package/src/model/trellis-splitk-prefill.ts +0 -158
- package/src/model/trellis-tiled-prefill.ts +0 -136
- package/src/model/trellis-vector-expand.ts +0 -62
- package/src/model/trellis-wide-prefill.ts +0 -94
- package/src/model/turboquant-codec.ts +0 -89
- package/src/model/universal/archs.ts +0 -332
- package/src/model/universal/dense.ts +0 -612
- package/src/model/universal/modules.ts +0 -170
- package/src/model/universal/rope.ts +0 -381
- package/src/model/whisper.ts +0 -435
- package/src/native/expert_io.c +0 -523
- package/src/native/frame_extract.swift +0 -140
- package/src/native/mic_capture.swift +0 -92
- package/src/native-pack.ts +0 -163
- package/src/pi-provider.ts +0 -53
- package/src/pi-session.ts +0 -81
- package/src/pi-terminal.ts +0 -274
- package/src/pi-web.ts +0 -1940
- package/src/preflight.ts +0 -158
- package/src/prompt-cache.ts +0 -682
- package/src/quantize/allocator.ts +0 -627
- package/src/quantize/atomic-output.ts +0 -38
- package/src/quantize/calibration.ts +0 -181
- package/src/quantize/config-writer.ts +0 -145
- package/src/quantize/index.ts +0 -84
- package/src/quantize/job.ts +0 -162
- package/src/quantize/quantizer.ts +0 -666
- package/src/quantize/rotate.ts +0 -603
- package/src/quantize/safetensors-writer.ts +0 -249
- package/src/quantize/sensitivity.ts +0 -216
- package/src/quantize/trellis.ts +0 -586
- package/src/quantize/weight-transform.ts +0 -292
- package/src/registry.ts +0 -602
- package/src/runtime-config.ts +0 -77
- package/src/safetensors.ts +0 -165
- package/src/sampler.ts +0 -1012
- package/src/serve/admin-routes.ts +0 -184
- package/src/serve/assets/curve-terrain.html +0 -105
- package/src/serve/assets/training-inference-map.html +0 -575
- package/src/serve/audio-routes.ts +0 -323
- package/src/serve/aux-routes.ts +0 -132
- package/src/serve/batch-scheduler.ts +0 -8
- package/src/serve/checkpoint-identity.ts +0 -64
- package/src/serve/generation-gateway.ts +0 -537
- package/src/serve/isolate.ts +0 -609
- package/src/serve/kv-budget.ts +0 -14
- package/src/serve/lab-routes.ts +0 -341
- package/src/serve/lane-registry.ts +0 -45
- package/src/serve/model-admin-routes.ts +0 -155
- package/src/serve/model-binding.ts +0 -49
- package/src/serve/model-host.ts +0 -511
- package/src/serve/parent-application.ts +0 -56
- package/src/serve/prompt-response-trace.ts +0 -161
- package/src/serve/response-lease.ts +0 -24
- package/src/serve/session-search.ts +0 -326
- package/src/serve/static-routes.ts +0 -101
- package/src/serve/transcription-server.ts +0 -64
- package/src/serve/transcription-service.ts +0 -502
- package/src/server.ts +0 -1282
- package/src/spec/assistant-rows.ts +0 -93
- package/src/spec/assistant-source.ts +0 -126
- package/src/spec/cache-identity.ts +0 -22
- package/src/spec/deepspec-rows.ts +0 -29
- package/src/spec/deepspec-source.ts +0 -145
- package/src/spec/dflash-source.ts +0 -149
- package/src/spec/drafter.ts +0 -304
- package/src/spec/dspark/ab-stats.ts +0 -136
- package/src/spec/dspark/calibration.ts +0 -112
- package/src/spec/dspark/data-dflash.ts +0 -156
- package/src/spec/dspark/data.ts +0 -201
- package/src/spec/dspark/deepspec-module.ts +0 -776
- package/src/spec/dspark/generate-dflash.ts +0 -245
- package/src/spec/dspark/generate.ts +0 -290
- package/src/spec/dspark/loader.ts +0 -23
- package/src/spec/dspark/loss.ts +0 -213
- package/src/spec/dspark/module-dflash.ts +0 -560
- package/src/spec/dspark/module.ts +0 -540
- package/src/spec/dspark/quantize-drafter.ts +0 -91
- package/src/spec/dspark/sample.ts +0 -112
- package/src/spec/generate.ts +0 -276
- package/src/spec/glm52-mtp-graph.ts +0 -29
- package/src/spec/glm52-mtp-rows.ts +0 -132
- package/src/spec/glm52-mtp-source.ts +0 -318
- package/src/spec/glm52-mtp-state.ts +0 -33
- package/src/spec/ngram-source.ts +0 -226
- package/src/spec/projected-draft-rows.ts +0 -73
- package/src/spec/qwen-mtp-module.ts +0 -171
- package/src/spec/qwen-mtp-rows.ts +0 -230
- package/src/spec/qwen-mtp-source.ts +0 -386
- package/src/spec/qwen-mtp-state.ts +0 -30
- package/src/spec/serve-loop.ts +0 -587
- package/src/spec/source.ts +0 -228
- package/src/spec/two-model-rows.ts +0 -62
- package/src/spec/two-model.ts +0 -113
- package/src/ssd-cache.ts +0 -431
- package/src/ssd-durability.ts +0 -209
- package/src/storage/host-buffer.ts +0 -24
- package/src/storage/kv-writer.ts +0 -83
- package/src/storage/kv-writer.worker.js +0 -264
- package/src/storage/retention-policy.ts +0 -37
- package/src/tiered-prompt-cache.ts +0 -45
- package/src/tokenizer.ts +0 -335
- package/src/tool-approvals.ts +0 -131
- package/src/tool-call.ts +0 -695
- package/src/train/dataset.ts +0 -484
- package/src/train/diffusion-lora.ts +0 -216
- package/src/train/export.ts +0 -32
- package/src/train/flash-cce.ts +0 -1234
- package/src/train/forward.ts +0 -266
- package/src/train/fuse.ts +0 -243
- package/src/train/index.ts +0 -46
- package/src/train/job.ts +0 -205
- package/src/train/lora-params.ts +0 -254
- package/src/train/loss.ts +0 -1591
- package/src/train/merge.ts +0 -195
- package/src/train/optimizer.ts +0 -183
- package/src/train/prefix-shared.ts +0 -490
- package/src/train/rank.ts +0 -137
- package/src/train/segmented.ts +0 -1828
- package/src/train/steel-qmm-header.ts +0 -1461
- package/src/train/trainer.ts +0 -1221
- package/src/train/watch.ts +0 -542
- package/src/vision/diffusion-vision.ts +0 -620
- package/src/vision/embedder.ts +0 -176
- package/src/vision/preprocess.ts +0 -247
- package/src/vision/prompt.ts +0 -409
- package/src/vision/qwen3vl-preprocess.ts +0 -409
- package/src/vision/qwen3vl-prompt.ts +0 -233
- package/src/vision/qwen3vl-tower.ts +0 -566
- package/src/vision/siglip.ts +0 -607
- package/src/vision/video-frames.ts +0 -148
- package/src/web/app.html +0 -2155
- package/src/web/app.js +0 -5863
- package/src/web/skills/memory/SKILL.md +0 -120
- package/src/web/skills/web-research/SKILL.md +0 -46
- package/src/web/skills.ts +0 -97
- package/src/web/src/adapters-panel.ts +0 -288
- package/src/web/src/assistant.ts +0 -451
- package/src/web/src/chat.ts +0 -1060
- package/src/web/src/composer.ts +0 -962
- package/src/web/src/dataset.ts +0 -132
- package/src/web/src/finetune.ts +0 -267
- package/src/web/src/hub.ts +0 -428
- package/src/web/src/main.ts +0 -98
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +0 -572
- package/src/web/src/model-picker.ts +0 -159
- package/src/web/src/palette.ts +0 -346
- package/src/web/src/protocol.ts +0 -26
- package/src/web/src/quantize.ts +0 -167
- package/src/web/src/rag.ts +0 -274
- package/src/web/src/sessions.ts +0 -469
- package/src/web/src/shell.ts +0 -804
- package/src/web/src/ui-catalog.ts +0 -78
- package/src/web/src/voice.ts +0 -141
- package/src/web/vendor/README.md +0 -61
- package/src/web-assets.ts +0 -47
- package/src/web-tools.ts +0 -478
- package/src/weights.ts +0 -255
- /package/src/{serve → server}/completion-sink.ts +0 -0
- /package/src/{serve → server}/generated-token-history.ts +0 -0
- /package/src/web/{icon.svg → public/icon.svg} +0 -0
- /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
- /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
// Batched sliding-window (rotating) KV cache for `--batch N` serving — the
|
|
2
|
-
// hard half of dynamic-B that BatchedDecodeMaskCache (full-attention) doesn't
|
|
3
|
-
// cover. Faithful port of mlx-lm's BatchRotatingKVCache (models/cache.py):
|
|
4
|
-
// a shared ring buffer whose rotation state (_idx / _offset / rotated) is
|
|
5
|
-
// SCALAR across the batch (all rows advance one token per step, so the write
|
|
6
|
-
// column is the same for every row), with PER-ROW `offset` (absolute position,
|
|
7
|
-
// drives RoPE) and `leftPad` (padding columns in the buffer, masked out).
|
|
8
|
-
//
|
|
9
|
-
// Includes merge, one-token writes, block prefill, padding finalization, masks
|
|
10
|
-
// and row extraction. Prefill preparation is a storage capability; the serving
|
|
11
|
-
// scheduler's use of whole prompt cohorts is a separate concern.
|
|
12
|
-
// Positions (offset/leftPad/_idx/_offset/
|
|
13
|
-
// rotated) are tracked on the HOST (small deterministic ints) so make_mask is
|
|
14
|
-
// built in JS like buildBatchedDecodeMask; only K/V live on device.
|
|
15
|
-
//
|
|
16
|
-
// The genuinely tricky bit is make_mask once the ring wraps: the buffer is no
|
|
17
|
-
// longer in temporal order, so the causal+window+padding mask is built in
|
|
18
|
-
// temporal coordinates then ROLLED to the ring's physical layout — see
|
|
19
|
-
// buildBatchedRotatingMask (a column-by-column port of mlx-lm make_mask,
|
|
20
|
-
// including the `roll(shift=idx+1)`). Gated model-free against mlx-lm
|
|
21
|
-
// (tests/unit/batched-rotating.test.ts) + end-to-end vs a long-context Gemma oracle.
|
|
22
|
-
|
|
23
|
-
import { MlxArray } from "../mlx/array";
|
|
24
|
-
import * as ops from "../mlx/ops";
|
|
25
|
-
import { RotatingKVCache, type Cache, type Mask, type PaddedPrefillCache, type PrefillPadding } from "./gemma4-base";
|
|
26
|
-
import { BatchedRotatingState, type RotatingPositionSnapshot } from "./batched-rotating-state";
|
|
27
|
-
import {
|
|
28
|
-
appendRotatingStorage,
|
|
29
|
-
mergeStorageRows,
|
|
30
|
-
plainRowStorage,
|
|
31
|
-
temporalStorageView,
|
|
32
|
-
rowRollIndices,
|
|
33
|
-
} from "./batched-row-storage";
|
|
34
|
-
|
|
35
|
-
const STEP = 256;
|
|
36
|
-
|
|
37
|
-
/** Port of BatchRotatingKVCache.make_mask for the DECODE case. Returns a
|
|
38
|
-
* [B,1,N,S] bool mask (S == min(maxSize-1, offsetScalar) + N) for the step
|
|
39
|
-
* ABOUT to be written: causal AND sliding-window AND per-row left-padding,
|
|
40
|
-
* rolled to the ring's physical layout once wrapped.
|
|
41
|
-
*
|
|
42
|
-
* Inputs are the PRE-write scalar ring state (`idx`=_idx, `offsetScalar`=_offset,
|
|
43
|
-
* `rotated`) and per-row `leftPad`. The leftPad adjustments here are LOCAL to
|
|
44
|
-
* the mask (mlx-lm decrements left_padding both in make_mask AND in update; the
|
|
45
|
-
* update's decrement is the persistent one, applied separately by the cache). */
|
|
46
|
-
export function buildBatchedRotatingMask(
|
|
47
|
-
B: number, N: number, leftPad: number[],
|
|
48
|
-
maxSize: number, window: number, idx: number, offsetScalar: number, rotated: boolean, block = N > 1,
|
|
49
|
-
): MlxArray {
|
|
50
|
-
const off = Math.min(maxSize - 1, offsetScalar);
|
|
51
|
-
const S = off + N;
|
|
52
|
-
|
|
53
|
-
// Local (non-persisted) leftPad for the mask: trim + rotation shrink it.
|
|
54
|
-
const trimSize = idx - maxSize + (block ? 1 : 0);
|
|
55
|
-
const isRot = !block && (rotated || idx >= maxSize);
|
|
56
|
-
const lp = leftPad.map((x) => x - (trimSize > 0 ? trimSize : 0) - (isRot ? 1 : 0));
|
|
57
|
-
|
|
58
|
-
// roll(shift): physical column = (temporal column + shift) mod S.
|
|
59
|
-
const shift = isRot ? (idx >= maxSize ? 0 : idx) + 1 : 0;
|
|
60
|
-
|
|
61
|
-
const data = new Int32Array(B * N * S);
|
|
62
|
-
for (let b = 0; b < B; b++) {
|
|
63
|
-
const pad = lp[b]!;
|
|
64
|
-
for (let i = 0; i < N; i++) {
|
|
65
|
-
const lind = off + i; // query temporal position
|
|
66
|
-
for (let j = 0; j < S; j++) {
|
|
67
|
-
// temporal key position j: causal, within window, past this row's pad.
|
|
68
|
-
const allow = lind >= j && lind < j + window && j >= pad;
|
|
69
|
-
if (!allow) continue;
|
|
70
|
-
const col = ((j + shift) % S + S) % S;
|
|
71
|
-
data[(b * N + i) * S + col] = 1;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const intArr = MlxArray.fromInt32(data, [B, 1, N, S]);
|
|
76
|
-
const zero = MlxArray.fromInt32(new Int32Array([0]), []);
|
|
77
|
-
const mask = ops.less(zero, intArr); // 0 < x → bool
|
|
78
|
-
zero.dispose();
|
|
79
|
-
intArr.dispose();
|
|
80
|
-
return mask;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** Port of mlx-lm BatchRotatingKVCache; padded singleton chunks use its
|
|
84
|
-
* concat operation with the matching block mask until finalization. */
|
|
85
|
-
export class BatchedRotatingCache implements Cache, PaddedPrefillCache {
|
|
86
|
-
keys: MlxArray | null = null;
|
|
87
|
-
values: MlxArray | null = null;
|
|
88
|
-
readonly #rows: BatchedRotatingState;
|
|
89
|
-
#ropeArr: MlxArray | null = null;
|
|
90
|
-
#ropeForOffset = -1;
|
|
91
|
-
readonly maxSize: number;
|
|
92
|
-
|
|
93
|
-
constructor(maxSize: number, leftPad: number[]) {
|
|
94
|
-
this.maxSize = maxSize;
|
|
95
|
-
this.#rows = new BatchedRotatingState(maxSize, leftPad);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** Same signature as the serial RotatingKVCache — the scheduler's merge
|
|
99
|
-
* guards recognize a batched ring as "rotating-plain + RowBatchCache"
|
|
100
|
-
* (batch-scheduler #mergeJoiner prevRot branch); without this the next
|
|
101
|
-
* join sees "unknown", skips the prevRot rows, and replaces the batch's
|
|
102
|
-
* sliding-layer KV with a one-row cache (B≥3 collapse). Guard order
|
|
103
|
-
* everywhere is isRowBatchCache FIRST, so the shared string never
|
|
104
|
-
* misroutes a batched cache into a serial-only path. */
|
|
105
|
-
signature(): string { return "kv:rotating-plain"; }
|
|
106
|
-
|
|
107
|
-
get positionSnapshot(): RotatingPositionSnapshot { return this.#rows.snapshot(); }
|
|
108
|
-
validOffset(row: number): number { return this.#rows.validOffset(row); }
|
|
109
|
-
preparePrefill(padding: PrefillPadding, rightPaddedBatch?: boolean): void { this.#rows.preparePrefill(padding, rightPaddedBatch); this.releaseRopeArr(); }
|
|
110
|
-
finalizePrefill(): void {
|
|
111
|
-
const shifts = this.#rows.prefillRoll();
|
|
112
|
-
if (shifts?.some(shift => shift !== 0) && this.keys && this.values) {
|
|
113
|
-
using indices = rowRollIndices(this.keys.shape[2]!, shifts);
|
|
114
|
-
const keys = plainRowStorage.rollRows(this.keys, indices);
|
|
115
|
-
let values: MlxArray;
|
|
116
|
-
try { values = plainRowStorage.rollRows(this.values, indices); }
|
|
117
|
-
catch (error) { keys.dispose(); throw error; }
|
|
118
|
-
this.keys.dispose(); this.values.dispose(); this.keys = keys; this.values = values;
|
|
119
|
-
}
|
|
120
|
-
this.#rows.finalizePrefill(); this.releaseRopeArr();
|
|
121
|
-
}
|
|
122
|
-
/** Adopt owned tensors without changing their physical ring columns. */
|
|
123
|
-
static adoptPhysical(keys: MlxArray | null, values: MlxArray | null, position: RotatingPositionSnapshot): BatchedRotatingCache {
|
|
124
|
-
const cache = new BatchedRotatingCache(position.maxSize, [...position.leftPad]);
|
|
125
|
-
cache.#rows.restore(position); cache.keys = keys; cache.values = values;
|
|
126
|
-
|
|
127
|
-
return cache;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
get offsetArr(): number[] { return this.#rows.offsets; }
|
|
131
|
-
get leftPad(): number[] { return this.#rows.leftPad; }
|
|
132
|
-
get batchSize(): number { return this.#rows.batchSize; }
|
|
133
|
-
|
|
134
|
-
/** Current batch size — tracks filter() (which shrinks the per-row arrays). */
|
|
135
|
-
get #B(): number {
|
|
136
|
-
return this.#rows.batchSize;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/** mlx-lm uses `cache.offset` (the per-row array) for the scalar interface
|
|
140
|
-
* too; we expose the scalar total as `offset` and the per-row positions via
|
|
141
|
-
* `ropeOffsetArr` (the model's per-row RoPE path). */
|
|
142
|
-
get offset(): number {
|
|
143
|
-
return this.#rows.totalOffset;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
get ropeOffsetArr(): MlxArray {
|
|
147
|
-
if (this.#ropeArr && this.#ropeForOffset === this.offset) return this.#ropeArr;
|
|
148
|
-
this.#ropeArr?.dispose();
|
|
149
|
-
this.#ropeArr = MlxArray.fromInt32(Int32Array.from(this.offsetArr), [this.#B]);
|
|
150
|
-
this.#ropeForOffset = this.offset;
|
|
151
|
-
return this.#ropeArr;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
makeMask(N: number, windowSize: number | null): Mask {
|
|
155
|
-
const window = windowSize ?? this.maxSize;
|
|
156
|
-
return {
|
|
157
|
-
mode: "array",
|
|
158
|
-
arr: buildBatchedRotatingMask(
|
|
159
|
-
this.#B, N, this.leftPad, this.maxSize, window,
|
|
160
|
-
this.#rows.ringIndex, this.offset, this.#rows.rotated, N > 1 || this.#rows.hasPendingPadding,
|
|
161
|
-
),
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/** N=1 decode update — port of _update_in_place. */
|
|
166
|
-
updateAndFetch(k: MlxArray, v: MlxArray): [MlxArray, MlxArray] {
|
|
167
|
-
const [B, H, S, D] = k.shape as [number, number, number, number];
|
|
168
|
-
const vD = v.shape[3]!;
|
|
169
|
-
if (S !== 1 || this.#rows.hasPendingPadding) return this.#updateConcat(k, v);
|
|
170
|
-
const prev = this.offset;
|
|
171
|
-
|
|
172
|
-
// Grow the buffer (in STEP chunks) until it reaches maxSize.
|
|
173
|
-
if (!this.keys || (prev >= this.keys.shape[2]! && this.keys.shape[2]! < this.maxSize)) {
|
|
174
|
-
const newSize = Math.min(STEP, this.maxSize - prev);
|
|
175
|
-
const newK = ops.zeros([B, H, newSize, D], k.dtype);
|
|
176
|
-
const newV = ops.zeros([B, H, newSize, vD], v.dtype);
|
|
177
|
-
if (this.keys && this.values) {
|
|
178
|
-
const ck = ops.concatAxis([this.keys, newK], 2);
|
|
179
|
-
const cv = ops.concatAxis([this.values, newV], 2);
|
|
180
|
-
for (const a of [this.keys, this.values, newK, newV]) a.dispose();
|
|
181
|
-
this.keys = ck;
|
|
182
|
-
this.values = cv;
|
|
183
|
-
} else {
|
|
184
|
-
this.keys = newK;
|
|
185
|
-
this.values = newV;
|
|
186
|
-
}
|
|
187
|
-
this.#rows.markGrown(prev);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Trim any overshoot past maxSize (decrements left padding persistently).
|
|
191
|
-
const trimSize = this.keys!.shape[2]! - this.maxSize;
|
|
192
|
-
if (trimSize > 0) {
|
|
193
|
-
const tk = this.keys!.slice([0, 0, trimSize, 0], this.keys!.shape as number[]);
|
|
194
|
-
const tv = this.values!.slice([0, 0, trimSize, 0], this.values!.shape as number[]);
|
|
195
|
-
this.keys!.dispose();
|
|
196
|
-
this.values!.dispose();
|
|
197
|
-
this.keys = tk;
|
|
198
|
-
this.values = tv;
|
|
199
|
-
this.#rows.trimOvershoot(trimSize);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Rotate when the write head reaches the end of the ring.
|
|
203
|
-
const writeIndex = this.#rows.beginWrite(S);
|
|
204
|
-
|
|
205
|
-
// Write the new K/V at the ring head.
|
|
206
|
-
const [, , SK, DK] = this.keys!.shape as [number, number, number, number];
|
|
207
|
-
const k2 = ops.sliceUpdate(this.keys!, k, [0, 0, writeIndex, 0], [B, H, writeIndex + S, DK]);
|
|
208
|
-
const v2 = ops.sliceUpdate(this.values!, v, [0, 0, writeIndex, 0], [B, H, writeIndex + S, vD]);
|
|
209
|
-
this.keys!.dispose();
|
|
210
|
-
this.values!.dispose();
|
|
211
|
-
this.keys = k2;
|
|
212
|
-
this.values = v2;
|
|
213
|
-
this.#rows.commitWrite(S);
|
|
214
|
-
|
|
215
|
-
// Return the populated prefix (ring not yet full) or the whole buffer.
|
|
216
|
-
if (this.offset < this.maxSize) {
|
|
217
|
-
return [
|
|
218
|
-
this.keys.slice([0, 0, 0, 0], [B, H, this.offset, DK]),
|
|
219
|
-
this.values.slice([0, 0, 0, 0], [B, H, this.offset, vD]),
|
|
220
|
-
];
|
|
221
|
-
}
|
|
222
|
-
return [
|
|
223
|
-
this.keys.slice([0, 0, 0, 0], [B, H, SK, DK]),
|
|
224
|
-
this.values.slice([0, 0, 0, 0], [B, H, SK, vD]),
|
|
225
|
-
];
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
#updateConcat(k: MlxArray, v: MlxArray): [MlxArray, MlxArray] {
|
|
229
|
-
const keys = appendRotatingStorage(plainRowStorage, this.keys, k, this.#rows);
|
|
230
|
-
let values: MlxArray;
|
|
231
|
-
try { values = appendRotatingStorage(plainRowStorage, this.values, v, this.#rows); }
|
|
232
|
-
catch (error) { keys.dispose(); throw error; }
|
|
233
|
-
const history = this.keys ? this.#rows.activeLength : 0;
|
|
234
|
-
this.keys?.dispose(); this.values?.dispose();
|
|
235
|
-
this.keys = keys; this.values = values;
|
|
236
|
-
this.#rows.commitConcat(k.shape[2]!, history);
|
|
237
|
-
return [
|
|
238
|
-
plainRowStorage.slice(keys, 0, this.#B, 0, this.#rows.ringIndex),
|
|
239
|
-
plainRowStorage.slice(values, 0, this.#B, 0, this.#rows.ringIndex),
|
|
240
|
-
];
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/** Free the per-step RoPE array without disposing KV (wrapper-rebuild path). */
|
|
244
|
-
releaseRopeArr(): void {
|
|
245
|
-
this.#ropeArr?.dispose();
|
|
246
|
-
this.#ropeArr = null;
|
|
247
|
-
this.#ropeForOffset = -1;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/** Ring contents in temporal order, cut to the valid length (extract). */
|
|
251
|
-
temporalView(): [MlxArray, MlxArray] {
|
|
252
|
-
if (!this.keys || !this.values) throw new Error("cache is empty");
|
|
253
|
-
return [
|
|
254
|
-
temporalStorageView(plainRowStorage, this.keys, this.#rows, {
|
|
255
|
-
from: Math.max(0, this.#rows.activeLength - this.maxSize), to: this.#rows.activeLength,
|
|
256
|
-
}),
|
|
257
|
-
temporalStorageView(plainRowStorage, this.values, this.#rows, {
|
|
258
|
-
from: Math.max(0, this.#rows.activeLength - this.maxSize), to: this.#rows.activeLength,
|
|
259
|
-
}),
|
|
260
|
-
];
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/** mlx-lm `BatchRotatingKVCache.extract` (models/cache.py:1417): row `i`
|
|
264
|
-
* as a fresh SERIAL RotatingKVCache — de-rolled to temporal order (the
|
|
265
|
-
* oracle's roll(-_idx) when rotated), left padding stripped
|
|
266
|
-
* (`max(0, left_padding[idx])` — post-wrap pads go negative), OWNED
|
|
267
|
-
* contiguous copies. `offset` = the row's absolute position (may exceed
|
|
268
|
-
* the buffer: wrapped rings have evicted tokens); ring idx = the new
|
|
269
|
-
* buffer length — temporal order ⇔ write head at the end, exactly the
|
|
270
|
-
* oracle's `cache._idx = cache.keys.shape[2]`. Bit-exact vs a solo run:
|
|
271
|
-
* merge/decode/filter keep each row's ring bytes identical to the serial
|
|
272
|
-
* cache's (tests/batched-rotating) and this is a pure slice+copy. */
|
|
273
|
-
extractRow(i: number, limit?: number): RotatingKVCache | null {
|
|
274
|
-
if (!this.keys || !this.values) return null;
|
|
275
|
-
const pad = Math.max(0, this.leftPad[i]!, limit === undefined ? 0 : this.#rows.activeLength - limit);
|
|
276
|
-
const c = new RotatingKVCache(this.maxSize);
|
|
277
|
-
const k = temporalStorageView(plainRowStorage, this.keys, this.#rows, {
|
|
278
|
-
row: i, from: pad, to: this.#rows.activeLength, copy: true,
|
|
279
|
-
});
|
|
280
|
-
const v = temporalStorageView(plainRowStorage, this.values, this.#rows, {
|
|
281
|
-
row: i, from: pad, to: this.#rows.activeLength, copy: true,
|
|
282
|
-
});
|
|
283
|
-
c.restoreState(k, v, this.offsetArr[i]!, k.shape[2]!);
|
|
284
|
-
return c;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/** Keep only `keep` rows along the batch axis (eviction). */
|
|
288
|
-
filter(keep: number[]): void {
|
|
289
|
-
if (this.keys && this.values) {
|
|
290
|
-
const k = plainRowStorage.takeRows(this.keys, keep);
|
|
291
|
-
const v = plainRowStorage.takeRows(this.values, keep);
|
|
292
|
-
this.keys.dispose();
|
|
293
|
-
this.values.dispose();
|
|
294
|
-
this.keys = k;
|
|
295
|
-
this.values = v;
|
|
296
|
-
}
|
|
297
|
-
this.#rows.filter(keep);
|
|
298
|
-
this.releaseRopeArr();
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
filterRows(keep: readonly number[]): void { this.filter([...keep]); }
|
|
302
|
-
|
|
303
|
-
state(): MlxArray[] {
|
|
304
|
-
return this.keys && this.values ? [this.keys, this.values] : [];
|
|
305
|
-
}
|
|
306
|
-
isTrimmable(): boolean {
|
|
307
|
-
return this.#rows.trimmable;
|
|
308
|
-
}
|
|
309
|
-
trim(n: number): void {
|
|
310
|
-
this.#rows.trim(n);
|
|
311
|
-
}
|
|
312
|
-
dispose(): void {
|
|
313
|
-
this.keys?.dispose();
|
|
314
|
-
this.values?.dispose();
|
|
315
|
-
this.keys = this.values = null;
|
|
316
|
-
this.#ropeArr?.dispose();
|
|
317
|
-
this.#ropeArr = null;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/** Assemble a batch from per-row temporal KV slices (port of merge). Each row
|
|
321
|
-
* is its solo cache's temporalView ([1,H,Li,D], Li ≤ maxSize, temporal
|
|
322
|
-
* order) and `offsets[i]` its absolute position. Left-pads to the longest
|
|
323
|
-
* row; the result is in temporal order (rotated=false, idx=offset=width). */
|
|
324
|
-
static merge(
|
|
325
|
-
rows: { keys: MlxArray; values: MlxArray }[], offsets: number[], maxSize: number,
|
|
326
|
-
): BatchedRotatingCache {
|
|
327
|
-
const lens = rows.map((r) => r.keys.shape[2]!);
|
|
328
|
-
const width = Math.max(...lens, 0);
|
|
329
|
-
const leftPad = lens.map((l) => width - l);
|
|
330
|
-
const cache = new BatchedRotatingCache(maxSize, leftPad);
|
|
331
|
-
cache.#rows.restoreMerged(width, offsets);
|
|
332
|
-
if (width === 0) return cache;
|
|
333
|
-
|
|
334
|
-
cache.keys = mergeStorageRows(plainRowStorage, rows.map((row) => row.keys), leftPad);
|
|
335
|
-
cache.values = mergeStorageRows(plainRowStorage, rows.map((row) => row.values), leftPad);
|
|
336
|
-
return cache;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
import { MlxArray } from "../mlx/array";
|
|
2
|
-
import * as ops from "../mlx/ops";
|
|
3
|
-
import { BatchedRotatingState } from "./batched-rotating-state";
|
|
4
|
-
import { Dtype } from "../mlx/ffi";
|
|
5
|
-
|
|
6
|
-
export interface RowStorage<T> {
|
|
7
|
-
shape(value: T): readonly [number, number, number, number];
|
|
8
|
-
slice(value: T, batchFrom: number, batchTo: number, tokenFrom: number, tokenTo: number): T;
|
|
9
|
-
concatTokens(values: readonly T[]): T;
|
|
10
|
-
concatRows(values: readonly T[]): T;
|
|
11
|
-
padLeft(value: T, tokens: number): T;
|
|
12
|
-
takeRows(value: T, keep: readonly number[]): T;
|
|
13
|
-
copy(value: T): T;
|
|
14
|
-
rollRows(value: T, indices: MlxArray): T;
|
|
15
|
-
dispose(value: T): void;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const plainRowStorage: RowStorage<MlxArray> = {
|
|
19
|
-
shape: (value) => value.shape as [number, number, number, number],
|
|
20
|
-
slice(value, batchFrom, batchTo, tokenFrom, tokenTo) {
|
|
21
|
-
const [, H, , D] = value.shape as [number, number, number, number];
|
|
22
|
-
return value.slice([batchFrom, 0, tokenFrom, 0], [batchTo, H, tokenTo, D]);
|
|
23
|
-
},
|
|
24
|
-
concatTokens: (values) => ops.concatAxis([...values], 2),
|
|
25
|
-
concatRows: (values) => ops.concatAxis([...values], 0),
|
|
26
|
-
padLeft(value, tokens) {
|
|
27
|
-
if (tokens === 0) return value.slice([0, 0, 0, 0], value.shape as number[]);
|
|
28
|
-
const [B, H, , D] = value.shape as [number, number, number, number];
|
|
29
|
-
const zeros = ops.zeros([B, H, tokens, D], value.dtype);
|
|
30
|
-
const out = ops.concatAxis([zeros, value], 2);
|
|
31
|
-
zeros.dispose();
|
|
32
|
-
return out;
|
|
33
|
-
},
|
|
34
|
-
takeRows(value, keep) {
|
|
35
|
-
const indices = MlxArray.fromInt32(Int32Array.from(keep), [keep.length]);
|
|
36
|
-
const out = ops.takeAxis(value, indices, 0);
|
|
37
|
-
indices.dispose();
|
|
38
|
-
return out;
|
|
39
|
-
},
|
|
40
|
-
copy: (value) => ops.copyOf(value),
|
|
41
|
-
rollRows: (value, indices) => ops.takeAlongAxis(value, indices, 2),
|
|
42
|
-
dispose: (value) => value.dispose(),
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export const quantizedRowStorage: RowStorage<ops.QuantizedTensor> = {
|
|
46
|
-
shape: (value) => value.packed.shape as [number, number, number, number],
|
|
47
|
-
slice(value, batchFrom, batchTo, tokenFrom, tokenTo) {
|
|
48
|
-
const cut = (array: MlxArray): MlxArray => {
|
|
49
|
-
const [, H, , D] = array.shape as [number, number, number, number];
|
|
50
|
-
return array.slice([batchFrom, 0, tokenFrom, 0], [batchTo, H, tokenTo, D]);
|
|
51
|
-
};
|
|
52
|
-
return { packed: cut(value.packed), scales: cut(value.scales), biases: cut(value.biases) };
|
|
53
|
-
},
|
|
54
|
-
concatTokens(values) {
|
|
55
|
-
return {
|
|
56
|
-
packed: ops.concatAxis(values.map((value) => value.packed), 2),
|
|
57
|
-
scales: ops.concatAxis(values.map((value) => value.scales), 2),
|
|
58
|
-
biases: ops.concatAxis(values.map((value) => value.biases), 2),
|
|
59
|
-
};
|
|
60
|
-
},
|
|
61
|
-
concatRows(values) {
|
|
62
|
-
return {
|
|
63
|
-
packed: ops.concatAxis(values.map((value) => value.packed), 0),
|
|
64
|
-
scales: ops.concatAxis(values.map((value) => value.scales), 0),
|
|
65
|
-
biases: ops.concatAxis(values.map((value) => value.biases), 0),
|
|
66
|
-
};
|
|
67
|
-
},
|
|
68
|
-
padLeft(value, tokens) {
|
|
69
|
-
const pad = (array: MlxArray): MlxArray => plainRowStorage.padLeft(array, tokens);
|
|
70
|
-
return { packed: pad(value.packed), scales: pad(value.scales), biases: pad(value.biases) };
|
|
71
|
-
},
|
|
72
|
-
takeRows(value, keep) {
|
|
73
|
-
const take = (array: MlxArray): MlxArray => plainRowStorage.takeRows(array, keep);
|
|
74
|
-
return { packed: take(value.packed), scales: take(value.scales), biases: take(value.biases) };
|
|
75
|
-
},
|
|
76
|
-
copy(value) {
|
|
77
|
-
return {
|
|
78
|
-
packed: ops.copyOf(value.packed),
|
|
79
|
-
scales: ops.copyOf(value.scales),
|
|
80
|
-
biases: ops.copyOf(value.biases),
|
|
81
|
-
};
|
|
82
|
-
},
|
|
83
|
-
rollRows(value, indices) {
|
|
84
|
-
const packed = ops.takeAlongAxis(value.packed, indices, 2);
|
|
85
|
-
let scales: MlxArray | undefined;
|
|
86
|
-
try {
|
|
87
|
-
scales = ops.takeAlongAxis(value.scales, indices, 2);
|
|
88
|
-
return { packed, scales, biases: ops.takeAlongAxis(value.biases, indices, 2) };
|
|
89
|
-
} catch (error) { packed.dispose(); scales?.dispose(); throw error; }
|
|
90
|
-
},
|
|
91
|
-
dispose(value) {
|
|
92
|
-
value.packed.dispose();
|
|
93
|
-
value.scales.dispose();
|
|
94
|
-
value.biases.dispose();
|
|
95
|
-
},
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
/** Per-row cyclic shift, shared by plain and encoded storage planes.
|
|
99
|
-
* This is mlx-lm's dynamic_roll indexing; only positions cross the FFI. */
|
|
100
|
-
export function rowRollIndices(length: number, shifts: readonly number[]): MlxArray {
|
|
101
|
-
using columns = ops.arange(0, length, 1, Dtype.int32);
|
|
102
|
-
using positions = ops.reshape(columns, [1, 1, length, 1]);
|
|
103
|
-
using starts = ops.fromInt32(shifts.map(shift => ((-shift % length) + length) % length), [shifts.length, 1, 1, 1]);
|
|
104
|
-
using raw = ops.add(positions, starts);
|
|
105
|
-
using width = ops.fromInt32([length], []);
|
|
106
|
-
using wrapped = ops.sub(raw, width);
|
|
107
|
-
using over = ops.greaterEqual(raw, width);
|
|
108
|
-
return ops.where(over, wrapped, raw);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function mergeStorageRows<T>(
|
|
112
|
-
storage: RowStorage<T>,
|
|
113
|
-
rows: readonly T[],
|
|
114
|
-
leftPad: readonly number[],
|
|
115
|
-
): T {
|
|
116
|
-
const padded = rows.map((row, index) => storage.padLeft(row, leftPad[index]!));
|
|
117
|
-
try {
|
|
118
|
-
return storage.concatRows(padded);
|
|
119
|
-
} finally {
|
|
120
|
-
for (const row of padded) storage.dispose(row);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** De-roll storage into temporal order, then cut one row or the whole batch. */
|
|
125
|
-
export function temporalStorageView<T>(
|
|
126
|
-
storage: RowStorage<T>,
|
|
127
|
-
value: T,
|
|
128
|
-
state: BatchedRotatingState,
|
|
129
|
-
options: { row?: number; from?: number; to?: number; copy?: boolean } = {},
|
|
130
|
-
): T {
|
|
131
|
-
const [batch, , tokens] = storage.shape(value);
|
|
132
|
-
const batchFrom = options.row ?? 0;
|
|
133
|
-
const batchTo = options.row === undefined ? batch : options.row + 1;
|
|
134
|
-
const parts = state.temporalRanges(tokens).map(([from, to]) =>
|
|
135
|
-
storage.slice(value, batchFrom, batchTo, from, to)
|
|
136
|
-
);
|
|
137
|
-
const ordered = parts.length === 1 ? parts[0]! : storage.concatTokens(parts);
|
|
138
|
-
if (parts.length > 1) for (const part of parts) storage.dispose(part);
|
|
139
|
-
const cut = storage.slice(
|
|
140
|
-
ordered,
|
|
141
|
-
0,
|
|
142
|
-
batchTo - batchFrom,
|
|
143
|
-
options.from ?? 0,
|
|
144
|
-
options.to ?? state.validLength,
|
|
145
|
-
);
|
|
146
|
-
storage.dispose(ordered);
|
|
147
|
-
if (!options.copy) return cut;
|
|
148
|
-
const owned = storage.copy(cut);
|
|
149
|
-
storage.dispose(cut);
|
|
150
|
-
return owned;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/** Borrow storage, return an owned chronological block without decoding the
|
|
154
|
-
* representation. Port of mlx-lm's BatchRotatingKVCache._update_concat
|
|
155
|
-
* (MIT): discard spare capacity, retain the full window for the first query. */
|
|
156
|
-
export function appendRotatingStorage<T>(
|
|
157
|
-
storage: RowStorage<T>, previous: T | null, incoming: T, state: BatchedRotatingState,
|
|
158
|
-
): T {
|
|
159
|
-
if (previous === null) return storage.slice(incoming, 0, storage.shape(incoming)[0], 0, storage.shape(incoming)[2]);
|
|
160
|
-
const active = state.activeLength;
|
|
161
|
-
const shifts = state.prefillRoll();
|
|
162
|
-
if (shifts?.some(shift => shift !== 0)) {
|
|
163
|
-
const chronological = temporalStorageView(storage, previous, state, { to: active });
|
|
164
|
-
let rolled: T | undefined, history: T | undefined;
|
|
165
|
-
try {
|
|
166
|
-
using indices = rowRollIndices(active, shifts);
|
|
167
|
-
rolled = storage.rollRows(chronological, indices);
|
|
168
|
-
history = storage.slice(rolled, 0, state.batchSize, Math.max(0, active - state.maxSize + 1), active);
|
|
169
|
-
return storage.concatTokens([history, incoming]);
|
|
170
|
-
} finally {
|
|
171
|
-
storage.dispose(chronological); if (rolled) storage.dispose(rolled); if (history) storage.dispose(history);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
const history = temporalStorageView(storage, previous, state, {
|
|
175
|
-
from: Math.max(0, active - state.maxSize + 1), to: active,
|
|
176
|
-
});
|
|
177
|
-
try { return storage.concatTokens([history, incoming]); }
|
|
178
|
-
finally { storage.dispose(history); }
|
|
179
|
-
}
|
package/src/model/batched-ssm.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { SsmPrefillPadding } from "./ssm-prefill-padding";
|
|
2
|
-
import type { PaddedPrefillCache, PrefillPadding } from "./gemma4-base";
|
|
3
|
-
import * as ops from "../mlx/ops";
|
|
4
|
-
import type { MlxArray } from "../mlx/array";
|
|
5
|
-
import type { BatchableCache, Cache } from "./gemma4-base";
|
|
6
|
-
import { SSMCache } from "./qwen3-delta";
|
|
7
|
-
|
|
8
|
-
/** Recurrent storage behind the same row-layout port as attention KV.
|
|
9
|
-
* Inputs to merge are borrowed; request membership is owned by the caller. */
|
|
10
|
-
export class BatchedSSMCache extends SSMCache implements BatchableCache, PaddedPrefillCache {
|
|
11
|
-
constructor() { super(); this.offsets = []; }
|
|
12
|
-
preparePrefill(padding: PrefillPadding): void {
|
|
13
|
-
if (!this.offsets!.length) this.offsets = padding.lengths.map(() => 0);
|
|
14
|
-
const padded = padding.leftPadding?.some(n => n > 0) || padding.rightPadding?.some(n => n > 0);
|
|
15
|
-
this.prefillPadding = padded ? new SsmPrefillPadding(padding) : null;
|
|
16
|
-
}
|
|
17
|
-
finalizePrefill(): void { this.prefillPadding = null; }
|
|
18
|
-
get rowOffsets(): readonly number[] { return this.offsets!; }
|
|
19
|
-
get leftPad(): readonly number[] { return this.rowOffsets.map(() => 0); }
|
|
20
|
-
makeEmptyBatch(): BatchedSSMCache { return new BatchedSSMCache(); }
|
|
21
|
-
projectedBytes(_tokens: number): number {
|
|
22
|
-
return this.batchSize ? this.state().reduce((bytes, array) => bytes + array.nbytes, 0) / this.batchSize : 0;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
mergeRows(rows: readonly Cache[]): void {
|
|
26
|
-
if (!rows.length) { this.dispose(); return; }
|
|
27
|
-
const sources = rows as readonly SSMCache[];
|
|
28
|
-
const offsets = sources.flatMap(source => source.offsets ?? [source.offset]);
|
|
29
|
-
const merge = (field: "conv" | "recurrent"): MlxArray | null => {
|
|
30
|
-
const prototype = sources.find(source => source[field])?.[field];
|
|
31
|
-
if (!prototype) return null;
|
|
32
|
-
if (sources.length === 1) return ops.copyOf(prototype);
|
|
33
|
-
const empty: MlxArray[] = [];
|
|
34
|
-
try {
|
|
35
|
-
return ops.concatAxis(sources.map(source => {
|
|
36
|
-
if (source[field]) return source[field]!;
|
|
37
|
-
const zeros = ops.zeros([source.offsets?.length ?? 1, ...prototype.shape.slice(1)], prototype.dtype);
|
|
38
|
-
empty.push(zeros); return zeros;
|
|
39
|
-
}), 0);
|
|
40
|
-
} finally { for (const array of empty) array.dispose(); }
|
|
41
|
-
};
|
|
42
|
-
const conv = merge("conv");
|
|
43
|
-
let recurrent;
|
|
44
|
-
try { recurrent = merge("recurrent"); }
|
|
45
|
-
catch (error) { conv?.dispose(); throw error; }
|
|
46
|
-
this.dispose();
|
|
47
|
-
this.conv = conv; this.recurrent = recurrent;
|
|
48
|
-
this.offsets = offsets; this.offset = Math.max(0, ...offsets);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
override dispose(): void { super.dispose(); this.offset = 0; this.offsets = []; }
|
|
52
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { decodedKvDonorAttention } from "./decoded-kv-donor";
|
|
2
|
-
import type { MlxArray } from "../mlx/array";
|
|
3
|
-
import { KvTensorRows, type KvTensorRowView } from "../backends/mlx/kv-tensor-rows";
|
|
4
|
-
import { disposeResources } from "../engine/resources";
|
|
5
|
-
import { TurboQuantKVCache, type BatchableCache, type Cache, type Mask, type RotatedValueAttentionState, type PaddedPrefillCache, type PrefillPadding } from "./gemma4-base";
|
|
6
|
-
import { TurboQuantCodec, turboQuantFusedDecode, disposeTurboQuant, type TurboQuantTensor } from "./turboquant-codec";
|
|
7
|
-
|
|
8
|
-
const fields = ["kIdx", "kScales", "kZeros", "vPacked", "vScales"] as const;
|
|
9
|
-
function encoded(planes: readonly MlxArray[]): TurboQuantTensor {
|
|
10
|
-
return { kIdx: planes[0]!, kScales: planes[1]!, kZeros: planes[2]!, vPacked: planes[3]!, vScales: planes[4]! };
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/** The existing TurboQuant codec over shared tensor-row storage. Row changes
|
|
14
|
-
* copy encoded bytes without decoding, rotating or requantizing their values. */
|
|
15
|
-
export class BatchedTurboQuantKVCache implements BatchableCache, PaddedPrefillCache {
|
|
16
|
-
readonly #storage = new KvTensorRows();
|
|
17
|
-
readonly #codec: TurboQuantCodec;
|
|
18
|
-
#reuseOffsets: number[] = [];
|
|
19
|
-
#headDim: number | null = null;
|
|
20
|
-
constructor(readonly kBits: number, readonly vBits: number,
|
|
21
|
-
readonly fusedDecode = turboQuantFusedDecode()) {
|
|
22
|
-
this.#codec = new TurboQuantCodec(kBits, vBits, fusedDecode);
|
|
23
|
-
}
|
|
24
|
-
restorePrefillEnds(ends: readonly number[] | undefined): void { this.#storage.restorePrefillEnds(ends); }
|
|
25
|
-
preparePrefill(padding: PrefillPadding): void {
|
|
26
|
-
this.#storage.preparePrefill(padding);
|
|
27
|
-
if (!this.#reuseOffsets.length) this.#reuseOffsets = padding.lengths.map(() => 0);
|
|
28
|
-
}
|
|
29
|
-
finalizePrefill(): void { this.#storage.finalizePrefill(); }
|
|
30
|
-
captureDonorRows(): import("./gemma4-base").KvDonorRows {
|
|
31
|
-
if (!this.#storage.planes.length || this.#headDim === null) throw new Error("cache is empty");
|
|
32
|
-
const [keys, values] = this.#codec.decode(encoded(this.#storage.planes), this.offset, this.#headDim, false);
|
|
33
|
-
return { keys, values, ...this.#storage.captureDonorValidity() };
|
|
34
|
-
}
|
|
35
|
-
captureDonorAttention(): import("./gemma4-base").KvDonorAttention {
|
|
36
|
-
return decodedKvDonorAttention(this.captureDonorRows());
|
|
37
|
-
}
|
|
38
|
-
get rotatedValueAttention(): RotatedValueAttentionState { return this; }
|
|
39
|
-
signature(): string { return `kv:batched-turboquant:${this.kBits}:${this.vBits}`; }
|
|
40
|
-
get minimumReusableOffset(): number { return Math.max(0, ...this.#reuseOffsets); }
|
|
41
|
-
get headDim(): number | null { return this.#headDim; }
|
|
42
|
-
get rowOffsets(): readonly number[] { return this.#storage.rowOffsets; }
|
|
43
|
-
get leftPad(): readonly number[] { return this.#storage.leftPad; }
|
|
44
|
-
get batchSize(): number | null { return this.#storage.batchSize; }
|
|
45
|
-
get offset(): number { return this.#storage.offset; }
|
|
46
|
-
get ropeOffsetArr(): MlxArray | undefined { return this.#storage.ropeOffsetArr; }
|
|
47
|
-
makeEmptyBatch(): BatchedTurboQuantKVCache { return new BatchedTurboQuantKVCache(this.kBits, this.vBits, this.fusedDecode); }
|
|
48
|
-
bytesPerToken(): number { return this.#storage.bytesPerToken(); }
|
|
49
|
-
projectedBytes(tokens: number): number { return this.bytesPerToken() * tokens; }
|
|
50
|
-
makeMask(tokens: number, window: number | null): Mask { return this.#storage.makeMask(tokens, window); }
|
|
51
|
-
isTrimmable(): boolean { return true; }
|
|
52
|
-
trim(count: number): void { this.#storage.trim(count); }
|
|
53
|
-
specRoundBegin(): void { this.#storage.specRoundBegin(); }
|
|
54
|
-
specRoundCommit(): void { this.#storage.specRoundCommit(); }
|
|
55
|
-
specRoundRollback(keep: number | readonly number[]): void { this.#storage.specRoundRollback(keep); }
|
|
56
|
-
#append(k: MlxArray, v: MlxArray, defer: boolean): [MlxArray, MlxArray] {
|
|
57
|
-
const packed = this.#codec.encode(k, v);
|
|
58
|
-
try {
|
|
59
|
-
this.#storage.append(fields.map(field => packed[field]));
|
|
60
|
-
this.#headDim = k.shape[3]!;
|
|
61
|
-
return this.#codec.decode(encoded(this.#storage.planes), this.offset, this.#headDim, defer);
|
|
62
|
-
} finally { disposeTurboQuant(packed); }
|
|
63
|
-
}
|
|
64
|
-
updateAndFetch(k: MlxArray, v: MlxArray): [MlxArray, MlxArray] { return this.#append(k, v, false); }
|
|
65
|
-
updateAndFetchDeferredV(k: MlxArray, v: MlxArray): [MlxArray, MlxArray] { return this.#append(k, v, true); }
|
|
66
|
-
mergeRows(rows: readonly Cache[]): void {
|
|
67
|
-
const views: KvTensorRowView[] = [], held: MlxArray[] = [];
|
|
68
|
-
const reuseOffsets: number[] = [];
|
|
69
|
-
let dim = this.#headDim;
|
|
70
|
-
try {
|
|
71
|
-
for (const row of rows) {
|
|
72
|
-
if (row instanceof BatchedTurboQuantKVCache) {
|
|
73
|
-
views.push(row.#storage); dim ??= row.headDim; reuseOffsets.push(...row.#reuseOffsets);
|
|
74
|
-
} else if (row instanceof TurboQuantKVCache) {
|
|
75
|
-
const planes = row.state(); held.push(...planes); reuseOffsets.push(row.minimumReusableOffset);
|
|
76
|
-
views.push({ planes, rowOffsets: [row.offset], leftPad: [0] }); dim ??= row.headDim;
|
|
77
|
-
} else throw new Error(`TurboQuant row layout cannot merge ${row.signature()}`);
|
|
78
|
-
}
|
|
79
|
-
this.#storage.mergeRows(views); this.#headDim = dim; this.#reuseOffsets = reuseOffsets;
|
|
80
|
-
} finally { disposeResources(held); }
|
|
81
|
-
}
|
|
82
|
-
alignRows(leftPad: readonly number[]): void { this.#storage.alignRows(leftPad); }
|
|
83
|
-
filterRows(keep: readonly number[]): void {
|
|
84
|
-
this.#storage.filterRows(keep); this.#reuseOffsets = keep.map(row => this.#reuseOffsets[row]!);
|
|
85
|
-
}
|
|
86
|
-
state(): MlxArray[] { return this.#storage.planes; }
|
|
87
|
-
extractRow(row: number): TurboQuantKVCache {
|
|
88
|
-
const result = new TurboQuantKVCache(this.kBits, this.vBits, this.fusedDecode), count = this.rowOffsets[row]!;
|
|
89
|
-
if (count) result.restoreState(encoded(this.#storage.extractRow(row)), count, this.#headDim!);
|
|
90
|
-
result.minimumReusableOffset = this.#reuseOffsets[row] ?? 0;
|
|
91
|
-
return result;
|
|
92
|
-
}
|
|
93
|
-
dispose(): void { this.#storage.dispose(); this.#headDim = null; this.#reuseOffsets = []; }
|
|
94
|
-
}
|