mlx-bun 0.2.0 → 0.4.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 (433) hide show
  1. package/README.md +71 -588
  2. package/docs/README.md +94 -0
  3. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  4. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  5. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  6. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  7. package/docs/archive/investigations/openjarvis-fit.md +198 -0
  8. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  9. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  10. package/docs/archive/investigations/qwen38-27b-campaign-log.md +1092 -0
  11. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  12. package/docs/archive/planning/release-notes-v0.3.0.md +35 -0
  13. package/docs/design/batching.md +1841 -0
  14. package/docs/design/decode-speed-program.md +2346 -169
  15. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  16. package/docs/design/generic-model-support.md +655 -334
  17. package/docs/design/kv-cache.md +824 -0
  18. package/docs/design/orpo-training.md +673 -1239
  19. package/docs/design/speculative-decoding.md +1990 -0
  20. package/docs/design/turboquant.md +2212 -0
  21. package/docs/design/unified-engine-frontier-plan.md +1833 -727
  22. package/docs/design/web-chat-redesign.md +666 -1083
  23. package/docs/planning/PRODUCT_ROADMAP.md +50 -1
  24. package/docs/planning/release-notes-v0.4.0.md +45 -0
  25. package/docs/planning/video-series.md +2 -2
  26. package/docs/reference/benchmarks.md +3613 -0
  27. package/docs/reference/cli.md +434 -160
  28. package/docs/reference/distribution.md +328 -182
  29. package/docs/reference/environment.md +398 -0
  30. package/docs/reference/glossary.md +39 -0
  31. package/docs/reference/library-api.md +566 -168
  32. package/docs/reference/memory.md +227 -64
  33. package/docs/reference/models.md +113 -6
  34. package/docs/reference/server-api.md +944 -429
  35. package/docs/reference/server-config.md +740 -338
  36. package/docs/reference/training.md +393 -254
  37. package/docs/reference/troubleshooting.md +158 -0
  38. package/package.json +9 -4
  39. package/src/audio/decode.ts +2 -2
  40. package/src/audio/features.ts +2 -2
  41. package/src/backends/mlx/assistant-target.ts +46 -0
  42. package/src/backends/mlx/autoregressive-draft-rows.ts +120 -0
  43. package/src/backends/mlx/autoregressive.ts +108 -0
  44. package/src/backends/mlx/batch-group.ts +1790 -0
  45. package/src/backends/mlx/cache-attachment.ts +67 -0
  46. package/src/backends/mlx/cache-layout.ts +31 -0
  47. package/src/backends/mlx/checkpoint-state.ts +53 -0
  48. package/src/backends/mlx/continuation-persistence.ts +106 -0
  49. package/src/backends/mlx/continuation-request.ts +43 -0
  50. package/src/backends/mlx/continuation.ts +77 -0
  51. package/src/backends/mlx/diffusion.ts +39 -0
  52. package/src/backends/mlx/draft-target.ts +32 -0
  53. package/src/backends/mlx/evaluation.ts +105 -0
  54. package/src/backends/mlx/fill-append.ts +45 -0
  55. package/src/backends/mlx/full-kv-row-append.ts +32 -0
  56. package/src/backends/mlx/full-kv-row-donor.ts +54 -0
  57. package/src/backends/mlx/full-transitioning-kv-rows.ts +65 -0
  58. package/src/backends/mlx/gateway-binding.ts +130 -0
  59. package/src/backends/mlx/graph.ts +38 -0
  60. package/src/backends/mlx/kv-codec.ts +9 -0
  61. package/src/backends/mlx/kv-maintenance.ts +133 -0
  62. package/src/backends/mlx/kv-tensor-rows.ts +212 -0
  63. package/src/backends/mlx/memory-client.ts +189 -0
  64. package/src/backends/mlx/methods.ts +90 -0
  65. package/src/backends/mlx/model-prompt.ts +164 -0
  66. package/src/backends/mlx/model-serving.ts +79 -0
  67. package/src/backends/mlx/prefill-cohort.ts +89 -0
  68. package/src/backends/mlx/prefill-rows.ts +200 -0
  69. package/src/backends/mlx/prefill.ts +33 -0
  70. package/src/backends/mlx/projected-context-rows.ts +72 -0
  71. package/src/backends/mlx/request-policy.ts +20 -0
  72. package/src/backends/mlx/request-state-policy.ts +41 -0
  73. package/src/backends/mlx/rollback.ts +89 -0
  74. package/src/backends/mlx/row-sampling.ts +49 -0
  75. package/src/backends/mlx/serial-executor.ts +242 -0
  76. package/src/backends/mlx/speculative-group.ts +359 -0
  77. package/src/backends/mlx/speculative-round.ts +161 -0
  78. package/src/backends/mlx/speculative.ts +114 -0
  79. package/src/backends/mlx/state-rows.ts +104 -0
  80. package/src/backends/mlx/state-views.ts +46 -0
  81. package/src/backends/mlx/target-layout-capability.ts +35 -0
  82. package/src/backends/mlx/text-engine.ts +73 -0
  83. package/src/backends/mlx/transitioning-kv-rows.ts +165 -0
  84. package/src/cli.ts +66 -58
  85. package/src/client.ts +66 -0
  86. package/src/config.ts +21 -4
  87. package/src/contracts/completion.ts +16 -0
  88. package/src/contracts/execution.ts +60 -0
  89. package/src/contracts/generation.ts +103 -0
  90. package/src/contracts/host.ts +7 -0
  91. package/src/contracts/jobs.ts +66 -0
  92. package/src/contracts/pi-provider.ts +30 -0
  93. package/src/contracts/pi.ts +259 -0
  94. package/src/contracts/prefix-cache.ts +23 -0
  95. package/src/contracts/resources.ts +25 -0
  96. package/src/contracts/sampling.ts +23 -0
  97. package/src/contracts/scheduling.ts +45 -0
  98. package/src/contracts/tsconfig.json +14 -0
  99. package/src/diffusion/diffusion-generate.ts +218 -153
  100. package/src/embed.ts +1 -1
  101. package/src/engine/admission.ts +59 -0
  102. package/src/engine/cancellation.ts +38 -0
  103. package/src/engine/engine.ts +56 -0
  104. package/src/engine/execution-coordinator.ts +70 -0
  105. package/src/engine/execution-plan.ts +53 -0
  106. package/src/engine/resources.ts +53 -0
  107. package/src/engine/scheduler.ts +72 -0
  108. package/src/engine/session.ts +247 -0
  109. package/src/eval/README.md +44 -1
  110. package/src/eval/kl.ts +236 -3
  111. package/src/eval/reference-logits.ts +207 -0
  112. package/src/eval/runner.ts +8 -96
  113. package/src/fill/echo-index.ts +188 -0
  114. package/src/fill/fill-session.ts +452 -0
  115. package/src/fill/proposal.ts +68 -0
  116. package/src/fill/schema-rows.ts +506 -0
  117. package/src/fill/tool-boundary.ts +103 -0
  118. package/src/fit.ts +30 -16
  119. package/src/generate.ts +709 -417
  120. package/src/grammar.ts +12 -7
  121. package/src/harness-pi.ts +14 -33
  122. package/src/hub-rest.ts +4 -4
  123. package/src/index.ts +7 -0
  124. package/src/inference/denoising.ts +17 -0
  125. package/src/inference/draft-acceptance.ts +41 -0
  126. package/src/inference/draft-output.ts +49 -0
  127. package/src/inference/graph.ts +33 -0
  128. package/src/inference/prefill.ts +39 -0
  129. package/src/inference/rollback.ts +7 -0
  130. package/src/jobs/db.ts +4 -0
  131. package/src/jobs/index.ts +2 -0
  132. package/src/jobs/job-entry.ts +12 -12
  133. package/src/jobs/runner.ts +98 -13
  134. package/src/jobs/task-client.ts +19 -0
  135. package/src/jobs/types.ts +2 -58
  136. package/src/kv-scheme.ts +70 -12
  137. package/src/kv-store.ts +177 -63
  138. package/src/lab/README.md +18 -0
  139. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  140. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  141. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +5 -5
  142. package/src/lab/paged-kv/paged-kv-rows.ts +83 -0
  143. package/src/{model → lab/paged-kv}/paged-kv.ts +32 -15
  144. package/src/library.ts +40 -0
  145. package/src/lora.ts +18 -0
  146. package/src/media-fetch.ts +1 -1
  147. package/src/memory/article.ts +1 -1
  148. package/src/memory/chunk.ts +1 -1
  149. package/src/memory/model.ts +30 -169
  150. package/src/memory/prompts.ts +1 -1
  151. package/src/memory/rest.ts +1 -1
  152. package/src/memory/schedule.ts +1 -1
  153. package/src/memory/stages.ts +4 -1
  154. package/src/memory/vault.ts +1 -3
  155. package/src/mlx/array.ts +11 -11
  156. package/src/mlx/compile.ts +12 -2
  157. package/src/mlx/ffi.ts +58 -11
  158. package/src/mlx/materialize.ts +23 -0
  159. package/src/mlx/metal-kernel.ts +10 -11
  160. package/src/mlx/ops.ts +33 -13
  161. package/src/mlx/quantized-rows.ts +36 -0
  162. package/src/mlx/token-bitmask.ts +52 -0
  163. package/src/mlx/turboquant-kv-decode.ts +82 -0
  164. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  165. package/src/mlx/turboquant-ops.ts +33 -3
  166. package/src/mlx/turboquant-tables.ts +2 -2
  167. package/src/model/artifact-identity.ts +73 -0
  168. package/src/model/batched-kv.ts +235 -0
  169. package/src/model/batched-mask.ts +20 -6
  170. package/src/model/batched-quant.ts +9 -3
  171. package/src/model/batched-quantized-kv.ts +144 -0
  172. package/src/model/batched-rotating-quant.ts +78 -17
  173. package/src/model/batched-rotating-state.ts +76 -0
  174. package/src/model/batched-rotating.ts +65 -23
  175. package/src/model/batched-row-storage.ts +52 -0
  176. package/src/model/batched-ssm.ts +52 -0
  177. package/src/model/batched-turboquant-kv.ts +93 -0
  178. package/src/model/compiled-decode.ts +8 -2
  179. package/src/model/decoded-kv-donor.ts +12 -0
  180. package/src/model/delayed-quantized-kv.ts +72 -0
  181. package/src/model/delayed-rotating-quantized-kv.ts +93 -0
  182. package/src/model/delayed-turboquant-kv.ts +55 -0
  183. package/src/model/diffusion-gemma.ts +8 -8
  184. package/src/model/factory.ts +76 -33
  185. package/src/model/fingerprint.ts +1 -1
  186. package/src/model/flash-attention.ts +3 -3
  187. package/src/model/full-prefill-padding.ts +56 -0
  188. package/src/model/full-prefill-row.ts +105 -0
  189. package/src/model/gemma4-base.ts +179 -80
  190. package/src/model/gemma4.ts +40 -32
  191. package/src/model/generated/gemma4-12b.ts +6 -3
  192. package/src/model/generated/gemma4-26b.ts +6 -3
  193. package/src/model/generated/gemma4-e4b.ts +6 -3
  194. package/src/model/glm52-cache.ts +80 -4
  195. package/src/model/glm52-dsa.ts +13 -9
  196. package/src/model/glm52-memory.ts +1 -1
  197. package/src/model/glm52-mla.ts +12 -6
  198. package/src/model/glm52.ts +19 -40
  199. package/src/model/implementation.ts +69 -0
  200. package/src/model/kv-attention-view.ts +67 -0
  201. package/src/model/minicpm5.ts +17 -15
  202. package/src/model/profile.ts +12 -2
  203. package/src/model/qwen-append.ts +12 -0
  204. package/src/model/qwen-conv.ts +52 -0
  205. package/src/model/qwen3-delta-state.ts +74 -0
  206. package/src/model/qwen3-delta.ts +59 -36
  207. package/src/model/qwen3_5-checkpoint.ts +164 -0
  208. package/src/model/qwen3_5.ts +202 -78
  209. package/src/model/rotating-kv-donor.ts +35 -0
  210. package/src/model/rotating-kv-layout.ts +262 -0
  211. package/src/model/rotating-row-transaction.ts +35 -0
  212. package/src/model/speculative-rotating-kv.ts +101 -0
  213. package/src/model/ssm-prefill-padding.ts +39 -0
  214. package/src/model/support.ts +1 -1
  215. package/src/model/trellis-balanced-scatter.ts +51 -0
  216. package/src/model/trellis-linear.ts +672 -0
  217. package/src/model/trellis-shared-m.ts +151 -0
  218. package/src/model/trellis-shared-scatter.ts +144 -0
  219. package/src/model/trellis-splitk-prefill.ts +158 -0
  220. package/src/model/trellis-tiled-prefill.ts +136 -0
  221. package/src/model/trellis-vector-expand.ts +62 -0
  222. package/src/model/trellis-wide-prefill.ts +94 -0
  223. package/src/model/turboquant-codec.ts +83 -0
  224. package/src/model/universal/dense.ts +15 -14
  225. package/src/model/universal/modules.ts +8 -1
  226. package/src/native-pack.ts +6 -5
  227. package/src/pi-provider.ts +6 -64
  228. package/src/pi-web.ts +8 -315
  229. package/src/preflight.ts +31 -15
  230. package/src/prompt-cache.ts +110 -69
  231. package/src/quantize/allocator.ts +1 -1
  232. package/src/quantize/config-writer.ts +10 -3
  233. package/src/quantize/rotate.ts +4 -4
  234. package/src/quantize/trellis.ts +586 -0
  235. package/src/responses.ts +28 -1
  236. package/src/runtime-config.ts +18 -4
  237. package/src/sampler.ts +40 -29
  238. package/src/serve/batch-scheduler.ts +8 -1671
  239. package/src/serve/chat-request.ts +391 -0
  240. package/src/serve/chat-stage.ts +195 -0
  241. package/src/serve/checkpoint-identity.ts +64 -0
  242. package/src/serve/completion-executor.ts +15 -7
  243. package/src/serve/discovery-routes.ts +12 -13
  244. package/src/serve/generation-gateway.ts +183 -213
  245. package/src/serve/http.ts +159 -0
  246. package/src/serve/inference-request.ts +79 -0
  247. package/src/serve/isolate.ts +297 -105
  248. package/src/serve/lab-routes.ts +3 -0
  249. package/src/serve/lane-registry.ts +2 -1
  250. package/src/serve/model-admin-routes.ts +7 -5
  251. package/src/serve/model-binding.ts +43 -0
  252. package/src/serve/model-host.ts +511 -0
  253. package/src/serve/openai-wire.ts +103 -0
  254. package/src/serve/parent-application.ts +56 -0
  255. package/src/serve/pipeline.ts +33 -0
  256. package/src/serve/preparation.ts +33 -0
  257. package/src/serve/request-plan.ts +23 -18
  258. package/src/serve/request-prep.ts +344 -0
  259. package/src/serve/response-lease.ts +24 -0
  260. package/src/serve/responses-client.ts +69 -0
  261. package/src/serve/session-completion-engine.ts +110 -0
  262. package/src/serve/session-search.ts +1 -1
  263. package/src/serve/static-routes.ts +5 -5
  264. package/src/serve/text-completion-stage.ts +104 -0
  265. package/src/serve/token-streams.ts +519 -0
  266. package/src/server.ts +335 -2711
  267. package/src/spec/assistant-rows.ts +92 -0
  268. package/src/spec/assistant-source.ts +31 -55
  269. package/src/spec/cache-identity.ts +22 -0
  270. package/src/spec/deepspec-rows.ts +29 -0
  271. package/src/spec/deepspec-source.ts +16 -14
  272. package/src/spec/dflash-source.ts +36 -12
  273. package/src/spec/drafter.ts +153 -142
  274. package/src/spec/dspark/ab-stats.ts +3 -3
  275. package/src/spec/dspark/calibration.ts +2 -2
  276. package/src/spec/dspark/deepspec-module.ts +97 -122
  277. package/src/spec/dspark/generate-dflash.ts +2 -2
  278. package/src/spec/dspark/generate.ts +2 -2
  279. package/src/spec/dspark/loader.ts +1 -1
  280. package/src/spec/dspark/module-dflash.ts +129 -172
  281. package/src/spec/dspark/module.ts +3 -3
  282. package/src/spec/dspark/quantize-drafter.ts +1 -1
  283. package/src/spec/generate.ts +1 -1
  284. package/src/spec/glm52-mtp-graph.ts +29 -0
  285. package/src/spec/glm52-mtp-rows.ts +132 -0
  286. package/src/spec/glm52-mtp-source.ts +54 -137
  287. package/src/spec/glm52-mtp-state.ts +33 -0
  288. package/src/spec/ngram-source.ts +93 -21
  289. package/src/spec/projected-draft-rows.ts +73 -0
  290. package/src/spec/qwen-mtp-module.ts +171 -0
  291. package/src/spec/qwen-mtp-rows.ts +219 -0
  292. package/src/spec/qwen-mtp-source.ts +147 -195
  293. package/src/spec/qwen-mtp-state.ts +30 -0
  294. package/src/spec/serve-loop.ts +201 -201
  295. package/src/spec/source.ts +110 -13
  296. package/src/spec/two-model-rows.ts +61 -0
  297. package/src/spec/two-model.ts +44 -102
  298. package/src/ssd-cache.ts +99 -19
  299. package/src/ssd-durability.ts +36 -20
  300. package/src/tool-call.ts +51 -14
  301. package/src/train/flash-cce.ts +2 -2
  302. package/src/train/forward.ts +6 -0
  303. package/src/train/loss.ts +1 -1
  304. package/src/train/prefix-shared.ts +5 -1
  305. package/src/train/segmented.ts +5 -3
  306. package/src/train/trainer.ts +6 -6
  307. package/src/vision/prompt.ts +1 -1
  308. package/src/vision/qwen3vl-tower.ts +52 -10
  309. package/src/web/app.html +1 -1
  310. package/src/web/app.js +62 -60
  311. package/src/web/src/adapters-panel.ts +3 -3
  312. package/src/web/src/assistant.ts +2 -36
  313. package/src/web/src/chat.ts +4 -4
  314. package/src/web/src/composer.ts +4 -4
  315. package/src/web/src/hub.ts +1 -1
  316. package/src/web/src/markdown.ts +0 -0
  317. package/src/web/src/memory-panel.ts +1 -1
  318. package/src/web/src/model-picker.ts +1 -1
  319. package/src/web/src/palette.ts +1 -1
  320. package/src/web/src/protocol.ts +3 -39
  321. package/src/web/src/sessions.ts +1 -1
  322. package/src/web/src/ui-catalog.ts +4 -18
  323. package/src/web-assets.ts +47 -0
  324. package/src/weights.ts +55 -9
  325. package/docs/archive/investigations/curve-runs/bisector-route.json +0 -98
  326. package/docs/archive/investigations/curve-runs/bisector-trace.json +0 -1393
  327. package/docs/archive/investigations/curve-runs/curve-terrain.json +0 -1179
  328. package/docs/archive/investigations/curve-runs/curve-terrain.svg +0 -42
  329. package/docs/archive/investigations/hlg-ab.html +0 -34
  330. package/docs/archive/investigations/hlg-explorer.html +0 -238
  331. package/docs/archive/investigations/hlg-figs/cliff.svg +0 -1
  332. package/docs/archive/investigations/hlg-figs/cross.svg +0 -1
  333. package/docs/archive/investigations/hlg-figs/edges.svg +0 -1
  334. package/docs/archive/investigations/hlg-figs/k20-grids.svg +0 -1
  335. package/docs/archive/investigations/hlg-figs/k20-peaks.svg +0 -1
  336. package/docs/archive/investigations/hlg-figs/lw-curve.svg +0 -1
  337. package/docs/archive/investigations/hlg-figs/terrain.svg +0 -1
  338. package/docs/archive/investigations/hlg-report.html +0 -262
  339. package/docs/archive/investigations/hlg-runs/hlg-ab.json +0 -149
  340. package/docs/archive/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  341. package/docs/archive/investigations/hlg-runs/hlg-blind.json +0 -107
  342. package/docs/archive/investigations/hlg-runs/hlg-cliff.json +0 -197
  343. package/docs/archive/investigations/hlg-runs/hlg-cross.json +0 -505
  344. package/docs/archive/investigations/hlg-runs/hlg-edge.json +0 -388
  345. package/docs/archive/investigations/hlg-runs/hlg-eval1.json +0 -25
  346. package/docs/archive/investigations/hlg-runs/hlg-frontier.json +0 -86
  347. package/docs/archive/investigations/hlg-runs/hlg-grid.json +0 -242
  348. package/docs/archive/investigations/hlg-runs/hlg-grid2.json +0 -343
  349. package/docs/archive/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  350. package/docs/archive/investigations/hlg-runs/hlg-map.json +0 -383
  351. package/docs/archive/investigations/hlg-runs/run0-original.log +0 -159
  352. package/docs/archive/investigations/hlg-runs/runA-recommended.log +0 -131
  353. package/docs/archive/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  354. package/docs/archive/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  355. package/docs/archive/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  356. package/docs/archive/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  357. package/docs/archive/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  358. package/docs/archive/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  359. package/docs/archive/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  360. package/docs/archive/investigations/hlg-runs/runB-gain-variants.log +0 -192
  361. package/docs/archive/investigations/hlg-runs/runC-pivots.log +0 -162
  362. package/docs/archive/investigations/hlg-runs/runD-oetf.log +0 -132
  363. package/docs/archive/investigations/hlg-runs/runE-eotf.log +0 -162
  364. package/docs/archive/investigations/hlg-runs/runF-shaper-working.log +0 -86
  365. package/docs/archive/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  366. package/docs/archive/investigations/hlg-runs/runH-wsweep.log +0 -176
  367. package/docs/archive/investigations/hlg-runs/runI-asweep.log +0 -176
  368. package/docs/archive/investigations/hlg-runs/runJ-knobmap.log +0 -49
  369. package/docs/archive/investigations/hlg-runs/runK-frontier.log +0 -19
  370. package/docs/archive/investigations/hlg-runs/runL-widemap.log +0 -65
  371. package/docs/archive/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  372. package/docs/archive/investigations/hlg-runs/runN-verify.log +0 -116
  373. package/docs/archive/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  374. package/docs/archive/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  375. package/docs/archive/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  376. package/docs/archive/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  377. package/docs/archive/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  378. package/docs/archive/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  379. package/docs/archive/investigations/hlg-runs/runU-cross-12b.log +0 -33
  380. package/docs/archive/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  381. package/docs/archive/investigations/hlg-runs/runW-lw-12b.log +0 -22
  382. package/docs/archive/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  383. package/docs/archive/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  384. package/docs/archive/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  385. package/docs/archive/mlx-bun-lab-report.html +0 -275
  386. package/docs/archive/wwdc-mlx-bun.html +0 -848
  387. package/docs/design/adapters-end-to-end.md +0 -205
  388. package/docs/design/batching-perf-path.md +0 -255
  389. package/docs/design/batching-v2-plan.md +0 -529
  390. package/docs/design/bucketing-stage.md +0 -197
  391. package/docs/design/compat-cli-surface-design.md +0 -230
  392. package/docs/design/docs-reorg-plan.md +0 -165
  393. package/docs/design/dspark-serving-program.md +0 -371
  394. package/docs/design/dspark-speculative-decoding.md +0 -318
  395. package/docs/design/grammar-spec-batching-integration.md +0 -301
  396. package/docs/design/memory-inference-path.md +0 -422
  397. package/docs/design/memory-synthesis.md +0 -287
  398. package/docs/design/memory-system.md +0 -237
  399. package/docs/design/mlx-lm-serving-execution-seam.md +0 -81
  400. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  401. package/docs/design/omlx-adoption-map.md +0 -98
  402. package/docs/design/orpo-dynamic-lambda.md +0 -220
  403. package/docs/design/orpo-future-enhancements.md +0 -340
  404. package/docs/design/paged-kv-cache.md +0 -214
  405. package/docs/design/parallel-slots.md +0 -567
  406. package/docs/design/parity-tier-dag.md +0 -161
  407. package/docs/design/repo-cleanup-plan.md +0 -231
  408. package/docs/design/runtime-isolation.md +0 -263
  409. package/docs/design/segmented-backward-training.md +0 -543
  410. package/docs/design/spec-decode-larger-targets.md +0 -229
  411. package/docs/design/ssd-kv-cold-tier.md +0 -415
  412. package/docs/design/structured-output.md +0 -484
  413. package/docs/design/tauri-desktop-app.md +0 -127
  414. package/docs/design/the-dreaming-master-plan.md +0 -445
  415. package/docs/design/turboquant-kv.md +0 -235
  416. package/docs/design/turboquant-weights.md +0 -467
  417. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  418. package/docs/design/web-chat-beat-matrix.md +0 -315
  419. package/docs/design/write-pipeline-entity.md +0 -468
  420. package/docs/planning/IDEAS.md +0 -69
  421. package/docs/reference/embedding.md +0 -197
  422. package/docs/reference/features-matrix.md +0 -101
  423. package/docs/reference/orpo-quickstart.md +0 -135
  424. package/src/flags.ts +0 -11
  425. /package/docs/{design → archive/investigations}/colibri-glm52-port.md +0 -0
  426. /package/docs/{planning → archive/planning}/chunk-task-roadmap.md +0 -0
  427. /package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +0 -0
  428. /package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +0 -0
  429. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  430. /package/docs/{planning → archive/planning}/release-notes-v0.2.0.md +0 -0
  431. /package/src/{memory-plan.ts → admission-plan.ts} +0 -0
  432. /package/{docs/archive/investigations → src/serve/assets}/curve-terrain.html +0 -0
  433. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
