第 8 章 · Hooks 与生命周期扩展

02 · 编辑后自动处理

利用 after_edit hook,在文件修改后自动格式化代码——让 agent 的输出更规范。

问题的提出

Agent 修改文件时,模型的输出格式不一定完美。可能多了空格、少了换行、缩进不一致。虽然不影响功能,但会让代码审查者觉得"agent 写的代码不够规范"。

人类开发者通常在编辑器里配置了自动格式化(保存时运行 Prettier)。Agent 也应该有同样的能力——修改文件后自动格式化

after_edit Hook

after_editwrite_filepatch_file 执行后触发。它知道哪个文件被编辑了、用什么方式编辑的:

interface AfterEditContext {
  path: string;         // "src/agent.ts"
  method: "write" | "patch";
  result: string;
}

有了这些信息,就可以在编辑后执行格式化:

export function createAutoFormatHook(): Hook {
  return {
    name: "auto_format",
    timing: "after_edit",
    handler: async (ctx: AfterEditContext) => {
      const supportedExtensions = [".ts", ".tsx", ".js", ".jsx"];
      if (!supportedExtensions.some((ext) => ctx.path.endsWith(ext))) return;

      try {
        await execFileAsync("npx", ["prettier", "--write", ctx.path], {
          timeout: 10000,
        });
      } catch {
        // prettier 不存在或执行失败,静默跳过
      }
    },
  };
}

关键设计点:

只处理支持的文件类型。 .ts.tsx.js.jsx 用 Prettier 格式化。Markdown、JSON、YAML 等文件不处理。

静默失败。 如果项目没有安装 Prettier,或者 Prettier 执行出错,不影响 agent 的正常工作。格式化是"锦上添花",不是必需品。

有超时保护。 10 秒超时,防止格式化命令卡住整个 agent。

在 agent 中的触发

agent 循环中,after_edit hook 在工具执行成功后、上下文记录之前触发:

if (options?.hookManager) {
  await options.hookManager.executeAfterTool({
    tool: toolCall.name,
    args: toolArgs,
    result,
  });

  if (toolCall.name === "write_file" || toolCall.name === "patch_file") {
    await options.hookManager.executeAfterEdit({
      path: String(toolArgs.path ?? ""),
      method: toolCall.name === "write_file" ? "write" : "patch",
      result,
    });
  }
}

注意 after_edit 是在 after_tool 之后才触发的——先执行通用的工具后处理,再执行文件编辑的专门处理。

扩展:编辑后自动验证

同样的 after_edit 时机,还可以做"编辑后自动跑测试":

export function createEditVerifyHook(): Hook {
  return {
    name: "edit_verify",
    timing: "after_edit",
    handler: async (ctx: AfterEditContext) => {
      if (!ctx.path.endsWith(".ts")) return;
      if (ctx.path.includes(".test.") || ctx.path.includes(".spec.")) return;

      // 找到对应的测试文件
      const testPath = ctx.path.replace("src/", "test/").replace(".ts", ".test.ts");
      // 如果测试文件存在,运行它
      // ...
    },
  };
}

修改 src/agent.ts 后自动跑 test/agent.test.ts——如果测试失败了,agent 能在下一次工具调用中看到失败结果并尝试修复。

Hook 的组合

多个 after_edit hook 可以共存。它们按注册顺序执行:

hookManager.register(createAutoFormatHook());   // 先格式化
hookManager.register(createEditVerifyHook());    // 再跑测试

先格式化、再验证——顺序很重要。如果不先格式化,测试可能在格式不一致的代码上运行,结果不可靠。

Hook 的组合能力让 agent 的行为可以灵活定制。需要格式化就注册格式化 hook,不需要就不注册。不同的项目可以注册不同的 hook 组合。

下一节讲解审计日志和安全相关的 hook。

登录以继续阅读

解锁完整文档、代码示例及更多高级功能。

立即登录

On this page