robot-wrapper-sdk 0.2.20__tar.gz → 0.2.22__tar.gz
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.
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/PKG-INFO +84 -30
- robot_wrapper_sdk-0.2.22/README.md +308 -0
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/pyproject.toml +1 -1
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/__init__.py +57 -19
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/application/usecases.py +43 -13
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/domain/entities.py +23 -0
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/domain/repositories.py +47 -7
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/infrastructure/api_client.py +4 -4
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/infrastructure/robot_api_repository.py +174 -16
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_wrapper_sdk.egg-info/PKG-INFO +84 -30
- robot_wrapper_sdk-0.2.20/README.md +0 -254
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/examples/main.py +0 -0
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/application/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/domain/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/infrastructure/__init__.py +0 -0
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_wrapper_sdk.egg-info/SOURCES.txt +0 -0
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_wrapper_sdk.egg-info/dependency_links.txt +0 -0
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_wrapper_sdk.egg-info/requires.txt +0 -0
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_wrapper_sdk.egg-info/top_level.txt +0 -0
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/setup.cfg +0 -0
- {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/tests/main.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: robot-wrapper-sdk
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.22
|
|
4
4
|
Summary: Robot Platform API SDK
|
|
5
5
|
Author-email: GH Robot Platform Team <team@ghrobot.com>
|
|
6
6
|
License: MIT
|
|
@@ -37,7 +37,11 @@ sdk.update_auth_status("2047631542552334336", RobotAuthStatus.AUTHORIZED)
|
|
|
37
37
|
|
|
38
38
|
session = sdk.open_browser(robot_id="2047631542552334336")
|
|
39
39
|
cookies = sdk.get_browser_cookies(session.pod_name, robot_id="2047631542552334336")
|
|
40
|
-
|
|
40
|
+
sdk.navigate_browser(session.pod_name, "https://example.com")
|
|
41
|
+
text = sdk.get_browser_clean_text(session.pod_name)
|
|
42
|
+
html = sdk.get_browser_html(session.pod_name)
|
|
43
|
+
capture = sdk.capture_browser(session.pod_name)
|
|
44
|
+
print(session.pod_name, cookies.cookie_count, text.text, html.html[:20], capture.image)
|
|
41
45
|
sdk.close_browser(session.pod_name, robot_id="2047631542552334336")
|
|
42
46
|
|
|
43
47
|
sdk.close()
|
|
@@ -58,7 +62,11 @@ async def main():
|
|
|
58
62
|
|
|
59
63
|
session = await sdk.open_browser(robot_id="2047631542552334336")
|
|
60
64
|
cookies = await sdk.get_browser_cookies(session.pod_name, robot_id="2047631542552334336")
|
|
61
|
-
|
|
65
|
+
await sdk.navigate_browser(session.pod_name, "https://example.com")
|
|
66
|
+
text = await sdk.get_browser_clean_text(session.pod_name)
|
|
67
|
+
html = await sdk.get_browser_html(session.pod_name)
|
|
68
|
+
capture = await sdk.capture_browser(session.pod_name)
|
|
69
|
+
print(session.pod_name, cookies.cookie_count, text.text, html.html[:20], capture.image)
|
|
62
70
|
await sdk.close_browser(session.pod_name, robot_id="2047631542552334336")
|
|
63
71
|
|
|
64
72
|
await sdk.close()
|
|
@@ -77,44 +85,65 @@ asyncio.run(main())
|
|
|
77
85
|
- Secrets retrieval.
|
|
78
86
|
- Login task acquire/unlock flow.
|
|
79
87
|
- Security hardening acquire/unlock flow.
|
|
80
|
-
- Browser node open, cookie read, and close flow.
|
|
88
|
+
- Browser node open, navigate, clean text, HTML, capture, cookie read, and close flow.
|
|
81
89
|
|
|
82
90
|
## Configuration
|
|
83
91
|
|
|
84
92
|
You can pass config directly to the module constructor or use environment variables.
|
|
85
93
|
|
|
86
|
-
| Variable
|
|
87
|
-
|
|
|
88
|
-
| `ROBOT_PLATFORM_BASE_URL`
|
|
89
|
-
| `ROBOT_PLATFORM_APP_ID`
|
|
90
|
-
| `ROBOT_PLATFORM_APP_SECRET` | Yes
|
|
91
|
-
| `ROBOT_PLATFORM_PROXY_URL`
|
|
94
|
+
| Variable | Required | Description |
|
|
95
|
+
| --------------------------- | -------- | ------------------------------------------------- |
|
|
96
|
+
| `ROBOT_PLATFORM_BASE_URL` | Yes | API server base URL, e.g. `http://localhost:8085` |
|
|
97
|
+
| `ROBOT_PLATFORM_APP_ID` | Yes | Developer App ID |
|
|
98
|
+
| `ROBOT_PLATFORM_APP_SECRET` | Yes | Developer App secret |
|
|
99
|
+
| `ROBOT_PLATFORM_PROXY_URL` | No | HTTP/SOCKS proxy URL for SDK HTTP calls |
|
|
92
100
|
|
|
93
101
|
## Required Developer App Scopes
|
|
94
102
|
|
|
95
|
-
| SDK method
|
|
96
|
-
|
|
|
97
|
-
| `list_robots`, `get_robot`
|
|
98
|
-
| `delete_robot`
|
|
99
|
-
| `get_secrets`
|
|
100
|
-
| `update_status`
|
|
101
|
-
| `update_auth_status`
|
|
102
|
-
| `update_security_hardened`
|
|
103
|
-
| `acquire_need_login`, `unlock_login_tasks`
|
|
104
|
-
| `acquire_unhardened`, `unlock_hardening_tasks`
|
|
105
|
-
| `
|
|
103
|
+
| SDK method | Required scope |
|
|
104
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
|
|
105
|
+
| `list_robots`, `get_robot` | `read:robots` |
|
|
106
|
+
| `delete_robot` | `delete:robots` |
|
|
107
|
+
| `get_secrets` | `read:secrets` |
|
|
108
|
+
| `update_status` | `write:status` |
|
|
109
|
+
| `update_auth_status` | `write:auth-status` |
|
|
110
|
+
| `update_security_hardened` | `write:security-hardened` |
|
|
111
|
+
| `acquire_need_login`, `unlock_login_tasks` | `acquire:login-tasks` |
|
|
112
|
+
| `acquire_unhardened`, `unlock_hardening_tasks` | `acquire:hardening-tasks` |
|
|
113
|
+
| `acquire_robots` | `acquire:robots` |
|
|
114
|
+
| `open_browser`, `navigate_browser`, `get_browser_clean_text`, `get_browser_html`, `capture_browser`, `get_browser_cookies`, `close_browser` | `open:browser` |
|
|
115
|
+
|
|
116
|
+
## Acquire Robots Flow
|
|
117
|
+
|
|
118
|
+
Acquire authenticated live robots with an acquire lock so concurrent workers do not receive the same robot.
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
robots = sdk.acquire_robots(
|
|
122
|
+
limit=5,
|
|
123
|
+
lock_minutes=30,
|
|
124
|
+
project_name="Project A",
|
|
125
|
+
platform="facebook",
|
|
126
|
+
environment="chrome",
|
|
127
|
+
metadata={"key": "country_code", "op": "ne", "value": "VN"},
|
|
128
|
+
)
|
|
129
|
+
```
|
|
106
130
|
|
|
107
131
|
## Browser Node Flow
|
|
108
132
|
|
|
109
133
|
If `robot_id` is provided, the backend loads `username`, `proxy/public_proxy`, and `country_code` from the robot record and metadata. Manual overrides are still supported when no robot ID is available.
|
|
110
134
|
|
|
111
135
|
```python
|
|
112
|
-
|
|
136
|
+
extra_data = {"job_id": "job-123", "step": "open-browser"}
|
|
137
|
+
session = sdk.open_browser(robot_id="2047631542552334336", extra_data=extra_data)
|
|
113
138
|
# Manual fallback:
|
|
114
|
-
# session = sdk.open_browser(username="example_user", proxy="socks5://127.0.0.1:1080", country_code="VN")
|
|
115
|
-
|
|
116
|
-
cookies = sdk.get_browser_cookies(session.pod_name, robot_id="2047631542552334336")
|
|
117
|
-
sdk.
|
|
139
|
+
# session = sdk.open_browser(username="example_user", proxy="socks5://127.0.0.1:1080", country_code="VN", extra_data=extra_data)
|
|
140
|
+
|
|
141
|
+
cookies = sdk.get_browser_cookies(session.pod_name, robot_id="2047631542552334336", extra_data=extra_data)
|
|
142
|
+
sdk.navigate_browser(session.pod_name, "https://example.com", extra_data=extra_data)
|
|
143
|
+
text = sdk.get_browser_clean_text(session.pod_name, extra_data=extra_data)
|
|
144
|
+
html = sdk.get_browser_html(session.pod_name, extra_data=extra_data)
|
|
145
|
+
capture = sdk.capture_browser(session.pod_name, extra_data=extra_data)
|
|
146
|
+
sdk.close_browser(session.pod_name, robot_id="2047631542552334336", extra_data=extra_data)
|
|
118
147
|
```
|
|
119
148
|
|
|
120
149
|
### Browser response models
|
|
@@ -122,7 +151,7 @@ sdk.close_browser(session.pod_name, robot_id="2047631542552334336")
|
|
|
122
151
|
`open_browser(...)` returns `BrowserSession`:
|
|
123
152
|
|
|
124
153
|
```python
|
|
125
|
-
BrowserSession(pod_name="selenium-node-abc123", session_id="selenium-node-abc123", status="running")
|
|
154
|
+
BrowserSession(pod_name="selenium-node-abc123", session_id="selenium-node-abc123", status="running", extra_data={"job_id": "job-123"})
|
|
126
155
|
```
|
|
127
156
|
|
|
128
157
|
`get_browser_cookies(...)` returns `BrowserCookies`:
|
|
@@ -132,6 +161,7 @@ BrowserCookies(
|
|
|
132
161
|
pod_name="selenium-node-abc123",
|
|
133
162
|
cookie_count=1,
|
|
134
163
|
cookies=[{"name": "c_user", "value": "123", "domain": ".facebook.com"}],
|
|
164
|
+
extra_data={"job_id": "job-123"},
|
|
135
165
|
)
|
|
136
166
|
```
|
|
137
167
|
|
|
@@ -151,10 +181,15 @@ BrowserCookies(
|
|
|
151
181
|
- `acquire_need_login(limit=20, lock_minutes=30, platforms=None)`
|
|
152
182
|
- `unlock_login_tasks(robot_ids)`
|
|
153
183
|
- `acquire_unhardened(limit=20, lock_minutes=30, min_age_days=0, platforms=None)`
|
|
184
|
+
- `acquire_robots(limit=20, lock_minutes=30, project_name=None, platform=None, environment=None, metadata=None)`
|
|
154
185
|
- `unlock_hardening_tasks(robot_ids)`
|
|
155
|
-
- `open_browser(robot_id=None, username="", proxy="", country_code="")`
|
|
156
|
-
- `get_browser_cookies(pod_name, robot_id=None)`
|
|
157
|
-
- `
|
|
186
|
+
- `open_browser(robot_id=None, username="", proxy="", country_code="", extra_data=None)`
|
|
187
|
+
- `get_browser_cookies(pod_name, robot_id=None, extra_data=None)`
|
|
188
|
+
- `navigate_browser(pod_name, url, extra_data=None)`
|
|
189
|
+
- `get_browser_clean_text(pod_name, extra_data=None)`
|
|
190
|
+
- `get_browser_html(pod_name, extra_data=None)`
|
|
191
|
+
- `capture_browser(pod_name, extra_data=None)`
|
|
192
|
+
- `close_browser(pod_name, robot_id=None, extra_data=None)`
|
|
158
193
|
- `close()`
|
|
159
194
|
|
|
160
195
|
### Async: `AsyncRobotPlatformModule`
|
|
@@ -202,6 +237,25 @@ Browser cookies response example:
|
|
|
202
237
|
|
|
203
238
|
## Changelog
|
|
204
239
|
|
|
240
|
+
### [0.2.22]
|
|
241
|
+
|
|
242
|
+
#### Added
|
|
243
|
+
|
|
244
|
+
- Added optional `extra_data` passthrough support for browser helpers:
|
|
245
|
+
- `open_browser(..., extra_data=None)`
|
|
246
|
+
- `get_browser_cookies(..., extra_data=None)`
|
|
247
|
+
- `close_browser(..., extra_data=None)`
|
|
248
|
+
- Added `extra_data` fields to `BrowserSession` and `BrowserCookies` response models.
|
|
249
|
+
- Added browser session action helpers for sync and async clients:
|
|
250
|
+
- `navigate_browser(pod_name, url, extra_data=None)`
|
|
251
|
+
- `get_browser_clean_text(pod_name, extra_data=None)`
|
|
252
|
+
- `get_browser_html(pod_name, extra_data=None)`
|
|
253
|
+
- `capture_browser(pod_name, extra_data=None)`
|
|
254
|
+
- Added typed response models for browser clean text, HTML, and capture results.
|
|
255
|
+
- Added generic authenticated robot acquire helper for sync and async clients:
|
|
256
|
+
- `acquire_robots(limit=20, lock_minutes=30, project_name=None, platform=None, environment=None, metadata=None)`
|
|
257
|
+
- Supports backend `acquire:robots` scope with project, platform, environment, and metadata `eq`/`ne` filters.
|
|
258
|
+
|
|
205
259
|
### [0.2.20] - 2026-05-25
|
|
206
260
|
|
|
207
261
|
#### Added
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Robot Platform SDK (Python)
|
|
2
|
+
|
|
3
|
+
Python SDK for Robot Platform Developer API. Supports app credentials auth, sync/async clients, robot operations, worker task flows, and browser node control.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install robot-wrapper-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from robot_sdk import RobotPlatformModule, RobotStatus, RobotAuthStatus
|
|
15
|
+
|
|
16
|
+
sdk = RobotPlatformModule(
|
|
17
|
+
base_url="http://localhost:8085",
|
|
18
|
+
app_id="your_app_id",
|
|
19
|
+
app_secret="your_app_secret",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
robot = sdk.get_robot("2047631542552334336")
|
|
23
|
+
print(robot.platform if robot else "not found")
|
|
24
|
+
|
|
25
|
+
sdk.update_status("2047631542552334336", RobotStatus.LIVE)
|
|
26
|
+
sdk.update_auth_status("2047631542552334336", RobotAuthStatus.AUTHORIZED)
|
|
27
|
+
|
|
28
|
+
session = sdk.open_browser(robot_id="2047631542552334336")
|
|
29
|
+
cookies = sdk.get_browser_cookies(session.pod_name, robot_id="2047631542552334336")
|
|
30
|
+
sdk.navigate_browser(session.pod_name, "https://example.com")
|
|
31
|
+
text = sdk.get_browser_clean_text(session.pod_name)
|
|
32
|
+
html = sdk.get_browser_html(session.pod_name)
|
|
33
|
+
capture = sdk.capture_browser(session.pod_name)
|
|
34
|
+
print(session.pod_name, cookies.cookie_count, text.text, html.html[:20], capture.image)
|
|
35
|
+
sdk.close_browser(session.pod_name, robot_id="2047631542552334336")
|
|
36
|
+
|
|
37
|
+
sdk.close()
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Async Quick Start
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
import asyncio
|
|
44
|
+
from robot_sdk import AsyncRobotPlatformModule
|
|
45
|
+
|
|
46
|
+
async def main():
|
|
47
|
+
sdk = AsyncRobotPlatformModule(
|
|
48
|
+
base_url="http://localhost:8085",
|
|
49
|
+
app_id="your_app_id",
|
|
50
|
+
app_secret="your_app_secret",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
session = await sdk.open_browser(robot_id="2047631542552334336")
|
|
54
|
+
cookies = await sdk.get_browser_cookies(session.pod_name, robot_id="2047631542552334336")
|
|
55
|
+
await sdk.navigate_browser(session.pod_name, "https://example.com")
|
|
56
|
+
text = await sdk.get_browser_clean_text(session.pod_name)
|
|
57
|
+
html = await sdk.get_browser_html(session.pod_name)
|
|
58
|
+
capture = await sdk.capture_browser(session.pod_name)
|
|
59
|
+
print(session.pod_name, cookies.cookie_count, text.text, html.html[:20], capture.image)
|
|
60
|
+
await sdk.close_browser(session.pod_name, robot_id="2047631542552334336")
|
|
61
|
+
|
|
62
|
+
await sdk.close()
|
|
63
|
+
|
|
64
|
+
asyncio.run(main())
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Features
|
|
68
|
+
|
|
69
|
+
- Developer App authentication with `app_id` and `app_secret`.
|
|
70
|
+
- Sync client: `RobotPlatformModule`.
|
|
71
|
+
- Async client: `AsyncRobotPlatformModule`.
|
|
72
|
+
- Automatic access token creation and refresh on `401`.
|
|
73
|
+
- HTTP/SOCKS proxy support through `httpx[socks]`.
|
|
74
|
+
- Robot list/detail/delete/update operations.
|
|
75
|
+
- Secrets retrieval.
|
|
76
|
+
- Login task acquire/unlock flow.
|
|
77
|
+
- Security hardening acquire/unlock flow.
|
|
78
|
+
- Browser node open, navigate, clean text, HTML, capture, cookie read, and close flow.
|
|
79
|
+
|
|
80
|
+
## Configuration
|
|
81
|
+
|
|
82
|
+
You can pass config directly to the module constructor or use environment variables.
|
|
83
|
+
|
|
84
|
+
| Variable | Required | Description |
|
|
85
|
+
| --------------------------- | -------- | ------------------------------------------------- |
|
|
86
|
+
| `ROBOT_PLATFORM_BASE_URL` | Yes | API server base URL, e.g. `http://localhost:8085` |
|
|
87
|
+
| `ROBOT_PLATFORM_APP_ID` | Yes | Developer App ID |
|
|
88
|
+
| `ROBOT_PLATFORM_APP_SECRET` | Yes | Developer App secret |
|
|
89
|
+
| `ROBOT_PLATFORM_PROXY_URL` | No | HTTP/SOCKS proxy URL for SDK HTTP calls |
|
|
90
|
+
|
|
91
|
+
## Required Developer App Scopes
|
|
92
|
+
|
|
93
|
+
| SDK method | Required scope |
|
|
94
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
|
|
95
|
+
| `list_robots`, `get_robot` | `read:robots` |
|
|
96
|
+
| `delete_robot` | `delete:robots` |
|
|
97
|
+
| `get_secrets` | `read:secrets` |
|
|
98
|
+
| `update_status` | `write:status` |
|
|
99
|
+
| `update_auth_status` | `write:auth-status` |
|
|
100
|
+
| `update_security_hardened` | `write:security-hardened` |
|
|
101
|
+
| `acquire_need_login`, `unlock_login_tasks` | `acquire:login-tasks` |
|
|
102
|
+
| `acquire_unhardened`, `unlock_hardening_tasks` | `acquire:hardening-tasks` |
|
|
103
|
+
| `acquire_robots` | `acquire:robots` |
|
|
104
|
+
| `open_browser`, `navigate_browser`, `get_browser_clean_text`, `get_browser_html`, `capture_browser`, `get_browser_cookies`, `close_browser` | `open:browser` |
|
|
105
|
+
|
|
106
|
+
## Acquire Robots Flow
|
|
107
|
+
|
|
108
|
+
Acquire authenticated live robots with an acquire lock so concurrent workers do not receive the same robot.
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
robots = sdk.acquire_robots(
|
|
112
|
+
limit=5,
|
|
113
|
+
lock_minutes=30,
|
|
114
|
+
project_name="Project A",
|
|
115
|
+
platform="facebook",
|
|
116
|
+
environment="chrome",
|
|
117
|
+
metadata={"key": "country_code", "op": "ne", "value": "VN"},
|
|
118
|
+
)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Browser Node Flow
|
|
122
|
+
|
|
123
|
+
If `robot_id` is provided, the backend loads `username`, `proxy/public_proxy`, and `country_code` from the robot record and metadata. Manual overrides are still supported when no robot ID is available.
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
extra_data = {"job_id": "job-123", "step": "open-browser"}
|
|
127
|
+
session = sdk.open_browser(robot_id="2047631542552334336", extra_data=extra_data)
|
|
128
|
+
# Manual fallback:
|
|
129
|
+
# session = sdk.open_browser(username="example_user", proxy="socks5://127.0.0.1:1080", country_code="VN", extra_data=extra_data)
|
|
130
|
+
|
|
131
|
+
cookies = sdk.get_browser_cookies(session.pod_name, robot_id="2047631542552334336", extra_data=extra_data)
|
|
132
|
+
sdk.navigate_browser(session.pod_name, "https://example.com", extra_data=extra_data)
|
|
133
|
+
text = sdk.get_browser_clean_text(session.pod_name, extra_data=extra_data)
|
|
134
|
+
html = sdk.get_browser_html(session.pod_name, extra_data=extra_data)
|
|
135
|
+
capture = sdk.capture_browser(session.pod_name, extra_data=extra_data)
|
|
136
|
+
sdk.close_browser(session.pod_name, robot_id="2047631542552334336", extra_data=extra_data)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Browser response models
|
|
140
|
+
|
|
141
|
+
`open_browser(...)` returns `BrowserSession`:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
BrowserSession(pod_name="selenium-node-abc123", session_id="selenium-node-abc123", status="running", extra_data={"job_id": "job-123"})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`get_browser_cookies(...)` returns `BrowserCookies`:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
BrowserCookies(
|
|
151
|
+
pod_name="selenium-node-abc123",
|
|
152
|
+
cookie_count=1,
|
|
153
|
+
cookies=[{"name": "c_user", "value": "123", "domain": ".facebook.com"}],
|
|
154
|
+
extra_data={"job_id": "job-123"},
|
|
155
|
+
)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Main API
|
|
159
|
+
|
|
160
|
+
### Sync: `RobotPlatformModule`
|
|
161
|
+
|
|
162
|
+
- `list_robots(platform=None, status=None, auth_status=None, project_id=None, page=1, limit=20)`
|
|
163
|
+
- `get_robot(robot_id)`
|
|
164
|
+
- `delete_robot(robot_id)`
|
|
165
|
+
- `get_secrets(robot_id)`
|
|
166
|
+
- `update_status(robot_id, status)`
|
|
167
|
+
- `update_auth_status(robot_id, auth_status)`
|
|
168
|
+
- `update_security_hardened(robot_id, security_hardened)`
|
|
169
|
+
- `update_metadata(robot_id, metadata)`
|
|
170
|
+
- `update_robot(robot_id, payload)`
|
|
171
|
+
- `acquire_need_login(limit=20, lock_minutes=30, platforms=None)`
|
|
172
|
+
- `unlock_login_tasks(robot_ids)`
|
|
173
|
+
- `acquire_unhardened(limit=20, lock_minutes=30, min_age_days=0, platforms=None)`
|
|
174
|
+
- `acquire_robots(limit=20, lock_minutes=30, project_name=None, platform=None, environment=None, metadata=None)`
|
|
175
|
+
- `unlock_hardening_tasks(robot_ids)`
|
|
176
|
+
- `open_browser(robot_id=None, username="", proxy="", country_code="", extra_data=None)`
|
|
177
|
+
- `get_browser_cookies(pod_name, robot_id=None, extra_data=None)`
|
|
178
|
+
- `navigate_browser(pod_name, url, extra_data=None)`
|
|
179
|
+
- `get_browser_clean_text(pod_name, extra_data=None)`
|
|
180
|
+
- `get_browser_html(pod_name, extra_data=None)`
|
|
181
|
+
- `capture_browser(pod_name, extra_data=None)`
|
|
182
|
+
- `close_browser(pod_name, robot_id=None, extra_data=None)`
|
|
183
|
+
- `close()`
|
|
184
|
+
|
|
185
|
+
### Async: `AsyncRobotPlatformModule`
|
|
186
|
+
|
|
187
|
+
Async equivalents of all sync methods. Use `await sdk.close()` to close the async client.
|
|
188
|
+
|
|
189
|
+
## Response Shape
|
|
190
|
+
|
|
191
|
+
All API responses use the backend standard envelope:
|
|
192
|
+
|
|
193
|
+
```json
|
|
194
|
+
{
|
|
195
|
+
"status": "success",
|
|
196
|
+
"code": 200,
|
|
197
|
+
"message": "OK",
|
|
198
|
+
"data": {}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Browser cookies response example:
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"status": "success",
|
|
207
|
+
"code": 200,
|
|
208
|
+
"message": "OK",
|
|
209
|
+
"data": {
|
|
210
|
+
"pod_name": "selenium-node-abc123",
|
|
211
|
+
"cookie_count": 1,
|
|
212
|
+
"cookies": [
|
|
213
|
+
{
|
|
214
|
+
"name": "c_user",
|
|
215
|
+
"value": "123",
|
|
216
|
+
"domain": ".facebook.com",
|
|
217
|
+
"path": "/",
|
|
218
|
+
"expires": 1790000000,
|
|
219
|
+
"httpOnly": true,
|
|
220
|
+
"secure": true,
|
|
221
|
+
"sameSite": "Lax"
|
|
222
|
+
}
|
|
223
|
+
]
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Changelog
|
|
229
|
+
|
|
230
|
+
### [0.2.22]
|
|
231
|
+
|
|
232
|
+
#### Added
|
|
233
|
+
|
|
234
|
+
- Added optional `extra_data` passthrough support for browser helpers:
|
|
235
|
+
- `open_browser(..., extra_data=None)`
|
|
236
|
+
- `get_browser_cookies(..., extra_data=None)`
|
|
237
|
+
- `close_browser(..., extra_data=None)`
|
|
238
|
+
- Added `extra_data` fields to `BrowserSession` and `BrowserCookies` response models.
|
|
239
|
+
- Added browser session action helpers for sync and async clients:
|
|
240
|
+
- `navigate_browser(pod_name, url, extra_data=None)`
|
|
241
|
+
- `get_browser_clean_text(pod_name, extra_data=None)`
|
|
242
|
+
- `get_browser_html(pod_name, extra_data=None)`
|
|
243
|
+
- `capture_browser(pod_name, extra_data=None)`
|
|
244
|
+
- Added typed response models for browser clean text, HTML, and capture results.
|
|
245
|
+
- Added generic authenticated robot acquire helper for sync and async clients:
|
|
246
|
+
- `acquire_robots(limit=20, lock_minutes=30, project_name=None, platform=None, environment=None, metadata=None)`
|
|
247
|
+
- Supports backend `acquire:robots` scope with project, platform, environment, and metadata `eq`/`ne` filters.
|
|
248
|
+
|
|
249
|
+
### [0.2.20] - 2026-05-25
|
|
250
|
+
|
|
251
|
+
#### Added
|
|
252
|
+
|
|
253
|
+
- Added browser cookie helper:
|
|
254
|
+
- `get_browser_cookies(pod_name, robot_id=None)`
|
|
255
|
+
- Added sync and async SDK support for `POST /api/v1/developer/browser/cookies`.
|
|
256
|
+
- Added `BrowserCookies` response model with `pod_name`, `cookie_count`, and `cookies`.
|
|
257
|
+
|
|
258
|
+
#### Changed
|
|
259
|
+
|
|
260
|
+
- README now includes PyPI-visible browser cookies examples and response schema.
|
|
261
|
+
|
|
262
|
+
### [0.2.19] - 2026-05-25
|
|
263
|
+
|
|
264
|
+
#### Added
|
|
265
|
+
|
|
266
|
+
- Added developer browser open/close helpers:
|
|
267
|
+
- `open_browser(robot_id=None, username="", proxy="", country_code="")`
|
|
268
|
+
- `close_browser(pod_name, robot_id=None)`
|
|
269
|
+
- Added sync and async SDK support for:
|
|
270
|
+
- `POST /api/v1/developer/browser/open`
|
|
271
|
+
- `DELETE /api/v1/developer/browser/close`
|
|
272
|
+
- Added `BrowserSession` response model with `pod_name`, `session_id`, and `status`.
|
|
273
|
+
|
|
274
|
+
#### Changed
|
|
275
|
+
|
|
276
|
+
- Browser open can use only `robot_id`; backend resolves username, proxy, and country code from robot data.
|
|
277
|
+
|
|
278
|
+
### [0.2.5] - 2026-04-24
|
|
279
|
+
|
|
280
|
+
#### Added
|
|
281
|
+
|
|
282
|
+
- Added login/hardening worker flows for sync and async clients.
|
|
283
|
+
- Added task acquire/unlock methods.
|
|
284
|
+
- Added auth status and security hardening update helpers.
|
|
285
|
+
|
|
286
|
+
#### Changed
|
|
287
|
+
|
|
288
|
+
- Updated README and guide for Developer App auth and worker task flow.
|
|
289
|
+
|
|
290
|
+
## Documentation
|
|
291
|
+
|
|
292
|
+
- Usage guide: [`docs/guide.md`](docs/guide.md)
|
|
293
|
+
- Package code: `robot_sdk/`
|
|
294
|
+
|
|
295
|
+
## Build & Publish
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
make venv
|
|
299
|
+
make install
|
|
300
|
+
make build
|
|
301
|
+
make publish
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Requires valid PyPI credentials for Twine.
|
|
305
|
+
|
|
306
|
+
## License
|
|
307
|
+
|
|
308
|
+
MIT
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
from typing import
|
|
2
|
-
|
|
3
|
-
from .
|
|
4
|
-
from .
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
2
|
+
|
|
3
|
+
from .application.usecases import AsyncRobotUsecase, RobotUsecase
|
|
4
|
+
from .domain.entities import (BrowserCapture, BrowserCookies, BrowserHTML,
|
|
5
|
+
BrowserSession, BrowserText, Robot,
|
|
6
|
+
RobotAuthStatus, RobotSecrets, RobotStatus,
|
|
7
|
+
UpdateRobotRequest)
|
|
8
|
+
from .infrastructure.api_client import AsyncHTTPClient, HTTPClient
|
|
9
|
+
from .infrastructure.robot_api_repository import (AsyncRobotAPIRepository,
|
|
10
|
+
RobotAPIRepository)
|
|
11
|
+
|
|
12
|
+
__version__ = "0.2.22"
|
|
8
13
|
class RobotPlatformModule:
|
|
9
14
|
"""Synchronous Facade for the Robot Platform SDK."""
|
|
10
15
|
|
|
@@ -37,6 +42,9 @@ class RobotPlatformModule:
|
|
|
37
42
|
def acquire_unhardened(self, limit: int = 20, lock_minutes: int = 30, min_age_days: int = 0, platforms: Optional[List[str]] = None):
|
|
38
43
|
return self.robot_usecase.acquire_unhardened(limit, lock_minutes, min_age_days, platforms)
|
|
39
44
|
|
|
45
|
+
def acquire_robots(self, limit: int = 20, lock_minutes: int = 30, project_name: Optional[str] = None, platform: Optional[str] = None, environment: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None):
|
|
46
|
+
return self.robot_usecase.acquire_robots(limit, lock_minutes, project_name, platform, environment, metadata)
|
|
47
|
+
|
|
40
48
|
def unlock_login_tasks(self, robot_ids: List[str]) -> None:
|
|
41
49
|
self.robot_usecase.unlock_login_tasks(robot_ids)
|
|
42
50
|
|
|
@@ -56,14 +64,26 @@ class RobotPlatformModule:
|
|
|
56
64
|
def update_robot(self, robot_id: str, payload: UpdateRobotRequest) -> None:
|
|
57
65
|
self.robot_usecase.update_robot(robot_id, payload)
|
|
58
66
|
|
|
59
|
-
def open_browser(self, robot_id: Optional[str] = None, username: str = "", proxy: str = "", country_code: str = "") -> BrowserSession:
|
|
60
|
-
return self.robot_usecase.open_browser(robot_id, username, proxy, country_code)
|
|
67
|
+
def open_browser(self, robot_id: Optional[str] = None, username: str = "", proxy: str = "", country_code: str = "", extra_data: Optional[Dict[str, Any]] = None) -> BrowserSession:
|
|
68
|
+
return self.robot_usecase.open_browser(robot_id, username, proxy, country_code, extra_data)
|
|
69
|
+
|
|
70
|
+
def close_browser(self, pod_name: str, robot_id: Optional[str] = None, extra_data: Optional[Dict[str, Any]] = None) -> None:
|
|
71
|
+
self.robot_usecase.close_browser(pod_name, robot_id, extra_data)
|
|
72
|
+
|
|
73
|
+
def get_browser_cookies(self, pod_name: str, robot_id: Optional[str] = None, extra_data: Optional[Dict[str, Any]] = None) -> BrowserCookies:
|
|
74
|
+
return self.robot_usecase.get_browser_cookies(pod_name, robot_id, extra_data)
|
|
75
|
+
|
|
76
|
+
def navigate_browser(self, pod_name: str, url: str, extra_data: Optional[Dict[str, Any]] = None) -> None:
|
|
77
|
+
self.robot_usecase.navigate_browser(pod_name, url, extra_data)
|
|
78
|
+
|
|
79
|
+
def get_browser_clean_text(self, pod_name: str, extra_data: Optional[Dict[str, Any]] = None) -> BrowserText:
|
|
80
|
+
return self.robot_usecase.get_browser_clean_text(pod_name, extra_data)
|
|
61
81
|
|
|
62
|
-
def
|
|
63
|
-
self.robot_usecase.
|
|
82
|
+
def get_browser_html(self, pod_name: str, extra_data: Optional[Dict[str, Any]] = None) -> BrowserHTML:
|
|
83
|
+
return self.robot_usecase.get_browser_html(pod_name, extra_data)
|
|
64
84
|
|
|
65
|
-
def
|
|
66
|
-
return self.robot_usecase.
|
|
85
|
+
def capture_browser(self, pod_name: str, extra_data: Optional[Dict[str, Any]] = None) -> BrowserCapture:
|
|
86
|
+
return self.robot_usecase.capture_browser(pod_name, extra_data)
|
|
67
87
|
|
|
68
88
|
|
|
69
89
|
class AsyncRobotPlatformModule:
|
|
@@ -98,6 +118,9 @@ class AsyncRobotPlatformModule:
|
|
|
98
118
|
async def acquire_unhardened(self, limit: int = 20, lock_minutes: int = 30, min_age_days: int = 0, platforms: Optional[List[str]] = None):
|
|
99
119
|
return await self.robot_usecase.acquire_unhardened(limit, lock_minutes, min_age_days, platforms)
|
|
100
120
|
|
|
121
|
+
async def acquire_robots(self, limit: int = 20, lock_minutes: int = 30, project_name: Optional[str] = None, platform: Optional[str] = None, environment: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None):
|
|
122
|
+
return await self.robot_usecase.acquire_robots(limit, lock_minutes, project_name, platform, environment, metadata)
|
|
123
|
+
|
|
101
124
|
async def unlock_login_tasks(self, robot_ids: List[str]) -> None:
|
|
102
125
|
await self.robot_usecase.unlock_login_tasks(robot_ids)
|
|
103
126
|
|
|
@@ -116,14 +139,26 @@ class AsyncRobotPlatformModule:
|
|
|
116
139
|
async def update_robot(self, robot_id: str, payload: UpdateRobotRequest) -> None:
|
|
117
140
|
await self.robot_usecase.update_robot(robot_id, payload)
|
|
118
141
|
|
|
119
|
-
async def open_browser(self, robot_id: Optional[str] = None, username: str = "", proxy: str = "", country_code: str = "") -> BrowserSession:
|
|
120
|
-
return await self.robot_usecase.open_browser(robot_id, username, proxy, country_code)
|
|
142
|
+
async def open_browser(self, robot_id: Optional[str] = None, username: str = "", proxy: str = "", country_code: str = "", extra_data: Optional[Dict[str, Any]] = None) -> BrowserSession:
|
|
143
|
+
return await self.robot_usecase.open_browser(robot_id, username, proxy, country_code, extra_data)
|
|
144
|
+
|
|
145
|
+
async def close_browser(self, pod_name: str, robot_id: Optional[str] = None, extra_data: Optional[Dict[str, Any]] = None) -> None:
|
|
146
|
+
await self.robot_usecase.close_browser(pod_name, robot_id, extra_data)
|
|
147
|
+
|
|
148
|
+
async def get_browser_cookies(self, pod_name: str, robot_id: Optional[str] = None, extra_data: Optional[Dict[str, Any]] = None) -> BrowserCookies:
|
|
149
|
+
return await self.robot_usecase.get_browser_cookies(pod_name, robot_id, extra_data)
|
|
150
|
+
|
|
151
|
+
async def navigate_browser(self, pod_name: str, url: str, extra_data: Optional[Dict[str, Any]] = None) -> None:
|
|
152
|
+
await self.robot_usecase.navigate_browser(pod_name, url, extra_data)
|
|
153
|
+
|
|
154
|
+
async def get_browser_clean_text(self, pod_name: str, extra_data: Optional[Dict[str, Any]] = None) -> BrowserText:
|
|
155
|
+
return await self.robot_usecase.get_browser_clean_text(pod_name, extra_data)
|
|
121
156
|
|
|
122
|
-
async def
|
|
123
|
-
await self.robot_usecase.
|
|
157
|
+
async def get_browser_html(self, pod_name: str, extra_data: Optional[Dict[str, Any]] = None) -> BrowserHTML:
|
|
158
|
+
return await self.robot_usecase.get_browser_html(pod_name, extra_data)
|
|
124
159
|
|
|
125
|
-
async def
|
|
126
|
-
return await self.robot_usecase.
|
|
160
|
+
async def capture_browser(self, pod_name: str, extra_data: Optional[Dict[str, Any]] = None) -> BrowserCapture:
|
|
161
|
+
return await self.robot_usecase.capture_browser(pod_name, extra_data)
|
|
127
162
|
|
|
128
163
|
|
|
129
164
|
__all__ = [
|
|
@@ -135,5 +170,8 @@ __all__ = [
|
|
|
135
170
|
"RobotAuthStatus",
|
|
136
171
|
"BrowserSession",
|
|
137
172
|
"BrowserCookies",
|
|
173
|
+
"BrowserText",
|
|
174
|
+
"BrowserHTML",
|
|
175
|
+
"BrowserCapture",
|
|
138
176
|
"UpdateRobotRequest",
|
|
139
177
|
]
|