4.3 核心方法与事件

生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~200,000 tokens,输出 ~15,000 tokens(本章合计)


在前两节中,我们理解了协议的设计哲学和类型系统。现在让我们具体看看:客户端通过这套协议能做什么?服务器会推送什么事件?本节将逐一分析 Gateway 提供的核心方法和事件。

4.3.1 请求方法一览

Gateway 支持的所有请求方法定义在 src/gateway/server-methods-list.ts 中:

// src/gateway/server-methods-list.ts
const BASE_METHODS = [
  // ─── 系统与运维 ───
  "health",              // 健康检查
  "status",              // 系统状态
  "logs.tail",           // 实时日志

  // ─── 通道管理 ───
  "channels.status",     // 通道连接状态
  "channels.logout",     // 登出通道

  // ─── 配置操作 ───
  "config.get",          // 获取配置
  "config.set",          // 设置配置
  "config.apply",        // 应用配置变更
  "config.patch",        // 部分更新配置
  "config.schema",       // 获取配置 Schema

  // ─── 执行审批 ───
  "exec.approvals.get",  // 获取审批策略
  "exec.approvals.set",  // 设置审批策略
  "exec.approval.request",  // 请求审批
  "exec.approval.resolve",  // 批准/拒绝

  // ─── 引导向导 ───
  "wizard.start",        // 启动引导向导
  "wizard.next",         // 下一步
  "wizard.cancel",       // 取消向导
  "wizard.status",       // 向导状态

  // ─── AI 对话 ───
  "agent",               // 发起 Agent 对话
  "agent.identity.get",  // 获取 Agent 身份信息
  "agent.wait",          // 等待 Agent 运行完成
  "send",                // 发送消息到通道
  "wake",                // 唤醒 Agent

  // ─── 模型与技能 ───
  "models.list",         // 列出可用模型
  "agents.list",         // 列出 Agent 配置
  "agents.files.list",   // 列出 Agent 文件
  "agents.files.get",    // 读取 Agent 文件
  "agents.files.set",    // 写入 Agent 文件
  "skills.status",       // 技能状态
  "skills.bins",         // 技能二进制
  "skills.install",      // 安装技能
  "skills.update",       // 更新技能

  // ─── 会话管理 ───
  "sessions.list",       // 列出会话
  "sessions.preview",    // 预览会话内容
  "sessions.patch",      // 修改会话属性
  "sessions.reset",      // 重置会话
  "sessions.delete",     // 删除会话
  "sessions.compact",    // 压缩会话

  // ─── 节点操作 ───
  "node.pair.request",   // 请求节点配对
  "node.pair.list",      // 列出配对请求
  "node.pair.approve",   // 批准配对
  "node.pair.reject",    // 拒绝配对
  "node.pair.verify",    // 验证配对
  "node.rename",         // 重命名节点
  "node.list",           // 列出节点
  "node.describe",       // 描述节点
  "node.invoke",         // 调用节点
  "node.invoke.result",  // 返回节点调用结果
  "node.event",          // 节点事件

  // ─── 设备管理 ───
  "device.pair.list",    // 列出设备配对请求
  "device.pair.approve", // 批准设备配对
  "device.pair.reject",  // 拒绝设备配对
  "device.token.rotate", // 轮换设备令牌
  "device.token.revoke", // 撤销设备令牌

  // ─── 定时任务 ───
  "cron.list",           // 列出定时任务
  "cron.status",         // 任务状态
  "cron.add",            // 添加任务
  "cron.update",         // 更新任务
  "cron.remove",         // 删除任务
  "cron.run",            // 手动运行任务
  "cron.runs",           // 运行历史

  // ─── 心跳与在线状态 ───
  "last-heartbeat",      // 最近一次心跳
  "set-heartbeats",      // 设置心跳
  "system-presence",     // 系统在线信息
  "system-event",        // 系统事件

  // ─── TTS(文字转语音) ───
  "tts.status",          // TTS 状态
  "tts.providers",       // TTS 供应商列表
  "tts.enable",          // 启用 TTS
  "tts.disable",         // 禁用 TTS
  "tts.convert",         // 文字转语音
  "tts.setProvider",     // 设置供应商

  // ─── WebChat 方法 ───
  "chat.history",        // 聊天历史
  "chat.send",           // 发送聊天消息
  "chat.abort",          // 中止聊天

  // ─── 其他 ───
  "usage.status",        // 使用量统计
  "usage.cost",          // 费用统计
  "update.run",          // 运行更新
  "talk.mode",           // 对话模式切换
  "voicewake.get",       // 语音唤醒设置
  "voicewake.set",       // 语音唤醒设置
  "browser.request",     // 浏览器操作请求
];

