@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,351 @@
1
+ // Model construction consumes one declared profile and one composition. Exact
2
+ // artifact profiles outrank family profiles; the profile names the family's
3
+ // implementation, and the family's graph table picks the graph for the
4
+ // composition. Request-level methods are resolved elsewhere and are never
5
+ // changed by this module.
6
+
7
+ import { loadModelConfig, type ModelConfig } from "../artifacts/config";
8
+ import { totalmem } from "node:os";
9
+ import { Weights } from "../artifacts/weights";
10
+ import { Gemma4Model } from "./gemma4/model";
11
+ import { configFingerprint } from "../artifacts/fingerprint";
12
+ import { qwen35GraphFingerprint } from "./qwen/checkpoint";
13
+ import {
14
+ DECODE_ROWS as QWEN38_M4PRO_DECODE_ROWS, QWEN38_TRELLIS_M4PRO_GRAPH, Qwen38TrellisM4Pro,
15
+ anePrograms as qwen38TrellisM4ProAnePrograms,
16
+ } from "./qwen/qwen38-27b-trellis-m4pro";
17
+ import {
18
+ QWEN38_TRELLIS_M1MAX_GRAPH, Qwen38TrellisM1Max,
19
+ anePrograms as qwen38TrellisM1MaxAnePrograms,
20
+ } from "./qwen/qwen38-27b-trellis-m1max";
21
+ import { GEMMA_GRAPHS, type Gemma4Graph } from "./gemma4/graphs";
22
+ import { MiniCPM5Model } from "./minicpm5/model";
23
+ import { Qwen35Model } from "./qwen/qwen3_5";
24
+ import { Qwen3Model } from "./qwen/qwen3";
25
+ import { Qwen3MoeModel } from "./qwen/qwen3-moe";
26
+ import { DiffusionGemmaModel } from "./diffusion-gemma/model";
27
+ import { Glm52Model, type Glm52LoadedModel, type Glm52LatentCaches } from "./glm52/model";
28
+ import {
29
+ GLM52_G5_DEFAULT_CONTEXT_TOKENS,
30
+ GLM52_G5_DEFAULT_MAX_GENERATION_TOKENS,
31
+ GLM52_G5_DEFAULT_PROCESS_LIMIT_BYTES,
32
+ planGlm52MemoryForArtifact,
33
+ type Glm52MemoryPlan,
34
+ } from "../artifacts/glm52/memory";
35
+ import { UniversalDenseModel } from "./universal/dense";
36
+ import { WhisperModel } from "./whisper/model";
37
+ import { genericArgsFor } from "./universal/archs";
38
+ import { familyForGraph } from "./families";
39
+ import { resolveComposition } from "./composition";
40
+ import { bindGraphCaches } from "./cache-composition";
41
+ import { phaseRowLimit } from "./graph";
42
+ import type { Composition } from "../contracts/portable/composition";
43
+ import type { Cache } from "../contracts/mlx/cache";
44
+ import {
45
+ GraphTable,
46
+ ModelImplementationRegistry,
47
+ type GraphEntry,
48
+ type ModelImplementation,
49
+ type ModelImplementationProvider,
50
+ } from "./implementation";
51
+ import {
52
+ assertResolvedModelProfile,
53
+ resolveModelProfile,
54
+ type ResolvedModelProfile,
55
+ type ResolveModelProfileOptions,
56
+ type ModelGraph,
57
+ type ModelLoader,
58
+ type GenerationLoop,
59
+ } from "./profile";
60
+
61
+ type WrittenGraph = (
62
+ | Gemma4Model | Gemma4Graph | MiniCPM5Model | Qwen35Model | Qwen38TrellisM4Pro | Qwen38TrellisM1Max | Qwen3Model | Qwen3MoeModel
63
+ | DiffusionGemmaModel | Glm52Model | UniversalDenseModel);
64
+
65
+ export type RuntimeModel = WrittenGraph & { makeCache(): Cache[]; readonly composition?: Composition };
66
+
67
+ /** The family's single fallback graph. */
68
+ function generic(id: string, create: GraphEntry<Weights, WrittenGraph>["create"]): GraphEntry<Weights, RuntimeModel> {
69
+ return loadedEntry({ id, serves: {}, create });
70
+ }
71
+
72
+ function loadedEntry(entry: GraphEntry<Weights, WrittenGraph>): GraphEntry<Weights, RuntimeModel> {
73
+ return { ...entry, create: (weights, config, composition) => loadedGraph(entry.create(weights, config, composition), composition) };
74
+ }
75
+
76
+ /** Attach the loader's cache and scheduler configuration to a shipped graph.
77
+ * Its written implementation only provides the layer layout and operations. */
78
+ function loadedGraph(graph: WrittenGraph, composition: Composition): RuntimeModel {
79
+ return Object.assign(bindGraphCaches(graph, composition), { composition });
80
+ }
81
+
82
+ /** Resident graph files and their default recommendation keys. Explicit
83
+ * choices are unrestricted; see {@link GraphTable}. */
84
+ export const MLX_GRAPH_TABLES: Readonly<Record<ModelGraph, GraphTable<Weights, RuntimeModel>>> = Object.freeze({
85
+ "diffusion-gemma": new GraphTable([generic("diffusion-gemma", (weights, config, composition) => new DiffusionGemmaModel(weights, config))]),
86
+ "minicpm5": new GraphTable([generic("minicpm5", (weights, config, composition) => new MiniCPM5Model(weights, config, phaseRowLimit(composition)))]),
87
+ // Written graph recommendations for the published Trellis artifact.
88
+ // Explicit caller choices bypass these artifact and device keys.
89
+ "qwen3.5": new GraphTable([
90
+ loadedEntry({ id: QWEN38_TRELLIS_M4PRO_GRAPH, serves: {
91
+ fingerprint:"cfa205c8f5af046a",device:"applegpu_g16s",maxRows:QWEN38_M4PRO_DECODE_ROWS,
92
+ kv:[{kind:"bf16"},{kind:"affine",bits:4,groupSize:64}],
93
+ },
94
+ create: (weights,config) => new Qwen38TrellisM4Pro(weights,config),
95
+ anePrograms: () => qwen38TrellisM4ProAnePrograms() }),
96
+ loadedEntry({ id: QWEN38_TRELLIS_M1MAX_GRAPH, serves: {
97
+ fingerprint:"cfa205c8f5af046a",device:"applegpu_g13s",
98
+ }, create: (weights, config) => new Qwen38TrellisM1Max(weights, config),
99
+ anePrograms: () => qwen38TrellisM1MaxAnePrograms() }),
100
+ generic("qwen3.5", (weights, config, composition) => new Qwen35Model(weights, config, phaseRowLimit(composition), composition.device)),
101
+ ], qwen35GraphFingerprint),
102
+ "qwen3-moe": new GraphTable([generic("qwen3-moe", (weights, config, composition) => new Qwen3MoeModel(weights, config, phaseRowLimit(composition)))]),
103
+ "qwen3": new GraphTable([generic("qwen3", (weights, config, composition) => new Qwen3Model(weights, config, phaseRowLimit(composition)))]),
104
+ "gemma4": new GraphTable([...GEMMA_GRAPHS.map(loadedEntry), generic("gemma4", (weights, config, composition) => new Gemma4Model(weights, config, phaseRowLimit(composition)))],
105
+ configFingerprint),
106
+ "universal-dense": new GraphTable([
107
+ generic("universal-dense", (weights, config, composition) =>
108
+ new UniversalDenseModel(weights, config, genericArgsFor(config)!, phaseRowLimit(composition), composition.device))]),
109
+ });
110
+
111
+ /** A resident family's native construction: its graph table selects the graph for
112
+ * the composition it receives. Its loader and loop are the family's own declaration. */
113
+ function residentImplementation(graph: ModelGraph, table: GraphTable<Weights, RuntimeModel>): ModelImplementation<Weights, RuntimeModel> {
114
+ const family = familyForGraph(graph);
115
+ if (!family) throw new Error(`graph table ${graph} names a graph no model family declares`);
116
+ return { id: graph, graph, loader: family.loader, loop: family.loop,
117
+ create: (weights, config, _profile, composition) =>
118
+ table.select(config, composition).create(weights, config, composition) };
119
+ }
120
+
121
+ /** Engine-owned registrations, one per resident graph of `MODEL_FAMILIES`. Exact
122
+ * quant profiles can name additional implementations in a composed registry,
123
+ * without changing sessions or files. */
124
+ export const MLX_MODEL_IMPLEMENTATIONS = new ModelImplementationRegistry<Weights, RuntimeModel>(
125
+ Object.entries(MLX_GRAPH_TABLES).map(([graph, table]) => residentImplementation(graph, table)));
126
+
127
+ export interface ModelOpenOptions<Model = RuntimeModel> extends Glm52RuntimeOpenOptions {
128
+ readonly profiles?: ResolveModelProfileOptions;
129
+ readonly implementations?: ModelImplementationProvider<Weights, Model>;
130
+ /** The composition the graph is built for; absent resolves the default record
131
+ * (`resolveComposition(config)`). The direct Colibri runtime plans its own
132
+ * resources from the options above and takes none. */
133
+ readonly composition?: Composition;
134
+ /** A named shipped graph or the caller's own load function. Explicit choices
135
+ * bypass device and configuration recommendations and need no registration. */
136
+ readonly graph?: string | ((weights: Weights, config: ModelConfig) => Model);
137
+ }
138
+
139
+ /** A loader entry cannot provide the requested artifact/operation pairing. */
140
+ export class UnsupportedModelLoadError extends Error {
141
+ readonly code = "unsupported-model-load";
142
+ constructor(readonly profile: ResolvedModelProfile, message: string) {
143
+ super(message);
144
+ this.name = "UnsupportedModelLoadError";
145
+ }
146
+ }
147
+
148
+ export interface Glm52RuntimeOpenOptions {
149
+ /** Whole-process ceiling. Defaults to the smaller of the validated 25 GiB
150
+ * preset and physical RAM. */
151
+ memoryBudgetBytes?: number;
152
+ /** Context reserved by the exact GLM resource equation. */
153
+ contextTokens?: number;
154
+ /** Generated-token allowance within contextTokens. */
155
+ maxGenerationTokens?: number;
156
+ /** Maximum ordinary continuous-batch rows. */
157
+ batchSize?: number;
158
+ /** Native checkpoint MTP row; on by default. */
159
+ enableMtp?: boolean;
160
+ mtpDraftTokens?: number;
161
+ /** Test/diagnostic override; normal callers use physical RAM. */
162
+ machineBytes?: number;
163
+ /** Native expert-I/O dylib override. Packaged/dev defaults are automatic. */
164
+ libraryPath?: string;
165
+ /** The composition's KV scheme and paging, which the graph's latent caches
166
+ * compose (default f32, unpaged). */
167
+ caches?: Glm52LatentCaches;
168
+ }
169
+
170
+ /** Open the direct Colibri artifact through the validated bounded expert
171
+ * runtime. The header-only plan runs before any resident tensor or expert slab
172
+ * is opened, so an impossible configuration fails without committing memory. */
173
+ export async function openGlm52RuntimeModel(
174
+ modelDir: string,
175
+ options: Glm52RuntimeOpenOptions = {},
176
+ ): Promise<{ model: Glm52LoadedModel; plan: Glm52MemoryPlan }> {
177
+ const machineBytes = options.machineBytes ?? totalmem();
178
+ const processLimitBytes = options.memoryBudgetBytes ??
179
+ Math.min(GLM52_G5_DEFAULT_PROCESS_LIMIT_BYTES, machineBytes);
180
+ const plan = await planGlm52MemoryForArtifact(modelDir, {
181
+ machineBytes,
182
+ processLimitBytes,
183
+ contextTokens: options.contextTokens ?? GLM52_G5_DEFAULT_CONTEXT_TOKENS,
184
+ maxGenerationTokens:
185
+ options.maxGenerationTokens ?? GLM52_G5_DEFAULT_MAX_GENERATION_TOKENS,
186
+ batchSize: options.batchSize ?? 1,
187
+ enableMtp: options.enableMtp !== false,
188
+ mtpDraftTokens: options.mtpDraftTokens,
189
+ });
190
+ const model = await Glm52Model.openStreamed(modelDir, {
191
+ budgetBytes: plan.processLimitBytes,
192
+ reserveBytes: plan.runtimeReserveBytes,
193
+ workingSlots: plan.mainWorkingSlots,
194
+ maxSlotsPerLayer: 1,
195
+ workers: 2,
196
+ libraryPath: options.libraryPath,
197
+ decodeKernel: "metal",
198
+ enableMtp: plan.enableMtp,
199
+ mtpDraftTokens: plan.mtpDraftTokens,
200
+ ...(options.caches ? { caches: options.caches } : {}),
201
+ });
202
+ if (model.expertRuntime?.plan.plannedBytes !== plan.plannedProcessBytes) {
203
+ const actual = model.expertRuntime?.plan.plannedBytes ?? 0;
204
+ model.dispose();
205
+ throw new Error(
206
+ `GLM runtime plan ${actual} != preflight resource equation ` +
207
+ `${plan.plannedProcessBytes}`,
208
+ );
209
+ }
210
+ return { model, plan };
211
+ }
212
+
213
+ /** Open a Whisper checkpoint (encoder-decoder speech model) through the same
214
+ * profile resolution as text models. Whisper never enters the chat loop, so
215
+ * it is not a RuntimeModel: the transcription engine
216
+ * (packages/inference/src/transcription/whisper/)
217
+ * owns it. */
218
+ export async function openWhisperModel(
219
+ modelDir: string, options: { readonly profiles?: ResolveModelProfileOptions } = {},
220
+ ): Promise<{ model: WhisperModel; profile: ResolvedModelProfile; config: ModelConfig }> {
221
+ const config = await loadModelConfig(modelDir);
222
+ const profile = resolveModelProfile(config, options.profiles);
223
+ if (profile.profile.execution.graph !== "whisper")
224
+ throw new Error(`${modelDir} is not a Whisper checkpoint (profile ${profile.profile.id})`);
225
+ const weights = await Weights.open(modelDir);
226
+ try {
227
+ return { model: new WhisperModel(weights, config), profile, config };
228
+ } catch (error) {
229
+ weights.dispose();
230
+ throw error;
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Artifact-aware construction. GLM-5.2's Colibri snapshot has no ordinary
236
+ * model.safetensors.index.json, so it must bypass Weights.open and use its
237
+ * dedicated header catalog/tensor source.
238
+ */
239
+ export function openModel<Model>(
240
+ modelDir: string,
241
+ options: ModelOpenOptions<Model> & { readonly graph: (weights: Weights, config: ModelConfig) => Model },
242
+ ): Promise<Model>;
243
+ export function openModel<Model>(
244
+ modelDir: string,
245
+ options: ModelOpenOptions<Model> & { readonly implementations: ModelImplementationProvider<Weights, Model> },
246
+ ): Promise<Model>;
247
+ export function openModel(modelDir: string, options?: ModelOpenOptions): Promise<RuntimeModel>;
248
+ export async function openModel<Model>(
249
+ modelDir: string,
250
+ options: ModelOpenOptions<Model> = {},
251
+ ): Promise<Model | RuntimeModel> {
252
+ const config = await loadModelConfig(modelDir);
253
+ const composition = options.composition ?? resolveComposition(config);
254
+ // A caller's graph is the complete arrangement. Loading it does not require
255
+ // a family profile or participation in the default recommendation table.
256
+ if (typeof options.graph === "function") {
257
+ const weights = await Weights.open(modelDir);
258
+ try { return options.graph(weights, config); }
259
+ catch (error) { weights.dispose(); throw error; }
260
+ }
261
+ const profile = resolveModelProfile(config, options.profiles);
262
+ if (options.graph !== undefined) {
263
+ const entry = MLX_GRAPH_TABLES[profile.profile.execution.graph]?.explicit(options.graph);
264
+ if (!entry) throw new Error(`no shipped graph table for ${profile.profile.execution.graph}`);
265
+ const weights = await Weights.open(modelDir);
266
+ try { return entry.create(weights, config, composition); }
267
+ catch (error) { weights.dispose(); throw error; }
268
+ }
269
+ return ARTIFACT_LOADERS[profile.profile.execution.loader][profile.profile.execution.loop]
270
+ .open({ modelDir, config, profile, composition, options });
271
+ }
272
+
273
+ interface ArtifactLoad<Model> {
274
+ readonly modelDir: string;
275
+ readonly config: ModelConfig;
276
+ readonly profile: ResolvedModelProfile;
277
+ readonly composition: Composition;
278
+ readonly options: ModelOpenOptions<Model>;
279
+ }
280
+
281
+ interface ArtifactLoader {
282
+ open<Model>(load: ArtifactLoad<Model>): Promise<Model | RuntimeModel>;
283
+ create<Model>(weights: Weights, config: ModelConfig, profile: ResolvedModelProfile,
284
+ composition: Composition, implementations: ModelImplementationProvider<Weights, Model>): Model;
285
+ }
286
+
287
+ const residentLoader: ArtifactLoader = {
288
+ async open({ modelDir, config, profile, composition, options }) {
289
+ const implementation = (options.implementations ?? MLX_MODEL_IMPLEMENTATIONS).select(config, profile);
290
+ const weights = await Weights.open(modelDir);
291
+ try { return implementation.create(weights, config, profile, composition); }
292
+ catch (error) { weights.dispose(); throw error; }
293
+ },
294
+ create: (weights, config, profile, composition, implementations) =>
295
+ implementations.select(config, profile).create(weights, config, profile, composition),
296
+ };
297
+
298
+ const streamedLoader: ArtifactLoader = {
299
+ async open({ modelDir, profile, composition, options }) {
300
+ if (options.implementations || profile.profile.execution.implementation !== undefined)
301
+ throw new UnsupportedModelLoadError(profile, "custom Colibri implementations require a streamed loader binding; refusing to fall back");
302
+ return (await openGlm52RuntimeModel(modelDir, options.composition
303
+ ? { ...options, caches: { kv: composition.kv, pagedKv: composition.pagedKv } } : options)).model;
304
+ },
305
+ create(_weights, _config, profile) {
306
+ throw new UnsupportedModelLoadError(profile, `${profile.profile.id} uses the direct Colibri container; construct it with ` +
307
+ "openModel(modelDir) or Glm52Model.open(modelDir)");
308
+ },
309
+ };
310
+
311
+ const speechLoader: ArtifactLoader = {
312
+ async open({ modelDir, profile }) {
313
+ throw new UnsupportedModelLoadError(profile, `${modelDir} is a speech model (${profile.profile.id}); open it with openWhisperModel ` +
314
+ "or serve it as a transcription model — it has no chat/completion loop");
315
+ },
316
+ create(_weights, _config, profile) {
317
+ throw new UnsupportedModelLoadError(profile, `${profile.profile.id} has an encoder-decoder graph; open it with openWhisperModel`);
318
+ },
319
+ };
320
+
321
+ /** Artifact loading follows declared table facts, including streamed weights
322
+ * and the separate speech operation. It never selects by a model predicate. */
323
+ const ARTIFACT_LOADERS: Readonly<Record<ModelLoader, Readonly<Record<GenerationLoop, ArtifactLoader>>>> = {
324
+ safetensors: { autoregressive: residentLoader, diffusion: residentLoader, "encoder-decoder": speechLoader },
325
+ colibri: { autoregressive: streamedLoader, diffusion: streamedLoader, "encoder-decoder": speechLoader },
326
+ };
327
+
328
+ /** Construct the binding named by a validated profile for `composition`, which
329
+ * the implementation receives (absent: the default record,
330
+ * `resolveComposition(config)`). A supplied registry can return any
331
+ * backend-owned interface; the compatibility default returns the legacy model
332
+ * union. The caller retains ownership of the supplied weights. */
333
+ export function createModel<Model>(
334
+ weights: Weights, config: ModelConfig, composition: Composition | undefined,
335
+ resolved: ResolvedModelProfile | undefined, implementations: ModelImplementationProvider<Weights, Model>,
336
+ ): Model;
337
+ export function createModel(
338
+ weights: Weights, config: ModelConfig, composition?: Composition, resolved?: ResolvedModelProfile,
339
+ implementations?: ModelImplementationProvider<Weights, RuntimeModel>,
340
+ ): RuntimeModel;
341
+ export function createModel<Model>(
342
+ weights: Weights,
343
+ config: ModelConfig,
344
+ composition: Composition = resolveComposition(config),
345
+ resolved: ResolvedModelProfile = resolveModelProfile(config),
346
+ implementations: ModelImplementationProvider<Weights, Model> | ModelImplementationProvider<Weights, RuntimeModel> = MLX_MODEL_IMPLEMENTATIONS,
347
+ ): Model | RuntimeModel {
348
+ assertResolvedModelProfile(config, resolved);
349
+ return ARTIFACT_LOADERS[resolved.profile.execution.loader][resolved.profile.execution.loop]
350
+ .create<Model | RuntimeModel>(weights, config, resolved, composition, implementations);
351
+ }
@@ -0,0 +1,70 @@
1
+ // The model-family registry: every family the engine serves, in one list. A new
2
+ // model is one record here plus its graph and its native implementation
3
+ // (`factory.ts`). Everything else that used to restate a family (support tiers,
4
+ // profiles, engine capabilities, declarations) is derived from this list.
5
+
6
+ import type { ModelConfig } from "../artifacts/config";
7
+ import { DIFFUSION_GEMMA_FAMILY } from "./diffusion-gemma/family";
8
+ import type { EngineCapability, ModelFamily, ModelGraph } from "./family";
9
+ import { GEMMA4_FAMILY } from "./gemma4/family";
10
+ import { GLM52_FAMILY } from "./glm52/family";
11
+ import { MINICPM5_FAMILY } from "./minicpm5/family";
12
+ import { QWEN35_FAMILY, QWEN3_FAMILY, QWEN3_MOE_FAMILY } from "./qwen/families";
13
+ import { GENERIC_MODEL_TYPES, remapModelType } from "./universal/archs";
14
+ import { UNIVERSAL_FAMILY } from "./universal/family";
15
+ import { WHISPER_FAMILY } from "./whisper/family";
16
+
17
+ /** First match wins. Targeted families accept disjoint configs; the universal
18
+ * family comes last so it never shadows one. */
19
+ export const MODEL_FAMILIES: readonly ModelFamily[] = Object.freeze([
20
+ GEMMA4_FAMILY,
21
+ DIFFUSION_GEMMA_FAMILY,
22
+ GLM52_FAMILY,
23
+ QWEN35_FAMILY,
24
+ QWEN3_FAMILY,
25
+ QWEN3_MOE_FAMILY,
26
+ WHISPER_FAMILY,
27
+ MINICPM5_FAMILY,
28
+ UNIVERSAL_FAMILY,
29
+ ]);
30
+
31
+ {
32
+ const graphs = MODEL_FAMILIES.map(family => family.graph);
33
+ const duplicate = graphs.find((graph, index) => graphs.indexOf(graph) !== index);
34
+ if (duplicate) throw new Error(`model families: duplicate graph ${duplicate}`);
35
+ }
36
+
37
+ /** The family whose graph runs this config, or null. Throws where the family's
38
+ * own parser rejects a malformed config. */
39
+ export function familyOf(config: ModelConfig): ModelFamily | null {
40
+ return MODEL_FAMILIES.find(family => family.accepts(config)) ?? null;
41
+ }
42
+
43
+ /** The family a registry record's `model_type` names before any config is read. */
44
+ export function familyOfModelType(modelType: string): ModelFamily | null {
45
+ if (typeof modelType !== "string") return null; // a record with no model_type names no family
46
+ return MODEL_FAMILIES.find(family => family.hasModelType(modelType)) ?? null;
47
+ }
48
+
49
+ export function familyForGraph(graph: ModelGraph): ModelFamily | null {
50
+ return MODEL_FAMILIES.find(family => family.graph === graph) ?? null;
51
+ }
52
+
53
+ /** What the engine can do independent of any model. */
54
+ const BASE_CAPABILITIES = [
55
+ "autoregressive", "colibri-container", "diffusion", "encoder-decoder",
56
+ "mixed-precision-kv", "native-mtp", "safetensors", "vision-sidecar",
57
+ ] as const satisfies readonly EngineCapability[];
58
+
59
+ /** The base capabilities plus what every registered family's graph brings. */
60
+ export const ENGINE_CAPABILITIES: readonly EngineCapability[] = Object.freeze(
61
+ [...new Set([...BASE_CAPABILITIES, ...MODEL_FAMILIES.flatMap(family => family.capabilities)])].sort());
62
+
63
+ /** Why no family serves this config, naming what is served. */
64
+ export function unsupportedModelMessage(config: ModelConfig): string {
65
+ const arch = remapModelType(config.modelType);
66
+ return `unsupported model_type "${config.modelType}"` +
67
+ (arch !== config.modelType ? ` (mlx-lm remaps it to "${arch}")` : "") +
68
+ ` — targeted: ${MODEL_FAMILIES.flatMap(family => family.label ?? []).join(", ")};` +
69
+ ` generic (Tier-0): ${[...GENERIC_MODEL_TYPES].sort().join(", ")}`;
70
+ }
@@ -0,0 +1,125 @@
1
+ // A model family is one record: what accepts a parsed config, which graph runs
2
+ // it, how it is composed, and every fact the layers above read about it. The
3
+ // records are listed once in `models/families.ts`; support tiers, profiles,
4
+ // engine capabilities, implementation composition and the declarations
5
+ // (training, generation, embedding, sentinels, media tokens, chat fallback)
6
+ // are all derived from that list. Records are native-free: they never import a
7
+ // graph class, so listing a model's support never loads MLX.
8
+
9
+ import type { ModelConfig } from "../artifacts/config";
10
+ import type { TemplateFallback } from "../input/chat-template";
11
+ import type { MediaTokenTexts, SentinelTokenTexts } from "../input/special-tokens";
12
+
13
+ /** An open string: a graph is a name a family declares and an implementation registers under. */
14
+ export type ModelGraph = string;
15
+ /** A named thing the engine can do. Families declare the ones their graph needs. */
16
+ export type EngineCapability = string;
17
+ export type FidelityTier = "l1" | "l2" | "l3";
18
+
19
+ export type FidelityTarget =
20
+ | Readonly<{ tier: "l1"; oracle: "mlx-lm"; claim: "bit-exact" }>
21
+ | Readonly<{ tier: "l1"; oracle: "mlx-whisper"; claim: "bit-exact" }>
22
+ | Readonly<{ tier: "l2"; oracle: "mlx-optiq"; claim: "bit-exact" }>
23
+ | Readonly<{ tier: "l3"; oracle: null; claim: "measured" }>;
24
+
25
+ export type ModelLoader = "safetensors" | "colibri";
26
+ export type GenerationLoop = "autoregressive" | "diffusion" | "encoder-decoder";
27
+ /** What a profile was declared for: an exact artifact, a family's own graphs, or
28
+ * the universal graph. Which of a family's graphs a load builds (its generic
29
+ * graph, or a written one built for the composition) is the
30
+ * family's graph table's choice (`models/implementation.ts`), not a profile's. */
31
+ export type ModelSpecialization = "artifact" | "dedicated" | "generic";
32
+
33
+ export const L1: FidelityTarget = Object.freeze({ tier: "l1", oracle: "mlx-lm", claim: "bit-exact" });
34
+ /** L1 for speech: the capability's own reference implementation (mlx-whisper)
35
+ * plays the mlx-lm role; no mlx-lm arm exists for Whisper. */
36
+ export const L1_WHISPER: FidelityTarget = Object.freeze({ tier: "l1", oracle: "mlx-whisper", claim: "bit-exact" });
37
+ export const L2: FidelityTarget = Object.freeze({ tier: "l2", oracle: "mlx-optiq", claim: "bit-exact" });
38
+ export const L3: FidelityTarget = Object.freeze({ tier: "l3", oracle: null, claim: "measured" });
39
+
40
+ /** Fine-tuning defaults a graph may declare. The CLI reads these from the
41
+ * resolved profile; nothing outside the model decides them by name. */
42
+ export interface TrainingDefaults {
43
+ /** Default maximum training sequence length in tokens. */
44
+ readonly maxSeqLength: number;
45
+ }
46
+
47
+ /** Applies to every graph that declares nothing of its own. */
48
+ export const GENERIC_TRAINING_DEFAULTS: TrainingDefaults = Object.freeze({ maxSeqLength: 4096 });
49
+
50
+ /** Request defaults a graph declares for chat generation. The server applies
51
+ * them under explicit request and server settings; nothing outside the model
52
+ * decides them by name. */
53
+ export interface GenerationDefaults {
54
+ /** `enable_thinking` when neither the request nor the server chose; absent leaves the template's own default. */
55
+ readonly enableThinking?: boolean;
56
+ /** Upper bound on the configured sampling temperature for replies with thinking off
57
+ * (model authors publish one think-mode temperature and recommend a cooler one for direct replies). */
58
+ readonly noThinkTemperatureCap: number;
59
+ }
60
+
61
+ /** Applies to every graph that declares nothing of its own. */
62
+ export const GENERIC_GENERATION_DEFAULTS: GenerationDefaults = Object.freeze({ noThinkTemperatureCap: 0.7 });
63
+
64
+ /** How a graph's pooled text embedding is formed from tokenized input. */
65
+ export interface EmbeddingDeclaration {
66
+ /** Special token appended to every input; its final hidden state is the vector. */
67
+ readonly terminator: string;
68
+ }
69
+
70
+ /** The experts a sparse graph routes each token through. */
71
+ export interface MoeDeclaration {
72
+ readonly experts: number;
73
+ readonly topK: number;
74
+ }
75
+
76
+ /** A MoE family whose config spells its experts with the shared text fields. */
77
+ export function configuredMoe(config: ModelConfig): MoeDeclaration | null {
78
+ const text = config.text;
79
+ return text.enableMoeBlock && text.numExperts > 0 ? { experts: text.numExperts, topK: text.topKExperts } : null;
80
+ }
81
+
82
+ export interface ModelFamily {
83
+ /** The graph this family runs: what profiles select, what an implementation
84
+ * registers under, and the key of every declaration below. */
85
+ readonly graph: ModelGraph;
86
+ /** The one structural rule: does this family's graph run this parsed config?
87
+ * May throw for a config too malformed to read (the generic parser does). */
88
+ accepts(config: ModelConfig): boolean;
89
+ /** Whether a bare `model_type` (a registry record, no config read) is this
90
+ * family's. False where the rule needs more than the type: MiniCPM5 shares
91
+ * `llama` and is told apart only by its dimensions. */
92
+ hasModelType(modelType: string): boolean;
93
+ /** `targeted`: a dedicated forward with its own oracle path. `generic`: the
94
+ * universal module (L1 only). */
95
+ readonly tier: "targeted" | "generic";
96
+ /** Names a targeted family in the unsupported-model message. */
97
+ readonly label?: string;
98
+ readonly loader: ModelLoader;
99
+ readonly loop: GenerationLoop;
100
+ readonly fidelity: FidelityTarget;
101
+ /** `dedicated` for a graph written for the family, `generic` for the universal one. */
102
+ readonly specialization: "dedicated" | "generic";
103
+ /** The family profile's id. */
104
+ readonly profileId: string;
105
+ /** Capabilities the graph needs of the engine, beyond its loader and loop's own. */
106
+ readonly capabilities: readonly EngineCapability[];
107
+ /** A speech-to-text family, served by the transcription engine. */
108
+ readonly transcribes?: true;
109
+ readonly moe?: (config: ModelConfig) => MoeDeclaration | null;
110
+ readonly trainingDefaults?: TrainingDefaults;
111
+ /** Present when the graph declares `GraphCapabilities.embeddings`. */
112
+ readonly embedding?: EmbeddingDeclaration;
113
+ /** Present when generated text delimits tool calls and reasoning with special tokens. */
114
+ readonly sentinels?: SentinelTokenTexts;
115
+ /** Soft-token markers of the graph's tower prompts. */
116
+ readonly mediaTokens?: MediaTokenTexts;
117
+ readonly generationDefaults?: GenerationDefaults;
118
+ /** Renders chats for artifacts that ship no template of their own. */
119
+ readonly chatTemplateFallback?: TemplateFallback;
120
+ }
121
+
122
+ /** Declare a family: typed against the record, frozen. */
123
+ export function defineFamily(family: ModelFamily): ModelFamily {
124
+ return Object.freeze(family);
125
+ }
@@ -0,0 +1,46 @@
1
+ import type { MlxArray } from "@mlx-bun/mlx/array";
2
+ import { Dtype } from "@mlx-bun/mlx/ffi";
3
+ import * as ops from "@mlx-bun/mlx/ops";
4
+ import type { Cache, KvDonorAttention } from "../../contracts/mlx/cache";
5
+ import { captureKvDonorAttention } from "../../state/kv-attention-view";
6
+ import type { AssistantAttention } from "../../contracts/mlx/attention";
7
+ import { disposeResources } from "../../runtime/resources";
8
+
9
+ /** Bind captured cache validity to Q-only attention. Encoded layouts can
10
+ * supply this same numerical port without changing the draft graph. */
11
+ export function readAssistantDonors(sliding: Cache, full: Cache) {
12
+ const views: KvDonorAttention[] = [], masks: MlxArray[] = [];
13
+ const dispose = () => disposeResources([...masks, ...views]);
14
+ try {
15
+ for (const cache of [sliding, full]) views.push(captureKvDonorAttention(cache));
16
+ const bind = (view: KvDonorAttention): AssistantAttention => {
17
+ // All draft steps borrow the same target snapshot. Build each validity
18
+ // mask once, then reuse it across matching layers and the entire chain.
19
+ const byWindow = new Map<number | null, MlxArray | null>();
20
+ return { attend(query, scale, window) {
21
+ if (!byWindow.has(window)) {
22
+ const width = view.width, B = view.offsets.length;
23
+ const starts = view.starts.map((start, row) => Math.max(start,
24
+ window === null ? start : view.ends[row]! - window));
25
+ let mask: MlxArray | null = null;
26
+ if (starts.some(start => start !== 0) || view.ends.some(end => end !== width)) {
27
+ using columns = ops.arange(0, width, 1, Dtype.int32);
28
+ using lower = ops.fromInt32(starts, [B, 1, 1, 1]);
29
+ using upper = ops.fromInt32([...view.ends], [B, 1, 1, 1]);
30
+ using before = ops.less(columns, lower);
31
+ using after = ops.greaterEqual(columns, upper);
32
+ using invalid = ops.logicalOr(before, after);
33
+ using floats = invalid.astype(view.dtype);
34
+ mask = ops.mulScalar(floats, -1e9);
35
+ masks.push(mask);
36
+ }
37
+ byWindow.set(window, mask);
38
+ }
39
+ const mask = byWindow.get(window)!;
40
+ return view.attend(query, scale, { mode: mask ? "array" : "", arr: mask });
41
+ } };
42
+ };
43
+ return { positions: views[0]!.offsets.map(offset => offset - 1),
44
+ sliding: bind(views[0]!), full: bind(views[1]!), dispose };
45
+ } catch (error) { dispose(); throw error; }
46
+ }