mlx-bun 0.0.12 → 0.2.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.
Files changed (226) hide show
  1. package/README.md +40 -24
  2. package/bin/mlx-bun.mjs +1 -1
  3. package/docs/{design → archive}/hlg-sampling.md +3 -3
  4. package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
  5. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
  6. package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
  7. package/docs/archive/planning/release-notes-v0.0.13.md +77 -0
  8. package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
  9. package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
  10. package/docs/design/colibri-glm52-port.md +8 -1
  11. package/docs/design/compat-cli-surface-design.md +1 -1
  12. package/docs/design/decode-speed-program.md +1 -1
  13. package/docs/design/docs-reorg-plan.md +1 -1
  14. package/docs/design/dspark-serving-program.md +1 -1
  15. package/docs/design/dspark-speculative-decoding.md +53 -3
  16. package/docs/design/grammar-spec-batching-integration.md +1 -1
  17. package/docs/design/mlx-lm-serving-execution-seam.md +81 -0
  18. package/docs/design/orpo-dynamic-lambda.md +1 -1
  19. package/docs/design/orpo-future-enhancements.md +1 -1
  20. package/docs/design/orpo-training.md +2 -2
  21. package/docs/design/parity-tier-dag.md +1 -1
  22. package/docs/design/repo-cleanup-plan.md +46 -4
  23. package/docs/design/segmented-backward-training.md +2 -2
  24. package/docs/design/ssd-kv-cold-tier.md +127 -0
  25. package/docs/design/turboquant-weights.md +467 -0
  26. package/docs/design/w4a16-compute-precision-spike.md +1 -1
  27. package/docs/design/web-chat-redesign.md +5 -5
  28. package/docs/planning/chunk-task-roadmap.md +1 -1
  29. package/docs/planning/curve-sampler-research-plan.md +4 -4
  30. package/docs/planning/memory-docs-and-dag-plan.md +1 -1
  31. package/docs/planning/release-notes-v0.2.0.md +49 -0
  32. package/docs/planning/video-series.md +421 -0
  33. package/docs/reference/cli.md +15 -4
  34. package/docs/reference/distribution.md +1 -0
  35. package/docs/reference/features-matrix.md +3 -1
  36. package/docs/reference/library-api.md +41 -1
  37. package/docs/reference/models.md +33 -0
  38. package/docs/reference/server-api.md +86 -19
  39. package/docs/reference/server-config.md +57 -33
  40. package/package.json +2 -2
  41. package/src/anthropic.ts +92 -3
  42. package/src/chat-template.ts +34 -1
  43. package/src/cli.ts +131 -36
  44. package/src/config.ts +10 -0
  45. package/src/eval/kl.ts +27 -20
  46. package/src/eval/runner.ts +23 -4
  47. package/src/eval/tasks/bfcl.ts +2 -1
  48. package/src/eval/tasks/gsm8k.ts +2 -1
  49. package/src/eval/tasks/hashhop.ts +2 -1
  50. package/src/eval/tasks/humaneval.ts +5 -4
  51. package/src/eval/tasks/ifeval.ts +2 -1
  52. package/src/eval/tasks/mmlu.ts +2 -1
  53. package/src/expert-io.ts +3 -1
  54. package/src/expert-offload.ts +3 -1
  55. package/src/expert-trace.ts +3 -1
  56. package/src/fit.ts +24 -43
  57. package/src/flags.ts +7 -9
  58. package/src/generate.ts +107 -92
  59. package/src/grammar.ts +2 -1
  60. package/src/harness-pi.ts +1 -1
  61. package/src/index.ts +20 -0
  62. package/src/jobs/job-entry.ts +3 -2
  63. package/src/kv-scheme.ts +199 -0
  64. package/src/kv-store.ts +370 -205
  65. package/src/media-fetch.ts +19 -3
  66. package/src/memory/model.ts +2 -1
  67. package/src/memory/vault.ts +2 -1
  68. package/src/memory-plan.ts +18 -0
  69. package/src/mlx/ffi.ts +8 -11
  70. package/src/mlx/ops.ts +31 -6
  71. package/src/model/batched-mask.ts +1 -1
  72. package/src/model/batched-quant.ts +1 -1
  73. package/src/model/batched-rotating-quant.ts +43 -97
  74. package/src/model/batched-rotating-state.ts +73 -0
  75. package/src/model/batched-rotating.ts +56 -105
  76. package/src/model/batched-row-storage.ts +127 -0
  77. package/src/model/compiled-decode.ts +3 -2
  78. package/src/model/factory.ts +44 -49
  79. package/src/model/gemma4-base.ts +163 -10
  80. package/src/model/generated/gemma4-12b.ts +50 -146
  81. package/src/model/generated/gemma4-26b.ts +32 -92
  82. package/src/model/generated/gemma4-e4b.ts +26 -74
  83. package/src/model/glm52-cache.ts +19 -9
  84. package/src/model/glm52-memory.ts +28 -1
  85. package/src/model/minicpm5.ts +2 -1
  86. package/src/model/profile.ts +433 -0
  87. package/src/model/qwen3-delta.ts +98 -2
  88. package/src/model/qwen3-mrope.ts +252 -0
  89. package/src/model/qwen3_5.ts +217 -25
  90. package/src/native/frame_extract.swift +140 -0
  91. package/src/native-pack.ts +13 -6
  92. package/src/pi-web.ts +6 -5
  93. package/src/prompt-cache.ts +2 -2
  94. package/src/quantize/atomic-output.ts +38 -0
  95. package/src/quantize/calibration.ts +2 -1
  96. package/src/quantize/config-writer.ts +6 -0
  97. package/src/quantize/index.ts +28 -1
  98. package/src/quantize/job.ts +11 -0
  99. package/src/quantize/quantizer.ts +265 -100
  100. package/src/quantize/rotate.ts +603 -0
  101. package/src/quantize/safetensors-writer.ts +79 -1
  102. package/src/quantize/sensitivity.ts +41 -59
  103. package/src/quantize/weight-transform.ts +292 -0
  104. package/src/responses.ts +102 -2
  105. package/src/runtime-config.ts +67 -0
  106. package/src/sampler.ts +272 -0
  107. package/src/serve/admin-routes.ts +184 -0
  108. package/src/serve/aux-routes.ts +132 -0
  109. package/src/serve/batch-scheduler.ts +200 -87
  110. package/src/serve/completion-executor.ts +346 -0
  111. package/src/serve/completion-sink.ts +157 -0
  112. package/src/serve/discovery-routes.ts +205 -0
  113. package/src/serve/generation-gateway.ts +116 -109
  114. package/src/serve/kv-budget.ts +14 -0
  115. package/src/serve/lab-routes.ts +338 -0
  116. package/src/serve/model-admin-routes.ts +153 -0
  117. package/src/serve/prompt-response-trace.ts +147 -0
  118. package/src/serve/request-plan.ts +158 -0
  119. package/src/serve/static-routes.ts +101 -0
  120. package/src/server.ts +768 -1367
  121. package/src/spec/dflash-source.ts +2 -1
  122. package/src/spec/dspark/module-dflash.ts +1 -1
  123. package/src/spec/glm52-mtp-source.ts +8 -0
  124. package/src/spec/qwen-mtp-source.ts +431 -0
  125. package/src/spec/serve-loop.ts +36 -68
  126. package/src/ssd-cache.ts +17 -14
  127. package/src/ssd-durability.ts +195 -0
  128. package/src/train/flash-cce.ts +12 -11
  129. package/src/train/forward.ts +32 -1
  130. package/src/train/loss.ts +2 -1
  131. package/src/train/segmented.ts +4 -3
  132. package/src/train/trainer.ts +3 -2
  133. package/src/vision/preprocess.ts +1 -1
  134. package/src/vision/prompt.ts +47 -1
  135. package/src/vision/qwen3vl-preprocess.ts +409 -0
  136. package/src/vision/qwen3vl-prompt.ts +196 -0
  137. package/src/vision/qwen3vl-tower.ts +513 -0
  138. package/src/vision/video-frames.ts +148 -0
  139. package/src/web/app.js +10 -3
  140. package/src/web/src/chat.ts +12 -5
  141. package/src/weights.ts +81 -26
  142. /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
  143. /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
  144. /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
  145. /package/docs/{investigations → archive/investigations}/curve-runs/bisector-route.json +0 -0
  146. /package/docs/{investigations → archive/investigations}/curve-runs/bisector-trace.json +0 -0
  147. /package/docs/{investigations → archive/investigations}/curve-runs/curve-terrain.json +0 -0
  148. /package/docs/{investigations → archive/investigations}/curve-runs/curve-terrain.svg +0 -0
  149. /package/docs/{investigations → archive/investigations}/curve-terrain.html +0 -0
  150. /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
  151. /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
  152. /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
  153. /package/docs/{investigations → archive/investigations}/hlg-ab.html +0 -0
  154. /package/docs/{investigations → archive/investigations}/hlg-explorer.html +0 -0
  155. /package/docs/{investigations → archive/investigations}/hlg-figs/cliff.svg +0 -0
  156. /package/docs/{investigations → archive/investigations}/hlg-figs/cross.svg +0 -0
  157. /package/docs/{investigations → archive/investigations}/hlg-figs/edges.svg +0 -0
  158. /package/docs/{investigations → archive/investigations}/hlg-figs/k20-grids.svg +0 -0
  159. /package/docs/{investigations → archive/investigations}/hlg-figs/k20-peaks.svg +0 -0
  160. /package/docs/{investigations → archive/investigations}/hlg-figs/lw-curve.svg +0 -0
  161. /package/docs/{investigations → archive/investigations}/hlg-figs/terrain.svg +0 -0
  162. /package/docs/{investigations → archive/investigations}/hlg-report.html +0 -0
  163. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-ab.json +0 -0
  164. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-blind-prompts.md +0 -0
  165. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-blind.json +0 -0
  166. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-cliff.json +0 -0
  167. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-cross.json +0 -0
  168. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-edge.json +0 -0
  169. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-eval1.json +0 -0
  170. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-frontier.json +0 -0
  171. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-grid.json +0 -0
  172. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-grid2.json +0 -0
  173. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-lw-coarse.json +0 -0
  174. /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-map.json +0 -0
  175. /package/docs/{investigations → archive/investigations}/hlg-runs/run0-original.log +0 -0
  176. /package/docs/{investigations → archive/investigations}/hlg-runs/runA-recommended.log +0 -0
  177. /package/docs/{investigations → archive/investigations}/hlg-runs/runAA-cliff-cpm5.log +0 -0
  178. /package/docs/{investigations → archive/investigations}/hlg-runs/runAB-grid2-e4b.log +0 -0
  179. /package/docs/{investigations → archive/investigations}/hlg-runs/runAC-peak-e4b-partial.log +0 -0
  180. /package/docs/{investigations → archive/investigations}/hlg-runs/runAD-ab-samples.log +0 -0
  181. /package/docs/{investigations → archive/investigations}/hlg-runs/runAE-edge-e4b.log +0 -0
  182. /package/docs/{investigations → archive/investigations}/hlg-runs/runAF-logit-calibration.log +0 -0
  183. /package/docs/{investigations → archive/investigations}/hlg-runs/runAG-eval-config2.log +0 -0
  184. /package/docs/{investigations → archive/investigations}/hlg-runs/runB-gain-variants.log +0 -0
  185. /package/docs/{investigations → archive/investigations}/hlg-runs/runC-pivots.log +0 -0
  186. /package/docs/{investigations → archive/investigations}/hlg-runs/runD-oetf.log +0 -0
  187. /package/docs/{investigations → archive/investigations}/hlg-runs/runE-eotf.log +0 -0
  188. /package/docs/{investigations → archive/investigations}/hlg-runs/runF-shaper-working.log +0 -0
  189. /package/docs/{investigations → archive/investigations}/hlg-runs/runG-shaper-sweep.log +0 -0
  190. /package/docs/{investigations → archive/investigations}/hlg-runs/runH-wsweep.log +0 -0
  191. /package/docs/{investigations → archive/investigations}/hlg-runs/runI-asweep.log +0 -0
  192. /package/docs/{investigations → archive/investigations}/hlg-runs/runJ-knobmap.log +0 -0
  193. /package/docs/{investigations → archive/investigations}/hlg-runs/runK-frontier.log +0 -0
  194. /package/docs/{investigations → archive/investigations}/hlg-runs/runL-widemap.log +0 -0
  195. /package/docs/{investigations → archive/investigations}/hlg-runs/runM-frontier-emb.log +0 -0
  196. /package/docs/{investigations → archive/investigations}/hlg-runs/runN-verify.log +0 -0
  197. /package/docs/{investigations → archive/investigations}/hlg-runs/runO-frontier-seed5000.log +0 -0
  198. /package/docs/{investigations → archive/investigations}/hlg-runs/runP-grid-AxSm.log +0 -0
  199. /package/docs/{investigations → archive/investigations}/hlg-runs/runQ-grid-tgW.log +0 -0
  200. /package/docs/{investigations → archive/investigations}/hlg-runs/runR-blind-transcript.log +0 -0
  201. /package/docs/{investigations → archive/investigations}/hlg-runs/runS-cross-coherence.log +0 -0
  202. /package/docs/{investigations → archive/investigations}/hlg-runs/runT-cross-cpm5.log +0 -0
  203. /package/docs/{investigations → archive/investigations}/hlg-runs/runU-cross-12b.log +0 -0
  204. /package/docs/{investigations → archive/investigations}/hlg-runs/runV-lw-e4b.log +0 -0
  205. /package/docs/{investigations → archive/investigations}/hlg-runs/runW-lw-12b.log +0 -0
  206. /package/docs/{investigations → archive/investigations}/hlg-runs/runX-lw-cpm5.log +0 -0
  207. /package/docs/{investigations → archive/investigations}/hlg-runs/runY-cliff-e4b.log +0 -0
  208. /package/docs/{investigations → archive/investigations}/hlg-runs/runZ-cliff-12b.log +0 -0
  209. /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
  210. /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
  211. /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
  212. /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
  213. /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
  214. /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
  215. /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
  216. /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
  217. /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
  218. /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
  219. /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
  220. /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
  221. /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
  222. /package/docs/{planning → archive/planning}/journal.md +0 -0
  223. /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
  224. /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
  225. /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
  226. /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
