# Agent 架构对比：Cyber Agent vs Claude Code

> 对比 **Cyber Agent**（本项目）与 **Claude Code v2.1.88**（非官方重建，仅供研究）的架构设计异同，目标是找到可借鉴的设计思路，以及两者各自的取舍。

---

## 总览

| 维度 | Cyber Agent | Claude Code |
|------|-------------|-------------|
| **语言/运行时** | Python / asyncio | TypeScript / Bun + Node.js |
| **定位** | 嵌入式 Agent 框架，供程序集成调用 | 面向开发者的交互式 CLI 工具 |
| **LLM 接入** | 多 Provider（OpenRouter / Gemini / Anthropic 等） | 仅 Claude API |
| **持久化** | 文件系统（JSONL + JSON），消息树结构 | 内存中维护会话，JSONL 转录为副产品 |
| **多 Agent** | 递归子 Trace，独立持久化，可跨设备 | Coordinator-Worker，内存中，不持久化 |
| **计划管理** | 原生 GoalTree（结构化、持久化、周期注入） | 无原生计划结构（TodoWriteTool 扁平备忘录） |
| **记忆层次** | 三层（Trace / Knowledge / Skill），Agent 主动写入 | 二层（CLAUDE.md / 历史压缩），人工维护 |
| **权限系统** | 预设白/黑名单（工具级） | 规则引擎（参数级 glob 匹配 + 交互审批） |
| **可观测性** | REST + WebSocket，结构化事件流 | 终端 UI + OpenTelemetry，无外部 API |
| **UI 层** | 无终端 UI | 自研 Ink 终端框架（251KB） |

---

## 核心结构类比

```
Cyber Agent              Claude Code
───────────────────      ───────────────────────
Trace                ↔   QueryEngine          （执行容器）
AgentRunner.loop     ↔   queryLoop            （while true 循环）
FileSystemTraceStore ↔   recordTranscript     （持久化）
GoalTree             ↔   TodoWriteTool        （计划管理，差距显著）
KnowHub + Reflect    ↔   CLAUDE.md            （跨任务记忆，差距显著）
```

---

## 一、执行容器：Trace vs QueryEngine

两者都是"单次执行会话"的容器，跨 turn 维护消息历史和统计数据。

| 维度 | Trace | QueryEngine |
|------|-------|-------------|
| **生命周期** | 持久化到文件系统 | 内存中，session 结束消失 |
| **消息结构** | 消息树（`parent_sequence`，支持 Rewind） | 线性数组 `Message[]` |
| **显式状态** | `running / completed / failed / stopped` | 无 |
| **计划结构** | GoalTree（持久化，周期注入） | 无 |
| **唯一标识** | `trace_id`（UUID，可跨设备引用） | 无专用 ID |
| **子执行单元** | 所有子 Agent 都是 Trace，结构统一 | AgentTool 各自独立，无统一模型 |
| **记忆去重** | `head_sequence` 管理主路径，消息树自动过滤 | `loadedNestedMemoryPaths` 防止 CLAUDE.md 重复注入 |

`loadedNestedMemoryPaths` 和 `head_sequence` 解决了相似的问题（防止重复处理），但层次完全不同：前者是内容级去重，后者是结构级的消息主路径管理。

**核心差异**：Cyber Agent 把 Agent 执行视为持久化的、可被外部观测的**任务**；Claude Code 更偏向交互式**会话**，持久化是副产品而非一等公民。

---

## 二、Agent 循环：AgentRunner.loop vs queryLoop

两者都是 `while true` → 调 LLM → 执行工具 → 继续 的循环，但在五个维度上有实质差异。

### 2.1 循环状态的管理方式

queryLoop 用一个**整体替换**的 `State` 对象管理跨迭代状态，所有 `continue` 点都是 `state = { ...newState }`：

```typescript
// queryLoop 的每个 continue 点——必须声明完整的下一轮状态
state = {
  messages: [...messagesForQuery, ...assistantMessages, recoveryMessage],
  maxOutputTokensRecoveryCount: maxOutputTokensRecoveryCount + 1,
  hasAttemptedReactiveCompact,   // 显式保留
  maxOutputTokensOverride: undefined,  // 显式重置
  pendingToolUseSummary: undefined,    // 显式重置
  stopHookActive,
  turnCount,
  transition: { reason: 'max_output_tokens_recovery', attempt: 2 },
}
continue
```

这带来三个好处：

