Skip to main content

adk_devtools/
toolset.rs

1//! [`DevToolset`] — the developer tools as a single [`Toolset`].
2
3use std::sync::Arc;
4
5use adk_core::{ReadonlyContext, Result, Tool, Toolset};
6use async_trait::async_trait;
7
8use crate::tools::{BashTool, EditFileTool, GlobTool, GrepTool, ReadFileTool, WriteFileTool};
9use crate::workspace::Workspace;
10
11/// Bundles the developer tools (`read_file`, `write_file`, `edit_file`, `glob`,
12/// `grep`, `bash`) so they can be attached to an agent in one call.
13///
14/// Mutating tools (`write_file`, `edit_file`) are omitted when the workspace is
15/// read-only, and `bash` is omitted when bash is disabled — so the toolset the
16/// model sees always matches what the workspace actually permits.
17pub struct DevToolset {
18    workspace: Workspace,
19    include_bash: bool,
20}
21
22impl DevToolset {
23    /// Create a toolset over `workspace` with all permitted tools enabled.
24    pub fn new(workspace: Workspace) -> Self {
25        Self { workspace, include_bash: true }
26    }
27
28    /// Enable or disable exposing the `bash` tool (independent of the workspace
29    /// bash flag; both must allow it).
30    pub fn with_bash(mut self, include: bool) -> Self {
31        self.include_bash = include;
32        self
33    }
34}
35
36#[async_trait]
37impl Toolset for DevToolset {
38    fn name(&self) -> &str {
39        "devtools"
40    }
41
42    async fn tools(&self, _ctx: Arc<dyn ReadonlyContext>) -> Result<Vec<Arc<dyn Tool>>> {
43        let ws = self.workspace.clone();
44        let mut tools: Vec<Arc<dyn Tool>> = vec![
45            Arc::new(ReadFileTool::new(ws.clone())),
46            Arc::new(GlobTool::new(ws.clone())),
47            Arc::new(GrepTool::new(ws.clone())),
48        ];
49        if ws.is_writable() {
50            tools.push(Arc::new(WriteFileTool::new(ws.clone())));
51            tools.push(Arc::new(EditFileTool::new(ws.clone())));
52        }
53        if self.include_bash && ws.bash_allowed() {
54            tools.push(Arc::new(BashTool::new(ws.clone())));
55        }
56        Ok(tools)
57    }
58}