Skip to content

Latest commit

 

History

History
219 lines (155 loc) · 9.65 KB

File metadata and controls

219 lines (155 loc) · 9.65 KB

Baton 工作流

本文是 Baton 双向工作流的唯一入口:用户输入如何经过 Controller 到达 Harness,Harness 的输出 如何成为可恢复事实并返回用户,以及 steer、Interaction、cancel、失败和恢复如何复用同一条 主路径。核心对象和不变量见 Kernel,Adapter 契约见 Harness

1. 一条双向流水线

控制(用户 → Harness)

User
  → chat-tui intent
  → Input admission / queue
  → Context Snapshot + Delivery
  → Delivery Attempt
  → Harness Adapter
  → Harness wire

感知(Harness → 用户)

Harness wire
  → Adapter normalize
  → Event append / broadcast
  → reduce / Projection
  → chat-tui render
  → User

Plugin 不另开执行通道。proposed-input 先展示给用户;只有用户确认或编辑并提交后,它才成为 普通 Input。Interaction 也不进入 prompt queue,而是按稳定 identity 就地解开等待方。

2. 用户输入到 Harness

2.1 采集与准入

chat-tui 只把 composer 内容和用户意图交给 Baton。mention、Session 引用和 Plugin Context 在 Context 层解析;chat-tui 不理解 HarnessSession 或 Harness wire。

Controller 为 prompt Input 分配稳定 messageIdturnId,并用一等状态记录它的消费位置:

queued → admitted → finalized
   │         │
   │         └──────────────→ interrupted
   └────────→ recalled

accepted_steer → finalized | interrupted

queued 输入仍可 recall。出队成为 admitted 后,用户消息已经是 BatonSession 的正典事实, 不能再伪装成“从未提交”;此后 Esc 表达 cancel/interrupt。队列只串行调度 driven Turn,Harness 自发产生的 observed Turn 不占 admission 槽。

2.2 Turn 开界

Controller 出队时先 append:

  1. user_message(source:user):保存用户原始输入;
  2. state_update(running, source:baton):为 driven Turn 开界。

这两个事实不等待 Harness 冷启动。否则用户消息会被进程启动时间绑住,Context prepend 也可能 被误写进正典历史。

2.3 Context 组装与交付

当前 ContextSource 首先承载 BatonSession 的缺失历史。Controller 按目标 HarnessSession 的 已确认水位组装 (afterSeq, throughSeq],先持久化 ContextSnapshot,再选择 transport:

  1. sync_context:Harness 提供独立同步能力;
  2. submit_side_channel:随本次 sendTurn 的 side channel 送达;
  3. prompt_prepend:都不支持时,在预算内 prepend 到 transport prompt。

Snapshot 只说明准备送什么。transport 接受后才 append ContextDeliveryReceipt 并推进该 HarnessSession 的 ContextEpoch;只有 Snapshot 没有 Receipt 时,下次必须重投。Context 注入 不修改 Codex、Claude Code 等原生 Session 文件,也不进入用户原始消息。

2.4 Attempt 与 Adapter admission

Harness 已打开、Context 已组装后,Controller 先 append _baton_delivery_attempt_update(prepared),记录 Input、Target 和不可变 HarnessLaunchSnapshot;随后把 Attempt 推到 dispatching,再调用:

adapter.sendTurn(handle, promptInput)

Adapter 根据自己的权威运行态返回:

  • new_turn:接受开启一轮新工作;
  • steer:输入已经进入匹配的当前 Turn;
  • rejected:没有接受责任,Controller 可以安全降级为 queued follow-up。

Receipt 只确认 Adapter 接受了投递责任,不代表 Harness 已完成。accepted 后的错误必须通过事件流 终结 Turn;throw 只能表示 Adapter 尚未接受。Controller 据此持久化 Attempt 的 accepteduncertain 或最终 outcome。

3. Harness 输出到用户

3.1 Adapter 归一

Adapter 消费原生 wire,把 message、thought、tool、diff、plan、task、usage、Interaction 和状态 翻译为 Baton Event 草稿。宿主在可信入口补齐 source:harness、HarnessTarget、HarnessSession 和 Turn 坐标,Store 再补 eventId、scope、时间与序号。

归一原则是“稳定语义 + raw 保真”:

  • message/tool/plan 按稳定 ID upsert;
  • 字段省略表示不变,null/空集合表示清除,具体值表示替换,chunk 表示追加;
  • completed item 应携带全量内容,纠正此前丢失或乱序的 chunk;
  • 原生粒度差异保留在 raw,Projection 与 Store 不出现 Harness 分支;
  • 未知终态悲观处理,未知通知进入有界诊断和原生 trace,不静默吞掉。

3.2 append、reduce 与 Projection

所有事件进入同一条路径:

append → broadcast → reduce → Projection snapshot → chat-tui

live 和重开 Session 使用相同 reducer。自愈也必须合成新的事实 Event 再走这条路径,不能直接 修改页面状态。chat-tui 只消费 transcript、activity、Interaction、status 等 view,不解析 Harness DTO。

