Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions codex-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 3 additions & 20 deletions codex-rs/app-server/src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use codex_core::NewThread;
use codex_core::StartThreadOptions;
use codex_core::ThreadManager;
use codex_core::config::Config;
use codex_exec_server::EnvironmentManager;
use codex_extension_api::AgentSpawnFuture;
use codex_extension_api::AgentSpawner;
use codex_extension_api::ExtensionEventSink;
Expand All @@ -35,8 +34,6 @@ pub(crate) struct ThreadExtensionDependencies {
pub(crate) analytics_events_client: AnalyticsEventsClient,
pub(crate) thread_manager: Weak<ThreadManager>,
pub(crate) goal_service: Arc<GoalService>,
pub(crate) environment_manager: Arc<EnvironmentManager>,
pub(crate) executor_skill_provider: Arc<dyn codex_skills_extension::SkillProvider>,
/// Process-scoped persistence backend for extensions that need stored thread history.
pub(crate) thread_store: Arc<dyn ThreadStore>,
}
Expand All @@ -55,8 +52,6 @@ where
analytics_events_client,
thread_manager,
goal_service,
environment_manager,
executor_skill_provider,
thread_store: _thread_store,
} = dependencies;
let mut builder = ExtensionRegistryBuilder::<Config>::with_event_sink(event_sink);
Expand All @@ -74,25 +69,13 @@ where
codex_guardian::install(&mut builder, guardian_agent_spawner);
codex_memories_extension::install(&mut builder, codex_otel::global());
codex_mcp_extension::install(&mut builder);
codex_mcp_extension::install_executor_plugins(&mut builder, environment_manager);
codex_web_search_extension::install(&mut builder, auth_manager.clone());
codex_image_generation_extension::install(&mut builder, auth_manager, |config: &Config| {
Some(config.codex_home.clone())
});
let skill_providers = codex_skills_extension::SkillProviders::new()
.with_executor_provider(executor_skill_provider)
.with_orchestrator_provider(Arc::new(
codex_skills_extension::OrchestratorSkillProvider::new(),
));
codex_skills_extension::install_with_providers(
&mut builder,
skill_providers,
|config: &Config| codex_skills_extension::SkillsExtensionConfig {
include_instructions: config.include_skill_instructions,
bundled_skills_enabled: config.bundled_skills_enabled(),
orchestrator_skills_enabled: config.orchestrator_skills_enabled,
},
);
codex_skills_extension::install(&mut builder, |config: &Config| {
config.orchestrator_skills_enabled
});
Arc::new(builder.build())
}

