diff --git a/codex-rs/core/src/test_support.rs b/codex-rs/core/src/test_support.rs index 1db714fadaa8..44ab8c7617aa 100644 --- a/codex-rs/core/src/test_support.rs +++ b/codex-rs/core/src/test_support.rs @@ -11,6 +11,8 @@ use codex_exec_server::EnvironmentManager; use codex_extension_api::LoadUserInstructionsFuture; use codex_extension_api::LoadedUserInstructions; use codex_extension_api::UserInstructionsProvider; +use codex_http_client::HttpClientFactory; +use codex_http_client::OutboundProxyPolicy; use codex_login::AuthManager; use codex_login::CodexAuth; use codex_model_provider::create_model_provider; @@ -148,7 +150,11 @@ pub fn models_manager_with_provider( provider: ModelProviderInfo, ) -> SharedModelsManager { let provider = create_model_provider(provider, Some(auth_manager)); - provider.models_manager(codex_home, /*config_model_catalog*/ None) + provider.models_manager( + codex_home, + HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault), + /*config_model_catalog*/ None, + ) } pub fn get_model_offline(model: Option<&str>) -> String { diff --git a/codex-rs/core/src/thread_manager.rs b/codex-rs/core/src/thread_manager.rs index 4ea86cb33d00..cf19d0062d8d 100644 --- a/codex-rs/core/src/thread_manager.rs +++ b/codex-rs/core/src/thread_manager.rs @@ -32,6 +32,8 @@ use codex_extension_api::LoadedUserInstructions; use codex_extension_api::UserInstructionsProvider; use codex_extension_api::empty_extension_registry; use codex_features::Feature; +use codex_http_client::HttpClientFactory; +use codex_http_client::OutboundProxyPolicy; use codex_login::AuthManager; use codex_login::CodexAuth; use codex_login::default_client::CODEX_INTERNAL_ORIGINATOR_OVERRIDE_ENV_VAR; @@ -266,6 +268,7 @@ pub fn build_models_manager( let provider = create_model_provider(config.model_provider.clone(), Some(auth_manager)); provider.models_manager( config.codex_home.to_path_buf(), + config.http_client_factory(), config.model_catalog.clone(), ) } @@ -447,7 +450,11 @@ impl ThreadManager { threads: Arc::new(RwLock::new(HashMap::new())), thread_created_tx, models_manager: create_model_provider(provider, Some(auth_manager.clone())) - .models_manager(codex_home, /*config_model_catalog*/ None), + .models_manager( + codex_home, + HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault), + /*config_model_catalog*/ None, + ), environment_manager, skills_service, plugins_manager, diff --git a/codex-rs/memories/write/src/startup_tests.rs b/codex-rs/memories/write/src/startup_tests.rs index fad1ce14a425..b1e6ec492b54 100644 --- a/codex-rs/memories/write/src/startup_tests.rs +++ b/codex-rs/memories/write/src/startup_tests.rs @@ -10,6 +10,7 @@ use codex_git_utils::diff_since_latest_init; use codex_git_utils::reset_git_repository; use codex_login::AuthManager; use codex_login::CodexAuth; +use codex_model_provider::HttpClientFactory; use codex_model_provider::ModelProvider; use codex_model_provider::ModelProviderFuture; use codex_model_provider::ProviderAccountResult; @@ -627,10 +628,11 @@ impl ModelProvider for MockMemoryModelProvider { fn models_manager( &self, codex_home: PathBuf, + http_client_factory: HttpClientFactory, config_model_catalog: Option, ) -> codex_models_manager::manager::SharedModelsManager { self.delegate - .models_manager(codex_home, config_model_catalog) + .models_manager(codex_home, http_client_factory, config_model_catalog) } } diff --git a/codex-rs/model-provider/src/amazon_bedrock/mod.rs b/codex-rs/model-provider/src/amazon_bedrock/mod.rs index 108308c1bfae..b538b59c8454 100644 --- a/codex-rs/model-provider/src/amazon_bedrock/mod.rs +++ b/codex-rs/model-provider/src/amazon_bedrock/mod.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use codex_api::ApiError; use codex_api::Provider; use codex_api::SharedAuthProvider; +use codex_http_client::HttpClientFactory; use codex_login::AuthManager; use codex_login::CodexAuth; use codex_login::auth::BedrockApiKeyAuth; @@ -164,6 +165,7 @@ impl ModelProvider for AmazonBedrockModelProvider { fn models_manager( &self, _codex_home: PathBuf, + _http_client_factory: HttpClientFactory, config_model_catalog: Option, ) -> SharedModelsManager { Arc::new(StaticModelsManager::new( diff --git a/codex-rs/model-provider/src/lib.rs b/codex-rs/model-provider/src/lib.rs index 15967c4fe033..771bf97b8773 100644 --- a/codex-rs/model-provider/src/lib.rs +++ b/codex-rs/model-provider/src/lib.rs @@ -11,6 +11,7 @@ pub use auth::auth_provider_from_auth; pub use auth::unauthenticated_auth_provider; pub use bearer_auth_provider::BearerAuthProvider; pub use bearer_auth_provider::BearerAuthProvider as CoreAuthProvider; +pub use codex_http_client::HttpClientFactory; pub use codex_model_provider_info::CHATGPT_CODEX_BASE_URL; pub use codex_protocol::account::ProviderAccount; pub use provider::ModelProvider; diff --git a/codex-rs/model-provider/src/models_endpoint.rs b/codex-rs/model-provider/src/models_endpoint.rs index 9a203c26e1c2..1f04db72f38b 100644 --- a/codex-rs/model-provider/src/models_endpoint.rs +++ b/codex-rs/model-provider/src/models_endpoint.rs @@ -10,11 +10,13 @@ use codex_api::auth_header_telemetry; use codex_api::map_api_error; use codex_feedback::FeedbackRequestTags; use codex_feedback::emit_feedback_request_tags_with_auth_env; +use codex_http_client::ClientRouteClass; +use codex_http_client::HttpClientFactory; use codex_login::AuthEnvTelemetry; use codex_login::AuthManager; use codex_login::CodexAuth; use codex_login::collect_auth_env_telemetry; -use codex_login::default_client::build_reqwest_client; +use codex_login::default_client::build_default_reqwest_client_for_route; use codex_model_provider_info::ModelProviderInfo; use codex_models_manager::manager::ModelsEndpointClient; use codex_models_manager::manager::ModelsEndpointFuture; @@ -38,16 +40,19 @@ const MODELS_ENDPOINT: &str = "/models"; pub(crate) struct OpenAiModelsEndpoint { provider_info: ModelProviderInfo, auth_manager: Option>, + http_client_factory: HttpClientFactory, } impl OpenAiModelsEndpoint { pub(crate) fn new( provider_info: ModelProviderInfo, auth_manager: Option>, + http_client_factory: HttpClientFactory, ) -> Self { Self { provider_info, auth_manager, + http_client_factory, } } @@ -75,7 +80,14 @@ impl OpenAiModelsEndpoint { let auth_mode = auth.as_ref().map(CodexAuth::auth_mode); let api_provider = self.provider_info.to_api_provider(auth_mode)?; let api_auth = resolve_provider_auth(auth.as_ref(), &self.provider_info)?; - let transport = ReqwestTransport::new(build_reqwest_client()); + let request_url = api_provider.url_for_path(MODELS_ENDPOINT); + let client = build_default_reqwest_client_for_route( + &self.http_client_factory, + &request_url, + ClientRouteClass::Api, + ) + .map_err(std::io::Error::from)?; + let transport = ReqwestTransport::new(client); let auth_telemetry = auth_header_telemetry(api_auth.as_ref()); let agent_identity_telemetry = if let Some(CodexAuth::AgentIdentity(auth)) = auth.as_ref() { Some(agent_identity_telemetry(auth)) @@ -229,8 +241,13 @@ mod tests { use std::num::NonZeroU64; use super::*; + use codex_http_client::OutboundProxyPolicy; use codex_protocol::config_types::ModelProviderAuthInfo; + fn default_http_client_factory() -> HttpClientFactory { + HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault) + } + fn provider_info_with_command_auth() -> ModelProviderInfo { ModelProviderInfo { auth: Some(ModelProviderAuthInfo { @@ -253,6 +270,7 @@ mod tests { let endpoint = OpenAiModelsEndpoint::new( provider_info_with_command_auth(), /*auth_manager*/ None, + default_http_client_factory(), ); assert!(endpoint.has_command_auth()); @@ -263,6 +281,7 @@ mod tests { let endpoint = OpenAiModelsEndpoint::new( ModelProviderInfo::create_openai_provider(/*base_url*/ None), /*auth_manager*/ None, + default_http_client_factory(), ); assert!(!endpoint.has_command_auth()); diff --git a/codex-rs/model-provider/src/provider.rs b/codex-rs/model-provider/src/provider.rs index 5f101e52cd6b..8ddf00a85374 100644 --- a/codex-rs/model-provider/src/provider.rs +++ b/codex-rs/model-provider/src/provider.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use codex_api::ApiError; use codex_api::Provider; use codex_api::SharedAuthProvider; +use codex_http_client::HttpClientFactory; use codex_login::AuthManager; use codex_login::CodexAuth; use codex_model_provider_info::ModelProviderInfo; @@ -197,6 +198,7 @@ pub trait ModelProvider: fmt::Debug + Send + Sync { fn models_manager( &self, codex_home: PathBuf, + http_client_factory: HttpClientFactory, config_model_catalog: Option, ) -> SharedModelsManager; } @@ -310,6 +312,7 @@ impl ModelProvider for ConfiguredModelProvider { fn models_manager( &self, codex_home: PathBuf, + http_client_factory: HttpClientFactory, config_model_catalog: Option, ) -> SharedModelsManager { match config_model_catalog { @@ -321,6 +324,7 @@ impl ModelProvider for ConfiguredModelProvider { let endpoint = Arc::new(OpenAiModelsEndpoint::new( self.info.clone(), self.auth_manager.clone(), + http_client_factory, )); Arc::new(OpenAiModelsManager::new( codex_home, @@ -336,6 +340,7 @@ impl ModelProvider for ConfiguredModelProvider { mod tests { use std::num::NonZeroU64; + use codex_http_client::OutboundProxyPolicy; use codex_login::auth::AgentIdentityAuthPolicy; use codex_login::auth::BedrockApiKeyAuth; use codex_model_provider_info::ModelProviderAwsAuthInfo; @@ -359,6 +364,10 @@ mod tests { use super::*; use crate::auth::AgentIdentitySessionFallback; + fn default_http_client_factory() -> HttpClientFactory { + HttpClientFactory::new(OutboundProxyPolicy::ReqwestDefault) + } + fn provider_info_with_command_auth() -> ModelProviderInfo { ModelProviderInfo { auth: Some(ModelProviderAuthInfo { @@ -649,8 +658,11 @@ mod tests { ModelProviderInfo::create_amazon_bedrock_provider(/*aws*/ None), /*auth_manager*/ None, ); - let manager = - provider.models_manager(test_codex_home(), /*config_model_catalog*/ None); + let manager = provider.models_manager( + test_codex_home(), + default_http_client_factory(), + /*config_model_catalog*/ None, + ); let catalog = manager.raw_model_catalog(RefreshStrategy::Online).await; let model_ids = catalog @@ -697,6 +709,7 @@ mod tests { ); let manager = provider.models_manager( test_codex_home(), + default_http_client_factory(), Some(ModelsResponse { models: vec![configured_model], }), @@ -742,8 +755,11 @@ mod tests { )), ); - let manager = - provider.models_manager(test_codex_home(), /*config_model_catalog*/ None); + let manager = provider.models_manager( + test_codex_home(), + default_http_client_factory(), + /*config_model_catalog*/ None, + ); let catalog = manager.raw_model_catalog(RefreshStrategy::Online).await; assert!(