方法列表并不是静态的。listGatewayMethods() 函数会动态合并通道插件注册的额外方法:

衍生解释:这种插件扩展的设计模式在 Web 框架中非常常见。例如,Express.js 的中间件可以注册新的路由,Webpack 的插件可以注册新的生命周期钩子。OpenClaw 的通道插件也可以向 Gateway 注册新的方法——比如 Slack 扩展可能会注册 slack.interactivity 方法来处理 Slack 的交互式消息回调。

方法使用点号分隔命名空间(Dot-separated Namespace),这是一种清晰的组织方式:

命名空间
含义
示例

config.*

配置操作

config.get, config.set

sessions.*

会话管理

sessions.list, sessions.delete

node.*

节点操作

node.invoke, node.list

device.*

设备管理

device.pair.approve

cron.*

定时任务

cron.add, cron.remove

skills.*

技能管理

skills.install, skills.status

exec.*

执行审批

exec.approval.request

chat.*

WebChat

chat.send, chat.history

这种设计对于连接握手时的功能协商(Feature Negotiation)也很关键——HelloOk 响应中的 features.methods 数组告诉客户端当前 Gateway 支持哪些方法。

4.3.2 connect — 握手与认证

connect 是客户端与 Gateway 建立通信的第一步。严格来说,connect 不是一个标准的请求方法(它在 WebSocket 连接建立后立即由客户端发送,而非通过 req 帧调用),但它遵循类似的请求-响应模式。

连接请求(ConnectParams)

这个结构承载了大量信息。让我们分组解析:

协议版本协商minProtocolmaxProtocol 让客户端和服务器能协商使用一个双方都支持的协议版本。当前协议版本是 3。如果服务器不支持客户端要求的版本范围,连接会被拒绝。

客户端身份client 字段标识了"谁在连接"。这不仅用于日志记录,还影响 Gateway 的行为——例如,mode: "cli" 的客户端和 mode: "ui" 的客户端可能有不同的权限和功能。

能力声明caps(Capabilities)让客户端声明自己支持的额外能力。目前定义的能力包括:

连接响应(HelloOk)

连接成功后,Gateway 返回 HelloOk 消息:

几个关键点:

  1. features.methodsfeatures.events 告诉客户端当前 Gateway 支持哪些操作。这实现了运行时功能发现——客户端不需要硬编码一个方法列表,而是在连接时动态获取。

  2. snapshot 包含了连接时刻的系统状态(在线用户、健康状况等),客户端可以用它初始化 UI,而不需要再发额外的请求。

  3. policy 告知客户端连接的限制参数。maxPayload 防止客户端发送过大的消息,tickIntervalMs 告诉客户端心跳频率。

4.3.3 agent / agent.wait — 发起 AI 对话

agent 方法是 OpenClaw 最核心的操作——它让客户端发起一次 AI 对话。

agent 方法参数

这是整个协议中最复杂的参数结构之一。字段多的原因是 agent 方法需要同时处理来自多种通道的消息——CLI 发来的消息可能只需要 messageidempotencyKey,而来自 Slack 群组的消息还需要 threadIdgroupIdchannel 等路由信息。

agent.wait — 等待运行完成

agent 方法是异步的——它立即返回一个 runId,实际的 Agent 运行在后台进行,结果通过事件推送。但有些场景需要同步等待结果,比如 CLI 执行 openclaw ask "什么是 OpenClaw?"

agent.wait 方法满足这个需求:

调用流程:

4.3.4 send — 发送消息到通道

