1033 lines
27 KiB
Markdown
1033 lines
27 KiB
Markdown
# OpenClaw 系统架构设计文档
|
||
|
||
> 项目:https://github.com/openclaw/openclaw
|
||
> 文档版本:1.0
|
||
> 创建日期:2026-02-06
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
- [1. 概述](#1-概述)
|
||
- [2. 项目整体结构](#2-项目整体结构)
|
||
- [3. 核心架构设计](#3-核心架构设计)
|
||
- [3.1 CLI 命令系统](#31-cli-命令系统)
|
||
- [3.2 网关架构](#32-网关架构)
|
||
- [3.3 消息通道系统](#33-消息通道系统)
|
||
- [3.4 媒体管道](#34-媒体管道)
|
||
- [3.5 基础设施层](#35-基础设施层)
|
||
- [4. 关键设计模式](#4-关键设计模式)
|
||
- [4.1 依赖注入](#41-依赖注入)
|
||
- [4.2 状态管理](#42-状态管理)
|
||
- [4.3 消息路由机制](#43-消息路由机制)
|
||
- [4.4 配置系统](#44-配置系统)
|
||
- [4.5 钩子系统](#45-钩子系统)
|
||
- [5. 插件扩展机制](#5-插件扩展机制)
|
||
- [5.1 插件类型](#51-插件类型)
|
||
- [5.2 插件 API](#52-插件-api)
|
||
- [5.3 通道插件](#53-通道插件)
|
||
- [5.4 插件运行时](#54-插件运行时)
|
||
- [6. 路与会话管理](#6-路由与会话管理)
|
||
- [6.1 路由解析](#61-路由解析)
|
||
- [6.2 会话管理](#62-会话管理)
|
||
- [6.3 会话持久化](#63-会话持久化)
|
||
- [7. 模块间关系](#7-模块间关系)
|
||
- [8. 通信协议](#8-通信协议)
|
||
- [8.1 Gateway Protocol](#81-gateway-protocol)
|
||
- [8.2 ACP (Agent Client Protocol)](#82-acp-agent-client-protocol)
|
||
- [9. 认证与安全](#9-认证与安全)
|
||
- [9.1 设备配对](#91-设备配对)
|
||
- [9.2 Gateway 认证](#92-gateway-认证)
|
||
- [9.3 SSRF 防护](#93-ssrf-防护)
|
||
- [10. 测试策略](#10-测试策略)
|
||
- [11. 构建与部署](#11-构建与部署)
|
||
- [12. 编码规范](#12-编码规范)
|
||
- [13. 附录:代码示例](#13-附录代码示例)
|
||
|
||
---
|
||
|
||
## 1. 概述
|
||
|
||
OpenClaw 是一个多平台消息聚合与 AI Agent 平台,支持 WhatsApp、Telegram、Discord、Slack、Signal、iMessage 等多个消息通道,以及多种 AI 模型提供者。
|
||
|
||
### 1.1 核心特性
|
||
|
||
- **多通道支持**:通过插件化架构支持十多种消息平台
|
||
- **Gateway 架构**:集中式的 WebSocket 网关服务所有客户端
|
||
- **插件系统**:可扩展的插件机制(通道、模型提供者、内存等)
|
||
- **灵活路由**:基于绑定的智能消息路由
|
||
- **会话管理**:持久化的会话存储和历史记录
|
||
- **媒体处理**:完整的媒体上传、存储和处理管道
|
||
|
||
### 1.2 技术栈
|
||
|
||
- **语言**:TypeScript (ESM)
|
||
- **运行时**:Node 22+,支持 Bun
|
||
- **包管理**:pnpm(保持 npm 兼容性)
|
||
- **测试**:Vitest + V8 覆盖率
|
||
- **Lint/Format**:Oxlint + Oxfmt
|
||
- **协议**:WebSocket (JSON),HTTP (REST + OpenAI 兼容)
|
||
|
||
---
|
||
|
||
## 2. 项目整体结构
|
||
|
||
### 2.1 主要目录
|
||
|
||
```
|
||
openclaw/
|
||
├── src/
|
||
│ ├── cli/ # CLI 入口和命令系统
|
||
│ ├── commands/ # 命令实现
|
||
│ ├── gateway/ # Gateway 服务器
|
||
│ ├── channels/ # 通道系统
|
||
│ ├── providers/ # AI 模型提供者
|
||
│ ├── agents/ # Agent 运行时
|
||
│ ├── media/ # 媒体管道
|
||
│ ├── infra/ # 基础设施
|
||
│ ├── config/ # 配置系统
|
||
│ ├── plugins/ # 插件系统
|
||
│ ├── plugin-sdk/ # 插件开发 SDK
|
||
│ ├── routing/ # 路由系统
|
||
│ ├── acp/ # Agent Client Protocol
|
||
│ ├── pairing/ # 设备配对
|
||
│ ├── hooks/ # 生命周期钩子
|
||
│ ├── terminal/ # 终端输出工具
|
||
│ ├── logging/ # 日志系统
|
||
│ └── ...
|
||
├── extensions/ # 扩展插件(工作区包)
|
||
├── apps/ # 移动应用和 macOS 应用
|
||
├── ui/ # Web UI (dien)
|
||
├── docs/ # 文档
|
||
├── skills/ # 内置技能
|
||
└── openclaw.mjs # CLI 入口点
|
||
```
|
||
|
||
### 2.2 程序入口
|
||
|
||
```
|
||
openclaw.mjs (编译缓存入口)
|
||
└─> src/index.ts
|
||
└─> buildProgram()
|
||
├─> createProgramContext()
|
||
└─> registerProgramCommands()
|
||
```
|
||
|
||
### 2.3 包导出
|
||
|
||
```json
|
||
{
|
||
"exports": {
|
||
".": "./dist/index.js",
|
||
"./plugin-sdk": "./dist/plugin-sdk/index.js",
|
||
"./cli-entry": "./openclaw.mjs"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 核心架构设计
|
||
|
||
### 3.1 CLI 命令系统
|
||
|
||
#### 3.1.1 命令注册表模式
|
||
|
||
CLI 基于 `commander`,采用注册表模式进行命令注册:
|
||
|
||
```typescript
|
||
// src/cli/program/command-registry.ts
|
||
export const commandRegistry: CommandRegistration[] = [
|
||
{ id: "setup", register: ({ program }) => registerSetupCommand(program) },
|
||
{ id: "onboard", register: ({ program }) => registerOnboardCommand(program) },
|
||
{ id: "config", register: ({ program }) => registerConfigCli(program) },
|
||
{ id: "memory", register: ({ program }) => registerMemoryCli(program) },
|
||
{ id: "agent", register: ({ program, ctx }) => registerAgentCommands(program, ctx) },
|
||
// ... 更多命令
|
||
];
|
||
```
|
||
|
||
#### 3.1.2 命令分类
|
||
|
||
| 类别 | 模块 | 示例命令 |
|
||
| -------- | --------------- | ------------------------------ |
|
||
| 核心命令 | `src/commands/` | `agent`, `send`, `message` |
|
||
| 配置命令 | `src/config/` | `config set/get/apply` |
|
||
| 通道命令 | Sub CLI | `channels status/login/logout` |
|
||
| Gateway | Sub CLI | `gateway run/stop` |
|
||
| Daemon | Sub CLI | `daemon start/stop` |
|
||
| 节点 | Sub CLI | `nodes list/status` |
|
||
|
||
#### 3.1.3 路由机制
|
||
|
||
```typescript
|
||
// src/cli/program/routing.ts
|
||
export type RouteSpec = {
|
||
match: (path: string[]) => boolean;
|
||
loadPlugins?: boolean; // 是否加载插件以解析命令
|
||
run: (argv: string[]) => Promise<boolean>;
|
||
};
|
||
```
|
||
|
||
路由机制允许快速解析某些命令路径,例如网关模式下直接启动而无需加载所有插件。
|
||
|
||
---
|
||
|
||
### 3.2 网关架构
|
||
|
||
#### 3.2.1 网关启动入口
|
||
|
||
```
|
||
src/gateway/server.impl.ts
|
||
└─> startGatewayServer(port, opts): Promise<GatewayServer>
|
||
```
|
||
|
||
#### 3.2.2 核心子系统
|
||
|
||
| 子系统 | 实现路径 | 职责 |
|
||
| ---------- | ------------------------------------- | --------------------- |
|
||
| 协议验证 | `src/gateway/protocol/` | Ajv 验证所有 JSON 帧 |
|
||
| 方法处理器 | `src/gateway/server-methods/` | 各个 gateway 方法实现 |
|
||
| 运行时状态 | `src/gateway/server-runtime-state.ts` | 服务器状态、缓冲区 |
|
||
| 通道管理 | `src/gateway/server-channels.ts` | 通道启停 |
|
||
| 事件处理 | `src/gateway/server-chat.ts` | Agent 事件和广播 |
|
||
| WebSocket | `src/gateway/server-ws-runtime.ts` | WS 连接和帧分发 |
|
||
| 配置重载 | `src/gateway/config-reload.ts` | 监听配置变更 |
|
||
| 启动/停止 | `src/gateway/server-close.ts` | 优雅关闭 |
|
||
| 协议定义 | `src/gateway/protocol/` | 请求/事件帧模式 |
|
||
|
||
#### 3.2.3 网关启动流程
|
||
|
||
```
|
||
startGatewayServer()
|
||
├─> 加载配置 (loadConfig)
|
||
├─> 加载插件 (loadGatewayPlugins)
|
||
│ ├─> 注册插件钩子
|
||
│ ├─> 注册通道插件
|
||
│ └─> 注册自定义 Gateway 方法
|
||
├─> 创建运行时状态 (createGatewayRuntimeState)
|
||
│ ├─> HTTP 服务器
|
||
│ ├─> WebSocket 服务器
|
||
│ ├─> Canvas Host (a2ui, 端口 18793)
|
||
│ └─> 协议验证 (AJV)
|
||
├─> 注册状态恢复
|
||
├─> 注册方法处理器 (coreGatewayHandlers + plugin 处理器)
|
||
├─> 启动通道 (startChannels)
|
||
├─> 启动 Cron 服务 (buildGatewayCronService)
|
||
├─> 配置重载监听 (startGatewayConfigReloader)
|
||
└─> 返回 GatewayServer 实例
|
||
```
|
||
|
||
#### 3.2.4 HTTP 端点
|
||
|
||
默认端口:`18789`
|
||
|
||
| 端点 | 方法 | 用途 |
|
||
| ---------------------- | --------- | ------------------ |
|
||
| `/ws` | WebSocket | 控制和事件流 |
|
||
| `/v1/gateway/*` | POST | 增量 API 方法 |
|
||
| `/v1/chat/completions` | POST | OpenAI 兼容 |
|
||
| `/v1/responses` | POST | OpenResponses 兼容 |
|
||
| `/media/*` | GET/PUT | 媒体服务 |
|
||
|
||
---
|
||
|
||
### 3.3 消息通道系统
|
||
|
||
#### 3.3.1 通道插件化
|
||
|
||
所有通道必须实现 `ChannelPlugin` 接口:
|
||
|
||
```typescript
|
||
export type ChannelPlugin<ResolvedAccount, Probe, Audit> = {
|
||
id: ChannelId;
|
||
meta: ChannelMeta;
|
||
capabilities: ChannelCapabilities;
|
||
config: ChannelConfigAdapter<ResolvedAccount>;
|
||
configSchema?: ChannelConfigSchema;
|
||
setup?: ChannelSetupAdapter;
|
||
pairing?: ChannelPairingAdapter;
|
||
security?: ChannelSecurityAdapter<ResolvedAccount>;
|
||
groups?: ChannelGroupAdapter;
|
||
mentions?: ChannelMentionAdapter;
|
||
outbound?: ChannelOutboundAdapter;
|
||
status?: ChannelStatusAdapter<ResolvedAccount, Probe, Audit>;
|
||
gatewayMethods?: string[];
|
||
gateway?: ChannelGatewayAdapter<ResolvedAccount>;
|
||
auth?: ChannelAuthAdapter;
|
||
elevated?: ChannelElevatedAdapter;
|
||
commands?: ChannelCommandAdapter;
|
||
streaming?: ChannelStreamingAdapter;
|
||
threading?: ChannelThreadingAdapter;
|
||
messaging?: ChannelMessagingAdapter;
|
||
agentPrompt?: ChannelAgentPromptAdapter;
|
||
directory?: ChannelDirectoryAdapter;
|
||
resolver?: ChannelResolverAdapter;
|
||
actions?: ChannelMessageActionAdapter;
|
||
heartbeat?: ChannelHeartbeatAdapter;
|
||
agentTools?: ChannelAgentToolFactory | ChannelAgentTool[];
|
||
};
|
||
```
|
||
|
||
#### 3.3.2 核心适配器
|
||
|
||
| 适配器 | 接口 | 职责 |
|
||
| ------------------------- | ---------------------------------- | ---------- |
|
||
| `ChannelConfigAdapter` | `listAccountIds`, `resolveAccount` | 配置解析 |
|
||
| `ChannelOutboundAdapter` | `sendText`, `sendMedia` | 消息发送 |
|
||
| `ChannelGatewayAdapter` | `startAccount`, `stopAccount` | 网关启停 |
|
||
| `ChannelStatusAdapter` | `snapshots`, `probe`, `audit` | 状态探查 |
|
||
| `ChannelGroupAdapter` | `resolveGroup` | 群组上下文 |
|
||
| `ChannelSecurityAdapter` | `resolveDMPolicy` | 安全策略 |
|
||
| `ChannelDirectoryAdapter` | `listGroups`, `listPeers` | 用户目录 |
|
||
| `ChannelAuthAdapter` | `login` | 登录流程 |
|
||
|
||
#### 3.3.3 内置通道
|
||
|
||
| 通道 | 实现目录 |
|
||
| ------------ | --------------------------- |
|
||
| WhatsApp Web | `src/web/`, `src/whatsapp/` |
|
||
| Telegram | `src/telegram/` |
|
||
| Discord | `src/discord/` |
|
||
| Slack | `src/slack/` |
|
||
| Signal | `src/signal/` |
|
||
| iMessage | `src/imessage/` |
|
||
| LINE | `src/line/` |
|
||
| Google Chat | `src/googlechat/` |
|
||
| MS Teams | `src/msteams/` |
|
||
|
||
#### 3.3.4 扩展通道
|
||
|
||
位于 `extensions/*/`:
|
||
|
||
- `bluebubbles` / `matrix` / `msteams` (extension)
|
||
- `tton` / `zalo` / `zalouser`
|
||
- `nostr` / `mattermost`
|
||
- `nextcloud-talk` / `feishu`
|
||
|
||
---
|
||
|
||
### 3.4 媒体管道
|
||
|
||
#### 3.4.1 核心组件
|
||
|
||
| 文件 | 职责 |
|
||
| -------------- | -------------------------------------------- |
|
||
| `mime.ts` | MIME 类型检测(magic number + content type) |
|
||
| `parse.ts` | 消息媒介提取(文本、图片、音频等) |
|
||
| `store.ts` | 磁盘存储,文件命名 `{original}---{uuid}.ext` |
|
||
| `fetch.ts` | HTTP/HTTPS 远程获取 |
|
||
| `host.ts` | HTTP 服务,鉴权和 Headers |
|
||
| `image-ops.ts` | 图片调整大小 (JPEG) |
|
||
| `audio.ts` | 音频转换、兼容性检查 |
|
||
| `server.ts` | HTTP 服务配置 |
|
||
|
||
#### 3.4.2 存储结构
|
||
|
||
```
|
||
~/.openclaw/media/
|
||
├── inbound/ # 接收的媒体
|
||
└── outbound/ # 发送的媒体
|
||
```
|
||
|
||
#### 3.4.3 媒体处理流程
|
||
|
||
```
|
||
入站:
|
||
消息媒介提取
|
||
↓
|
||
MIME 检测 (magic number)
|
||
↓
|
||
保存到磁盘 (store.ts)
|
||
↓
|
||
生成内部 URL
|
||
|
||
出站:
|
||
媒体上传/处理
|
||
↓
|
||
MIME 检测
|
||
↓
|
||
压缩/转换 (可选)
|
||
↓
|
||
保存到磁盘
|
||
↓
|
||
通过 HTTP 端点服务
|
||
```
|
||
|
||
---
|
||
|
||
### 3.5 基础设施层
|
||
|
||
#### 3.5.1 端口管理
|
||
|
||
`src/infra/ports.ts`
|
||
|
||
| 功能 | 说明 |
|
||
| -------------------------- | ------------------ |
|
||
| `checkPortAvailability` | 检查端口是否可用 |
|
||
| `killPortOccupyingProcess` | 杀死占用端口的进程 |
|
||
| `autoDetectAvailablePort` | 自动检测可用端口 |
|
||
| `DEFAULT_PORT` | 默认端口 18789 |
|
||
|
||
#### 3.5.2 SSRF 防护
|
||
|
||
`src/infra/net/ssrf.ts`
|
||
|
||
解析主机名并验证是否为安全的内部地址。
|
||
|
||
#### 3.5.3 事件系统
|
||
|
||
| 表件 | 事件类型 |
|
||
| ---------------------- | ------------ |
|
||
| `diagnostic-events.ts` | 诊断事件 |
|
||
| `heartbeat-events.ts` | 心跳事件 |
|
||
| `system-events.ts` | 系统事件队列 |
|
||
| `channel-activity.ts` | 通道活动跟踪 |
|
||
|
||
#### 3.5.4 出站传送
|
||
|
||
`src/infra/outbound/deliver.ts`
|
||
|
||
支持三种传送模式:
|
||
|
||
- `single` - 单通道
|
||
- `gateway` - 通过网关
|
||
- `mixed` - 混合模式
|
||
|
||
---
|
||
|
||
## 4. 关键设计模式
|
||
|
||
### 4.1 依赖注入
|
||
|
||
#### 4.1.1 CLI 依赖
|
||
|
||
```typescript
|
||
// src/cli/deps.ts
|
||
export type CliDeps = {
|
||
sendMessageWhatsApp: typeof sendMessageWhatsApp;
|
||
sendMessageTelegram: typeof sendMessageTelegram;
|
||
sendMessageDiscord: typeof sendMessageDiscord;
|
||
sendMessageSlack: typeof sendMessageSlack;
|
||
sendMessageSignal: typeof sendMessageSignal;
|
||
sendMessageIMessage: typeof sendMessageIMessage;
|
||
};
|
||
|
||
export function createDefaultDeps(): CliDeps {
|
||
return {
|
||
sendMessageWhatsApp,
|
||
sendMessageTelegram,
|
||
sendMessageDiscord,
|
||
sendMessageSlack,
|
||
sendMessageSignal,
|
||
sendMessageIMessage,
|
||
};
|
||
}
|
||
```
|
||
|
||
#### 4.1.2 插件运行时依赖
|
||
|
||
```typescript
|
||
// src/plugins/runtime/types.ts
|
||
export type PluginRuntime = {
|
||
version: string;
|
||
config: { loadConfig, writeConfigFile };
|
||
system: { enqueueSystemEvent, runCommandWithTimeout };
|
||
media: { loadWebMedia, detectMime, mediaKindFromMime, ... };
|
||
tts: { textToSpeechTelephony };
|
||
tools: { createMemoryGetTool, createMemorySearchTool, ... };
|
||
channel: {
|
||
text: { chunkByNewline, chunkMarkdownText, ... };
|
||
reply: { dispatchReplyWithBufferedBlockDispatcher, ... };
|
||
routing: { resolveAgentRoute };
|
||
pairing: { buildPairingReply, ... };
|
||
network: { fetchRemoteMedia, saveMediaBuffer };
|
||
activity: { record, get };
|
||
session: { resolveStorePath, ... };
|
||
// 各通道特定函数...
|
||
};
|
||
logging: { shouldLogVerbose, getChildLogger };
|
||
state: { resolveStateDir };
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
### 4.2 状态管理
|
||
|
||
#### 4.2.1 配置状态
|
||
|
||
```typescript
|
||
// 配置加载流程
|
||
loadConfig() → parseConfigJson5() → validateConfigObject() → migrateLegacyConfig()
|
||
```
|
||
|
||
配置文件位置:`~/.openclaw/config.json5`
|
||
|
||
#### 4.2.2 配置监听和重载
|
||
|
||
`src/gateway/config-reload.ts`
|
||
|
||
监听配置文件变更,触发网关状态更新。
|
||
|
||
#### 4.2.3 通道状态
|
||
|
||
```typescript
|
||
// src/gateway/server-channels.ts
|
||
type ChannelRuntime = {
|
||
id: string;
|
||
accountId: string;
|
||
status: Snapshot;
|
||
stop?: () => Promise<void>;
|
||
// ...
|
||
};
|
||
```
|
||
|
||
#### 4.2.4 会话状态
|
||
|
||
会话存储位置:`~/.openclaw/sessions/{channel}/{accountId}/{session}.jsonl`
|
||
|
||
会话键格式:`session/{agentId}/{channel}/{accountId}/{peer}`
|
||
|
||
---
|
||
|
||
### 4.3 消息路由机制
|
||
|
||
#### 4.3.1 路由解析
|
||
|
||
```typescript
|
||
// src/routing/resolve-route.ts
|
||
export type ResolveAgentRouteInput = {
|
||
cfg: OpenClawConfig;
|
||
channel: string;
|
||
accountId?: string | null;
|
||
peer?: RoutePeer | null;
|
||
parentPeer?: RoutePeer | null;
|
||
guildId?: string | null;
|
||
teamId?: string | null;
|
||
};
|
||
|
||
export type ResolvedAgentRoute = {
|
||
agentId: string;
|
||
channel: string;
|
||
accountId: string;
|
||
sessionKey: string;
|
||
mainSessionKey: string;
|
||
matchedBy:
|
||
| "binding.peer"
|
||
| "binding.peer.parent"
|
||
| "binding.guild"
|
||
| "binding.team"
|
||
| "binding.account"
|
||
| "binding.channel"
|
||
| "default";
|
||
};
|
||
```
|
||
|
||
#### 4.3.2 路由匹配优先级
|
||
|
||
```
|
||
1. peer (具体用户/组)
|
||
2. thread parent peer (继承)
|
||
3. guildId (Discord 服务器)
|
||
4. teamId (Slack/Teams)
|
||
5. account (非通配符)
|
||
6. account (通配符)
|
||
7. default (默认代理)
|
||
```
|
||
|
||
#### 4.3.3 会话键构建
|
||
|
||
```typescript
|
||
// src/routing/session-key.ts
|
||
export function buildAgentSessionKey(params: {
|
||
agentId: string;
|
||
channel: string;
|
||
accountId?: string | null;
|
||
peer?: RoutePeer | null;
|
||
dmScope?: "main" | "per-peer" | "per-channel-peer" | "per-account-channel-peer";
|
||
identityLinks?: Record<string, string[]>;
|
||
}): string;
|
||
```
|
||
|
||
---
|
||
|
||
### 4.4 配置系统
|
||
|
||
#### 4.4.1 配置模块
|
||
|
||
```
|
||
src/config/
|
||
├── types.agent-defaults.ts
|
||
├── types.agents.ts
|
||
├── types.auth.ts
|
||
├── types.base.ts
|
||
├── types.browser.ts
|
||
├── types.channels.ts
|
||
├── types.openclaw.ts
|
||
├── types.cron.ts
|
||
├── types.sandbox.ts
|
||
├── types.memory.ts
|
||
├── types.models.ts
|
||
├── types.node-host.ts
|
||
├── types.tts.ts
|
||
├── types.tools.ts
|
||
├── types.whatsapp.ts
|
||
├── types.imessage.ts
|
||
├── types.slack.ts
|
||
├── ... (更多通道配置)
|
||
├── config.ts (主导出)
|
||
└── ...
|
||
```
|
||
|
||
#### 4.4.2 验证机制
|
||
|
||
使用 Zod 进行模式验证:
|
||
|
||
```typescript
|
||
validateConfigObject(config): ValidationResult
|
||
validateConfigObjectWithPlugins(config, plugins): ValidationResult
|
||
```
|
||
|
||
#### 4.4.3 配置迁移
|
||
|
||
`migrateLegacyConfig()` - 处理旧配置版本的自动迁移。
|
||
|
||
---
|
||
|
||
### 4.5 钩子系统
|
||
|
||
#### 4.5.1 钩子类型
|
||
|
||
```typescript
|
||
// src/hooks/types.ts
|
||
export type HookEntry = {
|
||
name: string;
|
||
handler: HookHandler;
|
||
priority?: number;
|
||
};
|
||
|
||
export type HookEvent =
|
||
| "before_agent_start"
|
||
| "after_agent_start"
|
||
| "before_message_send"
|
||
| "after_message_send"
|
||
| "message_received"
|
||
| "tool_called"
|
||
| "config_changed"
|
||
// ... 更多钩子
|
||
};
|
||
```
|
||
|
||
#### 4.5.2 钩子注册方式
|
||
|
||
- 插件通过 `api.registerHook()` 注册
|
||
- 优先级按 `priority` 数值排序
|
||
|
||
---
|
||
|
||
## 5. 插件扩展机制
|
||
|
||
### 5.1 插件类型
|
||
|
||
| 类型 | 说明 | 示例 |
|
||
| ---------- | ----------------- | ---------------------- |
|
||
| `memory` | 内存/向量存储插件 | LanceDB |
|
||
| `channel` | 通道插件 | Matrix, Zalo |
|
||
| `provider` | 模型提供者插件 | 自定义 OpenAI 兼容 API |
|
||
|
||
### 5.2 插件 API
|
||
|
||
```typescript
|
||
// src/plugins/types.ts
|
||
export type OpenClawPluginDefinition = {
|
||
id?: string;
|
||
name?: string;
|
||
description?: string;
|
||
version?: string;
|
||
kind?: PluginKind; // "channel" | "memory" | "provider" | ...
|
||
configSchema?: OpenClawPluginConfigSchema;
|
||
register?: (api: OpenClawPluginApi) => void | Promise<void>;
|
||
activate?: (api: OpenClawPluginApi) => void | Promise<void>;
|
||
};
|
||
```
|
||
|
||
### 5.3 通道插件
|
||
|
||
参见 [3.3.1 节](#331-通道插件化)。
|
||
|
||
### 5.4 插件运行时
|
||
|
||
插件通过 `OpenClawPluginApi.runtime` 访问运行时 API,参见 [4.1.2 节](#412-插件运行时依赖)。
|
||
|
||
---
|
||
|
||
## 6. 路由与会话管理
|
||
|
||
### 6.1 路由解析
|
||
|
||
详见 [4.3.1 节](#431-路由解析)。
|
||
|
||
### 6.2 会话结构
|
||
|
||
```
|
||
~/.openclaw/sessions/
|
||
└── {channel}/
|
||
└── {accountId}/
|
||
└── {session}.jsonl (JSONL 格式)
|
||
```
|
||
|
||
每行包含:
|
||
|
||
- `role`: "user" | "assistant"
|
||
- `content`: 消息内容
|
||
- `timestamp`: 时间戳
|
||
- `meta`: 元数据
|
||
|
||
### 6.3 会话 API
|
||
|
||
```typescript
|
||
loadSessionStore(sessionPath): Promise<Session>
|
||
saveSessionStore(sessionPath, session): Promise<void>
|
||
updateLastRoute(channel, accountId, route): Promise<void>
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 模块间关系
|
||
|
||
### 7.1 CLI 层
|
||
|
||
```
|
||
openclaw.mjs
|
||
└─> src/index.ts
|
||
├─> createDefaultDeps()
|
||
├─> buildProgram()
|
||
│ ├─> createProgramContext()
|
||
│ └─> registerProgramCommands()
|
||
│ ├─> registerSetupCommand()
|
||
│ ├─> registerOnboardCommand()
|
||
│ ├─> registerConfigCli()
|
||
│ ├─> registerAgentCommands()
|
||
│ ├─> registerSubCliCommands()
|
||
│ └─> ...
|
||
└─> 程序解析 → 各命令处理器
|
||
```
|
||
|
||
### 7.2 Gateway 层
|
||
|
||
```
|
||
startGatewayServer()
|
||
├─> 配置加载 (loadConfig)
|
||
├─> 插件加载 (loadGatewayPlugins)
|
||
│ ├─> 插件注册表
|
||
│ └─> 通道插件 (listChannelPlugins)
|
||
├─> 运行时状态 (createGatewayRuntimeState)
|
||
│ ├─> HTTP 服务器
|
||
│ ├─> WebSocket 服务器
|
||
│ ├─> Canvas Host (a2ui)
|
||
│ └─> 协议验证 (AJV)
|
||
├─> 方法处理器
|
||
├─> 事件广播
|
||
├─> 通道管理器
|
||
├─> Cron 服务
|
||
├─> 节点注册
|
||
└─> 配置重载
|
||
```
|
||
|
||
### 7.3 消息流转
|
||
|
||
```
|
||
入站:
|
||
平台消息 → 通道适配器 → Gateway 事件 → 路由解析 → Agent 执行 → 出站
|
||
|
||
出站:
|
||
CLI/Web/App → Gateway 方法 → 根据路由分发 → 通道适配器 → 平台
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 通信协议
|
||
|
||
### 8.1 Gateway Protocol
|
||
|
||
详见 `docs/concepts/architecture.md` 和 `docs/gateway/protocol.md`。
|
||
|
||
核心帧类型:
|
||
|
||
```typescript
|
||
export type GatewayFrame =
|
||
| RequestFrame // {type:"req", id, method, params}
|
||
| ResponseFrame // {type:"res", id, ok, payload|error}
|
||
| EventFrame; // {type:"event", event, payload, seq?, stateVersion?}
|
||
```
|
||
|
||
#### 事件类型
|
||
|
||
- `agent` - Agent 执行事件
|
||
- `chat` - 聊天更新
|
||
- `presence` - 在线状态
|
||
- `health` - 健康状态
|
||
- `heartbeat` - 心跳
|
||
- `cron` - Cron 任务
|
||
- `tick` - 定时脉冲
|
||
|
||
#### 常用 Gateway 方法
|
||
|
||
| 方法 | 功能 |
|
||
| ----------------- | ------------ |
|
||
| `health` | 健康检查 |
|
||
| `status` | 状态查询 |
|
||
| `send` | 发送消息 |
|
||
| `agent` | 启动 Agent |
|
||
| `channels.list` | 列出通道账户 |
|
||
| `channels.status` | 通道状态 |
|
||
| `channels.login` | 通道登录 |
|
||
|
||
### 8.2 ACP (Agent Client Protocol)
|
||
|
||
位于 `src/acp/`,用于 Agent 与客户端的通信。
|
||
|
||
---
|
||
|
||
## 9. 认证与安全
|
||
|
||
### 9.1 设备配对
|
||
|
||
新建设备 ID 需要配对批准:
|
||
|
||
- 本地连接:自动批准
|
||
- 远程连接:需要显式批准
|
||
- 挑战签名:防止劫持
|
||
|
||
设备令牌存储在 `~/.openclaw/device-tokens.json`。
|
||
|
||
### 9.2 Gateway 认证
|
||
|
||
```typescript
|
||
// src/config/auth.ts
|
||
export type GatewayAuth = {
|
||
token?: string; // Bearer Token 检查
|
||
allowed?: string[]; // 允许的设备 ID
|
||
};
|
||
```
|
||
|
||
### 9.3 SSRF 防护
|
||
|
||
`src/infra/net/ssrf.ts` - 防止服务器端请求伪造。
|
||
|
||
---
|
||
|
||
## 10. 测试策略
|
||
|
||
### 10.1 测试框架
|
||
|
||
- **框架**:Vitest
|
||
- **覆盖率**:V8
|
||
- **阈值**:70% (线/分/函数/语句)
|
||
|
||
### 10.2 测试类型
|
||
|
||
| 类型 | 后缀 | 说明 |
|
||
| -------- | --------------- | ------------ |
|
||
| 单元测试 | `*.test.ts` | 功能单元测试 |
|
||
| E2E 测试 | `*.e2e.test.ts` | 端到端测试 |
|
||
|
||
### 10.3 测试命令
|
||
|
||
```bash
|
||
pnpm test # 运行所有测试
|
||
pnpm test:coverage # 运行测试并生成覆盖率报告
|
||
pnpm test:live # 运行 Live 测试 (需要真实凭证)
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 构建与部署
|
||
|
||
### 11.1 构建命令
|
||
|
||
```bash
|
||
pnpm build # 完整构建
|
||
pnpm tsgo # TypeScript 类型检查
|
||
pnpm check # Lint + Format
|
||
```
|
||
|
||
### 11.2 macOS 应用打包
|
||
|
||
```bash
|
||
scripts/package-mac-app.sh
|
||
```
|
||
|
||
### 11.3 发布流程
|
||
|
||
详解见 `docs/platforms/mac/release.md` 和 `docs/reference/RELEASING.md`。
|
||
|
||
发布通道:
|
||
|
||
- **stable**: 版本标签 (v2026.2.4) + npm tag `latest`
|
||
- **beta**: 预发布标签 (v2026.2.4-beta.N) + npm tag `beta`
|
||
- **dev**: main 分支头部 (无标签)
|
||
|
||
---
|
||
|
||
## 12. 编码规范
|
||
|
||
### 12.1 语言与风格
|
||
|
||
- **语言**:TypeScript (ESM)
|
||
- **严格类型**:避免 `any`
|
||
- **格式化**:Oxlint + Oxfmt
|
||
- **文件大小**:目标 < ~700 LOC
|
||
|
||
### 12.2 命名规范
|
||
|
||
- **产品/文档标题**:OpenClaw (大写)
|
||
- **CLI 命令**:openclaw (小写)
|
||
- **包/二进制名**:openclaw (小写)
|
||
- **配置键**:openclaw (小写)
|
||
|
||
### 12.3 代码注释
|
||
|
||
为复杂或非显而易见的逻辑添加简短注释。
|
||
|
||
### 12.4 终端输出
|
||
|
||
- **进度条**:`src/cli/progress.ts` (osc-progress + @clack/prompts)
|
||
- **表格**:`src/terminal/table.ts` (ANSI 安全换行)
|
||
|
||
### 12.5 多 Agent 安全
|
||
|
||
- 不创建/应用/删除 git stash 除非明确要求
|
||
- 不删除/修改 git worktree 除非明确要求
|
||
- 尊重其他 Agent 的工作
|
||
|
||
---
|
||
|
||
## 13. 附录:代码示例
|
||
|
||
### 13.1 注册插件钩子
|
||
|
||
```typescript
|
||
export default function register(api: OpenClawPluginApi) {
|
||
api.on("before_agent_start", async (event, ctx) => {
|
||
console.log("Agent starting:", ctx.agentId);
|
||
return {
|
||
systemPrompt: "Custom system prompt...",
|
||
prependContext: "Extended context...\n",
|
||
};
|
||
});
|
||
|
||
api.on("message_received", async (event, ctx) => {
|
||
console.log("Received:", event.content);
|
||
});
|
||
}
|
||
```
|
||
|
||
### 13.2 注册自定义命令
|
||
|
||
```typescript
|
||
api.registerCommand({
|
||
name: "tts",
|
||
description: "Text to speech",
|
||
acceptsArgs: true,
|
||
requireAuth: true,
|
||
handler: async (ctx) => {
|
||
const text = ctx.args || "";
|
||
// ... 处理 tts 并回复
|
||
return { text: `Speaking: ${text}` };
|
||
},
|
||
});
|
||
```
|
||
|
||
### 13.3 注册通道
|
||
|
||
```typescript
|
||
api.registerChannel({
|
||
id: "mychannel" as ChannelId,
|
||
meta: {
|
||
id: "mychannel" as ChannelId,
|
||
label: "My Channel",
|
||
selectionLabel: "My Channel",
|
||
docsPath: "/channels/mychannel",
|
||
blurb: "My custom channel implementation",
|
||
},
|
||
capabilities: {
|
||
chatTypes: ["dm", "group"],
|
||
media: true,
|
||
reactions: true,
|
||
reply: true,
|
||
},
|
||
config: {
|
||
listAccountIds: (cfg) => Object.keys(cfg.mychannel?.accounts ?? {}),
|
||
resolveAccount: (cfg, accountId) => cfg.mychannel?.accounts?.[accountId] ?? {},
|
||
defaultAccountId: (cfg) => "default",
|
||
},
|
||
outbound: {
|
||
deliveryMode: "gateway",
|
||
sendText: async (ctx) => {
|
||
// 发送文本到平台
|
||
return { ok: true };
|
||
},
|
||
},
|
||
gatewayMethods: ["mychannel.send"],
|
||
gateway: {
|
||
startAccount: async (ctx) => {
|
||
// 启动通道监听器
|
||
},
|
||
stopAccount: async (ctx) => {
|
||
// 停止通道监听器
|
||
},
|
||
},
|
||
});
|
||
```
|
||
|
||
### 13.4 使用插件 SDK
|
||
|
||
```typescript
|
||
import {
|
||
registerTool,
|
||
resolveAgentRoute,
|
||
loadConfig,
|
||
dispatchReplyWithBufferedBlockDispatcher,
|
||
} from 'openclaw/plugin-sdk';
|
||
|
||
export default function register(api: OpenClawPluginApi) {
|
||
const tool = {
|
||
type: 'function',
|
||
name: 'mytool',
|
||
description: 'My custom tool',
|
||
parameters: {
|
||
type: 'object',
|
||
properties: {},
|
||
additionalProperties: false,
|
||
},
|
||
handler: async ({ accountId, messageChannel, agentId, ... }) => {
|
||
// 处理工具
|
||
return {
|
||
success: true,
|
||
content: [],
|
||
data: undefined,
|
||
};
|
||
},
|
||
};
|
||
api.registerTool(tool);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 参考资料
|
||
|
||
- [Gateway Architecture](/docs/concepts/architecture.md)
|
||
- [Gateway Protocol](/docs/gateway/protocol.md)
|
||
- [提交 PR 指南](/docs/help/submitting-a-pr.md)
|
||
- [提交 Issue 指南](/docs/help/submitting-an-issue.md)
|
||
- [测试文档](/docs/testing.md)
|
||
- [发布文档](/docs/reference/RELEASING.md)
|
||
- [macOS 发布](/docs/platforms/mac/release.md)
|
||
|
||
---
|
||
|
||
**文档结束**
|