@cloudbase/agent-adapter-wx 0.0.19 → 0.0.20

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.d.mts CHANGED
@@ -384,11 +384,6 @@ interface WeChatAgentConfig extends AgentConfig {
384
384
  * Converts agent output to WeChat message format
385
385
  */
386
386
  messageFormatter?: (content: string, event: BaseEvent) => SendMessageOptions;
387
- /**
388
- * Optional: Filter which events should trigger WeChat messages
389
- * Default: only TEXT_MESSAGE_CONTENT events
390
- */
391
- eventFilter?: (event: BaseEvent) => boolean;
392
387
  /**
393
388
  * Optional: Recommended questions to show after reply
394
389
  */
@@ -468,7 +463,6 @@ declare class WeChatAgent extends AbstractAgent {
468
463
  private wechatConfig;
469
464
  private _historyManager;
470
465
  private messageFormatter;
471
- private eventFilter;
472
466
  private messageBuffer;
473
467
  private recommendQuestions?;
474
468
  aitools?: aitools.AITools;
package/dist/index.d.ts CHANGED
@@ -384,11 +384,6 @@ interface WeChatAgentConfig extends AgentConfig {
384
384
  * Converts agent output to WeChat message format
385
385
  */
386
386
  messageFormatter?: (content: string, event: BaseEvent) => SendMessageOptions;
387
- /**
388
- * Optional: Filter which events should trigger WeChat messages
389
- * Default: only TEXT_MESSAGE_CONTENT events
390
- */
391
- eventFilter?: (event: BaseEvent) => boolean;
392
387
  /**
393
388
  * Optional: Recommended questions to show after reply
394
389
  */
@@ -468,7 +463,6 @@ declare class WeChatAgent extends AbstractAgent {
468
463
  private wechatConfig;
469
464
  private _historyManager;
470
465
  private messageFormatter;
471
- private eventFilter;
472
466
  private messageBuffer;
473
467
  private recommendQuestions?;
474
468
  aitools?: aitools.AITools;
package/dist/index.js CHANGED
@@ -939,7 +939,6 @@ var WeChatAgent = class extends import_client2.AbstractAgent {
939
939
  },
940
940
  recommendQuestions: this.recommendQuestions
941
941
  }));
942
- this.eventFilter = config.eventFilter || ((event) => event.type === import_client2.EventType.TEXT_MESSAGE_CONTENT);
943
942
  }
944
943
  /**
945
944
  * Get previous reply from history
@@ -1102,20 +1101,12 @@ var WeChatAgent = class extends import_client2.AbstractAgent {
1102
1101
  this.sendToWeChat(errorMessage, input).catch(console.error);
1103
1102
  return;
1104
1103
  }
1105
- if (!this.eventFilter(event)) {
1106
- return;
1107
- }
1108
1104
  switch (event.type) {
1105
+ case import_client2.EventType.TEXT_MESSAGE_CHUNK:
1109
1106
  case import_client2.EventType.TEXT_MESSAGE_CONTENT:
1110
1107
  const content = event.delta || event.content || "";
1111
1108
  this.messageBuffer += content;
1112
1109
  break;
1113
- case import_client2.EventType.TEXT_MESSAGE_END:
1114
- if (this.messageBuffer.trim()) {
1115
- this.sendToWeChat(this.messageBuffer, input).catch(console.error);
1116
- this.messageBuffer = "";
1117
- }
1118
- break;
1119
1110
  }
1120
1111
  }
1121
1112
  /**
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/wechat-message-handler.ts","../src/server/wx.controller.ts","../src/token-manager.ts","../src/message-formatter.ts","../src/platform-router.ts","../src/wechat-sender.ts","../src/agent.ts","../src/wechat-history-manager.ts"],"sourcesContent":["/**\n * @cloudbase/agent-adapter-wx\n * WeChat adapter for AG-Kit - Forward LLM messages to WeChat platforms\n */\n\nexport { createWxMessageHandler } from \"./server/wx.controller\";\n\n// Main exports\nexport { WeChatSender } from \"./wechat-sender\";\nexport { WeChatAgent } from \"./agent\";\nexport { TokenManager } from \"./token-manager\";\nexport { MessageFormatter } from \"./message-formatter\";\nexport { PlatformRouter } from \"./platform-router\";\nexport {\n WeChatHistoryManager,\n getHistoryManager,\n} from \"./wechat-history-manager\";\nexport type {\n HistoryEntry,\n HistoryManagerConfig,\n} from \"./wechat-history-manager\";\n\n// Message handler exports - 消息处理工具\nexport {\n // Validation\n validateMessageType,\n extractMsgType,\n extractTriggerSrc,\n // Content extraction\n extractTextContent,\n extractVoiceMediaId,\n getWxChatContent,\n // Sender & conversation\n extractSender,\n extractConversation,\n // Record ID\n generateRecordId,\n extractMsgId,\n extractTimestamp,\n // Async reply\n needAsyncReply,\n // Core message processing\n dealMsgData,\n // Reply message formatting\n formatWeChatReplyMessage,\n // WeChat retry\n handleWeChatRetry,\n isContinueCommandValid,\n // Constants\n SUPPORTED_MSG_TYPES,\n} from \"./wechat-message-handler\";\n\n// Type exports\nexport { WeChatPlatform, WeChatSendMode, MessageType } from \"./types\";\n\nexport type {\n WeChatConfig,\n MessageContent,\n SendMessageOptions,\n AccessTokenResponse,\n WeChatAPIResponse,\n TokenCacheEntry,\n WeChatMessage,\n} from \"./types\";\n\nexport type { WeChatAgentConfig } from \"./agent\";\n\n// Message handler types - 消息处理类型\nexport type {\n WeChatCommonInput,\n WeChatWorkCommonInput,\n WeChatTriggerSrc,\n SupportedMsgType,\n ChatHistoryRecord,\n ProcessedMsgData,\n MessageValidationResult,\n VoiceMessageHandler,\n WeChatReplyMessage,\n} from \"./wechat-message-handler\";\n","/**\n * WeChat platform types\n */\nexport enum WeChatPlatform {\n /** 企业微信客服 */\n CUSTOM_SERVICE = \"WXCustomerService\",\n /** 微信小程序 */\n MINI_APP = \"WXMiniapp\",\n /** 微信服务号 */\n SERVICE = \"WXService\",\n /** 微信订阅号 */\n SUBSCRIPTION = \"WXSubscription\",\n}\n\n/**\n * Message types\n */\nexport enum MessageType {\n TEXT = \"text\",\n IMAGE = \"image\",\n EVENT = \"event\",\n VOICE = \"voice\",\n}\n\n/**\n * WeChat send mode\n */\nexport enum WeChatSendMode {\n /** Use local WeChatSender (for local development) */\n LOCAL = \"local\",\n /** Use aitools SDK (for cloud function environment) */\n AITOOLS = \"aitools\",\n}\n\nexport interface WeChatConfig {\n platform: WeChatPlatform;\n appId: string;\n appSecret: string;\n openKfId?: string;\n tokenCacheTTL?: number;\n sendMode?: WeChatSendMode;\n context?: any;\n}\n\nexport interface MessageContent {\n content: string;\n type: MessageType;\n imageUrl?: string;\n}\n\nexport interface SendMessageOptions {\n toUser: string;\n message: MessageContent;\n recommendQuestions?: string[];\n msgId?: string;\n}\n\nexport interface AccessTokenResponse {\n access_token: string;\n expires_in: number;\n errcode?: number;\n errmsg?: string;\n}\n\nexport interface WeChatAPIResponse {\n errcode: number;\n errmsg: string;\n [key: string]: any;\n}\n\nexport interface TokenCacheEntry {\n accessToken: string;\n expiresAt: number;\n}\n\nexport interface WeChatMessage {\n touser: string;\n msgtype: string;\n text?: { content: string };\n image?: { media_id?: string; pic_url?: string };\n open_kfid?: string;\n msgid?: string;\n}\n","/**\n * WeChat Message Handler - 微信消息处理工具\n *\n * 处理调用模型之前的所有逻辑:\n * - 消息类型校验\n * - 内容提取\n * - 消息数据生成\n * - 发送者/会话提取\n */\n\nimport { WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\nimport { HistoryEntry } from \"./wechat-history-manager\";\nimport { WeChatPlatform } from \"./types\";\n\n// ============================================================================\n// Types - 类型定义\n// ============================================================================\n\n/**\n * WeChat message input - 微信公众号/服务号/小程序消息\n */\nexport interface WeChatCommonInput {\n toUserName: string;\n fromUserName: string;\n createTime: number;\n msgType: string;\n msgId: string;\n content?: string; // 文本消息\n mediaId?: string; // 语音消息\n recognition?: string; // 语音识别结果\n}\n\n/**\n * WeChat Work customer service message input - 企业微信客服消息\n */\nexport interface WeChatWorkCommonInput {\n toUserName?: string;\n externalUserId: string;\n openKfId: string;\n msgType: string;\n msgId: string;\n sendTime: number;\n text?: { content: string };\n voice?: { mediaId: string };\n}\n\n/**\n * Supported trigger sources - 支持的触发源\n */\nexport type WeChatTriggerSrc =\n | WeChatPlatform.SUBSCRIPTION // 微信订阅号\n | WeChatPlatform.SERVICE // 微信服务号\n | WeChatPlatform.MINI_APP // 微信小程序\n | WeChatPlatform.CUSTOM_SERVICE; // 企业微信客服\n\n/**\n * Supported message types - 支持的消息类型\n */\nexport const SUPPORTED_MSG_TYPES = [\"text\", \"voice\"] as const;\nexport type SupportedMsgType = (typeof SUPPORTED_MSG_TYPES)[number];\n\n/**\n * Chat history record - 聊天历史记录\n */\nexport interface ChatHistoryRecord {\n recordId: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n // Optional fields\n image?: string;\n status?: string;\n traceId?: string;\n asyncReply?: string;\n replyTo?: string;\n event?: string;\n}\n\n/**\n * Processed message data - 处理后的消息数据\n */\nexport interface ProcessedMsgData {\n msgData: ChatHistoryRecord;\n replyMsgData: ChatHistoryRecord;\n}\n\n/**\n * Message validation result - 消息校验结果\n */\nexport interface MessageValidationResult {\n isValid: boolean;\n skipAI: boolean;\n errorMessage?: string;\n userErrorMessage?: string;\n}\n\n/**\n * Voice message handler type - 语音消息处理器类型\n */\nexport type VoiceMessageHandler = (\n botId: string,\n triggerSrc: string,\n mediaId: string\n) => Promise<{ content: string } | null>;\n\n// ============================================================================\n// Message Validation - 消息校验\n// ============================================================================\n\n/**\n * Validate message type - 校验消息类型\n */\nexport function validateMessageType(msgType: string): MessageValidationResult {\n if (SUPPORTED_MSG_TYPES.includes(msgType as SupportedMsgType)) {\n return { isValid: true, skipAI: false };\n }\n return {\n isValid: false,\n skipAI: true,\n errorMessage: `无法处理的消息类型:${msgType}`,\n userErrorMessage: \"抱歉暂时无法处理这个类型的消息\",\n };\n}\n\n/**\n * Extract message type from origin message - 从原始消息提取消息类型\n */\nexport function extractMsgType(originMsg: any): string {\n return originMsg.msgType || originMsg.MsgType || \"text\";\n}\n\n/**\n * Extract trigger source from origin message - 从原始消息提取触发源\n */\nexport function extractTriggerSrc(\n originMsg: any,\n defaultSrc: WeChatTriggerSrc = WeChatPlatform.SERVICE\n): WeChatTriggerSrc {\n return originMsg.triggerSrc || defaultSrc;\n}\n\n// ============================================================================\n// Content Extraction - 内容提取\n// ============================================================================\n\n/**\n * Extract text content from WeChat message - 从微信消息提取文本内容\n */\nexport function extractTextContent(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.Content || originMsg.content || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.text?.content || \"\";\n }\n return \"\";\n}\n\n/**\n * Extract voice media ID from WeChat message - 从微信消息提取语音媒体ID\n */\nexport function extractVoiceMediaId(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [WeChatPlatform.SUBSCRIPTION, WeChatPlatform.SERVICE].includes(triggerSrc)\n ) {\n return originMsg.MediaId || originMsg.mediaId || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.voice?.mediaId || \"\";\n }\n return \"\";\n}\n\n/**\n * Get content from WeChat message (text or voice) - 获取微信消息内容\n */\nexport async function getWxChatContent(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc,\n voiceMessageHandler?: VoiceMessageHandler,\n botId?: string\n): Promise<string> {\n const msgType = extractMsgType(originMsg);\n\n // Text message\n if (msgType === \"text\") {\n return extractTextContent(originMsg, triggerSrc);\n }\n\n // Voice message\n if (msgType === \"voice\") {\n const mediaId = extractVoiceMediaId(originMsg, triggerSrc);\n if (voiceMessageHandler && mediaId && botId) {\n const result = await voiceMessageHandler(botId, triggerSrc, mediaId);\n return result?.content || \"\";\n }\n }\n\n return \"\";\n}\n\n// ============================================================================\n// Sender & Conversation Extraction - 发送者和会话提取\n// ============================================================================\n\n/**\n * Extract sender from origin message - 从原始消息提取发送者\n */\nexport function extractSender(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.FromUserName || originMsg.fromUserName || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.externalUserId || \"\";\n }\n return \"\";\n}\n\n/**\n * Extract conversation ID from origin message - 从原始消息提取会话ID\n */\nexport function extractConversation(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.FromUserName || originMsg.fromUserName || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.externalUserId || \"\";\n }\n return \"\";\n}\n\n// ============================================================================\n// Record ID Generation - 记录ID生成\n// ============================================================================\n\n/**\n * Generate record ID - 生成记录ID\n */\nexport function generateRecordId(\n triggerSrc: WeChatTriggerSrc,\n msgId: string,\n timestamp: number\n): string {\n return `${triggerSrc}${msgId}${timestamp}`;\n}\n\n/**\n * Extract message ID from origin message - 从原始消息提取消息ID\n */\nexport function extractMsgId(originMsg: any): string {\n return originMsg.msgId || originMsg.MsgId || Date.now().toString();\n}\n\n/**\n * Extract timestamp from origin message - 从原始消息提取时间戳\n */\nexport function extractTimestamp(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): number {\n if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.sendTime || Math.floor(Date.now() / 1000);\n }\n return (\n originMsg.createTime ||\n originMsg.CreateTime ||\n Math.floor(Date.now() / 1000)\n );\n}\n\n// ============================================================================\n// Async Reply Logic - 异步回复逻辑\n// ============================================================================\n\n/**\n * Determine if async reply is needed - 判断是否需要异步回复\n */\nexport function needAsyncReply(\n triggerSrc: WeChatTriggerSrc,\n wxVerify: boolean\n): boolean {\n // 小程序和企业微信客服始终异步\n if (\n [WeChatPlatform.MINI_APP, WeChatPlatform.CUSTOM_SERVICE].includes(\n triggerSrc\n )\n ) {\n return true;\n }\n // 公众号/服务号根据认证状态决定\n return wxVerify;\n}\n\n// ============================================================================\n// Reply Message Formatting - 回复消息格式化\n// ============================================================================\n\n/**\n * WeChat reply message structure\n */\nexport interface WeChatReplyMessage {\n toUserName: string;\n fromUserName: string;\n createTime: number;\n msgType: string;\n content: string;\n msgId: string;\n openKfId?: string;\n}\n\n/**\n * Format reply message for WeChat\n * Used for both sync HTTP response and async aitools sending\n */\nexport function formatWeChatReplyMessage(\n callbackData: any,\n triggerSrc: string,\n content: string\n): WeChatReplyMessage {\n const createTime = Math.floor(Date.now() / 1000);\n const finalContent = content || \"抱歉暂时无法处理这个类型的消息\";\n\n // WeChat Work Customer Service\n if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return {\n toUserName: callbackData.externalUserId || callbackData.fromUserName,\n fromUserName: callbackData.openKfId,\n openKfId: callbackData.openKfId,\n createTime,\n msgType: \"text\",\n content: finalContent,\n msgId: callbackData.msgId,\n };\n }\n\n // WeChat Official Account / Service Account / Mini Program\n return {\n toUserName: callbackData.fromUserName || callbackData.FromUserName,\n fromUserName: callbackData.toUserName || callbackData.ToUserName,\n createTime,\n msgType: \"text\",\n content: finalContent,\n msgId: callbackData.msgId,\n };\n}\n\n// ============================================================================\n// Deal Message Data - 消息数据处理(核心方法)\n// ============================================================================\n\n/**\n * Deal message data - 处理微信消息,生成 msgData 和 replyMsgData\n * 完整实现原 chat_wx.service.ts 中的 dealMsgData 逻辑\n */\nexport function dealMsgData(\n originMsg: WxSendMessageInput[\"callbackData\"],\n triggerSrc: WeChatTriggerSrc,\n wxVerify: boolean,\n botId: string\n): ProcessedMsgData {\n const baseMsgData = {\n type: \"text\",\n triggerSrc: triggerSrc,\n botId: botId,\n recommendQuestions: [] as string[],\n content: \"\",\n originMsg: \"\",\n createdAt: Date.now(),\n };\n\n const sender = extractSender(originMsg, triggerSrc);\n const conversation = extractConversation(originMsg, triggerSrc);\n const msgId = extractMsgId(originMsg);\n const timestamp = extractTimestamp(originMsg, triggerSrc);\n const recordIdBase = generateRecordId(triggerSrc, msgId, timestamp);\n const asyncReply = needAsyncReply(triggerSrc, wxVerify);\n const msgType = extractMsgType(originMsg);\n\n return {\n msgData: {\n ...baseMsgData,\n recordId: `user-${recordIdBase}`,\n role: \"user\" as const,\n sender: sender,\n conversation: conversation,\n type: msgType,\n needAsyncReply: asyncReply,\n reply: recordIdBase,\n originMsg: JSON.stringify(originMsg),\n },\n replyMsgData: {\n ...baseMsgData,\n recordId: recordIdBase,\n role: \"assistant\" as const,\n sender: sender,\n conversation: conversation,\n type: \"text\",\n needAsyncReply: asyncReply,\n reply: \"\",\n originMsg: JSON.stringify({}),\n },\n };\n}\n\n// ============================================================================\n// WeChat Retry Logic - 微信重试逻辑\n// ============================================================================\n\n/**\n * Handle WeChat retry for unverified accounts (11-second rule)\n * 处理未认证账号的微信重试逻辑(11秒规则)\n */\nexport async function handleWeChatRetry(\n previousReply: HistoryEntry | null,\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): Promise<{ shouldSkip: boolean; content?: string }> {\n if (!previousReply) {\n return { shouldSkip: false };\n }\n\n const timestamp = extractTimestamp(originMsg, triggerSrc);\n const deltaTime = Date.now() - timestamp * 1000;\n\n // If already has content, return it\n if (previousReply.content) {\n return {\n shouldSkip: true,\n content: previousReply.content,\n };\n }\n\n // If more than 11 seconds, return status message\n if (deltaTime > 11 * 1000) {\n return {\n shouldSkip: true,\n content: '思考中,请稍后回复 \"继续\" 来获取回答内容',\n };\n }\n\n // Less than 11 seconds, sleep 5s to timeout (WeChat will retry)\n await new Promise((resolve) => setTimeout(resolve, 5000));\n return { shouldSkip: true };\n}\n\n/**\n * Check if \"继续\" command is within 5-minute timeout\n * 检查\"继续\"命令是否在5分钟超时内\n */\nexport function isContinueCommandValid(\n previousReply: HistoryEntry | null\n): boolean {\n if (!previousReply) {\n return false;\n }\n const fiveMinutes = 5 * 60 * 1000;\n return Date.now() - previousReply.createdAt < fiveMinutes;\n}\n","/**\n * WeChat Message Controller\n * Using @cloudbase/agent-adapter-wx for message processing\n * Directly using sendMessageAGUI handler from @cloudbase/agent-server\n */\n\nimport type { Request, Response } from \"express\";\nimport {\n validateMessageType,\n extractMsgType,\n getWxChatContent,\n dealMsgData,\n formatWeChatReplyMessage,\n VoiceMessageHandler,\n WeChatTriggerSrc,\n} from \"../wechat-message-handler\";\nimport { WeChatAgent } from \"../agent\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { agui } from \"@cloudbase/agent-server\";\nimport type { Logger } from \"@cloudbase/agent-shared\";\nimport { noopLogger } from \"@cloudbase/agent-shared\";\nimport { EventType } from \"@ag-ui/client\";\nexport {\n type Logger,\n type LogFn,\n noopLogger,\n createConsoleLogger,\n} from \"@cloudbase/agent-shared\";\n\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport { utils, WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\n\n/**\n * Agent creator function return type\n */\ninterface AgentCreatorResult {\n agent: AbstractAgent | WeChatAgent | { toAGUIAgent(): AbstractAgent };\n cleanup?: () => void;\n}\n\n/**\n * Agent creator function type\n */\ntype AgentCreator = (params: {\n request: Request;\n options?: { agentId: string };\n}) => AgentCreatorResult | Promise<AgentCreatorResult>;\n\n/**\n * Handler options\n */\ninterface WxMessageHandlerOptions {\n logger?: Logger;\n}\n\n/**\n * Extract service name from hostname by finding version number pattern\n * e.g., \"my-service-123456\" -> \"my-service\"\n */\nfunction getServiceNameFromHostname(hostname: string): string {\n const parts = hostname.split(\"-\");\n // Find the last part that is purely numeric (version number)\n // Use reverse loop for ES2015 compatibility (instead of findLastIndex)\n let versionIdx = -1;\n for (let i = parts.length - 1; i >= 0; i--) {\n if (/^\\d+$/.test(parts[i])) {\n versionIdx = i;\n break;\n }\n }\n return versionIdx > 0 ? parts.slice(0, versionIdx).join(\"-\") : hostname;\n}\n\n/**\n * Get bot ID from multiple sources\n * Priority: SCF_FUNCTIONNAME > URL (parsed) > HOSTNAME (parsed) > fallback\n */\nfunction getBotId(url?: string, fallback = \"agent-id\"): string {\n // 1. SCF function name (highest priority)\n if (process.env.SCF_FUNCTIONNAME) {\n return process.env.SCF_FUNCTIONNAME;\n }\n // 2. Parse from URL using utils\n if (url) {\n const parsedBotId = utils.parseBotId(url);\n if (parsedBotId) {\n return parsedBotId;\n }\n }\n // 3. Parse from HOSTNAME\n if (process.env.HOSTNAME) {\n return getServiceNameFromHostname(process.env.HOSTNAME);\n }\n return fallback;\n}\n\n/**\n * Create WeChat message handler\n * Directly using sendMessageAGUI.handler from @cloudbase/agent-server\n * Aligned with chat_wx_v2.service.ts logic\n *\n * @param createAgent - Function to create agent instance (returns { agent, cleanup?})\n * @param options - Handler options\n * @returns Express route handler\n */\nexport function createWxMessageHandler(\n createAgent: AgentCreator,\n options?: WxMessageHandlerOptions\n): (req: Request, res: Response) => Promise<Response> {\n const { logger: parentLogger = noopLogger } = options ?? {};\n const adapterLogger =\n parentLogger.child?.({ component: \"sendWXMessageAGUI\" }) ?? parentLogger;\n\n return async (req: Request, res: Response): Promise<Response> => {\n let cleanup: (() => void) | null = null;\n let agent: WeChatAgent = undefined as any;\n const { callbackData } = utils.transformKeysToCamelCase(req.body);\n const { triggerSrc, wxVerify } = utils.parseWxEnvParam({\n httpContext: {\n headers: req.headers,\n },\n } as any) as {\n triggerSrc: WeChatTriggerSrc;\n wxVerify: boolean;\n };\n const wxSendmessageInput: WxSendMessageInput = {\n callbackData,\n triggerSrc,\n wxVerify,\n };\n const requestId = uuidv4();\n const logger = adapterLogger.child?.({ requestId }) ?? adapterLogger;\n const botId = getBotId(\n `${req.protocol}://${req.get(\"host\")}${req.originalUrl}`,\n \"agent-wx-send-message\"\n );\n try {\n if (!callbackData || !triggerSrc) {\n return res.status(400).json({\n error: \"Bad Request\",\n message: \"Missing required fields: callbackData, triggerSrc\",\n });\n }\n\n logger.info?.(\"[WX] Received message:\", { triggerSrc, wxVerify, botId });\n\n // 1. Create agent instance first (needed for history and voice handling)\n const { agent: unknownAgent, cleanup: agentCleanup } =\n await Promise.resolve(\n createAgent({ request: req, options: { agentId: botId } })\n );\n cleanup = agentCleanup ?? null;\n agent = (\n \"toAGUIAgent\" in unknownAgent\n ? unknownAgent.toAGUIAgent()\n : unknownAgent\n ) as WeChatAgent;\n\n // 2. Process message data (aligned with beforeStream)\n const { msgData, replyMsgData } = dealMsgData(\n callbackData,\n triggerSrc,\n wxVerify,\n botId\n );\n let skipAI = false;\n let isEnd = false;\n\n // 3. Check for duplicate request using msgData.recordId\n // Skip dedup for unverified accounts (WXSubscription/WXService without wxVerify)\n // because they rely on WeChat's 11-second retry mechanism\n const isUnverifiedAccount =\n [\"WXSubscription\", \"WXService\"].includes(triggerSrc) && !wxVerify;\n\n if (!isUnverifiedAccount) {\n // recordId = user-{triggerSrc}{msgId}{timestamp}, conversation = fromUserName\n // This combination uniquely identifies a WeChat callback\n const existingUserMsg = await agent.getPreviousReply(\n msgData.conversation,\n msgData.recordId\n );\n if (existingUserMsg) {\n logger.info?.(\"[WX] Duplicate callback detected, skipping:\", {\n recordId: msgData.recordId,\n conversation: msgData.conversation,\n });\n return res.json({});\n }\n }\n\n // 4. Validate message type\n const msgType = extractMsgType(callbackData);\n const validation = validateMessageType(msgType);\n\n if (!validation.isValid) {\n skipAI = true;\n replyMsgData.content =\n validation.userErrorMessage || \"暂不支持该消息类型\";\n }\n\n // 5. Initialize history and check previous reply (for retry logic)\n const previousReply = await agent.getPreviousReply(\n replyMsgData.conversation,\n replyMsgData.recordId\n );\n\n // 6. Extract content using package utility (ASYNC)\n const voiceHandler: VoiceMessageHandler = async (\n vBotId: string,\n vTriggerSrc: string,\n mediaId: string\n ) => {\n try {\n const result = await agent?.aitools?.getWxMediaContent(\n vBotId,\n vTriggerSrc,\n mediaId\n );\n\n return result || null;\n } catch {\n return null;\n }\n };\n\n const content = await getWxChatContent(\n callbackData,\n triggerSrc,\n voiceHandler,\n botId\n );\n\n // 7. Handle unverified account logic (WXSubscription/WXService only)\n if (\n [\"WXSubscription\", \"WXService\"].includes(triggerSrc) &&\n !wxVerify &&\n !skipAI\n ) {\n const result = await agent.handleUnverifiedChat({\n content,\n conversation: replyMsgData.conversation,\n previousReply,\n callbackData,\n triggerSrc,\n });\n skipAI = result.needSkipAI;\n isEnd = result.isEnd;\n if (result.replyContent) replyMsgData.content = result.replyContent;\n }\n\n // 8. Early return: async reply already sent\n if (isEnd) {\n return res.json({});\n }\n\n // 9. Early return: empty content\n if (!content && !skipAI) {\n logger.warn?.(\"[WX] Empty content\");\n return res.json(\n formatWeChatReplyMessage(callbackData, triggerSrc, \"无法识别消息内容\")\n );\n }\n\n // 10. Early return: skipAI\n if (skipAI) {\n logger.info?.(\"[WX] Skipping AI\");\n return res.json(\n formatWeChatReplyMessage(\n callbackData,\n triggerSrc,\n replyMsgData.content\n )\n );\n }\n\n // 11. Prepare input for sendMessageAGUI.handler\n // History is auto-managed by adapter.run():\n // - Input message saved at start\n // - Reply saved at complete\n logger.info?.(\"[WX] Processing:\", content.substring(0, 100));\n const input = {\n messages: [\n {\n id: msgData.recordId,\n role: \"user\" as const,\n content,\n },\n ],\n state: undefined,\n threadId: msgData.conversation,\n runId: uuidv4(),\n tools: [],\n context: [],\n forwardedProps: {\n wxSendmessageInput,\n // Pass full msgData for history storage\n msgData: msgData,\n // Pass replay info with replyMsgData for assistant history\n replay: {\n id: replyMsgData.recordId,\n ...replyMsgData,\n },\n },\n };\n\n // 12. Call agent - WeChatAgentAdapter.run() handles:\n // - Message assembly (both modes)\n // - Message sending (async mode only)\n // - History saving (both modes)\n // - Error handling (async mode: sends error message)\n const events = agui.sendMessageAGUI.handler(input, agent);\n\n // 13. Consume events to trigger adapter processing\n for await (const event of events) {\n if (event.type === EventType.RUN_ERROR) {\n logger.error?.(\n \"[WX] Agent error:\",\n (event as any).error || (event as any).message\n );\n }\n }\n logger.info?.(\"[WX] Processing complete\");\n\n // 14. Return response - get assembled reply from agent\n if (replyMsgData.needAsyncReply) {\n // Async mode: message already sent by adapter\n return res.json({});\n }\n // Sync mode: get assembled reply from agent and return via HTTP\n const finalContent = agent.lastReply || \"抱歉,无法生成回复\";\n return res.json(\n formatWeChatReplyMessage(callbackData, triggerSrc, finalContent)\n );\n } catch (error) {\n logger.error?.(\"[WX] Error processing message:\", error);\n const message = error instanceof Error ? error.message : String(error);\n try {\n if (agent?.aitools?.sendWxClientMessage) {\n const data = formatWeChatReplyMessage(\n callbackData,\n triggerSrc,\n message\n );\n await agent.aitools.sendWxClientMessage(\n agent.agentId || botId,\n triggerSrc,\n {\n msgType: data.msgType,\n touser: data.toUserName,\n text: {\n content: data.content,\n },\n openKfId: data.openKfId,\n msgId: data.msgId,\n }\n );\n }\n } catch (e) {}\n return res.status(500).json({\n error: \"Internal Server Error\",\n message,\n });\n } finally {\n if (cleanup) cleanup();\n }\n };\n}\n","import {\n WeChatConfig,\n WeChatPlatform,\n AccessTokenResponse,\n TokenCacheEntry,\n} from \"./types\";\n\n/**\n * Token manager for WeChat access tokens\n * Handles token caching and automatic refresh\n */\nexport class TokenManager {\n private cache: Map<string, TokenCacheEntry> = new Map();\n\n /**\n * Get access token (with caching)\n */\n async getAccessToken(config: WeChatConfig): Promise<string> {\n const cacheKey = this.getCacheKey(config);\n const cached = this.cache.get(cacheKey);\n\n // Return cached token if still valid\n if (cached && cached.expiresAt > Date.now()) {\n return cached.accessToken;\n }\n\n // Fetch new token\n const token = await this.fetchAccessToken(config);\n return token;\n }\n\n /**\n * Fetch access token from WeChat API\n */\n private async fetchAccessToken(config: WeChatConfig): Promise<string> {\n const url = this.getTokenUrl(config);\n const response = await fetch(url);\n const data: AccessTokenResponse = await response.json();\n\n if (data.errcode && data.errcode !== 0) {\n throw new Error(`Failed to get access token: ${data.errmsg}`);\n }\n\n // Cache token with 5-minute early expiration\n const cacheKey = this.getCacheKey(config);\n const expiresAt = Date.now() + (data.expires_in - 300) * 1000;\n\n this.cache.set(cacheKey, {\n accessToken: data.access_token,\n expiresAt,\n });\n\n return data.access_token;\n }\n\n /**\n * Get token URL based on platform\n */\n private getTokenUrl(config: WeChatConfig): string {\n if (config.platform === WeChatPlatform.CUSTOM_SERVICE) {\n return `https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${config.appId}&corpsecret=${config.appSecret}`;\n }\n return `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${config.appId}&secret=${config.appSecret}`;\n }\n\n /**\n * Generate cache key\n */\n private getCacheKey(config: WeChatConfig): string {\n return `${config.platform}_${config.appId}`;\n }\n\n /**\n * Clear token cache\n */\n clearCache(config?: WeChatConfig): void {\n if (config) {\n this.cache.delete(this.getCacheKey(config));\n } else {\n this.cache.clear();\n }\n }\n}\n\n","import {\n MessageContent,\n SendMessageOptions,\n WeChatMessage,\n WeChatPlatform,\n MessageType,\n} from \"./types\";\n\n/**\n * Message formatter for different WeChat platforms\n */\nexport class MessageFormatter {\n /**\n * Format message for WeChat API\n */\n formatMessage(\n options: SendMessageOptions,\n platform: WeChatPlatform,\n originMsg?: any\n ): WeChatMessage {\n const { toUser, message, recommendQuestions, msgId } = options;\n let content = message.content;\n\n // Add recommended questions if provided\n if (recommendQuestions && recommendQuestions.length > 0) {\n content = this.withRecommendQuestions(content, recommendQuestions);\n }\n\n const baseMessage: WeChatMessage = {\n touser: toUser,\n msgtype: message.type,\n };\n\n // Format based on message type\n if (message.type === MessageType.TEXT) {\n baseMessage.text = { content };\n } else if (message.type === MessageType.IMAGE && message.imageUrl) {\n baseMessage.image = { pic_url: message.imageUrl };\n }\n\n // Add platform-specific fields\n if (platform === WeChatPlatform.CUSTOM_SERVICE) {\n baseMessage.open_kfid = originMsg?.open_kfid;\n baseMessage.msgid = msgId || originMsg?.msgid;\n }\n\n return baseMessage;\n }\n\n /**\n * Append recommended questions to content\n */\n private withRecommendQuestions(\n content: string,\n questions: string[]\n ): string {\n if (!questions || questions.length === 0) {\n return content;\n }\n return `${content}\\n\\n推荐问题:\\n${questions.join(\"\\n\")}`;\n }\n\n /**\n * Split long message into chunks\n */\n splitLongMessage(content: string, maxLength: number = 2000): string[] {\n if (content.length <= maxLength) {\n return [content];\n }\n\n const chunks: string[] = [];\n let currentChunk = \"\";\n\n const lines = content.split(\"\\n\");\n for (const line of lines) {\n if ((currentChunk + line).length > maxLength) {\n if (currentChunk) {\n chunks.push(currentChunk.trim());\n currentChunk = \"\";\n }\n // Handle lines longer than maxLength\n if (line.length > maxLength) {\n for (let i = 0; i < line.length; i += maxLength) {\n chunks.push(line.substring(i, i + maxLength));\n }\n } else {\n currentChunk = line + \"\\n\";\n }\n } else {\n currentChunk += line + \"\\n\";\n }\n }\n\n if (currentChunk) {\n chunks.push(currentChunk.trim());\n }\n\n return chunks;\n }\n}\n\n","import {\n WeChatConfig,\n WeChatMessage,\n WeChatPlatform,\n WeChatAPIResponse,\n} from \"./types\";\nimport { TokenManager } from \"./token-manager\";\n\n/**\n * Platform router for sending messages to different WeChat platforms\n */\nexport class PlatformRouter {\n private tokenManager: TokenManager;\n\n constructor(tokenManager: TokenManager) {\n this.tokenManager = tokenManager;\n }\n\n /**\n * Send message to WeChat platform\n */\n async send(\n message: WeChatMessage,\n config: WeChatConfig\n ): Promise<WeChatAPIResponse> {\n const accessToken = await this.tokenManager.getAccessToken(config);\n\n switch (config.platform) {\n case WeChatPlatform.CUSTOM_SERVICE:\n return this.sendToCustomService(message, accessToken, config);\n case WeChatPlatform.MINI_APP:\n return this.sendToMiniApp(message, accessToken);\n case WeChatPlatform.SERVICE:\n case WeChatPlatform.SUBSCRIPTION:\n return this.sendToOfficialAccount(message, accessToken);\n default:\n throw new Error(`Unsupported platform: ${config.platform}`);\n }\n }\n\n /**\n * Send to Enterprise WeChat Customer Service\n */\n private async sendToCustomService(\n message: WeChatMessage,\n accessToken: string,\n config: WeChatConfig\n ): Promise<WeChatAPIResponse> {\n const url = `https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n\n /**\n * Send to WeChat Mini Program\n */\n private async sendToMiniApp(\n message: WeChatMessage,\n accessToken: string\n ): Promise<WeChatAPIResponse> {\n const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n\n /**\n * Send to WeChat Official Account (Service/Subscription)\n */\n private async sendToOfficialAccount(\n message: WeChatMessage,\n accessToken: string\n ): Promise<WeChatAPIResponse> {\n const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n}\n\n","import { WeChatConfig, SendMessageOptions, WeChatAPIResponse } from \"./types\";\nimport { TokenManager } from \"./token-manager\";\nimport { MessageFormatter } from \"./message-formatter\";\nimport { PlatformRouter } from \"./platform-router\";\n\n/**\n * Main WeChat sender class\n * Provides a simple API to send LLM messages to WeChat platforms\n */\nexport class WeChatSender {\n private config: WeChatConfig;\n private tokenManager: TokenManager;\n private messageFormatter: MessageFormatter;\n private platformRouter: PlatformRouter;\n\n constructor(config: WeChatConfig) {\n // Validate config\n this.config = config;\n\n // Initialize components\n this.tokenManager = new TokenManager();\n this.messageFormatter = new MessageFormatter();\n this.platformRouter = new PlatformRouter(this.tokenManager);\n }\n\n /**\n * Send a message to WeChat\n */\n async send(\n options: SendMessageOptions,\n originMsg?: any\n ): Promise<WeChatAPIResponse> {\n // Validate options\n const validatedOptions = options;\n\n // Format message\n const message = this.messageFormatter.formatMessage(\n validatedOptions,\n this.config.platform,\n originMsg\n );\n\n // Send message\n const result = await this.platformRouter.send(message, this.config);\n\n // Check for errors\n if (result.errcode !== 0) {\n throw new Error(`Failed to send message: ${result.errmsg}`);\n }\n\n return result;\n }\n\n /**\n * Send multiple messages in batch\n */\n async sendBatch(\n messages: SendMessageOptions[]\n ): Promise<WeChatAPIResponse[]> {\n const results: WeChatAPIResponse[] = [];\n\n for (const message of messages) {\n try {\n const result = await this.send(message);\n results.push(result);\n } catch (error) {\n results.push({\n errcode: -1,\n errmsg: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n return results;\n }\n\n /**\n * Send message asynchronously (fire and forget)\n */\n async sendAsync(options: SendMessageOptions, originMsg?: any): Promise<void> {\n this.send(options, originMsg).catch((error) => {\n console.error(\"Failed to send message:\", error);\n });\n }\n\n /**\n * Clear token cache\n */\n clearCache(): void {\n this.tokenManager.clearCache(this.config);\n }\n\n /**\n * Get current configuration\n */\n getConfig(): WeChatConfig {\n return { ...this.config };\n }\n}\n","import {\n RunAgentInput,\n BaseEvent,\n EventType,\n AbstractAgent,\n AgentConfig,\n} from \"@ag-ui/client\";\nimport { Observable } from \"rxjs\";\nimport { WeChatSender } from \"./wechat-sender\";\nimport {\n WeChatConfig,\n SendMessageOptions,\n MessageType,\n WeChatSendMode,\n} from \"./types\";\nimport { WeChatHistoryManager, HistoryEntry } from \"./wechat-history-manager\";\nimport {\n handleWeChatRetry,\n isContinueCommandValid,\n formatWeChatReplyMessage,\n WeChatReplyMessage,\n} from \"./wechat-message-handler\";\nimport { aitools, WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\nimport { randomUUID } from \"crypto\";\n\nconst AITOOLS = aitools.AITools;\n\n/**\n * Configuration for WeChat Agent Adapter\n */\nexport interface WeChatAgentConfig extends AgentConfig {\n /**\n * The underlying agent to wrap\n */\n agent: AbstractAgent;\n\n /**\n * WeChat configuration\n */\n wechatConfig: WeChatConfig;\n\n /**\n * Optional: Custom message formatter\n * Converts agent output to WeChat message format\n */\n messageFormatter?: (content: string, event: BaseEvent) => SendMessageOptions;\n\n /**\n * Optional: Filter which events should trigger WeChat messages\n * Default: only TEXT_MESSAGE_CONTENT events\n */\n eventFilter?: (event: BaseEvent) => boolean;\n\n /**\n * Optional: Recommended questions to show after reply\n */\n recommendQuestions?: string[];\n\n /**\n * Optional: History manager for saving chat history\n * If not provided, will use singleton instance\n */\n historyManager?: WeChatHistoryManager;\n}\n\ninterface IWxRunAgentInput extends RunAgentInput {\n forwardedProps: {\n wxSendmessageInput: WxSendMessageInput;\n /** Full user message data from dealMsgData */\n msgData?: {\n recordId: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n };\n /** Reply metadata for assistant message */\n replay: {\n id: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n };\n };\n}\n\n/**\n * WeChat Agent Adapter\n *\n * Wraps any AbstractAgent and automatically sends its output to WeChat.\n * All methods are proxied to the underlying agent, with the run() method\n * enhanced to capture messages and send them via WeChat.\n *\n * @example\n * ```typescript\n * const myAgent = new SomeAgent({ ... });\n * const wechatAgent = new WeChatAgentAdapter({\n * agent: myAgent,\n * wechatConfig: {\n * platform: 'work',\n * corpId: 'xxx',\n * corpSecret: 'xxx'\n * }\n * });\n *\n * // Use it like any other agent\n * wechatAgent.run(input).subscribe(event => {\n * // Events are emitted normally\n * // AND automatically sent to WeChat\n * });\n * ```\n */\nexport class WeChatAgent extends AbstractAgent {\n private wrappedAgent: AbstractAgent;\n private wechatSender?: WeChatSender;\n private wechatConfig: WeChatConfig;\n private _historyManager: WeChatHistoryManager;\n private messageFormatter: (\n content: string,\n event: BaseEvent\n ) => SendMessageOptions;\n private eventFilter: (event: BaseEvent) => boolean;\n private messageBuffer: string = \"\";\n private recommendQuestions?: string[];\n public aitools?: aitools.AITools;\n\n constructor(config: WeChatAgentConfig) {\n super({\n agentId: config.agentId || config.agent.agentId,\n description: config.description || config.agent.description,\n threadId: config.threadId || config.agent.threadId,\n ...config,\n });\n\n this.wrappedAgent = config.agent;\n this.wechatConfig = config.wechatConfig;\n this.recommendQuestions = config.recommendQuestions;\n this._historyManager =\n config.historyManager || WeChatHistoryManager.getInstance();\n\n // Initialize sender based on send mode\n const sendMode = config.wechatConfig.sendMode || WeChatSendMode.LOCAL;\n\n if (sendMode === WeChatSendMode.AITOOLS) {\n // Use aitools SDK (for cloud function environment)\n if (!config.wechatConfig.context) {\n throw new Error(\"context is required when sendMode is AITOOLS\");\n }\n this.aitools = new AITOOLS(config.wechatConfig.context);\n } else {\n // Use local WeChatSender (for local development)\n this.wechatSender = new WeChatSender(config.wechatConfig);\n }\n\n // Default message formatter\n this.messageFormatter =\n config.messageFormatter ||\n ((content: string) => ({\n toUser: \"\", // Will be set from originMsg\n message: {\n content: content,\n type: MessageType.TEXT,\n },\n recommendQuestions: this.recommendQuestions,\n }));\n\n // Default event filter: only TEXT_MESSAGE_CONTENT\n this.eventFilter =\n config.eventFilter ||\n ((event: BaseEvent) => event.type === EventType.TEXT_MESSAGE_CONTENT);\n }\n\n /**\n * Last assembled reply content after run() completes\n * Controller can read this instead of re-assembling from events\n */\n public lastReply: string = \"\";\n\n /**\n * Whether last run had an error\n */\n public lastRunHadError: boolean = false;\n\n /**\n * Get previous reply from history\n * Used for: retry detection, \"继续\" command\n */\n async getPreviousReply(\n conversation: string,\n recordId?: string | null\n ): Promise<HistoryEntry | null> {\n return this._historyManager.getPreviousReply(conversation, recordId);\n }\n\n /**\n * Update message content in history\n */\n async updateHistoryContent(\n messageId: string,\n content: string,\n threadId: string\n ): Promise<void> {\n await this._historyManager.updateContent(threadId, messageId, content);\n }\n\n /**\n * Handle unverified account logic (WXSubscription/WXService)\n * Handles \"继续\" command and 11-second retry\n * Uses existing functions from wechat-message-handler.ts\n * @returns { needSkipAI, replyContent, isEnd }\n */\n async handleUnverifiedChat(params: {\n content: string;\n conversation: string;\n previousReply: HistoryEntry | null;\n callbackData: WxSendMessageInput;\n triggerSrc: string;\n }): Promise<{ needSkipAI: boolean; replyContent: string; isEnd: boolean }> {\n const { content, conversation, previousReply, callbackData, triggerSrc } =\n params;\n\n // Check if async reply already sent (for retry scenario)\n if (previousReply && previousReply.needAsyncReply) {\n return { needSkipAI: true, replyContent: \"\", isEnd: true };\n }\n\n // Handle \"继续\" command\n if (content === \"continue\" || content === \"继续\") {\n const latest = await this._historyManager.getPreviousReply(conversation);\n let replyContent = \"\";\n\n if (!latest) {\n replyContent = \"未找到相关回答,请先发送消息\";\n } else if (isContinueCommandValid(latest)) {\n replyContent = latest.content || '正在思考中,请稍后再回复\"继续\"';\n } else {\n replyContent = \"回答已过期,请重新发送消息\";\n }\n\n return { needSkipAI: true, replyContent, isEnd: false };\n }\n\n // Handle 11-second retry using existing function\n if (previousReply) {\n const result = await handleWeChatRetry(\n previousReply,\n callbackData,\n triggerSrc as any\n );\n return {\n needSkipAI: result.shouldSkip,\n replyContent: result.content || \"\",\n isEnd: false,\n };\n }\n\n return { needSkipAI: false, replyContent: \"\", isEnd: false };\n }\n\n /**\n * Run method with WeChat integration\n * Wraps the underlying agent's run() and sends messages to WeChat\n */\n run(input: IWxRunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber: any) => {\n this.messageBuffer = \"\";\n this.lastReply = \"\";\n this.lastRunHadError = false;\n let errorMessage = \"\";\n let subscription: any;\n\n const replyId = input?.forwardedProps?.replay.id || randomUUID();\n Promise.all([\n this.saveInputToHistory(input),\n this.saveReplyToHistory(\n {\n id: replyId,\n content: this.lastReply,\n },\n input\n ),\n ]).then(\n () => {\n // Subscribe to the wrapped agent's events\n subscription = this.wrappedAgent.run(input).subscribe({\n next: (event: BaseEvent) => {\n // Emit the event to our subscribers\n subscriber.next(event);\n\n // Track if error occurred and capture error message\n if (event.type === EventType.RUN_ERROR) {\n this.lastRunHadError = true;\n const errorEvent = event as any;\n errorMessage =\n errorEvent.message ||\n errorEvent.error?.message ||\n \"处理消息时发生错误,请稍后重试\";\n }\n\n // Handle WeChat sending\n this.handleWeChatSending(event, input);\n },\n error: (error: any) => {\n subscriber.error(error);\n },\n complete: () => {\n // Set lastReply for controller to read\n this.lastReply = this.lastRunHadError\n ? errorMessage\n : this.messageBuffer.trim() || \"\";\n\n // Send final message if buffer has content and no error occurred\n // (error message already sent in handleWeChatSending)\n if (this.messageBuffer.trim() && !this.lastRunHadError) {\n this.sendToWeChat(this.messageBuffer, input).catch(\n console.error\n );\n }\n\n // Auto-save reply to history at complete\n this.saveReplyToHistory(\n {\n id: input?.forwardedProps?.replay.id || randomUUID(),\n content: this.lastReply,\n },\n input\n ).catch(console.error);\n\n subscriber.complete();\n },\n });\n },\n (e) => {\n subscriber.error(e);\n }\n );\n\n // Return cleanup function\n return () => {\n subscription?.unsubscribe();\n };\n });\n }\n\n /**\n * Save input message to history at the start of run()\n * Only saves if the last message is from user role\n * Uses msgData from forwardedProps for complete data (similar to dealMsgData)\n */\n private async saveInputToHistory(input: IWxRunAgentInput): Promise<void> {\n const messages = input.messages;\n if (!messages || messages.length === 0) return;\n\n // Only process if the last message is from user\n const lastMessage = messages[messages.length - 1];\n if (lastMessage.role !== \"user\") return;\n\n const { threadId, runId } = input;\n const msgData = input.forwardedProps?.msgData;\n\n // Use msgData.recordId if available, otherwise fallback to lastMessage.id\n const messageId =\n msgData?.recordId ||\n lastMessage.id ||\n (lastMessage as any).messageId ||\n randomUUID();\n\n // Extract content from the last user message\n const rawContent = lastMessage.content;\n const content =\n typeof rawContent === \"string\"\n ? rawContent\n : Array.isArray(rawContent)\n ? rawContent\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\")\n : \"\";\n\n if (threadId && content) {\n await this._historyManager.saveToHistory({\n messageId,\n role: \"user\",\n content,\n threadId,\n runId,\n createdAt: msgData?.createdAt || Date.now(),\n // Additional fields from msgData (similar to dealMsgData)\n botId: msgData?.botId,\n needAsyncReply: msgData?.needAsyncReply,\n type: msgData?.type,\n metadata: {\n sender: msgData?.sender,\n triggerSrc: msgData?.triggerSrc,\n originMsg: msgData?.originMsg,\n reply: msgData?.reply,\n recommendQuestions: msgData?.recommendQuestions,\n },\n });\n }\n }\n\n /**\n * Handle WeChat message sending based on events\n */\n private handleWeChatSending(event: BaseEvent, input: IWxRunAgentInput): void {\n // Always handle RUN_ERROR regardless of eventFilter\n if (event.type === EventType.RUN_ERROR) {\n const errorEvent = event as any;\n const errorMessage =\n errorEvent.message ||\n errorEvent.error?.message ||\n \"处理消息时发生错误,请稍后重试\";\n // Clear buffer to prevent duplicate sending\n this.messageBuffer = \"\";\n // Send error message to WeChat\n this.sendToWeChat(errorMessage, input).catch(console.error);\n return;\n }\n\n // Check if this event should trigger WeChat sending\n if (!this.eventFilter(event)) {\n return;\n }\n\n // Handle different event types\n switch (event.type) {\n case EventType.TEXT_MESSAGE_CONTENT:\n // Accumulate text content\n const content = (event as any).delta || (event as any).content || \"\";\n this.messageBuffer += content;\n break;\n\n case EventType.TEXT_MESSAGE_END:\n // Send accumulated message\n if (this.messageBuffer.trim()) {\n this.sendToWeChat(this.messageBuffer, input).catch(console.error);\n this.messageBuffer = \"\";\n }\n break;\n }\n }\n\n /**\n * Send message to WeChat and save to history\n * Only sends in async mode (needAsyncReply=true)\n * For sync mode, message is returned via HTTP response by controller\n */\n private async sendToWeChat(\n content: string,\n input: IWxRunAgentInput\n ): Promise<void> {\n try {\n // Check if async reply is needed from originMsg\n const needAsyncReply =\n input.forwardedProps?.replay.needAsyncReply ?? true;\n\n // Only send via adapter in async mode\n // In sync mode, controller handles returning the message via HTTP response\n if (needAsyncReply) {\n const sendMode = this.wechatConfig.sendMode || WeChatSendMode.AITOOLS;\n\n if (sendMode === WeChatSendMode.AITOOLS) {\n // Use aitools SDK to send message\n await this.sendViaAITools(content, input);\n } else {\n // Use local WeChatSender to send message\n await this.sendViaLocalSender(content, input);\n }\n }\n } catch (error) {\n console.error(\"Failed to send message to WeChat:\", error);\n }\n }\n\n /**\n * Save reply content to history\n * Uses replay metadata from forwardedProps for complete data (similar to dealMsgData)\n */\n private async saveReplyToHistory(\n reply: { id: string; content: string },\n input: IWxRunAgentInput\n ): Promise<void> {\n const { threadId, runId } = input;\n const replay = input.forwardedProps?.replay;\n const msgData = input.forwardedProps?.msgData;\n\n const messageId = reply.id;\n\n if (threadId && messageId) {\n await this._historyManager.saveToHistory({\n id: messageId,\n messageId,\n role: \"assistant\",\n content: reply.content,\n threadId,\n runId,\n createdAt: Date.now(),\n // Additional fields from replay/msgData (similar to dealMsgData replyMsgData)\n botId: replay?.botId || msgData?.botId,\n needAsyncReply: replay?.needAsyncReply,\n type: replay?.type || \"text\",\n metadata: {\n sender: replay?.sender || msgData?.sender,\n triggerSrc: replay?.triggerSrc || msgData?.triggerSrc,\n // For assistant, reply field is empty, replyTo points to user message\n replyTo: (replay as any)?.replyTo || msgData?.recordId,\n originMsg: replay?.originMsg,\n reply: replay?.reply,\n recommendQuestions: replay?.recommendQuestions,\n },\n });\n }\n }\n\n /**\n * Send message via aitools SDK (for cloud function environment)\n */\n private async sendViaAITools(\n content: string,\n input: IWxRunAgentInput\n ): Promise<void> {\n if (!this.aitools) {\n throw new Error(\"aitools is not initialized\");\n }\n\n // Get origin message from forwardedProps\n const wxSendmessageInput = input.forwardedProps?.wxSendmessageInput;\n if (!wxSendmessageInput) {\n console.warn(\n \"wxSendmessageInput not found in forwardedProps, skipping aitools send\"\n );\n return;\n }\n\n // Process reply message to get correct format for different platforms\n const toWxMsgData = this.processReplyMsg(wxSendmessageInput, content);\n if (!toWxMsgData) {\n console.warn(\"Failed to process reply message, skipping send\");\n return;\n }\n\n // Extract trigger source\n const triggerSrc =\n wxSendmessageInput.triggerSrc || this.wechatConfig.platform;\n\n // Send message using aitools\n await this.aitools.sendWxClientMessage(\n this.agentId || \"agent\",\n triggerSrc,\n {\n msgType: toWxMsgData.msgType,\n touser: toWxMsgData.toUserName,\n text: {\n content: toWxMsgData.content,\n },\n openKfId: toWxMsgData.openKfId,\n msgId: toWxMsgData.msgId || \"\",\n }\n );\n }\n\n /**\n * Format reply message for WeChat HTTP response (sync mode)\n * Public method for controller to use\n */\n formatReplyMessage(\n callbackData: any,\n triggerSrc: string,\n content: string\n ): WeChatReplyMessage {\n return formatWeChatReplyMessage(callbackData, triggerSrc, content);\n }\n\n /**\n * Process reply message to get correct format for different WeChat platforms\n * Based on chat_wx.service.ts processReplyMsg implementation\n */\n private processReplyMsg(\n wxSendMessageInput: WxSendMessageInput,\n content: string\n ) {\n const triggerSrc =\n wxSendMessageInput.triggerSrc || this.wechatConfig.platform;\n const callbackData: any = wxSendMessageInput.callbackData;\n\n return formatWeChatReplyMessage(callbackData, triggerSrc, content);\n }\n\n /**\n * Send message via local WeChatSender (for local development)\n */\n private async sendViaLocalSender(\n content: string,\n input: RunAgentInput\n ): Promise<void> {\n if (!this.wechatSender) {\n throw new Error(\"wechatSender is not initialized\");\n }\n\n const messageOptions = this.messageFormatter(content, {\n type: EventType.TEXT_MESSAGE_CONTENT,\n content,\n } as any);\n\n // Get origin message from forwardedProps if available\n const originMsg = input.forwardedProps?.originMsg;\n\n await this.wechatSender.send(messageOptions, originMsg);\n }\n}\n","/**\n * WeChat Chat History Manager\n * Manages chat history for \"continue\" command and retry logic\n * Uses CloudBase database storage\n */\n\nimport tcb from \"@cloudbase/node-sdk\";\n\n// Re-export ChatHistoryRecord for convenience\nexport type { ChatHistoryRecord } from \"./wechat-message-handler\";\n\n/** Default collection name for chat history */\nexport const WX_CHAT_HISTORY_COLLECTION = \"wx_chat_history\";\n\n/**\n * Message role type\n */\nexport type MessageRole = \"user\" | \"assistant\" | \"system\";\n\n/**\n * Metadata for history entry (stored in metadata field)\n */\nexport interface HistoryEntryMetadata {\n /** Sender identifier */\n sender?: string;\n /** Trigger source (WXSubscription, WXService, etc.) */\n triggerSrc?: string;\n /** Original message data */\n originMsg?: string;\n /** Reply to message ID */\n replyTo?: string;\n /** Reply message ID */\n reply?: string;\n /** Image URL if applicable */\n image?: string;\n /** Recommended questions */\n recommendQuestions?: string[];\n}\n\n/**\n * History entry for storage\n * Contains message info plus optional metadata\n */\nexport interface HistoryEntry {\n id?: string;\n /** Unique message ID (record_id in database) */\n messageId: string;\n /** Message role: user, assistant, or system */\n role: MessageRole;\n /** Message content */\n content?: string;\n /** Thread/Conversation ID */\n threadId: string;\n /** Creation timestamp */\n createdAt: number;\n /** Bot ID */\n botId?: string;\n /** Run ID for tracking agent runs */\n runId?: string;\n /** Whether async reply is needed (WeChat specific) */\n needAsyncReply?: boolean;\n /** Message status: pending, done, error, cancel */\n status?: string;\n /** Message type */\n type?: string;\n /** Additional metadata */\n metadata?: HistoryEntryMetadata;\n}\n\n/**\n * Database document structure (snake_case for CloudBase)\n */\ninterface ChatHistoryData {\n _id?: string;\n bot_id: string;\n record_id: string;\n role: string;\n status?: string;\n content?: string;\n conversation: string;\n type?: string;\n trace_id?: string;\n async_reply?: boolean;\n metadata?: HistoryEntryMetadata;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface HistoryManagerConfig {\n /** CloudBase environment ID */\n envId?: string;\n /** CloudBase secret ID */\n secretId?: string;\n /** CloudBase secret key */\n secretKey?: string;\n /** CloudBase session token */\n token?: string;\n /** Collection name, default: wx_chat_history */\n collectionName?: string;\n /** Bot ID for filtering */\n botId?: string;\n}\n\n/**\n * Transform HistoryEntry to database document format\n */\nfunction entryToData(entry: HistoryEntry): Omit<ChatHistoryData, \"_id\"> {\n return {\n bot_id: entry.botId || \"\",\n record_id: entry.messageId,\n role: entry.role,\n status: entry.status,\n content: entry.content,\n conversation: entry.threadId,\n type: entry.type,\n trace_id: entry.runId,\n async_reply: entry.needAsyncReply,\n metadata: entry.metadata,\n createdAt: entry.createdAt || Date.now(),\n updatedAt: Date.now(),\n };\n}\n\n/**\n * Transform database document to HistoryEntry\n */\nfunction dataToEntry(data: ChatHistoryData): HistoryEntry {\n return {\n id: data._id,\n messageId: data.record_id,\n role: data.role as MessageRole,\n content: data.content,\n threadId: data.conversation,\n createdAt: data.createdAt,\n botId: data.bot_id,\n runId: data.trace_id,\n needAsyncReply: data.async_reply,\n status: data.status,\n type: data.type,\n metadata: data.metadata,\n };\n}\n\n/**\n * WeChat History Manager\n * Uses CloudBase database storage\n * Singleton pattern for shared history across adapter and controller\n */\nexport class WeChatHistoryManager {\n private static instance: WeChatHistoryManager;\n private tcbClient: tcb.CloudBase;\n private collectionName: string;\n private botId: string;\n private collectionReady = false;\n\n private constructor(config?: HistoryManagerConfig) {\n this.collectionName = config?.collectionName || WX_CHAT_HISTORY_COLLECTION;\n this.botId = config?.botId || \"default\";\n\n // Initialize CloudBase client\n const envId =\n config?.envId || process.env.TCB_ENV || process.env.CLOUDBASE_ENV;\n if (!envId) {\n throw new Error(\n \"[WeChatHistoryManager] envId is required. Set TCB_ENV or CLOUDBASE_ENV environment variable, or pass envId in config.\"\n );\n }\n\n this.tcbClient = tcb.init({\n env: envId,\n secretId: config?.secretId,\n secretKey: config?.secretKey,\n sessionToken: config?.token,\n });\n }\n\n static getInstance(config?: HistoryManagerConfig): WeChatHistoryManager {\n if (!WeChatHistoryManager.instance) {\n WeChatHistoryManager.instance = new WeChatHistoryManager(config);\n }\n return WeChatHistoryManager.instance;\n }\n\n /**\n * Ensure collection exists, create if not\n */\n private async ensureCollection(): Promise<void> {\n if (this.collectionReady) return;\n\n try {\n const db = this.tcbClient.database();\n await db.createCollection(this.collectionName);\n this.collectionReady = true;\n } catch (error: any) {\n // Collection already exists (error code -502005)\n if (error?.code === \"DATABASE_COLLECTION_ALREADY_EXIST\") {\n this.collectionReady = true;\n } else {\n console.error(\n \"[WeChatHistoryManager] Failed to create collection:\",\n error\n );\n throw error;\n }\n }\n }\n\n /**\n * Get previous reply from history\n */\n async getPreviousReply(\n threadId: string,\n messageId?: string | null\n ): Promise<HistoryEntry | null> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n const whereCondition: Record<string, any> = {\n conversation: _.eq(threadId),\n };\n\n if (messageId) {\n whereCondition.record_id = _.eq(messageId);\n }\n\n const result = await collection\n .where(whereCondition)\n .orderBy(\"createdAt\", \"desc\")\n .limit(1)\n .get();\n\n if (result.data && result.data.length > 0) {\n return dataToEntry(result.data[0] as ChatHistoryData);\n }\n return null;\n }\n\n /**\n * Save record to history\n */\n async saveToHistory(record: HistoryEntry): Promise<void> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n // Check if record exists\n const existing = await collection\n .where({ record_id: _.eq(record.messageId) })\n .limit(1)\n .get();\n\n const data = entryToData({ ...record, botId: record.botId || this.botId });\n\n if (existing.data && existing.data.length > 0) {\n // Update existing record\n await collection\n .where({ record_id: _.eq(record.messageId) })\n .update(data);\n } else {\n // Add new record\n await collection.add(data);\n }\n }\n\n /**\n * Update record content by messageId\n */\n async updateContent(\n _threadId: string,\n messageId: string,\n content: string\n ): Promise<void> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n await collection.where({ record_id: _.eq(messageId) }).update({\n content,\n updatedAt: Date.now(),\n });\n }\n\n}\n\n// Export singleton getter for convenience\nexport const getHistoryManager = WeChatHistoryManager.getInstance;\n"],"mappings":"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","names":["WeChatPlatform","MessageType","WeChatSendMode","import_agent_shared","uuidv4","import_client","tcb","import_aiagent_framework","needAsyncReply"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/wechat-message-handler.ts","../src/server/wx.controller.ts","../src/token-manager.ts","../src/message-formatter.ts","../src/platform-router.ts","../src/wechat-sender.ts","../src/agent.ts","../src/wechat-history-manager.ts"],"sourcesContent":["/**\n * @cloudbase/agent-adapter-wx\n * WeChat adapter for AG-Kit - Forward LLM messages to WeChat platforms\n */\n\nexport { createWxMessageHandler } from \"./server/wx.controller\";\n\n// Main exports\nexport { WeChatSender } from \"./wechat-sender\";\nexport { WeChatAgent } from \"./agent\";\nexport { TokenManager } from \"./token-manager\";\nexport { MessageFormatter } from \"./message-formatter\";\nexport { PlatformRouter } from \"./platform-router\";\nexport {\n WeChatHistoryManager,\n getHistoryManager,\n} from \"./wechat-history-manager\";\nexport type {\n HistoryEntry,\n HistoryManagerConfig,\n} from \"./wechat-history-manager\";\n\n// Message handler exports - 消息处理工具\nexport {\n // Validation\n validateMessageType,\n extractMsgType,\n extractTriggerSrc,\n // Content extraction\n extractTextContent,\n extractVoiceMediaId,\n getWxChatContent,\n // Sender & conversation\n extractSender,\n extractConversation,\n // Record ID\n generateRecordId,\n extractMsgId,\n extractTimestamp,\n // Async reply\n needAsyncReply,\n // Core message processing\n dealMsgData,\n // Reply message formatting\n formatWeChatReplyMessage,\n // WeChat retry\n handleWeChatRetry,\n isContinueCommandValid,\n // Constants\n SUPPORTED_MSG_TYPES,\n} from \"./wechat-message-handler\";\n\n// Type exports\nexport { WeChatPlatform, WeChatSendMode, MessageType } from \"./types\";\n\nexport type {\n WeChatConfig,\n MessageContent,\n SendMessageOptions,\n AccessTokenResponse,\n WeChatAPIResponse,\n TokenCacheEntry,\n WeChatMessage,\n} from \"./types\";\n\nexport type { WeChatAgentConfig } from \"./agent\";\n\n// Message handler types - 消息处理类型\nexport type {\n WeChatCommonInput,\n WeChatWorkCommonInput,\n WeChatTriggerSrc,\n SupportedMsgType,\n ChatHistoryRecord,\n ProcessedMsgData,\n MessageValidationResult,\n VoiceMessageHandler,\n WeChatReplyMessage,\n} from \"./wechat-message-handler\";\n","/**\n * WeChat platform types\n */\nexport enum WeChatPlatform {\n /** 企业微信客服 */\n CUSTOM_SERVICE = \"WXCustomerService\",\n /** 微信小程序 */\n MINI_APP = \"WXMiniapp\",\n /** 微信服务号 */\n SERVICE = \"WXService\",\n /** 微信订阅号 */\n SUBSCRIPTION = \"WXSubscription\",\n}\n\n/**\n * Message types\n */\nexport enum MessageType {\n TEXT = \"text\",\n IMAGE = \"image\",\n EVENT = \"event\",\n VOICE = \"voice\",\n}\n\n/**\n * WeChat send mode\n */\nexport enum WeChatSendMode {\n /** Use local WeChatSender (for local development) */\n LOCAL = \"local\",\n /** Use aitools SDK (for cloud function environment) */\n AITOOLS = \"aitools\",\n}\n\nexport interface WeChatConfig {\n platform: WeChatPlatform;\n appId: string;\n appSecret: string;\n openKfId?: string;\n tokenCacheTTL?: number;\n sendMode?: WeChatSendMode;\n context?: any;\n}\n\nexport interface MessageContent {\n content: string;\n type: MessageType;\n imageUrl?: string;\n}\n\nexport interface SendMessageOptions {\n toUser: string;\n message: MessageContent;\n recommendQuestions?: string[];\n msgId?: string;\n}\n\nexport interface AccessTokenResponse {\n access_token: string;\n expires_in: number;\n errcode?: number;\n errmsg?: string;\n}\n\nexport interface WeChatAPIResponse {\n errcode: number;\n errmsg: string;\n [key: string]: any;\n}\n\nexport interface TokenCacheEntry {\n accessToken: string;\n expiresAt: number;\n}\n\nexport interface WeChatMessage {\n touser: string;\n msgtype: string;\n text?: { content: string };\n image?: { media_id?: string; pic_url?: string };\n open_kfid?: string;\n msgid?: string;\n}\n","/**\n * WeChat Message Handler - 微信消息处理工具\n *\n * 处理调用模型之前的所有逻辑:\n * - 消息类型校验\n * - 内容提取\n * - 消息数据生成\n * - 发送者/会话提取\n */\n\nimport { WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\nimport { HistoryEntry } from \"./wechat-history-manager\";\nimport { WeChatPlatform } from \"./types\";\n\n// ============================================================================\n// Types - 类型定义\n// ============================================================================\n\n/**\n * WeChat message input - 微信公众号/服务号/小程序消息\n */\nexport interface WeChatCommonInput {\n toUserName: string;\n fromUserName: string;\n createTime: number;\n msgType: string;\n msgId: string;\n content?: string; // 文本消息\n mediaId?: string; // 语音消息\n recognition?: string; // 语音识别结果\n}\n\n/**\n * WeChat Work customer service message input - 企业微信客服消息\n */\nexport interface WeChatWorkCommonInput {\n toUserName?: string;\n externalUserId: string;\n openKfId: string;\n msgType: string;\n msgId: string;\n sendTime: number;\n text?: { content: string };\n voice?: { mediaId: string };\n}\n\n/**\n * Supported trigger sources - 支持的触发源\n */\nexport type WeChatTriggerSrc =\n | WeChatPlatform.SUBSCRIPTION // 微信订阅号\n | WeChatPlatform.SERVICE // 微信服务号\n | WeChatPlatform.MINI_APP // 微信小程序\n | WeChatPlatform.CUSTOM_SERVICE; // 企业微信客服\n\n/**\n * Supported message types - 支持的消息类型\n */\nexport const SUPPORTED_MSG_TYPES = [\"text\", \"voice\"] as const;\nexport type SupportedMsgType = (typeof SUPPORTED_MSG_TYPES)[number];\n\n/**\n * Chat history record - 聊天历史记录\n */\nexport interface ChatHistoryRecord {\n recordId: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n // Optional fields\n image?: string;\n status?: string;\n traceId?: string;\n asyncReply?: string;\n replyTo?: string;\n event?: string;\n}\n\n/**\n * Processed message data - 处理后的消息数据\n */\nexport interface ProcessedMsgData {\n msgData: ChatHistoryRecord;\n replyMsgData: ChatHistoryRecord;\n}\n\n/**\n * Message validation result - 消息校验结果\n */\nexport interface MessageValidationResult {\n isValid: boolean;\n skipAI: boolean;\n errorMessage?: string;\n userErrorMessage?: string;\n}\n\n/**\n * Voice message handler type - 语音消息处理器类型\n */\nexport type VoiceMessageHandler = (\n botId: string,\n triggerSrc: string,\n mediaId: string\n) => Promise<{ content: string } | null>;\n\n// ============================================================================\n// Message Validation - 消息校验\n// ============================================================================\n\n/**\n * Validate message type - 校验消息类型\n */\nexport function validateMessageType(msgType: string): MessageValidationResult {\n if (SUPPORTED_MSG_TYPES.includes(msgType as SupportedMsgType)) {\n return { isValid: true, skipAI: false };\n }\n return {\n isValid: false,\n skipAI: true,\n errorMessage: `无法处理的消息类型:${msgType}`,\n userErrorMessage: \"抱歉暂时无法处理这个类型的消息\",\n };\n}\n\n/**\n * Extract message type from origin message - 从原始消息提取消息类型\n */\nexport function extractMsgType(originMsg: any): string {\n return originMsg.msgType || originMsg.MsgType || \"text\";\n}\n\n/**\n * Extract trigger source from origin message - 从原始消息提取触发源\n */\nexport function extractTriggerSrc(\n originMsg: any,\n defaultSrc: WeChatTriggerSrc = WeChatPlatform.SERVICE\n): WeChatTriggerSrc {\n return originMsg.triggerSrc || defaultSrc;\n}\n\n// ============================================================================\n// Content Extraction - 内容提取\n// ============================================================================\n\n/**\n * Extract text content from WeChat message - 从微信消息提取文本内容\n */\nexport function extractTextContent(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.Content || originMsg.content || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.text?.content || \"\";\n }\n return \"\";\n}\n\n/**\n * Extract voice media ID from WeChat message - 从微信消息提取语音媒体ID\n */\nexport function extractVoiceMediaId(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [WeChatPlatform.SUBSCRIPTION, WeChatPlatform.SERVICE].includes(triggerSrc)\n ) {\n return originMsg.MediaId || originMsg.mediaId || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.voice?.mediaId || \"\";\n }\n return \"\";\n}\n\n/**\n * Get content from WeChat message (text or voice) - 获取微信消息内容\n */\nexport async function getWxChatContent(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc,\n voiceMessageHandler?: VoiceMessageHandler,\n botId?: string\n): Promise<string> {\n const msgType = extractMsgType(originMsg);\n\n // Text message\n if (msgType === \"text\") {\n return extractTextContent(originMsg, triggerSrc);\n }\n\n // Voice message\n if (msgType === \"voice\") {\n const mediaId = extractVoiceMediaId(originMsg, triggerSrc);\n if (voiceMessageHandler && mediaId && botId) {\n const result = await voiceMessageHandler(botId, triggerSrc, mediaId);\n return result?.content || \"\";\n }\n }\n\n return \"\";\n}\n\n// ============================================================================\n// Sender & Conversation Extraction - 发送者和会话提取\n// ============================================================================\n\n/**\n * Extract sender from origin message - 从原始消息提取发送者\n */\nexport function extractSender(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.FromUserName || originMsg.fromUserName || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.externalUserId || \"\";\n }\n return \"\";\n}\n\n/**\n * Extract conversation ID from origin message - 从原始消息提取会话ID\n */\nexport function extractConversation(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.FromUserName || originMsg.fromUserName || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.externalUserId || \"\";\n }\n return \"\";\n}\n\n// ============================================================================\n// Record ID Generation - 记录ID生成\n// ============================================================================\n\n/**\n * Generate record ID - 生成记录ID\n */\nexport function generateRecordId(\n triggerSrc: WeChatTriggerSrc,\n msgId: string,\n timestamp: number\n): string {\n return `${triggerSrc}${msgId}${timestamp}`;\n}\n\n/**\n * Extract message ID from origin message - 从原始消息提取消息ID\n */\nexport function extractMsgId(originMsg: any): string {\n return originMsg.msgId || originMsg.MsgId || Date.now().toString();\n}\n\n/**\n * Extract timestamp from origin message - 从原始消息提取时间戳\n */\nexport function extractTimestamp(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): number {\n if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.sendTime || Math.floor(Date.now() / 1000);\n }\n return (\n originMsg.createTime ||\n originMsg.CreateTime ||\n Math.floor(Date.now() / 1000)\n );\n}\n\n// ============================================================================\n// Async Reply Logic - 异步回复逻辑\n// ============================================================================\n\n/**\n * Determine if async reply is needed - 判断是否需要异步回复\n */\nexport function needAsyncReply(\n triggerSrc: WeChatTriggerSrc,\n wxVerify: boolean\n): boolean {\n // 小程序和企业微信客服始终异步\n if (\n [WeChatPlatform.MINI_APP, WeChatPlatform.CUSTOM_SERVICE].includes(\n triggerSrc\n )\n ) {\n return true;\n }\n // 公众号/服务号根据认证状态决定\n return wxVerify;\n}\n\n// ============================================================================\n// Reply Message Formatting - 回复消息格式化\n// ============================================================================\n\n/**\n * WeChat reply message structure\n */\nexport interface WeChatReplyMessage {\n toUserName: string;\n fromUserName: string;\n createTime: number;\n msgType: string;\n content: string;\n msgId: string;\n openKfId?: string;\n}\n\n/**\n * Format reply message for WeChat\n * Used for both sync HTTP response and async aitools sending\n */\nexport function formatWeChatReplyMessage(\n callbackData: any,\n triggerSrc: string,\n content: string\n): WeChatReplyMessage {\n const createTime = Math.floor(Date.now() / 1000);\n const finalContent = content || \"抱歉暂时无法处理这个类型的消息\";\n\n // WeChat Work Customer Service\n if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return {\n toUserName: callbackData.externalUserId || callbackData.fromUserName,\n fromUserName: callbackData.openKfId,\n openKfId: callbackData.openKfId,\n createTime,\n msgType: \"text\",\n content: finalContent,\n msgId: callbackData.msgId,\n };\n }\n\n // WeChat Official Account / Service Account / Mini Program\n return {\n toUserName: callbackData.fromUserName || callbackData.FromUserName,\n fromUserName: callbackData.toUserName || callbackData.ToUserName,\n createTime,\n msgType: \"text\",\n content: finalContent,\n msgId: callbackData.msgId,\n };\n}\n\n// ============================================================================\n// Deal Message Data - 消息数据处理(核心方法)\n// ============================================================================\n\n/**\n * Deal message data - 处理微信消息,生成 msgData 和 replyMsgData\n * 完整实现原 chat_wx.service.ts 中的 dealMsgData 逻辑\n */\nexport function dealMsgData(\n originMsg: WxSendMessageInput[\"callbackData\"],\n triggerSrc: WeChatTriggerSrc,\n wxVerify: boolean,\n botId: string\n): ProcessedMsgData {\n const baseMsgData = {\n type: \"text\",\n triggerSrc: triggerSrc,\n botId: botId,\n recommendQuestions: [] as string[],\n content: \"\",\n originMsg: \"\",\n createdAt: Date.now(),\n };\n\n const sender = extractSender(originMsg, triggerSrc);\n const conversation = extractConversation(originMsg, triggerSrc);\n const msgId = extractMsgId(originMsg);\n const timestamp = extractTimestamp(originMsg, triggerSrc);\n const recordIdBase = generateRecordId(triggerSrc, msgId, timestamp);\n const asyncReply = needAsyncReply(triggerSrc, wxVerify);\n const msgType = extractMsgType(originMsg);\n\n return {\n msgData: {\n ...baseMsgData,\n recordId: `user-${recordIdBase}`,\n role: \"user\" as const,\n sender: sender,\n conversation: conversation,\n type: msgType,\n needAsyncReply: asyncReply,\n reply: recordIdBase,\n originMsg: JSON.stringify(originMsg),\n },\n replyMsgData: {\n ...baseMsgData,\n recordId: recordIdBase,\n role: \"assistant\" as const,\n sender: sender,\n conversation: conversation,\n type: \"text\",\n needAsyncReply: asyncReply,\n reply: \"\",\n originMsg: JSON.stringify({}),\n },\n };\n}\n\n// ============================================================================\n// WeChat Retry Logic - 微信重试逻辑\n// ============================================================================\n\n/**\n * Handle WeChat retry for unverified accounts (11-second rule)\n * 处理未认证账号的微信重试逻辑(11秒规则)\n */\nexport async function handleWeChatRetry(\n previousReply: HistoryEntry | null,\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): Promise<{ shouldSkip: boolean; content?: string }> {\n if (!previousReply) {\n return { shouldSkip: false };\n }\n\n const timestamp = extractTimestamp(originMsg, triggerSrc);\n const deltaTime = Date.now() - timestamp * 1000;\n\n // If already has content, return it\n if (previousReply.content) {\n return {\n shouldSkip: true,\n content: previousReply.content,\n };\n }\n\n // If more than 11 seconds, return status message\n if (deltaTime > 11 * 1000) {\n return {\n shouldSkip: true,\n content: '思考中,请稍后回复 \"继续\" 来获取回答内容',\n };\n }\n\n // Less than 11 seconds, sleep 5s to timeout (WeChat will retry)\n await new Promise((resolve) => setTimeout(resolve, 5000));\n return { shouldSkip: true };\n}\n\n/**\n * Check if \"继续\" command is within 5-minute timeout\n * 检查\"继续\"命令是否在5分钟超时内\n */\nexport function isContinueCommandValid(\n previousReply: HistoryEntry | null\n): boolean {\n if (!previousReply) {\n return false;\n }\n const fiveMinutes = 5 * 60 * 1000;\n return Date.now() - previousReply.createdAt < fiveMinutes;\n}\n","/**\n * WeChat Message Controller\n * Using @cloudbase/agent-adapter-wx for message processing\n * Directly using sendMessageAGUI handler from @cloudbase/agent-server\n */\n\nimport type { Request, Response } from \"express\";\nimport {\n validateMessageType,\n extractMsgType,\n getWxChatContent,\n dealMsgData,\n formatWeChatReplyMessage,\n VoiceMessageHandler,\n WeChatTriggerSrc,\n} from \"../wechat-message-handler\";\nimport { WeChatAgent } from \"../agent\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { agui } from \"@cloudbase/agent-server\";\nimport type { Logger } from \"@cloudbase/agent-shared\";\nimport { noopLogger } from \"@cloudbase/agent-shared\";\nimport { EventType } from \"@ag-ui/client\";\nexport {\n type Logger,\n type LogFn,\n noopLogger,\n createConsoleLogger,\n} from \"@cloudbase/agent-shared\";\n\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport { utils, WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\n\n/**\n * Agent creator function return type\n */\ninterface AgentCreatorResult {\n agent: AbstractAgent | WeChatAgent | { toAGUIAgent(): AbstractAgent };\n cleanup?: () => void;\n}\n\n/**\n * Agent creator function type\n */\ntype AgentCreator = (params: {\n request: Request;\n options?: { agentId: string };\n}) => AgentCreatorResult | Promise<AgentCreatorResult>;\n\n/**\n * Handler options\n */\ninterface WxMessageHandlerOptions {\n logger?: Logger;\n}\n\n/**\n * Extract service name from hostname by finding version number pattern\n * e.g., \"my-service-123456\" -> \"my-service\"\n */\nfunction getServiceNameFromHostname(hostname: string): string {\n const parts = hostname.split(\"-\");\n // Find the last part that is purely numeric (version number)\n // Use reverse loop for ES2015 compatibility (instead of findLastIndex)\n let versionIdx = -1;\n for (let i = parts.length - 1; i >= 0; i--) {\n if (/^\\d+$/.test(parts[i])) {\n versionIdx = i;\n break;\n }\n }\n return versionIdx > 0 ? parts.slice(0, versionIdx).join(\"-\") : hostname;\n}\n\n/**\n * Get bot ID from multiple sources\n * Priority: SCF_FUNCTIONNAME > URL (parsed) > HOSTNAME (parsed) > fallback\n */\nfunction getBotId(url?: string, fallback = \"agent-id\"): string {\n // 1. SCF function name (highest priority)\n if (process.env.SCF_FUNCTIONNAME) {\n return process.env.SCF_FUNCTIONNAME;\n }\n // 2. Parse from URL using utils\n if (url) {\n const parsedBotId = utils.parseBotId(url);\n if (parsedBotId) {\n return parsedBotId;\n }\n }\n // 3. Parse from HOSTNAME\n if (process.env.HOSTNAME) {\n return getServiceNameFromHostname(process.env.HOSTNAME);\n }\n return fallback;\n}\n\n/**\n * Create WeChat message handler\n * Directly using sendMessageAGUI.handler from @cloudbase/agent-server\n * Aligned with chat_wx_v2.service.ts logic\n *\n * @param createAgent - Function to create agent instance (returns { agent, cleanup?})\n * @param options - Handler options\n * @returns Express route handler\n */\nexport function createWxMessageHandler(\n createAgent: AgentCreator,\n options?: WxMessageHandlerOptions\n): (req: Request, res: Response) => Promise<Response> {\n const { logger: parentLogger = noopLogger } = options ?? {};\n const adapterLogger =\n parentLogger.child?.({ component: \"sendWXMessageAGUI\" }) ?? parentLogger;\n\n return async (req: Request, res: Response): Promise<Response> => {\n let cleanup: (() => void) | null = null;\n let agent: WeChatAgent = undefined as any;\n const { callbackData } = utils.transformKeysToCamelCase(req.body);\n const { triggerSrc, wxVerify } = utils.parseWxEnvParam({\n httpContext: {\n headers: req.headers,\n },\n } as any) as {\n triggerSrc: WeChatTriggerSrc;\n wxVerify: boolean;\n };\n const wxSendmessageInput: WxSendMessageInput = {\n callbackData,\n triggerSrc,\n wxVerify,\n };\n const requestId = uuidv4();\n const logger = adapterLogger.child?.({ requestId }) ?? adapterLogger;\n const botId = getBotId(\n `${req.protocol}://${req.get(\"host\")}${req.originalUrl}`,\n \"agent-wx-send-message\"\n );\n try {\n if (!callbackData || !triggerSrc) {\n return res.status(400).json({\n error: \"Bad Request\",\n message: \"Missing required fields: callbackData, triggerSrc\",\n });\n }\n\n logger.info?.(\"[WX] Received message:\", { triggerSrc, wxVerify, botId });\n\n // 1. Create agent instance first (needed for history and voice handling)\n const { agent: unknownAgent, cleanup: agentCleanup } =\n await Promise.resolve(\n createAgent({ request: req, options: { agentId: botId } })\n );\n cleanup = agentCleanup ?? null;\n agent = (\n \"toAGUIAgent\" in unknownAgent\n ? unknownAgent.toAGUIAgent()\n : unknownAgent\n ) as WeChatAgent;\n\n // 2. Process message data (aligned with beforeStream)\n const { msgData, replyMsgData } = dealMsgData(\n callbackData,\n triggerSrc,\n wxVerify,\n botId\n );\n let skipAI = false;\n let isEnd = false;\n\n // 3. Check for duplicate request using msgData.recordId\n // Skip dedup for unverified accounts (WXSubscription/WXService without wxVerify)\n // because they rely on WeChat's 11-second retry mechanism\n const isUnverifiedAccount =\n [\"WXSubscription\", \"WXService\"].includes(triggerSrc) && !wxVerify;\n\n if (!isUnverifiedAccount) {\n // recordId = user-{triggerSrc}{msgId}{timestamp}, conversation = fromUserName\n // This combination uniquely identifies a WeChat callback\n const existingUserMsg = await agent.getPreviousReply(\n msgData.conversation,\n msgData.recordId\n );\n if (existingUserMsg) {\n logger.info?.(\"[WX] Duplicate callback detected, skipping:\", {\n recordId: msgData.recordId,\n conversation: msgData.conversation,\n });\n return res.json({});\n }\n }\n\n // 4. Validate message type\n const msgType = extractMsgType(callbackData);\n const validation = validateMessageType(msgType);\n\n if (!validation.isValid) {\n skipAI = true;\n replyMsgData.content =\n validation.userErrorMessage || \"暂不支持该消息类型\";\n }\n\n // 5. Initialize history and check previous reply (for retry logic)\n const previousReply = await agent.getPreviousReply(\n replyMsgData.conversation,\n replyMsgData.recordId\n );\n\n // 6. Extract content using package utility (ASYNC)\n const voiceHandler: VoiceMessageHandler = async (\n vBotId: string,\n vTriggerSrc: string,\n mediaId: string\n ) => {\n try {\n const result = await agent?.aitools?.getWxMediaContent(\n vBotId,\n vTriggerSrc,\n mediaId\n );\n\n return result || null;\n } catch {\n return null;\n }\n };\n\n const content = await getWxChatContent(\n callbackData,\n triggerSrc,\n voiceHandler,\n botId\n );\n\n // 7. Handle unverified account logic (WXSubscription/WXService only)\n if (\n [\"WXSubscription\", \"WXService\"].includes(triggerSrc) &&\n !wxVerify &&\n !skipAI\n ) {\n const result = await agent.handleUnverifiedChat({\n content,\n conversation: replyMsgData.conversation,\n previousReply,\n callbackData,\n triggerSrc,\n });\n skipAI = result.needSkipAI;\n isEnd = result.isEnd;\n if (result.replyContent) replyMsgData.content = result.replyContent;\n }\n\n // 8. Early return: async reply already sent\n if (isEnd) {\n return res.json({});\n }\n\n // 9. Early return: empty content\n if (!content && !skipAI) {\n logger.warn?.(\"[WX] Empty content\");\n return res.json(\n formatWeChatReplyMessage(callbackData, triggerSrc, \"无法识别消息内容\")\n );\n }\n\n // 10. Early return: skipAI\n if (skipAI) {\n logger.info?.(\"[WX] Skipping AI\");\n return res.json(\n formatWeChatReplyMessage(\n callbackData,\n triggerSrc,\n replyMsgData.content\n )\n );\n }\n\n // 11. Prepare input for sendMessageAGUI.handler\n // History is auto-managed by adapter.run():\n // - Input message saved at start\n // - Reply saved at complete\n logger.info?.(\"[WX] Processing:\", content.substring(0, 100));\n const input = {\n messages: [\n {\n id: msgData.recordId,\n role: \"user\" as const,\n content,\n },\n ],\n state: undefined,\n threadId: msgData.conversation,\n runId: uuidv4(),\n tools: [],\n context: [],\n forwardedProps: {\n wxSendmessageInput,\n // Pass full msgData for history storage\n msgData: msgData,\n // Pass replay info with replyMsgData for assistant history\n replay: {\n id: replyMsgData.recordId,\n ...replyMsgData,\n },\n },\n };\n\n // 12. Call agent - WeChatAgentAdapter.run() handles:\n // - Message assembly (both modes)\n // - Message sending (async mode only)\n // - History saving (both modes)\n // - Error handling (async mode: sends error message)\n const events = agui.sendMessageAGUI.handler(input, agent);\n\n // 13. Consume events to trigger adapter processing\n for await (const event of events) {\n if (event.type === EventType.RUN_ERROR) {\n logger.error?.(\n \"[WX] Agent error:\",\n (event as any).error || (event as any).message\n );\n }\n }\n logger.info?.(\"[WX] Processing complete\");\n\n // 14. Return response - get assembled reply from agent\n if (replyMsgData.needAsyncReply) {\n // Async mode: message already sent by adapter\n return res.json({});\n }\n // Sync mode: get assembled reply from agent and return via HTTP\n const finalContent = agent.lastReply || \"抱歉,无法生成回复\";\n return res.json(\n formatWeChatReplyMessage(callbackData, triggerSrc, finalContent)\n );\n } catch (error) {\n logger.error?.(\"[WX] Error processing message:\", error);\n const message = error instanceof Error ? error.message : String(error);\n try {\n if (agent?.aitools?.sendWxClientMessage) {\n const data = formatWeChatReplyMessage(\n callbackData,\n triggerSrc,\n message\n );\n await agent.aitools.sendWxClientMessage(\n agent.agentId || botId,\n triggerSrc,\n {\n msgType: data.msgType,\n touser: data.toUserName,\n text: {\n content: data.content,\n },\n openKfId: data.openKfId,\n msgId: data.msgId,\n }\n );\n }\n } catch (e) {}\n return res.status(500).json({\n error: \"Internal Server Error\",\n message,\n });\n } finally {\n if (cleanup) cleanup();\n }\n };\n}\n","import {\n WeChatConfig,\n WeChatPlatform,\n AccessTokenResponse,\n TokenCacheEntry,\n} from \"./types\";\n\n/**\n * Token manager for WeChat access tokens\n * Handles token caching and automatic refresh\n */\nexport class TokenManager {\n private cache: Map<string, TokenCacheEntry> = new Map();\n\n /**\n * Get access token (with caching)\n */\n async getAccessToken(config: WeChatConfig): Promise<string> {\n const cacheKey = this.getCacheKey(config);\n const cached = this.cache.get(cacheKey);\n\n // Return cached token if still valid\n if (cached && cached.expiresAt > Date.now()) {\n return cached.accessToken;\n }\n\n // Fetch new token\n const token = await this.fetchAccessToken(config);\n return token;\n }\n\n /**\n * Fetch access token from WeChat API\n */\n private async fetchAccessToken(config: WeChatConfig): Promise<string> {\n const url = this.getTokenUrl(config);\n const response = await fetch(url);\n const data: AccessTokenResponse = await response.json();\n\n if (data.errcode && data.errcode !== 0) {\n throw new Error(`Failed to get access token: ${data.errmsg}`);\n }\n\n // Cache token with 5-minute early expiration\n const cacheKey = this.getCacheKey(config);\n const expiresAt = Date.now() + (data.expires_in - 300) * 1000;\n\n this.cache.set(cacheKey, {\n accessToken: data.access_token,\n expiresAt,\n });\n\n return data.access_token;\n }\n\n /**\n * Get token URL based on platform\n */\n private getTokenUrl(config: WeChatConfig): string {\n if (config.platform === WeChatPlatform.CUSTOM_SERVICE) {\n return `https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${config.appId}&corpsecret=${config.appSecret}`;\n }\n return `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${config.appId}&secret=${config.appSecret}`;\n }\n\n /**\n * Generate cache key\n */\n private getCacheKey(config: WeChatConfig): string {\n return `${config.platform}_${config.appId}`;\n }\n\n /**\n * Clear token cache\n */\n clearCache(config?: WeChatConfig): void {\n if (config) {\n this.cache.delete(this.getCacheKey(config));\n } else {\n this.cache.clear();\n }\n }\n}\n\n","import {\n MessageContent,\n SendMessageOptions,\n WeChatMessage,\n WeChatPlatform,\n MessageType,\n} from \"./types\";\n\n/**\n * Message formatter for different WeChat platforms\n */\nexport class MessageFormatter {\n /**\n * Format message for WeChat API\n */\n formatMessage(\n options: SendMessageOptions,\n platform: WeChatPlatform,\n originMsg?: any\n ): WeChatMessage {\n const { toUser, message, recommendQuestions, msgId } = options;\n let content = message.content;\n\n // Add recommended questions if provided\n if (recommendQuestions && recommendQuestions.length > 0) {\n content = this.withRecommendQuestions(content, recommendQuestions);\n }\n\n const baseMessage: WeChatMessage = {\n touser: toUser,\n msgtype: message.type,\n };\n\n // Format based on message type\n if (message.type === MessageType.TEXT) {\n baseMessage.text = { content };\n } else if (message.type === MessageType.IMAGE && message.imageUrl) {\n baseMessage.image = { pic_url: message.imageUrl };\n }\n\n // Add platform-specific fields\n if (platform === WeChatPlatform.CUSTOM_SERVICE) {\n baseMessage.open_kfid = originMsg?.open_kfid;\n baseMessage.msgid = msgId || originMsg?.msgid;\n }\n\n return baseMessage;\n }\n\n /**\n * Append recommended questions to content\n */\n private withRecommendQuestions(\n content: string,\n questions: string[]\n ): string {\n if (!questions || questions.length === 0) {\n return content;\n }\n return `${content}\\n\\n推荐问题:\\n${questions.join(\"\\n\")}`;\n }\n\n /**\n * Split long message into chunks\n */\n splitLongMessage(content: string, maxLength: number = 2000): string[] {\n if (content.length <= maxLength) {\n return [content];\n }\n\n const chunks: string[] = [];\n let currentChunk = \"\";\n\n const lines = content.split(\"\\n\");\n for (const line of lines) {\n if ((currentChunk + line).length > maxLength) {\n if (currentChunk) {\n chunks.push(currentChunk.trim());\n currentChunk = \"\";\n }\n // Handle lines longer than maxLength\n if (line.length > maxLength) {\n for (let i = 0; i < line.length; i += maxLength) {\n chunks.push(line.substring(i, i + maxLength));\n }\n } else {\n currentChunk = line + \"\\n\";\n }\n } else {\n currentChunk += line + \"\\n\";\n }\n }\n\n if (currentChunk) {\n chunks.push(currentChunk.trim());\n }\n\n return chunks;\n }\n}\n\n","import {\n WeChatConfig,\n WeChatMessage,\n WeChatPlatform,\n WeChatAPIResponse,\n} from \"./types\";\nimport { TokenManager } from \"./token-manager\";\n\n/**\n * Platform router for sending messages to different WeChat platforms\n */\nexport class PlatformRouter {\n private tokenManager: TokenManager;\n\n constructor(tokenManager: TokenManager) {\n this.tokenManager = tokenManager;\n }\n\n /**\n * Send message to WeChat platform\n */\n async send(\n message: WeChatMessage,\n config: WeChatConfig\n ): Promise<WeChatAPIResponse> {\n const accessToken = await this.tokenManager.getAccessToken(config);\n\n switch (config.platform) {\n case WeChatPlatform.CUSTOM_SERVICE:\n return this.sendToCustomService(message, accessToken, config);\n case WeChatPlatform.MINI_APP:\n return this.sendToMiniApp(message, accessToken);\n case WeChatPlatform.SERVICE:\n case WeChatPlatform.SUBSCRIPTION:\n return this.sendToOfficialAccount(message, accessToken);\n default:\n throw new Error(`Unsupported platform: ${config.platform}`);\n }\n }\n\n /**\n * Send to Enterprise WeChat Customer Service\n */\n private async sendToCustomService(\n message: WeChatMessage,\n accessToken: string,\n config: WeChatConfig\n ): Promise<WeChatAPIResponse> {\n const url = `https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n\n /**\n * Send to WeChat Mini Program\n */\n private async sendToMiniApp(\n message: WeChatMessage,\n accessToken: string\n ): Promise<WeChatAPIResponse> {\n const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n\n /**\n * Send to WeChat Official Account (Service/Subscription)\n */\n private async sendToOfficialAccount(\n message: WeChatMessage,\n accessToken: string\n ): Promise<WeChatAPIResponse> {\n const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n}\n\n","import { WeChatConfig, SendMessageOptions, WeChatAPIResponse } from \"./types\";\nimport { TokenManager } from \"./token-manager\";\nimport { MessageFormatter } from \"./message-formatter\";\nimport { PlatformRouter } from \"./platform-router\";\n\n/**\n * Main WeChat sender class\n * Provides a simple API to send LLM messages to WeChat platforms\n */\nexport class WeChatSender {\n private config: WeChatConfig;\n private tokenManager: TokenManager;\n private messageFormatter: MessageFormatter;\n private platformRouter: PlatformRouter;\n\n constructor(config: WeChatConfig) {\n // Validate config\n this.config = config;\n\n // Initialize components\n this.tokenManager = new TokenManager();\n this.messageFormatter = new MessageFormatter();\n this.platformRouter = new PlatformRouter(this.tokenManager);\n }\n\n /**\n * Send a message to WeChat\n */\n async send(\n options: SendMessageOptions,\n originMsg?: any\n ): Promise<WeChatAPIResponse> {\n // Validate options\n const validatedOptions = options;\n\n // Format message\n const message = this.messageFormatter.formatMessage(\n validatedOptions,\n this.config.platform,\n originMsg\n );\n\n // Send message\n const result = await this.platformRouter.send(message, this.config);\n\n // Check for errors\n if (result.errcode !== 0) {\n throw new Error(`Failed to send message: ${result.errmsg}`);\n }\n\n return result;\n }\n\n /**\n * Send multiple messages in batch\n */\n async sendBatch(\n messages: SendMessageOptions[]\n ): Promise<WeChatAPIResponse[]> {\n const results: WeChatAPIResponse[] = [];\n\n for (const message of messages) {\n try {\n const result = await this.send(message);\n results.push(result);\n } catch (error) {\n results.push({\n errcode: -1,\n errmsg: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n return results;\n }\n\n /**\n * Send message asynchronously (fire and forget)\n */\n async sendAsync(options: SendMessageOptions, originMsg?: any): Promise<void> {\n this.send(options, originMsg).catch((error) => {\n console.error(\"Failed to send message:\", error);\n });\n }\n\n /**\n * Clear token cache\n */\n clearCache(): void {\n this.tokenManager.clearCache(this.config);\n }\n\n /**\n * Get current configuration\n */\n getConfig(): WeChatConfig {\n return { ...this.config };\n }\n}\n","import {\n RunAgentInput,\n BaseEvent,\n EventType,\n AbstractAgent,\n AgentConfig,\n} from \"@ag-ui/client\";\nimport { Observable } from \"rxjs\";\nimport { WeChatSender } from \"./wechat-sender\";\nimport {\n WeChatConfig,\n SendMessageOptions,\n MessageType,\n WeChatSendMode,\n} from \"./types\";\nimport { WeChatHistoryManager, HistoryEntry } from \"./wechat-history-manager\";\nimport {\n handleWeChatRetry,\n isContinueCommandValid,\n formatWeChatReplyMessage,\n WeChatReplyMessage,\n} from \"./wechat-message-handler\";\nimport { aitools, WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\nimport { randomUUID } from \"crypto\";\n\nconst AITOOLS = aitools.AITools;\n\n/**\n * Configuration for WeChat Agent Adapter\n */\nexport interface WeChatAgentConfig extends AgentConfig {\n /**\n * The underlying agent to wrap\n */\n agent: AbstractAgent;\n\n /**\n * WeChat configuration\n */\n wechatConfig: WeChatConfig;\n\n /**\n * Optional: Custom message formatter\n * Converts agent output to WeChat message format\n */\n messageFormatter?: (content: string, event: BaseEvent) => SendMessageOptions;\n\n /**\n * Optional: Recommended questions to show after reply\n */\n recommendQuestions?: string[];\n\n /**\n * Optional: History manager for saving chat history\n * If not provided, will use singleton instance\n */\n historyManager?: WeChatHistoryManager;\n}\n\ninterface IWxRunAgentInput extends RunAgentInput {\n forwardedProps: {\n wxSendmessageInput: WxSendMessageInput;\n /** Full user message data from dealMsgData */\n msgData?: {\n recordId: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n };\n /** Reply metadata for assistant message */\n replay: {\n id: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n };\n };\n}\n\n/**\n * WeChat Agent Adapter\n *\n * Wraps any AbstractAgent and automatically sends its output to WeChat.\n * All methods are proxied to the underlying agent, with the run() method\n * enhanced to capture messages and send them via WeChat.\n *\n * @example\n * ```typescript\n * const myAgent = new SomeAgent({ ... });\n * const wechatAgent = new WeChatAgentAdapter({\n * agent: myAgent,\n * wechatConfig: {\n * platform: 'work',\n * corpId: 'xxx',\n * corpSecret: 'xxx'\n * }\n * });\n *\n * // Use it like any other agent\n * wechatAgent.run(input).subscribe(event => {\n * // Events are emitted normally\n * // AND automatically sent to WeChat\n * });\n * ```\n */\nexport class WeChatAgent extends AbstractAgent {\n private wrappedAgent: AbstractAgent;\n private wechatSender?: WeChatSender;\n private wechatConfig: WeChatConfig;\n private _historyManager: WeChatHistoryManager;\n private messageFormatter: (\n content: string,\n event: BaseEvent\n ) => SendMessageOptions;\n private messageBuffer: string = \"\";\n private recommendQuestions?: string[];\n public aitools?: aitools.AITools;\n\n constructor(config: WeChatAgentConfig) {\n super({\n agentId: config.agentId || config.agent.agentId,\n description: config.description || config.agent.description,\n threadId: config.threadId || config.agent.threadId,\n ...config,\n });\n\n this.wrappedAgent = config.agent;\n this.wechatConfig = config.wechatConfig;\n this.recommendQuestions = config.recommendQuestions;\n this._historyManager =\n config.historyManager || WeChatHistoryManager.getInstance();\n\n // Initialize sender based on send mode\n const sendMode = config.wechatConfig.sendMode || WeChatSendMode.LOCAL;\n\n if (sendMode === WeChatSendMode.AITOOLS) {\n // Use aitools SDK (for cloud function environment)\n if (!config.wechatConfig.context) {\n throw new Error(\"context is required when sendMode is AITOOLS\");\n }\n this.aitools = new AITOOLS(config.wechatConfig.context);\n } else {\n // Use local WeChatSender (for local development)\n this.wechatSender = new WeChatSender(config.wechatConfig);\n }\n\n // Default message formatter\n this.messageFormatter =\n config.messageFormatter ||\n ((content: string) => ({\n toUser: \"\", // Will be set from originMsg\n message: {\n content: content,\n type: MessageType.TEXT,\n },\n recommendQuestions: this.recommendQuestions,\n }));\n }\n\n /**\n * Last assembled reply content after run() completes\n * Controller can read this instead of re-assembling from events\n */\n public lastReply: string = \"\";\n\n /**\n * Whether last run had an error\n */\n public lastRunHadError: boolean = false;\n\n /**\n * Get previous reply from history\n * Used for: retry detection, \"继续\" command\n */\n async getPreviousReply(\n conversation: string,\n recordId?: string | null\n ): Promise<HistoryEntry | null> {\n return this._historyManager.getPreviousReply(conversation, recordId);\n }\n\n /**\n * Update message content in history\n */\n async updateHistoryContent(\n messageId: string,\n content: string,\n threadId: string\n ): Promise<void> {\n await this._historyManager.updateContent(threadId, messageId, content);\n }\n\n /**\n * Handle unverified account logic (WXSubscription/WXService)\n * Handles \"继续\" command and 11-second retry\n * Uses existing functions from wechat-message-handler.ts\n * @returns { needSkipAI, replyContent, isEnd }\n */\n async handleUnverifiedChat(params: {\n content: string;\n conversation: string;\n previousReply: HistoryEntry | null;\n callbackData: WxSendMessageInput;\n triggerSrc: string;\n }): Promise<{ needSkipAI: boolean; replyContent: string; isEnd: boolean }> {\n const { content, conversation, previousReply, callbackData, triggerSrc } =\n params;\n\n // Check if async reply already sent (for retry scenario)\n if (previousReply && previousReply.needAsyncReply) {\n return { needSkipAI: true, replyContent: \"\", isEnd: true };\n }\n\n // Handle \"继续\" command\n if (content === \"continue\" || content === \"继续\") {\n const latest = await this._historyManager.getPreviousReply(conversation);\n let replyContent = \"\";\n\n if (!latest) {\n replyContent = \"未找到相关回答,请先发送消息\";\n } else if (isContinueCommandValid(latest)) {\n replyContent = latest.content || '正在思考中,请稍后再回复\"继续\"';\n } else {\n replyContent = \"回答已过期,请重新发送消息\";\n }\n\n return { needSkipAI: true, replyContent, isEnd: false };\n }\n\n // Handle 11-second retry using existing function\n if (previousReply) {\n const result = await handleWeChatRetry(\n previousReply,\n callbackData,\n triggerSrc as any\n );\n return {\n needSkipAI: result.shouldSkip,\n replyContent: result.content || \"\",\n isEnd: false,\n };\n }\n\n return { needSkipAI: false, replyContent: \"\", isEnd: false };\n }\n\n /**\n * Run method with WeChat integration\n * Wraps the underlying agent's run() and sends messages to WeChat\n */\n run(input: IWxRunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber: any) => {\n this.messageBuffer = \"\";\n this.lastReply = \"\";\n this.lastRunHadError = false;\n let errorMessage = \"\";\n let subscription: any;\n\n const replyId = input?.forwardedProps?.replay.id || randomUUID();\n Promise.all([\n this.saveInputToHistory(input),\n this.saveReplyToHistory(\n {\n id: replyId,\n content: this.lastReply,\n },\n input\n ),\n ]).then(\n () => {\n // Subscribe to the wrapped agent's events\n subscription = this.wrappedAgent.run(input).subscribe({\n next: (event: BaseEvent) => {\n // Emit the event to our subscribers\n subscriber.next(event);\n\n // Track if error occurred and capture error message\n if (event.type === EventType.RUN_ERROR) {\n this.lastRunHadError = true;\n const errorEvent = event as any;\n errorMessage =\n errorEvent.message ||\n errorEvent.error?.message ||\n \"处理消息时发生错误,请稍后重试\";\n }\n\n // Handle WeChat sending\n this.handleWeChatSending(event, input);\n },\n error: (error: any) => {\n subscriber.error(error);\n },\n complete: () => {\n // Set lastReply for controller to read\n this.lastReply = this.lastRunHadError\n ? errorMessage\n : this.messageBuffer.trim() || \"\";\n\n // Send final message if buffer has content and no error occurred\n // (error message already sent in handleWeChatSending)\n if (this.messageBuffer.trim() && !this.lastRunHadError) {\n this.sendToWeChat(this.messageBuffer, input).catch(\n console.error\n );\n }\n\n // Auto-save reply to history at complete\n this.saveReplyToHistory(\n {\n id: input?.forwardedProps?.replay.id || randomUUID(),\n content: this.lastReply,\n },\n input\n ).catch(console.error);\n\n subscriber.complete();\n },\n });\n },\n (e) => {\n subscriber.error(e);\n }\n );\n\n // Return cleanup function\n return () => {\n subscription?.unsubscribe();\n };\n });\n }\n\n /**\n * Save input message to history at the start of run()\n * Only saves if the last message is from user role\n * Uses msgData from forwardedProps for complete data (similar to dealMsgData)\n */\n private async saveInputToHistory(input: IWxRunAgentInput): Promise<void> {\n const messages = input.messages;\n if (!messages || messages.length === 0) return;\n\n // Only process if the last message is from user\n const lastMessage = messages[messages.length - 1];\n if (lastMessage.role !== \"user\") return;\n\n const { threadId, runId } = input;\n const msgData = input.forwardedProps?.msgData;\n\n // Use msgData.recordId if available, otherwise fallback to lastMessage.id\n const messageId =\n msgData?.recordId ||\n lastMessage.id ||\n (lastMessage as any).messageId ||\n randomUUID();\n\n // Extract content from the last user message\n const rawContent = lastMessage.content;\n const content =\n typeof rawContent === \"string\"\n ? rawContent\n : Array.isArray(rawContent)\n ? rawContent\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\")\n : \"\";\n\n if (threadId && content) {\n await this._historyManager.saveToHistory({\n messageId,\n role: \"user\",\n content,\n threadId,\n runId,\n createdAt: msgData?.createdAt || Date.now(),\n // Additional fields from msgData (similar to dealMsgData)\n botId: msgData?.botId,\n needAsyncReply: msgData?.needAsyncReply,\n type: msgData?.type,\n metadata: {\n sender: msgData?.sender,\n triggerSrc: msgData?.triggerSrc,\n originMsg: msgData?.originMsg,\n reply: msgData?.reply,\n recommendQuestions: msgData?.recommendQuestions,\n },\n });\n }\n }\n\n /**\n * Handle WeChat message sending based on events\n */\n private handleWeChatSending(event: BaseEvent, input: IWxRunAgentInput): void {\n // Always handle RUN_ERROR regardless of eventFilter\n if (event.type === EventType.RUN_ERROR) {\n const errorEvent = event as any;\n const errorMessage =\n errorEvent.message ||\n errorEvent.error?.message ||\n \"处理消息时发生错误,请稍后重试\";\n // Clear buffer to prevent duplicate sending\n this.messageBuffer = \"\";\n // Send error message to WeChat\n this.sendToWeChat(errorMessage, input).catch(console.error);\n return;\n }\n\n // Handle different event types\n switch (event.type) {\n case EventType.TEXT_MESSAGE_CHUNK:\n case EventType.TEXT_MESSAGE_CONTENT:\n // Accumulate text content\n const content = (event as any).delta || (event as any).content || \"\";\n this.messageBuffer += content;\n break;\n }\n }\n\n /**\n * Send message to WeChat and save to history\n * Only sends in async mode (needAsyncReply=true)\n * For sync mode, message is returned via HTTP response by controller\n */\n private async sendToWeChat(\n content: string,\n input: IWxRunAgentInput\n ): Promise<void> {\n try {\n // Check if async reply is needed from originMsg\n const needAsyncReply =\n input.forwardedProps?.replay.needAsyncReply ?? true;\n\n // Only send via adapter in async mode\n // In sync mode, controller handles returning the message via HTTP response\n if (needAsyncReply) {\n const sendMode = this.wechatConfig.sendMode || WeChatSendMode.AITOOLS;\n\n if (sendMode === WeChatSendMode.AITOOLS) {\n // Use aitools SDK to send message\n await this.sendViaAITools(content, input);\n } else {\n // Use local WeChatSender to send message\n await this.sendViaLocalSender(content, input);\n }\n }\n } catch (error) {\n console.error(\"Failed to send message to WeChat:\", error);\n }\n }\n\n /**\n * Save reply content to history\n * Uses replay metadata from forwardedProps for complete data (similar to dealMsgData)\n */\n private async saveReplyToHistory(\n reply: { id: string; content: string },\n input: IWxRunAgentInput\n ): Promise<void> {\n const { threadId, runId } = input;\n const replay = input.forwardedProps?.replay;\n const msgData = input.forwardedProps?.msgData;\n\n const messageId = reply.id;\n\n if (threadId && messageId) {\n await this._historyManager.saveToHistory({\n id: messageId,\n messageId,\n role: \"assistant\",\n content: reply.content,\n threadId,\n runId,\n createdAt: Date.now(),\n // Additional fields from replay/msgData (similar to dealMsgData replyMsgData)\n botId: replay?.botId || msgData?.botId,\n needAsyncReply: replay?.needAsyncReply,\n type: replay?.type || \"text\",\n metadata: {\n sender: replay?.sender || msgData?.sender,\n triggerSrc: replay?.triggerSrc || msgData?.triggerSrc,\n // For assistant, reply field is empty, replyTo points to user message\n replyTo: (replay as any)?.replyTo || msgData?.recordId,\n originMsg: replay?.originMsg,\n reply: replay?.reply,\n recommendQuestions: replay?.recommendQuestions,\n },\n });\n }\n }\n\n /**\n * Send message via aitools SDK (for cloud function environment)\n */\n private async sendViaAITools(\n content: string,\n input: IWxRunAgentInput\n ): Promise<void> {\n if (!this.aitools) {\n throw new Error(\"aitools is not initialized\");\n }\n\n // Get origin message from forwardedProps\n const wxSendmessageInput = input.forwardedProps?.wxSendmessageInput;\n if (!wxSendmessageInput) {\n console.warn(\n \"wxSendmessageInput not found in forwardedProps, skipping aitools send\"\n );\n return;\n }\n\n // Process reply message to get correct format for different platforms\n const toWxMsgData = this.processReplyMsg(wxSendmessageInput, content);\n if (!toWxMsgData) {\n console.warn(\"Failed to process reply message, skipping send\");\n return;\n }\n\n // Extract trigger source\n const triggerSrc =\n wxSendmessageInput.triggerSrc || this.wechatConfig.platform;\n\n // Send message using aitools\n await this.aitools.sendWxClientMessage(\n this.agentId || \"agent\",\n triggerSrc,\n {\n msgType: toWxMsgData.msgType,\n touser: toWxMsgData.toUserName,\n text: {\n content: toWxMsgData.content,\n },\n openKfId: toWxMsgData.openKfId,\n msgId: toWxMsgData.msgId || \"\",\n }\n );\n }\n\n /**\n * Format reply message for WeChat HTTP response (sync mode)\n * Public method for controller to use\n */\n formatReplyMessage(\n callbackData: any,\n triggerSrc: string,\n content: string\n ): WeChatReplyMessage {\n return formatWeChatReplyMessage(callbackData, triggerSrc, content);\n }\n\n /**\n * Process reply message to get correct format for different WeChat platforms\n * Based on chat_wx.service.ts processReplyMsg implementation\n */\n private processReplyMsg(\n wxSendMessageInput: WxSendMessageInput,\n content: string\n ) {\n const triggerSrc =\n wxSendMessageInput.triggerSrc || this.wechatConfig.platform;\n const callbackData: any = wxSendMessageInput.callbackData;\n\n return formatWeChatReplyMessage(callbackData, triggerSrc, content);\n }\n\n /**\n * Send message via local WeChatSender (for local development)\n */\n private async sendViaLocalSender(\n content: string,\n input: RunAgentInput\n ): Promise<void> {\n if (!this.wechatSender) {\n throw new Error(\"wechatSender is not initialized\");\n }\n\n const messageOptions = this.messageFormatter(content, {\n type: EventType.TEXT_MESSAGE_CONTENT,\n content,\n } as any);\n\n // Get origin message from forwardedProps if available\n const originMsg = input.forwardedProps?.originMsg;\n\n await this.wechatSender.send(messageOptions, originMsg);\n }\n}\n","/**\n * WeChat Chat History Manager\n * Manages chat history for \"continue\" command and retry logic\n * Uses CloudBase database storage\n */\n\nimport tcb from \"@cloudbase/node-sdk\";\n\n// Re-export ChatHistoryRecord for convenience\nexport type { ChatHistoryRecord } from \"./wechat-message-handler\";\n\n/** Default collection name for chat history */\nexport const WX_CHAT_HISTORY_COLLECTION = \"wx_chat_history\";\n\n/**\n * Message role type\n */\nexport type MessageRole = \"user\" | \"assistant\" | \"system\";\n\n/**\n * Metadata for history entry (stored in metadata field)\n */\nexport interface HistoryEntryMetadata {\n /** Sender identifier */\n sender?: string;\n /** Trigger source (WXSubscription, WXService, etc.) */\n triggerSrc?: string;\n /** Original message data */\n originMsg?: string;\n /** Reply to message ID */\n replyTo?: string;\n /** Reply message ID */\n reply?: string;\n /** Image URL if applicable */\n image?: string;\n /** Recommended questions */\n recommendQuestions?: string[];\n}\n\n/**\n * History entry for storage\n * Contains message info plus optional metadata\n */\nexport interface HistoryEntry {\n id?: string;\n /** Unique message ID (record_id in database) */\n messageId: string;\n /** Message role: user, assistant, or system */\n role: MessageRole;\n /** Message content */\n content?: string;\n /** Thread/Conversation ID */\n threadId: string;\n /** Creation timestamp */\n createdAt: number;\n /** Bot ID */\n botId?: string;\n /** Run ID for tracking agent runs */\n runId?: string;\n /** Whether async reply is needed (WeChat specific) */\n needAsyncReply?: boolean;\n /** Message status: pending, done, error, cancel */\n status?: string;\n /** Message type */\n type?: string;\n /** Additional metadata */\n metadata?: HistoryEntryMetadata;\n}\n\n/**\n * Database document structure (snake_case for CloudBase)\n */\ninterface ChatHistoryData {\n _id?: string;\n bot_id: string;\n record_id: string;\n role: string;\n status?: string;\n content?: string;\n conversation: string;\n type?: string;\n trace_id?: string;\n async_reply?: boolean;\n metadata?: HistoryEntryMetadata;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface HistoryManagerConfig {\n /** CloudBase environment ID */\n envId?: string;\n /** CloudBase secret ID */\n secretId?: string;\n /** CloudBase secret key */\n secretKey?: string;\n /** CloudBase session token */\n token?: string;\n /** Collection name, default: wx_chat_history */\n collectionName?: string;\n /** Bot ID for filtering */\n botId?: string;\n}\n\n/**\n * Transform HistoryEntry to database document format\n */\nfunction entryToData(entry: HistoryEntry): Omit<ChatHistoryData, \"_id\"> {\n return {\n bot_id: entry.botId || \"\",\n record_id: entry.messageId,\n role: entry.role,\n status: entry.status,\n content: entry.content,\n conversation: entry.threadId,\n type: entry.type,\n trace_id: entry.runId,\n async_reply: entry.needAsyncReply,\n metadata: entry.metadata,\n createdAt: entry.createdAt || Date.now(),\n updatedAt: Date.now(),\n };\n}\n\n/**\n * Transform database document to HistoryEntry\n */\nfunction dataToEntry(data: ChatHistoryData): HistoryEntry {\n return {\n id: data._id,\n messageId: data.record_id,\n role: data.role as MessageRole,\n content: data.content,\n threadId: data.conversation,\n createdAt: data.createdAt,\n botId: data.bot_id,\n runId: data.trace_id,\n needAsyncReply: data.async_reply,\n status: data.status,\n type: data.type,\n metadata: data.metadata,\n };\n}\n\n/**\n * WeChat History Manager\n * Uses CloudBase database storage\n * Singleton pattern for shared history across adapter and controller\n */\nexport class WeChatHistoryManager {\n private static instance: WeChatHistoryManager;\n private tcbClient: tcb.CloudBase;\n private collectionName: string;\n private botId: string;\n private collectionReady = false;\n\n private constructor(config?: HistoryManagerConfig) {\n this.collectionName = config?.collectionName || WX_CHAT_HISTORY_COLLECTION;\n this.botId = config?.botId || \"default\";\n\n // Initialize CloudBase client\n const envId =\n config?.envId || process.env.TCB_ENV || process.env.CLOUDBASE_ENV;\n if (!envId) {\n throw new Error(\n \"[WeChatHistoryManager] envId is required. Set TCB_ENV or CLOUDBASE_ENV environment variable, or pass envId in config.\"\n );\n }\n\n this.tcbClient = tcb.init({\n env: envId,\n secretId: config?.secretId,\n secretKey: config?.secretKey,\n sessionToken: config?.token,\n });\n }\n\n static getInstance(config?: HistoryManagerConfig): WeChatHistoryManager {\n if (!WeChatHistoryManager.instance) {\n WeChatHistoryManager.instance = new WeChatHistoryManager(config);\n }\n return WeChatHistoryManager.instance;\n }\n\n /**\n * Ensure collection exists, create if not\n */\n private async ensureCollection(): Promise<void> {\n if (this.collectionReady) return;\n\n try {\n const db = this.tcbClient.database();\n await db.createCollection(this.collectionName);\n this.collectionReady = true;\n } catch (error: any) {\n // Collection already exists (error code -502005)\n if (error?.code === \"DATABASE_COLLECTION_ALREADY_EXIST\") {\n this.collectionReady = true;\n } else {\n console.error(\n \"[WeChatHistoryManager] Failed to create collection:\",\n error\n );\n throw error;\n }\n }\n }\n\n /**\n * Get previous reply from history\n */\n async getPreviousReply(\n threadId: string,\n messageId?: string | null\n ): Promise<HistoryEntry | null> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n const whereCondition: Record<string, any> = {\n conversation: _.eq(threadId),\n };\n\n if (messageId) {\n whereCondition.record_id = _.eq(messageId);\n }\n\n const result = await collection\n .where(whereCondition)\n .orderBy(\"createdAt\", \"desc\")\n .limit(1)\n .get();\n\n if (result.data && result.data.length > 0) {\n return dataToEntry(result.data[0] as ChatHistoryData);\n }\n return null;\n }\n\n /**\n * Save record to history\n */\n async saveToHistory(record: HistoryEntry): Promise<void> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n // Check if record exists\n const existing = await collection\n .where({ record_id: _.eq(record.messageId) })\n .limit(1)\n .get();\n\n const data = entryToData({ ...record, botId: record.botId || this.botId });\n\n if (existing.data && existing.data.length > 0) {\n // Update existing record\n await collection\n .where({ record_id: _.eq(record.messageId) })\n .update(data);\n } else {\n // Add new record\n await collection.add(data);\n }\n }\n\n /**\n * Update record content by messageId\n */\n async updateContent(\n _threadId: string,\n messageId: string,\n content: string\n ): Promise<void> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n await collection.where({ record_id: _.eq(messageId) }).update({\n content,\n updatedAt: Date.now(),\n });\n }\n\n}\n\n// Export singleton getter for convenience\nexport const getHistoryManager = WeChatHistoryManager.getInstance;\n"],"mappings":"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","names":["WeChatPlatform","MessageType","WeChatSendMode","import_agent_shared","uuidv4","import_client","tcb","import_aiagent_framework","needAsyncReply"]}
package/dist/index.mjs CHANGED
@@ -882,7 +882,6 @@ var WeChatAgent = class extends AbstractAgent {
882
882
  },
883
883
  recommendQuestions: this.recommendQuestions
884
884
  }));
885
- this.eventFilter = config.eventFilter || ((event) => event.type === EventType2.TEXT_MESSAGE_CONTENT);
886
885
  }
887
886
  /**
888
887
  * Get previous reply from history
@@ -1045,20 +1044,12 @@ var WeChatAgent = class extends AbstractAgent {
1045
1044
  this.sendToWeChat(errorMessage, input).catch(console.error);
1046
1045
  return;
1047
1046
  }
1048
- if (!this.eventFilter(event)) {
1049
- return;
1050
- }
1051
1047
  switch (event.type) {
1048
+ case EventType2.TEXT_MESSAGE_CHUNK:
1052
1049
  case EventType2.TEXT_MESSAGE_CONTENT:
1053
1050
  const content = event.delta || event.content || "";
1054
1051
  this.messageBuffer += content;
1055
1052
  break;
1056
- case EventType2.TEXT_MESSAGE_END:
1057
- if (this.messageBuffer.trim()) {
1058
- this.sendToWeChat(this.messageBuffer, input).catch(console.error);
1059
- this.messageBuffer = "";
1060
- }
1061
- break;
1062
1053
  }
1063
1054
  }
1064
1055
  /**
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/wechat-message-handler.ts","../src/server/wx.controller.ts","../src/token-manager.ts","../src/message-formatter.ts","../src/platform-router.ts","../src/wechat-sender.ts","../src/agent.ts","../src/wechat-history-manager.ts"],"sourcesContent":["/**\n * WeChat platform types\n */\nexport enum WeChatPlatform {\n /** 企业微信客服 */\n CUSTOM_SERVICE = \"WXCustomerService\",\n /** 微信小程序 */\n MINI_APP = \"WXMiniapp\",\n /** 微信服务号 */\n SERVICE = \"WXService\",\n /** 微信订阅号 */\n SUBSCRIPTION = \"WXSubscription\",\n}\n\n/**\n * Message types\n */\nexport enum MessageType {\n TEXT = \"text\",\n IMAGE = \"image\",\n EVENT = \"event\",\n VOICE = \"voice\",\n}\n\n/**\n * WeChat send mode\n */\nexport enum WeChatSendMode {\n /** Use local WeChatSender (for local development) */\n LOCAL = \"local\",\n /** Use aitools SDK (for cloud function environment) */\n AITOOLS = \"aitools\",\n}\n\nexport interface WeChatConfig {\n platform: WeChatPlatform;\n appId: string;\n appSecret: string;\n openKfId?: string;\n tokenCacheTTL?: number;\n sendMode?: WeChatSendMode;\n context?: any;\n}\n\nexport interface MessageContent {\n content: string;\n type: MessageType;\n imageUrl?: string;\n}\n\nexport interface SendMessageOptions {\n toUser: string;\n message: MessageContent;\n recommendQuestions?: string[];\n msgId?: string;\n}\n\nexport interface AccessTokenResponse {\n access_token: string;\n expires_in: number;\n errcode?: number;\n errmsg?: string;\n}\n\nexport interface WeChatAPIResponse {\n errcode: number;\n errmsg: string;\n [key: string]: any;\n}\n\nexport interface TokenCacheEntry {\n accessToken: string;\n expiresAt: number;\n}\n\nexport interface WeChatMessage {\n touser: string;\n msgtype: string;\n text?: { content: string };\n image?: { media_id?: string; pic_url?: string };\n open_kfid?: string;\n msgid?: string;\n}\n","/**\n * WeChat Message Handler - 微信消息处理工具\n *\n * 处理调用模型之前的所有逻辑:\n * - 消息类型校验\n * - 内容提取\n * - 消息数据生成\n * - 发送者/会话提取\n */\n\nimport { WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\nimport { HistoryEntry } from \"./wechat-history-manager\";\nimport { WeChatPlatform } from \"./types\";\n\n// ============================================================================\n// Types - 类型定义\n// ============================================================================\n\n/**\n * WeChat message input - 微信公众号/服务号/小程序消息\n */\nexport interface WeChatCommonInput {\n toUserName: string;\n fromUserName: string;\n createTime: number;\n msgType: string;\n msgId: string;\n content?: string; // 文本消息\n mediaId?: string; // 语音消息\n recognition?: string; // 语音识别结果\n}\n\n/**\n * WeChat Work customer service message input - 企业微信客服消息\n */\nexport interface WeChatWorkCommonInput {\n toUserName?: string;\n externalUserId: string;\n openKfId: string;\n msgType: string;\n msgId: string;\n sendTime: number;\n text?: { content: string };\n voice?: { mediaId: string };\n}\n\n/**\n * Supported trigger sources - 支持的触发源\n */\nexport type WeChatTriggerSrc =\n | WeChatPlatform.SUBSCRIPTION // 微信订阅号\n | WeChatPlatform.SERVICE // 微信服务号\n | WeChatPlatform.MINI_APP // 微信小程序\n | WeChatPlatform.CUSTOM_SERVICE; // 企业微信客服\n\n/**\n * Supported message types - 支持的消息类型\n */\nexport const SUPPORTED_MSG_TYPES = [\"text\", \"voice\"] as const;\nexport type SupportedMsgType = (typeof SUPPORTED_MSG_TYPES)[number];\n\n/**\n * Chat history record - 聊天历史记录\n */\nexport interface ChatHistoryRecord {\n recordId: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n // Optional fields\n image?: string;\n status?: string;\n traceId?: string;\n asyncReply?: string;\n replyTo?: string;\n event?: string;\n}\n\n/**\n * Processed message data - 处理后的消息数据\n */\nexport interface ProcessedMsgData {\n msgData: ChatHistoryRecord;\n replyMsgData: ChatHistoryRecord;\n}\n\n/**\n * Message validation result - 消息校验结果\n */\nexport interface MessageValidationResult {\n isValid: boolean;\n skipAI: boolean;\n errorMessage?: string;\n userErrorMessage?: string;\n}\n\n/**\n * Voice message handler type - 语音消息处理器类型\n */\nexport type VoiceMessageHandler = (\n botId: string,\n triggerSrc: string,\n mediaId: string\n) => Promise<{ content: string } | null>;\n\n// ============================================================================\n// Message Validation - 消息校验\n// ============================================================================\n\n/**\n * Validate message type - 校验消息类型\n */\nexport function validateMessageType(msgType: string): MessageValidationResult {\n if (SUPPORTED_MSG_TYPES.includes(msgType as SupportedMsgType)) {\n return { isValid: true, skipAI: false };\n }\n return {\n isValid: false,\n skipAI: true,\n errorMessage: `无法处理的消息类型:${msgType}`,\n userErrorMessage: \"抱歉暂时无法处理这个类型的消息\",\n };\n}\n\n/**\n * Extract message type from origin message - 从原始消息提取消息类型\n */\nexport function extractMsgType(originMsg: any): string {\n return originMsg.msgType || originMsg.MsgType || \"text\";\n}\n\n/**\n * Extract trigger source from origin message - 从原始消息提取触发源\n */\nexport function extractTriggerSrc(\n originMsg: any,\n defaultSrc: WeChatTriggerSrc = WeChatPlatform.SERVICE\n): WeChatTriggerSrc {\n return originMsg.triggerSrc || defaultSrc;\n}\n\n// ============================================================================\n// Content Extraction - 内容提取\n// ============================================================================\n\n/**\n * Extract text content from WeChat message - 从微信消息提取文本内容\n */\nexport function extractTextContent(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.Content || originMsg.content || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.text?.content || \"\";\n }\n return \"\";\n}\n\n/**\n * Extract voice media ID from WeChat message - 从微信消息提取语音媒体ID\n */\nexport function extractVoiceMediaId(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [WeChatPlatform.SUBSCRIPTION, WeChatPlatform.SERVICE].includes(triggerSrc)\n ) {\n return originMsg.MediaId || originMsg.mediaId || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.voice?.mediaId || \"\";\n }\n return \"\";\n}\n\n/**\n * Get content from WeChat message (text or voice) - 获取微信消息内容\n */\nexport async function getWxChatContent(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc,\n voiceMessageHandler?: VoiceMessageHandler,\n botId?: string\n): Promise<string> {\n const msgType = extractMsgType(originMsg);\n\n // Text message\n if (msgType === \"text\") {\n return extractTextContent(originMsg, triggerSrc);\n }\n\n // Voice message\n if (msgType === \"voice\") {\n const mediaId = extractVoiceMediaId(originMsg, triggerSrc);\n if (voiceMessageHandler && mediaId && botId) {\n const result = await voiceMessageHandler(botId, triggerSrc, mediaId);\n return result?.content || \"\";\n }\n }\n\n return \"\";\n}\n\n// ============================================================================\n// Sender & Conversation Extraction - 发送者和会话提取\n// ============================================================================\n\n/**\n * Extract sender from origin message - 从原始消息提取发送者\n */\nexport function extractSender(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.FromUserName || originMsg.fromUserName || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.externalUserId || \"\";\n }\n return \"\";\n}\n\n/**\n * Extract conversation ID from origin message - 从原始消息提取会话ID\n */\nexport function extractConversation(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.FromUserName || originMsg.fromUserName || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.externalUserId || \"\";\n }\n return \"\";\n}\n\n// ============================================================================\n// Record ID Generation - 记录ID生成\n// ============================================================================\n\n/**\n * Generate record ID - 生成记录ID\n */\nexport function generateRecordId(\n triggerSrc: WeChatTriggerSrc,\n msgId: string,\n timestamp: number\n): string {\n return `${triggerSrc}${msgId}${timestamp}`;\n}\n\n/**\n * Extract message ID from origin message - 从原始消息提取消息ID\n */\nexport function extractMsgId(originMsg: any): string {\n return originMsg.msgId || originMsg.MsgId || Date.now().toString();\n}\n\n/**\n * Extract timestamp from origin message - 从原始消息提取时间戳\n */\nexport function extractTimestamp(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): number {\n if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.sendTime || Math.floor(Date.now() / 1000);\n }\n return (\n originMsg.createTime ||\n originMsg.CreateTime ||\n Math.floor(Date.now() / 1000)\n );\n}\n\n// ============================================================================\n// Async Reply Logic - 异步回复逻辑\n// ============================================================================\n\n/**\n * Determine if async reply is needed - 判断是否需要异步回复\n */\nexport function needAsyncReply(\n triggerSrc: WeChatTriggerSrc,\n wxVerify: boolean\n): boolean {\n // 小程序和企业微信客服始终异步\n if (\n [WeChatPlatform.MINI_APP, WeChatPlatform.CUSTOM_SERVICE].includes(\n triggerSrc\n )\n ) {\n return true;\n }\n // 公众号/服务号根据认证状态决定\n return wxVerify;\n}\n\n// ============================================================================\n// Reply Message Formatting - 回复消息格式化\n// ============================================================================\n\n/**\n * WeChat reply message structure\n */\nexport interface WeChatReplyMessage {\n toUserName: string;\n fromUserName: string;\n createTime: number;\n msgType: string;\n content: string;\n msgId: string;\n openKfId?: string;\n}\n\n/**\n * Format reply message for WeChat\n * Used for both sync HTTP response and async aitools sending\n */\nexport function formatWeChatReplyMessage(\n callbackData: any,\n triggerSrc: string,\n content: string\n): WeChatReplyMessage {\n const createTime = Math.floor(Date.now() / 1000);\n const finalContent = content || \"抱歉暂时无法处理这个类型的消息\";\n\n // WeChat Work Customer Service\n if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return {\n toUserName: callbackData.externalUserId || callbackData.fromUserName,\n fromUserName: callbackData.openKfId,\n openKfId: callbackData.openKfId,\n createTime,\n msgType: \"text\",\n content: finalContent,\n msgId: callbackData.msgId,\n };\n }\n\n // WeChat Official Account / Service Account / Mini Program\n return {\n toUserName: callbackData.fromUserName || callbackData.FromUserName,\n fromUserName: callbackData.toUserName || callbackData.ToUserName,\n createTime,\n msgType: \"text\",\n content: finalContent,\n msgId: callbackData.msgId,\n };\n}\n\n// ============================================================================\n// Deal Message Data - 消息数据处理(核心方法)\n// ============================================================================\n\n/**\n * Deal message data - 处理微信消息,生成 msgData 和 replyMsgData\n * 完整实现原 chat_wx.service.ts 中的 dealMsgData 逻辑\n */\nexport function dealMsgData(\n originMsg: WxSendMessageInput[\"callbackData\"],\n triggerSrc: WeChatTriggerSrc,\n wxVerify: boolean,\n botId: string\n): ProcessedMsgData {\n const baseMsgData = {\n type: \"text\",\n triggerSrc: triggerSrc,\n botId: botId,\n recommendQuestions: [] as string[],\n content: \"\",\n originMsg: \"\",\n createdAt: Date.now(),\n };\n\n const sender = extractSender(originMsg, triggerSrc);\n const conversation = extractConversation(originMsg, triggerSrc);\n const msgId = extractMsgId(originMsg);\n const timestamp = extractTimestamp(originMsg, triggerSrc);\n const recordIdBase = generateRecordId(triggerSrc, msgId, timestamp);\n const asyncReply = needAsyncReply(triggerSrc, wxVerify);\n const msgType = extractMsgType(originMsg);\n\n return {\n msgData: {\n ...baseMsgData,\n recordId: `user-${recordIdBase}`,\n role: \"user\" as const,\n sender: sender,\n conversation: conversation,\n type: msgType,\n needAsyncReply: asyncReply,\n reply: recordIdBase,\n originMsg: JSON.stringify(originMsg),\n },\n replyMsgData: {\n ...baseMsgData,\n recordId: recordIdBase,\n role: \"assistant\" as const,\n sender: sender,\n conversation: conversation,\n type: \"text\",\n needAsyncReply: asyncReply,\n reply: \"\",\n originMsg: JSON.stringify({}),\n },\n };\n}\n\n// ============================================================================\n// WeChat Retry Logic - 微信重试逻辑\n// ============================================================================\n\n/**\n * Handle WeChat retry for unverified accounts (11-second rule)\n * 处理未认证账号的微信重试逻辑(11秒规则)\n */\nexport async function handleWeChatRetry(\n previousReply: HistoryEntry | null,\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): Promise<{ shouldSkip: boolean; content?: string }> {\n if (!previousReply) {\n return { shouldSkip: false };\n }\n\n const timestamp = extractTimestamp(originMsg, triggerSrc);\n const deltaTime = Date.now() - timestamp * 1000;\n\n // If already has content, return it\n if (previousReply.content) {\n return {\n shouldSkip: true,\n content: previousReply.content,\n };\n }\n\n // If more than 11 seconds, return status message\n if (deltaTime > 11 * 1000) {\n return {\n shouldSkip: true,\n content: '思考中,请稍后回复 \"继续\" 来获取回答内容',\n };\n }\n\n // Less than 11 seconds, sleep 5s to timeout (WeChat will retry)\n await new Promise((resolve) => setTimeout(resolve, 5000));\n return { shouldSkip: true };\n}\n\n/**\n * Check if \"继续\" command is within 5-minute timeout\n * 检查\"继续\"命令是否在5分钟超时内\n */\nexport function isContinueCommandValid(\n previousReply: HistoryEntry | null\n): boolean {\n if (!previousReply) {\n return false;\n }\n const fiveMinutes = 5 * 60 * 1000;\n return Date.now() - previousReply.createdAt < fiveMinutes;\n}\n","/**\n * WeChat Message Controller\n * Using @cloudbase/agent-adapter-wx for message processing\n * Directly using sendMessageAGUI handler from @cloudbase/agent-server\n */\n\nimport type { Request, Response } from \"express\";\nimport {\n validateMessageType,\n extractMsgType,\n getWxChatContent,\n dealMsgData,\n formatWeChatReplyMessage,\n VoiceMessageHandler,\n WeChatTriggerSrc,\n} from \"../wechat-message-handler\";\nimport { WeChatAgent } from \"../agent\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { agui } from \"@cloudbase/agent-server\";\nimport type { Logger } from \"@cloudbase/agent-shared\";\nimport { noopLogger } from \"@cloudbase/agent-shared\";\nimport { EventType } from \"@ag-ui/client\";\nexport {\n type Logger,\n type LogFn,\n noopLogger,\n createConsoleLogger,\n} from \"@cloudbase/agent-shared\";\n\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport { utils, WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\n\n/**\n * Agent creator function return type\n */\ninterface AgentCreatorResult {\n agent: AbstractAgent | WeChatAgent | { toAGUIAgent(): AbstractAgent };\n cleanup?: () => void;\n}\n\n/**\n * Agent creator function type\n */\ntype AgentCreator = (params: {\n request: Request;\n options?: { agentId: string };\n}) => AgentCreatorResult | Promise<AgentCreatorResult>;\n\n/**\n * Handler options\n */\ninterface WxMessageHandlerOptions {\n logger?: Logger;\n}\n\n/**\n * Extract service name from hostname by finding version number pattern\n * e.g., \"my-service-123456\" -> \"my-service\"\n */\nfunction getServiceNameFromHostname(hostname: string): string {\n const parts = hostname.split(\"-\");\n // Find the last part that is purely numeric (version number)\n // Use reverse loop for ES2015 compatibility (instead of findLastIndex)\n let versionIdx = -1;\n for (let i = parts.length - 1; i >= 0; i--) {\n if (/^\\d+$/.test(parts[i])) {\n versionIdx = i;\n break;\n }\n }\n return versionIdx > 0 ? parts.slice(0, versionIdx).join(\"-\") : hostname;\n}\n\n/**\n * Get bot ID from multiple sources\n * Priority: SCF_FUNCTIONNAME > URL (parsed) > HOSTNAME (parsed) > fallback\n */\nfunction getBotId(url?: string, fallback = \"agent-id\"): string {\n // 1. SCF function name (highest priority)\n if (process.env.SCF_FUNCTIONNAME) {\n return process.env.SCF_FUNCTIONNAME;\n }\n // 2. Parse from URL using utils\n if (url) {\n const parsedBotId = utils.parseBotId(url);\n if (parsedBotId) {\n return parsedBotId;\n }\n }\n // 3. Parse from HOSTNAME\n if (process.env.HOSTNAME) {\n return getServiceNameFromHostname(process.env.HOSTNAME);\n }\n return fallback;\n}\n\n/**\n * Create WeChat message handler\n * Directly using sendMessageAGUI.handler from @cloudbase/agent-server\n * Aligned with chat_wx_v2.service.ts logic\n *\n * @param createAgent - Function to create agent instance (returns { agent, cleanup?})\n * @param options - Handler options\n * @returns Express route handler\n */\nexport function createWxMessageHandler(\n createAgent: AgentCreator,\n options?: WxMessageHandlerOptions\n): (req: Request, res: Response) => Promise<Response> {\n const { logger: parentLogger = noopLogger } = options ?? {};\n const adapterLogger =\n parentLogger.child?.({ component: \"sendWXMessageAGUI\" }) ?? parentLogger;\n\n return async (req: Request, res: Response): Promise<Response> => {\n let cleanup: (() => void) | null = null;\n let agent: WeChatAgent = undefined as any;\n const { callbackData } = utils.transformKeysToCamelCase(req.body);\n const { triggerSrc, wxVerify } = utils.parseWxEnvParam({\n httpContext: {\n headers: req.headers,\n },\n } as any) as {\n triggerSrc: WeChatTriggerSrc;\n wxVerify: boolean;\n };\n const wxSendmessageInput: WxSendMessageInput = {\n callbackData,\n triggerSrc,\n wxVerify,\n };\n const requestId = uuidv4();\n const logger = adapterLogger.child?.({ requestId }) ?? adapterLogger;\n const botId = getBotId(\n `${req.protocol}://${req.get(\"host\")}${req.originalUrl}`,\n \"agent-wx-send-message\"\n );\n try {\n if (!callbackData || !triggerSrc) {\n return res.status(400).json({\n error: \"Bad Request\",\n message: \"Missing required fields: callbackData, triggerSrc\",\n });\n }\n\n logger.info?.(\"[WX] Received message:\", { triggerSrc, wxVerify, botId });\n\n // 1. Create agent instance first (needed for history and voice handling)\n const { agent: unknownAgent, cleanup: agentCleanup } =\n await Promise.resolve(\n createAgent({ request: req, options: { agentId: botId } })\n );\n cleanup = agentCleanup ?? null;\n agent = (\n \"toAGUIAgent\" in unknownAgent\n ? unknownAgent.toAGUIAgent()\n : unknownAgent\n ) as WeChatAgent;\n\n // 2. Process message data (aligned with beforeStream)\n const { msgData, replyMsgData } = dealMsgData(\n callbackData,\n triggerSrc,\n wxVerify,\n botId\n );\n let skipAI = false;\n let isEnd = false;\n\n // 3. Check for duplicate request using msgData.recordId\n // Skip dedup for unverified accounts (WXSubscription/WXService without wxVerify)\n // because they rely on WeChat's 11-second retry mechanism\n const isUnverifiedAccount =\n [\"WXSubscription\", \"WXService\"].includes(triggerSrc) && !wxVerify;\n\n if (!isUnverifiedAccount) {\n // recordId = user-{triggerSrc}{msgId}{timestamp}, conversation = fromUserName\n // This combination uniquely identifies a WeChat callback\n const existingUserMsg = await agent.getPreviousReply(\n msgData.conversation,\n msgData.recordId\n );\n if (existingUserMsg) {\n logger.info?.(\"[WX] Duplicate callback detected, skipping:\", {\n recordId: msgData.recordId,\n conversation: msgData.conversation,\n });\n return res.json({});\n }\n }\n\n // 4. Validate message type\n const msgType = extractMsgType(callbackData);\n const validation = validateMessageType(msgType);\n\n if (!validation.isValid) {\n skipAI = true;\n replyMsgData.content =\n validation.userErrorMessage || \"暂不支持该消息类型\";\n }\n\n // 5. Initialize history and check previous reply (for retry logic)\n const previousReply = await agent.getPreviousReply(\n replyMsgData.conversation,\n replyMsgData.recordId\n );\n\n // 6. Extract content using package utility (ASYNC)\n const voiceHandler: VoiceMessageHandler = async (\n vBotId: string,\n vTriggerSrc: string,\n mediaId: string\n ) => {\n try {\n const result = await agent?.aitools?.getWxMediaContent(\n vBotId,\n vTriggerSrc,\n mediaId\n );\n\n return result || null;\n } catch {\n return null;\n }\n };\n\n const content = await getWxChatContent(\n callbackData,\n triggerSrc,\n voiceHandler,\n botId\n );\n\n // 7. Handle unverified account logic (WXSubscription/WXService only)\n if (\n [\"WXSubscription\", \"WXService\"].includes(triggerSrc) &&\n !wxVerify &&\n !skipAI\n ) {\n const result = await agent.handleUnverifiedChat({\n content,\n conversation: replyMsgData.conversation,\n previousReply,\n callbackData,\n triggerSrc,\n });\n skipAI = result.needSkipAI;\n isEnd = result.isEnd;\n if (result.replyContent) replyMsgData.content = result.replyContent;\n }\n\n // 8. Early return: async reply already sent\n if (isEnd) {\n return res.json({});\n }\n\n // 9. Early return: empty content\n if (!content && !skipAI) {\n logger.warn?.(\"[WX] Empty content\");\n return res.json(\n formatWeChatReplyMessage(callbackData, triggerSrc, \"无法识别消息内容\")\n );\n }\n\n // 10. Early return: skipAI\n if (skipAI) {\n logger.info?.(\"[WX] Skipping AI\");\n return res.json(\n formatWeChatReplyMessage(\n callbackData,\n triggerSrc,\n replyMsgData.content\n )\n );\n }\n\n // 11. Prepare input for sendMessageAGUI.handler\n // History is auto-managed by adapter.run():\n // - Input message saved at start\n // - Reply saved at complete\n logger.info?.(\"[WX] Processing:\", content.substring(0, 100));\n const input = {\n messages: [\n {\n id: msgData.recordId,\n role: \"user\" as const,\n content,\n },\n ],\n state: undefined,\n threadId: msgData.conversation,\n runId: uuidv4(),\n tools: [],\n context: [],\n forwardedProps: {\n wxSendmessageInput,\n // Pass full msgData for history storage\n msgData: msgData,\n // Pass replay info with replyMsgData for assistant history\n replay: {\n id: replyMsgData.recordId,\n ...replyMsgData,\n },\n },\n };\n\n // 12. Call agent - WeChatAgentAdapter.run() handles:\n // - Message assembly (both modes)\n // - Message sending (async mode only)\n // - History saving (both modes)\n // - Error handling (async mode: sends error message)\n const events = agui.sendMessageAGUI.handler(input, agent);\n\n // 13. Consume events to trigger adapter processing\n for await (const event of events) {\n if (event.type === EventType.RUN_ERROR) {\n logger.error?.(\n \"[WX] Agent error:\",\n (event as any).error || (event as any).message\n );\n }\n }\n logger.info?.(\"[WX] Processing complete\");\n\n // 14. Return response - get assembled reply from agent\n if (replyMsgData.needAsyncReply) {\n // Async mode: message already sent by adapter\n return res.json({});\n }\n // Sync mode: get assembled reply from agent and return via HTTP\n const finalContent = agent.lastReply || \"抱歉,无法生成回复\";\n return res.json(\n formatWeChatReplyMessage(callbackData, triggerSrc, finalContent)\n );\n } catch (error) {\n logger.error?.(\"[WX] Error processing message:\", error);\n const message = error instanceof Error ? error.message : String(error);\n try {\n if (agent?.aitools?.sendWxClientMessage) {\n const data = formatWeChatReplyMessage(\n callbackData,\n triggerSrc,\n message\n );\n await agent.aitools.sendWxClientMessage(\n agent.agentId || botId,\n triggerSrc,\n {\n msgType: data.msgType,\n touser: data.toUserName,\n text: {\n content: data.content,\n },\n openKfId: data.openKfId,\n msgId: data.msgId,\n }\n );\n }\n } catch (e) {}\n return res.status(500).json({\n error: \"Internal Server Error\",\n message,\n });\n } finally {\n if (cleanup) cleanup();\n }\n };\n}\n","import {\n WeChatConfig,\n WeChatPlatform,\n AccessTokenResponse,\n TokenCacheEntry,\n} from \"./types\";\n\n/**\n * Token manager for WeChat access tokens\n * Handles token caching and automatic refresh\n */\nexport class TokenManager {\n private cache: Map<string, TokenCacheEntry> = new Map();\n\n /**\n * Get access token (with caching)\n */\n async getAccessToken(config: WeChatConfig): Promise<string> {\n const cacheKey = this.getCacheKey(config);\n const cached = this.cache.get(cacheKey);\n\n // Return cached token if still valid\n if (cached && cached.expiresAt > Date.now()) {\n return cached.accessToken;\n }\n\n // Fetch new token\n const token = await this.fetchAccessToken(config);\n return token;\n }\n\n /**\n * Fetch access token from WeChat API\n */\n private async fetchAccessToken(config: WeChatConfig): Promise<string> {\n const url = this.getTokenUrl(config);\n const response = await fetch(url);\n const data: AccessTokenResponse = await response.json();\n\n if (data.errcode && data.errcode !== 0) {\n throw new Error(`Failed to get access token: ${data.errmsg}`);\n }\n\n // Cache token with 5-minute early expiration\n const cacheKey = this.getCacheKey(config);\n const expiresAt = Date.now() + (data.expires_in - 300) * 1000;\n\n this.cache.set(cacheKey, {\n accessToken: data.access_token,\n expiresAt,\n });\n\n return data.access_token;\n }\n\n /**\n * Get token URL based on platform\n */\n private getTokenUrl(config: WeChatConfig): string {\n if (config.platform === WeChatPlatform.CUSTOM_SERVICE) {\n return `https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${config.appId}&corpsecret=${config.appSecret}`;\n }\n return `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${config.appId}&secret=${config.appSecret}`;\n }\n\n /**\n * Generate cache key\n */\n private getCacheKey(config: WeChatConfig): string {\n return `${config.platform}_${config.appId}`;\n }\n\n /**\n * Clear token cache\n */\n clearCache(config?: WeChatConfig): void {\n if (config) {\n this.cache.delete(this.getCacheKey(config));\n } else {\n this.cache.clear();\n }\n }\n}\n\n","import {\n MessageContent,\n SendMessageOptions,\n WeChatMessage,\n WeChatPlatform,\n MessageType,\n} from \"./types\";\n\n/**\n * Message formatter for different WeChat platforms\n */\nexport class MessageFormatter {\n /**\n * Format message for WeChat API\n */\n formatMessage(\n options: SendMessageOptions,\n platform: WeChatPlatform,\n originMsg?: any\n ): WeChatMessage {\n const { toUser, message, recommendQuestions, msgId } = options;\n let content = message.content;\n\n // Add recommended questions if provided\n if (recommendQuestions && recommendQuestions.length > 0) {\n content = this.withRecommendQuestions(content, recommendQuestions);\n }\n\n const baseMessage: WeChatMessage = {\n touser: toUser,\n msgtype: message.type,\n };\n\n // Format based on message type\n if (message.type === MessageType.TEXT) {\n baseMessage.text = { content };\n } else if (message.type === MessageType.IMAGE && message.imageUrl) {\n baseMessage.image = { pic_url: message.imageUrl };\n }\n\n // Add platform-specific fields\n if (platform === WeChatPlatform.CUSTOM_SERVICE) {\n baseMessage.open_kfid = originMsg?.open_kfid;\n baseMessage.msgid = msgId || originMsg?.msgid;\n }\n\n return baseMessage;\n }\n\n /**\n * Append recommended questions to content\n */\n private withRecommendQuestions(\n content: string,\n questions: string[]\n ): string {\n if (!questions || questions.length === 0) {\n return content;\n }\n return `${content}\\n\\n推荐问题:\\n${questions.join(\"\\n\")}`;\n }\n\n /**\n * Split long message into chunks\n */\n splitLongMessage(content: string, maxLength: number = 2000): string[] {\n if (content.length <= maxLength) {\n return [content];\n }\n\n const chunks: string[] = [];\n let currentChunk = \"\";\n\n const lines = content.split(\"\\n\");\n for (const line of lines) {\n if ((currentChunk + line).length > maxLength) {\n if (currentChunk) {\n chunks.push(currentChunk.trim());\n currentChunk = \"\";\n }\n // Handle lines longer than maxLength\n if (line.length > maxLength) {\n for (let i = 0; i < line.length; i += maxLength) {\n chunks.push(line.substring(i, i + maxLength));\n }\n } else {\n currentChunk = line + \"\\n\";\n }\n } else {\n currentChunk += line + \"\\n\";\n }\n }\n\n if (currentChunk) {\n chunks.push(currentChunk.trim());\n }\n\n return chunks;\n }\n}\n\n","import {\n WeChatConfig,\n WeChatMessage,\n WeChatPlatform,\n WeChatAPIResponse,\n} from \"./types\";\nimport { TokenManager } from \"./token-manager\";\n\n/**\n * Platform router for sending messages to different WeChat platforms\n */\nexport class PlatformRouter {\n private tokenManager: TokenManager;\n\n constructor(tokenManager: TokenManager) {\n this.tokenManager = tokenManager;\n }\n\n /**\n * Send message to WeChat platform\n */\n async send(\n message: WeChatMessage,\n config: WeChatConfig\n ): Promise<WeChatAPIResponse> {\n const accessToken = await this.tokenManager.getAccessToken(config);\n\n switch (config.platform) {\n case WeChatPlatform.CUSTOM_SERVICE:\n return this.sendToCustomService(message, accessToken, config);\n case WeChatPlatform.MINI_APP:\n return this.sendToMiniApp(message, accessToken);\n case WeChatPlatform.SERVICE:\n case WeChatPlatform.SUBSCRIPTION:\n return this.sendToOfficialAccount(message, accessToken);\n default:\n throw new Error(`Unsupported platform: ${config.platform}`);\n }\n }\n\n /**\n * Send to Enterprise WeChat Customer Service\n */\n private async sendToCustomService(\n message: WeChatMessage,\n accessToken: string,\n config: WeChatConfig\n ): Promise<WeChatAPIResponse> {\n const url = `https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n\n /**\n * Send to WeChat Mini Program\n */\n private async sendToMiniApp(\n message: WeChatMessage,\n accessToken: string\n ): Promise<WeChatAPIResponse> {\n const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n\n /**\n * Send to WeChat Official Account (Service/Subscription)\n */\n private async sendToOfficialAccount(\n message: WeChatMessage,\n accessToken: string\n ): Promise<WeChatAPIResponse> {\n const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n}\n\n","import { WeChatConfig, SendMessageOptions, WeChatAPIResponse } from \"./types\";\nimport { TokenManager } from \"./token-manager\";\nimport { MessageFormatter } from \"./message-formatter\";\nimport { PlatformRouter } from \"./platform-router\";\n\n/**\n * Main WeChat sender class\n * Provides a simple API to send LLM messages to WeChat platforms\n */\nexport class WeChatSender {\n private config: WeChatConfig;\n private tokenManager: TokenManager;\n private messageFormatter: MessageFormatter;\n private platformRouter: PlatformRouter;\n\n constructor(config: WeChatConfig) {\n // Validate config\n this.config = config;\n\n // Initialize components\n this.tokenManager = new TokenManager();\n this.messageFormatter = new MessageFormatter();\n this.platformRouter = new PlatformRouter(this.tokenManager);\n }\n\n /**\n * Send a message to WeChat\n */\n async send(\n options: SendMessageOptions,\n originMsg?: any\n ): Promise<WeChatAPIResponse> {\n // Validate options\n const validatedOptions = options;\n\n // Format message\n const message = this.messageFormatter.formatMessage(\n validatedOptions,\n this.config.platform,\n originMsg\n );\n\n // Send message\n const result = await this.platformRouter.send(message, this.config);\n\n // Check for errors\n if (result.errcode !== 0) {\n throw new Error(`Failed to send message: ${result.errmsg}`);\n }\n\n return result;\n }\n\n /**\n * Send multiple messages in batch\n */\n async sendBatch(\n messages: SendMessageOptions[]\n ): Promise<WeChatAPIResponse[]> {\n const results: WeChatAPIResponse[] = [];\n\n for (const message of messages) {\n try {\n const result = await this.send(message);\n results.push(result);\n } catch (error) {\n results.push({\n errcode: -1,\n errmsg: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n return results;\n }\n\n /**\n * Send message asynchronously (fire and forget)\n */\n async sendAsync(options: SendMessageOptions, originMsg?: any): Promise<void> {\n this.send(options, originMsg).catch((error) => {\n console.error(\"Failed to send message:\", error);\n });\n }\n\n /**\n * Clear token cache\n */\n clearCache(): void {\n this.tokenManager.clearCache(this.config);\n }\n\n /**\n * Get current configuration\n */\n getConfig(): WeChatConfig {\n return { ...this.config };\n }\n}\n","import {\n RunAgentInput,\n BaseEvent,\n EventType,\n AbstractAgent,\n AgentConfig,\n} from \"@ag-ui/client\";\nimport { Observable } from \"rxjs\";\nimport { WeChatSender } from \"./wechat-sender\";\nimport {\n WeChatConfig,\n SendMessageOptions,\n MessageType,\n WeChatSendMode,\n} from \"./types\";\nimport { WeChatHistoryManager, HistoryEntry } from \"./wechat-history-manager\";\nimport {\n handleWeChatRetry,\n isContinueCommandValid,\n formatWeChatReplyMessage,\n WeChatReplyMessage,\n} from \"./wechat-message-handler\";\nimport { aitools, WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\nimport { randomUUID } from \"crypto\";\n\nconst AITOOLS = aitools.AITools;\n\n/**\n * Configuration for WeChat Agent Adapter\n */\nexport interface WeChatAgentConfig extends AgentConfig {\n /**\n * The underlying agent to wrap\n */\n agent: AbstractAgent;\n\n /**\n * WeChat configuration\n */\n wechatConfig: WeChatConfig;\n\n /**\n * Optional: Custom message formatter\n * Converts agent output to WeChat message format\n */\n messageFormatter?: (content: string, event: BaseEvent) => SendMessageOptions;\n\n /**\n * Optional: Filter which events should trigger WeChat messages\n * Default: only TEXT_MESSAGE_CONTENT events\n */\n eventFilter?: (event: BaseEvent) => boolean;\n\n /**\n * Optional: Recommended questions to show after reply\n */\n recommendQuestions?: string[];\n\n /**\n * Optional: History manager for saving chat history\n * If not provided, will use singleton instance\n */\n historyManager?: WeChatHistoryManager;\n}\n\ninterface IWxRunAgentInput extends RunAgentInput {\n forwardedProps: {\n wxSendmessageInput: WxSendMessageInput;\n /** Full user message data from dealMsgData */\n msgData?: {\n recordId: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n };\n /** Reply metadata for assistant message */\n replay: {\n id: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n };\n };\n}\n\n/**\n * WeChat Agent Adapter\n *\n * Wraps any AbstractAgent and automatically sends its output to WeChat.\n * All methods are proxied to the underlying agent, with the run() method\n * enhanced to capture messages and send them via WeChat.\n *\n * @example\n * ```typescript\n * const myAgent = new SomeAgent({ ... });\n * const wechatAgent = new WeChatAgentAdapter({\n * agent: myAgent,\n * wechatConfig: {\n * platform: 'work',\n * corpId: 'xxx',\n * corpSecret: 'xxx'\n * }\n * });\n *\n * // Use it like any other agent\n * wechatAgent.run(input).subscribe(event => {\n * // Events are emitted normally\n * // AND automatically sent to WeChat\n * });\n * ```\n */\nexport class WeChatAgent extends AbstractAgent {\n private wrappedAgent: AbstractAgent;\n private wechatSender?: WeChatSender;\n private wechatConfig: WeChatConfig;\n private _historyManager: WeChatHistoryManager;\n private messageFormatter: (\n content: string,\n event: BaseEvent\n ) => SendMessageOptions;\n private eventFilter: (event: BaseEvent) => boolean;\n private messageBuffer: string = \"\";\n private recommendQuestions?: string[];\n public aitools?: aitools.AITools;\n\n constructor(config: WeChatAgentConfig) {\n super({\n agentId: config.agentId || config.agent.agentId,\n description: config.description || config.agent.description,\n threadId: config.threadId || config.agent.threadId,\n ...config,\n });\n\n this.wrappedAgent = config.agent;\n this.wechatConfig = config.wechatConfig;\n this.recommendQuestions = config.recommendQuestions;\n this._historyManager =\n config.historyManager || WeChatHistoryManager.getInstance();\n\n // Initialize sender based on send mode\n const sendMode = config.wechatConfig.sendMode || WeChatSendMode.LOCAL;\n\n if (sendMode === WeChatSendMode.AITOOLS) {\n // Use aitools SDK (for cloud function environment)\n if (!config.wechatConfig.context) {\n throw new Error(\"context is required when sendMode is AITOOLS\");\n }\n this.aitools = new AITOOLS(config.wechatConfig.context);\n } else {\n // Use local WeChatSender (for local development)\n this.wechatSender = new WeChatSender(config.wechatConfig);\n }\n\n // Default message formatter\n this.messageFormatter =\n config.messageFormatter ||\n ((content: string) => ({\n toUser: \"\", // Will be set from originMsg\n message: {\n content: content,\n type: MessageType.TEXT,\n },\n recommendQuestions: this.recommendQuestions,\n }));\n\n // Default event filter: only TEXT_MESSAGE_CONTENT\n this.eventFilter =\n config.eventFilter ||\n ((event: BaseEvent) => event.type === EventType.TEXT_MESSAGE_CONTENT);\n }\n\n /**\n * Last assembled reply content after run() completes\n * Controller can read this instead of re-assembling from events\n */\n public lastReply: string = \"\";\n\n /**\n * Whether last run had an error\n */\n public lastRunHadError: boolean = false;\n\n /**\n * Get previous reply from history\n * Used for: retry detection, \"继续\" command\n */\n async getPreviousReply(\n conversation: string,\n recordId?: string | null\n ): Promise<HistoryEntry | null> {\n return this._historyManager.getPreviousReply(conversation, recordId);\n }\n\n /**\n * Update message content in history\n */\n async updateHistoryContent(\n messageId: string,\n content: string,\n threadId: string\n ): Promise<void> {\n await this._historyManager.updateContent(threadId, messageId, content);\n }\n\n /**\n * Handle unverified account logic (WXSubscription/WXService)\n * Handles \"继续\" command and 11-second retry\n * Uses existing functions from wechat-message-handler.ts\n * @returns { needSkipAI, replyContent, isEnd }\n */\n async handleUnverifiedChat(params: {\n content: string;\n conversation: string;\n previousReply: HistoryEntry | null;\n callbackData: WxSendMessageInput;\n triggerSrc: string;\n }): Promise<{ needSkipAI: boolean; replyContent: string; isEnd: boolean }> {\n const { content, conversation, previousReply, callbackData, triggerSrc } =\n params;\n\n // Check if async reply already sent (for retry scenario)\n if (previousReply && previousReply.needAsyncReply) {\n return { needSkipAI: true, replyContent: \"\", isEnd: true };\n }\n\n // Handle \"继续\" command\n if (content === \"continue\" || content === \"继续\") {\n const latest = await this._historyManager.getPreviousReply(conversation);\n let replyContent = \"\";\n\n if (!latest) {\n replyContent = \"未找到相关回答,请先发送消息\";\n } else if (isContinueCommandValid(latest)) {\n replyContent = latest.content || '正在思考中,请稍后再回复\"继续\"';\n } else {\n replyContent = \"回答已过期,请重新发送消息\";\n }\n\n return { needSkipAI: true, replyContent, isEnd: false };\n }\n\n // Handle 11-second retry using existing function\n if (previousReply) {\n const result = await handleWeChatRetry(\n previousReply,\n callbackData,\n triggerSrc as any\n );\n return {\n needSkipAI: result.shouldSkip,\n replyContent: result.content || \"\",\n isEnd: false,\n };\n }\n\n return { needSkipAI: false, replyContent: \"\", isEnd: false };\n }\n\n /**\n * Run method with WeChat integration\n * Wraps the underlying agent's run() and sends messages to WeChat\n */\n run(input: IWxRunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber: any) => {\n this.messageBuffer = \"\";\n this.lastReply = \"\";\n this.lastRunHadError = false;\n let errorMessage = \"\";\n let subscription: any;\n\n const replyId = input?.forwardedProps?.replay.id || randomUUID();\n Promise.all([\n this.saveInputToHistory(input),\n this.saveReplyToHistory(\n {\n id: replyId,\n content: this.lastReply,\n },\n input\n ),\n ]).then(\n () => {\n // Subscribe to the wrapped agent's events\n subscription = this.wrappedAgent.run(input).subscribe({\n next: (event: BaseEvent) => {\n // Emit the event to our subscribers\n subscriber.next(event);\n\n // Track if error occurred and capture error message\n if (event.type === EventType.RUN_ERROR) {\n this.lastRunHadError = true;\n const errorEvent = event as any;\n errorMessage =\n errorEvent.message ||\n errorEvent.error?.message ||\n \"处理消息时发生错误,请稍后重试\";\n }\n\n // Handle WeChat sending\n this.handleWeChatSending(event, input);\n },\n error: (error: any) => {\n subscriber.error(error);\n },\n complete: () => {\n // Set lastReply for controller to read\n this.lastReply = this.lastRunHadError\n ? errorMessage\n : this.messageBuffer.trim() || \"\";\n\n // Send final message if buffer has content and no error occurred\n // (error message already sent in handleWeChatSending)\n if (this.messageBuffer.trim() && !this.lastRunHadError) {\n this.sendToWeChat(this.messageBuffer, input).catch(\n console.error\n );\n }\n\n // Auto-save reply to history at complete\n this.saveReplyToHistory(\n {\n id: input?.forwardedProps?.replay.id || randomUUID(),\n content: this.lastReply,\n },\n input\n ).catch(console.error);\n\n subscriber.complete();\n },\n });\n },\n (e) => {\n subscriber.error(e);\n }\n );\n\n // Return cleanup function\n return () => {\n subscription?.unsubscribe();\n };\n });\n }\n\n /**\n * Save input message to history at the start of run()\n * Only saves if the last message is from user role\n * Uses msgData from forwardedProps for complete data (similar to dealMsgData)\n */\n private async saveInputToHistory(input: IWxRunAgentInput): Promise<void> {\n const messages = input.messages;\n if (!messages || messages.length === 0) return;\n\n // Only process if the last message is from user\n const lastMessage = messages[messages.length - 1];\n if (lastMessage.role !== \"user\") return;\n\n const { threadId, runId } = input;\n const msgData = input.forwardedProps?.msgData;\n\n // Use msgData.recordId if available, otherwise fallback to lastMessage.id\n const messageId =\n msgData?.recordId ||\n lastMessage.id ||\n (lastMessage as any).messageId ||\n randomUUID();\n\n // Extract content from the last user message\n const rawContent = lastMessage.content;\n const content =\n typeof rawContent === \"string\"\n ? rawContent\n : Array.isArray(rawContent)\n ? rawContent\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\")\n : \"\";\n\n if (threadId && content) {\n await this._historyManager.saveToHistory({\n messageId,\n role: \"user\",\n content,\n threadId,\n runId,\n createdAt: msgData?.createdAt || Date.now(),\n // Additional fields from msgData (similar to dealMsgData)\n botId: msgData?.botId,\n needAsyncReply: msgData?.needAsyncReply,\n type: msgData?.type,\n metadata: {\n sender: msgData?.sender,\n triggerSrc: msgData?.triggerSrc,\n originMsg: msgData?.originMsg,\n reply: msgData?.reply,\n recommendQuestions: msgData?.recommendQuestions,\n },\n });\n }\n }\n\n /**\n * Handle WeChat message sending based on events\n */\n private handleWeChatSending(event: BaseEvent, input: IWxRunAgentInput): void {\n // Always handle RUN_ERROR regardless of eventFilter\n if (event.type === EventType.RUN_ERROR) {\n const errorEvent = event as any;\n const errorMessage =\n errorEvent.message ||\n errorEvent.error?.message ||\n \"处理消息时发生错误,请稍后重试\";\n // Clear buffer to prevent duplicate sending\n this.messageBuffer = \"\";\n // Send error message to WeChat\n this.sendToWeChat(errorMessage, input).catch(console.error);\n return;\n }\n\n // Check if this event should trigger WeChat sending\n if (!this.eventFilter(event)) {\n return;\n }\n\n // Handle different event types\n switch (event.type) {\n case EventType.TEXT_MESSAGE_CONTENT:\n // Accumulate text content\n const content = (event as any).delta || (event as any).content || \"\";\n this.messageBuffer += content;\n break;\n\n case EventType.TEXT_MESSAGE_END:\n // Send accumulated message\n if (this.messageBuffer.trim()) {\n this.sendToWeChat(this.messageBuffer, input).catch(console.error);\n this.messageBuffer = \"\";\n }\n break;\n }\n }\n\n /**\n * Send message to WeChat and save to history\n * Only sends in async mode (needAsyncReply=true)\n * For sync mode, message is returned via HTTP response by controller\n */\n private async sendToWeChat(\n content: string,\n input: IWxRunAgentInput\n ): Promise<void> {\n try {\n // Check if async reply is needed from originMsg\n const needAsyncReply =\n input.forwardedProps?.replay.needAsyncReply ?? true;\n\n // Only send via adapter in async mode\n // In sync mode, controller handles returning the message via HTTP response\n if (needAsyncReply) {\n const sendMode = this.wechatConfig.sendMode || WeChatSendMode.AITOOLS;\n\n if (sendMode === WeChatSendMode.AITOOLS) {\n // Use aitools SDK to send message\n await this.sendViaAITools(content, input);\n } else {\n // Use local WeChatSender to send message\n await this.sendViaLocalSender(content, input);\n }\n }\n } catch (error) {\n console.error(\"Failed to send message to WeChat:\", error);\n }\n }\n\n /**\n * Save reply content to history\n * Uses replay metadata from forwardedProps for complete data (similar to dealMsgData)\n */\n private async saveReplyToHistory(\n reply: { id: string; content: string },\n input: IWxRunAgentInput\n ): Promise<void> {\n const { threadId, runId } = input;\n const replay = input.forwardedProps?.replay;\n const msgData = input.forwardedProps?.msgData;\n\n const messageId = reply.id;\n\n if (threadId && messageId) {\n await this._historyManager.saveToHistory({\n id: messageId,\n messageId,\n role: \"assistant\",\n content: reply.content,\n threadId,\n runId,\n createdAt: Date.now(),\n // Additional fields from replay/msgData (similar to dealMsgData replyMsgData)\n botId: replay?.botId || msgData?.botId,\n needAsyncReply: replay?.needAsyncReply,\n type: replay?.type || \"text\",\n metadata: {\n sender: replay?.sender || msgData?.sender,\n triggerSrc: replay?.triggerSrc || msgData?.triggerSrc,\n // For assistant, reply field is empty, replyTo points to user message\n replyTo: (replay as any)?.replyTo || msgData?.recordId,\n originMsg: replay?.originMsg,\n reply: replay?.reply,\n recommendQuestions: replay?.recommendQuestions,\n },\n });\n }\n }\n\n /**\n * Send message via aitools SDK (for cloud function environment)\n */\n private async sendViaAITools(\n content: string,\n input: IWxRunAgentInput\n ): Promise<void> {\n if (!this.aitools) {\n throw new Error(\"aitools is not initialized\");\n }\n\n // Get origin message from forwardedProps\n const wxSendmessageInput = input.forwardedProps?.wxSendmessageInput;\n if (!wxSendmessageInput) {\n console.warn(\n \"wxSendmessageInput not found in forwardedProps, skipping aitools send\"\n );\n return;\n }\n\n // Process reply message to get correct format for different platforms\n const toWxMsgData = this.processReplyMsg(wxSendmessageInput, content);\n if (!toWxMsgData) {\n console.warn(\"Failed to process reply message, skipping send\");\n return;\n }\n\n // Extract trigger source\n const triggerSrc =\n wxSendmessageInput.triggerSrc || this.wechatConfig.platform;\n\n // Send message using aitools\n await this.aitools.sendWxClientMessage(\n this.agentId || \"agent\",\n triggerSrc,\n {\n msgType: toWxMsgData.msgType,\n touser: toWxMsgData.toUserName,\n text: {\n content: toWxMsgData.content,\n },\n openKfId: toWxMsgData.openKfId,\n msgId: toWxMsgData.msgId || \"\",\n }\n );\n }\n\n /**\n * Format reply message for WeChat HTTP response (sync mode)\n * Public method for controller to use\n */\n formatReplyMessage(\n callbackData: any,\n triggerSrc: string,\n content: string\n ): WeChatReplyMessage {\n return formatWeChatReplyMessage(callbackData, triggerSrc, content);\n }\n\n /**\n * Process reply message to get correct format for different WeChat platforms\n * Based on chat_wx.service.ts processReplyMsg implementation\n */\n private processReplyMsg(\n wxSendMessageInput: WxSendMessageInput,\n content: string\n ) {\n const triggerSrc =\n wxSendMessageInput.triggerSrc || this.wechatConfig.platform;\n const callbackData: any = wxSendMessageInput.callbackData;\n\n return formatWeChatReplyMessage(callbackData, triggerSrc, content);\n }\n\n /**\n * Send message via local WeChatSender (for local development)\n */\n private async sendViaLocalSender(\n content: string,\n input: RunAgentInput\n ): Promise<void> {\n if (!this.wechatSender) {\n throw new Error(\"wechatSender is not initialized\");\n }\n\n const messageOptions = this.messageFormatter(content, {\n type: EventType.TEXT_MESSAGE_CONTENT,\n content,\n } as any);\n\n // Get origin message from forwardedProps if available\n const originMsg = input.forwardedProps?.originMsg;\n\n await this.wechatSender.send(messageOptions, originMsg);\n }\n}\n","/**\n * WeChat Chat History Manager\n * Manages chat history for \"continue\" command and retry logic\n * Uses CloudBase database storage\n */\n\nimport tcb from \"@cloudbase/node-sdk\";\n\n// Re-export ChatHistoryRecord for convenience\nexport type { ChatHistoryRecord } from \"./wechat-message-handler\";\n\n/** Default collection name for chat history */\nexport const WX_CHAT_HISTORY_COLLECTION = \"wx_chat_history\";\n\n/**\n * Message role type\n */\nexport type MessageRole = \"user\" | \"assistant\" | \"system\";\n\n/**\n * Metadata for history entry (stored in metadata field)\n */\nexport interface HistoryEntryMetadata {\n /** Sender identifier */\n sender?: string;\n /** Trigger source (WXSubscription, WXService, etc.) */\n triggerSrc?: string;\n /** Original message data */\n originMsg?: string;\n /** Reply to message ID */\n replyTo?: string;\n /** Reply message ID */\n reply?: string;\n /** Image URL if applicable */\n image?: string;\n /** Recommended questions */\n recommendQuestions?: string[];\n}\n\n/**\n * History entry for storage\n * Contains message info plus optional metadata\n */\nexport interface HistoryEntry {\n id?: string;\n /** Unique message ID (record_id in database) */\n messageId: string;\n /** Message role: user, assistant, or system */\n role: MessageRole;\n /** Message content */\n content?: string;\n /** Thread/Conversation ID */\n threadId: string;\n /** Creation timestamp */\n createdAt: number;\n /** Bot ID */\n botId?: string;\n /** Run ID for tracking agent runs */\n runId?: string;\n /** Whether async reply is needed (WeChat specific) */\n needAsyncReply?: boolean;\n /** Message status: pending, done, error, cancel */\n status?: string;\n /** Message type */\n type?: string;\n /** Additional metadata */\n metadata?: HistoryEntryMetadata;\n}\n\n/**\n * Database document structure (snake_case for CloudBase)\n */\ninterface ChatHistoryData {\n _id?: string;\n bot_id: string;\n record_id: string;\n role: string;\n status?: string;\n content?: string;\n conversation: string;\n type?: string;\n trace_id?: string;\n async_reply?: boolean;\n metadata?: HistoryEntryMetadata;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface HistoryManagerConfig {\n /** CloudBase environment ID */\n envId?: string;\n /** CloudBase secret ID */\n secretId?: string;\n /** CloudBase secret key */\n secretKey?: string;\n /** CloudBase session token */\n token?: string;\n /** Collection name, default: wx_chat_history */\n collectionName?: string;\n /** Bot ID for filtering */\n botId?: string;\n}\n\n/**\n * Transform HistoryEntry to database document format\n */\nfunction entryToData(entry: HistoryEntry): Omit<ChatHistoryData, \"_id\"> {\n return {\n bot_id: entry.botId || \"\",\n record_id: entry.messageId,\n role: entry.role,\n status: entry.status,\n content: entry.content,\n conversation: entry.threadId,\n type: entry.type,\n trace_id: entry.runId,\n async_reply: entry.needAsyncReply,\n metadata: entry.metadata,\n createdAt: entry.createdAt || Date.now(),\n updatedAt: Date.now(),\n };\n}\n\n/**\n * Transform database document to HistoryEntry\n */\nfunction dataToEntry(data: ChatHistoryData): HistoryEntry {\n return {\n id: data._id,\n messageId: data.record_id,\n role: data.role as MessageRole,\n content: data.content,\n threadId: data.conversation,\n createdAt: data.createdAt,\n botId: data.bot_id,\n runId: data.trace_id,\n needAsyncReply: data.async_reply,\n status: data.status,\n type: data.type,\n metadata: data.metadata,\n };\n}\n\n/**\n * WeChat History Manager\n * Uses CloudBase database storage\n * Singleton pattern for shared history across adapter and controller\n */\nexport class WeChatHistoryManager {\n private static instance: WeChatHistoryManager;\n private tcbClient: tcb.CloudBase;\n private collectionName: string;\n private botId: string;\n private collectionReady = false;\n\n private constructor(config?: HistoryManagerConfig) {\n this.collectionName = config?.collectionName || WX_CHAT_HISTORY_COLLECTION;\n this.botId = config?.botId || \"default\";\n\n // Initialize CloudBase client\n const envId =\n config?.envId || process.env.TCB_ENV || process.env.CLOUDBASE_ENV;\n if (!envId) {\n throw new Error(\n \"[WeChatHistoryManager] envId is required. Set TCB_ENV or CLOUDBASE_ENV environment variable, or pass envId in config.\"\n );\n }\n\n this.tcbClient = tcb.init({\n env: envId,\n secretId: config?.secretId,\n secretKey: config?.secretKey,\n sessionToken: config?.token,\n });\n }\n\n static getInstance(config?: HistoryManagerConfig): WeChatHistoryManager {\n if (!WeChatHistoryManager.instance) {\n WeChatHistoryManager.instance = new WeChatHistoryManager(config);\n }\n return WeChatHistoryManager.instance;\n }\n\n /**\n * Ensure collection exists, create if not\n */\n private async ensureCollection(): Promise<void> {\n if (this.collectionReady) return;\n\n try {\n const db = this.tcbClient.database();\n await db.createCollection(this.collectionName);\n this.collectionReady = true;\n } catch (error: any) {\n // Collection already exists (error code -502005)\n if (error?.code === \"DATABASE_COLLECTION_ALREADY_EXIST\") {\n this.collectionReady = true;\n } else {\n console.error(\n \"[WeChatHistoryManager] Failed to create collection:\",\n error\n );\n throw error;\n }\n }\n }\n\n /**\n * Get previous reply from history\n */\n async getPreviousReply(\n threadId: string,\n messageId?: string | null\n ): Promise<HistoryEntry | null> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n const whereCondition: Record<string, any> = {\n conversation: _.eq(threadId),\n };\n\n if (messageId) {\n whereCondition.record_id = _.eq(messageId);\n }\n\n const result = await collection\n .where(whereCondition)\n .orderBy(\"createdAt\", \"desc\")\n .limit(1)\n .get();\n\n if (result.data && result.data.length > 0) {\n return dataToEntry(result.data[0] as ChatHistoryData);\n }\n return null;\n }\n\n /**\n * Save record to history\n */\n async saveToHistory(record: HistoryEntry): Promise<void> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n // Check if record exists\n const existing = await collection\n .where({ record_id: _.eq(record.messageId) })\n .limit(1)\n .get();\n\n const data = entryToData({ ...record, botId: record.botId || this.botId });\n\n if (existing.data && existing.data.length > 0) {\n // Update existing record\n await collection\n .where({ record_id: _.eq(record.messageId) })\n .update(data);\n } else {\n // Add new record\n await collection.add(data);\n }\n }\n\n /**\n * Update record content by messageId\n */\n async updateContent(\n _threadId: string,\n messageId: string,\n content: string\n ): Promise<void> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n await collection.where({ record_id: _.eq(messageId) }).update({\n content,\n updatedAt: Date.now(),\n });\n }\n\n}\n\n// Export singleton getter for convenience\nexport const getHistoryManager = WeChatHistoryManager.getInstance;\n"],"mappings":"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","names":["WeChatPlatform","MessageType","WeChatSendMode","noopLogger","EventType","EventType","needAsyncReply"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/wechat-message-handler.ts","../src/server/wx.controller.ts","../src/token-manager.ts","../src/message-formatter.ts","../src/platform-router.ts","../src/wechat-sender.ts","../src/agent.ts","../src/wechat-history-manager.ts"],"sourcesContent":["/**\n * WeChat platform types\n */\nexport enum WeChatPlatform {\n /** 企业微信客服 */\n CUSTOM_SERVICE = \"WXCustomerService\",\n /** 微信小程序 */\n MINI_APP = \"WXMiniapp\",\n /** 微信服务号 */\n SERVICE = \"WXService\",\n /** 微信订阅号 */\n SUBSCRIPTION = \"WXSubscription\",\n}\n\n/**\n * Message types\n */\nexport enum MessageType {\n TEXT = \"text\",\n IMAGE = \"image\",\n EVENT = \"event\",\n VOICE = \"voice\",\n}\n\n/**\n * WeChat send mode\n */\nexport enum WeChatSendMode {\n /** Use local WeChatSender (for local development) */\n LOCAL = \"local\",\n /** Use aitools SDK (for cloud function environment) */\n AITOOLS = \"aitools\",\n}\n\nexport interface WeChatConfig {\n platform: WeChatPlatform;\n appId: string;\n appSecret: string;\n openKfId?: string;\n tokenCacheTTL?: number;\n sendMode?: WeChatSendMode;\n context?: any;\n}\n\nexport interface MessageContent {\n content: string;\n type: MessageType;\n imageUrl?: string;\n}\n\nexport interface SendMessageOptions {\n toUser: string;\n message: MessageContent;\n recommendQuestions?: string[];\n msgId?: string;\n}\n\nexport interface AccessTokenResponse {\n access_token: string;\n expires_in: number;\n errcode?: number;\n errmsg?: string;\n}\n\nexport interface WeChatAPIResponse {\n errcode: number;\n errmsg: string;\n [key: string]: any;\n}\n\nexport interface TokenCacheEntry {\n accessToken: string;\n expiresAt: number;\n}\n\nexport interface WeChatMessage {\n touser: string;\n msgtype: string;\n text?: { content: string };\n image?: { media_id?: string; pic_url?: string };\n open_kfid?: string;\n msgid?: string;\n}\n","/**\n * WeChat Message Handler - 微信消息处理工具\n *\n * 处理调用模型之前的所有逻辑:\n * - 消息类型校验\n * - 内容提取\n * - 消息数据生成\n * - 发送者/会话提取\n */\n\nimport { WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\nimport { HistoryEntry } from \"./wechat-history-manager\";\nimport { WeChatPlatform } from \"./types\";\n\n// ============================================================================\n// Types - 类型定义\n// ============================================================================\n\n/**\n * WeChat message input - 微信公众号/服务号/小程序消息\n */\nexport interface WeChatCommonInput {\n toUserName: string;\n fromUserName: string;\n createTime: number;\n msgType: string;\n msgId: string;\n content?: string; // 文本消息\n mediaId?: string; // 语音消息\n recognition?: string; // 语音识别结果\n}\n\n/**\n * WeChat Work customer service message input - 企业微信客服消息\n */\nexport interface WeChatWorkCommonInput {\n toUserName?: string;\n externalUserId: string;\n openKfId: string;\n msgType: string;\n msgId: string;\n sendTime: number;\n text?: { content: string };\n voice?: { mediaId: string };\n}\n\n/**\n * Supported trigger sources - 支持的触发源\n */\nexport type WeChatTriggerSrc =\n | WeChatPlatform.SUBSCRIPTION // 微信订阅号\n | WeChatPlatform.SERVICE // 微信服务号\n | WeChatPlatform.MINI_APP // 微信小程序\n | WeChatPlatform.CUSTOM_SERVICE; // 企业微信客服\n\n/**\n * Supported message types - 支持的消息类型\n */\nexport const SUPPORTED_MSG_TYPES = [\"text\", \"voice\"] as const;\nexport type SupportedMsgType = (typeof SUPPORTED_MSG_TYPES)[number];\n\n/**\n * Chat history record - 聊天历史记录\n */\nexport interface ChatHistoryRecord {\n recordId: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n // Optional fields\n image?: string;\n status?: string;\n traceId?: string;\n asyncReply?: string;\n replyTo?: string;\n event?: string;\n}\n\n/**\n * Processed message data - 处理后的消息数据\n */\nexport interface ProcessedMsgData {\n msgData: ChatHistoryRecord;\n replyMsgData: ChatHistoryRecord;\n}\n\n/**\n * Message validation result - 消息校验结果\n */\nexport interface MessageValidationResult {\n isValid: boolean;\n skipAI: boolean;\n errorMessage?: string;\n userErrorMessage?: string;\n}\n\n/**\n * Voice message handler type - 语音消息处理器类型\n */\nexport type VoiceMessageHandler = (\n botId: string,\n triggerSrc: string,\n mediaId: string\n) => Promise<{ content: string } | null>;\n\n// ============================================================================\n// Message Validation - 消息校验\n// ============================================================================\n\n/**\n * Validate message type - 校验消息类型\n */\nexport function validateMessageType(msgType: string): MessageValidationResult {\n if (SUPPORTED_MSG_TYPES.includes(msgType as SupportedMsgType)) {\n return { isValid: true, skipAI: false };\n }\n return {\n isValid: false,\n skipAI: true,\n errorMessage: `无法处理的消息类型:${msgType}`,\n userErrorMessage: \"抱歉暂时无法处理这个类型的消息\",\n };\n}\n\n/**\n * Extract message type from origin message - 从原始消息提取消息类型\n */\nexport function extractMsgType(originMsg: any): string {\n return originMsg.msgType || originMsg.MsgType || \"text\";\n}\n\n/**\n * Extract trigger source from origin message - 从原始消息提取触发源\n */\nexport function extractTriggerSrc(\n originMsg: any,\n defaultSrc: WeChatTriggerSrc = WeChatPlatform.SERVICE\n): WeChatTriggerSrc {\n return originMsg.triggerSrc || defaultSrc;\n}\n\n// ============================================================================\n// Content Extraction - 内容提取\n// ============================================================================\n\n/**\n * Extract text content from WeChat message - 从微信消息提取文本内容\n */\nexport function extractTextContent(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.Content || originMsg.content || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.text?.content || \"\";\n }\n return \"\";\n}\n\n/**\n * Extract voice media ID from WeChat message - 从微信消息提取语音媒体ID\n */\nexport function extractVoiceMediaId(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [WeChatPlatform.SUBSCRIPTION, WeChatPlatform.SERVICE].includes(triggerSrc)\n ) {\n return originMsg.MediaId || originMsg.mediaId || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.voice?.mediaId || \"\";\n }\n return \"\";\n}\n\n/**\n * Get content from WeChat message (text or voice) - 获取微信消息内容\n */\nexport async function getWxChatContent(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc,\n voiceMessageHandler?: VoiceMessageHandler,\n botId?: string\n): Promise<string> {\n const msgType = extractMsgType(originMsg);\n\n // Text message\n if (msgType === \"text\") {\n return extractTextContent(originMsg, triggerSrc);\n }\n\n // Voice message\n if (msgType === \"voice\") {\n const mediaId = extractVoiceMediaId(originMsg, triggerSrc);\n if (voiceMessageHandler && mediaId && botId) {\n const result = await voiceMessageHandler(botId, triggerSrc, mediaId);\n return result?.content || \"\";\n }\n }\n\n return \"\";\n}\n\n// ============================================================================\n// Sender & Conversation Extraction - 发送者和会话提取\n// ============================================================================\n\n/**\n * Extract sender from origin message - 从原始消息提取发送者\n */\nexport function extractSender(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.FromUserName || originMsg.fromUserName || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.externalUserId || \"\";\n }\n return \"\";\n}\n\n/**\n * Extract conversation ID from origin message - 从原始消息提取会话ID\n */\nexport function extractConversation(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): string {\n if (\n [\n WeChatPlatform.SUBSCRIPTION,\n WeChatPlatform.SERVICE,\n WeChatPlatform.MINI_APP,\n ].includes(triggerSrc)\n ) {\n return originMsg.FromUserName || originMsg.fromUserName || \"\";\n } else if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.externalUserId || \"\";\n }\n return \"\";\n}\n\n// ============================================================================\n// Record ID Generation - 记录ID生成\n// ============================================================================\n\n/**\n * Generate record ID - 生成记录ID\n */\nexport function generateRecordId(\n triggerSrc: WeChatTriggerSrc,\n msgId: string,\n timestamp: number\n): string {\n return `${triggerSrc}${msgId}${timestamp}`;\n}\n\n/**\n * Extract message ID from origin message - 从原始消息提取消息ID\n */\nexport function extractMsgId(originMsg: any): string {\n return originMsg.msgId || originMsg.MsgId || Date.now().toString();\n}\n\n/**\n * Extract timestamp from origin message - 从原始消息提取时间戳\n */\nexport function extractTimestamp(\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): number {\n if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return originMsg.sendTime || Math.floor(Date.now() / 1000);\n }\n return (\n originMsg.createTime ||\n originMsg.CreateTime ||\n Math.floor(Date.now() / 1000)\n );\n}\n\n// ============================================================================\n// Async Reply Logic - 异步回复逻辑\n// ============================================================================\n\n/**\n * Determine if async reply is needed - 判断是否需要异步回复\n */\nexport function needAsyncReply(\n triggerSrc: WeChatTriggerSrc,\n wxVerify: boolean\n): boolean {\n // 小程序和企业微信客服始终异步\n if (\n [WeChatPlatform.MINI_APP, WeChatPlatform.CUSTOM_SERVICE].includes(\n triggerSrc\n )\n ) {\n return true;\n }\n // 公众号/服务号根据认证状态决定\n return wxVerify;\n}\n\n// ============================================================================\n// Reply Message Formatting - 回复消息格式化\n// ============================================================================\n\n/**\n * WeChat reply message structure\n */\nexport interface WeChatReplyMessage {\n toUserName: string;\n fromUserName: string;\n createTime: number;\n msgType: string;\n content: string;\n msgId: string;\n openKfId?: string;\n}\n\n/**\n * Format reply message for WeChat\n * Used for both sync HTTP response and async aitools sending\n */\nexport function formatWeChatReplyMessage(\n callbackData: any,\n triggerSrc: string,\n content: string\n): WeChatReplyMessage {\n const createTime = Math.floor(Date.now() / 1000);\n const finalContent = content || \"抱歉暂时无法处理这个类型的消息\";\n\n // WeChat Work Customer Service\n if (triggerSrc === WeChatPlatform.CUSTOM_SERVICE) {\n return {\n toUserName: callbackData.externalUserId || callbackData.fromUserName,\n fromUserName: callbackData.openKfId,\n openKfId: callbackData.openKfId,\n createTime,\n msgType: \"text\",\n content: finalContent,\n msgId: callbackData.msgId,\n };\n }\n\n // WeChat Official Account / Service Account / Mini Program\n return {\n toUserName: callbackData.fromUserName || callbackData.FromUserName,\n fromUserName: callbackData.toUserName || callbackData.ToUserName,\n createTime,\n msgType: \"text\",\n content: finalContent,\n msgId: callbackData.msgId,\n };\n}\n\n// ============================================================================\n// Deal Message Data - 消息数据处理(核心方法)\n// ============================================================================\n\n/**\n * Deal message data - 处理微信消息,生成 msgData 和 replyMsgData\n * 完整实现原 chat_wx.service.ts 中的 dealMsgData 逻辑\n */\nexport function dealMsgData(\n originMsg: WxSendMessageInput[\"callbackData\"],\n triggerSrc: WeChatTriggerSrc,\n wxVerify: boolean,\n botId: string\n): ProcessedMsgData {\n const baseMsgData = {\n type: \"text\",\n triggerSrc: triggerSrc,\n botId: botId,\n recommendQuestions: [] as string[],\n content: \"\",\n originMsg: \"\",\n createdAt: Date.now(),\n };\n\n const sender = extractSender(originMsg, triggerSrc);\n const conversation = extractConversation(originMsg, triggerSrc);\n const msgId = extractMsgId(originMsg);\n const timestamp = extractTimestamp(originMsg, triggerSrc);\n const recordIdBase = generateRecordId(triggerSrc, msgId, timestamp);\n const asyncReply = needAsyncReply(triggerSrc, wxVerify);\n const msgType = extractMsgType(originMsg);\n\n return {\n msgData: {\n ...baseMsgData,\n recordId: `user-${recordIdBase}`,\n role: \"user\" as const,\n sender: sender,\n conversation: conversation,\n type: msgType,\n needAsyncReply: asyncReply,\n reply: recordIdBase,\n originMsg: JSON.stringify(originMsg),\n },\n replyMsgData: {\n ...baseMsgData,\n recordId: recordIdBase,\n role: \"assistant\" as const,\n sender: sender,\n conversation: conversation,\n type: \"text\",\n needAsyncReply: asyncReply,\n reply: \"\",\n originMsg: JSON.stringify({}),\n },\n };\n}\n\n// ============================================================================\n// WeChat Retry Logic - 微信重试逻辑\n// ============================================================================\n\n/**\n * Handle WeChat retry for unverified accounts (11-second rule)\n * 处理未认证账号的微信重试逻辑(11秒规则)\n */\nexport async function handleWeChatRetry(\n previousReply: HistoryEntry | null,\n originMsg: any,\n triggerSrc: WeChatTriggerSrc\n): Promise<{ shouldSkip: boolean; content?: string }> {\n if (!previousReply) {\n return { shouldSkip: false };\n }\n\n const timestamp = extractTimestamp(originMsg, triggerSrc);\n const deltaTime = Date.now() - timestamp * 1000;\n\n // If already has content, return it\n if (previousReply.content) {\n return {\n shouldSkip: true,\n content: previousReply.content,\n };\n }\n\n // If more than 11 seconds, return status message\n if (deltaTime > 11 * 1000) {\n return {\n shouldSkip: true,\n content: '思考中,请稍后回复 \"继续\" 来获取回答内容',\n };\n }\n\n // Less than 11 seconds, sleep 5s to timeout (WeChat will retry)\n await new Promise((resolve) => setTimeout(resolve, 5000));\n return { shouldSkip: true };\n}\n\n/**\n * Check if \"继续\" command is within 5-minute timeout\n * 检查\"继续\"命令是否在5分钟超时内\n */\nexport function isContinueCommandValid(\n previousReply: HistoryEntry | null\n): boolean {\n if (!previousReply) {\n return false;\n }\n const fiveMinutes = 5 * 60 * 1000;\n return Date.now() - previousReply.createdAt < fiveMinutes;\n}\n","/**\n * WeChat Message Controller\n * Using @cloudbase/agent-adapter-wx for message processing\n * Directly using sendMessageAGUI handler from @cloudbase/agent-server\n */\n\nimport type { Request, Response } from \"express\";\nimport {\n validateMessageType,\n extractMsgType,\n getWxChatContent,\n dealMsgData,\n formatWeChatReplyMessage,\n VoiceMessageHandler,\n WeChatTriggerSrc,\n} from \"../wechat-message-handler\";\nimport { WeChatAgent } from \"../agent\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport { agui } from \"@cloudbase/agent-server\";\nimport type { Logger } from \"@cloudbase/agent-shared\";\nimport { noopLogger } from \"@cloudbase/agent-shared\";\nimport { EventType } from \"@ag-ui/client\";\nexport {\n type Logger,\n type LogFn,\n noopLogger,\n createConsoleLogger,\n} from \"@cloudbase/agent-shared\";\n\nimport { AbstractAgent } from \"@ag-ui/client\";\nimport { utils, WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\n\n/**\n * Agent creator function return type\n */\ninterface AgentCreatorResult {\n agent: AbstractAgent | WeChatAgent | { toAGUIAgent(): AbstractAgent };\n cleanup?: () => void;\n}\n\n/**\n * Agent creator function type\n */\ntype AgentCreator = (params: {\n request: Request;\n options?: { agentId: string };\n}) => AgentCreatorResult | Promise<AgentCreatorResult>;\n\n/**\n * Handler options\n */\ninterface WxMessageHandlerOptions {\n logger?: Logger;\n}\n\n/**\n * Extract service name from hostname by finding version number pattern\n * e.g., \"my-service-123456\" -> \"my-service\"\n */\nfunction getServiceNameFromHostname(hostname: string): string {\n const parts = hostname.split(\"-\");\n // Find the last part that is purely numeric (version number)\n // Use reverse loop for ES2015 compatibility (instead of findLastIndex)\n let versionIdx = -1;\n for (let i = parts.length - 1; i >= 0; i--) {\n if (/^\\d+$/.test(parts[i])) {\n versionIdx = i;\n break;\n }\n }\n return versionIdx > 0 ? parts.slice(0, versionIdx).join(\"-\") : hostname;\n}\n\n/**\n * Get bot ID from multiple sources\n * Priority: SCF_FUNCTIONNAME > URL (parsed) > HOSTNAME (parsed) > fallback\n */\nfunction getBotId(url?: string, fallback = \"agent-id\"): string {\n // 1. SCF function name (highest priority)\n if (process.env.SCF_FUNCTIONNAME) {\n return process.env.SCF_FUNCTIONNAME;\n }\n // 2. Parse from URL using utils\n if (url) {\n const parsedBotId = utils.parseBotId(url);\n if (parsedBotId) {\n return parsedBotId;\n }\n }\n // 3. Parse from HOSTNAME\n if (process.env.HOSTNAME) {\n return getServiceNameFromHostname(process.env.HOSTNAME);\n }\n return fallback;\n}\n\n/**\n * Create WeChat message handler\n * Directly using sendMessageAGUI.handler from @cloudbase/agent-server\n * Aligned with chat_wx_v2.service.ts logic\n *\n * @param createAgent - Function to create agent instance (returns { agent, cleanup?})\n * @param options - Handler options\n * @returns Express route handler\n */\nexport function createWxMessageHandler(\n createAgent: AgentCreator,\n options?: WxMessageHandlerOptions\n): (req: Request, res: Response) => Promise<Response> {\n const { logger: parentLogger = noopLogger } = options ?? {};\n const adapterLogger =\n parentLogger.child?.({ component: \"sendWXMessageAGUI\" }) ?? parentLogger;\n\n return async (req: Request, res: Response): Promise<Response> => {\n let cleanup: (() => void) | null = null;\n let agent: WeChatAgent = undefined as any;\n const { callbackData } = utils.transformKeysToCamelCase(req.body);\n const { triggerSrc, wxVerify } = utils.parseWxEnvParam({\n httpContext: {\n headers: req.headers,\n },\n } as any) as {\n triggerSrc: WeChatTriggerSrc;\n wxVerify: boolean;\n };\n const wxSendmessageInput: WxSendMessageInput = {\n callbackData,\n triggerSrc,\n wxVerify,\n };\n const requestId = uuidv4();\n const logger = adapterLogger.child?.({ requestId }) ?? adapterLogger;\n const botId = getBotId(\n `${req.protocol}://${req.get(\"host\")}${req.originalUrl}`,\n \"agent-wx-send-message\"\n );\n try {\n if (!callbackData || !triggerSrc) {\n return res.status(400).json({\n error: \"Bad Request\",\n message: \"Missing required fields: callbackData, triggerSrc\",\n });\n }\n\n logger.info?.(\"[WX] Received message:\", { triggerSrc, wxVerify, botId });\n\n // 1. Create agent instance first (needed for history and voice handling)\n const { agent: unknownAgent, cleanup: agentCleanup } =\n await Promise.resolve(\n createAgent({ request: req, options: { agentId: botId } })\n );\n cleanup = agentCleanup ?? null;\n agent = (\n \"toAGUIAgent\" in unknownAgent\n ? unknownAgent.toAGUIAgent()\n : unknownAgent\n ) as WeChatAgent;\n\n // 2. Process message data (aligned with beforeStream)\n const { msgData, replyMsgData } = dealMsgData(\n callbackData,\n triggerSrc,\n wxVerify,\n botId\n );\n let skipAI = false;\n let isEnd = false;\n\n // 3. Check for duplicate request using msgData.recordId\n // Skip dedup for unverified accounts (WXSubscription/WXService without wxVerify)\n // because they rely on WeChat's 11-second retry mechanism\n const isUnverifiedAccount =\n [\"WXSubscription\", \"WXService\"].includes(triggerSrc) && !wxVerify;\n\n if (!isUnverifiedAccount) {\n // recordId = user-{triggerSrc}{msgId}{timestamp}, conversation = fromUserName\n // This combination uniquely identifies a WeChat callback\n const existingUserMsg = await agent.getPreviousReply(\n msgData.conversation,\n msgData.recordId\n );\n if (existingUserMsg) {\n logger.info?.(\"[WX] Duplicate callback detected, skipping:\", {\n recordId: msgData.recordId,\n conversation: msgData.conversation,\n });\n return res.json({});\n }\n }\n\n // 4. Validate message type\n const msgType = extractMsgType(callbackData);\n const validation = validateMessageType(msgType);\n\n if (!validation.isValid) {\n skipAI = true;\n replyMsgData.content =\n validation.userErrorMessage || \"暂不支持该消息类型\";\n }\n\n // 5. Initialize history and check previous reply (for retry logic)\n const previousReply = await agent.getPreviousReply(\n replyMsgData.conversation,\n replyMsgData.recordId\n );\n\n // 6. Extract content using package utility (ASYNC)\n const voiceHandler: VoiceMessageHandler = async (\n vBotId: string,\n vTriggerSrc: string,\n mediaId: string\n ) => {\n try {\n const result = await agent?.aitools?.getWxMediaContent(\n vBotId,\n vTriggerSrc,\n mediaId\n );\n\n return result || null;\n } catch {\n return null;\n }\n };\n\n const content = await getWxChatContent(\n callbackData,\n triggerSrc,\n voiceHandler,\n botId\n );\n\n // 7. Handle unverified account logic (WXSubscription/WXService only)\n if (\n [\"WXSubscription\", \"WXService\"].includes(triggerSrc) &&\n !wxVerify &&\n !skipAI\n ) {\n const result = await agent.handleUnverifiedChat({\n content,\n conversation: replyMsgData.conversation,\n previousReply,\n callbackData,\n triggerSrc,\n });\n skipAI = result.needSkipAI;\n isEnd = result.isEnd;\n if (result.replyContent) replyMsgData.content = result.replyContent;\n }\n\n // 8. Early return: async reply already sent\n if (isEnd) {\n return res.json({});\n }\n\n // 9. Early return: empty content\n if (!content && !skipAI) {\n logger.warn?.(\"[WX] Empty content\");\n return res.json(\n formatWeChatReplyMessage(callbackData, triggerSrc, \"无法识别消息内容\")\n );\n }\n\n // 10. Early return: skipAI\n if (skipAI) {\n logger.info?.(\"[WX] Skipping AI\");\n return res.json(\n formatWeChatReplyMessage(\n callbackData,\n triggerSrc,\n replyMsgData.content\n )\n );\n }\n\n // 11. Prepare input for sendMessageAGUI.handler\n // History is auto-managed by adapter.run():\n // - Input message saved at start\n // - Reply saved at complete\n logger.info?.(\"[WX] Processing:\", content.substring(0, 100));\n const input = {\n messages: [\n {\n id: msgData.recordId,\n role: \"user\" as const,\n content,\n },\n ],\n state: undefined,\n threadId: msgData.conversation,\n runId: uuidv4(),\n tools: [],\n context: [],\n forwardedProps: {\n wxSendmessageInput,\n // Pass full msgData for history storage\n msgData: msgData,\n // Pass replay info with replyMsgData for assistant history\n replay: {\n id: replyMsgData.recordId,\n ...replyMsgData,\n },\n },\n };\n\n // 12. Call agent - WeChatAgentAdapter.run() handles:\n // - Message assembly (both modes)\n // - Message sending (async mode only)\n // - History saving (both modes)\n // - Error handling (async mode: sends error message)\n const events = agui.sendMessageAGUI.handler(input, agent);\n\n // 13. Consume events to trigger adapter processing\n for await (const event of events) {\n if (event.type === EventType.RUN_ERROR) {\n logger.error?.(\n \"[WX] Agent error:\",\n (event as any).error || (event as any).message\n );\n }\n }\n logger.info?.(\"[WX] Processing complete\");\n\n // 14. Return response - get assembled reply from agent\n if (replyMsgData.needAsyncReply) {\n // Async mode: message already sent by adapter\n return res.json({});\n }\n // Sync mode: get assembled reply from agent and return via HTTP\n const finalContent = agent.lastReply || \"抱歉,无法生成回复\";\n return res.json(\n formatWeChatReplyMessage(callbackData, triggerSrc, finalContent)\n );\n } catch (error) {\n logger.error?.(\"[WX] Error processing message:\", error);\n const message = error instanceof Error ? error.message : String(error);\n try {\n if (agent?.aitools?.sendWxClientMessage) {\n const data = formatWeChatReplyMessage(\n callbackData,\n triggerSrc,\n message\n );\n await agent.aitools.sendWxClientMessage(\n agent.agentId || botId,\n triggerSrc,\n {\n msgType: data.msgType,\n touser: data.toUserName,\n text: {\n content: data.content,\n },\n openKfId: data.openKfId,\n msgId: data.msgId,\n }\n );\n }\n } catch (e) {}\n return res.status(500).json({\n error: \"Internal Server Error\",\n message,\n });\n } finally {\n if (cleanup) cleanup();\n }\n };\n}\n","import {\n WeChatConfig,\n WeChatPlatform,\n AccessTokenResponse,\n TokenCacheEntry,\n} from \"./types\";\n\n/**\n * Token manager for WeChat access tokens\n * Handles token caching and automatic refresh\n */\nexport class TokenManager {\n private cache: Map<string, TokenCacheEntry> = new Map();\n\n /**\n * Get access token (with caching)\n */\n async getAccessToken(config: WeChatConfig): Promise<string> {\n const cacheKey = this.getCacheKey(config);\n const cached = this.cache.get(cacheKey);\n\n // Return cached token if still valid\n if (cached && cached.expiresAt > Date.now()) {\n return cached.accessToken;\n }\n\n // Fetch new token\n const token = await this.fetchAccessToken(config);\n return token;\n }\n\n /**\n * Fetch access token from WeChat API\n */\n private async fetchAccessToken(config: WeChatConfig): Promise<string> {\n const url = this.getTokenUrl(config);\n const response = await fetch(url);\n const data: AccessTokenResponse = await response.json();\n\n if (data.errcode && data.errcode !== 0) {\n throw new Error(`Failed to get access token: ${data.errmsg}`);\n }\n\n // Cache token with 5-minute early expiration\n const cacheKey = this.getCacheKey(config);\n const expiresAt = Date.now() + (data.expires_in - 300) * 1000;\n\n this.cache.set(cacheKey, {\n accessToken: data.access_token,\n expiresAt,\n });\n\n return data.access_token;\n }\n\n /**\n * Get token URL based on platform\n */\n private getTokenUrl(config: WeChatConfig): string {\n if (config.platform === WeChatPlatform.CUSTOM_SERVICE) {\n return `https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=${config.appId}&corpsecret=${config.appSecret}`;\n }\n return `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${config.appId}&secret=${config.appSecret}`;\n }\n\n /**\n * Generate cache key\n */\n private getCacheKey(config: WeChatConfig): string {\n return `${config.platform}_${config.appId}`;\n }\n\n /**\n * Clear token cache\n */\n clearCache(config?: WeChatConfig): void {\n if (config) {\n this.cache.delete(this.getCacheKey(config));\n } else {\n this.cache.clear();\n }\n }\n}\n\n","import {\n MessageContent,\n SendMessageOptions,\n WeChatMessage,\n WeChatPlatform,\n MessageType,\n} from \"./types\";\n\n/**\n * Message formatter for different WeChat platforms\n */\nexport class MessageFormatter {\n /**\n * Format message for WeChat API\n */\n formatMessage(\n options: SendMessageOptions,\n platform: WeChatPlatform,\n originMsg?: any\n ): WeChatMessage {\n const { toUser, message, recommendQuestions, msgId } = options;\n let content = message.content;\n\n // Add recommended questions if provided\n if (recommendQuestions && recommendQuestions.length > 0) {\n content = this.withRecommendQuestions(content, recommendQuestions);\n }\n\n const baseMessage: WeChatMessage = {\n touser: toUser,\n msgtype: message.type,\n };\n\n // Format based on message type\n if (message.type === MessageType.TEXT) {\n baseMessage.text = { content };\n } else if (message.type === MessageType.IMAGE && message.imageUrl) {\n baseMessage.image = { pic_url: message.imageUrl };\n }\n\n // Add platform-specific fields\n if (platform === WeChatPlatform.CUSTOM_SERVICE) {\n baseMessage.open_kfid = originMsg?.open_kfid;\n baseMessage.msgid = msgId || originMsg?.msgid;\n }\n\n return baseMessage;\n }\n\n /**\n * Append recommended questions to content\n */\n private withRecommendQuestions(\n content: string,\n questions: string[]\n ): string {\n if (!questions || questions.length === 0) {\n return content;\n }\n return `${content}\\n\\n推荐问题:\\n${questions.join(\"\\n\")}`;\n }\n\n /**\n * Split long message into chunks\n */\n splitLongMessage(content: string, maxLength: number = 2000): string[] {\n if (content.length <= maxLength) {\n return [content];\n }\n\n const chunks: string[] = [];\n let currentChunk = \"\";\n\n const lines = content.split(\"\\n\");\n for (const line of lines) {\n if ((currentChunk + line).length > maxLength) {\n if (currentChunk) {\n chunks.push(currentChunk.trim());\n currentChunk = \"\";\n }\n // Handle lines longer than maxLength\n if (line.length > maxLength) {\n for (let i = 0; i < line.length; i += maxLength) {\n chunks.push(line.substring(i, i + maxLength));\n }\n } else {\n currentChunk = line + \"\\n\";\n }\n } else {\n currentChunk += line + \"\\n\";\n }\n }\n\n if (currentChunk) {\n chunks.push(currentChunk.trim());\n }\n\n return chunks;\n }\n}\n\n","import {\n WeChatConfig,\n WeChatMessage,\n WeChatPlatform,\n WeChatAPIResponse,\n} from \"./types\";\nimport { TokenManager } from \"./token-manager\";\n\n/**\n * Platform router for sending messages to different WeChat platforms\n */\nexport class PlatformRouter {\n private tokenManager: TokenManager;\n\n constructor(tokenManager: TokenManager) {\n this.tokenManager = tokenManager;\n }\n\n /**\n * Send message to WeChat platform\n */\n async send(\n message: WeChatMessage,\n config: WeChatConfig\n ): Promise<WeChatAPIResponse> {\n const accessToken = await this.tokenManager.getAccessToken(config);\n\n switch (config.platform) {\n case WeChatPlatform.CUSTOM_SERVICE:\n return this.sendToCustomService(message, accessToken, config);\n case WeChatPlatform.MINI_APP:\n return this.sendToMiniApp(message, accessToken);\n case WeChatPlatform.SERVICE:\n case WeChatPlatform.SUBSCRIPTION:\n return this.sendToOfficialAccount(message, accessToken);\n default:\n throw new Error(`Unsupported platform: ${config.platform}`);\n }\n }\n\n /**\n * Send to Enterprise WeChat Customer Service\n */\n private async sendToCustomService(\n message: WeChatMessage,\n accessToken: string,\n config: WeChatConfig\n ): Promise<WeChatAPIResponse> {\n const url = `https://qyapi.weixin.qq.com/cgi-bin/kf/send_msg?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n\n /**\n * Send to WeChat Mini Program\n */\n private async sendToMiniApp(\n message: WeChatMessage,\n accessToken: string\n ): Promise<WeChatAPIResponse> {\n const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n\n /**\n * Send to WeChat Official Account (Service/Subscription)\n */\n private async sendToOfficialAccount(\n message: WeChatMessage,\n accessToken: string\n ): Promise<WeChatAPIResponse> {\n const url = `https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=${accessToken}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(message),\n });\n return response.json();\n }\n}\n\n","import { WeChatConfig, SendMessageOptions, WeChatAPIResponse } from \"./types\";\nimport { TokenManager } from \"./token-manager\";\nimport { MessageFormatter } from \"./message-formatter\";\nimport { PlatformRouter } from \"./platform-router\";\n\n/**\n * Main WeChat sender class\n * Provides a simple API to send LLM messages to WeChat platforms\n */\nexport class WeChatSender {\n private config: WeChatConfig;\n private tokenManager: TokenManager;\n private messageFormatter: MessageFormatter;\n private platformRouter: PlatformRouter;\n\n constructor(config: WeChatConfig) {\n // Validate config\n this.config = config;\n\n // Initialize components\n this.tokenManager = new TokenManager();\n this.messageFormatter = new MessageFormatter();\n this.platformRouter = new PlatformRouter(this.tokenManager);\n }\n\n /**\n * Send a message to WeChat\n */\n async send(\n options: SendMessageOptions,\n originMsg?: any\n ): Promise<WeChatAPIResponse> {\n // Validate options\n const validatedOptions = options;\n\n // Format message\n const message = this.messageFormatter.formatMessage(\n validatedOptions,\n this.config.platform,\n originMsg\n );\n\n // Send message\n const result = await this.platformRouter.send(message, this.config);\n\n // Check for errors\n if (result.errcode !== 0) {\n throw new Error(`Failed to send message: ${result.errmsg}`);\n }\n\n return result;\n }\n\n /**\n * Send multiple messages in batch\n */\n async sendBatch(\n messages: SendMessageOptions[]\n ): Promise<WeChatAPIResponse[]> {\n const results: WeChatAPIResponse[] = [];\n\n for (const message of messages) {\n try {\n const result = await this.send(message);\n results.push(result);\n } catch (error) {\n results.push({\n errcode: -1,\n errmsg: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n return results;\n }\n\n /**\n * Send message asynchronously (fire and forget)\n */\n async sendAsync(options: SendMessageOptions, originMsg?: any): Promise<void> {\n this.send(options, originMsg).catch((error) => {\n console.error(\"Failed to send message:\", error);\n });\n }\n\n /**\n * Clear token cache\n */\n clearCache(): void {\n this.tokenManager.clearCache(this.config);\n }\n\n /**\n * Get current configuration\n */\n getConfig(): WeChatConfig {\n return { ...this.config };\n }\n}\n","import {\n RunAgentInput,\n BaseEvent,\n EventType,\n AbstractAgent,\n AgentConfig,\n} from \"@ag-ui/client\";\nimport { Observable } from \"rxjs\";\nimport { WeChatSender } from \"./wechat-sender\";\nimport {\n WeChatConfig,\n SendMessageOptions,\n MessageType,\n WeChatSendMode,\n} from \"./types\";\nimport { WeChatHistoryManager, HistoryEntry } from \"./wechat-history-manager\";\nimport {\n handleWeChatRetry,\n isContinueCommandValid,\n formatWeChatReplyMessage,\n WeChatReplyMessage,\n} from \"./wechat-message-handler\";\nimport { aitools, WxSendMessageInput } from \"@cloudbase/aiagent-framework\";\nimport { randomUUID } from \"crypto\";\n\nconst AITOOLS = aitools.AITools;\n\n/**\n * Configuration for WeChat Agent Adapter\n */\nexport interface WeChatAgentConfig extends AgentConfig {\n /**\n * The underlying agent to wrap\n */\n agent: AbstractAgent;\n\n /**\n * WeChat configuration\n */\n wechatConfig: WeChatConfig;\n\n /**\n * Optional: Custom message formatter\n * Converts agent output to WeChat message format\n */\n messageFormatter?: (content: string, event: BaseEvent) => SendMessageOptions;\n\n /**\n * Optional: Recommended questions to show after reply\n */\n recommendQuestions?: string[];\n\n /**\n * Optional: History manager for saving chat history\n * If not provided, will use singleton instance\n */\n historyManager?: WeChatHistoryManager;\n}\n\ninterface IWxRunAgentInput extends RunAgentInput {\n forwardedProps: {\n wxSendmessageInput: WxSendMessageInput;\n /** Full user message data from dealMsgData */\n msgData?: {\n recordId: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n };\n /** Reply metadata for assistant message */\n replay: {\n id: string;\n botId: string;\n conversation: string;\n role: \"user\" | \"assistant\";\n content: string;\n type: string;\n triggerSrc: string;\n sender: string;\n needAsyncReply: boolean;\n reply: string;\n originMsg: string;\n recommendQuestions: string[];\n createdAt: number;\n };\n };\n}\n\n/**\n * WeChat Agent Adapter\n *\n * Wraps any AbstractAgent and automatically sends its output to WeChat.\n * All methods are proxied to the underlying agent, with the run() method\n * enhanced to capture messages and send them via WeChat.\n *\n * @example\n * ```typescript\n * const myAgent = new SomeAgent({ ... });\n * const wechatAgent = new WeChatAgentAdapter({\n * agent: myAgent,\n * wechatConfig: {\n * platform: 'work',\n * corpId: 'xxx',\n * corpSecret: 'xxx'\n * }\n * });\n *\n * // Use it like any other agent\n * wechatAgent.run(input).subscribe(event => {\n * // Events are emitted normally\n * // AND automatically sent to WeChat\n * });\n * ```\n */\nexport class WeChatAgent extends AbstractAgent {\n private wrappedAgent: AbstractAgent;\n private wechatSender?: WeChatSender;\n private wechatConfig: WeChatConfig;\n private _historyManager: WeChatHistoryManager;\n private messageFormatter: (\n content: string,\n event: BaseEvent\n ) => SendMessageOptions;\n private messageBuffer: string = \"\";\n private recommendQuestions?: string[];\n public aitools?: aitools.AITools;\n\n constructor(config: WeChatAgentConfig) {\n super({\n agentId: config.agentId || config.agent.agentId,\n description: config.description || config.agent.description,\n threadId: config.threadId || config.agent.threadId,\n ...config,\n });\n\n this.wrappedAgent = config.agent;\n this.wechatConfig = config.wechatConfig;\n this.recommendQuestions = config.recommendQuestions;\n this._historyManager =\n config.historyManager || WeChatHistoryManager.getInstance();\n\n // Initialize sender based on send mode\n const sendMode = config.wechatConfig.sendMode || WeChatSendMode.LOCAL;\n\n if (sendMode === WeChatSendMode.AITOOLS) {\n // Use aitools SDK (for cloud function environment)\n if (!config.wechatConfig.context) {\n throw new Error(\"context is required when sendMode is AITOOLS\");\n }\n this.aitools = new AITOOLS(config.wechatConfig.context);\n } else {\n // Use local WeChatSender (for local development)\n this.wechatSender = new WeChatSender(config.wechatConfig);\n }\n\n // Default message formatter\n this.messageFormatter =\n config.messageFormatter ||\n ((content: string) => ({\n toUser: \"\", // Will be set from originMsg\n message: {\n content: content,\n type: MessageType.TEXT,\n },\n recommendQuestions: this.recommendQuestions,\n }));\n }\n\n /**\n * Last assembled reply content after run() completes\n * Controller can read this instead of re-assembling from events\n */\n public lastReply: string = \"\";\n\n /**\n * Whether last run had an error\n */\n public lastRunHadError: boolean = false;\n\n /**\n * Get previous reply from history\n * Used for: retry detection, \"继续\" command\n */\n async getPreviousReply(\n conversation: string,\n recordId?: string | null\n ): Promise<HistoryEntry | null> {\n return this._historyManager.getPreviousReply(conversation, recordId);\n }\n\n /**\n * Update message content in history\n */\n async updateHistoryContent(\n messageId: string,\n content: string,\n threadId: string\n ): Promise<void> {\n await this._historyManager.updateContent(threadId, messageId, content);\n }\n\n /**\n * Handle unverified account logic (WXSubscription/WXService)\n * Handles \"继续\" command and 11-second retry\n * Uses existing functions from wechat-message-handler.ts\n * @returns { needSkipAI, replyContent, isEnd }\n */\n async handleUnverifiedChat(params: {\n content: string;\n conversation: string;\n previousReply: HistoryEntry | null;\n callbackData: WxSendMessageInput;\n triggerSrc: string;\n }): Promise<{ needSkipAI: boolean; replyContent: string; isEnd: boolean }> {\n const { content, conversation, previousReply, callbackData, triggerSrc } =\n params;\n\n // Check if async reply already sent (for retry scenario)\n if (previousReply && previousReply.needAsyncReply) {\n return { needSkipAI: true, replyContent: \"\", isEnd: true };\n }\n\n // Handle \"继续\" command\n if (content === \"continue\" || content === \"继续\") {\n const latest = await this._historyManager.getPreviousReply(conversation);\n let replyContent = \"\";\n\n if (!latest) {\n replyContent = \"未找到相关回答,请先发送消息\";\n } else if (isContinueCommandValid(latest)) {\n replyContent = latest.content || '正在思考中,请稍后再回复\"继续\"';\n } else {\n replyContent = \"回答已过期,请重新发送消息\";\n }\n\n return { needSkipAI: true, replyContent, isEnd: false };\n }\n\n // Handle 11-second retry using existing function\n if (previousReply) {\n const result = await handleWeChatRetry(\n previousReply,\n callbackData,\n triggerSrc as any\n );\n return {\n needSkipAI: result.shouldSkip,\n replyContent: result.content || \"\",\n isEnd: false,\n };\n }\n\n return { needSkipAI: false, replyContent: \"\", isEnd: false };\n }\n\n /**\n * Run method with WeChat integration\n * Wraps the underlying agent's run() and sends messages to WeChat\n */\n run(input: IWxRunAgentInput): Observable<BaseEvent> {\n return new Observable<BaseEvent>((subscriber: any) => {\n this.messageBuffer = \"\";\n this.lastReply = \"\";\n this.lastRunHadError = false;\n let errorMessage = \"\";\n let subscription: any;\n\n const replyId = input?.forwardedProps?.replay.id || randomUUID();\n Promise.all([\n this.saveInputToHistory(input),\n this.saveReplyToHistory(\n {\n id: replyId,\n content: this.lastReply,\n },\n input\n ),\n ]).then(\n () => {\n // Subscribe to the wrapped agent's events\n subscription = this.wrappedAgent.run(input).subscribe({\n next: (event: BaseEvent) => {\n // Emit the event to our subscribers\n subscriber.next(event);\n\n // Track if error occurred and capture error message\n if (event.type === EventType.RUN_ERROR) {\n this.lastRunHadError = true;\n const errorEvent = event as any;\n errorMessage =\n errorEvent.message ||\n errorEvent.error?.message ||\n \"处理消息时发生错误,请稍后重试\";\n }\n\n // Handle WeChat sending\n this.handleWeChatSending(event, input);\n },\n error: (error: any) => {\n subscriber.error(error);\n },\n complete: () => {\n // Set lastReply for controller to read\n this.lastReply = this.lastRunHadError\n ? errorMessage\n : this.messageBuffer.trim() || \"\";\n\n // Send final message if buffer has content and no error occurred\n // (error message already sent in handleWeChatSending)\n if (this.messageBuffer.trim() && !this.lastRunHadError) {\n this.sendToWeChat(this.messageBuffer, input).catch(\n console.error\n );\n }\n\n // Auto-save reply to history at complete\n this.saveReplyToHistory(\n {\n id: input?.forwardedProps?.replay.id || randomUUID(),\n content: this.lastReply,\n },\n input\n ).catch(console.error);\n\n subscriber.complete();\n },\n });\n },\n (e) => {\n subscriber.error(e);\n }\n );\n\n // Return cleanup function\n return () => {\n subscription?.unsubscribe();\n };\n });\n }\n\n /**\n * Save input message to history at the start of run()\n * Only saves if the last message is from user role\n * Uses msgData from forwardedProps for complete data (similar to dealMsgData)\n */\n private async saveInputToHistory(input: IWxRunAgentInput): Promise<void> {\n const messages = input.messages;\n if (!messages || messages.length === 0) return;\n\n // Only process if the last message is from user\n const lastMessage = messages[messages.length - 1];\n if (lastMessage.role !== \"user\") return;\n\n const { threadId, runId } = input;\n const msgData = input.forwardedProps?.msgData;\n\n // Use msgData.recordId if available, otherwise fallback to lastMessage.id\n const messageId =\n msgData?.recordId ||\n lastMessage.id ||\n (lastMessage as any).messageId ||\n randomUUID();\n\n // Extract content from the last user message\n const rawContent = lastMessage.content;\n const content =\n typeof rawContent === \"string\"\n ? rawContent\n : Array.isArray(rawContent)\n ? rawContent\n .filter((c: any) => c.type === \"text\")\n .map((c: any) => c.text)\n .join(\"\")\n : \"\";\n\n if (threadId && content) {\n await this._historyManager.saveToHistory({\n messageId,\n role: \"user\",\n content,\n threadId,\n runId,\n createdAt: msgData?.createdAt || Date.now(),\n // Additional fields from msgData (similar to dealMsgData)\n botId: msgData?.botId,\n needAsyncReply: msgData?.needAsyncReply,\n type: msgData?.type,\n metadata: {\n sender: msgData?.sender,\n triggerSrc: msgData?.triggerSrc,\n originMsg: msgData?.originMsg,\n reply: msgData?.reply,\n recommendQuestions: msgData?.recommendQuestions,\n },\n });\n }\n }\n\n /**\n * Handle WeChat message sending based on events\n */\n private handleWeChatSending(event: BaseEvent, input: IWxRunAgentInput): void {\n // Always handle RUN_ERROR regardless of eventFilter\n if (event.type === EventType.RUN_ERROR) {\n const errorEvent = event as any;\n const errorMessage =\n errorEvent.message ||\n errorEvent.error?.message ||\n \"处理消息时发生错误,请稍后重试\";\n // Clear buffer to prevent duplicate sending\n this.messageBuffer = \"\";\n // Send error message to WeChat\n this.sendToWeChat(errorMessage, input).catch(console.error);\n return;\n }\n\n // Handle different event types\n switch (event.type) {\n case EventType.TEXT_MESSAGE_CHUNK:\n case EventType.TEXT_MESSAGE_CONTENT:\n // Accumulate text content\n const content = (event as any).delta || (event as any).content || \"\";\n this.messageBuffer += content;\n break;\n }\n }\n\n /**\n * Send message to WeChat and save to history\n * Only sends in async mode (needAsyncReply=true)\n * For sync mode, message is returned via HTTP response by controller\n */\n private async sendToWeChat(\n content: string,\n input: IWxRunAgentInput\n ): Promise<void> {\n try {\n // Check if async reply is needed from originMsg\n const needAsyncReply =\n input.forwardedProps?.replay.needAsyncReply ?? true;\n\n // Only send via adapter in async mode\n // In sync mode, controller handles returning the message via HTTP response\n if (needAsyncReply) {\n const sendMode = this.wechatConfig.sendMode || WeChatSendMode.AITOOLS;\n\n if (sendMode === WeChatSendMode.AITOOLS) {\n // Use aitools SDK to send message\n await this.sendViaAITools(content, input);\n } else {\n // Use local WeChatSender to send message\n await this.sendViaLocalSender(content, input);\n }\n }\n } catch (error) {\n console.error(\"Failed to send message to WeChat:\", error);\n }\n }\n\n /**\n * Save reply content to history\n * Uses replay metadata from forwardedProps for complete data (similar to dealMsgData)\n */\n private async saveReplyToHistory(\n reply: { id: string; content: string },\n input: IWxRunAgentInput\n ): Promise<void> {\n const { threadId, runId } = input;\n const replay = input.forwardedProps?.replay;\n const msgData = input.forwardedProps?.msgData;\n\n const messageId = reply.id;\n\n if (threadId && messageId) {\n await this._historyManager.saveToHistory({\n id: messageId,\n messageId,\n role: \"assistant\",\n content: reply.content,\n threadId,\n runId,\n createdAt: Date.now(),\n // Additional fields from replay/msgData (similar to dealMsgData replyMsgData)\n botId: replay?.botId || msgData?.botId,\n needAsyncReply: replay?.needAsyncReply,\n type: replay?.type || \"text\",\n metadata: {\n sender: replay?.sender || msgData?.sender,\n triggerSrc: replay?.triggerSrc || msgData?.triggerSrc,\n // For assistant, reply field is empty, replyTo points to user message\n replyTo: (replay as any)?.replyTo || msgData?.recordId,\n originMsg: replay?.originMsg,\n reply: replay?.reply,\n recommendQuestions: replay?.recommendQuestions,\n },\n });\n }\n }\n\n /**\n * Send message via aitools SDK (for cloud function environment)\n */\n private async sendViaAITools(\n content: string,\n input: IWxRunAgentInput\n ): Promise<void> {\n if (!this.aitools) {\n throw new Error(\"aitools is not initialized\");\n }\n\n // Get origin message from forwardedProps\n const wxSendmessageInput = input.forwardedProps?.wxSendmessageInput;\n if (!wxSendmessageInput) {\n console.warn(\n \"wxSendmessageInput not found in forwardedProps, skipping aitools send\"\n );\n return;\n }\n\n // Process reply message to get correct format for different platforms\n const toWxMsgData = this.processReplyMsg(wxSendmessageInput, content);\n if (!toWxMsgData) {\n console.warn(\"Failed to process reply message, skipping send\");\n return;\n }\n\n // Extract trigger source\n const triggerSrc =\n wxSendmessageInput.triggerSrc || this.wechatConfig.platform;\n\n // Send message using aitools\n await this.aitools.sendWxClientMessage(\n this.agentId || \"agent\",\n triggerSrc,\n {\n msgType: toWxMsgData.msgType,\n touser: toWxMsgData.toUserName,\n text: {\n content: toWxMsgData.content,\n },\n openKfId: toWxMsgData.openKfId,\n msgId: toWxMsgData.msgId || \"\",\n }\n );\n }\n\n /**\n * Format reply message for WeChat HTTP response (sync mode)\n * Public method for controller to use\n */\n formatReplyMessage(\n callbackData: any,\n triggerSrc: string,\n content: string\n ): WeChatReplyMessage {\n return formatWeChatReplyMessage(callbackData, triggerSrc, content);\n }\n\n /**\n * Process reply message to get correct format for different WeChat platforms\n * Based on chat_wx.service.ts processReplyMsg implementation\n */\n private processReplyMsg(\n wxSendMessageInput: WxSendMessageInput,\n content: string\n ) {\n const triggerSrc =\n wxSendMessageInput.triggerSrc || this.wechatConfig.platform;\n const callbackData: any = wxSendMessageInput.callbackData;\n\n return formatWeChatReplyMessage(callbackData, triggerSrc, content);\n }\n\n /**\n * Send message via local WeChatSender (for local development)\n */\n private async sendViaLocalSender(\n content: string,\n input: RunAgentInput\n ): Promise<void> {\n if (!this.wechatSender) {\n throw new Error(\"wechatSender is not initialized\");\n }\n\n const messageOptions = this.messageFormatter(content, {\n type: EventType.TEXT_MESSAGE_CONTENT,\n content,\n } as any);\n\n // Get origin message from forwardedProps if available\n const originMsg = input.forwardedProps?.originMsg;\n\n await this.wechatSender.send(messageOptions, originMsg);\n }\n}\n","/**\n * WeChat Chat History Manager\n * Manages chat history for \"continue\" command and retry logic\n * Uses CloudBase database storage\n */\n\nimport tcb from \"@cloudbase/node-sdk\";\n\n// Re-export ChatHistoryRecord for convenience\nexport type { ChatHistoryRecord } from \"./wechat-message-handler\";\n\n/** Default collection name for chat history */\nexport const WX_CHAT_HISTORY_COLLECTION = \"wx_chat_history\";\n\n/**\n * Message role type\n */\nexport type MessageRole = \"user\" | \"assistant\" | \"system\";\n\n/**\n * Metadata for history entry (stored in metadata field)\n */\nexport interface HistoryEntryMetadata {\n /** Sender identifier */\n sender?: string;\n /** Trigger source (WXSubscription, WXService, etc.) */\n triggerSrc?: string;\n /** Original message data */\n originMsg?: string;\n /** Reply to message ID */\n replyTo?: string;\n /** Reply message ID */\n reply?: string;\n /** Image URL if applicable */\n image?: string;\n /** Recommended questions */\n recommendQuestions?: string[];\n}\n\n/**\n * History entry for storage\n * Contains message info plus optional metadata\n */\nexport interface HistoryEntry {\n id?: string;\n /** Unique message ID (record_id in database) */\n messageId: string;\n /** Message role: user, assistant, or system */\n role: MessageRole;\n /** Message content */\n content?: string;\n /** Thread/Conversation ID */\n threadId: string;\n /** Creation timestamp */\n createdAt: number;\n /** Bot ID */\n botId?: string;\n /** Run ID for tracking agent runs */\n runId?: string;\n /** Whether async reply is needed (WeChat specific) */\n needAsyncReply?: boolean;\n /** Message status: pending, done, error, cancel */\n status?: string;\n /** Message type */\n type?: string;\n /** Additional metadata */\n metadata?: HistoryEntryMetadata;\n}\n\n/**\n * Database document structure (snake_case for CloudBase)\n */\ninterface ChatHistoryData {\n _id?: string;\n bot_id: string;\n record_id: string;\n role: string;\n status?: string;\n content?: string;\n conversation: string;\n type?: string;\n trace_id?: string;\n async_reply?: boolean;\n metadata?: HistoryEntryMetadata;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface HistoryManagerConfig {\n /** CloudBase environment ID */\n envId?: string;\n /** CloudBase secret ID */\n secretId?: string;\n /** CloudBase secret key */\n secretKey?: string;\n /** CloudBase session token */\n token?: string;\n /** Collection name, default: wx_chat_history */\n collectionName?: string;\n /** Bot ID for filtering */\n botId?: string;\n}\n\n/**\n * Transform HistoryEntry to database document format\n */\nfunction entryToData(entry: HistoryEntry): Omit<ChatHistoryData, \"_id\"> {\n return {\n bot_id: entry.botId || \"\",\n record_id: entry.messageId,\n role: entry.role,\n status: entry.status,\n content: entry.content,\n conversation: entry.threadId,\n type: entry.type,\n trace_id: entry.runId,\n async_reply: entry.needAsyncReply,\n metadata: entry.metadata,\n createdAt: entry.createdAt || Date.now(),\n updatedAt: Date.now(),\n };\n}\n\n/**\n * Transform database document to HistoryEntry\n */\nfunction dataToEntry(data: ChatHistoryData): HistoryEntry {\n return {\n id: data._id,\n messageId: data.record_id,\n role: data.role as MessageRole,\n content: data.content,\n threadId: data.conversation,\n createdAt: data.createdAt,\n botId: data.bot_id,\n runId: data.trace_id,\n needAsyncReply: data.async_reply,\n status: data.status,\n type: data.type,\n metadata: data.metadata,\n };\n}\n\n/**\n * WeChat History Manager\n * Uses CloudBase database storage\n * Singleton pattern for shared history across adapter and controller\n */\nexport class WeChatHistoryManager {\n private static instance: WeChatHistoryManager;\n private tcbClient: tcb.CloudBase;\n private collectionName: string;\n private botId: string;\n private collectionReady = false;\n\n private constructor(config?: HistoryManagerConfig) {\n this.collectionName = config?.collectionName || WX_CHAT_HISTORY_COLLECTION;\n this.botId = config?.botId || \"default\";\n\n // Initialize CloudBase client\n const envId =\n config?.envId || process.env.TCB_ENV || process.env.CLOUDBASE_ENV;\n if (!envId) {\n throw new Error(\n \"[WeChatHistoryManager] envId is required. Set TCB_ENV or CLOUDBASE_ENV environment variable, or pass envId in config.\"\n );\n }\n\n this.tcbClient = tcb.init({\n env: envId,\n secretId: config?.secretId,\n secretKey: config?.secretKey,\n sessionToken: config?.token,\n });\n }\n\n static getInstance(config?: HistoryManagerConfig): WeChatHistoryManager {\n if (!WeChatHistoryManager.instance) {\n WeChatHistoryManager.instance = new WeChatHistoryManager(config);\n }\n return WeChatHistoryManager.instance;\n }\n\n /**\n * Ensure collection exists, create if not\n */\n private async ensureCollection(): Promise<void> {\n if (this.collectionReady) return;\n\n try {\n const db = this.tcbClient.database();\n await db.createCollection(this.collectionName);\n this.collectionReady = true;\n } catch (error: any) {\n // Collection already exists (error code -502005)\n if (error?.code === \"DATABASE_COLLECTION_ALREADY_EXIST\") {\n this.collectionReady = true;\n } else {\n console.error(\n \"[WeChatHistoryManager] Failed to create collection:\",\n error\n );\n throw error;\n }\n }\n }\n\n /**\n * Get previous reply from history\n */\n async getPreviousReply(\n threadId: string,\n messageId?: string | null\n ): Promise<HistoryEntry | null> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n const whereCondition: Record<string, any> = {\n conversation: _.eq(threadId),\n };\n\n if (messageId) {\n whereCondition.record_id = _.eq(messageId);\n }\n\n const result = await collection\n .where(whereCondition)\n .orderBy(\"createdAt\", \"desc\")\n .limit(1)\n .get();\n\n if (result.data && result.data.length > 0) {\n return dataToEntry(result.data[0] as ChatHistoryData);\n }\n return null;\n }\n\n /**\n * Save record to history\n */\n async saveToHistory(record: HistoryEntry): Promise<void> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n // Check if record exists\n const existing = await collection\n .where({ record_id: _.eq(record.messageId) })\n .limit(1)\n .get();\n\n const data = entryToData({ ...record, botId: record.botId || this.botId });\n\n if (existing.data && existing.data.length > 0) {\n // Update existing record\n await collection\n .where({ record_id: _.eq(record.messageId) })\n .update(data);\n } else {\n // Add new record\n await collection.add(data);\n }\n }\n\n /**\n * Update record content by messageId\n */\n async updateContent(\n _threadId: string,\n messageId: string,\n content: string\n ): Promise<void> {\n await this.ensureCollection();\n const db = this.tcbClient.database();\n const _ = db.command;\n const collection = db.collection(this.collectionName);\n\n await collection.where({ record_id: _.eq(messageId) }).update({\n content,\n updatedAt: Date.now(),\n });\n }\n\n}\n\n// Export singleton getter for convenience\nexport const getHistoryManager = WeChatHistoryManager.getInstance;\n"],"mappings":"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","names":["WeChatPlatform","MessageType","WeChatSendMode","noopLogger","EventType","EventType","needAsyncReply"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/agent-adapter-wx",
3
- "version": "0.0.19",
3
+ "version": "0.0.20",
4
4
  "description": "WeChat adapter for AG-Kit - Forward LLM messages to WeChat platforms",
5
5
  "files": [
6
6
  "dist/",
@@ -47,8 +47,8 @@
47
47
  "rxjs": "^7.8.1",
48
48
  "uuid": "^13.0.0",
49
49
  "zod": "^3.25.0 || ^4.0.0",
50
- "@cloudbase/agent-shared": "^0.0.19",
51
- "@cloudbase/agent-server": "^0.0.19"
50
+ "@cloudbase/agent-server": "^0.0.20",
51
+ "@cloudbase/agent-shared": "^0.0.20"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "@ag-ui/client": "^0.0.42",