Move environment abstraction into exec server (#15125)

The idea is that codex-exec exposes an Environment struct with services
on it. Each of those is a trait.

Depending on construction parameters passed to Environment they are
either backed by local or remote server but core doesn't see these
differences.
This commit is contained in:
pakrym-oai 2026-03-19 08:31:14 -07:00 committed by GitHub
parent 32d2df5c1e
commit dee03da508
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 43 additions and 72 deletions

18
codex-rs/Cargo.lock generated
View file

@ -1427,7 +1427,7 @@ dependencies = [
"codex-chatgpt",
"codex-cloud-requirements",
"codex-core",
"codex-environment",
"codex-exec-server",
"codex-feedback",
"codex-file-search",
"codex-login",
@ -1843,7 +1843,7 @@ dependencies = [
"codex-client",
"codex-config",
"codex-connectors",
"codex-environment",
"codex-exec-server",
"codex-execpolicy",
"codex-file-search",
"codex-git",
@ -1947,17 +1947,6 @@ dependencies = [
"serde_json",
]
[[package]]
name = "codex-environment"
version = "0.0.0"
dependencies = [
"async-trait",
"codex-utils-absolute-path",
"pretty_assertions",
"tempfile",
"tokio",
]
[[package]]
name = "codex-exec"
version = "0.0.0"
@ -2008,13 +1997,16 @@ name = "codex-exec-server"
version = "0.0.0"
dependencies = [
"anyhow",
"async-trait",
"clap",
"codex-app-server-protocol",
"codex-utils-absolute-path",
"codex-utils-cargo-bin",
"futures",
"pretty_assertions",
"serde",
"serde_json",
"tempfile",
"thiserror 2.0.18",
"tokio",
"tokio-tungstenite",

View file

@ -22,7 +22,6 @@ members = [
"shell-escalation",
"skills",
"core",
"environment",
"hooks",
"secrets",
"exec",
@ -105,8 +104,8 @@ codex-cloud-requirements = { path = "cloud-requirements" }
codex-connectors = { path = "connectors" }
codex-config = { path = "config" }
codex-core = { path = "core" }
codex-environment = { path = "environment" }
codex-exec = { path = "exec" }
codex-exec-server = { path = "exec-server" }
codex-execpolicy = { path = "execpolicy" }
codex-experimental-api-macros = { path = "codex-experimental-api-macros" }
codex-feedback = { path = "feedback" }

View file

@ -32,7 +32,7 @@ axum = { workspace = true, default-features = false, features = [
codex-arg0 = { workspace = true }
codex-cloud-requirements = { workspace = true }
codex-core = { workspace = true }
codex-environment = { workspace = true }
codex-exec-server = { workspace = true }
codex-otel = { workspace = true }
codex-shell-command = { workspace = true }
codex-utils-cli = { workspace = true }

View file

@ -18,11 +18,11 @@ use codex_app_server_protocol::FsRemoveResponse;
use codex_app_server_protocol::FsWriteFileParams;
use codex_app_server_protocol::FsWriteFileResponse;
use codex_app_server_protocol::JSONRPCErrorError;
use codex_environment::CopyOptions;
use codex_environment::CreateDirectoryOptions;
use codex_environment::Environment;
use codex_environment::ExecutorFileSystem;
use codex_environment::RemoveOptions;
use codex_exec_server::CopyOptions;
use codex_exec_server::CreateDirectoryOptions;
use codex_exec_server::Environment;
use codex_exec_server::ExecutorFileSystem;
use codex_exec_server::RemoveOptions;
use std::io;
use std::sync::Arc;

View file

@ -34,7 +34,7 @@ codex-async-utils = { workspace = true }
codex-client = { workspace = true }
codex-connectors = { workspace = true }
codex-config = { workspace = true }
codex-environment = { workspace = true }
codex-exec-server = { workspace = true }
codex-shell-command = { workspace = true }
codex-skills = { workspace = true }
codex-execpolicy = { workspace = true }

View file

@ -59,7 +59,7 @@ use chrono::Local;
use chrono::Utc;
use codex_app_server_protocol::McpServerElicitationRequest;
use codex_app_server_protocol::McpServerElicitationRequestParams;
use codex_environment::Environment;
use codex_exec_server::Environment;
use codex_hooks::HookEvent;
use codex_hooks::HookEventAfterAgent;
use codex_hooks::HookPayload;

View file

@ -2450,7 +2450,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
true,
));
let network_approval = Arc::new(NetworkApprovalService::default());
let environment = Arc::new(codex_environment::Environment);
let environment = Arc::new(codex_exec_server::Environment);
let file_watcher = Arc::new(FileWatcher::noop());
let services = SessionServices {
@ -3244,7 +3244,7 @@ pub(crate) async fn make_session_and_context_with_dynamic_tools_and_rx(
true,
));
let network_approval = Arc::new(NetworkApprovalService::default());
let environment = Arc::new(codex_environment::Environment);
let environment = Arc::new(codex_exec_server::Environment);
let file_watcher = Arc::new(FileWatcher::noop());
let services = SessionServices {

View file

@ -20,7 +20,7 @@ use crate::tools::network_approval::NetworkApprovalService;
use crate::tools::runtimes::ExecveSessionApproval;
use crate::tools::sandboxing::ApprovalStore;
use crate::unified_exec::UnifiedExecProcessManager;
use codex_environment::Environment;
use codex_exec_server::Environment;
use codex_hooks::Hooks;
use codex_otel::SessionTelemetry;
use codex_utils_absolute_path::AbsolutePathBuf;

View file

@ -1,5 +1,5 @@
use async_trait::async_trait;
use codex_environment::ExecutorFileSystem;
use codex_exec_server::ExecutorFileSystem;
use codex_protocol::models::FunctionCallOutputBody;
use codex_protocol::models::FunctionCallOutputContentItem;
use codex_protocol::models::FunctionCallOutputPayload;

View file

@ -1,6 +0,0 @@
load("//:defs.bzl", "codex_rust_crate")
codex_rust_crate(
name = "environment",
crate_name = "codex_environment",
)

View file

@ -1,21 +0,0 @@
[package]
name = "codex-environment"
version.workspace = true
edition.workspace = true
license.workspace = true
[lib]
name = "codex_environment"
path = "src/lib.rs"
[lints]
workspace = true
[dependencies]
async-trait = { workspace = true }
codex-utils-absolute-path = { workspace = true }
tokio = { workspace = true, features = ["fs", "io-util", "rt"] }
[dev-dependencies]
pretty_assertions = { workspace = true }
tempfile = { workspace = true }

View file

@ -1,18 +0,0 @@
pub mod fs;
pub use fs::CopyOptions;
pub use fs::CreateDirectoryOptions;
pub use fs::ExecutorFileSystem;
pub use fs::FileMetadata;
pub use fs::FileSystemResult;
pub use fs::ReadDirectoryEntry;
pub use fs::RemoveOptions;
#[derive(Clone, Debug, Default)]
pub struct Environment;
impl Environment {
pub fn get_filesystem(&self) -> impl ExecutorFileSystem + use<> {
fs::LocalFileSystem
}
}

View file

@ -15,13 +15,16 @@ path = "src/bin/codex-exec-server.rs"
workspace = true
[dependencies]
async-trait = { workspace = true }
clap = { workspace = true, features = ["derive"] }
codex-app-server-protocol = { workspace = true }
codex-utils-absolute-path = { workspace = true }
futures = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = [
"fs",
"io-std",
"io-util",
"macros",
@ -38,3 +41,4 @@ tracing = { workspace = true }
anyhow = { workspace = true }
codex-utils-cargo-bin = { workspace = true }
pretty_assertions = { workspace = true }
tempfile = { workspace = true }

View file

@ -0,0 +1,11 @@
use crate::fs;
use crate::fs::ExecutorFileSystem;
#[derive(Clone, Debug, Default)]
pub struct Environment;
impl Environment {
pub fn get_filesystem(&self) -> impl ExecutorFileSystem + use<> {
fs::LocalFileSystem
}
}

View file

@ -1,6 +1,8 @@
mod client;
mod client_api;
mod connection;
mod environment;
mod fs;
mod protocol;
mod rpc;
mod server;
@ -9,6 +11,14 @@ pub use client::ExecServerClient;
pub use client::ExecServerError;
pub use client_api::ExecServerClientConnectOptions;
pub use client_api::RemoteExecServerConnectArgs;
pub use environment::Environment;
pub use fs::CopyOptions;
pub use fs::CreateDirectoryOptions;
pub use fs::ExecutorFileSystem;
pub use fs::FileMetadata;
pub use fs::FileSystemResult;
pub use fs::ReadDirectoryEntry;
pub use fs::RemoveOptions;
pub use protocol::InitializeParams;
pub use protocol::InitializeResponse;
pub use server::DEFAULT_LISTEN_URL;