@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 +3 -2
- package/src/api.ts +24 -1
- package/src/bot.ts +101 -47
- package/src/channel.ts +37 -75
- package/src/monitor.ts +3 -2
- package/src/oss.ts +2 -2
- package/src/request.ts +10 -3
- package/src/tool.ts +37 -30
- package/src/types.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcrays/dcgchat-test",
|
|
3
|
-
"version": "0.2.
|
|
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
|
-
"
|
|
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:
|
|
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
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
25
|
+
const file = files[i];
|
|
26
26
|
try {
|
|
27
|
-
const
|
|
28
|
-
|
|
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:
|
|
32
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
127
|
+
log(`dcgchat[${ctx.accountId}]: sendText to ${params.userId}, ${JSON.stringify(content)}`);
|
|
170
128
|
} else {
|
|
171
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 ||
|
|
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
|
-
|
|
213
|
-
|
|
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
|
-
|
|
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:
|
|
121
|
-
appId:
|
|
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
|
|
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/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
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
})
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
}
|