1. **消灭"隐式携带"bug**：每个 continue 点必须声明每个字段，想沿用旧值也要显式写出来，不可能因为"忘了重置"而静默出错。
2. **每个 continue 路径自描述**：不需要追踪前面的赋值历史，任意找一个 continue 块就能知道下一轮的完整状态。
3. **`transition` 字段：零成本可观测性**：记录每次 continue 的原因（源码注释明说是专为测试设计的）：

```typescript
transition: { reason: 'next_turn' }
transition: { reason: 'max_output_tokens_recovery', attempt: 2 }
transition: { reason: 'reactive_compact_retry' }
transition: { reason: 'stop_hook_blocking' }
transition: { reason: 'collapse_drain_retry' }
```

测试可以直接断言 `state.transition.reason === 'reactive_compact_retry'`，而不必解析消息内容推断"压缩是否发生了"。**这个字段也是天然的 debug 信息**：任何时候 dump 出 state 就能知道循环目前处于哪个恢复阶段。

注意：`state.messages` **不是** API payload。实际发给 API 的是 `prependUserContext(messagesForQuery, userContext)`，其中 `messagesForQuery` 是 `state.messages` 经过多层变换（compact 边界过滤 → 工具结果截断 → microcompact → autocompact）后的结果。State 本身不落盘，只有 queryLoop yield 出来的 Message 才被 QueryEngine 记录到 transcript。

AgentRunner 当前直接在迭代内修改变量，没有这个整体替换的抽象。

### 2.2 工具执行时机（最大差异）

queryLoop 有 `StreamingToolExecutor`（feature gate），工具在模型**还在流式输出期间**就并发开始执行：

```
模型流式输出：  [tool1 完整] ── [tool2 完整] ── [tool3 完整] ── 流结束
StreamingExecutor: └→ 立即开始执行  └→ 立即开始执行  └→ 立即开始执行
                        ↓ 执行完立即 yield 结果，不等流结束
```

工具执行时间被完全"藏"在模型输出时间里。AgentRunner 等 LLM response 完整后才执行工具。

### 2.3 循环内多层恢复路径

queryLoop 内置了多条恢复路径，全部通过 `state = next; continue` 在**循环内**动态触发：

```
prompt_too_long → 1. context_collapse drain（轻量，清空 staged collapses）
               → 2. reactive compact（重新压缩，LLM 调用）
               → 失败 → 暴露错误，return

max_output_tokens → 1. 升级到 64k（maxOutputTokensOverride，一次机会）
                 → 2. 多轮文本恢复（最多 3 次，注入 meta 消息）
                 → 3. 耗尽 → 暴露错误，return

模型降级（FallbackTriggeredError）→ 切换 fallbackModel，丢弃已有输出，重试

stop hook blocking → 注入 hook 错误消息，continue
```

AgentRunner 的恢复（`_heal_orphaned_tool_calls`）发生在进入循环**之前**（`_build_history` 阶段），不是循环内的动态恢复。

### 2.4 周期性上下文注入

AgentRunner **主动、周期性**注入 GoalTree + Collaborators：
```python
if iteration % 10 == 0:
    inject_context(goal_tree, collaborators)
```

queryLoop 的记忆是**被动消费**的：`startRelevantMemoryPrefetch` 在每轮开头触发异步预取，settled 且本轮尚未消费时才注入为 attachment。没有强制周期，也没有计划结构注入。

### 2.5 Hooks：外部介入点

这是两个系统差距最大的维度之一。

**Cyber Agent `context_hooks`**：每 10 轮调用一次，返回 markdown 字符串注入为上下文。功能是**只读注入**，无法阻断或修改任何事物。

**CC hooks**：覆盖 25+ 事件，三种执行模式（shell / HTTP / TypeScript 回调），每个事件有专用的双向契约：

| 维度 | Cyber Agent `context_hooks` | CC hooks |
|------|---------------------------|---------|
| **事件数量** | 1（周期注入） | 25+（全生命周期） |
| **工具生命周期** | 无 | PreToolUse / PostToolUse / PostToolUseFailure / PermissionDenied |
| **loop 控制** | 无 | Stop hook block → `stopHookActive=true` → 强制 continue |
| **修改输入/输出** | 无 | PreToolUse 改 toolInput；PostToolUse 改 MCP 输出 |
| **阻断执行** | 无 | PreToolUse deny；PostToolUse preventContinuation |
| **执行模式** | Python 函数 | shell / HTTP / TypeScript callback / postSampling |
| **会话级注册** | 随 AgentRunner 传入 | `addFunctionHook()`，Map-based，O(1)，高并发友好 |

