@mlx-bun/inference 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1475 -2
  3. package/THIRD_PARTY_NOTICES.md +3404 -0
  4. package/dist/native/libmlx_bun_ane.dylib +0 -0
  5. package/dist/native/libmlx_bun_expert_io.dylib +0 -0
  6. package/dist/native/mlx-bun-frame-extract +0 -0
  7. package/examples/fit-model.ts +25 -0
  8. package/examples/qwen3-forward.ts +42 -0
  9. package/examples/qwen3-generate.ts +28 -0
  10. package/examples/trellis-expand.ts +23 -0
  11. package/package.json +129 -4
  12. package/src/adapters/available.ts +110 -0
  13. package/src/adapters/index.ts +3 -0
  14. package/src/adapters/manager.ts +316 -0
  15. package/src/artifacts/auxiliary-files.ts +45 -0
  16. package/src/artifacts/config-dialects.ts +94 -0
  17. package/src/artifacts/config.ts +341 -0
  18. package/src/artifacts/draft-vocabulary.ts +30 -0
  19. package/src/artifacts/expert-offload-build.ts +75 -0
  20. package/src/artifacts/expert-offload.ts +89 -0
  21. package/src/artifacts/experts/index.ts +3 -0
  22. package/src/artifacts/experts/io.ts +386 -0
  23. package/src/artifacts/experts/residency.ts +1134 -0
  24. package/src/artifacts/experts/usage.ts +415 -0
  25. package/src/artifacts/fingerprint.ts +44 -0
  26. package/src/artifacts/glm52/container.ts +305 -0
  27. package/src/artifacts/glm52/expert-layout.ts +249 -0
  28. package/src/artifacts/glm52/index.ts +7 -0
  29. package/src/artifacts/glm52/kernel-layout.ts +124 -0
  30. package/src/artifacts/glm52/layout.ts +152 -0
  31. package/src/artifacts/glm52/memory.ts +500 -0
  32. package/src/artifacts/glm52/resident-weights.ts +135 -0
  33. package/src/artifacts/glm52/weights.ts +503 -0
  34. package/src/artifacts/glm52-config.ts +262 -0
  35. package/src/artifacts/identity.ts +94 -0
  36. package/src/artifacts/index.ts +15 -0
  37. package/src/artifacts/mmap.ts +90 -0
  38. package/src/artifacts/safetensors-writer.ts +249 -0
  39. package/src/artifacts/safetensors.ts +164 -0
  40. package/src/artifacts/turboquant-fold.ts +42 -0
  41. package/src/artifacts/weight-audit.ts +43 -0
  42. package/src/artifacts/weights.ts +255 -0
  43. package/src/contracts/index.ts +2 -0
  44. package/src/contracts/mlx/attention.ts +8 -0
  45. package/src/contracts/mlx/cache.ts +510 -0
  46. package/src/contracts/mlx/checkpoint.ts +10 -0
  47. package/src/contracts/mlx/draft-checkpoint.ts +14 -0
  48. package/src/contracts/mlx/draft-projection.ts +27 -0
  49. package/src/contracts/mlx/draft-target.ts +84 -0
  50. package/src/contracts/mlx/drafter.ts +176 -0
  51. package/src/contracts/mlx/forward-work.ts +23 -0
  52. package/src/contracts/mlx/glm52-weights.ts +25 -0
  53. package/src/contracts/mlx/graph.ts +309 -0
  54. package/src/contracts/mlx/head.ts +6 -0
  55. package/src/contracts/mlx/index.ts +15 -0
  56. package/src/contracts/mlx/kv-codec.ts +9 -0
  57. package/src/contracts/mlx/media.ts +113 -0
  58. package/src/contracts/mlx/positions.ts +16 -0
  59. package/src/contracts/mlx/row-table.ts +2 -0
  60. package/src/contracts/mlx/trainable.ts +103 -0
  61. package/src/contracts/mlx/whisper.ts +96 -0
  62. package/src/contracts/portable/composition.ts +106 -0
  63. package/src/contracts/portable/denoising.ts +17 -0
  64. package/src/contracts/portable/execution.ts +79 -0
  65. package/src/contracts/portable/generation.ts +103 -0
  66. package/src/contracts/portable/graph.ts +80 -0
  67. package/src/contracts/portable/index.ts +15 -0
  68. package/src/contracts/portable/memory-plan.ts +26 -0
  69. package/src/contracts/portable/object-cache.ts +8 -0
  70. package/src/contracts/portable/prefill.ts +63 -0
  71. package/src/contracts/portable/prefix-cache.ts +33 -0
  72. package/src/contracts/portable/prompt.ts +2 -0
  73. package/src/contracts/portable/resources.ts +25 -0
  74. package/src/contracts/portable/rollback.ts +7 -0
  75. package/src/contracts/portable/sampling.ts +44 -0
  76. package/src/contracts/portable/scheduling.ts +54 -0
  77. package/src/contracts/portable/token-delivery.ts +4 -0
  78. package/src/contracts/portable/tsconfig.json +14 -0
  79. package/src/embeddings/index.ts +1 -0
  80. package/src/embeddings/text.ts +85 -0
  81. package/src/execution/admission.ts +59 -0
  82. package/src/execution/batch-group.ts +1240 -0
  83. package/src/execution/batch-types.ts +225 -0
  84. package/src/execution/cancellation.ts +38 -0
  85. package/src/execution/continuation-request.ts +45 -0
  86. package/src/execution/continuation-types.ts +10 -0
  87. package/src/execution/coordinator.ts +70 -0
  88. package/src/execution/denoising-group.ts +180 -0
  89. package/src/execution/engine.ts +56 -0
  90. package/src/execution/fill-group.ts +505 -0
  91. package/src/execution/fit.ts +184 -0
  92. package/src/execution/gateway-binding.ts +178 -0
  93. package/src/execution/grammar-group.ts +224 -0
  94. package/src/execution/index.ts +18 -0
  95. package/src/execution/methods.ts +75 -0
  96. package/src/execution/mixed-iteration.ts +96 -0
  97. package/src/execution/plan.ts +65 -0
  98. package/src/execution/prefill-cohort.ts +100 -0
  99. package/src/execution/prefill-rows.ts +263 -0
  100. package/src/execution/request-policy.ts +19 -0
  101. package/src/execution/row-sampling.ts +49 -0
  102. package/src/execution/scheduler.ts +92 -0
  103. package/src/execution/session.ts +247 -0
  104. package/src/execution/speculative-group.ts +797 -0
  105. package/src/execution/tasks.ts +44 -0
  106. package/src/generation/autoregressive.ts +840 -0
  107. package/src/generation/bindings/autoregressive.ts +104 -0
  108. package/src/generation/bindings/denoising.ts +60 -0
  109. package/src/generation/bindings/prefill-policy.ts +36 -0
  110. package/src/generation/checkpoint-identity.ts +60 -0
  111. package/src/generation/denoising.ts +85 -0
  112. package/src/generation/diffusion.ts +583 -0
  113. package/src/generation/fill/echo-index.ts +188 -0
  114. package/src/generation/fill/index.ts +3 -0
  115. package/src/generation/fill/proposal.ts +69 -0
  116. package/src/generation/fill/schema-rows.ts +506 -0
  117. package/src/generation/fill/session.ts +464 -0
  118. package/src/generation/fill/tool-boundary.ts +103 -0
  119. package/src/generation/fill-append.ts +58 -0
  120. package/src/generation/generate.ts +44 -0
  121. package/src/generation/grammar-step.ts +39 -0
  122. package/src/generation/index.ts +14 -0
  123. package/src/generation/phase-dispatch.ts +115 -0
  124. package/src/generation/prefill.ts +33 -0
  125. package/src/generation/result.ts +49 -0
  126. package/src/generation/scopes.ts +157 -0
  127. package/src/generation/speculative/acceptance.ts +41 -0
  128. package/src/generation/speculative/adaptive-draft-gate.ts +166 -0
  129. package/src/generation/speculative/bindings/assistant-rows.ts +102 -0
  130. package/src/generation/speculative/bindings/autoregressive-rows.ts +124 -0
  131. package/src/generation/speculative/bindings/binding.ts +106 -0
  132. package/src/generation/speculative/bindings/deepspec-rows.ts +33 -0
  133. package/src/generation/speculative/bindings/draft-target.ts +10 -0
  134. package/src/generation/speculative/bindings/glm52-mtp-rows.ts +128 -0
  135. package/src/generation/speculative/bindings/projected-context-rows.ts +78 -0
  136. package/src/generation/speculative/bindings/projected-draft-rows.ts +95 -0
  137. package/src/generation/speculative/bindings/qwen-mtp-rows.ts +336 -0
  138. package/src/generation/speculative/bindings/two-model-rows.ts +63 -0
  139. package/src/generation/speculative/cache-identity.ts +16 -0
  140. package/src/generation/speculative/draft-kind.ts +149 -0
  141. package/src/generation/speculative/draft-policy.ts +41 -0
  142. package/src/generation/speculative/draft-registry.ts +118 -0
  143. package/src/generation/speculative/draft-vocab.ts +110 -0
  144. package/src/generation/speculative/index.ts +17 -0
  145. package/src/generation/speculative/output.ts +49 -0
  146. package/src/generation/speculative/round.ts +307 -0
  147. package/src/generation/speculative/source.ts +144 -0
  148. package/src/generation/speculative/sources/assistant-source.ts +64 -0
  149. package/src/generation/speculative/sources/deepspec-source.ts +70 -0
  150. package/src/generation/speculative/sources/dflash-source.ts +84 -0
  151. package/src/generation/speculative/sources/dflash2-source.ts +86 -0
  152. package/src/generation/speculative/sources/glm52-mtp-source.ts +66 -0
  153. package/src/generation/speculative/sources/ngram-source.ts +165 -0
  154. package/src/generation/speculative/sources/qwen-mtp-source.ts +154 -0
  155. package/src/generation/speculative/sources/two-model.ts +75 -0
  156. package/src/generation/types.ts +194 -0
  157. package/src/index.ts +20 -0
  158. package/src/input/audio/audiotoolbox.ts +112 -0
  159. package/src/input/audio/decode.ts +133 -0
  160. package/src/input/audio/features.ts +202 -0
  161. package/src/input/audio/index.ts +6 -0
  162. package/src/input/audio/transcode.ts +67 -0
  163. package/src/input/audio/whisper-mel.ts +185 -0
  164. package/src/input/audio/whisper-tokenizer.ts +238 -0
  165. package/src/input/chat-template.ts +389 -0
  166. package/src/input/index.ts +6 -0
  167. package/src/input/media-fetch.ts +439 -0
  168. package/src/input/packed-mixed.ts +43 -0
  169. package/src/input/special-tokens.ts +75 -0
  170. package/src/input/token-groups.ts +49 -0
  171. package/src/input/tokenizer.ts +336 -0
  172. package/src/input/tool-call.ts +689 -0
  173. package/src/input/vision/index.ts +3 -0
  174. package/src/input/vision/preprocess.ts +247 -0
  175. package/src/input/vision/prompt.ts +398 -0
  176. package/src/input/vision/qwen3vl-preprocess.ts +409 -0
  177. package/src/input/vision/qwen3vl-prompt.ts +237 -0
  178. package/src/input/vision/video-frames.ts +100 -0
  179. package/src/kernels/ane/fill.ts +101 -0
  180. package/src/kernels/ane/linear.ts +416 -0
  181. package/src/kernels/attention/flash.ts +694 -0
  182. package/src/kernels/attention/kvq4-decode.ts +155 -0
  183. package/src/kernels/attention/masks.ts +40 -0
  184. package/src/kernels/attention/multi-query.ts +193 -0
  185. package/src/kernels/attention/paged.ts +130 -0
  186. package/src/kernels/delta/gated.ts +306 -0
  187. package/src/kernels/delta/index.ts +3 -0
  188. package/src/kernels/delta/silu-rms-heads.ts +69 -0
  189. package/src/kernels/delta/state.ts +74 -0
  190. package/src/kernels/gated-rms-norm.ts +64 -0
  191. package/src/kernels/glm52/layout.ts +37 -0
  192. package/src/kernels/glm52/streamed-experts.ts +360 -0
  193. package/src/kernels/logits.ts +38 -0
  194. package/src/kernels/quantization/affine-row.ts +154 -0
  195. package/src/kernels/quantization/affine-rows.ts +36 -0
  196. package/src/kernels/quantization/affine-split-mma.ts +144 -0
  197. package/src/kernels/quantization/affine3-mma.ts +117 -0
  198. package/src/kernels/quantization/affine3-rows.ts +103 -0
  199. package/src/kernels/quantization/affine4-mma.ts +113 -0
  200. package/src/kernels/quantization/affine4-rows.ts +102 -0
  201. package/src/kernels/residual-rms-norm.ts +65 -0
  202. package/src/kernels/sampling/index.ts +2 -0
  203. package/src/kernels/sampling/normalized-argmax.ts +116 -0
  204. package/src/kernels/sampling/token-bitmask.ts +52 -0
  205. package/src/kernels/softcap.ts +35 -0
  206. package/src/kernels/trellis/codebook.ts +123 -0
  207. package/src/kernels/trellis/down-codebook.ts +184 -0
  208. package/src/kernels/trellis/down-factored.ts +180 -0
  209. package/src/kernels/trellis/down-k3-interleaved-factored.ts +146 -0
  210. package/src/kernels/trellis/down-mma-wide.ts +195 -0
  211. package/src/kernels/trellis/down-mma.ts +145 -0
  212. package/src/kernels/trellis/expand.ts +42 -0
  213. package/src/kernels/trellis/gate-up-codebook-mma.ts +141 -0
  214. package/src/kernels/trellis/gate-up-codebook.ts +137 -0
  215. package/src/kernels/trellis/gate-up-factored.ts +197 -0
  216. package/src/kernels/trellis/gate-up-mma-wide.ts +147 -0
  217. package/src/kernels/trellis/gate-up-mma.ts +148 -0
  218. package/src/kernels/trellis/gate-up.ts +248 -0
  219. package/src/kernels/trellis/geometry.ts +22 -0
  220. package/src/kernels/trellis/index.ts +103 -0
  221. package/src/kernels/trellis/launch.ts +12 -0
  222. package/src/kernels/trellis/mixed-gate-up-factored.ts +119 -0
  223. package/src/kernels/trellis/mixed-gate-up.ts +146 -0
  224. package/src/kernels/trellis/qualified.ts +34 -0
  225. package/src/kernels/trellis/reduce.ts +150 -0
  226. package/src/kernels/trellis/scatter.ts +407 -0
  227. package/src/kernels/trellis/splitk-prefill.ts +152 -0
  228. package/src/kernels/trellis/tiled-prefill.ts +131 -0
  229. package/src/kernels/trellis/vector-expand.ts +58 -0
  230. package/src/kernels/trellis/wide-prefill.ts +89 -0
  231. package/src/kernels/turboquant/decode.ts +82 -0
  232. package/src/kernels/turboquant/index.ts +5 -0
  233. package/src/kernels/turboquant/inverse.ts +122 -0
  234. package/src/kernels/turboquant/ops.ts +860 -0
  235. package/src/kernels/turboquant/signs.ts +130 -0
  236. package/src/kernels/turboquant/tables.ts +124 -0
  237. package/src/layers/affine-verify-linear.ts +75 -0
  238. package/src/layers/ane-prefill-split.ts +283 -0
  239. package/src/layers/compiled-normalization.ts +41 -0
  240. package/src/layers/delta-heads.ts +23 -0
  241. package/src/layers/dense-embedding.ts +29 -0
  242. package/src/layers/dense-linear.ts +32 -0
  243. package/src/layers/dequantized-linear.ts +72 -0
  244. package/src/layers/folded-attention.ts +42 -0
  245. package/src/layers/geglu.ts +130 -0
  246. package/src/layers/helpers.ts +7 -0
  247. package/src/layers/index.ts +36 -0
  248. package/src/layers/kv4-decode-attention.ts +15 -0
  249. package/src/layers/layer-norm.ts +24 -0
  250. package/src/layers/loading.ts +92 -0
  251. package/src/layers/lora.ts +150 -0
  252. package/src/layers/normalization.ts +9 -0
  253. package/src/layers/prefix-layout.ts +33 -0
  254. package/src/layers/quantized-append-attention.ts +32 -0
  255. package/src/layers/quantized-attention.ts +353 -0
  256. package/src/layers/quantized-embedding.ts +39 -0
  257. package/src/layers/quantized-linear.ts +137 -0
  258. package/src/layers/quantized-switch-linear.ts +37 -0
  259. package/src/layers/qwen-append.ts +12 -0
  260. package/src/layers/qwen-mrope.ts +238 -0
  261. package/src/layers/rope-2d.ts +110 -0
  262. package/src/layers/rope.ts +389 -0
  263. package/src/layers/swiglu.ts +23 -0
  264. package/src/layers/trellis-codebook-down.ts +52 -0
  265. package/src/layers/trellis-codebook-gate-up.ts +42 -0
  266. package/src/layers/trellis-down.ts +117 -0
  267. package/src/layers/trellis-gate-up.ts +71 -0
  268. package/src/layers/trellis-linear.ts +211 -0
  269. package/src/layers/trellis-prompt.ts +102 -0
  270. package/src/layers/trellis-reduce-gate-up.ts +73 -0
  271. package/src/layers/trellis-scatter-down.ts +98 -0
  272. package/src/models/ane-install.ts +74 -0
  273. package/src/models/audio/conformer.ts +656 -0
  274. package/src/models/cache-composition.ts +44 -0
  275. package/src/models/capabilities.ts +89 -0
  276. package/src/models/chat-template.ts +10 -0
  277. package/src/models/composition.ts +107 -0
  278. package/src/models/diffusion-gemma/experts.ts +59 -0
  279. package/src/models/diffusion-gemma/family.ts +21 -0
  280. package/src/models/diffusion-gemma/model.ts +900 -0
  281. package/src/models/diffusion-gemma/vision.ts +549 -0
  282. package/src/models/drafter-loaders.ts +49 -0
  283. package/src/models/drafters.ts +39 -0
  284. package/src/models/factory.ts +351 -0
  285. package/src/models/families.ts +70 -0
  286. package/src/models/family.ts +125 -0
  287. package/src/models/gemma4/assistant-target.ts +46 -0
  288. package/src/models/gemma4/assistant.ts +327 -0
  289. package/src/models/gemma4/blocks.ts +755 -0
  290. package/src/models/gemma4/compiled-decode.ts +452 -0
  291. package/src/models/gemma4/family.ts +39 -0
  292. package/src/models/gemma4/gemma4-12b.ts +677 -0
  293. package/src/models/gemma4/gemma4-26b.ts +544 -0
  294. package/src/models/gemma4/gemma4-e4b.ts +599 -0
  295. package/src/models/gemma4/graphs.ts +147 -0
  296. package/src/models/gemma4/media.ts +88 -0
  297. package/src/models/gemma4/model.ts +860 -0
  298. package/src/models/gemma4/serving-blocks.ts +72 -0
  299. package/src/models/gemma4/trainable.ts +186 -0
  300. package/src/models/gemma4/written-blocks.ts +232 -0
  301. package/src/models/gemma4/written-forward.ts +159 -0
  302. package/src/models/gemma4/written-input.ts +29 -0
  303. package/src/models/glm52/atlas.ts +507 -0
  304. package/src/models/glm52/coupling.ts +388 -0
  305. package/src/models/glm52/dsa.ts +601 -0
  306. package/src/models/glm52/family.ts +20 -0
  307. package/src/models/glm52/mla.ts +812 -0
  308. package/src/models/glm52/model.ts +1127 -0
  309. package/src/models/glm52/moe.ts +223 -0
  310. package/src/models/glm52/mtp.ts +60 -0
  311. package/src/models/glm52/pilot.ts +537 -0
  312. package/src/models/glm52/reference.ts +445 -0
  313. package/src/models/glm52/residency.ts +557 -0
  314. package/src/models/glm52/streamed-experts.ts +447 -0
  315. package/src/models/graph.ts +59 -0
  316. package/src/models/implementation.ts +230 -0
  317. package/src/models/index.ts +15 -0
  318. package/src/models/media-input.ts +15 -0
  319. package/src/models/memory-plan.ts +39 -0
  320. package/src/models/minicpm5/family.ts +29 -0
  321. package/src/models/minicpm5/model.ts +394 -0
  322. package/src/models/minicpm5/trainable.ts +90 -0
  323. package/src/models/profile.ts +337 -0
  324. package/src/models/qwen/blocks.ts +658 -0
  325. package/src/models/qwen/checkpoint.ts +190 -0
  326. package/src/models/qwen/families.ts +57 -0
  327. package/src/models/qwen/media-input.ts +161 -0
  328. package/src/models/qwen/mtp.ts +101 -0
  329. package/src/models/qwen/qwen3-moe.ts +355 -0
  330. package/src/models/qwen/qwen3.ts +323 -0
  331. package/src/models/qwen/qwen38-27b-trellis-m1max.ts +1532 -0
  332. package/src/models/qwen/qwen38-27b-trellis-m4pro.ts +1092 -0
  333. package/src/models/qwen/qwen3_5.ts +433 -0
  334. package/src/models/qwen/written-layers.ts +285 -0
  335. package/src/models/row-table.ts +1 -0
  336. package/src/models/runtime.ts +73 -0
  337. package/src/models/speculative/deepspec-artifact.ts +10 -0
  338. package/src/models/speculative/deepspec.ts +744 -0
  339. package/src/models/speculative/dflash.ts +553 -0
  340. package/src/models/speculative/dflash2-artifact.ts +9 -0
  341. package/src/models/speculative/dflash2-operations.ts +1 -0
  342. package/src/models/speculative/dflash2.ts +576 -0
  343. package/src/models/speculative/loader.ts +29 -0
  344. package/src/models/support.ts +79 -0
  345. package/src/models/universal/archs.ts +365 -0
  346. package/src/models/universal/blocks.ts +479 -0
  347. package/src/models/universal/dense.ts +255 -0
  348. package/src/models/universal/family.ts +17 -0
  349. package/src/models/vision/qwen3vl.ts +566 -0
  350. package/src/models/vision/siglip.ts +520 -0
  351. package/src/models/vision/unified.ts +176 -0
  352. package/src/models/whisper/family.ts +19 -0
  353. package/src/models/whisper/fast.ts +734 -0
  354. package/src/models/whisper/model.ts +430 -0
  355. package/src/runtime/compiled-trace.ts +16 -0
  356. package/src/runtime/config.ts +77 -0
  357. package/src/runtime/expert-trace.ts +71 -0
  358. package/src/runtime/graph-forward.ts +65 -0
  359. package/src/runtime/integers.ts +6 -0
  360. package/src/runtime/native.ts +16 -0
  361. package/src/runtime/resources.ts +53 -0
  362. package/src/runtime/row-operations.ts +42 -0
  363. package/src/runtime/trace.ts +161 -0
  364. package/src/sampling/curve.ts +122 -0
  365. package/src/sampling/draft.ts +55 -0
  366. package/src/sampling/extras.ts +45 -0
  367. package/src/sampling/filters.ts +134 -0
  368. package/src/sampling/grammar.ts +630 -0
  369. package/src/sampling/hlg.ts +290 -0
  370. package/src/sampling/index.ts +9 -0
  371. package/src/sampling/processors.ts +142 -0
  372. package/src/sampling/sampler.ts +120 -0
  373. package/src/sampling/step.ts +343 -0
  374. package/src/sampling/types.ts +161 -0
  375. package/src/sampling/window-filters.ts +46 -0
  376. package/src/scoring/decisions.ts +96 -0
  377. package/src/scoring/full-sequence.ts +103 -0
  378. package/src/scoring/index.ts +9 -0
  379. package/src/scoring/kl.ts +29 -0
  380. package/src/scoring/perplexity.ts +165 -0
  381. package/src/scoring/response-logps.ts +65 -0
  382. package/src/state/affine-attention.ts +180 -0
  383. package/src/state/attachment.ts +68 -0
  384. package/src/state/attention-read.ts +215 -0
  385. package/src/state/batched-kv.ts +294 -0
  386. package/src/state/batched-mask.ts +445 -0
  387. package/src/state/batched-quant.ts +389 -0
  388. package/src/state/batched-quantized-kv.ts +209 -0
  389. package/src/state/batched-rotating-quant.ts +457 -0
  390. package/src/state/batched-rotating-state.ts +149 -0
  391. package/src/state/batched-rotating.ts +430 -0
  392. package/src/state/batched-row-storage.ts +179 -0
  393. package/src/state/batched-ssm.ts +54 -0
  394. package/src/state/batched-turboquant-kv.ts +144 -0
  395. package/src/state/bf16-first-kv.ts +663 -0
  396. package/src/state/cache-service.ts +592 -0
  397. package/src/state/capabilities.ts +65 -0
  398. package/src/state/checkpoint.ts +46 -0
  399. package/src/state/continuation-persistence.ts +126 -0
  400. package/src/state/decode-step-inputs.ts +31 -0
  401. package/src/state/decoded-kv-donor.ts +12 -0
  402. package/src/state/delayed-quantized-kv.ts +141 -0
  403. package/src/state/delayed-rotating-quantized-kv.ts +178 -0
  404. package/src/state/delayed-turboquant-kv.ts +123 -0
  405. package/src/state/durability.ts +214 -0
  406. package/src/state/encoder-cache.ts +26 -0
  407. package/src/state/full-kv-row-append.ts +33 -0
  408. package/src/state/full-kv-row-donor.ts +54 -0
  409. package/src/state/full-prefill-padding.ts +56 -0
  410. package/src/state/full-prefill-row.ts +112 -0
  411. package/src/state/full-transitioning-kv-rows.ts +70 -0
  412. package/src/state/glm52-cache.ts +783 -0
  413. package/src/state/grouped-heads-kv4-cache.ts +26 -0
  414. package/src/state/index.ts +38 -0
  415. package/src/state/kv-attention-view.ts +77 -0
  416. package/src/state/kv-budget.ts +14 -0
  417. package/src/state/kv-scheme.ts +315 -0
  418. package/src/state/kv-storage.ts +57 -0
  419. package/src/state/kv-tensor-rows.ts +212 -0
  420. package/src/state/kv.ts +324 -0
  421. package/src/state/kv4-head256-cache.ts +46 -0
  422. package/src/state/latent-legos.ts +895 -0
  423. package/src/state/layout.ts +277 -0
  424. package/src/state/leases.ts +26 -0
  425. package/src/state/paged/cache.ts +689 -0
  426. package/src/state/paged/codec.ts +36 -0
  427. package/src/state/paged/rows.ts +223 -0
  428. package/src/state/persistence-types.ts +173 -0
  429. package/src/state/persistence-worker.ts +83 -0
  430. package/src/state/persistence.ts +1036 -0
  431. package/src/state/persistence.worker.d.ts +3 -0
  432. package/src/state/persistence.worker.js +264 -0
  433. package/src/state/prefix-cache.ts +685 -0
  434. package/src/state/quantized-kv.ts +369 -0
  435. package/src/state/quantized-tensor.ts +26 -0
  436. package/src/state/request-policy.ts +48 -0
  437. package/src/state/retention-policy.ts +37 -0
  438. package/src/state/rollback.ts +131 -0
  439. package/src/state/rotating-kv-donor.ts +35 -0
  440. package/src/state/rotating-kv-layout.ts +341 -0
  441. package/src/state/rotating-kv.ts +529 -0
  442. package/src/state/rotating-quantized-kv.ts +616 -0
  443. package/src/state/rotating-row-transaction.ts +35 -0
  444. package/src/state/rows.ts +104 -0
  445. package/src/state/softcap-attention.ts +118 -0
  446. package/src/state/speculative/glm52-mtp-state.ts +38 -0
  447. package/src/state/speculative/qwen-mtp-state.ts +34 -0
  448. package/src/state/speculative-rotating-kv.ts +113 -0
  449. package/src/state/ssd-cache.ts +434 -0
  450. package/src/state/ssm-prefill-padding.ts +39 -0
  451. package/src/state/ssm.ts +422 -0
  452. package/src/state/target-layout.ts +7 -0
  453. package/src/state/tiered-prefix-cache.ts +45 -0
  454. package/src/state/training-cache.ts +300 -0
  455. package/src/state/transitioning-kv-rows.ts +267 -0
  456. package/src/state/turboquant-attention.ts +97 -0
  457. package/src/state/turboquant-codec.ts +90 -0
  458. package/src/state/turboquant-kv.ts +442 -0
  459. package/src/state/views.ts +26 -0
  460. package/src/transcription/index.ts +3 -0
  461. package/src/transcription/silero-vad.ts +379 -0
  462. package/src/transcription/whisper/decode.ts +773 -0
  463. package/src/transcription/whisper/format.ts +74 -0
  464. package/src/transcription/whisper/index.ts +4 -0
  465. package/src/transcription/whisper/timing.ts +274 -0
  466. package/src/transcription/whisper/transcribe.ts +394 -0
  467. package/src/transcription/whisper/types.ts +22 -0
