跳转至

Hook 参考

注册规则、执行约定、每个处理程序的预算,以及完整的类型化钩子目录。属于 Plugin hooks 指南的一部分。

注册与执行

保持 register(api) 同步,并在其中注册处理程序。处理程序本身可以是异步的,但两个同步持久化钩子除外。

处理程序默认优先级为 0;优先级越高越先运行,注册顺序用于打破平局。执行方式取决于钩子类型:

类型 执行约定
Modify(修改) 顺序执行;结果按下方该钩子的约定合并。返回重写通常不会改变传递给后续处理程序的事件。
Claim(认领) 顺序执行;第一个 { handled: true } 获胜,并跳过其余处理程序。
Gate(门控) 顺序执行;阻止(block)会停止其余处理程序。
Observe(观察) 处理程序并发运行;返回值被忽略。发射器可等待完成,也可发出发射后不理(fire-and-forget)的调度。
Sync modify/gate(同步修改/门控) 按优先级顺序同步执行;每个处理程序都看到最新消息。Promise 会被忽略并发出警告。
Evaluate(评估) 技能评估器并发运行,产生各自独立归属的结果。

优先级不会序列化观察副作用。发射后不理事件可能与后续事件重叠,回调也不是持久化事件队列。请显式返回修改结果,而不要依赖就地变更。

api.on(name, handler, opts?) 接受以下选项:

选项 作用
matcher 非空列表,包含 before_tool_call 或 after_tool_call 所处理的规范 OpenClaw 工具 ID,例如 exec、apply_patch 或 spawn_agent。省略则匹配所有工具。空列表、通配符、空白以及特定提供商的别名均无效。
priority 排序;值越高越先运行。
registrationId 插件内某次注册的稳定身份标识。技能评估器将其用作 evaluatorId;否则使用插件 ID。
timeoutMs 每个处理程序的异步等待预算。超时后应用下方该钩子的失败策略;不会取消处理程序或其副作用。省略则使用运行器的默认值(如有)。
eligibleTriggers 仅用于 before_agent_reply,将宿主分发限制为 cron、heartbeat 或 user 中的一个或多个。
eligibleDispatchKinds 仅用于 reply_dispatch,将宿主分发限制为 agent、acp 或两者。省略则处理所有分发类型。
requiresToolAuthority 仅用于 before_prompt_build,在宿主确定当前轮次的工具面并提供临时 ctx.toolAuthority 后运行处理程序。适用于必须遵循工具策略的上下文检索。

触发资格由宿主在处理程序被调用前强制执行。因此,使用 eligibleTriggers: ["heartbeat", "cron"] 注册的钩子在用户轮次(包括恢复的用户轮次)中处于非活动状态。省略、为空、格式错误或部分未知的列表保持不受限制,因此该钩子会在这些轮次中运行。其他钩子类型不接受此选项。

操作员无需修改插件代码即可设置钩子预算:

{
  "plugins": {
    "entries": {
      "my-plugin": {
        "hooks": {
          "timeoutMs": 30000,
          "timeouts": {
            "before_prompt_build": 90000,
            "agent_end": 60000
          }
        }
      }
    }
  }
}

hooks.timeouts.<hookName> 会覆盖 hooks.timeoutMs,而后者又会覆盖插件作者在 api.on(..., { timeoutMs }) 中设置的值。这两个操作员配置字段接受不超过 600000 毫秒的正整数。对于已知较慢的钩子,建议优先使用按钩子覆盖,这样单个插件不会在所有地方都获得更长的预算。

超时的处理程序 promise 会继续运行,因为钩子回调不会收到由超时持有的取消信号。before_tool_call 可能会收到所属工具调用的 ctx.abortSignal,但钩子超时到期并不会中止它。当插件工作仍在进行时,钩子分发可以释放其 Gateway 准入。拥有长时间运行工作的插件必须提供自己的取消和关闭生命周期。

构建提示词(prompt)的处理器可以使用 ctx.hookInvocation.assertActive() 在其结果不再适用后拒绝副作用。参见 处理器生命周期。

标准运行器为每个处理器应用以下默认值:

钩子 默认超时 抛出错误或超时时
before_agent_run, before_tool_call, before_install 15 秒 失败即关闭:阻止运行、工具调用或安装
before_agent_finalize, before_prompt_build, message_sending, reply_payload_sending, resolve_exec_env 15 秒 记录日志并跳过失败的处理器;保留其他成功结果
agent_end, before_compaction, after_compaction, skill_changed, skill_proposal_changed 30 秒 记录日志并继续
channel_pairing_requested 2 秒 记录日志并继续
gateway_stop 5 秒 记录日志并继续关闭
skill_proposal_evaluate 120 秒 记录归因的错误结果
其他异步钩子,包括认领钩子 除非配置,否则无运行器超时 记录日志并继续
tool_result_persist, before_message_write 无异步超时 同步错误会被记录;失败结果会被忽略

