@dcrays/dcgchat 0.1.10 → 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 +2 -2
- package/index.ts +4 -4
- package/package.json +6 -16
- package/src/api.ts +24 -1
- package/src/bot.ts +138 -77
- package/src/channel.ts +81 -29
- package/src/libs/mime-types-3.0.2.tgz +0 -0
- package/src/monitor.ts +6 -1
- package/src/oss.ts +2 -2
- package/src/request.ts +10 -3
- package/src/runtime.ts +6 -4
- package/src/skill.ts +3 -3
- package/src/tool.ts +53 -33
- package/src/types.ts +13 -1
package/README.md
CHANGED
package/index.ts
CHANGED
|
@@ -2,16 +2,16 @@ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
|
2
2
|
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
3
3
|
import { dcgchatPlugin } from "./src/channel.js";
|
|
4
4
|
import { setDcgchatRuntime, setWorkspaceDir } from "./src/runtime.js";
|
|
5
|
-
import { monitoringToolMessage } from "./src/tool.js";
|
|
5
|
+
// import { monitoringToolMessage } from "./src/tool.js";
|
|
6
6
|
|
|
7
7
|
const plugin = {
|
|
8
8
|
id: "dcgchat",
|
|
9
|
-
name: "
|
|
10
|
-
description: "连接 OpenClaw 与
|
|
9
|
+
name: "书灵墨宝",
|
|
10
|
+
description: "连接 OpenClaw 与 书灵墨宝 产品(WebSocket)",
|
|
11
11
|
configSchema: emptyPluginConfigSchema(),
|
|
12
12
|
register(api: OpenClawPluginApi) {
|
|
13
13
|
setDcgchatRuntime(api.runtime);
|
|
14
|
-
monitoringToolMessage(api);
|
|
14
|
+
// monitoringToolMessage(api);
|
|
15
15
|
api.registerChannel({ plugin: dcgchatPlugin });
|
|
16
16
|
api.registerTool((ctx) => {
|
|
17
17
|
const workspaceDir = ctx.workspaceDir;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcrays/dcgchat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "OpenClaw channel plugin for
|
|
5
|
+
"description": "OpenClaw channel plugin for 书灵墨宝 (WebSocket)",
|
|
6
6
|
"main": "index.ts",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"files": [
|
|
@@ -21,32 +21,22 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"ali-oss": "file:src/libs/ali-oss-6.23.0.tgz",
|
|
24
|
-
"ws": "file:src/libs/ws-8.19.0.tgz",
|
|
25
24
|
"axios": "file:src/libs/axios-1.13.6.tgz",
|
|
25
|
+
"ws": "file:src/libs/ws-8.19.0.tgz",
|
|
26
26
|
"md5": "file:src/libs/md5-2.3.0.tgz",
|
|
27
27
|
"unzipper": "file:src/libs/unzipper-0.12.3.tgz"
|
|
28
28
|
},
|
|
29
|
-
"devDependencies": {
|
|
30
|
-
"@types/node": "^22.0.0",
|
|
31
|
-
"@types/ws": "^8.5.0",
|
|
32
|
-
"openclaw": "2026.2.13",
|
|
33
|
-
"tsx": "^4.19.0",
|
|
34
|
-
"typescript": "^5.7.0"
|
|
35
|
-
},
|
|
36
|
-
"peerDependencies": {
|
|
37
|
-
"openclaw": ">=2026.2.13"
|
|
38
|
-
},
|
|
39
29
|
"openclaw": {
|
|
40
30
|
"extensions": [
|
|
41
31
|
"./index.ts"
|
|
42
32
|
],
|
|
43
33
|
"channel": {
|
|
44
34
|
"id": "dcgchat",
|
|
45
|
-
"label": "
|
|
46
|
-
"selectionLabel": "
|
|
35
|
+
"label": "书灵墨宝",
|
|
36
|
+
"selectionLabel": "书灵墨宝",
|
|
47
37
|
"docsPath": "/channels/dcgchat",
|
|
48
38
|
"docsLabel": "dcgchat",
|
|
49
|
-
"blurb": "连接 OpenClaw 与
|
|
39
|
+
"blurb": "连接 OpenClaw 与 书灵墨宝 产品",
|
|
50
40
|
"order": 80
|
|
51
41
|
},
|
|
52
42
|
"install": {
|
package/src/api.ts
CHANGED
|
@@ -10,7 +10,7 @@ export const getStsToken = async (name: string, botToken: string) => {
|
|
|
10
10
|
"/user/getStsToken",
|
|
11
11
|
{
|
|
12
12
|
sourceFileName: name,
|
|
13
|
-
isPrivate:
|
|
13
|
+
isPrivate: 1,
|
|
14
14
|
},
|
|
15
15
|
{ botToken },
|
|
16
16
|
);
|
|
@@ -21,6 +21,29 @@ export const getStsToken = async (name: string, botToken: string) => {
|
|
|
21
21
|
|
|
22
22
|
return response.data;
|
|
23
23
|
};
|
|
24
|
+
export const generateSignUrl = async (file_url: string, botToken: string) => {
|
|
25
|
+
try {
|
|
26
|
+
// 确保 userToken 已缓存(如果未缓存会自动获取并缓存)
|
|
27
|
+
await getUserToken(botToken);
|
|
28
|
+
|
|
29
|
+
const response = await post<any>(
|
|
30
|
+
"/user/generateSignUrl",
|
|
31
|
+
{
|
|
32
|
+
loudPlatform: 0,
|
|
33
|
+
fileName: file_url
|
|
34
|
+
},
|
|
35
|
+
{ botToken },
|
|
36
|
+
);
|
|
37
|
+
if (response.code === 0 && response.data) {
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
return response.data?.filePath
|
|
40
|
+
}
|
|
41
|
+
return ''
|
|
42
|
+
|
|
43
|
+
} catch (error) {
|
|
44
|
+
return ''
|
|
45
|
+
}
|
|
46
|
+
};
|
|
24
47
|
|
|
25
48
|
/**
|
|
26
49
|
* 通过 botToken 查询 userToken
|
package/src/bot.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import type { ClawdbotConfig, ReplyPayload, RuntimeEnv } from "openclaw/plugin-sdk";
|
|
3
4
|
import { createReplyPrefixContext } from "openclaw/plugin-sdk";
|
|
4
5
|
import type { InboundMessage, OutboundReply } from "./types.js";
|
|
5
6
|
import { getDcgchatRuntime } from "./runtime.js";
|
|
6
7
|
import { resolveAccount } from "./channel.js";
|
|
7
8
|
import { setMsgStatus } from "./tool.js";
|
|
9
|
+
import { generateSignUrl } from "./api.js";
|
|
10
|
+
import { ossUpload } from "./oss.js";
|
|
8
11
|
|
|
9
12
|
type MediaInfo = {
|
|
10
13
|
path: string;
|
|
@@ -12,63 +15,53 @@ type MediaInfo = {
|
|
|
12
15
|
placeholder: string;
|
|
13
16
|
};
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
maxBytes: number,
|
|
18
|
-
log?: (msg: string) => void,
|
|
19
|
-
): Promise<MediaInfo[]> {
|
|
18
|
+
const mediaMaxBytes = 300 * 1024 * 1024;
|
|
19
|
+
async function resolveMediaFromUrls(files: { name: string, url: string }[], botToken: string, log: (message: string) => void): Promise<MediaInfo[]> {
|
|
20
20
|
const core = getDcgchatRuntime();
|
|
21
21
|
const out: MediaInfo[] = [];
|
|
22
|
+
log(`dcgchat media: starting resolve for ${files.length} file(s): ${JSON.stringify(files)}`);
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
for (let i = 0; i < fileUrls.length; i++) {
|
|
26
|
-
const url = fileUrls[i];
|
|
27
|
-
log?.(`dcgchat media: [${i + 1}/${fileUrls.length}] fetching ${url}`);
|
|
24
|
+
for (let i = 0; i < files.length; i++) {
|
|
25
|
+
const file = files[i];
|
|
28
26
|
try {
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
let data = ''
|
|
28
|
+
if (/^https?:\/\//i.test(file.url)) {
|
|
29
|
+
data = file.url
|
|
30
|
+
} else {
|
|
31
|
+
data = await generateSignUrl(file.url, botToken);
|
|
32
|
+
}
|
|
33
|
+
log(`dcgchat media: [${i + 1}/${files.length}] generateSignUrl: ${data}`);
|
|
34
|
+
const response = await fetch(data);
|
|
31
35
|
if (!response.ok) {
|
|
32
|
-
log?.(`dcgchat media: [${i + 1}/${
|
|
36
|
+
log?.(`dcgchat media: [${i + 1}/${files.length}] fetch failed with HTTP ${response.status}, skipping`);
|
|
33
37
|
continue;
|
|
34
38
|
}
|
|
35
39
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
36
|
-
log?.(`dcgchat media: [${i + 1}/${fileUrls.length}] downloaded buffer size=${buffer.length} bytes`);
|
|
37
40
|
|
|
38
41
|
let contentType = response.headers.get("content-type") || "";
|
|
39
42
|
if (!contentType) {
|
|
40
|
-
|
|
41
|
-
// @ts-ignore
|
|
42
|
-
contentType = await core.media.detectMime({ buffer });
|
|
43
|
+
contentType = await core.media.detectMime({ buffer }) || "";
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const fileName = path.basename(new URL(url).pathname) || "file";
|
|
47
|
-
log?.(`dcgchat media: [${i + 1}/${fileUrls.length}] fileName=${fileName}, saving to disk (maxBytes=${maxBytes})...`);
|
|
48
|
-
|
|
45
|
+
const fileName = file.name || path.basename(new URL(file.url).pathname) || "file";
|
|
49
46
|
const saved = await core.channel.media.saveMediaBuffer(
|
|
50
47
|
buffer,
|
|
51
48
|
contentType,
|
|
52
49
|
"inbound",
|
|
53
|
-
|
|
50
|
+
mediaMaxBytes,
|
|
54
51
|
fileName,
|
|
55
52
|
);
|
|
56
|
-
|
|
57
53
|
const isImage = contentType.startsWith("image/");
|
|
58
54
|
out.push({
|
|
59
55
|
path: saved.path,
|
|
60
|
-
|
|
61
|
-
contentType: saved.contentType,
|
|
56
|
+
contentType: saved.contentType || "",
|
|
62
57
|
placeholder: isImage ? "<media:image>" : "<media:file>",
|
|
63
58
|
});
|
|
64
59
|
|
|
65
|
-
log?.(`dcgchat media: [${i + 1}/${fileUrls.length}] saved to ${saved.path} (contentType=${saved.contentType}, isImage=${isImage})`);
|
|
66
60
|
} catch (err) {
|
|
67
|
-
log
|
|
61
|
+
log(`dcgchat media: [${i + 1}/${files.length}] FAILED to process ${file.url}: ${String(err)}`);
|
|
68
62
|
}
|
|
69
63
|
}
|
|
70
|
-
|
|
71
|
-
log?.(`dcgchat media: resolve complete, ${out.length}/${fileUrls.length} file(s) succeeded`);
|
|
64
|
+
log(`dcgchat media: resolve complete, ${out.length}/${files.length} file(s) succeeded`);
|
|
72
65
|
|
|
73
66
|
return out;
|
|
74
67
|
}
|
|
@@ -111,10 +104,9 @@ export async function handleDcgchatMessage(params: {
|
|
|
111
104
|
|
|
112
105
|
const account = resolveAccount(cfg, accountId);
|
|
113
106
|
const userId = msg._userId.toString();
|
|
114
|
-
// const text = msg.text?.trim();
|
|
115
107
|
const text = msg.content.text?.trim();
|
|
116
108
|
|
|
117
|
-
if (!
|
|
109
|
+
if (!text) {
|
|
118
110
|
params.onChunk({
|
|
119
111
|
messageType: "openclaw_bot_chat",
|
|
120
112
|
_userId: msg._userId,
|
|
@@ -122,9 +114,13 @@ export async function handleDcgchatMessage(params: {
|
|
|
122
114
|
// @ts-ignore
|
|
123
115
|
content: {
|
|
124
116
|
bot_token: msg.content.bot_token,
|
|
117
|
+
domain_id: msg.content.domain_id,
|
|
118
|
+
app_id: msg.content.app_id,
|
|
119
|
+
bot_id: msg.content.bot_id,
|
|
120
|
+
agent_id: msg.content.agent_id,
|
|
125
121
|
session_id: msg.content.session_id,
|
|
126
122
|
message_id: msg.content.message_id,
|
|
127
|
-
response: "
|
|
123
|
+
response: "你需要我帮你做什么呢?",
|
|
128
124
|
},
|
|
129
125
|
});
|
|
130
126
|
return;
|
|
@@ -135,28 +131,26 @@ export async function handleDcgchatMessage(params: {
|
|
|
135
131
|
|
|
136
132
|
const route = core.channel.routing.resolveAgentRoute({
|
|
137
133
|
cfg,
|
|
138
|
-
channel: "dcgchat",
|
|
134
|
+
channel: "dcgchat-test",
|
|
139
135
|
accountId: account.accountId,
|
|
140
136
|
peer: { kind: "direct", id: userId },
|
|
141
137
|
});
|
|
142
138
|
|
|
143
139
|
// 处理用户上传的文件
|
|
144
|
-
const
|
|
145
|
-
log(`dcgchat[${accountId}]: incoming message from user=${userId}, text="${text?.slice(0, 80)}", file_urls count=${fileUrls.length}`);
|
|
140
|
+
const files = msg.content.files ?? [];
|
|
146
141
|
let mediaPayload: Record<string, unknown> = {};
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
const mediaMaxBytes = 30 * 1024 * 1024;
|
|
150
|
-
const mediaList = await resolveMediaFromUrls(fileUrls, mediaMaxBytes, log);
|
|
142
|
+
if (files.length > 0) {
|
|
143
|
+
const mediaList = await resolveMediaFromUrls(files, msg.content.bot_token, log)
|
|
151
144
|
mediaPayload = buildMediaPayload(mediaList);
|
|
152
|
-
log(`dcgchat[${accountId}]: media resolved ${mediaList.length}/${
|
|
145
|
+
log(`dcgchat[${accountId}]: media resolved ${mediaList.length}/${files.length} file(s), payload=${JSON.stringify(mediaList)}`);
|
|
153
146
|
}
|
|
154
147
|
|
|
155
148
|
const envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(cfg);
|
|
156
149
|
// const messageBody = `${userId}: ${text}`;
|
|
150
|
+
// 补充消息
|
|
157
151
|
const messageBody = text;
|
|
158
152
|
const bodyFormatted = core.channel.reply.formatAgentEnvelope({
|
|
159
|
-
channel: "
|
|
153
|
+
channel: "书灵墨宝",
|
|
160
154
|
from: userId,
|
|
161
155
|
timestamp: new Date(),
|
|
162
156
|
envelope: envelopeOptions,
|
|
@@ -174,19 +168,21 @@ export async function handleDcgchatMessage(params: {
|
|
|
174
168
|
ChatType: "direct",
|
|
175
169
|
SenderName: userId,
|
|
176
170
|
SenderId: userId,
|
|
177
|
-
Provider: "dcgchat" as const,
|
|
178
|
-
Surface: "dcgchat" as const,
|
|
171
|
+
Provider: "dcgchat-test" as const,
|
|
172
|
+
Surface: "dcgchat-test" as const,
|
|
179
173
|
MessageSid: msg.content.message_id,
|
|
180
174
|
Timestamp: Date.now(),
|
|
181
175
|
WasMentioned: true,
|
|
182
176
|
CommandAuthorized: true,
|
|
183
|
-
OriginatingChannel: "dcgchat" as const,
|
|
177
|
+
OriginatingChannel: "dcgchat-test" as const,
|
|
184
178
|
OriginatingTo: `user:${userId}`,
|
|
185
179
|
...mediaPayload,
|
|
186
180
|
});
|
|
187
181
|
|
|
188
182
|
log(`dcgchat[${accountId}]: ctxPayload=${JSON.stringify(ctxPayload)}`);
|
|
189
183
|
|
|
184
|
+
let textChunk = ''
|
|
185
|
+
|
|
190
186
|
const prefixContext = createReplyPrefixContext({ cfg, agentId: route.agentId });
|
|
191
187
|
|
|
192
188
|
const { dispatcher, replyOptions, markDispatchIdle } =
|
|
@@ -195,46 +191,102 @@ export async function handleDcgchatMessage(params: {
|
|
|
195
191
|
responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
|
|
196
192
|
humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, route.agentId),
|
|
197
193
|
onReplyStart: async () => {},
|
|
198
|
-
deliver: async (payload) => {
|
|
194
|
+
deliver: async (payload: { text: string | any[]; }) => {
|
|
199
195
|
log(`dcgchat[${accountId}][deliver]: received chunk, text length=${payload.text?.length || 0}`);
|
|
200
|
-
const t = payload.text?.trim();
|
|
201
|
-
if (t) {
|
|
202
|
-
log(`dcgchat[${accountId}][deliver]: sending chunk to user ${msg._userId}, text="${t.slice(0, 50)}..."`);
|
|
203
|
-
params.onChunk({
|
|
204
|
-
messageType: "openclaw_bot_chat",
|
|
205
|
-
_userId: msg._userId,
|
|
206
|
-
source: "client",
|
|
207
|
-
content: {
|
|
208
|
-
bot_token: msg.content.bot_token,
|
|
209
|
-
session_id: msg.content.session_id,
|
|
210
|
-
message_id: msg.content.message_id,
|
|
211
|
-
response: t,
|
|
212
|
-
state: 'chunk',
|
|
213
|
-
},
|
|
214
|
-
});
|
|
215
|
-
log(`dcgchat[${accountId}][deliver]: chunk sent successfully`);
|
|
216
|
-
} else {
|
|
217
|
-
log(`dcgchat[${accountId}][deliver]: skipping empty chunk`);
|
|
218
|
-
}
|
|
219
196
|
},
|
|
220
|
-
onError: (err, info) => {
|
|
197
|
+
onError: (err: any, info: { kind: any; }) => {
|
|
221
198
|
error(`dcgchat[${accountId}] ${info.kind} reply failed: ${String(err)}`);
|
|
222
199
|
},
|
|
223
200
|
onIdle: () => {},
|
|
224
201
|
});
|
|
225
202
|
|
|
226
|
-
|
|
203
|
+
if (text === '/new') {
|
|
204
|
+
log(`dcgchat[${accountId}]: skipping agent dispatch for /new`);
|
|
205
|
+
await core.channel.reply.dispatchReplyFromConfig({
|
|
206
|
+
ctx: ctxPayload,
|
|
207
|
+
cfg,
|
|
208
|
+
dispatcher,
|
|
209
|
+
replyOptions: {
|
|
210
|
+
...replyOptions,
|
|
211
|
+
onModelSelected: prefixContext.onModelSelected
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
} else {
|
|
215
|
+
log(`dcgchat[${accountId}]: dispatching to agent (session=${route.sessionKey})`);
|
|
216
|
+
await core.channel.reply.dispatchReplyFromConfig({
|
|
217
|
+
ctx: ctxPayload,
|
|
218
|
+
cfg,
|
|
219
|
+
dispatcher,
|
|
220
|
+
replyOptions: {
|
|
221
|
+
...replyOptions,
|
|
222
|
+
onModelSelected: prefixContext.onModelSelected,
|
|
223
|
+
onPartialReply: async (payload: ReplyPayload) => {
|
|
224
|
+
log(`dcgchat[${accountId}][deliver]: received chunk, text length=${payload.text?.length || 0}`);
|
|
225
|
+
const mediaList =
|
|
226
|
+
payload.mediaUrls && payload.mediaUrls.length > 0
|
|
227
|
+
? payload.mediaUrls
|
|
228
|
+
: payload.mediaUrl
|
|
229
|
+
? [payload.mediaUrl]
|
|
230
|
+
: [];
|
|
231
|
+
if (mediaList.length > 0) {
|
|
232
|
+
const files = []
|
|
233
|
+
for (let i = 0; i < mediaList.length; i++) {
|
|
234
|
+
const file = mediaList[i]
|
|
235
|
+
const fileName = file.split(/[\\/]/).pop() || ''
|
|
236
|
+
const url = await ossUpload(file, msg.content.bot_token)
|
|
237
|
+
files.push({
|
|
238
|
+
url: url,
|
|
239
|
+
name: fileName,
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
params.onChunk({
|
|
243
|
+
messageType: "openclaw_bot_chat",
|
|
244
|
+
_userId: msg._userId,
|
|
245
|
+
source: "client",
|
|
246
|
+
content: {
|
|
247
|
+
bot_token: msg.content.bot_token,
|
|
248
|
+
domain_id: msg.content.domain_id,
|
|
249
|
+
app_id: msg.content.app_id,
|
|
250
|
+
bot_id: msg.content.bot_id,
|
|
251
|
+
agent_id: msg.content.agent_id,
|
|
252
|
+
session_id: msg.content.session_id,
|
|
253
|
+
message_id: msg.content.message_id,
|
|
254
|
+
response: '',
|
|
255
|
+
files: files,
|
|
256
|
+
state: 'chunk',
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
if (payload.text) {
|
|
261
|
+
log(`dcgchat[${accountId}][deliver]: sending chunk to user ${msg._userId}, text="${payload.text.slice(0, 50)}..."`);
|
|
262
|
+
params.onChunk({
|
|
263
|
+
messageType: "openclaw_bot_chat",
|
|
264
|
+
_userId: msg._userId,
|
|
265
|
+
source: "client",
|
|
266
|
+
content: {
|
|
267
|
+
bot_token: msg.content.bot_token,
|
|
268
|
+
domain_id: msg.content.domain_id,
|
|
269
|
+
app_id: msg.content.app_id,
|
|
270
|
+
bot_id: msg.content.bot_id,
|
|
271
|
+
agent_id: msg.content.agent_id,
|
|
272
|
+
session_id: msg.content.session_id,
|
|
273
|
+
message_id: msg.content.message_id,
|
|
274
|
+
response: payload.text.replace(textChunk, ''),
|
|
275
|
+
state: 'chunk',
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
textChunk = payload.text
|
|
279
|
+
log(`dcgchat[${accountId}][deliver]: chunk sent successfully`);
|
|
280
|
+
} else if (payload.mediaUrl && payload.mediaUrls) {
|
|
227
281
|
|
|
228
|
-
await core.channel.reply.dispatchReplyFromConfig({
|
|
229
|
-
ctx: ctxPayload,
|
|
230
|
-
cfg,
|
|
231
|
-
dispatcher,
|
|
232
|
-
replyOptions: {
|
|
233
|
-
...replyOptions,
|
|
234
|
-
onModelSelected: prefixContext.onModelSelected,
|
|
235
|
-
},
|
|
236
|
-
});
|
|
237
282
|
|
|
283
|
+
} else {
|
|
284
|
+
log(`dcgchat[${accountId}][deliver]: skipping empty chunk`);
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
});
|
|
289
|
+
}
|
|
238
290
|
log(`dcgchat[${accountId}]: dispatch complete, sending final state`);
|
|
239
291
|
params.onChunk({
|
|
240
292
|
messageType: "openclaw_bot_chat",
|
|
@@ -242,6 +294,10 @@ export async function handleDcgchatMessage(params: {
|
|
|
242
294
|
source: "client",
|
|
243
295
|
content: {
|
|
244
296
|
bot_token: msg.content.bot_token,
|
|
297
|
+
domain_id: msg.content.domain_id,
|
|
298
|
+
app_id: msg.content.app_id,
|
|
299
|
+
bot_id: msg.content.bot_id,
|
|
300
|
+
agent_id: msg.content.agent_id,
|
|
245
301
|
session_id: msg.content.session_id,
|
|
246
302
|
message_id: msg.content.message_id,
|
|
247
303
|
response: '',
|
|
@@ -249,6 +305,7 @@ export async function handleDcgchatMessage(params: {
|
|
|
249
305
|
},
|
|
250
306
|
});
|
|
251
307
|
setMsgStatus('finished');
|
|
308
|
+
textChunk = ''
|
|
252
309
|
log(`dcgchat[${accountId}]: final state sent`);
|
|
253
310
|
|
|
254
311
|
markDispatchIdle();
|
|
@@ -262,6 +319,10 @@ export async function handleDcgchatMessage(params: {
|
|
|
262
319
|
source: "client",
|
|
263
320
|
content: {
|
|
264
321
|
bot_token: msg.content.bot_token,
|
|
322
|
+
domain_id: msg.content.domain_id,
|
|
323
|
+
app_id: msg.content.app_id,
|
|
324
|
+
bot_id: msg.content.bot_id,
|
|
325
|
+
agent_id: msg.content.agent_id,
|
|
265
326
|
session_id: msg.content.session_id,
|
|
266
327
|
message_id: msg.content.message_id,
|
|
267
328
|
response: `[错误] ${err instanceof Error ? err.message : String(err)}`,
|
package/src/channel.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { ChannelPlugin, OpenClawConfig } from "openclaw/plugin-sdk";
|
|
2
2
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk";
|
|
3
3
|
import type { ResolvedDcgchatAccount, DcgchatConfig } from "./types.js";
|
|
4
|
-
import { logDcgchat } from "./log.js";
|
|
5
4
|
import { getWsConnection } from "./connection.js";
|
|
6
5
|
import { ossUpload } from "./oss.js";
|
|
7
6
|
import { getMsgParams } from "./tool.js";
|
|
8
7
|
|
|
8
|
+
|
|
9
9
|
export function resolveAccount(cfg: OpenClawConfig, accountId?: string | null): ResolvedDcgchatAccount {
|
|
10
10
|
const id = accountId ?? DEFAULT_ACCOUNT_ID;
|
|
11
|
-
const raw = (cfg.channels?.["dcgchat"] as DcgchatConfig | undefined) ?? {};
|
|
11
|
+
const raw = (cfg.channels?.["dcgchat-test"] as DcgchatConfig | undefined) ?? {};
|
|
12
12
|
return {
|
|
13
13
|
accountId: id,
|
|
14
14
|
enabled: raw.enabled !== false,
|
|
@@ -22,14 +22,14 @@ export function resolveAccount(cfg: OpenClawConfig, accountId?: string | null):
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
25
|
-
id: "dcgchat",
|
|
25
|
+
id: "dcgchat-test",
|
|
26
26
|
meta: {
|
|
27
|
-
id: "dcgchat",
|
|
28
|
-
label: "
|
|
29
|
-
selectionLabel: "
|
|
27
|
+
id: "dcgchat-test",
|
|
28
|
+
label: "书灵墨宝",
|
|
29
|
+
selectionLabel: "书灵墨宝",
|
|
30
30
|
docsPath: "/channels/dcgchat",
|
|
31
|
-
docsLabel: "dcgchat",
|
|
32
|
-
blurb: "连接 OpenClaw 与
|
|
31
|
+
docsLabel: "dcgchat-test",
|
|
32
|
+
blurb: "连接 OpenClaw 与 书灵墨宝 产品",
|
|
33
33
|
order: 80,
|
|
34
34
|
},
|
|
35
35
|
capabilities: {
|
|
@@ -68,8 +68,8 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
68
68
|
...cfg,
|
|
69
69
|
channels: {
|
|
70
70
|
...cfg.channels,
|
|
71
|
-
"dcgchat": {
|
|
72
|
-
...(cfg.channels?.["dcgchat"] as Record<string, unknown> | undefined),
|
|
71
|
+
"dcgchat-test": {
|
|
72
|
+
...(cfg.channels?.["dcgchat-test"] as Record<string, unknown> | undefined),
|
|
73
73
|
enabled,
|
|
74
74
|
},
|
|
75
75
|
},
|
|
@@ -98,77 +98,129 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
98
98
|
// textChunkLimit: 25,
|
|
99
99
|
textChunkLimit: 4000,
|
|
100
100
|
sendText: async (ctx) => {
|
|
101
|
-
const target = ctx.to || "(implicit)";
|
|
102
101
|
const ws = getWsConnection()
|
|
103
102
|
const params = getMsgParams();
|
|
103
|
+
const log = ctx.runtime?.log ?? console.log;
|
|
104
104
|
if (ws?.readyState === WebSocket.OPEN) {
|
|
105
105
|
const {botToken} = resolveAccount(ctx.cfg, ctx.accountId);
|
|
106
106
|
const content = {
|
|
107
107
|
messageType: "openclaw_bot_chat",
|
|
108
|
-
_userId:
|
|
108
|
+
_userId: params.userId,
|
|
109
109
|
source: "client",
|
|
110
110
|
content: {
|
|
111
111
|
bot_token: botToken,
|
|
112
|
+
domain_id: params.domainId,
|
|
113
|
+
app_id: params.appId,
|
|
114
|
+
bot_id: params.botId,
|
|
115
|
+
agent_id: params.agentId,
|
|
112
116
|
response: ctx.text,
|
|
113
117
|
session_id: params.sessionId,
|
|
114
118
|
message_id: params.messageId || Date.now().toString(),
|
|
115
119
|
},
|
|
116
120
|
};
|
|
117
121
|
ws.send(JSON.stringify(content));
|
|
118
|
-
|
|
122
|
+
ws.send(JSON.stringify({
|
|
123
|
+
messageType: "openclaw_bot_chat",
|
|
124
|
+
_userId: params.userId,
|
|
125
|
+
source: "client",
|
|
126
|
+
content: {
|
|
127
|
+
bot_token: botToken,
|
|
128
|
+
domain_id: params.domainId,
|
|
129
|
+
app_id: params.appId,
|
|
130
|
+
bot_id: params.botId,
|
|
131
|
+
agent_id: params.agentId,
|
|
132
|
+
ssession_id: params.sessionId,
|
|
133
|
+
message_id: params.messageId || Date.now().toString(),
|
|
134
|
+
response: '',
|
|
135
|
+
state: 'final',
|
|
136
|
+
},
|
|
137
|
+
}));
|
|
138
|
+
log(`dcgchat[${ctx.accountId}]: channel sendText to ${params.userId}, ${JSON.stringify(content)}`);
|
|
119
139
|
} else {
|
|
120
|
-
|
|
140
|
+
log(`[dcgchat][${ctx.accountId ?? DEFAULT_ACCOUNT_ID}] outbound -> ${ws?.readyState}: ${ctx.text}`);
|
|
121
141
|
}
|
|
122
142
|
return {
|
|
123
|
-
channel: "dcgchat",
|
|
143
|
+
channel: "dcgchat-test",
|
|
124
144
|
messageId: `dcg-${Date.now()}`,
|
|
125
|
-
chatId:
|
|
145
|
+
chatId: params.userId.toString(),
|
|
126
146
|
};
|
|
127
147
|
},
|
|
128
148
|
sendMedia: async (ctx) => {
|
|
129
|
-
const target = ctx.to || "(implicit)";
|
|
130
149
|
const ws = getWsConnection()
|
|
131
150
|
const params = getMsgParams();
|
|
132
|
-
|
|
151
|
+
const log = ctx.runtime?.log ?? console.log;
|
|
152
|
+
if (ws?.readyState === WebSocket.OPEN) {
|
|
153
|
+
const fileName = ctx.mediaUrl?.split(/[\\/]/).pop() || ''
|
|
133
154
|
const {botToken} = resolveAccount(ctx.cfg, ctx.accountId);
|
|
134
155
|
try {
|
|
135
156
|
const url = ctx.mediaUrl ? await ossUpload(ctx.mediaUrl, botToken) : '';
|
|
136
|
-
const fileName = ctx.mediaUrl?.split(/[\\/]/).pop() || ''
|
|
137
157
|
const content = {
|
|
138
158
|
messageType: "openclaw_bot_chat",
|
|
139
|
-
_userId:
|
|
159
|
+
_userId: params.userId,
|
|
140
160
|
source: "client",
|
|
141
161
|
content: {
|
|
142
162
|
bot_token: botToken,
|
|
143
|
-
|
|
163
|
+
domain_id: params.domainId,
|
|
164
|
+
app_id: params.appId,
|
|
165
|
+
bot_id: params.botId,
|
|
166
|
+
agent_id: params.agentId,
|
|
167
|
+
response: ctx.text,
|
|
168
|
+
files: [{
|
|
169
|
+
url: url,
|
|
170
|
+
name: fileName,
|
|
171
|
+
}],
|
|
144
172
|
session_id: params.sessionId,
|
|
145
173
|
message_id: params.messageId ||Date.now().toString(),
|
|
146
174
|
},
|
|
147
175
|
};
|
|
148
176
|
ws.send(JSON.stringify(content));
|
|
149
|
-
|
|
177
|
+
log(`dcgchat[${ctx.accountId}]: sendMedia alioss to ${params.userId}, ${JSON.stringify(content)}`);
|
|
150
178
|
} catch (error) {
|
|
151
179
|
const content = {
|
|
152
180
|
messageType: "openclaw_bot_chat",
|
|
153
|
-
_userId:
|
|
181
|
+
_userId: params.userId,
|
|
154
182
|
source: "client",
|
|
155
183
|
content: {
|
|
156
184
|
bot_token: botToken,
|
|
157
|
-
|
|
185
|
+
domain_id: params.domainId,
|
|
186
|
+
app_id: params.appId,
|
|
187
|
+
bot_id: params.botId,
|
|
188
|
+
agent_id: params.agentId,
|
|
189
|
+
response: ctx.text,
|
|
190
|
+
files: [{
|
|
191
|
+
url: ctx.mediaUrl,
|
|
192
|
+
name: fileName,
|
|
193
|
+
}],
|
|
158
194
|
session_id: params.sessionId || Date.now().toString(),
|
|
159
|
-
message_id:
|
|
195
|
+
message_id: Date.now().toString(),
|
|
160
196
|
},
|
|
161
197
|
};
|
|
162
198
|
ws.send(JSON.stringify(content));
|
|
163
|
-
|
|
199
|
+
ws.send(JSON.stringify({
|
|
200
|
+
messageType: "openclaw_bot_chat",
|
|
201
|
+
_userId: params.userId,
|
|
202
|
+
source: "client",
|
|
203
|
+
content: {
|
|
204
|
+
bot_token: botToken,
|
|
205
|
+
domain_id: params.domainId,
|
|
206
|
+
app_id: params.appId,
|
|
207
|
+
bot_id: params.botId,
|
|
208
|
+
agent_id: params.agentId,
|
|
209
|
+
ssession_id: params.sessionId,
|
|
210
|
+
message_id: Date.now().toString(),
|
|
211
|
+
response: '',
|
|
212
|
+
state: 'final',
|
|
213
|
+
},
|
|
214
|
+
}));
|
|
215
|
+
log(`dcgchat[${ctx.accountId}]: error sendMedia to ${params.userId}, ${JSON.stringify(content)}`);
|
|
164
216
|
}
|
|
165
217
|
} else {
|
|
166
|
-
|
|
218
|
+
log(`[dcgchat][${ctx.accountId ?? DEFAULT_ACCOUNT_ID}] outbound -> ${ws?.readyState}: ${ctx.text}`);
|
|
167
219
|
}
|
|
168
220
|
return {
|
|
169
|
-
channel: "dcgchat",
|
|
221
|
+
channel: "dcgchat-test",
|
|
170
222
|
messageId: `dcg-${Date.now()}`,
|
|
171
|
-
chatId:
|
|
223
|
+
chatId: params.userId.toString(),
|
|
172
224
|
};
|
|
173
225
|
},
|
|
174
226
|
},
|
|
Binary file
|
package/src/monitor.ts
CHANGED
|
@@ -112,11 +112,16 @@ export async function monitorDcgchatProvider(opts: MonitorDcgchatOpts): Promise<
|
|
|
112
112
|
if (parsed.messageType == "openclaw_bot_chat") {
|
|
113
113
|
const msg = parsed as unknown as InboundMessage;
|
|
114
114
|
setMsgStatus('running');
|
|
115
|
+
log(`dcgchat[${account.accountId}]: openclaw_bot_chat received, ${JSON.stringify(msg)}`);
|
|
115
116
|
setMsgParams({
|
|
116
117
|
userId: msg._userId,
|
|
117
118
|
token: msg.content.bot_token,
|
|
118
119
|
sessionId: msg.content.session_id,
|
|
119
120
|
messageId: msg.content.message_id,
|
|
121
|
+
domainId: account.domainId || 1000,
|
|
122
|
+
appId: account.appId || '100',
|
|
123
|
+
botId: msg.content.bot_id,
|
|
124
|
+
agentId: msg.content.agent_id,
|
|
120
125
|
});
|
|
121
126
|
await handleDcgchatMessage({
|
|
122
127
|
cfg,
|
|
@@ -134,7 +139,7 @@ export async function monitorDcgchatProvider(opts: MonitorDcgchatOpts): Promise<
|
|
|
134
139
|
const { event_type, operation_type, skill_url, skill_code, skill_id, bot_token, websocket_trace_id } = parsed.content ? parsed.content : {} as Record<string, any>;
|
|
135
140
|
const content = { event_type, operation_type, skill_url, skill_code, skill_id, bot_token, websocket_trace_id };
|
|
136
141
|
if (event_type === "skill") {
|
|
137
|
-
if (operation_type === "install" || operation_type === "enable") {
|
|
142
|
+
if (operation_type === "install" || operation_type === "enable" || operation_type === "update") {
|
|
138
143
|
installSkill({ path: skill_url, code: skill_code }, content);
|
|
139
144
|
} else if (operation_type === "remove" || operation_type === "disable") {
|
|
140
145
|
uninstallSkill({ code: skill_code }, content);
|
package/src/oss.ts
CHANGED
|
@@ -61,9 +61,9 @@ export const ossUpload = async (file: File | string | Buffer, botToken: string)
|
|
|
61
61
|
if (objectResult?.res?.status !== 200) {
|
|
62
62
|
throw new Error("OSS 上传失败");
|
|
63
63
|
}
|
|
64
|
-
console.log(objectResult
|
|
64
|
+
console.log(11111, JSON.stringify(objectResult));
|
|
65
65
|
// const url = `${data.protocol || 'http'}://${data.bucket}.${data.endPoint}/${data.uploadDir}${data.ossFileKey}`
|
|
66
|
-
return objectResult.url;
|
|
66
|
+
return objectResult.name || objectResult.url;
|
|
67
67
|
} catch (error) {
|
|
68
68
|
console.error("OSS 上传失败:", error);
|
|
69
69
|
throw error;
|
package/src/request.ts
CHANGED
|
@@ -2,6 +2,7 @@ import axios from "axios";
|
|
|
2
2
|
import md5 from "md5";
|
|
3
3
|
import type { IResponse } from "./types.js";
|
|
4
4
|
import { getUserTokenCache } from "./userInfo.js";
|
|
5
|
+
import { getMsgParams } from "./tool.js";
|
|
5
6
|
|
|
6
7
|
export const apiUrlMap = {
|
|
7
8
|
production: "https://api-gateway.shuwenda.com",
|
|
@@ -178,17 +179,23 @@ export function post<T = Record<string, unknown>, R = unknown>(
|
|
|
178
179
|
botToken?: string;
|
|
179
180
|
},
|
|
180
181
|
): Promise<IResponse<R>> {
|
|
182
|
+
const params = getMsgParams() || {}
|
|
181
183
|
const config: any = {
|
|
182
184
|
method: "POST",
|
|
183
185
|
url,
|
|
184
|
-
data
|
|
185
|
-
|
|
186
|
+
data: {
|
|
187
|
+
...data,
|
|
188
|
+
_appId: params.appId
|
|
189
|
+
},
|
|
190
|
+
headers: buildHeaders({
|
|
191
|
+
...data,
|
|
192
|
+
_appId: params.appId
|
|
193
|
+
} as Record<string, unknown>, url, options?.userToken),
|
|
186
194
|
};
|
|
187
195
|
|
|
188
196
|
// 将 botToken 附加到配置中,供请求拦截器使用
|
|
189
197
|
if (options?.botToken) {
|
|
190
198
|
config.__botToken = options.botToken;
|
|
191
199
|
}
|
|
192
|
-
|
|
193
200
|
return axiosInstance.request(config);
|
|
194
201
|
}
|
package/src/runtime.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
|
2
|
+
import { logDcgchat } from "./log.js";
|
|
2
3
|
|
|
3
4
|
const path = require('path');
|
|
4
5
|
const fs = require('fs');
|
|
6
|
+
const os = require("os")
|
|
7
|
+
|
|
5
8
|
function getWorkspacePath() {
|
|
6
|
-
const
|
|
7
|
-
const workspacePath = path.join(current, '.openclaw/workspace');
|
|
9
|
+
const workspacePath = path.join(os.homedir(), '.openclaw', 'workspace');
|
|
8
10
|
if (fs.existsSync(workspacePath)) {
|
|
9
11
|
return workspacePath;
|
|
10
12
|
}
|
|
@@ -21,7 +23,7 @@ export function setWorkspaceDir(dir?: string) {
|
|
|
21
23
|
}
|
|
22
24
|
export function getWorkspaceDir(): string {
|
|
23
25
|
if (!workspaceDir) {
|
|
24
|
-
|
|
26
|
+
logDcgchat.error("Workspace directory not initialized");
|
|
25
27
|
}
|
|
26
28
|
return workspaceDir;
|
|
27
29
|
}
|
|
@@ -32,7 +34,7 @@ export function setDcgchatRuntime(next: PluginRuntime) {
|
|
|
32
34
|
|
|
33
35
|
export function getDcgchatRuntime(): PluginRuntime {
|
|
34
36
|
if (!runtime) {
|
|
35
|
-
throw new Error("
|
|
37
|
+
throw new Error("书灵墨宝 runtime not initialized");
|
|
36
38
|
}
|
|
37
39
|
return runtime;
|
|
38
40
|
}
|
package/src/skill.ts
CHANGED
|
@@ -116,7 +116,7 @@ export async function installSkill(params: ISkillParams, msgContent: Record<stri
|
|
|
116
116
|
reject(err);
|
|
117
117
|
}
|
|
118
118
|
})
|
|
119
|
-
.on("error", (err) => {
|
|
119
|
+
.on("error", (err: { message: any; }) => {
|
|
120
120
|
hasError = true;
|
|
121
121
|
reject(new Error(`解压流错误: ${err.message}`));
|
|
122
122
|
});
|
|
@@ -136,7 +136,7 @@ export function uninstallSkill(params: Omit<ISkillParams, 'path'>, msgContent: R
|
|
|
136
136
|
|
|
137
137
|
const workspacePath = getWorkspaceDir();
|
|
138
138
|
if (!workspacePath) {
|
|
139
|
-
|
|
139
|
+
sendEvent({ ...msgContent, status: 'ok' })
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
const skillDir = path.join(workspacePath, 'skills', code);
|
|
@@ -145,6 +145,6 @@ export function uninstallSkill(params: Omit<ISkillParams, 'path'>, msgContent: R
|
|
|
145
145
|
fs.rmSync(skillDir, { recursive: true, force: true });
|
|
146
146
|
sendEvent({ ...msgContent, status: 'ok' })
|
|
147
147
|
} else {
|
|
148
|
-
sendEvent({ ...msgContent, status: '
|
|
148
|
+
sendEvent({ ...msgContent, status: 'ok' })
|
|
149
149
|
}
|
|
150
150
|
}
|
package/src/tool.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
|
|
2
2
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
3
3
|
import { getWsConnection } from "./connection.js";
|
|
4
|
-
import { logDcgchat } from "./log.js";
|
|
5
4
|
|
|
6
5
|
let msgParams = {} as {
|
|
7
6
|
userId: number;
|
|
8
|
-
token: string
|
|
9
|
-
sessionId: string
|
|
10
|
-
messageId: string
|
|
7
|
+
token: string;
|
|
8
|
+
sessionId: string;
|
|
9
|
+
messageId: string;
|
|
10
|
+
domainId: string;
|
|
11
|
+
appId: string;
|
|
12
|
+
botId: string;
|
|
13
|
+
agentId: string;
|
|
11
14
|
}
|
|
12
15
|
let msgStatus: 'running' | 'finished' | '' = '';
|
|
13
16
|
export function setMsgParams(params: any) {
|
|
@@ -25,51 +28,68 @@ export function setMsgStatus(status: 'running' | 'finished' | '') {
|
|
|
25
28
|
export function getMsgStatus() {
|
|
26
29
|
return msgStatus;
|
|
27
30
|
}
|
|
28
|
-
|
|
31
|
+
let runId = '';
|
|
32
|
+
let toolName = '';
|
|
29
33
|
export function monitoringToolMessage(api: OpenClawPluginApi) {
|
|
30
|
-
api.on("after_tool_call", (event
|
|
34
|
+
api.on("after_tool_call", (event) => {
|
|
31
35
|
const ws = getWsConnection()
|
|
32
36
|
const params = getMsgParams();
|
|
33
37
|
const status = getMsgStatus();
|
|
34
38
|
//
|
|
35
39
|
if (ws?.readyState === WebSocket.OPEN && status === 'running') {
|
|
40
|
+
const log = api.runtime?.log ?? api.log;
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
if (!runId || runId !== event.runId || !toolName || toolName !== event.toolName) {
|
|
43
|
+
ws.send(JSON.stringify({
|
|
44
|
+
messageType: "openclaw_bot_chat",
|
|
45
|
+
_userId: params?.userId,
|
|
46
|
+
source: "client",
|
|
47
|
+
content: {
|
|
48
|
+
bot_token: params?.token,
|
|
49
|
+
response: 'all_finished',
|
|
50
|
+
session_id:params?.sessionId,
|
|
51
|
+
message_id: params?.messageId || Date.now().toString()
|
|
52
|
+
},
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
const text = JSON.stringify({
|
|
56
|
+
type: 'tool_call',
|
|
57
|
+
specialIdentification: 'dcgchat_tool_call_special_identification',
|
|
58
|
+
...event
|
|
59
|
+
});
|
|
36
60
|
ws.send(JSON.stringify({
|
|
37
61
|
messageType: "openclaw_bot_chat",
|
|
38
62
|
_userId: params?.userId,
|
|
39
63
|
source: "client",
|
|
40
64
|
content: {
|
|
41
65
|
bot_token: params?.token,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
messageType: "openclaw_bot_chat",
|
|
49
|
-
_userId: params?.userId,
|
|
50
|
-
source: "client",
|
|
51
|
-
content: {
|
|
52
|
-
bot_token: params?.token,
|
|
53
|
-
response: JSON.stringify({
|
|
54
|
-
type: 'tool_call',
|
|
55
|
-
...event
|
|
56
|
-
}),
|
|
57
|
-
session_id:params?.sessionId,
|
|
58
|
-
message_id: params?.messageId || Date.now().toString()
|
|
59
|
-
},
|
|
60
|
-
}));
|
|
61
|
-
ws.send(JSON.stringify({
|
|
62
|
-
messageType: "openclaw_bot_chat",
|
|
63
|
-
_userId: params?.userId,
|
|
64
|
-
source: "client",
|
|
65
|
-
content: {
|
|
66
|
-
bot_token: params?.token,
|
|
67
|
-
response: 'all_finished',
|
|
66
|
+
domain_id: params?.domainId,
|
|
67
|
+
app_id: params?.appId,
|
|
68
|
+
bot_id: params?.botId,
|
|
69
|
+
agent_id: params?.agentId,
|
|
70
|
+
thinking_content: text,
|
|
71
|
+
response: '',
|
|
68
72
|
session_id:params?.sessionId,
|
|
69
73
|
message_id: params?.messageId || Date.now().toString()
|
|
70
74
|
},
|
|
71
75
|
}));
|
|
72
|
-
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
if (!runId || runId !== event.runId || !toolName || toolName !== event.toolName) {
|
|
78
|
+
ws.send(JSON.stringify({
|
|
79
|
+
messageType: "openclaw_bot_chat",
|
|
80
|
+
_userId: params?.userId,
|
|
81
|
+
source: "client",
|
|
82
|
+
content: {
|
|
83
|
+
bot_token: params?.token,
|
|
84
|
+
response: 'all_finished',
|
|
85
|
+
session_id:params?.sessionId,
|
|
86
|
+
message_id: params?.messageId || Date.now().toString()
|
|
87
|
+
},
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
runId = event.runId;
|
|
91
|
+
toolName = event.toolName;
|
|
92
|
+
log?.(`dcgchat[${params?.sessionId}]:11111111 tool message to ${params?.sessionId}, ${JSON.stringify(event)}`);
|
|
73
93
|
}
|
|
74
94
|
});
|
|
75
95
|
}
|
package/src/types.ts
CHANGED
|
@@ -39,10 +39,17 @@ export type InboundMessage = {
|
|
|
39
39
|
// content: string;
|
|
40
40
|
content: {
|
|
41
41
|
bot_token: string;
|
|
42
|
+
domain_id?: string;
|
|
43
|
+
app_id?: string;
|
|
44
|
+
bot_id?: string;
|
|
45
|
+
agent_id?: string;
|
|
42
46
|
session_id: string;
|
|
43
47
|
message_id: string;
|
|
44
48
|
text: string;
|
|
45
|
-
|
|
49
|
+
files?: {
|
|
50
|
+
url: string;
|
|
51
|
+
name: string;
|
|
52
|
+
}[];
|
|
46
53
|
};
|
|
47
54
|
};
|
|
48
55
|
|
|
@@ -68,6 +75,11 @@ export type OutboundReply = {
|
|
|
68
75
|
message_id: string; // ""
|
|
69
76
|
response: string; // ""
|
|
70
77
|
state: string; // final, chunk
|
|
78
|
+
domain_id?: string;
|
|
79
|
+
app_id?: string;
|
|
80
|
+
bot_id?: string;
|
|
81
|
+
agent_id?: string;
|
|
82
|
+
files?: {url: string, name: string}[];
|
|
71
83
|
};
|
|
72
84
|
};
|
|
73
85
|
|