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
package/src/index.ts CHANGED
@@ -20,6 +20,26 @@ export {
20
20
  type RuntimeModel,
21
21
  } from "./model/factory";
22
22
  export { Qwen3Model } from "./model/qwen3";
23
+ export { configFingerprint } from "./model/fingerprint";
24
+ export {
25
+ BUILTIN_ARTIFACT_PROFILES,
26
+ ENGINE_CAPABILITIES,
27
+ externalArtifactFingerprint,
28
+ resolveModelProfile,
29
+ type ArtifactModelProfile,
30
+ type EngineCapability,
31
+ type FidelityTarget,
32
+ type FidelityTier,
33
+ type GenerationLoop,
34
+ type ModelArtifactIdentity,
35
+ type ModelExecutionComposition,
36
+ type ModelGraph,
37
+ type ModelLoader,
38
+ type ModelProfile,
39
+ type ModelSpecialization,
40
+ type ResolveModelProfileOptions,
41
+ type ResolvedModelProfile,
42
+ } from "./model/profile";
23
43
  export { generate } from "./generate";
24
44
  export { loadTokenizer } from "./tokenizer";
25
45
  export { embedOne, embedMany, isEmbeddingModel, withInstruction, type EmbedResult } from "./embed";
@@ -10,6 +10,7 @@
10
10
  import { JobStore } from "./db";
11
11
  import { getRunner, makeEmit } from "./runner";
12
12
  import type { JobRunner } from "./types";
13
+ import { runtimeValue } from "../runtime-config";
13
14
 
