SPARKNET / src /tools /file_tools.py
MHamdan's picture
Initial commit: SPARKNET framework
a9dc537
"""
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)
# Create parent directories if needed
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)}",
)