mirror of
https://github.com/openai/codex.git
synced 2026-11-13 21:30:47 +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
138 lines
4.7 KiB
Rust
138 lines
4.7 KiB
Rust
use std::sync::Arc;
|
|
|
|
use codex_core::config::Config;
|
|
use codex_extension_api::ConfigContributor;
|
|
use codex_extension_api::ExtensionData;
|
|
use codex_extension_api::ExtensionFuture;
|
|
use codex_extension_api::ExtensionRegistryBuilder;
|
|
use codex_extension_api::ThreadLifecycleContributor;
|
|
use codex_extension_api::ThreadOriginator;
|
|
use codex_extension_api::ThreadStartInput;
|
|
use codex_extension_api::ToolCall;
|
|
use codex_extension_api::ToolContributor;
|
|
use codex_extension_api::ToolExecutor;
|
|
use codex_http_client::HttpClientFactory;
|
|
use codex_login::AuthManager;
|
|
use codex_model_provider_info::ModelProviderInfo;
|
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
|
|
|
use crate::backend::CodexImagesBackend;
|
|
use crate::tool::ImageGenerationTool;
|
|
|
|
#[derive(Clone)]
|
|
struct ImageGenerationExtension {
|
|
auth_manager: Arc<AuthManager>,
|
|
resolve_save_root: Arc<SaveRootResolver>,
|
|
}
|
|
|
|
type SaveRootResolver = dyn Fn(&Config) -> Option<AbsolutePathBuf> + Send + Sync;
|
|
|
|
#[derive(Clone)]
|
|
struct ImageGenerationExtensionConfig {
|
|
available: bool,
|
|
gif_enabled: bool,
|
|
http_client_factory: HttpClientFactory,
|
|
provider: ModelProviderInfo,
|
|
save_root: Option<AbsolutePathBuf>,
|
|
}
|
|
|
|
impl ImageGenerationExtensionConfig {
|
|
/// Resolves the image provider and save root for a thread.
|
|
fn from_config(config: &Config, resolve_save_root: &SaveRootResolver) -> Self {
|
|
Self {
|
|
available: config.model_provider.is_openai()
|
|
|| config.model_provider.requires_openai_auth
|
|
|| config.model_provider.uses_openai_actor_authorization(),
|
|
gif_enabled: config.features.image_generation_animation_enabled(),
|
|
http_client_factory: config.http_client_factory(),
|
|
provider: config.model_provider.clone(),
|
|
save_root: resolve_save_root(config),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ThreadLifecycleContributor<Config> for ImageGenerationExtension {
|
|
/// Seeds image-generation configuration when a thread begins.
|
|
fn on_thread_start<'a>(
|
|
&'a self,
|
|
input: ThreadStartInput<'a, Config>,
|
|
) -> ExtensionFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
input
|
|
.thread_store
|
|
.insert(ImageGenerationExtensionConfig::from_config(
|
|
input.config,
|
|
self.resolve_save_root.as_ref(),
|
|
));
|
|
})
|
|
}
|
|
}
|
|
|
|
impl ConfigContributor<Config> for ImageGenerationExtension {
|
|
/// Refreshes image-generation configuration after thread configuration changes.
|
|
fn on_config_changed(
|
|
&self,
|
|
_session_store: &ExtensionData,
|
|
thread_store: &ExtensionData,
|
|
_previous_config: &Config,
|
|
new_config: &Config,
|
|
) {
|
|
thread_store.insert(ImageGenerationExtensionConfig::from_config(
|
|
new_config,
|
|
self.resolve_save_root.as_ref(),
|
|
));
|
|
}
|
|
}
|
|
|
|
impl ToolContributor for ImageGenerationExtension {
|
|
/// Creates the image-generation tool exposed by this installed extension.
|
|
fn tools(
|
|
&self,
|
|
_session_store: &ExtensionData,
|
|
thread_store: &ExtensionData,
|
|
) -> Vec<Arc<dyn for<'call> ToolExecutor<ToolCall<'call>>>> {
|
|
let Some(config) = thread_store.get::<ImageGenerationExtensionConfig>() else {
|
|
return Vec::new();
|
|
};
|
|
if !config.available {
|
|
return Vec::new();
|
|
}
|
|
let auth = thread_store
|
|
.get::<codex_model_provider::ProviderAuthContext>()
|
|
.unwrap_or_else(|| {
|
|
Arc::new(codex_model_provider::ProviderAuthContext {
|
|
credentials: Arc::clone(&self.auth_manager),
|
|
runtime_auth: None,
|
|
})
|
|
});
|
|
|
|
vec![Arc::new(ImageGenerationTool::new(
|
|
CodexImagesBackend::new(
|
|
auth.model_provider(config.provider.clone()),
|
|
config.http_client_factory.clone(),
|
|
thread_store
|
|
.get::<ThreadOriginator>()
|
|
.map(|originator| originator.0.clone()),
|
|
),
|
|
config.save_root.clone(),
|
|
thread_store.level_id().to_string(),
|
|
config.gif_enabled,
|
|
))]
|
|
}
|
|
}
|
|
|
|
/// Installs the standalone image-generation extension contributors.
|
|
pub fn install(
|
|
registry: &mut ExtensionRegistryBuilder<Config>,
|
|
auth_manager: Arc<AuthManager>,
|
|
resolve_save_root: impl Fn(&Config) -> Option<AbsolutePathBuf> + Send + Sync + 'static,
|
|
) {
|
|
let extension = Arc::new(ImageGenerationExtension {
|
|
auth_manager,
|
|
resolve_save_root: Arc::new(resolve_save_root),
|
|
});
|
|
registry.thread_lifecycle_contributor(extension.clone());
|
|
registry.config_contributor(extension.clone());
|
|
registry.tool_contributor(extension);
|
|
}
|