mlx-bun 0.4.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1453 -88
- package/THIRD_PARTY_NOTICES.md +882 -0
- package/bin/mlx-bun.convert.mjs +4 -0
- package/bin/mlx-bun.fuse.mjs +4 -0
- package/bin/mlx-bun.generate.mjs +4 -0
- package/bin/mlx-bun.lora.mjs +4 -0
- package/bin/mlx-bun.mjs +13 -21
- package/bin/mlx-bun.server.mjs +4 -0
- package/bin/mlx-bun.upload.mjs +4 -0
- package/dist/web/app.js +9584 -0
- package/package.json +50 -53
- package/src/cli/ane-install.ts +76 -0
- package/src/cli/args.ts +179 -0
- package/src/cli/engine-entry.ts +68 -0
- package/src/cli/inference.ts +214 -0
- package/src/cli/job-entry.ts +97 -0
- package/src/cli/library-host.ts +117 -0
- package/src/cli/main.ts +57 -0
- package/src/cli/memory-engine.ts +163 -0
- package/src/cli/memory.ts +36 -0
- package/src/cli/mlx-lm-aliases.ts +309 -0
- package/src/cli/model-choice.ts +33 -0
- package/src/cli/model-selection.ts +84 -0
- package/src/cli/module-host.ts +11 -0
- package/src/cli/module-verbs.ts +50 -0
- package/src/cli/numerical-policy.ts +12 -0
- package/src/cli/perplexity.ts +89 -0
- package/src/cli/serve-host.ts +423 -0
- package/src/cli/serve-isolated.ts +217 -0
- package/src/cli/serve-options.ts +106 -0
- package/src/cli/serve-state.ts +205 -0
- package/src/cli/serve.ts +500 -0
- package/src/cli/served-model-host.ts +102 -0
- package/src/cli/server-entry.ts +148 -0
- package/src/cli/serving-unit.ts +177 -0
- package/src/{tui.ts → cli/terminal.ts} +13 -8
- package/src/cli/worker-adapters.ts +34 -0
- package/src/cli/worker-entry.ts +272 -0
- package/src/cli/worker-unit.ts +179 -0
- package/src/engine/adapter-operation.ts +26 -0
- package/src/engine/cache-services.ts +114 -0
- package/src/engine/completion.ts +39 -0
- package/src/engine/generation-gateway.ts +358 -0
- package/src/engine/index.ts +59 -0
- package/src/engine/kv-budget.ts +120 -0
- package/src/engine/media-preparation.ts +232 -0
- package/src/engine/model-binding.ts +24 -0
- package/src/engine/model-host.ts +513 -0
- package/src/engine/model-serving.ts +89 -0
- package/src/{serve → engine}/preparation.ts +10 -8
- package/src/{serve → engine}/session-completion-engine.ts +6 -6
- package/src/engine/telemetry.ts +109 -0
- package/src/hub/downloads.ts +116 -0
- package/src/jobs/db.ts +16 -7
- package/src/jobs/events.ts +29 -0
- package/src/jobs/executable.ts +5 -0
- package/src/jobs/host.ts +51 -0
- package/src/jobs/in-process.ts +55 -0
- package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
- package/src/jobs/runner.ts +150 -231
- package/src/jobs/service.ts +75 -0
- package/src/jobs/sse.ts +59 -23
- package/src/jobs/worker-memory.ts +46 -0
- package/src/jobs/worker-process.ts +163 -0
- package/src/jobs/worker-supervisor.ts +258 -0
- package/src/modules.ts +58 -0
- package/src/publishing/catalog-hub.ts +18 -0
- package/src/publishing/credentials.ts +31 -0
- package/src/publishing/upload.ts +37 -0
- package/src/residency/leased-adapters.ts +21 -0
- package/src/residency/local-records.ts +16 -0
- package/src/residency/model-residency.ts +405 -0
- package/src/residency/record-index.ts +28 -0
- package/src/residency/resident-estimate.ts +50 -0
- package/src/{anthropic.ts → server/anthropic.ts} +3 -81
- package/src/server/cache-routes.ts +36 -0
- package/src/{serve → server}/chat-request.ts +12 -10
- package/src/{serve → server}/chat-stage.ts +27 -22
- package/src/{client.ts → server/client.ts} +28 -2
- package/src/{serve → server}/completion-executor.ts +42 -42
- package/src/server/decision-body.ts +55 -0
- package/src/server/decision-routes.ts +134 -0
- package/src/server/decision-wire.ts +228 -0
- package/src/{serve → server}/discovery-routes.ts +42 -83
- package/src/server/generated-token-history.ts +57 -0
- package/src/{serve → server}/http.ts +25 -13
- package/src/{serve → server}/inference-request.ts +5 -5
- package/src/server/job-routes.ts +20 -0
- package/src/server/media-prompt.ts +63 -0
- package/src/server/memory-completion-client.ts +46 -0
- package/src/server/model-routes.ts +192 -0
- package/src/{serve → server}/openai-wire.ts +3 -2
- package/src/{serve → server}/pipeline.ts +1 -1
- package/src/server/prompt-builder.ts +13 -0
- package/src/server/prompt-contracts.ts +17 -0
- package/src/server/proxy-routes.ts +187 -0
- package/src/server/publishing-routes.ts +41 -0
- package/src/{serve → server}/request-plan.ts +8 -8
- package/src/{serve → server}/request-prep.ts +82 -68
- package/src/{serve → server}/responses-client.ts +30 -13
- package/src/{responses.ts → server/responses.ts} +12 -93
- package/src/server/routes.ts +205 -0
- package/src/server/start.ts +72 -0
- package/src/server/status-routes.ts +108 -0
- package/src/{serve → server}/text-completion-stage.ts +25 -4
- package/src/server/text-prompt.ts +12 -0
- package/src/{serve → server}/token-streams.ts +36 -38
- package/src/server/worker-routes.ts +311 -0
- package/src/storage/paths.ts +61 -0
- package/src/web/assets.ts +37 -0
- package/src/web/{src → browser}/api.ts +5 -23
- package/src/web/browser/chat-host.ts +17 -0
- package/src/web/browser/installed-panels.ts +6 -0
- package/src/web/browser/main.ts +55 -0
- package/src/web/browser/markdown.ts +279 -0
- package/src/web/browser/memory-panel.ts +9 -0
- package/src/web/browser/palette.ts +64 -0
- package/src/web/browser/protocol.ts +13 -0
- package/src/web/browser/shell.ts +467 -0
- package/src/web/{src → browser}/status.ts +32 -36
- package/src/web/build.ts +51 -0
- package/src/web/public/app.html +1054 -0
- package/src/web/{sw.js → public/sw.js} +4 -3
- package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
- package/src/web/{vendor → public/vendor}/hljs.js +2 -2
- package/THIRD_PARTY_LICENSES.md +0 -51
- package/docs/README.md +0 -94
- package/docs/archive/hlg-sampling.md +0 -350
- package/docs/archive/investigations/audio-input-plan.md +0 -356
- package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
- package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
- package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
- package/docs/archive/investigations/curve-bisector-routing.md +0 -123
- package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
- package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
- package/docs/archive/investigations/dspark-handoff.md +0 -224
- package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
- package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
- package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
- package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
- package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
- package/docs/archive/investigations/lab-build-journal.md +0 -157
- package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
- package/docs/archive/investigations/openjarvis-fit.md +0 -198
- package/docs/archive/investigations/openwiki-evaluation.md +0 -249
- package/docs/archive/investigations/optimization_plan.md +0 -346
- package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
- package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
- package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
- package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
- package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
- package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
- package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
- package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
- package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
- package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
- package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
- package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
- package/docs/archive/planning/chat-ui-vision.md +0 -50
- package/docs/archive/planning/chunk-task-roadmap.md +0 -77
- package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
- package/docs/archive/planning/journal.md +0 -316
- package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
- package/docs/archive/planning/pi-integration-review.md +0 -178
- package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
- package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
- package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
- package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
- package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
- package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
- package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
- package/docs/archive/planning/web-ui-pass-plan.md +0 -213
- package/docs/archive/planning/website-readme-pass-plan.md +0 -224
- package/docs/design/batching.md +0 -1841
- package/docs/design/decode-speed-program.md +0 -2349
- package/docs/design/dreaming-nightly-pipeline.md +0 -684
- package/docs/design/generic-model-support.md +0 -705
- package/docs/design/kv-cache.md +0 -824
- package/docs/design/orpo-training.md +0 -680
- package/docs/design/speculative-decoding.md +0 -1990
- package/docs/design/turboquant.md +0 -2212
- package/docs/design/unified-engine-frontier-plan.md +0 -1880
- package/docs/design/web-chat-redesign.md +0 -695
- package/docs/planning/PRODUCT_ROADMAP.md +0 -594
- package/docs/planning/ResearchTopics.md +0 -119
- package/docs/planning/release-notes-v0.4.0.md +0 -45
- package/docs/planning/video-series.md +0 -421
- package/docs/reference/benchmarks.md +0 -3613
- package/docs/reference/cli.md +0 -585
- package/docs/reference/distribution.md +0 -355
- package/docs/reference/environment.md +0 -398
- package/docs/reference/glossary.md +0 -39
- package/docs/reference/library-api.md +0 -674
- package/docs/reference/memory.md +0 -260
- package/docs/reference/models.md +0 -334
- package/docs/reference/server-api.md +0 -1775
- package/docs/reference/server-config.md +0 -846
- package/docs/reference/training.md +0 -462
- package/docs/reference/troubleshooting.md +0 -158
- package/src/admission-plan.ts +0 -18
- package/src/audio/conformer.ts +0 -647
- package/src/audio/decode.ts +0 -133
- package/src/audio/features.ts +0 -202
- package/src/audio/transcode.ts +0 -67
- package/src/backends/mlx/assistant-target.ts +0 -46
- package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
- package/src/backends/mlx/autoregressive.ts +0 -108
- package/src/backends/mlx/batch-group.ts +0 -1790
- package/src/backends/mlx/cache-attachment.ts +0 -67
- package/src/backends/mlx/cache-layout.ts +0 -31
- package/src/backends/mlx/checkpoint-state.ts +0 -53
- package/src/backends/mlx/continuation-persistence.ts +0 -106
- package/src/backends/mlx/continuation-request.ts +0 -43
- package/src/backends/mlx/continuation.ts +0 -77
- package/src/backends/mlx/diffusion.ts +0 -39
- package/src/backends/mlx/draft-target.ts +0 -32
- package/src/backends/mlx/evaluation.ts +0 -105
- package/src/backends/mlx/fill-append.ts +0 -45
- package/src/backends/mlx/full-kv-row-append.ts +0 -32
- package/src/backends/mlx/full-kv-row-donor.ts +0 -54
- package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
- package/src/backends/mlx/gateway-binding.ts +0 -130
- package/src/backends/mlx/graph.ts +0 -38
- package/src/backends/mlx/kv-codec.ts +0 -9
- package/src/backends/mlx/kv-maintenance.ts +0 -133
- package/src/backends/mlx/kv-tensor-rows.ts +0 -212
- package/src/backends/mlx/memory-client.ts +0 -189
- package/src/backends/mlx/methods.ts +0 -90
- package/src/backends/mlx/model-prompt.ts +0 -164
- package/src/backends/mlx/model-serving.ts +0 -79
- package/src/backends/mlx/prefill-cohort.ts +0 -89
- package/src/backends/mlx/prefill-rows.ts +0 -200
- package/src/backends/mlx/prefill.ts +0 -33
- package/src/backends/mlx/projected-context-rows.ts +0 -72
- package/src/backends/mlx/request-policy.ts +0 -20
- package/src/backends/mlx/request-state-policy.ts +0 -41
- package/src/backends/mlx/rollback.ts +0 -89
- package/src/backends/mlx/row-sampling.ts +0 -49
- package/src/backends/mlx/serial-executor.ts +0 -242
- package/src/backends/mlx/speculative-group.ts +0 -359
- package/src/backends/mlx/speculative-round.ts +0 -161
- package/src/backends/mlx/speculative.ts +0 -114
- package/src/backends/mlx/state-rows.ts +0 -104
- package/src/backends/mlx/state-views.ts +0 -46
- package/src/backends/mlx/target-layout-capability.ts +0 -35
- package/src/backends/mlx/text-engine.ts +0 -73
- package/src/backends/mlx/transitioning-kv-rows.ts +0 -165
- package/src/chat-template.ts +0 -382
- package/src/cli.ts +0 -3168
- package/src/config.ts +0 -399
- package/src/contracts/completion.ts +0 -16
- package/src/contracts/execution.ts +0 -60
- package/src/contracts/generation.ts +0 -103
- package/src/contracts/host.ts +0 -7
- package/src/contracts/pi-provider.ts +0 -30
- package/src/contracts/pi.ts +0 -259
- package/src/contracts/prefix-cache.ts +0 -23
- package/src/contracts/resources.ts +0 -25
- package/src/contracts/sampling.ts +0 -23
- package/src/contracts/scheduling.ts +0 -45
- package/src/contracts/tsconfig.json +0 -14
- package/src/dataset/generators.ts +0 -1087
- package/src/dataset/index.ts +0 -12
- package/src/dataset/job.ts +0 -81
- package/src/dataset/llm.ts +0 -71
- package/src/dataset/registry.ts +0 -528
- package/src/diffusion/diffusion-generate.ts +0 -507
- package/src/download.ts +0 -505
- package/src/embed.ts +0 -77
- package/src/engine/admission.ts +0 -59
- package/src/engine/cancellation.ts +0 -38
- package/src/engine/engine.ts +0 -56
- package/src/engine/execution-coordinator.ts +0 -70
- package/src/engine/execution-plan.ts +0 -53
- package/src/engine/resources.ts +0 -53
- package/src/engine/scheduler.ts +0 -72
- package/src/engine/session.ts +0 -247
- package/src/eval/README.md +0 -130
- package/src/eval/ifeval.ts +0 -81
- package/src/eval/kl-prompts.ts +0 -29
- package/src/eval/kl.ts +0 -590
- package/src/eval/perplexity.ts +0 -164
- package/src/eval/quality-db.ts +0 -92
- package/src/eval/reference-logits.ts +0 -207
- package/src/eval/runner.ts +0 -124
- package/src/eval/score.ts +0 -49
- package/src/eval/tasks/bfcl.ts +0 -535
- package/src/eval/tasks/gsm8k.ts +0 -98
- package/src/eval/tasks/hashhop.ts +0 -139
- package/src/eval/tasks/humaneval.ts +0 -275
- package/src/eval/tasks/ifeval.ts +0 -525
- package/src/eval/tasks/mmlu.ts +0 -157
- package/src/eval/ultrafeedback.ts +0 -60
- package/src/evaldb.ts +0 -199
- package/src/expert-io.ts +0 -393
- package/src/expert-offload-build.ts +0 -77
- package/src/expert-offload.ts +0 -76
- package/src/expert-residency.ts +0 -1134
- package/src/expert-usage.ts +0 -415
- package/src/fill/echo-index.ts +0 -188
- package/src/fill/fill-session.ts +0 -452
- package/src/fill/proposal.ts +0 -68
- package/src/fill/schema-rows.ts +0 -506
- package/src/fill/tool-boundary.ts +0 -103
- package/src/fit.ts +0 -249
- package/src/generate.ts +0 -1346
- package/src/grammar.ts +0 -591
- package/src/harness-pi.ts +0 -184
- package/src/hf-push.ts +0 -628
- package/src/hub-rest.ts +0 -242
- package/src/index.ts +0 -63
- package/src/inference/denoising.ts +0 -17
- package/src/inference/draft-acceptance.ts +0 -41
- package/src/inference/draft-output.ts +0 -49
- package/src/inference/graph.ts +0 -33
- package/src/inference/prefill.ts +0 -39
- package/src/inference/rollback.ts +0 -7
- package/src/jobs/index.ts +0 -31
- package/src/jobs/job-entry.ts +0 -107
- package/src/jobs/task-client.ts +0 -19
- package/src/jobs/types.ts +0 -2
- package/src/kv-scheme.ts +0 -257
- package/src/kv-store.ts +0 -1099
- package/src/lab/README.md +0 -18
- package/src/lab/curve/curve-designer.html +0 -303
- package/src/lab/curve/curve-sampler.ts +0 -122
- package/src/lab/expert-trace/expert-trace.ts +0 -69
- package/src/lab/paged-kv/paged-kv-rows.ts +0 -83
- package/src/lab/paged-kv/paged-kv.ts +0 -270
- package/src/library.ts +0 -40
- package/src/lora.ts +0 -408
- package/src/md-modules.d.ts +0 -49
- package/src/media-fetch.ts +0 -442
- package/src/memory/article.ts +0 -558
- package/src/memory/chunk-validation.ts +0 -150
- package/src/memory/chunk.ts +0 -318
- package/src/memory/cluster.ts +0 -351
- package/src/memory/coverage.ts +0 -134
- package/src/memory/crosslink.ts +0 -0
- package/src/memory/db.ts +0 -253
- package/src/memory/entity.ts +0 -203
- package/src/memory/gate.ts +0 -187
- package/src/memory/history.ts +0 -152
- package/src/memory/ingest.ts +0 -335
- package/src/memory/model.ts +0 -183
- package/src/memory/normalize.ts +0 -671
- package/src/memory/parse.ts +0 -22
- package/src/memory/pipeline.ts +0 -275
- package/src/memory/prompts.ts +0 -65
- package/src/memory/query.ts +0 -334
- package/src/memory/reconcile.ts +0 -734
- package/src/memory/redirect.ts +0 -108
- package/src/memory/reindex.ts +0 -325
- package/src/memory/resolve.ts +0 -307
- package/src/memory/rest.ts +0 -245
- package/src/memory/route.ts +0 -272
- package/src/memory/schedule.ts +0 -165
- package/src/memory/stages.ts +0 -777
- package/src/memory/synthesize.ts +0 -1638
- package/src/memory/tools.ts +0 -749
- package/src/memory/vault.ts +0 -1194
- package/src/memory/wikify.ts +0 -1064
- package/src/mlx/array.ts +0 -388
- package/src/mlx/autograd.ts +0 -304
- package/src/mlx/checkpoint.ts +0 -149
- package/src/mlx/compile.ts +0 -168
- package/src/mlx/custom-vjp.ts +0 -188
- package/src/mlx/ffi.ts +0 -512
- package/src/mlx/materialize.ts +0 -23
- package/src/mlx/metal-kernel.ts +0 -159
- package/src/mlx/ops.ts +0 -1021
- package/src/mlx/quantized-rows.ts +0 -36
- package/src/mlx/token-bitmask.ts +0 -52
- package/src/mlx/turboquant-kv-decode.ts +0 -82
- package/src/mlx/turboquant-kv-inverse.ts +0 -122
- package/src/mlx/turboquant-ops.ts +0 -861
- package/src/mlx/turboquant-tables.ts +0 -237
- package/src/mmap.ts +0 -90
- package/src/model/artifact-identity.ts +0 -73
- package/src/model/batched-kv.ts +0 -235
- package/src/model/batched-mask.ts +0 -279
- package/src/model/batched-quant.ts +0 -212
- package/src/model/batched-quantized-kv.ts +0 -144
- package/src/model/batched-rotating-quant.ts +0 -353
- package/src/model/batched-rotating-state.ts +0 -149
- package/src/model/batched-rotating.ts +0 -338
- package/src/model/batched-row-storage.ts +0 -179
- package/src/model/batched-ssm.ts +0 -52
- package/src/model/batched-turboquant-kv.ts +0 -93
- package/src/model/compiled-decode.ts +0 -712
- package/src/model/decoded-kv-donor.ts +0 -12
- package/src/model/delayed-quantized-kv.ts +0 -72
- package/src/model/delayed-rotating-quantized-kv.ts +0 -93
- package/src/model/delayed-turboquant-kv.ts +0 -55
- package/src/model/diffusion-gemma.ts +0 -1026
- package/src/model/factory.ts +0 -189
- package/src/model/fingerprint.ts +0 -33
- package/src/model/flash-attention.ts +0 -694
- package/src/model/full-prefill-padding.ts +0 -56
- package/src/model/full-prefill-row.ts +0 -105
- package/src/model/gemma4-base.ts +0 -2351
- package/src/model/gemma4.ts +0 -1315
- package/src/model/generated/gemma4-12b.ts +0 -429
- package/src/model/generated/gemma4-26b.ts +0 -448
- package/src/model/generated/gemma4-e4b.ts +0 -717
- package/src/model/generated/index.ts +0 -18
- package/src/model/glm52-atlas.ts +0 -511
- package/src/model/glm52-cache.ts +0 -792
- package/src/model/glm52-config.ts +0 -262
- package/src/model/glm52-container.ts +0 -305
- package/src/model/glm52-coupling.ts +0 -388
- package/src/model/glm52-dsa.ts +0 -606
- package/src/model/glm52-expert-layout.ts +0 -253
- package/src/model/glm52-layout.ts +0 -152
- package/src/model/glm52-memory.ts +0 -500
- package/src/model/glm52-mla.ts +0 -792
- package/src/model/glm52-moe.ts +0 -223
- package/src/model/glm52-pilot.ts +0 -537
- package/src/model/glm52-reference.ts +0 -445
- package/src/model/glm52-residency.ts +0 -557
- package/src/model/glm52-resident-weights.ts +0 -135
- package/src/model/glm52-streamed-experts.ts +0 -453
- package/src/model/glm52-streamed-metal.ts +0 -610
- package/src/model/glm52-weights.ts +0 -503
- package/src/model/glm52.ts +0 -1132
- package/src/model/implementation.ts +0 -69
- package/src/model/kv-attention-view.ts +0 -67
- package/src/model/minicpm5.ts +0 -376
- package/src/model/profile.ts +0 -443
- package/src/model/qwen-append.ts +0 -12
- package/src/model/qwen-conv.ts +0 -52
- package/src/model/qwen3-delta-state.ts +0 -74
- package/src/model/qwen3-delta.ts +0 -451
- package/src/model/qwen3-moe.ts +0 -404
- package/src/model/qwen3-mrope.ts +0 -252
- package/src/model/qwen3.ts +0 -277
- package/src/model/qwen3_5-checkpoint.ts +0 -164
- package/src/model/qwen3_5.ts +0 -819
- package/src/model/rotating-kv-donor.ts +0 -35
- package/src/model/rotating-kv-layout.ts +0 -262
- package/src/model/rotating-row-transaction.ts +0 -35
- package/src/model/speculative-rotating-kv.ts +0 -101
- package/src/model/ssm-prefill-padding.ts +0 -39
- package/src/model/support.ts +0 -102
- package/src/model/trellis-balanced-scatter.ts +0 -51
- package/src/model/trellis-linear.ts +0 -672
- package/src/model/trellis-shared-m.ts +0 -151
- package/src/model/trellis-shared-scatter.ts +0 -144
- package/src/model/trellis-splitk-prefill.ts +0 -158
- package/src/model/trellis-tiled-prefill.ts +0 -136
- package/src/model/trellis-vector-expand.ts +0 -62
- package/src/model/trellis-wide-prefill.ts +0 -94
- package/src/model/turboquant-codec.ts +0 -83
- package/src/model/universal/archs.ts +0 -332
- package/src/model/universal/dense.ts +0 -612
- package/src/model/universal/modules.ts +0 -170
- package/src/model/universal/rope.ts +0 -381
- package/src/native/expert_io.c +0 -523
- package/src/native/frame_extract.swift +0 -140
- package/src/native-pack.ts +0 -162
- package/src/pi-provider.ts +0 -53
- package/src/pi-session.ts +0 -81
- package/src/pi-terminal.ts +0 -274
- package/src/pi-web.ts +0 -1932
- package/src/preflight.ts +0 -158
- package/src/prompt-cache.ts +0 -460
- package/src/quantize/allocator.ts +0 -627
- package/src/quantize/atomic-output.ts +0 -38
- package/src/quantize/calibration.ts +0 -181
- package/src/quantize/config-writer.ts +0 -145
- package/src/quantize/index.ts +0 -84
- package/src/quantize/job.ts +0 -162
- package/src/quantize/quantizer.ts +0 -666
- package/src/quantize/rotate.ts +0 -603
- package/src/quantize/safetensors-writer.ts +0 -249
- package/src/quantize/sensitivity.ts +0 -216
- package/src/quantize/trellis.ts +0 -586
- package/src/quantize/weight-transform.ts +0 -292
- package/src/registry.ts +0 -602
- package/src/runtime-config.ts +0 -81
- package/src/safetensors.ts +0 -158
- package/src/sampler.ts +0 -1011
- package/src/serve/admin-routes.ts +0 -184
- package/src/serve/assets/curve-terrain.html +0 -105
- package/src/serve/assets/training-inference-map.html +0 -575
- package/src/serve/aux-routes.ts +0 -132
- package/src/serve/batch-scheduler.ts +0 -8
- package/src/serve/checkpoint-identity.ts +0 -64
- package/src/serve/generation-gateway.ts +0 -496
- package/src/serve/isolate.ts +0 -609
- package/src/serve/kv-budget.ts +0 -14
- package/src/serve/lab-routes.ts +0 -341
- package/src/serve/lane-registry.ts +0 -45
- package/src/serve/model-admin-routes.ts +0 -155
- package/src/serve/model-binding.ts +0 -43
- package/src/serve/model-host.ts +0 -511
- package/src/serve/parent-application.ts +0 -56
- package/src/serve/prompt-response-trace.ts +0 -147
- package/src/serve/response-lease.ts +0 -24
- package/src/serve/session-search.ts +0 -326
- package/src/serve/static-routes.ts +0 -101
- package/src/server.ts +0 -1314
- package/src/spec/assistant-rows.ts +0 -92
- package/src/spec/assistant-source.ts +0 -126
- package/src/spec/cache-identity.ts +0 -22
- package/src/spec/deepspec-rows.ts +0 -29
- package/src/spec/deepspec-source.ts +0 -145
- package/src/spec/dflash-source.ts +0 -149
- package/src/spec/drafter.ts +0 -304
- package/src/spec/dspark/ab-stats.ts +0 -136
- package/src/spec/dspark/calibration.ts +0 -112
- package/src/spec/dspark/data-dflash.ts +0 -156
- package/src/spec/dspark/data.ts +0 -201
- package/src/spec/dspark/deepspec-module.ts +0 -776
- package/src/spec/dspark/generate-dflash.ts +0 -245
- package/src/spec/dspark/generate.ts +0 -290
- package/src/spec/dspark/loader.ts +0 -23
- package/src/spec/dspark/loss.ts +0 -213
- package/src/spec/dspark/module-dflash.ts +0 -560
- package/src/spec/dspark/module.ts +0 -540
- package/src/spec/dspark/quantize-drafter.ts +0 -91
- package/src/spec/dspark/sample.ts +0 -112
- package/src/spec/generate.ts +0 -276
- package/src/spec/glm52-mtp-graph.ts +0 -29
- package/src/spec/glm52-mtp-rows.ts +0 -132
- package/src/spec/glm52-mtp-source.ts +0 -317
- package/src/spec/glm52-mtp-state.ts +0 -33
- package/src/spec/ngram-source.ts +0 -204
- package/src/spec/projected-draft-rows.ts +0 -73
- package/src/spec/qwen-mtp-module.ts +0 -171
- package/src/spec/qwen-mtp-rows.ts +0 -219
- package/src/spec/qwen-mtp-source.ts +0 -383
- package/src/spec/qwen-mtp-state.ts +0 -30
- package/src/spec/serve-loop.ts +0 -585
- package/src/spec/source.ts +0 -215
- package/src/spec/two-model-rows.ts +0 -61
- package/src/spec/two-model.ts +0 -113
- package/src/ssd-cache.ts +0 -372
- package/src/ssd-durability.ts +0 -211
- package/src/tokenizer.ts +0 -335
- package/src/tool-approvals.ts +0 -131
- package/src/tool-call.ts +0 -695
- package/src/train/dataset.ts +0 -484
- package/src/train/diffusion-lora.ts +0 -216
- package/src/train/export.ts +0 -32
- package/src/train/flash-cce.ts +0 -1234
- package/src/train/forward.ts +0 -266
- package/src/train/fuse.ts +0 -243
- package/src/train/index.ts +0 -46
- package/src/train/job.ts +0 -205
- package/src/train/lora-params.ts +0 -254
- package/src/train/loss.ts +0 -1591
- package/src/train/merge.ts +0 -195
- package/src/train/optimizer.ts +0 -183
- package/src/train/prefix-shared.ts +0 -490
- package/src/train/rank.ts +0 -137
- package/src/train/segmented.ts +0 -1828
- package/src/train/steel-qmm-header.ts +0 -1461
- package/src/train/trainer.ts +0 -1221
- package/src/train/watch.ts +0 -542
- package/src/vision/diffusion-vision.ts +0 -620
- package/src/vision/embedder.ts +0 -168
- package/src/vision/preprocess.ts +0 -247
- package/src/vision/prompt.ts +0 -373
- package/src/vision/qwen3vl-preprocess.ts +0 -409
- package/src/vision/qwen3vl-prompt.ts +0 -196
- package/src/vision/qwen3vl-tower.ts +0 -555
- package/src/vision/siglip.ts +0 -599
- package/src/vision/video-frames.ts +0 -148
- package/src/web/app.html +0 -2143
- package/src/web/app.js +0 -5703
- package/src/web/skills/memory/SKILL.md +0 -120
- package/src/web/skills/web-research/SKILL.md +0 -46
- package/src/web/skills.ts +0 -97
- package/src/web/src/adapters-panel.ts +0 -288
- package/src/web/src/assistant.ts +0 -451
- package/src/web/src/chat.ts +0 -1057
- package/src/web/src/composer.ts +0 -959
- package/src/web/src/dataset.ts +0 -132
- package/src/web/src/finetune.ts +0 -267
- package/src/web/src/hub.ts +0 -428
- package/src/web/src/main.ts +0 -98
- package/src/web/src/markdown.ts +0 -0
- package/src/web/src/memory-panel.ts +0 -572
- package/src/web/src/model-picker.ts +0 -159
- package/src/web/src/palette.ts +0 -346
- package/src/web/src/protocol.ts +0 -26
- package/src/web/src/quantize.ts +0 -167
- package/src/web/src/rag.ts +0 -274
- package/src/web/src/sessions.ts +0 -469
- package/src/web/src/shell.ts +0 -804
- package/src/web/src/ui-catalog.ts +0 -78
- package/src/web/vendor/README.md +0 -61
- package/src/web-assets.ts +0 -47
- package/src/web-tools.ts +0 -478
- package/src/weights.ts +0 -255
- /package/src/{serve → server}/completion-sink.ts +0 -0
- /package/src/web/{icon.svg → public/icon.svg} +0 -0
- /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
- /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
package/src/memory/tools.ts
DELETED
|
@@ -1,749 +0,0 @@
|
|
|
1
|
-
// mlx-bun memory — the read tools the local assistant uses to consult your wiki.
|
|
2
|
-
//
|
|
3
|
-
// These are pi custom tools (defineTool), registered alongside the coding +
|
|
4
|
-
// web tools in both front doors (pi-terminal.ts, pi-web.ts). They're read-only,
|
|
5
|
-
// so they auto-allow (not in GATED_TOOLS) — consulting your own memory never
|
|
6
|
-
// needs an approval gate. They read ~/.mlx-bun/wiki via src/memory/vault.ts +
|
|
7
|
-
// the deterministic navigation index in src/memory/query.ts.
|
|
8
|
-
//
|
|
9
|
-
// The read surface is a deliberate FIND → READ path, never a vector search and
|
|
10
|
-
// never an infobox-field filter (the infobox is CONTENT the model reads, not a
|
|
11
|
-
// query target — there is NO memory_infobox_query):
|
|
12
|
-
//
|
|
13
|
-
// memory_resolve (name/alias → the article) ─┐ FIND the article
|
|
14
|
-
// memory_category (category/type/series → members) ─┘ deterministically
|
|
15
|
-
// memory_read (TOC + lead by default) ─┐ READ it small:
|
|
16
|
-
// memory_section (one section's body — THE DEFAULT) ─┘ TOC → one section
|
|
17
|
-
// memory_links / memory_infobox (follow the graph / read the infobox)
|
|
18
|
-
// memory_search (LAST resort: substring fallback when FIND failed)
|
|
19
|
-
//
|
|
20
|
-
// Silent-colleague contract (ported from lucien's LUCIEN_INSTRUCTIONS): look the
|
|
21
|
-
// article up BEFORE answering; each article is the consolidated current position,
|
|
22
|
-
// so read it rather than reconstructing from raw history; then speak as a
|
|
23
|
-
// continuation, never "per the wiki…". Knowing *when* to consult is driven by
|
|
24
|
-
// these tool descriptions + the bundled memory skill (pi surfaces its description
|
|
25
|
-
// and loads the body on demand); the system prompt carries only a one-line
|
|
26
|
-
// presence hint (memoryIndexHint), not a title dump.
|
|
27
|
-
|
|
28
|
-
import { defineTool, type ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
29
|
-
import { Type } from "typebox";
|
|
30
|
-
import {
|
|
31
|
-
infoboxFieldValues,
|
|
32
|
-
parseInfobox,
|
|
33
|
-
parseSeriesBanner,
|
|
34
|
-
type Infobox,
|
|
35
|
-
} from "./article";
|
|
36
|
-
import {
|
|
37
|
-
articlesInCategory,
|
|
38
|
-
buildMemoryIndex,
|
|
39
|
-
resolveName,
|
|
40
|
-
type MemoryIndex,
|
|
41
|
-
} from "./query";
|
|
42
|
-
import { scheduleStatus } from "./schedule";
|
|
43
|
-
import {
|
|
44
|
-
extractSection,
|
|
45
|
-
extractWikilinkTargets,
|
|
46
|
-
listArticles,
|
|
47
|
-
listReferenceDocs,
|
|
48
|
-
parseToc,
|
|
49
|
-
readArticle,
|
|
50
|
-
resolveWikilinkToStem,
|
|
51
|
-
searchArticles,
|
|
52
|
-
vaultRoot,
|
|
53
|
-
vaultStatus,
|
|
54
|
-
type SearchHit,
|
|
55
|
-
} from "./vault";
|
|
56
|
-
|
|
57
|
-
/** Tool names, exported so the front doors can add them to the allowlist. The
|
|
58
|
-
* order is the recommended call order: FIND (resolve/category) → READ (read/
|
|
59
|
-
* section) → follow (links/infobox) → reference utilities → search LAST. */
|
|
60
|
-
export const MEMORY_TOOL_NAMES = [
|
|
61
|
-
"memory_resolve",
|
|
62
|
-
"memory_category",
|
|
63
|
-
"memory_read",
|
|
64
|
-
"memory_section",
|
|
65
|
-
"memory_links",
|
|
66
|
-
"memory_infobox",
|
|
67
|
-
"memory_list",
|
|
68
|
-
"memory_status",
|
|
69
|
-
"memory_search",
|
|
70
|
-
] as const;
|
|
71
|
-
|
|
72
|
-
export const REFERENCE_TOOL_NAMES = [
|
|
73
|
-
"reference_search",
|
|
74
|
-
"reference_read",
|
|
75
|
-
"reference_list",
|
|
76
|
-
] as const;
|
|
77
|
-
|
|
78
|
-
const MAX_SEARCH_HITS = 30;
|
|
79
|
-
/** memory_search is the demoted fallback: only the strongest few summaries. */
|
|
80
|
-
const MAX_MEMORY_SUMMARIES = 8;
|
|
81
|
-
/** A whole-article read above this many bytes degrades to TOC+lead+steer. */
|
|
82
|
-
const MAX_FULL_READ_BYTES = 8 * 1024;
|
|
83
|
-
/** memory_category page size (rows) and per-row lead budget. */
|
|
84
|
-
const MAX_CATEGORY_ROWS = 40;
|
|
85
|
-
const CATEGORY_LEAD_CHARS = 140;
|
|
86
|
-
/** memory_links: cap per origin group before "+N more". */
|
|
87
|
-
const MAX_LINKS_PER_GROUP = 25;
|
|
88
|
-
|
|
89
|
-
function textResult(text: string): { content: [{ type: "text"; text: string }]; details: Record<string, never> } {
|
|
90
|
-
return { content: [{ type: "text", text }], details: {} };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export async function isMemoryEnabled(): Promise<boolean> {
|
|
94
|
-
try {
|
|
95
|
-
return (await vaultStatus()).exists;
|
|
96
|
-
} catch {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function isReferenceId(article: string): boolean {
|
|
102
|
-
return article.trim().startsWith("Reference/");
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async function memoryUnavailableMessage(): Promise<string | null> {
|
|
106
|
-
const st = await vaultStatus();
|
|
107
|
-
if (st.exists) return null;
|
|
108
|
-
return `Memory is not set up yet at ${st.root}. Run \`mlx-bun memory init\` to create the local Markdown wiki, or ask the user before setting it up.`;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** Title form of a stem (underscores → spaces). */
|
|
112
|
-
function titleOf(stem: string): string {
|
|
113
|
-
return stem.replace(/_/g, " ");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** Casefold + collapse whitespace/underscores (mirrors query.ts/reindex.ts). */
|
|
117
|
-
function normalizeAlias(s: string): string {
|
|
118
|
-
return s.trim().toLowerCase().replace(/_/g, " ").replace(/\s+/g, " ").trim();
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/** Truncate to a budget, marking the cut so callers never silently lose text. */
|
|
122
|
-
function clip(text: string, max: number): string {
|
|
123
|
-
const t = text.trim();
|
|
124
|
-
return t.length <= max ? t : `${t.slice(0, max - 1).trimEnd()}…`;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/** Compact, model-friendly rendering of search hits grouped by relevance. */
|
|
128
|
-
function formatSearch(
|
|
129
|
-
query: string,
|
|
130
|
-
summaries: { article: string; occurrences: number; matched_terms?: string[] }[],
|
|
131
|
-
hits: SearchHit[],
|
|
132
|
-
opts: { corpusLabel?: string; readTool?: string; maxSummaries?: number } = {},
|
|
133
|
-
): string {
|
|
134
|
-
const corpus = opts.corpusLabel ?? "personal-memory articles";
|
|
135
|
-
const readTool = opts.readTool ?? "memory_read";
|
|
136
|
-
const maxSummaries = opts.maxSummaries ?? 12;
|
|
137
|
-
if (summaries.length === 0) return `No ${corpus} match "${query}".`;
|
|
138
|
-
const top = summaries.slice(0, maxSummaries);
|
|
139
|
-
const lines = [`${corpus[0]!.toUpperCase()}${corpus.slice(1)} matching "${query}" (most relevant first):`, ""];
|
|
140
|
-
for (const s of top) {
|
|
141
|
-
const terms = s.matched_terms && s.matched_terms.length ? ` [${s.matched_terms.join(", ")}]` : "";
|
|
142
|
-
lines.push(`- ${s.article} (${s.occurrences} hit${s.occurrences === 1 ? "" : "s"})${terms}`);
|
|
143
|
-
}
|
|
144
|
-
if (summaries.length > top.length) lines.push(` …and ${summaries.length - top.length} more.`);
|
|
145
|
-
if (hits.length) {
|
|
146
|
-
lines.push("", "Sample lines:");
|
|
147
|
-
for (const h of hits.slice(0, 8)) {
|
|
148
|
-
const where = h.anchor ? `${h.article}#${h.anchor}` : h.article;
|
|
149
|
-
lines.push(`- ${where}:${h.line} ${h.excerpt}`);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
lines.push("", `Read a result with ${readTool} (e.g. ${readTool} stem="${top[0]!.article}").`);
|
|
153
|
-
return lines.join("\n");
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// ---- index access -----------------------------------------------------
|
|
157
|
-
|
|
158
|
-
/** Build the (mtime-cached) navigation index over the live vault. */
|
|
159
|
-
function index(): MemoryIndex {
|
|
160
|
-
return buildMemoryIndex(vaultRoot());
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function kindOf(idx: MemoryIndex, stem: string): string {
|
|
164
|
-
return idx.infoboxByStem.get(stem)?.entityKind ?? "thing";
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function leadOf(idx: MemoryIndex, stem: string): string | null {
|
|
168
|
-
return idx.leadByStem.get(stem) ?? null;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// ---- FIND: resolve by name/alias --------------------------------------
|
|
172
|
-
|
|
173
|
-
const memoryResolveTool = defineTool({
|
|
174
|
-
name: "memory_resolve",
|
|
175
|
-
label: "Resolve Memory Article",
|
|
176
|
-
description:
|
|
177
|
-
"FIND the user's article for a name or alias — the first move when the user names a specific thing, person, project, or topic. " +
|
|
178
|
-
"Deterministic alias lookup (no model, no substring search): returns the matched article's stem, title, kind, and lead so you can then read it. " +
|
|
179
|
-
"On a miss it offers up to 3 near candidates. Look the article up before answering rather than guessing from raw history.",
|
|
180
|
-
parameters: Type.Object({
|
|
181
|
-
surface: Type.String({ description: "The name or alias as the user said it (a short form or the way they referred to the thing)." }),
|
|
182
|
-
}),
|
|
183
|
-
execute: async (_id, params) => {
|
|
184
|
-
const surface = params.surface.trim();
|
|
185
|
-
if (!surface) return textResult("memory_resolve needs a name or alias.");
|
|
186
|
-
try {
|
|
187
|
-
const unavailable = await memoryUnavailableMessage();
|
|
188
|
-
if (unavailable) return textResult(unavailable);
|
|
189
|
-
const idx = index();
|
|
190
|
-
const stem = resolveName(idx, surface);
|
|
191
|
-
if (stem) {
|
|
192
|
-
const lead = leadOf(idx, stem);
|
|
193
|
-
return textResult(
|
|
194
|
-
[
|
|
195
|
-
`${titleOf(stem)} (stem: ${stem}, kind: ${kindOf(idx, stem)})`,
|
|
196
|
-
lead ? `\n${clip(lead, 360)}` : "",
|
|
197
|
-
`\n\nRead it with memory_read stem="${stem}" (TOC + lead), then memory_section for the part you need.`,
|
|
198
|
-
].join(""),
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
// Miss: deterministic token-overlap candidates (no substring, no model).
|
|
202
|
-
const qTokens = new Set(normalizeAlias(surface).split(" ").filter(Boolean));
|
|
203
|
-
const scored = new Map<string, number>();
|
|
204
|
-
for (const [alias, st] of idx.aliasToStem) {
|
|
205
|
-
let shared = 0;
|
|
206
|
-
for (const tok of alias.split(" ")) if (qTokens.has(tok)) shared++;
|
|
207
|
-
if (shared > 0) scored.set(st, Math.max(scored.get(st) ?? 0, shared));
|
|
208
|
-
}
|
|
209
|
-
const candidates = [...scored.entries()]
|
|
210
|
-
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
|
211
|
-
.slice(0, 3)
|
|
212
|
-
.map(([st]) => st);
|
|
213
|
-
if (candidates.length === 0) {
|
|
214
|
-
return textResult(`No article resolves "${surface}". Try memory_category to find articles about a topic, or memory_search as a last resort.`);
|
|
215
|
-
}
|
|
216
|
-
return textResult(
|
|
217
|
-
`No exact match for "${surface}". Did you mean one of:\n` +
|
|
218
|
-
candidates.map((st) => `- ${titleOf(st)} (stem: ${st})`).join("\n") +
|
|
219
|
-
`\n\nResolve one with memory_read, or use memory_category for a topic.`,
|
|
220
|
-
);
|
|
221
|
-
} catch (err) {
|
|
222
|
-
return textResult(`memory_resolve failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
// ---- FIND: articles about a category / type / series ------------------
|
|
228
|
-
|
|
229
|
-
const memoryCategoryTool = defineTool({
|
|
230
|
-
name: "memory_category",
|
|
231
|
-
label: "Articles in Category",
|
|
232
|
-
description:
|
|
233
|
-
"FIND the articles ABOUT a topic by membership — the \"articles about X\" finder. " +
|
|
234
|
-
"Pass exactly one of category, type, or series; returns the member articles as \"stem · lead\" rows. " +
|
|
235
|
-
"This is deterministic set membership (declared [[Category:…]] / infobox type / series banner), NOT a search and NOT an infobox-field filter. " +
|
|
236
|
-
"Use it to land on the right article, then memory_read its TOC and memory_section the one part you need.",
|
|
237
|
-
parameters: Type.Object({
|
|
238
|
-
category: Type.Optional(Type.String({ description: "Category name — the grouping declared as [[Category:<Name>]] near the top of member articles." })),
|
|
239
|
-
type: Type.Optional(Type.String({ description: "Infobox type label (the article's `type:` field value)." })),
|
|
240
|
-
series: Type.Optional(Type.String({ description: "Series name from a *Part of a series on [[X]]* banner." })),
|
|
241
|
-
}),
|
|
242
|
-
execute: async (_id, params) => {
|
|
243
|
-
const category = params.category?.trim();
|
|
244
|
-
const type = params.type?.trim();
|
|
245
|
-
const series = params.series?.trim();
|
|
246
|
-
const picked = [category, type, series].filter((v) => v && v.length > 0);
|
|
247
|
-
if (picked.length !== 1) {
|
|
248
|
-
return textResult("memory_category needs exactly one of: category, type, or series.");
|
|
249
|
-
}
|
|
250
|
-
try {
|
|
251
|
-
const unavailable = await memoryUnavailableMessage();
|
|
252
|
-
if (unavailable) return textResult(unavailable);
|
|
253
|
-
const idx = index();
|
|
254
|
-
let stems: string[];
|
|
255
|
-
let label: string;
|
|
256
|
-
if (category) {
|
|
257
|
-
stems = articlesInCategory(idx, category);
|
|
258
|
-
label = `Category:${category}`;
|
|
259
|
-
} else if (type) {
|
|
260
|
-
stems = [...(idx.typeToStems.get(type) ?? [])];
|
|
261
|
-
label = `type:${type}`;
|
|
262
|
-
} else {
|
|
263
|
-
stems = [...(idx.seriesToStems.get(series!) ?? [])];
|
|
264
|
-
label = `series:${series}`;
|
|
265
|
-
}
|
|
266
|
-
if (stems.length === 0) return textResult(`No articles in ${label}.`);
|
|
267
|
-
const page = stems.slice(0, MAX_CATEGORY_ROWS);
|
|
268
|
-
const lines = [`Articles in ${label} (${stems.length}):`, ""];
|
|
269
|
-
for (const stem of page) {
|
|
270
|
-
const lead = leadOf(idx, stem);
|
|
271
|
-
lines.push(lead ? `- ${stem} · ${clip(lead, CATEGORY_LEAD_CHARS)}` : `- ${stem}`);
|
|
272
|
-
}
|
|
273
|
-
if (stems.length > page.length) lines.push(` …and ${stems.length - page.length} more.`);
|
|
274
|
-
lines.push("", "Open one with memory_read, then memory_section for the relevant part.");
|
|
275
|
-
return textResult(lines.join("\n"));
|
|
276
|
-
} catch (err) {
|
|
277
|
-
return textResult(`memory_category failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
278
|
-
}
|
|
279
|
-
},
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
// ---- READ: TOC + lead by default; full only on force -------------------
|
|
283
|
-
|
|
284
|
-
function tocAndLead(content: string, stem: string, idx: MemoryIndex, note?: string): string {
|
|
285
|
-
const lead = leadOf(idx, stem);
|
|
286
|
-
const toc = parseToc(content);
|
|
287
|
-
const lines = [`${titleOf(stem)} (stem: ${stem})`];
|
|
288
|
-
if (lead) lines.push("", clip(lead, 480));
|
|
289
|
-
if (note) lines.push("", note);
|
|
290
|
-
lines.push("", "Sections:");
|
|
291
|
-
if (toc.length === 0) lines.push("- (no headings)");
|
|
292
|
-
else for (const h of toc) lines.push(`${" ".repeat(Math.max(0, h.depth - 1))}- ${h.title} (#${h.anchor})`);
|
|
293
|
-
lines.push("", `Read the one relevant section with memory_section stem="${stem}" anchor="…". Whole article: memory_read stem="${stem}" force=true.`);
|
|
294
|
-
return lines.join("\n");
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const memoryReadTool = defineTool({
|
|
298
|
-
name: "memory_read",
|
|
299
|
-
label: "Read Memory Article",
|
|
300
|
-
description:
|
|
301
|
-
"Open one article. BY DEFAULT returns its TOC + lead so you can pick the one section you need — small focused reads are the norm, never a whole-article dump. " +
|
|
302
|
-
"Pass force=true for the full prose+infobox, but only when you genuinely need the whole article (large articles still degrade to TOC+lead). " +
|
|
303
|
-
"The article is the user's consolidated current position on its topic; read it before answering rather than reconstructing from history. " +
|
|
304
|
-
"Pass the article stem (underscored, e.g. an \"<Article_Stem>\" filename without .md).",
|
|
305
|
-
parameters: Type.Object({
|
|
306
|
-
stem: Type.String({ description: "Article stem (underscored filename, no .md — e.g. \"<Article_Stem>\")." }),
|
|
307
|
-
force: Type.Optional(Type.Boolean({ description: "Return the FULL article instead of TOC+lead. Use sparingly." })),
|
|
308
|
-
}),
|
|
309
|
-
execute: async (_id, params) => {
|
|
310
|
-
const stem = params.stem.trim();
|
|
311
|
-
if (!stem) return textResult("memory_read needs an article stem.");
|
|
312
|
-
try {
|
|
313
|
-
const unavailable = await memoryUnavailableMessage();
|
|
314
|
-
if (unavailable) return textResult(unavailable);
|
|
315
|
-
if (isReferenceId(stem)) return textResult("memory_read is for personal-memory articles. Use reference_read for Reference/ documents.");
|
|
316
|
-
const { content } = await readArticle(vaultRoot(), stem);
|
|
317
|
-
const idx = index();
|
|
318
|
-
if (!params.force) return textResult(tocAndLead(content, stem, idx));
|
|
319
|
-
const bytes = Buffer.byteLength(content, "utf8");
|
|
320
|
-
if (bytes > MAX_FULL_READ_BYTES) {
|
|
321
|
-
return textResult(
|
|
322
|
-
tocAndLead(content, stem, idx, `(This article is large — ${(bytes / 1024).toFixed(1)} KB. Read just the section you need.)`),
|
|
323
|
-
);
|
|
324
|
-
}
|
|
325
|
-
return textResult(content);
|
|
326
|
-
} catch (err) {
|
|
327
|
-
return textResult(`${err instanceof Error ? err.message : String(err)} — try memory_resolve or memory_category to find the right article.`);
|
|
328
|
-
}
|
|
329
|
-
},
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
const memorySectionTool = defineTool({
|
|
333
|
-
name: "memory_section",
|
|
334
|
-
label: "Read Memory Section",
|
|
335
|
-
description:
|
|
336
|
-
"Read ONE section of an article by its heading anchor. This is the DEFAULT read: find the article, scan its TOC with memory_read, then read just the relevant section here — much cheaper than the whole article. " +
|
|
337
|
-
"Get anchors from memory_read's TOC.",
|
|
338
|
-
parameters: Type.Object({
|
|
339
|
-
stem: Type.String({ description: "Article stem (underscored, e.g. \"<Article_Stem>\")." }),
|
|
340
|
-
anchor: Type.String({ description: "Heading anchor (the slug of a section heading from memory_read's TOC, e.g. \"<section-anchor>\")." }),
|
|
341
|
-
}),
|
|
342
|
-
execute: async (_id, params) => {
|
|
343
|
-
const stem = params.stem.trim();
|
|
344
|
-
const anchor = params.anchor.trim().replace(/^#/, "");
|
|
345
|
-
if (!stem) return textResult("memory_section needs an article stem.");
|
|
346
|
-
if (!anchor) return textResult("memory_section needs a heading anchor.");
|
|
347
|
-
try {
|
|
348
|
-
const unavailable = await memoryUnavailableMessage();
|
|
349
|
-
if (unavailable) return textResult(unavailable);
|
|
350
|
-
if (isReferenceId(stem)) return textResult("memory_section is for personal-memory articles. Use reference_read for Reference/ documents.");
|
|
351
|
-
const { content } = await readArticle(vaultRoot(), stem);
|
|
352
|
-
const section = extractSection(content, anchor);
|
|
353
|
-
if (!section) return textResult(`No section #${anchor} in ${stem}. Use memory_read stem="${stem}" to see the TOC.`);
|
|
354
|
-
return textResult(section);
|
|
355
|
-
} catch (err) {
|
|
356
|
-
return textResult(`${err instanceof Error ? err.message : String(err)} — try memory_resolve or memory_category to find the right article.`);
|
|
357
|
-
}
|
|
358
|
-
},
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
// ---- FOLLOW: links grouped by origin ----------------------------------
|
|
362
|
-
|
|
363
|
-
const WIKILINK_RE = /\[\[([^\]]+)\]\]/g;
|
|
364
|
-
|
|
365
|
-
/** Resolved outbound links grouped by where they appear in the article. Mirrors
|
|
366
|
-
* the reindex `via` taxonomy (infobox/series/seealso/prose); red links (no
|
|
367
|
-
* existing article) are dropped, matching getArticleLinks. */
|
|
368
|
-
function groupedOutbound(content: string, stem: string, stemSet: Set<string>, box: Infobox | null): {
|
|
369
|
-
infobox: string[];
|
|
370
|
-
series: string[];
|
|
371
|
-
seealso: string[];
|
|
372
|
-
prose: string[];
|
|
373
|
-
} {
|
|
374
|
-
const dedupe = (arr: string[]): string[] => [...new Set(arr)].sort((a, b) => a.localeCompare(b));
|
|
375
|
-
const resolve = (raw: string): string | null => {
|
|
376
|
-
const base = raw.split("|")[0]!.split("#")[0]!.trim();
|
|
377
|
-
const r = resolveWikilinkToStem(base, stemSet);
|
|
378
|
-
return r && r !== stem ? r : null;
|
|
379
|
-
};
|
|
380
|
-
|
|
381
|
-
const infobox: string[] = [];
|
|
382
|
-
if (box) {
|
|
383
|
-
for (const field of box.fields) {
|
|
384
|
-
for (const value of infoboxFieldValues(field)) {
|
|
385
|
-
WIKILINK_RE.lastIndex = 0;
|
|
386
|
-
const m = WIKILINK_RE.exec(value);
|
|
387
|
-
if (m) {
|
|
388
|
-
const r = resolve(m[1]!);
|
|
389
|
-
if (r) infobox.push(r);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const series: string[] = [];
|
|
396
|
-
const banner = parseSeriesBanner(content);
|
|
397
|
-
if (banner) {
|
|
398
|
-
const r = resolve(banner);
|
|
399
|
-
if (r) series.push(r);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
const seealso: string[] = [];
|
|
403
|
-
const prose: string[] = [];
|
|
404
|
-
const lines = content.split(/\r?\n/);
|
|
405
|
-
let inFence = false;
|
|
406
|
-
let section: string | null = null;
|
|
407
|
-
for (const line of lines) {
|
|
408
|
-
if (/^```/.test(line)) {
|
|
409
|
-
inFence = !inFence;
|
|
410
|
-
continue;
|
|
411
|
-
}
|
|
412
|
-
if (inFence) continue;
|
|
413
|
-
const hm = /^(#{1,6})\s+(.+)$/.exec(line);
|
|
414
|
-
if (hm) {
|
|
415
|
-
if (hm[1]!.length >= 2) section = hm[2]!.trim().toLowerCase();
|
|
416
|
-
continue;
|
|
417
|
-
}
|
|
418
|
-
const t = line.trim();
|
|
419
|
-
if (/^\*part of a series on \[\[/i.test(t)) continue;
|
|
420
|
-
if (/^categories:/i.test(t)) continue;
|
|
421
|
-
if (/^\*?\s*main article:/i.test(t)) continue;
|
|
422
|
-
WIKILINK_RE.lastIndex = 0;
|
|
423
|
-
let m: RegExpExecArray | null;
|
|
424
|
-
while ((m = WIKILINK_RE.exec(line)) !== null) {
|
|
425
|
-
const base = m[1]!.split("|")[0]!.split("#")[0]!.trim();
|
|
426
|
-
if (!base || /^conv:/i.test(base) || /^Category:/i.test(base)) continue;
|
|
427
|
-
const r = resolve(base);
|
|
428
|
-
if (!r) continue;
|
|
429
|
-
if (section === "see also") seealso.push(r);
|
|
430
|
-
else prose.push(r);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
return { infobox: dedupe(infobox), series: dedupe(series), seealso: dedupe(seealso), prose: dedupe(prose) };
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
const memoryLinksTool = defineTool({
|
|
438
|
-
name: "memory_links",
|
|
439
|
-
label: "Memory Links",
|
|
440
|
-
description:
|
|
441
|
-
"Follow the wiki graph: the article's outgoing [[links]] grouped by where they come from (infobox / series / see also / prose), plus inbound backlinks. " +
|
|
442
|
-
"Use to hop to a neighbouring article (e.g. from one entity's infobox [[wikilink]] to the linked entity's article) when a topic genuinely spans articles.",
|
|
443
|
-
parameters: Type.Object({
|
|
444
|
-
stem: Type.String({ description: "Article stem (underscored, e.g. \"<Article_Stem>\")." }),
|
|
445
|
-
}),
|
|
446
|
-
execute: async (_id, params) => {
|
|
447
|
-
const stem = params.stem.trim();
|
|
448
|
-
if (!stem) return textResult("memory_links needs an article stem.");
|
|
449
|
-
try {
|
|
450
|
-
const unavailable = await memoryUnavailableMessage();
|
|
451
|
-
if (unavailable) return textResult(unavailable);
|
|
452
|
-
if (isReferenceId(stem)) return textResult("memory_links is for personal-memory articles; Reference/ documents are not in the link graph.");
|
|
453
|
-
const { content } = await readArticle(vaultRoot(), stem);
|
|
454
|
-
const stems = await listArticles(vaultRoot());
|
|
455
|
-
const stemSet = new Set(stems);
|
|
456
|
-
if (!stemSet.has(stem)) return textResult(`Article not found: ${stem}.`);
|
|
457
|
-
const box = parseInfobox(content);
|
|
458
|
-
const groups = groupedOutbound(content, stem, stemSet, box);
|
|
459
|
-
|
|
460
|
-
// Inbound: who points here (any origin).
|
|
461
|
-
const inbound: string[] = [];
|
|
462
|
-
for (const other of stems) {
|
|
463
|
-
if (other === stem) continue;
|
|
464
|
-
try {
|
|
465
|
-
const oc = (await readArticle(vaultRoot(), other)).content;
|
|
466
|
-
const og = groupedOutbound(oc, other, stemSet, parseInfobox(oc));
|
|
467
|
-
if ([...og.infobox, ...og.series, ...og.seealso, ...og.prose].includes(stem)) inbound.push(other);
|
|
468
|
-
} catch {
|
|
469
|
-
// best-effort
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const renderGroup = (title: string, arr: string[]): string => {
|
|
474
|
-
if (arr.length === 0) return `${title}: (none)`;
|
|
475
|
-
const shown = arr.slice(0, MAX_LINKS_PER_GROUP);
|
|
476
|
-
const extra = arr.length > shown.length ? ` +${arr.length - shown.length} more` : "";
|
|
477
|
-
return `${title}: ${shown.join(", ")}${extra}`;
|
|
478
|
-
};
|
|
479
|
-
return textResult(
|
|
480
|
-
[
|
|
481
|
-
`Links for ${stem}:`,
|
|
482
|
-
"",
|
|
483
|
-
renderGroup("infobox", groups.infobox),
|
|
484
|
-
renderGroup("series", groups.series),
|
|
485
|
-
renderGroup("see also", groups.seealso),
|
|
486
|
-
renderGroup("prose", groups.prose),
|
|
487
|
-
renderGroup("inbound", inbound.sort((a, b) => a.localeCompare(b))),
|
|
488
|
-
].join("\n"),
|
|
489
|
-
);
|
|
490
|
-
} catch (err) {
|
|
491
|
-
return textResult(`${err instanceof Error ? err.message : String(err)} — try memory_resolve or memory_category to find the right article.`);
|
|
492
|
-
}
|
|
493
|
-
},
|
|
494
|
-
});
|
|
495
|
-
|
|
496
|
-
// ---- READ the infobox as content (NOT a query target) -----------------
|
|
497
|
-
|
|
498
|
-
const memoryInfoboxTool = defineTool({
|
|
499
|
-
name: "memory_infobox",
|
|
500
|
-
label: "Read Memory Infobox",
|
|
501
|
-
description:
|
|
502
|
-
"Read an article's infobox as key:value CONTENT — the structured facts (the `type:`, `kind:`, relationship, and world-fact fields). " +
|
|
503
|
-
"This surfaces facts to READ, not a filter: there is no way to query/sort articles by an infobox field; to find articles use memory_category or memory_resolve.",
|
|
504
|
-
parameters: Type.Object({
|
|
505
|
-
stem: Type.String({ description: "Article stem (underscored, e.g. \"<Article_Stem>\")." }),
|
|
506
|
-
}),
|
|
507
|
-
execute: async (_id, params) => {
|
|
508
|
-
const stem = params.stem.trim();
|
|
509
|
-
if (!stem) return textResult("memory_infobox needs an article stem.");
|
|
510
|
-
try {
|
|
511
|
-
const unavailable = await memoryUnavailableMessage();
|
|
512
|
-
if (unavailable) return textResult(unavailable);
|
|
513
|
-
if (isReferenceId(stem)) return textResult("memory_infobox is for personal-memory articles.");
|
|
514
|
-
const idx = index();
|
|
515
|
-
if (!idx.infoboxByStem.has(stem)) return textResult(`Article not found: ${stem}.`);
|
|
516
|
-
const box = idx.infoboxByStem.get(stem) ?? null;
|
|
517
|
-
if (!box || box.fields.length === 0) return textResult(`${stem} has no infobox.`);
|
|
518
|
-
return textResult(
|
|
519
|
-
`Infobox for ${stem} (facts to read, not a filter):\n\n` +
|
|
520
|
-
box.fields.map((f) => `${f.key}: ${f.value}`).join("\n"),
|
|
521
|
-
);
|
|
522
|
-
} catch (err) {
|
|
523
|
-
return textResult(`memory_infobox failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
524
|
-
}
|
|
525
|
-
},
|
|
526
|
-
});
|
|
527
|
-
|
|
528
|
-
// ---- overview + status ------------------------------------------------
|
|
529
|
-
|
|
530
|
-
const memoryListTool = defineTool({
|
|
531
|
-
name: "memory_list",
|
|
532
|
-
label: "List Memory",
|
|
533
|
-
description:
|
|
534
|
-
"List the stems of the user's personal-memory articles. An overview/fallback when memory_resolve and memory_category don't surface what you expected — not a first move.",
|
|
535
|
-
parameters: Type.Object({}),
|
|
536
|
-
execute: async () => {
|
|
537
|
-
try {
|
|
538
|
-
const unavailable = await memoryUnavailableMessage();
|
|
539
|
-
if (unavailable) return textResult(unavailable);
|
|
540
|
-
const articles = await listArticles(vaultRoot());
|
|
541
|
-
if (articles.length === 0) return textResult("The user's memory has no personal articles yet.");
|
|
542
|
-
return textResult(
|
|
543
|
-
`${articles.length} personal-memory article(s):\n\n` + articles.map((s) => `- ${s}`).join("\n"),
|
|
544
|
-
);
|
|
545
|
-
} catch (err) {
|
|
546
|
-
return textResult(`memory_list failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
547
|
-
}
|
|
548
|
-
},
|
|
549
|
-
});
|
|
550
|
-
|
|
551
|
-
/** Last synthesis-pipeline write to the vault, from its git log (every
|
|
552
|
-
* pipeline write commits with a "memory: …" message — synthesize.ts,
|
|
553
|
-
* reconcile.ts, wikify.ts, stages.ts). null when the vault has no git repo
|
|
554
|
-
* or no synthesis commit yet. */
|
|
555
|
-
async function lastSynthesisCommit(root: string): Promise<{ date: string; subject: string } | null> {
|
|
556
|
-
try {
|
|
557
|
-
const proc = Bun.spawn(
|
|
558
|
-
["git", "log", "-1", "--grep=^memory: ", "--format=%cI\t%s"],
|
|
559
|
-
{ cwd: root, stdout: "pipe", stderr: "ignore" },
|
|
560
|
-
);
|
|
561
|
-
const out = (await new Response(proc.stdout).text()).trim();
|
|
562
|
-
if ((await proc.exited) !== 0 || !out) return null;
|
|
563
|
-
const tab = out.indexOf("\t");
|
|
564
|
-
if (tab === -1) return null;
|
|
565
|
-
return { date: out.slice(0, tab), subject: out.slice(tab + 1) };
|
|
566
|
-
} catch {
|
|
567
|
-
return null;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
const memoryStatusTool = defineTool({
|
|
572
|
-
name: "memory_status",
|
|
573
|
-
label: "Memory Status",
|
|
574
|
-
description:
|
|
575
|
-
"Show read-only status for the user's memory: vault path, setup state, article count, git state, last synthesis run, and nightly schedule state. Use when the user asks whether memory is on or where it lives.",
|
|
576
|
-
parameters: Type.Object({}),
|
|
577
|
-
execute: async () => {
|
|
578
|
-
try {
|
|
579
|
-
const st = await vaultStatus();
|
|
580
|
-
const sched = await scheduleStatus();
|
|
581
|
-
const last = st.isGitRepo ? await lastSynthesisCommit(st.root) : null;
|
|
582
|
-
const recent = st.recentArticles.length
|
|
583
|
-
? st.recentArticles.slice(0, 5).map((r) => ` - ${r.article} (${new Date(r.mtimeMs).toISOString()})`).join("\n")
|
|
584
|
-
: " - (none)";
|
|
585
|
-
return textResult([
|
|
586
|
-
"Memory status:",
|
|
587
|
-
`- vault: ${st.root}`,
|
|
588
|
-
`- setup: ${st.exists ? "yes" : "no"}`,
|
|
589
|
-
`- articles: ${st.articleCount}`,
|
|
590
|
-
`- read-only references: ${st.referenceCount}`,
|
|
591
|
-
`- git: ${st.isGitRepo ? "tracked" : "not tracked"}`,
|
|
592
|
-
`- last synthesis: ${last ? `${last.date} (${last.subject})` : "no synthesis run recorded yet"}`,
|
|
593
|
-
"- synthesis: available — `mlx-bun memory synthesize` runs the full local pipeline (conversations → articles); the nightly job runs it automatically when scheduled",
|
|
594
|
-
`- nightly: ${sched.installed ? (sched.loaded ? "scheduled" : "installed but not loaded") : "not scheduled"}`,
|
|
595
|
-
sched.installed ? `- launchd plist: ${sched.plistPath}` : "- setup command: mlx-bun memory init",
|
|
596
|
-
"- recent changed articles:",
|
|
597
|
-
recent,
|
|
598
|
-
].join("\n"));
|
|
599
|
-
} catch (err) {
|
|
600
|
-
return textResult(`memory_status failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
601
|
-
}
|
|
602
|
-
},
|
|
603
|
-
});
|
|
604
|
-
|
|
605
|
-
// ---- search: the demoted last-resort fallback -------------------------
|
|
606
|
-
|
|
607
|
-
const memorySearchTool = defineTool({
|
|
608
|
-
name: "memory_search",
|
|
609
|
-
label: "Search Memory (fallback)",
|
|
610
|
-
description:
|
|
611
|
-
"LAST-RESORT substring search across memory articles — use ONLY when name/category lookup (memory_resolve, memory_category) has failed across a couple of phrasings. " +
|
|
612
|
-
"It does not understand meaning; prefer the deterministic finders first. Returns the top few article matches; follow up with memory_read.",
|
|
613
|
-
parameters: Type.Object({
|
|
614
|
-
query: Type.String({ description: "Word or phrase to substring-match across memory articles." }),
|
|
615
|
-
limit: Type.Optional(Type.Number({ description: `Max sample line-hits to return (default ${MAX_SEARCH_HITS}).` })),
|
|
616
|
-
}),
|
|
617
|
-
execute: async (_id, params) => {
|
|
618
|
-
const query = params.query.trim();
|
|
619
|
-
if (!query) return textResult("memory_search needs a non-empty query.");
|
|
620
|
-
const limit = Math.max(1, Math.min(MAX_SEARCH_HITS, Math.round(params.limit ?? MAX_SEARCH_HITS)));
|
|
621
|
-
try {
|
|
622
|
-
const unavailable = await memoryUnavailableMessage();
|
|
623
|
-
if (unavailable) return textResult(unavailable);
|
|
624
|
-
const { summaries, hits } = await searchArticles(vaultRoot(), query, { limit, scope: "articles" });
|
|
625
|
-
return textResult(formatSearch(query, summaries, hits, { maxSummaries: MAX_MEMORY_SUMMARIES }));
|
|
626
|
-
} catch (err) {
|
|
627
|
-
return textResult(`memory_search failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
628
|
-
}
|
|
629
|
-
},
|
|
630
|
-
});
|
|
631
|
-
|
|
632
|
-
// ---- reference docs (separate from personal memory) -------------------
|
|
633
|
-
|
|
634
|
-
const referenceSearchTool = defineTool({
|
|
635
|
-
name: "reference_search",
|
|
636
|
-
label: "Search mlx-bun Reference",
|
|
637
|
-
description:
|
|
638
|
-
"Search read-only mlx-bun reference documents that are symlinked into the memory vault. " +
|
|
639
|
-
"Use for mlx-bun documentation questions when repository files are not enough. This is project reference, not personal memory.",
|
|
640
|
-
parameters: Type.Object({
|
|
641
|
-
query: Type.String({ description: "Word or phrase to search for across mlx-bun reference documents." }),
|
|
642
|
-
limit: Type.Optional(Type.Number({ description: `Max sample line-hits to return (default ${MAX_SEARCH_HITS}).` })),
|
|
643
|
-
}),
|
|
644
|
-
execute: async (_id, params) => {
|
|
645
|
-
const query = params.query.trim();
|
|
646
|
-
if (!query) return textResult("reference_search needs a non-empty query.");
|
|
647
|
-
const limit = Math.max(1, Math.min(MAX_SEARCH_HITS, Math.round(params.limit ?? MAX_SEARCH_HITS)));
|
|
648
|
-
try {
|
|
649
|
-
const unavailable = await memoryUnavailableMessage();
|
|
650
|
-
if (unavailable) return textResult(unavailable);
|
|
651
|
-
const { summaries, hits } = await searchArticles(vaultRoot(), query, { limit, scope: "reference" });
|
|
652
|
-
return textResult(formatSearch(query, summaries, hits, { corpusLabel: "read-only reference documents", readTool: "reference_read" }));
|
|
653
|
-
} catch (err) {
|
|
654
|
-
return textResult(`reference_search failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
655
|
-
}
|
|
656
|
-
},
|
|
657
|
-
});
|
|
658
|
-
|
|
659
|
-
const referenceReadTool = defineTool({
|
|
660
|
-
name: "reference_read",
|
|
661
|
-
label: "Read mlx-bun Reference",
|
|
662
|
-
description:
|
|
663
|
-
"Read one read-only mlx-bun reference document from the vault's Reference/ namespace. " +
|
|
664
|
-
"Pass the id exactly as returned by reference_search or reference_list, e.g. \"Reference/mlx-bun_Server_API\".",
|
|
665
|
-
parameters: Type.Object({
|
|
666
|
-
article: Type.String({ description: "Reference doc id, e.g. \"Reference/mlx-bun_Server_API\"." }),
|
|
667
|
-
}),
|
|
668
|
-
execute: async (_id, params) => {
|
|
669
|
-
const article = params.article.trim();
|
|
670
|
-
if (!article) return textResult("reference_read needs a Reference/... document id.");
|
|
671
|
-
try {
|
|
672
|
-
const unavailable = await memoryUnavailableMessage();
|
|
673
|
-
if (unavailable) return textResult(unavailable);
|
|
674
|
-
const id = article.startsWith("Reference/") ? article : `Reference/${article}`;
|
|
675
|
-
const { content } = await readArticle(vaultRoot(), id);
|
|
676
|
-
return textResult(content);
|
|
677
|
-
} catch (err) {
|
|
678
|
-
return textResult(`${err instanceof Error ? err.message : String(err)} — try reference_search to find the right reference document.`);
|
|
679
|
-
}
|
|
680
|
-
},
|
|
681
|
-
});
|
|
682
|
-
|
|
683
|
-
const referenceListTool = defineTool({
|
|
684
|
-
name: "reference_list",
|
|
685
|
-
label: "List mlx-bun References",
|
|
686
|
-
description: "List read-only mlx-bun reference documents available under the vault's Reference/ namespace.",
|
|
687
|
-
parameters: Type.Object({}),
|
|
688
|
-
execute: async () => {
|
|
689
|
-
try {
|
|
690
|
-
const unavailable = await memoryUnavailableMessage();
|
|
691
|
-
if (unavailable) return textResult(unavailable);
|
|
692
|
-
const refs = await listReferenceDocs(vaultRoot());
|
|
693
|
-
if (refs.length === 0) return textResult("No read-only reference documents are linked in the memory vault.");
|
|
694
|
-
return textResult(`${refs.length} read-only reference document(s):\n\n` + refs.map((s) => `- ${s}`).join("\n"));
|
|
695
|
-
} catch (err) {
|
|
696
|
-
return textResult(`reference_list failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
697
|
-
}
|
|
698
|
-
},
|
|
699
|
-
});
|
|
700
|
-
|
|
701
|
-
export function createMemoryTools(): ToolDefinition[] {
|
|
702
|
-
return [
|
|
703
|
-
memoryResolveTool,
|
|
704
|
-
memoryCategoryTool,
|
|
705
|
-
memoryReadTool,
|
|
706
|
-
memorySectionTool,
|
|
707
|
-
memoryLinksTool,
|
|
708
|
-
memoryInfoboxTool,
|
|
709
|
-
memoryListTool,
|
|
710
|
-
memoryStatusTool,
|
|
711
|
-
memorySearchTool,
|
|
712
|
-
];
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
export function createReferenceTools(): ToolDefinition[] {
|
|
716
|
-
return [referenceSearchTool, referenceReadTool, referenceListTool];
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
/**
|
|
720
|
-
* One gated line for the system prompt: states that memory is ON for this user
|
|
721
|
-
* and points at the `memory` skill, plus the FIND→READ order and the
|
|
722
|
-
* silent-colleague contract. NOT a title dump and NOT a how-to. pi already
|
|
723
|
-
* auto-injects every skill's name+description+location (formatSkillsForPrompt)
|
|
724
|
-
* and loads the SKILL.md body on demand, so the skill owns the detailed
|
|
725
|
-
* workflow. This hint is intentionally soft: memory is a scoped retrieval
|
|
726
|
-
* capability for user-specific continuity, not a default first step for every
|
|
727
|
-
* prompt. Returns "" when memory is not turned on (vault absent) so we never
|
|
728
|
-
* advertise memory the user hasn't enabled. Runs once at session construction.
|
|
729
|
-
*/
|
|
730
|
-
export async function memoryIndexHint(): Promise<string> {
|
|
731
|
-
let st: Awaited<ReturnType<typeof vaultStatus>>;
|
|
732
|
-
try {
|
|
733
|
-
st = await vaultStatus();
|
|
734
|
-
} catch {
|
|
735
|
-
return "";
|
|
736
|
-
}
|
|
737
|
-
if (!st.exists) return ""; // memory not turned on → don't advertise it
|
|
738
|
-
const articleCount = st.articleCount > 0 ? `${st.articleCount} article${st.articleCount === 1 ? "" : "s"}` : "no user articles yet";
|
|
739
|
-
const refCount = st.referenceCount > 0 ? ` plus ${st.referenceCount} read-only mlx-bun reference doc${st.referenceCount === 1 ? "" : "s"}` : "";
|
|
740
|
-
return (
|
|
741
|
-
`\n\nThe user's personal memory is on (${articleCount}${refCount}). When the answer depends on user-specific ` +
|
|
742
|
-
`continuity or missing personal context, look it up BEFORE answering: FIND the article (memory_resolve a name, ` +
|
|
743
|
-
`or memory_category for a topic), open its TOC with memory_read, then memory_section the one relevant part — ` +
|
|
744
|
-
`each article is the user's consolidated current position, so read it rather than reconstructing from history. ` +
|
|
745
|
-
`Whole-article reads and memory_search are last resorts. Use what you find silently, as a continuation — never ` +
|
|
746
|
-
`"per the wiki…". Do not use memory for weather, current public facts, generic web research, or ordinary ` +
|
|
747
|
-
`coding/file tasks when the current files are enough. See the \`memory\` skill for the workflow.`
|
|
748
|
-
);
|
|
749
|
-
}
|