diff --git a/nanobot/agent/tools/filesystem.py b/nanobot/agent/tools/filesystem.py index 4f83642..da7778d 100644 --- a/nanobot/agent/tools/filesystem.py +++ b/nanobot/agent/tools/filesystem.py @@ -93,8 +93,10 @@ class ReadFileTool(_FsTool): "required": ["path"], } - async def execute(self, path: str, offset: int = 1, limit: int | None = None, **kwargs: Any) -> Any: + async def execute(self, path: str | None = None, offset: int = 1, limit: int | None = None, **kwargs: Any) -> Any: try: + if not path: + return "Error reading file: Unknown path" fp = self._resolve(path) if not fp.exists(): return f"Error: File not found: {path}" @@ -174,8 +176,12 @@ class WriteFileTool(_FsTool): "required": ["path", "content"], } - async def execute(self, path: str, content: str, **kwargs: Any) -> str: + async def execute(self, path: str | None = None, content: str | None = None, **kwargs: Any) -> str: try: + if not path: + raise ValueError("Unknown path") + if content is None: + raise ValueError("Unknown content") fp = self._resolve(path) fp.parent.mkdir(parents=True, exist_ok=True) fp.write_text(content, encoding="utf-8") @@ -248,10 +254,18 @@ class EditFileTool(_FsTool): } async def execute( - self, path: str, old_text: str, new_text: str, + self, path: str | None = None, old_text: str | None = None, + new_text: str | None = None, replace_all: bool = False, **kwargs: Any, ) -> str: try: + if not path: + raise ValueError("Unknown path") + if old_text is None: + raise ValueError("Unknown old_text") + if new_text is None: + raise ValueError("Unknown new_text") + fp = self._resolve(path) if not fp.exists(): return f"Error: File not found: {path}" @@ -350,10 +364,12 @@ class ListDirTool(_FsTool): } async def execute( - self, path: str, recursive: bool = False, + self, path: str | None = None, recursive: bool = False, max_entries: int | None = None, **kwargs: Any, ) -> str: try: + if path is None: + raise ValueError("Unknown path") dp = self._resolve(path) if not dp.exists(): return f"Error: Directory not found: {path}" diff --git a/pyproject.toml b/pyproject.toml index bbae925..7cc0094 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,6 +70,7 @@ dev = [ "matrix-nio[e2e]>=0.25.2", "mistune>=3.0.0,<4.0.0", "nh3>=0.2.17,<1.0.0", + "mypy>=1.19.1", ] [project.scripts] diff --git a/tests/test_filesystem_tools.py b/tests/test_filesystem_tools.py index cab2c94..f3069a7 100644 --- a/tests/test_filesystem_tools.py +++ b/tests/test_filesystem_tools.py @@ -77,6 +77,11 @@ class TestReadFileTool: assert "Error" in result assert "not found" in result + @pytest.mark.asyncio + async def test_missing_path_returns_clear_error(self, tool): + result = await tool.execute() + assert result == "Error reading file: Unknown path" + @pytest.mark.asyncio async def test_char_budget_trims(self, tool, tmp_path): """When the selected slice exceeds _MAX_CHARS the output is trimmed.""" @@ -200,6 +205,13 @@ class TestEditFileTool: assert "Error" in result assert "not found" in result + @pytest.mark.asyncio + async def test_missing_new_text_returns_clear_error(self, tool, tmp_path): + f = tmp_path / "a.py" + f.write_text("hello", encoding="utf-8") + result = await tool.execute(path=str(f), old_text="hello") + assert result == "Error editing file: Unknown new_text" + # --------------------------------------------------------------------------- # ListDirTool @@ -263,6 +275,11 @@ class TestListDirTool: assert "Error" in result assert "not found" in result + @pytest.mark.asyncio + async def test_missing_path_returns_clear_error(self, tool): + result = await tool.execute() + assert result == "Error listing directory: Unknown path" + # --------------------------------------------------------------------------- # Workspace restriction + extra_allowed_dirs