diff --git a/codex-rs/app-server-client/src/lib.rs b/codex-rs/app-server-client/src/lib.rs index 39768820de..7ff1322d72 100644 --- a/codex-rs/app-server-client/src/lib.rs +++ b/codex-rs/app-server-client/src/lib.rs @@ -1061,6 +1061,8 @@ mod tests { status: codex_app_server_protocol::TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }) } @@ -1835,6 +1837,8 @@ mod tests { status: codex_app_server_protocol::TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, } ) ) diff --git a/codex-rs/app-server-protocol/schema/json/ServerNotification.json b/codex-rs/app-server-protocol/schema/json/ServerNotification.json index b8b539a03b..251327a560 100644 --- a/codex-rs/app-server-protocol/schema/json/ServerNotification.json +++ b/codex-rs/app-server-protocol/schema/json/ServerNotification.json @@ -3566,6 +3566,19 @@ }, "TurnCompletedNotification": { "properties": { + "completedAt": { + "description": "Unix timestamp (in seconds) when the turn completed.", + "format": "int64", + "type": "integer" + }, + "durationMs": { + "description": "Duration between turn start and completion in milliseconds, if known.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, "threadId": { "type": "string" }, @@ -3574,6 +3587,7 @@ } }, "required": [ + "completedAt", "threadId", "turn" ], @@ -3680,6 +3694,11 @@ }, "TurnStartedNotification": { "properties": { + "createdAt": { + "description": "Unix timestamp (in seconds) when the turn started.", + "format": "int64", + "type": "integer" + }, "threadId": { "type": "string" }, @@ -3688,6 +3707,7 @@ } }, "required": [ + "createdAt", "threadId", "turn" ], diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index a589903032..acc274aaff 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -14364,6 +14364,19 @@ "TurnCompletedNotification": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { + "completedAt": { + "description": "Unix timestamp (in seconds) when the turn completed.", + "format": "int64", + "type": "integer" + }, + "durationMs": { + "description": "Duration between turn start and completion in milliseconds, if known.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, "threadId": { "type": "string" }, @@ -14372,6 +14385,7 @@ } }, "required": [ + "completedAt", "threadId", "turn" ], @@ -14640,6 +14654,11 @@ "TurnStartedNotification": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { + "createdAt": { + "description": "Unix timestamp (in seconds) when the turn started.", + "format": "int64", + "type": "integer" + }, "threadId": { "type": "string" }, @@ -14648,6 +14667,7 @@ } }, "required": [ + "createdAt", "threadId", "turn" ], diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index f041f8aae8..2421630d43 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -12219,6 +12219,19 @@ "TurnCompletedNotification": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { + "completedAt": { + "description": "Unix timestamp (in seconds) when the turn completed.", + "format": "int64", + "type": "integer" + }, + "durationMs": { + "description": "Duration between turn start and completion in milliseconds, if known.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, "threadId": { "type": "string" }, @@ -12227,6 +12240,7 @@ } }, "required": [ + "completedAt", "threadId", "turn" ], @@ -12495,6 +12509,11 @@ "TurnStartedNotification": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { + "createdAt": { + "description": "Unix timestamp (in seconds) when the turn started.", + "format": "int64", + "type": "integer" + }, "threadId": { "type": "string" }, @@ -12503,6 +12522,7 @@ } }, "required": [ + "createdAt", "threadId", "turn" ], diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json index 770cc920cf..3780541077 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json @@ -1559,6 +1559,19 @@ } }, "properties": { + "completedAt": { + "description": "Unix timestamp (in seconds) when the turn completed.", + "format": "int64", + "type": "integer" + }, + "durationMs": { + "description": "Duration between turn start and completion in milliseconds, if known.", + "format": "int64", + "type": [ + "integer", + "null" + ] + }, "threadId": { "type": "string" }, @@ -1567,6 +1580,7 @@ } }, "required": [ + "completedAt", "threadId", "turn" ], diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json index 761ddc9a62..94af685a0b 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json @@ -1559,6 +1559,11 @@ } }, "properties": { + "createdAt": { + "description": "Unix timestamp (in seconds) when the turn started.", + "format": "int64", + "type": "integer" + }, "threadId": { "type": "string" }, @@ -1567,6 +1572,7 @@ } }, "required": [ + "createdAt", "threadId", "turn" ], diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/TurnCompletedNotification.ts b/codex-rs/app-server-protocol/schema/typescript/v2/TurnCompletedNotification.ts index e1b151bfa7..fbe9e11b5a 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/TurnCompletedNotification.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/TurnCompletedNotification.ts @@ -3,4 +3,12 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { Turn } from "./Turn"; -export type TurnCompletedNotification = { threadId: string, turn: Turn, }; +export type TurnCompletedNotification = { threadId: string, turn: Turn, +/** + * Unix timestamp (in seconds) when the turn completed. + */ +completedAt: number, +/** + * Duration between turn start and completion in milliseconds, if known. + */ +durationMs: number | null, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/TurnStartedNotification.ts b/codex-rs/app-server-protocol/schema/typescript/v2/TurnStartedNotification.ts index 34f71b2465..8c31149506 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/TurnStartedNotification.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/TurnStartedNotification.ts @@ -3,4 +3,8 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { Turn } from "./Turn"; -export type TurnStartedNotification = { threadId: string, turn: Turn, }; +export type TurnStartedNotification = { threadId: string, turn: Turn, +/** + * Unix timestamp (in seconds) when the turn started. + */ +createdAt: number, }; diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 82b568515c..538293f1f5 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -5043,6 +5043,9 @@ pub struct ThreadNameUpdatedNotification { pub struct TurnStartedNotification { pub thread_id: String, pub turn: Turn, + /// Unix timestamp (in seconds) when the turn started. + #[ts(type = "number")] + pub created_at: i64, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] @@ -5069,6 +5072,12 @@ pub struct Usage { pub struct TurnCompletedNotification { pub thread_id: String, pub turn: Turn, + /// Unix timestamp (in seconds) when the turn completed. + #[ts(type = "number")] + pub completed_at: i64, + /// Duration between turn start and completion in milliseconds, if known. + #[ts(type = "number | null")] + pub duration_ms: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] diff --git a/codex-rs/app-server/src/bespoke_event_handling.rs b/codex-rs/app-server/src/bespoke_event_handling.rs index 78c60b0aee..6e288da81e 100644 --- a/codex-rs/app-server/src/bespoke_event_handling.rs +++ b/codex-rs/app-server/src/bespoke_event_handling.rs @@ -141,6 +141,8 @@ use std::convert::TryFrom; use std::path::Path; use std::path::PathBuf; use std::sync::Arc; +use std::time::SystemTime; +use std::time::UNIX_EPOCH; use tokio::sync::Mutex; use tokio::sync::oneshot; use tracing::error; @@ -289,6 +291,7 @@ pub(crate) async fn apply_bespoke_event_handling( let notification = TurnStartedNotification { thread_id: conversation_id.to_string(), turn, + created_at: set_turn_started_at(&thread_state).await, }; outgoing .send_server_notification(ServerNotification::TurnStarted(notification)) @@ -1947,8 +1950,10 @@ async fn emit_turn_completed_with_status( event_turn_id: String, status: TurnStatus, error: Option, + started_at_ms: Option, outgoing: &ThreadScopedOutgoingMessageSender, ) { + let completed_at_ms = now_unix_timestamp_millis(); let notification = TurnCompletedNotification { thread_id: conversation_id.to_string(), turn: Turn { @@ -1957,6 +1962,9 @@ async fn emit_turn_completed_with_status( error, status, }, + completed_at: completed_at_ms / 1000, + duration_ms: started_at_ms + .map(|started_at_ms| completed_at_ms.saturating_sub(started_at_ms)), }; outgoing .send_server_notification(ServerNotification::TurnCompleted(notification)) @@ -2105,13 +2113,22 @@ async fn handle_turn_complete( thread_state: &Arc>, ) { let turn_summary = find_and_remove_turn_summary(conversation_id, thread_state).await; + let started_at_ms = turn_summary.started_at_ms; let (status, error) = match turn_summary.last_error { Some(error) => (TurnStatus::Failed, Some(error)), None => (TurnStatus::Completed, None), }; - emit_turn_completed_with_status(conversation_id, event_turn_id, status, error, outgoing).await; + emit_turn_completed_with_status( + conversation_id, + event_turn_id, + status, + error, + started_at_ms, + outgoing, + ) + .await; } async fn handle_turn_interrupted( @@ -2120,18 +2137,33 @@ async fn handle_turn_interrupted( outgoing: &ThreadScopedOutgoingMessageSender, thread_state: &Arc>, ) { - find_and_remove_turn_summary(conversation_id, thread_state).await; + let turn_summary = find_and_remove_turn_summary(conversation_id, thread_state).await; emit_turn_completed_with_status( conversation_id, event_turn_id, TurnStatus::Interrupted, /*error*/ None, + turn_summary.started_at_ms, outgoing, ) .await; } +async fn set_turn_started_at(thread_state: &Arc>) -> i64 { + let started_at_ms = now_unix_timestamp_millis(); + let mut state = thread_state.lock().await; + state.turn_summary.started_at_ms = Some(started_at_ms); + started_at_ms / 1000 +} + +fn now_unix_timestamp_millis() -> i64 { + let duration = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default(); + i64::try_from(duration.as_millis()).unwrap_or(i64::MAX) +} + async fn handle_thread_rollback_failed( _conversation_id: ThreadId, message: String, diff --git a/codex-rs/app-server/src/in_process.rs b/codex-rs/app-server/src/in_process.rs index eda2c75da8..c2d535a126 100644 --- a/codex-rs/app-server/src/in_process.rs +++ b/codex-rs/app-server/src/in_process.rs @@ -824,6 +824,8 @@ mod tests { status: TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }) )); } diff --git a/codex-rs/app-server/src/thread_state.rs b/codex-rs/app-server/src/thread_state.rs index be5478dd51..e7af824009 100644 --- a/codex-rs/app-server/src/thread_state.rs +++ b/codex-rs/app-server/src/thread_state.rs @@ -44,6 +44,7 @@ pub(crate) enum ThreadListenerCommand { /// Per-conversation accumulation of the latest states e.g. error message while a turn runs. #[derive(Default, Clone)] pub(crate) struct TurnSummary { + pub(crate) started_at_ms: Option, pub(crate) file_change_started: HashSet, pub(crate) command_execution_started: HashSet, pub(crate) last_error: Option, diff --git a/codex-rs/exec/src/event_processor_with_human_output_tests.rs b/codex-rs/exec/src/event_processor_with_human_output_tests.rs index 2b625dd564..18d08f3bcd 100644 --- a/codex-rs/exec/src/event_processor_with_human_output_tests.rs +++ b/codex-rs/exec/src/event_processor_with_human_output_tests.rs @@ -157,6 +157,8 @@ fn turn_completed_recovers_final_message_from_turn_items() { let status = processor.process_server_notification(ServerNotification::TurnCompleted( codex_app_server_protocol::TurnCompletedNotification { thread_id: "thread-1".to_string(), + completed_at: 0, + duration_ms: None, turn: Turn { id: "turn-1".to_string(), items: vec![ThreadItem::AgentMessage { @@ -201,6 +203,8 @@ fn turn_completed_overwrites_stale_final_message_from_turn_items() { let status = processor.process_server_notification(ServerNotification::TurnCompleted( codex_app_server_protocol::TurnCompletedNotification { thread_id: "thread-1".to_string(), + completed_at: 0, + duration_ms: None, turn: Turn { id: "turn-1".to_string(), items: vec![ThreadItem::AgentMessage { @@ -246,6 +250,8 @@ fn turn_completed_preserves_streamed_final_message_when_turn_items_are_empty() { let status = processor.process_server_notification(ServerNotification::TurnCompleted( codex_app_server_protocol::TurnCompletedNotification { thread_id: "thread-1".to_string(), + completed_at: 0, + duration_ms: None, turn: Turn { id: "turn-1".to_string(), items: Vec::new(), @@ -286,6 +292,8 @@ fn turn_failed_clears_stale_final_message() { let status = processor.process_server_notification(ServerNotification::TurnCompleted( codex_app_server_protocol::TurnCompletedNotification { thread_id: "thread-1".to_string(), + completed_at: 0, + duration_ms: None, turn: Turn { id: "turn-1".to_string(), items: Vec::new(), @@ -327,6 +335,8 @@ fn turn_interrupted_clears_stale_final_message() { let status = processor.process_server_notification(ServerNotification::TurnCompleted( codex_app_server_protocol::TurnCompletedNotification { thread_id: "thread-1".to_string(), + completed_at: 0, + duration_ms: None, turn: Turn { id: "turn-1".to_string(), items: Vec::new(), diff --git a/codex-rs/exec/src/event_processor_with_jsonl_output_tests.rs b/codex-rs/exec/src/event_processor_with_jsonl_output_tests.rs index ffb4d1ed01..1f8a00b579 100644 --- a/codex-rs/exec/src/event_processor_with_jsonl_output_tests.rs +++ b/codex-rs/exec/src/event_processor_with_jsonl_output_tests.rs @@ -29,6 +29,8 @@ fn failed_turn_does_not_overwrite_output_last_message_file() { let status = processor.process_server_notification(ServerNotification::TurnCompleted( codex_app_server_protocol::TurnCompletedNotification { thread_id: "thread-1".to_string(), + completed_at: 0, + duration_ms: None, turn: codex_app_server_protocol::Turn { id: "turn-1".to_string(), items: Vec::new(), diff --git a/codex-rs/exec/src/lib.rs b/codex-rs/exec/src/lib.rs index 5a396a9810..5609fd0344 100644 --- a/codex-rs/exec/src/lib.rs +++ b/codex-rs/exec/src/lib.rs @@ -717,6 +717,7 @@ async fn run_exec_session(args: ExecRunArgs) -> anyhow::Result<()> { TurnStartedNotification { thread_id: response.review_thread_id.clone(), turn: response.turn.clone(), + created_at: 0, }, )); let task_id = response.turn.id; 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 5491e895e2..ed28aa8c85 100644 --- a/codex-rs/exec/tests/event_processor_with_json_output.rs +++ b/codex-rs/exec/tests/event_processor_with_json_output.rs @@ -145,6 +145,7 @@ fn turn_started_emits_turn_started_event() { status: TurnStatus::InProgress, error: None, }, + created_at: 0, })); assert_eq!( @@ -1067,6 +1068,8 @@ fn plan_update_emits_started_then_updated_then_completed() { status: TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }, )); assert_eq!( @@ -1123,6 +1126,8 @@ fn plan_update_after_completion_starts_new_todo_list_with_new_id() { status: TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }, )); @@ -1202,6 +1207,8 @@ fn token_usage_update_is_emitted_on_turn_completion() { status: TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }, )); assert_eq!( @@ -1237,6 +1244,8 @@ fn turn_completion_recovers_final_message_from_turn_items() { status: TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }, )); @@ -1311,6 +1320,8 @@ fn turn_completion_reconciles_started_items_from_turn_items() { status: TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }, )); @@ -1368,6 +1379,8 @@ fn turn_completion_overwrites_stale_final_message_from_turn_items() { status: TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }, )); @@ -1408,6 +1421,8 @@ fn turn_completion_preserves_streamed_final_message_when_turn_items_are_empty() status: TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }, )); @@ -1456,6 +1471,8 @@ fn failed_turn_clears_stale_final_message() { codex_error_info: None, }), }, + completed_at: 0, + duration_ms: None, }, )); @@ -1479,6 +1496,8 @@ fn turn_completion_falls_back_to_final_plan_text() { status: TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }, )); @@ -1527,6 +1546,8 @@ fn turn_failure_prefers_structured_error_message() { status: TurnStatus::Failed, error: None, }, + completed_at: 0, + duration_ms: None, }, )); assert_eq!( diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index e262b55a31..759bf52c7c 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -9191,6 +9191,7 @@ guardian_approval = true ServerNotification::TurnStarted(TurnStartedNotification { thread_id: thread_id.to_string(), turn: test_turn(turn_id, TurnStatus::InProgress, Vec::new()), + created_at: 0, }) } @@ -9202,6 +9203,8 @@ guardian_approval = true ServerNotification::TurnCompleted(TurnCompletedNotification { thread_id: thread_id.to_string(), turn: test_turn(turn_id, status, Vec::new()), + completed_at: 0, + duration_ms: None, }) } diff --git a/codex-rs/tui/src/app/app_server_adapter.rs b/codex-rs/tui/src/app/app_server_adapter.rs index ef5a061e32..3a994353b8 100644 --- a/codex-rs/tui/src/app/app_server_adapter.rs +++ b/codex-rs/tui/src/app/app_server_adapter.rs @@ -1104,6 +1104,8 @@ mod tests { status: TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }), ) .expect("notification should bridge"); @@ -1316,6 +1318,8 @@ mod tests { status: TurnStatus::Interrupted, error: None, }, + completed_at: 0, + duration_ms: None, }), ) .expect("notification should bridge"); @@ -1352,6 +1356,8 @@ mod tests { additional_details: None, }), }, + completed_at: 0, + duration_ms: None, }), ) .expect("notification should bridge"); diff --git a/codex-rs/tui/src/app/pending_interactive_replay.rs b/codex-rs/tui/src/app/pending_interactive_replay.rs index 63c8fe1249..408e4d0521 100644 --- a/codex-rs/tui/src/app/pending_interactive_replay.rs +++ b/codex-rs/tui/src/app/pending_interactive_replay.rs @@ -677,6 +677,8 @@ mod tests { status: TurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }) } diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index 02429e9d9b..63b201d111 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -5911,6 +5911,8 @@ impl ChatWidget { status, error, }, + completed_at: 0, + duration_ms: None, }, Some(replay_kind), ); diff --git a/codex-rs/tui/src/chatwidget/tests/app_server.rs b/codex-rs/tui/src/chatwidget/tests/app_server.rs index 2cabed2cc8..a5d1a706fd 100644 --- a/codex-rs/tui/src/chatwidget/tests/app_server.rs +++ b/codex-rs/tui/src/chatwidget/tests/app_server.rs @@ -94,6 +94,7 @@ async fn live_app_server_turn_completed_clears_working_status_after_answer_item( status: AppServerTurnStatus::InProgress, error: None, }, + created_at: 0, }), /*replay_kind*/ None, ); @@ -133,6 +134,8 @@ async fn live_app_server_turn_completed_clears_working_status_after_answer_item( status: AppServerTurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }), /*replay_kind*/ None, ); @@ -416,6 +419,7 @@ async fn live_app_server_failed_turn_does_not_duplicate_error_history() { status: AppServerTurnStatus::InProgress, error: None, }, + created_at: 0, }), /*replay_kind*/ None, ); @@ -451,6 +455,8 @@ async fn live_app_server_failed_turn_does_not_duplicate_error_history() { additional_details: None, }), }, + completed_at: 0, + duration_ms: None, }), /*replay_kind*/ None, ); @@ -472,6 +478,7 @@ async fn live_app_server_stream_recovery_restores_previous_status_header() { status: AppServerTurnStatus::InProgress, error: None, }, + created_at: 0, }), /*replay_kind*/ None, ); @@ -526,6 +533,7 @@ async fn live_app_server_server_overloaded_error_renders_warning() { status: AppServerTurnStatus::InProgress, error: None, }, + created_at: 0, }), /*replay_kind*/ None, ); diff --git a/codex-rs/tui/src/chatwidget/tests/history_replay.rs b/codex-rs/tui/src/chatwidget/tests/history_replay.rs index 58993d67e8..5fc1471f5d 100644 --- a/codex-rs/tui/src/chatwidget/tests/history_replay.rs +++ b/codex-rs/tui/src/chatwidget/tests/history_replay.rs @@ -537,6 +537,7 @@ async fn replayed_retryable_app_server_error_keeps_turn_running() { status: AppServerTurnStatus::InProgress, error: None, }, + created_at: 0, }), Some(ReplayKind::ThreadSnapshot), ); @@ -687,6 +688,7 @@ async fn live_reasoning_summary_is_not_rendered_twice_when_item_completes() { status: AppServerTurnStatus::InProgress, error: None, }, + created_at: 0, }), /*replay_kind*/ None, ); diff --git a/codex-rs/tui/src/chatwidget/tests/plan_mode.rs b/codex-rs/tui/src/chatwidget/tests/plan_mode.rs index 265339f5d1..7b2c5d8eb6 100644 --- a/codex-rs/tui/src/chatwidget/tests/plan_mode.rs +++ b/codex-rs/tui/src/chatwidget/tests/plan_mode.rs @@ -851,6 +851,7 @@ async fn submit_user_message_queues_while_compaction_turn_is_running() { status: AppServerTurnStatus::InProgress, error: None, }, + created_at: 0, }), /*replay_kind*/ None, ); @@ -894,6 +895,8 @@ async fn submit_user_message_queues_while_compaction_turn_is_running() { status: AppServerTurnStatus::Completed, error: None, }, + completed_at: 0, + duration_ms: None, }), /*replay_kind*/ None, );