Welcome back! In the previous chapter, IPC Bridge (Inter-Process Communication), we learned how to connect our React Frontend to our Node.js Backend using a secure bridge.
But why limit our AI to just the desktop application window?
Imagine your AI agent is a super-smart employee sitting in an office.
The Channel & Plugin System acts like a Call Center Switchboard.
Let's imagine you are away from your computer. You open the Lark mobile app and message your bot: User: "Check the server status."
Here is how the Channel System handles it:
The ChannelManager is the central hub. It is a Singleton (there is only ever one instance). It manages the lifecycle of all connections—turning them on when the app starts and shutting them down when the app closes.
It lives in src/channels/core/ChannelManager.ts.
When AionUi starts, the manager loads your settings from the database and boots up the enabled plugins.
// src/channels/core/ChannelManager.ts
async initialize(): Promise<void> {
// 1. Initialize helper services (Session, Pairing, Plugins)
this.pluginManager = new PluginManager(this.sessionManager);
// 2. Load enabled plugins (like Telegram or Lark) from DB
await this.loadEnabledPlugins();
console.log('[ChannelManager] Listening for external messages...');
}
Every platform (Lark, Telegram) speaks a different language. A Plugin wraps the official SDK of that platform and translates it for AionUi.
Let's look at the Lark Plugin (src/channels/plugins/lark/LarkPlugin.ts).
We use WebSockets so you don't need a public IP address. The bot initiates an outgoing connection to Lark.
// src/channels/plugins/lark/LarkPlugin.ts
protected async onStart(): Promise<void> {
// 1. Create the official Lark WebSocket Client
this.wsClient = new lark.WSClient({
appId: this.config.credentials.appId,
appSecret: this.config.credentials.appSecret,
});
// 2. Connect to Lark
await this.wsClient.start({
eventDispatcher: this.eventDispatcher
});
}
wsClient receives data.When the AI replies, the plugin must format the text into a Lark JSON object.
// src/channels/plugins/lark/LarkPlugin.ts
async sendMessage(chatId, message): Promise<string> {
// 1. Convert text to a Lark "Interactive Card" (for better formatting)
const card = this.buildTextCard(message.content);
// 2. Send via the SDK
const response = await this.client.im.message.create({
params: { receive_id_type: 'open_id' },
data: {
receive_id: chatId,
msg_type: 'interactive',
content: JSON.stringify(card),
},
});
return response.data.message_id;
}
External platforms often send the same message twice (retries due to network lag). If we aren't careful, the AI will reply twice.
The Plugin tracks processed Event IDs to ignore duplicates.
// src/channels/plugins/lark/LarkPlugin.ts
private async handleMessageEvent(event) {
const eventId = event.message.message_id;
// 1. Check if we already handled this ID
if (this.isEventProcessed(eventId)) {
return; // Ignore it!
}
// 2. Mark as processed
this.markEventProcessed(eventId);
// 3. Process the message...
}
How does a message travel from a phone in New York to your desktop in London and back?
To make the Agent logic (Chapter 1) reusable, the ChannelManager converts all inputs into a standard format before processing.
Input from Lark (Complex JSON):
{ "header": { "event_id": "123" }, "event": { "message": { "content": "{\"text\":\"Hello\"}" } } }
Converted Unified Message (Internal):
{
platform: 'lark',
userId: 'user-789',
content: {
type: 'text',
text: 'Hello'
}
}
This allows the core AI to not care if the user is on Telegram, Lark, or the Desktop App.
In ChannelManager.ts, we see how the system handles the user response. This connects back to the Agent Task Orchestration we learned in Chapter 1.
// src/channels/core/ChannelManager.ts
// Wiring up the message handler during initialization
this.pluginManager.setMessageHandler(async (msg) => {
// 1. Find the User's Session (Memory)
const session = this.sessionManager.getSession(msg.userId);
// 2. Pass the message to the Executor
// The executor internally calls the Agent Manager
await this.actionExecutor.handleMessage(session, msg);
});
In this chapter, we learned:
LarkPlugin) handle the specific translation and connection (often using WebSockets).We have now covered the Agent, its Tools, its Protocols, the Frontend Bridge, and External Channels.
Our agent is powerful and accessible. But what if we want to access the AionUi Dashboard itself from a web browser, not just chat with the bot?
Next, we will explore the final piece of the puzzle: Web Server & Remote Access.
Next Chapter: Web Server & Remote Access
Generated by Code IQ