mirror of
https://github.com/NCBM/plyngent.git
synced 2026-07-23 14:14:57 +08:00
core/tools/file: read, write, listdir, edit_replace
Module-level @tool handlers under workspace root; first-occurrence string replace.
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
from .edit_replace import edit_replace as edit_replace
|
||||
from .listdir import listdir as listdir
|
||||
from .read import read_file as read_file
|
||||
from .write import write_file as write_file
|
||||
|
||||
FILE_TOOLS = [read_file, write_file, listdir, edit_replace]
|
||||
@@ -0,0 +1,20 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from plyngent.agent import tool
|
||||
from plyngent.tools.workspace import resolve_path
|
||||
|
||||
|
||||
@tool
|
||||
def edit_replace(path: str, old_string: str, new_string: str) -> str:
|
||||
"""Replace the first occurrence of ``old_string`` with ``new_string`` in a file."""
|
||||
if not old_string:
|
||||
return "error: old_string must not be empty"
|
||||
target = resolve_path(path)
|
||||
if not target.is_file():
|
||||
return f"error: not a file: {path}"
|
||||
text = target.read_text(encoding="utf-8", errors="replace")
|
||||
if old_string not in text:
|
||||
return "error: old_string not found in file"
|
||||
updated = text.replace(old_string, new_string, 1)
|
||||
_ = target.write_text(updated, encoding="utf-8")
|
||||
return f"replaced first occurrence in {path}"
|
||||
@@ -0,0 +1,17 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from plyngent.agent import tool
|
||||
from plyngent.tools.workspace import resolve_path
|
||||
|
||||
|
||||
@tool
|
||||
def listdir(path: str = ".") -> str:
|
||||
"""List entries in a directory under the workspace (name and type)."""
|
||||
target = resolve_path(path)
|
||||
if not target.is_dir():
|
||||
return f"error: not a directory: {path}"
|
||||
lines: list[str] = []
|
||||
for entry in sorted(target.iterdir(), key=lambda p: p.name):
|
||||
kind = "dir" if entry.is_dir() else "file"
|
||||
lines.append(f"{kind}\t{entry.name}")
|
||||
return "\n".join(lines) if lines else "(empty)"
|
||||
@@ -0,0 +1,24 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from plyngent.agent import tool
|
||||
from plyngent.tools.workspace import resolve_path
|
||||
|
||||
|
||||
@tool
|
||||
def read_file(path: str, *, offset: int = 0, limit: int | None = None) -> str:
|
||||
"""Read a text file under the workspace.
|
||||
|
||||
``offset`` is 0-based line start; ``limit`` is max lines (None = rest of file).
|
||||
"""
|
||||
target = resolve_path(path)
|
||||
if not target.is_file():
|
||||
return f"error: not a file: {path}"
|
||||
text = target.read_text(encoding="utf-8", errors="replace")
|
||||
lines = text.splitlines(keepends=True)
|
||||
if offset < 0:
|
||||
return "error: offset must be >= 0"
|
||||
start = offset
|
||||
end = len(lines) if limit is None else min(len(lines), start + limit)
|
||||
if start >= len(lines):
|
||||
return ""
|
||||
return "".join(lines[start:end])
|
||||
@@ -0,0 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from plyngent.agent import tool
|
||||
from plyngent.tools.workspace import resolve_path
|
||||
|
||||
|
||||
@tool
|
||||
def write_file(path: str, content: str) -> str:
|
||||
"""Write text content to a file under the workspace (creates parents)."""
|
||||
target = resolve_path(path)
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
_ = target.write_text(content, encoding="utf-8")
|
||||
return f"wrote {len(content)} characters to {path}"
|
||||
Reference in New Issue
Block a user