vellum-ai 1.6.4__py3-none-any.whl → 1.7.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.
- vellum/__init__.py +2 -0
- vellum/client/core/client_wrapper.py +2 -2
- vellum/client/reference.md +81 -0
- vellum/client/resources/container_images/client.py +8 -2
- vellum/client/resources/container_images/raw_client.py +8 -0
- vellum/client/resources/workflows/client.py +81 -0
- vellum/client/resources/workflows/raw_client.py +85 -0
- vellum/client/types/__init__.py +2 -0
- vellum/client/types/workflow_resolved_state.py +31 -0
- vellum/types/workflow_resolved_state.py +3 -0
- vellum/workflows/descriptors/base.py +3 -0
- vellum/workflows/errors/types.py +1 -0
- vellum/workflows/inputs/base.py +4 -1
- vellum/workflows/inputs/tests/test_inputs.py +21 -0
- vellum/workflows/runner/runner.py +16 -0
- vellum/workflows/workflows/base.py +2 -0
- {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/METADATA +1 -1
- {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/RECORD +35 -33
- vellum_ee/assets/node-definitions.json +157 -12
- vellum_ee/workflows/display/exceptions.py +2 -6
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +11 -4
- vellum_ee/workflows/display/nodes/vellum/search_node.py +4 -4
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +11 -4
- vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py +1 -1
- vellum_ee/workflows/display/utils/exceptions.py +19 -0
- vellum_ee/workflows/display/utils/expressions.py +19 -11
- vellum_ee/workflows/display/utils/vellum.py +7 -1
- vellum_ee/workflows/display/workflows/base_workflow_display.py +2 -2
- vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +54 -1
- vellum_ee/workflows/tests/test_server.py +41 -0
- {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/LICENSE +0 -0
- {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/WHEEL +0 -0
- {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/entry_points.txt +0 -0
vellum/__init__.py
CHANGED
@@ -679,6 +679,7 @@ from .client.types import (
|
|
679
679
|
WorkflowRequestNumberInputRequest,
|
680
680
|
WorkflowRequestStringInputRequest,
|
681
681
|
WorkflowRequestVideoInputRequest,
|
682
|
+
WorkflowResolvedState,
|
682
683
|
WorkflowResultEvent,
|
683
684
|
WorkflowResultEventOutputData,
|
684
685
|
WorkflowResultEventOutputDataArray,
|
@@ -1429,6 +1430,7 @@ __all__ = [
|
|
1429
1430
|
"WorkflowRequestNumberInputRequest",
|
1430
1431
|
"WorkflowRequestStringInputRequest",
|
1431
1432
|
"WorkflowRequestVideoInputRequest",
|
1433
|
+
"WorkflowResolvedState",
|
1432
1434
|
"WorkflowResultEvent",
|
1433
1435
|
"WorkflowResultEventOutputData",
|
1434
1436
|
"WorkflowResultEventOutputDataArray",
|
@@ -27,10 +27,10 @@ class BaseClientWrapper:
|
|
27
27
|
|
28
28
|
def get_headers(self) -> typing.Dict[str, str]:
|
29
29
|
headers: typing.Dict[str, str] = {
|
30
|
-
"User-Agent": "vellum-ai/1.
|
30
|
+
"User-Agent": "vellum-ai/1.7.0",
|
31
31
|
"X-Fern-Language": "Python",
|
32
32
|
"X-Fern-SDK-Name": "vellum-ai",
|
33
|
-
"X-Fern-SDK-Version": "1.
|
33
|
+
"X-Fern-SDK-Version": "1.7.0",
|
34
34
|
**(self.get_custom_headers() or {}),
|
35
35
|
}
|
36
36
|
if self._api_version is not None:
|
vellum/client/reference.md
CHANGED
@@ -2279,6 +2279,14 @@ client.container_images.push_container_image(
|
|
2279
2279
|
<dl>
|
2280
2280
|
<dd>
|
2281
2281
|
|
2282
|
+
**force:** `typing.Optional[bool]`
|
2283
|
+
|
2284
|
+
</dd>
|
2285
|
+
</dl>
|
2286
|
+
|
2287
|
+
<dl>
|
2288
|
+
<dd>
|
2289
|
+
|
2282
2290
|
**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
|
2283
2291
|
|
2284
2292
|
</dd>
|
@@ -7088,6 +7096,79 @@ client.workflow_sandboxes.list_workflow_sandbox_examples()
|
|
7088
7096
|
</details>
|
7089
7097
|
|
7090
7098
|
## Workflows
|
7099
|
+
<details><summary><code>client.workflows.<a href="src/vellum/resources/workflows/client.py">retrieve_state</a>(...)</code></summary>
|
7100
|
+
<dl>
|
7101
|
+
<dd>
|
7102
|
+
|
7103
|
+
#### 📝 Description
|
7104
|
+
|
7105
|
+
<dl>
|
7106
|
+
<dd>
|
7107
|
+
|
7108
|
+
<dl>
|
7109
|
+
<dd>
|
7110
|
+
|
7111
|
+
Retrieve the current state of a workflow execution.
|
7112
|
+
|
7113
|
+
**Note:** Uses a base url of `https://predict.vellum.ai`.
|
7114
|
+
</dd>
|
7115
|
+
</dl>
|
7116
|
+
</dd>
|
7117
|
+
</dl>
|
7118
|
+
|
7119
|
+
#### 🔌 Usage
|
7120
|
+
|
7121
|
+
<dl>
|
7122
|
+
<dd>
|
7123
|
+
|
7124
|
+
<dl>
|
7125
|
+
<dd>
|
7126
|
+
|
7127
|
+
```python
|
7128
|
+
from vellum import Vellum
|
7129
|
+
|
7130
|
+
client = Vellum(
|
7131
|
+
api_version="YOUR_API_VERSION",
|
7132
|
+
api_key="YOUR_API_KEY",
|
7133
|
+
)
|
7134
|
+
client.workflows.retrieve_state(
|
7135
|
+
span_id="span_id",
|
7136
|
+
)
|
7137
|
+
|
7138
|
+
```
|
7139
|
+
</dd>
|
7140
|
+
</dl>
|
7141
|
+
</dd>
|
7142
|
+
</dl>
|
7143
|
+
|
7144
|
+
#### ⚙️ Parameters
|
7145
|
+
|
7146
|
+
<dl>
|
7147
|
+
<dd>
|
7148
|
+
|
7149
|
+
<dl>
|
7150
|
+
<dd>
|
7151
|
+
|
7152
|
+
**span_id:** `str` — The span ID of the workflow execution to retrieve state for
|
7153
|
+
|
7154
|
+
</dd>
|
7155
|
+
</dl>
|
7156
|
+
|
7157
|
+
<dl>
|
7158
|
+
<dd>
|
7159
|
+
|
7160
|
+
**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration.
|
7161
|
+
|
7162
|
+
</dd>
|
7163
|
+
</dl>
|
7164
|
+
</dd>
|
7165
|
+
</dl>
|
7166
|
+
|
7167
|
+
|
7168
|
+
</dd>
|
7169
|
+
</dl>
|
7170
|
+
</details>
|
7171
|
+
|
7091
7172
|
<details><summary><code>client.workflows.<a href="src/vellum/resources/workflows/client.py">serialize_workflow_files</a>(...)</code></summary>
|
7092
7173
|
<dl>
|
7093
7174
|
<dd>
|
@@ -140,6 +140,7 @@ class ContainerImagesClient:
|
|
140
140
|
name: str,
|
141
141
|
sha: str,
|
142
142
|
tags: typing.Sequence[str],
|
143
|
+
force: typing.Optional[bool] = OMIT,
|
143
144
|
request_options: typing.Optional[RequestOptions] = None,
|
144
145
|
) -> ContainerImageRead:
|
145
146
|
"""
|
@@ -151,6 +152,8 @@ class ContainerImagesClient:
|
|
151
152
|
|
152
153
|
tags : typing.Sequence[str]
|
153
154
|
|
155
|
+
force : typing.Optional[bool]
|
156
|
+
|
154
157
|
request_options : typing.Optional[RequestOptions]
|
155
158
|
Request-specific configuration.
|
156
159
|
|
@@ -174,7 +177,7 @@ class ContainerImagesClient:
|
|
174
177
|
)
|
175
178
|
"""
|
176
179
|
_response = self._raw_client.push_container_image(
|
177
|
-
name=name, sha=sha, tags=tags, request_options=request_options
|
180
|
+
name=name, sha=sha, tags=tags, force=force, request_options=request_options
|
178
181
|
)
|
179
182
|
return _response.data
|
180
183
|
|
@@ -328,6 +331,7 @@ class AsyncContainerImagesClient:
|
|
328
331
|
name: str,
|
329
332
|
sha: str,
|
330
333
|
tags: typing.Sequence[str],
|
334
|
+
force: typing.Optional[bool] = OMIT,
|
331
335
|
request_options: typing.Optional[RequestOptions] = None,
|
332
336
|
) -> ContainerImageRead:
|
333
337
|
"""
|
@@ -339,6 +343,8 @@ class AsyncContainerImagesClient:
|
|
339
343
|
|
340
344
|
tags : typing.Sequence[str]
|
341
345
|
|
346
|
+
force : typing.Optional[bool]
|
347
|
+
|
342
348
|
request_options : typing.Optional[RequestOptions]
|
343
349
|
Request-specific configuration.
|
344
350
|
|
@@ -370,6 +376,6 @@ class AsyncContainerImagesClient:
|
|
370
376
|
asyncio.run(main())
|
371
377
|
"""
|
372
378
|
_response = await self._raw_client.push_container_image(
|
373
|
-
name=name, sha=sha, tags=tags, request_options=request_options
|
379
|
+
name=name, sha=sha, tags=tags, force=force, request_options=request_options
|
374
380
|
)
|
375
381
|
return _response.data
|
@@ -158,6 +158,7 @@ class RawContainerImagesClient:
|
|
158
158
|
name: str,
|
159
159
|
sha: str,
|
160
160
|
tags: typing.Sequence[str],
|
161
|
+
force: typing.Optional[bool] = OMIT,
|
161
162
|
request_options: typing.Optional[RequestOptions] = None,
|
162
163
|
) -> HttpResponse[ContainerImageRead]:
|
163
164
|
"""
|
@@ -169,6 +170,8 @@ class RawContainerImagesClient:
|
|
169
170
|
|
170
171
|
tags : typing.Sequence[str]
|
171
172
|
|
173
|
+
force : typing.Optional[bool]
|
174
|
+
|
172
175
|
request_options : typing.Optional[RequestOptions]
|
173
176
|
Request-specific configuration.
|
174
177
|
|
@@ -185,6 +188,7 @@ class RawContainerImagesClient:
|
|
185
188
|
"name": name,
|
186
189
|
"sha": sha,
|
187
190
|
"tags": tags,
|
191
|
+
"force": force,
|
188
192
|
},
|
189
193
|
headers={
|
190
194
|
"content-type": "application/json",
|
@@ -349,6 +353,7 @@ class AsyncRawContainerImagesClient:
|
|
349
353
|
name: str,
|
350
354
|
sha: str,
|
351
355
|
tags: typing.Sequence[str],
|
356
|
+
force: typing.Optional[bool] = OMIT,
|
352
357
|
request_options: typing.Optional[RequestOptions] = None,
|
353
358
|
) -> AsyncHttpResponse[ContainerImageRead]:
|
354
359
|
"""
|
@@ -360,6 +365,8 @@ class AsyncRawContainerImagesClient:
|
|
360
365
|
|
361
366
|
tags : typing.Sequence[str]
|
362
367
|
|
368
|
+
force : typing.Optional[bool]
|
369
|
+
|
363
370
|
request_options : typing.Optional[RequestOptions]
|
364
371
|
Request-specific configuration.
|
365
372
|
|
@@ -376,6 +383,7 @@ class AsyncRawContainerImagesClient:
|
|
376
383
|
"name": name,
|
377
384
|
"sha": sha,
|
378
385
|
"tags": tags,
|
386
|
+
"force": force,
|
379
387
|
},
|
380
388
|
headers={
|
381
389
|
"content-type": "application/json",
|
@@ -8,6 +8,7 @@ from ...core.request_options import RequestOptions
|
|
8
8
|
from ...types.workflow_push_deployment_config_request import WorkflowPushDeploymentConfigRequest
|
9
9
|
from ...types.workflow_push_exec_config import WorkflowPushExecConfig
|
10
10
|
from ...types.workflow_push_response import WorkflowPushResponse
|
11
|
+
from ...types.workflow_resolved_state import WorkflowResolvedState
|
11
12
|
from .raw_client import AsyncRawWorkflowsClient, RawWorkflowsClient
|
12
13
|
|
13
14
|
# this is used as the default value for optional parameters
|
@@ -89,6 +90,42 @@ class WorkflowsClient:
|
|
89
90
|
) as r:
|
90
91
|
yield from r.data
|
91
92
|
|
93
|
+
def retrieve_state(
|
94
|
+
self, span_id: str, *, request_options: typing.Optional[RequestOptions] = None
|
95
|
+
) -> WorkflowResolvedState:
|
96
|
+
"""
|
97
|
+
Retrieve the current state of a workflow execution.
|
98
|
+
|
99
|
+
**Note:** Uses a base url of `https://predict.vellum.ai`.
|
100
|
+
|
101
|
+
Parameters
|
102
|
+
----------
|
103
|
+
span_id : str
|
104
|
+
The span ID of the workflow execution to retrieve state for
|
105
|
+
|
106
|
+
request_options : typing.Optional[RequestOptions]
|
107
|
+
Request-specific configuration.
|
108
|
+
|
109
|
+
Returns
|
110
|
+
-------
|
111
|
+
WorkflowResolvedState
|
112
|
+
|
113
|
+
|
114
|
+
Examples
|
115
|
+
--------
|
116
|
+
from vellum import Vellum
|
117
|
+
|
118
|
+
client = Vellum(
|
119
|
+
api_version="YOUR_API_VERSION",
|
120
|
+
api_key="YOUR_API_KEY",
|
121
|
+
)
|
122
|
+
client.workflows.retrieve_state(
|
123
|
+
span_id="span_id",
|
124
|
+
)
|
125
|
+
"""
|
126
|
+
_response = self._raw_client.retrieve_state(span_id, request_options=request_options)
|
127
|
+
return _response.data
|
128
|
+
|
92
129
|
def push(
|
93
130
|
self,
|
94
131
|
*,
|
@@ -245,6 +282,50 @@ class AsyncWorkflowsClient:
|
|
245
282
|
async for _chunk in r.data:
|
246
283
|
yield _chunk
|
247
284
|
|
285
|
+
async def retrieve_state(
|
286
|
+
self, span_id: str, *, request_options: typing.Optional[RequestOptions] = None
|
287
|
+
) -> WorkflowResolvedState:
|
288
|
+
"""
|
289
|
+
Retrieve the current state of a workflow execution.
|
290
|
+
|
291
|
+
**Note:** Uses a base url of `https://predict.vellum.ai`.
|
292
|
+
|
293
|
+
Parameters
|
294
|
+
----------
|
295
|
+
span_id : str
|
296
|
+
The span ID of the workflow execution to retrieve state for
|
297
|
+
|
298
|
+
request_options : typing.Optional[RequestOptions]
|
299
|
+
Request-specific configuration.
|
300
|
+
|
301
|
+
Returns
|
302
|
+
-------
|
303
|
+
WorkflowResolvedState
|
304
|
+
|
305
|
+
|
306
|
+
Examples
|
307
|
+
--------
|
308
|
+
import asyncio
|
309
|
+
|
310
|
+
from vellum import AsyncVellum
|
311
|
+
|
312
|
+
client = AsyncVellum(
|
313
|
+
api_version="YOUR_API_VERSION",
|
314
|
+
api_key="YOUR_API_KEY",
|
315
|
+
)
|
316
|
+
|
317
|
+
|
318
|
+
async def main() -> None:
|
319
|
+
await client.workflows.retrieve_state(
|
320
|
+
span_id="span_id",
|
321
|
+
)
|
322
|
+
|
323
|
+
|
324
|
+
asyncio.run(main())
|
325
|
+
"""
|
326
|
+
_response = await self._raw_client.retrieve_state(span_id, request_options=request_options)
|
327
|
+
return _response.data
|
328
|
+
|
248
329
|
async def push(
|
249
330
|
self,
|
250
331
|
*,
|
@@ -15,6 +15,7 @@ from ...errors.bad_request_error import BadRequestError
|
|
15
15
|
from ...types.workflow_push_deployment_config_request import WorkflowPushDeploymentConfigRequest
|
16
16
|
from ...types.workflow_push_exec_config import WorkflowPushExecConfig
|
17
17
|
from ...types.workflow_push_response import WorkflowPushResponse
|
18
|
+
from ...types.workflow_resolved_state import WorkflowResolvedState
|
18
19
|
|
19
20
|
# this is used as the default value for optional parameters
|
20
21
|
OMIT = typing.cast(typing.Any, ...)
|
@@ -112,6 +113,48 @@ class RawWorkflowsClient:
|
|
112
113
|
|
113
114
|
yield _stream()
|
114
115
|
|
116
|
+
def retrieve_state(
|
117
|
+
self, span_id: str, *, request_options: typing.Optional[RequestOptions] = None
|
118
|
+
) -> HttpResponse[WorkflowResolvedState]:
|
119
|
+
"""
|
120
|
+
Retrieve the current state of a workflow execution.
|
121
|
+
|
122
|
+
**Note:** Uses a base url of `https://predict.vellum.ai`.
|
123
|
+
|
124
|
+
Parameters
|
125
|
+
----------
|
126
|
+
span_id : str
|
127
|
+
The span ID of the workflow execution to retrieve state for
|
128
|
+
|
129
|
+
request_options : typing.Optional[RequestOptions]
|
130
|
+
Request-specific configuration.
|
131
|
+
|
132
|
+
Returns
|
133
|
+
-------
|
134
|
+
HttpResponse[WorkflowResolvedState]
|
135
|
+
|
136
|
+
"""
|
137
|
+
_response = self._client_wrapper.httpx_client.request(
|
138
|
+
f"v1/workflows/{jsonable_encoder(span_id)}/state",
|
139
|
+
base_url=self._client_wrapper.get_environment().predict,
|
140
|
+
method="GET",
|
141
|
+
request_options=request_options,
|
142
|
+
)
|
143
|
+
try:
|
144
|
+
if 200 <= _response.status_code < 300:
|
145
|
+
_data = typing.cast(
|
146
|
+
WorkflowResolvedState,
|
147
|
+
parse_obj_as(
|
148
|
+
type_=WorkflowResolvedState, # type: ignore
|
149
|
+
object_=_response.json(),
|
150
|
+
),
|
151
|
+
)
|
152
|
+
return HttpResponse(response=_response, data=_data)
|
153
|
+
_response_json = _response.json()
|
154
|
+
except JSONDecodeError:
|
155
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
156
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
157
|
+
|
115
158
|
def push(
|
116
159
|
self,
|
117
160
|
*,
|
@@ -324,6 +367,48 @@ class AsyncRawWorkflowsClient:
|
|
324
367
|
|
325
368
|
yield await _stream()
|
326
369
|
|
370
|
+
async def retrieve_state(
|
371
|
+
self, span_id: str, *, request_options: typing.Optional[RequestOptions] = None
|
372
|
+
) -> AsyncHttpResponse[WorkflowResolvedState]:
|
373
|
+
"""
|
374
|
+
Retrieve the current state of a workflow execution.
|
375
|
+
|
376
|
+
**Note:** Uses a base url of `https://predict.vellum.ai`.
|
377
|
+
|
378
|
+
Parameters
|
379
|
+
----------
|
380
|
+
span_id : str
|
381
|
+
The span ID of the workflow execution to retrieve state for
|
382
|
+
|
383
|
+
request_options : typing.Optional[RequestOptions]
|
384
|
+
Request-specific configuration.
|
385
|
+
|
386
|
+
Returns
|
387
|
+
-------
|
388
|
+
AsyncHttpResponse[WorkflowResolvedState]
|
389
|
+
|
390
|
+
"""
|
391
|
+
_response = await self._client_wrapper.httpx_client.request(
|
392
|
+
f"v1/workflows/{jsonable_encoder(span_id)}/state",
|
393
|
+
base_url=self._client_wrapper.get_environment().predict,
|
394
|
+
method="GET",
|
395
|
+
request_options=request_options,
|
396
|
+
)
|
397
|
+
try:
|
398
|
+
if 200 <= _response.status_code < 300:
|
399
|
+
_data = typing.cast(
|
400
|
+
WorkflowResolvedState,
|
401
|
+
parse_obj_as(
|
402
|
+
type_=WorkflowResolvedState, # type: ignore
|
403
|
+
object_=_response.json(),
|
404
|
+
),
|
405
|
+
)
|
406
|
+
return AsyncHttpResponse(response=_response, data=_data)
|
407
|
+
_response_json = _response.json()
|
408
|
+
except JSONDecodeError:
|
409
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
410
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
411
|
+
|
327
412
|
async def push(
|
328
413
|
self,
|
329
414
|
*,
|
vellum/client/types/__init__.py
CHANGED
@@ -703,6 +703,7 @@ from .workflow_request_json_input_request import WorkflowRequestJsonInputRequest
|
|
703
703
|
from .workflow_request_number_input_request import WorkflowRequestNumberInputRequest
|
704
704
|
from .workflow_request_string_input_request import WorkflowRequestStringInputRequest
|
705
705
|
from .workflow_request_video_input_request import WorkflowRequestVideoInputRequest
|
706
|
+
from .workflow_resolved_state import WorkflowResolvedState
|
706
707
|
from .workflow_result_event import WorkflowResultEvent
|
707
708
|
from .workflow_result_event_output_data import WorkflowResultEventOutputData
|
708
709
|
from .workflow_result_event_output_data_array import WorkflowResultEventOutputDataArray
|
@@ -1393,6 +1394,7 @@ __all__ = [
|
|
1393
1394
|
"WorkflowRequestNumberInputRequest",
|
1394
1395
|
"WorkflowRequestStringInputRequest",
|
1395
1396
|
"WorkflowRequestVideoInputRequest",
|
1397
|
+
"WorkflowResolvedState",
|
1396
1398
|
"WorkflowResultEvent",
|
1397
1399
|
"WorkflowResultEventOutputData",
|
1398
1400
|
"WorkflowResultEventOutputDataArray",
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
import datetime as dt
|
4
|
+
import typing
|
5
|
+
|
6
|
+
import pydantic
|
7
|
+
from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
|
8
|
+
|
9
|
+
|
10
|
+
class WorkflowResolvedState(UniversalBaseModel):
|
11
|
+
"""
|
12
|
+
The latest execution state of a given Workflow Execution
|
13
|
+
"""
|
14
|
+
|
15
|
+
trace_id: str
|
16
|
+
timestamp: dt.datetime
|
17
|
+
span_id: str
|
18
|
+
state: typing.Dict[str, typing.Optional[typing.Any]]
|
19
|
+
previous_span_id: typing.Optional[str] = None
|
20
|
+
previous_trace_id: typing.Optional[str] = None
|
21
|
+
root_span_id: typing.Optional[str] = None
|
22
|
+
root_trace_id: typing.Optional[str] = None
|
23
|
+
|
24
|
+
if IS_PYDANTIC_V2:
|
25
|
+
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
26
|
+
else:
|
27
|
+
|
28
|
+
class Config:
|
29
|
+
frozen = True
|
30
|
+
smart_union = True
|
31
|
+
extra = pydantic.Extra.allow
|
@@ -135,6 +135,9 @@ class BaseDescriptor(Generic[_T]):
|
|
135
135
|
|
136
136
|
return AccessorExpression(base=self, field=field)
|
137
137
|
|
138
|
+
def __iter__(self) -> None:
|
139
|
+
raise TypeError(f"'{type(self).__name__}' object is not iterable")
|
140
|
+
|
138
141
|
@overload
|
139
142
|
def equals(self, other: "BaseDescriptor[_O]") -> "EqualsExpression[_T, _O]": ...
|
140
143
|
|
vellum/workflows/errors/types.py
CHANGED
vellum/workflows/inputs/base.py
CHANGED
@@ -41,7 +41,10 @@ class _BaseInputsMeta(type):
|
|
41
41
|
else:
|
42
42
|
return WorkflowInputReference(name=name, types=types, instance=instance, inputs_class=cls)
|
43
43
|
|
44
|
-
|
44
|
+
if getattr(cls, "__descriptor_class__", None) is ExternalInputReference:
|
45
|
+
return ExternalInputReference(name=name, types=(), instance=undefined, inputs_class=cls)
|
46
|
+
else:
|
47
|
+
return WorkflowInputReference(name=name, types=(), instance=undefined, inputs_class=cls)
|
45
48
|
|
46
49
|
def __iter__(cls) -> Iterator[InputReference]:
|
47
50
|
# We iterate through the inheritance hierarchy to find all the WorkflowInputReference attached to this
|
@@ -62,3 +62,24 @@ def test_base_inputs__supports_inherited_inputs():
|
|
62
62
|
assert BottomInputs.first.name == "first"
|
63
63
|
assert BottomInputs.second.name == "second"
|
64
64
|
assert len([ref for ref in BottomInputs]) == 2
|
65
|
+
|
66
|
+
|
67
|
+
def test_base_inputs__iterating_over_descriptor_is_finite():
|
68
|
+
"""
|
69
|
+
Tests that iterating over a descriptor (like Inputs.image_url) creates a finite generator.
|
70
|
+
This was the bug reported in Slack where AB sometimes generates code that iterates over descriptors.
|
71
|
+
"""
|
72
|
+
|
73
|
+
class Inputs(BaseInputs):
|
74
|
+
image_url: str
|
75
|
+
|
76
|
+
iteration_count = 0
|
77
|
+
try:
|
78
|
+
for idx, x in enumerate(Inputs.image_url): # type: ignore[arg-type,var-annotated]
|
79
|
+
iteration_count += 1
|
80
|
+
if idx > 100:
|
81
|
+
break
|
82
|
+
except (TypeError, IndexError):
|
83
|
+
pass
|
84
|
+
|
85
|
+
assert iteration_count < 100
|
@@ -847,6 +847,22 @@ class WorkflowRunner(Generic[StateType]):
|
|
847
847
|
rejection_event = self._handle_work_item_event(event)
|
848
848
|
|
849
849
|
if rejection_event:
|
850
|
+
failed_node_name = rejection_event.body.node_definition.__name__
|
851
|
+
for active_span_id, active_node_data in list(self._active_nodes_by_execution_id.items()):
|
852
|
+
cancellation_event = NodeExecutionRejectedEvent(
|
853
|
+
trace_id=self._execution_context.trace_id,
|
854
|
+
span_id=active_span_id,
|
855
|
+
body=NodeExecutionRejectedBody(
|
856
|
+
node_definition=active_node_data.node.__class__,
|
857
|
+
error=WorkflowError(
|
858
|
+
message=f"Node execution cancelled due to {failed_node_name} failure",
|
859
|
+
code=WorkflowErrorCode.NODE_CANCELLED,
|
860
|
+
),
|
861
|
+
),
|
862
|
+
parent=self._execution_context.parent_context,
|
863
|
+
)
|
864
|
+
self._workflow_event_outer_queue.put(cancellation_event)
|
865
|
+
self._active_nodes_by_execution_id.pop(active_span_id)
|
850
866
|
break
|
851
867
|
|
852
868
|
# Handle any remaining events
|
@@ -692,6 +692,8 @@ class BaseWorkflow(Generic[InputsType, StateType], BaseExecutable, metaclass=_Ba
|
|
692
692
|
) from e
|
693
693
|
else:
|
694
694
|
raise
|
695
|
+
except (SyntaxError, ImportError, ModuleNotFoundError) as e:
|
696
|
+
raise WorkflowInitializationException(message=f"Failed to load workflow module: {e}") from e
|
695
697
|
workflows: List[Type[BaseWorkflow]] = []
|
696
698
|
for name in dir(module):
|
697
699
|
if name.startswith("__"):
|