14
15
  /** kind → module to dynamically import so it registers its runner. Real job
15
16
  * kinds are built by parallel efforts; importing the module is expected to
@@ -58,8 +59,8 @@ async function main(): Promise<void> {
58
59
  // Own fresh connection — overrides come from env so a spawned child finds
59
60
  // the same DB/logs the parent used (tests set these to a tmp dir).
60
61
  const store = new JobStore(
61
- process.env.MLX_BUN_JOBS_DB || undefined,
62
- process.env.MLX_BUN_JOBS_DIR || undefined,
62
+ runtimeValue("MLX_BUN_JOBS_DB") || undefined,
63
+ runtimeValue("MLX_BUN_JOBS_DIR") || undefined,
63
64
  );
64
65
 
65
66
  const row = store.get(jobId);
@@ -0,0 +1,199 @@
1
+ import type { KvQuantSpec, ModelConfig, TurboQuantScheme } from "./config";
2
+
3
+ const BF16_BYTES = 2;
4
+
5
+ export type KvQuantOverride = "off" | "config" | number | undefined;
6
+
7
+ export interface KvSchemeOptions {
8
+ kvBits?: number;
9
+ kvGroupSize?: number;
10
+ kvConfig?: KvQuantSpec[];
11
+ quantizedKvStart?: number;
12
+ turboQuant?: TurboQuantScheme;
13
+ }
14
+
15
+ interface ResolvedKvSchemeOptions extends Omit<KvSchemeOptions, "kvConfig" | "turboQuant"> {
16
+ readonly kvConfig?: readonly Readonly<KvQuantSpec>[];
17
+ readonly turboQuant?: Readonly<TurboQuantScheme>;
18
+ }
19
+
20
+ export type KvSchemeKind = "bf16" | "affine-uniform" | "affine-config" | "turbo";
21
+
22
+ export interface KvGeometry {
23
+ fullBytesPerToken: number;
24
+ slidingBytesPerToken: number;
25
+ linearStateBytes: number;
26
+ window: number;
27
+ }
28
+
29
+ /** Bytes per stored affine-quantized KV element, including scale and bias. */
30
+ export function kvQuantBytesPerElement(bits: number, groupSize: number): number {
31
+ return bits / 8 + 4 / groupSize;
32
+ }
33
+
34
+ export function kvGeometry(config: ModelConfig, options: KvSchemeOptions = {}): KvGeometry {
35
+ const text = config.text;
36
+ const byLayer = options.kvConfig?.length
37
+ ? new Map(options.kvConfig.map((entry) => [entry.layerIdx, entry]))
38
+ : null;
39
+ const uniformBytes = options.kvBits
40
+ ? kvQuantBytesPerElement(options.kvBits, options.kvGroupSize ?? 64)
41
+ : BF16_BYTES;
42
+ const elementBytes = (layer: number): number => {
43
+ const entry = byLayer?.get(layer);
44
+ return entry
45
+ ? kvQuantBytesPerElement(entry.bits, entry.groupSize)
46
+ : byLayer ? BF16_BYTES : uniformBytes;
47
+ };
48
+
49
+ let linearLayers = 0;
50
+ let fullBytesPerToken = 0;
51
+ let slidingBytesPerToken = 0;
52
+ for (let layer = 0; layer < text.numHiddenLayers; layer++) {
53
+ const type = text.layerTypes[layer] ?? "full_attention";
54
+ if (type === "linear_attention") {
55
+ linearLayers++;
56
+ } else if (type === "sliding_attention") {
57
+ slidingBytesPerToken +=
58
+ 2 * text.numKeyValueHeads * text.headDim * elementBytes(layer);
59
+ } else {
60
+ fullBytesPerToken +=
61
+ 2 * text.numGlobalKeyValueHeads * text.globalHeadDim * elementBytes(layer);
62
+ }
63
+ }
64
+ const convDim = 2 * text.linearNumKeyHeads * text.linearKeyHeadDim +
65
+ text.linearNumValueHeads * text.linearValueHeadDim;
66
+ const linearStateBytes = linearLayers === 0 ? 0 : linearLayers * (
67
+ text.linearNumValueHeads * text.linearValueHeadDim * text.linearKeyHeadDim * 4 +
68
+ Math.max(0, text.linearConvKernelDim - 1) * convDim * BF16_BYTES
69
+ );
70
+ return {
71
+ fullBytesPerToken,
72
+ slidingBytesPerToken,
73
+ linearStateBytes,
74
+ window: text.slidingWindow,
75
+ };
76
+ }
77
+
78
+ export function kvBytesAt(
79
+ config: ModelConfig,
80
+ tokens: number,
81
+ options: KvSchemeOptions = {},
82
+ ): number {
83
+ const value = kvGeometry(config, options);
84
+ return value.fullBytesPerToken * tokens +
85
+ value.slidingBytesPerToken * Math.min(tokens, value.window) +
86
+ value.linearStateBytes;
87
+ }
88
+
89
+ export class KvScheme {
90
+ readonly kind: KvSchemeKind;
91
+ readonly options: Readonly<ResolvedKvSchemeOptions>;
92
+
93
+ constructor(kind: KvSchemeKind, options: KvSchemeOptions) {
94
+ this.kind = kind;
95
+ const kvConfig = options.kvConfig?.map((entry) =>
96
+ Object.freeze({ ...entry }),
97
+ );
98
+ const turboQuant = options.turboQuant
99
+ ? Object.freeze({ ...options.turboQuant })
100
+ : undefined;
101
+ this.options = Object.freeze({
102
+ ...options,
103
+ ...(kvConfig ? { kvConfig: Object.freeze(kvConfig) } : {}),
104
+ ...(turboQuant ? { turboQuant } : {}),
105
+ });
106
+ }
107
+
108
+ get quantized(): boolean {
109
+ return this.kind !== "bf16";
110
+ }
111
+
112
+ get cacheKey(): string {
113
+ if (this.kind === "turbo") {
114
+ const turbo = this.options.turboQuant!;
115
+ return `turbo-k${turbo.kBits}v${turbo.vBits}`;
116
+ }
117
+ if (this.kind === "affine-uniform") return `kv${this.options.kvBits}`;
118
+ if (this.kind === "affine-config") return "config";
119
+ return "bf16";
120
+ }
121
+
122
+ get label(): string {
123
+ if (this.kind === "turbo") {
124
+ const turbo = this.options.turboQuant!;
125
+ return `turbo k${turbo.kBits}v${turbo.vBits}`;
126
+ }
127
+ if (this.kind === "affine-uniform") return `uniform-kv${this.options.kvBits}`;
128
+ if (this.kind === "affine-config") return "mixed (kv_config.json)";
129
+ return "bf16";
130
+ }
131
+
132
+ bytesAt(config: ModelConfig, tokens: number): number {
133
+ // TurboQuant stays conservatively billed as bf16 until its packed layout
134
+ // exposes a stable projector.
135
+ return kvBytesAt(config, tokens, this.fitOptions);
136
+ }
137
+
138
+ /** Mutable compatibility value for the numerical generator. The scheme
139
+ * keeps its declaration immutable and hands legacy consumers owned copies. */
140
+ get generationOptions(): KvSchemeOptions {
141
+ const { kvConfig, turboQuant, ...scalar } = this.options;
142
+ return {
143
+ ...scalar,
144
+ ...(kvConfig
145
+ ? { kvConfig: kvConfig.map((entry) => ({ ...entry })) }
146
+ : {}),
147
+ ...(turboQuant
148
+ ? { turboQuant: { ...turboQuant } }
149
+ : {}),
150
+ };
151
+ }
152
+
153
+ get fitOptions(): KvSchemeOptions {
154
+ return this.kind === "turbo" ? {} : this.generationOptions;
155
+ }
156
+
157
+ /** The current batch engine accepts only per-layer affine schemes whose
158
+ * named cache instances can perform the required conversion. The capability
159
+ * probe is mandatory for quantized schemes so config shape alone can never
160
+ * authorize placement. */
161
+ batchable(config: ModelConfig, canConvert?: (layerIdx: number) => boolean): boolean {
162
+ if (this.kind === "bf16") return true;
163
+ if (this.kind !== "affine-config") return false;
164
+ if (!canConvert) return false;
165
+ return this.options.kvConfig!.every((entry) => {
166
+ if (entry.layerIdx < 0 || entry.layerIdx >= config.text.numHiddenLayers) return false;
167
+ return (config.text.layerTypes[entry.layerIdx] ?? "full_attention") !== "linear_attention" &&
168
+ canConvert(entry.layerIdx);
169
+ });
170
+ }
171
+ }
172
+
173
+ export function resolveKvScheme(input: {
174
+ override?: KvQuantOverride;
175
+ turboQuant?: TurboQuantScheme;
176
+ config?: readonly KvQuantSpec[] | null;
177
+ missingConfig?: "bf16" | "error";
178
+ }): KvScheme {
179
+ if (input.turboQuant) {
180
+ return new KvScheme("turbo", {
181
+ turboQuant: input.turboQuant,
182
+ quantizedKvStart: 0,
183
+ });
184
+ }
185
+ if (input.override === "off" || input.override === undefined)
186
+ return new KvScheme("bf16", {});
187
+ if (input.override === "config") {
188
+ if (!input.config?.length) {
189
+ if (input.missingConfig === "error")
190
+ throw new Error("model has no kv_config.json (--kv-quant config)");
191
+ return new KvScheme("bf16", {});
192
+ }
193
+ return new KvScheme("affine-config", { kvConfig: [...input.config] });
194
+ }
195
+ return new KvScheme("affine-uniform", {
196
+ kvBits: input.override,
197
+ quantizedKvStart: 0,
198
+ });
199
+ }