From e60eeec4bf1be56777caf69243fa0fc66cab1e5f Mon Sep 17 00:00:00 2001 From: starr-openai Date: Thu, 19 Mar 2026 14:56:20 -0700 Subject: [PATCH] Make Environment construction async-only for process setup Remove sync Default from Environment, construct the local process client with connect_in_process() in create(None), and switch the fs-only app server default to a local filesystem constructor. Co-authored-by: Codex --- codex-rs/app-server/src/fs_api.rs | 2 +- codex-rs/exec-server/src/environment.rs | 120 +++++------------------- 2 files changed, 24 insertions(+), 98 deletions(-) diff --git a/codex-rs/app-server/src/fs_api.rs b/codex-rs/app-server/src/fs_api.rs index 9baa2b1dce..7ba4b28b9e 100644 --- a/codex-rs/app-server/src/fs_api.rs +++ b/codex-rs/app-server/src/fs_api.rs @@ -34,7 +34,7 @@ pub(crate) struct FsApi { impl Default for FsApi { fn default() -> Self { Self { - file_system: Arc::new(Environment::default().get_filesystem()), + file_system: Arc::new(Environment::local_filesystem()), } } } diff --git a/codex-rs/exec-server/src/environment.rs b/codex-rs/exec-server/src/environment.rs index f79084e411..6821700213 100644 --- a/codex-rs/exec-server/src/environment.rs +++ b/codex-rs/exec-server/src/environment.rs @@ -1,51 +1,16 @@ use crate::ExecServerClient; use crate::ExecServerClientConnectOptions; use crate::ExecServerError; -use crate::ExecServerEvent; use crate::ExecProcess; use crate::ExecutorEnvironment; use crate::RemoteExecServerConnectArgs; -use crate::protocol::ExecParams; -use crate::protocol::ExecResponse; -use crate::protocol::ReadParams; -use crate::protocol::ReadResponse; -use crate::protocol::TerminateResponse; -use crate::protocol::WriteResponse; use crate::fs; use crate::fs::ExecutorFileSystem; -use async_trait::async_trait; -use std::sync::Arc; -use tokio::sync::broadcast; -use tokio::sync::OnceCell; - -#[derive(Clone)] -struct LocalExecProcess { - client: Arc>, -} - -impl Default for LocalExecProcess { - fn default() -> Self { - Self { - client: Arc::new(OnceCell::new()), - } - } -} #[derive(Clone)] pub struct Environment { experimental_exec_server_url: Option, - remote_exec_server_client: Option, - local_exec_process: LocalExecProcess, -} - -impl Default for Environment { - fn default() -> Self { - Self { - experimental_exec_server_url: None, - remote_exec_server_client: None, - local_exec_process: LocalExecProcess::default(), - } - } + exec_server_client: ExecServerClient, } impl std::fmt::Debug for Environment { @@ -57,7 +22,7 @@ impl std::fmt::Debug for Environment { ) .field( "has_remote_exec_server_client", - &self.remote_exec_server_client.is_some(), + &self.experimental_exec_server_url.is_some(), ) .finish() } @@ -67,23 +32,20 @@ impl Environment { pub async fn create( experimental_exec_server_url: Option, ) -> Result { - let remote_exec_server_client = - if let Some(websocket_url) = experimental_exec_server_url.as_deref() { - Some( - ExecServerClient::connect_websocket(RemoteExecServerConnectArgs::new( - websocket_url.to_string(), - "codex-core".to_string(), - )) - .await?, - ) - } else { - None - }; + let exec_server_client = if let Some(websocket_url) = experimental_exec_server_url.as_deref() + { + ExecServerClient::connect_websocket(RemoteExecServerConnectArgs::new( + websocket_url.to_string(), + "codex-core".to_string(), + )) + .await? + } else { + ExecServerClient::connect_in_process(ExecServerClientConnectOptions::default()).await? + }; Ok(Self { experimental_exec_server_url, - remote_exec_server_client, - local_exec_process: LocalExecProcess::default(), + exec_server_client, }) } @@ -92,18 +54,24 @@ impl Environment { } pub fn remote_exec_server_client(&self) -> Option<&ExecServerClient> { - self.remote_exec_server_client.as_ref() + if self.experimental_exec_server_url.is_some() { + Some(&self.exec_server_client) + } else { + None + } } pub fn process(&self) -> &(dyn ExecProcess + '_) { - self.remote_exec_server_client - .as_ref() - .map_or(&self.local_exec_process as &dyn ExecProcess, |client| client) + &self.exec_server_client } pub fn get_filesystem(&self) -> impl ExecutorFileSystem + use<> { fs::LocalFileSystem } + + pub fn local_filesystem() -> impl ExecutorFileSystem + use<> { + fs::LocalFileSystem + } } impl ExecutorEnvironment for Environment { @@ -112,48 +80,6 @@ impl ExecutorEnvironment for Environment { } } -#[async_trait] -impl ExecProcess for LocalExecProcess { - async fn start(&self, params: ExecParams) -> Result { - self.client().await?.start(params).await - } - - async fn read(&self, params: ReadParams) -> Result { - self.client().await?.read(params).await - } - - async fn write( - &self, - process_id: &str, - chunk: Vec, - ) -> Result { - self.client().await?.write(process_id, chunk).await - } - - async fn terminate(&self, process_id: &str) -> Result { - self.client().await?.terminate(process_id).await - } - - fn subscribe_events(&self) -> broadcast::Receiver { - if let Some(client) = self.client.get() { - client.event_receiver() - } else { - let (_tx, rx) = broadcast::channel(1); - rx - } - } -} - -impl LocalExecProcess { - async fn client(&self) -> Result<&ExecServerClient, ExecServerError> { - self.client - .get_or_try_init(|| async { - ExecServerClient::connect_in_process(ExecServerClientConnectOptions::default()).await - }) - .await; - } -} - #[cfg(test)] mod tests { use super::Environment;