Skip to content

Commit 91db672

Browse files
committed
feat: add terminal tool for command execution
- Implement Terminal tool - Add security restrictions to prevent dangerous commands - Update team configuration template to use terminal tool
1 parent 842ab03 commit 91db672

6 files changed

Lines changed: 101 additions & 40 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ Coming soon
179179
- **current_time**: Current time retrieval tool solving model time awareness issues
180180
- **browser**: Web browsing tool based on browser-use, supporting web access, content extraction, and interaction
181181
- **google_search**: Search engine tool for retrieving up-to-date information
182+
- **file_save**: Tool for saving agent outputs to the local workspace
183+
- **terminal**: Command-line tool for executing system commands safely with security restrictions
182184
- **MCP**: Extended tool capabilities through MCP protocol support (coming soon)
183185

184186
## Contribution

agentmesh/tools/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from agentmesh.tools.calculator.calculator import Calculator
88
from agentmesh.tools.current_time.current_time import CurrentTime
99
from agentmesh.tools.file_save.file_save import FileSave
10+
from agentmesh.tools.terminal.terminal import Terminal
1011

1112

1213
# Delayed import for BrowserTool
@@ -38,7 +39,8 @@ def __init__(self, *args, **kwargs):
3839
'Calculator',
3940
'CurrentTime',
4041
'FileSave',
41-
'BrowserTool'
42+
'BrowserTool',
43+
'Terminal'
4244
]
4345

