はじめに
AI エージェントは、ユーザーが使い慣れたプラットフォームからアクセスできる場合にのみ役立ちます。チャット チャネルを使用すると、エージェントを Telegram、Slack、Discord、およびその他の多くのプラットフォームに展開でき、すべて同じエージェント コアを使用できます。
1. チャネルアダプターインターフェース
// packages/channels/src/types.ts
export interface ChannelAdapter {
readonly channelType: string;
// Initialize channel (set up webhooks, etc.)
initialize(config: ChannelConfig): Promise<void>;
// Send message to channel
sendMessage(channelId: string, message: ChannelMessage): Promise<void>;
// Parse incoming webhook to unified format
parseIncoming(rawPayload: unknown): IncomingMessage;
// Cleanup
shutdown(): Promise<void>;
}
export interface ChannelMessage {
text: string;
markdown?: string;
images?: string[];
buttons?: { label: string; action: string }[];
metadata?: Record<string, unknown>;
}
export interface IncomingMessage {
channelType: string;
channelId: string; // channel/group ID
userId: string; // user ID on the platform
userName: string;
text: string;
images?: string[];
replyToMessageId?: string;
raw: unknown; // Original payload
}
export interface ChannelConfig {
token: string;
webhookUrl?: string;
additionalConfig?: Record<string, unknown>;
}
2. 電報チャネル
// packages/channels/telegram/src/telegram-adapter.ts
export class TelegramAdapter implements ChannelAdapter {
readonly channelType = 'telegram';
private bot: TelegramBot;
async initialize(config: ChannelConfig) {
this.bot = new TelegramBot(config.token);
if (config.webhookUrl) {
await this.bot.setWebhook(config.webhookUrl);
}
}
parseIncoming(payload: unknown): IncomingMessage {
const update = payload as TelegramUpdate;
const msg = update.message!;
return {
channelType: 'telegram',
channelId: String(msg.chat.id),
userId: String(msg.from!.id),
userName: msg.from!.first_name,
text: msg.text || '',
images: msg.photo?.map(p => p.file_id),
replyToMessageId: msg.reply_to_message
? String(msg.reply_to_message.message_id)
: undefined,
raw: payload,
};
}
async sendMessage(chatId: string, message: ChannelMessage) {
if (message.markdown) {
await this.bot.sendMessage(chatId, message.markdown, {
parse_mode: 'MarkdownV2',
});
} else {
await this.bot.sendMessage(chatId, message.text);
}
// Send images if any
if (message.images) {
for (const image of message.images) {
await this.bot.sendPhoto(chatId, image);
}
}
}
async shutdown() {
await this.bot.deleteWebhook();
}
}
3. チャネルルーター
// packages/gateway/src/channels/channel-router.ts
export class ChannelRouter {
private channels = new Map<string, ChannelAdapter>();
private agent: Agent;
register(adapter: ChannelAdapter) {
this.channels.set(adapter.channelType, adapter);
}
// Webhook handler — receives messages from all channels
async handleWebhook(channelType: string, payload: unknown): Promise<void> {
const adapter = this.channels.get(channelType);
if (!adapter) throw new Error(`Unknown channel: ${channelType}`);
// Parse to unified format
const incoming = adapter.parseIncoming(payload);
// Find or create user mapping
const user = await this.resolveUser(incoming);
// Chat with agent
const response = await this.agent.chat(
incoming.text,
{
tenantId: user.tenantId,
userId: user.id,
sessionId: `${channelType}:${incoming.channelId}`,
},
);
// Send response back through the same channel
await adapter.sendMessage(incoming.channelId, {
text: response,
markdown: response,
});
}
}
// Webhook routes
app.post('/webhooks/telegram', async (c) => {
const payload = await c.req.json();
await channelRouter.handleWebhook('telegram', payload);
return c.json({ ok: true });
});
app.post('/webhooks/slack', async (c) => {
const payload = await c.req.json();
await channelRouter.handleWebhook('slack', payload);
return c.json({ ok: true });
});
4. サポートされているチャンネル
| チャンネル | 特長 | アダプター |
|---|---|---|
| ウェブチャット | フルリッチな UI、ストリーミング、ファイルアップロード | 組み込みの React アプリ |
| 電報 | マークダウン、インラインボタン、グループ | ボット API + Webhook |
| スラック | スレッド、リアクション、スラッシュコマンド | イベントAPI |
| ディスコード | 埋め込み、スレッド、スラッシュ コマンド | Discord.js |
| ザロ | ベトナム語メッセージング、OA API | Zalo OA API |
| Facebook メッセンジャー | クイック返信、テンプレート | グラフAPI |
| LINE | リッチメニュー、フレックスメッセージ | メッセージング API |
| テンプレート、メディア、ビジネス API | クラウドAPI |
5. まとめ
- アダプター パターン — すべてのプラットフォーム向けの統一インターフェイス
- チャネルルーター — Webhookゲートウェイ→解析→agent.chat()→応答の送信
- ユーザー マッピング — 外部プラットフォーム ユーザー → 内部ユーザー
- 1 つのエージェント、多数のチャネル — 同じ AI、異なるフロントエンド
次の記事: React フロントエンド — Web チャット インターフェイスを構築します。