@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
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
import test from "node:test";
|
|
2
|
-
import assert from "node:assert/strict";
|
|
3
|
-
import { createStore } from "../src/store.js";
|
|
4
|
-
import { createService } from "../src/service.js";
|
|
5
|
-
import { createSummarizer, parseSummaryJson } from "../src/summarize.js";
|
|
6
|
-
|
|
7
|
-
// 蒸馏的时间锚定(SimpleMem,arXiv 2601.02553:抽取与时间锚定在同一次生成里完成,
|
|
8
|
-
// 消融去掉后时间类问题 F1 掉 56.7%)。这组用例防的是三类回归:
|
|
9
|
-
// 1) occurred_at 在解析层被吞掉(历史形状里没有这个字段,改 prompt 时容易只改
|
|
10
|
-
// 提示词、忘记映射);
|
|
11
|
-
// 2) 解析不出来的时间被写成 null / "" 而不是省略键——空值会被下游当成「已锚定」,
|
|
12
|
-
// 污染 occurred_from/occurred_to 过滤与时间排序;
|
|
13
|
-
// 3) 模型瞎填的未来时间原样落库(store.normalizeOccurredAt 只判可解析性,拦不住)。
|
|
14
|
-
// 时间一律按「相对当下」构造:锁死某个日期会让用例在时钟走过该日期后变成反向断言。
|
|
15
|
-
const HOUR_MS = 3600 * 1000;
|
|
16
|
-
const DAY_MS = 24 * HOUR_MS;
|
|
17
|
-
|
|
18
|
-
/** 带 +08:00 偏移的同刻 ISO 写法:证明归一真的解析过时区,而不是原样搬运字符串。 */
|
|
19
|
-
function isoWithOffset(ms) {
|
|
20
|
-
return `${new Date(ms + 8 * HOUR_MS).toISOString().slice(0, 23)}+08:00`;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function setup(entries, deps = {}) {
|
|
24
|
-
const store = createStore(":memory:");
|
|
25
|
-
const service = createService({ store, mirror: null, config: {} });
|
|
26
|
-
const events = [];
|
|
27
|
-
const calls = [];
|
|
28
|
-
const ctx = {
|
|
29
|
-
on(name, fn) {
|
|
30
|
-
events.push({ name, fn });
|
|
31
|
-
return () => {
|
|
32
|
-
const i = events.findIndex((e) => e.name === name && e.fn === fn);
|
|
33
|
-
if (i !== -1) events.splice(i, 1);
|
|
34
|
-
};
|
|
35
|
-
},
|
|
36
|
-
llm: {
|
|
37
|
-
stream(options) {
|
|
38
|
-
calls.push(options);
|
|
39
|
-
const json = JSON.stringify(entries);
|
|
40
|
-
return (async function* () {
|
|
41
|
-
yield { type: "block-start", block: { type: "text" } };
|
|
42
|
-
yield { type: "text-delta", delta: json };
|
|
43
|
-
yield { type: "block-end", block: { type: "text" } };
|
|
44
|
-
yield { type: "finish", kind: "ok" };
|
|
45
|
-
})();
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
createSummarizer(ctx, service, { autoSummarize: true }, deps);
|
|
50
|
-
return { store, service, calls, handler: events.find((e) => e.name === "session/event").fn };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function turnEndSession(text = "上周把 occurred_at 接进蒸馏链路") {
|
|
54
|
-
return {
|
|
55
|
-
id: "s-time",
|
|
56
|
-
requestHeader: () => ({ config: { provider: "deepseek", model: "deepseek-chat" } }),
|
|
57
|
-
events: [
|
|
58
|
-
{ type: "user/message", data: { source: { kind: "user" }, content: [{ type: "text", text }] } },
|
|
59
|
-
{ seq: 2, type: "turn/end" }
|
|
60
|
-
]
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
test("parseSummaryJson keeps a parseable occurred_at, normalized to UTC ISO", () => {
|
|
65
|
-
const past = Date.now() - 30 * DAY_MS;
|
|
66
|
-
const parsed = parseSummaryJson(JSON.stringify([
|
|
67
|
-
{ type: "history", title: "时间锚定", content: "上周把 occurred_at 接进蒸馏", importance: 2, occurred_at: isoWithOffset(past) }
|
|
68
|
-
]));
|
|
69
|
-
assert.equal(parsed.length, 1);
|
|
70
|
-
assert.equal(parsed[0].occurred_at, new Date(past).toISOString(), "带偏移的绝对时间归一为 UTC ISO");
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test("parseSummaryJson omits occurred_at when it is unparseable, non-string, or beyond the 1-day future tolerance", () => {
|
|
74
|
-
const now = Date.now();
|
|
75
|
-
const parsed = parseSummaryJson(JSON.stringify([
|
|
76
|
-
{ type: "history", title: "脏字符串", content: "模型给了自然语言时间", importance: 2, occurred_at: "昨天下午" },
|
|
77
|
-
{ type: "history", title: "空白串", content: "模型给了空串", importance: 2, occurred_at: " " },
|
|
78
|
-
{ type: "history", title: "非字符串", content: "模型给了 epoch 数字", importance: 2, occurred_at: 1757000000000 },
|
|
79
|
-
{ type: "history", title: "未来时间", content: "模型编了个两年后的时间", importance: 2, occurred_at: new Date(now + 730 * DAY_MS).toISOString() },
|
|
80
|
-
{ type: "history", title: "略晚于当下", content: "时区/时钟偏移内的未来时间", importance: 2, occurred_at: new Date(now + HOUR_MS).toISOString() },
|
|
81
|
-
{ type: "history", title: "没给时间", content: "最普通的条目", importance: 2 }
|
|
82
|
-
]));
|
|
83
|
-
assert.equal(parsed.length, 6);
|
|
84
|
-
for (const i of [0, 1, 2, 3, 5]) {
|
|
85
|
-
assert.equal("occurred_at" in parsed[i], false, `${parsed[i].title}:必须整条省略该键(不是 null、不是空串)`);
|
|
86
|
-
}
|
|
87
|
-
// 1 天容忍内的未来时间保留:真实时钟与模型给出的时区写法会有小时级偏差,不是瞎填。
|
|
88
|
-
assert.equal(parsed[4].occurred_at, new Date(now + HOUR_MS).toISOString(), "容忍窗口内的时间照常保留");
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test("distilled occurred_at is visible in the store, dirty/future values are dropped", async () => {
|
|
92
|
-
const past = Date.now() - 3 * HOUR_MS;
|
|
93
|
-
const { store, handler } = setup([
|
|
94
|
-
{ type: "decision", title: "时间锚定", content: "蒸馏产物带绝对时间 occurred_at", importance: 4, occurred_at: isoWithOffset(past) },
|
|
95
|
-
{ type: "history", title: "脏时间", content: "模型给了不可解析的时间", importance: 2, occurred_at: "上周三" },
|
|
96
|
-
{ type: "history", title: "未来时间", content: "模型编了个两年后的时间", importance: 2, occurred_at: new Date(Date.now() + 730 * DAY_MS).toISOString() },
|
|
97
|
-
{ type: "history", title: "无时间", content: "条目里根本没有时间依据", importance: 2 }
|
|
98
|
-
]);
|
|
99
|
-
await handler(turnEndSession(), { seq: 2, type: "turn/end" });
|
|
100
|
-
|
|
101
|
-
const rows = store.all();
|
|
102
|
-
const byTitle = (title) => {
|
|
103
|
-
const row = rows.find((r) => r.title === title);
|
|
104
|
-
assert.ok(row, `记忆「${title}」应当落库`);
|
|
105
|
-
return row;
|
|
106
|
-
};
|
|
107
|
-
// 落库可见:解析层的归一值原样进 memories.occurred_at(saveWithDedupe 普通路径)。
|
|
108
|
-
assert.equal(byTitle("时间锚定").occurred_at, new Date(past).toISOString());
|
|
109
|
-
// 丢弃:不可解析与超容忍的未来时间都不落列(NULL),不是字符串化后硬存。
|
|
110
|
-
assert.equal(byTitle("脏时间").occurred_at, undefined);
|
|
111
|
-
assert.equal(byTitle("未来时间").occurred_at, undefined);
|
|
112
|
-
assert.equal(byTitle("无时间").occurred_at, undefined);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test("the distill system prompt carries the wall-clock anchor relative times are converted against", async () => {
|
|
116
|
-
const fixed = new Date("2026-05-04T03:02:01.000Z");
|
|
117
|
-
const { calls, handler } = setup([
|
|
118
|
-
{ type: "history", title: "锚点", content: "会话里只说了「昨天」", importance: 2 }
|
|
119
|
-
], { now: () => fixed.getTime() });
|
|
120
|
-
await handler(turnEndSession("昨天部署了 v0.8.4"), { seq: 2, type: "turn/end" });
|
|
121
|
-
|
|
122
|
-
const system = calls[0].messages.find((m) => m.role === "system")?.content?.[0]?.text ?? "";
|
|
123
|
-
assert.ok(system.includes("occurred_at"), "系统提示的形状串里给出可选时间字段");
|
|
124
|
-
assert.ok(system.includes("严格") || system.includes("严禁编造"), "提示词写明编造禁令");
|
|
125
|
-
// 锚点取自可注入时钟:没有它,「昨天」永远换算不出绝对值。
|
|
126
|
-
assert.ok(system.includes(`当前时间:${fixed.toISOString()}`), "系统提示末尾带上会话发生时间");
|
|
127
|
-
});
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { createStore } from "../src/store.js";
|
|
4
|
+
import { createService } from "../src/service.js";
|
|
5
|
+
import { createSummarizer, parseSummaryJson } from "../src/summarize.js";
|
|
6
|
+
|
|
7
|
+
// 蒸馏的时间锚定(SimpleMem,arXiv 2601.02553:抽取与时间锚定在同一次生成里完成,
|
|
8
|
+
// 消融去掉后时间类问题 F1 掉 56.7%)。这组用例防的是三类回归:
|
|
9
|
+
// 1) occurred_at 在解析层被吞掉(历史形状里没有这个字段,改 prompt 时容易只改
|
|
10
|
+
// 提示词、忘记映射);
|
|
11
|
+
// 2) 解析不出来的时间被写成 null / "" 而不是省略键——空值会被下游当成「已锚定」,
|
|
12
|
+
// 污染 occurred_from/occurred_to 过滤与时间排序;
|
|
13
|
+
// 3) 模型瞎填的未来时间原样落库(store.normalizeOccurredAt 只判可解析性,拦不住)。
|
|
14
|
+
// 时间一律按「相对当下」构造:锁死某个日期会让用例在时钟走过该日期后变成反向断言。
|
|
15
|
+
const HOUR_MS = 3600 * 1000;
|
|
16
|
+
const DAY_MS = 24 * HOUR_MS;
|
|
17
|
+
|
|
18
|
+
/** 带 +08:00 偏移的同刻 ISO 写法:证明归一真的解析过时区,而不是原样搬运字符串。 */
|
|
19
|
+
function isoWithOffset(ms) {
|
|
20
|
+
return `${new Date(ms + 8 * HOUR_MS).toISOString().slice(0, 23)}+08:00`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function setup(entries, deps = {}) {
|
|
24
|
+
const store = createStore(":memory:");
|
|
25
|
+
const service = createService({ store, mirror: null, config: {} });
|
|
26
|
+
const events = [];
|
|
27
|
+
const calls = [];
|
|
28
|
+
const ctx = {
|
|
29
|
+
on(name, fn) {
|
|
30
|
+
events.push({ name, fn });
|
|
31
|
+
return () => {
|
|
32
|
+
const i = events.findIndex((e) => e.name === name && e.fn === fn);
|
|
33
|
+
if (i !== -1) events.splice(i, 1);
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
llm: {
|
|
37
|
+
stream(options) {
|
|
38
|
+
calls.push(options);
|
|
39
|
+
const json = JSON.stringify(entries);
|
|
40
|
+
return (async function* () {
|
|
41
|
+
yield { type: "block-start", block: { type: "text" } };
|
|
42
|
+
yield { type: "text-delta", delta: json };
|
|
43
|
+
yield { type: "block-end", block: { type: "text" } };
|
|
44
|
+
yield { type: "finish", kind: "ok" };
|
|
45
|
+
})();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
createSummarizer(ctx, service, { autoSummarize: true }, deps);
|
|
50
|
+
return { store, service, calls, handler: events.find((e) => e.name === "session/event").fn };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function turnEndSession(text = "上周把 occurred_at 接进蒸馏链路") {
|
|
54
|
+
return {
|
|
55
|
+
id: "s-time",
|
|
56
|
+
requestHeader: () => ({ config: { provider: "deepseek", model: "deepseek-chat" } }),
|
|
57
|
+
events: [
|
|
58
|
+
{ type: "user/message", data: { source: { kind: "user" }, content: [{ type: "text", text }] } },
|
|
59
|
+
{ seq: 2, type: "turn/end" }
|
|
60
|
+
]
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
test("parseSummaryJson keeps a parseable occurred_at, normalized to UTC ISO", () => {
|
|
65
|
+
const past = Date.now() - 30 * DAY_MS;
|
|
66
|
+
const parsed = parseSummaryJson(JSON.stringify([
|
|
67
|
+
{ type: "history", title: "时间锚定", content: "上周把 occurred_at 接进蒸馏", importance: 2, occurred_at: isoWithOffset(past) }
|
|
68
|
+
]));
|
|
69
|
+
assert.equal(parsed.length, 1);
|
|
70
|
+
assert.equal(parsed[0].occurred_at, new Date(past).toISOString(), "带偏移的绝对时间归一为 UTC ISO");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("parseSummaryJson omits occurred_at when it is unparseable, non-string, or beyond the 1-day future tolerance", () => {
|
|
74
|
+
const now = Date.now();
|
|
75
|
+
const parsed = parseSummaryJson(JSON.stringify([
|
|
76
|
+
{ type: "history", title: "脏字符串", content: "模型给了自然语言时间", importance: 2, occurred_at: "昨天下午" },
|
|
77
|
+
{ type: "history", title: "空白串", content: "模型给了空串", importance: 2, occurred_at: " " },
|
|
78
|
+
{ type: "history", title: "非字符串", content: "模型给了 epoch 数字", importance: 2, occurred_at: 1757000000000 },
|
|
79
|
+
{ type: "history", title: "未来时间", content: "模型编了个两年后的时间", importance: 2, occurred_at: new Date(now + 730 * DAY_MS).toISOString() },
|
|
80
|
+
{ type: "history", title: "略晚于当下", content: "时区/时钟偏移内的未来时间", importance: 2, occurred_at: new Date(now + HOUR_MS).toISOString() },
|
|
81
|
+
{ type: "history", title: "没给时间", content: "最普通的条目", importance: 2 }
|
|
82
|
+
]));
|
|
83
|
+
assert.equal(parsed.length, 6);
|
|
84
|
+
for (const i of [0, 1, 2, 3, 5]) {
|
|
85
|
+
assert.equal("occurred_at" in parsed[i], false, `${parsed[i].title}:必须整条省略该键(不是 null、不是空串)`);
|
|
86
|
+
}
|
|
87
|
+
// 1 天容忍内的未来时间保留:真实时钟与模型给出的时区写法会有小时级偏差,不是瞎填。
|
|
88
|
+
assert.equal(parsed[4].occurred_at, new Date(now + HOUR_MS).toISOString(), "容忍窗口内的时间照常保留");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("distilled occurred_at is visible in the store, dirty/future values are dropped", async () => {
|
|
92
|
+
const past = Date.now() - 3 * HOUR_MS;
|
|
93
|
+
const { store, handler } = setup([
|
|
94
|
+
{ type: "decision", title: "时间锚定", content: "蒸馏产物带绝对时间 occurred_at", importance: 4, occurred_at: isoWithOffset(past) },
|
|
95
|
+
{ type: "history", title: "脏时间", content: "模型给了不可解析的时间", importance: 2, occurred_at: "上周三" },
|
|
96
|
+
{ type: "history", title: "未来时间", content: "模型编了个两年后的时间", importance: 2, occurred_at: new Date(Date.now() + 730 * DAY_MS).toISOString() },
|
|
97
|
+
{ type: "history", title: "无时间", content: "条目里根本没有时间依据", importance: 2 }
|
|
98
|
+
]);
|
|
99
|
+
await handler(turnEndSession(), { seq: 2, type: "turn/end" });
|
|
100
|
+
|
|
101
|
+
const rows = store.all();
|
|
102
|
+
const byTitle = (title) => {
|
|
103
|
+
const row = rows.find((r) => r.title === title);
|
|
104
|
+
assert.ok(row, `记忆「${title}」应当落库`);
|
|
105
|
+
return row;
|
|
106
|
+
};
|
|
107
|
+
// 落库可见:解析层的归一值原样进 memories.occurred_at(saveWithDedupe 普通路径)。
|
|
108
|
+
assert.equal(byTitle("时间锚定").occurred_at, new Date(past).toISOString());
|
|
109
|
+
// 丢弃:不可解析与超容忍的未来时间都不落列(NULL),不是字符串化后硬存。
|
|
110
|
+
assert.equal(byTitle("脏时间").occurred_at, undefined);
|
|
111
|
+
assert.equal(byTitle("未来时间").occurred_at, undefined);
|
|
112
|
+
assert.equal(byTitle("无时间").occurred_at, undefined);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("the distill system prompt carries the wall-clock anchor relative times are converted against", async () => {
|
|
116
|
+
const fixed = new Date("2026-05-04T03:02:01.000Z");
|
|
117
|
+
const { calls, handler } = setup([
|
|
118
|
+
{ type: "history", title: "锚点", content: "会话里只说了「昨天」", importance: 2 }
|
|
119
|
+
], { now: () => fixed.getTime() });
|
|
120
|
+
await handler(turnEndSession("昨天部署了 v0.8.4"), { seq: 2, type: "turn/end" });
|
|
121
|
+
|
|
122
|
+
const system = calls[0].messages.find((m) => m.role === "system")?.content?.[0]?.text ?? "";
|
|
123
|
+
assert.ok(system.includes("occurred_at"), "系统提示的形状串里给出可选时间字段");
|
|
124
|
+
assert.ok(system.includes("严格") || system.includes("严禁编造"), "提示词写明编造禁令");
|
|
125
|
+
// 锚点取自可注入时钟:没有它,「昨天」永远换算不出绝对值。
|
|
126
|
+
assert.ok(system.includes(`当前时间:${fixed.toISOString()}`), "系统提示末尾带上会话发生时间");
|
|
127
|
+
});
|
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
// issue #502:#493 的第二种形态。JSON 是合法的,条目却被 `VALID` 全部滤掉——过去这
|
|
2
|
-
// 和「模型压根没写数组」共用一句 `invalid summary JSON`,而两者要修的地方完全不同,
|
|
3
|
-
// 更要命的是失败路径游标不推进:同一个窗口会被一遍遍重放(社区报告的实测:0.9.4 装上
|
|
4
|
-
// 之后 summarize 解冻了,隔 19 秒又来一条 invalid,输入 2711→输出 2047)。
|
|
5
|
-
// 本文件锁三层:判据分得开、读数说得出是哪一种、以及 prompt 与枚举从此一致(中英两份)。
|
|
6
|
-
import test from "node:test";
|
|
7
|
-
import assert from "node:assert/strict";
|
|
8
|
-
import { parseSummaryJsonResult, summarizeParseFailureAudit } from "../src/summarize.js";
|
|
9
|
-
import { STR } from "../src/lang.js";
|
|
10
|
-
|
|
11
|
-
const GOOD = { type: "project", title: "发布只在包目录内", content: "根目录发过坏包。" };
|
|
12
|
-
// 报告现场的原样形状:自造中文分类 + 多带 id/source 键
|
|
13
|
-
const BOGUS = [
|
|
14
|
-
{ id: 1, type: "环境/版本", content: "本地安装的 @modusensus/dsh-mneme 版本为 0.9.4", source: "工具结果:版本确认" },
|
|
15
|
-
{ id: "user_intent", type: "用户需求", content: "希望插件不再重复询问", source: "用户输入" }
|
|
16
|
-
];
|
|
17
|
-
|
|
18
|
-
test("filtered-empty:JSON 合法、条目全被枚举滤掉,要能报出 arr/valid 两个数", () => {
|
|
19
|
-
const r = parseSummaryJsonResult(JSON.stringify(BOGUS));
|
|
20
|
-
assert.equal(r.ok, false, "全被滤掉的窗口不能算成功(否则会永久推进游标)");
|
|
21
|
-
assert.equal(r.failure.kind, "filtered-empty");
|
|
22
|
-
assert.equal(r.failure.arrCount, 2);
|
|
23
|
-
assert.deepEqual(r.failure.sampleTypes, ["环境/版本", "用户需求"],
|
|
24
|
-
"把模型实际用的分类词原样带出来——不看这一眼就得去猜");
|
|
25
|
-
|
|
26
|
-
const audit = summarizeParseFailureAudit(JSON.stringify(BOGUS), r.failure);
|
|
27
|
-
assert.equal(audit.errorMessage, "no valid summary entries (arr=2, valid=0)");
|
|
28
|
-
assert.equal(audit.metadata.failure_kind, "filtered-empty");
|
|
29
|
-
assert.equal(audit.metadata.arr_count, 2);
|
|
30
|
-
assert.equal(audit.metadata.invalid_entries, 2);
|
|
31
|
-
assert.equal(audit.metadata.raw_has_bracket, true, "有方括号正是这一型的特征:它不是「没写格式」");
|
|
32
|
-
assert.equal(audit.metadata.parse_failure, true);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test("no-array:模型在说话而不是在输出,判据与 filtered-empty 必须分开", () => {
|
|
36
|
-
const raw = "我觉得这批内容挺有意思,我来点评一下:第一,版本确认很重要……";
|
|
37
|
-
const r = parseSummaryJsonResult(raw);
|
|
38
|
-
assert.equal(r.ok, false);
|
|
39
|
-
assert.equal(r.failure.kind, "no-array");
|
|
40
|
-
const audit = summarizeParseFailureAudit(raw, r.failure);
|
|
41
|
-
assert.equal(audit.errorMessage, "invalid summary JSON", "这一型才该用原来那句话");
|
|
42
|
-
assert.equal(audit.metadata.raw_has_bracket, false);
|
|
43
|
-
assert.equal(audit.metadata.sample_types, undefined, "没有数组可言,不许编出 arr_count");
|
|
44
|
-
assert.equal(audit.metadata.arr_count, undefined);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test("有合法条目时不产出 failure(成功路径不被诊断字段污染)", () => {
|
|
48
|
-
const r = parseSummaryJsonResult(JSON.stringify([GOOD]));
|
|
49
|
-
assert.equal(r.ok, true);
|
|
50
|
-
assert.equal(r.failure, undefined);
|
|
51
|
-
assert.equal(r.entries.length, 1);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test("raw_tail 只在正文确实长于头部窗口时给(短输出不重复贴一遍)", () => {
|
|
55
|
-
const short = JSON.stringify(BOGUS);
|
|
56
|
-
assert.equal(summarizeParseFailureAudit(short, { kind: "filtered-empty", arrCount: 2, sampleTypes: [] }).metadata.raw_tail, undefined);
|
|
57
|
-
const long = JSON.stringify(BOGUS) + " ".repeat(600) + "尾巴在这里:后面其实还有半段点评";
|
|
58
|
-
const meta = summarizeParseFailureAudit(long, { kind: "filtered-empty", arrCount: 2, sampleTypes: [] }).metadata;
|
|
59
|
-
assert.ok(meta.raw_tail.includes("尾巴在这里"), "「先写几条合法再跑偏」的输出,只有尾巴能看出来");
|
|
60
|
-
assert.ok(meta.raw_head.length <= 300);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// prompt 与闸门对齐(报告者的第 3 条,零行为变更):菜单给全 7 个值、并写明不许自造。
|
|
64
|
-
// 中英两份都要锁——只改一种语言,另一种语言的窗口照样被滤空,而守卫看不见「两边一起过期」。
|
|
65
|
-
test("summary 提示词的枚举与 VALID 对齐,且中英两份都写明不许自造分类", () => {
|
|
66
|
-
const all = ["preference", "project", "decision", "history", "rejected_solution", "pitfall", "constraint"];
|
|
67
|
-
for (const lang of ["zh", "en"]) {
|
|
68
|
-
const p = STR.prompts.summary[lang];
|
|
69
|
-
for (const t of all) assert.ok(p.includes(t), `summary(${lang}) 枚举缺 ${t}`);
|
|
70
|
-
assert.match(lang === "zh" ? p : p, /只能取上面枚举|must be one of the enumerated/, `summary(${lang}) 缺「不许自造分类」的约束`);
|
|
71
|
-
assert.match(p, /id、source|id, source/, `summary(${lang}) 要写明不许附加 id/source 等额外键`);
|
|
72
|
-
}
|
|
73
|
-
// codingSummary 本来就列全了,确认没被这次批量替换改坏(它多出的说明句还在)
|
|
74
|
-
assert.ok(STR.prompts.codingSummary.zh.includes("rejected_solution") && STR.prompts.codingSummary.zh.includes("pitfall"));
|
|
75
|
-
});
|
|
1
|
+
// issue #502:#493 的第二种形态。JSON 是合法的,条目却被 `VALID` 全部滤掉——过去这
|
|
2
|
+
// 和「模型压根没写数组」共用一句 `invalid summary JSON`,而两者要修的地方完全不同,
|
|
3
|
+
// 更要命的是失败路径游标不推进:同一个窗口会被一遍遍重放(社区报告的实测:0.9.4 装上
|
|
4
|
+
// 之后 summarize 解冻了,隔 19 秒又来一条 invalid,输入 2711→输出 2047)。
|
|
5
|
+
// 本文件锁三层:判据分得开、读数说得出是哪一种、以及 prompt 与枚举从此一致(中英两份)。
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import { parseSummaryJsonResult, summarizeParseFailureAudit } from "../src/summarize.js";
|
|
9
|
+
import { STR } from "../src/lang.js";
|
|
10
|
+
|
|
11
|
+
const GOOD = { type: "project", title: "发布只在包目录内", content: "根目录发过坏包。" };
|
|
12
|
+
// 报告现场的原样形状:自造中文分类 + 多带 id/source 键
|
|
13
|
+
const BOGUS = [
|
|
14
|
+
{ id: 1, type: "环境/版本", content: "本地安装的 @modusensus/dsh-mneme 版本为 0.9.4", source: "工具结果:版本确认" },
|
|
15
|
+
{ id: "user_intent", type: "用户需求", content: "希望插件不再重复询问", source: "用户输入" }
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
test("filtered-empty:JSON 合法、条目全被枚举滤掉,要能报出 arr/valid 两个数", () => {
|
|
19
|
+
const r = parseSummaryJsonResult(JSON.stringify(BOGUS));
|
|
20
|
+
assert.equal(r.ok, false, "全被滤掉的窗口不能算成功(否则会永久推进游标)");
|
|
21
|
+
assert.equal(r.failure.kind, "filtered-empty");
|
|
22
|
+
assert.equal(r.failure.arrCount, 2);
|
|
23
|
+
assert.deepEqual(r.failure.sampleTypes, ["环境/版本", "用户需求"],
|
|
24
|
+
"把模型实际用的分类词原样带出来——不看这一眼就得去猜");
|
|
25
|
+
|
|
26
|
+
const audit = summarizeParseFailureAudit(JSON.stringify(BOGUS), r.failure);
|
|
27
|
+
assert.equal(audit.errorMessage, "no valid summary entries (arr=2, valid=0)");
|
|
28
|
+
assert.equal(audit.metadata.failure_kind, "filtered-empty");
|
|
29
|
+
assert.equal(audit.metadata.arr_count, 2);
|
|
30
|
+
assert.equal(audit.metadata.invalid_entries, 2);
|
|
31
|
+
assert.equal(audit.metadata.raw_has_bracket, true, "有方括号正是这一型的特征:它不是「没写格式」");
|
|
32
|
+
assert.equal(audit.metadata.parse_failure, true);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("no-array:模型在说话而不是在输出,判据与 filtered-empty 必须分开", () => {
|
|
36
|
+
const raw = "我觉得这批内容挺有意思,我来点评一下:第一,版本确认很重要……";
|
|
37
|
+
const r = parseSummaryJsonResult(raw);
|
|
38
|
+
assert.equal(r.ok, false);
|
|
39
|
+
assert.equal(r.failure.kind, "no-array");
|
|
40
|
+
const audit = summarizeParseFailureAudit(raw, r.failure);
|
|
41
|
+
assert.equal(audit.errorMessage, "invalid summary JSON", "这一型才该用原来那句话");
|
|
42
|
+
assert.equal(audit.metadata.raw_has_bracket, false);
|
|
43
|
+
assert.equal(audit.metadata.sample_types, undefined, "没有数组可言,不许编出 arr_count");
|
|
44
|
+
assert.equal(audit.metadata.arr_count, undefined);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("有合法条目时不产出 failure(成功路径不被诊断字段污染)", () => {
|
|
48
|
+
const r = parseSummaryJsonResult(JSON.stringify([GOOD]));
|
|
49
|
+
assert.equal(r.ok, true);
|
|
50
|
+
assert.equal(r.failure, undefined);
|
|
51
|
+
assert.equal(r.entries.length, 1);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("raw_tail 只在正文确实长于头部窗口时给(短输出不重复贴一遍)", () => {
|
|
55
|
+
const short = JSON.stringify(BOGUS);
|
|
56
|
+
assert.equal(summarizeParseFailureAudit(short, { kind: "filtered-empty", arrCount: 2, sampleTypes: [] }).metadata.raw_tail, undefined);
|
|
57
|
+
const long = JSON.stringify(BOGUS) + " ".repeat(600) + "尾巴在这里:后面其实还有半段点评";
|
|
58
|
+
const meta = summarizeParseFailureAudit(long, { kind: "filtered-empty", arrCount: 2, sampleTypes: [] }).metadata;
|
|
59
|
+
assert.ok(meta.raw_tail.includes("尾巴在这里"), "「先写几条合法再跑偏」的输出,只有尾巴能看出来");
|
|
60
|
+
assert.ok(meta.raw_head.length <= 300);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// prompt 与闸门对齐(报告者的第 3 条,零行为变更):菜单给全 7 个值、并写明不许自造。
|
|
64
|
+
// 中英两份都要锁——只改一种语言,另一种语言的窗口照样被滤空,而守卫看不见「两边一起过期」。
|
|
65
|
+
test("summary 提示词的枚举与 VALID 对齐,且中英两份都写明不许自造分类", () => {
|
|
66
|
+
const all = ["preference", "project", "decision", "history", "rejected_solution", "pitfall", "constraint"];
|
|
67
|
+
for (const lang of ["zh", "en"]) {
|
|
68
|
+
const p = STR.prompts.summary[lang];
|
|
69
|
+
for (const t of all) assert.ok(p.includes(t), `summary(${lang}) 枚举缺 ${t}`);
|
|
70
|
+
assert.match(lang === "zh" ? p : p, /只能取上面枚举|must be one of the enumerated/, `summary(${lang}) 缺「不许自造分类」的约束`);
|
|
71
|
+
assert.match(p, /id、source|id, source/, `summary(${lang}) 要写明不许附加 id/source 等额外键`);
|
|
72
|
+
}
|
|
73
|
+
// codingSummary 本来就列全了,确认没被这次批量替换改坏(它多出的说明句还在)
|
|
74
|
+
assert.ok(STR.prompts.codingSummary.zh.includes("rejected_solution") && STR.prompts.codingSummary.zh.includes("pitfall"));
|
|
75
|
+
});
|