@modusensus/dsh-mneme 0.7.10 → 0.7.11

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 (154) hide show
  1. package/README.en.md +368 -0
  2. package/README.md +298 -169
  3. package/{dsh-mneme/cordis.patch.yml → cordis.patch.yml} +1 -0
  4. package/{dsh-mneme/lib → lib}/api.js +50 -295
  5. package/{dsh-mneme/lib → lib}/client.js +780 -936
  6. package/{dsh-mneme/src → lib}/config.js +6 -100
  7. package/{dsh-mneme/lib → lib}/dream/decisions.js +94 -143
  8. package/{dsh-mneme/lib → lib}/dream/sleep.js +12 -152
  9. package/{dsh-mneme/lib → lib}/dream.js +22 -168
  10. package/{dsh-mneme/src → lib}/hot-memory.js +0 -7
  11. package/{dsh-mneme/lib → lib}/index.js +6 -34
  12. package/{dsh-mneme/lib → lib}/inject.js +11 -53
  13. package/{dsh-mneme/src → lib}/mirror.js +1 -12
  14. package/{dsh-mneme/lib → lib}/quality-filter.js +1 -3
  15. package/{dsh-mneme/lib → lib}/reranker.js +1 -4
  16. package/{dsh-mneme/lib → lib}/service.js +20 -410
  17. package/{dsh-mneme/lib → lib}/settings.js +0 -70
  18. package/{dsh-mneme/lib → lib}/store.js +35 -450
  19. package/{dsh-mneme/lib → lib}/summarize.js +10 -10
  20. package/lib/tools.js +274 -0
  21. package/package.json +41 -19
  22. package/{dsh-mneme/scripts → scripts}/e2e-dsh.js +3 -4
  23. package/{dsh-mneme/scripts → scripts}/sync-lib.js +5 -10
  24. package/{dsh-mneme/src → src}/api.js +50 -295
  25. package/{dsh-mneme/lib → src}/config.js +6 -100
  26. package/{dsh-mneme/src → src}/dream/decisions.js +94 -143
  27. package/{dsh-mneme/src → src}/dream/sleep.js +12 -152
  28. package/{dsh-mneme/src → src}/dream.js +22 -168
  29. package/{dsh-mneme/lib → src}/hot-memory.js +0 -7
  30. package/{dsh-mneme/src → src}/index.js +6 -34
  31. package/{dsh-mneme/src → src}/inject.js +11 -53
  32. package/{dsh-mneme/lib → src}/mirror.js +1 -12
  33. package/{dsh-mneme/src → src}/quality-filter.js +1 -3
  34. package/{dsh-mneme/src → src}/reranker.js +1 -4
  35. package/{dsh-mneme/src → src}/service.js +20 -410
  36. package/{dsh-mneme/src → src}/settings.js +0 -70
  37. package/{dsh-mneme/src → src}/store.js +35 -450
  38. package/{dsh-mneme/src → src}/summarize.js +10 -10
  39. package/src/tools.js +274 -0
  40. package/{dsh-mneme/test → test}/api.test.js +1 -156
  41. package/{dsh-mneme/test → test}/client.test.js +10 -206
  42. package/{dsh-mneme/test → test}/config.test.js +0 -21
  43. package/{dsh-mneme/test → test}/dream.test.js +1 -160
  44. package/{dsh-mneme/test → test}/graph-api.test.js +0 -34
  45. package/{dsh-mneme/test → test}/hot-memory.test.js +0 -29
  46. package/test/inject.test.js +120 -0
  47. package/{dsh-mneme/test → test}/llm-audit.test.js +4 -4
  48. package/{dsh-mneme/test → test}/reasoning-effort.test.js +0 -27
  49. package/{dsh-mneme/test → test}/recall-layer.test.js +5 -26
  50. package/{dsh-mneme/test → test}/reranker.test.js +0 -43
  51. package/{dsh-mneme/test → test}/service-search.test.js +0 -25
  52. package/{dsh-mneme/test → test}/service.test.js +0 -106
  53. package/{dsh-mneme/test → test}/settings.test.js +0 -43
  54. package/{dsh-mneme/test → test}/sleep.test.js +4 -171
  55. package/{dsh-mneme/test → test}/store.test.js +0 -76
  56. package/{dsh-mneme/test → test}/summarize.test.js +16 -15
  57. package/test/tools.test.js +265 -0
  58. package/.github/workflows/publish.yml +0 -58
  59. package/.github/workflows/test.yml +0 -32
  60. package/CHANGELOG.md +0 -91
  61. package/CONTRIBUTING.md +0 -293
  62. package/SECURITY.md +0 -718
  63. package/docs/devlog/2026-08-14-dsh-mneme-dev-log.md +0 -247
  64. package/docs/devlog/2026-08-15-dsh-mneme-audit-stress-dev-log.md +0 -145
  65. package/docs/devlog/2026-08-15-dsh-mneme-pipeline-dev-log.md +0 -56
  66. package/docs/devlog/2026-08-15-dsh-mneme-reflection-dev-log.md +0 -77
  67. package/docs/devlog/2026-08-15-dsh-mneme-review-fixes-dev-log.md +0 -64
  68. package/docs/devlog/2026-08-15-dsh-mneme-semantic-dev-log.md +0 -90
  69. package/dsh-mneme/CHANGELOG.md +0 -419
  70. package/dsh-mneme/LICENSE +0 -21
  71. package/dsh-mneme/README.md +0 -501
  72. package/dsh-mneme/docs/AGENT_MEMORY_RESEARCH.md +0 -183
  73. package/dsh-mneme/docs/ENTITIES.md +0 -245
  74. package/dsh-mneme/docs/LOCAL_MODEL.md +0 -141
  75. package/dsh-mneme/docs/MIGRATION.md +0 -127
  76. package/dsh-mneme/docs/SEMANTIC.md +0 -256
  77. package/dsh-mneme/docs/SLEEP.md +0 -163
  78. package/dsh-mneme/lib/dream/tag-extractor.js +0 -156
  79. package/dsh-mneme/lib/heat.js +0 -136
  80. package/dsh-mneme/lib/parser/tag.js +0 -59
  81. package/dsh-mneme/lib/parser/wiki-link.js +0 -38
  82. package/dsh-mneme/lib/search/tag-boost.js +0 -61
  83. package/dsh-mneme/lib/tools.js +0 -458
  84. package/dsh-mneme/package-lock.json +0 -1936
  85. package/dsh-mneme/package.json +0 -83
  86. package/dsh-mneme/scripts/check-sync.js +0 -42
  87. package/dsh-mneme/src/client.js +0 -2242
  88. package/dsh-mneme/src/dream/tag-extractor.js +0 -156
  89. package/dsh-mneme/src/heat.js +0 -136
  90. package/dsh-mneme/src/parser/tag.js +0 -59
  91. package/dsh-mneme/src/parser/wiki-link.js +0 -38
  92. package/dsh-mneme/src/search/tag-boost.js +0 -61
  93. package/dsh-mneme/src/tools.js +0 -458
  94. package/dsh-mneme/test/boundary-v0625.test.js +0 -82
  95. package/dsh-mneme/test/directory.test.js +0 -134
  96. package/dsh-mneme/test/heat.test.js +0 -148
  97. package/dsh-mneme/test/inject.test.js +0 -206
  98. package/dsh-mneme/test/layered-types-stats.test.js +0 -144
  99. package/dsh-mneme/test/lib-smoke.test.js +0 -109
  100. package/dsh-mneme/test/normalize-decisions.test.js +0 -120
  101. package/dsh-mneme/test/provenance.test.js +0 -103
  102. package/dsh-mneme/test/recall-runs.test.js +0 -93
  103. package/dsh-mneme/test/sleep-heat.test.js +0 -112
  104. package/dsh-mneme/test/tag-boost.test.js +0 -125
  105. package/dsh-mneme/test/tag.test.js +0 -426
  106. package/dsh-mneme/test/tools.test.js +0 -674
  107. package/dsh-mneme/test/updated-at-semantics.test.js +0 -113
  108. package/dsh-mneme/test/wiki-link.test.js +0 -332
  109. package//346/250/252/345/271/205.png +0 -0
  110. /package/{dsh-mneme/lib → lib}/commands.js +0 -0
  111. /package/{dsh-mneme/lib → lib}/dream/clustering.js +0 -0
  112. /package/{dsh-mneme/lib → lib}/embedding.js +0 -0
  113. /package/{dsh-mneme/lib → lib}/entities/extractor.js +0 -0
  114. /package/{dsh-mneme/lib → lib}/local-embedder.js +0 -0
  115. /package/{dsh-mneme/lib → lib}/search/adaptive.js +0 -0
  116. /package/{dsh-mneme/lib → lib}/search/bm25.js +0 -0
  117. /package/{dsh-mneme/lib → lib}/vector-index.js +0 -0
  118. /package/{dsh-mneme/scripts → scripts}/benchmark-embed.js +0 -0
  119. /package/{dsh-mneme/scripts → scripts}/benchmark-recall.js +0 -0
  120. /package/{dsh-mneme/scripts → scripts}/benchmark-rerank.js +0 -0
  121. /package/{dsh-mneme/scripts → scripts}/stress-dsh.js +0 -0
  122. /package/{dsh-mneme/src → src}/commands.js +0 -0
  123. /package/{dsh-mneme/src → src}/dream/clustering.js +0 -0
  124. /package/{dsh-mneme/src → src}/embedding.js +0 -0
  125. /package/{dsh-mneme/src → src}/entities/extractor.js +0 -0
  126. /package/{dsh-mneme/src → src}/local-embedder.js +0 -0
  127. /package/{dsh-mneme/src → src}/search/adaptive.js +0 -0
  128. /package/{dsh-mneme/src → src}/search/bm25.js +0 -0
  129. /package/{dsh-mneme/src → src}/vector-index.js +0 -0
  130. /package/{dsh-mneme/test → test}/audit.test.js +0 -0
  131. /package/{dsh-mneme/test → test}/benchmark.test.js +0 -0
  132. /package/{dsh-mneme/test → test}/clustering.test.js +0 -0
  133. /package/{dsh-mneme/test → test}/commands.test.js +0 -0
  134. /package/{dsh-mneme/test → test}/conflict-freeze.test.js +0 -0
  135. /package/{dsh-mneme/test → test}/entities.test.js +0 -0
  136. /package/{dsh-mneme/test → test}/epistemic.test.js +0 -0
  137. /package/{dsh-mneme/test → test}/fnew-0112.test.js +0 -0
  138. /package/{dsh-mneme/test → test}/fnew-03.test.js +0 -0
  139. /package/{dsh-mneme/test → test}/helpers/dream-mock.js +0 -0
  140. /package/{dsh-mneme/test → test}/local-embedder.test.js +0 -0
  141. /package/{dsh-mneme/test → test}/mirror-dirty.test.js +0 -0
  142. /package/{dsh-mneme/test → test}/mirror-edit-digest.test.js +0 -0
  143. /package/{dsh-mneme/test → test}/mirror-generation.test.js +0 -0
  144. /package/{dsh-mneme/test → test}/mirror.test.js +0 -0
  145. /package/{dsh-mneme/test → test}/peer-blockers.test.js +0 -0
  146. /package/{dsh-mneme/test → test}/policy-epoch.test.js +0 -0
  147. /package/{dsh-mneme/test → test}/quality-filter.test.js +0 -0
  148. /package/{dsh-mneme/test → test}/recall-evals.test.js +0 -0
  149. /package/{dsh-mneme/test → test}/receipt-chain.test.js +0 -0
  150. /package/{dsh-mneme/test → test}/reflection.test.js +0 -0
  151. /package/{dsh-mneme/test → test}/search-fusion.test.js +0 -0
  152. /package/{dsh-mneme/test → test}/semantic.test.js +0 -0
  153. /package/{dsh-mneme/test → test}/stress.test.js +0 -0
  154. /package/{dsh-mneme/test → test}/vector-index.test.js +0 -0
