gl-browser-use-binary 0.0.0b5__py3-none-any.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.
- gl_browser_use/__init__.py +60 -0
- gl_browser_use/__init__.pyi +12 -0
- gl_browser_use/client.py +639 -0
- gl_browser_use/client.pyi +57 -0
- gl_browser_use/config.py +169 -0
- gl_browser_use/config.pyi +42 -0
- gl_browser_use/errors.py +119 -0
- gl_browser_use/errors.pyi +40 -0
- gl_browser_use/events.py +147 -0
- gl_browser_use/events.pyi +29 -0
- gl_browser_use/infrastructure/__init__.py +39 -0
- gl_browser_use/infrastructure/__init__.pyi +6 -0
- gl_browser_use/infrastructure/base.py +103 -0
- gl_browser_use/infrastructure/base.pyi +56 -0
- gl_browser_use/infrastructure/steel.py +296 -0
- gl_browser_use/infrastructure/steel.pyi +56 -0
- gl_browser_use/models.py +45 -0
- gl_browser_use/models.pyi +32 -0
- gl_browser_use/parsing.py +264 -0
- gl_browser_use/parsing.pyi +41 -0
- gl_browser_use/parsing_recovery.py +204 -0
- gl_browser_use/parsing_recovery.pyi +35 -0
- gl_browser_use/session_errors.py +72 -0
- gl_browser_use/session_errors.pyi +16 -0
- gl_browser_use/storage/__init__.py +39 -0
- gl_browser_use/storage/__init__.pyi +6 -0
- gl_browser_use/storage/base.py +125 -0
- gl_browser_use/storage/base.pyi +46 -0
- gl_browser_use/storage/minio_compatible.py +84 -0
- gl_browser_use/storage/minio_compatible.pyi +15 -0
- gl_browser_use_binary-0.0.0b5.dist-info/METADATA +236 -0
- gl_browser_use_binary-0.0.0b5.dist-info/RECORD +34 -0
- gl_browser_use_binary-0.0.0b5.dist-info/WHEEL +5 -0
- gl_browser_use_binary-0.0.0b5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""Object storage abstractions for browser session recordings for GL Browser Use SDK.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Reinhart Linanda (reinhart.linanda@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from urllib.parse import urlparse
|
|
12
|
+
|
|
13
|
+
from gl_browser_use.errors import BrowserUseConfigurationError
|
|
14
|
+
|
|
15
|
+
OBJECT_NAME_PREFIX = "browser-recordings/"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ObjectStorage(ABC):
|
|
19
|
+
"""Abstract contract for object storage providers."""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
*,
|
|
24
|
+
endpoint: str | None = None,
|
|
25
|
+
access_key: str | None = None,
|
|
26
|
+
secret_key: str | None = None,
|
|
27
|
+
bucket_name: str | None = None,
|
|
28
|
+
directory_prefix: str | None = None,
|
|
29
|
+
secure: bool | None = None,
|
|
30
|
+
) -> None:
|
|
31
|
+
"""Initialize the object storage.
|
|
32
|
+
|
|
33
|
+
Raises:
|
|
34
|
+
------
|
|
35
|
+
BrowserUseConfigurationError
|
|
36
|
+
When any of ``endpoint``, ``access_key``, ``secret_key`` or
|
|
37
|
+
``bucket_name`` is missing from both the arguments and the
|
|
38
|
+
corresponding ``OBJECT_STORAGE_*`` environment variable.
|
|
39
|
+
"""
|
|
40
|
+
resolved_endpoint = endpoint if endpoint is not None else os.getenv("OBJECT_STORAGE_URL")
|
|
41
|
+
resolved_access_key = access_key if access_key is not None else os.getenv("OBJECT_STORAGE_USERNAME")
|
|
42
|
+
resolved_secret_key = secret_key if secret_key is not None else os.getenv("OBJECT_STORAGE_PASSWORD")
|
|
43
|
+
resolved_bucket_name = bucket_name if bucket_name is not None else os.getenv("OBJECT_STORAGE_BUCKET_NAME")
|
|
44
|
+
resolved_directory_prefix = (
|
|
45
|
+
directory_prefix if directory_prefix is not None else os.getenv("OBJECT_STORAGE_DIRECTORY_PREFIX")
|
|
46
|
+
)
|
|
47
|
+
secure_from_env = os.getenv("OBJECT_STORAGE_SECURE", "False").lower() == "true"
|
|
48
|
+
resolved_secure = secure_from_env if secure is None else secure
|
|
49
|
+
|
|
50
|
+
missing = [
|
|
51
|
+
name
|
|
52
|
+
for name, value in (
|
|
53
|
+
("endpoint", resolved_endpoint),
|
|
54
|
+
("access_key", resolved_access_key),
|
|
55
|
+
("secret_key", resolved_secret_key),
|
|
56
|
+
("bucket_name", resolved_bucket_name),
|
|
57
|
+
)
|
|
58
|
+
if not value
|
|
59
|
+
]
|
|
60
|
+
if missing:
|
|
61
|
+
raise BrowserUseConfigurationError(
|
|
62
|
+
"Object storage configuration is incomplete. Missing: " + ", ".join(missing),
|
|
63
|
+
details={"missing": missing},
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
parsed_host, parsed_secure = self._split_endpoint_scheme(resolved_endpoint)
|
|
67
|
+
|
|
68
|
+
self.endpoint = parsed_host
|
|
69
|
+
self.access_key = resolved_access_key
|
|
70
|
+
self.secret_key = resolved_secret_key
|
|
71
|
+
self.bucket_name = resolved_bucket_name
|
|
72
|
+
self.directory_prefix = resolved_directory_prefix
|
|
73
|
+
self.secure = parsed_secure if parsed_secure is not None else resolved_secure
|
|
74
|
+
|
|
75
|
+
self._client: object | None = None
|
|
76
|
+
self._error: str | None = None
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def _split_endpoint_scheme(endpoint: str) -> tuple[str, bool | None]:
|
|
80
|
+
"""Return ``(host, secure?)`` from an endpoint that may include a scheme."""
|
|
81
|
+
if "://" not in endpoint:
|
|
82
|
+
return endpoint, None
|
|
83
|
+
parsed = urlparse(endpoint)
|
|
84
|
+
host = parsed.netloc or parsed.path
|
|
85
|
+
return host, parsed.scheme == "https"
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
@abstractmethod
|
|
89
|
+
def provider(self) -> str:
|
|
90
|
+
"""Return the human-readable storage provider name."""
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def is_available(self) -> bool:
|
|
94
|
+
"""Whether this storage provider is currently available."""
|
|
95
|
+
return self._error is None and self._client is not None
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def last_error(self) -> str | None:
|
|
99
|
+
"""Return the last error encountered during client initialization or operation."""
|
|
100
|
+
return self._error
|
|
101
|
+
|
|
102
|
+
@classmethod
|
|
103
|
+
def from_environment(cls) -> ObjectStorage:
|
|
104
|
+
"""Create a storage instance from environment variables."""
|
|
105
|
+
return cls()
|
|
106
|
+
|
|
107
|
+
def resolve_object_name(self, object_name: str) -> str:
|
|
108
|
+
"""Return the effective remote object name."""
|
|
109
|
+
normalized_object_name = object_name.lstrip("/")
|
|
110
|
+
base_name = f"{OBJECT_NAME_PREFIX}{normalized_object_name}"
|
|
111
|
+
if self.directory_prefix:
|
|
112
|
+
normalized_directory_prefix = self.directory_prefix.strip("/")
|
|
113
|
+
return f"{normalized_directory_prefix}/{base_name}"
|
|
114
|
+
return base_name
|
|
115
|
+
|
|
116
|
+
@abstractmethod
|
|
117
|
+
def upload_file(self, file_path: str, object_name: str) -> str | None:
|
|
118
|
+
"""Upload a file and optionally return the stored object name."""
|
|
119
|
+
|
|
120
|
+
@abstractmethod
|
|
121
|
+
def get_file_url(self, object_name: str) -> str | None:
|
|
122
|
+
"""Return an object URL when available."""
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
__all__ = ["ObjectStorage", "OBJECT_NAME_PREFIX"]
|
|
@@ -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,84 @@
|
|
|
1
|
+
"""MinIO/S3-compatible storage for browser session recordings for GL Browser Use SDK.
|
|
2
|
+
|
|
3
|
+
Authors:
|
|
4
|
+
Reinhart Linanda (reinhart.linanda@gdplabs.id)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import mimetypes
|
|
10
|
+
|
|
11
|
+
from minio import Minio
|
|
12
|
+
|
|
13
|
+
from gl_browser_use.storage.base import ObjectStorage
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MinIOS3CompatibleStorage(ObjectStorage):
|
|
17
|
+
"""Concrete S3-compatible storage implemented with MinIO."""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
*,
|
|
22
|
+
endpoint: str | None = None,
|
|
23
|
+
access_key: str | None = None,
|
|
24
|
+
secret_key: str | None = None,
|
|
25
|
+
bucket_name: str | None = None,
|
|
26
|
+
directory_prefix: str | None = None,
|
|
27
|
+
secure: bool | None = None,
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Initialize the MinIO/S3-compatible storage."""
|
|
30
|
+
super().__init__(
|
|
31
|
+
endpoint=endpoint,
|
|
32
|
+
access_key=access_key,
|
|
33
|
+
secret_key=secret_key,
|
|
34
|
+
bucket_name=bucket_name,
|
|
35
|
+
directory_prefix=directory_prefix,
|
|
36
|
+
secure=secure,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
client = Minio(
|
|
41
|
+
self.endpoint,
|
|
42
|
+
access_key=self.access_key,
|
|
43
|
+
secret_key=self.secret_key,
|
|
44
|
+
secure=self.secure,
|
|
45
|
+
)
|
|
46
|
+
self._ensure_bucket_exists(client)
|
|
47
|
+
self._client = client
|
|
48
|
+
except Exception as error: # pragma: no cover - defensive dependency path
|
|
49
|
+
self._error = f"Failed to initialize MinIO client: {error}"
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def provider(self) -> str:
|
|
53
|
+
"""Return the human-readable storage provider name."""
|
|
54
|
+
return "minio"
|
|
55
|
+
|
|
56
|
+
def upload_file(self, file_path: str, object_name: str) -> str | None:
|
|
57
|
+
"""Upload a file and optionally return the stored object name."""
|
|
58
|
+
if not self.is_available:
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
remote_name = self.resolve_object_name(object_name)
|
|
62
|
+
content_type, _ = mimetypes.guess_type(file_path)
|
|
63
|
+
if content_type is None or not content_type.startswith("video/"):
|
|
64
|
+
content_type = "video/mp4"
|
|
65
|
+
|
|
66
|
+
assert isinstance(self._client, Minio)
|
|
67
|
+
self._client.fput_object(self.bucket_name, remote_name, file_path, content_type=content_type)
|
|
68
|
+
return remote_name
|
|
69
|
+
|
|
70
|
+
def get_file_url(self, object_name: str) -> str | None:
|
|
71
|
+
"""Return an object URL when available."""
|
|
72
|
+
if not self.is_available:
|
|
73
|
+
return None
|
|
74
|
+
remote_name = self.resolve_object_name(object_name)
|
|
75
|
+
assert isinstance(self._client, Minio)
|
|
76
|
+
return self._client.presigned_get_object(self.bucket_name, remote_name)
|
|
77
|
+
|
|
78
|
+
def _ensure_bucket_exists(self, client: Minio) -> None:
|
|
79
|
+
"""Ensure the configured bucket exists on the target endpoint."""
|
|
80
|
+
if not client.bucket_exists(self.bucket_name):
|
|
81
|
+
client.make_bucket(self.bucket_name)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
__all__ = ["MinIOS3CompatibleStorage"]
|
|
@@ -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."""
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gl-browser-use-binary
|
|
3
|
+
Version: 0.0.0b5
|
|
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.13,>=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.47.0,>=0.46.0
|
|
10
|
+
Requires-Dist: pydantic<3.0.0,>=2.0.0
|
|
11
|
+
Requires-Dist: requests<3.0.0,>=2.32.4
|
|
12
|
+
Provides-Extra: steel
|
|
13
|
+
Requires-Dist: steel-sdk<0.17.0,>=0.16.0; extra == "steel"
|
|
14
|
+
Provides-Extra: infrastructure
|
|
15
|
+
Requires-Dist: gl-browser-use-binary[steel]; extra == "infrastructure"
|
|
16
|
+
Provides-Extra: minio
|
|
17
|
+
Requires-Dist: minio<8.0.0,>=7.2.20; extra == "minio"
|
|
18
|
+
Provides-Extra: storage
|
|
19
|
+
Requires-Dist: gl-browser-use-binary[minio]; extra == "storage"
|
|
20
|
+
Provides-Extra: full
|
|
21
|
+
Requires-Dist: gl-browser-use-binary[infrastructure,storage]; extra == "full"
|
|
22
|
+
|
|
23
|
+
# GL Browser Use
|
|
24
|
+
|
|
25
|
+
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 browser infrastructure, optional MinIO/S3-compatible recording storage, and bounded retries for recoverable browser-session failures.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
Install the core SDK:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install gl-browser-use
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Install optional providers only when you need them:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install "gl-browser-use[steel]" # Steel browser infrastructure
|
|
39
|
+
pip install "gl-browser-use[infrastructure]" # All browser infrastructure providers
|
|
40
|
+
pip install "gl-browser-use[minio]" # MinIO/S3-compatible object storage
|
|
41
|
+
pip install "gl-browser-use[storage]" # All object storage providers
|
|
42
|
+
pip install "gl-browser-use[full]" # Infrastructure + storage providers
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Use the concrete extras (`steel`, `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.
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
`BrowserUseClient` supports streaming and non-streaming execution. API keys can be passed directly or read from environment variables.
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
import asyncio
|
|
53
|
+
|
|
54
|
+
from gl_browser_use import BrowserUseClient, BrowserUseClientConfig
|
|
55
|
+
from gl_browser_use.infrastructure import SteelBrowserInfrastructure
|
|
56
|
+
from gl_browser_use.storage import MinIOS3CompatibleStorage
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
async def main() -> None:
|
|
60
|
+
client = BrowserUseClient(
|
|
61
|
+
config=BrowserUseClientConfig(
|
|
62
|
+
llm_openai_api_key="...",
|
|
63
|
+
page_extraction_llm_openai_api_key="...",
|
|
64
|
+
max_session_retries=2,
|
|
65
|
+
session_retry_delay_in_s=3.0,
|
|
66
|
+
),
|
|
67
|
+
infrastructure=SteelBrowserInfrastructure(), # reads STEEL_API_KEY by default
|
|
68
|
+
storage=MinIOS3CompatibleStorage.from_environment(),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
async for event in client.run("Open Hacker News and list five article titles"):
|
|
72
|
+
print(event.content)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
asyncio.run(main())
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
For a single aggregated result:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from gl_browser_use import BrowserUseClient, BrowserUseClientConfig
|
|
82
|
+
from gl_browser_use.infrastructure import SteelBrowserInfrastructure
|
|
83
|
+
|
|
84
|
+
client = BrowserUseClient(
|
|
85
|
+
config=BrowserUseClientConfig(
|
|
86
|
+
llm_openai_api_key="...",
|
|
87
|
+
page_extraction_llm_openai_api_key="...",
|
|
88
|
+
),
|
|
89
|
+
infrastructure=SteelBrowserInfrastructure(),
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
result = client.run_sync("Open Hacker News and list five article titles")
|
|
93
|
+
|
|
94
|
+
print(result.status)
|
|
95
|
+
print(result.final_output)
|
|
96
|
+
print(result.session_id)
|
|
97
|
+
print(result.streaming_url)
|
|
98
|
+
print(result.recording_url)
|
|
99
|
+
print(result.metadata)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Configuration
|
|
103
|
+
|
|
104
|
+
`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`.
|
|
105
|
+
|
|
106
|
+
Common client options:
|
|
107
|
+
|
|
108
|
+
1. `llm_openai_model`: primary browser-control model. Default: `o3`.
|
|
109
|
+
2. `page_extraction_llm_openai_model`: page extraction model. Default: `gpt-5-mini`.
|
|
110
|
+
3. `extend_system_message`: optional system prompt extension.
|
|
111
|
+
4. `vision_detail_level`: `auto`, `low`, or `high`. Default: `auto`.
|
|
112
|
+
5. `llm_timeout_in_s`: optional LLM timeout.
|
|
113
|
+
6. `step_timeout_in_s`: per-step browser timeout. Default: `180`.
|
|
114
|
+
7. `enable_cloud_sync`: controls `browser-use` cloud sync. Default: `False`.
|
|
115
|
+
8. `logging_level`: `debug`, `info`, `warning`, `error`, or `result`. Default: `info`.
|
|
116
|
+
9. `max_session_retries`: recoverable session retries. Default: `2`.
|
|
117
|
+
10. `session_retry_delay_in_s`: delay between retries. Default: `3.0`.
|
|
118
|
+
|
|
119
|
+
Optional provider environment variables:
|
|
120
|
+
|
|
121
|
+
1. `STEEL_API_KEY`: used by `SteelBrowserInfrastructure()` when `api_key` is not passed.
|
|
122
|
+
2. `OBJECT_STORAGE_URL`: MinIO/S3 endpoint, for example `localhost:9001` or `https://storage.example`.
|
|
123
|
+
3. `OBJECT_STORAGE_USERNAME`: object storage access key.
|
|
124
|
+
4. `OBJECT_STORAGE_PASSWORD`: object storage secret key.
|
|
125
|
+
5. `OBJECT_STORAGE_BUCKET_NAME`: target bucket name.
|
|
126
|
+
6. `OBJECT_STORAGE_DIRECTORY_PREFIX`: optional object key prefix.
|
|
127
|
+
7. `OBJECT_STORAGE_SECURE`: `true` for HTTPS when the endpoint has no scheme.
|
|
128
|
+
|
|
129
|
+
Copy `.env.example` to `.env` for local development, then load it with your application environment manager.
|
|
130
|
+
|
|
131
|
+
## Runtime API
|
|
132
|
+
|
|
133
|
+
The client exposes three run methods:
|
|
134
|
+
|
|
135
|
+
1. `run(task)`: async generator that yields `BrowserUseStreamEvent` values as work progresses.
|
|
136
|
+
2. `run_once(task)`: async method that returns one `BrowserUseRunResult` and includes emitted events in `result.events`.
|
|
137
|
+
3. `run_sync(task)`: blocking wrapper around `run_once()` using `asyncio.run()`.
|
|
138
|
+
|
|
139
|
+
Do not call `run_sync()` from an already running event loop. Use `await run_once()` or `async for event in run()` in async applications.
|
|
140
|
+
|
|
141
|
+
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.
|
|
142
|
+
|
|
143
|
+
## Result Contract
|
|
144
|
+
|
|
145
|
+
`BrowserUseRunResult` contains:
|
|
146
|
+
|
|
147
|
+
1. `status`: `success`, `error`, or `cancelled`.
|
|
148
|
+
2. `task`: normalized task string.
|
|
149
|
+
3. `final_output`: final text extracted from the underlying agent, or `Task completed` when no final text is available.
|
|
150
|
+
4. `session_id`: infrastructure session ID when an external browser session was used.
|
|
151
|
+
5. `streaming_url`: browser debug or streaming URL when available.
|
|
152
|
+
6. `recording_url`: expected recording URL when recording is configured.
|
|
153
|
+
7. `steps`: number of browser-use steps executed.
|
|
154
|
+
8. `error`: terminal error message for error results.
|
|
155
|
+
9. `events`: collected stream events for `run_once()`.
|
|
156
|
+
10. `metadata`: attempt, retry, and recording metadata.
|
|
157
|
+
|
|
158
|
+
Recording metadata uses these statuses:
|
|
159
|
+
|
|
160
|
+
1. `disabled`: infrastructure, storage, or browser context is not available.
|
|
161
|
+
2. `unsupported`: the selected infrastructure does not support recording.
|
|
162
|
+
3. `unavailable`: storage is configured but not available.
|
|
163
|
+
4. `scheduled`: a background recording upload has been scheduled.
|
|
164
|
+
5. `unknown`: recording may have started, but the terminal error did not include enough context to determine the final state.
|
|
165
|
+
|
|
166
|
+
## Streaming Contract
|
|
167
|
+
|
|
168
|
+
`BrowserUseStreamEvent` contains:
|
|
169
|
+
|
|
170
|
+
1. `event_type`
|
|
171
|
+
2. `content`
|
|
172
|
+
3. `thinking_and_activity_info`
|
|
173
|
+
4. `is_final`
|
|
174
|
+
5. `tool_info`
|
|
175
|
+
6. `metadata`
|
|
176
|
+
|
|
177
|
+
Important event content values:
|
|
178
|
+
|
|
179
|
+
1. `Receive streaming URL`: emitted when a browser debug or streaming URL is available.
|
|
180
|
+
2. `Receive recording URL`: emitted when a recording URL can be resolved.
|
|
181
|
+
3. `Task completed`: emitted for the final successful step.
|
|
182
|
+
|
|
183
|
+
Activity events encode iframe URLs in `thinking_and_activity_info["data_value"]` as a JSON string:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{"type": "iframe", "message": "<url>"}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Step events include serialized tool calls in `tool_info["tool_calls"]`.
|
|
190
|
+
|
|
191
|
+
## Retries And Errors
|
|
192
|
+
|
|
193
|
+
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`.
|
|
194
|
+
|
|
195
|
+
Non-recoverable task failures return `BrowserUseRunResult(status="error")`. Recoverable failures that exhaust all attempts raise `BrowserUseRetryExhaustedError`.
|
|
196
|
+
|
|
197
|
+
SDK error types:
|
|
198
|
+
|
|
199
|
+
1. `BrowserUseConfigurationError`: missing or invalid runtime configuration.
|
|
200
|
+
2. `BrowserUseDependencyError`: optional provider dependency problem.
|
|
201
|
+
3. `BrowserUseMissingDependencyError`: optional provider extra is not installed.
|
|
202
|
+
4. `BrowserUseExecutionError`: execution-time failure.
|
|
203
|
+
5. `BrowserUseRetryExhaustedError`: recoverable session retries were exhausted.
|
|
204
|
+
|
|
205
|
+
## Optional Providers
|
|
206
|
+
|
|
207
|
+
Optional providers are lazy-loaded. Importing `gl_browser_use` does not require Steel or MinIO to be installed.
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
from gl_browser_use.infrastructure import SteelBrowserInfrastructure
|
|
211
|
+
from gl_browser_use.storage import MinIOS3CompatibleStorage
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
`SteelBrowserInfrastructure` creates Steel browser sessions and provides CDP/streaming URLs. `MinIOS3CompatibleStorage` uploads session recordings to MinIO or an S3-compatible service and returns presigned URLs.
|
|
215
|
+
|
|
216
|
+
## Development
|
|
217
|
+
|
|
218
|
+
From `libs/gl-browser-use`:
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
make install-dev
|
|
222
|
+
make test-unit
|
|
223
|
+
make test-integration
|
|
224
|
+
make lint
|
|
225
|
+
make build-check
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Useful targets:
|
|
229
|
+
|
|
230
|
+
1. `make test`: run all tests.
|
|
231
|
+
2. `make test-unit`: run unit tests with coverage.
|
|
232
|
+
3. `make test-integration`: run integration-marked contract tests.
|
|
233
|
+
4. `make lint`: run Ruff checks.
|
|
234
|
+
5. `make format`: run Ruff fixes and formatter.
|
|
235
|
+
6. `make pre-commit`: run pre-commit hooks.
|
|
236
|
+
7. `make build-check`: build the package and validate artifacts with Twine.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
gl_browser_use/__init__.py,sha256=yW8uu3Ls7Q9_PB7iRMR5YlY-DXzW9hT2g3-L6HaLxug,1947
|
|
2
|
+
gl_browser_use/__init__.pyi,sha256=1uchB2q9Iq7GBPac_MQf4okzXalqcwNQeBUAVpXDU8E,1417
|
|
3
|
+
gl_browser_use/client.py,sha256=iBFZJYynnfNfP0sMbs1j4mpGAAk3h31GEJgsChbxYIM,24576
|
|
4
|
+
gl_browser_use/client.pyi,sha256=_VnpATRXmxVlO7-XjCu32-KJ1vWYQ7msoVtbhKiQKsA,3614
|
|
5
|
+
gl_browser_use/config.py,sha256=kmeremVGjXVmyVNByuJ5dxf4ZH8kexmTm0ZKmR8I1C8,6460
|
|
6
|
+
gl_browser_use/config.pyi,sha256=0znX0glemnfIHQdS6eRBiFzgz3yJypkwklPN_k2Dg5A,1880
|
|
7
|
+
gl_browser_use/errors.py,sha256=-_HACPr3XhvzZCWsOsPT0UyabGN_bYAxW4jiWJPYu0A,3564
|
|
8
|
+
gl_browser_use/errors.pyi,sha256=lvgzHj2Vm7tD6UsHwT3LDzmUPQkNfJ1FF8zFnxxZ3J8,2036
|
|
9
|
+
gl_browser_use/events.py,sha256=BMPcCfClp-F8qcm2CEbbhdR0VTAYDjuSsCzNLN-UelI,5760
|
|
10
|
+
gl_browser_use/events.pyi,sha256=A7o-FcXn8FHbrxeIZqQ75byYo6OkUVYekaIrU-nVWiY,1888
|
|
11
|
+
gl_browser_use/models.py,sha256=QqeFofkzuNmMutFTiUc0YdocfQa36zNSgGILWD-noEU,1302
|
|
12
|
+
gl_browser_use/models.pyi,sha256=KcNLDd6XPQqHa7Ccuf5ezfDsJuLkVFQNqk67SA1A_1A,1078
|
|
13
|
+
gl_browser_use/parsing.py,sha256=bxXlmYAza1SjXh-pbEAoMYLFO_OyiweVTuwFnQ2Tsz8,9533
|
|
14
|
+
gl_browser_use/parsing.pyi,sha256=K14ptm7O5DgGRxtRxi-1SrKsMdm4XqzXhrBXeNE9V3w,2267
|
|
15
|
+
gl_browser_use/parsing_recovery.py,sha256=yRYA130cCPw_gSvBZHNLwC3KqZaG6_wR0mwhHzyopPc,6392
|
|
16
|
+
gl_browser_use/parsing_recovery.pyi,sha256=LCaHWb0oCSGgwPxEwG3z1f25UCLpb6y5WZnrXO7unMA,1416
|
|
17
|
+
gl_browser_use/session_errors.py,sha256=PXhLiAjg744X194s4B1e7MYlyC0XbTdQS_zb7Nh9RZ0,2052
|
|
18
|
+
gl_browser_use/session_errors.pyi,sha256=fQOcS7Gh2FSawL0VaIRICtCsd-3jdgJUAdExszWmwWU,662
|
|
19
|
+
gl_browser_use/infrastructure/__init__.py,sha256=G9vDxwlKy8Q_hHwBkZ_L4Za4_TU-GRYjsZnAzfe6Vqk,1374
|
|
20
|
+
gl_browser_use/infrastructure/__init__.pyi,sha256=9os_2GJcTxbm6NF1T0CqkXyGvuf4YcvUC1yolGXHSI0,332
|
|
21
|
+
gl_browser_use/infrastructure/base.py,sha256=mhfPWzSrFM5OJYznnXzNGZaZISGZkEP9qZ5IusTzAXc,3664
|
|
22
|
+
gl_browser_use/infrastructure/base.pyi,sha256=qLmZIahrkONBvNG_X8qVP63rmfhxUM2t4gDgJsZL61M,2872
|
|
23
|
+
gl_browser_use/infrastructure/steel.py,sha256=sy5q-NAX4iOTeHqxOsAFUJov8XM-cf4ei5jzWjAYtaM,11473
|
|
24
|
+
gl_browser_use/infrastructure/steel.pyi,sha256=Sh6LIX_OHgEamguMnV9ceI1h_N-fStQVgqcSxo6AJp0,2900
|
|
25
|
+
gl_browser_use/storage/__init__.py,sha256=gHWWdxHNsiL8VaNk43BlcilpIFksuglGOgGHygP0gDg,1294
|
|
26
|
+
gl_browser_use/storage/__init__.pyi,sha256=y1Yp7iB0WWc2sklofSSZe7xbUzbsBsm0K1OA9W_bnAY,267
|
|
27
|
+
gl_browser_use/storage/base.py,sha256=1wUG-hmFzQRWXwhNsDgmAKP96X1w67AICWNii4rpeks,4813
|
|
28
|
+
gl_browser_use/storage/base.pyi,sha256=_V26BMVpbCqY4jqWLTKrgXhsQ9pQ3NCgXEd4WHrgHGc,1936
|
|
29
|
+
gl_browser_use/storage/minio_compatible.py,sha256=VXrdtko7fNNk3zK-i7CzwVsDK9axusWwSMTfg5egfTY,2917
|
|
30
|
+
gl_browser_use/storage/minio_compatible.pyi,sha256=MQnQ1IxTnCx74uiBOlEdzs9BHf88YL37UFZZWTzoTag,871
|
|
31
|
+
gl_browser_use_binary-0.0.0b5.dist-info/METADATA,sha256=4KOI9yMgIuHvSovrQKDvuJ940kC4nuYra0xo_ohtZ5U,9756
|
|
32
|
+
gl_browser_use_binary-0.0.0b5.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
33
|
+
gl_browser_use_binary-0.0.0b5.dist-info/top_level.txt,sha256=I3agYm4bLWMzPbZo_gLgMdmn91EFAXX-hziarvf9VWY,15
|
|
34
|
+
gl_browser_use_binary-0.0.0b5.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gl_browser_use
|