Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions tests/tools/test_computer_use.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,21 @@ def test_right_click_sets_button(self, noop_backend):
click_kw = next(c[1] for c in noop_backend.calls if c[0] == "click")
assert click_kw["button"] == "right"

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)
Expand Down
8 changes: 8 additions & 0 deletions tools/computer_use/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ def list_apps(self) -> List[Dict[str, Any]]:
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."""
Expand Down
4 changes: 4 additions & 0 deletions tools/computer_use/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ def focus_app(self, app: str, raise_window: bool = False) -> ActionResult:
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
Expand Down