import asyncio def test_new_tmux_session_forwards_runtime_python_environment(monkeypatch): from src.agent_tools import subprocess_tools calls = [] checks = 0 async def fake_has_session(_name): nonlocal checks checks += 1 return checks > 1 async def fake_run_exec(*args, **kwargs): calls.append(args) if args[:2] == ("tmux", "has-session"): return "", "", 0 return "", "", 0 monkeypatch.setattr(subprocess_tools, "_tmux_has_session", fake_has_session) monkeypatch.setattr(subprocess_tools, "_run_exec", fake_run_exec) asyncio.run(subprocess_tools._ensure_tmux_session( "ody-test", "/workspace", { "PATH": "/opt/ody/bin:/usr/bin", "VIRTUAL_ENV": "/opt/ody", "HOME": "/workspace", "TMPDIR": "/workspace/.tmp", "SECRET": "must-not-forward", }, )) new_session = next(call for call in calls if call[:2] == ("tmux", "new-session")) assert "PATH=/opt/ody/bin:/usr/bin" in new_session assert "VIRTUAL_ENV=/opt/ody" in new_session assert "HOME=/workspace" in new_session assert "TMPDIR=/workspace/.tmp" in new_session assert not any("SECRET=" in arg for arg in new_session) def test_reused_tmux_session_refreshes_runtime_python_environment(monkeypatch): from src.agent_tools import subprocess_tools sent = [] async def fake_has_session(_name): return True async def fake_send_line(name, line): sent.append((name, line)) async def fake_run_exec(*_args, **_kwargs): return "", "", 0 monkeypatch.setattr(subprocess_tools, "_tmux_has_session", fake_has_session) monkeypatch.setattr(subprocess_tools, "_tmux_send_line", fake_send_line) monkeypatch.setattr(subprocess_tools, "_run_exec", fake_run_exec) asyncio.run(subprocess_tools._ensure_tmux_session( "ody-existing", "/workspace", {"PATH": "/path with spaces/bin:/usr/bin", "VIRTUAL_ENV": "/path with spaces"}, )) assert sent == [( "ody-existing", "export PATH='/path with spaces/bin:/usr/bin' VIRTUAL_ENV='/path with spaces'", )] def test_workspace_alias_rewrite_does_not_duplicate_absolute_host_path(): from src.agent_tools.subprocess_tools import _replace_workspace_alias cwd = "/runs/task/workspace" command = "cd /workspace && python /runs/task/workspace/plot.py" assert _replace_workspace_alias(command, cwd) == ( "cd /runs/task/workspace && python /runs/task/workspace/plot.py" ) def test_workspace_namespace_preserves_literal_paths_inside_scripts(tmp_path): from pathlib import Path import subprocess from src.agent_tools.subprocess_tools import _wrap_workspace_namespace command = _wrap_workspace_namespace( "python -c 'from pathlib import Path; Path(\"/workspace/result.txt\").write_text(\"ok\")'", str(tmp_path), ) if command is None: return subprocess.run(command, shell=True, check=True) assert (Path(tmp_path) / "result.txt").read_text() == "ok" def test_tmux_bash_runs_tool_command_with_closed_stdin(monkeypatch, tmp_path): from src.agent_tools import subprocess_tools sent = [] async def fake_ensure(*_args, **_kwargs): return None async def fake_send(_name, line): sent.append(line) async def fake_capture(_name): start = next(line for line in sent if "__ODYSSEUS_CMD_START_" in line) start = start.split("\\n")[1] end_line = next(line for line in sent if "__ODYSSEUS_CMD_END_" in line) end = end_line.split("\\n")[1].split("%s")[0] return f"{start}\ngot-eof\n{end}0\n" monkeypatch.setattr(subprocess_tools, "_ensure_tmux_session", fake_ensure) monkeypatch.setattr(subprocess_tools, "_tmux_send_line", fake_send) monkeypatch.setattr(subprocess_tools, "_tmux_capture", fake_capture) monkeypatch.setattr(subprocess_tools.time, "time", lambda: 0.123456) output, _stderr, rc, timed_out = asyncio.run( subprocess_tools._run_tmux_bash( "if read answer; then echo unexpected; else echo got-eof; fi", session_id="test", cwd=str(tmp_path), env={}, timeout=2, ) ) assert output == "got-eof" assert rc == 0 assert timed_out is False assert any("/bin/bash -lc" in line and "