| """ |
| File Tools for SPARKNET |
| Tools for file system operations |
| """ |
|
|
| from pathlib import Path |
| from typing import Optional |
| from loguru import logger |
| from .base_tool import BaseTool, ToolResult |
| import json |
|
|
|
|
| class FileReaderTool(BaseTool): |
| """Tool for reading files.""" |
|
|
| def __init__(self): |
| super().__init__( |
| name="file_reader", |
| description="Read contents of a file from the file system", |
| ) |
| self.add_parameter("file_path", "str", "Path to the file to read", required=True) |
| self.add_parameter("encoding", "str", "File encoding", required=False, default="utf-8") |
|
|
| async def execute(self, file_path: str, encoding: str = "utf-8", **kwargs) -> ToolResult: |
| """ |
| Read file contents. |
| |
| Args: |
| file_path: Path to file |
| encoding: File encoding |
| |
| Returns: |
| ToolResult with file contents |
| """ |
| try: |
| path = Path(file_path) |
|
|
| if not path.exists(): |
| return ToolResult( |
| success=False, |
| output=None, |
| error=f"File not found: {file_path}", |
| ) |
|
|
| if not path.is_file(): |
| return ToolResult( |
| success=False, |
| output=None, |
| error=f"Path is not a file: {file_path}", |
| ) |
|
|
| with open(path, "r", encoding=encoding) as f: |
| contents = f.read() |
|
|
| return ToolResult( |
| success=True, |
| output=contents, |
| metadata={ |
| "file_path": str(path.absolute()), |
| "size_bytes": len(contents), |
| "encoding": encoding, |
| }, |
| ) |
|
|
| except Exception as e: |
| return ToolResult( |
| success=False, |
| output=None, |
| error=f"Error reading file: {str(e)}", |
| ) |
|
|
|
|
| class FileWriterTool(BaseTool): |
| """Tool for writing files.""" |
|
|
| def __init__(self): |
| super().__init__( |
| name="file_writer", |
| description="Write contents to a file", |
| ) |
| self.add_parameter("file_path", "str", "Path to the file to write", required=True) |
| self.add_parameter("content", "str", "Content to write to file", required=True) |
| self.add_parameter("encoding", "str", "File encoding", required=False, default="utf-8") |
| self.add_parameter("append", "bool", "Append to file instead of overwriting", required=False, default=False) |
|
|
| async def execute( |
| self, |
| file_path: str, |
| content: str, |
| encoding: str = "utf-8", |
| append: bool = False, |
| **kwargs, |
| ) -> ToolResult: |
| """ |
| Write content to file. |
| |
| Args: |
| file_path: Path to file |
| content: Content to write |
| encoding: File encoding |
| append: Whether to append |
| |
| Returns: |
| ToolResult |
| """ |
| try: |
| path = Path(file_path) |
|
|
| |
| path.parent.mkdir(parents=True, exist_ok=True) |
|
|
| mode = "a" if append else "w" |
| with open(path, mode, encoding=encoding) as f: |
| f.write(content) |
|
|
| return ToolResult( |
| success=True, |
| output=f"Successfully wrote to {file_path}", |
| metadata={ |
| "file_path": str(path.absolute()), |
| "bytes_written": len(content.encode(encoding)), |
| "mode": "append" if append else "write", |
| }, |
| ) |
|
|
| except Exception as e: |
| return ToolResult( |
| success=False, |
| output=None, |
| error=f"Error writing file: {str(e)}", |
| ) |
|
|
|
|
| class FileSearchTool(BaseTool): |
| """Tool for searching files.""" |
|
|
| def __init__(self): |
| super().__init__( |
| name="file_search", |
| description="Search for files matching a pattern", |
| ) |
| self.add_parameter("directory", "str", "Directory to search in", required=True) |
| self.add_parameter("pattern", "str", "File pattern to match (e.g., '*.txt')", required=True) |
| self.add_parameter("recursive", "bool", "Search recursively", required=False, default=True) |
|
|
| async def execute( |
| self, |
| directory: str, |
| pattern: str, |
| recursive: bool = True, |
| **kwargs, |
| ) -> ToolResult: |
| """ |
| Search for files. |
| |
| Args: |
| directory: Directory to search |
| pattern: File pattern |
| recursive: Search recursively |
| |
| Returns: |
| ToolResult with list of matching files |
| """ |
| try: |
| path = Path(directory) |
|
|
| if not path.exists(): |
| return ToolResult( |
| success=False, |
| output=None, |
| error=f"Directory not found: {directory}", |
| ) |
|
|
| if recursive: |
| files = list(path.rglob(pattern)) |
| else: |
| files = list(path.glob(pattern)) |
|
|
| file_paths = [str(f.absolute()) for f in files if f.is_file()] |
|
|
| return ToolResult( |
| success=True, |
| output=file_paths, |
| metadata={ |
| "directory": str(path.absolute()), |
| "pattern": pattern, |
| "count": len(file_paths), |
| "recursive": recursive, |
| }, |
| ) |
|
|
| except Exception as e: |
| return ToolResult( |
| success=False, |
| output=None, |
| error=f"Error searching files: {str(e)}", |
| ) |
|
|
|
|
| class DirectoryListTool(BaseTool): |
| """Tool for listing directory contents.""" |
|
|
| def __init__(self): |
| super().__init__( |
| name="directory_list", |
| description="List contents of a directory", |
| ) |
| self.add_parameter("directory", "str", "Directory to list", required=True) |
| self.add_parameter("include_hidden", "bool", "Include hidden files", required=False, default=False) |
|
|
| async def execute( |
| self, |
| directory: str, |
| include_hidden: bool = False, |
| **kwargs, |
| ) -> ToolResult: |
| """ |
| List directory contents. |
| |
| Args: |
| directory: Directory to list |
| include_hidden: Include hidden files |
| |
| Returns: |
| ToolResult with directory contents |
| """ |
| try: |
| path = Path(directory) |
|
|
| if not path.exists(): |
| return ToolResult( |
| success=False, |
| output=None, |
| error=f"Directory not found: {directory}", |
| ) |
|
|
| if not path.is_dir(): |
| return ToolResult( |
| success=False, |
| output=None, |
| error=f"Path is not a directory: {directory}", |
| ) |
|
|
| items = [] |
| for item in path.iterdir(): |
| if not include_hidden and item.name.startswith("."): |
| continue |
|
|
| items.append({ |
| "name": item.name, |
| "path": str(item.absolute()), |
| "type": "directory" if item.is_dir() else "file", |
| "size": item.stat().st_size if item.is_file() else None, |
| }) |
|
|
| return ToolResult( |
| success=True, |
| output=items, |
| metadata={ |
| "directory": str(path.absolute()), |
| "count": len(items), |
| }, |
| ) |
|
|
| except Exception as e: |
| return ToolResult( |
| success=False, |
| output=None, |
| error=f"Error listing directory: {str(e)}", |
| ) |
|
|