|
|
from .tool import Tool, Toolkit |
|
|
from .storage_handler import FileStorageHandler, LocalStorageHandler |
|
|
from typing import Dict, Any, List, Optional |
|
|
from ..core.logging import logger |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SaveTool(Tool): |
|
|
name: str = "save" |
|
|
description: str = "Save content to a file with automatic format detection and support for various file types including documents, data files, images, videos, and sound files" |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"file_path": { |
|
|
"type": "string", |
|
|
"description": "Path to the file to save" |
|
|
}, |
|
|
"content": { |
|
|
"type": "string", |
|
|
"description": "Content to save to the file (string for text, JSON string for structured data, or Python object for JSON files)" |
|
|
}, |
|
|
"encoding": { |
|
|
"type": "string", |
|
|
"description": "Text encoding for text files (default: utf-8)" |
|
|
}, |
|
|
"indent": { |
|
|
"type": "integer", |
|
|
"description": "Indentation for JSON files (default: 2)" |
|
|
}, |
|
|
"sheet_name": { |
|
|
"type": "string", |
|
|
"description": "Sheet name for Excel files (default: Sheet1)" |
|
|
}, |
|
|
"root_tag": { |
|
|
"type": "string", |
|
|
"description": "Root tag for XML files (default: root)" |
|
|
} |
|
|
} |
|
|
required: Optional[List[str]] = ["file_path", "content"] |
|
|
|
|
|
def __init__(self, storage_handler: FileStorageHandler = None): |
|
|
super().__init__() |
|
|
self.storage_handler = storage_handler or LocalStorageHandler() |
|
|
|
|
|
@classmethod |
|
|
def validate_attributes(cls): |
|
|
|
|
|
|
|
|
pass |
|
|
|
|
|
def __call__(self, file_path: str, content: Any, encoding: str = "utf-8", indent: int = 2, |
|
|
sheet_name: str = "Sheet1", root_tag: str = "root") -> Dict[str, Any]: |
|
|
""" |
|
|
Save content to a file with automatic format detection. |
|
|
|
|
|
Args: |
|
|
file_path: Path to the file to save |
|
|
content: Content to save to the file (string for text, dict/list for JSON, list for CSV/Excel) |
|
|
encoding: Text encoding for text files |
|
|
indent: Indentation for JSON files |
|
|
sheet_name: Sheet name for Excel files |
|
|
root_tag: Root tag for XML files |
|
|
|
|
|
Returns: |
|
|
Dictionary containing the save operation result |
|
|
""" |
|
|
try: |
|
|
|
|
|
file_extension = self.storage_handler.get_file_type(file_path) |
|
|
parsed_content = content |
|
|
|
|
|
|
|
|
if file_extension in ['.json', '.yaml', '.yml', '.xml']: |
|
|
|
|
|
if isinstance(content, str): |
|
|
try: |
|
|
import json |
|
|
parsed_content = json.loads(content) |
|
|
except json.JSONDecodeError: |
|
|
|
|
|
parsed_content = content |
|
|
else: |
|
|
|
|
|
|
|
|
parsed_content = content |
|
|
|
|
|
|
|
|
elif file_extension == '.csv': |
|
|
|
|
|
if isinstance(content, list): |
|
|
parsed_content = content |
|
|
else: |
|
|
|
|
|
try: |
|
|
import json |
|
|
parsed_content = json.loads(content) |
|
|
if not isinstance(parsed_content, list): |
|
|
|
|
|
parsed_content = content |
|
|
except json.JSONDecodeError: |
|
|
|
|
|
parsed_content = content |
|
|
|
|
|
|
|
|
elif file_extension == '.xlsx': |
|
|
|
|
|
if isinstance(content, list): |
|
|
parsed_content = content |
|
|
else: |
|
|
|
|
|
try: |
|
|
import json |
|
|
parsed_content = json.loads(content) |
|
|
if not isinstance(parsed_content, list): |
|
|
return {"success": False, "error": "Excel content must be a list of lists"} |
|
|
except json.JSONDecodeError: |
|
|
return {"success": False, "error": "Excel content must be valid JSON array"} |
|
|
|
|
|
kwargs = { |
|
|
"encoding": encoding, |
|
|
"indent": indent, |
|
|
"sheet_name": sheet_name, |
|
|
"root_tag": root_tag |
|
|
} |
|
|
|
|
|
result = self.storage_handler.save(file_path, parsed_content, **kwargs) |
|
|
|
|
|
return result |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error in SaveTool: {str(e)}") |
|
|
return {"success": False, "error": str(e), "file_path": file_path} |
|
|
|
|
|
|
|
|
class ReadTool(Tool): |
|
|
name: str = "read" |
|
|
description: str = "Read content from a file with automatic format detection and support for various file types including documents, data files, images, videos, and sound files" |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"file_path": { |
|
|
"type": "string", |
|
|
"description": "Path to the file to read" |
|
|
}, |
|
|
"encoding": { |
|
|
"type": "string", |
|
|
"description": "Text encoding for text files (default: utf-8)" |
|
|
}, |
|
|
"sheet_name": { |
|
|
"type": "string", |
|
|
"description": "Sheet name for Excel files (optional)" |
|
|
}, |
|
|
"head": { |
|
|
"type": "integer", |
|
|
"description": "Number of characters to return from the beginning of the file (default: 0 means return everything)" |
|
|
} |
|
|
} |
|
|
required: Optional[List[str]] = ["file_path"] |
|
|
|
|
|
def __init__(self, storage_handler: FileStorageHandler = None): |
|
|
super().__init__() |
|
|
self.storage_handler = storage_handler or LocalStorageHandler() |
|
|
|
|
|
def __call__(self, file_path: str, encoding: str = "utf-8", sheet_name: str = None, head: int = 0) -> Dict[str, Any]: |
|
|
""" |
|
|
Read content from a file with automatic format detection. |
|
|
|
|
|
Args: |
|
|
file_path: Path to the file to read |
|
|
encoding: Text encoding for text files |
|
|
sheet_name: Sheet name for Excel files |
|
|
head: Number of characters to return from the beginning |
|
|
|
|
|
Returns: |
|
|
Dictionary containing the read operation result |
|
|
""" |
|
|
try: |
|
|
kwargs = { |
|
|
"encoding": encoding, |
|
|
"sheet_name": sheet_name, |
|
|
"head": head |
|
|
} |
|
|
|
|
|
result = self.storage_handler.read(file_path, **kwargs) |
|
|
|
|
|
return result |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error in ReadTool: {str(e)}") |
|
|
return {"success": False, "error": str(e), "file_path": file_path} |
|
|
|
|
|
|
|
|
class AppendTool(Tool): |
|
|
name: str = "append" |
|
|
description: str = "Append content to a file (only for supported formats: txt, json, csv, yaml, pickle, xlsx)" |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"file_path": { |
|
|
"type": "string", |
|
|
"description": "Path to the file to append to" |
|
|
}, |
|
|
"content": { |
|
|
"type": "string", |
|
|
"description": "Content to append to the file (can be JSON string for structured data)" |
|
|
}, |
|
|
"encoding": { |
|
|
"type": "string", |
|
|
"description": "Text encoding for text files (default: utf-8)" |
|
|
}, |
|
|
"sheet_name": { |
|
|
"type": "string", |
|
|
"description": "Sheet name for Excel files (optional)" |
|
|
} |
|
|
} |
|
|
required: Optional[List[str]] = ["file_path", "content"] |
|
|
|
|
|
def __init__(self, storage_handler: FileStorageHandler = None): |
|
|
super().__init__() |
|
|
self.storage_handler = storage_handler or LocalStorageHandler() |
|
|
|
|
|
def __call__(self, file_path: str, content: str, encoding: str = "utf-8", sheet_name: str = None) -> Dict[str, Any]: |
|
|
""" |
|
|
Append content to a file with automatic format detection. |
|
|
|
|
|
Args: |
|
|
file_path: Path to the file to append to |
|
|
content: Content to append to the file |
|
|
encoding: Text encoding for text files |
|
|
sheet_name: Sheet name for Excel files |
|
|
|
|
|
Returns: |
|
|
Dictionary containing the append operation result |
|
|
""" |
|
|
try: |
|
|
|
|
|
file_extension = self.storage_handler.get_file_type(file_path) |
|
|
parsed_content = content |
|
|
|
|
|
|
|
|
if file_extension in ['.json', '.yaml', '.yml']: |
|
|
try: |
|
|
import json |
|
|
parsed_content = json.loads(content) |
|
|
except json.JSONDecodeError: |
|
|
|
|
|
parsed_content = content |
|
|
|
|
|
|
|
|
elif file_extension == '.csv': |
|
|
try: |
|
|
import json |
|
|
parsed_content = json.loads(content) |
|
|
if not isinstance(parsed_content, list): |
|
|
|
|
|
parsed_content = content |
|
|
except json.JSONDecodeError: |
|
|
|
|
|
parsed_content = content |
|
|
|
|
|
|
|
|
elif file_extension == '.xlsx': |
|
|
try: |
|
|
import json |
|
|
parsed_content = json.loads(content) |
|
|
if not isinstance(parsed_content, list): |
|
|
return {"success": False, "error": "Excel content must be a list of lists"} |
|
|
except json.JSONDecodeError: |
|
|
return {"success": False, "error": "Excel content must be valid JSON array"} |
|
|
|
|
|
kwargs = { |
|
|
"encoding": encoding, |
|
|
"sheet_name": sheet_name |
|
|
} |
|
|
|
|
|
result = self.storage_handler.append(file_path, parsed_content, **kwargs) |
|
|
|
|
|
return result |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error in AppendTool: {str(e)}") |
|
|
return {"success": False, "error": str(e), "file_path": file_path} |
|
|
|
|
|
|
|
|
class DeleteTool(Tool): |
|
|
name: str = "delete" |
|
|
description: str = "Delete a file or directory" |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"path": { |
|
|
"type": "string", |
|
|
"description": "Path to the file or directory to delete" |
|
|
} |
|
|
} |
|
|
required: Optional[List[str]] = ["path"] |
|
|
|
|
|
def __init__(self, storage_handler: FileStorageHandler = None): |
|
|
super().__init__() |
|
|
self.storage_handler = storage_handler or LocalStorageHandler() |
|
|
|
|
|
def __call__(self, path: str) -> Dict[str, Any]: |
|
|
""" |
|
|
Delete a file or directory. |
|
|
|
|
|
Args: |
|
|
path: Path to the file or directory to delete |
|
|
|
|
|
Returns: |
|
|
Dictionary containing the delete operation result |
|
|
""" |
|
|
try: |
|
|
result = self.storage_handler.delete(path) |
|
|
return result |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error in DeleteTool: {str(e)}") |
|
|
return {"success": False, "error": str(e), "path": path} |
|
|
|
|
|
|
|
|
class MoveTool(Tool): |
|
|
name: str = "move" |
|
|
description: str = "Move or rename a file or directory" |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"source": { |
|
|
"type": "string", |
|
|
"description": "Source path of the file or directory to move" |
|
|
}, |
|
|
"destination": { |
|
|
"type": "string", |
|
|
"description": "Destination path where to move the file or directory" |
|
|
} |
|
|
} |
|
|
required: Optional[List[str]] = ["source", "destination"] |
|
|
|
|
|
def __init__(self, storage_handler: FileStorageHandler = None): |
|
|
super().__init__() |
|
|
self.storage_handler = storage_handler or LocalStorageHandler() |
|
|
|
|
|
def __call__(self, source: str, destination: str) -> Dict[str, Any]: |
|
|
""" |
|
|
Move or rename a file or directory. |
|
|
|
|
|
Args: |
|
|
source: Source path of the file or directory to move |
|
|
destination: Destination path where to move the file or directory |
|
|
|
|
|
Returns: |
|
|
Dictionary containing the move operation result |
|
|
""" |
|
|
try: |
|
|
result = self.storage_handler.move(source, destination) |
|
|
return result |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error in MoveTool: {str(e)}") |
|
|
return {"success": False, "error": str(e), "source": source, "destination": destination} |
|
|
|
|
|
|
|
|
class CopyTool(Tool): |
|
|
name: str = "copy" |
|
|
description: str = "Copy a file" |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"source": { |
|
|
"type": "string", |
|
|
"description": "Source path of the file to copy" |
|
|
}, |
|
|
"destination": { |
|
|
"type": "string", |
|
|
"description": "Destination path where to copy the file" |
|
|
} |
|
|
} |
|
|
required: Optional[List[str]] = ["source", "destination"] |
|
|
|
|
|
def __init__(self, storage_handler: FileStorageHandler = None): |
|
|
super().__init__() |
|
|
self.storage_handler = storage_handler or LocalStorageHandler() |
|
|
|
|
|
def __call__(self, source: str, destination: str) -> Dict[str, Any]: |
|
|
""" |
|
|
Copy a file. |
|
|
|
|
|
Args: |
|
|
source: Source path of the file to copy |
|
|
destination: Destination path where to copy the file |
|
|
|
|
|
Returns: |
|
|
Dictionary containing the copy operation result |
|
|
""" |
|
|
try: |
|
|
result = self.storage_handler.copy(source, destination) |
|
|
return result |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error in CopyTool: {str(e)}") |
|
|
return {"success": False, "error": str(e), "source": source, "destination": destination} |
|
|
|
|
|
|
|
|
class CreateDirectoryTool(Tool): |
|
|
name: str = "create_directory" |
|
|
description: str = "Create a directory" |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"path": { |
|
|
"type": "string", |
|
|
"description": "Path of the directory to create" |
|
|
} |
|
|
} |
|
|
required: Optional[List[str]] = ["path"] |
|
|
|
|
|
def __init__(self, storage_handler: FileStorageHandler = None): |
|
|
super().__init__() |
|
|
self.storage_handler = storage_handler or LocalStorageHandler() |
|
|
|
|
|
def __call__(self, path: str) -> Dict[str, Any]: |
|
|
""" |
|
|
Create a directory. |
|
|
|
|
|
Args: |
|
|
path: Path of the directory to create |
|
|
|
|
|
Returns: |
|
|
Dictionary containing the create directory operation result |
|
|
""" |
|
|
try: |
|
|
result = self.storage_handler.create_directory(path) |
|
|
return result |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error in CreateDirectoryTool: {str(e)}") |
|
|
return {"success": False, "error": str(e), "path": path} |
|
|
|
|
|
|
|
|
class ListFileTool(Tool): |
|
|
name: str = "list_files" |
|
|
description: str = "List files and directories in a path with structured information" |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"path": { |
|
|
"type": "string", |
|
|
"description": "Path to list files from (default: current working directory)" |
|
|
}, |
|
|
"max_depth": { |
|
|
"type": "integer", |
|
|
"description": "Maximum depth to traverse (default: 3)" |
|
|
}, |
|
|
"include_hidden": { |
|
|
"type": "boolean", |
|
|
"description": "Include hidden files and directories (default: false)" |
|
|
} |
|
|
} |
|
|
required: Optional[List[str]] = [] |
|
|
|
|
|
def __init__(self, storage_handler: FileStorageHandler = None): |
|
|
super().__init__() |
|
|
self.storage_handler = storage_handler or LocalStorageHandler() |
|
|
|
|
|
def __call__(self, path: str = None, max_depth: int = 3, include_hidden: bool = False) -> Dict[str, Any]: |
|
|
""" |
|
|
List files and directories in a path. |
|
|
|
|
|
Args: |
|
|
path: Path to list files from |
|
|
max_depth: Maximum depth to traverse |
|
|
include_hidden: Include hidden files and directories |
|
|
|
|
|
Returns: |
|
|
Dictionary containing the list operation result |
|
|
""" |
|
|
try: |
|
|
result = self.storage_handler.list(path, max_depth=max_depth, include_hidden=include_hidden) |
|
|
return result |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error in ListFileTool: {str(e)}") |
|
|
return {"success": False, "error": str(e), "path": path} |
|
|
|
|
|
|
|
|
class ExistsTool(Tool): |
|
|
name: str = "exists" |
|
|
description: str = "Check if a file or directory exists" |
|
|
inputs: Dict[str, Dict[str, str]] = { |
|
|
"path": { |
|
|
"type": "string", |
|
|
"description": "Path to check for existence" |
|
|
} |
|
|
} |
|
|
required: Optional[List[str]] = ["path"] |
|
|
|
|
|
def __init__(self, storage_handler: FileStorageHandler = None): |
|
|
super().__init__() |
|
|
self.storage_handler = storage_handler or LocalStorageHandler() |
|
|
|
|
|
def __call__(self, path: str) -> Dict[str, Any]: |
|
|
""" |
|
|
Check if a file or directory exists. |
|
|
|
|
|
Args: |
|
|
path: Path to check for existence |
|
|
|
|
|
Returns: |
|
|
Dictionary containing the existence check result |
|
|
""" |
|
|
try: |
|
|
exists = self.storage_handler.exists(path) |
|
|
return { |
|
|
"success": True, |
|
|
"path": path, |
|
|
"exists": exists |
|
|
} |
|
|
|
|
|
except Exception as e: |
|
|
logger.error(f"Error in ExistsTool: {str(e)}") |
|
|
return {"success": False, "error": str(e), "path": path} |
|
|
|
|
|
|
|
|
|
|
|
class StorageToolkit(Toolkit): |
|
|
""" |
|
|
Comprehensive storage toolkit with local filesystem operations. |
|
|
Provides tools for reading, writing, appending, deleting, moving, copying files, |
|
|
creating directories, and listing files with support for various file formats. |
|
|
""" |
|
|
|
|
|
def __init__(self, name: str = "StorageToolkit", base_path: str = "./workplace/storage", storage_handler: LocalStorageHandler = None): |
|
|
""" |
|
|
Initialize the storage toolkit. |
|
|
|
|
|
Args: |
|
|
name: Name of the toolkit |
|
|
base_path: Base directory for storage operations (default: ./workplace/storage) |
|
|
storage_handler: Storage handler instance (defaults to LocalStorageHandler) |
|
|
""" |
|
|
if not storage_handler: |
|
|
storage_handler = LocalStorageHandler(base_path=base_path) |
|
|
|
|
|
|
|
|
tools = [ |
|
|
SaveTool(storage_handler=storage_handler), |
|
|
ReadTool(storage_handler=storage_handler), |
|
|
AppendTool(storage_handler=storage_handler), |
|
|
DeleteTool(storage_handler=storage_handler), |
|
|
MoveTool(storage_handler=storage_handler), |
|
|
CopyTool(storage_handler=storage_handler), |
|
|
CreateDirectoryTool(storage_handler=storage_handler), |
|
|
ListFileTool(storage_handler=storage_handler), |
|
|
ExistsTool(storage_handler=storage_handler) |
|
|
] |
|
|
|
|
|
super().__init__(name=name, tools=tools) |
|
|
self.storage_handler = storage_handler |