Expand Down
7 changes: 0 additions & 7 deletions codex-rs/app-server/src/mcp_refresh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,6 @@ mod tests {
.expect("refresh tests require state db");
let thread_store = thread_store_from_config(&good_config, Some(state_db.clone()));
let environment_manager = Arc::new(EnvironmentManager::default_for_tests());
let executor_skill_provider: Arc<dyn codex_skills_extension::SkillProvider> = Arc::new(
codex_skills_extension::ExecutorSkillProvider::new_with_restriction_product(
Arc::clone(&environment_manager),
SessionSource::Exec.restriction_product(),
),
);
let thread_manager = Arc::new_cyclic(|thread_manager| {
ThreadManager::new(
&good_config,
Expand All @@ -238,7 +232,6 @@ mod tests {
thread_manager: thread_manager.clone(),
goal_service: Arc::new(codex_goal_extension::GoalService::new()),
environment_manager: Arc::clone(&environment_manager),
executor_skill_provider: Arc::clone(&executor_skill_provider),
thread_store: Arc::clone(&thread_store),
},
),
Expand Down
10 changes: 0 additions & 10 deletions codex-rs/app-server/src/message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,14 +336,6 @@ impl MessageProcessor {
// resumed, or forked threads to a different persistence backend/root.
let thread_store = codex_core::thread_store_from_config(config.as_ref(), state_db.clone());
let environment_manager_for_requests = Arc::clone(&environment_manager);
let environment_manager_for_extensions = Arc::clone(&environment_manager);
let restriction_product = session_source.restriction_product();
let executor_skill_provider: Arc<dyn codex_skills_extension::SkillProvider> = Arc::new(
codex_skills_extension::ExecutorSkillProvider::new_with_restriction_product(
Arc::clone(&environment_manager_for_extensions),
restriction_product,
),
);
let goal_service = Arc::new(GoalService::new());
let thread_manager = Arc::new_cyclic(|thread_manager| {
ThreadManager::new(
Expand All @@ -363,8 +355,6 @@ impl MessageProcessor {
analytics_events_client: analytics_events_client.clone(),
thread_manager: thread_manager.clone(),
goal_service: Arc::clone(&goal_service),
environment_manager: Arc::clone(&environment_manager_for_extensions),
executor_skill_provider: Arc::clone(&executor_skill_provider),
thread_store: Arc::clone(&thread_store),
},
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ impl ExternalAgentSessionImporter {
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
},
dynamic_tools: Vec::new(),
selected_capability_roots: Vec::new(),
multi_agent_version: Some(MultiAgentVersion::V1),
initial_window_id: uuid::Uuid::now_v7().to_string(),
metadata: ThreadPersistenceMetadata {
Expand Down
2 changes: 2 additions & 0 deletions codex-rs/app-server/tests/common/rollout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ fn create_fake_rollout_with_source_and_parent_thread_id(
model_provider: model_provider.map(str::to_string),
base_instructions: None,
dynamic_tools: None,
selected_capability_roots: Vec::new(),
memory_mode: None,
multi_agent_version: None,
context_window: None,
Expand Down Expand Up @@ -288,6 +289,7 @@ pub fn create_fake_rollout_with_text_elements(
model_provider: model_provider.map(str::to_string),
base_instructions: None,
dynamic_tools: None,
selected_capability_roots: Vec::new(),
memory_mode: None,
multi_agent_version: None,
context_window: None,
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/tests/suite/conversation_summary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ async fn get_conversation_summary_by_thread_id_reads_pathless_store_thread() ->
originator: "test_originator".to_string(),
base_instructions: BaseInstructions::default(),
dynamic_tools: Vec::new(),
selected_capability_roots: Vec::new(),
multi_agent_version: None,
initial_window_id: Uuid::now_v7().to_string(),
metadata: ThreadPersistenceMetadata {
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/tests/suite/v2/remote_thread_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ async fn thread_delete_with_non_local_thread_store_does_not_create_local_persist
originator: "test_originator".to_string(),
base_instructions: BaseInstructions::default(),
dynamic_tools: Vec::new(),
selected_capability_roots: Vec::new(),
multi_agent_version: None,
initial_window_id: Uuid::now_v7().to_string(),
metadata: ThreadPersistenceMetadata {
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/tests/suite/v2/thread_read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,7 @@ async fn seed_pathless_store_thread(
originator: "test_originator".to_string(),
base_instructions: BaseInstructions::default(),
dynamic_tools: Vec::new(),
selected_capability_roots: Vec::new(),
multi_agent_version: None,
initial_window_id: Uuid::now_v7().to_string(),
metadata: ThreadPersistenceMetadata {
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/tests/suite/v2/thread_resume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2070,6 +2070,7 @@ stream_max_retries = 0
model_provider: Some("mock_provider".to_string()),
base_instructions: None,
dynamic_tools: None,
selected_capability_roots: Vec::new(),
memory_mode: None,
multi_agent_version: None,
context_window: None,
Expand Down
1 change: 1 addition & 0 deletions codex-rs/app-server/tests/suite/v2/thread_unarchive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ async fn thread_unarchive_preserves_pathless_store_metadata() -> Result<()> {
originator: "test_originator".to_string(),
base_instructions: BaseInstructions::default(),
dynamic_tools: Vec::new(),
selected_capability_roots: Vec::new(),
multi_agent_version: None,
initial_window_id: Uuid::now_v7().to_string(),
metadata: ThreadPersistenceMetadata {
Expand Down
37 changes: 29 additions & 8 deletions codex-rs/codex-mcp/src/resource_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ pub struct McpResourceReadResult {
/// snapshot, so calls automatically use replacements installed during startup and refresh.
#[derive(Clone)]
pub struct McpResourceClient {
manager: Arc<ArcSwap<McpConnectionManager>>,
manager: ResourceManager,
}

#[derive(Clone)]
enum ResourceManager {
Live(Arc<ArcSwap<McpConnectionManager>>),
Snapshot(Arc<McpConnectionManager>),
}

/// Opaque identity for the manager currently used by an MCP resource client.
Expand All @@ -59,19 +65,36 @@ impl std::fmt::Debug for McpResourceClient {
impl McpResourceClient {
/// Creates a resource client backed by the session's replaceable MCP manager.
pub fn new(manager: Arc<ArcSwap<McpConnectionManager>>) -> Self {
Self { manager }
Self {
manager: ResourceManager::Live(manager),
}
}

/// Pins resource calls to the manager generation that is current now.
pub fn snapshot(&self) -> Self {
Self {
manager: ResourceManager::Snapshot(self.manager_snapshot()),
}
}

/// Returns the exact manager generation used by this client right now.
pub fn manager_snapshot(&self) -> Arc<McpConnectionManager> {
match &self.manager {
ResourceManager::Live(manager) => manager.load_full(),
ResourceManager::Snapshot(manager) => Arc::clone(manager),
}
}

/// Returns an identity that changes whenever the published manager changes.
pub fn cache_key(&self) -> McpResourceClientCacheKey {
McpResourceClientCacheKey(Arc::downgrade(&self.manager.load_full()))
McpResourceClientCacheKey(Arc::downgrade(&self.manager_snapshot()))
}

/// Returns whether the current manager contains the named server.
///
/// This does not wait for server startup or imply that startup succeeded.
pub async fn has_server(&self, server: &str) -> bool {
self.manager.load_full().contains_server(server)
self.manager_snapshot().contains_server(server)
}

/// Lists one resource page from the named server.
Expand All @@ -83,8 +106,7 @@ impl McpResourceClient {
let params =
cursor.map(|cursor| PaginatedRequestParams::default().with_cursor(Some(cursor)));
let result = self
.manager
.load_full()
.manager_snapshot()
.list_resources(server, params)
.await?;
let resources = result
Expand All @@ -101,8 +123,7 @@ impl McpResourceClient {
/// Reads one resource from the named server.
pub async fn read_resource(&self, server: &str, uri: &str) -> Result<McpResourceReadResult> {
let result = self
.manager
.load_full()
.manager_snapshot()
.read_resource(server, ReadResourceRequestParams::new(uri.to_string()))
.await?;
let contents = result
Expand Down
6 changes: 0 additions & 6 deletions codex-rs/connectors/src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,17 @@ use codex_plugin::PluginCapabilitySummary;
/// Connector declarations contributed by one plugin package.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PluginConnectorSource {
plugin_id: String,
plugin_display_name: String,
connector_ids: Vec<AppConnectorId>,
}

impl PluginConnectorSource {
/// Creates one plugin source from parsed app declarations.
pub fn new(
plugin_id: impl Into<String>,
plugin_display_name: impl Into<String>,
declarations: impl IntoIterator<Item = AppDeclaration>,
) -> Self {
Self::from_connector_ids(
plugin_id,
plugin_display_name,
declarations
.into_iter()
Expand All @@ -31,7 +28,6 @@ impl PluginConnectorSource {

/// Creates one plugin source from connector IDs that were already parsed.
pub fn from_connector_ids(
plugin_id: impl Into<String>,
plugin_display_name: impl Into<String>,
connector_ids: impl IntoIterator<Item = AppConnectorId>,
) -> Self {
Expand All @@ -42,7 +38,6 @@ impl PluginConnectorSource {
.filter(|connector_id| seen_connector_ids.insert(connector_id.clone()))
.collect();
Self {
plugin_id: plugin_id.into(),
plugin_display_name: plugin_display_name.into(),
connector_ids,
}
Expand Down Expand Up @@ -105,7 +100,6 @@ impl ConnectorSnapshot {
pub fn from_plugin_capability_summaries(summaries: &[PluginCapabilitySummary]) -> Self {
Self::from_plugin_sources(summaries.iter().map(|summary| {
PluginConnectorSource::from_connector_ids(
summary.config_name.clone(),
summary.display_name.clone(),
summary.app_connector_ids.clone(),
)
Expand Down
15 changes: 6 additions & 9 deletions codex-rs/connectors/src/snapshot_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ use super::PluginConnectorSource;

#[test]
fn snapshot_merges_sources_in_order_and_dedupes_provenance() {
let host_source = source("host", "Zulu", &["calendar", "calendar"]);
let host = ConnectorSnapshot::from_plugin_sources([
source("skills", "Skills only", &[]),
host_source.clone(),
]);
let host_source = source("Zulu", &["calendar", "calendar"]);
let host =
ConnectorSnapshot::from_plugin_sources([source("Skills only", &[]), host_source.clone()]);
let selected = ConnectorSnapshot::from_plugin_sources([
source("selected-a", "Alpha", &["drive", "calendar"]),
source("selected-b", "Alpha", &["calendar"]),
source("Alpha", &["drive", "calendar"]),
source("Alpha", &["calendar"]),
]);

let merged = host.merged_with(&selected);
Expand All @@ -36,9 +34,8 @@ fn snapshot_merges_sources_in_order_and_dedupes_provenance() {
);
}

fn source(id: &str, display_name: &str, connector_ids: &[&str]) -> PluginConnectorSource {
fn source(display_name: &str, connector_ids: &[&str]) -> PluginConnectorSource {
PluginConnectorSource::from_connector_ids(
id,
display_name,
connector_ids
.iter()
Expand Down
2 changes: 0 additions & 2 deletions codex-rs/core-skills/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ workspace = true

[dependencies]
anyhow = { workspace = true }
codex-analytics = { workspace = true }
codex-config = { workspace = true }
codex-context-fragments = { workspace = true }
codex-exec-server = { workspace = true }
codex-login = { workspace = true }
codex-model-provider = { workspace = true }
Expand Down
Loading
Loading