@mlx-bun/inference 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +1475 -2
- package/THIRD_PARTY_NOTICES.md +3404 -0
- package/dist/native/libmlx_bun_ane.dylib +0 -0
- package/dist/native/libmlx_bun_expert_io.dylib +0 -0
- package/dist/native/mlx-bun-frame-extract +0 -0
- package/examples/fit-model.ts +25 -0
- package/examples/qwen3-forward.ts +42 -0
- package/examples/qwen3-generate.ts +28 -0
- package/examples/trellis-expand.ts +23 -0
- package/package.json +129 -4
- package/src/adapters/available.ts +110 -0
- package/src/adapters/index.ts +3 -0
- package/src/adapters/manager.ts +316 -0
- package/src/artifacts/auxiliary-files.ts +45 -0
- package/src/artifacts/config-dialects.ts +94 -0
- package/src/artifacts/config.ts +341 -0
- package/src/artifacts/draft-vocabulary.ts +30 -0
- package/src/artifacts/expert-offload-build.ts +75 -0
- package/src/artifacts/expert-offload.ts +89 -0
- package/src/artifacts/experts/index.ts +3 -0
- package/src/artifacts/experts/io.ts +386 -0
- package/src/artifacts/experts/residency.ts +1134 -0
- package/src/artifacts/experts/usage.ts +415 -0
- package/src/artifacts/fingerprint.ts +44 -0
- package/src/artifacts/glm52/container.ts +305 -0
- package/src/artifacts/glm52/expert-layout.ts +249 -0
- package/src/artifacts/glm52/index.ts +7 -0
- package/src/artifacts/glm52/kernel-layout.ts +124 -0
- package/src/artifacts/glm52/layout.ts +152 -0
- package/src/artifacts/glm52/memory.ts +500 -0
- package/src/artifacts/glm52/resident-weights.ts +135 -0
- package/src/artifacts/glm52/weights.ts +503 -0
- package/src/artifacts/glm52-config.ts +262 -0
- package/src/artifacts/identity.ts +94 -0
- package/src/artifacts/index.ts +15 -0
- package/src/artifacts/mmap.ts +90 -0
- package/src/artifacts/safetensors-writer.ts +249 -0
- package/src/artifacts/safetensors.ts +164 -0
- package/src/artifacts/turboquant-fold.ts +42 -0
- package/src/artifacts/weight-audit.ts +43 -0
- package/src/artifacts/weights.ts +255 -0
- package/src/contracts/index.ts +2 -0
- package/src/contracts/mlx/attention.ts +8 -0
- package/src/contracts/mlx/cache.ts +510 -0
- package/src/contracts/mlx/checkpoint.ts +10 -0
- package/src/contracts/mlx/draft-checkpoint.ts +14 -0
- package/src/contracts/mlx/draft-projection.ts +27 -0
- package/src/contracts/mlx/draft-target.ts +84 -0
- package/src/contracts/mlx/drafter.ts +176 -0
- package/src/contracts/mlx/forward-work.ts +23 -0
- package/src/contracts/mlx/glm52-weights.ts +25 -0
- package/src/contracts/mlx/graph.ts +309 -0
- package/src/contracts/mlx/head.ts +6 -0
- package/src/contracts/mlx/index.ts +15 -0
- package/src/contracts/mlx/kv-codec.ts +9 -0
- package/src/contracts/mlx/media.ts +113 -0
- package/src/contracts/mlx/positions.ts +16 -0
- package/src/contracts/mlx/row-table.ts +2 -0
- package/src/contracts/mlx/trainable.ts +103 -0
- package/src/contracts/mlx/whisper.ts +96 -0
- package/src/contracts/portable/composition.ts +106 -0
- package/src/contracts/portable/denoising.ts +17 -0
- package/src/contracts/portable/execution.ts +79 -0
- package/src/contracts/portable/generation.ts +103 -0
- package/src/contracts/portable/graph.ts +80 -0
- package/src/contracts/portable/index.ts +15 -0
- package/src/contracts/portable/memory-plan.ts +26 -0
- package/src/contracts/portable/object-cache.ts +8 -0
- package/src/contracts/portable/prefill.ts +63 -0
- package/src/contracts/portable/prefix-cache.ts +33 -0
- package/src/contracts/portable/prompt.ts +2 -0
- package/src/contracts/portable/resources.ts +25 -0
- package/src/contracts/portable/rollback.ts +7 -0
- package/src/contracts/portable/sampling.ts +44 -0
- package/src/contracts/portable/scheduling.ts +54 -0
- package/src/contracts/portable/token-delivery.ts +4 -0
- package/src/contracts/portable/tsconfig.json +14 -0
- package/src/embeddings/index.ts +1 -0
- package/src/embeddings/text.ts +85 -0
- package/src/execution/admission.ts +59 -0
- package/src/execution/batch-group.ts +1240 -0
- package/src/execution/batch-types.ts +225 -0
- package/src/execution/cancellation.ts +38 -0
- package/src/execution/continuation-request.ts +45 -0
- package/src/execution/continuation-types.ts +10 -0
- package/src/execution/coordinator.ts +70 -0
- package/src/execution/denoising-group.ts +180 -0
- package/src/execution/engine.ts +56 -0
- package/src/execution/fill-group.ts +505 -0
- package/src/execution/fit.ts +184 -0
- package/src/execution/gateway-binding.ts +178 -0
- package/src/execution/grammar-group.ts +224 -0
- package/src/execution/index.ts +18 -0
- package/src/execution/methods.ts +75 -0
- package/src/execution/mixed-iteration.ts +96 -0
- package/src/execution/plan.ts +65 -0
- package/src/execution/prefill-cohort.ts +100 -0
- package/src/execution/prefill-rows.ts +263 -0
- package/src/execution/request-policy.ts +19 -0
- package/src/execution/row-sampling.ts +49 -0
- package/src/execution/scheduler.ts +92 -0
- package/src/execution/session.ts +247 -0
- package/src/execution/speculative-group.ts +797 -0
- package/src/execution/tasks.ts +44 -0
- package/src/generation/autoregressive.ts +840 -0
- package/src/generation/bindings/autoregressive.ts +104 -0
- package/src/generation/bindings/denoising.ts +60 -0
- package/src/generation/bindings/prefill-policy.ts +36 -0
- package/src/generation/checkpoint-identity.ts +60 -0
- package/src/generation/denoising.ts +85 -0
- package/src/generation/diffusion.ts +583 -0
- package/src/generation/fill/echo-index.ts +188 -0
- package/src/generation/fill/index.ts +3 -0
- package/src/generation/fill/proposal.ts +69 -0
- package/src/generation/fill/schema-rows.ts +506 -0
- package/src/generation/fill/session.ts +464 -0
- package/src/generation/fill/tool-boundary.ts +103 -0
- package/src/generation/fill-append.ts +58 -0
- package/src/generation/generate.ts +44 -0
- package/src/generation/grammar-step.ts +39 -0
- package/src/generation/index.ts +14 -0
- package/src/generation/phase-dispatch.ts +115 -0
- package/src/generation/prefill.ts +33 -0
- package/src/generation/result.ts +49 -0
- package/src/generation/scopes.ts +157 -0
- package/src/generation/speculative/acceptance.ts +41 -0
- package/src/generation/speculative/adaptive-draft-gate.ts +166 -0
- package/src/generation/speculative/bindings/assistant-rows.ts +102 -0
- package/src/generation/speculative/bindings/autoregressive-rows.ts +124 -0
- package/src/generation/speculative/bindings/binding.ts +106 -0
- package/src/generation/speculative/bindings/deepspec-rows.ts +33 -0
- package/src/generation/speculative/bindings/draft-target.ts +10 -0
- package/src/generation/speculative/bindings/glm52-mtp-rows.ts +128 -0
- package/src/generation/speculative/bindings/projected-context-rows.ts +78 -0
- package/src/generation/speculative/bindings/projected-draft-rows.ts +95 -0
- package/src/generation/speculative/bindings/qwen-mtp-rows.ts +336 -0
- package/src/generation/speculative/bindings/two-model-rows.ts +63 -0
- package/src/generation/speculative/cache-identity.ts +16 -0
- package/src/generation/speculative/draft-kind.ts +149 -0
- package/src/generation/speculative/draft-policy.ts +41 -0
- package/src/generation/speculative/draft-registry.ts +118 -0
- package/src/generation/speculative/draft-vocab.ts +110 -0
- package/src/generation/speculative/index.ts +17 -0
- package/src/generation/speculative/output.ts +49 -0
- package/src/generation/speculative/round.ts +307 -0
- package/src/generation/speculative/source.ts +144 -0
- package/src/generation/speculative/sources/assistant-source.ts +64 -0
- package/src/generation/speculative/sources/deepspec-source.ts +70 -0
- package/src/generation/speculative/sources/dflash-source.ts +84 -0
- package/src/generation/speculative/sources/dflash2-source.ts +86 -0
- package/src/generation/speculative/sources/glm52-mtp-source.ts +66 -0
- package/src/generation/speculative/sources/ngram-source.ts +165 -0
- package/src/generation/speculative/sources/qwen-mtp-source.ts +154 -0
- package/src/generation/speculative/sources/two-model.ts +75 -0
- package/src/generation/types.ts +194 -0
- package/src/index.ts +20 -0
- package/src/input/audio/audiotoolbox.ts +112 -0
- package/src/input/audio/decode.ts +133 -0
- package/src/input/audio/features.ts +202 -0
- package/src/input/audio/index.ts +6 -0
- package/src/input/audio/transcode.ts +67 -0
- package/src/input/audio/whisper-mel.ts +185 -0
- package/src/input/audio/whisper-tokenizer.ts +238 -0
- package/src/input/chat-template.ts +389 -0
- package/src/input/index.ts +6 -0
- package/src/input/media-fetch.ts +439 -0
- package/src/input/packed-mixed.ts +43 -0
- package/src/input/special-tokens.ts +75 -0
- package/src/input/token-groups.ts +49 -0
- package/src/input/tokenizer.ts +336 -0
- package/src/input/tool-call.ts +689 -0
- package/src/input/vision/index.ts +3 -0
- package/src/input/vision/preprocess.ts +247 -0
- package/src/input/vision/prompt.ts +398 -0
- package/src/input/vision/qwen3vl-preprocess.ts +409 -0
- package/src/input/vision/qwen3vl-prompt.ts +237 -0
- package/src/input/vision/video-frames.ts +100 -0
- package/src/kernels/ane/fill.ts +101 -0
- package/src/kernels/ane/linear.ts +416 -0
- package/src/kernels/attention/flash.ts +694 -0
- package/src/kernels/attention/kvq4-decode.ts +155 -0
- package/src/kernels/attention/masks.ts +40 -0
- package/src/kernels/attention/multi-query.ts +193 -0
- package/src/kernels/attention/paged.ts +130 -0
- package/src/kernels/delta/gated.ts +306 -0
- package/src/kernels/delta/index.ts +3 -0
- package/src/kernels/delta/silu-rms-heads.ts +69 -0
- package/src/kernels/delta/state.ts +74 -0
- package/src/kernels/gated-rms-norm.ts +64 -0
- package/src/kernels/glm52/layout.ts +37 -0
- package/src/kernels/glm52/streamed-experts.ts +360 -0
- package/src/kernels/logits.ts +38 -0
- package/src/kernels/quantization/affine-row.ts +154 -0
- package/src/kernels/quantization/affine-rows.ts +36 -0
- package/src/kernels/quantization/affine-split-mma.ts +144 -0
- package/src/kernels/quantization/affine3-mma.ts +117 -0
- package/src/kernels/quantization/affine3-rows.ts +103 -0
- package/src/kernels/quantization/affine4-mma.ts +113 -0
- package/src/kernels/quantization/affine4-rows.ts +102 -0
- package/src/kernels/residual-rms-norm.ts +65 -0
- package/src/kernels/sampling/index.ts +2 -0
- package/src/kernels/sampling/normalized-argmax.ts +116 -0
- package/src/kernels/sampling/token-bitmask.ts +52 -0
- package/src/kernels/softcap.ts +35 -0
- package/src/kernels/trellis/codebook.ts +123 -0
- package/src/kernels/trellis/down-codebook.ts +184 -0
- package/src/kernels/trellis/down-factored.ts +180 -0
- package/src/kernels/trellis/down-k3-interleaved-factored.ts +146 -0
- package/src/kernels/trellis/down-mma-wide.ts +195 -0
- package/src/kernels/trellis/down-mma.ts +145 -0
- package/src/kernels/trellis/expand.ts +42 -0
- package/src/kernels/trellis/gate-up-codebook-mma.ts +141 -0
- package/src/kernels/trellis/gate-up-codebook.ts +137 -0
- package/src/kernels/trellis/gate-up-factored.ts +197 -0
- package/src/kernels/trellis/gate-up-mma-wide.ts +147 -0
- package/src/kernels/trellis/gate-up-mma.ts +148 -0
- package/src/kernels/trellis/gate-up.ts +248 -0
- package/src/kernels/trellis/geometry.ts +22 -0
- package/src/kernels/trellis/index.ts +103 -0
- package/src/kernels/trellis/launch.ts +12 -0
- package/src/kernels/trellis/mixed-gate-up-factored.ts +119 -0
- package/src/kernels/trellis/mixed-gate-up.ts +146 -0
- package/src/kernels/trellis/qualified.ts +34 -0
- package/src/kernels/trellis/reduce.ts +150 -0
- package/src/kernels/trellis/scatter.ts +407 -0
- package/src/kernels/trellis/splitk-prefill.ts +152 -0
- package/src/kernels/trellis/tiled-prefill.ts +131 -0
- package/src/kernels/trellis/vector-expand.ts +58 -0
- package/src/kernels/trellis/wide-prefill.ts +89 -0
- package/src/kernels/turboquant/decode.ts +82 -0
- package/src/kernels/turboquant/index.ts +5 -0
- package/src/kernels/turboquant/inverse.ts +122 -0
- package/src/kernels/turboquant/ops.ts +860 -0
- package/src/kernels/turboquant/signs.ts +130 -0
- package/src/kernels/turboquant/tables.ts +124 -0
- package/src/layers/affine-verify-linear.ts +75 -0
- package/src/layers/ane-prefill-split.ts +283 -0
- package/src/layers/compiled-normalization.ts +41 -0
- package/src/layers/delta-heads.ts +23 -0
- package/src/layers/dense-embedding.ts +29 -0
- package/src/layers/dense-linear.ts +32 -0
- package/src/layers/dequantized-linear.ts +72 -0
- package/src/layers/folded-attention.ts +42 -0
- package/src/layers/geglu.ts +130 -0
- package/src/layers/helpers.ts +7 -0
- package/src/layers/index.ts +36 -0
- package/src/layers/kv4-decode-attention.ts +15 -0
- package/src/layers/layer-norm.ts +24 -0
- package/src/layers/loading.ts +92 -0
- package/src/layers/lora.ts +150 -0
- package/src/layers/normalization.ts +9 -0
- package/src/layers/prefix-layout.ts +33 -0
- package/src/layers/quantized-append-attention.ts +32 -0
- package/src/layers/quantized-attention.ts +353 -0
- package/src/layers/quantized-embedding.ts +39 -0
- package/src/layers/quantized-linear.ts +137 -0
- package/src/layers/quantized-switch-linear.ts +37 -0
- package/src/layers/qwen-append.ts +12 -0
- package/src/layers/qwen-mrope.ts +238 -0
- package/src/layers/rope-2d.ts +110 -0
- package/src/layers/rope.ts +389 -0
- package/src/layers/swiglu.ts +23 -0
- package/src/layers/trellis-codebook-down.ts +52 -0
- package/src/layers/trellis-codebook-gate-up.ts +42 -0
- package/src/layers/trellis-down.ts +117 -0
- package/src/layers/trellis-gate-up.ts +71 -0
- package/src/layers/trellis-linear.ts +211 -0
- package/src/layers/trellis-prompt.ts +102 -0
- package/src/layers/trellis-reduce-gate-up.ts +73 -0
- package/src/layers/trellis-scatter-down.ts +98 -0
- package/src/models/ane-install.ts +74 -0
- package/src/models/audio/conformer.ts +656 -0
- package/src/models/cache-composition.ts +44 -0
- package/src/models/capabilities.ts +89 -0
- package/src/models/chat-template.ts +10 -0
- package/src/models/composition.ts +107 -0
- package/src/models/diffusion-gemma/experts.ts +59 -0
- package/src/models/diffusion-gemma/family.ts +21 -0
- package/src/models/diffusion-gemma/model.ts +900 -0
- package/src/models/diffusion-gemma/vision.ts +549 -0
- package/src/models/drafter-loaders.ts +49 -0
- package/src/models/drafters.ts +39 -0
- package/src/models/factory.ts +351 -0
- package/src/models/families.ts +70 -0
- package/src/models/family.ts +125 -0
- package/src/models/gemma4/assistant-target.ts +46 -0
- package/src/models/gemma4/assistant.ts +327 -0
- package/src/models/gemma4/blocks.ts +755 -0
- package/src/models/gemma4/compiled-decode.ts +452 -0
- package/src/models/gemma4/family.ts +39 -0
- package/src/models/gemma4/gemma4-12b.ts +677 -0
- package/src/models/gemma4/gemma4-26b.ts +544 -0
- package/src/models/gemma4/gemma4-e4b.ts +599 -0
- package/src/models/gemma4/graphs.ts +147 -0
- package/src/models/gemma4/media.ts +88 -0
- package/src/models/gemma4/model.ts +860 -0
- package/src/models/gemma4/serving-blocks.ts +72 -0
- package/src/models/gemma4/trainable.ts +186 -0
- package/src/models/gemma4/written-blocks.ts +232 -0
- package/src/models/gemma4/written-forward.ts +159 -0
- package/src/models/gemma4/written-input.ts +29 -0
- package/src/models/glm52/atlas.ts +507 -0
- package/src/models/glm52/coupling.ts +388 -0
- package/src/models/glm52/dsa.ts +601 -0
- package/src/models/glm52/family.ts +20 -0
- package/src/models/glm52/mla.ts +812 -0
- package/src/models/glm52/model.ts +1127 -0
- package/src/models/glm52/moe.ts +223 -0
- package/src/models/glm52/mtp.ts +60 -0
- package/src/models/glm52/pilot.ts +537 -0
- package/src/models/glm52/reference.ts +445 -0
- package/src/models/glm52/residency.ts +557 -0
- package/src/models/glm52/streamed-experts.ts +447 -0
- package/src/models/graph.ts +59 -0
- package/src/models/implementation.ts +230 -0
- package/src/models/index.ts +15 -0
- package/src/models/media-input.ts +15 -0
- package/src/models/memory-plan.ts +39 -0
- package/src/models/minicpm5/family.ts +29 -0
- package/src/models/minicpm5/model.ts +394 -0
- package/src/models/minicpm5/trainable.ts +90 -0
- package/src/models/profile.ts +337 -0
- package/src/models/qwen/blocks.ts +658 -0
- package/src/models/qwen/checkpoint.ts +190 -0
- package/src/models/qwen/families.ts +57 -0
- package/src/models/qwen/media-input.ts +161 -0
- package/src/models/qwen/mtp.ts +101 -0
- package/src/models/qwen/qwen3-moe.ts +355 -0
- package/src/models/qwen/qwen3.ts +323 -0
- package/src/models/qwen/qwen38-27b-trellis-m1max.ts +1532 -0
- package/src/models/qwen/qwen38-27b-trellis-m4pro.ts +1092 -0
- package/src/models/qwen/qwen3_5.ts +433 -0
- package/src/models/qwen/written-layers.ts +285 -0
- package/src/models/row-table.ts +1 -0
- package/src/models/runtime.ts +73 -0
- package/src/models/speculative/deepspec-artifact.ts +10 -0
- package/src/models/speculative/deepspec.ts +744 -0
- package/src/models/speculative/dflash.ts +553 -0
- package/src/models/speculative/dflash2-artifact.ts +9 -0
- package/src/models/speculative/dflash2-operations.ts +1 -0
- package/src/models/speculative/dflash2.ts +576 -0
- package/src/models/speculative/loader.ts +29 -0
- package/src/models/support.ts +79 -0
- package/src/models/universal/archs.ts +365 -0
- package/src/models/universal/blocks.ts +479 -0
- package/src/models/universal/dense.ts +255 -0
- package/src/models/universal/family.ts +17 -0
- package/src/models/vision/qwen3vl.ts +566 -0
- package/src/models/vision/siglip.ts +520 -0
- package/src/models/vision/unified.ts +176 -0
- package/src/models/whisper/family.ts +19 -0
- package/src/models/whisper/fast.ts +734 -0
- package/src/models/whisper/model.ts +430 -0
- package/src/runtime/compiled-trace.ts +16 -0
- package/src/runtime/config.ts +77 -0
- package/src/runtime/expert-trace.ts +71 -0
- package/src/runtime/graph-forward.ts +65 -0
- package/src/runtime/integers.ts +6 -0
- package/src/runtime/native.ts +16 -0
- package/src/runtime/resources.ts +53 -0
- package/src/runtime/row-operations.ts +42 -0
- package/src/runtime/trace.ts +161 -0
- package/src/sampling/curve.ts +122 -0
- package/src/sampling/draft.ts +55 -0
- package/src/sampling/extras.ts +45 -0
- package/src/sampling/filters.ts +134 -0
- package/src/sampling/grammar.ts +630 -0
- package/src/sampling/hlg.ts +290 -0
- package/src/sampling/index.ts +9 -0
- package/src/sampling/processors.ts +142 -0
- package/src/sampling/sampler.ts +120 -0
- package/src/sampling/step.ts +343 -0
- package/src/sampling/types.ts +161 -0
- package/src/sampling/window-filters.ts +46 -0
- package/src/scoring/decisions.ts +96 -0
- package/src/scoring/full-sequence.ts +103 -0
- package/src/scoring/index.ts +9 -0
- package/src/scoring/kl.ts +29 -0
- package/src/scoring/perplexity.ts +165 -0
- package/src/scoring/response-logps.ts +65 -0
- package/src/state/affine-attention.ts +180 -0
- package/src/state/attachment.ts +68 -0
- package/src/state/attention-read.ts +215 -0
- package/src/state/batched-kv.ts +294 -0
- package/src/state/batched-mask.ts +445 -0
- package/src/state/batched-quant.ts +389 -0
- package/src/state/batched-quantized-kv.ts +209 -0
- package/src/state/batched-rotating-quant.ts +457 -0
- package/src/state/batched-rotating-state.ts +149 -0
- package/src/state/batched-rotating.ts +430 -0
- package/src/state/batched-row-storage.ts +179 -0
- package/src/state/batched-ssm.ts +54 -0
- package/src/state/batched-turboquant-kv.ts +144 -0
- package/src/state/bf16-first-kv.ts +663 -0
- package/src/state/cache-service.ts +592 -0
- package/src/state/capabilities.ts +65 -0
- package/src/state/checkpoint.ts +46 -0
- package/src/state/continuation-persistence.ts +126 -0
- package/src/state/decode-step-inputs.ts +31 -0
- package/src/state/decoded-kv-donor.ts +12 -0
- package/src/state/delayed-quantized-kv.ts +141 -0
- package/src/state/delayed-rotating-quantized-kv.ts +178 -0
- package/src/state/delayed-turboquant-kv.ts +123 -0
- package/src/state/durability.ts +214 -0
- package/src/state/encoder-cache.ts +26 -0
- package/src/state/full-kv-row-append.ts +33 -0
- package/src/state/full-kv-row-donor.ts +54 -0
- package/src/state/full-prefill-padding.ts +56 -0
- package/src/state/full-prefill-row.ts +112 -0
- package/src/state/full-transitioning-kv-rows.ts +70 -0
- package/src/state/glm52-cache.ts +783 -0
- package/src/state/grouped-heads-kv4-cache.ts +26 -0
- package/src/state/index.ts +38 -0
- package/src/state/kv-attention-view.ts +77 -0
- package/src/state/kv-budget.ts +14 -0
- package/src/state/kv-scheme.ts +315 -0
- package/src/state/kv-storage.ts +57 -0
- package/src/state/kv-tensor-rows.ts +212 -0
- package/src/state/kv.ts +324 -0
- package/src/state/kv4-head256-cache.ts +46 -0
- package/src/state/latent-legos.ts +895 -0
- package/src/state/layout.ts +277 -0
- package/src/state/leases.ts +26 -0
- package/src/state/paged/cache.ts +689 -0
- package/src/state/paged/codec.ts +36 -0
- package/src/state/paged/rows.ts +223 -0
- package/src/state/persistence-types.ts +173 -0
- package/src/state/persistence-worker.ts +83 -0
- package/src/state/persistence.ts +1036 -0
- package/src/state/persistence.worker.d.ts +3 -0
- package/src/state/persistence.worker.js +264 -0
- package/src/state/prefix-cache.ts +685 -0
- package/src/state/quantized-kv.ts +369 -0
- package/src/state/quantized-tensor.ts +26 -0
- package/src/state/request-policy.ts +48 -0
- package/src/state/retention-policy.ts +37 -0
- package/src/state/rollback.ts +131 -0
- package/src/state/rotating-kv-donor.ts +35 -0
- package/src/state/rotating-kv-layout.ts +341 -0
- package/src/state/rotating-kv.ts +529 -0
- package/src/state/rotating-quantized-kv.ts +616 -0
- package/src/state/rotating-row-transaction.ts +35 -0
- package/src/state/rows.ts +104 -0
- package/src/state/softcap-attention.ts +118 -0
- package/src/state/speculative/glm52-mtp-state.ts +38 -0
- package/src/state/speculative/qwen-mtp-state.ts +34 -0
- package/src/state/speculative-rotating-kv.ts +113 -0
- package/src/state/ssd-cache.ts +434 -0
- package/src/state/ssm-prefill-padding.ts +39 -0
- package/src/state/ssm.ts +422 -0
- package/src/state/target-layout.ts +7 -0
- package/src/state/tiered-prefix-cache.ts +45 -0
- package/src/state/training-cache.ts +300 -0
- package/src/state/transitioning-kv-rows.ts +267 -0
- package/src/state/turboquant-attention.ts +97 -0
- package/src/state/turboquant-codec.ts +90 -0
- package/src/state/turboquant-kv.ts +442 -0
- package/src/state/views.ts +26 -0
- package/src/transcription/index.ts +3 -0
- package/src/transcription/silero-vad.ts +379 -0
- package/src/transcription/whisper/decode.ts +773 -0
- package/src/transcription/whisper/format.ts +74 -0
- package/src/transcription/whisper/index.ts +4 -0
- package/src/transcription/whisper/timing.ts +274 -0
- package/src/transcription/whisper/transcribe.ts +394 -0
- package/src/transcription/whisper/types.ts +22 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { BatchableCache, Cache } from "../contracts/mlx/cache";
|
|
2
|
+
import { applyStateChanges, cleanupFailure, disposeResources } from "../runtime/resources";
|
|
3
|
+
import type { PreparedStateChange } from "../contracts/portable/resources";
|
|
4
|
+
|
|
5
|
+
/** Preserve the graph's layout capabilities when an empty sibling is made. */
|
|
6
|
+
export interface MlxRowLayout<Layout extends BatchableCache> extends BatchableCache {
|
|
7
|
+
makeEmptyBatch(): Layout;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Layer layouts own tensor geometry. This collection only applies the same
|
|
11
|
+
* row membership operation to every layer. It has no scheduling, sampling,
|
|
12
|
+
* checkpoint-key or persistence policy. */
|
|
13
|
+
export class MlxStateRows<Layout extends MlxRowLayout<Layout> = BatchableCache> {
|
|
14
|
+
/** Borrowed by the bound target graph; collection ownership stays here. */
|
|
15
|
+
readonly caches: Layout[];
|
|
16
|
+
#rows = 0;
|
|
17
|
+
|
|
18
|
+
/** Takes ownership of empty, compatible layer layouts. */
|
|
19
|
+
constructor(layouts: readonly Layout[]) { this.caches = [...layouts]; }
|
|
20
|
+
get rowCount(): number { return this.#rows; }
|
|
21
|
+
/** Retain an immutable batch boundary without extracting or materializing
|
|
22
|
+
* individual rows. Layer layouts decide how to share their backing arrays. */
|
|
23
|
+
clone(): MlxStateRows<Layout> {
|
|
24
|
+
const layouts: Layout[] = [];
|
|
25
|
+
try {
|
|
26
|
+
for (const source of this.caches) {
|
|
27
|
+
const layout = source.makeEmptyBatch(); layouts.push(layout);
|
|
28
|
+
layout.mergeRows([source]);
|
|
29
|
+
}
|
|
30
|
+
const result = new MlxStateRows(layouts); result.#rows = this.#rows;
|
|
31
|
+
return result;
|
|
32
|
+
} catch (error) { return cleanupFailure(error, () => disposeResources(layouts)); }
|
|
33
|
+
}
|
|
34
|
+
/** Prepare an initial cohort with one merge per layer. */
|
|
35
|
+
mergeRows(rows: readonly (readonly Cache[])[]): void {
|
|
36
|
+
const next: Layout[] = [];
|
|
37
|
+
try {
|
|
38
|
+
for (let layer = 0; layer < this.caches.length; layer++) {
|
|
39
|
+
const layout = this.caches[layer]!.makeEmptyBatch(); next.push(layout);
|
|
40
|
+
layout.mergeRows(rows.map(row => row[layer]!));
|
|
41
|
+
}
|
|
42
|
+
} catch (error) { return cleanupFailure(error, () => disposeResources(next)); }
|
|
43
|
+
const previous = this.caches.splice(0, this.caches.length, ...next);
|
|
44
|
+
this.#rows = rows.length; disposeResources(previous);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Borrow a prepared request's state. Build every replacement before
|
|
48
|
+
* releasing the active group, so a failed admission leaves it intact. */
|
|
49
|
+
append(row: readonly Cache[]): void {
|
|
50
|
+
applyStateChanges([() => this.prepareAppend(row)]);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Stage membership so a method can compose it with companion-state admission. */
|
|
54
|
+
prepareAppend(row: readonly Cache[]): PreparedStateChange {
|
|
55
|
+
return this.prepareAppendMany([row]);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Stage several admissions with one membership operation per layer. */
|
|
59
|
+
prepareAppendMany(rows: readonly (readonly Cache[])[]): PreparedStateChange {
|
|
60
|
+
const next: Layout[] = [];
|
|
61
|
+
try {
|
|
62
|
+
for (let layer = 0; layer < this.caches.length; layer++) {
|
|
63
|
+
const layout = this.caches[layer]!;
|
|
64
|
+
const merged = layout.makeEmptyBatch();
|
|
65
|
+
next.push(merged);
|
|
66
|
+
merged.mergeRows([...(this.#rows ? [layout] : []), ...rows.map(row => row[layer]!)]);
|
|
67
|
+
}
|
|
68
|
+
} catch (error) { return cleanupFailure(error, () => disposeResources(next)); }
|
|
69
|
+
return {
|
|
70
|
+
commit: () => {
|
|
71
|
+
const previous = this.caches.splice(0, this.caches.length, ...next.splice(0));
|
|
72
|
+
this.#rows += rows.length;
|
|
73
|
+
next.push(...previous);
|
|
74
|
+
},
|
|
75
|
+
dispose: () => disposeResources(next.splice(0)),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The method calls this only between committed steps. A layer failure
|
|
80
|
+
* invalidates the group; its caller discards the state. */
|
|
81
|
+
filterRows(keep: readonly number[]): void {
|
|
82
|
+
if (!keep.length) { this.clear(); return; }
|
|
83
|
+
for (const layout of this.caches) layout.filterRows(keep);
|
|
84
|
+
this.#rows = keep.length;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Returns independent request state for a cache publisher or a new group. */
|
|
88
|
+
extractRow(row: number): Cache[] {
|
|
89
|
+
const state: Cache[] = [];
|
|
90
|
+
try { for (const layout of this.caches) state.push(layout.extractRow(row)); return state; }
|
|
91
|
+
catch (error) { return cleanupFailure(error, () => disposeResources(state)); }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
clear(): void {
|
|
95
|
+
const next: Layout[] = [];
|
|
96
|
+
try { for (const layout of this.caches) next.push(layout.makeEmptyBatch()); }
|
|
97
|
+
catch (error) { return cleanupFailure(error, () => disposeResources(next)); }
|
|
98
|
+
const previous = this.caches.splice(0, this.caches.length, ...next);
|
|
99
|
+
this.#rows = 0;
|
|
100
|
+
disposeResources(previous);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
dispose(): void { this.#rows = 0; disposeResources(this.caches); }
|
|
104
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// The score-softcapped attention read (mlx-lm gemma2.py's manual attention):
|
|
2
|
+
// a graph whose layers softcap their attention scores composes it at
|
|
3
|
+
// construction in place of the cache's own read. The fused SDPA kernel cannot
|
|
4
|
+
// express the softcap, so this read fetches the window as plain keys and values
|
|
5
|
+
// and attends with the manual composition.
|
|
6
|
+
//
|
|
7
|
+
// It reads every KV storage through its dense fetch (`updateAndFetch`): plain
|
|
8
|
+
// and rotating storage and their row layouts hand their keys and values out as
|
|
9
|
+
// stored, TurboQuant storage decoded, affine storage dequantized (the delayed
|
|
10
|
+
// layouts per row, before and after a row's transition), paged storage
|
|
11
|
+
// gathered. Affine storage is dequantized and then read by the same manual
|
|
12
|
+
// attention, so a converted layer keeps the graph's own arithmetic over the
|
|
13
|
+
// values its storage holds. The read takes the storage's mask for the query
|
|
14
|
+
// count before the append, appends through `updateAndFetch`, then attends
|
|
15
|
+
// manually under that mask. The fetch and the mask are storage reads internal
|
|
16
|
+
// to `state/` (`KvStorage`); the cache contract carries neither.
|
|
17
|
+
|
|
18
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
19
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
20
|
+
import type { AttentionRead, Cache, Mask } from "../contracts/mlx/cache";
|
|
21
|
+
import { createCausalMask } from "../kernels/attention/masks";
|
|
22
|
+
import { logitSoftcap } from "../kernels/logits";
|
|
23
|
+
import { disposing } from "../layers/helpers";
|
|
24
|
+
import { FINFO_MIN } from "../layers/quantized-attention";
|
|
25
|
+
import { disposeResources } from "../runtime/resources";
|
|
26
|
+
import { kvStorage, type KvStorage } from "./kv-storage";
|
|
27
|
+
|
|
28
|
+
/** The softcapped reads of one attention layer, each appending `k` and `v`
|
|
29
|
+
* (borrowed; positional encoding applied) to `cache` for the phase it names and
|
|
30
|
+
* returning the read the layer attends once and disposes. `attend(q, scale)`
|
|
31
|
+
* takes queries [B, Hq, L, D] (borrowed) and returns an owned [B, Hq, L, Dv]. */
|
|
32
|
+
export interface SoftcapAttentionReads {
|
|
33
|
+
/** One new position per row. */
|
|
34
|
+
appendDecode(cache: Cache, k: MlxArray, v: MlxArray): AttentionRead;
|
|
35
|
+
/** `L` new positions per row, causal within the window. */
|
|
36
|
+
appendWindow(cache: Cache, k: MlxArray, v: MlxArray): AttentionRead;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The softcapped reads of a layer whose attention scores are capped at
|
|
40
|
+
* `softcap` (`tanh(scores / softcap) * softcap`). `window` is the layer's
|
|
41
|
+
* sliding window (null for a full-attention layer), the window its cache masks
|
|
42
|
+
* with. `arrayMasks` materializes the ordinary causal mask as a boolean array
|
|
43
|
+
* (gemma2's `create_attention_mask(..., return_array=True)`); the manual
|
|
44
|
+
* attention applies only array masks. Decode and window make the same call:
|
|
45
|
+
* the cache's own mask for the query count, which is no mask for one unpadded
|
|
46
|
+
* position. */
|
|
47
|
+
export function softcapAttentionReads(softcap: number, window: number | null, arrayMasks: boolean): SoftcapAttentionReads {
|
|
48
|
+
const mask = (cache: KvStorage, L: number): Mask => {
|
|
49
|
+
const own = cache.makeMask(L, window);
|
|
50
|
+
return arrayMasks && own.mode === "causal" ? { mode: "array", arr: createCausalMask(L, cache.offset, window) } : own;
|
|
51
|
+
};
|
|
52
|
+
const read = (row: Cache, k: MlxArray, v: MlxArray): AttentionRead => {
|
|
53
|
+
const cache = kvStorage(row);
|
|
54
|
+
const held = mask(cache, k.shape[2]!);
|
|
55
|
+
let keys: MlxArray, values: MlxArray;
|
|
56
|
+
try { [keys, values] = cache.updateAndFetch(k, v); }
|
|
57
|
+
catch (error) { held.arr?.dispose(); throw error; }
|
|
58
|
+
return {
|
|
59
|
+
attend: (q, scale) => softcapAttention(q, keys, values, held, scale, softcap),
|
|
60
|
+
dispose() { disposeResources(held.arr ? [keys, values, held.arr] : [keys, values]); },
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
return Object.freeze({ appendDecode: read, appendWindow: read });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** gemma2.py's manual attention: scale, the GQA 5-d reshape, q·kᵀ, the tanh
|
|
67
|
+
* softcap, a boolean mask through `where(mask, scores, finfo.min)`, the
|
|
68
|
+
* precise softmax, then ·v. `q` [B, Hq, L, D], `keys` [B, Hkv, S, D] and
|
|
69
|
+
* `values` [B, Hkv, S, Dv] are borrowed; only an array mask is applied. Returns
|
|
70
|
+
* an owned [B, Hq, L, Dv]. */
|
|
71
|
+
export function softcapAttention(q: MlxArray, keys: MlxArray, values: MlxArray, mask: Mask, scale: number,
|
|
72
|
+
softcap: number): MlxArray {
|
|
73
|
+
const [B, numHeads, L, headDim] = q.shape as [number, number, number, number];
|
|
74
|
+
const numKvHeads = keys.shape[1]!;
|
|
75
|
+
const repeats = Math.floor(numHeads / numKvHeads);
|
|
76
|
+
let queries = ops.mulScalar(q, scale); // queries * self.scale
|
|
77
|
+
|
|
78
|
+
let kk = keys;
|
|
79
|
+
let vv = values;
|
|
80
|
+
let kExp: MlxArray | null = null;
|
|
81
|
+
let vExp: MlxArray | null = null;
|
|
82
|
+
if (repeats > 1) {
|
|
83
|
+
queries = disposing(queries, ops.reshape(queries, [B, numKvHeads, repeats, L, headDim]));
|
|
84
|
+
kExp = ops.expandDims(keys, 2);
|
|
85
|
+
vExp = ops.expandDims(values, 2);
|
|
86
|
+
kk = kExp;
|
|
87
|
+
vv = vExp;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const kT = ops.transposeAxes(kk, repeats > 1 ? [0, 1, 2, 4, 3] : [0, 1, 3, 2]);
|
|
91
|
+
let scores = ops.matmul(queries, kT);
|
|
92
|
+
kT.dispose();
|
|
93
|
+
queries.dispose();
|
|
94
|
+
|
|
95
|
+
// tanh(scores / cap) * cap — same composition as logitSoftcap.
|
|
96
|
+
scores = disposing(scores, logitSoftcap(scores, softcap));
|
|
97
|
+
|
|
98
|
+
if (mask.mode === "array" && mask.arr) {
|
|
99
|
+
// bool mask: where(mask, scores, finfo(scores.dtype).min)
|
|
100
|
+
const minVal = FINFO_MIN[scores.dtype];
|
|
101
|
+
if (minVal === undefined) throw new Error(`no finfo.min for dtype ${scores.dtypeName}`);
|
|
102
|
+
const minArr = ops.scalarLike(minVal, scores);
|
|
103
|
+
// GQA scores are [B, Hkv, repeats, L, S]. Row masks carry B,
|
|
104
|
+
// unlike the ordinary [L, S] causal mask, so keep that axis aligned.
|
|
105
|
+
using rowMask = repeats > 1 && mask.arr.shape.length === 4
|
|
106
|
+
? ops.expandDims(mask.arr, 2) : null;
|
|
107
|
+
scores = disposing(scores, ops.where(rowMask ?? mask.arr, scores, minArr));
|
|
108
|
+
minArr.dispose();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
scores = disposing(scores, ops.softmaxAxis(scores, -1, true));
|
|
112
|
+
let out = ops.matmul(scores, vv);
|
|
113
|
+
scores.dispose();
|
|
114
|
+
kExp?.dispose();
|
|
115
|
+
vExp?.dispose();
|
|
116
|
+
if (repeats > 1) out = disposing(out, ops.reshape(out, [B, numHeads, L, values.shape[3]!]));
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import type { MLACache } from "../glm52-cache";
|
|
3
|
+
import { cloneAttachments } from "../checkpoint";
|
|
4
|
+
import { disposeResources } from "../../runtime/resources";
|
|
5
|
+
import { DRAFT_CHECKPOINT_SCHEMA, type DraftRowCheckpoint } from "../../contracts/mlx/draft-checkpoint";
|
|
6
|
+
|
|
7
|
+
export function captureGlm52MtpState(state: Glm52MtpRowState): DraftRowCheckpoint {
|
|
8
|
+
const held: MlxArray[] = [];
|
|
9
|
+
try {
|
|
10
|
+
if (state.cache.offset) {
|
|
11
|
+
const cache = state.cache.fetch(); held.push(cache.latent, cache.rope);
|
|
12
|
+
}
|
|
13
|
+
held.push(state.hidden.slice([0, 0, 0], [...state.hidden.shape]));
|
|
14
|
+
return { processedTokens: state.processedTokens, attachment: {
|
|
15
|
+
schema: DRAFT_CHECKPOINT_SCHEMA.glm52Mtp, metadata: { processedTokens: state.processedTokens, draftOffset: state.cache.offset },
|
|
16
|
+
tensors: held.splice(0),
|
|
17
|
+
} };
|
|
18
|
+
} finally { disposeResources(held); }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function restoreGlm52MtpState(checkpoint: DraftRowCheckpoint, makeCache: () => MLACache): Glm52MtpRowState {
|
|
22
|
+
const { attachment, processedTokens } = checkpoint;
|
|
23
|
+
if (attachment.schema !== DRAFT_CHECKPOINT_SCHEMA.glm52Mtp || attachment.metadata.processedTokens !== processedTokens)
|
|
24
|
+
throw new Error("invalid native GLM MTP checkpoint alignment");
|
|
25
|
+
const held = cloneAttachments([attachment])[0]!.tensors;
|
|
26
|
+
let cache: MLACache | null = makeCache();
|
|
27
|
+
try {
|
|
28
|
+
const offset = attachment.metadata.draftOffset as number;
|
|
29
|
+
if (offset) { cache.restoreCompressedState(held[0]!, held[1]!, null, offset); held.splice(0, 2); }
|
|
30
|
+
const state = { cache, hidden: held.pop()!, processedTokens }; cache = null; return state;
|
|
31
|
+
} finally { disposeResources([...held, ...(cache ? [cache] : [])]); }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface Glm52MtpRowState {
|
|
35
|
+
readonly cache: MLACache;
|
|
36
|
+
readonly hidden: MlxArray;
|
|
37
|
+
readonly processedTokens: number;
|
|
38
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
2
|
+
import { KVCache } from "../kv";
|
|
3
|
+
import { cloneAttachments } from "../checkpoint";
|
|
4
|
+
import { disposeResources } from "../../runtime/resources";
|
|
5
|
+
import { DRAFT_CHECKPOINT_SCHEMA, type DraftRowCheckpoint } from "../../contracts/mlx/draft-checkpoint";
|
|
6
|
+
|
|
7
|
+
/** The existing Qwen companion attachment is also the state interchange
|
|
8
|
+
* between prepared requests and a group. Storage-tier policy stays outside. */
|
|
9
|
+
export function restoreQwenMtpState(checkpoint: DraftRowCheckpoint): MtpRowState {
|
|
10
|
+
const { processedTokens: tokens, attachment } = checkpoint;
|
|
11
|
+
if (attachment.schema !== DRAFT_CHECKPOINT_SCHEMA.qwenMtp || attachment.metadata.draftOffset !== tokens - 1)
|
|
12
|
+
throw new Error("invalid paired Qwen MTP checkpoint alignment");
|
|
13
|
+
const held = cloneAttachments([attachment])[0]!.tensors;
|
|
14
|
+
let cache: KVCache | null = new KVCache();
|
|
15
|
+
try {
|
|
16
|
+
if (tokens > 1) { cache.restoreState(held[0]!, held[1]!, tokens - 1); held.splice(0, 2); }
|
|
17
|
+
const state = { cache, hidden: held.pop()! }; cache = null; return state;
|
|
18
|
+
} finally { disposeResources([...held, ...(cache ? [cache] : [])]); }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function captureQwenMtpState(state: MtpRowState): DraftRowCheckpoint {
|
|
22
|
+
const held: MlxArray[] = [];
|
|
23
|
+
try {
|
|
24
|
+
if (state.cache.offset > 0) held.push(...state.cache.temporalView());
|
|
25
|
+
held.push(state.hidden.slice([0, 0, 0], [...state.hidden.shape]));
|
|
26
|
+
return { processedTokens: state.cache.offset + 1,
|
|
27
|
+
attachment: { schema: DRAFT_CHECKPOINT_SCHEMA.qwenMtp, metadata: { draftOffset: state.cache.offset }, tensors: held.splice(0) } };
|
|
28
|
+
} finally { disposeResources(held); }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface MtpRowState {
|
|
32
|
+
readonly cache: KVCache;
|
|
33
|
+
readonly hidden: MlxArray;
|
|
34
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { rotatingSourcePosition } from "./rotating-kv-layout";
|
|
2
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
3
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
4
|
+
import { type AttentionRead, type Cache, type CommittedAttentionCache, type Mask, type PrefillPadding, type SpeculativeRowLayout } from "../contracts/mlx/cache";
|
|
5
|
+
import { RotatingKVCache } from "./rotating-kv";
|
|
6
|
+
import { BatchedRotatingCache } from "./batched-rotating";
|
|
7
|
+
import { rollbackRotatingRing } from "./rotating-row-transaction";
|
|
8
|
+
import { BatchedRotatingState } from "./batched-rotating-state";
|
|
9
|
+
import { plainRowStorage, temporalStorageView } from "./batched-row-storage";
|
|
10
|
+
import { disposeResources } from "../runtime/resources";
|
|
11
|
+
import { AttentionMasks, decodeByPosition } from "./attention-read";
|
|
12
|
+
|
|
13
|
+
/** Ring transactions retain accepted KV columns, including rounds that cross
|
|
14
|
+
* the window boundary. The verify block already retains the complete history
|
|
15
|
+
* needed by its earliest query; no target recomputation or scheduler policy.
|
|
16
|
+
* Reads are the current ring's (`BatchedRotatingCache`); every ring this layout
|
|
17
|
+
* builds shares its `masks`. */
|
|
18
|
+
export class SpeculativeRotatingKVCache implements CommittedAttentionCache, SpeculativeRowLayout {
|
|
19
|
+
#inner: BatchedRotatingCache;
|
|
20
|
+
#before?: number[];
|
|
21
|
+
constructor(
|
|
22
|
+
readonly maxSize: number,
|
|
23
|
+
/** The per-forward masks of the model this layout serves. */
|
|
24
|
+
readonly masks = new AttentionMasks(),
|
|
25
|
+
) { this.#inner = new BatchedRotatingCache(maxSize, [], masks); }
|
|
26
|
+
signature(): string { return "kv:rotating-plain"; }
|
|
27
|
+
get offset(): number { return this.#inner.offset; }
|
|
28
|
+
get rowOffsets(): readonly number[] { return this.#inner.offsetArr; }
|
|
29
|
+
get leftPad(): readonly number[] { return this.#inner.leftPad; }
|
|
30
|
+
get batchSize(): number { return this.#inner.batchSize; }
|
|
31
|
+
get ropeOffsetArr(): MlxArray { return this.#inner.ropeOffsetArr; }
|
|
32
|
+
makeEmptyBatch(): SpeculativeRotatingKVCache { return new SpeculativeRotatingKVCache(this.maxSize, this.masks); }
|
|
33
|
+
appendDecode(k: MlxArray, v: MlxArray): AttentionRead { return this.#inner.appendDecode(k, v); }
|
|
34
|
+
appendWindow(k: MlxArray, v: MlxArray): AttentionRead { return this.#inner.appendWindow(k, v); }
|
|
35
|
+
/** A committed span, one decode per position (`decodeByPosition`). */
|
|
36
|
+
appendCommitted(k: MlxArray, v: MlxArray): AttentionRead { return decodeByPosition(this, k, v); }
|
|
37
|
+
makeMask(tokens: number, window: number | null): Mask { return this.#inner.makeMask(tokens, window); }
|
|
38
|
+
updateAndFetch(k: MlxArray, v: MlxArray): [MlxArray, MlxArray] { return this.#inner.updateAndFetch(k, v); }
|
|
39
|
+
preparePrefill(padding: PrefillPadding): void { this.#inner.preparePrefill(padding); }
|
|
40
|
+
finalizePrefill(): void { this.#inner.finalizePrefill(); }
|
|
41
|
+
state(): MlxArray[] { return this.#inner.state(); }
|
|
42
|
+
isTrimmable(): boolean { return this.#inner.isTrimmable(); }
|
|
43
|
+
trim(count: number): void { this.#inner.trim(count); }
|
|
44
|
+
bytesPerToken(): number {
|
|
45
|
+
const state = this.state();
|
|
46
|
+
return state.length ? state.reduce((n, a) => n + a.nbytes, 0) / (this.batchSize * state[0]!.shape[2]!) : 0;
|
|
47
|
+
}
|
|
48
|
+
projectedBytes(tokens: number): number { return this.bytesPerToken() * Math.min(tokens, this.maxSize); }
|
|
49
|
+
extractRow(row: number): Cache {
|
|
50
|
+
const result = new RotatingKVCache(this.maxSize);
|
|
51
|
+
if (!this.rowOffsets[row] || !this.#inner.keys || !this.#inner.values) return result;
|
|
52
|
+
const position = new BatchedRotatingState(this.maxSize, []); position.restore(this.#inner.positionSnapshot);
|
|
53
|
+
const range = { row, from: Math.max(0, position.leftPad[row]!, position.activeLength - this.maxSize),
|
|
54
|
+
to: position.activeLength, copy: true };
|
|
55
|
+
const keys = temporalStorageView(plainRowStorage, this.#inner.keys, position, range);
|
|
56
|
+
let values: MlxArray;
|
|
57
|
+
try { values = temporalStorageView(plainRowStorage, this.#inner.values, position, range); }
|
|
58
|
+
catch (error) { keys.dispose(); throw error; }
|
|
59
|
+
result.restoreState(keys, values, this.rowOffsets[row]!, keys.shape[2]!); return result;
|
|
60
|
+
}
|
|
61
|
+
captureDonorRows(): import("../contracts/mlx/cache").KvDonorRows {
|
|
62
|
+
const position = new BatchedRotatingState(this.maxSize, []); position.restore(this.#inner.positionSnapshot);
|
|
63
|
+
const from = Math.max(0, position.activeLength - this.maxSize);
|
|
64
|
+
const range = { from, to: position.activeLength };
|
|
65
|
+
const keys = temporalStorageView(plainRowStorage, this.#inner.keys!, position, range); let values: MlxArray;
|
|
66
|
+
try { values = temporalStorageView(plainRowStorage, this.#inner.values!, position, range); }
|
|
67
|
+
catch (error) { keys.dispose(); throw error; }
|
|
68
|
+
return { keys, values, offsets: [...this.rowOffsets], starts: this.leftPad.map(pad => Math.max(0, pad - from)),
|
|
69
|
+
ends: this.rowOffsets.map(() => position.activeLength - from) };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
filterRows(keep: readonly number[]): void { this.#inner.filterRows(keep); }
|
|
73
|
+
mergeRows(sources: readonly Cache[]): void {
|
|
74
|
+
const only = sources.length === 1 ? sources[0] : undefined;
|
|
75
|
+
if (only instanceof SpeculativeRotatingKVCache) {
|
|
76
|
+
const keys = only.#inner.keys ? ops.copyOf(only.#inner.keys) : null;
|
|
77
|
+
let values: MlxArray | null;
|
|
78
|
+
try { values = only.#inner.values ? ops.copyOf(only.#inner.values) : null; }
|
|
79
|
+
catch (error) { keys?.dispose(); throw error; }
|
|
80
|
+
const next = BatchedRotatingCache.adoptPhysical(keys, values, only.#inner.positionSnapshot, this.masks);
|
|
81
|
+
this.#inner.dispose(); this.#inner = next; return;
|
|
82
|
+
}
|
|
83
|
+
const held: Cache[] = [], planes: { keys: MlxArray; values: MlxArray }[] = [], offsets: number[] = [];
|
|
84
|
+
try {
|
|
85
|
+
const rows = sources.flatMap(source => source instanceof SpeculativeRotatingKVCache
|
|
86
|
+
? Array.from({ length: source.batchSize }, (_, row) => { const cache = source.extractRow(row); held.push(cache); return cache; })
|
|
87
|
+
: [source]) as RotatingKVCache[];
|
|
88
|
+
const prototype = rows.find(row => row.keys !== null);
|
|
89
|
+
if (!prototype) {
|
|
90
|
+
this.#inner.dispose(); this.#inner = new BatchedRotatingCache(this.maxSize, rows.map(() => 0), this.masks); return;
|
|
91
|
+
}
|
|
92
|
+
for (const cache of rows) {
|
|
93
|
+
const state = rotatingSourcePosition(cache);
|
|
94
|
+
const range = { from: Math.max(0, state.activeLength - this.maxSize), to: state.activeLength };
|
|
95
|
+
const plane = (field: "keys" | "values") => cache[field]
|
|
96
|
+
? temporalStorageView(plainRowStorage, cache[field]!, state, range)
|
|
97
|
+
: ops.zeros([1, prototype[field]!.shape[1]!, 0, prototype[field]!.shape[3]!], prototype[field]!.dtype);
|
|
98
|
+
const keys = plane("keys"); let values: MlxArray;
|
|
99
|
+
try { values = plane("values"); } catch (error) { keys.dispose(); throw error; }
|
|
100
|
+
planes.push({ keys, values }); offsets.push(cache.offset);
|
|
101
|
+
}
|
|
102
|
+
const next = BatchedRotatingCache.merge(planes, offsets, this.maxSize, this.masks);
|
|
103
|
+
this.#inner.dispose(); this.#inner = next;
|
|
104
|
+
} finally { disposeResources([...held, ...planes.flatMap(row => [row.keys, row.values])]); }
|
|
105
|
+
}
|
|
106
|
+
specRoundBegin(): void { this.#before = [...this.rowOffsets]; }
|
|
107
|
+
specRoundCommit(): void { this.#before = undefined; }
|
|
108
|
+
specRoundRollback(keep: number | readonly number[]): void {
|
|
109
|
+
this.#inner = rollbackRotatingRing(this.#inner, this.#before!, keep);
|
|
110
|
+
this.#before = undefined;
|
|
111
|
+
}
|
|
112
|
+
dispose(): void { this.#before = undefined; this.#inner.dispose(); }
|
|
113
|
+
}
|