3.3 Turn 收口

正常完成、Harness error、子进程退出、transport close 和 cancel 最终都必须产生 state_update(idle, stopReason);错误路径先产生 _baton_error_update。Controller 按 turn ID 幂等 finalize:

  1. 持久化终态;
  2. 生成一次 Turn summary;
  3. finalize Delivery Attempt;
  4. 取消仍挂在该 Turn 上的 Interaction;
  5. 释放 driven Turn 并推进队列。

completed 但没有可见产出的空回合必须显式告警,不能表现成成功但无回复。

3.4 observed Turn

Harness 在没有用户 Input 时也可能产生后台结果。Adapter 以 Harness 来源的 running 开界, 以 idle 收界;Controller 只记账、持久化和投影,不把它放回输入队列。observed Turn 与 driven Turn 共享 Event/Projection 主路径,因此 live 与 resume 都能看到相同结果。

4. Busy 输入、steer 与 interrupt

follow-up 是 Controller 的排队策略,不是 Adapter 的另一套方法。用户在 Harness busy 时提交 第二条输入:

  1. 若目标支持且当前 turn identity 匹配,Controller 尝试 sendTurn
  2. Adapter 原生接受后,输入成为 accepted_steer,并以 delivery:"steer" 进入当前 Turn;
  3. Adapter 拒绝、原生 race 或无法安全定向时,原输入只入队一次,当前 Turn 结束后作为新 Turn 执行。

Esc 只打断当前 driven Turn。已经接受的 steer 与该 Turn 共命运:cancel 后标记 interrupted, 不静默重发;仍在 queue 的 follow-up 保留并在当前 Turn 收口后继续。cancel 请求本身不等于完成, 最终以 Harness 的 idle/cancelled 为准;超过 cancel 宽限且 transport 状态足够明确时,Controller 可以合成终态兜底。

5. Interaction 闭环

Interaction 表示“某个 requester 正在等待外部参与者给出结果”,当前 kind 包含 permission、 question 和 hook trust。完整闭环是:

Harness / Plugin request
  → kind-specific draft
  → Controller signs interactionId + requester
  → interaction.opened persisted
  → chat-tui presents to user
  → user / timeout / cancel resolves
  → interaction.resolved persisted
  → waiting Adapter or Resource reconcile continues

Harness Adapter 不自签 interaction ID,也不自行伪造 opened/resolved。resolution 就地解开等待方, 不进入 prompt queue。cancel、timeout、requester 带外解决和恢复清理都是显式 resolution。

Plugin Resource 请求用户决议时不在 Runner 中持有 Promise continuation。Baton 先持久化答案,再 重新 enqueue 原 Resource;下一次 reconcile 从持久 Interaction 读取结果。

自动 reviewer 没有向 Baton 打开 Interaction 时,审批回执是独立 ApprovalReview 审计事实, 不能伪造一组 opened/resolved;详见 审批生命周期

6. 失败、对账与恢复

6.1 无法证明投递结果

如果进程断开时 Baton 无法证明 Harness 是否接受或完成,Attempt 保留 uncertain。恢复先观察 Harness 和 Event Ledger,再决定 finalize;不能为了让队列前进而无条件重投可能已有副作用的工作。

6.2 静默悬挂

固定 wall-clock 超时会误杀合法长任务,因此 Baton 只把“长时间无事件”当作 stall signal:

  • L1:记录 stall notice,使静默可见,但不自动 finalize;
  • L2:Adapter 声明 reconcile 时查询 Harness 权威运行态;只有明确 idle 才合成终态;
  • 无对账能力或结果 unknown 时交给用户继续等待或取消。

6.3 Session 恢复与 Harness 接力

BatonSession 从 Event Ledger 重放 Projection、Attempt、Interaction 和 Context 水位。若原生 HarnessSession identity 仍可恢复,Adapter 使用它加速继续;否则新建原生 Session,并通过 Context delivery 补齐 BatonSession 历史。切换 Harness 也是同一机制,不需要复制粘贴上下文。

外部 HarnessSession 必须先由只读 Inspector 生成完整历史 Snapshot,再 adoption 为 BatonSession;此后 resume/fork 只走 BatonSession 主路径。详细边界见 Harnessresume 与 fork

7. 代码与测试锚点

  • src/controller/input.tsturn.tsattempt.ts — Input、Turn 与 Delivery Attempt owner
  • src/context/delivery.ts — Snapshot、Receipt 与 Epoch
  • src/controller/interaction.tssrc/interaction/types.ts — Interaction 生命周期
  • src/event/src/store/reduce.ts — Event 信封、append/reduce 与投影状态
  • tests/input-lifecycle.test.tstests/delivery-attempt.test.ts — 输入与投递状态迁移
  • tests/lifecycle.test.tstests/reconcile.test.ts — 终态与 stall 对账
  • tests/cancel-cascade.test.tstests/harness-initiated-turn.test.ts — Interaction 级联和 observed Turn