gl-browser-use-binary 0.0.0b9__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ from gl_browser_use.client import BrowserUseClient as BrowserUseClient
2
+ from gl_browser_use.config import BrowserUseClientConfig as BrowserUseClientConfig
3
+ from gl_browser_use.errors import BrowserUseConfigurationError as BrowserUseConfigurationError, BrowserUseDependencyError as BrowserUseDependencyError, BrowserUseExecutionError as BrowserUseExecutionError, BrowserUseMissingDependencyError as BrowserUseMissingDependencyError, BrowserUseRetryExhaustedError as BrowserUseRetryExhaustedError, BrowserUseSDKError as BrowserUseSDKError
4
+ from gl_browser_use.infrastructure.base import BrowserInfrastructure as BrowserInfrastructure, BrowserInfrastructureContext as BrowserInfrastructureContext
5
+ from gl_browser_use.models import BrowserUseRunResult as BrowserUseRunResult, BrowserUseStreamEvent as BrowserUseStreamEvent
6
+ from gl_browser_use.storage.base import ObjectStorage as ObjectStorage
7
+
8
+ __all__ = ['BrowserUseClient', 'BrowserUseClientConfig', 'BrowserUseConfigurationError', 'BrowserUseDependencyError', 'BrowserUseExecutionError', 'BrowserUseMissingDependencyError', 'BrowserUseRetryExhaustedError', 'BrowserUseSDKError', 'BrowserUseRunResult', 'BrowserUseStreamEvent', 'BrowserInfrastructure', 'BrowserInfrastructureContext', 'SteelBrowserInfrastructure', 'ObjectStorage', 'MinIOS3CompatibleStorage']
9
+
10
+ # Names in __all__ with no definition:
11
+ # MinIOS3CompatibleStorage
12
+ # SteelBrowserInfrastructure
@@ -0,0 +1,57 @@
1
+ from _typeshed import Incomplete
2
+ from collections.abc import AsyncGenerator, Awaitable, Callable
3
+ from gl_browser_use.config import BrowserUseClientConfig as BrowserUseClientConfig
4
+ from gl_browser_use.errors import BrowserUseExecutionError as BrowserUseExecutionError, BrowserUseRetryExhaustedError as BrowserUseRetryExhaustedError
5
+ from gl_browser_use.events import RECORDING_MESSAGE as RECORDING_MESSAGE, STREAMING_MESSAGE as STREAMING_MESSAGE, TASK_COMPLETED_MESSAGE as TASK_COMPLETED_MESSAGE, build_activity_event as build_activity_event, build_error_event as build_error_event, build_retry_event as build_retry_event, build_step_content as build_step_content, build_step_event as build_step_event, build_thinking_event as build_thinking_event
6
+ from gl_browser_use.infrastructure.base import BrowserInfrastructure as BrowserInfrastructure, BrowserInfrastructureContext as BrowserInfrastructureContext
7
+ from gl_browser_use.models import BrowserUseRunResult as BrowserUseRunResult, BrowserUseRunStatus as BrowserUseRunStatus, BrowserUseStreamEvent as BrowserUseStreamEvent
8
+ from gl_browser_use.parsing import coerce_string as coerce_string, extract_final_output as extract_final_output, extract_tool_calls as extract_tool_calls, summarize_terminal_error as summarize_terminal_error, validate_structured_data_output as validate_structured_data_output
9
+ from gl_browser_use.session_errors import is_recoverable_session_error as is_recoverable_session_error
10
+ from gl_browser_use.storage.base import ObjectStorage as ObjectStorage
11
+ from typing import Any
12
+
13
+ logger: Incomplete
14
+ EmitCallable = Callable[[BrowserUseStreamEvent | None], Awaitable[None] | None]
15
+
16
+ def recording_metadata(*, infrastructure: BrowserInfrastructure | None, storage: ObjectStorage | None, browser_context: BrowserInfrastructureContext | None) -> dict[str, Any]:
17
+ """Return recording status metadata aligned with implementation behavior."""
18
+
19
+ class BrowserUseClient:
20
+ """Facade for running browser automation tasks.
21
+
22
+ Note: ``infrastructure`` and ``storage`` attributes are read by ``run``/
23
+ ``run_once``/``run_sync`` on each call. Swapping them while a run is in
24
+ flight is undefined behavior.
25
+ """
26
+ config: Incomplete
27
+ infrastructure: Incomplete
28
+ storage: Incomplete
29
+ def __init__(self, *, config: BrowserUseClientConfig, infrastructure: BrowserInfrastructure | None = None, storage: ObjectStorage | None = None) -> None:
30
+ """Initialize the client."""
31
+ async def run(self, task: str) -> AsyncGenerator[BrowserUseStreamEvent, None]:
32
+ """Run the client."""
33
+ async def run_once(self, task: str) -> BrowserUseRunResult:
34
+ """Run the client once and return a single aggregated result.
35
+
36
+ Raises:
37
+ ------
38
+ BrowserUseExecutionError
39
+ When the task input is invalid.
40
+ BrowserUseConfigurationError
41
+ When required configuration is missing.
42
+ BrowserUseRetryExhaustedError
43
+ When all recoverable session retries are exhausted.
44
+ """
45
+ def run_sync(self, task: str) -> BrowserUseRunResult:
46
+ """Run the client synchronously.
47
+
48
+ Raises:
49
+ ------
50
+ BrowserUseExecutionError
51
+ When invoked from a thread that already has a running event loop,
52
+ or when task validation fails.
53
+ BrowserUseConfigurationError
54
+ When required configuration is missing.
55
+ BrowserUseRetryExhaustedError
56
+ When all recoverable session retries are exhausted.
57
+ """
@@ -0,0 +1,43 @@
1
+ from _typeshed import Incomplete
2
+ from gl_browser_use.errors import BrowserUseConfigurationError as BrowserUseConfigurationError
3
+ from openai.types.shared_params.chat_model import ChatModel
4
+ from openai.types.shared_params.reasoning_effort import ReasoningEffort
5
+ from pydantic import BaseModel
6
+ from typing import Any, Literal
7
+
8
+ class BrowserUseClientConfig(BaseModel):
9
+ """Typed runtime configuration for :class:`BrowserUseClient`."""
10
+ model_config: Incomplete
11
+ llm_openai_api_key: str | None
12
+ llm_openai_model: ChatModel | str
13
+ llm_openai_temperature: float | None
14
+ llm_openai_reasoning_effort: ReasoningEffort
15
+ llm_openai_base_url: str | None
16
+ page_extraction_llm_openai_api_key: str | None
17
+ page_extraction_llm_openai_model: ChatModel | str
18
+ page_extraction_llm_openai_temperature: float | None
19
+ page_extraction_llm_openai_reasoning_effort: ReasoningEffort
20
+ page_extraction_llm_openai_base_url: str | None
21
+ sensitive_data: dict[str, str | dict[str, str]] | None
22
+ extend_system_message: str | None
23
+ vision_detail_level: Literal['auto', 'low', 'high']
24
+ llm_timeout_in_s: int | None
25
+ step_timeout_in_s: int
26
+ agent_kwargs: dict[str, Any]
27
+ enable_cloud_sync: bool
28
+ logging_level: Literal['debug', 'info', 'warning', 'error', 'result']
29
+ max_steps: int
30
+ max_session_retries: int
31
+ session_retry_delay_in_s: float
32
+ def validate(self, *, strict: bool = False) -> list[str]:
33
+ """Validate required runtime values.
34
+
35
+ Returns a list of field-level validation issues. If ``strict`` is
36
+ ``True``, raise :class:`BrowserUseConfigurationError` on any issues.
37
+ """
38
+ def redacted_dict(self, *, include_secrets: bool = False) -> dict[str, Any]:
39
+ '''Return a config dictionary safe to log.
40
+
41
+ Fields marked with ``json_schema_extra={"secret": True}`` are replaced
42
+ with ``"***"`` unless ``include_secrets`` is ``True``.
43
+ '''
@@ -0,0 +1,41 @@
1
+ from _typeshed import Incomplete
2
+ from typing import Any, Final
3
+
4
+ __all__ = ['MINIO_EXTRA', 'OPENSANDBOX_EXTRA', 'PACKAGE_NAME', 'STEEL_EXTRA', 'BrowserUseConfigurationError', 'BrowserUseDependencyError', 'BrowserUseExecutionError', 'BrowserUseMissingDependencyError', 'BrowserUseRetryExhaustedError', 'BrowserUseSDKError', 'install_hint']
5
+
6
+ PACKAGE_NAME: Final[str]
7
+ STEEL_EXTRA: Final[str]
8
+ OPENSANDBOX_EXTRA: Final[str]
9
+ MINIO_EXTRA: Final[str]
10
+
11
+ def install_hint(extra: str) -> str:
12
+ """Return a ``pip install`` hint for the given optional extra."""
13
+
14
+ class BrowserUseSDKError(RuntimeError):
15
+ """Base exception for all SDK errors."""
16
+ message: Incomplete
17
+ details: Incomplete
18
+ origin: Incomplete
19
+ def __init__(self, message: str, *, details: dict[str, Any] | None = None, origin: BaseException | None = None) -> None:
20
+ """Initialize the error."""
21
+
22
+ class BrowserUseDependencyError(BrowserUseSDKError):
23
+ """Raised when required optional dependencies are unavailable."""
24
+ missing_dependency: Incomplete
25
+ package_hint: Incomplete
26
+ def __init__(self, message: str, *, missing_dependency: str | None = None, package_hint: str | None = None, details: dict[str, Any] | None = None, origin: BaseException | None = None) -> None:
27
+ """Initialize the error."""
28
+
29
+ class BrowserUseMissingDependencyError(BrowserUseDependencyError):
30
+ """Raised when an optional extra dependency is not installed."""
31
+ class BrowserUseConfigurationError(BrowserUseSDKError):
32
+ """Raised when required configuration values are missing or invalid."""
33
+ class BrowserUseExecutionError(BrowserUseSDKError):
34
+ """Raised when execution of a run fails."""
35
+
36
+ class BrowserUseRetryExhaustedError(BrowserUseExecutionError):
37
+ """Raised when session retries are exhausted after recoverable errors."""
38
+ attempt: Incomplete
39
+ max_attempts: Incomplete
40
+ def __init__(self, message: str, *, attempt: int, max_attempts: int, details: dict[str, Any] | None = None, origin: BaseException | None = None) -> None:
41
+ """Initialize the error."""
@@ -0,0 +1,29 @@
1
+ from gl_browser_use.models import BrowserUseStreamEvent
2
+ from typing import Any
3
+
4
+ __all__ = ['EVENT_ID', 'PROCESSING_MESSAGE', 'RECORDING_MESSAGE', 'STREAMING_MESSAGE', 'TASK_COMPLETED_MESSAGE', 'build_activity_event', 'build_error_event', 'build_fallback_thinking_message', 'build_retry_event', 'build_step_content', 'build_step_event', 'build_thinking_event']
5
+
6
+ EVENT_ID: str
7
+ TASK_COMPLETED_MESSAGE: str
8
+ PROCESSING_MESSAGE: str
9
+ STREAMING_MESSAGE: str
10
+ RECORDING_MESSAGE: str
11
+
12
+ def build_activity_event(url: str, content: str) -> BrowserUseStreamEvent:
13
+ """Return an activity event carrying ``url`` in the standard iframe payload."""
14
+ def build_thinking_event(marker: str, *, content: str, final: bool = False) -> BrowserUseStreamEvent:
15
+ """Return a thinking-marker event for ``thinking_start``/``thinking_end``/``thinking``."""
16
+ def build_step_event(tool_calls: list[Any], content: str, *, is_final: bool) -> BrowserUseStreamEvent:
17
+ """Return a step event summarizing ``tool_calls`` with a fallback thinking narration."""
18
+ def build_error_event(error_message: str, *, recording_url: str = '') -> BrowserUseStreamEvent:
19
+ """Return a terminal tool-result error event with optional ``recording_url``.
20
+
21
+ ``error_message`` is expected to be already summarized by the caller via
22
+ :func:`gl_browser_use.parsing.summarize_terminal_error`.
23
+ """
24
+ def build_retry_event(attempt: int, max_attempts: int, reason: str) -> BrowserUseStreamEvent:
25
+ """Return a retry status event carrying attempt counters and the recoverable reason."""
26
+ def build_fallback_thinking_message(content: str, tool_calls: list[Any]) -> str:
27
+ """Build a fallback thinking narration that lists recent tool-call outputs."""
28
+ def build_step_content(tool_calls: list[Any], is_done: bool) -> str:
29
+ """Return a user-visible content string for a step event based on ``tool_calls``."""
@@ -0,0 +1,7 @@
1
+ from gl_browser_use.infrastructure.base import BrowserInfrastructure as BrowserInfrastructure, BrowserInfrastructureContext as BrowserInfrastructureContext
2
+
3
+ __all__ = ['BrowserInfrastructure', 'BrowserInfrastructureContext', 'OpenSandboxBrowserInfrastructure', 'SteelBrowserInfrastructure']
4
+
5
+ # Names in __all__ with no definition:
6
+ # OpenSandboxBrowserInfrastructure
7
+ # SteelBrowserInfrastructure
@@ -0,0 +1,55 @@
1
+ from abc import ABC, abstractmethod
2
+ from dataclasses import dataclass, field
3
+ from gl_browser_use.storage.base import ObjectStorage
4
+ from typing import Any, Generic, TypeVar
5
+
6
+ __all__ = ['BrowserInfrastructure', 'BrowserInfrastructureContext']
7
+
8
+ ClientType = TypeVar('ClientType')
9
+ SessionType = TypeVar('SessionType')
10
+
11
+ @dataclass
12
+ class BrowserInfrastructureContext(Generic[ClientType, SessionType]):
13
+ """Runtime context for an active browser infrastructure session."""
14
+ client: ClientType
15
+ session: SessionType
16
+ session_id: str
17
+ streaming_url: str
18
+ metadata: dict[str, Any] = field(default_factory=dict)
19
+
20
+ class BrowserInfrastructure(ABC, Generic[ClientType, SessionType]):
21
+ """Abstract contract for browser infrastructure providers.
22
+
23
+ Provider-specific configuration (API keys, endpoints, timeouts) belongs to
24
+ the concrete subclass; this base only defines the behavioral surface.
25
+ """
26
+ @property
27
+ @abstractmethod
28
+ def provider(self) -> str:
29
+ """Return the human-readable infrastructure provider name."""
30
+ @property
31
+ def supports_recording(self) -> bool:
32
+ """Whether this infrastructure can produce session recordings."""
33
+ @abstractmethod
34
+ async def create_session(self) -> BrowserInfrastructureContext[ClientType, SessionType]:
35
+ """Create a new browser infrastructure session and return the active context."""
36
+ @abstractmethod
37
+ async def release_session(self, context: BrowserInfrastructureContext[ClientType, SessionType]) -> None:
38
+ """Release or dispose browser infrastructure session resources."""
39
+ @abstractmethod
40
+ def cdp_url(self, session_id: str) -> str:
41
+ """Build a CDP endpoint URL for the provided browser infrastructure session ID."""
42
+ def recording_filename(self, session_id: str) -> str:
43
+ """Return the preferred recording object name for the provided browser infrastructure session ID."""
44
+ def resolve_recording_url(self, session_id: str, storage: ObjectStorage | None) -> str | None:
45
+ """Resolve a recording URL from storage without scheduling any new work."""
46
+ def can_record(self, context: BrowserInfrastructureContext[ClientType, SessionType] | None, storage: ObjectStorage | None) -> bool:
47
+ '''Return True when an active recording can be produced for ``context``.
48
+
49
+ This encapsulates the "recording is supported, a live context exists,
50
+ and storage is available" check that clients use before scheduling a
51
+ recording or resolving a recording URL.
52
+ '''
53
+ @abstractmethod
54
+ def schedule_recording(self, context: BrowserInfrastructureContext[ClientType, SessionType], storage: ObjectStorage | None) -> None:
55
+ """Optionally schedule background recording for the provided context."""
@@ -0,0 +1,55 @@
1
+ from _typeshed import Incomplete
2
+ from datetime import timedelta
3
+ from gl_browser_use.infrastructure.base import BrowserInfrastructure, BrowserInfrastructureContext
4
+ from gl_browser_use.storage.base import ObjectStorage
5
+ from opensandbox.sandbox import Sandbox
6
+
7
+ __all__ = ['DEFAULT_OPENSANDBOX_DOMAIN', 'DEFAULT_OPENSANDBOX_IMAGE', 'OpenSandboxBrowserInfrastructure', '_build_novnc_url', '_extract_browser_id', '_fetch_web_socket_debugger_url', '_parse_domain', '_rewrite_cdp_url']
8
+
9
+ DEFAULT_OPENSANDBOX_DOMAIN: str
10
+ DEFAULT_OPENSANDBOX_IMAGE: str
11
+
12
+ def _parse_domain(raw: str | None) -> tuple[str, str]:
13
+ """Return ``(protocol, domain)`` from a domain string or URL."""
14
+ def _fetch_web_socket_debugger_url(devtools_endpoint: str, *, protocol: str, poll_timeout_s: float = ..., poll_interval_s: float = ...) -> str:
15
+ """Poll DevTools ``/json/version`` until ``webSocketDebuggerUrl`` is available."""
16
+ def _extract_browser_id(web_socket_debugger_url: str) -> str: ...
17
+ def _rewrite_cdp_url(devtools_endpoint: str, browser_id: str, ws_protocol: str) -> str: ...
18
+ def _build_novnc_url(novnc_endpoint: str, http_protocol: str) -> str:
19
+ """Build a noVNC URL that auto-connects to the sandbox VNC stream."""
20
+
21
+ class OpenSandboxBrowserInfrastructure(BrowserInfrastructure[Sandbox, Sandbox]):
22
+ """Concrete OpenSandbox implementation for browser infrastructure sessions."""
23
+ domain: Incomplete
24
+ protocol: Incomplete
25
+ api_key: Incomplete
26
+ use_server_proxy: Incomplete
27
+ image: Incomplete
28
+ entrypoint: Incomplete
29
+ timeout: Incomplete
30
+ devtools_poll_timeout_s: Incomplete
31
+ def __init__(self, *, domain: str | None = None, api_key: str | None = None, protocol: str | None = None, use_server_proxy: bool | None = None, image: str = ..., entrypoint: list[str] | None = None, timeout: timedelta = ..., devtools_poll_timeout_s: float = ...) -> None:
32
+ """Initialize OpenSandbox browser infrastructure.
33
+
34
+ ``domain`` defaults to ``OPENSANDBOX_DOMAIN`` or ``localhost:8080``.
35
+ ``api_key`` defaults to ``OPENSANDBOX_API_KEY``.
36
+ """
37
+ @property
38
+ def provider(self) -> str:
39
+ """Return the human-readable infrastructure provider name."""
40
+ @property
41
+ def supports_recording(self) -> bool:
42
+ """Whether Playwright-based noVNC recording is available."""
43
+ async def create_session(self) -> BrowserInfrastructureContext[Sandbox, Sandbox]:
44
+ """Create a new OpenSandbox session and return the active context."""
45
+ async def release_session(self, context: BrowserInfrastructureContext[Sandbox, Sandbox]) -> None:
46
+ """Release OpenSandbox resources.
47
+
48
+ Stops an orphaned recorder when recording was started but never scheduled.
49
+ """
50
+ def cdp_url(self, session_id: str) -> str:
51
+ """Build a CDP endpoint URL for the provided session ID."""
52
+ def recording_filename(self, session_id: str) -> str:
53
+ """Return the preferred recording object name for the provided session ID."""
54
+ def schedule_recording(self, context: BrowserInfrastructureContext[Sandbox, Sandbox], storage: ObjectStorage | None) -> None:
55
+ """Stop the recorder and schedule background upload to object storage."""
@@ -0,0 +1,22 @@
1
+ import threading
2
+ from gl_browser_use.storage.base import ObjectStorage
3
+
4
+ __all__ = ['PlaywrightRecorder', 'is_playwright_available']
5
+
6
+ def is_playwright_available() -> bool:
7
+ """Return True when Playwright is installed."""
8
+
9
+ class PlaywrightRecorder:
10
+ """Record a noVNC page in headless Chromium and upload to object storage."""
11
+ def __init__(self) -> None: ...
12
+ async def start(self, novnc_url: str, width: int = 1280, height: int = 1024) -> None:
13
+ """Open the noVNC URL and start recording."""
14
+ async def stop(self) -> tuple[bytes, str] | None:
15
+ """Stop recording and return WebM bytes."""
16
+ async def stop_and_upload(self, storage: ObjectStorage, object_name: str) -> str | None:
17
+ """Stop recording, upload WebM via object storage, and return the remote name."""
18
+ async def stop_best_effort(self) -> tuple[bytes, str] | None:
19
+ """Stop recording, suppressing errors."""
20
+ @classmethod
21
+ def schedule_stop_and_upload_in_background(cls, recorder: PlaywrightRecorder, storage: ObjectStorage | None, object_name: str, *, session_id: str = '') -> threading.Thread | None:
22
+ """Finalize Playwright on the event loop and upload in a background thread."""
@@ -0,0 +1,12 @@
1
+ from os import PathLike
2
+
3
+ __all__ = ['cleanup_temp_directory', 'recording_filename', 'safe_session_id', 'RECORDING_FILENAME_PREFIX']
4
+
5
+ RECORDING_FILENAME_PREFIX: str
6
+
7
+ def safe_session_id(session_id: str) -> str:
8
+ """Return a storage-safe session identifier."""
9
+ def recording_filename(session_id: str, extension: str = '.mp4') -> str:
10
+ """Return the preferred recording file name for a session ID."""
11
+ def cleanup_temp_directory(path: str | bytes | PathLike[str] | PathLike[bytes]) -> None:
12
+ """Remove a temporary recording directory, ignoring missing paths."""
@@ -0,0 +1,52 @@
1
+ import threading
2
+ from _typeshed import Incomplete
3
+ from gl_browser_use.infrastructure.base import BrowserInfrastructure, BrowserInfrastructureContext
4
+ from gl_browser_use.storage.base import ObjectStorage
5
+ from steel import Steel
6
+ from steel.types.session import Session
7
+
8
+ __all__ = ['SteelBrowserInfrastructure']
9
+
10
+ class _SteelSessionRecorder:
11
+ """Capture Steel HLS sessions and upload recordings to object storage."""
12
+ base_url: Incomplete
13
+ api_key: Incomplete
14
+ storage: Incomplete
15
+ def __init__(self, base_url: str, api_key: str, *, storage: ObjectStorage | None = None) -> None: ...
16
+ async def record_session_to_video(self, session_id: str) -> bool: ...
17
+ @classmethod
18
+ def schedule_recording_in_background(cls, session_id: str, base_url: str, api_key: str, storage: ObjectStorage | None) -> threading.Thread | None: ...
19
+
20
+ class SteelBrowserInfrastructure(BrowserInfrastructure[Steel, Session]):
21
+ """Concrete Steel implementation for browser infrastructure sessions."""
22
+ api_key: Incomplete
23
+ base_url: Incomplete
24
+ ws_url: Incomplete
25
+ timeout_in_ms: Incomplete
26
+ def __init__(self, api_key: str | None = None, base_url: str = ..., ws_url: str = ..., timeout_in_ms: int = ...) -> None:
27
+ """Initialize the Steel browser infrastructure.
28
+
29
+ ``api_key`` defaults to the ``STEEL_API_KEY`` environment variable
30
+ resolved at construction time (not import time) when not provided.
31
+ """
32
+ @property
33
+ def provider(self) -> str:
34
+ """Return the human-readable infrastructure provider name."""
35
+ @property
36
+ def supports_recording(self) -> bool:
37
+ """Whether this infrastructure can produce session recordings.
38
+
39
+ ``True`` indicates Steel supports recording. Recording is only
40
+ actually started when an available :class:`ObjectStorage` is also
41
+ provided to the :class:`BrowserUseClient`.
42
+ """
43
+ async def create_session(self) -> BrowserInfrastructureContext[Steel, Session]:
44
+ """Create a new Steel session and return the active context."""
45
+ async def release_session(self, context: BrowserInfrastructureContext[Steel, Session]) -> None:
46
+ """Release or dispose Steel session resources."""
47
+ def cdp_url(self, session_id: str) -> str:
48
+ """Build a CDP endpoint URL for the provided Steel session ID."""
49
+ def recording_filename(self, session_id: str) -> str:
50
+ """Return the preferred recording object name for the provided Steel session ID."""
51
+ def schedule_recording(self, context: BrowserInfrastructureContext[Steel, Session], storage: ObjectStorage | None) -> None:
52
+ """Schedule background recording for the provided context."""
@@ -0,0 +1,32 @@
1
+ from _typeshed import Incomplete
2
+ from dataclasses import dataclass, field
3
+ from typing import Any
4
+
5
+ BrowserUseRunStatus: Incomplete
6
+
7
+ @dataclass(frozen=True)
8
+ class BrowserUseStreamEvent:
9
+ """Structured stream event emitted during ``BrowserUseClient`` execution."""
10
+ event_type: str
11
+ content: str
12
+ thinking_and_activity_info: dict[str, Any] = field(default_factory=dict)
13
+ is_final: bool = ...
14
+ tool_info: dict[str, Any] | None = ...
15
+ metadata: dict[str, Any] | None = ...
16
+
17
+ @dataclass(frozen=True)
18
+ class BrowserUseRunResult:
19
+ """Final result returned for a completed run."""
20
+ status: BrowserUseRunStatus
21
+ task: str
22
+ final_output: str
23
+ session_id: str | None = ...
24
+ streaming_url: str | None = ...
25
+ recording_url: str | None = ...
26
+ steps: int = ...
27
+ error: str | None = ...
28
+ events: list[BrowserUseStreamEvent] = field(default_factory=list)
29
+ metadata: dict[str, Any] = field(default_factory=dict)
30
+ @property
31
+ def is_success(self) -> bool:
32
+ """Return True if the run was successful."""
@@ -0,0 +1,41 @@
1
+ from browser_use import Agent
2
+ from dataclasses import dataclass
3
+ from typing import Any
4
+
5
+ __all__ = ['ToolCall', 'coerce_string', 'extract_final_output', 'extract_outputs', 'extract_tool_calls', 'parse_structured_data', 'read_tool_call', 'summarize_terminal_error', 'validate_structured_data_output']
6
+
7
+ def coerce_string(value: Any) -> str:
8
+ '''Return a stable ``str`` representation of ``value`` (``None`` becomes ``""``).'''
9
+ def summarize_terminal_error(error_message: str, *, max_length: int = 200) -> str:
10
+ """Collapse whitespace in ``error_message`` and truncate to ``max_length`` characters."""
11
+
12
+ @dataclass
13
+ class ToolCall:
14
+ """Normalized tool-call snapshot extracted from the underlying agent state."""
15
+ name: str
16
+ args: dict[str, Any]
17
+ output: str = ...
18
+
19
+ def read_tool_call(call: Any) -> tuple[str, dict[str, Any], str]:
20
+ """Return a ``(name, args, output)`` triple for a tool call of any supported shape.
21
+
22
+ ``name`` may be an empty string when the underlying payload is missing
23
+ a name; callers requiring a fallback label should apply one explicitly.
24
+ """
25
+ def extract_outputs(last_result: list[Any]) -> list[str]:
26
+ """Return one display string per entry in ``last_result``."""
27
+ def extract_tool_calls(agent: Agent) -> list[ToolCall]:
28
+ """Extract serialized tool-call snapshots from the agent's last model output."""
29
+ def extract_final_output(agent: Agent) -> str:
30
+ """Return the final textual output from the agent, or an empty string if absent."""
31
+ def parse_structured_data(output: str) -> tuple[dict[str, Any] | list[Any] | None, str | None]:
32
+ """Parse the ``Extracted Content:`` block in ``output`` with fallback recovery.
33
+
34
+ The parser (1) trims trailers and slices from the first ``{``/``[``;
35
+ (2) attempts a direct ``json.loads``; (3) attempts to recover
36
+ concatenated top-level JSON objects; (4) extracts a balanced-prefix
37
+ JSON value with a depth-aware scanner that respects string literals
38
+ and parses it; and finally (5) falls back to ``json_repair.repair_json``.
39
+ """
40
+ def validate_structured_data_output(tool_calls: list[ToolCall]) -> str | None:
41
+ """Return a user-facing error when structured data extraction failed or yielded no usable entries."""
@@ -0,0 +1,35 @@
1
+ from _typeshed import Incomplete
2
+ from typing import Any
3
+
4
+ __all__ = ['extract_balanced_json_value', 'recover_concatenated_json_objects', 'repair_json_blob']
5
+
6
+ def extract_balanced_json_value(text: str) -> str | None:
7
+ """Return the first balanced JSON value found in ``text`` (respecting string literals).
8
+
9
+ Returns ``None`` when no ``{``/``[`` is found or when the scan never
10
+ closes cleanly (unbalanced, truncated, or ends inside a string).
11
+ """
12
+ def recover_concatenated_json_objects(json_blob: str) -> dict[str, Any] | None:
13
+ """Normalize concatenated JSON object strings into a single structured payload.
14
+
15
+ Returns ``None`` if ``json_blob`` does not contain multiple top-level JSON
16
+ objects or they cannot be parsed individually.
17
+ """
18
+ def repair_json_blob(json_blob: str) -> str | None:
19
+ """Apply ``json_repair.repair_json`` to ``json_blob`` and return the mutated payload.
20
+
21
+ Returns ``None`` when ``json_repair`` could not repair the input or when
22
+ the repair produced no changes.
23
+ """
24
+
25
+ class _JsonObjectSplitter:
26
+ """Split concatenated top-level JSON objects while respecting string literals."""
27
+ json_blob: Incomplete
28
+ segments: list[str]
29
+ depth: int
30
+ start: int | None
31
+ last_end: int
32
+ in_string: bool
33
+ escaping: bool
34
+ def __init__(self, json_blob: str) -> None: ...
35
+ def split_objects(self) -> list[str]: ...
@@ -0,0 +1,16 @@
1
+ from dataclasses import dataclass
2
+
3
+ __all__ = ['SessionErrorCategory', 'categorize_fatal_session_message', 'is_recoverable_session_error']
4
+
5
+ @dataclass(frozen=True)
6
+ class SessionErrorCategory:
7
+ """Session error classification for retry decisions."""
8
+ name: str
9
+ markers: tuple[str, ...]
10
+ fatal: bool
11
+ retryable: bool
12
+
13
+ def categorize_fatal_session_message(message: str) -> SessionErrorCategory | None:
14
+ """Return the matching :class:`SessionErrorCategory` for ``message`` or ``None``."""
15
+ def is_recoverable_session_error(message: str) -> bool:
16
+ """Return True when ``message`` matches a recoverable session-failure category."""
@@ -0,0 +1,6 @@
1
+ from gl_browser_use.storage.base import OBJECT_NAME_PREFIX as OBJECT_NAME_PREFIX, ObjectStorage as ObjectStorage
2
+
3
+ __all__ = ['OBJECT_NAME_PREFIX', 'ObjectStorage', 'MinIOS3CompatibleStorage']
4
+
5
+ # Names in __all__ with no definition:
6
+ # MinIOS3CompatibleStorage
@@ -0,0 +1,46 @@
1
+ from _typeshed import Incomplete
2
+ from abc import ABC, abstractmethod
3
+
4
+ __all__ = ['ObjectStorage', 'OBJECT_NAME_PREFIX']
5
+
6
+ OBJECT_NAME_PREFIX: str
7
+
8
+ class ObjectStorage(ABC):
9
+ """Abstract contract for object storage providers."""
10
+ endpoint: Incomplete
11
+ access_key: Incomplete
12
+ secret_key: Incomplete
13
+ bucket_name: Incomplete
14
+ directory_prefix: Incomplete
15
+ secure: Incomplete
16
+ def __init__(self, *, endpoint: str | None = None, access_key: str | None = None, secret_key: str | None = None, bucket_name: str | None = None, directory_prefix: str | None = None, secure: bool | None = None) -> None:
17
+ """Initialize the object storage.
18
+
19
+ Raises:
20
+ ------
21
+ BrowserUseConfigurationError
22
+ When any of ``endpoint``, ``access_key``, ``secret_key`` or
23
+ ``bucket_name`` is missing from both the arguments and the
24
+ corresponding ``OBJECT_STORAGE_*`` environment variable.
25
+ """
26
+ @property
27
+ @abstractmethod
28
+ def provider(self) -> str:
29
+ """Return the human-readable storage provider name."""
30
+ @property
31
+ def is_available(self) -> bool:
32
+ """Whether this storage provider is currently available."""
33
+ @property
34
+ def last_error(self) -> str | None:
35
+ """Return the last error encountered during client initialization or operation."""
36
+ @classmethod
37
+ def from_environment(cls) -> ObjectStorage:
38
+ """Create a storage instance from environment variables."""
39
+ def resolve_object_name(self, object_name: str) -> str:
40
+ """Return the effective remote object name."""
41
+ @abstractmethod
42
+ def upload_file(self, file_path: str, object_name: str) -> str | None:
43
+ """Upload a file and optionally return the stored object name."""
44
+ @abstractmethod
45
+ def get_file_url(self, object_name: str) -> str | None:
46
+ """Return an object URL when available."""
@@ -0,0 +1,15 @@
1
+ from gl_browser_use.storage.base import ObjectStorage
2
+
3
+ __all__ = ['MinIOS3CompatibleStorage']
4
+
5
+ class MinIOS3CompatibleStorage(ObjectStorage):
6
+ """Concrete S3-compatible storage implemented with MinIO."""
7
+ def __init__(self, *, endpoint: str | None = None, access_key: str | None = None, secret_key: str | None = None, bucket_name: str | None = None, directory_prefix: str | None = None, secure: bool | None = None) -> None:
8
+ """Initialize the MinIO/S3-compatible storage."""
9
+ @property
10
+ def provider(self) -> str:
11
+ """Return the human-readable storage provider name."""
12
+ def upload_file(self, file_path: str, object_name: str) -> str | None:
13
+ """Upload a file and optionally return the stored object name."""
14
+ def get_file_url(self, object_name: str) -> str | None:
15
+ """Return an object URL when available."""
Binary file
gl_browser_use.pyi ADDED
@@ -0,0 +1,83 @@
1
+ # This file was generated by Nuitka
2
+
3
+ # Stubs included by default
4
+ from __future__ import annotations
5
+ from __future__ import annotations
6
+ from gl_browser_use.client import BrowserUseClient
7
+ from gl_browser_use.config import BrowserUseClientConfig
8
+ from gl_browser_use.errors import BrowserUseConfigurationError, BrowserUseDependencyError, BrowserUseExecutionError, BrowserUseMissingDependencyError, BrowserUseRetryExhaustedError, BrowserUseSDKError
9
+ from gl_browser_use.infrastructure import __getattr__
10
+ from gl_browser_use.infrastructure.base import BrowserInfrastructure, BrowserInfrastructureContext
11
+ from gl_browser_use.models import BrowserUseRunResult, BrowserUseStreamEvent
12
+ from gl_browser_use.storage import __getattr__
13
+ from gl_browser_use.storage.base import ObjectStorage
14
+ from typing import Any
15
+
16
+ __all__ = ['BrowserUseClient', 'BrowserUseClientConfig', 'BrowserUseConfigurationError', 'BrowserUseDependencyError', 'BrowserUseExecutionError', 'BrowserUseMissingDependencyError', 'BrowserUseRetryExhaustedError', 'BrowserUseSDKError', 'BrowserUseRunResult', 'BrowserUseStreamEvent', 'BrowserInfrastructure', 'BrowserInfrastructureContext', 'SteelBrowserInfrastructure', 'ObjectStorage', 'MinIOS3CompatibleStorage']
17
+ def __getattr__(name: str) -> Any:
18
+ ...
19
+
20
+ def __dir__() -> list[str]:
21
+ ...
22
+
23
+ __version__ = '0.1.0'
24
+
25
+ __name__ = ...
26
+
27
+
28
+
29
+ # Modules used internally, to allow implicit dependencies to be seen:
30
+ import os
31
+ import __future__
32
+ import gl_browser_use.infrastructure.__getattr__
33
+ import gl_browser_use.storage.__getattr__
34
+ import asyncio
35
+ import contextlib
36
+ import copy
37
+ import dataclasses
38
+ import inspect
39
+ import logging
40
+ import time
41
+ import collections
42
+ import collections.abc
43
+ import typing
44
+ import browser_use
45
+ import browser_use.agent
46
+ import browser_use.agent.cloud_events
47
+ import browser_use.agent.views
48
+ import browser_use.browser
49
+ import browser_use.llm
50
+ import browser_use.logging_config
51
+ import bubus
52
+ import openai
53
+ import openai.types
54
+ import openai.types.shared_params
55
+ import openai.types.shared_params.chat_model
56
+ import openai.types.shared_params.reasoning_effort
57
+ import urllib
58
+ import urllib.parse
59
+ import pydantic
60
+ import json
61
+ import textwrap
62
+ import abc
63
+ import re
64
+ import datetime
65
+ import requests
66
+ import opensandbox
67
+ import opensandbox.config
68
+ import opensandbox.sandbox
69
+ import tempfile
70
+ import threading
71
+ import pathlib
72
+ import pathlib.Path
73
+ import importlib
74
+ import playwright
75
+ import playwright.async_api
76
+ import shutil
77
+ import io
78
+ import steel
79
+ import steel.types
80
+ import steel.types.session
81
+ import json_repair
82
+ import mimetypes
83
+ import minio
@@ -0,0 +1,287 @@
1
+ Metadata-Version: 2.2
2
+ Name: gl-browser-use-binary
3
+ Version: 0.0.0b9
4
+ Summary: A typed Python SDK for running browser automation tasks through `browser-use`
5
+ Author-email: Reinhart Linanda <reinhart.linanda@gdplabs.id>
6
+ Requires-Python: <3.14,>=3.11
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: browser-use<0.12.0,>=0.11.13
9
+ Requires-Dist: json-repair<0.61.0,>=0.60.1
10
+ Requires-Dist: pydantic<3.0.0,>=2.11.7
11
+ Requires-Dist: requests<3.0.0,>=2.32.4
12
+ Requires-Dist: pydantic-settings<3.0.0,>=2.5.2
13
+ Provides-Extra: steel
14
+ Requires-Dist: steel-sdk<0.17.0,>=0.16.0; extra == "steel"
15
+ Provides-Extra: opensandbox
16
+ Requires-Dist: opensandbox<0.2.0,>=0.1.9; extra == "opensandbox"
17
+ Requires-Dist: playwright<2.0.0,>=1.40.0; extra == "opensandbox"
18
+ Provides-Extra: infrastructure
19
+ Requires-Dist: gl-browser-use-binary[opensandbox,steel]; extra == "infrastructure"
20
+ Provides-Extra: minio
21
+ Requires-Dist: minio<8.0.0,>=7.2.20; extra == "minio"
22
+ Provides-Extra: storage
23
+ Requires-Dist: gl-browser-use-binary[minio]; extra == "storage"
24
+ Provides-Extra: full
25
+ Requires-Dist: gl-browser-use-binary[infrastructure,storage]; extra == "full"
26
+
27
+ # GL Browser Use
28
+
29
+ GL Browser Use is a typed Python SDK for running browser automation tasks through `browser-use`. It provides a stable client facade, structured stream events, explicit result objects, optional Steel or OpenSandbox browser infrastructure, optional MinIO/S3-compatible recording storage, and bounded retries for recoverable browser-session failures.
30
+
31
+ ## Installation
32
+
33
+ Install the core SDK:
34
+
35
+ ```bash
36
+ pip install gl-browser-use
37
+ ```
38
+
39
+ Install optional providers only when you need them:
40
+
41
+ ```bash
42
+ pip install "gl-browser-use[steel]" # Steel browser infrastructure
43
+ pip install "gl-browser-use[opensandbox]" # OpenSandbox browser infrastructure
44
+ pip install "gl-browser-use[infrastructure]" # All browser infrastructure providers
45
+ pip install "gl-browser-use[minio]" # MinIO/S3-compatible object storage
46
+ pip install "gl-browser-use[storage]" # All object storage providers
47
+ pip install "gl-browser-use[full]" # Infrastructure + storage providers
48
+ ```
49
+
50
+ Use the concrete extras (`steel`, `opensandbox`, `minio`) in application dependency files when you want to pin exactly which provider you depend on. The slot extras (`infrastructure`, `storage`, `full`) are convenience aliases and may include more providers later.
51
+
52
+ ## Quick Start
53
+
54
+ `BrowserUseClient` supports streaming and non-streaming execution. API keys can be passed directly or read from environment variables.
55
+
56
+ ```python
57
+ import asyncio
58
+
59
+ from gl_browser_use import BrowserUseClient, BrowserUseClientConfig
60
+ from gl_browser_use.infrastructure import SteelBrowserInfrastructure
61
+ from gl_browser_use.storage import MinIOS3CompatibleStorage
62
+
63
+
64
+ async def main() -> None:
65
+ client = BrowserUseClient(
66
+ config=BrowserUseClientConfig(
67
+ llm_openai_api_key="...",
68
+ page_extraction_llm_openai_api_key="...",
69
+ max_session_retries=2,
70
+ session_retry_delay_in_s=3.0,
71
+ ),
72
+ infrastructure=SteelBrowserInfrastructure(), # reads STEEL_API_KEY by default
73
+ storage=MinIOS3CompatibleStorage.from_environment(),
74
+ )
75
+
76
+ async for event in client.run("Open Hacker News and list five article titles"):
77
+ print(event.content)
78
+
79
+
80
+ asyncio.run(main())
81
+ ```
82
+
83
+ For a single aggregated result:
84
+
85
+ ```python
86
+ from gl_browser_use import BrowserUseClient, BrowserUseClientConfig
87
+ from gl_browser_use.infrastructure import SteelBrowserInfrastructure
88
+
89
+ client = BrowserUseClient(
90
+ config=BrowserUseClientConfig(
91
+ llm_openai_api_key="...",
92
+ page_extraction_llm_openai_api_key="...",
93
+ ),
94
+ infrastructure=SteelBrowserInfrastructure(),
95
+ )
96
+
97
+ result = client.run_sync("Open Hacker News and list five article titles")
98
+
99
+ print(result.status)
100
+ print(result.final_output)
101
+ print(result.session_id)
102
+ print(result.streaming_url)
103
+ print(result.recording_url)
104
+ print(result.metadata)
105
+ ```
106
+
107
+ ## Configuration
108
+
109
+ `BrowserUseClientConfig` validates required values when the client is created. If `llm_openai_api_key` or `page_extraction_llm_openai_api_key` is not passed, both default to `OPENAI_API_KEY`.
110
+
111
+ Common client options:
112
+
113
+ 1. `llm_openai_model`: primary browser-control model. Default: `o3`.
114
+ 2. `page_extraction_llm_openai_model`: page extraction model. Default: `gpt-5-mini`.
115
+ 3. `sensitive_data`: optional browser-use placeholder map. It accepts either a flat
116
+ placeholder-to-value map or a domain-scoped map. Values are excluded from normal
117
+ config serialization and redacted from `redacted_dict()` output.
118
+ 4. `extend_system_message`: optional system prompt extension.
119
+ 5. `vision_detail_level`: `auto`, `low`, or `high`. Default: `auto`.
120
+ 6. `llm_timeout_in_s`: optional LLM timeout.
121
+ 7. `step_timeout_in_s`: per-step browser timeout. Default: `180`.
122
+ 8. `agent_kwargs`: additional `browser_use.Agent` constructor arguments. It cannot
123
+ override SDK-managed arguments such as the task, LLMs, browser session, `sensitive_data`,
124
+ or timeouts.
125
+ 9. `enable_cloud_sync`: controls `browser-use` cloud sync. Default: `False`.
126
+ 10. `logging_level`: `debug`, `info`, `warning`, `error`, or `result`. Default: `info`.
127
+ 11. `max_session_retries`: recoverable session retries. Default: `2`.
128
+ 12. `session_retry_delay_in_s`: delay between retries. Default: `3.0`.
129
+
130
+ ### Sensitive data and Agent options
131
+
132
+ ```python
133
+ config = BrowserUseClientConfig(
134
+ llm_openai_api_key="...",
135
+ page_extraction_llm_openai_api_key="...",
136
+ sensitive_data={"username": "example-user", "password": "example-password"},
137
+ agent_kwargs={"use_vision": False, "max_actions_per_step": 2},
138
+ )
139
+ ```
140
+
141
+ Keep one configured client per credential scope. Browser-use also accepts domain-scoped
142
+ `sensitive_data` maps. Never put real values in logs, serialized configuration, or
143
+ `agent_kwargs`.
144
+
145
+ When supplying sensitive data, restrict browser navigation to the expected domains (for
146
+ example, through the infrastructure session's browser-use `BrowserProfile(allowed_domains=...)`)
147
+ to reduce prompt-injection exfiltration risk. `agent_kwargs` cannot override browser/session
148
+ ownership (`browser`, `browser_profile`, and `browser_session` are reserved); configure those
149
+ controls through the selected infrastructure instead.
150
+
151
+ Optional provider environment variables:
152
+
153
+ 1. `STEEL_API_KEY`: used by `SteelBrowserInfrastructure()` when `api_key` is not passed.
154
+ 2. `OPENSANDBOX_DOMAIN`: OpenSandbox control-plane host. Default: `localhost:8080`.
155
+ 3. `OPENSANDBOX_API_KEY`: required for shared OpenSandbox clusters; optional for local insecure servers.
156
+ 4. `OBJECT_STORAGE_URL`: MinIO/S3 endpoint, for example `localhost:9001` or `https://storage.example`.
157
+ 5. `OBJECT_STORAGE_USERNAME`: object storage access key.
158
+ 6. `OBJECT_STORAGE_PASSWORD`: object storage secret key.
159
+ 7. `OBJECT_STORAGE_BUCKET_NAME`: target bucket name.
160
+ 8. `OBJECT_STORAGE_DIRECTORY_PREFIX`: optional object key prefix.
161
+ 9. `OBJECT_STORAGE_SECURE`: `true` for HTTPS when the endpoint has no scheme.
162
+
163
+ Copy `.env.example` to `.env` for local development, then load it with your application environment manager.
164
+
165
+ ## Runtime API
166
+
167
+ The client exposes three run methods:
168
+
169
+ 1. `run(task)`: async generator that yields `BrowserUseStreamEvent` values as work progresses.
170
+ 2. `run_once(task)`: async method that returns one `BrowserUseRunResult` and includes emitted events in `result.events`.
171
+ 3. `run_sync(task)`: blocking wrapper around `run_once()` using `asyncio.run()`.
172
+
173
+ Do not call `run_sync()` from an already running event loop. Use `await run_once()` or `async for event in run()` in async applications.
174
+
175
+ Cancelling the stream by breaking from `async for` or calling `await stream.aclose()` cancels the underlying run task. Browser sessions and infrastructure sessions are released in cleanup.
176
+
177
+ ## Result Contract
178
+
179
+ `BrowserUseRunResult` contains:
180
+
181
+ 1. `status`: `success`, `error`, or `cancelled`.
182
+ 2. `task`: normalized task string.
183
+ 3. `final_output`: final text extracted from the underlying agent, or `Task completed` when no final text is available.
184
+ 4. `session_id`: infrastructure session ID when an external browser session was used.
185
+ 5. `streaming_url`: browser debug or streaming URL when available.
186
+ 6. `recording_url`: expected recording URL when recording is configured.
187
+ 7. `steps`: number of browser-use steps executed.
188
+ 8. `error`: terminal error message for error results.
189
+ 9. `events`: collected stream events for `run_once()`.
190
+ 10. `metadata`: attempt, retry, and recording metadata.
191
+
192
+ Recording metadata uses these statuses:
193
+
194
+ 1. `disabled`: infrastructure, storage, or browser context is not available.
195
+ 2. `unsupported`: the selected infrastructure does not support recording.
196
+ 3. `unavailable`: storage is configured but not available.
197
+ 4. `scheduled`: a background recording upload has been scheduled.
198
+ 5. `unknown`: recording may have started, but the terminal error did not include enough context to determine the final state.
199
+
200
+ ## Streaming Contract
201
+
202
+ `BrowserUseStreamEvent` contains:
203
+
204
+ 1. `event_type`
205
+ 2. `content`
206
+ 3. `thinking_and_activity_info`
207
+ 4. `is_final`
208
+ 5. `tool_info`
209
+ 6. `metadata`
210
+
211
+ Important event content values:
212
+
213
+ 1. `Receive streaming URL`: emitted when a browser debug or streaming URL is available.
214
+ 2. `Receive recording URL`: emitted when a recording URL can be resolved.
215
+ 3. `Task completed`: emitted for the final successful step.
216
+
217
+ Activity events encode iframe URLs in `thinking_and_activity_info["data_value"]` as a JSON string:
218
+
219
+ ```json
220
+ {"type": "iframe", "message": "<url>"}
221
+ ```
222
+
223
+ Step events include serialized tool calls in `tool_info["tool_calls"]`.
224
+
225
+ ## Retries And Errors
226
+
227
+ The client retries only classified recoverable browser-session failures, such as browser closure or websocket disconnect messages. Before each retry, it emits a retry status event. Retries are bounded by `max_session_retries`, so total attempts are `max_session_retries + 1`.
228
+
229
+ Non-recoverable task failures return `BrowserUseRunResult(status="error")`. Recoverable failures that exhaust all attempts raise `BrowserUseRetryExhaustedError`.
230
+
231
+ SDK error types:
232
+
233
+ 1. `BrowserUseConfigurationError`: missing or invalid runtime configuration.
234
+ 2. `BrowserUseDependencyError`: optional provider dependency problem.
235
+ 3. `BrowserUseMissingDependencyError`: optional provider extra is not installed.
236
+ 4. `BrowserUseExecutionError`: execution-time failure.
237
+ 5. `BrowserUseRetryExhaustedError`: recoverable session retries were exhausted.
238
+
239
+ ## Optional Providers
240
+
241
+ Optional providers are lazy-loaded. Importing `gl_browser_use` does not require Steel, OpenSandbox, or MinIO to be installed.
242
+
243
+ ```python
244
+ from gl_browser_use.infrastructure import OpenSandboxBrowserInfrastructure, SteelBrowserInfrastructure
245
+ from gl_browser_use.storage import MinIOS3CompatibleStorage
246
+ ```
247
+
248
+ `SteelBrowserInfrastructure` creates Steel browser sessions and provides CDP/streaming URLs.
249
+
250
+ `OpenSandboxBrowserInfrastructure` provisions the repo-committed Chrome example image (`opensandbox/chrome:latest`, built from `examples/opensandbox/chrome`) through a local or shared OpenSandbox server, exposes noVNC inspection URLs, connects over proxied CDP, and uploads WebM session recordings to object storage with the same deferred `recording_url` semantics as Steel. Pass `storage` to `BrowserUseClient` when recording is enabled.
251
+
252
+ **DevTools note:** the Chrome image exposes CDP on `0.0.0.0:9222` (`--remote-debugging-address=0.0.0.0` plus a `socat` forward for Chromium M113+). Rebuild from `examples/opensandbox/chrome` after pulling changes; the SDK discovers CDP via `sandbox.get_endpoint(9222)`. See `examples/opensandbox/chrome/README.md`.
253
+
254
+ OpenSandbox local setup:
255
+
256
+ ```bash
257
+ DOCKER_HOST=unix://${HOME}/.docker/desktop/docker.sock \
258
+ OPENSANDBOX_INSECURE_SERVER=YES opensandbox-server
259
+
260
+ cd libs/gl-browser-use/examples/opensandbox/chrome
261
+ docker build -t opensandbox/chrome:latest .
262
+ playwright install chromium
263
+ ```
264
+
265
+ `MinIOS3CompatibleStorage` uploads session recordings to MinIO or an S3-compatible service and returns presigned URLs.
266
+
267
+ ## Development
268
+
269
+ From `libs/gl-browser-use`:
270
+
271
+ ```bash
272
+ make install-dev
273
+ make test-unit
274
+ make test-integration
275
+ make lint
276
+ make build-check
277
+ ```
278
+
279
+ Useful targets:
280
+
281
+ 1. `make test`: run all tests.
282
+ 2. `make test-unit`: run unit tests with coverage.
283
+ 3. `make test-integration`: run integration-marked contract tests.
284
+ 4. `make lint`: run Ruff checks.
285
+ 5. `make format`: run Ruff fixes and formatter.
286
+ 6. `make pre-commit`: run pre-commit hooks.
287
+ 7. `make build-check`: build the package and validate artifacts with Twine.
@@ -0,0 +1,24 @@
1
+ gl_browser_use.cp313-win_amd64.pyd,sha256=s7TpsZ6Ztus48T-JbV4Tg_h1SN7odRx-OHf9rLFn9Qo,959488
2
+ gl_browser_use.pyi,sha256=p6iz4o2Hs4jLimApvxcZRQUcSr8UOu4SdRBJLMU_gLM,2528
3
+ gl_browser_use/__init__.pyi,sha256=1uchB2q9Iq7GBPac_MQf4okzXalqcwNQeBUAVpXDU8E,1417
4
+ gl_browser_use/client.pyi,sha256=_UWgAWXn85NHNVSfUboJOxDRSUvg_F-xrz4-Zn_UBu8,3552
5
+ gl_browser_use/config.pyi,sha256=73-MZI978JcBtUgeyjUftry2pB4ReuBoz4RKuCpfps4,1974
6
+ gl_browser_use/errors.pyi,sha256=LlpVLDHEQCyqekY0Jq88iqjJgQuSzDsM1gGQBkeWUMw,2088
7
+ gl_browser_use/events.pyi,sha256=A7o-FcXn8FHbrxeIZqQ75byYo6OkUVYekaIrU-nVWiY,1888
8
+ gl_browser_use/models.pyi,sha256=KcNLDd6XPQqHa7Ccuf5ezfDsJuLkVFQNqk67SA1A_1A,1078
9
+ gl_browser_use/parsing.pyi,sha256=K14ptm7O5DgGRxtRxi-1SrKsMdm4XqzXhrBXeNE9V3w,2267
10
+ gl_browser_use/parsing_recovery.pyi,sha256=LCaHWb0oCSGgwPxEwG3z1f25UCLpb6y5WZnrXO7unMA,1416
11
+ gl_browser_use/session_errors.pyi,sha256=fQOcS7Gh2FSawL0VaIRICtCsd-3jdgJUAdExszWmwWU,662
12
+ gl_browser_use/infrastructure/__init__.pyi,sha256=AmrO_89UUoEn8Xe_tiDLZ38rFwDd3Xs-rOaM6EHCYZw,406
13
+ gl_browser_use/infrastructure/base.pyi,sha256=kLTlBvVwpQrStuoo5FfdE_VoG1qCfApEThvb8xC48g4,2817
14
+ gl_browser_use/infrastructure/opensandbox.pyi,sha256=Tj9tg7WMbRbne3qkcOsiVZYkfQ3ZrsIV9iBAg14OSDA,3234
15
+ gl_browser_use/infrastructure/playwright_recorder.pyi,sha256=A27qsALvrhmwAwtNqe4VxzGaqzT1DwrY7DWjGPNczzA,1227
16
+ gl_browser_use/infrastructure/recording_utils.pyi,sha256=pcaDHoN_HeKeyg7fSVLNIfgU6MkZNDp6QPJb5zoAXVk,579
17
+ gl_browser_use/infrastructure/steel.pyi,sha256=Rwu-BqKFNu1UR_u_bVIKzaT5tLheeXF_tG6vWePymtI,2726
18
+ gl_browser_use/storage/__init__.pyi,sha256=y1Yp7iB0WWc2sklofSSZe7xbUzbsBsm0K1OA9W_bnAY,267
19
+ gl_browser_use/storage/base.pyi,sha256=_V26BMVpbCqY4jqWLTKrgXhsQ9pQ3NCgXEd4WHrgHGc,1936
20
+ gl_browser_use/storage/minio_compatible.pyi,sha256=MQnQ1IxTnCx74uiBOlEdzs9BHf88YL37UFZZWTzoTag,871
21
+ gl_browser_use_binary-0.0.0b9.dist-info/METADATA,sha256=-MvHMUQdl_8ddPeFnwy6OnN8jUnEWyTdgFVgvIMZ1yg,12766
22
+ gl_browser_use_binary-0.0.0b9.dist-info/WHEEL,sha256=ikXeVivtRq-oqOZfN0jwm7M68yNYx-wxpXplGP7L4Is,97
23
+ gl_browser_use_binary-0.0.0b9.dist-info/top_level.txt,sha256=I3agYm4bLWMzPbZo_gLgMdmn91EFAXX-hziarvf9VWY,15
24
+ gl_browser_use_binary-0.0.0b9.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: Nuitka (2.8.10)
3
+ Root-Is-Purelib: false
4
+ Tag: cp313-cp313-win_amd64
5
+
@@ -0,0 +1 @@
1
+ gl_browser_use