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.
Files changed (35) hide show
  1. vellum/__init__.py +2 -0
  2. vellum/client/core/client_wrapper.py +2 -2
  3. vellum/client/reference.md +81 -0
  4. vellum/client/resources/container_images/client.py +8 -2
  5. vellum/client/resources/container_images/raw_client.py +8 -0
  6. vellum/client/resources/workflows/client.py +81 -0
  7. vellum/client/resources/workflows/raw_client.py +85 -0
  8. vellum/client/types/__init__.py +2 -0
  9. vellum/client/types/workflow_resolved_state.py +31 -0
  10. vellum/types/workflow_resolved_state.py +3 -0
  11. vellum/workflows/descriptors/base.py +3 -0
  12. vellum/workflows/errors/types.py +1 -0
  13. vellum/workflows/inputs/base.py +4 -1
  14. vellum/workflows/inputs/tests/test_inputs.py +21 -0
  15. vellum/workflows/runner/runner.py +16 -0
  16. vellum/workflows/workflows/base.py +2 -0
  17. {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/METADATA +1 -1
  18. {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/RECORD +35 -33
  19. vellum_ee/assets/node-definitions.json +157 -12
  20. vellum_ee/workflows/display/exceptions.py +2 -6
  21. vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +1 -1
  22. vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +1 -1
  23. vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +11 -4
  24. vellum_ee/workflows/display/nodes/vellum/search_node.py +4 -4
  25. vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +11 -4
  26. vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py +1 -1
  27. vellum_ee/workflows/display/utils/exceptions.py +19 -0
  28. vellum_ee/workflows/display/utils/expressions.py +19 -11
  29. vellum_ee/workflows/display/utils/vellum.py +7 -1
  30. vellum_ee/workflows/display/workflows/base_workflow_display.py +2 -2
  31. vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +54 -1
  32. vellum_ee/workflows/tests/test_server.py +41 -0
  33. {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/LICENSE +0 -0
  34. {vellum_ai-1.6.4.dist-info → vellum_ai-1.7.0.dist-info}/WHEEL +0 -0
  35. {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.6.4",
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.6.4",
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:
@@ -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
  *,
@@ -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
@@ -0,0 +1,3 @@
1
+ # WARNING: This file will be removed in a future release. Please import from "vellum.client" instead.
2
+
3
+ from vellum.client.types.workflow_resolved_state import *
@@ -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
 
@@ -25,6 +25,7 @@ class WorkflowErrorCode(Enum):
25
25
  PROVIDER_ERROR = "PROVIDER_ERROR"
26
26
  USER_DEFINED_ERROR = "USER_DEFINED_ERROR"
27
27
  WORKFLOW_CANCELLED = "WORKFLOW_CANCELLED"
28
+ NODE_CANCELLED = "NODE_CANCELLED"
28
29
 
29
30
 
30
31
  @dataclass(frozen=True)
@@ -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
- return super().__getattribute__(name)
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("__"):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 1.6.4
3
+ Version: 1.7.0
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0