simplex 2.0.4__tar.gz → 3.0.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.
- {simplex-2.0.4/simplex.egg-info → simplex-3.0.1}/PKG-INFO +1 -1
- {simplex-2.0.4 → simplex-3.0.1}/pyproject.toml +1 -1
- {simplex-2.0.4 → simplex-3.0.1}/simplex/__init__.py +16 -1
- {simplex-2.0.4 → simplex-3.0.1}/simplex/_http_client.py +1 -1
- {simplex-2.0.4 → simplex-3.0.1}/simplex/client.py +170 -1
- simplex-3.0.1/simplex/types.py +188 -0
- simplex-3.0.1/simplex/webhook.py +70 -0
- {simplex-2.0.4 → simplex-3.0.1/simplex.egg-info}/PKG-INFO +1 -1
- {simplex-2.0.4 → simplex-3.0.1}/simplex.egg-info/SOURCES.txt +1 -0
- simplex-2.0.4/simplex/types.py +0 -70
- {simplex-2.0.4 → simplex-3.0.1}/LICENSE +0 -0
- {simplex-2.0.4 → simplex-3.0.1}/MANIFEST.in +0 -0
- {simplex-2.0.4 → simplex-3.0.1}/README.md +0 -0
- {simplex-2.0.4 → simplex-3.0.1}/requirements.txt +0 -0
- {simplex-2.0.4 → simplex-3.0.1}/setup.cfg +0 -0
- {simplex-2.0.4 → simplex-3.0.1}/simplex/errors.py +0 -0
- {simplex-2.0.4 → simplex-3.0.1}/simplex.egg-info/dependency_links.txt +0 -0
- {simplex-2.0.4 → simplex-3.0.1}/simplex.egg-info/requires.txt +0 -0
- {simplex-2.0.4 → simplex-3.0.1}/simplex.egg-info/top_level.txt +0 -0
|
@@ -31,11 +31,18 @@ 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
|
+
UpdateWorkflowMetadataResponse,
|
|
41
|
+
WebhookPayload,
|
|
36
42
|
)
|
|
43
|
+
from simplex.webhook import WebhookVerificationError, verify_simplex_webhook
|
|
37
44
|
|
|
38
|
-
__version__ = "
|
|
45
|
+
__version__ = "3.0.1"
|
|
39
46
|
__all__ = [
|
|
40
47
|
"SimplexClient",
|
|
41
48
|
"SimplexError",
|
|
@@ -47,4 +54,12 @@ __all__ = [
|
|
|
47
54
|
"FileMetadata",
|
|
48
55
|
"SessionStatusResponse",
|
|
49
56
|
"RunWorkflowResponse",
|
|
57
|
+
"PauseSessionResponse",
|
|
58
|
+
"ResumeSessionResponse",
|
|
59
|
+
"SearchWorkflowsResponse",
|
|
60
|
+
"SearchWorkflowItem",
|
|
61
|
+
"UpdateWorkflowMetadataResponse",
|
|
62
|
+
"WebhookPayload",
|
|
63
|
+
"verify_simplex_webhook",
|
|
64
|
+
"WebhookVerificationError",
|
|
50
65
|
]
|
|
@@ -12,7 +12,14 @@ from typing import Any
|
|
|
12
12
|
|
|
13
13
|
from simplex._http_client import HttpClient
|
|
14
14
|
from simplex.errors import WorkflowError
|
|
15
|
-
from simplex.types import
|
|
15
|
+
from simplex.types import (
|
|
16
|
+
PauseSessionResponse,
|
|
17
|
+
ResumeSessionResponse,
|
|
18
|
+
RunWorkflowResponse,
|
|
19
|
+
SearchWorkflowsResponse,
|
|
20
|
+
SessionStatusResponse,
|
|
21
|
+
UpdateWorkflowMetadataResponse,
|
|
22
|
+
)
|
|
16
23
|
|
|
17
24
|
|
|
18
25
|
class SimplexClient:
|
|
@@ -291,3 +298,165 @@ class SimplexClient:
|
|
|
291
298
|
f"Failed to retrieve session logs: {e}",
|
|
292
299
|
session_id=session_id,
|
|
293
300
|
)
|
|
301
|
+
|
|
302
|
+
def pause(self, session_id: str) -> PauseSessionResponse:
|
|
303
|
+
"""
|
|
304
|
+
Pause a running session.
|
|
305
|
+
|
|
306
|
+
Args:
|
|
307
|
+
session_id: The session ID to pause
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
PauseSessionResponse with pause details
|
|
311
|
+
|
|
312
|
+
Raises:
|
|
313
|
+
WorkflowError: If pausing the session fails
|
|
314
|
+
|
|
315
|
+
Example:
|
|
316
|
+
>>> result = client.pause("session-123")
|
|
317
|
+
>>> print(f"Paused with key: {result['pause_key']}")
|
|
318
|
+
"""
|
|
319
|
+
try:
|
|
320
|
+
response: PauseSessionResponse = self._http_client.post(
|
|
321
|
+
"/pause",
|
|
322
|
+
data={"session_id": session_id},
|
|
323
|
+
)
|
|
324
|
+
if not response.get("succeeded"):
|
|
325
|
+
raise WorkflowError(
|
|
326
|
+
response.get("error", "Failed to pause session"),
|
|
327
|
+
session_id=session_id,
|
|
328
|
+
)
|
|
329
|
+
return response
|
|
330
|
+
except Exception as e:
|
|
331
|
+
if isinstance(e, WorkflowError):
|
|
332
|
+
raise
|
|
333
|
+
raise WorkflowError(
|
|
334
|
+
f"Failed to pause session: {e}",
|
|
335
|
+
session_id=session_id,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
def resume(self, session_id: str) -> ResumeSessionResponse:
|
|
339
|
+
"""
|
|
340
|
+
Resume a paused session.
|
|
341
|
+
|
|
342
|
+
Args:
|
|
343
|
+
session_id: The session ID to resume
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
ResumeSessionResponse with resume details
|
|
347
|
+
|
|
348
|
+
Raises:
|
|
349
|
+
WorkflowError: If resuming the session fails
|
|
350
|
+
|
|
351
|
+
Example:
|
|
352
|
+
>>> result = client.resume("session-123")
|
|
353
|
+
>>> print(f"Resumed, pause type: {result['pause_type']}")
|
|
354
|
+
"""
|
|
355
|
+
try:
|
|
356
|
+
response: ResumeSessionResponse = self._http_client.post(
|
|
357
|
+
"/resume_session",
|
|
358
|
+
data={"session_id": session_id},
|
|
359
|
+
)
|
|
360
|
+
if not response.get("succeeded"):
|
|
361
|
+
raise WorkflowError(
|
|
362
|
+
response.get("error", "Failed to resume session"),
|
|
363
|
+
session_id=session_id,
|
|
364
|
+
)
|
|
365
|
+
return response
|
|
366
|
+
except Exception as e:
|
|
367
|
+
if isinstance(e, WorkflowError):
|
|
368
|
+
raise
|
|
369
|
+
raise WorkflowError(
|
|
370
|
+
f"Failed to resume session: {e}",
|
|
371
|
+
session_id=session_id,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
def search_workflows(
|
|
375
|
+
self,
|
|
376
|
+
workflow_name: str | None = None,
|
|
377
|
+
metadata: str | None = None,
|
|
378
|
+
) -> SearchWorkflowsResponse:
|
|
379
|
+
"""
|
|
380
|
+
Search workflows by name and/or metadata.
|
|
381
|
+
|
|
382
|
+
At least one of workflow_name or metadata must be provided.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
workflow_name: Name of the workflow to search for
|
|
386
|
+
metadata: Metadata string to search for
|
|
387
|
+
|
|
388
|
+
Returns:
|
|
389
|
+
SearchWorkflowsResponse with matching workflows
|
|
390
|
+
|
|
391
|
+
Raises:
|
|
392
|
+
ValueError: If neither workflow_name nor metadata is provided
|
|
393
|
+
WorkflowError: If the search fails
|
|
394
|
+
|
|
395
|
+
Example:
|
|
396
|
+
>>> results = client.search_workflows(workflow_name="my-workflow")
|
|
397
|
+
>>> for wf in results["workflows"]:
|
|
398
|
+
... print(f"{wf['workflow_name']} ({wf['workflow_id']})")
|
|
399
|
+
"""
|
|
400
|
+
if workflow_name is None and metadata is None:
|
|
401
|
+
raise ValueError("At least one of workflow_name or metadata must be provided")
|
|
402
|
+
|
|
403
|
+
params: dict[str, str] = {}
|
|
404
|
+
if workflow_name is not None:
|
|
405
|
+
params["workflow_name"] = workflow_name
|
|
406
|
+
if metadata is not None:
|
|
407
|
+
params["metadata"] = metadata
|
|
408
|
+
|
|
409
|
+
try:
|
|
410
|
+
response: SearchWorkflowsResponse = self._http_client.get(
|
|
411
|
+
"/search_workflows",
|
|
412
|
+
params=params,
|
|
413
|
+
)
|
|
414
|
+
return response
|
|
415
|
+
except Exception as e:
|
|
416
|
+
if isinstance(e, WorkflowError):
|
|
417
|
+
raise
|
|
418
|
+
raise WorkflowError(f"Failed to search workflows: {e}")
|
|
419
|
+
|
|
420
|
+
def update_workflow_metadata(
|
|
421
|
+
self,
|
|
422
|
+
workflow_id: str,
|
|
423
|
+
metadata: str,
|
|
424
|
+
) -> UpdateWorkflowMetadataResponse:
|
|
425
|
+
"""
|
|
426
|
+
Update the metadata of a workflow.
|
|
427
|
+
|
|
428
|
+
Args:
|
|
429
|
+
workflow_id: The ID of the workflow to update
|
|
430
|
+
metadata: The new metadata string
|
|
431
|
+
|
|
432
|
+
Returns:
|
|
433
|
+
UpdateWorkflowMetadataResponse with update confirmation
|
|
434
|
+
|
|
435
|
+
Raises:
|
|
436
|
+
WorkflowError: If updating the metadata fails
|
|
437
|
+
|
|
438
|
+
Example:
|
|
439
|
+
>>> result = client.update_workflow_metadata(
|
|
440
|
+
... "workflow-123",
|
|
441
|
+
... "new-metadata-value"
|
|
442
|
+
... )
|
|
443
|
+
>>> print(f"Updated: {result['message']}")
|
|
444
|
+
"""
|
|
445
|
+
try:
|
|
446
|
+
response: UpdateWorkflowMetadataResponse = self._http_client.post(
|
|
447
|
+
"/update_workflow_metadata",
|
|
448
|
+
data={"workflow_id": workflow_id, "metadata": metadata},
|
|
449
|
+
)
|
|
450
|
+
if not response.get("succeeded"):
|
|
451
|
+
raise WorkflowError(
|
|
452
|
+
"Failed to update workflow metadata",
|
|
453
|
+
workflow_id=workflow_id,
|
|
454
|
+
)
|
|
455
|
+
return response
|
|
456
|
+
except Exception as e:
|
|
457
|
+
if isinstance(e, WorkflowError):
|
|
458
|
+
raise
|
|
459
|
+
raise WorkflowError(
|
|
460
|
+
f"Failed to update workflow metadata: {e}",
|
|
461
|
+
workflow_id=workflow_id,
|
|
462
|
+
)
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Type definitions for the Simplex SDK.
|
|
3
|
+
|
|
4
|
+
This module contains TypedDict classes used for type hinting throughout the SDK.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any, TypedDict
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class FileMetadata(TypedDict):
|
|
13
|
+
"""
|
|
14
|
+
Metadata for a file downloaded or created during a session.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
filename: The filename
|
|
18
|
+
download_url: The URL the file was downloaded from
|
|
19
|
+
file_size: File size in bytes
|
|
20
|
+
download_timestamp: ISO timestamp when the file was downloaded/created
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
filename: str
|
|
24
|
+
download_url: str
|
|
25
|
+
file_size: int
|
|
26
|
+
download_timestamp: str
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SessionStatusResponse(TypedDict, total=False):
|
|
30
|
+
"""
|
|
31
|
+
Response from polling session status.
|
|
32
|
+
|
|
33
|
+
Attributes:
|
|
34
|
+
in_progress: Whether the session is still running
|
|
35
|
+
success: Whether the session completed successfully (None while in progress)
|
|
36
|
+
metadata: Custom metadata provided when the session was started
|
|
37
|
+
workflow_metadata: Metadata from the workflow definition
|
|
38
|
+
file_metadata: Metadata for files downloaded during the session
|
|
39
|
+
scraper_outputs: Scraper outputs collected during the session, keyed by output name
|
|
40
|
+
structured_output: Structured output fields from workflow execution (None while in progress)
|
|
41
|
+
paused: Whether the session is currently paused
|
|
42
|
+
paused_key: The pause key if the session is paused
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
in_progress: bool
|
|
46
|
+
success: bool | None
|
|
47
|
+
metadata: dict[str, Any]
|
|
48
|
+
workflow_metadata: dict[str, Any]
|
|
49
|
+
file_metadata: list[FileMetadata]
|
|
50
|
+
scraper_outputs: dict[str, Any]
|
|
51
|
+
structured_output: dict[str, Any] | None
|
|
52
|
+
paused: bool
|
|
53
|
+
paused_key: str
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class RunWorkflowResponse(TypedDict):
|
|
57
|
+
"""
|
|
58
|
+
Response from running a workflow.
|
|
59
|
+
|
|
60
|
+
Attributes:
|
|
61
|
+
succeeded: Whether the workflow started successfully
|
|
62
|
+
message: Human-readable status message
|
|
63
|
+
session_id: Unique identifier for this workflow session
|
|
64
|
+
vnc_url: URL for VNC access to the workflow session
|
|
65
|
+
logs_url: URL for viewing session logs
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
succeeded: bool
|
|
69
|
+
message: str
|
|
70
|
+
session_id: str
|
|
71
|
+
vnc_url: str
|
|
72
|
+
logs_url: str
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class PauseSessionResponse(TypedDict, total=False):
|
|
76
|
+
"""
|
|
77
|
+
Response from pausing a session.
|
|
78
|
+
|
|
79
|
+
Attributes:
|
|
80
|
+
succeeded: Whether the pause operation succeeded
|
|
81
|
+
action: The action that was performed
|
|
82
|
+
pause_key: The key associated with the pause
|
|
83
|
+
error: Error message if the operation failed
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
succeeded: bool
|
|
87
|
+
action: str
|
|
88
|
+
pause_key: str
|
|
89
|
+
error: str
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class ResumeSessionResponse(TypedDict, total=False):
|
|
93
|
+
"""
|
|
94
|
+
Response from resuming a paused session.
|
|
95
|
+
|
|
96
|
+
Attributes:
|
|
97
|
+
succeeded: Whether the resume operation succeeded
|
|
98
|
+
action: The action that was performed
|
|
99
|
+
pause_type: The type of pause ('external' or 'internal')
|
|
100
|
+
key: The key associated with the pause
|
|
101
|
+
error: Error message if the operation failed
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
succeeded: bool
|
|
105
|
+
action: str
|
|
106
|
+
pause_type: str
|
|
107
|
+
key: str
|
|
108
|
+
error: str
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class SearchWorkflowItem(TypedDict, total=False):
|
|
112
|
+
"""
|
|
113
|
+
A single workflow item returned from a search.
|
|
114
|
+
|
|
115
|
+
Attributes:
|
|
116
|
+
workflow_id: The workflow's unique identifier
|
|
117
|
+
workflow_name: The workflow's name
|
|
118
|
+
variables: Variables defined in the workflow
|
|
119
|
+
metadata: Optional metadata string
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
workflow_id: str
|
|
123
|
+
workflow_name: str
|
|
124
|
+
variables: dict[str, Any]
|
|
125
|
+
metadata: str
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class SearchWorkflowsResponse(TypedDict):
|
|
129
|
+
"""
|
|
130
|
+
Response from searching workflows.
|
|
131
|
+
|
|
132
|
+
Attributes:
|
|
133
|
+
succeeded: Whether the search succeeded
|
|
134
|
+
workflows: List of matching workflows
|
|
135
|
+
count: Total number of matching workflows
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
succeeded: bool
|
|
139
|
+
workflows: list[SearchWorkflowItem]
|
|
140
|
+
count: int
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class UpdateWorkflowMetadataResponse(TypedDict):
|
|
144
|
+
"""
|
|
145
|
+
Response from updating workflow metadata.
|
|
146
|
+
|
|
147
|
+
Attributes:
|
|
148
|
+
succeeded: Whether the update succeeded
|
|
149
|
+
message: Human-readable status message
|
|
150
|
+
workflow_id: The workflow that was updated
|
|
151
|
+
metadata: The updated metadata string
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
succeeded: bool
|
|
155
|
+
message: str
|
|
156
|
+
workflow_id: str
|
|
157
|
+
metadata: str
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class WebhookPayload(TypedDict, total=False):
|
|
161
|
+
"""
|
|
162
|
+
Payload received from a Simplex webhook.
|
|
163
|
+
|
|
164
|
+
Attributes:
|
|
165
|
+
success: Whether the session completed successfully
|
|
166
|
+
agent_response: The agent's response text
|
|
167
|
+
session_id: The session identifier
|
|
168
|
+
file_metadata: Metadata for files created during the session
|
|
169
|
+
scraper_outputs: Scraper outputs collected during the session
|
|
170
|
+
session_metadata: Custom metadata attached to the session
|
|
171
|
+
workflow_id: The workflow identifier
|
|
172
|
+
workflow_metadata: Metadata from the workflow definition
|
|
173
|
+
workflow_result: The workflow execution result
|
|
174
|
+
structured_output: Structured output from the workflow
|
|
175
|
+
screenshot_url: URL to a screenshot taken during the session
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
success: bool
|
|
179
|
+
agent_response: str
|
|
180
|
+
session_id: str
|
|
181
|
+
file_metadata: list[FileMetadata]
|
|
182
|
+
scraper_outputs: dict[str, Any]
|
|
183
|
+
session_metadata: dict[str, Any]
|
|
184
|
+
workflow_id: str
|
|
185
|
+
workflow_metadata: dict[str, Any]
|
|
186
|
+
workflow_result: dict[str, Any]
|
|
187
|
+
structured_output: dict[str, Any]
|
|
188
|
+
screenshot_url: str
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Webhook verification for the Simplex SDK.
|
|
3
|
+
|
|
4
|
+
This module provides utilities to verify incoming Simplex webhook requests
|
|
5
|
+
using HMAC-SHA256 signature verification.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import hashlib
|
|
11
|
+
import hmac
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class WebhookVerificationError(Exception):
|
|
15
|
+
"""Raised when webhook signature verification fails."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def verify_simplex_webhook(
|
|
19
|
+
body: str,
|
|
20
|
+
headers: dict[str, str],
|
|
21
|
+
webhook_secret: str,
|
|
22
|
+
) -> None:
|
|
23
|
+
"""
|
|
24
|
+
Verify a Simplex webhook request using HMAC-SHA256 signature verification.
|
|
25
|
+
|
|
26
|
+
This function ensures that webhook requests are authentic and haven't been
|
|
27
|
+
tampered with in transit.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
body: Raw request body as a string (must be the original unparsed body)
|
|
31
|
+
headers: Request headers dict containing the X-Simplex-Signature header
|
|
32
|
+
webhook_secret: Your webhook secret from the Simplex dashboard
|
|
33
|
+
|
|
34
|
+
Raises:
|
|
35
|
+
WebhookVerificationError: If the signature is missing, invalid,
|
|
36
|
+
or verification fails
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
>>> # Flask example
|
|
40
|
+
>>> from flask import Flask, request
|
|
41
|
+
>>> from simplex import verify_simplex_webhook, WebhookPayload
|
|
42
|
+
>>>
|
|
43
|
+
>>> @app.route("/webhook", methods=["POST"])
|
|
44
|
+
>>> def webhook():
|
|
45
|
+
... body = request.get_data(as_text=True)
|
|
46
|
+
... verify_simplex_webhook(body, dict(request.headers), WEBHOOK_SECRET)
|
|
47
|
+
... payload: WebhookPayload = request.get_json()
|
|
48
|
+
... print(f"Session: {payload['session_id']}")
|
|
49
|
+
... return {"success": True}
|
|
50
|
+
"""
|
|
51
|
+
# Normalize header lookup (case-insensitive)
|
|
52
|
+
signature = None
|
|
53
|
+
for key, value in headers.items():
|
|
54
|
+
if key.lower() == "x-simplex-signature":
|
|
55
|
+
signature = value
|
|
56
|
+
break
|
|
57
|
+
|
|
58
|
+
if not signature:
|
|
59
|
+
raise WebhookVerificationError("Missing X-Simplex-Signature header")
|
|
60
|
+
|
|
61
|
+
# Compute expected signature
|
|
62
|
+
expected_signature = hmac.new(
|
|
63
|
+
webhook_secret.encode("utf-8"),
|
|
64
|
+
body.encode("utf-8"),
|
|
65
|
+
hashlib.sha256,
|
|
66
|
+
).hexdigest()
|
|
67
|
+
|
|
68
|
+
# Constant-time comparison to prevent timing attacks
|
|
69
|
+
if not hmac.compare_digest(signature, expected_signature):
|
|
70
|
+
raise WebhookVerificationError("Invalid webhook signature")
|
simplex-2.0.4/simplex/types.py
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Type definitions for the Simplex SDK.
|
|
3
|
-
|
|
4
|
-
This module contains TypedDict classes used for type hinting throughout the SDK.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
from typing import Any, TypedDict
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class FileMetadata(TypedDict):
|
|
13
|
-
"""
|
|
14
|
-
Metadata for a file downloaded or created during a session.
|
|
15
|
-
|
|
16
|
-
Attributes:
|
|
17
|
-
filename: The filename
|
|
18
|
-
download_url: The URL the file was downloaded from
|
|
19
|
-
file_size: File size in bytes
|
|
20
|
-
download_timestamp: ISO timestamp when the file was downloaded/created
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
filename: str
|
|
24
|
-
download_url: str
|
|
25
|
-
file_size: int
|
|
26
|
-
download_timestamp: str
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class SessionStatusResponse(TypedDict, total=False):
|
|
30
|
-
"""
|
|
31
|
-
Response from polling session status.
|
|
32
|
-
|
|
33
|
-
Attributes:
|
|
34
|
-
in_progress: Whether the session is still running
|
|
35
|
-
success: Whether the session completed successfully (None while in progress)
|
|
36
|
-
metadata: Custom metadata provided when the session was started
|
|
37
|
-
workflow_metadata: Metadata from the workflow definition
|
|
38
|
-
file_metadata: Metadata for files downloaded during the session
|
|
39
|
-
scraper_outputs: Scraper outputs collected during the session, keyed by output name
|
|
40
|
-
paused: Whether the session is currently paused
|
|
41
|
-
paused_key: The pause key if the session is paused
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
in_progress: bool
|
|
45
|
-
success: bool | None
|
|
46
|
-
metadata: dict[str, Any]
|
|
47
|
-
workflow_metadata: dict[str, Any]
|
|
48
|
-
file_metadata: list[FileMetadata]
|
|
49
|
-
scraper_outputs: dict[str, Any]
|
|
50
|
-
paused: bool
|
|
51
|
-
paused_key: str
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class RunWorkflowResponse(TypedDict):
|
|
55
|
-
"""
|
|
56
|
-
Response from running a workflow.
|
|
57
|
-
|
|
58
|
-
Attributes:
|
|
59
|
-
succeeded: Whether the workflow started successfully
|
|
60
|
-
message: Human-readable status message
|
|
61
|
-
session_id: Unique identifier for this workflow session
|
|
62
|
-
vnc_url: URL for VNC access to the workflow session
|
|
63
|
-
logs_url: URL for viewing session logs
|
|
64
|
-
"""
|
|
65
|
-
|
|
66
|
-
succeeded: bool
|
|
67
|
-
message: str
|
|
68
|
-
session_id: str
|
|
69
|
-
vnc_url: str
|
|
70
|
-
logs_url: str
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|