PluginsHooks

Guard

详细说明 guard 的阻断语义、执行顺序,以及它为什么不应该拿来改值

Guard

guard 的核心语义很简单:

  • 通过,什么都不返回
  • 不通过,直接抛错

它的职责不是改值

很多人第一次写 guard,会忍不住在里面顺手改输入。

但 guard 最稳的职责其实只有一个:

  • 判断当前流程能不能继续

所以如果你的主要目标是“改一下输入”,那就应该去写 pipeline

一个最小例子

await agent.plugins.guard("review.require_checked", {
  reviewed: true,
});

plugin 里可以这样定义:

hooks: {
  guard: {
    "review.require_checked": [
      async ({ value }) => {
        const body = value as { reviewed?: unknown };
        if (body.reviewed !== true) {
          throw new Error("review is required before continuing");
        }
      },
    ],
  },
}

多个 guard handler 怎么跑

如果同一个点上有多个 guard:

  • 会按注册顺序依次执行
  • 只要其中一个抛错,后面的就不再跑

所以它像一串安检门。

适合的典型场景

权限判断

例如:

  • 当前用户有没有角色
  • 当前请求有没有权限

前置条件判断

例如:

  • 某个字段是不是必填
  • 某个状态是否已经准备好

安全边界

例如:

  • 某类请求是不是必须显式确认
  • 某类输入是不是要先过审

不适合的场景

想继续执行但顺手记一条日志

记录日志应该拆到 effect

想根据条件补默认值

补默认值应该拆到 pipeline

想给最终决策答案

那是 resolve

disabled plugin 时会怎样

如果某个 guard plugin 当前 disabled:

  • 它的 handler 会被跳过
  • 其他 active guard 仍然会继续执行

所以 guard 的语义是:

  • active 的 guard 参与检查
  • disabled 的 guard 不参与

最稳的实践

  • 让错误信息直接说明为什么被拦住
  • 不要在 guard 里偷偷写很多副作用
  • 不要把“改值”和“拦截”混成一件事

相关场景