view-file-tool 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
File without changes
|
view_file_tool/main.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
view_file Tool
|
|
3
|
+
==============
|
|
4
|
+
Read the contents of a file from the local filesystem.
|
|
5
|
+
|
|
6
|
+
Parameters:
|
|
7
|
+
path - Absolute path to the file to read (required).
|
|
8
|
+
start_line - First line to return, 1-indexed inclusive (optional).
|
|
9
|
+
end_line - Last line to return, 1-indexed inclusive (optional).
|
|
10
|
+
Must be >= start_line. Max 800 lines per call.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
import os
|
|
15
|
+
from typing import Any, Dict, List, Optional
|
|
16
|
+
import aiofiles
|
|
17
|
+
from openchadpy.tool_base import ToolBase
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
MAX_LINES = 800
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Tool(ToolBase):
|
|
25
|
+
name = "view_file"
|
|
26
|
+
description = (
|
|
27
|
+
"Read the contents of a file from the local filesystem. "
|
|
28
|
+
"Supports an optional line range (start_line / end_line). "
|
|
29
|
+
"Returns at most 800 lines per call. "
|
|
30
|
+
"Lines are returned 1-indexed with line numbers prepended."
|
|
31
|
+
)
|
|
32
|
+
input_schema = {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {
|
|
35
|
+
"path": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "Absolute path to the file to read.",
|
|
38
|
+
},
|
|
39
|
+
"start_line": {
|
|
40
|
+
"type": "integer",
|
|
41
|
+
"description": (
|
|
42
|
+
"First line to return, 1-indexed inclusive. "
|
|
43
|
+
"Defaults to 1 when omitted."
|
|
44
|
+
),
|
|
45
|
+
},
|
|
46
|
+
"end_line": {
|
|
47
|
+
"type": "integer",
|
|
48
|
+
"description": (
|
|
49
|
+
"Last line to return, 1-indexed inclusive. "
|
|
50
|
+
"Defaults to start_line + 799 when omitted. "
|
|
51
|
+
"Must be >= start_line."
|
|
52
|
+
),
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
"required": ["path"],
|
|
56
|
+
}
|
|
57
|
+
allowed_callers = ["direct", "code_execution"]
|
|
58
|
+
|
|
59
|
+
async def execute(self, **kwargs) -> Dict[str, Any]:
|
|
60
|
+
path: str = kwargs.get("path", "").strip()
|
|
61
|
+
start_line: Optional[int] = kwargs.get("start_line")
|
|
62
|
+
end_line: Optional[int] = kwargs.get("end_line")
|
|
63
|
+
|
|
64
|
+
if not path:
|
|
65
|
+
return {"error": "path is required and must not be empty."}
|
|
66
|
+
|
|
67
|
+
if not os.path.exists(path):
|
|
68
|
+
return {"error": f"File not found: {path!r}"}
|
|
69
|
+
|
|
70
|
+
if not os.path.isfile(path):
|
|
71
|
+
return {"error": f"Path is not a file: {path!r}"}
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
async with aiofiles.open(path, "r", encoding="utf-8", errors="replace") as f:
|
|
75
|
+
all_lines: List[str] = await f.readlines()
|
|
76
|
+
except Exception as e:
|
|
77
|
+
logger.error(f"[view_file] failed to read {path!r}: {e}")
|
|
78
|
+
return {"error": f"Failed to read file: {e}"}
|
|
79
|
+
|
|
80
|
+
total_lines = len(all_lines)
|
|
81
|
+
|
|
82
|
+
# Resolve defaults
|
|
83
|
+
sl: int = max(1, int(start_line)) if start_line is not None else 1
|
|
84
|
+
el: int = (
|
|
85
|
+
min(int(end_line), total_lines)
|
|
86
|
+
if end_line is not None
|
|
87
|
+
else min(sl + MAX_LINES - 1, total_lines)
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Validate range
|
|
91
|
+
if sl > total_lines:
|
|
92
|
+
return {
|
|
93
|
+
"error": (
|
|
94
|
+
f"start_line {sl} exceeds total lines in file ({total_lines})."
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
if el < sl:
|
|
98
|
+
return {"error": f"end_line ({el}) must be >= start_line ({sl})."}
|
|
99
|
+
|
|
100
|
+
# Clamp window to MAX_LINES
|
|
101
|
+
if el - sl + 1 > MAX_LINES:
|
|
102
|
+
el = sl + MAX_LINES - 1
|
|
103
|
+
|
|
104
|
+
selected = all_lines[sl - 1 : el]
|
|
105
|
+
numbered = "".join(f"{sl + i}: {line}" for i, line in enumerate(selected))
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
"path": path,
|
|
109
|
+
"total_lines": total_lines,
|
|
110
|
+
"start_line": sl,
|
|
111
|
+
"end_line": el,
|
|
112
|
+
"content": numbered,
|
|
113
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: view_file_tool
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Read the contents of a file from the local filesystem.
|
|
5
|
+
Requires-Python: >=3.13
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: aiofiles>=25.1.0
|
|
8
|
+
Requires-Dist: openchadpy>=0.1.23
|
|
9
|
+
Requires-Dist: types-aiofiles>=25.1.0.20260518
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
view_file_tool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
view_file_tool/main.py,sha256=eNYV2JDWcJq5TbXKJ7SXDMjnQHOBh2xpjIOHsZoQviY,3616
|
|
3
|
+
view_file_tool-0.1.0.dist-info/METADATA,sha256=V7zLyYiBVZ6QwF4abO8T5k-SGr3494Tic-WBoE6RsEY,299
|
|
4
|
+
view_file_tool-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
5
|
+
view_file_tool-0.1.0.dist-info/top_level.txt,sha256=7pl6hH7CP6NUe1ENmjoOqG8RcNowhC-7XDeZ_8mLmq4,15
|
|
6
|
+
view_file_tool-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
view_file_tool
|