mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-29 06:31:32 +00:00
fix(computer-use): add set_value to ComputerUseBackend ABC and _NoopBackend stub
_dispatch() routes action="set_value" to backend.set_value(), but: - ComputerUseBackend did not declare set_value as @abstractmethod, so subclasses could silently omit it without a TypeError at class load time. - _NoopBackend (the test/CI stub) had no set_value method at all, causing AttributeError in any test that exercises the set_value action path. Fix: - Add set_value as @abstractmethod to ComputerUseBackend in backend.py. - Add a recording stub in _NoopBackend in tool.py. - Add two TestDispatch cases: one verifying the call reaches the backend, one verifying the missing-value guard returns a clean error.
This commit is contained in:
parent
d3f62c6913
commit
c52cd48e25
3 changed files with 27 additions and 0 deletions
|
|
@ -226,6 +226,21 @@ class TestDispatch:
|
|||
parsed = json.loads(out)
|
||||
assert "error" in parsed
|
||||
|
||||
def test_set_value_routes_to_backend(self, noop_backend):
|
||||
"""set_value must reach the backend — regression for missing _NoopBackend stub."""
|
||||
from tools.computer_use.tool import handle_computer_use
|
||||
out = handle_computer_use({"action": "set_value", "value": "Option A", "element": 5})
|
||||
parsed = json.loads(out)
|
||||
assert parsed.get("ok") is True
|
||||
assert parsed.get("action") == "set_value"
|
||||
assert any(c[0] == "set_value" for c in noop_backend.calls)
|
||||
|
||||
def test_set_value_missing_value_returns_error(self, noop_backend):
|
||||
from tools.computer_use.tool import handle_computer_use
|
||||
out = handle_computer_use({"action": "set_value"})
|
||||
parsed = json.loads(out)
|
||||
assert "error" in parsed
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Safety guards (type / key block lists)
|
||||
|
|
|
|||
|
|
@ -142,6 +142,14 @@ class ComputerUseBackend(ABC):
|
|||
def focus_app(self, app: str, raise_window: bool = False) -> ActionResult:
|
||||
"""Route input to `app` (by name or bundle ID). Default: focus without raise."""
|
||||
|
||||
# ── Native-value mutation ────────────────────────────────────────
|
||||
@abstractmethod
|
||||
def set_value(self, value: str, element: Optional[int] = None) -> ActionResult:
|
||||
"""Set a native value on an element (e.g. AXPopUpButton selection).
|
||||
|
||||
`element` is the 1-based SOM index returned by a prior capture call.
|
||||
"""
|
||||
|
||||
# ── Timing ──────────────────────────────────────────────────────
|
||||
def wait(self, seconds: float) -> ActionResult:
|
||||
"""Default implementation: time.sleep."""
|
||||
|
|
|
|||
|
|
@ -200,6 +200,10 @@ class _NoopBackend(ComputerUseBackend): # pragma: no cover
|
|||
self.calls.append(("focus_app", {"app": app, "raise": raise_window}))
|
||||
return ActionResult(ok=True, action="focus_app")
|
||||
|
||||
def set_value(self, value: str, element: Optional[int] = None) -> ActionResult:
|
||||
self.calls.append(("set_value", {"value": value, "element": element}))
|
||||
return ActionResult(ok=True, action="set_value")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Dispatch
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue