sera-browser 3.1.1__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.
- sera_browser-3.1.1/PKG-INFO +244 -0
- sera_browser-3.1.1/README.md +189 -0
- sera_browser-3.1.1/pyproject.toml +123 -0
- sera_browser-3.1.1/setup.cfg +4 -0
- sera_browser-3.1.1/src/sera_browser/__init__.py +203 -0
- sera_browser-3.1.1/src/sera_browser/__main__.py +26 -0
- sera_browser-3.1.1/src/sera_browser/api/__init__.py +6 -0
- sera_browser-3.1.1/src/sera_browser/api/app.py +275 -0
- sera_browser-3.1.1/src/sera_browser/browser/__init__.py +19 -0
- sera_browser-3.1.1/src/sera_browser/browser/browser_use_fallback.py +108 -0
- sera_browser-3.1.1/src/sera_browser/browser/cdp_ax.py +230 -0
- sera_browser-3.1.1/src/sera_browser/browser/context.py +163 -0
- sera_browser-3.1.1/src/sera_browser/browser/driver.py +801 -0
- sera_browser-3.1.1/src/sera_browser/browser/inspector.py +208 -0
- sera_browser-3.1.1/src/sera_browser/browser/manager.py +178 -0
- sera_browser-3.1.1/src/sera_browser/browser/refmap.py +283 -0
- sera_browser-3.1.1/src/sera_browser/browser/resolver.py +231 -0
- sera_browser-3.1.1/src/sera_browser/browser/screenshots.py +59 -0
- sera_browser-3.1.1/src/sera_browser/browser/som.py +216 -0
- sera_browser-3.1.1/src/sera_browser/browser/stealth.py +271 -0
- sera_browser-3.1.1/src/sera_browser/browser/storage.py +78 -0
- sera_browser-3.1.1/src/sera_browser/browser/tabs.py +260 -0
- sera_browser-3.1.1/src/sera_browser/browser/trimmer.py +141 -0
- sera_browser-3.1.1/src/sera_browser/browser/viewer.py +328 -0
- sera_browser-3.1.1/src/sera_browser/cancel.py +107 -0
- sera_browser-3.1.1/src/sera_browser/challenge/__init__.py +6 -0
- sera_browser-3.1.1/src/sera_browser/challenge/detector.py +301 -0
- sera_browser-3.1.1/src/sera_browser/config.py +209 -0
- sera_browser-3.1.1/src/sera_browser/eval/__init__.py +20 -0
- sera_browser-3.1.1/src/sera_browser/eval/harness.py +405 -0
- sera_browser-3.1.1/src/sera_browser/logging.py +128 -0
- sera_browser-3.1.1/src/sera_browser/models.py +340 -0
- sera_browser-3.1.1/src/sera_browser/net/__init__.py +6 -0
- sera_browser-3.1.1/src/sera_browser/net/recorder.py +288 -0
- sera_browser-3.1.1/src/sera_browser/security.py +137 -0
- sera_browser-3.1.1/src/sera_browser/session/__init__.py +6 -0
- sera_browser-3.1.1/src/sera_browser/session/manager.py +214 -0
- sera_browser-3.1.1/src/sera_browser/state/__init__.py +6 -0
- sera_browser-3.1.1/src/sera_browser/state/state.py +109 -0
- sera_browser-3.1.1/src/sera_browser/task/__init__.py +63 -0
- sera_browser-3.1.1/src/sera_browser/task/action_schema.py +412 -0
- sera_browser-3.1.1/src/sera_browser/task/agent.py +750 -0
- sera_browser-3.1.1/src/sera_browser/task/executor.py +532 -0
- sera_browser-3.1.1/src/sera_browser/task/extraction.py +169 -0
- sera_browser-3.1.1/src/sera_browser/task/history.py +190 -0
- sera_browser-3.1.1/src/sera_browser/task/llm_client.py +743 -0
- sera_browser-3.1.1/src/sera_browser/task/llm_planner.py +696 -0
- sera_browser-3.1.1/src/sera_browser/task/loop.py +102 -0
- sera_browser-3.1.1/src/sera_browser/task/memory.py +168 -0
- sera_browser-3.1.1/src/sera_browser/task/observability.py +246 -0
- sera_browser-3.1.1/src/sera_browser/task/pav.py +453 -0
- sera_browser-3.1.1/src/sera_browser/task/planner.py +192 -0
- sera_browser-3.1.1/src/sera_browser/task/report.py +139 -0
- sera_browser-3.1.1/src/sera_browser/task/safety.py +294 -0
- sera_browser-3.1.1/src/sera_browser/task/soft_restrict.py +92 -0
- sera_browser-3.1.1/src/sera_browser.egg-info/PKG-INFO +244 -0
- sera_browser-3.1.1/src/sera_browser.egg-info/SOURCES.txt +78 -0
- sera_browser-3.1.1/src/sera_browser.egg-info/dependency_links.txt +1 -0
- sera_browser-3.1.1/src/sera_browser.egg-info/entry_points.txt +2 -0
- sera_browser-3.1.1/src/sera_browser.egg-info/requires.txt +32 -0
- sera_browser-3.1.1/src/sera_browser.egg-info/top_level.txt +1 -0
- sera_browser-3.1.1/tests/test_advanced_features.py +659 -0
- sera_browser-3.1.1/tests/test_api.py +121 -0
- sera_browser-3.1.1/tests/test_cancellation.py +99 -0
- sera_browser-3.1.1/tests/test_challenge.py +77 -0
- sera_browser-3.1.1/tests/test_dsh_features.py +498 -0
- sera_browser-3.1.1/tests/test_followups.py +569 -0
- sera_browser-3.1.1/tests/test_juice_shop.py +123 -0
- sera_browser-3.1.1/tests/test_llm_integration.py +180 -0
- sera_browser-3.1.1/tests/test_llm_planner.py +603 -0
- sera_browser-3.1.1/tests/test_llm_provider_agnostic.py +825 -0
- sera_browser-3.1.1/tests/test_loop_detection.py +54 -0
- sera_browser-3.1.1/tests/test_navigation.py +95 -0
- sera_browser-3.1.1/tests/test_network.py +128 -0
- sera_browser-3.1.1/tests/test_screenshots.py +71 -0
- sera_browser-3.1.1/tests/test_session_isolation.py +100 -0
- sera_browser-3.1.1/tests/test_state.py +104 -0
- sera_browser-3.1.1/tests/test_tier2_features.py +337 -0
- sera_browser-3.1.1/tests/test_timeout_crash.py +65 -0
- sera_browser-3.1.1/tests/test_viewer.py +354 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sera-browser
|
|
3
|
+
Version: 3.1.1
|
|
4
|
+
Summary: Standalone Playwright-first autonomous browser agent for SERA — provider-agnostic LLM planner, real-view human-takeoverable browser, CDP AX tree, multi-tab, stealth, history/replay, structured extraction.
|
|
5
|
+
Author-email: mir-ashiq <imsrenpsycho@gmail.com>
|
|
6
|
+
Maintainer-email: mir-ashiq <imsrenpsycho@gmail.com>
|
|
7
|
+
License: Apache-2.0
|
|
8
|
+
Project-URL: Homepage, https://github.com/mir-ashiq/sera-browser
|
|
9
|
+
Project-URL: Repository, https://github.com/mir-ashiq/sera-browser
|
|
10
|
+
Project-URL: Issues, https://github.com/mir-ashiq/sera-browser/issues
|
|
11
|
+
Project-URL: Documentation, https://github.com/mir-ashiq/sera-browser/tree/main/docs
|
|
12
|
+
Keywords: playwright,browser-automation,agent,sera,security,llm,cdp,accessibility,autonomous
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Operating System :: MacOS
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
|
|
22
|
+
Classifier: Topic :: Software Development :: Testing
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Python: >=3.12
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
Requires-Dist: playwright>=1.57
|
|
28
|
+
Requires-Dist: fastapi>=0.110
|
|
29
|
+
Requires-Dist: uvicorn[standard]>=0.29
|
|
30
|
+
Requires-Dist: pydantic>=2.6
|
|
31
|
+
Requires-Dist: pydantic-settings>=2.2
|
|
32
|
+
Requires-Dist: httpx>=0.27
|
|
33
|
+
Requires-Dist: anyio>=4.3
|
|
34
|
+
Requires-Dist: tenacity>=8.2
|
|
35
|
+
Provides-Extra: fallback
|
|
36
|
+
Requires-Dist: browser-use>=0.1.30; extra == "fallback"
|
|
37
|
+
Provides-Extra: vision
|
|
38
|
+
Requires-Dist: Pillow>=10.0; extra == "vision"
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest-timeout>=2.3; extra == "dev"
|
|
43
|
+
Requires-Dist: pytest-cov>=4; extra == "dev"
|
|
44
|
+
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
45
|
+
Requires-Dist: trio>=0.25; extra == "dev"
|
|
46
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
47
|
+
Requires-Dist: twine>=4.0; extra == "dev"
|
|
48
|
+
Provides-Extra: test
|
|
49
|
+
Requires-Dist: pytest>=8; extra == "test"
|
|
50
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "test"
|
|
51
|
+
Requires-Dist: pytest-timeout>=2.3; extra == "test"
|
|
52
|
+
Requires-Dist: pytest-cov>=4; extra == "test"
|
|
53
|
+
Requires-Dist: httpx>=0.27; extra == "test"
|
|
54
|
+
Requires-Dist: trio>=0.25; extra == "test"
|
|
55
|
+
|
|
56
|
+
# SERA Browser Agent
|
|
57
|
+
|
|
58
|
+
A standalone, production-quality **Playwright-first** autonomous browser agent.
|
|
59
|
+
Receives a high-level objective, drives a real browser, reasons from a single
|
|
60
|
+
structured browser state, escalates to vision only when needed, and returns a
|
|
61
|
+
deterministic structured report.
|
|
62
|
+
|
|
63
|
+
Designed as a reusable worker that SERA can call without any Playwright
|
|
64
|
+
knowledge. Now supports a **real-view, human-takeoverable browser** for the
|
|
65
|
+
SERA assessment chat UI.
|
|
66
|
+
|
|
67
|
+
> Status: standalone. The SERA integration itself is **not** implemented in
|
|
68
|
+
> this repository — only the contract (see `docs/ARCHITECTURE.md` §17).
|
|
69
|
+
|
|
70
|
+
## Highlights
|
|
71
|
+
|
|
72
|
+
- **Playwright first.** Direct async Playwright is the normal path.
|
|
73
|
+
Accessibility-tree/snapshot-driven interaction with deterministic element
|
|
74
|
+
refs (Playwright-MCP-inspired). No MCP runtime dependency.
|
|
75
|
+
- **Reason-from-state.** One structured `BrowserState` per task; no
|
|
76
|
+
re-scraping on every step.
|
|
77
|
+
- **LLM planner with provider-agnostic layer + deterministic fallback.**
|
|
78
|
+
Optional LLM-backed planner (`SBA_LLM_PROVIDER`) receives a structured
|
|
79
|
+
state view, returns a validated action from a fixed set, and the
|
|
80
|
+
`ActionExecutor` executes it. The LLM never touches Playwright directly.
|
|
81
|
+
Supports Z.ai (`zai`), any OpenAI-compatible API (`openai` — OpenAI,
|
|
82
|
+
Azure, OpenRouter, Ollama, vLLM, ...), or `none` (deterministic only).
|
|
83
|
+
Falls back to the deterministic planner on unavailable / timeout / invalid
|
|
84
|
+
action / cancellation.
|
|
85
|
+
- **Vision is optional, not default.** Screenshots are only sent to the LLM
|
|
86
|
+
on the loop-recovery escalation path, never on every step.
|
|
87
|
+
- **Idempotent `navigate`.** If the URL is already current, the agent only
|
|
88
|
+
re-snapshots (no reload) unless reload is explicit.
|
|
89
|
+
- **Bounded everything.** Timeouts, cancellation, and bounded retries on every
|
|
90
|
+
operation.
|
|
91
|
+
- **Loop detection.** Tool repetition + semantic (dom_hash) repetition, with
|
|
92
|
+
recovery or declared block.
|
|
93
|
+
- **Network intelligence.** Structured request/response/WebSocket recording
|
|
94
|
+
with sensitive-header redaction. Reusable as a security sensor for SERA.
|
|
95
|
+
- **Challenge-aware.** Detects CAPTCHA / Turnstile / Cloudflare / hCaptcha /
|
|
96
|
+
reCAPTCHA / MFA. Uses official test keys on owned test sites; pauses for
|
|
97
|
+
human-in-the-loop otherwise. **Never bypasses** third-party protections.
|
|
98
|
+
- **Optional `browser-use` fallback.** Lazy-imported, off by default, never
|
|
99
|
+
the normal path, shares the same state/session/cancellation/result format.
|
|
100
|
+
- **Browser isolation.** Per-task isolated context. `cancel_task` +
|
|
101
|
+
`force_cleanup` guarantee no leaked Chromium / context / page / WebSocket.
|
|
102
|
+
- **Security boundaries.** SSRF on by default; explicit `local_lab` +
|
|
103
|
+
allowlist for private targets; no credential logging; selectors validated
|
|
104
|
+
against the snapshot.
|
|
105
|
+
- **Real-view browser (human-takeoverable).** When `SBA_ENABLE_VIEWER=true`,
|
|
106
|
+
the browser launches in headed mode with CDP remote debugging. The SERA
|
|
107
|
+
chat UI connects via WebSocket to watch every step in real-time
|
|
108
|
+
(screenshots + state). The human can grab control at any time via
|
|
109
|
+
`POST /tasks/{id}/human_takeover` — the agent pauses, the human interacts,
|
|
110
|
+
then `POST /tasks/{id}/resume` continues.
|
|
111
|
+
|
|
112
|
+
## Quick start
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
pip install sera-browser
|
|
116
|
+
playwright install chromium
|
|
117
|
+
sera-browser # API on 127.0.0.1:8765
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Or for development:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
git clone https://github.com/mir-ashiq/sera-browser.git
|
|
124
|
+
cd sera-browser
|
|
125
|
+
pip install -e ".[dev]"
|
|
126
|
+
playwright install chromium
|
|
127
|
+
python -m sera_browser # API on 127.0.0.1:8765
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Create a task:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
curl -X POST http://127.0.0.1:8765/tasks \
|
|
134
|
+
-H 'content-type: application/json' \
|
|
135
|
+
-d '{
|
|
136
|
+
"target": "http://localhost:3000",
|
|
137
|
+
"task": "Analyze this application for business flows, authentication, APIs, routes, technologies and security-relevant browser behavior.",
|
|
138
|
+
"browser_mode": "headless",
|
|
139
|
+
"timeout": 180,
|
|
140
|
+
"local_lab": true,
|
|
141
|
+
"allowed_targets": ["localhost:3000", "127.0.0.1:3000"]
|
|
142
|
+
}'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Real-View Browser (Human-Takeoverable, for SERA Chat UI)
|
|
146
|
+
|
|
147
|
+
The "real view, not a relay" paradigm: the browser is a **native visible
|
|
148
|
+
window** the human can see and interact with, not a headless relay. The agent
|
|
149
|
+
streams every step to the SERA chat UI in real-time, and the human can grab
|
|
150
|
+
control at any time.
|
|
151
|
+
|
|
152
|
+
### Enable
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
SBA_ENABLE_VIEWER=true
|
|
156
|
+
SBA_VIEWER_CDP_PORT=9222
|
|
157
|
+
# The browser will launch in headed mode with CDP remote debugging.
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### How it works
|
|
161
|
+
|
|
162
|
+
1. **CDP remote debugging** — Chromium launches with `--remote-debugging-port=9222`.
|
|
163
|
+
The SERA UI (or `chrome://inspect`) can connect to the same browser instance
|
|
164
|
+
for full interactive access.
|
|
165
|
+
|
|
166
|
+
2. **Screenshot + state streaming** — after each agent step, a JPEG screenshot +
|
|
167
|
+
current URL/title/step info is streamed to connected WebSocket clients.
|
|
168
|
+
The SERA chat UI renders this stream for real-time visibility.
|
|
169
|
+
|
|
170
|
+
3. **Human takeover** — the agent (or the human via API) can trigger a takeover.
|
|
171
|
+
The agent pauses, the human interacts with the real browser window, then
|
|
172
|
+
signals "done". The agent re-observes and continues.
|
|
173
|
+
|
|
174
|
+
### API endpoints
|
|
175
|
+
|
|
176
|
+
| Method | Path | Purpose |
|
|
177
|
+
|---|---|---|
|
|
178
|
+
| GET | `/tasks/{id}/viewer` | Viewer status (CDP URL, takeover state, stats) |
|
|
179
|
+
| POST | `/tasks/{id}/human_takeover` | Pause agent for human interaction |
|
|
180
|
+
| POST | `/tasks/{id}/resume` | Resume agent after human takeover |
|
|
181
|
+
| GET | `/tasks/{id}/screenshot` | Current page screenshot (base64 data URL) |
|
|
182
|
+
| WS | `/tasks/{id}/stream` | Real-time browser state stream |
|
|
183
|
+
|
|
184
|
+
### SERA chat UI integration
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
// Connect to the real-time stream
|
|
188
|
+
const ws = new WebSocket(`ws://localhost:8765/tasks/${taskId}/stream`);
|
|
189
|
+
ws.onmessage = (event) => {
|
|
190
|
+
const data = JSON.parse(event.data);
|
|
191
|
+
if (data.type === "step") {
|
|
192
|
+
// data.data.screenshot is a base64 JPEG data URL
|
|
193
|
+
document.getElementById("browser-view").src = data.data.screenshot;
|
|
194
|
+
document.getElementById("step-info").textContent =
|
|
195
|
+
`Step ${data.data.step}: ${data.data.action} → ${data.data.url}`;
|
|
196
|
+
}
|
|
197
|
+
if (data.type === "takeover") {
|
|
198
|
+
// Show "Agent paused — human can interact" banner
|
|
199
|
+
}
|
|
200
|
+
if (data.type === "resume") {
|
|
201
|
+
// Hide the banner
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Request human takeover
|
|
206
|
+
fetch(`http://localhost:8765/tasks/${taskId}/human_takeover`, { method: "POST" });
|
|
207
|
+
|
|
208
|
+
// Resume after the human is done
|
|
209
|
+
fetch(`http://localhost:8765/tasks/${taskId}/resume`, { method: "POST" });
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### CDP direct access
|
|
213
|
+
|
|
214
|
+
The SERA UI can also connect directly to the browser via CDP for full
|
|
215
|
+
interactive control (DevTools, custom inspector, etc.):
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
http://127.0.0.1:9222 (the CDP endpoint — exposed in /tasks/{id}/viewer)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Documentation
|
|
222
|
+
|
|
223
|
+
- `docs/ARCHITECTURE.md` — component map, flow, integration contract.
|
|
224
|
+
- `docs/BROWSER-AUTOMATION.md` — operational manual, primitives, challenges.
|
|
225
|
+
- `docs/DECISIONS.md` — ADR log.
|
|
226
|
+
- `docs/RELEASE.md` — release process, PyPI Trusted Publishing, versioning.
|
|
227
|
+
- `docs/SERA-INTEGRATION.md` — SERA integration contract (library + HTTP modes).
|
|
228
|
+
|
|
229
|
+
## Installation
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# From PyPI (public):
|
|
233
|
+
pip install sera-browser
|
|
234
|
+
|
|
235
|
+
# With optional extras:
|
|
236
|
+
pip install "sera-browser[fallback,vision,dev]"
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The package is **public on PyPI**; the source repository is **private on GitHub**.
|
|
240
|
+
PyPI publishing uses Trusted Publishing (OIDC, no stored tokens).
|
|
241
|
+
|
|
242
|
+
## License
|
|
243
|
+
|
|
244
|
+
Apache-2.0.
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# SERA Browser Agent
|
|
2
|
+
|
|
3
|
+
A standalone, production-quality **Playwright-first** autonomous browser agent.
|
|
4
|
+
Receives a high-level objective, drives a real browser, reasons from a single
|
|
5
|
+
structured browser state, escalates to vision only when needed, and returns a
|
|
6
|
+
deterministic structured report.
|
|
7
|
+
|
|
8
|
+
Designed as a reusable worker that SERA can call without any Playwright
|
|
9
|
+
knowledge. Now supports a **real-view, human-takeoverable browser** for the
|
|
10
|
+
SERA assessment chat UI.
|
|
11
|
+
|
|
12
|
+
> Status: standalone. The SERA integration itself is **not** implemented in
|
|
13
|
+
> this repository — only the contract (see `docs/ARCHITECTURE.md` §17).
|
|
14
|
+
|
|
15
|
+
## Highlights
|
|
16
|
+
|
|
17
|
+
- **Playwright first.** Direct async Playwright is the normal path.
|
|
18
|
+
Accessibility-tree/snapshot-driven interaction with deterministic element
|
|
19
|
+
refs (Playwright-MCP-inspired). No MCP runtime dependency.
|
|
20
|
+
- **Reason-from-state.** One structured `BrowserState` per task; no
|
|
21
|
+
re-scraping on every step.
|
|
22
|
+
- **LLM planner with provider-agnostic layer + deterministic fallback.**
|
|
23
|
+
Optional LLM-backed planner (`SBA_LLM_PROVIDER`) receives a structured
|
|
24
|
+
state view, returns a validated action from a fixed set, and the
|
|
25
|
+
`ActionExecutor` executes it. The LLM never touches Playwright directly.
|
|
26
|
+
Supports Z.ai (`zai`), any OpenAI-compatible API (`openai` — OpenAI,
|
|
27
|
+
Azure, OpenRouter, Ollama, vLLM, ...), or `none` (deterministic only).
|
|
28
|
+
Falls back to the deterministic planner on unavailable / timeout / invalid
|
|
29
|
+
action / cancellation.
|
|
30
|
+
- **Vision is optional, not default.** Screenshots are only sent to the LLM
|
|
31
|
+
on the loop-recovery escalation path, never on every step.
|
|
32
|
+
- **Idempotent `navigate`.** If the URL is already current, the agent only
|
|
33
|
+
re-snapshots (no reload) unless reload is explicit.
|
|
34
|
+
- **Bounded everything.** Timeouts, cancellation, and bounded retries on every
|
|
35
|
+
operation.
|
|
36
|
+
- **Loop detection.** Tool repetition + semantic (dom_hash) repetition, with
|
|
37
|
+
recovery or declared block.
|
|
38
|
+
- **Network intelligence.** Structured request/response/WebSocket recording
|
|
39
|
+
with sensitive-header redaction. Reusable as a security sensor for SERA.
|
|
40
|
+
- **Challenge-aware.** Detects CAPTCHA / Turnstile / Cloudflare / hCaptcha /
|
|
41
|
+
reCAPTCHA / MFA. Uses official test keys on owned test sites; pauses for
|
|
42
|
+
human-in-the-loop otherwise. **Never bypasses** third-party protections.
|
|
43
|
+
- **Optional `browser-use` fallback.** Lazy-imported, off by default, never
|
|
44
|
+
the normal path, shares the same state/session/cancellation/result format.
|
|
45
|
+
- **Browser isolation.** Per-task isolated context. `cancel_task` +
|
|
46
|
+
`force_cleanup` guarantee no leaked Chromium / context / page / WebSocket.
|
|
47
|
+
- **Security boundaries.** SSRF on by default; explicit `local_lab` +
|
|
48
|
+
allowlist for private targets; no credential logging; selectors validated
|
|
49
|
+
against the snapshot.
|
|
50
|
+
- **Real-view browser (human-takeoverable).** When `SBA_ENABLE_VIEWER=true`,
|
|
51
|
+
the browser launches in headed mode with CDP remote debugging. The SERA
|
|
52
|
+
chat UI connects via WebSocket to watch every step in real-time
|
|
53
|
+
(screenshots + state). The human can grab control at any time via
|
|
54
|
+
`POST /tasks/{id}/human_takeover` — the agent pauses, the human interacts,
|
|
55
|
+
then `POST /tasks/{id}/resume` continues.
|
|
56
|
+
|
|
57
|
+
## Quick start
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install sera-browser
|
|
61
|
+
playwright install chromium
|
|
62
|
+
sera-browser # API on 127.0.0.1:8765
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or for development:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
git clone https://github.com/mir-ashiq/sera-browser.git
|
|
69
|
+
cd sera-browser
|
|
70
|
+
pip install -e ".[dev]"
|
|
71
|
+
playwright install chromium
|
|
72
|
+
python -m sera_browser # API on 127.0.0.1:8765
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Create a task:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
curl -X POST http://127.0.0.1:8765/tasks \
|
|
79
|
+
-H 'content-type: application/json' \
|
|
80
|
+
-d '{
|
|
81
|
+
"target": "http://localhost:3000",
|
|
82
|
+
"task": "Analyze this application for business flows, authentication, APIs, routes, technologies and security-relevant browser behavior.",
|
|
83
|
+
"browser_mode": "headless",
|
|
84
|
+
"timeout": 180,
|
|
85
|
+
"local_lab": true,
|
|
86
|
+
"allowed_targets": ["localhost:3000", "127.0.0.1:3000"]
|
|
87
|
+
}'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Real-View Browser (Human-Takeoverable, for SERA Chat UI)
|
|
91
|
+
|
|
92
|
+
The "real view, not a relay" paradigm: the browser is a **native visible
|
|
93
|
+
window** the human can see and interact with, not a headless relay. The agent
|
|
94
|
+
streams every step to the SERA chat UI in real-time, and the human can grab
|
|
95
|
+
control at any time.
|
|
96
|
+
|
|
97
|
+
### Enable
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
SBA_ENABLE_VIEWER=true
|
|
101
|
+
SBA_VIEWER_CDP_PORT=9222
|
|
102
|
+
# The browser will launch in headed mode with CDP remote debugging.
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### How it works
|
|
106
|
+
|
|
107
|
+
1. **CDP remote debugging** — Chromium launches with `--remote-debugging-port=9222`.
|
|
108
|
+
The SERA UI (or `chrome://inspect`) can connect to the same browser instance
|
|
109
|
+
for full interactive access.
|
|
110
|
+
|
|
111
|
+
2. **Screenshot + state streaming** — after each agent step, a JPEG screenshot +
|
|
112
|
+
current URL/title/step info is streamed to connected WebSocket clients.
|
|
113
|
+
The SERA chat UI renders this stream for real-time visibility.
|
|
114
|
+
|
|
115
|
+
3. **Human takeover** — the agent (or the human via API) can trigger a takeover.
|
|
116
|
+
The agent pauses, the human interacts with the real browser window, then
|
|
117
|
+
signals "done". The agent re-observes and continues.
|
|
118
|
+
|
|
119
|
+
### API endpoints
|
|
120
|
+
|
|
121
|
+
| Method | Path | Purpose |
|
|
122
|
+
|---|---|---|
|
|
123
|
+
| GET | `/tasks/{id}/viewer` | Viewer status (CDP URL, takeover state, stats) |
|
|
124
|
+
| POST | `/tasks/{id}/human_takeover` | Pause agent for human interaction |
|
|
125
|
+
| POST | `/tasks/{id}/resume` | Resume agent after human takeover |
|
|
126
|
+
| GET | `/tasks/{id}/screenshot` | Current page screenshot (base64 data URL) |
|
|
127
|
+
| WS | `/tasks/{id}/stream` | Real-time browser state stream |
|
|
128
|
+
|
|
129
|
+
### SERA chat UI integration
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
// Connect to the real-time stream
|
|
133
|
+
const ws = new WebSocket(`ws://localhost:8765/tasks/${taskId}/stream`);
|
|
134
|
+
ws.onmessage = (event) => {
|
|
135
|
+
const data = JSON.parse(event.data);
|
|
136
|
+
if (data.type === "step") {
|
|
137
|
+
// data.data.screenshot is a base64 JPEG data URL
|
|
138
|
+
document.getElementById("browser-view").src = data.data.screenshot;
|
|
139
|
+
document.getElementById("step-info").textContent =
|
|
140
|
+
`Step ${data.data.step}: ${data.data.action} → ${data.data.url}`;
|
|
141
|
+
}
|
|
142
|
+
if (data.type === "takeover") {
|
|
143
|
+
// Show "Agent paused — human can interact" banner
|
|
144
|
+
}
|
|
145
|
+
if (data.type === "resume") {
|
|
146
|
+
// Hide the banner
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// Request human takeover
|
|
151
|
+
fetch(`http://localhost:8765/tasks/${taskId}/human_takeover`, { method: "POST" });
|
|
152
|
+
|
|
153
|
+
// Resume after the human is done
|
|
154
|
+
fetch(`http://localhost:8765/tasks/${taskId}/resume`, { method: "POST" });
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### CDP direct access
|
|
158
|
+
|
|
159
|
+
The SERA UI can also connect directly to the browser via CDP for full
|
|
160
|
+
interactive control (DevTools, custom inspector, etc.):
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
http://127.0.0.1:9222 (the CDP endpoint — exposed in /tasks/{id}/viewer)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Documentation
|
|
167
|
+
|
|
168
|
+
- `docs/ARCHITECTURE.md` — component map, flow, integration contract.
|
|
169
|
+
- `docs/BROWSER-AUTOMATION.md` — operational manual, primitives, challenges.
|
|
170
|
+
- `docs/DECISIONS.md` — ADR log.
|
|
171
|
+
- `docs/RELEASE.md` — release process, PyPI Trusted Publishing, versioning.
|
|
172
|
+
- `docs/SERA-INTEGRATION.md` — SERA integration contract (library + HTTP modes).
|
|
173
|
+
|
|
174
|
+
## Installation
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
# From PyPI (public):
|
|
178
|
+
pip install sera-browser
|
|
179
|
+
|
|
180
|
+
# With optional extras:
|
|
181
|
+
pip install "sera-browser[fallback,vision,dev]"
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The package is **public on PyPI**; the source repository is **private on GitHub**.
|
|
185
|
+
PyPI publishing uses Trusted Publishing (OIDC, no stored tokens).
|
|
186
|
+
|
|
187
|
+
## License
|
|
188
|
+
|
|
189
|
+
Apache-2.0.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sera-browser"
|
|
7
|
+
version = "3.1.1"
|
|
8
|
+
description = "Standalone Playwright-first autonomous browser agent for SERA — provider-agnostic LLM planner, real-view human-takeoverable browser, CDP AX tree, multi-tab, stealth, history/replay, structured extraction."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = { text = "Apache-2.0" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "mir-ashiq", email = "imsrenpsycho@gmail.com" }
|
|
14
|
+
]
|
|
15
|
+
maintainers = [
|
|
16
|
+
{ name = "mir-ashiq", email = "imsrenpsycho@gmail.com" }
|
|
17
|
+
]
|
|
18
|
+
keywords = [
|
|
19
|
+
"playwright",
|
|
20
|
+
"browser-automation",
|
|
21
|
+
"agent",
|
|
22
|
+
"sera",
|
|
23
|
+
"security",
|
|
24
|
+
"llm",
|
|
25
|
+
"cdp",
|
|
26
|
+
"accessibility",
|
|
27
|
+
"autonomous",
|
|
28
|
+
]
|
|
29
|
+
classifiers = [
|
|
30
|
+
"Development Status :: 4 - Beta",
|
|
31
|
+
"Intended Audience :: Developers",
|
|
32
|
+
"License :: OSI Approved :: Apache Software License",
|
|
33
|
+
"Operating System :: POSIX :: Linux",
|
|
34
|
+
"Operating System :: MacOS",
|
|
35
|
+
"Programming Language :: Python :: 3",
|
|
36
|
+
"Programming Language :: Python :: 3.12",
|
|
37
|
+
"Programming Language :: Python :: 3.13",
|
|
38
|
+
"Topic :: Internet :: WWW/HTTP :: Browsers",
|
|
39
|
+
"Topic :: Software Development :: Testing",
|
|
40
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
41
|
+
"Typing :: Typed",
|
|
42
|
+
]
|
|
43
|
+
dependencies = [
|
|
44
|
+
"playwright>=1.57",
|
|
45
|
+
"fastapi>=0.110",
|
|
46
|
+
"uvicorn[standard]>=0.29",
|
|
47
|
+
"pydantic>=2.6",
|
|
48
|
+
"pydantic-settings>=2.2",
|
|
49
|
+
"httpx>=0.27",
|
|
50
|
+
"anyio>=4.3",
|
|
51
|
+
"tenacity>=8.2",
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
[project.optional-dependencies]
|
|
55
|
+
# Optional: browser-use fallback driver for difficult visual interactions.
|
|
56
|
+
fallback = [
|
|
57
|
+
"browser-use>=0.1.30",
|
|
58
|
+
]
|
|
59
|
+
# Optional: vision escalation (Set-of-Mark screenshot annotation).
|
|
60
|
+
vision = [
|
|
61
|
+
"Pillow>=10.0",
|
|
62
|
+
]
|
|
63
|
+
# Development + testing dependencies.
|
|
64
|
+
dev = [
|
|
65
|
+
"pytest>=8",
|
|
66
|
+
"pytest-asyncio>=0.23",
|
|
67
|
+
"pytest-timeout>=2.3",
|
|
68
|
+
"pytest-cov>=4",
|
|
69
|
+
"httpx>=0.27",
|
|
70
|
+
"trio>=0.25",
|
|
71
|
+
"build>=1.0",
|
|
72
|
+
"twine>=4.0",
|
|
73
|
+
]
|
|
74
|
+
# Alias for backward compatibility.
|
|
75
|
+
test = [
|
|
76
|
+
"pytest>=8",
|
|
77
|
+
"pytest-asyncio>=0.23",
|
|
78
|
+
"pytest-timeout>=2.3",
|
|
79
|
+
"pytest-cov>=4",
|
|
80
|
+
"httpx>=0.27",
|
|
81
|
+
"trio>=0.25",
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
[project.scripts]
|
|
85
|
+
sera-browser = "sera_browser_agent.__main__:main"
|
|
86
|
+
|
|
87
|
+
[project.urls]
|
|
88
|
+
Homepage = "https://github.com/mir-ashiq/sera-browser"
|
|
89
|
+
Repository = "https://github.com/mir-ashiq/sera-browser"
|
|
90
|
+
Issues = "https://github.com/mir-ashiq/sera-browser/issues"
|
|
91
|
+
Documentation = "https://github.com/mir-ashiq/sera-browser/tree/main/docs"
|
|
92
|
+
|
|
93
|
+
[tool.setuptools.packages.find]
|
|
94
|
+
where = ["src"]
|
|
95
|
+
|
|
96
|
+
[tool.setuptools.package-data]
|
|
97
|
+
sera_browser_agent = ["py.typed"]
|
|
98
|
+
|
|
99
|
+
[tool.pytest.ini_options]
|
|
100
|
+
asyncio_mode = "auto"
|
|
101
|
+
testpaths = ["tests"]
|
|
102
|
+
markers = [
|
|
103
|
+
"juice_shop: tests requiring OWASP Juice Shop to be running",
|
|
104
|
+
"slow: tests that take more than 10 seconds",
|
|
105
|
+
]
|
|
106
|
+
addopts = "-ra --strict-markers"
|
|
107
|
+
filterwarnings = [
|
|
108
|
+
"error::DeprecationWarning:playwright.*",
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
[tool.coverage.run]
|
|
112
|
+
source = ["sera_browser_agent"]
|
|
113
|
+
branch = true
|
|
114
|
+
|
|
115
|
+
[tool.coverage.report]
|
|
116
|
+
exclude_lines = [
|
|
117
|
+
"pragma: no cover",
|
|
118
|
+
"def __repr__",
|
|
119
|
+
"raise NotImplementedError",
|
|
120
|
+
"if __name__ == .__main__.:",
|
|
121
|
+
"pass",
|
|
122
|
+
"if TYPE_CHECKING:",
|
|
123
|
+
]
|