@@ -1,7 +1,7 @@
1
1
  // Paged KV cache — vLLM-style block-pool storage behind the standard Cache
2
- // interface (docs/design/paged-kv-cache.md). OPTIONAL and default-off
3
- // (`--paged-kv` / GenerateOptions.pagedKv); v1 scope is serial batch=1
4
- // decode on Gemma4-family plain full-attention layers, bf16 only.
2
+ // interface (docs/design/kv-cache.md). OPTIONAL and default-off
3
+ // (`--paged-kv` / GenerateOptions.pagedKv); Gemma4-family plain full-attention
4
+ // layers, bf16 only. PagedKvRows composes independent pools at B1/B>1.
5
5
  //
6
6
  // Storage: K/V live in fixed-size per-layer pool tensors
7
7
  // [numBlocks, H_kv, blockSize, headDim]; a host-side block table maps the
@@ -11,20 +11,19 @@
11
11
  // block axis + transpose + reshape) and hand that to the unchanged
12
12
  // ops.sdpa call site — identical bytes to what a plain KVCache would have
13
13
  // fetched, so the paged path is gated bit-exact, not KL-tolerated
14
- // (tests/paged-kv-parity.test.ts). The gather IS the cost: a full K/V copy
14
+ // (tests/parity/paged-kv-parity.test.ts). The gather IS the cost: a full K/V copy
15
15
  // per step, pure bandwidth tax at batch=1 — v1 ships the abstraction for
