Files
hermes-agent/tests/tools/test_computer_use_native_platform.py
Teknium 63f5e0ea45 feat(computer-use): pluggable single-select computer-use providers
Third-party drivers (e.g. a Codex-style computer-use reimplementation) could
only replace cua-driver by patching core. computer_use now follows the
single-select provider model Hermes uses for memory providers, context
engines and cron schedulers:

- plugins/computer_use/__init__.py discovers bundled
  plugins/computer_use/<name>/ then user $HERMES_HOME/plugins/<name>/
  (marker: register_computer_use_provider / ComputerUseProvider) and loads
  ONLY the provider computer_use.backend names (default "cua"), read per
  call so each profile gets its own. Unselected providers are never
  imported; listing reads plugin.yaml only. An unknown/unloadable name
  returns an error naming it and the installed providers; no fallback.
- The built-in cua-driver is an ordinary bundled provider at
  plugins/computer_use/cua/ (driver implementation stays in
  tools/computer_use). tools/computer_use/backend.py gains
  ComputerUseProvider (create_backend(permission_mode=...), is_available(),
  optional doctor()).
- The tool's check_fn and backend construction go through the selected
  provider; the model-facing schema is unchanged for every provider
  (prompt-cache invariant). The test-only HERMES_COMPUTER_USE_BACKEND env
  switch is gone (tests patch _new_backend).
- General plugin discovery treats computer-use providers as exclusive
  (not eagerly imported, not listed as toggleable) and skips the bundled
  computer_use/ category, same as memory/, context_engine/, cron_providers/.
- hermes tools and the Desktop toolset panel list installed providers next
  to cua; computer-use doctor/status/permissions and the Desktop status
  payload skip cua-driver/TCC probes when another provider is selected.
2026-10-05 17:20:30 -07:00

42 lines
1.5 KiB
Python

"""Exercise existing computer-use actions on the actual Windows/macOS CI hosts."""
import json
import sys
import pytest
from tools.computer_use import tool
@pytest.fixture
def backend(monkeypatch):
tool.reset_backend_for_tests()
monkeypatch.setattr(tool, "_new_backend", lambda mode: tool._NoopBackend())
# Input actions are approval-gated; a CI runner has no approver, so the gate would block
# before the dispatch this test is about. Same seam the capture-fence tests use.
monkeypatch.setattr(tool, "_request_approval", lambda *a, **k: None)
value = tool._get_backend()
yield value
tool.reset_backend_for_tests()
@pytest.mark.parametrize("host_platform", [
pytest.param("win32", marks=pytest.mark.platforms("windows")),
pytest.param("darwin", marks=pytest.mark.platforms("macos")),
])
@pytest.mark.parametrize("args, expected_call", [
({"action": "capture", "mode": "ax"}, "capture"),
({"action": "click", "coordinate": [10, 10]}, "click"),
({"action": "type", "text": "test input"}, "type"),
({"action": "list_windows"}, "list_windows"),
])
def test_native_computer_use_dispatches_to_backend(backend, args, expected_call, host_platform):
import tools.computer_use_tool # noqa: F401 - register the real tool handler
from tools.registry import registry
assert sys.platform == host_platform
result = registry.dispatch("computer_use", args)
assert "error" not in json.loads(result)
assert [name for name, _ in backend.calls] == [expected_call]