diff --git a/codex-rs/core/src/apply_patch.rs b/codex-rs/core/src/apply_patch.rs index 7efae19f15..f1653bf9e9 100644 --- a/codex-rs/core/src/apply_patch.rs +++ b/codex-rs/core/src/apply_patch.rs @@ -114,7 +114,7 @@ pub(crate) fn convert_apply_patch_to_protocol( mod tests { use super::*; use pretty_assertions::assert_eq; - + use tempfile::tempdir; #[test] diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index cde64105f4..2877098444 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -2616,7 +2616,7 @@ async fn handle_container_exec_with_params( stdout_stream, }; - sess.executor.update_environment( // todo this should not be needed ? Not sure what it means + sess.executor.update_environment( turn_context.sandbox_policy.clone(), turn_context.cwd.clone(), ); diff --git a/codex-rs/core/src/executor/backends.rs b/codex-rs/core/src/executor/backends.rs index 09c786a9d4..aa744b8174 100644 --- a/codex-rs/core/src/executor/backends.rs +++ b/codex-rs/core/src/executor/backends.rs @@ -1,13 +1,11 @@ use std::collections::HashMap; use std::env; -use std::sync::Arc; use async_trait::async_trait; -use crate::apply_patch::ApplyPatchExec; use crate::CODEX_APPLY_PATCH_ARG1; +use crate::apply_patch::ApplyPatchExec; use crate::exec::ExecParams; -use crate::exec::ExecToolCallOutput; use crate::function_tool::FunctionCallError; pub(crate) enum ExecutionMode { @@ -27,29 +25,14 @@ pub(crate) trait ExecutionBackend: Send + Sync { ) -> Result; } -pub(crate) struct BackendStore { - shell: Arc, - apply_patch: Arc, -} +static SHELL_BACKEND: ShellBackend = ShellBackend; +static APPLY_PATCH_BACKEND: ApplyPatchBackend = ApplyPatchBackend; -impl BackendStore { - pub(crate) fn new() -> Self { - Self { - shell: Arc::new(ShellBackend), - apply_patch: Arc::new(ApplyPatchBackend), - } +pub(crate) fn backend_for_mode(mode: &ExecutionMode) -> &'static dyn ExecutionBackend { + match mode { + ExecutionMode::Shell => &SHELL_BACKEND, + ExecutionMode::ApplyPatch(_) => &APPLY_PATCH_BACKEND, } - - pub(crate) fn for_mode(&self, mode: &ExecutionMode) -> Arc { - match mode { - ExecutionMode::Shell => self.shell.clone(), - ExecutionMode::ApplyPatch(_) => self.apply_patch.clone(), - } - } -} - -pub(crate) fn default_backends() -> BackendStore { - BackendStore::new() } struct ShellBackend; @@ -101,7 +84,7 @@ impl ExecutionBackend for ApplyPatchBackend { with_escalated_permissions: params.with_escalated_permissions, justification: params.justification, }) - }, + } ExecutionMode::Shell => Err(FunctionCallError::RespondToModel( "apply_patch backend invoked without patch context".to_string(), )), diff --git a/codex-rs/core/src/executor/runner.rs b/codex-rs/core/src/executor/runner.rs index a65da13802..9161e78659 100644 --- a/codex-rs/core/src/executor/runner.rs +++ b/codex-rs/core/src/executor/runner.rs @@ -5,10 +5,8 @@ use std::time::Duration; use thiserror::Error; -use super::backends::BackendStore; -use super::backends::ExecutionBackend; use super::backends::ExecutionMode; -use super::backends::default_backends; +use super::backends::backend_for_mode; use super::cache::ApprovalCache; use crate::codex::Session; use crate::error::CodexErr; @@ -64,7 +62,6 @@ impl ExecError { /// Coordinates sandbox selection, backend-specific preparation, and command /// execution for tool calls requested by the model. pub(crate) struct Executor { - backends: BackendStore, approval_cache: ApprovalCache, config: Arc>, } @@ -72,7 +69,6 @@ pub(crate) struct Executor { impl Executor { pub(crate) fn new(config: ExecutorConfig) -> Self { Self { - backends: default_backends(), approval_cache: ApprovalCache::default(), config: Arc::new(RwLock::new(config)), } @@ -80,11 +76,7 @@ impl Executor { /// Updates the sandbox policy and working directory used for future /// executions without recreating the executor. - pub(crate) fn update_environment( - &self, - sandbox_policy: SandboxPolicy, - sandbox_cwd: PathBuf, - ) { + pub(crate) fn update_environment(&self, sandbox_policy: SandboxPolicy, sandbox_cwd: PathBuf) { if let Ok(mut cfg) = self.config.write() { cfg.sandbox_policy = sandbox_policy; cfg.sandbox_cwd = sandbox_cwd; @@ -103,7 +95,7 @@ impl Executor { call_id: &str, ) -> Result { // Step 1: Normalise parameters via the selected backend. - let backend = self.backends.for_mode(&request.mode); + let backend = backend_for_mode(&request.mode); request.params = backend .prepare(request.params, &request.mode) .map_err(ExecError::from)?; @@ -148,10 +140,8 @@ impl Executor { } Err(CodexErr::Sandbox(error @ SandboxErr::Denied { .. })) => { return if sandbox_decision.escalate_on_failure { - self.retry_without_sandbox( - &*backend, &request, &config, session, sub_id, call_id, error, - ) - .await + self.retry_without_sandbox(&request, &config, session, sub_id, call_id, error) + .await } else { Err(ExecError::rejection(format!( "failed in sandbox {:?} with execution error: {error:?}", @@ -170,7 +160,6 @@ impl Executor { #[allow(clippy::too_many_arguments)] async fn retry_without_sandbox( &self, - backend: &dyn ExecutionBackend, request: &ExecutionRequest, config: &ExecutorConfig, session: &Session,