Skip to main content

Agents with ibot- prefix integrating with WeChat callback messages

This article introduces how to implement WeChat callback message handling for Agents with the ibot- prefix, enabling AI auto-reply in scenarios such as WeChat official accounts, WeChat Mini Program customer service, and WeChat Customer Service.

Overview​

Agents with the ibot- prefix are function-based Agents provided by CloudBase. By implementing the wxSendMessage method, they can receive and process callback messages from the WeChat platform.

Supported WeChat Platforms​

PlatformtriggerSrc ValueReply Mode
WeChat Mini Program Customer ServiceWXMiniappAlways asynchronous
WeChat Service AccountWXServiceSynchronous (authenticated) / Asynchronous (unauthenticated)
WeChat Subscription AccountWXSubscriptionSynchronous (authenticated) / Asynchronous (unauthenticated)
WeChat Customer ServiceWXCustomerServiceAlways asynchronous

Core Interfaces​

wxSendMessage Method​

ibot- Agent needs to implement the wxSendMessage method for handling WeChat callback messages:

wxSendMessage(input: WxSendMessageInput): Promise<WeChatTextOutput>

API Route: POST /v1/aibot/bots/:botId/wx-send-message

When a WeChat user sends a message, CloudBase will forward the message to this interface to be handled by your ibot- Agent.

Input Parameters​

WxSendMessageInput​

FieldTypeDescription
callbackDataWeChatTextInput | WeChatVoiceInput | WeChatWorkTextInput | WeChatWorkVoiceInputWeChat callback message data
triggerSrcstringMessage source: WXSubscription (Subscription Account), WXService (Service Account), WXMiniapp (Mini Program), WXCustomerService (Customer Service)
wxVerifybooleanAuthentication status of the WeChat AppId

WeChatTextInput (Text Messages from WeChat Official Accounts/Mini Programs)​

FieldTypeDescription
contentstringMessage content
createTimenumberMessage creation time
fromUserNamestringSender's OpenId
toUserNamestringRecipient
msgIdstringMessage ID
msgTypestringMessage type

WeChatVoiceInput (Voice Messages from WeChat Official Accounts/Mini Programs)​

FieldTypeDescription
formatstringAudio format
mediaIdstringVoice Media ID
createTimenumberMessage creation time
fromUserNamestringSender's OpenId
toUserNamestringRecipient
msgIdstringMessage ID
msgTypestringMessage type

WeChatWorkTextInput (WeChat Customer Service Text Messages)​

FieldTypeDescription
externalUserIdstringExternal User ID
openKfIdstringCustomer Service ID
originnumberMessage source
sendTimenumberMessage sending time
msgIdstringMessage ID
msgTypestringMessage type
text.contentstringMessage content

WeChatWorkVoiceInput (WeChat Customer Service Voice Messages)​

FieldTypeDescription
externalUserIdstringExternal User ID
openKfIdstringCustomer Service ID
originnumberMessage source
sendTimenumberMessage sending time
msgIdstringMessage ID
msgTypestringMessage type
voice.mediaIdstringVoice Media ID

Response Parameters​

WeChatTextOutput​

For authenticated WeChat official accounts, it is necessary to return synchronous reply messages:

FieldTypeDescription
ContentstringReply content
CreateTimenumberCreation timestamp
FromUserNamestringSender (WeChat official accounts)
ToUserNamestringRecipient (User)
MsgTypestringMessage type, fixed to text

Quick Start​

Step 1: Create a Project​

Use the @cloudbase/aiagent-framework framework to create a project:

npm init -y
npm install @cloudbase/aiagent-framework

Step 2: Implement the wxSendMessage Method​

const { BotCore, BotRunner } = require("@cloudbase/aiagent-framework");

class MyBot extends BotCore {
/**
* Handle WeChat callback messages
* @param {import('@cloudbase/aiagent-framework').WxSendMessageInput} input
* @returns {Promise<import('@cloudbase/aiagent-framework').WeChatTextOutput>}
*/
async wxSendMessage(input) {
const { callbackData, triggerSrc, wxVerify } = input;

// Get user message content
let userMessage = '';
if (callbackData.msgType === 'text') {
// Text message
userMessage = callbackData.content || callbackData.text?.content || '';
} else if (callbackData.msgType === 'voice') {
// Voice message - speech-to-text can be called
const voiceResult = await this.tools.speechToText({
mediaId: callbackData.mediaId || callbackData.voice?.mediaId,
});
userMessage = voiceResult.Result;
}

// Invoke the large model to generate a reply
const reply = await this.generateReply(userMessage);

// Return different formats based on the authentication status
if (wxVerify && (triggerSrc === 'WXSubscription' || triggerSrc === 'WXService')) {
// Authenticated WeChat official accounts: synchronous reply
return {
Content: reply,
CreateTime: Math.floor(Date.now() / 1000),
FromUserName: callbackData.toUserName,
ToUserName: callbackData.fromUserName,
MsgType: 'text',
};
} else {
// Unauthenticated or Mini Program / WeChat Customer Service: asynchronous sending
await this.tools.sendWxMessage({
toUser: callbackData.fromUserName || callbackData.externalUserId,
content: reply,
triggerSrc,
});
return {};
}
}

/**
* Generate AI reply
*/
async generateReply(userMessage) {
// Implement your AI reply logic here
// Can invoke large models, knowledge bases, etc.
const result = await this.tools.chat({
messages: [{ role: 'user', content: userMessage }],
});
return result.content;
}
}

