mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-18 04:41:56 +00:00
fix(install): skip browser download when system chromium exists
This commit is contained in:
parent
7f08cb5941
commit
52521c937a
4 changed files with 173 additions and 54 deletions
|
|
@ -64,6 +64,7 @@ NODE_VERSION="22"
|
|||
# data still at /root/.hermes (HERMES_HOME). Matches Claude Code / Codex CLI
|
||||
# and keeps Docker bind-mounted /root/ volumes lean.
|
||||
ROOT_FHS_LAYOUT=false
|
||||
DETECTED_BROWSER_EXECUTABLE=""
|
||||
|
||||
# Options
|
||||
USE_VENV=true
|
||||
|
|
@ -1421,6 +1422,7 @@ copy_config_templates() {
|
|||
else
|
||||
log_info "~/.hermes/.env already exists, keeping it"
|
||||
fi
|
||||
configure_browser_env_from_system_browser
|
||||
|
||||
# Create config.yaml at ~/.hermes/config.yaml (top level, easy to find)
|
||||
if [ ! -f "$HERMES_HOME/config.yaml" ]; then
|
||||
|
|
@ -1469,6 +1471,68 @@ SOUL_EOF
|
|||
fi
|
||||
}
|
||||
|
||||
find_system_browser() {
|
||||
# Prefer a user-specified browser path, then common Linux/macOS Chrome and
|
||||
# Chromium command names. Arch-family distributions commonly ship plain
|
||||
# `chromium`, while Debian-family systems often use `chromium-browser`.
|
||||
if [ -n "${AGENT_BROWSER_EXECUTABLE_PATH:-}" ]; then
|
||||
if [ -x "$AGENT_BROWSER_EXECUTABLE_PATH" ]; then
|
||||
echo "$AGENT_BROWSER_EXECUTABLE_PATH"
|
||||
return 0
|
||||
fi
|
||||
if command -v "$AGENT_BROWSER_EXECUTABLE_PATH" >/dev/null 2>&1; then
|
||||
command -v "$AGENT_BROWSER_EXECUTABLE_PATH"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
local candidate
|
||||
for candidate in google-chrome google-chrome-stable chromium chromium-browser chrome; do
|
||||
if command -v "$candidate" >/dev/null 2>&1; then
|
||||
command -v "$candidate"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
run_browser_install_with_timeout() {
|
||||
local timeout_seconds="$1"
|
||||
shift
|
||||
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout "$timeout_seconds" "$@"
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
configure_browser_env_from_system_browser() {
|
||||
local env_file="$HERMES_HOME/.env"
|
||||
local browser_path="${DETECTED_BROWSER_EXECUTABLE:-}"
|
||||
|
||||
if [ -z "$browser_path" ]; then
|
||||
browser_path="$(find_system_browser 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
if [ -z "$browser_path" ] || [ ! -f "$env_file" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if grep -q '^AGENT_BROWSER_EXECUTABLE_PATH=' "$env_file" 2>/dev/null; then
|
||||
log_info "AGENT_BROWSER_EXECUTABLE_PATH already configured"
|
||||
return 0
|
||||
fi
|
||||
|
||||
{
|
||||
echo ""
|
||||
echo "# Hermes Agent browser tools — use the system Chrome/Chromium binary."
|
||||
echo "AGENT_BROWSER_EXECUTABLE_PATH=$browser_path"
|
||||
} >> "$env_file"
|
||||
log_success "Configured browser tools to use $browser_path"
|
||||
}
|
||||
|
||||
install_node_deps() {
|
||||
if [ "$HAS_NODE" = false ]; then
|
||||
log_info "Skipping Node.js dependencies (Node not installed)"
|
||||
|
|
@ -1495,57 +1559,63 @@ install_node_deps() {
|
|||
# For Arch/Manjaro we install the system libs via pacman first.
|
||||
# Other systems must install Chromium dependencies manually.
|
||||
log_info "Installing browser engine (Playwright Chromium)..."
|
||||
case "$DISTRO" in
|
||||
ubuntu|debian|raspbian|pop|linuxmint|elementary|zorin|kali|parrot)
|
||||
log_info "Playwright may request sudo to install browser system dependencies (shared libraries)."
|
||||
log_info "This is standard Playwright setup — Hermes itself does not require root access."
|
||||
cd "$INSTALL_DIR" && npx playwright install --with-deps chromium 2>/dev/null || {
|
||||
log_warn "Playwright browser installation failed — browser tools will not work."
|
||||
log_warn "Try running manually: cd $INSTALL_DIR && npx playwright install --with-deps chromium"
|
||||
}
|
||||
;;
|
||||
arch|manjaro)
|
||||
if command -v pacman &> /dev/null; then
|
||||
log_info "Arch/Manjaro detected — installing Chromium system dependencies via pacman..."
|
||||
if command -v sudo &> /dev/null && sudo -n true 2>/dev/null; then
|
||||
sudo NEEDRESTART_MODE=a pacman -S --noconfirm --needed \
|
||||
nss atk at-spi2-core cups libdrm libxkbcommon mesa pango cairo alsa-lib >/dev/null 2>&1 || true
|
||||
elif [ "$(id -u)" -eq 0 ]; then
|
||||
pacman -S --noconfirm --needed \
|
||||
nss atk at-spi2-core cups libdrm libxkbcommon mesa pango cairo alsa-lib >/dev/null 2>&1 || true
|
||||
else
|
||||
log_warn "Cannot install browser deps without sudo. Run manually:"
|
||||
log_warn " sudo pacman -S nss atk at-spi2-core cups libdrm libxkbcommon mesa pango cairo alsa-lib"
|
||||
DETECTED_BROWSER_EXECUTABLE="$(find_system_browser 2>/dev/null || true)"
|
||||
if [ -n "$DETECTED_BROWSER_EXECUTABLE" ]; then
|
||||
log_success "Found system Chrome/Chromium at $DETECTED_BROWSER_EXECUTABLE"
|
||||
log_info "Skipping Playwright browser download; Hermes will use the system browser."
|
||||
else
|
||||
case "$DISTRO" in
|
||||
ubuntu|debian|raspbian|pop|linuxmint|elementary|zorin|kali|parrot)
|
||||
log_info "Playwright may request sudo to install browser system dependencies (shared libraries)."
|
||||
log_info "This is standard Playwright setup — Hermes itself does not require root access."
|
||||
cd "$INSTALL_DIR" && run_browser_install_with_timeout 600 npx playwright install --with-deps chromium 2>/dev/null || {
|
||||
log_warn "Playwright browser installation failed — browser tools will not work."
|
||||
log_warn "Try running manually: cd $INSTALL_DIR && npx playwright install --with-deps chromium"
|
||||
}
|
||||
;;
|
||||
arch|manjaro|cachyos|endeavouros|garuda)
|
||||
if command -v pacman &> /dev/null; then
|
||||
log_info "Arch-family distro detected — installing Chromium system dependencies via pacman..."
|
||||
if command -v sudo &> /dev/null && sudo -n true 2>/dev/null; then
|
||||
sudo NEEDRESTART_MODE=a pacman -S --noconfirm --needed \
|
||||
nss atk at-spi2-core cups libdrm libxkbcommon mesa pango cairo alsa-lib >/dev/null 2>&1 || true
|
||||
elif [ "$(id -u)" -eq 0 ]; then
|
||||
pacman -S --noconfirm --needed \
|
||||
nss atk at-spi2-core cups libdrm libxkbcommon mesa pango cairo alsa-lib >/dev/null 2>&1 || true
|
||||
else
|
||||
log_warn "Cannot install browser deps without sudo. Run manually:"
|
||||
log_warn " sudo pacman -S nss atk at-spi2-core cups libdrm libxkbcommon mesa pango cairo alsa-lib"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
cd "$INSTALL_DIR" && npx playwright install chromium 2>/dev/null || {
|
||||
log_warn "Playwright browser installation failed — browser tools will not work."
|
||||
}
|
||||
;;
|
||||
fedora|rhel|centos|rocky|alma)
|
||||
log_warn "Playwright does not support automatic dependency installation on RPM-based systems."
|
||||
log_info "Install Chromium system dependencies manually before using browser tools:"
|
||||
log_info " sudo dnf install nss atk at-spi2-core cups-libs libdrm libxkbcommon mesa-libgbm pango cairo alsa-lib"
|
||||
cd "$INSTALL_DIR" && npx playwright install chromium 2>/dev/null || {
|
||||
log_warn "Playwright browser installation failed — install dependencies above and retry."
|
||||
}
|
||||
;;
|
||||
opensuse*|sles)
|
||||
log_warn "Playwright does not support automatic dependency installation on zypper-based systems."
|
||||
log_info "Install Chromium system dependencies manually before using browser tools:"
|
||||
log_info " sudo zypper install mozilla-nss libatk-1_0-0 at-spi2-core cups-libs libdrm2 libxkbcommon0 Mesa-libgbm1 pango cairo libasound2"
|
||||
cd "$INSTALL_DIR" && npx playwright install chromium 2>/dev/null || {
|
||||
log_warn "Playwright browser installation failed — install dependencies above and retry."
|
||||
}
|
||||
;;
|
||||
*)
|
||||
log_warn "Playwright does not support automatic dependency installation on $DISTRO."
|
||||
log_info "Install Chromium/browser system dependencies for your distribution, then run:"
|
||||
log_info " cd $INSTALL_DIR && npx playwright install chromium"
|
||||
log_info "Browser tools will not work until dependencies are installed."
|
||||
cd "$INSTALL_DIR" && npx playwright install chromium 2>/dev/null || true
|
||||
;;
|
||||
esac
|
||||
cd "$INSTALL_DIR" && run_browser_install_with_timeout 600 npx playwright install chromium 2>/dev/null || {
|
||||
log_warn "Playwright browser installation failed — browser tools will not work."
|
||||
}
|
||||
;;
|
||||
fedora|rhel|centos|rocky|alma)
|
||||
log_warn "Playwright does not support automatic dependency installation on RPM-based systems."
|
||||
log_info "Install Chromium system dependencies manually before using browser tools:"
|
||||
log_info " sudo dnf install nss atk at-spi2-core cups-libs libdrm libxkbcommon mesa-libgbm pango cairo alsa-lib"
|
||||
cd "$INSTALL_DIR" && run_browser_install_with_timeout 600 npx playwright install chromium 2>/dev/null || {
|
||||
log_warn "Playwright browser installation failed — install dependencies above and retry."
|
||||
}
|
||||
;;
|
||||
opensuse*|sles)
|
||||
log_warn "Playwright does not support automatic dependency installation on zypper-based systems."
|
||||
log_info "Install Chromium system dependencies manually before using browser tools:"
|
||||
log_info " sudo zypper install mozilla-nss libatk-1_0-0 at-spi2-core cups-libs libdrm2 libxkbcommon0 Mesa-libgbm1 pango cairo libasound2"
|
||||
cd "$INSTALL_DIR" && run_browser_install_with_timeout 600 npx playwright install chromium 2>/dev/null || {
|
||||
log_warn "Playwright browser installation failed — install dependencies above and retry."
|
||||
}
|
||||
;;
|
||||
*)
|
||||
log_warn "Playwright does not support automatic dependency installation on $DISTRO."
|
||||
log_info "Install Chromium/browser system dependencies for your distribution, then run:"
|
||||
log_info " cd $INSTALL_DIR && npx playwright install chromium"
|
||||
log_info "Browser tools will not work until dependencies are installed."
|
||||
cd "$INSTALL_DIR" && run_browser_install_with_timeout 600 npx playwright install chromium 2>/dev/null || true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
log_success "Browser engine setup complete"
|
||||
fi
|
||||
|
||||
|
|
|
|||
35
tests/test_install_sh_browser_install.py
Normal file
35
tests/test_install_sh_browser_install.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
"""Regression tests for install.sh browser setup.
|
||||
|
||||
Browser automation is optional. The installer should not leave Hermes
|
||||
half-installed just because Playwright's managed Chromium download hangs on an
|
||||
unsupported distribution.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
INSTALL_SH = REPO_ROOT / "scripts" / "install.sh"
|
||||
|
||||
|
||||
def test_install_script_skips_playwright_download_when_system_browser_exists() -> None:
|
||||
text = INSTALL_SH.read_text()
|
||||
|
||||
assert "find_system_browser()" in text
|
||||
assert "google-chrome google-chrome-stable chromium chromium-browser chrome" in text
|
||||
assert "Skipping Playwright browser download; Hermes will use the system browser." in text
|
||||
|
||||
|
||||
def test_install_script_persists_system_browser_for_agent_browser() -> None:
|
||||
text = INSTALL_SH.read_text()
|
||||
|
||||
assert "configure_browser_env_from_system_browser()" in text
|
||||
assert "AGENT_BROWSER_EXECUTABLE_PATH=$browser_path" in text
|
||||
|
||||
|
||||
def test_playwright_installs_are_timeout_guarded() -> None:
|
||||
text = INSTALL_SH.read_text()
|
||||
|
||||
assert "run_browser_install_with_timeout()" in text
|
||||
assert "run_browser_install_with_timeout 600 npx playwright install chromium" in text
|
||||
assert "run_browser_install_with_timeout 600 npx playwright install --with-deps chromium" in text
|
||||
|
|
@ -41,6 +41,16 @@ class TestChromiumSearchRoots:
|
|||
|
||||
|
||||
class TestChromiumInstalled:
|
||||
def test_true_when_plain_chromium_on_path(self, monkeypatch):
|
||||
monkeypatch.delenv("AGENT_BROWSER_EXECUTABLE_PATH", raising=False)
|
||||
monkeypatch.setattr(
|
||||
bt.shutil,
|
||||
"which",
|
||||
lambda name: "/usr/bin/chromium" if name == "chromium" else None,
|
||||
)
|
||||
|
||||
assert bt._chromium_installed() is True
|
||||
|
||||
def test_true_when_chromium_dir_present(self, monkeypatch, tmp_path):
|
||||
monkeypatch.setenv("PLAYWRIGHT_BROWSERS_PATH", str(tmp_path))
|
||||
(tmp_path / "chromium-1208").mkdir()
|
||||
|
|
@ -108,4 +118,3 @@ class TestRunBrowserCommandChromiumGuard:
|
|||
"""
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3381,8 +3381,8 @@ def _chromium_installed() -> bool:
|
|||
|
||||
1. ``AGENT_BROWSER_EXECUTABLE_PATH`` env var — the official way to point
|
||||
agent-browser at a pre-installed Chrome/Chromium.
|
||||
2. System Chrome/Chromium in PATH (``google-chrome``, ``chromium-browser``,
|
||||
``chrome``).
|
||||
2. System Chrome/Chromium in PATH (``google-chrome``, ``chromium``,
|
||||
``chromium-browser``, ``chrome``).
|
||||
3. Playwright's browser cache (current logic) — directories containing
|
||||
``chromium-*`` or ``chromium_headless_shell-*``.
|
||||
|
||||
|
|
@ -3405,7 +3405,12 @@ def _chromium_installed() -> bool:
|
|||
return True
|
||||
|
||||
# 2. System Chrome/Chromium in PATH (common names)
|
||||
system_chrome = shutil.which("google-chrome") or shutil.which("chromium-browser") or shutil.which("chrome")
|
||||
system_chrome = (
|
||||
shutil.which("google-chrome")
|
||||
or shutil.which("chromium")
|
||||
or shutil.which("chromium-browser")
|
||||
or shutil.which("chrome")
|
||||
)
|
||||
if system_chrome:
|
||||
_cached_chromium_installed = True
|
||||
return True
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue