From c15eac2fc8ce4d0133736cff971059e74d588eac Mon Sep 17 00:00:00 2001 From: Cedric Conday Date: Tue, 30 Jun 2026 12:33:40 +0000 Subject: [PATCH] fix(computer): clear error when file_read_tool is given a directory astrbot_file_read_tool opened the path directly, so passing a directory surfaced a misleading OS error ('[Errno 13] Permission denied' on Windows, IsADirectoryError on Linux) instead of saying it's a directory. Add a proactive is_dir() guard in read_file_tool_result (local mode) that returns a clear message pointing to astrbot_execute_shell for listing. Fixes #9087 Co-Authored-By: Claude --- astrbot/core/computer/file_read_utils.py | 6 ++++++ tests/test_computer_fs_tools.py | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/astrbot/core/computer/file_read_utils.py b/astrbot/core/computer/file_read_utils.py index 5b5fd9fc8e..3e0432bcf5 100644 --- a/astrbot/core/computer/file_read_utils.py +++ b/astrbot/core/computer/file_read_utils.py @@ -652,6 +652,12 @@ async def read_file_tool_result( workspace_dir: str | None = None, ) -> ToolExecResult: if local_mode: + if Path(path).is_dir(): + return ( + f"Error: `{path}` is a directory, not a file. " + "Provide a file path instead, or use `astrbot_execute_shell` " + "to list directory contents." + ) probe_payload = await _probe_local_file(path) else: probe_payload = await _exec_python_json( diff --git a/tests/test_computer_fs_tools.py b/tests/test_computer_fs_tools.py index 11571665a5..61586aee93 100644 --- a/tests/test_computer_fs_tools.py +++ b/tests/test_computer_fs_tools.py @@ -450,6 +450,25 @@ async def test_file_read_tool_allows_partial_read_for_large_text_file( assert result == "".join(lines[1000:1003]) +@pytest.mark.asyncio +async def test_file_read_tool_reports_directory_clearly( + monkeypatch: pytest.MonkeyPatch, + tmp_path, +): + workspace = _setup_local_fs_tools(monkeypatch, tmp_path) + (workspace / "some_dir").mkdir() + + result = await fs_tools.FileReadTool().call( + _make_context(), + path="some_dir", + ) + + assert isinstance(result, str) + assert "is a directory" in result + assert "astrbot_execute_shell" in result + assert "Permission denied" not in result + + @pytest.mark.asyncio async def test_file_read_tool_returns_image_call_tool_result_for_images( monkeypatch: pytest.MonkeyPatch,