@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,29 @@
1
+ import type { MlxArray } from "@mlx-bun/mlx/array";
2
+ import * as ops from "@mlx-bun/mlx/ops";
3
+ import type { Cache } from "../../contracts/mlx/cache";
4
+ import type { Gemma4Phase } from "./blocks";
5
+
6
+ type MediaForward = (hidden: MlxArray, caches: Cache[], phase: Gemma4Phase, ids: MlxArray) => MlxArray;
7
+
8
+ /** Prepared media request data before entering the fixed operation its range
9
+ * names. A request's image mask declares its bidirectional attention spans. */
10
+ export function writtenMedia(embedScale: number, operation: MediaForward,
11
+ embeds: MlxArray, caches: Cache[], bidir: MlxArray | null, ids: MlxArray): MlxArray {
12
+ const hidden = ops.mulScalar(embeds, embedScale);
13
+ return operation(hidden, caches, bidir ? { bidirectional: bidir } : "window", ids);
14
+ }
15
+
16
+ /** Per-layer-input media positions take token zero's input, as the reference
17
+ * does. The masks are request data; the file names this input operation. */
18
+ export function writtenInputMedia(embedScale: number, operation: MediaForward,
19
+ embeds: MlxArray, caches: Cache[], bidir: MlxArray | null, ids: MlxArray, multimodal: MlxArray | null): MlxArray {
20
+ const zeroing = multimodal ?? bidir;
21
+ let inputIds = ids;
22
+ if (zeroing) {
23
+ using condition = ops.reshape(zeroing, ids.shape);
24
+ using zero = ops.zeros(ids.shape, ids.dtype);
25
+ inputIds = ops.where(condition, zero, ids);
26
+ }
27
+ try { return writtenMedia(embedScale, operation, embeds, caches, bidir, inputIds); }
28
+ finally { if (inputIds !== ids) inputIds.dispose(); }
29
+ }
@@ -0,0 +1,507 @@
1
+ // Offline GLM-5.2 Expert Atlas analysis.
2
+ //
3
+ // Each prompt is one independent observation. Selection counts are normalized
4
+ // within a run, averaged within a category, and only promoted to an affinity
5
+ // label when the top topic fires in multiple independent prompts. Nothing in
6
+ // this module feeds residency, routing, or prefetch policy.
7
+
8
+ import type { Glm52RouteTraceRecord } from "./coupling";
9
+ import { positiveInteger } from "../../runtime/integers";
10
+
11
+ export interface Glm52AtlasProbeSet {
12
+ readonly schemaVersion: 1;
13
+ readonly provenance: {
14
+ readonly source: string;
15
+ readonly sourceCommit: string;
16
+ readonly method: string;
17
+ };
18
+ readonly categories: Readonly<Record<string, readonly string[]>>;
19
+ }
20
+
21
+ export interface Glm52AtlasRun {
22
+ readonly category: string;
23
+ readonly promptIndex: number;
24
+ readonly totalSelections: number;
25
+ readonly counts: ReadonlyMap<string, number>;
26
+ }
27
+
28
+ export interface Glm52AtlasExpert {
29
+ readonly layer: number;
30
+ readonly expert: number;
31
+ readonly total: number;
32
+ readonly specialization: number;
33
+ readonly topTopic: string;
34
+ readonly topLift: number;
35
+ readonly reliability: {
36
+ readonly firedRuns: number;
37
+ readonly totalRuns: number;
38
+ };
39
+ readonly affinity: Readonly<Record<string, number>>;
40
+ }
41
+
42
+ export interface Glm52AtlasAnalysis {
43
+ readonly schemaVersion: 1;
44
+ readonly categories: readonly string[];
45
+ readonly runCount: number;
46
+ readonly method: {
47
+ readonly minCount: number;
48
+ readonly minRuns: number;
49
+ readonly strongThreshold: number;
50
+ readonly normalization: "mean per-run selection share";
51
+ };
52
+ readonly summary: {
53
+ readonly expertsSeen: number;
54
+ readonly expertsKept: number;
55
+ readonly droppedSparse: number;
56
+ readonly droppedUnreplicated: number;
57
+ readonly strongSpecialists: number;
58
+ readonly strongSpecialistRate: number;
59
+ };
60
+ readonly experts: readonly Glm52AtlasExpert[];
61
+ }
62
+
63
+ export interface Glm52AtlasValidationTrial {
64
+ readonly category: string;
65
+ readonly promptIndex: number;
66
+ readonly predicted: string;
67
+ readonly correct: boolean;
68
+ readonly ownShare: number;
69
+ readonly bestOtherShare: number;
70
+ readonly scores: Readonly<Record<string, number>>;
71
+ }
72
+
73
+ export interface Glm52AtlasValidation {
74
+ readonly topK: number;
75
+ readonly hits: number;
76
+ readonly trials: number;
77
+ readonly accuracy: number;
78
+ readonly chance: number;
79
+ readonly protocol: "global leave-one-prompt-out";
80
+ readonly trialsByPrompt: readonly Glm52AtlasValidationTrial[];
81
+ }
82
+
83
+ export interface Glm52AtlasBuildOptions {
84
+ readonly minCount?: number;
85
+ readonly minRuns?: number;
86
+ readonly strongThreshold?: number;
87
+ }
88
+
89
+ const CATEGORY = /^[a-z0-9][a-z0-9_]*$/;
90
+
91
+ function finiteUnit(value: number, label: string): void {
92
+ if (!Number.isFinite(value) || value < 0 || value > 1)
93
+ throw new RangeError(`${label} must be in [0, 1]`);
94
+ }
95
+
96
+ function round(value: number, digits = 6): number {
97
+ const scale = 10 ** digits;
98
+ return Math.round(value * scale) / scale;
99
+ }
100
+
101
+ function expertKey(layer: number, expert: number): string {
102
+ return `${layer}:${expert}`;
103
+ }
104
+
105
+ function parseExpertKey(key: string): [number, number] {
106
+ const fields = key.split(":");
107
+ const layer = Number(fields[0]);
108
+ const expert = Number(fields[1]);
109
+ if (fields.length !== 2 || !Number.isSafeInteger(layer) || layer < 0 ||
110
+ !Number.isSafeInteger(expert) || expert < 0) {
111
+ throw new Error(`invalid GLM Atlas expert key ${key}`);
112
+ }
113
+ return [layer, expert];
114
+ }
115
+
116
+ export function glm52AtlasRunId(category: string, promptIndex: number): string {
117
+ if (!CATEGORY.test(category))
118
+ throw new Error(`invalid GLM Atlas category ${category}`);
119
+ if (!Number.isSafeInteger(promptIndex) || promptIndex < 0)
120
+ throw new RangeError(`invalid GLM Atlas prompt index ${promptIndex}`);
121
+ return `${category}:${promptIndex}`;
122
+ }
123
+
124
+ export function validateGlm52AtlasProbeSet(
125
+ value: unknown,
126
+ ): Glm52AtlasProbeSet {
127
+ if (!value || typeof value !== "object")
128
+ throw new Error("GLM Atlas probe set must be an object");
129
+ const input = value as Record<string, unknown>;
130
+ if (input.schemaVersion !== 1)
131
+ throw new Error("unsupported GLM Atlas probe schema");
132
+ const provenance = input.provenance as Record<string, unknown> | undefined;
133
+ if (!provenance || ["source", "sourceCommit", "method"].some(
134
+ (key) => typeof provenance[key] !== "string" ||
135
+ !(provenance[key] as string).trim(),
136
+ )) {
137
+ throw new Error("GLM Atlas probe provenance is incomplete");
138
+ }
139
+ const raw = input.categories;
140
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
141
+ throw new Error("GLM Atlas categories must be an object");
142
+ const entries = Object.entries(raw as Record<string, unknown>);
143
+ if (entries.length < 2)
144
+ throw new Error("GLM Atlas requires at least two categories");
145
+ const categories: Record<string, readonly string[]> = {};
146
+ for (const [category, prompts] of entries) {
147
+ if (!CATEGORY.test(category))
148
+ throw new Error(`invalid GLM Atlas category ${category}`);
149
+ if (!Array.isArray(prompts) || prompts.length < 3 ||
150
+ prompts.some((prompt) => typeof prompt !== "string" || !prompt.trim())) {
151
+ throw new Error(
152
+ `GLM Atlas category ${category} requires at least three prompts`,
153
+ );
154
+ }
155
+ categories[category] = Object.freeze(prompts.slice());
156
+ }
157
+ return Object.freeze({
158
+ schemaVersion: 1,
159
+ provenance: Object.freeze({
160
+ source: provenance.source as string,
161
+ sourceCommit: provenance.sourceCommit as string,
162
+ method: provenance.method as string,
163
+ }),
164
+ categories: Object.freeze(categories),
165
+ });
166
+ }
167
+
168
+ export function buildGlm52AtlasRun(
169
+ category: string,
170
+ promptIndex: number,
171
+ records: readonly Glm52RouteTraceRecord[],
172
+ ): Glm52AtlasRun {
173
+ const segment = glm52AtlasRunId(category, promptIndex);
174
+ const counts = new Map<string, number>();
175
+ let totalSelections = 0;
176
+ if (records.length === 0)
177
+ throw new Error(`GLM Atlas run ${segment} has no route records`);
178
+ for (const record of records) {
179
+ if (record.segment !== segment)
180
+ throw new Error(
181
+ `GLM Atlas run ${segment} contains segment ${record.segment}`,
182
+ );
183
+ if (!Number.isSafeInteger(record.forward) || record.forward < 0 ||
184
+ !Number.isSafeInteger(record.row) || record.row < 0 ||
185
+ !Number.isSafeInteger(record.layer) || record.layer < 0 ||
186
+ record.indices.length === 0 ||
187
+ new Set(record.indices).size !== record.indices.length) {
188
+ throw new Error(`GLM Atlas run ${segment} has an invalid route row`);
189
+ }
190
+ for (const expert of record.indices) {
191
+ if (!Number.isSafeInteger(expert) || expert < 0)
192
+ throw new Error(`GLM Atlas run ${segment} has invalid expert ${expert}`);
193
+ const key = expertKey(record.layer, expert);
194
+ counts.set(key, (counts.get(key) ?? 0) + 1);
195
+ totalSelections++;
196
+ }
197
+ }
198
+ return Object.freeze({
199
+ category,
200
+ promptIndex,
201
+ totalSelections,
202
+ counts,
203
+ });
204
+ }
205
+
206
+ function checkedRuns(
207
+ probes: Glm52AtlasProbeSet,
208
+ runs: readonly Glm52AtlasRun[],
209
+ ): {
210
+ categories: string[];
211
+ ordered: Glm52AtlasRun[];
212
+ } {
213
+ const categories = Object.keys(probes.categories).sort();
214
+ const expected = new Set<string>();
215
+ for (const category of categories) {
216
+ const prompts = probes.categories[category]!;
217
+ for (let index = 0; index < prompts.length; index++)
218
+ expected.add(glm52AtlasRunId(category, index));
219
+ }
220
+ const seen = new Set<string>();
221
+ for (const run of runs) {
222
+ const id = glm52AtlasRunId(run.category, run.promptIndex);
223
+ if (!expected.has(id)) throw new Error(`unexpected GLM Atlas run ${id}`);
224
+ if (seen.has(id)) throw new Error(`duplicate GLM Atlas run ${id}`);
225
+ if (!Number.isSafeInteger(run.totalSelections) || run.totalSelections <= 0)
226
+ throw new Error(`GLM Atlas run ${id} has no selections`);
227
+ let counted = 0;
228
+ for (const [key, count] of run.counts) {
229
+ parseExpertKey(key);
230
+ positiveInteger(count, `GLM Atlas count ${id}/${key}`);
231
+ counted += count;
232
+ }
233
+ if (counted !== run.totalSelections)
234
+ throw new Error(
235
+ `GLM Atlas run ${id} count total ${counted} != ${run.totalSelections}`,
236
+ );
237
+ seen.add(id);
238
+ }
239
+ const missing = [...expected].filter((id) => !seen.has(id));
240
+ if (missing.length)
241
+ throw new Error(`missing GLM Atlas runs: ${missing.join(", ")}`);
242
+ return {
243
+ categories,
244
+ ordered: runs.slice().sort((left, right) =>
245
+ left.category.localeCompare(right.category) ||
246
+ left.promptIndex - right.promptIndex),
247
+ };
248
+ }
249
+
250
+ function categoryShares(
251
+ categories: readonly string[],
252
+ runs: readonly Glm52AtlasRun[],
253
+ ): Map<string, Float64Array> {
254
+ const index = new Map(categories.map((category, i) => [category, i]));
255
+ const byCategory = new Map<string, Glm52AtlasRun[]>();
256
+ for (const category of categories) byCategory.set(category, []);
257
+ for (const run of runs) byCategory.get(run.category)?.push(run);
258
+ const shares = new Map<string, Float64Array>();
259
+ for (const category of categories) {
260
+ const categoryRuns = byCategory.get(category)!;
261
+ if (categoryRuns.length === 0) continue;
262
+ const c = index.get(category)!;
263
+ for (const run of categoryRuns) {
264
+ for (const [key, count] of run.counts) {
265
+ let values = shares.get(key);
266
+ if (!values) {
267
+ values = new Float64Array(categories.length);
268
+ shares.set(key, values);
269
+ }
270
+ values[c] = values[c]! +
271
+ count / run.totalSelections / categoryRuns.length;
272
+ }
273
+ }
274
+ }
275
+ return shares;
276
+ }
277
+
278
+ function deterministicTop(
279
+ categories: readonly string[],
280
+ values: ArrayLike<number>,
281
+ ): number {
282
+ let best = 0;
283
+ for (let index = 1; index < categories.length; index++)
284
+ if (values[index]! > values[best]!) best = index;
285
+ return best;
286
+ }
287
+
288
+ export function buildGlm52Atlas(
289
+ probes: Glm52AtlasProbeSet,
290
+ runs: readonly Glm52AtlasRun[],
291
+ options: Glm52AtlasBuildOptions = {},
292
+ ): Glm52AtlasAnalysis {
293
+ const minCount = options.minCount ?? 30;
294
+ const minRuns = options.minRuns ?? 2;
295
+ const strongThreshold = options.strongThreshold ?? 0.5;
296
+ positiveInteger(minCount, "GLM Atlas minCount");
297
+ positiveInteger(minRuns, "GLM Atlas minRuns");
298
+ finiteUnit(strongThreshold, "GLM Atlas strongThreshold");
299
+ const checked = checkedRuns(probes, runs);
300
+ const { categories, ordered } = checked;
301
+ if (categories.some((category) =>
302
+ probes.categories[category]!.length < minRuns)) {
303
+ throw new Error("GLM Atlas minRuns exceeds a category's prompt count");
304
+ }
305
+ const shares = categoryShares(categories, ordered);
306
+ const runsByCategory = new Map<string, Glm52AtlasRun[]>();
307
+ for (const category of categories) runsByCategory.set(category, []);
308
+ for (const run of ordered) runsByCategory.get(run.category)!.push(run);
309
+
310
+ let droppedSparse = 0;
311
+ let droppedUnreplicated = 0;
312
+ const experts: Glm52AtlasExpert[] = [];
313
+ for (const [key, meanShares] of shares) {
314
+ const total = ordered.reduce(
315
+ (sum, run) => sum + (run.counts.get(key) ?? 0),
316
+ 0,
317
+ );
318
+ if (total < minCount) {
319
+ droppedSparse++;
320
+ continue;
321
+ }
322
+ const sum = meanShares.reduce((value, next) => value + next, 0);
323
+ if (sum <= 0) continue;
324
+ const probabilities = Array.from(meanShares, (value) => value / sum);
325
+ const topIndex = deterministicTop(categories, probabilities);
326
+ const topTopic = categories[topIndex]!;
327
+ const topRuns = runsByCategory.get(topTopic)!;
328
+ const firedRuns = topRuns.filter((run) =>
329
+ (run.counts.get(key) ?? 0) > 0).length;
330
+ if (firedRuns < minRuns) {
331
+ droppedUnreplicated++;
332
+ continue;
333
+ }
334
+ const entropy = -probabilities.reduce(
335
+ (value, probability) =>
336
+ value + (probability > 0 ? probability * Math.log(probability) : 0),
337
+ 0,
338
+ );
339
+ const specialization = Math.max(
340
+ 0,
341
+ Math.min(1, 1 - entropy / Math.log(categories.length)),
342
+ );
343
+ const affinity: Record<string, number> = {};
344
+ for (let index = 0; index < categories.length; index++)
345
+ affinity[categories[index]!] = round(probabilities[index]!);
346
+ const [layer, expert] = parseExpertKey(key);
347
+ experts.push(Object.freeze({
348
+ layer,
349
+ expert,
350
+ total,
351
+ specialization: round(specialization),
352
+ topTopic,
353
+ topLift: round(probabilities[topIndex]! * categories.length),
354
+ reliability: Object.freeze({
355
+ firedRuns,
356
+ totalRuns: topRuns.length,
357
+ }),
358
+ affinity: Object.freeze(affinity),
359
+ }));
360
+ }
361
+ experts.sort((left, right) =>
362
+ right.specialization - left.specialization ||
363
+ right.total - left.total ||
364
+ left.layer - right.layer ||
365
+ left.expert - right.expert);
366
+ const strongSpecialists = experts.filter(
367
+ (expert) => expert.specialization >= strongThreshold,
368
+ ).length;
369
+ return Object.freeze({
370
+ schemaVersion: 1,
371
+ categories: Object.freeze(categories),
372
+ runCount: ordered.length,
373
+ method: Object.freeze({
374
+ minCount,
375
+ minRuns,
376
+ strongThreshold,
377
+ normalization: "mean per-run selection share",
378
+ }),
379
+ summary: Object.freeze({
380
+ expertsSeen: shares.size,
381
+ expertsKept: experts.length,
382
+ droppedSparse,
383
+ droppedUnreplicated,
384
+ strongSpecialists,
385
+ strongSpecialistRate: round(
386
+ strongSpecialists / Math.max(1, experts.length),
387
+ ),
388
+ }),
389
+ experts: Object.freeze(experts),
390
+ });
391
+ }
392
+
393
+ function specialistSets(
394
+ categories: readonly string[],
395
+ training: readonly Glm52AtlasRun[],
396
+ topK: number,
397
+ ): Map<string, Set<string>> {
398
+ const shares = categoryShares(categories, training);
399
+ const sets = new Map<string, Set<string>>();
400
+ for (let categoryIndex = 0;
401
+ categoryIndex < categories.length;
402
+ categoryIndex++
403
+ ) {
404
+ const scored: Array<{ key: string; score: number; layer: number; expert: number }> = [];
405
+ for (const [key, values] of shares) {
406
+ if (values[categoryIndex]! <= 0) continue;
407
+ const sum = values.reduce((value, next) => value + next, 0);
408
+ const [layer, expert] = parseExpertKey(key);
409
+ scored.push({
410
+ key,
411
+ score: values[categoryIndex]! / sum,
412
+ layer,
413
+ expert,
414
+ });
415
+ }
416
+ scored.sort((left, right) =>
417
+ right.score - left.score ||
418
+ left.layer - right.layer ||
419
+ left.expert - right.expert);
420
+ sets.set(
421
+ categories[categoryIndex]!,
422
+ new Set(scored.slice(0, topK).map((entry) => entry.key)),
423
+ );
424
+ }
425
+ return sets;
426
+ }
427
+
428
+ export function validateGlm52Atlas(
429
+ probes: Glm52AtlasProbeSet,
430
+ runs: readonly Glm52AtlasRun[],
431
+ topK = 200,
432
+ ): Glm52AtlasValidation {
433
+ positiveInteger(topK, "GLM Atlas validation topK");
434
+ const { categories, ordered } = checkedRuns(probes, runs);
435
+ const trialsByPrompt: Glm52AtlasValidationTrial[] = [];
436
+ let hits = 0;
437
+ for (const held of ordered) {
438
+ // The held-out prompt is absent from every topic model, including the
439
+ // background distribution used to score other categories.
440
+ const training = ordered.filter((run) => run !== held);
441
+ const sets = specialistSets(categories, training, topK);
442
+ const scores: Record<string, number> = {};
443
+ for (const category of categories) {
444
+ const selected = sets.get(category)!;
445
+ let count = 0;
446
+ for (const [key, value] of held.counts)
447
+ if (selected.has(key)) count += value;
448
+ scores[category] = count / held.totalSelections;
449
+ }
450
+ const predictedIndex = deterministicTop(
451
+ categories,
452
+ categories.map((category) => scores[category]!),
453
+ );
454
+ const predicted = categories[predictedIndex]!;
455
+ const correct = predicted === held.category;
456
+ if (correct) hits++;
457
+ const bestOtherShare = Math.max(
458
+ ...categories.filter((category) => category !== held.category)
459
+ .map((category) => scores[category]!),
460
+ );
461
+ trialsByPrompt.push(Object.freeze({
462
+ category: held.category,
463
+ promptIndex: held.promptIndex,
464
+ predicted,
465
+ correct,
466
+ ownShare: round(scores[held.category]!),
467
+ bestOtherShare: round(bestOtherShare),
468
+ scores: Object.freeze(Object.fromEntries(
469
+ categories.map((category) => [category, round(scores[category]!)]),
470
+ )),
471
+ }));
472
+ }
473
+ return Object.freeze({
474
+ topK,
475
+ hits,
476
+ trials: trialsByPrompt.length,
477
+ accuracy: round(hits / trialsByPrompt.length),
478
+ chance: round(1 / categories.length),
479
+ protocol: "global leave-one-prompt-out",
480
+ trialsByPrompt: Object.freeze(trialsByPrompt),
481
+ });
482
+ }
483
+
484
+ export function glm52AtlasWebExperts(
485
+ analysis: Glm52AtlasAnalysis,
486
+ ): Readonly<Record<string, unknown>> {
487
+ const experts: Record<string, unknown> = {};
488
+ for (const expert of analysis.experts) {
489
+ const entropy = -Object.values(expert.affinity).reduce(
490
+ (value, probability) => value +
491
+ (probability > 0 ? probability * Math.log2(probability) : 0),
492
+ 0,
493
+ );
494
+ experts[expertKey(expert.layer, expert.expert)] = Object.freeze({
495
+ affinity: expert.affinity,
496
+ entropy: round(entropy, 3),
497
+ specialization: expert.specialization,
498
+ top: expert.topTopic,
499
+ label: expert.specialization >= analysis.method.strongThreshold
500
+ ? `specialist: ${expert.topTopic}`
501
+ : "generalist",
502
+ total: expert.total,
503
+ reliability: expert.reliability,
504
+ });
505
+ }
506
+ return Object.freeze(experts);
507
+ }