发射器(emitter)可以施加更严格的整体生命周期预算,例如下面关闭时的 session_end 排空。超时仅约束异步等待(await);它无法中断同步 JavaScript。对于策略要求,请使用失败即关闭的门控,而不要假设观察或投递钩子会在失败时拒绝该操作。

对于认领钩子,继续意味着尝试下一个处理器。调用方决定若无人认领时会发生什么;对于已绑定的对话,失败的 inbound_claim 可能会生成绑定通知,而不是普通的代理回复。

使用 createReplyDispatcher 的渠道插件同样可以通过 beforeDeliverOptions: { timeoutMs } 声明更大的正数阶段预算,或在追加工作时使用 dispatcher.appendBeforeDeliver(handler, { timeoutMs })。若没有所有者声明的预算,这些回调使用相同的 15 秒默认值,这样挂起的回调就不会占用串行化的投递通道。

钩子目录

钩子按其所扩展的层面分组。种类(Kinds)指上述执行契约;修改型钩子不是观察型钩子。

代理回合

钩子 种类 用途
before_model_resolve 修改 在会话消息加载前覆盖 provider 或 model
agent_turn_prepare 修改 检查已排空的插件回合注入,并在提示词钩子之前添加上下文
before_prompt_build 修改 添加提示词上下文,收窄当前回合提交的工具,或执行已授权的策略后增强
before_agent_run 门控 在模型提交前检查最终提示词和会话消息;可阻止运行
before_agent_reply 认领 使用合成回复或静默来短路模型回合
before_agent_finalize 修改 检查自然的最终答案,并请求再进行一次模型传递
agent_end 观察 观察最终消息、成功状态和运行时长
heartbeat_prompt_contribution 修改 为后台监控和生命周期插件添加仅限心跳的上下文

对话观察

钩子 种类 用途
model_call_started / model_call_ended 观察 脱敏后的 provider/model 调用元数据:时序、结果、有界 request-id 哈希。不含提示词或响应内容。
llm_input 观察 Provider 输入:系统提示词、提示词、历史
llm_output 观察 Provider 输出、用量,以及可用时解析出的 contextTokenBudget

工具

钩子 类型 用途
before_tool_call 修改 / 门控 重写工具参数、阻止执行或要求审批
after_tool_call 观察 观察工具结果、错误和耗时
resolve_exec_env 修改 向 exec 贡献插件拥有的环境变量
tool_result_persist 同步修改 在转录持久化之前重写 toolResult 消息
before_message_write 同步修改 / 门控 在转录持久化之前重写或阻止消息

消息与投递

钩子 类型 用途
inbound_claim 认领 为拥有其会话绑定的插件认领一条入站消息
channel_pairing_requested 观察 观察新创建的 DM 配对请求
message_received 观察 观察入站内容、发送者、线程和元数据
message_sending 修改 / 门控 重写出站内容或取消投递
reply_payload_sending 修改 / 门控 在投递前修改或取消规范化后的回复负载
message_sent 观察 观察出站投递成功或失败
before_dispatch 认领 在正常模型分发之前处理入站消息
reply_dispatch 认领 替代默认模型路径,自行负责回复生成与分发

inbound_claim 不是全局预路由广播。OpenClaw 仅对拥有消息的核心管理会话绑定的插件调用它。要在模型输入之前抑制普通 agent 轮次而不在转录中保留原始提示词,请在受支持的 runner 上使用 before_agent_run。要使用合成回复或静默来短路 agent 轮次,请使用 before_agent_reply。

会话与压缩

钩子 类型 用途
session_start / session_end 观察 跟踪会话生命周期边界
before_compaction / after_compaction 观察 观察压缩边界;没有重写或否决结果
before_reset 观察 观察会话重置事件(/reset、编程式重置)

成功的由引擎执行的压缩尝试即使没有历史更改也会发出 after_compaction,并带有 compactedCount: 0。失败或中止的尝试不会发出该完成钩子。

session_end.reason 是以下之一:new、reset、idle、daily、compaction、deleted、shutdown、restart 或 unknown。session_start 没有 reason 字段;它可以包含 resumedFrom。关闭/重启事件来自活动会话的 Gateway finalizer,因此插件可以在进程退出前关闭会话状态。

关闭和重启共享一个 2 秒的 session_end 排空总预算,作用于所有活动会话和插件处理器;该预算不是按处理器分配的。请快速返回,或保持终结过程有界且持久化具备崩溃一致性。如果预算超时,OpenClaw 会记录 shutdown session-end drain timed out 并继续关闭,因此未完成的插件工作可能被中断。

对于带有 parentSessionKey 和 emitCommandHooks: true 的 sessions.create 调用,独立的子会话始终会收到 session_start。调用方通过 succeedsParent 声明父会话是否也会收到终结性的 session_end:true 表示后继者,false 表示并行子会话。省略该字段则保留旧的父会话滚动行为。在这两种情况下,command:new 和 before_reset 钩子仍然描述请求的 /new 操作。

