@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/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
- // const ws = getWsConnection()
188
+ const ws = getWsConnection()
189
189
  const params = getMsgParams();
190
190
  const log = console.log;
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 {
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, OutboundReply } from "./types.js";
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(opts: MonitorDcgchatOpts): Promise<void> {
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(`dcgchat[${account.accountId}]: heartbeat ack received, ${data.toString()}`);
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
- setMsgStatus('running');
115
- log(`dcgchat[${account.accountId}]: openclaw_bot_chat received, ${JSON.stringify(msg)}`);
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 || 1000,
122
- appId: account.appId || '100',
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
- } else if (parsed.messageType == "openclaw_bot_event") {
139
- const { event_type, operation_type, skill_url, skill_code, skill_id, bot_token, websocket_trace_id } = parsed.content ? parsed.content : {} as Record<string, any>;
140
- const content = { event_type, operation_type, skill_url, skill_code, skill_id, bot_token, websocket_trace_id };
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 (operation_type === "install" || operation_type === "enable" || operation_type === "update") {
143
- installSkill({ path: skill_url, code: skill_code }, content, { cfg, accountId: account.accountId, runtime });
144
- } else if (operation_type === "remove" || operation_type === "disable") {
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(`dcgchat[${account.accountId}]: openclaw_bot_event unknown event_type: ${event_type}, ${data.toString()}`);
196
+ log(
197
+ `dcgchat[${account.accountId}]: openclaw_bot_event unknown event_type: ${event_type}, ${data.toString()}`,
198
+ );
148
199
  }
149
200
  } else {
150
- log(`dcgchat[${account.accountId}]: openclaw_bot_event unknown operation_type: ${operation_type}, ${data.toString()}`);
201
+ log(
202
+ `dcgchat[${account.accountId}]: openclaw_bot_event unknown operation_type: ${operation_type}, ${data.toString()}`,
203
+ );
151
204
  }
152
205
  } else {
153
- log(`dcgchat[${account.accountId}]: ignoring unknown messageType: ${parsed.messageType}`);
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(`dcgchat[${account.accountId}]: reconnecting in ${RECONNECT_DELAY_MS}ms...`);
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
- 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
- }
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
- await sendNewSessionCommand(ctx);
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 runId = '';
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
- api.on("after_tool_call", (event) => {
35
- const ws = getWsConnection()
36
- const params = getMsgParams();
37
- const status = getMsgStatus();
38
- //
39
- if (ws?.readyState === WebSocket.OPEN && status === 'running') {
40
- const log = api.runtime?.log ?? api.log;
41
- // @ts-ignore
42
- if (!runId || runId !== event.runId || !toolName || toolName !== event.toolName) {
43
- ws.send(JSON.stringify({
44
- messageType: "openclaw_bot_chat",
45
- _userId: params?.userId,
46
- source: "client",
47
- content: {
48
- bot_token: params?.token,
49
- response: 'all_finished',
50
- session_id:params?.sessionId,
51
- message_id: params?.messageId || Date.now().toString()
52
- },
53
- }));
54
- }
55
- const text = JSON.stringify({
56
- type: 'tool_call',
57
- specialIdentification: 'dcgchat_tool_call_special_identification',
58
- ...event
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
- - [ ] 错误消息类型