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.
- package/README.md +1449 -109
- package/THIRD_PARTY_NOTICES.md +882 -0
- package/bin/mlx-bun.convert.mjs +4 -0
- package/bin/mlx-bun.fuse.mjs +4 -0
- package/bin/mlx-bun.generate.mjs +4 -0
- package/bin/mlx-bun.lora.mjs +4 -0
- package/bin/mlx-bun.mjs +13 -21
- package/bin/mlx-bun.server.mjs +4 -0
- package/bin/mlx-bun.upload.mjs +4 -0
- package/dist/web/app.js +9584 -0
- package/package.json +50 -53
- package/src/cli/ane-install.ts +76 -0
- package/src/cli/args.ts +179 -0
- package/src/cli/engine-entry.ts +68 -0
- package/src/cli/inference.ts +214 -0
- package/src/cli/job-entry.ts +97 -0
- package/src/cli/library-host.ts +117 -0
- package/src/cli/main.ts +57 -0
- package/src/cli/memory-engine.ts +163 -0
- package/src/cli/memory.ts +36 -0
- package/src/cli/mlx-lm-aliases.ts +309 -0
- package/src/cli/model-choice.ts +33 -0
- package/src/cli/model-selection.ts +84 -0
- package/src/cli/module-host.ts +11 -0
- package/src/cli/module-verbs.ts +50 -0
- package/src/cli/numerical-policy.ts +12 -0
- package/src/cli/perplexity.ts +89 -0
- package/src/cli/serve-host.ts +423 -0
- package/src/cli/serve-isolated.ts +217 -0
- package/src/cli/serve-options.ts +106 -0
- package/src/cli/serve-state.ts +205 -0
- package/src/cli/serve.ts +500 -0
- package/src/cli/served-model-host.ts +102 -0
- package/src/cli/server-entry.ts +148 -0
- package/src/cli/serving-unit.ts +177 -0
- package/src/{tui.ts → cli/terminal.ts} +13 -8
- package/src/cli/worker-adapters.ts +34 -0
- package/src/cli/worker-entry.ts +272 -0
- package/src/cli/worker-unit.ts +179 -0
- package/src/engine/adapter-operation.ts +26 -0
- package/src/engine/cache-services.ts +114 -0
- package/src/engine/completion.ts +39 -0
- package/src/engine/generation-gateway.ts +358 -0
- package/src/engine/index.ts +59 -0
- package/src/engine/kv-budget.ts +120 -0
- package/src/engine/media-preparation.ts +232 -0
- package/src/engine/model-binding.ts +24 -0
- package/src/engine/model-host.ts +513 -0
- package/src/engine/model-serving.ts +89 -0
- package/src/{serve → engine}/preparation.ts +7 -5
- package/src/{serve → engine}/session-completion-engine.ts +6 -6
- package/src/engine/telemetry.ts +109 -0
- package/src/hub/downloads.ts +116 -0
- package/src/jobs/db.ts +16 -7
- package/src/jobs/events.ts +29 -0
- package/src/jobs/executable.ts +5 -0
- package/src/jobs/host.ts +51 -0
- package/src/jobs/in-process.ts +55 -0
- package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
- package/src/jobs/runner.ts +150 -231
- package/src/jobs/service.ts +75 -0
- package/src/jobs/sse.ts +59 -23
- package/src/jobs/worker-memory.ts +46 -0
- package/src/jobs/worker-process.ts +163 -0
- package/src/jobs/worker-supervisor.ts +258 -0
- package/src/modules.ts +58 -0
- package/src/publishing/catalog-hub.ts +18 -0
- package/src/publishing/credentials.ts +31 -0
- package/src/publishing/upload.ts +37 -0
- package/src/residency/leased-adapters.ts +21 -0
- package/src/residency/local-records.ts +16 -0
- package/src/residency/model-residency.ts +405 -0
- package/src/residency/record-index.ts +28 -0
- package/src/residency/resident-estimate.ts +50 -0
- package/src/{anthropic.ts → server/anthropic.ts} +3 -81
- package/src/server/cache-routes.ts +36 -0
- package/src/{serve → server}/chat-request.ts +10 -10
- package/src/{serve → server}/chat-stage.ts +14 -14
- package/src/{client.ts → server/client.ts} +28 -2
- package/src/{serve → server}/completion-executor.ts +33 -41
- package/src/server/decision-body.ts +55 -0
- package/src/server/decision-routes.ts +134 -0
- package/src/server/decision-wire.ts +228 -0
- package/src/{serve → server}/discovery-routes.ts +25 -82
- package/src/{serve → server}/http.ts +25 -13
- package/src/{serve → server}/inference-request.ts +5 -5
- package/src/server/job-routes.ts +20 -0
- package/src/server/media-prompt.ts +63 -0
- package/src/server/memory-completion-client.ts +46 -0
- package/src/server/model-routes.ts +192 -0
- package/src/{serve → server}/openai-wire.ts +3 -2
- package/src/{serve → server}/pipeline.ts +1 -1
- package/src/server/prompt-builder.ts +13 -0
- package/src/server/prompt-contracts.ts +17 -0
- package/src/server/proxy-routes.ts +187 -0
- package/src/server/publishing-routes.ts +41 -0
- package/src/{serve → server}/request-plan.ts +6 -8
- package/src/{serve → server}/request-prep.ts +47 -50
- package/src/{serve → server}/responses-client.ts +30 -13
- package/src/{responses.ts → server/responses.ts} +12 -93
- package/src/server/routes.ts +205 -0
- package/src/server/start.ts +72 -0
- package/src/server/status-routes.ts +108 -0
- package/src/{serve → server}/text-completion-stage.ts +25 -4
- package/src/server/text-prompt.ts +12 -0
- package/src/{serve → server}/token-streams.ts +36 -38
- package/src/server/worker-routes.ts +311 -0
- package/src/storage/paths.ts +61 -0
- package/src/web/assets.ts +37 -0
- package/src/web/{src → browser}/api.ts +5 -23
- package/src/web/browser/chat-host.ts +17 -0
- package/src/web/browser/installed-panels.ts +6 -0
- package/src/web/browser/main.ts +55 -0
- package/src/web/browser/markdown.ts +279 -0
- package/src/web/browser/memory-panel.ts +9 -0
- package/src/web/browser/palette.ts +64 -0
- package/src/web/browser/protocol.ts +13 -0
- package/src/web/browser/shell.ts +467 -0
- package/src/web/{src → browser}/status.ts +32 -36
- package/src/web/build.ts +51 -0
- package/src/web/public/app.html +1054 -0
- package/src/web/{sw.js → public/sw.js} +4 -3
- package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
- package/src/web/{vendor → public/vendor}/hljs.js +2 -2
- package/THIRD_PARTY_LICENSES.md +0 -51
- package/docs/README.md +0 -107
- package/docs/archive/hlg-sampling.md +0 -350
- package/docs/archive/investigations/audio-input-plan.md +0 -356
- package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
- package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
- package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
- package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
- package/docs/archive/investigations/curve-bisector-routing.md +0 -123
- package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
- package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
- package/docs/archive/investigations/dspark-handoff.md +0 -224
- package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
- package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
- package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
- package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
- package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
- package/docs/archive/investigations/lab-build-journal.md +0 -157
- package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
- package/docs/archive/investigations/openjarvis-fit.md +0 -198
- package/docs/archive/investigations/openwiki-evaluation.md +0 -249
- package/docs/archive/investigations/optimization_plan.md +0 -346
- package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
- package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
- package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
- package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
- package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
- package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
- package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
- package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
- package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
- package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
- package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
- package/docs/archive/planning/chat-ui-vision.md +0 -50
- package/docs/archive/planning/chunk-task-roadmap.md +0 -77
- package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
- package/docs/archive/planning/journal.md +0 -316
- package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
- package/docs/archive/planning/pi-integration-review.md +0 -178
- package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
- package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
- package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
- package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
- package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
- package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
- package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
- package/docs/archive/planning/release-notes-v0.4.0.md +0 -45
- package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
- package/docs/archive/planning/web-ui-pass-plan.md +0 -213
- package/docs/archive/planning/website-readme-pass-plan.md +0 -224
- package/docs/design/batching.md +0 -2054
- package/docs/design/decode-speed-program.md +0 -2404
- package/docs/design/dreaming-nightly-pipeline.md +0 -684
- package/docs/design/generic-model-support.md +0 -821
- package/docs/design/kv-cache.md +0 -993
- package/docs/design/orpo-training.md +0 -680
- package/docs/design/speculative-decoding.md +0 -2129
- package/docs/design/turboquant.md +0 -2225
- package/docs/design/unified-engine-frontier-plan.md +0 -1987
- package/docs/design/web-chat-redesign.md +0 -695
- package/docs/planning/PRODUCT_ROADMAP.md +0 -593
- package/docs/planning/ResearchTopics.md +0 -119
- package/docs/planning/public-readiness-handoff.md +0 -244
- package/docs/planning/public-readiness.md +0 -149
- package/docs/planning/video-series.md +0 -421
- package/docs/reference/benchmarks.md +0 -3587
- package/docs/reference/cli.md +0 -646
- package/docs/reference/distribution.md +0 -380
- package/docs/reference/environment.md +0 -494
- package/docs/reference/glossary.md +0 -39
- package/docs/reference/library-api.md +0 -688
- package/docs/reference/memory.md +0 -260
- package/docs/reference/models.md +0 -346
- package/docs/reference/server-api.md +0 -1945
- package/docs/reference/server-config.md +0 -973
- package/docs/reference/training.md +0 -462
- package/docs/reference/troubleshooting.md +0 -158
- package/src/admission-plan.ts +0 -18
- package/src/audio/audiotoolbox.ts +0 -112
- package/src/audio/conformer.ts +0 -655
- package/src/audio/decode.ts +0 -133
- package/src/audio/features.ts +0 -202
- package/src/audio/mic-capture.ts +0 -98
- package/src/audio/silero-vad.ts +0 -379
- package/src/audio/transcode.ts +0 -67
- package/src/audio/whisper-decode.ts +0 -774
- package/src/audio/whisper-fast.ts +0 -732
- package/src/audio/whisper-format.ts +0 -73
- package/src/audio/whisper-mel.ts +0 -185
- package/src/audio/whisper-timing.ts +0 -274
- package/src/audio/whisper-tokenizer.ts +0 -239
- package/src/audio/whisper-transcribe.ts +0 -410
- package/src/backends/mlx/assistant-target.ts +0 -46
- package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
- package/src/backends/mlx/autoregressive.ts +0 -129
- package/src/backends/mlx/batch-group.ts +0 -1874
- package/src/backends/mlx/cache-attachment.ts +0 -67
- package/src/backends/mlx/cache-layout.ts +0 -31
- package/src/backends/mlx/checkpoint-state.ts +0 -53
- package/src/backends/mlx/continuation-persistence.ts +0 -107
- package/src/backends/mlx/continuation-request.ts +0 -43
- package/src/backends/mlx/continuation.ts +0 -77
- package/src/backends/mlx/diffusion.ts +0 -39
- package/src/backends/mlx/draft-target.ts +0 -32
- package/src/backends/mlx/encoder-cache.ts +0 -25
- package/src/backends/mlx/evaluation.ts +0 -105
- package/src/backends/mlx/fill-append.ts +0 -58
- package/src/backends/mlx/fill-group.ts +0 -497
- package/src/backends/mlx/full-kv-row-append.ts +0 -32
- package/src/backends/mlx/full-kv-row-donor.ts +0 -54
- package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
- package/src/backends/mlx/gateway-binding.ts +0 -174
- package/src/backends/mlx/graph.ts +0 -38
- package/src/backends/mlx/kv-codec.ts +0 -9
- package/src/backends/mlx/kv-maintenance.ts +0 -161
- package/src/backends/mlx/kv-tensor-rows.ts +0 -212
- package/src/backends/mlx/memory-client.ts +0 -189
- package/src/backends/mlx/methods.ts +0 -90
- package/src/backends/mlx/mixed-iteration.ts +0 -62
- package/src/backends/mlx/model-prompt.ts +0 -178
- package/src/backends/mlx/model-serving.ts +0 -80
- package/src/backends/mlx/paged-cache-codec.ts +0 -27
- package/src/backends/mlx/prefill-cohort.ts +0 -100
- package/src/backends/mlx/prefill-policy.ts +0 -26
- package/src/backends/mlx/prefill-rows.ts +0 -244
- package/src/backends/mlx/prefill.ts +0 -33
- package/src/backends/mlx/projected-context-rows.ts +0 -72
- package/src/backends/mlx/prompt-input.ts +0 -29
- package/src/backends/mlx/qwen-prompt-input.ts +0 -40
- package/src/backends/mlx/request-policy.ts +0 -20
- package/src/backends/mlx/request-state-policy.ts +0 -54
- package/src/backends/mlx/rollback.ts +0 -92
- package/src/backends/mlx/row-sampling.ts +0 -49
- package/src/backends/mlx/serial-executor.ts +0 -251
- package/src/backends/mlx/speculative-group.ts +0 -438
- package/src/backends/mlx/speculative-round.ts +0 -161
- package/src/backends/mlx/speculative.ts +0 -131
- package/src/backends/mlx/state-rows.ts +0 -104
- package/src/backends/mlx/state-views.ts +0 -46
- package/src/backends/mlx/target-layout-capability.ts +0 -35
- package/src/backends/mlx/text-engine.ts +0 -73
- package/src/backends/mlx/transitioning-kv-rows.ts +0 -173
- package/src/chat-template.ts +0 -382
- package/src/cli.ts +0 -3490
- package/src/config.ts +0 -399
- package/src/contracts/completion.ts +0 -16
- package/src/contracts/execution.ts +0 -70
- package/src/contracts/generation.ts +0 -103
- package/src/contracts/host.ts +0 -7
- package/src/contracts/object-cache.ts +0 -8
- package/src/contracts/pi-provider.ts +0 -30
- package/src/contracts/pi.ts +0 -261
- package/src/contracts/prefix-cache.ts +0 -33
- package/src/contracts/resources.ts +0 -25
- package/src/contracts/sampling.ts +0 -23
- package/src/contracts/scheduling.ts +0 -54
- package/src/contracts/tsconfig.json +0 -14
- package/src/dataset/generators.ts +0 -1087
- package/src/dataset/index.ts +0 -12
- package/src/dataset/job.ts +0 -81
- package/src/dataset/llm.ts +0 -71
- package/src/dataset/registry.ts +0 -528
- package/src/diffusion/diffusion-generate.ts +0 -507
- package/src/download.ts +0 -505
- package/src/embed.ts +0 -77
- package/src/engine/admission.ts +0 -59
- package/src/engine/cancellation.ts +0 -38
- package/src/engine/engine.ts +0 -56
- package/src/engine/execution-coordinator.ts +0 -70
- package/src/engine/execution-plan.ts +0 -64
- package/src/engine/execution-tasks.ts +0 -44
- package/src/engine/namespaced-cache.ts +0 -13
- package/src/engine/resources.ts +0 -53
- package/src/engine/scheduler.ts +0 -92
- package/src/engine/session.ts +0 -247
- package/src/eval/README.md +0 -130
- package/src/eval/ifeval.ts +0 -81
- package/src/eval/kl-prompts.ts +0 -29
- package/src/eval/kl.ts +0 -590
- package/src/eval/perplexity.ts +0 -164
- package/src/eval/quality-db.ts +0 -92
- package/src/eval/reference-logits.ts +0 -207
- package/src/eval/runner.ts +0 -124
- package/src/eval/score.ts +0 -49
- package/src/eval/tasks/bfcl.ts +0 -535
- package/src/eval/tasks/gsm8k.ts +0 -98
- package/src/eval/tasks/hashhop.ts +0 -139
- package/src/eval/tasks/humaneval.ts +0 -275
- package/src/eval/tasks/ifeval.ts +0 -525
- package/src/eval/tasks/mmlu.ts +0 -157
- package/src/eval/ultrafeedback.ts +0 -60
- package/src/evaldb.ts +0 -199
- package/src/expert-io.ts +0 -393
- package/src/expert-offload-build.ts +0 -77
- package/src/expert-offload.ts +0 -76
- package/src/expert-residency.ts +0 -1134
- package/src/expert-usage.ts +0 -415
- package/src/fill/echo-index.ts +0 -188
- package/src/fill/fill-session.ts +0 -463
- package/src/fill/proposal.ts +0 -68
- package/src/fill/schema-rows.ts +0 -506
- package/src/fill/tool-boundary.ts +0 -103
- package/src/fit.ts +0 -249
- package/src/generate.ts +0 -1352
- package/src/grammar.ts +0 -604
- package/src/harness-pi.ts +0 -184
- package/src/hf-push.ts +0 -628
- package/src/hub-rest.ts +0 -242
- package/src/index.ts +0 -63
- package/src/inference/denoising.ts +0 -17
- package/src/inference/draft-acceptance.ts +0 -41
- package/src/inference/draft-output.ts +0 -49
- package/src/inference/graph.ts +0 -33
- package/src/inference/prefill.ts +0 -45
- package/src/inference/rollback.ts +0 -7
- package/src/jobs/index.ts +0 -31
- package/src/jobs/job-entry.ts +0 -107
- package/src/jobs/task-client.ts +0 -19
- package/src/jobs/types.ts +0 -2
- package/src/kv-scheme.ts +0 -279
- package/src/kv-store.ts +0 -1135
- package/src/lab/README.md +0 -22
- package/src/lab/curve/curve-designer.html +0 -303
- package/src/lab/curve/curve-sampler.ts +0 -122
- package/src/lab/expert-trace/expert-trace.ts +0 -69
- package/src/lab/paged-kv/paged-attention.ts +0 -117
- package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
- package/src/lab/paged-kv/paged-kv.ts +0 -336
- package/src/library.ts +0 -40
- package/src/lora.ts +0 -408
- package/src/md-modules.d.ts +0 -54
- package/src/media-fetch.ts +0 -442
- package/src/memory/article.ts +0 -558
- package/src/memory/chunk-validation.ts +0 -150
- package/src/memory/chunk.ts +0 -318
- package/src/memory/cluster.ts +0 -351
- package/src/memory/coverage.ts +0 -134
- package/src/memory/crosslink.ts +0 -0
- package/src/memory/db.ts +0 -253
- package/src/memory/entity.ts +0 -203
- package/src/memory/gate.ts +0 -187
- package/src/memory/history.ts +0 -152
- package/src/memory/ingest.ts +0 -335
- package/src/memory/model.ts +0 -183
- package/src/memory/normalize.ts +0 -671
- package/src/memory/parse.ts +0 -22
- package/src/memory/pipeline.ts +0 -275
- package/src/memory/prompts.ts +0 -65
- package/src/memory/query.ts +0 -334
- package/src/memory/reconcile.ts +0 -734
- package/src/memory/redirect.ts +0 -108
- package/src/memory/reindex.ts +0 -325
- package/src/memory/resolve.ts +0 -307
- package/src/memory/rest.ts +0 -245
- package/src/memory/route.ts +0 -272
- package/src/memory/schedule.ts +0 -165
- package/src/memory/stages.ts +0 -777
- package/src/memory/synthesize.ts +0 -1638
- package/src/memory/tools.ts +0 -749
- package/src/memory/vault.ts +0 -1194
- package/src/memory/wikify.ts +0 -1064
- package/src/mlx/array.ts +0 -425
- package/src/mlx/autograd.ts +0 -304
- package/src/mlx/checkpoint.ts +0 -149
- package/src/mlx/compile.ts +0 -168
- package/src/mlx/custom-vjp.ts +0 -188
- package/src/mlx/ffi.ts +0 -531
- package/src/mlx/materialize.ts +0 -23
- package/src/mlx/metal-kernel.ts +0 -159
- package/src/mlx/normalized-argmax.ts +0 -116
- package/src/mlx/ops.ts +0 -1108
- package/src/mlx/quantized-rows.ts +0 -36
- package/src/mlx/token-bitmask.ts +0 -52
- package/src/mlx/turboquant-kv-decode.ts +0 -82
- package/src/mlx/turboquant-kv-inverse.ts +0 -122
- package/src/mlx/turboquant-ops.ts +0 -861
- package/src/mlx/turboquant-tables.ts +0 -237
- package/src/mmap.ts +0 -90
- package/src/model/artifact-identity.ts +0 -73
- package/src/model/batched-kv.ts +0 -235
- package/src/model/batched-mask.ts +0 -279
- package/src/model/batched-quant.ts +0 -212
- package/src/model/batched-quantized-kv.ts +0 -144
- package/src/model/batched-rotating-quant.ts +0 -353
- package/src/model/batched-rotating-state.ts +0 -149
- package/src/model/batched-rotating.ts +0 -338
- package/src/model/batched-row-storage.ts +0 -179
- package/src/model/batched-ssm.ts +0 -52
- package/src/model/batched-turboquant-kv.ts +0 -94
- package/src/model/compiled-decode.ts +0 -712
- package/src/model/decoded-kv-donor.ts +0 -12
- package/src/model/delayed-quantized-kv.ts +0 -72
- package/src/model/delayed-rotating-quantized-kv.ts +0 -93
- package/src/model/delayed-turboquant-kv.ts +0 -57
- package/src/model/diffusion-gemma.ts +0 -1026
- package/src/model/factory.ts +0 -215
- package/src/model/fingerprint.ts +0 -45
- package/src/model/flash-attention.ts +0 -694
- package/src/model/full-prefill-padding.ts +0 -56
- package/src/model/full-prefill-row.ts +0 -105
- package/src/model/gemma4-base.ts +0 -2370
- package/src/model/gemma4.ts +0 -1395
- package/src/model/generated/gemma4-12b.ts +0 -429
- package/src/model/generated/gemma4-26b.ts +0 -448
- package/src/model/generated/gemma4-e4b.ts +0 -717
- package/src/model/generated/index.ts +0 -18
- package/src/model/glm52-atlas.ts +0 -511
- package/src/model/glm52-cache.ts +0 -792
- package/src/model/glm52-config.ts +0 -262
- package/src/model/glm52-container.ts +0 -305
- package/src/model/glm52-coupling.ts +0 -388
- package/src/model/glm52-dsa.ts +0 -606
- package/src/model/glm52-expert-layout.ts +0 -253
- package/src/model/glm52-layout.ts +0 -152
- package/src/model/glm52-memory.ts +0 -500
- package/src/model/glm52-mla.ts +0 -792
- package/src/model/glm52-moe.ts +0 -223
- package/src/model/glm52-pilot.ts +0 -537
- package/src/model/glm52-reference.ts +0 -445
- package/src/model/glm52-residency.ts +0 -557
- package/src/model/glm52-resident-weights.ts +0 -135
- package/src/model/glm52-streamed-experts.ts +0 -453
- package/src/model/glm52-streamed-metal.ts +0 -610
- package/src/model/glm52-weights.ts +0 -503
- package/src/model/glm52.ts +0 -1132
- package/src/model/implementation.ts +0 -69
- package/src/model/kv-attention-view.ts +0 -70
- package/src/model/minicpm5.ts +0 -376
- package/src/model/profile.ts +0 -468
- package/src/model/quantized-append-attention.ts +0 -31
- package/src/model/qwen-append.ts +0 -12
- package/src/model/qwen-conv.ts +0 -52
- package/src/model/qwen3-delta-state.ts +0 -74
- package/src/model/qwen3-delta.ts +0 -451
- package/src/model/qwen3-moe.ts +0 -404
- package/src/model/qwen3-mrope.ts +0 -250
- package/src/model/qwen3.ts +0 -277
- package/src/model/qwen3_5-checkpoint.ts +0 -164
- package/src/model/qwen3_5.ts +0 -881
- package/src/model/rotating-kv-donor.ts +0 -35
- package/src/model/rotating-kv-layout.ts +0 -262
- package/src/model/rotating-row-transaction.ts +0 -35
- package/src/model/speculative-rotating-kv.ts +0 -101
- package/src/model/ssm-prefill-padding.ts +0 -39
- package/src/model/support.ts +0 -110
- package/src/model/token-groups.ts +0 -66
- package/src/model/trellis-balanced-scatter.ts +0 -51
- package/src/model/trellis-linear.ts +0 -672
- package/src/model/trellis-shared-m.ts +0 -151
- package/src/model/trellis-shared-scatter.ts +0 -144
- package/src/model/trellis-splitk-prefill.ts +0 -158
- package/src/model/trellis-tiled-prefill.ts +0 -136
- package/src/model/trellis-vector-expand.ts +0 -62
- package/src/model/trellis-wide-prefill.ts +0 -94
- package/src/model/turboquant-codec.ts +0 -89
- package/src/model/universal/archs.ts +0 -332
- package/src/model/universal/dense.ts +0 -612
- package/src/model/universal/modules.ts +0 -170
- package/src/model/universal/rope.ts +0 -381
- package/src/model/whisper.ts +0 -435
- package/src/native/expert_io.c +0 -523
- package/src/native/frame_extract.swift +0 -140
- package/src/native/mic_capture.swift +0 -92
- package/src/native-pack.ts +0 -163
- package/src/pi-provider.ts +0 -53
- package/src/pi-session.ts +0 -81
- package/src/pi-terminal.ts +0 -274
- package/src/pi-web.ts +0 -1940
- package/src/preflight.ts +0 -158
- package/src/prompt-cache.ts +0 -682
- package/src/quantize/allocator.ts +0 -627
- package/src/quantize/atomic-output.ts +0 -38
- package/src/quantize/calibration.ts +0 -181
- package/src/quantize/config-writer.ts +0 -145
- package/src/quantize/index.ts +0 -84
- package/src/quantize/job.ts +0 -162
- package/src/quantize/quantizer.ts +0 -666
- package/src/quantize/rotate.ts +0 -603
- package/src/quantize/safetensors-writer.ts +0 -249
- package/src/quantize/sensitivity.ts +0 -216
- package/src/quantize/trellis.ts +0 -586
- package/src/quantize/weight-transform.ts +0 -292
- package/src/registry.ts +0 -602
- package/src/runtime-config.ts +0 -77
- package/src/safetensors.ts +0 -165
- package/src/sampler.ts +0 -1012
- package/src/serve/admin-routes.ts +0 -184
- package/src/serve/assets/curve-terrain.html +0 -105
- package/src/serve/assets/training-inference-map.html +0 -575
- package/src/serve/audio-routes.ts +0 -323
- package/src/serve/aux-routes.ts +0 -132
- package/src/serve/batch-scheduler.ts +0 -8
- package/src/serve/checkpoint-identity.ts +0 -64
- package/src/serve/generation-gateway.ts +0 -537
- package/src/serve/isolate.ts +0 -609
- package/src/serve/kv-budget.ts +0 -14
- package/src/serve/lab-routes.ts +0 -341
- package/src/serve/lane-registry.ts +0 -45
- package/src/serve/model-admin-routes.ts +0 -155
- package/src/serve/model-binding.ts +0 -49
- package/src/serve/model-host.ts +0 -511
- package/src/serve/parent-application.ts +0 -56
- package/src/serve/prompt-response-trace.ts +0 -161
- package/src/serve/response-lease.ts +0 -24
- package/src/serve/session-search.ts +0 -326
- package/src/serve/static-routes.ts +0 -101
- package/src/serve/transcription-server.ts +0 -64
- package/src/serve/transcription-service.ts +0 -502
- package/src/server.ts +0 -1282
- package/src/spec/assistant-rows.ts +0 -93
- package/src/spec/assistant-source.ts +0 -126
- package/src/spec/cache-identity.ts +0 -22
- package/src/spec/deepspec-rows.ts +0 -29
- package/src/spec/deepspec-source.ts +0 -145
- package/src/spec/dflash-source.ts +0 -149
- package/src/spec/drafter.ts +0 -304
- package/src/spec/dspark/ab-stats.ts +0 -136
- package/src/spec/dspark/calibration.ts +0 -112
- package/src/spec/dspark/data-dflash.ts +0 -156
- package/src/spec/dspark/data.ts +0 -201
- package/src/spec/dspark/deepspec-module.ts +0 -776
- package/src/spec/dspark/generate-dflash.ts +0 -245
- package/src/spec/dspark/generate.ts +0 -290
- package/src/spec/dspark/loader.ts +0 -23
- package/src/spec/dspark/loss.ts +0 -213
- package/src/spec/dspark/module-dflash.ts +0 -560
- package/src/spec/dspark/module.ts +0 -540
- package/src/spec/dspark/quantize-drafter.ts +0 -91
- package/src/spec/dspark/sample.ts +0 -112
- package/src/spec/generate.ts +0 -276
- package/src/spec/glm52-mtp-graph.ts +0 -29
- package/src/spec/glm52-mtp-rows.ts +0 -132
- package/src/spec/glm52-mtp-source.ts +0 -318
- package/src/spec/glm52-mtp-state.ts +0 -33
- package/src/spec/ngram-source.ts +0 -226
- package/src/spec/projected-draft-rows.ts +0 -73
- package/src/spec/qwen-mtp-module.ts +0 -171
- package/src/spec/qwen-mtp-rows.ts +0 -230
- package/src/spec/qwen-mtp-source.ts +0 -386
- package/src/spec/qwen-mtp-state.ts +0 -30
- package/src/spec/serve-loop.ts +0 -587
- package/src/spec/source.ts +0 -228
- package/src/spec/two-model-rows.ts +0 -62
- package/src/spec/two-model.ts +0 -113
- package/src/ssd-cache.ts +0 -431
- package/src/ssd-durability.ts +0 -209
- package/src/storage/host-buffer.ts +0 -24
- package/src/storage/kv-writer.ts +0 -83
- package/src/storage/kv-writer.worker.js +0 -264
- package/src/storage/retention-policy.ts +0 -37
- package/src/tiered-prompt-cache.ts +0 -45
- package/src/tokenizer.ts +0 -335
- package/src/tool-approvals.ts +0 -131
- package/src/tool-call.ts +0 -695
- package/src/train/dataset.ts +0 -484
- package/src/train/diffusion-lora.ts +0 -216
- package/src/train/export.ts +0 -32
- package/src/train/flash-cce.ts +0 -1234
- package/src/train/forward.ts +0 -266
- package/src/train/fuse.ts +0 -243
- package/src/train/index.ts +0 -46
- package/src/train/job.ts +0 -205
- package/src/train/lora-params.ts +0 -254
- package/src/train/loss.ts +0 -1591
- package/src/train/merge.ts +0 -195
- package/src/train/optimizer.ts +0 -183
- package/src/train/prefix-shared.ts +0 -490
- package/src/train/rank.ts +0 -137
- package/src/train/segmented.ts +0 -1828
- package/src/train/steel-qmm-header.ts +0 -1461
- package/src/train/trainer.ts +0 -1221
- package/src/train/watch.ts +0 -542
- package/src/vision/diffusion-vision.ts +0 -620
- package/src/vision/embedder.ts +0 -176
- package/src/vision/preprocess.ts +0 -247
- package/src/vision/prompt.ts +0 -409
- package/src/vision/qwen3vl-preprocess.ts +0 -409
- package/src/vision/qwen3vl-prompt.ts +0 -233
- package/src/vision/qwen3vl-tower.ts +0 -566
- package/src/vision/siglip.ts +0 -607
- package/src/vision/video-frames.ts +0 -148
- package/src/web/app.html +0 -2155
- package/src/web/app.js +0 -5863
- package/src/web/skills/memory/SKILL.md +0 -120
- package/src/web/skills/web-research/SKILL.md +0 -46
- package/src/web/skills.ts +0 -97
- package/src/web/src/adapters-panel.ts +0 -288
- package/src/web/src/assistant.ts +0 -451
- package/src/web/src/chat.ts +0 -1060
- package/src/web/src/composer.ts +0 -962
- package/src/web/src/dataset.ts +0 -132
- package/src/web/src/finetune.ts +0 -267
- package/src/web/src/hub.ts +0 -428
- package/src/web/src/main.ts +0 -98
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +0 -572
- package/src/web/src/model-picker.ts +0 -159
- package/src/web/src/palette.ts +0 -346
- package/src/web/src/protocol.ts +0 -26
- package/src/web/src/quantize.ts +0 -167
- package/src/web/src/rag.ts +0 -274
- package/src/web/src/sessions.ts +0 -469
- package/src/web/src/shell.ts +0 -804
- package/src/web/src/ui-catalog.ts +0 -78
- package/src/web/src/voice.ts +0 -141
- package/src/web/vendor/README.md +0 -61
- package/src/web-assets.ts +0 -47
- package/src/web-tools.ts +0 -478
- package/src/weights.ts +0 -255
- /package/src/{serve → server}/completion-sink.ts +0 -0
- /package/src/{serve → server}/generated-token-history.ts +0 -0
- /package/src/web/{icon.svg → public/icon.svg} +0 -0
- /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
- /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
|
-
}
|