三个最重要的 hook 事件在 loop 上下文里：

- **PreToolUse**：在权限检查之前调用，可 `allow`/`deny`/`ask` + 修改 toolInput。允许外部系统做"无人值守的审批代理"，比交互弹窗更适合自主运行场景。
- **Stop hook**：每轮结束时调用，若返回 block，则 `state.transition = 'stop_hook_blocking'`，loop 强制再 continue 一轮。这是"外部系统驱动 Agent 继续工作"的接入点。
- **UserPromptSubmit**：用户消息进队列时调用，可注入 `additionalContext` 或改写消息本体。比 `context_hooks` 的定时注入更精确（每次用户输入时触发，而非每 10 轮）。

### 2.6 工具摘要的异步隐藏

queryLoop 在工具执行完毕后 fire-and-forget 一个 Haiku 摘要任务，**不等它**，Promise 存入 `nextPendingToolUseSummary`，下一轮迭代开头才 await：

```typescript
// 工具执行完毕后立即触发（不阻塞当前轮）
nextPendingToolUseSummary = generateToolUseSummary({...})

// 下一轮迭代开头取结果——此时 Haiku ~1s 早已完成
const summary = await pendingToolUseSummary
```

Haiku 摘要的延迟被下一轮 5-30s 的 API 调用时间完全吸收。AgentRunner 没有对应机制。

---

## 三、持久化与消息结构

### Cyber Agent：消息树（非破坏性）

每条 Message 有 `sequence`（全局递增）和 `parent_sequence`，构成树结构：

```
正常执行：   1 → 2 → 3 → 4 → 5
Rewind 到3：             3 → 6 → 7    （4,5 自动脱离主路径）
压缩 1-3：   8(summary,parent=None) → 6 → 7
侧分支：     5 → 6(reflection) → 7   （不在主路径）
             5 → 8(summary, 主路径)
```

`trace.head_sequence` 始终指向主路径头，`build_llm_messages` 沿链回溯，侧分支自动被过滤。所有历史永久保留，Rewind 是非破坏性操作。

### Claude Code：线性历史（有损压缩）

消息以数组形式存在内存中，转录文件是 append-only JSONL。没有树结构，压缩是破坏性的（原始消息不再恢复）。QueryEngine 维护完整的 `mutableMessages`，queryLoop 内的 `state.messages` 在压缩后被替换为压缩后版本。

**关键差异**：Cyber Agent 是非破坏性时间旅行；Claude Code 是有损折叠。代价是 Cyber Agent 存储开销更高，查询需要沿链回溯。

---

## 四、计划管理

### Cyber Agent：原生 GoalTree

GoalTree 是一等公民，有独立数据模型（`Goal`）、专用工具（`goal`）、持久化（`goal.json`）和周期注入机制：

```
1. [in_progress] 分析代码架构
   1.1. [completed] 读取项目结构
   1.2. [in_progress] 分析核心模块
        1.2.1. [pending] 分析 runner.py
        1.2.2. [pending] 分析 tool_registry.py
```

- Goal 与 Message 关联（`msg.goal_id`），压缩以 Goal 为粒度
- 每 10 轮自动注入，模型始终知道自己在做什么
- 支持 `focus` / `done`（附 summary）/ `abandon`（附原因）

### Claude Code：TodoWriteTool（扁平备忘录）

扁平的待办列表，markdown 文本，格式由模型自行决定。无层级结构，无与消息的关联，不跨 session 持久化，不参与压缩粒度决策。

**结论**：这是两个系统差距最大的维度之一。GoalTree 是架构级方案，TodoWriteTool 是临时补丁。

---

## 五、记忆系统

### Cyber Agent：三层记忆，Agent 主动写入

```
Layer 3: Skills（技能库）
  Markdown 文件，领域知识和操作规范，启动时注入 system prompt
        ▲ 归纳
Layer 2: Knowledge（知识库）
  数据库 + 向量索引（KnowHub），语义检索按需注入
        ▲ 提取（Reflect 机制）
Layer 1: Trace（任务状态）
  当前任务的工作记忆：Messages + GoalTree
```

- **Reflect**：执行完成后触发侧分支 Agent，分析历史，调用 `knowledge_save` 结构化入库
- **跨任务学习**：知识从一个 Trace 提取后，下一个 Trace 可语义检索复用

### Claude Code：二层记忆，人工维护

