@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,394 @@
1
+ import type { MlxCacheLayer, MlxMixedRange, MlxSequenceRange } from "../../contracts/mlx/graph";
2
+ // Concrete model graph for MiniCPM5-1B-OptiQ-4bit.
3
+ // Port target: mlx_lm.models.llama from the oracle venv. Each block is built
4
+ // once and reads its cache through the cache contract for the phase its caller
5
+ // names (`ReadPhase`); the cache was composed with its read, so no block builds
6
+ // a mask or chooses an attention kernel. The training forward
7
+ // (`forwardTraining`) reads its training caches the same way and adds only the
8
+ // prefix-shared block RoPE.
9
+
10
+ import { MlxArray } from "@mlx-bun/mlx/array";
11
+ import * as ops from "@mlx-bun/mlx/ops";
12
+ import { LoraState } from "../../layers/lora";
13
+ import type { GraphDeclaration } from "../../contracts/portable/graph";
14
+ import type { MlxRowTable, MlxCapturingForward, MlxDeclaredGraph, MlxHeadForward, MlxPhaseForward, MlxPromptRange, MlxTokenPhases, MlxVerifyForward } from "../../contracts/mlx/graph";
15
+ import type { TrainableGraph } from "../../contracts/mlx/trainable";
16
+ import { miniCpmTrainable } from "./trainable";
17
+ import { declareGraph } from "../capabilities";
18
+ import { DEFAULT_PHASE_ROWS, rowTable, type ReadPhase } from "../graph";
19
+ import type { ModelConfig } from "../../artifacts/config";
20
+ import type { Weights } from "../../artifacts/weights";
21
+ import type { Cache, TrainingAttentionCache } from "../../contracts/mlx/cache";
22
+ import { disposing } from "../../layers/helpers";
23
+ import { RMSNorm } from "../../layers/normalization";
24
+ import { QuantizedEmbedding } from "../../layers/quantized-embedding";
25
+ import { QuantizedLinear, QuantizedLinearPlain } from "../../layers/quantized-linear";
26
+ import { composedFullAttentionCache } from "../../state/bf16-first-kv";
27
+ import { AttentionMasks } from "../../state/attention-read";
28
+ import { deferredTurboQuantKernels } from "../../state/turboquant-attention";
29
+ import { compiledSwiglu } from "../../layers/swiglu";
30
+ import { cacheRead, type AttentionReadStrategy } from "../qwen/blocks";
31
+
32
+ export class LlamaAttention {
33
+ readonly qProj: QuantizedLinear;
34
+ readonly kProj: QuantizedLinear;
35
+ readonly vProj: QuantizedLinear;
36
+ readonly oProj: QuantizedLinear;
37
+ readonly nHeads: number;
38
+ readonly nKvHeads: number;
39
+ readonly headDim: number;
40
+ readonly scale: number;
41
+ readonly ropeBase: number;
42
+
43
+ readonly #q: QuantizedLinearPlain;
44
+ readonly #k: QuantizedLinearPlain;
45
+ readonly #v: QuantizedLinearPlain;
46
+ readonly #out: QuantizedLinearPlain;
47
+
48
+ /** `reads` is how the block reads its cache: the cache's own read, fixed when
49
+ * the block is built. */
50
+ constructor(weights: Weights, config: ModelConfig, prefix: string, readonly reads: AttentionReadStrategy = cacheRead) {
51
+ const t = config.text;
52
+ this.nHeads = t.numAttentionHeads;
53
+ this.nKvHeads = t.numKeyValueHeads;
54
+ this.headDim = t.headDim;
55
+ this.scale = Math.pow(this.headDim, -0.5);
56
+ this.ropeBase = t.ropeParameters.full_attention?.ropeTheta ?? 10000;
57
+ this.qProj = QuantizedLinear.load(weights, `${prefix}.q_proj`, config);
58
+ this.kProj = QuantizedLinear.load(weights, `${prefix}.k_proj`, config);
59
+ this.vProj = QuantizedLinear.load(weights, `${prefix}.v_proj`, config);
60
+ this.oProj = QuantizedLinear.load(weights, `${prefix}.o_proj`, config);
61
+ this.#q = new QuantizedLinearPlain(this.qProj);
62
+ this.#k = new QuantizedLinearPlain(this.kProj);
63
+ this.#v = new QuantizedLinearPlain(this.vProj);
64
+ this.#out = new QuantizedLinearPlain(this.oProj);
65
+ }
66
+
67
+ /** `x` [B, L, hidden] (borrowed) to an owned [B, L, hidden], appending to
68
+ * `cache` and attending through the read `phase` names. */
69
+ forward(x: MlxArray, cache: Cache, phase: ReadPhase): MlxArray {
70
+ const [B, L] = x.shape as [number, number, number];
71
+ let [q, k, v] = this.#heads(x, B, L);
72
+ // RoPE: a number offset takes the static fast::rope; an array offset
73
+ // (per-row positions for left-padded batched decode) takes the dynamic
74
+ // variant — same kernel, offset read from the array. Captured once: rope
75
+ // runs before the append, so K and Q share the pre-write offset.
76
+ const offsetArr = cache.ropeOffsetArr;
77
+ const ropeStep = (x: MlxArray): MlxArray => offsetArr
78
+ ? ops.ropeDynamic(x, this.headDim, this.ropeBase, offsetArr, null)
79
+ : ops.rope(x, this.headDim, this.ropeBase, cache.offset, null);
80
+ q = disposing(q, ropeStep(q));
81
+ k = disposing(k, ropeStep(k));
82
+ const read = this.reads.read(cache, phase, k, v);
83
+ k.dispose();
84
+ v.dispose();
85
+ let attn: MlxArray;
86
+ try { attn = read.attend(q, this.scale); } finally { read.dispose(); }
87
+ q.dispose();
88
+ return this.#output(attn, B, L);
89
+ }
90
+
91
+ /** The training forward over a training cache (`TrainingCache`,
92
+ * `PrefixSharedCache`), roped at the positions the cache owns (block-wise
93
+ * for a prefix-shared concat), read through its window read, which owns the mask (causal, padded or
94
+ * block-sparse) and the kernel the run composed (the SDPA, or the validated
95
+ * flash kernel). */
96
+ forwardTraining(x: MlxArray, cache: TrainingAttentionCache): MlxArray {
97
+ const [B, L] = x.shape as [number, number, number];
98
+ let [q, k, v] = this.#heads(x, B, L);
99
+ const ropeStep = (x: MlxArray): MlxArray =>
100
+ cache.ropePositions(x, (block, offset) => ops.rope(block, this.headDim, this.ropeBase, offset, null));
101
+ q = disposing(q, ropeStep(q));
102
+ k = disposing(k, ropeStep(k));
103
+ const read = cache.appendWindow(k, v);
104
+ k.dispose();
105
+ v.dispose();
106
+ let attn: MlxArray;
107
+ try { attn = read.attend(q, this.scale); } finally { read.dispose(); }
108
+ q.dispose();
109
+ return this.#output(attn, B, L);
110
+ }
111
+
112
+ /** q, k and v heads [B, H, L, D] of `x` (borrowed), before RoPE. */
113
+ #heads(x: MlxArray, B: number, L: number): [MlxArray, MlxArray, MlxArray] {
114
+ let q = this.#q.forward(x);
115
+ let k = this.#k.forward(x);
116
+ let v = this.#v.forward(x);
117
+
118
+ q = disposing(q, ops.reshape(q, [B, L, this.nHeads, this.headDim]));
119
+ k = disposing(k, ops.reshape(k, [B, L, this.nKvHeads, this.headDim]));
120
+ v = disposing(v, ops.reshape(v, [B, L, this.nKvHeads, this.headDim]));
121
+
122
+ q = disposing(q, ops.transposeAxes(q, [0, 2, 1, 3]));
123
+ k = disposing(k, ops.transposeAxes(k, [0, 2, 1, 3]));
124
+ v = disposing(v, ops.transposeAxes(v, [0, 2, 1, 3]));
125
+ return [q, k, v];
126
+ }
127
+
128
+ /** The output projection of `attn` [B, H, L, D] (consumed). */
129
+ #output(attn: MlxArray, B: number, L: number): MlxArray {
130
+ const attnT = ops.transposeAxes(attn, [0, 2, 1, 3]);
131
+ attn.dispose();
132
+ const merged = ops.reshape(attnT, [B, L, -1]);
133
+ attnT.dispose();
134
+ const out = this.#out.forward(merged);
135
+ merged.dispose();
136
+ return out;
137
+ }
138
+ }
139
+
140
+ /** The MLP with mlx_lm activations.py's compiled swiglu, at every sequence
141
+ * length: separate kernels differ numerically on MLX 0.32.2 at larger prefill
142
+ * shapes. */
143
+ export class LlamaMLP {
144
+ readonly kind = "compiled";
145
+ readonly gate: QuantizedLinear;
146
+ readonly up: QuantizedLinear;
147
+ readonly down: QuantizedLinear;
148
+
149
+ readonly #gate: QuantizedLinearPlain;
150
+ readonly #up: QuantizedLinearPlain;
151
+ readonly #down: QuantizedLinearPlain;
152
+
153
+ constructor(weights: Weights, config: ModelConfig, prefix: string) {
154
+ this.gate = QuantizedLinear.load(weights, `${prefix}.gate_proj`, config);
155
+ this.up = QuantizedLinear.load(weights, `${prefix}.up_proj`, config);
156
+ this.down = QuantizedLinear.load(weights, `${prefix}.down_proj`, config);
157
+ this.#gate = new QuantizedLinearPlain(this.gate);
158
+ this.#up = new QuantizedLinearPlain(this.up);
159
+ this.#down = new QuantizedLinearPlain(this.down);
160
+ }
161
+
162
+ /** MLP: returns mlp(x); the caller adds the residual when given. */
163
+ forward(x: MlxArray, residual?: MlxArray): MlxArray {
164
+ const gate = this.#gate.forward(x);
165
+ const up = this.#up.forward(x);
166
+ const hidden = compiledSwiglu(gate, up);
167
+ gate.dispose();
168
+ up.dispose();
169
+ return downWithResidual(this.#down, hidden, residual);
170
+ }
171
+ }
172
+
173
+ /** The MLP with the swiglu as separate silu and multiply kernels: the explicit
174
+ * layer form, available for callers writing their own graph. */
175
+ export class LlamaUnfusedMLP {
176
+ readonly kind = "unfused";
177
+ readonly gate: QuantizedLinear;
178
+ readonly up: QuantizedLinear;
179
+ readonly down: QuantizedLinear;
180
+
181
+ constructor(weights: Weights, config: ModelConfig, prefix: string) {
182
+ this.gate = QuantizedLinear.load(weights, `${prefix}.gate_proj`, config);
183
+ this.up = QuantizedLinear.load(weights, `${prefix}.up_proj`, config);
184
+ this.down = QuantizedLinear.load(weights, `${prefix}.down_proj`, config);
185
+ }
186
+
187
+ /** MLP: returns mlp(x); the caller adds the residual when given. */
188
+ forward(x: MlxArray, residual?: MlxArray): MlxArray {
189
+ const gate = this.gate.forward(x);
190
+ const up = this.up.forward(x);
191
+ const sig = ops.sigmoid(gate);
192
+ const silu = ops.mul(gate, sig);
193
+ gate.dispose();
194
+ sig.dispose();
195
+ const hidden = ops.mul(silu, up);
196
+ silu.dispose();
197
+ up.dispose();
198
+ return downWithResidual(this.down, hidden, residual);
199
+ }
200
+ }
201
+
202
+ /** down(hidden) (hidden consumed), plus `residual` when given. */
203
+ function downWithResidual(down: { forward(x: MlxArray): MlxArray }, hidden: MlxArray, residual: MlxArray | undefined): MlxArray {
204
+ const m = down.forward(hidden);
205
+ hidden.dispose();
206
+ if (residual == null) return m;
207
+ return disposing(m, ops.add(residual, m));
208
+ }
209
+
210
+ export type MiniCpmMlp = LlamaMLP | LlamaUnfusedMLP;
211
+ type MlpBlock = new (weights: Weights, config: ModelConfig, prefix: string) => MiniCpmMlp;
212
+
213
+ export class LlamaLayer {
214
+ readonly attn: LlamaAttention;
215
+ readonly mlp: MiniCpmMlp;
216
+ readonly inputNorm: RMSNorm;
217
+ readonly postAttnNorm: RMSNorm;
218
+
219
+ constructor(weights: Weights, config: ModelConfig, prefix: string, Mlp: MlpBlock = LlamaMLP) {
220
+ this.attn = new LlamaAttention(weights, config, `${prefix}.self_attn`);
221
+ this.mlp = new Mlp(weights, config, `${prefix}.mlp`);
222
+ this.inputNorm = new RMSNorm(weights.tensor(`${prefix}.input_layernorm.weight`), config.text.rmsNormEps);
223
+ this.postAttnNorm = new RMSNorm(weights.tensor(`${prefix}.post_attention_layernorm.weight`), config.text.rmsNormEps);
224
+ }
225
+
226
+ forward(x: MlxArray, cache: Cache, phase: ReadPhase): MlxArray {
227
+ const xn = this.inputNorm.forward(x);
228
+ const a = this.attn.forward(xn, cache, phase);
229
+ xn.dispose();
230
+ return this.#mlp(x, a);
231
+ }
232
+
233
+ /** The training forward (`LlamaAttention.forwardTraining`). */
234
+ forwardTraining(x: MlxArray, cache: TrainingAttentionCache): MlxArray {
235
+ const xn = this.inputNorm.forward(x);
236
+ const a = this.attn.forwardTraining(xn, cache);
237
+ xn.dispose();
238
+ return this.#mlp(x, a);
239
+ }
240
+
241
+ /** The residual over the attention output `a` (consumed), then the MLP. */
242
+ #mlp(x: MlxArray, a: MlxArray): MlxArray {
243
+ const h = ops.add(x, a);
244
+ a.dispose();
245
+ const hn = this.postAttnNorm.forward(h);
246
+ // Pass the residual h INTO the MLP so the fused kernel absorbs it (out = h + mlp).
247
+ const out = this.mlp.forward(hn, h);
248
+ hn.dispose();
249
+ h.dispose();
250
+ return out;
251
+ }
252
+ }
253
+
254
+ export class MiniCPM5Model implements MlxDeclaredGraph, MlxTokenPhases {
255
+ readonly config: ModelConfig;
256
+ readonly weightsBytes: number;
257
+ readonly prefixBase = "model";
258
+ readonly loraState = new LoraState();
259
+ /** An ordinary autoregressive graph: every method over every cache lego. */
260
+ get graphCapabilities(): GraphDeclaration { return declareGraph(); }
261
+ #trainable: TrainableGraph | undefined;
262
+ /** The separate quantized head, segmented backward, prefix-shared ORPO and flash training attention. */
263
+ get trainable(): TrainableGraph { return this.#trainable ??= miniCpmTrainable(this); }
264
+ readonly embed: QuantizedEmbedding;
265
+ readonly layers: LlamaLayer[];
266
+ readonly finalNorm: RMSNorm;
267
+ readonly lmHead: QuantizedLinear;
268
+ readonly #head: QuantizedLinearPlain;
269
+
270
+ constructor(weights: Weights, config: ModelConfig, maxPhaseRows = DEFAULT_PHASE_ROWS) {
271
+ if (config.text.tieWordEmbeddings)
272
+ throw new Error("llama tied embeddings are not supported yet");
273
+ this.config = config;
274
+ this.weightsBytes = [...weights.shards.files.values()]
275
+ .reduce((a, f) => a + f.mmap.size, 0);
276
+ this.embed = QuantizedEmbedding.load(weights, "model.embed_tokens", config);
277
+ const Mlp = LlamaMLP;
278
+ this.layers = Array.from(
279
+ { length: config.text.numHiddenLayers },
280
+ (_, i) => new LlamaLayer(weights, config, `model.layers.${i}`, Mlp),
281
+ );
282
+ this.finalNorm = new RMSNorm(weights.tensor("model.norm.weight"), config.text.rmsNormEps);
283
+ this.lmHead = QuantizedLinear.load(weights, "lm_head", config);
284
+ this.#head = new QuantizedLinearPlain(this.lmHead);
285
+
286
+ const multiSequencePrompt: MlxCapturingForward = (ids, cache) =>
287
+ this.forwardLayers(this.embed.encode(ids), cache, "window");
288
+ this.prompt = [{ from: 1, to: Infinity, operation: multiSequencePrompt }];
289
+ this.promptChunk = this.prompt;
290
+ this.multiSequencePrompt = this.prompt;
291
+ this.multiSequencePromptChunk = this.multiSequencePrompt;
292
+ this.appendKnown = [{from:1,to:Infinity,operation:(ids, cache) =>
293
+ this.forwardLayers(this.embed.encode(ids), cache, "window")}];
294
+ this.logits = rowTable<MlxHeadForward>(hidden => this.logitsFromHidden(hidden), maxPhaseRows);
295
+ this.decode = rowTable<MlxPhaseForward>((ids, cache) =>
296
+ this.forwardLayers(this.embed.encode(ids), cache, "decode"), maxPhaseRows);
297
+ this.verify = rowTable<MlxVerifyForward>((ids, cache) =>
298
+ this.forwardLayers(this.embed.encode(ids), cache, "window"), maxPhaseRows);
299
+
300
+
301
+ this.sequence = [{from:1,to:Infinity,operation:(ids,cache)=>this.sequenceHidden(ids,cache,1)}];
302
+
303
+ this.cacheLayers = this.layers.map(() => ({kind:"full" as const,turboQuant:"deferred" as const}));
304
+ }
305
+
306
+ loraTargets(): Map<string, QuantizedLinear> {
307
+ const out = new Map<string, QuantizedLinear>();
308
+ for (let i = 0; i < this.layers.length; i++) {
309
+ const l = this.layers[i]!;
310
+ const p = `model.layers.${i}`;
311
+ out.set(`${p}.self_attn.q_proj`, l.attn.qProj);
312
+ out.set(`${p}.self_attn.k_proj`, l.attn.kProj);
313
+ out.set(`${p}.self_attn.v_proj`, l.attn.vProj);
314
+ out.set(`${p}.self_attn.o_proj`, l.attn.oProj);
315
+ out.set(`${p}.mlp.gate_proj`, l.mlp.gate);
316
+ out.set(`${p}.mlp.up_proj`, l.mlp.up);
317
+ out.set(`${p}.mlp.down_proj`, l.mlp.down);
318
+ }
319
+ return out;
320
+ }
321
+
322
+ /** Builds no constants and opens no weights: nothing to release. */
323
+ dispose(): void {}
324
+
325
+ /** One cache per layer, sharing one mask memo. Their TurboQuant read is
326
+ * deferred (`deferredTurboQuantKernels`): attention runs on the rotated
327
+ * values and the read un-rotates its output. */
328
+ readonly cacheLayers: readonly MlxCacheLayer[];
329
+ readonly sequence: readonly MlxSequenceRange[];
330
+
331
+
332
+ /** The scoring and training forward (`MlxSequenceForward`, `trainForward`
333
+ * over the training caches): the window read at every width. The training
334
+ * caches were composed with the run's training attention, so a run that
335
+ * selects flash attention reads with it here. */
336
+ sequenceHidden(ids: MlxArray, cache: Cache[], _width: number): MlxArray {
337
+ return this.forwardLayers(this.embed.encode(ids), cache, "window");
338
+ }
339
+
340
+ /** One whole chunk of a prompt; rows are sequences times the chunk size. The GPU is this graph's one unit. */
341
+ readonly prompt: readonly MlxPromptRange[];
342
+ readonly promptChunk: typeof this.prompt;
343
+ readonly multiSequencePromptChunk: typeof this.multiSequencePrompt;
344
+ readonly multiSequencePrompt: readonly MlxPromptRange[];
345
+
346
+ /** A prompt's positions that are not a whole chunk: the window read at every width. */
347
+
348
+ /** Known tokens: this graph declares no committed spans, so they read as a window. */
349
+ readonly appendKnown: import("../../contracts/mlx/graph").MlxKnownOperations;
350
+
351
+ /** The one output head at every width. */
352
+ readonly logits: MlxRowTable<MlxHeadForward>;
353
+
354
+ /** One new token per sequence: `ids` [sequences, 1]. */
355
+ readonly decode: MlxRowTable<MlxCapturingForward>;
356
+
357
+ /** A speculative window of depth + 1 positions per sequence. This graph
358
+ * declares no hidden-layer taps, so `capture` is always null. */
359
+ readonly verify: MlxRowTable<MlxCapturingForward>;
360
+
361
+ /** The decoder over `h0` (consumed), every block reading its cache for `phase`. */
362
+ protected forwardLayers(h0: MlxArray, cache: Cache[], phase: ReadPhase): MlxArray {
363
+ let h = h0;
364
+ for (let i = 0; i < this.layers.length; i++) {
365
+ const next = this.layers[i]!.forward(h, cache[i]!, phase);
366
+ h.dispose();
367
+ h = next;
368
+ }
369
+ return disposing(h, this.finalNorm.forward(h));
370
+ }
371
+
372
+ /** Run decoder layers `[aIdx, bIdx)` on hidden `h`, returning the residual
373
+ * stream after the last layer in the range (NO finalNorm). The input `h` is
374
+ * NEVER disposed — the caller owns it (for segmented backward `h` is a leaf
375
+ * whose lifetime is managed by the autograd closure); intra-range
376
+ * intermediates ARE disposed. The segmented-backward and prefix-shared
377
+ * training paths' building block (`02d723a:docs/design/orpo-training.md`
378
+ * §5.3). MiniCPM5 is plain full-attention with no KV-sharing, so each layer
379
+ * reads its own stateless training cache `cache[i]`. */
380
+ runLayerRange(h: MlxArray, aIdx: number, bIdx: number, cache: Cache[]): MlxArray {
381
+ if (aIdx >= bIdx) return h;
382
+ let cur = h;
383
+ for (let i = aIdx; i < bIdx; i++) {
384
+ const next = this.layers[i]!.forwardTraining(cur, cache[i] as TrainingAttentionCache);
385
+ if (i > aIdx) cur.dispose(); // keep the input boundary leaf; drop interiors
386
+ cur = next;
387
+ }
388
+ return cur;
389
+ }
390
+
391
+ logitsFromHidden(h: MlxArray): MlxArray {
392
+ return this.#head.forward(h);
393
+ }
394
+ }
@@ -0,0 +1,90 @@
1
+ import type { MlxArray } from "@mlx-bun/mlx/array";
2
+ import type { Cache, SharedKv } from "../../contracts/mlx/cache";
3
+ import type { HeadQuant, PrefixLayout, SegmentedPass, TrainableGraph } from "../../contracts/mlx/trainable";
4
+ import { AttentionMasks } from "../../state/attention-read";
5
+ import { prefixSharedCaches, selectedTrainingAttention, TrainingCache } from "../../state/training-cache";
6
+ import type { RMSNorm } from "../../layers/normalization";
7
+ import type { QuantizedEmbedding } from "../../layers/quantized-embedding";
8
+ import type { QuantizedLinear } from "../../layers/quantized-linear";
9
+
10
+ /** What the training declaration reads from a MiniCPM5 model (structural, so this
11
+ * module does not depend on the model file). */
12
+ export interface MiniCpmTraining {
13
+ readonly embed: QuantizedEmbedding;
14
+ readonly layers: readonly unknown[];
15
+ readonly finalNorm: RMSNorm;
16
+ readonly lmHead: QuantizedLinear;
17
+ /** The training forward over layers `[aIdx, bIdx)`; `h` stays the caller's. */
18
+ runLayerRange(h: MlxArray, aIdx: number, bIdx: number, cache: Cache[]): MlxArray;
19
+ }
20
+
21
+ /** One stateless training cache per layer, full attention, sharing one mask
22
+ * memo and attending with the run's training attention: prefix-shared caches
23
+ * under a layout, plain ones otherwise. */
24
+ function trainingCaches(model: MiniCpmTraining, prefix?: PrefixLayout): Cache[] {
25
+ const attention = selectedTrainingAttention(), windows = model.layers.map(() => null);
26
+ if (prefix) return prefixSharedCaches(prefix, windows, attention);
27
+ const masks = new AttentionMasks();
28
+ return windows.map(window => new TrainingCache(window, masks, attention));
29
+ }
30
+
31
+ /** One segmented pass over a MiniCPM5 sequence: plain full attention with no KV
32
+ * sharing, so each layer reads its own stateless cache (prefix-shared caches
33
+ * read under the block-sparse mask when a layout is given). */
34
+ class MiniCpmSegmentedPass implements SegmentedPass {
35
+ readonly input: MlxArray;
36
+ private readonly caches: Cache[];
37
+
38
+ constructor(private readonly model: MiniCpmTraining, ids: MlxArray, prefix?: PrefixLayout) {
39
+ this.caches = trainingCaches(model, prefix);
40
+ try {
41
+ this.input = model.embed.encode(ids); // [1, T, hidden]
42
+ } catch (error) {
43
+ this.releaseCaches();
44
+ throw error;
45
+ }
46
+ }
47
+
48
+ private releaseCaches(): void {
49
+ for (const c of this.caches) c.dispose();
50
+ }
51
+
52
+ runRange(h: MlxArray, lo: number, hi: number, _donorKvIn: Map<number, SharedKv>) {
53
+ return { h: this.model.runLayerRange(h, lo, hi, this.caches), donorKvOut: new Map<number, SharedKv>() };
54
+ }
55
+
56
+ dispose(): void { this.releaseCaches(); }
57
+ }
58
+
59
+ /** MiniCPM5's training declaration. */
60
+ export function miniCpmTrainable(model: MiniCpmTraining): TrainableGraph {
61
+ return {
62
+ lmHead(): HeadQuant {
63
+ const h = model.lmHead;
64
+ return { w: h.w, scales: h.scales, biases: h.biases, spec: h.spec, softcap: null };
65
+ },
66
+ flashAttention: { supported: true },
67
+ segmented: {
68
+ layerCount: model.layers.length,
69
+ sharedKv: { reusedDonors: new Set(), donorOf: model.layers.map(() => null) },
70
+ finalNorm: (h) => model.finalNorm.forward(h),
71
+ begin: (ids, prefix) => new MiniCpmSegmentedPass(model, ids, prefix),
72
+ },
73
+ prefixShared: {
74
+ /** The training forward (`runLayerRange`) over the whole concat, whose
75
+ * prefix-shared caches read under the block-sparse mask and whose
76
+ * queries and keys take the block-wise RoPE those caches own. */
77
+ prefixSharedHidden(ids: MlxArray, layout: PrefixLayout): MlxArray {
78
+ const caches = trainingCaches(model, layout);
79
+ try {
80
+ const h0 = model.embed.encode(ids);
81
+ let h: MlxArray;
82
+ try { h = model.runLayerRange(h0, 0, model.layers.length, caches); } finally { h0.dispose(); }
83
+ try { return model.finalNorm.forward(h); } finally { h.dispose(); } // [1, T, hidden], post-finalNorm
84
+ } finally {
85
+ for (const c of caches) c.dispose();
86
+ }
87
+ },
88
+ },
89
+ };
90
+ }