mirror of
https://github.com/openai/codex.git
synced 2026-11-07 20:30:33 +00:00
## What changed - Share a lazily registered runtime across threads, model discovery, and extension clients when `runtime_agent_instances` is enabled, while honoring each thread's authentication mode and credential owner. - Bind model catalogs to the effective provider and authentication context while preserving cache policy and live API-key discovery settings. - Resolve credentials, routing, and transport policy together for each request. Preserve proxy and TLS settings, validate runtime account selectors, and prevent pooled connections from crossing runtime identities. - Accept supported ChatGPT subdomains when selecting the registration environment. ## Testing Add integration coverage for shared runtime registration, dual-header and assertion-only modes, disabled and third-party providers, credential replacement, subagents, and delegated review. Add coverage for catalog cache policy and runtime-aware connection reuse. GitOrigin-RevId: 99dd9d987c29c93597a648f6586f98ac6a932c3c
159 lines
4.7 KiB
Rust
159 lines
4.7 KiB
Rust
use codex_api::ImageEditRequest;
|
|
use codex_api::ImageGenerationRequest;
|
|
use codex_api::ImageRequestError;
|
|
use codex_api::ImageResponse;
|
|
use codex_api::ImagesClient;
|
|
use codex_api::ReqwestTransport;
|
|
use codex_api::map_api_error;
|
|
use codex_core::X_CODEX_TURN_METADATA_HEADER;
|
|
use codex_http_client::ClientRouteClass;
|
|
use codex_http_client::HttpClientFactory;
|
|
use codex_login::default_client::add_originator_header;
|
|
use codex_login::default_client::create_transport_for_routes_async;
|
|
use codex_model_provider::SharedModelProvider;
|
|
use codex_protocol::error::CodexErr;
|
|
use http::HeaderMap;
|
|
use http::HeaderValue;
|
|
|
|
const X_CODEX_IMAGE_TURN_ID_HEADER: &str = "x-codex-image-turn-id";
|
|
|
|
pub(crate) struct ImageBackendError {
|
|
message: String,
|
|
codex_error: CodexErr,
|
|
imagegen_request_id: Option<String>,
|
|
}
|
|
|
|
impl ImageBackendError {
|
|
fn from_image_request(error: ImageRequestError) -> Self {
|
|
let (error, imagegen_request_id) = error.into_parts();
|
|
let message = error.to_string();
|
|
Self {
|
|
message,
|
|
codex_error: map_api_error(error),
|
|
imagegen_request_id,
|
|
}
|
|
}
|
|
|
|
fn from_message(message: String) -> Self {
|
|
Self {
|
|
codex_error: CodexErr::Stream(message.clone()),
|
|
message,
|
|
imagegen_request_id: None,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn message(&self) -> &str {
|
|
&self.message
|
|
}
|
|
|
|
pub(crate) fn codex_error(&self) -> &CodexErr {
|
|
&self.codex_error
|
|
}
|
|
|
|
pub(crate) fn imagegen_request_id(&self) -> Option<&str> {
|
|
self.imagegen_request_id.as_deref()
|
|
}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub(crate) struct CodexImagesBackend {
|
|
provider: SharedModelProvider,
|
|
http_client_factory: HttpClientFactory,
|
|
originator: Option<String>,
|
|
}
|
|
|
|
impl CodexImagesBackend {
|
|
/// Creates a backend that sends image requests through the active model provider.
|
|
pub(crate) fn new(
|
|
provider: SharedModelProvider,
|
|
http_client_factory: HttpClientFactory,
|
|
originator: Option<String>,
|
|
) -> Self {
|
|
Self {
|
|
provider,
|
|
http_client_factory,
|
|
originator,
|
|
}
|
|
}
|
|
|
|
/// Resolves the provider and auth required for the current image API request.
|
|
async fn client(&self) -> Result<ImagesClient<ReqwestTransport>, ImageBackendError> {
|
|
let setup = codex_model_provider::resolve_request(
|
|
self.provider.as_ref(),
|
|
/*scope*/ None,
|
|
/*routing*/ None,
|
|
self.http_client_factory.clone(),
|
|
)
|
|
.await
|
|
.map_err(|err| ImageBackendError::from_message(err.to_string()))?;
|
|
let transport = create_transport_for_routes_async(
|
|
setup.http_client_factory,
|
|
ClientRouteClass::Api,
|
|
setup.redirect_policy,
|
|
)
|
|
.await
|
|
.map_err(|err| ImageBackendError::from_message(err.to_string()))?;
|
|
Ok(ImagesClient::new(
|
|
transport,
|
|
setup.api_provider,
|
|
setup.api_auth,
|
|
))
|
|
}
|
|
|
|
/// Sends a standalone image generation request through the configured Images client.
|
|
pub(crate) async fn generate(
|
|
&self,
|
|
request: ImageGenerationRequest,
|
|
turn_id: &str,
|
|
codex_turn_metadata: Option<&str>,
|
|
) -> Result<(ImageResponse, Option<String>), ImageBackendError> {
|
|
self.client()
|
|
.await?
|
|
.generate(
|
|
&request,
|
|
image_request_headers(self.originator.as_deref(), turn_id, codex_turn_metadata),
|
|
)
|
|
.await
|
|
.map_err(ImageBackendError::from_image_request)
|
|
}
|
|
|
|
/// Sends a standalone image edit request through the configured Images client.
|
|
pub(crate) async fn edit(
|
|
&self,
|
|
request: ImageEditRequest,
|
|
turn_id: &str,
|
|
codex_turn_metadata: Option<&str>,
|
|
) -> Result<(ImageResponse, Option<String>), ImageBackendError> {
|
|
self.client()
|
|
.await?
|
|
.edit(
|
|
&request,
|
|
image_request_headers(self.originator.as_deref(), turn_id, codex_turn_metadata),
|
|
)
|
|
.await
|
|
.map_err(ImageBackendError::from_image_request)
|
|
}
|
|
}
|
|
|
|
fn image_request_headers(
|
|
originator: Option<&str>,
|
|
turn_id: &str,
|
|
codex_turn_metadata: Option<&str>,
|
|
) -> HeaderMap {
|
|
let mut headers = HeaderMap::new();
|
|
if let Ok(turn_id) = HeaderValue::from_str(turn_id) {
|
|
headers.insert(X_CODEX_IMAGE_TURN_ID_HEADER, turn_id);
|
|
}
|
|
if let Some(originator) = originator {
|
|
add_originator_header(&mut headers, originator);
|
|
}
|
|
|
|
if let Some(metadata) = codex_turn_metadata
|
|
&& let Ok(metadata) = HeaderValue::from_str(metadata)
|
|
{
|
|
headers.insert(X_CODEX_TURN_METADATA_HEADER, metadata);
|
|
}
|
|
|
|
headers
|
|
}
|