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,18 @@
|
|
|
1
|
+
# src/lab — quarantined, no-oracle code
|
|
2
|
+
|
|
3
|
+
Everything here is a Lab-tier module (docs/design/unified-engine-frontier-plan.md):
|
|
4
|
+
no external oracle, off by default, kept only while a measurement decides its
|
|
5
|
+
fate (PLAN.md "Maintainability program", D6 darlings). Rules, gate-enforced by
|
|
6
|
+
`scripts/check-hygiene.ts` (check 11):
|
|
7
|
+
|
|
8
|
+
- nothing outside `src/lab/` may import from `src/lab/` except the edges listed
|
|
9
|
+
in `LAB_IMPORT_ALLOWLIST` — those are recorded debt, not permission;
|
|
10
|
+
- a new production dependency on a Lab module is a decision, not a default:
|
|
11
|
+
either promote the module out of the lab with an oracle/measurement, or
|
|
12
|
+
route it through an option seam.
|
|
13
|
+
|
|
14
|
+
| module | flag / entry | oracle |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `curve/` (curve sampler + designer page) | `--curve-*`, `/curves` | none (Lab) |
|
|
17
|
+
| `paged-kv/` | `--paged-kv` (serial-only) | parity vs plain KVCache (bit-exact), no measured win |
|
|
18
|
+
| `expert-trace/` | `MLX_BUN_EXPERT_TRACE` hook in gemma4 | closed study (expert-offload) |
|
|
@@ -88,7 +88,7 @@ button.ghost{background:var(--card);border:1px solid var(--bd);border-radius:8px
|
|
|
88
88
|
|
|
89
89
|
<script>
|
|
90
90
|
const ln=Math.log;
|
|
91
|
-
const UMIN=ln(1e-6); // bottom-left / plot floor (matches src/curve-sampler.ts CURVE_UMIN)
|
|
91
|
+
const UMIN=ln(1e-6); // bottom-left / plot floor (matches src/lab/curve/curve-sampler.ts CURVE_UMIN)
|
|
92
92
|
const ENGINE_BASE = location.protocol.startsWith("http") ? location.origin : "http://localhost:8080";
|
|
93
93
|
// ---- curve state: 5 movable control points, sorted ascending in p_in ----
|
|
94
94
|
function identityPoints(){ return [{x_pct:1e-4,y_pct:1e-4},{x_pct:0.1,y_pct:0.1},{x_pct:1,y_pct:1},{x_pct:9,y_pct:9},{x_pct:100,y_pct:100}]; }
|
|
@@ -102,7 +102,7 @@ const PROMPTS=[
|
|
|
102
102
|
"Describe the feeling of a city at 3am in one vivid sentence.",
|
|
103
103
|
];
|
|
104
104
|
|
|
105
|
-
// ---- math: monotone cubic (PCHIP), IDENTICAL to src/curve-sampler.ts ----
|
|
105
|
+
// ---- math: monotone cubic (PCHIP), IDENTICAL to src/lab/curve/curve-sampler.ts ----
|
|
106
106
|
const Lp=pt=>[ln(Math.max(pt.x_pct,1e-9)/100),ln(Math.max(pt.y_pct,1e-9)/100)];
|
|
107
107
|
function knotArrays(c){ const k=c.points.map(Lp).sort((a,b)=>a[0]-b[0]); return {X:k.map(q=>q[0]),Y:k.map(q=>q[1])}; }
|
|
108
108
|
function secants(c){ const {X,Y}=knotArrays(c),s=[]; for(let i=X.length-1;i>0;i--)s.push((Y[i]-Y[i-1])/(X[i]-X[i-1])); return s; }
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
// BELOW lowers them (renorm makes the literal number an intent); the SLOPE across
|
|
17
17
|
// a region sets how evenly the tokens inside it spread (flat<1 even, steep>1 separated).
|
|
18
18
|
|
|
19
|
-
import { MlxArray } from "
|
|
20
|
-
import * as ops from "
|
|
19
|
+
import { MlxArray } from "../../mlx/array";
|
|
20
|
+
import * as ops from "../../mlx/ops";
|
|
21
21
|
|
|
22
22
|
export interface CurvePoint { x_pct: number; y_pct: number; }
|
|
23
23
|
export interface CurveParams {
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Records every MoE router decision as JSONL — one record per router call:
|
|
4
4
|
// { c: callSeq, l: layerIdx, s: [B, L, k], i: [flattened uint32 expert ids] }
|
|
5
|
-
// Analyse with
|
|
5
|
+
// Analyse with analyze-expert-trace.ts (deleted 2026-08-23; git history) (coverage curve, working-set
|
|
6
6
|
// size, within-task stability, cross-task specialisation).
|
|
7
7
|
//
|
|
8
8
|
// Two ways to drive it:
|
|
9
9
|
// - env: `MLX_BUN_EXPERT_TRACE=<path> mlx-bun serve ...` (auto-starts here)
|
|
10
10
|
// - programmatic: beginExpertTrace(path) / endExpertTrace() per domain
|
|
11
|
-
// (
|
|
11
|
+
// (run-expert-trace.ts (deleted 2026-08-23; git history) uses this to trace several domains from
|
|
12
12
|
// one model load).
|
|
13
13
|
//
|
|
14
14
|
// Recording adds a per-call GPU->host sync (it reads the routed indices back),
|
|
@@ -17,8 +17,9 @@
|
|
|
17
17
|
// Router.forward is a single branch (zero overhead) — inert by default, same
|
|
18
18
|
// discipline as the slots flag.
|
|
19
19
|
|
|
20
|
-
import { Dtype } from "
|
|
21
|
-
import type { MlxArray } from "
|
|
20
|
+
import { Dtype } from "../../mlx/ffi";
|
|
21
|
+
import type { MlxArray } from "../../mlx/array";
|
|
22
|
+
import { runtimeValue } from "../../runtime-config";
|
|
22
23
|
|
|
23
24
|
let sink: Bun.FileSink | null = null;
|
|
24
25
|
let seq = 0;
|
|
@@ -61,7 +62,8 @@ export function recordRouting(layer: number, indices: MlxArray): void {
|
|
|
61
62
|
if (++written % 2000 === 0) sink.flush();
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
const expertTracePath = runtimeValue("MLX_BUN_EXPERT_TRACE");
|
|
66
|
+
if (expertTracePath) beginExpertTrace(expertTracePath);
|
|
65
67
|
|
|
66
68
|
process.on("exit", () => { try { endExpertTrace(); } catch { /* best-effort */ } });
|
|
67
69
|
process.on("SIGINT", () => { endExpertTrace(); process.exit(0); });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Paged KV cache — vLLM-style block-pool storage behind the standard Cache
|
|
2
|
-
// interface (docs/design/
|
|
2
|
+
// interface (docs/design/kv-cache.md). OPTIONAL and default-off
|
|
3
3
|
// (`--paged-kv` / GenerateOptions.pagedKv); v1 scope is serial batch=1
|
|
4
4
|
// decode on Gemma4-family plain full-attention layers, bf16 only.
|
|
5
5
|
//
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// block axis + transpose + reshape) and hand that to the unchanged
|
|
12
12
|
// ops.sdpa call site — identical bytes to what a plain KVCache would have
|
|
13
13
|
// fetched, so the paged path is gated bit-exact, not KL-tolerated
|
|
14
|
-
// (tests/paged-kv-parity.test.ts). The gather IS the cost: a full K/V copy
|
|
14
|
+
// (tests/parity/paged-kv-parity.test.ts). The gather IS the cost: a full K/V copy
|
|
15
15
|
// per step, pure bandwidth tax at batch=1 — v1 ships the abstraction for
|
|
16
16
|
// the batched/CoW follow-ups, not a speed win (see the design doc's
|
|
17
17
|
// Motivation, which says this honestly).
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
// gateway's #modelCachesBatchable, generated forwards' #matches() — must
|
|
22
22
|
// EXCLUDE paged caches and fall back to the monolith/uncompiled path.
|
|
23
23
|
|
|
24
|
-
import { MlxArray } from "
|
|
25
|
-
import { Dtype } from "
|
|
26
|
-
import * as ops from "
|
|
27
|
-
import { createCausalMask, type Cache, type Mask } from "
|
|
24
|
+
import { MlxArray } from "../../mlx/array";
|
|
25
|
+
import { Dtype } from "../../mlx/ffi";
|
|
26
|
+
import * as ops from "../../mlx/ops";
|
|
27
|
+
import { createCausalMask, type Cache, type Mask } from "../../model/gemma4-base";
|
|
28
28
|
|
|
29
29
|
/** Typed pool-exhaustion error: a generation outgrew its pool. Sizing from
|
|
30
30
|
* prompt+maxTokens at construction makes this unreachable in practice;
|
|
@@ -134,6 +134,9 @@ export class BlockPool {
|
|
|
134
134
|
* shape): head count / head dims / dtype come from the first k/v pair,
|
|
135
135
|
* so the wiring (maybePageKv) needs no per-model shape plumbing. */
|
|
136
136
|
export class PagedKVCache implements Cache {
|
|
137
|
+
/** Distinct kind: paged layout is serial-only and never merges into a
|
|
138
|
+
* batch, so no capability guard should ever match it as plain. */
|
|
139
|
+
signature(): string { return "kv:paged"; }
|
|
137
140
|
/** Matches KVCache.STEP: v1's growth granularity is a permutation of
|
|
138
141
|
* today's 256-token step into fixed reusable slots, not a new tuning
|
|
139
142
|
* axis (--paged-kv-block-size overrides for experiments). */
|
package/src/library.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** CPU-safe high-level entry. Native modules load only after bootstrap. */
|
|
2
|
+
export { createInferenceEngine } from "./engine/engine";
|
|
3
|
+
export { CancellationSource } from "./engine/cancellation";
|
|
4
|
+
export { createCompletionClient, createDirectHost } from "./client";
|
|
5
|
+
export type * from "./contracts/generation";
|
|
6
|
+
export type * from "./contracts/completion";
|
|
7
|
+
export type * from "./contracts/host";
|
|
8
|
+
|
|
9
|
+
/** Install/locate the native pack before importing the compatibility API. */
|
|
10
|
+
export async function initializeMlx(): Promise<typeof import("./index")> {
|
|
11
|
+
const { ensureNativeRuntime } = await import("./native-pack");
|
|
12
|
+
await ensureNativeRuntime();
|
|
13
|
+
return import("./index");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Own one local worker. Model resolution and native initialization remain in
|
|
17
|
+
* the existing CLI; importing this module does not start it or download weights. */
|
|
18
|
+
export async function openIsolatedHost(model: string, options: {
|
|
19
|
+
arguments?: readonly string[];
|
|
20
|
+
command?: readonly string[];
|
|
21
|
+
readyTimeoutMs?: number;
|
|
22
|
+
} = {}): Promise<import("./contracts/host").EngineHost<Request, Response>> {
|
|
23
|
+
const { EngineChild } = await import("./serve/isolate");
|
|
24
|
+
const { tmpdir } = await import("node:os");
|
|
25
|
+
const { join } = await import("node:path");
|
|
26
|
+
const { fileURLToPath } = await import("node:url");
|
|
27
|
+
const source = fileURLToPath(new URL("./cli.ts", import.meta.url));
|
|
28
|
+
if (!options.command && source.includes("$bunfs"))
|
|
29
|
+
throw new Error("a compiled library consumer must supply the mlx-bun executable as command");
|
|
30
|
+
const command = options.command ?? [process.execPath, source];
|
|
31
|
+
if (!command.length) throw new Error("engine command must not be empty");
|
|
32
|
+
const socketPath = join(tmpdir(), `mlx-bun-library-${crypto.randomUUID()}.sock`);
|
|
33
|
+
const host = new EngineChild({
|
|
34
|
+
argv: [...command,
|
|
35
|
+
"serve", "--model", model, ...options.arguments ?? [], "--unix", socketPath, "--no-open"],
|
|
36
|
+
socketPath, readyTimeoutMs: options.readyTimeoutMs,
|
|
37
|
+
});
|
|
38
|
+
try { await host.ready; return host; }
|
|
39
|
+
catch (error) { await host.close(); throw error; }
|
|
40
|
+
}
|
package/src/lora.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
14
14
|
import { resolve } from "node:path";
|
|
15
|
+
import { createHash } from "node:crypto";
|
|
15
16
|
import { ptr, read } from "bun:ffi";
|
|
16
17
|
import { MlxArray, cpuStream } from "./mlx/array";
|
|
17
18
|
import { C } from "./mlx/ffi";
|
|
@@ -198,6 +199,7 @@ export class AdapterManager {
|
|
|
198
199
|
readonly #mounted = new Map<string, AdapterInfo>();
|
|
199
200
|
/** Owned adapter arrays per id (disposed on unmount). */
|
|
200
201
|
readonly #arrays = new Map<string, MlxArray[]>();
|
|
202
|
+
readonly #revisions = new Map<string, string>();
|
|
201
203
|
|
|
202
204
|
constructor(model: RuntimeModel) {
|
|
203
205
|
this.#model = model;
|
|
@@ -216,6 +218,11 @@ export class AdapterManager {
|
|
|
216
218
|
|
|
217
219
|
const weightsFile = adapterWeightsFile(path);
|
|
218
220
|
const { scale, rank: configRank, rsLora } = await readAdapterScale(path);
|
|
221
|
+
// Hash once at mount, before native allocation. Reusing an adapter name
|
|
222
|
+
// for different weights or scale must never reuse its prefix/checkpoint.
|
|
223
|
+
const digest = createHash("sha256").update(JSON.stringify({ scale, rank: configRank, rsLora }));
|
|
224
|
+
for await (const chunk of Bun.file(weightsFile).stream()) digest.update(chunk);
|
|
225
|
+
const revision = digest.digest("hex");
|
|
219
226
|
const tensors = loadAdapterTensors(weightsFile);
|
|
220
227
|
const targets = this.#model.loraTargets();
|
|
221
228
|
|
|
@@ -347,6 +354,7 @@ export class AdapterManager {
|
|
|
347
354
|
ramBytes,
|
|
348
355
|
};
|
|
349
356
|
this.#mounted.set(id, info);
|
|
357
|
+
this.#revisions.set(id, revision);
|
|
350
358
|
this.#arrays.set(id, validated.flatMap(({ lw }) => [lw.a, lw.b]));
|
|
351
359
|
return info;
|
|
352
360
|
}
|
|
@@ -355,6 +363,7 @@ export class AdapterManager {
|
|
|
355
363
|
* stay in place for other adapters, like the reference. */
|
|
356
364
|
unmount(id: string): number {
|
|
357
365
|
if (!this.#mounted.delete(id)) return 0;
|
|
366
|
+
this.#revisions.delete(id);
|
|
358
367
|
let removed = 0;
|
|
359
368
|
for (const linear of this.#model.loraTargets().values()) {
|
|
360
369
|
if (linear.adapters?.delete(id)) removed++;
|
|
@@ -366,6 +375,15 @@ export class AdapterManager {
|
|
|
366
375
|
return removed;
|
|
367
376
|
}
|
|
368
377
|
|
|
378
|
+
/** Ordered, content-addressed namespace for the actual mounted composition. */
|
|
379
|
+
cacheNamespace(ids: readonly string[]): string {
|
|
380
|
+
return ids.map((id) => {
|
|
381
|
+
const revision = this.#revisions.get(id);
|
|
382
|
+
if (!revision) throw new Error(`adapter ${id} is no longer mounted`);
|
|
383
|
+
return `${id}@${revision}`;
|
|
384
|
+
}).join("+");
|
|
385
|
+
}
|
|
386
|
+
|
|
369
387
|
list(): AdapterInfo[] {
|
|
370
388
|
return [...this.#mounted.values()];
|
|
371
389
|
}
|
package/src/media-fetch.ts
CHANGED
|
@@ -17,10 +17,11 @@
|
|
|
17
17
|
// preserving the logical Host header and HTTPS SNI, so the transport cannot
|
|
18
18
|
// re-resolve to a private address between validation and connect.
|
|
19
19
|
//
|
|
20
|
-
// This module must stay free of mlx imports so tests/media-fetch.test.ts
|
|
20
|
+
// This module must stay free of mlx imports so tests/unit/media-fetch.test.ts
|
|
21
21
|
// runs model-free.
|
|
22
22
|
|
|
23
23
|
import { lookup } from "node:dns/promises";
|
|
24
|
+
import { runtimeValue } from "./runtime-config";
|
|
24
25
|
|
|
25
26
|
export interface MediaFetchPolicy {
|
|
26
27
|
/** Permit private/loopback/link-local destinations (LAN hosts). */
|
|
@@ -71,7 +72,7 @@ export interface RestrictedFetchResult {
|
|
|
71
72
|
|
|
72
73
|
export function defaultMediaFetchPolicy(): MediaFetchPolicy {
|
|
73
74
|
return {
|
|
74
|
-
allowPrivate:
|
|
75
|
+
allowPrivate: runtimeValue("MLX_BUN_ALLOW_PRIVATE_MEDIA") === "1",
|
|
75
76
|
// 10 s / 64 MB: well above what a 30 s audio clip (~5 MB of 16 kHz
|
|
76
77
|
// WAV, less compressed) or any supported image needs.
|
|
77
78
|
timeoutMs: 10_000,
|
|
@@ -405,10 +406,19 @@ export async function fetchRestrictedHttpBytes(
|
|
|
405
406
|
* redirect hop re-validated, one wall-clock timeout, and a streaming
|
|
406
407
|
* size cap. Throws Error with a client-presentable message — callers
|
|
407
408
|
* surface it as a 400 (the prompt-build catch in server.ts). */
|
|
409
|
+
/** Video clips are legitimately larger than images/audio: same SSRF guard
|
|
410
|
+
* and timeout discipline, quadruple the body cap (a 30 s 1080p H.264 clip
|
|
411
|
+
* runs tens of MB; frame sampling truncates long clips server-side). */
|
|
412
|
+
export function videoMediaFetchPolicy(): MediaFetchPolicy {
|
|
413
|
+
return { ...defaultMediaFetchPolicy(), maxBytes: 256 * 1024 * 1024 };
|
|
414
|
+
}
|
|
415
|
+
|
|
408
416
|
export async function fetchMediaBytes(
|
|
409
417
|
url: string,
|
|
410
|
-
kind: "image" | "audio",
|
|
411
|
-
policy: MediaFetchPolicy =
|
|
418
|
+
kind: "image" | "audio" | "video",
|
|
419
|
+
policy: MediaFetchPolicy = kind === "video"
|
|
420
|
+
? videoMediaFetchPolicy()
|
|
421
|
+
: defaultMediaFetchPolicy(),
|
|
412
422
|
): Promise<Uint8Array> {
|
|
413
423
|
if (url.startsWith("data:")) {
|
|
414
424
|
const comma = url.indexOf(",");
|
|
@@ -416,6 +426,12 @@ export async function fetchMediaBytes(
|
|
|
416
426
|
const meta = url.slice(0, comma);
|
|
417
427
|
const body = url.slice(comma + 1);
|
|
418
428
|
if (!meta.includes("base64")) throw new Error("data: URL must be base64");
|
|
429
|
+
// The same body cap as the HTTP path — inline payloads must not become
|
|
430
|
+
// the uncapped route (base64 inflates 4/3, so check pre-decode too).
|
|
431
|
+
if (body.length * 0.75 > policy.maxBytes)
|
|
432
|
+
throw new Error(
|
|
433
|
+
`${kind} data: URL exceeds the ${Math.round(policy.maxBytes / 1024 / 1024)} MB cap`,
|
|
434
|
+
);
|
|
419
435
|
return Uint8Array.from(Buffer.from(body, "base64"));
|
|
420
436
|
}
|
|
421
437
|
return (
|
package/src/memory/article.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// The Dreaming write pipeline emits Wikipedia-shaped articles: each entity gets
|
|
4
4
|
// one Markdown file with a fixed top-to-bottom skeleton —
|
|
5
5
|
// H1 → series banner → infobox → lead → sections → See also → Notes → References
|
|
6
|
-
// (see docs/design/
|
|
6
|
+
// (see docs/design/dreaming-nightly-pipeline.md and docs/design/dreaming-nightly-pipeline.md).
|
|
7
7
|
// This module reads that grammar deterministically: the structured outputs the
|
|
8
8
|
// read side traverses (infobox key-value facts, the [[wikilink]] graph, footnote
|
|
9
9
|
// bijection) are parsed here, never by the model.
|
package/src/memory/chunk.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
//
|
|
17
17
|
// Re-chunk only conversations whose updated_at > chunked_at (NULL chunked_at = a
|
|
18
18
|
// never-segmented conversation). Setting chunked_at after a successful run makes
|
|
19
|
-
// re-running a no-op. See docs/design/
|
|
19
|
+
// re-running a no-op. See docs/design/dreaming-nightly-pipeline.md → P5-T2.
|
|
20
20
|
|
|
21
21
|
import { MemoryStore, chunkId } from "./db";
|
|
22
22
|
import { callLocal, type LocalInput } from "./model";
|
package/src/memory/model.ts
CHANGED
|
@@ -24,12 +24,9 @@
|
|
|
24
24
|
// server and to the trainer's prompt-region render (dataset.ts:98-101).
|
|
25
25
|
|
|
26
26
|
import { existsSync, readdirSync } from "node:fs";
|
|
27
|
-
import { loadTaskModel, greedyDecodeBitExact, type TaskModel } from "../eval/runner";
|
|
28
27
|
import type { ChatMessage, ChatTemplate } from "../chat-template";
|
|
29
28
|
import type { LoadedTokenizer } from "../tokenizer";
|
|
30
|
-
import {
|
|
31
|
-
import * as ops from "../mlx/ops";
|
|
32
|
-
import type { MlxArray } from "../mlx/array";
|
|
29
|
+
import { runtimeValue } from "../runtime-config";
|
|
33
30
|
|
|
34
31
|
const HF_HUB = `${process.env.HOME}/.cache/huggingface/hub`;
|
|
35
32
|
const E4B_REPO = "models--mlx-community--gemma-4-e4b-it-OptiQ-4bit";
|
|
@@ -37,7 +34,7 @@ const E4B_REPO = "models--mlx-community--gemma-4-e4b-it-OptiQ-4bit";
|
|
|
37
34
|
/** Resolve the e4b snapshot dir by globbing snapshots/ for the one carrying
|
|
38
35
|
* config.json — so a freshly-downloaded model needs no hardcoded commit hash.
|
|
39
36
|
* Returns an _unresolved sentinel (precheck → STOP) until the download lands.
|
|
40
|
-
* Mirrors tests/paths.ts hfSnapshot / SNAPSHOT_E4B, inlined to keep src self-
|
|
37
|
+
* Mirrors tests/support/paths.ts hfSnapshot / SNAPSHOT_E4B, inlined to keep src self-
|
|
41
38
|
* contained (no src→tests dependency). */
|
|
42
39
|
function resolveE4bSnapshot(): string {
|
|
43
40
|
const base = `${HF_HUB}/${E4B_REPO}/snapshots`;
|
|
@@ -139,183 +136,48 @@ export function memoryPromptIds(
|
|
|
139
136
|
/** Async mutex: acquire() resolves to a release fn; releases run FIFO. Serializes
|
|
140
137
|
* memory generation ops so the global `loraState.active` is owned exclusively for
|
|
141
138
|
* one op's lifetime (set for the chunk batch, reset after). */
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const gate = new Promise<void>((r) => { release = r; });
|
|
147
|
-
const wait = this.#tail;
|
|
148
|
-
this.#tail = this.#tail.then(() => gate);
|
|
149
|
-
return wait.then(() => release);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
interface MemoryRuntime {
|
|
154
|
-
tm: TaskModel;
|
|
155
|
-
template: ChatTemplate;
|
|
156
|
-
scheduler: BatchScheduler;
|
|
157
|
-
/** True once the `memory-chunk` adapter is mounted on the shared model. */
|
|
158
|
-
hasChunkAdapter: boolean;
|
|
139
|
+
export interface MemoryCompletionRequest {
|
|
140
|
+
readonly stage: string;
|
|
141
|
+
readonly input: LocalInput;
|
|
142
|
+
readonly maxTokens: number;
|
|
159
143
|
}
|
|
144
|
+
export type MemoryCompletionClient = import("../contracts/completion").BatchCompletionClient<MemoryCompletionRequest, string>;
|
|
160
145
|
|
|
161
146
|
/** Max rows in a memory batch (continuous-batching width). 1 disables batching
|
|
162
147
|
* (callLocalBatch then loops on the bit-exact greedy fallback).
|
|
163
148
|
* Default 1 (serial): batching measured 1.7-1.9x SLOWER for the real
|
|
164
149
|
* extract/chunk workload (heterogeneous prefills pad) and can diverge on
|
|
165
|
-
* near-ties — see docs/design/
|
|
150
|
+
* near-ties — see docs/design/dreaming-nightly-pipeline.md "Verification results".
|
|
166
151
|
* Opt back in with MLX_BUN_MEMORY_BATCH=8 if a length-bucketed scheduler
|
|
167
152
|
* lands. (Decision: Josh, 2026-07-01.) */
|
|
168
153
|
export function memoryBatchSize(): number {
|
|
169
|
-
const n = Number(
|
|
154
|
+
const n = Number(runtimeValue("MLX_BUN_MEMORY_BATCH") ?? "1");
|
|
170
155
|
return Number.isFinite(n) && n >= 1 ? Math.floor(n) : 1;
|
|
171
156
|
}
|
|
172
157
|
|
|
173
|
-
function requireModel(): void {
|
|
174
|
-
if (!existsSync(`${MODEL_ID}/config.json`)) {
|
|
175
|
-
throw new Error(
|
|
176
|
-
`memory: Gemma-4-e4b is not downloaded (looked under ${HF_HUB}/${E4B_REPO}/snapshots). ` +
|
|
177
|
-
`Fetch it first:\n HF_HUB_DISABLE_XET=1 hf download mlx-community/gemma-4-e4b-it-OptiQ-4bit`,
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
let runtimePromise: Promise<MemoryRuntime> | null = null;
|
|
183
|
-
const opLock = new AsyncMutex(); // serializes whole memory ops (loraState ownership)
|
|
184
|
-
const schedLock = new AsyncMutex(); // the scheduler's exclusive-GPU lock
|
|
185
|
-
|
|
186
|
-
/** Lazily load the ONE shared model + mount memory-chunk + build the scheduler.
|
|
187
|
-
* Never auto-downloads; throws (with the fetch hint) until the snapshot lands. */
|
|
188
|
-
async function getRuntime(): Promise<MemoryRuntime> {
|
|
189
|
-
if (!runtimePromise) {
|
|
190
|
-
runtimePromise = (async () => {
|
|
191
|
-
requireModel();
|
|
192
|
-
const tm = await loadTaskModel(MODEL_ID); // base e4b, no adapter
|
|
193
|
-
if (!tm.template) throw new Error(`memory: ${MODEL_ID} has no chat template`);
|
|
194
|
-
let hasChunkAdapter = false;
|
|
195
|
-
const chunkDir = adapterDirFor("chunk");
|
|
196
|
-
if (chunkDir) {
|
|
197
|
-
// Mount ONCE; activation is per-call via loraState.active (see decodeGreedy
|
|
198
|
-
// / batchDecode). Mounting alone runs base — it must be activated.
|
|
199
|
-
const { AdapterManager } = await import("../lora");
|
|
200
|
-
await new AdapterManager(tm.model).mount("memory-chunk", chunkDir);
|
|
201
|
-
hasChunkAdapter = true;
|
|
202
|
-
}
|
|
203
|
-
const scheduler = new BatchScheduler(tm.model, {
|
|
204
|
-
maxBatch: memoryBatchSize(),
|
|
205
|
-
lock: { acquire: () => schedLock.acquire() },
|
|
206
|
-
});
|
|
207
|
-
return { tm, template: tm.template, scheduler, hasChunkAdapter };
|
|
208
|
-
})();
|
|
209
|
-
}
|
|
210
|
-
return runtimePromise;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/** The adapters to activate for a stage. Only `chunk` is adapter-bound (and only
|
|
214
|
-
* when `memory-chunk` is mounted); every base stage runs with `active = []`. */
|
|
215
|
-
function activeFor(stage: string, rt: MemoryRuntime): string[] {
|
|
216
|
-
return stage === "chunk" && rt.hasChunkAdapter ? ["memory-chunk"] : [];
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/** One bit-exact greedy decode for a stage (raw-forward argmax, runner parity).
|
|
220
|
-
* Sets the stage's adapter for the call and resets `active` to [] after. */
|
|
221
|
-
function decodeGreedy(rt: MemoryRuntime, stage: string, input: LocalInput, maxTokens: number): string {
|
|
222
|
-
const active = activeFor(stage, rt);
|
|
223
|
-
rt.tm.model.loraState.active = active;
|
|
224
|
-
const ids = memoryPromptIds(stage, input, rt.tm.tokenizer, rt.template);
|
|
225
|
-
try {
|
|
226
|
-
return greedyDecodeBitExact(
|
|
227
|
-
{ ...rt.tm, activeAdapters: active.length ? active : undefined },
|
|
228
|
-
ids,
|
|
229
|
-
maxTokens,
|
|
230
|
-
);
|
|
231
|
-
} finally {
|
|
232
|
-
rt.tm.model.loraState.active = [];
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/** Batched decode for N independent inputs of ONE stage. Sets the stage adapter
|
|
237
|
-
* globally for the whole batch (the scheduler reads `loraState.active` per
|
|
238
|
-
* forward, so all rows get it uniformly — a batch is necessarily single-adapter),
|
|
239
|
-
* submits every row to the shared scheduler with a greedy per-row sampler, and
|
|
240
|
-
* resets `active` after all rows finish. Order-preserving: out[i] ↔ inputs[i].
|
|
241
|
-
*
|
|
242
|
-
* Decode-path caveat: this samples via forwardHidden/logitsFromHidden (the
|
|
243
|
-
* scheduler), which can diverge from the runner's raw-forward greedy on near-ties
|
|
244
|
-
* past ~32 tokens. For the JSON/binary memory stages (validated by
|
|
245
|
-
* well-formedness) this is acceptable; the single-call fallback stays bit-exact. */
|
|
246
|
-
async function batchDecode(
|
|
247
|
-
rt: MemoryRuntime,
|
|
248
|
-
stage: string,
|
|
249
|
-
inputs: LocalInput[],
|
|
250
|
-
maxTokens: number,
|
|
251
|
-
): Promise<string[]> {
|
|
252
|
-
const active = activeFor(stage, rt);
|
|
253
|
-
rt.tm.model.loraState.active = active;
|
|
254
|
-
const eos = rt.tm.config.eosTokenIds;
|
|
255
|
-
const greedySample: RowSampler = (logits1V: MlxArray) => ops.argmaxAxis(logits1V, -1);
|
|
256
|
-
try {
|
|
257
|
-
return await Promise.all(
|
|
258
|
-
inputs.map((inp) => {
|
|
259
|
-
const ids = memoryPromptIds(stage, inp, rt.tm.tokenizer, rt.template);
|
|
260
|
-
const toks: number[] = [];
|
|
261
|
-
return rt.scheduler
|
|
262
|
-
.submit({
|
|
263
|
-
promptIds: ids,
|
|
264
|
-
maxTokens,
|
|
265
|
-
eosTokenIds: eos,
|
|
266
|
-
sample: greedySample,
|
|
267
|
-
onToken: (t) => { toks.push(t); },
|
|
268
|
-
})
|
|
269
|
-
.then(() => rt.tm.tokenizer.decode(toks, true));
|
|
270
|
-
}),
|
|
271
|
-
);
|
|
272
|
-
} finally {
|
|
273
|
-
rt.tm.model.loraState.active = [];
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// ---------------------------------------------------------------------------
|
|
278
|
-
// Public seams
|
|
279
|
-
// ---------------------------------------------------------------------------
|
|
280
158
|
|
|
281
|
-
/**
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
):
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
return decodeGreedy(rt, stage, input, opts?.maxTokens ?? 256);
|
|
294
|
-
} finally {
|
|
295
|
-
release();
|
|
296
|
-
}
|
|
159
|
+
/** One configured client per pipeline. Importing this module does not load MLX. */
|
|
160
|
+
export function createMemoryCalls(client: MemoryCompletionClient) {
|
|
161
|
+
return {
|
|
162
|
+
callLocal(stage: string, input: LocalInput, opts?: { maxTokens?: number }): Promise<string> {
|
|
163
|
+
return client.complete({ stage, input, maxTokens: opts?.maxTokens ?? 256 });
|
|
164
|
+
},
|
|
165
|
+
callLocalBatch(stage: string, inputs: LocalInput[], opts?: { maxTokens?: number }): Promise<string[]> {
|
|
166
|
+
if (!inputs.length) return Promise.resolve([]);
|
|
167
|
+
return client.completeBatch(inputs.map((input) => ({ stage, input, maxTokens: opts?.maxTokens ?? 256 })));
|
|
168
|
+
},
|
|
169
|
+
};
|
|
297
170
|
}
|
|
298
171
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
try {
|
|
312
|
-
if (inputs.length === 1 || memoryBatchSize() <= 1) {
|
|
313
|
-
const out: string[] = [];
|
|
314
|
-
for (const inp of inputs) out.push(decodeGreedy(rt, stage, inp, maxTokens));
|
|
315
|
-
return out;
|
|
316
|
-
}
|
|
317
|
-
return await batchDecode(rt, stage, inputs, maxTokens);
|
|
318
|
-
} finally {
|
|
319
|
-
release();
|
|
320
|
-
}
|
|
321
|
-
}
|
|
172
|
+
const defaultCalls = createMemoryCalls({
|
|
173
|
+
async complete(request) {
|
|
174
|
+
const { memoryCompletionClient } = await import("../backends/mlx/memory-client");
|
|
175
|
+
return memoryCompletionClient.complete(request);
|
|
176
|
+
},
|
|
177
|
+
async completeBatch(requests) {
|
|
178
|
+
const { memoryCompletionClient } = await import("../backends/mlx/memory-client");
|
|
179
|
+
return memoryCompletionClient.completeBatch(requests);
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
export const callLocal = defaultCalls.callLocal;
|
|
183
|
+
export const callLocalBatch = defaultCalls.callLocalBatch;
|
package/src/memory/prompts.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// Topics_to_Ignore.md) and are read in at synthesis time so the system governs
|
|
8
8
|
// itself in its own substrate.
|
|
9
9
|
//
|
|
10
|
-
// See docs/design/
|
|
10
|
+
// See docs/design/dreaming-nightly-pipeline.md → "Synthesis runs on the local model".
|
|
11
11
|
|
|
12
12
|
import { readFileSync } from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
package/src/memory/rest.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// rest of server.ts's /api/* conventions. Route dispatch (matching
|
|
12
12
|
// url.pathname + method) lives in server.ts; this file is the pure handler
|
|
13
13
|
// bodies so they're unit-testable without booting a model context (see
|
|
14
|
-
// tests/memory-rest.test.ts).
|
|
14
|
+
// tests/using/memory-rest.test.ts).
|
|
15
15
|
|
|
16
16
|
import { realpath } from "node:fs/promises";
|
|
17
17
|
import { tmpdir } from "node:os";
|
package/src/memory/schedule.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// it. That job runs the full synthesis DAG and produces/updates articles on the
|
|
12
12
|
// schedule with no further configuration.
|
|
13
13
|
//
|
|
14
|
-
// See docs/design/
|
|
14
|
+
// See docs/design/dreaming-nightly-pipeline.md → "Scheduling (launchd)".
|
|
15
15
|
|
|
16
16
|
import { spawn } from "node:child_process";
|
|
17
17
|
import { mkdir, rm, writeFile } from "node:fs/promises";
|
package/src/memory/stages.ts
CHANGED
|
@@ -356,7 +356,10 @@ export async function runExtractStage(
|
|
|
356
356
|
// SERIAL fallback (injected `call`, single chunk, or batching disabled).
|
|
357
357
|
let extracted = 0;
|
|
358
358
|
for (const id of targetIds) {
|
|
359
|
-
|
|
359
|
+
// Pass the (possibly empty) policy through: `|| undefined` made extractEntities
|
|
360
|
+
// re-load Meta/Entities.md and THROW on a vault without it, while the batched
|
|
361
|
+
// path above proceeds with "" — the serial path must match.
|
|
362
|
+
await extractEntities(store, id, { resolver, policy, call: opts.call });
|
|
360
363
|
extracted++;
|
|
361
364
|
if (extracted % 10 === 0) {
|
|
362
365
|
opts.onEvent?.({ type: "log", message: ` extracted ${extracted}/${target} chunks` });
|
package/src/memory/vault.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// an already-working system at real scale — they're pure filesystem functions
|
|
10
10
|
// with no MCP coupling, so they drop straight in. We keep lucien's good
|
|
11
11
|
// descriptive concepts (articles, [[wikilinks]], Meta governance pages,
|
|
12
|
-
// conv: citations) and drop the mythology. See docs/design/
|
|
12
|
+
// conv: citations) and drop the mythology. See docs/design/dreaming-nightly-pipeline.md.
|
|
13
13
|
//
|
|
14
14
|
// M0 is the read path: setup the vault, then list / read / search / index it.
|
|
15
15
|
// Synthesis (writing articles from conversations) is M1 and lives elsewhere.
|
|
@@ -19,12 +19,13 @@ import { homedir } from "node:os";
|
|
|
19
19
|
import { isAbsolute, join } from "node:path";
|
|
20
20
|
import { spawn } from "node:child_process";
|
|
21
21
|
import { isFenceLine } from "./article";
|
|
22
|
+
import { runtimeValue } from "../runtime-config";
|
|
22
23
|
|
|
23
24
|
// ---- paths -----------------------------------------------------------
|
|
24
25
|
|
|
25
26
|
/** Root of the memory vault: ~/.mlx-bun/wiki (override with MLX_BUN_WIKI). */
|
|
26
27
|
export function vaultRoot(): string {
|
|
27
|
-
const override =
|
|
28
|
+
const override = runtimeValue("MLX_BUN_WIKI")?.trim();
|
|
28
29
|
if (override) return override.replace(/^~(?=$|[/\\])/, homedir());
|
|
29
30
|
return join(homedir(), ".mlx-bun", "wiki");
|
|
30
31
|
}
|
|
@@ -986,10 +987,8 @@ const REFERENCE_LINKS: { name: string; source: string }[] = [
|
|
|
986
987
|
{ name: "mlx-bun_Server_API", source: join(REPO_ROOT, "docs", "reference", "server-api.md") },
|
|
987
988
|
{ name: "mlx-bun_Server_Config", source: join(REPO_ROOT, "docs", "reference", "server-config.md") },
|
|
988
989
|
{ name: "mlx-bun_Library_API", source: join(REPO_ROOT, "docs", "reference", "library-api.md") },
|
|
989
|
-
{ name: "mlx-bun_Embedding", source: join(REPO_ROOT, "docs", "reference", "embedding.md") },
|
|
990
990
|
{ name: "mlx-bun_Distribution", source: join(REPO_ROOT, "docs", "reference", "distribution.md") },
|
|
991
991
|
{ name: "mlx-bun_Training", source: join(REPO_ROOT, "docs", "reference", "training.md") },
|
|
992
|
-
{ name: "mlx-bun_ORPO_Quickstart", source: join(REPO_ROOT, "docs", "reference", "orpo-quickstart.md") },
|
|
993
992
|
{ name: "mlx-bun_Product_Roadmap", source: join(REPO_ROOT, "docs", "planning", "PRODUCT_ROADMAP.md") },
|
|
994
993
|
];
|
|
995
994
|
|