From e43f381b4e0d5a211d64ddec1fc047df27db7795 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Wed, 2 Sep 2026 11:23:21 -0700 Subject: [PATCH] refactor(plugins/browser): shared BaseCloudBrowserProvider for browser_use/browserbase/firecrawl --- plugins/browser/_common.py | 161 +++++++++ plugins/browser/browser_use/__init__.py | 7 +- plugins/browser/browser_use/provider.py | 307 ++++------------- plugins/browser/browserbase/__init__.py | 8 +- plugins/browser/browserbase/provider.py | 308 ++++-------------- plugins/browser/firecrawl/__init__.py | 9 +- plugins/browser/firecrawl/provider.py | 164 ++-------- .../test_managed_browserbase_and_modal.py | 3 + 8 files changed, 342 insertions(+), 625 deletions(-) create mode 100644 plugins/browser/_common.py diff --git a/plugins/browser/_common.py b/plugins/browser/_common.py new file mode 100644 index 0000000000..533c9d10df --- /dev/null +++ b/plugins/browser/_common.py @@ -0,0 +1,161 @@ +"""Shared base for the bundled cloud-browser provider plugins. + +Every vendor (Browserbase, Browser Use, Firecrawl) speaks the same REST shape: +POST to create a session, one request to release it, credentials from +:func:`agent.secret_scope.get_secret`. :class:`CloudBrowserProvider` owns that +lifecycle; subclasses supply class attributes and small hooks. Log messages are +rendered with the vendor label so the emitted text matches the pre-refactor +per-vendor modules, and they are emitted on the subclass module's logger. +""" + +from __future__ import annotations + +import logging +import uuid +from typing import Any, Dict, List, Optional + +import requests + +from agent.browser_provider import BrowserProvider + +_CLOSE_OK = {200, 201, 204} + + +class CloudBrowserProvider(BrowserProvider): + """REST cloud-browser provider driven by class attributes + hooks. + + Subclasses set ``provider_id`` / ``label``, ``release_method`` / + ``release_path`` (``{session_id}`` placeholder, appended to + ``config["base_url"]``), implement ``_get_config_or_none()`` and + ``_headers(config)``, and write ``create_session`` on top of + :meth:`_post_create` / :meth:`_check_created` / :meth:`_session_name`. + """ + + provider_id: str + label: str + release_method: str + release_path: str + missing_credentials_error: str = "" + # Setup-picker metadata; ``setup_tag=None`` hides the provider from the picker. + setup_tag: Optional[str] = None + setup_env_vars: List[Dict[str, str]] = [] + # Rendered noun in "Failed to create