```
Layer 2: CLAUDE.md（持久指令）
  项目/用户级 Markdown，自动发现（目录树遍历），注入 system prompt

Layer 1: Session 历史（工作记忆）
  当前对话历史（内存），超长时自动压缩折叠
```

跨 session 保留的内容只有写入 CLAUDE.md 的部分，Agent 本身不会主动提炼知识。

### 记忆组织轴的根本差异

| | Claude Code | Cyber Agent |
|--|-------------|-------------|
| **组织轴** | 人为定义的实体（用户、项目） | 执行本身涌现的语义主题 |
| **边界划定者** | 人（目录结构、项目边界） | Agent（`type` + `tags` + `scopes`） |
| **谁来写记忆** | 人（或由 Claude 辅助人写 CLAUDE.md） | Agent 自身（Reflect 触发后主动入库） |

Claude Code 的记忆是**静态附加的上下文**，边界由人预先划定。Cyber Agent 的记忆可以从**执行本身涌现**，围绕"自主执行的任务"或"跨任务的全局线索"（如某类 bug 的修复模式）自然积累。

---

## 六、上下文压缩

### Cyber Agent：两级压缩 + 侧分支（非破坏性）

**Level 1（Goal 完成压缩，零 LLM 成本）**：以 Goal 为粒度，completed goal 的消息折叠为 `long_term_memory` 摘要，确定性，无额外 API 调用。

**Level 2（LLM 侧分支压缩）**：`POST /compact` 触发，在 Trace 末尾创建 `branch_type="compression"` 侧分支，压缩结果作为 summary 消息插入主路径。原始消息保留在侧分支，可审计。

控制参数：`RunConfig(goal_compression="none"|"on_complete"|"on_overflow")`

### Claude Code：多层被动触发（有损）

每轮迭代前依次经过：`HISTORY_SNIP` → `microcompact` → `CONTEXT_COLLAPSE` → `autocompact`（token 接近阈值时触发）。触发后用摘要模型折叠历史，原始消息丢失。`prompt_too_long` 错误时进入 reactive compact（最后手段）。

| 方面 | Cyber Agent | Claude Code |
|------|-------------|-------------|
| 压缩粒度 | Goal 级（语义边界） | 全量历史折叠 |
| 压缩成本 | Level 1 零成本；Level 2 LLM 成本 | 始终有 LLM 成本 |
| 压缩可逆性 | ✅ 侧分支，原始消息保留 | ❌ 有损折叠，原始丢失 |
| 触发时机 | 主动（on_complete / on_overflow） | 被动（超限后）+ 手动 |

---

## 七、多 Agent 协作

### Cyber Agent：递归 Trace + 跨设备协议

```
主 Agent（Trace A）
    ├── agent(task="研究X")           → 子 Trace B（独立持久化，可单独续跑）
    │    └── agent(task="分析子模块") → 子 Trace C（递归）
    └── agent(agent_url="https://remote/", task="...")
         → 远程 Trace（agent://remote/xxx，跨设备）
```

- **explore 模式**：`task: List[str]` 触发 `asyncio.gather()` 并行多 Agent
- **evaluate 工具**：专用评估 Agent，从 GoalTree 自动注入评估标准
- **续跑子 Agent**：`agent(continue_from=sub_trace_id)` 可续跑被中断的子 Agent

### Claude Code：Coordinator-Worker（内存中）

```
Coordinator Agent
    ├── AgentTool(subagent_type="worker") → Worker 1（内存，非持久化）
    ├── AgentTool(subagent_type="worker") → Worker 2
    └── SendMessageTool(to=agent_id)      → 向活跃 Worker 发消息
```

Worker 以 `<task-notification>` XML 上报状态，通过 `SendMessageTool` 持续对话。

| 方面 | Cyber Agent | Claude Code |
|------|-------------|-------------|
| 子 Agent 持久化 | ✅ 独立 Trace | ❌ 内存中 |
| 续跑子 Agent | ✅ `continue_from` | ✅ `SendMessageTool` |
| 跨设备协作 | ✅ `agent_url` + 远程 Trace ID | ❌ 不支持 |
| 并行执行 | ✅ explore 模式 | ✅ 多 Worker 并行 |
| 评估反馈循环 | ✅ evaluate 工具 | ❌ 无原生评估工具 |

---

## 八、工具系统

### 工具定义

**Cyber Agent（装饰器，轻量）：**
```python
@tool(description="执行 shell 命令")
async def bash(command: str, ctx: ToolContext) -> ToolResult:
    return ToolResult(
        output=result.stdout,
        long_term_memory=f"Ran: {command}",  # 压缩后保留的摘要
    )
```

