Realtime、Review 和普通 Turn 共享同一个 Session,却不是三种相同 Task。普通 Turn 由 RegularTask 驱动 Responses 采样;Review 是父 Session 中的 ReviewTask 加受限子 Codex;Realtime 则是独立长连接状态机,只有 handoff 文本需要后台 Agent 时才进入普通 Turn 路径。
生命周期对照
| 维度 | 普通 Turn | Review | Realtime |
|---|---|---|---|
| 主执行体 | RegularTask | ReviewTask + one-shot child | RealtimeConversationManager tasks |
| 模型通道 | Responses stream | 子 Codex Responses | Realtime WS/WebRTC sideband |
| 公开开始 | TurnStarted | 当前父 Review 缺 TurnStarted | ConversationStarted/SDP/Realtime |
| 输入追加 | Steer pending input | 拒绝 Steer | audio/text/speech queues |
| 结束 | TurnComplete/Aborted | ExitedReviewMode + Turn terminal | ConversationClosed |
| 与 Agent 连接 | 本身就是 Agent Turn | 子线程结果投影 | handoff/delegation 可启动或 steer Agent |
Review 是受限子会话的投影
Review 构造专用 TurnContext:可选 review model,禁用 WebSearch、Goals 等功能,MultiAgent disabled,developer instructions 置空,保留父环境、权限和 Skills snapshot。ReviewTask 再启动 one-shot 子 Codex,approval policy强制 Never并设置 REVIEW_PROMPT。
父 Task 消费子事件:普通事件选择性转发,隐藏 assistant delta,等子 TurnComplete 后解析结构化 ReviewOutput;解析失败则把纯文本放入 fallback explanation。最后发 ExitedReviewMode item。abort 同样发退出项,但 output 为 None。
async def run_review(parent, review_turn):
child_cfg = constrain_for_review(parent.config)
child_events = await start_one_shot_child(child_cfg, review_prompt)
output = await project_until_child_terminal(child_events)
if not cancelled():
await emit_exited_review_mode(output)
源码 TODO 明确指出当前父 Review turn 依赖 spawn_task获得 TurnComplete,却没有对应公开 TurnStarted。这是现状,不应在文章中为“对称”而虚构事件。
Realtime 是 Session 级连接状态机
Realtime start准备认证、版本、voice/session config和 WebSocket/WebRTC transport,建立有界 audio/text/handoff/output channels、input task、fanout task和 stop token。Audio/Text/Speech Op 直接写 manager 的输入通道,不通过 ActiveTurn pending queue。
realtime_active 会在新 TurnContext 中取 manager running state,用 WorldState 告知 Responses 模型当前有实时会话。反方向上,普通 Agent 的 ItemStarted、text delta、ItemCompleted和 TurnComplete会被镜像到 realtime handoff,完成时清 active handoff。
async def on_realtime_handoff(text):
wrapped = render_realtime_delegation(text, transcript_tail)
await session.route_realtime_text_input(wrapped) # 新 Turn 或 steer
async def on_agent_event(event):
if realtime.running and event.is_agent_text():
await realtime.stream_handoff(event)
if event.is_turn_complete():
await realtime.handoff_complete()
await realtime.clear_active_handoff()
Realtime close 取消 stop token,等待 input task,并根据结束原因选择等待或 detach fanout,再发 ConversationClosed。它不等于 Session Shutdown;后者会调用 manager.shutdown 后继续清 ActiveTurn、进程、MCP 和持久化。
共同点只在外围生命周期
三者都使用 Session 事件发送、trace和部分持久化设施,也都必须有明确停止路径。但输入协议、模型传输和终态事件不同。设计上让 Realtime 成为旁路连接、Review 成为特殊 Task,而不是把所有东西强塞进 run_turn,避免一个循环同时承担音频时序、审查投影和代码工具反馈。
评论
登录后即可评论