Reduce dependency coupling in shared configuration crates (#47713)

## What changed

- Move `Provider` and `RetryConfig` into `codex-client`, retaining re-exports from `codex-api`, and switch `codex-model-provider-info` to depend on `codex-client`.
- Move feature-state metric emission into `codex-core`, preserving its behavior while removing the `codex-features` dependency on `codex-otel`.
- Explicitly enable TLS features for `tonic` in `codex-config` and `reqwest` in `codex-http-client`.
- Enable `png`'s `zlib-rs` feature directly in `codex-utils-image` to keep encoded PNG bytes stable when WebSocket dependencies are absent.

GitOrigin-RevId: 91fd63ab01b55d516b3e80e3644d06af8d5a01f6
This commit is contained in:
Ahmed Ibrahim
2026-09-24 01:50:36 +00:00
committed by copyberry
parent 4891c4e35f
commit f5960fcc22
13 changed files with 140 additions and 129 deletions
+3
View File
@@ -1,7 +1,10 @@
mod provider;
mod retry;
mod sse;
mod telemetry;
pub use crate::provider::Provider;
pub use crate::provider::RetryConfig;
pub use crate::retry::RetryOn;
pub use crate::retry::RetryOperation;
pub use crate::retry::RetryPolicy;
+103
View File
@@ -0,0 +1,103 @@
//! Endpoint configuration and request construction shared by API clients.
use crate::Request;
use crate::RequestCompression;
use crate::RetryOn;
use crate::RetryPolicy;
use http::Method;
use http::header::HeaderMap;
use std::collections::HashMap;
use std::time::Duration;
use url::Url;
/// High-level retry configuration for a provider.
///
/// This is converted into a `RetryPolicy` used by `codex-client` to drive
/// transport-level retries for both unary and streaming calls.
#[derive(Debug, Clone)]
pub struct RetryConfig {
pub max_attempts: u64,
pub base_delay: Duration,
pub retry_429: bool,
pub retry_5xx: bool,
pub retry_transport: bool,
}
impl RetryConfig {
pub fn to_policy(&self) -> RetryPolicy {
RetryPolicy {
max_attempts: self.max_attempts,
base_delay: self.base_delay,
retry_on: RetryOn {
retry_429: self.retry_429,
retry_5xx: self.retry_5xx,
retry_transport: self.retry_transport,
},
}
}
}
/// HTTP endpoint configuration used to talk to a concrete API deployment.
///
/// Encapsulates base URL, default headers, query params, retry policy, and
/// stream idle timeout, plus helper methods for building requests.
#[derive(Debug, Clone)]
pub struct Provider {
pub name: String,
pub base_url: String,
pub query_params: Option<HashMap<String, String>>,
pub headers: HeaderMap,
pub retry: RetryConfig,
pub stream_idle_timeout: Duration,
}
impl Provider {
pub fn url_for_path(&self, path: &str) -> String {
let base = self.base_url.trim_end_matches('/');
let path = path.trim_start_matches('/');
let mut url = if path.is_empty() {
base.to_string()
} else {
format!("{base}/{path}")
};
if let Some(params) = &self.query_params
&& !params.is_empty()
{
let qs = params
.iter()
.map(|(k, v)| format!("{k}={v}"))
.collect::<Vec<_>>()
.join("&");
url.push('?');
url.push_str(&qs);
}
url
}
pub fn build_request(&self, method: Method, path: &str) -> Request {
Request {
method,
url: self.url_for_path(path),
headers: self.headers.clone(),
body: None,
compression: RequestCompression::None,
timeout: None,
response_body_limit_bytes: None,
}
}
pub fn websocket_url_for_path(&self, path: &str) -> Result<Url, url::ParseError> {
let mut url = Url::parse(&self.url_for_path(path))?;
let scheme = match url.scheme() {
"http" => "ws",
"https" => "wss",
"ws" | "wss" => return Ok(url),
_ => return Ok(url),
};
let _ = url.set_scheme(scheme);
Ok(url)
}
}