@dcrays/dcgchat 0.1.10 → 0.2.0
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 +2 -2
- package/package.json +7 -18
- package/src/bot.ts +44 -52
- package/src/channel.ts +96 -33
- package/src/libs/mime-types-3.0.2.tgz +0 -0
- package/src/monitor.ts +4 -0
- package/src/runtime.ts +6 -4
- package/src/skill.ts +1 -1
- package/src/tool.ts +19 -7
- package/src/types.ts +12 -1
package/README.md
CHANGED
package/index.ts
CHANGED
|
@@ -6,8 +6,8 @@ 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);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcrays/dcgchat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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": [
|
|
@@ -20,33 +20,22 @@
|
|
|
20
20
|
"typecheck": "tsc --noEmit"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"ali-oss": "file:src/libs/ali-oss-6.23.0.tgz",
|
|
24
|
-
"ws": "file:src/libs/ws-8.19.0.tgz",
|
|
25
23
|
"axios": "file:src/libs/axios-1.13.6.tgz",
|
|
26
|
-
"
|
|
24
|
+
"ws": "file:src/libs/ws-8.19.0.tgz",
|
|
25
|
+
"mime-types": "file:src/libs/mime-types-3.0.2.tgz",
|
|
27
26
|
"unzipper": "file:src/libs/unzipper-0.12.3.tgz"
|
|
28
27
|
},
|
|
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
28
|
"openclaw": {
|
|
40
29
|
"extensions": [
|
|
41
30
|
"./index.ts"
|
|
42
31
|
],
|
|
43
32
|
"channel": {
|
|
44
33
|
"id": "dcgchat",
|
|
45
|
-
"label": "
|
|
46
|
-
"selectionLabel": "
|
|
34
|
+
"label": "书灵墨宝",
|
|
35
|
+
"selectionLabel": "书灵墨宝",
|
|
47
36
|
"docsPath": "/channels/dcgchat",
|
|
48
37
|
"docsLabel": "dcgchat",
|
|
49
|
-
"blurb": "连接 OpenClaw 与
|
|
38
|
+
"blurb": "连接 OpenClaw 与 书灵墨宝 产品",
|
|
50
39
|
"order": 80
|
|
51
40
|
},
|
|
52
41
|
"install": {
|
package/src/bot.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import type { ClawdbotConfig, 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 mime from "mime-types"
|
|
10
|
+
|
|
11
|
+
const targetPath = path.join(os.homedir(), '../');
|
|
8
12
|
|
|
9
13
|
type MediaInfo = {
|
|
10
14
|
path: string;
|
|
@@ -13,63 +17,26 @@ type MediaInfo = {
|
|
|
13
17
|
};
|
|
14
18
|
|
|
15
19
|
async function resolveMediaFromUrls(
|
|
16
|
-
|
|
17
|
-
maxBytes: number,
|
|
20
|
+
files: { url: string, name: string }[],
|
|
18
21
|
log?: (msg: string) => void,
|
|
19
22
|
): Promise<MediaInfo[]> {
|
|
20
|
-
const core = getDcgchatRuntime();
|
|
21
23
|
const out: MediaInfo[] = [];
|
|
22
|
-
|
|
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 url = path.join(targetPath, files[i]?.url);
|
|
28
26
|
try {
|
|
29
27
|
const response = await fetch(url);
|
|
30
|
-
|
|
31
|
-
if (!response.ok) {
|
|
32
|
-
log?.(`dcgchat media: [${i + 1}/${fileUrls.length}] fetch failed with HTTP ${response.status}, skipping`);
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
const buffer = Buffer.from(await response.arrayBuffer());
|
|
36
|
-
log?.(`dcgchat media: [${i + 1}/${fileUrls.length}] downloaded buffer size=${buffer.length} bytes`);
|
|
37
|
-
|
|
38
|
-
let contentType = response.headers.get("content-type") || "";
|
|
39
|
-
if (!contentType) {
|
|
40
|
-
log?.(`dcgchat media: [${i + 1}/${fileUrls.length}] no content-type header, detecting mime...`);
|
|
41
|
-
// @ts-ignore
|
|
42
|
-
contentType = await core.media.detectMime({ buffer });
|
|
43
|
-
}
|
|
44
|
-
log?.(`dcgchat media: [${i + 1}/${fileUrls.length}] resolved contentType=${contentType}`);
|
|
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
|
-
|
|
49
|
-
const saved = await core.channel.media.saveMediaBuffer(
|
|
50
|
-
buffer,
|
|
51
|
-
contentType,
|
|
52
|
-
"inbound",
|
|
53
|
-
maxBytes,
|
|
54
|
-
fileName,
|
|
55
|
-
);
|
|
56
|
-
|
|
28
|
+
const contentType = response.headers.get("content-type") || "";
|
|
57
29
|
const isImage = contentType.startsWith("image/");
|
|
58
30
|
out.push({
|
|
59
|
-
path:
|
|
31
|
+
path: url,
|
|
60
32
|
// @ts-ignore
|
|
61
33
|
contentType: saved.contentType,
|
|
62
34
|
placeholder: isImage ? "<media:image>" : "<media:file>",
|
|
63
35
|
});
|
|
64
|
-
|
|
65
|
-
log?.(`dcgchat media: [${i + 1}/${fileUrls.length}] saved to ${saved.path} (contentType=${saved.contentType}, isImage=${isImage})`);
|
|
66
36
|
} catch (err) {
|
|
67
|
-
log?.(`dcgchat media: [${i + 1}/${
|
|
37
|
+
log?.(`dcgchat media: [${i + 1}/${files.length}] FAILED to process ${url}: ${String(err)}`);
|
|
68
38
|
}
|
|
69
39
|
}
|
|
70
|
-
|
|
71
|
-
log?.(`dcgchat media: resolve complete, ${out.length}/${fileUrls.length} file(s) succeeded`);
|
|
72
|
-
|
|
73
40
|
return out;
|
|
74
41
|
}
|
|
75
42
|
|
|
@@ -122,6 +89,10 @@ export async function handleDcgchatMessage(params: {
|
|
|
122
89
|
// @ts-ignore
|
|
123
90
|
content: {
|
|
124
91
|
bot_token: msg.content.bot_token,
|
|
92
|
+
domain_id: msg.content.domain_id,
|
|
93
|
+
app_id: msg.content.app_id,
|
|
94
|
+
bot_id: msg.content.bot_id,
|
|
95
|
+
agent_id: msg.content.agent_id,
|
|
125
96
|
session_id: msg.content.session_id,
|
|
126
97
|
message_id: msg.content.message_id,
|
|
127
98
|
response: "[错误] 消息格式不正确",
|
|
@@ -141,22 +112,28 @@ export async function handleDcgchatMessage(params: {
|
|
|
141
112
|
});
|
|
142
113
|
|
|
143
114
|
// 处理用户上传的文件
|
|
144
|
-
const
|
|
145
|
-
log(`dcgchat[${accountId}]: incoming message from user=${userId}, text="${text?.slice(0, 80)}", file_urls count=${fileUrls.length}`);
|
|
115
|
+
const files = msg.content.files ?? [];
|
|
146
116
|
let mediaPayload: Record<string, unknown> = {};
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
117
|
+
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
|
+
});
|
|
151
127
|
mediaPayload = buildMediaPayload(mediaList);
|
|
152
|
-
log(`dcgchat[${accountId}]: media resolved ${mediaList.length}/${
|
|
128
|
+
log(`dcgchat[${accountId}]: media resolved ${mediaList.length}/${files.length} file(s), payload=${JSON.stringify(mediaList)}`);
|
|
153
129
|
}
|
|
154
130
|
|
|
155
131
|
const envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(cfg);
|
|
156
132
|
// const messageBody = `${userId}: ${text}`;
|
|
133
|
+
// 补充消息
|
|
157
134
|
const messageBody = text;
|
|
158
135
|
const bodyFormatted = core.channel.reply.formatAgentEnvelope({
|
|
159
|
-
channel: "
|
|
136
|
+
channel: "书灵墨宝",
|
|
160
137
|
from: userId,
|
|
161
138
|
timestamp: new Date(),
|
|
162
139
|
envelope: envelopeOptions,
|
|
@@ -197,7 +174,10 @@ export async function handleDcgchatMessage(params: {
|
|
|
197
174
|
onReplyStart: async () => {},
|
|
198
175
|
deliver: async (payload) => {
|
|
199
176
|
log(`dcgchat[${accountId}][deliver]: received chunk, text length=${payload.text?.length || 0}`);
|
|
200
|
-
const t = payload.text?.trim()
|
|
177
|
+
const t = payload.text?.trim().replaceAll(
|
|
178
|
+
"/root/.openclaw/workspace/moBooksAgentGenerate",
|
|
179
|
+
"/upload"
|
|
180
|
+
);
|
|
201
181
|
if (t) {
|
|
202
182
|
log(`dcgchat[${accountId}][deliver]: sending chunk to user ${msg._userId}, text="${t.slice(0, 50)}..."`);
|
|
203
183
|
params.onChunk({
|
|
@@ -206,6 +186,10 @@ export async function handleDcgchatMessage(params: {
|
|
|
206
186
|
source: "client",
|
|
207
187
|
content: {
|
|
208
188
|
bot_token: msg.content.bot_token,
|
|
189
|
+
domain_id: msg.content.domain_id,
|
|
190
|
+
app_id: msg.content.app_id,
|
|
191
|
+
bot_id: msg.content.bot_id,
|
|
192
|
+
agent_id: msg.content.agent_id,
|
|
209
193
|
session_id: msg.content.session_id,
|
|
210
194
|
message_id: msg.content.message_id,
|
|
211
195
|
response: t,
|
|
@@ -242,6 +226,10 @@ export async function handleDcgchatMessage(params: {
|
|
|
242
226
|
source: "client",
|
|
243
227
|
content: {
|
|
244
228
|
bot_token: msg.content.bot_token,
|
|
229
|
+
domain_id: msg.content.domain_id,
|
|
230
|
+
app_id: msg.content.app_id,
|
|
231
|
+
bot_id: msg.content.bot_id,
|
|
232
|
+
agent_id: msg.content.agent_id,
|
|
245
233
|
session_id: msg.content.session_id,
|
|
246
234
|
message_id: msg.content.message_id,
|
|
247
235
|
response: '',
|
|
@@ -262,6 +250,10 @@ export async function handleDcgchatMessage(params: {
|
|
|
262
250
|
source: "client",
|
|
263
251
|
content: {
|
|
264
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,
|
|
265
257
|
session_id: msg.content.session_id,
|
|
266
258
|
message_id: msg.content.message_id,
|
|
267
259
|
response: `[错误] ${err instanceof Error ? err.message : String(err)}`,
|
package/src/channel.ts
CHANGED
|
@@ -1,11 +1,51 @@
|
|
|
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";
|
|
1
4
|
import type { ChannelPlugin, OpenClawConfig } from "openclaw/plugin-sdk";
|
|
2
5
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk";
|
|
3
6
|
import type { ResolvedDcgchatAccount, DcgchatConfig } from "./types.js";
|
|
4
7
|
import { logDcgchat } from "./log.js";
|
|
5
8
|
import { getWsConnection } from "./connection.js";
|
|
6
|
-
import { ossUpload } from "./oss.js";
|
|
7
9
|
import { getMsgParams } from "./tool.js";
|
|
8
10
|
|
|
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
|
+
|
|
9
49
|
export function resolveAccount(cfg: OpenClawConfig, accountId?: string | null): ResolvedDcgchatAccount {
|
|
10
50
|
const id = accountId ?? DEFAULT_ACCOUNT_ID;
|
|
11
51
|
const raw = (cfg.channels?.["dcgchat"] as DcgchatConfig | undefined) ?? {};
|
|
@@ -25,11 +65,11 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
25
65
|
id: "dcgchat",
|
|
26
66
|
meta: {
|
|
27
67
|
id: "dcgchat",
|
|
28
|
-
label: "
|
|
29
|
-
selectionLabel: "
|
|
68
|
+
label: "书灵墨宝",
|
|
69
|
+
selectionLabel: "书灵墨宝",
|
|
30
70
|
docsPath: "/channels/dcgchat",
|
|
31
71
|
docsLabel: "dcgchat",
|
|
32
|
-
blurb: "连接 OpenClaw 与
|
|
72
|
+
blurb: "连接 OpenClaw 与 书灵墨宝 产品",
|
|
33
73
|
order: 80,
|
|
34
74
|
},
|
|
35
75
|
capabilities: {
|
|
@@ -44,6 +84,11 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
44
84
|
effects: true,
|
|
45
85
|
// blockStreaming: true,
|
|
46
86
|
},
|
|
87
|
+
agentPrompt: {
|
|
88
|
+
messageToolHints: () => [
|
|
89
|
+
"- 如果有文件生成,直接将文件生成到根目录的/upload文件夹下,并将文件发送给我",
|
|
90
|
+
],
|
|
91
|
+
},
|
|
47
92
|
reload: { configPrefixes: ["channels.dcgchat"] },
|
|
48
93
|
configSchema: {
|
|
49
94
|
schema: {
|
|
@@ -98,77 +143,95 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
98
143
|
// textChunkLimit: 25,
|
|
99
144
|
textChunkLimit: 4000,
|
|
100
145
|
sendText: async (ctx) => {
|
|
101
|
-
const target = ctx.to || "(implicit)";
|
|
102
146
|
const ws = getWsConnection()
|
|
103
147
|
const params = getMsgParams();
|
|
104
148
|
if (ws?.readyState === WebSocket.OPEN) {
|
|
105
149
|
const {botToken} = resolveAccount(ctx.cfg, ctx.accountId);
|
|
106
150
|
const content = {
|
|
107
151
|
messageType: "openclaw_bot_chat",
|
|
108
|
-
_userId:
|
|
152
|
+
_userId: params.userId,
|
|
109
153
|
source: "client",
|
|
110
154
|
content: {
|
|
111
155
|
bot_token: botToken,
|
|
112
|
-
|
|
156
|
+
domain_id: params.domainId,
|
|
157
|
+
app_id: params.appId,
|
|
158
|
+
bot_id: params.botId,
|
|
159
|
+
agent_id: params.agentId,
|
|
160
|
+
response: ctx.text.replaceAll(
|
|
161
|
+
"/root/.openclaw/workspace/moBooksAgentGenerate",
|
|
162
|
+
"/upload"
|
|
163
|
+
),
|
|
113
164
|
session_id: params.sessionId,
|
|
114
165
|
message_id: params.messageId || Date.now().toString(),
|
|
115
166
|
},
|
|
116
167
|
};
|
|
117
168
|
ws.send(JSON.stringify(content));
|
|
118
|
-
logDcgchat.info(`dcgchat[${ctx.accountId}]: sendText to ${
|
|
169
|
+
logDcgchat.info(`dcgchat[${ctx.accountId}]: sendText to ${params.userId}, ${JSON.stringify(content)}`);
|
|
119
170
|
} else {
|
|
120
171
|
logDcgchat.warn(`[dcgchat][${ctx.accountId ?? DEFAULT_ACCOUNT_ID}] outbound -> ${ws?.readyState}: ${ctx.text}`);
|
|
121
172
|
}
|
|
122
173
|
return {
|
|
123
174
|
channel: "dcgchat",
|
|
124
175
|
messageId: `dcg-${Date.now()}`,
|
|
125
|
-
chatId:
|
|
176
|
+
chatId: params.userId.toString(),
|
|
126
177
|
};
|
|
127
178
|
},
|
|
128
179
|
sendMedia: async (ctx) => {
|
|
129
|
-
const target = ctx.to || "(implicit)";
|
|
130
180
|
const ws = getWsConnection()
|
|
131
181
|
const params = getMsgParams();
|
|
182
|
+
|
|
132
183
|
if (ws?.readyState === WebSocket.OPEN) {
|
|
133
184
|
const {botToken} = resolveAccount(ctx.cfg, ctx.accountId);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const
|
|
185
|
+
|
|
186
|
+
// try {
|
|
187
|
+
const url = await ensureMediaInUploadDir(ctx.mediaUrl ?? '');
|
|
188
|
+
const fileName = url?.split(/[\\/]/).pop() || ''
|
|
137
189
|
const content = {
|
|
138
190
|
messageType: "openclaw_bot_chat",
|
|
139
|
-
_userId:
|
|
191
|
+
_userId: params.userId,
|
|
140
192
|
source: "client",
|
|
141
193
|
content: {
|
|
142
194
|
bot_token: botToken,
|
|
143
|
-
|
|
195
|
+
domain_id: params.domainId,
|
|
196
|
+
app_id: params.appId,
|
|
197
|
+
bot_id: params.botId,
|
|
198
|
+
agent_id: params.agentId,
|
|
199
|
+
response: ctx.text.replaceAll(
|
|
200
|
+
"/root/.openclaw/workspace/moBooksAgentGenerate",
|
|
201
|
+
"/upload"
|
|
202
|
+
),
|
|
203
|
+
files: [{
|
|
204
|
+
url: url,
|
|
205
|
+
name: fileName,
|
|
206
|
+
}],
|
|
144
207
|
session_id: params.sessionId,
|
|
145
|
-
message_id: params.messageId ||Date.now().toString(),
|
|
146
|
-
},
|
|
147
|
-
};
|
|
148
|
-
ws.send(JSON.stringify(content));
|
|
149
|
-
logDcgchat.info(`dcgchat[${ctx.accountId}]: sendMedia to ${target}, ${JSON.stringify(content)}`);
|
|
150
|
-
} catch (error) {
|
|
151
|
-
const content = {
|
|
152
|
-
messageType: "openclaw_bot_chat",
|
|
153
|
-
_userId: target,
|
|
154
|
-
source: "client",
|
|
155
|
-
content: {
|
|
156
|
-
bot_token: botToken,
|
|
157
|
-
response: ctx.text + '\n' + ctx.mediaUrl,
|
|
158
|
-
session_id: params.sessionId || Date.now().toString(),
|
|
159
|
-
message_id: params.messageId ||Date.now().toString(),
|
|
208
|
+
message_id: params.messageId || Date.now().toString(),
|
|
160
209
|
},
|
|
161
210
|
};
|
|
162
211
|
ws.send(JSON.stringify(content));
|
|
163
|
-
logDcgchat.info(`dcgchat[${ctx.accountId}]: sendMedia to ${
|
|
164
|
-
}
|
|
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
|
+
// }
|
|
165
228
|
} else {
|
|
166
229
|
logDcgchat.warn(`[dcgchat][${ctx.accountId ?? DEFAULT_ACCOUNT_ID}] outbound -> ${ws?.readyState}: ${ctx.text}`);
|
|
167
230
|
}
|
|
168
231
|
return {
|
|
169
232
|
channel: "dcgchat",
|
|
170
233
|
messageId: `dcg-${Date.now()}`,
|
|
171
|
-
chatId:
|
|
234
|
+
chatId: params.userId.toString(),
|
|
172
235
|
};
|
|
173
236
|
},
|
|
174
237
|
},
|
|
Binary file
|
package/src/monitor.ts
CHANGED
|
@@ -117,6 +117,10 @@ export async function monitorDcgchatProvider(opts: MonitorDcgchatOpts): Promise<
|
|
|
117
117
|
token: msg.content.bot_token,
|
|
118
118
|
sessionId: msg.content.session_id,
|
|
119
119
|
messageId: msg.content.message_id,
|
|
120
|
+
domainId: msg.content.domain_id,
|
|
121
|
+
appId: msg.content.app_id,
|
|
122
|
+
botId: msg.content.bot_id,
|
|
123
|
+
agentId: msg.content.agent_id,
|
|
120
124
|
});
|
|
121
125
|
await handleDcgchatMessage({
|
|
122
126
|
cfg,
|
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
|
});
|
package/src/tool.ts
CHANGED
|
@@ -5,9 +5,13 @@ import { logDcgchat } from "./log.js";
|
|
|
5
5
|
|
|
6
6
|
let msgParams = {} as {
|
|
7
7
|
userId: number;
|
|
8
|
-
token: string
|
|
9
|
-
sessionId: string
|
|
10
|
-
messageId: string
|
|
8
|
+
token: string;
|
|
9
|
+
sessionId: string;
|
|
10
|
+
messageId: string;
|
|
11
|
+
domainId: string;
|
|
12
|
+
appId: string;
|
|
13
|
+
botId: string;
|
|
14
|
+
agentId: string;
|
|
11
15
|
}
|
|
12
16
|
let msgStatus: 'running' | 'finished' | '' = '';
|
|
13
17
|
export function setMsgParams(params: any) {
|
|
@@ -44,16 +48,24 @@ export function monitoringToolMessage(api: OpenClawPluginApi) {
|
|
|
44
48
|
message_id: params?.messageId || Date.now().toString()
|
|
45
49
|
},
|
|
46
50
|
}));
|
|
51
|
+
const text = JSON.stringify({
|
|
52
|
+
type: 'tool_call',
|
|
53
|
+
...event
|
|
54
|
+
}).replaceAll(
|
|
55
|
+
"/root/.openclaw/workspace/moBooksAgentGenerate",
|
|
56
|
+
"/upload"
|
|
57
|
+
);
|
|
47
58
|
ws.send(JSON.stringify({
|
|
48
59
|
messageType: "openclaw_bot_chat",
|
|
49
60
|
_userId: params?.userId,
|
|
50
61
|
source: "client",
|
|
51
62
|
content: {
|
|
52
63
|
bot_token: params?.token,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
domain_id: params?.domainId,
|
|
65
|
+
app_id: params?.appId,
|
|
66
|
+
bot_id: params?.botId,
|
|
67
|
+
agent_id: params?.agentId,
|
|
68
|
+
response: text,
|
|
57
69
|
session_id:params?.sessionId,
|
|
58
70
|
message_id: params?.messageId || Date.now().toString()
|
|
59
71
|
},
|
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,10 @@ 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;
|
|
71
82
|
};
|
|
72
83
|
};
|
|
73
84
|
|