@modusensus/dsh-mneme 0.14.0-beta.1 → 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 -830
- package/assets/icon.svg +3 -3
- package/bin/cli.mjs +964 -964
- package/bin/dsh-mneme-choro.mjs +262 -262
- 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 -404
- 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 -3600
- 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 -14322
- package/lib/commands.js +95 -95
- package/lib/config-keys.js +144 -144
- package/lib/config.js +1361 -1344
- 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 -945
- package/lib/dream/narratives.js +44 -44
- package/lib/dream/sleep.js +2027 -2027
- package/lib/dream/triage.js +139 -139
- package/lib/dream.js +1879 -1879
- 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 -119
- package/lib/image-describe.js +158 -0
- package/lib/index.js +852 -852
- package/lib/inject.js +656 -651
- 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 -595
- 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 -3268
- package/lib/session-gate.js +91 -91
- package/lib/session-usage.js +350 -350
- package/lib/settings.js +827 -817
- 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 -5895
- 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 -267
- 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 -640
- package/lib/wiki/render.js +261 -261
- package/lib/wiki/scan.js +371 -371
- package/lib/wiki/t0.js +500 -500
- package/lib/wiki/t1-jobs.js +232 -232
- package/lib/wiki/t1.js +609 -609
- package/lib/write-admission.js +404 -404
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/package.json +1 -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 -210
- package/scripts/release-notes.mjs +164 -164
- 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 -3600
- 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 -1344
- 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 -945
- package/src/dream/narratives.js +44 -44
- package/src/dream/sleep.js +2027 -2027
- package/src/dream/triage.js +139 -139
- package/src/dream.js +1879 -1879
- 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 -119
- package/src/image-describe.js +158 -0
- package/src/index.js +852 -852
- package/src/inject.js +656 -651
- 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 -595
- 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 -3268
- package/src/session-gate.js +91 -91
- package/src/session-usage.js +350 -350
- package/src/settings.js +827 -817
- 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 -5895
- 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 -267
- 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 -640
- package/src/wiki/render.js +261 -261
- package/src/wiki/scan.js +371 -371
- package/src/wiki/t0.js +500 -500
- package/src/wiki/t1-jobs.js +232 -232
- package/src/wiki/t1.js +609 -609
- 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 -2998
- 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 -4425
- 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 -452
- package/test/conflict-ledger.test.js +242 -242
- 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 -432
- 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 -174
- 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 -333
- 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 -259
- 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 -109
- 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 -553
- 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 -90
- package/test/panel-tokens.test.js +245 -245
- 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 -156
- package/test/release-notes.test.js +265 -265
- 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 -188
- 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 -1455
- 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 -734
- package/test/wiki-claims.test.js +194 -194
- 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 -202
- package/test/wiki-queries.test.js +398 -398
- package/test/wiki-scan.test.js +208 -208
- package/test/wiki-store.test.js +190 -190
- package/test/wiki-t0.test.js +456 -456
- package/test/wiki-t1-jobs.test.js +125 -125
- package/test/wiki-t1.test.js +460 -460
- 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/lib/user-settings.js
CHANGED
|
@@ -1,230 +1,230 @@
|
|
|
1
|
-
// dsh-mneme/src/user-settings.js
|
|
2
|
-
// 「用户设置」注入块(人格 / 画像 / 自动画像事实 / 规则)的唯一渲染处。
|
|
3
|
-
//
|
|
4
|
-
// 为什么要单独成模块:面板「Agent 眼中的画像」那张卡原本自己在前端拼了一份 profile +
|
|
5
|
-
// rules 的列表,注释写着「注入生效文本」——但它没有表头、没有「- 用户画像:」前缀,
|
|
6
|
-
// 也完全没有人格三行。两处渲染代码各写各的,就一定会漂;而漂了没人报错,因为两边都
|
|
7
|
-
// 「看着像」。现在注入器与预览路由调同一个函数,前端只显示后端给的文本。
|
|
8
|
-
//
|
|
9
|
-
// 顺序是设计口径(人格设计稿⑥):特化指令(人格)先出,画像与规则后出、后写覆盖占
|
|
10
|
-
// 上风,rules 恒最硬。改这个顺序等于改提示词权重,别顺手调。自动画像事实(2026-11-06,
|
|
11
|
-
// src/profile-facts.js)插在画像之后、规则之前——它是「画像的 agent 侧补充」,与
|
|
12
|
-
// 手填画像物理分离(模型对 user_settings.profile 永远只有读权)。
|
|
13
|
-
|
|
14
|
-
import { STR, langOf } from "./lang.js";
|
|
15
|
-
|
|
16
|
-
// 事实段的注入预算(本块此前无任何截断机制——它是「身份文本」,从不轮换)。
|
|
17
|
-
// 不设上限的话,一次失控的维护轮能把每帧 systemPrompt 撑爆;行数与总字符双帽,
|
|
18
|
-
// 截断不静默(尾注如实说还剩几条,与 #164① 同一纪律)。
|
|
19
|
-
const PROFILE_FACTS_MAX_LINES = 40;
|
|
20
|
-
const PROFILE_FACTS_MAX_CHARS = 1200;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* 提示词变量转义:宿主模板插值对 `{{`/`}}` 会按变量名解析并在缺失时抛错,整轮崩掉。
|
|
24
|
-
* 所以把 2 个以上连续花括号逐字符插 `\`,让任何 `{{`/`}}` 子串都不残留;转换幂等,
|
|
25
|
-
* 单花括号原样通过。`config.escapePromptVariables === false` 时退回原文。
|
|
26
|
-
*
|
|
27
|
-
* 住在这里是刻意的:预览必须与注入共用同一个转义,否则「同源」又是假的。
|
|
28
|
-
* `src/inject.js` 的同名闭包函数只是薄薄一层委托,其余调用点不动。
|
|
29
|
-
*/
|
|
30
|
-
export function escapePromptVars(config, text) {
|
|
31
|
-
if (config?.escapePromptVariables === false) return String(text);
|
|
32
|
-
return String(text).replace(/[{}]{2,}/g, (run) => run.split("").join("\\"));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 按会话身份取人格卡。返回 `{ card, source }`,`source` 是给面板解释「用的哪张卡」的
|
|
37
|
-
* 读数,不参与判定。
|
|
38
|
-
*
|
|
39
|
-
* 寻址维度(#606 起两维,子 agent 继承再加一维共三维):`sessionId`(绑会话卡,
|
|
40
|
-
* 最具体)优先于 `parentSessionId`(子 agent 继承父会话卡),最后是 `agentId`(按预设建卡)。
|
|
41
|
-
* 理由是具体性——会话比预设更具体,而 DS Bot 这类宿主里 `agentPreset` 恒为
|
|
42
|
-
* `"standard"`(`ds-bot/src/host/roster.js:72-80` 强制写入,实测 50 个会话里 43 个是
|
|
43
|
-
* 它),若让 byAgent 优先,则谁给 `standard` 建一张卡就会盖掉所有按会话建的卡。
|
|
44
|
-
* 父会话卡排在 byAgent 之前:子 agent 自己没卡时,它属于哪段对话比它属于哪个预设
|
|
45
|
-
* 更能说明「该用谁的人格」。
|
|
46
|
-
*
|
|
47
|
-
* `strict`(config.personaStrictAddressing,默认关)决定「有身份、没这张身份的卡」
|
|
48
|
-
* 与「这张卡被显式关掉」这两种情况:
|
|
49
|
-
* - 关(现状):落 default 卡。default 于是变成「所有没建卡的 agent 都能拿到它」,
|
|
50
|
-
* 包括宿主里跑的外部 bot——它自带身份与设定,两处「你是谁」撞在同一帧里。
|
|
51
|
-
* - 开:不注入人格(`source: "none"`)。default 退回它的本意:只兜「这一帧解析不到
|
|
52
|
-
* 身份」的会话(无名会话本来就是 default 卡的受众)。
|
|
53
|
-
* 默认关是有意的:这是一次口径变更,不能让老用户的注入文本在升级后静默变化。
|
|
54
|
-
*
|
|
55
|
-
* 严格模式有一格例外(#587):两维**都没建过卡**时仍回落 default。两种处境必须
|
|
56
|
-
* 分开——「建了卡、只是没这一张的卡」是真该按 none 处理(否则关掉一张卡等于没关),
|
|
57
|
-
* 而「一张卡都没建」时 default 是用户手里唯一的一张卡,按 none 处理等于把它永久
|
|
58
|
-
* 废掉,且面板不报错。判据看两维合起来的键数(#606 起):只建了 bySession 卡时,
|
|
59
|
-
* 一个按 byAgent 寻址的会话同样不该被 default 兜底——用户已经做过分区了。
|
|
60
|
-
*/
|
|
61
|
-
export function resolvePersonaCard(
|
|
62
|
-
settings,
|
|
63
|
-
agentId,
|
|
64
|
-
{ strict = false, sessionId = null, parentSessionId = null } = {}
|
|
65
|
-
) {
|
|
66
|
-
const store = settings.getPersona();
|
|
67
|
-
const id = typeof agentId === "string" && agentId.trim() ? agentId.trim() : "";
|
|
68
|
-
const sid = typeof sessionId === "string" && sessionId.trim() ? sessionId.trim() : "";
|
|
69
|
-
const pid =
|
|
70
|
-
typeof parentSessionId === "string" && parentSessionId.trim() ? parentSessionId.trim() : "";
|
|
71
|
-
// 第一维:绑会话卡(最具体)
|
|
72
|
-
const sessionCard = sid ? store.bySession?.[sid] : null;
|
|
73
|
-
if (sessionCard && sessionCard.enabled === true) return { card: sessionCard, source: "bySession" };
|
|
74
|
-
// 第二维(子 agent 继承):自己没卡就取父会话的卡。
|
|
75
|
-
// 为什么必须有这一维:子 agent 是新会话,用户不可能给每个派生会话都建一张卡;而
|
|
76
|
-
// strict 一旦生效,「有身份、没这张身份的卡」= 不注入人格,子 agent 会从「自称父
|
|
77
|
-
// 会话的人格」变成「不知道自己是谁」——比串味更糟。继承父会话卡才是用户能预期的
|
|
78
|
-
// 语义:同一个 agent 派生出去的手脚,仍是同一个 agent。
|
|
79
|
-
// 注意与 `src/session-gate.js` 的口径区别:那里**刻意不**用 parentSession 判「是不是
|
|
80
|
-
// 子代理」(宿主 fork 出来的主会话同样带 parentSession,用它判会把主会话误关)。
|
|
81
|
-
// 这里要问的不是「你是不是子代理」而是「你自己有没有卡」,所以 fork 出的分支继承
|
|
82
|
-
// 父卡也是正确的(它就是同一段对话的副本)。父 id 与自身 id 相同(脏数据)时跳过,
|
|
83
|
-
// 免得一次寻址查两遍同一个键。
|
|
84
|
-
const parentCard = pid && pid !== sid ? store.bySession?.[pid] : null;
|
|
85
|
-
if (parentCard && parentCard.enabled === true) return { card: parentCard, source: "parentSession" };
|
|
86
|
-
// 第三维:按预设/身份建的卡
|
|
87
|
-
const card = id ? store.byAgent[id] : null;
|
|
88
|
-
if (card && card.enabled === true) return { card, source: "byAgent" };
|
|
89
|
-
// 严格模式只在「确实建过卡」时才拒绝兜底:两维都空时兜底是唯一的出路。
|
|
90
|
-
const anyCard = Object.keys(store.byAgent ?? {}).length > 0 || Object.keys(store.bySession ?? {}).length > 0;
|
|
91
|
-
// 身份判定要把父会话 id 算进来:子 agent 只有父会话 id、没有自己的卡时,也是
|
|
92
|
-
// 「确实有身份」,不许被 default 兜底。
|
|
93
|
-
if ((id || sid || pid) && strict && anyCard) return { card: {}, source: "none" };
|
|
94
|
-
return { card: store.default, source: "default" };
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* 按会话身份取自动事实卡(resolvePersonaCard 的镜像,形状不同:facts 没有
|
|
99
|
-
* enabled 位,「卡存在」就是非空数组)。strict 语义与人格一致:有身份但没这张
|
|
100
|
-
* 身份的卡时不落 default——两个 bot 对用户的认知不互串是 store 层分区(输入行)
|
|
101
|
-
* 与本层寻址(输出注入)共同守住的边界。与人格同一条例外(#587):`byAgent` 整体
|
|
102
|
-
* 为空时仍落 default,「一张都没建」不等于「这一张没建」。
|
|
103
|
-
*/
|
|
104
|
-
export function resolveFactsCard(factsStore, agentId, { strict = false } = {}) {
|
|
105
|
-
const id = typeof agentId === "string" && agentId.trim() ? agentId.trim() : "";
|
|
106
|
-
const byAgent = factsStore?.byAgent ?? {};
|
|
107
|
-
const card = id ? (byAgent[id] ?? null) : null;
|
|
108
|
-
if (card && card.length) return { facts: card, source: "byAgent" };
|
|
109
|
-
if (id && strict && Object.keys(byAgent).length > 0) return { facts: [], source: "none" };
|
|
110
|
-
return { facts: factsStore?.default ?? [], source: "default" };
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* 渲染整块「用户设置」。`agentId` 是会话身份(解析不到传 null → 走 default 兜底),
|
|
115
|
-
* `sessionId` 是绑会话卡的键(#606;解析不到传 null)。
|
|
116
|
-
* `factsProvider` 是 profile-facts 域的读口(返回 `{ default: [...], byAgent: {...} }`),
|
|
117
|
-
* 可选;**开关与 provider 双闸**——profileFactsEnabled 关着时连 provider 都不调,
|
|
118
|
-
* 「关」必须是零读数而不是「读了不渲染」。返回 `{ text, source, agent, session, configGate }`:
|
|
119
|
-
* `text` 为最终注入文本(全空时 ""),`configGate` 是 personaEnabled 的现值——面板
|
|
120
|
-
* 要靠它解释「卡开着为什么没生效」。
|
|
121
|
-
*/
|
|
122
|
-
export function renderUserSettingsBlock({
|
|
123
|
-
settings,
|
|
124
|
-
config,
|
|
125
|
-
agentId = null,
|
|
126
|
-
sessionId = null,
|
|
127
|
-
parentSessionId = null,
|
|
128
|
-
factsProvider = null
|
|
129
|
-
}) {
|
|
130
|
-
const language = langOf(config);
|
|
131
|
-
const profile = settings.getProfile().trim();
|
|
132
|
-
const rules = settings.getRules();
|
|
133
|
-
const enabled = config?.personaEnabled === true;
|
|
134
|
-
const strict = config?.personaStrictAddressing === true;
|
|
135
|
-
const resolved = enabled
|
|
136
|
-
? resolvePersonaCard(settings, agentId, { strict, sessionId, parentSessionId })
|
|
137
|
-
: { card: {}, source: "default" };
|
|
138
|
-
const persona = resolved.card;
|
|
139
|
-
// 段(#600):每一行都带上它的 kind 与写回所需的定位信息,供面板按段读、按段改。
|
|
140
|
-
// 段文本是**未转义**的原样行;整串 `text` 仍走原来的「先 join 再统一转义」,
|
|
141
|
-
// 所以注入字节不变(转义只动连续花括号,换行不参与,逐段转义与整串转义等价)。
|
|
142
|
-
//
|
|
143
|
-
// `text` 是**带模板前缀的整行**(如 `- 用户画像:xxx`),不能拿去当新值回写,
|
|
144
|
-
// 否则每写一次叠一层前缀。可回写的段另带 `value`=原始值(无前缀、未转义);
|
|
145
|
-
// 没有原始值的段(表头、事实表头、截断尾注)不带 `value` 键。
|
|
146
|
-
const personaLines = [];
|
|
147
|
-
if (persona?.enabled === true) {
|
|
148
|
-
if (typeof persona.name === "string" && persona.name.trim()) {
|
|
149
|
-
const value = persona.name.trim();
|
|
150
|
-
personaLines.push({ kind: "personaName", field: "name", value, text: STR.personaNameLine[language](value) });
|
|
151
|
-
}
|
|
152
|
-
if (typeof persona.personality === "string" && persona.personality.trim()) {
|
|
153
|
-
const value = persona.personality.trim();
|
|
154
|
-
personaLines.push({ kind: "personaPersonality", field: "personality", value, text: STR.personaPersonalityLine[language](value) });
|
|
155
|
-
}
|
|
156
|
-
if (typeof persona.replyStyle === "string" && persona.replyStyle.trim()) {
|
|
157
|
-
const value = persona.replyStyle.trim();
|
|
158
|
-
personaLines.push({ kind: "personaReplyStyle", field: "replyStyle", value, text: STR.personaReplyStyleLine[language](value) });
|
|
159
|
-
}
|
|
160
|
-
// scenario / mesExample(#606):只有设置了才输出,未设置时本块逐字节不变。
|
|
161
|
-
if (typeof persona.scenario === "string" && persona.scenario.trim()) {
|
|
162
|
-
const value = persona.scenario.trim();
|
|
163
|
-
personaLines.push({ kind: "personaScenario", field: "scenario", value, text: STR.personaScenarioLine[language](value) });
|
|
164
|
-
}
|
|
165
|
-
if (typeof persona.mesExample === "string" && persona.mesExample.trim()) {
|
|
166
|
-
const value = persona.mesExample.trim();
|
|
167
|
-
personaLines.push({ kind: "personaMesExample", field: "mesExample", value, text: STR.personaMesExampleLine[language](value) });
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
// 事实段:开关关 / 无 provider / 该卡没事实三种情况都不渲染,注入文本与
|
|
171
|
-
// 未启用事实时逐字节一致(老用户零变化)。
|
|
172
|
-
const factsResolved = config?.profileFactsEnabled === true && typeof factsProvider === "function"
|
|
173
|
-
? resolveFactsCard(factsProvider(), agentId, { strict })
|
|
174
|
-
: { facts: [], source: "none" };
|
|
175
|
-
const factLines = [];
|
|
176
|
-
if (factsResolved.facts.length) {
|
|
177
|
-
let chars = 0;
|
|
178
|
-
let shown = 0;
|
|
179
|
-
for (const fact of factsResolved.facts) {
|
|
180
|
-
const value = String(fact);
|
|
181
|
-
const line = STR.profileFactLine[language](value);
|
|
182
|
-
if (shown >= PROFILE_FACTS_MAX_LINES || chars + line.length > PROFILE_FACTS_MAX_CHARS) break;
|
|
183
|
-
factLines.push({ kind: "fact", index: shown, value, text: line });
|
|
184
|
-
chars += line.length;
|
|
185
|
-
shown += 1;
|
|
186
|
-
}
|
|
187
|
-
const remaining = factsResolved.facts.length - shown;
|
|
188
|
-
if (remaining > 0) factLines.push({ kind: "factsTruncated", remaining, text: STR.profileFactsTruncated[language](remaining) });
|
|
189
|
-
if (factLines.length) {
|
|
190
|
-
// 表头的 n 是**总条数**(含没注入的),与「另有 N 条未注入」互补,别改成 shown。
|
|
191
|
-
factLines.unshift({
|
|
192
|
-
kind: "factsHeader",
|
|
193
|
-
shown,
|
|
194
|
-
total: factsResolved.facts.length,
|
|
195
|
-
text: STR.profileFactsHeader[language](factsResolved.facts.length)
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
const id = typeof agentId === "string" && agentId.trim() ? agentId.trim() : null;
|
|
200
|
-
const sid = typeof sessionId === "string" && sessionId.trim() ? sessionId.trim() : null;
|
|
201
|
-
const pid =
|
|
202
|
-
typeof parentSessionId === "string" && parentSessionId.trim() ? parentSessionId.trim() : null;
|
|
203
|
-
if (!profile && !rules.length && !personaLines.length && !factLines.length) {
|
|
204
|
-
// `parent` 是读数(面板要能说清「这张卡是从父会话继承来的」),不参与判定。
|
|
205
|
-
return {
|
|
206
|
-
text: "",
|
|
207
|
-
segments: [],
|
|
208
|
-
source: resolved.source,
|
|
209
|
-
agent: id,
|
|
210
|
-
session: sid,
|
|
211
|
-
parent: pid,
|
|
212
|
-
configGate: enabled
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
const segments = [{ kind: "header", text: STR.userSettingsHeader[language] }];
|
|
216
|
-
segments.push(...personaLines);
|
|
217
|
-
if (profile) segments.push({ kind: "profile", value: profile, text: STR.profileLine[language](profile) });
|
|
218
|
-
segments.push(...factLines);
|
|
219
|
-
for (const rule of rules) segments.push({ kind: "rule", value: rule, text: STR.ruleLine[language](rule) });
|
|
220
|
-
const lines = segments.map((s) => s.text);
|
|
221
|
-
return {
|
|
222
|
-
text: escapePromptVars(config, lines.join("\n")),
|
|
223
|
-
segments,
|
|
224
|
-
source: resolved.source,
|
|
225
|
-
agent: id,
|
|
226
|
-
session: sid,
|
|
227
|
-
parent: pid,
|
|
228
|
-
configGate: enabled
|
|
229
|
-
};
|
|
230
|
-
}
|
|
1
|
+
// dsh-mneme/src/user-settings.js
|
|
2
|
+
// 「用户设置」注入块(人格 / 画像 / 自动画像事实 / 规则)的唯一渲染处。
|
|
3
|
+
//
|
|
4
|
+
// 为什么要单独成模块:面板「Agent 眼中的画像」那张卡原本自己在前端拼了一份 profile +
|
|
5
|
+
// rules 的列表,注释写着「注入生效文本」——但它没有表头、没有「- 用户画像:」前缀,
|
|
6
|
+
// 也完全没有人格三行。两处渲染代码各写各的,就一定会漂;而漂了没人报错,因为两边都
|
|
7
|
+
// 「看着像」。现在注入器与预览路由调同一个函数,前端只显示后端给的文本。
|
|
8
|
+
//
|
|
9
|
+
// 顺序是设计口径(人格设计稿⑥):特化指令(人格)先出,画像与规则后出、后写覆盖占
|
|
10
|
+
// 上风,rules 恒最硬。改这个顺序等于改提示词权重,别顺手调。自动画像事实(2026-11-06,
|
|
11
|
+
// src/profile-facts.js)插在画像之后、规则之前——它是「画像的 agent 侧补充」,与
|
|
12
|
+
// 手填画像物理分离(模型对 user_settings.profile 永远只有读权)。
|
|
13
|
+
|
|
14
|
+
import { STR, langOf } from "./lang.js";
|
|
15
|
+
|
|
16
|
+
// 事实段的注入预算(本块此前无任何截断机制——它是「身份文本」,从不轮换)。
|
|
17
|
+
// 不设上限的话,一次失控的维护轮能把每帧 systemPrompt 撑爆;行数与总字符双帽,
|
|
18
|
+
// 截断不静默(尾注如实说还剩几条,与 #164① 同一纪律)。
|
|
19
|
+
const PROFILE_FACTS_MAX_LINES = 40;
|
|
20
|
+
const PROFILE_FACTS_MAX_CHARS = 1200;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 提示词变量转义:宿主模板插值对 `{{`/`}}` 会按变量名解析并在缺失时抛错,整轮崩掉。
|
|
24
|
+
* 所以把 2 个以上连续花括号逐字符插 `\`,让任何 `{{`/`}}` 子串都不残留;转换幂等,
|
|
25
|
+
* 单花括号原样通过。`config.escapePromptVariables === false` 时退回原文。
|
|
26
|
+
*
|
|
27
|
+
* 住在这里是刻意的:预览必须与注入共用同一个转义,否则「同源」又是假的。
|
|
28
|
+
* `src/inject.js` 的同名闭包函数只是薄薄一层委托,其余调用点不动。
|
|
29
|
+
*/
|
|
30
|
+
export function escapePromptVars(config, text) {
|
|
31
|
+
if (config?.escapePromptVariables === false) return String(text);
|
|
32
|
+
return String(text).replace(/[{}]{2,}/g, (run) => run.split("").join("\\"));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 按会话身份取人格卡。返回 `{ card, source }`,`source` 是给面板解释「用的哪张卡」的
|
|
37
|
+
* 读数,不参与判定。
|
|
38
|
+
*
|
|
39
|
+
* 寻址维度(#606 起两维,子 agent 继承再加一维共三维):`sessionId`(绑会话卡,
|
|
40
|
+
* 最具体)优先于 `parentSessionId`(子 agent 继承父会话卡),最后是 `agentId`(按预设建卡)。
|
|
41
|
+
* 理由是具体性——会话比预设更具体,而 DS Bot 这类宿主里 `agentPreset` 恒为
|
|
42
|
+
* `"standard"`(`ds-bot/src/host/roster.js:72-80` 强制写入,实测 50 个会话里 43 个是
|
|
43
|
+
* 它),若让 byAgent 优先,则谁给 `standard` 建一张卡就会盖掉所有按会话建的卡。
|
|
44
|
+
* 父会话卡排在 byAgent 之前:子 agent 自己没卡时,它属于哪段对话比它属于哪个预设
|
|
45
|
+
* 更能说明「该用谁的人格」。
|
|
46
|
+
*
|
|
47
|
+
* `strict`(config.personaStrictAddressing,默认关)决定「有身份、没这张身份的卡」
|
|
48
|
+
* 与「这张卡被显式关掉」这两种情况:
|
|
49
|
+
* - 关(现状):落 default 卡。default 于是变成「所有没建卡的 agent 都能拿到它」,
|
|
50
|
+
* 包括宿主里跑的外部 bot——它自带身份与设定,两处「你是谁」撞在同一帧里。
|
|
51
|
+
* - 开:不注入人格(`source: "none"`)。default 退回它的本意:只兜「这一帧解析不到
|
|
52
|
+
* 身份」的会话(无名会话本来就是 default 卡的受众)。
|
|
53
|
+
* 默认关是有意的:这是一次口径变更,不能让老用户的注入文本在升级后静默变化。
|
|
54
|
+
*
|
|
55
|
+
* 严格模式有一格例外(#587):两维**都没建过卡**时仍回落 default。两种处境必须
|
|
56
|
+
* 分开——「建了卡、只是没这一张的卡」是真该按 none 处理(否则关掉一张卡等于没关),
|
|
57
|
+
* 而「一张卡都没建」时 default 是用户手里唯一的一张卡,按 none 处理等于把它永久
|
|
58
|
+
* 废掉,且面板不报错。判据看两维合起来的键数(#606 起):只建了 bySession 卡时,
|
|
59
|
+
* 一个按 byAgent 寻址的会话同样不该被 default 兜底——用户已经做过分区了。
|
|
60
|
+
*/
|
|
61
|
+
export function resolvePersonaCard(
|
|
62
|
+
settings,
|
|
63
|
+
agentId,
|
|
64
|
+
{ strict = false, sessionId = null, parentSessionId = null } = {}
|
|
65
|
+
) {
|
|
66
|
+
const store = settings.getPersona();
|
|
67
|
+
const id = typeof agentId === "string" && agentId.trim() ? agentId.trim() : "";
|
|
68
|
+
const sid = typeof sessionId === "string" && sessionId.trim() ? sessionId.trim() : "";
|
|
69
|
+
const pid =
|
|
70
|
+
typeof parentSessionId === "string" && parentSessionId.trim() ? parentSessionId.trim() : "";
|
|
71
|
+
// 第一维:绑会话卡(最具体)
|
|
72
|
+
const sessionCard = sid ? store.bySession?.[sid] : null;
|
|
73
|
+
if (sessionCard && sessionCard.enabled === true) return { card: sessionCard, source: "bySession" };
|
|
74
|
+
// 第二维(子 agent 继承):自己没卡就取父会话的卡。
|
|
75
|
+
// 为什么必须有这一维:子 agent 是新会话,用户不可能给每个派生会话都建一张卡;而
|
|
76
|
+
// strict 一旦生效,「有身份、没这张身份的卡」= 不注入人格,子 agent 会从「自称父
|
|
77
|
+
// 会话的人格」变成「不知道自己是谁」——比串味更糟。继承父会话卡才是用户能预期的
|
|
78
|
+
// 语义:同一个 agent 派生出去的手脚,仍是同一个 agent。
|
|
79
|
+
// 注意与 `src/session-gate.js` 的口径区别:那里**刻意不**用 parentSession 判「是不是
|
|
80
|
+
// 子代理」(宿主 fork 出来的主会话同样带 parentSession,用它判会把主会话误关)。
|
|
81
|
+
// 这里要问的不是「你是不是子代理」而是「你自己有没有卡」,所以 fork 出的分支继承
|
|
82
|
+
// 父卡也是正确的(它就是同一段对话的副本)。父 id 与自身 id 相同(脏数据)时跳过,
|
|
83
|
+
// 免得一次寻址查两遍同一个键。
|
|
84
|
+
const parentCard = pid && pid !== sid ? store.bySession?.[pid] : null;
|
|
85
|
+
if (parentCard && parentCard.enabled === true) return { card: parentCard, source: "parentSession" };
|
|
86
|
+
// 第三维:按预设/身份建的卡
|
|
87
|
+
const card = id ? store.byAgent[id] : null;
|
|
88
|
+
if (card && card.enabled === true) return { card, source: "byAgent" };
|
|
89
|
+
// 严格模式只在「确实建过卡」时才拒绝兜底:两维都空时兜底是唯一的出路。
|
|
90
|
+
const anyCard = Object.keys(store.byAgent ?? {}).length > 0 || Object.keys(store.bySession ?? {}).length > 0;
|
|
91
|
+
// 身份判定要把父会话 id 算进来:子 agent 只有父会话 id、没有自己的卡时,也是
|
|
92
|
+
// 「确实有身份」,不许被 default 兜底。
|
|
93
|
+
if ((id || sid || pid) && strict && anyCard) return { card: {}, source: "none" };
|
|
94
|
+
return { card: store.default, source: "default" };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 按会话身份取自动事实卡(resolvePersonaCard 的镜像,形状不同:facts 没有
|
|
99
|
+
* enabled 位,「卡存在」就是非空数组)。strict 语义与人格一致:有身份但没这张
|
|
100
|
+
* 身份的卡时不落 default——两个 bot 对用户的认知不互串是 store 层分区(输入行)
|
|
101
|
+
* 与本层寻址(输出注入)共同守住的边界。与人格同一条例外(#587):`byAgent` 整体
|
|
102
|
+
* 为空时仍落 default,「一张都没建」不等于「这一张没建」。
|
|
103
|
+
*/
|
|
104
|
+
export function resolveFactsCard(factsStore, agentId, { strict = false } = {}) {
|
|
105
|
+
const id = typeof agentId === "string" && agentId.trim() ? agentId.trim() : "";
|
|
106
|
+
const byAgent = factsStore?.byAgent ?? {};
|
|
107
|
+
const card = id ? (byAgent[id] ?? null) : null;
|
|
108
|
+
if (card && card.length) return { facts: card, source: "byAgent" };
|
|
109
|
+
if (id && strict && Object.keys(byAgent).length > 0) return { facts: [], source: "none" };
|
|
110
|
+
return { facts: factsStore?.default ?? [], source: "default" };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* 渲染整块「用户设置」。`agentId` 是会话身份(解析不到传 null → 走 default 兜底),
|
|
115
|
+
* `sessionId` 是绑会话卡的键(#606;解析不到传 null)。
|
|
116
|
+
* `factsProvider` 是 profile-facts 域的读口(返回 `{ default: [...], byAgent: {...} }`),
|
|
117
|
+
* 可选;**开关与 provider 双闸**——profileFactsEnabled 关着时连 provider 都不调,
|
|
118
|
+
* 「关」必须是零读数而不是「读了不渲染」。返回 `{ text, source, agent, session, configGate }`:
|
|
119
|
+
* `text` 为最终注入文本(全空时 ""),`configGate` 是 personaEnabled 的现值——面板
|
|
120
|
+
* 要靠它解释「卡开着为什么没生效」。
|
|
121
|
+
*/
|
|
122
|
+
export function renderUserSettingsBlock({
|
|
123
|
+
settings,
|
|
124
|
+
config,
|
|
125
|
+
agentId = null,
|
|
126
|
+
sessionId = null,
|
|
127
|
+
parentSessionId = null,
|
|
128
|
+
factsProvider = null
|
|
129
|
+
}) {
|
|
130
|
+
const language = langOf(config);
|
|
131
|
+
const profile = settings.getProfile().trim();
|
|
132
|
+
const rules = settings.getRules();
|
|
133
|
+
const enabled = config?.personaEnabled === true;
|
|
134
|
+
const strict = config?.personaStrictAddressing === true;
|
|
135
|
+
const resolved = enabled
|
|
136
|
+
? resolvePersonaCard(settings, agentId, { strict, sessionId, parentSessionId })
|
|
137
|
+
: { card: {}, source: "default" };
|
|
138
|
+
const persona = resolved.card;
|
|
139
|
+
// 段(#600):每一行都带上它的 kind 与写回所需的定位信息,供面板按段读、按段改。
|
|
140
|
+
// 段文本是**未转义**的原样行;整串 `text` 仍走原来的「先 join 再统一转义」,
|
|
141
|
+
// 所以注入字节不变(转义只动连续花括号,换行不参与,逐段转义与整串转义等价)。
|
|
142
|
+
//
|
|
143
|
+
// `text` 是**带模板前缀的整行**(如 `- 用户画像:xxx`),不能拿去当新值回写,
|
|
144
|
+
// 否则每写一次叠一层前缀。可回写的段另带 `value`=原始值(无前缀、未转义);
|
|
145
|
+
// 没有原始值的段(表头、事实表头、截断尾注)不带 `value` 键。
|
|
146
|
+
const personaLines = [];
|
|
147
|
+
if (persona?.enabled === true) {
|
|
148
|
+
if (typeof persona.name === "string" && persona.name.trim()) {
|
|
149
|
+
const value = persona.name.trim();
|
|
150
|
+
personaLines.push({ kind: "personaName", field: "name", value, text: STR.personaNameLine[language](value) });
|
|
151
|
+
}
|
|
152
|
+
if (typeof persona.personality === "string" && persona.personality.trim()) {
|
|
153
|
+
const value = persona.personality.trim();
|
|
154
|
+
personaLines.push({ kind: "personaPersonality", field: "personality", value, text: STR.personaPersonalityLine[language](value) });
|
|
155
|
+
}
|
|
156
|
+
if (typeof persona.replyStyle === "string" && persona.replyStyle.trim()) {
|
|
157
|
+
const value = persona.replyStyle.trim();
|
|
158
|
+
personaLines.push({ kind: "personaReplyStyle", field: "replyStyle", value, text: STR.personaReplyStyleLine[language](value) });
|
|
159
|
+
}
|
|
160
|
+
// scenario / mesExample(#606):只有设置了才输出,未设置时本块逐字节不变。
|
|
161
|
+
if (typeof persona.scenario === "string" && persona.scenario.trim()) {
|
|
162
|
+
const value = persona.scenario.trim();
|
|
163
|
+
personaLines.push({ kind: "personaScenario", field: "scenario", value, text: STR.personaScenarioLine[language](value) });
|
|
164
|
+
}
|
|
165
|
+
if (typeof persona.mesExample === "string" && persona.mesExample.trim()) {
|
|
166
|
+
const value = persona.mesExample.trim();
|
|
167
|
+
personaLines.push({ kind: "personaMesExample", field: "mesExample", value, text: STR.personaMesExampleLine[language](value) });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// 事实段:开关关 / 无 provider / 该卡没事实三种情况都不渲染,注入文本与
|
|
171
|
+
// 未启用事实时逐字节一致(老用户零变化)。
|
|
172
|
+
const factsResolved = config?.profileFactsEnabled === true && typeof factsProvider === "function"
|
|
173
|
+
? resolveFactsCard(factsProvider(), agentId, { strict })
|
|
174
|
+
: { facts: [], source: "none" };
|
|
175
|
+
const factLines = [];
|
|
176
|
+
if (factsResolved.facts.length) {
|
|
177
|
+
let chars = 0;
|
|
178
|
+
let shown = 0;
|
|
179
|
+
for (const fact of factsResolved.facts) {
|
|
180
|
+
const value = String(fact);
|
|
181
|
+
const line = STR.profileFactLine[language](value);
|
|
182
|
+
if (shown >= PROFILE_FACTS_MAX_LINES || chars + line.length > PROFILE_FACTS_MAX_CHARS) break;
|
|
183
|
+
factLines.push({ kind: "fact", index: shown, value, text: line });
|
|
184
|
+
chars += line.length;
|
|
185
|
+
shown += 1;
|
|
186
|
+
}
|
|
187
|
+
const remaining = factsResolved.facts.length - shown;
|
|
188
|
+
if (remaining > 0) factLines.push({ kind: "factsTruncated", remaining, text: STR.profileFactsTruncated[language](remaining) });
|
|
189
|
+
if (factLines.length) {
|
|
190
|
+
// 表头的 n 是**总条数**(含没注入的),与「另有 N 条未注入」互补,别改成 shown。
|
|
191
|
+
factLines.unshift({
|
|
192
|
+
kind: "factsHeader",
|
|
193
|
+
shown,
|
|
194
|
+
total: factsResolved.facts.length,
|
|
195
|
+
text: STR.profileFactsHeader[language](factsResolved.facts.length)
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const id = typeof agentId === "string" && agentId.trim() ? agentId.trim() : null;
|
|
200
|
+
const sid = typeof sessionId === "string" && sessionId.trim() ? sessionId.trim() : null;
|
|
201
|
+
const pid =
|
|
202
|
+
typeof parentSessionId === "string" && parentSessionId.trim() ? parentSessionId.trim() : null;
|
|
203
|
+
if (!profile && !rules.length && !personaLines.length && !factLines.length) {
|
|
204
|
+
// `parent` 是读数(面板要能说清「这张卡是从父会话继承来的」),不参与判定。
|
|
205
|
+
return {
|
|
206
|
+
text: "",
|
|
207
|
+
segments: [],
|
|
208
|
+
source: resolved.source,
|
|
209
|
+
agent: id,
|
|
210
|
+
session: sid,
|
|
211
|
+
parent: pid,
|
|
212
|
+
configGate: enabled
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
const segments = [{ kind: "header", text: STR.userSettingsHeader[language] }];
|
|
216
|
+
segments.push(...personaLines);
|
|
217
|
+
if (profile) segments.push({ kind: "profile", value: profile, text: STR.profileLine[language](profile) });
|
|
218
|
+
segments.push(...factLines);
|
|
219
|
+
for (const rule of rules) segments.push({ kind: "rule", value: rule, text: STR.ruleLine[language](rule) });
|
|
220
|
+
const lines = segments.map((s) => s.text);
|
|
221
|
+
return {
|
|
222
|
+
text: escapePromptVars(config, lines.join("\n")),
|
|
223
|
+
segments,
|
|
224
|
+
source: resolved.source,
|
|
225
|
+
agent: id,
|
|
226
|
+
session: sid,
|
|
227
|
+
parent: pid,
|
|
228
|
+
configGate: enabled
|
|
229
|
+
};
|
|
230
|
+
}
|