mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-22 09:32:33 +00:00
docs(tools): clarify coding tool guidance
This commit is contained in:
parent
7e122d6e49
commit
44ef697aac
@ -298,11 +298,14 @@ class ApplyPatchTool(_FsTool):
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return (
|
||||
"Apply a structured patch for code edits. The patch must include "
|
||||
"Default tool for code edits. Apply a structured patch with "
|
||||
"*** Begin Patch and *** End Patch. Supports Add File, Update File, "
|
||||
"Delete File, and Move to. Paths must be relative. Prefer this for "
|
||||
"multi-file coding changes; use edit_file for small exact replacements. "
|
||||
"Set dry_run=true to validate and preview the change without writing files."
|
||||
"Delete File, and Move to across one or more files. Use this for "
|
||||
"multi-file changes, structural edits, generated code, or any edit "
|
||||
"where a reviewable patch is clearer than an exact replacement. "
|
||||
"Paths must be relative. Set dry_run=true to validate and preview "
|
||||
"the change summary without writing files. Use edit_file only for "
|
||||
"small exact replacements copied from read_file."
|
||||
)
|
||||
|
||||
async def execute(self, patch: str, dry_run: bool = False, **kwargs: Any) -> str:
|
||||
|
||||
@ -424,11 +424,12 @@ class WriteStdinTool(Tool):
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return (
|
||||
"Write text to a running exec session and return recent output. "
|
||||
"Use chars='' to poll without writing. Set close_stdin=true to send EOF, "
|
||||
"or terminate=true to stop the session. Use wait_for to keep polling "
|
||||
"until expected output appears. Sessions finish automatically when "
|
||||
"their process exits."
|
||||
"Interact with a running exec session created by exec with "
|
||||
"yield_time_ms. Use chars='' to poll without writing, chars to send "
|
||||
"stdin, close_stdin=true to send EOF, or terminate=true to stop the "
|
||||
"process. Use wait_for with wait_timeout_ms for dev servers, test "
|
||||
"watchers, and prompts where you need to wait for expected output. "
|
||||
"Do not use this to start new commands; start them with exec."
|
||||
)
|
||||
|
||||
async def execute(
|
||||
@ -561,7 +562,8 @@ class ListExecSessionsTool(Tool):
|
||||
return (
|
||||
"List active long-running exec sessions, including session_id, cwd, "
|
||||
"elapsed time, idle time, remaining timeout, and command preview. "
|
||||
"Use this to recover a session_id before polling with write_stdin."
|
||||
"Use this to recover a session_id after context shifts before "
|
||||
"polling, writing stdin, or terminating with write_stdin."
|
||||
)
|
||||
|
||||
@property
|
||||
|
||||
@ -158,6 +158,9 @@ class ReadFileTool(_FsTool):
|
||||
"Text output format: LINE_NUM|CONTENT. "
|
||||
"Images return visual content for analysis. "
|
||||
"Supports PDF, DOCX, XLSX, PPTX documents. "
|
||||
"Use find_files/list_dir first when the path is uncertain. "
|
||||
"Read the relevant range before editing so replacements or patches "
|
||||
"are based on current content. "
|
||||
"Use offset and limit for large text files. "
|
||||
"Use force=true to re-read content even if unchanged. "
|
||||
"Reads exceeding ~128K chars are truncated."
|
||||
@ -384,9 +387,10 @@ class WriteFileTool(_FsTool):
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return (
|
||||
"Write content to a file. Overwrites if the file already exists; "
|
||||
"creates parent directories as needed. "
|
||||
"For partial edits, prefer edit_file instead."
|
||||
"Create a new file or intentionally replace an entire file with "
|
||||
"the provided content. Overwrites existing files and creates parent "
|
||||
"directories as needed. For code changes or partial edits, prefer "
|
||||
"apply_patch; use edit_file only for small exact replacements."
|
||||
)
|
||||
|
||||
async def execute(self, path: str | None = None, content: str | None = None, **kwargs: Any) -> str:
|
||||
@ -711,10 +715,13 @@ class EditFileTool(_FsTool):
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return (
|
||||
"Edit a file by replacing old_text with new_text. "
|
||||
"Tolerates minor whitespace/indentation differences and curly/straight quote mismatches. "
|
||||
"If old_text matches multiple times, you must provide more context "
|
||||
"or set occurrence/line_hint/replace_all. Shows a diff of the closest match on failure."
|
||||
"Perform a small, exact replacement in one file by replacing "
|
||||
"old_text with new_text. Use this for narrow text substitutions "
|
||||
"with old_text copied from read_file. For multi-file, structural, "
|
||||
"or generated code edits, prefer apply_patch. If old_text matches "
|
||||
"multiple times, provide more context or set occurrence, line_hint, "
|
||||
"replace_all, and expected_replacements. Shows closest-match "
|
||||
"diagnostics on failure."
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
||||
@ -130,8 +130,10 @@ class FindFilesTool(_SearchTool):
|
||||
def description(self) -> str:
|
||||
return (
|
||||
"Find files by path fragment, glob, or file type. "
|
||||
"Use this before read_file when you need to locate files. "
|
||||
"Returns workspace-relative paths and skips common dependency/build directories."
|
||||
"Use this before read_file when you need to locate files, and "
|
||||
"prefer it over shell find/ls for ordinary workspace discovery. "
|
||||
"Returns workspace-relative paths and skips common dependency/build "
|
||||
"directories."
|
||||
)
|
||||
|
||||
@property
|
||||
@ -289,7 +291,8 @@ class GrepTool(_SearchTool):
|
||||
return (
|
||||
"Search file contents with a regex pattern. "
|
||||
"Default output_mode is files_with_matches (file paths only); "
|
||||
"use content mode for matching lines with context. "
|
||||
"use content mode for matching lines with context. Prefer this "
|
||||
"over shell grep for ordinary workspace searches. "
|
||||
"Skips binary and files >2 MB. Supports glob/type filtering."
|
||||
)
|
||||
|
||||
|
||||
@ -211,8 +211,10 @@ class ExecTool(Tool):
|
||||
def description(self) -> str:
|
||||
return (
|
||||
"Execute a shell command and return its output. "
|
||||
"Prefer read_file/write_file/edit_file over cat/echo/sed, "
|
||||
"and grep/glob over shell find/grep. "
|
||||
"Use this for tests, builds, package commands, git commands, and "
|
||||
"other process execution. Prefer read_file/find_files/grep for "
|
||||
"inspection and apply_patch/write_file/edit_file for file changes "
|
||||
"instead of cat, shell find/grep, echo, or sed. "
|
||||
"Use -y or --yes flags to avoid interactive prompts. "
|
||||
"For long-running or interactive commands, pass yield_time_ms; "
|
||||
"if the command keeps running, exec returns a session_id that can "
|
||||
|
||||
46
tests/tools/test_tool_descriptions.py
Normal file
46
tests/tools/test_tool_descriptions.py
Normal file
@ -0,0 +1,46 @@
|
||||
from nanobot.agent.tools.apply_patch import ApplyPatchTool
|
||||
from nanobot.agent.tools.exec_session import ListExecSessionsTool, WriteStdinTool
|
||||
from nanobot.agent.tools.filesystem import EditFileTool, ReadFileTool, WriteFileTool
|
||||
from nanobot.agent.tools.search import FindFilesTool, GrepTool
|
||||
from nanobot.agent.tools.shell import ExecTool
|
||||
|
||||
|
||||
def test_coding_tool_descriptions_steer_editing_priority() -> None:
|
||||
apply_patch = ApplyPatchTool().description.lower()
|
||||
edit_file = EditFileTool().description.lower()
|
||||
write_file = WriteFileTool().description.lower()
|
||||
|
||||
assert "default tool for code edits" in apply_patch
|
||||
assert "multi-file" in apply_patch
|
||||
assert "dry_run=true" in apply_patch
|
||||
assert "edit_file only for small exact replacements" in apply_patch
|
||||
|
||||
assert "small, exact replacement" in edit_file
|
||||
assert "copied from read_file" in edit_file
|
||||
assert "prefer apply_patch" in edit_file
|
||||
|
||||
assert "replace an entire file" in write_file
|
||||
assert "prefer apply_patch" in write_file
|
||||
|
||||
|
||||
def test_coding_tool_descriptions_steer_discovery_and_shell_usage() -> None:
|
||||
read_file = ReadFileTool().description.lower()
|
||||
find_files = FindFilesTool().description.lower()
|
||||
grep = GrepTool().description.lower()
|
||||
exec_tool = ExecTool().description.lower()
|
||||
write_stdin = WriteStdinTool().description.lower()
|
||||
list_sessions = ListExecSessionsTool().description.lower()
|
||||
|
||||
assert "find_files/list_dir first" in read_file
|
||||
assert "before editing" in read_file
|
||||
assert "prefer it over shell find/ls" in find_files
|
||||
assert "prefer this over shell grep" in grep
|
||||
|
||||
assert "tests, builds" in exec_tool
|
||||
assert "prefer read_file/find_files/grep" in exec_tool
|
||||
assert "apply_patch/write_file/edit_file" in exec_tool
|
||||
assert "yield_time_ms" in exec_tool
|
||||
|
||||
assert "do not use this to start new commands" in write_stdin
|
||||
assert "wait_for" in write_stdin
|
||||
assert "recover a session_id" in list_sessions
|
||||
Loading…
x
Reference in New Issue
Block a user