mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-08 16:02:20 +02:00
fix(agent): capture Windows Bash output and pass the subprocess env
The Windows branch of `_create_bash_subprocess` spawned Git Bash with neither pipes nor the env it was handed. `proc.stdout` and `proc.stderr` came back `None`, so `_run_subprocess_streaming`'s reader returned immediately and the Bash tool reported `"(no output)"` alongside the real exit code — while the child inherited the server's own stdout/stderr and wrote agent command output into the console and the launchd/Docker logs. The `env` parameter was accepted and never used, so `PATH`, `VIRTUAL_ENV`, `HOME`, `TMPDIR` and the configured import paths carried in `ctx["subproc_env"]` never reached the child on Windows, even though every POSIX path applies them. Spawn it the way the POSIX path at `:688` already does: `stdin=DEVNULL`, `stdout=PIPE`, `stderr=PIPE`, `env=env`. `website/configuration-reference.md` is generated from source line numbers, so the four added lines shift one entry; regenerated with `scripts/generate_env_reference.py`.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
"""Windows execution contract for the agent Bash tool."""
|
||||
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
from types import SimpleNamespace
|
||||
|
||||
@@ -38,6 +40,82 @@ async def test_windows_bash_uses_git_bash_with_structural_cwd(monkeypatch):
|
||||
assert captured["kwargs"]["cwd"] == workspace
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_windows_bash_captures_output_instead_of_inheriting_server_handles(monkeypatch):
|
||||
captured = {}
|
||||
|
||||
monkeypatch.setattr(subprocess_tools, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(
|
||||
subprocess_tools, "find_bash", lambda: r"C:\Program Files\Git\bin\bash.exe"
|
||||
)
|
||||
|
||||
async def fake_exec(*_argv, **kwargs):
|
||||
captured.update(kwargs)
|
||||
return object()
|
||||
|
||||
monkeypatch.setattr(subprocess_tools.asyncio, "create_subprocess_exec", fake_exec)
|
||||
|
||||
await subprocess_tools._create_bash_subprocess("pwd", cwd=r"C:\Work")
|
||||
|
||||
assert captured["stdout"] == asyncio.subprocess.PIPE
|
||||
assert captured["stderr"] == asyncio.subprocess.PIPE
|
||||
assert captured["stdin"] == asyncio.subprocess.DEVNULL
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_windows_bash_applies_the_subprocess_env(monkeypatch):
|
||||
captured = {}
|
||||
env = {"PATH": r"C:\Odysseus\venv\Scripts", "HOME": r"C:\Odysseus\data"}
|
||||
|
||||
monkeypatch.setattr(subprocess_tools, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(
|
||||
subprocess_tools, "find_bash", lambda: r"C:\Program Files\Git\bin\bash.exe"
|
||||
)
|
||||
|
||||
async def fake_exec(*_argv, **kwargs):
|
||||
captured.update(kwargs)
|
||||
return object()
|
||||
|
||||
monkeypatch.setattr(subprocess_tools.asyncio, "create_subprocess_exec", fake_exec)
|
||||
|
||||
await subprocess_tools._create_bash_subprocess("pwd", cwd=r"C:\Work", env=env)
|
||||
|
||||
assert captured["env"] == env
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_windows_bash_tool_passes_ctx_env_through_to_the_child(monkeypatch):
|
||||
captured = {}
|
||||
env = {"PATH": r"C:\Odysseus\venv\Scripts", "VIRTUAL_ENV": r"C:\Odysseus\venv"}
|
||||
|
||||
monkeypatch.setattr(subprocess_tools, "IS_WINDOWS", True)
|
||||
monkeypatch.setattr(
|
||||
subprocess_tools, "find_bash", lambda: r"C:\Program Files\Git\bin\bash.exe"
|
||||
)
|
||||
monkeypatch.setattr("src.tool_execution.agent_cwd", lambda: r"D:\Workspaces\Project")
|
||||
|
||||
async def fake_exec(*argv, **kwargs):
|
||||
captured["argv"] = argv
|
||||
captured["kwargs"] = kwargs
|
||||
return SimpleNamespace(pid=4242)
|
||||
|
||||
async def fake_stream(_process, **_kwargs):
|
||||
return "ok", "", 0, False
|
||||
|
||||
monkeypatch.setattr(subprocess_tools.asyncio, "create_subprocess_exec", fake_exec)
|
||||
monkeypatch.setattr(subprocess_tools, "_run_subprocess_streaming", fake_stream)
|
||||
|
||||
result = await subprocess_tools.BashTool().execute(
|
||||
"pwd",
|
||||
{"subproc_env": env, "session_id": "chat-1"},
|
||||
)
|
||||
|
||||
assert result == {"output": "ok", "exit_code": 0}
|
||||
assert captured["kwargs"]["env"] == env
|
||||
assert captured["kwargs"]["stdout"] == asyncio.subprocess.PIPE
|
||||
assert captured["kwargs"]["stderr"] == asyncio.subprocess.PIPE
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_windows_bash_without_git_bash_fails_clearly(monkeypatch):
|
||||
monkeypatch.setattr(subprocess_tools, "IS_WINDOWS", True)
|
||||
|
||||
Reference in New Issue
Block a user