Skip to content

Commit 41f8960

Browse files
authored
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
1 parent 7831c68 commit 41f8960

2 files changed

Lines changed: 25 additions & 0 deletions

File tree

astrbot/core/tools/computer_tools/fs.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ async def call(
304304
)
305305
if not normalized_path:
306306
raise ValueError("`path` must be a non-empty string.")
307+
if local_env and os.path.isdir(normalized_path):
308+
return (
309+
f"Error: '{normalized_path}' is a directory, not a file. "
310+
"Use a file path instead, or use 'astrbot_execute_shell' to list directory contents."
311+
)
307312
offset, limit = self._validate_read_window(offset, limit)
308313
sb = await get_booter(
309314
context.context.context,

tests/test_computer_fs_tools.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,3 +620,23 @@ async def test_grep_tool_applies_result_limit(
620620
assert "match-2" in result
621621
assert "match-3" not in result
622622
assert "[Truncated to first 2 result groups.]" in result
623+
624+
625+
@pytest.mark.asyncio
626+
async def test_file_read_tool_rejects_directory_with_clear_message(
627+
monkeypatch: pytest.MonkeyPatch,
628+
tmp_path,
629+
):
630+
"""FileReadTool should return a helpful message when given a directory path."""
631+
workspace = _setup_local_fs_tools(monkeypatch, tmp_path)
632+
subdir = workspace / "my-directory"
633+
subdir.mkdir()
634+
635+
result = await fs_tools.FileReadTool().call(
636+
_make_context(),
637+
path="my-directory",
638+
)
639+
640+
assert "is a directory, not a file" in result
641+
assert "my-directory" in result
642+
assert "'astrbot_execute_shell'" in result

0 commit comments

Comments
 (0)