DeepSeeker-Code源码导读12-Hooks四引擎

读懂 Hooks:agent 全生命周期的可编程切面,四种引擎怎么接

这篇讲什么

前面几篇讲的都是"agent 主动做什么"------工具、压缩、子 agent。这篇反过来讲"外部代码能在 agent 的哪些时刻插手"。

agent 跑起来不是黑盒------它有一系列关键节点:会话启动、用户输入、工具执行前后、退出、压缩前后、审批请求。如果这些节点能"挂"自定义逻辑,用户就能在不改 agent 源码的前提下扩展行为:比如每次 edit_file 后自动跑 prettier、每次用户输入前过一道敏感词、每次高危工具调用前 spawn 一个子 agent 智能评判。这就是 Hooks------agent 全生命周期的可编程切面

这篇拆 hooks/,四个文件------types.ts(11 类事件 + 类型)、registry.ts(注册分发)、loader.ts(配置→编译→注册)、shellExecutor.ts(命令执行)。核心是"同一套分发骨架,四种执行引擎":command(spawn shell)、http(POST webhook)、prompt(注入文本)、agent(spawn 子 agent 评判)。读完你会看到,把生命周期切成可挂载的事件点、把执行方式抽象成可替换的引擎,是"让 agent 可扩展又不失控"的关键。

一、先看全貌:什么事件能挂、用什么引擎挂

读这篇的钥匙,是下面这张"生命周期事件 × 能不能拦截"表。11 类事件覆盖 agent 全程,但只有两类能"拦":