子代理

  • subagent_spawned / subagent_ended - 观察子代理的启动和完成。
  • subagent_progress - 观察后台子运行的便携式 started / ended 进度;包含 runId、childSessionKey、可选的请求者路由,以及 ended 时的结果。
  • subagent_delivery_target - 用于完成投递的修改性兼容钩子,当没有核心会话绑定可以投射路由时使用。第一个返回的 origin 生效。
  • 当 OpenClaw 在启动前已解析子会话的原生模型时,subagent_spawned 包含 resolvedModel 和 resolvedProvider。
  • subagent_ended 携带 targetSessionKey(标识——与 subagent_spawned.childSessionKey 匹配)、targetKind("subagent" 或 "acp")、reason、可选的 outcome("ok"、"error"、"timeout"、"killed"、"reset" 或 "deleted")、可选的 error、runId、endedAt、accountId 和 sendFarewell。它不包含 agentId 或 childSessionKey;请使用 targetSessionKey 与对应的 subagent_spawned 事件关联。

生命周期

钩子 类型 用途
gateway_start / gateway_stop 观察 随网关启动或停止插件自有服务
cron_reconciled 观察 启动或重新加载后,与完整网关定时任务状态进行协调
cron_changed 观察 观察网关自有定时任务的生命周期变化(添加、更新、移除、启动、完成、调度)
before_install 修改 / 门控 检查已加载插件运行时中暂存的技能或插件安装材料
skill_proposal_evaluate 评估 评估某个精确的技能工坊(Skill Workshop)草稿,并返回带归属的发现、指标或决策
skill_proposal_changed 观察 观察持久化技能工坊提案生命周期事件提交后的变化
skill_changed 观察 观察已提交的实时技能创建、更新和移除事件

技能生命周期与评估

将 skill_proposal_evaluate 用于静态分析器、安全扫描器、基准测试、基于模型的评分器或其他第三方评估器。OpenClaw 会传递一个不可变的候选包,其中包含文件哈希和树哈希。更新提案还会将完整的当前技能作为 baseline 包含在内。文本文件使用 UTF-8 内容;二进制文件使用 base64。

评估器注册并发运行。为每个评估器指定一个稳定的 registrationId:

api.on(
  "skill_proposal_evaluate",
  async (event) => {
    const score = await evaluateBundle(event.candidate, event.baseline);
    return {
      evaluatorVersion: "rules-2026-07",
      mode: "baseline-comparison",
      decision: score.regressed ? "revise" : "pass",
      summary: score.summary,
      metrics: score.metrics,
      findings: score.findings,
    };
  },
  { registrationId: "quality-regression", timeoutMs: 90_000 },
);

当评估输入包含 correlationId 时,OpenClaw 会将其转发给评估器事件,无论是手动触发的评估还是 apply 触发的评估均如此。该值是调用方提供的关联元数据,而非经过身份验证的身份或授权证明。授权插件必须通过受信任的入口点生成或替换该值,将其绑定到预期操作,并自行验证和消费该值。

存储的结果标识了评估器、插件 ID、插件包版本、状态和返回结果。超时和抛出的错误会被记录为带归属的错误结果;它们不会导致整个评估失败。在评估器的所有结果中,只有已完成的 decision: "block" 会否决 apply 操作。其他 Workshop 验证和所有权检查仍然生效。Apply 会在 Workshop 变更锁下重新验证被评估的目标树,因此任何实时技能资产的漂移都需要重新评估。完整持久化的评估信封上限为 512 KiB。

skill_proposal_changed 在对应的提案行和追加式生命周期事件提交后触发。它携带事件 ID、序列号、精确的提案修订哈希、可选的关联 ID 以及评估结果。skill_changed 在实时技能创建、更新或移除提交后触发,并包含可选的变更前后产物(带有内容哈希和树哈希),以及在可用时的声明版本和源版本。

这些钩子是原语,而非优化调度器。插件或外部控制器可以观察持久化的提案事件,评估其精确修订哈希,使用该哈希和关联 ID 进行修订,然后重复此过程。OpenClaw 不会自动修订提案,也不会运行无界的评估循环。事件重放受字节数限制,当另一页可用时返回 nextSequence。

渠道配对请求

当未配对的 DM 发送者创建待处理的配对请求后,插件需要通知操作员或写入审计记录时,请使用 channel_pairing_requested。该钩子在请求创建时被调度;配对回复的渠道投递不会因缓慢或失败的钩子处理器而延迟。

api.on("channel_pairing_requested", async (event) => {
  await notifyOperator({
    text: `New ${event.channel} pairing request from ${event.senderId}: ${event.code}`,
  });
});

该钩子仅用于观察。它不会批准、拒绝、抑制或重写配对回复。负载包含渠道、可选的 accountId、渠道作用域内的 senderId、配对 code 以及渠道元数据。请将配对码视为一次性的实时批准凭据,并且仅将其投递到受信任的操作员接收端。将 metadata 视为不可信的、由发送者提供的身份文本。该钩子不包含入站消息正文或媒体。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw