Feat : adding work that was done locally
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
|
||||
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 = 10):
|
||||
"""
|
||||
Execute bash commands.
|
||||
"""
|
||||
if safety and input("Execute command? y/n ") != "y":
|
||||
return "Command rejected by user."
|
||||
|
||||
for command in commands:
|
||||
try:
|
||||
output = subprocess.check_output(command,
|
||||
shell=True,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True,
|
||||
timeout=timeout
|
||||
)
|
||||
return output.strip()
|
||||
except subprocess.CalledProcessError as e:
|
||||
return f"Command execution failed:\n{e.output}"
|
||||
except subprocess.TimeoutExpired:
|
||||
return f"Command timed out. Output:\n{e.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"]))
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
import sys
|
||||
import re
|
||||
from io import StringIO
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tools import Tools
|
||||
else:
|
||||
from sources.tools.tools import Tools
|
||||
|
||||
class PyInterpreter(Tools):
|
||||
"""
|
||||
This class is a tool to allow agent for python code execution.
|
||||
"""
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.tag = "python"
|
||||
|
||||
def execute(self, codes:str, safety = False) -> str:
|
||||
"""
|
||||
Execute python code.
|
||||
"""
|
||||
output = ""
|
||||
if safety and input("Execute code ? y/n") != "y":
|
||||
return "Code rejected by user."
|
||||
stdout_buffer = StringIO()
|
||||
sys.stdout = stdout_buffer
|
||||
code = '\n\n'.join(codes)
|
||||
try:
|
||||
try:
|
||||
buffer = exec(code)
|
||||
if buffer is not None:
|
||||
output = buffer + '\n'
|
||||
except Exception as e:
|
||||
return "code execution failed:" + str(e)
|
||||
output = stdout_buffer.getvalue()
|
||||
finally:
|
||||
sys.stdout = sys.__stdout__
|
||||
return output
|
||||
|
||||
def interpreter_feedback(self, output:str) -> str:
|
||||
"""
|
||||
Provide feedback based on the output of the code execution
|
||||
"""
|
||||
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:str) -> bool:
|
||||
"""
|
||||
Check if the code execution failed.
|
||||
"""
|
||||
error_patterns = [
|
||||
r"expected",
|
||||
r"errno",
|
||||
r"failed",
|
||||
r"traceback",
|
||||
r"invalid",
|
||||
r"unrecognized",
|
||||
r"exception",
|
||||
r"syntax",
|
||||
r"crash",
|
||||
r"segmentation fault",
|
||||
r"core dumped"
|
||||
]
|
||||
combined_pattern = "|".join(error_patterns)
|
||||
if re.search(combined_pattern, feedback, re.IGNORECASE):
|
||||
return True
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
codes = ["""
|
||||
def test():
|
||||
print("Hello world")
|
||||
test()
|
||||
"""]
|
||||
py = PyInterpreter()
|
||||
print(py.execute(codes))
|
||||
@@ -0,0 +1,4 @@
|
||||
from .PyInterpreter import PyInterpreter
|
||||
from .BashInterpreter import BashInterpreter
|
||||
|
||||
__all__ = ["PyInterpreter", "BashInterpreter"]
|
||||
@@ -0,0 +1,94 @@
|
||||
|
||||
"""
|
||||
define a generic tool class, any tool can be used by the agent.
|
||||
|
||||
A tool can be used by deepseek like so:
|
||||
```<tool name>
|
||||
<code or query to execute>
|
||||
```
|
||||
|
||||
For example:
|
||||
```python
|
||||
print("Hello world")
|
||||
```
|
||||
|
||||
This is then executed by the tool with its own class implementation of execute().
|
||||
|
||||
A tool is not just for code tool but also API, internet, etc..
|
||||
For example a flight API tool could be used like so:
|
||||
```flight_search
|
||||
HU787
|
||||
```
|
||||
"""
|
||||
|
||||
import sys
|
||||
from abc import abstractmethod
|
||||
|
||||
sys.path.append('..')
|
||||
|
||||
class Tools():
|
||||
"""
|
||||
Abstract class for all tools.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.tag = "undefined"
|
||||
self.api_key = None
|
||||
self.client = None
|
||||
self.messages = []
|
||||
|
||||
@abstractmethod
|
||||
def execute(self, codes:str, safety:bool) -> str:
|
||||
"""
|
||||
abstract method, implementation in child class.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def execution_failure_check(self, output:str) -> bool:
|
||||
"""
|
||||
abstract method, implementation in child class.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def interpreter_feedback(self, output:str) -> str:
|
||||
"""
|
||||
abstract method, implementation in child class.
|
||||
"""
|
||||
pass
|
||||
|
||||
def remove_block(self, text:str) -> str:
|
||||
"""
|
||||
Remove all code/query blocks within a tag from the answer text.
|
||||
"""
|
||||
assert self.tag != "undefined", "Tag not defined"
|
||||
start_tag = f'```{self.tag}'
|
||||
end_tag = '```'
|
||||
start_idx = text.find(start_tag)
|
||||
end_idx = text.rfind(end_tag)+3
|
||||
if start_idx == -1 or end_idx == -1:
|
||||
return text
|
||||
return text[:start_idx] + text[end_idx:]
|
||||
|
||||
def load_exec_block(self, generation:str) -> str:
|
||||
"""
|
||||
Extract the code/query blocks from the answer text.
|
||||
"""
|
||||
assert self.tag != "undefined", "Tag not defined"
|
||||
start_tag = f'```{self.tag}'
|
||||
end_tag = '```'
|
||||
code_blocks = []
|
||||
start_index = 0
|
||||
|
||||
if start_tag not in generation:
|
||||
return None
|
||||
while True:
|
||||
start_pos = generation.find(start_tag, start_index)
|
||||
if start_pos == -1:
|
||||
break
|
||||
end_pos = generation.find(end_tag, start_pos + len(start_tag))
|
||||
if end_pos == -1:
|
||||
break
|
||||
code_blocks.append(generation[start_pos + len(start_tag):end_pos])
|
||||
start_index = end_pos + len(end_tag)
|
||||
return code_blocks
|
||||
Reference in New Issue
Block a user