@modusensus/dsh-mneme 0.13.0 → 0.14.0-beta.2
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/LICENSE +21 -21
- package/README.md +830 -828
- package/assets/icon.svg +3 -3
- package/bin/cli.mjs +964 -964
- package/bin/dsh-mneme-choro.mjs +262 -254
- package/bin/dsh-mneme-mcp.mjs +510 -510
- package/bin/dsh-mneme-serve.mjs +151 -151
- package/cordis.patch.yml +21 -21
- package/docs/CONFIGURATION.md +407 -402
- package/docs/CONTINUITY.md +139 -139
- package/docs/DAEMON.md +57 -57
- package/docs/DIRECTORIES.md +114 -114
- package/docs/DISTILL.md +397 -371
- package/docs/DSH-GO.md +97 -97
- package/docs/ENTITIES.md +247 -247
- package/docs/FORGET.md +77 -77
- package/docs/KB.md +110 -110
- package/docs/LOCAL_MODEL.md +222 -222
- package/docs/SEMANTIC.md +256 -256
- package/docs/SHARE.md +552 -552
- package/docs/SLEEP.md +202 -202
- package/docs/STORAGE.md +122 -122
- package/docs/WORKFLOWS.md +366 -366
- package/lib/api-standalone.js +1007 -1007
- package/lib/api.js +3600 -3394
- package/lib/attachment-text.js +122 -122
- package/lib/bootstrap-http.js +105 -105
- package/lib/bootstrap.js +215 -215
- package/lib/candidates.js +454 -454
- package/lib/capabilities.js +819 -819
- package/lib/choro-command.js +111 -111
- package/lib/client.js +14420 -13436
- package/lib/commands.js +95 -95
- package/lib/config-keys.js +144 -144
- package/lib/config.js +1361 -1317
- package/lib/content-hash.js +54 -54
- package/lib/continuity.js +258 -258
- package/lib/date-hint.js +32 -0
- package/lib/diary/auto.js +190 -190
- package/lib/diary/compose.js +440 -440
- package/lib/diary/dir.js +59 -59
- package/lib/diary/export.js +97 -97
- package/lib/diary/index.js +26 -26
- package/lib/diary/library.js +189 -189
- package/lib/diary/qq-inbox.js +142 -142
- package/lib/diary/rollover.js +61 -61
- package/lib/diary/session-provider.js +122 -122
- package/lib/document-index.js +94 -94
- package/lib/document.js +322 -322
- package/lib/dream/clustering.js +123 -123
- package/lib/dream/decisions.js +945 -907
- package/lib/dream/narratives.js +44 -44
- package/lib/dream/sleep.js +2027 -1887
- package/lib/dream/triage.js +139 -0
- package/lib/dream.js +1879 -1764
- package/lib/dsh-go/host.js +162 -162
- package/lib/dsh-go/panel.js +2091 -2091
- package/lib/dsh-go/text.js +342 -342
- package/lib/dsh-go/views/common.js +68 -68
- package/lib/dsh-go/views/entity.js +48 -48
- package/lib/dsh-go/views/memory.js +198 -198
- package/lib/dsh-go/views/root.js +30 -30
- package/lib/dsh-go/views/settings.js +398 -398
- package/lib/dsh-go/views/status.js +51 -51
- package/lib/embedding.js +342 -342
- package/lib/entities/extractor.js +285 -285
- package/lib/fence.js +24 -24
- package/lib/graph/anchoring.js +184 -184
- package/lib/guide.js +74 -74
- package/lib/heat.js +144 -144
- package/lib/hot-memory.js +119 -107
- package/lib/image-describe.js +158 -0
- package/lib/index.js +852 -822
- package/lib/inject.js +656 -639
- package/lib/kb/index.js +309 -309
- package/lib/kb/routes.js +219 -219
- package/lib/kb/tools.js +148 -148
- package/lib/lang.js +607 -584
- package/lib/local-embedder.js +358 -358
- package/lib/maintenance.js +162 -162
- package/lib/memory-source.js +9 -9
- package/lib/mirror.js +330 -330
- package/lib/organize.js +456 -456
- package/lib/peak-hours.js +172 -172
- package/lib/pipeline-activities.js +178 -178
- package/lib/pipeline-attribution.js +165 -165
- package/lib/pipeline-command.js +279 -279
- package/lib/pipeline-confirm.js +142 -142
- package/lib/pipeline-exec.js +174 -174
- package/lib/pipeline-nudge-auto.js +129 -129
- package/lib/pipeline-nudge.js +1623 -1623
- package/lib/pipeline-observations.js +181 -181
- package/lib/pipeline-observe.js +133 -133
- package/lib/pipeline-runner.js +361 -361
- package/lib/pipeline-runs.js +442 -442
- package/lib/pipeline.js +716 -716
- package/lib/placement.js +13 -13
- package/lib/pre-inject-gate.js +354 -354
- package/lib/profile-extract.js +164 -164
- package/lib/profile-facts.js +356 -356
- package/lib/provenance-http.js +251 -251
- package/lib/quality-filter.js +162 -162
- package/lib/recall-stats.js +190 -190
- package/lib/reclaim-http.js +150 -150
- package/lib/reranker.js +269 -269
- package/lib/runtime/adopt.js +176 -176
- package/lib/runtime/closure.js +172 -172
- package/lib/runtime/download.js +247 -247
- package/lib/runtime/layout.js +265 -265
- package/lib/runtime/loader.js +252 -252
- package/lib/runtime/model-fetch.js +361 -361
- package/lib/runtime/provision.js +237 -237
- package/lib/runtime/tarball.js +130 -130
- package/lib/runtime/verify.js +223 -223
- package/lib/safe-slice.js +18 -18
- package/lib/scope-state.js +277 -277
- package/lib/scope.js +187 -187
- package/lib/search/adaptive.js +60 -60
- package/lib/search/bm25.js +96 -96
- package/lib/semantic.js +572 -572
- package/lib/sensitive-scan.js +209 -209
- package/lib/serve.js +228 -228
- package/lib/service.js +3268 -3196
- package/lib/session-gate.js +91 -91
- package/lib/session-usage.js +350 -350
- package/lib/settings.js +827 -802
- package/lib/share-http.js +281 -281
- package/lib/share-import.js +234 -234
- package/lib/share.js +335 -335
- package/lib/store.js +5895 -5662
- package/lib/summarize.js +1388 -1343
- package/lib/tools.js +1370 -1356
- package/lib/user-settings.js +230 -230
- package/lib/vector-index.js +180 -180
- package/lib/version-check.js +122 -122
- package/lib/wiki/claims.js +267 -0
- package/lib/wiki/cli-hint.js +90 -90
- package/lib/wiki/inject.js +164 -164
- package/lib/wiki/partition.js +200 -200
- package/lib/wiki/plan.js +214 -214
- package/lib/wiki/queries.js +640 -474
- package/lib/wiki/render.js +261 -187
- package/lib/wiki/scan.js +371 -371
- package/lib/wiki/t0.js +500 -463
- package/lib/wiki/t1-jobs.js +232 -232
- package/lib/wiki/t1.js +609 -502
- package/lib/write-admission.js +404 -404
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/package.json +15 -1
- package/runtime-manifest.json +526 -526
- package/scripts/benchmark-embed.js +201 -201
- package/scripts/benchmark-recall.js +249 -249
- package/scripts/benchmark-rerank.js +166 -166
- package/scripts/build-runtime-manifest.mjs +224 -224
- package/scripts/changelog-prep.mjs +91 -91
- package/scripts/check-sync.js +44 -44
- package/scripts/e2e-dsh.js +220 -220
- package/scripts/mneme-runtime.mjs +277 -277
- package/scripts/publish-gate.mjs +197 -197
- package/scripts/release-docs.mjs +210 -204
- package/scripts/release-notes.mjs +164 -161
- package/scripts/stress-dsh.js +255 -255
- package/scripts/sync-lib.js +47 -47
- package/scripts/sync-test-badge.mjs +69 -69
- package/scripts/test-count-sync.mjs +48 -48
- package/src/api-standalone.js +1007 -1007
- package/src/api.js +3600 -3394
- package/src/attachment-text.js +122 -122
- package/src/bootstrap-http.js +105 -105
- package/src/bootstrap.js +215 -215
- package/src/candidates.js +454 -454
- package/src/capabilities.js +819 -819
- package/src/choro-command.js +111 -111
- package/src/commands.js +95 -95
- package/src/config-keys.js +144 -144
- package/src/config.js +1361 -1317
- package/src/content-hash.js +54 -54
- package/src/continuity.js +258 -258
- package/src/date-hint.js +32 -0
- package/src/diary/auto.js +190 -190
- package/src/diary/compose.js +440 -440
- package/src/diary/dir.js +59 -59
- package/src/diary/export.js +97 -97
- package/src/diary/index.js +26 -26
- package/src/diary/library.js +189 -189
- package/src/diary/qq-inbox.js +142 -142
- package/src/diary/rollover.js +61 -61
- package/src/diary/session-provider.js +122 -122
- package/src/document-index.js +94 -94
- package/src/document.js +322 -322
- package/src/dream/clustering.js +123 -123
- package/src/dream/decisions.js +945 -907
- package/src/dream/narratives.js +44 -44
- package/src/dream/sleep.js +2027 -1887
- package/src/dream/triage.js +139 -0
- package/src/dream.js +1879 -1764
- package/src/dsh-go/host.js +162 -162
- package/src/dsh-go/panel.js +2091 -2091
- package/src/dsh-go/text.js +342 -342
- package/src/dsh-go/views/common.js +68 -68
- package/src/dsh-go/views/entity.js +48 -48
- package/src/dsh-go/views/memory.js +198 -198
- package/src/dsh-go/views/root.js +30 -30
- package/src/dsh-go/views/settings.js +398 -398
- package/src/dsh-go/views/status.js +51 -51
- package/src/embedding.js +342 -342
- package/src/entities/extractor.js +285 -285
- package/src/fence.js +24 -24
- package/src/graph/anchoring.js +184 -184
- package/src/guide.js +74 -74
- package/src/heat.js +144 -144
- package/src/hot-memory.js +119 -107
- package/src/image-describe.js +158 -0
- package/src/index.js +852 -822
- package/src/inject.js +656 -639
- package/src/kb/index.js +309 -309
- package/src/kb/routes.js +219 -219
- package/src/kb/tools.js +148 -148
- package/src/lang.js +607 -584
- package/src/local-embedder.js +358 -358
- package/src/maintenance.js +162 -162
- package/src/memory-source.js +9 -9
- package/src/mirror.js +330 -330
- package/src/organize.js +456 -456
- package/src/peak-hours.js +172 -172
- package/src/pipeline-activities.js +178 -178
- package/src/pipeline-attribution.js +165 -165
- package/src/pipeline-command.js +279 -279
- package/src/pipeline-confirm.js +142 -142
- package/src/pipeline-exec.js +174 -174
- package/src/pipeline-nudge-auto.js +129 -129
- package/src/pipeline-nudge.js +1623 -1623
- package/src/pipeline-observations.js +181 -181
- package/src/pipeline-observe.js +133 -133
- package/src/pipeline-runner.js +361 -361
- package/src/pipeline-runs.js +442 -442
- package/src/pipeline.js +716 -716
- package/src/placement.js +13 -13
- package/src/pre-inject-gate.js +354 -354
- package/src/profile-extract.js +164 -164
- package/src/profile-facts.js +356 -356
- package/src/provenance-http.js +251 -251
- package/src/quality-filter.js +162 -162
- package/src/recall-stats.js +190 -190
- package/src/reclaim-http.js +150 -150
- package/src/reranker.js +269 -269
- package/src/runtime/adopt.js +176 -176
- package/src/runtime/closure.js +172 -172
- package/src/runtime/download.js +247 -247
- package/src/runtime/layout.js +265 -265
- package/src/runtime/loader.js +252 -252
- package/src/runtime/model-fetch.js +361 -361
- package/src/runtime/provision.js +237 -237
- package/src/runtime/tarball.js +130 -130
- package/src/runtime/verify.js +223 -223
- package/src/safe-slice.js +18 -18
- package/src/scope-state.js +277 -277
- package/src/scope.js +187 -187
- package/src/search/adaptive.js +60 -60
- package/src/search/bm25.js +96 -96
- package/src/semantic.js +572 -572
- package/src/sensitive-scan.js +209 -209
- package/src/serve.js +228 -228
- package/src/service.js +3268 -3196
- package/src/session-gate.js +91 -91
- package/src/session-usage.js +350 -350
- package/src/settings.js +827 -802
- package/src/share-http.js +281 -281
- package/src/share-import.js +234 -234
- package/src/share.js +335 -335
- package/src/store.js +5895 -5662
- package/src/summarize.js +1388 -1343
- package/src/tools.js +1370 -1356
- package/src/user-settings.js +230 -230
- package/src/vector-index.js +180 -180
- package/src/version-check.js +122 -122
- package/src/wiki/claims.js +267 -0
- package/src/wiki/cli-hint.js +90 -90
- package/src/wiki/inject.js +164 -164
- package/src/wiki/partition.js +200 -200
- package/src/wiki/plan.js +214 -214
- package/src/wiki/queries.js +640 -474
- package/src/wiki/render.js +261 -187
- package/src/wiki/scan.js +371 -371
- package/src/wiki/t0.js +500 -463
- package/src/wiki/t1-jobs.js +232 -232
- package/src/wiki/t1.js +609 -502
- package/src/write-admission.js +404 -404
- package/test/adaptive-inject-budget.test.js +85 -85
- package/test/api-hardening.test.js +173 -173
- package/test/api-nudge-route.test.js +259 -259
- package/test/api-routes-gaps.test.js +1092 -1092
- package/test/api.test.js +3007 -2988
- package/test/attachment-text.test.js +139 -139
- package/test/audit.test.js +448 -448
- package/test/baseline-persist.test.js +248 -248
- package/test/benchmark.test.js +94 -94
- package/test/bm25-corpus-cache.test.js +145 -145
- package/test/bootstrap.test.js +228 -228
- package/test/candidates.test.js +345 -345
- package/test/capabilities.test.js +577 -577
- package/test/capacity-warning.test.js +262 -262
- package/test/changelog-prep.test.js +125 -125
- package/test/choro-command.test.js +218 -218
- package/test/cli-enums.test.js +37 -37
- package/test/cli-flag-value.test.js +86 -86
- package/test/cli-receive.test.js +390 -390
- package/test/cli-share.test.js +437 -437
- package/test/client-share.test.js +225 -225
- package/test/client.test.js +4595 -4184
- package/test/clustering.test.js +100 -100
- package/test/commands.test.js +106 -106
- package/test/config-keys-routes.test.js +233 -233
- package/test/config.test.js +153 -153
- package/test/conflict-freeze.test.js +344 -344
- package/test/conflict-ledger-enforce.test.js +452 -0
- package/test/conflict-ledger.test.js +242 -0
- package/test/conflict-reviewed.test.js +79 -79
- package/test/content-hash.test.js +204 -204
- package/test/continuity.test.js +452 -452
- package/test/contrast.test.js +432 -320
- package/test/date-hint.test.js +156 -0
- package/test/dedupe-candidate-window.test.js +180 -180
- package/test/dependency-overrides.test.js +78 -78
- package/test/diary-library.test.js +187 -187
- package/test/diary.test.js +576 -576
- package/test/differentiate-feedback.test.js +248 -248
- package/test/distill-tx-embed-gap.test.js +110 -110
- package/test/docs-config-keys.test.js +65 -65
- package/test/document-dir.test.js +233 -233
- package/test/document.test.js +703 -703
- package/test/dream-archive-guardrail.test.js +116 -116
- package/test/dream-baseline-clamp.test.js +174 -0
- package/test/dream-candidate-hybrid.test.js +281 -281
- package/test/dream-coverage-degrade.test.js +86 -86
- package/test/dream-decision-evidence.test.js +314 -314
- package/test/dream-failure-backoff.test.js +173 -173
- package/test/dream-fence.test.js +207 -207
- package/test/dream-maxtokens-fallback.test.js +132 -132
- package/test/dream-merge-guardrail.test.js +219 -219
- package/test/dream-peak-hours.test.js +194 -194
- package/test/dream.test.js +1528 -1528
- package/test/dsh-go-host.test.js +134 -134
- package/test/dsh-go-panel-actions.test.js +854 -854
- package/test/dsh-go-panel.test.js +251 -251
- package/test/embed-ready-poll.test.js +94 -94
- package/test/embed-text-reasons.test.js +112 -112
- package/test/embedding-cache-f32.test.js +276 -276
- package/test/embedding-ready.test.js +226 -226
- package/test/entities.test.js +711 -711
- package/test/entity-recall.test.js +179 -179
- package/test/epistemic.test.js +325 -325
- package/test/failure-query.test.js +147 -147
- package/test/failure-retention.test.js +105 -105
- package/test/fnew-0112.test.js +311 -311
- package/test/fnew-03.test.js +422 -422
- package/test/forget-corrections.test.js +70 -70
- package/test/graph-anchoring.test.js +184 -184
- package/test/graph-api.test.js +333 -209
- package/test/graph-boosted-relations.test.js +189 -189
- package/test/graph-inject-budget.test.js +103 -103
- package/test/graph-multipath.test.js +269 -269
- package/test/graph-passive-confirm.test.js +91 -91
- package/test/graph-weight-evolution.test.js +104 -104
- package/test/heat.test.js +175 -175
- package/test/helpers/dream-mock.js +86 -86
- package/test/helpers/peer-worker.mjs +25 -25
- package/test/helpers/runtime-source.js +60 -60
- package/test/helpers/tar-builder.js +80 -80
- package/test/helpers/write-admission-samples.js +312 -312
- package/test/hot-memory.test.js +259 -211
- package/test/image-description.test.js +271 -0
- package/test/image-memory.test.js +170 -170
- package/test/inject-content-cap.test.js +91 -91
- package/test/inject-first-round-bm25.test.js +89 -89
- package/test/inject-heat.test.js +77 -77
- package/test/inject-parent-gate.test.js +134 -106
- package/test/inject-pin-explicit.test.js +300 -300
- package/test/inject-pin-vector-crowd.test.js +225 -225
- package/test/inject-pools.test.js +195 -195
- package/test/inject-recall.test.js +172 -172
- package/test/inject-rotation.test.js +161 -161
- package/test/inject.test.js +553 -494
- package/test/issue-617-step1-query-and-fusion.test.js +361 -361
- package/test/kb-api-wiring.test.js +128 -128
- package/test/kb-collections.test.js +272 -272
- package/test/kb-routes.test.js +379 -379
- package/test/lang.test.js +98 -98
- package/test/lastrunat-persist.test.js +101 -101
- package/test/lib-smoke.test.js +116 -116
- package/test/llm-audit.test.js +815 -815
- package/test/llm-message-source.test.js +207 -207
- package/test/local-embedder.test.js +292 -292
- package/test/maintenance.test.js +501 -501
- package/test/mcp-stdio.test.js +385 -385
- package/test/mint-source.test.js +311 -311
- package/test/mirror-dirty.test.js +424 -424
- package/test/mirror-edit-digest.test.js +187 -187
- package/test/mirror-generation.test.js +499 -499
- package/test/mirror-types.test.js +208 -208
- package/test/mirror.test.js +249 -249
- package/test/narrative-bars.test.js +162 -162
- package/test/organize-tool.test.js +232 -232
- package/test/organize.test.js +418 -418
- package/test/panel-chart-scale.test.js +90 -0
- package/test/panel-tokens.test.js +245 -0
- package/test/peak-hours-observability.test.js +70 -70
- package/test/peer-blockers.test.js +193 -193
- package/test/persona-addressing.test.js +83 -83
- package/test/persona-api.test.js +172 -172
- package/test/persona-by-session.test.js +568 -568
- package/test/persona-flag.test.js +36 -36
- package/test/persona-inject.test.js +145 -145
- package/test/persona-settings.test.js +198 -198
- package/test/pipeline-activities.test.js +155 -155
- package/test/pipeline-attribution.test.js +175 -175
- package/test/pipeline-command.test.js +243 -243
- package/test/pipeline-confirm.test.js +148 -148
- package/test/pipeline-exec.test.js +172 -172
- package/test/pipeline-nudge-auto.test.js +248 -248
- package/test/pipeline-nudge.test.js +1278 -1278
- package/test/pipeline-observations.test.js +157 -157
- package/test/pipeline-observe.test.js +127 -127
- package/test/pipeline-r1r2.test.js +278 -278
- package/test/pipeline-runner.test.js +468 -468
- package/test/pipeline-runs.test.js +767 -767
- package/test/pipeline.test.js +636 -636
- package/test/placement.test.js +36 -36
- package/test/policy-epoch.test.js +259 -259
- package/test/pre-inject-gate.test.js +444 -444
- package/test/profile-extract.test.js +269 -269
- package/test/profile-facts.test.js +492 -492
- package/test/prompt-stance.test.js +128 -128
- package/test/provenance-http.test.js +367 -367
- package/test/publish-gate.test.js +272 -272
- package/test/quality-backfill.test.js +290 -290
- package/test/quality-filter.test.js +295 -295
- package/test/readme-claims.test.js +113 -113
- package/test/reasoning-effort.test.js +752 -752
- package/test/recall-anti-update.test.js +82 -82
- package/test/recall-evals.test.js +253 -253
- package/test/recall-layer.test.js +326 -326
- package/test/recall-retention.test.js +128 -128
- package/test/recall-stats.test.js +274 -274
- package/test/receipt-chain.test.js +451 -451
- package/test/reclaim-http.test.js +209 -209
- package/test/reflection-update-gate.test.js +129 -129
- package/test/reflection.test.js +226 -226
- package/test/reindex-backfill.test.js +475 -475
- package/test/reindex-scheduler.test.js +369 -369
- package/test/release-docs.test.js +156 -136
- package/test/release-notes.test.js +265 -240
- package/test/release-workflow.test.js +93 -93
- package/test/reranker-single-logit.test.js +73 -73
- package/test/reranker.test.js +197 -197
- package/test/resident-status.test.js +83 -83
- package/test/route-policy.test.js +113 -113
- package/test/runtime-adopt.test.js +206 -206
- package/test/runtime-cli.test.js +89 -89
- package/test/runtime-closure.test.js +193 -193
- package/test/runtime-download.test.js +302 -302
- package/test/runtime-layout.test.js +163 -163
- package/test/runtime-loader.test.js +255 -255
- package/test/runtime-manifest.test.js +159 -159
- package/test/runtime-model-fetch.test.js +348 -348
- package/test/runtime-provision.test.js +101 -101
- package/test/runtime-tarball.test.js +81 -81
- package/test/runtime-verify.test.js +319 -319
- package/test/scope-candidates.test.js +491 -491
- package/test/scope-distill-stamp.test.js +134 -134
- package/test/scope-explicit.test.js +452 -452
- package/test/scope-inject-soft.test.js +106 -106
- package/test/scope-optional-service.test.js +110 -110
- package/test/scope-retrieval.test.js +197 -197
- package/test/scope-state.test.js +610 -610
- package/test/scope-storage.test.js +255 -255
- package/test/scope-strict.test.js +367 -367
- package/test/search-fusion.test.js +90 -90
- package/test/security-doc.test.js +188 -178
- package/test/semantic.test.js +124 -124
- package/test/sensitive-scan.test.js +251 -251
- package/test/serve-bin.test.js +121 -121
- package/test/serve.test.js +258 -258
- package/test/service-search.test.js +174 -174
- package/test/service.test.js +410 -410
- package/test/session-gate.test.js +264 -264
- package/test/session-usage.test.js +317 -317
- package/test/settings.test.js +273 -273
- package/test/share-foreign-rows.test.js +144 -144
- package/test/share-http.test.js +144 -144
- package/test/share-import.test.js +577 -577
- package/test/share-imported-guard.test.js +311 -311
- package/test/share-imported-identity.test.js +111 -111
- package/test/share-pack.test.js +511 -511
- package/test/share-receive-http.test.js +756 -756
- package/test/share-routes.test.js +337 -337
- package/test/share-store.test.js +133 -133
- package/test/share-validate.test.js +101 -101
- package/test/skip-invalid-restore.test.js +262 -262
- package/test/sleep-action-set.test.js +441 -441
- package/test/sleep-catchup.test.js +315 -315
- package/test/sleep-failure-backoff.test.js +156 -156
- package/test/sleep-heat.test.js +174 -174
- package/test/sleep-scheduler-rearm.test.js +89 -89
- package/test/sleep.test.js +1455 -1418
- package/test/standalone-api.test.js +1344 -1344
- package/test/store-vector-cache.test.js +98 -98
- package/test/store-write-path-columns.test.js +191 -191
- package/test/store.test.js +744 -744
- package/test/stress.test.js +209 -209
- package/test/summarize-occurred-at.test.js +127 -127
- package/test/summarize-parse-diagnostics.test.js +75 -75
- package/test/summarize-reasoning-effort.test.js +189 -189
- package/test/summarize.test.js +2251 -2251
- package/test/supersede-state-tracking.test.js +394 -394
- package/test/test-count-sync.test.js +71 -71
- package/test/tool-state-ignore.test.js +65 -65
- package/test/tools-dto-schema-matrix.test.js +398 -398
- package/test/tools-memory-get-schema.test.js +65 -65
- package/test/tools.test.js +585 -585
- package/test/updated-at-semantics.test.js +113 -113
- package/test/user-settings-preview.test.js +127 -127
- package/test/user-settings-segments.test.js +527 -527
- package/test/vector-index.test.js +334 -334
- package/test/version-check.test.js +152 -152
- package/test/webServer-optional.test.js +82 -82
- package/test/wiki-api.test.js +734 -627
- package/test/wiki-claims.test.js +194 -0
- package/test/wiki-cli-hint.test.js +118 -118
- package/test/wiki-inject.test.js +265 -265
- package/test/wiki-partition.test.js +112 -112
- package/test/wiki-plan.test.js +80 -80
- package/test/wiki-provenance.test.js +202 -0
- package/test/wiki-queries.test.js +398 -277
- package/test/wiki-scan.test.js +208 -208
- package/test/wiki-store.test.js +190 -190
- package/test/wiki-t0.test.js +456 -380
- package/test/wiki-t1-jobs.test.js +125 -125
- package/test/wiki-t1.test.js +460 -235
- package/test/wiki-tools.test.js +176 -176
- package/test/workflow-guards.test.js +155 -155
- package/test/write-admission.test.js +668 -668
package/docs/CONTINUITY.md
CHANGED
|
@@ -1,139 +1,139 @@
|
|
|
1
|
-
# dsh-mneme 压缩边缘抢救(issue #249 N3)
|
|
2
|
-
|
|
3
|
-
- **日期**:2026-09-24
|
|
4
|
-
- **状态**:✅ 已实现(opt-in,默认关)
|
|
5
|
-
- **范围**:上下文即将被宿主压缩前,抢救「正在做什么」,让它活过这次压缩
|
|
6
|
-
- **相关文档**:[存储与回收](STORAGE.md)(同批的 #275 第一批) · [语义增强](SEMANTIC.md)
|
|
7
|
-
|
|
8
|
-
## 1. 问题
|
|
9
|
-
|
|
10
|
-
宿主的压缩摘要器只看对话里的内容:压缩时它按固定字段模板重建对话(Current Work /
|
|
11
|
-
Next Step / Critical Context 等),**系统提示段里的东西不进这次重建**。所以任何"只放在
|
|
12
|
-
提示段里的工作状态",一过压缩就等于没写过。
|
|
13
|
-
|
|
14
|
-
## 2. 形态:必须双落点
|
|
15
|
-
|
|
16
|
-
| 落点 | 去处 | 为什么不能省 |
|
|
17
|
-
|---|---|---|
|
|
18
|
-
| ① 落提案 | `continuity_proposals` 表(`src/store.js`) | 脱离对话独立存活;注入失败/被跳过也不丢工作状态 |
|
|
19
|
-
| ② 追加消息 | 序列末尾一条 `user/message`(`source: {kind: "plugin", plugin: "dsh-mneme"}`) | 这是唯一能进宿主摘要器重建范围的落点 |
|
|
20
|
-
|
|
21
|
-
落库先于注入。落点顺序由宿主契约保证:压缩插件在自己那一步先压缩、再 `return next()`,
|
|
22
|
-
所以我们在 `agent/pre-step` 拿到 `next()` 结果时压缩事件已落库;而我们返回的
|
|
23
|
-
`decision.messages` 由宿主在本步末尾以 `surfaceOp: "append"` 追加,晚于压缩的
|
|
24
|
-
`surfaceOp: "replace"`——追加物天然在压缩之后、靠近序列末尾。
|
|
25
|
-
|
|
26
|
-
注入文本是**结构化快照**(统一前缀 + 三行固定字段,整条 ≤900 字符),不是 §6.3 那种
|
|
27
|
-
≤160B 的单行提醒——那条上限约束的是"一句话提醒",不约束固定字段的快照;字段内部的换行
|
|
28
|
-
仍会被压平成空格,保证它仍是一条消息。**判重按当前表面**(`session.surface.nodes`),
|
|
29
|
-
不按全量日志:被一次压缩折叠出表面的旧快照还在 append-only 日志里,照日志判重会让这次
|
|
30
|
-
该补的注入静默跳过。
|
|
31
|
-
|
|
32
|
-
## 3. 触发
|
|
33
|
-
|
|
34
|
-
**不自定阈值**,就是订阅宿主真的压缩(都在宿主的事件白名单里)。理由:「压缩边缘」由宿主
|
|
35
|
-
定义,我们再校准一份阈值参数只会与之漂移,还多一份没人维护的旋钮。
|
|
36
|
-
|
|
37
|
-
**但「发过压缩事件」不等于「这段历史真的被折叠了」**:宿主的压缩插件在**每一步**都会试一次
|
|
38
|
-
(`agent/pre-step` 里的 `compactIfNeeded`),而代理层(如 billion-context)会拒掉原生压缩。
|
|
39
|
-
一次失败的尝试什么都没折叠,不需要抢救 —— 按「试过就救」记账,触发器就退化成「每步一次」。
|
|
40
|
-
所以只认**内容真的被移除过**的三种事件(判定在 `src/continuity.js` 的 `isCompactionEdge`):
|
|
41
|
-
|
|
42
|
-
| 事件 | 算不算边缘 | 为什么 |
|
|
43
|
-
|---|---|---|
|
|
44
|
-
| `compaction/summary` | ✅ | 宿主压缩成功才落(`dsh-compaction-basic` 的 `commitCompactionBody`) |
|
|
45
|
-
| `compaction/prune` | ✅ | 宿主把超预算的旧 tool/result 折叠出表面 —— 「表面真的变短了」最直接的证据 |
|
|
46
|
-
| `compaction/end` **不带 error** | ✅ | 成功路的收尾 |
|
|
47
|
-
| `compaction/end` **带 error** | ❌ | 成败两条路都发这个事件,失败路额外带 `error`;整笔事务失败 |
|
|
48
|
-
| `compaction/start` | ❌ | 只是开锁标记(「有人试过」) |
|
|
49
|
-
|
|
50
|
-
本机实测(2026-10-14,两个长会话、12,000+ 事件,原生压缩被 100% 拒绝):按 `start|summary|end`
|
|
51
|
-
记账置位 1,287 / 2,895 次,改成「真落地」后降到 39 / 161 次。
|
|
52
|
-
|
|
53
|
-
DSH 没有 in-memory 消息改写钩子,所以本机制一律是「注入 + 序号引用寻址」,**不改写
|
|
54
|
-
历史消息本体**。
|
|
55
|
-
|
|
56
|
-
## 4. 字段与抽取口径
|
|
57
|
-
|
|
58
|
-
固定三字段(不用自由散文),全程不调模型、纯确定性抽取(`src/continuity.js`):
|
|
59
|
-
|
|
60
|
-
| 字段 | 来源 | 截断 |
|
|
61
|
-
|---|---|---|
|
|
62
|
-
| `current_work` | 最近一条**真实** `user/message`(插件注入与子代理上报不算用户指令) | 头部 200 字符 |
|
|
63
|
-
| `next_step` | 最近一条 `assistant/message` | **尾部** 200 字符(下一步活在末尾那句里) |
|
|
64
|
-
| `open_questions` | 恒 `null` | —— |
|
|
65
|
-
|
|
66
|
-
「哪些问题还没解决」判不出就是判不出,硬猜会给出似是而非的字段;空字段在注入文本里
|
|
67
|
-
如实标 `(none)`。这个字段留给转正通道与人工补。
|
|
68
|
-
|
|
69
|
-
字段名以 #249 §6.2 为准(`current_work` / `next_step` / `open_questions`)。§4.4 里的
|
|
70
|
-
Current Work / Next Step / Critical Context 是**宿主压缩模板**的字段名,不是这张表的列名
|
|
71
|
-
(规格里两处用词不同,实现取 §6.2)。
|
|
72
|
-
|
|
73
|
-
## 5. 存储与生命周期
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
continuity_proposals(id, session_id, kind, current_work, next_step, open_questions,
|
|
77
|
-
status, edge_seq, created_at, updated_at)
|
|
78
|
-
UNIQUE (session_id, kind) -- 「同一会话同一类只留一条」:再次触发是刷新,不是新增
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
- `kind`:`compaction-edge`(一次会话里这一类只留一条)。
|
|
82
|
-
- `status`:`pending`(本批唯一写入态)→ 未来 `promoted` / `discarded`(转正通道与
|
|
83
|
-
#254 的二次确认共用一套,阶段二才打开)。
|
|
84
|
-
- **队列满则弃新**(`MAX_CONTINUITY_PENDING = 200`):达上限丢掉本次触发,而不是淘汰
|
|
85
|
-
旧行——旧行是别的会话还没转正的工作状态,用「更近的边缘」把它挤掉是反的。满队列
|
|
86
|
-
不影响已有行的刷新。
|
|
87
|
-
- 丢弃会**留痕**(`agent/pre-step` 监听器 `logger.warn`):弃新属于"静默失效",不报出来
|
|
88
|
-
的话 §8 的触发率口径会把它算成"没触发"。
|
|
89
|
-
- **本批没有回收路径**:`status` 只写 `pending`,`maintenance`/`reclaim` 不碰这张表,
|
|
90
|
-
所以 200 是上限——满了之后新会话不再落行,直到转正通道打开(阶段二)。判定是进程内的
|
|
91
|
-
(先查计数再写),两个宿主共用同一 `memoryDir` 时可能各自都看到未满,实际越过 200 条。
|
|
92
|
-
- `edge_seq` 记最近一次触发的压缩事件序号,是「实际触发率」的证据。
|
|
93
|
-
- 落库失败只告警、不抛:可选插件的故障不该把宿主的这一步变成失败,而注入那一半不依赖
|
|
94
|
-
库,照做。
|
|
95
|
-
|
|
96
|
-
指标口径(#249 §8 要求触发率/采纳率可统计):实际触发率 = 提案行数;采纳率 =
|
|
97
|
-
`promoted` / 全部。两者都是就地读表,不需要额外打点。
|
|
98
|
-
|
|
99
|
-
## 6. 开关
|
|
100
|
-
|
|
101
|
-
| 层级 | 键 | 默认 |
|
|
102
|
-
|---|---|---|
|
|
103
|
-
| 父 | `autoInject` | 开(既有总闸) |
|
|
104
|
-
| 子 | `continuityRescueEnabled` | **关**(引入新注入表面,按 #249 §10 判据独立成键) |
|
|
105
|
-
|
|
106
|
-
父关则子不生效(`injectChildEnabled`);轻量档默认置关(`applyLightModePreset`
|
|
107
|
-
把它算进 `LIGHT_MODE_OFF`),但那只是默认值——装配时按「用户开关 > 轻量预设 >
|
|
108
|
-
bundle 配置」合并,用户在面板里显式勾选仍然赢。面板落点在 `lib/client.js`
|
|
109
|
-
的 `FEATURE_CHILDREN` / `FEATURE_GROUPS`(该文件无 src 对应物),跨文件关系由
|
|
110
|
-
`test/inject-parent-gate.test.js` 逐个断言钉住。
|
|
111
|
-
|
|
112
|
-
## 7. 降级路径(不要求宿主加接口)
|
|
113
|
-
|
|
114
|
-
宿主若不提供可挂钩的压缩前时机,双落点里的 ② 就没有触发者。这时**不算失败**:把规则
|
|
115
|
-
写成持久规则交给 agent 自判(`src/guide.js` 的 `CONTINUITY_TOOL_RULE`,挂在
|
|
116
|
-
`memory_save` 的工具描述尾部——常驻文本、零注入成本,只在子开关开启时出现)。
|
|
117
|
-
|
|
118
|
-
本批**不做宿主能力探测**(没有可靠的探测口,宿主也没有暴露"有没有压缩前时机"这个事实),
|
|
119
|
-
所以子开关打开时这条规则就常驻,与 ② 并存——两者不是互斥的备选,而是同一个开关下的两层:
|
|
120
|
-
② 在宿主真的压缩时自动生效,持久规则在 agent 自己判断"上下文要炸了"时兜底。
|
|
121
|
-
|
|
122
|
-
## 8. 已知坑
|
|
123
|
-
|
|
124
|
-
- **判重只能做到「同一份文本不追加第二次」**。没有改写钩子,就不能删掉表面里已经存在
|
|
125
|
-
的那条旧快照;内容一变就是新的一份(旧的那份随宿主压缩自然消失)。这是形态上限,
|
|
126
|
-
不是实现偷懒。
|
|
127
|
-
- **注入物不得变成记忆**:追加消息用 `source.kind = "plugin"`,`summarize.js` 的
|
|
128
|
-
`collectMessages` 会跳过它——否则注入物会被下一轮蒸馏成记忆,形成自我强化。
|
|
129
|
-
- **`open_questions` 恒 null** 是刻意留白,不是没实现。
|
|
130
|
-
|
|
131
|
-
## 9. 验收锚点
|
|
132
|
-
|
|
133
|
-
`test/continuity.test.js` 逐条锁形态(不是锁文案):抽取口径(头/尾方向、插件消息跳过、
|
|
134
|
-
插件消息是最后一条 `user/message` 时仍被跳过)、渲染(统一前缀、单行、`none`、整条上限)、
|
|
135
|
-
唯一键刷新(`created_at` 不动、幂等 UPSERT)、队列满弃新且不影响刷新、丢弃留痕、
|
|
136
|
-
pre-step 双落点与一次性消费、同文本不重复追加(按当前表面)、被折叠出表面的旧注入要补、
|
|
137
|
-
落库失败不打断宿主的一步、`reject` 放行且不消费边缘、缺 session 不抛、dispose 后不再动作、
|
|
138
|
-
默认关 + 父关不生效 + 轻量档压掉 + 降级规则只在开启时进描述、门控不调模型(静态锁)、
|
|
139
|
-
存量库重开即建表。
|
|
1
|
+
# dsh-mneme 压缩边缘抢救(issue #249 N3)
|
|
2
|
+
|
|
3
|
+
- **日期**:2026-09-24
|
|
4
|
+
- **状态**:✅ 已实现(opt-in,默认关)
|
|
5
|
+
- **范围**:上下文即将被宿主压缩前,抢救「正在做什么」,让它活过这次压缩
|
|
6
|
+
- **相关文档**:[存储与回收](STORAGE.md)(同批的 #275 第一批) · [语义增强](SEMANTIC.md)
|
|
7
|
+
|
|
8
|
+
## 1. 问题
|
|
9
|
+
|
|
10
|
+
宿主的压缩摘要器只看对话里的内容:压缩时它按固定字段模板重建对话(Current Work /
|
|
11
|
+
Next Step / Critical Context 等),**系统提示段里的东西不进这次重建**。所以任何"只放在
|
|
12
|
+
提示段里的工作状态",一过压缩就等于没写过。
|
|
13
|
+
|
|
14
|
+
## 2. 形态:必须双落点
|
|
15
|
+
|
|
16
|
+
| 落点 | 去处 | 为什么不能省 |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| ① 落提案 | `continuity_proposals` 表(`src/store.js`) | 脱离对话独立存活;注入失败/被跳过也不丢工作状态 |
|
|
19
|
+
| ② 追加消息 | 序列末尾一条 `user/message`(`source: {kind: "plugin", plugin: "dsh-mneme"}`) | 这是唯一能进宿主摘要器重建范围的落点 |
|
|
20
|
+
|
|
21
|
+
落库先于注入。落点顺序由宿主契约保证:压缩插件在自己那一步先压缩、再 `return next()`,
|
|
22
|
+
所以我们在 `agent/pre-step` 拿到 `next()` 结果时压缩事件已落库;而我们返回的
|
|
23
|
+
`decision.messages` 由宿主在本步末尾以 `surfaceOp: "append"` 追加,晚于压缩的
|
|
24
|
+
`surfaceOp: "replace"`——追加物天然在压缩之后、靠近序列末尾。
|
|
25
|
+
|
|
26
|
+
注入文本是**结构化快照**(统一前缀 + 三行固定字段,整条 ≤900 字符),不是 §6.3 那种
|
|
27
|
+
≤160B 的单行提醒——那条上限约束的是"一句话提醒",不约束固定字段的快照;字段内部的换行
|
|
28
|
+
仍会被压平成空格,保证它仍是一条消息。**判重按当前表面**(`session.surface.nodes`),
|
|
29
|
+
不按全量日志:被一次压缩折叠出表面的旧快照还在 append-only 日志里,照日志判重会让这次
|
|
30
|
+
该补的注入静默跳过。
|
|
31
|
+
|
|
32
|
+
## 3. 触发
|
|
33
|
+
|
|
34
|
+
**不自定阈值**,就是订阅宿主真的压缩(都在宿主的事件白名单里)。理由:「压缩边缘」由宿主
|
|
35
|
+
定义,我们再校准一份阈值参数只会与之漂移,还多一份没人维护的旋钮。
|
|
36
|
+
|
|
37
|
+
**但「发过压缩事件」不等于「这段历史真的被折叠了」**:宿主的压缩插件在**每一步**都会试一次
|
|
38
|
+
(`agent/pre-step` 里的 `compactIfNeeded`),而代理层(如 billion-context)会拒掉原生压缩。
|
|
39
|
+
一次失败的尝试什么都没折叠,不需要抢救 —— 按「试过就救」记账,触发器就退化成「每步一次」。
|
|
40
|
+
所以只认**内容真的被移除过**的三种事件(判定在 `src/continuity.js` 的 `isCompactionEdge`):
|
|
41
|
+
|
|
42
|
+
| 事件 | 算不算边缘 | 为什么 |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `compaction/summary` | ✅ | 宿主压缩成功才落(`dsh-compaction-basic` 的 `commitCompactionBody`) |
|
|
45
|
+
| `compaction/prune` | ✅ | 宿主把超预算的旧 tool/result 折叠出表面 —— 「表面真的变短了」最直接的证据 |
|
|
46
|
+
| `compaction/end` **不带 error** | ✅ | 成功路的收尾 |
|
|
47
|
+
| `compaction/end` **带 error** | ❌ | 成败两条路都发这个事件,失败路额外带 `error`;整笔事务失败 |
|
|
48
|
+
| `compaction/start` | ❌ | 只是开锁标记(「有人试过」) |
|
|
49
|
+
|
|
50
|
+
本机实测(2026-10-14,两个长会话、12,000+ 事件,原生压缩被 100% 拒绝):按 `start|summary|end`
|
|
51
|
+
记账置位 1,287 / 2,895 次,改成「真落地」后降到 39 / 161 次。
|
|
52
|
+
|
|
53
|
+
DSH 没有 in-memory 消息改写钩子,所以本机制一律是「注入 + 序号引用寻址」,**不改写
|
|
54
|
+
历史消息本体**。
|
|
55
|
+
|
|
56
|
+
## 4. 字段与抽取口径
|
|
57
|
+
|
|
58
|
+
固定三字段(不用自由散文),全程不调模型、纯确定性抽取(`src/continuity.js`):
|
|
59
|
+
|
|
60
|
+
| 字段 | 来源 | 截断 |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `current_work` | 最近一条**真实** `user/message`(插件注入与子代理上报不算用户指令) | 头部 200 字符 |
|
|
63
|
+
| `next_step` | 最近一条 `assistant/message` | **尾部** 200 字符(下一步活在末尾那句里) |
|
|
64
|
+
| `open_questions` | 恒 `null` | —— |
|
|
65
|
+
|
|
66
|
+
「哪些问题还没解决」判不出就是判不出,硬猜会给出似是而非的字段;空字段在注入文本里
|
|
67
|
+
如实标 `(none)`。这个字段留给转正通道与人工补。
|
|
68
|
+
|
|
69
|
+
字段名以 #249 §6.2 为准(`current_work` / `next_step` / `open_questions`)。§4.4 里的
|
|
70
|
+
Current Work / Next Step / Critical Context 是**宿主压缩模板**的字段名,不是这张表的列名
|
|
71
|
+
(规格里两处用词不同,实现取 §6.2)。
|
|
72
|
+
|
|
73
|
+
## 5. 存储与生命周期
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
continuity_proposals(id, session_id, kind, current_work, next_step, open_questions,
|
|
77
|
+
status, edge_seq, created_at, updated_at)
|
|
78
|
+
UNIQUE (session_id, kind) -- 「同一会话同一类只留一条」:再次触发是刷新,不是新增
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- `kind`:`compaction-edge`(一次会话里这一类只留一条)。
|
|
82
|
+
- `status`:`pending`(本批唯一写入态)→ 未来 `promoted` / `discarded`(转正通道与
|
|
83
|
+
#254 的二次确认共用一套,阶段二才打开)。
|
|
84
|
+
- **队列满则弃新**(`MAX_CONTINUITY_PENDING = 200`):达上限丢掉本次触发,而不是淘汰
|
|
85
|
+
旧行——旧行是别的会话还没转正的工作状态,用「更近的边缘」把它挤掉是反的。满队列
|
|
86
|
+
不影响已有行的刷新。
|
|
87
|
+
- 丢弃会**留痕**(`agent/pre-step` 监听器 `logger.warn`):弃新属于"静默失效",不报出来
|
|
88
|
+
的话 §8 的触发率口径会把它算成"没触发"。
|
|
89
|
+
- **本批没有回收路径**:`status` 只写 `pending`,`maintenance`/`reclaim` 不碰这张表,
|
|
90
|
+
所以 200 是上限——满了之后新会话不再落行,直到转正通道打开(阶段二)。判定是进程内的
|
|
91
|
+
(先查计数再写),两个宿主共用同一 `memoryDir` 时可能各自都看到未满,实际越过 200 条。
|
|
92
|
+
- `edge_seq` 记最近一次触发的压缩事件序号,是「实际触发率」的证据。
|
|
93
|
+
- 落库失败只告警、不抛:可选插件的故障不该把宿主的这一步变成失败,而注入那一半不依赖
|
|
94
|
+
库,照做。
|
|
95
|
+
|
|
96
|
+
指标口径(#249 §8 要求触发率/采纳率可统计):实际触发率 = 提案行数;采纳率 =
|
|
97
|
+
`promoted` / 全部。两者都是就地读表,不需要额外打点。
|
|
98
|
+
|
|
99
|
+
## 6. 开关
|
|
100
|
+
|
|
101
|
+
| 层级 | 键 | 默认 |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| 父 | `autoInject` | 开(既有总闸) |
|
|
104
|
+
| 子 | `continuityRescueEnabled` | **关**(引入新注入表面,按 #249 §10 判据独立成键) |
|
|
105
|
+
|
|
106
|
+
父关则子不生效(`injectChildEnabled`);轻量档默认置关(`applyLightModePreset`
|
|
107
|
+
把它算进 `LIGHT_MODE_OFF`),但那只是默认值——装配时按「用户开关 > 轻量预设 >
|
|
108
|
+
bundle 配置」合并,用户在面板里显式勾选仍然赢。面板落点在 `lib/client.js`
|
|
109
|
+
的 `FEATURE_CHILDREN` / `FEATURE_GROUPS`(该文件无 src 对应物),跨文件关系由
|
|
110
|
+
`test/inject-parent-gate.test.js` 逐个断言钉住。
|
|
111
|
+
|
|
112
|
+
## 7. 降级路径(不要求宿主加接口)
|
|
113
|
+
|
|
114
|
+
宿主若不提供可挂钩的压缩前时机,双落点里的 ② 就没有触发者。这时**不算失败**:把规则
|
|
115
|
+
写成持久规则交给 agent 自判(`src/guide.js` 的 `CONTINUITY_TOOL_RULE`,挂在
|
|
116
|
+
`memory_save` 的工具描述尾部——常驻文本、零注入成本,只在子开关开启时出现)。
|
|
117
|
+
|
|
118
|
+
本批**不做宿主能力探测**(没有可靠的探测口,宿主也没有暴露"有没有压缩前时机"这个事实),
|
|
119
|
+
所以子开关打开时这条规则就常驻,与 ② 并存——两者不是互斥的备选,而是同一个开关下的两层:
|
|
120
|
+
② 在宿主真的压缩时自动生效,持久规则在 agent 自己判断"上下文要炸了"时兜底。
|
|
121
|
+
|
|
122
|
+
## 8. 已知坑
|
|
123
|
+
|
|
124
|
+
- **判重只能做到「同一份文本不追加第二次」**。没有改写钩子,就不能删掉表面里已经存在
|
|
125
|
+
的那条旧快照;内容一变就是新的一份(旧的那份随宿主压缩自然消失)。这是形态上限,
|
|
126
|
+
不是实现偷懒。
|
|
127
|
+
- **注入物不得变成记忆**:追加消息用 `source.kind = "plugin"`,`summarize.js` 的
|
|
128
|
+
`collectMessages` 会跳过它——否则注入物会被下一轮蒸馏成记忆,形成自我强化。
|
|
129
|
+
- **`open_questions` 恒 null** 是刻意留白,不是没实现。
|
|
130
|
+
|
|
131
|
+
## 9. 验收锚点
|
|
132
|
+
|
|
133
|
+
`test/continuity.test.js` 逐条锁形态(不是锁文案):抽取口径(头/尾方向、插件消息跳过、
|
|
134
|
+
插件消息是最后一条 `user/message` 时仍被跳过)、渲染(统一前缀、单行、`none`、整条上限)、
|
|
135
|
+
唯一键刷新(`created_at` 不动、幂等 UPSERT)、队列满弃新且不影响刷新、丢弃留痕、
|
|
136
|
+
pre-step 双落点与一次性消费、同文本不重复追加(按当前表面)、被折叠出表面的旧注入要补、
|
|
137
|
+
落库失败不打断宿主的一步、`reject` 放行且不消费边缘、缺 session 不抛、dispose 后不再动作、
|
|
138
|
+
默认关 + 父关不生效 + 轻量档压掉 + 降级规则只在开启时进描述、门控不调模型(静态锁)、
|
|
139
|
+
存量库重开即建表。
|
package/docs/DAEMON.md
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
# dsh-mneme 独立服务(daemon)
|
|
2
|
-
|
|
3
|
-
`dsh-mneme-serve`:在 DSH 宿主之外把 mneme 跑成一个常驻数据面。#363(Mneme Bridge)确立的方向——第三方集成需要长期挂载,而 DSH 不必一直开着;这是官方推荐姿势,lib 直挂的 embedded 模式降级为无网兜底。
|
|
4
|
-
|
|
5
|
-
## 1. 职责边界
|
|
6
|
-
|
|
7
|
-
daemon 是**数据面**,不是第二个宿主:
|
|
8
|
-
|
|
9
|
-
- **有**:存储(SQLite)、检索(关键词 + BM25 + 向量,`/search` 统一召回,与宿主共用 `src/semantic.js` 同一套装配)、注入候选(`/context`,issue #370,与宿主注入管线同一份 `injectCandidates`)、镜像同步与人改合并、`/maintenance/reclaim`、`/share`(记忆分享包,纯读,见 [SHARE.md](SHARE.md))、`/receive` 与 `/receive/undo`(吃包入库与整包退出,车道 C;写的是**本机自己的库**,与 `/share` 同一条 4 MiB 入站上限)、`/bootstrap`、recall_runs 检索/注入回执。
|
|
10
|
-
- **没有(第一期,无 LLM)**:巩固(autoDream)、蒸馏(autoSummarize)、实体抽取、sleep、注入/工具/面板路由。前两者是**结构性缺失**而非开关——daemon 装配里没有 LLM 句柄,巩固只属于 DSH 宿主进程。这就是 daemon 与宿主「单写者」的机械保证(AGENTS.md externalApi/autoDream 单侧纪律的 daemon 版),不依赖用户自觉。
|
|
11
|
-
- **收包在 daemon 上付的是什么**:一个事务里逐条先查 `share_external_id` 再 `store.save`,嵌入随最外层 COMMIT 排空(`--embed local` 时真打向量,`off` 时只落结构),镜像重渲染照 daemon 自己那条回灌路走。**实体一个都不建**——不是 daemon 缺 LLM 才不建,车道 C 对外来行本来就不做抽取(有向量、无实体,实体与图检索看不见它们),宿主侧同样如此。成本的量级读数见 [SHARE.md](SHARE.md)「收侧」那一节实测。
|
|
12
|
-
|
|
13
|
-
与宿主装配(`src/index.js` apply)的关系:`src/serve.js` 只搬数据面那一半,每步注释锚定 index.js 来源行号;刻意不抽公共装配函数(apply 其余环节与宿主 ctx 纠缠,防御段纪律「最后动或不动」)。装配漂移风险由 `test/serve-bin.test.js` 的多进程共存用例兜底(两进程真开同一个库互写互读)。
|
|
14
|
-
|
|
15
|
-
## 2. 对外接口
|
|
16
|
-
|
|
17
|
-
路由面 = `src/api-standalone.js` 全表(health/status/profile/rules/memories 读写/`/memory/provenance`(记忆级 / 会话级溯源读出口,#421+#524)/search/context/share/receive(含 `/receive/undo`)/maintenance/bootstrap),鉴权同源(Bearer + timingSafeEqual,`GET /health` 免鉴权)。daemon 自身零新路由;#370 的 `/context` 落在 api-standalone 工厂里,宿主外部访问与 daemon 自动同享(参数、scope 语义与 recall_runs 注入分账见包 README 路由表)。daemon 侧唯一自有选项是 `strictPort`(见 §4)。
|
|
18
|
-
|
|
19
|
-
`/memory/provenance` 的开关门(#509 评审整改):这个面返回蒸馏窗口的**逐条会话原文**,所以它吃 `distillRecords.enabled`——与写侧 `src/summarize.js:988` 同一枚开关、同一个判据表达式(读侧唯一一份在 `src/provenance-http.js` 的 `isDistillRecordsEnabled`)。关着时回 `409 {"error":"distill-records-disabled"}`,不是 404(本端点刻意不就「这条记忆是否存在」作断言:未知 id 是 200 + 空 windows),也不是 503(那是「装配没接线」,`src/index.js:589-591` 立的可区分性原则)。状态码阶梯:`401` 无 token → `400` 缺参(`missing-id` / `ambiguous-id` / `invalid-limit`) → `409` 功能关了 → `503` 装配没接线(按方向判) → `200`。
|
|
20
|
-
|
|
21
|
-
两个读方向共用同一条路径(#524 补上方向 2):`?id=<memoryId>` 是「这条记忆派生自哪些窗口」,`?sessionId=<sid>` 是「这个会话蒸出了哪些窗口」;两个主键**互斥**,都缺与都给都回 400(择一等于让调用方发一个自己也不知道会读哪个主键的请求,而两边的结果形状不同)。方向 2 必须带 `limit`(默认 20、上限 100)——按会话读是这张脸里天然最容易放大的方向,一个会话几十个窗口、每个窗口都是整段逐字原文,不限量就是「按会话导出全量转录」,与 `/export` 同量级只是换了形状;撞上限时答复带 `truncated: true`,少了这个读数,被截断的答复与「本来就这么少」逐字节相同。方向 2 的窗口按 `(session_id, seq_start, seq_end)` 合并成一行 `GROUP BY`,带 `link_count`——一条蒸馏窗口通常产出多条记忆,逐链接返回会让「这个会话蒸了几次」被重复行淹没。daemon 读的是**面板持久化的开关**(`serve.js` 把 `feature_flags` 里的 `distillRecords.enabled` 展开进 cfg,与宿主 `index.js:217-233` 同款),与宿主共用同一个 memory.db、同一份 kv——所以用户在面板里开着,daemon 这一面就读得到。
|
|
22
|
-
|
|
23
|
-
`/memory/provenance` 的响应形状(#512):窗口在 `session_id/seq_start/seq_end/created_at/records` 之外另带 `distill_run_id / run_type / trigger_source / run_status`(读不到整轮归因时整组 `null`,不从区间或时间戳反推),答复级再带 `mints[]`(行级归因:这条记忆出生自哪一轮 dream/sleep)。归因元数据不受 `distillRecords.enabled` 约束——它不含任何会话正文,所以开关关着时这个端点照旧 409,但库里那两张表仍在记账。
|
|
24
|
-
|
|
25
|
-
残留不对称要知道:daemon 结构上看不到宿主的 **bundle config**(第一期不吃宿主 config schema),所以「只写在部署侧 bundle 配置里打开、从没在面板点过」的用户,宿主认、daemon 不认——daemon 会对每个请求回 409。这不是故障,是 daemon 装配面的已知边界;要让 daemon 也认,去面板里把开关显式打开一次(面板的「待重启」提示同样适用:开关是启动快照,改完要重启才生效)。
|
|
26
|
-
|
|
27
|
-
`/context` 的档位信号(#383):响应多一个 `tier`(`full` 语义档 / `degraded` 规则档 / `unknown` 语义路未启用或判不出来,fail-closed),**具体降级原因只在 stderr**——`dsh-mneme: /context degraded to the rule tier (<reason>)`,不进响应体。原因是给运维的读数,六值互不吞并(成例「修法不同就分开」):`embed-unavailable` 无可用接口(embedder 对象在、缺 `embedSingle`/`embed`,修适配器)/ `embed-empty` 空向量 / `embed-timeout` 挂起 / `embed-error` 抛错 / `embed-dimension` 维度不符(有向量但没有一条与查询同维,修法是重建索引)/ `no-embedder` 压根没装配 embedder(`--embed off` / lightMode / 宿主未装配,**预期态不是故障**,修法是把嵌装扮上或开起来)。`tier` 是给调用方的读数,两套消费者分开;六值的唯一真源是 `src/api-standalone.js` 的 `CONTEXT_DEGRADE_REASONS`,契约测试从它派生。`unknown` 之下(维度探针没跑成 / 有行却一条向量都读不出来)另有一行 `dsh-mneme: /context tier left unknown: <what>`,**不是**那六值的一员(`tier` 不是 degraded,没有降级原因可记),运维程序不要按原因枚举解析它——没有它,调用方对 unknown 的策略是「不告警」时,一次真实的判档故障会整个消失。`no-embedder` 不并进 `embed-unavailable` 是故意的:那两者共用「语义路没通」的结果,但一个是适配器坏了(异常)、一个是语义路没开(设计内常态),并成一个值会让按 `embed-unavailable` 告警的面板对每个轻量模式安装报警;用词则与宿主面 `/api/dsh-mneme/semantic` 的 `reason` 对齐(那边是另一套枚举、另一个消费者,别顺手统一)。这里最值得盯的是 `embed-dimension`:嵌入接口一切正常,但库里是旧维度向量,`searchVector` 直接跳过、不抛错,召回静默退回关键词档——修法是重建索引,不是查端点。判档有成本:`q` 非空且装了 embedder 时一次 `/context` 会真起一次查询嵌入(一次往返 + `embedTimeoutMs` 窗口),维度探针本身是**按匹配短路的存在性判据**(有没有一条活跃向量与查询同维,不是 `LIMIT 1` 读一行——混合维度库里那会抽错维误报 degraded、首条损坏又会漏报 full):一次无 `LIMIT` 的全 id 扫描 + 短路解析,同维度健康库只解析 1 个向量,只有要报 degraded 时才走完全表;不复用 `/health`(它只回 `{ok:true}`)也不做全表扫。
|
|
28
|
-
|
|
29
|
-
CLI:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
dsh-mneme-serve [--memory-dir <dir>] [--port <n>] [--host <addr>] [--embed <provider>]
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
- `memoryDir`:CLI > env `DSH_MNEME_MEMORY_DIR` > `~/.dsh/memory`(与宿主 config.js 同默认,支持前导 `~`)。
|
|
36
|
-
- `--embed`:语义检索提供方。`local`(默认:自管 runtime 与嵌入模型缺失时**自动取件**,download 档,约 200MB;失败降级关键词并打可操作日志)| `ollama` | `openai`(读宿主面板存的 vector-config)| `off`(纯关键词 + BM25)。取件来源可用 env 换道:`DSH_MNEME_RUNTIME_DIR`(自管 runtime 目录)、`DSH_MNEME_RUNTIME_TARBALL_DIR`(离线 .tgz 目录,优先于联网)、`DSH_MNEME_RUNTIME_MIRROR`(registry 镜像前缀)。
|
|
37
|
-
- port/host 解析链与宿主「外部访问」一致:显式参数 > kv `external_api` 持久值 > 默认 8790 / 127.0.0.1。
|
|
38
|
-
- token 与 DSH 面板 / CLI **共用同一份**(kv `external_api`,首次启动自动生成并持久化)——三方零配置互通。
|
|
39
|
-
- 安全:daemon 使用明文 HTTP,不提供原生 TLS。指定非回环 `--host` 时,请勿直接把服务暴露给不可信网络;远程访问请走 TLS 终止代理或 SSH 隧道。
|
|
40
|
-
- stdout 只在就绪时打一行 `dsh-mneme-serve listening on http://host:port (pid N)`(机器可读,脚本/测试解析端口用);日志全走 stderr。
|
|
41
|
-
- SIGINT/SIGTERM 优雅收库后 exit 0;Windows 强杀由 WAL 回放兜底。
|
|
42
|
-
|
|
43
|
-
## 3. 内部文件
|
|
44
|
-
|
|
45
|
-
- `src/serve.js` — `createServeRuntime({memoryDir, port, host, logger, strictPort, embed, embedder, reranker})`:装配链 createStore → createSettings → createMirror → createService(最小 config)→ recoverMirror → 人改镜像合并闭包 → vectorIndex + semantic → recall recorder → createMaintenance → createStandaloneApi(带 `embedder: embedder ?? semantic?.embedder ?? null`,供 `/context` 查询嵌入),每步锚定 index.js 行号。返回 `{api, store, service, settings, maintenance, semantic, tokenExisted, dispose}`;第三方可 import 它自行托管生命周期(bin 只是薄壳),`embedder/reranker` 参数供注入自管嵌入。
|
|
46
|
-
- `src/semantic.js` — embedder/reranker 装配 + boot 自动回填,**纯搬移自 index.js**(PR2),宿主与 daemon 共用同一份;`backfillMissingEmbeddings` 经 index.js barrel 再出口(测试照旧从 index.js import)。
|
|
47
|
-
- `bin/dsh-mneme-serve.mjs` — CLI 壳。独立成 bin 而非 cli.mjs 子命令:CONTRIBUTING 禁止给 cli.mjs 加 import;命名循 dsh-mneme-mcp 先例。
|
|
48
|
-
- `src/api-standalone.js` 的 `strictPort` 选项 — daemon 自己引入的唯一数据面改动,默认关闭(daemon 侧显式传 true)。#370 起该工厂另增 `/context` 路由与可选 `embedder` 注入,宿主外部访问同享。
|
|
49
|
-
|
|
50
|
-
## 4. 已知坑
|
|
51
|
-
|
|
52
|
-
1. **端口互斥,二选一**:daemon 与 DSH 的「外部访问」抢同一个默认端口。daemon 侧 strictPort 报错退出;反方向( daemon 先占 8790,DSH 后开外部访问)宿主侧会**静默顺延**到下一端口(宿主旁路的多实例恢复语义,api-standalone.js listenWithRetry)——面板显示的端口会变,别当 bug 报。
|
|
53
|
-
2. **双进程写并发**:与 DSH 同时运行是设计内场景(WAL + busy_timeout 先序,store.js createStore)。但 `saveWithDedupe` 的 (type,title,scope) 去重是先查后写、库层无 UNIQUE 约束,两进程并发写同一三元组有极小概率产生重复条目——已知限制,勿当强保证宣传(要不要加 UNIQUE 索引属 schema 防御段,单独决策)。
|
|
54
|
-
3. **镜像双写竞态**:daemon 与宿主都会渲镜像 .md;可再生物,失败由 recoverMirror 自愈,极端并发下单文件可能短暂脏,下次同步覆盖。
|
|
55
|
-
4. **版本偏斜**:库迁移是幂等加法式(PRAGMA 检查 + ALTER),旧代码读新 schema 一般无碍,但该组合无人测过——daemon 与插件请同版本升级。
|
|
56
|
-
5. **第一期不吃宿主配置**:daemon 不加载 config schema(schemastery 是宿主 peer 依赖),面板/feature_flags 对它不生效;它只有 CLI 参数 + 上述固定最小 config(`language: zh`、document 子系统关闭;语义键默认值逐键锚定 config.js,见 `src/serve.js` 的 `daemonSemanticCfg`)。`--embed local` 首次启动会自动取件 runtime + 模型(均有日志);取件/嵌入失败统一降级关键词 + BM25,不影响读写。
|
|
57
|
-
6. **验收锚点**:`test/serve.test.js`(in-process 全链路 + token 复用 + recall_runs 回执 + 注入假 embedder 的向量轴锁)、`test/serve-bin.test.js`(真子进程 + 多进程互写互读)、`test/standalone-api.test.js` 的 strictPort 用例(busy → reject,默认路径仍顺延)、`test/reindex-backfill.test.js`(semantic 纯搬移后宿主行为不变)。
|
|
1
|
+
# dsh-mneme 独立服务(daemon)
|
|
2
|
+
|
|
3
|
+
`dsh-mneme-serve`:在 DSH 宿主之外把 mneme 跑成一个常驻数据面。#363(Mneme Bridge)确立的方向——第三方集成需要长期挂载,而 DSH 不必一直开着;这是官方推荐姿势,lib 直挂的 embedded 模式降级为无网兜底。
|
|
4
|
+
|
|
5
|
+
## 1. 职责边界
|
|
6
|
+
|
|
7
|
+
daemon 是**数据面**,不是第二个宿主:
|
|
8
|
+
|
|
9
|
+
- **有**:存储(SQLite)、检索(关键词 + BM25 + 向量,`/search` 统一召回,与宿主共用 `src/semantic.js` 同一套装配)、注入候选(`/context`,issue #370,与宿主注入管线同一份 `injectCandidates`)、镜像同步与人改合并、`/maintenance/reclaim`、`/share`(记忆分享包,纯读,见 [SHARE.md](SHARE.md))、`/receive` 与 `/receive/undo`(吃包入库与整包退出,车道 C;写的是**本机自己的库**,与 `/share` 同一条 4 MiB 入站上限)、`/bootstrap`、recall_runs 检索/注入回执。
|
|
10
|
+
- **没有(第一期,无 LLM)**:巩固(autoDream)、蒸馏(autoSummarize)、实体抽取、sleep、注入/工具/面板路由。前两者是**结构性缺失**而非开关——daemon 装配里没有 LLM 句柄,巩固只属于 DSH 宿主进程。这就是 daemon 与宿主「单写者」的机械保证(AGENTS.md externalApi/autoDream 单侧纪律的 daemon 版),不依赖用户自觉。
|
|
11
|
+
- **收包在 daemon 上付的是什么**:一个事务里逐条先查 `share_external_id` 再 `store.save`,嵌入随最外层 COMMIT 排空(`--embed local` 时真打向量,`off` 时只落结构),镜像重渲染照 daemon 自己那条回灌路走。**实体一个都不建**——不是 daemon 缺 LLM 才不建,车道 C 对外来行本来就不做抽取(有向量、无实体,实体与图检索看不见它们),宿主侧同样如此。成本的量级读数见 [SHARE.md](SHARE.md)「收侧」那一节实测。
|
|
12
|
+
|
|
13
|
+
与宿主装配(`src/index.js` apply)的关系:`src/serve.js` 只搬数据面那一半,每步注释锚定 index.js 来源行号;刻意不抽公共装配函数(apply 其余环节与宿主 ctx 纠缠,防御段纪律「最后动或不动」)。装配漂移风险由 `test/serve-bin.test.js` 的多进程共存用例兜底(两进程真开同一个库互写互读)。
|
|
14
|
+
|
|
15
|
+
## 2. 对外接口
|
|
16
|
+
|
|
17
|
+
路由面 = `src/api-standalone.js` 全表(health/status/profile/rules/memories 读写/`/memory/provenance`(记忆级 / 会话级溯源读出口,#421+#524)/search/context/share/receive(含 `/receive/undo`)/maintenance/bootstrap),鉴权同源(Bearer + timingSafeEqual,`GET /health` 免鉴权)。daemon 自身零新路由;#370 的 `/context` 落在 api-standalone 工厂里,宿主外部访问与 daemon 自动同享(参数、scope 语义与 recall_runs 注入分账见包 README 路由表)。daemon 侧唯一自有选项是 `strictPort`(见 §4)。
|
|
18
|
+
|
|
19
|
+
`/memory/provenance` 的开关门(#509 评审整改):这个面返回蒸馏窗口的**逐条会话原文**,所以它吃 `distillRecords.enabled`——与写侧 `src/summarize.js:988` 同一枚开关、同一个判据表达式(读侧唯一一份在 `src/provenance-http.js` 的 `isDistillRecordsEnabled`)。关着时回 `409 {"error":"distill-records-disabled"}`,不是 404(本端点刻意不就「这条记忆是否存在」作断言:未知 id 是 200 + 空 windows),也不是 503(那是「装配没接线」,`src/index.js:589-591` 立的可区分性原则)。状态码阶梯:`401` 无 token → `400` 缺参(`missing-id` / `ambiguous-id` / `invalid-limit`) → `409` 功能关了 → `503` 装配没接线(按方向判) → `200`。
|
|
20
|
+
|
|
21
|
+
两个读方向共用同一条路径(#524 补上方向 2):`?id=<memoryId>` 是「这条记忆派生自哪些窗口」,`?sessionId=<sid>` 是「这个会话蒸出了哪些窗口」;两个主键**互斥**,都缺与都给都回 400(择一等于让调用方发一个自己也不知道会读哪个主键的请求,而两边的结果形状不同)。方向 2 必须带 `limit`(默认 20、上限 100)——按会话读是这张脸里天然最容易放大的方向,一个会话几十个窗口、每个窗口都是整段逐字原文,不限量就是「按会话导出全量转录」,与 `/export` 同量级只是换了形状;撞上限时答复带 `truncated: true`,少了这个读数,被截断的答复与「本来就这么少」逐字节相同。方向 2 的窗口按 `(session_id, seq_start, seq_end)` 合并成一行 `GROUP BY`,带 `link_count`——一条蒸馏窗口通常产出多条记忆,逐链接返回会让「这个会话蒸了几次」被重复行淹没。daemon 读的是**面板持久化的开关**(`serve.js` 把 `feature_flags` 里的 `distillRecords.enabled` 展开进 cfg,与宿主 `index.js:217-233` 同款),与宿主共用同一个 memory.db、同一份 kv——所以用户在面板里开着,daemon 这一面就读得到。
|
|
22
|
+
|
|
23
|
+
`/memory/provenance` 的响应形状(#512):窗口在 `session_id/seq_start/seq_end/created_at/records` 之外另带 `distill_run_id / run_type / trigger_source / run_status`(读不到整轮归因时整组 `null`,不从区间或时间戳反推),答复级再带 `mints[]`(行级归因:这条记忆出生自哪一轮 dream/sleep)。归因元数据不受 `distillRecords.enabled` 约束——它不含任何会话正文,所以开关关着时这个端点照旧 409,但库里那两张表仍在记账。
|
|
24
|
+
|
|
25
|
+
残留不对称要知道:daemon 结构上看不到宿主的 **bundle config**(第一期不吃宿主 config schema),所以「只写在部署侧 bundle 配置里打开、从没在面板点过」的用户,宿主认、daemon 不认——daemon 会对每个请求回 409。这不是故障,是 daemon 装配面的已知边界;要让 daemon 也认,去面板里把开关显式打开一次(面板的「待重启」提示同样适用:开关是启动快照,改完要重启才生效)。
|
|
26
|
+
|
|
27
|
+
`/context` 的档位信号(#383):响应多一个 `tier`(`full` 语义档 / `degraded` 规则档 / `unknown` 语义路未启用或判不出来,fail-closed),**具体降级原因只在 stderr**——`dsh-mneme: /context degraded to the rule tier (<reason>)`,不进响应体。原因是给运维的读数,六值互不吞并(成例「修法不同就分开」):`embed-unavailable` 无可用接口(embedder 对象在、缺 `embedSingle`/`embed`,修适配器)/ `embed-empty` 空向量 / `embed-timeout` 挂起 / `embed-error` 抛错 / `embed-dimension` 维度不符(有向量但没有一条与查询同维,修法是重建索引)/ `no-embedder` 压根没装配 embedder(`--embed off` / lightMode / 宿主未装配,**预期态不是故障**,修法是把嵌装扮上或开起来)。`tier` 是给调用方的读数,两套消费者分开;六值的唯一真源是 `src/api-standalone.js` 的 `CONTEXT_DEGRADE_REASONS`,契约测试从它派生。`unknown` 之下(维度探针没跑成 / 有行却一条向量都读不出来)另有一行 `dsh-mneme: /context tier left unknown: <what>`,**不是**那六值的一员(`tier` 不是 degraded,没有降级原因可记),运维程序不要按原因枚举解析它——没有它,调用方对 unknown 的策略是「不告警」时,一次真实的判档故障会整个消失。`no-embedder` 不并进 `embed-unavailable` 是故意的:那两者共用「语义路没通」的结果,但一个是适配器坏了(异常)、一个是语义路没开(设计内常态),并成一个值会让按 `embed-unavailable` 告警的面板对每个轻量模式安装报警;用词则与宿主面 `/api/dsh-mneme/semantic` 的 `reason` 对齐(那边是另一套枚举、另一个消费者,别顺手统一)。这里最值得盯的是 `embed-dimension`:嵌入接口一切正常,但库里是旧维度向量,`searchVector` 直接跳过、不抛错,召回静默退回关键词档——修法是重建索引,不是查端点。判档有成本:`q` 非空且装了 embedder 时一次 `/context` 会真起一次查询嵌入(一次往返 + `embedTimeoutMs` 窗口),维度探针本身是**按匹配短路的存在性判据**(有没有一条活跃向量与查询同维,不是 `LIMIT 1` 读一行——混合维度库里那会抽错维误报 degraded、首条损坏又会漏报 full):一次无 `LIMIT` 的全 id 扫描 + 短路解析,同维度健康库只解析 1 个向量,只有要报 degraded 时才走完全表;不复用 `/health`(它只回 `{ok:true}`)也不做全表扫。
|
|
28
|
+
|
|
29
|
+
CLI:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
dsh-mneme-serve [--memory-dir <dir>] [--port <n>] [--host <addr>] [--embed <provider>]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- `memoryDir`:CLI > env `DSH_MNEME_MEMORY_DIR` > `~/.dsh/memory`(与宿主 config.js 同默认,支持前导 `~`)。
|
|
36
|
+
- `--embed`:语义检索提供方。`local`(默认:自管 runtime 与嵌入模型缺失时**自动取件**,download 档,约 200MB;失败降级关键词并打可操作日志)| `ollama` | `openai`(读宿主面板存的 vector-config)| `off`(纯关键词 + BM25)。取件来源可用 env 换道:`DSH_MNEME_RUNTIME_DIR`(自管 runtime 目录)、`DSH_MNEME_RUNTIME_TARBALL_DIR`(离线 .tgz 目录,优先于联网)、`DSH_MNEME_RUNTIME_MIRROR`(registry 镜像前缀)。
|
|
37
|
+
- port/host 解析链与宿主「外部访问」一致:显式参数 > kv `external_api` 持久值 > 默认 8790 / 127.0.0.1。
|
|
38
|
+
- token 与 DSH 面板 / CLI **共用同一份**(kv `external_api`,首次启动自动生成并持久化)——三方零配置互通。
|
|
39
|
+
- 安全:daemon 使用明文 HTTP,不提供原生 TLS。指定非回环 `--host` 时,请勿直接把服务暴露给不可信网络;远程访问请走 TLS 终止代理或 SSH 隧道。
|
|
40
|
+
- stdout 只在就绪时打一行 `dsh-mneme-serve listening on http://host:port (pid N)`(机器可读,脚本/测试解析端口用);日志全走 stderr。
|
|
41
|
+
- SIGINT/SIGTERM 优雅收库后 exit 0;Windows 强杀由 WAL 回放兜底。
|
|
42
|
+
|
|
43
|
+
## 3. 内部文件
|
|
44
|
+
|
|
45
|
+
- `src/serve.js` — `createServeRuntime({memoryDir, port, host, logger, strictPort, embed, embedder, reranker})`:装配链 createStore → createSettings → createMirror → createService(最小 config)→ recoverMirror → 人改镜像合并闭包 → vectorIndex + semantic → recall recorder → createMaintenance → createStandaloneApi(带 `embedder: embedder ?? semantic?.embedder ?? null`,供 `/context` 查询嵌入),每步锚定 index.js 行号。返回 `{api, store, service, settings, maintenance, semantic, tokenExisted, dispose}`;第三方可 import 它自行托管生命周期(bin 只是薄壳),`embedder/reranker` 参数供注入自管嵌入。
|
|
46
|
+
- `src/semantic.js` — embedder/reranker 装配 + boot 自动回填,**纯搬移自 index.js**(PR2),宿主与 daemon 共用同一份;`backfillMissingEmbeddings` 经 index.js barrel 再出口(测试照旧从 index.js import)。
|
|
47
|
+
- `bin/dsh-mneme-serve.mjs` — CLI 壳。独立成 bin 而非 cli.mjs 子命令:CONTRIBUTING 禁止给 cli.mjs 加 import;命名循 dsh-mneme-mcp 先例。
|
|
48
|
+
- `src/api-standalone.js` 的 `strictPort` 选项 — daemon 自己引入的唯一数据面改动,默认关闭(daemon 侧显式传 true)。#370 起该工厂另增 `/context` 路由与可选 `embedder` 注入,宿主外部访问同享。
|
|
49
|
+
|
|
50
|
+
## 4. 已知坑
|
|
51
|
+
|
|
52
|
+
1. **端口互斥,二选一**:daemon 与 DSH 的「外部访问」抢同一个默认端口。daemon 侧 strictPort 报错退出;反方向( daemon 先占 8790,DSH 后开外部访问)宿主侧会**静默顺延**到下一端口(宿主旁路的多实例恢复语义,api-standalone.js listenWithRetry)——面板显示的端口会变,别当 bug 报。
|
|
53
|
+
2. **双进程写并发**:与 DSH 同时运行是设计内场景(WAL + busy_timeout 先序,store.js createStore)。但 `saveWithDedupe` 的 (type,title,scope) 去重是先查后写、库层无 UNIQUE 约束,两进程并发写同一三元组有极小概率产生重复条目——已知限制,勿当强保证宣传(要不要加 UNIQUE 索引属 schema 防御段,单独决策)。
|
|
54
|
+
3. **镜像双写竞态**:daemon 与宿主都会渲镜像 .md;可再生物,失败由 recoverMirror 自愈,极端并发下单文件可能短暂脏,下次同步覆盖。
|
|
55
|
+
4. **版本偏斜**:库迁移是幂等加法式(PRAGMA 检查 + ALTER),旧代码读新 schema 一般无碍,但该组合无人测过——daemon 与插件请同版本升级。
|
|
56
|
+
5. **第一期不吃宿主配置**:daemon 不加载 config schema(schemastery 是宿主 peer 依赖),面板/feature_flags 对它不生效;它只有 CLI 参数 + 上述固定最小 config(`language: zh`、document 子系统关闭;语义键默认值逐键锚定 config.js,见 `src/serve.js` 的 `daemonSemanticCfg`)。`--embed local` 首次启动会自动取件 runtime + 模型(均有日志);取件/嵌入失败统一降级关键词 + BM25,不影响读写。
|
|
57
|
+
6. **验收锚点**:`test/serve.test.js`(in-process 全链路 + token 复用 + recall_runs 回执 + 注入假 embedder 的向量轴锁)、`test/serve-bin.test.js`(真子进程 + 多进程互写互读)、`test/standalone-api.test.js` 的 strictPort 用例(busy → reject,默认路径仍顺延)、`test/reindex-backfill.test.js`(semantic 纯搬移后宿主行为不变)。
|