Include start times in terminal turn events (#32263)

## What changed

- Add an optional `started_at` Unix timestamp to `TurnCompleteEvent` and
  `TurnAbortedEvent`.
- Populate the timestamp from turn timing state when a turn completes or is
  aborted.
- Preserve the timestamp when synthesizing interrupted fork history and when
  importing external sessions.

## Testing

- Verify that interrupting a turn emits a `TurnAbortedEvent` with a start
  timestamp.

GitOrigin-RevId: 75b3911b95c060e5fc1843a5e293d8fe47377186
This commit is contained in:
Owen Lin
2026-07-10 20:25:03 +00:00
committed by copyberry
parent b66c25c6a3
commit bca577d69a
20 changed files with 144 additions and 7 deletions
+11
View File
@@ -486,6 +486,7 @@ async fn interrupting_regular_turn_waiting_on_startup_prewarm_emits_turn_aborted
let EventMsg::TurnAborted(TurnAbortedEvent {
turn_id,
reason,
started_at,
completed_at,
duration_ms,
}) = second.msg
@@ -494,6 +495,7 @@ async fn interrupting_regular_turn_waiting_on_startup_prewarm_emits_turn_aborted
};
assert_eq!(turn_id, Some(tc.sub_id.clone()));
assert_eq!(reason, TurnAbortReason::Interrupted);
assert!(started_at.is_some());
assert!(completed_at.is_some());
assert!(duration_ms.is_some());
}
@@ -3134,6 +3136,7 @@ async fn record_initial_history_forked_hydrates_previous_turn_settings() {
codex_protocol::protocol::TurnCompleteEvent {
turn_id,
last_agent_message: None,
started_at: None,
completed_at: None,
duration_ms: None,
time_to_first_token_ms: None,
@@ -3333,6 +3336,7 @@ async fn thread_rollback_recomputes_previous_turn_settings_and_reference_context
RolloutItem::ResponseItem(turn_one_assistant.clone()),
RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent {
turn_id: first_turn_id,
started_at: None,
last_agent_message: None,
completed_at: None,
duration_ms: None,
@@ -3362,6 +3366,7 @@ async fn thread_rollback_recomputes_previous_turn_settings_and_reference_context
RolloutItem::ResponseItem(turn_two_assistant),
RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent {
turn_id: rolled_back_turn_id,
started_at: None,
last_agent_message: None,
completed_at: None,
duration_ms: None,
@@ -3451,6 +3456,7 @@ async fn thread_rollback_restores_cleared_reference_context_item_after_compactio
RolloutItem::ResponseItem(assistant_message("turn 1 assistant")),
RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent {
turn_id: first_turn_id,
started_at: None,
last_agent_message: None,
completed_at: None,
duration_ms: None,
@@ -3475,6 +3481,7 @@ async fn thread_rollback_restores_cleared_reference_context_item_after_compactio
}),
RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent {
turn_id: compact_turn_id,
started_at: None,
last_agent_message: None,
completed_at: None,
duration_ms: None,
@@ -3507,6 +3514,7 @@ async fn thread_rollback_restores_cleared_reference_context_item_after_compactio
RolloutItem::ResponseItem(assistant_message("turn 2 assistant")),
RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent {
turn_id: rolled_back_turn_id,
started_at: None,
last_agent_message: None,
completed_at: None,
duration_ms: None,
@@ -3580,6 +3588,7 @@ async fn thread_rollback_persists_marker_and_replays_cumulatively() {
RolloutItem::ResponseItem(assistant_message("turn 1 assistant")),
RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent {
turn_id: "turn-1".to_string(),
started_at: None,
last_agent_message: None,
completed_at: None,
duration_ms: None,
@@ -3607,6 +3616,7 @@ async fn thread_rollback_persists_marker_and_replays_cumulatively() {
RolloutItem::ResponseItem(assistant_message("turn 2 assistant")),
RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent {
turn_id: "turn-2".to_string(),
started_at: None,
last_agent_message: None,
completed_at: None,
duration_ms: None,
@@ -3634,6 +3644,7 @@ async fn thread_rollback_persists_marker_and_replays_cumulatively() {
RolloutItem::ResponseItem(assistant_message("turn 3 assistant")),
RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent {
turn_id: "turn-3".to_string(),
started_at: None,
last_agent_message: None,
completed_at: None,
duration_ms: None,