package/README.en.md ADDED
@@ -0,0 +1,368 @@
1
+ <p align="center"><strong>中文 | <a href="docs/SEMANTIC.md">English (Semantic)</a></strong></p>
2
+
3
+ # dsh-mneme
4
+
5
+ English | [简体中文](README.md)
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@modusensus/dsh-mneme?color=blue&label=npm)](https://www.npmjs.com/package/@modusensus/dsh-mneme)
8
+ [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
9
+ [![Awesome](https://awesome-dsh-plugin.com/badge.svg)](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin)
10
+ [![tests](https://img.shields.io/badge/tests-450%20passed-success)](https://github.com/modusensus/dsh-mneme)
11
+
12
+ > A cross-session memory plugin for DeepSeek Harness: it lets the Agent remember you, remember your projects, and organize memories automatically. **Mneme** (Μνήμη) — named after Mnemosyne, the Greek goddess of memory who presides over memory and dreams, just as autoDream consolidates memories in the background.
13
+
14
+ `dsh-mneme` is a [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) plugin that gives Agents persistent cross-session memory. It draws on Claude's **Dream mechanism** and the **autoDream** implementation ideas from cc-haha / Claude Code — it does not just **store** memories, it also **consolidates them automatically** (deduplication, merging, conflict adjudication, summary generation), so the memory store keeps getting more refined with use.
15
+
16
+ ## ✨ Features
17
+
18
+ ### Memory Storage (SQLite + Markdown Mirror)
19
+
20
+ - **SQLite primary storage**: `~/.dsh/memory/memory.db`, built-in `node:sqlite`, zero native dependencies
21
+ - **Markdown mirror**: `preferences.md` / `projects.md` / `decisions.md` / `history.md` / `summary.md` — human-readable and hand-editable (**manual edits take priority** when merged back into the store)
22
+ - **4+1 memory types**: `preference` / `project` / `decision` / `history` / `summary`
23
+ - **Mirror sync state machine (v0.3.6+)**: the mirror is strongly consistent with the primary store, with sync debt modeled via `generation` (desired round) / `applied_generation` (applied round)
24
+ - Business write operations **atomically increment** the desired generation **within their own transaction** — even a crash after COMMIT but before rendering recovers on restart from the durable debt, never silently skipped (v0.3.8)
25
+ - `generation` is incremented with atomic SQLite statements — zero loss under multi-process concurrency; a `CHECK` upper bound rejects negative values/overflow
26
+ - Per-type `committed / failed / pending` receipts; the health endpoint distinguishes `ok / degraded / unknown`
27
+ - State write failures are never silent: sync failures are logged and leave debt behind, converging automatically on restart
28
+
29
+ ### Model Tools (7)
30
+
31
+ | Tool | Function |
32
+ |------|------|
33
+ | `memory_save` | Save a memory (automatic dedup and merge by title) |
34
+ | `memory_search` | Full-text search (Chinese-substring friendly; vector semantic search can be enabled) |
35
+ | `memory_list` | Paginated listing by type (`include_archived=true` to view archived items) |
36
+ | `memory_update` | Modify an existing memory |
37
+ | `memory_delete` | Delete a memory |
38
+ | `memory_forget` | Suppress injection (down-weighted rather than deleted; recoverable) |
39
+ | `memory_archive` | Archive/restore memories (v0.2.5; archived items are hidden from listing/search/injection/consolidation, `archived=false` restores them) |
40
+
41
+ ### Auto Injection + Session Summary
42
+
43
+ - **Auto injection**: at the start of a new session, a memory digest is injected (the `summary` first, plus a few high-importance items)
44
+ - **Session summary**: at `turn/end`, an LLM distills the preferences/decisions/lessons of the session and stores them automatically (plugin-injected context is filtered out to avoid contamination)
45
+
46
+ ### autoDream Automatic Memory Consolidation 🧠
47
+
48
+ - **Trigger**: fires asynchronously and automatically once memory count > 10 or total characters > 5000 (never blocks writes)
49
+ - **Decision-list consolidation**: the LLM outputs a decision list of `keep` / `merge` / `archive` / `conflict` / `update` decisions, which the server validates and then applies item by item
50
+ - `merge`: merges entries with similar topics, keeping the most information-complete one
51
+ - `archive`: archives outdated/redundant entries (recoverable, never physically deleted)
52
+ - `conflict`: adjudicates contradictory information — the winner is kept, the loser is archived with a provenance note appended
53
+ - `update` (v0.2.1): directly corrects outdated/incorrect content of a single memory (single id / must actually change / not `summary` / 24h protection / ≤2 per run)
54
+ - **Failure tracking (v0.2.1)**: when the user corrects a memory, it is written to the `failure_memories` table (old value/new value), accumulating data for future self-evolution
55
+ - **Summary generation**: after consolidation, a "memory store overview" (single instance) is generated, injected with priority in the next session
56
+ - **Fail-safe**: illegal LLM output (unknown id / invalid action / cross-type merge / out-of-range importance) rejects the entire decision list — the memory store is never corrupted
57
+ - **Adjudication audit**: every run writes to the `dream_runs` audit table (input snapshot sha256 digest + full input snapshot + decision list + per-id disposition + receipt), replayable offline; merge / conflict / update are applied idempotently — replays and concurrent duplicate runs have no cumulative side effects; `update` records a `_before` snapshot
58
+
59
+ #### dreamMaxTokens Tuning Guide
60
+
61
+ The default `4096` covers ordinary memory stores. When the **memory volume is large** (tens of thousands of characters or more), the decision list and summary may exceed the default budget; scale it up by size:
62
+
63
+ | Memory store size | Recommended `dreamMaxTokens` |
64
+ |-----------|----------------------|
65
+ | Ordinary (<10k chars) | `4096` (default) |
66
+ | Medium (10k–50k chars) | `65536` |
67
+ | Large (>50k chars) | `131072` (cap) |
68
+
69
+ > With **reasoning models** (e.g. DeepSeek-R1-like), the model may spend the entire budget on reasoning and return an empty body (the log shows `no json array in llm output`). In that case, setting `dreamReasoningEffort` to `low` suppresses reasoning overhead and leaves the budget for the body output; the sleep side has the corresponding `sleepReasoningEffort`. The default `none` omits the field entirely, fully honoring the model's own default — behavior identical to earlier versions.
70
+
71
+ ### Sleep Mode: System-Level Sleep 💤 (v0.4.0, opt-in)
72
+
73
+ Upgrades autoDream's "passive threshold triggering" into "proactive scheduled maintenance + tiered compression". Once the system has been idle for `sleepIdleMinutes` minutes, deep maintenance runs automatically. **Off by default** (`sleepModeEnabled: false`); once enabled:
74
+
75
+ - **Interruptible**: implemented with AbortController — user activity aborts the current cycle (`noteWrite` resets the idle timer + the abort signal)
76
+ - **Serially safe**: sleep cycles go through the `service.enqueue` serial queue, strictly non-overlapping with autoDream; `minRefTimeMs` prevents memories recalled after the snapshot from being mistakenly demoted
77
+ - **Four-phase deep maintenance**:
78
+ 1. `conflict_resolution`: store-wide conflict resolution, strictness configurable in three levels (gentle 0.92 / normal 0.85 / aggressive 0.75)
79
+ 2. `archival_demotion`: tiered by `last_accessed_at` — not recalled for 30 days → compressed into a summary (original text kept in `_full_content`, losslessly restorable); 90 days → fully archived
80
+ 3. `pattern_discovery`: the LLM scans recent memories to distill patterns, producing `type=pattern` memories, with strict evidence validation to prevent fabrication
81
+ 4. `relation_completion`: detects orphaned entities and completes implicit relations (co-occurrence `related_to` / project `part_of` / technology `depends_on`)
82
+ - **Fail-safe**: each phase has its own try/catch — an LLM failure only skips the corresponding phase; without an LLM route, the pure-rule fallbacks (demotion/relations) still run
83
+ - **Audit continuity**: sleep cycles write to `dream_runs` with `run_type='sleep'`, sharing the audit table with autoDream for traceability
84
+
85
+ > See `docs/SLEEP.md` for configuration; see `docs/MIGRATION.md` for migration notes.
86
+
87
+ ### Web Memory Panel
88
+
89
+ Official settings panel → "Memory Store Settings" → "Memory" tab: browse by type, full-text search; once vector search is enabled, the "Semantic" toggle becomes available for vector recall.
90
+
91
+ ### User Settings (Profile / Rules) and Custom Commands ⚙️
92
+
93
+ Official settings panel → "Memory Store Settings" tab:
94
+
95
+ - **User profile**: a free-text passage describing the user (role, background, preferences), **injected into the system prompt every turn** so the Agent always follows it
96
+ - **Rules**: a list of behavioral rules the Agent must obey (e.g. "give the conclusion first"), likewise injected every turn
97
+ - **Custom commands**: register slash commands (`/name`); when triggered, the user-defined instruction content is handed to the Agent. Commands persist to SQLite, are automatically registered into the DSH command table at startup, and adding/removing takes effect in real time
98
+
99
+ > Profile and rules are injected through a separate `[用户设置]` (User Settings) block (higher priority than the memory store), and are injected even when memories are empty.
100
+
101
+ ### Vector Search (Semantic Search) 🔎
102
+
103
+ An optional capability: connect an OpenAI-compatible embeddings API so search can hit memories that are **literally different but semantically close**.
104
+
105
+ **Configuration**: official settings → "Memory Store Settings" → scroll to the bottom "Vector Search" section:
106
+
107
+ | Field | Description |
108
+ |------|------|
109
+ | `启用向量搜索` (Enable vector search) | Master switch; once on, a "Semantic" toggle appears in the memory panel |
110
+ | `API 地址 (Base URL)` | OpenAI-compatible endpoint, e.g. `https://api.openai.com/v1`; also supports SiliconFlow, Zhipu, local Ollama, etc. |
111
+ | `API Key` | The key for the corresponding service |
112
+ | `模型名` (Model name) | Embedding model, e.g. `text-embedding-3-small`, `text-embedding-v3`, `bge-m3`, etc. |
113
+
114
+ After saving, click "重建索引" (Rebuild Index) to backfill vectors for existing memories in bulk (newly written memories are embedded automatically). Then enter a query in the memory panel and click "语义" (Semantic) to recall semantically related results via vectors; if the vector service is unavailable, it automatically falls back to full-text search.
115
+
116
+ > ⚠️ The key is stored only in the local `user_settings` table of `~/.dsh/memory/memory.db`; it is never uploaded and never written into the code repository.
117
+ > You need an embedding model, not a rerank model: e.g. Alibaba Cloud's `text-embedding-v3` works, while `qwen3-vl-rerank` is a rerank model (it does not go through `/embeddings`).
118
+
119
+ ### Semantic Enhancement 🧠
120
+
121
+ Since v0.2, a **fully offline semantic memory engine** (local models + reranking + clustering):
122
+
123
+ - **Local embedding**: three selectable backends — ONNX (`Xenova/bge-small-zh-v1.5`, offline) / Ollama / OpenAI-compatible; failures fall back level by level automatically, with keyword search as the last resort
124
+ - **Rerank fine-ranking**: `Xenova/bge-reranker-base` cross-encodes recalled candidates for reranking, improving Top-K accuracy
125
+ - **autoDream semantic enhancement**: clusters memory vectors (`clusterMemories`) to automatically discover topically similar / potentially contradictory memories, making consolidation more precise
126
+ - **Search pipeline**: hybrid recall (keywords + vectors) → Rerank → Top-K
127
+
128
+ Configuration only requires setting `embedProvider` in `cordis.patch.yml` (default `openai`, preserving v0.1 behavior; switch it to `local` for offline). Upgrading requires no data migration.
129
+
130
+ ### Entity-Structured Memory (Entity Gene) 🧬
131
+
132
+ Since v0.3.0, a new **memory gene** layer: extracts **named entities**, **attributes with a timeline**, and **relations between entities** from memories, upgrading search from "literal keywords" to "precise recall by entity/attribute".
133
+
134
+ - **Three tables**: `entities` / `entity_attrs` (`valid_until` snapshot-style timeline) / `entity_relations`; opening an older database creates the tables automatically — idempotent, zero migration cost
135
+ - **Automatic extraction**: once `entityExtractionEnabled=true`, newly written memories fire-and-forget trigger LLM extraction (same-name entity dedup, attributes stored on the timeline, relations appended; failures never block writes)
136
+ - **Entity search** (`searchMemories` prefix routing, `entitySearchEnabled` on by default):
137
+ - `entity:阿尔托` → memories precisely associated via attributes (`_score 1.0`) rank ahead of keyword mentions (`_score 0.7`)
138
+ - `attr:国籍=芬兰` → memories exactly matching that attribute value
139
+ - `attr:国籍` → **all** currently valid memories for that attribute key (empty-value contract)
140
+ - **autoDream integration**: `update` decisions write a `supersedes` self-reference (the attribute version is superseded); `merge` decisions migrate the loser's attribute ownership to the keeper (void if the keeper already has a current value for the same key)
141
+
142
+ > 📖 See also: [Entity-Structured Memory Design](docs/ENTITIES.md) · [Semantic Enhancement Architecture](docs/SEMANTIC.md) · [Local Model Deployment Guide](docs/LOCAL_MODEL.md) · [Upgrading from v0.1](docs/MIGRATION.md)
143
+
144
+ ### Memory Quality Filter 🧼 (v0.4.6, on by default)
145
+
146
+ Before writing to the store, every memory receives a **heuristic quality score** (a pure function — no I/O, no shared state): meta-memory vocabulary (talking about the memory system itself), self-referential type tags, overly short content, high repetition, and near-duplication of recent memories all deduct points (0-100):
147
+
148
+ - `score ≥ 60`: stored normally
149
+ - `30 ≤ score < 60`: `quality_score` is persisted and injection ranking is down-weighted by `importance × quality/100` (degraded)
150
+ - `score < 30`: archived and flagged `low_quality` — still recallable via explicit search, but **never auto-injected**
151
+
152
+ `memoryQualityFilter.enabled` turns the feature off entirely; `archiveThreshold` / `degradeThreshold` / `minContentLength` are tunable.
153
+
154
+ ### LLM Usage Audit 📊 (v0.4.6, on by default)
155
+
156
+ Every **background LLM call** (autoDream consolidation + summary, autoSummarize compression) is written to the `llm_audit_logs` table: `tokens` / `duration` / `status` / `source` (which trigger produced it). Failed calls are recorded as `status=error` and never block the feature itself; `retentionDays` (default 90) purges expired rows at startup. Two new read-only APIs:
157
+
158
+ - `GET /api/dsh-mneme/semantic/llm-audit?page=&pageSize=&source=` — paginated query + filter by source
159
+ - `GET /api/dsh-mneme/semantic/llm-audit/stats?days=` — budget aggregated by source over the last N days (tokens / calls / failures)
160
+
161
+ > Read-only endpoints; like list/search/semantic, they remain open even after `apiToken` is set.
162
+
163
+ ## 🆕 Recent Release Highlights
164
+
165
+ | Version | Highlights |
166
+ |------|------|
167
+ | **v0.4.2** | autoSummarize custom model: the `summarizeProvider`/`summarizeModel` config options let you independently designate a lightweight model (e.g. qwen3.6-plus) for session summaries, saving main-model tokens; 473 tests green |
168
+ | **v0.4.0** | System-level Sleep Mode: idle-triggered four-phase deep maintenance (conflict resolution / archival demotion / pattern discovery / relation completion), interruptible, serially safe, fail-safe; tiered compression releases cold memories; 471 tests green |
169
+ | **v0.3.9** | Fixed 4 FAILs from the third-party audit: CAS made atomic within the same transaction, mirror degraded-receipt passthrough, per-type physical terminal-state convergence, strict integer validation for generation and stabilized concurrent initialization |
170
+ | **v0.3.8** | All 6 runtime-blocking findings from the audit peer re-review fixed: desired generation atomically incremented within the same transaction (the crash window no longer skips silently), sync failures not silent, atomic generation increments (zero loss across processes), per-type committed/failed/pending receipts, explicit unknown on read failure, generation upper-bound/negative CHECK |
171
+ | **v0.3.7** | Startup race fix: vector rebuild failing after a restart following manual edits to the md mirror (backfill moved to after init readiness + scheduleEmbed readiness gate) |
172
+ | **v0.3.6** | Mirror sync state machine: generation/applied_generation debt modeling, F-NEW-03 mirror health status, persistent dirty + recoverMirror at startup |
173
+ | **v0.3.0** | Memory gene: entity/attribute/relation three tables + timeline + entity search + autoDream supersedes |
174
+
175
+ ## 🗺️ Evolution Roadmap
176
+
177
+ | Version | Status | Theme | Description |
178
+ |------|------|------|------|
179
+ | v0.2.x | ✅ Done | Semantic enhancement + reflection updates | Local embedding/rerank/clustering, `failure_memories` failure tracking |
180
+ | v0.3.0 | ✅ Done | Memory gene | entities/attrs/relations three tables + timeline + entity search |
181
+ | v0.3.6–0.3.8 | ✅ Done | Mirror consistency + audit hardening | generation sync state machine, 6 audit-peer runtime-blocking fixes, 450 tests green |
182
+ | v0.3.9 | ✅ Done | Audit hardening A/B/D/F | compareAndUpdate same-transaction atomicity, degraded receipts, per-type physical terminal state, integer fail-closed, stable concurrent initialization |
183
+ | **v0.4.0** | ✅ Done | System-level Sleep Mode | Idle-triggered four-phase deep maintenance (conflict resolution / archival demotion / pattern discovery / relation completion), tiered compression, interruptible serial fail-safe; 471 tests green |
184
+ | **v0.4.2** | ✅ Done | autoSummarize custom model | `summarizeProvider`/`summarizeModel` config options, letting you independently designate a lightweight model (e.g. qwen3.6-plus) for session summaries and save main-model tokens; 473 tests green |
185
+ | **v0.4.3** | ✅ Done | autoDream large-memory fix | issue#9 B+A: `dreamMaxTokens` cap raised 32768→131072 + `dreamReasoningEffort`/`sleepReasoningEffort` reasoning toggles (`none` by default, main conversation unaffected); 478 tests green |
186
+ | **v0.4.4** | ✅ Done | autoDream decision coverage fix | issue#9 plan C: sliding window `dreamMaxSnapshotSize` (default 200, truncated by updated_at descending) + implicit keep `dreamImplicitKeep` (default true) + coverage floor `dreamMinExplicitCoverage` (default 50%) + fixed decision schema; 487 tests green |
187
+ | **v0.4.5** | ✅ Done | Epistemic trust + recall eval | Memory credibility grading `trustEpistemicWeighting` (observation>inferred>subjective: retrieval ranking favors high-credibility memories, injection tags `[verified]`, dream merge/conflict favors the more credible side; opt-in, off by default) + retrieval evaluation `evaluateRetrieval` persisted to `recall_evals` (`evalPersistTestResults` opt-in, off by default; production retrieval always goes through `recall_runs`, unconditionally isolated); 518 tests green |
188
+ | **v0.4.6** | ✅ Done | 8 fixes (vector pipeline + injection/quality/audit) | Vector pipeline fixes (embedSingle adaptation / `autoReindexOnBoot` backfill of existing data / `vector_meta` metadata) + injection semantic recall `hybridInject` + same-title append `content_history` + injection length caps (300 per item / 1500 per block) + memory quality filter `memoryQualityFilter` + LLM usage audit `llmAudit` (table + instrumentation + read-only APIs); 553 tests green |
189
+ | **v0.4.7** | ✅ Done | Idempotent schema migrations | When the same db is opened concurrently, the `PRAGMA table_info` check and ALTER are non-atomic and may repeat `ADD COLUMN`, failing with a duplicate column name; switched to an `addColumn` helper that swallows the race (try/catch), unifying all 12 migration sites |
190
+ | **v0.5.0+** | 🚀 Long-term | Self-evolving memory | Interest drift tracking + cross-workspace memory sharing (pending DSH support) |
191
+
192
+ > All new capabilities ship as **toggleable features** (enabled/disabled via configuration), conservatively on by default and never breaking existing behavior. The `failure_memories` table and the autoDream decision engine have already paved the way for future reflective growth.
193
+
194
+ ## 📦 Installation
195
+
196
+ ### Prerequisites
197
+
198
+ - [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH)
199
+ - Node 24+ (`node:sqlite`)
200
+
201
+ ### Installation Steps
202
+
203
+ #### Option 1: npm install (recommended)
204
+
205
+ dsh-mneme is a **bundle** (it declares a `dsh.bundle` manifest); installation activates it automatically, no manual configuration required:
206
+
207
+ ```bash
208
+ # 1. 安装插件(自动注册 bundle 层)
209
+ dsh plugin --profile web add @modusensus/dsh-mneme
210
+
211
+ # 2. 重启
212
+ dsh web
213
+ ```
214
+
215
+ > For custom configuration (thresholds, delays, etc.), override the defaults under `id: dsh-mneme` in `~/.dsh/profiles/web/cordis.patch.yml` (see the configuration table below).
216
+
217
+ #### Option 2: Install from source
218
+
219
+ ```bash
220
+ git clone https://github.com/modusensus/dsh-mneme.git
221
+ cd dsh-mneme
222
+ dsh plugin --profile web add .
223
+ dsh web
224
+ ```
225
+
226
+ #### Custom configuration (optional)
227
+
228
+ It works out of the box with the defaults. To adjust, override in `~/.dsh/profiles/web/cordis.patch.yml`:
229
+
230
+ ```yaml
231
+ - id: dsh-mneme
232
+ name: '@modusensus/dsh-mneme'
233
+ config:
234
+ memoryDir: ~/.dsh/memory
235
+ autoInject: true
236
+ autoSummarize: true
237
+ maxInjectedItems: 5
238
+ importanceThreshold: 3
239
+ autoDream: true
240
+ dreamThresholdCount: 10
241
+ dreamThresholdChars: 5000
242
+ dreamDelayMs: 2000
243
+ ```
244
+
245
+ ## ⚙️ Configuration
246
+
247
+ | Key | Default | Description |
248
+ |----|--------|------|
249
+ | `memoryDir` | `~/.dsh/memory` | Memory storage directory (SQLite + Markdown) |
250
+ | `autoInject` | `true` | Automatically inject memories at session start |
251
+ | `autoSummarize` | `true` | Automatically distill a summary at session end |
252
+ | `summarizeProvider` / `summarizeModel` | empty | LLM route override for summaries (empty = use the current session model); a lightweight model is recommended to save main-model tokens |
253
+ | `maxInjectedItems` | `5` | Maximum number of memories to inject |
254
+ | `importanceThreshold` | `3` | Minimum importance for injection (1-5) |
255
+ | `autoDream` | `true` | Automatic memory consolidation switch |
256
+ | `dreamThresholdCount` | `10` | Memory count threshold that triggers consolidation |
257
+ | `dreamThresholdChars` | `5000` | Total character threshold that triggers consolidation |
258
+ | `dreamDelayMs` | `2000` | Asynchronous consolidation delay (debounce) |
259
+ | `dreamProvider` / `dreamModel` | empty | LLM route fallback for dream (defaults to the agent's default model) |
260
+ | `dreamMaxTokens` | `4096` | Maximum tokens per dream LLM call (cap 131072; increase for large memory stores — see the tuning guide below) |
261
+ | `dreamReasoningEffort` | `none` | Reasoning-effort passthrough for the dream LLM: `low` / `medium` / `high` / `none` (`none` = omit the field and use the model default; set `low` when a reasoning model exhausts its budget on reasoning and produces an empty body) |
262
+ | `apiToken` | empty | Optional API auth token; once set, write operations and key endpoints require `Authorization: Bearer <apiToken>` |
263
+ | `embedProvider` | `openai` | Semantic backend: `openai` (default, v0.1-compatible) / `local` (ONNX offline) / `ollama` |
264
+ | `localEmbedModel` | `Xenova/bge-small-zh-v1.5` | Local ONNX embedding model |
265
+ | `localEmbedDimension` | `512` | Local embedding vector dimension |
266
+ | `localEmbedDevice` | `cpu` | Local inference device: `cpu` / `gpu` |
267
+ | `localEmbedBatchSize` | `8` | Local embedding batch size (1-64) |
268
+ | `ollamaBaseUrl` | `http://localhost:11434` | Ollama service address |
269
+ | `ollamaModel` | `nomic-embed-text` | Ollama embedding model |
270
+ | `embedModelCacheDir` | empty | Model cache directory (empty = user-level `~/.dsh/mneme/models`) |
271
+ | `embedModelMirror` | `https://hf-mirror.com` | Mirror source for model downloads |
272
+ | `vectorSearchTopK` | `20` | Top-K returned by vector search |
273
+ | `vectorSearchThreshold` | `0.65` | Vector search similarity threshold |
274
+ | `hybridSearchVectorWeight` | `0.6` | Vector weight in hybrid search |
275
+ | `hybridSearchKeywordWeight` | `0.4` | Keyword weight in hybrid search |
276
+ | `rerankEnabled` | `false` | Whether to enable rerank fine-ranking (the local onnxruntime model loads only when explicitly enabled) |
277
+ | `rerankProvider` | `none` | Rerank backend: `local` / `none` (default `none`) |
278
+ | `rerankModel` | `Xenova/bge-reranker-base` | Rerank cross-encoding model |
279
+ | `rerankBatchSize` | `8` | Rerank batch size |
280
+ | `rerankMaxCandidates` | `30` | Maximum number of rerank candidates |
281
+ | `rerankScoreThreshold` | `0.1` | Rerank score threshold (candidates below it are dropped) |
282
+ | `reflectionUpdateEnabled` | `true` | Master switch for `update` decisions |
283
+ | `reflectionFailureTracking` | `true` | Master switch for failure tracking |
284
+ | `reflectionUpdateMaxPerRun` | `2` | Maximum `update` decisions per consolidation run |
285
+ | `reflectionUpdateMinAgeHours` | `24` | Protection period for newly created memories (hours) |
286
+ | `entityExtractionEnabled` | `false` | Master switch for entity extraction (v0.3.0; always available at the storage layer) |
287
+ | `entityExtractionModel` | empty | Dedicated extraction model (empty = use the agent's default model) |
288
+ | `entityExtractionMaxEntities` | `10` | Maximum entities per extraction |
289
+ | `entityExtractionMaxAttrs` | `20` | Maximum attributes per entity |
290
+ | `entitySearchEnabled` | `true` | Switch for `entity:` / `attr:` prefix search |
291
+ | `trustEpistemicWeighting` | `false` | Memory credibility weighting (v0.4.5, opt-in, off by default): memories are graded by source as `observation` > `inferred` > `subjective`; when enabled, retrieval ranking favors high-credibility memories, injection tags observation entries `[verified]`, and dream merge/conflict favors the more credible side; when off, `epistemic_status` is only persisted on save and does not participate in behavior |
292
+ | `evalPersistTestResults` | `false` | Retrieval evaluation persistence (v0.4.5, opt-in, off by default): when enabled, `evaluateRetrieval` writes precision/recall/mrr snapshots into `recall_evals`; when off it only returns them to the caller without persisting. Production `searchMemories` auditing always goes through `recall_runs`, unconditionally never touching `recall_evals` |
293
+ | `autoReindexOnBoot` | `true` | When existing memories lack embeddings and vectors are configured, a delayed, rate-limited background backfill rebuild starts after boot (set to `false` for manual rebuild only) |
294
+ | `hybridInject` | `true` | Semantic-recall-first injection (v0.4.6, Bug4): when `injectCandidates` receives a non-empty query, it first recalls candidates via the vector index semantically, then fills in/deduplicates with rule-based filtering; empty query / no vectors falls back to the old logic |
295
+ | `memoryQualityFilter` | `{enabled:true, archiveThreshold:30, degradeThreshold:60, minContentLength:10}` | Memory quality filter (v0.4.6, on by default): heuristic 0-100 scoring before write; meta-memory vocabulary/self-reference/overly short/duplicate/near-duplicate content deduct points; ≥60 stored normally, 30-60 down-weighted (injection ranked by importance×quality/100), <30 archived and flagged `low_quality` (still recallable via explicit search, never auto-injected) |
296
+ | `llmAudit` | `{enabled:true, retentionDays:90}` | LLM usage audit (v0.4.6, on by default): every background LLM call (autoDream/autoSummarize) writes `llm_audit_logs` (tokens/duration/status/source); failures are recorded as error without blocking; read-only APIs `/api/dsh-mneme/semantic/llm-audit` + `/llm-audit/stats` |
297
+
298
+ > 🔐 **API security**: DSH has no built-in authentication and by default listens only on `127.0.0.1`. The plugin API is open by default (so the web panel works out of the box). For protection (e.g. when exposed to a LAN), set `apiToken` in the configuration: write operations (profile/rules/commands) and key endpoints (`vector-config`, `vector-reindex`) require `Authorization: Bearer <token>` (the frontend settings panel accepts the same token), while the read-only `list` / `search` / `semantic` endpoints remain open. The `apiKey` returned by `/api/dsh-mneme/vector-config` is masked (`sk-***…`), while the stored plaintext is kept for actual calls; the frontend sending back an empty or masked value means "do not change the key".
299
+
300
+ ## 🏗️ Architecture
301
+
302
+ ```
303
+ ┌─────────────────────────────────────────────────┐
304
+ │ 存储层:SQLite (archived/forgotten 状态) │
305
+ │ + Markdown 镜像(人工可编辑,双向同步) │
306
+ ├─────────────────────────────────────────────────┤
307
+ │ 服务层:saveWithDedupe / injectCandidates │
308
+ │ / mergeHumanEdits / onWrite 钩子 │
309
+ ├─────────────────────────────────────────────────┤
310
+ │ 模型接口:7 个工具 + 自动注入 + 会话摘要 │
311
+ ├─────────────────────────────────────────────────┤
312
+ │ autoDream:阈值调度 → LLM 决策清单 │
313
+ │ → 校验(fail-safe)→ 应用 → 摘要 │
314
+ ├─────────────────────────────────────────────────┤
315
+ │ Web 面板:设置面板内嵌 + 浏览/搜索(含向量) │
316
+ └─────────────────────────────────────────────────┘
317
+ ```
318
+
319
+ **Source layout**:
320
+
321
+ ```
322
+ src/
323
+ ├── store.js # SQLite 存储(CRUD、搜索、归档/遗忘、schema 迁移)
324
+ ├── mirror.js # Markdown 镜像(渲染/解析,人工优先)
325
+ ├── service.js # 领域逻辑(去重合并、注入筛选、写入钩子)
326
+ ├── config.js # schemastery 配置 schema
327
+ ├── tools.js # 7 个模型工具(defineTool)
328
+ ├── inject.js # systemPrompt.context 动态注入
329
+ ├── summarize.js # 会话结束 LLM 摘要
330
+ ├── dream.js # autoDream 调度 + runDream(LLM 决策 + 摘要)
331
+ ├── dream/decisions.js# 决策校验(fail-safe)+ 决策应用
332
+ ├── entities/extractor.js # 实体抽取器(v0.3.0:LLM JSON 抽取 + 去重 + fail-safe)
333
+ ├── embedding.js # OpenAI 兼容 embeddings 客户端 + 向量检索
334
+ ├── api.js # HTTP 路由(Web 面板数据通道)
335
+ └── index.js # 插件接线
336
+ lib/
337
+ ├── client.js # Web 面板(手写 ModuleLoader bundle)
338
+ └── *.js # src 的同步分发产物
339
+ test/ # 450 个 node:test 测试(含审计与三轴线压测不变量)
340
+ scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压测 · sync-lib.js 同步
341
+ ```
342
+
343
+ ## 🧪 Development
344
+
345
+ ```bash
346
+ cd dsh-mneme
347
+ npm install # 安装 peer 依赖(以 devDependencies 形式,用于本地测试)
348
+ npm test # 运行 450 个测试
349
+ npm run stress # 三轴线压测:长会话检索 / 冲突仲裁 / 多 Agent 并发(离线 mock LLM)
350
+ npm run sync # 把 src/ 同步到 lib/(发布时由 prepack 钩子自动执行)
351
+ ```
352
+
353
+ > The stress test (`npm run stress`) covers three axes: **long-session retrieval** (Recall@k, stale-residual rate), **conflict adjudication** (a replayable adjudication set: audit snapshot hash + receipt + idempotent replay), and **multi-Agent concurrency** (lost updates, duplicate merges, transaction/crash recovery). Every autoDream run writes to the `dream_runs` audit table (input snapshot digest + decision list + per-id disposition + receipt), so silent errors can be pinpointed even when the pass rate is high.
354
+
355
+ > `lib/` is the synced distribution artifact of `src/` (`npm run sync`); `lib/client.js` is the hand-written web panel source and is unaffected by the sync.
356
+
357
+ ## 📄 Design Documents
358
+
359
+ > Design documents live in `docs/` at the repository root; the links point there via the `../docs/` relative path (they resolve correctly on GitHub when opened from this directory).
360
+
361
+ - [Entity-Structured Memory Design](docs/ENTITIES.md)
362
+ - [Semantic Enhancement Architecture](docs/SEMANTIC.md)
363
+ - [Local Model Deployment Guide](docs/LOCAL_MODEL.md)
364
+ - [Upgrading from v0.1](docs/MIGRATION.md)
365
+
366
+ ## 📜 License
367
+
368
+ MIT