通道抽象层
通道抽象层是 OpenClaw 通道系统的核心设计——通过 ChannelPlugin 接口和 ChannelDock 元数据的分离,实现了"重逻辑运行时加载、轻元数据全局可用"的架构。
ChannelPlugin 接口
Source: src/channels/plugins/types.ts
ChannelPlugin 是每个通道实现必须提供的核心接口,由多个 Adapter 组合而成:
typescript
// src/channels/plugins/types.ts (simplified)
interface ChannelPlugin {
// Capabilities declaration
capabilities: ChannelCapabilities;
// Adapters
outbound: ChannelOutboundAdapter; // Send messages out
messaging: ChannelMessagingAdapter; // Receive messages
commands?: ChannelCommandAdapter; // Handle commands
groups?: ChannelGroupAdapter; // Group-specific behavior
threading?: ChannelThreadingAdapter; // Reply/thread handling
mentions?: ChannelMentionAdapter; // @mention parsing
agentPrompt?: ChannelAgentPromptAdapter; // Platform-specific prompts
}能力声明
typescript
// src/channels/plugins/types.ts (simplified)
interface ChannelCapabilities {
chatTypes: ("direct" | "group" | "channel" | "thread")[];
nativeCommands: boolean; // Supports / commands
blockStreaming: boolean; // Can stream responses
polls: boolean; // Supports polls
reactions: boolean; // Supports reactions
media: MediaCapabilities; // Image/audio/video support
}每个通道声明自己支持的能力,Agent 和路由层据此决定行为。
Adapter 详解
OutboundAdapter — 消息发送
typescript
interface ChannelOutboundAdapter {
sendText(opts: SendTextOpts): Promise<SendResult>;
sendMedia(opts: SendMediaOpts): Promise<SendResult>;
sendPayload?(opts: SendPayloadOpts): Promise<SendResult>;
sendReaction?(opts: SendReactionOpts): Promise<void>;
}ThreadingAdapter — 线程与回复
typescript
interface ChannelThreadingAdapter {
// "first": reply to first message only
// "all": reply to every message
resolveReplyToMode(): "first" | "all";
// Build context for tool execution
buildToolContext(): {
currentChannelId: string;
currentThreadTs?: string;
};
}Telegram 默认使用 "first" 模式(只回复第一条消息),而 Slack 可能使用线程模式。
MentionAdapter — @提及处理
typescript
interface ChannelMentionAdapter {
parseMention(text: string): MentionResult | null;
stripMention(text: string): string;
}ChannelDock 元数据
Source: src/channels/dock.ts
ChannelDock 是轻量级的通道元数据对象,在核心代码中全局可用,不依赖插件运行时:
typescript
// src/channels/dock.ts (simplified)
interface ChannelDock {
id: string; // Channel identifier
capabilities: ChannelCapabilities;
outbound?: ChannelOutboundAdapter;
commands?: ChannelCommandAdapter;
groups?: ChannelGroupAdapter;
mentions?: ChannelMentionAdapter;
threading?: ChannelThreadingAdapter;
agentPrompt?: ChannelAgentPromptAdapter;
// Lightweight metadata (no runtime loading needed)
textChunkLimit: number; // Max chars per message
streamingDefaults: boolean; // Streaming enabled by default
allowFrom: AllowFromConfig; // Access control
}Plugin vs Dock 的分离
为什么要这样分离?
- Dock 是配置读取器和格式化工具——读取
textChunkLimit或allowFrom不需要启动 Telegram bot - Plugin 是运行时操作——连接 bot、监听消息、发送回复等需要实际的网络 I/O
- 这种分离让核心路由逻辑可以快速访问通道元数据,而不必等待插件加载
Mention Gating
Source: src/channels/mention-gating.ts
Mention gating 决定在群组中是否需要 @ 提及才触发 AI 回复:
typescript
// src/channels/mention-gating.ts (simplified)
function resolveMentionGating(
channel: string,
chatType: "direct" | "group",
config: ChannelConfig
): boolean {
// Direct messages: never require mention
if (chatType === "direct") return false;
// Group messages: check per-group settings
// Falls back to channel-level default
return config.requireMention ?? true;
}门控流程
通道配置
Source: src/channels/channel-config.ts
每个通道都有自己的配置模块:
typescript
// src/channels/channel-config.ts (simplified)
interface ChannelConfig {
enabled: boolean;
allowFrom?: AllowFromConfig; // Who can send messages
textChunkLimit?: number; // Override default chunk limit
requireMention?: boolean; // Override mention gating
// Channel-specific settings...
}小结
- ChannelPlugin 接口定义了 7 种 Adapter:Outbound、Messaging、Command、Group、Threading、Mention、AgentPrompt
- ChannelDock 提供轻量元数据,不依赖运行时加载
- 双层分离 让核心路由快速访问元数据,而插件按需加载
- Mention gating 控制群组中是否需要 @提及 才触发 AI
- 每个通道声明自己的 Capabilities,Agent 据此调整行为
下一章:Telegram 实现