Make local environment optional in EnvironmentManager (#23369)

## Summary
- make `EnvironmentManager` local environment/runtime paths optional
- simplify constructor surface around snapshot materialization
- rename local env accessors to `require_local_environment` /
`try_local_environment`

## Validation
- devbox Bazel build for touched crate surfaces
- `//codex-rs/exec-server:exec-server-unit-tests`
- `//codex-rs/app-server-client:app-server-client-unit-tests`
- filtered touched `//codex-rs/core:core-unit-tests` cases
This commit is contained in:
starr-openai
2026-05-19 12:55:34 -07:00
committed by GitHub
parent 7f4d7ae3a4
commit 5c43a64e2b
26 changed files with 853 additions and 298 deletions
+9 -6
View File
@@ -198,7 +198,8 @@ pub async fn list_accessible_connectors_from_mcp_tools_with_options_and_status(
config.codex_linux_sandbox_exe.clone(),
)?;
let environment_manager =
EnvironmentManager::from_codex_home(config.codex_home.clone(), local_runtime_paths).await?;
EnvironmentManager::from_codex_home(config.codex_home.clone(), Some(local_runtime_paths))
.await?;
list_accessible_connectors_from_mcp_tools_with_environment_manager(
config,
force_refetch,
@@ -261,10 +262,6 @@ pub async fn list_accessible_connectors_from_mcp_tools_with_environment_manager(
let (tx_event, rx_event) = unbounded();
drop(rx_event);
let environment = environment_manager
.default_environment()
.unwrap_or_else(|| environment_manager.local_environment());
let (mut mcp_connection_manager, cancel_token) = McpConnectionManager::new(
&mcp_servers,
config.mcp_oauth_credentials_store_mode,
@@ -273,7 +270,13 @@ pub async fn list_accessible_connectors_from_mcp_tools_with_environment_manager(
INITIAL_SUBMIT_ID.to_owned(),
tx_event,
PermissionProfile::default(),
McpRuntimeEnvironment::new(environment, config.cwd.to_path_buf()),
// Connector discovery is threadless. Use an actually configured env if
// one exists, but do not reintroduce the old hidden-local fallback.
McpRuntimeEnvironment::new(
environment_manager.default_or_local_environment(),
environment_manager.try_local_environment(),
config.cwd.to_path_buf(),
),
config.codex_home.to_path_buf(),
codex_apps_tools_cache_key(auth.as_ref()),
host_owned_codex_apps_enabled,
+6 -5
View File
@@ -106,7 +106,7 @@ mod tests {
let cwd = AbsolutePathBuf::current_dir().expect("cwd");
let manager = EnvironmentManager::create_for_tests(
Some("ws://127.0.0.1:8765".to_string()),
test_runtime_paths(),
Some(test_runtime_paths()),
)
.await;
@@ -132,9 +132,10 @@ url = "ws://127.0.0.1:8765"
)
.expect("write environments.toml");
let cwd = AbsolutePathBuf::current_dir().expect("cwd");
let manager = EnvironmentManager::from_codex_home(temp_dir.path(), test_runtime_paths())
.await
.expect("environment manager");
let manager =
EnvironmentManager::from_codex_home(temp_dir.path(), Some(test_runtime_paths()))
.await
.expect("environment manager");
assert_eq!(
default_thread_environment_selections(&manager, &cwd),
@@ -154,7 +155,7 @@ url = "ws://127.0.0.1:8765"
#[tokio::test]
async fn default_thread_environment_selections_empty_when_default_disabled() {
let cwd = AbsolutePathBuf::current_dir().expect("cwd");
let manager = EnvironmentManager::disabled_for_tests(test_runtime_paths());
let manager = EnvironmentManager::without_environments();
assert_eq!(
default_thread_environment_selections(&manager, &cwd),
+10 -6
View File
@@ -1235,8 +1235,8 @@ async fn install_host_owned_codex_apps_manager(session: &Session, turn_context:
let environment = session
.services
.environment_manager
.default_environment()
.unwrap_or_else(|| session.services.environment_manager.local_environment());
.default_or_local_environment()
.expect("test session should have an MCP runtime environment");
let (manager, _cancel_token) = codex_mcp::McpConnectionManager::new(
&HashMap::new(),
turn_context.config.mcp_oauth_credentials_store_mode,
@@ -1245,10 +1245,14 @@ async fn install_host_owned_codex_apps_manager(session: &Session, turn_context:
turn_context.sub_id.clone(),
session.get_tx_event(),
turn_context.permission_profile(),
codex_mcp::McpRuntimeEnvironment::new(environment, {
#[allow(deprecated)]
turn_context.cwd.to_path_buf()
}),
codex_mcp::McpRuntimeEnvironment::new(
Some(environment),
session.services.environment_manager.try_local_environment(),
{
#[allow(deprecated)]
turn_context.cwd.to_path_buf()
},
),
turn_context.config.codex_home.to_path_buf(),
codex_mcp::codex_apps_tools_cache_key(auth.as_ref()),
/*host_owned_codex_apps_enabled*/ true,
+6 -3
View File
@@ -45,9 +45,12 @@ pub async fn build_prompt_input(
Arc::clone(&auth_manager),
SessionSource::Exec,
Arc::new(
EnvironmentManager::from_codex_home(config.codex_home.clone(), local_runtime_paths)
.await
.map_err(|err| CodexErr::Fatal(err.to_string()))?,
EnvironmentManager::from_codex_home(
config.codex_home.clone(),
Some(local_runtime_paths),
)
.await
.map_err(|err| CodexErr::Fatal(err.to_string()))?,
),
empty_extension_registry(),
/*analytics_events_client*/ None,
+4 -3
View File
@@ -291,14 +291,15 @@ impl Session {
compute_auth_statuses(mcp_servers.iter(), store_mode, auth.as_ref()).await;
let mcp_runtime_environment = match turn_context.environments.primary() {
Some(turn_environment) => McpRuntimeEnvironment::new(
Arc::clone(&turn_environment.environment),
Some(Arc::clone(&turn_environment.environment)),
self.services.environment_manager.try_local_environment(),
turn_environment.cwd.to_path_buf(),
),
None => McpRuntimeEnvironment::new(
self.services
.environment_manager
.default_environment()
.unwrap_or_else(|| self.services.environment_manager.local_environment()),
.default_or_local_environment(),
self.services.environment_manager.try_local_environment(),
#[allow(deprecated)]
turn_context.cwd.to_path_buf(),
),
+4 -5
View File
@@ -1050,14 +1050,13 @@ impl Session {
.cloned();
let mcp_runtime_environment = match turn_environment {
Some(turn_environment) => McpRuntimeEnvironment::new(
Arc::clone(&turn_environment.environment),
Some(Arc::clone(&turn_environment.environment)),
sess.services.environment_manager.try_local_environment(),
turn_environment.cwd.to_path_buf(),
),
None => McpRuntimeEnvironment::new(
sess.services
.environment_manager
.default_environment()
.unwrap_or_else(|| sess.services.environment_manager.local_environment()),
sess.services.environment_manager.default_or_local_environment(),
sess.services.environment_manager.try_local_environment(),
session_configuration.cwd.to_path_buf(),
),
};
+2 -2
View File
@@ -309,7 +309,7 @@ async fn start_thread_rejects_explicit_local_environment_when_default_provider_i
let environment_manager = Arc::new(
codex_exec_server::EnvironmentManager::create_for_tests(
Some("none".to_string()),
runtime_paths,
Some(runtime_paths),
)
.await,
);
@@ -373,7 +373,7 @@ args = ["dev", "cd /tmp && true"]
let environment_manager = Arc::new(
codex_exec_server::EnvironmentManager::from_codex_home(
config.codex_home.clone(),
runtime_paths,
Some(runtime_paths),
)
.await
.expect("environment manager"),