mlx-bun 0.2.0 → 0.4.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 -588
- package/docs/README.md +94 -0
- package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
- package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
- package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
- package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
- package/docs/archive/investigations/openjarvis-fit.md +198 -0
- package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
- package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +1092 -0
- package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
- package/docs/archive/planning/release-notes-v0.3.0.md +35 -0
- package/docs/design/batching.md +1841 -0
- package/docs/design/decode-speed-program.md +2346 -169
- package/docs/design/dreaming-nightly-pipeline.md +675 -282
- package/docs/design/generic-model-support.md +655 -334
- package/docs/design/kv-cache.md +824 -0
- package/docs/design/orpo-training.md +673 -1239
- package/docs/design/speculative-decoding.md +1990 -0
- package/docs/design/turboquant.md +2212 -0
- package/docs/design/unified-engine-frontier-plan.md +1833 -727
- package/docs/design/web-chat-redesign.md +666 -1083
- package/docs/planning/PRODUCT_ROADMAP.md +50 -1
- package/docs/planning/release-notes-v0.4.0.md +45 -0
- package/docs/planning/video-series.md +2 -2
- package/docs/reference/benchmarks.md +3613 -0
- package/docs/reference/cli.md +434 -160
- package/docs/reference/distribution.md +328 -182
- package/docs/reference/environment.md +398 -0
- package/docs/reference/glossary.md +39 -0
- package/docs/reference/library-api.md +566 -168
- package/docs/reference/memory.md +227 -64
- package/docs/reference/models.md +113 -6
- package/docs/reference/server-api.md +944 -429
- package/docs/reference/server-config.md +740 -338
- package/docs/reference/training.md +393 -254
- package/docs/reference/troubleshooting.md +158 -0
- package/package.json +9 -4
- package/src/audio/decode.ts +2 -2
- package/src/audio/features.ts +2 -2
- package/src/backends/mlx/assistant-target.ts +46 -0
- package/src/backends/mlx/autoregressive-draft-rows.ts +120 -0
- package/src/backends/mlx/autoregressive.ts +108 -0
- package/src/backends/mlx/batch-group.ts +1790 -0
- package/src/backends/mlx/cache-attachment.ts +67 -0
- package/src/backends/mlx/cache-layout.ts +31 -0
- package/src/backends/mlx/checkpoint-state.ts +53 -0
- package/src/backends/mlx/continuation-persistence.ts +106 -0
- package/src/backends/mlx/continuation-request.ts +43 -0
- package/src/backends/mlx/continuation.ts +77 -0
- package/src/backends/mlx/diffusion.ts +39 -0
- package/src/backends/mlx/draft-target.ts +32 -0
- package/src/backends/mlx/evaluation.ts +105 -0
- package/src/backends/mlx/fill-append.ts +45 -0
- package/src/backends/mlx/full-kv-row-append.ts +32 -0
- package/src/backends/mlx/full-kv-row-donor.ts +54 -0
- package/src/backends/mlx/full-transitioning-kv-rows.ts +65 -0
- package/src/backends/mlx/gateway-binding.ts +130 -0
- package/src/backends/mlx/graph.ts +38 -0
- package/src/backends/mlx/kv-codec.ts +9 -0
- package/src/backends/mlx/kv-maintenance.ts +133 -0
- package/src/backends/mlx/kv-tensor-rows.ts +212 -0
- package/src/backends/mlx/memory-client.ts +189 -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-cohort.ts +89 -0
- package/src/backends/mlx/prefill-rows.ts +200 -0
- package/src/backends/mlx/prefill.ts +33 -0
- package/src/backends/mlx/projected-context-rows.ts +72 -0
- package/src/backends/mlx/request-policy.ts +20 -0
- package/src/backends/mlx/request-state-policy.ts +41 -0
- package/src/backends/mlx/rollback.ts +89 -0
- package/src/backends/mlx/row-sampling.ts +49 -0
- package/src/backends/mlx/serial-executor.ts +242 -0
- package/src/backends/mlx/speculative-group.ts +359 -0
- package/src/backends/mlx/speculative-round.ts +161 -0
- package/src/backends/mlx/speculative.ts +114 -0
- package/src/backends/mlx/state-rows.ts +104 -0
- package/src/backends/mlx/state-views.ts +46 -0
- package/src/backends/mlx/target-layout-capability.ts +35 -0
- package/src/backends/mlx/text-engine.ts +73 -0
- package/src/backends/mlx/transitioning-kv-rows.ts +165 -0
- package/src/cli.ts +66 -58
- package/src/client.ts +66 -0
- package/src/config.ts +21 -4
- package/src/contracts/completion.ts +16 -0
- package/src/contracts/execution.ts +60 -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/prefix-cache.ts +23 -0
- package/src/contracts/resources.ts +25 -0
- package/src/contracts/sampling.ts +23 -0
- package/src/contracts/scheduling.ts +45 -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 +53 -0
- package/src/engine/resources.ts +53 -0
- package/src/engine/scheduler.ts +72 -0
- package/src/engine/session.ts +247 -0
- package/src/eval/README.md +44 -1
- package/src/eval/kl.ts +236 -3
- package/src/eval/reference-logits.ts +207 -0
- package/src/eval/runner.ts +8 -96
- 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 +30 -16
- package/src/generate.ts +709 -417
- package/src/grammar.ts +12 -7
- package/src/harness-pi.ts +14 -33
- package/src/hub-rest.ts +4 -4
- package/src/index.ts +7 -0
- package/src/inference/denoising.ts +17 -0
- package/src/inference/draft-acceptance.ts +41 -0
- package/src/inference/draft-output.ts +49 -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 +12 -12
- 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 +70 -12
- package/src/kv-store.ts +177 -63
- 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} +5 -5
- package/src/lab/paged-kv/paged-kv-rows.ts +83 -0
- package/src/{model → lab/paged-kv}/paged-kv.ts +32 -15
- package/src/library.ts +40 -0
- package/src/lora.ts +18 -0
- package/src/media-fetch.ts +1 -1
- package/src/memory/article.ts +1 -1
- package/src/memory/chunk.ts +1 -1
- package/src/memory/model.ts +30 -169
- 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 +1 -3
- package/src/mlx/array.ts +11 -11
- package/src/mlx/compile.ts +12 -2
- package/src/mlx/ffi.ts +58 -11
- package/src/mlx/materialize.ts +23 -0
- package/src/mlx/metal-kernel.ts +10 -11
- package/src/mlx/ops.ts +33 -13
- 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/artifact-identity.ts +73 -0
- package/src/model/batched-kv.ts +235 -0
- package/src/model/batched-mask.ts +20 -6
- package/src/model/batched-quant.ts +9 -3
- package/src/model/batched-quantized-kv.ts +144 -0
- package/src/model/batched-rotating-quant.ts +78 -17
- package/src/model/batched-rotating-state.ts +76 -0
- package/src/model/batched-rotating.ts +65 -23
- package/src/model/batched-row-storage.ts +52 -0
- package/src/model/batched-ssm.ts +52 -0
- package/src/model/batched-turboquant-kv.ts +93 -0
- package/src/model/compiled-decode.ts +8 -2
- package/src/model/decoded-kv-donor.ts +12 -0
- package/src/model/delayed-quantized-kv.ts +72 -0
- package/src/model/delayed-rotating-quantized-kv.ts +93 -0
- package/src/model/delayed-turboquant-kv.ts +55 -0
- package/src/model/diffusion-gemma.ts +8 -8
- package/src/model/factory.ts +76 -33
- package/src/model/fingerprint.ts +1 -1
- package/src/model/flash-attention.ts +3 -3
- package/src/model/full-prefill-padding.ts +56 -0
- package/src/model/full-prefill-row.ts +105 -0
- package/src/model/gemma4-base.ts +179 -80
- package/src/model/gemma4.ts +40 -32
- package/src/model/generated/gemma4-12b.ts +6 -3
- package/src/model/generated/gemma4-26b.ts +6 -3
- package/src/model/generated/gemma4-e4b.ts +6 -3
- package/src/model/glm52-cache.ts +80 -4
- package/src/model/glm52-dsa.ts +13 -9
- package/src/model/glm52-memory.ts +1 -1
- package/src/model/glm52-mla.ts +12 -6
- package/src/model/glm52.ts +19 -40
- package/src/model/implementation.ts +69 -0
- package/src/model/kv-attention-view.ts +67 -0
- package/src/model/minicpm5.ts +17 -15
- package/src/model/profile.ts +12 -2
- package/src/model/qwen-append.ts +12 -0
- package/src/model/qwen-conv.ts +52 -0
- package/src/model/qwen3-delta-state.ts +74 -0
- package/src/model/qwen3-delta.ts +59 -36
- package/src/model/qwen3_5-checkpoint.ts +164 -0
- package/src/model/qwen3_5.ts +202 -78
- package/src/model/rotating-kv-donor.ts +35 -0
- package/src/model/rotating-kv-layout.ts +262 -0
- package/src/model/rotating-row-transaction.ts +35 -0
- package/src/model/speculative-rotating-kv.ts +101 -0
- package/src/model/ssm-prefill-padding.ts +39 -0
- 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/turboquant-codec.ts +83 -0
- package/src/model/universal/dense.ts +15 -14
- package/src/model/universal/modules.ts +8 -1
- package/src/native-pack.ts +6 -5
- package/src/pi-provider.ts +6 -64
- package/src/pi-web.ts +8 -315
- package/src/preflight.ts +31 -15
- package/src/prompt-cache.ts +110 -69
- package/src/quantize/allocator.ts +1 -1
- package/src/quantize/config-writer.ts +10 -3
- package/src/quantize/rotate.ts +4 -4
- package/src/quantize/trellis.ts +586 -0
- package/src/responses.ts +28 -1
- package/src/runtime-config.ts +18 -4
- package/src/sampler.ts +40 -29
- package/src/serve/batch-scheduler.ts +8 -1671
- 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 +15 -7
- package/src/serve/discovery-routes.ts +12 -13
- package/src/serve/generation-gateway.ts +183 -213
- 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/lab-routes.ts +3 -0
- package/src/serve/lane-registry.ts +2 -1
- package/src/serve/model-admin-routes.ts +7 -5
- package/src/serve/model-binding.ts +43 -0
- package/src/serve/model-host.ts +511 -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/request-plan.ts +23 -18
- package/src/serve/request-prep.ts +344 -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 +5 -5
- package/src/serve/text-completion-stage.ts +104 -0
- package/src/serve/token-streams.ts +519 -0
- package/src/server.ts +335 -2711
- package/src/spec/assistant-rows.ts +92 -0
- package/src/spec/assistant-source.ts +31 -55
- package/src/spec/cache-identity.ts +22 -0
- package/src/spec/deepspec-rows.ts +29 -0
- package/src/spec/deepspec-source.ts +16 -14
- package/src/spec/dflash-source.ts +36 -12
- package/src/spec/drafter.ts +153 -142
- package/src/spec/dspark/ab-stats.ts +3 -3
- package/src/spec/dspark/calibration.ts +2 -2
- package/src/spec/dspark/deepspec-module.ts +97 -122
- 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 +129 -172
- 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-graph.ts +29 -0
- package/src/spec/glm52-mtp-rows.ts +132 -0
- package/src/spec/glm52-mtp-source.ts +54 -137
- package/src/spec/glm52-mtp-state.ts +33 -0
- package/src/spec/ngram-source.ts +93 -21
- package/src/spec/projected-draft-rows.ts +73 -0
- package/src/spec/qwen-mtp-module.ts +171 -0
- package/src/spec/qwen-mtp-rows.ts +219 -0
- package/src/spec/qwen-mtp-source.ts +147 -195
- package/src/spec/qwen-mtp-state.ts +30 -0
- package/src/spec/serve-loop.ts +201 -201
- package/src/spec/source.ts +110 -13
- package/src/spec/two-model-rows.ts +61 -0
- package/src/spec/two-model.ts +44 -102
- package/src/ssd-cache.ts +99 -19
- package/src/ssd-durability.ts +36 -20
- package/src/tool-call.ts +51 -14
- package/src/train/flash-cce.ts +2 -2
- package/src/train/forward.ts +6 -0
- package/src/train/loss.ts +1 -1
- package/src/train/prefix-shared.ts +5 -1
- package/src/train/segmented.ts +5 -3
- package/src/train/trainer.ts +6 -6
- package/src/vision/prompt.ts +1 -1
- package/src/vision/qwen3vl-tower.ts +52 -10
- package/src/web/app.html +1 -1
- package/src/web/app.js +62 -60
- package/src/web/src/adapters-panel.ts +3 -3
- package/src/web/src/assistant.ts +2 -36
- package/src/web/src/chat.ts +4 -4
- 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 +55 -9
- package/docs/archive/investigations/curve-runs/bisector-route.json +0 -98
- package/docs/archive/investigations/curve-runs/bisector-trace.json +0 -1393
- package/docs/archive/investigations/curve-runs/curve-terrain.json +0 -1179
- package/docs/archive/investigations/curve-runs/curve-terrain.svg +0 -42
- package/docs/archive/investigations/hlg-ab.html +0 -34
- package/docs/archive/investigations/hlg-explorer.html +0 -238
- package/docs/archive/investigations/hlg-figs/cliff.svg +0 -1
- package/docs/archive/investigations/hlg-figs/cross.svg +0 -1
- package/docs/archive/investigations/hlg-figs/edges.svg +0 -1
- package/docs/archive/investigations/hlg-figs/k20-grids.svg +0 -1
- package/docs/archive/investigations/hlg-figs/k20-peaks.svg +0 -1
- package/docs/archive/investigations/hlg-figs/lw-curve.svg +0 -1
- package/docs/archive/investigations/hlg-figs/terrain.svg +0 -1
- package/docs/archive/investigations/hlg-report.html +0 -262
- package/docs/archive/investigations/hlg-runs/hlg-ab.json +0 -149
- package/docs/archive/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
- package/docs/archive/investigations/hlg-runs/hlg-blind.json +0 -107
- package/docs/archive/investigations/hlg-runs/hlg-cliff.json +0 -197
- package/docs/archive/investigations/hlg-runs/hlg-cross.json +0 -505
- package/docs/archive/investigations/hlg-runs/hlg-edge.json +0 -388
- package/docs/archive/investigations/hlg-runs/hlg-eval1.json +0 -25
- package/docs/archive/investigations/hlg-runs/hlg-frontier.json +0 -86
- package/docs/archive/investigations/hlg-runs/hlg-grid.json +0 -242
- package/docs/archive/investigations/hlg-runs/hlg-grid2.json +0 -343
- package/docs/archive/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
- package/docs/archive/investigations/hlg-runs/hlg-map.json +0 -383
- package/docs/archive/investigations/hlg-runs/run0-original.log +0 -159
- package/docs/archive/investigations/hlg-runs/runA-recommended.log +0 -131
- package/docs/archive/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
- package/docs/archive/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
- package/docs/archive/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
- package/docs/archive/investigations/hlg-runs/runAD-ab-samples.log +0 -8
- package/docs/archive/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
- package/docs/archive/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
- package/docs/archive/investigations/hlg-runs/runAG-eval-config2.log +0 -16
- package/docs/archive/investigations/hlg-runs/runB-gain-variants.log +0 -192
- package/docs/archive/investigations/hlg-runs/runC-pivots.log +0 -162
- package/docs/archive/investigations/hlg-runs/runD-oetf.log +0 -132
- package/docs/archive/investigations/hlg-runs/runE-eotf.log +0 -162
- package/docs/archive/investigations/hlg-runs/runF-shaper-working.log +0 -86
- package/docs/archive/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
- package/docs/archive/investigations/hlg-runs/runH-wsweep.log +0 -176
- package/docs/archive/investigations/hlg-runs/runI-asweep.log +0 -176
- package/docs/archive/investigations/hlg-runs/runJ-knobmap.log +0 -49
- package/docs/archive/investigations/hlg-runs/runK-frontier.log +0 -19
- package/docs/archive/investigations/hlg-runs/runL-widemap.log +0 -65
- package/docs/archive/investigations/hlg-runs/runM-frontier-emb.log +0 -15
- package/docs/archive/investigations/hlg-runs/runN-verify.log +0 -116
- package/docs/archive/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
- package/docs/archive/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
- package/docs/archive/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
- package/docs/archive/investigations/hlg-runs/runR-blind-transcript.log +0 -79
- package/docs/archive/investigations/hlg-runs/runS-cross-coherence.log +0 -33
- package/docs/archive/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
- package/docs/archive/investigations/hlg-runs/runU-cross-12b.log +0 -33
- package/docs/archive/investigations/hlg-runs/runV-lw-e4b.log +0 -22
- package/docs/archive/investigations/hlg-runs/runW-lw-12b.log +0 -22
- package/docs/archive/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
- package/docs/archive/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
- package/docs/archive/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
- 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 -318
- 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-serving-execution-seam.md +0 -81
- 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 -231
- 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 -415
- 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/turboquant-weights.md +0 -467
- 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/planning/IDEAS.md +0 -69
- package/docs/reference/embedding.md +0 -197
- package/docs/reference/features-matrix.md +0 -101
- package/docs/reference/orpo-quickstart.md +0 -135
- package/src/flags.ts +0 -11
- /package/docs/{design → archive/investigations}/colibri-glm52-port.md +0 -0
- /package/docs/{planning → archive/planning}/chunk-task-roadmap.md +0 -0
- /package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +0 -0
- /package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +0 -0
- /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.2.0.md +0 -0
- /package/src/{memory-plan.ts → admission-plan.ts} +0 -0
- /package/{docs/archive/investigations → src/serve/assets}/curve-terrain.html +0 -0
- /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
# Memory synthesis — the local Morpheus (M1 design)
|
|
2
|
-
|
|
3
|
-
> **SUPERSEDED (2026-07-01)** by
|
|
4
|
-
> [dreaming-nightly-pipeline.md](./dreaming-nightly-pipeline.md). Kept for
|
|
5
|
-
> history. Known-dead parts: embedding-based section-routing and silhouette
|
|
6
|
-
> signals (**no embeddings anywhere in the project**), bucket-as-optional
|
|
7
|
-
> framing, and the periodic-only wikify (RECONCILE/LINK/infobox are nightly
|
|
8
|
-
> stages now).
|
|
9
|
-
|
|
10
|
-
Status: **design**, 2026-06-26. Companion to [memory-system.md](./memory-system.md)
|
|
11
|
-
(the M0 substrate: vault, read tools, CLI, scheduling — all landed). This doc is
|
|
12
|
-
the M1 design for the **write side**: the synthesis pipeline that turns raw
|
|
13
|
-
conversations into well-formed wiki articles, **on local models**.
|
|
14
|
-
|
|
15
|
-
The inspiration and proof-of-concept is Lucien / The Dreaming / Morpheus
|
|
16
|
-
(`../lucien`) — it works, but every stage runs on a cloud model (`claude --model
|
|
17
|
-
opus`, `pi`). The whole point of M1 is to keep every learning from Lucien and
|
|
18
|
-
**solve the cost by running the pipeline locally**, using one local base model +
|
|
19
|
-
a per-stage LoRA adapter trained from Lucien's corpus (the e4b chunk adapter is
|
|
20
|
-
the first of these — designed components of the appliance, each distilled from
|
|
21
|
-
the cloud pipeline's gold output).
|
|
22
|
-
|
|
23
|
-
Guiding principle, inherited verbatim from Lucien: **do whatever Wikipedia does.**
|
|
24
|
-
Wikipedia turned a crowd of strangers into the largest organized, continuously-
|
|
25
|
-
updated knowledge base ever built. We are not going to out-design it — we copy
|
|
26
|
-
its conventions (articles, sections, talk pages, citations, wikilinks, edit
|
|
27
|
-
history) and supply the per-edit labor with local models instead of volunteers.
|
|
28
|
-
|
|
29
|
-
And the division of labor is fixed: **AI does the judgment; deterministic code
|
|
30
|
-
enforces the invariants we can't trust AI on** (footnote bijection, wikilink
|
|
31
|
-
canonicalization, the conservative write gate).
|
|
32
|
-
|
|
33
|
-
## Current state: ZERO articles
|
|
34
|
-
|
|
35
|
-
The vault starts empty. So the pipeline has to handle the **creation flow**, not
|
|
36
|
-
just steady-state updates — most of the early design discussion assumed an
|
|
37
|
-
existing structured article to patch; from zero there is nothing to patch yet.
|
|
38
|
-
The two flows are genuinely different operations and the doc treats them
|
|
39
|
-
separately below.
|
|
40
|
-
|
|
41
|
-
## The pipeline (DAG)
|
|
42
|
-
|
|
43
|
-
```
|
|
44
|
-
WRITE · the local Morpheus (what `mlx-bun memory synthesize` runs)
|
|
45
|
-
══════════════════════════════════════════════════════════════════
|
|
46
|
-
|
|
47
|
-
conversation transcripts (ingest, by cursor)
|
|
48
|
-
│
|
|
49
|
-
▼ CHUNK ································· local model + chunk LoRA [e4b ✓]
|
|
50
|
-
single-topic (segment + label)
|
|
51
|
-
│
|
|
52
|
-
▼ FILTER — worth keeping? ──no──▶ drop
|
|
53
|
-
│ yes
|
|
54
|
-
▼ CLASSIFY → bucket(s) many-to-many ──no fit──▶ drop
|
|
55
|
-
│ bucket ≈ article; from zero, buckets are PROPOSED (taxonomy emerges)
|
|
56
|
-
▼ SYNTHESIZE ······························ local model + synth LoRA
|
|
57
|
-
│ ├─ article does NOT exist → CREATE (sub-cluster → outline → per-section draft)
|
|
58
|
-
│ └─ article EXISTS → UPDATE (SECTION-ROUTE → PATCH one section)
|
|
59
|
-
│ + conservative write gate (≥70% prose floor, every citation survives, weak → NO-OP)
|
|
60
|
-
▼
|
|
61
|
-
article written / one section changed (rest byte-identical)
|
|
62
|
-
│
|
|
63
|
-
▼ NORMALIZE (deterministic code, not a model)
|
|
64
|
-
│ footnote renumber/repair · wikilink canonicalize
|
|
65
|
-
▼
|
|
66
|
-
▼ WIKIFY (periodic, local model + wikify LoRA) ◀── distinct LLM node
|
|
67
|
-
│ "make this a BETTER version" — per-section improve + structural pass
|
|
68
|
-
└──▶ Talk-page signals (embedding/silhouette): SPLIT · MERGE · CONTRADICTION
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
READ · any chat agent (M0, landed; read-only via memory_* tools)
|
|
72
|
-
══════════════════════════════════════════════════════════════════
|
|
73
|
-
question ─▶ search / toc ─▶ read section · follow [[links]] ─▶ reason ─▶ answer
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
```mermaid
|
|
77
|
-
flowchart TD
|
|
78
|
-
T[conversation transcripts] --> C["CHUNK · local+LoRA"]
|
|
79
|
-
C -->|segment+label| F{worth keeping?}
|
|
80
|
-
F -->|no| D1((drop))
|
|
81
|
-
F -->|yes| CL["CLASSIFY → bucket(s)"]
|
|
82
|
-
CL -->|no fit| D2((drop))
|
|
83
|
-
CL --> EX{article exists?}
|
|
84
|
-
EX -->|no| CR["CREATE: sub-cluster → outline → per-section draft"]
|
|
85
|
-
EX -->|yes| UP["UPDATE: section-route → patch one section"]
|
|
86
|
-
CR --> GATE["conservative write gate"]
|
|
87
|
-
UP --> GATE
|
|
88
|
-
GATE --> NORM["NORMALIZE footnotes + wikilinks · deterministic"]
|
|
89
|
-
NORM --> WK["WIKIFY periodic · per-section improve + structural pass"]
|
|
90
|
-
WK -->|talk-page| SIG["SPLIT · MERGE · CONTRADICTION"]
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## The two synthesis flows
|
|
94
|
-
|
|
95
|
-
### CREATE (cold-start / bootstrap — the zero-article case)
|
|
96
|
-
|
|
97
|
-
Trigger: a bucket has accumulated enough chunks (≥N, conservative) and has **no
|
|
98
|
-
article file yet**. Naively this is whole-article generation from a pile of
|
|
99
|
-
chunks — exactly the open-ended task a small local model is *worst* at. So we
|
|
100
|
-
decompose it the same way we decompose updates — **section-granular**:
|
|
101
|
-
|
|
102
|
-
1. **Sub-cluster** the bucket's chunks into proto-sections (cluster the chunks
|
|
103
|
-
*within* the bucket — the cohesion/embedding machinery applies one level down;
|
|
104
|
-
silhouette is a strong cohesion signal, ρ≈0.68 vs the judges).
|
|
105
|
-
2. **Outline** — name each section from its sub-cluster, write the lead. A small
|
|
106
|
-
structural task, not long-form prose.
|
|
107
|
-
3. **Draft each section** by synthesizing only its sub-cluster's chunks — the
|
|
108
|
-
*same bounded per-section operation* as a patch, just starting from empty.
|
|
109
|
-
4. **Assemble** → article with `# Title`, lead, sections, `## References`, TOC.
|
|
110
|
-
|
|
111
|
-
So even creation never asks the model to hold a whole article in its head: it's
|
|
112
|
-
sub-cluster → outline → N bounded section drafts. Conservative bootstrap bias:
|
|
113
|
-
**under-cover rather than over-cover** — thin buckets stay `{{stub}}` or wait for
|
|
114
|
-
more material (Lucien's lesson: twenty good articles beat a sprawling mediocre
|
|
115
|
-
set).
|
|
116
|
-
|
|
117
|
-
### UPDATE (steady state — article exists)
|
|
118
|
-
|
|
119
|
-
1. **SECTION-ROUTE** the new chunk to the section(s) it affects, via the TOC —
|
|
120
|
-
"this topic affects THESE sections" (e.g. a Reflecting-Pool-renovation chunk →
|
|
121
|
-
the *Renovation* section, and possibly an *Abuse-of-Power* section of a Trump
|
|
122
|
-
article). Many-to-many at section granularity. If it fits no existing section,
|
|
123
|
-
the route is "new section."
|
|
124
|
-
2. **PATCH** just that section: hand the model the section text + the chunk, ask
|
|
125
|
-
it to weave the chunk in with a `[^N]` citation. Bounded in, bounded out.
|
|
126
|
-
Facet extraction is implicit — the same chunk becomes the renovation facts in
|
|
127
|
-
one section and the no-bid-contract framing in another, because the model
|
|
128
|
-
writes what's relevant to the section it's editing.
|
|
129
|
-
3. **Everything else stays byte-identical** — only the routed section is rewritten.
|
|
130
|
-
|
|
131
|
-
Both flows share the **conservative write gate** (already specced in
|
|
132
|
-
`synthesize.ts`): preserve prose, ≥70% word-count floor, every original `conv:`
|
|
133
|
-
citation survives, integrate-not-overwrite; a weak local pass is gated to NO-OP
|
|
134
|
-
rather than allowed to corrupt the vault.
|
|
135
|
-
|
|
136
|
-
## Why WIKIFY is its own (necessary) node
|
|
137
|
-
|
|
138
|
-
Section-patches are greedy and local. Over many of them an article accumulates
|
|
139
|
-
cruft: a section sprawls, sentences go redundant, the lead goes stale, section
|
|
140
|
-
order drifts. **Wikify is the periodic global pass that keeps the article *good*
|
|
141
|
-
— "how do I turn this into a better version of this article" — and it is
|
|
142
|
-
necessary; without it you just keep bolting things on.** This is the LLM
|
|
143
|
-
editorial-restructure (Lucien's "Editorial restructure" commits), *distinct from*
|
|
144
|
-
the deterministic footnote/wikilink normalize that the current `wikify.ts` stub
|
|
145
|
-
conflates it with.
|
|
146
|
-
|
|
147
|
-
Structure makes even this global pass decompose toward local: wikify can run
|
|
148
|
-
**per-section "improve this section"** + a **cheap structural pass over the TOC**
|
|
149
|
-
(reorder, fix the lead, re-section, emit split/merge signals) instead of one
|
|
150
|
-
whole-article regeneration. So wikify is local-tractable for the same reason
|
|
151
|
-
synthesis is: sections.
|
|
152
|
-
|
|
153
|
-
## Data model — pointers, not copies
|
|
154
|
-
|
|
155
|
-
The SQLite store (`~/.cache/mlx-bun/memory.sqlite`) is **derived, rebuildable**
|
|
156
|
-
state — not the source of truth. The principle that keeps it lean and consistent:
|
|
157
|
-
**materialize text in exactly one place; everything else points.**
|
|
158
|
-
|
|
159
|
-
- **Messages hold the text, once.** A `messages` table (text per message), keyed
|
|
160
|
-
by `(conv, position)`.
|
|
161
|
-
- **A chunk is a pointer range, not a copy.** `chunks(id, conv, start, end, label)`
|
|
162
|
-
— a segmentation is *where the boundaries are*, so storing it as a message range
|
|
163
|
-
+ label is the natural representation. Synthesis *dereferences* to message text
|
|
164
|
-
only when it reads a chunk. Re-chunking rewrites pointer rows, never text.
|
|
165
|
-
- **Assignments are join tables (many-to-many).** `chunk_buckets(chunk_id,
|
|
166
|
-
bucket_name)` and, for the section design, `chunk_sections(chunk_id, article,
|
|
167
|
-
section_anchor)` — "this chunk affects THESE sections of THESE articles."
|
|
168
|
-
- **The article markdown is the only materialized synthesis.** Its `[^N]:
|
|
169
|
-
conv:HASH` citations are themselves *pointers back to source conversations*, not
|
|
170
|
-
copies. The vault is the precious git-tracked truth for *articles*; the DB is the
|
|
171
|
-
rebuildable index for *pipeline state*.
|
|
172
|
-
|
|
173
|
-
**The current `db.ts` stub violates this and must be fixed for M1** (it mirrors a
|
|
174
|
-
naive copy design, not Lucien's pointer design):
|
|
175
|
-
- `conversations.transcript` stores the whole transcript blob AND `chunks.text`
|
|
176
|
-
copies each slice → the same text twice. Replace with a `messages` table +
|
|
177
|
-
pointer `chunks` (drop `chunks.text`).
|
|
178
|
-
- `chunks.bucket TEXT` is one-bucket-per-chunk → breaks many-to-many. Replace with
|
|
179
|
-
`chunk_buckets`. Add `chunk_sections` for the section-route output.
|
|
180
|
-
- `synthesized_bucket_chunks` → `synthesized_chunk_sections(article, section_anchor,
|
|
181
|
-
chunk_id, synthesized_at)` so the patch ledger is per-section (fold each chunk
|
|
182
|
-
into each section exactly once).
|
|
183
|
-
|
|
184
|
-
Target tables: `messages` · `chunks` (pointers) · `conversations` · `buckets` ·
|
|
185
|
-
`chunk_buckets` · `chunk_sections` · `synthesized_chunk_sections` · `watermarks`.
|
|
186
|
-
|
|
187
|
-
### Engine: bun:sqlite now, Turso swappable (for vectors)
|
|
188
|
-
|
|
189
|
-
Build M1 on **`bun:sqlite`** — native to Bun, zero-dependency, synchronous, the
|
|
190
|
-
most battle-tested DB there is, and already the project's pattern (`JobStore`,
|
|
191
|
-
`EvalDB`, `registry`, `MemoryStore`). No reason to pay friction on day one.
|
|
192
|
-
|
|
193
|
-
**Turso** (the current product — a from-scratch Rust rewrite of SQLite that is
|
|
194
|
-
*embedded / on-device / offline / SQLite-compatible*, NOT the old cloud-sync
|
|
195
|
-
product) is the evaluation path. Its one concrete payoff for us is **native vector
|
|
196
|
-
search** — and this design is embedding-heavy (section-routing, semantic article
|
|
197
|
-
search, the silhouette signals). Reasons to defer rather than adopt now: it's a
|
|
198
|
-
young engine vs C SQLite, and the Bun-integration story (native binding vs
|
|
199
|
-
FFI/overhead) needs checking.
|
|
200
|
-
|
|
201
|
-
The decision is cheap to defer because (a) Turso is SQLite-*compatible* so the
|
|
202
|
-
schema/SQL above is identical either way, (b) `MemoryStore` already wraps the DB
|
|
203
|
-
behind a small class, so it's a driver swap not a rewrite, and (c) this DB is a
|
|
204
|
-
**rebuildable cache** (truth = vault + git), so it's a low-risk place to adopt a
|
|
205
|
-
younger engine. Plan: keep the SQL standard, keep the driver swappable, and switch
|
|
206
|
-
to Turso *if/when* its vector search beats in-process cosine (or `sqlite-vec`) at a
|
|
207
|
-
corpus size that actually needs ANN.
|
|
208
|
-
|
|
209
|
-
## The cascade (why local is possible at all)
|
|
210
|
-
|
|
211
|
-
```
|
|
212
|
-
clean single-topic chunks → clean buckets → clean section-routing → bounded section-patch
|
|
213
|
-
└──── purity at the root ────┘
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
Each stage's locality depends on the prior stage's cleanliness. If a chunk fuses
|
|
217
|
-
two topics, it pollutes every section it's routed into. So **chunk purity is the
|
|
218
|
-
foundation of the whole local system** — not an abstract metric.
|
|
219
|
-
|
|
220
|
-
Caution from the chunk research (research-journal, reports/orpo-chunk-paper):
|
|
221
|
-
embeddings measure **cohesion/dispersion well** (silhouette ρ≈0.68 per-conv vs
|
|
222
|
-
the LLM judges) but **purity/contamination poorly** (−intraSpread ρ≈0.32, ns
|
|
223
|
-
within variants). So a clean-bucket guarantee cannot lean on a cheap embedding
|
|
224
|
-
signal — it rides on the local **chunker** actually being good at single-topic
|
|
225
|
-
splitting (the e4b adapter's real job), backed where needed by a non-embedding
|
|
226
|
-
purity check, not by cosine geometry.
|
|
227
|
-
|
|
228
|
-
## Stage → model → adapter
|
|
229
|
-
|
|
230
|
-
| stage | file | model | adapter |
|
|
231
|
-
|---|---|---|---|
|
|
232
|
-
| chunk | `src/memory/chunk.ts` | local | **chunk LoRA (e4b chunk-300, exists)** |
|
|
233
|
-
| classify | `src/memory/cluster.ts` | local + embeddings | classify LoRA (TODO) |
|
|
234
|
-
| synthesize (create/update) | `src/memory/synthesize.ts` | local | synth LoRA (TODO) |
|
|
235
|
-
| normalize | `src/memory/wikify.ts` (rename) | **deterministic code** | — |
|
|
236
|
-
| wikify (LLM) | **new node** | local | wikify LoRA (TODO) |
|
|
237
|
-
|
|
238
|
-
Section-routing (the new intra-article step) is embeddings-shaped: embed the
|
|
239
|
-
chunk (or its label) and the article's section headings/lead (from `parseToc` /
|
|
240
|
-
`extractSection`, already in `vault.ts`), route to the nearest section(s) over a
|
|
241
|
-
threshold. The local Qwen3-Embedding backbone (bit-exact, served, `/v1/embeddings`)
|
|
242
|
-
is exactly the "vector search over articles, not conversations" the vision calls
|
|
243
|
-
for — now applied at section granularity.
|
|
244
|
-
|
|
245
|
-
## What changes in the scaffold
|
|
246
|
-
|
|
247
|
-
The M1 stubs are wired (`pipeline.ts` orchestrates ingest→chunk→cluster→
|
|
248
|
-
synthesize→wikify→changelog; stage bodies throw "not implemented"). Two
|
|
249
|
-
corrections vs the stubs:
|
|
250
|
-
|
|
251
|
-
1. **`synthesize.ts` is whole-article today.** Make it `create-or-update`, with
|
|
252
|
-
update = section-route + section-patch (not whole-article regeneration).
|
|
253
|
-
2. **The LLM wikify node is missing.** The current `wikify.ts` is *only*
|
|
254
|
-
deterministic normalize. Keep that (rename to `normalize.ts`), and add a
|
|
255
|
-
distinct **LLM wikify** node for the periodic "better version" pass.
|
|
256
|
-
|
|
257
|
-
## Build sequence
|
|
258
|
-
|
|
259
|
-
Cold-start first, because the vault is empty and you can't patch what doesn't exist:
|
|
260
|
-
|
|
261
|
-
1. **Wire CHUNK** to the e4b chunk adapter (`chunk.ts`) — the one stage with an
|
|
262
|
-
adapter in hand. Verify single-topic chunks + labels on real conversations.
|
|
263
|
-
2. **CLASSIFY from zero** (`cluster.ts`) — emergent bucket taxonomy
|
|
264
|
-
(`Meta/Buckets.md`); assign chunks to buckets, propose new ones; filter no-fit.
|
|
265
|
-
3. **CREATE flow** (`synthesize.ts`) — sub-cluster → outline → per-section draft
|
|
266
|
-
for buckets crossing the chunk threshold. Behind the conservative gate. This
|
|
267
|
-
is what gets us from zero to a first set of articles.
|
|
268
|
-
4. **NORMALIZE** (`normalize.ts`) — wire the deterministic footnote/wikilink
|
|
269
|
-
repair (`vault.ts` already has the resolver).
|
|
270
|
-
5. **UPDATE flow** — section-route + patch, once articles exist to update.
|
|
271
|
-
6. **WIKIFY (LLM)** + Talk-page split/merge signals — once articles have
|
|
272
|
-
accumulated enough cruft/drift to need them.
|
|
273
|
-
|
|
274
|
-
Steps 1–4 are the cold-start path (zero → first articles); 5–6 are steady state.
|
|
275
|
-
|
|
276
|
-
## Open questions
|
|
277
|
-
|
|
278
|
-
- **Article granularity / when to CREATE** — chunk threshold per bucket; when a
|
|
279
|
-
bucket should become one article vs several (the vision's "soft size caps").
|
|
280
|
-
- **Section-route confidence** — threshold for "fits an existing section" vs
|
|
281
|
-
"new section needed" vs "route to a different article."
|
|
282
|
-
- **Provisional facts** — representing "work set to begin July" so the next pass
|
|
283
|
-
cleanly updates it to "began / completed" (temporal/trajectory tracking).
|
|
284
|
-
- **Create vs strong-model** — is first-creation good enough on the local model,
|
|
285
|
-
or is bootstrap the one place a stronger model is worth it (vision: bootstrap is
|
|
286
|
-
heavier but the same code path)?
|
|
287
|
-
- **The purity check** — what non-embedding signal guarantees clean buckets.
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
# Memory system
|
|
2
|
-
|
|
3
|
-
Status: **M0/M0.5 landed (2026-06-19)**. The vault, read tools, CLI, Obsidian open flow, and launchd scheduling are implemented. The actual synthesis stage bodies are still **M1 TODO**; `mlx-bun memory synthesize` is currently a safe no-op stub. The planned M1/M2 synthesis engine uses the same local models the user chats with, plus stage-specific LoRA adapters trained by Josh from the existing Lucien-scale memory corpus and distributed from Hugging Face.
|
|
4
|
-
|
|
5
|
-
## Contract
|
|
6
|
-
|
|
7
|
-
The memory contract is ported from `../lucien`:
|
|
8
|
-
|
|
9
|
-
> **Chat-time agents read memory. The synthesis pipeline writes memory.**
|
|
10
|
-
|
|
11
|
-
Memory articles are durable priors. Conversations are evidence. Synthesis is the deliberate, auditable process that turns evidence into updated articles. Normal chat must not mutate articles.
|
|
12
|
-
|
|
13
|
-
This gives both terminal and web the full pi agent experience without turning memory into an unsafe scratchpad:
|
|
14
|
-
|
|
15
|
-
- Terminal and web expose the same read-only memory tools through one shared pi surface factory.
|
|
16
|
-
- Memory tools/skill are exposed only when the user has enabled the vault.
|
|
17
|
-
- When enabled, memory is scoped to user-specific continuity: explicit recall, named personal projects/people/preferences/decisions/history, or missing personal context.
|
|
18
|
-
- Memory is **not** the default first step for weather, current public facts, generic web research, or ordinary coding/file tasks where the current files are sufficient.
|
|
19
|
-
- Mutating/coding tools remain full-power and approval-gated by pi/web as usual.
|
|
20
|
-
- Memory article writes happen only through `mlx-bun memory synthesize` once M1 lands.
|
|
21
|
-
- Users can always browse/edit their own Markdown vault directly, especially via Obsidian.
|
|
22
|
-
|
|
23
|
-
## User-facing model
|
|
24
|
-
|
|
25
|
-
- User-facing capability: **memory**.
|
|
26
|
-
- Store on disk: `~/.mlx-bun/wiki/` (override: `MLX_BUN_WIKI`).
|
|
27
|
-
- User articles: `~/.mlx-bun/wiki/articles/*.md`.
|
|
28
|
-
- Read-only reference residents: `~/.mlx-bun/wiki/Reference/*.md` symlinked to mlx-bun's own docs.
|
|
29
|
-
- Operational pages: `~/.mlx-bun/wiki/Meta/*.md`.
|
|
30
|
-
- Talk pages: `~/.mlx-bun/wiki/Talk/`.
|
|
31
|
-
- Synthesis DB: `~/.cache/mlx-bun/memory.sqlite`.
|
|
32
|
-
|
|
33
|
-
The vault is plain Markdown and git-tracked. It is intentionally usable as an Obsidian vault. `Reference/` is a separate read-only namespace: chat tools may search/read it, but synthesis must skip it and never write through those symlinks. The SQLite DB is derived state and lives in the rebuildable cache, not in the user-owned Markdown vault.
|
|
34
|
-
|
|
35
|
-
Stage-specific memory LoRAs are product assets, not user-authored vault content. The creator trains them from the existing memory-pipeline data, publishes them to Hugging Face, and `memory init` can offer to download/cache them for local synthesis.
|
|
36
|
-
|
|
37
|
-
## What is implemented now
|
|
38
|
-
|
|
39
|
-
### Vault and article helpers
|
|
40
|
-
|
|
41
|
-
`src/memory/vault.ts` implements:
|
|
42
|
-
|
|
43
|
-
- `vaultRoot()` → `~/.mlx-bun/wiki` or `MLX_BUN_WIKI`.
|
|
44
|
-
- `setupVault()` — idempotent directory/Meta/README/git setup plus `Reference/` symlinks.
|
|
45
|
-
- `listArticles()` / `listReferenceDocs()` / `listMemoryDocuments()`.
|
|
46
|
-
- `readArticle()` / `searchArticles()` over both user articles and read-only references.
|
|
47
|
-
- `parseToc()` / `extractSection()`.
|
|
48
|
-
- `getArticleLinks()` with resolved inbound/outbound wikilinks.
|
|
49
|
-
- `importArticlesFrom()` for seeding from an existing vault such as `~/Dreaming`.
|
|
50
|
-
- `vaultStatus()` with article/reference counts and recent user article mtimes.
|
|
51
|
-
|
|
52
|
-
The read/search/link logic is ported from Lucien's pure filesystem helpers, not from MCP.
|
|
53
|
-
|
|
54
|
-
### CLI
|
|
55
|
-
|
|
56
|
-
`mlx-bun memory` supports:
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
mlx-bun memory init # create vault, optionally import + schedule
|
|
60
|
-
mlx-bun memory setup # alias for init
|
|
61
|
-
mlx-bun memory status # path, article count, git, schedule, recent articles
|
|
62
|
-
mlx-bun memory open # open the vault in Obsidian, fallback Finder
|
|
63
|
-
mlx-bun memory open <article> # open one article in Obsidian/default Markdown app
|
|
64
|
-
mlx-bun memory list # list article stems + Reference/* docs
|
|
65
|
-
mlx-bun memory search <query> # search articles
|
|
66
|
-
mlx-bun memory toc <article> # headings + anchors
|
|
67
|
-
mlx-bun memory section <article> <anchor>
|
|
68
|
-
mlx-bun memory links <article> # inbound/outbound wikilinks
|
|
69
|
-
mlx-bun memory read <article> # print full article
|
|
70
|
-
mlx-bun memory synthesize [--dry-run] [--model <q>] [--since <cursor>]
|
|
71
|
-
mlx-bun memory schedule [--at HH:MM]
|
|
72
|
-
mlx-bun memory unschedule
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
`memory synthesize` currently reports the M1 stub and writes nothing. Scheduling is real; the scheduled job is harmless until synthesis lands. In the full flow, `memory init` should also offer to download the memory pipeline adapter pack from Hugging Face so synthesis is ready to run locally.
|
|
76
|
-
|
|
77
|
-
### pi/web tools
|
|
78
|
-
|
|
79
|
-
`src/memory/tools.ts` defines native pi custom tools:
|
|
80
|
-
|
|
81
|
-
- `memory_search`
|
|
82
|
-
- `memory_read`
|
|
83
|
-
- `memory_toc`
|
|
84
|
-
- `memory_section`
|
|
85
|
-
- `memory_links`
|
|
86
|
-
- `memory_list` (user articles plus read-only `Reference/*` docs)
|
|
87
|
-
- `memory_status` (vault path, setup state, article count, git state, last-synthesis placeholder, schedule state, recent changed articles)
|
|
88
|
-
|
|
89
|
-
These tools are registered by the shared pi surface in `src/pi-session.ts` and consumed by both front doors:
|
|
90
|
-
|
|
91
|
-
- `src/pi-terminal.ts`
|
|
92
|
-
- `src/pi-web.ts`
|
|
93
|
-
|
|
94
|
-
If the vault does not exist, memory tools and the memory skill are not exposed at all, avoiding prompt fixation on unavailable memory. If the vault exists, `memoryIndexHint()` adds a short scoped presence hint. Detailed usage lives in the memory skill rather than dumping article titles into the prompt.
|
|
95
|
-
|
|
96
|
-
Read-only mlx-bun docs are now a separate lookup surface (`reference_search`, `reference_read`, `reference_list`) rather than being mixed into personal-memory search. Personal memory answers “what does the user think / what did we decide”; reference tools answer “what do mlx-bun docs say.”
|
|
97
|
-
|
|
98
|
-
### Bundled memory skill
|
|
99
|
-
|
|
100
|
-
`src/web/skills/memory/SKILL.md` is bundled through `src/web/skills.ts` and materialized under `~/.mlx-bun/skills` for pi to load.
|
|
101
|
-
|
|
102
|
-
The skill tells the agent to:
|
|
103
|
-
|
|
104
|
-
- consult memory quietly for personal context;
|
|
105
|
-
- use `memory_search` then `memory_read`, or `memory_toc` + `memory_section` for focused reads;
|
|
106
|
-
- use `memory_links` for nearby concepts/backlinks;
|
|
107
|
-
- use `memory_status` for setup/location/schedule questions;
|
|
108
|
-
- never announce retrieval as the user's experience;
|
|
109
|
-
- never edit memory articles during chat;
|
|
110
|
-
- open the vault/article for the user if asked via `mlx-bun memory open [article]`.
|
|
111
|
-
|
|
112
|
-
### Session capture substrate
|
|
113
|
-
|
|
114
|
-
The synthesis pipeline will ingest mlx-bun's own pi sessions only:
|
|
115
|
-
|
|
116
|
-
- web sessions: `~/.mlx-bun/sessions/...` / `~/.mlx-bun/pi-sessions/...` depending on the web `SessionManager` path;
|
|
117
|
-
- terminal sessions: `~/.mlx-bun/pi/sessions/...`.
|
|
118
|
-
|
|
119
|
-
No Playwright, scraping, cloud transcript import, or Lucien runtime dependency is planned for mlx-bun memory.
|
|
120
|
-
|
|
121
|
-
### Scheduling
|
|
122
|
-
|
|
123
|
-
`src/memory/schedule.ts` installs a launchd agent:
|
|
124
|
-
|
|
125
|
-
- label: `com.mlx-bun.memory`
|
|
126
|
-
- plist: `~/Library/LaunchAgents/com.mlx-bun.memory.plist`
|
|
127
|
-
- command: `mlx-bun memory synthesize`
|
|
128
|
-
- logs: `~/.mlx-bun/logs/memory-synthesis.{out,err}.log`
|
|
129
|
-
|
|
130
|
-
`mlx-bun memory schedule --at 03:00` installs/loads it. `unschedule` unloads/removes it. `status` and `memory_status` report it.
|
|
131
|
-
|
|
132
|
-
## Synthesis pipeline design (M1/M2)
|
|
133
|
-
|
|
134
|
-
The M1/M2 pipeline mirrors Lucien's proven stages while running on the same local model stack the user chats with. The difference is execution context and authority: chat uses the model conversationally and read-only; synthesis runs the model as a constrained editor behind deterministic gates.
|
|
135
|
-
|
|
136
|
-
```text
|
|
137
|
-
ingest deterministic: pi session JSONL -> memory.sqlite conversations
|
|
138
|
-
chunk base model + memory-chunk LoRA -> topic chunks
|
|
139
|
-
cluster base model + memory-bucket LoRA -> buckets / target articles
|
|
140
|
-
synthesize base model + memory-synthesis LoRA -> candidate article updates
|
|
141
|
-
wikify base model + memory-editor LoRA + deterministic normalization
|
|
142
|
-
changelog deterministic: run summary + git commit
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
The chunking LoRA has already been trained as a WIP artifact. The remaining stage adapters are planned product assets trained by Josh from the existing Lucien/pipeline data and published to Hugging Face. mlx-bun should download/cache them during `memory init` (with user consent) or lazily on first `memory synthesize`.
|
|
146
|
-
|
|
147
|
-
Important nouns must stay distinct:
|
|
148
|
-
|
|
149
|
-
- **Conversation** — source transcript/evidence.
|
|
150
|
-
- **Chunk** — topical segment from a conversation.
|
|
151
|
-
- **Bucket** — staging group that collects related chunks.
|
|
152
|
-
- **Article** — durable Markdown memory page.
|
|
153
|
-
|
|
154
|
-
### Bookkeeping DB
|
|
155
|
-
|
|
156
|
-
`src/memory/db.ts` defines `MemoryStore` over `~/.cache/mlx-bun/memory.sqlite` with tables for:
|
|
157
|
-
|
|
158
|
-
- `conversations`
|
|
159
|
-
- `chunks`
|
|
160
|
-
- `buckets`
|
|
161
|
-
- `watermarks`
|
|
162
|
-
- `synthesized_bucket_chunks`
|
|
163
|
-
|
|
164
|
-
The DB is derived and rebuildable from sessions + articles. It should not be committed to the vault.
|
|
165
|
-
|
|
166
|
-
### Stage-specific adapters
|
|
167
|
-
|
|
168
|
-
The pipeline deliberately uses **four specialized LoRA adapters** rather than one generic memory adapter:
|
|
169
|
-
|
|
170
|
-
| Stage | Adapter | Job | Primary quality signal |
|
|
171
|
-
| --- | --- | --- | --- |
|
|
172
|
-
| Chunk | memory-chunk | Conversation transcript → topic-coherent chunks | Boundary/label accuracy vs gold chunks |
|
|
173
|
-
| Bucket | memory-bucket | Chunk → existing bucket or new bucket proposal | Stable routing, low duplicate topics, good article target |
|
|
174
|
-
| Synthesize | memory-synthesis | New chunks + existing article → conservative candidate update | Citation preservation, faithful integration, no hallucinated claims |
|
|
175
|
-
| Edit/wikify | memory-editor | Candidate article → normalized wiki Markdown | Style, wikilinks, references, deterministic format compliance |
|
|
176
|
-
|
|
177
|
-
These adapters do **not** get direct write authority. They produce candidates. The pipeline validates, normalizes, and decides whether to write/commit.
|
|
178
|
-
|
|
179
|
-
Implementation notes:
|
|
180
|
-
|
|
181
|
-
- Adapters should be cached with the rest of mlx-bun's HF/downloaded artifacts, not stored in the wiki vault.
|
|
182
|
-
- `memory init` should describe the adapter pack plainly and ask before downloading multi-MB/GB assets.
|
|
183
|
-
- `memory synthesize --dry-run` must work without downloading adapters when it only builds the deterministic manifest.
|
|
184
|
-
- If a required adapter is missing for a real synthesis stage, the command should offer the download or fail cleanly; it should not silently fall back to an untrained prompt path unless explicitly requested.
|
|
185
|
-
- Future routing should use the existing adapter-scoped generation path: one resident base model, stage LoRA mounted per pipeline call.
|
|
186
|
-
|
|
187
|
-
### Current stage modules
|
|
188
|
-
|
|
189
|
-
These files exist as typed stubs and currently throw if called directly:
|
|
190
|
-
|
|
191
|
-
- `src/memory/ingest.ts`
|
|
192
|
-
- `src/memory/chunk.ts`
|
|
193
|
-
- `src/memory/cluster.ts`
|
|
194
|
-
- `src/memory/synthesize.ts`
|
|
195
|
-
- `src/memory/wikify.ts`
|
|
196
|
-
- `src/memory/prompts.ts`
|
|
197
|
-
|
|
198
|
-
`src/memory/pipeline.ts` intentionally does **not** call them yet. It emits a no-op M1-stub plan so manual and scheduled synthesis cannot accidentally corrupt the vault before gates exist.
|
|
199
|
-
|
|
200
|
-
## Synthesis quality gates to port from Lucien
|
|
201
|
-
|
|
202
|
-
M1 should preserve these Lucien properties:
|
|
203
|
-
|
|
204
|
-
- deterministic manifest / dry-run before writes;
|
|
205
|
-
- per-bucket/per-article workers so failures are isolated;
|
|
206
|
-
- idempotency via `synthesized_bucket_chunks`;
|
|
207
|
-
- backfill behavior for existing imported articles;
|
|
208
|
-
- orphan detection when ledger and files disagree;
|
|
209
|
-
- conservative update prompt: integrate, do not rewrite wholesale;
|
|
210
|
-
- minimum word-count/truncation guard, e.g. Lucien's 70% floor;
|
|
211
|
-
- citation preservation: every original `conv:` reference survives;
|
|
212
|
-
- deterministic footnote repair;
|
|
213
|
-
- deterministic wikilink normalization;
|
|
214
|
-
- git commit for article changes;
|
|
215
|
-
- changelog / run summary.
|
|
216
|
-
|
|
217
|
-
A weak local-model synthesis pass should no-op, not damage the vault. This remains true even with trained adapters: LoRAs propose; deterministic gates dispose. Synthesis must operate only on `articles/` and must treat `Reference/` as immutable read-only context.
|
|
218
|
-
|
|
219
|
-
## Consent and safety
|
|
220
|
-
|
|
221
|
-
- Local session capture is local-only and part of pi/web session persistence.
|
|
222
|
-
- Creating the vault is explicit: `mlx-bun memory init`.
|
|
223
|
-
- Scheduling is explicit: `mlx-bun memory schedule` or the init wizard prompt.
|
|
224
|
-
- Chat-time memory tools are read-only and auto-allowed.
|
|
225
|
-
- Opening Obsidian/Finder is user-directed browsing/editing; it is not agent mutation.
|
|
226
|
-
- Article mutation by the agent during chat is out of bounds.
|
|
227
|
-
|
|
228
|
-
## Next implementation steps
|
|
229
|
-
|
|
230
|
-
1. Implement `memory synthesize --dry-run` manifest generation without model calls.
|
|
231
|
-
2. Add memory adapter-pack metadata and `memory init` download prompt (HF-hosted LoRAs; chunk adapter exists as WIP, others follow).
|
|
232
|
-
3. Implement ingest from saved pi session JSONL into `MemoryStore`.
|
|
233
|
-
4. Wire the chunk stage to the memory-chunk LoRA and evaluate with chunk boundary/label accuracy.
|
|
234
|
-
5. Implement bucket assignment with the memory-bucket LoRA and article manifest create/update/backfill/orphan modes.
|
|
235
|
-
6. Implement per-article synthesis workers with the memory-synthesis LoRA and conservative gates.
|
|
236
|
-
7. Implement editor/wikify adapter pass plus deterministic footnote/wikilink normalization and git commits.
|
|
237
|
-
8. Move synthesis execution onto the jobs runner with SSE progress once manual synthesis is reliable.
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# mlx-lm serving execution seam
|
|
2
|
-
|
|
3
|
-
## Question
|
|
4
|
-
|
|
5
|
-
What should mlx-bun borrow from the pinned mlx-lm oracle when deepening Completion execution around this flow?
|
|
6
|
-
|
|
7
|
-
```text
|
|
8
|
-
prepared prompt -> semantic events -> terminal summary
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
This note reads the local mlx-lm 0.31.3 source installed in the reference venv. The comparison uses the serving term defined in `CONTEXT.md`: a **Completion execution** includes output, resource lifetime, usage, and scheduling placement.
|
|
12
|
-
|
|
13
|
-
mlx-lm is the correctness oracle only for behavior and numeric schemes it implements. It is not mlx-bun's architecture oracle or capability ceiling. mlx-bun also implements explicitly selected features such as mixed-precision KV, TurboQuant, and native draft methods. The execution path must preserve those resolved settings exactly.
|
|
14
|
-
|
|
15
|
-
## Implementation status
|
|
16
|
-
|
|
17
|
-
The first consolidation slice landed on 2026-08-21. `prepareCompletion()` performs admission before a streaming response starts and returns an opaque, single-use `PreparedCompletion`. `CompletionExecutor.execute()` then owns placement reporting, `CompletionSink`, logprobs, semantic event delivery, finish reason, usage, and pre-generation cleanup. [`completion-executor.ts:75`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-executor.ts:75) [`completion-executor.ts:219`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-executor.ts:219)
|
|
18
|
-
|
|
19
|
-
Chat and raw-text adapters still declare their semantic components and format their own wire responses. Their streaming and non-streaming branches now call the same executor. `GenerationGateway` still owns placement and model execution. The change does not add or remove flags, alter defaults, or substitute one inference method for another.
|
|
20
|
-
|
|
21
|
-
S3 completed the scheduling declaration at the same seam. A
|
|
22
|
-
`GenerationPlacement` now names `serial` or `continuous`; it no longer calls a
|
|
23
|
-
lone scheduler request "batched." The continuous scheduler chooses its B=1
|
|
24
|
-
fast path or B=N step from active rows. The strict serial executor remains for
|
|
25
|
-
`--batch 1` and for declared compositions the continuous scheduler does not yet
|
|
26
|
-
implement. Existing parity evidence covers both the default scheduler's B=1
|
|
27
|
-
path and strict serial. The recorded scheduler/serial decode ratios are
|
|
28
|
-
0.992–0.996, and a fresh main-vs-branch serial gate after the sampler
|
|
29
|
-
consolidation measured a 1.000 median-best ratio (about 265.0 tok/s on both
|
|
30
|
-
sides, MiniCPM5, two interleaved 256-token repeats).
|
|
31
|
-
|
|
32
|
-
Final acceptance after the GPQA pause exercised the seam through the complete
|
|
33
|
-
two-shard suite and a real two-turn browser conversation. The suite passed
|
|
34
|
-
2,064 tests with zero failures. The browser run verified streaming, tool
|
|
35
|
-
events, context carryover, metrics, and turn recovery. A mainline-only queued
|
|
36
|
-
DOM render race found by that run was fixed at the UI lifecycle boundary; no
|
|
37
|
-
decode-loop work was added. The architecture changes likewise keep accounting
|
|
38
|
-
and capability decisions outside numerical kernels. The fresh serial A/B plus
|
|
39
|
-
the established scheduler B=1 parity and latency evidence are the performance
|
|
40
|
-
gate.
|
|
41
|
-
|
|
42
|
-
## What the oracle actually does
|
|
43
|
-
|
|
44
|
-
The HTTP adapter creates a small `CompletionRequest` that still contains protocol-shaped chat messages or a raw text prompt. It separately builds `GenerationArguments`. Prompt preparation has not happened yet. [`server.py:182`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:182) [`server.py:198`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:198) [`server.py:1368`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1368)
|
|
45
|
-
|
|
46
|
-
`ResponseGenerator.generate()` submits that pair to one worker thread through a queue. The worker applies the chat template, tokenizes, finds cache segments, chooses the initial reasoning state, constructs stop/tool/reasoning transitions, selects a lane, owns cache work, and emits per-token `Response` records. [`server.py:516`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:516) [`server.py:626`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:626) [`server.py:688`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:688) [`server.py:1026`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1026)
|
|
47
|
-
|
|
48
|
-
That organization can be summarized as:
|
|
49
|
-
|
|
50
|
-
```text
|
|
51
|
-
HTTP request
|
|
52
|
-
-> CompletionRequest + GenerationArguments
|
|
53
|
-
-> ResponseGenerator queue
|
|
54
|
-
-> tokenize + state machine + lane + cache
|
|
55
|
-
-> token Response { text, token, state, match, logprob, finish_reason }
|
|
56
|
-
-> HTTP handler accumulates semantics and formats the protocol response
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
The model loader is separate. `utils.load()` returns the model and a tokenizer wrapper, while tokenizer loading chooses the streaming detokenizer and tool parser. This keeps model construction out of per-request execution. [`utils.py:453`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/utils.py:453) [`tokenizer_utils.py:578`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/tokenizer_utils.py:578)
|
|
60
|
-
|
|
61
|
-
## Comparison by concern
|
|
62
|
-
|
|
63
|
-
| Concern | Oracle organization | Consequence for the mlx-bun seam |
|
|
64
|
-
| --- | --- | --- |
|
|
65
|
-
| Prepared prompt | The worker owns chat templating, tokenization, initial reasoning state, and cache-oriented prompt segmentation. The HTTP adapter does not know those details. [`server.py:530`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:530) [`server.py:565`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:565) | A prepared-prompt value is a sound seam, but it should be richer than token ids. It must carry the generation inputs and owned media or grammar state needed by either lane. Protocol adapters should not assemble `RequestShape` or transfer resources piecemeal. |
|
|
66
|
-
| Semantic events | The state machine classifies tokens as `normal`, `reasoning`, or `tool`. `_process_control_tokens` withholds matched control sequences. The HTTP handler then accumulates reasoning, tool text, visible text, and parses completed tool calls. [`server.py:236`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:236) [`server.py:654`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:654) [`server.py:1442`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1442) | Do not copy this split. mlx-bun's `CompletionSink` already emits content, reasoning, and tool-call events through one interface. [`completion-sink.ts:7`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-sink.ts:7) [`completion-sink.ts:90`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-sink.ts:90) The deepened module should own that semantic work so all protocol adapters consume the same events. |
|
|
67
|
-
| Terminal summary | `generate.stream_generate()` puts timing, token counts, memory, and finish reason on every low-level response, but the server discards most of it. The HTTP handler counts emitted tokens, reads prompt and cache counts from `GenerationContext`, derives tool-call finish, and builds usage. [`generate.py:269`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/generate.py:269) [`generate.py:728`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/generate.py:728) [`server.py:1495`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1495) [`server.py:1517`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1517) | The oracle has no single terminal summary at the server seam. mlx-bun should add one. It should be the sole source of finish reason, prompt/generated/cached counts, final lane, speculation facts, and collected result. |
|
|
68
|
-
| Streaming and non-streaming | Both modes consume the same response iterator and semantic accumulation loop. Streaming flushes deltas and optionally emits a final usage packet; non-streaming sends one accumulated response. [`server.py:1454`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1454) [`server.py:1507`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1507) [`server.py:1529`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1529) | Keep one Completion execution interface. Streaming and non-streaming are protocol adapters over the same semantic events and terminal summary, not separate execution paths. |
|
|
69
|
-
| Scheduling placement | Model loading marks a model batchable only when no draft model exists and every cache supports merge. Per-request placement also excludes a fixed seed. The worker joins the active batch, creates a batch, runs serially, or drains an incompatible batch. [`server.py:370`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:370) [`server.py:685`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:685) [`server.py:731`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:731) [`server.py:801`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:801) [`server.py:831`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:831) | `RequestShape` describes settings already resolved from flags, request fields, model metadata, and defaults. `place()` asks only whether the continuous scheduler implements that exact composition; it never replaces MTP, a KV scheme, or another requested method. The frozen declaration names the `serial` or `continuous` mechanism, and both reporting and `run()` consume it. Active-row count selects B=1 or B=N inside the continuous mechanism. |
|
|
70
|
-
| Cancellation and flow | Cancellation is cooperative. The handler's `finally` sets a flag; serial execution checks it after tokens, while batched execution checks it during prompt and generation work and removes the row. [`server.py:1008`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1008) [`server.py:861`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:861) [`server.py:911`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:911) [`server.py:1551`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1551) The response queue is unbounded, and socket writes block only the HTTP thread, so there is no end-to-end demand signal from the client to generation. [`server.py:444`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:444) [`server.py:1032`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1032) [`server.py:1489`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1489) | Do not regress to the oracle here. mlx-bun's token callback accepts a promise or `false`, and `GenerationGateway.run()` accepts an `AbortSignal`. [`generation-gateway.ts:94`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/generation-gateway.ts:94) [`generation-gateway.ts:354`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/generation-gateway.ts:354) Cancellation and async flow control are part of the interface, not HTTP details. |
|
|
71
|
-
| Cache and resource lifetime | The worker fetches or creates the serial cache, generates, then inserts it. Batched execution fetches before admission, snapshots segment caches, inserts the final cache, and removes cancelled rows. [`server.py:963`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:963) [`server.py:1018`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1018) [`server.py:752`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:752) [`server.py:864`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:864) [`server.py:901`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:901) `LRUPromptCache` hides prefix matching, copying, trimming, and count/byte eviction behind a small interface. [`cache.py:1623`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/models/cache.py:1623) [`cache.py:1674`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/models/cache.py:1674) [`cache.py:1696`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/models/cache.py:1696) | `prepareCompletion()` now disposes owned media and grammar state on admission rejection. `execute()` disposes the same plan on placement or pre-generation failure, then transfers ownership exactly once before `GenerationGateway.run()`. Cache and in-generation disposal remain in the gateway and generation path. [`completion-executor.ts:75`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-executor.ts:75) [`completion-executor.ts:219`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-executor.ts:219) |
|
|
72
|
-
| Errors | Errors before the response iterator exists become a JSON error, although the oracle uses status 404 for that whole class. Errors delivered later through the worker queue are raised by the iterator. The handler guarantees `ctx.stop()` but has no matching mid-stream error packet in this loop. [`server.py:1417`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1417) [`server.py:1424`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1424) [`server.py:1035`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1035) [`server.py:1454`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1454) | Preserve a typed distinction between rejection before execution and failure after events begin. Both must run the same ownership cleanup. Protocol adapters decide how to encode the failure after headers have been sent. |
|
|
73
|
-
|
|
74
|
-
## Strongest conclusions
|
|
75
|
-
|
|
76
|
-
1. **Keep resolved inference settings authoritative.** Serial and continuous execution are scheduling mechanisms for the already-selected composition. Consolidating placement may shrink the HTTP adapter, but it must not turn explicit features or opinionated defaults into inferred choices.
|
|
77
|
-
2. **Do not borrow the oracle's semantic split.** Its worker emits state-tagged token records, then the HTTP handler performs semantic accumulation and tool parsing. mlx-bun already has a better starting point in `CompletionSink`. Move that module behind the Completion execution seam so protocol adapters see semantic events only.
|
|
78
|
-
3. **Keep the terminal summary as the only completion result.** It now settles finish reason, usage, cached-token count, final lane, speculation, logprobs, and collected output once. The four HTTP branches only format that summary. [`completion-executor.ts:103`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-executor.ts:103) [`server.ts:3104`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/server.ts:3104)
|
|
79
|
-
4. **Treat cancellation, async flow control, and ownership as interface requirements.** The oracle's queue makes cancellation and socket pressure indirect. mlx-bun has stronger mechanisms already. The deepening should hide their implementation without weakening their behavior.
|
|
80
|
-
|
|
81
|
-
The deletion test is positive. If this Completion execution module disappeared, scheduling policy, cache participation, semantic parsing, finish rules, usage, and cleanup would spread back across four protocol branches. Concentrating those rules gives callers leverage and gives maintainers locality. Feature selection and fidelity policy remain outside this seam as resolved inputs.
|