@@ -15,6 +15,7 @@ import { Dtype } from "../mlx/ffi";
15
15
  import * as ops from "../mlx/ops";
16
16
  import { expertOffloadArray } from "../expert-offload";
17
17
  import * as tq from "../mlx/turboquant-ops";
18
+ import { runtimeValue } from "../runtime-config";
18
19
 
19
20
  export type MaskMode = "" | "causal";
20
21
  export interface Mask {
@@ -53,6 +54,15 @@ export class LoraState {
53
54
  dropoutSeed: number | null = null;
54
55
  }
55
56
 
57
+ /** Replaceable quantized payload. Inference sees this as read-only through
58
+ * QuantizedLinear getters; sensitivity analysis exchanges it atomically. */
59
+ export interface QuantizedLinearState {
60
+ w: MlxArray;
61
+ scales: MlxArray;
62
+ biases: MlxArray | null;
63
+ spec: ops.QuantSpec;
64
+ }
65
+
56
66
  /** Inverted LoRA-input dropout, keyed by (seed, id) so it is deterministic —
57
67
  * the same (seed, id, shape) reproduces the mask, which is what makes the
58
68
  * segmented / gradient-checkpoint recompute correct. kept ⇒ x/(1-p),
@@ -79,18 +89,48 @@ export class QuantizedLinear {
79
89
  /** Stable per-target index for keying training-only LoRA dropout (set by
80
90
  * attachForTraining). Gives each adapted linear an independent dropout mask. */
81
91
  dropoutId = 0;
92
+ private _w: MlxArray;
93
+ private _scales: MlxArray;
94
+ private _biases: MlxArray | null;
95
+ private _spec: ops.QuantSpec;
82
96
 
83
97
  constructor(
84
- readonly w: MlxArray,
85
- readonly scales: MlxArray,
86
- readonly biases: MlxArray | null,
87
- readonly spec: ops.QuantSpec,
98
+ w: MlxArray,
99
+ scales: MlxArray,
100
+ biases: MlxArray | null,
101
+ spec: ops.QuantSpec,
88
102
  /** ADDITIVE bias term (`.bias`, mlx nn.QuantizedLinear's optional bias —
89
103
  * qwen2 qkv, starcoder2, …). Distinct from `biases`, the quantization
90
104
  * zero-points. Applied after the matmul, before any LoRA residual,
91
105
  * exactly like mlx's QuantizedLinear.__call__. */
92
106
  readonly bias: MlxArray | null = null,
93
- ) {}
107
+ ) {
108
+ this._w = w;
109
+ this._scales = scales;
110
+ this._biases = biases;
111
+ this._spec = spec;
112
+ }
113
+
114
+ get w(): MlxArray { return this._w; }
115
+ get scales(): MlxArray { return this._scales; }
116
+ get biases(): MlxArray | null { return this._biases; }
117
+ get spec(): ops.QuantSpec { return this._spec; }
118
+
119
+ /** Atomically install a quantized payload and return the previous one.
120
+ * This is the sole mutation capability used by sensitivity sweeps. */
121
+ exchangeQuantizedState(next: QuantizedLinearState): QuantizedLinearState {
122
+ const previous = {
123
+ w: this._w,
124
+ scales: this._scales,
125
+ biases: this._biases,
126
+ spec: this._spec,
127
+ };
128
+ this._w = next.w;
129
+ this._scales = next.scales;
130
+ this._biases = next.biases;
131
+ this._spec = next.spec;
132
+ return previous;
133
+ }
94
134
 
