@yaoqi10012/wechat-kf 0.3.1
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/LICENSE +21 -0
- package/dist/accounts.d.ts +38 -0
- package/dist/accounts.js +247 -0
- package/dist/accounts.js.map +1 -0
- package/dist/api.d.ts +58 -0
- package/dist/api.js +200 -0
- package/dist/api.js.map +1 -0
- package/dist/bot.d.ts +37 -0
- package/dist/bot.js +672 -0
- package/dist/bot.js.map +1 -0
- package/dist/channel.d.ts +14 -0
- package/dist/channel.js +320 -0
- package/dist/channel.js.map +1 -0
- package/dist/config-schema.d.ts +56 -0
- package/dist/config-schema.js +39 -0
- package/dist/config-schema.js.map +1 -0
- package/dist/constants.d.ts +41 -0
- package/dist/constants.js +51 -0
- package/dist/constants.js.map +1 -0
- package/dist/crypto.d.ts +18 -0
- package/dist/crypto.js +81 -0
- package/dist/crypto.js.map +1 -0
- package/dist/fs-utils.d.ts +7 -0
- package/dist/fs-utils.js +13 -0
- package/dist/fs-utils.js.map +1 -0
- package/dist/monitor.d.ts +31 -0
- package/dist/monitor.js +80 -0
- package/dist/monitor.js.map +1 -0
- package/dist/outbound.d.ts +32 -0
- package/dist/outbound.js +411 -0
- package/dist/outbound.js.map +1 -0
- package/dist/reply-dispatcher.d.ts +36 -0
- package/dist/reply-dispatcher.js +216 -0
- package/dist/reply-dispatcher.js.map +1 -0
- package/dist/runtime.d.ts +12 -0
- package/dist/runtime.js +23 -0
- package/dist/runtime.js.map +1 -0
- package/dist/send-utils.d.ts +52 -0
- package/dist/send-utils.js +217 -0
- package/dist/send-utils.js.map +1 -0
- package/dist/token.d.ts +8 -0
- package/dist/token.js +61 -0
- package/dist/token.js.map +1 -0
- package/dist/types.d.ts +236 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/unicode-format.d.ts +26 -0
- package/dist/unicode-format.js +157 -0
- package/dist/unicode-format.js.map +1 -0
- package/dist/webhook.d.ts +22 -0
- package/dist/webhook.js +148 -0
- package/dist/webhook.js.map +1 -0
- package/dist/wechat-kf-directives.d.ts +157 -0
- package/dist/wechat-kf-directives.js +576 -0
- package/dist/wechat-kf-directives.js.map +1 -0
- package/openclaw.plugin.json +31 -0
- package/package.json +92 -0
package/dist/outbound.js
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound message adapter for WeChat KF (framework-driven direct delivery)
|
|
3
|
+
*
|
|
4
|
+
* Responsibility:
|
|
5
|
+
* This module implements the OpenClaw `ChannelPlugin.outbound` interface and
|
|
6
|
+
* is called by the framework when the agent produces a final reply.
|
|
7
|
+
*
|
|
8
|
+
* Text is first converted from markdown to Unicode formatting (formatText),
|
|
9
|
+
* then chunked by UTF-8 byte length via `chunkTextByUtf8Bytes` (WeChat API
|
|
10
|
+
* enforces a 2048-byte limit on text.content). Framework auto-chunking is
|
|
11
|
+
* disabled (`chunker: null`) because it would chunk *before* formatting,
|
|
12
|
+
* causing post-format expansion to exceed the limit.
|
|
13
|
+
*
|
|
14
|
+
* For media, the framework's `loadWebMedia` handles all URL formats
|
|
15
|
+
* (HTTP, file://, local paths, MEDIA: prefix, ~), then the buffer is
|
|
16
|
+
* uploaded to WeChat and sent using `uploadAndSendMedia` from `send-utils.ts`.
|
|
17
|
+
*
|
|
18
|
+
* WeChat KF session limits:
|
|
19
|
+
* The API enforces a 48-hour / 5-message limit per session window.
|
|
20
|
+
* Once a customer sends a message, the agent may reply with up to 5 messages
|
|
21
|
+
* within 48 hours. After that, sending returns errcode 95026.
|
|
22
|
+
* This module detects that error and logs a clear warning rather than
|
|
23
|
+
* propagating a generic failure.
|
|
24
|
+
*
|
|
25
|
+
* Counterpart:
|
|
26
|
+
* `reply-dispatcher.ts` handles the *other* outbound path: typing-aware
|
|
27
|
+
* streaming replies dispatched internally by `bot.ts`.
|
|
28
|
+
*
|
|
29
|
+
* accountId = openKfId (dynamically discovered)
|
|
30
|
+
*/
|
|
31
|
+
import { resolveAccount } from "./accounts.js";
|
|
32
|
+
import { sendBusinessCardMessage, sendCaLinkMessage, sendLinkMessage, sendLocationMessage, sendMiniprogramMessage, sendMsgMenuMessage, sendRawMessage, sendTextMessage, } from "./api.js";
|
|
33
|
+
import { CHANNEL_ID, logTag, WECHAT_MSG_LIMIT_ERRCODE, WECHAT_TEXT_CHUNK_BYTE_SAFETY_MARGIN, WECHAT_TEXT_CHUNK_LIMIT, } from "./constants.js";
|
|
34
|
+
import { getSharedContext } from "./monitor.js";
|
|
35
|
+
import { getRuntime } from "./runtime.js";
|
|
36
|
+
import { chunkTextByUtf8Bytes, formatText, mediaKindToWechatType, resolveThumbMediaId, uploadAndSendMedia, } from "./send-utils.js";
|
|
37
|
+
import { buildMsgMenuPayload, parseWechatDirective } from "./wechat-kf-directives.js";
|
|
38
|
+
const BYTE_LIMIT = WECHAT_TEXT_CHUNK_LIMIT - WECHAT_TEXT_CHUNK_BYTE_SAFETY_MARGIN;
|
|
39
|
+
/**
|
|
40
|
+
* Check whether an error indicates the WeChat 48h/5-message session limit.
|
|
41
|
+
* When detected, logs a warning and returns true so the caller can handle
|
|
42
|
+
* gracefully instead of throwing a generic error.
|
|
43
|
+
*/
|
|
44
|
+
function isSessionLimitError(err) {
|
|
45
|
+
if (err instanceof Error) {
|
|
46
|
+
return err.message.includes(String(WECHAT_MSG_LIMIT_ERRCODE));
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
function warnSessionLimit(err, externalUserId, openKfId) {
|
|
51
|
+
if (isSessionLimitError(err)) {
|
|
52
|
+
getSharedContext()?.botCtx.log?.warn(`${logTag()} session limit exceeded (48h/5-msg) for user=${externalUserId} kf=${openKfId}. ` +
|
|
53
|
+
`The customer must send a new message before more replies can be delivered.`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export const wechatKfOutbound = {
|
|
57
|
+
deliveryMode: "direct",
|
|
58
|
+
chunker: null, // disabled — sendText formats first, then chunks internally
|
|
59
|
+
textChunkLimit: WECHAT_TEXT_CHUNK_LIMIT,
|
|
60
|
+
sendText: async ({ cfg, to, text, accountId }) => {
|
|
61
|
+
const account = resolveAccount(cfg, accountId ?? "");
|
|
62
|
+
const effectiveAccountId = accountId ?? "";
|
|
63
|
+
const openKfId = account.openKfId ?? effectiveAccountId;
|
|
64
|
+
if (!account.corpId || !account.appSecret || !openKfId) {
|
|
65
|
+
throw new Error(`${logTag()} missing corpId/appSecret/openKfId`);
|
|
66
|
+
}
|
|
67
|
+
const externalUserId = String(to).replace(/^user:/, "");
|
|
68
|
+
// ── Intercept [[wechat_*:...]] directives BEFORE formatText ──
|
|
69
|
+
// Parse on raw text so fields stay clean (formatText would
|
|
70
|
+
// convert markdown inside the directive to unicode characters).
|
|
71
|
+
const directive = parseWechatDirective(text);
|
|
72
|
+
if (directive.link) {
|
|
73
|
+
try {
|
|
74
|
+
let thumbMediaId;
|
|
75
|
+
if (directive.link.thumbUrl) {
|
|
76
|
+
thumbMediaId = await resolveThumbMediaId(directive.link.thumbUrl, account.corpId, account.appSecret);
|
|
77
|
+
}
|
|
78
|
+
// WeChat requires thumb_media_id for link cards — fall back to plain text if missing
|
|
79
|
+
if (!thumbMediaId) {
|
|
80
|
+
const fallbackText = directive.text
|
|
81
|
+
? `${formatText(directive.text)}\n${directive.link.title}: ${directive.link.url}`
|
|
82
|
+
: `${directive.link.title}: ${directive.link.url}`;
|
|
83
|
+
const fallbackChunks = chunkTextByUtf8Bytes(fallbackText, BYTE_LIMIT);
|
|
84
|
+
let lastResult;
|
|
85
|
+
for (const chunk of fallbackChunks) {
|
|
86
|
+
lastResult = await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, chunk);
|
|
87
|
+
}
|
|
88
|
+
return { channel: CHANNEL_ID, messageId: lastResult?.msgid ?? "", chatId: to };
|
|
89
|
+
}
|
|
90
|
+
const linkResult = await sendLinkMessage(account.corpId, account.appSecret, externalUserId, openKfId, {
|
|
91
|
+
title: directive.link.title,
|
|
92
|
+
desc: directive.link.desc,
|
|
93
|
+
url: directive.link.url,
|
|
94
|
+
thumb_media_id: thumbMediaId,
|
|
95
|
+
});
|
|
96
|
+
// Send remaining text if non-empty (apply formatText to surrounding text only)
|
|
97
|
+
if (directive.text) {
|
|
98
|
+
const remainFormatted = formatText(directive.text);
|
|
99
|
+
const remainChunks = chunkTextByUtf8Bytes(remainFormatted, BYTE_LIMIT);
|
|
100
|
+
for (const chunk of remainChunks) {
|
|
101
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, chunk);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return { channel: CHANNEL_ID, messageId: linkResult.msgid, chatId: to };
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (directive.location) {
|
|
112
|
+
try {
|
|
113
|
+
const locResult = await sendLocationMessage(account.corpId, account.appSecret, externalUserId, openKfId, directive.location);
|
|
114
|
+
if (directive.text) {
|
|
115
|
+
const remainChunks = chunkTextByUtf8Bytes(formatText(directive.text), BYTE_LIMIT);
|
|
116
|
+
for (const chunk of remainChunks) {
|
|
117
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, chunk);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { channel: CHANNEL_ID, messageId: locResult.msgid, chatId: to };
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
124
|
+
throw err;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (directive.miniprogram) {
|
|
128
|
+
try {
|
|
129
|
+
let thumbMediaId;
|
|
130
|
+
if (directive.miniprogram.thumbUrl) {
|
|
131
|
+
thumbMediaId = await resolveThumbMediaId(directive.miniprogram.thumbUrl, account.corpId, account.appSecret);
|
|
132
|
+
}
|
|
133
|
+
if (!thumbMediaId) {
|
|
134
|
+
// Miniprogram card requires thumb — fall back to text
|
|
135
|
+
const fallback = directive.text
|
|
136
|
+
? `${formatText(directive.text)}\n[小程序] ${directive.miniprogram.title}`
|
|
137
|
+
: `[小程序] ${directive.miniprogram.title}`;
|
|
138
|
+
const chunks = chunkTextByUtf8Bytes(fallback, BYTE_LIMIT);
|
|
139
|
+
let lastResult;
|
|
140
|
+
for (const chunk of chunks) {
|
|
141
|
+
lastResult = await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, chunk);
|
|
142
|
+
}
|
|
143
|
+
return { channel: CHANNEL_ID, messageId: lastResult?.msgid ?? "", chatId: to };
|
|
144
|
+
}
|
|
145
|
+
const mpResult = await sendMiniprogramMessage(account.corpId, account.appSecret, externalUserId, openKfId, {
|
|
146
|
+
appid: directive.miniprogram.appid,
|
|
147
|
+
title: directive.miniprogram.title,
|
|
148
|
+
pagepath: directive.miniprogram.pagepath,
|
|
149
|
+
thumb_media_id: thumbMediaId,
|
|
150
|
+
});
|
|
151
|
+
if (directive.text) {
|
|
152
|
+
const remainChunks = chunkTextByUtf8Bytes(formatText(directive.text), BYTE_LIMIT);
|
|
153
|
+
for (const chunk of remainChunks) {
|
|
154
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, chunk);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return { channel: CHANNEL_ID, messageId: mpResult.msgid, chatId: to };
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
161
|
+
throw err;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (directive.menu) {
|
|
165
|
+
try {
|
|
166
|
+
const menuPayload = buildMsgMenuPayload(directive.menu);
|
|
167
|
+
const menuResult = await sendMsgMenuMessage(account.corpId, account.appSecret, externalUserId, openKfId, menuPayload);
|
|
168
|
+
if (directive.text) {
|
|
169
|
+
const remainChunks = chunkTextByUtf8Bytes(formatText(directive.text), BYTE_LIMIT);
|
|
170
|
+
for (const chunk of remainChunks) {
|
|
171
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, chunk);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return { channel: CHANNEL_ID, messageId: menuResult.msgid, chatId: to };
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
178
|
+
throw err;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (directive.businessCard) {
|
|
182
|
+
try {
|
|
183
|
+
const cardResult = await sendBusinessCardMessage(account.corpId, account.appSecret, externalUserId, openKfId, directive.businessCard);
|
|
184
|
+
if (directive.text) {
|
|
185
|
+
const remainChunks = chunkTextByUtf8Bytes(formatText(directive.text), BYTE_LIMIT);
|
|
186
|
+
for (const chunk of remainChunks) {
|
|
187
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, chunk);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return { channel: CHANNEL_ID, messageId: cardResult.msgid, chatId: to };
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
194
|
+
throw err;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (directive.caLink) {
|
|
198
|
+
try {
|
|
199
|
+
const caResult = await sendCaLinkMessage(account.corpId, account.appSecret, externalUserId, openKfId, directive.caLink);
|
|
200
|
+
if (directive.text) {
|
|
201
|
+
const remainChunks = chunkTextByUtf8Bytes(formatText(directive.text), BYTE_LIMIT);
|
|
202
|
+
for (const chunk of remainChunks) {
|
|
203
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, chunk);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return { channel: CHANNEL_ID, messageId: caResult.msgid, chatId: to };
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
210
|
+
throw err;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (directive.raw) {
|
|
214
|
+
try {
|
|
215
|
+
const rawResult = await sendRawMessage(account.corpId, account.appSecret, externalUserId, openKfId, directive.raw.msgtype, directive.raw.payload);
|
|
216
|
+
if (directive.text) {
|
|
217
|
+
const remainChunks = chunkTextByUtf8Bytes(formatText(directive.text), BYTE_LIMIT);
|
|
218
|
+
for (const chunk of remainChunks) {
|
|
219
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, chunk);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return { channel: CHANNEL_ID, messageId: rawResult.msgid, chatId: to };
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
226
|
+
throw err;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const formatted = formatText(text);
|
|
230
|
+
const chunks = chunkTextByUtf8Bytes(formatted, BYTE_LIMIT);
|
|
231
|
+
try {
|
|
232
|
+
let lastResult;
|
|
233
|
+
for (const chunk of chunks) {
|
|
234
|
+
lastResult = await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, chunk);
|
|
235
|
+
}
|
|
236
|
+
return { channel: CHANNEL_ID, messageId: lastResult?.msgid ?? "", chatId: to };
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
240
|
+
throw err;
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
sendMedia: async ({ cfg, to, text, mediaUrl, accountId }) => {
|
|
244
|
+
const account = resolveAccount(cfg, accountId ?? "");
|
|
245
|
+
const openKfId = account.openKfId ?? accountId ?? "";
|
|
246
|
+
if (!account.corpId || !account.appSecret || !openKfId) {
|
|
247
|
+
throw new Error(`${logTag()} missing corpId/appSecret/openKfId`);
|
|
248
|
+
}
|
|
249
|
+
const externalUserId = String(to).replace(/^user:/, "");
|
|
250
|
+
if (mediaUrl) {
|
|
251
|
+
const core = getRuntime();
|
|
252
|
+
const loaded = await core.media.loadWebMedia(mediaUrl, { optimizeImages: false });
|
|
253
|
+
const mediaType = mediaKindToWechatType(loaded.kind);
|
|
254
|
+
try {
|
|
255
|
+
const result = await uploadAndSendMedia(account.corpId, account.appSecret, externalUserId, openKfId, loaded.buffer, loaded.fileName ?? "file", mediaType);
|
|
256
|
+
if (text?.trim()) {
|
|
257
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, formatText(text));
|
|
258
|
+
}
|
|
259
|
+
return { channel: CHANNEL_ID, messageId: result.msgid, chatId: to };
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
263
|
+
throw err;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// ── No resolvable media: send as text ──
|
|
267
|
+
const content = text?.trim() ? `${text}\n${mediaUrl || ""}` : mediaUrl || text || "";
|
|
268
|
+
try {
|
|
269
|
+
const result = await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, content);
|
|
270
|
+
return { channel: CHANNEL_ID, messageId: result.msgid, chatId: to };
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
274
|
+
throw err;
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
sendPayload: async ({ cfg, to, text, accountId, payload }) => {
|
|
278
|
+
const account = resolveAccount(cfg, accountId ?? "");
|
|
279
|
+
const openKfId = account.openKfId ?? accountId ?? "";
|
|
280
|
+
if (!account.corpId || !account.appSecret || !openKfId) {
|
|
281
|
+
throw new Error(`${logTag()} missing corpId/appSecret/openKfId`);
|
|
282
|
+
}
|
|
283
|
+
const externalUserId = String(to).replace(/^user:/, "");
|
|
284
|
+
const wechatKf = payload.channelData?.wechatKf;
|
|
285
|
+
const link = wechatKf?.link;
|
|
286
|
+
if (link) {
|
|
287
|
+
let thumbMediaId = link.thumb_media_id;
|
|
288
|
+
// Resolve thumbnail if only thumbUrl/path/media_id is provided
|
|
289
|
+
if (!thumbMediaId && link.thumbUrl) {
|
|
290
|
+
thumbMediaId = await resolveThumbMediaId(link.thumbUrl, account.corpId, account.appSecret);
|
|
291
|
+
}
|
|
292
|
+
if (!thumbMediaId) {
|
|
293
|
+
throw new Error(`${logTag()} sendPayload link requires thumb_media_id or thumbUrl`);
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
const result = await sendLinkMessage(account.corpId, account.appSecret, externalUserId, openKfId, {
|
|
297
|
+
title: link.title,
|
|
298
|
+
desc: link.desc,
|
|
299
|
+
url: link.url,
|
|
300
|
+
thumb_media_id: thumbMediaId,
|
|
301
|
+
});
|
|
302
|
+
// Send accompanying text if present
|
|
303
|
+
if ((text ?? payload.text)?.trim()) {
|
|
304
|
+
const textContent = (text ?? payload.text);
|
|
305
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, formatText(textContent));
|
|
306
|
+
}
|
|
307
|
+
return { channel: CHANNEL_ID, messageId: result.msgid, chatId: to };
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
311
|
+
throw err;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
const location = wechatKf?.location;
|
|
315
|
+
if (location) {
|
|
316
|
+
try {
|
|
317
|
+
const result = await sendLocationMessage(account.corpId, account.appSecret, externalUserId, openKfId, location);
|
|
318
|
+
if ((text ?? payload.text)?.trim()) {
|
|
319
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, formatText((text ?? payload.text)));
|
|
320
|
+
}
|
|
321
|
+
return { channel: CHANNEL_ID, messageId: result.msgid, chatId: to };
|
|
322
|
+
}
|
|
323
|
+
catch (err) {
|
|
324
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
325
|
+
throw err;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
const miniprogram = wechatKf?.miniprogram;
|
|
329
|
+
if (miniprogram) {
|
|
330
|
+
let thumbMediaId = miniprogram.thumb_media_id;
|
|
331
|
+
if (!thumbMediaId && miniprogram.thumbUrl) {
|
|
332
|
+
thumbMediaId = await resolveThumbMediaId(miniprogram.thumbUrl, account.corpId, account.appSecret);
|
|
333
|
+
}
|
|
334
|
+
if (!thumbMediaId) {
|
|
335
|
+
throw new Error(`${logTag()} sendPayload miniprogram requires thumb_media_id or thumbUrl`);
|
|
336
|
+
}
|
|
337
|
+
try {
|
|
338
|
+
const result = await sendMiniprogramMessage(account.corpId, account.appSecret, externalUserId, openKfId, {
|
|
339
|
+
appid: miniprogram.appid,
|
|
340
|
+
title: miniprogram.title,
|
|
341
|
+
pagepath: miniprogram.pagepath,
|
|
342
|
+
thumb_media_id: thumbMediaId,
|
|
343
|
+
});
|
|
344
|
+
if ((text ?? payload.text)?.trim()) {
|
|
345
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, formatText((text ?? payload.text)));
|
|
346
|
+
}
|
|
347
|
+
return { channel: CHANNEL_ID, messageId: result.msgid, chatId: to };
|
|
348
|
+
}
|
|
349
|
+
catch (err) {
|
|
350
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
351
|
+
throw err;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const msgmenu = wechatKf?.msgmenu;
|
|
355
|
+
if (msgmenu) {
|
|
356
|
+
try {
|
|
357
|
+
const result = await sendMsgMenuMessage(account.corpId, account.appSecret, externalUserId, openKfId, msgmenu);
|
|
358
|
+
if ((text ?? payload.text)?.trim()) {
|
|
359
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, formatText((text ?? payload.text)));
|
|
360
|
+
}
|
|
361
|
+
return { channel: CHANNEL_ID, messageId: result.msgid, chatId: to };
|
|
362
|
+
}
|
|
363
|
+
catch (err) {
|
|
364
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
365
|
+
throw err;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const businessCard = wechatKf?.businessCard;
|
|
369
|
+
if (businessCard) {
|
|
370
|
+
try {
|
|
371
|
+
const result = await sendBusinessCardMessage(account.corpId, account.appSecret, externalUserId, openKfId, businessCard);
|
|
372
|
+
if ((text ?? payload.text)?.trim()) {
|
|
373
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, formatText((text ?? payload.text)));
|
|
374
|
+
}
|
|
375
|
+
return { channel: CHANNEL_ID, messageId: result.msgid, chatId: to };
|
|
376
|
+
}
|
|
377
|
+
catch (err) {
|
|
378
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
379
|
+
throw err;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
const caLink = wechatKf?.caLink;
|
|
383
|
+
if (caLink) {
|
|
384
|
+
try {
|
|
385
|
+
const result = await sendCaLinkMessage(account.corpId, account.appSecret, externalUserId, openKfId, caLink);
|
|
386
|
+
if ((text ?? payload.text)?.trim()) {
|
|
387
|
+
await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, formatText((text ?? payload.text)));
|
|
388
|
+
}
|
|
389
|
+
return { channel: CHANNEL_ID, messageId: result.msgid, chatId: to };
|
|
390
|
+
}
|
|
391
|
+
catch (err) {
|
|
392
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
393
|
+
throw err;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
// No link data — fall back to sending text
|
|
397
|
+
const textContent = text ?? payload.text ?? "";
|
|
398
|
+
if (textContent.trim()) {
|
|
399
|
+
try {
|
|
400
|
+
const result = await sendTextMessage(account.corpId, account.appSecret, externalUserId, openKfId, formatText(textContent));
|
|
401
|
+
return { channel: CHANNEL_ID, messageId: result.msgid, chatId: to };
|
|
402
|
+
}
|
|
403
|
+
catch (err) {
|
|
404
|
+
warnSessionLimit(err, externalUserId, openKfId);
|
|
405
|
+
throw err;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return { channel: CHANNEL_ID, messageId: "", chatId: to };
|
|
409
|
+
},
|
|
410
|
+
};
|
|
411
|
+
//# sourceMappingURL=outbound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound.js","sourceRoot":"","sources":["../src/outbound.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reply dispatcher for WeChat KF (typing-aware streaming replies)
|
|
3
|
+
*
|
|
4
|
+
* Responsibility:
|
|
5
|
+
* This module is used internally by `bot.ts` when the agent streams tokens
|
|
6
|
+
* back to the user. It wraps OpenClaw's `createReplyDispatcherWithTyping` to
|
|
7
|
+
* batch tokens into natural-looking messages with simulated human typing
|
|
8
|
+
* delay, then delivers them through the WeChat KF API.
|
|
9
|
+
*
|
|
10
|
+
* Text chunking is performed at delivery time via `chunkTextByUtf8Bytes`
|
|
11
|
+
* (UTF-8 byte-aware, NOT the framework auto-chunker), because streaming
|
|
12
|
+
* replies accumulate text incrementally.
|
|
13
|
+
*
|
|
14
|
+
* Counterpart:
|
|
15
|
+
* `outbound.ts` handles the *other* outbound path: framework-driven direct
|
|
16
|
+
* delivery where the framework itself pre-chunks text via the declared
|
|
17
|
+
* `chunker` function.
|
|
18
|
+
*
|
|
19
|
+
* accountId = openKfId (dynamically discovered)
|
|
20
|
+
*/
|
|
21
|
+
import type { OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk";
|
|
22
|
+
/** Minimal runtime shape used only for error logging in the reply dispatcher. */
|
|
23
|
+
type RuntimeErrorLogger = {
|
|
24
|
+
error?: (...args: unknown[]) => void;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
};
|
|
27
|
+
export type CreateReplyDispatcherParams = {
|
|
28
|
+
cfg: OpenClawConfig;
|
|
29
|
+
agentId: string;
|
|
30
|
+
runtime: RuntimeErrorLogger;
|
|
31
|
+
externalUserId: string;
|
|
32
|
+
openKfId: string;
|
|
33
|
+
accountId: string;
|
|
34
|
+
};
|
|
35
|
+
export declare function createReplyDispatcher(params: CreateReplyDispatcherParams): ReturnType<PluginRuntime["channel"]["reply"]["createReplyDispatcherWithTyping"]>;
|
|
36
|
+
export {};
|