From 3e33e14335ef3f5fd07bc3dcfb2c74f045d49988 Mon Sep 17 00:00:00 2001 From: Ben Date: Wed, 27 May 2026 20:27:45 +1000 Subject: [PATCH] fix(docker): discover agent-browser Chromium binary at boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The image's Dockerfile runs npx playwright install chromium, which populates $PLAYWRIGHT_BROWSERS_PATH (=/opt/hermes/.playwright) with a `chromium_headless_shell-/chrome-headless-shell-linux64/` tree. agent-browser (the runtime CLI Hermes spawns for the browser tool) doesn't recognise this layout in its own cache scan and fails with `Auto-launch failed: Chrome not found` — even though the binary is right there. Reproduction on current main: $ docker run --rm sh -c 'npx -y agent-browser snapshot --url about:blank' ✗ Auto-launch failed: Chrome not found. Checked: - agent-browser cache: /tmp/.../.agent-browser/browsers - System Chrome installations - Puppeteer browser cache - Playwright browser cache Run `agent-browser install` to download Chrome, or use --executable-path. Fix: at boot, locate the binary under $PLAYWRIGHT_BROWSERS_PATH and export AGENT_BROWSER_EXECUTABLE_PATH via /run/s6/container_environment so the with-contenv shebang on main-wrapper.sh propagates it into the supervised `hermes` process and thence to agent-browser subprocesses. Filename-matched (chrome / chromium / chrome-headless-shell / chromium-browser), not path-matched: the chromium dir contains many shared libraries (libGLESv2.so, libEGL.so, ...) which inherit the executable bit from Playwright's tarball but are NOT browser binaries. Compare PR #18635's earlier `find | grep -Ei 'chrome|chromium'` which would match the path .../chrome-headless-shell-linux64/libGLESv2.so and pick a .so as the browser binary. User overrides (e.g. `-e AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/...`) are respected — the discovery block is skipped when the env var is already set. Quietly skipped when $PLAYWRIGHT_BROWSERS_PATH doesn't exist (e.g. custom builds that strip Playwright). This salvages PR #18635 by @jackey8616, who identified the bug and proposed the same env-var approach but in the now-deprecated docker/entrypoint.sh shim and with a path-match find command that selected .so files instead of the chrome binary. The fix retargets docker/stage2-hook.sh (the s6-overlay cont-init script where boot-time env setup belongs) with a corrected filename-match query. Fixes #15697 Closes #18635 Co-authored-by: Clooooode <12930377+jackey8616@users.noreply.github.com> --- docker/stage2-hook.sh | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/docker/stage2-hook.sh b/docker/stage2-hook.sh index 1c41c6967ac..1e8af197de9 100755 --- a/docker/stage2-hook.sh +++ b/docker/stage2-hook.sh @@ -188,4 +188,47 @@ if [ -d "$INSTALL_DIR/skills" ]; then || echo "[stage2] Warning: skills_sync.py failed; continuing" fi +# --- Discover agent-browser's Chromium binary --- +# The image's Dockerfile runs `npx playwright install chromium`, which +# populates ``$PLAYWRIGHT_BROWSERS_PATH`` (=/opt/hermes/.playwright) with +# a ``chromium_headless_shell-/chrome-headless-shell-linux64/`` +# directory. agent-browser (the runtime CLI Hermes spawns for the +# browser tool) doesn't recognise this layout in its own cache scan and +# fails with "Auto-launch failed: Chrome not found" — even though the +# binary is right there (#15697). +# +# Fix: locate the binary at boot and export ``AGENT_BROWSER_EXECUTABLE_PATH`` +# via /run/s6/container_environment so the `with-contenv` shebang on +# main-wrapper.sh propagates it into the supervised ``hermes`` process +# and thence to agent-browser subprocesses. +# +# - Skipped when the user has already set ``AGENT_BROWSER_EXECUTABLE_PATH`` +# (lets users override with a system Chrome install). +# - Filename-matched (not path-matched): the chromium dir contains many +# shared libraries (libGLESv2.so, libEGL.so, ...) which inherit the +# executable bit from Playwright's tarball but are NOT browser binaries. +# We only accept files whose basename is chrome / chromium / +# chrome-headless-shell / chromium-browser. Compare PR #18635's earlier +# ``find | grep -Ei 'chrome|chromium'`` which would match the path +# ``.../chrome-headless-shell-linux64/libGLESv2.so`` and pick a .so. +# - Quietly skipped when $PLAYWRIGHT_BROWSERS_PATH doesn't exist (e.g. +# custom builds that strip Playwright). +if [ -z "${AGENT_BROWSER_EXECUTABLE_PATH:-}" ] && \ + [ -n "${PLAYWRIGHT_BROWSERS_PATH:-}" ] && \ + [ -d "$PLAYWRIGHT_BROWSERS_PATH" ]; then + browser_bin=$(find "$PLAYWRIGHT_BROWSERS_PATH" -type f -executable \ + \( -name 'chrome' -o -name 'chromium' \ + -o -name 'chrome-headless-shell' -o -name 'chromium-browser' \) \ + 2>/dev/null | head -n 1) + if [ -n "$browser_bin" ]; then + echo "[stage2] Found agent-browser Chromium binary: $browser_bin" + # Write to s6's container_environment so with-contenv picks it + # up for all supervised services (main-hermes, dashboard, etc.). + # Idempotent: each boot overwrites with the current path. + printf '%s' "$browser_bin" > /run/s6/container_environment/AGENT_BROWSER_EXECUTABLE_PATH + else + echo "[stage2] Warning: no Chromium binary under $PLAYWRIGHT_BROWSERS_PATH; browser tool may fail" + fi +fi + echo "[stage2] Setup complete; starting user services"