From ac37f98c730391c21b02e55d07cbb7a2ca2b1738 Mon Sep 17 00:00:00 2001 From: cooper-oai Date: Mon, 9 Nov 2026 19:10:55 +0000 Subject: [PATCH] Reset app-server turn summaries when a turn starts (#60434) ## Why An error recorded before a turn starts can cause a successful turn to be reported as failed. ## What changed Reset `TurnSummary` on `TurnStarted`, preserving the new turn's `started_at` timestamp while clearing accumulated errors, command start times, and the last agent message. ## Testing Extend turn completion tests to cover clearing an error recorded before turn start and retaining an error recorded during the turn. GitOrigin-RevId: 19989b55d20df7b9a265bd0a1dfb3f00b6e8a9c5 --- .../app-server/src/bespoke_event_handling.rs | 23 +++++++++++++++++++ codex-rs/app-server/src/thread_state.rs | 5 +++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/codex-rs/app-server/src/bespoke_event_handling.rs b/codex-rs/app-server/src/bespoke_event_handling.rs index 41e0b49f02..485f8e1445 100644 --- a/codex-rs/app-server/src/bespoke_event_handling.rs +++ b/codex-rs/app-server/src/bespoke_event_handling.rs @@ -3492,6 +3492,17 @@ mod tests { ThreadId::new(), ); let thread_state = new_thread_state(); + handle_error( + conversation_id, + TurnError { + misalignment: None, + message: "conversation is not running".to_string(), + codex_error_info: Some(V2CodexErrorInfo::Other), + additional_details: None, + }, + &thread_state, + ) + .await; let event = turn_complete_event(&event_turn_id); { let mut state = thread_state.lock().await; @@ -3648,6 +3659,18 @@ mod tests { let conversation_id = ThreadId::new(); let event_turn_id = "complete_err1".to_string(); let thread_state = new_thread_state(); + thread_state.lock().await.track_current_turn_event( + &event_turn_id, + &EventMsg::TurnStarted(codex_protocol::protocol::TurnStartedEvent { + turn_attribution: None, + turn_id: event_turn_id.clone(), + root_turn_id: None, + trace_id: None, + started_at: Some(42), + model_context_window: None, + collaboration_mode_kind: Default::default(), + }), + ); handle_error( conversation_id, TurnError { diff --git a/codex-rs/app-server/src/thread_state.rs b/codex-rs/app-server/src/thread_state.rs index a712ee2f47..ab0464f2f8 100644 --- a/codex-rs/app-server/src/thread_state.rs +++ b/codex-rs/app-server/src/thread_state.rs @@ -235,7 +235,10 @@ impl ThreadState { pub(crate) fn track_current_turn_event(&mut self, event_turn_id: &str, event: &EventMsg) { if let EventMsg::TurnStarted(payload) = event { - self.turn_summary.started_at = payload.started_at; + self.turn_summary = TurnSummary { + started_at: payload.started_at, + ..Default::default() + }; } if let EventMsg::ItemCompleted(payload) = event && let CoreTurnItem::AgentMessage(item) = &payload.item