diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index e759acb4..7004dcfc 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -396,11 +396,15 @@ impl Session { &self, sub_id: &str, call_id: &str, - stdout: &str, - stderr: &str, - exit_code: i32, + output: &ExecToolCallOutput, is_apply_patch: bool, ) { + let ExecToolCallOutput { + stdout, + stderr, + duration, + exit_code, + } = output; // Because stdout and stderr could each be up to 100 KiB, we send // truncated versions. const MAX_STREAM_OUTPUT: usize = 5 * 1024; // 5KiB @@ -412,14 +416,15 @@ impl Session { call_id: call_id.to_string(), stdout, stderr, - success: exit_code == 0, + success: *exit_code == 0, }) } else { EventMsg::ExecCommandEnd(ExecCommandEndEvent { call_id: call_id.to_string(), stdout, stderr, - exit_code, + duration: *duration, + exit_code: *exit_code, }) }; @@ -1775,23 +1780,21 @@ async fn handle_container_exec_with_params( stdout, stderr, duration, - } = output; + } = &output; sess.notify_exec_command_end( &sub_id, &call_id, - &stdout, - &stderr, - exit_code, + &output, exec_command_context.apply_patch.is_some(), ) .await; - let is_success = exit_code == 0; + let is_success = *exit_code == 0; let content = format_exec_output( - if is_success { &stdout } else { &stderr }, - exit_code, - duration, + if is_success { stdout } else { stderr }, + *exit_code, + *duration, ); ResponseInputItem::FunctionCallOutput { @@ -1900,23 +1903,16 @@ async fn handle_sandbox_error( stdout, stderr, duration, - } = retry_output; + } = &retry_output; - sess.notify_exec_command_end( - &sub_id, - &call_id, - &stdout, - &stderr, - exit_code, - is_apply_patch, - ) - .await; + sess.notify_exec_command_end(&sub_id, &call_id, &retry_output, is_apply_patch) + .await; - let is_success = exit_code == 0; + let is_success = *exit_code == 0; let content = format_exec_output( - if is_success { &stdout } else { &stderr }, - exit_code, - duration, + if is_success { stdout } else { stderr }, + *exit_code, + *duration, ); ResponseInputItem::FunctionCallOutput { diff --git a/codex-rs/core/src/protocol.rs b/codex-rs/core/src/protocol.rs index 1bfeee56..cbb211d9 100644 --- a/codex-rs/core/src/protocol.rs +++ b/codex-rs/core/src/protocol.rs @@ -523,6 +523,8 @@ pub struct ExecCommandEndEvent { pub stderr: String, /// The command's exit code. pub exit_code: i32, + /// The duration of the command execution. + pub duration: Duration, } #[derive(Debug, Clone, Deserialize, Serialize)] diff --git a/codex-rs/core/tests/live_agent.rs b/codex-rs/core/tests/live_agent.rs index 95408e20..81b3bb2a 100644 --- a/codex-rs/core/tests/live_agent.rs +++ b/codex-rs/core/tests/live_agent.rs @@ -177,8 +177,7 @@ async fn live_shell_function_call() { match ev.msg { EventMsg::ExecCommandBegin(codex_core::protocol::ExecCommandBeginEvent { command, - call_id: _, - cwd: _, + .. }) => { assert_eq!(command, vec!["echo", MARKER]); saw_begin = true; @@ -186,8 +185,7 @@ async fn live_shell_function_call() { EventMsg::ExecCommandEnd(codex_core::protocol::ExecCommandEndEvent { stdout, exit_code, - call_id: _, - stderr: _, + .. }) => { assert_eq!(exit_code, 0, "echo returned non‑zero exit code"); assert!(stdout.contains(MARKER)); diff --git a/codex-rs/exec/src/event_processor_with_human_output.rs b/codex-rs/exec/src/event_processor_with_human_output.rs index 7393ab72..72e2f929 100644 --- a/codex-rs/exec/src/event_processor_with_human_output.rs +++ b/codex-rs/exec/src/event_processor_with_human_output.rs @@ -106,7 +106,6 @@ impl EventProcessorWithHumanOutput { struct ExecCommandBegin { command: Vec, - start_time: Instant, } struct PatchApplyBegin { @@ -228,7 +227,6 @@ impl EventProcessor for EventProcessorWithHumanOutput { call_id.clone(), ExecCommandBegin { command: command.clone(), - start_time: Instant::now(), }, ); ts_println!( @@ -244,16 +242,14 @@ impl EventProcessor for EventProcessorWithHumanOutput { call_id, stdout, stderr, + duration, exit_code, }) => { let exec_command = self.call_id_to_command.remove(&call_id); - let (duration, call) = if let Some(ExecCommandBegin { - command, - start_time, - }) = exec_command + let (duration, call) = if let Some(ExecCommandBegin { command, .. }) = exec_command { ( - format!(" in {}", format_elapsed(start_time)), + format!(" in {}", format_duration(duration)), format!("{}", escape_command(&command).style(self.bold)), ) } else { diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 31151d56..e5ebf58a 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use std::path::PathBuf; use std::sync::Arc; -use std::time::Duration; use codex_core::codex_wrapper::CodexConversation; use codex_core::codex_wrapper::init_codex; @@ -390,6 +389,7 @@ impl ChatWidget<'_> { EventMsg::ExecCommandEnd(ExecCommandEndEvent { call_id, exit_code, + duration, stdout, stderr, }) => { @@ -400,7 +400,7 @@ impl ChatWidget<'_> { exit_code, stdout, stderr, - duration: Duration::from_secs(0), + duration, }, )); }