dsh-tdai-memory 0.3.2 → 0.3.4

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 (67) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +15 -19
  3. package/README.zh.md +7 -1
  4. package/THIRD-PARTY-NOTICES.md +20 -20
  5. package/client.js +2 -2
  6. package/cordis.patch.yml +8 -8
  7. package/index.js +13 -22
  8. package/package.json +94 -78
  9. package/recall-inject.js +86 -86
  10. package/vendor/tdai/adapters/index.js +15 -15
  11. package/vendor/tdai/adapters/openclaw/host-adapter.js +83 -83
  12. package/vendor/tdai/adapters/openclaw/index.js +5 -5
  13. package/vendor/tdai/adapters/openclaw/llm-runner.js +69 -69
  14. package/vendor/tdai/adapters/standalone/host-adapter.js +58 -58
  15. package/vendor/tdai/adapters/standalone/index.js +5 -5
  16. package/vendor/tdai/core/conversation/l0-recorder.js +420 -420
  17. package/vendor/tdai/core/hooks/auto-capture.js +236 -236
  18. package/vendor/tdai/core/hooks/auto-recall.js +640 -640
  19. package/vendor/tdai/core/index.js +8 -8
  20. package/vendor/tdai/core/persona/persona-generator.js +184 -184
  21. package/vendor/tdai/core/persona/persona-trigger.js +94 -94
  22. package/vendor/tdai/core/profile/profile-sync.js +200 -200
  23. package/vendor/tdai/core/prompts/l1-dedup.js +72 -72
  24. package/vendor/tdai/core/prompts/l1-extraction.js +34 -34
  25. package/vendor/tdai/core/prompts/persona-generation.js +35 -35
  26. package/vendor/tdai/core/prompts/scene-extraction.js +45 -45
  27. package/vendor/tdai/core/record/l1-dedup.js +318 -318
  28. package/vendor/tdai/core/record/l1-extractor.js +379 -379
  29. package/vendor/tdai/core/record/l1-reader.js +178 -178
  30. package/vendor/tdai/core/record/l1-writer.js +141 -141
  31. package/vendor/tdai/core/report/reporter.js +86 -86
  32. package/vendor/tdai/core/scene/filename-normalizer.js +161 -161
  33. package/vendor/tdai/core/scene/scene-extractor.js +410 -410
  34. package/vendor/tdai/core/scene/scene-format.js +53 -53
  35. package/vendor/tdai/core/scene/scene-index.js +82 -82
  36. package/vendor/tdai/core/scene/scene-navigation.js +57 -57
  37. package/vendor/tdai/core/seed/input.js +404 -404
  38. package/vendor/tdai/core/seed/types.js +9 -9
  39. package/vendor/tdai/core/store/bm25-client.js +117 -117
  40. package/vendor/tdai/core/store/bm25-local.js +68 -68
  41. package/vendor/tdai/core/store/embedding.js +632 -632
  42. package/vendor/tdai/core/store/factory.js +95 -95
  43. package/vendor/tdai/core/store/search-utils.js +54 -54
  44. package/vendor/tdai/core/store/sqlite.js +1632 -1632
  45. package/vendor/tdai/core/store/tcvdb-client.js +221 -221
  46. package/vendor/tdai/core/store/tcvdb.js +1047 -1047
  47. package/vendor/tdai/core/store/types.js +17 -17
  48. package/vendor/tdai/core/tools/conversation-search.js +199 -199
  49. package/vendor/tdai/core/tools/memory-search.js +207 -207
  50. package/vendor/tdai/core/types.js +12 -12
  51. package/vendor/tdai/utils/backup.js +189 -189
  52. package/vendor/tdai/utils/checkpoint.js +360 -360
  53. package/vendor/tdai/utils/clean-context-runner.js +472 -472
  54. package/vendor/tdai/utils/ensure-hook-policy.js +213 -213
  55. package/vendor/tdai/utils/env.js +13 -13
  56. package/vendor/tdai/utils/managed-timer.js +127 -127
  57. package/vendor/tdai/utils/manifest.js +91 -91
  58. package/vendor/tdai/utils/memory-cleaner.js +300 -300
  59. package/vendor/tdai/utils/no-think-fetch.js +109 -109
  60. package/vendor/tdai/utils/openclaw-state-dir.js +26 -26
  61. package/vendor/tdai/utils/pipeline-factory.js +517 -517
  62. package/vendor/tdai/utils/pipeline-manager.js +892 -892
  63. package/vendor/tdai/utils/sanitize.js +360 -360
  64. package/vendor/tdai/utils/serial-queue.js +103 -103
  65. package/vendor/tdai/utils/session-filter.js +88 -88
  66. package/vendor/tdai/utils/text-utils.js +29 -29
  67. package/vendor/tdai/utils/time.js +252 -252
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Scorp1o117
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Scorp1o117
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -11,7 +11,13 @@ Part of the [DeepSeek Harness Enhancement Suite](https://github.com/Scorp1o117/d
11
11
  A port of **TencentDB Agent Memory** (Tencent Cloud's open-source four-layer
12
12
  memory system, originally an OpenClaw plugin) into DeepSeek Harness.
13
13
 
14
- ## Features
14
+ ## Compatibility (v0.3.4)
15
+
16
+ Targets DSH `0.1.7-rc.1` (`next`); npm `latest` is `0.1.5-rc.3`.
17
+ Settings now live in the Profile patch, and the browser uses `configForms`.
18
+ Older hosts require an older plugin release; alpha builds remain `unknown`.
19
+
20
+ ## Features
15
21
 
16
22
  - **L0 conversation capture**: every turn (turn end, request boundary) is
17
23
  written to raw conversation storage (JSONL + SQLite + FTS + vectors)
@@ -50,23 +56,14 @@ Hard-won wiring details:
50
56
 
51
57
  ## Configuration (profile patch + settings)
52
58
 
53
- Configuration is **settings-namespace driven**: the profile patch is the base
54
- layer, and the `tdai-memory:` section of `$DSH_HOME/settings.yaml` overrides it
55
- (LLM/embedding keys live in settings.yaml). The **Web UI Settings → 记忆**
59
+ Configuration is stored in the `tdai-memory` entry of the active Profile patch.
60
+ On first launch, DSH imports the old `$DSH_HOME/settings.yaml` values into that
61
+ entry. The **Web UI Settings → 记忆**
56
62
  section edits every field (v0.2.0, write-only keys); TdaiCore is built at
57
63
  startup, so changes apply **after a restart**.
58
64
 
59
- ```yaml
60
- # $DSH_HOME/settings.yaml
61
- tdai-memory:
62
- llm:
63
- apiKey: 'sk-...'
64
- embedding:
65
- apiKey: 'local-no-key'
66
- ```
67
-
68
- ```yaml
69
- # profile patch (base layer)
65
+ ```yaml
66
+ # $DSH_HOME/profiles/web/cordis.patch.yml
70
67
  - id: tdai-memory
71
68
  name: 'dsh-tdai-memory'
72
69
  config:
@@ -97,12 +94,11 @@ then mount it in `$DSH_HOME/profiles/web/cordis.patch.yml`:
97
94
  - insert:
98
95
  - id: tdai-memory
99
96
  name: 'dsh-tdai-memory'
100
- config: {} # keys can live in settings.yaml instead
97
+ config: {} # fill through Settings → 记忆
101
98
  ```
102
99
 
103
- and restart `dsh web`. LLM/embedding API keys can be set in the Web UI
104
- settings page (记忆 / Memory) or directly in `settings.yaml` under
105
- `tdai-memory:`.
100
+ and restart `dsh web`. LLM/embedding API keys can be set in the Web UI
101
+ settings page (记忆 / Memory) or in the `tdai-memory` Profile patch entry.
106
102
 
107
103
  > **Note for users**
108
104
  > - This plugin is a standard **profile bundle** (`dsh.bundle.patch`):
package/README.zh.md CHANGED
@@ -8,7 +8,13 @@
8
8
 
9
9
  把 **TencentDB Agent Memory**(腾讯云开源的四层记忆系统,原为 OpenClaw 插件)移植进 DeepSeek Harness。
10
10
 
11
- ## 能力
11
+ ## 兼容性(v0.3.4)
12
+
13
+ 适配 DSH `0.1.7-rc.1`(npm `next`);npm `latest` 是 `0.1.5-rc.3`。
14
+ 设置保存在当前 Profile patch,Web 端使用 `configForms`。
15
+ 旧宿主请使用插件旧版;alpha 构建仍标记 `unknown`。
16
+
17
+ ## 能力
12
18
 
13
19
  - **L0 对话捕获**:每轮对话(turn 结束、请求边界)自动写入原始对话(JSONL + SQLite + FTS + 向量)
14
20
  - **L1 结构化记忆**:后台管线用 LLM 从对话中提取事实/偏好/事件(persona / episodic / instruction),写入 `records/` + SQLite + FTS + 向量
@@ -1,20 +1,20 @@
1
- # Third-party notices
2
-
3
- ## TencentDB Agent Memory core (vendored in `vendor/tdai`)
4
-
5
- `vendor/tdai` is a TypeScript-compiled copy of the host-neutral core of
6
- [TencentCloud/TencentDB-Agent-Memory](https://github.com/TencentCloud/TencentDB-Agent-Memory)
7
- (`tdai-memory-openclaw-plugin`, npm: `@tencentdb-agent-memory/memory-tencentdb`),
8
- compiled with `tsc -p dsh-tsconfig.json` (see the upstream repo for source).
9
- Its runtime dependencies are declared in this package's `dependencies`.
10
-
11
- MIT License — Copyright (c) 2026 TencentCloud
12
-
13
- ## Runtime dependencies
14
-
15
- - `ai` / `@ai-sdk/openai` — Vercel AI SDK (Apache-2.0)
16
- - `@node-rs/jieba` — Rust jieba bindings (MIT)
17
- - `sqlite-vec` — vector search extension for SQLite (Apache-2.0 / MIT)
18
- - `json5` — JSON5 parser (MIT)
19
- - `undici` — HTTP client (MIT)
20
- - `@tencentdb-agent-memory/tcvdb-text` — TencentDB text utilities (MIT)
1
+ # Third-party notices
2
+
3
+ ## TencentDB Agent Memory core (vendored in `vendor/tdai`)
4
+
5
+ `vendor/tdai` is a TypeScript-compiled copy of the host-neutral core of
6
+ [TencentCloud/TencentDB-Agent-Memory](https://github.com/TencentCloud/TencentDB-Agent-Memory)
7
+ (`tdai-memory-openclaw-plugin`, npm: `@tencentdb-agent-memory/memory-tencentdb`),
8
+ compiled with `tsc -p dsh-tsconfig.json` (see the upstream repo for source).
9
+ Its runtime dependencies are declared in this package's `dependencies`.
10
+
11
+ MIT License — Copyright (c) 2026 TencentCloud
12
+
13
+ ## Runtime dependencies
14
+
15
+ - `ai` / `@ai-sdk/openai` — Vercel AI SDK (Apache-2.0)
16
+ - `@node-rs/jieba` — Rust jieba bindings (MIT)
17
+ - `sqlite-vec` — vector search extension for SQLite (Apache-2.0 / MIT)
18
+ - `json5` — JSON5 parser (MIT)
19
+ - `undici` — HTTP client (MIT)
20
+ - `@tencentdb-agent-memory/tcvdb-text` — TencentDB text utilities (MIT)
package/client.js CHANGED
@@ -47,7 +47,7 @@ window.__ModuleLoader__.load({
47
47
 
48
48
  // ── locale ────────────────────────────────────────────────────────────
49
49
  var NS = "tdaiMemory";
50
- var inject = ["slots", "locale", "settingsScope", "connection"];
50
+ var inject = ["slots", "locale", "configForms", "connection"];
51
51
  var zh = {
52
52
  nav: "记忆",
53
53
  intro: "TDAI 记忆配置:L0 捕获 → L1 结构化提取 → 召回注入。密钥只写不读。TdaiCore 在启动时构建,修改后需重启生效。",
@@ -345,7 +345,7 @@ window.__ModuleLoader__.load({
345
345
  function apply(ctx) {
346
346
  var t = ctx.locale.bind(NS);
347
347
  ctx.effect(function () { return ctx.locale.register(NS, { zh: zh, en: en }); }, "dsh-tdai-memory: dictionaries");
348
- var scope = ctx.settingsScope.bind({ namespace: "tdai-memory" });
348
+ var scope = ctx.configForms.get("tdai-memory");
349
349
  var api = ctx.connection.api;
350
350
  ctx.slots.inject("settings.section", function () {
351
351
  return ctx.slots.register({
package/cordis.patch.yml CHANGED
@@ -1,8 +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'
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
@@ -37,7 +37,7 @@ const Config = z.object({
37
37
  /** TDAI data directory; default: ~/.memory-tencentdb/memory-tdai. */
38
38
  dataDir: z.string().default(""),
39
39
  /** LLM used for L1/L2/L3 extraction (OpenAI-compatible). Falls back to TDAI_LLM_* env. */
40
- llm: z.object({
40
+ llm: z.object({
41
41
  baseUrl: z.string().default(""),
42
42
  apiKey: z.string().default("").role("secret"),
43
43
  model: z.string().default(""),
@@ -52,34 +52,34 @@ const Config = z.object({
52
52
  sessionHeaderName: z.string().default("x-opencode-session"),
53
53
  /** Fixed session id for LLM requests; empty = persistent auto id. */
54
54
  sessionId: z.string().default(""),
55
- }),
55
+ }).default({}),
56
56
  /** Embedding endpoint (OpenAI-compatible /v1/embeddings). */
57
- embedding: z.object({
57
+ embedding: z.object({
58
58
  baseUrl: z.string().default("http://127.0.0.1:8088/v1"),
59
59
  apiKey: z.string().default("").role("secret"),
60
60
  model: z.string().default("Qwen3-Embedding-0.6B"),
61
61
  dimensions: z.number().default(1024),
62
62
  sendDimensions: z.boolean().default(false),
63
- }),
63
+ }).default({}),
64
64
  /** Capture conversations into L0. */
65
65
  captureEnabled: z.boolean().default(true),
66
66
  /** L1 extraction pipeline (facts from conversations). */
67
- extraction: z.object({
67
+ extraction: z.object({
68
68
  enabled: z.boolean().default(true),
69
69
  /** Conflict detection before storing; extra LLM call, disable if flaky.
70
70
  * Off by default: dedup LLM output parsing is flaky (README matches). */
71
71
  enableDedup: z.boolean().default(false),
72
- }),
72
+ }).default({}),
73
73
  /** Recall injection settings. */
74
- recall: z.object({
74
+ recall: z.object({
75
75
  enabled: z.boolean().default(true),
76
76
  maxResults: z.number().default(5),
77
77
  scoreThreshold: z.number().default(0.3),
78
78
  timeoutMs: z.number().default(3000),
79
- }),
79
+ }).default({}),
80
80
  /** Register the two search tools. */
81
81
  toolsEnabled: z.boolean().default(true),
82
- });
82
+ }).volatile();
83
83
 
84
84
  /**
85
85
  * Whether a derived message is real human input.
@@ -390,18 +390,9 @@ function apply(ctx, config) {
390
390
  // `installSettingsSection` export (the provider now lives at ctx.settings).
391
391
  // Inline the same logic via ctx.inject(["settings"]) — works on both
392
392
  // 0.1.1 (module export wrapper) and 0.1.2 (ctx.settings) hosts.
393
- ctx.inject(["settings"], (sctx) => {
394
- const scope = sctx.settings.register(NS, Config, { base: config });
395
- const fire = () => {
396
- builtOnce = true;
397
- void build(scope.get());
398
- };
399
- sctx.effect(() => () => {});
400
- fire();
401
- scope.watch(() => {
402
- ctx.logger.warn("[tdai-memory] settings updated; restart to apply (TdaiCore is built at startup)");
403
- });
404
- });
393
+ ctx.on("settings/document-updated", (id) => {
394
+ if (id === NS) ctx.logger.warn("[tdai-memory] settings updated; restart to apply (TdaiCore is built at startup)");
395
+ });
405
396
 
406
397
  // Fallback when no settings service ever mounts: build from the entry
407
398
  // config. One-shot — if the settings mount arrives later, its build
@@ -410,7 +401,7 @@ function apply(ctx, config) {
410
401
  setTimeout(() => {
411
402
  if (!builtOnce) {
412
403
  builtOnce = true;
413
- void build(config);
404
+ void build(typeof config.get === "function" ? config.get() : config);
414
405
  }
415
406
  }, 500);
416
407
 
package/package.json CHANGED
@@ -1,78 +1,94 @@
1
- {
2
- "name": "dsh-tdai-memory",
3
- "version": "0.3.2",
4
- "description": "DeepSeek Harness 的 TencentDB Agent Memory 移植:L0 对话捕获 → L1 结构化记忆提取 → L2 场景/L3 画像,自动召回注入 + 记忆/对话搜索工具;复用现有 ~/.memory-tencentdb/memory-tdai 数据;附 Web UI 设置栏。",
5
- "type": "module",
6
- "main": "index.js",
7
- "exports": {
8
- ".": "./index.js",
9
- "./client": "./client.js",
10
- "./package.json": "./package.json"
11
- },
12
- "dsh": {
13
- "bundle": {
14
- "patch": "./cordis.patch.yml"
15
- },
16
- "client": {
17
- "platform": "web"
18
- }
19
- },
20
- "homepage": "https://github.com/Scorp1o117/dsh-tdai-memory",
21
- "files": [
22
- "index.js",
23
- "recall-inject.js",
24
- "client.js",
25
- "cordis.patch.yml",
26
- "vendor",
27
- "README.md",
28
- "README.zh.md",
29
- "LICENSE",
30
- "THIRD-PARTY-NOTICES.md"
31
- ],
32
- "keywords": [
33
- "dsh",
34
- "dsh-plugin",
35
- "deepseek-harness",
36
- "memory",
37
- "tencentdb",
38
- "agent-memory",
39
- "rag",
40
- "vector-search",
41
- "persona"
42
- ],
43
- "license": "MIT",
44
- "engines": {
45
- "node": ">=22.18"
46
- },
47
- "repository": {
48
- "type": "git",
49
- "url": "git+https://github.com/Scorp1o117/dsh-tdai-memory.git"
50
- },
51
- "bugs": {
52
- "url": "https://github.com/Scorp1o117/dsh-tdai-memory/issues"
53
- },
54
- "dependencies": {
55
- "@ai-sdk/openai": "^3.0.53",
56
- "@deepseek-ai/schemastery": "^3.18.1",
57
- "@node-rs/jieba": "^2.0.1",
58
- "@tencentdb-agent-memory/tcvdb-text": "^0.1.1",
59
- "ai": "^6.0.164",
60
- "json5": "^2.2.3",
61
- "sqlite-vec": "0.1.7-alpha.2",
62
- "undici": "^8.1.0"
63
- },
64
- "peerDependencies": {
65
- "react": "^18.2.0",
66
- "@deepseek-ai/dsh-tools": "^0.1.0-rc.7 || ^0.1.1-rc.1 || ^0.1.2-rc.1 || ^0.1.5-rc.1",
67
- "@deepseek-ai/dsh-settings": "^0.1.0-rc.7 || ^0.1.1-rc.1 || ^0.1.2-rc.1 || ^0.1.5-rc.1",
68
- "node-llama-cpp": "^3.19.1"
69
- },
70
- "peerDependenciesMeta": {
71
- "node-llama-cpp": {
72
- "optional": true
73
- }
74
- },
75
- "scripts": {
76
- "test": "node tests/settings-scope-compat.test.mjs && node tests/install-contract.test.mjs"
77
- }
78
- }
1
+ {
2
+ "name": "dsh-tdai-memory",
3
+ "version": "0.3.4",
4
+ "description": "DeepSeek Harness 的 TencentDB Agent Memory 移植:L0 对话捕获 → L1 结构化记忆提取 → L2 场景/L3 画像,自动召回注入 + 记忆/对话搜索工具;复用现有 ~/.memory-tencentdb/memory-tdai 数据;附 Web UI 设置栏。",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "exports": {
8
+ ".": "./index.js",
9
+ "./client": "./client.js",
10
+ "./package.json": "./package.json"
11
+ },
12
+ "dsh": {
13
+ "bundle": {
14
+ "patch": "./cordis.patch.yml"
15
+ },
16
+ "client": {
17
+ "platform": "web"
18
+ },
19
+ "compatibility": {
20
+ "dsh": ">=0.1.7-rc.1 <0.2.0",
21
+ "dshReleases": {
22
+ "0.1.5-rc.2": "incompatible",
23
+ "0.1.5-rc.3": "incompatible",
24
+ "0.1.6-alpha.1": "unknown",
25
+ "0.1.6-alpha.2": "unknown",
26
+ "0.1.7-alpha.1": "unknown",
27
+ "0.1.7-alpha.2": "unknown",
28
+ "0.1.7-rc.1": "compatible"
29
+ },
30
+ "node": ">=22.18",
31
+ "profiles": [
32
+ "web"
33
+ ]
34
+ }
35
+ },
36
+ "homepage": "https://github.com/Scorp1o117/dsh-tdai-memory",
37
+ "files": [
38
+ "index.js",
39
+ "recall-inject.js",
40
+ "client.js",
41
+ "cordis.patch.yml",
42
+ "vendor",
43
+ "README.md",
44
+ "README.zh.md",
45
+ "LICENSE",
46
+ "THIRD-PARTY-NOTICES.md"
47
+ ],
48
+ "keywords": [
49
+ "dsh",
50
+ "dsh-plugin",
51
+ "deepseek-harness",
52
+ "memory",
53
+ "tencentdb",
54
+ "agent-memory",
55
+ "rag",
56
+ "vector-search",
57
+ "persona"
58
+ ],
59
+ "license": "MIT",
60
+ "engines": {
61
+ "node": ">=22.18"
62
+ },
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "git+https://github.com/Scorp1o117/dsh-tdai-memory.git"
66
+ },
67
+ "bugs": {
68
+ "url": "https://github.com/Scorp1o117/dsh-tdai-memory/issues"
69
+ },
70
+ "dependencies": {
71
+ "@ai-sdk/openai": "^3.0.53",
72
+ "@deepseek-ai/schemastery": "^3.18.4",
73
+ "@node-rs/jieba": "^2.0.1",
74
+ "@tencentdb-agent-memory/tcvdb-text": "^0.1.1",
75
+ "ai": "^6.0.164",
76
+ "json5": "^2.2.3",
77
+ "sqlite-vec": "0.1.7-alpha.2",
78
+ "undici": "^8.1.0"
79
+ },
80
+ "peerDependencies": {
81
+ "react": "^18.2.0",
82
+ "@deepseek-ai/dsh-tools": "^0.1.7-rc.1",
83
+ "@deepseek-ai/dsh-settings": "^0.1.7-rc.1",
84
+ "node-llama-cpp": "^3.19.1"
85
+ },
86
+ "peerDependenciesMeta": {
87
+ "node-llama-cpp": {
88
+ "optional": true
89
+ }
90
+ },
91
+ "scripts": {
92
+ "test": "node tests/settings-scope-compat.test.mjs && node tests/install-contract.test.mjs"
93
+ }
94
+ }
package/recall-inject.js CHANGED
@@ -1,86 +1,86 @@
1
- /**
2
- * tdai-recall-inject — agent-plane recall injection row for dsh-tdai-memory.
3
- *
4
- * Mounted INSIDE an agent preset (agent.cordis.yml), this row listens on the
5
- * `system-prompt/assemble` waterfall in the preset's scope, so it runs for
6
- * every assembly of every agent joined to that preset (agent -> preset scope
7
- * chain). It asks the `tdaiMemory` service (provided by the root-level
8
- * dsh-tdai-memory plugin) for relevant long-term memories and appends them
9
- * as dynamic context sections (user-role snapshots):
10
- *
11
- * - tdai:recall — relevant L1 memories for the current user message
12
- * - tdai:profile — stable persona / scene navigation context
13
- *
14
- * The recall call is bounded by `recall.timeoutMs`; failures degrade to no
15
- * injection and never break the assembly.
16
- */
17
- import z from "@deepseek-ai/schemastery";
18
-
19
- /** Cordis plugin name. */
20
- const name = "tdai-recall-inject";
21
- /** Services consumed: the prompt registry and the memory core service. */
22
- const inject = ["systemPrompt", "tdaiMemory"];
23
-
24
- /** Runtime schema for the recall-inject row. */
25
- const Config = z.object({
26
- /** Skip recall when the user message is shorter than this. */
27
- minUserTextChars: z.number().default(1),
28
- /** Per-session cache TTL for identical user text (ms). */
29
- cacheTtlMs: z.number().default(30_000),
30
- });
31
-
32
- function apply(ctx, config) {
33
- const cache = new Map();
34
-
35
- ctx.on("system-prompt/assemble", async (assembly, context) => {
36
- try {
37
- const agent = context?.agent;
38
- if (!agent) return assembly;
39
- const session = agent.session;
40
- if (!session) return assembly;
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"));
48
- if (!lastUser) return assembly;
49
- const text = extractText(lastUser.content);
50
- if (!text || text.length < config.minUserTextChars) return assembly;
51
-
52
- const now = Date.now();
53
- const cached = cache.get(session.id);
54
- if (cached && cached.text === text && now - cached.ts < config.cacheTtlMs) {
55
- return injectRecall(assembly, cached.result);
56
- }
57
- const result = await ctx.tdaiMemory
58
- .handleBeforeRecall(text, session.id)
59
- .catch(() => null);
60
- cache.set(session.id, { text, result: result ?? {}, ts: now });
61
- return injectRecall(assembly, result ?? {});
62
- } catch {
63
- return assembly;
64
- }
65
- });
66
- }
67
-
68
- function extractText(content) {
69
- if (typeof content === "string") return content.trim();
70
- if (!Array.isArray(content)) return "";
71
- return content
72
- .filter((b) => b && b.type === "text" && typeof b.text === "string")
73
- .map((b) => b.text)
74
- .join("\n")
75
- .trim();
76
- }
77
-
78
- function injectRecall(assembly, result) {
79
- const extras = [];
80
- if (result.prependContext) extras.push({ name: "tdai:recall", order: 1000, text: result.prependContext });
81
- if (result.appendSystemContext) extras.push({ name: "tdai:profile", order: 1001, text: result.appendSystemContext });
82
- if (extras.length === 0) return assembly;
83
- return { ...assembly, contexts: [...assembly.contexts, ...extras] };
84
- }
85
-
86
- export { Config, apply, inject, name };
1
+ /**
2
+ * tdai-recall-inject — agent-plane recall injection row for dsh-tdai-memory.
3
+ *
4
+ * Mounted INSIDE an agent preset (agent.cordis.yml), this row listens on the
5
+ * `system-prompt/assemble` waterfall in the preset's scope, so it runs for
6
+ * every assembly of every agent joined to that preset (agent -> preset scope
7
+ * chain). It asks the `tdaiMemory` service (provided by the root-level
8
+ * dsh-tdai-memory plugin) for relevant long-term memories and appends them
9
+ * as dynamic context sections (user-role snapshots):
10
+ *
11
+ * - tdai:recall — relevant L1 memories for the current user message
12
+ * - tdai:profile — stable persona / scene navigation context
13
+ *
14
+ * The recall call is bounded by `recall.timeoutMs`; failures degrade to no
15
+ * injection and never break the assembly.
16
+ */
17
+ import z from "@deepseek-ai/schemastery";
18
+
19
+ /** Cordis plugin name. */
20
+ const name = "tdai-recall-inject";
21
+ /** Services consumed: the prompt registry and the memory core service. */
22
+ const inject = ["systemPrompt", "tdaiMemory"];
23
+
24
+ /** Runtime schema for the recall-inject row. */
25
+ const Config = z.object({
26
+ /** Skip recall when the user message is shorter than this. */
27
+ minUserTextChars: z.number().default(1),
28
+ /** Per-session cache TTL for identical user text (ms). */
29
+ cacheTtlMs: z.number().default(30_000),
30
+ });
31
+
32
+ function apply(ctx, config) {
33
+ const cache = new Map();
34
+
35
+ ctx.on("system-prompt/assemble", async (assembly, context) => {
36
+ try {
37
+ const agent = context?.agent;
38
+ if (!agent) return assembly;
39
+ const session = agent.session;
40
+ if (!session) return assembly;
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"));
48
+ if (!lastUser) return assembly;
49
+ const text = extractText(lastUser.content);
50
+ if (!text || text.length < config.minUserTextChars) return assembly;
51
+
52
+ const now = Date.now();
53
+ const cached = cache.get(session.id);
54
+ if (cached && cached.text === text && now - cached.ts < config.cacheTtlMs) {
55
+ return injectRecall(assembly, cached.result);
56
+ }
57
+ const result = await ctx.tdaiMemory
58
+ .handleBeforeRecall(text, session.id)
59
+ .catch(() => null);
60
+ cache.set(session.id, { text, result: result ?? {}, ts: now });
61
+ return injectRecall(assembly, result ?? {});
62
+ } catch {
63
+ return assembly;
64
+ }
65
+ });
66
+ }
67
+
68
+ function extractText(content) {
69
+ if (typeof content === "string") return content.trim();
70
+ if (!Array.isArray(content)) return "";
71
+ return content
72
+ .filter((b) => b && b.type === "text" && typeof b.text === "string")
73
+ .map((b) => b.text)
74
+ .join("\n")
75
+ .trim();
76
+ }
77
+
78
+ function injectRecall(assembly, result) {
79
+ const extras = [];
80
+ if (result.prependContext) extras.push({ name: "tdai:recall", order: 1000, text: result.prependContext });
81
+ if (result.appendSystemContext) extras.push({ name: "tdai:profile", order: 1001, text: result.appendSystemContext });
82
+ if (extras.length === 0) return assembly;
83
+ return { ...assembly, contexts: [...assembly.contexts, ...extras] };
84
+ }
85
+
86
+ export { Config, apply, inject, name };