vellum-ai 1.2.4__py3-none-any.whl → 1.3.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 (105) hide show
  1. vellum/__init__.py +56 -0
  2. vellum/client/README.md +1 -1
  3. vellum/client/core/client_wrapper.py +2 -2
  4. vellum/client/reference.md +0 -9
  5. vellum/client/resources/workflow_sandboxes/client.py +0 -12
  6. vellum/client/resources/workflow_sandboxes/raw_client.py +2 -10
  7. vellum/client/resources/workflows/client.py +20 -0
  8. vellum/client/resources/workflows/raw_client.py +20 -0
  9. vellum/client/types/__init__.py +56 -0
  10. vellum/client/types/audio_input.py +30 -0
  11. vellum/client/types/code_executor_input.py +8 -0
  12. vellum/client/types/deployment_read.py +5 -5
  13. vellum/client/types/document_input.py +30 -0
  14. vellum/client/types/image_input.py +30 -0
  15. vellum/client/types/named_scenario_input_audio_variable_value_request.py +22 -0
  16. vellum/client/types/named_scenario_input_document_variable_value_request.py +22 -0
  17. vellum/client/types/named_scenario_input_image_variable_value_request.py +22 -0
  18. vellum/client/types/named_scenario_input_request.py +8 -0
  19. vellum/client/types/named_scenario_input_video_variable_value_request.py +22 -0
  20. vellum/client/types/named_test_case_audio_variable_value.py +26 -0
  21. vellum/client/types/named_test_case_audio_variable_value_request.py +26 -0
  22. vellum/client/types/named_test_case_document_variable_value.py +22 -0
  23. vellum/client/types/named_test_case_document_variable_value_request.py +22 -0
  24. vellum/client/types/named_test_case_image_variable_value.py +22 -0
  25. vellum/client/types/named_test_case_image_variable_value_request.py +22 -0
  26. vellum/client/types/named_test_case_variable_value.py +8 -0
  27. vellum/client/types/named_test_case_variable_value_request.py +8 -0
  28. vellum/client/types/named_test_case_video_variable_value.py +22 -0
  29. vellum/client/types/named_test_case_video_variable_value_request.py +22 -0
  30. vellum/client/types/node_execution_span_attributes.py +1 -0
  31. vellum/client/types/scenario_input.py +11 -1
  32. vellum/client/types/scenario_input_audio_variable_value.py +22 -0
  33. vellum/client/types/scenario_input_document_variable_value.py +22 -0
  34. vellum/client/types/scenario_input_image_variable_value.py +22 -0
  35. vellum/client/types/scenario_input_video_variable_value.py +22 -0
  36. vellum/client/types/slim_deployment_read.py +5 -5
  37. vellum/client/types/slim_workflow_deployment.py +5 -5
  38. vellum/client/types/span_link.py +1 -1
  39. vellum/client/types/span_link_type_enum.py +1 -1
  40. vellum/client/types/test_case_audio_variable_value.py +27 -0
  41. vellum/client/types/test_case_document_variable_value.py +27 -0
  42. vellum/client/types/test_case_image_variable_value.py +27 -0
  43. vellum/client/types/test_case_variable_value.py +8 -0
  44. vellum/client/types/test_case_video_variable_value.py +27 -0
  45. vellum/client/types/video_input.py +30 -0
  46. vellum/client/types/workflow_deployment_read.py +5 -5
  47. vellum/client/types/workflow_push_deployment_config_request.py +1 -0
  48. vellum/client/types/workflow_request_audio_input_request.py +30 -0
  49. vellum/client/types/workflow_request_document_input_request.py +30 -0
  50. vellum/client/types/workflow_request_image_input_request.py +30 -0
  51. vellum/client/types/workflow_request_input_request.py +8 -0
  52. vellum/client/types/workflow_request_video_input_request.py +30 -0
  53. vellum/types/audio_input.py +3 -0
  54. vellum/types/document_input.py +3 -0
  55. vellum/types/image_input.py +3 -0
  56. vellum/types/named_scenario_input_audio_variable_value_request.py +3 -0
  57. vellum/types/named_scenario_input_document_variable_value_request.py +3 -0
  58. vellum/types/named_scenario_input_image_variable_value_request.py +3 -0
  59. vellum/types/named_scenario_input_video_variable_value_request.py +3 -0
  60. vellum/types/named_test_case_audio_variable_value.py +3 -0
  61. vellum/types/named_test_case_audio_variable_value_request.py +3 -0
  62. vellum/types/named_test_case_document_variable_value.py +3 -0
  63. vellum/types/named_test_case_document_variable_value_request.py +3 -0
  64. vellum/types/named_test_case_image_variable_value.py +3 -0
  65. vellum/types/named_test_case_image_variable_value_request.py +3 -0
  66. vellum/types/named_test_case_video_variable_value.py +3 -0
  67. vellum/types/named_test_case_video_variable_value_request.py +3 -0
  68. vellum/types/scenario_input_audio_variable_value.py +3 -0
  69. vellum/types/scenario_input_document_variable_value.py +3 -0
  70. vellum/types/scenario_input_image_variable_value.py +3 -0
  71. vellum/types/scenario_input_video_variable_value.py +3 -0
  72. vellum/types/test_case_audio_variable_value.py +3 -0
  73. vellum/types/test_case_document_variable_value.py +3 -0
  74. vellum/types/test_case_image_variable_value.py +3 -0
  75. vellum/types/test_case_video_variable_value.py +3 -0
  76. vellum/types/video_input.py +3 -0
  77. vellum/types/workflow_request_audio_input_request.py +3 -0
  78. vellum/types/workflow_request_document_input_request.py +3 -0
  79. vellum/types/workflow_request_image_input_request.py +3 -0
  80. vellum/types/workflow_request_video_input_request.py +3 -0
  81. vellum/workflows/events/types.py +6 -1
  82. vellum/workflows/integrations/tests/test_mcp_service.py +106 -1
  83. vellum/workflows/nodes/__init__.py +2 -0
  84. vellum/workflows/nodes/displayable/__init__.py +2 -0
  85. vellum/workflows/nodes/displayable/web_search_node/__init__.py +3 -0
  86. vellum/workflows/nodes/displayable/web_search_node/node.py +133 -0
  87. vellum/workflows/resolvers/base.py +19 -1
  88. vellum/workflows/resolvers/resolver.py +97 -0
  89. vellum/workflows/resolvers/tests/test_resolver.py +131 -0
  90. vellum/workflows/resolvers/types.py +11 -0
  91. vellum/workflows/runner/runner.py +49 -1
  92. vellum/workflows/state/context.py +41 -7
  93. vellum/workflows/utils/zip.py +46 -0
  94. vellum/workflows/workflows/base.py +13 -0
  95. {vellum_ai-1.2.4.dist-info → vellum_ai-1.3.0.dist-info}/METADATA +1 -1
  96. {vellum_ai-1.2.4.dist-info → vellum_ai-1.3.0.dist-info}/RECORD +105 -43
  97. vellum_cli/tests/test_init.py +7 -24
  98. vellum_cli/tests/test_pull.py +27 -52
  99. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +7 -33
  100. vellum_ee/workflows/display/utils/events.py +19 -1
  101. vellum_ee/workflows/display/utils/tests/test_events.py +42 -0
  102. vellum_ee/workflows/tests/test_server.py +115 -0
  103. {vellum_ai-1.2.4.dist-info → vellum_ai-1.3.0.dist-info}/LICENSE +0 -0
  104. {vellum_ai-1.2.4.dist-info → vellum_ai-1.3.0.dist-info}/WHEEL +0 -0
  105. {vellum_ai-1.2.4.dist-info → vellum_ai-1.3.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,131 @@
1
+ from datetime import datetime
2
+ from unittest.mock import Mock
3
+ from uuid import uuid4
4
+
5
+ from vellum.client.types.span_link import SpanLink
6
+ from vellum.client.types.vellum_code_resource_definition import VellumCodeResourceDefinition
7
+ from vellum.client.types.workflow_execution_detail import WorkflowExecutionDetail
8
+ from vellum.client.types.workflow_execution_initiated_body import WorkflowExecutionInitiatedBody
9
+ from vellum.client.types.workflow_execution_initiated_event import WorkflowExecutionInitiatedEvent
10
+ from vellum.client.types.workflow_execution_span import WorkflowExecutionSpan
11
+ from vellum.client.types.workflow_execution_span_attributes import WorkflowExecutionSpanAttributes
12
+ from vellum.client.types.workflow_parent_context import WorkflowParentContext
13
+ from vellum.workflows import BaseWorkflow
14
+ from vellum.workflows.inputs.base import BaseInputs
15
+ from vellum.workflows.resolvers.resolver import VellumResolver
16
+ from vellum.workflows.resolvers.types import LoadStateResult
17
+ from vellum.workflows.state.base import BaseState, NodeExecutionCache
18
+ from vellum.workflows.state.context import WorkflowContext
19
+
20
+
21
+ def test_load_state_with_context_success():
22
+ """Test load_state successfully loads state when context and client are available."""
23
+ resolver = VellumResolver()
24
+ execution_id = uuid4()
25
+ root_execution_id = uuid4()
26
+
27
+ class TestState(BaseState):
28
+ test_key: str = "test_value"
29
+
30
+ class TestWorkflow(BaseWorkflow[BaseInputs, TestState]):
31
+ pass
32
+
33
+ # GIVEN a state dictionary that matches what the resolver expects
34
+ prev_id = str(uuid4())
35
+ prev_span_id = str(uuid4())
36
+ state_dict = {
37
+ "test_key": "test_value",
38
+ "meta": {
39
+ "workflow_definition": "MockWorkflow",
40
+ "id": prev_id,
41
+ "span_id": prev_span_id,
42
+ "updated_ts": datetime.now().isoformat(),
43
+ "workflow_inputs": BaseInputs(),
44
+ "external_inputs": {},
45
+ "node_outputs": {},
46
+ "node_execution_cache": NodeExecutionCache(),
47
+ "parent": None,
48
+ },
49
+ }
50
+
51
+ mock_workflow_definition = VellumCodeResourceDefinition(
52
+ name="TestWorkflow", module=["test", "module"], id=str(uuid4())
53
+ )
54
+
55
+ mock_body = WorkflowExecutionInitiatedBody(workflow_definition=mock_workflow_definition, inputs={})
56
+
57
+ previous_trace_id = str(uuid4())
58
+ root_trace_id = str(uuid4())
59
+
60
+ previous_invocation = WorkflowExecutionInitiatedEvent(
61
+ id=str(uuid4()),
62
+ timestamp=datetime.now(),
63
+ trace_id=previous_trace_id,
64
+ span_id=str(execution_id),
65
+ body=mock_body,
66
+ links=[
67
+ SpanLink(
68
+ trace_id=previous_trace_id,
69
+ type="PREVIOUS_SPAN",
70
+ span_context=WorkflowParentContext(workflow_definition=mock_workflow_definition, span_id=str(uuid4())),
71
+ ),
72
+ SpanLink(
73
+ trace_id=root_trace_id,
74
+ type="ROOT_SPAN",
75
+ span_context=WorkflowParentContext(
76
+ workflow_definition=mock_workflow_definition, span_id=str(root_execution_id)
77
+ ),
78
+ ),
79
+ ],
80
+ )
81
+
82
+ root_invocation = WorkflowExecutionInitiatedEvent(
83
+ id=str(uuid4()),
84
+ timestamp=datetime.now(),
85
+ trace_id=root_trace_id,
86
+ span_id=str(root_execution_id),
87
+ body=mock_body,
88
+ links=None, # Root invocation has no links
89
+ )
90
+
91
+ mock_span = WorkflowExecutionSpan(
92
+ span_id=str(execution_id), # Use the actual execution_id
93
+ start_ts=datetime.now(),
94
+ end_ts=datetime.now(),
95
+ attributes=WorkflowExecutionSpanAttributes(label="Test Workflow", workflow_id=str(uuid4())),
96
+ events=[previous_invocation, root_invocation],
97
+ )
98
+
99
+ mock_response = WorkflowExecutionDetail(
100
+ span_id="test-span-id", start=datetime.now(), inputs=[], outputs=[], spans=[mock_span], state=state_dict
101
+ )
102
+
103
+ mock_client = Mock()
104
+ mock_client.workflow_executions.retrieve_workflow_execution_detail.return_value = mock_response
105
+
106
+ # AND context with the test workflow class is set up
107
+ context = WorkflowContext(vellum_client=mock_client)
108
+ TestWorkflow(context=context, resolvers=[resolver])
109
+
110
+ # WHEN load_state is called
111
+ result = resolver.load_state(previous_execution_id=execution_id)
112
+
113
+ # THEN should return LoadStateResult with state and span link info
114
+ assert isinstance(result, LoadStateResult)
115
+ assert result.state is not None
116
+ assert isinstance(result.state, TestState)
117
+ assert result.state.test_key == "test_value"
118
+
119
+ # AND the new state should have different meta IDs than those provided in the loaded state_dict
120
+ assert str(result.state.meta.id) != prev_id
121
+ assert str(result.state.meta.span_id) != prev_span_id
122
+
123
+ # AND should have span link info
124
+ assert result.previous_trace_id == previous_invocation.trace_id
125
+ assert result.previous_span_id == previous_invocation.span_id
126
+ assert result.root_trace_id == root_invocation.trace_id
127
+ assert result.root_span_id == root_invocation.span_id
128
+
129
+ mock_client.workflow_executions.retrieve_workflow_execution_detail.assert_called_once_with(
130
+ execution_id=str(execution_id)
131
+ )
@@ -0,0 +1,11 @@
1
+ from typing import NamedTuple
2
+
3
+ from vellum.workflows.state.base import BaseState
4
+
5
+
6
+ class LoadStateResult(NamedTuple):
7
+ state: BaseState
8
+ previous_trace_id: str
9
+ previous_span_id: str
10
+ root_trace_id: str
11
+ root_span_id: str
@@ -46,7 +46,7 @@ from vellum.workflows.events.node import (
46
46
  NodeExecutionRejectedBody,
47
47
  NodeExecutionStreamingBody,
48
48
  )
49
- from vellum.workflows.events.types import BaseEvent, NodeParentContext, ParentContext, WorkflowParentContext
49
+ from vellum.workflows.events.types import BaseEvent, NodeParentContext, ParentContext, SpanLink, WorkflowParentContext
50
50
  from vellum.workflows.events.workflow import (
51
51
  WorkflowEventStream,
52
52
  WorkflowExecutionFulfilledBody,
@@ -99,6 +99,7 @@ class WorkflowRunner(Generic[StateType]):
99
99
  state: Optional[StateType] = None,
100
100
  entrypoint_nodes: Optional[RunFromNodeArg] = None,
101
101
  external_inputs: Optional[ExternalInputsArg] = None,
102
+ previous_execution_id: Optional[Union[str, UUID]] = None,
102
103
  cancel_signal: Optional[ThreadingEvent] = None,
103
104
  node_output_mocks: Optional[MockNodeExecutionArg] = None,
104
105
  max_concurrency: Optional[int] = None,
@@ -110,6 +111,7 @@ class WorkflowRunner(Generic[StateType]):
110
111
  self.workflow = workflow
111
112
  self._is_resuming = False
112
113
  self._should_emit_initial_state = True
114
+ self._span_link_info: Optional[Tuple[str, str, str, str]] = None
113
115
  if entrypoint_nodes:
114
116
  if len(list(entrypoint_nodes)) > 1:
115
117
  raise ValueError("Cannot resume from multiple nodes")
@@ -140,6 +142,28 @@ class WorkflowRunner(Generic[StateType]):
140
142
  if issubclass(ei.inputs_class.__parent_class__, BaseNode)
141
143
  ]
142
144
  self._is_resuming = True
145
+ elif previous_execution_id:
146
+ for resolver in self.workflow.resolvers:
147
+ try:
148
+ load_state_result = resolver.load_state(previous_execution_id)
149
+ if load_state_result is not None:
150
+ state_class = self.workflow.get_state_class()
151
+ if isinstance(load_state_result.state, state_class):
152
+ self._initial_state = load_state_result.state
153
+ normalized_inputs = deepcopy(inputs) if inputs else self.workflow.get_default_inputs()
154
+ self._initial_state.meta.workflow_inputs = normalized_inputs
155
+ self._initial_state.meta.workflow_definition = self.workflow.__class__
156
+ self._span_link_info = (
157
+ load_state_result.previous_trace_id,
158
+ load_state_result.previous_span_id,
159
+ load_state_result.root_trace_id,
160
+ load_state_result.root_span_id,
161
+ )
162
+ break
163
+ except Exception as e:
164
+ logger.warning(f"Failed to load state from resolver {type(resolver).__name__}: {e}")
165
+ continue
166
+ self._entrypoints = self.workflow.get_entrypoints()
143
167
  else:
144
168
  normalized_inputs = deepcopy(inputs) if inputs else self.workflow.get_default_inputs()
145
169
  if state:
@@ -627,6 +651,29 @@ class WorkflowRunner(Generic[StateType]):
627
651
  return None
628
652
 
629
653
  def _initiate_workflow_event(self) -> WorkflowExecutionInitiatedEvent:
654
+ links: Optional[List[SpanLink]] = None
655
+
656
+ if self._span_link_info:
657
+ previous_trace_id, previous_span_id, root_trace_id, root_span_id = self._span_link_info
658
+ links = [
659
+ SpanLink(
660
+ trace_id=previous_trace_id,
661
+ type="PREVIOUS_SPAN",
662
+ span_context=WorkflowParentContext(
663
+ workflow_definition=self.workflow.__class__,
664
+ span_id=previous_span_id,
665
+ ),
666
+ ),
667
+ SpanLink(
668
+ trace_id=root_trace_id,
669
+ type="ROOT_SPAN",
670
+ span_context=WorkflowParentContext(
671
+ workflow_definition=self.workflow.__class__,
672
+ span_id=root_span_id,
673
+ ),
674
+ ),
675
+ ]
676
+
630
677
  return WorkflowExecutionInitiatedEvent(
631
678
  trace_id=self._execution_context.trace_id,
632
679
  span_id=self._initial_state.meta.span_id,
@@ -636,6 +683,7 @@ class WorkflowRunner(Generic[StateType]):
636
683
  initial_state=deepcopy(self._initial_state) if self._should_emit_initial_state else None,
637
684
  ),
638
685
  parent=self._execution_context.parent_context,
686
+ links=links,
639
687
  )
640
688
 
641
689
  def _stream_workflow_event(self, output: BaseOutput) -> WorkflowExecutionStreamingEvent:
@@ -1,15 +1,16 @@
1
1
  from functools import cached_property
2
2
  from queue import Queue
3
- from uuid import uuid4
3
+ from uuid import UUID, uuid4
4
4
  from typing import TYPE_CHECKING, Dict, List, Optional, Type
5
5
 
6
- from vellum import Vellum
6
+ from vellum import Vellum, __version__
7
7
  from vellum.workflows.context import ExecutionContext, get_execution_context, set_execution_context
8
8
  from vellum.workflows.events.types import ExternalParentContext
9
9
  from vellum.workflows.nodes.mocks import MockNodeExecution, MockNodeExecutionArg
10
10
  from vellum.workflows.outputs.base import BaseOutputs
11
11
  from vellum.workflows.references.constant import ConstantValueReference
12
12
  from vellum.workflows.utils.uuids import generate_workflow_deployment_prefix
13
+ from vellum.workflows.utils.zip import extract_zip_files
13
14
  from vellum.workflows.vellum_client import create_vellum_client
14
15
 
15
16
  if TYPE_CHECKING:
@@ -40,6 +41,9 @@ class WorkflowContext:
40
41
 
41
42
  if self._execution_context.parent_context is None:
