diff --git a/codex-rs/core/src/auth.rs b/codex-rs/core/src/auth.rs index 4eea313e..21cb4bf6 100644 --- a/codex-rs/core/src/auth.rs +++ b/codex-rs/core/src/auth.rs @@ -135,6 +135,10 @@ impl CodexAuth { self.get_current_token_data().and_then(|t| t.account_id) } + pub fn get_account_email(&self) -> Option { + self.get_current_token_data().and_then(|t| t.id_token.email) + } + pub(crate) fn get_plan_type(&self) -> Option { self.get_current_token_data() .and_then(|t| t.id_token.chatgpt_plan_type) diff --git a/codex-rs/core/src/client.rs b/codex-rs/core/src/client.rs index a8dcb725..f59f30c5 100644 --- a/codex-rs/core/src/client.rs +++ b/codex-rs/core/src/client.rs @@ -1030,6 +1030,7 @@ mod tests { "test", "test", None, + Some("test@test.com".to_string()), Some(AuthMode::ChatGPT), false, "test".to_string(), diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index 5e28a817..ce86b808 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -445,6 +445,7 @@ impl Session { config.model.as_str(), config.model_family.slug.as_str(), auth_manager.auth().and_then(|a| a.get_account_id()), + auth_manager.auth().and_then(|a| a.get_account_email()), auth_manager.auth().map(|a| a.mode), config.otel.log_user_prompt, terminal::user_agent(), @@ -2744,6 +2745,7 @@ mod tests { config.model.as_str(), config.model_family.slug.as_str(), None, + Some("test@test.com".to_string()), Some(AuthMode::ChatGPT), false, "test".to_string(), diff --git a/codex-rs/core/tests/chat_completions_payload.rs b/codex-rs/core/tests/chat_completions_payload.rs index 9e10b378..0d0d60d4 100644 --- a/codex-rs/core/tests/chat_completions_payload.rs +++ b/codex-rs/core/tests/chat_completions_payload.rs @@ -79,6 +79,7 @@ async fn run_request(input: Vec) -> Value { config.model.as_str(), config.model_family.slug.as_str(), None, + Some("test@test.com".to_string()), Some(AuthMode::ChatGPT), false, "test".to_string(), diff --git a/codex-rs/core/tests/chat_completions_sse.rs b/codex-rs/core/tests/chat_completions_sse.rs index 1aab6ac3..dffc9e42 100644 --- a/codex-rs/core/tests/chat_completions_sse.rs +++ b/codex-rs/core/tests/chat_completions_sse.rs @@ -78,6 +78,7 @@ async fn run_stream_with_bytes(sse_body: &[u8]) -> Vec { config.model.as_str(), config.model_family.slug.as_str(), None, + Some("test@test.com".to_string()), Some(AuthMode::ChatGPT), false, "test".to_string(), diff --git a/codex-rs/core/tests/responses_headers.rs b/codex-rs/core/tests/responses_headers.rs index 19967b06..4a086cf1 100644 --- a/codex-rs/core/tests/responses_headers.rs +++ b/codex-rs/core/tests/responses_headers.rs @@ -63,6 +63,7 @@ async fn responses_stream_includes_task_type_header() { config.model.as_str(), config.model_family.slug.as_str(), None, + Some("test@test.com".to_string()), Some(AuthMode::ChatGPT), false, "test".to_string(), diff --git a/codex-rs/core/tests/suite/client.rs b/codex-rs/core/tests/suite/client.rs index eb14dabb..beaa87a8 100644 --- a/codex-rs/core/tests/suite/client.rs +++ b/codex-rs/core/tests/suite/client.rs @@ -657,6 +657,7 @@ async fn azure_responses_request_includes_store_and_reasoning_ids() { config.model.as_str(), config.model_family.slug.as_str(), None, + Some("test@test.com".to_string()), Some(AuthMode::ChatGPT), false, "test".to_string(), diff --git a/codex-rs/otel/src/otel_event_manager.rs b/codex-rs/otel/src/otel_event_manager.rs index 2d6f278a..c02ea19f 100644 --- a/codex-rs/otel/src/otel_event_manager.rs +++ b/codex-rs/otel/src/otel_event_manager.rs @@ -33,6 +33,7 @@ pub struct OtelEventMetadata { conversation_id: ConversationId, auth_mode: Option, account_id: Option, + account_email: Option, model: String, slug: String, log_user_prompts: bool, @@ -46,11 +47,13 @@ pub struct OtelEventManager { } impl OtelEventManager { + #[allow(clippy::too_many_arguments)] pub fn new( conversation_id: ConversationId, model: &str, slug: &str, account_id: Option, + account_email: Option, auth_mode: Option, log_user_prompts: bool, terminal_type: String, @@ -60,6 +63,7 @@ impl OtelEventManager { conversation_id, auth_mode: auth_mode.map(|m| m.to_string()), account_id, + account_email, model: model.to_owned(), slug: slug.to_owned(), log_user_prompts, @@ -98,6 +102,7 @@ impl OtelEventManager { app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, user.account_id = self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, @@ -136,6 +141,7 @@ impl OtelEventManager { app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, user.account_id = self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, @@ -205,6 +211,7 @@ impl OtelEventManager { app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, user.account_id = self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, @@ -226,6 +233,7 @@ impl OtelEventManager { app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, user.account_id = self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, @@ -240,6 +248,7 @@ impl OtelEventManager { app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, user.account_id = self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, @@ -262,6 +271,7 @@ impl OtelEventManager { app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, user.account_id = self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, @@ -286,6 +296,7 @@ impl OtelEventManager { app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, user.account_id = self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, @@ -320,6 +331,7 @@ impl OtelEventManager { app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, user.account_id = self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, @@ -343,6 +355,7 @@ impl OtelEventManager { app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, user.account_id = self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, @@ -383,7 +396,8 @@ impl OtelEventManager { conversation.id = %self.metadata.conversation_id, app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, - user.account_id = self.metadata.account_id, + user.account_id= self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, @@ -408,6 +422,7 @@ impl OtelEventManager { app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, user.account_id = self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, @@ -437,6 +452,7 @@ impl OtelEventManager { app.version = %self.metadata.app_version, auth_mode = self.metadata.auth_mode, user.account_id = self.metadata.account_id, + user.email = self.metadata.account_email, terminal.type = %self.metadata.terminal_type, model = %self.metadata.model, slug = %self.metadata.slug, diff --git a/docs/config.md b/docs/config.md index c1d305f3..ad329088 100644 --- a/docs/config.md +++ b/docs/config.md @@ -509,7 +509,7 @@ crate—the events listed below—is forwarded to the exporter. Every event shares a common set of metadata fields: `event.timestamp`, `conversation.id`, `app.version`, `auth_mode` (when available), -`user.account_id` (when available), `terminal.type`, `model`, and `slug`. +`user.account_id` (when available), `user.email` (when available), `terminal.type`, `model`, and `slug`. With OTEL enabled Codex emits the following event types (in addition to the metadata above):