事件 触发点 可拦截? 典型用途
SessionStart 会话启动,拿到 sessionId 后 观察 初始化日志、准备环境
UserPromptSubmit 用户输入进 agent 前 可拦截 敏感词过滤、注入附加上下文
PreToolUse 全部安全门禁之前(改写档)/ 审批后(兼容档) 可拦截 + 可改写 args lint、安全扫描、高危命令二次把关、参数规范化
PostToolUse 工具 execute 后 观察(可改写模型视图 edit_file 后自动 format、压缩啰嗦输出
Stop agent 主循环退出 观察 退出通知、结果上报
SessionEnd 请求结束、SSE 关闭前 观察 清理、统计
SubagentStart/Stop 子 agent 启动/收尾 观察 监控子 agent
PreCompact/PostCompact 上下文压缩前后 观察 记录 token 变化
PermissionRequest 审批请求发出前 观察 权限审计

注意"可拦截"那栏------11 类事件里,只有 PreToolUse 和 UserPromptSubmit 能 deny(阻断),其余全是"观察型"(只看不拦) 。这个二分是 Hooks 安全性的核心:能拦的只有"工具执行前"和"用户输入前"这两个"还来得及阻止"的点,其它都是事后观察,不影响流程。不过"观察"不等于"无能为力"------PreToolUse 现在还能改写 args 、PostToolUse 能改写模型看到的结果(resultOverride),这是在"拦/不拦"之外新增的第三种能力:改。

然后是"用什么引擎挂"------同一套 dispatch 骨架,四种执行引擎,看下表:

引擎 type 干什么 deny 决策依据 适用事件
command command(缺省) spawn shell 命令 退出码非 0 → deny;stdout JSON 可带改写 全部
http http POST 上下文 JSON 到 url 响应 JSON {deny:true} 或非 2xx(JSON 可带改写) 全部
prompt prompt 向 agent 注入文本 不 deny(只注入) 仅 UserPromptSubmit
agent agent spawn 子 agent 智能评判 子 agent 回 DENY:/ALLOW 仅 PreToolUse

拿几个场景盘活:

  • 场景 A:edit_file 后自动格式化。 配一条 PostToolUse 的 command hook,matcher=edit_file,command=npx prettier --write "$HOOK_FILE_PATH"。每次改完文件,shellExecutor 自动注入 HOOK_FILE_PATH(目标文件绝对路径),prettier 直接用。

  • 场景 B:高危命令二次把关。 配一条 PreToolUse 的 command hook,matcher=run_command,跑一个安全扫描脚本。脚本判定危险就 exit 1,denyOnNonZero(PreToolUse 默认 true)→ 工具被拦。

  • 场景 C:云端合规审计。 配一条 PreToolUse 的 http hook,把工具调用上下文 POST 到公司审计服务。服务返回 {deny:true, reason:"违反策略"} → 工具被拦。这适合团队/企业用 webhook 做集中策略。

  • 场景 D:注入附加上下文。 配一条 UserPromptSubmit 的 prompt hook,text="本次涉及数据库,务必先确认备份策略"。这条文本经 contextAdditions 通道拼进用户输入,模型每次都能看到。prompt 引擎不拦、只注入。

  • 场景 E:智能评判高危操作。 配一条 PreToolUse 的 agent hook,task="审查这个 git push 是否安全"。每次命中工具调用,spawn 一个完整子 agent 来评判,它回 DENY: 含未测试提交ALLOW用模型智能替代死规则,但成本高(每次都 spawn 一个 agent)。

  • 场景 F:参数规范化(改写)。 配一条 PreToolUse 的 command hook,matcher=write_file,脚本读 stdin 里的 args,把绝对路径改写成工作区相对路径,stdout 输出 {"argsOverride":{"path":"src/a.ts","content":"..."}}。模型传什么参数,都被规范化后才进安全门禁和执行。PostToolUse 同理:脚本可以输出 {"resultOverride":"(已格式化,无错误)"},把啰嗦的工具输出压成一行给模型(用户看到的仍是原始输出)。

理解了这两张表,再去看四个文件,主线就清晰了:types 定义"什么事件、什么引擎",loader 把配置编译成 HookRule(每种引擎一套 run 逻辑),registry 的 dispatch 统一分发,shellExecutor 执行 command。下面拆。

二、事件分类与分发模型

可拦截 vs 观察的二分

types.ts 用两个集合固化这个二分(:168):

ts 复制代码
export const INTERCEPTABLE_EVENTS = new Set(['PreToolUse', 'UserPromptSubmit']);  // 仅这两类能 deny
export const TOOL_EVENTS = new Set(['PreToolUse', 'PostToolUse']);                // 仅这两类消费 matcher

INTERCEPTABLE_EVENTS------只有工具执行前和用户输入前能拦。为什么是这两类?因为这是流程里"还来得及阻止"的最后两个点:用户输入拦了就不进 agent、工具执行拦了就不写盘。其它点(工具执行后、退出、压缩后)木已成舟,拦了没意义,只能观察记录。

TOOL_EVENTS------matcher(工具名匹配)只对工具事件有意义。给 SessionStart 配 matcher 没意义(它没有 toolName),loader 会 warn 并忽略。

dispatch:串行短路 vs 并发

registry.tsdispatch 按事件类型选两种执行模型(:74):

  • 可拦截事件:串行 + 短路 + 瀑布改写 。逐条跑 hook,首个 deny:true 立即返回拦截 (短路),不跑后续。hook 返回 argsOverride原地更新 ctx.args------后续 hook 和安全门禁看到的都是改写后的参数,最终瀑布值随 DispatchResult 带出。deny 短路时未消费的 override 直接丢弃(被拒的调用不会执行,改写无意义)。
  • 观察事件:Promise.all 并发 + last-wins 改写 。所有匹配的 hook 一起跑,单个失败只 warn。并发是为了累积延迟不线性叠加 ------10 条观察 hook 串行跑要 10 倍延迟,并发跑只要最慢那条。PostToolUse 的 resultOverride 在并发结果数组里按注册序收集、后者胜(last-wins,非瀑布)------不为改写牺牲观察事件的并发性,这是有意取舍。

这个分流很关键:拦截事件必须串行(要按顺序判定、短路、瀑布),但观察事件没顺序依赖,并发省时间。还有个单点门禁设计值得注意:改写能力只在 appConfig.hookRewrite 开启时生效(dispatch 内判定),开关关时两字段恒 undefined------调用方不需要到处判开关,行为自动回到"只拦不改"的旧世界。

matcher 匹配

matcher 只对工具事件生效,dispatch 里按 ctx.toolName 过滤(:79)。matcher 支持三种(:27):精确字符串("run_command")、通配("*")、正则(/edit|write/)、谓词函数。这让 hook 能精准挂到"某一类工具"上(只挂 edit_file、只挂 run_command),而不是对所有工具一刀切。

三、四种执行引擎

四种引擎的差异,全在 loader.ts 的 compileRule:241)里------同一段配置,按 type 编译成四种不同的 HookRule.run