16
16
  // the batched/CoW follow-ups, not a speed win (see the design doc's
17
17
  // Motivation, which says this honestly).
18
18
  //
19
19
  // Deliberately NOT a KVCache subclass (the TurboQuantKVCache reasoning):
20
- // every instanceof gate in the tree — CompiledDecode.supports, the batch
21
- // gateway's #modelCachesBatchable, generated forwards' #matches() — must
22
- // EXCLUDE paged caches and fall back to the monolith/uncompiled path.
20
+ // compiled graph adapters exclude the changing block-list geometry. The
21
+ // cache-layout binding supplies dynamic rows independently of scheduling.
23
22
 
24
- import { MlxArray } from "../mlx/array";
25
- import { Dtype } from "../mlx/ffi";
26
- import * as ops from "../mlx/ops";
27
- import { createCausalMask, type Cache, type Mask } from "./gemma4-base";
23
+ import { MlxArray } from "../../mlx/array";
24
+ import { Dtype } from "../../mlx/ffi";
25
+ import * as ops from "../../mlx/ops";
26
+ import { createCausalMask, type Cache, type Mask } from "../../model/gemma4-base";
28
27
 
29
28
  /** Typed pool-exhaustion error: a generation outgrew its pool. Sizing from
30
29
  * prompt+maxTokens at construction makes this unreachable in practice;
@@ -58,16 +57,24 @@ export class BlockPool {
58
57
  * reach v1's gemma4 scope, but the pool stays shape-honest). */
