|
20 | 20 | - read_file: Read file contents |
21 | 21 | - list_directory: List directory contents |
22 | 22 | - delete_file: Delete files |
| 23 | +- run_bash: Execute bash/shell commands on the terminal |
23 | 24 | - create_sub_agent: Create specialized sub-agents for delegation |
24 | 25 | - assign_task: Assign tasks to sub-agents asynchronously |
25 | 26 | """ |
26 | 27 |
|
27 | 28 | import asyncio |
28 | 29 | import os |
| 30 | +import subprocess |
29 | 31 | from typing import Any, Dict, List |
30 | 32 | from loguru import logger |
31 | 33 |
|
@@ -392,6 +394,27 @@ def get_autonomous_planning_tools() -> List[Dict[str, Any]]: |
392 | 394 | }, |
393 | 395 | }, |
394 | 396 | }, |
| 397 | + { |
| 398 | + "type": "function", |
| 399 | + "function": { |
| 400 | + "name": "run_bash", |
| 401 | + "description": "Execute a bash/shell command on the terminal. Use this to run system commands, scripts, or any shell operations. Returns stdout and stderr.", |
| 402 | + "parameters": { |
| 403 | + "type": "object", |
| 404 | + "properties": { |
| 405 | + "command": { |
| 406 | + "type": "string", |
| 407 | + "description": "The bash/shell command to execute (e.g. 'ls -la', 'python script.py')", |
| 408 | + }, |
| 409 | + "timeout_seconds": { |
| 410 | + "type": "integer", |
| 411 | + "description": "Maximum seconds to wait for the command (default: 60). Use to avoid hanging on long-running commands.", |
| 412 | + }, |
| 413 | + }, |
| 414 | + "required": ["command"], |
| 415 | + }, |
| 416 | + }, |
| 417 | + }, |
395 | 418 | { |
396 | 419 | "type": "function", |
397 | 420 | "function": { |
@@ -802,6 +825,79 @@ def delete_file_tool(agent: Any, file_path: str, **kwargs) -> str: |
802 | 825 | return error_msg |
803 | 826 |
|
804 | 827 |
|
| 828 | +def run_bash_tool( |
| 829 | + agent: Any, command: str, timeout_seconds: int = 60, **kwargs |
| 830 | +) -> str: |
| 831 | + """ |
| 832 | + Execute a bash/shell command on the terminal. |
| 833 | +
|
| 834 | + Args: |
| 835 | + agent: The agent instance |
| 836 | + command: The bash/shell command to execute |
| 837 | + timeout_seconds: Maximum seconds to wait (default: 60) |
| 838 | + **kwargs: Additional arguments |
| 839 | +
|
| 840 | + Returns: |
| 841 | + str: Command stdout and stderr, or error message |
| 842 | + """ |
| 843 | + try: |
| 844 | + # Run in process cwd (where the user started the script) so commands like |
| 845 | + # ls -la and python script.py see the project directory, not the agent workspace. |
| 846 | + result = subprocess.run( |
| 847 | + command, |
| 848 | + shell=True, |
| 849 | + capture_output=True, |
| 850 | + text=True, |
| 851 | + timeout=timeout_seconds, |
| 852 | + cwd=None, # use process current working directory |
| 853 | + encoding="utf-8", |
| 854 | + errors="replace", |
| 855 | + ) |
| 856 | + |
| 857 | + stdout = result.stdout or "" |
| 858 | + stderr = result.stderr or "" |
| 859 | + |
| 860 | + output_parts = [] |
| 861 | + if stdout: |
| 862 | + output_parts.append(f"stdout:\n{stdout}") |
| 863 | + if stderr: |
| 864 | + output_parts.append(f"stderr:\n{stderr}") |
| 865 | + if not output_parts: |
| 866 | + output_parts.append("(no output)") |
| 867 | + |
| 868 | + result_msg = ( |
| 869 | + f"Command exited with code {result.returncode}\n" |
| 870 | + + "\n".join(output_parts) |
| 871 | + ) |
| 872 | + |
| 873 | + # Add to memory |
| 874 | + agent.short_memory.add( |
| 875 | + role="Terminal", |
| 876 | + content=f"Executed: {command[:100]}{'...' if len(command) > 100 else ''} -> exit {result.returncode}", |
| 877 | + ) |
| 878 | + |
| 879 | + if agent.verbose: |
| 880 | + logger.info(f"Executed bash command: {command[:80]}...") |
| 881 | + |
| 882 | + return result_msg.strip() |
| 883 | + except subprocess.TimeoutExpired: |
| 884 | + error_msg = f"Error: Command timed out after {timeout_seconds} seconds" |
| 885 | + logger.error(error_msg) |
| 886 | + agent.short_memory.add( |
| 887 | + role="Terminal", |
| 888 | + content=f"Timeout: {command[:80]}...", |
| 889 | + ) |
| 890 | + return error_msg |
| 891 | + except Exception as e: |
| 892 | + error_msg = f"Error executing command: {str(e)}" |
| 893 | + logger.error(error_msg) |
| 894 | + agent.short_memory.add( |
| 895 | + role="Terminal", |
| 896 | + content=f"Error: {error_msg}", |
| 897 | + ) |
| 898 | + return error_msg |
| 899 | + |
| 900 | + |
805 | 901 | def create_sub_agent_tool( |
806 | 902 | agent: Any, agents: List[Dict[str, str]], **kwargs |
807 | 903 | ) -> str: |
|
0 commit comments