@dcrays/dcgchat-test 0.2.0 → 0.2.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcrays/dcgchat-test",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin for 书灵墨宝 (WebSocket)",
6
6
  "main": "index.ts",
@@ -20,9 +20,10 @@
20
20
  "typecheck": "tsc --noEmit"
21
21
  },
22
22
  "dependencies": {
23
+ "ali-oss": "file:src/libs/ali-oss-6.23.0.tgz",
23
24
  "axios": "file:src/libs/axios-1.13.6.tgz",
24
25
  "ws": "file:src/libs/ws-8.19.0.tgz",
25
- "mime-types": "file:src/libs/mime-types-3.0.2.tgz",
26
+ "md5": "file:src/libs/md5-2.3.0.tgz",
26
27
  "unzipper": "file:src/libs/unzipper-0.12.3.tgz"
27
28
  },
28
29
  "openclaw": {
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: 0,
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,14 +1,13 @@
1
1
  import path from "node:path";
2
2
  import os from "node:os";
3
- import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk";
3
+ import type { ClawdbotConfig, ReplyPayload, RuntimeEnv } from "openclaw/plugin-sdk";
4
4
  import { createReplyPrefixContext } from "openclaw/plugin-sdk";
5
5
  import type { InboundMessage, OutboundReply } from "./types.js";
6
6
  import { getDcgchatRuntime } from "./runtime.js";
7
7
  import { resolveAccount } from "./channel.js";
8
8
  import { setMsgStatus } from "./tool.js";
9
- import mime from "mime-types"
10
-
11
- const targetPath = path.join(os.homedir(), '../');
9
+ import { generateSignUrl } from "./api.js";
10
+ import { ossUpload } from "./oss.js";
12
11
 
13
12
  type MediaInfo = {
14
13
  path: string;
@@ -16,27 +15,49 @@ type MediaInfo = {
16
15
  placeholder: string;
17
16
  };
18
17
 
19
- async function resolveMediaFromUrls(
20
- files: { url: string, name: string }[],
21
- log?: (msg: string) => void,
22
- ): 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
+ const core = getDcgchatRuntime();
23
21
  const out: MediaInfo[] = [];
22
+ log(`dcgchat media: starting resolve for ${files.length} file(s): ${JSON.stringify(files)}`);
23
+
24
24
  for (let i = 0; i < files.length; i++) {
25
- const url = path.join(targetPath, files[i]?.url);
25
+ const file = files[i];
26
26
  try {
27
- const response = await fetch(url);
28
- const contentType = response.headers.get("content-type") || "";
27
+ const data = await generateSignUrl(file.url, botToken);
28
+ log(`dcgchat media: [${i + 1}/${files.length}] generateSignUrl: ${data}`);
29
+ const response = await fetch(data);
30
+ if (!response.ok) {
31
+ log?.(`dcgchat media: [${i + 1}/${files.length}] fetch failed with HTTP ${response.status}, skipping`);
32
+ continue;
33
+ }
34
+ const buffer = Buffer.from(await response.arrayBuffer());
35
+
36
+ let contentType = response.headers.get("content-type") || "";
37
+ if (!contentType) {
38
+ contentType = await core.media.detectMime({ buffer }) || "";
39
+ }
40
+ const fileName = file.name || path.basename(new URL(file.url).pathname) || "file";
41
+ const saved = await core.channel.media.saveMediaBuffer(
42
+ buffer,
43
+ contentType,
44
+ "inbound",
45
+ // maxByte: mediaMaxBytes,
46
+ fileName,
47
+ );
29
48
  const isImage = contentType.startsWith("image/");
30
49
  out.push({
31
- path: url,
32
- // @ts-ignore
33
- contentType: saved.contentType,
50
+ path: saved.path,
51
+ contentType: saved.contentType || "",
34
52
  placeholder: isImage ? "<media:image>" : "<media:file>",
35
53
  });
54
+
36
55
  } catch (err) {
37
- log?.(`dcgchat media: [${i + 1}/${files.length}] FAILED to process ${url}: ${String(err)}`);
56
+ log(`dcgchat media: [${i + 1}/${files.length}] FAILED to process ${file.url}: ${String(err)}`);
38
57
  }
39
58
  }
59
+ log(`dcgchat media: resolve complete, ${out.length}/${files.length} file(s) succeeded`);
60
+
40
61
  return out;
41
62
  }
42
63
 
@@ -115,15 +136,7 @@ export async function handleDcgchatMessage(params: {
115
136
  const files = msg.content.files ?? [];
116
137
  let mediaPayload: Record<string, unknown> = {};
117
138
  if (files.length > 0) {
118
- const mediaList = files?.map(item => {
119
- const contentType = mime.lookup(item.name) || "application/octet-stream";
120
- const isImage = contentType.startsWith("image/");
121
- return {
122
- path: path.join(targetPath, item?.url),
123
- contentType: contentType,
124
- placeholder: isImage ? "<media:image>" : "<media:file>",
125
- }
126
- });
139
+ const mediaList = await resolveMediaFromUrls(files, msg.content.bot_token, log)
127
140
  mediaPayload = buildMediaPayload(mediaList);
128
141
  log(`dcgchat[${accountId}]: media resolved ${mediaList.length}/${files.length} file(s), payload=${JSON.stringify(mediaList)}`);
129
142
  }
@@ -164,6 +177,8 @@ export async function handleDcgchatMessage(params: {
164
177
 
165
178
  log(`dcgchat[${accountId}]: ctxPayload=${JSON.stringify(ctxPayload)}`);
166
179
 
180
+ let textChunk = ''
181
+
167
182
  const prefixContext = createReplyPrefixContext({ cfg, agentId: route.agentId });
168
183
 
169
184
  const { dispatcher, replyOptions, markDispatchIdle } =
@@ -172,14 +187,43 @@ export async function handleDcgchatMessage(params: {
172
187
  responsePrefixContextProvider: prefixContext.responsePrefixContextProvider,
173
188
  humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, route.agentId),
174
189
  onReplyStart: async () => {},
175
- deliver: async (payload) => {
190
+ deliver: async (payload: { text: string | any[]; }) => {
176
191
  log(`dcgchat[${accountId}][deliver]: received chunk, text length=${payload.text?.length || 0}`);
177
- const t = payload.text?.trim().replaceAll(
178
- "/root/.openclaw/workspace/moBooksAgentGenerate",
179
- "/upload"
180
- );
181
- if (t) {
182
- log(`dcgchat[${accountId}][deliver]: sending chunk to user ${msg._userId}, text="${t.slice(0, 50)}..."`);
192
+ },
193
+ onError: (err: any, info: { kind: any; }) => {
194
+ error(`dcgchat[${accountId}] ${info.kind} reply failed: ${String(err)}`);
195
+ },
196
+ onIdle: () => {},
197
+ });
198
+
199
+ log(`dcgchat[${accountId}]: dispatching to agent (session=${route.sessionKey})`);
200
+
201
+ await core.channel.reply.dispatchReplyFromConfig({
202
+ ctx: ctxPayload,
203
+ cfg,
204
+ dispatcher,
205
+ replyOptions: {
206
+ ...replyOptions,
207
+ onModelSelected: prefixContext.onModelSelected,
208
+ onPartialReply: async (payload: ReplyPayload) => {
209
+ log(`dcgchat[${accountId}][deliver]: received chunk, text length=${payload.text?.length || 0}`);
210
+ const mediaList =
211
+ payload.mediaUrls && payload.mediaUrls.length > 0
212
+ ? payload.mediaUrls
213
+ : payload.mediaUrl
214
+ ? [payload.mediaUrl]
215
+ : [];
216
+ if (mediaList.length > 0) {
217
+ const files = []
218
+ for (let i = 0; i < mediaList.length; i++) {
219
+ const file = mediaList[i]
220
+ const fileName = file.split(/[\\/]/).pop() || ''
221
+ const url = await ossUpload(file, msg.content.bot_token)
222
+ files.push({
223
+ url: url,
224
+ name: fileName,
225
+ })
226
+ }
183
227
  params.onChunk({
184
228
  messageType: "openclaw_bot_chat",
185
229
  _userId: msg._userId,
@@ -192,30 +236,39 @@ export async function handleDcgchatMessage(params: {
192
236
  agent_id: msg.content.agent_id,
193
237
  session_id: msg.content.session_id,
194
238
  message_id: msg.content.message_id,
195
- response: t,
239
+ response: '',
240
+ files: files,
196
241
  state: 'chunk',
197
242
  },
198
243
  });
244
+ }
245
+ if (payload.text) {
246
+ log(`dcgchat[${accountId}][deliver]: sending chunk to user ${msg._userId}, text="${payload.text.slice(0, 50)}..."`);
247
+ params.onChunk({
248
+ messageType: "openclaw_bot_chat",
249
+ _userId: msg._userId,
250
+ source: "client",
251
+ content: {
252
+ bot_token: msg.content.bot_token,
253
+ domain_id: msg.content.domain_id,
254
+ app_id: msg.content.app_id,
255
+ bot_id: msg.content.bot_id,
256
+ agent_id: msg.content.agent_id,
257
+ session_id: msg.content.session_id,
258
+ message_id: msg.content.message_id,
259
+ response: payload.text.replace(textChunk, ''),
260
+ state: 'chunk',
261
+ },
262
+ });
263
+ textChunk = payload.text
199
264
  log(`dcgchat[${accountId}][deliver]: chunk sent successfully`);
265
+ } else if (payload.mediaUrl && payload.mediaUrls) {
266
+
267
+
200
268
  } else {
201
269
  log(`dcgchat[${accountId}][deliver]: skipping empty chunk`);
202
270
  }
203
271
  },
204
- onError: (err, info) => {
205
- error(`dcgchat[${accountId}] ${info.kind} reply failed: ${String(err)}`);
206
- },
207
- onIdle: () => {},
208
- });
209
-
210
- log(`dcgchat[${accountId}]: dispatching to agent (session=${route.sessionKey})`);
211
-
212
- await core.channel.reply.dispatchReplyFromConfig({
213
- ctx: ctxPayload,
214
- cfg,
215
- dispatcher,
216
- replyOptions: {
217
- ...replyOptions,
218
- onModelSelected: prefixContext.onModelSelected,
219
272
  },
220
273
  });
221
274
 
@@ -237,6 +290,7 @@ export async function handleDcgchatMessage(params: {
237
290
  },
238
291
  });
239
292
  setMsgStatus('finished');
293
+ textChunk = ''
240
294
  log(`dcgchat[${accountId}]: final state sent`);
241
295
 
242
296
  markDispatchIdle();
package/src/channel.ts CHANGED
@@ -1,50 +1,10 @@
1
- import { copyFile, mkdir, rename, unlink } from "node:fs/promises";
2
- import { basename, dirname, isAbsolute, relative, resolve } from "node:path";
3
- import os from "node:os";
4
1
  import type { ChannelPlugin, OpenClawConfig } from "openclaw/plugin-sdk";
5
2
  import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk";
6
3
  import type { ResolvedDcgchatAccount, DcgchatConfig } from "./types.js";
7
- import { logDcgchat } from "./log.js";
8
4
  import { getWsConnection } from "./connection.js";
5
+ import { ossUpload } from "./oss.js";
9
6
  import { getMsgParams } from "./tool.js";
10
7
 
11
- const uploadRoot = resolve('/', "upload");
12
-
13
- function isPathInside(parentPath: string, targetPath: string): boolean {
14
- const relativePath = relative(parentPath, targetPath);
15
- return relativePath === "" || (!relativePath.startsWith("..") && !isAbsolute(relativePath));
16
- }
17
-
18
- async function ensureMediaInUploadDir(url: string): Promise<string> {
19
- if (!url || /^([a-z][a-z\d+\-.]*):\/\//i.test(url) || !isAbsolute(url)) {
20
- return url;
21
- }
22
- const sourcePath = resolve(url);
23
- if (isPathInside(uploadRoot, sourcePath)) {
24
- return sourcePath;
25
- }
26
- const fileName = basename(sourcePath);
27
- if (!fileName) {
28
- return sourcePath;
29
- }
30
- const targetPath = resolve(uploadRoot, fileName);
31
- if (targetPath === sourcePath) {
32
- return targetPath;
33
- }
34
-
35
- await mkdir(uploadRoot, { recursive: true });
36
-
37
- try {
38
- await rename(sourcePath, targetPath);
39
- } catch (error) {
40
- if ((error as NodeJS.ErrnoException).code !== "EXDEV") {
41
- throw error;
42
- }
43
- await copyFile(sourcePath, targetPath);
44
- await unlink(sourcePath);
45
- }
46
- return targetPath;
47
- }
48
8
 
49
9
  export function resolveAccount(cfg: OpenClawConfig, accountId?: string | null): ResolvedDcgchatAccount {
50
10
  const id = accountId ?? DEFAULT_ACCOUNT_ID;
@@ -145,6 +105,7 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
145
105
  sendText: async (ctx) => {
146
106
  const ws = getWsConnection()
147
107
  const params = getMsgParams();
108
+ const log = ctx.runtime?.log ?? console.log;
148
109
  if (ws?.readyState === WebSocket.OPEN) {
149
110
  const {botToken} = resolveAccount(ctx.cfg, ctx.accountId);
150
111
  const content = {
@@ -157,18 +118,15 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
157
118
  app_id: params.appId,
158
119
  bot_id: params.botId,
159
120
  agent_id: params.agentId,
160
- response: ctx.text.replaceAll(
161
- "/root/.openclaw/workspace/moBooksAgentGenerate",
162
- "/upload"
163
- ),
121
+ response: ctx.text,
164
122
  session_id: params.sessionId,
165
123
  message_id: params.messageId || Date.now().toString(),
166
124
  },
167
125
  };
168
126
  ws.send(JSON.stringify(content));
169
- logDcgchat.info(`dcgchat[${ctx.accountId}]: sendText to ${params.userId}, ${JSON.stringify(content)}`);
127
+ log(`dcgchat[${ctx.accountId}]: sendText to ${params.userId}, ${JSON.stringify(content)}`);
170
128
  } else {
171
- logDcgchat.warn(`[dcgchat][${ctx.accountId ?? DEFAULT_ACCOUNT_ID}] outbound -> ${ws?.readyState}: ${ctx.text}`);
129
+ log(`[dcgchat][${ctx.accountId ?? DEFAULT_ACCOUNT_ID}] outbound -> ${ws?.readyState}: ${ctx.text}`);
172
130
  }
173
131
  return {
174
132
  channel: "dcgchat-test",
@@ -179,13 +137,12 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
179
137
  sendMedia: async (ctx) => {
180
138
  const ws = getWsConnection()
181
139
  const params = getMsgParams();
182
-
183
- if (ws?.readyState === WebSocket.OPEN) {
140
+ const log = ctx.runtime?.log ?? console.log;
141
+ if (ws?.readyState === WebSocket.OPEN) {
142
+ const fileName = ctx.mediaUrl?.split(/[\\/]/).pop() || ''
184
143
  const {botToken} = resolveAccount(ctx.cfg, ctx.accountId);
185
-
186
- // try {
187
- const url = await ensureMediaInUploadDir(ctx.mediaUrl ?? '');
188
- const fileName = url?.split(/[\\/]/).pop() || ''
144
+ try {
145
+ const url = ctx.mediaUrl ? await ossUpload(ctx.mediaUrl, botToken) : '';
189
146
  const content = {
190
147
  messageType: "openclaw_bot_chat",
191
148
  _userId: params.userId,
@@ -196,37 +153,42 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
196
153
  app_id: params.appId,
197
154
  bot_id: params.botId,
198
155
  agent_id: params.agentId,
199
- response: ctx.text.replaceAll(
200
- "/root/.openclaw/workspace/moBooksAgentGenerate",
201
- "/upload"
202
- ),
156
+ response: ctx.text,
203
157
  files: [{
204
158
  url: url,
205
159
  name: fileName,
206
160
  }],
207
161
  session_id: params.sessionId,
208
- message_id: params.messageId || Date.now().toString(),
162
+ message_id: params.messageId ||Date.now().toString(),
163
+ },
164
+ };
165
+ ws.send(JSON.stringify(content));
166
+ log(`dcgchat[${ctx.accountId}]: sendMedia alioss to ${params.userId}, ${JSON.stringify(content)}`);
167
+ } catch (error) {
168
+ const content = {
169
+ messageType: "openclaw_bot_chat",
170
+ _userId: params.userId,
171
+ source: "client",
172
+ content: {
173
+ bot_token: botToken,
174
+ domain_id: params.domainId,
175
+ app_id: params.appId,
176
+ bot_id: params.botId,
177
+ agent_id: params.agentId,
178
+ response: ctx.text,
179
+ files: [{
180
+ url: ctx.mediaUrl,
181
+ name: fileName,
182
+ }],
183
+ session_id: params.sessionId || Date.now().toString(),
184
+ message_id: params.messageId ||Date.now().toString(),
209
185
  },
210
186
  };
211
187
  ws.send(JSON.stringify(content));
212
- logDcgchat.info(`dcgchat[${ctx.accountId}]: agent sendMedia to ${params.userId}, ${JSON.stringify(content)}`);
213
- // } catch (error) {
214
- // const content = {
215
- // messageType: "openclaw_bot_chat",
216
- // _userId: target,
217
- // source: "client",
218
- // content: {
219
- // bot_token: botToken,
220
- // response: ctx.text + '\n' + ctx.mediaUrl,
221
- // session_id: params.sessionId || Date.now().toString(),
222
- // message_id: params.messageId ||Date.now().toString(),
223
- // },
224
- // };
225
- // ws.send(JSON.stringify(content));
226
- // logDcgchat.info(`dcgchat[${ctx.accountId}]: sendMedia to ${target}, ${JSON.stringify(content)}`);
227
- // }
188
+ log(`dcgchat[${ctx.accountId}]: error sendMedia to ${params.userId}, ${JSON.stringify(content)}`);
189
+ }
228
190
  } else {
229
- logDcgchat.warn(`[dcgchat][${ctx.accountId ?? DEFAULT_ACCOUNT_ID}] outbound -> ${ws?.readyState}: ${ctx.text}`);
191
+ log(`[dcgchat][${ctx.accountId ?? DEFAULT_ACCOUNT_ID}] outbound -> ${ws?.readyState}: ${ctx.text}`);
230
192
  }
231
193
  return {
232
194
  channel: "dcgchat-test",
package/src/monitor.ts CHANGED
@@ -112,13 +112,14 @@ 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,
120
- domainId: msg.content.domain_id,
121
- appId: msg.content.app_id,
121
+ domainId: account.domainId || 1000,
122
+ appId: account.appId || '100',
122
123
  botId: msg.content.bot_id,
123
124
  agentId: msg.content.agent_id,
124
125
  });
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.url);
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
- headers: buildHeaders(data as Record<string, unknown>, url, options?.userToken),
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/tool.ts CHANGED
@@ -1,7 +1,6 @@
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;
@@ -29,32 +28,35 @@ export function setMsgStatus(status: 'running' | 'finished' | '') {
29
28
  export function getMsgStatus() {
30
29
  return msgStatus;
31
30
  }
32
-
31
+ let runId = '';
32
+ let toolName = '';
33
33
  export function monitoringToolMessage(api: OpenClawPluginApi) {
34
- api.on("after_tool_call", (event, payload) => {
34
+ api.on("after_tool_call", (event) => {
35
35
  const ws = getWsConnection()
36
36
  const params = getMsgParams();
37
37
  const status = getMsgStatus();
38
38
  //
39
39
  if (ws?.readyState === WebSocket.OPEN && status === 'running') {
40
- ws.send(JSON.stringify({
41
- messageType: "openclaw_bot_chat",
42
- _userId: params?.userId,
43
- source: "client",
44
- content: {
45
- bot_token: params?.token,
46
- response: 'all_finished',
47
- session_id:params?.sessionId,
48
- message_id: params?.messageId || Date.now().toString()
49
- },
50
- }));
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
+ }
51
55
  const text = JSON.stringify({
52
56
  type: 'tool_call',
57
+ specialIdentification: 'dcgchat_tool_call_special_identification',
53
58
  ...event
54
- }).replaceAll(
55
- "/root/.openclaw/workspace/moBooksAgentGenerate",
56
- "/upload"
57
- );
59
+ });
58
60
  ws.send(JSON.stringify({
59
61
  messageType: "openclaw_bot_chat",
60
62
  _userId: params?.userId,
@@ -70,18 +72,23 @@ export function monitoringToolMessage(api: OpenClawPluginApi) {
70
72
  message_id: params?.messageId || Date.now().toString()
71
73
  },
72
74
  }));
73
- ws.send(JSON.stringify({
74
- messageType: "openclaw_bot_chat",
75
- _userId: params?.userId,
76
- source: "client",
77
- content: {
78
- bot_token: params?.token,
79
- response: 'all_finished',
80
- session_id:params?.sessionId,
81
- message_id: params?.messageId || Date.now().toString()
82
- },
83
- }));
84
- logDcgchat.info(`dcgchat: tool message to ${params?.sessionId}, ${JSON.stringify(event)}`);
75
+ // @ts-ignore
76
+ if (!runId || runId !== event.runId || !toolName || toolName !== event.toolName) {
77
+ ws.send(JSON.stringify({
78
+ messageType: "openclaw_bot_chat",
79
+ _userId: params?.userId,
80
+ source: "client",
81
+ content: {
82
+ bot_token: params?.token,
83
+ response: 'all_finished',
84
+ session_id:params?.sessionId,
85
+ message_id: params?.messageId || Date.now().toString()
86
+ },
87
+ }));
88
+ }
89
+ runId = event.runId;
90
+ toolName = event.toolName;
91
+ log?.(`dcgchat[${params?.sessionId}]:11111111 tool message to ${params?.sessionId}, ${JSON.stringify(event)}`);
85
92
  }
86
93
  });
87
94
  }
package/src/types.ts CHANGED
@@ -79,6 +79,7 @@ export type OutboundReply = {
79
79
  app_id?: string;
80
80
  bot_id?: string;
81
81
  agent_id?: string;
82
+ files?: {url: string, name: string}[];
82
83
  };
83
84
  };
84
85