mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
Second, deeper pass over tools/gateway/hermes_cli plus first pass over the trees wave 1 missed (acp, acp_adapter, skills, computer_use, docker, dashboard, conformance, monitoring, secret_sources, hermes_state, providers). Same rubric as wave 1 (AGENTS.md test policy); security, alternation/caching invariants, issue-number regressions, and E2E kept. Real test-quality fixes found and rooted out along the way: - tests/tools/test_command_guards.py made real auxiliary-LLM HTTPS calls (DEFAULT_CONFIG smart-approval leaked in) — pinned approval mode=manual via autouse fixture: 17.4s → 0.4s. - test_model_switch_custom_providers.py / test_user_providers_model_switch.py silently probed live provider catalogs (~2s/test) — stubbed cached_provider_model_ids/provider_model_ids/fetch_api_models. - test_telegram_noise_filter.py: 15-platform copy-paste matrix over shared gateway.run logic → 3 representative platforms (55s → 3.9s). - test_gateway_shutdown.py: stop()'s 5s interrupt-deadline loop spun on MagicMock agents — interrupt.side_effect now clears _running_agents (22s → 1.0s). - test_gateway_inactivity_timeout.py poll-harness timings shrunk 3-5x (24s → 1.1s); test_mcp_stability.py backoff/SIGTERM-grace sleeps patched (15.4s → 2.5s); test_async_delegation.py negative-drain wait 5s → 0.5s. - test_telegram_init_deadline.py: loop-block margin restored to 1.0s with rationale comment — the watchdog-dump assertion needs the loop blocked well past deadline+grace under parallel load (flaked once in the 40-worker verification run at a 0.2s margin). Verification: full hermetic suite via scripts/run_tests.sh — 2,438 files, 21,718 tests passed, 0 failed, 293.9s wall. Suite totals vs original baseline: 46,820 → 19,757 test functions (−57.8%), wall 583.5s → 293.9s (−50%), subprocess CPU 13,564s → 11,623s.
121 lines
4.2 KiB
Python
121 lines
4.2 KiB
Python
"""Regression for the X11 null-PID `list_windows` crash.
|
||
|
||
On X11 a window's PID comes from the *optional* ``_NET_WM_PID`` property, so
|
||
the cua-driver legitimately reports ``pid: null`` for windows that don't set
|
||
it (the desktop root, panels, override-redirect popups, …). Both
|
||
``capture()`` and ``focus_app()`` previously coerced *every* window's pid via
|
||
``int(w["pid"])`` inside a list comprehension, so a single null-pid window
|
||
raised::
|
||
|
||
TypeError: int() argument must be a string, a bytes-like object or a
|
||
real number, not 'NoneType'
|
||
|
||
…aborting the whole enumeration before any screenshot was taken — i.e. the
|
||
agent could never capture the screen at all on an X11 desktop that had even
|
||
one such window.
|
||
|
||
The fix routes both ingestion sites through ``_ingest_windows``, which skips
|
||
windows lacking a usable pid/window_id (uncapturable anyway) and coerces the
|
||
rest, so real targetable windows survive.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import base64
|
||
from unittest.mock import MagicMock
|
||
|
||
# 8×8 transparent PNG — decodes cleanly so capture() can size it.
|
||
_PNG_B64 = (
|
||
"iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAADUlEQVR4nG"
|
||
"NgGAUgAAABCAABgukLHQAAAABJRU5ErkJggg=="
|
||
)
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# _ingest_windows: the fix locus (pure function, no session needed)
|
||
# ---------------------------------------------------------------------------
|
||
|
||
class TestIngestWindows:
|
||
def test_skips_window_with_null_pid(self):
|
||
from tools.computer_use.cua_backend import _ingest_windows
|
||
|
||
raw = [
|
||
{"app_name": "Desktop", "pid": None, "window_id": 1, "z_index": 0},
|
||
{"app_name": "Firefox", "pid": 4321, "window_id": 77, "z_index": 1},
|
||
]
|
||
|
||
out = _ingest_windows(raw)
|
||
|
||
assert [w["app_name"] for w in out] == ["Firefox"]
|
||
assert out[0]["pid"] == 4321
|
||
assert out[0]["window_id"] == 77
|
||
|
||
|
||
def test_preserves_fields_capture_relies_on(self):
|
||
from tools.computer_use.cua_backend import _ingest_windows
|
||
|
||
out = _ingest_windows([
|
||
{
|
||
"app_name": "Firefox",
|
||
"pid": 1,
|
||
"window_id": 2,
|
||
"is_on_screen": False,
|
||
"title": "Mozilla Firefox",
|
||
"z_index": 3,
|
||
}
|
||
])
|
||
|
||
w = out[0]
|
||
assert w["off_screen"] is True # derived from is_on_screen
|
||
assert w["title"] == "Mozilla Firefox"
|
||
assert w["z_index"] == 3
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# capture(): end-to-end proof the null-pid window no longer crashes capture
|
||
# ---------------------------------------------------------------------------
|
||
|
||
def _backend_with_windows(raw_windows):
|
||
"""A CuaDriverBackend whose session returns `raw_windows` from
|
||
list_windows and a valid PNG from screenshot."""
|
||
from tools.computer_use.cua_backend import CuaDriverBackend
|
||
|
||
backend = CuaDriverBackend()
|
||
session = MagicMock()
|
||
session.capabilities_discovered = True
|
||
session._has_tool.return_value = True
|
||
|
||
def _call_tool(name, args, *a, **k):
|
||
if name == "list_windows":
|
||
return {"structuredContent": {"windows": raw_windows}}
|
||
if name == "screenshot":
|
||
return {
|
||
"structuredContent": {
|
||
"screenshot_png_b64": _PNG_B64,
|
||
"screenshot_mime_type": "image/png",
|
||
}
|
||
}
|
||
return {}
|
||
|
||
session.call_tool.side_effect = _call_tool
|
||
backend._session = session
|
||
return backend
|
||
|
||
|
||
def test_capture_vision_survives_null_pid_window():
|
||
raw = [
|
||
{"app_name": "Desktop", "pid": None, "window_id": 1, "z_index": 0},
|
||
{"app_name": "Firefox", "pid": 4321, "window_id": 77,
|
||
"is_on_screen": True, "title": "Mozilla Firefox", "z_index": 1},
|
||
]
|
||
backend = _backend_with_windows(raw)
|
||
|
||
cap = backend.capture(mode="vision")
|
||
|
||
# The real, targetable window is selected rather than the whole capture
|
||
# crashing on the null-pid desktop window.
|
||
assert cap.app == "Firefox"
|
||
assert cap.png_b64 == _PNG_B64
|
||
assert backend._active_pid == 4321
|
||
assert backend._active_window_id == 77
|
||
assert base64.b64decode(cap.png_b64) # decodes cleanly
|