simplex 2.0.5__tar.gz → 3.0.2__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.
- simplex-3.0.2/PKG-INFO +292 -0
- simplex-3.0.2/README.md +259 -0
- {simplex-2.0.5 → simplex-3.0.2}/pyproject.toml +9 -1
- {simplex-2.0.5 → simplex-3.0.2}/simplex/__init__.py +18 -1
- {simplex-2.0.5 → simplex-3.0.2}/simplex/_http_client.py +46 -3
- simplex-3.0.2/simplex/cli/__init__.py +0 -0
- simplex-3.0.2/simplex/cli/auth.py +201 -0
- simplex-3.0.2/simplex/cli/config.py +93 -0
- simplex-3.0.2/simplex/cli/connect.py +304 -0
- simplex-3.0.2/simplex/cli/editor.py +88 -0
- simplex-3.0.2/simplex/cli/main.py +50 -0
- simplex-3.0.2/simplex/cli/output.py +45 -0
- simplex-3.0.2/simplex/cli/run.py +198 -0
- simplex-3.0.2/simplex/cli/send.py +51 -0
- simplex-3.0.2/simplex/cli/sessions.py +119 -0
- simplex-3.0.2/simplex/cli/variables.py +74 -0
- simplex-3.0.2/simplex/cli/workflows.py +343 -0
- simplex-3.0.2/simplex/client.py +687 -0
- simplex-3.0.2/simplex/types.py +213 -0
- simplex-3.0.2/simplex/webhook.py +70 -0
- simplex-3.0.2/simplex.egg-info/PKG-INFO +292 -0
- simplex-3.0.2/simplex.egg-info/SOURCES.txt +29 -0
- simplex-3.0.2/simplex.egg-info/entry_points.txt +2 -0
- {simplex-2.0.5 → simplex-3.0.2}/simplex.egg-info/requires.txt +2 -0
- simplex-2.0.5/PKG-INFO +0 -224
- simplex-2.0.5/README.md +0 -193
- simplex-2.0.5/simplex/client.py +0 -293
- simplex-2.0.5/simplex/types.py +0 -72
- simplex-2.0.5/simplex.egg-info/PKG-INFO +0 -224
- simplex-2.0.5/simplex.egg-info/SOURCES.txt +0 -15
- {simplex-2.0.5 → simplex-3.0.2}/LICENSE +0 -0
- {simplex-2.0.5 → simplex-3.0.2}/MANIFEST.in +0 -0
- {simplex-2.0.5 → simplex-3.0.2}/requirements.txt +0 -0
- {simplex-2.0.5 → simplex-3.0.2}/setup.cfg +0 -0
- {simplex-2.0.5 → simplex-3.0.2}/simplex/errors.py +0 -0
- {simplex-2.0.5 → simplex-3.0.2}/simplex.egg-info/dependency_links.txt +0 -0
- {simplex-2.0.5 → simplex-3.0.2}/simplex.egg-info/top_level.txt +0 -0
simplex-3.0.2/PKG-INFO
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simplex
|
|
3
|
+
Version: 3.0.2
|
|
4
|
+
Summary: Official Python SDK for the Simplex API
|
|
5
|
+
Author-email: Simplex <support@simplex.sh>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://simplex.sh
|
|
8
|
+
Project-URL: Documentation, https://docs.simplex.sh
|
|
9
|
+
Project-URL: Repository, https://github.com/simplexlabs/simplex-python
|
|
10
|
+
Keywords: simplex,api,sdk,workflow,automation,browser,scraping
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Operating System :: OS Independent
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: requests>=2.25.0
|
|
26
|
+
Requires-Dist: typer>=0.9.0
|
|
27
|
+
Requires-Dist: rich>=13.0.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
30
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: types-requests>=2.25.0; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# Simplex Python SDK & CLI
|
|
35
|
+
|
|
36
|
+
Official Python SDK and CLI for the [Simplex](https://simplex.sh) browser automation platform.
|
|
37
|
+
|
|
38
|
+
[](https://www.python.org/downloads/)
|
|
39
|
+
[](https://opensource.org/licenses/MIT)
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install simplex
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This installs both the Python SDK (`from simplex import SimplexClient`) and the CLI (`simplex` command).
|
|
48
|
+
|
|
49
|
+
## Authentication
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Option 1: Environment variable
|
|
53
|
+
export SIMPLEX_API_KEY="your-api-key"
|
|
54
|
+
|
|
55
|
+
# Option 2: Login command (saves to ~/.simplex/credentials)
|
|
56
|
+
simplex login
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Claude Code Plugin
|
|
60
|
+
|
|
61
|
+
Give Claude Code full knowledge of the Simplex CLI and SDK:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
/plugin install simplexlabs/simplex-python
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Once installed, Claude Code automatically knows how to use `simplex editor`, `simplex connect`, `simplex run`, and the full Python SDK.
|
|
68
|
+
|
|
69
|
+
## CLI
|
|
70
|
+
|
|
71
|
+
### `simplex editor` — Create a workflow and start an interactive session
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
simplex editor --name "My Workflow" --url "https://example.com"
|
|
75
|
+
simplex editor -n "My Workflow" -u "https://example.com" --var key=value
|
|
76
|
+
simplex editor -n "Test" -u "https://example.com" --json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Creates a workflow, starts a browser session, and streams live agent events. Prints session info (session_id, workflow_id, vnc_url) then streams SSE events until Ctrl+C.
|
|
80
|
+
|
|
81
|
+
### `simplex connect` — Stream events from a running session
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
simplex connect <session_id>
|
|
85
|
+
simplex connect "https://host:port/stream" --json
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### `simplex run` — Run an existing workflow
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
simplex run <workflow_id>
|
|
92
|
+
simplex run <workflow_id> --var email=test@test.com --watch
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `simplex send` — Send a message to a running session
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
simplex send <session_id> "Click the login button"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### `simplex pause` / `simplex resume`
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
simplex pause <session_id>
|
|
105
|
+
simplex resume <session_id>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `simplex workflows list`
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
simplex workflows list --name "search term"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `simplex sessions`
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
simplex sessions status <session_id>
|
|
118
|
+
simplex sessions logs <session_id>
|
|
119
|
+
simplex sessions download <session_id> --filename report.pdf --output ./report.pdf
|
|
120
|
+
simplex sessions replay <session_id> --output replay.mp4
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### `simplex login` / `whoami` / `logout`
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
simplex login # Prompts for API key
|
|
127
|
+
simplex whoami # Shows current auth status
|
|
128
|
+
simplex logout # Removes saved credentials
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Python SDK
|
|
132
|
+
|
|
133
|
+
### Quick Start
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from simplex import SimplexClient
|
|
137
|
+
|
|
138
|
+
client = SimplexClient(api_key="your-api-key")
|
|
139
|
+
|
|
140
|
+
# Start an interactive editor session
|
|
141
|
+
result = client.start_editor_session(
|
|
142
|
+
name="My Session",
|
|
143
|
+
url="https://example.com",
|
|
144
|
+
test_data={"username": "test"},
|
|
145
|
+
)
|
|
146
|
+
print(f"Session: {result['session_id']}")
|
|
147
|
+
print(f"VNC: {result['vnc_url']}")
|
|
148
|
+
|
|
149
|
+
# Stream live events
|
|
150
|
+
for event in client.stream_session(result["logs_url"]):
|
|
151
|
+
print(event)
|
|
152
|
+
|
|
153
|
+
# Send a message to the agent
|
|
154
|
+
client.send_message(result["message_url"], "Click the login button")
|
|
155
|
+
|
|
156
|
+
# Close the session
|
|
157
|
+
client.close_session(result["session_id"])
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Client
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
client = SimplexClient(
|
|
164
|
+
api_key="your-api-key",
|
|
165
|
+
base_url="https://api.simplex.sh", # Optional
|
|
166
|
+
timeout=30, # Request timeout in seconds
|
|
167
|
+
max_retries=3, # Retry attempts
|
|
168
|
+
retry_delay=1.0, # Delay between retries
|
|
169
|
+
)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Workflow Management
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
# Create
|
|
176
|
+
result = client.create_workflow(name="My Workflow", url="https://example.com")
|
|
177
|
+
workflow_id = result["workflow"]["id"]
|
|
178
|
+
|
|
179
|
+
# Get
|
|
180
|
+
workflow = client.get_workflow(workflow_id)
|
|
181
|
+
|
|
182
|
+
# Update
|
|
183
|
+
client.update_workflow(workflow_id, name="New Name", url="https://new-url.com")
|
|
184
|
+
|
|
185
|
+
# Search
|
|
186
|
+
results = client.search_workflows(workflow_name="search term")
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Editor Sessions
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
# Start an editor session (creates workflow + browser session)
|
|
193
|
+
# NOTE: Takes 10-15 seconds. Use timeout=120.
|
|
194
|
+
result = client.start_editor_session(
|
|
195
|
+
name="My Session",
|
|
196
|
+
url="https://example.com",
|
|
197
|
+
test_data={"username": "test"},
|
|
198
|
+
)
|
|
199
|
+
# Returns: succeeded, workflow_id, session_id, vnc_url, logs_url, message_url, filesystem_url
|
|
200
|
+
|
|
201
|
+
# Stream live SSE events
|
|
202
|
+
for event in client.stream_session(result["logs_url"]):
|
|
203
|
+
event_type = event.get("event") or event.get("type", "")
|
|
204
|
+
print(f"[{event_type}] {event}")
|
|
205
|
+
|
|
206
|
+
# Send a message to the agent
|
|
207
|
+
client.send_message(result["message_url"], "Click the login button")
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Run Workflows
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
import time
|
|
214
|
+
|
|
215
|
+
result = client.run_workflow("workflow-id", variables={"key": "value"})
|
|
216
|
+
|
|
217
|
+
# Poll for completion
|
|
218
|
+
while True:
|
|
219
|
+
status = client.get_session_status(result["session_id"])
|
|
220
|
+
if not status["in_progress"]:
|
|
221
|
+
break
|
|
222
|
+
time.sleep(2)
|
|
223
|
+
|
|
224
|
+
if status["success"]:
|
|
225
|
+
print(status["scraper_outputs"])
|
|
226
|
+
print(status["structured_output"])
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Session Management
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
client.pause(session_id)
|
|
233
|
+
client.resume(session_id)
|
|
234
|
+
client.close_session(session_id)
|
|
235
|
+
client.get_session_status(session_id)
|
|
236
|
+
client.retrieve_session_logs(session_id)
|
|
237
|
+
client.download_session_files(session_id)
|
|
238
|
+
client.retrieve_session_replay(session_id)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## SSE Event Format
|
|
242
|
+
|
|
243
|
+
Events from `stream_session()` are dicts. The event type is in the `event` key:
|
|
244
|
+
|
|
245
|
+
| Event | Description |
|
|
246
|
+
|-------|-------------|
|
|
247
|
+
| `RunContent` | Agent text output |
|
|
248
|
+
| `ToolCallStarted` | Tool invocation started |
|
|
249
|
+
| `ToolCallCompleted` | Tool result |
|
|
250
|
+
| `FlowPaused` | Session paused |
|
|
251
|
+
| `FlowResumed` | Session resumed |
|
|
252
|
+
| `RunCompleted` | Agent finished |
|
|
253
|
+
| `RunError` | Error occurred |
|
|
254
|
+
|
|
255
|
+
## Error Handling
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
from simplex import (
|
|
259
|
+
SimplexError,
|
|
260
|
+
AuthenticationError,
|
|
261
|
+
RateLimitError,
|
|
262
|
+
NetworkError,
|
|
263
|
+
ValidationError,
|
|
264
|
+
WorkflowError,
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
try:
|
|
268
|
+
result = client.run_workflow("workflow-id")
|
|
269
|
+
except AuthenticationError:
|
|
270
|
+
print("Invalid API key")
|
|
271
|
+
except RateLimitError as e:
|
|
272
|
+
print(f"Rate limited. Retry after {e.retry_after}s")
|
|
273
|
+
except WorkflowError as e:
|
|
274
|
+
print(f"Workflow error: {e.message}, session: {e.session_id}")
|
|
275
|
+
except SimplexError as e:
|
|
276
|
+
print(f"Error: {e.message}")
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Requirements
|
|
280
|
+
|
|
281
|
+
- Python 3.9+
|
|
282
|
+
- `requests>=2.25.0`
|
|
283
|
+
|
|
284
|
+
## License
|
|
285
|
+
|
|
286
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
287
|
+
|
|
288
|
+
## Links
|
|
289
|
+
|
|
290
|
+
- [Simplex](https://simplex.sh)
|
|
291
|
+
- [Documentation](https://docs.simplex.sh)
|
|
292
|
+
- [Support](mailto:support@simplex.sh)
|
simplex-3.0.2/README.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# Simplex Python SDK & CLI
|
|
2
|
+
|
|
3
|
+
Official Python SDK and CLI for the [Simplex](https://simplex.sh) browser automation platform.
|
|
4
|
+
|
|
5
|
+
[](https://www.python.org/downloads/)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install simplex
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
This installs both the Python SDK (`from simplex import SimplexClient`) and the CLI (`simplex` command).
|
|
15
|
+
|
|
16
|
+
## Authentication
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Option 1: Environment variable
|
|
20
|
+
export SIMPLEX_API_KEY="your-api-key"
|
|
21
|
+
|
|
22
|
+
# Option 2: Login command (saves to ~/.simplex/credentials)
|
|
23
|
+
simplex login
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Claude Code Plugin
|
|
27
|
+
|
|
28
|
+
Give Claude Code full knowledge of the Simplex CLI and SDK:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
/plugin install simplexlabs/simplex-python
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Once installed, Claude Code automatically knows how to use `simplex editor`, `simplex connect`, `simplex run`, and the full Python SDK.
|
|
35
|
+
|
|
36
|
+
## CLI
|
|
37
|
+
|
|
38
|
+
### `simplex editor` — Create a workflow and start an interactive session
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
simplex editor --name "My Workflow" --url "https://example.com"
|
|
42
|
+
simplex editor -n "My Workflow" -u "https://example.com" --var key=value
|
|
43
|
+
simplex editor -n "Test" -u "https://example.com" --json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Creates a workflow, starts a browser session, and streams live agent events. Prints session info (session_id, workflow_id, vnc_url) then streams SSE events until Ctrl+C.
|
|
47
|
+
|
|
48
|
+
### `simplex connect` — Stream events from a running session
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
simplex connect <session_id>
|
|
52
|
+
simplex connect "https://host:port/stream" --json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### `simplex run` — Run an existing workflow
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
simplex run <workflow_id>
|
|
59
|
+
simplex run <workflow_id> --var email=test@test.com --watch
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### `simplex send` — Send a message to a running session
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
simplex send <session_id> "Click the login button"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `simplex pause` / `simplex resume`
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
simplex pause <session_id>
|
|
72
|
+
simplex resume <session_id>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### `simplex workflows list`
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
simplex workflows list --name "search term"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### `simplex sessions`
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
simplex sessions status <session_id>
|
|
85
|
+
simplex sessions logs <session_id>
|
|
86
|
+
simplex sessions download <session_id> --filename report.pdf --output ./report.pdf
|
|
87
|
+
simplex sessions replay <session_id> --output replay.mp4
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### `simplex login` / `whoami` / `logout`
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
simplex login # Prompts for API key
|
|
94
|
+
simplex whoami # Shows current auth status
|
|
95
|
+
simplex logout # Removes saved credentials
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Python SDK
|
|
99
|
+
|
|
100
|
+
### Quick Start
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from simplex import SimplexClient
|
|
104
|
+
|
|
105
|
+
client = SimplexClient(api_key="your-api-key")
|
|
106
|
+
|
|
107
|
+
# Start an interactive editor session
|
|
108
|
+
result = client.start_editor_session(
|
|
109
|
+
name="My Session",
|
|
110
|
+
url="https://example.com",
|
|
111
|
+
test_data={"username": "test"},
|
|
112
|
+
)
|
|
113
|
+
print(f"Session: {result['session_id']}")
|
|
114
|
+
print(f"VNC: {result['vnc_url']}")
|
|
115
|
+
|
|
116
|
+
# Stream live events
|
|
117
|
+
for event in client.stream_session(result["logs_url"]):
|
|
118
|
+
print(event)
|
|
119
|
+
|
|
120
|
+
# Send a message to the agent
|
|
121
|
+
client.send_message(result["message_url"], "Click the login button")
|
|
122
|
+
|
|
123
|
+
# Close the session
|
|
124
|
+
client.close_session(result["session_id"])
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Client
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
client = SimplexClient(
|
|
131
|
+
api_key="your-api-key",
|
|
132
|
+
base_url="https://api.simplex.sh", # Optional
|
|
133
|
+
timeout=30, # Request timeout in seconds
|
|
134
|
+
max_retries=3, # Retry attempts
|
|
135
|
+
retry_delay=1.0, # Delay between retries
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Workflow Management
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
# Create
|
|
143
|
+
result = client.create_workflow(name="My Workflow", url="https://example.com")
|
|
144
|
+
workflow_id = result["workflow"]["id"]
|
|
145
|
+
|
|
146
|
+
# Get
|
|
147
|
+
workflow = client.get_workflow(workflow_id)
|
|
148
|
+
|
|
149
|
+
# Update
|
|
150
|
+
client.update_workflow(workflow_id, name="New Name", url="https://new-url.com")
|
|
151
|
+
|
|
152
|
+
# Search
|
|
153
|
+
results = client.search_workflows(workflow_name="search term")
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Editor Sessions
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
# Start an editor session (creates workflow + browser session)
|
|
160
|
+
# NOTE: Takes 10-15 seconds. Use timeout=120.
|
|
161
|
+
result = client.start_editor_session(
|
|
162
|
+
name="My Session",
|
|
163
|
+
url="https://example.com",
|
|
164
|
+
test_data={"username": "test"},
|
|
165
|
+
)
|
|
166
|
+
# Returns: succeeded, workflow_id, session_id, vnc_url, logs_url, message_url, filesystem_url
|
|
167
|
+
|
|
168
|
+
# Stream live SSE events
|
|
169
|
+
for event in client.stream_session(result["logs_url"]):
|
|
170
|
+
event_type = event.get("event") or event.get("type", "")
|
|
171
|
+
print(f"[{event_type}] {event}")
|
|
172
|
+
|
|
173
|
+
# Send a message to the agent
|
|
174
|
+
client.send_message(result["message_url"], "Click the login button")
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Run Workflows
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
import time
|
|
181
|
+
|
|
182
|
+
result = client.run_workflow("workflow-id", variables={"key": "value"})
|
|
183
|
+
|
|
184
|
+
# Poll for completion
|
|
185
|
+
while True:
|
|
186
|
+
status = client.get_session_status(result["session_id"])
|
|
187
|
+
if not status["in_progress"]:
|
|
188
|
+
break
|
|
189
|
+
time.sleep(2)
|
|
190
|
+
|
|
191
|
+
if status["success"]:
|
|
192
|
+
print(status["scraper_outputs"])
|
|
193
|
+
print(status["structured_output"])
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Session Management
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
client.pause(session_id)
|
|
200
|
+
client.resume(session_id)
|
|
201
|
+
client.close_session(session_id)
|
|
202
|
+
client.get_session_status(session_id)
|
|
203
|
+
client.retrieve_session_logs(session_id)
|
|
204
|
+
client.download_session_files(session_id)
|
|
205
|
+
client.retrieve_session_replay(session_id)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## SSE Event Format
|
|
209
|
+
|
|
210
|
+
Events from `stream_session()` are dicts. The event type is in the `event` key:
|
|
211
|
+
|
|
212
|
+
| Event | Description |
|
|
213
|
+
|-------|-------------|
|
|
214
|
+
| `RunContent` | Agent text output |
|
|
215
|
+
| `ToolCallStarted` | Tool invocation started |
|
|
216
|
+
| `ToolCallCompleted` | Tool result |
|
|
217
|
+
| `FlowPaused` | Session paused |
|
|
218
|
+
| `FlowResumed` | Session resumed |
|
|
219
|
+
| `RunCompleted` | Agent finished |
|
|
220
|
+
| `RunError` | Error occurred |
|
|
221
|
+
|
|
222
|
+
## Error Handling
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
from simplex import (
|
|
226
|
+
SimplexError,
|
|
227
|
+
AuthenticationError,
|
|
228
|
+
RateLimitError,
|
|
229
|
+
NetworkError,
|
|
230
|
+
ValidationError,
|
|
231
|
+
WorkflowError,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
try:
|
|
235
|
+
result = client.run_workflow("workflow-id")
|
|
236
|
+
except AuthenticationError:
|
|
237
|
+
print("Invalid API key")
|
|
238
|
+
except RateLimitError as e:
|
|
239
|
+
print(f"Rate limited. Retry after {e.retry_after}s")
|
|
240
|
+
except WorkflowError as e:
|
|
241
|
+
print(f"Workflow error: {e.message}, session: {e.session_id}")
|
|
242
|
+
except SimplexError as e:
|
|
243
|
+
print(f"Error: {e.message}")
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Requirements
|
|
247
|
+
|
|
248
|
+
- Python 3.9+
|
|
249
|
+
- `requests>=2.25.0`
|
|
250
|
+
|
|
251
|
+
## License
|
|
252
|
+
|
|
253
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
254
|
+
|
|
255
|
+
## Links
|
|
256
|
+
|
|
257
|
+
- [Simplex](https://simplex.sh)
|
|
258
|
+
- [Documentation](https://docs.simplex.sh)
|
|
259
|
+
- [Support](mailto:support@simplex.sh)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simplex"
|
|
7
|
-
version = "
|
|
7
|
+
version = "3.0.2"
|
|
8
8
|
description = "Official Python SDK for the Simplex API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -28,8 +28,13 @@ classifiers = [
|
|
|
28
28
|
]
|
|
29
29
|
dependencies = [
|
|
30
30
|
"requests>=2.25.0",
|
|
31
|
+
"typer>=0.9.0",
|
|
32
|
+
"rich>=13.0.0",
|
|
31
33
|
]
|
|
32
34
|
|
|
35
|
+
[project.scripts]
|
|
36
|
+
simplex = "simplex.cli.main:app"
|
|
37
|
+
|
|
33
38
|
[project.optional-dependencies]
|
|
34
39
|
dev = [
|
|
35
40
|
"pytest>=7.0.0",
|
|
@@ -42,6 +47,9 @@ Homepage = "https://simplex.sh"
|
|
|
42
47
|
Documentation = "https://docs.simplex.sh"
|
|
43
48
|
Repository = "https://github.com/simplexlabs/simplex-python"
|
|
44
49
|
|
|
50
|
+
[tool.setuptools.packages.find]
|
|
51
|
+
include = ["simplex*"]
|
|
52
|
+
|
|
45
53
|
[tool.mypy]
|
|
46
54
|
python_version = "3.9"
|
|
47
55
|
warn_return_any = true
|
|
@@ -31,11 +31,19 @@ from simplex.errors import (
|
|
|
31
31
|
)
|
|
32
32
|
from simplex.types import (
|
|
33
33
|
FileMetadata,
|
|
34
|
+
PauseSessionResponse,
|
|
35
|
+
ResumeSessionResponse,
|
|
34
36
|
RunWorkflowResponse,
|
|
37
|
+
SearchWorkflowItem,
|
|
38
|
+
SearchWorkflowsResponse,
|
|
35
39
|
SessionStatusResponse,
|
|
40
|
+
StartEditorSessionResponse,
|
|
41
|
+
UpdateWorkflowMetadataResponse,
|
|
42
|
+
WebhookPayload,
|
|
36
43
|
)
|
|
44
|
+
from simplex.webhook import WebhookVerificationError, verify_simplex_webhook
|
|
37
45
|
|
|
38
|
-
__version__ = "
|
|
46
|
+
__version__ = "3.0.2"
|
|
39
47
|
__all__ = [
|
|
40
48
|
"SimplexClient",
|
|
41
49
|
"SimplexError",
|
|
@@ -47,4 +55,13 @@ __all__ = [
|
|
|
47
55
|
"FileMetadata",
|
|
48
56
|
"SessionStatusResponse",
|
|
49
57
|
"RunWorkflowResponse",
|
|
58
|
+
"PauseSessionResponse",
|
|
59
|
+
"ResumeSessionResponse",
|
|
60
|
+
"SearchWorkflowsResponse",
|
|
61
|
+
"SearchWorkflowItem",
|
|
62
|
+
"StartEditorSessionResponse",
|
|
63
|
+
"UpdateWorkflowMetadataResponse",
|
|
64
|
+
"WebhookPayload",
|
|
65
|
+
"verify_simplex_webhook",
|
|
66
|
+
"WebhookVerificationError",
|
|
50
67
|
]
|
|
@@ -21,7 +21,7 @@ from simplex.errors import (
|
|
|
21
21
|
ValidationError,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
|
-
__version__ = "
|
|
24
|
+
__version__ = "3.0.2"
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
class HttpClient:
|
|
@@ -77,6 +77,7 @@ class HttpClient:
|
|
|
77
77
|
"""Convert HTTP errors to appropriate exception types."""
|
|
78
78
|
status_code = response.status_code
|
|
79
79
|
|
|
80
|
+
data = None
|
|
80
81
|
try:
|
|
81
82
|
data = response.json()
|
|
82
83
|
if isinstance(data, dict):
|
|
@@ -87,7 +88,7 @@ class HttpClient:
|
|
|
87
88
|
message = response.text or "An error occurred"
|
|
88
89
|
|
|
89
90
|
if status_code == 400:
|
|
90
|
-
return ValidationError(message, data=
|
|
91
|
+
return ValidationError(message, data=data)
|
|
91
92
|
elif status_code in [401, 403]:
|
|
92
93
|
return AuthenticationError(message)
|
|
93
94
|
elif status_code == 429:
|
|
@@ -95,7 +96,7 @@ class HttpClient:
|
|
|
95
96
|
retry_after_seconds = int(retry_after) if retry_after and retry_after.isdigit() else None
|
|
96
97
|
return RateLimitError(message, retry_after=retry_after_seconds)
|
|
97
98
|
else:
|
|
98
|
-
return SimplexError(message, status_code=status_code, data=
|
|
99
|
+
return SimplexError(message, status_code=status_code, data=data)
|
|
99
100
|
|
|
100
101
|
def _make_request(
|
|
101
102
|
self,
|
|
@@ -205,6 +206,48 @@ class HttpClient:
|
|
|
205
206
|
)
|
|
206
207
|
return response.json()
|
|
207
208
|
|
|
209
|
+
def post_json(self, path: str, data: dict | None = None) -> Any:
|
|
210
|
+
"""POST with JSON body."""
|
|
211
|
+
response = self._make_request("POST", path, json=data)
|
|
212
|
+
return response.json()
|
|
213
|
+
|
|
214
|
+
def patch_json(self, path: str, data: dict | None = None) -> Any:
|
|
215
|
+
"""PATCH with JSON body."""
|
|
216
|
+
response = self._make_request("PATCH", path, json=data)
|
|
217
|
+
return response.json()
|
|
218
|
+
|
|
219
|
+
def stream_sse(self, url: str) -> Any:
|
|
220
|
+
"""Connect to an SSE endpoint and yield parsed events.
|
|
221
|
+
|
|
222
|
+
Uses absolute URL (not base_url) since SSE endpoints are on container tunnels.
|
|
223
|
+
The generator ends cleanly when the connection closes (e.g. session finished).
|
|
224
|
+
"""
|
|
225
|
+
import json as json_module
|
|
226
|
+
|
|
227
|
+
response = self.session.get(url, stream=True, timeout=None)
|
|
228
|
+
response.raise_for_status()
|
|
229
|
+
try:
|
|
230
|
+
for line in response.iter_lines(decode_unicode=True):
|
|
231
|
+
if line and line.startswith("data: "):
|
|
232
|
+
try:
|
|
233
|
+
yield json_module.loads(line[6:])
|
|
234
|
+
except json_module.JSONDecodeError:
|
|
235
|
+
continue
|
|
236
|
+
except (requests.exceptions.ChunkedEncodingError, requests.exceptions.ConnectionError):
|
|
237
|
+
return # Connection closed — session ended
|
|
238
|
+
|
|
239
|
+
def post_to_url(self, url: str, json_data: dict) -> Any:
|
|
240
|
+
"""POST JSON to an absolute URL (not relative to base_url)."""
|
|
241
|
+
response = self.session.post(url, json=json_data, timeout=self.timeout)
|
|
242
|
+
response.raise_for_status()
|
|
243
|
+
return response.json()
|
|
244
|
+
|
|
245
|
+
def get_from_url(self, url: str, params: dict | None = None) -> Any:
|
|
246
|
+
"""GET from an absolute URL (not relative to base_url)."""
|
|
247
|
+
response = self.session.get(url, params=params, timeout=self.timeout)
|
|
248
|
+
response.raise_for_status()
|
|
249
|
+
return response.json()
|
|
250
|
+
|
|
208
251
|
def download_file(self, path: str, params: dict[str, Any] | None = None) -> bytes:
|
|
209
252
|
"""
|
|
210
253
|
Download a file from the API.
|
|
File without changes
|