先看全链路
下面这条路径不是每种子命令的唯一分支,而是交互式 Coding Agent 主路径的教学压缩。实际代码还包含恢复、review、compact、MCP、协作等分支。
sequenceDiagram autonumber actor U as User participant CLI as codex-cli participant TM as ThreadManager participant S as Session participant T as run_turn participant API as Model API participant TR as Tool runtime participant OS as Sandbox / OS U->>CLI: codex + user input CLI->>TM: spawn_thread(config) TM->>S: Session::spawn S-->>TM: CodexThread + initial events CLI->>S: Op::UserInput S->>T: start RegularTask T->>T: build_prompt(context, tools) T->>API: streaming sampling request API-->>T: function_call(shell) T->>TR: dispatch ToolInvocation TR->>OS: approval / sandbox / execute OS-->>TR: stdout + exit status TR-->>T: tool output T->>API: follow-up sampling API-->>T: function_call(apply_patch) T->>TR: dispatch patch TR->>OS: verify + write OS-->>T: patch result T->>API: follow-up sampling API-->>T: final assistant message T-->>S: TurnComplete S-->>CLI: Event stream CLI-->>U: diff, validation, summary
1. 二进制入口决定运行表面
Rust CLI 的 main 进入 cli_main,解析子命令和配置后分流到 TUI、非交互 exec、MCP、App Server 等模式。默认交互路径进入 TUI。
2. ThreadManager 组装会话依赖
ThreadManager 负责基于配置创建 Thread,并把认证、模型、工具服务等依赖交给 Session。它还处理恢复、fork 等线程级操作。
3. Session::spawn 启动提交循环
Session 初始化 Context、状态和通道后,后台启动 submission_loop。调用方得到的不是“最终答案 future”,而是一个能持续提交 Op、读取 Event 的 CodexThread。
4. 用户输入变成 Op
界面通过 CodexThread::submit 发送带 id 的 Op::UserInput。Session 的提交循环根据 Op 类型启动任务或处理控制信号。
5. RegularTask 进入 run_turn
一个普通用户任务由 Task 基础设施承载,最终进入 run_turn。这里捕获本轮 Context,加载可用 skills/plugins,构建输入并循环采样。
6. build_prompt 形成模型请求
模型看到的是结构化历史、基础指令、工具定义和参数,而不是整个 Session 对象。随后 run_sampling_request 负责流式请求、重试与响应处理。
7. 输出 item 触发工具 future
当流中完成一个 function call,handle_output_item_done 将其转成 ToolCall,记录模型消息,排入工具执行,并让本轮知道还需要 follow-up。
8. Router → Registry → Orchestrator → Handler
路由层解释 payload,注册表找到 handler,编排器插入批准和沙箱,最后具体 handler 调用操作系统或其他服务。
9. 结果回到 Context,再次采样
工具输出与 call id 配对后进入历史。只要还有待执行工具或需要后续推理,run_turn 会再次请求模型。最终 assistant 消息结束本轮。
10. Event 让界面重建过程
整个过程中,命令开始、输出增量、Patch、审批和 Turn 完成都会通过事件通道返回。CLI/TUI 负责呈现,而不是重新实现 Agent Loop。
源码可证实 事件类型以本教程冻结 commit 的 protocol.rs::EventMsg 为准。
调试时从哪里切入
| 症状 | 第一落点 |
|---|---|
| 子命令或参数不对 | cli/src/main.rs |
| 会话创建/恢复问题 | thread_manager.rs |
| 输入没触发任务 | session/mod.rs submission loop |
| 模型不断循环或早停 | session/turn.rs |
| 工具名字/参数不对 | tools/router.rs |
| 审批/沙箱行为不对 | tools/orchestrator.rs |
| UI 漏状态 | protocol.rs::EventMsg + 消费端 |
下一章拆开调用链中最重要的控制面:Sandbox 与 Approval。