构建浏览器 Provider 插件

浏览器 provider 插件注册一个云浏览器后端,为 cloud 模式的 browser_* 工具调用(导航、点击、截图……)提供服务。内置 provider——Browserbase、Browser Use、Firecrawl——都以插件形式放在 plugins/browser/<name>/ 下。你可以在它们旁边放一个目录来新增一个,或覆盖某个内置的。

TIP

浏览器后端只是 Hermes 支持的若干后端插件之一。其他几类(各有自己的 ABC)是 Web 搜索 Provider 插件(本 ABC 刻意与其对齐)、图像生成、视频生成、记忆 Provider、上下文引擎、机密源、模型 Provider。通用的工具/hook/CLI 插件见构建 Hermes 插件。

它如何组装

浏览器 provider 不实现浏览本身。它实现的是会话生命周期:创建远程浏览器会话、回传一个 CDP websocket URL、再拆掉会话。Hermes 自己的浏览器栈(agent-browser + tools/browser_tool.py)连接到你返回的任意 CDP URL 并从那里驱动页面——每个 provider 都免费获得完整的 browser_* 工具集。

激活的 provider 由 config.yaml 中的 browser.cloud_provider 选定;tools/browser_tool.py 中的分发器是纯粹的注册表查找,不含任何按 provider 的条件分支。

发现

Hermes 在三处扫描浏览器后端:

  1. 内置——<repo>/plugins/browser/<name>/(以 kind: backend 自动加载)
  2. 用户——~/.hermes/plugins/browser/<name>/(经 plugins.enabled 或 hermes plugins enable <name> 选择启用)
  3. Pip——声明了 hermes_agent.plugins entry point 的包

每个插件的 register(ctx) 调用 ctx.register_browser_provider(...),把实例放入 agent/browser_registry.py 的注册表。

目录结构

plugins/browser/my-backend/
├── __init__.py     # register() 入口
├── provider.py     # BrowserProvider 子类
└── plugin.yaml     # 清单,含 kind: backend 与 provides_browser_providers

plugin.yaml:

name: browser-my-backend
version: 1.0.0
description: "My cloud browser backend. Requires MY_BACKEND_API_KEY."
author: you
kind: backend
provides_browser_providers:
  - my-backend

__init__.py:

from plugins.browser.my_backend.provider import MyBackendProvider


def register(ctx) -> None:
    ctx.register_browser_provider(MyBackendProvider())

BrowserProvider ABC

实现 agent.browser_provider.BrowserProvider。三个生命周期方法加身份标识:

from agent.browser_provider import BrowserProvider


class MyBackendProvider(BrowserProvider):
    @property
    def name(self) -> str:
        return "my-backend"          # 即 browser.cloud_provider 的配置值

    @property
    def display_name(self) -> str:
        return "My Backend"          # 显示在 `hermes tools` 中

    def is_available(self) -> bool:
        """只做廉价检查——环境变量是否存在、依赖可否导入。
        不做网络调用:它在工具注册时以及每次
        `hermes tools` 绘制时运行。"""
        return bool(os.environ.get("MY_BACKEND_API_KEY"))

    def create_session(self, task_id: str) -> dict:
        """创建远程浏览器会话;返回会话元数据契约。"""
        session = my_api.create_browser(...)
        return {
            "session_name": f"my-backend-{task_id}",  # 唯一的 agent-browser 会话名
            "bb_session_id": session.id,              # provider 会话 ID(用于清理)
            "cdp_url": session.cdp_ws_url,            # CDP websocket URL
            "features": {"stealth": True},            # 你启用的特性开关
        }

    def close_session(self, session_id: str) -> bool:
        """按 provider 会话 ID 终止。出错时记录日志并返回 False——
        绝不抛异常,以便分发器的清理循环继续推进。"""
        ...

    def emergency_cleanup(self, session_id: str) -> None:
        """来自 atexit/信号处理器的尽力拆除。不得抛异常。"""
        ...

会话元数据契约

create_session() 必须至少返回 session_name、bb_session_id、cdp_url 和 features。两个需要知道的怪癖:

  • bb_session_id 是一个遗留键名,为与 tools/browser_tool.py 向后兼容而原样保留——无论哪家厂商,它都装着你的 provider 的会话 ID。不要改名。
  • create_session() 可以抛异常——缺凭据抛 ValueError,网络/API 失败抛 RuntimeError。分发器会把这些呈现给用户。这与 close_session/emergency_cleanup 不同,后两者绝不能抛异常。

可选的 external_call_id 键支持托管 gateway 计费。

get_setup_schema()——hermes tools 选择器中的一行

重写它,即可在浏览器自动化选择器中作为一等选项出现,并带 API key 提示和安装钩子:

def get_setup_schema(self) -> dict:
    return {
        "name": "My Backend",
        "badge": "paid",
        "tag": "Cloud browser with stealth and proxies",
        "env_vars": [
            {"key": "MY_BACKEND_API_KEY",
             "prompt": "My Backend API key",
             "url": "https://mybackend.example"},
        ],
        "post_setup": "agent_browser",   # 确保本地 Chromium 已安装(agent-browser 自身经 npx 解析)
    }

按项目对工具后端的标准:如果一个后端无法通过 hermes tools 被选中并配置,它就不算完成——"手动设置这个环境变量"不算集成。

用户如何配置

browser:
  cloud_provider: my-backend

参考实现

plugins/browser/ 下的三个内置 provider 是规范示例,按复杂度递增排列:firecrawl(最简单)、browser_use、browserbase(带 stealth/代理/保活特性开关,并在付费特性不可用时优雅回退)。复制最接近的那一个。

检查清单

  •  name 小写且稳定(它是用户写入的配置值)
  •  is_available() 零网络调用
  •  create_session() 返回完整元数据契约(bb_session_id 键名原样保留)
  •  close_session() / emergency_cleanup() 绝不抛异常
  •  get_setup_schema() 暴露你的环境变量,让 hermes tools 能配置该后端
  •  plugin.yaml 声明 kind: backend + provides_browser_providers