adp-openclaw 0.0.2 → 0.0.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.
- package/e2e_test.cjs +98 -0
- package/index.ts +8 -7
- package/openclaw.plugin.json +4 -17
- package/package.json +6 -6
- package/src/channel.ts +120 -90
- package/src/config-schema.ts +1 -1
- package/src/monitor.ts +50 -34
- package/src/runtime.ts +27 -8
- package/DESIGN.md +0 -733
- package/README.md +0 -70
- package/USAGE.md +0 -910
- package/WEBSOCKET_PROTOCOL.md +0 -506
- package/server/.claude/settings.local.json +0 -16
- package/server/go.mod +0 -5
- package/server/main.go +0 -786
package/e2e_test.cjs
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const WebSocket = require('ws');
|
|
2
|
+
|
|
3
|
+
// 测试配置
|
|
4
|
+
const token = '334b209ed0833464202cc4438e7ce801583fc74c13384cbac60d02949f33e09c';
|
|
5
|
+
const host = '101.32.33.231';
|
|
6
|
+
const port = 9876;
|
|
7
|
+
|
|
8
|
+
console.log('🧪 OpenClaw 发送消息测试');
|
|
9
|
+
console.log(`📍 目标服务器: ${host}:${port}`);
|
|
10
|
+
console.log(`🔑 Token: ${token.slice(0, 16)}...\n`);
|
|
11
|
+
|
|
12
|
+
// Step 1: 测试 WebSocket 连接
|
|
13
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
14
|
+
console.log('1️⃣ 连接 WebSocket...');
|
|
15
|
+
const ws = new WebSocket(`ws://${host}:${port}/ws`);
|
|
16
|
+
|
|
17
|
+
ws.on('open', () => {
|
|
18
|
+
console.log(' ✅ WebSocket 连接成功');
|
|
19
|
+
console.log(' 📤 发送认证请求...');
|
|
20
|
+
ws.send(JSON.stringify({ type: 'auth', payload: { token, name: 'e2e-test-client' } }));
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
ws.on('message', (data) => {
|
|
24
|
+
const msg = JSON.parse(data.toString());
|
|
25
|
+
console.log(' 📥 收到消息:', msg.type);
|
|
26
|
+
|
|
27
|
+
if (msg.type === 'auth_result') {
|
|
28
|
+
console.log(' 完整响应:', JSON.stringify(msg.payload, null, 2));
|
|
29
|
+
if (msg.payload.success) {
|
|
30
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
31
|
+
console.log('2️⃣ 认证成功');
|
|
32
|
+
console.log(' ClientID:', msg.payload.clientId);
|
|
33
|
+
|
|
34
|
+
// Step 3: 发送 outbound 消息 (Bot 回复)
|
|
35
|
+
setTimeout(() => {
|
|
36
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
37
|
+
console.log('3️⃣ 发送 outbound 消息...');
|
|
38
|
+
|
|
39
|
+
const requestId = 'req-' + Date.now() + '-test';
|
|
40
|
+
const testMessage = {
|
|
41
|
+
type: 'outbound',
|
|
42
|
+
requestId: requestId,
|
|
43
|
+
payload: {
|
|
44
|
+
to: 'test-user',
|
|
45
|
+
text: '🎉 这是来自 E2E 测试的消息!时间: ' + new Date().toLocaleString('zh-CN'),
|
|
46
|
+
conversationId: 'conv-test-' + Date.now()
|
|
47
|
+
},
|
|
48
|
+
timestamp: Date.now()
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
console.log(' 发送内容:', JSON.stringify(testMessage, null, 2));
|
|
52
|
+
ws.send(JSON.stringify(testMessage));
|
|
53
|
+
|
|
54
|
+
console.log(' 📤 消息已发送,等待服务器确认 (ack)...');
|
|
55
|
+
}, 500);
|
|
56
|
+
} else {
|
|
57
|
+
console.log(' ❌ 认证失败:', msg.payload.message || msg.payload.error);
|
|
58
|
+
ws.close();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 处理服务器的响应
|
|
63
|
+
if (msg.type === 'ack') {
|
|
64
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
65
|
+
console.log('4️⃣ 收到服务器确认 (ack)');
|
|
66
|
+
console.log(' 确认内容:', JSON.stringify(msg.payload, null, 2));
|
|
67
|
+
if (msg.payload?.ok) {
|
|
68
|
+
console.log(' ✅ 消息发送成功!');
|
|
69
|
+
console.log(' 消息ID:', msg.payload.message?.id);
|
|
70
|
+
} else {
|
|
71
|
+
console.log(' ❌ 消息发送失败');
|
|
72
|
+
}
|
|
73
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
74
|
+
console.log('✅ 测试完成!');
|
|
75
|
+
ws.close();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (msg.type === 'error') {
|
|
79
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
80
|
+
console.log('❌ 服务器错误:', JSON.stringify(msg.payload, null, 2));
|
|
81
|
+
ws.close();
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
ws.on('error', (err) => {
|
|
86
|
+
console.log(' ❌ WebSocket 错误:', err.message);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
ws.on('close', () => {
|
|
90
|
+
console.log('\n📴 连接已关闭');
|
|
91
|
+
process.exit(0);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// 超时处理
|
|
95
|
+
setTimeout(() => {
|
|
96
|
+
console.log('\n⏱️ 测试超时 (10秒)');
|
|
97
|
+
ws.close();
|
|
98
|
+
}, 10000);
|
package/index.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
2
|
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { adpOpenclawPlugin } from "./src/channel.js";
|
|
4
|
+
import { setAdpOpenclawRuntime } from "./src/runtime.js";
|
|
5
5
|
|
|
6
6
|
const plugin = {
|
|
7
|
-
id: "
|
|
8
|
-
name: "
|
|
9
|
-
description: "
|
|
7
|
+
id: "adp-openclaw",
|
|
8
|
+
name: "ADP OpenClaw",
|
|
9
|
+
description: "ADP channel plugin backed by a Go WebSocket server",
|
|
10
10
|
configSchema: emptyPluginConfigSchema(),
|
|
11
11
|
register(api: OpenClawPluginApi) {
|
|
12
|
-
|
|
13
|
-
api.
|
|
12
|
+
console.log("[adp-openclaw] register() called");
|
|
13
|
+
setAdpOpenclawRuntime(api.runtime);
|
|
14
|
+
api.registerChannel({ plugin: adpOpenclawPlugin });
|
|
14
15
|
},
|
|
15
16
|
};
|
|
16
17
|
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,22 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"id": "
|
|
3
|
-
"
|
|
4
|
-
"version": "0.0.1",
|
|
5
|
-
"description": "OpenClaw demo channel plugin (Go HTTP backend)",
|
|
2
|
+
"id": "adp-openclaw",
|
|
3
|
+
"channels": ["adp-openclaw"],
|
|
6
4
|
"configSchema": {
|
|
7
5
|
"type": "object",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
},
|
|
11
|
-
"extensions": [
|
|
12
|
-
"./index.ts"
|
|
13
|
-
],
|
|
14
|
-
"channel": {
|
|
15
|
-
"id": "simplego",
|
|
16
|
-
"label": "Simple Go",
|
|
17
|
-
"selectionLabel": "Simple Go (demo)",
|
|
18
|
-
"docsPath": "/channels/simplego",
|
|
19
|
-
"blurb": "demo channel backed by a Go HTTP server.",
|
|
20
|
-
"order": 999
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"properties": {}
|
|
21
8
|
}
|
|
22
9
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adp-openclaw",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "OpenClaw demo channel plugin (Go WebSocket backend)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"dependencies": {
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"./index.ts"
|
|
16
16
|
],
|
|
17
17
|
"channel": {
|
|
18
|
-
"id": "adp",
|
|
19
|
-
"label": "
|
|
20
|
-
"selectionLabel": "
|
|
21
|
-
"docsPath": "/channels/adp",
|
|
22
|
-
"blurb": "
|
|
18
|
+
"id": "adp-openclaw",
|
|
19
|
+
"label": "ADP OpenClaw",
|
|
20
|
+
"selectionLabel": "ADP OpenClaw",
|
|
21
|
+
"docsPath": "/channels/adp-openclaw",
|
|
22
|
+
"blurb": "ADP channel backed by a Go WebSocket server.",
|
|
23
23
|
"order": 999
|
|
24
24
|
}
|
|
25
25
|
}
|
package/src/channel.ts
CHANGED
|
@@ -1,25 +1,23 @@
|
|
|
1
|
-
//
|
|
1
|
+
// ADP OpenClaw channel plugin for OpenClaw
|
|
2
2
|
// Supports: API Token auth, multiple clients, multi-turn conversations
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
type ChannelPlugin,
|
|
6
|
+
type ClawdbotConfig,
|
|
6
7
|
DEFAULT_ACCOUNT_ID,
|
|
7
|
-
setAccountEnabledInConfigSection,
|
|
8
|
-
deleteAccountFromConfigSection,
|
|
9
8
|
} from "openclaw/plugin-sdk";
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
10
|
+
// Channel-level config type (from channels["adp-openclaw"])
|
|
11
|
+
export type AdpOpenclawChannelConfig = {
|
|
12
|
+
enabled?: boolean;
|
|
13
|
+
serverUrl?: string;
|
|
14
|
+
wsUrl?: string;
|
|
15
|
+
apiToken?: string;
|
|
16
|
+
clientToken?: string;
|
|
17
|
+
pollIntervalMs?: number;
|
|
20
18
|
};
|
|
21
19
|
|
|
22
|
-
export type
|
|
20
|
+
export type ResolvedAdpOpenclawAccount = {
|
|
23
21
|
accountId: string;
|
|
24
22
|
name: string;
|
|
25
23
|
enabled: boolean;
|
|
@@ -29,35 +27,67 @@ export type ResolvedSimpleGoAccount = {
|
|
|
29
27
|
pollIntervalMs: number;
|
|
30
28
|
};
|
|
31
29
|
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
function resolveAdpOpenclawCredentials(channelCfg?: AdpOpenclawChannelConfig): {
|
|
31
|
+
serverUrl: string;
|
|
32
|
+
apiToken: string;
|
|
33
|
+
pollIntervalMs: number;
|
|
34
|
+
} | null {
|
|
35
|
+
// Get serverUrl: support both serverUrl and wsUrl
|
|
36
|
+
let serverUrl = channelCfg?.serverUrl?.trim();
|
|
37
|
+
if (!serverUrl && channelCfg?.wsUrl) {
|
|
38
|
+
// Convert ws://host:port/ws to http://host:port
|
|
39
|
+
serverUrl = channelCfg.wsUrl
|
|
40
|
+
.replace(/^wss:\/\//, "https://")
|
|
41
|
+
.replace(/^ws:\/\//, "http://")
|
|
42
|
+
.replace(/\/ws\/?$/, "");
|
|
43
|
+
}
|
|
44
|
+
if (!serverUrl) {
|
|
45
|
+
serverUrl = process.env.ADP_OPENCLAW_SERVER_URL || "";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Get apiToken: support both apiToken and clientToken
|
|
49
|
+
let apiToken = channelCfg?.apiToken?.trim();
|
|
50
|
+
if (!apiToken && channelCfg?.clientToken) {
|
|
51
|
+
apiToken = channelCfg.clientToken.trim();
|
|
52
|
+
}
|
|
53
|
+
if (!apiToken) {
|
|
54
|
+
apiToken = process.env.ADP_OPENCLAW_API_TOKEN || "";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Both are required for configured status
|
|
58
|
+
if (!serverUrl || !apiToken) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const pollIntervalMs = channelCfg?.pollIntervalMs ?? 1000;
|
|
63
|
+
|
|
64
|
+
return { serverUrl, apiToken, pollIntervalMs };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function resolveAccount(cfg: ClawdbotConfig, accountId?: string): ResolvedAdpOpenclawAccount {
|
|
68
|
+
const channelCfg = cfg.channels?.["adp-openclaw"] as AdpOpenclawChannelConfig | undefined;
|
|
69
|
+
const enabled = channelCfg?.enabled !== false;
|
|
70
|
+
const creds = resolveAdpOpenclawCredentials(channelCfg);
|
|
41
71
|
|
|
42
72
|
return {
|
|
43
|
-
accountId: accountId || DEFAULT_ACCOUNT_ID,
|
|
44
|
-
name: "
|
|
45
|
-
enabled
|
|
46
|
-
configured: Boolean(
|
|
47
|
-
serverUrl,
|
|
48
|
-
apiToken,
|
|
49
|
-
pollIntervalMs:
|
|
73
|
+
accountId: accountId?.trim() || DEFAULT_ACCOUNT_ID,
|
|
74
|
+
name: "ADP OpenClaw",
|
|
75
|
+
enabled,
|
|
76
|
+
configured: Boolean(creds),
|
|
77
|
+
serverUrl: creds?.serverUrl || "http://localhost:9876",
|
|
78
|
+
apiToken: creds?.apiToken || "",
|
|
79
|
+
pollIntervalMs: creds?.pollIntervalMs || 1000,
|
|
50
80
|
};
|
|
51
81
|
}
|
|
52
82
|
|
|
53
|
-
export const
|
|
54
|
-
id: "
|
|
83
|
+
export const adpOpenclawPlugin: ChannelPlugin<ResolvedAdpOpenclawAccount> = {
|
|
84
|
+
id: "adp-openclaw",
|
|
55
85
|
meta: {
|
|
56
|
-
id: "
|
|
57
|
-
label: "
|
|
58
|
-
selectionLabel: "
|
|
59
|
-
docsPath: "/channels/
|
|
60
|
-
blurb: "
|
|
86
|
+
id: "adp-openclaw",
|
|
87
|
+
label: "ADP OpenClaw",
|
|
88
|
+
selectionLabel: "ADP OpenClaw",
|
|
89
|
+
docsPath: "/channels/adp-openclaw",
|
|
90
|
+
blurb: "ADP channel backed by a Go WebSocket server.",
|
|
61
91
|
order: 999,
|
|
62
92
|
},
|
|
63
93
|
capabilities: {
|
|
@@ -67,27 +97,48 @@ export const simpleGoPlugin: ChannelPlugin<ResolvedSimpleGoAccount> = {
|
|
|
67
97
|
threads: false,
|
|
68
98
|
media: false,
|
|
69
99
|
},
|
|
70
|
-
reload: { configPrefixes: ["channels.
|
|
100
|
+
reload: { configPrefixes: ["channels.adp-openclaw"] },
|
|
101
|
+
configSchema: {
|
|
102
|
+
schema: {
|
|
103
|
+
type: "object",
|
|
104
|
+
additionalProperties: false,
|
|
105
|
+
properties: {
|
|
106
|
+
enabled: { type: "boolean" },
|
|
107
|
+
serverUrl: { type: "string" },
|
|
108
|
+
wsUrl: { type: "string" },
|
|
109
|
+
apiToken: { type: "string" },
|
|
110
|
+
clientToken: { type: "string" },
|
|
111
|
+
pollIntervalMs: { type: "integer", minimum: 100 },
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
},
|
|
71
115
|
config: {
|
|
72
116
|
listAccountIds: () => [DEFAULT_ACCOUNT_ID],
|
|
73
|
-
resolveAccount: (cfg
|
|
117
|
+
resolveAccount: (cfg) => resolveAccount(cfg),
|
|
74
118
|
defaultAccountId: () => DEFAULT_ACCOUNT_ID,
|
|
75
|
-
setAccountEnabled: ({ cfg,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
119
|
+
setAccountEnabled: ({ cfg, enabled }) => ({
|
|
120
|
+
...cfg,
|
|
121
|
+
channels: {
|
|
122
|
+
...cfg.channels,
|
|
123
|
+
"adp-openclaw": {
|
|
124
|
+
...cfg.channels?.["adp-openclaw"],
|
|
125
|
+
enabled,
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
}),
|
|
129
|
+
deleteAccount: ({ cfg }) => {
|
|
130
|
+
const next = { ...cfg } as ClawdbotConfig;
|
|
131
|
+
const nextChannels = { ...cfg.channels };
|
|
132
|
+
delete (nextChannels as Record<string, unknown>)["adp-openclaw"];
|
|
133
|
+
if (Object.keys(nextChannels).length > 0) {
|
|
134
|
+
next.channels = nextChannels;
|
|
135
|
+
} else {
|
|
136
|
+
delete next.channels;
|
|
137
|
+
}
|
|
138
|
+
return next;
|
|
139
|
+
},
|
|
140
|
+
isConfigured: (_account, cfg) =>
|
|
141
|
+
Boolean(resolveAdpOpenclawCredentials(cfg.channels?.["adp-openclaw"] as AdpOpenclawChannelConfig | undefined)),
|
|
91
142
|
describeAccount: (account) => ({
|
|
92
143
|
accountId: account.accountId,
|
|
93
144
|
name: account.name,
|
|
@@ -100,38 +151,16 @@ export const simpleGoPlugin: ChannelPlugin<ResolvedSimpleGoAccount> = {
|
|
|
100
151
|
},
|
|
101
152
|
setup: {
|
|
102
153
|
resolveAccountId: () => DEFAULT_ACCOUNT_ID,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
if (!apiToken?.trim()) {
|
|
112
|
-
return "Simple Go requires --token (API token)";
|
|
113
|
-
}
|
|
114
|
-
return null;
|
|
115
|
-
},
|
|
116
|
-
applyAccountConfig: ({ cfg, input }) => {
|
|
117
|
-
const existing = (cfg as SimpleGoConfig).channels?.simplego ?? {};
|
|
118
|
-
// Accept both standard names and custom names
|
|
119
|
-
const serverUrl = input.url || input.serverUrl;
|
|
120
|
-
const apiToken = input.token || input.apiToken;
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
...cfg,
|
|
124
|
-
channels: {
|
|
125
|
-
...(cfg as SimpleGoConfig).channels,
|
|
126
|
-
simplego: {
|
|
127
|
-
...existing,
|
|
128
|
-
enabled: true,
|
|
129
|
-
serverUrl: serverUrl?.trim() || existing.serverUrl || "http://localhost:9876",
|
|
130
|
-
apiToken: apiToken?.trim() || existing.apiToken,
|
|
131
|
-
},
|
|
154
|
+
applyAccountConfig: ({ cfg }) => ({
|
|
155
|
+
...cfg,
|
|
156
|
+
channels: {
|
|
157
|
+
...cfg.channels,
|
|
158
|
+
"adp-openclaw": {
|
|
159
|
+
...cfg.channels?.["adp-openclaw"],
|
|
160
|
+
enabled: true,
|
|
132
161
|
},
|
|
133
|
-
}
|
|
134
|
-
},
|
|
162
|
+
},
|
|
163
|
+
}),
|
|
135
164
|
},
|
|
136
165
|
status: {
|
|
137
166
|
defaultRuntime: {
|
|
@@ -151,7 +180,7 @@ export const simpleGoPlugin: ChannelPlugin<ResolvedSimpleGoAccount> = {
|
|
|
151
180
|
lastError: snapshot.lastError ?? null,
|
|
152
181
|
}),
|
|
153
182
|
probeAccount: async ({ cfg, timeoutMs }) => {
|
|
154
|
-
const account = resolveAccount(cfg
|
|
183
|
+
const account = resolveAccount(cfg);
|
|
155
184
|
const start = Date.now();
|
|
156
185
|
try {
|
|
157
186
|
const controller = new AbortController();
|
|
@@ -188,15 +217,16 @@ export const simpleGoPlugin: ChannelPlugin<ResolvedSimpleGoAccount> = {
|
|
|
188
217
|
startAccount: async (ctx) => {
|
|
189
218
|
const account = ctx.account;
|
|
190
219
|
ctx.setStatus({ accountId: account.accountId, baseUrl: account.serverUrl });
|
|
191
|
-
ctx.log?.info(`[
|
|
220
|
+
ctx.log?.info(`[adp-openclaw] starting poll loop → ${account.serverUrl}`);
|
|
192
221
|
|
|
193
|
-
const {
|
|
194
|
-
return
|
|
222
|
+
const { monitorAdpOpenclaw } = await import("./monitor.js");
|
|
223
|
+
return monitorAdpOpenclaw({
|
|
195
224
|
serverUrl: account.serverUrl,
|
|
196
225
|
apiToken: account.apiToken,
|
|
197
226
|
pollIntervalMs: account.pollIntervalMs,
|
|
198
227
|
abortSignal: ctx.abortSignal,
|
|
199
228
|
log: ctx.log,
|
|
229
|
+
cfg: ctx.cfg,
|
|
200
230
|
});
|
|
201
231
|
},
|
|
202
232
|
},
|
|
@@ -212,7 +242,7 @@ export const simpleGoPlugin: ChannelPlugin<ResolvedSimpleGoAccount> = {
|
|
|
212
242
|
tenantId?: string;
|
|
213
243
|
};
|
|
214
244
|
}) => {
|
|
215
|
-
const account = resolveAccount(cfg as
|
|
245
|
+
const account = resolveAccount(cfg as ClawdbotConfig);
|
|
216
246
|
const conversationId = context?.conversationId || "";
|
|
217
247
|
|
|
218
248
|
// Extract user info from context for response tracing
|
package/src/config-schema.ts
CHANGED