mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-01 01:10:21 +08:00
fix: astrbot_file_read_tool returns clear error for directory path instead of misleading Permission denied (#9088)
When LLM passes a directory path to astrbot_file_read_tool, the tool previously
returned Error: [Errno 13] Permission denied, misleading the LLM into thinking
it was a permissions issue. The real cause: _probe_local_file() calls open('rb')
on the path, which fails on directories with Errno 13 on Windows. This is caught
by except PermissionError and displayed as-is.
Fix: Add os.path.isdir() check in FileReadTool.call() before any file I/O, at
the earliest safe point after path normalization and permission validation.
Returns a clear message: '<path> is a directory, not a file. Use a file path
instead, or use astrbot_execute_shell to list directory contents.'
Changes:
- astrbot/core/tools/computer_tools/fs.py: add isdir guard
- tests/test_computer_fs_tools.py: add test_file_read_tool_rejects_directory_with_clear_message
This commit is contained in:
@@ -304,6 +304,11 @@ class FileReadTool(FunctionTool):
|
|||||||
)
|
)
|
||||||
if not normalized_path:
|
if not normalized_path:
|
||||||
raise ValueError("`path` must be a non-empty string.")
|
raise ValueError("`path` must be a non-empty string.")
|
||||||
|
if local_env and os.path.isdir(normalized_path):
|
||||||
|
return (
|
||||||
|
f"Error: '{normalized_path}' is a directory, not a file. "
|
||||||
|
"Use a file path instead, or use 'astrbot_execute_shell' to list directory contents."
|
||||||
|
)
|
||||||
offset, limit = self._validate_read_window(offset, limit)
|
offset, limit = self._validate_read_window(offset, limit)
|
||||||
sb = await get_booter(
|
sb = await get_booter(
|
||||||
context.context.context,
|
context.context.context,
|
||||||
|
|||||||
@@ -620,3 +620,23 @@ async def test_grep_tool_applies_result_limit(
|
|||||||
assert "match-2" in result
|
assert "match-2" in result
|
||||||
assert "match-3" not in result
|
assert "match-3" not in result
|
||||||
assert "[Truncated to first 2 result groups.]" in result
|
assert "[Truncated to first 2 result groups.]" in result
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_file_read_tool_rejects_directory_with_clear_message(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
tmp_path,
|
||||||
|
):
|
||||||
|
"""FileReadTool should return a helpful message when given a directory path."""
|
||||||
|
workspace = _setup_local_fs_tools(monkeypatch, tmp_path)
|
||||||
|
subdir = workspace / "my-directory"
|
||||||
|
subdir.mkdir()
|
||||||
|
|
||||||
|
result = await fs_tools.FileReadTool().call(
|
||||||
|
_make_context(),
|
||||||
|
path="my-directory",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "is a directory, not a file" in result
|
||||||
|
assert "my-directory" in result
|
||||||
|
assert "'astrbot_execute_shell'" in result
|
||||||
|
|||||||
Reference in New Issue
Block a user