| """ |
| Tool implementations for the Data Cleaning environment. |
| |
| Provides file operations and Python code execution for data cleaning tasks. |
| """ |
|
|
| import os |
| import subprocess |
| import tempfile |
| from typing import Any, Dict, Tuple |
|
|
|
|
| class DataCleanTools: |
| """ |
| Tool implementations for data cleaning tasks. |
| |
| Args: |
| workspace_dir: Working directory for agent operations |
| messy_file_path: Path to the input messy file |
| """ |
|
|
| def __init__(self, workspace_dir: str, messy_file_path: str): |
| self.workspace_dir = workspace_dir |
| self.messy_file_path = messy_file_path |
| self.submitted_file_path = None |
|
|
| def execute_tool( |
| self, tool_name: str, tool_args: Dict[str, Any] |
| ) -> Tuple[str, bool]: |
| """ |
| Execute a tool and return its result. |
| |
| Args: |
| tool_name: Name of the tool to execute |
| tool_args: Arguments for the tool |
| |
| Returns: |
| Tuple of (result_string, is_final_action) |
| """ |
| if tool_name == "read_file": |
| return self.read_file(**tool_args), False |
| elif tool_name == "run_python": |
| return self.run_python(**tool_args), False |
| elif tool_name == "write_file": |
| return self.write_file(**tool_args), False |
| elif tool_name == "submit_cleaned_file": |
| return self.submit_cleaned_file(**tool_args), True |
| else: |
| return f"Error: Unknown tool '{tool_name}'", False |
|
|
| def read_file(self, path: str) -> str: |
| """ |
| Read a file from the workspace. |
| |
| Args: |
| path: Relative path to the file in the workspace |
| |
| Returns: |
| File contents or error message |
| """ |
| |
| if not os.path.isabs(path): |
| full_path = os.path.join(self.workspace_dir, path) |
| else: |
| |
| full_path = os.path.abspath(path) |
| if not full_path.startswith(os.path.abspath(self.workspace_dir)): |
| return f"Error: Path '{path}' is outside workspace directory" |
|
|
| if not os.path.exists(full_path): |
| return f"Error: File '{path}' not found" |
|
|
| try: |
| with open(full_path, "r", encoding="utf-8") as f: |
| content = f.read() |
| return content |
| except Exception as e: |
| return f"Error reading file: {str(e)}" |
|
|
| def run_python(self, code: str) -> str: |
| """ |
| Execute Python code in a sandboxed environment. |
| |
| Args: |
| code: Python code to execute |
| |
| Returns: |
| stdout/stderr from execution or error message |
| """ |
| |
| with tempfile.NamedTemporaryFile( |
| mode="w", suffix=".py", delete=False, dir=self.workspace_dir |
| ) as f: |
| f.write(code) |
| temp_file = f.name |
|
|
| try: |
| |
| result = subprocess.run( |
| ["python", temp_file], |
| cwd=self.workspace_dir, |
| capture_output=True, |
| text=True, |
| timeout=10, |
| ) |
|
|
| output = "" |
| if result.stdout: |
| output += f"stdout:\n{result.stdout}\n" |
| if result.stderr: |
| output += f"stderr:\n{result.stderr}\n" |
| if result.returncode != 0: |
| output += f"\nExit code: {result.returncode}" |
|
|
| return output if output else "Code executed successfully (no output)" |
|
|
| except subprocess.TimeoutExpired: |
| return "Error: Code execution timed out (10s limit)" |
| except Exception as e: |
| return f"Error executing code: {str(e)}" |
| finally: |
| |
| try: |
| os.unlink(temp_file) |
| except: |
| pass |
|
|
| def write_file(self, path: str, content: str) -> str: |
| """ |
| Write content to a file in the workspace. |
| |
| Args: |
| path: Relative path to the file in the workspace |
| content: Content to write |
| |
| Returns: |
| Success message or error |
| """ |
| |
| if not os.path.isabs(path): |
| full_path = os.path.join(self.workspace_dir, path) |
| else: |
| |
| full_path = os.path.abspath(path) |
| if not full_path.startswith(os.path.abspath(self.workspace_dir)): |
| return f"Error: Path '{path}' is outside workspace directory" |
|
|
| try: |
| |
| dir_path = os.path.dirname(full_path) |
| if dir_path: |
| os.makedirs(dir_path, exist_ok=True) |
|
|
| with open(full_path, "w", encoding="utf-8") as f: |
| f.write(content) |
| return f"File written successfully: {path}" |
| except Exception as e: |
| return f"Error writing file: {str(e)}" |
|
|
| def submit_cleaned_file(self, path: str) -> str: |
| """ |
| Submit a cleaned file as the final answer. |
| |
| Args: |
| path: Relative path to the cleaned file |
| |
| Returns: |
| Confirmation message |
| """ |
| |
| if not os.path.isabs(path): |
| full_path = os.path.join(self.workspace_dir, path) |
| else: |
| full_path = os.path.abspath(path) |
| if not full_path.startswith(os.path.abspath(self.workspace_dir)): |
| return f"Error: Path '{path}' is outside workspace directory" |
|
|
| if not os.path.exists(full_path): |
| return f"Error: File '{path}' not found. Please create it first." |
|
|
| self.submitted_file_path = full_path |
| return f"Cleaned file submitted: {path}" |
|
|