03 — 协议、Op 与 Thread / Turn / Item 模型
App-Server 的三层抽象
codex-rs/app-server/README.md 定义:
- Thread:用户与 agent 的一段对话,包含多轮 Turn。
- Turn:一轮交互,通常以用户消息开始、以 agent 产出结束;内部有多条 Item。
- Item:持久化、可重放的原子记录(用户消息、推理、工具调用、shell 输出、文件编辑等)。
该模型直接映射到 IDE 线程列表、时间线视图、审计日志,比单纯 messages[] 更易做 增量同步与断线续传。
Op:提交语义
Op 在 protocol/src/protocol.rs 中声明,节选设计要点:
207:247:codex-rs/protocol/src/protocol.rs
/// Submission operation
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
#[allow(clippy::large_enum_variant)]
#[non_exhaustive]
pub enum Op {
/// Abort current task without terminating background terminal processes.
/// This server sends [`EventMsg::TurnAborted`] in response.
Interrupt,
// ...
/// Legacy user input.
///
/// Prefer [`Op::UserTurn`] so the caller provides full turn context
/// (cwd/approval/sandbox/model/etc.) for each turn.
UserInput {
items: Vec<UserInput>,
#[serde(skip_serializing_if = "Option::is_none")]
final_output_json_schema: Option<Value>,
},
/// Similar to [`Op::UserInput`], but contains additional context required
/// for a turn of a [`crate::codex_thread::CodexThread`].
UserTurn {
items: Vec<UserInput>,
cwd: PathBuf,
approval_policy: AskForApproval,
// ...
sandbox_policy: SandboxPolicy,
model: String,设计原因(可背诵):
UserTurn携带 cwd / sandbox / approval / model`:同一 Thread 在不同回合可以改变工作目录与策略,符合「工具调用依赖环境」的真实场景;也避免全局可变配置带来的竞态。Interrupt与CleanBackgroundTerminals分离:中断当前推理/流式任务时,未必希望杀掉用户刻意留着的长期 shell;需要「停任务」与「清后台」两种语义。- Legacy
UserInput:兼容旧调用方;注释明确引导迁移到UserTurn。
CodexThread:对外 API 壳
CodexThread 包装 Codex,提供 submit(Op)、shutdown_and_wait、steer_input 等:
46:71:codex-rs/core/src/codex_thread.rs
pub struct CodexThread {
pub(crate) codex: Codex,
rollout_path: Option<PathBuf>,
out_of_band_elicitation_count: Mutex<u64>,
_watch_registration: WatchRegistration,
}
impl CodexThread {
pub async fn submit(&self, op: Op) -> CodexResult<String> {
self.codex.submit(op).await
}依据:Thread 层附加 rollout 持久化路径、文件监视、带外 elicitation 计数 等「会话级」 concern,而 Codex 专注执行循环。
延伸追问:steer_input 解决什么问题?
SteerInputError(见 codex.rs)包含:无活跃 Turn、Turn ID 不匹配、当前 Turn 不可 steer、空输入等。典型用途是 在流式生成过程中注入补充说明(类似 ChatGPT 的「编辑上次请求」但发生在 agent 执行期),需要严格的 Turn 状态机 防止错乱写入。
延伸阅读
- 04 沙箱
- 08 TUI 退出流(
Op::Shutdown与 UI 协作)