59
58
  vHeadDim?: number;
60
59
  dtype: Dtype;
61
- }) {
60
+ }, source?: BlockPool) {
62
61
  this.numBlocks = opts.numBlocks;
63
62
  this.blockSize = opts.blockSize;
64
- this.keys = ops.zeros(
63
+ this.keys = source ? ops.contiguous(source.keys) : ops.zeros(
65
64
  [opts.numBlocks, opts.numKvHeads, opts.blockSize, opts.headDim], opts.dtype);
66
- this.values = ops.zeros(
65
+ this.values = source ? ops.contiguous(source.values) : ops.zeros(
67
66
  [opts.numBlocks, opts.numKvHeads, opts.blockSize, opts.vHeadDim ?? opts.headDim],
68
67
  opts.dtype);
69
68
  // LIFO free list, low indices first — deterministic layout for tests.
70
- this.#free = Array.from({ length: opts.numBlocks }, (_, i) => opts.numBlocks - 1 - i);
69
+ this.#free = source ? [...source.#free] : Array.from({ length: opts.numBlocks }, (_, i) => opts.numBlocks - 1 - i);
70
+ }
71
+
72
+ /** Independent ownership and allocation metadata over immutable MLX buffers.
73
+ * Functional writes detach storage while another snapshot retains it. */
74
+ clone(): BlockPool {
75
+ return new BlockPool({ numBlocks: this.numBlocks, blockSize: this.blockSize,
76
+ numKvHeads: this.keys.shape[1]!, headDim: this.keys.shape[3]!,
77
+ vHeadDim: this.values.shape[3]!, dtype: this.keys.dtype }, this);
71
78
  }
72
79
 
73
80
  get freeBlocks(): number {
@@ -134,6 +141,8 @@ export class BlockPool {
134
141
  * shape): head count / head dims / dtype come from the first k/v pair,
135
142
  * so the wiring (maybePageKv) needs no per-model shape plumbing. */
136
143
  export class PagedKVCache implements Cache {
144
+ /** Distinct storage kind; the row adapter preserves its block pools. */
145
+ signature(): string { return "kv:paged"; }
137
146
  /** Matches KVCache.STEP: v1's growth granularity is a permutation of
138
147
  * today's 256-token step into fixed reusable slots, not a new tuning
139
148
  * axis (--paged-kv-block-size overrides for experiments). */
@@ -152,6 +161,14 @@ export class PagedKVCache implements Cache {
152
161
  readonly blockSize: number,
153
162
  ) {}
154
163
 
164
+ clone(): PagedKVCache {
165
+ const copy = new PagedKVCache(this.capacityTokens, this.blockSize);
166
+ copy.offset = this.offset;
167
+ copy.blockTable = [...this.blockTable];
168
+ copy.pool = this.pool?.clone() ?? null;
169
+ return copy;
170
+ }
171
+
155
172
  get #blockSize(): number {
156
173
  return this.blockSize;
157
174
  }
package/src/library.ts ADDED
@@ -0,0 +1,40 @@
1
+ /** CPU-safe high-level entry. Native modules load only after bootstrap. */
2
+ export { createInferenceEngine } from "./engine/engine";
3
+ export { CancellationSource } from "./engine/cancellation";
4
+ export { createCompletionClient, createDirectHost } from "./client";
5
+ export type * from "./contracts/generation";
6
+ export type * from "./contracts/completion";
7
+ export type * from "./contracts/host";
8
+
9
+ /** Install/locate the native pack before importing the compatibility API. */
10
+ export async function initializeMlx(): Promise<typeof import("./index")> {
11
+ const { ensureNativeRuntime } = await import("./native-pack");
12
+ await ensureNativeRuntime();
13
+ return import("./index");
14
+ }
15
+
16
+ /** Own one local worker. Model resolution and native initialization remain in
17
+ * the existing CLI; importing this module does not start it or download weights. */
18
+ export async function openIsolatedHost(model: string, options: {
19
+ arguments?: readonly string[];
20
+ command?: readonly string[];
21
+ readyTimeoutMs?: number;
22
+ } = {}): Promise<import("./contracts/host").EngineHost<Request, Response>> {
23
+ const { EngineChild } = await import("./serve/isolate");
24
+ const { tmpdir } = await import("node:os");
25
+ const { join } = await import("node:path");
26
+ const { fileURLToPath } = await import("node:url");
27
+ const source = fileURLToPath(new URL("./cli.ts", import.meta.url));
28
+ if (!options.command && source.includes("$bunfs"))
29
+ throw new Error("a compiled library consumer must supply the mlx-bun executable as command");
30
+ const command = options.command ?? [process.execPath, source];
31
+ if (!command.length) throw new Error("engine command must not be empty");
32
+ const socketPath = join(tmpdir(), `mlx-bun-library-${crypto.randomUUID()}.sock`);
33
+ const host = new EngineChild({
34
+ argv: [...command,
35
+ "serve", "--model", model, ...options.arguments ?? [], "--unix", socketPath, "--no-open"],
36
+ socketPath, readyTimeoutMs: options.readyTimeoutMs,
37
+ });
38
+ try { await host.ready; return host; }
39
+ catch (error) { await host.close(); throw error; }
40
+ }
package/src/lora.ts CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  import { existsSync, readdirSync, statSync } from "node:fs";
14
14
  import { resolve } from "node:path";
15
+ import { createHash } from "node:crypto";
15
16
  import { ptr, read } from "bun:ffi";
16
17
  import { MlxArray, cpuStream } from "./mlx/array";
17
18
  import { C } from "./mlx/ffi";
@@ -198,6 +199,7 @@ export class AdapterManager {
198
199
  readonly #mounted = new Map<string, AdapterInfo>();
199
200
  /** Owned adapter arrays per id (disposed on unmount). */
200
201
  readonly #arrays = new Map<string, MlxArray[]>();
202
+ readonly #revisions = new Map<string, string>();
201
203
 
202
204
  constructor(model: RuntimeModel) {
203
205
  this.#model = model;
@@ -216,6 +218,11 @@ export class AdapterManager {
216
218
 
217
219
  const weightsFile = adapterWeightsFile(path);
218
220
  const { scale, rank: configRank, rsLora } = await readAdapterScale(path);
221
+ // Hash once at mount, before native allocation. Reusing an adapter name
222
+ // for different weights or scale must never reuse its prefix/checkpoint.
223
+ const digest = createHash("sha256").update(JSON.stringify({ scale, rank: configRank, rsLora }));
224
+ for await (const chunk of Bun.file(weightsFile).stream()) digest.update(chunk);
225
+ const revision = digest.digest("hex");
219
226
  const tensors = loadAdapterTensors(weightsFile);
220
227
  const targets = this.#model.loraTargets();
221
228
 
@@ -347,6 +354,7 @@ export class AdapterManager {
347
354
  ramBytes,
348
355
  };
349
356
  this.#mounted.set(id, info);
357
+ this.#revisions.set(id, revision);
350
358
  this.#arrays.set(id, validated.flatMap(({ lw }) => [lw.a, lw.b]));
351
359
  return info;
352
360
  }
@@ -355,6 +363,7 @@ export class AdapterManager {
355
363
  * stay in place for other adapters, like the reference. */
356
364
  unmount(id: string): number {
357
365
  if (!this.#mounted.delete(id)) return 0;
366
+ this.#revisions.delete(id);
358
367
  let removed = 0;
359
368
  for (const linear of this.#model.loraTargets().values()) {
360
369
  if (linear.adapters?.delete(id)) removed++;
@@ -366,6 +375,15 @@ export class AdapterManager {
366
375
  return removed;
367
376
  }
368
377
 
378
+ /** Ordered, content-addressed namespace for the actual mounted composition. */
379
+ cacheNamespace(ids: readonly string[]): string {
380
+ return ids.map((id) => {
381
+ const revision = this.#revisions.get(id);
382
+ if (!revision) throw new Error(`adapter ${id} is no longer mounted`);
383
+ return `${id}@${revision}`;
384
+ }).join("+");
385
+ }
386
+
369
387
  list(): AdapterInfo[] {
370
388
  return [...this.#mounted.values()];
371
389
  }
@@ -17,7 +17,7 @@
17
17
  // preserving the logical Host header and HTTPS SNI, so the transport cannot
18
18
  // re-resolve to a private address between validation and connect.
19
19
  //
20
- // This module must stay free of mlx imports so tests/media-fetch.test.ts
20
+ // This module must stay free of mlx imports so tests/unit/media-fetch.test.ts
21
21
  // runs model-free.
22
22
 
23
23
  import { lookup } from "node:dns/promises";
@@ -3,7 +3,7 @@
3
3
  // The Dreaming write pipeline emits Wikipedia-shaped articles: each entity gets
4
4
  // one Markdown file with a fixed top-to-bottom skeleton —
5
5
  // H1 → series banner → infobox → lead → sections → See also → Notes → References
6
- // (see docs/design/the-dreaming-master-plan.md and write-pipeline-entity.md).
6
+ // (see docs/design/dreaming-nightly-pipeline.md and docs/design/dreaming-nightly-pipeline.md).
7
7
  // This module reads that grammar deterministically: the structured outputs the
8
8
  // read side traverses (infobox key-value facts, the [[wikilink]] graph, footnote
9
9
  // bijection) are parsed here, never by the model.
@@ -16,7 +16,7 @@
16
16
  //
17
17
  // Re-chunk only conversations whose updated_at > chunked_at (NULL chunked_at = a
18
18
  // never-segmented conversation). Setting chunked_at after a successful run makes
19
- // re-running a no-op. See docs/design/the-dreaming-master-plan.md → P5-T2.
19
+ // re-running a no-op. See docs/design/dreaming-nightly-pipeline.md → P5-T2.
20
20
 
21
21
  import { MemoryStore, chunkId } from "./db";
22
22
  import { callLocal, type LocalInput } from "./model";
@@ -24,12 +24,8 @@
24
24
  // server and to the trainer's prompt-region render (dataset.ts:98-101).
25
25
 
26
26
  import { existsSync, readdirSync } from "node:fs";
27
- import { loadTaskModel, greedyDecodeBitExact, type TaskModel } from "../eval/runner";
28
27
  import type { ChatMessage, ChatTemplate } from "../chat-template";
29
28
  import type { LoadedTokenizer } from "../tokenizer";
30
- import { BatchScheduler, type RowSampler } from "../serve/batch-scheduler";
31
- import * as ops from "../mlx/ops";
32
- import type { MlxArray } from "../mlx/array";
33
29
  import { runtimeValue } from "../runtime-config";
34
30
 
35
31
  const HF_HUB = `${process.env.HOME}/.cache/huggingface/hub`;
@@ -38,7 +34,7 @@ const E4B_REPO = "models--mlx-community--gemma-4-e4b-it-OptiQ-4bit";
38
34
  /** Resolve the e4b snapshot dir by globbing snapshots/ for the one carrying
39
35
  * config.json — so a freshly-downloaded model needs no hardcoded commit hash.
40
36
  * Returns an _unresolved sentinel (precheck → STOP) until the download lands.
41
- * Mirrors tests/paths.ts hfSnapshot / SNAPSHOT_E4B, inlined to keep src self-
37
+ * Mirrors tests/support/paths.ts hfSnapshot / SNAPSHOT_E4B, inlined to keep src self-
42
38
  * contained (no src→tests dependency). */
43
39
  function resolveE4bSnapshot(): string {
44
40
  const base = `${HF_HUB}/${E4B_REPO}/snapshots`;
@@ -140,30 +136,18 @@ export function memoryPromptIds(
140
136
  /** Async mutex: acquire() resolves to a release fn; releases run FIFO. Serializes
141
137
  * memory generation ops so the global `loraState.active` is owned exclusively for
142
138
  * one op's lifetime (set for the chunk batch, reset after). */
143
- class AsyncMutex {
144
- #tail: Promise<void> = Promise.resolve();
145
- acquire(): Promise<() => void> {
146
- let release!: () => void;
147
- const gate = new Promise<void>((r) => { release = r; });
148
- const wait = this.#tail;
149
- this.#tail = this.#tail.then(() => gate);
150
- return wait.then(() => release);
151
- }
152
- }
153
-
154
- interface MemoryRuntime {
155
- tm: TaskModel;
156
- template: ChatTemplate;
157
- scheduler: BatchScheduler;
158
- /** True once the `memory-chunk` adapter is mounted on the shared model. */
159
- hasChunkAdapter: boolean;
139
+ export interface MemoryCompletionRequest {
140
+ readonly stage: string;
141
+ readonly input: LocalInput;
142
+ readonly maxTokens: number;
160
143
  }
144
+ export type MemoryCompletionClient = import("../contracts/completion").BatchCompletionClient<MemoryCompletionRequest, string>;
161
145
 
162
146
  /** Max rows in a memory batch (continuous-batching width). 1 disables batching
163
147
  * (callLocalBatch then loops on the bit-exact greedy fallback).
164
148
  * Default 1 (serial): batching measured 1.7-1.9x SLOWER for the real
165
149
  * extract/chunk workload (heterogeneous prefills pad) and can diverge on
166
- * near-ties — see docs/design/memory-inference-path.md "Verification results".
150
+ * near-ties — see docs/design/dreaming-nightly-pipeline.md "Verification results".
167
151
  * Opt back in with MLX_BUN_MEMORY_BATCH=8 if a length-bucketed scheduler
168
152
  * lands. (Decision: Josh, 2026-07-01.) */
169
153
  export function memoryBatchSize(): number {
@@ -171,152 +155,29 @@ export function memoryBatchSize(): number {
171
155
  return Number.isFinite(n) && n >= 1 ? Math.floor(n) : 1;
172
156
  }
173
157
 
174
- function requireModel(): void {
175
- if (!existsSync(`${MODEL_ID}/config.json`)) {
176
- throw new Error(
177
- `memory: Gemma-4-e4b is not downloaded (looked under ${HF_HUB}/${E4B_REPO}/snapshots). ` +
178
- `Fetch it first:\n HF_HUB_DISABLE_XET=1 hf download mlx-community/gemma-4-e4b-it-OptiQ-4bit`,
179
- );
180
- }
181
- }
182
-
183
- let runtimePromise: Promise<MemoryRuntime> | null = null;
184
- const opLock = new AsyncMutex(); // serializes whole memory ops (loraState ownership)
185
- const schedLock = new AsyncMutex(); // the scheduler's exclusive-GPU lock
186
-
187
- /** Lazily load the ONE shared model + mount memory-chunk + build the scheduler.
188
- * Never auto-downloads; throws (with the fetch hint) until the snapshot lands. */
189
- async function getRuntime(): Promise<MemoryRuntime> {
190
- if (!runtimePromise) {
191
- runtimePromise = (async () => {
192
- requireModel();
193
- const tm = await loadTaskModel(MODEL_ID); // base e4b, no adapter
194
- if (!tm.template) throw new Error(`memory: ${MODEL_ID} has no chat template`);
195
- let hasChunkAdapter = false;
196
- const chunkDir = adapterDirFor("chunk");
197
- if (chunkDir) {
198
- // Mount ONCE; activation is per-call via loraState.active (see decodeGreedy
199
- // / batchDecode). Mounting alone runs base — it must be activated.
200
- const { AdapterManager } = await import("../lora");
201
- await new AdapterManager(tm.model).mount("memory-chunk", chunkDir);
202
- hasChunkAdapter = true;
203
- }
204
- const scheduler = new BatchScheduler(tm.model, {
205
- maxBatch: memoryBatchSize(),
206
- lock: { acquire: () => schedLock.acquire() },
207
- });
208
- return { tm, template: tm.template, scheduler, hasChunkAdapter };
209
- })();
210
- }
211
- return runtimePromise;
212
- }
213
-
214
- /** The adapters to activate for a stage. Only `chunk` is adapter-bound (and only
215
- * when `memory-chunk` is mounted); every base stage runs with `active = []`. */
216
- function activeFor(stage: string, rt: MemoryRuntime): string[] {
217
- return stage === "chunk" && rt.hasChunkAdapter ? ["memory-chunk"] : [];
218
- }
219
-
220
- /** One bit-exact greedy decode for a stage (raw-forward argmax, runner parity).
221
- * Sets the stage's adapter for the call and resets `active` to [] after. */
222
- function decodeGreedy(rt: MemoryRuntime, stage: string, input: LocalInput, maxTokens: number): string {
223
- const active = activeFor(stage, rt);
224
- rt.tm.model.loraState.active = active;
225
- const ids = memoryPromptIds(stage, input, rt.tm.tokenizer, rt.template);
226
- try {
227
- return greedyDecodeBitExact(
228
- { ...rt.tm, activeAdapters: active.length ? active : undefined },
229
- ids,
230
- maxTokens,
231
- );
232
- } finally {
233
- rt.tm.model.loraState.active = [];
234
- }
235
- }
236
-
237
- /** Batched decode for N independent inputs of ONE stage. Sets the stage adapter
238
- * globally for the whole batch (the scheduler reads `loraState.active` per
239
- * forward, so all rows get it uniformly — a batch is necessarily single-adapter),
240
- * submits every row to the shared scheduler with a greedy per-row sampler, and
241
- * resets `active` after all rows finish. Order-preserving: out[i] ↔ inputs[i].
242
- *
243
- * Decode-path caveat: this samples via forwardHidden/logitsFromHidden (the
244
- * scheduler), which can diverge from the runner's raw-forward greedy on near-ties
245
- * past ~32 tokens. For the JSON/binary memory stages (validated by
246
- * well-formedness) this is acceptable; the single-call fallback stays bit-exact. */
247
- async function batchDecode(
248
- rt: MemoryRuntime,
249
- stage: string,
250
- inputs: LocalInput[],
251
- maxTokens: number,
252
- ): Promise<string[]> {
253
- const active = activeFor(stage, rt);
254
- rt.tm.model.loraState.active = active;
255
- const eos = rt.tm.config.eosTokenIds;
256
- const greedySample: RowSampler = (logits1V: MlxArray) => ops.argmaxAxis(logits1V, -1);
257
- try {
258
- return await Promise.all(
259
- inputs.map((inp) => {
260
- const ids = memoryPromptIds(stage, inp, rt.tm.tokenizer, rt.template);
261
- const toks: number[] = [];
262
- return rt.scheduler
263
- .submit({
264
- promptIds: ids,
265
- maxTokens,
266
- eosTokenIds: eos,
267
- sample: greedySample,
268
- onToken: (t) => { toks.push(t); },
269
- })
270
- .then(() => rt.tm.tokenizer.decode(toks, true));
271
- }),
272
- );
273
- } finally {
274
- rt.tm.model.loraState.active = [];
275
- }
276
- }
277
-
278
- // ---------------------------------------------------------------------------
279
- // Public seams
280
- // ---------------------------------------------------------------------------
281
158
 
282
- /** Call the local model for a pipeline `stage` with a {system?, user} input.
283
- * Renders through the shared chat-template path, runs the MODEL precheck, and
284
- * decodes ONE completion on the bit-exact greedy path (the safe fallback used by
285
- * every single-call site). NEVER auto-downloads. */
286
- export async function callLocal(
287
- stage: string,
288
- input: LocalInput,
289
- opts?: { maxTokens?: number },
290
- ): Promise<string> {
291
- const rt = await getRuntime();
292
- const release = await opLock.acquire();
293
- try {
294
- return decodeGreedy(rt, stage, input, opts?.maxTokens ?? 256);
295
- } finally {
296
- release();
297
- }
159
+ /** One configured client per pipeline. Importing this module does not load MLX. */
160
+ export function createMemoryCalls(client: MemoryCompletionClient) {
161
+ return {
162
+ callLocal(stage: string, input: LocalInput, opts?: { maxTokens?: number }): Promise<string> {
163
+ return client.complete({ stage, input, maxTokens: opts?.maxTokens ?? 256 });
164
+ },
165
+ callLocalBatch(stage: string, inputs: LocalInput[], opts?: { maxTokens?: number }): Promise<string[]> {
166
+ if (!inputs.length) return Promise.resolve([]);
167
+ return client.completeBatch(inputs.map((input) => ({ stage, input, maxTokens: opts?.maxTokens ?? 256 })));
168
+ },
169
+ };
298
170
  }
299
171
 
300
- /** N independent calls for ONE stage (homogeneous adapter by construction).
301
- * Routed through the shared in-process BatchScheduler when batch>1 AND N>1, else
302
- * looped on the bit-exact greedy fallback. Order-preserving: out[i] ↔ inputs[i]. */
303
- export async function callLocalBatch(
304
- stage: string,
305
- inputs: LocalInput[],
306
- opts?: { maxTokens?: number },
307
- ): Promise<string[]> {
308
- if (inputs.length === 0) return [];
309
- const rt = await getRuntime();
310
- const maxTokens = opts?.maxTokens ?? 256;
311
- const release = await opLock.acquire();
312
- try {
313
- if (inputs.length === 1 || memoryBatchSize() <= 1) {
314
- const out: string[] = [];
315
- for (const inp of inputs) out.push(decodeGreedy(rt, stage, inp, maxTokens));
316
- return out;
317
- }
318
- return await batchDecode(rt, stage, inputs, maxTokens);
319
- } finally {
320
- release();
321
- }
322
- }
172
+ const defaultCalls = createMemoryCalls({
173
+ async complete(request) {
174
+ const { memoryCompletionClient } = await import("../backends/mlx/memory-client");
175
+ return memoryCompletionClient.complete(request);
176
+ },
177
+ async completeBatch(requests) {
178
+ const { memoryCompletionClient } = await import("../backends/mlx/memory-client");
179
+ return memoryCompletionClient.completeBatch(requests);
180
+ },
181
+ });
182
+ export const callLocal = defaultCalls.callLocal;
183
+ export const callLocalBatch = defaultCalls.callLocalBatch;
@@ -7,7 +7,7 @@
7
7
  // Topics_to_Ignore.md) and are read in at synthesis time so the system governs
8
8
  // itself in its own substrate.
9
9
  //
10
- // See docs/design/memory-system.md → "Synthesis runs on the local model".
10
+ // See docs/design/dreaming-nightly-pipeline.md → "Synthesis runs on the local model".
11
11
 
12
12
  import { readFileSync } from "node:fs";
13
13
  import { join } from "node:path";
@@ -11,7 +11,7 @@
11
11
  // rest of server.ts's /api/* conventions. Route dispatch (matching
12
12
  // url.pathname + method) lives in server.ts; this file is the pure handler
13
13
  // bodies so they're unit-testable without booting a model context (see
14
- // tests/memory-rest.test.ts).
14
+ // tests/using/memory-rest.test.ts).
15
15
 
16
16
  import { realpath } from "node:fs/promises";
17
17
  import { tmpdir } from "node:os";
@@ -11,7 +11,7 @@
11
11
  // it. That job runs the full synthesis DAG and produces/updates articles on the
12
12
  // schedule with no further configuration.
13
13
  //
14
- // See docs/design/memory-system.md → "Scheduling (launchd)".
14
+ // See docs/design/dreaming-nightly-pipeline.md → "Scheduling (launchd)".
15
15
 
16
16
  import { spawn } from "node:child_process";
17
17
  import { mkdir, rm, writeFile } from "node:fs/promises";
@@ -356,7 +356,10 @@ export async function runExtractStage(
356
356
  // SERIAL fallback (injected `call`, single chunk, or batching disabled).
357
357
  let extracted = 0;
358
358
  for (const id of targetIds) {
359
- await extractEntities(store, id, { resolver, policy: policy || undefined, call: opts.call });
359
+ // Pass the (possibly empty) policy through: `|| undefined` made extractEntities
360
+ // re-load Meta/Entities.md and THROW on a vault without it, while the batched
361
+ // path above proceeds with "" — the serial path must match.
362
+ await extractEntities(store, id, { resolver, policy, call: opts.call });
360
363
  extracted++;
361
364
  if (extracted % 10 === 0) {
362
365
  opts.onEvent?.({ type: "log", message: ` extracted ${extracted}/${target} chunks` });
@@ -9,7 +9,7 @@
9
9
  // an already-working system at real scale — they're pure filesystem functions
10
10
  // with no MCP coupling, so they drop straight in. We keep lucien's good
11
11
  // descriptive concepts (articles, [[wikilinks]], Meta governance pages,
12
- // conv: citations) and drop the mythology. See docs/design/memory-system.md.
12
+ // conv: citations) and drop the mythology. See docs/design/dreaming-nightly-pipeline.md.
13
13
  //
14
14
  // M0 is the read path: setup the vault, then list / read / search / index it.
15
15
  // Synthesis (writing articles from conversations) is M1 and lives elsewhere.
@@ -987,10 +987,8 @@ const REFERENCE_LINKS: { name: string; source: string }[] = [
987
987
  { name: "mlx-bun_Server_API", source: join(REPO_ROOT, "docs", "reference", "server-api.md") },
988
988
  { name: "mlx-bun_Server_Config", source: join(REPO_ROOT, "docs", "reference", "server-config.md") },
989
989
  { name: "mlx-bun_Library_API", source: join(REPO_ROOT, "docs", "reference", "library-api.md") },
990
- { name: "mlx-bun_Embedding", source: join(REPO_ROOT, "docs", "reference", "embedding.md") },
991
990
  { name: "mlx-bun_Distribution", source: join(REPO_ROOT, "docs", "reference", "distribution.md") },
992
991
  { name: "mlx-bun_Training", source: join(REPO_ROOT, "docs", "reference", "training.md") },
993
- { name: "mlx-bun_ORPO_Quickstart", source: join(REPO_ROOT, "docs", "reference", "orpo-quickstart.md") },
994
992
  { name: "mlx-bun_Product_Roadmap", source: join(REPO_ROOT, "docs", "planning", "PRODUCT_ROADMAP.md") },
995
993
  ];
996
994
 
package/src/mlx/array.ts CHANGED
@@ -46,17 +46,16 @@ let nextPinId = 1;
46
46
  // do nothing — a dtor mlx can safely call from ANY thread. The pointed-to
47
47
  // memory's lifetime is the CALLER's contract (weight mmaps live for the
48
48
  // process; restored KV is COPIED at load since 2026-07-07 — see kv-store.ts
49
- // loadKvCache — so no restore mapping needs pinning anymore). The address
50
- // comes via dlsym because
51
- // bun:ffi's symbol .ptr returns the pointer bit-cast to float64
52
- // (lab/repro/bun-ffi-f64) — passing that back truncates to NULL.
53
- const libcDlsym = dlopen("/usr/lib/libSystem.B.dylib", {
54
- dlsym: { args: ["u64", "ptr"], returns: "u64" },
49
+ // loadKvCache — so no restore mapping needs pinning anymore). Bun >= 1.4
50
+ // returns a numeric function address from .ptr; verified against dlsym on
51
+ // 1.4.0 and 1.4.2. Keep the library open for every native destructor's lifetime.
52
+ const libcFree = dlopen("/usr/lib/libSystem.B.dylib", {
53
+ free: { args: ["ptr"], returns: "void" },
55
54
  });
56
- const FREE_NAME = Buffer.from("free\0");
57
- const RTLD_DEFAULT = 0xfffffffffffffffen;
58
- const freeFnAddr = Number(libcDlsym.symbols.dlsym(RTLD_DEFAULT, ptr(FREE_NAME)));
59
- if (!freeFnAddr) throw new Error("dlsym(free) failed — zero-copy arrays need a native no-op dtor");
55
+ // The pinned bun-types predates the runtime's numeric .ptr property.
56
+ const freeFnAddr = Number(Reflect.get(libcFree.symbols.free, "ptr"));
57
+ if (!Number.isSafeInteger(freeFnAddr) || freeFnAddr <= 0)
58
+ throw new Error("free.ptr is invalid — zero-copy arrays need a native no-op dtor");
60
59
 
61
60
  export function pinnedBufferCount(): number {
62
61
  return pinned.size;
@@ -233,7 +232,7 @@ export class MlxArray {
233
232
  );
234
233
  }
235
234
 
236
- /** Raw bytes of the evaluated array (copy). bf16/f16/f32 only. */
235
+ /** Raw bytes of a supported floating-point or integer array (copy). */
237
236
  rawBytes(): Uint8Array {
238
237
  return this.rawBytesView().slice();
239
238
  }
@@ -254,6 +253,7 @@ export class MlxArray {
254
253
  : dt === Dtype.float16 ? C.mlx_array_data_float16(this.handle)
255
254
  : dt === Dtype.bfloat16 ? C.mlx_array_data_bfloat16(this.handle)
256
255
  : dt === Dtype.uint32 ? C.mlx_array_data_uint32(this.handle)
256
+ : dt === Dtype.int32 ? C.mlx_array_data_int32(this.handle)
257
257
  : dt === Dtype.uint8 ? C.mlx_array_data_uint8(this.handle)
258
258
  : dt === Dtype.int8 ? C.mlx_array_data_int8(this.handle)
259
259
  : null;
@@ -23,8 +23,14 @@ import { MlxArray } from "./array";
23
23
 
24
24
  export type TraceFn = (inputs: MlxArray[]) => MlxArray[];
25
25
 
26
- const traceRegistry = new Map<number, { fn: TraceFn; count: number }>();
26
+ const traceRegistry = new Map<number, { fn: TraceFn; count: number; shapeless: boolean }>();
27
27
  let nextTraceId = 1;
28
+ let shapelessTracing = false;
29
+
30
+ /** Fixed-shape custom kernels must fall back while a shapeless graph traces. */
31
+ export function isShapelessTracing(): boolean {
32
+ return shapelessTracing;
33
+ }
28
34
  /** Error thrown by a trace fn, carried across the C boundary (the
29
35
  * trampoline must not throw into mlx; it returns non-zero instead). */
30
36
  let traceError: unknown = null;
@@ -40,9 +46,11 @@ export let traceCalls = 0;
40
46
  // error handler in ffi.ts).
41
47
  const trampoline = new JSCallback(
42
48
  (resPtr: number, argsVec: bigint, payload: number): number => {
49
+ const previousShapeless = shapelessTracing;
43
50
  try {
44
51
  const entry = traceRegistry.get(payload);
45
52
  if (!entry) throw new Error(`compile trampoline: unknown trace id ${payload}`);
53
+ shapelessTracing ||= entry.shapeless;
46
54
  const fn = entry.fn;
47
55
  entry.count++;
48
56
  traceCalls++;
@@ -66,6 +74,8 @@ const trampoline = new JSCallback(
66
74
  } catch (e) {
67
75
  traceError = e;
68
76
  return 1;
77
+ } finally {
78
+ shapelessTracing = previousShapeless;
69
79
  }
70
80
  },
71
81
  { args: ["ptr", "u64", "ptr"], returns: "i32" },
@@ -95,7 +105,7 @@ export class CompiledFunction {
95
105
 
96
106
  constructor(fn: TraceFn, shapeless = true) {
97
107
  this.#traceId = nextTraceId++;
98
- traceRegistry.set(this.#traceId, { fn, count: 0 });
108
+ traceRegistry.set(this.#traceId, { fn, count: 0, shapeless });
99
109
  // payload is the trace id smuggled through the void* (never deref'd);
100
110
  // dtor is null — nothing to free on the C side.
101
111
  const raw = C.mlx_closure_new_func_payload(trampoline.ptr, this.#traceId as never, null);