diff --git a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst index 04ec7af91f..97809f7e6a 100644 Binary files a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst and b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst differ diff --git a/codex-rs/app-server-protocol/src/protocol/thread_history.rs b/codex-rs/app-server-protocol/src/protocol/thread_history.rs index 95a2bba6cd..28e7e6ffad 100644 --- a/codex-rs/app-server-protocol/src/protocol/thread_history.rs +++ b/codex-rs/app-server-protocol/src/protocol/thread_history.rs @@ -2408,12 +2408,9 @@ mod tests { source: ExecCommandSource::Agent, interaction_input: None, status: CoreCommandExecutionStatus::Completed, - stdout: Some("hello world\n".to_string()), - stderr: Some(String::new()), aggregated_output: Some("hello world\n".to_string()), exit_code: Some(0), duration: Some(Duration::from_millis(12)), - formatted_output: Some("hello world\n".to_string()), }); let events = vec![ EventMsg::TurnStarted(TurnStartedEvent { @@ -2456,12 +2453,9 @@ mod tests { parsed_cmd, source: ExecCommandSource::Agent, interaction_input: None, - stdout: "hello world\n".to_string(), - stderr: String::new(), aggregated_output: "hello world\n".to_string(), exit_code: 0, duration: Duration::from_millis(12), - formatted_output: "hello world\n".to_string(), status: CoreExecCommandStatus::Completed, }), EventMsg::TurnComplete(TurnCompleteEvent { @@ -3145,12 +3139,9 @@ mod tests { }], source: ExecCommandSource::Agent, interaction_input: None, - stdout: String::new(), - stderr: String::new(), aggregated_output: "hello world\n".into(), exit_code: 0, duration: Duration::from_millis(12), - formatted_output: String::new(), status: CoreExecCommandStatus::Completed, }), EventMsg::McpToolCallEnd(McpToolCallEndEvent { @@ -3439,12 +3430,9 @@ mod tests { parsed_cmd: vec![ParsedCommand::Unknown { cmd: "ls".into() }], source: ExecCommandSource::Agent, interaction_input: None, - stdout: String::new(), - stderr: "exec command rejected by user".into(), aggregated_output: "exec command rejected by user".into(), exit_code: -1, duration: Duration::ZERO, - formatted_output: String::new(), status: CoreExecCommandStatus::Declined, }), EventMsg::PatchApplyEnd(PatchApplyEndEvent { @@ -3833,12 +3821,9 @@ mod tests { }], source: ExecCommandSource::Agent, interaction_input: None, - stdout: "done\n".into(), - stderr: String::new(), aggregated_output: "done\n".into(), exit_code: 0, duration: Duration::from_millis(5), - formatted_output: "done\n".into(), status: CoreExecCommandStatus::Completed, }), EventMsg::TurnComplete(TurnCompleteEvent { @@ -3943,12 +3928,9 @@ mod tests { }], source: ExecCommandSource::Agent, interaction_input: None, - stdout: "done\n".into(), - stderr: String::new(), aggregated_output: "done\n".into(), exit_code: 0, duration: Duration::from_millis(5), - formatted_output: "done\n".into(), status: CoreExecCommandStatus::Completed, }), EventMsg::TurnComplete(TurnCompleteEvent { diff --git a/codex-rs/app-server-protocol/src/protocol/v2/tests.rs b/codex-rs/app-server-protocol/src/protocol/v2/tests.rs index 0ec1535c00..e299c13095 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/tests.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/tests.rs @@ -3330,12 +3330,9 @@ fn core_turn_item_into_thread_item_converts_supported_variants() { source: CoreExecCommandSource::Agent, interaction_input: None, status: CoreCommandExecutionStatus::Completed, - stdout: Some("done\n".to_string()), - stderr: Some(String::new()), aggregated_output: Some("done\n".to_string()), exit_code: Some(0), duration: Some(Duration::from_millis(5)), - formatted_output: Some("done\n".to_string()), }); assert_eq!( diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index c001365742..fa5f967090 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -1710,7 +1710,7 @@ async fn user_shell_commands_do_not_inherit_managed_network_proxy() -> anyhow::R let event = rx.recv().await.expect("channel open"); if let EventMsg::ExecCommandEnd(event) = event.msg { assert_eq!(event.exit_code, 0); - assert_eq!(event.stdout.trim(), "not-set"); + assert_eq!(event.aggregated_output.trim(), "not-set"); break; } } diff --git a/codex-rs/core/src/tasks/user_shell.rs b/codex-rs/core/src/tasks/user_shell.rs index e802122c0f..a58d3dbb59 100644 --- a/codex-rs/core/src/tasks/user_shell.rs +++ b/codex-rs/core/src/tasks/user_shell.rs @@ -21,7 +21,6 @@ use crate::session::TurnInput; use crate::session::turn_context::TurnContext; use crate::shell::Shell; use crate::state::TaskKind; -use crate::tools::format_exec_output_str; use crate::tools::runtimes::RuntimePathPrepends; #[cfg(unix)] use crate::tools::runtimes::apply_package_path_prepend; @@ -200,12 +199,9 @@ pub(crate) async fn execute_user_shell_command( source: ExecCommandSource::UserShell, interaction_input: None, status: CommandExecutionStatus::InProgress, - stdout: None, - stderr: None, aggregated_output: None, exit_code: None, duration: None, - formatted_output: None, }), ) .await; @@ -281,12 +277,9 @@ pub(crate) async fn execute_user_shell_command( source: ExecCommandSource::UserShell, interaction_input: None, status: CommandExecutionStatus::Failed, - stdout: Some(String::new()), - stderr: Some(aborted_message.clone()), aggregated_output: Some(aborted_message.clone()), exit_code: Some(-1), duration: Some(Duration::ZERO), - formatted_output: Some(aborted_message), }), ) .await; @@ -312,15 +305,9 @@ pub(crate) async fn execute_user_shell_command( } else { CommandExecutionStatus::Failed }, - stdout: Some(output.stdout.text.clone()), - stderr: Some(output.stderr.text.clone()), aggregated_output: Some(output.aggregated_output.text.clone()), exit_code: Some(output.exit_code), duration: Some(output.duration), - formatted_output: Some(format_exec_output_str( - &output, - turn_context.model_info().truncation_policy.into(), - )), }), ) .await; @@ -355,15 +342,9 @@ pub(crate) async fn execute_user_shell_command( source: ExecCommandSource::UserShell, interaction_input: None, status: CommandExecutionStatus::Failed, - stdout: Some(exec_output.stdout.text.clone()), - stderr: Some(exec_output.stderr.text.clone()), aggregated_output: Some(exec_output.aggregated_output.text.clone()), exit_code: Some(exec_output.exit_code), duration: Some(exec_output.duration), - formatted_output: Some(format_exec_output_str( - &exec_output, - turn_context.model_info().truncation_policy.into(), - )), }), ) .await; diff --git a/codex-rs/core/src/tools/events.rs b/codex-rs/core/src/tools/events.rs index 61eedddc7d..2d5262ee9b 100644 --- a/codex-rs/core/src/tools/events.rs +++ b/codex-rs/core/src/tools/events.rs @@ -34,8 +34,6 @@ use std::collections::HashMap; use std::path::PathBuf; use std::time::Duration; -use super::format_exec_output_str; - const REJECTION_MESSAGE_MAX_TOKENS: usize = 900; pub(super) fn truncate_rejection_message(message: &str) -> String { @@ -185,12 +183,9 @@ async fn emit_exec_command_begin(ctx: ToolEventCtx<'_>, exec_input: &ExecCommand source: exec_input.source, interaction_input: exec_input.interaction_input.map(str::to_owned), status: CommandExecutionStatus::InProgress, - stdout: None, - stderr: None, aggregated_output: None, exit_code: None, duration: None, - formatted_output: None, }), ) .await; @@ -511,12 +506,9 @@ impl<'a> ExecCommandInput<'a> { } struct ExecCommandResult { - stdout: String, - stderr: String, aggregated_output: String, exit_code: i32, duration: Duration, - formatted_output: String, status: ExecCommandStatus, } @@ -532,15 +524,9 @@ async fn emit_exec_stage( ToolEventStage::Success { output, .. } | ToolEventStage::Failure(ToolEventFailure::Output(output)) => { let exec_result = ExecCommandResult { - stdout: output.stdout.text.clone(), - stderr: output.stderr.text.clone(), - aggregated_output: output.aggregated_output.text.clone(), + aggregated_output: output.aggregated_output.text, exit_code: output.exit_code, duration: output.duration, - formatted_output: format_exec_output_str( - &output, - ctx.model_info.truncation_policy.into(), - ), status: if output.exit_code == 0 { ExecCommandStatus::Completed } else { @@ -552,12 +538,9 @@ async fn emit_exec_stage( ToolEventStage::Failure(ToolEventFailure::Message(message)) => { let text = message.to_string(); let exec_result = ExecCommandResult { - stdout: String::new(), - stderr: text.clone(), - aggregated_output: text.clone(), + aggregated_output: text, exit_code: -1, duration: Duration::ZERO, - formatted_output: text, status: ExecCommandStatus::Failed, }; emit_exec_end(ctx, exec_input, exec_result).await; @@ -565,12 +548,9 @@ async fn emit_exec_stage( ToolEventStage::Failure(ToolEventFailure::Rejected { message, .. }) => { let text = message.to_string(); let exec_result = ExecCommandResult { - stdout: String::new(), - stderr: text.clone(), - aggregated_output: text.clone(), + aggregated_output: text, exit_code: -1, duration: Duration::ZERO, - formatted_output: text, status: ExecCommandStatus::Declined, }; emit_exec_end(ctx, exec_input, exec_result).await; @@ -598,14 +578,11 @@ async fn emit_exec_end( cwd: exec_input.cwd.clone(), parsed_cmd: exec_input.parsed_cmd.to_vec(), source: exec_input.source, - interaction_input: exec_input.interaction_input.map(str::to_owned), + interaction_input: None, status: exec_result.status.into(), - stdout: Some(exec_result.stdout), - stderr: Some(exec_result.stderr), aggregated_output: Some(exec_result.aggregated_output), exit_code: Some(exec_result.exit_code), duration: Some(exec_result.duration), - formatted_output: Some(exec_result.formatted_output), }), ) .await; diff --git a/codex-rs/core/src/unified_exec/async_watcher_tests.rs b/codex-rs/core/src/unified_exec/async_watcher_tests.rs index d5e1b9ba3e..8443994551 100644 --- a/codex-rs/core/src/unified_exec/async_watcher_tests.rs +++ b/codex-rs/core/src/unified_exec/async_watcher_tests.rs @@ -357,13 +357,6 @@ async fn exit_watcher_waits_for_late_network_denial_before_classifying_end() -> Some("LATE_DENIAL") ) ); - assert_eq!( - item.formatted_output, - Some(codex_utils_output_truncation::formatted_truncate_text( - "LATE_DENIAL", - codex_utils_output_truncation::TruncationPolicy::Bytes(4), - )) - ); assert!( elapsed >= Duration::from_millis(10) && elapsed < TRAILING_OUTPUT_GRACE, "completion should wait for denial without falling back to the output grace: {elapsed:?}" diff --git a/codex-rs/core/tests/suite/shell_snapshot.rs b/codex-rs/core/tests/suite/shell_snapshot.rs index af6881b332..7e047b44f4 100644 --- a/codex-rs/core/tests/suite/shell_snapshot.rs +++ b/codex-rs/core/tests/suite/shell_snapshot.rs @@ -905,7 +905,7 @@ async fn shell_snapshot_v2_filters_profile_secrets_without_creating_files() -> R assert_eq!(end.exit_code, 0); assert_eq!( - normalize_newlines(&end.stdout).trim(), + normalize_newlines(&end.aggregated_output).trim(), "helper|path|policy|missing" ); } @@ -953,7 +953,7 @@ async fn shell_snapshot_v2_preserves_legacy_snapshots_for_user_shell() -> Result .await; assert_eq!(end.exit_code, 0); - assert_eq!(normalize_newlines(&end.stdout).trim(), "legacy"); + assert_eq!(normalize_newlines(&end.aggregated_output).trim(), "legacy"); Ok(()) } @@ -962,7 +962,7 @@ async fn shell_snapshot_v2_preserves_legacy_snapshots_for_user_shell() -> Result async fn linux_unified_exec_uses_shell_snapshot() -> Result<()> { let command = "echo snapshot-linux"; let run = run_snapshot_command(command).await?; - let stdout = normalize_newlines(&run.end.stdout); + let output = normalize_newlines(&run.end.aggregated_output); assert_eq!(run.begin.command.get(1).map(String::as_str), Some("-lc")); assert_eq!(run.begin.command.get(2).map(String::as_str), Some(command)); @@ -971,8 +971,8 @@ async fn linux_unified_exec_uses_shell_snapshot() -> Result<()> { assert_posix_snapshot_sections(&run.snapshot_content); assert_eq!(run.end.exit_code, 0); assert!( - stdout.contains("snapshot-linux"), - "stdout should contain snapshot marker; stdout={stdout:?}" + output.contains("snapshot-linux"), + "output should contain snapshot marker; output={output:?}" ); Ok(()) @@ -1018,7 +1018,7 @@ async fn unified_exec_snapshot_preserves_shell_environment_policy_set() -> Resul .await?; assert_eq!( - normalize_newlines(&end.stdout).trim(), + normalize_newlines(&end.aggregated_output).trim(), POLICY_SUCCESS_OUTPUT ); assert_eq!(end.exit_code, 0); @@ -1239,10 +1239,13 @@ async fn macos_unified_exec_resolves_command_from_tied_path_snapshot( assert_eq!( end.exit_code, 0, - "tied-path command failed: stderr={:?}", - end.stderr + "tied-path command failed: output={:?}", + end.aggregated_output + ); + assert_eq!( + normalize_newlines(&end.aggregated_output).trim(), + "tied-path-command" ); - assert_eq!(normalize_newlines(&end.stdout).trim(), "tied-path-command"); Ok(()) } @@ -1274,7 +1277,10 @@ async fn macos_unified_exec_uses_shell_snapshot() -> Result<()> { assert!(run.snapshot_path.starts_with(&run.codex_home)); assert_posix_snapshot_sections(&run.snapshot_content); - assert_eq!(normalize_newlines(&run.end.stdout).trim(), "snapshot-macos"); + assert_eq!( + normalize_newlines(&run.end.aggregated_output).trim(), + "snapshot-macos" + ); assert_eq!(run.end.exit_code, 0); Ok(()) @@ -1308,7 +1314,7 @@ async fn windows_unified_exec_uses_shell_snapshot() -> Result<()> { assert!(run.snapshot_content.contains("# aliases ")); assert!(run.snapshot_content.contains("# exports ")); assert_eq!( - normalize_newlines(&run.end.stdout).trim(), + normalize_newlines(&run.end.aggregated_output).trim(), "snapshot-windows" ); assert_eq!(run.end.exit_code, 0); diff --git a/codex-rs/core/tests/suite/step_settings.rs b/codex-rs/core/tests/suite/step_settings.rs index 8308c42436..5334a593b7 100644 --- a/codex-rs/core/tests/suite/step_settings.rs +++ b/codex-rs/core/tests/suite/step_settings.rs @@ -2815,8 +2815,6 @@ async fn captured_step_controls_exec_completion_and_write_stdin_output() -> Resu .await; let end = end.expect("exec completion"); - use codex_utils_output_truncation::TruncationPolicy; - use codex_utils_output_truncation::formatted_truncate_text; let requests = responses.requests(); let exec = requests[2] .function_call_output_text("exec-b") @@ -2836,13 +2834,7 @@ async fn captured_step_controls_exec_completion_and_write_stdin_output() -> Resu "{stdin}" ); assert_eq!(end.exit_code, 7); - // The formatting check needs an untruncated chunk, independent of how the executor - // aggregates output across the initial command and later stdin interactions. assert!(end.aggregated_output.contains(&output)); - assert_eq!( - end.formatted_output, - formatted_truncate_text(&end.aggregated_output, TruncationPolicy::Bytes(400)) - ); Ok(()) } diff --git a/codex-rs/core/tests/suite/unified_exec.rs b/codex-rs/core/tests/suite/unified_exec.rs index 3d95f61190..194652b926 100644 --- a/codex-rs/core/tests/suite/unified_exec.rs +++ b/codex-rs/core/tests/suite/unified_exec.rs @@ -1113,12 +1113,8 @@ async fn unified_exec_emits_output_delta_for_exec_command() -> Result<()> { ); let end_event = end_event.expect("expected command completion"); assert_eq!( - ( - end_event.exit_code, - end_event.stdout, - end_event.aggregated_output - ), - (0, "HELLO-UEXECé�".to_string(), "HELLO-UEXECé�".to_string()) + (end_event.exit_code, end_event.aggregated_output), + (0, "HELLO-UEXECé�".to_string()) ); Ok(()) } diff --git a/codex-rs/core/tests/suite/user_shell_cmd.rs b/codex-rs/core/tests/suite/user_shell_cmd.rs index 48e42a0e37..49d27cf395 100644 --- a/codex-rs/core/tests/suite/user_shell_cmd.rs +++ b/codex-rs/core/tests/suite/user_shell_cmd.rs @@ -77,15 +77,17 @@ async fn user_shell_cmd_ls_and_cat_in_temp_dir() { .unwrap(); let msg = wait_for_event(&codex, |ev| matches!(ev, EventMsg::ExecCommandEnd(_))).await; let EventMsg::ExecCommandEnd(ExecCommandEndEvent { - stdout, exit_code, .. + aggregated_output, + exit_code, + .. }) = msg else { unreachable!() }; assert_eq!(exit_code, 0); assert!( - stdout.contains(file_name), - "ls output should include {file_name}, got: {stdout:?}" + aggregated_output.contains(file_name), + "ls output should include {file_name}, got: {aggregated_output:?}" ); // 2) shell command should print the file contents verbatim @@ -99,7 +101,7 @@ async fn user_shell_cmd_ls_and_cat_in_temp_dir() { .unwrap(); let msg = wait_for_event(&codex, |ev| matches!(ev, EventMsg::ExecCommandEnd(_))).await; let EventMsg::ExecCommandEnd(ExecCommandEndEvent { - mut stdout, + mut aggregated_output, exit_code, .. }) = msg @@ -109,9 +111,9 @@ async fn user_shell_cmd_ls_and_cat_in_temp_dir() { assert_eq!(exit_code, 0); if cfg!(windows) { // Windows shells emit CRLF line endings; normalize so the assertion remains portable. - stdout = stdout.replace("\r\n", "\n"); + aggregated_output = aggregated_output.replace("\r\n", "\n"); } - assert_eq!(stdout, contents); + assert_eq!(aggregated_output, contents); } #[tokio::test] @@ -447,7 +449,7 @@ async fn user_shell_command_history_is_persisted_and_shared_with_model() -> anyh }) .await; assert_eq!(end_event.exit_code, 0); - assert_eq!(end_event.stdout.trim(), "not-set"); + assert_eq!(end_event.aggregated_output.trim(), "not-set"); let _ = wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -507,8 +509,7 @@ async fn user_shell_command_does_not_set_network_sandbox_env_var() -> anyhow::Re let ExecCommandEndEvent { exit_code, - stdout, - stderr, + aggregated_output, .. } = wait_for_event_match(&test.codex, |ev| match ev { EventMsg::ExecCommandEnd(event) => Some(event.clone()), @@ -518,9 +519,9 @@ async fn user_shell_command_does_not_set_network_sandbox_env_var() -> anyhow::Re assert_eq!( exit_code, 0, - "shell command should execute successfully. stdout=`{stdout}`, stderr=`{stderr}`", + "shell command should execute successfully. output=`{aggregated_output}`", ); - assert_eq!(stdout.trim(), "not-set"); + assert_eq!(aggregated_output.trim(), "not-set"); Ok(()) } diff --git a/codex-rs/protocol/src/items.rs b/codex-rs/protocol/src/items.rs index 0ba13300f8..0e48870650 100644 --- a/codex-rs/protocol/src/items.rs +++ b/codex-rs/protocol/src/items.rs @@ -271,12 +271,6 @@ pub struct CommandExecutionItem { pub status: CommandExecutionStatus, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] - pub stdout: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub stderr: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] pub aggregated_output: Option, #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(optional)] @@ -284,9 +278,6 @@ pub struct CommandExecutionItem { #[serde(default, skip_serializing_if = "Option::is_none")] #[ts(type = "string", optional)] pub duration: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub formatted_output: Option, } #[derive(Debug, Clone, Copy, Deserialize, Serialize, TS, JsonSchema, PartialEq, Eq)] diff --git a/codex-rs/protocol/src/legacy_events.rs b/codex-rs/protocol/src/legacy_events.rs index fb59d1a0ad..05a66f6cee 100644 --- a/codex-rs/protocol/src/legacy_events.rs +++ b/codex-rs/protocol/src/legacy_events.rs @@ -222,12 +222,9 @@ impl CommandExecutionItem { parsed_cmd: self.parsed_cmd.clone(), source: self.source, interaction_input: self.interaction_input.clone(), - stdout: self.stdout.clone().unwrap_or_default(), - stderr: self.stderr.clone().unwrap_or_default(), aggregated_output: self.aggregated_output.clone().unwrap_or_default(), exit_code: self.exit_code.unwrap_or_default(), duration: self.duration.unwrap_or_default(), - formatted_output: self.formatted_output.clone().unwrap_or_default(), status, })) } diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 2ccac2bff4..b3b5f3aaf3 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -3625,10 +3625,6 @@ pub struct ExecCommandEndEvent { #[ts(optional)] pub interaction_input: Option, - /// Captured stdout - pub stdout: String, - /// Captured stderr - pub stderr: String, /// Captured aggregated output #[serde(default)] pub aggregated_output: String, @@ -3637,8 +3633,6 @@ pub struct ExecCommandEndEvent { /// The duration of the command execution. #[ts(type = "string")] pub duration: Duration, - /// Formatted output from the command, as seen by the model. - pub formatted_output: String, /// Completion status for this command execution. pub status: ExecCommandStatus, } @@ -5598,12 +5592,9 @@ mod tests { source: ExecCommandSource::Agent, interaction_input: None, status: CommandExecutionStatus::InProgress, - stdout: None, - stderr: None, aggregated_output: None, exit_code: None, duration: None, - formatted_output: None, }), }; let completed = ItemCompletedEvent { @@ -5626,12 +5617,9 @@ mod tests { source: ExecCommandSource::Agent, interaction_input: None, status: CommandExecutionStatus::Completed, - stdout: Some("done\n".into()), - stderr: Some(String::new()), aggregated_output: Some("done\n".into()), exit_code: Some(0), duration: Some(Duration::from_millis(5)), - formatted_output: Some("done\n".into()), }), }; diff --git a/codex-rs/rollout-trace/src/protocol_event.rs b/codex-rs/rollout-trace/src/protocol_event.rs index dadc4bb0ac..b5e23153d5 100644 --- a/codex-rs/rollout-trace/src/protocol_event.rs +++ b/codex-rs/rollout-trace/src/protocol_event.rs @@ -220,12 +220,9 @@ struct ExecCommandEndTracePayload<'a> { source: ExecCommandSource, #[serde(skip_serializing_if = "Option::is_none")] interaction_input: Option<&'a str>, - stdout: &'a str, - stderr: &'a str, aggregated_output: &'a str, exit_code: i32, duration: Duration, - formatted_output: &'a str, status: &'a ExecCommandStatus, } @@ -243,12 +240,9 @@ impl<'a> From<&'a ExecCommandEndEvent> for ExecCommandEndTracePayload<'a> { parsed_cmd, source, interaction_input, - stdout, - stderr, aggregated_output, exit_code, duration, - formatted_output, status, } = event; Self { @@ -263,12 +257,9 @@ impl<'a> From<&'a ExecCommandEndEvent> for ExecCommandEndTracePayload<'a> { parsed_cmd, source: *source, interaction_input: interaction_input.as_deref(), - stdout, - stderr, aggregated_output, exit_code: *exit_code, duration: *duration, - formatted_output, status, } } diff --git a/codex-rs/rollout-trace/src/protocol_event_tests.rs b/codex-rs/rollout-trace/src/protocol_event_tests.rs index c7c53c3ef3..acd1f0231a 100644 --- a/codex-rs/rollout-trace/src/protocol_event_tests.rs +++ b/codex-rs/rollout-trace/src/protocol_event_tests.rs @@ -93,12 +93,9 @@ fn exec_command_trace_payloads_use_inferred_native_cwd() -> anyhow::Result<()> { parsed_cmd: Vec::new(), source: ExecCommandSource::UnifiedExecInteraction, interaction_input: Some("input".to_string()), - stdout: "output".to_string(), - stderr: String::new(), - aggregated_output: "output".to_string(), + aggregated_output: "combined output".to_string(), exit_code: 0, duration: Duration::from_millis(250), - formatted_output: "output".to_string(), status: ExecCommandStatus::Completed, }); @@ -138,12 +135,9 @@ fn exec_command_trace_payloads_use_inferred_native_cwd() -> anyhow::Result<()> { "parsed_cmd": [], "source": "unified_exec_interaction", "interaction_input": "input", - "stdout": "output", - "stderr": "", - "aggregated_output": "output", + "aggregated_output": "combined output", "exit_code": 0, "duration": {"secs": 0, "nanos": 250000000}, - "formatted_output": "output", "status": "completed" }) ); diff --git a/codex-rs/rollout-trace/src/reducer/tool/terminal.rs b/codex-rs/rollout-trace/src/reducer/tool/terminal.rs index cdd28ec5da..20d5a34a4e 100644 --- a/codex-rs/rollout-trace/src/reducer/tool/terminal.rs +++ b/codex-rs/rollout-trace/src/reducer/tool/terminal.rs @@ -450,9 +450,9 @@ fn parse_protocol_terminal_response(payload: ExecCommandEndPayload) -> ParsedTer terminal_id: payload.process_id, result: TerminalResult { exit_code: Some(payload.exit_code), - stdout: payload.stdout, - stderr: payload.stderr, - formatted_output: Some(payload.formatted_output), + stdout: payload.aggregated_output, + stderr: String::new(), + formatted_output: None, original_token_count: None, chunk_id: None, }, @@ -557,10 +557,9 @@ struct ExecCommandBeginPayload { #[derive(Deserialize)] struct ExecCommandEndPayload { process_id: Option, - stdout: String, - stderr: String, + #[serde(default)] + aggregated_output: String, exit_code: i32, - formatted_output: String, } #[derive(Deserialize)] diff --git a/codex-rs/rollout-trace/src/reducer/tool/terminal_tests.rs b/codex-rs/rollout-trace/src/reducer/tool/terminal_tests.rs index e51e54a740..a42f3bbd0d 100644 --- a/codex-rs/rollout-trace/src/reducer/tool/terminal_tests.rs +++ b/codex-rs/rollout-trace/src/reducer/tool/terminal_tests.rs @@ -81,10 +81,8 @@ fn exec_tool_reduces_to_terminal_operation_and_session() -> anyhow::Result<()> { "turn_id": "turn-1", "command": ["cargo", "test"], "cwd": "/repo", - "stdout": "ok\n", - "stderr": "", + "aggregated_output": "ok\n", "exit_code": 0, - "formatted_output": "ok\n", "status": "completed" }), )?; @@ -180,7 +178,7 @@ fn exec_tool_reduces_to_terminal_operation_and_session() -> anyhow::Result<()> { exit_code: Some(0), stdout: "ok\n".to_string(), stderr: String::new(), - formatted_output: Some("ok\n".to_string()), + formatted_output: None, original_token_count: None, chunk_id: None, }), diff --git a/codex-rs/thread-store/src/local/rollout_migration/legacy_event.rs b/codex-rs/thread-store/src/local/rollout_migration/legacy_event.rs index ce2e0691f6..a1481d62cd 100644 --- a/codex-rs/thread-store/src/local/rollout_migration/legacy_event.rs +++ b/codex-rs/thread-store/src/local/rollout_migration/legacy_event.rs @@ -277,16 +277,12 @@ pub(super) fn completed_item( cwd: event.cwd.clone(), parsed_cmd: event.parsed_cmd.clone(), source: event.source, - interaction_input: event.interaction_input.clone(), + interaction_input: None, status: event.status.clone().into(), - stdout: (!event.stdout.is_empty()).then(|| event.stdout.clone()), - stderr: (!event.stderr.is_empty()).then(|| event.stderr.clone()), aggregated_output: (!event.aggregated_output.is_empty()) .then(|| event.aggregated_output.clone()), exit_code: Some(event.exit_code), duration: Some(event.duration), - formatted_output: (!event.formatted_output.is_empty()) - .then(|| event.formatted_output.clone()), }), Some(event.turn_id.clone()), )), diff --git a/codex-rs/thread-store/src/local/rollout_migration_tests.rs b/codex-rs/thread-store/src/local/rollout_migration_tests.rs index d27cbd035c..c040d43a52 100644 --- a/codex-rs/thread-store/src/local/rollout_migration_tests.rs +++ b/codex-rs/thread-store/src/local/rollout_migration_tests.rs @@ -471,6 +471,7 @@ async fn migration_projects_explicit_and_implicit_legacy_completed_items() { let reasoning: serde_json::Value = serde_json::from_slice(&items.items[1].item_json).expect("parse projected reasoning"); assert_eq!(command["type"], "commandExecution"); + assert_eq!(command["aggregatedOutput"], "ok"); assert_eq!(reasoning["type"], "reasoning"); assert_eq!(reasoning["summary"], json!(["summary"])); assert_eq!(reasoning["content"], json!(["raw"]));