@cloudbase/agent-adapter-wx 0.0.18

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/dist/index.js ADDED
@@ -0,0 +1,1257 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ MessageFormatter: () => MessageFormatter,
34
+ MessageType: () => MessageType,
35
+ PlatformRouter: () => PlatformRouter,
36
+ SUPPORTED_MSG_TYPES: () => SUPPORTED_MSG_TYPES,
37
+ TokenManager: () => TokenManager,
38
+ WeChatAgent: () => WeChatAgent,
39
+ WeChatHistoryManager: () => WeChatHistoryManager,
40
+ WeChatPlatform: () => WeChatPlatform,
41
+ WeChatSendMode: () => WeChatSendMode,
42
+ WeChatSender: () => WeChatSender,
43
+ createWxMessageHandler: () => createWxMessageHandler,
44
+ dealMsgData: () => dealMsgData,
45
+ extractConversation: () => extractConversation,
46
+ extractMsgId: () => extractMsgId,
47
+ extractMsgType: () => extractMsgType,
48
+ extractSender: () => extractSender,
49
+ extractTextContent: () => extractTextContent,
50
+ extractTimestamp: () => extractTimestamp,
51
+ extractTriggerSrc: () => extractTriggerSrc,
52
+ extractVoiceMediaId: () => extractVoiceMediaId,
53
+ formatWeChatReplyMessage: () => formatWeChatReplyMessage,
54
+ generateRecordId: () => generateRecordId,
55
+ getHistoryManager: () => getHistoryManager,
56
+ getWxChatContent: () => getWxChatContent,
57
+ handleWeChatRetry: () => handleWeChatRetry,
58
+ isContinueCommandValid: () => isContinueCommandValid,
59
+ needAsyncReply: () => needAsyncReply,
60
+ validateMessageType: () => validateMessageType
61
+ });
62
+ module.exports = __toCommonJS(index_exports);
63
+
64
+ // src/types.ts
65
+ var WeChatPlatform = /* @__PURE__ */ ((WeChatPlatform2) => {
66
+ WeChatPlatform2["CUSTOM_SERVICE"] = "WXCustomerService";
67
+ WeChatPlatform2["MINI_APP"] = "WXMiniapp";
68
+ WeChatPlatform2["SERVICE"] = "WXService";
69
+ WeChatPlatform2["SUBSCRIPTION"] = "WXSubscription";
70
+ return WeChatPlatform2;
71
+ })(WeChatPlatform || {});
72
+ var MessageType = /* @__PURE__ */ ((MessageType2) => {
73
+ MessageType2["TEXT"] = "text";
74
+ MessageType2["IMAGE"] = "image";
75
+ MessageType2["EVENT"] = "event";
76
+ MessageType2["VOICE"] = "voice";
77
+ return MessageType2;
78
+ })(MessageType || {});
79
+ var WeChatSendMode = /* @__PURE__ */ ((WeChatSendMode2) => {
80
+ WeChatSendMode2["LOCAL"] = "local";
81
+ WeChatSendMode2["AITOOLS"] = "aitools";
82
+ return WeChatSendMode2;
83
+ })(WeChatSendMode || {});
84
+
85
+ // src/wechat-message-handler.ts
86
+ var SUPPORTED_MSG_TYPES = ["text", "voice"];
87
+ function validateMessageType(msgType) {
88
+ if (SUPPORTED_MSG_TYPES.includes(msgType)) {
89
+ return { isValid: true, skipAI: false };
90
+ }
91
+ return {
92
+ isValid: false,
93
+ skipAI: true,
94
+ errorMessage: `\u65E0\u6CD5\u5904\u7406\u7684\u6D88\u606F\u7C7B\u578B:${msgType}`,
95
+ userErrorMessage: "\u62B1\u6B49\u6682\u65F6\u65E0\u6CD5\u5904\u7406\u8FD9\u4E2A\u7C7B\u578B\u7684\u6D88\u606F"
96
+ };
97
+ }
98
+ function extractMsgType(originMsg) {
99
+ return originMsg.msgType || originMsg.MsgType || "text";
100
+ }
101
+ function extractTriggerSrc(originMsg, defaultSrc = "WXService" /* SERVICE */) {
102
+ return originMsg.triggerSrc || defaultSrc;
103
+ }
104
+ function extractTextContent(originMsg, triggerSrc) {
105
+ if ([
106
+ "WXSubscription" /* SUBSCRIPTION */,
107
+ "WXService" /* SERVICE */,
108
+ "WXMiniapp" /* MINI_APP */
109
+ ].includes(triggerSrc)) {
110
+ return originMsg.Content || originMsg.content || "";
111
+ } else if (triggerSrc === "WXCustomerService" /* CUSTOM_SERVICE */) {
112
+ return originMsg.text?.content || "";
113
+ }
114
+ return "";
115
+ }
116
+ function extractVoiceMediaId(originMsg, triggerSrc) {
117
+ if (["WXSubscription" /* SUBSCRIPTION */, "WXService" /* SERVICE */].includes(triggerSrc)) {
118
+ return originMsg.MediaId || originMsg.mediaId || "";
119
+ } else if (triggerSrc === "WXCustomerService" /* CUSTOM_SERVICE */) {
120
+ return originMsg.voice?.mediaId || "";
121
+ }
122
+ return "";
123
+ }
124
+ async function getWxChatContent(originMsg, triggerSrc, voiceMessageHandler, botId) {
125
+ const msgType = extractMsgType(originMsg);
126
+ if (msgType === "text") {
127
+ return extractTextContent(originMsg, triggerSrc);
128
+ }
129
+ if (msgType === "voice") {
130
+ const mediaId = extractVoiceMediaId(originMsg, triggerSrc);
131
+ if (voiceMessageHandler && mediaId && botId) {
132
+ const result = await voiceMessageHandler(botId, triggerSrc, mediaId);
133
+ return result?.content || "";
134
+ }
135
+ }
136
+ return "";
137
+ }
138
+ function extractSender(originMsg, triggerSrc) {
139
+ if ([
140
+ "WXSubscription" /* SUBSCRIPTION */,
141
+ "WXService" /* SERVICE */,
142
+ "WXMiniapp" /* MINI_APP */
143
+ ].includes(triggerSrc)) {
144
+ return originMsg.FromUserName || originMsg.fromUserName || "";
145
+ } else if (triggerSrc === "WXCustomerService" /* CUSTOM_SERVICE */) {
146
+ return originMsg.externalUserId || "";
147
+ }
148
+ return "";
149
+ }
150
+ function extractConversation(originMsg, triggerSrc) {
151
+ if ([
152
+ "WXSubscription" /* SUBSCRIPTION */,
153
+ "WXService" /* SERVICE */,
154
+ "WXMiniapp" /* MINI_APP */
155
+ ].includes(triggerSrc)) {
156
+ return originMsg.FromUserName || originMsg.fromUserName || "";
157
+ } else if (triggerSrc === "WXCustomerService" /* CUSTOM_SERVICE */) {
158
+ return originMsg.externalUserId || "";
159
+ }
160
+ return "";
161
+ }
162
+ function generateRecordId(triggerSrc, msgId, timestamp) {
163
+ return `${triggerSrc}${msgId}${timestamp}`;
164
+ }
165
+ function extractMsgId(originMsg) {
166
+ return originMsg.msgId || originMsg.MsgId || Date.now().toString();
167
+ }
168
+ function extractTimestamp(originMsg, triggerSrc) {
169
+ if (triggerSrc === "WXCustomerService" /* CUSTOM_SERVICE */) {
170
+ return originMsg.sendTime || Math.floor(Date.now() / 1e3);
171
+ }
172
+ return originMsg.createTime || originMsg.CreateTime || Math.floor(Date.now() / 1e3);
173
+ }
174
+ function needAsyncReply(triggerSrc, wxVerify) {
175
+ if (["WXMiniapp" /* MINI_APP */, "WXCustomerService" /* CUSTOM_SERVICE */].includes(
176
+ triggerSrc
177
+ )) {
178
+ return true;
179
+ }
180
+ return wxVerify;
181
+ }
182
+ function formatWeChatReplyMessage(callbackData, triggerSrc, content) {
183
+ const createTime = Math.floor(Date.now() / 1e3);
184
+ const finalContent = content || "\u62B1\u6B49\u6682\u65F6\u65E0\u6CD5\u5904\u7406\u8FD9\u4E2A\u7C7B\u578B\u7684\u6D88\u606F";
185
+ if (triggerSrc === "WXCustomerService" /* CUSTOM_SERVICE */) {
186
+ return {
187
+ toUserName: callbackData.externalUserId || callbackData.fromUserName,
188
+ fromUserName: callbackData.openKfId,
189
+ openKfId: callbackData.openKfId,
190
+ createTime,
191
+ msgType: "text",
192
+ content: finalContent,
193
+ msgId: callbackData.msgId
194
+ };
195
+ }
196
+ return {
197
+ toUserName: callbackData.fromUserName || callbackData.FromUserName,
198
+ fromUserName: callbackData.toUserName || callbackData.ToUserName,
199
+ createTime,
200
+ msgType: "text",
201
+ content: finalContent,
202
+ msgId: callbackData.msgId
203
+ };
204
+ }
205
+ function dealMsgData(originMsg, triggerSrc, wxVerify, botId) {
206
+ const baseMsgData = {
207
+ type: "text",
208
+ triggerSrc,
209
+ botId,
210
+ recommendQuestions: [],
211
+ content: "",
212
+ originMsg: "",
213
+ createdAt: Date.now()
214
+ };
215
+ const sender = extractSender(originMsg, triggerSrc);
216
+ const conversation = extractConversation(originMsg, triggerSrc);
217
+ const msgId = extractMsgId(originMsg);
218
+ const timestamp = extractTimestamp(originMsg, triggerSrc);
219
+ const recordIdBase = generateRecordId(triggerSrc, msgId, timestamp);
220
+ const asyncReply = needAsyncReply(triggerSrc, wxVerify);
221
+ const msgType = extractMsgType(originMsg);
222
+ return {
223
+ msgData: {
224
+ ...baseMsgData,
225
+ recordId: `user-${recordIdBase}`,
226
+ role: "user",
227
+ sender,
228
+ conversation,
229
+ type: msgType,
230
+ needAsyncReply: asyncReply,
231
+ reply: recordIdBase,
232
+ originMsg: JSON.stringify(originMsg)
233
+ },
234
+ replyMsgData: {
235
+ ...baseMsgData,
236
+ recordId: recordIdBase,
237
+ role: "assistant",
238
+ sender,
239
+ conversation,
240
+ type: "text",
241
+ needAsyncReply: asyncReply,
242
+ reply: "",
243
+ originMsg: JSON.stringify({})
244
+ }
245
+ };
246
+ }
247
+ async function handleWeChatRetry(previousReply, originMsg, triggerSrc) {
248
+ if (!previousReply) {
249
+ return { shouldSkip: false };
250
+ }
251
+ const timestamp = extractTimestamp(originMsg, triggerSrc);
252
+ const deltaTime = Date.now() - timestamp * 1e3;
253
+ if (previousReply.content) {
254
+ return {
255
+ shouldSkip: true,
256
+ content: previousReply.content
257
+ };
258
+ }
259
+ if (deltaTime > 11 * 1e3) {
260
+ return {
261
+ shouldSkip: true,
262
+ content: '\u601D\u8003\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u56DE\u590D "\u7EE7\u7EED" \u6765\u83B7\u53D6\u56DE\u7B54\u5185\u5BB9'
263
+ };
264
+ }
265
+ await new Promise((resolve) => setTimeout(resolve, 5e3));
266
+ return { shouldSkip: true };
267
+ }
268
+ function isContinueCommandValid(previousReply) {
269
+ if (!previousReply) {
270
+ return false;
271
+ }
272
+ const fiveMinutes = 5 * 60 * 1e3;
273
+ return Date.now() - previousReply.createdAt < fiveMinutes;
274
+ }
275
+
276
+ // src/server/wx.controller.ts
277
+ var import_uuid = require("uuid");
278
+ var import_agent_server = require("@cloudbase/agent-server");
279
+ var import_agent_shared = require("@cloudbase/agent-shared");
280
+ var import_client = require("@ag-ui/client");
281
+ var import_agent_shared2 = require("@cloudbase/agent-shared");
282
+ var import_aiagent_framework = require("@cloudbase/aiagent-framework");
283
+ function getServiceNameFromHostname(hostname) {
284
+ const parts = hostname.split("-");
285
+ let versionIdx = -1;
286
+ for (let i = parts.length - 1; i >= 0; i--) {
287
+ if (/^\d+$/.test(parts[i])) {
288
+ versionIdx = i;
289
+ break;
290
+ }
291
+ }
292
+ return versionIdx > 0 ? parts.slice(0, versionIdx).join("-") : hostname;
293
+ }
294
+ function getBotId(url, fallback = "agent-id") {
295
+ if (process.env.SCF_FUNCTIONNAME) {
296
+ return process.env.SCF_FUNCTIONNAME;
297
+ }
298
+ if (url) {
299
+ const parsedBotId = import_aiagent_framework.utils.parseBotId(url);
300
+ if (parsedBotId) {
301
+ return parsedBotId;
302
+ }
303
+ }
304
+ if (process.env.HOSTNAME) {
305
+ return getServiceNameFromHostname(process.env.HOSTNAME);
306
+ }
307
+ return fallback;
308
+ }
309
+ function createWxMessageHandler(createAgent, options) {
310
+ const { logger: parentLogger = import_agent_shared.noopLogger } = options ?? {};
311
+ const adapterLogger = parentLogger.child?.({ component: "sendWXMessageAGUI" }) ?? parentLogger;
312
+ return async (req, res) => {
313
+ let cleanup = null;
314
+ let agent = void 0;
315
+ const { callbackData } = import_aiagent_framework.utils.transformKeysToCamelCase(req.body);
316
+ const { triggerSrc, wxVerify } = import_aiagent_framework.utils.parseWxEnvParam({
317
+ httpContext: {
318
+ headers: req.headers
319
+ }
320
+ });
321
+ const wxSendmessageInput = {
322
+ callbackData,
323
+ triggerSrc,
324
+ wxVerify
325
+ };
326
+ const requestId = (0, import_uuid.v4)();
327
+ const logger = adapterLogger.child?.({ requestId }) ?? adapterLogger;
328
+ const botId = getBotId(
329
+ `${req.protocol}://${req.get("host")}${req.originalUrl}`,
330
+ "agent-wx-send-message"
331
+ );
332
+ try {
333
+ if (!callbackData || !triggerSrc) {
334
+ return res.status(400).json({
335
+ error: "Bad Request",
336
+ message: "Missing required fields: callbackData, triggerSrc"
337
+ });
338
+ }
339
+ logger.info?.("[WX] Received message:", { triggerSrc, wxVerify, botId });
340
+ const { agent: unknownAgent, cleanup: agentCleanup } = await Promise.resolve(
341
+ createAgent({ request: req, options: { agentId: botId } })
342
+ );
343
+ cleanup = agentCleanup ?? null;
344
+ agent = "toAGUIAgent" in unknownAgent ? unknownAgent.toAGUIAgent() : unknownAgent;
345
+ const { msgData, replyMsgData } = dealMsgData(
346
+ callbackData,
347
+ triggerSrc,
348
+ wxVerify,
349
+ botId
350
+ );
351
+ let skipAI = false;
352
+ let isEnd = false;
353
+ const msgType = extractMsgType(callbackData);
354
+ const validation = validateMessageType(msgType);
355
+ if (!validation.isValid) {
356
+ skipAI = true;
357
+ replyMsgData.content = validation.userErrorMessage || "\u6682\u4E0D\u652F\u6301\u8BE5\u6D88\u606F\u7C7B\u578B";
358
+ }
359
+ const previousReply = await agent.getPreviousReply(
360
+ replyMsgData.conversation,
361
+ replyMsgData.recordId
362
+ );
363
+ const voiceHandler = async (vBotId, vTriggerSrc, mediaId) => {
364
+ try {
365
+ const result = await agent?.aitools?.getWxMediaContent(
366
+ vBotId,
367
+ vTriggerSrc,
368
+ mediaId
369
+ );
370
+ return result || null;
371
+ } catch {
372
+ return null;
373
+ }
374
+ };
375
+ const content = await getWxChatContent(
376
+ callbackData,
377
+ triggerSrc,
378
+ voiceHandler,
379
+ botId
380
+ );
381
+ if (["WXSubscription", "WXService"].includes(triggerSrc) && !wxVerify && !skipAI) {
382
+ const result = await agent.handleUnverifiedChat({
383
+ content,
384
+ conversation: replyMsgData.conversation,
385
+ previousReply,
386
+ callbackData,
387
+ triggerSrc
388
+ });
389
+ skipAI = result.needSkipAI;
390
+ isEnd = result.isEnd;
391
+ if (result.replyContent) replyMsgData.content = result.replyContent;
392
+ }
393
+ if (isEnd) {
394
+ return res.json({});
395
+ }
396
+ if (!content && !skipAI) {
397
+ logger.warn?.("[WX] Empty content");
398
+ return res.json(
399
+ formatWeChatReplyMessage(callbackData, triggerSrc, "\u65E0\u6CD5\u8BC6\u522B\u6D88\u606F\u5185\u5BB9")
400
+ );
401
+ }
402
+ if (skipAI) {
403
+ logger.info?.("[WX] Skipping AI");
404
+ return res.json(
405
+ formatWeChatReplyMessage(
406
+ callbackData,
407
+ triggerSrc,
408
+ replyMsgData.content
409
+ )
410
+ );
411
+ }
412
+ logger.info?.("[WX] Processing:", content.substring(0, 100));
413
+ const input = {
414
+ messages: [
415
+ {
416
+ id: msgData.recordId,
417
+ role: "user",
418
+ content
419
+ }
420
+ ],
421
+ state: void 0,
422
+ threadId: msgData.conversation,
423
+ runId: (0, import_uuid.v4)(),
424
+ tools: [],
425
+ context: [],
426
+ forwardedProps: {
427
+ wxSendmessageInput,
428
+ // Pass full msgData for history storage
429
+ msgData,
430
+ // Pass replay info with replyMsgData for assistant history
431
+ replay: {
432
+ id: replyMsgData.recordId,
433
+ ...replyMsgData
434
+ }
435
+ }
436
+ };
437
+ const events = import_agent_server.agui.sendMessageAGUI.handler(input, agent);
438
+ for await (const event of events) {
439
+ if (event.type === import_client.EventType.RUN_ERROR) {
440
+ logger.error?.(
441
+ "[WX] Agent error:",
442
+ event.error || event.message
443
+ );
444
+ }
445
+ }
446
+ logger.info?.("[WX] Processing complete");
447
+ if (replyMsgData.needAsyncReply) {
448
+ return res.json({});
449
+ }
450
+ const finalContent = agent.lastReply || "\u62B1\u6B49\uFF0C\u65E0\u6CD5\u751F\u6210\u56DE\u590D";
451
+ return res.json(
452
+ formatWeChatReplyMessage(callbackData, triggerSrc, finalContent)
453
+ );
454
+ } catch (error) {
455
+ logger.error?.("[WX] Error processing message:", error);
456
+ const message = error instanceof Error ? error.message : String(error);
457
+ try {
458
+ if (agent?.aitools?.sendWxClientMessage) {
459
+ const data = formatWeChatReplyMessage(
460
+ callbackData,
461
+ triggerSrc,
462
+ message
463
+ );
464
+ await agent.aitools.sendWxClientMessage(
465
+ agent.agentId || botId,
466
+ triggerSrc,
467
+ {
468
+ msgType: data.msgType,
469
+ touser: data.toUserName,
470
+ text: {
471
+ content: data.content
472
+ },
473
+ openKfId: data.openKfId,
474
+ msgId: data.msgId
475
+ }
476
+ );
477
+ }
478
+ } catch (e) {
479
+ }
480
+ return res.status(500).json({
481
+ error: "Internal Server Error",
482
+ message
483
+ });
484
+ } finally {
485
+ if (cleanup) cleanup();
486
+ }
487
+ };
488
+ }
489
+
490
+ // src/token-manager.ts
491
+ var TokenManager = class {
492
+ constructor() {
493
+ this.cache = /* @__PURE__ */ new Map();
494
+ }
495
+ /**
496
+ * Get access token (with caching)
497
+ */
498
+ async getAccessToken(config) {
499
+ const cacheKey = this.getCacheKey(config);
500
+ const cached = this.cache.get(cacheKey);
501
+ if (cached && cached.expiresAt > Date.now()) {
502
+ return cached.accessToken;
503
+ }
504
+ const token = await this.fetchAccessToken(config);
505
+ return token;
506
+ }
507
+ /**
508
+ * Fetch access token from WeChat API
509
+ */
510
+ async fetchAccessToken(config) {
511
+ const url = this.getTokenUrl(config);
512
+ const response = await fetch(url);
513
+ const data = await response.json();
514
+ if (data.errcode && data.errcode !== 0) {
515
+ throw new Error(`Failed to get access token: ${data.errmsg}`);
516
+ }
517
+ const cacheKey = this.getCacheKey(config);
518
+ const expiresAt = Date.now() + (data.expires_in - 300) * 1e3;
519
+ this.cache.set(cacheKey, {
520
+ accessToken: data.access_token,
521
+ expiresAt
522
+ });
523
+ return data.access_token;
524
+ }
525
+ /**
526
+ * Get token URL based on platform
527
+ */
528
+ getTokenUrl(config) {
529
+ if (config.platform === "WXCustomerService" /* CUSTOM_SERVICE */) {
530
+ return `https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${config.appId}&corpsecret=${config.appSecret}`;
531
+ }
532
+ return `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${config.appId}&secret=${config.appSecret}`;
533
+ }
534
+ /**
535
+ * Generate cache key
536
+ */
537
+ getCacheKey(config) {
538
+ return `${config.platform}_${config.appId}`;
539
+ }
540
+ /**
541
+ * Clear token cache
542
+ */
543
+ clearCache(config) {
544
+ if (config) {
545
+ this.cache.delete(this.getCacheKey(config));
546
+ } else {
547
+ this.cache.clear();
548
+ }
549
+ }
550
+ };
551
+
552
+ // src/message-formatter.ts
553
+ var MessageFormatter = class {
554
+ /**
555
+ * Format message for WeChat API
556
+ */
557
+ formatMessage(options, platform, originMsg) {
558
+ const { toUser, message, recommendQuestions, msgId } = options;
559
+ let content = message.content;
560
+ if (recommendQuestions && recommendQuestions.length > 0) {
561
+ content = this.withRecommendQuestions(content, recommendQuestions);
562
+ }
563
+ const baseMessage = {
564
+ touser: toUser,
565
+ msgtype: message.type
566
+ };
567
+ if (message.type === "text" /* TEXT */) {
568
+ baseMessage.text = { content };
569
+ } else if (message.type === "image" /* IMAGE */ && message.imageUrl) {
570
+ baseMessage.image = { pic_url: message.imageUrl };
571
+ }
572
+ if (platform === "WXCustomerService" /* CUSTOM_SERVICE */) {
573
+ baseMessage.open_kfid = originMsg?.open_kfid;
574
+ baseMessage.msgid = msgId || originMsg?.msgid;
575
+ }
576
+ return baseMessage;
577
+ }
578
+ /**
579
+ * Append recommended questions to content
580
+ */
581
+ withRecommendQuestions(content, questions) {
582
+ if (!questions || questions.length === 0) {
583
+ return content;
584
+ }
585
+ return `${content}
586
+
587
+ \u63A8\u8350\u95EE\u9898:
588
+ ${questions.join("\n")}`;
589
+ }
590
+ /**
591
+ * Split long message into chunks
592
+ */
593
+ splitLongMessage(content, maxLength = 2e3) {
594
+ if (content.length <= maxLength) {
595
+ return [content];
596
+ }
597
+ const chunks = [];
598
+ let currentChunk = "";
599
+ const lines = content.split("\n");
600
+ for (const line of lines) {
601
+ if ((currentChunk + line).length > maxLength) {
602
+ if (currentChunk) {
603
+ chunks.push(currentChunk.trim());
604
+ currentChunk = "";
605
+ }
606
+ if (line.length > maxLength) {
607
+ for (let i = 0; i < line.length; i += maxLength) {
608
+ chunks.push(line.substring(i, i + maxLength));
609
+ }
610
+ } else {
611
+ currentChunk = line + "\n";
612
+ }
613
+ } else {
614
+ currentChunk += line + "\n";
615
+ }
616
+ }
617
+ if (currentChunk) {
618
+ chunks.push(currentChunk.trim());
619
+ }
620
+ return chunks;
621
+ }
622
+ };
623
+
624
+ // src/platform-router.ts
625
+ var PlatformRouter = class {
626
+ constructor(tokenManager) {
627
+ this.tokenManager = tokenManager;
628
+ }
629
+ /**
630
+ * Send message to WeChat platform
631
+ */
632
+ async send(message, config) {
633
+ const accessToken = await this.tokenManager.getAccessToken(config);
634
+ switch (config.platform) {
635
+ case "WXCustomerService" /* CUSTOM_SERVICE */:
636
+ return this.sendToCustomService(message, accessToken, config);
637
+ case "WXMiniapp" /* MINI_APP */:
638
+ return this.sendToMiniApp(message, accessToken);
639
+ case "WXService" /* SERVICE */:
640
+ case "WXSubscription" /* SUBSCRIPTION */:
641
+ return this.sendToOfficialAccount(message, accessToken);
642
+ default:
643
+ throw new Error(`Unsupported platform: ${config.platform}`);
644
+ }
645
+ }
646
+ /**
647
+ * Send to Enterprise WeChat Customer Service
648
+ */
649
+ async sendToCustomService(message, accessToken, config) {
650
+ const url = `https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token=${accessToken}`;
651
+ const response = await fetch(url, {
652
+ method: "POST",
653
+ headers: { "Content-Type": "application/json" },
654
+ body: JSON.stringify(message)
655
+ });
656
+ return response.json();
657
+ }
658
+ /**
659
+ * Send to WeChat Mini Program
660
+ */
661
+ async sendToMiniApp(message, accessToken) {
662
+ const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${accessToken}`;
663
+ const response = await fetch(url, {
664
+ method: "POST",
665
+ headers: { "Content-Type": "application/json" },
666
+ body: JSON.stringify(message)
667
+ });
668
+ return response.json();
669
+ }
670
+ /**
671
+ * Send to WeChat Official Account (Service/Subscription)
672
+ */
673
+ async sendToOfficialAccount(message, accessToken) {
674
+ const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${accessToken}`;
675
+ const response = await fetch(url, {
676
+ method: "POST",
677
+ headers: { "Content-Type": "application/json" },
678
+ body: JSON.stringify(message)
679
+ });
680
+ return response.json();
681
+ }
682
+ };
683
+
684
+ // src/wechat-sender.ts
685
+ var WeChatSender = class {
686
+ constructor(config) {
687
+ this.config = config;
688
+ this.tokenManager = new TokenManager();
689
+ this.messageFormatter = new MessageFormatter();
690
+ this.platformRouter = new PlatformRouter(this.tokenManager);
691
+ }
692
+ /**
693
+ * Send a message to WeChat
694
+ */
695
+ async send(options, originMsg) {
696
+ const validatedOptions = options;
697
+ const message = this.messageFormatter.formatMessage(
698
+ validatedOptions,
699
+ this.config.platform,
700
+ originMsg
701
+ );
702
+ const result = await this.platformRouter.send(message, this.config);
703
+ if (result.errcode !== 0) {
704
+ throw new Error(`Failed to send message: ${result.errmsg}`);
705
+ }
706
+ return result;
707
+ }
708
+ /**
709
+ * Send multiple messages in batch
710
+ */
711
+ async sendBatch(messages) {
712
+ const results = [];
713
+ for (const message of messages) {
714
+ try {
715
+ const result = await this.send(message);
716
+ results.push(result);
717
+ } catch (error) {
718
+ results.push({
719
+ errcode: -1,
720
+ errmsg: error instanceof Error ? error.message : "Unknown error"
721
+ });
722
+ }
723
+ }
724
+ return results;
725
+ }
726
+ /**
727
+ * Send message asynchronously (fire and forget)
728
+ */
729
+ async sendAsync(options, originMsg) {
730
+ this.send(options, originMsg).catch((error) => {
731
+ console.error("Failed to send message:", error);
732
+ });
733
+ }
734
+ /**
735
+ * Clear token cache
736
+ */
737
+ clearCache() {
738
+ this.tokenManager.clearCache(this.config);
739
+ }
740
+ /**
741
+ * Get current configuration
742
+ */
743
+ getConfig() {
744
+ return { ...this.config };
745
+ }
746
+ };
747
+
748
+ // src/agent.ts
749
+ var import_client2 = require("@ag-ui/client");
750
+ var import_rxjs = require("rxjs");
751
+
752
+ // src/wechat-history-manager.ts
753
+ var import_node_sdk = __toESM(require("@cloudbase/node-sdk"));
754
+ var WX_CHAT_HISTORY_COLLECTION = "wx_chat_history";
755
+ function entryToData(entry) {
756
+ return {
757
+ bot_id: entry.botId || "",
758
+ record_id: entry.messageId,
759
+ role: entry.role,
760
+ status: entry.status,
761
+ content: entry.content,
762
+ conversation: entry.threadId,
763
+ type: entry.type,
764
+ trace_id: entry.runId,
765
+ async_reply: entry.needAsyncReply,
766
+ metadata: entry.metadata,
767
+ createdAt: entry.createdAt || Date.now(),
768
+ updatedAt: Date.now()
769
+ };
770
+ }
771
+ function dataToEntry(data) {
772
+ return {
773
+ id: data._id,
774
+ messageId: data.record_id,
775
+ role: data.role,
776
+ content: data.content,
777
+ threadId: data.conversation,
778
+ createdAt: data.createdAt,
779
+ botId: data.bot_id,
780
+ runId: data.trace_id,
781
+ needAsyncReply: data.async_reply,
782
+ status: data.status,
783
+ type: data.type,
784
+ metadata: data.metadata
785
+ };
786
+ }
787
+ var WeChatHistoryManager = class _WeChatHistoryManager {
788
+ constructor(config) {
789
+ this.collectionReady = false;
790
+ this.collectionName = config?.collectionName || WX_CHAT_HISTORY_COLLECTION;
791
+ this.botId = config?.botId || "default";
792
+ const envId = config?.envId || process.env.TCB_ENV || process.env.CLOUDBASE_ENV;
793
+ if (!envId) {
794
+ throw new Error(
795
+ "[WeChatHistoryManager] envId is required. Set TCB_ENV or CLOUDBASE_ENV environment variable, or pass envId in config."
796
+ );
797
+ }
798
+ this.tcbClient = import_node_sdk.default.init({
799
+ env: envId,
800
+ secretId: config?.secretId,
801
+ secretKey: config?.secretKey,
802
+ sessionToken: config?.token
803
+ });
804
+ }
805
+ static getInstance(config) {
806
+ if (!_WeChatHistoryManager.instance) {
807
+ _WeChatHistoryManager.instance = new _WeChatHistoryManager(config);
808
+ }
809
+ return _WeChatHistoryManager.instance;
810
+ }
811
+ /**
812
+ * Ensure collection exists, create if not
813
+ */
814
+ async ensureCollection() {
815
+ if (this.collectionReady) return;
816
+ try {
817
+ const db = this.tcbClient.database();
818
+ await db.createCollection(this.collectionName);
819
+ this.collectionReady = true;
820
+ } catch (error) {
821
+ if (error?.code === "DATABASE_COLLECTION_ALREADY_EXIST") {
822
+ this.collectionReady = true;
823
+ } else {
824
+ console.error(
825
+ "[WeChatHistoryManager] Failed to create collection:",
826
+ error
827
+ );
828
+ throw error;
829
+ }
830
+ }
831
+ }
832
+ /**
833
+ * Get previous reply from history
834
+ */
835
+ async getPreviousReply(threadId, messageId) {
836
+ await this.ensureCollection();
837
+ const db = this.tcbClient.database();
838
+ const _ = db.command;
839
+ const collection = db.collection(this.collectionName);
840
+ const whereCondition = {
841
+ conversation: _.eq(threadId)
842
+ };
843
+ if (messageId) {
844
+ whereCondition.record_id = _.eq(messageId);
845
+ }
846
+ const result = await collection.where(whereCondition).orderBy("createdAt", "desc").limit(1).get();
847
+ if (result.data && result.data.length > 0) {
848
+ return dataToEntry(result.data[0]);
849
+ }
850
+ return null;
851
+ }
852
+ /**
853
+ * Save record to history
854
+ */
855
+ async saveToHistory(record) {
856
+ await this.ensureCollection();
857
+ const db = this.tcbClient.database();
858
+ const _ = db.command;
859
+ const collection = db.collection(this.collectionName);
860
+ const existing = await collection.where({ record_id: _.eq(record.messageId) }).limit(1).get();
861
+ const data = entryToData({ ...record, botId: record.botId || this.botId });
862
+ if (existing.data && existing.data.length > 0) {
863
+ await collection.where({ record_id: _.eq(record.messageId) }).update(data);
864
+ } else {
865
+ await collection.add(data);
866
+ }
867
+ }
868
+ /**
869
+ * Update record content by messageId
870
+ */
871
+ async updateContent(_threadId, messageId, content) {
872
+ await this.ensureCollection();
873
+ const db = this.tcbClient.database();
874
+ const _ = db.command;
875
+ const collection = db.collection(this.collectionName);
876
+ await collection.where({ record_id: _.eq(messageId) }).update({
877
+ content,
878
+ updatedAt: Date.now()
879
+ });
880
+ }
881
+ };
882
+ var getHistoryManager = WeChatHistoryManager.getInstance;
883
+
884
+ // src/agent.ts
885
+ var import_aiagent_framework2 = require("@cloudbase/aiagent-framework");
886
+ var import_crypto = require("crypto");
887
+ var AITOOLS = import_aiagent_framework2.aitools.AITools;
888
+ var WeChatAgent = class extends import_client2.AbstractAgent {
889
+ constructor(config) {
890
+ super({
891
+ agentId: config.agentId || config.agent.agentId,
892
+ description: config.description || config.agent.description,
893
+ threadId: config.threadId || config.agent.threadId,
894
+ ...config
895
+ });
896
+ this.messageBuffer = "";
897
+ /**
898
+ * Last assembled reply content after run() completes
899
+ * Controller can read this instead of re-assembling from events
900
+ */
901
+ this.lastReply = "";
902
+ /**
903
+ * Whether last run had an error
904
+ */
905
+ this.lastRunHadError = false;
906
+ this.wrappedAgent = config.agent;
907
+ this.wechatConfig = config.wechatConfig;
908
+ this.recommendQuestions = config.recommendQuestions;
909
+ this._historyManager = config.historyManager || WeChatHistoryManager.getInstance();
910
+ const sendMode = config.wechatConfig.sendMode || "local" /* LOCAL */;
911
+ if (sendMode === "aitools" /* AITOOLS */) {
912
+ if (!config.wechatConfig.context) {
913
+ throw new Error("context is required when sendMode is AITOOLS");
914
+ }
915
+ this.aitools = new AITOOLS(config.wechatConfig.context);
916
+ } else {
917
+ this.wechatSender = new WeChatSender(config.wechatConfig);
918
+ }
919
+ this.messageFormatter = config.messageFormatter || ((content) => ({
920
+ toUser: "",
921
+ // Will be set from originMsg
922
+ message: {
923
+ content,
924
+ type: "text" /* TEXT */
925
+ },
926
+ recommendQuestions: this.recommendQuestions
927
+ }));
928
+ this.eventFilter = config.eventFilter || ((event) => event.type === import_client2.EventType.TEXT_MESSAGE_CONTENT);
929
+ }
930
+ /**
931
+ * Get previous reply from history
932
+ * Used for: retry detection, "继续" command
933
+ */
934
+ async getPreviousReply(conversation, recordId) {
935
+ return this._historyManager.getPreviousReply(conversation, recordId);
936
+ }
937
+ /**
938
+ * Update message content in history
939
+ */
940
+ async updateHistoryContent(messageId, content, threadId) {
941
+ await this._historyManager.updateContent(threadId, messageId, content);
942
+ }
943
+ /**
944
+ * Handle unverified account logic (WXSubscription/WXService)
945
+ * Handles "继续" command and 11-second retry
946
+ * Uses existing functions from wechat-message-handler.ts
947
+ * @returns { needSkipAI, replyContent, isEnd }
948
+ */
949
+ async handleUnverifiedChat(params) {
950
+ const { content, conversation, previousReply, callbackData, triggerSrc } = params;
951
+ if (previousReply && previousReply.needAsyncReply) {
952
+ return { needSkipAI: true, replyContent: "", isEnd: true };
953
+ }
954
+ if (content === "continue" || content === "\u7EE7\u7EED") {
955
+ const latest = await this._historyManager.getPreviousReply(conversation);
956
+ let replyContent = "";
957
+ if (!latest) {
958
+ replyContent = "\u672A\u627E\u5230\u76F8\u5173\u56DE\u7B54\uFF0C\u8BF7\u5148\u53D1\u9001\u6D88\u606F";
959
+ } else if (isContinueCommandValid(latest)) {
960
+ replyContent = latest.content || '\u6B63\u5728\u601D\u8003\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u56DE\u590D"\u7EE7\u7EED"';
961
+ } else {
962
+ replyContent = "\u56DE\u7B54\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u6D88\u606F";
963
+ }
964
+ return { needSkipAI: true, replyContent, isEnd: false };
965
+ }
966
+ if (previousReply) {
967
+ const result = await handleWeChatRetry(
968
+ previousReply,
969
+ callbackData,
970
+ triggerSrc
971
+ );
972
+ return {
973
+ needSkipAI: result.shouldSkip,
974
+ replyContent: result.content || "",
975
+ isEnd: false
976
+ };
977
+ }
978
+ return { needSkipAI: false, replyContent: "", isEnd: false };
979
+ }
980
+ /**
981
+ * Run method with WeChat integration
982
+ * Wraps the underlying agent's run() and sends messages to WeChat
983
+ */
984
+ run(input) {
985
+ return new import_rxjs.Observable((subscriber) => {
986
+ this.messageBuffer = "";
987
+ this.lastReply = "";
988
+ this.lastRunHadError = false;
989
+ let errorMessage = "";
990
+ let subscription;
991
+ const replyId = input?.forwardedProps?.replay.id || (0, import_crypto.randomUUID)();
992
+ Promise.all([
993
+ this.saveInputToHistory(input),
994
+ this.saveReplyToHistory(
995
+ {
996
+ id: replyId,
997
+ content: this.lastReply
998
+ },
999
+ input
1000
+ )
1001
+ ]).then(
1002
+ () => {
1003
+ subscription = this.wrappedAgent.run(input).subscribe({
1004
+ next: (event) => {
1005
+ subscriber.next(event);
1006
+ if (event.type === import_client2.EventType.RUN_ERROR) {
1007
+ this.lastRunHadError = true;
1008
+ const errorEvent = event;
1009
+ errorMessage = errorEvent.message || errorEvent.error?.message || "\u5904\u7406\u6D88\u606F\u65F6\u53D1\u751F\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";
1010
+ }
1011
+ this.handleWeChatSending(event, input);
1012
+ },
1013
+ error: (error) => {
1014
+ subscriber.error(error);
1015
+ },
1016
+ complete: () => {
1017
+ this.lastReply = this.lastRunHadError ? errorMessage : this.messageBuffer.trim() || "";
1018
+ if (this.messageBuffer.trim() && !this.lastRunHadError) {
1019
+ this.sendToWeChat(this.messageBuffer, input).catch(
1020
+ console.error
1021
+ );
1022
+ }
1023
+ this.saveReplyToHistory(
1024
+ {
1025
+ id: input?.forwardedProps?.replay.id || (0, import_crypto.randomUUID)(),
1026
+ content: this.lastReply
1027
+ },
1028
+ input
1029
+ ).catch(console.error);
1030
+ subscriber.complete();
1031
+ }
1032
+ });
1033
+ },
1034
+ (e) => {
1035
+ subscriber.error(e);
1036
+ }
1037
+ );
1038
+ return () => {
1039
+ subscription?.unsubscribe();
1040
+ };
1041
+ });
1042
+ }
1043
+ /**
1044
+ * Save input message to history at the start of run()
1045
+ * Only saves if the last message is from user role
1046
+ * Uses msgData from forwardedProps for complete data (similar to dealMsgData)
1047
+ */
1048
+ async saveInputToHistory(input) {
1049
+ const messages = input.messages;
1050
+ if (!messages || messages.length === 0) return;
1051
+ const lastMessage = messages[messages.length - 1];
1052
+ if (lastMessage.role !== "user") return;
1053
+ const { threadId, runId } = input;
1054
+ const msgData = input.forwardedProps?.msgData;
1055
+ const messageId = msgData?.recordId || lastMessage.id || lastMessage.messageId || (0, import_crypto.randomUUID)();
1056
+ const rawContent = lastMessage.content;
1057
+ const content = typeof rawContent === "string" ? rawContent : Array.isArray(rawContent) ? rawContent.filter((c) => c.type === "text").map((c) => c.text).join("") : "";
1058
+ if (threadId && content) {
1059
+ await this._historyManager.saveToHistory({
1060
+ messageId,
1061
+ role: "user",
1062
+ content,
1063
+ threadId,
1064
+ runId,
1065
+ createdAt: msgData?.createdAt || Date.now(),
1066
+ // Additional fields from msgData (similar to dealMsgData)
1067
+ botId: msgData?.botId,
1068
+ needAsyncReply: msgData?.needAsyncReply,
1069
+ type: msgData?.type,
1070
+ metadata: {
1071
+ sender: msgData?.sender,
1072
+ triggerSrc: msgData?.triggerSrc,
1073
+ originMsg: msgData?.originMsg,
1074
+ reply: msgData?.reply,
1075
+ recommendQuestions: msgData?.recommendQuestions
1076
+ }
1077
+ });
1078
+ }
1079
+ }
1080
+ /**
1081
+ * Handle WeChat message sending based on events
1082
+ */
1083
+ handleWeChatSending(event, input) {
1084
+ if (event.type === import_client2.EventType.RUN_ERROR) {
1085
+ const errorEvent = event;
1086
+ const errorMessage = errorEvent.message || errorEvent.error?.message || "\u5904\u7406\u6D88\u606F\u65F6\u53D1\u751F\u9519\u8BEF\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5";
1087
+ this.messageBuffer = "";
1088
+ this.sendToWeChat(errorMessage, input).catch(console.error);
1089
+ return;
1090
+ }
1091
+ if (!this.eventFilter(event)) {
1092
+ return;
1093
+ }
1094
+ switch (event.type) {
1095
+ case import_client2.EventType.TEXT_MESSAGE_CONTENT:
1096
+ const content = event.delta || event.content || "";
1097
+ this.messageBuffer += content;
1098
+ break;
1099
+ case import_client2.EventType.TEXT_MESSAGE_END:
1100
+ if (this.messageBuffer.trim()) {
1101
+ this.sendToWeChat(this.messageBuffer, input).catch(console.error);
1102
+ this.messageBuffer = "";
1103
+ }
1104
+ break;
1105
+ }
1106
+ }
1107
+ /**
1108
+ * Send message to WeChat and save to history
1109
+ * Only sends in async mode (needAsyncReply=true)
1110
+ * For sync mode, message is returned via HTTP response by controller
1111
+ */
1112
+ async sendToWeChat(content, input) {
1113
+ try {
1114
+ const needAsyncReply2 = input.forwardedProps?.replay.needAsyncReply ?? true;
1115
+ if (needAsyncReply2) {
1116
+ const sendMode = this.wechatConfig.sendMode || "aitools" /* AITOOLS */;
1117
+ if (sendMode === "aitools" /* AITOOLS */) {
1118
+ await this.sendViaAITools(content, input);
1119
+ } else {
1120
+ await this.sendViaLocalSender(content, input);
1121
+ }
1122
+ }
1123
+ } catch (error) {
1124
+ console.error("Failed to send message to WeChat:", error);
1125
+ }
1126
+ }
1127
+ /**
1128
+ * Save reply content to history
1129
+ * Uses replay metadata from forwardedProps for complete data (similar to dealMsgData)
1130
+ */
1131
+ async saveReplyToHistory(reply, input) {
1132
+ const { threadId, runId } = input;
1133
+ const replay = input.forwardedProps?.replay;
1134
+ const msgData = input.forwardedProps?.msgData;
1135
+ const messageId = reply.id;
1136
+ if (threadId && messageId) {
1137
+ await this._historyManager.saveToHistory({
1138
+ id: messageId,
1139
+ messageId,
1140
+ role: "assistant",
1141
+ content: reply.content,
1142
+ threadId,
1143
+ runId,
1144
+ createdAt: Date.now(),
1145
+ // Additional fields from replay/msgData (similar to dealMsgData replyMsgData)
1146
+ botId: replay?.botId || msgData?.botId,
1147
+ needAsyncReply: replay?.needAsyncReply,
1148
+ type: replay?.type || "text",
1149
+ metadata: {
1150
+ sender: replay?.sender || msgData?.sender,
1151
+ triggerSrc: replay?.triggerSrc || msgData?.triggerSrc,
1152
+ // For assistant, reply field is empty, replyTo points to user message
1153
+ replyTo: replay?.replyTo || msgData?.recordId,
1154
+ originMsg: replay?.originMsg,
1155
+ reply: replay?.reply,
1156
+ recommendQuestions: replay?.recommendQuestions
1157
+ }
1158
+ });
1159
+ }
1160
+ }
1161
+ /**
1162
+ * Send message via aitools SDK (for cloud function environment)
1163
+ */
1164
+ async sendViaAITools(content, input) {
1165
+ if (!this.aitools) {
1166
+ throw new Error("aitools is not initialized");
1167
+ }
1168
+ const wxSendmessageInput = input.forwardedProps?.wxSendmessageInput;
1169
+ if (!wxSendmessageInput) {
1170
+ console.warn(
1171
+ "wxSendmessageInput not found in forwardedProps, skipping aitools send"
1172
+ );
1173
+ return;
1174
+ }
1175
+ const toWxMsgData = this.processReplyMsg(wxSendmessageInput, content);
1176
+ if (!toWxMsgData) {
1177
+ console.warn("Failed to process reply message, skipping send");
1178
+ return;
1179
+ }
1180
+ const triggerSrc = wxSendmessageInput.triggerSrc || this.wechatConfig.platform;
1181
+ await this.aitools.sendWxClientMessage(
1182
+ this.agentId || "agent",
1183
+ triggerSrc,
1184
+ {
1185
+ msgType: toWxMsgData.msgType,
1186
+ touser: toWxMsgData.toUserName,
1187
+ text: {
1188
+ content: toWxMsgData.content
1189
+ },
1190
+ openKfId: toWxMsgData.openKfId,
1191
+ msgId: toWxMsgData.msgId || ""
1192
+ }
1193
+ );
1194
+ }
1195
+ /**
1196
+ * Format reply message for WeChat HTTP response (sync mode)
1197
+ * Public method for controller to use
1198
+ */
1199
+ formatReplyMessage(callbackData, triggerSrc, content) {
1200
+ return formatWeChatReplyMessage(callbackData, triggerSrc, content);
1201
+ }
1202
+ /**
1203
+ * Process reply message to get correct format for different WeChat platforms
1204
+ * Based on chat_wx.service.ts processReplyMsg implementation
1205
+ */
1206
+ processReplyMsg(wxSendMessageInput, content) {
1207
+ const triggerSrc = wxSendMessageInput.triggerSrc || this.wechatConfig.platform;
1208
+ const callbackData = wxSendMessageInput.callbackData;
1209
+ return formatWeChatReplyMessage(callbackData, triggerSrc, content);
1210
+ }
1211
+ /**
1212
+ * Send message via local WeChatSender (for local development)
1213
+ */
1214
+ async sendViaLocalSender(content, input) {
1215
+ if (!this.wechatSender) {
1216
+ throw new Error("wechatSender is not initialized");
1217
+ }
1218
+ const messageOptions = this.messageFormatter(content, {
1219
+ type: import_client2.EventType.TEXT_MESSAGE_CONTENT,
1220
+ content
1221
+ });
1222
+ const originMsg = input.forwardedProps?.originMsg;
1223
+ await this.wechatSender.send(messageOptions, originMsg);
1224
+ }
1225
+ };
1226
+ // Annotate the CommonJS export names for ESM import in node:
1227
+ 0 && (module.exports = {
1228
+ MessageFormatter,
1229
+ MessageType,
1230
+ PlatformRouter,
1231
+ SUPPORTED_MSG_TYPES,
1232
+ TokenManager,
1233
+ WeChatAgent,
1234
+ WeChatHistoryManager,
1235
+ WeChatPlatform,
1236
+ WeChatSendMode,
1237
+ WeChatSender,
1238
+ createWxMessageHandler,
1239
+ dealMsgData,
1240
+ extractConversation,
1241
+ extractMsgId,
1242
+ extractMsgType,
1243
+ extractSender,
1244
+ extractTextContent,
1245
+ extractTimestamp,
1246
+ extractTriggerSrc,
1247
+ extractVoiceMediaId,
1248
+ formatWeChatReplyMessage,
1249
+ generateRecordId,
1250
+ getHistoryManager,
1251
+ getWxChatContent,
1252
+ handleWeChatRetry,
1253
+ isContinueCommandValid,
1254
+ needAsyncReply,
1255
+ validateMessageType
1256
+ });
1257
+ //# sourceMappingURL=index.js.map