diff --git a/src/benchflow/rollout/__init__.py b/src/benchflow/rollout/__init__.py index 8e73b0f96..49a73c666 100644 --- a/src/benchflow/rollout/__init__.py +++ b/src/benchflow/rollout/__init__.py @@ -1380,8 +1380,16 @@ async def disconnect(self) -> None: self._session = None self._session_adapter = None self._is_session_factory = False - # Kill any lingering agent processes to prevent context bleed between scenes - agent_pattern = _agent_process_kill_pattern(self._agent_launch) + # Kill any lingering agent processes to prevent context bleed between scenes. + # Oracle awaits solve.sh directly and starts no persistent agent. Its launch + # value is only a fallback label; on shared PID namespaces, a pkill pattern + # derived from it can match the host's ``--agent oracle`` command. + # Use the current launch label because connect_as() updates it for each role. + agent_pattern = ( + None + if self._agent_launch.strip() == "oracle" + else _agent_process_kill_pattern(self._agent_launch) + ) if self._env and agent_pattern: with contextlib.suppress(Exception): await self._env.exec( diff --git a/tests/test_oracle.py b/tests/test_oracle.py index b40f63f2d..0bd23caa8 100644 --- a/tests/test_oracle.py +++ b/tests/test_oracle.py @@ -1,8 +1,51 @@ +from types import SimpleNamespace from unittest.mock import AsyncMock, MagicMock import pytest +@pytest.mark.asyncio +@pytest.mark.parametrize( + ("agent_launch", "cleanup_command"), + [ + ("oracle", None), + ("opencode", "pkill -f '(^|[ /])opencode( |$)' || true"), + ( + "oracle-agent-acp", + "pkill -f '(^|[ /])oracle\\-agent\\-acp( |$)' || true", + ), + ], +) +async def test_disconnect_skips_process_cleanup_only_for_oracle( + agent_launch: str, cleanup_command: str | None +): + """Guards the Oracle fix against PR #274's unconditional label cleanup.""" + from benchflow.rollout import Rollout + + env = SimpleNamespace(exec=AsyncMock()) + rollout = SimpleNamespace( + _phase="verified", + _is_session_factory=False, + _capture_partial_acp_trajectory=lambda: None, + _acp_client=None, + _session=None, + _session_adapter=None, + _agent_launch=agent_launch, + _env=env, + _active_role=None, + _session_tool_count=0, + _session_traj_count=0, + ) + + await Rollout.disconnect(rollout) + + if cleanup_command: + env.exec.assert_awaited_once_with(cleanup_command, timeout_sec=10) + else: + env.exec.assert_not_awaited() + assert rollout._phase == "verified" + + def _oracle_env(): env = MagicMock()