File size: 2,975 Bytes
5dc5419 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | """FileReadTool - Read file contents for Stack 2.9"""
import os
from pathlib import Path
from typing import Optional
from .base import BaseTool, ToolResult
from .registry import tool_registry
class FileReadTool(BaseTool):
"""Read contents of a file."""
name = "file_read"
description = "Read contents of a file"
input_schema = {
"type": "object",
"properties": {
"path": {"type": "string", "description": "File path to read"},
"offset": {"type": "number", "description": "Line offset to start reading"},
"limit": {"type": "number", "description": "Maximum lines to read"},
"show_lines": {"type": "boolean", "default": False, "description": "Include line numbers"}
},
"required": ["path"]
}
async def execute(self, path: str, offset: Optional[int] = None, limit: Optional[int] = None, show_lines: bool = False) -> ToolResult:
"""Read file."""
file_path = Path(path)
if not file_path.exists():
return ToolResult(success=False, error=f"File not found: {path}")
if not file_path.is_file():
return ToolResult(success=False, error=f"Not a file: {path}")
try:
lines = file_path.read_text().split('\n')
except Exception as e:
return ToolResult(success=False, error=f"Cannot read file: {e}")
total_lines = len(lines)
# Apply offset
if offset is not None and offset > 0:
lines = lines[offset:]
elif offset is not None:
offset = 0
# Apply limit
if limit is not None and limit > 0:
lines = lines[:limit]
if show_lines:
start_line = (offset or 0) + 1
content = '\n'.join(f"{i}: {line}" for i, line in enumerate(lines, start_line))
else:
content = '\n'.join(lines)
return ToolResult(success=True, data={
"path": path,
"content": content,
"lines_read": len(lines),
"total_lines": total_lines,
"offset": offset,
"truncated": limit is not None and len(lines) >= limit
})
class FileExistsTool(BaseTool):
"""Check if a file exists."""
name = "file_exists"
description = "Check if a file or directory exists"
input_schema = {
"type": "object",
"properties": {
"path": {"type": "string", "description": "Path to check"}
},
"required": ["path"]
}
async def execute(self, path: str) -> ToolResult:
"""Check existence."""
p = Path(path)
return ToolResult(success=True, data={
"path": path,
"exists": p.exists(),
"is_file": p.is_file() if p.exists() else None,
"is_dir": p.is_dir() if p.exists() else None
})
# Register tools
tool_registry.register(FileReadTool())
tool_registry.register(FileExistsTool())
|