| from smolagents.tools import Tool |
| import pdb |
| import smolagents |
| import io |
| import sys |
|
|
| class LocalPythonDebuggerTool(Tool): |
| name = "local-python-debugger" |
| description = """ |
| The Local Python Debugger Tool is designed to assist in debugging InterpreterErrors—specifically, errors related to "Code execution failed at line". |
| It is not intended for other types of InterpreterErrors, such as: |
| - "Reached the max number of operations" |
| - "Code parsing failed on line" |
| |
| The tool debugs code executed in the following manner: |
| ```python |
| expression = ast.parse(code) |
| for node in expression.body: |
| result = evaluate_ast(node, ...) |
| ``` |
| where evaluate_ast processes the Abstract Syntax Tree (AST) by evaluating AST functions like: ast.Assign, ast.AugAssign, ast.Call, ast.Constant, ast.Name, ast.BinOp, etc. |
| As a result, the debugger output reflects the evaluate_ast execution context rather than a direct Python runtime environment. |
| |
| Possible debugger commands: |
| - bt - Shows the full stack trace, helping to understand where the error occurred in the call stack. |
| - args - Shows the arguments passed to the function. |
| - l - Lists the source code of the current file. |
| - p {variable} - Prints the value of the variable. NOTE: variable names are different than in the code. They should be inspected first with `l` command. |
| |
| """ |
| inputs = {'code': {'type': 'string', 'description': 'code to debug'}, 'command': {'type': 'string', 'description': 'pdb command to execute'}} |
| output_type = "string" |
|
|
| def setup(self): |
| from smolagents import LocalPythonInterpreter |
| from smolagents.default_tools import FinalAnswerTool |
|
|
| import io |
| import pdb |
|
|
| self.python_executor = LocalPythonInterpreter( |
| [], |
| {"final_answer": FinalAnswerTool()}, |
| max_print_outputs_length=None, |
| ) |
|
|
| self.output_capture = io.StringIO() |
|
|
| self.pdb_instance = pdb.Pdb(stdout=self.output_capture) |
|
|
| def wrap_code_with_trycatch(self, code: str) -> str: |
| from smolagents.utils import parse_code_blobs |
|
|
| try: |
| code = parse_code_blobs(code) |
| except Exception as e: |
| pass |
|
|
| code_lines = code.split("\n") |
| for i, line in enumerate(code_lines): |
| code_lines[i] = f"\t{line}" |
| code = "\n".join(code_lines) |
|
|
| |
| code = ( |
| f"try:\n{code}\n" + "except Exception as e:" + "\n\t" + "out=sys.exc_info()" |
| ) |
| code = "out=None" + "\n" + code + "\n" + "out" |
|
|
| return code |
|
|
| def execute_code(self, code: str, state: dict): |
| from smolagents.utils import parse_code_blobs |
|
|
| code = parse_code_blobs(code) |
|
|
| |
| py_executor_output = None |
| py_executor_logs = None |
| py_executor_is_final_answer = None |
|
|
| py_executor_output, py_executor_logs, py_executor_is_final_answer = ( |
| self.python_executor(code, state) |
| ) |
|
|
| return py_executor_output, py_executor_logs, py_executor_is_final_answer |
|
|
| def execude_pdb_command( |
| self, command: str, traceback |
| ): |
| output = None |
| try: |
| |
| frame = traceback.tb_frame |
| while frame.f_back: |
| frame = frame.f_back |
| self.pdb_instance.reset() |
| self.pdb_instance.setup(frame, traceback) |
| |
| self.pdb_instance.onecmd(command) |
| |
| output = self.output_capture.getvalue() |
| finally: |
| |
| self.output_capture.truncate(0) |
| self.output_capture.seek(0) |
|
|
| return output |
|
|
| def forward(self, code: str, command: str): |
| import sys |
|
|
| code = self.wrap_code_with_trycatch(code) |
|
|
| state = {"sys": sys} |
|
|
| |
| py_executor_output = None |
| tb = None |
|
|
| py_executor_output, py_executor_logs, py_executor_is_final_answer = ( |
| self.execute_code(code, state) |
| ) |
|
|
| if py_executor_output is not None: |
| try: |
| exc_type, exc_value, tb = py_executor_output |
| except Exception as e: |
| return "No traceback found" |
| pdb_result = self.execude_pdb_command(command, tb) |
| return pdb_result |
|
|
| return "No traceback found" |
|
|
| def __init__(self, *args, **kwargs): |
| self.is_initialized = False |
|
|