@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,80 @@
|
|
|
1
|
+
/** Describes an implementation's ABI, not a claim of oracle parity or speed. */
|
|
2
|
+
export interface GraphDescriptor {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly backend: string;
|
|
5
|
+
readonly graphAbi: string;
|
|
6
|
+
readonly stateAbi: string;
|
|
7
|
+
readonly artifact: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** How prepared media reaches the graph.
|
|
11
|
+
* - `embeddings`: spliced prompt embeddings (image/audio soft tokens, optional
|
|
12
|
+
* bidirectional and multimodal masks) enter the ordinary forward.
|
|
13
|
+
* - `embeddings+positions`: spliced embeddings with request-owned multi-axis
|
|
14
|
+
* rotary positions and a decode delta.
|
|
15
|
+
* - `pixels`: raw image pixels are the denoising method's own prefill input. */
|
|
16
|
+
export type GraphMediaInput = "embeddings" | "embeddings+positions" | "pixels";
|
|
17
|
+
|
|
18
|
+
/** Portable facts about a bound graph. Composition binds the
|
|
19
|
+
* operations these facts require and refuses what is genuinely missing;
|
|
20
|
+
* scheduling reads only these declarations plus request and dynamic state
|
|
21
|
+
* (batch membership, cache contents, cancellation), never a model's class or
|
|
22
|
+
* name. A declaration that promises an operation is checked where it is bound. */
|
|
23
|
+
export interface GraphCapabilities {
|
|
24
|
+
/** The method the graph's forward serves. Token-level methods (speculation,
|
|
25
|
+
* grammar proposals, fill) bind only to `autoregressive`. */
|
|
26
|
+
readonly method: "autoregressive" | "denoising";
|
|
27
|
+
/** Prepared media the graph accepts, or null. Requests carrying prepared
|
|
28
|
+
* embeddings need a `bindMediaInput` operation; `video` says video frames
|
|
29
|
+
* are accepted input. */
|
|
30
|
+
readonly media: { readonly input: GraphMediaInput; readonly video: boolean } | null;
|
|
31
|
+
/** The graph owns a compiled decode step. The composition keeps it on only
|
|
32
|
+
* where its storage has a compiled form (`Composition.compiledDecode`). */
|
|
33
|
+
readonly compiledDecode: boolean;
|
|
34
|
+
/** Attention selects a sparse subset of positions (surfaced to clients). */
|
|
35
|
+
readonly sparseAttention: boolean;
|
|
36
|
+
/** Derived from the bound graph's pooled text-embedding operation. */
|
|
37
|
+
readonly embeddings: boolean;
|
|
38
|
+
/** Hidden-layer outputs can be tapped for drafts that read them. */
|
|
39
|
+
readonly hiddenLayerTaps: boolean;
|
|
40
|
+
/** A draft head the graph's own checkpoint carries and has loaded, or null.
|
|
41
|
+
* `kind` names the native draft provider that binds to this graph; the
|
|
42
|
+
* provider registry resolves it, so no consumer names the graph or its
|
|
43
|
+
* provider. `numDraftTokens` is the head's round width. */
|
|
44
|
+
readonly nativeDraft: { readonly kind: string; readonly numDraftTokens: number } | null;
|
|
45
|
+
/** How prefill is sized for this graph. */
|
|
46
|
+
readonly prefill: {
|
|
47
|
+
/** Long prompts prefill in smaller chunks so the attention score matrices
|
|
48
|
+
* a fallback (unfused) attention materializes stay within a fixed
|
|
49
|
+
* workspace. It changes work size, never admission. */
|
|
50
|
+
readonly boundedWorkspace: boolean;
|
|
51
|
+
};
|
|
52
|
+
/** What the graph's target verification qualifies beyond ordinary rounds.
|
|
53
|
+
* Each is a property of the graph's verifier, independent of the draft that
|
|
54
|
+
* supplies proposals and of how the composition's caches store keys and
|
|
55
|
+
* values (every cache lego holds the speculative transaction). */
|
|
56
|
+
readonly speculation: {
|
|
57
|
+
/** Verification under mounted adapters. */
|
|
58
|
+
readonly adapters: boolean;
|
|
59
|
+
/** Verification of requests that return logprobs. */
|
|
60
|
+
readonly logprobs: boolean;
|
|
61
|
+
/** Verification of externally supplied tokens (echo of a known continuation). */
|
|
62
|
+
readonly externalTokens: boolean;
|
|
63
|
+
/** Verified grammar-constraint proposals. */
|
|
64
|
+
readonly grammarProposals: boolean;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Facts supplied by a graph at construction. Pooled embedding support is the
|
|
69
|
+
* presence of its operation; only the bound portable description carries the
|
|
70
|
+
* derived boolean. `never` also rejects separately typed declaration objects
|
|
71
|
+
* that try to supply that flag. */
|
|
72
|
+
export type GraphDeclaration = Omit<GraphCapabilities, "embeddings"> & {
|
|
73
|
+
readonly embeddings?: never;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/** A fused InferenceMethod can bypass this graph interface entirely. It need
|
|
77
|
+
* only satisfy the method's output, cancellation, and ownership contracts. */
|
|
78
|
+
export interface GraphFactory<Artifact, Binding, Graph> {
|
|
79
|
+
open(artifact: Artifact, binding: Binding): Promise<{ graph: Graph; close(): Promise<void> }>;
|
|
80
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from "./composition";
|
|
2
|
+
export * from "./denoising";
|
|
3
|
+
export * from "./execution";
|
|
4
|
+
export * from "./generation";
|
|
5
|
+
export * from "./graph";
|
|
6
|
+
export * from "./memory-plan";
|
|
7
|
+
export * from "./object-cache";
|
|
8
|
+
export * from "./prefill";
|
|
9
|
+
export * from "./prefix-cache";
|
|
10
|
+
export * from "./prompt";
|
|
11
|
+
export * from "./resources";
|
|
12
|
+
export * from "./rollback";
|
|
13
|
+
export * from "./sampling";
|
|
14
|
+
export * from "./scheduling";
|
|
15
|
+
export * from "./token-delivery";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Common admission contract for every runtime. Representation-specific
|
|
2
|
+
* planners may expose richer fields, but serving consumes only this shape. */
|
|
3
|
+
export interface MemoryPlan {
|
|
4
|
+
readonly schemaVersion: 1;
|
|
5
|
+
/** Names the accounting the plan comes from; informational, never branched on. */
|
|
6
|
+
readonly strategy: string;
|
|
7
|
+
readonly fits: boolean;
|
|
8
|
+
readonly contextTokens: number;
|
|
9
|
+
readonly maxSafeContext: number;
|
|
10
|
+
readonly weightsBytes: number;
|
|
11
|
+
readonly kvBytes: number;
|
|
12
|
+
readonly transientBytes: number;
|
|
13
|
+
readonly reserveBytes: number;
|
|
14
|
+
readonly totalBytes: number;
|
|
15
|
+
readonly usableBytes: number;
|
|
16
|
+
readonly predictedDecodeTps: number | null;
|
|
17
|
+
/** mlx allocator-cache limit, distinct from the process admission limit. */
|
|
18
|
+
readonly allocatorLimitBytes?: number;
|
|
19
|
+
/** Generated-token allowance reserved within `contextTokens`; absent when the plan reserves none. */
|
|
20
|
+
readonly maxGenerationTokens?: number;
|
|
21
|
+
/** Parts of `weightsBytes` held in bounded streaming tiers instead of resident
|
|
22
|
+
* memory, by display label. Resident weights are `weightsBytes` minus their sum. */
|
|
23
|
+
readonly streamedWeights?: Readonly<Record<string, number>>;
|
|
24
|
+
/** RAM the plan leaves to the rest of the machine. */
|
|
25
|
+
readonly machineHeadroomBytes?: number;
|
|
26
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Exact reusable work, independent of token-prefix matching. The same cache
|
|
2
|
+
* owner chooses residency and persistence for objects and conversation state. */
|
|
3
|
+
export interface ObjectCache<Value> {
|
|
4
|
+
/** Borrow immutable data through an owned lease. A miss permits recompute. */
|
|
5
|
+
take(key: string): Promise<{ value: Value; dispose(): void } | null>;
|
|
6
|
+
/** Successful return transfers ownership, including immediate eviction. */
|
|
7
|
+
put(key: string, value: Value): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** Request-level chunk policy. Execution consumes the selected size; model
|
|
2
|
+
* backends can account for their temporary workspace without changing admission. */
|
|
3
|
+
export interface PrefillPolicy {
|
|
4
|
+
chunkSize(promptTokens: number): number;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface PrefillPosition {
|
|
8
|
+
readonly length: number;
|
|
9
|
+
readonly position: number;
|
|
10
|
+
readonly chunkSize: number;
|
|
11
|
+
readonly tailSplit: boolean;
|
|
12
|
+
readonly snapshotAt?: number | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** The phase a prompt step runs in, named by the planner that cut it: a whole
|
|
16
|
+
* planned `chunk` (exactly the step's chunk size), a `tail` (any other number
|
|
17
|
+
* of positions above one: what is left after the whole chunks, or a piece a
|
|
18
|
+
* snapshot boundary cuts short), or `decode`, a single position, which appends
|
|
19
|
+
* through the one-position read. */
|
|
20
|
+
export type PrefillPhase = "chunk" | "tail" | "decode";
|
|
21
|
+
|
|
22
|
+
export interface PrefillStep {
|
|
23
|
+
readonly start: number;
|
|
24
|
+
readonly end: number;
|
|
25
|
+
readonly kind: "drain" | "final";
|
|
26
|
+
readonly snapshot: boolean;
|
|
27
|
+
/** Batch admission may finish a short last drain and token zero in one tick.
|
|
28
|
+
* Otherwise execution yields between every drain and the next forward. */
|
|
29
|
+
readonly batchYield: boolean;
|
|
30
|
+
readonly phase: PrefillPhase;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The phase of a step the planner made `whole` (a full chunk) or not, from
|
|
34
|
+
* `start` to `end`. */
|
|
35
|
+
export function prefillPhase(start: number, end: number, whole: boolean): PrefillPhase {
|
|
36
|
+
return end - start === 1 ? "decode" : whole ? "chunk" : "tail";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The prefill program a row follows, alone or in a batch. No tensors, runtime policy reads,
|
|
40
|
+
* or sampling. Advance position only after executing the returned step. */
|
|
41
|
+
export function nextPrefillStep(input: PrefillPosition): PrefillStep {
|
|
42
|
+
const { length, position, chunkSize, tailSplit, snapshotAt } = input;
|
|
43
|
+
if (!Number.isSafeInteger(length) || !Number.isSafeInteger(position) ||
|
|
44
|
+
!Number.isSafeInteger(chunkSize) || chunkSize < 1 || position < 0 || position >= length)
|
|
45
|
+
throw new Error("invalid prefill position or chunk size");
|
|
46
|
+
if (snapshotAt != null && (!Number.isSafeInteger(snapshotAt) || snapshotAt < 0 || snapshotAt > length))
|
|
47
|
+
throw new Error("invalid prefill snapshot boundary");
|
|
48
|
+
if (snapshotAt != null && snapshotAt > position && snapshotAt < length) {
|
|
49
|
+
const whole = position + chunkSize <= snapshotAt;
|
|
50
|
+
const end = whole ? position + chunkSize : snapshotAt;
|
|
51
|
+
return { start: position, end, kind: "drain", snapshot: end === snapshotAt, batchYield: true,
|
|
52
|
+
phase: prefillPhase(position, end, whole) };
|
|
53
|
+
}
|
|
54
|
+
const remaining = length - position;
|
|
55
|
+
if (remaining > (tailSplit ? 1 : chunkSize)) {
|
|
56
|
+
const whole = !tailSplit || chunkSize <= remaining - 1;
|
|
57
|
+
const end = position + (whole ? chunkSize : remaining - 1);
|
|
58
|
+
return { start: position, end, kind: "drain", snapshot: false,
|
|
59
|
+
batchYield: !tailSplit || remaining - 1 > chunkSize, phase: prefillPhase(position, end, whole) };
|
|
60
|
+
}
|
|
61
|
+
return { start: position, end: length, kind: "final", snapshot: false, batchYield: false,
|
|
62
|
+
phase: prefillPhase(position, length, remaining === chunkSize) };
|
|
63
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** A reusable prefix and the backend/method state that covers its tokens.
|
|
2
|
+
* The caller owns a returned hit. After releasing or returning its state,
|
|
3
|
+
* it must release any retained backing through retain. */
|
|
4
|
+
export interface PrefixCacheHit<State, Attachment = never> {
|
|
5
|
+
tokens: number[];
|
|
6
|
+
caches: State;
|
|
7
|
+
attachments?: Attachment;
|
|
8
|
+
retain?: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Storage is independent of request scheduling and the method producing
|
|
12
|
+
* state. Both prefill and decode can publish processed-token prefixes.
|
|
13
|
+
* State is opaque here; its backend/method defines layout and alignment.
|
|
14
|
+
* Implementations own prefix selection, retention and storage tiers. */
|
|
15
|
+
export interface PrefixCache<State, Attachment = never> {
|
|
16
|
+
/** Give optional retained state back to the allocator at an execution
|
|
17
|
+
* boundary. This never rejects or changes the active request. */
|
|
18
|
+
reclaim?(): void;
|
|
19
|
+
/** Drop session affinity without deleting reusable checkpoints. */
|
|
20
|
+
closeSession?(sessionId: string): void;
|
|
21
|
+
/** Prepare a reusable prefix before execution. The returned release ends
|
|
22
|
+
* request interest; cache residency and IO remain implementation-owned. */
|
|
23
|
+
prefetch?(prompt: number[], ns?: string, sessionId?: string): Promise<() => void>;
|
|
24
|
+
/** Return owned state for a usable session continuation, otherwise the
|
|
25
|
+
* longest usable prefix, or null on a miss. Session identity is an affinity
|
|
26
|
+
* hint and never changes the content or numerical namespace.
|
|
27
|
+
* Namespace distinguishes incompatible artifacts, methods and adapters. */
|
|
28
|
+
take(prompt: number[], ns?: string, sessionId?: string): PrefixCacheHit<State, Attachment> | null;
|
|
29
|
+
/** Transfer state and its optional backing release to storage. If this
|
|
30
|
+
* throws, ownership stays with the caller; successful return transfers
|
|
31
|
+
* ownership even when storage immediately spills or disposes the entry. */
|
|
32
|
+
put(tokens: number[], caches: State, ns?: string, retain?: () => void, attachments?: Attachment, sessionId?: string): void;
|
|
33
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** A single owner. Borrowing does not extend lifetime; transfer invalidates
|
|
2
|
+
* the old owner. close is idempotent, including when release throws. */
|
|
3
|
+
export interface ResourceOwner<T> {
|
|
4
|
+
borrow(): T;
|
|
5
|
+
transfer(): T;
|
|
6
|
+
close(): void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** State views may own temporary handles or borrow live state. Consumers
|
|
10
|
+
* always close the lease; only the provider knows which handles to release. */
|
|
11
|
+
export interface StateView<T> {
|
|
12
|
+
borrow(): readonly T[];
|
|
13
|
+
close(): void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface DisposableResource {
|
|
17
|
+
dispose(): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** A prepared replacement for live state. Commit once between method rounds;
|
|
21
|
+
* it publishes already-built state without graph work or validation. Dispose
|
|
22
|
+
* releases the unpublished replacement, or the superseded state after commit. */
|
|
23
|
+
export interface PreparedStateChange extends DisposableResource {
|
|
24
|
+
commit(): void;
|
|
25
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** A complete transaction over every participating target state layer.
|
|
2
|
+
* A failed begin/resolve invalidates the run; its state must be discarded. */
|
|
3
|
+
export interface SpeculativeTransaction<Acceptance = number> {
|
|
4
|
+
canBegin(drafts: number): boolean;
|
|
5
|
+
begin(drafts: number): void;
|
|
6
|
+
resolve(accepted: Acceptance): void;
|
|
7
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Sampling owns score processing, token selection, and request-local history.
|
|
2
|
+
* Score/token representations and sync/device execution belong to the backend;
|
|
3
|
+
* this contract has no scheduling, cache, or tensor-runtime dependency. */
|
|
4
|
+
export interface SampledToken<Token, Metadata> {
|
|
5
|
+
token: Token;
|
|
6
|
+
extras: Metadata | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface SamplingSession<Scores, DeviceToken, Result> {
|
|
10
|
+
/** Optional stateless operation shared across compatible rows and positions.
|
|
11
|
+
* It borrows scores and returns owned device tokens, without advancing history. */
|
|
12
|
+
readonly independent?: { sample(scores: Scores): DeviceToken };
|
|
13
|
+
/** Optional per-position operation for ONE request whose selection depends on
|
|
14
|
+
* no grammar or probability capture: position p's draw depends only on its
|
|
15
|
+
* scores, its step and its processor history. Borrows [N,V] scores and returns
|
|
16
|
+
* owned device tokens [N] for the given steps, without advancing history.
|
|
17
|
+
* A request with processor history (`needsHistory`) also passes the window's
|
|
18
|
+
* inputs [N] (borrowed: the pending token, then the drafts): position p reads
|
|
19
|
+
* its history extended by inputs[1..p], the history sample() would hold there
|
|
20
|
+
* had every earlier position drawn its draft. Draws are those sample() would
|
|
21
|
+
* make at each step: seeded sampling keys by (seed, step), never by a shared
|
|
22
|
+
* stream, so unused positions cost nothing. `commit` takes the tokens a walk
|
|
23
|
+
* over the window used, in order, and advances history as sample() would have
|
|
24
|
+
* advanced it drawing each. */
|
|
25
|
+
readonly positional?: {
|
|
26
|
+
sample(scores: Scores, steps: readonly number[], inputs?: DeviceToken): DeviceToken;
|
|
27
|
+
commit(tokens: readonly number[]): void;
|
|
28
|
+
};
|
|
29
|
+
/** Optional draw left on the device for a request whose selection depends on
|
|
30
|
+
* its processor history but on no grammar or probability capture: borrows
|
|
31
|
+
* [1,V] scores and returns the owned device token sample() would draw at
|
|
32
|
+
* `step`, committing it to history unread when sample() would commit it. */
|
|
33
|
+
readonly unread?: { sample(scores: Scores, step: number): DeviceToken };
|
|
34
|
+
readonly isPlainGreedy: boolean;
|
|
35
|
+
readonly capturesLogprobs: boolean;
|
|
36
|
+
readonly needsHistory: boolean;
|
|
37
|
+
/** Borrows scores; transfers ownership of the result to the caller. */
|
|
38
|
+
sample(logits: Scores, step: number): Result;
|
|
39
|
+
seedHistory(tokens: readonly number[]): void;
|
|
40
|
+
/** Commit accepted tokens when configured for manual history updates. */
|
|
41
|
+
commitDevice(token: DeviceToken): void;
|
|
42
|
+
commitNumbers(tokens: readonly number[]): void;
|
|
43
|
+
dispose(): void;
|
|
44
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** Backend-owned context shared by compatible requests. A key identifies
|
|
2
|
+
* equivalent execution state; enter returns its scoped release. Scheduling
|
|
3
|
+
* observes group readiness without inspecting this context. */
|
|
4
|
+
export interface ExecutionContext {
|
|
5
|
+
readonly key: string;
|
|
6
|
+
enter(): () => void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** A backend execution group exposes bounded work units and readiness. Queue
|
|
10
|
+
* payloads, tensors, cache merging and sampling remain inside its adapter. */
|
|
11
|
+
export interface ExecutionGroup {
|
|
12
|
+
/** Native preparation may borrow the execution lease between work units.
|
|
13
|
+
* Payloads and task failures belong to the backend's queue. */
|
|
14
|
+
readonly pendingTasks?: number;
|
|
15
|
+
advanceTask?(): Promise<void>;
|
|
16
|
+
readonly active: number;
|
|
17
|
+
readonly queued: number;
|
|
18
|
+
readonly preparing: boolean;
|
|
19
|
+
readonly preparingRows?: number;
|
|
20
|
+
/** The preparation owner can accept another row before its next work unit. */
|
|
21
|
+
readonly canPrepareMore?: boolean;
|
|
22
|
+
/** Work estimates affect grouping only. A request larger than this budget
|
|
23
|
+
* still runs alone; it is never rejected or sent to another executor. */
|
|
24
|
+
readonly preparingTokens?: number;
|
|
25
|
+
readonly nextPreparationTokens?: number;
|
|
26
|
+
readonly maxPreparationTokens?: number;
|
|
27
|
+
/** The latest preparation published output that can be flushed by yielding. */
|
|
28
|
+
readonly preparationPublishedOutput?: boolean;
|
|
29
|
+
readonly maxActive: number;
|
|
30
|
+
readonly admissionHeld: boolean;
|
|
31
|
+
readonly closed: boolean;
|
|
32
|
+
pruneCancelled(): void;
|
|
33
|
+
/** May reject/remove an impossible queued request before returning false. */
|
|
34
|
+
admitNext(): boolean;
|
|
35
|
+
/** Read-only budget check used to preserve admission before decode. */
|
|
36
|
+
canBurst(): boolean;
|
|
37
|
+
/** Method-owned token demand for a compatible mixed iteration. Absent when
|
|
38
|
+
* the backend has no packed implementation for the current work. */
|
|
39
|
+
readonly mixedPreparation?: { readonly runningTokens: number; readonly minimumPreparationTokens: number };
|
|
40
|
+
readonly maxIterationTokens?: number;
|
|
41
|
+
advanceMixed?(tokenBudget: number): Promise<void>;
|
|
42
|
+
advancePreparation(): Promise<void>;
|
|
43
|
+
advance(): Promise<void>;
|
|
44
|
+
failActive(error: unknown): void;
|
|
45
|
+
failAll(error: unknown): void;
|
|
46
|
+
reserveResidency(): () => void;
|
|
47
|
+
acquireExecution?(): Promise<() => void>;
|
|
48
|
+
waitForWork(): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface SchedulingClock {
|
|
52
|
+
now(): number;
|
|
53
|
+
yield(): Promise<void>;
|
|
54
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["ES2022"],
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"module": "Preserve",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"types": [],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"skipLibCheck": false,
|
|
10
|
+
"noUncheckedIndexedAccess": true,
|
|
11
|
+
"noEmit": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["./*.ts"]
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./text";
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Text-embedding entry point. Wraps a graph's `embedPooled` (last-token hidden,
|
|
2
|
+
// L2-normalized vector) with the input convention its profile declares, so the
|
|
3
|
+
// CLI (`mlx-bun embed`), the server (`/v1/embeddings`), and in-repo experiments
|
|
4
|
+
// all produce the SAME vectors — the ones verified bit-exact vs mlx-lm and main in
|
|
5
|
+
// tests/parity/embedding-parity.test.ts (opt-in) for the Qwen3-Embedding backbone.
|
|
6
|
+
|
|
7
|
+
import type { MlxArray } from "@mlx-bun/mlx/array";
|
|
8
|
+
import { declaredGraph } from "../models/capabilities";
|
|
9
|
+
import type { LoadedTokenizer } from "../input/tokenizer";
|
|
10
|
+
import * as ops from "@mlx-bun/mlx/ops";
|
|
11
|
+
|
|
12
|
+
/** The operation behind a graph's `embeddings` capability. */
|
|
13
|
+
export interface EmbeddingGraph { embedPooled(ids: MlxArray): MlxArray }
|
|
14
|
+
|
|
15
|
+
/** A graph declares the pooled-embedding path. */
|
|
16
|
+
export function isEmbeddingModel(model: object): model is EmbeddingGraph {
|
|
17
|
+
return typeof declaredGraph(model).embedPooled === "function";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** The token id of the profile's declared pooling terminator in this tokenizer. */
|
|
21
|
+
export function embeddingTerminatorId(tok: Pick<LoadedTokenizer, "encode">, terminator: string): number {
|
|
22
|
+
const ids = tok.encode(terminator, false);
|
|
23
|
+
if (ids.length !== 1) throw new Error(`embedding terminator ${JSON.stringify(terminator)} is not a single token in this tokenizer`);
|
|
24
|
+
return ids[0]!;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Qwen3-Embedding query format: a task instruction steers WHICH similarity axis
|
|
28
|
+
* the geometry reflects ("represent this for topic routing" vs "...for
|
|
29
|
+
* sentiment"). Documents are embedded raw; only queries get an instruction. */
|
|
30
|
+
export function withInstruction(text: string, instruction?: string): string {
|
|
31
|
+
return instruction ? `Instruct: ${instruction}\nQuery:${text}` : text;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Tripwire: counts embedOne invocations (embedMany accrues via embedOne) so
|
|
35
|
+
* callers can assert the pipeline embeds exactly as many times as expected. */
|
|
36
|
+
let embedCallCount = 0;
|
|
37
|
+
|
|
38
|
+
/** Reset the embed tripwire counter to 0. */
|
|
39
|
+
export function resetEmbedCounter(): void {
|
|
40
|
+
embedCallCount = 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Read the embed tripwire counter (total embedOne calls since last reset). */
|
|
44
|
+
export function getEmbedCounter(): number {
|
|
45
|
+
return embedCallCount;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface EmbedResult {
|
|
49
|
+
/** L2-normalized embedding (length = model hidden size). */
|
|
50
|
+
vector: Float32Array;
|
|
51
|
+
/** Token count of the embedded input (incl. the pooling token). */
|
|
52
|
+
tokens: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Embed one text. `terminator` is the pooling token id from
|
|
56
|
+
* `embeddingTerminatorId`; `instruction` (optional) applies the query format. */
|
|
57
|
+
export function embedOne(
|
|
58
|
+
model: EmbeddingGraph,
|
|
59
|
+
tok: LoadedTokenizer,
|
|
60
|
+
terminator: number,
|
|
61
|
+
text: string,
|
|
62
|
+
instruction?: string,
|
|
63
|
+
): EmbedResult {
|
|
64
|
+
embedCallCount++;
|
|
65
|
+
// addSpecialTokens=false matches the bit-exact parity path (no BOS;
|
|
66
|
+
// we append the pooling token ourselves).
|
|
67
|
+
const ids = [...tok.encode(withInstruction(text, instruction), false), terminator];
|
|
68
|
+
const idArr = ops.fromInt32(ids, [1, ids.length]);
|
|
69
|
+
const vec = model.embedPooled(idArr);
|
|
70
|
+
idArr.dispose();
|
|
71
|
+
const out = vec.toFloat32();
|
|
72
|
+
vec.dispose();
|
|
73
|
+
return { vector: out, tokens: ids.length };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Embed many texts (one forward each — the runtime is single-sequence). */
|
|
77
|
+
export function embedMany(
|
|
78
|
+
model: EmbeddingGraph,
|
|
79
|
+
tok: LoadedTokenizer,
|
|
80
|
+
terminator: number,
|
|
81
|
+
texts: string[],
|
|
82
|
+
instruction?: string,
|
|
83
|
+
): EmbedResult[] {
|
|
84
|
+
return texts.map((t) => embedOne(model, tok, terminator, t, instruction));
|
|
85
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Cancellation } from "../contracts/portable/generation";
|
|
2
|
+
import type { DisposableResource } from "../contracts/portable/resources";
|
|
3
|
+
import { throwIfCancelled } from "./cancellation";
|
|
4
|
+
|
|
5
|
+
export class AdmissionRejected extends Error {
|
|
6
|
+
constructor() { super("admission queue is full"); this.name = "AdmissionRejected"; }
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** FIFO reservations. A cancelled waiter releases no active owner's capacity. */
|
|
10
|
+
export class AdmissionPool {
|
|
11
|
+
#active = 0;
|
|
12
|
+
#closed = false;
|
|
13
|
+
#waiting: Array<{ resolve(lease: DisposableResource): void; reject(error: unknown): void; unsubscribe(): void }> = [];
|
|
14
|
+
constructor(readonly capacity: number, readonly maxQueued = 64) {
|
|
15
|
+
if (!Number.isSafeInteger(capacity) || capacity < 1 || !Number.isSafeInteger(maxQueued) || maxQueued < 0)
|
|
16
|
+
throw new Error("invalid admission capacity");
|
|
17
|
+
}
|
|
18
|
+
get active(): number { return this.#active; }
|
|
19
|
+
get queued(): number { return this.#waiting.length; }
|
|
20
|
+
|
|
21
|
+
acquire(cancellation?: Cancellation): Promise<DisposableResource> {
|
|
22
|
+
if (this.#closed) return Promise.reject(new Error("admission is closed"));
|
|
23
|
+
try { if (cancellation) throwIfCancelled(cancellation); }
|
|
24
|
+
catch (error) { return Promise.reject(error); }
|
|
25
|
+
if (this.#active < this.capacity) return Promise.resolve(this.#lease());
|
|
26
|
+
if (this.#waiting.length >= this.maxQueued) return Promise.reject(new AdmissionRejected());
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
const waiter = { resolve, reject, unsubscribe() {} };
|
|
29
|
+
this.#waiting.push(waiter);
|
|
30
|
+
waiter.unsubscribe = cancellation?.subscribe((reason) => {
|
|
31
|
+
const index = this.#waiting.indexOf(waiter);
|
|
32
|
+
if (index < 0) return;
|
|
33
|
+
this.#waiting.splice(index, 1);
|
|
34
|
+
waiter.unsubscribe();
|
|
35
|
+
reject(new Error(`admission cancelled: ${reason}`));
|
|
36
|
+
}) ?? (() => {});
|
|
37
|
+
if (!this.#waiting.includes(waiter)) waiter.unsubscribe();
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
#lease(): DisposableResource {
|
|
42
|
+
this.#active++;
|
|
43
|
+
let released = false;
|
|
44
|
+
return { dispose: () => {
|
|
45
|
+
if (released) return;
|
|
46
|
+
released = true;
|
|
47
|
+
this.#active--;
|
|
48
|
+
const next = this.#waiting.shift();
|
|
49
|
+
if (next) { next.unsubscribe(); next.resolve(this.#lease()); }
|
|
50
|
+
} };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
close(): void {
|
|
54
|
+
this.#closed = true;
|
|
55
|
+
for (const waiter of this.#waiting.splice(0)) {
|
|
56
|
+
waiter.unsubscribe(); waiter.reject(new Error("admission is closed"));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|