22.2 插件钩子(Plugin Hooks)

生成模型:Claude Opus 4.6 (anthropic/claude-opus-4-6) Token 消耗:输入 ~140k tokens,输出 ~8k tokens(本节)


上一节介绍的内部钩子(Internal Hooks)运行在 Gateway 进程内部,通过事件键注册和触发。本节聚焦 OpenClaw 的另一套钩子体系——插件钩子(Plugin Hooks),它由插件系统驱动,提供了更结构化的生命周期拦截能力,以及将外部 HTTP 请求映射为 Agent 动作的网关钩子映射机制。


22.2.1 钩子映射(src/gateway/hooks-mapping.ts

设计场景

想象这样一个场景:你希望 Gmail 收到新邮件时,自动通知 OpenClaw 的 Agent 进行处理。传统做法需要编写一个中间服务来桥接 Gmail Webhook 和 Agent API。OpenClaw 的**钩子映射(Hook Mapping)**机制直接内置了这个桥接能力——它接收外部 HTTP 请求,按规则匹配后转换为 Agent 可理解的动作。

整体架构

外部系统(Gmail/GitHub/自定义服务)

        ▼ HTTP POST /hooks/gmail
┌─────────────────────────────┐
│   Gateway HTTP 端点          │
│   ① Token 鉴权               │
│   ② 路径/来源匹配            │
│   ③ 模板渲染                 │
│   ④ Transform 转换(可选)   │
│   ⑤ 生成 HookAction          │
└─────────────────────────────┘


   wake(唤醒心跳)或 agent(发送消息给 Agent)

钩子端点配置

Gateway 钩子端点通过配置启用,必须设置鉴权 Token:

Token 从请求中提取,支持两种方式:

方式
HTTP 头
示例

Bearer Token

Authorization: Bearer <token>

标准 OAuth 风格

自定义头

X-OpenClaw-Token: <token>

简化集成

映射规则与预设

映射规则定义了"什么请求触发什么动作"。每条规则包含匹配条件和动作模板:

OpenClaw 内置了 Gmail 预设映射:

用户也可以在配置中定义自定义映射规则:

匹配与渲染

当 HTTP 请求到达钩子端点时,applyHookMappings 按顺序尝试匹配:

模板引擎

消息模板使用类 Mustache 的 {{expr}} 语法,支持以下表达式:

getByPath 支持点号和方括号语法(如 messages[0].from),可以深度访问嵌套的 JSON 数据。

动作类型

匹配成功后生成两种动作之一:

动作
用途
效果

wake

唤醒 Agent 心跳

发送一段文本触发 Agent 心跳处理

agent

发送消息给 Agent

创建一个新的 Agent 消息,包含 sessionKey、通道、模型等参数

agent 动作是最常用的——它等价于从某个通道发送一条消息给 Agent,但消息内容由外部系统的 Webhook 数据填充。

Transform 自定义转换

对于复杂的数据转换需求,模板语法可能不够用。OpenClaw 支持加载自定义 Transform 模块来完全控制映射逻辑:

Transform 函数接收完整的请求上下文,返回部分动作字段(与基础模板渲染结果合并),或返回 null 跳过此请求。Transform 模块带有缓存——同一模块路径只会被 import() 一次。


22.2.2 Agent 生命周期钩子:before_agent_start / agent_end

从这一小节开始,我们进入**插件钩子系统(Plugin Hook System)**的领域。与内部钩子的发布/订阅模式不同,插件钩子通过插件注册表(Plugin Registry)管理,由 createHookRunner 创建的运行器统一调度。

插件钩子总览

OpenClaw 定义了 14 种插件钩子,覆盖五个生命周期域:

执行模型:Void vs Modifying

插件钩子有两种执行模式,对应不同的使用场景:

模式
执行方式
返回值
适用场景

Void

Promise.all(并行)

观察型钩子(日志、统计)

Modifying

顺序串行

可返回修改结果

拦截型钩子(修改、阻止)

衍生解释:这种双模式设计在中间件架构中很常见。Express.js 的中间件是纯顺序的(每个 next() 调用下一个);Koa 的洋葱模型也是顺序的。OpenClaw 增加了并行模式——对于不需要互相影响的观察型钩子,并行执行能显著提高性能。

before_agent_start

before_agent_start 在 Agent 开始处理请求前触发,允许插件注入额外的系统提示词或上下文:

这是一个 Modifying Hook——多个插件的结果会被合并:

合并策略是:systemPrompt 后者覆盖前者(最后一个插件说了算),prependContext 则追加拼接(所有插件的前置上下文都保留)。

agent_end

agent_end 在 Agent 完成处理后触发,是一个 Void Hook(并行执行、无返回值):

典型用途包括:对话质量分析、使用量统计上报、异常监控告警等。


22.2.3 工具生命周期钩子:before_tool_call / after_tool_call / tool_result_persist

工具钩子是插件钩子中最精细的一组,覆盖了工具调用的完整生命周期。

before_tool_call

在 Agent 发起工具调用之前触发。这是一个 Modifying Hook,插件可以修改参数甚至阻止调用:

合并策略:

这意味着任何一个插件返回 block: true,工具调用就会被阻止——这是安全策略的关键拦截点。例如,一个安全插件可以检查 bash 工具的参数,阻止执行危险命令:

after_tool_call

在工具调用完成后触发,是一个 Void Hook(并行、观察型):

典型用途:工具使用统计、性能监控、错误追踪。

tool_result_persist(同步钩子)

tool_result_persist 是整个钩子系统中唯一的同步钩子——它在工具结果写入会话记录时触发,必须同步返回:

设计为同步的原因是:此钩子运行在会话记录追加的热路径上——会话 JSONL 文件的写入是同步操作,如果这里引入异步等待,会破坏写入的原子性和顺序性。

这个钩子采用管道模式——每个处理器接收上一个处理器的输出作为输入,最终结果是链式传递的最后一版消息。典型用途:在持久化前过滤敏感信息、压缩大型工具输出、添加元数据标注。

衍生解释:管道模式(Pipeline Pattern)是一种数据处理模式,数据依次通过一系列处理阶段,每个阶段接收前一阶段的输出并产生新的输出。Unix 的管道操作符 | 是最经典的例子:cat file | grep error | sort。这里的 tool_result_persist 钩子链就是一个同步的内存管道。


22.2.4 消息钩子:message_received / message_sending / message_sent

消息钩子拦截用户与 Agent 之间的消息流,覆盖消息的"进-处理-出"三个阶段:

message_received

用户消息到达时触发,是一个 Void Hook

用途:消息接收统计、内容审计日志、用户行为分析。

message_sending

Agent 回复即将发送前触发,是一个 Modifying Hook——插件可以修改内容甚至取消发送:

合并策略:

这个钩子给了插件极大的控制权:

  • 内容过滤:在发送前替换敏感信息或不恰当内容

  • 格式转换:将 Markdown 转为特定通道支持的格式

  • 发送拦截:满足特定条件时阻止消息发出

message_sent

消息实际发送后触发,是一个 Void Hook

用途:发送成功率监控、失败重试触发、消息归档。


22.2.5 网关钩子:gateway_start / gateway_stop

网关钩子在 Gateway 服务器的启动和停止时触发,是最外层的生命周期钩子。

gateway_start

Gateway HTTP 服务器启动后触发,是一个 Void Hook

用途:初始化外部连接(数据库、消息队列)、注册服务发现、发送启动通知。

gateway_stop

Gateway 即将关闭时触发:

用途:清理资源、断开外部连接、发送关闭通知、刷新缓冲区。

钩子运行器工厂

所有插件钩子通过 createHookRunner 统一创建运行器:

运行器的关键设计决策:

  1. 默认容错catchErrors 默认为 true,一个插件的钩子失败不会影响其他插件和核心流程。

  2. 优先级排序:处理器按 priority 降序排列——高优先级先执行。对于 Modifying Hook,这意味着高优先级的插件可以先设定默认值,低优先级的可以覆盖。

  3. 按需检查hasHooks 让调用方可以在不调用运行器的情况下判断是否有注册钩子,避免不必要的事件对象构建开销。

插件钩子注册

插件通过 OpenClawPluginApi.on() 方法注册钩子处理器:

每个注册会创建一个 PluginHookRegistration 记录,存储在插件注册表中:

两套钩子系统的对比

至此,我们已经完整介绍了 OpenClaw 的两套钩子系统。以下是它们的关键差异:

维度
内部钩子(Internal Hooks)
插件钩子(Plugin Hooks)

来源

HOOK.md + handler.ts 文件

插件代码中 api.on() 注册

管理方式

目录发现 + 配置控制

插件注册表

事件命名

type:action 字符串键

枚举类型 PluginHookName

执行模式

全部顺序串行

Void(并行)/ Modifying(顺序)

返回值

无(通过 event.messages 回推)

Modifying Hook 可返回修改结果

典型用途

文件系统级扩展(自定义钩子目录)

编程级扩展(插件代码)

安装方式

openclaw hooks install

插件系统自动加载

错误处理

try/catch 隔离

可配置(默认捕获)

两套系统互不冲突,可以同时使用。内部钩子更适合"运维级"的轻量扩展(如审计日志、会话保存),插件钩子更适合"开发级"的深度集成(如安全拦截、内容转换、外部系统联动)。


本节小结

  1. 钩子映射是 Gateway 内置的 HTTP→Agent 桥接机制,通过路径/来源匹配和模板渲染将外部 Webhook 请求转换为 Agent 动作,支持预设(Gmail)和自定义映射规则,以及 Transform 模块进行复杂转换。

  2. 插件钩子系统定义了 14 种钩子,覆盖 Agent、消息、工具、会话、网关五个生命周期域,由 createHookRunner 工厂统一调度。

  3. Agent 钩子中,before_agent_start 允许注入系统提示词(顺序合并),agent_end 用于完成后的观察分析(并行执行)。

  4. 工具钩子提供了最精细的控制——before_tool_call 可以修改参数或阻止调用,tool_result_persist 是唯一的同步管道钩子,在会话记录的热路径上运行。

  5. 消息钩子拦截消息的进-出流程,其中 message_sending 是唯一可以修改或取消消息的拦截点。

  6. 两套钩子系统(内部 + 插件)互补共存——内部钩子面向文件系统级扩展,插件钩子面向编程级深度集成,共同构成了 OpenClaw 完整的可扩展性基础。

Last updated