From 7795203bdd05eec979773080ba1982a54728fe6c Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Thu, 13 Nov 2025 15:51:36 -0800 Subject: [PATCH] populate turn_id on exec command begin/end events --- codex-rs/core/src/tasks/user_shell.rs | 3 +++ codex-rs/core/src/tools/events.rs | 1 + codex-rs/exec/tests/event_processor_with_json_output.rs | 5 +++++ codex-rs/protocol/src/protocol.rs | 6 +++++- codex-rs/tui/src/chatwidget/tests.rs | 5 +++++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/codex-rs/core/src/tasks/user_shell.rs b/codex-rs/core/src/tasks/user_shell.rs index 5c1231fbcf..fe6107b05e 100644 --- a/codex-rs/core/src/tasks/user_shell.rs +++ b/codex-rs/core/src/tasks/user_shell.rs @@ -128,6 +128,7 @@ impl SessionTask for UserShellCommandTask { turn_context.as_ref(), EventMsg::ExecCommandEnd(ExecCommandEndEvent { call_id, + turn_id: turn_context.sub_id.clone(), stdout: String::new(), stderr: aborted_message.clone(), aggregated_output: aborted_message.clone(), @@ -144,6 +145,7 @@ impl SessionTask for UserShellCommandTask { turn_context.as_ref(), EventMsg::ExecCommandEnd(ExecCommandEndEvent { call_id: call_id.clone(), + turn_id: turn_context.sub_id.clone(), stdout: output.stdout.text.clone(), stderr: output.stderr.text.clone(), aggregated_output: output.aggregated_output.text.clone(), @@ -175,6 +177,7 @@ impl SessionTask for UserShellCommandTask { turn_context.as_ref(), EventMsg::ExecCommandEnd(ExecCommandEndEvent { call_id, + turn_id: turn_context.sub_id.clone(), stdout: exec_output.stdout.text.clone(), stderr: exec_output.stderr.text.clone(), aggregated_output: exec_output.aggregated_output.text.clone(), diff --git a/codex-rs/core/src/tools/events.rs b/codex-rs/core/src/tools/events.rs index 06a3f3f115..9cfcfb730c 100644 --- a/codex-rs/core/src/tools/events.rs +++ b/codex-rs/core/src/tools/events.rs @@ -332,6 +332,7 @@ async fn emit_exec_end( ctx.turn, EventMsg::ExecCommandEnd(ExecCommandEndEvent { call_id: ctx.call_id.to_string(), + turn_id: ctx.turn.sub_id.clone(), stdout, stderr, aggregated_output, diff --git a/codex-rs/exec/tests/event_processor_with_json_output.rs b/codex-rs/exec/tests/event_processor_with_json_output.rs index 5e2ef17dc1..5f51ff4727 100644 --- a/codex-rs/exec/tests/event_processor_with_json_output.rs +++ b/codex-rs/exec/tests/event_processor_with_json_output.rs @@ -623,6 +623,7 @@ fn exec_command_end_success_produces_completed_command_item() { "c1", EventMsg::ExecCommandBegin(ExecCommandBeginEvent { call_id: "1".to_string(), + turn_id: "turn-1".to_string(), command: vec!["bash".to_string(), "-lc".to_string(), "echo hi".to_string()], cwd: std::env::current_dir().unwrap(), parsed_cmd: Vec::new(), @@ -650,6 +651,7 @@ fn exec_command_end_success_produces_completed_command_item() { "c2", EventMsg::ExecCommandEnd(ExecCommandEndEvent { call_id: "1".to_string(), + turn_id: "turn-1".to_string(), stdout: String::new(), stderr: String::new(), aggregated_output: "hi\n".to_string(), @@ -684,6 +686,7 @@ fn exec_command_end_failure_produces_failed_command_item() { "c1", EventMsg::ExecCommandBegin(ExecCommandBeginEvent { call_id: "2".to_string(), + turn_id: "turn-1".to_string(), command: vec!["sh".to_string(), "-c".to_string(), "exit 1".to_string()], cwd: std::env::current_dir().unwrap(), parsed_cmd: Vec::new(), @@ -710,6 +713,7 @@ fn exec_command_end_failure_produces_failed_command_item() { "c2", EventMsg::ExecCommandEnd(ExecCommandEndEvent { call_id: "2".to_string(), + turn_id: "turn-1".to_string(), stdout: String::new(), stderr: String::new(), aggregated_output: String::new(), @@ -744,6 +748,7 @@ fn exec_command_end_without_begin_is_ignored() { "c1", EventMsg::ExecCommandEnd(ExecCommandEndEvent { call_id: "no-begin".to_string(), + turn_id: "turn-1".to_string(), stdout: String::new(), stderr: String::new(), aggregated_output: String::new(), diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 4705ce6fc0..58732c3d4f 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -1208,7 +1208,7 @@ pub struct ExecCommandBeginEvent { /// Identifier so this can be paired with the ExecCommandEnd event. pub call_id: String, /// Turn ID that this command belongs to. - /// Use `#[serde(default)]` for backwards compatibility. + /// Uses `#[serde(default)]` for backwards compatibility. #[serde(default)] pub turn_id: String, /// The command to be executed. @@ -1226,6 +1226,10 @@ pub struct ExecCommandBeginEvent { pub struct ExecCommandEndEvent { /// Identifier for the ExecCommandBegin that finished. pub call_id: String, + /// Turn ID that this command belongs to. + /// Uses `#[serde(default)]` for backwards compatibility. + #[serde(default)] + pub turn_id: String, /// Captured stdout pub stdout: String, /// Captured stderr diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index 217e0fb307..e9ea5813fa 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -638,6 +638,7 @@ fn begin_exec(chat: &mut ChatWidget, call_id: &str, raw_cmd: &str) { id: call_id.to_string(), msg: EventMsg::ExecCommandBegin(ExecCommandBeginEvent { call_id: call_id.to_string(), + turn_id: "turn-1".to_string(), command, cwd: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")), parsed_cmd, @@ -656,6 +657,7 @@ fn end_exec(chat: &mut ChatWidget, call_id: &str, stdout: &str, stderr: &str, ex id: call_id.to_string(), msg: EventMsg::ExecCommandEnd(ExecCommandEndEvent { call_id: call_id.to_string(), + turn_id: "turn-1".to_string(), stdout: stdout.to_string(), stderr: stderr.to_string(), aggregated_output: aggregated.clone(), @@ -1710,6 +1712,7 @@ async fn binary_size_transcript_snapshot() { id: ev.id, msg: EventMsg::ExecCommandBegin(ExecCommandBeginEvent { call_id: e.call_id.clone(), + turn_id: e.turn_id, command: e.command, cwd: e.cwd, parsed_cmd, @@ -2770,6 +2773,7 @@ fn chatwidget_exec_and_status_layout_vt100_snapshot() { id: "c1".into(), msg: EventMsg::ExecCommandBegin(ExecCommandBeginEvent { call_id: "c1".into(), + turn_id: "turn-1".into(), command: vec!["bash".into(), "-lc".into(), "rg \"Change Approved\"".into()], cwd: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")), parsed_cmd: vec![ @@ -2791,6 +2795,7 @@ fn chatwidget_exec_and_status_layout_vt100_snapshot() { id: "c1".into(), msg: EventMsg::ExecCommandEnd(ExecCommandEndEvent { call_id: "c1".into(), + turn_id: "turn-1".into(), stdout: String::new(), stderr: String::new(), aggregated_output: String::new(),