一、Channel 系统定位
Channel 系统是 OpenClaw 的消息渠道抽象层——通过统一接口接入 30+ 消息平台,对上屏蔽平台差异。
┌─────────────────────────────────────────────────────────────┐
│ OpenClaw Core │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Gateway │ │ Agent RT │ │ Memory │ │
│ └──────┬───────┘ └──────────────┘ └──────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Channel 抽象层 (src/channels/) │ │
│ │ inbound → session → outbound │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────┬─────────────────────────────────┘
│
┌─────────────────────────┼─────────────────────────────────┐
│ Channel 插件层 (extensions/channels/) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │telegram/│ │discord/ │ │whatsapp/│ │ slack/ │ ... │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────┘
二、模块结构
| 文件 | 职责 |
|---|
channels/plugins/types.plugin.ts | ChannelPlugin 接口定义 |
channels/plugins/types.core.ts | 核心类型(ChannelId、ChannelCapabilities) |
channels/plugins/types.adapters.ts | 各 Adapter 接口 |
channels/plugins/config-schema.ts | 配置 Schema |
channels/plugins/config-writes.ts | 配置写入逻辑 |
channels/plugins/config-helpers.ts | 配置辅助函数 |
channels/inbound-debounce-policy.ts | 入站消息去抖 |
channels/conversation-resolution.ts | 会话解析 |
channels/allow-from.ts | AllowFrom 逻辑 |
channels/mention-gating.ts | 提及过滤 |
extensions/channels/*/ | 30+ Channel 插件 |
三、ChannelPlugin 接口
文件:channels/plugins/types.plugin.ts
3.1 完整接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| export type ChannelPlugin<
ResolvedAccount = any,
Probe = unknown,
Audit = unknown,
> = {
id: ChannelId;
meta: ChannelMeta;
capabilities: ChannelCapabilities;
defaults?: { queue?: { debounceMs?: number } };
reload?: { configPrefixes: string[]; noopPrefixes?: string[] };
// Setup Wizard
setupWizard?: ChannelSetupWizard | ChannelSetupWizardAdapter;
// Configuration
config: ChannelConfigAdapter<ResolvedAccount>;
configSchema?: ChannelConfigSchema;
// Setup flow
setup?: ChannelSetupAdapter;
// Pairing
pairing?: ChannelPairingAdapter;
// Security & Groups
security?: ChannelSecurityAdapter<ResolvedAccount>;
groups?: ChannelGroupAdapter;
mentions?: ChannelMentionAdapter;
// Messaging
outbound?: ChannelOutboundAdapter;
status?: ChannelStatusAdapter<ResolvedAccount, Probe, Audit>;
messaging?: ChannelMessagingAdapter;
streaming?: ChannelStreamingAdapter;
threading?: ChannelThreadingAdapter;
// Lifecycle
lifecycle?: ChannelLifecycleAdapter;
heartbeat?: ChannelHeartbeatAdapter;
// Commands & Tools
commands?: ChannelCommandAdapter;
agentTools?: ChannelAgentToolFactory | ChannelAgentTool[];
// Auth
auth?: ChannelAuthAdapter;
approvalCapability?: ChannelApprovalCapability;
elevated?: ChannelElevatedAdapter;
// Gateway
gatewayMethods?: string[];
gateway?: ChannelGatewayAdapter<ResolvedAccount>;
// Bindings
bindings?: ChannelConfiguredBindingProvider;
conversationBindings?: ChannelConversationBindingSupport;
// Misc
secrets?: ChannelSecretsAdapter;
allowlist?: ChannelAllowlistAdapter;
doctor?: ChannelDoctorAdapter;
agentPrompt?: ChannelAgentPromptAdapter;
directory?: ChannelDirectoryAdapter;
resolver?: ChannelResolverAdapter;
actions?: ChannelMessageActionAdapter;
};
|
3.2 ChannelId
1
2
3
| // channels/plugins/types.core.ts
export type ChannelId = string;
// e.g. "telegram", "discord", "whatsapp", "slack"
|
3.3 ChannelCapabilities
1
2
3
4
5
6
7
8
9
10
11
12
| export type ChannelCapabilities = {
streaming: boolean; // 支持流式响应
markdown: boolean; // 支持 Markdown
markdownCode: boolean; // 支持代码块
typing: boolean; // 支持输入状态
reactions: boolean; // 支持反应
multiModal: boolean; // 支持多模态
conversationThreading: boolean; // 支持线程
allowFrom: boolean; // 支持 allowFrom 过滤
nativeMentions: boolean; // 原生提及
nativeCommand: boolean; // 原生命令
};
|
四、消息收发流程
4.1 入站(Inbound)
外部消息 → Channel Plugin → inbound-debounce → session → Agent RT
channels/plugins/ 中的 lifecycle.ts 定义了入站处理钩子。
1
2
3
4
5
6
7
8
| export type ChannelLifecycleAdapter = {
start?: (ctx: ChannelLifecycleStartContext) => Promise<void>;
stop?: (ctx: ChannelLifecycleStopContext) => Promise<void>;
onInboundContext?: (ctx: ChannelLifecycleInboundContext) => Promise<void>;
onInboundMessage?: (ctx: ChannelLifecycleInboundMessage) => Promise<boolean>;
onOutboundMessage?: (ctx: ChannelLifecycleOutboundMessage) => Promise<void>;
onError?: (ctx: ChannelLifecycleError) => Promise<void>;
};
|
4.2 出站(Outbound)
1
2
3
4
5
6
| export type ChannelOutboundAdapter = {
sendMessage(ctx: ChannelOutboundSendMessageContext): Promise<ChannelOutboundResult>;
sendReaction?(ctx: ChannelOutboundSendReactionContext): Promise<ChannelOutboundResult>;
sendTyping?(ctx: ChannelOutboundSendTypingContext): Promise<ChannelOutboundResult>;
sendDraft?(ctx: ChannelOutboundSendDraftContext): Promise<ChannelOutboundResult>;
};
|
4.3 去抖策略
文件:channels/inbound-debounce-policy.ts
1
2
3
4
5
6
| export type InboundDebouncePolicy = {
id: string;
debounceMs?: number;
maxBatchSize?: number;
maxWaitMs?: number;
};
|
五、会话解析
5.1 Conversation Resolution
文件:channels/conversation-resolution.ts
1
2
3
4
5
6
7
8
9
| export function resolveInboundConversationResolution(params: {
cfg: OpenClawConfig;
channel: string;
accountId?: string;
to?: string;
threadId?: string | number;
groupId?: string;
isGroup: boolean;
}): InboundConversationResolutionResult | null;
|
5.2 ChannelConfig
1
2
3
4
5
6
| // channels/plugins/config-helpers.ts
export function resolveChannelConfig(params: {
cfg: OpenClawConfig;
channelId: string;
accountId?: string;
}): ResolvedChannelConfig | null;
|
六、配置管理
6.1 Config Schema
文件:channels/plugins/config-schema.ts
1
2
3
4
5
6
| export type ChannelConfigSchema = {
type: "object";
properties: Record<string, JsonSchemaObject>;
required?: string[];
additionalProperties?: boolean;
};
|
6.2 Config Writes
文件:channels/plugins/config-writes.ts
1
2
3
4
5
6
| export async function writeChannelConfig(params: {
cfg: OpenClawConfig;
channelId: string;
accountId: string;
updates: Record<string, unknown>;
}): Promise<void>;
|
七、AllowFrom 机制
文件:channels/allow-from.ts
7.1 Allowlist Match
1
2
3
4
5
6
| export function resolveAllowFrom(params: {
cfg: OpenClawConfig;
channelId: string;
accountId: string;
senderId: string;
}): AllowFromResult;
|
7.2 Match Types
| 类型 | 说明 |
|---|
allow | 明确允许 |
deny | 明确拒绝 |
no_match | 无匹配规则 |
八、支持的 Channel 列表
| Channel | 说明 |
|---|
telegram | Telegram |
discord | Discord |
whatsapp | WhatsApp |
slack | Slack |
microsoft | Microsoft Teams |
googlechat | Google Chat |
msteams | Microsoft Teams(原生) |
matrix | Matrix |
irc | IRC |
signal | Signal |
feishu | 飞书 |
line | LINE |
mattermost | Mattermost |
nextcloud-talk | Nextcloud Talk |
synology-chat | 群晖 Chat |
tlon | Tlon |
nostr | Nostr |
twitch | Twitch |
bluebubbles | BlueBubbles(iMessage) |
imessage | iMessage |
九、设计权衡
9.1 Adapter 模式
ChannelPlugin 使用大量 Adapter 接口,允许插件选择性地实现功能:
1
2
3
4
5
| // 每个 Adapter 都是可选的
setup?: ChannelSetupAdapter; // 可选
pairing?: ChannelPairingAdapter; // 可选
security?: ChannelSecurityAdapter; // 可选
// ...
|
这使得简单渠道(如 IRC)只需实现核心接口,复杂渠道(如 Discord)可以实现全套。
9.2 Config Schema 分离
configSchema: 声明式配置定义(用于 UI 生成)config: 运行时配置访问
这种分离允许 Setup UI 在不加载运行时的情况下渲染配置表单。
9.3 Channel ID vs Account ID
ChannelId: 渠道类型标识(如 "telegram")AccountId: 同一渠道下的多个账号(如 "default"、"personal"、"work")
下一步
下一篇:07 - 会话与状态管理,深入会话生命周期与状态持久化。
OpenClaw 源码剖析系列 · 2026 · skyseraph