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

F/bb sdk v1.0: Updating the BrowserBase SDK from v0.x to v1.x #1033

Open
wants to merge 15 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 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
6 changes: 4 additions & 2 deletions integrations-service/integrations/models/browserbase.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Literal

from browserbase import DebugConnectionURLs, Session
from browserbase.types import Session
from browserbase.types.session_live_urls import SessionLiveURLs
from pydantic import AnyUrl, Field

from .base_models import BaseOutput
Expand All @@ -12,6 +13,7 @@ class BrowserbaseListSessionsOutput(BaseOutput):

class BrowserbaseCreateSessionOutput(BaseOutput):
id: str = Field(..., description="Unique identifier for the session")
connectionUrl: str | None = Field(None, description="The connection URL for the session")
createdAt: str | None = Field(
None, description="Timestamp indicating when the session was created"
)
Expand Down Expand Up @@ -90,7 +92,7 @@ class PageInfo(BaseOutput):


class BrowserbaseGetSessionLiveUrlsOutput(BaseOutput):
urls: DebugConnectionURLs = Field(..., description="The live URLs for the session")
urls: SessionLiveURLs = Field(..., description="The live URLs for the session")


class BrowserbaseContextOutput(BaseOutput):
Expand Down
196 changes: 125 additions & 71 deletions integrations-service/integrations/utils/integrations/browserbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@

import httpx
from beartype import beartype
from browserbase import (
Browserbase,
BrowserSettings,
CreateSessionOptions,
DebugConnectionURLs,
Session,
)
from browserbase import Browserbase
from browserbase.types.session import Session
from browserbase.types.session_create_params import BrowserSettings
from browserbase.types.session_live_urls import SessionLiveURLs
from pydantic import TypeAdapter
from tenacity import retry, stop_after_attempt, wait_exponential

