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.
Files changed (21) hide show
  1. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/PKG-INFO +84 -30
  2. robot_wrapper_sdk-0.2.22/README.md +308 -0
  3. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/pyproject.toml +1 -1
  4. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/__init__.py +57 -19
  5. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/application/usecases.py +43 -13
  6. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/domain/entities.py +23 -0
  7. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/domain/repositories.py +47 -7
  8. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/infrastructure/api_client.py +4 -4
  9. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/infrastructure/robot_api_repository.py +174 -16
  10. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_wrapper_sdk.egg-info/PKG-INFO +84 -30
  11. robot_wrapper_sdk-0.2.20/README.md +0 -254
  12. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/examples/main.py +0 -0
  13. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/application/__init__.py +0 -0
  14. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/domain/__init__.py +0 -0
  15. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_sdk/infrastructure/__init__.py +0 -0
  16. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_wrapper_sdk.egg-info/SOURCES.txt +0 -0
  17. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_wrapper_sdk.egg-info/dependency_links.txt +0 -0
  18. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_wrapper_sdk.egg-info/requires.txt +0 -0
  19. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/robot_wrapper_sdk.egg-info/top_level.txt +0 -0
  20. {robot_wrapper_sdk-0.2.20 → robot_wrapper_sdk-0.2.22}/setup.cfg +0 -0
  21. {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.20
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
- print(session.pod_name, cookies.cookie_count)
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
- print(session.pod_name, cookies.cookie_count)
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 | Required | Description |
87
- | --- | --- | --- |
88
- | `ROBOT_PLATFORM_BASE_URL` | Yes | API server base URL, e.g. `http://localhost:8085` |
89
- | `ROBOT_PLATFORM_APP_ID` | Yes | Developer App ID |
90
- | `ROBOT_PLATFORM_APP_SECRET` | Yes | Developer App secret |
91
- | `ROBOT_PLATFORM_PROXY_URL` | No | HTTP/SOCKS proxy URL for SDK HTTP calls |
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 | Required scope |
96
- | --- | --- |
97
- | `list_robots`, `get_robot` | `read:robots` |
98
- | `delete_robot` | `delete:robots` |
99
- | `get_secrets` | `read:secrets` |
100
- | `update_status` | `write:status` |
101
- | `update_auth_status` | `write:auth-status` |
102
- | `update_security_hardened` | `write:security-hardened` |
103
- | `acquire_need_login`, `unlock_login_tasks` | `acquire:login-tasks` |
104
- | `acquire_unhardened`, `unlock_hardening_tasks` | `acquire:hardening-tasks` |
105
- | `open_browser`, `get_browser_cookies`, `close_browser` | `open:browser` |
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
- session = sdk.open_browser(robot_id="2047631542552334336")
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.close_browser(session.pod_name, robot_id="2047631542552334336")
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
- - `close_browser(pod_name, robot_id=None)`
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
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
8
8
 
9
9
  [project]
10
10
  name = "robot-wrapper-sdk"
11
- version = "0.2.20"
11
+ version = "0.2.22"
12
12
  description = "Robot Platform API SDK"
13
13
  readme = "README.md"
14
14
  requires-python = ">=3.10"
@@ -1,10 +1,15 @@
1
- from typing import Optional, List, Dict, Any, Tuple
2
- from .infrastructure.api_client import HTTPClient, AsyncHTTPClient
3
- from .infrastructure.robot_api_repository import RobotAPIRepository, AsyncRobotAPIRepository
4
- from .application.usecases import RobotUsecase, AsyncRobotUsecase
5
- from .domain.entities import Robot, RobotSecrets, RobotStatus, RobotAuthStatus, BrowserSession, BrowserCookies, UpdateRobotRequest
6
-
7
- __version__ = "0.2.20"
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 close_browser(self, pod_name: str, robot_id: Optional[str] = None) -> None:
63
- self.robot_usecase.close_browser(pod_name, robot_id)
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 get_browser_cookies(self, pod_name: str, robot_id: Optional[str] = None) -> BrowserCookies:
66
- return self.robot_usecase.get_browser_cookies(pod_name, robot_id)
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 close_browser(self, pod_name: str, robot_id: Optional[str] = None) -> None:
123
- await self.robot_usecase.close_browser(pod_name, robot_id)
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 get_browser_cookies(self, pod_name: str, robot_id: Optional[str] = None) -> BrowserCookies:
126
- return await self.robot_usecase.get_browser_cookies(pod_name, robot_id)
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
  ]