@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,601 @@
|
|
|
1
|
+
// GLM-5.2 DeepSeek Sparse Attention (DSA) correctness primitives.
|
|
2
|
+
//
|
|
3
|
+
// Projection/scoring has an MLX path for the model graph. The small host
|
|
4
|
+
// helpers are deliberately retained as the G2 correctness oracle and for the
|
|
5
|
+
// discrete threshold/tie decision, which Colibri itself performs on the CPU.
|
|
6
|
+
|
|
7
|
+
import { MlxArray } from "@mlx-bun/mlx/array";
|
|
8
|
+
import { positiveInteger } from "../../runtime/integers";
|
|
9
|
+
import { Dtype } from "@mlx-bun/mlx/ffi";
|
|
10
|
+
import { MetalKernel } from "@mlx-bun/mlx/metal-kernel";
|
|
11
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
12
|
+
import {
|
|
13
|
+
dsaScoresFromProjectedF32,
|
|
14
|
+
matvecF32,
|
|
15
|
+
partialInterleavedRopeF32,
|
|
16
|
+
selectDsaThresholdTiesF32,
|
|
17
|
+
type NumericVector,
|
|
18
|
+
type OutputMajorMatrix,
|
|
19
|
+
} from "./reference";
|
|
20
|
+
|
|
21
|
+
export interface Glm52DsaGeometry {
|
|
22
|
+
readonly numHeads: number;
|
|
23
|
+
readonly headDim: number;
|
|
24
|
+
/** GLM rotates only the first qk_rope_head_dim values of each index head. */
|
|
25
|
+
readonly rotaryDimensions: number;
|
|
26
|
+
readonly ropeTheta: number;
|
|
27
|
+
readonly topK: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface Glm52DsaProjectionWeights {
|
|
31
|
+
/** [numHeads * headDim, q_lora_rank] */
|
|
32
|
+
readonly query: OutputMajorMatrix;
|
|
33
|
+
/** [headDim, hidden_size] */
|
|
34
|
+
readonly key: OutputMajorMatrix;
|
|
35
|
+
/** [numHeads, hidden_size] */
|
|
36
|
+
readonly headWeights: OutputMajorMatrix;
|
|
37
|
+
/** Classical LayerNorm parameters for the projected index key. */
|
|
38
|
+
readonly keyNormWeight: NumericVector;
|
|
39
|
+
readonly keyNormBias: NumericVector;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface Glm52DsaProjectedQuery {
|
|
43
|
+
readonly heads: Float32Array[];
|
|
44
|
+
readonly headWeights: Float32Array;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Owned device result for one FULL-layer sparse selection. `positions` is the
|
|
49
|
+
* compact int32/uint32 buffer shared by the following SHARED layers; neither
|
|
50
|
+
* positions nor threshold is read back unless an explicit probe asks for it.
|
|
51
|
+
*/
|
|
52
|
+
export interface Glm52DsaDeviceSelection {
|
|
53
|
+
readonly contextLength: number;
|
|
54
|
+
readonly topK: number;
|
|
55
|
+
readonly positions: MlxArray;
|
|
56
|
+
readonly threshold: MlxArray;
|
|
57
|
+
dispose(): void;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type Glm52DsaLayerSelection =
|
|
61
|
+
| {
|
|
62
|
+
readonly mode: "dense";
|
|
63
|
+
readonly layer: number;
|
|
64
|
+
readonly ownerLayer: number;
|
|
65
|
+
readonly contextLength: number;
|
|
66
|
+
readonly positions: null;
|
|
67
|
+
readonly threshold: null;
|
|
68
|
+
}
|
|
69
|
+
| {
|
|
70
|
+
readonly mode: "sparse";
|
|
71
|
+
readonly layer: number;
|
|
72
|
+
readonly ownerLayer: number;
|
|
73
|
+
readonly contextLength: number;
|
|
74
|
+
readonly positions: readonly number[];
|
|
75
|
+
readonly threshold: number;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/** Debug/probe-only observer for selections computed by FULL indexer layers. */
|
|
79
|
+
export type Glm52DsaSelectionObserver = (
|
|
80
|
+
selection: Glm52DsaLayerSelection,
|
|
81
|
+
) => void;
|
|
82
|
+
|
|
83
|
+
function f32(value: number): number {
|
|
84
|
+
return Math.fround(value);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function nonNegativeInteger(value: number, label: string): number {
|
|
88
|
+
if (!Number.isSafeInteger(value) || value < 0)
|
|
89
|
+
throw new Error(`${label} must be a non-negative integer`);
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function validateGeometry(geometry: Glm52DsaGeometry): void {
|
|
94
|
+
positiveInteger(geometry.numHeads, "DSA numHeads");
|
|
95
|
+
positiveInteger(geometry.headDim, "DSA headDim");
|
|
96
|
+
positiveInteger(geometry.topK, "DSA topK");
|
|
97
|
+
if (
|
|
98
|
+
!Number.isSafeInteger(geometry.rotaryDimensions) ||
|
|
99
|
+
geometry.rotaryDimensions < 2 ||
|
|
100
|
+
(geometry.rotaryDimensions & 1) !== 0 ||
|
|
101
|
+
geometry.rotaryDimensions > geometry.headDim
|
|
102
|
+
) {
|
|
103
|
+
throw new Error("DSA rotaryDimensions must be even and within headDim");
|
|
104
|
+
}
|
|
105
|
+
if (!Number.isFinite(geometry.ropeTheta) || geometry.ropeTheta <= 0)
|
|
106
|
+
throw new Error("DSA ropeTheta must be finite and positive");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Colibri's index-key norm is ordinary LayerNorm, not RMSNorm. Reductions are
|
|
111
|
+
* accumulated in JS float64 just as Colibri accumulates them in C double; all
|
|
112
|
+
* stored/intermediate scalar operations are rounded back to float32.
|
|
113
|
+
*/
|
|
114
|
+
export function glm52DsaKeyLayerNormF32(
|
|
115
|
+
input: NumericVector,
|
|
116
|
+
weight: NumericVector,
|
|
117
|
+
bias: NumericVector,
|
|
118
|
+
epsilon = 1e-6,
|
|
119
|
+
): Float32Array {
|
|
120
|
+
positiveInteger(input.length, "DSA key length");
|
|
121
|
+
if (weight.length !== input.length || bias.length !== input.length)
|
|
122
|
+
throw new Error("DSA key LayerNorm parameters must match the key length");
|
|
123
|
+
if (!Number.isFinite(epsilon) || epsilon < 0)
|
|
124
|
+
throw new Error("DSA key LayerNorm epsilon must be finite and non-negative");
|
|
125
|
+
|
|
126
|
+
let mean = 0;
|
|
127
|
+
for (let index = 0; index < input.length; index++) {
|
|
128
|
+
const value = input[index]!;
|
|
129
|
+
if (!Number.isFinite(value)) throw new Error(`DSA key ${index} must be finite`);
|
|
130
|
+
mean += value;
|
|
131
|
+
}
|
|
132
|
+
mean /= input.length;
|
|
133
|
+
|
|
134
|
+
let variance = 0;
|
|
135
|
+
for (let index = 0; index < input.length; index++) {
|
|
136
|
+
const delta = input[index]! - mean;
|
|
137
|
+
variance += delta * delta;
|
|
138
|
+
}
|
|
139
|
+
variance /= input.length;
|
|
140
|
+
const inverseRoot = f32(1 / f32(Math.sqrt(f32(variance) + f32(epsilon))));
|
|
141
|
+
|
|
142
|
+
return Float32Array.from({ length: input.length }, (_, index) => {
|
|
143
|
+
const scale = weight[index]!;
|
|
144
|
+
const offset = bias[index]!;
|
|
145
|
+
if (!Number.isFinite(scale) || !Number.isFinite(offset))
|
|
146
|
+
throw new Error(`DSA key LayerNorm parameter ${index} must be finite`);
|
|
147
|
+
const centered = f32(input[index]! - mean);
|
|
148
|
+
return f32(f32(f32(centered * inverseRoot) * scale) + offset);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Project, normalize, and partially RoPE one index key. */
|
|
153
|
+
export function projectGlm52DsaKeyF32(
|
|
154
|
+
hidden: NumericVector,
|
|
155
|
+
position: number,
|
|
156
|
+
weights: Glm52DsaProjectionWeights,
|
|
157
|
+
geometry: Glm52DsaGeometry,
|
|
158
|
+
): Float32Array {
|
|
159
|
+
validateGeometry(geometry);
|
|
160
|
+
nonNegativeInteger(position, "DSA key position");
|
|
161
|
+
const projected = matvecF32(hidden, weights.key);
|
|
162
|
+
if (projected.length !== geometry.headDim)
|
|
163
|
+
throw new Error(`DSA key projection rows ${projected.length} != headDim ${geometry.headDim}`);
|
|
164
|
+
const normalized = glm52DsaKeyLayerNormF32(
|
|
165
|
+
projected,
|
|
166
|
+
weights.keyNormWeight,
|
|
167
|
+
weights.keyNormBias,
|
|
168
|
+
);
|
|
169
|
+
return partialInterleavedRopeF32(
|
|
170
|
+
normalized,
|
|
171
|
+
position,
|
|
172
|
+
geometry.rotaryDimensions,
|
|
173
|
+
geometry.ropeTheta,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Project and partially RoPE every query index head; project head weights. */
|
|
178
|
+
export function projectGlm52DsaQueryF32(
|
|
179
|
+
qLora: NumericVector,
|
|
180
|
+
hidden: NumericVector,
|
|
181
|
+
position: number,
|
|
182
|
+
weights: Glm52DsaProjectionWeights,
|
|
183
|
+
geometry: Glm52DsaGeometry,
|
|
184
|
+
): Glm52DsaProjectedQuery {
|
|
185
|
+
validateGeometry(geometry);
|
|
186
|
+
nonNegativeInteger(position, "DSA query position");
|
|
187
|
+
const flat = matvecF32(qLora, weights.query);
|
|
188
|
+
const expected = geometry.numHeads * geometry.headDim;
|
|
189
|
+
if (flat.length !== expected)
|
|
190
|
+
throw new Error(`DSA query projection rows ${flat.length} != ${expected}`);
|
|
191
|
+
|
|
192
|
+
const heads: Float32Array[] = [];
|
|
193
|
+
for (let head = 0; head < geometry.numHeads; head++) {
|
|
194
|
+
const start = head * geometry.headDim;
|
|
195
|
+
heads.push(partialInterleavedRopeF32(
|
|
196
|
+
flat.subarray(start, start + geometry.headDim),
|
|
197
|
+
position,
|
|
198
|
+
geometry.rotaryDimensions,
|
|
199
|
+
geometry.ropeTheta,
|
|
200
|
+
));
|
|
201
|
+
}
|
|
202
|
+
const headWeights = matvecF32(hidden, weights.headWeights);
|
|
203
|
+
if (headWeights.length !== geometry.numHeads)
|
|
204
|
+
throw new Error(
|
|
205
|
+
`DSA head-weight projection rows ${headWeights.length} != ${geometry.numHeads}`,
|
|
206
|
+
);
|
|
207
|
+
return { heads, headWeights };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* MLX data-plane score computation for already-projected tensors:
|
|
212
|
+
* queryHeads [H,D], keys [T,D], headWeights [H] -> scores [T].
|
|
213
|
+
*
|
|
214
|
+
* The threshold/tie decision remains a bounded host control-path operation;
|
|
215
|
+
* use Glm52DsaSelectionState after reading these scores.
|
|
216
|
+
*/
|
|
217
|
+
export function glm52DsaScoresMlx(
|
|
218
|
+
queryHeads: MlxArray,
|
|
219
|
+
keys: MlxArray,
|
|
220
|
+
headWeights: MlxArray,
|
|
221
|
+
): MlxArray {
|
|
222
|
+
const [heads, dimensions] = queryHeads.shape;
|
|
223
|
+
const [positions, keyDimensions] = keys.shape;
|
|
224
|
+
if (
|
|
225
|
+
queryHeads.ndim !== 2 ||
|
|
226
|
+
keys.ndim !== 2 ||
|
|
227
|
+
headWeights.ndim !== 1 ||
|
|
228
|
+
heads === undefined ||
|
|
229
|
+
dimensions === undefined ||
|
|
230
|
+
positions === undefined ||
|
|
231
|
+
keyDimensions === undefined ||
|
|
232
|
+
dimensions !== keyDimensions ||
|
|
233
|
+
headWeights.shape[0] !== heads
|
|
234
|
+
) {
|
|
235
|
+
throw new Error(
|
|
236
|
+
"DSA MLX scores require queryHeads [H,D], keys [T,D], and headWeights [H]",
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const queryF32 = queryHeads.dtype === Dtype.float32
|
|
241
|
+
? queryHeads
|
|
242
|
+
: queryHeads.astype(Dtype.float32);
|
|
243
|
+
const keysF32 = keys.dtype === Dtype.float32 ? keys : keys.astype(Dtype.float32);
|
|
244
|
+
const weightsF32 = headWeights.dtype === Dtype.float32
|
|
245
|
+
? headWeights
|
|
246
|
+
: headWeights.astype(Dtype.float32);
|
|
247
|
+
|
|
248
|
+
// [H,D] @ [D,T] -> [H,T]. MLX tiles the contraction internally, avoiding
|
|
249
|
+
// the correctness scaffold's materialized [H,T,D] broadcast product.
|
|
250
|
+
const keyTranspose = ops.transposeAxes(keysF32, [1, 0]);
|
|
251
|
+
let dots = ops.matmul(queryF32, keyTranspose);
|
|
252
|
+
keyTranspose.dispose();
|
|
253
|
+
dots = replaceDisposed(dots, ops.mulScalar(dots, 1 / Math.sqrt(dimensions)));
|
|
254
|
+
const zero = ops.scalarLike(0, dots);
|
|
255
|
+
const relu = ops.maximum(dots, zero);
|
|
256
|
+
dots.dispose();
|
|
257
|
+
zero.dispose();
|
|
258
|
+
const weights = ops.reshape(weightsF32, [heads, 1]);
|
|
259
|
+
const weighted = ops.mul(relu, weights);
|
|
260
|
+
relu.dispose();
|
|
261
|
+
weights.dispose();
|
|
262
|
+
let scores = ops.sumAxis(weighted, 0, false);
|
|
263
|
+
weighted.dispose();
|
|
264
|
+
scores = replaceDisposed(scores, ops.mulScalar(scores, 1 / Math.sqrt(heads)));
|
|
265
|
+
|
|
266
|
+
if (queryF32 !== queryHeads) queryF32.dispose();
|
|
267
|
+
if (keysF32 !== keys) keysF32.dispose();
|
|
268
|
+
if (weightsF32 !== headWeights) weightsF32.dispose();
|
|
269
|
+
return scores;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
let dsaRankKeyKernel: MetalKernel | null = null;
|
|
273
|
+
let dsaContractOrderKeyKernel: MetalKernel | null = null;
|
|
274
|
+
|
|
275
|
+
function getDsaRankKeyKernel(): MetalKernel {
|
|
276
|
+
if (!dsaRankKeyKernel) {
|
|
277
|
+
dsaRankKeyKernel = new MetalKernel({
|
|
278
|
+
name: "glm52_dsa_rank_key",
|
|
279
|
+
inputNames: ["scores"],
|
|
280
|
+
outputNames: ["keys"],
|
|
281
|
+
source: `
|
|
282
|
+
const uint i = thread_position_in_grid.x;
|
|
283
|
+
const float score = scores[i];
|
|
284
|
+
const uint bits = as_type<uint>(score);
|
|
285
|
+
const uint ascending = (bits & 0x80000000u) != 0u
|
|
286
|
+
? ~bits
|
|
287
|
+
: (bits ^ 0x80000000u);
|
|
288
|
+
const uint descending = ~ascending;
|
|
289
|
+
keys[i] = descending;
|
|
290
|
+
`,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
return dsaRankKeyKernel;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function getDsaContractOrderKeyKernel(): MetalKernel {
|
|
297
|
+
if (!dsaContractOrderKeyKernel) {
|
|
298
|
+
dsaContractOrderKeyKernel = new MetalKernel({
|
|
299
|
+
name: "glm52_dsa_contract_order_key",
|
|
300
|
+
inputNames: ["selected_scores", "selected_positions", "threshold"],
|
|
301
|
+
outputNames: ["keys"],
|
|
302
|
+
source: `
|
|
303
|
+
const uint i = thread_position_in_grid.x;
|
|
304
|
+
const uint position = selected_positions[i];
|
|
305
|
+
const uint threshold_class = selected_scores[i] > threshold ? 0u : 1u;
|
|
306
|
+
// MLX axis lengths are signed int32; positions leave the high bit free.
|
|
307
|
+
keys[i] = (threshold_class << 31) | position;
|
|
308
|
+
`,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
return dsaContractOrderKeyKernel;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Deterministic on-device equivalent of `selectDsaThresholdTiesF32`.
|
|
316
|
+
*
|
|
317
|
+
* Stable sorting of the first uint32 key orders scores descending and keeps
|
|
318
|
+
* equal-score positions ascending, including threshold ties. The second key
|
|
319
|
+
* restores Colibri's observable two-scan order: all scores strictly above the
|
|
320
|
+
* threshold in position order, followed by threshold ties in position order.
|
|
321
|
+
* The caller owns the returned arrays and must call `dispose()` once the last
|
|
322
|
+
* SHARED-layer consumer is done.
|
|
323
|
+
*/
|
|
324
|
+
export function selectGlm52DsaDevice(
|
|
325
|
+
scores: MlxArray,
|
|
326
|
+
topK: number,
|
|
327
|
+
): Glm52DsaDeviceSelection {
|
|
328
|
+
if (scores.ndim !== 1)
|
|
329
|
+
throw new Error("DSA device selection requires scores [context]");
|
|
330
|
+
const contextLength = positiveInteger(scores.shape[0]!, "DSA context length");
|
|
331
|
+
positiveInteger(topK, "DSA topK");
|
|
332
|
+
if (topK >= contextLength)
|
|
333
|
+
throw new Error("DSA device selection requires context length greater than topK");
|
|
334
|
+
|
|
335
|
+
const scoresF32 = scores.dtype === Dtype.float32
|
|
336
|
+
? scores
|
|
337
|
+
: scores.astype(Dtype.float32);
|
|
338
|
+
const [rankKeys] = getDsaRankKeyKernel().apply([scoresF32], {
|
|
339
|
+
outputs: [{ shape: [contextLength], dtype: Dtype.uint32 }],
|
|
340
|
+
grid: [contextLength, 1, 1],
|
|
341
|
+
threadGroup: [Math.min(256, contextLength), 1, 1],
|
|
342
|
+
});
|
|
343
|
+
// Stable argsort retains ascending positions for equal score bits, so the
|
|
344
|
+
// ranking key needs no position field. MLX 0.31.2's GPU argpartition also
|
|
345
|
+
// sorts fully, but does not promise this tie order in its public contract.
|
|
346
|
+
const rankedPositions = ops.argsortAxis(rankKeys!, 0);
|
|
347
|
+
const selectedUnordered = rankedPositions.slice([0], [topK]);
|
|
348
|
+
const selectedScores = ops.takeAlongAxis(scoresF32, selectedUnordered, 0);
|
|
349
|
+
const threshold = ops.minAxis(selectedScores, 0, false);
|
|
350
|
+
const [orderKeys] = getDsaContractOrderKeyKernel().apply(
|
|
351
|
+
[selectedScores, selectedUnordered, threshold],
|
|
352
|
+
{
|
|
353
|
+
outputs: [{ shape: [topK], dtype: Dtype.uint32 }],
|
|
354
|
+
grid: [topK, 1, 1],
|
|
355
|
+
threadGroup: [Math.min(256, topK), 1, 1],
|
|
356
|
+
},
|
|
357
|
+
);
|
|
358
|
+
const order = ops.argsortAxis(orderKeys!, 0);
|
|
359
|
+
const positions = ops.takeAlongAxis(selectedUnordered, order, 0);
|
|
360
|
+
|
|
361
|
+
rankKeys!.dispose();
|
|
362
|
+
rankedPositions.dispose();
|
|
363
|
+
selectedUnordered.dispose();
|
|
364
|
+
selectedScores.dispose();
|
|
365
|
+
orderKeys!.dispose();
|
|
366
|
+
order.dispose();
|
|
367
|
+
if (scoresF32 !== scores) scoresF32.dispose();
|
|
368
|
+
|
|
369
|
+
let disposed = false;
|
|
370
|
+
return {
|
|
371
|
+
contextLength,
|
|
372
|
+
topK,
|
|
373
|
+
positions,
|
|
374
|
+
threshold,
|
|
375
|
+
dispose(): void {
|
|
376
|
+
if (disposed) return;
|
|
377
|
+
disposed = true;
|
|
378
|
+
positions.dispose();
|
|
379
|
+
threshold.dispose();
|
|
380
|
+
},
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function replaceDisposed(oldValue: MlxArray, newValue: MlxArray): MlxArray {
|
|
385
|
+
oldValue.dispose();
|
|
386
|
+
return newValue;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Exact G2 host correctness path: float32 score accumulation followed by
|
|
391
|
+
* Colibri's threshold/tie selection. It is intentionally separate from the
|
|
392
|
+
* MLX score graph so cross-kernel reduction drift cannot hide contract bugs.
|
|
393
|
+
*/
|
|
394
|
+
export function scoreAndSelectGlm52DsaF32(
|
|
395
|
+
query: Glm52DsaProjectedQuery,
|
|
396
|
+
keys: OutputMajorMatrix,
|
|
397
|
+
topK: number,
|
|
398
|
+
): Glm52DsaLayerSelection {
|
|
399
|
+
const state = new Glm52DsaSelectionState(topK);
|
|
400
|
+
return state.selectFull(0, dsaScoresFromProjectedF32(query.heads, keys, query.headWeights));
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Carries Colibri's per-token latest-FULL selection across SHARED layers.
|
|
405
|
+
* A zero selection count is represented explicitly as `mode: "dense"`.
|
|
406
|
+
*/
|
|
407
|
+
export class Glm52DsaSelectionState {
|
|
408
|
+
readonly topK: number;
|
|
409
|
+
#latest: Glm52DsaLayerSelection | null = null;
|
|
410
|
+
#latestDevices: Array<{
|
|
411
|
+
readonly layer: number;
|
|
412
|
+
readonly row: number;
|
|
413
|
+
readonly contextLength: number;
|
|
414
|
+
/** The only buffer retained across FULL -> SHARED layers. */
|
|
415
|
+
readonly positions: MlxArray;
|
|
416
|
+
}> = [];
|
|
417
|
+
readonly #observer: Glm52DsaSelectionObserver | null;
|
|
418
|
+
|
|
419
|
+
constructor(
|
|
420
|
+
topK: number,
|
|
421
|
+
observer: Glm52DsaSelectionObserver | null = null,
|
|
422
|
+
) {
|
|
423
|
+
this.topK = positiveInteger(topK, "DSA topK");
|
|
424
|
+
this.#observer = observer;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
get latestFull(): Glm52DsaLayerSelection | null {
|
|
428
|
+
return this.#latest;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
reset(): void {
|
|
432
|
+
for (const device of this.#latestDevices) device.positions.dispose();
|
|
433
|
+
this.#latestDevices = [];
|
|
434
|
+
this.#latest = null;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
selectFull(layer: number, scores: NumericVector): Glm52DsaLayerSelection {
|
|
438
|
+
for (const device of this.#latestDevices) device.positions.dispose();
|
|
439
|
+
this.#latestDevices = [];
|
|
440
|
+
nonNegativeInteger(layer, "DSA layer");
|
|
441
|
+
positiveInteger(scores.length, "DSA context length");
|
|
442
|
+
let selection: Glm52DsaLayerSelection;
|
|
443
|
+
if (scores.length <= this.topK) {
|
|
444
|
+
// Exact Colibri dense fallback: dsa_nsel=0 until nk > index_topk.
|
|
445
|
+
selection = {
|
|
446
|
+
mode: "dense",
|
|
447
|
+
layer,
|
|
448
|
+
ownerLayer: layer,
|
|
449
|
+
contextLength: scores.length,
|
|
450
|
+
positions: null,
|
|
451
|
+
threshold: null,
|
|
452
|
+
};
|
|
453
|
+
} else {
|
|
454
|
+
const chosen = selectDsaThresholdTiesF32(scores, this.topK);
|
|
455
|
+
selection = {
|
|
456
|
+
mode: "sparse",
|
|
457
|
+
layer,
|
|
458
|
+
ownerLayer: layer,
|
|
459
|
+
contextLength: scores.length,
|
|
460
|
+
positions: chosen.selected,
|
|
461
|
+
threshold: chosen.threshold,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
this.#latest = selection;
|
|
465
|
+
if (this.#observer) {
|
|
466
|
+
this.#observer(selection.mode === "dense"
|
|
467
|
+
? { ...selection }
|
|
468
|
+
: { ...selection, positions: [...selection.positions] });
|
|
469
|
+
}
|
|
470
|
+
return selection;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Benchmark-only control for constructing a long KV/index-key context in a
|
|
475
|
+
* batched prefill without exercising the unfinished sparse-prefill path.
|
|
476
|
+
* Decode calls still use `selectFullDevice` once they append one token.
|
|
477
|
+
*/
|
|
478
|
+
selectFullDense(layer: number, contextLength: number): Glm52DsaLayerSelection {
|
|
479
|
+
for (const device of this.#latestDevices) device.positions.dispose();
|
|
480
|
+
this.#latestDevices = [];
|
|
481
|
+
nonNegativeInteger(layer, "DSA layer");
|
|
482
|
+
positiveInteger(contextLength, "DSA context length");
|
|
483
|
+
const selection: Glm52DsaLayerSelection = {
|
|
484
|
+
mode: "dense",
|
|
485
|
+
layer,
|
|
486
|
+
ownerLayer: layer,
|
|
487
|
+
contextLength,
|
|
488
|
+
positions: null,
|
|
489
|
+
threshold: null,
|
|
490
|
+
};
|
|
491
|
+
this.#latest = selection;
|
|
492
|
+
this.#observer?.({ ...selection });
|
|
493
|
+
return selection;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Production sparse path: keep the exact top-k and threshold on device and
|
|
498
|
+
* retain the compact position buffer for the following SHARED layers. A
|
|
499
|
+
* probe observer deliberately opts into the otherwise-absent host readback.
|
|
500
|
+
*/
|
|
501
|
+
selectFullDevice(layer: number, scores: MlxArray, row = 0): MlxArray {
|
|
502
|
+
nonNegativeInteger(layer, "DSA layer");
|
|
503
|
+
nonNegativeInteger(row, "DSA row");
|
|
504
|
+
const contextLength = positiveInteger(scores.shape[0]!, "DSA context length");
|
|
505
|
+
if (scores.ndim !== 1)
|
|
506
|
+
throw new Error("DSA device selection requires scores [context]");
|
|
507
|
+
if (contextLength <= this.topK)
|
|
508
|
+
throw new Error("DSA device selection requires sparse context");
|
|
509
|
+
|
|
510
|
+
const previousLayer = this.#latestDevices[0]?.layer;
|
|
511
|
+
if (previousLayer !== undefined && previousLayer !== layer) {
|
|
512
|
+
for (const previous of this.#latestDevices) previous.positions.dispose();
|
|
513
|
+
this.#latestDevices = [];
|
|
514
|
+
}
|
|
515
|
+
if (this.#latestDevices.some((entry) =>
|
|
516
|
+
entry.layer === layer && entry.row === row &&
|
|
517
|
+
entry.contextLength === contextLength
|
|
518
|
+
)) {
|
|
519
|
+
throw new Error(
|
|
520
|
+
`DSA full layer ${layer} already selected context ${contextLength}`,
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
const device = selectGlm52DsaDevice(scores, this.topK);
|
|
524
|
+
this.#latest = null;
|
|
525
|
+
|
|
526
|
+
try {
|
|
527
|
+
if (this.#observer) {
|
|
528
|
+
const host: Glm52DsaLayerSelection = {
|
|
529
|
+
mode: "sparse",
|
|
530
|
+
layer,
|
|
531
|
+
ownerLayer: layer,
|
|
532
|
+
contextLength,
|
|
533
|
+
positions: device.positions.toIntTokens(),
|
|
534
|
+
threshold: device.threshold.toFloat32()[0]!,
|
|
535
|
+
};
|
|
536
|
+
this.#latest = host;
|
|
537
|
+
this.#observer({ ...host, positions: [...host.positions] });
|
|
538
|
+
}
|
|
539
|
+
} catch (error) {
|
|
540
|
+
device.dispose();
|
|
541
|
+
throw error;
|
|
542
|
+
}
|
|
543
|
+
// Threshold is needed to construct/order positions and for optional probe
|
|
544
|
+
// readback only. Drop its wrapper now so state retains exactly one 8 KiB
|
|
545
|
+
// index buffer, not a second root into the score graph.
|
|
546
|
+
device.threshold.dispose();
|
|
547
|
+
this.#latestDevices.push({ layer, row, contextLength, positions: device.positions });
|
|
548
|
+
return device.positions;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/** Borrow the latest FULL selection without copying or re-uploading it. */
|
|
552
|
+
selectSharedPositions(
|
|
553
|
+
layer: number,
|
|
554
|
+
contextLength: number,
|
|
555
|
+
row = 0,
|
|
556
|
+
): MlxArray | null {
|
|
557
|
+
nonNegativeInteger(layer, "DSA layer");
|
|
558
|
+
nonNegativeInteger(row, "DSA row");
|
|
559
|
+
positiveInteger(contextLength, "DSA context length");
|
|
560
|
+
const device = this.#latestDevices.find(
|
|
561
|
+
(entry) => entry.row === row && entry.contextLength === contextLength,
|
|
562
|
+
);
|
|
563
|
+
if (device) {
|
|
564
|
+
return device.positions;
|
|
565
|
+
}
|
|
566
|
+
// A small verification batch may straddle the dense/sparse boundary. Its
|
|
567
|
+
// sparse rows have device buffers while the earlier rows remain dense by
|
|
568
|
+
// the model contract and therefore need no index vector.
|
|
569
|
+
if (contextLength <= this.topK) return null;
|
|
570
|
+
if (this.#latestDevices.length > 0) {
|
|
571
|
+
throw new Error(
|
|
572
|
+
`DSA shared context length ${contextLength} has no FULL selection`,
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
const host = this.selectShared(layer, contextLength);
|
|
576
|
+
if (host.mode === "sparse") {
|
|
577
|
+
throw new Error("host DSA selection cannot be reused as a device buffer");
|
|
578
|
+
}
|
|
579
|
+
return null;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
selectShared(layer: number, contextLength: number): Glm52DsaLayerSelection {
|
|
583
|
+
nonNegativeInteger(layer, "DSA layer");
|
|
584
|
+
positiveInteger(contextLength, "DSA context length");
|
|
585
|
+
const latest = this.#latest;
|
|
586
|
+
if (latest === null)
|
|
587
|
+
throw new Error("DSA shared layer has no preceding full-layer selection");
|
|
588
|
+
if (latest.contextLength !== contextLength) {
|
|
589
|
+
throw new Error(
|
|
590
|
+
`DSA shared context length ${contextLength} != latest full ${latest.contextLength}`,
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
return latest.mode === "dense"
|
|
594
|
+
? { ...latest, layer }
|
|
595
|
+
: { ...latest, layer, positions: [...latest.positions] };
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
dispose(): void {
|
|
599
|
+
this.reset();
|
|
600
|
+
}
|
|
601
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { renderGlm52Chat } from "../../input/chat-template";
|
|
2
|
+
import { L3, configuredMoe, defineFamily } from "../family";
|
|
3
|
+
|
|
4
|
+
/** GLM-5.2 Colibri architecture. Its dedicated MLA/DSA/shared-MoE graph is
|
|
5
|
+
* intentionally distinct from the universal dense `glm4` descriptor. */
|
|
6
|
+
export const GLM52_FAMILY = defineFamily({
|
|
7
|
+
graph: "glm5.2",
|
|
8
|
+
accepts: config => config.modelType === "glm_moe_dsa",
|
|
9
|
+
hasModelType: modelType => modelType === "glm_moe_dsa",
|
|
10
|
+
tier: "targeted",
|
|
11
|
+
label: "glm_moe_dsa",
|
|
12
|
+
loader: "colibri",
|
|
13
|
+
loop: "autoregressive",
|
|
14
|
+
fidelity: L3,
|
|
15
|
+
specialization: "dedicated",
|
|
16
|
+
profileId: "glm5.2-colibri",
|
|
17
|
+
capabilities: ["glm5.2-graph", "streamed-experts"],
|
|
18
|
+
moe: configuredMoe,
|
|
19
|
+
chatTemplateFallback: { render: renderGlm52Chat, thinkingFormat: "think-tag" },
|
|
20
|
+
});
|