command:spawn shell(默认)

最常用,既有行为。compileRule 把 command 编译成一个 run,调 shellExecutor(:331):

ts 复制代码
run: async (ctx) => {
    const res = await executeHookCommand({ command, cwd: ctx.cwd, env: ctx.env, timeoutMs, stdinPayload: ctx });
    if (res.timedOut) return denyOnNonZero ? { deny: true, ... } : { deny: false };
    if (denyOnNonZero && res.exitCode !== 0) return { deny: true, ... };
    if (res.exitCode === 0) {
        const out = parseStdoutDecision(res.stdout);   // ★ stdout JSON 决策协议
        if (out) return out;
    }
    return { deny: false };
}

deny 决策依据是退出码 :非 0 退出(脚本判定失败/危险)→ deny。denyOnNonZero 控制是否启用,PreToolUse 默认 true(非零即拦),其它事件默认 false。

退出码之外还有第二条决策通道------stdout JSON 协议 (loader.ts :230parseStdoutDecision)。exitCode 0 时,脚本可以在 stdout 输出一行 JSON 参与拦截/改写:

json 复制代码
{ "deny": true, "reason": "...", "argsOverride": { ... }, "resultOverride": "..." }

解析很挑剔:非 JSON、非对象、或不含任何已知字段 → 返回 undefined 静默忽略。这是刻意的向后兼容------prettier、lint 这类普通文本输出的既有 hook("Formatted 3 files")完全不受影响,只有显式输出决策 JSON 的脚本才拿到话语权。退出码解决"拦不拦",stdout JSON 解决"改什么"------脚本不用改退出约定就能精细参与参数规范化。

http:POST webhook

把整个 hook 上下文 JSON 化 POST 到 url,按响应决策(:296)。决策依据有两层:

  • 响应体是 JSON 且含 {deny:true, reason} → 直接采纳对端决策(让远端服务做策略判定);deny 分支早返回,不携带改写字段 (拒了的调用不执行,改写无意义)。否则 argsOverride / resultOverride 也走这条通道------仅 2xx 才采纳,让对端既能拦也能改。
  • 否则按状态码:非 2xx → denyOnNonZero 决策。

这适合"集中策略"------公司有一个审计服务,所有 agent 的工具调用都 POST 过去,由服务统一判定(升级后还能统一做参数规范化)。validateRule 强制 url 必须 http/https(防 file:// 之类的协议注入)。

prompt:注入文本(不 deny)

这是最特殊的一种------它不执行外部命令、不 deny,只往 agent 上下文注入文本:249):

ts 复制代码
if (raw.type === 'prompt') {
    const text = raw.text!;
    return { ...base, run: async () => ({ contextAdditions: [text] }) };
}

返回 contextAdditions,经 UserPromptSubmit 接缝拼入用户输入。validateRule 限制 prompt 只能配在 UserPromptSubmit(注入只在"进 agent 前"有意义,进了之后注入太晚)。它本质是"声明式的系统提示词补充"------不用改 agent 代码,配置一句文本就能影响模型每轮行为。

agent:spawn 子 agent 智能评判

最强大也最贵的一种(:255)。每次命中工具调用,spawn 一个完整子 agent,给它一个评判任务,让它按 DECISION 协议(最后一行 DENY: <理由>ALLOW)决策:

ts 复制代码
run: async (ctx) => {
    const tc = ctx?.toolContext;
    if (!tc || (typeof tc.depth === "number" && tc.depth > 0)) return { deny: false };  // ★ 深度门控
    const fullTask = ["审查即将执行的工具调用...", "决策协议:最后一行 DENY:/ALLOW", ...].join("\n");
    const res = await runSubagent({ task: fullTask }, tc, () => agentTools);
    const decision = parseAgentDecision(res.output);  // 解析最后一行 DENY/ALLOW
    return decision.deny ? { deny: true, ... } : { deny: false };
}

这是"用模型智能替代死规则"------command/http 的规则是死的(退出码、状态码),agent 能理解语义("这个 git push 含未测试代码,危险")。代价是每次命中都 spawn 一个子 agent,成本显著 (loader 注释明确警告"谨慎配置")。validateRule 限制 agent 只能配在 PreToolUse(PostToolUse 是观察型,deny 被忽略,spawn 子 agent 纯浪费)。

四、四个设计决策

决策一:hook 失败不得击垮主流程(容错铁律)

这是 Hooks 系统的最高原则(registry.ts 文件头)。两类事件两种容错:

  • 可拦截事件 handler 抛错 :按 rule.onError 决策。默认 'allow'(放行)------防有缺陷的 hook 误拦阻断 agent;安全类 hook 可显式设 'deny'(fail-closed)------自身崩溃即拒绝。
  • 观察事件 handler 抛错:静默吞掉(仅 warn)------观察型 hook 崩了不该影响任何流程。

核心思路:hook 是"锦上添花的外挂",不是"agent 的必需组件"。一条坏 hook(脚本写错、服务超时)绝不该让整个 agent 跑不下去。这个铁律贯穿整个系统。

决策二:可拦截 vs 观察二分(改写沿同一条边界落位)

11 类事件,只有 2 类能 deny。这不是偷懒,是职责边界------能拦的点只有"还来得及阻止"的两个(工具执行前、用户输入前),其余只能观察。强行给"工具执行后"加 deny 没意义(文件已经改了)。这个二分让"拦截"这个强能力被严格限定在合理的时机点。

后来加的改写能力也沿这条边界落位,没有开新口子:PreToolUse 改 args (行为还没发生,改的是"将要做的事"),PostToolUse 改 result (木已成舟,改的只是"模型看到的视图"------磁盘和执行结果不变,用户看到的仍是原始输出)。三类改写字段(argsOverride/resultOverride)各守各的事件位,且有三道安全边界:argsOverride 必须 plain-object(非对象 warn 后忽略,校验点统一在 dispatch------程序化和声明式 hook 共用一套);deny 短路时未消费的 override 直接丢弃(拦和改互斥,被拒的调用不会执行);总开关 DEEP_SEEK_HOOK_REWRITE 默认关,关着时两字段恒 undefined,整个系统回到"只拦不改"的旧世界。

决策三:四引擎统一 dispatch 骨架

command/http/prompt/agent 四种截然不同的执行方式,对外都是同一个 HookRule.run。差异全封装在 compileRule 的编译里------dispatch 完全不感知"这条 hook 是什么引擎"。这让分发逻辑(串行短路/并发)和执行逻辑(四种引擎)彻底解耦。加第五种引擎(比如未来的 event 评估器),只动 compileRule,dispatch 一行不改。这是"执行后端可替换"的抽象。

决策四:梯度超时 + 硬顶

hook 不能无限挂着(会阻塞主流程)。超时设计成梯度 + 硬顶 (types.ts :186):

ts 复制代码
SessionStart / UserPromptSubmit: 10_000,   // 阻塞启动和首字节,必须快
PreToolUse / PostToolUse / Stop: 30_000,   // 单工具级检查
SessionEnd: 60_000,                         // 收尾清理,最宽容
// 硬顶 HARD_TIMEOUT_CAP_MS = 300_000(5分钟)

分档依据是"事件对用户感知延迟的敏感度"------启动/首字节必须快(用户在等),收尾最宽容(用户已在等响应收尾)。用户显式配置的 timeoutMs 优先,但仍受 300s 硬顶约束。hook 是外挂,不能让它的耗时拖垮 agent 的响应性。

五、六个技术难点

难点一:fail-open vs fail-closed 的取舍