**Claude Code（接口，功能丰富）：** 每个工具实现约 15 个方法：`call`、`description`、`checkPermissions`、`isReadOnly`、`isConcurrencySafe`、`prompt`（注入 system prompt 的说明）、`renderToolResultMessage`（UI 渲染）等。接口更重，但权限检查、并发安全标记、进度报告、UI 渲染都内置其中。

### ToolResult 双层记忆（Cyber Agent 特有）

```python
ToolResult(
    output="<10K tokens 完整内容>",      # 第一次给 LLM 完整内容
    long_term_memory="提取了 10000 字符", # 之后只看摘要
    include_output_only_once=True
)
```

大输出只在首次注入完整内容，后续轮次自动替换为摘要，有效节约 context window。Claude Code 没有对应机制。

### Bash 安全（Claude Code 更精细）

Cyber Agent 通过 `AgentPreset.denied_tools` 黑名单控制，粒度是整个工具。

Claude Code 有独立的 102KB 安全分析器（`bashSecurity.ts`）：
- 命令语义分析（参数级，不只是工具名匹配）
- 路径白名单（工作目录 + 额外允许目录）
- 破坏性命令检测（rm -rf, dd, mkfs 等）
- 模式匹配规则：`"Bash(git *)"` 自动允许所有 git 命令

---

## 九、权限系统

### Cyber Agent：静态预设（工具级）

```python
AgentPreset(
    allowed_tools=["read", "glob", "grep"],
    denied_tools=["write", "edit", "bash"],
)
```

工具级粒度，静态配置，无动态审批。适合离线/批量 Agent 场景。

### Claude Code：规则引擎（参数级）+ 交互审批

- 规则格式：`"Bash(git *)"` 支持 glob 模式匹配到参数级
- 三种规则：alwaysAllow / alwaysDeny / alwaysAsk
- 权限模式：default（交互）/ auto（ML 分类器）/ bypass
- **规则自动学习**：用户选择"始终允许"后自动写入配置，构建个性化规则库
- 企业远程策略：通过 managed settings 下发权限规则

适合面向开发者的交互式场景。

---

## 十、可观测性

### Cyber Agent：结构化事件流（服务视角）

- **WebSocket** `/api/traces/{id}/watch`：实时推送所有 Message 事件
- **REST API**：查询 Trace、Messages（main_path / all）、GoalTree
- **GoalTree 统计**：每个 Goal 有 `self_stats` 和 `cumulative_stats`（token、cost、duration）
- **全历史可查**：包括 rewind 旧路径、侧分支

### Claude Code：终端 UI + 遥测（工具视角）

- **Ink 终端 UI**：实时 spinner、CoordinatorTaskPanel
- **OpenTelemetry**：结构化日志（懒加载）
- **无外部 API**：不暴露 HTTP 接口

**关键差异**：Cyber Agent 从架构上是**服务**，天然可集成监控；Claude Code 是**工具**，可观测性服务于操作者自己。

---

## 总结：差异与互补

### Cyber Agent 的架构优势

| 优势 | 价值 |
|------|------|
| **消息树 + Rewind** | 非破坏性时间旅行，支持回溯，全历史可审计 |
| **GoalTree** | 结构化计划，与消息关联，驱动细粒度压缩 |
| **Knowledge + Reflect** | 跨任务知识积累，Agent 主动从经验中学习 |
| **记忆组织轴** | 围绕执行语义积累，不依赖人为划定边界 |
| **evaluate 工具** | 内置评估-反馈循环，Agent 可自我校正 |
| **ToolResult 双层记忆** | 精细的 context 节约机制 |
| **跨设备 Agent 协作** | 分布式 Agent 网络，协议级支持 |
| **Context Injection Hooks** | 灵活的外部事件注入（A2A IM、监控告警等） |
| **服务化 API** | REST + WebSocket，天然可集成、可观测 |

### 值得从 Claude Code 借鉴的设计