42
43
  self._execution_context.parent_context = ExternalParentContext(span_id=uuid4())
44
+ # Only generate a new trace_id if one wasn't explicitly provided (i.e., if it's the default zero UUID)
45
+ if self._execution_context.trace_id == UUID("00000000-0000-0000-0000-000000000000"):
46
+ self._execution_context.trace_id = uuid4()
43
47
  # Propagate the updated context back to the global execution context
44
48
  set_execution_context(self._execution_context)
45
49
 
@@ -156,23 +160,53 @@ class WorkflowContext:
156
160
  Returns:
157
161
  BaseWorkflow instance if found, None otherwise
158
162
  """
159
- if not self.generated_files or not self.namespace:
163
+ if not self._generated_files or not self._namespace:
160
164
  return None
161
165
 
162
166
  expected_prefix = generate_workflow_deployment_prefix(deployment_name, release_tag)
163
167
 
164
- workflow_file_key = f"{expected_prefix}/workflow.py"
165
- if workflow_file_key not in self.generated_files:
166
- return None
168
+ try:
169
+ from vellum.workflows.workflows.base import BaseWorkflow
170
+
171
+ WorkflowClass = BaseWorkflow.load_from_module(f"{self.namespace}.{expected_prefix}")
172
+ WorkflowClass.is_dynamic = True
173
+ workflow_instance = WorkflowClass(context=WorkflowContext.create_from(self), parent_state=state)
174
+ return workflow_instance
175
+ except Exception:
176
+ pass
167
177
 
168
178
  try:
179
+ major_version = __version__.split(".")[0]
180
+ version_range = f">={major_version}.0.0,<={__version__}"
181
+
182
+ response = self.vellum_client.workflows.pull(
183
+ deployment_name,
184
+ release_tag=release_tag,
185
+ version=version_range,
186
+ request_options={"additional_headers": {"X-Vellum-Always-Success": "true"}},
187
+ )
188
+
189
+ if isinstance(response, dict) and response.get("success") is False:
190
+ return None
191
+
192
+ zip_bytes = b"".join(response)
193
+ pulled_files = extract_zip_files(zip_bytes)
194
+
195
+ for file_name, content in pulled_files.items():
196
+ prefixed_file_name = f"{expected_prefix}/{file_name}"
197
+ self._generated_files[prefixed_file_name] = content
198
+
169
199
  from vellum.workflows.workflows.base import BaseWorkflow
170
200
 
171
201
  WorkflowClass = BaseWorkflow.load_from_module(f"{self.namespace}.{expected_prefix}")
202
+ WorkflowClass.is_dynamic = True
172
203
  workflow_instance = WorkflowClass(context=WorkflowContext.create_from(self), parent_state=state)
173
204
  return workflow_instance
205
+
174
206
  except Exception:
175
- return None
207
+ pass
208
+
209
+ return None
176
210
 
177
211
  @classmethod
178
212
  def create_from(cls, context):
@@ -0,0 +1,46 @@
1
+ import io
2
+ import zipfile
3
+
4
+
5
+ def zip_file_map(file_map: dict[str, str]) -> bytes:
6
+ """
7
+ Create a zip file from a dictionary of file names to content.
8
+
9
+ Args:
10
+ file_map: Dictionary mapping file names to their content
11
+
12
+ Returns:
13
+ Bytes representing the zip file
14
+ """
15
+ zip_buffer = io.BytesIO()
16
+
17
+ with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file:
18
+ for filename, content in file_map.items():
19
+ zip_file.writestr(filename, content)
20
+
21
+ zip_bytes = zip_buffer.getvalue()
22
+ zip_buffer.close()
23
+
24
+ return zip_bytes
25
+
26
+
27
+ def extract_zip_files(zip_bytes: bytes) -> dict[str, str]:
28
+ """
29
+ Extract files from a zip archive.
30
+
31
+ Args:
32
+ zip_bytes: Bytes representing the zip file
33
+
34
+ Returns:
35
+ Dictionary mapping file names to their content
36
+ """
37
+ zip_buffer = io.BytesIO(zip_bytes)
38
+ extracted_files = {}
39
+
40
+ with zipfile.ZipFile(zip_buffer) as zip_file:
41
+ for file_name in zip_file.namelist():
42
+ with zip_file.open(file_name) as source:
43
+ content = source.read().decode("utf-8")
44
+ extracted_files[file_name] = content
45
+
46
+ return extracted_files
@@ -251,6 +251,9 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
251
251
  for emitter in self.emitters:
252
252
  emitter.register_context(self._context)
253
253
 
254
+ for resolver in self.resolvers:
255
+ resolver.register_workflow_instance(self)
256
+
254
257
  self.validate()
255
258
 
256
259
  @property
@@ -361,6 +364,7 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
361
364
  state: Optional[StateType] = None,
362
365
  entrypoint_nodes: Optional[RunFromNodeArg] = None,
363
366
  external_inputs: Optional[ExternalInputsArg] = None,
367
+ previous_execution_id: Optional[Union[str, UUID]] = None,
364
368
  cancel_signal: Optional[ThreadingEvent] = None,
365
369
  node_output_mocks: Optional[MockNodeExecutionArg] = None,
366
370
  max_concurrency: Optional[int] = None,
@@ -386,6 +390,9 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
386
390
  external_inputs: Optional[ExternalInputsArg] = None
387
391
  External inputs to pass to the Workflow. Useful for providing human-in-the-loop behavior to the Workflow.
388
392
 
393
+ previous_execution_id: Optional[Union[str, UUID]] = None
394
+ The execution ID of the previous execution to resume from.
395
+
389
396
  cancel_signal: Optional[ThreadingEvent] = None
390
397
  A threading event that can be used to cancel the Workflow Execution.
391
398
 
@@ -405,6 +412,7 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
405
412
  state=state,
406
413
  entrypoint_nodes=entrypoint_nodes,
407
414
  external_inputs=external_inputs,
415
+ previous_execution_id=previous_execution_id,
408
416
  cancel_signal=cancel_signal,
409
417
  node_output_mocks=node_output_mocks,
410
418
  max_concurrency=max_concurrency,
@@ -473,6 +481,7 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
473
481
  state: Optional[StateType] = None,
474
482
  entrypoint_nodes: Optional[RunFromNodeArg] = None,
475
483
  external_inputs: Optional[ExternalInputsArg] = None,
484
+ previous_execution_id: Optional[Union[str, UUID]] = None,
476
485
  cancel_signal: Optional[ThreadingEvent] = None,
477
486
  node_output_mocks: Optional[MockNodeExecutionArg] = None,
478
487
  max_concurrency: Optional[int] = None,
@@ -499,6 +508,9 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
499
508
  external_inputs: Optional[ExternalInputsArg] = None
500
509
  External inputs to pass to the Workflow. Useful for providing human-in-the-loop behavior to the Workflow.
501
510
 
511
+ previous_execution_id: Optional[Union[str, UUID]] = None
512
+ The execution ID of the previous execution to resume from.
513
+
502
514
  cancel_signal: Optional[ThreadingEvent] = None
503
515
  A threading event that can be used to cancel the Workflow Execution.
504
516
 
@@ -519,6 +531,7 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
519
531
  state=state,
520
532
  entrypoint_nodes=entrypoint_nodes,
521
533
  external_inputs=external_inputs,
534
+ previous_execution_id=previous_execution_id,
522
535
  cancel_signal=cancel_signal,
523
536
  node_output_mocks=node_output_mocks,
524
537
  max_concurrency=max_concurrency,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 1.2.4
3
+ Version: 1.3.0
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0