diff --git a/crates/attractor/src/cli/backend.rs b/crates/attractor/src/cli/backend.rs index 66812c610..d787d8e86 100644 --- a/crates/attractor/src/cli/backend.rs +++ b/crates/attractor/src/cli/backend.rs @@ -4,8 +4,9 @@ use std::sync::Arc; use async_trait::async_trait; use agent::{ - AnthropicProfile, EventData, EventKind, GeminiProfile, LocalExecutionEnvironment, - OpenAiProfile, ProviderProfile, Session, SessionConfig, Turn, + AnthropicProfile, DockerConfig, DockerExecutionEnvironment, EventData, EventKind, + ExecutionEnvironment, GeminiProfile, LocalExecutionEnvironment, OpenAiProfile, ProviderProfile, + Session, SessionConfig, Turn, }; use llm::client::Client; use terminal::Styles; @@ -21,6 +22,7 @@ pub struct AgentBackend { provider: Option, verbose: u8, styles: &'static Styles, + docker: bool, } impl AgentBackend { @@ -30,12 +32,14 @@ impl AgentBackend { provider: Option, verbose: u8, styles: &'static Styles, + docker: bool, ) -> Self { Self { model, provider, verbose, styles, + docker, } } @@ -64,7 +68,19 @@ impl CodergenBackend for AgentBackend { let profile = self.build_profile(); let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")); - let exec_env = Arc::new(LocalExecutionEnvironment::new(cwd)); + + let exec_env: Arc = if self.docker { + let config = DockerConfig { + host_working_directory: cwd.to_string_lossy().to_string(), + ..DockerConfig::default() + }; + Arc::new( + DockerExecutionEnvironment::new(config) + .map_err(|e| AttractorError::Handler(format!("Failed to create Docker environment: {e}")))?, + ) + } else { + Arc::new(LocalExecutionEnvironment::new(cwd)) + }; let config = SessionConfig { reasoning_effort: Some(node.reasoning_effort().to_string()), diff --git a/crates/attractor/src/cli/mod.rs b/crates/attractor/src/cli/mod.rs index 2349071a3..844943230 100644 --- a/crates/attractor/src/cli/mod.rs +++ b/crates/attractor/src/cli/mod.rs @@ -63,6 +63,10 @@ pub struct RunArgs { /// Verbosity level (-v summary, -vv full details) #[arg(short, long, action = clap::ArgAction::Count)] pub verbose: u8, + + /// Run agent tools inside a Docker container + #[arg(long)] + pub docker: bool, } #[derive(Args)] @@ -93,6 +97,10 @@ pub struct ServeArgs { /// Execute with simulated LLM backend #[arg(long)] pub dry_run: bool, + + /// Run agent tools inside a Docker container + #[arg(long)] + pub docker: bool, } /// Read a .dot file from disk. diff --git a/crates/attractor/src/cli/run.rs b/crates/attractor/src/cli/run.rs index f37fba9c2..ede22b010 100644 --- a/crates/attractor/src/cli/run.rs +++ b/crates/attractor/src/cli/run.rs @@ -133,6 +133,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu provider.clone(), args.verbose, styles, + args.docker, ))) } }); diff --git a/crates/attractor/src/cli/serve.rs b/crates/attractor/src/cli/serve.rs index e21cdf47f..282d809b7 100644 --- a/crates/attractor/src/cli/serve.rs +++ b/crates/attractor/src/cli/serve.rs @@ -60,6 +60,7 @@ pub async fn serve_command(args: ServeArgs, styles: &'static Styles) -> anyhow:: provider.clone(), 0, styles, + args.docker, ))) } })