@@ -0,0 +1,452 @@
1
+ import { rowOperationFor } from "../../runtime/row-operations";
2
+ // Compiled decode step (Phase A of `02d723a:docs/archive/investigations/optimization_plan.md`).
3
+ //
4
+ // The single-token decode graph is identical token-to-token except for
5
+ // integer state (RoPE offset, cache write position, active length). This
6
+ // module wraps one whole step — embed → all layers → finalNorm → logits —
7
+ // in an mx.compile'd closure (packages/mlx/src/compile.ts) so the per-step graph
8
+ // is REPLAYED in C++ instead of rebuilt through ~2000 bun:ffi crossings.
9
+ //
10
+ // How the per-step state crosses into a fixed graph:
11
+ // - RoPE offset and ring write positions enter as int32 ARRAY inputs
12
+ // (fast_rope_dynamic / slice_update_dynamic) — values change, graph
13
+ // doesn't.
14
+ // - Shapes that grow (the active KV prefix) enter as inputs and the
15
+ // closure is compiled shapeless=true: dim sizes may vary per step,
16
+ // ndim/dtype may not.
17
+ //
18
+ // The trace runs the graph's own one-row decode operation (decode.one) against the stand-in
19
+ // each cache supplies for its slot (CompiledDecodeCache in
20
+ // packages/inference/src/contracts/mlx/cache.ts; the stand-ins live beside their
21
+ // cache classes in packages/inference/src/state/) — so the compiled graph
22
+ // is the production op sequence by construction, not a reimplementation, and this
23
+ // module names no cache class. Every layer reads its stand-in through the
24
+ // decode read (`appendDecode`), as the ordinary decode reads the real cache.
25
+ // Per-cache fetch strategy (see DecodeStepPlan in
26
+ // packages/inference/src/contracts/mlx/cache.ts):
27
+ // - "concat": graph returns this step's (quantized) KV row; the buffer
28
+ // write stays OUTSIDE, right after the step — the buffer keeps a single
29
+ // reference at its slice_update, so mlx donates it (no per-step copy).
30
+ // - "ring": write in-graph at a dynamic position, read the full updated
31
+ // ring — bit-exact with the rotating steady state, where a concat
32
+ // would permute KV positions and change reduction order.
33
+ //
34
+ // The composition chooses this step at load, for storage whose every cache it
35
+ // drives, and the scheduler never falls back: it refuses active LoRA
36
+ // adapters (their weights would bake into the trace as constants); a step this
37
+ // module cannot take throws.
38
+
39
+ import { disposeResources } from "../../runtime/resources";
40
+ import { MlxArray } from "@mlx-bun/mlx/array";
41
+ import { CompiledFunction } from "@mlx-bun/mlx/compile";
42
+ import * as ops from "@mlx-bun/mlx/ops";
43
+ import { decodeStepInputs } from "../../state/decode-step-inputs";
44
+ import { setCompiledTrace } from "../../runtime/compiled-trace";
45
+ import type { Cache, CompiledDecodeCache, DecodeSlot, DecodeTrace } from "../../contracts/mlx/cache";
46
+ import type { MlxCompiledDecodeStep, MlxRowTable, MlxCapturingForward } from "../../contracts/mlx/graph";
47
+
48
+ /** What the runner reads of the Gemma graph it compiles (the graph passes
49
+ * itself; a structural type keeps the graph file and this one acyclic). */
50
+ export interface CompiledGemmaTarget {
51
+ readonly config: { readonly text: { readonly numKvSharedLayers: number; readonly enableMoeBlock: boolean } };
52
+ readonly perLayerWidth: number;
53
+ readonly embedScale: number;
54
+ readonly embed: { encode(ids: MlxArray): MlxArray };
55
+ readonly finalNorm: { forward(h: MlxArray): MlxArray };
56
+ /** A decoder layer reading its cache for one decode position. A donor layer
57
+ * returns its read, which the runner disposes. */
58
+ readonly layers: readonly {
59
+ forward(x: MlxArray, cache: Cache, phase: "decode", donor: null,
60
+ perLayerInput: null): { h: MlxArray; donor: { dispose(): void } | null };
61
+ }[];
62
+ materializeGraphConstants(): void;
63
+ /** The one-row decode operation the trace records. */
64
+ readonly decode: MlxRowTable<MlxCapturingForward>;
65
+ logitsFromHidden(hidden: MlxArray): MlxArray;
66
+ /** Written graphs name their plain operations for the enclosing trace. */
67
+ readonly traceDecode?: MlxCapturingForward;
68
+ readonly traceLogits?: (hidden: MlxArray) => MlxArray;
69
+ readonly traceLayers?: CompiledGemmaTarget["layers"];
70
+ }
71
+
72
+ /** Graph-shape signature: anything that changes the traced op sequence
73
+ * must appear here. That is the slots' cache kinds and quant params, and no
74
+ * kernel set: every composed affine set decodes with the one unfused kernel,
75
+ * which the quantized stand-ins are built with. Offsets/capacities don't —
76
+ * they're array values or shapeless dims. */
77
+ function closureKey(slots: DecodeSlot[]): string {
78
+ return slots.map((d) => d.key).join(",");
79
+ }
80
+
81
+ /** The stand-ins for `slots` over the closure inputs that follow the token and
82
+ * RoPE offset, in slot order. */
83
+ function traceCaches(slots: readonly DecodeSlot[], inputs: readonly MlxArray[], ropeOff: MlxArray): DecodeTrace[] {
84
+ let pos = 2;
85
+ return slots.map((slot) => {
86
+ const trace = slot.trace(inputs.slice(pos, pos + slot.inputs), ropeOff);
87
+ pos += slot.inputs;
88
+ return trace;
89
+ });
90
+ }
91
+
92
+ function makeTraceFn(model: CompiledGemmaTarget, slots: DecodeSlot[]) {
93
+ const decode = model.traceDecode ?? rowOperationFor(model.decode, 1);
94
+ const head = model.traceLogits ?? model.logitsFromHidden.bind(model);
95
+ return (inputs: MlxArray[]): MlxArray[] => {
96
+ const adapters = traceCaches(slots, inputs, inputs[1]!);
97
+ setCompiledTrace(true);
98
+ try {
99
+ const ids = ops.reshape(inputs[0]!, [1, 1]);
100
+ const h = decode(ids, adapters, null) as MlxArray;
101
+ ids.dispose();
102
+ const logits = head(h);
103
+ h.dispose();
104
+ return [logits, ...adapters.flatMap((a) => a.outs)];
105
+ } finally {
106
+ setCompiledTrace(false);
107
+ }
108
+ };
109
+ }
110
+
111
+ // --- segmented mode (dense models) ------------------------------------------
112
+ // Measured: the concat fetch materializes a copy
113
+ // of each growing cache's active window every step — per-op encode
114
+ // overhead + 2× byte traffic + allocator churn from monotonically
115
+ // growing transient sizes. Ring-phase caches (write-in-graph, read the
116
+ // updated buffer) cost nothing extra. So for models without KV sharing /
117
+ // per-layer inputs / MoE, the compiled graph is SEGMENTED at growing-
118
+ // cache layers: those layers run uncompiled (today's exact view-based
119
+ // ops — no copies, bit-exact trivially) and everything between them
120
+ // replays compiled. At steady state on the 12B that is 6 JS layers and
121
+ // 7 compiled segments per step.
122
+
123
+ /** Trace one compiled segment: layers [from, to) — all ring caches, one slot each —
124
+ * with embed before (first) and finalNorm+logits after (last).
125
+ * Input layout: [idsOrH, ropeOffset, ...ring slots in layer order].
126
+ * Output layout: [hOrLogits, ...ring buffer updates]. */
127
+ function makeSegmentTraceFn(
128
+ model: CompiledGemmaTarget, slots: DecodeSlot[], from: number, to: number,
129
+ first: boolean, last: boolean,
130
+ ) {
131
+ const layers = model.traceLayers ?? model.layers;
132
+ const head = model.traceLogits ?? model.logitsFromHidden.bind(model);
133
+ return (inputs: MlxArray[]): MlxArray[] => {
134
+ setCompiledTrace(true);
135
+ try {
136
+ const adapters = traceCaches(slots, inputs, inputs[1]!);
137
+
138
+ let h: MlxArray;
139
+ if (first) {
140
+ const ids = ops.reshape(inputs[0]!, [1, 1]);
141
+ const embedded = model.embed.encode(ids);
142
+ ids.dispose();
143
+ h = ops.mulScalar(embedded, model.embedScale);
144
+ embedded.dispose();
145
+ } else {
146
+ // owned alias of the carried hidden state (constant [1,1,H])
147
+ h = ops.reshape(inputs[0]!, inputs[0]!.shape);
148
+ }
149
+
150
+ for (let i = from; i < to; i++) {
151
+ const { h: next, donor } = layers[i]!.forward(h, adapters[i - from]!, "decode", null, null);
152
+ h.dispose();
153
+ h = next;
154
+ donor?.dispose();
155
+ }
156
+
157
+ let out = h;
158
+ if (last) {
159
+ const normed = model.finalNorm.forward(h);
160
+ h.dispose();
161
+ out = head(normed);
162
+ normed.dispose();
163
+ }
164
+ return [out, ...adapters.flatMap((a) => a.outs)];
165
+ } finally {
166
+ setCompiledTrace(false);
167
+ }
168
+ };
169
+ }
170
+
171
+ // --- runner -----------------------------------------------------------------
172
+
173
+ const runners = new WeakMap<object, CompiledDecode>();
174
+
175
+ /** The Gemma graph's compiled decode step (its `compiledDecodeStep`). */
176
+ export class CompiledDecode implements MlxCompiledDecodeStep {
177
+ /** Total compiled steps executed (tests assert the compiled path ran
178
+ * rather than silently falling back). */
179
+ static stepsExecuted = 0;
180
+ /** Total UNEXPECTED retraces observed (a shapeless closure tracing more
181
+ * than once). Must stay 0: a retrace means per-step JS graph builds
182
+ * sneaked back in, which both wrecks the perf win and signals shape
183
+ * drift. Surfaced loudly; tests assert on it. */
184
+ static unexpectedRetraces = 0;
185
+
186
+ #disposed = false;
187
+ #closures = new Map<string, CompiledFunction>();
188
+ /** Segmented mode: per layout key, one closure per segment (null for
189
+ * empty middle segments, which are identity). */
190
+ #segClosures = new Map<string, (CompiledFunction | null)[]>();
191
+ /** Closure keys whose apply failed (e.g. a primitive without
192
+ * output_shapes under shapeless replay): never re-trace these — the
193
+ * step throws at once instead of paying a trace per
194
+ * generation. */
195
+ #broken = new Set<string>();
196
+ /** Dense models (no KV sharing, per-layer inputs, or MoE) use the
197
+ * segmented form — growing-cache layers uncompiled, ring runs
198
+ * compiled. Models with cross-layer plumbing keep the whole-graph
199
+ * form (measured net-win on e4b; the concat copies it pays are the
200
+ * price of the sharing). */
201
+ readonly #segmented: boolean;
202
+
203
+ private constructor(readonly model: CompiledGemmaTarget) {
204
+ // A fresh resume has no prefill to evaluate lazy FP32 constants. Capture
205
+ // their values, not their construction graph, in every compiled closure.
206
+ model.materializeGraphConstants();
207
+ const t = model.config.text;
208
+ this.#segmented =
209
+ t.numKvSharedLayers === 0 && !t.enableMoeBlock && model.perLayerWidth === 0;
210
+ }
211
+
212
+ static for(model: CompiledGemmaTarget): CompiledDecode {
213
+ let r = runners.get(model);
214
+ if (!r) {
215
+ r = new CompiledDecode(model);
216
+ runners.set(model, r);
217
+ }
218
+ return r;
219
+ }
220
+
221
+ /** Release an existing model-owned runner without materializing constants or
222
+ * creating a new native closure. Call only after all borrowers have stopped;
223
+ * a no-op for a graph that owns none. */
224
+ static release(model: object): void {
225
+ const runner = runners.get(model);
226
+ if (runner) runner.dispose();
227
+ }
228
+
229
+ /** One decode step: consumes the pending token array (uint32 [1],
230
+ * unevaluated is fine), advances every cache by one position, returns
231
+ * the logits node plus the cache-update nodes that must ride the same
232
+ * async_eval. Throws on unsupported state, leaving
233
+ * the caches as they were (any growth already done is benign). */
234
+ step(cur: MlxArray, caches: Cache[]): { logits: MlxArray; evalWith: MlxArray[] } {
235
+ if (this.#disposed) throw new Error("compiled decode runner is disposed");
236
+ const offset0 = caches[0]!.offset;
237
+ for (const c of caches)
238
+ if (c.offset !== offset0)
239
+ throw new Error("compiled decode: cache offsets diverged");
240
+ const decodable = caches as CompiledDecodeCache[];
241
+ return this.#segmented
242
+ ? this.#stepSegmented(cur, decodable, offset0)
243
+ : this.#stepWhole(cur, decodable, offset0);
244
+ }
245
+
246
+ #stepWhole(cur: MlxArray, decodable: CompiledDecodeCache[], offset0: number): { logits: MlxArray; evalWith: MlxArray[] } {
247
+ const plans = decodable.map((c) => c.prepareDecodeStep());
248
+ const slots = decodable.map((c, i) => c.decodeSlot(plans[i]!));
249
+ const key = closureKey(slots);
250
+ if (this.#broken.has(key)) throw new Error(`compiled decode: known-broken closure ${key}`);
251
+
252
+ // gather inputs — [cur, ropeOffset, ...per-cache slots]
253
+ const inputs: MlxArray[] = [cur];
254
+ const temps: MlxArray[] = [];
255
+ const ropeOff = ops.fromInt32([offset0], []);
256
+ temps.push(ropeOff);
257
+ inputs.push(ropeOff);
258
+ const step = decodeStepInputs(temps);
259
+ for (let i = 0; i < decodable.length; i++)
260
+ inputs.push(...decodable[i]!.decodeInputs(plans[i]!, step));
261
+
262
+ let closure = this.#closures.get(key);
263
+ if (!closure) {
264
+ closure = new CompiledFunction(makeTraceFn(this.model, slots), true);
265
+ this.#closures.set(key, closure);
266
+ }
267
+
268
+ let outs: MlxArray[];
269
+ try {
270
+ outs = closure.apply(inputs);
271
+ } catch (e) {
272
+ this.#broken.add(key);
273
+ throw e;
274
+ } finally {
275
+ for (const t of temps) t.dispose();
276
+ }
277
+ if (closure.traceCount > 1) {
278
+ CompiledDecode.unexpectedRetraces++;
279
+ console.warn(
280
+ `compiled decode: closure retraced (count=${closure.traceCount}) — ` +
281
+ `input ndim/dtype drifted for key ${key}`,
282
+ );
283
+ }
284
+
285
+ const logits = outs[0]!;
286
+ const evalWith: MlxArray[] = [];
287
+ let oi = 1;
288
+ for (let i = 0; i < decodable.length; i++) {
289
+ const slot = slots[i]!;
290
+ evalWith.push(...decodable[i]!.commitDecodeStep(slot, outs.slice(oi, oi + slot.outputs)));
291
+ oi += slot.outputs;
292
+ }
293
+ CompiledDecode.stepsExecuted++;
294
+ return { logits, evalWith };
295
+ }
296
+
297
+ #stepSegmented(cur: MlxArray, caches: CompiledDecodeCache[], offset0: number): { logits: MlxArray; evalWith: MlxArray[] } {
298
+ const phases = caches.map((c) => c.decodePhase());
299
+ // ring caches need their host bookkeeping (growth/trim/rotation) now;
300
+ // growing caches keep it inside their layer's real decode read (appendDecode)
301
+ const plans = caches.map((c, i) =>
302
+ phases[i] === "ring" ? c.prepareDecodeStep() : null,
303
+ );
304
+ const slots = caches.map((c, i) => (plans[i] ? c.decodeSlot(plans[i]!) : null));
305
+
306
+ // layout: consecutive ring layers form compiled segments, each
307
+ // growing-cache layer runs uncompiled between them
308
+ const segs: { from: number; to: number }[] = [];
309
+ const jsLayers: number[] = [];
310
+ let runStart = 0;
311
+ for (let i = 0; i < caches.length; i++) {
312
+ if (phases[i] === "concat") {
313
+ segs.push({ from: runStart, to: i });
314
+ jsLayers.push(i);
315
+ runStart = i + 1;
316
+ }
317
+ }
318
+ segs.push({ from: runStart, to: caches.length });
319
+
320
+ // layout key: ring slot tags at their positions; js layers only by
321
+ // position (their quant params live outside the closures)
322
+ const key = "seg|" + slots.map((slot) => slot?.key ?? "js").join(",");
323
+ if (this.#broken.has(key)) throw new Error(`compiled decode: known-broken closure ${key}`);
324
+
325
+ let closures = this.#segClosures.get(key);
326
+ if (!closures) {
327
+ closures = segs.map(() => null);
328
+ this.#segClosures.set(key, closures);
329
+ }
330
+
331
+ const ropeOff = ops.fromInt32([offset0], []);
332
+ const stepTemps: MlxArray[] = [ropeOff];
333
+ const step = decodeStepInputs(stepTemps);
334
+
335
+ const evalWith: MlxArray[] = [];
336
+ let carried = cur; // seg 0 consumes the token array; later, hidden state
337
+ let carriedOwned = false; // cur belongs to the caller
338
+ // Mid-step failure safety (a later segment's closure.apply can throw at
339
+ // first trace AFTER earlier layers already advanced): the step must be
340
+ // TRANSACTIONAL, or the caller's uncompiled re-forward of the same token
341
+ // double-writes the committed layers (+1 offset skew forever, silently
342
+ // corrupted attention). Two mechanisms, chosen by what each phase allows:
343
+ // - ring segments: the ring commit is a pure host-side handle swap with
344
+ // no reader between here and step end (each cache is read only by its
345
+ // own layer, inside the closure that produced the update), so the
346
+ // adopts are STAGED and committed only once every segment and js layer
347
+ // has succeeded. On failure the staged buffers are disposed and the
348
+ // ring caches are exactly at their pre-step state (prepareDecodeStep's
349
+ // growth/trim/rotate bookkeeping is benign for the uncompiled path —
350
+ // the same invariant #stepWhole and generate.ts's fallback rely on).
351
+ // - js (concat) layers: layer.forward commits via the cache's real
352
+ // decode read (appendDecode) mid-loop, so on failure the commit is ROLLED BACK by
353
+ // reverting offset (and ring index) — trim(1) semantics. The written
354
+ // KV row beyond the reverted offset is dead data the re-forward
355
+ // overwrites at the same position (the decode read writes at offset/
356
+ // ringIdx), so post-recovery state equals a single clean write; the
357
+ // in-place S=1 write slot is re-derived from the reverted ringIdx.
358
+ const stagedAdopts: { c: CompiledDecodeCache; slot: DecodeSlot; bufs: MlxArray[] }[] = [];
359
+ const committedJs: { c: CompiledDecodeCache; offsetBefore: number }[] = [];
360
+ try {
361
+ for (let s = 0; s < segs.length; s++) {
362
+ const { from, to } = segs[s]!;
363
+ const firstSeg = s === 0;
364
+ const lastSeg = s === segs.length - 1;
365
+ if (firstSeg || lastSeg || from < to) {
366
+ const ringSlots: DecodeSlot[] = [];
367
+ const inputs: MlxArray[] = [carried, ropeOff];
368
+ for (let i = from; i < to; i++) {
369
+ ringSlots.push(slots[i]!);
370
+ inputs.push(...caches[i]!.decodeInputs(plans[i]!, step));
371
+ }
372
+ let closure = closures[s];
373
+ if (!closure) {
374
+ closure = new CompiledFunction(
375
+ makeSegmentTraceFn(this.model, ringSlots, from, to, firstSeg, lastSeg),
376
+ true,
377
+ );
378
+ closures[s] = closure;
379
+ }
380
+ let outs: MlxArray[];
381
+ try {
382
+ outs = closure.apply(inputs);
383
+ } catch (e) {
384
+ this.#broken.add(key);
385
+ throw e;
386
+ }
387
+ if (closure.traceCount > 1) {
388
+ CompiledDecode.unexpectedRetraces++;
389
+ console.warn(`compiled decode: segment ${s} retraced for key ${key}`);
390
+ }
391
+ if (carriedOwned) carried.dispose();
392
+ carried = outs[0]!;
393
+ carriedOwned = true;
394
+ // ring updates are ancestors of the carried hidden state (the
395
+ // in-graph fetch reads the updated buffer): no eval roots. The
396
+ // host-side adoption is deferred to the end of the step (see above).
397
+ let oi = 1;
398
+ for (let i = from; i < to; i++) {
399
+ const slot = slots[i]!;
400
+ stagedAdopts.push({ c: caches[i]!, slot, bufs: outs.slice(oi, oi + slot.outputs) });
401
+ oi += slot.outputs;
402
+ }
403
+ }
404
+ if (s < jsLayers.length) {
405
+ const li = jsLayers[s]!;
406
+ const c = caches[li]!;
407
+ committedJs.push({ c, offsetBefore: c.offset });
408
+ const { h: next, donor } = this.model.layers[li]!.forward(carried, c, "decode", null, null);
409
+ if (carriedOwned) carried.dispose();
410
+ carried = next;
411
+ carriedOwned = true;
412
+ donor?.dispose();
413
+ }
414
+ }
415
+ // every segment and js layer succeeded — commit the staged ring adopts
416
+ for (const { c, slot, bufs } of stagedAdopts) c.commitDecodeStep(slot, bufs);
417
+ // The js layers read their caches through the ordinary decode read, so
418
+ // those caches take the post-dispatch hook the scheduler gives them after
419
+ // the decode operation (batch-group): a row layout's per-row RoPE
420
+ // positions stay fixed across a step and advance only there
421
+ // (`BatchedRotatingQuantCache.ropeOffsetArr`), and without it every
422
+ // later step ropes at the positions of the step that last refreshed them.
423
+ for (const { c } of committedJs) (c as { releaseRopeArr?: () => void }).releaseRopeArr?.();
424
+ } catch (e) {
425
+ // unwind: free staged (never-adopted) ring buffers and the owned hidden
426
+ // state, and revert the js layers' committed writes, so the caller's
427
+ // uncompiled re-forward of this token starts from the pre-step state.
428
+ for (const { bufs } of stagedAdopts) for (const b of bufs) b.dispose();
429
+ for (const { c, offsetBefore } of committedJs)
430
+ if (c.offset > offsetBefore) c.trim(c.offset - offsetBefore);
431
+ if (carriedOwned) carried.dispose();
432
+ throw e;
433
+ } finally {
434
+ for (const t of stepTemps) t.dispose();
435
+ }
436
+ CompiledDecode.stepsExecuted++;
437
+ return { logits: carried, evalWith };
438
+ }
439
+
440
+ /** Free compiled closures (model unload). */
441
+ dispose(): void {
442
+ if (this.#disposed) return;
443
+ this.#disposed = true;
444
+ if (runners.get(this.model) === this) runners.delete(this.model);
445
+ const closures = [...this.#closures.values(), ...[...this.#segClosures.values()].flat()]
446
+ .filter((closure): closure is CompiledFunction => closure !== null);
447
+ this.#closures.clear();
448
+ this.#segClosures.clear();
449
+ this.#broken.clear();
450
+ disposeResources(closures);
451
+ }
452
+ }
@@ -0,0 +1,39 @@
1
+ import type { SentinelTokenTexts, MediaTokenTexts } from "../../input/special-tokens";
2
+ import { L1, type TrainingDefaults, configuredMoe, defineFamily } from "../family";
3
+
4
+ /** Artifact fingerprints used by the written Gemma 4 graph entries
5
+ * (`graphs.ts`). Metadata only. */
6
+ export const GEMMA_GRAPH_FINGERPRINTS = Object.freeze({
7
+ "12b": "9f812d2eb461fcbe",
8
+ "e4b": "418e9adc386ea67c",
9
+ "26b": "c9dd67ed5a525231",
10
+ });
11
+
12
+ /** Gemma-family towers (Gemma 4 and DiffusionGemma) train on longer sequences than the generic default. */
13
+ export const GEMMA_TRAINING_DEFAULTS: TrainingDefaults = Object.freeze({ maxSeqLength: 8192 });
14
+
15
+ const GEMMA_SENTINELS: SentinelTokenTexts = Object.freeze({
16
+ toolCallStart: "<|tool_call>", toolCallEnd: "<tool_call|>", channelStart: "<|channel>", channelEnd: "<channel|>",
17
+ });
18
+ export const GEMMA_MEDIA_TOKENS: MediaTokenTexts = Object.freeze({
19
+ vision: Object.freeze({ image: "<|image|>", begin: "<|image>", end: "<image|>" }),
20
+ audio: Object.freeze({ audio: "<|audio|>", begin: "<|audio>", end: "<audio|>" }),
21
+ });
22
+
23
+ export const GEMMA4_FAMILY = defineFamily({
24
+ graph: "gemma4",
25
+ accepts: config => config.modelType.startsWith("gemma4"),
26
+ hasModelType: modelType => modelType.startsWith("gemma4"),
27
+ tier: "targeted",
28
+ label: "gemma4*",
29
+ loader: "safetensors",
30
+ loop: "autoregressive",
31
+ fidelity: L1,
32
+ specialization: "dedicated",
33
+ profileId: "gemma4-dedicated",
34
+ capabilities: ["gemma4-graph"],
35
+ moe: configuredMoe,
36
+ trainingDefaults: GEMMA_TRAINING_DEFAULTS,
37
+ sentinels: GEMMA_SENTINELS,
38
+ mediaTokens: GEMMA_MEDIA_TOKENS,
39
+ });