Skip to content
Merged
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
1 change: 1 addition & 0 deletions codex-rs/Cargo.lock

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

11 changes: 5 additions & 6 deletions codex-rs/core/tests/common/test_codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const SUBMIT_TURN_COMPLETE_TIMEOUT: Duration = Duration::from_secs(30);
#[derive(Debug)]
pub struct TestEnv {
environment: codex_exec_server::Environment,
exec_server_url: Option<String>,
cwd: AbsolutePathBuf,
local_cwd_temp_dir: Option<Arc<TempDir>>,
remote_container_name: Option<String>,
Expand All @@ -85,6 +86,7 @@ impl TestEnv {
codex_exec_server::Environment::create_for_tests(/*exec_server_url*/ None)?;
Ok(Self {
environment,
exec_server_url: None,
cwd,
local_cwd_temp_dir: Some(local_cwd_temp_dir),
remote_container_name: None,
Expand All @@ -99,10 +101,6 @@ impl TestEnv {
&self.environment
}

pub fn exec_server_url(&self) -> Option<&str> {
self.environment.exec_server_url()
}

fn local_cwd_temp_dir(&self) -> Option<Arc<TempDir>> {
self.local_cwd_temp_dir.clone()
}
Expand All @@ -122,7 +120,7 @@ pub async fn test_env() -> Result<TestEnv> {
Some(remote_env) => {
let websocket_url = remote_exec_server_url()?;
let environment =
codex_exec_server::Environment::create_for_tests(Some(websocket_url))?;
codex_exec_server::Environment::create_for_tests(Some(websocket_url.clone()))?;
let cwd = remote_aware_cwd_path();
environment
.get_filesystem()
Expand All @@ -134,6 +132,7 @@ pub async fn test_env() -> Result<TestEnv> {
.await?;
Ok(TestEnv {
environment,
exec_server_url: Some(websocket_url),
cwd,
local_cwd_temp_dir: None,
remote_container_name: Some(remote_env.container_name),
Expand Down Expand Up @@ -384,7 +383,7 @@ impl TestCodexBuilder {
let exec_server_url = self
.exec_server_url
.clone()
.or_else(|| test_env.exec_server_url().map(str::to_owned));
.or_else(|| test_env.exec_server_url.clone());
let local_runtime_paths = codex_exec_server::ExecServerRuntimePaths::new(
std::env::current_exe()?,
/*codex_linux_sandbox_exe*/ None,
Expand Down
3 changes: 3 additions & 0 deletions codex-rs/exec-server/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ load("//:defs.bzl", "codex_rust_crate")
codex_rust_crate(
name = "exec-server",
crate_name = "codex_exec_server",
deps_extra = [
"@crates//:toml",
],
# Keep the crate's integration tests single-threaded under Bazel because
# they install process-global test-binary dispatch state, and the remote
# exec-server cases already rely on serialization around the full CLI path.
Expand Down
1 change: 1 addition & 0 deletions codex-rs/exec-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sha2 = { workspace = true }
thiserror = { workspace = true }
toml = { workspace = true }
tokio = { workspace = true, features = [
"fs",
"io-std",
Expand Down
43 changes: 38 additions & 5 deletions codex-rs/exec-server/src/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::environment_provider::EnvironmentDefault;
use crate::environment_provider::EnvironmentProvider;
use crate::environment_provider::EnvironmentProviderSnapshot;
use crate::environment_provider::normalize_exec_server_url;
use crate::environment_toml::environment_provider_from_codex_home;
use crate::local_file_system::LocalFileSystem;
use crate::local_process::LocalProcess;
use crate::process::ExecBackend;
Expand Down Expand Up @@ -99,6 +100,20 @@ impl EnvironmentManager {
Self::from_default_provider_url(exec_server_url, local_runtime_paths).await
}

/// Builds a manager from `CODEX_HOME` and local runtime paths used when
/// creating local filesystem helpers.
///
/// If `CODEX_HOME/environments.toml` is present, it defines the configured
/// environments. Otherwise this preserves the legacy
/// `CODEX_EXEC_SERVER_URL` behavior.
pub async fn from_codex_home(
codex_home: impl AsRef<std::path::Path>,
local_runtime_paths: ExecServerRuntimePaths,
) -> Result<Self, ExecServerError> {
let provider = environment_provider_from_codex_home(codex_home.as_ref())?;
Self::from_provider(provider.as_ref(), local_runtime_paths).await
}

async fn from_default_provider_url(
exec_server_url: Option<String>,
local_runtime_paths: ExecServerRuntimePaths,
Expand Down Expand Up @@ -194,6 +209,7 @@ impl EnvironmentManager {
#[derive(Clone)]
pub struct Environment {
exec_server_url: Option<String>,
remote_transport: Option<ExecServerTransportParams>,
exec_backend: Arc<dyn ExecBackend>,
filesystem: Arc<dyn ExecutorFileSystem>,
http_client: Arc<dyn HttpClient>,
Expand All @@ -205,6 +221,7 @@ impl Environment {
pub fn default_for_tests() -> Self {
Self {
exec_server_url: None,
remote_transport: None,
exec_backend: Arc::new(LocalProcess::default()),
filesystem: Arc::new(LocalFileSystem::unsandboxed()),
http_client: Arc::new(ReqwestHttpClient),
Expand Down Expand Up @@ -260,6 +277,7 @@ impl Environment {
pub(crate) fn local(local_runtime_paths: ExecServerRuntimePaths) -> Self {
Self {
exec_server_url: None,
remote_transport: None,
exec_backend: Arc::new(LocalProcess::default()),
filesystem: Arc::new(LocalFileSystem::with_runtime_paths(
local_runtime_paths.clone(),
Expand All @@ -273,15 +291,30 @@ impl Environment {
exec_server_url: String,
local_runtime_paths: Option<ExecServerRuntimePaths>,
) -> Self {
let client = LazyRemoteExecServerClient::new(ExecServerTransportParams::WebSocketUrl(
exec_server_url.clone(),
));
Self::remote_with_transport(
ExecServerTransportParams::WebSocketUrl(exec_server_url),
local_runtime_paths,
)
}

pub(crate) fn remote_with_transport(
remote_transport: ExecServerTransportParams,
local_runtime_paths: Option<ExecServerRuntimePaths>,
) -> Self {
let exec_server_url = match &remote_transport {
ExecServerTransportParams::WebSocketUrl(exec_server_url) => {
Some(exec_server_url.clone())
}
ExecServerTransportParams::StdioCommand(_) => None,
};
let client = LazyRemoteExecServerClient::new(remote_transport.clone());
let exec_backend: Arc<dyn ExecBackend> = Arc::new(RemoteProcess::new(client.clone()));
let filesystem: Arc<dyn ExecutorFileSystem> =
Arc::new(RemoteFileSystem::new(client.clone()));

Self {
exec_server_url: Some(exec_server_url),
exec_server_url,
remote_transport: Some(remote_transport),
exec_backend,
filesystem,
http_client: Arc::new(client),
Expand All @@ -290,7 +323,7 @@ impl Environment {
}

pub fn is_remote(&self) -> bool {
self.exec_server_url.is_some()
self.remote_transport.is_some()
}

/// Returns the remote exec-server URL when this environment is remote.
Expand Down
Loading
Loading