dsh-tdai-memory 0.2.7 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  **GitHub**: [Scorp1o117/dsh-tdai-memory](https://github.com/Scorp1o117/dsh-tdai-memory) · **npm**: [dsh-tdai-memory](https://www.npmjs.com/package/dsh-tdai-memory)
6
6
 
7
+ [![Enhancement Suite](https://img.shields.io/badge/part%20of-Enhancement%20Suite-3964fe)](https://github.com/Scorp1o117/dsh-enhancement-suite) [![npm](https://img.shields.io/npm/v/dsh-enhancement-suite)](https://www.npmjs.com/package/dsh-enhancement-suite)
8
+
9
+ Part of the [DeepSeek Harness Enhancement Suite](https://github.com/Scorp1o117/dsh-enhancement-suite) — Vision · Soul/Persona · Long-term Memory · Plugin Marketplace.
10
+
7
11
  A port of **TencentDB Agent Memory** (Tencent Cloud's open-source four-layer
8
12
  memory system, originally an OpenClaw plugin) into DeepSeek Harness.
9
13
 
@@ -79,6 +83,36 @@ tdai-memory:
79
83
  sendDimensions: false
80
84
  ```
81
85
 
86
+ ## Install
87
+
88
+ ```bash
89
+ dsh plugin --profile web add dsh-tdai-memory
90
+ ```
91
+
92
+ then mount it in `$DSH_HOME/profiles/web/cordis.patch.yml`:
93
+
94
+ ```yaml
95
+ - insert:
96
+ - id: tdai-memory
97
+ name: 'dsh-tdai-memory'
98
+ config: {} # keys can live in settings.yaml instead
99
+ ```
100
+
101
+ and restart `dsh web`. LLM/embedding API keys can be set in the Web UI
102
+ settings page (记忆 / Memory) or directly in `settings.yaml` under
103
+ `tdai-memory:`.
104
+
105
+ > **Note for users**
106
+ > - This plugin is a standard **profile bundle** (`dsh.bundle.patch`):
107
+ > `dsh plugin --profile web add dsh-tdai-memory` installs and mounts it in
108
+ > one step — no manual `cordis.patch.yml` edits needed.
109
+ > - The settings section needs the `dsh-host-apiproxy` namespace allowlist;
110
+ > the plugin patches it automatically on first start — **restart `dsh web`
111
+ > once more** and the section appears. A dsh update overwrites the patch;
112
+ > the next plugin start re-applies it.
113
+ > - Settings changes apply **after a restart** (TdaiCore is built at startup).
114
+ > - Tested against DSH `0.1.0-rc.6`.
115
+
82
116
  ## Known trade-offs
83
117
 
84
118
  - **Extraction model**: `mimo-v2.5` extracts correctly but takes 20-30s per
package/README.zh.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  **GitHub**: [Scorp1o117/dsh-tdai-memory](https://github.com/Scorp1o117/dsh-tdai-memory) · **npm**: [dsh-tdai-memory](https://www.npmjs.com/package/dsh-tdai-memory) · [English](README.md)
4
4
 
5
+ [![Enhancement Suite](https://img.shields.io/badge/part%20of-Enhancement%20Suite-3964fe)](https://github.com/Scorp1o117/dsh-enhancement-suite) [![npm](https://img.shields.io/npm/v/dsh-enhancement-suite)](https://www.npmjs.com/package/dsh-enhancement-suite)
6
+
7
+ 属于 [DeepSeek Harness Enhancement Suite](https://github.com/Scorp1o117/dsh-enhancement-suite) —— Vision · Soul/Persona · 长期记忆 · 插件市场。
8
+
5
9
  把 **TencentDB Agent Memory**(腾讯云开源的四层记忆系统,原为 OpenClaw 插件)移植进 DeepSeek Harness。
6
10
 
7
11
  ## 能力
package/client.js CHANGED
@@ -32,7 +32,7 @@ window.__ModuleLoader__.load({
32
32
  ".__tm_btn{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:8px;padding:6px 14px;font:inherit;font-size:13px;cursor:pointer}" +
33
33
  ".__tm_btn:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary)}" +
34
34
  ".__tm_btn:disabled{opacity:.5;cursor:default}" +
35
- ".__tm_btnPrimary{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-on-accent)}" +
35
+ ".__tm_btnPrimary{border-color:var(--dsw-alias-state-business-primary, #3964fe);background:var(--dsw-alias-state-business-primary, #3964fe);color:#fff}" +
36
36
  ".__tm_status{font-size:12px;color:var(--dsw-alias-label-tertiary)}" +
37
37
  ".__tm_error{font-size:12px;color:var(--dsw-alias-state-error-primary)}" +
38
38
  ".__tm_unavailable{font-size:13px;color:var(--dsw-alias-label-tertiary)}";
@@ -0,0 +1,8 @@
1
+ # dsh-tdai-memory — bundle patch layer
2
+ #
3
+ # Declares the plugin as a Cordis loader entry, making the package a standard
4
+ # profile bundle: `dsh plugin --profile <p> add dsh-tdai-memory` installs and
5
+ # mounts it without manual cordis.patch.yml edits.
6
+ - insert:
7
+ - id: tdai-memory
8
+ name: 'dsh-tdai-memory'
package/index.js CHANGED
@@ -74,6 +74,20 @@ const Config = z.object({
74
74
  toolsEnabled: z.boolean().default(true),
75
75
  });
76
76
 
77
+ /**
78
+ * Whether a derived message is real human input.
79
+ *
80
+ * A `"user"` role alone is not enough: DSH injects synthetic user-role
81
+ * context (system reminders, runtime context, skill catalogs, goal rounds,
82
+ * tool results, …) that must never be treated as user input. Real input is
83
+ * distinguished by `message.source.kind === "user"` (see dsh-llm Message
84
+ * types). Messages without a `source` (older harnesses) are treated as real
85
+ * input to stay compatible.
86
+ */
87
+ function isRealUserMessage(m) {
88
+ return m?.role === "user" && (m.source == null || m.source.kind === "user");
89
+ }
90
+
77
91
  /** Extract plain text from a dsh message content (block array or string). */
78
92
  function extractText(content) {
79
93
  if (typeof content === "string") return content.trim();
@@ -227,11 +241,19 @@ function apply(ctx, config) {
227
241
  async function captureTurn(session, startedAt) {
228
242
  if (!tdaiConfig?.capture.enabled) return;
229
243
  const derived = session.deriveMessages();
230
- const lastUserIdx = derived.map((m) => m.role).lastIndexOf("user");
244
+ // Start from the last REAL user message. DSH injects synthetic user-role
245
+ // context (system reminders, runtime context, skill catalogs, goal
246
+ // rounds, …) whose `source.kind` is not "user"; those must not pollute
247
+ // L0 memory (issue #1).
248
+ const lastUserIdx = derived.findLastIndex(isRealUserMessage);
231
249
  if (lastUserIdx < 0) return;
232
250
  const messages = derived
233
251
  .slice(lastUserIdx)
234
252
  .map((m) => {
253
+ // Keep assistant replies and real user input only; drop synthetic
254
+ // user-role messages (plugin context, tool results, …) injected
255
+ // after the last real user message.
256
+ if (m.role !== "assistant" && !isRealUserMessage(m)) return null;
235
257
  const text = extractText(m.content);
236
258
  if (!text) return null;
237
259
  return {
@@ -268,7 +290,7 @@ function apply(ctx, config) {
268
290
  agent.ctx.on("system-prompt/assemble", async (assembly, context) => {
269
291
  try {
270
292
  if (!tdaiConfig?.recall.enabled) return assembly;
271
- const lastUser = [...session.deriveMessages()].reverse().find((m) => m.role === "user");
293
+ const lastUser = [...session.deriveMessages()].reverse().find(isRealUserMessage);
272
294
  if (!lastUser) return assembly;
273
295
  const text = extractText(lastUser.content);
274
296
  if (!text) return assembly;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-tdai-memory",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "DeepSeek Harness 的 TencentDB Agent Memory 移植:L0 对话捕获 → L1 结构化记忆提取 → L2 场景/L3 画像,自动召回注入 + 记忆/对话搜索工具;复用现有 ~/.memory-tencentdb/memory-tdai 数据;附 Web UI 设置栏。",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -10,6 +10,9 @@
10
10
  "./package.json": "./package.json"
11
11
  },
12
12
  "dsh": {
13
+ "bundle": {
14
+ "patch": "./cordis.patch.yml"
15
+ },
13
16
  "client": {
14
17
  "platform": "web"
15
18
  }
@@ -19,6 +22,7 @@
19
22
  "index.js",
20
23
  "recall-inject.js",
21
24
  "client.js",
25
+ "cordis.patch.yml",
22
26
  "vendor",
23
27
  "README.md",
24
28
  "README.zh.md",
package/recall-inject.js CHANGED
@@ -38,7 +38,13 @@ function apply(ctx, config) {
38
38
  if (!agent) return assembly;
39
39
  const session = agent.session;
40
40
  if (!session) return assembly;
41
- const lastUser = [...session.deriveMessages()].reverse().find((m) => m.role === "user");
41
+ // Only real human input triggers recall. DSH injects synthetic
42
+ // user-role context (system reminders, runtime context, skill
43
+ // catalogs, …) whose source.kind is not "user"; recalling on those
44
+ // would pollute the prompt with irrelevant memories (issue #1).
45
+ const lastUser = [...session.deriveMessages()]
46
+ .reverse()
47
+ .find((m) => m.role === "user" && (m.source == null || m.source.kind === "user"));
42
48
  if (!lastUser) return assembly;
43
49
  const text = extractText(lastUser.content);
44
50
  if (!text || text.length < config.minUserTextChars) return assembly;