feat: add output truncation and offset paging to all large-output tools
- coding_tools: list_files (max_entries=200, sorted), run_command (max_chars=8000, output_offset), grep_search (max_lines=100, offset); added _truncate_output helper for run_command paging - pr_tools: get_pull_request_diff / get_pull_request_patch now truncate at 15k chars with hunk-boundary awareness and char_offset paging; get_pull_request_comments gains limit/offset paging - issue_tools: get_issue_comments gains limit/offset paging - file_tools: get_file_content / get_file_content_with_ref now paginate by line (offset=1, limit=250), matching existing read_file convention; added _paginate_lines helper - research_tools: fetch_url gains char_offset parameter; _smart_truncate now slices from an offset and embeds next char_offset in the footer - gitea_tools facade: all new params threaded through
This commit is contained in:
@@ -8,21 +8,74 @@ class FileTools:
|
||||
def __init__(self, client: GiteaClient) -> None:
|
||||
self._client = client
|
||||
|
||||
def get_file_content(self, owner: str, repo: str, path: str) -> str:
|
||||
def _paginate_lines(
|
||||
self,
|
||||
content: str,
|
||||
offset: int,
|
||||
limit: int,
|
||||
) -> str:
|
||||
"""Return lines[offset-1 : offset-1+limit] with a paging footer if truncated.
|
||||
|
||||
Uses the same 1-indexed convention as CodingTools.read_file.
|
||||
"""
|
||||
lines: list[str] = content.splitlines()
|
||||
total: int = len(lines)
|
||||
start: int = offset - 1 # convert to 0-indexed
|
||||
page: list[str] = lines[start : start + limit]
|
||||
formatted: list[str] = [
|
||||
f"{start + i + 1}: {line}" for i, line in enumerate(page)
|
||||
]
|
||||
result: str = "\n".join(formatted)
|
||||
end_line: int = start + len(page)
|
||||
if end_line < total:
|
||||
next_offset: int = end_line + 1
|
||||
result += (
|
||||
f"\n\n[{total} lines total — showing lines {offset}–{end_line}. "
|
||||
f"Re-call with offset={next_offset} to read more.]"
|
||||
)
|
||||
return result
|
||||
|
||||
def get_file_content(
|
||||
self,
|
||||
owner: str,
|
||||
repo: str,
|
||||
path: str,
|
||||
offset: int = 1,
|
||||
limit: int = 250,
|
||||
) -> str:
|
||||
"""Get the content of a file from a Gitea repository with line paging.
|
||||
|
||||
Args:
|
||||
offset: 1-indexed line to start from (default 1).
|
||||
limit: Maximum number of lines to return (default 250).
|
||||
"""
|
||||
try:
|
||||
content = self._client.get_file_content(owner, repo, path)
|
||||
if isinstance(content, list):
|
||||
return "\n".join(content)
|
||||
return content
|
||||
raw: str = "\n".join(content) if isinstance(content, list) else content
|
||||
return self._paginate_lines(raw, offset, limit)
|
||||
except Exception as e:
|
||||
return f"Error getting file content: {str(e)}"
|
||||
|
||||
def get_file_content_with_ref(self, owner: str, repo: str, path: str, ref: str = "master") -> str:
|
||||
def get_file_content_with_ref(
|
||||
self,
|
||||
owner: str,
|
||||
repo: str,
|
||||
path: str,
|
||||
ref: str = "master",
|
||||
offset: int = 1,
|
||||
limit: int = 250,
|
||||
) -> str:
|
||||
"""Get file content at a specific git ref with line paging.
|
||||
|
||||
Args:
|
||||
ref: Branch, tag, or commit SHA (default 'master').
|
||||
offset: 1-indexed line to start from (default 1).
|
||||
limit: Maximum number of lines to return (default 250).
|
||||
"""
|
||||
try:
|
||||
content = self._client.get_file_content(owner, repo, path, ref)
|
||||
if isinstance(content, list):
|
||||
return "\n".join(content)
|
||||
return content
|
||||
raw: str = "\n".join(content) if isinstance(content, list) else content
|
||||
return self._paginate_lines(raw, offset, limit)
|
||||
except Exception as e:
|
||||
return f"Error getting file content: {str(e)}"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user