mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-31 00:03:01 +03:00
fix(cli): foreground the WebUI browser
This commit is contained in:
@@ -23,6 +23,7 @@ from nanobot.cli.webui_support import (
|
||||
_gateway_health_bind_note,
|
||||
_gateway_health_url,
|
||||
_host_for_local_browser,
|
||||
_launch_browser,
|
||||
_prepare_webui_bundle_for_gateway,
|
||||
_print_foreground_port_conflict,
|
||||
_tcp_endpoint_reachable,
|
||||
@@ -864,7 +865,6 @@ def _run_gateway(
|
||||
"""Wait for the gateway to bind, then point the user's browser at the webui."""
|
||||
if not open_browser_url:
|
||||
return
|
||||
import webbrowser
|
||||
from urllib.parse import urlparse
|
||||
|
||||
# Channels start asynchronously. When the caller supplies a backend
|
||||
@@ -896,8 +896,10 @@ def _run_gateway(
|
||||
await asyncio.sleep(0.1)
|
||||
display_url = _webui_display_url(open_browser_url)
|
||||
try:
|
||||
webbrowser.open(open_browser_url)
|
||||
console.print(f"[green]✓[/green] Opened browser at {display_url}")
|
||||
if _launch_browser(open_browser_url):
|
||||
console.print(f"[green]✓[/green] Opened browser at {display_url}")
|
||||
else:
|
||||
console.print(f"[yellow]Could not open browser; visit {display_url}[/yellow]")
|
||||
except Exception as e:
|
||||
console.print(f"[yellow]Could not open browser ({e}); visit {display_url}[/yellow]")
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
"""Shared WebUI setup, URL, health, and browser helpers."""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import webbrowser
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any
|
||||
@@ -40,6 +42,7 @@ __all__ = [
|
||||
"_gateway_instance_command",
|
||||
"_host_for_local_browser",
|
||||
"_load_webui_setup_config",
|
||||
"_launch_browser",
|
||||
"_open_webui_browser",
|
||||
"_prepare_webui_bundle_for_gateway",
|
||||
"_print_foreground_port_conflict",
|
||||
@@ -60,6 +63,20 @@ __all__ = [
|
||||
console = Console()
|
||||
|
||||
|
||||
def _launch_browser(url: str) -> bool:
|
||||
"""Open *url* and request a foreground browser window."""
|
||||
if sys.platform == "darwin":
|
||||
result = subprocess.run(
|
||||
["open", url],
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
check=False,
|
||||
)
|
||||
return result.returncode == 0
|
||||
return bool(webbrowser.open(url, new=2, autoraise=True))
|
||||
|
||||
|
||||
def _confirm_webui_action(message: str, *, yes: bool) -> None:
|
||||
"""Confirm a WebUI first-run mutation or fail clearly in non-interactive shells."""
|
||||
if yes:
|
||||
@@ -419,14 +436,14 @@ def _print_foreground_port_conflict(
|
||||
|
||||
def _open_webui_browser(url: str, *, wait: bool = True) -> None:
|
||||
"""Open the WebUI in the user's default browser, with a copyable fallback."""
|
||||
import webbrowser
|
||||
|
||||
if wait:
|
||||
_wait_for_webui(url)
|
||||
display_url = _webui_display_url(url)
|
||||
try:
|
||||
webbrowser.open(url)
|
||||
console.print(f"[green]✓[/green] Opened WebUI: [cyan]{display_url}[/cyan]")
|
||||
if _launch_browser(url):
|
||||
console.print(f"[green]✓[/green] Opened WebUI: [cyan]{display_url}[/cyan]")
|
||||
else:
|
||||
console.print(f"[yellow]Could not open browser; visit {display_url}[/yellow]")
|
||||
except Exception as exc:
|
||||
console.print(f"[yellow]Could not open browser ({exc}); visit {display_url}[/yellow]")
|
||||
|
||||
|
||||
@@ -2534,7 +2534,11 @@ def test_webui_yes_still_refuses_invalid_custom_model_setup(
|
||||
def test_open_webui_browser_redacts_bootstrap_secret(monkeypatch, capsys) -> None:
|
||||
opened: list[str] = []
|
||||
url = "http://127.0.0.1:8765/#/?bootstrapSecret=super-secret"
|
||||
monkeypatch.setattr("webbrowser.open", lambda value: opened.append(value))
|
||||
monkeypatch.setattr(
|
||||
cli_webui_support,
|
||||
"_launch_browser",
|
||||
lambda value: opened.append(value) or True,
|
||||
)
|
||||
|
||||
cli_webui_support._open_webui_browser(url, wait=False)
|
||||
|
||||
@@ -2544,6 +2548,42 @@ def test_open_webui_browser_redacts_bootstrap_secret(monkeypatch, capsys) -> Non
|
||||
assert "super-secret" not in output
|
||||
|
||||
|
||||
def test_open_webui_browser_reports_launch_failure(monkeypatch, capsys) -> None:
|
||||
monkeypatch.setattr(cli_webui_support, "_launch_browser", lambda _value: False)
|
||||
|
||||
cli_webui_support._open_webui_browser("http://127.0.0.1:8765/", wait=False)
|
||||
|
||||
assert "Could not open browser; visit http://127.0.0.1:8765/" in _strip_ansi(
|
||||
capsys.readouterr().out
|
||||
)
|
||||
|
||||
|
||||
def test_launch_browser_uses_macos_foreground_opener(monkeypatch) -> None:
|
||||
seen: list[list[str]] = []
|
||||
monkeypatch.setattr(cli_webui_support.sys, "platform", "darwin")
|
||||
monkeypatch.setattr(
|
||||
cli_webui_support.subprocess,
|
||||
"run",
|
||||
lambda command, **_kwargs: seen.append(command) or SimpleNamespace(returncode=0),
|
||||
)
|
||||
|
||||
assert cli_webui_support._launch_browser("http://127.0.0.1:8765/") is True
|
||||
assert seen == [["open", "http://127.0.0.1:8765/"]]
|
||||
|
||||
|
||||
def test_launch_browser_uses_default_browser_off_macos(monkeypatch) -> None:
|
||||
opened: list[tuple[str, int, bool]] = []
|
||||
monkeypatch.setattr(cli_webui_support.sys, "platform", "linux")
|
||||
monkeypatch.setattr(
|
||||
cli_webui_support.webbrowser,
|
||||
"open",
|
||||
lambda url, *, new, autoraise: opened.append((url, new, autoraise)) or True,
|
||||
)
|
||||
|
||||
assert cli_webui_support._launch_browser("http://127.0.0.1:8765/") is True
|
||||
assert opened == [("http://127.0.0.1:8765/", 2, True)]
|
||||
|
||||
|
||||
def test_webui_foreground_attaches_to_existing_managed_gateway(monkeypatch, tmp_path: Path) -> None:
|
||||
config_file = tmp_path / "config.json"
|
||||
config_file.write_text("{}")
|
||||
|
||||
Reference in New Issue
Block a user