hook 自己崩溃(抛错,区别于"正常退出非零"的 denyOnNonZero)时怎么办?两种选择:放行(fail-open)或拒绝(fail-closed)。默认 fail-open------因为大多数 hook 是辅助性的(lint、format),它崩了不该误拦 agent。但安全类 hook(高危命令检测)应该 fail-closed------它崩了说明防护失效,宁可拒绝也不能放行高危操作。这个取舍通过 onError 字段下放给每条规则自己定。没有一刀切,因为 hook 的"重要性"因规则而异。

难点二:捕获同步抛错要用 Promise.resolve().then()

观察事件的并发执行有个隐蔽坑(registry.ts :96 注释):

ts 复制代码
// ★ 不能写 Promise.resolve(rule.run(ctx)),要写 Promise.resolve().then(() => rule.run(ctx))
Promise.resolve().then(() => rule.run(ctx)).catch(...)

为什么?Promise.resolve(rule.run(ctx))先求值参数 (执行 run),如果 run 是同步抛错的,异常在 .catch 挂上之前 就抛出了,逃逸出 catch。改成 Promise.resolve().then(() => run(ctx))------把 run 的执行延到 then 回调里,这时 catch 已经挂上,同步异常能被捕获。这是个 JS 微任务的细节坑,写错了会导致同步抛错的 hook 击垮主流程(违背容错铁律)。

难点三:agent hook 的深度门控防递归爆炸

agent 引擎 spawn 子 agent 评判工具调用。但子 agent 自己也会调工具 ,它的工具调用又会触发 PreToolUse → 又 spawn 子 agent → 树状 fan-out 爆炸。所以有深度门控(:264):

ts 复制代码
if (!tc || (typeof tc.depth === "number" && tc.depth > 0)) return { deny: false };

只有主 agent(depth=0)的工具调用才触发 agent hook;子 agent(depth>0)的工具调用跳过。注意:只有 agent 引擎受此门控,command/http/prompt 仍全深度触发(它们不 spawn 子 agent,不会递归)。这是"agent 引擎特有的递归风险,agent 引擎特有的防护"。

难点四:跨平台杀进程组

和第 9 篇 MCP 一样的坑。hook 命令经 shell 执行(spawn({shell:true})),超时要杀时,只 child.kill() 只杀了 sh -c,shell 派生的实际命令变孤儿继续跑。所以(shellExecutor.ts :117):

ts 复制代码
detached: !isWin,   // 非 Win 独立进程组
// 超时时:
void killTree(child);   // Win taskkill /T/F,非 Win process.kill(-pid) 杀整组

这是"shell 包装层"的固有麻烦------命令在 shell 子进程里,杀 shell 杀不到实际命令。killTree 跨平台杀整棵树。

难点五:环境变量白名单 + 字段截断

hook 命令是用户配置的 shell,执行时不能全量透传 process.env(有 DEEPSEEKER_CODE_TOKEN/API key)。所以白名单透传(shellExecutor.ts :29),和第 9 篇 MCP 的 MCP_ENV_WHITELIST 一致------任何 spawn 子进程的地方,都要防机密泄露

还有 stdin 载荷的字段截断(:60):edit_file 的 old_str/new_str 可能很大,无截断直传 stdin 会滞留管道缓冲、背压拖慢。capFieldStrings 递归按字段截断到 4KB,既限总量又保持合法 JSON。这个 MAX_STDIN_FIELD 还被 registry.ts 的 PostToolUse 结果截断复用------单一真相源,避免"名义 8K 实际 4K"的口径不一致

难点六:HOOK_FILE_PATH 注入,简单脚本不读 stdin 也能用

