[codex] add ChatGPT HTTP state adapter [ci changed_files]

This commit is contained in:
Cooper Gamble
2026-06-03 07:46:15 +00:00
parent 2fbbd204b4
commit 0fc80189bf
6 changed files with 70 additions and 17 deletions

1
codex-rs/Cargo.lock generated
View File

@@ -2230,6 +2230,7 @@ dependencies = [
"codex-core",
"codex-core-plugins",
"codex-git-utils",
"codex-http-state",
"codex-login",
"codex-model-provider",
"codex-plugin",

View File

@@ -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 }

View File

@@ -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<T: DeserializeOwned>(
pub(crate) async fn chatgpt_get_request_with_http_state<T: DeserializeOwned>(
config: &Config,
path: String,
http_state: HttpStateContext,
) -> anyhow::Result<T> {
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<T: DeserializeOwned>(
pub(crate) async fn chatgpt_get_request_with_timeout_and_http_state<T: DeserializeOwned>(
config: &Config,
path: String,
timeout: Option<Duration>,
http_state: Option<HttpStateContext>,
) -> anyhow::Result<T> {
let chatgpt_base_url = &config.chatgpt_base_url;
let auth_manager =
@@ -46,9 +54,16 @@ pub(crate) async fn chatgpt_get_request_with_timeout<T: DeserializeOwned>(
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<T: DeserializeOwned>(
}
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

View File

@@ -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<Vec<AppInfo>>
pub async fn list_all_connectors_with_options(
config: &Config,
force_refetch: bool,
) -> anyhow::Result<Vec<AppInfo>> {
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<HttpStateContext>,
) -> anyhow::Result<Vec<AppInfo>> {
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::<DirectoryListResponse>(
config,
path,
Some(DIRECTORY_CONNECTORS_TIMEOUT),
)
.await
|path| {
let http_state = http_state.clone();
async move {
chatgpt_get_request_with_timeout_and_http_state::<DirectoryListResponse>(
config,
path,
Some(DIRECTORY_CONNECTORS_TIMEOUT),
http_state,
)
.await
}
},
)
.await?;

View File

@@ -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<GetTaskResponse> {
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
}

View File

@@ -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<bool> {
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<HttpStateContext>,
) -> anyhow::Result<bool> {
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?;