@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
|
@@ -1,113 +1,113 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { runSleep } from "../src/dream/sleep.js";
|
|
4
|
-
import { createStore } from "../src/store.js";
|
|
5
|
-
import { createService } from "../src/service.js";
|
|
6
|
-
|
|
7
|
-
// v0.7.0 语义修正(待办④ updated_at 不算访问):
|
|
8
|
-
// - merge/update 刷 updated_at 绝不当访问,last_accessed_at 与 updated_at 正交;
|
|
9
|
-
// - sleep 降级 ref 只用 last_accessed_at ?? created_at,杜绝 autoDream 合并
|
|
10
|
-
// 动作把"刚更新过内容"伪装成"刚被召回";
|
|
11
|
-
// - 触达数据采集(touchRecalled)由 heatEnabled 控制,不再依赖 sleepModeEnabled。
|
|
12
|
-
|
|
13
|
-
const DAY = 86400000;
|
|
14
|
-
|
|
15
|
-
function setup(config = {}) {
|
|
16
|
-
const store = createStore(":memory:");
|
|
17
|
-
const service = createService({ store, mirror: null, config });
|
|
18
|
-
return { store, service };
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function saveMemory(service, title, content, type = "project") {
|
|
22
|
-
return service.saveWithDedupe({ type, title, content, importance: 3 }).memory;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
test("store.update bumps updated_at but never last_accessed_at", () => {
|
|
26
|
-
const { store, service } = setup();
|
|
27
|
-
const mem = saveMemory(service, "项目A", "状态:进行中");
|
|
28
|
-
assert.equal(mem.last_accessed_at, undefined, "saved memory has no last_accessed_at");
|
|
29
|
-
|
|
30
|
-
const touched = service.touchLastAccess(mem.id, new Date(Date.now() - 5 * DAY).toISOString());
|
|
31
|
-
assert.equal(touched, true, "explicit touch succeeds");
|
|
32
|
-
const afterTouch = store.getById(mem.id);
|
|
33
|
-
assert.ok(afterTouch.last_accessed_at, "last_accessed_at set after touch");
|
|
34
|
-
|
|
35
|
-
const updatedAtBefore = afterTouch.updated_at;
|
|
36
|
-
store.update(mem.id, { content: "状态:已交付" });
|
|
37
|
-
const afterUpdate = store.getById(mem.id);
|
|
38
|
-
assert.notEqual(afterUpdate.updated_at, updatedAtBefore, "updated_at changed by update");
|
|
39
|
-
assert.equal(
|
|
40
|
-
afterUpdate.last_accessed_at,
|
|
41
|
-
afterTouch.last_accessed_at,
|
|
42
|
-
"last_accessed_at untouched by update (content change ≠ access)"
|
|
43
|
-
);
|
|
44
|
-
store.close();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test("search bumps last_accessed_at with heatEnabled on, and is gated off by heatEnabled=false", async () => {
|
|
48
|
-
// 显式开启 heat(v0.7.20 起默认关):last_accessed_at 被采集(与 sleep 开关解耦)。
|
|
49
|
-
const a = setup({ heatEnabled: true });
|
|
50
|
-
saveMemory(a.service, "量子计算", "入门");
|
|
51
|
-
await a.service.searchMemories("量子", { mode: "keyword" });
|
|
52
|
-
const rowA = a.store.getById(a.service.all()[0].id);
|
|
53
|
-
assert.ok(rowA.last_accessed_at, "touch runs when heatEnabled is true even when sleepModeEnabled off");
|
|
54
|
-
a.store.close();
|
|
55
|
-
|
|
56
|
-
// heatEnabled=false(默认值)→ 热路径零写入。
|
|
57
|
-
const b = setup({ heatEnabled: false });
|
|
58
|
-
saveMemory(b.service, "量子计算", "入门");
|
|
59
|
-
await b.service.searchMemories("量子", { mode: "keyword" });
|
|
60
|
-
const rowB = b.store.getById(b.service.all()[0].id);
|
|
61
|
-
assert.equal(rowB.last_accessed_at, undefined, "no touch when heatEnabled=false");
|
|
62
|
-
b.store.close();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test("sleep demotion anchors on last_accessed_at — a merge-bumped updated_at does not reset the fresh clock", async () => {
|
|
66
|
-
const { store, service } = setup();
|
|
67
|
-
const now = Date.now();
|
|
68
|
-
const idle = saveMemory(service, "冷查记忆A", "很久没被召回");
|
|
69
|
-
// 模拟一次 autoDream 合并:updated_at 刷成"现在",但真实访问在 100 天前。
|
|
70
|
-
store.update(idle.id, { content: "合并带来的内容更新" });
|
|
71
|
-
const wait = saveMemory(service, "冷查记忆B", "40 天未访问");
|
|
72
|
-
|
|
73
|
-
service.touchLastAccess(idle.id, new Date(now - 100 * DAY).toISOString());
|
|
74
|
-
service.touchLastAccess(wait.id, new Date(now - 40 * DAY).toISOString());
|
|
75
|
-
|
|
76
|
-
// runSleep 的最低配置:demotion 阶段不需要 LLM/语义,其余阶段会 skip。
|
|
77
|
-
const ctx = {
|
|
78
|
-
logger: { warn: () => {}, info: () => {} },
|
|
79
|
-
agentDefaultModel: { currentSelection: () => ({ provider: "mock", model: "sleep-model" }) },
|
|
80
|
-
llm: {
|
|
81
|
-
async *stream() {
|
|
82
|
-
yield { type: "text-delta", index: 0, text: "[]" };
|
|
83
|
-
yield { type: "finish", reason: { kind: "stop" } };
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
const config = {
|
|
88
|
-
sleepModeEnabled: true,
|
|
89
|
-
sleepConflictStrictness: "normal",
|
|
90
|
-
sleepArchiveDays: 30,
|
|
91
|
-
sleepCompressDays: 90,
|
|
92
|
-
sleepPatternMinMemories: 100,
|
|
93
|
-
sleepMaxPatternPerRun: 3,
|
|
94
|
-
// v0.7.0 热联合判定:project λ=0.0008 默认太慢衰减,40/100 天热值都高于
|
|
95
|
-
// 阈值、被热闸保护——本测试只验证"updated_at 不算访问"的 ref 语义,故把
|
|
96
|
-
// λ 调快到 0.02 打开降级路径(默认保守语义由 sleep-heat.test.js 覆盖)。
|
|
97
|
-
heatTypeDecay: { project: 0.02 }
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const result = await runSleep(ctx, service, config, { warn: () => {}, info: () => {} }, null, null);
|
|
101
|
-
|
|
102
|
-
const demotion = result.phases?.["demotion"];
|
|
103
|
-
assert.ok(demotion, "demotion phase ran");
|
|
104
|
-
// A:last_accessed 100 天前(即使 updated_at 是"现在")→ 越过 90 天归档线。
|
|
105
|
-
assert.ok(demotion.archived.includes(idle.id), "A archived by last_accessed_at (updated_at ignored)");
|
|
106
|
-
const afterA = store.getById(idle.id);
|
|
107
|
-
assert.equal(afterA.archived, true, "A is archived in store");
|
|
108
|
-
// B:last_accessed 40 天前 → 进入 30 天压缩窗口,被降级为摘要。
|
|
109
|
-
assert.ok(demotion.demoted.includes(wait.id), "B demoted in 30d compress window");
|
|
110
|
-
const afterB = store.getById(wait.id);
|
|
111
|
-
assert.ok(afterB._full_content, "B full body parked in _full_content");
|
|
112
|
-
store.close();
|
|
113
|
-
});
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { runSleep } from "../src/dream/sleep.js";
|
|
4
|
+
import { createStore } from "../src/store.js";
|
|
5
|
+
import { createService } from "../src/service.js";
|
|
6
|
+
|
|
7
|
+
// v0.7.0 语义修正(待办④ updated_at 不算访问):
|
|
8
|
+
// - merge/update 刷 updated_at 绝不当访问,last_accessed_at 与 updated_at 正交;
|
|
9
|
+
// - sleep 降级 ref 只用 last_accessed_at ?? created_at,杜绝 autoDream 合并
|
|
10
|
+
// 动作把"刚更新过内容"伪装成"刚被召回";
|
|
11
|
+
// - 触达数据采集(touchRecalled)由 heatEnabled 控制,不再依赖 sleepModeEnabled。
|
|
12
|
+
|
|
13
|
+
const DAY = 86400000;
|
|
14
|
+
|
|
15
|
+
function setup(config = {}) {
|
|
16
|
+
const store = createStore(":memory:");
|
|
17
|
+
const service = createService({ store, mirror: null, config });
|
|
18
|
+
return { store, service };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function saveMemory(service, title, content, type = "project") {
|
|
22
|
+
return service.saveWithDedupe({ type, title, content, importance: 3 }).memory;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
test("store.update bumps updated_at but never last_accessed_at", () => {
|
|
26
|
+
const { store, service } = setup();
|
|
27
|
+
const mem = saveMemory(service, "项目A", "状态:进行中");
|
|
28
|
+
assert.equal(mem.last_accessed_at, undefined, "saved memory has no last_accessed_at");
|
|
29
|
+
|
|
30
|
+
const touched = service.touchLastAccess(mem.id, new Date(Date.now() - 5 * DAY).toISOString());
|
|
31
|
+
assert.equal(touched, true, "explicit touch succeeds");
|
|
32
|
+
const afterTouch = store.getById(mem.id);
|
|
33
|
+
assert.ok(afterTouch.last_accessed_at, "last_accessed_at set after touch");
|
|
34
|
+
|
|
35
|
+
const updatedAtBefore = afterTouch.updated_at;
|
|
36
|
+
store.update(mem.id, { content: "状态:已交付" });
|
|
37
|
+
const afterUpdate = store.getById(mem.id);
|
|
38
|
+
assert.notEqual(afterUpdate.updated_at, updatedAtBefore, "updated_at changed by update");
|
|
39
|
+
assert.equal(
|
|
40
|
+
afterUpdate.last_accessed_at,
|
|
41
|
+
afterTouch.last_accessed_at,
|
|
42
|
+
"last_accessed_at untouched by update (content change ≠ access)"
|
|
43
|
+
);
|
|
44
|
+
store.close();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("search bumps last_accessed_at with heatEnabled on, and is gated off by heatEnabled=false", async () => {
|
|
48
|
+
// 显式开启 heat(v0.7.20 起默认关):last_accessed_at 被采集(与 sleep 开关解耦)。
|
|
49
|
+
const a = setup({ heatEnabled: true });
|
|
50
|
+
saveMemory(a.service, "量子计算", "入门");
|
|
51
|
+
await a.service.searchMemories("量子", { mode: "keyword" });
|
|
52
|
+
const rowA = a.store.getById(a.service.all()[0].id);
|
|
53
|
+
assert.ok(rowA.last_accessed_at, "touch runs when heatEnabled is true even when sleepModeEnabled off");
|
|
54
|
+
a.store.close();
|
|
55
|
+
|
|
56
|
+
// heatEnabled=false(默认值)→ 热路径零写入。
|
|
57
|
+
const b = setup({ heatEnabled: false });
|
|
58
|
+
saveMemory(b.service, "量子计算", "入门");
|
|
59
|
+
await b.service.searchMemories("量子", { mode: "keyword" });
|
|
60
|
+
const rowB = b.store.getById(b.service.all()[0].id);
|
|
61
|
+
assert.equal(rowB.last_accessed_at, undefined, "no touch when heatEnabled=false");
|
|
62
|
+
b.store.close();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("sleep demotion anchors on last_accessed_at — a merge-bumped updated_at does not reset the fresh clock", async () => {
|
|
66
|
+
const { store, service } = setup();
|
|
67
|
+
const now = Date.now();
|
|
68
|
+
const idle = saveMemory(service, "冷查记忆A", "很久没被召回");
|
|
69
|
+
// 模拟一次 autoDream 合并:updated_at 刷成"现在",但真实访问在 100 天前。
|
|
70
|
+
store.update(idle.id, { content: "合并带来的内容更新" });
|
|
71
|
+
const wait = saveMemory(service, "冷查记忆B", "40 天未访问");
|
|
72
|
+
|
|
73
|
+
service.touchLastAccess(idle.id, new Date(now - 100 * DAY).toISOString());
|
|
74
|
+
service.touchLastAccess(wait.id, new Date(now - 40 * DAY).toISOString());
|
|
75
|
+
|
|
76
|
+
// runSleep 的最低配置:demotion 阶段不需要 LLM/语义,其余阶段会 skip。
|
|
77
|
+
const ctx = {
|
|
78
|
+
logger: { warn: () => {}, info: () => {} },
|
|
79
|
+
agentDefaultModel: { currentSelection: () => ({ provider: "mock", model: "sleep-model" }) },
|
|
80
|
+
llm: {
|
|
81
|
+
async *stream() {
|
|
82
|
+
yield { type: "text-delta", index: 0, text: "[]" };
|
|
83
|
+
yield { type: "finish", reason: { kind: "stop" } };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const config = {
|
|
88
|
+
sleepModeEnabled: true,
|
|
89
|
+
sleepConflictStrictness: "normal",
|
|
90
|
+
sleepArchiveDays: 30,
|
|
91
|
+
sleepCompressDays: 90,
|
|
92
|
+
sleepPatternMinMemories: 100,
|
|
93
|
+
sleepMaxPatternPerRun: 3,
|
|
94
|
+
// v0.7.0 热联合判定:project λ=0.0008 默认太慢衰减,40/100 天热值都高于
|
|
95
|
+
// 阈值、被热闸保护——本测试只验证"updated_at 不算访问"的 ref 语义,故把
|
|
96
|
+
// λ 调快到 0.02 打开降级路径(默认保守语义由 sleep-heat.test.js 覆盖)。
|
|
97
|
+
heatTypeDecay: { project: 0.02 }
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const result = await runSleep(ctx, service, config, { warn: () => {}, info: () => {} }, null, null);
|
|
101
|
+
|
|
102
|
+
const demotion = result.phases?.["demotion"];
|
|
103
|
+
assert.ok(demotion, "demotion phase ran");
|
|
104
|
+
// A:last_accessed 100 天前(即使 updated_at 是"现在")→ 越过 90 天归档线。
|
|
105
|
+
assert.ok(demotion.archived.includes(idle.id), "A archived by last_accessed_at (updated_at ignored)");
|
|
106
|
+
const afterA = store.getById(idle.id);
|
|
107
|
+
assert.equal(afterA.archived, true, "A is archived in store");
|
|
108
|
+
// B:last_accessed 40 天前 → 进入 30 天压缩窗口,被降级为摘要。
|
|
109
|
+
assert.ok(demotion.demoted.includes(wait.id), "B demoted in 30d compress window");
|
|
110
|
+
const afterB = store.getById(wait.id);
|
|
111
|
+
assert.ok(afterB._full_content, "B full body parked in _full_content");
|
|
112
|
+
store.close();
|
|
113
|
+
});
|
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
// 修复二:面板「Agent 眼中的画像」那张卡标榜的是「注入生效文本」,但它原本是前端
|
|
2
|
-
// 自己拼的(只有 profile + rules,既没有 [用户设置] 表头、没有「- 用户画像:」前缀,
|
|
3
|
-
// 也完全没有人格三行)。两块渲染代码各写各的,就一定会漂——所以这里要的是**同源**:
|
|
4
|
-
// 预览必须由注入器用的同一个渲染函数产出,而不是第二份实现。
|
|
5
|
-
// 本文件最关键的一条是第 1 条:拿同一个 settings、同一个 config、同一个会话身份,
|
|
6
|
-
// 让注入器与路由各渲染一次,断言逐字节相等。前端复刻模板的写法永远锁不住这条。
|
|
7
|
-
import test from "node:test";
|
|
8
|
-
import assert from "node:assert/strict";
|
|
9
|
-
import { EventEmitter } from "node:events";
|
|
10
|
-
import { createStore } from "../src/store.js";
|
|
11
|
-
import { createService } from "../src/service.js";
|
|
12
|
-
import { createInjector } from "../src/inject.js";
|
|
13
|
-
import { createApi } from "../src/api.js";
|
|
14
|
-
import { createSettings } from "../src/settings.js";
|
|
15
|
-
|
|
16
|
-
class FakeRes extends EventEmitter {
|
|
17
|
-
constructor() { super(); this.statusCode = 200; this.body = ""; }
|
|
18
|
-
writeHead(code, headers) { this.statusCode = code; this.headers = headers; return this; }
|
|
19
|
-
end(text) { this.body = text ?? ""; this.emit("end"); return this; }
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function req(path, method = "GET") {
|
|
23
|
-
return { url: path, method, headers: {}, on() {}, emit() {} };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// 一份 settings/config 同时喂注入器与 API:两侧必须读同一个源,否则「同源」是假的。
|
|
27
|
-
function setup(config = {}) {
|
|
28
|
-
const store = createStore(":memory:");
|
|
29
|
-
const service = createService({ store, mirror: null, config });
|
|
30
|
-
const settings = createSettings(store.db);
|
|
31
|
-
const contexts = [];
|
|
32
|
-
const ctx = { systemPrompt: { context(def) { contexts.push(def); return () => {}; } } };
|
|
33
|
-
createInjector(ctx, service, settings, config);
|
|
34
|
-
const injectorText = (agentPreset) =>
|
|
35
|
-
contexts.find((c) => c.name === "user-settings").text(agentPreset ? { agent: { session: { header: { agentPreset } } } } : {});
|
|
36
|
-
const routes = [];
|
|
37
|
-
createApi(
|
|
38
|
-
{ webServer: { register: (route) => { routes.push(route); return () => {}; } } },
|
|
39
|
-
service,
|
|
40
|
-
settings,
|
|
41
|
-
{ add: () => {}, remove: () => {}, list: () => [] },
|
|
42
|
-
undefined,
|
|
43
|
-
undefined,
|
|
44
|
-
"",
|
|
45
|
-
config
|
|
46
|
-
);
|
|
47
|
-
const route = routes.find((r) => r.path === "/api/dsh-mneme/persona");
|
|
48
|
-
const preview = async (agent) => {
|
|
49
|
-
const res = new FakeRes();
|
|
50
|
-
await route.handler(req(`/api/dsh-mneme/persona${agent ? `?agent=${agent}` : ""}`), res);
|
|
51
|
-
return JSON.parse(res.body);
|
|
52
|
-
};
|
|
53
|
-
return { store, settings, injectorText, preview };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function seed(settings) {
|
|
57
|
-
settings.setProfile("用户是规划背景");
|
|
58
|
-
settings.setRules(["不提及用户名"]);
|
|
59
|
-
settings.setPersona({ name: "Amarre", personality: "轻松幽默", replyStyle: "先结论后展开", enabled: true });
|
|
60
|
-
settings.setPersonaFor("zephyr", { name: "泽菲尔", personality: "冷危", enabled: true });
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
test("预览与注入器逐字节同源(同身份、同配置渲染两次必须一致)", async () => {
|
|
64
|
-
const { store, settings, injectorText, preview } = setup({ personaEnabled: true });
|
|
65
|
-
seed(settings);
|
|
66
|
-
for (const agent of ["zephyr", "unknown-bot", undefined]) {
|
|
67
|
-
const fromInjector = injectorText(agent);
|
|
68
|
-
const body = await preview(agent);
|
|
69
|
-
assert.equal(body.preview.text, fromInjector, `agent=${agent ?? "(无)"} 的预览必须等于注入器这一帧的输出`);
|
|
70
|
-
}
|
|
71
|
-
store.close();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test("预览含表头与画像前缀,且人格行在最前(原样复刻注入文本,不是前端拼的三条)", async () => {
|
|
75
|
-
const { store, settings, preview } = setup({ personaEnabled: true });
|
|
76
|
-
seed(settings);
|
|
77
|
-
const { preview: p } = await preview();
|
|
78
|
-
assert.ok(p.text.startsWith("[用户设置] 来自 dsh-mneme 的用户画像与规则:"), "表头缺失就不是「生效文本」");
|
|
79
|
-
assert.ok(p.text.includes("- 你的人格名字:Amarre"), "人格行必须在预览里——原来那段完全没有它");
|
|
80
|
-
assert.ok(p.text.includes("- 用户画像:用户是规划背景"), "画像前缀同理");
|
|
81
|
-
assert.ok(p.text.indexOf("你的人格名字") < p.text.indexOf("用户画像:"), "顺序即优先级:人格先出、画像与规则后出");
|
|
82
|
-
assert.equal(p.source, "default", "无 agent 参数 = 按「解析不到身份」寻址");
|
|
83
|
-
// agent 是面板区分两种 default 的唯一依据:解析不到身份(null)与「身份解析到了、
|
|
84
|
-
// 但没建卡/卡被关」(回显那个身份)。少了这条断言,面板那条回落文案就没有依据。
|
|
85
|
-
assert.equal(p.agent, null);
|
|
86
|
-
store.close();
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
test("身份解析到了却没有可用的卡:source=default 且回显该身份", async () => {
|
|
90
|
-
const { store, settings, preview } = setup({ personaEnabled: true });
|
|
91
|
-
seed(settings);
|
|
92
|
-
settings.setPersonaFor("ghost", { name: "无人格", enabled: false });
|
|
93
|
-
const { preview: p } = await preview("ghost");
|
|
94
|
-
assert.equal(p.source, "default", "默认口径下这张关掉的卡落回默认卡");
|
|
95
|
-
assert.equal(p.agent, "ghost", "但身份是解析到的——面板要靠它说「回落」而不是「解析不到」");
|
|
96
|
-
store.close();
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test("预览按 agent 参数寻址,并说明用的是哪张卡", async () => {
|
|
100
|
-
const { store, settings, preview } = setup({ personaEnabled: true });
|
|
101
|
-
seed(settings);
|
|
102
|
-
const hit = await preview("zephyr");
|
|
103
|
-
assert.equal(hit.preview.source, "byAgent");
|
|
104
|
-
assert.equal(hit.preview.agent, "zephyr");
|
|
105
|
-
assert.ok(hit.preview.text.includes("你的人格名字:泽菲尔"));
|
|
106
|
-
store.close();
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
test("总闸关着时预览如实说「人格不会注入」,且不把人格行混进去", async () => {
|
|
110
|
-
const { store, settings, preview } = setup({ personaEnabled: false });
|
|
111
|
-
seed(settings);
|
|
112
|
-
const { preview: p } = await preview();
|
|
113
|
-
assert.equal(p.configGate, false, "面板要靠这个字段解释「卡开着为什么没生效」");
|
|
114
|
-
assert.ok(!p.text.includes("你的人格名字"), "预览里也不许出现实际不会注入的行");
|
|
115
|
-
assert.ok(p.text.includes("用户画像:"), "画像与规则照旧注入——闸只管人格");
|
|
116
|
-
store.close();
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
test("strict 寻址 + 身份未命中:source=none,人格行一段都不出现", async () => {
|
|
120
|
-
const { store, settings, preview } = setup({ personaEnabled: true, personaStrictAddressing: true });
|
|
121
|
-
seed(settings);
|
|
122
|
-
const { preview: p } = await preview("unknown-bot");
|
|
123
|
-
assert.equal(p.source, "none");
|
|
124
|
-
assert.ok(!p.text.includes("Amarre"), "外部身份在严格寻址下拿不到任何人格");
|
|
125
|
-
assert.ok(p.text.includes("用户画像:"), "画像与规则不受影响");
|
|
126
|
-
store.close();
|
|
127
|
-
});
|
|
1
|
+
// 修复二:面板「Agent 眼中的画像」那张卡标榜的是「注入生效文本」,但它原本是前端
|
|
2
|
+
// 自己拼的(只有 profile + rules,既没有 [用户设置] 表头、没有「- 用户画像:」前缀,
|
|
3
|
+
// 也完全没有人格三行)。两块渲染代码各写各的,就一定会漂——所以这里要的是**同源**:
|
|
4
|
+
// 预览必须由注入器用的同一个渲染函数产出,而不是第二份实现。
|
|
5
|
+
// 本文件最关键的一条是第 1 条:拿同一个 settings、同一个 config、同一个会话身份,
|
|
6
|
+
// 让注入器与路由各渲染一次,断言逐字节相等。前端复刻模板的写法永远锁不住这条。
|
|
7
|
+
import test from "node:test";
|
|
8
|
+
import assert from "node:assert/strict";
|
|
9
|
+
import { EventEmitter } from "node:events";
|
|
10
|
+
import { createStore } from "../src/store.js";
|
|
11
|
+
import { createService } from "../src/service.js";
|
|
12
|
+
import { createInjector } from "../src/inject.js";
|
|
13
|
+
import { createApi } from "../src/api.js";
|
|
14
|
+
import { createSettings } from "../src/settings.js";
|
|
15
|
+
|
|
16
|
+
class FakeRes extends EventEmitter {
|
|
17
|
+
constructor() { super(); this.statusCode = 200; this.body = ""; }
|
|
18
|
+
writeHead(code, headers) { this.statusCode = code; this.headers = headers; return this; }
|
|
19
|
+
end(text) { this.body = text ?? ""; this.emit("end"); return this; }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function req(path, method = "GET") {
|
|
23
|
+
return { url: path, method, headers: {}, on() {}, emit() {} };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 一份 settings/config 同时喂注入器与 API:两侧必须读同一个源,否则「同源」是假的。
|
|
27
|
+
function setup(config = {}) {
|
|
28
|
+
const store = createStore(":memory:");
|
|
29
|
+
const service = createService({ store, mirror: null, config });
|
|
30
|
+
const settings = createSettings(store.db);
|
|
31
|
+
const contexts = [];
|
|
32
|
+
const ctx = { systemPrompt: { context(def) { contexts.push(def); return () => {}; } } };
|
|
33
|
+
createInjector(ctx, service, settings, config);
|
|
34
|
+
const injectorText = (agentPreset) =>
|
|
35
|
+
contexts.find((c) => c.name === "user-settings").text(agentPreset ? { agent: { session: { header: { agentPreset } } } } : {});
|
|
36
|
+
const routes = [];
|
|
37
|
+
createApi(
|
|
38
|
+
{ webServer: { register: (route) => { routes.push(route); return () => {}; } } },
|
|
39
|
+
service,
|
|
40
|
+
settings,
|
|
41
|
+
{ add: () => {}, remove: () => {}, list: () => [] },
|
|
42
|
+
undefined,
|
|
43
|
+
undefined,
|
|
44
|
+
"",
|
|
45
|
+
config
|
|
46
|
+
);
|
|
47
|
+
const route = routes.find((r) => r.path === "/api/dsh-mneme/persona");
|
|
48
|
+
const preview = async (agent) => {
|
|
49
|
+
const res = new FakeRes();
|
|
50
|
+
await route.handler(req(`/api/dsh-mneme/persona${agent ? `?agent=${agent}` : ""}`), res);
|
|
51
|
+
return JSON.parse(res.body);
|
|
52
|
+
};
|
|
53
|
+
return { store, settings, injectorText, preview };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function seed(settings) {
|
|
57
|
+
settings.setProfile("用户是规划背景");
|
|
58
|
+
settings.setRules(["不提及用户名"]);
|
|
59
|
+
settings.setPersona({ name: "Amarre", personality: "轻松幽默", replyStyle: "先结论后展开", enabled: true });
|
|
60
|
+
settings.setPersonaFor("zephyr", { name: "泽菲尔", personality: "冷危", enabled: true });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
test("预览与注入器逐字节同源(同身份、同配置渲染两次必须一致)", async () => {
|
|
64
|
+
const { store, settings, injectorText, preview } = setup({ personaEnabled: true });
|
|
65
|
+
seed(settings);
|
|
66
|
+
for (const agent of ["zephyr", "unknown-bot", undefined]) {
|
|
67
|
+
const fromInjector = injectorText(agent);
|
|
68
|
+
const body = await preview(agent);
|
|
69
|
+
assert.equal(body.preview.text, fromInjector, `agent=${agent ?? "(无)"} 的预览必须等于注入器这一帧的输出`);
|
|
70
|
+
}
|
|
71
|
+
store.close();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("预览含表头与画像前缀,且人格行在最前(原样复刻注入文本,不是前端拼的三条)", async () => {
|
|
75
|
+
const { store, settings, preview } = setup({ personaEnabled: true });
|
|
76
|
+
seed(settings);
|
|
77
|
+
const { preview: p } = await preview();
|
|
78
|
+
assert.ok(p.text.startsWith("[用户设置] 来自 dsh-mneme 的用户画像与规则:"), "表头缺失就不是「生效文本」");
|
|
79
|
+
assert.ok(p.text.includes("- 你的人格名字:Amarre"), "人格行必须在预览里——原来那段完全没有它");
|
|
80
|
+
assert.ok(p.text.includes("- 用户画像:用户是规划背景"), "画像前缀同理");
|
|
81
|
+
assert.ok(p.text.indexOf("你的人格名字") < p.text.indexOf("用户画像:"), "顺序即优先级:人格先出、画像与规则后出");
|
|
82
|
+
assert.equal(p.source, "default", "无 agent 参数 = 按「解析不到身份」寻址");
|
|
83
|
+
// agent 是面板区分两种 default 的唯一依据:解析不到身份(null)与「身份解析到了、
|
|
84
|
+
// 但没建卡/卡被关」(回显那个身份)。少了这条断言,面板那条回落文案就没有依据。
|
|
85
|
+
assert.equal(p.agent, null);
|
|
86
|
+
store.close();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("身份解析到了却没有可用的卡:source=default 且回显该身份", async () => {
|
|
90
|
+
const { store, settings, preview } = setup({ personaEnabled: true });
|
|
91
|
+
seed(settings);
|
|
92
|
+
settings.setPersonaFor("ghost", { name: "无人格", enabled: false });
|
|
93
|
+
const { preview: p } = await preview("ghost");
|
|
94
|
+
assert.equal(p.source, "default", "默认口径下这张关掉的卡落回默认卡");
|
|
95
|
+
assert.equal(p.agent, "ghost", "但身份是解析到的——面板要靠它说「回落」而不是「解析不到」");
|
|
96
|
+
store.close();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("预览按 agent 参数寻址,并说明用的是哪张卡", async () => {
|
|
100
|
+
const { store, settings, preview } = setup({ personaEnabled: true });
|
|
101
|
+
seed(settings);
|
|
102
|
+
const hit = await preview("zephyr");
|
|
103
|
+
assert.equal(hit.preview.source, "byAgent");
|
|
104
|
+
assert.equal(hit.preview.agent, "zephyr");
|
|
105
|
+
assert.ok(hit.preview.text.includes("你的人格名字:泽菲尔"));
|
|
106
|
+
store.close();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("总闸关着时预览如实说「人格不会注入」,且不把人格行混进去", async () => {
|
|
110
|
+
const { store, settings, preview } = setup({ personaEnabled: false });
|
|
111
|
+
seed(settings);
|
|
112
|
+
const { preview: p } = await preview();
|
|
113
|
+
assert.equal(p.configGate, false, "面板要靠这个字段解释「卡开着为什么没生效」");
|
|
114
|
+
assert.ok(!p.text.includes("你的人格名字"), "预览里也不许出现实际不会注入的行");
|
|
115
|
+
assert.ok(p.text.includes("用户画像:"), "画像与规则照旧注入——闸只管人格");
|
|
116
|
+
store.close();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("strict 寻址 + 身份未命中:source=none,人格行一段都不出现", async () => {
|
|
120
|
+
const { store, settings, preview } = setup({ personaEnabled: true, personaStrictAddressing: true });
|
|
121
|
+
seed(settings);
|
|
122
|
+
const { preview: p } = await preview("unknown-bot");
|
|
123
|
+
assert.equal(p.source, "none");
|
|
124
|
+
assert.ok(!p.text.includes("Amarre"), "外部身份在严格寻址下拿不到任何人格");
|
|
125
|
+
assert.ok(p.text.includes("用户画像:"), "画像与规则不受影响");
|
|
126
|
+
store.close();
|
|
127
|
+
});
|