hook 上下文经 stdin 传 JSON,但有些简单脚本(比如 npx prettier --write "$HOOK_FILE_PATH"不读 stdin,只用环境变量 。所以 shellExecutor 把关键字段同步到 HOOK_* 环境变量(:104):HOOK_SESSION_ID、HOOK_TOOL_NAME、HOOK_PROMPT,工具事件额外注入 HOOK_FILE_PATH(从 args.path/file_path 提取,resolve 成绝对路径)。这让"一行命令的格式化 hook"不用解析 stdin 就能拿到目标文件路径------降低简单 hook 的编写门槛

六、推荐的源码阅读顺序

  1. 先读 types.ts 全文:建立"11 类事件 + 四引擎 + 可拦截/观察二分"的全景。重点看 INTERCEPTABLE_EVENTS / TOOL_EVENTS 两个集合、DEFAULT_TIMEOUT_BY_EVENT 梯度。
  2. registry.ts 的 dispatch(:74 :理解串行短路(拦截)vs 并发(观察)的分流,以及改写的两条通路------PreToolUse argsOverride 瀑布(:127,hook 返回即原地更新 ctx.args)、PostToolUse resultOverride last-wins(:111,保注册序并发收集)。重点读 Promise.resolve().then() 那个同步抛错坑(:96)。
  3. loader.ts 的 compileRule(:241 :这是四引擎的核心。逐个 type 分支读,看同一套配置怎么编译成四种 run。重点读 agent 的深度门控(:264)和 DECISION 协议解析。
  4. 读 validateRule(:129:看每种引擎的合法性约束(prompt 只能 UserPromptSubmit、agent 只能 PreToolUse、http 强制 http/https)。
  5. shellExecutor.ts 全文:看 command 引擎的执行细节------环境变量白名单、字段截断、HOOK_FILE_PATH 注入、跨平台杀进程组。
  6. 读 httpExecutor.ts:http 引擎的执行(POST + 响应解析 + 超时/abort),对照 shellExecutor 看两种外部执行的异同。

七、关联:Hooks 在整个系统里的位置

Hooks 是 agent 的"可扩展切面",和几个系统咬合:

  • 触发点 :dispatch 的调用散落在 agent 主循环各处------runAgent 的工具执行前后(第 2 篇)、SessionStart/End、压缩前后(第 4 篇)、子 agent 启停(第 5 篇)、审批请求(第 7 篇)。Hooks 不引入新流程,只是在既有流程的节点上挂监听。
  • 和 CustomTool 的对照:第 6 篇的 requireApproval(工具自己声明要审批)和 PreToolUse hook(外部代码在工具执行前插手)是两种"工具执行前的干预"。前者是工具内置的、声明式的;后者是用户/外部配置的、可编程的。两者叠加构成"工具执行前"的多道干预。
  • 和 registry 骨架的关系 :第 11 篇的 common/registry 是"声明式资源(skill/agent/command)的注册表"。Hooks 的 loader 复刻了同一套容错骨架(readXxxConfig 容错 + 单项失败隔离 + init 不阻断启动)------loader.ts 注释明写"复刻 MCP loader 四件套"。容错骨架是跨子系统的通用模式。
  • 信任边界 :项目级 hook(.deepseeker-code/settings.json)的 command 以 shell 执行,等同 git hooks 的信任模型。loader 加载时会打安全告警(:101)------克隆未知仓库前应核查这个文件。这和第 11 篇 filterSources 的项目级闸门一脉相承:项目级资源默认不可信。

你会看到,Hooks 不是孤立的"事件系统",它是 agent 把自己的关键节点开放出来的接口------11 类事件是"开放点",四引擎是"在这些点能做什么",dispatch 是"怎么安全地做"。容错铁律保证外挂不拖垮主体,可拦截/观察二分保证强能力被合理约束。

最后

让 agent 可扩展,最直接的想法是"开放一堆配置项"。但真正灵活的扩展,是"开放一堆可挂载的生命周期事件点,再给每个点多种执行方式"。Hooks 就是这个设计------SessionStart 到 SessionEnd 的 11 个节点都能挂规则,每条规则可以是跑个命令、发个 webhook、注入段文本、甚至 spawn 个智能子 agent 来评判。

读这段源码,最值得带走的是两个思路:一是"切面"思维 ------agent 的关键节点是可挂载的,外部逻辑能不侵入地介入(lint、审计、注入上下文);二是"引擎可替换"抽象------四种截然不同的执行方式,对外是同一个 run,差异封装在编译层,dispatch 完全不感知。再加上那条"hook 失败不得击垮主流程"的容错铁律,这套 Hooks 系统才真正做到了"可扩展又不失控"。

下一篇,我们读记忆系统------看 agent 怎么跨会话记住东西,以及系统提示词的注入策略。

项目源码开源在 github.com/xnk/deepSee... ,文章里提到的文件都在 src/core/src/hooks/ 下,欢迎对着源码读。觉得这个导读系列有点意思,点个 star 是我最大的鼓励。

总结

  1. 11 类事件覆盖 agent 全生命周期 :SessionStart/UserPromptSubmit/PreToolUse/PostToolUse/Stop/SessionEnd + Subagent/Compact/Permission 系列;只有 PreToolUse 和 UserPromptSubmit 可拦截(deny),其余全是观察型------能拦的只有"还来得及阻止"的两个点;
  2. 四引擎统一 dispatch 骨架:command(spawn shell,退出码决策 + stdout JSON 决策协议)/ http(POST webhook,响应 JSON 或状态码决策,改写仅 2xx 采纳)/ prompt(注入文本不 deny,仅 UserPromptSubmit)/ agent(spawn 子 agent 智能评判,DECISION 协议,仅 PreToolUse),差异全封装在 compileRule 编译层,dispatch 按"可拦截串行短路 / 观察并发"分流;
  3. 改写协议沿拦截/观察边界落位 :PreToolUse 返回 argsOverride 原地更新参数(瀑布,后续 hook 与安全门禁均见改写后值)、PostToolUse 返回 resultOverride 改模型视图(last-wins,并发不串行化);command 走 stdout JSON、http 走响应 JSON,非 JSON 静默忽略(既有 hook 零影响);DEEP_SEEK_HOOK_REWRITE 默认关,关时两字段恒 undefined;
  4. 四个设计决策:hook 失败不得击垮主流程(容错铁律,可拦截抛错按 onError 决策默认放行防误拦、观察静默吞)、可拦截 vs 观察二分(强能力限定合理时机,改写沿同一边界)、四引擎统一骨架(执行后端可替换)、梯度超时 + 硬顶(10/30/60s 按延迟敏感度分档,硬顶 300s);
  5. 六个技术难点:fail-open vs fail-closed 取舍(onError 下放)、Promise.resolve().then() 捕获同步抛错(不能 Promise.resolve(run()))、agent hook 深度门控防递归爆炸(仅 depth=0 触发)、跨平台杀进程组(detached + killTree)、环境变量白名单 + stdin 字段截断(防机密泄露 + 防背压)、HOOK_FILE_PATH 注入(简单脚本不读 stdin 也能用)。
相关推荐
quarter_day12 分钟前
DeepSeek Harness (DSH) 中配置 Google Gemini 与避坑实践
agent·deepseek
叠层归一研究院14 分钟前
螺旋时空:E框架的整合宇宙论
人工智能·经验分享·算法·机器学习·agi
xm_xm_xm_116 分钟前
TypeScript 7 个 核心特性
前端·typescript
pppiii23 分钟前
前端并发请求控制:5 种实现方案完整梳理
前端
DigitalOcean26 分钟前
GLM 5.3 已上线 DigitalOcean AI 推理云平台:Agent 任务的高性价比底座来了
llm·agent·chatglm (智谱)
LorryJovens29 分钟前
【LAAP意识动力工程学】aris自述如何让Agent产生意识的关键
人工智能
ms365copilot34 分钟前
Copilot分析销售收入变化、找出涨跌原因
大数据·人工智能·copilot
郑州光合科技余经理38 分钟前
本地生活平台搭建:统一订单表与多后台切换怎么拆
java·开发语言·前端·系统架构·uni-app·php·ai编程
YOLO数据集集合43 分钟前
煤炭质量目标检测数据集 、| 煤炭检测 工业视觉 质量分级 异物检测 煤炭异物8005期
人工智能·yolo·目标检测·计算机视觉·分类·煤炭检测数据集·异物数据集