95
135
  static load(weights: Weights, path: string, config: ModelConfig): QuantizedLinear {
96
136
  if (!weights.has(`${path}.scales`))
@@ -109,14 +149,21 @@ export class QuantizedLinear {
109
149
  /** (in_features, out_features) from the quantized tensors (reference
110
150
  * _infer_linear_shape: scales are [out, in/group_size]). */
111
151
  get inFeatures(): number {
112
- return this.scales.shape[1]! * this.spec.groupSize;
152
+ return this._scales.shape[1]! * this._spec.groupSize;
113
153
  }
114
154
  get outFeatures(): number {
115
- return this.scales.shape[0]!;
155
+ return this._scales.shape[0]!;
116
156
  }
117
157
 
118
158
  forward(x: MlxArray): MlxArray {
119
- let out = ops.quantizedMatmul(x, this.w, this.scales, this.biases, this.spec, true);
159
+ let out = ops.quantizedMatmul(
160
+ x,
161
+ this._w,
162
+ this._scales,
163
+ this._biases,
164
+ this._spec,
165
+ true,
166
+ );
120
167
  // Additive bias (mlx QuantizedLinear: `x = x + self["bias"]`), before
121
168
  // the LoRA residual (LoRALinear calls the base linear bias-inclusive).
122
169
  if (this.bias) out = disposing(out, ops.add(out, this.bias));
@@ -216,6 +263,15 @@ export type SharedKv =
216
263
 
217
264
  export interface Cache {
218
265
  offset: number;
266
+ /** Stable storage identity for compatibility guards and persistence. */
267
+ signature?(): string;
268
+ /** Physical cache storage consumed by one additional token for one row.
269
+ * Recurrent caches return 0 because their state does not grow with the
270
+ * sequence. Optional for stateless/training adapters that are never
271
+ * admitted or persisted. */
272
+ bytesPerToken?(): number;
273
+ /** state() returned temporary views that the caller must release. */
274
+ readonly stateNeedsDispose?: boolean;
219
275
  /** Compiled-decode trace adapters expose the RoPE offset as an int32
220
276
  * array input here; real caches leave it unset (static int path). */
221
277
  readonly ropeOffsetArr?: MlxArray;
@@ -231,9 +287,56 @@ export interface Cache {
231
287
  * speculative-decode rollback case (trim the last n ≤ γ tips right after a
232
288
  * >1 concat write); rotating caches then physically shrink the buffer tail. */
233
289
  trim(n: number, bypass?: boolean): void;
290
+ /** Speculative verify-round support for NON-trimmable recurrent caches
291
+ * (SSMCache — gated-DeltaNet conv + recurrent state). A cache exposing
292
+ * these is spec-eligible without isTrimmable(): the serve loop arms a
293
+ * round before the verify forward (the layer snapshots pre-round state —
294
+ * free, MLX arrays are immutable — and records its position-local kernel
295
+ * inputs), then resolves it: commit on full accept, or rollback(keep)
296
+ * which restores the snapshot and bit-exactly REPLAYS the first `keep`
297
+ * window tokens through the recurrence (identical arithmetic prefix ⇒
298
+ * identical state). Trimmable caches leave these unset and keep trim(). */
299
+ specRoundBegin?(): void;
300
+ specRoundCommit?(): void;
301
+ specRoundRollback?(keep: number): void;
234
302
  dispose(): void;
235
303
  }
236
304
 
305
+ export function cacheSignature(cache: Cache | undefined): string {
306
+ return cache?.signature?.() ?? "unknown";
307
+ }
308
+
309
+ export interface RowBatchCache extends Cache {
310
+ readonly batchSize: number;
311
+ filterRows(keep: readonly number[]): void;
312
+ extractRow(row: number): Cache | null;
313
+ }
314
+
315
+ export function isRowBatchCache(cache: Cache): cache is RowBatchCache {
316
+ const candidate = cache as Partial<RowBatchCache>;
317
+ return typeof candidate.batchSize === "number" &&
318
+ typeof candidate.filterRows === "function" &&
319
+ typeof candidate.extractRow === "function";
320
+ }
321
+
322
+ export function isPlainKvCache(cache: Cache | undefined): cache is KVCache {
323
+ return cacheSignature(cache) === "kv:plain";
324
+ }
325
+
326
+ export function isQuantizedKvCache(cache: Cache | undefined): cache is QuantizedKVCache {
327
+ return cacheSignature(cache).startsWith("kv:quant:");
328
+ }
329
+
330
+ export function isRotatingPlainCache(cache: Cache | undefined): cache is RotatingKVCache {
331
+ return cacheSignature(cache) === "kv:rotating-plain";
332
+ }
333
+
334
+ export function isRotatingQuantizedCache(
335
+ cache: Cache | undefined,
336
+ ): cache is RotatingQuantizedKVCache {
337
+ return cacheSignature(cache).startsWith("kv:rotating-quant:");
338
+ }
339
+
237
340
  /**
238
341
  * Capability contract for cache layouts that own their dynamic-row batching.
239
342
  * The scheduler uses this for non-K/V state families (for example GLM's
@@ -296,6 +399,13 @@ export class KVCache implements Cache {
296
399
  values: MlxArray | null = null;
297
400
  offset = 0;
298
401
 
402
+ signature(): string { return "kv:plain"; }
403
+
404
+ bytesPerToken(): number {
405
+ const steps = this.keys?.shape[2] ?? 0;
406
+ return steps > 0 ? (this.keys!.nbytes + this.values!.nbytes) / steps : 0;
407
+ }
408
+
299
409
  updateAndFetch(k: MlxArray, v: MlxArray): [MlxArray, MlxArray] {
300
410
  const prev = this.offset;
301
411
  const L = k.shape[2]!;
@@ -469,6 +579,18 @@ export class QuantizedKVCache implements Cache {
469
579
 
470
580
  constructor(readonly groupSize: number, readonly bits: number) {}
471
581
 
582
+ signature(): string { return `kv:quant:${this.bits}:${this.groupSize}`; }
583
+
584
+ bytesPerToken(): number {
585
+ const steps = this.keys?.packed.shape[2] ?? 0;
586
+ if (steps === 0 || !this.keys || !this.values) return 0;
587
+ const tensors = [
588
+ this.keys.packed, this.keys.scales, this.keys.biases,
589
+ this.values.packed, this.values.scales, this.values.biases,
590
+ ];
591
+ return tensors.reduce((bytes, array) => bytes + array.nbytes, 0) / steps;
592
+ }
593
+
472
594
  updateAndFetch(): [MlxArray, MlxArray] {
473
595
  throw new Error("QuantizedKVCache: use updateAndFetchQuantized");
474
596
  }
@@ -681,6 +803,13 @@ export class RotatingKVCache implements Cache {
681
803
  this.maxSize = maxSize;
682
804
  }
683
805
 
806
+ signature(): string { return "kv:rotating-plain"; }
807
+
808
+ bytesPerToken(): number {
809
+ const steps = this.keys?.shape[2] ?? 0;
810
+ return steps > 0 ? (this.keys!.nbytes + this.values!.nbytes) / steps : 0;
811
+ }
812
+
684
813
  /** v with ring contents rearranged into temporal order (keep=0). */
685
814
  #temporalOrder(v: MlxArray): MlxArray {
686
815
  const S = v.shape[2]!;
@@ -1011,6 +1140,18 @@ export class RotatingQuantizedKVCache implements Cache {
1011
1140
  this.maxSize = maxSize;
1012
1141
  }
1013
1142
 
1143
+ signature(): string { return `kv:rotating-quant:${this.bits}:${this.groupSize}`; }
1144
+
1145
+ bytesPerToken(): number {
1146
+ const steps = this.keys?.packed.shape[2] ?? 0;
1147
+ if (steps === 0 || !this.keys || !this.values) return 0;
1148
+ const tensors = [
1149
+ this.keys.packed, this.keys.scales, this.keys.biases,
1150
+ this.values.packed, this.values.scales, this.values.biases,
1151
+ ];
1152
+ return tensors.reduce((bytes, array) => bytes + array.nbytes, 0) / steps;
1153
+ }
1154
+
1014
1155
  updateAndFetch(): [MlxArray, MlxArray] {
1015
1156
  throw new Error("RotatingQuantizedKVCache: use updateAndFetchQuantized");
1016
1157
  }
@@ -1396,6 +1537,7 @@ export const disposeTurboQuant = (t: TurboQuantTensor): void => {
1396
1537
  * a full-window dequant every step; the deferred-InvFWHT trick is a
1397
1538
  * documented non-goal until the quality gate passes. */
1398
1539
  export class TurboQuantKVCache implements Cache {
1540
+ readonly stateNeedsDispose = true;
1399
1541
  static readonly STEP = 256;
1400
1542
  /** Set only by compiled-decode trace adapters (see Cache) — TurboQuant
1401
1543
  * is not a compiled-decode participant in v1 (novel class, monolith
@@ -1409,6 +1551,17 @@ export class TurboQuantKVCache implements Cache {
1409
1551
 
1410
1552
  constructor(readonly kBits: number, readonly vBits: number) {}
1411
1553
 
1554
+ signature(): string { return `kv:turboquant:${this.kBits}:${this.vBits}`; }
1555
+
1556
+ bytesPerToken(): number {
1557
+ const steps = this.#seqLen();
1558
+ if (steps === 0 || !this.#kv) return 0;
1559
+ return [
1560
+ this.#kv.kIdx, this.#kv.kScales, this.#kv.kZeros,
1561
+ this.#kv.vPacked, this.#kv.vScales,
1562
+ ].reduce((bytes, array) => bytes + array.nbytes, 0) / steps;
1563
+ }
1564
+
1412
1565
  get headDim(): number | null {
1413
1566
  return this.#headDim;
1414
1567
  }
@@ -1929,7 +2082,7 @@ function fusedSdpaSupported(q: MlxArray, mask: Mask, groupSize: number, bits: nu
1929
2082
  // stock unfused path everywhere. Also the A/B lever for
1930
2083
  // scripts/bench-fused-prefill.ts. Read per call (cheap next to the
1931
2084
  // FFI work) so tests and paired A/B harnesses can flip it in-process.
1932
- if (process.env.MLX_BUN_NO_FUSED_SDPA === "1") return false;
2085
+ if (runtimeValue("MLX_BUN_NO_FUSED_SDPA") === "1") return false;
1933
2086
  if (bits !== 4 && bits !== 8) return false;
1934
2087
  if (groupSize !== 32 && groupSize !== 64 && groupSize !== 128) return false;
1935
2088
  if (q.dtype !== Dtype.bfloat16 && q.dtype !== Dtype.float16) return false;
@@ -1971,7 +2124,7 @@ export function quantizedSdpa(
1971
2124
  * as a compile-time constant and call this for the rest. The combined
1972
2125
  * predicate is exactly fusedSdpaSupported. */
1973
2126
  export function fusedSdpaRuntimeOk(q: MlxArray, mask: Mask): boolean {
1974
- if (process.env.MLX_BUN_NO_FUSED_SDPA === "1") return false;
2127
+ if (runtimeValue("MLX_BUN_NO_FUSED_SDPA") === "1") return false;
1975
2128
  if (q.dtype !== Dtype.bfloat16 && q.dtype !== Dtype.float16) return false;
1976
2129
  if (mask.mode === "causal" || mask.mode === "") return true;
1977
2130
  if (mask.mode === "array")
@@ -12,6 +12,7 @@
12
12
  import { MlxArray } from "../../mlx/array";
13
13
  import * as ops from "../../mlx/ops";
14
14
  import {
15
+ cacheSignature,
15
16
  disposing,
16
17
  fusedSdpaRuntimeOk,
17
18
  KVCache,
@@ -202,155 +203,58 @@ function donorFullQuantG64B4KeqVScal(layer: DecoderLayer, x: MlxArray, mask: Mas
202
203
  }
203
204
 
204
205
  export class GeneratedGemma4 extends Gemma4Model {
205
- /** Per-layer cache classes must match what this file was generated
206
- * for; anything else runs the monolith path. */
206
+ /** Per-layer cache signatures must match what this file was generated for. */
207
207
  #matches(cache: Cache[]): boolean {
208
208
  return (
209
209
  cache.length === 48 &&
210
- cache[0] instanceof RotatingQuantizedKVCache &&
211
- cache[0].bits === 4 &&
212
- cache[0].groupSize === 64 &&
213
- cache[1] instanceof RotatingQuantizedKVCache &&
214
- cache[1].bits === 4 &&
215
- cache[1].groupSize === 64 &&
216
- cache[2] instanceof RotatingQuantizedKVCache &&
217
- cache[2].bits === 4 &&
218
- cache[2].groupSize === 64 &&
219
- cache[3] instanceof RotatingQuantizedKVCache &&
220
- cache[3].bits === 8 &&
221
- cache[3].groupSize === 64 &&
222
- cache[4] instanceof RotatingQuantizedKVCache &&
223
- cache[4].bits === 4 &&
224
- cache[4].groupSize === 64 &&
225
- cache[5] instanceof QuantizedKVCache &&
226
- cache[5].bits === 4 &&
227
- cache[5].groupSize === 64 &&
228
- cache[6] instanceof RotatingQuantizedKVCache &&
229
- cache[6].bits === 8 &&
230
- cache[6].groupSize === 64 &&
231
- cache[7] instanceof RotatingQuantizedKVCache &&
232
- cache[7].bits === 8 &&
233
- cache[7].groupSize === 64 &&
234
- cache[8] instanceof RotatingQuantizedKVCache &&
235
- cache[8].bits === 8 &&
236
- cache[8].groupSize === 64 &&
237
- cache[9] instanceof RotatingQuantizedKVCache &&
238
- cache[9].bits === 4 &&
239
- cache[9].groupSize === 64 &&
240
- cache[10] instanceof RotatingQuantizedKVCache &&
241
- cache[10].bits === 8 &&
242
- cache[10].groupSize === 64 &&
243
- cache[11] instanceof QuantizedKVCache &&
244
- cache[11].bits === 4 &&
245
- cache[11].groupSize === 64 &&
246
- cache[12] instanceof RotatingQuantizedKVCache &&
247
- cache[12].bits === 8 &&
248
- cache[12].groupSize === 64 &&
249
- cache[13] instanceof RotatingQuantizedKVCache &&
250
- cache[13].bits === 4 &&
251
- cache[13].groupSize === 64 &&
252
- cache[14] instanceof RotatingQuantizedKVCache &&
253
- cache[14].bits === 4 &&
254
- cache[14].groupSize === 64 &&
255
- cache[15] instanceof RotatingQuantizedKVCache &&
256
- cache[15].bits === 4 &&
257
- cache[15].groupSize === 64 &&
258
- cache[16] instanceof RotatingQuantizedKVCache &&
259
- cache[16].bits === 4 &&
260
- cache[16].groupSize === 64 &&
261
- cache[17] instanceof QuantizedKVCache &&
262
- cache[17].bits === 4 &&
263
- cache[17].groupSize === 64 &&
264
- cache[18] instanceof RotatingQuantizedKVCache &&
265
- cache[18].bits === 4 &&
266
- cache[18].groupSize === 64 &&
267
- cache[19] instanceof RotatingQuantizedKVCache &&
268
- cache[19].bits === 4 &&
269
- cache[19].groupSize === 64 &&
270
- cache[20] instanceof RotatingQuantizedKVCache &&
271
- cache[20].bits === 4 &&
272
- cache[20].groupSize === 64 &&
273
- cache[21] instanceof RotatingQuantizedKVCache &&
274
- cache[21].bits === 4 &&
275
- cache[21].groupSize === 64 &&
276
- cache[22] instanceof RotatingQuantizedKVCache &&
277
- cache[22].bits === 4 &&
278
- cache[22].groupSize === 64 &&
279
- cache[23] instanceof QuantizedKVCache &&
280
- cache[23].bits === 4 &&
281
- cache[23].groupSize === 64 &&
282
- cache[24] instanceof RotatingQuantizedKVCache &&
283
- cache[24].bits === 4 &&
284
- cache[24].groupSize === 64 &&
285
- cache[25] instanceof RotatingQuantizedKVCache &&
286
- cache[25].bits === 4 &&
287
- cache[25].groupSize === 64 &&
288
- cache[26] instanceof RotatingQuantizedKVCache &&
289
- cache[26].bits === 4 &&
290
- cache[26].groupSize === 64 &&
291
- cache[27] instanceof RotatingQuantizedKVCache &&
292
- cache[27].bits === 4 &&
293
- cache[27].groupSize === 64 &&
294
- cache[28] instanceof RotatingQuantizedKVCache &&
295
- cache[28].bits === 4 &&
296
- cache[28].groupSize === 64 &&
297
- cache[29] instanceof QuantizedKVCache &&
298
- cache[29].bits === 4 &&
299
- cache[29].groupSize === 64 &&
300
- cache[30] instanceof RotatingQuantizedKVCache &&
301
- cache[30].bits === 4 &&
302
- cache[30].groupSize === 64 &&
303
- cache[31] instanceof RotatingQuantizedKVCache &&
304
- cache[31].bits === 4 &&
305
- cache[31].groupSize === 64 &&
306
- cache[32] instanceof RotatingQuantizedKVCache &&
307
- cache[32].bits === 4 &&
308
- cache[32].groupSize === 64 &&
309
- cache[33] instanceof RotatingQuantizedKVCache &&
310
- cache[33].bits === 4 &&
311
- cache[33].groupSize === 64 &&
312
- cache[34] instanceof RotatingQuantizedKVCache &&
313
- cache[34].bits === 4 &&
314
- cache[34].groupSize === 64 &&
315
- cache[35] instanceof QuantizedKVCache &&
316
- cache[35].bits === 4 &&
317
- cache[35].groupSize === 64 &&
318
- cache[36] instanceof RotatingQuantizedKVCache &&
319
- cache[36].bits === 4 &&
320
- cache[36].groupSize === 64 &&
321
- cache[37] instanceof RotatingQuantizedKVCache &&
322
- cache[37].bits === 4 &&
323
- cache[37].groupSize === 64 &&
324
- cache[38] instanceof RotatingQuantizedKVCache &&
325
- cache[38].bits === 4 &&
326
- cache[38].groupSize === 64 &&
327
- cache[39] instanceof RotatingQuantizedKVCache &&
328
- cache[39].bits === 4 &&
329
- cache[39].groupSize === 64 &&
330
- cache[40] instanceof RotatingQuantizedKVCache &&
331
- cache[40].bits === 4 &&
332
- cache[40].groupSize === 64 &&
333
- cache[41] instanceof QuantizedKVCache &&
334
- cache[41].bits === 4 &&
335
- cache[41].groupSize === 64 &&
336
- cache[42] instanceof RotatingQuantizedKVCache &&
337
- cache[42].bits === 4 &&
338
- cache[42].groupSize === 64 &&
339
- cache[43] instanceof RotatingQuantizedKVCache &&
340
- cache[43].bits === 4 &&
341
- cache[43].groupSize === 64 &&
342
- cache[44] instanceof RotatingQuantizedKVCache &&
343
- cache[44].bits === 4 &&
344
- cache[44].groupSize === 64 &&
345
- cache[45] instanceof RotatingQuantizedKVCache &&
346
- cache[45].bits === 4 &&
347
- cache[45].groupSize === 64 &&
348
- cache[46] instanceof RotatingQuantizedKVCache &&
349
- cache[46].bits === 4 &&
350
- cache[46].groupSize === 64 &&
351
- cache[47] instanceof QuantizedKVCache &&
352
- cache[47].bits === 4 &&
353
- cache[47].groupSize === 64
210
+ cacheSignature(cache[0]) === "kv:rotating-quant:4:64" &&
211
+ cacheSignature(cache[1]) === "kv:rotating-quant:4:64" &&
212
+ cacheSignature(cache[2]) === "kv:rotating-quant:4:64" &&
213
+ cacheSignature(cache[3]) === "kv:rotating-quant:8:64" &&
214
+ cacheSignature(cache[4]) === "kv:rotating-quant:4:64" &&
215
+ cacheSignature(cache[5]) === "kv:quant:4:64" &&
216
+ cacheSignature(cache[6]) === "kv:rotating-quant:8:64" &&
217
+ cacheSignature(cache[7]) === "kv:rotating-quant:8:64" &&
218
+ cacheSignature(cache[8]) === "kv:rotating-quant:8:64" &&
219
+ cacheSignature(cache[9]) === "kv:rotating-quant:4:64" &&
220
+ cacheSignature(cache[10]) === "kv:rotating-quant:8:64" &&
221
+ cacheSignature(cache[11]) === "kv:quant:4:64" &&
222
+ cacheSignature(cache[12]) === "kv:rotating-quant:8:64" &&
223
+ cacheSignature(cache[13]) === "kv:rotating-quant:4:64" &&
224
+ cacheSignature(cache[14]) === "kv:rotating-quant:4:64" &&
225
+ cacheSignature(cache[15]) === "kv:rotating-quant:4:64" &&
226
+ cacheSignature(cache[16]) === "kv:rotating-quant:4:64" &&
227
+ cacheSignature(cache[17]) === "kv:quant:4:64" &&
228
+ cacheSignature(cache[18]) === "kv:rotating-quant:4:64" &&
229
+ cacheSignature(cache[19]) === "kv:rotating-quant:4:64" &&
230
+ cacheSignature(cache[20]) === "kv:rotating-quant:4:64" &&
231
+ cacheSignature(cache[21]) === "kv:rotating-quant:4:64" &&
232
+ cacheSignature(cache[22]) === "kv:rotating-quant:4:64" &&
233
+ cacheSignature(cache[23]) === "kv:quant:4:64" &&
234
+ cacheSignature(cache[24]) === "kv:rotating-quant:4:64" &&
235
+ cacheSignature(cache[25]) === "kv:rotating-quant:4:64" &&
236
+ cacheSignature(cache[26]) === "kv:rotating-quant:4:64" &&
237
+ cacheSignature(cache[27]) === "kv:rotating-quant:4:64" &&
238
+ cacheSignature(cache[28]) === "kv:rotating-quant:4:64" &&
239
+ cacheSignature(cache[29]) === "kv:quant:4:64" &&
240
+ cacheSignature(cache[30]) === "kv:rotating-quant:4:64" &&
241
+ cacheSignature(cache[31]) === "kv:rotating-quant:4:64" &&
242
+ cacheSignature(cache[32]) === "kv:rotating-quant:4:64" &&
243
+ cacheSignature(cache[33]) === "kv:rotating-quant:4:64" &&
244
+ cacheSignature(cache[34]) === "kv:rotating-quant:4:64" &&
245
+ cacheSignature(cache[35]) === "kv:quant:4:64" &&
246
+ cacheSignature(cache[36]) === "kv:rotating-quant:4:64" &&
247
+ cacheSignature(cache[37]) === "kv:rotating-quant:4:64" &&
248
+ cacheSignature(cache[38]) === "kv:rotating-quant:4:64" &&
249
+ cacheSignature(cache[39]) === "kv:rotating-quant:4:64" &&
250
+ cacheSignature(cache[40]) === "kv:rotating-quant:4:64" &&
251
+ cacheSignature(cache[41]) === "kv:quant:4:64" &&
252
+ cacheSignature(cache[42]) === "kv:rotating-quant:4:64" &&
253
+ cacheSignature(cache[43]) === "kv:rotating-quant:4:64" &&
254
+ cacheSignature(cache[44]) === "kv:rotating-quant:4:64" &&
255
+ cacheSignature(cache[45]) === "kv:rotating-quant:4:64" &&
256
+ cacheSignature(cache[46]) === "kv:rotating-quant:4:64" &&
257
+ cacheSignature(cache[47]) === "kv:quant:4:64"
354
258
  );
355
259
  }
356
260
 
@@ -12,6 +12,7 @@
12
12
  import { MlxArray } from "../../mlx/array";
13
13
  import * as ops from "../../mlx/ops";
14
14
  import {
15
+ cacheSignature,
15
16
  disposing,
16
17
  fusedSdpaRuntimeOk,
17
18
  KVCache,
@@ -293,101 +294,40 @@ function donorFullQuantG64B4KeqVMoeScal(layer: DecoderLayer, x: MlxArray, mask:
293
294
  }
294
295
 
295
296
  export class GeneratedGemma4 extends Gemma4Model {
296
- /** Per-layer cache classes must match what this file was generated
297
- * for; anything else runs the monolith path. */
297
+ /** Per-layer cache signatures must match what this file was generated for. */
298
298
  #matches(cache: Cache[]): boolean {
299
299
  return (
300
300
  cache.length === 30 &&
301
- cache[0] instanceof RotatingQuantizedKVCache &&
302
- cache[0].bits === 8 &&
303
- cache[0].groupSize === 64 &&
304
- cache[1] instanceof RotatingQuantizedKVCache &&
305
- cache[1].bits === 4 &&
306
- cache[1].groupSize === 64 &&
307
- cache[2] instanceof RotatingQuantizedKVCache &&
308
- cache[2].bits === 4 &&
309
- cache[2].groupSize === 64 &&
310
- cache[3] instanceof RotatingQuantizedKVCache &&
311
- cache[3].bits === 8 &&
312
- cache[3].groupSize === 64 &&
313
- cache[4] instanceof RotatingQuantizedKVCache &&
314
- cache[4].bits === 8 &&
315
- cache[4].groupSize === 64 &&
316
- cache[5] instanceof QuantizedKVCache &&
317
- cache[5].bits === 8 &&
318
- cache[5].groupSize === 64 &&
319
- cache[6] instanceof RotatingQuantizedKVCache &&
320
- cache[6].bits === 4 &&
321
- cache[6].groupSize === 64 &&
322
- cache[7] instanceof RotatingQuantizedKVCache &&
323
- cache[7].bits === 4 &&
324
- cache[7].groupSize === 64 &&
325
- cache[8] instanceof RotatingQuantizedKVCache &&
326
- cache[8].bits === 8 &&
327
- cache[8].groupSize === 64 &&
328
- cache[9] instanceof RotatingQuantizedKVCache &&
329
- cache[9].bits === 8 &&
330
- cache[9].groupSize === 64 &&
331
- cache[10] instanceof RotatingQuantizedKVCache &&
332
- cache[10].bits === 4 &&
333
- cache[10].groupSize === 64 &&
334
- cache[11] instanceof QuantizedKVCache &&
335
- cache[11].bits === 8 &&
336
- cache[11].groupSize === 64 &&
337
- cache[12] instanceof RotatingQuantizedKVCache &&
338
- cache[12].bits === 8 &&
339
- cache[12].groupSize === 64 &&
340
- cache[13] instanceof RotatingQuantizedKVCache &&
341
- cache[13].bits === 4 &&
342
- cache[13].groupSize === 64 &&
343
- cache[14] instanceof RotatingQuantizedKVCache &&
344
- cache[14].bits === 4 &&
345
- cache[14].groupSize === 64 &&
346
- cache[15] instanceof RotatingQuantizedKVCache &&
347
- cache[15].bits === 4 &&
348
- cache[15].groupSize === 64 &&
349
- cache[16] instanceof RotatingQuantizedKVCache &&
350
- cache[16].bits === 4 &&
351
- cache[16].groupSize === 64 &&
352
- cache[17] instanceof QuantizedKVCache &&
353
- cache[17].bits === 4 &&
354
- cache[17].groupSize === 64 &&
355
- cache[18] instanceof RotatingQuantizedKVCache &&
356
- cache[18].bits === 4 &&
357
- cache[18].groupSize === 64 &&
358
- cache[19] instanceof RotatingQuantizedKVCache &&
359
- cache[19].bits === 4 &&
360
- cache[19].groupSize === 64 &&
361
- cache[20] instanceof RotatingQuantizedKVCache &&
362
- cache[20].bits === 4 &&
363
- cache[20].groupSize === 64 &&
364
- cache[21] instanceof RotatingQuantizedKVCache &&
365
- cache[21].bits === 4 &&
366
- cache[21].groupSize === 64 &&
367
- cache[22] instanceof RotatingQuantizedKVCache &&
368
- cache[22].bits === 4 &&
369
- cache[22].groupSize === 64 &&
370
- cache[23] instanceof QuantizedKVCache &&
371
- cache[23].bits === 4 &&
372
- cache[23].groupSize === 64 &&
373
- cache[24] instanceof RotatingQuantizedKVCache &&
374
- cache[24].bits === 4 &&
375
- cache[24].groupSize === 64 &&
376
- cache[25] instanceof RotatingQuantizedKVCache &&
377
- cache[25].bits === 4 &&
378
- cache[25].groupSize === 64 &&
379
- cache[26] instanceof RotatingQuantizedKVCache &&
380
- cache[26].bits === 4 &&
381
- cache[26].groupSize === 64 &&
382
- cache[27] instanceof RotatingQuantizedKVCache &&
383
- cache[27].bits === 4 &&
384
- cache[27].groupSize === 64 &&
385
- cache[28] instanceof RotatingQuantizedKVCache &&
386
- cache[28].bits === 4 &&
387
- cache[28].groupSize === 64 &&
388
- cache[29] instanceof QuantizedKVCache &&
389
- cache[29].bits === 4 &&
390
- cache[29].groupSize === 64
301
+ cacheSignature(cache[0]) === "kv:rotating-quant:8:64" &&
302
+ cacheSignature(cache[1]) === "kv:rotating-quant:4:64" &&
303
+ cacheSignature(cache[2]) === "kv:rotating-quant:4:64" &&
304
+ cacheSignature(cache[3]) === "kv:rotating-quant:8:64" &&
305
+ cacheSignature(cache[4]) === "kv:rotating-quant:8:64" &&
306
+ cacheSignature(cache[5]) === "kv:quant:8:64" &&
307
+ cacheSignature(cache[6]) === "kv:rotating-quant:4:64" &&
308
+ cacheSignature(cache[7]) === "kv:rotating-quant:4:64" &&
309
+ cacheSignature(cache[8]) === "kv:rotating-quant:8:64" &&
310
+ cacheSignature(cache[9]) === "kv:rotating-quant:8:64" &&
311
+ cacheSignature(cache[10]) === "kv:rotating-quant:4:64" &&
312
+ cacheSignature(cache[11]) === "kv:quant:8:64" &&
313
+ cacheSignature(cache[12]) === "kv:rotating-quant:8:64" &&
314
+ cacheSignature(cache[13]) === "kv:rotating-quant:4:64" &&
315
+ cacheSignature(cache[14]) === "kv:rotating-quant:4:64" &&
316
+ cacheSignature(cache[15]) === "kv:rotating-quant:4:64" &&
317
+ cacheSignature(cache[16]) === "kv:rotating-quant:4:64" &&
318
+ cacheSignature(cache[17]) === "kv:quant:4:64" &&
319
+ cacheSignature(cache[18]) === "kv:rotating-quant:4:64" &&
320
+ cacheSignature(cache[19]) === "kv:rotating-quant:4:64" &&
321
+ cacheSignature(cache[20]) === "kv:rotating-quant:4:64" &&
322
+ cacheSignature(cache[21]) === "kv:rotating-quant:4:64" &&
323
+ cacheSignature(cache[22]) === "kv:rotating-quant:4:64" &&
324
+ cacheSignature(cache[23]) === "kv:quant:4:64" &&
325
+ cacheSignature(cache[24]) === "kv:rotating-quant:4:64" &&
326
+ cacheSignature(cache[25]) === "kv:rotating-quant:4:64" &&
327
+ cacheSignature(cache[26]) === "kv:rotating-quant:4:64" &&
328
+ cacheSignature(cache[27]) === "kv:rotating-quant:4:64" &&
329
+ cacheSignature(cache[28]) === "kv:rotating-quant:4:64" &&
330
+ cacheSignature(cache[29]) === "kv:quant:4:64"
391
331
  );
392
332
  }
393
333