Files
deepseek-harness/docs/rfc/implemented/architecture/2026-06-30-event-domain-semantics.zh.md
T
Ziya 2565133af3 docs(i18n): RFC tree batch — 146 bilingual pairs via the committed pipeline
implemented(除 4 篇超长文档随后补)、proposed、rejected 全树配对;
同一流水线 + 二遍校验(paraphrase-back + 仓库上下文一致性)产出。
docs/rfc/implemented/AGENTS.md 与其 CLAUDE.md 符号链接列入排除
(agent 指令文件,与根 AGENTS.md 同策略)。
2026-07-15 23:25:06 -07:00

5.4 KiB
Raw Blame History

RFC:事件域语义——session 是事实日志,agent 是实时表面

Status: implemented

English | 中文

问题

harness 通过 Cordis 事件分类体系扩展 agent loop(智能体循环)(见微内核事件分类体系 RFC)。随着分类体系的增长,三个事件域之间的界限变得模糊:

  • session/* 承载持久的、事件溯源的日志(SessionEventMap)。
  • agent/* 承载实时运行时信号,向插件传递 Agent 句柄。
  • tools/* 承载工具注册表与执行 seam。

两个问题促使我们明确固定这些语义。第一,若干轮次/步骤边界同时以持久的 SessionEvent(turn/start、turn/end、step/start、step/end)和镜像的 agent/* emit(agent/turn-start、agent/turn-end、agent/step-start、agent/step-end)两种形式存在。消费方对同一事实有两个真源,每次生命周期变更都必须同时更新两处。第二,即将到来的 Hooks 子系统需要一个统一、有文档的订阅表面:插件作者(以及基于其上构建的 Claude Code / Codex 钩子桥接)必须无需阅读循环代码就能判断应该监听会话事件还是 agent 事件,以及为什么。

这套词汇是拦截决策、持久的 hook/* 日志,以及 Claude Code 与 Codex 桥接的基础。

决策

三个域,各司其职,一条边界规则。

  • session/*——持久的、可回放的事实日志。 拥有 SessionEventMap;每条记录仅含 JSON(无活对象)。每次追加触发一次 session/event emit,加上 session/flush 并行持久性检查点。它同时也是实时 transcript(文本记录)流:想要渲染或响应已发生事件的消费方在此订阅,因此实时渲染与 session/load 回放共享同一路径。
  • agent/*——实时运行时表面。 始终携带活的 Agent。两种形态:拦截型 waterfall(瀑布式事件)(agent/request、agent/step-result、agent/turn-continuation)可修改或否决,以及瞬态 emit(agent/status、agent/error、agent/created/agent/disposed、agent/queued)在持有 Agent 的情况下通知。轮次和步骤的边界不在此域——它们是持久的会话事件,从 session/event 读取;token 流(assistant/chunk)和中途引导(steering/message)同理。
  • tools/*——工具注册表与执行 seam。

边界规则: 持久的、可回放的事实是 SessionEvent;实时拦截或瞬态/活对象信号是 agent/tools Cordis 事件。轮次或步骤边界是持久事实,因此存在于会话日志中、从 session/event 流读取——不会被镜像为 agent/* emit。

将规则应用于边界镜像: 全部四个边界镜像——agent/turn-start、agent/turn-end、agent/step-start、agent/step-end——被移除。没有生产消费方需要在边界处持有活的 Agent:ACP 桥接从 session/event 的 turn/end 加 agent/status 结算;唯一的 turn 镜像消费方(dsh-ui-stdio,一个一次性测试 REPL)已迁移为从 session/event 渲染边界,通过 agent/created→id 映射恢复简短的 agent 标签。step 镜像先被移除(它们根本没有消费方);turn 镜像在 ui-stdio 迁移后随之移除——见移除边界镜像事件 RFC,该决策由它拥有。移除这些 emit 也简化了循环的 closeStep/closeTurn(各只需一次 append,无需配对 emit)。

后果

  • 循环不再 emit 任何边界镜像;closeStep 仅追加 step/end,closeTurn 仅追加 turn/end。Session.append 负责 post-commit observer 的隔离,因此抛出异常的边界 observer 无法改变轮次结果或饿死后续消费方;acceptance 或内部校验失败仍会在边界进入日志之前逃逸。
  • 之前通过已移除 emit 观察边界的测试现在观察持久的 turn/start/turn/end/step/start/step/end 会话事件——它们所固定的行为(边界排序、步骤计数)不变;只是读取的流切换到了权威的那一个。那些测试「抛出异常的 turn 边界 emit 监听器」的用例被删除,因为该代码路径已不存在(没有 emit 可供抛出)。按照 AGENTS.md "tests document behavior, not golden truth",行为与其测试一起迁移(或一起消亡)。
  • 循环仅在 append('step/start') 返回后才标记步骤为已打开(stepOpen = true)。内部 dispatch 校验在日志推送前运行,可能在不打开步骤的情况下拒绝;post-commit session/event observer 的失败被隔离在 Session.append 内部。因此该标记精确代表已提交的边界,该边界欠一个后续的 step/end。
  • 本 RFC 的完整实现是简化 RFC「停止将持久边界镜像为 agent 事件」:全部四个边界镜像被移除,所有消费方从 session/event 读取边界。agent/steering(不是边界镜像)不在该 RFC 范围内,由其后续 RFC 移除 agent/steering 镜像 emit 单独移除——它镜像的是持久的 steering/message。
  • Cordis 事件目录(docs/cordis-catalog/events.md)重新生成以移除镜像事件。