from ...autogen.Tools import (
Expand Down Expand Up @@ -46,9 +44,6 @@ def get_browserbase_client(setup: BrowserbaseSetup) -> Browserbase:

return Browserbase(
api_key=setup.api_key,
project_id=setup.project_id,
api_url=setup.api_url,
connect_url=setup.connect_url,
)


Expand All @@ -63,11 +58,17 @@ async def list_sessions(
) -> BrowserbaseListSessionsOutput:
client = get_browserbase_client(setup)

# FIXME: Implement status filter
# Run the list_sessions method
sessions: list[Session] = client.list_sessions()
try:
# Add status filter if provided
params = {}
if hasattr(arguments, "status") and arguments.status:
params["status"] = arguments.status

return BrowserbaseListSessionsOutput(sessions=sessions)
sessions: list[Session] = client.sessions.list(**params)
return BrowserbaseListSessionsOutput(sessions=sessions)
except Exception as e:
print(f"Error listing sessions: {e}")
raise


@beartype
Expand All @@ -84,19 +85,39 @@ async def create_session(
if arguments.project_id == "DEMO_PROJECT_ID":
arguments.project_id = browserbase_project_id

if arguments.project_id == "DEMO_PROJECT_ID":
arguments.project_id = browserbase_project_id

options = CreateSessionOptions(
projectId=arguments.project_id or setup.project_id,
extensionId=arguments.extension_id,
browserSettings=BrowserSettings(**arguments.browser_settings),
# Convert browser settings using TypeAdapter
browser_settings = TypeAdapter(BrowserSettings).validate_python(arguments.browser_settings)

# Create session parameters
create_params = {
"project_id": arguments.project_id or setup.project_id,
"browser_settings": browser_settings,
}

# Only add extension_id if it's provided and not None/empty
if arguments.extension_id:
create_params["extension_id"] = arguments.extension_id

# Changed to use sessions.create() with direct parameters
session = client.sessions.create(**create_params)

# Convert datetime fields to ISO format strings
return BrowserbaseCreateSessionOutput(
id=session.id,
connectionslqUrl=session.connect_url,
Vedantsahai18 marked this conversation as resolved.
Show resolved Hide resolved
createdAt=session.created_at.isoformat() if session.created_at else None,
projectId=session.project_id,
startedAt=session.started_at.isoformat() if session.started_at else None,
endedAt=session.ended_at.isoformat() if session.ended_at else None,
expiresAt=session.expires_at.isoformat() if session.expires_at else None,
status=session.status,
proxyBytes=session.proxy_bytes,
avgCpuUsage=session.avg_cpu_usage,
memoryUsage=session.memory_usage,
keepAlive=session.keep_alive,
contextId=session.context_id,
)

session = client.create_session(options)

return BrowserbaseCreateSessionOutput(**session.model_dump())


@beartype
@retry(
Expand All @@ -109,9 +130,23 @@ async def get_session(
) -> BrowserbaseGetSessionOutput:
client = get_browserbase_client(setup)

session = client.get_session(arguments.id)

return BrowserbaseGetSessionOutput(**session.model_dump())
# Changed from get_session() to sessions.retrieve()
session = client.sessions.retrieve(id=arguments.id)

return BrowserbaseGetSessionOutput(
id=session.id,
createdAt=session.created_at.isoformat() if session.created_at else None,
projectId=session.project_id,
startedAt=session.started_at.isoformat() if session.started_at else None,
endedAt=session.ended_at.isoformat() if session.ended_at else None,
expiresAt=session.expires_at.isoformat() if session.expires_at else None,
status=session.status,
proxyBytes=session.proxy_bytes,
avgCpuUsage=session.avg_cpu_usage,
memoryUsage=session.memory_usage,
keepAlive=session.keep_alive,
contextId=session.context_id,
)


@beartype
Expand All @@ -126,7 +161,10 @@ async def complete_session(
client = get_browserbase_client(setup)

try:
client.complete_session(arguments.id)
# Changed to use sessions.update() with REQUEST_RELEASE status
client.sessions.update(
id=arguments.id, status="REQUEST_RELEASE", project_id=setup.project_id
)
except Exception:
return BrowserbaseCompleteSessionOutput(success=False)

Expand All @@ -144,8 +182,13 @@ async def get_live_urls(
) -> BrowserbaseGetSessionLiveUrlsOutput:
"""Get the live URLs for a session."""
client = get_browserbase_client(setup)
urls: DebugConnectionURLs = client.get_debug_connection_urls(arguments.id)
return BrowserbaseGetSessionLiveUrlsOutput(urls=urls)
try:
# Use the debug() method to get live URLs
urls: SessionLiveURLs = client.sessions.debug(id=arguments.id)
return BrowserbaseGetSessionLiveUrlsOutput(urls=urls)
except Exception as e:
print(f"Error getting debug URLs: {e}")
raise


@beartype
Expand All @@ -157,11 +200,17 @@ async def get_live_urls(
async def get_connect_url(
setup: BrowserbaseSetup, arguments: BrowserbaseGetSessionConnectUrlArguments
) -> BrowserbaseGetSessionConnectUrlOutput:
client = get_browserbase_client(setup)

url = client.get_connect_url(arguments.id)

return BrowserbaseGetSessionConnectUrlOutput(url=url)
"""Get the connect URL for a session."""
# TODO: Get a better way to get the connect URL than this
try:
# Get session to access its connect_url
CONNECT_URL = (
f"wss://connect.browserbase.com?sessionId={arguments.id}&apiKey={setup.api_key}"
)
return BrowserbaseGetSessionConnectUrlOutput(url=CONNECT_URL)
except Exception as e:
print(f"Error getting connect URL: {e}")
raise


@beartype
Expand All @@ -174,42 +223,47 @@ async def install_extension_from_github(
setup: BrowserbaseSetup, arguments: BrowserbaseExtensionArguments
) -> BrowserbaseExtensionOutput:
"""Download and install an extension from GitHub to the user's Browserbase account."""
try:
github_url = f"https://github.com/{arguments.repository_name}/archive/refs/tags/{arguments.ref}.zip"

github_url = (
f"https://github.com/{arguments.repository_name}/archive/refs/tags/{arguments.ref}.zip"
)

async with httpx.AsyncClient(timeout=600) as client:
# Download the extension zip
response = await client.get(github_url, follow_redirects=True)
response.raise_for_status()

with tempfile.NamedTemporaryFile(
delete=True, delete_on_close=False, suffix=".zip"
) as tmp_file:
tmp_file.write(response.content)
tmp_file_path = tmp_file.name

# Upload the extension to Browserbase
upload_url = "https://www.browserbase.com/v1/extensions"
headers = {
# NOTE: httpx won't add a boundary if Content-Type header is set when you pass files=
# "Content-Type": "multipart/form-data",
"X-BB-API-Key": setup.api_key,
}

with open(tmp_file_path, "rb") as f:
files = {"file": f}
upload_response = await client.post(upload_url, headers=headers, files=files)

async with httpx.AsyncClient(timeout=600) as client:
# Download the extension zip
try:
upload_response.raise_for_status()
except httpx.HTTPStatusError:
print(upload_response.text)
response = await client.get(github_url, follow_redirects=True)
response.raise_for_status()
except httpx.HTTPError as e:
print(f"Error downloading extension from GitHub: {e}")
raise
Vedantsahai18 marked this conversation as resolved.
Show resolved Hide resolved

# Delete the temporary file
with contextlib.suppress(FileNotFoundError):
os.remove(tmp_file_path)

return BrowserbaseExtensionOutput(id=upload_response.json()["id"])
with tempfile.NamedTemporaryFile(
delete=True, delete_on_close=False, suffix=".zip"
) as tmp_file:
tmp_file.write(response.content)
tmp_file_path = tmp_file.name

upload_url = "https://api.browserbase.com/v1/extensions"
headers = {
"X-BB-API-Key": setup.api_key,
}

try:
with open(tmp_file_path, "rb") as f:
files = {"file": f}
upload_response = await client.post(
upload_url, headers=headers, files=files
)
upload_response.raise_for_status()
except httpx.HTTPError as e:
print(f"Error uploading extension to Browserbase: {e}")
if hasattr(e, "response") and e.response is not None:
print(f"Response content: {e.response.text}")
raise

# Delete the temporary file
with contextlib.suppress(FileNotFoundError):
os.remove(tmp_file_path)

return BrowserbaseExtensionOutput(id=upload_response.json()["id"])
except Exception as e:
print(f"Unexpected error in install_extension_from_github: {e}")
raise
2 changes: 1 addition & 1 deletion integrations-service/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ dependencies = [
"fire~=0.6.0",
"pyowm~=3.3.0",
"spider-client~=0.0.70",
"browserbase~=0.3.0",
"browserbase>=1.0.5",
"setuptools~=75.1.0",
"beartype~=0.19.0",
"tenacity>=8.2.0,<8.4.0",
Expand Down
17 changes: 10 additions & 7 deletions integrations-service/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading