From 0fc80189bfa63a52608a4ebede070637599062ed Mon Sep 17 00:00:00 2001 From: Cooper Gamble Date: Wed, 3 Jun 2026 07:46:15 +0000 Subject: [PATCH] [codex] add ChatGPT HTTP state adapter [ci changed_files] --- codex-rs/Cargo.lock | 1 + codex-rs/chatgpt/Cargo.toml | 1 + codex-rs/chatgpt/src/chatgpt_client.rs | 26 +++++++++++++++---- codex-rs/chatgpt/src/connectors.rs | 30 ++++++++++++++++------ codex-rs/chatgpt/src/get_task.rs | 11 ++++++-- codex-rs/chatgpt/src/workspace_settings.rs | 18 +++++++++++-- 6 files changed, 70 insertions(+), 17 deletions(-) diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index b1836a2aaa..f387d2c1ac 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -2230,6 +2230,7 @@ dependencies = [ "codex-core", "codex-core-plugins", "codex-git-utils", + "codex-http-state", "codex-login", "codex-model-provider", "codex-plugin", diff --git a/codex-rs/chatgpt/Cargo.toml b/codex-rs/chatgpt/Cargo.toml index 6b0e010964..289d8f92a7 100644 --- a/codex-rs/chatgpt/Cargo.toml +++ b/codex-rs/chatgpt/Cargo.toml @@ -15,6 +15,7 @@ codex-connectors = { workspace = true } codex-core = { workspace = true } codex-core-plugins = { workspace = true } codex-git-utils = { workspace = true } +codex-http-state = { workspace = true } codex-login = { workspace = true } codex-model-provider = { workspace = true } codex-plugin = { workspace = true } diff --git a/codex-rs/chatgpt/src/chatgpt_client.rs b/codex-rs/chatgpt/src/chatgpt_client.rs index 372f62e696..76e7e65fea 100644 --- a/codex-rs/chatgpt/src/chatgpt_client.rs +++ b/codex-rs/chatgpt/src/chatgpt_client.rs @@ -1,4 +1,5 @@ use codex_core::config::Config; +use codex_http_state::HttpStateContext; use codex_login::AuthManager; use codex_login::default_client::create_client; @@ -9,18 +10,25 @@ use std::time::Duration; const OAI_PRODUCT_SKU_HEADER: &str = "OAI-Product-Sku"; const CODEX_PRODUCT_SKU: &str = "codex"; -/// Make a GET request to the ChatGPT backend API. -pub(crate) async fn chatgpt_get_request( +pub(crate) async fn chatgpt_get_request_with_http_state( config: &Config, path: String, + http_state: HttpStateContext, ) -> anyhow::Result { - chatgpt_get_request_with_timeout(config, path, /*timeout*/ None).await + chatgpt_get_request_with_timeout_and_http_state( + config, + path, + /*timeout*/ None, + Some(http_state), + ) + .await } -pub(crate) async fn chatgpt_get_request_with_timeout( +pub(crate) async fn chatgpt_get_request_with_timeout_and_http_state( config: &Config, path: String, timeout: Option, + http_state: Option, ) -> anyhow::Result { let chatgpt_base_url = &config.chatgpt_base_url; let auth_manager = @@ -46,9 +54,16 @@ pub(crate) async fn chatgpt_get_request_with_timeout( path.trim_start_matches('/') ); + let auth_provider = codex_model_provider::with_native_integrity_state( + codex_model_provider::auth_provider_from_auth(&auth), + Some(&auth), + http_state, + ); + let mut request_headers = Default::default(); + auth_provider.add_auth_headers_for_url(&url, &mut request_headers); let mut request = client .get(&url) - .headers(codex_model_provider::auth_provider_from_auth(&auth).to_auth_headers()) + .headers(request_headers.clone()) .header(OAI_PRODUCT_SKU_HEADER, CODEX_PRODUCT_SKU) .header("Content-Type", "application/json"); @@ -57,6 +72,7 @@ pub(crate) async fn chatgpt_get_request_with_timeout( } let response = request.send().await.context("Failed to send request")?; + auth_provider.observe_response_headers(&url, &request_headers, response.headers()); if response.status().is_success() { let result: T = response diff --git a/codex-rs/chatgpt/src/connectors.rs b/codex-rs/chatgpt/src/connectors.rs index 63b34e7355..c59e650df4 100644 --- a/codex-rs/chatgpt/src/connectors.rs +++ b/codex-rs/chatgpt/src/connectors.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::collections::HashSet; use std::time::Duration; -use crate::chatgpt_client::chatgpt_get_request_with_timeout; +use crate::chatgpt_client::chatgpt_get_request_with_timeout_and_http_state; use codex_app_server_protocol::AppInfo; use codex_connectors::ConnectorDirectoryCacheContext; @@ -19,6 +19,7 @@ pub use codex_core::connectors::list_accessible_connectors_from_mcp_tools_with_o pub use codex_core::connectors::list_cached_accessible_connectors_from_mcp_tools; pub use codex_core::connectors::with_app_enabled_state; use codex_core_plugins::PluginsManager; +use codex_http_state::HttpStateContext; use codex_login::AuthManager; use codex_login::CodexAuth; use codex_login::default_client::originator; @@ -95,6 +96,15 @@ pub async fn list_cached_all_connectors(config: &Config) -> Option> pub async fn list_all_connectors_with_options( config: &Config, force_refetch: bool, +) -> anyhow::Result> { + list_all_connectors_with_options_and_http_state(config, force_refetch, /*http_state*/ None) + .await +} + +pub async fn list_all_connectors_with_options_and_http_state( + config: &Config, + force_refetch: bool, + http_state: Option, ) -> anyhow::Result> { if !apps_enabled(config).await { return Ok(Vec::new()); @@ -105,13 +115,17 @@ pub async fn list_all_connectors_with_options( cache_context, auth.is_workspace_account(), force_refetch, - |path| async move { - chatgpt_get_request_with_timeout::( - config, - path, - Some(DIRECTORY_CONNECTORS_TIMEOUT), - ) - .await + |path| { + let http_state = http_state.clone(); + async move { + chatgpt_get_request_with_timeout_and_http_state::( + config, + path, + Some(DIRECTORY_CONNECTORS_TIMEOUT), + http_state, + ) + .await + } }, ) .await?; diff --git a/codex-rs/chatgpt/src/get_task.rs b/codex-rs/chatgpt/src/get_task.rs index 9301ffc38d..1aaede3388 100644 --- a/codex-rs/chatgpt/src/get_task.rs +++ b/codex-rs/chatgpt/src/get_task.rs @@ -1,7 +1,9 @@ use codex_core::config::Config; +use codex_http_state::HttpStateContext; +use codex_http_state::HttpStateSurface; use serde::Deserialize; -use crate::chatgpt_client::chatgpt_get_request; +use crate::chatgpt_client::chatgpt_get_request_with_http_state; #[derive(Debug, Deserialize)] pub struct GetTaskResponse { @@ -36,5 +38,10 @@ pub struct OutputDiff { pub(crate) async fn get_task(config: &Config, task_id: String) -> anyhow::Result { let path = format!("/wham/tasks/{task_id}"); - chatgpt_get_request(config, path).await + chatgpt_get_request_with_http_state( + config, + path, + HttpStateContext::new(config.codex_home.to_path_buf(), HttpStateSurface::CodexCli), + ) + .await } diff --git a/codex-rs/chatgpt/src/workspace_settings.rs b/codex-rs/chatgpt/src/workspace_settings.rs index a177215518..1383d0b0cf 100644 --- a/codex-rs/chatgpt/src/workspace_settings.rs +++ b/codex-rs/chatgpt/src/workspace_settings.rs @@ -5,10 +5,11 @@ use std::time::Instant; use anyhow::Context; use codex_core::config::Config; +use codex_http_state::HttpStateContext; use codex_login::CodexAuth; use serde::Deserialize; -use crate::chatgpt_client::chatgpt_get_request_with_timeout; +use crate::chatgpt_client::chatgpt_get_request_with_timeout_and_http_state; const WORKSPACE_SETTINGS_TIMEOUT: Duration = Duration::from_secs(10); const WORKSPACE_SETTINGS_CACHE_TTL: Duration = Duration::from_secs(15 * 60); @@ -85,6 +86,18 @@ pub async fn codex_plugins_enabled_for_workspace( config: &Config, auth: Option<&CodexAuth>, cache: Option<&WorkspaceSettingsCache>, +) -> anyhow::Result { + codex_plugins_enabled_for_workspace_with_http_state( + config, auth, cache, /*http_state*/ None, + ) + .await +} + +pub async fn codex_plugins_enabled_for_workspace_with_http_state( + config: &Config, + auth: Option<&CodexAuth>, + cache: Option<&WorkspaceSettingsCache>, + http_state: Option, ) -> anyhow::Result { let Some(auth) = auth else { return Ok(true); @@ -115,10 +128,11 @@ pub async fn codex_plugins_enabled_for_workspace( } let encoded_account_id = encode_path_segment(account_id); - let settings: WorkspaceSettingsResponse = chatgpt_get_request_with_timeout( + let settings: WorkspaceSettingsResponse = chatgpt_get_request_with_timeout_and_http_state( config, format!("/accounts/{encoded_account_id}/settings"), Some(WORKSPACE_SETTINGS_TIMEOUT), + http_state, ) .await?;