Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions examples/swe-agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ generous — agentic trials routinely run past an hour, and a short timeout kill
them mid-episode. Verify `http://<agent-server>:30000/health` before launching
Miles.

The two per-trial timeouts must be ordered. `--agent-timeout` is the authoritative
one: when it fires, the agent server ends the trial and frees its sandbox. The
rollout client applies a second ceiling, `AGENT_TRIAL_TIMEOUT` (default 7200
seconds), which has to stay above `--agent-timeout`. If the client gives up first,
the trial is recorded as aborted while the agent server keeps running it, so the
sandbox and its `--max-concurrent` slot stay busy for the remaining difference, and
the aborted sample takes its whole GRPO group down with it. Raise it through the
launcher's generic env-var hook:

```bash
python examples/swe-agent/run.py ... --extra-env-vars 'AGENT_TRIAL_TIMEOUT=10800'
```

If the trainer reaches the agent server through a proxy or an in-cluster service
rather than directly, point `--agent-server-url` at that stable name rather than
an ephemeral pod address. The rollout client enables TCP keepalive probes so
Expand Down
13 changes: 11 additions & 2 deletions examples/swe-agent/swe_agent_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,17 @@

logger = logging.getLogger(__name__)

# Backstop for an unreachable agent server; its own --agent-timeout should fire first.
_DEFAULT_AGENT_TRIAL_TIMEOUT_S = 7200

_agent_server_client: httpx.AsyncClient | None = None


def _agent_trial_timeout_s() -> int:
"""Per-trial ceiling for the agent-server call, overridable via AGENT_TRIAL_TIMEOUT."""
return int(os.environ.get("AGENT_TRIAL_TIMEOUT", _DEFAULT_AGENT_TRIAL_TIMEOUT_S))


def _get_agent_server_client() -> httpx.AsyncClient:
"""Return a client whose long-running requests survive idle network paths."""
global _agent_server_client
Expand Down Expand Up @@ -102,13 +110,14 @@ async def run(
if session_server_instance_id is not None:
request["session_server_instance_id"] = session_server_instance_id

trial_timeout_s = _agent_trial_timeout_s()
try:
response = await asyncio.wait_for(
_post_agent_server(f"{agent_server_url}/run", request),
timeout=3600, # 1 hour max per trial
timeout=trial_timeout_s,
)
except asyncio.TimeoutError:
logger.error("Agent server call timed out after 3600s")
logger.error(f"Agent server call timed out after {trial_timeout_s}s")
return None
except asyncio.CancelledError:
logger.warning("Agent server call cancelled (sibling task failure?)")
Expand Down