1use crate::types::*;
2use std::process::Command;
3
4pub struct BashTool;
5
6impl BashTool {
7 pub fn new() -> Self {
8 Self
9 }
10
11 pub fn name(&self) -> &str {
12 "Bash"
13 }
14
15 pub fn description(&self) -> &str {
16 "Execute a shell command and return its output"
17 }
18
19 pub fn input_schema(&self) -> ToolInputSchema {
20 ToolInputSchema {
21 schema_type: "object".to_string(),
22 properties: serde_json::json!({
23 "command": { "type": "string", "description": "Shell command to execute" },
24 "description": { "type": "string", "description": "What this command does" }
25 }),
26 required: Some(vec!["command".to_string()]),
27 }
28 }
29
30 pub async fn execute(
31 &self,
32 input: serde_json::Value,
33 context: &ToolContext,
34 ) -> Result<ToolResult, crate::error::AgentError> {
35 let command = input["command"]
36 .as_str()
37 .ok_or_else(|| crate::error::AgentError::Tool("command required".to_string()))?
38 .to_string();
39
40 let cwd = context.cwd.clone();
41 let output = tokio::task::spawn_blocking(move || {
42 let mut cmd = Command::new("sh");
43 cmd.arg("-c").arg(&command);
44 if !cwd.is_empty() {
45 cmd.current_dir(&cwd);
46 }
47 cmd.output()
48 })
49 .await
50 .map_err(|e| crate::error::AgentError::Tool(e.to_string()))?
51 .map_err(|e| crate::error::AgentError::Tool(e.to_string()))?;
52
53 let stdout = String::from_utf8_lossy(&output.stdout);
54 let stderr = String::from_utf8_lossy(&output.stderr);
55
56 let content = if !stdout.is_empty() {
57 stdout.to_string()
58 } else {
59 stderr.to_string()
60 };
61
62 let is_error = !output.status.success();
63
64 Ok(ToolResult {
65 result_type: "tool_result".to_string(),
66 tool_use_id: "".to_string(),
67 content,
68 is_error: Some(is_error),
69 })
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[tokio::test]
78 async fn test_bash_tool() {
79 let tool = BashTool::new();
80 let result = tool
81 .execute(
82 serde_json::json!({"command": "echo hello"}),
83 &ToolContext {
84 cwd: "/tmp".to_string(),
85 abort_signal: None,
86 },
87 )
88 .await;
89 assert!(result.is_ok());
90 }
91}