From a57a747eb667753118217b8bb47dfd1fff88cbde Mon Sep 17 00:00:00 2001 From: jif-oai Date: Fri, 8 May 2026 14:37:38 +0200 Subject: [PATCH] extension: wire extension registries --- codex-rs/Cargo.lock | 5 ++ codex-rs/app-server/Cargo.toml | 1 + codex-rs/app-server/src/extensions.rs | 9 +++ codex-rs/app-server/src/lib.rs | 1 + codex-rs/app-server/src/mcp_refresh.rs | 2 + codex-rs/app-server/src/message_processor.rs | 2 + codex-rs/core-api/Cargo.toml | 1 + codex-rs/core-api/src/lib.rs | 1 + codex-rs/core/Cargo.toml | 1 + codex-rs/core/src/codex_delegate.rs | 1 + codex-rs/core/src/lib.rs | 1 + codex-rs/core/src/prompt_debug.rs | 2 + codex-rs/core/src/session/mod.rs | 30 ++++++++ codex-rs/core/src/session/session.rs | 15 ++++ codex-rs/core/src/session/tests.rs | 76 +++++++++++++++++++ .../core/src/session/tests/guardian_tests.rs | 1 + codex-rs/core/src/session/turn_context.rs | 6 +- codex-rs/core/src/state/service.rs | 5 ++ codex-rs/core/src/thread_manager.rs | 7 ++ codex-rs/core/src/thread_manager_tests.rs | 12 +++ .../src/tools/handlers/multi_agents_tests.rs | 2 + codex-rs/core/tests/common/Cargo.toml | 1 + codex-rs/core/tests/common/test_codex.rs | 2 + codex-rs/core/tests/suite/client.rs | 2 + codex-rs/mcp-server/Cargo.toml | 1 + codex-rs/mcp-server/src/message_processor.rs | 2 + codex-rs/thread-manager-sample/src/main.rs | 2 + 27 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 codex-rs/app-server/src/extensions.rs diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index fc7bf1fe42..8ddf5256a7 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -1895,6 +1895,7 @@ dependencies = [ "codex-core", "codex-core-plugins", "codex-exec-server", + "codex-extension-api", "codex-external-agent-migration", "codex-external-agent-sessions", "codex-features", @@ -2471,6 +2472,7 @@ dependencies = [ "codex-core-skills", "codex-exec-server", "codex-execpolicy", + "codex-extension-api", "codex-features", "codex-feedback", "codex-git-utils", @@ -2575,6 +2577,7 @@ dependencies = [ "codex-config", "codex-core", "codex-exec-server", + "codex-extension-api", "codex-features", "codex-login", "codex-model-provider-info", @@ -3065,6 +3068,7 @@ dependencies = [ "codex-config", "codex-core", "codex-exec-server", + "codex-extension-api", "codex-login", "codex-protocol", "codex-shell-command", @@ -4273,6 +4277,7 @@ dependencies = [ "codex-config", "codex-core", "codex-exec-server", + "codex-extension-api", "codex-features", "codex-hooks", "codex-login", diff --git a/codex-rs/app-server/Cargo.toml b/codex-rs/app-server/Cargo.toml index b4a5e64a89..3d2eb0bc36 100644 --- a/codex-rs/app-server/Cargo.toml +++ b/codex-rs/app-server/Cargo.toml @@ -37,6 +37,7 @@ codex-config = { workspace = true } codex-core = { workspace = true } codex-core-plugins = { workspace = true } codex-exec-server = { workspace = true } +codex-extension-api = { workspace = true } codex-external-agent-migration = { workspace = true } codex-external-agent-sessions = { workspace = true } codex-features = { workspace = true } diff --git a/codex-rs/app-server/src/extensions.rs b/codex-rs/app-server/src/extensions.rs new file mode 100644 index 0000000000..8fa5e3f693 --- /dev/null +++ b/codex-rs/app-server/src/extensions.rs @@ -0,0 +1,9 @@ +use std::sync::Arc; + +use codex_core::config::Config; +use codex_extension_api::ExtensionRegistry; +use codex_extension_api::ExtensionRegistryBuilder; + +pub(crate) fn thread_extensions() -> Arc> { + Arc::new(ExtensionRegistryBuilder::::new().build()) +} diff --git a/codex-rs/app-server/src/lib.rs b/codex-rs/app-server/src/lib.rs index 08aab99f65..5a8a357519 100644 --- a/codex-rs/app-server/src/lib.rs +++ b/codex-rs/app-server/src/lib.rs @@ -82,6 +82,7 @@ mod config_manager_service; mod connection_rpc_gate; mod dynamic_tools; mod error_code; +mod extensions; mod filters; mod fs_watch; mod fuzzy_file_search; diff --git a/codex-rs/app-server/src/mcp_refresh.rs b/codex-rs/app-server/src/mcp_refresh.rs index 8e1ccd3c0a..46a75111be 100644 --- a/codex-rs/app-server/src/mcp_refresh.rs +++ b/codex-rs/app-server/src/mcp_refresh.rs @@ -99,6 +99,7 @@ async fn queue_refresh( #[cfg(test)] mod tests { use super::*; + use crate::extensions::thread_extensions; use async_trait::async_trait; use codex_arg0::Arg0DispatchPaths; use codex_config::CloudRequirementsLoader; @@ -183,6 +184,7 @@ mod tests { auth_manager, SessionSource::Exec, Arc::new(EnvironmentManager::default_for_tests()), + thread_extensions(), /*analytics_events_client*/ None, thread_store, Some(state_db.clone()), diff --git a/codex-rs/app-server/src/message_processor.rs b/codex-rs/app-server/src/message_processor.rs index 7006c40343..0d842307b3 100644 --- a/codex-rs/app-server/src/message_processor.rs +++ b/codex-rs/app-server/src/message_processor.rs @@ -7,6 +7,7 @@ use std::sync::atomic::AtomicBool; use crate::config_manager::ConfigManager; use crate::connection_rpc_gate::ConnectionRpcGate; use crate::error_code::invalid_request; +use crate::extensions::thread_extensions; use crate::fs_watch::FsWatchManager; use crate::outgoing_message::ConnectionId; use crate::outgoing_message::ConnectionRequestId; @@ -289,6 +290,7 @@ impl MessageProcessor { auth_manager.clone(), session_source, environment_manager, + thread_extensions(), Some(analytics_events_client.clone()), Arc::clone(&thread_store), state_db.clone(), diff --git a/codex-rs/core-api/Cargo.toml b/codex-rs/core-api/Cargo.toml index 2b4a0216d6..998da39ce7 100644 --- a/codex-rs/core-api/Cargo.toml +++ b/codex-rs/core-api/Cargo.toml @@ -19,6 +19,7 @@ codex-arg0 = { workspace = true } codex-analytics = { workspace = true } codex-config = { workspace = true } codex-core = { workspace = true } +codex-extension-api = { workspace = true } codex-exec-server = { workspace = true } codex-features = { workspace = true } codex-login = { workspace = true } diff --git a/codex-rs/core-api/src/lib.rs b/codex-rs/core-api/src/lib.rs index f9bdc9b56b..0dccf1a56a 100644 --- a/codex-rs/core-api/src/lib.rs +++ b/codex-rs/core-api/src/lib.rs @@ -46,6 +46,7 @@ pub use codex_core::thread_store_from_config; pub use codex_exec_server::EnvironmentManager; pub use codex_exec_server::EnvironmentManagerArgs; pub use codex_exec_server::ExecServerRuntimePaths; +pub use codex_extension_api::empty_extension_registry; pub use codex_features::Feature; pub use codex_features::Features; pub use codex_login::AuthManager; diff --git a/codex-rs/core/Cargo.toml b/codex-rs/core/Cargo.toml index 5e799b259f..a8b87fa8fb 100644 --- a/codex-rs/core/Cargo.toml +++ b/codex-rs/core/Cargo.toml @@ -35,6 +35,7 @@ codex-config = { workspace = true } codex-core-plugins = { workspace = true } codex-core-skills = { workspace = true } codex-exec-server = { workspace = true } +codex-extension-api = { workspace = true } codex-features = { workspace = true } codex-feedback = { workspace = true } codex-login = { workspace = true } diff --git a/codex-rs/core/src/codex_delegate.rs b/codex-rs/core/src/codex_delegate.rs index a89d8fc973..039c0de9d2 100644 --- a/codex-rs/core/src/codex_delegate.rs +++ b/codex-rs/core/src/codex_delegate.rs @@ -83,6 +83,7 @@ pub(crate) async fn run_codex_thread_interactive( skills_manager: Arc::clone(&parent_session.services.skills_manager), plugins_manager: Arc::clone(&parent_session.services.plugins_manager), mcp_manager: Arc::clone(&parent_session.services.mcp_manager), + extensions: Arc::clone(&parent_session.services.extensions), skills_watcher: Arc::clone(&parent_session.services.skills_watcher), conversation_history: initial_history.unwrap_or(InitialHistory::New), session_source: SessionSource::SubAgent(subagent_source.clone()), diff --git a/codex-rs/core/src/lib.rs b/codex-rs/core/src/lib.rs index 0cdf0e2d46..979f64beb0 100644 --- a/codex-rs/core/src/lib.rs +++ b/codex-rs/core/src/lib.rs @@ -22,6 +22,7 @@ mod config_lock; pub use codex_thread::CodexThread; pub use codex_thread::CodexThreadTurnContextOverrides; pub use codex_thread::ThreadConfigSnapshot; +pub use session::turn_context::TurnContext; mod agent; mod codex_delegate; mod command_canonicalization; diff --git a/codex-rs/core/src/prompt_debug.rs b/codex-rs/core/src/prompt_debug.rs index 8717427afe..a88d94a1de 100644 --- a/codex-rs/core/src/prompt_debug.rs +++ b/codex-rs/core/src/prompt_debug.rs @@ -20,6 +20,7 @@ use crate::session::turn::built_tools; use crate::state_db_bridge::StateDbHandle; use crate::thread_manager::ThreadManager; use crate::thread_manager::thread_store_from_config; +use codex_extension_api::empty_extension_registry; /// Build the model-visible `input` list for a single debug turn. #[doc(hidden)] @@ -45,6 +46,7 @@ pub async fn build_prompt_input( Arc::clone(&auth_manager), SessionSource::Exec, Arc::new(EnvironmentManager::new(EnvironmentManagerArgs::new(local_runtime_paths)).await), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store, state_db.clone(), diff --git a/codex-rs/core/src/session/mod.rs b/codex-rs/core/src/session/mod.rs index 89c12aaf81..ebb3aba98d 100644 --- a/codex-rs/core/src/session/mod.rs +++ b/codex-rs/core/src/session/mod.rs @@ -52,6 +52,7 @@ use codex_config::types::OAuthCredentialsStoreMode; use codex_exec_server::Environment; use codex_exec_server::EnvironmentManager; use codex_exec_server::FileSystemSandboxContext; +use codex_extension_api::PromptSlot; use codex_features::FEATURES; use codex_features::Feature; use codex_features::unstable_features_warning_event; @@ -392,6 +393,7 @@ pub(crate) struct CodexSpawnArgs { pub(crate) skills_manager: Arc, pub(crate) plugins_manager: Arc, pub(crate) mcp_manager: Arc, + pub(crate) extensions: Arc>, pub(crate) skills_watcher: Arc, pub(crate) conversation_history: InitialHistory, pub(crate) session_source: SessionSource, @@ -455,6 +457,7 @@ impl Codex { skills_manager, plugins_manager, mcp_manager, + extensions, skills_watcher, conversation_history, session_source, @@ -650,6 +653,7 @@ impl Codex { skills_manager, plugins_manager, mcp_manager.clone(), + extensions, skills_watcher, agent_control, environment_manager, @@ -2588,6 +2592,7 @@ impl Session { ) -> Vec { let mut developer_sections = Vec::::with_capacity(8); let mut contextual_user_sections = Vec::::with_capacity(2); + let mut separate_developer_sections = Vec::::new(); let ( reference_context_item, previous_turn_settings, @@ -2732,6 +2737,24 @@ impl Session { { developer_sections.push(commit_message_instruction); } + for contributor in self.services.extensions.context_contributors() { + for fragment in contributor.contribute( + &self.services.session_extension_data, + &self.services.thread_extension_data, + ) { + match fragment.slot() { + PromptSlot::DeveloperPolicy | PromptSlot::DeveloperCapabilities => { + developer_sections.push(fragment.text().to_string()); + } + PromptSlot::ContextualUser => { + contextual_user_sections.push(fragment.text().to_string()); + } + PromptSlot::SeparateDeveloper => { + separate_developer_sections.push(fragment.text().to_string()); + } + } + } + } if let Some(user_instructions) = turn_context.user_instructions.as_deref() { contextual_user_sections.push( UserInstructions { @@ -2764,6 +2787,13 @@ impl Session { { items.push(developer_message); } + for section in separate_developer_sections { + if let Some(developer_message) = + crate::context_manager::updates::build_developer_update_item(vec![section]) + { + items.push(developer_message); + } + } if let Some(usage_hint_text) = multi_agent_v2_usage_hint_text && let Some(usage_hint_message) = crate::context_manager::updates::build_developer_update_item(vec![ diff --git a/codex-rs/core/src/session/session.rs b/codex-rs/core/src/session/session.rs index f72a173c80..a12f3f36ec 100644 --- a/codex-rs/core/src/session/session.rs +++ b/codex-rs/core/src/session/session.rs @@ -364,6 +364,7 @@ impl Session { skills_manager: Arc, plugins_manager: Arc, mcp_manager: Arc, + extensions: Arc>, skills_watcher: Arc, agent_control: AgentControl, environment_manager: Arc, @@ -810,6 +811,16 @@ impl Session { SessionId::from(thread_id) }; let agent_control = agent_control.with_session_id(session_id); + let session_extension_data = codex_extension_api::ExtensionData::new(); + let thread_extension_data = codex_extension_api::ExtensionData::new(); + for contributor in extensions.thread_start_contributors() { + contributor.contribute( + config.as_ref(), + &session_extension_data, + &thread_extension_data, + ); + } + let services = SessionServices { // Initialize the MCP connection manager with an uninitialized // instance. It will be replaced with one created via @@ -845,6 +856,10 @@ impl Session { skills_manager, plugins_manager: Arc::clone(&plugins_manager), mcp_manager: Arc::clone(&mcp_manager), + extensions, + // TODO(jif): extract session to share between sub-agents + session_extension_data, + thread_extension_data, skills_watcher, agent_control, network_proxy, diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index b63b16cbf4..1b78ea039c 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -3724,6 +3724,7 @@ async fn session_new_fails_when_zsh_fork_enabled_without_zsh_path() { skills_manager, plugins_manager, mcp_manager, + Arc::new(codex_extension_api::ExtensionRegistryBuilder::new().build()), Arc::new(SkillsWatcher::noop()), AgentControl::default(), Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), @@ -3871,6 +3872,9 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) { skills_manager, plugins_manager, mcp_manager, + extensions: Arc::new(codex_extension_api::ExtensionRegistryBuilder::new().build()), + session_extension_data: codex_extension_api::ExtensionData::new(), + thread_extension_data: codex_extension_api::ExtensionData::new(), skills_watcher, agent_control, network_proxy: None, @@ -4060,6 +4064,7 @@ async fn make_session_with_config_and_rx( skills_manager, plugins_manager, mcp_manager, + Arc::new(codex_extension_api::ExtensionRegistryBuilder::new().build()), Arc::new(SkillsWatcher::noop()), AgentControl::default(), Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), @@ -4162,6 +4167,7 @@ async fn make_session_with_history_source_and_agent_control_and_rx( skills_manager, plugins_manager, mcp_manager, + Arc::new(codex_extension_api::ExtensionRegistryBuilder::new().build()), Arc::new(SkillsWatcher::noop()), agent_control, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), @@ -5586,6 +5592,9 @@ where skills_manager, plugins_manager, mcp_manager, + extensions: Arc::new(codex_extension_api::ExtensionRegistryBuilder::new().build()), + session_extension_data: codex_extension_api::ExtensionData::new(), + thread_extension_data: codex_extension_api::ExtensionData::new(), skills_watcher, agent_control, network_proxy: None, @@ -6132,6 +6141,73 @@ async fn make_multi_agent_v2_usage_hint_test_session( (session, turn_context) } +struct GitAttributionTestContributor; +struct GitAttributionTestState; + +impl codex_extension_api::ContextContributor for GitAttributionTestContributor { + fn contribute( + &self, + _session_store: &codex_extension_api::ExtensionData, + thread_store: &codex_extension_api::ExtensionData, + ) -> Vec { + thread_store + .get::() + .is_some() + .then(|| { + codex_extension_api::PromptFragment::developer_policy( + "git attribution extension enabled", + ) + }) + .into_iter() + .collect() + } +} + +fn git_attribution_test_registry() +-> Arc> { + let mut builder = codex_extension_api::ExtensionRegistryBuilder::new(); + builder.prompt_contributor(Arc::new(GitAttributionTestContributor)); + Arc::new(builder.build()) +} + +#[tokio::test] +async fn build_initial_context_includes_git_attribution_from_extensions() { + let (mut session, turn_context) = make_session_and_context().await; + session.services.extensions = git_attribution_test_registry(); + session + .services + .thread_extension_data + .insert(GitAttributionTestState); + + let initial_context = session.build_initial_context(&turn_context).await; + let developer_messages = developer_message_texts(&initial_context); + + assert!( + developer_messages + .iter() + .flatten() + .any(|text| *text == "git attribution extension enabled"), + "expected git attribution developer text, got {developer_messages:?}" + ); +} + +#[tokio::test] +async fn build_initial_context_omits_git_attribution_when_feature_is_disabled() { + let (mut session, turn_context) = make_session_and_context().await; + session.services.extensions = git_attribution_test_registry(); + + let initial_context = session.build_initial_context(&turn_context).await; + let developer_messages = developer_message_texts(&initial_context); + + assert!( + !developer_messages + .iter() + .flatten() + .any(|text| *text == "git attribution extension enabled"), + "did not expect git attribution developer text, got {developer_messages:?}" + ); +} + #[tokio::test] async fn build_initial_context_adds_multi_agent_v2_root_usage_hint_as_developer_message() { let (session, turn_context) = diff --git a/codex-rs/core/src/session/tests/guardian_tests.rs b/codex-rs/core/src/session/tests/guardian_tests.rs index 5c473ef1f9..3957cedb55 100644 --- a/codex-rs/core/src/session/tests/guardian_tests.rs +++ b/codex-rs/core/src/session/tests/guardian_tests.rs @@ -743,6 +743,7 @@ async fn guardian_subagent_does_not_inherit_parent_exec_policy_rules() { skills_manager, plugins_manager, mcp_manager, + extensions: codex_extension_api::empty_extension_registry(), skills_watcher, conversation_history: InitialHistory::New, session_source: SessionSource::SubAgent(SubAgentSource::Other( diff --git a/codex-rs/core/src/session/turn_context.rs b/codex-rs/core/src/session/turn_context.rs index d4fe30063f..0e271671ac 100644 --- a/codex-rs/core/src/session/turn_context.rs +++ b/codex-rs/core/src/session/turn_context.rs @@ -52,11 +52,11 @@ impl TurnEnvironment { /// The context needed for a single turn of the thread. #[derive(Debug)] -pub(crate) struct TurnContext { +pub struct TurnContext { pub(crate) sub_id: String, pub(crate) trace_id: Option, pub(crate) realtime_active: bool, - pub(crate) config: Arc, + pub config: Arc, pub(crate) auth_manager: Option>, pub(crate) model_info: ModelInfo, pub(crate) session_telemetry: SessionTelemetry, @@ -84,7 +84,7 @@ pub(crate) struct TurnContext { pub(crate) windows_sandbox_level: WindowsSandboxLevel, pub(crate) shell_environment_policy: ShellEnvironmentPolicy, pub(crate) tools_config: ToolsConfig, - pub(crate) features: ManagedFeatures, + pub features: ManagedFeatures, pub(crate) ghost_snapshot: GhostSnapshotConfig, pub(crate) final_output_json_schema: Option, pub(crate) codex_self_exe: Option, diff --git a/codex-rs/core/src/state/service.rs b/codex-rs/core/src/state/service.rs index 9cd9e97fbb..a255ee9603 100644 --- a/codex-rs/core/src/state/service.rs +++ b/codex-rs/core/src/state/service.rs @@ -18,6 +18,8 @@ use arc_swap::ArcSwap; use codex_analytics::AnalyticsEventsClient; use codex_core_plugins::PluginsManager; use codex_exec_server::EnvironmentManager; +use codex_extension_api::ExtensionData; +use codex_extension_api::ExtensionRegistry; use codex_hooks::Hooks; use codex_login::AuthManager; use codex_mcp::McpConnectionManager; @@ -59,6 +61,9 @@ pub(crate) struct SessionServices { pub(crate) skills_manager: Arc, pub(crate) plugins_manager: Arc, pub(crate) mcp_manager: Arc, + pub(crate) extensions: Arc>, + pub(crate) session_extension_data: ExtensionData, + pub(crate) thread_extension_data: ExtensionData, pub(crate) skills_watcher: Arc, pub(crate) agent_control: AgentControl, pub(crate) network_proxy: Option, diff --git a/codex-rs/core/src/thread_manager.rs b/codex-rs/core/src/thread_manager.rs index 003f2786b0..b9fbedbf3b 100644 --- a/codex-rs/core/src/thread_manager.rs +++ b/codex-rs/core/src/thread_manager.rs @@ -22,6 +22,8 @@ use codex_app_server_protocol::ThreadHistoryBuilder; use codex_app_server_protocol::TurnStatus; use codex_core_plugins::PluginsManager; use codex_exec_server::EnvironmentManager; +use codex_extension_api::ExtensionRegistry; +use codex_extension_api::empty_extension_registry; use codex_login::AuthManager; use codex_login::CodexAuth; use codex_model_provider::create_model_provider; @@ -246,6 +248,7 @@ pub(crate) struct ThreadManagerState { skills_manager: Arc, plugins_manager: Arc, mcp_manager: Arc, + extensions: Arc>, skills_watcher: Arc, thread_store: Arc, session_source: SessionSource, @@ -287,6 +290,7 @@ impl ThreadManager { auth_manager: Arc, session_source: SessionSource, environment_manager: Arc, + extensions: Arc>, analytics_events_client: Option, thread_store: Arc, state_db: Option, @@ -315,6 +319,7 @@ impl ThreadManager { skills_manager, plugins_manager, mcp_manager, + extensions, skills_watcher, thread_store, auth_manager, @@ -416,6 +421,7 @@ impl ThreadManager { skills_manager, plugins_manager, mcp_manager, + extensions: empty_extension_registry(), skills_watcher, thread_store, auth_manager, @@ -1188,6 +1194,7 @@ impl ThreadManagerState { skills_manager: Arc::clone(&self.skills_manager), plugins_manager: Arc::clone(&self.plugins_manager), mcp_manager: Arc::clone(&self.mcp_manager), + extensions: Arc::clone(&self.extensions), skills_watcher: Arc::clone(&self.skills_watcher), conversation_history: initial_history, session_source, diff --git a/codex-rs/core/src/thread_manager_tests.rs b/codex-rs/core/src/thread_manager_tests.rs index 0834c18e21..a52182c888 100644 --- a/codex-rs/core/src/thread_manager_tests.rs +++ b/codex-rs/core/src/thread_manager_tests.rs @@ -7,6 +7,7 @@ use crate::session::session::SessionSettingsUpdate; use crate::session::tests::make_session_and_context; use crate::tasks::InterruptedTurnHistoryMarker; use crate::tasks::interrupted_turn_history_marker; +use codex_extension_api::empty_extension_registry; use codex_features::Feature; use codex_models_manager::manager::RefreshStrategy; use codex_protocol::models::ContentItem; @@ -397,6 +398,7 @@ async fn resume_and_fork_do_not_restore_thread_environments_from_rollout() { auth_manager.clone(), SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store_from_config(&config, /*state_db*/ None), /*state_db*/ None, @@ -513,6 +515,7 @@ async fn explicit_installation_id_skips_codex_home_file() { auth_manager, SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store, state_db.clone(), @@ -550,6 +553,7 @@ async fn resume_active_thread_from_rollout_returns_running_thread() { auth_manager.clone(), SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store_from_config(&config, /*state_db*/ None), /*state_db*/ None, @@ -605,6 +609,7 @@ async fn resume_stopped_thread_from_rollout_spawns_new_thread() { auth_manager.clone(), SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store_from_config(&config, /*state_db*/ None), /*state_db*/ None, @@ -667,6 +672,7 @@ async fn resume_stopped_thread_from_rollout_preserves_thread_source() { auth_manager.clone(), SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store, state_db.clone(), @@ -755,6 +761,7 @@ async fn rollout_path_resume_and_fork_read_history_through_thread_store() { auth_manager.clone(), SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store.clone(), state_db, @@ -856,6 +863,7 @@ async fn new_uses_active_provider_for_model_refresh() { auth_manager, SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store_from_config(&config, /*state_db*/ None), /*state_db*/ None, @@ -1070,6 +1078,7 @@ async fn interrupted_fork_snapshot_does_not_synthesize_turn_id_for_legacy_histor auth_manager.clone(), SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store_from_config(&config, state_db.clone()), state_db.clone(), @@ -1176,6 +1185,7 @@ async fn interrupted_fork_snapshot_preserves_explicit_turn_id() { auth_manager.clone(), SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store_from_config(&config, state_db.clone()), state_db.clone(), @@ -1271,6 +1281,7 @@ async fn interrupted_fork_snapshot_uses_persisted_mid_turn_history_without_live_ auth_manager.clone(), SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store_from_config(&config, state_db.clone()), state_db.clone(), @@ -1412,6 +1423,7 @@ async fn resumed_thread_keeps_paused_goal_paused() -> anyhow::Result<()> { auth_manager.clone(), SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store_from_config(&config, state_db.clone()), state_db.clone(), diff --git a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs index 43503be8c1..17b06c1a66 100644 --- a/codex-rs/core/src/tools/handlers/multi_agents_tests.rs +++ b/codex-rs/core/src/tools/handlers/multi_agents_tests.rs @@ -15,6 +15,7 @@ use crate::tools::handlers::multi_agents_v2::SendMessageHandler as SendMessageHa use crate::tools::handlers::multi_agents_v2::SpawnAgentHandler as SpawnAgentHandlerV2; use crate::tools::handlers::multi_agents_v2::WaitAgentHandler as WaitAgentHandlerV2; use crate::turn_diff_tracker::TurnDiffTracker; +use codex_extension_api::empty_extension_registry; use codex_features::Feature; use codex_login::AuthManager; use codex_login::CodexAuth; @@ -3163,6 +3164,7 @@ async fn tool_handlers_cascade_close_and_resume_and_keep_explicitly_closed_subtr AuthManager::from_auth_for_testing(CodexAuth::from_api_key("dummy")), SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store_from_config(&config, state_db.clone()), state_db.clone(), diff --git a/codex-rs/core/tests/common/Cargo.toml b/codex-rs/core/tests/common/Cargo.toml index e22a287267..fb6221cfce 100644 --- a/codex-rs/core/tests/common/Cargo.toml +++ b/codex-rs/core/tests/common/Cargo.toml @@ -18,6 +18,7 @@ base64 = { workspace = true } codex-arg0 = { workspace = true } codex-config = { workspace = true } codex-core = { workspace = true } +codex-extension-api = { workspace = true } codex-exec-server = { workspace = true } codex-features = { workspace = true } codex-hooks = { workspace = true } diff --git a/codex-rs/core/tests/common/test_codex.rs b/codex-rs/core/tests/common/test_codex.rs index c348d76481..ba338b877c 100644 --- a/codex-rs/core/tests/common/test_codex.rs +++ b/codex-rs/core/tests/common/test_codex.rs @@ -23,6 +23,7 @@ use codex_core::thread_store_from_config; use codex_exec_server::CreateDirectoryOptions; use codex_exec_server::ExecutorFileSystem; use codex_exec_server::RemoveOptions; +use codex_extension_api::empty_extension_registry; use codex_features::Feature; use codex_login::CodexAuth; use codex_model_provider_info::ModelProviderInfo; @@ -431,6 +432,7 @@ impl TestCodexBuilder { codex_core::test_support::auth_manager_from_auth(auth.clone()), SessionSource::Exec, Arc::clone(&environment_manager), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store, state_db.clone(), diff --git a/codex-rs/core/tests/suite/client.rs b/codex-rs/core/tests/suite/client.rs index 432b57de9f..63b8b3e31a 100644 --- a/codex-rs/core/tests/suite/client.rs +++ b/codex-rs/core/tests/suite/client.rs @@ -7,6 +7,7 @@ use codex_core::ResponseEvent; use codex_core::ThreadManager; use codex_core::resolve_installation_id; use codex_core::thread_store_from_config; +use codex_extension_api::empty_extension_registry; use codex_features::Feature; use codex_login::AuthManager; use codex_login::CodexAuth; @@ -1122,6 +1123,7 @@ async fn prefers_apikey_when_config_prefers_apikey_even_with_chatgpt_tokens() { auth_manager, SessionSource::Exec, Arc::new(codex_exec_server::EnvironmentManager::default_for_tests()), + empty_extension_registry(), /*analytics_events_client*/ None, thread_store_from_config(&config, /*state_db*/ None), /*state_db*/ None, diff --git a/codex-rs/mcp-server/Cargo.toml b/codex-rs/mcp-server/Cargo.toml index ffe729aae1..29b2d6c7d7 100644 --- a/codex-rs/mcp-server/Cargo.toml +++ b/codex-rs/mcp-server/Cargo.toml @@ -22,6 +22,7 @@ codex-arg0 = { workspace = true } codex-config = { workspace = true } codex-core = { workspace = true } codex-exec-server = { workspace = true } +codex-extension-api = { workspace = true } codex-login = { workspace = true } codex-protocol = { workspace = true } codex-utils-cli = { workspace = true } diff --git a/codex-rs/mcp-server/src/message_processor.rs b/codex-rs/mcp-server/src/message_processor.rs index d64fc43b1b..bb6d4bb84a 100644 --- a/codex-rs/mcp-server/src/message_processor.rs +++ b/codex-rs/mcp-server/src/message_processor.rs @@ -7,6 +7,7 @@ use codex_core::ThreadManager; use codex_core::config::Config; use codex_core::thread_store_from_config; use codex_exec_server::EnvironmentManager; +use codex_extension_api::empty_extension_registry; use codex_login::AuthManager; use codex_login::default_client::USER_AGENT_SUFFIX; use codex_login::default_client::get_codex_user_agent; @@ -68,6 +69,7 @@ impl MessageProcessor { auth_manager, SessionSource::Mcp, environment_manager, + empty_extension_registry(), /*analytics_events_client*/ None, thread_store_from_config(config.as_ref(), state_db.clone()), state_db.clone(), diff --git a/codex-rs/thread-manager-sample/src/main.rs b/codex-rs/thread-manager-sample/src/main.rs index 6817f677e6..335d30595d 100644 --- a/codex-rs/thread-manager-sample/src/main.rs +++ b/codex-rs/thread-manager-sample/src/main.rs @@ -54,6 +54,7 @@ use codex_core_api::UserInput; use codex_core_api::WebSearchMode; use codex_core_api::arg0_dispatch_or_else; use codex_core_api::built_in_model_providers; +use codex_core_api::empty_extension_registry; use codex_core_api::find_codex_home; use codex_core_api::init_state_db; use codex_core_api::item_event_to_server_notification; @@ -122,6 +123,7 @@ async fn run_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> { auth_manager, SessionSource::Exec, environment_manager, + empty_extension_registry(), /*analytics_events_client*/ None, Arc::clone(&thread_store), state_db,