mlx-bun 0.5.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 +1449 -109
- 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 +7 -5
- 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 +10 -10
- package/src/{serve → server}/chat-stage.ts +14 -14
- package/src/{client.ts → server/client.ts} +28 -2
- package/src/{serve → server}/completion-executor.ts +33 -41
- 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 +25 -82
- 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 +6 -8
- package/src/{serve → server}/request-prep.ts +47 -50
- 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 -107
- package/docs/archive/hlg-sampling.md +0 -350
- package/docs/archive/investigations/audio-input-plan.md +0 -356
- package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
- 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/release-notes-v0.4.0.md +0 -45
- package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
- 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 -2054
- package/docs/design/decode-speed-program.md +0 -2404
- package/docs/design/dreaming-nightly-pipeline.md +0 -684
- package/docs/design/generic-model-support.md +0 -821
- package/docs/design/kv-cache.md +0 -993
- package/docs/design/orpo-training.md +0 -680
- package/docs/design/speculative-decoding.md +0 -2129
- package/docs/design/turboquant.md +0 -2225
- package/docs/design/unified-engine-frontier-plan.md +0 -1987
- package/docs/design/web-chat-redesign.md +0 -695
- package/docs/planning/PRODUCT_ROADMAP.md +0 -593
- package/docs/planning/ResearchTopics.md +0 -119
- package/docs/planning/public-readiness-handoff.md +0 -244
- package/docs/planning/public-readiness.md +0 -149
- package/docs/planning/video-series.md +0 -421
- package/docs/reference/benchmarks.md +0 -3587
- package/docs/reference/cli.md +0 -646
- package/docs/reference/distribution.md +0 -380
- package/docs/reference/environment.md +0 -494
- package/docs/reference/glossary.md +0 -39
- package/docs/reference/library-api.md +0 -688
- package/docs/reference/memory.md +0 -260
- package/docs/reference/models.md +0 -346
- package/docs/reference/server-api.md +0 -1945
- package/docs/reference/server-config.md +0 -973
- package/docs/reference/training.md +0 -462
- package/docs/reference/troubleshooting.md +0 -158
- package/src/admission-plan.ts +0 -18
- package/src/audio/audiotoolbox.ts +0 -112
- package/src/audio/conformer.ts +0 -655
- package/src/audio/decode.ts +0 -133
- package/src/audio/features.ts +0 -202
- package/src/audio/mic-capture.ts +0 -98
- package/src/audio/silero-vad.ts +0 -379
- package/src/audio/transcode.ts +0 -67
- package/src/audio/whisper-decode.ts +0 -774
- package/src/audio/whisper-fast.ts +0 -732
- package/src/audio/whisper-format.ts +0 -73
- package/src/audio/whisper-mel.ts +0 -185
- package/src/audio/whisper-timing.ts +0 -274
- package/src/audio/whisper-tokenizer.ts +0 -239
- package/src/audio/whisper-transcribe.ts +0 -410
- 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 -129
- package/src/backends/mlx/batch-group.ts +0 -1874
- 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 -107
- 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/encoder-cache.ts +0 -25
- package/src/backends/mlx/evaluation.ts +0 -105
- package/src/backends/mlx/fill-append.ts +0 -58
- package/src/backends/mlx/fill-group.ts +0 -497
- 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 -174
- 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 -161
- 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/mixed-iteration.ts +0 -62
- package/src/backends/mlx/model-prompt.ts +0 -178
- package/src/backends/mlx/model-serving.ts +0 -80
- package/src/backends/mlx/paged-cache-codec.ts +0 -27
- package/src/backends/mlx/prefill-cohort.ts +0 -100
- package/src/backends/mlx/prefill-policy.ts +0 -26
- package/src/backends/mlx/prefill-rows.ts +0 -244
- package/src/backends/mlx/prefill.ts +0 -33
- package/src/backends/mlx/projected-context-rows.ts +0 -72
- package/src/backends/mlx/prompt-input.ts +0 -29
- package/src/backends/mlx/qwen-prompt-input.ts +0 -40
- package/src/backends/mlx/request-policy.ts +0 -20
- package/src/backends/mlx/request-state-policy.ts +0 -54
- package/src/backends/mlx/rollback.ts +0 -92
- package/src/backends/mlx/row-sampling.ts +0 -49
- package/src/backends/mlx/serial-executor.ts +0 -251
- package/src/backends/mlx/speculative-group.ts +0 -438
- package/src/backends/mlx/speculative-round.ts +0 -161
- package/src/backends/mlx/speculative.ts +0 -131
- 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 -173
- package/src/chat-template.ts +0 -382
- package/src/cli.ts +0 -3490
- package/src/config.ts +0 -399
- package/src/contracts/completion.ts +0 -16
- package/src/contracts/execution.ts +0 -70
- package/src/contracts/generation.ts +0 -103
- package/src/contracts/host.ts +0 -7
- package/src/contracts/object-cache.ts +0 -8
- package/src/contracts/pi-provider.ts +0 -30
- package/src/contracts/pi.ts +0 -261
- package/src/contracts/prefix-cache.ts +0 -33
- package/src/contracts/resources.ts +0 -25
- package/src/contracts/sampling.ts +0 -23
- package/src/contracts/scheduling.ts +0 -54
- 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 -64
- package/src/engine/execution-tasks.ts +0 -44
- package/src/engine/namespaced-cache.ts +0 -13
- package/src/engine/resources.ts +0 -53
- package/src/engine/scheduler.ts +0 -92
- 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 -463
- 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 -1352
- package/src/grammar.ts +0 -604
- 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 -45
- 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 -279
- package/src/kv-store.ts +0 -1135
- package/src/lab/README.md +0 -22
- 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-attention.ts +0 -117
- package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
- package/src/lab/paged-kv/paged-kv.ts +0 -336
- package/src/library.ts +0 -40
- package/src/lora.ts +0 -408
- package/src/md-modules.d.ts +0 -54
- 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 -425
- 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 -531
- package/src/mlx/materialize.ts +0 -23
- package/src/mlx/metal-kernel.ts +0 -159
- package/src/mlx/normalized-argmax.ts +0 -116
- package/src/mlx/ops.ts +0 -1108
- 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 -94
- 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 -57
- package/src/model/diffusion-gemma.ts +0 -1026
- package/src/model/factory.ts +0 -215
- package/src/model/fingerprint.ts +0 -45
- 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 -2370
- package/src/model/gemma4.ts +0 -1395
- 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 -70
- package/src/model/minicpm5.ts +0 -376
- package/src/model/profile.ts +0 -468
- package/src/model/quantized-append-attention.ts +0 -31
- 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 -250
- package/src/model/qwen3.ts +0 -277
- package/src/model/qwen3_5-checkpoint.ts +0 -164
- package/src/model/qwen3_5.ts +0 -881
- 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 -110
- package/src/model/token-groups.ts +0 -66
- 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 -89
- 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/model/whisper.ts +0 -435
- package/src/native/expert_io.c +0 -523
- package/src/native/frame_extract.swift +0 -140
- package/src/native/mic_capture.swift +0 -92
- package/src/native-pack.ts +0 -163
- 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 -1940
- package/src/preflight.ts +0 -158
- package/src/prompt-cache.ts +0 -682
- 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 -77
- package/src/safetensors.ts +0 -165
- package/src/sampler.ts +0 -1012
- 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/audio-routes.ts +0 -323
- 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 -537
- 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 -49
- package/src/serve/model-host.ts +0 -511
- package/src/serve/parent-application.ts +0 -56
- package/src/serve/prompt-response-trace.ts +0 -161
- 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/serve/transcription-server.ts +0 -64
- package/src/serve/transcription-service.ts +0 -502
- package/src/server.ts +0 -1282
- package/src/spec/assistant-rows.ts +0 -93
- 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 -318
- package/src/spec/glm52-mtp-state.ts +0 -33
- package/src/spec/ngram-source.ts +0 -226
- 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 -230
- package/src/spec/qwen-mtp-source.ts +0 -386
- package/src/spec/qwen-mtp-state.ts +0 -30
- package/src/spec/serve-loop.ts +0 -587
- package/src/spec/source.ts +0 -228
- package/src/spec/two-model-rows.ts +0 -62
- package/src/spec/two-model.ts +0 -113
- package/src/ssd-cache.ts +0 -431
- package/src/ssd-durability.ts +0 -209
- package/src/storage/host-buffer.ts +0 -24
- package/src/storage/kv-writer.ts +0 -83
- package/src/storage/kv-writer.worker.js +0 -264
- package/src/storage/retention-policy.ts +0 -37
- package/src/tiered-prompt-cache.ts +0 -45
- 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 -176
- package/src/vision/preprocess.ts +0 -247
- package/src/vision/prompt.ts +0 -409
- package/src/vision/qwen3vl-preprocess.ts +0 -409
- package/src/vision/qwen3vl-prompt.ts +0 -233
- package/src/vision/qwen3vl-tower.ts +0 -566
- package/src/vision/siglip.ts +0 -607
- package/src/vision/video-frames.ts +0 -148
- package/src/web/app.html +0 -2155
- package/src/web/app.js +0 -5863
- 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 -1060
- package/src/web/src/composer.ts +0 -962
- 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/src/voice.ts +0 -141
- 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/{serve → server}/generated-token-history.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/db.ts
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
// mlx-bun memory — "The Dreaming" synthesis store (bun:sqlite).
|
|
2
|
-
//
|
|
3
|
-
// Two kinds of tables live here:
|
|
4
|
-
//
|
|
5
|
-
// • DERIVED CACHE — entities, entity_aliases, categories, article_categories,
|
|
6
|
-
// infobox_facts, links. These are a *cache of the markdown vault*: every row
|
|
7
|
-
// can be regenerated by reindexing the articles. reindex makes them match the
|
|
8
|
-
// vault, NEVER the reverse — if a row disagrees with the markdown, the
|
|
9
|
-
// markdown wins and the row is rebuilt.
|
|
10
|
-
//
|
|
11
|
-
// • SYNTHESIS LEDGER — messages, chunks, chunk_entities, chunk_sections,
|
|
12
|
-
// synthesized_chunk_sections, watermarks (+ buckets/chunk_buckets +
|
|
13
|
-
// subject_redirects, the fold/capture sub-concept→home-article edges that the
|
|
14
|
-
// reindex projects into entity_aliases). These are
|
|
15
|
-
// the pipeline's bookkeeping: what we ingested, how we cut it, and what has
|
|
16
|
-
// already been folded into the vault. This is the authoritative record of
|
|
17
|
-
// pipeline progress and is not reconstructable from the vault alone.
|
|
18
|
-
//
|
|
19
|
-
// Storage is pointer-based: chunks do NOT copy conversation text. A chunk is a
|
|
20
|
-
// [start,end] position range into its conversation's messages; chunkText()
|
|
21
|
-
// reassembles the slice on demand. Total stored text == the messages, once.
|
|
22
|
-
//
|
|
23
|
-
// Reuses mlx-bun's per-domain sqlite pattern (cf. JobStore in src/jobs/db.ts,
|
|
24
|
-
// EvalDB in src/evaldb.ts): a small class over bun:sqlite with WAL +
|
|
25
|
-
// schema-in-constructor + a migrate() hook, living under ~/.cache/mlx-bun/.
|
|
26
|
-
// It's rebuildable derived state, so it belongs in the cache, NOT the vault.
|
|
27
|
-
|
|
28
|
-
import { Database } from "bun:sqlite";
|
|
29
|
-
import { mkdirSync } from "node:fs";
|
|
30
|
-
|
|
31
|
-
export const DEFAULT_MEMORY_DB = `${process.env.HOME}/.cache/mlx-bun/memory.sqlite`;
|
|
32
|
-
|
|
33
|
-
export interface ConversationRow {
|
|
34
|
-
/** Stable conv id: first 8 hex of the session UUID (the conv:HASH citation). */
|
|
35
|
-
conv: string;
|
|
36
|
-
source: string; // "pi-web" | "pi-terminal"
|
|
37
|
-
title: string;
|
|
38
|
-
updated_at: number;
|
|
39
|
-
chunked_at: number | null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface ChunkRow {
|
|
43
|
-
/** Deterministic id `${conv}:${start}-${end}` — idempotent re-chunking. */
|
|
44
|
-
id: string;
|
|
45
|
-
conv: string;
|
|
46
|
-
start: number;
|
|
47
|
-
end: number;
|
|
48
|
-
label: string | null;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface EntityRow {
|
|
52
|
-
name: string;
|
|
53
|
-
article_stem: string | null;
|
|
54
|
-
kind: string | null;
|
|
55
|
-
notable: number;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface BucketRow {
|
|
59
|
-
name: string;
|
|
60
|
-
article_stem: string;
|
|
61
|
-
description: string;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** Deterministic chunk id from its conversation + position range. */
|
|
65
|
-
export function chunkId(conv: string, start: number, end: number): string {
|
|
66
|
-
return `${conv}:${start}-${end}`;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const SCHEMA = `
|
|
70
|
-
CREATE TABLE IF NOT EXISTS conversations (
|
|
71
|
-
conv TEXT PRIMARY KEY,
|
|
72
|
-
source TEXT,
|
|
73
|
-
title TEXT DEFAULT '',
|
|
74
|
-
updated_at INTEGER,
|
|
75
|
-
chunked_at INTEGER
|
|
76
|
-
);
|
|
77
|
-
CREATE TABLE IF NOT EXISTS messages (
|
|
78
|
-
conv TEXT REFERENCES conversations(conv) ON DELETE CASCADE,
|
|
79
|
-
position INTEGER,
|
|
80
|
-
role TEXT,
|
|
81
|
-
uuid TEXT,
|
|
82
|
-
text TEXT,
|
|
83
|
-
PRIMARY KEY (conv, position)
|
|
84
|
-
);
|
|
85
|
-
CREATE TABLE IF NOT EXISTS chunks (
|
|
86
|
-
id TEXT PRIMARY KEY,
|
|
87
|
-
conv TEXT REFERENCES conversations(conv) ON DELETE CASCADE,
|
|
88
|
-
start INTEGER,
|
|
89
|
-
end INTEGER,
|
|
90
|
-
label TEXT
|
|
91
|
-
);
|
|
92
|
-
CREATE INDEX IF NOT EXISTS idx_chunks_conv ON chunks(conv);
|
|
93
|
-
CREATE TABLE IF NOT EXISTS entities (
|
|
94
|
-
name TEXT PRIMARY KEY,
|
|
95
|
-
article_stem TEXT,
|
|
96
|
-
kind TEXT,
|
|
97
|
-
notable INTEGER DEFAULT 0
|
|
98
|
-
);
|
|
99
|
-
CREATE TABLE IF NOT EXISTS entity_aliases (
|
|
100
|
-
alias TEXT,
|
|
101
|
-
entity_name TEXT REFERENCES entities(name) ON DELETE CASCADE,
|
|
102
|
-
PRIMARY KEY (alias, entity_name)
|
|
103
|
-
);
|
|
104
|
-
CREATE INDEX IF NOT EXISTS idx_aliases_alias ON entity_aliases(alias);
|
|
105
|
-
CREATE TABLE IF NOT EXISTS chunk_entities (
|
|
106
|
-
chunk_id TEXT REFERENCES chunks(id) ON DELETE CASCADE,
|
|
107
|
-
entity_name TEXT REFERENCES entities(name) ON DELETE CASCADE,
|
|
108
|
-
surface_form TEXT,
|
|
109
|
-
PRIMARY KEY (chunk_id, entity_name)
|
|
110
|
-
);
|
|
111
|
-
CREATE TABLE IF NOT EXISTS categories (
|
|
112
|
-
name TEXT PRIMARY KEY,
|
|
113
|
-
definition TEXT DEFAULT '',
|
|
114
|
-
parent TEXT REFERENCES categories(name) ON DELETE SET NULL
|
|
115
|
-
);
|
|
116
|
-
CREATE TABLE IF NOT EXISTS article_categories (
|
|
117
|
-
article_stem TEXT,
|
|
118
|
-
category TEXT REFERENCES categories(name) ON DELETE CASCADE,
|
|
119
|
-
source TEXT,
|
|
120
|
-
PRIMARY KEY (article_stem, category)
|
|
121
|
-
);
|
|
122
|
-
CREATE INDEX IF NOT EXISTS idx_artcat_category ON article_categories(category);
|
|
123
|
-
CREATE TABLE IF NOT EXISTS infobox_facts (
|
|
124
|
-
article_stem TEXT,
|
|
125
|
-
key TEXT,
|
|
126
|
-
value TEXT,
|
|
127
|
-
kind TEXT,
|
|
128
|
-
entity_link TEXT,
|
|
129
|
-
PRIMARY KEY (article_stem, key, value)
|
|
130
|
-
);
|
|
131
|
-
CREATE INDEX IF NOT EXISTS idx_infobox_key ON infobox_facts(key);
|
|
132
|
-
CREATE INDEX IF NOT EXISTS idx_infobox_link ON infobox_facts(entity_link);
|
|
133
|
-
CREATE TABLE IF NOT EXISTS links (
|
|
134
|
-
src_stem TEXT,
|
|
135
|
-
dst_stem TEXT,
|
|
136
|
-
via TEXT,
|
|
137
|
-
PRIMARY KEY (src_stem, dst_stem, via)
|
|
138
|
-
);
|
|
139
|
-
CREATE INDEX IF NOT EXISTS idx_links_dst ON links(dst_stem);
|
|
140
|
-
CREATE TABLE IF NOT EXISTS chunk_sections (
|
|
141
|
-
chunk_id TEXT REFERENCES chunks(id) ON DELETE CASCADE,
|
|
142
|
-
article_stem TEXT,
|
|
143
|
-
section_anchor TEXT,
|
|
144
|
-
PRIMARY KEY (chunk_id, article_stem, section_anchor)
|
|
145
|
-
);
|
|
146
|
-
CREATE TABLE IF NOT EXISTS synthesized_chunk_sections (
|
|
147
|
-
chunk_id TEXT REFERENCES chunks(id) ON DELETE CASCADE,
|
|
148
|
-
article_stem TEXT,
|
|
149
|
-
section_anchor TEXT,
|
|
150
|
-
synthesized_at INTEGER,
|
|
151
|
-
PRIMARY KEY (chunk_id, article_stem, section_anchor)
|
|
152
|
-
);
|
|
153
|
-
CREATE TABLE IF NOT EXISTS reconciled_articles (
|
|
154
|
-
article_stem TEXT,
|
|
155
|
-
reconciled_at INTEGER,
|
|
156
|
-
refreshed TEXT,
|
|
157
|
-
rewritten TEXT,
|
|
158
|
-
PRIMARY KEY (article_stem, reconciled_at)
|
|
159
|
-
);
|
|
160
|
-
CREATE TABLE IF NOT EXISTS watermarks (
|
|
161
|
-
source TEXT PRIMARY KEY,
|
|
162
|
-
cursor TEXT,
|
|
163
|
-
updated_at INTEGER
|
|
164
|
-
);
|
|
165
|
-
CREATE TABLE IF NOT EXISTS buckets (
|
|
166
|
-
name TEXT PRIMARY KEY,
|
|
167
|
-
article_stem TEXT,
|
|
168
|
-
description TEXT DEFAULT ''
|
|
169
|
-
);
|
|
170
|
-
CREATE TABLE IF NOT EXISTS chunk_buckets (
|
|
171
|
-
chunk_id TEXT REFERENCES chunks(id) ON DELETE CASCADE,
|
|
172
|
-
bucket TEXT REFERENCES buckets(name) ON DELETE CASCADE,
|
|
173
|
-
PRIMARY KEY (chunk_id, bucket)
|
|
174
|
-
);
|
|
175
|
-
CREATE TABLE IF NOT EXISTS subject_redirects (
|
|
176
|
-
surface TEXT,
|
|
177
|
-
target_stem TEXT,
|
|
178
|
-
kind TEXT,
|
|
179
|
-
PRIMARY KEY (surface, target_stem)
|
|
180
|
-
);
|
|
181
|
-
CREATE INDEX IF NOT EXISTS idx_redirect_target ON subject_redirects(target_stem);
|
|
182
|
-
`;
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* "The Dreaming" synthesis store. Same shape as JobStore/EvalDB: open in the
|
|
186
|
-
* constructor (WAL on, foreign keys on, schema ensured, additive migrate),
|
|
187
|
-
* expose `db`, and a `close()`.
|
|
188
|
-
*/
|
|
189
|
-
export class MemoryStore {
|
|
190
|
-
readonly db: Database;
|
|
191
|
-
readonly dbPath: string;
|
|
192
|
-
|
|
193
|
-
constructor(dbPath: string = DEFAULT_MEMORY_DB) {
|
|
194
|
-
if (dbPath !== ":memory:") {
|
|
195
|
-
try { mkdirSync(dbPath.slice(0, dbPath.lastIndexOf("/")), { recursive: true }); } catch {}
|
|
196
|
-
}
|
|
197
|
-
this.dbPath = dbPath;
|
|
198
|
-
this.db = new Database(dbPath);
|
|
199
|
-
this.db.exec("PRAGMA journal_mode = WAL");
|
|
200
|
-
if (this.hasLegacySchema()) this.dropAllTables();
|
|
201
|
-
this.db.exec("PRAGMA foreign_keys = ON");
|
|
202
|
-
this.db.exec(SCHEMA);
|
|
203
|
-
this.migrate();
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* A DB written by the pre-rewrite (bucket/transcript) schema. There is no
|
|
208
|
-
* production data to preserve, so detecting either marker means: nuke and
|
|
209
|
-
* recreate from scratch. Markers: chunks.text column, or the dropped
|
|
210
|
-
* synthesized_bucket_chunks table.
|
|
211
|
-
*/
|
|
212
|
-
private hasLegacySchema(): boolean {
|
|
213
|
-
const cols = this.db.query("PRAGMA table_info(chunks)").all() as { name: string }[];
|
|
214
|
-
if (cols.some((c) => c.name === "text")) return true;
|
|
215
|
-
const legacy = this.db
|
|
216
|
-
.query("SELECT name FROM sqlite_master WHERE type='table' AND name='synthesized_bucket_chunks'")
|
|
217
|
-
.get();
|
|
218
|
-
return legacy != null;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/** Drop every user table (FK checks off during the teardown). */
|
|
222
|
-
private dropAllTables(): void {
|
|
223
|
-
this.db.exec("PRAGMA foreign_keys = OFF");
|
|
224
|
-
const tables = this.db
|
|
225
|
-
.query("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'")
|
|
226
|
-
.all() as { name: string }[];
|
|
227
|
-
for (const { name } of tables) this.db.exec(`DROP TABLE IF EXISTS "${name}"`);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/** Additive-only migrations (mirrors JobStore.migrate). Re-opening is a no-op. */
|
|
231
|
-
private migrate(): void {
|
|
232
|
-
// No columns to add today; the hook stays so future fields are additive.
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Reassemble a chunk's text from its messages by position range — chunks are
|
|
237
|
-
* pointers, not copies. Returns "" for an unknown chunk id.
|
|
238
|
-
*/
|
|
239
|
-
chunkText(id: string): string {
|
|
240
|
-
const chunk = this.db
|
|
241
|
-
.query("SELECT conv, start, end FROM chunks WHERE id = ?")
|
|
242
|
-
.get(id) as { conv: string; start: number; end: number } | null;
|
|
243
|
-
if (!chunk) return "";
|
|
244
|
-
const rows = this.db
|
|
245
|
-
.query("SELECT text FROM messages WHERE conv = ? AND position BETWEEN ? AND ? ORDER BY position")
|
|
246
|
-
.all(chunk.conv, chunk.start, chunk.end) as { text: string }[];
|
|
247
|
-
return rows.map((r) => r.text).join("\n");
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
close(): void {
|
|
251
|
-
this.db.close();
|
|
252
|
-
}
|
|
253
|
-
}
|
package/src/memory/entity.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
// mlx-bun memory — ENTITY-EXTRACT (P5-T3).
|
|
2
|
-
//
|
|
3
|
-
// Reads ONE chunk's reassembled TEXT and asks the local model "what things is
|
|
4
|
-
// this chunk about?", returning canonical wiki-title entity names — the specific
|
|
5
|
-
// things AND the broad domain. This is the REAL routing-thesis test: unlike the
|
|
6
|
-
// P4 label-proxy (which routed on the 4–10-word episodic chunk label), this
|
|
7
|
-
// stage reads the full conversation text, so it sees the entities the label
|
|
8
|
-
// merely gestures at.
|
|
9
|
-
//
|
|
10
|
-
// Design (P5-T3):
|
|
11
|
-
// - ONE chunk per call (NO multi-item JSON, NO batch indices — that
|
|
12
|
-
// batch-index drift is what sank Lucien's batched assign). Output is a plain
|
|
13
|
-
// newline list parsed by parseLines.
|
|
14
|
-
// - `Entities.md` policy (the five kinds, notability checklist, naming rules,
|
|
15
|
-
// emit-both-granularities) is inlined into the prompt via loadMetaPolicy, so
|
|
16
|
-
// editing the vault page re-tunes extraction with no code change.
|
|
17
|
-
// - Deterministic canonicalization (casefold, ws-collapse, strip leading
|
|
18
|
-
// articles/possessives) so a name's spacing/short-form/brand-only variants
|
|
19
|
-
// collapse to one stem. The canonical stem feeds dedup + the entity_aliases index.
|
|
20
|
-
// - Persists chunk_entities(chunk_id, entity_name, surface_form) and upserts a
|
|
21
|
-
// candidate entities row (article_stem NULL — no article exists yet) so the
|
|
22
|
-
// FK on chunk_entities.entity_name is satisfied; the raw model surface is
|
|
23
|
-
// stored as an alias of the canonical name.
|
|
24
|
-
//
|
|
25
|
-
// The base model + policy runs until a `memory-entity` LoRA is trained (P10-T3),
|
|
26
|
-
// which only happens on a measured recall miss here.
|
|
27
|
-
|
|
28
|
-
import type { MemoryStore } from "./db";
|
|
29
|
-
import { callLocal } from "./model";
|
|
30
|
-
import { parseLines } from "./parse";
|
|
31
|
-
import { loadMetaPolicy } from "./prompts";
|
|
32
|
-
import { EntityResolver, goldSeeds } from "./resolve";
|
|
33
|
-
|
|
34
|
-
/** Model-call seam for extraction (defaults to the local `entity` stage). Injected
|
|
35
|
-
* by the pipeline + tests so the deterministic scaffolding runs with no GPU. */
|
|
36
|
-
export type ExtractCall = (prompt: string, opts?: { maxTokens?: number }) => Promise<string>;
|
|
37
|
-
|
|
38
|
-
/** One extracted entity: the canonical wiki-title name + the raw model surface. */
|
|
39
|
-
export interface ExtractedEntity {
|
|
40
|
-
/** Canonical wiki-title name (the model's line, cleaned of markup/trailing
|
|
41
|
-
* punctuation) — the value written to chunk_entities.entity_name. */
|
|
42
|
-
name: string;
|
|
43
|
-
/** The raw surface the model emitted (chunk_entities.surface_form). */
|
|
44
|
-
surface: string;
|
|
45
|
-
/** Deterministic canonical stem (casefold/ws-collapse/strip articles+
|
|
46
|
-
* possessives) used for dedup and alias keying. */
|
|
47
|
-
stem: string;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const QUESTION =
|
|
51
|
-
"What things is this chunk about? List canonical wiki-title names, one per " +
|
|
52
|
-
"line; include specific things AND the broad domain. Output NONE if nothing " +
|
|
53
|
-
"nameable or substantive.";
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Deterministic canonical stem of an entity surface: casefold, collapse
|
|
57
|
-
* whitespace/underscores, strip surrounding markdown/quotes, drop a trailing
|
|
58
|
-
* period, then strip ONE leading article (the/a/an) and ONE leading possessive
|
|
59
|
-
* determiner (my/your/his/her/its/our/their), plus a trailing possessive `'s`.
|
|
60
|
-
*
|
|
61
|
-
* This is the dedup key: a name's spacing variants, short forms, brand-only
|
|
62
|
-
* surfaces, and possessive surfaces all collapse toward one stem so variants of
|
|
63
|
-
* the same thing unify.
|
|
64
|
-
*/
|
|
65
|
-
export function canonicalize(surface: string): string {
|
|
66
|
-
let t = surface
|
|
67
|
-
.toLowerCase()
|
|
68
|
-
.replace(/[*_`"'“”]+/g, " ") // strip md emphasis / quotes
|
|
69
|
-
.replace(/[_\s]+/g, " ")
|
|
70
|
-
.trim()
|
|
71
|
-
.replace(/[.,;:]+$/, "")
|
|
72
|
-
.trim();
|
|
73
|
-
// strip a leading list marker / numbering the model may emit ("- ", "1. ")
|
|
74
|
-
t = t.replace(/^(?:[-*•]\s+|\d+[.)]\s+)/, "").trim();
|
|
75
|
-
// strip ONE leading article, then ONE leading possessive determiner
|
|
76
|
-
t = t.replace(/^(?:the|a|an)\s+/, "").trim();
|
|
77
|
-
t = t.replace(/^(?:my|your|his|her|its|our|their)\s+/, "").trim();
|
|
78
|
-
// strip a trailing saxon-genitive
|
|
79
|
-
t = t.replace(/['’]s$/, "").trim();
|
|
80
|
-
return t;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** Clean a raw model line into a stored canonical NAME (preserve casing/words,
|
|
84
|
-
* just strip surrounding markup, list markers, and trailing punctuation). */
|
|
85
|
-
function cleanName(line: string): string {
|
|
86
|
-
return line
|
|
87
|
-
.replace(/^(?:[-*•]\s+|\d+[.)]\s+)/, "")
|
|
88
|
-
.replace(/^[*_`"“]+|[*_`"”]+$/g, "")
|
|
89
|
-
.replace(/[.,;:]+$/, "")
|
|
90
|
-
.trim();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Build the entity-extraction prompt: inlined `Entities.md` policy + the chunk
|
|
95
|
-
* text + the fixed question. The policy block is passed in so callers can cache
|
|
96
|
-
* it across many chunks (loadMetaPolicy does disk IO).
|
|
97
|
-
*/
|
|
98
|
-
export function buildEntityPrompt(text: string, policy: string): string {
|
|
99
|
-
return (
|
|
100
|
-
`${policy}\n\n` +
|
|
101
|
-
`--- Conversation chunk ---\n${text}\n--- end chunk ---\n\n` +
|
|
102
|
-
QUESTION
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Core extraction: render the prompt, call the base model (maxTokens 128), parse
|
|
108
|
-
* the newline list, clean + canonicalize each surface, and de-duplicate by stem.
|
|
109
|
-
* Pure w.r.t. the DB. Returns the extracted entities AND the raw newline-line
|
|
110
|
-
* count (pre-dedup) so instruments can report the canonicalizer's parse health.
|
|
111
|
-
*/
|
|
112
|
-
export async function extractEntityNamesRaw(
|
|
113
|
-
text: string,
|
|
114
|
-
policy?: string,
|
|
115
|
-
opts?: { maxTokens?: number; call?: ExtractCall },
|
|
116
|
-
): Promise<{ entities: ExtractedEntity[]; rawLines: number }> {
|
|
117
|
-
if (!text.trim()) return { entities: [], rawLines: 0 };
|
|
118
|
-
const pol = policy ?? loadMetaPolicy(["Entities"]);
|
|
119
|
-
const prompt = buildEntityPrompt(text, pol);
|
|
120
|
-
const call: ExtractCall = opts?.call ?? ((p, o) => callLocal("entity", { user: p }, o));
|
|
121
|
-
const out = await call(prompt, { maxTokens: opts?.maxTokens ?? 128 });
|
|
122
|
-
const lines = parseLines(out);
|
|
123
|
-
const seen = new Set<string>();
|
|
124
|
-
const entities: ExtractedEntity[] = [];
|
|
125
|
-
for (const raw of lines) {
|
|
126
|
-
const surface = cleanName(raw);
|
|
127
|
-
const stem = canonicalize(surface);
|
|
128
|
-
if (!stem || !surface) continue;
|
|
129
|
-
if (seen.has(stem)) continue; // collapse variants of one thing
|
|
130
|
-
seen.add(stem);
|
|
131
|
-
entities.push({ name: surface, surface: raw.trim(), stem });
|
|
132
|
-
}
|
|
133
|
-
return { entities, rawLines: lines.length };
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/** Convenience wrapper: just the extracted entities (no raw-line count). */
|
|
137
|
-
export async function extractEntityNames(
|
|
138
|
-
text: string,
|
|
139
|
-
policy?: string,
|
|
140
|
-
opts?: { maxTokens?: number; call?: ExtractCall },
|
|
141
|
-
): Promise<ExtractedEntity[]> {
|
|
142
|
-
return (await extractEntityNamesRaw(text, policy, opts)).entities;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Full stage: extract the entities a chunk is about and PERSIST them.
|
|
147
|
-
*
|
|
148
|
-
* Each extracted surface is RESOLVED to a canonical entity through the variant
|
|
149
|
-
* resolver (squeeze/alias/token-subset; see resolve.ts) so casing/spacing/brand
|
|
150
|
-
* variants collapse onto ONE entity instead of minting a fresh row each — the
|
|
151
|
-
* dedup fix. The resolver is seeded from the store's existing entities/aliases
|
|
152
|
-
* AND the curated gold (so notable brand-only nicknames fold), and accumulates
|
|
153
|
-
* minted canonicals across chunks when the caller threads one in via `opts`.
|
|
154
|
-
*
|
|
155
|
-
* Upserts the resolved canonical `entities` row (article_stem NULL — no article
|
|
156
|
-
* exists yet; ROUTE/CREATE promote it later) so the chunk_entities FK is
|
|
157
|
-
* satisfied, records the raw surface as an alias of the canonical, and writes one
|
|
158
|
-
* chunk_entities row per distinct resolved entity. Idempotent: re-running on the
|
|
159
|
-
* same chunk INSERT-OR-IGNOREs the same rows.
|
|
160
|
-
*
|
|
161
|
-
* Returns the extracted list (also useful to callers that route immediately).
|
|
162
|
-
*/
|
|
163
|
-
export async function extractEntities(
|
|
164
|
-
store: MemoryStore,
|
|
165
|
-
chunkId: string,
|
|
166
|
-
opts?: { maxTokens?: number; policy?: string; resolver?: EntityResolver; call?: ExtractCall },
|
|
167
|
-
): Promise<ExtractedEntity[]> {
|
|
168
|
-
const text = store.chunkText(chunkId);
|
|
169
|
-
const extracted = await extractEntityNames(text, opts?.policy, opts);
|
|
170
|
-
|
|
171
|
-
// Seed once from the store + gold unless the caller threads a shared resolver
|
|
172
|
-
// (which lets minted canonicals carry across chunks in a single run).
|
|
173
|
-
const resolver = opts?.resolver ?? EntityResolver.fromStore(store);
|
|
174
|
-
if (!opts?.resolver) for (const s of goldSeeds()) resolver.register(s.canonical, s.aliases);
|
|
175
|
-
|
|
176
|
-
const insEntity = store.db.query(
|
|
177
|
-
"INSERT OR IGNORE INTO entities (name, article_stem, kind, notable) VALUES (?, NULL, NULL, 0)",
|
|
178
|
-
);
|
|
179
|
-
const insAlias = store.db.query(
|
|
180
|
-
"INSERT OR IGNORE INTO entity_aliases (alias, entity_name) VALUES (?, ?)",
|
|
181
|
-
);
|
|
182
|
-
const insChunkEntity = store.db.query(
|
|
183
|
-
"INSERT OR IGNORE INTO chunk_entities (chunk_id, entity_name, surface_form) VALUES (?, ?, ?)",
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
// Resolve OUTSIDE the write tx (the resolver index is in-memory, no DB writes),
|
|
187
|
-
// collapsing within-chunk variants onto one canonical before persisting.
|
|
188
|
-
const resolved = new Map<string, string>(); // canonical → first raw surface seen
|
|
189
|
-
for (const e of extracted) {
|
|
190
|
-
const canonical = resolver.resolve(e.name).name;
|
|
191
|
-
if (!resolved.has(canonical)) resolved.set(canonical, e.surface);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const tx = store.db.transaction(() => {
|
|
195
|
-
for (const [canonical, surface] of resolved) {
|
|
196
|
-
insEntity.run(canonical);
|
|
197
|
-
insAlias.run(canonicalize(surface), canonical);
|
|
198
|
-
insChunkEntity.run(chunkId, canonical, surface);
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
tx();
|
|
202
|
-
return extracted;
|
|
203
|
-
}
|
package/src/memory/gate.ts
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
// mlx-bun memory — the conservative write gate.
|
|
2
|
-
//
|
|
3
|
-
// The Dreaming write pipeline patches articles section-by-section. Before any
|
|
4
|
-
// synthesized edit is committed to the vault, it passes through this gate: a
|
|
5
|
-
// deterministic, GPU-free check that the edit PRESERVED the existing article
|
|
6
|
-
// rather than degrading it. A weak pass is a NO-OP — the caller discards the
|
|
7
|
-
// model's output and leaves the vault byte-for-byte unchanged.
|
|
8
|
-
//
|
|
9
|
-
// This is a faithful port of Lucien's editorial gate (scripts/wikify.ts:
|
|
10
|
-
// verifyEditorialResult / checkFootnoteIntegrity / extractConvHashes). It
|
|
11
|
-
// catches citation loss, structural loss, footnote-bijection breaks, and gross
|
|
12
|
-
// prose deletion. It does NOT catch nuance loss — that is the cloud judge's job.
|
|
13
|
-
// The gate is mechanism, not policy: it can only reject, never rewrite.
|
|
14
|
-
|
|
15
|
-
// ---- citation hashes --------------------------------------------------
|
|
16
|
-
|
|
17
|
-
// Illustrative placeholder hashes the synthesis prompt warns against; never
|
|
18
|
-
// real citations, so excluded from the preservation set.
|
|
19
|
-
const SPEC_HASHES = new Set(["00000000", "00000001"]);
|
|
20
|
-
|
|
21
|
-
/** All real `conv:HASH` citation hashes in `text`, lowercased, minus the
|
|
22
|
-
* documented spec placeholders. A `conv:` hash is exactly 8 lowercase
|
|
23
|
-
* hex-ish chars `[0-9a-z]` (matched case-insensitively, then lowered). */
|
|
24
|
-
export function extractConvHashes(text: string): Set<string> {
|
|
25
|
-
const out = new Set<string>();
|
|
26
|
-
for (const m of text.matchAll(/conv:([0-9a-z]{8})/gi)) {
|
|
27
|
-
const h = m[1]!.toLowerCase();
|
|
28
|
-
if (!SPEC_HASHES.has(h)) out.add(h);
|
|
29
|
-
}
|
|
30
|
-
return out;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// ---- footnote integrity ----------------------------------------------
|
|
34
|
-
|
|
35
|
-
export interface CheckResult {
|
|
36
|
-
ok: boolean;
|
|
37
|
-
/** Human-readable violations; empty when `ok`. */
|
|
38
|
-
errors: string[];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Verify footnote markers and definitions form a clean bijection:
|
|
43
|
-
* - every `[^N]` body marker has a matching `[^N]:` definition and vice versa;
|
|
44
|
-
* - marker/definition numbers are contiguous from 1;
|
|
45
|
-
* - every definition line carries exactly one backticked `conv:HASH`.
|
|
46
|
-
*
|
|
47
|
-
* Only a line-START `[^N]:` is a definition. A body marker glued to a
|
|
48
|
-
* list-introducing colon (`...two types[^2]:`) is still a marker, so we strip
|
|
49
|
-
* definition lines before scanning for markers rather than excluding any
|
|
50
|
-
* `[^N]` followed by `:`.
|
|
51
|
-
*/
|
|
52
|
-
export function checkFootnoteIntegrity(text: string): CheckResult {
|
|
53
|
-
const errors: string[] = [];
|
|
54
|
-
|
|
55
|
-
// Definition lines: `[^N]: ...` at line start.
|
|
56
|
-
const defNums = new Set<number>();
|
|
57
|
-
const defLineByNum = new Map<number, string>();
|
|
58
|
-
const defSeen = new Set<number>();
|
|
59
|
-
for (const m of text.matchAll(/^\[\^(\d+)\]:(.*)$/gm)) {
|
|
60
|
-
const n = parseInt(m[1]!, 10);
|
|
61
|
-
if (defSeen.has(n)) errors.push(`definition [^${n}] is duplicated`);
|
|
62
|
-
defSeen.add(n);
|
|
63
|
-
defNums.add(n);
|
|
64
|
-
defLineByNum.set(n, m[2]!);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Body markers: every `[^N]` outside a definition line.
|
|
68
|
-
const bodyText = text
|
|
69
|
-
.split("\n")
|
|
70
|
-
.filter((l) => !/^\[\^\d+\]:/.test(l))
|
|
71
|
-
.join("\n");
|
|
72
|
-
const markerNums = new Set<number>();
|
|
73
|
-
for (const m of bodyText.matchAll(/\[\^(\d+)\]/g)) {
|
|
74
|
-
markerNums.add(parseInt(m[1]!, 10));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
for (const n of markerNums) {
|
|
78
|
-
if (!defNums.has(n)) errors.push(`marker [^${n}] has no definition`);
|
|
79
|
-
}
|
|
80
|
-
for (const n of defNums) {
|
|
81
|
-
if (!markerNums.has(n)) errors.push(`definition [^${n}] has no marker`);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const all = [...new Set([...markerNums, ...defNums])].sort((a, b) => a - b);
|
|
85
|
-
for (let i = 0; i < all.length; i++) {
|
|
86
|
-
if (all[i] !== i + 1) {
|
|
87
|
-
errors.push(`footnote numbers not contiguous from 1 (saw ${all.join(",")})`);
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
for (const [n, line] of defLineByNum) {
|
|
93
|
-
const backticked = line.match(/`conv:[0-9a-z]{8}`/gi) ?? [];
|
|
94
|
-
if (backticked.length !== 1) {
|
|
95
|
-
errors.push(`[^${n}] definition lacks a backticked \`conv:HASH\` (found ${backticked.length})`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return { ok: errors.length === 0, errors };
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// ---- the gate ---------------------------------------------------------
|
|
103
|
-
|
|
104
|
-
export interface GateOptions {
|
|
105
|
-
/** Edited word count must be >= floor * before's word count. Default 0.7. */
|
|
106
|
-
floor?: number;
|
|
107
|
-
/** Citation hashes the caller has DELIBERATELY pruned (a factual-error fix that
|
|
108
|
-
* removes a wrong value as if it had never been there). Their loss is permitted
|
|
109
|
-
* rather than vetoed as accidental citation loss. Empty by default. */
|
|
110
|
-
allowDroppedHashes?: Set<string>;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export interface GateVerdict {
|
|
114
|
-
/** True when the edit is safe to commit. */
|
|
115
|
-
ok: boolean;
|
|
116
|
-
/** Null when `ok`; otherwise the joined failing reasons, so the caller can
|
|
117
|
-
* log WHY the edit was discarded. */
|
|
118
|
-
reason: string | null;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function wordCount(s: string): number {
|
|
122
|
-
const t = s.trim();
|
|
123
|
-
return t ? t.split(/\s+/).length : 0;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/** True when `text` contains an H1 title line (`# Title`). */
|
|
127
|
-
function hasH1(text: string): boolean {
|
|
128
|
-
return text.split("\n").some((l) => /^#\s+\S/.test(l.trim()));
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** True when `text` contains a `## References` section heading. */
|
|
132
|
-
function hasReferences(text: string): boolean {
|
|
133
|
-
return /^##\s+References\s*$/m.test(text);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* The conservative write gate. Given the (before, after) text of a section or
|
|
138
|
-
* article, decide whether the edit preserved it. On `ok: false` the caller
|
|
139
|
-
* MUST discard `after` and keep `before` — the vault stays unchanged.
|
|
140
|
-
*
|
|
141
|
-
* Enforces (deterministically, no GPU):
|
|
142
|
-
* 1. Citation preservation — every pre-existing `conv:HASH` survives.
|
|
143
|
-
* 2. Footnote bijection — every `[^N]` marker ⇔ one `[^N]:` definition.
|
|
144
|
-
* 3. Prose preservation — the edited word count stays at/above the floor.
|
|
145
|
-
* 4. Structural survival — an H1 and `## References` present before survive.
|
|
146
|
-
*
|
|
147
|
-
* Catches citation/structure/bulk-prose loss; does NOT catch nuance loss.
|
|
148
|
-
*/
|
|
149
|
-
export function gateEdit(before: string, after: string, opts: GateOptions = {}): GateVerdict {
|
|
150
|
-
const floor = opts.floor ?? 0.7;
|
|
151
|
-
const reasons: string[] = [];
|
|
152
|
-
|
|
153
|
-
// 1. Citation preservation: every pre-existing hash must still be cited —
|
|
154
|
-
// UNLESS the caller deliberately pruned it (a factual-error fix).
|
|
155
|
-
const beforeHashes = extractConvHashes(before);
|
|
156
|
-
const afterHashes = extractConvHashes(after);
|
|
157
|
-
const allowed = opts.allowDroppedHashes ?? new Set<string>();
|
|
158
|
-
for (const h of beforeHashes) {
|
|
159
|
-
if (!afterHashes.has(h) && !allowed.has(h)) reasons.push(`dropped citation conv:${h}`);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// 2. Footnote bijection on the edited text.
|
|
163
|
-
const fn = checkFootnoteIntegrity(after);
|
|
164
|
-
if (!fn.ok) reasons.push(...fn.errors);
|
|
165
|
-
|
|
166
|
-
// 3. Prose preservation: word floor on the touched text.
|
|
167
|
-
const bw = wordCount(before);
|
|
168
|
-
const aw = wordCount(after);
|
|
169
|
-
if (bw > 0 && aw < floor * bw) {
|
|
170
|
-
reasons.push(`word count ${aw} below floor ${Math.ceil(floor * bw)} (before ${bw})`);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// 4. Structural survival: an H1 / ## References present before must survive.
|
|
174
|
-
if (hasH1(before) && !hasH1(after)) reasons.push("edit dropped the H1 title");
|
|
175
|
-
if (hasReferences(before) && !hasReferences(after)) {
|
|
176
|
-
reasons.push("edit dropped the ## References section");
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// 5. See-also singularity: a fence-confused rebuild that buried one ## See also
|
|
180
|
-
// and appended another would grow the section unboundedly. Reject (NO-OP) any
|
|
181
|
-
// result carrying more than ONE ## See also heading, so the section can never
|
|
182
|
-
// grow regardless of how pathological the input was.
|
|
183
|
-
const seeAlsoCount = (after.match(/^##\s+See also\s*$/gim) ?? []).length;
|
|
184
|
-
if (seeAlsoCount > 1) reasons.push(`multiple ## See also sections (${seeAlsoCount})`);
|
|
185
|
-
|
|
186
|
-
return reasons.length ? { ok: false, reason: reasons.join("; ") } : { ok: true, reason: null };
|
|
187
|
-
}
|