mlx-bun 0.4.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 (601) hide show
  1. package/README.md +1453 -88
  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 +10 -8
  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 +12 -10
  78. package/src/{serve → server}/chat-stage.ts +27 -22
  79. package/src/{client.ts → server/client.ts} +28 -2
  80. package/src/{serve → server}/completion-executor.ts +42 -42
  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 +42 -83
  85. package/src/server/generated-token-history.ts +57 -0
  86. package/src/{serve → server}/http.ts +25 -13
  87. package/src/{serve → server}/inference-request.ts +5 -5
  88. package/src/server/job-routes.ts +20 -0
  89. package/src/server/media-prompt.ts +63 -0
  90. package/src/server/memory-completion-client.ts +46 -0
  91. package/src/server/model-routes.ts +192 -0
  92. package/src/{serve → server}/openai-wire.ts +3 -2
  93. package/src/{serve → server}/pipeline.ts +1 -1
  94. package/src/server/prompt-builder.ts +13 -0
  95. package/src/server/prompt-contracts.ts +17 -0
  96. package/src/server/proxy-routes.ts +187 -0
  97. package/src/server/publishing-routes.ts +41 -0
  98. package/src/{serve → server}/request-plan.ts +8 -8
  99. package/src/{serve → server}/request-prep.ts +82 -68
  100. package/src/{serve → server}/responses-client.ts +30 -13
  101. package/src/{responses.ts → server/responses.ts} +12 -93
  102. package/src/server/routes.ts +205 -0
  103. package/src/server/start.ts +72 -0
  104. package/src/server/status-routes.ts +108 -0
  105. package/src/{serve → server}/text-completion-stage.ts +25 -4
  106. package/src/server/text-prompt.ts +12 -0
  107. package/src/{serve → server}/token-streams.ts +36 -38
  108. package/src/server/worker-routes.ts +311 -0
  109. package/src/storage/paths.ts +61 -0
  110. package/src/web/assets.ts +37 -0
  111. package/src/web/{src → browser}/api.ts +5 -23
  112. package/src/web/browser/chat-host.ts +17 -0
  113. package/src/web/browser/installed-panels.ts +6 -0
  114. package/src/web/browser/main.ts +55 -0
  115. package/src/web/browser/markdown.ts +279 -0
  116. package/src/web/browser/memory-panel.ts +9 -0
  117. package/src/web/browser/palette.ts +64 -0
  118. package/src/web/browser/protocol.ts +13 -0
  119. package/src/web/browser/shell.ts +467 -0
  120. package/src/web/{src → browser}/status.ts +32 -36
  121. package/src/web/build.ts +51 -0
  122. package/src/web/public/app.html +1054 -0
  123. package/src/web/{sw.js → public/sw.js} +4 -3
  124. package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
  125. package/src/web/{vendor → public/vendor}/hljs.js +2 -2
  126. package/THIRD_PARTY_LICENSES.md +0 -51
  127. package/docs/README.md +0 -94
  128. package/docs/archive/hlg-sampling.md +0 -350
  129. package/docs/archive/investigations/audio-input-plan.md +0 -356
  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/web-ui-pass-plan.md +0 -213
  174. package/docs/archive/planning/website-readme-pass-plan.md +0 -224
  175. package/docs/design/batching.md +0 -1841
  176. package/docs/design/decode-speed-program.md +0 -2349
  177. package/docs/design/dreaming-nightly-pipeline.md +0 -684
  178. package/docs/design/generic-model-support.md +0 -705
  179. package/docs/design/kv-cache.md +0 -824
  180. package/docs/design/orpo-training.md +0 -680
  181. package/docs/design/speculative-decoding.md +0 -1990
  182. package/docs/design/turboquant.md +0 -2212
  183. package/docs/design/unified-engine-frontier-plan.md +0 -1880
  184. package/docs/design/web-chat-redesign.md +0 -695
  185. package/docs/planning/PRODUCT_ROADMAP.md +0 -594
  186. package/docs/planning/ResearchTopics.md +0 -119
  187. package/docs/planning/release-notes-v0.4.0.md +0 -45
  188. package/docs/planning/video-series.md +0 -421
  189. package/docs/reference/benchmarks.md +0 -3613
  190. package/docs/reference/cli.md +0 -585
  191. package/docs/reference/distribution.md +0 -355
  192. package/docs/reference/environment.md +0 -398
  193. package/docs/reference/glossary.md +0 -39
  194. package/docs/reference/library-api.md +0 -674
  195. package/docs/reference/memory.md +0 -260
  196. package/docs/reference/models.md +0 -334
  197. package/docs/reference/server-api.md +0 -1775
  198. package/docs/reference/server-config.md +0 -846
  199. package/docs/reference/training.md +0 -462
  200. package/docs/reference/troubleshooting.md +0 -158
  201. package/src/admission-plan.ts +0 -18
  202. package/src/audio/conformer.ts +0 -647
  203. package/src/audio/decode.ts +0 -133
  204. package/src/audio/features.ts +0 -202
  205. package/src/audio/transcode.ts +0 -67
  206. package/src/backends/mlx/assistant-target.ts +0 -46
  207. package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
  208. package/src/backends/mlx/autoregressive.ts +0 -108
  209. package/src/backends/mlx/batch-group.ts +0 -1790
  210. package/src/backends/mlx/cache-attachment.ts +0 -67
  211. package/src/backends/mlx/cache-layout.ts +0 -31
  212. package/src/backends/mlx/checkpoint-state.ts +0 -53
  213. package/src/backends/mlx/continuation-persistence.ts +0 -106
  214. package/src/backends/mlx/continuation-request.ts +0 -43
  215. package/src/backends/mlx/continuation.ts +0 -77
  216. package/src/backends/mlx/diffusion.ts +0 -39
  217. package/src/backends/mlx/draft-target.ts +0 -32
  218. package/src/backends/mlx/evaluation.ts +0 -105
  219. package/src/backends/mlx/fill-append.ts +0 -45
  220. package/src/backends/mlx/full-kv-row-append.ts +0 -32
  221. package/src/backends/mlx/full-kv-row-donor.ts +0 -54
  222. package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
  223. package/src/backends/mlx/gateway-binding.ts +0 -130
  224. package/src/backends/mlx/graph.ts +0 -38
  225. package/src/backends/mlx/kv-codec.ts +0 -9
  226. package/src/backends/mlx/kv-maintenance.ts +0 -133
  227. package/src/backends/mlx/kv-tensor-rows.ts +0 -212
  228. package/src/backends/mlx/memory-client.ts +0 -189
  229. package/src/backends/mlx/methods.ts +0 -90
  230. package/src/backends/mlx/model-prompt.ts +0 -164
  231. package/src/backends/mlx/model-serving.ts +0 -79
  232. package/src/backends/mlx/prefill-cohort.ts +0 -89
  233. package/src/backends/mlx/prefill-rows.ts +0 -200
  234. package/src/backends/mlx/prefill.ts +0 -33
  235. package/src/backends/mlx/projected-context-rows.ts +0 -72
  236. package/src/backends/mlx/request-policy.ts +0 -20
  237. package/src/backends/mlx/request-state-policy.ts +0 -41
  238. package/src/backends/mlx/rollback.ts +0 -89
  239. package/src/backends/mlx/row-sampling.ts +0 -49
  240. package/src/backends/mlx/serial-executor.ts +0 -242
  241. package/src/backends/mlx/speculative-group.ts +0 -359
  242. package/src/backends/mlx/speculative-round.ts +0 -161
  243. package/src/backends/mlx/speculative.ts +0 -114
  244. package/src/backends/mlx/state-rows.ts +0 -104
  245. package/src/backends/mlx/state-views.ts +0 -46
  246. package/src/backends/mlx/target-layout-capability.ts +0 -35
  247. package/src/backends/mlx/text-engine.ts +0 -73
  248. package/src/backends/mlx/transitioning-kv-rows.ts +0 -165
  249. package/src/chat-template.ts +0 -382
  250. package/src/cli.ts +0 -3168
  251. package/src/config.ts +0 -399
  252. package/src/contracts/completion.ts +0 -16
  253. package/src/contracts/execution.ts +0 -60
  254. package/src/contracts/generation.ts +0 -103
  255. package/src/contracts/host.ts +0 -7
  256. package/src/contracts/pi-provider.ts +0 -30
  257. package/src/contracts/pi.ts +0 -259
  258. package/src/contracts/prefix-cache.ts +0 -23
  259. package/src/contracts/resources.ts +0 -25
  260. package/src/contracts/sampling.ts +0 -23
  261. package/src/contracts/scheduling.ts +0 -45
  262. package/src/contracts/tsconfig.json +0 -14
  263. package/src/dataset/generators.ts +0 -1087
  264. package/src/dataset/index.ts +0 -12
  265. package/src/dataset/job.ts +0 -81
  266. package/src/dataset/llm.ts +0 -71
  267. package/src/dataset/registry.ts +0 -528
  268. package/src/diffusion/diffusion-generate.ts +0 -507
  269. package/src/download.ts +0 -505
  270. package/src/embed.ts +0 -77
  271. package/src/engine/admission.ts +0 -59
  272. package/src/engine/cancellation.ts +0 -38
  273. package/src/engine/engine.ts +0 -56
  274. package/src/engine/execution-coordinator.ts +0 -70
  275. package/src/engine/execution-plan.ts +0 -53
  276. package/src/engine/resources.ts +0 -53
  277. package/src/engine/scheduler.ts +0 -72
  278. package/src/engine/session.ts +0 -247
  279. package/src/eval/README.md +0 -130
  280. package/src/eval/ifeval.ts +0 -81
  281. package/src/eval/kl-prompts.ts +0 -29
  282. package/src/eval/kl.ts +0 -590
  283. package/src/eval/perplexity.ts +0 -164
  284. package/src/eval/quality-db.ts +0 -92
  285. package/src/eval/reference-logits.ts +0 -207
  286. package/src/eval/runner.ts +0 -124
  287. package/src/eval/score.ts +0 -49
  288. package/src/eval/tasks/bfcl.ts +0 -535
  289. package/src/eval/tasks/gsm8k.ts +0 -98
  290. package/src/eval/tasks/hashhop.ts +0 -139
  291. package/src/eval/tasks/humaneval.ts +0 -275
  292. package/src/eval/tasks/ifeval.ts +0 -525
  293. package/src/eval/tasks/mmlu.ts +0 -157
  294. package/src/eval/ultrafeedback.ts +0 -60
  295. package/src/evaldb.ts +0 -199
  296. package/src/expert-io.ts +0 -393
  297. package/src/expert-offload-build.ts +0 -77
  298. package/src/expert-offload.ts +0 -76
  299. package/src/expert-residency.ts +0 -1134
  300. package/src/expert-usage.ts +0 -415
  301. package/src/fill/echo-index.ts +0 -188
  302. package/src/fill/fill-session.ts +0 -452
  303. package/src/fill/proposal.ts +0 -68
  304. package/src/fill/schema-rows.ts +0 -506
  305. package/src/fill/tool-boundary.ts +0 -103
  306. package/src/fit.ts +0 -249
  307. package/src/generate.ts +0 -1346
  308. package/src/grammar.ts +0 -591
  309. package/src/harness-pi.ts +0 -184
  310. package/src/hf-push.ts +0 -628
  311. package/src/hub-rest.ts +0 -242
  312. package/src/index.ts +0 -63
  313. package/src/inference/denoising.ts +0 -17
  314. package/src/inference/draft-acceptance.ts +0 -41
  315. package/src/inference/draft-output.ts +0 -49
  316. package/src/inference/graph.ts +0 -33
  317. package/src/inference/prefill.ts +0 -39
  318. package/src/inference/rollback.ts +0 -7
  319. package/src/jobs/index.ts +0 -31
  320. package/src/jobs/job-entry.ts +0 -107
  321. package/src/jobs/task-client.ts +0 -19
  322. package/src/jobs/types.ts +0 -2
  323. package/src/kv-scheme.ts +0 -257
  324. package/src/kv-store.ts +0 -1099
  325. package/src/lab/README.md +0 -18
  326. package/src/lab/curve/curve-designer.html +0 -303
  327. package/src/lab/curve/curve-sampler.ts +0 -122
  328. package/src/lab/expert-trace/expert-trace.ts +0 -69
  329. package/src/lab/paged-kv/paged-kv-rows.ts +0 -83
  330. package/src/lab/paged-kv/paged-kv.ts +0 -270
  331. package/src/library.ts +0 -40
  332. package/src/lora.ts +0 -408
  333. package/src/md-modules.d.ts +0 -49
  334. package/src/media-fetch.ts +0 -442
  335. package/src/memory/article.ts +0 -558
  336. package/src/memory/chunk-validation.ts +0 -150
  337. package/src/memory/chunk.ts +0 -318
  338. package/src/memory/cluster.ts +0 -351
  339. package/src/memory/coverage.ts +0 -134
  340. package/src/memory/crosslink.ts +0 -0
  341. package/src/memory/db.ts +0 -253
  342. package/src/memory/entity.ts +0 -203
  343. package/src/memory/gate.ts +0 -187
  344. package/src/memory/history.ts +0 -152
  345. package/src/memory/ingest.ts +0 -335
  346. package/src/memory/model.ts +0 -183
  347. package/src/memory/normalize.ts +0 -671
  348. package/src/memory/parse.ts +0 -22
  349. package/src/memory/pipeline.ts +0 -275
  350. package/src/memory/prompts.ts +0 -65
  351. package/src/memory/query.ts +0 -334
  352. package/src/memory/reconcile.ts +0 -734
  353. package/src/memory/redirect.ts +0 -108
  354. package/src/memory/reindex.ts +0 -325
  355. package/src/memory/resolve.ts +0 -307
  356. package/src/memory/rest.ts +0 -245
  357. package/src/memory/route.ts +0 -272
  358. package/src/memory/schedule.ts +0 -165
  359. package/src/memory/stages.ts +0 -777
  360. package/src/memory/synthesize.ts +0 -1638
  361. package/src/memory/tools.ts +0 -749
  362. package/src/memory/vault.ts +0 -1194
  363. package/src/memory/wikify.ts +0 -1064
  364. package/src/mlx/array.ts +0 -388
  365. package/src/mlx/autograd.ts +0 -304
  366. package/src/mlx/checkpoint.ts +0 -149
  367. package/src/mlx/compile.ts +0 -168
  368. package/src/mlx/custom-vjp.ts +0 -188
  369. package/src/mlx/ffi.ts +0 -512
  370. package/src/mlx/materialize.ts +0 -23
  371. package/src/mlx/metal-kernel.ts +0 -159
  372. package/src/mlx/ops.ts +0 -1021
  373. package/src/mlx/quantized-rows.ts +0 -36
  374. package/src/mlx/token-bitmask.ts +0 -52
  375. package/src/mlx/turboquant-kv-decode.ts +0 -82
  376. package/src/mlx/turboquant-kv-inverse.ts +0 -122
  377. package/src/mlx/turboquant-ops.ts +0 -861
  378. package/src/mlx/turboquant-tables.ts +0 -237
  379. package/src/mmap.ts +0 -90
  380. package/src/model/artifact-identity.ts +0 -73
  381. package/src/model/batched-kv.ts +0 -235
  382. package/src/model/batched-mask.ts +0 -279
  383. package/src/model/batched-quant.ts +0 -212
  384. package/src/model/batched-quantized-kv.ts +0 -144
  385. package/src/model/batched-rotating-quant.ts +0 -353
  386. package/src/model/batched-rotating-state.ts +0 -149
  387. package/src/model/batched-rotating.ts +0 -338
  388. package/src/model/batched-row-storage.ts +0 -179
  389. package/src/model/batched-ssm.ts +0 -52
  390. package/src/model/batched-turboquant-kv.ts +0 -93
  391. package/src/model/compiled-decode.ts +0 -712
  392. package/src/model/decoded-kv-donor.ts +0 -12
  393. package/src/model/delayed-quantized-kv.ts +0 -72
  394. package/src/model/delayed-rotating-quantized-kv.ts +0 -93
  395. package/src/model/delayed-turboquant-kv.ts +0 -55
  396. package/src/model/diffusion-gemma.ts +0 -1026
  397. package/src/model/factory.ts +0 -189
  398. package/src/model/fingerprint.ts +0 -33
  399. package/src/model/flash-attention.ts +0 -694
  400. package/src/model/full-prefill-padding.ts +0 -56
  401. package/src/model/full-prefill-row.ts +0 -105
  402. package/src/model/gemma4-base.ts +0 -2351
  403. package/src/model/gemma4.ts +0 -1315
  404. package/src/model/generated/gemma4-12b.ts +0 -429
  405. package/src/model/generated/gemma4-26b.ts +0 -448
  406. package/src/model/generated/gemma4-e4b.ts +0 -717
  407. package/src/model/generated/index.ts +0 -18
  408. package/src/model/glm52-atlas.ts +0 -511
  409. package/src/model/glm52-cache.ts +0 -792
  410. package/src/model/glm52-config.ts +0 -262
  411. package/src/model/glm52-container.ts +0 -305
  412. package/src/model/glm52-coupling.ts +0 -388
  413. package/src/model/glm52-dsa.ts +0 -606
  414. package/src/model/glm52-expert-layout.ts +0 -253
  415. package/src/model/glm52-layout.ts +0 -152
  416. package/src/model/glm52-memory.ts +0 -500
  417. package/src/model/glm52-mla.ts +0 -792
  418. package/src/model/glm52-moe.ts +0 -223
  419. package/src/model/glm52-pilot.ts +0 -537
  420. package/src/model/glm52-reference.ts +0 -445
  421. package/src/model/glm52-residency.ts +0 -557
  422. package/src/model/glm52-resident-weights.ts +0 -135
  423. package/src/model/glm52-streamed-experts.ts +0 -453
  424. package/src/model/glm52-streamed-metal.ts +0 -610
  425. package/src/model/glm52-weights.ts +0 -503
  426. package/src/model/glm52.ts +0 -1132
  427. package/src/model/implementation.ts +0 -69
  428. package/src/model/kv-attention-view.ts +0 -67
  429. package/src/model/minicpm5.ts +0 -376
  430. package/src/model/profile.ts +0 -443
  431. package/src/model/qwen-append.ts +0 -12
  432. package/src/model/qwen-conv.ts +0 -52
  433. package/src/model/qwen3-delta-state.ts +0 -74
  434. package/src/model/qwen3-delta.ts +0 -451
  435. package/src/model/qwen3-moe.ts +0 -404
  436. package/src/model/qwen3-mrope.ts +0 -252
  437. package/src/model/qwen3.ts +0 -277
  438. package/src/model/qwen3_5-checkpoint.ts +0 -164
  439. package/src/model/qwen3_5.ts +0 -819
  440. package/src/model/rotating-kv-donor.ts +0 -35
  441. package/src/model/rotating-kv-layout.ts +0 -262
  442. package/src/model/rotating-row-transaction.ts +0 -35
  443. package/src/model/speculative-rotating-kv.ts +0 -101
  444. package/src/model/ssm-prefill-padding.ts +0 -39
  445. package/src/model/support.ts +0 -102
  446. package/src/model/trellis-balanced-scatter.ts +0 -51
  447. package/src/model/trellis-linear.ts +0 -672
  448. package/src/model/trellis-shared-m.ts +0 -151
  449. package/src/model/trellis-shared-scatter.ts +0 -144
  450. package/src/model/trellis-splitk-prefill.ts +0 -158
  451. package/src/model/trellis-tiled-prefill.ts +0 -136
  452. package/src/model/trellis-vector-expand.ts +0 -62
  453. package/src/model/trellis-wide-prefill.ts +0 -94
  454. package/src/model/turboquant-codec.ts +0 -83
  455. package/src/model/universal/archs.ts +0 -332
  456. package/src/model/universal/dense.ts +0 -612
  457. package/src/model/universal/modules.ts +0 -170
  458. package/src/model/universal/rope.ts +0 -381
  459. package/src/native/expert_io.c +0 -523
  460. package/src/native/frame_extract.swift +0 -140
  461. package/src/native-pack.ts +0 -162
  462. package/src/pi-provider.ts +0 -53
  463. package/src/pi-session.ts +0 -81
  464. package/src/pi-terminal.ts +0 -274
  465. package/src/pi-web.ts +0 -1932
  466. package/src/preflight.ts +0 -158
  467. package/src/prompt-cache.ts +0 -460
  468. package/src/quantize/allocator.ts +0 -627
  469. package/src/quantize/atomic-output.ts +0 -38
  470. package/src/quantize/calibration.ts +0 -181
  471. package/src/quantize/config-writer.ts +0 -145
  472. package/src/quantize/index.ts +0 -84
  473. package/src/quantize/job.ts +0 -162
  474. package/src/quantize/quantizer.ts +0 -666
  475. package/src/quantize/rotate.ts +0 -603
  476. package/src/quantize/safetensors-writer.ts +0 -249
  477. package/src/quantize/sensitivity.ts +0 -216
  478. package/src/quantize/trellis.ts +0 -586
  479. package/src/quantize/weight-transform.ts +0 -292
  480. package/src/registry.ts +0 -602
  481. package/src/runtime-config.ts +0 -81
  482. package/src/safetensors.ts +0 -158
  483. package/src/sampler.ts +0 -1011
  484. package/src/serve/admin-routes.ts +0 -184
  485. package/src/serve/assets/curve-terrain.html +0 -105
  486. package/src/serve/assets/training-inference-map.html +0 -575
  487. package/src/serve/aux-routes.ts +0 -132
  488. package/src/serve/batch-scheduler.ts +0 -8
  489. package/src/serve/checkpoint-identity.ts +0 -64
  490. package/src/serve/generation-gateway.ts +0 -496
  491. package/src/serve/isolate.ts +0 -609
  492. package/src/serve/kv-budget.ts +0 -14
  493. package/src/serve/lab-routes.ts +0 -341
  494. package/src/serve/lane-registry.ts +0 -45
  495. package/src/serve/model-admin-routes.ts +0 -155
  496. package/src/serve/model-binding.ts +0 -43
  497. package/src/serve/model-host.ts +0 -511
  498. package/src/serve/parent-application.ts +0 -56
  499. package/src/serve/prompt-response-trace.ts +0 -147
  500. package/src/serve/response-lease.ts +0 -24
  501. package/src/serve/session-search.ts +0 -326
  502. package/src/serve/static-routes.ts +0 -101
  503. package/src/server.ts +0 -1314
  504. package/src/spec/assistant-rows.ts +0 -92
  505. package/src/spec/assistant-source.ts +0 -126
  506. package/src/spec/cache-identity.ts +0 -22
  507. package/src/spec/deepspec-rows.ts +0 -29
  508. package/src/spec/deepspec-source.ts +0 -145
  509. package/src/spec/dflash-source.ts +0 -149
  510. package/src/spec/drafter.ts +0 -304
  511. package/src/spec/dspark/ab-stats.ts +0 -136
  512. package/src/spec/dspark/calibration.ts +0 -112
  513. package/src/spec/dspark/data-dflash.ts +0 -156
  514. package/src/spec/dspark/data.ts +0 -201
  515. package/src/spec/dspark/deepspec-module.ts +0 -776
  516. package/src/spec/dspark/generate-dflash.ts +0 -245
  517. package/src/spec/dspark/generate.ts +0 -290
  518. package/src/spec/dspark/loader.ts +0 -23
  519. package/src/spec/dspark/loss.ts +0 -213
  520. package/src/spec/dspark/module-dflash.ts +0 -560
  521. package/src/spec/dspark/module.ts +0 -540
  522. package/src/spec/dspark/quantize-drafter.ts +0 -91
  523. package/src/spec/dspark/sample.ts +0 -112
  524. package/src/spec/generate.ts +0 -276
  525. package/src/spec/glm52-mtp-graph.ts +0 -29
  526. package/src/spec/glm52-mtp-rows.ts +0 -132
  527. package/src/spec/glm52-mtp-source.ts +0 -317
  528. package/src/spec/glm52-mtp-state.ts +0 -33
  529. package/src/spec/ngram-source.ts +0 -204
  530. package/src/spec/projected-draft-rows.ts +0 -73
  531. package/src/spec/qwen-mtp-module.ts +0 -171
  532. package/src/spec/qwen-mtp-rows.ts +0 -219
  533. package/src/spec/qwen-mtp-source.ts +0 -383
  534. package/src/spec/qwen-mtp-state.ts +0 -30
  535. package/src/spec/serve-loop.ts +0 -585
  536. package/src/spec/source.ts +0 -215
  537. package/src/spec/two-model-rows.ts +0 -61
  538. package/src/spec/two-model.ts +0 -113
  539. package/src/ssd-cache.ts +0 -372
  540. package/src/ssd-durability.ts +0 -211
  541. package/src/tokenizer.ts +0 -335
  542. package/src/tool-approvals.ts +0 -131
  543. package/src/tool-call.ts +0 -695
  544. package/src/train/dataset.ts +0 -484
  545. package/src/train/diffusion-lora.ts +0 -216
  546. package/src/train/export.ts +0 -32
  547. package/src/train/flash-cce.ts +0 -1234
  548. package/src/train/forward.ts +0 -266
  549. package/src/train/fuse.ts +0 -243
  550. package/src/train/index.ts +0 -46
  551. package/src/train/job.ts +0 -205
  552. package/src/train/lora-params.ts +0 -254
  553. package/src/train/loss.ts +0 -1591
  554. package/src/train/merge.ts +0 -195
  555. package/src/train/optimizer.ts +0 -183
  556. package/src/train/prefix-shared.ts +0 -490
  557. package/src/train/rank.ts +0 -137
  558. package/src/train/segmented.ts +0 -1828
  559. package/src/train/steel-qmm-header.ts +0 -1461
  560. package/src/train/trainer.ts +0 -1221
  561. package/src/train/watch.ts +0 -542
  562. package/src/vision/diffusion-vision.ts +0 -620
  563. package/src/vision/embedder.ts +0 -168
  564. package/src/vision/preprocess.ts +0 -247
  565. package/src/vision/prompt.ts +0 -373
  566. package/src/vision/qwen3vl-preprocess.ts +0 -409
  567. package/src/vision/qwen3vl-prompt.ts +0 -196
  568. package/src/vision/qwen3vl-tower.ts +0 -555
  569. package/src/vision/siglip.ts +0 -599
  570. package/src/vision/video-frames.ts +0 -148
  571. package/src/web/app.html +0 -2143
  572. package/src/web/app.js +0 -5703
  573. package/src/web/skills/memory/SKILL.md +0 -120
  574. package/src/web/skills/web-research/SKILL.md +0 -46
  575. package/src/web/skills.ts +0 -97
  576. package/src/web/src/adapters-panel.ts +0 -288
  577. package/src/web/src/assistant.ts +0 -451
  578. package/src/web/src/chat.ts +0 -1057
  579. package/src/web/src/composer.ts +0 -959
  580. package/src/web/src/dataset.ts +0 -132
  581. package/src/web/src/finetune.ts +0 -267
  582. package/src/web/src/hub.ts +0 -428
  583. package/src/web/src/main.ts +0 -98
  584. package/src/web/src/markdown.ts +0 -0
  585. package/src/web/src/memory-panel.ts +0 -572
  586. package/src/web/src/model-picker.ts +0 -159
  587. package/src/web/src/palette.ts +0 -346
  588. package/src/web/src/protocol.ts +0 -26
  589. package/src/web/src/quantize.ts +0 -167
  590. package/src/web/src/rag.ts +0 -274
  591. package/src/web/src/sessions.ts +0 -469
  592. package/src/web/src/shell.ts +0 -804
  593. package/src/web/src/ui-catalog.ts +0 -78
  594. package/src/web/vendor/README.md +0 -61
  595. package/src/web-assets.ts +0 -47
  596. package/src/web-tools.ts +0 -478
  597. package/src/weights.ts +0 -255
  598. /package/src/{serve → server}/completion-sink.ts +0 -0
  599. /package/src/web/{icon.svg → public/icon.svg} +0 -0
  600. /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
  601. /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
- }