exports.main = function (event, context) {
return BotRunner.run(event, context, new MyBot(context));
};

Step 3: Process Messages from Different Platforms​

Differentiate platforms based on triggerSrc and perform differential processing:

class MyBot extends BotCore {
async wxSendMessage(input) {
const { callbackData, triggerSrc, wxVerify } = input;

switch (triggerSrc) {
case 'WXMiniapp':
return this.handleMiniappMessage(callbackData);
case 'WXSubscription':
return this.handleSubscriptionMessage(callbackData, wxVerify);
case 'WXService':
return this.handleServiceMessage(callbackData, wxVerify);
case 'WXCustomerService':
return this.handleWorkWxMessage(callbackData);
default:
console.log('Unknown message source:', triggerSrc);
return {};
}
}

// Handle Mini Program customer service messages (always asynchronous)
async handleMiniappMessage(data) {
const reply = await this.generateReply(data.content);
await this.tools.sendWxMessage({
toUser: data.fromUserName,
content: reply,
triggerSrc: 'WXMiniapp',
});
return {};
}

// Handle Subscription Account messages
async handleSubscriptionMessage(data, wxVerify) {
const reply = await this.generateReply(data.content);

if (wxVerify) {
// Authenticated: synchronous reply
return {
Content: reply,
CreateTime: Math.floor(Date.now() / 1000),
FromUserName: data.toUserName,
ToUserName: data.fromUserName,
MsgType: 'text',
};
} else {
// Unauthenticated: asynchronous sending
await this.tools.sendWxMessage({
toUser: data.fromUserName,
content: reply,
triggerSrc: 'WXSubscription',
});
return {};
}
}

// Handle Service Account messages
async handleServiceMessage(data, wxVerify) {
// The logic is similar to that of Subscription Accounts
return this.handleSubscriptionMessage(data, wxVerify);
}

// Handling WeChat customer service messages (always asynchronous)
async handleWorkWxMessage(data) {
const reply = await this.generateReply(data.text.content);
await this.tools.sendWxMessage({
toUser: data.externalUserId,
content: reply,
triggerSrc: 'WXCustomerService',
openKfId: data.openKfId,
});
return {};
}
}

Complete Example​

Combining BotCore's Chat History Feature​

const { BotCore, BotRunner } = require("@cloudbase/aiagent-framework");

class MyBot extends BotCore {
async wxSendMessage(input) {
const { callbackData, triggerSrc, wxVerify } = input;

// Obtain user message
const userMessage = this.extractMessage(callbackData);
const userId = callbackData.fromUserName || callbackData.externalUserId;

// Create chat history pair
const { updateBotRecord } = await this.createRecordPair({
userContent: userMessage,
});

// Obtain historical messages for context
const history = await this.getHistoryMessages({ size: 10 });

// Invoke large model
const reply = await this.tools.chat({
messages: [
...history,
{ role: 'user', content: userMessage },
],
});

// Update Bot record
await updateBotRecord({ content: reply.content });

// Return or send the message
if (wxVerify && (triggerSrc === 'WXSubscription' || triggerSrc === 'WXService')) {
return {
Content: reply.content,
CreateTime: Math.floor(Date.now() / 1000),
FromUserName: callbackData.toUserName,
ToUserName: callbackData.fromUserName,
MsgType: 'text',
};
} else {
await this.tools.sendWxMessage({
toUser: userId,
content: reply.content,
triggerSrc,
openKfId: callbackData.openKfId,
});
return {};
}
}

extractMessage(data) {
if (data.content) return data.content;
if (data.text?.content) return data.text.content;
return '';
}
}

exports.main = function (event, context) {
return BotRunner.run(event, context, new MyBot(context));
};

Deployment​

After completing the code development, deploy the function to cloud function or cloud hosting:

  1. Create a function-type cloud hosting service in the CloudBase console
  2. Upload the code and deploy
  3. Associate the Agent with the service in the CloudBase AI console.

Notes​

1. Timeout Handling​

The WeChat platform imposes a time limit on message replies:

  • WeChat official accounts: A response must be returned within 5 seconds; otherwise, WeChat will retry.
  • Mini Program/WeChat customer service: Adopts asynchronous mode with no strict time limit.

It is recommended to uniformly use the asynchronous mode for sending messages in complex AI processing.

2. Message Deduplication​

WeChat may repeatedly push the same message. It is recommended to perform deduplication based on msgId:

async wxSendMessage(input) {
const { callbackData } = input;

// Check whether it has been processed
const processed = await this.checkMessageProcessed(callbackData.msgId);
if (processed) {
return {}; // Processed, return directly
}

// Mark as processed
await this.markMessageProcessed(callbackData.msgId);

// Continue processing the message...
}

3. Reply Length Limit​

WeChat imposes a length limit on individual messages (approximately 2000 characters). For lengthy AI-generated replies, it is recommended to:

  • Segment and send
  • Prompt the user to send "Continue" to obtain the subsequent content.
  • Restrict the reply length in the prompt