send 方法允许 Agent 或客户端向特定的通道发送消息:

sendagent 的区别在于:agent 是"请 AI 处理这条消息",而 send 是"直接发送这条消息到目标通道"。send 通常由 Agent 在工具调用中使用(比如 Agent 决定向某个 Slack 频道发送一条通知)。

PollParamsSchemasend 的变体,用于发送投票:

投票选项限制在 2–12 个之间,最大可选择数量限制为 12——这些都是通过 TypeBox Schema 的约束直接表达的。

4.3.5 sessions.* — 会话管理方法族

会话是 OpenClaw 中 AI 对话的上下文容器。sessions.* 方法族提供了会话的完整 CRUD 操作:

方法
功能
参数特点

sessions.list

列出会话

支持过滤:limitactiveMinuteslabelagentIdsearch

sessions.preview

预览会话内容

支持多会话批量预览,可限制字符数

sessions.resolve

解析会话

通过 keysessionIdlabel 等多种方式定位会话

sessions.patch

修改会话属性

可修改 labelmodelthinkingLevelexecSecurity

sessions.reset

重置会话

清空对话历史,保留会话键

sessions.delete

删除会话

可选是否同时删除转录文件

sessions.compact

压缩会话

调用 LLM 总结旧消息,减少上下文长度

sessions.patch 的参数特别丰富,反映了会话的可配置性:

注意一个设计模式:几乎所有字段都是 Type.Union([SomeType, Type.Null()])——传值时设置,传 null 时重置为默认值,不传时保持不变。这是一种优雅的三态更新(Three-State Update)模式。

4.3.6 事件类型

除了请求方法,Gateway 还会主动推送事件。所有事件类型定义在 GATEWAY_EVENTS 数组中:

agent 事件

agent 事件是最核心的事件类型,它承载了 Agent 运行过程中的所有流式输出:

stream 字段区分了不同类型的事件数据:

  • "text" — 模型生成的文本块

  • "tool-call" — 模型决定调用某个工具

  • "tool-result" — 工具执行结果

  • "thinking" — 模型的思考过程

  • "error" — 运行时错误

seq 序列号保证即使事件到达顺序被打乱(在网络层面极少发生,但在多路复用场景中理论上可能),客户端也能正确重排。

tick 事件

tick 是一个简单的心跳事件:

Gateway 按 policy.tickIntervalMs 指定的间隔发送 tick 事件。客户端据此:

  1. 确认连接仍然活跃

  2. 同步与服务器的时钟差

shutdown 事件

当 Gateway 准备关闭时,会发送 shutdown 事件给所有连接的客户端:

restartExpectedMs 是一个贴心的设计——如果 Gateway 因为升级而重启,客户端知道大约多久后可以尝试重连,而不需要盲目重试。

状态版本与增量同步

事件帧可以携带一个 stateVersion 字段:

衍生解释:状态版本(State Version)是一种乐观并发控制(Optimistic Concurrency Control)技术。每当某个状态发生变化时,版本号递增。客户端记住当前的版本号,如果收到的事件的版本号大于自己记录的版本号,就知道状态发生了变化需要更新。这比每次都获取完整状态要高效得多。

类似的设计在数据库中也很常见——例如 PostgreSQL 的 MVCC(多版本并发控制)和 etcd 的 revision 机制。


本节小结

Gateway 的方法和事件设计体现了几个原则:

  1. 功能分族:通过点号命名空间将 80+ 个方法组织为清晰的功能组

  2. 异步优先agent 方法是异步的,结果通过事件流推送;agent.wait 提供同步等待的选择

  3. 丰富的元数据connect 握手时交换大量信息(版本、能力、状态快照),减少后续的往返通信

  4. 三态更新模式sessions.patch 等方法使用"传值设置、传 null 重置、不传保持"的模式

  5. 事件驱动:18 种事件类型覆盖了系统状态变更的方方面面,客户端可以根据需要订阅感兴趣的事件

在下一节中,我们将深入 Gateway 的认证机制——Token 认证、设备配对和 Origin 检查是如何保护 WebSocket 连接安全的。

Last updated