一、Channels 概述
Channels 是 OpenClaw 的消息通道层,负责:
• 接收和发送消息 • 多平台适配(Telegram、Discord、钉钉等) • 消息格式转换 • 会话绑定 • 群组权限管理
二、核心文件结构
src/channels/├── plugins/ # 通道插件核心│ ├── types.plugin.ts # 通道插件接口定义│ ├── types.core.ts # 核心类型│ ├── types.adapters.ts # 适配器接口│ ├── registry.ts # 通道注册表│ ├── catalog.ts # 通道目录│ ├── actions/ # 通道动作适配器│ │ ├── telegram.ts│ │ ├── discord.ts│ │ └── signal.ts│ └── contracts/ # 接口契约├── channel-config.ts # 通道配置├── session.ts # 会话管理├── targets.ts # 目标解析├── status-reactions.ts # 状态反应├── typing.ts # 打字状态├── allowlist-match.ts # 白名单匹配└── group-*.ts # 群组相关extensions/ # 通道扩展实现├── telegram/ # Telegram 完整实现│ └── src/│ ├── bot.ts # Bot 核心│ ├── channel.ts # 通道定义│ ├── send.ts # 消息发送│ ├── webhook.ts # Webhook│ └── ...├── discord/ # Discord 实现├── signal/ # Signal 实现├── imessage/ # iMessage 实现├── feishu/ # 飞书实现└── ...三、通道插件接口
3.1 核心接口定义
// src/channels/plugins/types.plugin.tstypeChannelPlugin<ResolvedAccount = any, Probe = unknown, Audit = unknown> = {// 基本信息id: ChannelId;meta: ChannelMeta;capabilities: ChannelCapabilities;// 配置config: ChannelConfigAdapter<ResolvedAccount>;configSchema?: ChannelConfigSchema;// 适配器setup?: ChannelSetupAdapter;pairing?: ChannelPairingAdapter;security?: ChannelSecurityAdapter;groups?: ChannelGroupAdapter;mentions?: ChannelMentionAdapter;outbound?: ChannelOutboundAdapter;status?: ChannelStatusAdapter;gateway?: ChannelGatewayAdapter;auth?: ChannelAuthAdapter;commands?: ChannelCommandAdapter;lifecycle?: ChannelLifecycleAdapter;execApprovals?: ChannelExecApprovalAdapter;allowlist?: ChannelAllowlistAdapter;acpBindings?: ChannelAcpBindingAdapter;streaming?: ChannelStreamingAdapter;threading?: ChannelThreadingAdapter;messaging?: ChannelMessagingAdapter;heartbeat?: ChannelHeartbeatAdapter;// Agent 工具agentTools?: ChannelAgentToolFactory | ChannelAgentTool[];};3.2 通道元信息
typeChannelMeta = {id: ChannelId;label: string; // 显示名称selectionLabel: string; // 选择标签docsPath: string; // 文档路径blurb: string; // 简介order?: number; // 排序aliases?: string[]; // 别名systemImage?: string; // 系统图标};3.3 通道能力
typeChannelCapabilities = {// 消息能力canSendText?: boolean;canSendMedia?: boolean;canSendStickers?: boolean;canSendPolls?: boolean;canEditMessage?: boolean;canDeleteMessage?: boolean;canReact?: boolean;// 线程能力canThread?: boolean;canReplyTo?: boolean;// 群组能力canGroup?: boolean;canMention?: boolean;// 流式能力canStream?: boolean;canTyping?: boolean;};四、适配器详解
4.1 配置适配器 (ConfigAdapter)
typeChannelConfigAdapter<ResolvedAccount> = {// 解析账户resolveAccount(params: {cfg: OpenClawConfig;accountId?: string; }): Promise<ResolvedAccount | null>;// 列出账户listAccountIds(cfg: OpenClawConfig): string[];// 验证配置 validateConfig?(cfg: OpenClawConfig): Promise<void>;};4.2 出站适配器 (OutboundAdapter)
typeChannelOutboundAdapter = {// 发送消息send(params: {cfg: OpenClawConfig;account: ResolvedAccount;to: string;payload: ReplyPayload; }): Promise<SendResult>;// 打字状态 startTyping?(params: {cfg: OpenClawConfig;to: string; }): Promise<void>; stopTyping?(params: {cfg: OpenClawConfig;to: string; }): Promise<void>;};4.3 状态适配器 (StatusAdapter)
typeChannelStatusAdapter<ResolvedAccount, Probe, Audit> = {// 探测状态probe(params: {cfg: OpenClawConfig;account: ResolvedAccount; }): Promise<Probe>;// 审计 audit?(params: {cfg: OpenClawConfig;account: ResolvedAccount; }): Promise<Audit>;// 收集问题 collectIssues?(params: {cfg: OpenClawConfig;account: ResolvedAccount; }): Promise<ChannelStatusIssue[]>;};4.4 群组适配器 (GroupAdapter)
typeChannelGroupAdapter = {// 解析群组策略resolveGroupPolicy(params: {cfg: OpenClawConfig;chatId: string;chatType: "group"; }): Promise<GroupPolicy>;// 检查权限checkGroupAccess(params: {cfg: OpenClawConfig;chatId: string;senderId: string; }): Promise<boolean>;};4.5 线程适配器 (ThreadingAdapter)
typeChannelThreadingAdapter = {// 解析线程 IDresolveThreadId(params: {cfg: OpenClawConfig;message: InboundMessage; }): string | number | null;// 创建线程 createThread?(params: {cfg: OpenClawConfig;to: string;name?: string; }): Promise<string>;};五、支持的通道
| Telegram | extensions/telegram/ | |
| Discord | extensions/discord/ | |
| Signal | extensions/signal/ | |
| iMessage | extensions/imessage/ | |
| 钉钉 | ||
| 飞书 | extensions/feishu/ | |
| Google Chat | extensions/googlechat/ |
六、消息处理流程
6.1 入站消息
通道服务器 (Telegram Bot API / Discord Gateway) ↓extensions/telegram/src/bot.ts (接收) ↓src/channels/plugins/actions/telegram.ts (转换) ↓Gateway (路由) ↓Agent Command (处理) ↓回复生成 ↓Outbound Adapter (发送) ↓通道服务器 → 用户6.2 出站消息
// 1. 构建出站参数const outboundParams = {cfg: config,account: resolvedAccount,to: targetId,payload: replyPayload,};// 2. 调用适配器const result = await channel.outbound.send(outboundParams);// 3. 处理结果if (result.status === "sent") {// 发送成功} elseif (result.status === "failed") {// 发送失败}七、会话绑定
7.1 会话键格式
// 主会话sessionKey = "telegram::default::123456789"// 子会话sessionKey = "telegram::default::123456789::thread::42"7.2 会话解析
// src/routing/session-key.tsfunctionparseSessionKey(sessionKey: string) {const parts = sessionKey.split("::");return {channel: parts[0], // "telegram"accountId: parts[1], // "default"chatId: parts[2], // "123456789"threadId: parts[4], // "42" (可选) };}7.3 ACP 绑定
// 线程绑定到 ACP 会话typeAcpBinding = {sessionKey: string;threadId: string | number;boundAt: number;idleTimeoutMs?: number;};八、消息目标解析
8.1 目标格式
// 用户"telegram::123456789"// 群组"telegram::-100123456789"// 频道"telegram::-100123456789"// 带账户"telegram:default:123456789"8.2 解析逻辑
// src/channels/plugins/target-parsing.tsfunctionparseTarget(target: string) {const match = target.match(/^(\w+)(?::(\w+))?::(-?\d+)$/);if (!match) thrownewError("Invalid target format");return {channel: match[1],accountId: match[2] || "default",chatId: match[3], };}九、打字状态
// src/channels/typing.tstypeTypingState = {channelId: string;chatId: string;startedAt: number;};asyncfunctionstartTyping(channel: string, to: string) {const adapter = getChannelAdapter(channel);await adapter.outbound.startTyping?.({ cfg, to });}asyncfunctionstopTyping(channel: string, to: string) {const adapter = getChannelAdapter(channel);await adapter.outbound.stopTyping?.({ cfg, to });}十、状态反应
// src/channels/status-reactions.ts// 通过消息反应显示状态typeStatusReaction = {emoji: string; // "👀" / "✅" / "❌"messageId: string;state: "thinking" | "done" | "error";};asyncfunctionsetStatusReaction(params: { channel: string; to: string; messageId: string; state: StatusReaction["state"];}) {const emoji = STATUS_EMOJI_MAP[params.state];awaitsendMessageReaction({channel: params.channel,to: params.to,messageId: params.messageId, emoji, });}十一、白名单
11.1 白名单类型
typeAllowlistEntry = | { type: "user"; id: string } | { type: "group"; id: string } | { type: "domain"; domain: string };11.2 白名单匹配
// src/channels/allowlist-match.tsfunctionmatchesAllowlist(params: { entry: AllowlistEntry; sender: { id: string; groupId?: string };}): boolean {switch (params.entry.type) {case"user":return params.sender.id === params.entry.id;case"group":return params.sender.groupId === params.entry.id;case"domain":// 域名匹配returntrue; }}十二、命令门控
// src/channels/command-gating.tsfunctionshouldGateCommand(params: { command: string; chatType: "direct" | "group"; config: OpenClawConfig;}): boolean {// 群组中某些命令需要提及if (params.chatType === "group") {const gatedCommands = config.channels?.gatedCommands ?? [];return gatedCommands.includes(params.command); }returnfalse;}十三、总结
Channels 是 OpenClaw 的消息门户:
1. 插件架构:通过 ChannelPlugin 接口定义统一规范 2. 适配器模式:每个功能点(配置、出站、状态等)独立适配 3. 扩展目录: extensions/存放具体通道实现4. 会话绑定:支持线程级会话隔离 5. 权限控制:白名单、群组策略、命令门控
关键特性:
• 统一的通道接口 • 热插拔扩展 • 会话级绑定 • 流式消息支持 • 状态反应
夜雨聆风