mirror of
https://github.com/openai/codex.git
synced 2026-10-21 17:48:44 +00:00
[codex-analytics] guardian review TTFT plumbing and emission
This commit is contained in:
@@ -1332,6 +1332,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -1406,6 +1407,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
];
|
||||
|
||||
@@ -1729,6 +1731,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -2235,6 +2238,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
EventMsg::TurnStarted(TurnStartedEvent {
|
||||
turn_id: "turn-b".into(),
|
||||
@@ -2272,6 +2276,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -2324,6 +2329,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
EventMsg::TurnStarted(TurnStartedEvent {
|
||||
turn_id: "turn-b".into(),
|
||||
@@ -2361,6 +2367,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -2535,6 +2542,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
EventMsg::TurnStarted(TurnStartedEvent {
|
||||
turn_id: "turn-b".into(),
|
||||
@@ -2553,6 +2561,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
EventMsg::AgentMessage(AgentMessageEvent {
|
||||
message: "still in b".into(),
|
||||
@@ -2564,6 +2573,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -2598,6 +2608,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
EventMsg::TurnStarted(TurnStartedEvent {
|
||||
turn_id: "turn-b".into(),
|
||||
@@ -2654,6 +2665,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
];
|
||||
|
||||
@@ -2899,6 +2911,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
EventMsg::Error(ErrorEvent {
|
||||
message: "request-level failure".into(),
|
||||
@@ -2958,6 +2971,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
];
|
||||
|
||||
@@ -3009,6 +3023,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
];
|
||||
|
||||
@@ -3057,6 +3072,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
];
|
||||
|
||||
|
||||
@@ -3042,6 +3042,7 @@ mod tests {
|
||||
last_agent_message: None,
|
||||
completed_at: Some(TEST_TURN_COMPLETED_AT),
|
||||
duration_ms: Some(TEST_TURN_DURATION_MS),
|
||||
time_to_first_token_ms: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -275,6 +275,7 @@ async fn on_event_updates_status_from_task_complete() {
|
||||
last_agent_message: Some("done".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}));
|
||||
let expected = AgentStatus::Completed(Some("done".to_string()));
|
||||
assert_eq!(status, Some(expected));
|
||||
@@ -1225,6 +1226,7 @@ async fn multi_agent_v2_completion_ignores_dead_direct_parent() {
|
||||
last_agent_message: Some("done".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
@@ -1311,6 +1313,7 @@ async fn multi_agent_v2_completion_queues_message_for_direct_parent() {
|
||||
last_agent_message: Some("done".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -148,6 +148,7 @@ async fn record_initial_history_resumed_hydrates_previous_turn_settings_from_lif
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
];
|
||||
@@ -215,6 +216,7 @@ async fn reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_com
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
@@ -242,6 +244,7 @@ async fn reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_com
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::ThreadRolledBack(
|
||||
@@ -311,6 +314,7 @@ async fn reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_inc
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
@@ -400,6 +404,7 @@ async fn reconstruct_history_rollback_skips_non_user_turns_for_history_and_metad
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
@@ -426,6 +431,7 @@ async fn reconstruct_history_rollback_skips_non_user_turns_for_history_and_metad
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
@@ -443,6 +449,7 @@ async fn reconstruct_history_rollback_skips_non_user_turns_for_history_and_metad
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::ThreadRolledBack(
|
||||
@@ -515,6 +522,7 @@ async fn reconstruct_history_rollback_counts_inter_agent_assistant_turns() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
@@ -534,6 +542,7 @@ async fn reconstruct_history_rollback_counts_inter_agent_assistant_turns() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::ThreadRolledBack(
|
||||
@@ -601,6 +610,7 @@ async fn reconstruct_history_rollback_clears_history_and_metadata_when_exceeding
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::ThreadRolledBack(
|
||||
@@ -650,6 +660,7 @@ async fn record_initial_history_resumed_rollback_skips_only_user_turns() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
// Standalone task turn (no UserMessage) should not consume rollback skips.
|
||||
@@ -667,6 +678,7 @@ async fn record_initial_history_resumed_rollback_skips_only_user_turns() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::ThreadRolledBack(
|
||||
@@ -720,6 +732,7 @@ async fn record_initial_history_resumed_rollback_drops_incomplete_user_turn_comp
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
@@ -876,6 +889,7 @@ async fn reconstruct_history_legacy_compaction_without_replacement_history_clear
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
];
|
||||
@@ -945,6 +959,7 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
];
|
||||
@@ -1046,6 +1061,7 @@ async fn record_initial_history_resumed_aborted_turn_without_id_clears_active_tu
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
@@ -1153,6 +1169,7 @@ async fn record_initial_history_resumed_unmatched_abort_preserves_active_turn_fo
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
@@ -1186,6 +1203,7 @@ async fn record_initial_history_resumed_unmatched_abort_preserves_active_turn_fo
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
];
|
||||
@@ -1268,6 +1286,7 @@ async fn record_initial_history_resumed_trailing_incomplete_turn_compaction_clea
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
@@ -1418,6 +1437,7 @@ async fn record_initial_history_resumed_replaced_incomplete_compacted_turn_clear
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
|
||||
@@ -1381,6 +1381,7 @@ async fn record_initial_history_forked_hydrates_previous_turn_settings() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
},
|
||||
)),
|
||||
];
|
||||
@@ -1566,6 +1567,7 @@ async fn thread_rollback_recomputes_previous_turn_settings_and_reference_context
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
codex_protocol::protocol::TurnStartedEvent {
|
||||
@@ -1591,6 +1593,7 @@ async fn thread_rollback_recomputes_previous_turn_settings_and_reference_context
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
])
|
||||
.await;
|
||||
@@ -1668,6 +1671,7 @@ async fn thread_rollback_restores_cleared_reference_context_item_after_compactio
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
codex_protocol::protocol::TurnStartedEvent {
|
||||
@@ -1686,6 +1690,7 @@ async fn thread_rollback_restores_cleared_reference_context_item_after_compactio
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
codex_protocol::protocol::TurnStartedEvent {
|
||||
@@ -1713,6 +1718,7 @@ async fn thread_rollback_restores_cleared_reference_context_item_after_compactio
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
])
|
||||
.await;
|
||||
@@ -1759,6 +1765,7 @@ async fn thread_rollback_persists_marker_and_replays_cumulatively() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
codex_protocol::protocol::TurnStartedEvent {
|
||||
@@ -1782,6 +1789,7 @@ async fn thread_rollback_persists_marker_and_replays_cumulatively() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
RolloutItem::EventMsg(EventMsg::TurnStarted(
|
||||
codex_protocol::protocol::TurnStartedEvent {
|
||||
@@ -1805,6 +1813,7 @@ async fn thread_rollback_persists_marker_and_replays_cumulatively() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
])
|
||||
.await;
|
||||
@@ -4785,6 +4794,7 @@ async fn task_finish_emits_turn_item_lifecycle_for_leftover_pending_user_input()
|
||||
EventMsg::TurnComplete(TurnCompleteEvent {
|
||||
turn_id,
|
||||
last_agent_message: None,
|
||||
time_to_first_token_ms: None,
|
||||
..
|
||||
}) if turn_id == tc.sub_id
|
||||
));
|
||||
|
||||
@@ -282,6 +282,7 @@ impl GuardianReviewAnalyticsResult {
|
||||
terminal.had_prior_review_context = Some(metadata.had_prior_review_context);
|
||||
terminal.reviewed_action_truncated = metadata.reviewed_action_truncated;
|
||||
terminal.token_usage = metadata.token_usage;
|
||||
terminal.time_to_first_token_ms = metadata.time_to_first_token_ms;
|
||||
}
|
||||
|
||||
terminal
|
||||
|
||||
@@ -74,6 +74,7 @@ pub(crate) struct GuardianReviewSessionMetadata {
|
||||
pub(crate) had_prior_review_context: bool,
|
||||
pub(crate) reviewed_action_truncated: bool,
|
||||
pub(crate) token_usage: Option<TokenUsage>,
|
||||
pub(crate) time_to_first_token_ms: Option<u64>,
|
||||
}
|
||||
|
||||
pub(crate) struct GuardianReviewSessionParams {
|
||||
@@ -623,6 +624,7 @@ async fn run_review_on_session(
|
||||
had_prior_review_context: had_prior_review_context(&prompt_mode),
|
||||
reviewed_action_truncated: false,
|
||||
token_usage: None,
|
||||
time_to_first_token_ms: None,
|
||||
};
|
||||
if send_followup_reminder {
|
||||
append_guardian_followup_reminder(review_session).await;
|
||||
@@ -695,8 +697,13 @@ async fn run_review_on_session(
|
||||
};
|
||||
guardian_metadata.reviewed_action_truncated = reviewed_action_truncated;
|
||||
|
||||
let outcome =
|
||||
wait_for_guardian_review(review_session, deadline, params.external_cancel.as_ref()).await;
|
||||
let outcome = wait_for_guardian_review(
|
||||
review_session,
|
||||
deadline,
|
||||
params.external_cancel.as_ref(),
|
||||
&mut guardian_metadata,
|
||||
)
|
||||
.await;
|
||||
if matches!(outcome.0, GuardianReviewSessionOutcome::Completed(_)) {
|
||||
if outcome.2
|
||||
&& let Some(token_usage_at_review_start) = token_usage_at_review_start
|
||||
@@ -740,6 +747,7 @@ async fn wait_for_guardian_review(
|
||||
review_session: &GuardianReviewSession,
|
||||
deadline: tokio::time::Instant,
|
||||
external_cancel: Option<&CancellationToken>,
|
||||
metadata: &mut GuardianReviewSessionMetadata,
|
||||
) -> (GuardianReviewSessionOutcome, bool, bool) {
|
||||
let timeout = tokio::time::sleep_until(deadline);
|
||||
tokio::pin!(timeout);
|
||||
@@ -765,6 +773,9 @@ async fn wait_for_guardian_review(
|
||||
match event {
|
||||
Ok(event) => match event.msg {
|
||||
EventMsg::TurnComplete(turn_complete) => {
|
||||
metadata.time_to_first_token_ms = turn_complete
|
||||
.time_to_first_token_ms
|
||||
.and_then(|ms| u64::try_from(ms).ok());
|
||||
if turn_complete.last_agent_message.is_none()
|
||||
&& let Some(error_message) = last_error_message
|
||||
{
|
||||
|
||||
@@ -958,6 +958,10 @@ async fn guardian_review_request_layout_matches_model_visible_request_snapshot()
|
||||
assert_eq!(metadata.guardian_model, "gpt-5.4");
|
||||
assert_eq!(metadata.guardian_reasoning_effort.as_deref(), Some("low"));
|
||||
assert!(!metadata.had_prior_review_context);
|
||||
assert!(
|
||||
metadata.time_to_first_token_ms.is_some(),
|
||||
"guardian review metadata should capture TTFT when the nested turn completes"
|
||||
);
|
||||
|
||||
let request = request_log.single_request();
|
||||
let mut settings = Settings::clone_current();
|
||||
|
||||
@@ -535,11 +535,16 @@ impl Session {
|
||||
.turn_timing_state
|
||||
.completed_at_and_duration_ms()
|
||||
.await;
|
||||
let time_to_first_token_ms = turn_context
|
||||
.turn_timing_state
|
||||
.time_to_first_token_ms()
|
||||
.await;
|
||||
let event = EventMsg::TurnComplete(TurnCompleteEvent {
|
||||
turn_id: turn_context.sub_id.clone(),
|
||||
last_agent_message,
|
||||
completed_at,
|
||||
duration_ms,
|
||||
time_to_first_token_ms,
|
||||
});
|
||||
self.send_event(turn_context.as_ref(), event).await;
|
||||
|
||||
|
||||
@@ -1154,6 +1154,7 @@ async fn multi_agent_v2_list_agents_returns_completed_status_and_last_task_messa
|
||||
last_agent_message: Some("done".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
@@ -1631,6 +1632,7 @@ async fn multi_agent_v2_followup_task_completion_notifies_parent_on_every_turn()
|
||||
last_agent_message: Some("first done".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
@@ -1659,6 +1661,7 @@ async fn multi_agent_v2_followup_task_completion_notifies_parent_on_every_turn()
|
||||
last_agent_message: Some("second done".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -74,6 +74,16 @@ impl TurnTimingState {
|
||||
(completed_at, duration_ms)
|
||||
}
|
||||
|
||||
pub(crate) async fn time_to_first_token_ms(&self) -> Option<i64> {
|
||||
let state = self.state.lock().await;
|
||||
let started_at = state.started_at?;
|
||||
let first_token_at = state.first_token_at?;
|
||||
Some(
|
||||
i64::try_from(first_token_at.duration_since(started_at).as_millis())
|
||||
.unwrap_or(i64::MAX),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) async fn record_ttft_for_response_event(
|
||||
&self,
|
||||
event: &ResponseEvent,
|
||||
|
||||
@@ -69,6 +69,7 @@ fn resume_history(
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})),
|
||||
],
|
||||
rollout_path: rollout_path.to_path_buf(),
|
||||
|
||||
@@ -2057,6 +2057,10 @@ pub struct TurnCompleteEvent {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(type = "number | null", optional)]
|
||||
pub duration_ms: Option<i64>,
|
||||
/// Duration between turn start and the first model token in milliseconds, if known.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(type = "number | null", optional)]
|
||||
pub time_to_first_token_ms: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
|
||||
@@ -762,6 +762,7 @@ fn append_terminal_turn_events(events: &mut Vec<Event>, turn: &Turn, include_fai
|
||||
last_agent_message: None,
|
||||
completed_at: turn.completed_at,
|
||||
duration_ms: turn.duration_ms,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
}),
|
||||
TurnStatus::Interrupted => events.push(Event {
|
||||
@@ -793,6 +794,7 @@ fn append_terminal_turn_events(events: &mut Vec<Event>, turn: &Turn, include_fai
|
||||
last_agent_message: None,
|
||||
completed_at: turn.completed_at,
|
||||
duration_ms: turn.duration_ms,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -654,6 +654,7 @@ async fn unified_exec_wait_after_final_agent_message_snapshot() {
|
||||
last_agent_message: Some("Final response.".into()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -699,6 +700,7 @@ async fn unified_exec_wait_before_streamed_agent_message_snapshot() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -766,6 +768,7 @@ async fn unified_exec_waiting_multiple_empty_snapshots() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -846,6 +849,7 @@ async fn unified_exec_non_empty_then_empty_snapshots() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -1350,6 +1354,7 @@ async fn turn_complete_keeps_unified_exec_processes() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -546,6 +546,7 @@ async fn plan_implementation_popup_skips_replayed_turn_complete() {
|
||||
last_agent_message: Some("Plan details".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})]);
|
||||
|
||||
let popup = render_bottom_popup(&chat, /*width*/ 80);
|
||||
@@ -572,6 +573,7 @@ async fn plan_implementation_popup_shows_once_when_replay_precedes_live_turn_com
|
||||
last_agent_message: Some("Plan details".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
})]);
|
||||
let replay_popup = render_bottom_popup(&chat, /*width*/ 80);
|
||||
assert!(
|
||||
@@ -586,6 +588,7 @@ async fn plan_implementation_popup_shows_once_when_replay_precedes_live_turn_com
|
||||
last_agent_message: Some("Plan details".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -609,6 +612,7 @@ async fn plan_implementation_popup_shows_once_when_replay_precedes_live_turn_com
|
||||
last_agent_message: Some("Plan details".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
let duplicate_popup = render_bottom_popup(&chat, /*width*/ 80);
|
||||
|
||||
@@ -234,6 +234,7 @@ async fn steer_rejection_queues_review_follow_up_before_existing_queued_messages
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -255,6 +256,7 @@ async fn steer_rejection_queues_review_follow_up_before_existing_queued_messages
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -225,6 +225,7 @@ async fn slash_copy_state_tracks_turn_complete_final_reply() {
|
||||
last_agent_message: Some("Final reply **markdown**".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -257,6 +258,7 @@ async fn slash_copy_state_tracks_plan_item_completion() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -343,6 +345,7 @@ async fn slash_copy_state_is_preserved_during_running_task() {
|
||||
last_agent_message: Some("Previous completed reply".to_string()),
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
chat.on_task_started();
|
||||
@@ -373,6 +376,7 @@ async fn slash_copy_tracks_replayed_legacy_agent_message_when_turn_complete_omit
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
let _ = drain_insert_history(&mut rx);
|
||||
@@ -410,6 +414,7 @@ async fn slash_copy_uses_agent_message_item_when_turn_complete_omits_final_text(
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
let _ = drain_insert_history(&mut rx);
|
||||
|
||||
@@ -961,6 +961,7 @@ async fn status_line_branch_refreshes_after_turn_complete() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -1311,6 +1312,7 @@ async fn multiple_agent_messages_in_single_turn_emit_multiple_headers() {
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -2251,6 +2253,7 @@ printf 'fenced within fenced\n'
|
||||
last_agent_message: None,
|
||||
completed_at: None,
|
||||
duration_ms: None,
|
||||
time_to_first_token_ms: None,
|
||||
}),
|
||||
});
|
||||
for lines in drain_insert_history(&mut rx) {
|
||||
|
||||
Reference in New Issue
Block a user