构建浏览器服务商插件
浏览器服务商插件注册一个云浏览器后端,用于服务云模式下的 browser_* 工具调用(导航、点击、截图……)。内置服务商 —— Browserbase、Browser Use 和 Firecrawl —— 都以插件形式发布于 plugins/browser/<name>/ 下。你可以在它们旁边放置一个目录来添加新服务商,或覆盖某个内置服务商。
浏览器后端是 Hermes 支持的若干种后端插件之一。其他后端(各有自己的 ABC)包括 Web 搜索服务商插件(此 ABC 有意与其保持一致)、图像生成、视频生成、记忆服务商、上下文引擎、密钥来源 和 模型服务商。通用的工具/钩子/CLI 插件见 构建 Hermes 插件。
各部分如何协同工作
浏览器服务商并不实现浏览功能。它实现的是会话生命周期:创建远程浏览器会话、交回一个 CDP websocket URL,并拆除会话。Hermes 自己的浏览器技术栈(agent-browser + tools/browser_tool.py)会连接到你所返回的任意 CDP URL,并从那里驱动页面 —— 每个服务商都能免费获得完整的 browser_* 工具集。
当前生效的服务商由 config.yaml 中的 browser.cloud_provider 选择;tools/browser_tool.py 中的分发器是一次纯粹的注册表查找,没有任何针对具体服务商的条件判断。
发现机制
Hermes 在三个位置扫描浏览器后端:
- 内置 ——
<repo>/plugins/browser/<name>/(以kind: backend自动加载) - 用户 ——
~/.hermes/plugins/browser/<name>/(通过plugins.enabled或hermes plugins enable <name>选择性启用) - Pip —— 声明了
hermes_agent.plugins入口点的包
每个插件的 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" # the browser.cloud_provider config value
@property
def display_name(self) -> str:
return "My Backend" # shown in `hermes tools`
def is_available(self) -> bool:
"""Cheap check only — env var present, dep importable.
NO network calls: runs at tool-registration time and on every
`hermes tools` paint."""
return bool(os.environ.get("MY_BACKEND_API_KEY"))
def create_session(self, task_id: str) -> dict:
"""Create a remote browser session; return the session-metadata contract."""
session = my_api.create_browser(...)
return {
"session_name": f"my-backend-{task_id}", # unique agent-browser session name
"bb_session_id": session.id, # provider session ID (for cleanup)
"cdp_url": session.cdp_ws_url, # CDP websocket URL
"features": {"stealth": True}, # feature flags you enabled
}
def close_session(self, session_id: str) -> bool:
"""Terminate by provider session ID. Log-and-return-False on error —
never raise, so the dispatcher's cleanup loop keeps moving."""
...
def emergency_cleanup(self, session_id: str) -> None:
"""Best-effort teardown from atexit/signal handlers. Must not raise."""
...
会话元数据契约
create_session() 至少必须返回 session_name、bb_session_id、cdp_url 和 features。有两个值得了解的怪癖:
bb_session_id是一个历史遗留的键名,为保持与tools/browser_tool.py的向后兼容而逐字保留 —— 无论使用哪家厂商,它都存放你的服务商的会话 ID。不要重命名它。create_session()可以抛出异常 —— 缺少凭据时抛ValueError,网络/API 失败时抛RuntimeError。分发器会将这些错误呈现给用户。这与close_session/emergency_cleanup不同,后两者绝不能抛异常。
可选的 external_call_id 键用于支持托管网关计费。
get_setup_schema() —— hermes tools 选择器中的一行
覆盖此方法,即可作为一等选项出现在 Browser Automation 选择器中,并带有 API 密钥提示和安装钩子:
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", # ensures local Chromium is installed (agent-browser itself resolves via npx)
}
按照项目对工具后端的标准:如果一个后端无法通过 hermes tools 被选择和配置,那它就不算完成 ——“手动设置这个环境变量”不是一种集成。
用户如何配置
browser:
cloud_provider: my-backend
参考实现
plugins/browser/ 下的三个内置服务商是标准范例,复杂性递增:firecrawl(最简单)、browser_use 和 browserbase(带有 stealth/proxy/keep-alive 功能标志,并在付费功能不可用时优雅降级)。复制最接近的一个即可。
检查清单
-
name为小写且稳定(它是用户要写的配置值) -
is_available()不进行任何网络调用 -
create_session()返回完整的元数据契约(bb_session_id键名保持不变) -
close_session()/emergency_cleanup()绝不抛出异常 -
get_setup_schema()暴露你的环境变量,以便hermes tools能配置该后端 -
plugin.yaml声明了kind: backend+provides_browser_providers