mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-21 16:18:55 +00:00
fix(cli): expand oneshot cleanup to cover all process-global resources
The initial salvage from #43698 only shut down MCP servers and cached auxiliary clients. The interactive CLI's _run_cleanup() also closes terminal environments, browser sessions, and interrupts async delegations — all of which can hold native-extension-backed resources (aiohttp connectors, websocket clients) that SIGABRT during Py_FinalizeEx. Add the missing three sites to _cleanup_oneshot_runtime(), matching the order in cli.py:_run_cleanup(). Update tests to cover the expanded cleanup chain. Credit: @konsisumer (#67768) identified the full cleanup surface.
This commit is contained in:
parent
7462546a33
commit
2de60a3a7e
2 changed files with 59 additions and 7 deletions
|
|
@ -111,10 +111,26 @@ def _exit_after_oneshot(rc: object) -> None:
|
|||
def _cleanup_oneshot_runtime() -> None:
|
||||
"""Best-effort process-global cleanup before one-shot hard exit.
|
||||
|
||||
``run_oneshot`` owns the agent-local cleanup. This mirrors the lightweight,
|
||||
process-global pieces from the interactive CLI shutdown path that would
|
||||
otherwise be skipped by ``os._exit``.
|
||||
``run_oneshot`` owns the agent-local cleanup (memory provider, agent.close,
|
||||
session_db.close — all in ``_run_agent``'s finally block). This mirrors the
|
||||
process-global pieces from ``cli.py:_run_cleanup()`` that would otherwise
|
||||
be skipped by ``os._exit``.
|
||||
"""
|
||||
try:
|
||||
from tools.terminal_tool import cleanup_all_environments
|
||||
cleanup_all_environments()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
from tools.async_delegation import interrupt_all
|
||||
interrupt_all(reason="oneshot shutdown")
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
from tools.browser_tool import _emergency_cleanup_all_sessions
|
||||
_emergency_cleanup_all_sessions()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
from tools.mcp_tool import shutdown_mcp_servers
|
||||
shutdown_mcp_servers()
|
||||
|
|
|
|||
|
|
@ -857,20 +857,41 @@ def test_run_and_exit_oneshot_cleans_global_runtime_before_hard_exit(
|
|||
):
|
||||
events = []
|
||||
|
||||
def _mod(name, **attrs):
|
||||
fake = types.ModuleType(name)
|
||||
for key, value in attrs.items():
|
||||
setattr(fake, key, value)
|
||||
return fake
|
||||
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"hermes_cli.oneshot",
|
||||
types.SimpleNamespace(run_oneshot=lambda *_args, **_kwargs: events.append("run") or 0),
|
||||
)
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"tools.terminal_tool",
|
||||
_mod("tools.terminal_tool", cleanup_all_environments=lambda: events.append("terminal")),
|
||||
)
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"tools.async_delegation",
|
||||
_mod("tools.async_delegation", interrupt_all=lambda **kw: events.append("delegation")),
|
||||
)
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"tools.browser_tool",
|
||||
_mod("tools.browser_tool", _emergency_cleanup_all_sessions=lambda: events.append("browser")),
|
||||
)
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"tools.mcp_tool",
|
||||
types.SimpleNamespace(shutdown_mcp_servers=lambda: events.append("mcp")),
|
||||
_mod("tools.mcp_tool", shutdown_mcp_servers=lambda: events.append("mcp")),
|
||||
)
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"agent.auxiliary_client",
|
||||
types.SimpleNamespace(shutdown_cached_clients=lambda: events.append("aux")),
|
||||
_mod("agent.auxiliary_client", shutdown_cached_clients=lambda: events.append("aux")),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
main_mod, "_exit_after_oneshot", lambda rc: events.append(f"exit:{rc}")
|
||||
|
|
@ -878,7 +899,7 @@ def test_run_and_exit_oneshot_cleans_global_runtime_before_hard_exit(
|
|||
|
||||
main_mod._run_and_exit_oneshot("hello")
|
||||
|
||||
assert events == ["run", "mcp", "aux", "exit:0"]
|
||||
assert events == ["run", "terminal", "delegation", "browser", "mcp", "aux", "exit:0"]
|
||||
|
||||
|
||||
def test_run_and_exit_oneshot_still_exits_when_global_cleanup_raises(
|
||||
|
|
@ -894,6 +915,21 @@ def test_run_and_exit_oneshot_still_exits_when_global_cleanup_raises(
|
|||
"hermes_cli.oneshot",
|
||||
types.SimpleNamespace(run_oneshot=lambda *_args, **_kwargs: 0),
|
||||
)
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"tools.terminal_tool",
|
||||
types.SimpleNamespace(cleanup_all_environments=lambda: events.append("terminal")),
|
||||
)
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"tools.async_delegation",
|
||||
types.SimpleNamespace(interrupt_all=lambda **kw: events.append("delegation")),
|
||||
)
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"tools.browser_tool",
|
||||
types.SimpleNamespace(_emergency_cleanup_all_sessions=lambda: events.append("browser")),
|
||||
)
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"tools.mcp_tool",
|
||||
|
|
@ -910,7 +946,7 @@ def test_run_and_exit_oneshot_still_exits_when_global_cleanup_raises(
|
|||
|
||||
main_mod._run_and_exit_oneshot("hello")
|
||||
|
||||
assert events == ["aux", "exit:0"]
|
||||
assert events == ["terminal", "delegation", "browser", "aux", "exit:0"]
|
||||
|
||||
|
||||
def test_run_and_exit_oneshot_hard_exits_when_cleanup_is_interrupted(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue