@xgjktech/xg_cwork_im 1.11.1 → 1.11.4
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 +25 -18
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/{index.ts → dist/index.js} +33 -37
- package/dist/index.js.map +1 -0
- package/dist/src/auth.d.ts +25 -0
- package/dist/src/auth.d.ts.map +1 -0
- package/{src/auth.ts → dist/src/auth.js} +55 -79
- package/dist/src/auth.js.map +1 -0
- package/dist/src/channel.d.ts +13 -0
- package/dist/src/channel.d.ts.map +1 -0
- package/{src/channel.ts → dist/src/channel.js} +224 -368
- package/dist/src/channel.js.map +1 -0
- package/dist/src/connection.d.ts +51 -0
- package/dist/src/connection.d.ts.map +1 -0
- package/{src/connection.ts → dist/src/connection.js} +45 -122
- package/dist/src/connection.js.map +1 -0
- package/dist/src/group-history-tool.d.ts +23 -0
- package/dist/src/group-history-tool.d.ts.map +1 -0
- package/{src/group-history-tool.ts → dist/src/group-history-tool.js} +168 -204
- package/dist/src/group-history-tool.js.map +1 -0
- package/dist/src/inbound-media-local.d.ts +40 -0
- package/dist/src/inbound-media-local.d.ts.map +1 -0
- package/{src/inbound-media-local.ts → dist/src/inbound-media-local.js} +52 -90
- package/dist/src/inbound-media-local.js.map +1 -0
- package/dist/src/recommended-system-prompt.d.ts +3 -0
- package/dist/src/recommended-system-prompt.d.ts.map +1 -0
- package/dist/src/recommended-system-prompt.js +3 -0
- package/dist/src/recommended-system-prompt.js.map +1 -0
- package/dist/src/resource-file.d.ts +65 -0
- package/dist/src/resource-file.d.ts.map +1 -0
- package/{src/resource-file.ts → dist/src/resource-file.js} +317 -339
- package/dist/src/resource-file.js.map +1 -0
- package/dist/src/send-group-message-tool.d.ts +16 -0
- package/dist/src/send-group-message-tool.d.ts.map +1 -0
- package/{src/send-group-message-tool.ts → dist/src/send-group-message-tool.js} +17 -34
- package/dist/src/send-group-message-tool.js.map +1 -0
- package/dist/src/send-service.d.ts +34 -0
- package/dist/src/send-service.d.ts.map +1 -0
- package/dist/src/send-service.js +197 -0
- package/dist/src/send-service.js.map +1 -0
- package/{src/tool-json-result.ts → dist/src/tool-json-result.d.ts} +14 -24
- package/dist/src/tool-json-result.d.ts.map +1 -0
- package/dist/src/tool-json-result.js +20 -0
- package/dist/src/tool-json-result.js.map +1 -0
- package/{src/types.ts → dist/src/types.d.ts} +32 -96
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +32 -0
- package/dist/src/types.js.map +1 -0
- package/openclaw.plugin.json +9 -0
- package/package.json +7 -6
- package/src/recommended-system-prompt.ts +0 -3
- package/src/send-service.ts +0 -228
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* XG-IM Channel Plugin — 类型定义
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
import type {
|
|
6
|
-
OpenClawConfig,
|
|
7
|
-
OpenClawPluginApi,
|
|
8
|
-
ChannelLogSink as SDKChannelLogSink,
|
|
9
|
-
ChannelAccountSnapshot as SDKChannelAccountSnapshot,
|
|
10
|
-
ChannelGatewayContext as SDKChannelGatewayContext,
|
|
11
|
-
ChannelPlugin as SDKChannelPlugin,
|
|
12
|
-
PluginRuntime,
|
|
13
|
-
} from "openclaw/plugin-sdk";
|
|
14
|
-
|
|
15
|
-
// ─── 插件模块 ───────────────────────────────────────────────────────────────
|
|
16
|
-
|
|
4
|
+
import type { OpenClawConfig, OpenClawPluginApi, ChannelLogSink as SDKChannelLogSink, ChannelAccountSnapshot as SDKChannelAccountSnapshot, ChannelGatewayContext as SDKChannelGatewayContext, ChannelPlugin as SDKChannelPlugin, PluginRuntime } from "openclaw/plugin-sdk";
|
|
17
5
|
export interface XgImPluginModule {
|
|
18
6
|
id: string;
|
|
19
7
|
name: string;
|
|
@@ -21,15 +9,13 @@ export interface XgImPluginModule {
|
|
|
21
9
|
configSchema?: unknown;
|
|
22
10
|
register?: (api: OpenClawPluginApi) => void | Promise<void>;
|
|
23
11
|
}
|
|
24
|
-
|
|
25
12
|
/** 与 openclaw.plugin.json 中 id: xg_cwork_im 对应 */
|
|
26
13
|
export type XgCworkImPluginModule = XgImPluginModule;
|
|
27
|
-
|
|
28
|
-
// ─── Channel 配置 ────────────────────────────────────────────────────────────
|
|
29
|
-
|
|
30
14
|
/** 单个机器人账户配置 */
|
|
31
15
|
export interface XgImAccountConfig {
|
|
32
|
-
/** 机器人 appKey
|
|
16
|
+
/** 机器人 Key(新字段,优先于 appKey) */
|
|
17
|
+
robotKey?: string;
|
|
18
|
+
/** 机器人 appKey,从 IM 后台注册获取(已改名为 robotKey,此字段保留兼容旧配置) */
|
|
33
19
|
appKey?: string;
|
|
34
20
|
/** 对应 OpenClaw 的 Agent ID,默认为 'main' */
|
|
35
21
|
agentId?: string;
|
|
@@ -60,12 +46,12 @@ export interface XgImAccountConfig {
|
|
|
60
46
|
*/
|
|
61
47
|
systemPrompt?: string;
|
|
62
48
|
}
|
|
63
|
-
|
|
64
49
|
export interface XgImConfig extends OpenClawConfig {
|
|
65
50
|
/** 多账户列表 */
|
|
66
51
|
accounts?: Record<string, XgImAccountConfig>;
|
|
67
|
-
|
|
68
|
-
|
|
52
|
+
/** 机器人 Key(新字段,优先于 appKey,单账户模式) */
|
|
53
|
+
robotKey?: string;
|
|
54
|
+
/** 机器人 appKey(单账户模式,已改名为 robotKey,此字段保留兼容旧配置) */
|
|
69
55
|
appKey?: string;
|
|
70
56
|
/** 对应 OpenClaw 的 Agent ID(单账户模式) */
|
|
71
57
|
agentId?: string;
|
|
@@ -98,7 +84,6 @@ export interface XgImConfig extends OpenClawConfig {
|
|
|
98
84
|
* - 仅用于保护「思考中」占位消息,避免长时间不被更新。
|
|
99
85
|
*/
|
|
100
86
|
firstReplyTimeoutMs?: number;
|
|
101
|
-
|
|
102
87
|
/**
|
|
103
88
|
* 附件上传地址固定为 `{baseUrl}/file/upDownload/uploadWholeFile`,请求头 `access-token` 与发 IM 相同。
|
|
104
89
|
* multipart 字段名默认 `file`,可通过 fileUploadFormField 覆盖。
|
|
@@ -106,7 +91,6 @@ export interface XgImConfig extends OpenClawConfig {
|
|
|
106
91
|
fileUploadFormField?: string;
|
|
107
92
|
/** 单个附件下载/上传允许的最大字节数,默认 50MB */
|
|
108
93
|
maxAttachmentBytes?: number;
|
|
109
|
-
|
|
110
94
|
/**
|
|
111
95
|
* 若配置为非空相对路径(相对于当前 Agent workspace 根目录):入站附件会先下载到
|
|
112
96
|
* `{workspace}/{本字段}/{userId}/{YYYY-MM-DD}/{name}_{HHmmssmmm}.ext`,再向 OpenClaw 传入 **workspace 相对路径**(默认 `./子目录/...`,便于沙箱挂载 `/workspace`)或 `file://`(见 `inboundMediaOpenClawPath`)。
|
|
@@ -126,9 +110,6 @@ export interface XgImConfig extends OpenClawConfig {
|
|
|
126
110
|
*/
|
|
127
111
|
systemPrompt?: string;
|
|
128
112
|
}
|
|
129
|
-
|
|
130
|
-
// ─── IM 接口 Request / Response ─────────────────────────────────────────────
|
|
131
|
-
|
|
132
113
|
/** GET /user/login/appkey 的响应 */
|
|
133
114
|
export interface GetTokenResponse {
|
|
134
115
|
data?: {
|
|
@@ -145,23 +126,18 @@ export interface GetTokenResponse {
|
|
|
145
126
|
resultCode?: number;
|
|
146
127
|
resultMsg?: string | null;
|
|
147
128
|
}
|
|
148
|
-
|
|
149
129
|
/** 机器人身份信息(认证成功后缓存) */
|
|
150
130
|
export interface BotIdentity {
|
|
151
131
|
token: string;
|
|
152
132
|
userId: string;
|
|
153
133
|
name: string;
|
|
154
134
|
}
|
|
155
|
-
|
|
156
|
-
// ─── WebSocket 消息 ──────────────────────────────────────────────────────────
|
|
157
|
-
|
|
158
135
|
/** WebSocket 消息通知(cmd = robotMention) */
|
|
159
136
|
export interface WsMessage {
|
|
160
137
|
cmd: string;
|
|
161
138
|
params: WsMessageParams;
|
|
162
139
|
ts: number;
|
|
163
140
|
}
|
|
164
|
-
|
|
165
141
|
/**
|
|
166
142
|
* 与 IM 服务 `MsgFileVO` 对齐的附件项(WebSocket `msgContent.files[]`)。
|
|
167
143
|
*/
|
|
@@ -182,38 +158,10 @@ export interface MsgFileVO {
|
|
|
182
158
|
*/
|
|
183
159
|
content?: string;
|
|
184
160
|
}
|
|
185
|
-
|
|
186
161
|
/** @deprecated 使用 {@link MsgFileVO} */
|
|
187
162
|
export type WsInboundFileItem = MsgFileVO;
|
|
188
|
-
|
|
189
163
|
/** 常见 IM format → MIME,供 OpenClaw 媒体理解;未知格式返回 undefined */
|
|
190
|
-
export function imFormatToMimeType(format: string | undefined): string | undefined
|
|
191
|
-
const f = format?.trim().toLowerCase();
|
|
192
|
-
if (!f) return undefined;
|
|
193
|
-
const map: Record<string, string> = {
|
|
194
|
-
pdf: "application/pdf",
|
|
195
|
-
png: "image/png",
|
|
196
|
-
jpg: "image/jpeg",
|
|
197
|
-
jpeg: "image/jpeg",
|
|
198
|
-
gif: "image/gif",
|
|
199
|
-
webp: "image/webp",
|
|
200
|
-
doc: "application/msword",
|
|
201
|
-
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
202
|
-
ppt: "application/vnd.ms-powerpoint",
|
|
203
|
-
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
204
|
-
xls: "application/vnd.ms-excel",
|
|
205
|
-
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
206
|
-
txt: "text/plain",
|
|
207
|
-
md: "text/markdown",
|
|
208
|
-
csv: "text/csv",
|
|
209
|
-
zip: "application/zip",
|
|
210
|
-
mp3: "audio/mpeg",
|
|
211
|
-
wav: "audio/wav",
|
|
212
|
-
mp4: "video/mp4",
|
|
213
|
-
};
|
|
214
|
-
return map[f];
|
|
215
|
-
}
|
|
216
|
-
|
|
164
|
+
export declare function imFormatToMimeType(format: string | undefined): string | undefined;
|
|
217
165
|
/**
|
|
218
166
|
* 入站消息内容体(与 IM WebSocket `params.msgContent` 对齐)。
|
|
219
167
|
*
|
|
@@ -230,7 +178,6 @@ export interface WsMessageContent {
|
|
|
230
178
|
files?: MsgFileVO[];
|
|
231
179
|
ext?: Record<string, any>;
|
|
232
180
|
}
|
|
233
|
-
|
|
234
181
|
/** robotMention 消息的 params */
|
|
235
182
|
export interface WsMessageParams {
|
|
236
183
|
msgId: string;
|
|
@@ -254,9 +201,6 @@ export interface WsMessageParams {
|
|
|
254
201
|
/** 被 @ 的人员 ID 列表 */
|
|
255
202
|
mentions?: string[] | null;
|
|
256
203
|
}
|
|
257
|
-
|
|
258
|
-
// ─── IM 发送消息 ─────────────────────────────────────────────────────────────
|
|
259
|
-
|
|
260
204
|
/** POST /im/message/send 请求体 */
|
|
261
205
|
export interface SendMessageReply {
|
|
262
206
|
/** 被回复消息ID */
|
|
@@ -268,7 +212,6 @@ export interface SendMessageReply {
|
|
|
268
212
|
/** 被回复消息摘要 */
|
|
269
213
|
previewText: string;
|
|
270
214
|
}
|
|
271
|
-
|
|
272
215
|
/** IM 发送 FILE 类型消息时的附件项(与发消息接口约定一致) */
|
|
273
216
|
export interface SendMessageFileAttachment {
|
|
274
217
|
fileId: string;
|
|
@@ -281,42 +224,34 @@ export interface SendMessageFileAttachment {
|
|
|
281
224
|
/** 固定为 resource */
|
|
282
225
|
source: "resource";
|
|
283
226
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
msgId?: string;
|
|
305
|
-
reply?: SendMessageReply;
|
|
306
|
-
};
|
|
307
|
-
|
|
227
|
+
export type SendMessageBody = {
|
|
228
|
+
type: "TEXT" | "RICH_TEXT" | "VOICE";
|
|
229
|
+
groupId?: string;
|
|
230
|
+
toUserId?: string;
|
|
231
|
+
text: string;
|
|
232
|
+
atUserIds?: string[];
|
|
233
|
+
/** 流式占位消息 ID,用于将回复更新到对应的占位消息上 */
|
|
234
|
+
msgId?: string;
|
|
235
|
+
reply?: SendMessageReply;
|
|
236
|
+
} | {
|
|
237
|
+
type: "FILE";
|
|
238
|
+
groupId?: string;
|
|
239
|
+
toUserId?: string;
|
|
240
|
+
text: string;
|
|
241
|
+
attachments: SendMessageFileAttachment[];
|
|
242
|
+
atUserIds?: string[];
|
|
243
|
+
/** 流式占位消息 ID,用于将回复更新到对应的占位消息上 */
|
|
244
|
+
msgId?: string;
|
|
245
|
+
reply?: SendMessageReply;
|
|
246
|
+
};
|
|
308
247
|
/** GET /im/message/getLatestMsgListForAI 响应 */
|
|
309
248
|
export interface GetLatestMsgListResponse {
|
|
310
249
|
data?: WsMessageParams[];
|
|
311
250
|
resultCode?: number;
|
|
312
251
|
message?: string;
|
|
313
252
|
}
|
|
314
|
-
|
|
315
|
-
// ─── OpenClaw 插件 SDK 类型别名 ───────────────────────────────────────────────
|
|
316
|
-
|
|
317
253
|
export type ChannelLogSink = SDKChannelLogSink;
|
|
318
254
|
export type ChannelAccountSnapshot = SDKChannelAccountSnapshot;
|
|
319
|
-
|
|
320
255
|
export interface ResolvedAccount {
|
|
321
256
|
accountId: string;
|
|
322
257
|
config: XgImConfig;
|
|
@@ -324,9 +259,10 @@ export interface ResolvedAccount {
|
|
|
324
259
|
configured: boolean;
|
|
325
260
|
name?: string | null;
|
|
326
261
|
}
|
|
327
|
-
|
|
328
262
|
export type GatewayStartContext = SDKChannelGatewayContext<ResolvedAccount>;
|
|
329
|
-
export type XgImChannelPlugin = SDKChannelPlugin<ResolvedAccount & {
|
|
330
|
-
|
|
263
|
+
export type XgImChannelPlugin = SDKChannelPlugin<ResolvedAccount & {
|
|
264
|
+
configured: boolean;
|
|
265
|
+
}>;
|
|
331
266
|
/** PluginRuntime 的类型(内部 API 丰富,用 any 表示) */
|
|
332
267
|
export type { PluginRuntime };
|
|
268
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XG-IM Channel Plugin — 类型定义
|
|
3
|
+
*/
|
|
4
|
+
/** 常见 IM format → MIME,供 OpenClaw 媒体理解;未知格式返回 undefined */
|
|
5
|
+
export function imFormatToMimeType(format) {
|
|
6
|
+
const f = format?.trim().toLowerCase();
|
|
7
|
+
if (!f)
|
|
8
|
+
return undefined;
|
|
9
|
+
const map = {
|
|
10
|
+
pdf: "application/pdf",
|
|
11
|
+
png: "image/png",
|
|
12
|
+
jpg: "image/jpeg",
|
|
13
|
+
jpeg: "image/jpeg",
|
|
14
|
+
gif: "image/gif",
|
|
15
|
+
webp: "image/webp",
|
|
16
|
+
doc: "application/msword",
|
|
17
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
18
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
19
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
20
|
+
xls: "application/vnd.ms-excel",
|
|
21
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
22
|
+
txt: "text/plain",
|
|
23
|
+
md: "text/markdown",
|
|
24
|
+
csv: "text/csv",
|
|
25
|
+
zip: "application/zip",
|
|
26
|
+
mp3: "audio/mpeg",
|
|
27
|
+
wav: "audio/wav",
|
|
28
|
+
mp4: "video/mp4",
|
|
29
|
+
};
|
|
30
|
+
return map[f];
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AA8LH,2DAA2D;AAC3D,MAAM,UAAU,kBAAkB,CAAC,MAA0B;IACzD,MAAM,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACvC,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzB,MAAM,GAAG,GAA2B;QAChC,GAAG,EAAE,iBAAiB;QACtB,GAAG,EAAE,WAAW;QAChB,GAAG,EAAE,YAAY;QACjB,IAAI,EAAE,YAAY;QAClB,GAAG,EAAE,WAAW;QAChB,IAAI,EAAE,YAAY;QAClB,GAAG,EAAE,oBAAoB;QACzB,IAAI,EAAE,yEAAyE;QAC/E,GAAG,EAAE,+BAA+B;QACpC,IAAI,EAAE,2EAA2E;QACjF,GAAG,EAAE,0BAA0B;QAC/B,IAAI,EAAE,mEAAmE;QACzE,GAAG,EAAE,YAAY;QACjB,EAAE,EAAE,eAAe;QACnB,GAAG,EAAE,UAAU;QACf,GAAG,EAAE,iBAAiB;QACtB,GAAG,EAAE,YAAY;QACjB,GAAG,EAAE,WAAW;QAChB,GAAG,EAAE,WAAW;KACnB,CAAC;IACF,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
|
package/openclaw.plugin.json
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
"channels": [
|
|
4
4
|
"xg_cwork_im"
|
|
5
5
|
],
|
|
6
|
+
"channelConfigs": {
|
|
7
|
+
"xg_cwork_im": {
|
|
8
|
+
"schema": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"additionalProperties": true,
|
|
11
|
+
"properties": {}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
6
15
|
"configSchema": {
|
|
7
16
|
"type": "object",
|
|
8
17
|
"additionalProperties": true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xgjktech/xg_cwork_im",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.4",
|
|
4
4
|
"description": "XG CWork IM channel plugin for OpenClaw",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bot",
|
|
@@ -11,18 +11,19 @@
|
|
|
11
11
|
],
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"type": "module",
|
|
14
|
-
"main": "index.
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"types": "dist/index.d.ts",
|
|
15
16
|
"files": [
|
|
16
17
|
".npmrc",
|
|
17
|
-
"
|
|
18
|
-
"src/*.ts",
|
|
18
|
+
"dist/**/*",
|
|
19
19
|
"openclaw.plugin.json"
|
|
20
20
|
],
|
|
21
21
|
"scripts": {
|
|
22
|
+
"build": "tsc -p tsconfig.json",
|
|
22
23
|
"type-check": "tsc -p tsconfig.json --noEmit",
|
|
23
24
|
"lint": "tsc -p tsconfig.json --noEmit",
|
|
24
25
|
"install:prod": "npm install --omit=dev",
|
|
25
|
-
"prepublishOnly": "npm run
|
|
26
|
+
"prepublishOnly": "npm run build"
|
|
26
27
|
},
|
|
27
28
|
"dependencies": {
|
|
28
29
|
"@sinclair/typebox": "^0.32.0",
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
},
|
|
41
42
|
"openclaw": {
|
|
42
43
|
"extensions": [
|
|
43
|
-
"./index.
|
|
44
|
+
"./dist/index.js"
|
|
44
45
|
],
|
|
45
46
|
"channels": [
|
|
46
47
|
"xg_cwork_im"
|
package/src/send-service.ts
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* XG-IM 消息发送模块
|
|
3
|
-
*
|
|
4
|
-
* 调用 IM 接口将 AI 回复发送到指定群聊,并 @ 原始发送者。
|
|
5
|
-
* 支持 RICH_TEXT 与带资源 fileId 的 FILE 类型(attachments)。
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import axios from "axios";
|
|
9
|
-
import type { Log } from "./auth.js";
|
|
10
|
-
import {
|
|
11
|
-
downloadMediaBuffer,
|
|
12
|
-
formatFromFilename,
|
|
13
|
-
resolveMaxAttachmentBytes,
|
|
14
|
-
resolveResourceUploadUrl,
|
|
15
|
-
uploadWholeResourceFile,
|
|
16
|
-
} from "./resource-file.js";
|
|
17
|
-
import type { SendMessageBody, SendMessageFileAttachment, SendMessageReply, XgImConfig } from "./types.js";
|
|
18
|
-
|
|
19
|
-
function formatDeliverError(err: unknown): string {
|
|
20
|
-
if (axios.isAxiosError(err)) {
|
|
21
|
-
const parts = [err.message];
|
|
22
|
-
if (err.code) parts.push(`axiosCode=${err.code}`);
|
|
23
|
-
if (err.response?.status != null) parts.push(`httpStatus=${err.response.status}`);
|
|
24
|
-
return parts.join(" ");
|
|
25
|
-
}
|
|
26
|
-
if (err instanceof Error) return err.message;
|
|
27
|
-
return String(err);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async function postImMessage(
|
|
31
|
-
config: XgImConfig,
|
|
32
|
-
token: string,
|
|
33
|
-
groupId: string,
|
|
34
|
-
body: SendMessageBody,
|
|
35
|
-
atUserIds: string[] = [],
|
|
36
|
-
log?: Log,
|
|
37
|
-
): Promise<void> {
|
|
38
|
-
const url = `${config.baseUrl}/im/message/send`;
|
|
39
|
-
const full: SendMessageBody = {
|
|
40
|
-
...body,
|
|
41
|
-
groupId,
|
|
42
|
-
...(atUserIds.length > 0 ? { atUserIds } : {}),
|
|
43
|
-
} as SendMessageBody;
|
|
44
|
-
|
|
45
|
-
log?.info(`[cwork_im:send] POST ${url} groupId=${groupId} type=${full.type} atUsers=${JSON.stringify(atUserIds)}`);
|
|
46
|
-
if (config.debug) {
|
|
47
|
-
log?.debug?.(`[cwork_im:send] Request body: ${JSON.stringify(full)}`);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
const res = await axios.post(url, full, {
|
|
52
|
-
headers: {
|
|
53
|
-
"Content-Type": "application/json",
|
|
54
|
-
"access-token": token,
|
|
55
|
-
},
|
|
56
|
-
timeout: 10_000,
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
log?.info(`[cwork_im:send] Response status=${res.status}`);
|
|
60
|
-
if (config.debug) {
|
|
61
|
-
log?.debug?.(`[cwork_im:send] Response body: ${JSON.stringify(res.data)}`);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Detect business-level errors that arrive with HTTP 200.
|
|
65
|
-
// IM API unified response: { data, resultCode: 1, resultMsg: "" } — resultCode=1 means success.
|
|
66
|
-
const d = res.data;
|
|
67
|
-
if (d && typeof d === "object") {
|
|
68
|
-
const resultCode = (d as Record<string, unknown>).resultCode;
|
|
69
|
-
const resultMsg = (d as Record<string, unknown>).resultMsg;
|
|
70
|
-
if (resultCode !== undefined && resultCode !== 1) {
|
|
71
|
-
throw new Error(
|
|
72
|
-
`IM API error resultCode=${resultCode}${resultMsg ? ` resultMsg=${resultMsg}` : ""}`,
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
} catch (err: unknown) {
|
|
77
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
78
|
-
log?.error(`[cwork_im:send] Failed to send message to groupId=${groupId}: ${msg}`);
|
|
79
|
-
throw err;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** OpenClaw dispatch deliver 单块载荷:文本 + 可选媒体 URL(与 plugin-sdk 约定对齐)。 */
|
|
84
|
-
export type ReplyDeliverPayload = {
|
|
85
|
-
markdown?: string;
|
|
86
|
-
text?: string;
|
|
87
|
-
isThinking?: boolean;
|
|
88
|
-
mediaUrl?: string;
|
|
89
|
-
mediaUrls?: string[];
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* 将 deliver 块发到 IM:若有媒体则先 POST baseUrl/file/upDownload/uploadWholeFile 再发 FILE;否则发 RICH_TEXT。
|
|
94
|
-
*/
|
|
95
|
-
export async function sendReplyDeliverBlock(
|
|
96
|
-
config: XgImConfig,
|
|
97
|
-
token: string,
|
|
98
|
-
groupId: string,
|
|
99
|
-
payload: ReplyDeliverPayload,
|
|
100
|
-
atUserIds: string[] = [],
|
|
101
|
-
log?: Log,
|
|
102
|
-
msgId?: string,
|
|
103
|
-
reply?: SendMessageReply,
|
|
104
|
-
): Promise<void> {
|
|
105
|
-
const textToSend = (payload.markdown || payload.text || "").trim();
|
|
106
|
-
const mediaList = [
|
|
107
|
-
...(payload.mediaUrl ? [payload.mediaUrl] : []),
|
|
108
|
-
...((payload.mediaUrls ?? []).filter((u) => typeof u === "string" && u.trim())),
|
|
109
|
-
];
|
|
110
|
-
const uniqueUrls = [...new Set(mediaList)];
|
|
111
|
-
const maxBytes = resolveMaxAttachmentBytes(config);
|
|
112
|
-
const formField = config.fileUploadFormField?.trim() || "file";
|
|
113
|
-
|
|
114
|
-
const wantFile = uniqueUrls.length > 0 && !payload.isThinking;
|
|
115
|
-
|
|
116
|
-
if (wantFile) {
|
|
117
|
-
const fileUploadUrl = resolveResourceUploadUrl(config.baseUrl);
|
|
118
|
-
try {
|
|
119
|
-
const attachments: SendMessageFileAttachment[] = [];
|
|
120
|
-
for (const u of uniqueUrls) {
|
|
121
|
-
const { buffer, filename } = await downloadMediaBuffer(u, maxBytes, log);
|
|
122
|
-
const { fileId } = await uploadWholeResourceFile({
|
|
123
|
-
fileUploadUrl,
|
|
124
|
-
token,
|
|
125
|
-
buffer,
|
|
126
|
-
filename,
|
|
127
|
-
formField,
|
|
128
|
-
log,
|
|
129
|
-
});
|
|
130
|
-
attachments.push({
|
|
131
|
-
fileId,
|
|
132
|
-
fileType: "FILE",
|
|
133
|
-
format: formatFromFilename(filename),
|
|
134
|
-
name: filename,
|
|
135
|
-
size: buffer.length,
|
|
136
|
-
source: "resource",
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
const caption = textToSend.length > 0 ? textToSend : " ";
|
|
140
|
-
await postImMessage(
|
|
141
|
-
config,
|
|
142
|
-
token,
|
|
143
|
-
groupId,
|
|
144
|
-
{
|
|
145
|
-
type: "FILE",
|
|
146
|
-
text: caption,
|
|
147
|
-
attachments,
|
|
148
|
-
...(msgId ? { msgId } : {}),
|
|
149
|
-
...(reply ? { reply } : {}),
|
|
150
|
-
},
|
|
151
|
-
atUserIds,
|
|
152
|
-
log,
|
|
153
|
-
);
|
|
154
|
-
return;
|
|
155
|
-
} catch (err: unknown) {
|
|
156
|
-
log?.error(`[cwork_im:send] FILE deliver failed, fallback to text if any: ${formatDeliverError(err)}`);
|
|
157
|
-
const errNote = `(文件发送失败:${formatDeliverError(err)})`;
|
|
158
|
-
const fallbackText = textToSend.length > 0 ? `${textToSend}\n\n${errNote}` : errNote;
|
|
159
|
-
await postImMessage(
|
|
160
|
-
config,
|
|
161
|
-
token,
|
|
162
|
-
groupId,
|
|
163
|
-
{
|
|
164
|
-
type: "RICH_TEXT",
|
|
165
|
-
text: fallbackText,
|
|
166
|
-
...(msgId ? { msgId } : {}),
|
|
167
|
-
...(reply ? { reply } : {}),
|
|
168
|
-
},
|
|
169
|
-
atUserIds,
|
|
170
|
-
log,
|
|
171
|
-
);
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (textToSend.length > 0) {
|
|
177
|
-
await postImMessage(
|
|
178
|
-
config,
|
|
179
|
-
token,
|
|
180
|
-
groupId,
|
|
181
|
-
{
|
|
182
|
-
type: "RICH_TEXT",
|
|
183
|
-
text: textToSend,
|
|
184
|
-
...(msgId ? { msgId } : {}),
|
|
185
|
-
...(reply ? { reply } : {}),
|
|
186
|
-
},
|
|
187
|
-
atUserIds,
|
|
188
|
-
log,
|
|
189
|
-
);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* 发送文本消息到指定 IM 群聊。
|
|
195
|
-
*
|
|
196
|
-
* @param config 插件配置
|
|
197
|
-
* @param token 鉴权 token
|
|
198
|
-
* @param groupId 目标群聊 ID(gid / groupId)
|
|
199
|
-
* @param content 消息内容文本
|
|
200
|
-
* @param atUserIds 需要 @ 的用户 ID 列表(可为空)
|
|
201
|
-
* @param log 日志接口
|
|
202
|
-
* @param msgId 可选的业务消息 ID(用于覆盖/更新已有消息)
|
|
203
|
-
* @param reply 可选的被回复消息信息(用于在 IM 中建立“回复某条消息”的关联)
|
|
204
|
-
*/
|
|
205
|
-
export async function sendTextMessage(
|
|
206
|
-
config: XgImConfig,
|
|
207
|
-
token: string,
|
|
208
|
-
groupId: string,
|
|
209
|
-
content: string,
|
|
210
|
-
atUserIds: string[] = [],
|
|
211
|
-
log?: Log,
|
|
212
|
-
msgId?: string,
|
|
213
|
-
reply?: SendMessageReply,
|
|
214
|
-
): Promise<void> {
|
|
215
|
-
await postImMessage(
|
|
216
|
-
config,
|
|
217
|
-
token,
|
|
218
|
-
groupId,
|
|
219
|
-
{
|
|
220
|
-
type: "RICH_TEXT",
|
|
221
|
-
text: content,
|
|
222
|
-
...(msgId ? { msgId } : {}),
|
|
223
|
-
...(reply ? { reply } : {}),
|
|
224
|
-
},
|
|
225
|
-
atUserIds,
|
|
226
|
-
log,
|
|
227
|
-
);
|
|
228
|
-
}
|