vellum-ai 1.2.5__py3-none-any.whl → 1.3.1__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 +8 -0
- vellum/client/README.md +1 -1
- vellum/client/core/client_wrapper.py +2 -2
- vellum/client/reference.md +0 -9
- vellum/client/resources/workflow_sandboxes/client.py +0 -12
- vellum/client/resources/workflow_sandboxes/raw_client.py +2 -10
- vellum/client/types/__init__.py +8 -0
- vellum/client/types/deployment_read.py +5 -5
- vellum/client/types/slim_deployment_read.py +5 -5
- vellum/client/types/slim_workflow_deployment.py +5 -5
- vellum/client/types/workflow_deployment_read.py +5 -5
- vellum/client/types/workflow_request_audio_input_request.py +30 -0
- vellum/client/types/workflow_request_document_input_request.py +30 -0
- vellum/client/types/workflow_request_image_input_request.py +30 -0
- vellum/client/types/workflow_request_input_request.py +8 -0
- vellum/client/types/workflow_request_video_input_request.py +30 -0
- vellum/types/workflow_request_audio_input_request.py +3 -0
- vellum/types/workflow_request_document_input_request.py +3 -0
- vellum/types/workflow_request_image_input_request.py +3 -0
- vellum/types/workflow_request_video_input_request.py +3 -0
- vellum/workflows/events/types.py +6 -1
- vellum/workflows/events/workflow.py +9 -2
- vellum/workflows/integrations/tests/test_mcp_service.py +106 -1
- vellum/workflows/nodes/__init__.py +2 -0
- vellum/workflows/nodes/displayable/__init__.py +2 -0
- vellum/workflows/nodes/displayable/tool_calling_node/utils.py +11 -0
- vellum/workflows/nodes/displayable/web_search_node/__init__.py +3 -0
- vellum/workflows/nodes/displayable/web_search_node/node.py +133 -0
- vellum/workflows/nodes/displayable/web_search_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/web_search_node/tests/test_node.py +319 -0
- vellum/workflows/resolvers/base.py +3 -2
- vellum/workflows/resolvers/resolver.py +62 -7
- vellum/workflows/resolvers/tests/test_resolver.py +79 -7
- vellum/workflows/resolvers/types.py +11 -0
- vellum/workflows/runner/runner.py +49 -1
- vellum/workflows/state/context.py +41 -7
- vellum/workflows/utils/zip.py +46 -0
- vellum/workflows/workflows/base.py +10 -0
- {vellum_ai-1.2.5.dist-info → vellum_ai-1.3.1.dist-info}/METADATA +1 -1
- {vellum_ai-1.2.5.dist-info → vellum_ai-1.3.1.dist-info}/RECORD +48 -34
- vellum_cli/tests/test_init.py +7 -24
- vellum_cli/tests/test_pull.py +27 -52
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +7 -33
- vellum_ee/workflows/display/utils/events.py +3 -0
- vellum_ee/workflows/tests/test_server.py +115 -0
- {vellum_ai-1.2.5.dist-info → vellum_ai-1.3.1.dist-info}/LICENSE +0 -0
- {vellum_ai-1.2.5.dist-info → vellum_ai-1.3.1.dist-info}/WHEEL +0 -0
- {vellum_ai-1.2.5.dist-info → vellum_ai-1.3.1.dist-info}/entry_points.txt +0 -0
@@ -2,10 +2,18 @@ from datetime import datetime
|
|
2
2
|
from unittest.mock import Mock
|
3
3
|
from uuid import uuid4
|
4
4
|
|
5
|
+
from vellum.client.types.span_link import SpanLink
|
6
|
+
from vellum.client.types.vellum_code_resource_definition import VellumCodeResourceDefinition
|
5
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
|
6
13
|
from vellum.workflows import BaseWorkflow
|
7
14
|
from vellum.workflows.inputs.base import BaseInputs
|
8
15
|
from vellum.workflows.resolvers.resolver import VellumResolver
|
16
|
+
from vellum.workflows.resolvers.types import LoadStateResult
|
9
17
|
from vellum.workflows.state.base import BaseState, NodeExecutionCache
|
10
18
|
from vellum.workflows.state.context import WorkflowContext
|
11
19
|
|
@@ -14,6 +22,7 @@ def test_load_state_with_context_success():
|
|
14
22
|
"""Test load_state successfully loads state when context and client are available."""
|
15
23
|
resolver = VellumResolver()
|
16
24
|
execution_id = uuid4()
|
25
|
+
root_execution_id = uuid4()
|
17
26
|
|
18
27
|
class TestState(BaseState):
|
19
28
|
test_key: str = "test_value"
|
@@ -22,12 +31,14 @@ def test_load_state_with_context_success():
|
|
22
31
|
pass
|
23
32
|
|
24
33
|
# GIVEN a state dictionary that matches what the resolver expects
|
34
|
+
prev_id = str(uuid4())
|
35
|
+
prev_span_id = str(uuid4())
|
25
36
|
state_dict = {
|
26
37
|
"test_key": "test_value",
|
27
38
|
"meta": {
|
28
39
|
"workflow_definition": "MockWorkflow",
|
29
|
-
"id":
|
30
|
-
"span_id":
|
40
|
+
"id": prev_id,
|
41
|
+
"span_id": prev_span_id,
|
31
42
|
"updated_ts": datetime.now().isoformat(),
|
32
43
|
"workflow_inputs": BaseInputs(),
|
33
44
|
"external_inputs": {},
|
@@ -37,22 +48,83 @@ def test_load_state_with_context_success():
|
|
37
48
|
},
|
38
49
|
}
|
39
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
|
+
|
40
99
|
mock_response = WorkflowExecutionDetail(
|
41
|
-
span_id="test-span-id", start=datetime.now(), inputs=[], outputs=[], spans=[], state=state_dict
|
100
|
+
span_id="test-span-id", start=datetime.now(), inputs=[], outputs=[], spans=[mock_span], state=state_dict
|
42
101
|
)
|
43
102
|
|
44
103
|
mock_client = Mock()
|
45
104
|
mock_client.workflow_executions.retrieve_workflow_execution_detail.return_value = mock_response
|
46
105
|
|
47
|
-
# AND context with the test workflow class
|
106
|
+
# AND context with the test workflow class is set up
|
48
107
|
context = WorkflowContext(vellum_client=mock_client)
|
49
108
|
TestWorkflow(context=context, resolvers=[resolver])
|
50
109
|
|
110
|
+
# WHEN load_state is called
|
51
111
|
result = resolver.load_state(previous_execution_id=execution_id)
|
52
112
|
|
53
|
-
# THEN should return
|
54
|
-
assert isinstance(result,
|
55
|
-
assert result.
|
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
|
56
128
|
|
57
129
|
mock_client.workflow_executions.retrieve_workflow_execution_detail.assert_called_once_with(
|
58
130
|
execution_id=str(execution_id)
|
@@ -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.
|
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
|
-
|
165
|
-
|
166
|
-
|
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
|
-
|
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
|
@@ -364,6 +364,7 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
|
|
364
364
|
state: Optional[StateType] = None,
|
365
365
|
entrypoint_nodes: Optional[RunFromNodeArg] = None,
|
366
366
|
external_inputs: Optional[ExternalInputsArg] = None,
|
367
|
+
previous_execution_id: Optional[Union[str, UUID]] = None,
|
367
368
|
cancel_signal: Optional[ThreadingEvent] = None,
|
368
369
|
node_output_mocks: Optional[MockNodeExecutionArg] = None,
|
369
370
|
max_concurrency: Optional[int] = None,
|
@@ -389,6 +390,9 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
|
|
389
390
|
external_inputs: Optional[ExternalInputsArg] = None
|
390
391
|
External inputs to pass to the Workflow. Useful for providing human-in-the-loop behavior to the Workflow.
|
391
392
|
|
393
|
+
previous_execution_id: Optional[Union[str, UUID]] = None
|
394
|
+
The execution ID of the previous execution to resume from.
|
395
|
+
|
392
396
|
cancel_signal: Optional[ThreadingEvent] = None
|
393
397
|
A threading event that can be used to cancel the Workflow Execution.
|
394
398
|
|
@@ -408,6 +412,7 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
|
|
408
412
|
state=state,
|
409
413
|
entrypoint_nodes=entrypoint_nodes,
|
410
414
|
external_inputs=external_inputs,
|
415
|
+
previous_execution_id=previous_execution_id,
|
411
416
|
cancel_signal=cancel_signal,
|
412
417
|
node_output_mocks=node_output_mocks,
|
413
418
|
max_concurrency=max_concurrency,
|
@@ -476,6 +481,7 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
|
|
476
481
|
state: Optional[StateType] = None,
|
477
482
|
entrypoint_nodes: Optional[RunFromNodeArg] = None,
|
478
483
|
external_inputs: Optional[ExternalInputsArg] = None,
|
484
|
+
previous_execution_id: Optional[Union[str, UUID]] = None,
|
479
485
|
cancel_signal: Optional[ThreadingEvent] = None,
|
480
486
|
node_output_mocks: Optional[MockNodeExecutionArg] = None,
|
481
487
|
max_concurrency: Optional[int] = None,
|
@@ -502,6 +508,9 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
|
|
502
508
|
external_inputs: Optional[ExternalInputsArg] = None
|
503
509
|
External inputs to pass to the Workflow. Useful for providing human-in-the-loop behavior to the Workflow.
|
504
510
|
|
511
|
+
previous_execution_id: Optional[Union[str, UUID]] = None
|
512
|
+
The execution ID of the previous execution to resume from.
|
513
|
+
|
505
514
|
cancel_signal: Optional[ThreadingEvent] = None
|
506
515
|
A threading event that can be used to cancel the Workflow Execution.
|
507
516
|
|
@@ -522,6 +531,7 @@ class BaseWorkflow(Generic[InputsType, StateType], metaclass=_BaseWorkflowMeta):
|
|
522
531
|
state=state,
|
523
532
|
entrypoint_nodes=entrypoint_nodes,
|
524
533
|
external_inputs=external_inputs,
|
534
|
+
previous_execution_id=previous_execution_id,
|
525
535
|
cancel_signal=cancel_signal,
|
526
536
|
node_output_mocks=node_output_mocks,
|
527
537
|
max_concurrency=max_concurrency,
|