@wildfirechat/openclaw-plugin 1.0.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 +107 -0
- package/dist/channel.d.ts +65 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +221 -0
- package/dist/channel.js.map +1 -0
- package/dist/clients.d.ts +26 -0
- package/dist/clients.d.ts.map +1 -0
- package/dist/clients.js +81 -0
- package/dist/clients.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +77 -0
- package/dist/config.js.map +1 -0
- package/dist/inbound.d.ts +9 -0
- package/dist/inbound.d.ts.map +1 -0
- package/dist/inbound.js +286 -0
- package/dist/inbound.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/targets.d.ts +23 -0
- package/dist/targets.d.ts.map +1 -0
- package/dist/targets.js +36 -0
- package/dist/targets.js.map +1 -0
- package/dist/utils.d.ts +9 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +85 -0
- package/dist/utils.js.map +1 -0
- package/openclaw.plugin.json +95 -0
- package/package.json +59 -0
package/dist/inbound.js
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handle incoming messages from Wildfire IM
|
|
3
|
+
*/
|
|
4
|
+
// @ts-ignore - runtime may not be fully typed
|
|
5
|
+
import { shouldRespondToGroupMessage } from "./utils.js";
|
|
6
|
+
import { getClient } from "./clients.js";
|
|
7
|
+
import { TextMessageContent, StreamingTextGeneratingMessageContent, StreamingTextGeneratedMessageContent, } from "@wildfirechat/server-sdk";
|
|
8
|
+
// Message type constants
|
|
9
|
+
const MESSAGE_TYPE_TEXT = 1;
|
|
10
|
+
const MESSAGE_TYPE_IMAGE = 3;
|
|
11
|
+
const MESSAGE_TYPE_VIDEO = 4;
|
|
12
|
+
const MESSAGE_TYPE_FILE = 5;
|
|
13
|
+
// Conversation type constants
|
|
14
|
+
const CONV_TYPE_SINGLE = 0;
|
|
15
|
+
const CONV_TYPE_GROUP = 1;
|
|
16
|
+
const CONV_TYPE_CHANNEL = 2;
|
|
17
|
+
/**
|
|
18
|
+
* Process incoming message from Wildfire IM
|
|
19
|
+
*/
|
|
20
|
+
export async function handleIncomingMessage(api, message, config) {
|
|
21
|
+
const runtime = api.runtime;
|
|
22
|
+
if (!runtime?.channel?.reply?.dispatchReplyWithBufferedBlockDispatcher) {
|
|
23
|
+
api.logger?.warn?.("[wildfire] runtime.channel.reply not available");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const data = message.data;
|
|
27
|
+
if (!data)
|
|
28
|
+
return;
|
|
29
|
+
const sender = data.sender;
|
|
30
|
+
const conv = data.conv;
|
|
31
|
+
const payload = data.payload;
|
|
32
|
+
if (!sender || !conv || !payload)
|
|
33
|
+
return;
|
|
34
|
+
// Skip non-content messages
|
|
35
|
+
const payloadType = payload.type;
|
|
36
|
+
if (payloadType <= 0 || (payloadType > 15 && payloadType < 100) || payloadType > 200) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const isGroup = conv.type === CONV_TYPE_GROUP || conv.type === CONV_TYPE_CHANNEL;
|
|
40
|
+
const text = extractTextContent(payload);
|
|
41
|
+
// Check if should respond (group filtering)
|
|
42
|
+
if (isGroup && !shouldRespondToGroupMessage(text, data, config)) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const baseSessionKey = isGroup
|
|
46
|
+
? `wildfire:group:${conv.target}`.toLowerCase()
|
|
47
|
+
: `wildfire:${sender}`.toLowerCase();
|
|
48
|
+
const cfg = api.config;
|
|
49
|
+
const route = runtime.channel.routing?.resolveAgentRoute?.({
|
|
50
|
+
cfg,
|
|
51
|
+
sessionKey: baseSessionKey,
|
|
52
|
+
channel: "wildfire",
|
|
53
|
+
accountId: "default",
|
|
54
|
+
}) ?? { agentId: "main", sessionKey: baseSessionKey };
|
|
55
|
+
const sessionKey = String(route?.sessionKey ?? baseSessionKey).trim() || baseSessionKey;
|
|
56
|
+
const storePath = runtime.channel.session?.resolveStorePath?.(cfg?.session?.store, {
|
|
57
|
+
agentId: route.agentId,
|
|
58
|
+
}) ?? "";
|
|
59
|
+
const chatType = isGroup ? "group" : "direct";
|
|
60
|
+
const fromLabel = String(sender);
|
|
61
|
+
const senderId = String(sender);
|
|
62
|
+
const timestamp = Date.now();
|
|
63
|
+
const ctxPayload = {
|
|
64
|
+
Body: text,
|
|
65
|
+
RawBody: text,
|
|
66
|
+
From: `wildfire:user:${sender}`,
|
|
67
|
+
To: isGroup ? `wildfire:group:${conv.target}` : `wildfire:user:${sender}`,
|
|
68
|
+
SessionKey: sessionKey,
|
|
69
|
+
AccountId: "default",
|
|
70
|
+
ChatType: chatType,
|
|
71
|
+
ConversationLabel: fromLabel,
|
|
72
|
+
SenderName: fromLabel,
|
|
73
|
+
SenderId: senderId,
|
|
74
|
+
Provider: "wildfire",
|
|
75
|
+
Surface: "wildfire",
|
|
76
|
+
MessageSid: `wildfire-${Date.now()}`,
|
|
77
|
+
Timestamp: timestamp,
|
|
78
|
+
OriginatingChannel: "wildfire",
|
|
79
|
+
OriginatingTo: `wildfire:${config.robotId || "bot"}`,
|
|
80
|
+
CommandAuthorized: true,
|
|
81
|
+
_wildfire: {
|
|
82
|
+
accountId: "default",
|
|
83
|
+
isGroup,
|
|
84
|
+
senderId,
|
|
85
|
+
conversationId: conv.target,
|
|
86
|
+
messageType: payloadType,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
// Record session
|
|
90
|
+
if (runtime.channel.session?.recordInboundSession) {
|
|
91
|
+
await runtime.channel.session.recordInboundSession({
|
|
92
|
+
storePath,
|
|
93
|
+
sessionKey,
|
|
94
|
+
ctx: ctxPayload,
|
|
95
|
+
updateLastRoute: !isGroup
|
|
96
|
+
? {
|
|
97
|
+
sessionKey,
|
|
98
|
+
channel: "wildfire",
|
|
99
|
+
to: senderId,
|
|
100
|
+
accountId: "default",
|
|
101
|
+
}
|
|
102
|
+
: undefined,
|
|
103
|
+
onRecordError: (err) => api.logger?.warn?.(`[wildfire] recordInboundSession: ${String(err)}`),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Record activity
|
|
107
|
+
if (runtime.channel.activity?.record) {
|
|
108
|
+
runtime.channel.activity.record({
|
|
109
|
+
channel: "wildfire",
|
|
110
|
+
accountId: "default",
|
|
111
|
+
direction: "inbound",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
// 生成唯一的 streamId 用于流式消息(每条用户消息有独立的流)
|
|
115
|
+
const streamId = `stream-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
116
|
+
let finalText = "";
|
|
117
|
+
let hasStarted = false;
|
|
118
|
+
let hasCompleted = false;
|
|
119
|
+
// 先发送一个空的 generating 消息显示转圈等待
|
|
120
|
+
try {
|
|
121
|
+
await sendStreamingReply(sender, conv, "...", streamId, "generating", api);
|
|
122
|
+
hasStarted = true;
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
api.logger?.error?.(`[wildfire] initial stream failed: ${e.message}`);
|
|
126
|
+
}
|
|
127
|
+
// Dispatch to OpenClaw - 使用真正的流式回复(onPartialReply)
|
|
128
|
+
try {
|
|
129
|
+
await runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
130
|
+
ctx: ctxPayload,
|
|
131
|
+
cfg,
|
|
132
|
+
dispatcherOptions: {
|
|
133
|
+
deliver: async (payload) => {
|
|
134
|
+
// deliver 接收最终完整内容
|
|
135
|
+
if (payload.text) {
|
|
136
|
+
finalText = payload.text;
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
onError: (err, info) => {
|
|
140
|
+
api.logger?.error?.(`[wildfire] ${info?.kind || "reply"} failed: ${String(err)}`);
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
replyOptions: {
|
|
144
|
+
disableBlockStreaming: false,
|
|
145
|
+
// 真正的流式回调:每次生成新内容时触发
|
|
146
|
+
onPartialReply: async (payload) => {
|
|
147
|
+
if (!payload.text)
|
|
148
|
+
return;
|
|
149
|
+
// 更新最终文本
|
|
150
|
+
finalText = payload.text;
|
|
151
|
+
api.logger?.debug?.(`[wildfire-debug] onPartialReply: ${payload.text.substring(0, 30)}...`);
|
|
152
|
+
try {
|
|
153
|
+
// 发送 generating 消息更新同一条消息
|
|
154
|
+
await sendStreamingReply(sender, conv, payload.text, streamId, "generating", api);
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
api.logger?.error?.(`[wildfire] stream update failed: ${e.message}`);
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
// 流式完成,发送 completed 消息
|
|
163
|
+
if (!hasCompleted) {
|
|
164
|
+
hasCompleted = true;
|
|
165
|
+
api.logger?.debug?.(`[wildfire-debug] stream completed, text=${finalText?.substring(0, 30)}`);
|
|
166
|
+
// 如果有内容就发送 completed,否则发送错误提示
|
|
167
|
+
const textToSend = finalText || "(no response)";
|
|
168
|
+
await sendStreamingReply(sender, conv, textToSend, streamId, "completed", api);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
api.logger?.error?.(`[wildfire] dispatch failed: ${err.message}`);
|
|
173
|
+
try {
|
|
174
|
+
const errorText = `Processing failed: ${err.message.slice(0, 80)}`;
|
|
175
|
+
await sendStreamingReply(sender, conv, errorText, streamId, "completed", api);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// ignore secondary send errors
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Send streaming reply back to Wildfire IM
|
|
184
|
+
*
|
|
185
|
+
* 流式消息分为三种状态:
|
|
186
|
+
* - start: 流式开始,发送首段内容
|
|
187
|
+
* - generating: 流式生成中,发送增量内容
|
|
188
|
+
* - completed: 流式完成,发送最终完整内容
|
|
189
|
+
*/
|
|
190
|
+
async function sendStreamingReply(sender, conv, text, streamId, state, api) {
|
|
191
|
+
api?.logger?.debug?.(`[wildfire-debug] sendStreamingReply called, state=${state}, text=${text?.substring(0, 30)}`);
|
|
192
|
+
const client = getClient();
|
|
193
|
+
if (!client) {
|
|
194
|
+
api?.logger?.error?.("[wildfire-debug] client not connected");
|
|
195
|
+
throw new Error("Wildfire client not connected");
|
|
196
|
+
}
|
|
197
|
+
const conversation = {
|
|
198
|
+
type: conv.type,
|
|
199
|
+
target: conv.type === 0 ? sender : conv.target,
|
|
200
|
+
line: conv.line,
|
|
201
|
+
};
|
|
202
|
+
let payload;
|
|
203
|
+
if (state === "generating" || state === "start") {
|
|
204
|
+
// 流式生成中 - 使用 StreamingTextGeneratingMessageContent
|
|
205
|
+
const generatingContent = new StreamingTextGeneratingMessageContent();
|
|
206
|
+
generatingContent.text = text;
|
|
207
|
+
generatingContent.streamId = streamId;
|
|
208
|
+
payload = generatingContent.encode();
|
|
209
|
+
}
|
|
210
|
+
else if (state === "completed") {
|
|
211
|
+
// 流式生成完成 - 使用 StreamingTextGeneratedMessageContent
|
|
212
|
+
const generatedContent = new StreamingTextGeneratedMessageContent();
|
|
213
|
+
generatedContent.text = text;
|
|
214
|
+
generatedContent.streamId = streamId;
|
|
215
|
+
payload = generatedContent.encode();
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
// 其他情况使用普通文本消息
|
|
219
|
+
const textContent = new TextMessageContent();
|
|
220
|
+
textContent.content = text;
|
|
221
|
+
payload = textContent.encode();
|
|
222
|
+
}
|
|
223
|
+
api?.logger?.debug?.(`[wildfire-debug] sending streaming message: state=${state}, streamId=${streamId}`);
|
|
224
|
+
try {
|
|
225
|
+
const result = await client.sendMessage(conversation, payload);
|
|
226
|
+
api?.logger?.debug?.(`[wildfire-debug] sendMessage result: success=${result.isSuccess()}, msg=${result.getMsg()}`);
|
|
227
|
+
if (!result.isSuccess()) {
|
|
228
|
+
throw new Error(result.getMsg());
|
|
229
|
+
}
|
|
230
|
+
api?.logger?.debug?.(`[wildfire-debug] streaming message sent successfully`);
|
|
231
|
+
}
|
|
232
|
+
catch (e) {
|
|
233
|
+
api?.logger?.error?.(`[wildfire-debug] sendMessage error: ${e.message}`);
|
|
234
|
+
throw e;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Send reply back to Wildfire IM
|
|
239
|
+
*/
|
|
240
|
+
async function sendReply(sender, conv, text, api) {
|
|
241
|
+
api?.logger?.debug?.(`[wildfire-debug] sendReply called, text=${text?.substring(0, 30)}`);
|
|
242
|
+
const client = getClient();
|
|
243
|
+
if (!client) {
|
|
244
|
+
api?.logger?.error?.("[wildfire-debug] client not connected");
|
|
245
|
+
throw new Error("Wildfire client not connected");
|
|
246
|
+
}
|
|
247
|
+
const conversation = {
|
|
248
|
+
type: conv.type,
|
|
249
|
+
target: conv.type === 0 ? sender : conv.target,
|
|
250
|
+
line: conv.line,
|
|
251
|
+
};
|
|
252
|
+
api?.logger?.debug?.(`[wildfire-debug] conversation: type=${conv.type}, target=${conversation.target}, line=${conv.line}`);
|
|
253
|
+
const content = new TextMessageContent();
|
|
254
|
+
content.content = text;
|
|
255
|
+
api?.logger?.debug?.(`[wildfire-debug] content encoded, sending...`);
|
|
256
|
+
try {
|
|
257
|
+
const result = await client.sendMessage(conversation, content.encode());
|
|
258
|
+
api?.logger?.debug?.(`[wildfire-debug] sendMessage result: success=${result.isSuccess()}, msg=${result.getMsg()}`);
|
|
259
|
+
if (!result.isSuccess()) {
|
|
260
|
+
throw new Error(result.getMsg());
|
|
261
|
+
}
|
|
262
|
+
api?.logger?.debug?.(`[wildfire-debug] message sent successfully`);
|
|
263
|
+
}
|
|
264
|
+
catch (e) {
|
|
265
|
+
api?.logger?.error?.(`[wildfire-debug] sendMessage error: ${e.message}`);
|
|
266
|
+
throw e;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Extract text content from payload
|
|
271
|
+
*/
|
|
272
|
+
function extractTextContent(payload) {
|
|
273
|
+
switch (payload.type) {
|
|
274
|
+
case MESSAGE_TYPE_TEXT:
|
|
275
|
+
return payload.searchableContent || payload.content || "";
|
|
276
|
+
case MESSAGE_TYPE_IMAGE:
|
|
277
|
+
return "[图片]";
|
|
278
|
+
case MESSAGE_TYPE_VIDEO:
|
|
279
|
+
return "[视频]";
|
|
280
|
+
case MESSAGE_TYPE_FILE:
|
|
281
|
+
return `[文件] ${payload.searchableContent || ""}`;
|
|
282
|
+
default:
|
|
283
|
+
return `[消息类型:${payload.type}]`;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=inbound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbound.js","sourceRoot":"","sources":["../src/inbound.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAyC/C"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw Wildfire IM Channel Plugin
|
|
3
|
+
*/
|
|
4
|
+
import { WildfireChannelPlugin } from "./channel.js";
|
|
5
|
+
import { startClient, stopClient, isClientConnected } from "./clients.js";
|
|
6
|
+
import { getAccountConfig, validateConfig } from "./config.js";
|
|
7
|
+
export default function register(api) {
|
|
8
|
+
// Register channel
|
|
9
|
+
api.registerChannel({ plugin: WildfireChannelPlugin });
|
|
10
|
+
// Register service for lifecycle management
|
|
11
|
+
api.registerService({
|
|
12
|
+
id: "wildfire",
|
|
13
|
+
start: async () => {
|
|
14
|
+
if (isClientConnected()) {
|
|
15
|
+
api.logger?.info?.("[wildfire] service already started");
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const config = getAccountConfig(api);
|
|
19
|
+
if (!config) {
|
|
20
|
+
api.logger?.warn?.("[wildfire] plugin disabled or no config");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// Validate config
|
|
24
|
+
const error = validateConfig(config);
|
|
25
|
+
if (error) {
|
|
26
|
+
api.logger?.error?.(`[wildfire] invalid config: ${error}`);
|
|
27
|
+
throw new Error(`Wildfire config error: ${error}`);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
await startClient(api, config);
|
|
31
|
+
api.logger?.info?.("[wildfire] service started");
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
api.logger?.error?.("[wildfire] failed to start:", err);
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
stop: async () => {
|
|
39
|
+
await stopClient(api);
|
|
40
|
+
api.logger?.info?.("[wildfire] service stopped");
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
api.logger?.info?.("[wildfire] plugin loaded");
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE/D,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAQ;IACvC,mBAAmB;IACnB,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAEvD,4CAA4C;IAC5C,GAAG,CAAC,eAAe,CAAC;QAClB,EAAE,EAAE,UAAU;QACd,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,IAAI,iBAAiB,EAAE,EAAE,CAAC;gBACxB,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,oCAAoC,CAAC,CAAC;gBACzD,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,yCAAyC,CAAC,CAAC;gBAC9D,OAAO;YACT,CAAC;YAED,kBAAkB;YAClB,MAAM,KAAK,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;YACrC,IAAI,KAAK,EAAE,CAAC;gBACV,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,8BAA8B,KAAK,EAAE,CAAC,CAAC;gBAC3D,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,EAAE,CAAC,CAAC;YACrD,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;gBAC/B,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,4BAA4B,CAAC,CAAC;YACnD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;gBACxD,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;QACD,IAAI,EAAE,KAAK,IAAI,EAAE;YACf,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;YACtB,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,4BAA4B,CAAC,CAAC;QACnD,CAAC;KACF,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,0BAA0B,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Target parsing utilities
|
|
3
|
+
*/
|
|
4
|
+
export interface ParsedTarget {
|
|
5
|
+
id: string;
|
|
6
|
+
isGroup: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Parse a target string into id and type
|
|
10
|
+
*
|
|
11
|
+
* 支持的格式:
|
|
12
|
+
* - wildfire:user:<id> 或 wf:user:<id> → 单聊
|
|
13
|
+
* - wildfire:group:<id> 或 wf:group:<id> → 群聊
|
|
14
|
+
* - user:<id> → 单聊
|
|
15
|
+
* - group:<id> → 群聊
|
|
16
|
+
* - 纯 ID(无前缀)→ 默认为单聊
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseTarget(to: string): ParsedTarget | null;
|
|
19
|
+
/**
|
|
20
|
+
* Format a target string
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatTarget(id: string, isGroup: boolean): string;
|
|
23
|
+
//# sourceMappingURL=targets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAiB3D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAEjE"}
|
package/dist/targets.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Target parsing utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Parse a target string into id and type
|
|
6
|
+
*
|
|
7
|
+
* 支持的格式:
|
|
8
|
+
* - wildfire:user:<id> 或 wf:user:<id> → 单聊
|
|
9
|
+
* - wildfire:group:<id> 或 wf:group:<id> → 群聊
|
|
10
|
+
* - user:<id> → 单聊
|
|
11
|
+
* - group:<id> → 群聊
|
|
12
|
+
* - 纯 ID(无前缀)→ 默认为单聊
|
|
13
|
+
*/
|
|
14
|
+
export function parseTarget(to) {
|
|
15
|
+
if (!to)
|
|
16
|
+
return null;
|
|
17
|
+
// Remove optional provider prefix (wildfire: or wf:)
|
|
18
|
+
let cleanTarget = to.replace(/^(wildfire|wf):/i, "");
|
|
19
|
+
// Check explicit type prefix
|
|
20
|
+
if (cleanTarget.startsWith("group:")) {
|
|
21
|
+
return { id: cleanTarget.slice(6), isGroup: true };
|
|
22
|
+
}
|
|
23
|
+
if (cleanTarget.startsWith("user:")) {
|
|
24
|
+
return { id: cleanTarget.slice(5), isGroup: false };
|
|
25
|
+
}
|
|
26
|
+
// No explicit prefix - default to direct (user) chat
|
|
27
|
+
// This matches OpenIM's behavior where bare IDs are treated as user IDs
|
|
28
|
+
return { id: cleanTarget, isGroup: false };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Format a target string
|
|
32
|
+
*/
|
|
33
|
+
export function formatTarget(id, isGroup) {
|
|
34
|
+
return isGroup ? `group:${id}` : `user:${id}`;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=targets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.js","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAErB,qDAAqD;IACrD,IAAI,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAErD,6BAA6B;IAC7B,IAAI,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,EAAE,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACrD,CAAC;IACD,IAAI,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,EAAE,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACtD,CAAC;IAED,qDAAqD;IACrD,wEAAwE;IACxE,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,EAAU,EAAE,OAAgB;IACvD,OAAO,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC;AAChD,CAAC"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions
|
|
3
|
+
*/
|
|
4
|
+
import type { WildfireConfig } from "./config.js";
|
|
5
|
+
/**
|
|
6
|
+
* Check if should respond to a group message
|
|
7
|
+
*/
|
|
8
|
+
export declare function shouldRespondToGroupMessage(text: string, messageData: any, config: WildfireConfig): boolean;
|
|
9
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,GAAG,EAChB,MAAM,EAAE,cAAc,GACrB,OAAO,CA2BT"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check if should respond to a group message
|
|
6
|
+
*/
|
|
7
|
+
export function shouldRespondToGroupMessage(text, messageData, config) {
|
|
8
|
+
// Strategy 1: Check if mentioned
|
|
9
|
+
if (config.requireMention !== false) {
|
|
10
|
+
if (isMentioned(messageData)) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
// Strategy 2: Check question mark
|
|
15
|
+
if (/.*[??]$/.test(text)) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
// Strategy 3: Check help keywords
|
|
19
|
+
const keywords = (config.helpKeywords || "帮,请,分析,总结").split(",").map((k) => k.trim()).filter(Boolean);
|
|
20
|
+
for (const keyword of keywords) {
|
|
21
|
+
if (text.includes(keyword)) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// If requireMention is true and not met, don't respond
|
|
26
|
+
if (config.requireMention !== false) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if the robot is mentioned in the message
|
|
33
|
+
*
|
|
34
|
+
* 野火 IM mention 规则:
|
|
35
|
+
* - mentionedType === 2: @所有人,应该回复
|
|
36
|
+
* - mentionedType === 1: @部分人,检查 mentionedTargets 是否包含机器人 ID
|
|
37
|
+
* - mentionedType === 0 或不存在: 未被提及
|
|
38
|
+
*/
|
|
39
|
+
function isMentioned(messageData) {
|
|
40
|
+
try {
|
|
41
|
+
const payload = messageData.payload;
|
|
42
|
+
if (!payload)
|
|
43
|
+
return false;
|
|
44
|
+
const mentionedType = payload.mentionedType;
|
|
45
|
+
// mentionedType === 2: @所有人
|
|
46
|
+
if (mentionedType === 2) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
// mentionedType === 1: @部分人,检查 mentionedTargets
|
|
50
|
+
if (mentionedType === 1) {
|
|
51
|
+
const mentionedTargets = payload.mentionedTargets;
|
|
52
|
+
if (Array.isArray(mentionedTargets) && mentionedTargets.length > 0) {
|
|
53
|
+
// 获取机器人 ID(从 messageData 的 target 或 sender 推断)
|
|
54
|
+
// 机器人通常不是 sender,所以这里只需要检查是否有任何 mention
|
|
55
|
+
// 实际上,如果 mentionedTargets 不为空,说明有人被 @ 了
|
|
56
|
+
// 但为了精确匹配,我们需要知道机器人自己的 ID
|
|
57
|
+
// 简化处理:只要有部分人被 @,就认为机器人可能需要响应
|
|
58
|
+
// 或者可以通过配置来指定机器人 ID
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// 尝试从 extra 字段解析(旧格式兼容)
|
|
63
|
+
const extra = payload.extra;
|
|
64
|
+
if (extra && typeof extra === "string") {
|
|
65
|
+
try {
|
|
66
|
+
const extraData = JSON.parse(extra);
|
|
67
|
+
if (extraData.mentionedType === 2) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
if (extraData.mentionedType === 1 && Array.isArray(extraData.mentionedTargets)) {
|
|
71
|
+
return extraData.mentionedTargets.length > 0;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// JSON 解析失败,忽略
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Utility functions moved to targets.ts
|
|
85
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,MAAM,UAAU,2BAA2B,CACzC,IAAY,EACZ,WAAgB,EAChB,MAAsB;IAEtB,iCAAiC;IACjC,IAAI,MAAM,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;QACpC,IAAI,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,kCAAkC;IAClC,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,kCAAkC;IAClC,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9G,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,IAAI,MAAM,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,WAAW,CAAC,WAAgB;IACnC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;QACpC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAE3B,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;QAE5C,4BAA4B;QAC5B,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,gDAAgD;QAChD,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;YAClD,IAAI,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnE,+CAA+C;gBAC/C,wCAAwC;gBACxC,wCAAwC;gBACxC,0BAA0B;gBAC1B,8BAA8B;gBAC9B,oBAAoB;gBACpB,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,wBAAwB;QACxB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACvC,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACpC,IAAI,SAAS,CAAC,aAAa,KAAK,CAAC,EAAE,CAAC;oBAClC,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,IAAI,SAAS,CAAC,aAAa,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,gBAAgB,CAAC,EAAE,CAAC;oBAC/E,OAAO,SAAS,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,eAAe;YACjB,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,wCAAwC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "wildfire",
|
|
3
|
+
"name": "Wildfire IM",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "Wildfire IM channel for OpenClaw",
|
|
6
|
+
"author": "Wildfire IM Team",
|
|
7
|
+
"channels": [
|
|
8
|
+
"wildfire"
|
|
9
|
+
],
|
|
10
|
+
"configSchema": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"additionalProperties": false,
|
|
13
|
+
"properties": {
|
|
14
|
+
"enabled": {
|
|
15
|
+
"type": "boolean",
|
|
16
|
+
"default": true
|
|
17
|
+
},
|
|
18
|
+
"gatewayUrl": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "Wildfire IM gateway WebSocket URL, e.g. ws://localhost:8884/robot/gateway",
|
|
21
|
+
"default": ""
|
|
22
|
+
},
|
|
23
|
+
"robotId": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "Robot ID",
|
|
26
|
+
"default": ""
|
|
27
|
+
},
|
|
28
|
+
"robotSecret": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"description": "Robot secret",
|
|
31
|
+
"default": ""
|
|
32
|
+
},
|
|
33
|
+
"requireMention": {
|
|
34
|
+
"type": "boolean",
|
|
35
|
+
"default": true,
|
|
36
|
+
"description": "Whether replies in groups require mentioning the robot"
|
|
37
|
+
},
|
|
38
|
+
"helpKeywords": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"default": "帮,请,分析,总结",
|
|
41
|
+
"description": "Comma-separated keywords that trigger bot response in groups"
|
|
42
|
+
},
|
|
43
|
+
"accounts": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"description": "Multi-account configuration keyed by accountId",
|
|
46
|
+
"default": {},
|
|
47
|
+
"additionalProperties": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"additionalProperties": false,
|
|
50
|
+
"properties": {
|
|
51
|
+
"enabled": {
|
|
52
|
+
"type": "boolean",
|
|
53
|
+
"default": true
|
|
54
|
+
},
|
|
55
|
+
"gatewayUrl": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"default": ""
|
|
58
|
+
},
|
|
59
|
+
"robotId": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"default": ""
|
|
62
|
+
},
|
|
63
|
+
"robotSecret": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"default": ""
|
|
66
|
+
},
|
|
67
|
+
"requireMention": {
|
|
68
|
+
"type": "boolean",
|
|
69
|
+
"default": true
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"uiHints": {
|
|
77
|
+
"gatewayUrl": {
|
|
78
|
+
"label": "Gateway URL",
|
|
79
|
+
"placeholder": "ws://localhost:8884/robot/gateway"
|
|
80
|
+
},
|
|
81
|
+
"robotId": {
|
|
82
|
+
"label": "Robot ID"
|
|
83
|
+
},
|
|
84
|
+
"robotSecret": {
|
|
85
|
+
"label": "Robot Secret",
|
|
86
|
+
"sensitive": true
|
|
87
|
+
},
|
|
88
|
+
"requireMention": {
|
|
89
|
+
"label": "Require Mention in Group"
|
|
90
|
+
},
|
|
91
|
+
"helpKeywords": {
|
|
92
|
+
"label": "Help Keywords"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|