From 3582b74d018c3b472fd28e1482efe277af80ab4a Mon Sep 17 00:00:00 2001 From: Owen Lin Date: Thu, 5 Feb 2026 10:46:06 -0800 Subject: [PATCH] fix(auth): isolate chatgptAuthTokens concept to auth manager and app-server (#10423) So that the rest of the codebase (like TUI) don't need to be concerned whether ChatGPT auth was handled by Codex itself or passed in via app-server's external auth mode. --- codex-rs/Cargo.lock | 1 - .../app-server/src/codex_message_processor.rs | 15 ++++++---- codex-rs/cli/src/login.rs | 8 ++--- codex-rs/core/src/auth.rs | 30 ++++++++++++------- codex-rs/core/src/client.rs | 8 ++--- codex-rs/core/src/codex.rs | 10 ++++--- codex-rs/core/src/models_manager/manager.rs | 13 ++++---- codex-rs/core/tests/responses_headers.rs | 11 +++---- codex-rs/core/tests/suite/client.rs | 3 +- .../core/tests/suite/client_websockets.rs | 3 +- codex-rs/otel/Cargo.toml | 1 - codex-rs/otel/src/lib.rs | 7 +++++ codex-rs/otel/src/traces/otel_manager.rs | 4 +-- codex-rs/otel/tests/suite/manager_metrics.rs | 11 ++++--- codex-rs/otel/tests/suite/runtime_summary.rs | 4 +-- codex-rs/otel/tests/suite/snapshot.rs | 9 ++++-- codex-rs/tui/src/app.rs | 6 +++- codex-rs/tui/src/lib.rs | 4 +-- codex-rs/tui/src/onboarding/auth.rs | 7 ++--- codex-rs/tui/src/status/helpers.rs | 8 ++--- 20 files changed, 92 insertions(+), 71 deletions(-) diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 4e1758355..e90b25ee9 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -1917,7 +1917,6 @@ version = "0.0.0" dependencies = [ "chrono", "codex-api", - "codex-app-server-protocol", "codex-protocol", "codex-utils-absolute-path", "codex-utils-string", diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index 6c0956acf..ea60d2087 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -152,6 +152,7 @@ use codex_core::SessionMeta; use codex_core::ThreadConfigSnapshot; use codex_core::ThreadManager; use codex_core::ThreadSortKey as CoreThreadSortKey; +use codex_core::auth::AuthMode as CoreAuthMode; use codex_core::auth::CLIENT_ID; use codex_core::auth::login_with_api_key; use codex_core::auth::login_with_chatgpt_auth_tokens; @@ -1188,7 +1189,7 @@ impl CodexMessageProcessor { .await; let payload_v2 = AccountUpdatedNotification { - auth_mode: self.auth_manager.get_auth_mode(), + auth_mode: self.auth_manager.get_api_auth_mode(), }; self.outgoing .send_server_notification(ServerNotification::AccountUpdated(payload_v2)) @@ -1336,14 +1337,16 @@ impl CodexMessageProcessor { } let account = match self.auth_manager.auth_cached() { - Some(auth) => Some(match auth { - CodexAuth::ApiKey(_) => Account::ApiKey {}, - CodexAuth::Chatgpt(_) | CodexAuth::ChatgptAuthTokens(_) => { + Some(auth) => match auth.auth_mode() { + CoreAuthMode::ApiKey => Some(Account::ApiKey {}), + CoreAuthMode::Chatgpt => { let email = auth.get_account_email(); let plan_type = auth.account_plan_type(); match (email, plan_type) { - (Some(email), Some(plan_type)) => Account::Chatgpt { email, plan_type }, + (Some(email), Some(plan_type)) => { + Some(Account::Chatgpt { email, plan_type }) + } _ => { let error = JSONRPCErrorError { code: INVALID_REQUEST_ERROR_CODE, @@ -1357,7 +1360,7 @@ impl CodexMessageProcessor { } } } - }), + }, None => None, }; diff --git a/codex-rs/cli/src/login.rs b/codex-rs/cli/src/login.rs index 01a830acb..8cb6f3d01 100644 --- a/codex-rs/cli/src/login.rs +++ b/codex-rs/cli/src/login.rs @@ -1,7 +1,7 @@ -use codex_app_server_protocol::AuthMode; use codex_common::CliConfigOverrides; use codex_core::CodexAuth; use codex_core::auth::AuthCredentialsStoreMode; +use codex_core::auth::AuthMode; use codex_core::auth::CLIENT_ID; use codex_core::auth::login_with_api_key; use codex_core::auth::logout; @@ -225,7 +225,7 @@ pub async fn run_login_status(cli_config_overrides: CliConfigOverrides) -> ! { let config = load_config_or_exit(cli_config_overrides).await; match CodexAuth::from_auth_storage(&config.codex_home, config.cli_auth_credentials_store_mode) { - Ok(Some(auth)) => match auth.api_auth_mode() { + Ok(Some(auth)) => match auth.auth_mode() { AuthMode::ApiKey => match auth.get_token() { Ok(api_key) => { eprintln!("Logged in using an API key - {}", safe_format_key(&api_key)); @@ -240,10 +240,6 @@ pub async fn run_login_status(cli_config_overrides: CliConfigOverrides) -> ! { eprintln!("Logged in using ChatGPT"); std::process::exit(0); } - AuthMode::ChatgptAuthTokens => { - eprintln!("Logged in using ChatGPT (external tokens)"); - std::process::exit(0); - } }, Ok(None) => { eprintln!("Not logged in"); diff --git a/codex-rs/core/src/auth.rs b/codex-rs/core/src/auth.rs index fb4114a7c..7e58ff125 100644 --- a/codex-rs/core/src/auth.rs +++ b/codex-rs/core/src/auth.rs @@ -16,6 +16,7 @@ use std::sync::Mutex; use std::sync::RwLock; use codex_app_server_protocol::AuthMode as ApiAuthMode; +use codex_otel::TelemetryAuthMode; use codex_protocol::config_types::ForcedLoginMethod; pub use crate::auth::storage::AuthCredentialsStoreMode; @@ -47,6 +48,15 @@ pub enum AuthMode { Chatgpt, } +impl From for TelemetryAuthMode { + fn from(mode: AuthMode) -> Self { + match mode { + AuthMode::ApiKey => TelemetryAuthMode::ApiKey, + AuthMode::Chatgpt => TelemetryAuthMode::Chatgpt, + } + } +} + /// Authentication mechanism used by the current user. #[derive(Debug, Clone)] pub enum CodexAuth { @@ -186,7 +196,7 @@ impl CodexAuth { load_auth(codex_home, false, auth_credentials_store_mode) } - pub fn internal_auth_mode(&self) -> AuthMode { + pub fn auth_mode(&self) -> AuthMode { match self { Self::ApiKey(_) => AuthMode::ApiKey, Self::Chatgpt(_) | Self::ChatgptAuthTokens(_) => AuthMode::Chatgpt, @@ -202,14 +212,14 @@ impl CodexAuth { } pub fn is_chatgpt_auth(&self) -> bool { - self.internal_auth_mode() == AuthMode::Chatgpt + self.auth_mode() == AuthMode::Chatgpt } pub fn is_external_chatgpt_tokens(&self) -> bool { matches!(self, Self::ChatgptAuthTokens(_)) } - /// Returns `None` is `is_internal_auth_mode() != AuthMode::ApiKey`. + /// Returns `None` if `auth_mode() != AuthMode::ApiKey`. pub fn api_key(&self) -> Option<&str> { match self { Self::ApiKey(auth) => Some(auth.api_key.as_str()), @@ -434,7 +444,7 @@ pub fn enforce_login_restrictions(config: &Config) -> std::io::Result<()> { }; if let Some(required_method) = config.forced_login_method { - let method_violation = match (required_method, auth.internal_auth_mode()) { + let method_violation = match (required_method, auth.auth_mode()) { (ForcedLoginMethod::Api, AuthMode::ApiKey) => None, (ForcedLoginMethod::Chatgpt, AuthMode::Chatgpt) => None, (ForcedLoginMethod::Api, AuthMode::Chatgpt) => Some( @@ -1158,14 +1168,12 @@ impl AuthManager { Ok(removed) } - pub fn get_auth_mode(&self) -> Option { + pub fn get_api_auth_mode(&self) -> Option { self.auth_cached().as_ref().map(CodexAuth::api_auth_mode) } - pub fn get_internal_auth_mode(&self) -> Option { - self.auth_cached() - .as_ref() - .map(CodexAuth::internal_auth_mode) + pub fn auth_mode(&self) -> Option { + self.auth_cached().as_ref().map(CodexAuth::auth_mode) } async fn refresh_if_stale(&self, auth: &CodexAuth) -> Result { @@ -1373,7 +1381,7 @@ mod tests { .unwrap() .unwrap(); assert_eq!(None, auth.api_key()); - assert_eq!(AuthMode::Chatgpt, auth.internal_auth_mode()); + assert_eq!(AuthMode::Chatgpt, auth.auth_mode()); let auth_dot_json = auth .get_current_auth_json() @@ -1418,7 +1426,7 @@ mod tests { let auth = super::load_auth(dir.path(), false, AuthCredentialsStoreMode::File) .unwrap() .unwrap(); - assert_eq!(auth.internal_auth_mode(), AuthMode::ApiKey); + assert_eq!(auth.auth_mode(), AuthMode::ApiKey); assert_eq!(auth.api_key(), Some("sk-test-key")); assert!(auth.get_token_data().is_err()); diff --git a/codex-rs/core/src/client.rs b/codex-rs/core/src/client.rs index 570cdc830..5acb3d6da 100644 --- a/codex-rs/core/src/client.rs +++ b/codex-rs/core/src/client.rs @@ -225,7 +225,7 @@ impl ModelClient { let api_provider = self .state .provider - .to_api_provider(auth.as_ref().map(CodexAuth::internal_auth_mode))?; + .to_api_provider(auth.as_ref().map(CodexAuth::auth_mode))?; let api_auth = auth_provider_from_auth(auth.clone(), &self.state.provider)?; let transport = ReqwestTransport::new(build_reqwest_client()); let request_telemetry = Self::build_request_telemetry(otel_manager); @@ -271,7 +271,7 @@ impl ModelClient { let api_provider = self .state .provider - .to_api_provider(auth.as_ref().map(CodexAuth::internal_auth_mode))?; + .to_api_provider(auth.as_ref().map(CodexAuth::auth_mode))?; let api_auth = auth_provider_from_auth(auth, &self.state.provider)?; let transport = ReqwestTransport::new(build_reqwest_client()); let request_telemetry = Self::build_request_telemetry(otel_manager); @@ -557,7 +557,7 @@ impl ModelClientSession { .client .state .provider - .to_api_provider(auth.as_ref().map(CodexAuth::internal_auth_mode))?; + .to_api_provider(auth.as_ref().map(CodexAuth::auth_mode))?; let api_auth = auth_provider_from_auth(auth.clone(), &self.client.state.provider)?; let transport = ReqwestTransport::new(build_reqwest_client()); let (request_telemetry, sse_telemetry) = Self::build_streaming_telemetry(otel_manager); @@ -622,7 +622,7 @@ impl ModelClientSession { .client .state .provider - .to_api_provider(auth.as_ref().map(CodexAuth::internal_auth_mode))?; + .to_api_provider(auth.as_ref().map(CodexAuth::auth_mode))?; let api_auth = auth_provider_from_auth(auth.clone(), &self.client.state.provider)?; let compression = self.responses_request_compression(auth.as_ref()); diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index 95c13ec9d..77d6d6a73 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -207,6 +207,7 @@ use crate::util::backoff; use crate::windows_sandbox::WindowsSandboxLevelExt; use codex_async_utils::OrCancelExt; use codex_otel::OtelManager; +use codex_otel::TelemetryAuthMode; use codex_protocol::config_types::CollaborationMode; use codex_protocol::config_types::Personality; use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig; @@ -949,13 +950,14 @@ impl Session { maybe_push_unstable_features_warning(&config, &mut post_session_configured_events); let auth = auth.as_ref(); + let auth_mode = auth.map(CodexAuth::auth_mode).map(TelemetryAuthMode::from); let otel_manager = OtelManager::new( conversation_id, session_configuration.collaboration_mode.model(), session_configuration.collaboration_mode.model(), auth.and_then(CodexAuth::get_account_id), auth.and_then(CodexAuth::get_account_email), - auth.map(CodexAuth::api_auth_mode), + auth_mode, config.otel.log_user_prompt, terminal::user_agent(), session_configuration.session_source.clone(), @@ -4518,7 +4520,7 @@ async fn try_run_sampling_request( approval_policy = turn_context.approval_policy, sandbox_policy = turn_context.sandbox_policy, effort = turn_context.reasoning_effort, - auth_mode = sess.services.auth_manager.get_auth_mode(), + auth_mode = sess.services.auth_manager.auth_mode(), features = sess.features.enabled_features(), ); @@ -4842,7 +4844,7 @@ mod tests { use crate::tools::registry::ToolHandler; use crate::turn_diff_tracker::TurnDiffTracker; use codex_app_server_protocol::AppInfo; - use codex_app_server_protocol::AuthMode; + use codex_otel::TelemetryAuthMode; use codex_protocol::models::BaseInstructions; use codex_protocol::models::ContentItem; use codex_protocol::models::ResponseInputItem; @@ -5652,7 +5654,7 @@ mod tests { model_info.slug.as_str(), None, Some("test@test.com".to_string()), - Some(AuthMode::Chatgpt), + Some(TelemetryAuthMode::Chatgpt), false, "test".to_string(), session_source, diff --git a/codex-rs/core/src/models_manager/manager.rs b/codex-rs/core/src/models_manager/manager.rs index fffc28073..2d8518507 100644 --- a/codex-rs/core/src/models_manager/manager.rs +++ b/codex-rs/core/src/models_manager/manager.rs @@ -61,7 +61,7 @@ impl ModelsManager { let cache_path = codex_home.join(MODEL_CACHE_FILE); let cache_manager = ModelsCacheManager::new(cache_path, DEFAULT_MODEL_CACHE_TTL); Self { - local_models: builtin_model_presets(auth_manager.get_internal_auth_mode()), + local_models: builtin_model_presets(auth_manager.auth_mode()), remote_models: RwLock::new(Self::load_remote_models_from_file().unwrap_or_default()), auth_manager, etag: RwLock::new(None), @@ -175,7 +175,7 @@ impl ModelsManager { refresh_strategy: RefreshStrategy, ) -> CoreResult<()> { if !config.features.enabled(Feature::RemoteModels) - || self.auth_manager.get_internal_auth_mode() == Some(AuthMode::ApiKey) + || self.auth_manager.auth_mode() == Some(AuthMode::ApiKey) { return Ok(()); } @@ -204,7 +204,7 @@ impl ModelsManager { let _timer = codex_otel::start_global_timer("codex.remote_models.fetch_update.duration_ms", &[]); let auth = self.auth_manager.auth().await; - let auth_mode = self.auth_manager.get_internal_auth_mode(); + let auth_mode = self.auth_manager.auth_mode(); let api_provider = self.provider.to_api_provider(auth_mode)?; let api_auth = auth_provider_from_auth(auth.clone(), &self.provider)?; let transport = ReqwestTransport::new(build_reqwest_client()); @@ -275,10 +275,7 @@ impl ModelsManager { let remote_presets: Vec = remote_models.into_iter().map(Into::into).collect(); let existing_presets = self.local_models.clone(); let mut merged_presets = ModelPreset::merge(remote_presets, existing_presets); - let chatgpt_mode = matches!( - self.auth_manager.get_internal_auth_mode(), - Some(AuthMode::Chatgpt) - ); + let chatgpt_mode = matches!(self.auth_manager.auth_mode(), Some(AuthMode::Chatgpt)); merged_presets = ModelPreset::filter_by_auth(merged_presets, chatgpt_mode); for preset in &mut merged_presets { @@ -322,7 +319,7 @@ impl ModelsManager { let cache_path = codex_home.join(MODEL_CACHE_FILE); let cache_manager = ModelsCacheManager::new(cache_path, DEFAULT_MODEL_CACHE_TTL); Self { - local_models: builtin_model_presets(auth_manager.get_internal_auth_mode()), + local_models: builtin_model_presets(auth_manager.auth_mode()), remote_models: RwLock::new(Self::load_remote_models_from_file().unwrap_or_default()), auth_manager, etag: RwLock::new(None), diff --git a/codex-rs/core/tests/responses_headers.rs b/codex-rs/core/tests/responses_headers.rs index 9e70264bf..04cfdc037 100644 --- a/codex-rs/core/tests/responses_headers.rs +++ b/codex-rs/core/tests/responses_headers.rs @@ -1,7 +1,6 @@ use std::process::Command; use std::sync::Arc; -use codex_app_server_protocol::AuthMode; use codex_core::AuthManager; use codex_core::CodexAuth; use codex_core::ContentItem; @@ -14,6 +13,7 @@ use codex_core::WEB_SEARCH_ELIGIBLE_HEADER; use codex_core::WireApi; use codex_core::models_manager::manager::ModelsManager; use codex_otel::OtelManager; +use codex_otel::TelemetryAuthMode; use codex_protocol::ThreadId; use codex_protocol::config_types::ReasoningSummary; use codex_protocol::config_types::WebSearchMode; @@ -72,7 +72,7 @@ async fn responses_stream_includes_subagent_header_on_review() { let config = Arc::new(config); let conversation_id = ThreadId::new(); - let auth_mode = AuthMode::Chatgpt; + let auth_mode = TelemetryAuthMode::Chatgpt; let session_source = SessionSource::SubAgent(SubAgentSource::Review); let model_info = ModelsManager::construct_model_info_offline(model.as_str(), &config); let otel_manager = OtelManager::new( @@ -182,7 +182,7 @@ async fn responses_stream_includes_subagent_header_on_other() { let config = Arc::new(config); let conversation_id = ThreadId::new(); - let auth_mode = AuthMode::Chatgpt; + let auth_mode = TelemetryAuthMode::Chatgpt; let session_source = SessionSource::SubAgent(SubAgentSource::Other("my-task".to_string())); let model_info = ModelsManager::construct_model_info_offline(model.as_str(), &config); @@ -350,8 +350,9 @@ async fn responses_respects_model_info_overrides_from_config() { let config = Arc::new(config); let conversation_id = ThreadId::new(); - let auth_mode = - AuthManager::from_auth_for_testing(CodexAuth::from_api_key("Test API Key")).get_auth_mode(); + let auth_mode = AuthManager::from_auth_for_testing(CodexAuth::from_api_key("Test API Key")) + .auth_mode() + .map(TelemetryAuthMode::from); let session_source = SessionSource::SubAgent(SubAgentSource::Other("override-check".to_string())); let model_info = ModelsManager::construct_model_info_offline(model.as_str(), &config); diff --git a/codex-rs/core/tests/suite/client.rs b/codex-rs/core/tests/suite/client.rs index 731ce97c0..7debde217 100644 --- a/codex-rs/core/tests/suite/client.rs +++ b/codex-rs/core/tests/suite/client.rs @@ -21,6 +21,7 @@ use codex_core::protocol::EventMsg; use codex_core::protocol::Op; use codex_core::protocol::SessionSource; use codex_otel::OtelManager; +use codex_otel::TelemetryAuthMode; use codex_protocol::ThreadId; use codex_protocol::config_types::CollaborationMode; use codex_protocol::config_types::ModeKind; @@ -1257,7 +1258,7 @@ async fn azure_responses_request_includes_store_and_reasoning_ids() { model_info.slug.as_str(), None, Some("test@test.com".to_string()), - auth_manager.get_auth_mode(), + auth_manager.auth_mode().map(TelemetryAuthMode::from), false, "test".to_string(), SessionSource::Exec, diff --git a/codex-rs/core/tests/suite/client_websockets.rs b/codex-rs/core/tests/suite/client_websockets.rs index e3a1ef0a8..f78b7b1a3 100644 --- a/codex-rs/core/tests/suite/client_websockets.rs +++ b/codex-rs/core/tests/suite/client_websockets.rs @@ -14,6 +14,7 @@ use codex_core::features::Feature; use codex_core::models_manager::manager::ModelsManager; use codex_core::protocol::SessionSource; use codex_otel::OtelManager; +use codex_otel::TelemetryAuthMode; use codex_otel::metrics::MetricsClient; use codex_otel::metrics::MetricsConfig; use codex_protocol::ThreadId; @@ -446,7 +447,7 @@ async fn websocket_harness_with_runtime_metrics( model_info.slug.as_str(), None, Some("test@test.com".to_string()), - auth_manager.get_auth_mode(), + auth_manager.auth_mode().map(TelemetryAuthMode::from), false, "test".to_string(), SessionSource::Exec, diff --git a/codex-rs/otel/Cargo.toml b/codex-rs/otel/Cargo.toml index c0bcb365b..6e6321d2e 100644 --- a/codex-rs/otel/Cargo.toml +++ b/codex-rs/otel/Cargo.toml @@ -21,7 +21,6 @@ disable-default-metrics-exporter = [] [dependencies] chrono = { workspace = true } -codex-app-server-protocol = { workspace = true } codex-utils-absolute-path = { workspace = true } codex-utils-string = { workspace = true } codex-api = { workspace = true } diff --git a/codex-rs/otel/src/lib.rs b/codex-rs/otel/src/lib.rs index ed6e5a1c9..a86e5ef52 100644 --- a/codex-rs/otel/src/lib.rs +++ b/codex-rs/otel/src/lib.rs @@ -31,6 +31,13 @@ pub enum ToolDecisionSource { User, } +/// Maps to core AuthMode to avoid a circular dependency on codex-core. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)] +pub enum TelemetryAuthMode { + ApiKey, + Chatgpt, +} + #[derive(Debug, Clone)] pub struct OtelEventMetadata { pub(crate) conversation_id: ThreadId, diff --git a/codex-rs/otel/src/traces/otel_manager.rs b/codex-rs/otel/src/traces/otel_manager.rs index bde9515c2..b174dabe6 100644 --- a/codex-rs/otel/src/traces/otel_manager.rs +++ b/codex-rs/otel/src/traces/otel_manager.rs @@ -1,3 +1,4 @@ +use crate::TelemetryAuthMode; use crate::metrics::names::API_CALL_COUNT_METRIC; use crate::metrics::names::API_CALL_DURATION_METRIC; use crate::metrics::names::RESPONSES_API_INFERENCE_TIME_DURATION_METRIC; @@ -15,7 +16,6 @@ use chrono::SecondsFormat; use chrono::Utc; use codex_api::ApiError; use codex_api::ResponseEvent; -use codex_app_server_protocol::AuthMode; use codex_protocol::ThreadId; use codex_protocol::config_types::ReasoningSummary; use codex_protocol::models::ResponseItem; @@ -57,7 +57,7 @@ impl OtelManager { slug: &str, account_id: Option, account_email: Option, - auth_mode: Option, + auth_mode: Option, log_user_prompts: bool, terminal_type: String, session_source: SessionSource, diff --git a/codex-rs/otel/tests/suite/manager_metrics.rs b/codex-rs/otel/tests/suite/manager_metrics.rs index ad98543bc..164bb43b3 100644 --- a/codex-rs/otel/tests/suite/manager_metrics.rs +++ b/codex-rs/otel/tests/suite/manager_metrics.rs @@ -2,8 +2,8 @@ use crate::harness::attributes_to_map; use crate::harness::build_metrics_with_defaults; use crate::harness::find_metric; use crate::harness::latest_metrics; -use codex_app_server_protocol::AuthMode; use codex_otel::OtelManager; +use codex_otel::TelemetryAuthMode; use codex_otel::metrics::Result; use codex_protocol::ThreadId; use codex_protocol::protocol::SessionSource; @@ -22,7 +22,7 @@ fn manager_attaches_metadata_tags_to_metrics() -> Result<()> { "gpt-5.1", Some("account-id".to_string()), None, - Some(AuthMode::ApiKey), + Some(TelemetryAuthMode::ApiKey), true, "tty".to_string(), SessionSource::Cli, @@ -52,7 +52,10 @@ fn manager_attaches_metadata_tags_to_metrics() -> Result<()> { "app.version".to_string(), env!("CARGO_PKG_VERSION").to_string(), ), - ("auth_mode".to_string(), AuthMode::ApiKey.to_string()), + ( + "auth_mode".to_string(), + TelemetryAuthMode::ApiKey.to_string(), + ), ("model".to_string(), "gpt-5.1".to_string()), ("service".to_string(), "codex-cli".to_string()), ("session_source".to_string(), "cli".to_string()), @@ -73,7 +76,7 @@ fn manager_allows_disabling_metadata_tags() -> Result<()> { "gpt-4o", Some("account-id".to_string()), None, - Some(AuthMode::ApiKey), + Some(TelemetryAuthMode::ApiKey), true, "tty".to_string(), SessionSource::Cli, diff --git a/codex-rs/otel/tests/suite/runtime_summary.rs b/codex-rs/otel/tests/suite/runtime_summary.rs index 811c801fc..71d9a140c 100644 --- a/codex-rs/otel/tests/suite/runtime_summary.rs +++ b/codex-rs/otel/tests/suite/runtime_summary.rs @@ -1,7 +1,7 @@ -use codex_app_server_protocol::AuthMode; use codex_otel::OtelManager; use codex_otel::RuntimeMetricTotals; use codex_otel::RuntimeMetricsSummary; +use codex_otel::TelemetryAuthMode; use codex_otel::metrics::MetricsClient; use codex_otel::metrics::MetricsConfig; use codex_otel::metrics::Result; @@ -26,7 +26,7 @@ fn runtime_metrics_summary_collects_tool_api_and_streaming_metrics() -> Result<( "gpt-5.1", Some("account-id".to_string()), None, - Some(AuthMode::ApiKey), + Some(TelemetryAuthMode::ApiKey), true, "tty".to_string(), SessionSource::Cli, diff --git a/codex-rs/otel/tests/suite/snapshot.rs b/codex-rs/otel/tests/suite/snapshot.rs index f0a7a18c5..aa7990d06 100644 --- a/codex-rs/otel/tests/suite/snapshot.rs +++ b/codex-rs/otel/tests/suite/snapshot.rs @@ -1,7 +1,7 @@ use crate::harness::attributes_to_map; use crate::harness::find_metric; -use codex_app_server_protocol::AuthMode; use codex_otel::OtelManager; +use codex_otel::TelemetryAuthMode; use codex_otel::metrics::MetricsClient; use codex_otel::metrics::MetricsConfig; use codex_otel::metrics::Result; @@ -75,7 +75,7 @@ fn manager_snapshot_metrics_collects_without_shutdown() -> Result<()> { "gpt-5.1", Some("account-id".to_string()), None, - Some(AuthMode::ApiKey), + Some(TelemetryAuthMode::ApiKey), true, "tty".to_string(), SessionSource::Cli, @@ -107,7 +107,10 @@ fn manager_snapshot_metrics_collects_without_shutdown() -> Result<()> { "app.version".to_string(), env!("CARGO_PKG_VERSION").to_string(), ), - ("auth_mode".to_string(), AuthMode::ApiKey.to_string()), + ( + "auth_mode".to_string(), + TelemetryAuthMode::ApiKey.to_string(), + ), ("model".to_string(), "gpt-5.1".to_string()), ("service".to_string(), "codex-cli".to_string()), ("session_source".to_string(), "cli".to_string()), diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs index 8c3bd5188..8ef4283c6 100644 --- a/codex-rs/tui/src/app.rs +++ b/codex-rs/tui/src/app.rs @@ -60,6 +60,7 @@ use codex_core::protocol::TokenUsage; #[cfg(target_os = "windows")] use codex_core::windows_sandbox::WindowsSandboxLevelExt; use codex_otel::OtelManager; +use codex_otel::TelemetryAuthMode; use codex_protocol::ThreadId; use codex_protocol::config_types::Personality; #[cfg(target_os = "windows")] @@ -975,13 +976,16 @@ impl App { } else { FeedbackAudience::External }; + let auth_mode = auth_ref + .map(CodexAuth::auth_mode) + .map(TelemetryAuthMode::from); let otel_manager = OtelManager::new( ThreadId::new(), model.as_str(), model.as_str(), auth_ref.and_then(CodexAuth::get_account_id), auth_ref.and_then(CodexAuth::get_account_email), - auth_ref.map(CodexAuth::api_auth_mode), + auth_mode, config.otel.log_user_prompt, codex_core::terminal::user_agent(), SessionSource::Cli, diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs index 95e26fe67..daabb6027 100644 --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs @@ -7,7 +7,6 @@ use additional_dirs::add_dir_warning_message; use app::App; pub use app::AppExitInfo; pub use app::ExitReason; -use codex_app_server_protocol::AuthMode; use codex_cloud_requirements::cloud_requirements_loader; use codex_common::oss::ensure_oss_provider_ready; use codex_common::oss::get_default_model_for_oss_provider; @@ -16,6 +15,7 @@ use codex_core::CodexAuth; use codex_core::INTERACTIVE_SESSION_SOURCES; use codex_core::RolloutRecorder; use codex_core::ThreadSortKey; +use codex_core::auth::AuthMode; use codex_core::auth::enforce_login_restrictions; use codex_core::config::Config; use codex_core::config::ConfigBuilder; @@ -841,7 +841,7 @@ fn get_login_status(config: &Config) -> LoginStatus { // to refresh the token. Block on it. let codex_home = config.codex_home.clone(); match CodexAuth::from_auth_storage(&codex_home, config.cli_auth_credentials_store_mode) { - Ok(Some(auth)) => LoginStatus::AuthMode(auth.api_auth_mode()), + Ok(Some(auth)) => LoginStatus::AuthMode(auth.auth_mode()), Ok(None) => LoginStatus::NotAuthenticated, Err(err) => { error!("Failed to read auth.json: {err}"); diff --git a/codex-rs/tui/src/onboarding/auth.rs b/codex-rs/tui/src/onboarding/auth.rs index 7378b6628..c639d24a0 100644 --- a/codex-rs/tui/src/onboarding/auth.rs +++ b/codex-rs/tui/src/onboarding/auth.rs @@ -30,7 +30,7 @@ use ratatui::widgets::Paragraph; use ratatui::widgets::WidgetRef; use ratatui::widgets::Wrap; -use codex_app_server_protocol::AuthMode; +use codex_core::auth::AuthMode; use codex_protocol::config_types::ForcedLoginMethod; use std::sync::RwLock; @@ -661,10 +661,7 @@ impl AuthModeWidget { } fn handle_existing_chatgpt_login(&mut self) -> bool { - if matches!( - self.login_status, - LoginStatus::AuthMode(AuthMode::Chatgpt | AuthMode::ChatgptAuthTokens) - ) { + if matches!(self.login_status, LoginStatus::AuthMode(AuthMode::Chatgpt)) { *self.sign_in_state.write().unwrap() = SignInState::ChatGptSuccess; self.request_frame.schedule_frame(); true diff --git a/codex-rs/tui/src/status/helpers.rs b/codex-rs/tui/src/status/helpers.rs index bc4cbb9c1..c81940541 100644 --- a/codex-rs/tui/src/status/helpers.rs +++ b/codex-rs/tui/src/status/helpers.rs @@ -3,7 +3,7 @@ use crate::text_formatting; use chrono::DateTime; use chrono::Local; use codex_core::AuthManager; -use codex_core::CodexAuth; +use codex_core::auth::AuthMode as CoreAuthMode; use codex_core::config::Config; use codex_core::project_doc::discover_project_doc_paths; use codex_protocol::account::PlanType; @@ -90,15 +90,15 @@ pub(crate) fn compose_account_display( ) -> Option { let auth = auth_manager.auth_cached()?; - match auth { - CodexAuth::Chatgpt(_) | CodexAuth::ChatgptAuthTokens(_) => { + match auth.auth_mode() { + CoreAuthMode::ApiKey => Some(StatusAccountDisplay::ApiKey), + CoreAuthMode::Chatgpt => { let email = auth.get_account_email(); let plan = plan .map(|plan_type| title_case(format!("{plan_type:?}").as_str())) .or_else(|| Some("Unknown".to_string())); Some(StatusAccountDisplay::ChatGpt { email, plan }) } - CodexAuth::ApiKey(_) => Some(StatusAccountDisplay::ApiKey), } }