simplai-sdk 0.1.0__py3-none-any.whl
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.
- billing/__init__.py +6 -0
- billing/api.py +55 -0
- billing/client.py +14 -0
- billing/schema.py +15 -0
- constants/__init__.py +90 -0
- core/__init__.py +53 -0
- core/agents/__init__.py +42 -0
- core/agents/execution/__init__.py +49 -0
- core/agents/execution/api.py +283 -0
- core/agents/execution/client.py +1139 -0
- core/agents/models.py +99 -0
- core/workflows/WORKFLOW_ARCHITECTURE.md +417 -0
- core/workflows/__init__.py +31 -0
- core/workflows/bulk/__init__.py +14 -0
- core/workflows/bulk/api.py +202 -0
- core/workflows/bulk/client.py +115 -0
- core/workflows/bulk/schema.py +58 -0
- core/workflows/models.py +49 -0
- core/workflows/scheduling/__init__.py +9 -0
- core/workflows/scheduling/api.py +179 -0
- core/workflows/scheduling/client.py +128 -0
- core/workflows/scheduling/schema.py +74 -0
- core/workflows/tool_execution/__init__.py +16 -0
- core/workflows/tool_execution/api.py +172 -0
- core/workflows/tool_execution/client.py +195 -0
- core/workflows/tool_execution/schema.py +40 -0
- exceptions/__init__.py +21 -0
- simplai_sdk/__init__.py +7 -0
- simplai_sdk/simplai.py +239 -0
- simplai_sdk-0.1.0.dist-info/METADATA +728 -0
- simplai_sdk-0.1.0.dist-info/RECORD +42 -0
- simplai_sdk-0.1.0.dist-info/WHEEL +5 -0
- simplai_sdk-0.1.0.dist-info/licenses/LICENSE +21 -0
- simplai_sdk-0.1.0.dist-info/top_level.txt +7 -0
- traces/__init__.py +1 -0
- traces/agents/__init__.py +55 -0
- traces/agents/api.py +350 -0
- traces/agents/client.py +697 -0
- traces/agents/models.py +249 -0
- traces/workflows/__init__.py +0 -0
- utils/__init__.py +0 -0
- utils/config.py +117 -0
core/agents/models.py
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AgentStatus(str, Enum):
|
|
9
|
+
"""Known agent response status values returned by the Simplai agent API.
|
|
10
|
+
|
|
11
|
+
The API returns messageStatus as an integer:
|
|
12
|
+
- 0 or None = PENDING/PROCESSING
|
|
13
|
+
- 1 = PROCESSING
|
|
14
|
+
- 2 = COMPLETED
|
|
15
|
+
- Other values = FAILED/ERROR
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
PENDING = "PENDING"
|
|
19
|
+
PROCESSING = "PROCESSING"
|
|
20
|
+
COMPLETED = "COMPLETED"
|
|
21
|
+
FAILED = "FAILED"
|
|
22
|
+
TIMEOUT = "TIMEOUT"
|
|
23
|
+
UNKNOWN = "UNKNOWN"
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def from_raw(cls, value: Any) -> "AgentStatus":
|
|
27
|
+
"""Convert a raw status value from the API into an AgentStatus.
|
|
28
|
+
|
|
29
|
+
Handles both integer messageStatus and string status values.
|
|
30
|
+
"""
|
|
31
|
+
# Handle integer messageStatus (0, 1, 2, etc.)
|
|
32
|
+
if isinstance(value, int):
|
|
33
|
+
if value == 0:
|
|
34
|
+
return cls.PROCESSING # 0 typically means processing
|
|
35
|
+
elif value == 1:
|
|
36
|
+
return cls.PROCESSING
|
|
37
|
+
elif value == 2:
|
|
38
|
+
return cls.COMPLETED
|
|
39
|
+
else:
|
|
40
|
+
return cls.FAILED
|
|
41
|
+
|
|
42
|
+
# Handle None/empty
|
|
43
|
+
if value is None:
|
|
44
|
+
return cls.PROCESSING
|
|
45
|
+
|
|
46
|
+
# Handle string values
|
|
47
|
+
if isinstance(value, str):
|
|
48
|
+
upper = value.upper()
|
|
49
|
+
for member in cls:
|
|
50
|
+
if member.value == upper:
|
|
51
|
+
return member
|
|
52
|
+
|
|
53
|
+
return cls.UNKNOWN
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class AgentMessage:
|
|
58
|
+
"""Represents a message in agent conversation."""
|
|
59
|
+
|
|
60
|
+
role: str # "user" or "assistant"
|
|
61
|
+
content: str
|
|
62
|
+
message_id: Optional[str] = None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class AgentResult:
|
|
67
|
+
"""Final result of an agent conversation."""
|
|
68
|
+
|
|
69
|
+
conversation_id: str
|
|
70
|
+
message_id: str
|
|
71
|
+
status: AgentStatus
|
|
72
|
+
response: str
|
|
73
|
+
payload: Dict[str, Any] # Full response from API
|
|
74
|
+
trace_id: Optional[str] = None # Trace ID for tracing (from response)
|
|
75
|
+
node_id: Optional[str] = None # Node ID for tracing (from response)
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def succeeded(self) -> bool:
|
|
79
|
+
"""True if the agent conversation completed successfully."""
|
|
80
|
+
return self.status == AgentStatus.COMPLETED
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass
|
|
84
|
+
class AgentStreamChunk:
|
|
85
|
+
"""Represents a chunk in streaming agent response."""
|
|
86
|
+
|
|
87
|
+
content: str
|
|
88
|
+
conversation_id: Optional[str] = None
|
|
89
|
+
message_id: Optional[str] = None
|
|
90
|
+
is_complete: bool = False
|
|
91
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
92
|
+
trace_id: Optional[str] = None # Trace ID from first chunk (for request-level traces)
|
|
93
|
+
node_id: Optional[str] = None # Node ID from first chunk (for tree-based traces)
|
|
94
|
+
tree_id: Optional[str] = None # Tree ID from first chunk (for tree-based traces)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class AgentExecutionError(Exception):
|
|
98
|
+
"""Raised when an agent conversation fails, times out, or cannot be executed."""
|
|
99
|
+
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# Workflow Execution Architecture
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
The workflow execution system is organized in layers, from high-level API functions down to low-level HTTP client methods. Both synchronous and asynchronous execution paths are supported.
|
|
5
|
+
|
|
6
|
+
## Architecture Layers
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
10
|
+
│ API Layer (api.py) │
|
|
11
|
+
│ - execute_workflow() (sync high-level) │
|
|
12
|
+
│ - aexecute_workflow() (async high-level) │
|
|
13
|
+
│ - get_execution_status() (sync status check) │
|
|
14
|
+
│ - aget_execution_status() (async status check) │
|
|
15
|
+
└────────────────────┬────────────────────────────────────────┘
|
|
16
|
+
│
|
|
17
|
+
▼
|
|
18
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
19
|
+
│ Client Layer (client.py) │
|
|
20
|
+
│ - SimplaiClient class │
|
|
21
|
+
│ ├─ execute_once() / aexecute_once() │
|
|
22
|
+
│ ├─ get_status_once() / aget_status_once() │
|
|
23
|
+
│ └─ execute_and_wait() / aexecute_and_wait() │
|
|
24
|
+
└────────────────────┬────────────────────────────────────────┘
|
|
25
|
+
│
|
|
26
|
+
▼
|
|
27
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
28
|
+
│ HTTP Layer (httpx) │
|
|
29
|
+
│ - _request_with_retries_sync() │
|
|
30
|
+
│ - _request_with_retries_async() │
|
|
31
|
+
└──────────────────────────────────────────────────────────────┘
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Module Responsibilities
|
|
35
|
+
|
|
36
|
+
### 1. **constants.py** - Configuration
|
|
37
|
+
- `DEFAULT_BASE_URL`: Base API endpoint
|
|
38
|
+
- `EXECUTE_PATH`: Endpoint for workflow execution
|
|
39
|
+
- `STATUS_PATH_TEMPLATE`: Endpoint template for status checks
|
|
40
|
+
|
|
41
|
+
### 2. **models.py** - Data Models
|
|
42
|
+
- `ExecutionStatus`: Enum for workflow states (PENDING, RUNNING, SUCCEEDED, etc.)
|
|
43
|
+
- `WorkflowResult`: Result container with execution_id, status, and payload
|
|
44
|
+
- `WorkflowExecutionError`: Exception for workflow failures
|
|
45
|
+
|
|
46
|
+
### 3. **client.py** - HTTP Client & Polling Logic
|
|
47
|
+
- `SimplaiClient`: Reusable HTTP client with retry logic
|
|
48
|
+
- Handles both sync and async HTTP requests
|
|
49
|
+
- Implements polling mechanism for waiting on workflow completion
|
|
50
|
+
|
|
51
|
+
### 4. **api.py** - High-Level API
|
|
52
|
+
- Convenience functions that wrap `SimplaiClient`
|
|
53
|
+
- Supports "sync" and "async" modes
|
|
54
|
+
- Provides simple interface for users
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Synchronous Workflow Execution Flow
|
|
59
|
+
|
|
60
|
+
### Mode: "sync" (Polling until completion)
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
User calls:
|
|
64
|
+
execute_workflow(workflow_id, inputs, mode="sync")
|
|
65
|
+
│
|
|
66
|
+
├─► Creates SimplaiClient instance
|
|
67
|
+
│
|
|
68
|
+
├─► Calls client.execute_and_wait()
|
|
69
|
+
│ │
|
|
70
|
+
│ ├─► Step 1: Execute workflow
|
|
71
|
+
│ │ └─► client.execute_once()
|
|
72
|
+
│ │ └─► POST /interact/api/v2/tool/execute
|
|
73
|
+
│ │ └─► Returns execution_id
|
|
74
|
+
│ │
|
|
75
|
+
│ └─► Step 2: Poll until completion
|
|
76
|
+
│ │
|
|
77
|
+
│ ├─► Loop:
|
|
78
|
+
│ │ ├─► client.get_status_once(execution_id)
|
|
79
|
+
│ │ │ └─► GET /interact/api/v2/tool/executions/{id}/status
|
|
80
|
+
│ │ │
|
|
81
|
+
│ │ ├─► Check if terminal status:
|
|
82
|
+
│ │ │ - SUCCEEDED → Return WorkflowResult
|
|
83
|
+
│ │ │ - FAILED/CANCELED/TIMEOUT → Raise WorkflowExecutionError
|
|
84
|
+
│ │ │ - PENDING/RUNNING → Continue polling
|
|
85
|
+
│ │ │
|
|
86
|
+
│ │ └─► time.sleep(poll_interval) # Wait before next poll
|
|
87
|
+
│ │
|
|
88
|
+
│ └─► Return WorkflowResult or raise exception
|
|
89
|
+
│
|
|
90
|
+
└─► Returns WorkflowResult to user
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Mode: "async" (Fire and forget)
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
User calls:
|
|
97
|
+
execute_workflow(workflow_id, inputs, mode="async")
|
|
98
|
+
│
|
|
99
|
+
├─► Creates SimplaiClient instance
|
|
100
|
+
│
|
|
101
|
+
└─► Calls client.execute_once()
|
|
102
|
+
└─► POST /interact/api/v2/tool/execute
|
|
103
|
+
└─► Returns execution_id (string)
|
|
104
|
+
|
|
105
|
+
Returns: execution_id (user must poll manually)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Asynchronous Workflow Execution Flow
|
|
111
|
+
|
|
112
|
+
### Mode: "sync" (Polling until completion)
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
User calls:
|
|
116
|
+
await aexecute_workflow(workflow_id, inputs, mode="sync")
|
|
117
|
+
│
|
|
118
|
+
├─► Creates SimplaiClient instance
|
|
119
|
+
│
|
|
120
|
+
├─► Calls await client.aexecute_and_wait()
|
|
121
|
+
│ │
|
|
122
|
+
│ ├─► Step 1: Execute workflow
|
|
123
|
+
│ │ └─► await client.aexecute_once()
|
|
124
|
+
│ │ └─► POST /interact/api/v2/tool/execute (async)
|
|
125
|
+
│ │ └─► Returns execution_id
|
|
126
|
+
│ │
|
|
127
|
+
│ └─► Step 2: Poll until completion
|
|
128
|
+
│ │
|
|
129
|
+
│ ├─► Loop:
|
|
130
|
+
│ │ ├─► await client.aget_status_once(execution_id)
|
|
131
|
+
│ │ │ └─► GET /interact/api/v2/tool/executions/{id}/status (async)
|
|
132
|
+
│ │ │
|
|
133
|
+
│ │ ├─► Check if terminal status:
|
|
134
|
+
│ │ │ - SUCCEEDED → Return WorkflowResult
|
|
135
|
+
│ │ │ - FAILED/CANCELED/TIMEOUT → Raise WorkflowExecutionError
|
|
136
|
+
│ │ │ - PENDING/RUNNING → Continue polling
|
|
137
|
+
│ │ │
|
|
138
|
+
│ │ └─► await asyncio.sleep(poll_interval) # Non-blocking wait
|
|
139
|
+
│ │
|
|
140
|
+
│ └─► Return WorkflowResult or raise exception
|
|
141
|
+
│
|
|
142
|
+
└─► Returns WorkflowResult to user
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Mode: "async" (Fire and forget)
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
User calls:
|
|
149
|
+
await aexecute_workflow(workflow_id, inputs, mode="async")
|
|
150
|
+
│
|
|
151
|
+
├─► Creates SimplaiClient instance
|
|
152
|
+
│
|
|
153
|
+
└─► Calls await client.aexecute_once()
|
|
154
|
+
└─► POST /interact/api/v2/tool/execute (async)
|
|
155
|
+
└─► Returns execution_id (string)
|
|
156
|
+
|
|
157
|
+
Returns: execution_id (user must poll manually)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Function Reference
|
|
163
|
+
|
|
164
|
+
### High-Level API Functions (api.py)
|
|
165
|
+
|
|
166
|
+
#### `execute_workflow()` - Synchronous
|
|
167
|
+
```python
|
|
168
|
+
def execute_workflow(
|
|
169
|
+
workflow_id: str,
|
|
170
|
+
inputs: Dict[str, Any],
|
|
171
|
+
*,
|
|
172
|
+
api_key: str,
|
|
173
|
+
mode: str = "sync", # "sync" or "async"
|
|
174
|
+
timeout: Optional[float] = None,
|
|
175
|
+
poll_interval: float = 2.0,
|
|
176
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
177
|
+
) -> WorkflowResult | str:
|
|
178
|
+
```
|
|
179
|
+
- **mode="sync"**: Polls until completion, returns `WorkflowResult`
|
|
180
|
+
- **mode="async"**: Returns immediately with `execution_id` (string)
|
|
181
|
+
|
|
182
|
+
#### `aexecute_workflow()` - Asynchronous
|
|
183
|
+
```python
|
|
184
|
+
async def aexecute_workflow(...) -> WorkflowResult | str:
|
|
185
|
+
```
|
|
186
|
+
- Same as `execute_workflow()` but async/await compatible
|
|
187
|
+
- Uses `await` for non-blocking operations
|
|
188
|
+
|
|
189
|
+
#### `get_execution_status()` - Synchronous Status Check
|
|
190
|
+
```python
|
|
191
|
+
def get_execution_status(
|
|
192
|
+
execution_id: str,
|
|
193
|
+
*,
|
|
194
|
+
api_key: str,
|
|
195
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
196
|
+
) -> Dict[str, Any]:
|
|
197
|
+
```
|
|
198
|
+
- One-off status check (doesn't poll)
|
|
199
|
+
- Returns raw status dictionary
|
|
200
|
+
|
|
201
|
+
#### `aget_execution_status()` - Asynchronous Status Check
|
|
202
|
+
```python
|
|
203
|
+
async def aget_execution_status(...) -> Dict[str, Any]:
|
|
204
|
+
```
|
|
205
|
+
- Async version of `get_execution_status()`
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### Client Methods (client.py)
|
|
210
|
+
|
|
211
|
+
#### `SimplaiClient.execute_once()` - Sync Execute
|
|
212
|
+
```python
|
|
213
|
+
def execute_once(
|
|
214
|
+
self,
|
|
215
|
+
workflow_id: str,
|
|
216
|
+
inputs: Dict[str, Any],
|
|
217
|
+
) -> str:
|
|
218
|
+
```
|
|
219
|
+
- Sends POST request to execute workflow
|
|
220
|
+
- Returns `execution_id`
|
|
221
|
+
- Uses `_request_with_retries_sync()` with retry logic
|
|
222
|
+
|
|
223
|
+
#### `SimplaiClient.aexecute_once()` - Async Execute
|
|
224
|
+
```python
|
|
225
|
+
async def aexecute_once(...) -> str:
|
|
226
|
+
```
|
|
227
|
+
- Async version of `execute_once()`
|
|
228
|
+
- Uses `_request_with_retries_async()`
|
|
229
|
+
|
|
230
|
+
#### `SimplaiClient.get_status_once()` - Sync Status Check
|
|
231
|
+
```python
|
|
232
|
+
def get_status_once(self, execution_id: str) -> Dict[str, Any]:
|
|
233
|
+
```
|
|
234
|
+
- Sends GET request to check status
|
|
235
|
+
- Returns raw status dictionary
|
|
236
|
+
- Uses `_request_with_retries_sync()`
|
|
237
|
+
|
|
238
|
+
#### `SimplaiClient.aget_status_once()` - Async Status Check
|
|
239
|
+
```python
|
|
240
|
+
async def aget_status_once(...) -> Dict[str, Any]:
|
|
241
|
+
```
|
|
242
|
+
- Async version of `get_status_once()`
|
|
243
|
+
- Uses `_request_with_retries_async()`
|
|
244
|
+
|
|
245
|
+
#### `SimplaiClient.execute_and_wait()` - Sync Polling
|
|
246
|
+
```python
|
|
247
|
+
def execute_and_wait(
|
|
248
|
+
self,
|
|
249
|
+
workflow_id: str,
|
|
250
|
+
inputs: Dict[str, Any],
|
|
251
|
+
*,
|
|
252
|
+
poll_interval: float = 2.0,
|
|
253
|
+
timeout: Optional[float] = None,
|
|
254
|
+
) -> WorkflowResult:
|
|
255
|
+
```
|
|
256
|
+
**Flow:**
|
|
257
|
+
1. Calls `execute_once()` to start workflow
|
|
258
|
+
2. Enters polling loop:
|
|
259
|
+
- Calls `get_status_once()` to check status
|
|
260
|
+
- Checks if status is terminal (SUCCEEDED, FAILED, CANCELED, TIMEOUT)
|
|
261
|
+
- If terminal and SUCCEEDED → return `WorkflowResult`
|
|
262
|
+
- If terminal and not SUCCEEDED → raise `WorkflowExecutionError`
|
|
263
|
+
- If not terminal → `time.sleep(poll_interval)` and loop again
|
|
264
|
+
3. Respects `timeout` parameter (raises error if exceeded)
|
|
265
|
+
|
|
266
|
+
#### `SimplaiClient.aexecute_and_wait()` - Async Polling
|
|
267
|
+
```python
|
|
268
|
+
async def aexecute_and_wait(...) -> WorkflowResult:
|
|
269
|
+
```
|
|
270
|
+
- Async version of `execute_and_wait()`
|
|
271
|
+
- Uses `await asyncio.sleep()` instead of `time.sleep()`
|
|
272
|
+
- Non-blocking, allows other coroutines to run
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Polling Mechanism Details
|
|
277
|
+
|
|
278
|
+
### Terminal States
|
|
279
|
+
The polling loop stops when it encounters one of these states:
|
|
280
|
+
- `SUCCEEDED`: Workflow completed successfully → Returns `WorkflowResult`
|
|
281
|
+
- `FAILED`: Workflow failed → Raises `WorkflowExecutionError`
|
|
282
|
+
- `CANCELED`: Workflow was canceled → Raises `WorkflowExecutionError`
|
|
283
|
+
- `TIMEOUT`: Workflow timed out → Raises `WorkflowExecutionError`
|
|
284
|
+
|
|
285
|
+
### Non-Terminal States
|
|
286
|
+
- `PENDING`: Workflow queued but not started
|
|
287
|
+
- `RUNNING`: Workflow currently executing
|
|
288
|
+
- `UNKNOWN`: Status couldn't be parsed
|
|
289
|
+
|
|
290
|
+
### Polling Behavior
|
|
291
|
+
- **Default interval**: 2.0 seconds between polls
|
|
292
|
+
- **Timeout**: Optional maximum wait time
|
|
293
|
+
- **Sync**: Uses `time.sleep()` (blocks thread)
|
|
294
|
+
- **Async**: Uses `asyncio.sleep()` (non-blocking, allows concurrency)
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Error Handling
|
|
299
|
+
|
|
300
|
+
### Retry Logic
|
|
301
|
+
Both sync and async request methods implement retry with exponential backoff:
|
|
302
|
+
- **Max retries**: 3 (configurable)
|
|
303
|
+
- **Backoff**: `backoff_factor * (2^attempt)` seconds
|
|
304
|
+
- **Retries on**: 5xx server errors, transport errors
|
|
305
|
+
- **No retry on**: 4xx client errors (immediate error)
|
|
306
|
+
|
|
307
|
+
### Error Types
|
|
308
|
+
- `WorkflowExecutionError`: Raised for:
|
|
309
|
+
- Workflow failures (FAILED, CANCELED, TIMEOUT status)
|
|
310
|
+
- HTTP client errors (4xx)
|
|
311
|
+
- Timeout exceeded
|
|
312
|
+
- Invalid JSON responses
|
|
313
|
+
- Missing execution_id in response
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Usage Examples
|
|
318
|
+
|
|
319
|
+
### Synchronous Execution (Blocking)
|
|
320
|
+
```python
|
|
321
|
+
from simplai_sdk import execute_workflow
|
|
322
|
+
|
|
323
|
+
# Poll until completion
|
|
324
|
+
result = execute_workflow(
|
|
325
|
+
workflow_id="my-workflow",
|
|
326
|
+
inputs={"key": "value"},
|
|
327
|
+
api_key="my-api-key",
|
|
328
|
+
mode="sync",
|
|
329
|
+
timeout=60.0,
|
|
330
|
+
poll_interval=2.0
|
|
331
|
+
)
|
|
332
|
+
print(result.payload) # Access result data
|
|
333
|
+
|
|
334
|
+
# Fire and forget (get execution_id)
|
|
335
|
+
execution_id = execute_workflow(
|
|
336
|
+
workflow_id="my-workflow",
|
|
337
|
+
inputs={"key": "value"},
|
|
338
|
+
api_key="my-api-key",
|
|
339
|
+
mode="async"
|
|
340
|
+
)
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Asynchronous Execution (Non-blocking)
|
|
344
|
+
```python
|
|
345
|
+
from simplai_sdk import aexecute_workflow
|
|
346
|
+
import asyncio
|
|
347
|
+
|
|
348
|
+
async def main():
|
|
349
|
+
# Poll until completion (non-blocking)
|
|
350
|
+
result = await aexecute_workflow(
|
|
351
|
+
workflow_id="my-workflow",
|
|
352
|
+
inputs={"key": "value"},
|
|
353
|
+
api_key="my-api-key",
|
|
354
|
+
mode="sync",
|
|
355
|
+
timeout=60.0,
|
|
356
|
+
poll_interval=2.0
|
|
357
|
+
)
|
|
358
|
+
print(result.payload)
|
|
359
|
+
|
|
360
|
+
# Fire and forget
|
|
361
|
+
execution_id = await aexecute_workflow(
|
|
362
|
+
workflow_id="my-workflow",
|
|
363
|
+
inputs={"key": "value"},
|
|
364
|
+
api_key="my-api-key",
|
|
365
|
+
mode="async"
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
asyncio.run(main())
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Manual Status Checking
|
|
372
|
+
```python
|
|
373
|
+
from simplai_sdk import get_execution_status, aget_execution_status
|
|
374
|
+
|
|
375
|
+
# Sync
|
|
376
|
+
status = get_execution_status(
|
|
377
|
+
execution_id="exec-123",
|
|
378
|
+
api_key="my-api-key"
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
# Async
|
|
382
|
+
status = await aget_execution_status(
|
|
383
|
+
execution_id="exec-123",
|
|
384
|
+
api_key="my-api-key"
|
|
385
|
+
)
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## Key Differences: Sync vs Async
|
|
391
|
+
|
|
392
|
+
| Aspect | Synchronous | Asynchronous |
|
|
393
|
+
|--------|------------|--------------|
|
|
394
|
+
| **Blocking** | Blocks thread during I/O | Non-blocking, allows concurrency |
|
|
395
|
+
| **Sleep** | `time.sleep()` | `asyncio.sleep()` |
|
|
396
|
+
| **HTTP Client** | `httpx.Client` | `httpx.AsyncClient` |
|
|
397
|
+
| **Request Method** | `client.request()` | `await client.request()` |
|
|
398
|
+
| **Use Case** | Simple scripts, blocking operations | Concurrent operations, web servers |
|
|
399
|
+
| **Performance** | One workflow at a time | Can handle multiple workflows concurrently |
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Summary
|
|
404
|
+
|
|
405
|
+
The workflow execution system provides:
|
|
406
|
+
1. **High-level API** (`api.py`) - Simple functions for users
|
|
407
|
+
2. **Client layer** (`client.py`) - Reusable client with polling logic
|
|
408
|
+
3. **Models** (`models.py`) - Type-safe data structures
|
|
409
|
+
4. **Constants** (`constants.py`) - Configuration values
|
|
410
|
+
|
|
411
|
+
Both sync and async paths follow the same logical flow:
|
|
412
|
+
1. Execute workflow → Get `execution_id`
|
|
413
|
+
2. Poll status → Check for terminal state
|
|
414
|
+
3. Return result or raise error
|
|
415
|
+
|
|
416
|
+
The async path uses `await` and `asyncio.sleep()` to allow concurrent execution of multiple workflows, while the sync path blocks until completion.
|
|
417
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Backwards-compatibility shim for earlier imports.
|
|
2
|
+
|
|
3
|
+
The implementation has been split into smaller modules for readability:
|
|
4
|
+
- tool_execution: workflow execution APIs
|
|
5
|
+
- bulk: bulk run APIs
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .tool_execution import (
|
|
9
|
+
execute_workflow,
|
|
10
|
+
get_tool_result,
|
|
11
|
+
execute_and_wait_workflow,
|
|
12
|
+
cancel_execution,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from .bulk import (
|
|
16
|
+
trigger_bulk_run,
|
|
17
|
+
get_bulk_run_status,
|
|
18
|
+
cancel_bulk_run,
|
|
19
|
+
download_bulk_run_result,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"execute_workflow",
|
|
24
|
+
"get_tool_result",
|
|
25
|
+
"execute_and_wait_workflow",
|
|
26
|
+
"cancel_execution",
|
|
27
|
+
"trigger_bulk_run",
|
|
28
|
+
"get_bulk_run_status",
|
|
29
|
+
"cancel_bulk_run",
|
|
30
|
+
"download_bulk_run_result",
|
|
31
|
+
]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Public SDK interface for bulk workflow execution."""
|
|
2
|
+
|
|
3
|
+
from .client import trigger_bulk_run
|
|
4
|
+
from .client import get_bulk_run_status
|
|
5
|
+
from .client import cancel_bulk_run
|
|
6
|
+
from .client import download_bulk_run_result
|
|
7
|
+
__all__ = [
|
|
8
|
+
"trigger_bulk_run",
|
|
9
|
+
"get_bulk_run_status",
|
|
10
|
+
"cancel_bulk_run",
|
|
11
|
+
"download_bulk_run_result",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
|