fix(agent): route loop dispatches through prebuilt fused dispatcher

Address review feedback on PR #1738:
- ReactLoopAgent builds its AgentEventDispatch once in the constructor and
  routes every emit/serial/waterfall through it, so hot-path dispatches no
  longer allocate a carrier and dispatcher per call; the public carrier
  field is gone (fused dispatcher is private).
- agentEvents accepts an optional prebuilt carrier.
- The fused payload builder spreads the payload before the injected agent
  so a structurally acceptable payload carrying an agent field can never
  override the subject.
- Regenerate doc graphs; re-record core + architecture + affected Agent
  Note translation pairs; add payload-object event contract Agent Note.
This commit is contained in:
_Kerman
2026-08-06 13:44:23 +08:00
parent 23671848c3
commit 262d044642
23 changed files with 143 additions and 61 deletions
@@ -15,8 +15,8 @@ harness 需要一套钩子子系统:用户像 Claude Code(CC)和 Codex 那
规范表面将可变换策略、环绕调度控制与仅观测通知分离。策略 waterfall(瀑布式事件)返回小型的、seam 专属的**类型化 Decision 联合类型**;包装层返回规范化结果;通知接收不可变快照,无法影响结果。覆盖的钩子点包括 `session-start`、`prompt-submit`、`pre-tool`、`post-tool`、通过 continuation 实现的 `stop`,同时将非钩子的执行策略留作独立可组合。
**Agent 事件**(`dsh-agent`):
- `agent/session-start(agent, source)` ——emit,在第 1 轮次之前触发一次,携带 `SessionStartSource`(`startup` 表示全新/fork 创建,`resume` 表示重新加载的持久化会话;`clear`/`compact` 保留)。纯通知,不能阻塞启动(这是有意的空白:桥接可以记录/注入,但不管控启动)。监听器通过 `agent.inject()` 注入上下文。
- `agent/pre-step(agent, messages, context, next) → PreStepDecision` ——waterfall,在每个拟议步骤之前、循环原子移除其独占 inbox 批次后触发。`PreStepContext` 携带该请求的 `turn`、`step` 与取消 `signal`;没有中途输入的工具续步会收到空批次。`enter` 返回完整消息批次,其中包括监听器为当前请求贡献的上下文;`reject` 不打开步骤,并让已领取消息保持已删除。
- `agent/session-start({ agent, source })` ——emit,在第 1 轮次之前触发一次,携带 `SessionStartSource`(`startup` 表示全新/fork 创建,`resume` 表示重新加载的持久化会话;`clear`/`compact` 保留)。纯通知,不能阻塞启动(这是有意的空白:桥接可以记录/注入,但不管控启动)。监听器通过 `agent.inject()` 注入上下文。
- `agent/pre-step({ agent, messages, turn, step, signal }, next) → PreStepDecision` ——waterfall,在每个拟议步骤之前、循环原子移除其独占 inbox 批次后触发。payload 携带该请求的 `turn`、`step` 与取消 `signal`(已退役的 `PreStepContext` 字段位于 payload 中;参见 [payload-object 事件决策](../architecture/2026-08-06-agent-event-payload-objects.md));没有中途输入的工具续步会收到空批次。`enter` 返回完整消息批次,其中包括监听器为当前请求贡献的上下文;`reject` 不打开步骤,并让已领取消息保持已删除。
**`agent/turn-stopping`** 是自然停止边界上的一次 awaited 通知。需要再执行一步的监听器调用 `agent.steer()`,传入来源显式的 steering(中途引导)内容供模型使用;循环随后重新读取 outbox,继续执行或关闭轮次。