Skip to content

Commit 9098f5f

Browse files
committed
[codex-analytics] feature plumbing and emittance
1 parent ecca342 commit 9098f5f

34 files changed

Lines changed: 1508 additions & 70 deletions

codex-rs/analytics/src/analytics_client_tests.rs

Lines changed: 524 additions & 1 deletion
Large diffs are not rendered by default.

codex-rs/analytics/src/client.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ use crate::facts::SkillInvocation;
1313
use crate::facts::SkillInvokedInput;
1414
use crate::facts::SubAgentThreadStartedInput;
1515
use crate::facts::TrackEventsContext;
16+
use crate::facts::TurnResolvedConfigFact;
1617
use crate::reducer::AnalyticsReducer;
18+
use codex_app_server_protocol::ClientRequest;
1719
use codex_app_server_protocol::ClientResponse;
1820
use codex_app_server_protocol::InitializeParams;
21+
use codex_app_server_protocol::RequestId;
22+
use codex_app_server_protocol::ServerNotification;
1923
use codex_login::AuthManager;
2024
use codex_login::default_client::create_client;
2125
use codex_plugin::PluginTelemetryMetadata;
@@ -160,6 +164,14 @@ impl AnalyticsEventsClient {
160164
)));
161165
}
162166

167+
pub fn track_request(&self, connection_id: u64, request_id: RequestId, request: ClientRequest) {
168+
self.record_fact(AnalyticsFact::Request {
169+
connection_id,
170+
request_id,
171+
request: Box::new(request),
172+
});
173+
}
174+
163175
pub fn track_app_used(&self, tracking: TrackEventsContext, app: AppInvocation) {
164176
if !self.queue.should_enqueue_app_used(&tracking, &app) {
165177
return;
@@ -178,6 +190,12 @@ impl AnalyticsEventsClient {
178190
)));
179191
}
180192

193+
pub fn track_turn_resolved_config(&self, fact: TurnResolvedConfigFact) {
194+
self.record_fact(AnalyticsFact::Custom(
195+
CustomAnalyticsFact::TurnResolvedConfig(Box::new(fact)),
196+
));
197+
}
198+
181199
pub fn track_plugin_installed(&self, plugin: PluginTelemetryMetadata) {
182200
self.record_fact(AnalyticsFact::Custom(
183201
CustomAnalyticsFact::PluginStateChanged(PluginStateChangedInput {
@@ -227,6 +245,10 @@ impl AnalyticsEventsClient {
227245
response: Box::new(response),
228246
});
229247
}
248+
249+
pub fn track_notification(&self, notification: ServerNotification) {
250+
self.record_fact(AnalyticsFact::Notification(Box::new(notification)));
251+
}
230252
}
231253

232254
async fn send_track_events(

codex-rs/analytics/src/events.rs

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ use crate::facts::AppInvocation;
22
use crate::facts::InvocationType;
33
use crate::facts::PluginState;
44
use crate::facts::SubAgentThreadStartedInput;
5+
use crate::facts::ThreadInitializationMode;
56
use crate::facts::TrackEventsContext;
7+
use crate::facts::TurnStatus;
8+
use crate::facts::TurnSubmissionType;
9+
use codex_app_server_protocol::CodexErrorInfo;
610
use codex_login::default_client::originator;
711
use codex_plugin::PluginTelemetryMetadata;
812
use codex_protocol::protocol::SessionSource;
@@ -17,14 +21,6 @@ pub enum AppServerRpcTransport {
1721
InProcess,
1822
}
1923

20-
#[derive(Clone, Copy, Debug, Serialize)]
21-
#[serde(rename_all = "snake_case")]
22-
pub(crate) enum ThreadInitializationMode {
23-
New,
24-
Forked,
25-
Resumed,
26-
}
27-
2824
#[derive(Serialize)]
2925
pub(crate) struct TrackEventsRequest {
3026
pub(crate) events: Vec<TrackEventRequest>,
@@ -37,6 +33,7 @@ pub(crate) enum TrackEventRequest {
3733
ThreadInitialized(ThreadInitializedEvent),
3834
AppMentioned(CodexAppMentionedEventRequest),
3935
AppUsed(CodexAppUsedEventRequest),
36+
TurnEvent(Box<CodexTurnEventRequest>),
4037
PluginUsed(CodexPluginUsedEventRequest),
4138
PluginInstalled(CodexPluginEventRequest),
4239
PluginUninstalled(CodexPluginEventRequest),
@@ -122,6 +119,53 @@ pub(crate) struct CodexAppUsedEventRequest {
122119
pub(crate) event_params: CodexAppMetadata,
123120
}
124121

122+
#[derive(Serialize)]
123+
pub(crate) struct CodexTurnEventParams {
124+
pub(crate) thread_id: String,
125+
pub(crate) turn_id: String,
126+
pub(crate) submission_type: Option<TurnSubmissionType>,
127+
pub(crate) app_server_client: CodexAppServerClientMetadata,
128+
pub(crate) runtime: CodexRuntimeMetadata,
129+
pub(crate) ephemeral: bool,
130+
pub(crate) thread_source: Option<String>,
131+
pub(crate) initialization_mode: ThreadInitializationMode,
132+
pub(crate) subagent_source: Option<String>,
133+
pub(crate) parent_thread_id: Option<String>,
134+
pub(crate) model: Option<String>,
135+
pub(crate) model_provider: String,
136+
pub(crate) sandbox_policy: Option<&'static str>,
137+
pub(crate) reasoning_effort: Option<String>,
138+
pub(crate) reasoning_summary: Option<String>,
139+
pub(crate) service_tier: String,
140+
pub(crate) approval_policy: String,
141+
pub(crate) approvals_reviewer: String,
142+
pub(crate) sandbox_network_access: bool,
143+
pub(crate) collaboration_mode: Option<&'static str>,
144+
pub(crate) personality: Option<String>,
145+
pub(crate) num_input_images: usize,
146+
pub(crate) is_first_turn: bool,
147+
pub(crate) status: Option<TurnStatus>,
148+
pub(crate) turn_error: Option<CodexErrorInfo>,
149+
pub(crate) steer_count: Option<usize>,
150+
pub(crate) total_tool_call_count: Option<usize>,
151+
pub(crate) shell_command_count: Option<usize>,
152+
pub(crate) file_change_count: Option<usize>,
153+
pub(crate) mcp_tool_call_count: Option<usize>,
154+
pub(crate) dynamic_tool_call_count: Option<usize>,
155+
pub(crate) subagent_tool_call_count: Option<usize>,
156+
pub(crate) web_search_count: Option<usize>,
157+
pub(crate) image_generation_count: Option<usize>,
158+
pub(crate) duration_ms: Option<u64>,
159+
pub(crate) started_at: Option<u64>,
160+
pub(crate) completed_at: Option<u64>,
161+
}
162+
163+
#[derive(Serialize)]
164+
pub(crate) struct CodexTurnEventRequest {
165+
pub(crate) event_type: &'static str,
166+
pub(crate) event_params: CodexTurnEventParams,
167+
}
168+
125169
#[derive(Serialize)]
126170
pub(crate) struct CodexPluginMetadata {
127171
pub(crate) plugin_id: Option<String>,

codex-rs/analytics/src/facts.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ use codex_app_server_protocol::InitializeParams;
66
use codex_app_server_protocol::RequestId;
77
use codex_app_server_protocol::ServerNotification;
88
use codex_plugin::PluginTelemetryMetadata;
9+
use codex_protocol::config_types::ApprovalsReviewer;
10+
use codex_protocol::config_types::ModeKind;
11+
use codex_protocol::config_types::Personality;
12+
use codex_protocol::config_types::ReasoningSummary;
13+
use codex_protocol::config_types::ServiceTier;
14+
use codex_protocol::openai_models::ReasoningEffort;
15+
use codex_protocol::protocol::AskForApproval;
16+
use codex_protocol::protocol::SandboxPolicy;
17+
use codex_protocol::protocol::SessionSource;
918
use codex_protocol::protocol::SkillScope;
1019
use codex_protocol::protocol::SubAgentSource;
1120
use serde::Serialize;
@@ -30,6 +39,52 @@ pub fn build_track_events_context(
3039
}
3140
}
3241

42+
#[derive(Clone, Copy, Debug, Serialize)]
43+
#[serde(rename_all = "snake_case")]
44+
pub enum TurnSubmissionType {
45+
Default,
46+
Queued,
47+
}
48+
49+
#[derive(Clone)]
50+
pub struct TurnResolvedConfigFact {
51+
pub turn_id: String,
52+
pub thread_id: String,
53+
pub num_input_images: usize,
54+
pub submission_type: Option<TurnSubmissionType>,
55+
pub ephemeral: bool,
56+
pub session_source: SessionSource,
57+
pub initialization_mode: ThreadInitializationMode,
58+
pub model: String,
59+
pub model_provider: String,
60+
pub sandbox_policy: SandboxPolicy,
61+
pub reasoning_effort: Option<ReasoningEffort>,
62+
pub reasoning_summary: Option<ReasoningSummary>,
63+
pub service_tier: Option<ServiceTier>,
64+
pub approval_policy: AskForApproval,
65+
pub approvals_reviewer: ApprovalsReviewer,
66+
pub sandbox_network_access: bool,
67+
pub collaboration_mode: ModeKind,
68+
pub personality: Option<Personality>,
69+
pub is_first_turn: bool,
70+
}
71+
72+
#[derive(Clone, Copy, Debug, Serialize)]
73+
#[serde(rename_all = "snake_case")]
74+
pub enum ThreadInitializationMode {
75+
New,
76+
Forked,
77+
Resumed,
78+
}
79+
80+
#[derive(Clone, Copy, Debug, Serialize)]
81+
#[serde(rename_all = "snake_case")]
82+
pub enum TurnStatus {
83+
Completed,
84+
Failed,
85+
Interrupted,
86+
}
87+
3388
#[derive(Clone, Debug)]
3489
pub struct SkillInvocation {
3590
pub skill_name: String,
@@ -89,6 +144,7 @@ pub(crate) enum AnalyticsFact {
89144

90145
pub(crate) enum CustomAnalyticsFact {
91146
SubAgentThreadStarted(SubAgentThreadStartedInput),
147+
TurnResolvedConfig(Box<TurnResolvedConfigFact>),
92148
SkillInvoked(SkillInvokedInput),
93149
AppMentioned(AppMentionedInput),
94150
AppUsed(AppUsedInput),

codex-rs/analytics/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ pub use facts::AppInvocation;
99
pub use facts::InvocationType;
1010
pub use facts::SkillInvocation;
1111
pub use facts::SubAgentThreadStartedInput;
12+
pub use facts::ThreadInitializationMode;
1213
pub use facts::TrackEventsContext;
14+
pub use facts::TurnResolvedConfigFact;
15+
pub use facts::TurnStatus;
1316
pub use facts::build_track_events_context;
1417

1518
#[cfg(test)]

0 commit comments

Comments
 (0)