
文档版本:2026.3.24 最后更新:2026-03-25
1. 层概述
职责: 连接各个消息平台,提供统一的消息收发接口
定位: Gateway 和外部消息平台之间的桥梁
核心特性:
- • 多渠道支持 (9个内置聊天渠道 + 25+扩展平台)
- • 统一消息抽象
- • 插件化架构
- • 独立故障隔离
内置聊天渠道 (9个,CHAT_CHANNEL_ORDER 顺序):
tg, whatsapp, discord, irc, googlechat, slack, signal, imessage, line
变更说明: IRC 和 Google Chat 自 v2026.3 起已升级为一级内置聊天渠道;
ACP(内部代理协议)和 Web(提供者接口)不再列于 CHAT_CHANNEL_META,各自以独立模块运行。
通道注册: src/channels/ids.ts (CHAT_CHANNEL_ORDER / CHANNEL_IDS常量)
2. 核心渠道实现 (extensions/)

2.1 WhatsApp (Baileys)
路径: extensions/whatsapp/ (插件通道)
注: src/whatsapp/ 仅包含消息归一化工具,主要实现在extensions
协议: Baileys Web (开源 WhatsApp Web 协议实现)
功能:
- • 扫码登录 (QR Code)
- • 文本消息收发
- • 媒体消息 (图片/音频/视频/文档)
- • 群组消息
- • 引用回复
- • 状态更新
技术实现:
import makeWASocket from '@whiskeysockets/baileys'
export class WhatsAppChannel {
private sock?: WASocket
async start(): Promise<void> {
const { state, saveCreds } = await useMultiFileAuthState('./auth')
this.sock = makeWASocket({
auth: state,
printQRInTerminal: true
})
this.sock.ev.on('connection.update', this.handleConnection)
this.sock.ev.on('messages.upsert', this.handleMessage)
this.sock.ev.on('creds.update', saveCreds)
}
async sendMessage(to: string, content: string): Promise<void> {
await this.sock!.sendMessage(to, { text: content })
}
}依赖: @whiskeysockets/baileys (7.0.0-rc.9)
2.2 TG (grammY)
路径: extensions/tele*/ (插件通道)
协议: TG Bot API
功能:
- • Bot Token 认证
- • 私聊和群组消息
- • 内联键盘
- • 媒体消息
- • Webhook 模式
- • 长轮询模式
技术实现:
import { Bot } from 'grammy'
import { run } from '@grammyjs/runner'
export class TelegramChannel {
private bot: Bot
async start(token: string): Promise<void> {
this.bot = new Bot(token)
this.bot.on('message', async (ctx) => {
await this.handleMessage(ctx)
})
// 使用 runner 提高性能
run(this.bot)
}
async sendMessage(chatId: number, text: string): Promise<void> {
await this.bot.api.sendMessage(chatId, text)
}
}依赖:
- •
grammy(1.39.3) - •
@grammyjs/runner(2.0.3) - •
@grammyjs/transformer-throttler(1.2.1)
2.3 Slack (Bolt)
路径: extensions/slack/ (插件通道)
协议: Slack Bolt SDK
功能:
- • Socket Mode (无需公网 IP)
- • 事件订阅
- • 斜杠命令
- • 交互式消息
- • 文件上传
- • 线程回复
技术实现:
import { App } from '@slack/bolt'
export class SlackChannel {
private app: App
async start(token: string, appToken: string): Promise<void> {
this.app = new App({
token,
appToken,
socketMode: true
})
this.app.message(async ({ message, say }) => {
await this.handleMessage(message)
})
await this.app.start()
}
async sendMessage(channel: string, text: string): Promise<void> {
await this.app.client.chat.postMessage({
channel,
text
})
}
}依赖: @slack/bolt (4.6.0)
2.4 Discord
路径: extensions/discord/ (插件通道)
协议: Discord.js
功能:
- • Bot Token 认证
- • 文本频道消息
- • 语音频道 (可选)
- • 嵌入消息
- • 按钮和选择菜单
- • 斜杠命令
技术实现:
import { Client, GatewayIntentBits } from 'discord.js'
export class DiscordChannel {
private client: Client
async start(token: string): Promise<void> {
this.client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent
]
})
this.client.on('messageCreate', async (message) => {
await this.handleMessage(message)
})
await this.client.login(token)
}
async sendMessage(channelId: string, content: string): Promise<void> {
const channel = await this.client.channels.fetch(channelId)
if (channel?.isTextBased()) {
await channel.send(content)
}
}
}依赖: discord-api-types (0.38.40) + @snazzah/davey(DAVE 语音加密)
2.5 Google Chat
路径: src/channels/googlechat/, extensions/googlechat/
协议: Google Chat API
功能:
- • Service Account 认证
- • 空间消息
- • 私聊消息
- • 卡片消息
- • 线程回复
技术实现:
import { google } from 'googleapis'
export class GoogleChatChannel {
private chat: any
async start(credentials: ServiceAccountCreds): Promise<void> {
const auth = new google.auth.GoogleAuth({
credentials,
scopes: ['https://www.googleapis.com/auth/chat.bot']
})
this.chat = google.chat({ version: 'v1', auth })
}
async sendMessage(space: string, text: string): Promise<void> {
await this.chat.spaces.messages.create({
parent: space,
requestBody: {
text
}
})
}
}2.6 IRC
路径: extensions/irc/
协议: IRC(Internet Relay Chat)文本协议
特点: 自 v2026.3 起从扩展渠道升级为一级内置聊天渠道
功能:
- • 传统 IRC 网络 DM / 频道路由
- • Pairing 控制
2.7 LINE
路径: src/line/, extensions/line/
协议: LINE Messaging API
依赖: @line/bot-sdk (10.6.0)
3. 扩展渠道 (extensions/)
3.1 Signal
路径: extensions/signal/
协议: signal-cli
特点: 需要本地运行 signal-cli 守护进程
3.2 iMessage
路径: extensions/imessage/
协议: imsg (macOS only)
特点: 仅支持 macOS 系统
3.3 BlueBubbles
路径: extensions/bluebubbles/
协议: BlueBubbles Server API
特点: iMessage 服务器代理
3.4 Microsoft Teams
路径: extensions/msteams/
协议: Bot Framework
3.5 Matrix
路径: extensions/matrix/
协议: Matrix Client-Server API
3.6 Zalo / ZaloUser
路径: extensions/zalo/, extensions/zalouser/
协议: Zalo API
3.7 其他扩展
- •
extensions/feishu/- Feishu/Lark(飞书) - •
extensions/synology-chat/- Synology Chat - •
extensions/tlon/- Tlon (Urbit) - •
extensions/twitch/- Twitch Chat - •
extensions/nostr/- Nostr Protocol - •
extensions/nextcloud-talk/- Nextcloud Talk - •
extensions/mattermost/- Mattermost - •
extensions/voice-call/- Voice Call(Telnyx 语音通话) - •
extensions/phone-control/- 手机控制
3.8 新增扩展插件 (v2026.3)
Talk Voice (extensions/talk-voice/)
职责: 管理 Talk 语音选项(列出/设置语音角色),为语音通话渠道提供声音选择控制。
Thread Ownership (extensions/thread-ownership/)
职责: 防止多个代理同时在同一 Slack 线程中响应,通过调用 slack-forwarder 的 ownership API 实现线程级独占控制。
配置项:
| 字段 | 说明 |
|---|---|
forwarderUrl | slack-forwarder ownership API 基础 URL(默认 http://slack-forwarder:8750) |
abTestChannels | 实施线程所有权控制的 Slack 频道 ID 列表 |
4. 统一渠道接口
4.1 Channel 接口
// src/channels/channel.ts
export interface Channel {
// 渠道元数据
readonly id: string
readonly name: string
readonly type: ChannelType
// 生命周期
start(config: ChannelConfig): Promise<void>
stop(): Promise<void>
restart(): Promise<void>
// 消息收发
sendMessage(target: MessageTarget, content: MessageContent): Promise<void>
onMessage(handler: MessageHandler): void
// 状态查询
getStatus(): ChannelStatus
isConnected(): boolean
// 能力查询
supports(capability: Capability): boolean
}
export interface MessageTarget {
type: 'user' | 'group' | 'channel'
id: string
}
export interface MessageContent {
text?: string
media?: MediaAttachment[]
replyTo?: string
metadata?: Record<string, any>
}
export type MessageHandler = (message: InboundMessage) => Promise<void>
export interface InboundMessage {
id: string
channel: string
from: MessageTarget
to: MessageTarget
content: MessageContent
timestamp: Date
}4.2 Channel Manager
实际路径: src/gateway/server-channels.ts (createChannelManager)
// 集成在Gateway Runtime中,不是独立类
export function createChannelManager(opts) {
private channels: Map<string, Channel> = new Map()
async register(channel: Channel): Promise<void> {
this.channels.set(channel.id, channel)
}
async startAll(): Promise<void> {
for (const channel of this.channels.values()) {
try {
await channel.start(this.getConfig(channel.id))
logger.info(`Started channel: ${channel.id}`)
} catch (error) {
logger.error(`Failed to start channel: ${channel.id}`, error)
}
}
}
async stopAll(): Promise<void> {
for (const channel of this.channels.values()) {
await channel.stop()
}
}
async send(
channelId: string,
target: MessageTarget,
content: MessageContent
): Promise<void> {
const channel = this.channels.get(channelId)
if (!channel) {
throw new Error(`Channel not found: ${channelId}`)
}
await channel.sendMessage(target, content)
}
getStatus(): ChannelStatusMap {
const status: ChannelStatusMap = {}
for (const [id, channel] of this.channels) {
status[id] = channel.getStatus()
}
return status
}
}5. 消息处理流程

5.1 入站消息流
外部平台 (WhatsApp/Telegram/etc.)
↓ Platform Event
渠道实现 (WhatsAppChannel/TGChannel/etc.)
↓ 转换为统一格式
ChannelManager
↓ 发布渠道事件
Gateway 事件总线
↓ 订阅者处理
消息路由层5.2 出站消息流
AI 代理响应
↓
消息路由层
↓ 确定目标渠道
ChannelManager
↓ 查找渠道实例
渠道实现
↓ 平台特定格式
外部平台 API6. 技术实现细节

6.1 渠道生命周期
// src/channels/base-channel.ts
export abstract class BaseChannel implements Channel {
protected status: ChannelStatus = 'disconnected'
protected messageHandlers: MessageHandler[] = []
abstract async connect(): Promise<void>
abstract async disconnect(): Promise<void>
abstract async sendRaw(message: any): Promise<void>
async start(config: ChannelConfig): Promise<void> {
this.config = config
this.status = 'connecting'
try {
await this.connect()
this.status = 'connected'
this.emit('connected')
} catch (error) {
this.status = 'error'
this.emit('error', error)
throw error
}
}
async stop(): Promise<void> {
this.status = 'disconnecting'
await this.disconnect()
this.status = 'disconnected'
this.emit('disconnected')
}
async restart(): Promise<void> {
await this.stop()
await new Promise(resolve => setTimeout(resolve, 1000))
await this.start(this.config)
}
protected handleIncomingMessage(platformMessage: any): void {
// 转换为统一格式
const message = this.transformMessage(platformMessage)
// 调用所有处理器
for (const handler of this.messageHandlers) {
handler(message).catch(error => {
logger.error('Message handler error', error)
})
}
}
abstract transformMessage(platformMessage: any): InboundMessage
}6.2 媒体处理
// src/channels/media-handler.ts
export class MediaHandler {
async downloadMedia(url: string): Promise<Buffer> {
const response = await fetch(url)
return Buffer.from(await response.arrayBuffer())
}
async uploadMedia(
channel: Channel,
media: Buffer,
type: MediaType
): Promise<string> {
// 特定渠道的上传逻辑
if (channel.type === 'telegram') {
return await this.uploadToTelegram(media, type)
}
// 通用上传
return await this.uploadToStorage(media, type)
}
async processMedia(
media: Buffer,
options: ProcessOptions
): Promise<Buffer> {
// 使用媒体管道处理
const pipeline = createMediaPipeline()
return await pipeline.process(media, options)
}
}6.3 错误恢复
// src/channels/error-recovery.ts
export class ChannelRecovery {
private retryCount: Map<string, number> = new Map()
private maxRetries = 3
private backoffMs = 5000
async recover(channel: Channel, error: Error): Promise<void> {
const retries = this.retryCount.get(channel.id) || 0
if (retries >= this.maxRetries) {
logger.error(`Max retries exceeded for channel: ${channel.id}`)
this.emit('recovery_failed', channel, error)
return
}
// 指数退避
const delay = this.backoffMs * Math.pow(2, retries)
await new Promise(resolve => setTimeout(resolve, delay))
try {
await channel.restart()
this.retryCount.set(channel.id, 0)
logger.info(`Successfully recovered channel: ${channel.id}`)
} catch (retryError) {
this.retryCount.set(channel.id, retries + 1)
await this.recover(channel, retryError)
}
}
}7. 渠道配置
7.1 配置结构
channels:
whatsapp:
enabled: true
sessionDir: ~/.openclaw/sessions/whatsapp
autoReconnect: true
slack:
enabled: true
token: env:SLACK_BOT_TOKEN
appToken: env:SLACK_APP_TOKEN
socketMode: true
discord:
enabled: true
token: env:DISCORD_BOT_TOKEN
intents:
- guilds
- guildMessages
- messageContent7.2 环境变量
# Telegram
export TELEGRAM_BOT_TOKEN="123456:ABC-DEF..."
# Slack
export SLACK_BOT_TOKEN="xoxb-..."
export SLACK_APP_TOKEN="xapp-..."
# Discord
export DISCORD_BOT_TOKEN="MTk..."
# Google Chat
export GOOGLE_CHAT_CREDENTIALS='{"type":"service_account",...}'8. 安全特性
8.1 消息验证
// src/channels/message-validator.ts
export class MessageValidator {
validate(message: InboundMessage): ValidationResult {
// 验证消息来源
if (!this.isValidSender(message.from)) {
return { valid: false, reason: 'Invalid sender' }
}
// 验证消息内容
if (!this.isValidContent(message.content)) {
return { valid: false, reason: 'Invalid content' }
}
// 验证消息大小
if (this.isOversized(message)) {
return { valid: false, reason: 'Message too large' }
}
return { valid: true }
}
}8.2 速率限制
// src/channels/rate-limiter.ts
export class ChannelRateLimiter {
private limits: Map<string, RateLimit> = new Map()
async checkLimit(channel: string, action: string): Promise<boolean> {
const key = `${channel}:${action}`
const limit = this.limits.get(key) || this.createLimit()
return await limit.check()
}
private createLimit(): RateLimit {
// Telegram: 30 messages per second
// WhatsApp: Unlimited (但建议限制)
// Slack: 1 message per second per channel
return new RateLimit({
maxRequests: 30,
windowMs: 1000
})
}
}9. 性能优化
9.1 连接复用
// 复用 WebSocket 连接
export class ConnectionPool {
private connections: Map<string, WebSocket> = new Map()
getConnection(url: string): WebSocket {
if (!this.connections.has(url)) {
const ws = new WebSocket(url)
this.connections.set(url, ws)
}
return this.connections.get(url)!
}
}9.2 消息批处理
// 批量发送消息
export class MessageBatcher {
private queue: OutboundMessage[] = []
private flushInterval = 100
enqueue(message: OutboundMessage): void {
this.queue.push(message)
if (this.queue.length >= 10) {
this.flush()
}
}
private async flush(): Promise<void> {
const batch = this.queue.splice(0)
await this.sendBatch(batch)
}
}10. 总结
渠道接入层是 OpenClaw 的多平台桥梁,提供:
- • 广泛兼容: 25+ 消息平台支持
- • 统一抽象: 一致的消息接口
- • 插件化: 独立扩展包
- • 健壮性: 错误恢复和重连
- • 安全性: 消息验证和速率限制
- • 高性能: 连接复用和批处理
v2026.3 变更摘要:
- • IRC 和 Google Chat 升级为一级内置聊天渠道(与 Telegram、Slack 等同级)
- • 新增 Talk Voice 扩展插件(语音选择管理)
- • 新增 Thread Ownership 扩展插件(Slack 多代理线程冲突防护)
使得 OpenClaw 能够跨越不同平台,为用户提供统一的 AI 助手体验。
夜雨聆风