ブラウザプロバイダプラグインを作る
目次
ブラウザプロバイダプラグインは、クラウドモードの browser_* ツール呼び出し(ページを開く、クリックする、画面を撮る、など)を引き受けるクラウドブラウザのバックエンドを登録します。組み込みのプロバイダ(Browserbase、Browser Use、Firecrawl)は、いずれも plugins/browser/<name>/ にプラグインとして同梱されています。新しいものを足したい場合も、同梱のものを差し替えたい場合も、その隣にディレクトリを 1 つ置くだけです。
どうつながっているか
ブラウザプロバイダは、ブラウザの操作そのものを実装するわけではありません。実装するのはセッションの出し入れです。遠隔のブラウザセッションを作り、CDP の websocket URL を返し、終わったらセッションを片付けます。ページを実際に動かすのは Hermes 自身のブラウザまわり(agent-browser と tools/browser_tool.py)で、返ってきた CDP の URL につないで操作します。そのため、どのプロバイダでも browser_* のツール一式がそのまま使えます。
どのプロバイダを使うかは config.yaml の browser.cloud_provider で決まります。tools/browser_tool.py の振り分けは登録簿を引くだけで、プロバイダごとの分岐は入っていません。
見つけ方
Hermes はブラウザのバックエンドを次の 3 か所から探します。
- 同梱 —
<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() entry point
├── provider.py # BrowserProvider subclass
└── plugin.yaml # Manifest with kind: backend and provides_browser_providersplugin.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 の抽象基底クラス
agent.browser_provider.BrowserProvider を実装します。名前まわりに加えて、セッションを扱うメソッドが 3 つです。
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 を返す必要があります。知っておきたい癖が 2 つあります。
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/ に同梱された 3 つのプロバイダが、そのままお手本になります。単純なものから順に、firecrawl(いちばん簡単)、browser_use、browserbase(ステルス・プロキシ・セッション維持のフラグを持ち、有料機能が使えないときは無理なく切り替えます)です。近いものを写して始めてください。
確認リスト
- [ ]
nameは小文字で、あとから変えない(利用者が設定に書く値です) - [ ]
is_available()は通信をいっさいしない - [ ]
create_session()が決まりどおりの情報を返す(bb_session_idというキー名はそのまま) - [ ]
close_session()とemergency_cleanup()は決して例外を投げない - [ ]
get_setup_schema()で環境変数を伝え、hermes toolsから設定できるようにする - [ ]
plugin.yamlにkind: backendとprovides_browser_providersを書く