refactor(cli): route /browser subcommands through a dispatch table (#116914)

The 5-branch if/elif ladder in CLICommandsMixin._handle_browser_command
becomes a _BROWSER_SUBCOMMANDS word -> handler table; adding a subcommand
is one row plus a usage line. Subcommand word is case-insensitive, the
argument keeps its case (CDP URL paths are case-sensitive).
This commit is contained in:
teknium1
2026-09-20 14:35:41 -07:00
committed by Teknium
parent 2a00b06212
commit fafa2e215c
2 changed files with 53 additions and 12 deletions

View File

@@ -606,6 +606,16 @@ def _browser_status() -> None:
" /browser disconnect — revert to default")
# /browser subcommand word → handler(cli, rest); ``rest`` is the raw (case-preserved)
# remainder of the line. Adding a subcommand is one row here plus a usage line.
_BROWSER_SUBCOMMANDS = {
"use": lambda cli, rest: _browser_use(cli, rest.lower() or "on"),
"connect": lambda cli, rest: _browser_connect(cli, rest or DEFAULT_BROWSER_CDP_URL),
"disconnect": lambda cli, rest: _browser_disconnect(cli),
"status": lambda cli, rest: _browser_status(),
}
class CLICommandsMixin:
"""Mixin holding the interactive-CLI slash-command handlers."""
@@ -2150,24 +2160,21 @@ class CLICommandsMixin:
def _handle_browser_command(self, cmd: str):
"""Handle /browser connect|disconnect|status|use — manage the live Chromium-family CDP connection."""
sub = _command_arg(cmd).lower() or "status"
if sub == "use" or sub.startswith("use "):
_browser_use(self, sub.split(None, 1)[1].strip() if " " in sub else "on")
elif sub.startswith("connect"):
connect_parts = cmd.strip().split(None, 2) # ["/browser", "connect", "ws://..."]
url = connect_parts[2].strip() if len(connect_parts) > 2 else DEFAULT_BROWSER_CDP_URL
_browser_connect(self, url)
elif sub == "disconnect":
_browser_disconnect(self)
elif sub == "status":
_browser_status()
else:
# The subcommand word is matched case-insensitively; the raw argument keeps
# its case because a CDP URL's path segment is case-sensitive.
parts = _command_arg(cmd).split(None, 1)
word = parts[0].lower() if parts else "status"
rest = parts[1].strip() if len(parts) > 1 else ""
handler = _BROWSER_SUBCOMMANDS.get(word)
if handler is None:
_say_block(
"Usage: /browser connect|disconnect|status|use", "",
" connect Connect browser tools to your live Chromium-family browser session",
" disconnect Revert to default browser backend",
" status Show current browser mode",
" use [off] Switch to Browser Use mode (CLI 3.0) / back to built-in tools")
return
handler(self, rest.strip())
# ---- /heartbeat, /refine, /review -----------------------------------------------------
def _session_manager(self, getter, label: str):

View File

@@ -814,6 +814,40 @@ class TestBrowserUseSlashCommand:
assert stub.session_resets == 0
class TestBrowserSlashDispatch:
"""/browser routes through the _BROWSER_SUBCOMMANDS table: the subcommand word is
case-insensitive, the argument keeps its case (CDP URL paths are case-sensitive),
and an unknown word prints the usage block without touching any handler."""
def _run(self, cmd, monkeypatch):
import contextlib
import io
import hermes_cli.cli_commands_mixin as mod
calls = []
monkeypatch.setattr(mod, "_browser_connect", lambda cli, url: calls.append(("connect", url)))
monkeypatch.setattr(mod, "_browser_disconnect", lambda cli: calls.append(("disconnect",)))
monkeypatch.setattr(mod, "_browser_status", lambda: calls.append(("status",)))
buf = io.StringIO()
with contextlib.redirect_stdout(buf):
mod.CLICommandsMixin._handle_browser_command(object(), cmd)
return calls, buf.getvalue()
def test_connect_keeps_url_case_and_defaults_to_status(self, monkeypatch):
from hermes_cli.browser_connect import DEFAULT_BROWSER_CDP_URL
assert self._run("/browser CONNECT ws://127.0.0.1:9222/devtools/browser/AbC", monkeypatch)[0] == [
("connect", "ws://127.0.0.1:9222/devtools/browser/AbC")]
assert self._run("/browser connect", monkeypatch)[0] == [("connect", DEFAULT_BROWSER_CDP_URL)]
assert self._run("/browser", monkeypatch)[0] == [("status",)]
def test_unknown_subcommand_prints_usage_only(self, monkeypatch):
calls, out = self._run("/browser frobnicate", monkeypatch)
assert calls == []
assert "Usage: /browser connect|disconnect|status|use" in out
class TestNativeScreenshots:
"""Screenshots printed by capture_screenshot() attach directly to the
model's context when it has native vision — no aux vision-LLM detour."""