| 设计 | 价值 |
|------|------|
| **Loop State 整体替换 + transition 字段** | 消灭"隐式携带"bug；transition 记录每次 continue 的原因，可用于测试断言和 debug，扩展后也可通过 WebSocket 推出去实现循环级可观测性 |
| **流式工具并发执行** | 工具在模型流式输出期间就开始执行，延迟藏在模型输出时间里 |
| **循环内多层恢复路径** | prompt_too_long / max_tokens / 模型降级等错误在循环内动态恢复，无需重启 |
| **工具摘要异步隐藏** | Haiku 摘要在工具执行后 fire-and-forget，延迟藏在下一轮 API 调用时间里 |
| **Bash 语义级安全分析** | 参数级权限控制，远比工具级黑名单精准，生产环境自主运行时重要 |
| **ToolSearch 延迟加载** | 工具数量大时按需加载描述，节约 system prompt token |
| **权限规则自动学习** | "始终允许"自动写入配置，构建个性化规则库 |
| **工具生命周期 hooks（PreToolUse / PostToolUse）** | 在工具执行前后插入外部逻辑：审批代理（PreToolUse allow/deny）、MCP 输出改写（PostToolUse updatedMCPToolOutput）、失败后通知（PostToolUseFailure）。Cyber Agent 目前对工具执行无介入点 |
| **Stop hook（loop 控制）** | 每轮结束时调用，可返回 block 强制 loop 再 continue 一轮（`transition='stop_hook_blocking'`）。这是"外部事件驱动 Agent 继续"的最直接接入点 |
| **UserPromptSubmit hook** | 用户消息进队列时触发，可注入 `additionalContext` 或改写消息。比 `context_hooks` 定时注入更精确，也更适合做"收到外部信号时注入上下文"的触发器 |
| **工具结果自动存档（toolResultStorage）** | 每个工具声明 `maxResultSizeChars`，超限时自动写入磁盘临时文件，API 收到 preview（前 2000 字节）+ 文件路径，模型可按需用 FileReadTool 读回完整内容。与 Cyber Agent 的 `long_term_memory`（手动摘要、原始内容丢弃）互补：这是零开发者工作量的兜底层，防止意外大输出撑爆 context，且原始内容可恢复 |

---

## 待办：值得引入的改进

| 优先级 | 改进项 | 说明 |
|--------|--------|------|
| ★★★ | **Loop State 整体替换 + transition 字段** | 将 AgentRunner loop 的跨迭代变量收拢为一个整体替换的 State 对象；每个 continue 点声明完整下一轮状态，消灭"忘记重置某字段"的隐患。新增 `transition` 字段记录每次 continue 的原因（`tool_use` / `compressed` / `healed_orphan` 等），可直接用于测试断言，也可通过 WebSocket 推出去作为循环级可观测事件 |
| ★★★ | **工具结果自动存档** | 每个工具声明 `max_result_size`（字符数），超限时自动写入临时文件，给模型 preview（前 N 字节）+ 文件路径，模型可用 `read` 工具读回完整内容。与现有 `long_term_memory`（开发者手写精炼摘要）互补：这是零开发者工作量的兜底层，防止 `bash` 大输出、`webfetch` 整页 HTML 等意外撑爆 context |
| ★★☆ | **工具并发执行** | 单次 LLM 响应包含多个 tool_use 时，用 `asyncio.gather()` 并行执行，而非顺序执行。对"同时读取多个文件"等场景延迟改善明显 |
| ★★☆ | **工具摘要异步隐藏** | 工具执行完毕后 fire-and-forget 启动摘要生成（用小模型），不阻塞当前轮，下一轮迭代开头取结果。摘要延迟藏在下一次 LLM 调用时间里，对用户零感知 |
| ★★☆ | **工具生命周期 hooks** | 在 `ToolRegistry` / `AgentRunner` 层面引入 `pre_tool_use` / `post_tool_use` / `post_tool_use_failure` 三个事件。最高价值用例：① `pre_tool_use` 实现无人值守审批代理（尤其对 `bash` 危险命令）；② `post_tool_use_failure` 触发外部通知或重试策略；③ `post_tool_use` 对特定 MCP 工具的输出做后处理 |
| ★★☆ | **Stop hook + Loop 控制接入点** | 在每轮 loop 结束时（得到 `stop_reason='end_turn'`）触发一个 hook，如果返回 block 则注入消息并 continue。这让外部系统（监控、测试框架）可以在运行时"插入"下一步指令，而无需重新发起整个对话 |
| ★☆☆ | **循环内多层恢复路径** | 目前 `_heal_orphaned_tool_calls` 在进入循环前执行。可考虑将更多恢复逻辑移入循环内（context 超限时自动触发压缩并 continue，而非报错退出） |

---

*对比基于 Cyber Agent 文档（`architecture.md`）与 Claude Code v2.1.88 npm 包 source map 分析（非官方重建，仅供研究），生成日期：2026-04-02。*
