mlx-bun 0.2.0 → 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 -588
- package/docs/README.md +91 -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/{design → archive/investigations}/optimization_plan.md +1 -1
- package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
- package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
- 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 +2 -2
- package/docs/reference/benchmarks.md +1162 -0
- package/docs/reference/cli.md +394 -159
- package/docs/reference/distribution.md +321 -182
- package/docs/reference/environment.md +348 -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 +104 -6
- package/docs/reference/server-api.md +886 -425
- package/docs/reference/server-config.md +638 -330
- package/docs/reference/training.md +393 -254
- package/docs/reference/troubleshooting.md +166 -0
- package/package.json +9 -4
- 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 +58 -25
- 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 +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 +1 -1
- package/src/generate.ts +656 -268
- 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/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-store.ts +109 -49
- 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/{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 +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 +9 -10
- 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/batched-mask.ts +8 -2
- package/src/model/batched-quant.ts +1 -1
- package/src/model/batched-rotating-quant.ts +2 -2
- package/src/model/batched-rotating.ts +1 -1
- package/src/model/compiled-decode.ts +1 -1
- 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/gemma4-base.ts +26 -9
- package/src/model/gemma4.ts +6 -6
- package/src/model/generated/gemma4-12b.ts +2 -2
- package/src/model/generated/gemma4-26b.ts +2 -2
- package/src/model/generated/gemma4-e4b.ts +2 -2
- package/src/model/glm52-dsa.ts +13 -9
- package/src/model/glm52-memory.ts +1 -1
- package/src/model/implementation.ts +69 -0
- package/src/model/minicpm5.ts +6 -8
- 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_5-checkpoint.ts +164 -0
- package/src/model/qwen3_5.ts +140 -56
- 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-pack.ts +6 -5
- package/src/pi-provider.ts +6 -64
- package/src/pi-web.ts +8 -315
- package/src/prompt-cache.ts +96 -53
- 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 +4 -4
- 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 +154 -193
- 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 +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/request-plan.ts +19 -15
- 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 +5 -5
- package/src/serve/text-completion-stage.ts +104 -0
- package/src/serve/token-streams.ts +519 -0
- package/src/server.ts +317 -2649
- package/src/spec/assistant-source.ts +10 -44
- package/src/spec/deepspec-source.ts +6 -6
- package/src/spec/dflash-source.ts +8 -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 +4 -3
- 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 +1 -1
- package/src/spec/ngram-source.ts +1 -1
- package/src/spec/prefix-state.ts +45 -0
- package/src/spec/qwen-mtp-source.ts +166 -69
- package/src/spec/serve-loop.ts +154 -156
- package/src/spec/source.ts +42 -10
- package/src/spec/two-model.ts +1 -1
- package/src/ssd-cache.ts +80 -12
- package/src/ssd-durability.ts +25 -13
- 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 +5 -3
- 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
|
@@ -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,9 +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 "
|
|
22
|
-
import { runtimeValue } from "
|
|
20
|
+
import { Dtype } from "../../mlx/ffi";
|
|
21
|
+
import type { MlxArray } from "../../mlx/array";
|
|
22
|
+
import { runtimeValue } from "../../runtime-config";
|
|
23
23
|
|
|
24
24
|
let sink: Bun.FileSink | null = null;
|
|
25
25
|
let seq = 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,7 +17,7 @@
|
|
|
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";
|
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,8 @@
|
|
|
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 { BatchScheduler, type RowSampler } from "../serve/batch-scheduler";
|
|
31
|
-
import * as ops from "../mlx/ops";
|
|
32
|
-
import type { MlxArray } from "../mlx/array";
|
|
33
29
|
import { runtimeValue } from "../runtime-config";
|
|
34
30
|
|
|
35
31
|
const HF_HUB = `${process.env.HOME}/.cache/huggingface/hub`;
|
|
@@ -38,7 +34,7 @@ const E4B_REPO = "models--mlx-community--gemma-4-e4b-it-OptiQ-4bit";
|
|
|
38
34
|
/** Resolve the e4b snapshot dir by globbing snapshots/ for the one carrying
|
|
39
35
|
* config.json — so a freshly-downloaded model needs no hardcoded commit hash.
|
|
40
36
|
* Returns an _unresolved sentinel (precheck → STOP) until the download lands.
|
|
41
|
-
* 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-
|
|
42
38
|
* contained (no src→tests dependency). */
|
|
43
39
|
function resolveE4bSnapshot(): string {
|
|
44
40
|
const base = `${HF_HUB}/${E4B_REPO}/snapshots`;
|
|
@@ -140,30 +136,18 @@ export function memoryPromptIds(
|
|
|
140
136
|
/** Async mutex: acquire() resolves to a release fn; releases run FIFO. Serializes
|
|
141
137
|
* memory generation ops so the global `loraState.active` is owned exclusively for
|
|
142
138
|
* one op's lifetime (set for the chunk batch, reset after). */
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const gate = new Promise<void>((r) => { release = r; });
|
|
148
|
-
const wait = this.#tail;
|
|
149
|
-
this.#tail = this.#tail.then(() => gate);
|
|
150
|
-
return wait.then(() => release);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
interface MemoryRuntime {
|
|
155
|
-
tm: TaskModel;
|
|
156
|
-
template: ChatTemplate;
|
|
157
|
-
scheduler: BatchScheduler;
|
|
158
|
-
/** True once the `memory-chunk` adapter is mounted on the shared model. */
|
|
159
|
-
hasChunkAdapter: boolean;
|
|
139
|
+
export interface MemoryCompletionRequest {
|
|
140
|
+
readonly stage: string;
|
|
141
|
+
readonly input: LocalInput;
|
|
142
|
+
readonly maxTokens: number;
|
|
160
143
|
}
|
|
144
|
+
export type MemoryCompletionClient = import("../contracts/completion").BatchCompletionClient<MemoryCompletionRequest, string>;
|
|
161
145
|
|
|
162
146
|
/** Max rows in a memory batch (continuous-batching width). 1 disables batching
|
|
163
147
|
* (callLocalBatch then loops on the bit-exact greedy fallback).
|
|
164
148
|
* Default 1 (serial): batching measured 1.7-1.9x SLOWER for the real
|
|
165
149
|
* extract/chunk workload (heterogeneous prefills pad) and can diverge on
|
|
166
|
-
* near-ties — see docs/design/
|
|
150
|
+
* near-ties — see docs/design/dreaming-nightly-pipeline.md "Verification results".
|
|
167
151
|
* Opt back in with MLX_BUN_MEMORY_BATCH=8 if a length-bucketed scheduler
|
|
168
152
|
* lands. (Decision: Josh, 2026-07-01.) */
|
|
169
153
|
export function memoryBatchSize(): number {
|
|
@@ -171,152 +155,29 @@ export function memoryBatchSize(): number {
|
|
|
171
155
|
return Number.isFinite(n) && n >= 1 ? Math.floor(n) : 1;
|
|
172
156
|
}
|
|
173
157
|
|
|
174
|
-
function requireModel(): void {
|
|
175
|
-
if (!existsSync(`${MODEL_ID}/config.json`)) {
|
|
176
|
-
throw new Error(
|
|
177
|
-
`memory: Gemma-4-e4b is not downloaded (looked under ${HF_HUB}/${E4B_REPO}/snapshots). ` +
|
|
178
|
-
`Fetch it first:\n HF_HUB_DISABLE_XET=1 hf download mlx-community/gemma-4-e4b-it-OptiQ-4bit`,
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
let runtimePromise: Promise<MemoryRuntime> | null = null;
|
|
184
|
-
const opLock = new AsyncMutex(); // serializes whole memory ops (loraState ownership)
|
|
185
|
-
const schedLock = new AsyncMutex(); // the scheduler's exclusive-GPU lock
|
|
186
|
-
|
|
187
|
-
/** Lazily load the ONE shared model + mount memory-chunk + build the scheduler.
|
|
188
|
-
* Never auto-downloads; throws (with the fetch hint) until the snapshot lands. */
|
|
189
|
-
async function getRuntime(): Promise<MemoryRuntime> {
|
|
190
|
-
if (!runtimePromise) {
|
|
191
|
-
runtimePromise = (async () => {
|
|
192
|
-
requireModel();
|
|
193
|
-
const tm = await loadTaskModel(MODEL_ID); // base e4b, no adapter
|
|
194
|
-
if (!tm.template) throw new Error(`memory: ${MODEL_ID} has no chat template`);
|
|
195
|
-
let hasChunkAdapter = false;
|
|
196
|
-
const chunkDir = adapterDirFor("chunk");
|
|
197
|
-
if (chunkDir) {
|
|
198
|
-
// Mount ONCE; activation is per-call via loraState.active (see decodeGreedy
|
|
199
|
-
// / batchDecode). Mounting alone runs base — it must be activated.
|
|
200
|
-
const { AdapterManager } = await import("../lora");
|
|
201
|
-
await new AdapterManager(tm.model).mount("memory-chunk", chunkDir);
|
|
202
|
-
hasChunkAdapter = true;
|
|
203
|
-
}
|
|
204
|
-
const scheduler = new BatchScheduler(tm.model, {
|
|
205
|
-
maxBatch: memoryBatchSize(),
|
|
206
|
-
lock: { acquire: () => schedLock.acquire() },
|
|
207
|
-
});
|
|
208
|
-
return { tm, template: tm.template, scheduler, hasChunkAdapter };
|
|
209
|
-
})();
|
|
210
|
-
}
|
|
211
|
-
return runtimePromise;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/** The adapters to activate for a stage. Only `chunk` is adapter-bound (and only
|
|
215
|
-
* when `memory-chunk` is mounted); every base stage runs with `active = []`. */
|
|
216
|
-
function activeFor(stage: string, rt: MemoryRuntime): string[] {
|
|
217
|
-
return stage === "chunk" && rt.hasChunkAdapter ? ["memory-chunk"] : [];
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/** One bit-exact greedy decode for a stage (raw-forward argmax, runner parity).
|
|
221
|
-
* Sets the stage's adapter for the call and resets `active` to [] after. */
|
|
222
|
-
function decodeGreedy(rt: MemoryRuntime, stage: string, input: LocalInput, maxTokens: number): string {
|
|
223
|
-
const active = activeFor(stage, rt);
|
|
224
|
-
rt.tm.model.loraState.active = active;
|
|
225
|
-
const ids = memoryPromptIds(stage, input, rt.tm.tokenizer, rt.template);
|
|
226
|
-
try {
|
|
227
|
-
return greedyDecodeBitExact(
|
|
228
|
-
{ ...rt.tm, activeAdapters: active.length ? active : undefined },
|
|
229
|
-
ids,
|
|
230
|
-
maxTokens,
|
|
231
|
-
);
|
|
232
|
-
} finally {
|
|
233
|
-
rt.tm.model.loraState.active = [];
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/** Batched decode for N independent inputs of ONE stage. Sets the stage adapter
|
|
238
|
-
* globally for the whole batch (the scheduler reads `loraState.active` per
|
|
239
|
-
* forward, so all rows get it uniformly — a batch is necessarily single-adapter),
|
|
240
|
-
* submits every row to the shared scheduler with a greedy per-row sampler, and
|
|
241
|
-
* resets `active` after all rows finish. Order-preserving: out[i] ↔ inputs[i].
|
|
242
|
-
*
|
|
243
|
-
* Decode-path caveat: this samples via forwardHidden/logitsFromHidden (the
|
|
244
|
-
* scheduler), which can diverge from the runner's raw-forward greedy on near-ties
|
|
245
|
-
* past ~32 tokens. For the JSON/binary memory stages (validated by
|
|
246
|
-
* well-formedness) this is acceptable; the single-call fallback stays bit-exact. */
|
|
247
|
-
async function batchDecode(
|
|
248
|
-
rt: MemoryRuntime,
|
|
249
|
-
stage: string,
|
|
250
|
-
inputs: LocalInput[],
|
|
251
|
-
maxTokens: number,
|
|
252
|
-
): Promise<string[]> {
|
|
253
|
-
const active = activeFor(stage, rt);
|
|
254
|
-
rt.tm.model.loraState.active = active;
|
|
255
|
-
const eos = rt.tm.config.eosTokenIds;
|
|
256
|
-
const greedySample: RowSampler = (logits1V: MlxArray) => ops.argmaxAxis(logits1V, -1);
|
|
257
|
-
try {
|
|
258
|
-
return await Promise.all(
|
|
259
|
-
inputs.map((inp) => {
|
|
260
|
-
const ids = memoryPromptIds(stage, inp, rt.tm.tokenizer, rt.template);
|
|
261
|
-
const toks: number[] = [];
|
|
262
|
-
return rt.scheduler
|
|
263
|
-
.submit({
|
|
264
|
-
promptIds: ids,
|
|
265
|
-
maxTokens,
|
|
266
|
-
eosTokenIds: eos,
|
|
267
|
-
sample: greedySample,
|
|
268
|
-
onToken: (t) => { toks.push(t); },
|
|
269
|
-
})
|
|
270
|
-
.then(() => rt.tm.tokenizer.decode(toks, true));
|
|
271
|
-
}),
|
|
272
|
-
);
|
|
273
|
-
} finally {
|
|
274
|
-
rt.tm.model.loraState.active = [];
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// ---------------------------------------------------------------------------
|
|
279
|
-
// Public seams
|
|
280
|
-
// ---------------------------------------------------------------------------
|
|
281
158
|
|
|
282
|
-
/**
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
):
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
try {
|
|
294
|
-
return decodeGreedy(rt, stage, input, opts?.maxTokens ?? 256);
|
|
295
|
-
} finally {
|
|
296
|
-
release();
|
|
297
|
-
}
|
|
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
|
+
};
|
|
298
170
|
}
|
|
299
171
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
)
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
try {
|
|
313
|
-
if (inputs.length === 1 || memoryBatchSize() <= 1) {
|
|
314
|
-
const out: string[] = [];
|
|
315
|
-
for (const inp of inputs) out.push(decodeGreedy(rt, stage, inp, maxTokens));
|
|
316
|
-
return out;
|
|
317
|
-
}
|
|
318
|
-
return await batchDecode(rt, stage, inputs, maxTokens);
|
|
319
|
-
} finally {
|
|
320
|
-
release();
|
|
321
|
-
}
|
|
322
|
-
}
|
|
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.
|
|
@@ -987,10 +987,8 @@ const REFERENCE_LINKS: { name: string; source: string }[] = [
|
|
|
987
987
|
{ name: "mlx-bun_Server_API", source: join(REPO_ROOT, "docs", "reference", "server-api.md") },
|
|
988
988
|
{ name: "mlx-bun_Server_Config", source: join(REPO_ROOT, "docs", "reference", "server-config.md") },
|
|
989
989
|
{ name: "mlx-bun_Library_API", source: join(REPO_ROOT, "docs", "reference", "library-api.md") },
|
|
990
|
-
{ name: "mlx-bun_Embedding", source: join(REPO_ROOT, "docs", "reference", "embedding.md") },
|
|
991
990
|
{ name: "mlx-bun_Distribution", source: join(REPO_ROOT, "docs", "reference", "distribution.md") },
|
|
992
991
|
{ name: "mlx-bun_Training", source: join(REPO_ROOT, "docs", "reference", "training.md") },
|
|
993
|
-
{ name: "mlx-bun_ORPO_Quickstart", source: join(REPO_ROOT, "docs", "reference", "orpo-quickstart.md") },
|
|
994
992
|
{ name: "mlx-bun_Product_Roadmap", source: join(REPO_ROOT, "docs", "planning", "PRODUCT_ROADMAP.md") },
|
|
995
993
|
];
|
|
996
994
|
|
package/src/mlx/array.ts
CHANGED
|
@@ -46,17 +46,16 @@ let nextPinId = 1;
|
|
|
46
46
|
// do nothing — a dtor mlx can safely call from ANY thread. The pointed-to
|
|
47
47
|
// memory's lifetime is the CALLER's contract (weight mmaps live for the
|
|
48
48
|
// process; restored KV is COPIED at load since 2026-07-07 — see kv-store.ts
|
|
49
|
-
// loadKvCache — so no restore mapping needs pinning anymore).
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
dlsym: { args: ["u64", "ptr"], returns: "u64" },
|
|
49
|
+
// loadKvCache — so no restore mapping needs pinning anymore). Bun >= 1.4
|
|
50
|
+
// returns a numeric function address from .ptr; verified against dlsym on
|
|
51
|
+
// 1.4.0 and 1.4.2. Keep the library open for every native destructor's lifetime.
|
|
52
|
+
const libcFree = dlopen("/usr/lib/libSystem.B.dylib", {
|
|
53
|
+
free: { args: ["ptr"], returns: "void" },
|
|
55
54
|
});
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
// The pinned bun-types predates the runtime's numeric .ptr property.
|
|
56
|
+
const freeFnAddr = Number(Reflect.get(libcFree.symbols.free, "ptr"));
|
|
57
|
+
if (!Number.isSafeInteger(freeFnAddr) || freeFnAddr <= 0)
|
|
58
|
+
throw new Error("free.ptr is invalid — zero-copy arrays need a native no-op dtor");
|
|
60
59
|
|
|
61
60
|
export function pinnedBufferCount(): number {
|
|
62
61
|
return pinned.size;
|
package/src/mlx/compile.ts
CHANGED
|
@@ -23,8 +23,14 @@ import { MlxArray } from "./array";
|
|
|
23
23
|
|
|
24
24
|
export type TraceFn = (inputs: MlxArray[]) => MlxArray[];
|
|
25
25
|
|
|
26
|
-
const traceRegistry = new Map<number, { fn: TraceFn; count: number }>();
|
|
26
|
+
const traceRegistry = new Map<number, { fn: TraceFn; count: number; shapeless: boolean }>();
|
|
27
27
|
let nextTraceId = 1;
|
|
28
|
+
let shapelessTracing = false;
|
|
29
|
+
|
|
30
|
+
/** Fixed-shape custom kernels must fall back while a shapeless graph traces. */
|
|
31
|
+
export function isShapelessTracing(): boolean {
|
|
32
|
+
return shapelessTracing;
|
|
33
|
+
}
|
|
28
34
|
/** Error thrown by a trace fn, carried across the C boundary (the
|
|
29
35
|
* trampoline must not throw into mlx; it returns non-zero instead). */
|
|
30
36
|
let traceError: unknown = null;
|
|
@@ -40,9 +46,11 @@ export let traceCalls = 0;
|
|
|
40
46
|
// error handler in ffi.ts).
|
|
41
47
|
const trampoline = new JSCallback(
|
|
42
48
|
(resPtr: number, argsVec: bigint, payload: number): number => {
|
|
49
|
+
const previousShapeless = shapelessTracing;
|
|
43
50
|
try {
|
|
44
51
|
const entry = traceRegistry.get(payload);
|
|
45
52
|
if (!entry) throw new Error(`compile trampoline: unknown trace id ${payload}`);
|
|
53
|
+
shapelessTracing ||= entry.shapeless;
|
|
46
54
|
const fn = entry.fn;
|
|
47
55
|
entry.count++;
|
|
48
56
|
traceCalls++;
|
|
@@ -66,6 +74,8 @@ const trampoline = new JSCallback(
|
|
|
66
74
|
} catch (e) {
|
|
67
75
|
traceError = e;
|
|
68
76
|
return 1;
|
|
77
|
+
} finally {
|
|
78
|
+
shapelessTracing = previousShapeless;
|
|
69
79
|
}
|
|
70
80
|
},
|
|
71
81
|
{ args: ["ptr", "u64", "ptr"], returns: "i32" },
|
|
@@ -95,7 +105,7 @@ export class CompiledFunction {
|
|
|
95
105
|
|
|
96
106
|
constructor(fn: TraceFn, shapeless = true) {
|
|
97
107
|
this.#traceId = nextTraceId++;
|
|
98
|
-
traceRegistry.set(this.#traceId, { fn, count: 0 });
|
|
108
|
+
traceRegistry.set(this.#traceId, { fn, count: 0, shapeless });
|
|
99
109
|
// payload is the trace id smuggled through the void* (never deref'd);
|
|
100
110
|
// dtor is null — nothing to free on the C side.
|
|
101
111
|
const raw = C.mlx_closure_new_func_payload(trampoline.ptr, this.#traceId as never, null);
|