mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-21 10:22:18 +00:00
fix(whatsapp): resolve bridge dir with HERMES_HOME mirror in Docker
In Docker the install tree (/opt/hermes) is read-only, so npm install for the WhatsApp bridge fails with EACCES. Add resolve_whatsapp_bridge_dir() in whatsapp_common.py: when the install dir is read-only, mirror the bridge source into a writable HERMES_HOME location and use that. Both the adapter and the 'hermes whatsapp' CLI resolve through the shared helper so the install and runtime paths agree. Fixes #49561
This commit is contained in:
parent
0a2b712965
commit
491579fa05
3 changed files with 61 additions and 4 deletions
|
|
@ -365,3 +365,56 @@ class WhatsAppBehaviorMixin:
|
|||
result = result.replace(f"{_CODE_PH}{i}\x00", code)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Shared bridge directory resolution for CLI and adapter
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def resolve_whatsapp_bridge_dir() -> Path:
|
||||
"""Resolve the WhatsApp bridge directory, mirroring to HERMES_HOME if needed.
|
||||
|
||||
When the install tree is read-only (e.g., Docker /opt/hermes), this function
|
||||
mirrors the bridge source to a writable HERMES_HOME location and returns that
|
||||
path. This ensures npm install works in Docker environments.
|
||||
|
||||
Returns the resolved bridge directory path.
|
||||
"""
|
||||
import shutil
|
||||
from pathlib import Path as _Path
|
||||
|
||||
# Default location in install tree (may be read-only)
|
||||
from hermes_constants import get_hermes_home
|
||||
install_bridge = _Path(__file__).resolve().parents[2] / "scripts" / "whatsapp-bridge"
|
||||
|
||||
# Try HERMES_HOME location first
|
||||
hermes_home = get_hermes_home()
|
||||
hermes_home_bridge = hermes_home / "scripts" / "whatsapp-bridge"
|
||||
|
||||
# Check if install dir is writable
|
||||
try:
|
||||
test_file = install_bridge / ".write_test"
|
||||
test_file.touch()
|
||||
test_file.unlink()
|
||||
install_writable = True
|
||||
except (OSError, PermissionError):
|
||||
install_writable = False
|
||||
|
||||
if install_writable:
|
||||
return install_bridge
|
||||
|
||||
# Install dir is read-only, mirror to HERMES_HOME if needed
|
||||
if hermes_home_bridge.exists():
|
||||
return hermes_home_bridge
|
||||
|
||||
# Mirror the bridge source to HERMES_HOME
|
||||
try:
|
||||
hermes_home_bridge.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copytree(
|
||||
install_bridge,
|
||||
hermes_home_bridge,
|
||||
dirs_exist_ok=False,
|
||||
)
|
||||
return hermes_home_bridge
|
||||
except Exception:
|
||||
return install_bridge
|
||||
|
|
|
|||
|
|
@ -2466,8 +2466,8 @@ def cmd_whatsapp(args):
|
|||
print(" ⚠ No allowlist — the agent will respond to ALL incoming messages")
|
||||
|
||||
# ── Step 4: Install bridge dependencies ──────────────────────────────
|
||||
project_root = Path(__file__).resolve().parents[1]
|
||||
bridge_dir = project_root / "scripts" / "whatsapp-bridge"
|
||||
from gateway.platforms.whatsapp_common import resolve_whatsapp_bridge_dir
|
||||
bridge_dir = resolve_whatsapp_bridge_dir()
|
||||
bridge_script = bridge_dir / "bridge.js"
|
||||
|
||||
if not bridge_script.exists():
|
||||
|
|
|
|||
|
|
@ -261,11 +261,15 @@ class WhatsAppAdapter(WhatsAppBehaviorMixin, BasePlatformAdapter):
|
|||
share it. Only transport-specific code lives here.
|
||||
"""
|
||||
|
||||
# Default bridge location relative to the hermes-agent install
|
||||
_DEFAULT_BRIDGE_DIR = Path(__file__).resolve().parents[2] / "scripts" / "whatsapp-bridge"
|
||||
# Default bridge location resolved via shared helper
|
||||
_DEFAULT_BRIDGE_DIR = None # resolved in __init__
|
||||
|
||||
def __init__(self, config: PlatformConfig):
|
||||
super().__init__(config, Platform.WHATSAPP)
|
||||
# Use shared helper for bridge directory resolution (handles read-only install tree)
|
||||
if WhatsAppAdapter._DEFAULT_BRIDGE_DIR is None:
|
||||
from gateway.platforms.whatsapp_common import resolve_whatsapp_bridge_dir
|
||||
WhatsAppAdapter._DEFAULT_BRIDGE_DIR = resolve_whatsapp_bridge_dir()
|
||||
self._bridge_process: Optional[subprocess.Popen] = None
|
||||
self._bridge_port: int = config.extra.get("bridge_port", 3000)
|
||||
self._bridge_script: Optional[str] = config.extra.get(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue