@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.
Files changed (543) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +830 -830
  3. package/assets/icon.svg +3 -3
  4. package/bin/cli.mjs +964 -964
  5. package/bin/dsh-mneme-choro.mjs +262 -262
  6. package/bin/dsh-mneme-mcp.mjs +510 -510
  7. package/bin/dsh-mneme-serve.mjs +151 -151
  8. package/cordis.patch.yml +21 -21
  9. package/docs/CONFIGURATION.md +407 -404
  10. package/docs/CONTINUITY.md +139 -139
  11. package/docs/DAEMON.md +57 -57
  12. package/docs/DIRECTORIES.md +114 -114
  13. package/docs/DISTILL.md +397 -371
  14. package/docs/DSH-GO.md +97 -97
  15. package/docs/ENTITIES.md +247 -247
  16. package/docs/FORGET.md +77 -77
  17. package/docs/KB.md +110 -110
  18. package/docs/LOCAL_MODEL.md +222 -222
  19. package/docs/SEMANTIC.md +256 -256
  20. package/docs/SHARE.md +552 -552
  21. package/docs/SLEEP.md +202 -202
  22. package/docs/STORAGE.md +122 -122
  23. package/docs/WORKFLOWS.md +366 -366
  24. package/lib/api-standalone.js +1007 -1007
  25. package/lib/api.js +3600 -3600
  26. package/lib/attachment-text.js +122 -122
  27. package/lib/bootstrap-http.js +105 -105
  28. package/lib/bootstrap.js +215 -215
  29. package/lib/candidates.js +454 -454
  30. package/lib/capabilities.js +819 -819
  31. package/lib/choro-command.js +111 -111
  32. package/lib/client.js +14420 -14322
  33. package/lib/commands.js +95 -95
  34. package/lib/config-keys.js +144 -144
  35. package/lib/config.js +1361 -1344
  36. package/lib/content-hash.js +54 -54
  37. package/lib/continuity.js +258 -258
  38. package/lib/date-hint.js +32 -0
  39. package/lib/diary/auto.js +190 -190
  40. package/lib/diary/compose.js +440 -440
  41. package/lib/diary/dir.js +59 -59
  42. package/lib/diary/export.js +97 -97
  43. package/lib/diary/index.js +26 -26
  44. package/lib/diary/library.js +189 -189
  45. package/lib/diary/qq-inbox.js +142 -142
  46. package/lib/diary/rollover.js +61 -61
  47. package/lib/diary/session-provider.js +122 -122
  48. package/lib/document-index.js +94 -94
  49. package/lib/document.js +322 -322
  50. package/lib/dream/clustering.js +123 -123
  51. package/lib/dream/decisions.js +945 -945
  52. package/lib/dream/narratives.js +44 -44
  53. package/lib/dream/sleep.js +2027 -2027
  54. package/lib/dream/triage.js +139 -139
  55. package/lib/dream.js +1879 -1879
  56. package/lib/dsh-go/host.js +162 -162
  57. package/lib/dsh-go/panel.js +2091 -2091
  58. package/lib/dsh-go/text.js +342 -342
  59. package/lib/dsh-go/views/common.js +68 -68
  60. package/lib/dsh-go/views/entity.js +48 -48
  61. package/lib/dsh-go/views/memory.js +198 -198
  62. package/lib/dsh-go/views/root.js +30 -30
  63. package/lib/dsh-go/views/settings.js +398 -398
  64. package/lib/dsh-go/views/status.js +51 -51
  65. package/lib/embedding.js +342 -342
  66. package/lib/entities/extractor.js +285 -285
  67. package/lib/fence.js +24 -24
  68. package/lib/graph/anchoring.js +184 -184
  69. package/lib/guide.js +74 -74
  70. package/lib/heat.js +144 -144
  71. package/lib/hot-memory.js +119 -119
  72. package/lib/image-describe.js +158 -0
  73. package/lib/index.js +852 -852
  74. package/lib/inject.js +656 -651
  75. package/lib/kb/index.js +309 -309
  76. package/lib/kb/routes.js +219 -219
  77. package/lib/kb/tools.js +148 -148
  78. package/lib/lang.js +607 -595
  79. package/lib/local-embedder.js +358 -358
  80. package/lib/maintenance.js +162 -162
  81. package/lib/memory-source.js +9 -9
  82. package/lib/mirror.js +330 -330
  83. package/lib/organize.js +456 -456
  84. package/lib/peak-hours.js +172 -172
  85. package/lib/pipeline-activities.js +178 -178
  86. package/lib/pipeline-attribution.js +165 -165
  87. package/lib/pipeline-command.js +279 -279
  88. package/lib/pipeline-confirm.js +142 -142
  89. package/lib/pipeline-exec.js +174 -174
  90. package/lib/pipeline-nudge-auto.js +129 -129
  91. package/lib/pipeline-nudge.js +1623 -1623
  92. package/lib/pipeline-observations.js +181 -181
  93. package/lib/pipeline-observe.js +133 -133
  94. package/lib/pipeline-runner.js +361 -361
  95. package/lib/pipeline-runs.js +442 -442
  96. package/lib/pipeline.js +716 -716
  97. package/lib/placement.js +13 -13
  98. package/lib/pre-inject-gate.js +354 -354
  99. package/lib/profile-extract.js +164 -164
  100. package/lib/profile-facts.js +356 -356
  101. package/lib/provenance-http.js +251 -251
  102. package/lib/quality-filter.js +162 -162
  103. package/lib/recall-stats.js +190 -190
  104. package/lib/reclaim-http.js +150 -150
  105. package/lib/reranker.js +269 -269
  106. package/lib/runtime/adopt.js +176 -176
  107. package/lib/runtime/closure.js +172 -172
  108. package/lib/runtime/download.js +247 -247
  109. package/lib/runtime/layout.js +265 -265
  110. package/lib/runtime/loader.js +252 -252
  111. package/lib/runtime/model-fetch.js +361 -361
  112. package/lib/runtime/provision.js +237 -237
  113. package/lib/runtime/tarball.js +130 -130
  114. package/lib/runtime/verify.js +223 -223
  115. package/lib/safe-slice.js +18 -18
  116. package/lib/scope-state.js +277 -277
  117. package/lib/scope.js +187 -187
  118. package/lib/search/adaptive.js +60 -60
  119. package/lib/search/bm25.js +96 -96
  120. package/lib/semantic.js +572 -572
  121. package/lib/sensitive-scan.js +209 -209
  122. package/lib/serve.js +228 -228
  123. package/lib/service.js +3268 -3268
  124. package/lib/session-gate.js +91 -91
  125. package/lib/session-usage.js +350 -350
  126. package/lib/settings.js +827 -817
  127. package/lib/share-http.js +281 -281
  128. package/lib/share-import.js +234 -234
  129. package/lib/share.js +335 -335
  130. package/lib/store.js +5895 -5895
  131. package/lib/summarize.js +1388 -1343
  132. package/lib/tools.js +1370 -1356
  133. package/lib/user-settings.js +230 -230
  134. package/lib/vector-index.js +180 -180
  135. package/lib/version-check.js +122 -122
  136. package/lib/wiki/claims.js +267 -267
  137. package/lib/wiki/cli-hint.js +90 -90
  138. package/lib/wiki/inject.js +164 -164
  139. package/lib/wiki/partition.js +200 -200
  140. package/lib/wiki/plan.js +214 -214
  141. package/lib/wiki/queries.js +640 -640
  142. package/lib/wiki/render.js +261 -261
  143. package/lib/wiki/scan.js +371 -371
  144. package/lib/wiki/t0.js +500 -500
  145. package/lib/wiki/t1-jobs.js +232 -232
  146. package/lib/wiki/t1.js +609 -609
  147. package/lib/write-admission.js +404 -404
  148. package/locale/en.json +6 -6
  149. package/locale/zh.json +6 -6
  150. package/package.json +1 -1
  151. package/runtime-manifest.json +526 -526
  152. package/scripts/benchmark-embed.js +201 -201
  153. package/scripts/benchmark-recall.js +249 -249
  154. package/scripts/benchmark-rerank.js +166 -166
  155. package/scripts/build-runtime-manifest.mjs +224 -224
  156. package/scripts/changelog-prep.mjs +91 -91
  157. package/scripts/check-sync.js +44 -44
  158. package/scripts/e2e-dsh.js +220 -220
  159. package/scripts/mneme-runtime.mjs +277 -277
  160. package/scripts/publish-gate.mjs +197 -197
  161. package/scripts/release-docs.mjs +210 -210
  162. package/scripts/release-notes.mjs +164 -164
  163. package/scripts/stress-dsh.js +255 -255
  164. package/scripts/sync-lib.js +47 -47
  165. package/scripts/sync-test-badge.mjs +69 -69
  166. package/scripts/test-count-sync.mjs +48 -48
  167. package/src/api-standalone.js +1007 -1007
  168. package/src/api.js +3600 -3600
  169. package/src/attachment-text.js +122 -122
  170. package/src/bootstrap-http.js +105 -105
  171. package/src/bootstrap.js +215 -215
  172. package/src/candidates.js +454 -454
  173. package/src/capabilities.js +819 -819
  174. package/src/choro-command.js +111 -111
  175. package/src/commands.js +95 -95
  176. package/src/config-keys.js +144 -144
  177. package/src/config.js +1361 -1344
  178. package/src/content-hash.js +54 -54
  179. package/src/continuity.js +258 -258
  180. package/src/date-hint.js +32 -0
  181. package/src/diary/auto.js +190 -190
  182. package/src/diary/compose.js +440 -440
  183. package/src/diary/dir.js +59 -59
  184. package/src/diary/export.js +97 -97
  185. package/src/diary/index.js +26 -26
  186. package/src/diary/library.js +189 -189
  187. package/src/diary/qq-inbox.js +142 -142
  188. package/src/diary/rollover.js +61 -61
  189. package/src/diary/session-provider.js +122 -122
  190. package/src/document-index.js +94 -94
  191. package/src/document.js +322 -322
  192. package/src/dream/clustering.js +123 -123
  193. package/src/dream/decisions.js +945 -945
  194. package/src/dream/narratives.js +44 -44
  195. package/src/dream/sleep.js +2027 -2027
  196. package/src/dream/triage.js +139 -139
  197. package/src/dream.js +1879 -1879
  198. package/src/dsh-go/host.js +162 -162
  199. package/src/dsh-go/panel.js +2091 -2091
  200. package/src/dsh-go/text.js +342 -342
  201. package/src/dsh-go/views/common.js +68 -68
  202. package/src/dsh-go/views/entity.js +48 -48
  203. package/src/dsh-go/views/memory.js +198 -198
  204. package/src/dsh-go/views/root.js +30 -30
  205. package/src/dsh-go/views/settings.js +398 -398
  206. package/src/dsh-go/views/status.js +51 -51
  207. package/src/embedding.js +342 -342
  208. package/src/entities/extractor.js +285 -285
  209. package/src/fence.js +24 -24
  210. package/src/graph/anchoring.js +184 -184
  211. package/src/guide.js +74 -74
  212. package/src/heat.js +144 -144
  213. package/src/hot-memory.js +119 -119
  214. package/src/image-describe.js +158 -0
  215. package/src/index.js +852 -852
  216. package/src/inject.js +656 -651
  217. package/src/kb/index.js +309 -309
  218. package/src/kb/routes.js +219 -219
  219. package/src/kb/tools.js +148 -148
  220. package/src/lang.js +607 -595
  221. package/src/local-embedder.js +358 -358
  222. package/src/maintenance.js +162 -162
  223. package/src/memory-source.js +9 -9
  224. package/src/mirror.js +330 -330
  225. package/src/organize.js +456 -456
  226. package/src/peak-hours.js +172 -172
  227. package/src/pipeline-activities.js +178 -178
  228. package/src/pipeline-attribution.js +165 -165
  229. package/src/pipeline-command.js +279 -279
  230. package/src/pipeline-confirm.js +142 -142
  231. package/src/pipeline-exec.js +174 -174
  232. package/src/pipeline-nudge-auto.js +129 -129
  233. package/src/pipeline-nudge.js +1623 -1623
  234. package/src/pipeline-observations.js +181 -181
  235. package/src/pipeline-observe.js +133 -133
  236. package/src/pipeline-runner.js +361 -361
  237. package/src/pipeline-runs.js +442 -442
  238. package/src/pipeline.js +716 -716
  239. package/src/placement.js +13 -13
  240. package/src/pre-inject-gate.js +354 -354
  241. package/src/profile-extract.js +164 -164
  242. package/src/profile-facts.js +356 -356
  243. package/src/provenance-http.js +251 -251
  244. package/src/quality-filter.js +162 -162
  245. package/src/recall-stats.js +190 -190
  246. package/src/reclaim-http.js +150 -150
  247. package/src/reranker.js +269 -269
  248. package/src/runtime/adopt.js +176 -176
  249. package/src/runtime/closure.js +172 -172
  250. package/src/runtime/download.js +247 -247
  251. package/src/runtime/layout.js +265 -265
  252. package/src/runtime/loader.js +252 -252
  253. package/src/runtime/model-fetch.js +361 -361
  254. package/src/runtime/provision.js +237 -237
  255. package/src/runtime/tarball.js +130 -130
  256. package/src/runtime/verify.js +223 -223
  257. package/src/safe-slice.js +18 -18
  258. package/src/scope-state.js +277 -277
  259. package/src/scope.js +187 -187
  260. package/src/search/adaptive.js +60 -60
  261. package/src/search/bm25.js +96 -96
  262. package/src/semantic.js +572 -572
  263. package/src/sensitive-scan.js +209 -209
  264. package/src/serve.js +228 -228
  265. package/src/service.js +3268 -3268
  266. package/src/session-gate.js +91 -91
  267. package/src/session-usage.js +350 -350
  268. package/src/settings.js +827 -817
  269. package/src/share-http.js +281 -281
  270. package/src/share-import.js +234 -234
  271. package/src/share.js +335 -335
  272. package/src/store.js +5895 -5895
  273. package/src/summarize.js +1388 -1343
  274. package/src/tools.js +1370 -1356
  275. package/src/user-settings.js +230 -230
  276. package/src/vector-index.js +180 -180
  277. package/src/version-check.js +122 -122
  278. package/src/wiki/claims.js +267 -267
  279. package/src/wiki/cli-hint.js +90 -90
  280. package/src/wiki/inject.js +164 -164
  281. package/src/wiki/partition.js +200 -200
  282. package/src/wiki/plan.js +214 -214
  283. package/src/wiki/queries.js +640 -640
  284. package/src/wiki/render.js +261 -261
  285. package/src/wiki/scan.js +371 -371
  286. package/src/wiki/t0.js +500 -500
  287. package/src/wiki/t1-jobs.js +232 -232
  288. package/src/wiki/t1.js +609 -609
  289. package/src/write-admission.js +404 -404
  290. package/test/adaptive-inject-budget.test.js +85 -85
  291. package/test/api-hardening.test.js +173 -173
  292. package/test/api-nudge-route.test.js +259 -259
  293. package/test/api-routes-gaps.test.js +1092 -1092
  294. package/test/api.test.js +3007 -2998
  295. package/test/attachment-text.test.js +139 -139
  296. package/test/audit.test.js +448 -448
  297. package/test/baseline-persist.test.js +248 -248
  298. package/test/benchmark.test.js +94 -94
  299. package/test/bm25-corpus-cache.test.js +145 -145
  300. package/test/bootstrap.test.js +228 -228
  301. package/test/candidates.test.js +345 -345
  302. package/test/capabilities.test.js +577 -577
  303. package/test/capacity-warning.test.js +262 -262
  304. package/test/changelog-prep.test.js +125 -125
  305. package/test/choro-command.test.js +218 -218
  306. package/test/cli-enums.test.js +37 -37
  307. package/test/cli-flag-value.test.js +86 -86
  308. package/test/cli-receive.test.js +390 -390
  309. package/test/cli-share.test.js +437 -437
  310. package/test/client-share.test.js +225 -225
  311. package/test/client.test.js +4595 -4425
  312. package/test/clustering.test.js +100 -100
  313. package/test/commands.test.js +106 -106
  314. package/test/config-keys-routes.test.js +233 -233
  315. package/test/config.test.js +153 -153
  316. package/test/conflict-freeze.test.js +344 -344
  317. package/test/conflict-ledger-enforce.test.js +452 -452
  318. package/test/conflict-ledger.test.js +242 -242
  319. package/test/conflict-reviewed.test.js +79 -79
  320. package/test/content-hash.test.js +204 -204
  321. package/test/continuity.test.js +452 -452
  322. package/test/contrast.test.js +432 -432
  323. package/test/date-hint.test.js +156 -0
  324. package/test/dedupe-candidate-window.test.js +180 -180
  325. package/test/dependency-overrides.test.js +78 -78
  326. package/test/diary-library.test.js +187 -187
  327. package/test/diary.test.js +576 -576
  328. package/test/differentiate-feedback.test.js +248 -248
  329. package/test/distill-tx-embed-gap.test.js +110 -110
  330. package/test/docs-config-keys.test.js +65 -65
  331. package/test/document-dir.test.js +233 -233
  332. package/test/document.test.js +703 -703
  333. package/test/dream-archive-guardrail.test.js +116 -116
  334. package/test/dream-baseline-clamp.test.js +174 -174
  335. package/test/dream-candidate-hybrid.test.js +281 -281
  336. package/test/dream-coverage-degrade.test.js +86 -86
  337. package/test/dream-decision-evidence.test.js +314 -314
  338. package/test/dream-failure-backoff.test.js +173 -173
  339. package/test/dream-fence.test.js +207 -207
  340. package/test/dream-maxtokens-fallback.test.js +132 -132
  341. package/test/dream-merge-guardrail.test.js +219 -219
  342. package/test/dream-peak-hours.test.js +194 -194
  343. package/test/dream.test.js +1528 -1528
  344. package/test/dsh-go-host.test.js +134 -134
  345. package/test/dsh-go-panel-actions.test.js +854 -854
  346. package/test/dsh-go-panel.test.js +251 -251
  347. package/test/embed-ready-poll.test.js +94 -94
  348. package/test/embed-text-reasons.test.js +112 -112
  349. package/test/embedding-cache-f32.test.js +276 -276
  350. package/test/embedding-ready.test.js +226 -226
  351. package/test/entities.test.js +711 -711
  352. package/test/entity-recall.test.js +179 -179
  353. package/test/epistemic.test.js +325 -325
  354. package/test/failure-query.test.js +147 -147
  355. package/test/failure-retention.test.js +105 -105
  356. package/test/fnew-0112.test.js +311 -311
  357. package/test/fnew-03.test.js +422 -422
  358. package/test/forget-corrections.test.js +70 -70
  359. package/test/graph-anchoring.test.js +184 -184
  360. package/test/graph-api.test.js +333 -333
  361. package/test/graph-boosted-relations.test.js +189 -189
  362. package/test/graph-inject-budget.test.js +103 -103
  363. package/test/graph-multipath.test.js +269 -269
  364. package/test/graph-passive-confirm.test.js +91 -91
  365. package/test/graph-weight-evolution.test.js +104 -104
  366. package/test/heat.test.js +175 -175
  367. package/test/helpers/dream-mock.js +86 -86
  368. package/test/helpers/peer-worker.mjs +25 -25
  369. package/test/helpers/runtime-source.js +60 -60
  370. package/test/helpers/tar-builder.js +80 -80
  371. package/test/helpers/write-admission-samples.js +312 -312
  372. package/test/hot-memory.test.js +259 -259
  373. package/test/image-description.test.js +271 -0
  374. package/test/image-memory.test.js +170 -170
  375. package/test/inject-content-cap.test.js +91 -91
  376. package/test/inject-first-round-bm25.test.js +89 -89
  377. package/test/inject-heat.test.js +77 -77
  378. package/test/inject-parent-gate.test.js +134 -109
  379. package/test/inject-pin-explicit.test.js +300 -300
  380. package/test/inject-pin-vector-crowd.test.js +225 -225
  381. package/test/inject-pools.test.js +195 -195
  382. package/test/inject-recall.test.js +172 -172
  383. package/test/inject-rotation.test.js +161 -161
  384. package/test/inject.test.js +553 -553
  385. package/test/issue-617-step1-query-and-fusion.test.js +361 -361
  386. package/test/kb-api-wiring.test.js +128 -128
  387. package/test/kb-collections.test.js +272 -272
  388. package/test/kb-routes.test.js +379 -379
  389. package/test/lang.test.js +98 -98
  390. package/test/lastrunat-persist.test.js +101 -101
  391. package/test/lib-smoke.test.js +116 -116
  392. package/test/llm-audit.test.js +815 -815
  393. package/test/llm-message-source.test.js +207 -207
  394. package/test/local-embedder.test.js +292 -292
  395. package/test/maintenance.test.js +501 -501
  396. package/test/mcp-stdio.test.js +385 -385
  397. package/test/mint-source.test.js +311 -311
  398. package/test/mirror-dirty.test.js +424 -424
  399. package/test/mirror-edit-digest.test.js +187 -187
  400. package/test/mirror-generation.test.js +499 -499
  401. package/test/mirror-types.test.js +208 -208
  402. package/test/mirror.test.js +249 -249
  403. package/test/narrative-bars.test.js +162 -162
  404. package/test/organize-tool.test.js +232 -232
  405. package/test/organize.test.js +418 -418
  406. package/test/panel-chart-scale.test.js +90 -90
  407. package/test/panel-tokens.test.js +245 -245
  408. package/test/peak-hours-observability.test.js +70 -70
  409. package/test/peer-blockers.test.js +193 -193
  410. package/test/persona-addressing.test.js +83 -83
  411. package/test/persona-api.test.js +172 -172
  412. package/test/persona-by-session.test.js +568 -568
  413. package/test/persona-flag.test.js +36 -36
  414. package/test/persona-inject.test.js +145 -145
  415. package/test/persona-settings.test.js +198 -198
  416. package/test/pipeline-activities.test.js +155 -155
  417. package/test/pipeline-attribution.test.js +175 -175
  418. package/test/pipeline-command.test.js +243 -243
  419. package/test/pipeline-confirm.test.js +148 -148
  420. package/test/pipeline-exec.test.js +172 -172
  421. package/test/pipeline-nudge-auto.test.js +248 -248
  422. package/test/pipeline-nudge.test.js +1278 -1278
  423. package/test/pipeline-observations.test.js +157 -157
  424. package/test/pipeline-observe.test.js +127 -127
  425. package/test/pipeline-r1r2.test.js +278 -278
  426. package/test/pipeline-runner.test.js +468 -468
  427. package/test/pipeline-runs.test.js +767 -767
  428. package/test/pipeline.test.js +636 -636
  429. package/test/placement.test.js +36 -36
  430. package/test/policy-epoch.test.js +259 -259
  431. package/test/pre-inject-gate.test.js +444 -444
  432. package/test/profile-extract.test.js +269 -269
  433. package/test/profile-facts.test.js +492 -492
  434. package/test/prompt-stance.test.js +128 -128
  435. package/test/provenance-http.test.js +367 -367
  436. package/test/publish-gate.test.js +272 -272
  437. package/test/quality-backfill.test.js +290 -290
  438. package/test/quality-filter.test.js +295 -295
  439. package/test/readme-claims.test.js +113 -113
  440. package/test/reasoning-effort.test.js +752 -752
  441. package/test/recall-anti-update.test.js +82 -82
  442. package/test/recall-evals.test.js +253 -253
  443. package/test/recall-layer.test.js +326 -326
  444. package/test/recall-retention.test.js +128 -128
  445. package/test/recall-stats.test.js +274 -274
  446. package/test/receipt-chain.test.js +451 -451
  447. package/test/reclaim-http.test.js +209 -209
  448. package/test/reflection-update-gate.test.js +129 -129
  449. package/test/reflection.test.js +226 -226
  450. package/test/reindex-backfill.test.js +475 -475
  451. package/test/reindex-scheduler.test.js +369 -369
  452. package/test/release-docs.test.js +156 -156
  453. package/test/release-notes.test.js +265 -265
  454. package/test/release-workflow.test.js +93 -93
  455. package/test/reranker-single-logit.test.js +73 -73
  456. package/test/reranker.test.js +197 -197
  457. package/test/resident-status.test.js +83 -83
  458. package/test/route-policy.test.js +113 -113
  459. package/test/runtime-adopt.test.js +206 -206
  460. package/test/runtime-cli.test.js +89 -89
  461. package/test/runtime-closure.test.js +193 -193
  462. package/test/runtime-download.test.js +302 -302
  463. package/test/runtime-layout.test.js +163 -163
  464. package/test/runtime-loader.test.js +255 -255
  465. package/test/runtime-manifest.test.js +159 -159
  466. package/test/runtime-model-fetch.test.js +348 -348
  467. package/test/runtime-provision.test.js +101 -101
  468. package/test/runtime-tarball.test.js +81 -81
  469. package/test/runtime-verify.test.js +319 -319
  470. package/test/scope-candidates.test.js +491 -491
  471. package/test/scope-distill-stamp.test.js +134 -134
  472. package/test/scope-explicit.test.js +452 -452
  473. package/test/scope-inject-soft.test.js +106 -106
  474. package/test/scope-optional-service.test.js +110 -110
  475. package/test/scope-retrieval.test.js +197 -197
  476. package/test/scope-state.test.js +610 -610
  477. package/test/scope-storage.test.js +255 -255
  478. package/test/scope-strict.test.js +367 -367
  479. package/test/search-fusion.test.js +90 -90
  480. package/test/security-doc.test.js +188 -188
  481. package/test/semantic.test.js +124 -124
  482. package/test/sensitive-scan.test.js +251 -251
  483. package/test/serve-bin.test.js +121 -121
  484. package/test/serve.test.js +258 -258
  485. package/test/service-search.test.js +174 -174
  486. package/test/service.test.js +410 -410
  487. package/test/session-gate.test.js +264 -264
  488. package/test/session-usage.test.js +317 -317
  489. package/test/settings.test.js +273 -273
  490. package/test/share-foreign-rows.test.js +144 -144
  491. package/test/share-http.test.js +144 -144
  492. package/test/share-import.test.js +577 -577
  493. package/test/share-imported-guard.test.js +311 -311
  494. package/test/share-imported-identity.test.js +111 -111
  495. package/test/share-pack.test.js +511 -511
  496. package/test/share-receive-http.test.js +756 -756
  497. package/test/share-routes.test.js +337 -337
  498. package/test/share-store.test.js +133 -133
  499. package/test/share-validate.test.js +101 -101
  500. package/test/skip-invalid-restore.test.js +262 -262
  501. package/test/sleep-action-set.test.js +441 -441
  502. package/test/sleep-catchup.test.js +315 -315
  503. package/test/sleep-failure-backoff.test.js +156 -156
  504. package/test/sleep-heat.test.js +174 -174
  505. package/test/sleep-scheduler-rearm.test.js +89 -89
  506. package/test/sleep.test.js +1455 -1455
  507. package/test/standalone-api.test.js +1344 -1344
  508. package/test/store-vector-cache.test.js +98 -98
  509. package/test/store-write-path-columns.test.js +191 -191
  510. package/test/store.test.js +744 -744
  511. package/test/stress.test.js +209 -209
  512. package/test/summarize-occurred-at.test.js +127 -127
  513. package/test/summarize-parse-diagnostics.test.js +75 -75
  514. package/test/summarize-reasoning-effort.test.js +189 -189
  515. package/test/summarize.test.js +2251 -2251
  516. package/test/supersede-state-tracking.test.js +394 -394
  517. package/test/test-count-sync.test.js +71 -71
  518. package/test/tool-state-ignore.test.js +65 -65
  519. package/test/tools-dto-schema-matrix.test.js +398 -398
  520. package/test/tools-memory-get-schema.test.js +65 -65
  521. package/test/tools.test.js +585 -585
  522. package/test/updated-at-semantics.test.js +113 -113
  523. package/test/user-settings-preview.test.js +127 -127
  524. package/test/user-settings-segments.test.js +527 -527
  525. package/test/vector-index.test.js +334 -334
  526. package/test/version-check.test.js +152 -152
  527. package/test/webServer-optional.test.js +82 -82
  528. package/test/wiki-api.test.js +734 -734
  529. package/test/wiki-claims.test.js +194 -194
  530. package/test/wiki-cli-hint.test.js +118 -118
  531. package/test/wiki-inject.test.js +265 -265
  532. package/test/wiki-partition.test.js +112 -112
  533. package/test/wiki-plan.test.js +80 -80
  534. package/test/wiki-provenance.test.js +202 -202
  535. package/test/wiki-queries.test.js +398 -398
  536. package/test/wiki-scan.test.js +208 -208
  537. package/test/wiki-store.test.js +190 -190
  538. package/test/wiki-t0.test.js +456 -456
  539. package/test/wiki-t1-jobs.test.js +125 -125
  540. package/test/wiki-t1.test.js +460 -460
  541. package/test/wiki-tools.test.js +176 -176
  542. package/test/workflow-guards.test.js +155 -155
  543. package/test/write-admission.test.js +668 -668
package/README.md CHANGED
@@ -1,830 +1,830 @@
1
- <p align="center"><strong>中文 | <a href="docs/SEMANTIC.md">English(语义增强)</a></strong></p>
2
-
3
- # dsh-mneme
4
-
5
- [![npm version](https://img.shields.io/npm/v/@modusensus/dsh-mneme?color=blue&label=npm)](https://www.npmjs.com/package/@modusensus/dsh-mneme)
6
- [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
7
- [![Awesome](https://awesome-dsh-plugin.com/badge.svg)](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin)
8
- [![tests](https://img.shields.io/badge/tests-3375%20total-success)](https://github.com/slow-stack/mneme)
9
- [![CI](https://img.shields.io/github/actions/workflow/status/slow-stack/mneme/ci.yml)](https://github.com/slow-stack/mneme/actions)
10
- [![node](https://img.shields.io/badge/node-22%2B-blue)](https://nodejs.org)
11
- [![npm downloads](https://img.shields.io/npm/d18m/@modusensus/dsh-mneme.svg?color=blue&label=downloads)](https://www.npmjs.com/package/@modusensus/dsh-mneme)
12
- [![coverage](https://img.shields.io/codecov/c/github/slow-stack/mneme/main)](https://codecov.io/gh/slow-stack/mneme)
13
-
14
- > 给 DeepSeek Harness 的跨会话记忆插件:让 Agent 记住你、记住项目、自动整理记忆。**Mneme**(Μνήμη)——希腊记忆女神 Mnemosyne 之名,掌管记忆与梦境,正如 autoDream 在后台巩固记忆。
15
-
16
- `dsh-mneme` 是一个 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) 插件,为 Agent 提供持久的跨会话记忆能力。它借鉴了 Claude 的 **Dream 机制** 与 cc-haha / Claude Code 的 **autoDream** 记忆巩固功能——不仅**存储**记忆,还会**自动巩固**(去重、合并、冲突裁决、摘要生成),让记忆库越用越精炼。完整溯源与致谢见文末「[🙏 致谢](#-致谢)」。
17
-
18
- ## ⏱️ 30 秒理解
19
-
20
- **一句话**:给 Agent 装上跨会话记忆——记住你、记住项目,并在后台自动整理,越用越懂你;**v0.8.0 起**记忆可按 agent 与工作区隔离(`scopeEnabled`),多 Agent / 多项目互不串台;**v0.9.0 起**「这件事怎么跑」也能落进项目仓库(M.O.,`actionPipelineEnabled`,默认关)。
21
-
22
- | ① 写入 | ② 存储 | ③ 进化 |
23
- |--------|--------|--------|
24
- | 对话中模型主动记录(`memory_save`,可带敏感度与事件时间);会话结束自动提炼(`autoSummarize`) | SQLite 主库 + 人类可编辑 Markdown 镜像;实体 / 属性 / 时间轴三层结构化;记忆带 agent / workspace / 敏感度 / 发生时间标注 | 新会话自动注入相关记忆(按当前作用域加权,strictScope 开启后显式收窄的归属硬隔离);autoDream 后台去重 / 合并 / 归档,冲突冻结待人工裁决 |
25
-
26
- ```bash
27
- # 30 秒上手
28
- dsh plugin --profile web add @modusensus/dsh-mneme
29
- dsh web
30
- ```
31
-
32
- **它不是什么**(边界声明):
33
-
34
- - 不是向量数据库——语义搜索是可选增强,默认零额外依赖
35
- - 不替代会话日志——它存的是「值得跨会话记住的」精炼知识
36
- - 不改变模型本身——进化的是记忆库与每次注入的上下文
37
- - 删对话 ≠ 删记忆——记忆是跨会话的全局知识(v0.7.11 起不再与会话绑定),删除会话不影响已存入的记忆
38
-
39
- ## ✨ 功能
40
-
41
- ### 记忆存储(SQLite + Markdown 镜像)
42
-
43
- - **SQLite 主存储**:`~/.dsh/memory/memory.db`,`node:sqlite` 内置,零原生依赖
44
- - **Markdown 镜像**:按类型分文件(`preferences.md` / `projects.md` / `decisions.md` / `history.md` / `summary.md` / `patterns.md` / `pitfalls.md` / `constraints.md` / `rejected-solutions.md`,外加只读视图 `documents.md`),文件头是 YAML frontmatter(`type` / `generated.by` / `generated.at` / `covered` / `coverage` / `tags`)。人类可读,条目标题与正文可手工编辑(**人工修改优先**合并回库);`documents.md` 例外:它只有 document 指针行(id、标题、摘要首句、文件路径),不含正文也不参与人工回填。文件头与条目元数据行由机器维护
45
- - **10 种记忆类型**:`preference` 偏好 / `project` 项目 / `decision` 决策 / `history` 历史 / `summary` 会话总览 / `pattern` 模式 + 编码记忆三型 `rejected_solution` 被否方案 / `pitfall` 踩坑 / `constraint` 约束(v0.7.13 起,`codingRetrospect` 默认关;v0.7.11 近重写已收窄删除 user/fact 两型)+ `document` 文档指针(#230,只存摘要与 `doc_path`,正文留在磁盘由 agent 自管)
46
- - **镜像同步状态机(v0.3.6+)**:mirror 与主库强一致,用 `generation`(期望轮次)/ `applied_generation`(已应用轮次)建模同步债务
47
- - 业务写操作在**自身事务内原子递增** desired generation——崩溃在 COMMIT 后、渲染前,重启也能凭 durable 债务恢复,绝不静默跳过(v0.3.8)
48
- - `generation` 用 SQLite 原子语句递增,多进程并发零丢失;带 `CHECK` 上界,负数/溢出拒绝
49
- - 逐 type 记录 `committed / failed / pending` 回执,健康端点区分 `ok / degraded / unknown`
50
- - 状态写失败不静默:同步失败落日志并留债务,重启自动收敛
51
-
52
- ### 模型工具(默认注册 12 个;开 `organizeEnabled` 后 13 个)
53
-
54
-
55
- | 工具 | 功能 |
56
- |------|------|
57
- | `memory_save` | 记录一条记忆(自动按标题去重合并;v0.8.0 起去重键含 agent/workspace/scope 作用域,可选 `sensitivity` / `occurred_at` 参数) |
58
- | `memory_search` | 全文搜索(中文子串友好,可启用向量语义搜索;可选 `occurred_from` / `occurred_to` 按事件发生时间过滤) |
59
- | `memory_list` | 按类型分页列出(`include_archived=true` 可查看已归档;可选 `occurred_from` / `occurred_to` 时间过滤) |
60
- | `memory_get` | 读取单条记忆完整正文(v0.7.25,按 id;memory_search / memory_list 命中后读全文) |
61
- | `memory_update` | 修改已有记忆 |
62
- | `memory_delete` | 删除记忆(按记忆 ID 精确删除) |
63
- | `memory_forget` | 抑制注入(降权不删除,可恢复) |
64
- | `memory_archive` | 归档/恢复记忆(v0.2.5;归档后隐藏于列表/搜索/注入/整理,`archived=false` 可恢复) |
65
- | `memory_pin` | 钉住一条记忆:无论类型、无论它和其他记忆怎么竞争,每轮都注入在记忆块最前面(#249 第二批;受 `pinnedInjectBudget` 上限约束,钉的顺序是「先钉的占位」,预算不够时最早钉的优先)。**只在她明确说「这条必须一直在」时用**,不是标记重要性的手段——重要性本来就参与排序。钉着 ≠ 会注入:遗忘 / 归档 / 暂停作用域都优先于 pin,回执里的 `injectable` 如实报告这件事。`unpin: true` 松开 |
66
- | `set_scope_state` | 按下/松开某个作用域的**可逆闸门**(#471:政策轴。暂停期间该作用域的记忆照旧存着,只是不注入、不参与巩固,松开即原样回来;不改任何一条记忆的标注,与上面逐条操作的 `memory_forget` / `memory_archive` 是两根不同的轴)。两级开关 `scopeState.enabled` / `.enforce` 默认都关,没开时按下不产生拦截效果 |
67
- | `memory_register_document` | 登记 agent 产长文档的指针行(#230:摘要 + `doc_path` + evidence 落 `document` 类型;正文留在磁盘、由 agent 自管,注册口唯一,旁路写入被拒) |
68
- | `memory_organize` | 主动整理(#231,**要 `organizeEnabled` 打开才注册**):`mode=dryRun` 先出比对报告(每条候选 `exact` / `near` / `new` + 命中行,**不写一行库**、只留审计回执),agent 判断后 `mode=apply` 引用那份报告的 `run_id` 落地。两种「不要它」要分清——**`discard`** = 这条候选不写,什么都不动(只进回执);**`archive`** = 把报告标为被取代的那条**既有行**归档(可恢复,绝不物理删除)。没有比对过的候选写不进库,一份报告也只许落地一次 |
69
- | `memory_runtime` | 本地推理运行时的状态 / 供给 / 校验(v0.7.32,自管运行时三档取件) |
70
-
71
- 开启 `chorographyEnabled` 后可用仓库地志工具。多个仓库已登记时请传仓库 ID。若搜索只读到部分页面,结果会标明漏查的页。
72
-
73
- ### 工作流(M.O.,v0.9 beta;v0.13.0 起从面板下架)
74
-
75
- > **状态**:设置面板不再渲染这一组,界面上没有入口。三个旗标(`actionPipelineEnabled` / `actionRunEnabled` / `actionNudgeEnabled`)与 `/mo-run` 命令、座位注册逻辑都还在,语义零改动;想恢复界面把该组加回 `FEATURE_GROUPS` 与 `FEATURE_FIRST_SCREEN` 即可。下面是设计说明。
76
-
77
- 记忆库答的是「这件事**为什么**这么办」,答不了「这件事**到底怎么跑**」。v0.9 把后者从记忆库里的一行文字变成项目里可提交、可 review、可被 CI 读的一份文件——一条工作流一个 JSON:
78
-
79
- ```
80
- <项目>/.mneme/pipelines/<id>.json ← 项目层(默认;跟着项目提交)
81
- <插件包>/pipelines/<id>.json ← 全局层(兜底;今天包里没有这个目录,有意为空)
82
- ```
83
-
84
- - **两层来源,顺序即优先级**:同 id 两处都有,项目层赢,被挡住的那份进 `shadowed` 报出来(不静默丢弃);项目层的坏文件进 `unreadable` 而不拖死全局层——一层写坏不该让人连兜底那份也看不见
85
- - **校验很硬**:`id` / `name` / `project` / `version` / `status` / `done` 与每一步的 `phase` / `title` / `when` / `do` / `done` / `why` 缺一不可,`risk` 限 R0–R3、`needs` 必须指向存在的步骤、图里有环直接报错——任何一处不合规**整条读不出来**,不做「跳过坏文件继续」:半个工作流比没有更危险
86
- - **护栏,不是轨道**:绕行要留出口。自报 R0/R1 **且**不跨闸门 **且**兜底清单(`IRREVERSIBLE_PATTERNS`,机械匹配、不看自报)没命中 → 记账先走;其余 → 停下问人
87
- - **候选分层**:草稿住 `<memoryDir>/candidates/<项目键>/`,只在本地。升格要同时满足「走过两次(至少一次成功)」**且**「写得出反事实」;够格之后系统只**提议**,`promoteCandidate()` 只返回内容不写盘,提交与推送是人握着的那道门
88
- - **两个指标分开数**:跳过(这次不用这一步,≥3 次提议删**这一步**)与绕开(这条路整个不对,≥3 次提议重看**这条路径**)各自累加,混在一起两种提议都发不出来
89
- - **只读路由** `GET /api/dsh-mneme/pipeline[?id=&project=]`(`project` 非绝对路径回 400 `project-not-absolute`,不回退 `process.cwd()`);答复契约 `mneme.pipeline/v1`,面板渲染与 agent 读的是同一份数据
90
- - 默认关(`actionPipelineEnabled`),设计取舍见 [docs/WORKFLOWS.md](docs/WORKFLOWS.md)
91
-
92
- ### 自动注入 + 会话摘要
93
-
94
- - **自动注入**:新会话开局注入记忆摘要(`summary` 优先 + 少量高重要性条目)
95
- - **会话摘要**:`turn/end` 时用 LLM 提炼本次会话的偏好/决策/教训,自动入库(过滤 plugin 注入上下文,避免污染)
96
-
97
- ### autoDream 自动记忆整理 🧠
98
-
99
- > **溯源**:autoDream 的理念源自 Claude Code 的 Auto Dream 记忆巩固功能(Anthropic,Memory 2.0 的后台整理子代理),其「离线巩固」思路与 UC Berkeley & Letta 的 *Sleep-time Compute* 论文([arXiv:2504.13171](https://arxiv.org/abs/2504.13171))一脉相承。dsh-mneme 将其引入 DSH 插件生态,并发展为自己的实现——K-Means++ 聚类预分组、类型化决策清单与可回放的 sha256 摘要审计链,详见文末「[🙏 致谢](#-致谢)」。
100
-
101
- - **触发**:记忆数 > 10 或总字符 > 5000 时,异步自动触发(不阻塞写入)
102
- - **决策清单式整理**:LLM 输出 `keep` / `merge` / `archive` / `conflict` / `update` 决策清单,服务端校验后逐条应用
103
- - `merge`:合并主题相近的条目,保留信息最完整者
104
- - `archive`:归档过时/冗余条目(可恢复,不物理删除)
105
- - `conflict`:裁决矛盾信息,胜者保留、败者归档并追加溯源注释;`conflictFreezeEnabled`(默认关)开启后矛盾对不自动裁决,改为冻结进**冲突队列**(状态页并排对比,人工选保留方,#166)
106
- - `update`(v0.2.1):直接修正单条记忆的过时/错误内容(单 id / 必须实际变化 / 非 summary / 24h 保护 / 每次 ≤2)
107
- - **失败追踪(v0.2.1)**:用户纠正记忆时写入 `failure_memories` 表(旧值/新值),为后续自进化积累数据
108
- - **摘要生成**:整理后生成"记忆库总览"(单一实例),作为下次会话的优先注入
109
- - **Fail-safe**:非法 LLM 输出(未知 id / 非法 action / 越界 importance / 跨类型合并等"单条非法"决策,Issue #26)默认跳过该条并应用合法子集(run 记为 `degraded`),绝不破坏记忆库
110
- - **裁决审计**:每次运行写入 `dream_runs` 审计表(输入快照 sha256 digest + 完整输入快照 + 决策清单 + 逐 id 去向 + receipt),可离线回放;merge / conflict / update 幂等应用,重放/并发重复执行无累积副作用;update 记录 `_before` 快照
111
-
112
- #### dreamMaxTokens 调优指南
113
-
114
- 默认 `131072`(即上限,#135)已为思考型模型预留推理+正文的双重预算(部分思考型模型仅推理就可能消耗 8k+ token),常规记忆库无需调整。若**记忆量大**(数万字符以上)且正文仍被截断,优先按下方「巩固模型分类声明」换非思考模型 / 配 `dreamReasoningEffort` 压低思考,再考虑调大输入侧上限(如 `distillMaxChars`)——`dreamMaxTokens` 本身已无上调空间。
115
-
116
- > **不要为了省 token 把它调小**(#135 成本审计实测):这个键是**上限**而非计费口径,流式按实际用量计费,压上限只在真撞顶时生效;而撞顶的后果是**整轮失败**(截断 → 无完整 JSON → `no json array in llm output`),且调度器只有 `ok` 轮才刷新基线,下一次写入会用同一批输入重跑。按 133 个有真实用量的成功轮折算,cap=16384 撞顶 78.9%、净总量 **+54.1%**;cap=32768 +15.9%。真正的大头(`dream_consolidate` 输出 token 里约 88% 是推理与 JSON 骨架,只有约 11.8% 是决策正文)由 `dreamReasoningEffort` 与模型选择决定,与本键无关。相关的数量护栏见 `dreamMaxMergePerRun`。
117
-
118
- > 若使用**思考型模型**(如 deepseek-v4-flash / DeepSeek-R1 类),模型可能把全部预算花在 reasoning 上导致正文为空(日志出现 `no json array in llm output`)。#135 修复后:未配置 `dreamReasoningEffort` 时会**自动取模型支持的最低档**发流(不再省略字段让模型自带默认档——v4-flash 系默认 high——顶上烧光预算),默认配置即生效;显式 `none` = 不发送字段用服务商默认,`off`/`low`/`medium`/`high` 原样传递,模型不支持的档位自动换用(拒绝原因记入 llm_audit)。正文仍为空时配置 `dreamProvider`/`dreamModel` 指向非思考模型(`dreamMaxTokens` 默认已是上限 131072,无上调空间)。sleep 侧对应 `sleepReasoningEffort`。
119
-
120
- **巩固模型分类声明**(settings panel「巩固模型」= `dreamProvider`/`dreamModel`,睡眠侧对应 `sleepProvider`/`sleepModel`):
121
-
122
- | 模型类别 | 例子 | 说明 |
123
- |---------|------|------|
124
- | **非思考模型(推荐)** | glm-5-2 类等 | 无 reasoning 声明;即使配了 effort 被 harness 拒绝,fallback 去掉字段重试即成功。空体风险最低 |
125
- | **思考模型(需实测)** | deepseek-v4-flash-ga 等 v4-flash-ga 系 | 默认开推理,可能烧光 token 预算返回空体;部分型号(如 v4-flash-ga)在 harness 侧被声明为**不接受任何 reasoning effort**(去掉 effort 时 harness 的 `defaultEffort` 会顶上来再次拒绝)。v0.7.26+ 已根治:`resolveDreamEffort` 发流前探测模型支持的档位,不支持的配置档位自动换用模型默认/首个支持档位,声明无 reasoning 能力的型号则省略字段。选用时建议配 `dreamReasoningEffort` 实测(未配置时自动取最低档),不行就换非思考模型 |
126
-
127
- ### Sleep Mode 系统级睡眠 💤(v0.4.0,opt-in)
128
-
129
- 从 autoDream 的"被动阈值触发"升级为"主动定时维护 + 分层压缩"。系统空闲 `sleepIdleMinutes` 分钟自动执行深度维护,**默认关闭**(`sleepModeEnabled: false`),开启后行为:
130
-
131
- - **可中断**:AbortController 实现,用户恢复活动即中止当前周期(`noteWrite` 重置空闲计时 + 中断信号)
132
- - **串行安全**:睡眠周期走 `service.enqueue` 串行队列,与 autoDream 严格不重叠;`minRefTimeMs` 防止快照后被召回的记忆被误降级
133
- - **四阶段深度维护**:
134
- 1. `conflict_resolution`:全库冲突消解,strictness 三级可配(gentle 0.92 / normal 0.85 / aggressive 0.75)
135
- 2. `archival_demotion`:按 `last_accessed_at` 分层——30 天未召回压成摘要(原文进 `_full_content`,可无损恢复)、90 天完全归档
136
- 3. `pattern_discovery`:LLM 扫描近期记忆提炼规律,产出 `type=pattern` 记忆,evidence 强校验防伪造
137
- 4. `relation_completion`:检测孤立实体并补全隐含关系(共现 `related_to` / 项目 `part_of` / 技术 `depends_on`)
138
- - **Fail-safe**:每阶段独立 try/catch,LLM 故障只跳过对应阶段;无 LLM 路由时纯规则降级(demotion/relations)照常执行
139
- - **审计延续**:睡眠周期写入 `dream_runs`,`run_type='sleep'`,与 autoDream 共用审计表可追溯
140
-
141
- > 配置详见 `docs/SLEEP.md`。
142
-
143
- 官方设置面板 → 「记忆库设置」→「记忆」标签:按类型浏览、全文搜索;启用向量搜索后可用「语义」切换做向量召回。
144
-
145
- ### 用户设置(画像 / 规则)与自定义指令 ⚙️
146
-
147
- 官方设置面板 → 「记忆库设置」标签:
148
-
149
- - **用户画像**:一段自由文本描述用户自己(角色、背景、偏好),**每轮注入**到系统提示,让 Agent 始终遵循
150
- - **规则**:Agent 必须遵守的行为规则列表(如"回答先给结论"),同样每轮注入
151
- - **自定义指令**:注册斜杠命令(`/名称 [补充说明]`),触发时把用户定义的指令内容作为一条用户消息提交给当前 Agent,命令后缀会作为补充说明一并提交;界面仅显示提交回执(宿主不支持 followup 提交时退回旧行为,指令原文会显示在界面,便于复制后手动发送)。命令持久化到 SQLite,启动时自动注册到 DSH 命令表,增删实时生效
152
-
153
- > 画像与规则通过独立的 `[用户设置]` 注入区块(优先级高于记忆库),即使记忆为空也会注入。
154
-
155
- ### 向量搜索(语义搜索)🔎
156
-
157
- 可选能力:接入 OpenAI 兼容的 embeddings API,让搜索能命中**字面不同但语义相近**的记忆。
158
-
159
- **配置**:官方设置 → 「记忆库设置」→ 滚动到底部「向量搜索」区块:
160
-
161
- | 字段 | 说明 |
162
- |------|------|
163
- | `启用向量搜索` | 总开关;开启后记忆面板出现「语义」切换 |
164
- | `API 地址 (Base URL)` | OpenAI 兼容端点,如 `https://api.openai.com/v1`;也支持 SiliconFlow、智谱、本地 Ollama 等 |
165
- | `API Key` | 对应服务的密钥 |
166
- | `模型名` | embedding 模型,如 `text-embedding-3-small`、`text-embedding-v3`、`bge-m3` 等 |
167
-
168
- 保存配置后点「重建索引」,为已有记忆批量补建向量(新写入的记忆会自动嵌入)。之后在记忆面板输入查询并点「语义」,即可用向量召回语义相关结果;向量服务不可用时自动回退全文搜索。
169
-
170
- > ⚠️ 密钥仅保存在本机 `~/.dsh/memory/memory.db` 的 `user_settings` 表,不会上传,也不会写入代码仓库。
171
- > 需要 embedding 而非 rerank 模型:如阿里云 `text-embedding-v3` 可用,`qwen3-vl-rerank` 是 rerank 模型(不走 `/embeddings`)。
172
-
173
- ### 语义增强(Semantic)🧠
174
-
175
- v0.2 起新增**可以完全离线运行的语义记忆引擎**(本地模型 + 精排 + 聚类):
176
-
177
- - **本地 Embedding**:三后端可选——ONNX(`Xenova/bge-small-zh-v1.5`,离线)/ Ollama / OpenAI 兼容,失败自动逐级降级,最差回退关键词搜索
178
- - **Rerank 精排**:`Xenova/bge-reranker-base` 对召回候选交叉编码精排,提升 Top-K 准确率
179
- - **autoDream 语义增强**:对记忆向量聚类(`clusterMemories`),自动发现主题相近 / 疑似矛盾的记忆,巩固更精准
180
- - **搜索流水线**:混合召回(关键词 + 向量)→ Rerank → Top-K
181
- - **自管运行时**:本地推理的依赖闭包(`@huggingface/transformers` + `onnxruntime-node` + `sharp`,从宿主收编时本机实测 49 个包 / 约 393MB)可收编到 `~/.dsh/mneme/runtime/`,与 profile 的依赖图解耦——由于 profile 是所有插件共用的依赖图,这份闭包留在此前的位置会让「安装任何插件」都替它重走一遍整条依赖链;收编优先硬链接,同盘时几乎不额外占盘。`@huggingface/transformers` 已从 `dependencies` 降为**可选 peer**,因此安装插件不再携带它;正在使用本地嵌入的用户请先按文档收编,否则升级后本地嵌入不可用(读写信道不受影响)
182
- - **取回运行时的三条来源**:① 收编本机已有(零网络、同盘硬链接)→ ② 本地 `.tgz` 目录(`runtimeTarballDir`,某个包网络下不到时用)→ ③ npm registry(`runtimeMirror` 可换镜像),按随包发布的 `runtime-manifest.json` 逐个取并**先校验 sha512 再落盘**(win32-x64 实测约 33 个包 / 2142 个文件 / 数百 MB;清单平台无关,一份覆盖 win32/darwin/linux × x64/arm64;剔除 `onnxruntime-web`——Node 构建从不 import 它)。面板「向量索引」卡片在不就绪时会给出这段代价说明并提供一个按钮;不想开面板也可以让 agent 用 `memory_runtime` 工具(`status` / `provision` / `verify`)代做
183
-
184
- 配置只需在 `cordis.patch.yml` 里设置 `embedProvider`(默认 `openai`,保持 v0.1 行为;改为 `local` 即离线)。升级无需迁移数据。
185
-
186
- ```bash
187
- node scripts/mneme-runtime.mjs status # 运行时在哪、来源、结构是否完整(不加载模型)
188
- node scripts/mneme-runtime.mjs adopt --from ~/.dsh/profiles/<profile>/node_modules
189
- node scripts/mneme-runtime.mjs verify # 真加载运行时并跑一次推理
190
- ```
191
-
192
- > 三个命令的退出码为 `0` 健康 / `1` 不健康 / `2` 用法错误,便于脚本 gate;`--json` 输出机器可读结果。运行时不可用时不会崩——检索降级为关键词/BM25,读写不受影响。详见 [本地模型部署指南 §2.5](docs/LOCAL_MODEL.md)。
193
-
194
- ### 实体结构化记忆(Entity Gene)🧬
195
-
196
- v0.3.0 起新增**记忆基因**层:从记忆里抽取**命名实体**、**带时间轴的属性**、**实体间关系**,让搜索从"字面关键词"升级为"按实体/属性精确召回"。
197
-
198
- - **三表**:`entities` / `entity_attrs`(`valid_until` 快照式时间轴)/ `entity_relations`,旧库打开自动建表,幂等无迁移成本
199
- - **自动抽取**:`entityExtractionEnabled=true` 后,新写入的记忆 fire-and-forget 触发 LLM 抽取(同名实体去重、属性存时间轴、关系追加;失败绝不阻塞写入)
200
- - **实体搜索**(`searchMemories` 前缀路由,`entitySearchEnabled` 默认开):
201
- - `entity:阿尔托` → 属性精确关联的记忆(`_score 1.0`)排在关键词提及(`_score 0.7`)之前
202
- - `attr:国籍=芬兰` → 精确匹配该属性值的记忆
203
- - `attr:国籍` → 该属性键的**全部**当前有效记忆(value 为空契约)
204
- - **autoDream 联动**:update 决策写 `supersedes` 自引用(属性版本被替代);merge 决策把 loser 的属性归属迁移到 keeper(keeper 已有同键当前值则失效)
205
-
206
- > 📖 详见 [实体结构化记忆设计](docs/ENTITIES.md) · [语义增强架构](docs/SEMANTIC.md) · [本地模型部署指南](docs/LOCAL_MODEL.md)
207
-
208
- ### 记忆质量过滤 🧼(v0.4.6,默认开)
209
-
210
- 写库前对每条记忆做**启发式质量打分**(纯函数,无 I/O、无共享状态):元记忆词汇(谈论记忆系统本身)、自指类型标签、内容过短、重复度高、与近期记忆近似重复都会扣分(0-100):
211
-
212
- - `score ≥ 60`:正常存储
213
- - `30 ≤ score < 60`:`quality_score` 落库,注入排序改为按 `importance × quality/100` 降权(degraded)
214
- - `score < 30`:归档并标记 `low_quality`——仍可显式搜索召回,只是**永不自动注入**。**例外(#135)**:`importance ≥ memoryQualityFilter.exemptImportance`(默认 4)的记忆只降权不归档——评分与信号标签照常落库,归档决定不再静默越过用户标注的重要性
215
-
216
- `memoryQualityFilter.enabled` 可整体关闭,`archiveThreshold` / `degradeThreshold` / `minContentLength` / `exemptImportance`(1=全部豁免,5=仅最重要豁免)可调。此外更新记忆(`memory_update` 等)不会抹掉系统信号标签(`low_quality` / `duplicate` / `meta` / `self_referential` / `repetitive` / `short_content`)——它们是「为什么被降权/归档」的审计线索,与用户自传标签并集保留(#135)。
217
-
218
- ### LLM 消耗审计 📊(v0.4.6,默认开)
219
-
220
- 每次**后台 LLM 调用**都会写入 `llm_audit_logs` 表:`tokens` / `duration` / `status` / `source`(由哪个触发产生)。失败调用记为 `status=error`,绝不阻塞功能本体;`retentionDays`(默认 90)在启动时清理超期行。
221
-
222
- 巩固那一轮还有一层**事后判决**:调用成功不等于决策可用,而校验发生在调用之后。判决以 `metadata.decision_validation`(`verdict` / `error_count` / `skipped_count` / `survivor_count` / `invalid_actions`)浅合并回同一行——`status`、tokens、时间戳一律不改,它们是调用层的事实。`verdict` 四档:`unparsed`(没解析出 JSON 数组)/ `rejected`(整单拒绝)/ `degraded`(只应用了合法子集)/ `ok`。有了这一层,「调用成功率」与「整轮有效率」才对得上账。
223
-
224
- 覆盖的后台调用(`source` 即触发源,`operation_type` 区分同一源下的不同调用):
225
-
226
- | `source` | `operation_type` | 说明 |
227
- |---|---|---|
228
- | `autoDream` | `dream_consolidate` / `dream_summarize` | 巩固的整理裁决与总览摘要,各一行 |
229
- | `autoDream` | `dream_narrative` | 叙述条合成,需 `dreamNarrativeEnabled`(默认关)才跑 |
230
- | `autoSummarize` | `summarize_compress` | 空闲蒸馏的压缩 |
231
- | `sleep` | `sleep_conflict` / `sleep_pattern` | Sleep Mode 的冲突裁决与模式挖掘,两阶段各一行 |
232
- | `entityExtract` | `entity_extract` | 实体抽取,**每次写入记忆都会跑** |
233
-
234
- > 后两条链路见 #250——它们是结构上漏接的后台路径(sleep 的 `streamText` 副本没有 `onUsage`、实体抽取适配器拿不到 `service`),不是刻意收窄口径。
235
-
236
- 新增两个只读 API:
237
-
238
- - `GET /api/dsh-mneme/semantic/llm-audit?page=&pageSize=&source=` — 分页查询 + 按 source 过滤
239
- - `GET /api/dsh-mneme/semantic/llm-audit/stats?days=` — 近 N 天按 source 汇总预算(tokens / 次数 / 失败数)
240
-
241
- `/llm-audit/stats` 的 `by_source` 是服务端 `GROUP BY trigger_source`,不做任何白名单过滤,因此新链路自动进入汇总。
242
-
243
- 面板侧现状(#250 之后,未改面板):
244
-
245
- - 「LLM 消耗」卡读 `/llm-audit/stats`,但只渲染 `total_calls` / `total_tokens` 两个总数。新链路的 token 与次数**已经计入这两个总数**,所以「mneme 总共花了多少」现在是对的;
246
- - 按链路的拆分(`by_source`)目前只能从 API 读,面板不展示——「哪条链路最费」在面板上还答不了;
247
- - 状态页活动流仍只显示 `autoDream` / `autoSummarize` 两个硬编码来源(`lib/client.js`),新链路不会出现在活动流里。
248
-
249
- 这三处要动面板(活动流还有一处来源白名单加一处二元标签兜底,且 `pageSize=12` 会被每次写入都跑的实体抽取占满),留到面板批次,不在 #250 内。
250
-
251
- > 实体抽取是**每次写入记忆都会跑**的链路,计入审计后 `llm_audit_logs` 的行数会随写入量线性增长(`retentionDays` 只约束上界、不约束增速)。若实测增速过快,再考虑按 `operation_type` 采样或单独保留期。
252
-
253
- > 只读端点,与 list/search/semantic 一样在设置 `apiToken` 后仍保持开放。
254
-
255
- 沉淀曲线(面板状态页「8 周沉淀」图的数据源):
256
-
257
- - `GET /api/dsh-mneme/semantic/consolidation-stats?days=` — 近 N 天(缺省 56,钳 1–365)按天返回三条序列:`added`(新建记忆,排除外来导入行)、`merged`(当天被巩固掉的**去重记录数**,取自 `receipt_chain` 里 `kind∈(merge,update)` 且 `verdict='live'`)、`archived`(当天进入归档面的条数),另附三个窗口合计。
258
-
259
- `merged` 刻意按去重 `record_id` 数而不是行数:同一条记录被多轮巩固重复记账是常态(活库实测 2412 行只对应 1796 个记录),按行数会把「又记了一遍」算成「又沉淀了一条」。新增与合并背离才是这张图要看的东西——2026-10-25–10-31 那段新增照旧、合并归零,只看新增或只看总量都发现不了。
260
-
261
- ### 记忆库主区视图与记忆图谱 🕸️(v0.5.0)
262
-
263
- 记忆功能从侧边栏抽屉收进**主内容区全宽 tab**(conversation.view 插槽,与「对话 / Trajectory」并列),侧边栏「记忆」入口点击后直接激活该 tab。页面顶部子 tab 行切换三个子视图:
264
-
265
- - **记忆(三栏浏览)**:左栏分类树(类型 + 计数)/ 中栏时间树(月 → 日两级倒序、可折叠)/ 右栏详情(**全文不截断** + 复制全文);语义搜索内嵌工具栏开关(防抖 250ms),`entity:` 前缀可「在图谱中查看」
266
- - **图谱**:输入实体名,加载以该实体为中心的关联网络——
267
- - 服务端只读 ego-graph API:`GET /api/dsh-mneme/semantic/graph/ego?entity=<name>&depth=1|2`(BFS 层级遍历,`limit` 防大图失控,实体不存在 404;配套 `/semantic/graph/entity-attrs` 查实体属性)
268
- - 前端**零依赖手写 SVG 力导向布局**(插件运行时无法 require vis-network 等第三方库):斥力 + 弹簧 + 向心引力物理模拟,节点按类型着色、按提及次数定半径,支持拖拽、点节点看属性、点边跳回来源记忆
269
- - **设置**:画像 / 规则 / 指令 / 向量配置,限宽居中
270
-
271
- 图谱 ↔ 记忆双向互跳:图谱详情侧的关联记忆可点击,记忆边的「来源记忆」按 memory_id 直跳三栏视图并自动定位。
272
-
273
- - **分享包三步(面板)**:「⋯」菜单里的**分享记忆包…**(报告先于下载:进包条数、同键折叠、六个跳过原因、可展开的跳过清单,超水位回 413 同屏)与**导入分享包…**(选文件 → 干跑预览将新建几条 / 撞名几条 → 确认才写库),外来行带 `from-<别名>` 徽标、工具条「外来」chip 按 `source=imported` 服务端筛、抽屉「收起这个包」两段式整包退出(先清点后物删)。口径与判据一条都不在面板里复述——出包在 `src/share.js`、入包闸门在 `src/share-import.js`、协议层在 `src/share-http.js`,细则与实测见 [docs/SHARE.md](docs/SHARE.md)
274
-
275
- ### 四路召回融合与会话热记忆 🔎(v0.5.0,v0.8.4 扩四路)
276
-
277
- - **BM25 稀疏第三路召回**(`src/search/bm25.js`):与向量召回、FTS5/LIKE 关键词并列——ASCII 词元 + CJK bigram 分词、IDF 加权(归一化 [0,1]),专有名词 / ID / 代码片段等散词查询不再依赖子串命中。融合规则:未召回行按 `0.3×BM25分` 回填;仅向量召回行获得词法加分;LIKE 已命中行不叠分。`bm25SearchEnabled` 可关
278
- - **实体图召回轴(第四路,v0.8.4)**(`entityRecallEnabled` 默认关):开启后检索融合池三源扩四源——store 新增 `findEntitiesMentionedIn` / `getLinkedMemoryIds` 反查原语 + `idx_relations_memory` 索引,命中实体所在记忆按边入池,fuseRecall 的 blend / rrf / minmax 全配方参与;实体轴与 BM25 同为确认/回填信号(we 并入 wb 共用 0.3 回填权重),永不主导语义排序,失败降级空数组;keyword 模式纯文本路径不吃实体轴
279
- - **自适应阈值**(`src/search/adaptive.js`):取代固定 `0.65` 截断——`entity:`/`attr:` 前缀放宽 0.5,短查询(<5 字符)收紧 0.7,长查询(>50)放宽 0.6,Top1/Top5 分差 > 0.3 时放宽让尾部进 Rerank;显式传 `threshold` 或 `adaptiveThresholdEnabled=false` 走旧行为
280
- - **会话级短期热记忆**(`src/hot-memory.js`):最近 N 轮对话(默认 5 轮,`hotMemoryRounds`)按 token 预算(默认 2000,`hotMemoryMaxTokens`)滚动截断,从会话事件日志无状态重建、不落库;注入顺序为「短期上下文 → 长期记忆召回 → 摘要」
281
- - **选择性注入**:query 向量可用时注入候选按主题相似度重排(`selectiveInjectEnabled` 可关);**搜索时语义去重**为激进选项(`searchSemanticDedup=true` 显式开启,近重复行 Rerank 前丢弃)
282
- - **召回基准**(`scripts/benchmark-recall.js`):标准查询集驱动,计算 Recall@5 与 MRR,`legacy`(三特性全关)vs `fused`(默认配置)双跑对比
283
-
284
- ## 📜 版本历史
285
-
286
- 🧬 基因 → 🛡️ 审计加固 → 💤 睡眠巩固 → 🕸️ 召回融合与图谱 → 🌡️ 自进化 → 🔐 作用域隔离 → 🌐 MCP 生态 → 🧭 M.O. → 💭 情绪归因 → 📔 日记本
287
-
288
- 当前版本的能力以本 README 正文的配置章节为准——**这张表只留一句话头条**,每一版具体怎么实现见 [CHANGELOG](CHANGELOG.md) 与 [Releases](https://github.com/slow-stack/mneme/releases)。
289
-
290
- | 版本 | 头条 |
291
- |------|------|
292
- | **v0.13.0**(2026-11-10) | 情绪终于有地方可放:`affective_context` 带情绪词与归因,三个独立会话才升成稳定倾向,不足就降级不丢弃 |
293
- | **v0.12.0**(2026-11-07) | pin 从「按类型猜」变成你亲手钉的事实;向量缓存从恒 0% 命中改为跟工作集自适应(1.8–2.4s → 370–424ms) |
294
- | **v0.11.0**(2026-11-05) | 记忆读得懂仓库:文件树与 import 图编译成模块划分与地志页 |
295
- | **v0.10.1**(2026-11-03) | 打开记忆详情不再崩掉整个宿主 |
296
- | **v0.10.0**(2026-11-02) | 记忆开始按「哪一轮」算账:蒸馏有了运行身份,溯源补上反方向 |
297
- | **v0.9.5**(2026-10-30) | 记忆能安全地递出去,也能整包收回来 |
298
- | **v0.9.4**(2026-10-21) | 三条链各自补上「最后一环」:主动整理、画像提取草稿、人格寻址收口 |
299
- | **v0.9.3**(2026-10-20) | M.O. 从「挖得出来」跑到「会被叫去挖」 |
300
- | **v0.9.2**(2026-10-19) | 让「看不见的失败」显形 |
301
- | **v0.9.1**(2026-10-18) | M.O. 从「看得见」跑到「跑得出账」 |
302
- | **v0.9.0**(2026-10-17) | M.O.(工作流)进入 beta:工作流住进项目仓库、可提交可 diff |
303
- | **v0.8.x** | 作用域隔离(agent / workspace 双维)、冲突队列人工裁决、stdio MCP server、图召回轴、冷启动 |
304
-
305
- > 早期版本中的实验性功能(Wiki-Link、tag 系统等)已在 v0.7.11 移除,详见 CHANGELOG 对应条目。
306
-
307
- ## 📦 安装
308
-
309
- ### 前置条件
310
-
311
- - [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)— 兼容 DSH 0.1.x 与 0.2.x(三段式 peer 范围见 `package.json`);开发与 CI 已对齐 0.2 线,`0.2.0-rc.1` / `0.2.0-rc.2` 实测全绿。旧版兼容垫片(`Session.events` → `snapshotEvents()`,v0.7.9 起确保进入发布产物 lib/)保留
312
- - Node 24+(`node:sqlite`)
313
-
314
- ### 安装步骤
315
-
316
- #### 方式一:npm 安装(推荐)
317
-
318
- dsh-mneme 是一个 **bundle**(声明了 `dsh.bundle` manifest),安装即自动激活,无需手动写配置:
319
-
320
- ```bash
321
- # 1. 安装插件(自动注册 bundle 层)
322
- dsh plugin --profile web add @modusensus/dsh-mneme
323
-
324
- # 2. 重启
325
- dsh web
326
- ```
327
-
328
- > 如需自定义配置(阈值、延迟等),可在 `~/.dsh/profiles/web/cordis.patch.yml` 中按 `id: dsh-mneme` 覆盖默认值(见下方配置表)。
329
-
330
- #### 方式二:从源码安装(本地目录)
331
-
332
- ```bash
333
- git clone https://github.com/slow-stack/mneme.git
334
- cd mneme/dsh-mneme
335
- dsh plugin --profile web add "$(pwd)"
336
- dsh web
337
- ```
338
-
339
- > **路径必须绝对**:宿主对 `dsh plugin add` 的本地路径有一条硬校验(`parseInstallSpec` 里的 `a local path must be absolute`),相对路径(含 `.`、`..`)一律拒掉。上面用 `"$(pwd)"` 就地展开,就是为了不给它相对路径。
340
-
341
- #### 方式三:直接从 Git 仓库安装
342
-
343
- 本仓库是**单仓多包**:仓库根那份 `package.json` 是**仓库壳**(`private`、不带 `dsh` 字段),插件本体在 `dsh-mneme/`。所以 Git 地址必须带 `#path:` 指到子目录:
344
-
345
- ```bash
346
- dsh plugin --profile web add 'git+https://github.com/slow-stack/mneme.git#path:/dsh-mneme'
347
- dsh web
348
- ```
349
-
350
- | 写法 | 结果 |
351
- |------|------|
352
- | `git+https://github.com/slow-stack/mneme.git#path:/dsh-mneme` | ✅ 装出 `@modusensus/dsh-mneme`(实测 0.9.0,38 个包) |
353
- | `https://github.com/slow-stack/mneme#path:/dsh-mneme` | ✅ 同上;lockfile 会归一成 `github:slow-stack/mneme#path:/dsh-mneme` |
354
- | `git+https://github.com/slow-stack/mneme.git` | ❌ 装到仓库根那份壳(`0.0.0`、无 `dsh` 字段),宿主不认它是插件 |
355
-
356
- `#path:` 是 pnpm 的 git 参数(`parseGitParams` 里按 `path:` 前缀解析),**不是**本仓库自定义的语法;pnpm 官方文档没写这一条,所以这里给出实测结果。
357
-
358
- #### 方式四:tarball
359
-
360
- ```bash
361
- cd dsh-mneme
362
- npm pack # 产出 modusensus-dsh-mneme-<版本>.tgz
363
- dsh plugin --profile web add "C:/path/to/modusensus-dsh-mneme-0.9.0.tgz"
364
- ```
365
-
366
- > 必须用 `npm pack`,别用 `pnpm pack`:`bin/cli.mjs` 在工作区里是 CRLF,pnpm 会以 `ERR_PNPM_BIN_CRLF` 直接失败。
367
-
368
- #### 自定义配置(可选)
369
-
370
- 默认配置即可用。如需调整,在 `~/.dsh/profiles/web/cordis.patch.yml` 中覆盖:
371
-
372
- ```yaml
373
- - id: dsh-mneme
374
- name: '@modusensus/dsh-mneme'
375
- config:
376
- memoryDir: ~/.dsh/memory
377
- language: zh
378
- autoInject: true
379
- autoSummarize: true
380
- maxInjectedItems: 5
381
- importanceThreshold: 3
382
- autoDream: true
383
- dreamThresholdCount: 10
384
- dreamThresholdChars: 5000
385
- dreamDelayMs: 2000
386
- ```
387
-
388
- ## 怎么升级(设置不会丢)
389
-
390
- **升级只动代码,不动你的记忆和设置。**
391
-
392
- 设置与记忆是**同一个 SQLite 文件**里的表(`user_settings` 与 `memories` 等),文件位置由 `memoryDir` 决定,默认在 `~/.dsh/memory`——**不在插件安装目录下**。所以卸插件、装插件都不碰它。
393
-
394
- 升级就是覆盖安装,装完重启一次:
395
-
396
- ```bash
397
- # --profile 后面写你当初安装它时用的那个名字,默认是 web
398
- dsh plugin --profile web remove @modusensus/dsh-mneme
399
- dsh plugin --profile web add @modusensus/dsh-mneme
400
- dsh web
401
- ```
402
-
403
- > 上面是 npm 来源的装法;当初从 Git、tarball 或本地目录装的,按下同一种来源重装即可。唯一要求是**先 remove 再 add**。
404
- > 不用重装 DSH。重装 DSH 动的是 profile,是更大范围的改动,与插件版本无关。
405
- > 也不要只 `add` 不 `remove`——宿主可能拿到缓存的旧副本,版本号没变就说明没换成。
406
-
407
- **这件事是实测过的,不是推断**:用 v0.12.0 的代码建库、写入画像、规则、人格卡与四个功能开关,再换成本次发布的代码打开同一个库——四项全部原样读回。反向也测了:新代码写的库,v0.12.0 同样读得出来。
408
-
409
- **但有两处不对称要提前知道**:人格卡的按会话分配(`bySession`)以及 `scenario` / `mesExample` 两个字段,v0.12.0 都不认识——用旧版打开新版写的库,这些键读不出来,旧版再写回时可能把它们覆盖掉。所以**回退前先备份整个记忆库目录**(复制 `memoryDir`,默认 `~/.dsh/memory`),需要回退时把库一起退。另外,撤销某个开关只影响之后的行为,不保证把已经写下的数据(例如已经铸出的情绪倾向)一并回滚——要真正清掉得手动删对应条目。
410
-
411
- 唯一会让你丢数据的是**把库指进 profile 作用域**(形如 `…/profiles/<名字>/…`),宿主清理 profile 时会连带带走——把 `memoryDir` 保持在 profile 之外即可(默认就是),要迁移库则:停止写入 → 复制整个目录 → 改配置指向新位置 → 重启。
412
-
413
- ## ⚙️ 配置
414
-
415
- | 键 | 默认值 | 说明 |
416
- |----|--------|------|
417
- | `memoryDir` | `~/.dsh/memory` | 记忆存储目录(SQLite + Markdown) |
418
- | `language` | `zh` | 记忆语言:生成的记忆条目、注入标题与后台 LLM 提示词所用语言(`zh` / `en`) |
419
- | `autoInject` | `true` | 会话启动自动注入记忆 |
420
- | `autoSummarize` | `true` | 会话结束自动提炼摘要 |
421
- | `summarizeProvider` / `summarizeModel` | 空 | 摘要的 LLM 路由覆盖(空=使用当前会话模型);推荐轻量模型节省主模型 token |
422
- | `summarizeMinIntervalMinutes` | `0` | autoSummarize 最小触发间隔(0-10080,0=不限):两次蒸馏之间最短间隔,失败/degraded run 也占用(#127) |
423
- | `summarizeMaxEntriesPerRun` | `0` | 单次蒸馏产出记忆条数上限(0-50,0=不限):节流防单会话大量重复条目(#127) |
424
- | `summarizeMinWindowChars` | `0` | 蒸馏前零 LLM 预判:窗口可蒸馏文本不足此字符数直接跳过调用(0-100000,0=关);skip 原因写入审计(#239) |
425
- | `summarizeMaxRunsPerSession` | `0` | 每会话最多发起多少次蒸馏 LLM 调用(0-1000,0=不限);只计真实调用,被预判拦下的不占额度(#239) |
426
- | `summarizeParseFailureMaxRetries` | `0` | 连续几次解析失败后放弃当前窗口(0-10,0=关):确定性失败(模型把转录当成该自己回话,`finish_reason=stop`)重试收益为 0,而窗口只会越攒越大;设 2-3 可止血,达到阈值强制消费游标跳过,失败行 metadata 带 `raw_head`/`raw_has_bracket`/`streak`(#493) |
427
- | `summarizePeakHours` | 空 | 高峰时段(本地时间,逗号分隔、可带星期前缀,支持跨零点):空=关;命中时蒸馏顺延到非高峰、窗口累积后一次蒸、skip 原因入审计。例:按高峰计费的供应商可写 `mon-fri 08:00-12:00,14:00-18:00`(如 DeepSeek,以其官方定价页为准)(#239) |
428
- | `summarizePeakMaxDeferMinutes` | `120` | 高峰顺延上限(0-1440 分钟,0=不设上限):到点仍处高峰就照常跑,避免长高峰把蒸馏饿死(#239) |
429
- | `summarizeDedupeMode` | `off` | 落库前去重档位:`off`(默认=现状)/ `title`(零成本,仅拦完全同名)/ `vector`(复用 embedding 列做同会话语义近邻,无 LLM 调用,#127) |
430
- | `summarizeDedupeMinSim` | `0.92` | vector 去重档的相似度阈值(0.5-0.99) |
431
- | `summarizeDedupeWindowHours` | `24` | vector 去重的同会话时间窗(小时,0-168) |
432
- | `distillMaxChars` | `24000` | 蒸馏输入的正文截断上限(1000-200000):防止单轮转录把 LLM 输入撑爆 |
433
- | `distillRateLimitIntervalMs` | `1000` | 蒸馏 LLM 调用全局串行队列的最小间隔(ms,0-60000,429 保护默认开) |
434
- | `distillRateLimitRetries` | `3` | 命中 429 限流时的指数退避重试次数(0-10) |
435
- | `distillRateLimitBaseDelayMs` | `1000` | 429 退避基准延迟(ms):1s→2s→4s… |
436
- | `maxInjectedItems` | `5` | 最多注入几条记忆 |
437
- | `injectUncertaintyAdaptive` | `false` | 注入条数的查询自适应:确定性强的话题把条数收缩到一半(下限 1),模糊话题(回指/时间线索,或极短查询)维持 `maxInjectedItems` 上限;**只做单向收缩**,判据只看查询本身、不做额外检索(#239 第 5 项) |
438
- | `injectRotationTurns` | `0` | 注入位跨轮轮换:同一条记忆在最近 N 个查询轮次注入过后本轮不再优先(新鲜优先、不足回填,槽位数不变;会话边界自动重置;`0` = 关闭保持现状) |
439
- | `injectContentMaxChars` | `300` | 注入单条正文截断上限(60-4000,原硬编码 300,#164①/#225):截断尾部带上限/原长/全文 `memory_get` 指引;块预算 `Math.max(1500, 上限+600)` 随上限放大 |
440
- | `importanceThreshold` | `3` | 注入的最低重要性(1-5) |
441
- | `autoDream` | `true` | 自动记忆整理开关 |
442
- | `dreamThresholdCount` | `10` | 触发整理的记忆条数阈值 |
443
- | `dreamThresholdChars` | `5000` | 触发整理的总字符阈值 |
444
- | `dreamDelayMs` | `2000` | 整理异步延迟(去抖) |
445
- | `dreamProvider` / `dreamModel` | 空 | dream 的 LLM 路由覆盖(显式配置优先于 agent 默认模型;留空则回退到 agent 默认模型) |
446
- | `dreamMaxTokens` | `131072` | dream LLM 调用最大 token 数(上限 131072;#135 起默认即上限——思考型模型的 reasoning 与正文共享该预算,正文仍为空时优先换非思考模型或调 `dreamProvider`/`dreamModel`,见下方调优指南) |
447
- | `dreamReasoningEffort` | 未配置=最低档 | dream LLM 推理强度透传:`off` / `low` / `medium` / `high` / `none`(未配置 = 自动取模型支持的最低档,避免思考模型用自带默认档烧光预算;`none`=不传该字段、用服务商自带默认;v0.7.26+ 模型不支持配置档位时自动换用其支持的默认/首个档位,无 reasoning 能力的型号省略字段) |
448
- | `dreamCandidateMode` | `window` | dream 候选集构造:`window`(只取最近 `dreamMaxSnapshotSize` 条)/ `hybrid`(在此基础上并入向量翻出的高相似组)。纯时间窗口下,实测 45 对「双方活跃且 sim≥0.85」里 0 对能同时进窗口——该合并的一对几乎永远碰不到面。**已知边界**:dream 侧动作集仍是五分支(keep / merge / archive / update / conflict),hybrid 翻出的互补型 / 演进型对在 dream 里没有 `differentiate` / `supersede` 出口;正确出口在 sleep 侧(`sleepActionSet: full`)|
449
- | `dreamCandidateMax` | `0` | hybrid 的候选总量上限;`0` = 复用 `dreamMaxSnapshotSize`。候选总量与库总量解耦,输入成本不随库增长 |
450
- | `dreamCandidateMinSim` | `0.85` | hybrid 判「高相似」的阈值(与 sleep 的 normal 档对齐,两个模块共用同一个「高相似」定义) |
451
- | `dreamMaxArchivePerRun` | `8` | 单轮 archive 决策上限(超限整单拒绝,防一次性大扫除;正常清理可调高) |
452
- | `dreamMaxMergePerRun` | `40` | 单轮 merge 决策上限(超限整单拒绝)。merge 是巩固里唯一回吐正文的动作(每条要模型重写合并后的 content),所以这是「输出里正文占比」唯一可控的杠杆;默认 40 = 实测每轮 merge 数分布上沿(全库 p99 28 / max 39,历史 0 命中),与 archive 闸默认 8 同为尾险护栏而非成本削减工具。**注意**:`dream_consolidate` 的输出 token 里只有约 11.8% 是决策正文,其余约 88% 是推理与 JSON 骨架——想省 token 请调 `dreamReasoningEffort` 或换非思考模型,调小本键收益有限 |
453
- | `dreamSkipInvalid` | `true` | 单条非法决策跳过 + 合法子集应用 + run 记 degraded(#89);`false` 恢复严格模式整单拒绝 |
454
- | `allowCrossTypeMerge` | `false` | 显式放宽跨类型合并(默认关,类型边界由用户承担);跨类型意图的正确出口是 `sleepActionSet: full` |
455
- | `dreamImplicitKeep` | `true` | 显式决策覆盖率不足时的隐式 keep(未提及条目保持原样);`false` + `dreamMinExplicitCoverage: 0` 恢复旧严格行为 |
456
- | `dreamMinExplicitCoverage` | `0.5` | 显式决策覆盖率下限(0-1):合法子集低于该值降级 degraded 而非整单拒绝(#104 方向 1,PR #200) |
457
- | `dreamMaxSnapshotSize` | `200` | autoDream 滑动窗口上限:每次只对最近 N 条做 consolidation,窗口外不进 snapshot(防 LLM 输入撑爆) |
458
- | `dreamSummaryProvider` / `dreamSummaryModel` | 空 | 总览(dream_summarize)专用模型路由(留空 = 沿用 `dreamProvider`/`dreamModel`)。consolidate 有窗口(`dreamMaxSnapshotSize`)而总览输入随库增长,ctx 需求差数倍——用小 ctx 模型跑巩固时把总览指到大 ctx 模型(issue #258) |
459
- | `dreamSummaryMaxInputs` | `0` | 总览输入条数硬上限(0 = 不设上限):超过时按 `updated_at` 倒序只保留最新 N 条进总览,防小 ctx 模型被全库输入撑爆;总览口径脚注的条数随实际输入变化 |
460
- | `dreamMinIntervalMinutes` | `0` | autoDream 最小触发间隔(0-10080,0=不限):失败/degraded run 也占用 |
461
- | `dreamPeakHours` | 空 | 巩固侧高峰时段(本地时间,与 `summarizePeakHours` **同一份语法**):空=关;命中时不调模型、baseline 不刷新(阈值继续累积,留到非高峰一次性巩固)、登记 `skipped`/`peak-hours` 审计并顺延到最近的高峰结束时刻。适合「白天要留算力给交互、巩固挪到夜里」的场景(#239 第 4 项镜像到巩固) |
462
- | `dreamPeakMaxDeferMinutes` | `120` | 巩固侧高峰顺延上限(0-1440 分钟,0=不设上限):到点仍处高峰就照常跑,避免长高峰把巩固饿死(#239) |
463
- | `dreamNarrativeEnabled` | `false` | 叙述条总开关(#164 对齐,v0.8.4):按共享 tag 主题簇合成叙述 + evidence 证据链,注入候选排除(按需检索,常驻位只留 dream 总览);也走 feature_flags 白名单,lightMode 强制关 |
464
- | `dreamNarrativeMinCluster` | `3` | 主题簇合成叙述的最小成员数(2-20,v0.8.4) |
465
- | `apiToken` | 空 | 可选 API 鉴权 token;设置后写操作与密钥接口要求 `Authorization: Bearer <apiToken>` |
466
- | `externalApiEnabled` | `false` | 独立 HTTP API 服务开关(v0.7.12):开 standalone API(CLI 依赖它) |
467
- | `externalApiHost` | `127.0.0.1` | standalone API 监听地址 |
468
- | `externalApiPort` | `8790` | standalone API 监听端口 |
469
- | `lightMode` | `false` | 轻量模式(v0.7.12):关闭所有重型增强(语义/实体/叙述/heat 等,见 feature_flags 白名单),纯存储+注入 |
470
- | `policyEpoch` | `0` | 冲突裁决规则版本:bump 后旧 dream_runs 降级为历史证据(receipt 不再驱动实时裁决) |
471
- | `embedProvider` | `openai` | 语义后端:`openai`(默认,兼容 v0.1)/ `local`(ONNX 离线)/ `ollama` |
472
- | `localEmbedModel` | `Xenova/bge-small-zh-v1.5` | 本地 ONNX embedding 模型 |
473
- | `localEmbedDimension` | `512` | 本地 embedding 向量维度 |
474
- | `localEmbedDevice` | `cpu` | 本地推理设备:`cpu` / `gpu` |
475
- | `localEmbedBatchSize` | `8` | 本地 embedding 批大小(1-64) |
476
- | `ollamaBaseUrl` | `http://localhost:11434` | Ollama 服务地址 |
477
- | `ollamaModel` | `nomic-embed-text` | Ollama embedding 模型 |
478
- | `embedModelCacheDir` | 空 | 模型缓存目录(空 = 用户级 `~/.dsh/mneme/models`) |
479
- | `embedModelMirror` | `https://hf-mirror.com` | 模型下载镜像源 |
480
- | `resilientModelDownload` | `true` | 模型文件下载断点续传与重试(v0.8.3,#194/#207):Range/If-Range 续传、416/偏移失配重置、单写者锁+降级直通、空闲看门狗;`false` 恢复 env.fetch 原样 |
481
- | `runtimeDir` | 空 | 自管运行时目录(#131):空 = `~/.dsh/mneme/runtime`,放收编/下载的 transformers+onnxruntime 闭包(不留宿主 profile 依赖图) |
482
- | `runtimeTarballDir` | 空 | 运行时离线取件:本地 `.tgz` 目录(如 onnxruntime-node 网络下不到时 `npm pack` 丢进去),有则优先于联网 |
483
- | `runtimeMirror` | 空 | 运行时 registry 镜像前缀(如 `https://npmmirror.com/mirrors/npm/`);留空用 runtime-manifest.json 官方地址 |
484
- | `vectorSearchTopK` | `20` | 向量搜索返回 Top-K |
485
- | `vectorSearchThreshold` | `0.65` | 向量搜索相似度阈值 |
486
- | `hybridSearchVectorWeight` | `0.6` | 混合搜索向量权重 |
487
- | `hybridSearchKeywordWeight` | `0.4` | 混合搜索关键词权重 |
488
- | `recallFusion` | `blend` | 召回融合配方:`blend`(默认,加权求和)/ `rrf`(Reciprocal Rank Fusion)/ `minmax`(min-max 归一化加权)——后两者按 rank/尺度感知融合,修复原始分数单位不匹配 |
489
- | `signalTransparency` | `false` | 给每条检索结果附加 `signals` 对象({keyword, vector, bm25, final})便于调试;只装饰不改排序 |
490
- | `rerankEnabled` | `false` | 是否启用 Rerank 精排(显式开启才加载本地 onnxruntime 模型) |
491
- | `rerankProvider` | `none` | Rerank 后端:`local` / `none`(默认 `none`) |
492
- | `rerankModel` | `Xenova/bge-reranker-base` | Rerank 交叉编码模型 |
493
- | `rerankBatchSize` | `8` | Rerank 批大小 |
494
- | `rerankMaxCandidates` | `30` | Rerank 最大候选数 |
495
- | `rerankScoreThreshold` | `0.1` | Rerank 分数阈值(低于丢弃) |
496
- | `rerankDtype` | `q8` | Rerank 模型量化档(`q8` ≈ fp32 体积的 1/4,`fp32` 可关) |
497
- | `reflectionUpdateEnabled` | `true` | update 决策总开关 |
498
- | `reflectionFailureTracking` | `true` | 失败追踪总开关 |
499
- | `reflectionUpdateMaxPerRun` | `2` | 每次整理最多 update 数 |
500
- | `reflectionUpdateMinAgeHours` | `24` | 新建记忆保护期(小时) |
501
- | `reflectionFailureRetentionDays` | `90` | 失败表(`failure_memories`)启动期清理保留天数(1-3650;此前写死 90) |
502
- | `codingRetrospect` | `false` | 编码记忆蒸馏(v0.7.13,默认关):完整转录提炼编码原子记忆(rejected_solution/pitfall/constraint 三类型) |
503
- | `codingKeywords` | 内置词表 | 编码任务识别词表(读取侧门控):命中即视为编码类任务,编码记忆才注入 |
504
- | `codingBoostFactor` | `2` | 编码记忆注入排序的 boost 倍数(1-5) |
505
- | `entityExtractionEnabled` | `false` | 实体抽取总开关(v0.3.0;存储层恒可用) |
506
- | `entityExtractionModel` | 空 | 抽取专用模型(空 = 用 agent 默认模型) |
507
- | `entityExtractionProvider` | 空 | 抽取专用模型服务商(空 = 用 agent 默认 provider/model,v0.7.29) |
508
- | `entityExtractionReasoning` | 未配置=最低档 | 实体抽取推理档位(同 dreamReasoningEffort 语义,v0.7.29):被模型拒绝时自动去 effort 重试 |
509
- | `entityExtractionMaxEntities` | `10` | 每次抽取实体数上限 |
510
- | `entityRecallEnabled` | `false` | 图召回轴(v0.8.4,#219):实体挂联记忆并入检索融合池(三源扩四源,blend/rrf/minmax 全配方参与);依赖实体抽取产出,也走 feature_flags 白名单,lightMode 强制关 |
511
- | `entityExtractionMaxAttrs` | `20` | 每实体属性数上限 |
512
- | `entitySearchEnabled` | `true` | `entity:` / `attr:` 前缀搜索开关 |
513
- | `trustEpistemicWeighting` | `false` | 记忆可信度加权(v0.4.5,opt-in 默认关):记忆按来源分级 `observation`> `inferred` > `subjective`,开启后检索排序优先高可信记忆、注入对 observation 标注 `[verified]`、dream merge/conflict 偏向高可信一方;关闭时 `epistemic_status` 仅随保存落库、不参与行为 |
514
- | `evalPersistTestResults` | `false` | 检索评估落库(v0.4.5,opt-in 默认关):开启后 `evaluateRetrieval` 把 precision/recall/mrr 快照写入 `recall_evals`;默认关时仅返回调用方不落库。生产 `searchMemories` 审计始终走 `recall_runs`,无条件不触碰 `recall_evals` |
515
- | `autoReindexOnBoot` | `true` | 存量记忆缺 embedding 时,向量已配置则启动后延迟后台按批次限速自动回填重建(设为 `false` 仅手动重建)。只补**活跃**记忆(归档/遗忘行不参与召回,#128);模型指纹一致时照常补缺失行、不再短路(#128) |
516
- | `hybridInject` | `true` | 注入语义召回优先(v0.4.6,Bug4):`injectCandidates` 带非空 query 时先走向量索引语义召回候选,规则筛选补足/去重;空 query / 无向量回退旧逻辑 |
517
- | `bm25SearchEnabled` | `true` | BM25 稀疏第三路召回(v0.5.0):ASCII 词元 + CJK bigram,IDF 加权,散词/ID/代码片段查询不再依赖子串命中 |
518
- | `adaptiveThresholdEnabled` | `true` | 自适应相似度阈值(v0.5.0):按查询形态动态截断(前缀 0.5 / 短查询 0.7 / 长查询 0.6 / 头部分差大放宽 0.5),显式传 `threshold` 走旧行为 |
519
- | `hotMemoryEnabled` | `true` | 会话级短期热记忆总开关(v0.5.0):关闭后热记忆块不再注入(长期召回不受影响) |
520
- | `heatEnabled` | `false` | 热度模型总开关(v0.7.0 / v0.7.20 回归,**默认关**——v0.7.12 起用户已习惯无 heat 行为):开启后提供热度字段 / sleep 热联合降级保护 / 前端热度投影;注入排序乘热度已拆为独立开关 `injectHeatEnabled`(#218 / E5 考卷:heat 乘进注入排序在真实年龄混合下饿死老约束,默认关,显式开启恢复旧序)。关闭则跳过 heat 计算与热度触达,sleep 降级退回纯时间分层。也走 feature_flags 白名单(面板可启停=回滚开关),lightMode 预设强制关 |
521
- | `heatGlobalBeta` | `1.0` | 广义指数形状参数 β(`H=exp(-λ·Δt^β)`,issue #218 拍板):β=1 纯指数;以 Δt>1 小时为准,β<1 衰减更慢(亚线性长尾)、β>1 衰减更快(超线性);0<Δt<1 的首小时内方向相反(Δt^β 随 β 增大而变小) |
522
- | `heatTypeDecay` | 内置 TYPE_DECAY | per-type 衰减因子 λ;λ=0 的类型免疫(preference/pattern/summary 热度恒 1.0,sleep 永不降级) |
523
- | `sleepHeatThreshold` | `0.05` | sleep 降级联合判定热度下限:heat<该值 **且** importance<5 才允许降级 |
524
- | `sleepModeEnabled` | `false` | Sleep Mode 总开关(v0.4.0,opt-in):会话空闲 `sleepIdleMinutes` 后触发深维护(巩固/降级/模式发现),与 autoDream 串行不重叠 |
525
- | `sleepIdleMinutes` | `5` | 触发 sleep 的空闲窗口(分钟,1-60) |
526
- | `sleepMinIntervalHours` | `8` | 两次 sleep 最小间隔(小时,1-168):间隔内再次空闲不重复触发 |
527
- | `sleepConflictStrictness` | `normal` | 冲突裁决严格度:`gentle`(高置信,阈值 0.92)/ `normal`(标准,0.85)/ `aggressive`(低置信也裁决,0.75) |
528
- | `sleepActionSet` | `conflict` | sleep 冲突阶段动作集:`conflict`(默认=现状,只用 conflict/keep,后台流程不静默扩张)/ `full`(六分支 merge/update/supersede/differentiate/conflict/keep,#126) |
529
- | `sleepArchiveDays` | `30` | 降级分层一:N 天未访问 → 缩为摘要(正文进 `_full_content`) |
530
- | `sleepCompressDays` | `90` | 降级分层二:N 天未访问 → 直接归档(实体关系保留) |
531
- | `sleepPatternMinMemories` | `100` | 模式发现扫描窗口(最近 N 条记忆,10-1000) |
532
- | `sleepPatternLookbackDays` | `30` | 模式发现回看实体属性变更的天数(1-90) |
533
- | `sleepMaxPatternPerRun` | `3` | 每轮模式记忆产出上限(0=禁用,0-10) |
534
- | `sleepProvider` / `sleepModel` | 空 | sleep 深维护专用 LLM 路由覆盖(留空用巩固模型或当前模型;建议同巩固模型选非思考模型) |
535
- | `sleepReasoningEffort` | 未配置=最低档 | sleep 各阶段 LLM 推理档位(同 dreamReasoningEffort 语义,v0.7.26) |
536
- | `recallRecordDefault` | `true` | recall_runs 记录默认开(显式传 `recordRecall:false` 的调用方不受影响);注入同样落账(`mode='inject'`,随本开关,#217) |
537
- | `recallRetentionDays` | `90` | recall_runs 滚动清理保留天数 |
538
- | `hotMemoryRounds` | `5` | 会话级短期热记忆轮次(v0.5.0):最近 N 轮对话滚动注入,从会话事件日志无状态重建、不落库 |
539
- | `hotMemoryMaxTokens` | `2000` | 热记忆 token 预算(v0.5.0,200-32000),超出滚动截断 |
540
- | `selectiveInjectEnabled` | `true` | 选择性注入(v0.5.0):query 向量可用时注入候选按主题相似度重排,替代固定规则序 |
541
- | `searchSemanticDedup` | `false` | 搜索时语义去重(v0.5.0,激进选项默认关):embedding 余弦 ≥0.95 近重复行在 Rerank 前丢弃 |
542
- | `searchSemanticDedupThreshold` | `0.95` | 语义去重相似度阈值(v0.5.0,默认 0.95,范围 0.5-1.0):`searchSemanticDedup=true` 时生效,调整可防小模型误折叠 |
543
- | `memoryQualityFilter` | `{enabled:true, archiveThreshold:30, degradeThreshold:60, minContentLength:10, exemptImportance:4}` | 记忆质量过滤(v0.4.6,默认开):写库前启发式打分 0-100,元记忆词汇/自指/过短/重复/近似重复扣分;≥60 正常存储,30-60 降权(注入排序按 importance×quality/100),<30 归档标记 `low_quality`(显式搜索仍可召回,永不自动注入;`exemptImportance` 豁免:importance ≥ 该值只降权不归档,#135) |
544
- | `llmAudit` | `{enabled:true, retentionDays:90}` | LLM 消耗审计(v0.4.6,默认开):每次后台 LLM 调用(`autoDream` / `autoSummarize` / `sleep` / `entityExtract`,对应 `operation_type` 为 `dream_consolidate` / `dream_summarize` / `dream_narrative`、`summarize_compress`、`sleep_conflict` / `sleep_pattern`、`entity_extract`)写 `llm_audit_logs`(tokens/duration/status/source);失败记 error 不阻塞;只读 API `/api/dsh-mneme/semantic/llm-audit` + `/llm-audit/stats` |
545
- | `scopeEnabled` | `false` | 作用域隔离总开关(v0.8.0,issue #17):memory_save 按会话身份写入 agent / workspace 标注(agentPreset / 工作区路径,registry 反查取不到回退 header.cwd,再取不到 NULL);去重键扩展含作用域三元——跨作用域同标题不再物理合并;检索与注入排序按当前会话作用域加权(命中 ×1.25、他 scope ×0.5 保留可见,issue #339 补齐注入通道)。也走 feature_flags 白名单(面板可启停) |
546
- | `strictScope` | `false` | 作用域硬过滤(v0.8.0 引入,v0.8.1 起只认显式声明;依赖 `scopeEnabled`):检索 / 注入 / 列表 / 单取四路过滤,**显式声明**收窄到他者作用域的记忆完全不可见;载体自动标注只降权保留可见——真正的物理隔离请用 sensitivity。会话身份解析不到时 fail-closed 只挡显式行。关闭时全部为软隔离(降权保留可见)。也走 feature_flags 白名单 |
547
- | `writeAdmission` | `{enabled:false, enforce:false}` | 写入准入(issue #254,默认关):把「这条该不该进库」前移到 LLM 之前。第 1 级是零 LLM 的确定性判据——空白 / 纯噪声 + 密钥 / PII(判据来源是 #164 A2,经 `sensitiveScan` 注入,本批只定义接口)。`enabled` 跑判据并落审计行(`llm_audit_logs` 的 `metadata.deny`),`enforce` 才真的拒(`store.save` 之前返回,`memory_save` 返回 `action:"denied"` + `reason`);只开 `enabled` = 仅告警、写入不拦。去重键命中不进第 1 级(归 write-update 放行),G1/G2 阈值只计量。也走 feature_flags 白名单 |
548
- | `preInjectGate` | `{enabled:false, enforce:false}` | 注入前判定(issue #380,默认关):每帧注入候选出池后、进入 system prompt 前,一次池级 LLM 调用判出「会向本次请求注入意见/立场」的记忆(判定协议与 E12 实验同源;实测过滤把谄媚 26.9%→2.5%,且判定结果绝不进模型上下文——给模型看标记的线已被 E2/E3 关闭)。`enabled` 跑判定并落审计行(真实 token 用量 + 被标记记忆 id),`enforce` 才在缓存命中帧真滤除;冷缓存首帧降级为原样注入(宿主注入渲染是同步回调,判定走 prefetch+cache)。pin 池与检索线索行豁免;判定失败原样注入不阻塞;整池被标记时放弃本次滤除(fail-open);判定连续失败 3 次熔断一个冷却期;无默认路由时审计行 `model_id` 落 `unknown` 占位;`llmAudit` 关闭时本闸不运行;lightMode 强制关。也走 feature_flags 白名单 |
549
- | `distillRecords` | `{enabled:false, retentionDays:90}` | 蒸馏原文留存 + 记忆级溯源(issue #399,默认关):把蒸馏从「替换」降级为「叠加索引」——蒸过的窗口原文旁路落 `distill_records`(一个事件一行,主键 `(session_id, seq)`,`INSERT OR IGNORE` 幂等),每条新记忆落 `memory_provenance` 回指来源窗口(`(memory_id, session_id, seq_start, seq_end)` 唯一)。**渲染与落盘共用同一隐私谓词**:私有推理链、插件注入的机器内容(AGENTS.md / skill 正文 / 文件变更通知)两条路都不进;工具调用入参与结果、code 输出**只进渲染、不落盘**(渲染是 `codingRetrospect` 的输入,落盘只留对话)。留存文本**不受** `distillMaxChars` / 工具裁剪约束(原文就是原文)。到期裁剪只删 `distill_records`,溯源链接保留指向空区间(面板显示「来源已过期」),**绝不级联删记忆**;删记忆时显式清链接。无历史回填、从未蒸馏的窗口不留记录。进 `dsh-mneme reclaim` 报告第三项;lightMode 强制关。也走 feature_flags 白名单 |
550
- | `capacityWarning` | `{dbSizeWarnMb:256, archivedRowsWarn:5000, archivedRatioWarn:0.95}` | 容量预警(issue #275,空间维度):库体积 / 归档区规模过线时在 `GET /api/dsh-mneme/health` 的 `capacity` 块与面板「库体积」卡上报。三道阈值都是**观察口**,不是动作触发——没有周期性消费者,预警也永不自动归档 / 删除(真删由人显式确认),出口是维护卡的无损回收(`dsh-mneme reclaim`)。阈值判 `>=` 过线、**0 = 关掉该条检查**;判级 fail-safe(读失败显式 unknown,绝不伪装 ok)。默认值锚定 #275 议题的形态区间(活跃数百 / 归档数千;占比健康区就在 0.8~0.9,故 0.95 起才算过线)。答复只带数字、不带库文件路径;归档净增速率是 recall-stats `archive` 块的第五指标,不在这里重复。也走 feature_flags 白名单(改动启动快照生效,面板显示「待重启」) |
551
- | `conflictFreezeEnabled` | `false` | 冲突冻结(v0.4.4):dream 发现矛盾对不自动裁决,冻结进冲突队列;状态页「冲突队列」支持并排对比与人工确认(保留 A / 保留 B / 仅标记已处理,v0.8.0) |
552
- | `conflictFreezeMaxPending` | `100` | 冲突冻结队列最大挂起数(1-1000):超出后不再入队(防队列无限膨胀) |
553
- | `escapePromptVariables` | `true` | 注入文本花括号转义(v0.8.0 恢复,issue #162):注入边界把 `{{...}}` 转义,防止 hot memory / 记忆原文里的 Go template / Vue 语法触发宿主 interpolate 抛错卡死会话(v0.7.4 曾修复、v0.7.11 误删) |
554
-
555
- > 🔐 **API 安全**:DSH 无内置鉴权且默认仅监听 `127.0.0.1`。插件 API 默认开放(便于 Web 面板即装即用)——**未配 `apiToken` 时读和写都开放**,真正的围栏是回环 + 宿主监听器的 Host/Origin 校验(它防 DNS rebinding 与跨站浏览器请求,但不建立身份)。如需防护(如局域网暴露),在配置中设置 `apiToken`:此时**写操作**(新增/更新/删除/导入/收包(`/receive`、`/receive/undo`——写的是**本机自己的库**,归 `token-write`,所以免 token 的 GET 在那两条路径上只会拿到 405)/画像/规则/命令/开关/开关计费类)与**敏感读**(`/export`、`/external-api`、`/vector-config`、`/vector-reindex`、`/maintenance/*`、`/runtime/provision`、`/share`、`/memory/provenance`(蒸馏窗口的逐条会话原文,另受 `distillRecords.enabled` 门控))需携带 `Authorization: Bearer <token>`(前端设置面板填同一个 token);只读的 `list` / `search` / `semantic` / `inject-preview` 等**仍然开放**,不要把它们当成被 token 保护的面。`/api/dsh-mneme/vector-config` 返回的 `apiKey` 已掩码(`sk-***…`),存储仍保留明文供调用;前端回传空或掩码值表示"不改 key"。
556
- >
557
- > 安全模型全表(哪些路由免鉴权、为什么)见 [SECURITY.md](../SECURITY.md#5-security-model-what-actually-protects-what)。
558
-
559
-
560
- > ⚠️ **已知边界:极简模式(minimal agent preset)下不注入**(宿主设计,非插件缺陷):minimal 预设的组合文件显式 `complete: true` + `includeRuntimeContext: false`——整条系统提示词被 persona 钉死、全部 runtime context 快照被压制,**记忆注入 / 用户画像 / hot memory 在极简模式会话中一律不送达模型**(宿主内置 context 同样消失)。判断与解法:会话头部显示「极简模式」即为该形态;需要记忆注入请改用标准模式(会话级切换,或 `~/.dsh/settings.yaml` 设 `agent-presets.default: standard`——注意 `--dump-config` 显示的是 bundle 默认值,会被用户层覆盖,不能反映实际生效值);极简模式下的过渡方案是把画像/规则写入 `AGENTS.md`(agent-instructions 走 section 路径,不受该压制影响)。
561
-
562
- ## 外部 API 与 CLI
563
-
564
- 除 DSH 内部端口外,插件还可以开启一个**独立的 HTTP 外部 API**(默认 `http://127.0.0.1:8790`,Bearer token 鉴权),供其他插件、CLI 脚本或桌面工具读写记忆,不依赖 DSH 内部端口。
565
-
566
- ### 启用与鉴权
567
-
568
- - 在插件设置中开启外部 API(默认监听 `127.0.0.1:8790`,仅本机可访问);
569
- - 访问 token 在插件设置 / 面板「设置 → 外部访问」中查看;
570
- - 除 `GET /health`(免鉴权)外,所有路由需携带 `Authorization: Bearer <token>`,无效 token 返回 `401 {"error":"unauthorized"}`。
571
-
572
- 主要路由:
573
-
574
- | 方法 | 路由 | 说明 |
575
- |------|------|------|
576
- | `GET` | `/health` | 健康检查(免鉴权),返回 `{ok:true}` |
577
- | `GET` | `/status` | 版本、记忆统计、实体数、运行时长 |
578
- | `GET` | `/profile` | 用户画像,返回 `{profile:"..."}`;未设置时为空字符串 |
579
- | `GET` | `/rules` | 行为规则列表,返回 `{rules:[...]}`;未设置时为空数组 |
580
- | `GET` | `/memories?limit&offset&type&minImportance&source&order=chrono&include_archived&occurred_from&occurred_to` | 分页列出记忆(`include_archived=true` 含归档;occurred 时间窗按 `occurred_at` 回退 `created_at`) |
581
- | `GET` | `/memory/provenance?id=<memoryId>` 或 `?sessionId=<sid>`(可选 `&limit=`,默认 20、上限 100) | 溯源读出口,两个方向共用一条路径(#421 拆出两条:方向 1 记忆→窗口由 #509 交付,方向 2 会话→窗口由 #524 补上;宿主内面板路由 `/api/dsh-mneme/memory/provenance` 同一口径)。**两个主键互斥**:都缺 `400 {"error":"missing-id"}`、都给 `400 {"error":"ambiguous-id"}`(刻意不静默择一——两个方向的结果形状不同,猜一个只会在出事之后才发现)。方向 1 是一条溯源链接一个窗口 `{session_id, seq_start, seq_end, created_at, distill_run_id, run_type, trigger_source, run_status, records[]}`(#512 补运行归因:run 是归因主体,窗口只是它的一批输入;读不到整轮归因时整组 `null`,**不从区间或时间戳反推**),答复级另带 `mints[]`(行级归因:这条记忆出生自哪一轮 dream/sleep,只填 create);方向 2 把同一个 `(session_id, seq_start, seq_end)` 合并成一项(`GROUP BY`),带 `link_count`=这个窗口派生出几条记忆,按 `seq_start` 排——逐链接返回会让「这个会话蒸了几次」被重复行淹没。两个方向都带 `truncated`(撞上 limit 时说「还有更多」;少了它,被截断的答复与「本来就这么少」逐字节相同)。`records` 是那段蒸馏窗口的**逐条会话原文**(按 `seq` 升序、不越出区间)。没有链接返回**空 `windows`**——「不是蒸馏来的」是有效答案,不是错误。状态码阶梯:`401` 无 token → `400` 缺参/多参/`invalid-limit` → `409 {"error":"distill-records-disabled"}`(`distillRecords.enabled` 关着;该开关是**启动快照**,面板改完要到下次启动生效,面板会显示「待重启」)→ `503 {"error":"provenance-unavailable"}`(该方向要用的方法没接线,**按方向判**——只缺 session 侧方法时方向 1 仍然 200)→ `200`。`409` 与 `503` 必须分开读数:前者是「用户关了」,后者是「装配坏了」。**关开关 ≠ 删掉已留存原文**——只是不再经 HTTP 提供,盘上的行要 `dsh-mneme reclaim`(或重新开启后的启动裁剪)才走,详见 [docs/DISTILL.md](docs/DISTILL.md) |
582
-
583
- | `GET` | `/memories/:id` | 单条记忆 |
584
- | `POST` | `/memories` | 新增记忆 `{type,title,content,importance?,tags?,source?,sensitivity?,occurred_at?,agent_scope?,workspace_scope?}`;响应含 `action: created\|merged` |
585
- | `PUT` | `/memories/:id` | 局部更新 `{title?,content?,type?,importance?,tags?,reason?,agent_scope?,workspace_scope?}`;content 改写按 human_override 入档 |
586
- | `DELETE` | `/memories/:id` | 删除记忆 |
587
- | `GET` | `/search?q&mode=keyword\|vector\|hybrid\|auto&topK&occurred_from&occurred_to&agent_scope&workspace_scope` | 搜索(关键词 / 向量 / hybrid=向量领位关键词补位 / 自动)。scope 两参声明调用方身份(不传 = 不解析,行为与旧版一致;任一给出则 strictScope 硬过滤与 A2 软加权随之生效) |
588
- | `GET` | `/context?q&topK&threshold&agent_scope&workspace_scope` | 注入候选一站式聚合(issue #370,#363 承诺):宿主注入管线 `injectCandidates` 全语义(优先级分层 / 编码门控 / heat / scope 软加权 / hybrid 语义路 / pin 前置)+ 画像 + 规则,返回 `{profile, rules, items, pinnedCount, tier}` 结构化条目,不含渲染文本。`threshold` 是 **importance 阈值**(默认 3,与 `/search` 的相似度阈值同名不同义);`topK` 默认 5(对齐宿主 `maxInjectedItems`);scope 语义与 `/search` 同口径;跨轮轮换 / 热记忆 / 时间前缀不含(调用方自管);recall_runs 注入分账与宿主注入同口径(#217 `mode='inject'`) |
589
- | `POST` | `/bootstrap` | 冷启动(v0.8.4):从仓库目录反向构建初始记忆,body `{dir}` 必填;幂等((type,title,scope) 去重 + `_overwrite` 原地刷新),零 LLM、必有产出 |
590
- | `POST` | `/maintenance/reclaim` | 无损回收(#275 / #411,与面板同口径):**只有 POST**(本路径不提供 GET 预估分支)。字段只从 JSON body 读;`dryRun` 默认 `true`,只有 `dryRun:false` 且 `confirm:true` 才真删;`vacuum` 只允许显式指定 |
591
- | `POST` | `/share` | 记忆分享包:把活跃记忆按口径打成可外发的 JSON 包,纯读不写库;取行与跳过口径、脱敏规则与 3 MiB 体积水位见 [docs/SHARE.md](docs/SHARE.md)。本路径的 GET 一律 405 |
592
- | `POST` | `/receive` | 吃进一份分享包(body `{pack, confirm?}`,包内容整个送上来、服务端不读路径):**默认干跑**,只有 `confirm: true` 才写库;整包一个事务、按 `share_external_id` 幂等(同一个包重跑 `created = 0`),外来行标 `source=imported`,不参与本机巩固/降级。包里一条不合格就**整包拒**(收侧不做逐条修复,也不跑敏感扫描)。入站上限 4 MiB;GET 一律 405。细则与实测见 [docs/SHARE.md](docs/SHARE.md) |
593
- | `POST` | `/receive/undo` | 整包退出(body `{packId, confirm?}`,同样**默认干跑**只清点):按 `share_pack_id` **物删**(不是归档——归档行会占住 UNIQUE 位,撤了反而导不回来),`deleted` 是全量、`sample` 只给前 20 条预览;什么都没导入时答 0,不抛。GET 一律 405 |
594
-
595
- #### `/context` 的 `tier` 档位信号(#383)
596
-
597
- `GET /context` 的响应多一个 `tier` 字段,回答「这次注入跑在哪一档」。嵌入降级在调用方视角原本完全静默——`items` 看着正常,只是召回质量悄悄变差,外部集成方无从感知自己长期跑在降级档上。
598
-
599
- | `tier` | 含义 |
600
- |--------|------|
601
- | `full` | 语义档:查询嵌入成功,且与库里的向量维度可比 |
602
- | `degraded` | 规则档:语义路本次不可用(原因见日志) |
603
- | `unknown` | 语义路未启用(`q` 为空),或判不出来(维度探针没跑成 / 一条向量都读不出)——那不是降级,但也不宣称 `full` |
604
-
605
- **两套消费者的分工:** `tier` 是**响应读数**,给调用方——三态、fail-closed(判不出来报 `unknown`,不报 `full`),用于在集成侧告警或切换策略。降级的**具体原因**是**日志读数**,给运维——走 daemon 的 stderr(`dsh-mneme: /context degraded to the rule tier (<reason>)`),不进响应体。原因枚举六值,互不吞并(成例是「修法不同就分开」):`embed-unavailable`(无可用嵌入接口:embedder 对象在,上面没有 `embedSingle` / `embed`)/ `embed-empty`(返回了空或非数组向量)/ `embed-timeout`(接口挂起,被超时护栏按缺失处理)/ `embed-error`(接口抛错)/ `embed-dimension`(接口成功了,但库里没有一条维度相符的活跃向量)/ `no-embedder`(压根没装配 embedder——daemon `--embed off`、lightMode、宿主未装配;**这是预期态,不是故障**)。六值的唯一真源是 `src/api-standalone.js` 导出的 `CONTEXT_DEGRADE_REASONS`,契约测试从它派生断言集合。
606
-
607
- `embed-dimension` 值得单说:它是「拿到了向量却不可比」——`searchVector` 对维度不符的行直接跳过,不抛错、只是命中为零,于是召回静默退回关键词/规则档,而嵌入侧一切正常。修法是重建索引,不是查端点,所以它必须和前四个分开。`no-embedder` 与前四个也分开:前者(`embed-unavailable`)是适配器坏了、要修代码,后者是语义路没开、要把嵌装扮上或开起来,主体与动作都不同;并成一个值会让按 `embed-unavailable` 告警的面板对每个轻量模式安装报警。用词则与宿主面 `/api/dsh-mneme/semantic` 的 `reason` 对齐——同一个物理条件在两个面叫同一个名字(那边是另一套枚举、另一个消费者,别顺手统一)。
608
-
609
- **`unknown` 之下的判档故障另有一条 warn:** `unknown` 有三个生产者(空 `q` / 维度探针没跑成 / 有行却一条向量都读不出来),响应体只有 `tier` 一个键、分不出它们,而调用方对 `unknown` 的策略常常是「不告警」——所以判不出来的情形会另打一行 `dsh-mneme: /context tier left unknown: <what>`(探针抛错 / 没有可读的向量可比)。**它不是上面那六值的一员**(`tier` 不是 `degraded`,没有降级原因可记),运维程序不要按原因枚举解析它。
610
-
611
- **预算:** 判档不是免费的。`q` 非空且装配了 embedder 时,一次 `/context` 真的会起一次查询嵌入(一次网络往返 + `embedTimeoutMs` 的超时窗口)——档位要回答的正是「这次嵌入成不成」。这里没有复用 `/health` 的数据源:standalone 的 `/health` 只回 `{ok:true}`,而 `embeddingDimensionBreakdown` 是宿主面的一次全表扫(每行 JSON.parse 一个向量),按请求跑会把语义路成本翻倍。维度探针因此走 `service.vectorDimensionState()`——**按匹配短路的存在性判据**(有没有一条活跃向量的维度等于查询维度),不是「读一行的维度」:混合维度库里 `LIMIT 1` 会抽错维(明明有可比的向量却报 `degraded`),首条恰好解析失败时又会漏报成 `full`。成本是一次无 `LIMIT` 的全 id 扫描 + 按匹配短路的解析:全库同维度(常态)时循环第一行就返回,只解析 1 个向量;只有一条都不匹配时才走完整个循环,而那正是要报 `degraded` 的情形,值得。解析复用 `getParsedEmbedding` 的缓存,缓存热不热取决于 `injectCandidates` 是否真的走了 vectorIndex 分支。
612
-
613
- ### curl 示例
614
-
615
- ```bash
616
- # 服务状态
617
- curl -s -H "Authorization: Bearer $DSH_MNEME_TOKEN" http://127.0.0.1:8790/status
618
-
619
- # 列出最近 5 条记忆
620
- curl -s -H "Authorization: Bearer $DSH_MNEME_TOKEN" \
621
- "http://127.0.0.1:8790/memories?limit=5"
622
-
623
- # 新增一条决策记忆
624
- curl -s -X POST http://127.0.0.1:8790/memories \
625
- -H "Authorization: Bearer $DSH_MNEME_TOKEN" \
626
- -H "Content-Type: application/json" \
627
- -d '{"type":"decision","title":"采用 SQLite","content":"存储层使用 node:sqlite","importance":4,"tags":["存储"]}'
628
- ```
629
-
630
- ### CLI 安装
631
-
632
- 插件自带零依赖 CLI(随 npm 包一起发布):
633
-
634
- ```bash
635
- npm i -g @modusensus/dsh-mneme
636
- dsh-mneme --help
637
- ```
638
-
639
- 首次使用先配置服务地址与 token(也可用环境变量 `DSH_MNEME_URL` / `DSH_MNEME_TOKEN`,或 `--url` / `--token` 参数临时覆盖):
640
-
641
- ```bash
642
- dsh-mneme config set http://127.0.0.1:8790 <你的token>
643
- ```
644
-
645
- ### CLI 常用命令
646
-
647
- ```bash
648
- dsh-mneme status # 服务状态
649
- dsh-mneme list --type project --limit 10 # 列出记忆
650
- dsh-mneme search "部署流程" --mode vector --topk 5 # 语义搜索
651
- dsh-mneme add --type decision --title "采用 SQLite" \
652
- --content "存储层使用 node:sqlite" --importance 4 --tags 存储,决策
653
- dsh-mneme get 42 # 查看单条
654
- dsh-mneme delete 42 # 删除
655
- dsh-mneme config show # 查看当前配置(token 打码)
656
- dsh-mneme share --dry-run # 分享包:只看会进几条、跳过几条,不落盘
657
- dsh-mneme share --out pack.json # 写一个可外发的脱敏包(3 MiB 水位在源头拒)
658
- dsh-mneme receive pack.json # 吃包:默认干跑,一个字都不写
659
- dsh-mneme receive pack.json --apply # 确认后真的吃进自己的库(整包一个事务,可重跑)
660
- dsh-mneme undo-share pack.json --apply # 按 pack_id 整包收回(物删,不是归档)
661
- ```
662
-
663
- > 所有读取/写入命令支持 `--json` 输出原始 JSON;`config path` 打印配置文件路径(`~/.dsh-mneme/cli.json`)。
664
- > 人类可读档只转达服务端文案里的 `hint` / `bytes` / `limitBytes`;闸门的 `detail`(坏在哪一格)与
665
- > 413 的 `limit` 要 `--json` 才看得见——排查收包失败时先加它。
666
-
667
- ### 独立服务(daemon,`dsh-mneme-serve`)
668
-
669
- 不启动 DSH 也能让记忆库对外服务:`dsh-mneme-serve` 在宿主之外组装同一套 lib,把数据面跑成常驻进程(路由与鉴权与「独立外部 API」完全同源)。适用场景:第三方集成(如 [Mneme-Bridge](https://github.com/SternChiri/Mneme-Bridge) 这类网页端桥接,见下方[社区适配器](#社区适配器))需要长期挂载记忆库,而 DSH 不必一直开着。
670
-
671
- ```bash
672
- dsh-mneme-serve # 默认 ~/.dsh/memory + 8790
673
- dsh-mneme-serve --memory-dir "D:\my mem" --port 8790 --host 127.0.0.1
674
- dsh-mneme-serve --embed off # 纯关键词 + BM25(不取件模型)
675
- ```
676
-
677
- - **鉴权与端口**:Bearer token 与 DSH 面板 / CLI 共用同一份(kv `external_api`,首次启动自动生成并持久化到 `memory.db`);端口/主机解析链与「外部访问」一致(显式参数 > 持久值 > 默认 8790/127.0.0.1)。配置端口被占会**直接报错退出**(不做端口顺延)——第三方把 URL 写死,静默换端口等于坏。因此 **daemon 与 DSH 的「外部访问」二选一**,不要同端口同开。
678
- - **安全**:daemon 使用明文 HTTP,不提供原生 TLS。指定非回环 `--host` 时,请勿直接把服务暴露给不可信网络;远程访问请走 TLS 终止代理或 SSH 隧道。
679
- - **能力边界(第一期,无 LLM)**:存储 / 检索(关键词 + BM25 + 向量)/ 镜像同步与人改合并 / `POST /maintenance/reclaim` / `POST /receive`(吃包入库与整包退出:结构落库 + 随提交排空嵌入,**不建实体**——外来行本来就不做抽取,见 [docs/SHARE.md](docs/SHARE.md))/ `/bootstrap` 全可用;巩固(autoDream)与蒸馏不在 daemon 内——巩固只属于 DSH 宿主进程,这是与宿主「单写者」的机械保证。`--embed` 默认 `local`(自管 runtime 与嵌入模型缺失时自动取件,约 200MB;失败降级关键词并打日志),也可选 `ollama` / `openai`(读宿主面板的 vector-config)/ `off`。
680
- - **检索回执**:daemon 的 `/search` 同样落 `recall_runs`,第三方检索的复用统计不缺数。
681
- - **生命周期**:stdout 仅就绪时打一行 `dsh-mneme-serve listening on http://host:port (pid N)`(供脚本解析实际端口),日志走 stderr;SIGINT/SIGTERM 优雅收库,Windows 强杀由 WAL 回放兜底。
682
- - **已知限制**:与 DSH 同时运行属设计内场景(WAL 多进程并发),但去重是先查后写、库层无 UNIQUE 约束,双进程并发写同一 `(type, title, scope)` 有极小概率产生重复;daemon 与插件请同版本升级。细节与坑清单见 [docs/DAEMON.md](docs/DAEMON.md)。
683
-
684
- ### MCP Server(任意 MCP 客户端接入)
685
-
686
- > Claude Code / Codex / Hermes / OpenCode / OpenClaw 等各客户端的最小挂载配置速查表见[根 README](../README.md#用在其他-ai-工具里mcp);本节是完整配置与安全说明。独立分发包 [`mneme-memory`](https://www.npmjs.com/package/mneme-memory)(bin `mneme-mcp`)已发布,与插件内置的 `dsh-mneme-mcp` 并存、挂载命令互相兼容。
687
-
688
- 插件自带 stdio MCP server(`bin/dsh-mneme-mcp.mjs`,零依赖,随 npm 包发布,bin 名 `dsh-mneme-mcp`)。任何支持 Model Context Protocol 的客户端(Claude Code、Cursor 等)挂载后即可获得与 DSH 内一致的记忆工具六件套:`memory_save` / `memory_search` / `memory_list` / `memory_get` / `memory_update` / `memory_delete`——工具名、参数与去重合并、重要性等语义与 DSH 内工具对齐(测试锁漂移)。
689
-
690
- 数据面走上面的**独立外部 API**(8790,Bearer):写入并发由 DSH 单点负责;DSH 未运行(外部 API 未启动)时 MCP 侧调用会报连接失败。scope 语义注意:外部 API 无会话上下文,`memory_save` 不做自动标注,只认显式 `agent_scope` / `workspace_scope` 声明。
691
-
692
- 配置优先级沿用 CLI 约定:环境变量 `DSH_MNEME_URL` / `DSH_MNEME_TOKEN` > `~/.dsh-mneme/cli.json` > 默认 `http://127.0.0.1:8790`。安全注意:服务默认只绑 `127.0.0.1`;若把 `DSH_MNEME_URL` 指向非回环的明文 HTTP 地址,Bearer token 将明文过网(启动时会有 stderr 警告)——远程场景建议走 SSH 隧道。
693
-
694
- Claude Code 挂载示例(项目根 `.mcp.json`;token 在面板「设置 → 外部访问 API」查看):
695
-
696
- ```json
697
- {
698
- "mcpServers": {
699
- "dsh-mneme": {
700
- "command": "dsh-mneme-mcp",
701
- "env": { "DSH_MNEME_TOKEN": "<你的token>" }
702
- }
703
- }
704
- }
705
- ```
706
-
707
- 未全局安装 npm 包时,把 `command` 换成 `npx`、加 `args: ["-p", "@modusensus/dsh-mneme", "dsh-mneme-mcp"]` 即可。
708
-
709
- ## 社区适配器
710
-
711
- 以下项目由社区维护,把 mneme 接入第三方平台或宿主。它们不是本仓库的一部分,兼容性由各自维护者跟进——升级 mneme 后如遇接口变更,请优先查看对应项目的 release note。
712
-
713
- | 项目 | 平台 | 说明 |
714
- |------|------|------|
715
- | [Mneme-Bridge](https://github.com/SternChiri/Mneme-Bridge) | DeepSeek 网页端 | 浏览器扩展(MV3)+ 本地 Node 服务:网页端会话蒸馏进 mneme 记忆库,DSH 侧记忆按话题回注网页对话,两侧共享同一份记忆。embedded(直接挂载 mneme lib)与 remote(standalone API,推荐配合 [`dsh-mneme-serve`](docs/DAEMON.md))双模式 |
716
-
717
- > 想被收录?在 [Discussions](https://github.com/slow-stack/mneme/discussions) 开帖介绍你的项目,或直接提 PR 补充本表。
718
-
719
- ## 🏗️ 架构
720
-
721
- ```
722
- ┌─────────────────────────────────────────────────┐
723
- │ 存储层:SQLite (archived/forgotten 状态) │
724
- │ + Markdown 镜像(人工可编辑,双向同步) │
725
- ├─────────────────────────────────────────────────┤
726
- │ 服务层:saveWithDedupe / injectCandidates │
727
- │ / mergeHumanEdits / onWrite 钩子 │
728
- ├─────────────────────────────────────────────────┤
729
- │ 模型接口:12 个工具 + 自动注入 + 会话摘要 │
730
- ├─────────────────────────────────────────────────┤
731
- │ autoDream:阈值调度 → LLM 决策清单 │
732
- │ → 校验(fail-safe)→ 应用 → 摘要 │
733
- ├─────────────────────────────────────────────────┤
734
- │ Web 面板:设置面板内嵌 + 浏览/搜索(含向量) │
735
- └─────────────────────────────────────────────────┘
736
- ```
737
-
738
- **源码结构**:
739
-
740
- ```
741
- src/
742
- ├── store.js # SQLite 存储(CRUD、搜索、归档/遗忘、schema 迁移、scope 四列)
743
- ├── mirror.js # Markdown 镜像(渲染/解析,人工优先)
744
- ├── service.js # 领域逻辑(去重合并、注入筛选、写入钩子、scope 加权/硬过滤、冲突队列)
745
- ├── scope.js # 作用域解析(agentPreset + workspace registry 反查,issue #17)
746
- ├── config.js # schemastery 配置 schema
747
- ├── tools.js # 12 个模型工具(defineTool;memory_organize 要 organizeEnabled 打开才注册,开了是 13 个)
748
- ├── user-settings.js # 「用户设置」注入块(人格 → 画像 → 规则)的唯一渲染处,注入与面板预览共用
749
- ├── profile-extract.js # 从活跃记忆提取「助手眼中的用户」画像草稿(只出草稿,不写 user_settings)
750
- ├── organize.js # agent 主动整理:dryRun 比对报告 → agent 判断 → apply 落库(筛除=归档不删,留 dream_runs 回执)
751
- ├── inject.js # systemPrompt.context 动态注入(含花括号转义)
752
- ├── summarize.js # 会话结束 LLM 摘要
753
- ├── dream.js # autoDream 调度 + runDream(LLM 决策 + 摘要)
754
- ├── dream/decisions.js# 决策校验(fail-safe)+ 决策应用
755
- ├── dream/clustering.js # 候选集聚类(k-means++ seeding)
756
- ├── dream/sleep.js # Sleep Mode 分层压缩
757
- ├── entities/extractor.js # 实体抽取器(v0.3.0:LLM JSON 抽取 + 去重 + fail-safe)
758
- ├── search/bm25.js # BM25 稀疏召回(v0.5.0:分词 + IDF 索引)
759
- ├── search/adaptive.js# 自适应相似度阈值(v0.5.0)
760
- ├── hot-memory.js # 会话级短期热记忆(v0.5.0:滚动轮次 + token 预算;注入剥离 reasoning)
761
- ├── runtime/ # 自管本地推理运行时(收编 / 本地 .tgz / registry 三档取件 + 校验)
762
- ├── embedding.js # OpenAI 兼容 embeddings 客户端 + 向量检索
763
- ├── api.js # HTTP 路由(Web 面板数据通道,含 /conflicts 冲突队列)
764
- └── index.js # 插件接线
765
- lib/ # src 的同步分发产物(npm run sync,prepack 钩子在发布时自动跑;一致性由 scripts/check-sync.js 在 CI 与 release.yml 校验——它只查不同步;唯一手写例外 lib/client.js——Web 面板 bundle,sync 不覆盖)
766
- test/ # 3375 个 node:test 测试(审计与三轴线压测不变量;src↔lib 一致性由 scripts/check-sync.js 发布闸门校验)
767
- scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压测 · sync-lib.js 同步 · check-sync.js 发布闸门 · benchmark-recall.js / benchmark-embed.js / benchmark-rerank.js 基准 · sync-test-badge.mjs 测试徽章 · build-runtime-manifest.mjs 运行时清单
768
- ```
769
-
770
- ## 🧪 开发
771
-
772
- ```bash
773
- cd dsh-mneme
774
- npm install # 安装 peer 依赖(以 devDependencies 形式,用于本地测试)
775
- npm test # 运行 3375 个测试
776
- npm run stress # 三轴线压测:长会话检索 / 冲突仲裁 / 多 Agent 并发(离线 mock LLM)
777
- npm run sync # 把 src/ 同步到 lib/(发布时由 prepack 钩子自动执行)
778
- ```
779
-
780
- > 压测(`npm run stress`)三条轴线:**长会话检索**(Recall@k、陈旧残留率)、**冲突裁决**(可重放仲裁集:审计快照 hash + receipt + 幂等回放)、**多 Agent 并发**(丢更新、重复合并、事务/崩溃恢复)。每次 autoDream 运行都会写入审计表 `dream_runs`(输入快照 digest + 决策清单 + 逐 id 去向 + receipt),让高通过率下也能定位静默错误。
781
-
782
- > `lib/` 是 `src/` 的同步分发产物(`npm run sync`):除 **`lib/client.js`**(Web 面板 bundle)为 lib 独有的手写文件、sync 与 check-sync 均不触碰外,其余全部由 src 复制而来。改 src 必 `npm run sync` 并提交 lib,否则发布产物静默失效(issue #65 教训)。
783
-
784
- ## 📄 设计文档
785
-
786
- > 设计文档在 `dsh-mneme/docs/`(本目录内,直接相对链接);只有能力对比表在仓库根 `docs/`,用 `../docs/` 指过去。GitHub 上从本目录打开均可正常跳转。
787
-
788
- - [配置说明(全键参考)](docs/CONFIGURATION.md)
789
- - [蒸馏原文留存与记忆级溯源](docs/DISTILL.md)(#399)
790
- - [实体结构化记忆设计](docs/ENTITIES.md)
791
- - [语义增强架构](docs/SEMANTIC.md)
792
- - [本地模型部署指南](docs/LOCAL_MODEL.md)
793
- - [工作流(M.O.):本体住项目,证据住记忆库](docs/WORKFLOWS.md)
794
- - [连续性抢救(#249 N3):触发器口径与事件契约](docs/CONTINUITY.md)
795
- - [Sleep Mode:空闲四阶段深度维护](docs/SLEEP.md)
796
- - [存储与回收:表结构、保留期、`dsh-mneme reclaim`](docs/STORAGE.md)
797
- - [选择性遗忘与事实更正:行粒度契约与失效关系缺口(#532)](docs/FORGET.md)
798
- - [记忆分享包:出包与收包的口径、信任边界与实测(`dsh-mneme share` / `receive` / `undo-share`)](docs/SHARE.md)
799
- - [独立服务 daemon(`dsh-mneme-serve`)](docs/DAEMON.md)
800
- - [与 Zep / Graphiti / Mem0 / Letta / Hindsight 的能力对比](../docs/COMPARISON.md)
801
-
802
- ## 🙏 致谢
803
-
804
- autoDream 的理念溯源(理念借鉴、实现原创):
805
-
806
- - **[Claude Code 的 Auto Dream](https://code.claude.com/docs/en/memory)**(Anthropic,Memory 2.0):理念源头——会话间隙由后台子代理整理记忆文件(去重、修矛盾、清衰减)。
807
- - **[Sleep-time Compute: Beyond Inference Scaling at Test-time](https://arxiv.org/abs/2504.13171)**(UC Berkeley & Letta,arXiv:2504.13171):Auto Dream「离线巩固」思想背后的学术脉络。
808
- - **cc-haha**:早期实现思路的参照之一。
809
-
810
- 在上述工作之上,dsh-mneme 做了自己的工程发展:K-Means++ 聚类预分组(`src/dream/clustering.js`)、类型化决策清单(keep / merge / archive / conflict / update,及 sleep 侧 supersede / differentiate)与可回放的 sha256 摘要审计链(`dream_runs` / `receipt_chain`)。如有遗漏的灵感来源,欢迎提 issue 指出。
811
-
812
- ## 📚 相关研究
813
-
814
- dsh-mneme 的机制设计与下列公开研究相互印证(以下引用均逐一核对过 arXiv 收录页;机制对应关系为我们自己的映射,非原论文观点):
815
-
816
- - **在线写入 + 离线巩固**:[Dual-Layer Agentic Memory with Fast Write Routing and Slow Consolidation](https://arxiv.org/abs/2608.22215)(arXiv:2608.22215)——与 autoDream 的「快写慢巩固」分工同构。
817
- - **热度衰减与访问强化**:[FadeMem](https://arxiv.org/abs/2601.18642)(arXiv:2601.18642)——heat 记忆热度模型(指数衰减 × 访问强化 × 重要性调制)的学术近亲。
818
- - **冲突裁决与状态追踪**:[StateMemBench](https://arxiv.org/abs/2608.19652)(arXiv:2608.19652)——记忆系统追踪演化状态的考卷;C1 冲突裁决(supersede 后不再引用旧值)以其为验收靶子。
819
- - **何时该忘 / scope 门控**:[PersistBench](https://arxiv.org/abs/2602.01146)(arXiv:2602.01146);呈现层缓解见 [Structured Memory](https://arxiv.org/abs/2608.08300)(arXiv:2608.08300)——scope 语义域门控的问题出处与零契约变更改法。
820
- - **领域全景**:[Write–Manage–Read 综述](https://arxiv.org/abs/2603.07670)(arXiv:2603.07670)——「写入 / 管理 / 读取」三段式与插件整体形状互证。
821
- - **数月尺度的可靠性工程**:[Memory as Infrastructure](https://arxiv.org/abs/2609.05510)(arXiv:2609.05510)——与 sha256 审计链、fail-safe 降级同属「记忆即基础设施」路线。
822
- - **相邻系统(对照)**:[Zep](https://arxiv.org/abs/2501.13956)(时序知识图谱)、[Mem0](https://arxiv.org/abs/2504.19413)(生产级抽取式记忆)、[Hindsight](https://arxiv.org/abs/2512.12818)(retain / recall / reflect 三操作)走「写入时 LLM 抽取 + 向量/图检索」路线;dsh-mneme 的差异点在于:巩固由 LLM 参与但产物全程留痕可回放,冲突冻结待人工复核,记忆只落本机。
823
-
824
- ## 📜 License
825
-
826
- MIT
827
-
828
- ## 🤝 参与之前
829
-
830
- 行为守则:[CODE_OF_CONDUCT.md](../CODE_OF_CONDUCT.md)。它管三件事——**署名归人**(模型不进作者行)、**责任落在签下作者行的人身上**、**发言权按证据分配,不按身份**。参与 issue / PR / 评审即受其约束;使用本插件不受约束,MIT 已经授权。
1
+ <p align="center"><strong>中文 | <a href="docs/SEMANTIC.md">English(语义增强)</a></strong></p>
2
+
3
+ # dsh-mneme
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@modusensus/dsh-mneme?color=blue&label=npm)](https://www.npmjs.com/package/@modusensus/dsh-mneme)
6
+ [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
7
+ [![Awesome](https://awesome-dsh-plugin.com/badge.svg)](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin)
8
+ [![tests](https://img.shields.io/badge/tests-3399%20total-success)](https://github.com/slow-stack/mneme)
9
+ [![CI](https://img.shields.io/github/actions/workflow/status/slow-stack/mneme/ci.yml)](https://github.com/slow-stack/mneme/actions)
10
+ [![node](https://img.shields.io/badge/node-22%2B-blue)](https://nodejs.org)
11
+ [![npm downloads](https://img.shields.io/npm/d18m/@modusensus/dsh-mneme.svg?color=blue&label=downloads)](https://www.npmjs.com/package/@modusensus/dsh-mneme)
12
+ [![coverage](https://img.shields.io/codecov/c/github/slow-stack/mneme/main)](https://codecov.io/gh/slow-stack/mneme)
13
+
14
+ > 给 DeepSeek Harness 的跨会话记忆插件:让 Agent 记住你、记住项目、自动整理记忆。**Mneme**(Μνήμη)——希腊记忆女神 Mnemosyne 之名,掌管记忆与梦境,正如 autoDream 在后台巩固记忆。
15
+
16
+ `dsh-mneme` 是一个 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) 插件,为 Agent 提供持久的跨会话记忆能力。它借鉴了 Claude 的 **Dream 机制** 与 cc-haha / Claude Code 的 **autoDream** 记忆巩固功能——不仅**存储**记忆,还会**自动巩固**(去重、合并、冲突裁决、摘要生成),让记忆库越用越精炼。完整溯源与致谢见文末「[🙏 致谢](#-致谢)」。
17
+
18
+ ## ⏱️ 30 秒理解
19
+
20
+ **一句话**:给 Agent 装上跨会话记忆——记住你、记住项目,并在后台自动整理,越用越懂你;**v0.8.0 起**记忆可按 agent 与工作区隔离(`scopeEnabled`),多 Agent / 多项目互不串台;**v0.9.0 起**「这件事怎么跑」也能落进项目仓库(M.O.,`actionPipelineEnabled`,默认关)。
21
+
22
+ | ① 写入 | ② 存储 | ③ 进化 |
23
+ |--------|--------|--------|
24
+ | 对话中模型主动记录(`memory_save`,可带敏感度与事件时间);会话结束自动提炼(`autoSummarize`) | SQLite 主库 + 人类可编辑 Markdown 镜像;实体 / 属性 / 时间轴三层结构化;记忆带 agent / workspace / 敏感度 / 发生时间标注 | 新会话自动注入相关记忆(按当前作用域加权,strictScope 开启后显式收窄的归属硬隔离);autoDream 后台去重 / 合并 / 归档,冲突冻结待人工裁决 |
25
+
26
+ ```bash
27
+ # 30 秒上手
28
+ dsh plugin --profile web add @modusensus/dsh-mneme
29
+ dsh web
30
+ ```
31
+
32
+ **它不是什么**(边界声明):
33
+
34
+ - 不是向量数据库——语义搜索是可选增强,默认零额外依赖
35
+ - 不替代会话日志——它存的是「值得跨会话记住的」精炼知识
36
+ - 不改变模型本身——进化的是记忆库与每次注入的上下文
37
+ - 删对话 ≠ 删记忆——记忆是跨会话的全局知识(v0.7.11 起不再与会话绑定),删除会话不影响已存入的记忆
38
+
39
+ ## ✨ 功能
40
+
41
+ ### 记忆存储(SQLite + Markdown 镜像)
42
+
43
+ - **SQLite 主存储**:`~/.dsh/memory/memory.db`,`node:sqlite` 内置,零原生依赖
44
+ - **Markdown 镜像**:按类型分文件(`preferences.md` / `projects.md` / `decisions.md` / `history.md` / `summary.md` / `patterns.md` / `pitfalls.md` / `constraints.md` / `rejected-solutions.md`,外加只读视图 `documents.md`),文件头是 YAML frontmatter(`type` / `generated.by` / `generated.at` / `covered` / `coverage` / `tags`)。人类可读,条目标题与正文可手工编辑(**人工修改优先**合并回库);`documents.md` 例外:它只有 document 指针行(id、标题、摘要首句、文件路径),不含正文也不参与人工回填。文件头与条目元数据行由机器维护
45
+ - **10 种记忆类型**:`preference` 偏好 / `project` 项目 / `decision` 决策 / `history` 历史 / `summary` 会话总览 / `pattern` 模式 + 编码记忆三型 `rejected_solution` 被否方案 / `pitfall` 踩坑 / `constraint` 约束(v0.7.13 起,`codingRetrospect` 默认关;v0.7.11 近重写已收窄删除 user/fact 两型)+ `document` 文档指针(#230,只存摘要与 `doc_path`,正文留在磁盘由 agent 自管)
46
+ - **镜像同步状态机(v0.3.6+)**:mirror 与主库强一致,用 `generation`(期望轮次)/ `applied_generation`(已应用轮次)建模同步债务
47
+ - 业务写操作在**自身事务内原子递增** desired generation——崩溃在 COMMIT 后、渲染前,重启也能凭 durable 债务恢复,绝不静默跳过(v0.3.8)
48
+ - `generation` 用 SQLite 原子语句递增,多进程并发零丢失;带 `CHECK` 上界,负数/溢出拒绝
49
+ - 逐 type 记录 `committed / failed / pending` 回执,健康端点区分 `ok / degraded / unknown`
50
+ - 状态写失败不静默:同步失败落日志并留债务,重启自动收敛
51
+
52
+ ### 模型工具(默认注册 12 个;开 `organizeEnabled` 后 13 个)
53
+
54
+
55
+ | 工具 | 功能 |
56
+ |------|------|
57
+ | `memory_save` | 记录一条记忆(自动按标题去重合并;v0.8.0 起去重键含 agent/workspace/scope 作用域,可选 `sensitivity` / `occurred_at` 参数) |
58
+ | `memory_search` | 全文搜索(中文子串友好,可启用向量语义搜索;可选 `occurred_from` / `occurred_to` 按事件发生时间过滤) |
59
+ | `memory_list` | 按类型分页列出(`include_archived=true` 可查看已归档;可选 `occurred_from` / `occurred_to` 时间过滤) |
60
+ | `memory_get` | 读取单条记忆完整正文(v0.7.25,按 id;memory_search / memory_list 命中后读全文) |
61
+ | `memory_update` | 修改已有记忆 |
62
+ | `memory_delete` | 删除记忆(按记忆 ID 精确删除) |
63
+ | `memory_forget` | 抑制注入(降权不删除,可恢复) |
64
+ | `memory_archive` | 归档/恢复记忆(v0.2.5;归档后隐藏于列表/搜索/注入/整理,`archived=false` 可恢复) |
65
+ | `memory_pin` | 钉住一条记忆:无论类型、无论它和其他记忆怎么竞争,每轮都注入在记忆块最前面(#249 第二批;受 `pinnedInjectBudget` 上限约束,钉的顺序是「先钉的占位」,预算不够时最早钉的优先)。**只在她明确说「这条必须一直在」时用**,不是标记重要性的手段——重要性本来就参与排序。钉着 ≠ 会注入:遗忘 / 归档 / 暂停作用域都优先于 pin,回执里的 `injectable` 如实报告这件事。`unpin: true` 松开 |
66
+ | `set_scope_state` | 按下/松开某个作用域的**可逆闸门**(#471:政策轴。暂停期间该作用域的记忆照旧存着,只是不注入、不参与巩固,松开即原样回来;不改任何一条记忆的标注,与上面逐条操作的 `memory_forget` / `memory_archive` 是两根不同的轴)。两级开关 `scopeState.enabled` / `.enforce` 默认都关,没开时按下不产生拦截效果 |
67
+ | `memory_register_document` | 登记 agent 产长文档的指针行(#230:摘要 + `doc_path` + evidence 落 `document` 类型;正文留在磁盘、由 agent 自管,注册口唯一,旁路写入被拒) |
68
+ | `memory_organize` | 主动整理(#231,**要 `organizeEnabled` 打开才注册**):`mode=dryRun` 先出比对报告(每条候选 `exact` / `near` / `new` + 命中行,**不写一行库**、只留审计回执),agent 判断后 `mode=apply` 引用那份报告的 `run_id` 落地。两种「不要它」要分清——**`discard`** = 这条候选不写,什么都不动(只进回执);**`archive`** = 把报告标为被取代的那条**既有行**归档(可恢复,绝不物理删除)。没有比对过的候选写不进库,一份报告也只许落地一次 |
69
+ | `memory_runtime` | 本地推理运行时的状态 / 供给 / 校验(v0.7.32,自管运行时三档取件) |
70
+
71
+ 开启 `chorographyEnabled` 后可用仓库地志工具。多个仓库已登记时请传仓库 ID。若搜索只读到部分页面,结果会标明漏查的页。
72
+
73
+ ### 工作流(M.O.,v0.9 beta;v0.13.0 起从面板下架)
74
+
75
+ > **状态**:设置面板不再渲染这一组,界面上没有入口。三个旗标(`actionPipelineEnabled` / `actionRunEnabled` / `actionNudgeEnabled`)与 `/mo-run` 命令、座位注册逻辑都还在,语义零改动;想恢复界面把该组加回 `FEATURE_GROUPS` 与 `FEATURE_FIRST_SCREEN` 即可。下面是设计说明。
76
+
77
+ 记忆库答的是「这件事**为什么**这么办」,答不了「这件事**到底怎么跑**」。v0.9 把后者从记忆库里的一行文字变成项目里可提交、可 review、可被 CI 读的一份文件——一条工作流一个 JSON:
78
+
79
+ ```
80
+ <项目>/.mneme/pipelines/<id>.json ← 项目层(默认;跟着项目提交)
81
+ <插件包>/pipelines/<id>.json ← 全局层(兜底;今天包里没有这个目录,有意为空)
82
+ ```
83
+
84
+ - **两层来源,顺序即优先级**:同 id 两处都有,项目层赢,被挡住的那份进 `shadowed` 报出来(不静默丢弃);项目层的坏文件进 `unreadable` 而不拖死全局层——一层写坏不该让人连兜底那份也看不见
85
+ - **校验很硬**:`id` / `name` / `project` / `version` / `status` / `done` 与每一步的 `phase` / `title` / `when` / `do` / `done` / `why` 缺一不可,`risk` 限 R0–R3、`needs` 必须指向存在的步骤、图里有环直接报错——任何一处不合规**整条读不出来**,不做「跳过坏文件继续」:半个工作流比没有更危险
86
+ - **护栏,不是轨道**:绕行要留出口。自报 R0/R1 **且**不跨闸门 **且**兜底清单(`IRREVERSIBLE_PATTERNS`,机械匹配、不看自报)没命中 → 记账先走;其余 → 停下问人
87
+ - **候选分层**:草稿住 `<memoryDir>/candidates/<项目键>/`,只在本地。升格要同时满足「走过两次(至少一次成功)」**且**「写得出反事实」;够格之后系统只**提议**,`promoteCandidate()` 只返回内容不写盘,提交与推送是人握着的那道门
88
+ - **两个指标分开数**:跳过(这次不用这一步,≥3 次提议删**这一步**)与绕开(这条路整个不对,≥3 次提议重看**这条路径**)各自累加,混在一起两种提议都发不出来
89
+ - **只读路由** `GET /api/dsh-mneme/pipeline[?id=&project=]`(`project` 非绝对路径回 400 `project-not-absolute`,不回退 `process.cwd()`);答复契约 `mneme.pipeline/v1`,面板渲染与 agent 读的是同一份数据
90
+ - 默认关(`actionPipelineEnabled`),设计取舍见 [docs/WORKFLOWS.md](docs/WORKFLOWS.md)
91
+
92
+ ### 自动注入 + 会话摘要
93
+
94
+ - **自动注入**:新会话开局注入记忆摘要(`summary` 优先 + 少量高重要性条目)
95
+ - **会话摘要**:`turn/end` 时用 LLM 提炼本次会话的偏好/决策/教训,自动入库(过滤 plugin 注入上下文,避免污染)
96
+
97
+ ### autoDream 自动记忆整理 🧠
98
+
99
+ > **溯源**:autoDream 的理念源自 Claude Code 的 Auto Dream 记忆巩固功能(Anthropic,Memory 2.0 的后台整理子代理),其「离线巩固」思路与 UC Berkeley & Letta 的 *Sleep-time Compute* 论文([arXiv:2504.13171](https://arxiv.org/abs/2504.13171))一脉相承。dsh-mneme 将其引入 DSH 插件生态,并发展为自己的实现——K-Means++ 聚类预分组、类型化决策清单与可回放的 sha256 摘要审计链,详见文末「[🙏 致谢](#-致谢)」。
100
+
101
+ - **触发**:记忆数 > 10 或总字符 > 5000 时,异步自动触发(不阻塞写入)
102
+ - **决策清单式整理**:LLM 输出 `keep` / `merge` / `archive` / `conflict` / `update` 决策清单,服务端校验后逐条应用
103
+ - `merge`:合并主题相近的条目,保留信息最完整者
104
+ - `archive`:归档过时/冗余条目(可恢复,不物理删除)
105
+ - `conflict`:裁决矛盾信息,胜者保留、败者归档并追加溯源注释;`conflictFreezeEnabled`(默认关)开启后矛盾对不自动裁决,改为冻结进**冲突队列**(状态页并排对比,人工选保留方,#166)
106
+ - `update`(v0.2.1):直接修正单条记忆的过时/错误内容(单 id / 必须实际变化 / 非 summary / 24h 保护 / 每次 ≤2)
107
+ - **失败追踪(v0.2.1)**:用户纠正记忆时写入 `failure_memories` 表(旧值/新值),为后续自进化积累数据
108
+ - **摘要生成**:整理后生成"记忆库总览"(单一实例),作为下次会话的优先注入
109
+ - **Fail-safe**:非法 LLM 输出(未知 id / 非法 action / 越界 importance / 跨类型合并等"单条非法"决策,Issue #26)默认跳过该条并应用合法子集(run 记为 `degraded`),绝不破坏记忆库
110
+ - **裁决审计**:每次运行写入 `dream_runs` 审计表(输入快照 sha256 digest + 完整输入快照 + 决策清单 + 逐 id 去向 + receipt),可离线回放;merge / conflict / update 幂等应用,重放/并发重复执行无累积副作用;update 记录 `_before` 快照
111
+
112
+ #### dreamMaxTokens 调优指南
113
+
114
+ 默认 `131072`(即上限,#135)已为思考型模型预留推理+正文的双重预算(部分思考型模型仅推理就可能消耗 8k+ token),常规记忆库无需调整。若**记忆量大**(数万字符以上)且正文仍被截断,优先按下方「巩固模型分类声明」换非思考模型 / 配 `dreamReasoningEffort` 压低思考,再考虑调大输入侧上限(如 `distillMaxChars`)——`dreamMaxTokens` 本身已无上调空间。
115
+
116
+ > **不要为了省 token 把它调小**(#135 成本审计实测):这个键是**上限**而非计费口径,流式按实际用量计费,压上限只在真撞顶时生效;而撞顶的后果是**整轮失败**(截断 → 无完整 JSON → `no json array in llm output`),且调度器只有 `ok` 轮才刷新基线,下一次写入会用同一批输入重跑。按 133 个有真实用量的成功轮折算,cap=16384 撞顶 78.9%、净总量 **+54.1%**;cap=32768 +15.9%。真正的大头(`dream_consolidate` 输出 token 里约 88% 是推理与 JSON 骨架,只有约 11.8% 是决策正文)由 `dreamReasoningEffort` 与模型选择决定,与本键无关。相关的数量护栏见 `dreamMaxMergePerRun`。
117
+
118
+ > 若使用**思考型模型**(如 deepseek-v4-flash / DeepSeek-R1 类),模型可能把全部预算花在 reasoning 上导致正文为空(日志出现 `no json array in llm output`)。#135 修复后:未配置 `dreamReasoningEffort` 时会**自动取模型支持的最低档**发流(不再省略字段让模型自带默认档——v4-flash 系默认 high——顶上烧光预算),默认配置即生效;显式 `none` = 不发送字段用服务商默认,`off`/`low`/`medium`/`high` 原样传递,模型不支持的档位自动换用(拒绝原因记入 llm_audit)。正文仍为空时配置 `dreamProvider`/`dreamModel` 指向非思考模型(`dreamMaxTokens` 默认已是上限 131072,无上调空间)。sleep 侧对应 `sleepReasoningEffort`。
119
+
120
+ **巩固模型分类声明**(settings panel「巩固模型」= `dreamProvider`/`dreamModel`,睡眠侧对应 `sleepProvider`/`sleepModel`):
121
+
122
+ | 模型类别 | 例子 | 说明 |
123
+ |---------|------|------|
124
+ | **非思考模型(推荐)** | glm-5-2 类等 | 无 reasoning 声明;即使配了 effort 被 harness 拒绝,fallback 去掉字段重试即成功。空体风险最低 |
125
+ | **思考模型(需实测)** | deepseek-v4-flash-ga 等 v4-flash-ga 系 | 默认开推理,可能烧光 token 预算返回空体;部分型号(如 v4-flash-ga)在 harness 侧被声明为**不接受任何 reasoning effort**(去掉 effort 时 harness 的 `defaultEffort` 会顶上来再次拒绝)。v0.7.26+ 已根治:`resolveDreamEffort` 发流前探测模型支持的档位,不支持的配置档位自动换用模型默认/首个支持档位,声明无 reasoning 能力的型号则省略字段。选用时建议配 `dreamReasoningEffort` 实测(未配置时自动取最低档),不行就换非思考模型 |
126
+
127
+ ### Sleep Mode 系统级睡眠 💤(v0.4.0,opt-in)
128
+
129
+ 从 autoDream 的"被动阈值触发"升级为"主动定时维护 + 分层压缩"。系统空闲 `sleepIdleMinutes` 分钟自动执行深度维护,**默认关闭**(`sleepModeEnabled: false`),开启后行为:
130
+
131
+ - **可中断**:AbortController 实现,用户恢复活动即中止当前周期(`noteWrite` 重置空闲计时 + 中断信号)
132
+ - **串行安全**:睡眠周期走 `service.enqueue` 串行队列,与 autoDream 严格不重叠;`minRefTimeMs` 防止快照后被召回的记忆被误降级
133
+ - **四阶段深度维护**:
134
+ 1. `conflict_resolution`:全库冲突消解,strictness 三级可配(gentle 0.92 / normal 0.85 / aggressive 0.75)
135
+ 2. `archival_demotion`:按 `last_accessed_at` 分层——30 天未召回压成摘要(原文进 `_full_content`,可无损恢复)、90 天完全归档
136
+ 3. `pattern_discovery`:LLM 扫描近期记忆提炼规律,产出 `type=pattern` 记忆,evidence 强校验防伪造
137
+ 4. `relation_completion`:检测孤立实体并补全隐含关系(共现 `related_to` / 项目 `part_of` / 技术 `depends_on`)
138
+ - **Fail-safe**:每阶段独立 try/catch,LLM 故障只跳过对应阶段;无 LLM 路由时纯规则降级(demotion/relations)照常执行
139
+ - **审计延续**:睡眠周期写入 `dream_runs`,`run_type='sleep'`,与 autoDream 共用审计表可追溯
140
+
141
+ > 配置详见 `docs/SLEEP.md`。
142
+
143
+ 官方设置面板 → 「记忆库设置」→「记忆」标签:按类型浏览、全文搜索;启用向量搜索后可用「语义」切换做向量召回。
144
+
145
+ ### 用户设置(画像 / 规则)与自定义指令 ⚙️
146
+
147
+ 官方设置面板 → 「记忆库设置」标签:
148
+
149
+ - **用户画像**:一段自由文本描述用户自己(角色、背景、偏好),**每轮注入**到系统提示,让 Agent 始终遵循
150
+ - **规则**:Agent 必须遵守的行为规则列表(如"回答先给结论"),同样每轮注入
151
+ - **自定义指令**:注册斜杠命令(`/名称 [补充说明]`),触发时把用户定义的指令内容作为一条用户消息提交给当前 Agent,命令后缀会作为补充说明一并提交;界面仅显示提交回执(宿主不支持 followup 提交时退回旧行为,指令原文会显示在界面,便于复制后手动发送)。命令持久化到 SQLite,启动时自动注册到 DSH 命令表,增删实时生效
152
+
153
+ > 画像与规则通过独立的 `[用户设置]` 注入区块(优先级高于记忆库),即使记忆为空也会注入。
154
+
155
+ ### 向量搜索(语义搜索)🔎
156
+
157
+ 可选能力:接入 OpenAI 兼容的 embeddings API,让搜索能命中**字面不同但语义相近**的记忆。
158
+
159
+ **配置**:官方设置 → 「记忆库设置」→ 滚动到底部「向量搜索」区块:
160
+
161
+ | 字段 | 说明 |
162
+ |------|------|
163
+ | `启用向量搜索` | 总开关;开启后记忆面板出现「语义」切换 |
164
+ | `API 地址 (Base URL)` | OpenAI 兼容端点,如 `https://api.openai.com/v1`;也支持 SiliconFlow、智谱、本地 Ollama 等 |
165
+ | `API Key` | 对应服务的密钥 |
166
+ | `模型名` | embedding 模型,如 `text-embedding-3-small`、`text-embedding-v3`、`bge-m3` 等 |
167
+
168
+ 保存配置后点「重建索引」,为已有记忆批量补建向量(新写入的记忆会自动嵌入)。之后在记忆面板输入查询并点「语义」,即可用向量召回语义相关结果;向量服务不可用时自动回退全文搜索。
169
+
170
+ > ⚠️ 密钥仅保存在本机 `~/.dsh/memory/memory.db` 的 `user_settings` 表,不会上传,也不会写入代码仓库。
171
+ > 需要 embedding 而非 rerank 模型:如阿里云 `text-embedding-v3` 可用,`qwen3-vl-rerank` 是 rerank 模型(不走 `/embeddings`)。
172
+
173
+ ### 语义增强(Semantic)🧠
174
+
175
+ v0.2 起新增**可以完全离线运行的语义记忆引擎**(本地模型 + 精排 + 聚类):
176
+
177
+ - **本地 Embedding**:三后端可选——ONNX(`Xenova/bge-small-zh-v1.5`,离线)/ Ollama / OpenAI 兼容,失败自动逐级降级,最差回退关键词搜索
178
+ - **Rerank 精排**:`Xenova/bge-reranker-base` 对召回候选交叉编码精排,提升 Top-K 准确率
179
+ - **autoDream 语义增强**:对记忆向量聚类(`clusterMemories`),自动发现主题相近 / 疑似矛盾的记忆,巩固更精准
180
+ - **搜索流水线**:混合召回(关键词 + 向量)→ Rerank → Top-K
181
+ - **自管运行时**:本地推理的依赖闭包(`@huggingface/transformers` + `onnxruntime-node` + `sharp`,从宿主收编时本机实测 49 个包 / 约 393MB)可收编到 `~/.dsh/mneme/runtime/`,与 profile 的依赖图解耦——由于 profile 是所有插件共用的依赖图,这份闭包留在此前的位置会让「安装任何插件」都替它重走一遍整条依赖链;收编优先硬链接,同盘时几乎不额外占盘。`@huggingface/transformers` 已从 `dependencies` 降为**可选 peer**,因此安装插件不再携带它;正在使用本地嵌入的用户请先按文档收编,否则升级后本地嵌入不可用(读写信道不受影响)
182
+ - **取回运行时的三条来源**:① 收编本机已有(零网络、同盘硬链接)→ ② 本地 `.tgz` 目录(`runtimeTarballDir`,某个包网络下不到时用)→ ③ npm registry(`runtimeMirror` 可换镜像),按随包发布的 `runtime-manifest.json` 逐个取并**先校验 sha512 再落盘**(win32-x64 实测约 33 个包 / 2142 个文件 / 数百 MB;清单平台无关,一份覆盖 win32/darwin/linux × x64/arm64;剔除 `onnxruntime-web`——Node 构建从不 import 它)。面板「向量索引」卡片在不就绪时会给出这段代价说明并提供一个按钮;不想开面板也可以让 agent 用 `memory_runtime` 工具(`status` / `provision` / `verify`)代做
183
+
184
+ 配置只需在 `cordis.patch.yml` 里设置 `embedProvider`(默认 `openai`,保持 v0.1 行为;改为 `local` 即离线)。升级无需迁移数据。
185
+
186
+ ```bash
187
+ node scripts/mneme-runtime.mjs status # 运行时在哪、来源、结构是否完整(不加载模型)
188
+ node scripts/mneme-runtime.mjs adopt --from ~/.dsh/profiles/<profile>/node_modules
189
+ node scripts/mneme-runtime.mjs verify # 真加载运行时并跑一次推理
190
+ ```
191
+
192
+ > 三个命令的退出码为 `0` 健康 / `1` 不健康 / `2` 用法错误,便于脚本 gate;`--json` 输出机器可读结果。运行时不可用时不会崩——检索降级为关键词/BM25,读写不受影响。详见 [本地模型部署指南 §2.5](docs/LOCAL_MODEL.md)。
193
+
194
+ ### 实体结构化记忆(Entity Gene)🧬
195
+
196
+ v0.3.0 起新增**记忆基因**层:从记忆里抽取**命名实体**、**带时间轴的属性**、**实体间关系**,让搜索从"字面关键词"升级为"按实体/属性精确召回"。
197
+
198
+ - **三表**:`entities` / `entity_attrs`(`valid_until` 快照式时间轴)/ `entity_relations`,旧库打开自动建表,幂等无迁移成本
199
+ - **自动抽取**:`entityExtractionEnabled=true` 后,新写入的记忆 fire-and-forget 触发 LLM 抽取(同名实体去重、属性存时间轴、关系追加;失败绝不阻塞写入)
200
+ - **实体搜索**(`searchMemories` 前缀路由,`entitySearchEnabled` 默认开):
201
+ - `entity:阿尔托` → 属性精确关联的记忆(`_score 1.0`)排在关键词提及(`_score 0.7`)之前
202
+ - `attr:国籍=芬兰` → 精确匹配该属性值的记忆
203
+ - `attr:国籍` → 该属性键的**全部**当前有效记忆(value 为空契约)
204
+ - **autoDream 联动**:update 决策写 `supersedes` 自引用(属性版本被替代);merge 决策把 loser 的属性归属迁移到 keeper(keeper 已有同键当前值则失效)
205
+
206
+ > 📖 详见 [实体结构化记忆设计](docs/ENTITIES.md) · [语义增强架构](docs/SEMANTIC.md) · [本地模型部署指南](docs/LOCAL_MODEL.md)
207
+
208
+ ### 记忆质量过滤 🧼(v0.4.6,默认开)
209
+
210
+ 写库前对每条记忆做**启发式质量打分**(纯函数,无 I/O、无共享状态):元记忆词汇(谈论记忆系统本身)、自指类型标签、内容过短、重复度高、与近期记忆近似重复都会扣分(0-100):
211
+
212
+ - `score ≥ 60`:正常存储
213
+ - `30 ≤ score < 60`:`quality_score` 落库,注入排序改为按 `importance × quality/100` 降权(degraded)
214
+ - `score < 30`:归档并标记 `low_quality`——仍可显式搜索召回,只是**永不自动注入**。**例外(#135)**:`importance ≥ memoryQualityFilter.exemptImportance`(默认 4)的记忆只降权不归档——评分与信号标签照常落库,归档决定不再静默越过用户标注的重要性
215
+
216
+ `memoryQualityFilter.enabled` 可整体关闭,`archiveThreshold` / `degradeThreshold` / `minContentLength` / `exemptImportance`(1=全部豁免,5=仅最重要豁免)可调。此外更新记忆(`memory_update` 等)不会抹掉系统信号标签(`low_quality` / `duplicate` / `meta` / `self_referential` / `repetitive` / `short_content`)——它们是「为什么被降权/归档」的审计线索,与用户自传标签并集保留(#135)。
217
+
218
+ ### LLM 消耗审计 📊(v0.4.6,默认开)
219
+
220
+ 每次**后台 LLM 调用**都会写入 `llm_audit_logs` 表:`tokens` / `duration` / `status` / `source`(由哪个触发产生)。失败调用记为 `status=error`,绝不阻塞功能本体;`retentionDays`(默认 90)在启动时清理超期行。
221
+
222
+ 巩固那一轮还有一层**事后判决**:调用成功不等于决策可用,而校验发生在调用之后。判决以 `metadata.decision_validation`(`verdict` / `error_count` / `skipped_count` / `survivor_count` / `invalid_actions`)浅合并回同一行——`status`、tokens、时间戳一律不改,它们是调用层的事实。`verdict` 四档:`unparsed`(没解析出 JSON 数组)/ `rejected`(整单拒绝)/ `degraded`(只应用了合法子集)/ `ok`。有了这一层,「调用成功率」与「整轮有效率」才对得上账。
223
+
224
+ 覆盖的后台调用(`source` 即触发源,`operation_type` 区分同一源下的不同调用):
225
+
226
+ | `source` | `operation_type` | 说明 |
227
+ |---|---|---|
228
+ | `autoDream` | `dream_consolidate` / `dream_summarize` | 巩固的整理裁决与总览摘要,各一行 |
229
+ | `autoDream` | `dream_narrative` | 叙述条合成,需 `dreamNarrativeEnabled`(默认关)才跑 |
230
+ | `autoSummarize` | `summarize_compress` | 空闲蒸馏的压缩 |
231
+ | `sleep` | `sleep_conflict` / `sleep_pattern` | Sleep Mode 的冲突裁决与模式挖掘,两阶段各一行 |
232
+ | `entityExtract` | `entity_extract` | 实体抽取,**每次写入记忆都会跑** |
233
+
234
+ > 后两条链路见 #250——它们是结构上漏接的后台路径(sleep 的 `streamText` 副本没有 `onUsage`、实体抽取适配器拿不到 `service`),不是刻意收窄口径。
235
+
236
+ 新增两个只读 API:
237
+
238
+ - `GET /api/dsh-mneme/semantic/llm-audit?page=&pageSize=&source=` — 分页查询 + 按 source 过滤
239
+ - `GET /api/dsh-mneme/semantic/llm-audit/stats?days=` — 近 N 天按 source 汇总预算(tokens / 次数 / 失败数)
240
+
241
+ `/llm-audit/stats` 的 `by_source` 是服务端 `GROUP BY trigger_source`,不做任何白名单过滤,因此新链路自动进入汇总。
242
+
243
+ 面板侧现状(#250 之后,未改面板):
244
+
245
+ - 「LLM 消耗」卡读 `/llm-audit/stats`,但只渲染 `total_calls` / `total_tokens` 两个总数。新链路的 token 与次数**已经计入这两个总数**,所以「mneme 总共花了多少」现在是对的;
246
+ - 按链路的拆分(`by_source`)目前只能从 API 读,面板不展示——「哪条链路最费」在面板上还答不了;
247
+ - 状态页活动流仍只显示 `autoDream` / `autoSummarize` 两个硬编码来源(`lib/client.js`),新链路不会出现在活动流里。
248
+
249
+ 这三处要动面板(活动流还有一处来源白名单加一处二元标签兜底,且 `pageSize=12` 会被每次写入都跑的实体抽取占满),留到面板批次,不在 #250 内。
250
+
251
+ > 实体抽取是**每次写入记忆都会跑**的链路,计入审计后 `llm_audit_logs` 的行数会随写入量线性增长(`retentionDays` 只约束上界、不约束增速)。若实测增速过快,再考虑按 `operation_type` 采样或单独保留期。
252
+
253
+ > 只读端点,与 list/search/semantic 一样在设置 `apiToken` 后仍保持开放。
254
+
255
+ 沉淀曲线(面板状态页「8 周沉淀」图的数据源):
256
+
257
+ - `GET /api/dsh-mneme/semantic/consolidation-stats?days=` — 近 N 天(缺省 56,钳 1–365)按天返回三条序列:`added`(新建记忆,排除外来导入行)、`merged`(当天被巩固掉的**去重记录数**,取自 `receipt_chain` 里 `kind∈(merge,update)` 且 `verdict='live'`)、`archived`(当天进入归档面的条数),另附三个窗口合计。
258
+
259
+ `merged` 刻意按去重 `record_id` 数而不是行数:同一条记录被多轮巩固重复记账是常态(活库实测 2412 行只对应 1796 个记录),按行数会把「又记了一遍」算成「又沉淀了一条」。新增与合并背离才是这张图要看的东西——2026-10-25–10-31 那段新增照旧、合并归零,只看新增或只看总量都发现不了。
260
+
261
+ ### 记忆库主区视图与记忆图谱 🕸️(v0.5.0)
262
+
263
+ 记忆功能从侧边栏抽屉收进**主内容区全宽 tab**(conversation.view 插槽,与「对话 / Trajectory」并列),侧边栏「记忆」入口点击后直接激活该 tab。页面顶部子 tab 行切换三个子视图:
264
+
265
+ - **记忆(三栏浏览)**:左栏分类树(类型 + 计数)/ 中栏时间树(月 → 日两级倒序、可折叠)/ 右栏详情(**全文不截断** + 复制全文);语义搜索内嵌工具栏开关(防抖 250ms),`entity:` 前缀可「在图谱中查看」
266
+ - **图谱**:输入实体名,加载以该实体为中心的关联网络——
267
+ - 服务端只读 ego-graph API:`GET /api/dsh-mneme/semantic/graph/ego?entity=<name>&depth=1|2`(BFS 层级遍历,`limit` 防大图失控,实体不存在 404;配套 `/semantic/graph/entity-attrs` 查实体属性)
268
+ - 前端**零依赖手写 SVG 力导向布局**(插件运行时无法 require vis-network 等第三方库):斥力 + 弹簧 + 向心引力物理模拟,节点按类型着色、按提及次数定半径,支持拖拽、点节点看属性、点边跳回来源记忆
269
+ - **设置**:画像 / 规则 / 指令 / 向量配置,限宽居中
270
+
271
+ 图谱 ↔ 记忆双向互跳:图谱详情侧的关联记忆可点击,记忆边的「来源记忆」按 memory_id 直跳三栏视图并自动定位。
272
+
273
+ - **分享包三步(面板)**:「⋯」菜单里的**分享记忆包…**(报告先于下载:进包条数、同键折叠、六个跳过原因、可展开的跳过清单,超水位回 413 同屏)与**导入分享包…**(选文件 → 干跑预览将新建几条 / 撞名几条 → 确认才写库),外来行带 `from-<别名>` 徽标、工具条「外来」chip 按 `source=imported` 服务端筛、抽屉「收起这个包」两段式整包退出(先清点后物删)。口径与判据一条都不在面板里复述——出包在 `src/share.js`、入包闸门在 `src/share-import.js`、协议层在 `src/share-http.js`,细则与实测见 [docs/SHARE.md](docs/SHARE.md)
274
+
275
+ ### 四路召回融合与会话热记忆 🔎(v0.5.0,v0.8.4 扩四路)
276
+
277
+ - **BM25 稀疏第三路召回**(`src/search/bm25.js`):与向量召回、FTS5/LIKE 关键词并列——ASCII 词元 + CJK bigram 分词、IDF 加权(归一化 [0,1]),专有名词 / ID / 代码片段等散词查询不再依赖子串命中。融合规则:未召回行按 `0.3×BM25分` 回填;仅向量召回行获得词法加分;LIKE 已命中行不叠分。`bm25SearchEnabled` 可关
278
+ - **实体图召回轴(第四路,v0.8.4)**(`entityRecallEnabled` 默认关):开启后检索融合池三源扩四源——store 新增 `findEntitiesMentionedIn` / `getLinkedMemoryIds` 反查原语 + `idx_relations_memory` 索引,命中实体所在记忆按边入池,fuseRecall 的 blend / rrf / minmax 全配方参与;实体轴与 BM25 同为确认/回填信号(we 并入 wb 共用 0.3 回填权重),永不主导语义排序,失败降级空数组;keyword 模式纯文本路径不吃实体轴
279
+ - **自适应阈值**(`src/search/adaptive.js`):取代固定 `0.65` 截断——`entity:`/`attr:` 前缀放宽 0.5,短查询(<5 字符)收紧 0.7,长查询(>50)放宽 0.6,Top1/Top5 分差 > 0.3 时放宽让尾部进 Rerank;显式传 `threshold` 或 `adaptiveThresholdEnabled=false` 走旧行为
280
+ - **会话级短期热记忆**(`src/hot-memory.js`):最近 N 轮对话(默认 5 轮,`hotMemoryRounds`)按 token 预算(默认 2000,`hotMemoryMaxTokens`)滚动截断,从会话事件日志无状态重建、不落库;注入顺序为「短期上下文 → 长期记忆召回 → 摘要」
281
+ - **选择性注入**:query 向量可用时注入候选按主题相似度重排(`selectiveInjectEnabled` 可关);**搜索时语义去重**为激进选项(`searchSemanticDedup=true` 显式开启,近重复行 Rerank 前丢弃)
282
+ - **召回基准**(`scripts/benchmark-recall.js`):标准查询集驱动,计算 Recall@5 与 MRR,`legacy`(三特性全关)vs `fused`(默认配置)双跑对比
283
+
284
+ ## 📜 版本历史
285
+
286
+ 🧬 基因 → 🛡️ 审计加固 → 💤 睡眠巩固 → 🕸️ 召回融合与图谱 → 🌡️ 自进化 → 🔐 作用域隔离 → 🌐 MCP 生态 → 🧭 M.O. → 💭 情绪归因 → 📔 日记本
287
+
288
+ 当前版本的能力以本 README 正文的配置章节为准——**这张表只留一句话头条**,每一版具体怎么实现见 [CHANGELOG](CHANGELOG.md) 与 [Releases](https://github.com/slow-stack/mneme/releases)。
289
+
290
+ | 版本 | 头条 |
291
+ |------|------|
292
+ | **v0.13.0**(2026-11-10) | 情绪终于有地方可放:`affective_context` 带情绪词与归因,三个独立会话才升成稳定倾向,不足就降级不丢弃 |
293
+ | **v0.12.0**(2026-11-07) | pin 从「按类型猜」变成你亲手钉的事实;向量缓存从恒 0% 命中改为跟工作集自适应(1.8–2.4s → 370–424ms) |
294
+ | **v0.11.0**(2026-11-05) | 记忆读得懂仓库:文件树与 import 图编译成模块划分与地志页 |
295
+ | **v0.10.1**(2026-11-03) | 打开记忆详情不再崩掉整个宿主 |
296
+ | **v0.10.0**(2026-11-02) | 记忆开始按「哪一轮」算账:蒸馏有了运行身份,溯源补上反方向 |
297
+ | **v0.9.5**(2026-10-30) | 记忆能安全地递出去,也能整包收回来 |
298
+ | **v0.9.4**(2026-10-21) | 三条链各自补上「最后一环」:主动整理、画像提取草稿、人格寻址收口 |
299
+ | **v0.9.3**(2026-10-20) | M.O. 从「挖得出来」跑到「会被叫去挖」 |
300
+ | **v0.9.2**(2026-10-19) | 让「看不见的失败」显形 |
301
+ | **v0.9.1**(2026-10-18) | M.O. 从「看得见」跑到「跑得出账」 |
302
+ | **v0.9.0**(2026-10-17) | M.O.(工作流)进入 beta:工作流住进项目仓库、可提交可 diff |
303
+ | **v0.8.x** | 作用域隔离(agent / workspace 双维)、冲突队列人工裁决、stdio MCP server、图召回轴、冷启动 |
304
+
305
+ > 早期版本中的实验性功能(Wiki-Link、tag 系统等)已在 v0.7.11 移除,详见 CHANGELOG 对应条目。
306
+
307
+ ## 📦 安装
308
+
309
+ ### 前置条件
310
+
311
+ - [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)— 兼容 DSH 0.1.x 与 0.2.x(三段式 peer 范围见 `package.json`);开发与 CI 已对齐 0.2 线,`0.2.0-rc.1` / `0.2.0-rc.2` 实测全绿。旧版兼容垫片(`Session.events` → `snapshotEvents()`,v0.7.9 起确保进入发布产物 lib/)保留
312
+ - Node 24+(`node:sqlite`)
313
+
314
+ ### 安装步骤
315
+
316
+ #### 方式一:npm 安装(推荐)
317
+
318
+ dsh-mneme 是一个 **bundle**(声明了 `dsh.bundle` manifest),安装即自动激活,无需手动写配置:
319
+
320
+ ```bash
321
+ # 1. 安装插件(自动注册 bundle 层)
322
+ dsh plugin --profile web add @modusensus/dsh-mneme
323
+
324
+ # 2. 重启
325
+ dsh web
326
+ ```
327
+
328
+ > 如需自定义配置(阈值、延迟等),可在 `~/.dsh/profiles/web/cordis.patch.yml` 中按 `id: dsh-mneme` 覆盖默认值(见下方配置表)。
329
+
330
+ #### 方式二:从源码安装(本地目录)
331
+
332
+ ```bash
333
+ git clone https://github.com/slow-stack/mneme.git
334
+ cd mneme/dsh-mneme
335
+ dsh plugin --profile web add "$(pwd)"
336
+ dsh web
337
+ ```
338
+
339
+ > **路径必须绝对**:宿主对 `dsh plugin add` 的本地路径有一条硬校验(`parseInstallSpec` 里的 `a local path must be absolute`),相对路径(含 `.`、`..`)一律拒掉。上面用 `"$(pwd)"` 就地展开,就是为了不给它相对路径。
340
+
341
+ #### 方式三:直接从 Git 仓库安装
342
+
343
+ 本仓库是**单仓多包**:仓库根那份 `package.json` 是**仓库壳**(`private`、不带 `dsh` 字段),插件本体在 `dsh-mneme/`。所以 Git 地址必须带 `#path:` 指到子目录:
344
+
345
+ ```bash
346
+ dsh plugin --profile web add 'git+https://github.com/slow-stack/mneme.git#path:/dsh-mneme'
347
+ dsh web
348
+ ```
349
+
350
+ | 写法 | 结果 |
351
+ |------|------|
352
+ | `git+https://github.com/slow-stack/mneme.git#path:/dsh-mneme` | ✅ 装出 `@modusensus/dsh-mneme`(实测 0.9.0,38 个包) |
353
+ | `https://github.com/slow-stack/mneme#path:/dsh-mneme` | ✅ 同上;lockfile 会归一成 `github:slow-stack/mneme#path:/dsh-mneme` |
354
+ | `git+https://github.com/slow-stack/mneme.git` | ❌ 装到仓库根那份壳(`0.0.0`、无 `dsh` 字段),宿主不认它是插件 |
355
+
356
+ `#path:` 是 pnpm 的 git 参数(`parseGitParams` 里按 `path:` 前缀解析),**不是**本仓库自定义的语法;pnpm 官方文档没写这一条,所以这里给出实测结果。
357
+
358
+ #### 方式四:tarball
359
+
360
+ ```bash
361
+ cd dsh-mneme
362
+ npm pack # 产出 modusensus-dsh-mneme-<版本>.tgz
363
+ dsh plugin --profile web add "C:/path/to/modusensus-dsh-mneme-0.9.0.tgz"
364
+ ```
365
+
366
+ > 必须用 `npm pack`,别用 `pnpm pack`:`bin/cli.mjs` 在工作区里是 CRLF,pnpm 会以 `ERR_PNPM_BIN_CRLF` 直接失败。
367
+
368
+ #### 自定义配置(可选)
369
+
370
+ 默认配置即可用。如需调整,在 `~/.dsh/profiles/web/cordis.patch.yml` 中覆盖:
371
+
372
+ ```yaml
373
+ - id: dsh-mneme
374
+ name: '@modusensus/dsh-mneme'
375
+ config:
376
+ memoryDir: ~/.dsh/memory
377
+ language: zh
378
+ autoInject: true
379
+ autoSummarize: true
380
+ maxInjectedItems: 5
381
+ importanceThreshold: 3
382
+ autoDream: true
383
+ dreamThresholdCount: 10
384
+ dreamThresholdChars: 5000
385
+ dreamDelayMs: 2000
386
+ ```
387
+
388
+ ## 怎么升级(设置不会丢)
389
+
390
+ **升级只动代码,不动你的记忆和设置。**
391
+
392
+ 设置与记忆是**同一个 SQLite 文件**里的表(`user_settings` 与 `memories` 等),文件位置由 `memoryDir` 决定,默认在 `~/.dsh/memory`——**不在插件安装目录下**。所以卸插件、装插件都不碰它。
393
+
394
+ 升级就是覆盖安装,装完重启一次:
395
+
396
+ ```bash
397
+ # --profile 后面写你当初安装它时用的那个名字,默认是 web
398
+ dsh plugin --profile web remove @modusensus/dsh-mneme
399
+ dsh plugin --profile web add @modusensus/dsh-mneme
400
+ dsh web
401
+ ```
402
+
403
+ > 上面是 npm 来源的装法;当初从 Git、tarball 或本地目录装的,按下同一种来源重装即可。唯一要求是**先 remove 再 add**。
404
+ > 不用重装 DSH。重装 DSH 动的是 profile,是更大范围的改动,与插件版本无关。
405
+ > 也不要只 `add` 不 `remove`——宿主可能拿到缓存的旧副本,版本号没变就说明没换成。
406
+
407
+ **这件事是实测过的,不是推断**:用 v0.12.0 的代码建库、写入画像、规则、人格卡与四个功能开关,再换成本次发布的代码打开同一个库——四项全部原样读回。反向也测了:新代码写的库,v0.12.0 同样读得出来。
408
+
409
+ **但有两处不对称要提前知道**:人格卡的按会话分配(`bySession`)以及 `scenario` / `mesExample` 两个字段,v0.12.0 都不认识——用旧版打开新版写的库,这些键读不出来,旧版再写回时可能把它们覆盖掉。所以**回退前先备份整个记忆库目录**(复制 `memoryDir`,默认 `~/.dsh/memory`),需要回退时把库一起退。另外,撤销某个开关只影响之后的行为,不保证把已经写下的数据(例如已经铸出的情绪倾向)一并回滚——要真正清掉得手动删对应条目。
410
+
411
+ 唯一会让你丢数据的是**把库指进 profile 作用域**(形如 `…/profiles/<名字>/…`),宿主清理 profile 时会连带带走——把 `memoryDir` 保持在 profile 之外即可(默认就是),要迁移库则:停止写入 → 复制整个目录 → 改配置指向新位置 → 重启。
412
+
413
+ ## ⚙️ 配置
414
+
415
+ | 键 | 默认值 | 说明 |
416
+ |----|--------|------|
417
+ | `memoryDir` | `~/.dsh/memory` | 记忆存储目录(SQLite + Markdown) |
418
+ | `language` | `zh` | 记忆语言:生成的记忆条目、注入标题与后台 LLM 提示词所用语言(`zh` / `en`) |
419
+ | `autoInject` | `true` | 会话启动自动注入记忆 |
420
+ | `autoSummarize` | `true` | 会话结束自动提炼摘要 |
421
+ | `summarizeProvider` / `summarizeModel` | 空 | 摘要的 LLM 路由覆盖(空=使用当前会话模型);推荐轻量模型节省主模型 token |
422
+ | `summarizeMinIntervalMinutes` | `0` | autoSummarize 最小触发间隔(0-10080,0=不限):两次蒸馏之间最短间隔,失败/degraded run 也占用(#127) |
423
+ | `summarizeMaxEntriesPerRun` | `0` | 单次蒸馏产出记忆条数上限(0-50,0=不限):节流防单会话大量重复条目(#127) |
424
+ | `summarizeMinWindowChars` | `0` | 蒸馏前零 LLM 预判:窗口可蒸馏文本不足此字符数直接跳过调用(0-100000,0=关);skip 原因写入审计(#239) |
425
+ | `summarizeMaxRunsPerSession` | `0` | 每会话最多发起多少次蒸馏 LLM 调用(0-1000,0=不限);只计真实调用,被预判拦下的不占额度(#239) |
426
+ | `summarizeParseFailureMaxRetries` | `0` | 连续几次解析失败后放弃当前窗口(0-10,0=关):确定性失败(模型把转录当成该自己回话,`finish_reason=stop`)重试收益为 0,而窗口只会越攒越大;设 2-3 可止血,达到阈值强制消费游标跳过,失败行 metadata 带 `raw_head`/`raw_has_bracket`/`streak`(#493) |
427
+ | `summarizePeakHours` | 空 | 高峰时段(本地时间,逗号分隔、可带星期前缀,支持跨零点):空=关;命中时蒸馏顺延到非高峰、窗口累积后一次蒸、skip 原因入审计。例:按高峰计费的供应商可写 `mon-fri 08:00-12:00,14:00-18:00`(如 DeepSeek,以其官方定价页为准)(#239) |
428
+ | `summarizePeakMaxDeferMinutes` | `120` | 高峰顺延上限(0-1440 分钟,0=不设上限):到点仍处高峰就照常跑,避免长高峰把蒸馏饿死(#239) |
429
+ | `summarizeDedupeMode` | `off` | 落库前去重档位:`off`(默认=现状)/ `title`(零成本,仅拦完全同名)/ `vector`(复用 embedding 列做同会话语义近邻,无 LLM 调用,#127) |
430
+ | `summarizeDedupeMinSim` | `0.92` | vector 去重档的相似度阈值(0.5-0.99) |
431
+ | `summarizeDedupeWindowHours` | `24` | vector 去重的同会话时间窗(小时,0-168) |
432
+ | `distillMaxChars` | `24000` | 蒸馏输入的正文截断上限(1000-200000):防止单轮转录把 LLM 输入撑爆 |
433
+ | `distillRateLimitIntervalMs` | `1000` | 蒸馏 LLM 调用全局串行队列的最小间隔(ms,0-60000,429 保护默认开) |
434
+ | `distillRateLimitRetries` | `3` | 命中 429 限流时的指数退避重试次数(0-10) |
435
+ | `distillRateLimitBaseDelayMs` | `1000` | 429 退避基准延迟(ms):1s→2s→4s… |
436
+ | `maxInjectedItems` | `5` | 最多注入几条记忆 |
437
+ | `injectUncertaintyAdaptive` | `false` | 注入条数的查询自适应:确定性强的话题把条数收缩到一半(下限 1),模糊话题(回指/时间线索,或极短查询)维持 `maxInjectedItems` 上限;**只做单向收缩**,判据只看查询本身、不做额外检索(#239 第 5 项) |
438
+ | `injectRotationTurns` | `0` | 注入位跨轮轮换:同一条记忆在最近 N 个查询轮次注入过后本轮不再优先(新鲜优先、不足回填,槽位数不变;会话边界自动重置;`0` = 关闭保持现状) |
439
+ | `injectContentMaxChars` | `300` | 注入单条正文截断上限(60-4000,原硬编码 300,#164①/#225):截断尾部带上限/原长/全文 `memory_get` 指引;块预算 `Math.max(1500, 上限+600)` 随上限放大 |
440
+ | `importanceThreshold` | `3` | 注入的最低重要性(1-5) |
441
+ | `autoDream` | `true` | 自动记忆整理开关 |
442
+ | `dreamThresholdCount` | `10` | 触发整理的记忆条数阈值 |
443
+ | `dreamThresholdChars` | `5000` | 触发整理的总字符阈值 |
444
+ | `dreamDelayMs` | `2000` | 整理异步延迟(去抖) |
445
+ | `dreamProvider` / `dreamModel` | 空 | dream 的 LLM 路由覆盖(显式配置优先于 agent 默认模型;留空则回退到 agent 默认模型) |
446
+ | `dreamMaxTokens` | `131072` | dream LLM 调用最大 token 数(上限 131072;#135 起默认即上限——思考型模型的 reasoning 与正文共享该预算,正文仍为空时优先换非思考模型或调 `dreamProvider`/`dreamModel`,见下方调优指南) |
447
+ | `dreamReasoningEffort` | 未配置=最低档 | dream LLM 推理强度透传:`off` / `low` / `medium` / `high` / `none`(未配置 = 自动取模型支持的最低档,避免思考模型用自带默认档烧光预算;`none`=不传该字段、用服务商自带默认;v0.7.26+ 模型不支持配置档位时自动换用其支持的默认/首个档位,无 reasoning 能力的型号省略字段) |
448
+ | `dreamCandidateMode` | `window` | dream 候选集构造:`window`(只取最近 `dreamMaxSnapshotSize` 条)/ `hybrid`(在此基础上并入向量翻出的高相似组)。纯时间窗口下,实测 45 对「双方活跃且 sim≥0.85」里 0 对能同时进窗口——该合并的一对几乎永远碰不到面。**已知边界**:dream 侧动作集仍是五分支(keep / merge / archive / update / conflict),hybrid 翻出的互补型 / 演进型对在 dream 里没有 `differentiate` / `supersede` 出口;正确出口在 sleep 侧(`sleepActionSet: full`)|
449
+ | `dreamCandidateMax` | `0` | hybrid 的候选总量上限;`0` = 复用 `dreamMaxSnapshotSize`。候选总量与库总量解耦,输入成本不随库增长 |
450
+ | `dreamCandidateMinSim` | `0.85` | hybrid 判「高相似」的阈值(与 sleep 的 normal 档对齐,两个模块共用同一个「高相似」定义) |
451
+ | `dreamMaxArchivePerRun` | `8` | 单轮 archive 决策上限(超限整单拒绝,防一次性大扫除;正常清理可调高) |
452
+ | `dreamMaxMergePerRun` | `40` | 单轮 merge 决策上限(超限整单拒绝)。merge 是巩固里唯一回吐正文的动作(每条要模型重写合并后的 content),所以这是「输出里正文占比」唯一可控的杠杆;默认 40 = 实测每轮 merge 数分布上沿(全库 p99 28 / max 39,历史 0 命中),与 archive 闸默认 8 同为尾险护栏而非成本削减工具。**注意**:`dream_consolidate` 的输出 token 里只有约 11.8% 是决策正文,其余约 88% 是推理与 JSON 骨架——想省 token 请调 `dreamReasoningEffort` 或换非思考模型,调小本键收益有限 |
453
+ | `dreamSkipInvalid` | `true` | 单条非法决策跳过 + 合法子集应用 + run 记 degraded(#89);`false` 恢复严格模式整单拒绝 |
454
+ | `allowCrossTypeMerge` | `false` | 显式放宽跨类型合并(默认关,类型边界由用户承担);跨类型意图的正确出口是 `sleepActionSet: full` |
455
+ | `dreamImplicitKeep` | `true` | 显式决策覆盖率不足时的隐式 keep(未提及条目保持原样);`false` + `dreamMinExplicitCoverage: 0` 恢复旧严格行为 |
456
+ | `dreamMinExplicitCoverage` | `0.5` | 显式决策覆盖率下限(0-1):合法子集低于该值降级 degraded 而非整单拒绝(#104 方向 1,PR #200) |
457
+ | `dreamMaxSnapshotSize` | `200` | autoDream 滑动窗口上限:每次只对最近 N 条做 consolidation,窗口外不进 snapshot(防 LLM 输入撑爆) |
458
+ | `dreamSummaryProvider` / `dreamSummaryModel` | 空 | 总览(dream_summarize)专用模型路由(留空 = 沿用 `dreamProvider`/`dreamModel`)。consolidate 有窗口(`dreamMaxSnapshotSize`)而总览输入随库增长,ctx 需求差数倍——用小 ctx 模型跑巩固时把总览指到大 ctx 模型(issue #258) |
459
+ | `dreamSummaryMaxInputs` | `0` | 总览输入条数硬上限(0 = 不设上限):超过时按 `updated_at` 倒序只保留最新 N 条进总览,防小 ctx 模型被全库输入撑爆;总览口径脚注的条数随实际输入变化 |
460
+ | `dreamMinIntervalMinutes` | `0` | autoDream 最小触发间隔(0-10080,0=不限):失败/degraded run 也占用 |
461
+ | `dreamPeakHours` | 空 | 巩固侧高峰时段(本地时间,与 `summarizePeakHours` **同一份语法**):空=关;命中时不调模型、baseline 不刷新(阈值继续累积,留到非高峰一次性巩固)、登记 `skipped`/`peak-hours` 审计并顺延到最近的高峰结束时刻。适合「白天要留算力给交互、巩固挪到夜里」的场景(#239 第 4 项镜像到巩固) |
462
+ | `dreamPeakMaxDeferMinutes` | `120` | 巩固侧高峰顺延上限(0-1440 分钟,0=不设上限):到点仍处高峰就照常跑,避免长高峰把巩固饿死(#239) |
463
+ | `dreamNarrativeEnabled` | `false` | 叙述条总开关(#164 对齐,v0.8.4):按共享 tag 主题簇合成叙述 + evidence 证据链,注入候选排除(按需检索,常驻位只留 dream 总览);也走 feature_flags 白名单,lightMode 强制关 |
464
+ | `dreamNarrativeMinCluster` | `3` | 主题簇合成叙述的最小成员数(2-20,v0.8.4) |
465
+ | `apiToken` | 空 | 可选 API 鉴权 token;设置后写操作与密钥接口要求 `Authorization: Bearer <apiToken>` |
466
+ | `externalApiEnabled` | `false` | 独立 HTTP API 服务开关(v0.7.12):开 standalone API(CLI 依赖它) |
467
+ | `externalApiHost` | `127.0.0.1` | standalone API 监听地址 |
468
+ | `externalApiPort` | `8790` | standalone API 监听端口 |
469
+ | `lightMode` | `false` | 轻量模式(v0.7.12):关闭所有重型增强(语义/实体/叙述/heat 等,见 feature_flags 白名单),纯存储+注入 |
470
+ | `policyEpoch` | `0` | 冲突裁决规则版本:bump 后旧 dream_runs 降级为历史证据(receipt 不再驱动实时裁决) |
471
+ | `embedProvider` | `openai` | 语义后端:`openai`(默认,兼容 v0.1)/ `local`(ONNX 离线)/ `ollama` |
472
+ | `localEmbedModel` | `Xenova/bge-small-zh-v1.5` | 本地 ONNX embedding 模型 |
473
+ | `localEmbedDimension` | `512` | 本地 embedding 向量维度 |
474
+ | `localEmbedDevice` | `cpu` | 本地推理设备:`cpu` / `gpu` |
475
+ | `localEmbedBatchSize` | `8` | 本地 embedding 批大小(1-64) |
476
+ | `ollamaBaseUrl` | `http://localhost:11434` | Ollama 服务地址 |
477
+ | `ollamaModel` | `nomic-embed-text` | Ollama embedding 模型 |
478
+ | `embedModelCacheDir` | 空 | 模型缓存目录(空 = 用户级 `~/.dsh/mneme/models`) |
479
+ | `embedModelMirror` | `https://hf-mirror.com` | 模型下载镜像源 |
480
+ | `resilientModelDownload` | `true` | 模型文件下载断点续传与重试(v0.8.3,#194/#207):Range/If-Range 续传、416/偏移失配重置、单写者锁+降级直通、空闲看门狗;`false` 恢复 env.fetch 原样 |
481
+ | `runtimeDir` | 空 | 自管运行时目录(#131):空 = `~/.dsh/mneme/runtime`,放收编/下载的 transformers+onnxruntime 闭包(不留宿主 profile 依赖图) |
482
+ | `runtimeTarballDir` | 空 | 运行时离线取件:本地 `.tgz` 目录(如 onnxruntime-node 网络下不到时 `npm pack` 丢进去),有则优先于联网 |
483
+ | `runtimeMirror` | 空 | 运行时 registry 镜像前缀(如 `https://npmmirror.com/mirrors/npm/`);留空用 runtime-manifest.json 官方地址 |
484
+ | `vectorSearchTopK` | `20` | 向量搜索返回 Top-K |
485
+ | `vectorSearchThreshold` | `0.65` | 向量搜索相似度阈值 |
486
+ | `hybridSearchVectorWeight` | `0.6` | 混合搜索向量权重 |
487
+ | `hybridSearchKeywordWeight` | `0.4` | 混合搜索关键词权重 |
488
+ | `recallFusion` | `blend` | 召回融合配方:`blend`(默认,加权求和)/ `rrf`(Reciprocal Rank Fusion)/ `minmax`(min-max 归一化加权)——后两者按 rank/尺度感知融合,修复原始分数单位不匹配 |
489
+ | `signalTransparency` | `false` | 给每条检索结果附加 `signals` 对象({keyword, vector, bm25, final})便于调试;只装饰不改排序 |
490
+ | `rerankEnabled` | `false` | 是否启用 Rerank 精排(显式开启才加载本地 onnxruntime 模型) |
491
+ | `rerankProvider` | `none` | Rerank 后端:`local` / `none`(默认 `none`) |
492
+ | `rerankModel` | `Xenova/bge-reranker-base` | Rerank 交叉编码模型 |
493
+ | `rerankBatchSize` | `8` | Rerank 批大小 |
494
+ | `rerankMaxCandidates` | `30` | Rerank 最大候选数 |
495
+ | `rerankScoreThreshold` | `0.1` | Rerank 分数阈值(低于丢弃) |
496
+ | `rerankDtype` | `q8` | Rerank 模型量化档(`q8` ≈ fp32 体积的 1/4,`fp32` 可关) |
497
+ | `reflectionUpdateEnabled` | `true` | update 决策总开关 |
498
+ | `reflectionFailureTracking` | `true` | 失败追踪总开关 |
499
+ | `reflectionUpdateMaxPerRun` | `2` | 每次整理最多 update 数 |
500
+ | `reflectionUpdateMinAgeHours` | `24` | 新建记忆保护期(小时) |
501
+ | `reflectionFailureRetentionDays` | `90` | 失败表(`failure_memories`)启动期清理保留天数(1-3650;此前写死 90) |
502
+ | `codingRetrospect` | `false` | 编码记忆蒸馏(v0.7.13,默认关):完整转录提炼编码原子记忆(rejected_solution/pitfall/constraint 三类型) |
503
+ | `codingKeywords` | 内置词表 | 编码任务识别词表(读取侧门控):命中即视为编码类任务,编码记忆才注入 |
504
+ | `codingBoostFactor` | `2` | 编码记忆注入排序的 boost 倍数(1-5) |
505
+ | `entityExtractionEnabled` | `false` | 实体抽取总开关(v0.3.0;存储层恒可用) |
506
+ | `entityExtractionModel` | 空 | 抽取专用模型(空 = 用 agent 默认模型) |
507
+ | `entityExtractionProvider` | 空 | 抽取专用模型服务商(空 = 用 agent 默认 provider/model,v0.7.29) |
508
+ | `entityExtractionReasoning` | 未配置=最低档 | 实体抽取推理档位(同 dreamReasoningEffort 语义,v0.7.29):被模型拒绝时自动去 effort 重试 |
509
+ | `entityExtractionMaxEntities` | `10` | 每次抽取实体数上限 |
510
+ | `entityRecallEnabled` | `false` | 图召回轴(v0.8.4,#219):实体挂联记忆并入检索融合池(三源扩四源,blend/rrf/minmax 全配方参与);依赖实体抽取产出,也走 feature_flags 白名单,lightMode 强制关 |
511
+ | `entityExtractionMaxAttrs` | `20` | 每实体属性数上限 |
512
+ | `entitySearchEnabled` | `true` | `entity:` / `attr:` 前缀搜索开关 |
513
+ | `trustEpistemicWeighting` | `false` | 记忆可信度加权(v0.4.5,opt-in 默认关):记忆按来源分级 `observation`> `inferred` > `subjective`,开启后检索排序优先高可信记忆、注入对 observation 标注 `[verified]`、dream merge/conflict 偏向高可信一方;关闭时 `epistemic_status` 仅随保存落库、不参与行为 |
514
+ | `evalPersistTestResults` | `false` | 检索评估落库(v0.4.5,opt-in 默认关):开启后 `evaluateRetrieval` 把 precision/recall/mrr 快照写入 `recall_evals`;默认关时仅返回调用方不落库。生产 `searchMemories` 审计始终走 `recall_runs`,无条件不触碰 `recall_evals` |
515
+ | `autoReindexOnBoot` | `true` | 存量记忆缺 embedding 时,向量已配置则启动后延迟后台按批次限速自动回填重建(设为 `false` 仅手动重建)。只补**活跃**记忆(归档/遗忘行不参与召回,#128);模型指纹一致时照常补缺失行、不再短路(#128) |
516
+ | `hybridInject` | `true` | 注入语义召回优先(v0.4.6,Bug4):`injectCandidates` 带非空 query 时先走向量索引语义召回候选,规则筛选补足/去重;空 query / 无向量回退旧逻辑 |
517
+ | `bm25SearchEnabled` | `true` | BM25 稀疏第三路召回(v0.5.0):ASCII 词元 + CJK bigram,IDF 加权,散词/ID/代码片段查询不再依赖子串命中 |
518
+ | `adaptiveThresholdEnabled` | `true` | 自适应相似度阈值(v0.5.0):按查询形态动态截断(前缀 0.5 / 短查询 0.7 / 长查询 0.6 / 头部分差大放宽 0.5),显式传 `threshold` 走旧行为 |
519
+ | `hotMemoryEnabled` | `true` | 会话级短期热记忆总开关(v0.5.0):关闭后热记忆块不再注入(长期召回不受影响) |
520
+ | `heatEnabled` | `false` | 热度模型总开关(v0.7.0 / v0.7.20 回归,**默认关**——v0.7.12 起用户已习惯无 heat 行为):开启后提供热度字段 / sleep 热联合降级保护 / 前端热度投影;注入排序乘热度已拆为独立开关 `injectHeatEnabled`(#218 / E5 考卷:heat 乘进注入排序在真实年龄混合下饿死老约束,默认关,显式开启恢复旧序)。关闭则跳过 heat 计算与热度触达,sleep 降级退回纯时间分层。也走 feature_flags 白名单(面板可启停=回滚开关),lightMode 预设强制关 |
521
+ | `heatGlobalBeta` | `1.0` | 广义指数形状参数 β(`H=exp(-λ·Δt^β)`,issue #218 拍板):β=1 纯指数;以 Δt>1 小时为准,β<1 衰减更慢(亚线性长尾)、β>1 衰减更快(超线性);0<Δt<1 的首小时内方向相反(Δt^β 随 β 增大而变小) |
522
+ | `heatTypeDecay` | 内置 TYPE_DECAY | per-type 衰减因子 λ;λ=0 的类型免疫(preference/pattern/summary 热度恒 1.0,sleep 永不降级) |
523
+ | `sleepHeatThreshold` | `0.05` | sleep 降级联合判定热度下限:heat<该值 **且** importance<5 才允许降级 |
524
+ | `sleepModeEnabled` | `false` | Sleep Mode 总开关(v0.4.0,opt-in):会话空闲 `sleepIdleMinutes` 后触发深维护(巩固/降级/模式发现),与 autoDream 串行不重叠 |
525
+ | `sleepIdleMinutes` | `5` | 触发 sleep 的空闲窗口(分钟,1-60) |
526
+ | `sleepMinIntervalHours` | `8` | 两次 sleep 最小间隔(小时,1-168):间隔内再次空闲不重复触发 |
527
+ | `sleepConflictStrictness` | `normal` | 冲突裁决严格度:`gentle`(高置信,阈值 0.92)/ `normal`(标准,0.85)/ `aggressive`(低置信也裁决,0.75) |
528
+ | `sleepActionSet` | `conflict` | sleep 冲突阶段动作集:`conflict`(默认=现状,只用 conflict/keep,后台流程不静默扩张)/ `full`(六分支 merge/update/supersede/differentiate/conflict/keep,#126) |
529
+ | `sleepArchiveDays` | `30` | 降级分层一:N 天未访问 → 缩为摘要(正文进 `_full_content`) |
530
+ | `sleepCompressDays` | `90` | 降级分层二:N 天未访问 → 直接归档(实体关系保留) |
531
+ | `sleepPatternMinMemories` | `100` | 模式发现扫描窗口(最近 N 条记忆,10-1000) |
532
+ | `sleepPatternLookbackDays` | `30` | 模式发现回看实体属性变更的天数(1-90) |
533
+ | `sleepMaxPatternPerRun` | `3` | 每轮模式记忆产出上限(0=禁用,0-10) |
534
+ | `sleepProvider` / `sleepModel` | 空 | sleep 深维护专用 LLM 路由覆盖(留空用巩固模型或当前模型;建议同巩固模型选非思考模型) |
535
+ | `sleepReasoningEffort` | 未配置=最低档 | sleep 各阶段 LLM 推理档位(同 dreamReasoningEffort 语义,v0.7.26) |
536
+ | `recallRecordDefault` | `true` | recall_runs 记录默认开(显式传 `recordRecall:false` 的调用方不受影响);注入同样落账(`mode='inject'`,随本开关,#217) |
537
+ | `recallRetentionDays` | `90` | recall_runs 滚动清理保留天数 |
538
+ | `hotMemoryRounds` | `5` | 会话级短期热记忆轮次(v0.5.0):最近 N 轮对话滚动注入,从会话事件日志无状态重建、不落库 |
539
+ | `hotMemoryMaxTokens` | `2000` | 热记忆 token 预算(v0.5.0,200-32000),超出滚动截断 |
540
+ | `selectiveInjectEnabled` | `true` | 选择性注入(v0.5.0):query 向量可用时注入候选按主题相似度重排,替代固定规则序 |
541
+ | `searchSemanticDedup` | `false` | 搜索时语义去重(v0.5.0,激进选项默认关):embedding 余弦 ≥0.95 近重复行在 Rerank 前丢弃 |
542
+ | `searchSemanticDedupThreshold` | `0.95` | 语义去重相似度阈值(v0.5.0,默认 0.95,范围 0.5-1.0):`searchSemanticDedup=true` 时生效,调整可防小模型误折叠 |
543
+ | `memoryQualityFilter` | `{enabled:true, archiveThreshold:30, degradeThreshold:60, minContentLength:10, exemptImportance:4}` | 记忆质量过滤(v0.4.6,默认开):写库前启发式打分 0-100,元记忆词汇/自指/过短/重复/近似重复扣分;≥60 正常存储,30-60 降权(注入排序按 importance×quality/100),<30 归档标记 `low_quality`(显式搜索仍可召回,永不自动注入;`exemptImportance` 豁免:importance ≥ 该值只降权不归档,#135) |
544
+ | `llmAudit` | `{enabled:true, retentionDays:90}` | LLM 消耗审计(v0.4.6,默认开):每次后台 LLM 调用(`autoDream` / `autoSummarize` / `sleep` / `entityExtract`,对应 `operation_type` 为 `dream_consolidate` / `dream_summarize` / `dream_narrative`、`summarize_compress`、`sleep_conflict` / `sleep_pattern`、`entity_extract`)写 `llm_audit_logs`(tokens/duration/status/source);失败记 error 不阻塞;只读 API `/api/dsh-mneme/semantic/llm-audit` + `/llm-audit/stats` |
545
+ | `scopeEnabled` | `false` | 作用域隔离总开关(v0.8.0,issue #17):memory_save 按会话身份写入 agent / workspace 标注(agentPreset / 工作区路径,registry 反查取不到回退 header.cwd,再取不到 NULL);去重键扩展含作用域三元——跨作用域同标题不再物理合并;检索与注入排序按当前会话作用域加权(命中 ×1.25、他 scope ×0.5 保留可见,issue #339 补齐注入通道)。也走 feature_flags 白名单(面板可启停) |
546
+ | `strictScope` | `false` | 作用域硬过滤(v0.8.0 引入,v0.8.1 起只认显式声明;依赖 `scopeEnabled`):检索 / 注入 / 列表 / 单取四路过滤,**显式声明**收窄到他者作用域的记忆完全不可见;载体自动标注只降权保留可见——真正的物理隔离请用 sensitivity。会话身份解析不到时 fail-closed 只挡显式行。关闭时全部为软隔离(降权保留可见)。也走 feature_flags 白名单 |
547
+ | `writeAdmission` | `{enabled:false, enforce:false}` | 写入准入(issue #254,默认关):把「这条该不该进库」前移到 LLM 之前。第 1 级是零 LLM 的确定性判据——空白 / 纯噪声 + 密钥 / PII(判据来源是 #164 A2,经 `sensitiveScan` 注入,本批只定义接口)。`enabled` 跑判据并落审计行(`llm_audit_logs` 的 `metadata.deny`),`enforce` 才真的拒(`store.save` 之前返回,`memory_save` 返回 `action:"denied"` + `reason`);只开 `enabled` = 仅告警、写入不拦。去重键命中不进第 1 级(归 write-update 放行),G1/G2 阈值只计量。也走 feature_flags 白名单 |
548
+ | `preInjectGate` | `{enabled:false, enforce:false}` | 注入前判定(issue #380,默认关):每帧注入候选出池后、进入 system prompt 前,一次池级 LLM 调用判出「会向本次请求注入意见/立场」的记忆(判定协议与 E12 实验同源;实测过滤把谄媚 26.9%→2.5%,且判定结果绝不进模型上下文——给模型看标记的线已被 E2/E3 关闭)。`enabled` 跑判定并落审计行(真实 token 用量 + 被标记记忆 id),`enforce` 才在缓存命中帧真滤除;冷缓存首帧降级为原样注入(宿主注入渲染是同步回调,判定走 prefetch+cache)。pin 池与检索线索行豁免;判定失败原样注入不阻塞;整池被标记时放弃本次滤除(fail-open);判定连续失败 3 次熔断一个冷却期;无默认路由时审计行 `model_id` 落 `unknown` 占位;`llmAudit` 关闭时本闸不运行;lightMode 强制关。也走 feature_flags 白名单 |
549
+ | `distillRecords` | `{enabled:false, retentionDays:90}` | 蒸馏原文留存 + 记忆级溯源(issue #399,默认关):把蒸馏从「替换」降级为「叠加索引」——蒸过的窗口原文旁路落 `distill_records`(一个事件一行,主键 `(session_id, seq)`,`INSERT OR IGNORE` 幂等),每条新记忆落 `memory_provenance` 回指来源窗口(`(memory_id, session_id, seq_start, seq_end)` 唯一)。**渲染与落盘共用同一隐私谓词**:私有推理链、插件注入的机器内容(AGENTS.md / skill 正文 / 文件变更通知)两条路都不进;工具调用入参与结果、code 输出**只进渲染、不落盘**(渲染是 `codingRetrospect` 的输入,落盘只留对话)。留存文本**不受** `distillMaxChars` / 工具裁剪约束(原文就是原文)。到期裁剪只删 `distill_records`,溯源链接保留指向空区间(面板显示「来源已过期」),**绝不级联删记忆**;删记忆时显式清链接。无历史回填、从未蒸馏的窗口不留记录。进 `dsh-mneme reclaim` 报告第三项;lightMode 强制关。也走 feature_flags 白名单 |
550
+ | `capacityWarning` | `{dbSizeWarnMb:256, archivedRowsWarn:5000, archivedRatioWarn:0.95}` | 容量预警(issue #275,空间维度):库体积 / 归档区规模过线时在 `GET /api/dsh-mneme/health` 的 `capacity` 块与面板「库体积」卡上报。三道阈值都是**观察口**,不是动作触发——没有周期性消费者,预警也永不自动归档 / 删除(真删由人显式确认),出口是维护卡的无损回收(`dsh-mneme reclaim`)。阈值判 `>=` 过线、**0 = 关掉该条检查**;判级 fail-safe(读失败显式 unknown,绝不伪装 ok)。默认值锚定 #275 议题的形态区间(活跃数百 / 归档数千;占比健康区就在 0.8~0.9,故 0.95 起才算过线)。答复只带数字、不带库文件路径;归档净增速率是 recall-stats `archive` 块的第五指标,不在这里重复。也走 feature_flags 白名单(改动启动快照生效,面板显示「待重启」) |
551
+ | `conflictFreezeEnabled` | `false` | 冲突冻结(v0.4.4):dream 发现矛盾对不自动裁决,冻结进冲突队列;状态页「冲突队列」支持并排对比与人工确认(保留 A / 保留 B / 仅标记已处理,v0.8.0) |
552
+ | `conflictFreezeMaxPending` | `100` | 冲突冻结队列最大挂起数(1-1000):超出后不再入队(防队列无限膨胀) |
553
+ | `escapePromptVariables` | `true` | 注入文本花括号转义(v0.8.0 恢复,issue #162):注入边界把 `{{...}}` 转义,防止 hot memory / 记忆原文里的 Go template / Vue 语法触发宿主 interpolate 抛错卡死会话(v0.7.4 曾修复、v0.7.11 误删) |
554
+
555
+ > 🔐 **API 安全**:DSH 无内置鉴权且默认仅监听 `127.0.0.1`。插件 API 默认开放(便于 Web 面板即装即用)——**未配 `apiToken` 时读和写都开放**,真正的围栏是回环 + 宿主监听器的 Host/Origin 校验(它防 DNS rebinding 与跨站浏览器请求,但不建立身份)。如需防护(如局域网暴露),在配置中设置 `apiToken`:此时**写操作**(新增/更新/删除/导入/收包(`/receive`、`/receive/undo`——写的是**本机自己的库**,归 `token-write`,所以免 token 的 GET 在那两条路径上只会拿到 405)/画像/规则/命令/开关/开关计费类)与**敏感读**(`/export`、`/external-api`、`/vector-config`、`/vector-reindex`、`/maintenance/*`、`/runtime/provision`、`/share`、`/memory/provenance`(蒸馏窗口的逐条会话原文,另受 `distillRecords.enabled` 门控))需携带 `Authorization: Bearer <token>`(前端设置面板填同一个 token);只读的 `list` / `search` / `semantic` / `inject-preview` 等**仍然开放**,不要把它们当成被 token 保护的面。`/api/dsh-mneme/vector-config` 返回的 `apiKey` 已掩码(`sk-***…`),存储仍保留明文供调用;前端回传空或掩码值表示"不改 key"。
556
+ >
557
+ > 安全模型全表(哪些路由免鉴权、为什么)见 [SECURITY.md](../SECURITY.md#5-security-model-what-actually-protects-what)。
558
+
559
+
560
+ > ⚠️ **已知边界:极简模式(minimal agent preset)下不注入**(宿主设计,非插件缺陷):minimal 预设的组合文件显式 `complete: true` + `includeRuntimeContext: false`——整条系统提示词被 persona 钉死、全部 runtime context 快照被压制,**记忆注入 / 用户画像 / hot memory 在极简模式会话中一律不送达模型**(宿主内置 context 同样消失)。判断与解法:会话头部显示「极简模式」即为该形态;需要记忆注入请改用标准模式(会话级切换,或 `~/.dsh/settings.yaml` 设 `agent-presets.default: standard`——注意 `--dump-config` 显示的是 bundle 默认值,会被用户层覆盖,不能反映实际生效值);极简模式下的过渡方案是把画像/规则写入 `AGENTS.md`(agent-instructions 走 section 路径,不受该压制影响)。
561
+
562
+ ## 外部 API 与 CLI
563
+
564
+ 除 DSH 内部端口外,插件还可以开启一个**独立的 HTTP 外部 API**(默认 `http://127.0.0.1:8790`,Bearer token 鉴权),供其他插件、CLI 脚本或桌面工具读写记忆,不依赖 DSH 内部端口。
565
+
566
+ ### 启用与鉴权
567
+
568
+ - 在插件设置中开启外部 API(默认监听 `127.0.0.1:8790`,仅本机可访问);
569
+ - 访问 token 在插件设置 / 面板「设置 → 外部访问」中查看;
570
+ - 除 `GET /health`(免鉴权)外,所有路由需携带 `Authorization: Bearer <token>`,无效 token 返回 `401 {"error":"unauthorized"}`。
571
+
572
+ 主要路由:
573
+
574
+ | 方法 | 路由 | 说明 |
575
+ |------|------|------|
576
+ | `GET` | `/health` | 健康检查(免鉴权),返回 `{ok:true}` |
577
+ | `GET` | `/status` | 版本、记忆统计、实体数、运行时长 |
578
+ | `GET` | `/profile` | 用户画像,返回 `{profile:"..."}`;未设置时为空字符串 |
579
+ | `GET` | `/rules` | 行为规则列表,返回 `{rules:[...]}`;未设置时为空数组 |
580
+ | `GET` | `/memories?limit&offset&type&minImportance&source&order=chrono&include_archived&occurred_from&occurred_to` | 分页列出记忆(`include_archived=true` 含归档;occurred 时间窗按 `occurred_at` 回退 `created_at`) |
581
+ | `GET` | `/memory/provenance?id=<memoryId>` 或 `?sessionId=<sid>`(可选 `&limit=`,默认 20、上限 100) | 溯源读出口,两个方向共用一条路径(#421 拆出两条:方向 1 记忆→窗口由 #509 交付,方向 2 会话→窗口由 #524 补上;宿主内面板路由 `/api/dsh-mneme/memory/provenance` 同一口径)。**两个主键互斥**:都缺 `400 {"error":"missing-id"}`、都给 `400 {"error":"ambiguous-id"}`(刻意不静默择一——两个方向的结果形状不同,猜一个只会在出事之后才发现)。方向 1 是一条溯源链接一个窗口 `{session_id, seq_start, seq_end, created_at, distill_run_id, run_type, trigger_source, run_status, records[]}`(#512 补运行归因:run 是归因主体,窗口只是它的一批输入;读不到整轮归因时整组 `null`,**不从区间或时间戳反推**),答复级另带 `mints[]`(行级归因:这条记忆出生自哪一轮 dream/sleep,只填 create);方向 2 把同一个 `(session_id, seq_start, seq_end)` 合并成一项(`GROUP BY`),带 `link_count`=这个窗口派生出几条记忆,按 `seq_start` 排——逐链接返回会让「这个会话蒸了几次」被重复行淹没。两个方向都带 `truncated`(撞上 limit 时说「还有更多」;少了它,被截断的答复与「本来就这么少」逐字节相同)。`records` 是那段蒸馏窗口的**逐条会话原文**(按 `seq` 升序、不越出区间)。没有链接返回**空 `windows`**——「不是蒸馏来的」是有效答案,不是错误。状态码阶梯:`401` 无 token → `400` 缺参/多参/`invalid-limit` → `409 {"error":"distill-records-disabled"}`(`distillRecords.enabled` 关着;该开关是**启动快照**,面板改完要到下次启动生效,面板会显示「待重启」)→ `503 {"error":"provenance-unavailable"}`(该方向要用的方法没接线,**按方向判**——只缺 session 侧方法时方向 1 仍然 200)→ `200`。`409` 与 `503` 必须分开读数:前者是「用户关了」,后者是「装配坏了」。**关开关 ≠ 删掉已留存原文**——只是不再经 HTTP 提供,盘上的行要 `dsh-mneme reclaim`(或重新开启后的启动裁剪)才走,详见 [docs/DISTILL.md](docs/DISTILL.md) |
582
+
583
+ | `GET` | `/memories/:id` | 单条记忆 |
584
+ | `POST` | `/memories` | 新增记忆 `{type,title,content,importance?,tags?,source?,sensitivity?,occurred_at?,agent_scope?,workspace_scope?}`;响应含 `action: created\|merged` |
585
+ | `PUT` | `/memories/:id` | 局部更新 `{title?,content?,type?,importance?,tags?,reason?,agent_scope?,workspace_scope?}`;content 改写按 human_override 入档 |
586
+ | `DELETE` | `/memories/:id` | 删除记忆 |
587
+ | `GET` | `/search?q&mode=keyword\|vector\|hybrid\|auto&topK&occurred_from&occurred_to&agent_scope&workspace_scope` | 搜索(关键词 / 向量 / hybrid=向量领位关键词补位 / 自动)。scope 两参声明调用方身份(不传 = 不解析,行为与旧版一致;任一给出则 strictScope 硬过滤与 A2 软加权随之生效) |
588
+ | `GET` | `/context?q&topK&threshold&agent_scope&workspace_scope` | 注入候选一站式聚合(issue #370,#363 承诺):宿主注入管线 `injectCandidates` 全语义(优先级分层 / 编码门控 / heat / scope 软加权 / hybrid 语义路 / pin 前置)+ 画像 + 规则,返回 `{profile, rules, items, pinnedCount, tier}` 结构化条目,不含渲染文本。`threshold` 是 **importance 阈值**(默认 3,与 `/search` 的相似度阈值同名不同义);`topK` 默认 5(对齐宿主 `maxInjectedItems`);scope 语义与 `/search` 同口径;跨轮轮换 / 热记忆 / 时间前缀不含(调用方自管);recall_runs 注入分账与宿主注入同口径(#217 `mode='inject'`) |
589
+ | `POST` | `/bootstrap` | 冷启动(v0.8.4):从仓库目录反向构建初始记忆,body `{dir}` 必填;幂等((type,title,scope) 去重 + `_overwrite` 原地刷新),零 LLM、必有产出 |
590
+ | `POST` | `/maintenance/reclaim` | 无损回收(#275 / #411,与面板同口径):**只有 POST**(本路径不提供 GET 预估分支)。字段只从 JSON body 读;`dryRun` 默认 `true`,只有 `dryRun:false` 且 `confirm:true` 才真删;`vacuum` 只允许显式指定 |
591
+ | `POST` | `/share` | 记忆分享包:把活跃记忆按口径打成可外发的 JSON 包,纯读不写库;取行与跳过口径、脱敏规则与 3 MiB 体积水位见 [docs/SHARE.md](docs/SHARE.md)。本路径的 GET 一律 405 |
592
+ | `POST` | `/receive` | 吃进一份分享包(body `{pack, confirm?}`,包内容整个送上来、服务端不读路径):**默认干跑**,只有 `confirm: true` 才写库;整包一个事务、按 `share_external_id` 幂等(同一个包重跑 `created = 0`),外来行标 `source=imported`,不参与本机巩固/降级。包里一条不合格就**整包拒**(收侧不做逐条修复,也不跑敏感扫描)。入站上限 4 MiB;GET 一律 405。细则与实测见 [docs/SHARE.md](docs/SHARE.md) |
593
+ | `POST` | `/receive/undo` | 整包退出(body `{packId, confirm?}`,同样**默认干跑**只清点):按 `share_pack_id` **物删**(不是归档——归档行会占住 UNIQUE 位,撤了反而导不回来),`deleted` 是全量、`sample` 只给前 20 条预览;什么都没导入时答 0,不抛。GET 一律 405 |
594
+
595
+ #### `/context` 的 `tier` 档位信号(#383)
596
+
597
+ `GET /context` 的响应多一个 `tier` 字段,回答「这次注入跑在哪一档」。嵌入降级在调用方视角原本完全静默——`items` 看着正常,只是召回质量悄悄变差,外部集成方无从感知自己长期跑在降级档上。
598
+
599
+ | `tier` | 含义 |
600
+ |--------|------|
601
+ | `full` | 语义档:查询嵌入成功,且与库里的向量维度可比 |
602
+ | `degraded` | 规则档:语义路本次不可用(原因见日志) |
603
+ | `unknown` | 语义路未启用(`q` 为空),或判不出来(维度探针没跑成 / 一条向量都读不出)——那不是降级,但也不宣称 `full` |
604
+
605
+ **两套消费者的分工:** `tier` 是**响应读数**,给调用方——三态、fail-closed(判不出来报 `unknown`,不报 `full`),用于在集成侧告警或切换策略。降级的**具体原因**是**日志读数**,给运维——走 daemon 的 stderr(`dsh-mneme: /context degraded to the rule tier (<reason>)`),不进响应体。原因枚举六值,互不吞并(成例是「修法不同就分开」):`embed-unavailable`(无可用嵌入接口:embedder 对象在,上面没有 `embedSingle` / `embed`)/ `embed-empty`(返回了空或非数组向量)/ `embed-timeout`(接口挂起,被超时护栏按缺失处理)/ `embed-error`(接口抛错)/ `embed-dimension`(接口成功了,但库里没有一条维度相符的活跃向量)/ `no-embedder`(压根没装配 embedder——daemon `--embed off`、lightMode、宿主未装配;**这是预期态,不是故障**)。六值的唯一真源是 `src/api-standalone.js` 导出的 `CONTEXT_DEGRADE_REASONS`,契约测试从它派生断言集合。
606
+
607
+ `embed-dimension` 值得单说:它是「拿到了向量却不可比」——`searchVector` 对维度不符的行直接跳过,不抛错、只是命中为零,于是召回静默退回关键词/规则档,而嵌入侧一切正常。修法是重建索引,不是查端点,所以它必须和前四个分开。`no-embedder` 与前四个也分开:前者(`embed-unavailable`)是适配器坏了、要修代码,后者是语义路没开、要把嵌装扮上或开起来,主体与动作都不同;并成一个值会让按 `embed-unavailable` 告警的面板对每个轻量模式安装报警。用词则与宿主面 `/api/dsh-mneme/semantic` 的 `reason` 对齐——同一个物理条件在两个面叫同一个名字(那边是另一套枚举、另一个消费者,别顺手统一)。
608
+
609
+ **`unknown` 之下的判档故障另有一条 warn:** `unknown` 有三个生产者(空 `q` / 维度探针没跑成 / 有行却一条向量都读不出来),响应体只有 `tier` 一个键、分不出它们,而调用方对 `unknown` 的策略常常是「不告警」——所以判不出来的情形会另打一行 `dsh-mneme: /context tier left unknown: <what>`(探针抛错 / 没有可读的向量可比)。**它不是上面那六值的一员**(`tier` 不是 `degraded`,没有降级原因可记),运维程序不要按原因枚举解析它。
610
+
611
+ **预算:** 判档不是免费的。`q` 非空且装配了 embedder 时,一次 `/context` 真的会起一次查询嵌入(一次网络往返 + `embedTimeoutMs` 的超时窗口)——档位要回答的正是「这次嵌入成不成」。这里没有复用 `/health` 的数据源:standalone 的 `/health` 只回 `{ok:true}`,而 `embeddingDimensionBreakdown` 是宿主面的一次全表扫(每行 JSON.parse 一个向量),按请求跑会把语义路成本翻倍。维度探针因此走 `service.vectorDimensionState()`——**按匹配短路的存在性判据**(有没有一条活跃向量的维度等于查询维度),不是「读一行的维度」:混合维度库里 `LIMIT 1` 会抽错维(明明有可比的向量却报 `degraded`),首条恰好解析失败时又会漏报成 `full`。成本是一次无 `LIMIT` 的全 id 扫描 + 按匹配短路的解析:全库同维度(常态)时循环第一行就返回,只解析 1 个向量;只有一条都不匹配时才走完整个循环,而那正是要报 `degraded` 的情形,值得。解析复用 `getParsedEmbedding` 的缓存,缓存热不热取决于 `injectCandidates` 是否真的走了 vectorIndex 分支。
612
+
613
+ ### curl 示例
614
+
615
+ ```bash
616
+ # 服务状态
617
+ curl -s -H "Authorization: Bearer $DSH_MNEME_TOKEN" http://127.0.0.1:8790/status
618
+
619
+ # 列出最近 5 条记忆
620
+ curl -s -H "Authorization: Bearer $DSH_MNEME_TOKEN" \
621
+ "http://127.0.0.1:8790/memories?limit=5"
622
+
623
+ # 新增一条决策记忆
624
+ curl -s -X POST http://127.0.0.1:8790/memories \
625
+ -H "Authorization: Bearer $DSH_MNEME_TOKEN" \
626
+ -H "Content-Type: application/json" \
627
+ -d '{"type":"decision","title":"采用 SQLite","content":"存储层使用 node:sqlite","importance":4,"tags":["存储"]}'
628
+ ```
629
+
630
+ ### CLI 安装
631
+
632
+ 插件自带零依赖 CLI(随 npm 包一起发布):
633
+
634
+ ```bash
635
+ npm i -g @modusensus/dsh-mneme
636
+ dsh-mneme --help
637
+ ```
638
+
639
+ 首次使用先配置服务地址与 token(也可用环境变量 `DSH_MNEME_URL` / `DSH_MNEME_TOKEN`,或 `--url` / `--token` 参数临时覆盖):
640
+
641
+ ```bash
642
+ dsh-mneme config set http://127.0.0.1:8790 <你的token>
643
+ ```
644
+
645
+ ### CLI 常用命令
646
+
647
+ ```bash
648
+ dsh-mneme status # 服务状态
649
+ dsh-mneme list --type project --limit 10 # 列出记忆
650
+ dsh-mneme search "部署流程" --mode vector --topk 5 # 语义搜索
651
+ dsh-mneme add --type decision --title "采用 SQLite" \
652
+ --content "存储层使用 node:sqlite" --importance 4 --tags 存储,决策
653
+ dsh-mneme get 42 # 查看单条
654
+ dsh-mneme delete 42 # 删除
655
+ dsh-mneme config show # 查看当前配置(token 打码)
656
+ dsh-mneme share --dry-run # 分享包:只看会进几条、跳过几条,不落盘
657
+ dsh-mneme share --out pack.json # 写一个可外发的脱敏包(3 MiB 水位在源头拒)
658
+ dsh-mneme receive pack.json # 吃包:默认干跑,一个字都不写
659
+ dsh-mneme receive pack.json --apply # 确认后真的吃进自己的库(整包一个事务,可重跑)
660
+ dsh-mneme undo-share pack.json --apply # 按 pack_id 整包收回(物删,不是归档)
661
+ ```
662
+
663
+ > 所有读取/写入命令支持 `--json` 输出原始 JSON;`config path` 打印配置文件路径(`~/.dsh-mneme/cli.json`)。
664
+ > 人类可读档只转达服务端文案里的 `hint` / `bytes` / `limitBytes`;闸门的 `detail`(坏在哪一格)与
665
+ > 413 的 `limit` 要 `--json` 才看得见——排查收包失败时先加它。
666
+
667
+ ### 独立服务(daemon,`dsh-mneme-serve`)
668
+
669
+ 不启动 DSH 也能让记忆库对外服务:`dsh-mneme-serve` 在宿主之外组装同一套 lib,把数据面跑成常驻进程(路由与鉴权与「独立外部 API」完全同源)。适用场景:第三方集成(如 [Mneme-Bridge](https://github.com/SternChiri/Mneme-Bridge) 这类网页端桥接,见下方[社区适配器](#社区适配器))需要长期挂载记忆库,而 DSH 不必一直开着。
670
+
671
+ ```bash
672
+ dsh-mneme-serve # 默认 ~/.dsh/memory + 8790
673
+ dsh-mneme-serve --memory-dir "D:\my mem" --port 8790 --host 127.0.0.1
674
+ dsh-mneme-serve --embed off # 纯关键词 + BM25(不取件模型)
675
+ ```
676
+
677
+ - **鉴权与端口**:Bearer token 与 DSH 面板 / CLI 共用同一份(kv `external_api`,首次启动自动生成并持久化到 `memory.db`);端口/主机解析链与「外部访问」一致(显式参数 > 持久值 > 默认 8790/127.0.0.1)。配置端口被占会**直接报错退出**(不做端口顺延)——第三方把 URL 写死,静默换端口等于坏。因此 **daemon 与 DSH 的「外部访问」二选一**,不要同端口同开。
678
+ - **安全**:daemon 使用明文 HTTP,不提供原生 TLS。指定非回环 `--host` 时,请勿直接把服务暴露给不可信网络;远程访问请走 TLS 终止代理或 SSH 隧道。
679
+ - **能力边界(第一期,无 LLM)**:存储 / 检索(关键词 + BM25 + 向量)/ 镜像同步与人改合并 / `POST /maintenance/reclaim` / `POST /receive`(吃包入库与整包退出:结构落库 + 随提交排空嵌入,**不建实体**——外来行本来就不做抽取,见 [docs/SHARE.md](docs/SHARE.md))/ `/bootstrap` 全可用;巩固(autoDream)与蒸馏不在 daemon 内——巩固只属于 DSH 宿主进程,这是与宿主「单写者」的机械保证。`--embed` 默认 `local`(自管 runtime 与嵌入模型缺失时自动取件,约 200MB;失败降级关键词并打日志),也可选 `ollama` / `openai`(读宿主面板的 vector-config)/ `off`。
680
+ - **检索回执**:daemon 的 `/search` 同样落 `recall_runs`,第三方检索的复用统计不缺数。
681
+ - **生命周期**:stdout 仅就绪时打一行 `dsh-mneme-serve listening on http://host:port (pid N)`(供脚本解析实际端口),日志走 stderr;SIGINT/SIGTERM 优雅收库,Windows 强杀由 WAL 回放兜底。
682
+ - **已知限制**:与 DSH 同时运行属设计内场景(WAL 多进程并发),但去重是先查后写、库层无 UNIQUE 约束,双进程并发写同一 `(type, title, scope)` 有极小概率产生重复;daemon 与插件请同版本升级。细节与坑清单见 [docs/DAEMON.md](docs/DAEMON.md)。
683
+
684
+ ### MCP Server(任意 MCP 客户端接入)
685
+
686
+ > Claude Code / Codex / Hermes / OpenCode / OpenClaw 等各客户端的最小挂载配置速查表见[根 README](../README.md#用在其他-ai-工具里mcp);本节是完整配置与安全说明。独立分发包 [`mneme-memory`](https://www.npmjs.com/package/mneme-memory)(bin `mneme-mcp`)已发布,与插件内置的 `dsh-mneme-mcp` 并存、挂载命令互相兼容。
687
+
688
+ 插件自带 stdio MCP server(`bin/dsh-mneme-mcp.mjs`,零依赖,随 npm 包发布,bin 名 `dsh-mneme-mcp`)。任何支持 Model Context Protocol 的客户端(Claude Code、Cursor 等)挂载后即可获得与 DSH 内一致的记忆工具六件套:`memory_save` / `memory_search` / `memory_list` / `memory_get` / `memory_update` / `memory_delete`——工具名、参数与去重合并、重要性等语义与 DSH 内工具对齐(测试锁漂移)。
689
+
690
+ 数据面走上面的**独立外部 API**(8790,Bearer):写入并发由 DSH 单点负责;DSH 未运行(外部 API 未启动)时 MCP 侧调用会报连接失败。scope 语义注意:外部 API 无会话上下文,`memory_save` 不做自动标注,只认显式 `agent_scope` / `workspace_scope` 声明。
691
+
692
+ 配置优先级沿用 CLI 约定:环境变量 `DSH_MNEME_URL` / `DSH_MNEME_TOKEN` > `~/.dsh-mneme/cli.json` > 默认 `http://127.0.0.1:8790`。安全注意:服务默认只绑 `127.0.0.1`;若把 `DSH_MNEME_URL` 指向非回环的明文 HTTP 地址,Bearer token 将明文过网(启动时会有 stderr 警告)——远程场景建议走 SSH 隧道。
693
+
694
+ Claude Code 挂载示例(项目根 `.mcp.json`;token 在面板「设置 → 外部访问 API」查看):
695
+
696
+ ```json
697
+ {
698
+ "mcpServers": {
699
+ "dsh-mneme": {
700
+ "command": "dsh-mneme-mcp",
701
+ "env": { "DSH_MNEME_TOKEN": "<你的token>" }
702
+ }
703
+ }
704
+ }
705
+ ```
706
+
707
+ 未全局安装 npm 包时,把 `command` 换成 `npx`、加 `args: ["-p", "@modusensus/dsh-mneme", "dsh-mneme-mcp"]` 即可。
708
+
709
+ ## 社区适配器
710
+
711
+ 以下项目由社区维护,把 mneme 接入第三方平台或宿主。它们不是本仓库的一部分,兼容性由各自维护者跟进——升级 mneme 后如遇接口变更,请优先查看对应项目的 release note。
712
+
713
+ | 项目 | 平台 | 说明 |
714
+ |------|------|------|
715
+ | [Mneme-Bridge](https://github.com/SternChiri/Mneme-Bridge) | DeepSeek 网页端 | 浏览器扩展(MV3)+ 本地 Node 服务:网页端会话蒸馏进 mneme 记忆库,DSH 侧记忆按话题回注网页对话,两侧共享同一份记忆。embedded(直接挂载 mneme lib)与 remote(standalone API,推荐配合 [`dsh-mneme-serve`](docs/DAEMON.md))双模式 |
716
+
717
+ > 想被收录?在 [Discussions](https://github.com/slow-stack/mneme/discussions) 开帖介绍你的项目,或直接提 PR 补充本表。
718
+
719
+ ## 🏗️ 架构
720
+
721
+ ```
722
+ ┌─────────────────────────────────────────────────┐
723
+ │ 存储层:SQLite (archived/forgotten 状态) │
724
+ │ + Markdown 镜像(人工可编辑,双向同步) │
725
+ ├─────────────────────────────────────────────────┤
726
+ │ 服务层:saveWithDedupe / injectCandidates │
727
+ │ / mergeHumanEdits / onWrite 钩子 │
728
+ ├─────────────────────────────────────────────────┤
729
+ │ 模型接口:12 个工具 + 自动注入 + 会话摘要 │
730
+ ├─────────────────────────────────────────────────┤
731
+ │ autoDream:阈值调度 → LLM 决策清单 │
732
+ │ → 校验(fail-safe)→ 应用 → 摘要 │
733
+ ├─────────────────────────────────────────────────┤
734
+ │ Web 面板:设置面板内嵌 + 浏览/搜索(含向量) │
735
+ └─────────────────────────────────────────────────┘
736
+ ```
737
+
738
+ **源码结构**:
739
+
740
+ ```
741
+ src/
742
+ ├── store.js # SQLite 存储(CRUD、搜索、归档/遗忘、schema 迁移、scope 四列)
743
+ ├── mirror.js # Markdown 镜像(渲染/解析,人工优先)
744
+ ├── service.js # 领域逻辑(去重合并、注入筛选、写入钩子、scope 加权/硬过滤、冲突队列)
745
+ ├── scope.js # 作用域解析(agentPreset + workspace registry 反查,issue #17)
746
+ ├── config.js # schemastery 配置 schema
747
+ ├── tools.js # 12 个模型工具(defineTool;memory_organize 要 organizeEnabled 打开才注册,开了是 13 个)
748
+ ├── user-settings.js # 「用户设置」注入块(人格 → 画像 → 规则)的唯一渲染处,注入与面板预览共用
749
+ ├── profile-extract.js # 从活跃记忆提取「助手眼中的用户」画像草稿(只出草稿,不写 user_settings)
750
+ ├── organize.js # agent 主动整理:dryRun 比对报告 → agent 判断 → apply 落库(筛除=归档不删,留 dream_runs 回执)
751
+ ├── inject.js # systemPrompt.context 动态注入(含花括号转义)
752
+ ├── summarize.js # 会话结束 LLM 摘要
753
+ ├── dream.js # autoDream 调度 + runDream(LLM 决策 + 摘要)
754
+ ├── dream/decisions.js# 决策校验(fail-safe)+ 决策应用
755
+ ├── dream/clustering.js # 候选集聚类(k-means++ seeding)
756
+ ├── dream/sleep.js # Sleep Mode 分层压缩
757
+ ├── entities/extractor.js # 实体抽取器(v0.3.0:LLM JSON 抽取 + 去重 + fail-safe)
758
+ ├── search/bm25.js # BM25 稀疏召回(v0.5.0:分词 + IDF 索引)
759
+ ├── search/adaptive.js# 自适应相似度阈值(v0.5.0)
760
+ ├── hot-memory.js # 会话级短期热记忆(v0.5.0:滚动轮次 + token 预算;注入剥离 reasoning)
761
+ ├── runtime/ # 自管本地推理运行时(收编 / 本地 .tgz / registry 三档取件 + 校验)
762
+ ├── embedding.js # OpenAI 兼容 embeddings 客户端 + 向量检索
763
+ ├── api.js # HTTP 路由(Web 面板数据通道,含 /conflicts 冲突队列)
764
+ └── index.js # 插件接线
765
+ lib/ # src 的同步分发产物(npm run sync,prepack 钩子在发布时自动跑;一致性由 scripts/check-sync.js 在 CI 与 release.yml 校验——它只查不同步;唯一手写例外 lib/client.js——Web 面板 bundle,sync 不覆盖)
766
+ test/ # 3399 个 node:test 测试(审计与三轴线压测不变量;src↔lib 一致性由 scripts/check-sync.js 发布闸门校验)
767
+ scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压测 · sync-lib.js 同步 · check-sync.js 发布闸门 · benchmark-recall.js / benchmark-embed.js / benchmark-rerank.js 基准 · sync-test-badge.mjs 测试徽章 · build-runtime-manifest.mjs 运行时清单
768
+ ```
769
+
770
+ ## 🧪 开发
771
+
772
+ ```bash
773
+ cd dsh-mneme
774
+ npm install # 安装 peer 依赖(以 devDependencies 形式,用于本地测试)
775
+ npm test # 运行 3399 个测试
776
+ npm run stress # 三轴线压测:长会话检索 / 冲突仲裁 / 多 Agent 并发(离线 mock LLM)
777
+ npm run sync # 把 src/ 同步到 lib/(发布时由 prepack 钩子自动执行)
778
+ ```
779
+
780
+ > 压测(`npm run stress`)三条轴线:**长会话检索**(Recall@k、陈旧残留率)、**冲突裁决**(可重放仲裁集:审计快照 hash + receipt + 幂等回放)、**多 Agent 并发**(丢更新、重复合并、事务/崩溃恢复)。每次 autoDream 运行都会写入审计表 `dream_runs`(输入快照 digest + 决策清单 + 逐 id 去向 + receipt),让高通过率下也能定位静默错误。
781
+
782
+ > `lib/` 是 `src/` 的同步分发产物(`npm run sync`):除 **`lib/client.js`**(Web 面板 bundle)为 lib 独有的手写文件、sync 与 check-sync 均不触碰外,其余全部由 src 复制而来。改 src 必 `npm run sync` 并提交 lib,否则发布产物静默失效(issue #65 教训)。
783
+
784
+ ## 📄 设计文档
785
+
786
+ > 设计文档在 `dsh-mneme/docs/`(本目录内,直接相对链接);只有能力对比表在仓库根 `docs/`,用 `../docs/` 指过去。GitHub 上从本目录打开均可正常跳转。
787
+
788
+ - [配置说明(全键参考)](docs/CONFIGURATION.md)
789
+ - [蒸馏原文留存与记忆级溯源](docs/DISTILL.md)(#399)
790
+ - [实体结构化记忆设计](docs/ENTITIES.md)
791
+ - [语义增强架构](docs/SEMANTIC.md)
792
+ - [本地模型部署指南](docs/LOCAL_MODEL.md)
793
+ - [工作流(M.O.):本体住项目,证据住记忆库](docs/WORKFLOWS.md)
794
+ - [连续性抢救(#249 N3):触发器口径与事件契约](docs/CONTINUITY.md)
795
+ - [Sleep Mode:空闲四阶段深度维护](docs/SLEEP.md)
796
+ - [存储与回收:表结构、保留期、`dsh-mneme reclaim`](docs/STORAGE.md)
797
+ - [选择性遗忘与事实更正:行粒度契约与失效关系缺口(#532)](docs/FORGET.md)
798
+ - [记忆分享包:出包与收包的口径、信任边界与实测(`dsh-mneme share` / `receive` / `undo-share`)](docs/SHARE.md)
799
+ - [独立服务 daemon(`dsh-mneme-serve`)](docs/DAEMON.md)
800
+ - [与 Zep / Graphiti / Mem0 / Letta / Hindsight 的能力对比](../docs/COMPARISON.md)
801
+
802
+ ## 🙏 致谢
803
+
804
+ autoDream 的理念溯源(理念借鉴、实现原创):
805
+
806
+ - **[Claude Code 的 Auto Dream](https://code.claude.com/docs/en/memory)**(Anthropic,Memory 2.0):理念源头——会话间隙由后台子代理整理记忆文件(去重、修矛盾、清衰减)。
807
+ - **[Sleep-time Compute: Beyond Inference Scaling at Test-time](https://arxiv.org/abs/2504.13171)**(UC Berkeley & Letta,arXiv:2504.13171):Auto Dream「离线巩固」思想背后的学术脉络。
808
+ - **cc-haha**:早期实现思路的参照之一。
809
+
810
+ 在上述工作之上,dsh-mneme 做了自己的工程发展:K-Means++ 聚类预分组(`src/dream/clustering.js`)、类型化决策清单(keep / merge / archive / conflict / update,及 sleep 侧 supersede / differentiate)与可回放的 sha256 摘要审计链(`dream_runs` / `receipt_chain`)。如有遗漏的灵感来源,欢迎提 issue 指出。
811
+
812
+ ## 📚 相关研究
813
+
814
+ dsh-mneme 的机制设计与下列公开研究相互印证(以下引用均逐一核对过 arXiv 收录页;机制对应关系为我们自己的映射,非原论文观点):
815
+
816
+ - **在线写入 + 离线巩固**:[Dual-Layer Agentic Memory with Fast Write Routing and Slow Consolidation](https://arxiv.org/abs/2608.22215)(arXiv:2608.22215)——与 autoDream 的「快写慢巩固」分工同构。
817
+ - **热度衰减与访问强化**:[FadeMem](https://arxiv.org/abs/2601.18642)(arXiv:2601.18642)——heat 记忆热度模型(指数衰减 × 访问强化 × 重要性调制)的学术近亲。
818
+ - **冲突裁决与状态追踪**:[StateMemBench](https://arxiv.org/abs/2608.19652)(arXiv:2608.19652)——记忆系统追踪演化状态的考卷;C1 冲突裁决(supersede 后不再引用旧值)以其为验收靶子。
819
+ - **何时该忘 / scope 门控**:[PersistBench](https://arxiv.org/abs/2602.01146)(arXiv:2602.01146);呈现层缓解见 [Structured Memory](https://arxiv.org/abs/2608.08300)(arXiv:2608.08300)——scope 语义域门控的问题出处与零契约变更改法。
820
+ - **领域全景**:[Write–Manage–Read 综述](https://arxiv.org/abs/2603.07670)(arXiv:2603.07670)——「写入 / 管理 / 读取」三段式与插件整体形状互证。
821
+ - **数月尺度的可靠性工程**:[Memory as Infrastructure](https://arxiv.org/abs/2609.05510)(arXiv:2609.05510)——与 sha256 审计链、fail-safe 降级同属「记忆即基础设施」路线。
822
+ - **相邻系统(对照)**:[Zep](https://arxiv.org/abs/2501.13956)(时序知识图谱)、[Mem0](https://arxiv.org/abs/2504.19413)(生产级抽取式记忆)、[Hindsight](https://arxiv.org/abs/2512.12818)(retain / recall / reflect 三操作)走「写入时 LLM 抽取 + 向量/图检索」路线;dsh-mneme 的差异点在于:巩固由 LLM 参与但产物全程留痕可回放,冲突冻结待人工复核,记忆只落本机。
823
+
824
+ ## 📜 License
825
+
826
+ MIT
827
+
828
+ ## 🤝 参与之前
829
+
830
+ 行为守则:[CODE_OF_CONDUCT.md](../CODE_OF_CONDUCT.md)。它管三件事——**署名归人**(模型不进作者行)、**责任落在签下作者行的人身上**、**发言权按证据分配,不按身份**。参与 issue / PR / 评审即受其约束;使用本插件不受约束,MIT 已经授权。