@dcrays/dcgchat 0.2.18 → 0.2.25
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/openclaw.plugin.json +4 -2
- package/package.json +8 -6
- package/src/bot.ts +394 -265
- package/src/channel.ts +38 -38
- package/src/monitor.ts +77 -21
- package/src/skill.ts +72 -72
- package/src/tool.ts +105 -60
- package/README.md +0 -83
package/src/channel.ts
CHANGED
|
@@ -185,47 +185,47 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
185
185
|
// textChunkLimit: 25,
|
|
186
186
|
textChunkLimit: 4000,
|
|
187
187
|
sendText: async (ctx) => {
|
|
188
|
-
|
|
188
|
+
const ws = getWsConnection()
|
|
189
189
|
const params = getMsgParams();
|
|
190
190
|
const log = console.log;
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
191
|
+
if (ws?.readyState === WebSocket.OPEN) {
|
|
192
|
+
const {botToken} = resolveAccount(ctx.cfg, ctx.accountId);
|
|
193
|
+
const content = {
|
|
194
|
+
messageType: "openclaw_bot_chat",
|
|
195
|
+
_userId: params.userId,
|
|
196
|
+
source: "client",
|
|
197
|
+
content: {
|
|
198
|
+
bot_token: botToken,
|
|
199
|
+
domain_id: params.domainId,
|
|
200
|
+
app_id: params.appId,
|
|
201
|
+
bot_id: params.botId,
|
|
202
|
+
agent_id: params.agentId,
|
|
203
|
+
response: ctx.text,
|
|
204
|
+
session_id: params.sessionId,
|
|
205
|
+
message_id: params.messageId || Date.now().toString(),
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
ws.send(JSON.stringify(content));
|
|
209
|
+
ws.send(JSON.stringify({
|
|
210
|
+
messageType: "openclaw_bot_chat",
|
|
211
|
+
_userId: params.userId,
|
|
212
|
+
source: "client",
|
|
213
|
+
content: {
|
|
214
|
+
bot_token: botToken,
|
|
215
|
+
domain_id: params.domainId,
|
|
216
|
+
app_id: params.appId,
|
|
217
|
+
bot_id: params.botId,
|
|
218
|
+
agent_id: params.agentId,
|
|
219
|
+
ssession_id: params.sessionId,
|
|
220
|
+
message_id: params.messageId || Date.now().toString(),
|
|
221
|
+
response: '',
|
|
222
|
+
state: 'final',
|
|
223
|
+
},
|
|
224
|
+
}));
|
|
225
|
+
log(`dcgchat[${ctx.accountId}]: channel sendText to ${params.userId}, ${JSON.stringify(content)}`);
|
|
226
|
+
} else {
|
|
227
227
|
log(`[dcgchat][${ctx.accountId ?? DEFAULT_ACCOUNT_ID}] outbound -> : ${ctx.text}`);
|
|
228
|
-
|
|
228
|
+
}
|
|
229
229
|
return {
|
|
230
230
|
channel: "dcgchat",
|
|
231
231
|
messageId: `dcg-${Date.now()}`,
|
package/src/monitor.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ClawdbotConfig, RuntimeEnv } from "openclaw/plugin-sdk";
|
|
2
2
|
import WebSocket from "ws";
|
|
3
|
-
import { handleDcgchatMessage } from "./bot.js";
|
|
3
|
+
import { abortMobookappGeneration, handleDcgchatMessage } from "./bot.js";
|
|
4
4
|
import { resolveAccount } from "./channel.js";
|
|
5
5
|
import { setWsConnection } from "./connection.js";
|
|
6
|
-
import type { InboundMessage
|
|
7
|
-
import { setMsgParams,setMsgStatus } from "./tool.js";
|
|
6
|
+
import type { InboundMessage } from "./types.js";
|
|
7
|
+
import { setMsgParams, setMsgStatus } from "./tool.js";
|
|
8
8
|
import { installSkill, uninstallSkill } from "./skill.js";
|
|
9
9
|
|
|
10
10
|
export type MonitorDcgchatOpts = {
|
|
@@ -16,6 +16,13 @@ export type MonitorDcgchatOpts = {
|
|
|
16
16
|
|
|
17
17
|
const RECONNECT_DELAY_MS = 3000;
|
|
18
18
|
const HEARTBEAT_INTERVAL_MS = 30_000;
|
|
19
|
+
const emptyToolText = [
|
|
20
|
+
"/new",
|
|
21
|
+
"/search",
|
|
22
|
+
"/stop",
|
|
23
|
+
"/abort",
|
|
24
|
+
"/queue interrupt",
|
|
25
|
+
];
|
|
19
26
|
|
|
20
27
|
function buildConnectUrl(account: Record<string, string>): string {
|
|
21
28
|
const { wsUrl, botToken, userId, domainId, appId } = account;
|
|
@@ -27,7 +34,9 @@ function buildConnectUrl(account: Record<string, string>): string {
|
|
|
27
34
|
return url.toString();
|
|
28
35
|
}
|
|
29
36
|
|
|
30
|
-
export async function monitorDcgchatProvider(
|
|
37
|
+
export async function monitorDcgchatProvider(
|
|
38
|
+
opts: MonitorDcgchatOpts,
|
|
39
|
+
): Promise<void> {
|
|
31
40
|
const { config, runtime, abortSignal, accountId } = opts;
|
|
32
41
|
// @ts-ignore
|
|
33
42
|
const cfg = config ?? (runtime?.config?.() as ClawdbotConfig | undefined);
|
|
@@ -99,7 +108,9 @@ export async function monitorDcgchatProvider(opts: MonitorDcgchatOpts): Promise<
|
|
|
99
108
|
}
|
|
100
109
|
|
|
101
110
|
if (parsed.messageType === "openclaw_bot_heartbeat") {
|
|
102
|
-
log(
|
|
111
|
+
log(
|
|
112
|
+
`dcgchat[${account.accountId}]: heartbeat ack received, ${data.toString()}`,
|
|
113
|
+
);
|
|
103
114
|
return;
|
|
104
115
|
}
|
|
105
116
|
try {
|
|
@@ -108,21 +119,36 @@ export async function monitorDcgchatProvider(opts: MonitorDcgchatOpts): Promise<
|
|
|
108
119
|
err(`dcgchat[${account.accountId}]: invalid JSON received`);
|
|
109
120
|
return;
|
|
110
121
|
}
|
|
111
|
-
|
|
122
|
+
|
|
112
123
|
if (parsed.messageType == "openclaw_bot_chat") {
|
|
113
124
|
const msg = parsed as unknown as InboundMessage;
|
|
114
|
-
|
|
115
|
-
|
|
125
|
+
if (!emptyToolText.includes(msg.content.text?.trim())) {
|
|
126
|
+
setMsgStatus("running");
|
|
127
|
+
}
|
|
128
|
+
log(
|
|
129
|
+
`dcgchat[${account.accountId}]: openclaw_bot_chat received, ${JSON.stringify(msg)}`,
|
|
130
|
+
);
|
|
131
|
+
if (msg.content.text === "/stop") {
|
|
132
|
+
const rawConvId = msg.content.session_id as string | undefined;
|
|
133
|
+
const conversationId =
|
|
134
|
+
rawConvId || `${accountId}:${account.botToken}`;
|
|
135
|
+
console.log("🚀 ~ connect ~ conversationId:", conversationId)
|
|
136
|
+
abortMobookappGeneration(conversationId);
|
|
137
|
+
log(`[dcgchat][in] abort conversationId=${conversationId}`);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
116
140
|
setMsgParams({
|
|
117
141
|
userId: msg._userId,
|
|
118
142
|
token: msg.content.bot_token,
|
|
119
143
|
sessionId: msg.content.session_id,
|
|
120
144
|
messageId: msg.content.message_id,
|
|
121
|
-
domainId: account.domainId ||
|
|
122
|
-
appId: account.appId ||
|
|
145
|
+
domainId: account.domainId || 1000,
|
|
146
|
+
appId: account.appId || "100",
|
|
123
147
|
botId: msg.content.bot_id,
|
|
124
148
|
agentId: msg.content.agent_id,
|
|
125
149
|
});
|
|
150
|
+
msg.content.app_id = account.appId || "100";
|
|
151
|
+
msg.content.domain_id = account.domainId || "1000";
|
|
126
152
|
await handleDcgchatMessage({
|
|
127
153
|
cfg,
|
|
128
154
|
msg,
|
|
@@ -135,24 +161,52 @@ export async function monitorDcgchatProvider(opts: MonitorDcgchatOpts): Promise<
|
|
|
135
161
|
}
|
|
136
162
|
},
|
|
137
163
|
});
|
|
138
|
-
}
|
|
139
|
-
const {
|
|
140
|
-
|
|
164
|
+
} else if (parsed.messageType == "openclaw_bot_event") {
|
|
165
|
+
const {
|
|
166
|
+
event_type,
|
|
167
|
+
operation_type,
|
|
168
|
+
skill_url,
|
|
169
|
+
skill_code,
|
|
170
|
+
skill_id,
|
|
171
|
+
bot_token,
|
|
172
|
+
websocket_trace_id,
|
|
173
|
+
} = parsed.content ? parsed.content : ({} as Record<string, any>);
|
|
174
|
+
const content = {
|
|
175
|
+
event_type,
|
|
176
|
+
operation_type,
|
|
177
|
+
skill_url,
|
|
178
|
+
skill_code,
|
|
179
|
+
skill_id,
|
|
180
|
+
bot_token,
|
|
181
|
+
websocket_trace_id,
|
|
182
|
+
};
|
|
141
183
|
if (event_type === "skill") {
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
|
|
184
|
+
if (
|
|
185
|
+
operation_type === "install" ||
|
|
186
|
+
operation_type === "enable" ||
|
|
187
|
+
operation_type === "update"
|
|
188
|
+
) {
|
|
189
|
+
installSkill({ path: skill_url, code: skill_code }, content);
|
|
190
|
+
} else if (
|
|
191
|
+
operation_type === "remove" ||
|
|
192
|
+
operation_type === "disable"
|
|
193
|
+
) {
|
|
145
194
|
uninstallSkill({ code: skill_code }, content);
|
|
146
195
|
} else {
|
|
147
|
-
log(
|
|
196
|
+
log(
|
|
197
|
+
`dcgchat[${account.accountId}]: openclaw_bot_event unknown event_type: ${event_type}, ${data.toString()}`,
|
|
198
|
+
);
|
|
148
199
|
}
|
|
149
200
|
} else {
|
|
150
|
-
log(
|
|
201
|
+
log(
|
|
202
|
+
`dcgchat[${account.accountId}]: openclaw_bot_event unknown operation_type: ${operation_type}, ${data.toString()}`,
|
|
203
|
+
);
|
|
151
204
|
}
|
|
152
205
|
} else {
|
|
153
|
-
log(
|
|
206
|
+
log(
|
|
207
|
+
`dcgchat[${account.accountId}]: ignoring unknown messageType: ${parsed.messageType}`,
|
|
208
|
+
);
|
|
154
209
|
}
|
|
155
|
-
|
|
156
210
|
});
|
|
157
211
|
|
|
158
212
|
ws.on("close", (code, reason) => {
|
|
@@ -162,7 +216,9 @@ export async function monitorDcgchatProvider(opts: MonitorDcgchatOpts): Promise<
|
|
|
162
216
|
`dcgchat[${account.accountId}]: disconnected (code=${code}, reason=${reason?.toString() || ""})`,
|
|
163
217
|
);
|
|
164
218
|
if (shouldReconnect) {
|
|
165
|
-
log(
|
|
219
|
+
log(
|
|
220
|
+
`dcgchat[${account.accountId}]: reconnecting in ${RECONNECT_DELAY_MS}ms...`,
|
|
221
|
+
);
|
|
166
222
|
setTimeout(connect, RECONNECT_DELAY_MS);
|
|
167
223
|
}
|
|
168
224
|
});
|
package/src/skill.ts
CHANGED
|
@@ -36,75 +36,75 @@ function sendEvent(msgContent: Record<string, any>) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
async function sendNewSessionCommand(ctx: SkillContext) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
39
|
+
// async function sendNewSessionCommand(ctx: SkillContext) {
|
|
40
|
+
// try {
|
|
41
|
+
// const core = getDcgchatRuntime();
|
|
42
|
+
// const log = ctx.runtime?.log ?? console.log;
|
|
43
|
+
// const params = getMsgParams();
|
|
44
|
+
// const account = resolveAccount(ctx.cfg, ctx.accountId);
|
|
45
|
+
// const userId = String(params.userId);
|
|
46
|
+
|
|
47
|
+
// const route = core.channel.routing.resolveAgentRoute({
|
|
48
|
+
// cfg: ctx.cfg,
|
|
49
|
+
// channel: "dcgchat",
|
|
50
|
+
// accountId: account.accountId,
|
|
51
|
+
// peer: { kind: "direct", id: userId },
|
|
52
|
+
// });
|
|
53
|
+
|
|
54
|
+
// const envelopeOptions = core.channel.reply.resolveEnvelopeFormatOptions(ctx.cfg);
|
|
55
|
+
// const bodyFormatted = core.channel.reply.formatAgentEnvelope({
|
|
56
|
+
// channel: "书灵墨宝",
|
|
57
|
+
// from: userId,
|
|
58
|
+
// timestamp: new Date(),
|
|
59
|
+
// envelope: envelopeOptions,
|
|
60
|
+
// body: "/new",
|
|
61
|
+
// });
|
|
62
|
+
|
|
63
|
+
// const ctxPayload = core.channel.reply.finalizeInboundContext({
|
|
64
|
+
// Body: bodyFormatted,
|
|
65
|
+
// RawBody: "/new",
|
|
66
|
+
// CommandBody: "/new",
|
|
67
|
+
// From: userId,
|
|
68
|
+
// To: userId,
|
|
69
|
+
// SessionKey: route.sessionKey,
|
|
70
|
+
// AccountId: params.sessionId,
|
|
71
|
+
// ChatType: "direct",
|
|
72
|
+
// SenderName: userId,
|
|
73
|
+
// SenderId: userId,
|
|
74
|
+
// Provider: "dcgchat" as const,
|
|
75
|
+
// Surface: "dcgchat" as const,
|
|
76
|
+
// MessageSid: Date.now().toString(),
|
|
77
|
+
// Timestamp: Date.now(),
|
|
78
|
+
// WasMentioned: true,
|
|
79
|
+
// CommandAuthorized: true,
|
|
80
|
+
// OriginatingChannel: "dcgchat" as const,
|
|
81
|
+
// OriginatingTo: `user:${userId}`,
|
|
82
|
+
// });
|
|
83
|
+
|
|
84
|
+
// const noopDispatcher = {
|
|
85
|
+
// sendToolResult: () => false,
|
|
86
|
+
// sendBlockReply: () => false,
|
|
87
|
+
// sendFinalReply: () => false,
|
|
88
|
+
// waitForIdle: async () => {},
|
|
89
|
+
// getQueuedCounts: () => ({ tool: 0, block: 0, final: 0 }),
|
|
90
|
+
// markComplete: () => {},
|
|
91
|
+
// };
|
|
92
|
+
|
|
93
|
+
// await core.channel.reply.withReplyDispatcher({
|
|
94
|
+
// dispatcher: noopDispatcher,
|
|
95
|
+
// run: () =>
|
|
96
|
+
// core.channel.reply.dispatchReplyFromConfig({
|
|
97
|
+
// ctx: ctxPayload,
|
|
98
|
+
// cfg: ctx.cfg,
|
|
99
|
+
// dispatcher: noopDispatcher,
|
|
100
|
+
// }),
|
|
101
|
+
// });
|
|
102
|
+
|
|
103
|
+
// log(`dcgchat: /new command dispatched silently after skill install`);
|
|
104
|
+
// } catch (err) {
|
|
105
|
+
// logDcgchat.error(`sendNewSessionCommand failed: ${err}`);
|
|
106
|
+
// }
|
|
107
|
+
// }
|
|
108
108
|
|
|
109
109
|
export async function installSkill(params: ISkillParams, msgContent: Record<string, any>, ctx?: SkillContext) {
|
|
110
110
|
const { path: cdnUrl, code } = params;
|
|
@@ -208,9 +208,9 @@ export async function installSkill(params: ISkillParams, msgContent: Record<stri
|
|
|
208
208
|
});
|
|
209
209
|
});
|
|
210
210
|
sendEvent({ ...msgContent, status: 'ok' })
|
|
211
|
-
if (ctx) {
|
|
212
|
-
|
|
213
|
-
}
|
|
211
|
+
// if (ctx) {
|
|
212
|
+
// await sendNewSessionCommand(ctx);
|
|
213
|
+
// }
|
|
214
214
|
} catch (error) {
|
|
215
215
|
// 如果安装失败,清理目录
|
|
216
216
|
if (fs.existsSync(skillDir)) {
|
package/src/tool.ts
CHANGED
|
@@ -28,68 +28,113 @@ export function setMsgStatus(status: 'running' | 'finished' | '') {
|
|
|
28
28
|
export function getMsgStatus() {
|
|
29
29
|
return msgStatus;
|
|
30
30
|
}
|
|
31
|
-
let
|
|
31
|
+
let toolCallId = '';
|
|
32
32
|
let toolName = '';
|
|
33
|
+
type PluginHookName = "before_model_resolve" | "before_prompt_build" | "before_agent_start" | "llm_input" | "llm_output" | "agent_end" | "before_compaction" | "after_compaction" | "before_reset" | "message_received" | "message_sending" | "message_sent" | "before_tool_call" | "after_tool_call" | "tool_result_persist" | "before_message_write" | "session_start" | "session_end" | "subagent_spawning" | "subagent_delivery_target" | "subagent_spawned" | "subagent_ended" | "gateway_start" | "gateway_stop";
|
|
34
|
+
const eventList = [
|
|
35
|
+
{event: 'message_received', message: ''},
|
|
36
|
+
// {event: 'before_model_resolve', message: ''},
|
|
37
|
+
// {event: 'before_prompt_build', message: '正在查阅背景资料,构建思考逻辑'},
|
|
38
|
+
// {event: 'before_agent_start', message: '书灵墨宝已就位,准备开始执行任务'},
|
|
39
|
+
{event: 'subagent_spawning', message: ''},
|
|
40
|
+
{event: 'subagent_spawned', message: ''},
|
|
41
|
+
{event: 'subagent_delivery_target', message: ''},
|
|
42
|
+
// {event: 'llm_input', message: ''},
|
|
43
|
+
{event: 'llm_output', message: ''},
|
|
44
|
+
// {event: 'agent_end', message: '核心任务已处理完毕...'},
|
|
45
|
+
{event: 'subagent_ended', message: ''},
|
|
46
|
+
// {event: 'before_message_write', message: '正在将本次对话存入记忆库...'},
|
|
47
|
+
// {event: 'message_sending', message: ''},
|
|
48
|
+
// {event: 'message_send', message: ''},
|
|
49
|
+
{event: 'before_tool_call', message: ''},
|
|
50
|
+
{event: 'after_tool_call', message: ''},
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
function sendToolCallMessage(text: string, toolCallId: string, isCover: number) {
|
|
54
|
+
const ws = getWsConnection()
|
|
55
|
+
const params = getMsgParams();
|
|
56
|
+
const status = getMsgStatus();
|
|
57
|
+
if (ws?.readyState === WebSocket.OPEN && status === 'running') {
|
|
58
|
+
ws.send(JSON.stringify({
|
|
59
|
+
messageType: "openclaw_bot_chat",
|
|
60
|
+
_userId: params?.userId,
|
|
61
|
+
source: "client",
|
|
62
|
+
content: {
|
|
63
|
+
bot_token: params?.token,
|
|
64
|
+
domain_id: params?.domainId,
|
|
65
|
+
app_id: params?.appId,
|
|
66
|
+
bot_id: params?.botId,
|
|
67
|
+
agent_id: params?.agentId,
|
|
68
|
+
response: 'all_finished',
|
|
69
|
+
session_id:params?.sessionId,
|
|
70
|
+
message_id: params?.messageId || Date.now().toString()
|
|
71
|
+
},
|
|
72
|
+
}))
|
|
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
|
+
domain_id: params?.domainId,
|
|
80
|
+
app_id: params?.appId,
|
|
81
|
+
bot_id: params?.botId,
|
|
82
|
+
agent_id: params?.agentId,
|
|
83
|
+
tool_call_id: toolCallId,
|
|
84
|
+
is_cover: isCover,
|
|
85
|
+
thinking_content: text,
|
|
86
|
+
response: '',
|
|
87
|
+
session_id:params?.sessionId,
|
|
88
|
+
message_id: params?.messageId || Date.now().toString()
|
|
89
|
+
},
|
|
90
|
+
}));
|
|
91
|
+
ws.send(JSON.stringify({
|
|
92
|
+
messageType: "openclaw_bot_chat",
|
|
93
|
+
_userId: params?.userId,
|
|
94
|
+
source: "client",
|
|
95
|
+
content: {
|
|
96
|
+
bot_token: params?.token,
|
|
97
|
+
domain_id: params?.domainId,
|
|
98
|
+
app_id: params?.appId,
|
|
99
|
+
bot_id: params?.botId,
|
|
100
|
+
agent_id: params?.agentId,
|
|
101
|
+
response: 'all_finished',
|
|
102
|
+
session_id:params?.sessionId,
|
|
103
|
+
message_id: params?.messageId || Date.now().toString()
|
|
104
|
+
},
|
|
105
|
+
}))
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
33
109
|
export function monitoringToolMessage(api: OpenClawPluginApi) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
110
|
+
for (const item of eventList) {
|
|
111
|
+
api.on(item.event as PluginHookName, (event: any) => {
|
|
112
|
+
console.log("🚀 ~ 工具调用结果: ~ event:", item.event)
|
|
113
|
+
if (['after_tool_call', 'before_tool_call'].includes(item.event)) {
|
|
114
|
+
const { result: _result, ...rest } = event;
|
|
115
|
+
const text = JSON.stringify({
|
|
116
|
+
type: item.event,
|
|
117
|
+
specialIdentification: 'dcgchat_tool_call_special_identification',
|
|
118
|
+
callId: event.toolCallId || event.runId || Date.now().toString(),
|
|
119
|
+
...rest,
|
|
120
|
+
status: item.event === 'after_tool_call' ? 'finished' : 'running'
|
|
121
|
+
});
|
|
122
|
+
sendToolCallMessage(text, event.toolCallId || event.runId || Date.now().toString(), item.event === 'after_tool_call' ? 1 : 0)
|
|
123
|
+
} else if (item.event) {
|
|
124
|
+
const text = JSON.stringify({
|
|
125
|
+
type: item.event,
|
|
126
|
+
specialIdentification: 'dcgchat_tool_call_special_identification',
|
|
127
|
+
toolName: '',
|
|
128
|
+
callId: event.runId || Date.now().toString(),
|
|
129
|
+
params: item.message
|
|
130
|
+
});
|
|
131
|
+
sendToolCallMessage(text, event.runId || Date.now().toString(), 0)
|
|
132
|
+
console.log('消息事件:', item.event, item.message)
|
|
133
|
+
}
|
|
134
|
+
// log?.(`dcgchat[${params?.sessionId}]:11111111 tool message to ${params?.sessionId}, ${JSON.stringify(rest)}`);
|
|
135
|
+
// } else {
|
|
136
|
+
// log?.(`dcgchat[${params?.sessionId}]:22222222 tool ${status} message to ${ws?.readyState}, ${JSON.stringify(rest)}`);
|
|
137
|
+
// }
|
|
59
138
|
});
|
|
60
|
-
ws.send(JSON.stringify({
|
|
61
|
-
messageType: "openclaw_bot_chat",
|
|
62
|
-
_userId: params?.userId,
|
|
63
|
-
source: "client",
|
|
64
|
-
content: {
|
|
65
|
-
bot_token: params?.token,
|
|
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: '',
|
|
72
|
-
session_id:params?.sessionId,
|
|
73
|
-
message_id: params?.messageId || Date.now().toString()
|
|
74
|
-
},
|
|
75
|
-
}));
|
|
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)}`);
|
|
93
139
|
}
|
|
94
|
-
});
|
|
95
140
|
}
|
package/README.md
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# OpenClaw 书灵墨宝 插件
|
|
2
|
-
|
|
3
|
-
连接 OpenClaw 与 书灵墨宝 产品的通道插件。
|
|
4
|
-
|
|
5
|
-
## 架构
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
┌──────────┐ WebSocket ┌──────────────┐ WebSocket ┌─────────────────────┐
|
|
9
|
-
│ Web 前端 │ ←───────────────→ │ 公司后端服务 │ ←───────────────→ │ OpenClaw(工作电脑) │
|
|
10
|
-
└──────────┘ └──────────────┘ (OpenClaw 主动连) └─────────────────────┘
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
- OpenClaw 插件**主动连接**后端的 WebSocket 服务(不需要公网 IP)
|
|
14
|
-
- 后端收到用户消息后转发给 OpenClaw,OpenClaw 回复后发回后端
|
|
15
|
-
|
|
16
|
-
## 快速开始
|
|
17
|
-
|
|
18
|
-
### 1. 安装插件
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
pnpm openclaw plugins install -l /path/to/openclaw-dcgchat
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### 2. 配置
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
openclaw config set channels.dcgchat.enabled true
|
|
28
|
-
openclaw config set channels.dcgchat.wsUrl "ws://your-backend:8080/openclaw/ws"
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### 3. 启动
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
pnpm openclaw gateway
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## 消息协议(MVP)
|
|
38
|
-
|
|
39
|
-
### 下行:后端 → OpenClaw(用户消息)
|
|
40
|
-
|
|
41
|
-
```json
|
|
42
|
-
{ "type": "message", "userId": "user_001", "text": "你好" }
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### 上行:OpenClaw → 后端(Agent 回复)
|
|
46
|
-
|
|
47
|
-
```json
|
|
48
|
-
{ "type": "reply", "userId": "user_001", "text": "你好!有什么可以帮你的?" }
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## 配置项
|
|
52
|
-
|
|
53
|
-
| 配置键 | 类型 | 说明 |
|
|
54
|
-
|--------|------|------|
|
|
55
|
-
| `channels.dcgchat.enabled` | boolean | 是否启用 |
|
|
56
|
-
| `channels.dcgchat.wsUrl` | string | 后端 WebSocket 地址 |
|
|
57
|
-
|
|
58
|
-
## 开发
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
# 安装依赖
|
|
62
|
-
pnpm install
|
|
63
|
-
|
|
64
|
-
# 类型检查
|
|
65
|
-
pnpm typecheck
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## 文件结构
|
|
69
|
-
|
|
70
|
-
- `index.ts` - 插件入口
|
|
71
|
-
- `src/channel.ts` - ChannelPlugin 定义
|
|
72
|
-
- `src/runtime.ts` - 插件 runtime
|
|
73
|
-
- `src/types.ts` - 类型定义
|
|
74
|
-
- `src/monitor.ts` - WebSocket 连接与断线重连
|
|
75
|
-
- `src/bot.ts` - 消息处理与 Agent 调用
|
|
76
|
-
|
|
77
|
-
## 后续迭代
|
|
78
|
-
|
|
79
|
-
- [ ] Token 认证
|
|
80
|
-
- [ ] 流式输出
|
|
81
|
-
- [ ] Typing 指示
|
|
82
|
-
- [ ] messageId 去重
|
|
83
|
-
- [ ] 错误消息类型
|