Files
hermes-agent/tests/tools/test_execute_code_lifecycle_guard_deadline.py
teknium1 30b22b54ae fix(tools): bound execute_code's lifecycle probe and keep the terminal guard answerable to /stop
execute_code ran the same unbounded _is_supervised_gateway_process() probe
ahead of every cell, so the wedge #111922 bounds in terminal_tool still hung
an execute_code call (and its cron slot) forever: share the cell's deadline
and fail closed with a retryable error when the probe renders no verdict.

Moving the terminal pre-exec guard onto a deadline worker made it blind to
/stop, which keys on the tool thread's ident: record the acting-for tid in a
contextvar (copied into the worker by run_bounded_sync) so is_interrupted()
on the worker honours the tool thread's bit too.

Floor the guard's share of the deadline at 30s so a short command timeout
does not turn the guard's own cold-start cost (imports, git probes under
load) into a refusal — tests/tools/test_terminal_error_redaction.py was red
on the branch for exactly that.
2026-09-15 19:09:29 -07:00

34 lines
1.4 KiB
Python

"""execute_code's gateway-lifecycle identity probe shares the cell deadline (#111922).
The same ``_is_supervised_gateway_process`` probe that wedged ``terminal_tool`` runs
ahead of every ``execute_code`` cell; a probe that renders no verdict must fail closed
within the deadline instead of holding the tool call (and its cron slot) forever.
"""
from __future__ import annotations
import json
import time
import tools.code_execution_tool as cet
import tools.terminal_tool as terminal_module
def test_wedged_lifecycle_probe_returns_bounded_error_without_running(monkeypatch):
import tools.process_registry as process_registry
monkeypatch.setattr(cet, "SANDBOX_AVAILABLE", True)
monkeypatch.setattr(cet, "_load_config", lambda: {"timeout": 0.05})
monkeypatch.setattr(terminal_module, "_PRE_EXEC_GUARD_MIN_TIMEOUT_S", 0)
monkeypatch.setattr(process_registry, "_is_supervised_gateway_process", lambda: time.sleep(1))
ran: list[str] = []
monkeypatch.setattr(cet, "_get_env_config", lambda: ran.append("env") or {"env_type": "local"}, raising=False)
start = time.monotonic()
result = json.loads(cet.execute_code("print('hi')"))
elapsed = time.monotonic() - start
assert elapsed < 0.5, f"lifecycle probe wedged execute_code for {elapsed:.2f}s"
assert "did not finish" in result["error"]
assert ran == [], "a probe with no verdict must not fail open into execution"