diff --git a/hermes_cli/config.py b/hermes_cli/config.py index 685de3d7341f..b74e84cc9e9d 100644 --- a/hermes_cli/config.py +++ b/hermes_cli/config.py @@ -614,6 +614,10 @@ def _ensure_hermes_home_managed(home: Path): "command_timeout": 30, # Timeout for browser commands in seconds (screenshot, navigate, etc.) "record_sessions": False, # Auto-record browser sessions as WebM videos "allow_private_urls": False, # Allow navigating to private/internal IPs (localhost, 192.168.x.x, etc.) + # Run browser in headed mode (visible window). When disabled, + # the browser runs headless (no visible window). + # This directly sets AGENT_BROWSER_HEADED env var. + "headed": False, # Browser engine for local mode. Passed as ``--engine `` to # agent-browser v0.25.3+. # "auto" — use Chrome (default, don't pass --engine at all) diff --git a/hermes_cli/web_server.py b/hermes_cli/web_server.py index bdb24554f87b..0f8eb4ae6e50 100644 --- a/hermes_cli/web_server.py +++ b/hermes_cli/web_server.py @@ -344,6 +344,10 @@ async def auth_middleware(request: Request, call_next): "description": "Reasoning effort for delegated subagents", "options": ["", "low", "medium", "high"], }, + "browser.headed": { + "type": "boolean", + "description": "Run browser in headed mode (visible window). Enable to show a visible browser window via AGENT_BROWSER_HEADED.", + }, } # Categories with fewer fields get merged into "general" to avoid tab sprawl. diff --git a/tools/browser_tool.py b/tools/browser_tool.py index 79a6c7e61721..e45e6a817252 100644 --- a/tools/browser_tool.py +++ b/tools/browser_tool.py @@ -1859,6 +1859,17 @@ def _run_browser_command( browser_env["PATH"] = _merge_browser_path(browser_env.get("PATH", "")) browser_env["AGENT_BROWSER_SOCKET_DIR"] = task_socket_dir + # Honor browser.headed config — when enabled, show a visible + # browser window so the user can watch what the agent is doing. + if not session_info.get("cdp_url") and not _is_camofox_mode(): + try: + from hermes_cli.config import read_raw_config + _cfg = read_raw_config() + if _cfg.get("browser", {}).get("headed", False): + browser_env["AGENT_BROWSER_HEADED"] = "true" + except Exception: + pass + # Tell the agent-browser daemon to self-terminate after being idle # for our configured inactivity timeout. This is the daemon-side # counterpart to our Python-side _cleanup_inactive_browser_sessions