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 TCB. 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, TCB 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 TCB console
  2. Upload the code and deploy
  3. Associate the Agent with the service in the TCB 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