feat: add global timeout to terminal bench - #2826
Conversation
Signed-off-by: Elisa Martinez Abad <elisam@nvidia.com>
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
Signed-off-by: Elisa Martinez Abad <elisam@nvidia.com>
|
/claude review |
|
SHIP — LGTM, no reliability concerns. Small, additive change adding an opt-in
Optional NOTE (author's call): the new field isn't documented in any exemplar YAML under |
…meout-anyterminal
| config_overrides = {} | ||
| if problem_info.get("agent_timeout_sec"): | ||
| if self.config.global_agent_timeout is not None: | ||
| config_overrides["tb_agent_timeout"] = self.config.global_agent_timeout |
There was a problem hiding this comment.
This can be set higher than the container's own lifetime, and nothing checks that. The sandbox starts with ttl_s=cfg.tb_sandbox_ttl (default 7200) at L582. In the Docker provider, that makes PID 1 a literal sleep 7200 with --rm (provider.py:337-345), so the container is deleted at t=7200 regardless of the agent timeout.
The tests use global_agent_timeout=7200, exactly equal to the TTL. That leaves no room for startup, staging, or the 300s eval afterward, so the container can disappear before the run finishes. The config comment also points to 12000 as the TB2 max, which is well beyond the TTL.
anyswe_agent derives the TTL instead: swebench_agent_timeout + swebench_tests_timeout + 600 (anyswe_agent/app.py:335). Could we do the same here, or fail at config time if global_agent_timeout + tb_eval_timeout >= tb_sandbox_ttl?
| if result.return_code != 0: | ||
| detail = result.stderr or result.stdout or "" | ||
| print(f"[{cfg.task_name}] agent exit {result.return_code}: {detail[-2000:]}", flush=True) | ||
| return time.time() - t0, result.error_type == "timeout" |
There was a problem hiding this comment.
When the container is killed by its TTL, we score the task as a real zero instead of masking it.
exec on a removed container returns error_type="sandbox" and does not raise. This line and L570 only check for "timeout", while sandbox_failed is only set in the except block, which never runs. As a result, mask_sample at L628 stays False, and a dead container looks like a genuine failed attempt.
anyswe_agent checks result.error_type in ("timeout", "sandbox") (app.py:411, 458). Maybe worth matching that behavior here
| agent_runtime_source: str = "auto" | ||
| tb_agent_timeout: int = 1800 | ||
| # When set, overrides the per-task agent_timeout_sec from the dataset for every task. | ||
| global_agent_timeout: Optional[int] = None |
There was a problem hiding this comment.
Could this use Field(default=None, gt=0)?
Right now, global_agent_timeout: 0 passes validation, and the check on L777 is is not None, so 0 goes straight through as the agent timeout and every task fails immediately with an empty trace. The old code used a truthiness check, which effectively ignored 0.
What does this PR do?
Adds an optional
global_agent_timeoutconfig field toAnyTerminalAgentConfig. When set, it overrides the per-taskagent_timeout_secfrom the dataset for every task, instead of the current default of a per-task timeout falling back totb_agent_timeout.This is useful for harness-optimization evals where we want longer traces to observe model behavior — e.g. when running slower models, per-task dataset timeouts can cut off runs before enough signal is collected. Setting
global_agent_timeoutlets a single config value apply uniformly across all tasks without editing the dataset.Default behavior (per-task timeout takes precedence) is unchanged when
global_agent_timeoutis left unset (None).Checklist
pre-commit run --all-files) (so CI lint/format/copyright pass).git commit -s) (so the DCO check passes).