add client metadata

This commit is contained in:
Roy Han
2026-03-27 11:00:11 -07:00
parent a1e506f17d
commit 7afe91c1df
2 changed files with 40 additions and 11 deletions
+20 -9
View File
@@ -149,6 +149,9 @@ pub struct AnalyticsReducer {
struct ConnectionState {
product_client_id: String,
client_name: Option<String>,
client_version: Option<String>,
experimental_api_enabled: Option<bool>,
}
#[derive(Clone)]
@@ -377,6 +380,9 @@ struct SkillInvocationEventParams {
struct CodexThreadInitializedEventParams {
thread_id: String,
product_client_id: String,
client_name: Option<String>,
client_version: Option<String>,
experimental_api_enabled: Option<bool>,
model: String,
ephemeral: bool,
session_source: Option<&'static str>,
@@ -492,7 +498,12 @@ impl AnalyticsReducer {
self.connections.insert(
connection_id,
ConnectionState {
product_client_id: params.client_info.name,
product_client_id: params.client_info.name.clone(),
client_name: Some(params.client_info.name),
client_version: Some(params.client_info.version),
experimental_api_enabled: params
.capabilities
.map(|capabilities| capabilities.experimental_api),
},
);
}
@@ -506,10 +517,7 @@ impl AnalyticsReducer {
return;
};
out.push(TrackEventRequest::CodexThreadInitialized(
codex_thread_initialized_event_request(
connection_state.product_client_id.clone(),
input,
),
codex_thread_initialized_event_request(connection_state, input),
));
}
@@ -666,22 +674,25 @@ fn codex_app_metadata(tracking: &TrackEventsContext, app: AppInvocation) -> Code
}
fn codex_thread_initialized_event_request(
product_client_id: String,
connection_state: &ConnectionState,
input: ThreadInitializedInput,
) -> CodexThreadInitializedEvent {
CodexThreadInitializedEvent {
event_type: "codex_thread_initialized",
event_params: codex_thread_initialized_event_params(product_client_id, input),
event_params: codex_thread_initialized_event_params(connection_state, input),
}
}
fn codex_thread_initialized_event_params(
product_client_id: String,
connection_state: &ConnectionState,
input: ThreadInitializedInput,
) -> CodexThreadInitializedEventParams {
CodexThreadInitializedEventParams {
thread_id: input.thread_id,
product_client_id,
product_client_id: connection_state.product_client_id.clone(),
client_name: connection_state.client_name.clone(),
client_version: connection_state.client_version.clone(),
experimental_api_enabled: connection_state.experimental_api_enabled,
model: input.model,
ephemeral: input.ephemeral,
session_source: session_source_name(&input.session_source),
@@ -20,6 +20,7 @@ use codex_app_server_protocol::ApprovalsReviewer as AppServerApprovalsReviewer;
use codex_app_server_protocol::AskForApproval as AppServerAskForApproval;
use codex_app_server_protocol::ClientInfo;
use codex_app_server_protocol::ClientResponse;
use codex_app_server_protocol::InitializeCapabilities;
use codex_app_server_protocol::InitializeParams;
use codex_app_server_protocol::RequestId;
use codex_app_server_protocol::SandboxPolicy as AppServerSandboxPolicy;
@@ -262,7 +263,12 @@ fn app_used_dedupe_is_keyed_by_turn_and_connector() {
#[test]
fn thread_initialized_event_serializes_expected_shape() {
let event = TrackEventRequest::CodexThreadInitialized(codex_thread_initialized_event_request(
"codex-tui".to_string(),
&super::ConnectionState {
product_client_id: "codex-tui".to_string(),
client_name: Some("codex-tui".to_string()),
client_version: Some("1.0.0".to_string()),
experimental_api_enabled: Some(true),
},
ThreadInitializedInput {
connection_id: 1,
thread_id: "thread-0".to_string(),
@@ -282,6 +288,9 @@ fn thread_initialized_event_serializes_expected_shape() {
"event_params": {
"thread_id": "thread-0",
"product_client_id": "codex-tui",
"client_name": "codex-tui",
"client_version": "1.0.0",
"experimental_api_enabled": true,
"model": "gpt-5",
"ephemeral": true,
"session_source": "user",
@@ -325,7 +334,10 @@ async fn initialize_caches_client_and_thread_lifecycle_publishes_once_initialize
title: None,
version: "1.0.0".to_string(),
},
capabilities: None,
capabilities: Some(InitializeCapabilities {
experimental_api: false,
opt_out_notification_methods: None,
}),
},
},
&mut events,
@@ -347,6 +359,12 @@ async fn initialize_caches_client_and_thread_lifecycle_publishes_once_initialize
assert_eq!(payload.as_array().expect("events array").len(), 1);
assert_eq!(payload[0]["event_type"], "codex_thread_initialized");
assert_eq!(payload[0]["event_params"]["product_client_id"], "codex-tui");
assert_eq!(payload[0]["event_params"]["client_name"], "codex-tui");
assert_eq!(payload[0]["event_params"]["client_version"], "1.0.0");
assert_eq!(
payload[0]["event_params"]["experimental_api_enabled"],
false
);
assert_eq!(payload[0]["event_params"]["initialization_mode"], "resumed");
assert_eq!(payload[0]["event_params"]["session_source"], "user");
assert_eq!(payload[0]["event_params"]["subagent_source"], json!(null));