agenticSeek/sources/tools/BashInterpreter.py
2025-03-02 20:51:50 +01:00

103 lines
3.2 KiB
Python

import sys
import re
from io import StringIO
import subprocess
if __name__ == "__main__":
from tools import Tools
else:
from sources.tools.tools import Tools
class BashInterpreter(Tools):
"""
This class is a tool to allow agent for bash code execution.
"""
def __init__(self):
super().__init__()
self.tag = "bash"
def execute(self, commands: str, safety=False, timeout=1000):
"""
Execute bash commands and display output in real-time.
"""
if safety and input("Execute command? y/n ") != "y":
return "Command rejected by user."
concat_output = ""
for command in commands:
if "python3" in command:
continue # because stubborn AI always want to run python3 with bash when it write code
try:
process = subprocess.Popen(
command,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True
)
command_output = ""
for line in process.stdout:
print(line, end="")
command_output += line
return_code = process.wait(timeout=timeout)
if return_code != 0:
return f"Command {command} failed with return code {return_code}:\n{command_output}"
concat_output += f"Output of {command}:\n{command_output.strip()}\n\n"
except subprocess.TimeoutExpired:
process.kill() # Kill the process if it times out
return f"Command {command} timed out. Output:\n{command_output}"
except Exception as e:
return f"Command {command} failed:\n{str(e)}"
return concat_output
def interpreter_feedback(self, output):
"""
Provide feedback based on the output of the bash interpreter
"""
if self.execution_failure_check(output):
feedback = f"[failure] Error in execution:\n{output}"
else:
feedback = "[success] Execution success, code output:\n" + output
return feedback
def execution_failure_check(self, feedback):
"""
check if bash command failed.
"""
error_patterns = [
r"expected",
r"errno",
r"failed",
r"invalid",
r"unrecognized",
r"exception",
r"syntax",
r"segmentation fault",
r"core dumped",
r"unexpected",
r"denied",
r"not recognized",
r"not permitted",
r"not installed",
r"not found",
r"no such",
r"too many",
r"too few",
r"busy",
r"broken pipe",
r"missing",
r"undefined",
r"refused",
r"unreachable",
r"not known"
]
combined_pattern = "|".join(error_patterns)
if re.search(combined_pattern, feedback, re.IGNORECASE):
return True
return False
if __name__ == "__main__":
bash = BashInterpreter()
print(bash.execute(["ls", "pwd", "ip a", "nmap -sC 127.0.0.1"]))