Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HyperbrowserBrowser #2

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ OPENAI_ORG = "org-123"
BROWSERBASE_API_KEY="00000000-0000-0000-0000-000000000000"
BROWSERBASE_PROJECT_ID="bb_live_00000000-00000"

SCRAPYBARA_API_KEY="scrapy-123"
SCRAPYBARA_API_KEY="scrapy-123"

HYPERBROWSER_API_KEY="00000000-0000-0000-0000-000000000000"
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
__pycache__/
.env
.venv/
.venv/
venv
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ This sample app provides a set of implemented `Computer` examples, but feel free
| `Browserbase` | browserbase | `browser` | Remote browser environment | [Browserbase](https://www.browserbase.com/) API key in `.env` |
| `ScrapybaraBrowser` | scrapybara-browser | `browser` | Remote browser environment | [Scrapybara](https://scrapybara.com/dashboard) API key in `.env` |
| `ScrapybaraUbuntu` | scrapybara-ubuntu | `linux` | Remote Ubuntu desktop environment | [Scrapybara](https://scrapybara.com/dashboard) API key in `.env` |
| `Hyperbrowser` | hyperbrowser | `browser` | Remote browser environment | [Hyperbrowser](https://www.hyperbrowser.ai/) API key in `.env` |

Using the CLI, you can run the sample app with different computer environments using the options listed above:

Expand Down
13 changes: 7 additions & 6 deletions agent/agent.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import json
from typing import Callable

from computers import Computer
from utils import (
check_blocklisted_url,
create_response,
show_image,
pp,
sanitize_message,
check_blocklisted_url,
show_image,
)
import json
from typing import Callable


class Agent:
Expand All @@ -19,7 +20,7 @@ class Agent:

def __init__(
self,
model="computer-use-preview-2025-02-04",
model="computer-use-preview",
computer: Computer = None,
tools: list[dict] = [],
acknowledge_safety_check_callback: Callable = lambda: False,
Expand All @@ -35,7 +36,7 @@ def __init__(
if computer:
self.tools += [
{
"type": "computer-preview",
"type": "computer_use_preview",
"display_width": computer.dimensions[0],
"display_height": computer.dimensions[1],
"environment": computer.environment,
Expand Down
5 changes: 3 additions & 2 deletions computers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .computer import Computer
from .browserbase import BrowserbaseBrowser
from .local_playwright import LocalPlaywrightComputer
from .computer import Computer
from .docker import DockerComputer
from .hyperbrowser import HyperbrowserBrowser
from .local_playwright import LocalPlaywrightComputer
from .scrapybara import ScrapybaraBrowser, ScrapybaraUbuntu
178 changes: 178 additions & 0 deletions computers/hyperbrowser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import os
from typing import Tuple

from dotenv import load_dotenv
from hyperbrowser import Hyperbrowser
from hyperbrowser.models.session import CreateSessionParams, ScreenConfig
from playwright.sync_api import Browser, Page
from playwright.sync_api import Error as PlaywrightError

from .base_playwright import BasePlaywrightComputer

load_dotenv()


class HyperbrowserBrowser(BasePlaywrightComputer):
"""
Hyperbrowser is the next-generation platform for effortless, scalable browser automation. It provides a cloud-based browser instance
that can be controlled through code, eliminating the need for local infrastructure setup.

Key features include:
- Instant Scalability: Spin up hundreds of browser sessions in seconds without infrastructure headaches
- Simple Integration: Works seamlessly with popular tools like Puppeteer and Playwright
- Powerful APIs: Easy to use APIs for managing sessions, scraping/crawling any site, and much more
- Production Ready: Enterprise-grade reliability and security built-in
- Bypass Anti-Bot Measures: Built-in stealth mode, ad blocking, automatic CAPTCHA solving, and rotating proxies

IMPORTANT: This Hyperbrowser computer requires the use of the `goto` tool defined in playwright_with_custom_functions.py.
Make sure to include this tool in your configuration when using the Hyperbrowser computer.
"""

def __init__(
self,
width: int = 1024,
height: int = 768,
proxy: bool = False,
ad_blocker: bool = False,
accept_cookies: bool = False,
):
"""
Initialize the Hyperbrowser instance.
Additional configuration options for features such as persistent cookies, ad blockers, file downloads and more can be found in the Hyperbrowser API documentation: https://docs.hyperbrowser.ai/

In Hyperbrowser, a Session is a dedicated, cloud-based browser instance that's fully controllable through code.
Each Session keeps its own cookies, storage, and browsing context.

Args:
width (int): The width of the browser viewport. Default is 1024.
height (int): The height of the browser viewport. Default is 768.
proxy (bool): Whether to use a proxy for the session. Default is False. Enables rotating proxies to bypass IP-based blocking.
virtual_mouse (bool): Whether to enable the virtual mouse cursor. Default is True.
ad_blocker (bool): Whether to enable the built-in ad blocker. Default is False.
"""
super().__init__()
self.hb = Hyperbrowser(api_key=os.getenv("HYPERBROWSER_API_KEY"))
self.session = None
self.dimensions = (width, height)
self.proxy = proxy
self.ad_blocker = ad_blocker
self.accept_cookies = accept_cookies

def _get_browser_and_page(self) -> Tuple[Browser, Page]:
"""
Create a Hyperbrowser session and connect to it.

This method creates a cloud-based browser session using Hyperbrowser's Sessions API,
configures it with the specified parameters, and establishes a connection using Playwright.

Returns:
Tuple[Browser, Page]: A tuple containing the connected browser and page objects.
"""
# Create a session on Hyperbrowser with specified parameters
width, height = self.dimensions
self.session = self.hb.sessions.create(
CreateSessionParams(
use_proxy=self.proxy,
adblock=self.ad_blocker,
accept_cookies=self.accept_cookies,
screen=ScreenConfig(width=width, height=height),
)
)

# Print the live session URL
print(f"Watch and control this browser live at {self.session.live_url}")

# Connect to the remote session
browser = self._playwright.chromium.connect_over_cdp(
self.session.ws_endpoint, timeout=60000
)
context = browser.contexts[0]

# Add event listeners for page creation and closure
context.on("page", self._handle_new_page)

page = context.pages[0]
page.on("close", self._handle_page_close)

page.goto("https://bing.com")

return browser, page

def _handle_new_page(self, page: Page):
"""
Handle the creation of a new page in the Hyperbrowser session.

This event handler is triggered when a new page is created in the browser context,
allowing for tracking and management of multiple pages within a single session.
"""
print("New page created")
self._page = page
self._page.set_viewport_size(
{"width": self.dimensions[0], "height": self.dimensions[1]}
)
page.on("close", self._handle_page_close)

def _handle_page_close(self, page: Page):
"""
Handle the closure of a page in the Hyperbrowser session.

This event handler is triggered when a page is closed, ensuring proper cleanup
and management of the active page reference within the session.
"""
print("Page closed")
if self._page == page:
if self._browser.contexts[0].pages:
self._page = self._browser.contexts[0].pages[-1]
else:
print("Warning: All pages have been closed.")
self._page = None

def __exit__(self, exc_type, exc_val, exc_tb):
"""
Clean up resources when exiting the context manager.

This method ensures proper cleanup of the Hyperbrowser session, closing pages and browsers,
stopping the Playwright instance, and providing a link to view the session replay.

Args:
exc_type: The type of the exception that caused the context to be exited.
exc_val: The exception instance that caused the context to be exited.
exc_tb: A traceback object encapsulating the call stack at the point where the exception occurred.
"""
if self._page:
self._page.close()
if self._browser:
self._browser.close()
if self._playwright:
self._playwright.stop()

if self.session:
print(
f"Session completed. View replay at https://app.hyperbrowser.ai/sessions/{self.session.id}"
)

def screenshot(self) -> str:
"""
Capture a screenshot of the current viewport in the Hyperbrowser session using CDP.

This method uses Chrome DevTools Protocol (CDP) to capture a high-quality screenshot
of the current page, with a fallback to standard Playwright screenshot functionality.

Returns:
str: A base64 encoded string of the screenshot.
"""
try:
# Get CDP session from the page
cdp_session = self._page.context.new_cdp_session(self._page)

# Capture screenshot using CDP
result = cdp_session.send(
"Page.captureScreenshot", {"format": "png", "fromSurface": True}
)

return result["data"]
except PlaywrightError as error:
print(
f"CDP screenshot failed, falling back to standard screenshot: {error}"
)
return super().screenshot()
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ browserbase==1.2.0
certifi==2025.1.31
charset-normalizer==3.4.1
distro==1.9.0
exceptiongroup==1.2.2
greenlet==3.1.1
h11==0.14.0
httpcore==1.0.7
httpx==0.28.1
hyperbrowser==0.33.0
idna==3.10
jiter==0.8.2
pillow==11.1.0
Expand Down