@modusensus/dsh-mneme 0.7.9 → 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 (155) hide show
  1. package/README.en.md +368 -0
  2. package/README.md +298 -167
  3. package/{dsh-mneme/cordis.patch.yml → cordis.patch.yml} +1 -0
  4. package/{dsh-mneme/lib → lib}/api.js +58 -284
  5. package/lib/client.js +2086 -0
  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/src → 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/src → 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 -3
  23. package/{dsh-mneme/scripts → scripts}/sync-lib.js +5 -10
  24. package/{dsh-mneme/src → src}/api.js +58 -284
  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/lib → 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/lib → 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 +22 -207
  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 -291
  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 -406
  70. package/dsh-mneme/LICENSE +0 -21
  71. package/dsh-mneme/README.md +0 -498
  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/client.js +0 -2050
  79. package/dsh-mneme/lib/dream/tag-extractor.js +0 -156
  80. package/dsh-mneme/lib/heat.js +0 -136
  81. package/dsh-mneme/lib/parser/tag.js +0 -59
  82. package/dsh-mneme/lib/parser/wiki-link.js +0 -38
  83. package/dsh-mneme/lib/search/tag-boost.js +0 -61
  84. package/dsh-mneme/lib/tools.js +0 -458
  85. package/dsh-mneme/package-lock.json +0 -1936
  86. package/dsh-mneme/package.json +0 -83
  87. package/dsh-mneme/scripts/check-sync.js +0 -42
  88. package/dsh-mneme/src/client.js +0 -2050
  89. package/dsh-mneme/src/dream/tag-extractor.js +0 -156
  90. package/dsh-mneme/src/heat.js +0 -136
  91. package/dsh-mneme/src/parser/tag.js +0 -59
  92. package/dsh-mneme/src/parser/wiki-link.js +0 -38
  93. package/dsh-mneme/src/search/tag-boost.js +0 -61
  94. package/dsh-mneme/src/tools.js +0 -458
  95. package/dsh-mneme/test/boundary-v0625.test.js +0 -82
  96. package/dsh-mneme/test/directory.test.js +0 -134
  97. package/dsh-mneme/test/heat.test.js +0 -148
  98. package/dsh-mneme/test/inject.test.js +0 -206
  99. package/dsh-mneme/test/layered-types-stats.test.js +0 -144
  100. package/dsh-mneme/test/lib-smoke.test.js +0 -109
  101. package/dsh-mneme/test/normalize-decisions.test.js +0 -120
  102. package/dsh-mneme/test/provenance.test.js +0 -103
  103. package/dsh-mneme/test/recall-runs.test.js +0 -93
  104. package/dsh-mneme/test/sleep-heat.test.js +0 -112
  105. package/dsh-mneme/test/tag-boost.test.js +0 -125
  106. package/dsh-mneme/test/tag.test.js +0 -426
  107. package/dsh-mneme/test/tools.test.js +0 -674
  108. package/dsh-mneme/test/updated-at-semantics.test.js +0 -113
  109. package/dsh-mneme/test/wiki-link.test.js +0 -332
  110. package//346/250/252/345/271/205.png +0 -0
  111. /package/{dsh-mneme/lib → lib}/commands.js +0 -0
  112. /package/{dsh-mneme/lib → lib}/dream/clustering.js +0 -0
  113. /package/{dsh-mneme/lib → lib}/embedding.js +0 -0
  114. /package/{dsh-mneme/lib → lib}/entities/extractor.js +0 -0
  115. /package/{dsh-mneme/lib → lib}/local-embedder.js +0 -0
  116. /package/{dsh-mneme/lib → lib}/search/adaptive.js +0 -0
  117. /package/{dsh-mneme/lib → lib}/search/bm25.js +0 -0
  118. /package/{dsh-mneme/lib → lib}/vector-index.js +0 -0
  119. /package/{dsh-mneme/scripts → scripts}/benchmark-embed.js +0 -0
  120. /package/{dsh-mneme/scripts → scripts}/benchmark-recall.js +0 -0
  121. /package/{dsh-mneme/scripts → scripts}/benchmark-rerank.js +0 -0
  122. /package/{dsh-mneme/scripts → scripts}/stress-dsh.js +0 -0
  123. /package/{dsh-mneme/src → src}/commands.js +0 -0
  124. /package/{dsh-mneme/src → src}/dream/clustering.js +0 -0
  125. /package/{dsh-mneme/src → src}/embedding.js +0 -0
  126. /package/{dsh-mneme/src → src}/entities/extractor.js +0 -0
  127. /package/{dsh-mneme/src → src}/local-embedder.js +0 -0
  128. /package/{dsh-mneme/src → src}/search/adaptive.js +0 -0
  129. /package/{dsh-mneme/src → src}/search/bm25.js +0 -0
  130. /package/{dsh-mneme/src → src}/vector-index.js +0 -0
  131. /package/{dsh-mneme/test → test}/audit.test.js +0 -0
  132. /package/{dsh-mneme/test → test}/benchmark.test.js +0 -0
  133. /package/{dsh-mneme/test → test}/clustering.test.js +0 -0
  134. /package/{dsh-mneme/test → test}/commands.test.js +0 -0
  135. /package/{dsh-mneme/test → test}/conflict-freeze.test.js +0 -0
  136. /package/{dsh-mneme/test → test}/entities.test.js +0 -0
  137. /package/{dsh-mneme/test → test}/epistemic.test.js +0 -0
  138. /package/{dsh-mneme/test → test}/fnew-0112.test.js +0 -0
  139. /package/{dsh-mneme/test → test}/fnew-03.test.js +0 -0
  140. /package/{dsh-mneme/test → test}/helpers/dream-mock.js +0 -0
  141. /package/{dsh-mneme/test → test}/local-embedder.test.js +0 -0
  142. /package/{dsh-mneme/test → test}/mirror-dirty.test.js +0 -0
  143. /package/{dsh-mneme/test → test}/mirror-edit-digest.test.js +0 -0
  144. /package/{dsh-mneme/test → test}/mirror-generation.test.js +0 -0
  145. /package/{dsh-mneme/test → test}/mirror.test.js +0 -0
  146. /package/{dsh-mneme/test → test}/peer-blockers.test.js +0 -0
  147. /package/{dsh-mneme/test → test}/policy-epoch.test.js +0 -0
  148. /package/{dsh-mneme/test → test}/quality-filter.test.js +0 -0
  149. /package/{dsh-mneme/test → test}/recall-evals.test.js +0 -0
  150. /package/{dsh-mneme/test → test}/receipt-chain.test.js +0 -0
  151. /package/{dsh-mneme/test → test}/reflection.test.js +0 -0
  152. /package/{dsh-mneme/test → test}/search-fusion.test.js +0 -0
  153. /package/{dsh-mneme/test → test}/semantic.test.js +0 -0
  154. /package/{dsh-mneme/test → test}/stress.test.js +0 -0
  155. /package/{dsh-mneme/test → test}/vector-index.test.js +0 -0
