import pandas as pd import logging import ast from src.utils.asyncHandler import asyncHandler from src.core.dependencies import connect_data from langchain_core.tools import tool @tool(description="Executes python code on the dataframe df to query and answer user questions.") @asyncHandler async def code_runner(code: str): logging.info("code_runner tool - entering tool execution") logging.info(f"code_runner tool - code payload:\n{code}") logging.info("code_runner tool - establishing data connection and loading dataframe") df = await connect_data().load_data() local_vars = {"df": df, "pd": pd} logging.info(f"code_runner tool - loaded dataframe shape: {df.shape if hasattr(df, 'shape') else 'unknown'}") try: logging.info("code_runner tool - parsing python code into AST tree") tree = ast.parse(code) if tree.body and isinstance(tree.body[-1], ast.Expr): logging.info("code_runner tool - last node is an expression. separating it for evaluation") last_expr = tree.body.pop() logging.info("code_runner tool - executing prefix code statements") exec(compile(tree, filename="", mode="exec"), {}, local_vars) logging.info("code_runner tool - evaluating last expression and assigning to result") eval_res = eval(compile(ast.Expression(last_expr.value), filename="", mode="eval"), {}, local_vars) if 'result' not in local_vars: local_vars['result'] = eval_res else: logging.info("code_runner tool - executing standard code block") exec(code, {}, local_vars) result = local_vars.get('result', "Code executed successfully") logging.info(f"code_runner tool - execution succeeded. result output: {result}") return str(result) except Exception as e: logging.error(f"code_runner tool - error raised during execution: {e}", exc_info=True) return f"Error: {str(e)}"