diff --git a/codex-rs/analytics/src/analytics_client_tests.rs b/codex-rs/analytics/src/analytics_client_tests.rs index 44fc65c792..895c0962cd 100644 --- a/codex-rs/analytics/src/analytics_client_tests.rs +++ b/codex-rs/analytics/src/analytics_client_tests.rs @@ -32,6 +32,7 @@ use crate::events::ReviewTrigger; use crate::events::Reviewer; use crate::events::ThreadInitializedEvent; use crate::events::ThreadInitializedEventParams; +use crate::events::ThreadStartTimingEventParams; use crate::events::ToolItemTerminalStatus; use crate::events::TrackEventRequest; use crate::events::codex_app_metadata; @@ -1329,10 +1330,12 @@ fn thread_initialized_event_serializes_expected_shape() { initialization_mode: ThreadInitializationMode::New, subagent_source: None, parent_thread_id: None, - thread_start_duration_ms: Some(321), - thread_start_prepare_duration_ms: Some(111), - thread_start_spawn_duration_ms: Some(123), - thread_start_finalize_duration_ms: Some(87), + thread_start_timing: ThreadStartTimingEventParams { + thread_start_duration_ms: Some(321), + thread_start_prepare_duration_ms: Some(111), + thread_start_spawn_duration_ms: Some(123), + thread_start_finalize_duration_ms: Some(87), + }, created_at: 1, }, }); diff --git a/codex-rs/analytics/src/events.rs b/codex-rs/analytics/src/events.rs index 873b2bdc4d..870de097c6 100644 --- a/codex-rs/analytics/src/events.rs +++ b/codex-rs/analytics/src/events.rs @@ -159,6 +159,14 @@ pub(crate) struct CodexAppServerStartedEventRequest { pub(crate) event_params: CodexAppServerStartedEventParams, } +#[derive(Default, Serialize)] +pub(crate) struct ThreadStartTimingEventParams { + pub(crate) thread_start_duration_ms: Option, + pub(crate) thread_start_prepare_duration_ms: Option, + pub(crate) thread_start_spawn_duration_ms: Option, + pub(crate) thread_start_finalize_duration_ms: Option, +} + #[derive(Serialize)] pub(crate) struct ThreadInitializedEventParams { pub(crate) thread_id: String, @@ -170,10 +178,8 @@ pub(crate) struct ThreadInitializedEventParams { pub(crate) initialization_mode: ThreadInitializationMode, pub(crate) subagent_source: Option, pub(crate) parent_thread_id: Option, - pub(crate) thread_start_duration_ms: Option, - pub(crate) thread_start_prepare_duration_ms: Option, - pub(crate) thread_start_spawn_duration_ms: Option, - pub(crate) thread_start_finalize_duration_ms: Option, + #[serde(flatten)] + pub(crate) thread_start_timing: ThreadStartTimingEventParams, pub(crate) created_at: u64, } @@ -1061,10 +1067,7 @@ pub(crate) fn subagent_thread_started_event_request( parent_thread_id: input .parent_thread_id .or_else(|| subagent_parent_thread_id(&input.subagent_source)), - thread_start_duration_ms: None, - thread_start_prepare_duration_ms: None, - thread_start_spawn_duration_ms: None, - thread_start_finalize_duration_ms: None, + thread_start_timing: ThreadStartTimingEventParams::default(), created_at: input.created_at, }; ThreadInitializedEvent { diff --git a/codex-rs/analytics/src/reducer.rs b/codex-rs/analytics/src/reducer.rs index 5075e5baec..1476dc5f3e 100644 --- a/codex-rs/analytics/src/reducer.rs +++ b/codex-rs/analytics/src/reducer.rs @@ -47,6 +47,7 @@ use crate::events::SkillInvocationEventParams; use crate::events::SkillInvocationEventRequest; use crate::events::ThreadInitializedEvent; use crate::events::ThreadInitializedEventParams; +use crate::events::ThreadStartTimingEventParams; use crate::events::ToolItemFailureKind; use crate::events::ToolItemTerminalStatus; use crate::events::TrackEventRequest; @@ -1309,13 +1310,15 @@ impl AnalyticsReducer { initialization_mode, subagent_source: thread_metadata.subagent_source.clone(), parent_thread_id: thread_metadata.parent_thread_id, - thread_start_duration_ms: thread_start_timing.map(|timing| timing.duration_ms), - thread_start_prepare_duration_ms: thread_start_timing - .map(|timing| timing.prepare_duration_ms), - thread_start_spawn_duration_ms: thread_start_timing - .map(|timing| timing.spawn_duration_ms), - thread_start_finalize_duration_ms: thread_start_timing - .map(|timing| timing.finalize_duration_ms), + thread_start_timing: match thread_start_timing { + Some(timing) => ThreadStartTimingEventParams { + thread_start_duration_ms: Some(timing.duration_ms), + thread_start_prepare_duration_ms: Some(timing.prepare_duration_ms), + thread_start_spawn_duration_ms: Some(timing.spawn_duration_ms), + thread_start_finalize_duration_ms: Some(timing.finalize_duration_ms), + }, + None => ThreadStartTimingEventParams::default(), + }, created_at: u64::try_from(thread.created_at).unwrap_or_default(), }, },