This graph shows where policy, hooks, sandboxing, filesystem guards, result rewriting, final-outcome observation, and UI rendering run without changing the loop. The tools/pre-execute waterfall runs first, monotonic guards run next, and the tools/execute and tools/post-execute waterfalls follow; the three waterfalls may transform a call. Definition-owned finalizeContent and tools/result run afterward.
flowchart TD
model["Assistant message contains tool-call block"]
toolCall["Session event: <code>tool/call</code><br/>logged before execution"]
presentCall["UI pending card<br/>presentCall(args)"]
pre["<code>tools/pre-execute</code> waterfall<br/>hooks, permission, sandbox"]
guards["Registered monotonic guards<br/>deny or abstain; identity protected"]
denied["denied or approval refused<br/>tool body skipped"]
approval["<code>ctx.approval</code> one-shot prompt<br/>absent or unanswerable: deny"]
around["<code>tools/execute</code> waterfall<br/>timeout, retry, metrics (around dispatch)"]
toolBody["Registered tool execute() body"]
fsGate["<code>fs/write-intent</code> or <code>fs/edit-intent</code><br/>tool-fs mutations only"]
owned["Tool-owned session events<br/><code>todo/write</code>, <code>fs/observed</code>, <code>hook/invoked</code>, <code>hook/result</code>, <code>tool/code-dispatch</code>"]
post["<code>tools/post-execute</code> waterfall<br/>accept, block, replace, add context"]
normalized["Registry outer normalization<br/>pipeline/result snapshot throws become isError"]
finalize["ToolDefinition.finalizeContent<br/>last content-only invariant"]
final["<code>tools/result</code> synchronous notification<br/>frozen authoritative outcome"]
context["Active-batch additionalContexts FIFO<br/>injected user/message after recorded tool results"]
toolResult["Session event: <code>tool/result</code><br/>single model-facing outcome"]
allResults["Tool batch settled<br/>recorded tool/result events complete"]
presentResult["UI completed card<br/>presentResult(args, result)"]
model --> toolCall
toolCall --> presentCall
toolCall --> pre
pre -->|allow| guards
guards -->|allow| around
guards -->|deny| denied
guards -.->|throw| normalized
around --> toolBody
pre -->|deny| denied
pre -->|ask| approval
approval -->|allowed-once| guards
approval -->|rejected, cancelled, unavailable| denied
approval -.->|throw| normalized
denied --> post
pre -.->|throw| normalized
toolBody --> fsGate
fsGate --> toolBody
toolBody --> owned
toolBody --> around
around --> post
around -.->|wrapper throws| normalized
post -.->|throw| normalized
post --> finalize
normalized --> finalize
finalize --> final
final --> toolResult
toolResult --> presentResult
toolResult --> allResults
allResults --> context
Filesystem read-before-edit checks stay below tool-fs on fs/* events. Generic pre/post waterfalls host hooks and approval policy; ctx.approval resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap tools/execute. The registry losslessly snapshots the candidate result and normalizes a snapshot failure before the visible definition's snapshotted finalizeContent callback enforces its synchronous content-only invariant. tools/result then observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved run_code transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log tool/code-dispatch, return denials as binding rejections, and omit additionalContexts to preserve call/result adjacency.
Maintenance mode: curated Mermaid flow; exact tool schemas and event signatures live in generated catalogs.
工具执行流水线
此图展示策略、钩子、沙箱、文件系统守卫、结果重写、最终结果观察和 UI 渲染在不改变循环的情况下何时运行。tools/pre-execute waterfall(瀑布式事件)首先运行,随后是单调守卫,然后运行 tools/execute 和 tools/post-execute waterfall;这三个 waterfall 可以改写一次调用。由定义自身控制的 finalizeContent 和 tools/result 在此之后运行。
flowchart TD
model["Assistant message contains tool-call block"]
toolCall["Session event: <code>tool/call</code><br/>logged before execution"]
presentCall["UI pending card<br/>presentCall(args)"]
pre["<code>tools/pre-execute</code> waterfall<br/>hooks, permission, sandbox"]
guards["Registered monotonic guards<br/>deny or abstain; identity protected"]
denied["denied or approval refused<br/>tool body skipped"]
approval["<code>ctx.approval</code> one-shot prompt<br/>absent or unanswerable: deny"]
around["<code>tools/execute</code> waterfall<br/>timeout, retry, metrics (around dispatch)"]
toolBody["Registered tool execute() body"]
fsGate["<code>fs/write-intent</code> or <code>fs/edit-intent</code><br/>tool-fs mutations only"]
owned["Tool-owned session events<br/><code>todo/write</code>, <code>fs/observed</code>, <code>hook/invoked</code>, <code>hook/result</code>, <code>tool/code-dispatch</code>"]
post["<code>tools/post-execute</code> waterfall<br/>accept, block, replace, add context"]
normalized["Registry outer normalization<br/>pipeline/result snapshot throws become isError"]
finalize["ToolDefinition.finalizeContent<br/>last content-only invariant"]
final["<code>tools/result</code> synchronous notification<br/>frozen authoritative outcome"]
context["Active-batch additionalContexts FIFO<br/>injected user/message after recorded tool results"]
toolResult["Session event: <code>tool/result</code><br/>single model-facing outcome"]
allResults["Tool batch settled<br/>recorded tool/result events complete"]
presentResult["UI completed card<br/>presentResult(args, result)"]
model --> toolCall
toolCall --> presentCall
toolCall --> pre
pre -->|allow| guards
guards -->|allow| around
guards -->|deny| denied
guards -.->|throw| normalized
around --> toolBody
pre -->|deny| denied
pre -->|ask| approval
approval -->|allowed-once| guards
approval -->|rejected, cancelled, unavailable| denied
approval -.->|throw| normalized
denied --> post
pre -.->|throw| normalized
toolBody --> fsGate
fsGate --> toolBody
toolBody --> owned
toolBody --> around
around --> post
around -.->|wrapper throws| normalized
post -.->|throw| normalized
post --> finalize
normalized --> finalize
finalize --> final
final --> toolResult
toolResult --> presentResult
toolResult --> allResults
allResults --> context
文件系统的先读后编辑检查位于 tool-fs 之下,通过 fs/* 事件实现。通用的前置/后置 waterfall 承载钩子与审批策略;ctx.approval 在单调守卫之前处理询问,而不得重新排序的所有者策略仍作为已注册的守卫。超时等环绕分发关注点对 tools/execute 进行包装。注册表会对候选结果进行无损快照;如果快照失败,则会先将失败规范化,之后再由可见定义中已随快照固定的 finalizeContent 回调强制执行其同步且仅限内容的不变式。随后,tools/result 会观察不可变、可由 JSON 无损表示的结果。这样一来,钩子便可跨越不同工具系列,而无需让工具与某个策略服务耦合。Code Mode 会将保留的 run_code 传输及其序列化子调用都送入流水线;子调用携带父级 token、记录 tool/code-dispatch、将拒绝呈现为具有约束力的驳回,并省略 additionalContexts,以保持调用与结果相邻。
维护模式:英文源文件包含人工维护的 Mermaid 流程图,并由生成器写出;本中文文件作为经评审对侧通过双语配对维护。确切的工具 schema 与事件签名位于生成的目录中。