Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hermes_cli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ def ensure_hermes_home():

"browser": {
"inactivity_timeout": 120,
"command_timeout": 30, # Timeout for browser commands in seconds (screenshot, navigate, etc.)
"record_sessions": False, # Auto-record browser sessions as WebM videos
},

Expand Down
31 changes: 27 additions & 4 deletions tools/browser_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,27 @@ def _discover_homebrew_node_dirs() -> list[str]:
SNAPSHOT_SUMMARIZE_THRESHOLD = 8000


def _get_command_timeout() -> int:
"""Return the configured browser command timeout from config.yaml.

Reads ``config["browser"]["command_timeout"]`` and falls back to
``DEFAULT_COMMAND_TIMEOUT`` (30s) if unset or unreadable.
"""
try:
hermes_home = Path(os.environ.get("HERMES_HOME", Path.home() / ".hermes"))
config_path = hermes_home / "config.yaml"
if config_path.exists():
import yaml
with open(config_path) as f:
cfg = yaml.safe_load(f) or {}
val = cfg.get("browser", {}).get("command_timeout")
if val is not None:
return max(int(val), 5) # Floor at 5s to avoid instant kills
except Exception as e:
logger.debug("Could not read command_timeout from config: %s", e)
return DEFAULT_COMMAND_TIMEOUT


def _get_vision_model() -> Optional[str]:
"""Model for browser_vision (screenshot analysis — multimodal)."""
return os.getenv("AUXILIARY_VISION_MODEL", "").strip() or None
Expand Down Expand Up @@ -725,7 +746,7 @@ def _run_browser_command(
task_id: str,
command: str,
args: List[str] = None,
timeout: int = DEFAULT_COMMAND_TIMEOUT
timeout: Optional[int] = None,
) -> Dict[str, Any]:
"""
Run an agent-browser CLI command using our pre-created Browserbase session.
Expand All @@ -734,11 +755,14 @@ def _run_browser_command(
task_id: Task identifier to get the right session
command: The command to run (e.g., "open", "click")
args: Additional arguments for the command
timeout: Command timeout in seconds
timeout: Command timeout in seconds. ``None`` reads
``browser.command_timeout`` from config (default 30s).

Returns:
Parsed JSON response from agent-browser
"""
if timeout is None:
timeout = _get_command_timeout()
args = args or []

# Build the command
Expand Down Expand Up @@ -1022,7 +1046,7 @@ def browser_navigate(url: str, task_id: Optional[str] = None) -> str:
session_info["_first_nav"] = False
_maybe_start_recording(effective_task_id)

result = _run_browser_command(effective_task_id, "open", [url], timeout=60)
result = _run_browser_command(effective_task_id, "open", [url], timeout=max(_get_command_timeout(), 60))

if result.get("success"):
data = result.get("data", {})
Expand Down Expand Up @@ -1496,7 +1520,6 @@ def browser_vision(question: str, annotate: bool = False, task_id: Optional[str]
effective_task_id,
"screenshot",
screenshot_args,
timeout=30
)

if not result.get("success"):
Expand Down
Loading