diff --git a/backend/packages/harness/deerflow/community/aio_sandbox/local_backend.py b/backend/packages/harness/deerflow/community/aio_sandbox/local_backend.py index 9dca58fcd..52124ab73 100644 --- a/backend/packages/harness/deerflow/community/aio_sandbox/local_backend.py +++ b/backend/packages/harness/deerflow/community/aio_sandbox/local_backend.py @@ -18,6 +18,26 @@ from .sandbox_info import SandboxInfo logger = logging.getLogger(__name__) +def _format_container_mount(runtime: str, host_path: str, container_path: str, read_only: bool) -> list[str]: + """Format a bind-mount argument for the selected runtime. + + Docker's ``-v host:container`` syntax is ambiguous for Windows drive-letter + paths like ``D:/...`` because ``:`` is both the drive separator and the + volume separator. Use ``--mount type=bind,...`` for Docker to avoid that + parsing ambiguity. Apple Container keeps using ``-v``. + """ + if runtime == "docker": + mount_spec = f"type=bind,src={host_path},dst={container_path}" + if read_only: + mount_spec += ",readonly" + return ["--mount", mount_spec] + + mount_spec = f"{host_path}:{container_path}" + if read_only: + mount_spec += ":ro" + return ["-v", mount_spec] + + class LocalContainerBackend(SandboxBackend): """Backend that manages sandbox containers locally using Docker or Apple Container. @@ -246,18 +266,26 @@ class LocalContainerBackend(SandboxBackend): # Config-level volume mounts for mount in self._config_mounts: - mount_spec = f"{mount.host_path}:{mount.container_path}" - if mount.read_only: - mount_spec += ":ro" - cmd.extend(["-v", mount_spec]) + cmd.extend( + _format_container_mount( + self._runtime, + mount.host_path, + mount.container_path, + mount.read_only, + ) + ) # Extra mounts (thread-specific, skills, etc.) if extra_mounts: for host_path, container_path, read_only in extra_mounts: - mount_spec = f"{host_path}:{container_path}" - if read_only: - mount_spec += ":ro" - cmd.extend(["-v", mount_spec]) + cmd.extend( + _format_container_mount( + self._runtime, + host_path, + container_path, + read_only, + ) + ) cmd.append(self._image) diff --git a/backend/tests/test_aio_sandbox_local_backend.py b/backend/tests/test_aio_sandbox_local_backend.py new file mode 100644 index 000000000..d0b99bec1 --- /dev/null +++ b/backend/tests/test_aio_sandbox_local_backend.py @@ -0,0 +1,28 @@ +from deerflow.community.aio_sandbox.local_backend import _format_container_mount + + +def test_format_container_mount_uses_mount_syntax_for_docker_windows_paths(): + args = _format_container_mount("docker", "D:/deer-flow/backend/.deer-flow/threads", "/mnt/threads", False) + + assert args == [ + "--mount", + "type=bind,src=D:/deer-flow/backend/.deer-flow/threads,dst=/mnt/threads", + ] + + +def test_format_container_mount_marks_docker_readonly_mounts(): + args = _format_container_mount("docker", "/host/path", "/mnt/path", True) + + assert args == [ + "--mount", + "type=bind,src=/host/path,dst=/mnt/path,readonly", + ] + + +def test_format_container_mount_keeps_volume_syntax_for_apple_container(): + args = _format_container_mount("container", "/host/path", "/mnt/path", True) + + assert args == [ + "-v", + "/host/path:/mnt/path:ro", + ]