pub mod binding;
pub mod tools;
use crate::Runner;
use adk_sandbox::SandboxError;
use adk_sandbox::workspace::{SandboxConfig, SnapshotId};
use std::sync::Arc;
use tracing::{info, warn};
pub struct SandboxRunner {
inner: Runner,
}
impl SandboxRunner {
pub fn new(inner: Runner) -> Self {
Self { inner }
}
pub fn inner(&self) -> &Runner {
&self.inner
}
pub async fn run(
&self,
config: &SandboxConfig,
user_id: &str,
session_id: &str,
) -> Result<SandboxRunResult, adk_core::AdkError> {
info!("provisioning sandbox workspace");
let handle =
config.client.provision(&config.manifest).await.map_err(adk_core::AdkError::from)?;
info!(session_handle = %handle.0, "starting sandbox session");
let session = match config.client.start(&handle).await {
Ok(s) => s,
Err(e) => {
let _ = config.client.stop(&handle).await;
return Err(adk_core::AdkError::from(e));
}
};
let session_arc = Arc::from(session);
let _bound_tools =
binding::bind_tools(session_arc, &config.capabilities, config.command_timeout);
info!(
capabilities = ?config.capabilities,
tool_count = _bound_tools.len(),
"bound sandbox tools"
);
let agent_loop_future = async {
let _ = (user_id, session_id);
Ok::<(), adk_core::AdkError>(())
};
let agent_loop_result =
tokio::time::timeout(config.session_timeout, agent_loop_future).await;
let agent_loop_result = match agent_loop_result {
Ok(result) => result,
Err(_elapsed) => {
warn!(
session_handle = %handle.0,
timeout = ?config.session_timeout,
"sandbox session timed out"
);
Err(adk_core::AdkError::from(SandboxError::SessionTimeout {
timeout: config.session_timeout,
}))
}
};
info!(session_handle = %handle.0, "stopping sandbox session");
if let Err(e) = config.client.stop(&handle).await {
warn!(
session_handle = %handle.0,
error = %e,
"failed to stop sandbox session during cleanup"
);
}
agent_loop_result?;
let snapshot_id = if config.snapshot_on_stop {
info!(session_handle = %handle.0, "snapshotting sandbox workspace");
match config.client.snapshot(&handle).await {
Ok(id) => {
info!(snapshot_id = %id.0, "sandbox snapshot created");
Some(id)
}
Err(e) => {
warn!(
session_handle = %handle.0,
error = %e,
"sandbox snapshot failed, continuing without snapshot"
);
None
}
}
} else {
None
};
Ok(SandboxRunResult { snapshot_id })
}
}
#[derive(Debug)]
pub struct SandboxRunResult {
pub snapshot_id: Option<SnapshotId>,
}