@@ -8,7 +8,10 @@ import { createHotMemory } from "./hot-memory.js";
8
8
  // falls back to the legacy rule-based pick, never breaking the render.
9
9
  function lastUserQuery(ctx) {
10
10
  try {
11
- const events = ctx?.agent?.session?.snapshotEvents?.() ?? ctx?.agent?.session?.events;
11
+ const session = ctx?.agent?.session;
12
+ // DSH ≥0.1.2-rc only exposes events via snapshotEvents(); older builds
13
+ // still have the .events property, so fall back to it.
14
+ const events = session?.snapshotEvents?.() ?? session?.events;
12
15
  if (!Array.isArray(events) || events.length === 0) return "";
13
16
  for (let i = events.length - 1; i >= 0; i--) {
14
17
  const event = events[i];
@@ -34,7 +37,8 @@ function lastUserQuery(ctx) {
34
37
  // returns [] on any failure, and the hot block simply does not render.
35
38
  function extractRounds(ctx, maxRounds) {
36
39
  try {
37
- const events = ctx?.agent?.session?.snapshotEvents?.() ?? ctx?.agent?.session?.events;
40
+ const session = ctx?.agent?.session;
41
+ const events = session?.snapshotEvents?.() ?? session?.events;
38
42
  if (!Array.isArray(events) || events.length === 0) return [];
39
43
  const rounds = [];
40
44
  let pendingQuery = null;
@@ -75,49 +79,6 @@ export function createInjector(ctx, service, settings, config) {
75
79
  const maxItems = config.maxInjectedItems ?? 5;
76
80
  const threshold = config.importanceThreshold ?? 3;
77
81
 
78
- // Prompt-variable escaping (issue #40): DSH's interpolate() treats `{{name}}`
79
- // as a prompt variable and strictly validates the name against
80
- // /^[a-z][a-z0-9_]*$/ — memory/profile content carrying legal template syntax
81
- // (Obsidian-style `{{hl|}}`, `{{挖空}}`, `{{关键词}}`) would hit an illegal
82
- // variable name and throw, crashing the whole turn. At the injection boundary
83
- // we escape every run of 2+ consecutive braces, inserting a `\` between each
84
- // pair, so no `{{`/`}}` substring survives into the prompt: `{{a}}` → `{\{a\}\}`,
85
- // and odd runs like `{{{a}}}` (which pair-wise escaping would leave with a
86
- // literal `{{`) are handled too. The text keeps its readable template form,
87
- // the transform is idempotent (escaped braces are single + `\`, never two
88
- // adjacent), and single braces pass through untouched — interpolate only
89
- // scans `{{`. Off via config.escapePromptVariables=false (default true).
90
- function escapePromptVars(text) {
91
- if (config.escapePromptVariables === false) return String(text);
92
- return String(text).replace(/[{}]{2,}/g, (run) => run.split("").join("\\"));
93
- }
94
-
95
- // Time-prefix injection (issue #34): opt-in, off by default. When enabled the
96
- // current date/time is injected once per conversation — at the first prompt
97
- // assembly of a new session — so the model can sense what time/day it is.
98
- // A per-session latch means later assemblies in the same session never
99
- // re-inject; a bare render ctx (no session id) falls back to once per
100
- // injector lifetime.
101
- const WEEKDAYS = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
102
- let timePrefixSession = null;
103
-
104
- function renderTimePrefix(ctx) {
105
- if (config.injectTimePrefix !== true) return "";
106
- const sessionId = ctx?.agent?.session?.id;
107
- if (sessionId === undefined) {
108
- if (timePrefixSession !== null) return "";
109
- timePrefixSession = true;
110
- } else {
111
- if (sessionId === timePrefixSession) return "";
112
- timePrefixSession = sessionId;
113
- }
114
- const now = new Date();
115
- const pad = (n) => String(n).padStart(2, "0");
116
- const date = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
117
- const time = `${pad(now.getHours())}:${pad(now.getMinutes())}`;
118
- return `[当前时间: ${date} ${WEEKDAYS[now.getDay()]} ${time}]`;
119
- }
120
-
121
82
  // Bug6: bound the injected memory block. Each entry's content is truncated to
122
83
  // MAX_CONTENT chars (trailing `…`); the whole block gets a MAX_BLOCK budget
123
84
  // and an entry that would exceed it collapses to its title only, so a long
@@ -151,7 +112,7 @@ export function createInjector(ctx, service, settings, config) {
151
112
  for (const r of rounds) hot.add(r);
152
113
  const body = hot.getContext();
153
114
  if (!body) return "";
154
- return escapePromptVars(`[短期上下文] 最近对话(共 ${rounds.length} 轮):\n${body}`);
115
+ return `[短期上下文] 最近对话(共 ${rounds.length} 轮):\n${body}`;
155
116
  }
156
117
 
157
118
  function render(candidates) {
@@ -175,7 +136,7 @@ export function createInjector(ctx, service, settings, config) {
175
136
  lines.push(`- [${m.type}] ${verified}${title}`);
176
137
  }
177
138
  }
178
- return escapePromptVars(lines.join("\n"));
139
+ return lines.join("\n");
179
140
  }
180
141
 
181
142
  // Bug4: the system-prompt render is synchronous, so the semantic query vector
@@ -209,7 +170,7 @@ export function createInjector(ctx, service, settings, config) {
209
170
  const lines = ["[用户设置] 来自 dsh-mneme 的用户画像与规则:"];
210
171
  if (profile) lines.push(`- 用户画像:${profile}`);
211
172
  for (const rule of rules) lines.push(`- 规则:${rule}`);
212
- return escapePromptVars(lines.join("\n"));
173
+ return lines.join("\n");
213
174
  }
214
175
 
215
176
  const disposers = [
@@ -231,11 +192,8 @@ export function createInjector(ctx, service, settings, config) {
231
192
  // separate context) keeps the prompt assembly stable at two blocks.
232
193
  const hotText = renderHotContext(ctx);
233
194
  const body = render(candidates);
234
- let out = !hotText ? body : (body ? `${hotText}\n\n${body}` : hotText);
235
- // Time prefix (issue #34): leads the injection block once per session.
236
- const timePrefix = renderTimePrefix(ctx);
237
- if (!timePrefix) return out;
238
- return out ? `${timePrefix}\n\n${out}` : timePrefix;
195
+ if (!hotText) return body;
196
+ return body ? `${hotText}\n\n${body}` : hotText;
239
197
  }
240
198
  }),
241
199
  ctx.systemPrompt.context({
@@ -7,9 +7,7 @@ export const TYPE_FILE = {
7
7
  project: "projects.md",
8
8
  decision: "decisions.md",
9
9
  history: "history.md",
10
- summary: "summary.md",
11
- user: "user.md",
12
- fact: "facts.md"
10
+ summary: "summary.md"
13
11
  };
14
12
 
15
13
  const ESCAPE = /([\\`*_[\]{}()#+.!|>~-])/g;
@@ -33,15 +31,6 @@ function renderMemory(m) {
33
31
  .digest("hex");
34
32
  const lines = [];
35
33
  lines.push(`## ${esc(m.title)}`);
36
- // v0.6.2 tag line: entity_attrs-backed tags (attached by the service as
37
- // `entityTags`) rendered as `#tag` space-separated under the title. No tags
38
- // → no line. Legacy `- **标签**:` metadata below keeps the memories.tags
39
- // column (still written by save/update) readable.
40
- const entityTags = Array.isArray(m.entityTags) ? m.entityTags : [];
41
- if (entityTags.length) {
42
- lines.push("");
43
- lines.push(entityTags.map((t) => `#${esc(t)}`).join(" "));
44
- }
45
34
  lines.push("");
46
35
  lines.push(`- **ID**: \`${m.id}\``);
47
36
  lines.push(`- **类型**: ${m.type}`);
@@ -34,9 +34,7 @@ const TYPE_LABELS = {
34
34
  decision: ["decision", "决策", "决定"],
35
35
  history: ["history", "历史", "事件"],
36
36
  summary: ["summary", "总结", "摘要", "总览"],
37
- pattern: ["pattern", "模式", "规律"],
38
- user: ["user", "用户"],
39
- fact: ["fact", "事实", "原子事实"]
37
+ pattern: ["pattern", "模式", "规律"]
40
38
  };
41
39
 
42
40
  /** Normalized bigram-overlap similarity in [0,1]; 0 for tiny/empty inputs. */
@@ -21,10 +21,7 @@ function modelHash(model) {
21
21
 
22
22
  /** Lazy default pipeline factory: dynamic import keeps module load cheap. */
23
23
  async function defaultPipelineLoader(task, model, options) {
24
- const { env, pipeline } = await import("@huggingface/transformers");
25
- // issue #13: mirror cache_dir onto env.cacheDir so the tokenizer pre-check
26
- // resolves locally too (same fix as local-embedder.js).
27
- if (options?.cache_dir) env.cacheDir = options.cache_dir;
24
+ const { pipeline } = await import("@huggingface/transformers");
28
25
  return pipeline(task, model, options);
29
26
  }
30
27