mlx-bun 0.5.0 → 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 (640) hide show
  1. package/README.md +1449 -109
  2. package/THIRD_PARTY_NOTICES.md +882 -0
  3. package/bin/mlx-bun.convert.mjs +4 -0
  4. package/bin/mlx-bun.fuse.mjs +4 -0
  5. package/bin/mlx-bun.generate.mjs +4 -0
  6. package/bin/mlx-bun.lora.mjs +4 -0
  7. package/bin/mlx-bun.mjs +13 -21
  8. package/bin/mlx-bun.server.mjs +4 -0
  9. package/bin/mlx-bun.upload.mjs +4 -0
  10. package/dist/web/app.js +9584 -0
  11. package/package.json +50 -53
  12. package/src/cli/ane-install.ts +76 -0
  13. package/src/cli/args.ts +179 -0
  14. package/src/cli/engine-entry.ts +68 -0
  15. package/src/cli/inference.ts +214 -0
  16. package/src/cli/job-entry.ts +97 -0
  17. package/src/cli/library-host.ts +117 -0
  18. package/src/cli/main.ts +57 -0
  19. package/src/cli/memory-engine.ts +163 -0
  20. package/src/cli/memory.ts +36 -0
  21. package/src/cli/mlx-lm-aliases.ts +309 -0
  22. package/src/cli/model-choice.ts +33 -0
  23. package/src/cli/model-selection.ts +84 -0
  24. package/src/cli/module-host.ts +11 -0
  25. package/src/cli/module-verbs.ts +50 -0
  26. package/src/cli/numerical-policy.ts +12 -0
  27. package/src/cli/perplexity.ts +89 -0
  28. package/src/cli/serve-host.ts +423 -0
  29. package/src/cli/serve-isolated.ts +217 -0
  30. package/src/cli/serve-options.ts +106 -0
  31. package/src/cli/serve-state.ts +205 -0
  32. package/src/cli/serve.ts +500 -0
  33. package/src/cli/served-model-host.ts +102 -0
  34. package/src/cli/server-entry.ts +148 -0
  35. package/src/cli/serving-unit.ts +177 -0
  36. package/src/{tui.ts → cli/terminal.ts} +13 -8
  37. package/src/cli/worker-adapters.ts +34 -0
  38. package/src/cli/worker-entry.ts +272 -0
  39. package/src/cli/worker-unit.ts +179 -0
  40. package/src/engine/adapter-operation.ts +26 -0
  41. package/src/engine/cache-services.ts +114 -0
  42. package/src/engine/completion.ts +39 -0
  43. package/src/engine/generation-gateway.ts +358 -0
  44. package/src/engine/index.ts +59 -0
  45. package/src/engine/kv-budget.ts +120 -0
  46. package/src/engine/media-preparation.ts +232 -0
  47. package/src/engine/model-binding.ts +24 -0
  48. package/src/engine/model-host.ts +513 -0
  49. package/src/engine/model-serving.ts +89 -0
  50. package/src/{serve → engine}/preparation.ts +7 -5
  51. package/src/{serve → engine}/session-completion-engine.ts +6 -6
  52. package/src/engine/telemetry.ts +109 -0
  53. package/src/hub/downloads.ts +116 -0
  54. package/src/jobs/db.ts +16 -7
  55. package/src/jobs/events.ts +29 -0
  56. package/src/jobs/executable.ts +5 -0
  57. package/src/jobs/host.ts +51 -0
  58. package/src/jobs/in-process.ts +55 -0
  59. package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
  60. package/src/jobs/runner.ts +150 -231
  61. package/src/jobs/service.ts +75 -0
  62. package/src/jobs/sse.ts +59 -23
  63. package/src/jobs/worker-memory.ts +46 -0
  64. package/src/jobs/worker-process.ts +163 -0
  65. package/src/jobs/worker-supervisor.ts +258 -0
  66. package/src/modules.ts +58 -0
  67. package/src/publishing/catalog-hub.ts +18 -0
  68. package/src/publishing/credentials.ts +31 -0
  69. package/src/publishing/upload.ts +37 -0
  70. package/src/residency/leased-adapters.ts +21 -0
  71. package/src/residency/local-records.ts +16 -0
  72. package/src/residency/model-residency.ts +405 -0
  73. package/src/residency/record-index.ts +28 -0
  74. package/src/residency/resident-estimate.ts +50 -0
  75. package/src/{anthropic.ts → server/anthropic.ts} +3 -81
  76. package/src/server/cache-routes.ts +36 -0
  77. package/src/{serve → server}/chat-request.ts +10 -10
  78. package/src/{serve → server}/chat-stage.ts +14 -14
  79. package/src/{client.ts → server/client.ts} +28 -2
  80. package/src/{serve → server}/completion-executor.ts +33 -41
  81. package/src/server/decision-body.ts +55 -0
  82. package/src/server/decision-routes.ts +134 -0
  83. package/src/server/decision-wire.ts +228 -0
  84. package/src/{serve → server}/discovery-routes.ts +25 -82
  85. package/src/{serve → server}/http.ts +25 -13
  86. package/src/{serve → server}/inference-request.ts +5 -5
  87. package/src/server/job-routes.ts +20 -0
  88. package/src/server/media-prompt.ts +63 -0
  89. package/src/server/memory-completion-client.ts +46 -0
  90. package/src/server/model-routes.ts +192 -0
  91. package/src/{serve → server}/openai-wire.ts +3 -2
  92. package/src/{serve → server}/pipeline.ts +1 -1
  93. package/src/server/prompt-builder.ts +13 -0
  94. package/src/server/prompt-contracts.ts +17 -0
  95. package/src/server/proxy-routes.ts +187 -0
  96. package/src/server/publishing-routes.ts +41 -0
  97. package/src/{serve → server}/request-plan.ts +6 -8
  98. package/src/{serve → server}/request-prep.ts +47 -50
  99. package/src/{serve → server}/responses-client.ts +30 -13
  100. package/src/{responses.ts → server/responses.ts} +12 -93
  101. package/src/server/routes.ts +205 -0
  102. package/src/server/start.ts +72 -0
  103. package/src/server/status-routes.ts +108 -0
  104. package/src/{serve → server}/text-completion-stage.ts +25 -4
  105. package/src/server/text-prompt.ts +12 -0
  106. package/src/{serve → server}/token-streams.ts +36 -38
  107. package/src/server/worker-routes.ts +311 -0
  108. package/src/storage/paths.ts +61 -0
  109. package/src/web/assets.ts +37 -0
  110. package/src/web/{src → browser}/api.ts +5 -23
  111. package/src/web/browser/chat-host.ts +17 -0
  112. package/src/web/browser/installed-panels.ts +6 -0
  113. package/src/web/browser/main.ts +55 -0
  114. package/src/web/browser/markdown.ts +279 -0
  115. package/src/web/browser/memory-panel.ts +9 -0
  116. package/src/web/browser/palette.ts +64 -0
  117. package/src/web/browser/protocol.ts +13 -0
  118. package/src/web/browser/shell.ts +467 -0
  119. package/src/web/{src → browser}/status.ts +32 -36
  120. package/src/web/build.ts +51 -0
  121. package/src/web/public/app.html +1054 -0
  122. package/src/web/{sw.js → public/sw.js} +4 -3
  123. package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
  124. package/src/web/{vendor → public/vendor}/hljs.js +2 -2
  125. package/THIRD_PARTY_LICENSES.md +0 -51
  126. package/docs/README.md +0 -107
  127. package/docs/archive/hlg-sampling.md +0 -350
  128. package/docs/archive/investigations/audio-input-plan.md +0 -356
  129. package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
  130. package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
  131. package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
  132. package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
  133. package/docs/archive/investigations/curve-bisector-routing.md +0 -123
  134. package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
  135. package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
  136. package/docs/archive/investigations/dspark-handoff.md +0 -224
  137. package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
  138. package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
  139. package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
  140. package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
  141. package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
  142. package/docs/archive/investigations/lab-build-journal.md +0 -157
  143. package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
  144. package/docs/archive/investigations/openjarvis-fit.md +0 -198
  145. package/docs/archive/investigations/openwiki-evaluation.md +0 -249
  146. package/docs/archive/investigations/optimization_plan.md +0 -346
  147. package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
  148. package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
  149. package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
  150. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
  151. package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
  152. package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
  153. package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
  154. package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
  155. package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
  156. package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
  157. package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
  158. package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
  159. package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
  160. package/docs/archive/planning/chat-ui-vision.md +0 -50
  161. package/docs/archive/planning/chunk-task-roadmap.md +0 -77
  162. package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
  163. package/docs/archive/planning/journal.md +0 -316
  164. package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
  165. package/docs/archive/planning/pi-integration-review.md +0 -178
  166. package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
  167. package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
  168. package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
  169. package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
  170. package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
  171. package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
  172. package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
  173. package/docs/archive/planning/release-notes-v0.4.0.md +0 -45
  174. package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
  175. package/docs/archive/planning/web-ui-pass-plan.md +0 -213
  176. package/docs/archive/planning/website-readme-pass-plan.md +0 -224
  177. package/docs/design/batching.md +0 -2054
  178. package/docs/design/decode-speed-program.md +0 -2404
  179. package/docs/design/dreaming-nightly-pipeline.md +0 -684
  180. package/docs/design/generic-model-support.md +0 -821
  181. package/docs/design/kv-cache.md +0 -993
  182. package/docs/design/orpo-training.md +0 -680
  183. package/docs/design/speculative-decoding.md +0 -2129
  184. package/docs/design/turboquant.md +0 -2225
  185. package/docs/design/unified-engine-frontier-plan.md +0 -1987
  186. package/docs/design/web-chat-redesign.md +0 -695
  187. package/docs/planning/PRODUCT_ROADMAP.md +0 -593
  188. package/docs/planning/ResearchTopics.md +0 -119
  189. package/docs/planning/public-readiness-handoff.md +0 -244
  190. package/docs/planning/public-readiness.md +0 -149
  191. package/docs/planning/video-series.md +0 -421
  192. package/docs/reference/benchmarks.md +0 -3587
  193. package/docs/reference/cli.md +0 -646
  194. package/docs/reference/distribution.md +0 -380
  195. package/docs/reference/environment.md +0 -494
  196. package/docs/reference/glossary.md +0 -39
  197. package/docs/reference/library-api.md +0 -688
  198. package/docs/reference/memory.md +0 -260
  199. package/docs/reference/models.md +0 -346
  200. package/docs/reference/server-api.md +0 -1945
  201. package/docs/reference/server-config.md +0 -973
  202. package/docs/reference/training.md +0 -462
  203. package/docs/reference/troubleshooting.md +0 -158
  204. package/src/admission-plan.ts +0 -18
  205. package/src/audio/audiotoolbox.ts +0 -112
  206. package/src/audio/conformer.ts +0 -655
  207. package/src/audio/decode.ts +0 -133
  208. package/src/audio/features.ts +0 -202
  209. package/src/audio/mic-capture.ts +0 -98
  210. package/src/audio/silero-vad.ts +0 -379
  211. package/src/audio/transcode.ts +0 -67
  212. package/src/audio/whisper-decode.ts +0 -774
  213. package/src/audio/whisper-fast.ts +0 -732
  214. package/src/audio/whisper-format.ts +0 -73
  215. package/src/audio/whisper-mel.ts +0 -185
  216. package/src/audio/whisper-timing.ts +0 -274
  217. package/src/audio/whisper-tokenizer.ts +0 -239
  218. package/src/audio/whisper-transcribe.ts +0 -410
  219. package/src/backends/mlx/assistant-target.ts +0 -46
  220. package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
  221. package/src/backends/mlx/autoregressive.ts +0 -129
  222. package/src/backends/mlx/batch-group.ts +0 -1874
  223. package/src/backends/mlx/cache-attachment.ts +0 -67
  224. package/src/backends/mlx/cache-layout.ts +0 -31
  225. package/src/backends/mlx/checkpoint-state.ts +0 -53
  226. package/src/backends/mlx/continuation-persistence.ts +0 -107
  227. package/src/backends/mlx/continuation-request.ts +0 -43
  228. package/src/backends/mlx/continuation.ts +0 -77
  229. package/src/backends/mlx/diffusion.ts +0 -39
  230. package/src/backends/mlx/draft-target.ts +0 -32
  231. package/src/backends/mlx/encoder-cache.ts +0 -25
  232. package/src/backends/mlx/evaluation.ts +0 -105
  233. package/src/backends/mlx/fill-append.ts +0 -58
  234. package/src/backends/mlx/fill-group.ts +0 -497
  235. package/src/backends/mlx/full-kv-row-append.ts +0 -32
  236. package/src/backends/mlx/full-kv-row-donor.ts +0 -54
  237. package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
  238. package/src/backends/mlx/gateway-binding.ts +0 -174
  239. package/src/backends/mlx/graph.ts +0 -38
  240. package/src/backends/mlx/kv-codec.ts +0 -9
  241. package/src/backends/mlx/kv-maintenance.ts +0 -161
  242. package/src/backends/mlx/kv-tensor-rows.ts +0 -212
  243. package/src/backends/mlx/memory-client.ts +0 -189
  244. package/src/backends/mlx/methods.ts +0 -90
  245. package/src/backends/mlx/mixed-iteration.ts +0 -62
  246. package/src/backends/mlx/model-prompt.ts +0 -178
  247. package/src/backends/mlx/model-serving.ts +0 -80
  248. package/src/backends/mlx/paged-cache-codec.ts +0 -27
  249. package/src/backends/mlx/prefill-cohort.ts +0 -100
  250. package/src/backends/mlx/prefill-policy.ts +0 -26
  251. package/src/backends/mlx/prefill-rows.ts +0 -244
  252. package/src/backends/mlx/prefill.ts +0 -33
  253. package/src/backends/mlx/projected-context-rows.ts +0 -72
  254. package/src/backends/mlx/prompt-input.ts +0 -29
  255. package/src/backends/mlx/qwen-prompt-input.ts +0 -40
  256. package/src/backends/mlx/request-policy.ts +0 -20
  257. package/src/backends/mlx/request-state-policy.ts +0 -54
  258. package/src/backends/mlx/rollback.ts +0 -92
  259. package/src/backends/mlx/row-sampling.ts +0 -49
  260. package/src/backends/mlx/serial-executor.ts +0 -251
  261. package/src/backends/mlx/speculative-group.ts +0 -438
  262. package/src/backends/mlx/speculative-round.ts +0 -161
  263. package/src/backends/mlx/speculative.ts +0 -131
  264. package/src/backends/mlx/state-rows.ts +0 -104
  265. package/src/backends/mlx/state-views.ts +0 -46
  266. package/src/backends/mlx/target-layout-capability.ts +0 -35
  267. package/src/backends/mlx/text-engine.ts +0 -73
  268. package/src/backends/mlx/transitioning-kv-rows.ts +0 -173
  269. package/src/chat-template.ts +0 -382
  270. package/src/cli.ts +0 -3490
  271. package/src/config.ts +0 -399
  272. package/src/contracts/completion.ts +0 -16
  273. package/src/contracts/execution.ts +0 -70
  274. package/src/contracts/generation.ts +0 -103
  275. package/src/contracts/host.ts +0 -7
  276. package/src/contracts/object-cache.ts +0 -8
  277. package/src/contracts/pi-provider.ts +0 -30
  278. package/src/contracts/pi.ts +0 -261
  279. package/src/contracts/prefix-cache.ts +0 -33
  280. package/src/contracts/resources.ts +0 -25
  281. package/src/contracts/sampling.ts +0 -23
  282. package/src/contracts/scheduling.ts +0 -54
  283. package/src/contracts/tsconfig.json +0 -14
  284. package/src/dataset/generators.ts +0 -1087
  285. package/src/dataset/index.ts +0 -12
  286. package/src/dataset/job.ts +0 -81
  287. package/src/dataset/llm.ts +0 -71
  288. package/src/dataset/registry.ts +0 -528
  289. package/src/diffusion/diffusion-generate.ts +0 -507
  290. package/src/download.ts +0 -505
  291. package/src/embed.ts +0 -77
  292. package/src/engine/admission.ts +0 -59
  293. package/src/engine/cancellation.ts +0 -38
  294. package/src/engine/engine.ts +0 -56
  295. package/src/engine/execution-coordinator.ts +0 -70
  296. package/src/engine/execution-plan.ts +0 -64
  297. package/src/engine/execution-tasks.ts +0 -44
  298. package/src/engine/namespaced-cache.ts +0 -13
  299. package/src/engine/resources.ts +0 -53
  300. package/src/engine/scheduler.ts +0 -92
  301. package/src/engine/session.ts +0 -247
  302. package/src/eval/README.md +0 -130
  303. package/src/eval/ifeval.ts +0 -81
  304. package/src/eval/kl-prompts.ts +0 -29
  305. package/src/eval/kl.ts +0 -590
  306. package/src/eval/perplexity.ts +0 -164
  307. package/src/eval/quality-db.ts +0 -92
  308. package/src/eval/reference-logits.ts +0 -207
  309. package/src/eval/runner.ts +0 -124
  310. package/src/eval/score.ts +0 -49
  311. package/src/eval/tasks/bfcl.ts +0 -535
  312. package/src/eval/tasks/gsm8k.ts +0 -98
  313. package/src/eval/tasks/hashhop.ts +0 -139
  314. package/src/eval/tasks/humaneval.ts +0 -275
  315. package/src/eval/tasks/ifeval.ts +0 -525
  316. package/src/eval/tasks/mmlu.ts +0 -157
  317. package/src/eval/ultrafeedback.ts +0 -60
  318. package/src/evaldb.ts +0 -199
  319. package/src/expert-io.ts +0 -393
  320. package/src/expert-offload-build.ts +0 -77
  321. package/src/expert-offload.ts +0 -76
  322. package/src/expert-residency.ts +0 -1134
  323. package/src/expert-usage.ts +0 -415
  324. package/src/fill/echo-index.ts +0 -188
  325. package/src/fill/fill-session.ts +0 -463
  326. package/src/fill/proposal.ts +0 -68
  327. package/src/fill/schema-rows.ts +0 -506
  328. package/src/fill/tool-boundary.ts +0 -103
  329. package/src/fit.ts +0 -249
  330. package/src/generate.ts +0 -1352
  331. package/src/grammar.ts +0 -604
  332. package/src/harness-pi.ts +0 -184
  333. package/src/hf-push.ts +0 -628
  334. package/src/hub-rest.ts +0 -242
  335. package/src/index.ts +0 -63
  336. package/src/inference/denoising.ts +0 -17
  337. package/src/inference/draft-acceptance.ts +0 -41
  338. package/src/inference/draft-output.ts +0 -49
  339. package/src/inference/graph.ts +0 -33
  340. package/src/inference/prefill.ts +0 -45
  341. package/src/inference/rollback.ts +0 -7
  342. package/src/jobs/index.ts +0 -31
  343. package/src/jobs/job-entry.ts +0 -107
  344. package/src/jobs/task-client.ts +0 -19
  345. package/src/jobs/types.ts +0 -2
  346. package/src/kv-scheme.ts +0 -279
  347. package/src/kv-store.ts +0 -1135
  348. package/src/lab/README.md +0 -22
  349. package/src/lab/curve/curve-designer.html +0 -303
  350. package/src/lab/curve/curve-sampler.ts +0 -122
  351. package/src/lab/expert-trace/expert-trace.ts +0 -69
  352. package/src/lab/paged-kv/paged-attention.ts +0 -117
  353. package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
  354. package/src/lab/paged-kv/paged-kv.ts +0 -336
  355. package/src/library.ts +0 -40
  356. package/src/lora.ts +0 -408
  357. package/src/md-modules.d.ts +0 -54
  358. package/src/media-fetch.ts +0 -442
  359. package/src/memory/article.ts +0 -558
  360. package/src/memory/chunk-validation.ts +0 -150
  361. package/src/memory/chunk.ts +0 -318
  362. package/src/memory/cluster.ts +0 -351
  363. package/src/memory/coverage.ts +0 -134
  364. package/src/memory/crosslink.ts +0 -0
  365. package/src/memory/db.ts +0 -253
  366. package/src/memory/entity.ts +0 -203
  367. package/src/memory/gate.ts +0 -187
  368. package/src/memory/history.ts +0 -152
  369. package/src/memory/ingest.ts +0 -335
  370. package/src/memory/model.ts +0 -183
  371. package/src/memory/normalize.ts +0 -671
  372. package/src/memory/parse.ts +0 -22
  373. package/src/memory/pipeline.ts +0 -275
  374. package/src/memory/prompts.ts +0 -65
  375. package/src/memory/query.ts +0 -334
  376. package/src/memory/reconcile.ts +0 -734
  377. package/src/memory/redirect.ts +0 -108
  378. package/src/memory/reindex.ts +0 -325
  379. package/src/memory/resolve.ts +0 -307
  380. package/src/memory/rest.ts +0 -245
  381. package/src/memory/route.ts +0 -272
  382. package/src/memory/schedule.ts +0 -165
  383. package/src/memory/stages.ts +0 -777
  384. package/src/memory/synthesize.ts +0 -1638
  385. package/src/memory/tools.ts +0 -749
  386. package/src/memory/vault.ts +0 -1194
  387. package/src/memory/wikify.ts +0 -1064
  388. package/src/mlx/array.ts +0 -425
  389. package/src/mlx/autograd.ts +0 -304
  390. package/src/mlx/checkpoint.ts +0 -149
  391. package/src/mlx/compile.ts +0 -168
  392. package/src/mlx/custom-vjp.ts +0 -188
  393. package/src/mlx/ffi.ts +0 -531
  394. package/src/mlx/materialize.ts +0 -23
  395. package/src/mlx/metal-kernel.ts +0 -159
  396. package/src/mlx/normalized-argmax.ts +0 -116
  397. package/src/mlx/ops.ts +0 -1108
  398. package/src/mlx/quantized-rows.ts +0 -36
  399. package/src/mlx/token-bitmask.ts +0 -52
  400. package/src/mlx/turboquant-kv-decode.ts +0 -82
  401. package/src/mlx/turboquant-kv-inverse.ts +0 -122
  402. package/src/mlx/turboquant-ops.ts +0 -861
  403. package/src/mlx/turboquant-tables.ts +0 -237
  404. package/src/mmap.ts +0 -90
  405. package/src/model/artifact-identity.ts +0 -73
  406. package/src/model/batched-kv.ts +0 -235
  407. package/src/model/batched-mask.ts +0 -279
  408. package/src/model/batched-quant.ts +0 -212
  409. package/src/model/batched-quantized-kv.ts +0 -144
  410. package/src/model/batched-rotating-quant.ts +0 -353
  411. package/src/model/batched-rotating-state.ts +0 -149
  412. package/src/model/batched-rotating.ts +0 -338
  413. package/src/model/batched-row-storage.ts +0 -179
  414. package/src/model/batched-ssm.ts +0 -52
  415. package/src/model/batched-turboquant-kv.ts +0 -94
  416. package/src/model/compiled-decode.ts +0 -712
  417. package/src/model/decoded-kv-donor.ts +0 -12
  418. package/src/model/delayed-quantized-kv.ts +0 -72
  419. package/src/model/delayed-rotating-quantized-kv.ts +0 -93
  420. package/src/model/delayed-turboquant-kv.ts +0 -57
  421. package/src/model/diffusion-gemma.ts +0 -1026
  422. package/src/model/factory.ts +0 -215
  423. package/src/model/fingerprint.ts +0 -45
  424. package/src/model/flash-attention.ts +0 -694
  425. package/src/model/full-prefill-padding.ts +0 -56
  426. package/src/model/full-prefill-row.ts +0 -105
  427. package/src/model/gemma4-base.ts +0 -2370
  428. package/src/model/gemma4.ts +0 -1395
  429. package/src/model/generated/gemma4-12b.ts +0 -429
  430. package/src/model/generated/gemma4-26b.ts +0 -448
  431. package/src/model/generated/gemma4-e4b.ts +0 -717
  432. package/src/model/generated/index.ts +0 -18
  433. package/src/model/glm52-atlas.ts +0 -511
  434. package/src/model/glm52-cache.ts +0 -792
  435. package/src/model/glm52-config.ts +0 -262
  436. package/src/model/glm52-container.ts +0 -305
  437. package/src/model/glm52-coupling.ts +0 -388
  438. package/src/model/glm52-dsa.ts +0 -606
  439. package/src/model/glm52-expert-layout.ts +0 -253
  440. package/src/model/glm52-layout.ts +0 -152
  441. package/src/model/glm52-memory.ts +0 -500
  442. package/src/model/glm52-mla.ts +0 -792
  443. package/src/model/glm52-moe.ts +0 -223
  444. package/src/model/glm52-pilot.ts +0 -537
  445. package/src/model/glm52-reference.ts +0 -445
  446. package/src/model/glm52-residency.ts +0 -557
  447. package/src/model/glm52-resident-weights.ts +0 -135
  448. package/src/model/glm52-streamed-experts.ts +0 -453
  449. package/src/model/glm52-streamed-metal.ts +0 -610
  450. package/src/model/glm52-weights.ts +0 -503
  451. package/src/model/glm52.ts +0 -1132
  452. package/src/model/implementation.ts +0 -69
  453. package/src/model/kv-attention-view.ts +0 -70
  454. package/src/model/minicpm5.ts +0 -376
  455. package/src/model/profile.ts +0 -468
  456. package/src/model/quantized-append-attention.ts +0 -31
  457. package/src/model/qwen-append.ts +0 -12
  458. package/src/model/qwen-conv.ts +0 -52
  459. package/src/model/qwen3-delta-state.ts +0 -74
  460. package/src/model/qwen3-delta.ts +0 -451
  461. package/src/model/qwen3-moe.ts +0 -404
  462. package/src/model/qwen3-mrope.ts +0 -250
  463. package/src/model/qwen3.ts +0 -277
  464. package/src/model/qwen3_5-checkpoint.ts +0 -164
  465. package/src/model/qwen3_5.ts +0 -881
  466. package/src/model/rotating-kv-donor.ts +0 -35
  467. package/src/model/rotating-kv-layout.ts +0 -262
  468. package/src/model/rotating-row-transaction.ts +0 -35
  469. package/src/model/speculative-rotating-kv.ts +0 -101
  470. package/src/model/ssm-prefill-padding.ts +0 -39
  471. package/src/model/support.ts +0 -110
  472. package/src/model/token-groups.ts +0 -66
  473. package/src/model/trellis-balanced-scatter.ts +0 -51
  474. package/src/model/trellis-linear.ts +0 -672
  475. package/src/model/trellis-shared-m.ts +0 -151
  476. package/src/model/trellis-shared-scatter.ts +0 -144
  477. package/src/model/trellis-splitk-prefill.ts +0 -158
  478. package/src/model/trellis-tiled-prefill.ts +0 -136
  479. package/src/model/trellis-vector-expand.ts +0 -62
  480. package/src/model/trellis-wide-prefill.ts +0 -94
  481. package/src/model/turboquant-codec.ts +0 -89
  482. package/src/model/universal/archs.ts +0 -332
  483. package/src/model/universal/dense.ts +0 -612
  484. package/src/model/universal/modules.ts +0 -170
  485. package/src/model/universal/rope.ts +0 -381
  486. package/src/model/whisper.ts +0 -435
  487. package/src/native/expert_io.c +0 -523
  488. package/src/native/frame_extract.swift +0 -140
  489. package/src/native/mic_capture.swift +0 -92
  490. package/src/native-pack.ts +0 -163
  491. package/src/pi-provider.ts +0 -53
  492. package/src/pi-session.ts +0 -81
  493. package/src/pi-terminal.ts +0 -274
  494. package/src/pi-web.ts +0 -1940
  495. package/src/preflight.ts +0 -158
  496. package/src/prompt-cache.ts +0 -682
  497. package/src/quantize/allocator.ts +0 -627
  498. package/src/quantize/atomic-output.ts +0 -38
  499. package/src/quantize/calibration.ts +0 -181
  500. package/src/quantize/config-writer.ts +0 -145
  501. package/src/quantize/index.ts +0 -84
  502. package/src/quantize/job.ts +0 -162
  503. package/src/quantize/quantizer.ts +0 -666
  504. package/src/quantize/rotate.ts +0 -603
  505. package/src/quantize/safetensors-writer.ts +0 -249
  506. package/src/quantize/sensitivity.ts +0 -216
  507. package/src/quantize/trellis.ts +0 -586
  508. package/src/quantize/weight-transform.ts +0 -292
  509. package/src/registry.ts +0 -602
  510. package/src/runtime-config.ts +0 -77
  511. package/src/safetensors.ts +0 -165
  512. package/src/sampler.ts +0 -1012
  513. package/src/serve/admin-routes.ts +0 -184
  514. package/src/serve/assets/curve-terrain.html +0 -105
  515. package/src/serve/assets/training-inference-map.html +0 -575
  516. package/src/serve/audio-routes.ts +0 -323
  517. package/src/serve/aux-routes.ts +0 -132
  518. package/src/serve/batch-scheduler.ts +0 -8
  519. package/src/serve/checkpoint-identity.ts +0 -64
  520. package/src/serve/generation-gateway.ts +0 -537
  521. package/src/serve/isolate.ts +0 -609
  522. package/src/serve/kv-budget.ts +0 -14
  523. package/src/serve/lab-routes.ts +0 -341
  524. package/src/serve/lane-registry.ts +0 -45
  525. package/src/serve/model-admin-routes.ts +0 -155
  526. package/src/serve/model-binding.ts +0 -49
  527. package/src/serve/model-host.ts +0 -511
  528. package/src/serve/parent-application.ts +0 -56
  529. package/src/serve/prompt-response-trace.ts +0 -161
  530. package/src/serve/response-lease.ts +0 -24
  531. package/src/serve/session-search.ts +0 -326
  532. package/src/serve/static-routes.ts +0 -101
  533. package/src/serve/transcription-server.ts +0 -64
  534. package/src/serve/transcription-service.ts +0 -502
  535. package/src/server.ts +0 -1282
  536. package/src/spec/assistant-rows.ts +0 -93
  537. package/src/spec/assistant-source.ts +0 -126
  538. package/src/spec/cache-identity.ts +0 -22
  539. package/src/spec/deepspec-rows.ts +0 -29
  540. package/src/spec/deepspec-source.ts +0 -145
  541. package/src/spec/dflash-source.ts +0 -149
  542. package/src/spec/drafter.ts +0 -304
  543. package/src/spec/dspark/ab-stats.ts +0 -136
  544. package/src/spec/dspark/calibration.ts +0 -112
  545. package/src/spec/dspark/data-dflash.ts +0 -156
  546. package/src/spec/dspark/data.ts +0 -201
  547. package/src/spec/dspark/deepspec-module.ts +0 -776
  548. package/src/spec/dspark/generate-dflash.ts +0 -245
  549. package/src/spec/dspark/generate.ts +0 -290
  550. package/src/spec/dspark/loader.ts +0 -23
  551. package/src/spec/dspark/loss.ts +0 -213
  552. package/src/spec/dspark/module-dflash.ts +0 -560
  553. package/src/spec/dspark/module.ts +0 -540
  554. package/src/spec/dspark/quantize-drafter.ts +0 -91
  555. package/src/spec/dspark/sample.ts +0 -112
  556. package/src/spec/generate.ts +0 -276
  557. package/src/spec/glm52-mtp-graph.ts +0 -29
  558. package/src/spec/glm52-mtp-rows.ts +0 -132
  559. package/src/spec/glm52-mtp-source.ts +0 -318
  560. package/src/spec/glm52-mtp-state.ts +0 -33
  561. package/src/spec/ngram-source.ts +0 -226
  562. package/src/spec/projected-draft-rows.ts +0 -73
  563. package/src/spec/qwen-mtp-module.ts +0 -171
  564. package/src/spec/qwen-mtp-rows.ts +0 -230
  565. package/src/spec/qwen-mtp-source.ts +0 -386
  566. package/src/spec/qwen-mtp-state.ts +0 -30
  567. package/src/spec/serve-loop.ts +0 -587
  568. package/src/spec/source.ts +0 -228
  569. package/src/spec/two-model-rows.ts +0 -62
  570. package/src/spec/two-model.ts +0 -113
  571. package/src/ssd-cache.ts +0 -431
  572. package/src/ssd-durability.ts +0 -209
  573. package/src/storage/host-buffer.ts +0 -24
  574. package/src/storage/kv-writer.ts +0 -83
  575. package/src/storage/kv-writer.worker.js +0 -264
  576. package/src/storage/retention-policy.ts +0 -37
  577. package/src/tiered-prompt-cache.ts +0 -45
  578. package/src/tokenizer.ts +0 -335
  579. package/src/tool-approvals.ts +0 -131
  580. package/src/tool-call.ts +0 -695
  581. package/src/train/dataset.ts +0 -484
  582. package/src/train/diffusion-lora.ts +0 -216
  583. package/src/train/export.ts +0 -32
  584. package/src/train/flash-cce.ts +0 -1234
  585. package/src/train/forward.ts +0 -266
  586. package/src/train/fuse.ts +0 -243
  587. package/src/train/index.ts +0 -46
  588. package/src/train/job.ts +0 -205
  589. package/src/train/lora-params.ts +0 -254
  590. package/src/train/loss.ts +0 -1591
  591. package/src/train/merge.ts +0 -195
  592. package/src/train/optimizer.ts +0 -183
  593. package/src/train/prefix-shared.ts +0 -490
  594. package/src/train/rank.ts +0 -137
  595. package/src/train/segmented.ts +0 -1828
  596. package/src/train/steel-qmm-header.ts +0 -1461
  597. package/src/train/trainer.ts +0 -1221
  598. package/src/train/watch.ts +0 -542
  599. package/src/vision/diffusion-vision.ts +0 -620
  600. package/src/vision/embedder.ts +0 -176
  601. package/src/vision/preprocess.ts +0 -247
  602. package/src/vision/prompt.ts +0 -409
  603. package/src/vision/qwen3vl-preprocess.ts +0 -409
  604. package/src/vision/qwen3vl-prompt.ts +0 -233
  605. package/src/vision/qwen3vl-tower.ts +0 -566
  606. package/src/vision/siglip.ts +0 -607
  607. package/src/vision/video-frames.ts +0 -148
  608. package/src/web/app.html +0 -2155
  609. package/src/web/app.js +0 -5863
  610. package/src/web/skills/memory/SKILL.md +0 -120
  611. package/src/web/skills/web-research/SKILL.md +0 -46
  612. package/src/web/skills.ts +0 -97
  613. package/src/web/src/adapters-panel.ts +0 -288
  614. package/src/web/src/assistant.ts +0 -451
  615. package/src/web/src/chat.ts +0 -1060
  616. package/src/web/src/composer.ts +0 -962
  617. package/src/web/src/dataset.ts +0 -132
  618. package/src/web/src/finetune.ts +0 -267
  619. package/src/web/src/hub.ts +0 -428
  620. package/src/web/src/main.ts +0 -98
  621. package/src/web/src/markdown.ts +0 -0
  622. package/src/web/src/memory-panel.ts +0 -572
  623. package/src/web/src/model-picker.ts +0 -159
  624. package/src/web/src/palette.ts +0 -346
  625. package/src/web/src/protocol.ts +0 -26
  626. package/src/web/src/quantize.ts +0 -167
  627. package/src/web/src/rag.ts +0 -274
  628. package/src/web/src/sessions.ts +0 -469
  629. package/src/web/src/shell.ts +0 -804
  630. package/src/web/src/ui-catalog.ts +0 -78
  631. package/src/web/src/voice.ts +0 -141
  632. package/src/web/vendor/README.md +0 -61
  633. package/src/web-assets.ts +0 -47
  634. package/src/web-tools.ts +0 -478
  635. package/src/weights.ts +0 -255
  636. /package/src/{serve → server}/completion-sink.ts +0 -0
  637. /package/src/{serve → server}/generated-token-history.ts +0 -0
  638. /package/src/web/{icon.svg → public/icon.svg} +0 -0
  639. /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
  640. /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
@@ -1,1087 +0,0 @@
1
- // The 13 dataset generators, ported from optiq's dataset_templates.py
2
- // `_gen_*` functions. Each is `async (inputs, emit, llm?) -> Row[]`.
3
- //
4
- // Row shapes (per output_format):
5
- // messages → { messages: [{ role, content }, ...] }
6
- // prompt_completion → { prompt, completion }
7
- // dpo → { prompt, chosen, rejected }
8
- // text → { text }
9
- // Rows may carry extra keys (metadata, tools) to mirror the Python output.
10
-
11
- import type { Emit } from "../jobs/types";
12
- import type { ChatMessage, LlmClient } from "./llm";
13
-
14
- export type Row = Record<string, unknown>;
15
-
16
- type Inputs = Record<string, unknown>;
17
-
18
- /** Coerce a maybe-undefined input to a trimmed string. */
19
- function str(v: unknown): string {
20
- if (v === undefined || v === null) return "";
21
- return typeof v === "string" ? v : String(v);
22
- }
23
-
24
- /** Coerce a maybe-undefined numeric input, falling back to `dflt`. */
25
- function num(v: unknown, dflt: number): number {
26
- if (v === undefined || v === null || v === "") return dflt;
27
- const n = typeof v === "number" ? v : parseInt(String(v), 10);
28
- return Number.isFinite(n) ? n : dflt;
29
- }
30
-
31
- /** Split lines, trim, drop blanks (Python `splitlines()` + strip filter). */
32
- function nonEmptyLines(v: unknown): string[] {
33
- return str(v)
34
- .split(/\r?\n/)
35
- .map((s) => s.trim())
36
- .filter((s) => s.length > 0);
37
- }
38
-
39
- /** Require an llm client, with a clear message naming the template. */
40
- function requireLlm(llm: LlmClient | undefined, template: string): LlmClient {
41
- if (!llm) {
42
- throw new Error(
43
- `template ${JSON.stringify(template)} is LLM-driven and requires a served ` +
44
- `model — pass an LlmClient (mlx-bun loopback /v1/chat/completions).`,
45
- );
46
- }
47
- return llm;
48
- }
49
-
50
- // ===========================================================================
51
- // Non-LLM generators (full ports, well-tested)
52
- // ===========================================================================
53
-
54
- export async function genSftQa(inputs: Inputs): Promise<Row[]> {
55
- const text = str(inputs.pairs_text).trim();
56
- if (!text) return [];
57
- const rows: Row[] = [];
58
- // Split on blank lines; each block expected to contain Q: / A:.
59
- for (const block of text.split(/\n\s*\n/)) {
60
- const qMatch = block.match(/^[ \t]*Q[ \t]*:[ \t]*(.+)/im);
61
- // DOTALL for the answer: capture everything after `A:` to end of block.
62
- const aMatch = block.match(/^[ \t]*A[ \t]*:[ \t]*([\s\S]+)/im);
63
- if (qMatch && aMatch) {
64
- rows.push({
65
- messages: [
66
- { role: "user", content: qMatch[1]!.trim() },
67
- { role: "assistant", content: aMatch[1]!.trim() },
68
- ],
69
- });
70
- }
71
- }
72
- return rows;
73
- }
74
-
75
- /**
76
- * Minimal RFC-4180-ish CSV parser: handles quoted fields, embedded commas,
77
- * embedded newlines, and "" escaped quotes. No external dep. Returns a list
78
- * of records keyed by the header row.
79
- */
80
- export function parseCsv(text: string): Record<string, string>[] {
81
- const rows: string[][] = [];
82
- let field = "";
83
- let record: string[] = [];
84
- let inQuotes = false;
85
- let i = 0;
86
- const n = text.length;
87
-
88
- const endField = () => {
89
- record.push(field);
90
- field = "";
91
- };
92
- const endRecord = () => {
93
- endField();
94
- rows.push(record);
95
- record = [];
96
- };
97
-
98
- while (i < n) {
99
- const ch = text[i]!;
100
- if (inQuotes) {
101
- if (ch === '"') {
102
- if (text[i + 1] === '"') {
103
- field += '"'; // escaped quote
104
- i += 2;
105
- continue;
106
- }
107
- inQuotes = false;
108
- i++;
109
- continue;
110
- }
111
- field += ch;
112
- i++;
113
- continue;
114
- }
115
- if (ch === '"') {
116
- inQuotes = true;
117
- i++;
118
- continue;
119
- }
120
- if (ch === ",") {
121
- endField();
122
- i++;
123
- continue;
124
- }
125
- if (ch === "\r") {
126
- // Treat \r\n and lone \r as record separators.
127
- endRecord();
128
- if (text[i + 1] === "\n") i += 2;
129
- else i++;
130
- continue;
131
- }
132
- if (ch === "\n") {
133
- endRecord();
134
- i++;
135
- continue;
136
- }
137
- field += ch;
138
- i++;
139
- }
140
- // Flush trailing field/record if there's pending content.
141
- if (field.length > 0 || record.length > 0) endRecord();
142
-
143
- if (rows.length === 0) return [];
144
- const header = rows[0]!.map((h) => h.trim());
145
- const out: Record<string, string>[] = [];
146
- for (let r = 1; r < rows.length; r++) {
147
- const cells = rows[r]!;
148
- // Skip fully-empty trailing rows (e.g. file ending in a newline).
149
- if (cells.length === 1 && cells[0] === "") continue;
150
- const obj: Record<string, string> = {};
151
- for (let c = 0; c < header.length; c++) {
152
- obj[header[c]!] = cells[c] ?? "";
153
- }
154
- out.push(obj);
155
- }
156
- return out;
157
- }
158
-
159
- export async function genDpoPairs(inputs: Inputs): Promise<Row[]> {
160
- const text = str(inputs.csv_text).trim();
161
- if (!text) return [];
162
- const rows: Row[] = [];
163
- for (const r of parseCsv(text)) {
164
- // Match Python: keep only rows where all three are truthy (non-empty).
165
- if (r.prompt && r.chosen && r.rejected) {
166
- rows.push({ prompt: r.prompt, chosen: r.chosen, rejected: r.rejected });
167
- }
168
- }
169
- return rows;
170
- }
171
-
172
- export async function genCodeCompletion(inputs: Inputs): Promise<Row[]> {
173
- const srcRaw = str(inputs.src_dir).trim();
174
- const maxPairs = num(inputs.max_pairs, 500);
175
- // Expand a leading ~ to the home dir (parity with Path.expanduser()).
176
- const src = srcRaw.startsWith("~")
177
- ? `${process.env.HOME ?? ""}${srcRaw.slice(1)}`
178
- : srcRaw;
179
-
180
- const { statSync } = await import("node:fs");
181
- let isDir = false;
182
- try {
183
- isDir = statSync(src).isDirectory();
184
- } catch {
185
- isDir = false;
186
- }
187
- if (!isDir) throw new Error(`src_dir not a directory: ${src}`);
188
-
189
- // Deterministic PRNG (mulberry32) so test splits are stable. We do NOT use
190
- // Math.random; the Python uses random.Random(42) — we mirror the intent
191
- // (seeded) rather than the exact sequence.
192
- let seed = 42 >>> 0;
193
- const randInt = (lo: number, hi: number): number => {
194
- // inclusive [lo, hi]
195
- seed = (seed + 0x6d2b79f5) | 0;
196
- let t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
197
- t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
198
- const u = ((t ^ (t >>> 14)) >>> 0) / 4294967296;
199
- return lo + Math.floor(u * (hi - lo + 1));
200
- };
201
-
202
- const rows: Row[] = [];
203
- const glob = new Bun.Glob("**/*.py");
204
- // Sort the file list for determinism across filesystems.
205
- const files: string[] = [];
206
- for await (const rel of glob.scan({ cwd: src, onlyFiles: true })) {
207
- files.push(rel);
208
- }
209
- files.sort();
210
-
211
- for (const rel of files) {
212
- let text: string;
213
- try {
214
- text = await Bun.file(`${src}/${rel}`).text();
215
- } catch {
216
- continue;
217
- }
218
- // Split on def / class / async def boundaries (lookahead at line start).
219
- const chunks = text.split(/(?=^(?:def |class |async def ))/m);
220
- for (const raw of chunks) {
221
- const chunk = raw.trim();
222
- if (chunk.length < 30) continue;
223
- const lo = Math.floor(chunk.length / 4);
224
- const hi = Math.max(lo + 1, Math.floor((chunk.length * 3) / 4));
225
- const splitAt = randInt(lo, hi);
226
- rows.push({
227
- prompt: chunk.slice(0, splitAt),
228
- completion: chunk.slice(splitAt),
229
- });
230
- if (rows.length >= maxPairs) return rows;
231
- }
232
- }
233
- return rows;
234
- }
235
-
236
- export async function genFormatConversion(inputs: Inputs): Promise<Row[]> {
237
- const text = str(inputs.input_jsonl).trim();
238
- const userKey = str(inputs.user_key) || "input";
239
- const asstKey = str(inputs.assistant_key) || "output";
240
- const rows: Row[] = [];
241
- for (const rawLine of text.split(/\r?\n/)) {
242
- const line = rawLine.trim();
243
- if (!line) continue;
244
- let obj: any;
245
- try {
246
- obj = JSON.parse(line);
247
- } catch {
248
- continue;
249
- }
250
- const u = obj?.[userKey];
251
- const a = obj?.[asstKey];
252
- if (u === undefined || u === null || a === undefined || a === null) continue;
253
- rows.push({
254
- messages: [
255
- { role: "user", content: String(u) },
256
- { role: "assistant", content: String(a) },
257
- ],
258
- });
259
- }
260
- return rows;
261
- }
262
-
263
- // ===========================================================================
264
- // hf_dataset_import — pull a public HF dataset via the datasets-server REST
265
- // API and shape it. Faithful port of optiq's `_gen_hf_dataset_import`, with
266
- // the `datasets` library swapped for the datasets-server `/rows` endpoint
267
- // (no Python, no `datasets` dep).
268
- // ===========================================================================
269
-
270
- /** A single datasets-server row envelope: `{ row_idx, row: {col: value} }`. */
271
- export interface HfServerRow {
272
- row?: Record<string, unknown>;
273
- [k: string]: unknown;
274
- }
275
-
276
- /** Parsed + normalized options for the row→example transform. */
277
- export interface HfImportOpts {
278
- textColumn: string;
279
- labelColumn: string | null;
280
- labelFilter: string | null;
281
- minChars: number; // 0 = no minimum
282
- maxRows: number; // 0 = no cap
283
- outputFormat: string; // "messages_user_only" | "prompt_completion" | "text"
284
- }
285
-
286
- /** Running tallies + accumulated rows, threaded through the transform. */
287
- export interface HfTransformState {
288
- rows: Row[];
289
- kept: number;
290
- rejectedShort: number;
291
- rejectedFilter: number;
292
- }
293
-
294
- /** Fresh, zeroed transform state. */
295
- export function newHfTransformState(): HfTransformState {
296
- return { rows: [], kept: 0, rejectedShort: 0, rejectedFilter: 0 };
297
- }
298
-
299
- /**
300
- * Python truthiness for a JSON-decoded value, mirroring `(x or "")` semantics.
301
- * Falsy: None/undefined, "", 0/0.0, False, NaN, empty array, empty object.
302
- */
303
- function isPythonTruthy(v: unknown): boolean {
304
- if (v === undefined || v === null || v === false || v === "") return false;
305
- if (typeof v === "number") return v !== 0 && !Number.isNaN(v);
306
- if (Array.isArray(v)) return v.length > 0;
307
- if (typeof v === "object") return Object.keys(v as object).length > 0;
308
- return true;
309
- }
310
-
311
- /**
312
- * Pure row→example transform — exact port of the body of the optiq loop in
313
- * `_gen_hf_dataset_import`. Mutates `state` in place and returns it.
314
- *
315
- * Apply order (matching Python): (1) max_rows cap → return `false` (caller
316
- * should stop), (2) coerce text via `str()` + strip, (3) min_chars drop,
317
- * (4) label filter drop (`str(row[col]) !== filter`), (5) shape by format.
318
- *
319
- * @returns `true` if the caller should keep feeding rows, `false` once the
320
- * `max_rows` cap is reached (the current row was NOT consumed).
321
- */
322
- export function applyHfRow(
323
- envelope: HfServerRow,
324
- opts: HfImportOpts,
325
- state: HfTransformState,
326
- ): boolean {
327
- // Python: `if max_rows and kept >= max_rows: break` (checked before the row).
328
- if (opts.maxRows && state.kept >= opts.maxRows) return false;
329
-
330
- const row = envelope.row ?? {};
331
- const raw = row[opts.textColumn];
332
- // Python: `text = (row.get(text_column) or "")` then `str(...)` if not str.
333
- // `or ""` collapses Python-falsy values (None, "", 0, 0.0, False, [], {}) to "".
334
- let text: string;
335
- if (!isPythonTruthy(raw)) {
336
- text = "";
337
- } else if (typeof raw === "string") {
338
- text = raw;
339
- } else {
340
- text = String(raw);
341
- }
342
- text = text.trim();
343
-
344
- if (opts.minChars && text.length < opts.minChars) {
345
- state.rejectedShort++;
346
- return true;
347
- }
348
- if (opts.labelColumn && opts.labelFilter) {
349
- // Python: `str(row.get(label_column, ""))` — missing → "".
350
- const lv = row[opts.labelColumn];
351
- const labelStr = lv === undefined || lv === null ? "" : String(lv);
352
- if (labelStr !== opts.labelFilter) {
353
- state.rejectedFilter++;
354
- return true;
355
- }
356
- }
357
-
358
- if (opts.outputFormat === "messages_user_only") {
359
- state.rows.push({ messages: [{ role: "user", content: text }] });
360
- } else if (opts.outputFormat === "prompt_completion") {
361
- state.rows.push({ prompt: text, completion: "" });
362
- } else {
363
- // default: text
364
- state.rows.push({ text });
365
- }
366
- state.kept++;
367
- return true;
368
- }
369
-
370
- const HF_ROWS_ENDPOINT = "https://datasets-server.huggingface.co/rows";
371
- const HF_SPLITS_ENDPOINT = "https://datasets-server.huggingface.co/splits";
372
- const HF_PAGE = 100; // datasets-server caps `length` at 100 rows/request.
373
-
374
- /** Bearer header for gated datasets when HF_TOKEN is set; else anonymous. */
375
- function hfAuthHeaders(): Record<string, string> {
376
- const tok = process.env.HF_TOKEN;
377
- return tok ? { Authorization: `Bearer ${tok}` } : {};
378
- }
379
-
380
- /** Fetch JSON with a couple of retries on transient 429/5xx (and net errors). */
381
- async function hfFetchJson(url: string): Promise<any> {
382
- const headers = hfAuthHeaders();
383
- let lastErr: unknown;
384
- for (let attempt = 0; attempt < 3; attempt++) {
385
- try {
386
- const res = await fetch(url, { headers });
387
- if (res.ok) return await res.json();
388
- // Retry transient statuses; fail fast on 4xx (except 429).
389
- if (res.status === 429 || res.status >= 500) {
390
- lastErr = new Error(`HF datasets-server ${res.status} for ${url}`);
391
- } else {
392
- const body = await res.text().catch(() => "");
393
- throw new Error(
394
- `HF datasets-server ${res.status} for ${url}` + (body ? `: ${body.slice(0, 300)}` : ""),
395
- );
396
- }
397
- } catch (e) {
398
- lastErr = e;
399
- }
400
- // Backoff: 0.5s, 1s before the final attempt.
401
- if (attempt < 2) await new Promise((r) => setTimeout(r, 500 * (attempt + 1)));
402
- }
403
- throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
404
- }
405
-
406
- /** Resolve the default config for a dataset (first config of the split, or any). */
407
- async function resolveDefaultConfig(hfId: string, split: string): Promise<string> {
408
- const url = `${HF_SPLITS_ENDPOINT}?dataset=${encodeURIComponent(hfId)}`;
409
- const data = await hfFetchJson(url);
410
- const splits: Array<{ config?: string; split?: string }> = Array.isArray(data?.splits)
411
- ? data.splits
412
- : [];
413
- // Prefer a config that actually has the requested split; else the first one.
414
- const match = splits.find((s) => s.split === split) ?? splits[0];
415
- return (match?.config ?? "default").trim() || "default";
416
- }
417
-
418
- export async function genHfDatasetImport(
419
- inputs: Inputs = {},
420
- emit: Emit = () => {},
421
- ): Promise<Row[]> {
422
- // ---- parse inputs (mirror optiq's `.strip() or default` coercions) ----
423
- const hfId = str(inputs.hf_id).trim();
424
- if (!hfId) return [];
425
- let config = str(inputs.config).trim() || null;
426
- const split = str(inputs.split).trim() || "train";
427
- const opts: HfImportOpts = {
428
- textColumn: str(inputs.text_column).trim() || "text",
429
- labelColumn: str(inputs.label_column).trim() || null,
430
- labelFilter: str(inputs.label_filter).trim() || null,
431
- maxRows: num(inputs.max_rows, 0),
432
- minChars: num(inputs.min_chars, 0),
433
- outputFormat: str(inputs.output_format).trim() || "text",
434
- };
435
-
436
- emit({
437
- type: "stage",
438
- stage: "loading",
439
- message: `Loading ${hfId} (${split})…`,
440
- progress: 0.05,
441
- });
442
-
443
- // Resolve the default config if the user didn't give one.
444
- if (!config) {
445
- config = await resolveDefaultConfig(hfId, split);
446
- }
447
-
448
- emit({
449
- type: "stage",
450
- stage: "filtering",
451
- message: `Loading rows from ${hfId} (${config}/${split})…`,
452
- progress: 0.2,
453
- });
454
-
455
- // ---- paginate /rows by offset, applying the transform per page ----
456
- const state = newHfTransformState();
457
- let offset = 0;
458
- let columnsChecked = false;
459
- outer: while (true) {
460
- const url =
461
- `${HF_ROWS_ENDPOINT}?dataset=${encodeURIComponent(hfId)}` +
462
- `&config=${encodeURIComponent(config)}` +
463
- `&split=${encodeURIComponent(split)}` +
464
- `&offset=${offset}&length=${HF_PAGE}`;
465
- const data = await hfFetchJson(url);
466
- const page: HfServerRow[] = Array.isArray(data?.rows) ? data.rows : [];
467
- if (page.length === 0) break;
468
-
469
- // Validate columns once (parity with optiq's column_names guard).
470
- if (!columnsChecked) {
471
- columnsChecked = true;
472
- const cols = new Set<string>(Object.keys(page[0]!.row ?? {}));
473
- if (!cols.has(opts.textColumn)) {
474
- throw new Error(
475
- `text_column=${JSON.stringify(opts.textColumn)} not in dataset. ` +
476
- `Available columns: ${JSON.stringify([...cols])}`,
477
- );
478
- }
479
- if (opts.labelColumn && !cols.has(opts.labelColumn)) {
480
- throw new Error(
481
- `label_column=${JSON.stringify(opts.labelColumn)} not in dataset. ` +
482
- `Available columns: ${JSON.stringify([...cols])}`,
483
- );
484
- }
485
- }
486
-
487
- for (const env of page) {
488
- const cont = applyHfRow(env, opts, state);
489
- if (!cont) break outer; // hit max_rows
490
- // Progress every 500 kept rows (mirror optiq's emit cadence).
491
- if (state.kept && state.kept % 500 === 0) {
492
- emit({
493
- type: "stage",
494
- stage: "filtering",
495
- message: `kept ${state.kept} rows…`,
496
- progress:
497
- 0.2 + 0.7 * Math.min(1.0, state.kept / Math.max(1, opts.maxRows || state.kept)),
498
- });
499
- }
500
- }
501
-
502
- offset += page.length;
503
- }
504
-
505
- emit({
506
- type: "stage",
507
- stage: "writing",
508
- message: `kept ${state.kept}; dropped ${state.rejectedShort} short, ${state.rejectedFilter} filtered out`,
509
- progress: 0.95,
510
- });
511
- return state.rows;
512
- }
513
-
514
- // ===========================================================================
515
- // LLM-driven generators (call the loopback server)
516
- // ===========================================================================
517
-
518
- export async function genStyleTransfer(
519
- inputs: Inputs,
520
- emit: Emit,
521
- llm?: LlmClient,
522
- ): Promise<Row[]> {
523
- const client = requireLlm(llm, "style_transfer");
524
- const refs = str(inputs.reference_samples).trim();
525
- const raw = str(inputs.raw_text).trim();
526
- if (!(refs && raw)) return [];
527
- const paragraphs = raw
528
- .split("\n\n")
529
- .map((p) => p.trim())
530
- .filter((p) => p.length > 0);
531
- const rows: Row[] = [];
532
- for (let i = 0; i < paragraphs.length; i++) {
533
- const p = paragraphs[i]!;
534
- emit({
535
- type: "stage",
536
- stage: "generating",
537
- progress: 0.1 + 0.85 * (i / Math.max(paragraphs.length, 1)),
538
- message: `rewriting paragraph ${i + 1}/${paragraphs.length}`,
539
- });
540
- const prompt =
541
- "Rewrite the text below in the same style and tone as these reference samples.\n\n" +
542
- `REFERENCES:\n${refs}\n\nTEXT TO REWRITE:\n${p}\n\nREWRITTEN:`;
543
- const out = await client.chat([{ role: "user", content: prompt }], { maxTokens: 512 });
544
- rows.push({ prompt: p, completion: out });
545
- }
546
- return rows;
547
- }
548
-
549
- /**
550
- * Best-effort extract a list of K instructions from LLM output. Tries (in
551
- * order): strict JSON on the shortest balanced [...] span, comma-split of the
552
- * first [...] span, then numbered/bulleted lines. Port of
553
- * `_parse_instruction_list`.
554
- */
555
- export function parseInstructionList(text: string, k: number): string[] {
556
- if (!text) return [];
557
- const s = text.trim();
558
-
559
- // Collect every balanced [ ... ] span.
560
- const spans: Array<[number, number]> = [];
561
- let depth = 0;
562
- let start = -1;
563
- for (let i = 0; i < s.length; i++) {
564
- const ch = s[i];
565
- if (ch === "[") {
566
- if (depth === 0) start = i;
567
- depth++;
568
- } else if (ch === "]") {
569
- depth--;
570
- if (depth === 0 && start >= 0) {
571
- spans.push([start, i + 1]);
572
- start = -1;
573
- }
574
- }
575
- }
576
-
577
- // Strict JSON on each balanced span (first that yields a non-empty list).
578
- for (const [si, ei] of spans) {
579
- try {
580
- const v = JSON.parse(s.slice(si, ei));
581
- if (Array.isArray(v)) {
582
- const items = v.map((x) => String(x).trim()).filter((x) => x.length > 0);
583
- if (items.length) return items.slice(0, k);
584
- }
585
- } catch {
586
- // fall through
587
- }
588
- }
589
-
590
- // First [ ... ] span, comma-split (handles unquoted strings).
591
- if (spans.length) {
592
- const [si, ei] = spans[0]!;
593
- const inner = s.slice(si + 1, ei - 1);
594
- const parts = inner
595
- .split(",")
596
- .map((p) => p.trim().replace(/^["']|["']$/g, ""))
597
- .filter((p) => p.length > 0);
598
- if (parts.length) return parts.slice(0, k);
599
- }
600
-
601
- // Numbered / bulleted lines.
602
- const out: string[] = [];
603
- for (const rawLine of s.split(/\r?\n/)) {
604
- let line = rawLine.trim();
605
- if (!line) continue;
606
- line = line.replace(/^(?:\d+[.)]|[-*])\s+/, "");
607
- if (line) out.push(line.replace(/^["']|["']$/g, ""));
608
- }
609
- return out.slice(0, k);
610
- }
611
-
612
- export async function genSelfInstruct(
613
- inputs: Inputs,
614
- emit: Emit,
615
- llm?: LlmClient,
616
- ): Promise<Row[]> {
617
- const client = requireLlm(llm, "self_instruct");
618
- const seeds = nonEmptyLines(inputs.seeds);
619
- const k = num(inputs.variants_per_seed, 5);
620
- if (!seeds.length) return [];
621
- const rows: Row[] = [];
622
- for (let i = 0; i < seeds.length; i++) {
623
- const seed = seeds[i]!;
624
- emit({
625
- type: "stage",
626
- stage: "generating",
627
- progress: 0.1 + 0.85 * (i / Math.max(seeds.length, 1)),
628
- message: `seed ${i + 1}/${seeds.length}`,
629
- });
630
- const prompt =
631
- `Generate ${k} new instructions in the same spirit as the example. ` +
632
- "Return them as a JSON array of strings, no commentary. Example " +
633
- 'output format: ["instruction one", "instruction two"]\n\n' +
634
- `Example: ${seed}\n\nArray:`;
635
- const out = await client.chat([{ role: "user", content: prompt }], { maxTokens: 512 });
636
- const variants = parseInstructionList(out, k);
637
- for (const v of variants.slice(0, k)) {
638
- rows.push({
639
- messages: [
640
- { role: "user", content: String(v) },
641
- { role: "assistant", content: "" }, // filled by a later pass
642
- ],
643
- });
644
- }
645
- }
646
- return rows;
647
- }
648
-
649
- export async function genPromptReconstruction(
650
- inputs: Inputs,
651
- emit: Emit,
652
- llm?: LlmClient,
653
- ): Promise<Row[]> {
654
- const client = requireLlm(llm, "prompt_reconstruction");
655
- const raw = (str(inputs.target_text) || str(inputs.human_text)).trim();
656
- const style = str(inputs.style).trim() || "direct technical blog";
657
- const tone = str(inputs.tone).trim() || "analytical, clear";
658
- const preserve = str(inputs.preserve).trim() || "facts, names, numbers, URLs, citations";
659
- const avoid = str(inputs.avoid).trim() || "em dashes, generic transitions";
660
- if (!raw) return [];
661
-
662
- const paragraphs = raw
663
- .split(/\n\s*\n/)
664
- .map((p) => p.trim())
665
- .filter((p) => p.length > 0);
666
-
667
- // Cheap preservation extractors (mirror humanizer/extractors.py).
668
- const urlRe = /https?:\/\/[^\s)\]>]+/g;
669
- const pctRe = /\b\d+(?:\.\d+)?\s?%/g;
670
- const curRe = /(?:\$|€|£|¥|USD\s*|EUR\s*|GBP\s*)\s?[\d,]+(?:\.\d+)?(?:[KMBkmb])?/g;
671
- const dateRe = /\b(?:\d{4}-\d{2}-\d{2}|(?:19|20)\d{2}|(?:Q[1-4]|FY)\s?\d{2,4})\b/g;
672
- const codeRe = /`([^`\n]{1,80})`/g;
673
- const citeRe = /\[\d{1,4}\]|\[[A-Z][A-Za-z\-]+(?:\s+et\s+al\.?)?,?\s*\d{4}[a-z]?\]/g;
674
-
675
- const findAll = (re: RegExp, t: string): string[] => {
676
- const r = new RegExp(re.source, re.flags);
677
- return [...t.matchAll(r)].map((m) => m[0]);
678
- };
679
- const locksOf = (t: string) => ({
680
- urls: findAll(urlRe, t),
681
- percentages: findAll(pctRe, t),
682
- currencies: findAll(curRe, t),
683
- dates: findAll(dateRe, t),
684
- code: findAll(codeRe, t),
685
- citations: findAll(citeRe, t),
686
- });
687
-
688
- const rows: Row[] = [];
689
- for (let i = 0; i < paragraphs.length; i++) {
690
- const para = paragraphs[i]!;
691
- emit({
692
- type: "stage",
693
- stage: "generating",
694
- progress: 0.05 + 0.9 * (i / Math.max(paragraphs.length, 1)),
695
- message: `reconstruct ${i + 1}/${paragraphs.length}`,
696
- });
697
-
698
- // 1. infer prompt
699
- const inferPrompt =
700
- "Given the human-written text below, infer a realistic user prompt " +
701
- "that could have led an AI assistant to produce this kind of text. " +
702
- "Capture topic, intent, audience, and depth. Do NOT quote the text.\n\n" +
703
- `HUMAN TEXT:\n${para}\n\nPROMPT:`;
704
- let inferred = (
705
- await client.chat([{ role: "user", content: inferPrompt }], { maxTokens: 160 })
706
- ).trim();
707
- if (!inferred) inferred = "Write a piece on the topic implied by the chunk.";
708
-
709
- // 2. generate AI-ish draft
710
- const draftPrompt =
711
- "Answer the following user request in a polished but generic AI-assistant style. " +
712
- "Be coherent, use common AI transitions, slightly over-explain, keep similar length. " +
713
- "Do not introduce errors.\n\n" +
714
- `USER REQUEST:\n${inferred}\n\nSTYLE HINT:\n${style} / ${tone}\n\nANSWER:`;
715
- const draft = (
716
- await client.chat([{ role: "user", content: draftPrompt }], { maxTokens: 800 })
717
- ).trim();
718
- if (!draft) continue;
719
-
720
- const lk = locksOf(para);
721
- const sysPrompt =
722
- "You are a controlled rewrite model. Rewrite AI-generated drafts into " +
723
- "natural human-style prose while preserving meaning, facts, names, " +
724
- "numbers, citations, URLs, quotes, and formatting. Do not add unsupported " +
725
- "claims.";
726
- const userMsg =
727
- `STYLE:\n${style}\n\nTONE:\n${tone}\n\n` +
728
- `PRESERVE:\n${preserve}\n\nAVOID:\n${avoid}\n\n` +
729
- `USER PROMPT:\n${inferred}\n\nSOURCE AI DRAFT:\n${draft}\n\n` +
730
- "TASK:\nRewrite only the SOURCE AI DRAFT into natural human prose. " +
731
- "Do not introduce new facts.";
732
- rows.push({
733
- messages: [
734
- { role: "system", content: sysPrompt },
735
- { role: "user", content: userMsg },
736
- { role: "assistant", content: para },
737
- ],
738
- metadata: {
739
- inferred_prompt: inferred,
740
- source_ai_draft: draft,
741
- preservation_locks: lk,
742
- style,
743
- tone,
744
- },
745
- });
746
- }
747
- return rows;
748
- }
749
-
750
- /** Render a chat history as plain text for a one-shot followup prompt. */
751
- function formatConvoForFollowup(convo: ChatMessage[]): string {
752
- const lines: string[] = [];
753
- for (const m of convo) {
754
- const role = m.role ?? "";
755
- const content = str(m.content).trim();
756
- if (!content || role === "system") continue;
757
- lines.push(`${role.toUpperCase()}:\n${content}\n`);
758
- }
759
- return lines.join("\n");
760
- }
761
-
762
- export async function genMultiTurnChat(
763
- inputs: Inputs,
764
- emit: Emit,
765
- llm?: LlmClient,
766
- ): Promise<Row[]> {
767
- const client = requireLlm(llm, "multi_turn_chat");
768
- const seeds = nonEmptyLines(inputs.seeds);
769
- const turns = Math.max(2, num(inputs.turns, 4));
770
- const persona = str(inputs.persona).trim() || "You are a helpful, concise assistant.";
771
- const userPersona =
772
- str(inputs.user_persona).trim() || "a curious developer probing for specifics";
773
- if (!seeds.length) return [];
774
-
775
- const rows: Row[] = [];
776
- for (let i = 0; i < seeds.length; i++) {
777
- const seed = seeds[i]!;
778
- emit({
779
- type: "stage",
780
- stage: "generating",
781
- progress: 0.05 + 0.9 * (i / Math.max(seeds.length, 1)),
782
- message: `seed ${i + 1}/${seeds.length} (${turns} turns)`,
783
- });
784
- const convo: ChatMessage[] = [
785
- { role: "system", content: persona },
786
- { role: "user", content: seed },
787
- ];
788
-
789
- for (let t = 0; t < turns; t++) {
790
- const isUserTurn = t % 2 === 1;
791
- if (isUserTurn) {
792
- const followupPrompt =
793
- "Continue the conversation below by writing ONLY the next " +
794
- "user-turn message in character as " +
795
- userPersona +
796
- ". " +
797
- "Keep it short (one or two sentences), grounded in what " +
798
- "the assistant just said. Do not write the assistant's " +
799
- "next reply.\n\n" +
800
- formatConvoForFollowup(convo);
801
- const followup = (
802
- await client.chat([{ role: "user", content: followupPrompt }], { maxTokens: 160 })
803
- ).trim();
804
- if (!followup) break;
805
- convo.push({ role: "user", content: followup });
806
- } else {
807
- const reply = (await client.chat(convo, { maxTokens: 512 })).trim();
808
- if (!reply) break;
809
- convo.push({ role: "assistant", content: reply });
810
- }
811
- }
812
- rows.push({ messages: convo });
813
- }
814
- return rows;
815
- }
816
-
817
- export async function genToolUseTraces(
818
- inputs: Inputs,
819
- emit: Emit,
820
- llm?: LlmClient,
821
- ): Promise<Row[]> {
822
- const client = requireLlm(llm, "tool_use_traces");
823
- let tools: unknown[];
824
- try {
825
- const parsed = JSON.parse(str(inputs.tools_json) || "[]");
826
- tools = Array.isArray(parsed) ? parsed : [];
827
- } catch {
828
- tools = [];
829
- }
830
- if (!tools.length) return [];
831
- const scenarios = nonEmptyLines(inputs.scenarios);
832
- const mocks = nonEmptyLines(inputs.mock_results);
833
- if (!scenarios.length || mocks.length !== scenarios.length) return [];
834
-
835
- const rows: Row[] = [];
836
- for (let i = 0; i < scenarios.length; i++) {
837
- const scenario = scenarios[i]!;
838
- const mock = mocks[i]!;
839
- emit({
840
- type: "stage",
841
- stage: "generating",
842
- progress: 0.05 + 0.9 * (i / scenarios.length),
843
- message: `scenario ${i + 1}/${scenarios.length}`,
844
- });
845
-
846
- // Turn 1: model picks a tool (structured tool_calls reply).
847
- const first = await client.chatRaw([{ role: "user", content: scenario }], {
848
- tools,
849
- maxTokens: 512,
850
- });
851
- const firstMsg = first?.choices?.[0]?.message ?? {};
852
- const toolCalls = firstMsg.tool_calls ?? [];
853
- if (!Array.isArray(toolCalls) || !toolCalls.length) continue; // no tool → skip
854
-
855
- const tc = toolCalls[0];
856
- const tcId = tc?.id || `call_${i}`;
857
- const toolName = tc?.function?.name ?? "";
858
-
859
- // Turn 2: feed back the mocked result, ask for the final answer.
860
- const messagesForFinal: ChatMessage[] = [
861
- { role: "user", content: scenario },
862
- { role: "assistant", content: firstMsg.content || "", tool_calls: toolCalls },
863
- { role: "tool", tool_call_id: tcId, name: toolName, content: mock },
864
- ];
865
- const final = (await client.chat(messagesForFinal, { maxTokens: 512 })).trim();
866
- if (!final) continue;
867
-
868
- rows.push({
869
- messages: [
870
- { role: "user", content: scenario },
871
- { role: "assistant", content: firstMsg.content || "", tool_calls: toolCalls },
872
- { role: "tool", tool_call_id: tcId, name: toolName, content: mock },
873
- { role: "assistant", content: final },
874
- ],
875
- tools,
876
- });
877
- }
878
- return rows;
879
- }
880
-
881
- export async function genRagQa(
882
- inputs: Inputs,
883
- emit: Emit,
884
- llm?: LlmClient,
885
- ): Promise<Row[]> {
886
- const client = requireLlm(llm, "rag_qa");
887
- const docs = str(inputs.documents).trim();
888
- const qpc = Math.max(1, num(inputs.questions_per_chunk, 2));
889
- const minChars = Math.max(40, num(inputs.min_chunk_chars, 200));
890
- if (!docs) return [];
891
-
892
- // Split on blank lines, glue tiny fragments together until >= minChars.
893
- const rawChunks = docs
894
- .split(/\n\s*\n/)
895
- .map((c) => c.trim())
896
- .filter((c) => c.length > 0);
897
- const chunks: string[] = [];
898
- let buf = "";
899
- for (const c of rawChunks) {
900
- buf = buf ? `${buf}\n\n${c}`.trim() : c;
901
- if (buf.length >= minChars) {
902
- chunks.push(buf);
903
- buf = "";
904
- }
905
- }
906
- if (buf) {
907
- if (chunks.length) chunks[chunks.length - 1] = `${chunks[chunks.length - 1]}\n\n${buf}`.trim();
908
- else chunks.push(buf);
909
- }
910
-
911
- const rows: Row[] = [];
912
- for (let i = 0; i < chunks.length; i++) {
913
- const chunk = chunks[i]!;
914
- emit({
915
- type: "stage",
916
- stage: "generating",
917
- progress: 0.05 + 0.9 * (i / Math.max(chunks.length, 1)),
918
- message: `chunk ${i + 1}/${chunks.length} (${qpc} questions)`,
919
- });
920
- for (let j = 0; j < qpc; j++) {
921
- const qPrompt =
922
- "Write ONE concise, specific question whose answer is " +
923
- "stated directly in the passage below. Do not answer; only " +
924
- "write the question. Vary it from any other question you " +
925
- "would write for the same passage.\n\n" +
926
- `PASSAGE:\n${chunk}\n\nQUESTION (question number ${j + 1}):`;
927
- const q = (await client.chat([{ role: "user", content: qPrompt }], { maxTokens: 120 })).trim();
928
- if (!q) continue;
929
- const aPrompt =
930
- "Answer the question using ONLY information from the passage. " +
931
- "If the answer is not in the passage, reply exactly: " +
932
- '"The passage does not say." Be concise.\n\n' +
933
- `PASSAGE:\n${chunk}\n\nQUESTION:\n${q}\n\nANSWER:`;
934
- const a = (await client.chat([{ role: "user", content: aPrompt }], { maxTokens: 400 })).trim();
935
- if (!a) continue;
936
- rows.push({
937
- messages: [
938
- { role: "system", content: `Use only the following passage to answer.\n\n${chunk}` },
939
- { role: "user", content: q },
940
- { role: "assistant", content: a },
941
- ],
942
- metadata: { chunk_index: i, passage_chars: chunk.length },
943
- });
944
- }
945
- }
946
- return rows;
947
- }
948
-
949
- export async function genCotSynthesis(
950
- inputs: Inputs,
951
- emit: Emit,
952
- llm?: LlmClient,
953
- ): Promise<Row[]> {
954
- const client = requireLlm(llm, "cot_synthesis");
955
- const qs = nonEmptyLines(inputs.questions);
956
- const category = str(inputs.category).trim() || "general reasoning";
957
- if (!qs.length) return [];
958
-
959
- const rows: Row[] = [];
960
- for (let i = 0; i < qs.length; i++) {
961
- const q = qs[i]!;
962
- emit({
963
- type: "stage",
964
- stage: "generating",
965
- progress: 0.05 + 0.9 * (i / qs.length),
966
- message: `question ${i + 1}/${qs.length}`,
967
- });
968
- const prompt =
969
- `You are solving a ${category} problem. Think step by step in ` +
970
- "a <think>...</think> block first, then write the final answer " +
971
- "after the closing </think> tag. Keep the final answer concise.\n\n" +
972
- `QUESTION:\n${q}\n\nRESPONSE:`;
973
- let out = (await client.chat([{ role: "user", content: prompt }], { maxTokens: 1024 })).trim();
974
- if (!out) continue;
975
- // Normalize: ensure the output has <think>...</think>.
976
- if (!out.includes("<think>")) {
977
- const paras = out.split("\n\n").filter((p) => p.trim());
978
- if (paras.length >= 2) {
979
- const trace = paras.slice(0, -1).join("\n\n");
980
- const ans = paras[paras.length - 1];
981
- out = `<think>\n${trace}\n</think>\n\n${ans}`;
982
- } else {
983
- out = `<think>\n${out}\n</think>\n\n${out}`;
984
- }
985
- }
986
- rows.push({
987
- messages: [
988
- { role: "user", content: q },
989
- { role: "assistant", content: out },
990
- ],
991
- metadata: { category },
992
- });
993
- }
994
- return rows;
995
- }
996
-
997
- /** Pull a ```python ... ``` block out of LLM output, or return whole text. */
998
- export function extractPythonBlock(text: string): string {
999
- const m = text.match(/```(?:python|py)?\n([\s\S]*?)\n```/);
1000
- return m ? m[1]!.trim() : text.trim();
1001
- }
1002
-
1003
- export async function genVerifiedCode(
1004
- inputs: Inputs,
1005
- emit: Emit,
1006
- llm?: LlmClient,
1007
- ): Promise<Row[]> {
1008
- const client = requireLlm(llm, "verified_code");
1009
- const specs = nonEmptyLines(inputs.specs);
1010
- const language = (str(inputs.language).trim() || "python").toLowerCase();
1011
- if (!specs.length) return [];
1012
-
1013
- // Probe for python3 once; if absent, keep rows with verified=false (mirrors
1014
- // optiq keeping unverified rows).
1015
- let havePython = false;
1016
- if (language === "python") {
1017
- try {
1018
- const probe = Bun.spawnSync(["python3", "--version"]);
1019
- havePython = probe.exitCode === 0;
1020
- } catch {
1021
- havePython = false;
1022
- }
1023
- }
1024
-
1025
- const rows: Row[] = [];
1026
- let nVerified = 0;
1027
- let nTotal = 0;
1028
- for (let i = 0; i < specs.length; i++) {
1029
- const spec = specs[i]!;
1030
- emit({
1031
- type: "stage",
1032
- stage: "generating",
1033
- progress: 0.05 + 0.9 * (i / specs.length),
1034
- message: `spec ${i + 1}/${specs.length} (${nVerified}/${nTotal} verified so far)`,
1035
- });
1036
- nTotal++;
1037
- const prompt =
1038
- "Write a Python function that satisfies the spec. Then write " +
1039
- "three `assert` statements at module level that verify the " +
1040
- "function. Output ONLY the code as a single fenced ```python " +
1041
- "block, no commentary.\n\n" +
1042
- `SPEC:\n${spec}\n\nCODE:`;
1043
- const out = await client.chatRaw([{ role: "user", content: prompt }], {
1044
- maxTokens: 1200,
1045
- temperature: 0.2,
1046
- });
1047
- const outText = out?.choices?.[0]?.message?.content ?? "";
1048
- const code = extractPythonBlock(outText);
1049
- if (!code || code.length < 10) continue;
1050
-
1051
- let verified = false;
1052
- let verifyError: string | null = null;
1053
- if (language === "python" && havePython) {
1054
- try {
1055
- const proc = Bun.spawnSync(["python3", "-c", code], {
1056
- stdout: "pipe",
1057
- stderr: "pipe",
1058
- });
1059
- verified = proc.exitCode === 0;
1060
- if (!verified) {
1061
- const stderr = proc.stderr ? new TextDecoder().decode(proc.stderr) : "";
1062
- const stdout = proc.stdout ? new TextDecoder().decode(proc.stdout) : "";
1063
- verifyError = (stderr || stdout || "").slice(0, 400);
1064
- }
1065
- } catch (e) {
1066
- verified = false;
1067
- verifyError = String(e).slice(0, 400);
1068
- }
1069
- }
1070
- if (verified) nVerified++;
1071
-
1072
- rows.push({
1073
- messages: [
1074
- { role: "user", content: spec },
1075
- { role: "assistant", content: `\`\`\`python\n${code}\n\`\`\`` },
1076
- ],
1077
- metadata: { verified, language, verify_error: verifyError },
1078
- });
1079
- }
1080
- emit({
1081
- type: "stage",
1082
- stage: "generating",
1083
- progress: 0.96,
1084
- message: `${nVerified}/${nTotal} specs verified (unverified rows kept with verified=false)`,
1085
- });
1086
- return rows;
1087
- }