Fix Windows Path Handling in Filesystem Operations
Fix Windows Path Handling in Filesystem Operations
Summary
This PR fixes Windows path handling issues in the filesystem backend and middleware that prevented proper file operations on Windows systems. **Fixes #340 **
Problem
The codebase had multiple issues with Windows path handling:
-
Path Validation Issue: The
_validate_path()function in middleware incorrectly added a leading slash to Windows absolute paths (e.g.,C:/Users/...became/C:/Users/...), breaking path resolution in the backend. -
Inconsistent Path Separators: The
FilesystemBackend.ls_info()method mixed Windows backslashes and POSIX forward slashes, causing test failures and inconsistent behavior (e.g., returning/\local.txtinstead of/local.txt).
Reproduction Steps
This procedure demonstrates the incorrect path handling on Windows:
- Environment: Win10, Powershell (or any Windows terminal).
-
Setup: Checkout the commit (
9ed6483e...) and run the application:cd libs\deepagents-cli uv run deepagents - Execute the Command: Ask the deep agent to list the contents of the current working directory
-
Agent move The agent will use tool
ls(.) - Observed Failure: The agent incorrectly reports that the directory is empty.
⚠️ Temporary File Modification Required for Testing ⚠️
We might need to add an exception handler for ModuleNotFoundError: No module named 'termios' within execution.py to ensure successful startup of deepagents on Windows environments. This module is typically Unix-specific, and catching the exception would allow the program to gracefully proceed without terminal control features
Root Cause
When an AI agent called ls("C:\..."):
- Middleware's
_validate_path()normalized it to/C:/...(added leading/) -
FilesystemBackend._resolve_path()treated this as a relative path - Path resolution failed, resulting in empty directory listings
In backends/filesystem.py: ls_info
dir_path = self._resolve_path(path)
if not dir_path.exists() or not dir_path.is_dir():
return [] # <--
Additionally, the backend's ls_info() returned paths with mixed separators on Windows, breaking cross-platform compatibility.
Solution
1. Improved Windows Path Detection (middleware/filesystem.py)
Before:
if not normalized.startswith("/") and not (len(normalized) >= 2 and normalized[1] == ":"):
normalized = f"/{normalized}"
After:
# Use os.path.splitdrive for robust Windows path detection
drive, _ = os.path.splitdrive(normalized)
if not normalized.startswith("/") and not drive:
normalized = f"/{normalized}"
Benefits:
- Handles Windows drive letters correctly (e.g.,
C:,D:) - Supports UNC paths (e.g.,
\\server\share) - Prevents incorrectly adding leading slash to Windows absolute paths
2. Consistent POSIX-Style Path Normalization (backends/filesystem.py)
Updated ls_info(), grep_raw(), and glob_info() to consistently normalize all returned paths to POSIX style (forward slashes only):
# Normalize to POSIX style (forward slashes only) for consistency
abs_path = abs_path.replace("\\", "/")
relative_path = relative_path.replace("\\", "/")
Benefits:
- Consistent path format across platforms
3. Updated Tests for Cross-Platform Compatibility
Modified test assertions to normalize paths before comparison:
# Before
assert str(root / "file1.txt") in root_paths
# After
assert str(root / "file1.txt").replace("\\", "/") in root_paths
Unit Tests on Windows
Before Fix
FAILED libs/deepagents/tests/unit_tests/backends/test_filesystem_backend.py::test_filesystem_backend_normal_mode
FAILED libs/deepagents/tests/unit_tests/backends/test_filesystem_backend.py::test_filesystem_backend_virtual_mode
FAILED libs/deepagents/tests/unit_tests/backends/test_filesystem_backend.py::test_filesystem_backend_ls_nested_directories
FAILED libs/deepagents/tests/unit_tests/backends/test_composite_backend.py::test_composite_backend_filesystem_plus_store
FAILED libs/deepagents/tests/unit_tests/backends/test_composite_backend.py::test_composite_backend_ls_nested_directories
5 failed, 73 passed
After Fix
78 passed
Thanks! This is blocking me selecting deepagents🫡