dsh-tdai-memory 0.2.7 → 0.2.8
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 +29 -0
- package/client.js +1 -1
- package/index.js +24 -2
- package/package.json +1 -1
- package/recall-inject.js +7 -1
package/README.md
CHANGED
|
@@ -79,6 +79,35 @@ tdai-memory:
|
|
|
79
79
|
sendDimensions: false
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
+
## Install
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
dsh plugin --profile web add dsh-tdai-memory
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
then mount it in `$DSH_HOME/profiles/web/cordis.patch.yml`:
|
|
89
|
+
|
|
90
|
+
```yaml
|
|
91
|
+
- insert:
|
|
92
|
+
- id: tdai-memory
|
|
93
|
+
name: 'dsh-tdai-memory'
|
|
94
|
+
config: {} # keys can live in settings.yaml instead
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
and restart `dsh web`. LLM/embedding API keys can be set in the Web UI
|
|
98
|
+
settings page (记忆 / Memory) or directly in `settings.yaml` under
|
|
99
|
+
`tdai-memory:`.
|
|
100
|
+
|
|
101
|
+
> **Note for users**
|
|
102
|
+
> - `dsh plugin` prints "declares no dsh.bundle — installed as a plain
|
|
103
|
+
> dependency" — **expected**: this plugin mounts via `cordis.patch.yml`.
|
|
104
|
+
> - The settings section needs the `dsh-host-apiproxy` namespace allowlist;
|
|
105
|
+
> the plugin patches it automatically on first start — **restart `dsh web`
|
|
106
|
+
> once more** and the section appears. A dsh update overwrites the patch;
|
|
107
|
+
> the next plugin start re-applies it.
|
|
108
|
+
> - Settings changes apply **after a restart** (TdaiCore is built at startup).
|
|
109
|
+
> - Tested against DSH `0.1.0-rc.6`.
|
|
110
|
+
|
|
82
111
|
## Known trade-offs
|
|
83
112
|
|
|
84
113
|
- **Extraction model**: `mimo-v2.5` extracts correctly but takes 20-30s per
|
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
|
|
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)}";
|
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
|
-
|
|
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(
|
|
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.
|
|
3
|
+
"version": "0.2.8",
|
|
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",
|
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
|
-
|
|
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;
|