OpenClaw源码剖析 #06 · Channel 系统:多渠道消息接入

一、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.tsChannelPlugin 接口定义
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.tsAllowFrom 逻辑
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说明
telegramTelegram
discordDiscord
whatsappWhatsApp
slackSlack
microsoftMicrosoft Teams
googlechatGoogle Chat
msteamsMicrosoft Teams(原生)
matrixMatrix
ircIRC
signalSignal
feishu飞书
lineLINE
mattermostMattermost
nextcloud-talkNextcloud Talk
synology-chat群晖 Chat
tlonTlon
nostrNostr
twitchTwitch
bluebubblesBlueBubbles(iMessage)
imessageiMessage

九、设计权衡

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

SkySeraph
SkySeraph
AI for All & All for AI
留言 Comments