CoolFace
Apppublic

piotrekgrl/smolagents-local-python-debugger-tool

sourceHugging Faceapache-2.0updated 2y agoView on Hugging Face
3likes
tool.py137 linesDownload Raw Back to root
1from smolagents.tools import Tool2import pdb3import smolagents4import io5import sys6 7class LocalPythonDebuggerTool(Tool):8    name = "local-python-debugger"9    description = """10    The Local Python Debugger Tool is designed to assist in debugging InterpreterErrors—specifically, errors related to "Code execution failed at line". 11    It is not intended for other types of InterpreterErrors, such as:12    - "Reached the max number of operations"13    - "Code parsing failed on line"14 15    The tool debugs code executed in the following manner:16    ```python17    expression = ast.parse(code)18    for node in expression.body:19        result = evaluate_ast(node, ...)20    ```21    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.22    As a result, the debugger output reflects the evaluate_ast execution context rather than a direct Python runtime environment.23    24    Possible debugger commands:25    - bt - Shows the full stack trace, helping to understand where the error occurred in the call stack.26    - args - Shows the arguments passed to the function.27    - l - Lists the source code of the current file.28    - 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.29 30    """31    inputs = {'code': {'type': 'string', 'description': 'code to debug'}, 'command': {'type': 'string', 'description': 'pdb command to execute'}}32    output_type = "string"33 34    def setup(self):35        from smolagents import LocalPythonInterpreter36        from smolagents.default_tools import FinalAnswerTool37 38        import io39        import pdb40 41        self.python_executor = LocalPythonInterpreter(42            [],43            {"final_answer": FinalAnswerTool()},44            max_print_outputs_length=None,45        )46 47        self.output_capture = io.StringIO()48 49        self.pdb_instance = pdb.Pdb(stdout=self.output_capture)50 51    def wrap_code_with_trycatch(self, code: str) -> str:52        from smolagents.utils import parse_code_blobs53 54        try:55            code = parse_code_blobs(code)56        except Exception as e:57            pass58 59        code_lines = code.split("\n")60        for i, line in enumerate(code_lines):61            code_lines[i] = f"\t{line}"62        code = "\n".join(code_lines)63 64        # add extra indentation65        code = (66            f"try:\n{code}\n" + "except Exception as e:" + "\n\t" + "out=sys.exc_info()"67        )68        code = "out=None" + "\n" + code + "\n" + "out"  # provide results in output69 70        return code71 72    def execute_code(self, code: str, state: dict):73        from smolagents.utils import parse_code_blobs74 75        code = parse_code_blobs(code)76 77        # Silencing the tool_validation error: execute_code: Name '' is undefined.78        py_executor_output = None79        py_executor_logs = None80        py_executor_is_final_answer = None81 82        py_executor_output, py_executor_logs, py_executor_is_final_answer = (83            self.python_executor(code, state)84        )85 86        return py_executor_output, py_executor_logs, py_executor_is_final_answer87 88    def execude_pdb_command(89        self, command: str, traceback90    ):91        output = None92        try:93            # Set up the pdb instance with the current frame and traceback94            frame = traceback.tb_frame95            while frame.f_back:96                frame = frame.f_back97            self.pdb_instance.reset()98            self.pdb_instance.setup(frame, traceback)99            # Execute the pdb command100            self.pdb_instance.onecmd(command)101            # Retrieve the output102            output = self.output_capture.getvalue()103        finally:104            # Clear the output capture for future use105            self.output_capture.truncate(0)106            self.output_capture.seek(0)107 108        return output109 110    def forward(self, code: str, command: str):111        import sys112 113        code = self.wrap_code_with_trycatch(code)114 115        state = {"sys": sys}116 117        # Silencing the tool_validation error: execute_code: Name '' is undefined.118        py_executor_output = None119        tb = None120 121        py_executor_output, py_executor_logs, py_executor_is_final_answer = (122            self.execute_code(code, state)123        )124 125        if py_executor_output is not None:126            try:127                exc_type, exc_value, tb = py_executor_output128            except Exception as e:129                return "No traceback found"130            pdb_result = self.execude_pdb_command(command, tb)131            return pdb_result132 133        return "No traceback found"134 135    def __init__(self, *args, **kwargs):136        self.is_initialized = False137