| | """ |
| | 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)}", |
| | ) |
| |
|