dsh-tdai-memory 0.2.9 → 0.2.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.
- package/LICENSE +21 -21
- package/README.md +130 -130
- package/README.zh.md +72 -72
- package/THIRD-PARTY-NOTICES.md +20 -20
- package/client.js +349 -311
- package/cordis.patch.yml +8 -8
- package/index.js +421 -421
- package/package.json +8 -5
- package/recall-inject.js +86 -86
- package/vendor/dsh-settings-expose.js +75 -75
- package/vendor/tdai/adapters/index.js +15 -15
- package/vendor/tdai/adapters/openclaw/host-adapter.js +83 -83
- package/vendor/tdai/adapters/openclaw/index.js +5 -5
- package/vendor/tdai/adapters/openclaw/llm-runner.js +69 -69
- package/vendor/tdai/adapters/standalone/host-adapter.js +58 -58
- package/vendor/tdai/adapters/standalone/index.js +5 -5
- package/vendor/tdai/adapters/standalone/llm-runner.js +246 -246
- package/vendor/tdai/config.js +363 -363
- package/vendor/tdai/core/conversation/l0-recorder.js +420 -420
- package/vendor/tdai/core/hooks/auto-capture.js +236 -236
- package/vendor/tdai/core/hooks/auto-recall.js +640 -640
- package/vendor/tdai/core/index.js +8 -8
- package/vendor/tdai/core/persona/persona-generator.js +184 -184
- package/vendor/tdai/core/persona/persona-trigger.js +94 -94
- package/vendor/tdai/core/profile/profile-sync.js +200 -200
- package/vendor/tdai/core/prompts/l1-dedup.js +72 -72
- package/vendor/tdai/core/prompts/l1-extraction.js +34 -34
- package/vendor/tdai/core/prompts/persona-generation.js +35 -35
- package/vendor/tdai/core/prompts/scene-extraction.js +45 -45
- package/vendor/tdai/core/record/l1-dedup.js +318 -318
- package/vendor/tdai/core/record/l1-extractor.js +379 -379
- package/vendor/tdai/core/record/l1-reader.js +178 -178
- package/vendor/tdai/core/record/l1-writer.js +141 -141
- package/vendor/tdai/core/report/reporter.js +86 -86
- package/vendor/tdai/core/scene/filename-normalizer.js +161 -161
- package/vendor/tdai/core/scene/scene-extractor.js +410 -410
- package/vendor/tdai/core/scene/scene-format.js +53 -53
- package/vendor/tdai/core/scene/scene-index.js +82 -82
- package/vendor/tdai/core/scene/scene-navigation.js +57 -57
- package/vendor/tdai/core/seed/input.js +404 -404
- package/vendor/tdai/core/seed/seed-runtime.js +314 -314
- package/vendor/tdai/core/seed/types.js +9 -9
- package/vendor/tdai/core/store/bm25-client.js +117 -117
- package/vendor/tdai/core/store/bm25-local.js +68 -68
- package/vendor/tdai/core/store/embedding.js +632 -632
- package/vendor/tdai/core/store/factory.js +95 -95
- package/vendor/tdai/core/store/search-utils.js +54 -54
- package/vendor/tdai/core/store/sqlite.js +1632 -1632
- package/vendor/tdai/core/store/tcvdb-client.js +221 -221
- package/vendor/tdai/core/store/tcvdb.js +1047 -1047
- package/vendor/tdai/core/store/types.js +17 -17
- package/vendor/tdai/core/tdai-core.js +446 -446
- package/vendor/tdai/core/tools/conversation-search.js +199 -199
- package/vendor/tdai/core/tools/memory-search.js +207 -207
- package/vendor/tdai/core/types.js +12 -12
- package/vendor/tdai/utils/backup.js +189 -189
- package/vendor/tdai/utils/checkpoint.js +360 -360
- package/vendor/tdai/utils/clean-context-runner.js +472 -472
- package/vendor/tdai/utils/ensure-hook-policy.js +213 -213
- package/vendor/tdai/utils/env.js +13 -13
- package/vendor/tdai/utils/managed-timer.js +127 -127
- package/vendor/tdai/utils/manifest.js +91 -91
- package/vendor/tdai/utils/memory-cleaner.js +300 -300
- package/vendor/tdai/utils/no-think-fetch.js +109 -109
- package/vendor/tdai/utils/openclaw-state-dir.js +26 -26
- package/vendor/tdai/utils/pipeline-factory.js +517 -517
- package/vendor/tdai/utils/pipeline-manager.js +892 -892
- package/vendor/tdai/utils/sanitize.js +360 -360
- package/vendor/tdai/utils/serial-queue.js +103 -103
- package/vendor/tdai/utils/session-filter.js +88 -88
- package/vendor/tdai/utils/text-utils.js +29 -29
- package/vendor/tdai/utils/time.js +252 -252
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-tdai-memory",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.11",
|
|
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",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dsh": {
|
|
13
13
|
"bundle": {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
"patch": "./cordis.patch.yml"
|
|
15
|
+
},
|
|
16
16
|
"client": {
|
|
17
17
|
"platform": "web"
|
|
18
18
|
}
|
|
@@ -68,5 +68,8 @@
|
|
|
68
68
|
"react": "^18.2.0",
|
|
69
69
|
"@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
|
|
70
70
|
"@deepseek-ai/dsh-settings": "^0.1.0-rc.6"
|
|
71
|
-
}
|
|
72
|
-
|
|
71
|
+
},
|
|
72
|
+
"scripts": {
|
|
73
|
+
"test": "node tests/settings-scope-compat.test.mjs"
|
|
74
|
+
}
|
|
75
|
+
}
|
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 };
|
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* dsh-host-apiproxy exposes only namespaces listed in its hard-coded
|
|
3
|
-
* WEB_SETTINGS_NAMESPACES allowlist to the Web settings client. A namespace
|
|
4
|
-
* registered by a third-party plugin answers `settings-not-exposed` even
|
|
5
|
-
* though it is registered — upstream explicitly defers letting plugins
|
|
6
|
-
* expose their own configuration.
|
|
7
|
-
*
|
|
8
|
-
* This module idempotently patches that allowlist in the dsh installation
|
|
9
|
-
* actually loaded by the host process, so the plugin's settings section
|
|
10
|
-
* becomes visible in the Web UI without manual edits. A dsh update
|
|
11
|
-
* overwrites the file; the next plugin start re-patches it.
|
|
12
|
-
*/
|
|
13
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
|
-
import { createRequire } from "node:module";
|
|
15
|
-
import { dirname, join, sep } from "node:path";
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Ensure `nsName` is present in dsh-host-apiproxy's WEB_SETTINGS_NAMESPACES.
|
|
19
|
-
* No-op when already exposed or when the file cannot be located/patched.
|
|
20
|
-
* @param {import("cordis").Context} ctx
|
|
21
|
-
* @param {string} nsName - settings namespace short name (e.g. "tdai-memory").
|
|
22
|
-
* @param {{info?: Function, warn?: Function}} logger - dsh logger.
|
|
23
|
-
*/
|
|
24
|
-
export function ensureSettingsNamespaceExposed(ctx, nsName, logger) {
|
|
25
|
-
void ctx;
|
|
26
|
-
try {
|
|
27
|
-
const target = findApiproxyIndex();
|
|
28
|
-
if (!target) {
|
|
29
|
-
logger?.warn?.(`[settings-expose] could not locate dsh-host-apiproxy; add "${nsName}" to WEB_SETTINGS_NAMESPACES in dsh-host-apiproxy/lib/index.js to get a Web settings section`);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
let src;
|
|
33
|
-
try {
|
|
34
|
-
src = readFileSync(target, "utf8");
|
|
35
|
-
} catch (error) {
|
|
36
|
-
logger?.warn?.(`[settings-expose] cannot read ${target}: ${String(error)}`);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const body = src.match(/const WEB_SETTINGS_NAMESPACES = \[([\s\S]*?)\];/)?.[1] ?? "";
|
|
40
|
-
if (body.includes(`"${nsName}"`)) return; // already exposed (manual or previous patch)
|
|
41
|
-
const patched = src.replace(/(const WEB_SETTINGS_NAMESPACES = \[[\s\S]*?)(\n\s*\];)/, (_, pre, post) => {
|
|
42
|
-
const trailingComma = /,\s*$/.test(pre) ? "" : ",";
|
|
43
|
-
const sep2 = pre.trimEnd().endsWith("[") ? "" : trailingComma;
|
|
44
|
-
return `${pre}${sep2}\n\t"${nsName}"${post}`;
|
|
45
|
-
});
|
|
46
|
-
if (patched === src) {
|
|
47
|
-
logger?.warn?.(`[settings-expose] allowlist pattern not found in ${target}; add "${nsName}" to WEB_SETTINGS_NAMESPACES manually`);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
writeFileSync(target, patched, "utf8");
|
|
51
|
-
logger?.info?.(`[settings-expose] added "${nsName}" to WEB_SETTINGS_NAMESPACES (${target}) — restart dsh web for the settings section to appear`);
|
|
52
|
-
} catch (error) {
|
|
53
|
-
logger?.warn?.(`[settings-expose] failed: ${String(error)}`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function findApiproxyIndex() {
|
|
58
|
-
// 1) The host process has already loaded dsh-host-apiproxy: read the real
|
|
59
|
-
// module path from the CommonJS module cache (any install layout).
|
|
60
|
-
try {
|
|
61
|
-
const Module = createRequire(import.meta.url)("module");
|
|
62
|
-
const cache = Module._cache ?? {};
|
|
63
|
-
for (const key of Object.keys(cache)) {
|
|
64
|
-
if (key.includes(`${sep}dsh-host-apiproxy${sep}`) && key.endsWith(`${sep}index.js`)) return key;
|
|
65
|
-
}
|
|
66
|
-
} catch { /* fall through */ }
|
|
67
|
-
// 2) Fallback: sibling of @deepseek-ai/dsh-settings (dsh's nested layout).
|
|
68
|
-
try {
|
|
69
|
-
const require = createRequire(import.meta.url);
|
|
70
|
-
const settingsEntry = require.resolve("@deepseek-ai/dsh-settings");
|
|
71
|
-
const candidate = join(dirname(dirname(dirname(settingsEntry))), "dsh-host-apiproxy", "lib", "index.js");
|
|
72
|
-
if (existsSync(candidate)) return candidate;
|
|
73
|
-
} catch { /* fall through */ }
|
|
74
|
-
return "";
|
|
75
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* dsh-host-apiproxy exposes only namespaces listed in its hard-coded
|
|
3
|
+
* WEB_SETTINGS_NAMESPACES allowlist to the Web settings client. A namespace
|
|
4
|
+
* registered by a third-party plugin answers `settings-not-exposed` even
|
|
5
|
+
* though it is registered — upstream explicitly defers letting plugins
|
|
6
|
+
* expose their own configuration.
|
|
7
|
+
*
|
|
8
|
+
* This module idempotently patches that allowlist in the dsh installation
|
|
9
|
+
* actually loaded by the host process, so the plugin's settings section
|
|
10
|
+
* becomes visible in the Web UI without manual edits. A dsh update
|
|
11
|
+
* overwrites the file; the next plugin start re-patches it.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
14
|
+
import { createRequire } from "node:module";
|
|
15
|
+
import { dirname, join, sep } from "node:path";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Ensure `nsName` is present in dsh-host-apiproxy's WEB_SETTINGS_NAMESPACES.
|
|
19
|
+
* No-op when already exposed or when the file cannot be located/patched.
|
|
20
|
+
* @param {import("cordis").Context} ctx
|
|
21
|
+
* @param {string} nsName - settings namespace short name (e.g. "tdai-memory").
|
|
22
|
+
* @param {{info?: Function, warn?: Function}} logger - dsh logger.
|
|
23
|
+
*/
|
|
24
|
+
export function ensureSettingsNamespaceExposed(ctx, nsName, logger) {
|
|
25
|
+
void ctx;
|
|
26
|
+
try {
|
|
27
|
+
const target = findApiproxyIndex();
|
|
28
|
+
if (!target) {
|
|
29
|
+
logger?.warn?.(`[settings-expose] could not locate dsh-host-apiproxy; add "${nsName}" to WEB_SETTINGS_NAMESPACES in dsh-host-apiproxy/lib/index.js to get a Web settings section`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
let src;
|
|
33
|
+
try {
|
|
34
|
+
src = readFileSync(target, "utf8");
|
|
35
|
+
} catch (error) {
|
|
36
|
+
logger?.warn?.(`[settings-expose] cannot read ${target}: ${String(error)}`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const body = src.match(/const WEB_SETTINGS_NAMESPACES = \[([\s\S]*?)\];/)?.[1] ?? "";
|
|
40
|
+
if (body.includes(`"${nsName}"`)) return; // already exposed (manual or previous patch)
|
|
41
|
+
const patched = src.replace(/(const WEB_SETTINGS_NAMESPACES = \[[\s\S]*?)(\n\s*\];)/, (_, pre, post) => {
|
|
42
|
+
const trailingComma = /,\s*$/.test(pre) ? "" : ",";
|
|
43
|
+
const sep2 = pre.trimEnd().endsWith("[") ? "" : trailingComma;
|
|
44
|
+
return `${pre}${sep2}\n\t"${nsName}"${post}`;
|
|
45
|
+
});
|
|
46
|
+
if (patched === src) {
|
|
47
|
+
logger?.warn?.(`[settings-expose] allowlist pattern not found in ${target}; add "${nsName}" to WEB_SETTINGS_NAMESPACES manually`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
writeFileSync(target, patched, "utf8");
|
|
51
|
+
logger?.info?.(`[settings-expose] added "${nsName}" to WEB_SETTINGS_NAMESPACES (${target}) — restart dsh web for the settings section to appear`);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
logger?.warn?.(`[settings-expose] failed: ${String(error)}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function findApiproxyIndex() {
|
|
58
|
+
// 1) The host process has already loaded dsh-host-apiproxy: read the real
|
|
59
|
+
// module path from the CommonJS module cache (any install layout).
|
|
60
|
+
try {
|
|
61
|
+
const Module = createRequire(import.meta.url)("module");
|
|
62
|
+
const cache = Module._cache ?? {};
|
|
63
|
+
for (const key of Object.keys(cache)) {
|
|
64
|
+
if (key.includes(`${sep}dsh-host-apiproxy${sep}`) && key.endsWith(`${sep}index.js`)) return key;
|
|
65
|
+
}
|
|
66
|
+
} catch { /* fall through */ }
|
|
67
|
+
// 2) Fallback: sibling of @deepseek-ai/dsh-settings (dsh's nested layout).
|
|
68
|
+
try {
|
|
69
|
+
const require = createRequire(import.meta.url);
|
|
70
|
+
const settingsEntry = require.resolve("@deepseek-ai/dsh-settings");
|
|
71
|
+
const candidate = join(dirname(dirname(dirname(settingsEntry))), "dsh-host-apiproxy", "lib", "index.js");
|
|
72
|
+
if (existsSync(candidate)) return candidate;
|
|
73
|
+
} catch { /* fall through */ }
|
|
74
|
+
return "";
|
|
75
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TDAI Adapters — barrel re-export for all host adapter implementations.
|
|
3
|
-
*
|
|
4
|
-
* Each adapter translates a specific host environment's API into
|
|
5
|
-
* the host-neutral HostAdapter interface consumed by TdaiCore.
|
|
6
|
-
*
|
|
7
|
-
* Directory structure:
|
|
8
|
-
* adapters/
|
|
9
|
-
* ├── openclaw/ — OpenClaw plugin host (in-process, runEmbeddedPiAgent)
|
|
10
|
-
* └── standalone/ — Gateway / Hermes sidecar (HTTP, OpenAI-compatible API)
|
|
11
|
-
*/
|
|
12
|
-
// OpenClaw adapter
|
|
13
|
-
export { OpenClawHostAdapter, OpenClawLLMRunner, OpenClawLLMRunnerFactory } from "./openclaw/index.js";
|
|
14
|
-
// Standalone adapter
|
|
15
|
-
export { StandaloneHostAdapter, StandaloneLLMRunner, StandaloneLLMRunnerFactory } from "./standalone/index.js";
|
|
1
|
+
/**
|
|
2
|
+
* TDAI Adapters — barrel re-export for all host adapter implementations.
|
|
3
|
+
*
|
|
4
|
+
* Each adapter translates a specific host environment's API into
|
|
5
|
+
* the host-neutral HostAdapter interface consumed by TdaiCore.
|
|
6
|
+
*
|
|
7
|
+
* Directory structure:
|
|
8
|
+
* adapters/
|
|
9
|
+
* ├── openclaw/ — OpenClaw plugin host (in-process, runEmbeddedPiAgent)
|
|
10
|
+
* └── standalone/ — Gateway / Hermes sidecar (HTTP, OpenAI-compatible API)
|
|
11
|
+
*/
|
|
12
|
+
// OpenClaw adapter
|
|
13
|
+
export { OpenClawHostAdapter, OpenClawLLMRunner, OpenClawLLMRunnerFactory } from "./openclaw/index.js";
|
|
14
|
+
// Standalone adapter
|
|
15
|
+
export { StandaloneHostAdapter, StandaloneLLMRunner, StandaloneLLMRunnerFactory } from "./standalone/index.js";
|
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenClawHostAdapter — translates OpenClaw's plugin API into TDAI Core's
|
|
3
|
-
* unified HostAdapter interface.
|
|
4
|
-
*
|
|
5
|
-
* This is the "thin shell" that keeps OpenClaw-specific dependencies
|
|
6
|
-
* (OpenClawPluginApi, pluginConfig, resolveStateDir, event system)
|
|
7
|
-
* confined to the adapter layer while TDAI Core remains host-neutral.
|
|
8
|
-
*
|
|
9
|
-
* Usage (in index.ts):
|
|
10
|
-
* const adapter = new OpenClawHostAdapter({ api, pluginDataDir, config });
|
|
11
|
-
* const core = new TdaiCore({ hostAdapter: adapter, config: parsedConfig });
|
|
12
|
-
*/
|
|
13
|
-
import { OpenClawLLMRunnerFactory } from "./llm-runner.js";
|
|
14
|
-
// ============================
|
|
15
|
-
// OpenClawHostAdapter
|
|
16
|
-
// ============================
|
|
17
|
-
export class OpenClawHostAdapter {
|
|
18
|
-
hostType = "openclaw";
|
|
19
|
-
api;
|
|
20
|
-
pluginDataDir;
|
|
21
|
-
openclawConfig;
|
|
22
|
-
runnerFactory;
|
|
23
|
-
constructor(opts) {
|
|
24
|
-
this.api = opts.api;
|
|
25
|
-
this.pluginDataDir = opts.pluginDataDir;
|
|
26
|
-
this.openclawConfig = opts.openclawConfig;
|
|
27
|
-
this.runnerFactory = new OpenClawLLMRunnerFactory({
|
|
28
|
-
config: opts.openclawConfig,
|
|
29
|
-
agentRuntime: opts.api.runtime.agent,
|
|
30
|
-
logger: opts.api.logger,
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Build a RuntimeContext from the current OpenClaw session.
|
|
35
|
-
*
|
|
36
|
-
* In OpenClaw, sessionKey and sessionId come from the event/ctx objects
|
|
37
|
-
* passed to hooks. This method returns a context with sensible defaults;
|
|
38
|
-
* callers can override sessionKey/sessionId per-hook invocation using
|
|
39
|
-
* `buildRuntimeContextForSession()`.
|
|
40
|
-
*/
|
|
41
|
-
getRuntimeContext() {
|
|
42
|
-
return {
|
|
43
|
-
userId: "default_user",
|
|
44
|
-
sessionId: "",
|
|
45
|
-
sessionKey: "",
|
|
46
|
-
platform: "openclaw",
|
|
47
|
-
workspaceDir: process.cwd(),
|
|
48
|
-
dataDir: this.pluginDataDir,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Build a RuntimeContext for a specific session (used per-hook).
|
|
53
|
-
*
|
|
54
|
-
* This is an OpenClaw-specific convenience that merges session-level
|
|
55
|
-
* identifiers from hook ctx into the base context.
|
|
56
|
-
*/
|
|
57
|
-
buildRuntimeContextForSession(sessionKey, sessionId) {
|
|
58
|
-
return {
|
|
59
|
-
...this.getRuntimeContext(),
|
|
60
|
-
sessionKey,
|
|
61
|
-
sessionId: sessionId ?? "",
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
getLogger() {
|
|
65
|
-
return this.api.logger;
|
|
66
|
-
}
|
|
67
|
-
getLLMRunnerFactory() {
|
|
68
|
-
return this.runnerFactory;
|
|
69
|
-
}
|
|
70
|
-
// -- OpenClaw-specific accessors (for index.ts bridge) --------------------
|
|
71
|
-
/** Get the raw OpenClaw plugin API (for legacy callers during migration). */
|
|
72
|
-
getPluginApi() {
|
|
73
|
-
return this.api;
|
|
74
|
-
}
|
|
75
|
-
/** Get the OpenClaw config object (for legacy callers during migration). */
|
|
76
|
-
getOpenClawConfig() {
|
|
77
|
-
return this.openclawConfig;
|
|
78
|
-
}
|
|
79
|
-
/** Get the resolved plugin data directory. */
|
|
80
|
-
getPluginDataDir() {
|
|
81
|
-
return this.pluginDataDir;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* OpenClawHostAdapter — translates OpenClaw's plugin API into TDAI Core's
|
|
3
|
+
* unified HostAdapter interface.
|
|
4
|
+
*
|
|
5
|
+
* This is the "thin shell" that keeps OpenClaw-specific dependencies
|
|
6
|
+
* (OpenClawPluginApi, pluginConfig, resolveStateDir, event system)
|
|
7
|
+
* confined to the adapter layer while TDAI Core remains host-neutral.
|
|
8
|
+
*
|
|
9
|
+
* Usage (in index.ts):
|
|
10
|
+
* const adapter = new OpenClawHostAdapter({ api, pluginDataDir, config });
|
|
11
|
+
* const core = new TdaiCore({ hostAdapter: adapter, config: parsedConfig });
|
|
12
|
+
*/
|
|
13
|
+
import { OpenClawLLMRunnerFactory } from "./llm-runner.js";
|
|
14
|
+
// ============================
|
|
15
|
+
// OpenClawHostAdapter
|
|
16
|
+
// ============================
|
|
17
|
+
export class OpenClawHostAdapter {
|
|
18
|
+
hostType = "openclaw";
|
|
19
|
+
api;
|
|
20
|
+
pluginDataDir;
|
|
21
|
+
openclawConfig;
|
|
22
|
+
runnerFactory;
|
|
23
|
+
constructor(opts) {
|
|
24
|
+
this.api = opts.api;
|
|
25
|
+
this.pluginDataDir = opts.pluginDataDir;
|
|
26
|
+
this.openclawConfig = opts.openclawConfig;
|
|
27
|
+
this.runnerFactory = new OpenClawLLMRunnerFactory({
|
|
28
|
+
config: opts.openclawConfig,
|
|
29
|
+
agentRuntime: opts.api.runtime.agent,
|
|
30
|
+
logger: opts.api.logger,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build a RuntimeContext from the current OpenClaw session.
|
|
35
|
+
*
|
|
36
|
+
* In OpenClaw, sessionKey and sessionId come from the event/ctx objects
|
|
37
|
+
* passed to hooks. This method returns a context with sensible defaults;
|
|
38
|
+
* callers can override sessionKey/sessionId per-hook invocation using
|
|
39
|
+
* `buildRuntimeContextForSession()`.
|
|
40
|
+
*/
|
|
41
|
+
getRuntimeContext() {
|
|
42
|
+
return {
|
|
43
|
+
userId: "default_user",
|
|
44
|
+
sessionId: "",
|
|
45
|
+
sessionKey: "",
|
|
46
|
+
platform: "openclaw",
|
|
47
|
+
workspaceDir: process.cwd(),
|
|
48
|
+
dataDir: this.pluginDataDir,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build a RuntimeContext for a specific session (used per-hook).
|
|
53
|
+
*
|
|
54
|
+
* This is an OpenClaw-specific convenience that merges session-level
|
|
55
|
+
* identifiers from hook ctx into the base context.
|
|
56
|
+
*/
|
|
57
|
+
buildRuntimeContextForSession(sessionKey, sessionId) {
|
|
58
|
+
return {
|
|
59
|
+
...this.getRuntimeContext(),
|
|
60
|
+
sessionKey,
|
|
61
|
+
sessionId: sessionId ?? "",
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
getLogger() {
|
|
65
|
+
return this.api.logger;
|
|
66
|
+
}
|
|
67
|
+
getLLMRunnerFactory() {
|
|
68
|
+
return this.runnerFactory;
|
|
69
|
+
}
|
|
70
|
+
// -- OpenClaw-specific accessors (for index.ts bridge) --------------------
|
|
71
|
+
/** Get the raw OpenClaw plugin API (for legacy callers during migration). */
|
|
72
|
+
getPluginApi() {
|
|
73
|
+
return this.api;
|
|
74
|
+
}
|
|
75
|
+
/** Get the OpenClaw config object (for legacy callers during migration). */
|
|
76
|
+
getOpenClawConfig() {
|
|
77
|
+
return this.openclawConfig;
|
|
78
|
+
}
|
|
79
|
+
/** Get the resolved plugin data directory. */
|
|
80
|
+
getPluginDataDir() {
|
|
81
|
+
return this.pluginDataDir;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenClaw adapter — barrel exports.
|
|
3
|
-
*/
|
|
4
|
-
export { OpenClawHostAdapter } from "./host-adapter.js";
|
|
5
|
-
export { OpenClawLLMRunner, OpenClawLLMRunnerFactory } from "./llm-runner.js";
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw adapter — barrel exports.
|
|
3
|
+
*/
|
|
4
|
+
export { OpenClawHostAdapter } from "./host-adapter.js";
|
|
5
|
+
export { OpenClawLLMRunner, OpenClawLLMRunnerFactory } from "./llm-runner.js";
|