mlx-bun 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -588
- package/docs/README.md +91 -0
- package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
- package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
- package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
- package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
- package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
- package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
- package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
- package/docs/design/batching.md +569 -0
- package/docs/design/decode-speed-program.md +3178 -169
- package/docs/design/dreaming-nightly-pipeline.md +675 -282
- package/docs/design/generic-model-support.md +579 -334
- package/docs/design/kv-cache.md +680 -0
- package/docs/design/orpo-training.md +673 -1239
- package/docs/design/speculative-decoding.md +1627 -0
- package/docs/design/turboquant.md +2102 -0
- package/docs/design/unified-engine-frontier-plan.md +1831 -727
- package/docs/design/web-chat-redesign.md +666 -1083
- package/docs/planning/PRODUCT_ROADMAP.md +34 -1
- package/docs/planning/release-notes-v0.3.0.md +35 -0
- package/docs/planning/video-series.md +2 -2
- package/docs/reference/benchmarks.md +1162 -0
- package/docs/reference/cli.md +394 -159
- package/docs/reference/distribution.md +321 -182
- package/docs/reference/environment.md +348 -0
- package/docs/reference/glossary.md +39 -0
- package/docs/reference/library-api.md +566 -168
- package/docs/reference/memory.md +227 -64
- package/docs/reference/models.md +104 -6
- package/docs/reference/server-api.md +886 -425
- package/docs/reference/server-config.md +638 -330
- package/docs/reference/training.md +393 -254
- package/docs/reference/troubleshooting.md +166 -0
- package/package.json +9 -4
- package/src/audio/decode.ts +2 -2
- package/src/audio/features.ts +2 -2
- package/src/backends/mlx/autoregressive.ts +108 -0
- package/src/backends/mlx/batch-group.ts +1646 -0
- package/src/backends/mlx/diffusion.ts +39 -0
- package/src/backends/mlx/draft-target.ts +47 -0
- package/src/backends/mlx/evaluation.ts +105 -0
- package/src/backends/mlx/fill-append.ts +45 -0
- package/src/backends/mlx/gateway-binding.ts +71 -0
- package/src/backends/mlx/graph.ts +38 -0
- package/src/backends/mlx/memory-client.ts +189 -0
- package/src/backends/mlx/memory-guard.ts +40 -0
- package/src/backends/mlx/methods.ts +90 -0
- package/src/backends/mlx/model-prompt.ts +164 -0
- package/src/backends/mlx/model-serving.ts +79 -0
- package/src/backends/mlx/prefill.ts +33 -0
- package/src/backends/mlx/request-policy.ts +20 -0
- package/src/backends/mlx/rollback.ts +51 -0
- package/src/backends/mlx/serial-executor.ts +273 -0
- package/src/backends/mlx/speculative.ts +114 -0
- package/src/backends/mlx/state-views.ts +26 -0
- package/src/backends/mlx/text-engine.ts +73 -0
- package/src/cli.ts +58 -25
- package/src/client.ts +66 -0
- package/src/config.ts +21 -4
- package/src/contracts/completion.ts +16 -0
- package/src/contracts/execution.ts +49 -0
- package/src/contracts/generation.ts +103 -0
- package/src/contracts/host.ts +7 -0
- package/src/contracts/jobs.ts +66 -0
- package/src/contracts/pi-provider.ts +30 -0
- package/src/contracts/pi.ts +259 -0
- package/src/contracts/resources.ts +18 -0
- package/src/contracts/scheduling.ts +27 -0
- package/src/contracts/tsconfig.json +14 -0
- package/src/diffusion/diffusion-generate.ts +218 -153
- package/src/embed.ts +1 -1
- package/src/engine/admission.ts +59 -0
- package/src/engine/cancellation.ts +38 -0
- package/src/engine/engine.ts +56 -0
- package/src/engine/execution-coordinator.ts +70 -0
- package/src/engine/execution-plan.ts +51 -0
- package/src/engine/resources.ts +42 -0
- package/src/engine/scheduler.ts +67 -0
- package/src/engine/session.ts +247 -0
- package/src/eval/README.md +44 -1
- package/src/eval/kl.ts +236 -3
- package/src/eval/reference-logits.ts +207 -0
- package/src/eval/runner.ts +8 -96
- package/src/fill/echo-index.ts +188 -0
- package/src/fill/fill-session.ts +452 -0
- package/src/fill/proposal.ts +68 -0
- package/src/fill/schema-rows.ts +506 -0
- package/src/fill/tool-boundary.ts +103 -0
- package/src/fit.ts +1 -1
- package/src/generate.ts +656 -268
- package/src/grammar.ts +12 -7
- package/src/harness-pi.ts +14 -33
- package/src/hub-rest.ts +4 -4
- package/src/index.ts +7 -0
- package/src/inference/denoising.ts +17 -0
- package/src/inference/graph.ts +33 -0
- package/src/inference/prefill.ts +39 -0
- package/src/inference/rollback.ts +7 -0
- package/src/jobs/db.ts +4 -0
- package/src/jobs/index.ts +2 -0
- package/src/jobs/job-entry.ts +12 -12
- package/src/jobs/runner.ts +98 -13
- package/src/jobs/task-client.ts +19 -0
- package/src/jobs/types.ts +2 -58
- package/src/kv-store.ts +109 -49
- package/src/lab/README.md +18 -0
- package/src/{assets → lab/curve}/curve-designer.html +2 -2
- package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
- package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +5 -5
- package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
- package/src/library.ts +40 -0
- package/src/lora.ts +18 -0
- package/src/media-fetch.ts +1 -1
- package/src/memory/article.ts +1 -1
- package/src/memory/chunk.ts +1 -1
- package/src/memory/model.ts +30 -169
- package/src/memory/prompts.ts +1 -1
- package/src/memory/rest.ts +1 -1
- package/src/memory/schedule.ts +1 -1
- package/src/memory/stages.ts +4 -1
- package/src/memory/vault.ts +1 -3
- package/src/mlx/array.ts +9 -10
- package/src/mlx/compile.ts +12 -2
- package/src/mlx/ffi.ts +58 -11
- package/src/mlx/materialize.ts +23 -0
- package/src/mlx/metal-kernel.ts +10 -11
- package/src/mlx/ops.ts +33 -13
- package/src/mlx/quantized-rows.ts +36 -0
- package/src/mlx/token-bitmask.ts +52 -0
- package/src/mlx/turboquant-kv-decode.ts +82 -0
- package/src/mlx/turboquant-kv-inverse.ts +122 -0
- package/src/mlx/turboquant-ops.ts +33 -3
- package/src/mlx/turboquant-tables.ts +2 -2
- package/src/model/batched-mask.ts +8 -2
- package/src/model/batched-quant.ts +1 -1
- package/src/model/batched-rotating-quant.ts +2 -2
- package/src/model/batched-rotating.ts +1 -1
- package/src/model/compiled-decode.ts +1 -1
- package/src/model/diffusion-gemma.ts +8 -8
- package/src/model/factory.ts +76 -33
- package/src/model/fingerprint.ts +1 -1
- package/src/model/flash-attention.ts +3 -3
- package/src/model/gemma4-base.ts +26 -9
- package/src/model/gemma4.ts +6 -6
- package/src/model/generated/gemma4-12b.ts +2 -2
- package/src/model/generated/gemma4-26b.ts +2 -2
- package/src/model/generated/gemma4-e4b.ts +2 -2
- package/src/model/glm52-dsa.ts +13 -9
- package/src/model/glm52-memory.ts +1 -1
- package/src/model/implementation.ts +69 -0
- package/src/model/minicpm5.ts +6 -8
- package/src/model/profile.ts +12 -2
- package/src/model/qwen-append.ts +12 -0
- package/src/model/qwen-conv.ts +52 -0
- package/src/model/qwen3_5-checkpoint.ts +164 -0
- package/src/model/qwen3_5.ts +140 -56
- package/src/model/support.ts +1 -1
- package/src/model/trellis-balanced-scatter.ts +51 -0
- package/src/model/trellis-linear.ts +672 -0
- package/src/model/trellis-shared-m.ts +151 -0
- package/src/model/trellis-shared-scatter.ts +144 -0
- package/src/model/trellis-splitk-prefill.ts +158 -0
- package/src/model/trellis-tiled-prefill.ts +136 -0
- package/src/model/trellis-vector-expand.ts +62 -0
- package/src/model/trellis-wide-prefill.ts +94 -0
- package/src/model/universal/dense.ts +1 -1
- package/src/model/universal/modules.ts +8 -1
- package/src/native-pack.ts +6 -5
- package/src/pi-provider.ts +6 -64
- package/src/pi-web.ts +8 -315
- package/src/prompt-cache.ts +96 -53
- package/src/quantize/allocator.ts +1 -1
- package/src/quantize/config-writer.ts +10 -3
- package/src/quantize/rotate.ts +4 -4
- package/src/quantize/trellis.ts +586 -0
- package/src/responses.ts +28 -1
- package/src/runtime-config.ts +18 -4
- package/src/sampler.ts +4 -4
- package/src/serve/batch-scheduler.ts +8 -1671
- package/src/serve/chat-request.ts +391 -0
- package/src/serve/chat-stage.ts +195 -0
- package/src/serve/checkpoint-identity.ts +64 -0
- package/src/serve/completion-executor.ts +15 -7
- package/src/serve/discovery-routes.ts +12 -13
- package/src/serve/generation-gateway.ts +154 -193
- package/src/serve/http.ts +159 -0
- package/src/serve/inference-request.ts +79 -0
- package/src/serve/isolate.ts +297 -105
- package/src/serve/lab-routes.ts +3 -0
- package/src/serve/lane-registry.ts +2 -1
- package/src/serve/model-admin-routes.ts +7 -5
- package/src/serve/model-binding.ts +43 -0
- package/src/serve/model-host.ts +512 -0
- package/src/serve/openai-wire.ts +103 -0
- package/src/serve/parent-application.ts +56 -0
- package/src/serve/pipeline.ts +33 -0
- package/src/serve/preparation.ts +33 -0
- package/src/serve/request-plan.ts +19 -15
- package/src/serve/request-prep.ts +346 -0
- package/src/serve/response-lease.ts +24 -0
- package/src/serve/responses-client.ts +69 -0
- package/src/serve/session-completion-engine.ts +110 -0
- package/src/serve/session-search.ts +1 -1
- package/src/serve/static-routes.ts +5 -5
- package/src/serve/text-completion-stage.ts +104 -0
- package/src/serve/token-streams.ts +519 -0
- package/src/server.ts +317 -2649
- package/src/spec/assistant-source.ts +10 -44
- package/src/spec/deepspec-source.ts +6 -6
- package/src/spec/dflash-source.ts +8 -8
- package/src/spec/dspark/ab-stats.ts +3 -3
- package/src/spec/dspark/calibration.ts +2 -2
- package/src/spec/dspark/deepspec-module.ts +2 -2
- package/src/spec/dspark/generate-dflash.ts +2 -2
- package/src/spec/dspark/generate.ts +2 -2
- package/src/spec/dspark/loader.ts +1 -1
- package/src/spec/dspark/module-dflash.ts +4 -3
- package/src/spec/dspark/module.ts +3 -3
- package/src/spec/dspark/quantize-drafter.ts +1 -1
- package/src/spec/generate.ts +1 -1
- package/src/spec/glm52-mtp-source.ts +1 -1
- package/src/spec/ngram-source.ts +1 -1
- package/src/spec/prefix-state.ts +45 -0
- package/src/spec/qwen-mtp-source.ts +166 -69
- package/src/spec/serve-loop.ts +154 -156
- package/src/spec/source.ts +42 -10
- package/src/spec/two-model.ts +1 -1
- package/src/ssd-cache.ts +80 -12
- package/src/ssd-durability.ts +25 -13
- package/src/tool-call.ts +51 -14
- package/src/train/flash-cce.ts +2 -2
- package/src/train/forward.ts +6 -0
- package/src/train/loss.ts +1 -1
- package/src/train/prefix-shared.ts +5 -1
- package/src/train/segmented.ts +5 -3
- package/src/train/trainer.ts +6 -6
- package/src/vision/prompt.ts +1 -1
- package/src/vision/qwen3vl-tower.ts +52 -10
- package/src/web/app.html +1 -1
- package/src/web/app.js +5 -3
- package/src/web/src/adapters-panel.ts +3 -3
- package/src/web/src/assistant.ts +2 -36
- package/src/web/src/chat.ts +4 -4
- package/src/web/src/composer.ts +4 -4
- package/src/web/src/hub.ts +1 -1
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +1 -1
- package/src/web/src/model-picker.ts +1 -1
- package/src/web/src/palette.ts +1 -1
- package/src/web/src/protocol.ts +3 -39
- package/src/web/src/sessions.ts +1 -1
- package/src/web/src/ui-catalog.ts +4 -18
- package/src/web-assets.ts +47 -0
- package/src/weights.ts +55 -9
- package/docs/archive/investigations/curve-runs/bisector-route.json +0 -98
- package/docs/archive/investigations/curve-runs/bisector-trace.json +0 -1393
- package/docs/archive/investigations/curve-runs/curve-terrain.json +0 -1179
- package/docs/archive/investigations/curve-runs/curve-terrain.svg +0 -42
- package/docs/archive/investigations/hlg-ab.html +0 -34
- package/docs/archive/investigations/hlg-explorer.html +0 -238
- package/docs/archive/investigations/hlg-figs/cliff.svg +0 -1
- package/docs/archive/investigations/hlg-figs/cross.svg +0 -1
- package/docs/archive/investigations/hlg-figs/edges.svg +0 -1
- package/docs/archive/investigations/hlg-figs/k20-grids.svg +0 -1
- package/docs/archive/investigations/hlg-figs/k20-peaks.svg +0 -1
- package/docs/archive/investigations/hlg-figs/lw-curve.svg +0 -1
- package/docs/archive/investigations/hlg-figs/terrain.svg +0 -1
- package/docs/archive/investigations/hlg-report.html +0 -262
- package/docs/archive/investigations/hlg-runs/hlg-ab.json +0 -149
- package/docs/archive/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
- package/docs/archive/investigations/hlg-runs/hlg-blind.json +0 -107
- package/docs/archive/investigations/hlg-runs/hlg-cliff.json +0 -197
- package/docs/archive/investigations/hlg-runs/hlg-cross.json +0 -505
- package/docs/archive/investigations/hlg-runs/hlg-edge.json +0 -388
- package/docs/archive/investigations/hlg-runs/hlg-eval1.json +0 -25
- package/docs/archive/investigations/hlg-runs/hlg-frontier.json +0 -86
- package/docs/archive/investigations/hlg-runs/hlg-grid.json +0 -242
- package/docs/archive/investigations/hlg-runs/hlg-grid2.json +0 -343
- package/docs/archive/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
- package/docs/archive/investigations/hlg-runs/hlg-map.json +0 -383
- package/docs/archive/investigations/hlg-runs/run0-original.log +0 -159
- package/docs/archive/investigations/hlg-runs/runA-recommended.log +0 -131
- package/docs/archive/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
- package/docs/archive/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
- package/docs/archive/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
- package/docs/archive/investigations/hlg-runs/runAD-ab-samples.log +0 -8
- package/docs/archive/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
- package/docs/archive/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
- package/docs/archive/investigations/hlg-runs/runAG-eval-config2.log +0 -16
- package/docs/archive/investigations/hlg-runs/runB-gain-variants.log +0 -192
- package/docs/archive/investigations/hlg-runs/runC-pivots.log +0 -162
- package/docs/archive/investigations/hlg-runs/runD-oetf.log +0 -132
- package/docs/archive/investigations/hlg-runs/runE-eotf.log +0 -162
- package/docs/archive/investigations/hlg-runs/runF-shaper-working.log +0 -86
- package/docs/archive/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
- package/docs/archive/investigations/hlg-runs/runH-wsweep.log +0 -176
- package/docs/archive/investigations/hlg-runs/runI-asweep.log +0 -176
- package/docs/archive/investigations/hlg-runs/runJ-knobmap.log +0 -49
- package/docs/archive/investigations/hlg-runs/runK-frontier.log +0 -19
- package/docs/archive/investigations/hlg-runs/runL-widemap.log +0 -65
- package/docs/archive/investigations/hlg-runs/runM-frontier-emb.log +0 -15
- package/docs/archive/investigations/hlg-runs/runN-verify.log +0 -116
- package/docs/archive/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
- package/docs/archive/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
- package/docs/archive/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
- package/docs/archive/investigations/hlg-runs/runR-blind-transcript.log +0 -79
- package/docs/archive/investigations/hlg-runs/runS-cross-coherence.log +0 -33
- package/docs/archive/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
- package/docs/archive/investigations/hlg-runs/runU-cross-12b.log +0 -33
- package/docs/archive/investigations/hlg-runs/runV-lw-e4b.log +0 -22
- package/docs/archive/investigations/hlg-runs/runW-lw-12b.log +0 -22
- package/docs/archive/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
- package/docs/archive/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
- package/docs/archive/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
- package/docs/archive/mlx-bun-lab-report.html +0 -275
- package/docs/archive/wwdc-mlx-bun.html +0 -848
- package/docs/design/adapters-end-to-end.md +0 -205
- package/docs/design/batching-perf-path.md +0 -255
- package/docs/design/batching-v2-plan.md +0 -529
- package/docs/design/bucketing-stage.md +0 -197
- package/docs/design/compat-cli-surface-design.md +0 -230
- package/docs/design/docs-reorg-plan.md +0 -165
- package/docs/design/dspark-serving-program.md +0 -371
- package/docs/design/dspark-speculative-decoding.md +0 -318
- package/docs/design/grammar-spec-batching-integration.md +0 -301
- package/docs/design/memory-inference-path.md +0 -422
- package/docs/design/memory-synthesis.md +0 -287
- package/docs/design/memory-system.md +0 -237
- package/docs/design/mlx-lm-serving-execution-seam.md +0 -81
- package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
- package/docs/design/omlx-adoption-map.md +0 -98
- package/docs/design/orpo-dynamic-lambda.md +0 -220
- package/docs/design/orpo-future-enhancements.md +0 -340
- package/docs/design/paged-kv-cache.md +0 -214
- package/docs/design/parallel-slots.md +0 -567
- package/docs/design/parity-tier-dag.md +0 -161
- package/docs/design/repo-cleanup-plan.md +0 -231
- package/docs/design/runtime-isolation.md +0 -263
- package/docs/design/segmented-backward-training.md +0 -543
- package/docs/design/spec-decode-larger-targets.md +0 -229
- package/docs/design/ssd-kv-cold-tier.md +0 -415
- package/docs/design/structured-output.md +0 -484
- package/docs/design/tauri-desktop-app.md +0 -127
- package/docs/design/the-dreaming-master-plan.md +0 -445
- package/docs/design/turboquant-kv.md +0 -235
- package/docs/design/turboquant-weights.md +0 -467
- package/docs/design/w4a16-compute-precision-spike.md +0 -232
- package/docs/design/web-chat-beat-matrix.md +0 -315
- package/docs/design/write-pipeline-entity.md +0 -468
- package/docs/planning/IDEAS.md +0 -69
- package/docs/reference/embedding.md +0 -197
- package/docs/reference/features-matrix.md +0 -101
- package/docs/reference/orpo-quickstart.md +0 -135
- package/src/flags.ts +0 -11
- /package/docs/{design → archive/investigations}/colibri-glm52-port.md +0 -0
- /package/docs/{planning → archive/planning}/chunk-task-roadmap.md +0 -0
- /package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +0 -0
- /package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +0 -0
- /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.2.0.md +0 -0
- /package/src/{memory-plan.ts → admission-plan.ts} +0 -0
- /package/{docs/archive/investigations → src/serve/assets}/curve-terrain.html +0 -0
- /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
|
@@ -21,10 +21,8 @@
|
|
|
21
21
|
import { readdirSync, statSync } from "node:fs";
|
|
22
22
|
import { join } from "node:path";
|
|
23
23
|
import type { MlxArray } from "../mlx/array";
|
|
24
|
-
import * as ops from "../mlx/ops";
|
|
25
|
-
import { Gemma4Model, type Cache } from "../model/gemma4";
|
|
26
24
|
import { GemmaAssistantDrafter } from "./drafter";
|
|
27
|
-
import type { DraftProvider, DraftSource, TargetView } from "./source";
|
|
25
|
+
import type { DraftProvider, DraftSource, TargetView, AssistantTarget } from "./source";
|
|
28
26
|
|
|
29
27
|
/** Sum of the drafter's on-disk safetensors — admission accounting only. */
|
|
30
28
|
function safetensorsBytes(dir: string): number {
|
|
@@ -34,19 +32,6 @@ function safetensorsBytes(dir: string): number {
|
|
|
34
32
|
return total;
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
/** The target's LAST sliding and LAST full cache owners (port of optiq
|
|
38
|
-
* kv_view.find_donor_layers; mirrors donorIndices in generate.ts). */
|
|
39
|
-
function donorIndices(model: Gemma4Model): { sliding: number; full: number } {
|
|
40
|
-
let sliding = -1;
|
|
41
|
-
let full = -1;
|
|
42
|
-
for (let i = 0; i < model.numDonors; i++) {
|
|
43
|
-
if (model.layers[i]!.layerType === "sliding_attention") sliding = i;
|
|
44
|
-
else full = i;
|
|
45
|
-
}
|
|
46
|
-
if (sliding < 0 || full < 0) throw new Error("assistant drafter: missing donor layer type");
|
|
47
|
-
return { sliding, full };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
35
|
export class AssistantProvider implements DraftProvider {
|
|
51
36
|
readonly id: string;
|
|
52
37
|
readonly weightsBytes: number;
|
|
@@ -75,46 +60,27 @@ export class AssistantProvider implements DraftProvider {
|
|
|
75
60
|
}
|
|
76
61
|
}
|
|
77
62
|
|
|
78
|
-
class AssistantSource implements DraftSource {
|
|
63
|
+
export class AssistantSource implements DraftSource {
|
|
79
64
|
readonly weightsBytes = 0; // provider-owned weights; per-request adds nothing
|
|
80
|
-
private readonly
|
|
81
|
-
private readonly caches: Cache[];
|
|
82
|
-
private readonly donors: { sliding: number; full: number };
|
|
65
|
+
private readonly target: AssistantTarget;
|
|
83
66
|
|
|
84
|
-
constructor(private readonly drafter: GemmaAssistantDrafter, target: TargetView) {
|
|
85
|
-
if (!
|
|
86
|
-
throw new Error("assistant drafter requires a Gemma4 target");
|
|
87
|
-
this.
|
|
88
|
-
this.caches = target.caches;
|
|
89
|
-
this.donors = donorIndices(this.model);
|
|
67
|
+
constructor(private readonly drafter: Pick<GemmaAssistantDrafter, "forward">, target: TargetView) {
|
|
68
|
+
if (!target.assistant)
|
|
69
|
+
throw new Error("assistant drafter requires a Gemma4 target with donor views");
|
|
70
|
+
this.target = target.assistant;
|
|
90
71
|
}
|
|
91
72
|
|
|
92
73
|
/** No own cache to prime — the drafter reads the target's live state. */
|
|
93
74
|
prefill(_promptIds: number[], _ctxML?: MlxArray): void {}
|
|
94
75
|
|
|
95
|
-
private embedScaled(token: number): MlxArray {
|
|
96
|
-
const ids = ops.fromInt32([token], [1, 1]);
|
|
97
|
-
const e = this.model.embed.encode(ids);
|
|
98
|
-
ids.dispose();
|
|
99
|
-
const s = ops.mulScalar(e, this.model.embedScale);
|
|
100
|
-
e.dispose();
|
|
101
|
-
return s;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
private readDonors(): { sliding: [MlxArray, MlxArray]; full: [MlxArray, MlxArray] } {
|
|
105
|
-
const view = (i: number) =>
|
|
106
|
-
(this.caches[i] as unknown as { temporalView(): [MlxArray, MlxArray] }).temporalView();
|
|
107
|
-
return { sliding: view(this.donors.sliding), full: view(this.donors.full) };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
76
|
/** Draft n tokens against the target's donor K/V, conditioning the first
|
|
111
77
|
* step on the anchor (the last emitted token + its target hidden) and
|
|
112
78
|
* chaining the drafter's own post-projected hiddens after that — exactly
|
|
113
79
|
* specGenerate's 2a block. anchorHidden is borrowed; never disposed here. */
|
|
114
80
|
draft(feed: number[], n: number, _stepBase: number, anchorHidden?: MlxArray): number[] {
|
|
115
81
|
if (!anchorHidden) throw new Error("assistant drafter needs the target anchor hidden");
|
|
116
|
-
const position = this.
|
|
117
|
-
const shared = this.readDonors();
|
|
82
|
+
const position = this.target.position();
|
|
83
|
+
const shared = this.target.readDonors();
|
|
118
84
|
const drafts: number[] = [];
|
|
119
85
|
const ownedHiddens: MlxArray[] = [];
|
|
120
86
|
let dTok = feed[feed.length - 1]!; // the pending token (anchorHidden's token)
|
|
@@ -122,7 +88,7 @@ class AssistantSource implements DraftSource {
|
|
|
122
88
|
let emb: MlxArray | null = null; // hoisted so a mid-loop throw still frees it
|
|
123
89
|
try {
|
|
124
90
|
for (let k = 0; k < n; k++) {
|
|
125
|
-
emb = this.embedScaled(dTok);
|
|
91
|
+
emb = this.target.embedScaled(dTok);
|
|
126
92
|
const step = this.drafter.forward(emb, dHid, shared, position + k);
|
|
127
93
|
emb.dispose();
|
|
128
94
|
emb = null;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// (github.com/deepseek-ai/DeepSpec, MIT); the module port with transcription
|
|
5
5
|
// notes lives in src/spec/dspark/deepspec-module.ts. Oracle: DeepSpec's eval
|
|
6
6
|
// at temperature 0 (RNG-free — verify degenerates to argmax token-match),
|
|
7
|
-
// scripts/oracle-dspark-deepspec.py →
|
|
7
|
+
// scripts/oracle/oracle-dspark-deepspec.py → dspark-deepspec-compare.ts (deleted 2026-08-23; git history).
|
|
8
8
|
//
|
|
9
9
|
// Seam mapping (why this fits without serve-loop changes): the reference
|
|
10
10
|
// recycles target hidden states from each verify pass into the drafter's
|
|
@@ -26,7 +26,6 @@ import { readdirSync, statSync } from "node:fs";
|
|
|
26
26
|
import { join } from "node:path";
|
|
27
27
|
import type { MlxArray } from "../mlx/array";
|
|
28
28
|
import * as ops from "../mlx/ops";
|
|
29
|
-
import { Gemma4Model } from "../model/gemma4";
|
|
30
29
|
import { DeepspecDrafter, type ContextKV } from "./dspark/deepspec-module";
|
|
31
30
|
import type { DraftProvider, DraftSource, TargetView } from "./source";
|
|
32
31
|
|
|
@@ -65,16 +64,17 @@ export class DeepspecProvider implements DraftProvider {
|
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
|
|
68
|
-
class DeepspecSource implements DraftSource {
|
|
67
|
+
export class DeepspecSource implements DraftSource {
|
|
69
68
|
readonly weightsBytes = 0; // provider-owned weights
|
|
70
69
|
readonly tapLayers: number[];
|
|
71
70
|
private ctxKV: ContextKV[] | null = null; // per-layer projected context rows
|
|
72
71
|
private ctxLen = 0; // context rows cached == the anchor's absolute position
|
|
73
72
|
|
|
74
|
-
constructor(private readonly drafter: DeepspecDrafter,
|
|
75
|
-
|
|
73
|
+
constructor(private readonly drafter: Pick<DeepspecDrafter,
|
|
74
|
+
"cfg" | "tapLayers" | "projectContext" | "projectContextKV" | "draftBlock">, target: TargetView) {
|
|
75
|
+
if (!target.gemmaTaps)
|
|
76
76
|
throw new Error("DeepSpec drafter requires a Gemma4 target");
|
|
77
|
-
const nLayers = target.
|
|
77
|
+
const nLayers = target.gemmaTaps.layerCount;
|
|
78
78
|
if (nLayers !== drafter.cfg.num_target_layers)
|
|
79
79
|
throw new Error(
|
|
80
80
|
`DeepSpec drafter was trained for a ${drafter.cfg.num_target_layers}-layer target; ` +
|
|
@@ -22,10 +22,9 @@ import { readdirSync, statSync } from "node:fs";
|
|
|
22
22
|
import { join } from "node:path";
|
|
23
23
|
import type { MlxArray } from "../mlx/array";
|
|
24
24
|
import * as ops from "../mlx/ops";
|
|
25
|
-
import { Gemma4Model } from "../model/gemma4";
|
|
26
25
|
import type { DflashDrafter } from "./dspark/module-dflash";
|
|
27
26
|
import { loadDsparkDrafter } from "./dspark/loader";
|
|
28
|
-
import type { DraftProvider, DraftSource, TargetView } from "./source";
|
|
27
|
+
import type { DraftProvider, DraftSource, TargetView, DraftProjection } from "./source";
|
|
29
28
|
import { runtimeValue } from "../runtime-config";
|
|
30
29
|
|
|
31
30
|
function safetensorsBytes(dir: string): number {
|
|
@@ -65,16 +64,17 @@ export class DflashProvider implements DraftProvider {
|
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
|
|
68
|
-
class DflashSource implements DraftSource {
|
|
67
|
+
export class DflashSource implements DraftSource {
|
|
69
68
|
readonly weightsBytes = 0; // provider-owned weights
|
|
70
69
|
readonly tapLayers: number[];
|
|
71
|
-
private readonly model:
|
|
70
|
+
private readonly model: DraftProjection;
|
|
71
|
+
private readonly minConf = runtimeValue("MLX_BUN_DSPARK_MINCONF");
|
|
72
72
|
private hCtx: MlxArray | null = null; // [1, L, m*H] — grows with the accepted stream
|
|
73
73
|
|
|
74
|
-
constructor(private readonly drafter: DflashDrafter, target: TargetView) {
|
|
75
|
-
if (!
|
|
74
|
+
constructor(private readonly drafter: Pick<DflashDrafter, "cfg" | "forwardInfer">, target: TargetView) {
|
|
75
|
+
if (!target.gemmaTaps)
|
|
76
76
|
throw new Error("DSpark drafter requires a Gemma4 target");
|
|
77
|
-
this.model = target.
|
|
77
|
+
this.model = target.gemmaTaps.projection;
|
|
78
78
|
this.tapLayers = drafter.cfg.tapLayers;
|
|
79
79
|
}
|
|
80
80
|
|
|
@@ -94,7 +94,7 @@ class DflashSource implements DraftSource {
|
|
|
94
94
|
draft(feed: number[], n: number, _stepBase: number, _anchorHidden?: MlxArray): number[] {
|
|
95
95
|
if (!this.hCtx) throw new Error("DSpark drafter: draft before prefill");
|
|
96
96
|
const anchorTok = feed[feed.length - 1]!;
|
|
97
|
-
const envMin =
|
|
97
|
+
const envMin = this.minConf;
|
|
98
98
|
const block = this.drafter.forwardInfer(this.model, this.hCtx, anchorTok, n, {
|
|
99
99
|
thresholds: this.drafter.cfg.sts?.thresholds,
|
|
100
100
|
collectLogits: false, // serve loop runs its own verify lm-head, never reads this
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Model-free math for the Phase-1c drafter acceptance A/B
|
|
2
|
-
// (docs/design/
|
|
3
|
-
// scripts/dspark
|
|
2
|
+
// (docs/design/speculative-decoding.md; runner:
|
|
3
|
+
// scripts/dspark.ts ab). THE gate for every drafter-quantization
|
|
4
4
|
// experiment: same target, same prompts, temp 0 — drafter A vs drafter B.
|
|
5
5
|
//
|
|
6
6
|
// Paired design: prompts are the pairing unit, so per-prompt deltas cancel
|
|
@@ -76,7 +76,7 @@ export function summarizeArm(results: AbPromptResult[]): AbArmSummary {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
/** Phase-1d exit: acceptance drop ≤ maxDropPts absolute AND wall-clock
|
|
79
|
-
* strictly improves (docs/design/
|
|
79
|
+
* strictly improves (docs/design/speculative-decoding.md 1d). */
|
|
80
80
|
export function pairedVerdict(
|
|
81
81
|
aResults: AbPromptResult[],
|
|
82
82
|
bResults: AbPromptResult[],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// confidence thresholds from real (confidence, accepted) verify outcomes, so
|
|
3
3
|
// the scheduler in module-dflash.ts#forwardInfer prunes positions the
|
|
4
4
|
// confidence head can't actually call. Pure math, no MLX/GPU here: the
|
|
5
|
-
// caller (scripts/dspark
|
|
5
|
+
// caller (scripts/dspark.ts calibrate) collects samples off a live model via
|
|
6
6
|
// dflashGenerate's onRound hook, this module just fits.
|
|
7
7
|
//
|
|
8
8
|
// VERIFIED vs the paper + reference (2026-07-06 audit, arXiv:2607.05147 +
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// survival products, feeding Alg-1's throughput-maximizing scheduler with a
|
|
15
15
|
// profiled SPS(B) cost table) — that machinery lives in DeepSeek's UNRELEASED
|
|
16
16
|
// production serving layer, not in DeepSpec. Paper-faithful STS/Alg-1 is a
|
|
17
|
-
// future Lab item; details in docs/design/
|
|
17
|
+
// future Lab item; details in docs/design/speculative-decoding.md
|
|
18
18
|
// "DeepSpec ground truth". The isotonic-style "smallest τ meeting a target
|
|
19
19
|
// precision, Laplace-smoothed" fit below is ours (the reference ships no
|
|
20
20
|
// calibrator at all — raw sigmoid vs a hand-set threshold).
|
|
@@ -38,7 +38,7 @@ function disposing(old: MlxArray, next: MlxArray): MlxArray {
|
|
|
38
38
|
// ---------------------------------------------------------------------------
|
|
39
39
|
// Weight representation: every matmul weight and gather table loads as either
|
|
40
40
|
// bf16 (the released checkpoint) or affine-quantized (a
|
|
41
|
-
// scripts/dspark
|
|
41
|
+
// scripts/dspark.ts quantize sibling). Detection is the house
|
|
42
42
|
// pattern — a `.scales` sibling key marks a quantized module; bits/group_size
|
|
43
43
|
// come from the config's `quantization` block (per-module overrides + the
|
|
44
44
|
// mlx `false` = kept-full-precision convention). Both formats flow through
|
|
@@ -366,7 +366,7 @@ export class DeepspecDrafter {
|
|
|
366
366
|
static async load(dir: string): Promise<DeepspecDrafter> {
|
|
367
367
|
const raw = (await Bun.file(`${dir}/config.json`).json()) as Record<string, any>;
|
|
368
368
|
const cfg = readConfig(raw);
|
|
369
|
-
// Quantized siblings (scripts/dspark
|
|
369
|
+
// Quantized siblings (scripts/dspark.ts quantize) carry the house
|
|
370
370
|
// quantization block; the released bf16 checkpoint has none → null.
|
|
371
371
|
const quant = parseQuantization(raw.quantization ?? raw.quantization_config);
|
|
372
372
|
const w = await Weights.open(dir);
|
|
@@ -27,7 +27,7 @@ export interface DflashGenOptions {
|
|
|
27
27
|
* minConf for a uniform manual override; pass thresholds:[] to disable. */
|
|
28
28
|
thresholds?: number[];
|
|
29
29
|
minConf?: number;
|
|
30
|
-
/** Calibration hook (scripts/dspark
|
|
30
|
+
/** Calibration hook (scripts/dspark.ts calibrate): called once per draft
|
|
31
31
|
* round with that round's per-position (confidence, accepted) samples,
|
|
32
32
|
* AFTER kAccept is known. Not used by ordinary decode. */
|
|
33
33
|
onRound?: (samples: ConfSample[]) => void;
|
|
@@ -192,7 +192,7 @@ export function dflashGenerate(model: Gemma4Model, drafter: DflashDrafter, promp
|
|
|
192
192
|
blockLogits = null;
|
|
193
193
|
stats.accepted += kAccept; rounds++; acceptLenSum += kAccept + 1;
|
|
194
194
|
|
|
195
|
-
// Calibration hook (scripts/dspark
|
|
195
|
+
// Calibration hook (scripts/dspark.ts calibrate): report this round's
|
|
196
196
|
// per-position (confidence, accepted) outcomes now that kAccept is known.
|
|
197
197
|
if (options.onRound) {
|
|
198
198
|
const roundSamples: ConfSample[] = [];
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
// (sample.ts), so the emitted stream is distributed exactly as if e4b
|
|
18
18
|
// sampled token-by-token at that temperature — independent of draft quality.
|
|
19
19
|
//
|
|
20
|
-
// Verify the corresponding gate before chasing τ (
|
|
20
|
+
// Verify the corresponding gate before chasing τ (dspark-ab.ts (deleted 2026-08-23; git history)): greedy
|
|
21
21
|
// output must match model.generate; the sampling rule's correctness is the
|
|
22
|
-
// statistical "emit distribution == target" check in
|
|
22
|
+
// statistical "emit distribution == target" check in dspark-smoke.ts (deleted 2026-08-23; git history).
|
|
23
23
|
// If a gate fails, the accept/reject or KV rollback is wrong — fix that first.
|
|
24
24
|
|
|
25
25
|
import { MlxArray } from "../../mlx/array";
|
|
@@ -18,6 +18,6 @@ export function loadDsparkDrafter(dir: string): DflashDrafter {
|
|
|
18
18
|
if (meta.variant === "dspark" || meta.variant === "dflash") return DflashDrafter.load(dir);
|
|
19
19
|
throw new Error(
|
|
20
20
|
`${dir} is a v1 single-vector DSpark checkpoint (variant=${meta.variant ?? "none"}) — ` +
|
|
21
|
-
`superseded, not serveable; retrain with scripts/dspark
|
|
21
|
+
`superseded, not serveable; retrain with scripts/dspark.ts train`,
|
|
22
22
|
);
|
|
23
23
|
}
|
|
@@ -17,6 +17,7 @@ import { MlxArray } from "../../mlx/array";
|
|
|
17
17
|
import { Dtype } from "../../mlx/ffi";
|
|
18
18
|
import * as ops from "../../mlx/ops";
|
|
19
19
|
import type { Gemma4Model } from "../../model/gemma4";
|
|
20
|
+
import type { DraftProjection } from "../source";
|
|
20
21
|
import { loadAdapterTensors } from "../../lora";
|
|
21
22
|
import { writeShardedSafetensors, type NamedTensor } from "../../quantize/safetensors-writer";
|
|
22
23
|
import { processLogits, sampleToken, KeyStream, type DSparkSampleConfig } from "./sample";
|
|
@@ -25,7 +26,7 @@ import { join } from "node:path";
|
|
|
25
26
|
|
|
26
27
|
/** STS calibration (§3.2.1) — per-position confidence thresholds fit on real
|
|
27
28
|
* (confidence, accepted) verify outcomes (src/spec/dspark/calibration.ts,
|
|
28
|
-
* scripts/dspark
|
|
29
|
+
* scripts/dspark.ts calibrate). Consumed by the confidence-scheduled
|
|
29
30
|
* draft-length pruning (Alg 1, single-user form) in forwardInfer. Stored
|
|
30
31
|
* inside DflashConfig so it round-trips through dspark.json for free.
|
|
31
32
|
* ABSENT ⟹ no pruning — an uncalibrated checkpoint drafts exactly as before. */
|
|
@@ -300,7 +301,7 @@ export class DflashDrafter {
|
|
|
300
301
|
return H_d;
|
|
301
302
|
}
|
|
302
303
|
|
|
303
|
-
#baseLogits(model:
|
|
304
|
+
#baseLogits(model: DraftProjection, block: MlxArray): MlxArray {
|
|
304
305
|
const hOut = ops.matmul(block, this.get("out_proj")); // [A,γ,H]
|
|
305
306
|
const hBf = hOut.astype(model.embed.scales.dtype); hOut.dispose();
|
|
306
307
|
const logits = model.logitsFromHidden(hBf); hBf.dispose();
|
|
@@ -416,7 +417,7 @@ export class DflashDrafter {
|
|
|
416
417
|
* one toFloat32 after the loop). The sampling path already forces a host
|
|
417
418
|
* read every position (sampleToken draws from a device RNG key) — that
|
|
418
419
|
* path is unchanged. */
|
|
419
|
-
forwardInfer(model:
|
|
420
|
+
forwardInfer(model: DraftProjection, hCtx: MlxArray, anchorTok: number, gamma: number, opts: DflashDraftOpts = {}): DflashDraftBlock {
|
|
420
421
|
const { dDraft, markovRank: r } = this.cfg;
|
|
421
422
|
const V = this.dims.vocabSize;
|
|
422
423
|
const sample = opts.sample && opts.sample.temperature > 0 ? opts.sample : null;
|
|
@@ -31,6 +31,7 @@ import { MlxArray } from "../../mlx/array";
|
|
|
31
31
|
import { Dtype } from "../../mlx/ffi";
|
|
32
32
|
import * as ops from "../../mlx/ops";
|
|
33
33
|
import type { Gemma4Model } from "../../model/gemma4";
|
|
34
|
+
import type { DraftProjection } from "../source";
|
|
34
35
|
import { loadAdapterTensors } from "../../lora";
|
|
35
36
|
import { writeShardedSafetensors, type NamedTensor } from "../../quantize/safetensors-writer";
|
|
36
37
|
import { processLogits, sampleToken, KeyStream, type DSparkSampleConfig } from "./sample";
|
|
@@ -343,7 +344,7 @@ export class DSparkDrafter {
|
|
|
343
344
|
|
|
344
345
|
/** Base logits U from the SHARED frozen LM head over the backbone block
|
|
345
346
|
* hidden. [A,γ,V] (model dtype). */
|
|
346
|
-
#baseLogits(model:
|
|
347
|
+
#baseLogits(model: DraftProjection, block: MlxArray): MlxArray {
|
|
347
348
|
const hOut = ops.matmul(block, this.get("out_proj")); // [A,γ,H] (f32)
|
|
348
349
|
const hBf = hOut.astype(model.embed.scales.dtype); // head's activation dtype
|
|
349
350
|
hOut.dispose();
|
|
@@ -404,7 +405,7 @@ export class DSparkDrafter {
|
|
|
404
405
|
* reconstructs (so q is consistent). hCtx [1,H], anchorTok the bonus token.
|
|
405
406
|
* Returns the raw per-position logits so the verifier can recover q.
|
|
406
407
|
*/
|
|
407
|
-
forwardInfer(model:
|
|
408
|
+
forwardInfer(model: DraftProjection, hCtx: MlxArray, anchorTok: number, gamma: number, opts: DSparkDraftOpts = {}): DSparkDraftBlock {
|
|
408
409
|
const { dDraft, markovRank: r } = this.cfg;
|
|
409
410
|
const V = this.dims.vocabSize;
|
|
410
411
|
const A = 1;
|
|
@@ -537,4 +538,3 @@ function buildNames(cfg: DSparkConfig): string[] {
|
|
|
537
538
|
"markov.w1", "markov.w2", "conf.w", "conf.b");
|
|
538
539
|
return names;
|
|
539
540
|
}
|
|
540
|
-
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Quantize a DeepSpec-format drafter checkpoint (Phase 1a of the DSpark
|
|
2
|
-
// serving program, docs/design/
|
|
2
|
+
// serving program, docs/design/speculative-decoding.md).
|
|
3
3
|
//
|
|
4
4
|
// Thin policy layer over the house quantizer (src/quantize): the generic
|
|
5
5
|
// shape-eligibility rule already captures every 2-D matmul weight — the
|
package/src/spec/generate.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// with stock only on tie-free prompts (where batched == per-position).
|
|
12
12
|
// An earlier version verified per-position to stay bit-exact to STOCK —
|
|
13
13
|
// that matched no real oracle and cost an extra γ× read of the lm-head
|
|
14
|
-
// weight per step; superseded. See docs/design/
|
|
14
|
+
// weight per step; superseded. See docs/design/speculative-decoding.md.
|
|
15
15
|
//
|
|
16
16
|
// Limitation (same as the reference): partial-accept rollback requires
|
|
17
17
|
// trimmable caches; RotatingKVCache loses trimability once its ring
|
|
@@ -57,7 +57,7 @@ export class Glm52NativeMtpProvider implements DraftProvider {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
open(opts: Parameters<DraftProvider["open"]>[0]): DraftSource {
|
|
60
|
-
if (opts.target.
|
|
60
|
+
if (opts.target.identity !== this.model)
|
|
61
61
|
throw new Error("native MTP provider was opened for a different target");
|
|
62
62
|
return new Glm52NativeMtpSource(this.model, this.#layer, opts.sampler);
|
|
63
63
|
}
|
package/src/spec/ngram-source.ts
CHANGED
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
// speculation is structurally never worse than plain decode by more than the
|
|
39
39
|
// JS scan (~µs against 30k-token histories).
|
|
40
40
|
|
|
41
|
-
import { flagOn } from "../
|
|
41
|
+
import { flagOn } from "../runtime-config";
|
|
42
42
|
import type { DraftProvider, DraftSource } from "./source";
|
|
43
43
|
|
|
44
44
|
export interface NgramOptions {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Cache } from "../model/gemma4";
|
|
2
|
+
import type { DisposableResource } from "../contracts/resources";
|
|
3
|
+
import { cleanupFailure } from "../engine/resources";
|
|
4
|
+
|
|
5
|
+
/** One most-recent, exact prefill boundary. Taking transfers ownership; a
|
|
6
|
+
* recurrent target cannot be trimmed to an arbitrary common prefix. The
|
|
7
|
+
* provider owns this state and releases it before its weights at shutdown. */
|
|
8
|
+
export interface SpeculativePrefixState extends DisposableResource {
|
|
9
|
+
readonly tokens: number[];
|
|
10
|
+
readonly targetIdentity: object;
|
|
11
|
+
readonly namespace: string;
|
|
12
|
+
readonly bytes: number;
|
|
13
|
+
readonly target: Cache[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class SpeculativePrefixStore<T extends SpeculativePrefixState> {
|
|
17
|
+
#entry: T | null = null;
|
|
18
|
+
|
|
19
|
+
take(prompt: readonly number[], targetIdentity: object, namespace: string,
|
|
20
|
+
maxBytes: number): T | null {
|
|
21
|
+
const entry = this.#entry;
|
|
22
|
+
this.#entry = null;
|
|
23
|
+
if (!entry) return null;
|
|
24
|
+
if (entry.bytes <= maxBytes && entry.targetIdentity === targetIdentity &&
|
|
25
|
+
entry.namespace === namespace && entry.tokens.length < prompt.length &&
|
|
26
|
+
entry.tokens.every((token, index) => prompt[index] === token))
|
|
27
|
+
return entry;
|
|
28
|
+
entry.dispose();
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Takes ownership even when the entry exceeds the configured RAM budget. */
|
|
33
|
+
put(entry: T, maxBytes: number): void {
|
|
34
|
+
try { this.dispose(); }
|
|
35
|
+
catch (error) { cleanupFailure(error, () => entry.dispose()); }
|
|
36
|
+
if (entry.bytes <= maxBytes && maxBytes > 0) this.#entry = entry;
|
|
37
|
+
else entry.dispose();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
dispose(): void {
|
|
41
|
+
const entry = this.#entry;
|
|
42
|
+
this.#entry = null;
|
|
43
|
+
entry?.dispose();
|
|
44
|
+
}
|
|
45
|
+
}
|