mlx-bun 0.0.13 → 0.3.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 +71 -578
- package/bin/mlx-bun.mjs +1 -1
- package/docs/README.md +91 -0
- package/docs/{design → archive}/hlg-sampling.md +3 -3
- package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
- package/docs/{design → archive/investigations}/colibri-glm52-port.md +1 -1
- package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
- package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
- package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
- package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
- package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
- package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
- package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
- package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
- package/docs/{planning → archive/planning}/chunk-task-roadmap.md +1 -1
- package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +4 -4
- package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +1 -1
- package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
- package/docs/archive/planning/release-notes-v0.2.0.md +49 -0
- package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
- package/docs/design/batching.md +569 -0
- package/docs/design/decode-speed-program.md +3178 -169
- package/docs/design/dreaming-nightly-pipeline.md +675 -282
- package/docs/design/generic-model-support.md +579 -334
- package/docs/design/kv-cache.md +680 -0
- package/docs/design/orpo-training.md +673 -1239
- package/docs/design/speculative-decoding.md +1627 -0
- package/docs/design/turboquant.md +2102 -0
- package/docs/design/unified-engine-frontier-plan.md +1831 -727
- package/docs/design/web-chat-redesign.md +666 -1083
- package/docs/planning/PRODUCT_ROADMAP.md +34 -1
- package/docs/planning/release-notes-v0.3.0.md +35 -0
- package/docs/planning/video-series.md +421 -0
- package/docs/reference/benchmarks.md +1162 -0
- package/docs/reference/cli.md +395 -149
- package/docs/reference/distribution.md +321 -181
- package/docs/reference/environment.md +348 -0
- package/docs/reference/glossary.md +39 -0
- package/docs/reference/library-api.md +580 -142
- package/docs/reference/memory.md +227 -64
- package/docs/reference/models.md +137 -6
- package/docs/reference/server-api.md +938 -422
- package/docs/reference/server-config.md +652 -320
- package/docs/reference/training.md +393 -254
- package/docs/reference/troubleshooting.md +166 -0
- package/package.json +10 -5
- package/src/admission-plan.ts +18 -0
- package/src/anthropic.ts +92 -3
- package/src/audio/decode.ts +2 -2
- package/src/audio/features.ts +2 -2
- package/src/backends/mlx/autoregressive.ts +108 -0
- package/src/backends/mlx/batch-group.ts +1646 -0
- package/src/backends/mlx/diffusion.ts +39 -0
- package/src/backends/mlx/draft-target.ts +47 -0
- package/src/backends/mlx/evaluation.ts +105 -0
- package/src/backends/mlx/fill-append.ts +45 -0
- package/src/backends/mlx/gateway-binding.ts +71 -0
- package/src/backends/mlx/graph.ts +38 -0
- package/src/backends/mlx/memory-client.ts +189 -0
- package/src/backends/mlx/memory-guard.ts +40 -0
- package/src/backends/mlx/methods.ts +90 -0
- package/src/backends/mlx/model-prompt.ts +164 -0
- package/src/backends/mlx/model-serving.ts +79 -0
- package/src/backends/mlx/prefill.ts +33 -0
- package/src/backends/mlx/request-policy.ts +20 -0
- package/src/backends/mlx/rollback.ts +51 -0
- package/src/backends/mlx/serial-executor.ts +273 -0
- package/src/backends/mlx/speculative.ts +114 -0
- package/src/backends/mlx/state-views.ts +26 -0
- package/src/backends/mlx/text-engine.ts +73 -0
- package/src/cli.ts +189 -61
- package/src/client.ts +66 -0
- package/src/config.ts +21 -4
- package/src/contracts/completion.ts +16 -0
- package/src/contracts/execution.ts +49 -0
- package/src/contracts/generation.ts +103 -0
- package/src/contracts/host.ts +7 -0
- package/src/contracts/jobs.ts +66 -0
- package/src/contracts/pi-provider.ts +30 -0
- package/src/contracts/pi.ts +259 -0
- package/src/contracts/resources.ts +18 -0
- package/src/contracts/scheduling.ts +27 -0
- package/src/contracts/tsconfig.json +14 -0
- package/src/diffusion/diffusion-generate.ts +218 -153
- package/src/embed.ts +1 -1
- package/src/engine/admission.ts +59 -0
- package/src/engine/cancellation.ts +38 -0
- package/src/engine/engine.ts +56 -0
- package/src/engine/execution-coordinator.ts +70 -0
- package/src/engine/execution-plan.ts +51 -0
- package/src/engine/resources.ts +42 -0
- package/src/engine/scheduler.ts +67 -0
- package/src/engine/session.ts +247 -0
- package/src/eval/README.md +44 -1
- package/src/eval/kl.ts +263 -23
- package/src/eval/reference-logits.ts +207 -0
- package/src/eval/runner.ts +10 -79
- package/src/eval/tasks/bfcl.ts +2 -1
- package/src/eval/tasks/gsm8k.ts +2 -1
- package/src/eval/tasks/hashhop.ts +2 -1
- package/src/eval/tasks/humaneval.ts +5 -4
- package/src/eval/tasks/ifeval.ts +2 -1
- package/src/eval/tasks/mmlu.ts +2 -1
- package/src/expert-io.ts +3 -1
- package/src/expert-offload.ts +3 -1
- package/src/fill/echo-index.ts +188 -0
- package/src/fill/fill-session.ts +452 -0
- package/src/fill/proposal.ts +68 -0
- package/src/fill/schema-rows.ts +506 -0
- package/src/fill/tool-boundary.ts +103 -0
- package/src/fit.ts +24 -43
- package/src/generate.ts +740 -337
- package/src/grammar.ts +14 -8
- package/src/harness-pi.ts +15 -34
- package/src/hub-rest.ts +4 -4
- package/src/index.ts +27 -0
- package/src/inference/denoising.ts +17 -0
- package/src/inference/graph.ts +33 -0
- package/src/inference/prefill.ts +39 -0
- package/src/inference/rollback.ts +7 -0
- package/src/jobs/db.ts +4 -0
- package/src/jobs/index.ts +2 -0
- package/src/jobs/job-entry.ts +15 -14
- package/src/jobs/runner.ts +98 -13
- package/src/jobs/task-client.ts +19 -0
- package/src/jobs/types.ts +2 -58
- package/src/kv-scheme.ts +199 -0
- package/src/kv-store.ts +459 -234
- package/src/lab/README.md +18 -0
- package/src/{assets → lab/curve}/curve-designer.html +2 -2
- package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
- package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +7 -5
- package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
- package/src/library.ts +40 -0
- package/src/lora.ts +18 -0
- package/src/media-fetch.ts +20 -4
- package/src/memory/article.ts +1 -1
- package/src/memory/chunk.ts +1 -1
- package/src/memory/model.ts +32 -170
- package/src/memory/prompts.ts +1 -1
- package/src/memory/rest.ts +1 -1
- package/src/memory/schedule.ts +1 -1
- package/src/memory/stages.ts +4 -1
- package/src/memory/vault.ts +3 -4
- package/src/mlx/array.ts +9 -10
- package/src/mlx/compile.ts +12 -2
- package/src/mlx/ffi.ts +66 -22
- package/src/mlx/materialize.ts +23 -0
- package/src/mlx/metal-kernel.ts +10 -11
- package/src/mlx/ops.ts +64 -19
- package/src/mlx/quantized-rows.ts +36 -0
- package/src/mlx/token-bitmask.ts +52 -0
- package/src/mlx/turboquant-kv-decode.ts +82 -0
- package/src/mlx/turboquant-kv-inverse.ts +122 -0
- package/src/mlx/turboquant-ops.ts +33 -3
- package/src/mlx/turboquant-tables.ts +2 -2
- package/src/model/batched-mask.ts +9 -3
- package/src/model/batched-quant.ts +2 -2
- package/src/model/batched-rotating-quant.ts +45 -99
- package/src/model/batched-rotating-state.ts +73 -0
- package/src/model/batched-rotating.ts +57 -106
- package/src/model/batched-row-storage.ts +127 -0
- package/src/model/compiled-decode.ts +4 -3
- package/src/model/diffusion-gemma.ts +8 -8
- package/src/model/factory.ts +87 -49
- package/src/model/fingerprint.ts +1 -1
- package/src/model/flash-attention.ts +3 -3
- package/src/model/gemma4-base.ts +187 -17
- package/src/model/gemma4.ts +6 -6
- package/src/model/generated/gemma4-12b.ts +52 -148
- package/src/model/generated/gemma4-26b.ts +34 -94
- package/src/model/generated/gemma4-e4b.ts +28 -76
- package/src/model/glm52-cache.ts +19 -9
- package/src/model/glm52-dsa.ts +13 -9
- package/src/model/glm52-memory.ts +28 -1
- package/src/model/implementation.ts +69 -0
- package/src/model/minicpm5.ts +7 -8
- package/src/model/profile.ts +443 -0
- package/src/model/qwen-append.ts +12 -0
- package/src/model/qwen-conv.ts +52 -0
- package/src/model/qwen3-delta.ts +98 -2
- package/src/model/qwen3-mrope.ts +252 -0
- package/src/model/qwen3_5-checkpoint.ts +164 -0
- package/src/model/qwen3_5.ts +336 -60
- package/src/model/support.ts +1 -1
- package/src/model/trellis-balanced-scatter.ts +51 -0
- package/src/model/trellis-linear.ts +672 -0
- package/src/model/trellis-shared-m.ts +151 -0
- package/src/model/trellis-shared-scatter.ts +144 -0
- package/src/model/trellis-splitk-prefill.ts +158 -0
- package/src/model/trellis-tiled-prefill.ts +136 -0
- package/src/model/trellis-vector-expand.ts +62 -0
- package/src/model/trellis-wide-prefill.ts +94 -0
- package/src/model/universal/dense.ts +1 -1
- package/src/model/universal/modules.ts +8 -1
- package/src/native/frame_extract.swift +140 -0
- package/src/native-pack.ts +15 -7
- package/src/pi-provider.ts +6 -64
- package/src/pi-web.ts +14 -320
- package/src/prompt-cache.ts +97 -54
- package/src/quantize/allocator.ts +1 -1
- package/src/quantize/atomic-output.ts +38 -0
- package/src/quantize/calibration.ts +2 -1
- package/src/quantize/config-writer.ts +16 -3
- package/src/quantize/index.ts +28 -1
- package/src/quantize/job.ts +11 -0
- package/src/quantize/quantizer.ts +265 -100
- package/src/quantize/rotate.ts +603 -0
- package/src/quantize/safetensors-writer.ts +79 -1
- package/src/quantize/sensitivity.ts +41 -59
- package/src/quantize/trellis.ts +586 -0
- package/src/quantize/weight-transform.ts +292 -0
- package/src/responses.ts +130 -3
- package/src/runtime-config.ts +81 -0
- package/src/sampler.ts +276 -4
- package/src/serve/admin-routes.ts +184 -0
- package/src/serve/aux-routes.ts +132 -0
- package/src/serve/batch-scheduler.ts +8 -1558
- package/src/serve/chat-request.ts +391 -0
- package/src/serve/chat-stage.ts +195 -0
- package/src/serve/checkpoint-identity.ts +64 -0
- package/src/serve/completion-executor.ts +354 -0
- package/src/serve/completion-sink.ts +157 -0
- package/src/serve/discovery-routes.ts +204 -0
- package/src/serve/generation-gateway.ts +211 -243
- package/src/serve/http.ts +159 -0
- package/src/serve/inference-request.ts +79 -0
- package/src/serve/isolate.ts +297 -105
- package/src/serve/kv-budget.ts +14 -0
- package/src/serve/lab-routes.ts +341 -0
- package/src/serve/lane-registry.ts +2 -1
- package/src/serve/model-admin-routes.ts +155 -0
- package/src/serve/model-binding.ts +43 -0
- package/src/serve/model-host.ts +512 -0
- package/src/serve/openai-wire.ts +103 -0
- package/src/serve/parent-application.ts +56 -0
- package/src/serve/pipeline.ts +33 -0
- package/src/serve/preparation.ts +33 -0
- package/src/serve/prompt-response-trace.ts +147 -0
- package/src/serve/request-plan.ts +162 -0
- package/src/serve/request-prep.ts +346 -0
- package/src/serve/response-lease.ts +24 -0
- package/src/serve/responses-client.ts +69 -0
- package/src/serve/session-completion-engine.ts +110 -0
- package/src/serve/session-search.ts +1 -1
- package/src/serve/static-routes.ts +101 -0
- package/src/serve/text-completion-stage.ts +104 -0
- package/src/serve/token-streams.ts +519 -0
- package/src/server.ts +523 -3551
- package/src/spec/assistant-source.ts +10 -44
- package/src/spec/deepspec-source.ts +6 -6
- package/src/spec/dflash-source.ts +9 -8
- package/src/spec/dspark/ab-stats.ts +3 -3
- package/src/spec/dspark/calibration.ts +2 -2
- package/src/spec/dspark/deepspec-module.ts +2 -2
- package/src/spec/dspark/generate-dflash.ts +2 -2
- package/src/spec/dspark/generate.ts +2 -2
- package/src/spec/dspark/loader.ts +1 -1
- package/src/spec/dspark/module-dflash.ts +5 -4
- package/src/spec/dspark/module.ts +3 -3
- package/src/spec/dspark/quantize-drafter.ts +1 -1
- package/src/spec/generate.ts +1 -1
- package/src/spec/glm52-mtp-source.ts +9 -1
- package/src/spec/ngram-source.ts +1 -1
- package/src/spec/prefix-state.ts +45 -0
- package/src/spec/qwen-mtp-source.ts +528 -0
- package/src/spec/serve-loop.ts +179 -213
- package/src/spec/source.ts +42 -10
- package/src/spec/two-model.ts +1 -1
- package/src/ssd-cache.ts +95 -24
- package/src/ssd-durability.ts +207 -0
- package/src/tool-call.ts +51 -14
- package/src/train/flash-cce.ts +14 -13
- package/src/train/forward.ts +38 -1
- package/src/train/loss.ts +3 -2
- package/src/train/prefix-shared.ts +5 -1
- package/src/train/segmented.ts +9 -6
- package/src/train/trainer.ts +9 -8
- package/src/vision/preprocess.ts +1 -1
- package/src/vision/prompt.ts +48 -2
- package/src/vision/qwen3vl-preprocess.ts +409 -0
- package/src/vision/qwen3vl-prompt.ts +196 -0
- package/src/vision/qwen3vl-tower.ts +555 -0
- package/src/vision/video-frames.ts +148 -0
- package/src/web/app.html +1 -1
- package/src/web/app.js +15 -6
- package/src/web/src/adapters-panel.ts +3 -3
- package/src/web/src/assistant.ts +2 -36
- package/src/web/src/chat.ts +16 -9
- package/src/web/src/composer.ts +4 -4
- package/src/web/src/hub.ts +1 -1
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +1 -1
- package/src/web/src/model-picker.ts +1 -1
- package/src/web/src/palette.ts +1 -1
- package/src/web/src/protocol.ts +3 -39
- package/src/web/src/sessions.ts +1 -1
- package/src/web/src/ui-catalog.ts +4 -18
- package/src/web-assets.ts +47 -0
- package/src/weights.ts +134 -33
- package/docs/archive/mlx-bun-lab-report.html +0 -275
- package/docs/archive/wwdc-mlx-bun.html +0 -848
- package/docs/design/adapters-end-to-end.md +0 -205
- package/docs/design/batching-perf-path.md +0 -255
- package/docs/design/batching-v2-plan.md +0 -529
- package/docs/design/bucketing-stage.md +0 -197
- package/docs/design/compat-cli-surface-design.md +0 -230
- package/docs/design/docs-reorg-plan.md +0 -165
- package/docs/design/dspark-serving-program.md +0 -371
- package/docs/design/dspark-speculative-decoding.md +0 -268
- package/docs/design/grammar-spec-batching-integration.md +0 -301
- package/docs/design/memory-inference-path.md +0 -422
- package/docs/design/memory-synthesis.md +0 -287
- package/docs/design/memory-system.md +0 -237
- package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
- package/docs/design/omlx-adoption-map.md +0 -98
- package/docs/design/orpo-dynamic-lambda.md +0 -220
- package/docs/design/orpo-future-enhancements.md +0 -340
- package/docs/design/paged-kv-cache.md +0 -214
- package/docs/design/parallel-slots.md +0 -567
- package/docs/design/parity-tier-dag.md +0 -161
- package/docs/design/repo-cleanup-plan.md +0 -189
- package/docs/design/runtime-isolation.md +0 -263
- package/docs/design/segmented-backward-training.md +0 -543
- package/docs/design/spec-decode-larger-targets.md +0 -229
- package/docs/design/ssd-kv-cold-tier.md +0 -288
- package/docs/design/structured-output.md +0 -484
- package/docs/design/tauri-desktop-app.md +0 -127
- package/docs/design/the-dreaming-master-plan.md +0 -445
- package/docs/design/turboquant-kv.md +0 -235
- package/docs/design/w4a16-compute-precision-spike.md +0 -232
- package/docs/design/web-chat-beat-matrix.md +0 -315
- package/docs/design/write-pipeline-entity.md +0 -468
- package/docs/investigations/curve-runs/bisector-route.json +0 -98
- package/docs/investigations/curve-runs/bisector-trace.json +0 -1393
- package/docs/investigations/curve-runs/curve-terrain.json +0 -1179
- package/docs/investigations/curve-runs/curve-terrain.svg +0 -42
- package/docs/investigations/hlg-ab.html +0 -34
- package/docs/investigations/hlg-explorer.html +0 -238
- package/docs/investigations/hlg-figs/cliff.svg +0 -1
- package/docs/investigations/hlg-figs/cross.svg +0 -1
- package/docs/investigations/hlg-figs/edges.svg +0 -1
- package/docs/investigations/hlg-figs/k20-grids.svg +0 -1
- package/docs/investigations/hlg-figs/k20-peaks.svg +0 -1
- package/docs/investigations/hlg-figs/lw-curve.svg +0 -1
- package/docs/investigations/hlg-figs/terrain.svg +0 -1
- package/docs/investigations/hlg-report.html +0 -262
- package/docs/investigations/hlg-runs/hlg-ab.json +0 -149
- package/docs/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
- package/docs/investigations/hlg-runs/hlg-blind.json +0 -107
- package/docs/investigations/hlg-runs/hlg-cliff.json +0 -197
- package/docs/investigations/hlg-runs/hlg-cross.json +0 -505
- package/docs/investigations/hlg-runs/hlg-edge.json +0 -388
- package/docs/investigations/hlg-runs/hlg-eval1.json +0 -25
- package/docs/investigations/hlg-runs/hlg-frontier.json +0 -86
- package/docs/investigations/hlg-runs/hlg-grid.json +0 -242
- package/docs/investigations/hlg-runs/hlg-grid2.json +0 -343
- package/docs/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
- package/docs/investigations/hlg-runs/hlg-map.json +0 -383
- package/docs/investigations/hlg-runs/run0-original.log +0 -159
- package/docs/investigations/hlg-runs/runA-recommended.log +0 -131
- package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
- package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
- package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
- package/docs/investigations/hlg-runs/runAD-ab-samples.log +0 -8
- package/docs/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
- package/docs/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
- package/docs/investigations/hlg-runs/runAG-eval-config2.log +0 -16
- package/docs/investigations/hlg-runs/runB-gain-variants.log +0 -192
- package/docs/investigations/hlg-runs/runC-pivots.log +0 -162
- package/docs/investigations/hlg-runs/runD-oetf.log +0 -132
- package/docs/investigations/hlg-runs/runE-eotf.log +0 -162
- package/docs/investigations/hlg-runs/runF-shaper-working.log +0 -86
- package/docs/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
- package/docs/investigations/hlg-runs/runH-wsweep.log +0 -176
- package/docs/investigations/hlg-runs/runI-asweep.log +0 -176
- package/docs/investigations/hlg-runs/runJ-knobmap.log +0 -49
- package/docs/investigations/hlg-runs/runK-frontier.log +0 -19
- package/docs/investigations/hlg-runs/runL-widemap.log +0 -65
- package/docs/investigations/hlg-runs/runM-frontier-emb.log +0 -15
- package/docs/investigations/hlg-runs/runN-verify.log +0 -116
- package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
- package/docs/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
- package/docs/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
- package/docs/investigations/hlg-runs/runR-blind-transcript.log +0 -79
- package/docs/investigations/hlg-runs/runS-cross-coherence.log +0 -33
- package/docs/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
- package/docs/investigations/hlg-runs/runU-cross-12b.log +0 -33
- package/docs/investigations/hlg-runs/runV-lw-e4b.log +0 -22
- package/docs/investigations/hlg-runs/runW-lw-12b.log +0 -22
- package/docs/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
- package/docs/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
- package/docs/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
- package/docs/planning/IDEAS.md +0 -69
- package/docs/reference/embedding.md +0 -197
- package/docs/reference/features-matrix.md +0 -100
- package/docs/reference/orpo-quickstart.md +0 -135
- package/src/flags.ts +0 -13
- /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
- /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
- /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
- /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
- /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
- /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
- /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
- /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
- /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
- /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
- /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
- /package/docs/{planning → archive/planning}/journal.md +0 -0
- /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
- /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
- /package/{docs/investigations → src/serve/assets}/curve-terrain.html +0 -0
- /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
// Quantizer-facing offline weight-transform seam. Recipe math lives in
|
|
2
|
+
// rotate.ts; this module owns planning, family adaptation, and tensor ownership
|
|
3
|
+
// so the artifact writer has one contract for every fold implementation.
|
|
4
|
+
|
|
5
|
+
import type { ModelConfig } from "../config";
|
|
6
|
+
import type { MlxArray } from "../mlx/array";
|
|
7
|
+
import type { Weights } from "../weights";
|
|
8
|
+
import {
|
|
9
|
+
foldLlamaWeights,
|
|
10
|
+
planQwen35Fold,
|
|
11
|
+
planQwenMtpFold,
|
|
12
|
+
QwenFoldContext,
|
|
13
|
+
type FoldGeometry,
|
|
14
|
+
type FoldOptions,
|
|
15
|
+
type QwenFoldOptions,
|
|
16
|
+
type QwenFoldPlan,
|
|
17
|
+
} from "./rotate";
|
|
18
|
+
|
|
19
|
+
/** Serialized alongside a quantized artifact so a folded basis is a property
|
|
20
|
+
* of the artifact, not an out-of-band experiment-script convention. */
|
|
21
|
+
export interface WeightTransformMetadata {
|
|
22
|
+
id: string;
|
|
23
|
+
seed: number;
|
|
24
|
+
family: string;
|
|
25
|
+
deviations: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Pure output plan. `sourceByOutput` makes cloning/untie operations explicit:
|
|
29
|
+
* most outputs map to themselves; a synthesized head maps to its embedding. */
|
|
30
|
+
export interface WeightTransformPlan {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly outputNames: readonly string[];
|
|
33
|
+
readonly sourceByOutput: ReadonlyMap<string, string>;
|
|
34
|
+
readonly untieWordEmbeddings: boolean;
|
|
35
|
+
readonly metadata: WeightTransformMetadata;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Per-run executor. `apply` returns a lazy, owned array and never disposes
|
|
39
|
+
* `source`; the quantizer owns the result and the Weights object owns source. */
|
|
40
|
+
export interface WeightTransformContext {
|
|
41
|
+
apply(outputName: string, source: MlxArray): MlxArray;
|
|
42
|
+
dispose(): void;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Common seam for the Llama, Qwen3.5 trunk, and Qwen MTP fold recipes. */
|
|
46
|
+
export interface WeightTransform {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
/** Name/config analysis only: no mlx arrays, model load, or device work. */
|
|
49
|
+
plan(names: readonly string[], config: ModelConfig): WeightTransformPlan;
|
|
50
|
+
createContext(weights: Weights, plan: WeightTransformPlan): WeightTransformContext;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface LlamaWeightTransformPlan extends WeightTransformPlan {
|
|
54
|
+
readonly kind: "llama";
|
|
55
|
+
readonly geometry: FoldGeometry;
|
|
56
|
+
readonly options: FoldOptions;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface QwenWeightTransformPlan extends WeightTransformPlan {
|
|
60
|
+
readonly kind: "qwen3_5" | "qwen3_5_mtp";
|
|
61
|
+
readonly hiddenSize: number;
|
|
62
|
+
readonly seed: number;
|
|
63
|
+
readonly fold: QwenFoldPlan;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function sourceMap(names: readonly string[]): Map<string, string> {
|
|
67
|
+
return new Map(names.map((name) => [name, name]));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function assertPow2(n: number, what: string): void {
|
|
71
|
+
if (n < 2 || (n & (n - 1)) !== 0)
|
|
72
|
+
throw new Error(
|
|
73
|
+
`rotation fold: ${what}=${n} is not a power of two — the Kronecker ` +
|
|
74
|
+
"Hadamard path is not implemented",
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Pure Llama fold plan. Array work remains inside createContext/apply. */
|
|
79
|
+
export function planLlamaWeightTransform(
|
|
80
|
+
names: readonly string[],
|
|
81
|
+
config: ModelConfig,
|
|
82
|
+
options: FoldOptions,
|
|
83
|
+
): LlamaWeightTransformPlan {
|
|
84
|
+
const has = new Set(names);
|
|
85
|
+
for (const required of ["model.embed_tokens.weight", "model.norm.weight"])
|
|
86
|
+
if (!has.has(required)) throw new Error(`rotation fold: missing tensor ${required}`);
|
|
87
|
+
if (has.has("lm_head.weight"))
|
|
88
|
+
throw new Error("rotation fold: llama adapter currently requires tied embeddings");
|
|
89
|
+
|
|
90
|
+
for (let i = 0; i < config.text.numHiddenLayers; i++) {
|
|
91
|
+
const layer = `model.layers.${i}`;
|
|
92
|
+
for (const required of [
|
|
93
|
+
`${layer}.input_layernorm.weight`,
|
|
94
|
+
`${layer}.post_attention_layernorm.weight`,
|
|
95
|
+
`${layer}.self_attn.q_proj.weight`,
|
|
96
|
+
`${layer}.self_attn.k_proj.weight`,
|
|
97
|
+
`${layer}.self_attn.v_proj.weight`,
|
|
98
|
+
`${layer}.self_attn.o_proj.weight`,
|
|
99
|
+
`${layer}.mlp.gate_proj.weight`,
|
|
100
|
+
`${layer}.mlp.up_proj.weight`,
|
|
101
|
+
`${layer}.mlp.down_proj.weight`,
|
|
102
|
+
]) {
|
|
103
|
+
if (!has.has(required)) throw new Error(`rotation fold: missing tensor ${required}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const geometry: FoldGeometry = {
|
|
108
|
+
numLayers: config.text.numHiddenLayers,
|
|
109
|
+
hiddenSize: config.text.hiddenSize,
|
|
110
|
+
numHeads: config.text.numAttentionHeads,
|
|
111
|
+
numKvHeads: config.text.numKeyValueHeads,
|
|
112
|
+
headDim: config.text.headDim,
|
|
113
|
+
};
|
|
114
|
+
if (options.r1 ?? true) assertPow2(geometry.hiddenSize, "hidden_size");
|
|
115
|
+
if (options.r2 ?? true) assertPow2(geometry.headDim, "head_dim");
|
|
116
|
+
|
|
117
|
+
const outputNames = [...names, "lm_head.weight"];
|
|
118
|
+
const sourceByOutput = sourceMap(names);
|
|
119
|
+
sourceByOutput.set("lm_head.weight", "model.embed_tokens.weight");
|
|
120
|
+
return {
|
|
121
|
+
kind: "llama",
|
|
122
|
+
id: "rotation.llama",
|
|
123
|
+
outputNames,
|
|
124
|
+
sourceByOutput,
|
|
125
|
+
untieWordEmbeddings: true,
|
|
126
|
+
geometry,
|
|
127
|
+
options: { ...options },
|
|
128
|
+
metadata: {
|
|
129
|
+
id: "rotation.llama",
|
|
130
|
+
seed: options.seed,
|
|
131
|
+
family: "llama",
|
|
132
|
+
deviations: [
|
|
133
|
+
"no-embedding-mean-centering",
|
|
134
|
+
"no-R4-downproj-input-fold",
|
|
135
|
+
"no-R3",
|
|
136
|
+
"gamma-kept-in-module-as-ones (eps preserved)",
|
|
137
|
+
"fold-precision-f32",
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function createLlamaContext(
|
|
144
|
+
weights: Weights,
|
|
145
|
+
plan: LlamaWeightTransformPlan,
|
|
146
|
+
): WeightTransformContext {
|
|
147
|
+
const folded = foldLlamaWeights(weights, plan.geometry, plan.options);
|
|
148
|
+
const pending = new Map(folded.tensors.map((tensor) => [tensor.name, tensor.array]));
|
|
149
|
+
return {
|
|
150
|
+
apply(outputName, source) {
|
|
151
|
+
const transformed = pending.get(outputName);
|
|
152
|
+
if (transformed) {
|
|
153
|
+
pending.delete(outputName);
|
|
154
|
+
return transformed;
|
|
155
|
+
}
|
|
156
|
+
// Preserve family-specific tensors outside the fold corridor.
|
|
157
|
+
return source.astype(source.dtype);
|
|
158
|
+
},
|
|
159
|
+
dispose() {
|
|
160
|
+
for (const array of pending.values()) array.dispose();
|
|
161
|
+
pending.clear();
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function qwenTransformPlan(
|
|
167
|
+
names: readonly string[],
|
|
168
|
+
config: ModelConfig,
|
|
169
|
+
seed: number,
|
|
170
|
+
companion: boolean,
|
|
171
|
+
prefix?: string,
|
|
172
|
+
): QwenWeightTransformPlan {
|
|
173
|
+
const fold = companion
|
|
174
|
+
? planQwenMtpFold(names)
|
|
175
|
+
: planQwen35Fold(
|
|
176
|
+
names,
|
|
177
|
+
prefix ?? (names.includes("language_model.model.norm.weight") ? "language_model." : ""),
|
|
178
|
+
);
|
|
179
|
+
const outputNames = [...names];
|
|
180
|
+
const sourceByOutput = sourceMap(names);
|
|
181
|
+
if (fold.extraHead) {
|
|
182
|
+
outputNames.push(fold.extraHead.name);
|
|
183
|
+
sourceByOutput.set(fold.extraHead.name, fold.extraHead.from);
|
|
184
|
+
}
|
|
185
|
+
const family = companion ? "qwen3_5_mtp" : "qwen3_5";
|
|
186
|
+
return {
|
|
187
|
+
kind: family,
|
|
188
|
+
id: `rotation.${family}`,
|
|
189
|
+
outputNames,
|
|
190
|
+
sourceByOutput,
|
|
191
|
+
untieWordEmbeddings: fold.extraHead !== null,
|
|
192
|
+
hiddenSize: config.text.hiddenSize,
|
|
193
|
+
seed,
|
|
194
|
+
fold,
|
|
195
|
+
metadata: {
|
|
196
|
+
id: `rotation.${family}`,
|
|
197
|
+
seed,
|
|
198
|
+
family,
|
|
199
|
+
deviations: [...fold.deviations],
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function createQwenContext(
|
|
205
|
+
weights: Weights,
|
|
206
|
+
plan: QwenWeightTransformPlan,
|
|
207
|
+
): WeightTransformContext {
|
|
208
|
+
// Lazy mode composes into the quantizer's existing writer. The experiment
|
|
209
|
+
// script keeps QwenFoldContext's eager default because it releases shards.
|
|
210
|
+
const context = new QwenFoldContext(
|
|
211
|
+
weights,
|
|
212
|
+
plan.hiddenSize,
|
|
213
|
+
plan.seed,
|
|
214
|
+
plan.fold.gammaNames,
|
|
215
|
+
false,
|
|
216
|
+
);
|
|
217
|
+
return {
|
|
218
|
+
apply(outputName, source) {
|
|
219
|
+
const extra = plan.fold.extraHead;
|
|
220
|
+
if (extra && outputName === extra.name)
|
|
221
|
+
return context.apply({ kind: "input", gamma: extra.gamma }, source);
|
|
222
|
+
const op = plan.fold.ops.get(outputName);
|
|
223
|
+
if (!op) throw new Error(`weight transform ${plan.id}: unplanned output ${outputName}`);
|
|
224
|
+
return context.apply(op, source);
|
|
225
|
+
},
|
|
226
|
+
dispose: () => context.dispose(),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Llama-family γ+R1+R2 adapter. */
|
|
231
|
+
export function llamaWeightTransform(options: FoldOptions): WeightTransform {
|
|
232
|
+
return {
|
|
233
|
+
id: "rotation.llama",
|
|
234
|
+
plan: (names, config) => planLlamaWeightTransform(names, config, options),
|
|
235
|
+
createContext(weights, plan) {
|
|
236
|
+
if (!("kind" in plan) || plan.kind !== "llama")
|
|
237
|
+
throw new Error(`weight transform rotation.llama received plan ${plan.id}`);
|
|
238
|
+
return createLlamaContext(weights, plan as LlamaWeightTransformPlan);
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Qwen3.5 trunk/VL adapter (R1 only because of the attention output gate). */
|
|
244
|
+
export function qwen35WeightTransform(options: QwenFoldOptions): WeightTransform {
|
|
245
|
+
return {
|
|
246
|
+
id: "rotation.qwen3_5",
|
|
247
|
+
plan: (names, config) =>
|
|
248
|
+
qwenTransformPlan(names, config, options.seed, false, options.prefix),
|
|
249
|
+
createContext(weights, plan) {
|
|
250
|
+
if (!("kind" in plan) || plan.kind !== "qwen3_5")
|
|
251
|
+
throw new Error(`weight transform rotation.qwen3_5 received plan ${plan.id}`);
|
|
252
|
+
return createQwenContext(weights, plan as QwenWeightTransformPlan);
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** Qwen3.5 MTP companion adapter. Must use the same seed as its trunk. */
|
|
258
|
+
export function qwenMtpWeightTransform(seed: number): WeightTransform {
|
|
259
|
+
return {
|
|
260
|
+
id: "rotation.qwen3_5_mtp",
|
|
261
|
+
plan: (names, config) => qwenTransformPlan(names, config, seed, true),
|
|
262
|
+
createContext(weights, plan) {
|
|
263
|
+
if (!("kind" in plan) || plan.kind !== "qwen3_5_mtp")
|
|
264
|
+
throw new Error(`weight transform rotation.qwen3_5_mtp received plan ${plan.id}`);
|
|
265
|
+
return createQwenContext(weights, plan as QwenWeightTransformPlan);
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** Select one of the three adapters from the source model and tensor schema. */
|
|
271
|
+
export function automaticRotationWeightTransform(
|
|
272
|
+
options: FoldOptions & { prefix?: string },
|
|
273
|
+
): WeightTransform {
|
|
274
|
+
return {
|
|
275
|
+
id: "rotation.auto",
|
|
276
|
+
plan(names, config) {
|
|
277
|
+
if (names.includes("fc.weight") && names.includes("pre_fc_norm_hidden.weight"))
|
|
278
|
+
return qwenTransformPlan(names, config, options.seed, true);
|
|
279
|
+
if (config.modelType === "qwen3_5")
|
|
280
|
+
return qwenTransformPlan(names, config, options.seed, false, options.prefix);
|
|
281
|
+
if (config.modelType === "llama")
|
|
282
|
+
return planLlamaWeightTransform(names, config, options);
|
|
283
|
+
throw new Error(`rotation transform: unsupported model_type ${config.modelType}`);
|
|
284
|
+
},
|
|
285
|
+
createContext(weights, plan) {
|
|
286
|
+
if (!("kind" in plan)) throw new Error(`rotation transform: invalid plan ${plan.id}`);
|
|
287
|
+
return plan.kind === "llama"
|
|
288
|
+
? createLlamaContext(weights, plan as LlamaWeightTransformPlan)
|
|
289
|
+
: createQwenContext(weights, plan as QwenWeightTransformPlan);
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
}
|
package/src/responses.ts
CHANGED
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
// - previous_response_id is echoed in the response when the request
|
|
18
18
|
// carried one (oracle always emits null).
|
|
19
19
|
|
|
20
|
+
import type {
|
|
21
|
+
CompletionEvent,
|
|
22
|
+
CompletionStreamProtocol,
|
|
23
|
+
} from "./serve/completion-sink";
|
|
24
|
+
|
|
20
25
|
// ---------------------------------------------------------------------
|
|
21
26
|
// Response store (previous_response_id resumption)
|
|
22
27
|
// ---------------------------------------------------------------------
|
|
@@ -38,7 +43,16 @@ const DEFAULT_MAX_BYTES = 32 * 1024 * 1024;
|
|
|
38
43
|
/** Process-local TTL + byte-capped LRU (port of response_store.py).
|
|
39
44
|
* Does not survive restarts — sufficient for local serving; anything
|
|
40
45
|
* sturdier means external storage, out of scope upstream too. */
|
|
41
|
-
export
|
|
46
|
+
export interface ResponseHistory {
|
|
47
|
+
readonly ttlMs: number;
|
|
48
|
+
readonly maxBytes: number;
|
|
49
|
+
readonly size: number;
|
|
50
|
+
readonly totalBytes: number;
|
|
51
|
+
put(id: string, entry: StoredResponse): void;
|
|
52
|
+
get(id: string): StoredResponse | null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class ResponseStore implements ResponseHistory {
|
|
42
56
|
#items = new Map<string, StoreEntry>(); // Map iterates in insertion order
|
|
43
57
|
#bytes = 0;
|
|
44
58
|
|
|
@@ -109,6 +123,24 @@ export class ResponseStore {
|
|
|
109
123
|
}
|
|
110
124
|
}
|
|
111
125
|
|
|
126
|
+
/** Conversation policy shared by direct and isolated application hosts. */
|
|
127
|
+
export function resolveResponsesConversation(body: ResponsesRequest, store: Pick<ResponseHistory, "get">) {
|
|
128
|
+
const previousId = body.previous_response_id ?? null;
|
|
129
|
+
if (previousId) {
|
|
130
|
+
const prior = store.get(previousId);
|
|
131
|
+
if (!prior) throw new Error(`previous_response_id '${previousId}' not found or expired`);
|
|
132
|
+
const next = typeof body.input === "string"
|
|
133
|
+
? body.input ? [{ type: "message", role: "user", content: body.input }] : []
|
|
134
|
+
: body.input ?? [];
|
|
135
|
+
body = { ...body, input: [...prior.input, ...outputItemsToInputItems(prior.output), ...next] as Array<Record<string, unknown>>,
|
|
136
|
+
instructions: body.instructions ?? prior.instructions ?? undefined };
|
|
137
|
+
}
|
|
138
|
+
return { body, previousId,
|
|
139
|
+
input: typeof body.input === "string" ? [{ type: "message", role: "user", content: body.input }] : [...body.input ?? []],
|
|
140
|
+
instructions: body.instructions ?? null,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
112
144
|
// ---------------------------------------------------------------------
|
|
113
145
|
// Request translation: Responses → Chat Completions
|
|
114
146
|
// ---------------------------------------------------------------------
|
|
@@ -167,6 +199,55 @@ function coerceText(content: unknown): string {
|
|
|
167
199
|
return parts.join("");
|
|
168
200
|
}
|
|
169
201
|
|
|
202
|
+
/** Convert a Responses message content array to chat-shaped content: text
|
|
203
|
+
* flattens, media TRANSLATES (`input_image` → `image_url`, incl. the
|
|
204
|
+
* Responses-standard string `image_url` field; video symmetrically), and
|
|
205
|
+
* unknown non-text parts REJECT loudly — a silent media drop answers
|
|
206
|
+
* confidently about content the model never saw (the anthropic.ts audio
|
|
207
|
+
* doctrine). Text-only arrays keep the legacy flattened-string shape. */
|
|
208
|
+
function coerceContent(content: unknown): string | Record<string, unknown>[] {
|
|
209
|
+
if (content == null) return "";
|
|
210
|
+
if (typeof content === "string") return content;
|
|
211
|
+
if (!Array.isArray(content)) return String(content);
|
|
212
|
+
const parts: Record<string, unknown>[] = [];
|
|
213
|
+
let hasMedia = false;
|
|
214
|
+
for (const part of content) {
|
|
215
|
+
if (typeof part === "string") {
|
|
216
|
+
parts.push({ type: "text", text: part });
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (!part || typeof part !== "object") continue;
|
|
220
|
+
const p = part as Record<string, unknown>;
|
|
221
|
+
if (p.type === "input_image" || p.type === "image_url") {
|
|
222
|
+
const url = typeof p.image_url === "string"
|
|
223
|
+
? p.image_url
|
|
224
|
+
: (p.image_url as { url?: string } | undefined)?.url;
|
|
225
|
+
if (typeof url !== "string")
|
|
226
|
+
throw new Error("input_image part missing image_url");
|
|
227
|
+
parts.push({ type: "image_url", image_url: { url } });
|
|
228
|
+
hasMedia = true;
|
|
229
|
+
} else if (p.type === "input_video" || p.type === "video_url") {
|
|
230
|
+
const url = typeof p.video_url === "string"
|
|
231
|
+
? p.video_url
|
|
232
|
+
: (p.video_url as { url?: string } | undefined)?.url;
|
|
233
|
+
if (typeof url !== "string")
|
|
234
|
+
throw new Error("input_video part missing video_url");
|
|
235
|
+
parts.push({ type: "video_url", video_url: { url } });
|
|
236
|
+
hasMedia = true;
|
|
237
|
+
} else if (p.text != null) {
|
|
238
|
+
parts.push({ type: "text", text: String(p.text) });
|
|
239
|
+
} else {
|
|
240
|
+
throw new Error(
|
|
241
|
+
`unsupported Responses content part type "${String(p.type)}" — ` +
|
|
242
|
+
`use input_text, input_image, or input_video`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (!hasMedia)
|
|
247
|
+
return parts.map((p) => String((p as { text?: unknown }).text ?? "")).join("");
|
|
248
|
+
return parts;
|
|
249
|
+
}
|
|
250
|
+
|
|
170
251
|
/** Convert a prior response's output array into input-shaped items for
|
|
171
252
|
* previous_response_id resumption (reasoning items dropped — replaying
|
|
172
253
|
* them invites the model to repeat itself). */
|
|
@@ -232,11 +313,14 @@ export function responsesToChatBody(body: ResponsesRequest): Record<string, unkn
|
|
|
232
313
|
}
|
|
233
314
|
// regular message item (explicit type or implicit by having role)
|
|
234
315
|
let role = String(item.role ?? "user");
|
|
235
|
-
const content = coerceText(item.content);
|
|
236
316
|
if (role === "system" || role === "developer") {
|
|
237
|
-
|
|
317
|
+
// System prompts are text by contract — flatten (media in a system
|
|
318
|
+
// item has no defined semantics on any surface we mirror).
|
|
319
|
+
const text = coerceText(item.content);
|
|
320
|
+
if (text) systemParts.push(text);
|
|
238
321
|
continue;
|
|
239
322
|
}
|
|
323
|
+
const content = coerceContent(item.content);
|
|
240
324
|
if (!["user", "assistant", "tool"].includes(role)) role = "user";
|
|
241
325
|
messages.push({ role, content });
|
|
242
326
|
}
|
|
@@ -722,6 +806,49 @@ export class ResponsesStreamTranslator {
|
|
|
722
806
|
}
|
|
723
807
|
}
|
|
724
808
|
|
|
809
|
+
/** Direct semantic-event adapter used by the server. `onComplete` receives
|
|
810
|
+
* the same response.completed payload stored for previous_response_id. */
|
|
811
|
+
export function createResponsesStreamProtocol(
|
|
812
|
+
model: string,
|
|
813
|
+
previousResponseId: string | null,
|
|
814
|
+
onComplete: (final: Record<string, unknown>) => void,
|
|
815
|
+
): CompletionStreamProtocol {
|
|
816
|
+
const translator = new ResponsesStreamTranslator(model, previousResponseId);
|
|
817
|
+
const chunk = (delta: Record<string, unknown>) => ({ choices: [{ delta }] });
|
|
818
|
+
return {
|
|
819
|
+
start: () => translator.addChunk(chunk({ role: "assistant", content: "" })),
|
|
820
|
+
addEvents(events: CompletionEvent[]) {
|
|
821
|
+
return events.flatMap((event) => {
|
|
822
|
+
if (event.type === "reasoning") {
|
|
823
|
+
return translator.addChunk(chunk({ reasoning: event.text }));
|
|
824
|
+
}
|
|
825
|
+
if (event.type === "content") {
|
|
826
|
+
return translator.addChunk(chunk({ content: event.text }));
|
|
827
|
+
}
|
|
828
|
+
return translator.addChunk(chunk({
|
|
829
|
+
tool_calls: event.calls.map((call, index) => ({ index, ...call })),
|
|
830
|
+
}));
|
|
831
|
+
});
|
|
832
|
+
},
|
|
833
|
+
finish(reason, usage) {
|
|
834
|
+
const frames = [
|
|
835
|
+
...translator.addChunk({ choices: [{ delta: {}, finish_reason: reason }], usage }),
|
|
836
|
+
...translator.finalize(),
|
|
837
|
+
];
|
|
838
|
+
onComplete(translator.finalResponse());
|
|
839
|
+
return frames;
|
|
840
|
+
},
|
|
841
|
+
error(message) {
|
|
842
|
+
return [sse("error", {
|
|
843
|
+
type: "error",
|
|
844
|
+
code: "server_error",
|
|
845
|
+
message,
|
|
846
|
+
param: null,
|
|
847
|
+
})];
|
|
848
|
+
},
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
|
|
725
852
|
/** Wrap our OpenAI SSE byte stream as a Responses SSE byte stream.
|
|
726
853
|
* onComplete fires after response.completed with the final payload so
|
|
727
854
|
* the route can store it for previous_response_id resumption. */
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
|
|
3
|
+
export type RuntimeKey = `MLX_BUN_${string}`;
|
|
4
|
+
export type RuntimeOverrides = Readonly<Partial<Record<RuntimeKey, string | undefined>>>;
|
|
5
|
+
|
|
6
|
+
export interface RuntimeConfig {
|
|
7
|
+
readonly values: Readonly<Record<string, string | undefined>>;
|
|
8
|
+
value(name: RuntimeKey): string | undefined;
|
|
9
|
+
flag(name: RuntimeKey, defaultOn: boolean): boolean;
|
|
10
|
+
number(name: RuntimeKey, fallback: number): number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Build one immutable runtime snapshot. Only mlx-bun-owned keys cross this
|
|
14
|
+
* boundary; feature code never reads or mutates process.env. */
|
|
15
|
+
export function createRuntimeConfig(
|
|
16
|
+
source: Readonly<Record<string, string | undefined>>,
|
|
17
|
+
): RuntimeConfig {
|
|
18
|
+
const values = Object.freeze(Object.fromEntries(
|
|
19
|
+
Object.entries(source).filter(([key, value]) =>
|
|
20
|
+
key.startsWith("MLX_BUN_") && value !== undefined),
|
|
21
|
+
));
|
|
22
|
+
return Object.freeze({
|
|
23
|
+
values,
|
|
24
|
+
value: (name: RuntimeKey) => values[name],
|
|
25
|
+
flag: (name: RuntimeKey, defaultOn: boolean) => {
|
|
26
|
+
const value = values[name];
|
|
27
|
+
return value === "1" ? true : value === "0" ? false : defaultOn;
|
|
28
|
+
},
|
|
29
|
+
number: (name: RuntimeKey, fallback: number) => {
|
|
30
|
+
const value = values[name];
|
|
31
|
+
if (value === undefined) return fallback;
|
|
32
|
+
const parsed = Number(value);
|
|
33
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let active = createRuntimeConfig(process.env);
|
|
39
|
+
const executionConfig = new AsyncLocalStorage<RuntimeConfig>();
|
|
40
|
+
|
|
41
|
+
/** Legacy kernels read through this port. A bound execution sees its own
|
|
42
|
+
* immutable snapshot across awaits, independently of later host settings. */
|
|
43
|
+
export function withRuntimeConfig<T>(config: RuntimeConfig, run: () => T): T {
|
|
44
|
+
return executionConfig.getStore() === config ? run() : executionConfig.run(config, run);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function runtimeConfig(): RuntimeConfig {
|
|
48
|
+
return executionConfig.getStore() ?? active;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function runtimeValue(name: RuntimeKey): string | undefined {
|
|
52
|
+
return runtimeConfig().value(name);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** On/off env flag: an explicit "1"/"0" always wins; otherwise `defaultOn`.
|
|
56
|
+
* (Formerly src/flags.ts `flagOn` — same resolver, one module.) */
|
|
57
|
+
export function flagOn(name: RuntimeKey, defaultOn: boolean): boolean {
|
|
58
|
+
return runtimeFlag(name, defaultOn);
|
|
59
|
+
}
|
|
60
|
+
export function runtimeFlag(name: RuntimeKey, defaultOn: boolean): boolean {
|
|
61
|
+
return runtimeConfig().flag(name, defaultOn);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function runtimeNumber(name: RuntimeKey, fallback: number): number {
|
|
65
|
+
return runtimeConfig().number(name, fallback);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function runtimeKey(name: string): RuntimeKey {
|
|
69
|
+
if (!name.startsWith("MLX_BUN_"))
|
|
70
|
+
throw new Error(`runtime flag must start with MLX_BUN_ (got ${name})`);
|
|
71
|
+
return name as RuntimeKey;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Replace selected values by installing a new frozen snapshot. The CLI uses
|
|
75
|
+
* this once while resolving flags; tests may use the returned restore hook.
|
|
76
|
+
* No environment mutation is involved. */
|
|
77
|
+
export function configureRuntime(overrides: RuntimeOverrides): () => void {
|
|
78
|
+
const previous = active;
|
|
79
|
+
active = createRuntimeConfig({ ...previous.values, ...overrides });
|
|
80
|
+
return () => { active = previous; };
|
|
81
|
+
}
|