SessionTask 是一次 Turn 的执行策略,不是 Tokio Task 本身。真正的 Tokio Task 由 Session 统一创建;Regular、Review、Compact 和 UserShell 只提供“怎样运行、怎样在取消后做专用收尾”。这层间接性让终态、统计、Rollout 和 ActiveTurn 清理集中在同一处。
两个 Task 概念必须分开
| 名称 | 含义 |
|---|---|
SessionTask | Codex 业务策略 trait |
AnySessionTask | 把 trait 的 async 返回装箱后用于动态分派 |
| Tokio task | tokio::spawn 创建的实际异步执行单元 |
RunningTask | 保存策略对象、Tokio handle、Token 和 TurnContext 的运行记录 |
SessionTask 的接口刻意很小:kind() 用于状态、Steer 和遥测,span_name() 用于 trace,run() 返回可选最终消息或错误,abort() 提供取消后的专用清理。AnySessionTask 用 boxed future 消除泛型,使 RunningTask 可以保存 Arc<dyn AnySessionTask>。
class SessionTask(Protocol):
def kind(self) -> TaskKind: ...
def span_name(self) -> str: ...
async def run(session, turn, input, cancel) -> Optional[str]: ...
async def abort(session, turn) -> None: pass
async def start_task(task, turn, input):
cancel = CancellationToken()
done = Notify()
handle = tokio_spawn(run_and_finish(task, turn, input, cancel, done))
active_turn.task = RunningTask(task, handle, cancel, turn, done)
四类工作怎样落在这个壳里
RegularTask 的 kind 是 Regular,真正运行多轮 run_turn。CompactTask 根据 feature/provider 选择 token-budget、本地、remote 或 remote-v2 压缩。ReviewTask 启动受限制的一次性子 Codex,过滤和重投影事件,并在正常或 abort 时退出 Review Mode。
UserShell 值得单独说明:它有 SessionTask 实现和统一终态外壳,但在 TaskKind 层归入 Regular,而不是新增 UserShell 枚举。它不经过模型采样,直接发命令项事件、执行用户命令并持久化输出。这说明 TaskKind 是客户端/生命周期需要的粗分类,不是每个实现类型的一一枚举。
spawn_task 与 start_task 的区别
spawn_task 是“替换式启动”:先以 Replaced 原因 abort 旧任务、清连接器选择,再调用 start_task。start_task 假定调用者已经满足单主任务条件,负责记录起始时间和起始 Token、吸收 mailbox 输入、发 turn-start lifecycle、创建 CancellationToken 与 Tokio handle,并把 RunningTask 写入 ActiveTurn。
async def spawn_task(new_task):
await abort_all_tasks(reason=REPLACED)
await clear_connector_selection()
await start_task(new_task)
async def run_and_finish(task, ctx, cancel, done):
result = await task.run(ctx, cancel.child_token())
await session.flush_rollout()
if not cancel.is_cancelled():
await session.on_task_finished(ctx, result)
done.notify_waiters()
先 flush 再进入统一完成处理,保证普通 items 在终态计算前尽量落盘。取消者若已经拿走 ActiveTurn 并取消 token,后台 task 不再自己发终态,避免与 abort 路径竞争。
为什么 Review 需要覆盖 abort
多数 Task 的默认 abort 是空操作,因为取消 token 和中止 handle 已足够。ReviewTask 还向父 UI 投影 EnteredReviewMode;若中断时不发退出语义,界面会永久留在审查模式。因此它覆写 abort,调用 exit_review_mode(..., None)。
评论
登录后即可评论