4446
"""
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .terminal import Terminal
2+
3+
__all__ = ['Terminal']
Lines changed: 82 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,100 @@
11
import platform
22
import subprocess
3+
from typing import Dict, Any
34

5+
from agentmesh.tools.base_tool import BaseTool, ToolResult
46

5-
class Terminal:
6-
def open_terminal(self, command):
7-
system = platform.system()
87

9-
try:
10-
if system == "Windows":
11-
subprocess.Popen(f'start cmd /k "{command}"', shell=True)
12-
elif system == "Darwin":
13-
applescript = f'''
14-
tell application "Terminal"
15-
activate
16-
do script "{command}"
17-
end tell
18-
'''
19-
subprocess.run(["osascript", "-e", applescript])
20-
elif system == "Linux":
21-
subprocess.Popen(f'gnome-terminal -- bash -c "{command}; exec bash"', shell=True)
22-
else:
23-
raise OSError("Unsupported operating system")
24-
return True
25-
except Exception as e:
26-
print(f"Error opening terminal: {str(e)}")
27-
return False
8+
class Terminal(BaseTool):
9+
name: str = "terminal"
10+
description: str = "A tool to run terminal commands on the local system"
11+
params: dict = {
12+
"type": "object",
13+
"properties": {
14+
"command": {
15+
"type": "string",
16+
"description": f"The terminal command to execute which should be valid in {platform.system()} platform"
17+
}
18+
},
19+
"required": ["command"]
20+
}
21+
config: dict = {}
22+
23+
def __init__(self, config=None):
24+
self.config = config or {}
25+
# Set of dangerous commands that should be blocked
26+
self.command_ban_set = {"halt", "poweroff", "shutdown", "reboot", "rm", "kill",
27+
"exit", "sudo", "su", "userdel", "groupdel", "logout", "alias"}
28+
29+
def execute(self, args: Dict[str, Any]) -> ToolResult:
30+
"""
31+
Execute a terminal command safely.
32+
33+
:param args: Dictionary containing the command to execute
34+
:return: Result of the command execution
35+
"""
36+
command = args.get("command", "").strip()
37+
38+
# Check if the command is safe to execute
39+
if not self._is_safe_command(command):
40+
return ToolResult.fail(result=f"Command '{command}' is not allowed for security reasons.")
2841

29-
def run_command(self, command):
3042
try:
3143
result = subprocess.run(
3244
command,
3345
shell=True,
34-
check=True,
46+
check=True, # Raise exception on non-zero return code
3547
stdout=subprocess.PIPE,
3648
stderr=subprocess.PIPE,
37-
text=True
49+
text=True,
50+
timeout=self.config.get("timeout", 30)
3851
)
39-
return {
40-
"status": "success",
52+
53+
return ToolResult.success({
4154
"stdout": result.stdout,
4255
"stderr": result.stderr,
43-
"returncode": result.returncode
44-
}
56+
"return_code": result.returncode,
57+
"command": command
58+
})
4559
except subprocess.CalledProcessError as e:
46-
return {
47-
"status": "error",
60+
# Preserve the original error handling for CalledProcessError
61+
return ToolResult.fail({
4862
"stdout": e.stdout,
4963
"stderr": e.stderr,
50-
"returncode": e.returncode
51-
}
64+
"return_code": e.returncode,
65+
"command": command
66+
})
67+
except subprocess.TimeoutExpired:
68+
return ToolResult.fail(result=f"Command timed out after {self.config.get('timeout', 20)} seconds.")
69+
except Exception as e:
70+
return ToolResult.fail(result=f"Error executing command: {str(e)}")
71+
72+
def _is_safe_command(self, command: str) -> bool:
73+
"""
74+
Check if a command is safe to execute.
75+
76+
:param command: The command to check
77+
:return: True if the command is safe, False otherwise
78+
"""
79+
# Split the command to get the base command
80+
cmd_parts = command.split()
81+
if not cmd_parts:
82+
return False
83+
84+
base_cmd = cmd_parts[0].lower()
85+
86+
# Check if the base command is in the ban list
87+
if base_cmd in self.command_ban_set:
88+
return False
89+
90+
# Check for sudo/su commands
91+
if any(banned in command.lower() for banned in ["sudo ", "su -"]):
92+
return False
93+
94+
# Check for rm -rf or similar dangerous patterns
95+
if "rm" in base_cmd and ("-rf" in command or "-r" in command or "-f" in command):
96+
return False
97+
98+
# Additional security checks can be added here
99+
100+
return True

config-template.yaml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@ tools:
2424
teams:
2525
general_team:
2626
model: "gpt-4.1"
27-
description: "A general-purpose research and information agent team"
27+
description: "A versatile research and information agent team"
2828
max_steps: 10
2929
agents:
3030
- name: "General Agent"
31-
description: "Universal assistant specializing in research and information synthesis"
31+
description: "Universal assistant specializing in research, information synthesis, and task execution"
3232
system_prompt: |
33-
You are a versatile assistant who answers questions and completes tasks using available tools. Specialize in researching topics, organizing information, and presenting findings in clear, well-structured, informative Markdown reports. Your reports should include:
33+
You are a versatile assistant who answers questions and completes tasks using available tools.
34+
When conducting research and analysis work, present findings in clear, well-structured, informative Markdown reports. Your reports should include:
3435
1. Clear introduction and context
3536
2. Detailed main content with relevant facts, data, and examples
3637
3. Multiple perspectives when appropriate
@@ -43,27 +44,30 @@ teams:
4344
- google_search
4445
- browser
4546
- file_save
47+
- terminal
48+
4649

4750
software_team:
4851
model: "gpt-4.1"
4952
description: "A software development team with product manager, developer and tester."
5053
rule: "A normal R&D process should be that Product Manager writes PRD, Developer writes code based on PRD, and Finally, Tester performs testing."
5154
max_steps: 20
5255
agents:
53-
- name: "Product Manager"
56+
- name: "Product-Manager"
5457
description: "Responsible for product requirements and documentation"
5558
system_prompt: "You are an experienced product manager who creates concise PRDs, focusing on user needs and feature specifications. You always format your responses in Markdown."
5659
tools:
5760
- time
5861
- file_save
5962
- name: "Developer"
6063
description: "Implements code based on PRD"
61-
system_prompt: "You are a skilled web developer who creates single-page website based on user needs. You deliver HTML files with embedded JavaScript and CSS that are visually appealing, responsive, and user-friendly, featuring a grand layout and beautiful background. The HTML, CSS, and JavaScript code should be well-structured and effectively organized."
64+
system_prompt: "You are a skilled developer. When developing web application, you creates single-page website based on user needs, you deliver HTML files with embedded JavaScript and CSS that are visually appealing, responsive, and user-friendly, featuring a grand layout and beautiful background. The HTML, CSS, and JavaScript code should be well-structured and effectively organized."
6265
tools:
6366
- file_save
6467
- name: "Tester"
6568
description: "Tests code and verifies functionality"
66-
system_prompt: "You are a tester who validates code against requirements. For HTML applications, use browser tools to test functionality. You only need to test a few core cases."
69+
system_prompt: "You are a tester who validates code against requirements. For HTML applications, use browser tools to test functionality. For Python or other client-side applications, use the terminal tool to run and test. You only need to test a few core cases."
6770
tools:
6871
- browser
6972
- file_save
73+
- terminal

docs/README-CN.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ result = team.run(task="Write a Snake client game")
176176
- **browser**: 浏览器操作工具,基于browser-use实现,支持网页访问、内容提取和交互操作
177177
- **google_search**: 搜索引擎工具,获取最新信息和知识
178178
- **file_save**: 将Agent输出内容保存在本地工作空间中
179+
- **terminal**: 终端命令执行工具,支持安全地执行系统命令
179180
- **MCP**: 通过支持MCP协议获得更多工具能力(即将支持)
180181

181182
## 贡献

0 commit comments

Comments
 (0)