vellum-ai 0.14.4__py3-none-any.whl → 0.14.6__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 +6 -0
- vellum/client/__init__.py +8 -8
- vellum/client/core/client_wrapper.py +1 -1
- vellum/client/resources/__init__.py +2 -0
- vellum/client/resources/workflow_sandboxes/__init__.py +3 -0
- vellum/client/resources/workflow_sandboxes/client.py +146 -0
- vellum/client/resources/workflow_sandboxes/types/__init__.py +5 -0
- vellum/client/resources/workflow_sandboxes/types/list_workflow_sandbox_examples_request_tag.py +5 -0
- vellum/client/types/__init__.py +4 -0
- vellum/client/types/paginated_workflow_sandbox_example_list.py +23 -0
- vellum/client/types/workflow_sandbox_example.py +22 -0
- vellum/resources/workflow_sandboxes/types/__init__.py +3 -0
- vellum/resources/workflow_sandboxes/types/list_workflow_sandbox_examples_request_tag.py +3 -0
- vellum/types/paginated_workflow_sandbox_example_list.py +3 -0
- vellum/types/workflow_sandbox_example.py +3 -0
- vellum/workflows/context.py +8 -3
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +81 -1
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +44 -20
- vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +17 -10
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +12 -2
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py +23 -0
- vellum/workflows/workflows/base.py +61 -53
- vellum/workflows/workflows/tests/test_base_workflow.py +47 -0
- vellum/workflows/workflows/tests/test_context.py +60 -0
- {vellum_ai-0.14.4.dist-info → vellum_ai-0.14.6.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.4.dist-info → vellum_ai-0.14.6.dist-info}/RECORD +39 -29
- vellum_ee/workflows/display/nodes/vellum/__init__.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/base_adornment_node.py +39 -0
- vellum_ee/workflows/display/nodes/vellum/map_node.py +2 -2
- vellum_ee/workflows/display/nodes/vellum/retry_node.py +36 -4
- vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +31 -0
- vellum_ee/workflows/display/nodes/vellum/try_node.py +43 -29
- vellum_ee/workflows/display/nodes/vellum/utils.py +8 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +25 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +14 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +19 -1
- {vellum_ai-0.14.4.dist-info → vellum_ai-0.14.6.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.4.dist-info → vellum_ai-0.14.6.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.4.dist-info → vellum_ai-0.14.6.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
from uuid import UUID
|
2
|
+
from typing import Any, Callable, Generic, Optional, TypeVar, cast
|
3
|
+
|
4
|
+
from vellum.workflows.nodes.bases.base_adornment_node import BaseAdornmentNode
|
5
|
+
from vellum.workflows.nodes.utils import get_wrapped_node
|
6
|
+
from vellum.workflows.types.core import JsonArray, JsonObject
|
7
|
+
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
8
|
+
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
9
|
+
from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
|
10
|
+
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
11
|
+
|
12
|
+
_BaseAdornmentNodeType = TypeVar("_BaseAdornmentNodeType", bound=BaseAdornmentNode)
|
13
|
+
|
14
|
+
|
15
|
+
class BaseAdornmentNodeDisplay(BaseNodeVellumDisplay[_BaseAdornmentNodeType], Generic[_BaseAdornmentNodeType]):
|
16
|
+
def serialize(
|
17
|
+
self,
|
18
|
+
display_context: "WorkflowDisplayContext",
|
19
|
+
**kwargs: Any,
|
20
|
+
) -> dict:
|
21
|
+
node = self._node
|
22
|
+
adornment = cast(Optional[JsonObject], kwargs.get("adornment"))
|
23
|
+
get_additional_kwargs = cast(Optional[Callable[[UUID], dict]], kwargs.get("get_additional_kwargs"))
|
24
|
+
|
25
|
+
wrapped_node = get_wrapped_node(node)
|
26
|
+
if not wrapped_node:
|
27
|
+
raise NotImplementedError(
|
28
|
+
"Unable to serialize standalone adornment nodes. Please use adornment nodes as a decorator."
|
29
|
+
)
|
30
|
+
|
31
|
+
wrapped_node_display_class = get_node_display_class(BaseNodeDisplay, wrapped_node)
|
32
|
+
wrapped_node_display = wrapped_node_display_class()
|
33
|
+
additional_kwargs = get_additional_kwargs(wrapped_node_display.node_id) if get_additional_kwargs else {}
|
34
|
+
serialized_wrapped_node = wrapped_node_display.serialize(display_context, **kwargs, **additional_kwargs)
|
35
|
+
|
36
|
+
adornments = cast(JsonArray, serialized_wrapped_node.get("adornments")) or []
|
37
|
+
serialized_wrapped_node["adornments"] = adornments + [adornment] if adornment else adornments
|
38
|
+
|
39
|
+
return serialized_wrapped_node
|
@@ -3,8 +3,8 @@ from typing import Dict, Generic, List, Optional, TypeVar, cast
|
|
3
3
|
|
4
4
|
from vellum.workflows.nodes import MapNode
|
5
5
|
from vellum.workflows.types.core import JsonObject
|
6
|
-
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
7
6
|
from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
|
7
|
+
from vellum_ee.workflows.display.nodes.vellum.base_adornment_node import BaseAdornmentNodeDisplay
|
8
8
|
from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
|
9
9
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
10
10
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
@@ -12,7 +12,7 @@ from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class imp
|
|
12
12
|
_MapNodeType = TypeVar("_MapNodeType", bound=MapNode)
|
13
13
|
|
14
14
|
|
15
|
-
class BaseMapNodeDisplay(
|
15
|
+
class BaseMapNodeDisplay(BaseAdornmentNodeDisplay[_MapNodeType], Generic[_MapNodeType]):
|
16
16
|
def serialize(
|
17
17
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
18
18
|
) -> JsonObject:
|
@@ -1,10 +1,42 @@
|
|
1
|
-
|
1
|
+
import inspect
|
2
|
+
from typing import Any, Generic, TypeVar, cast
|
2
3
|
|
4
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
3
5
|
from vellum.workflows.nodes.core.retry_node.node import RetryNode
|
4
|
-
from
|
6
|
+
from vellum.workflows.types.core import JsonArray, JsonObject
|
7
|
+
from vellum.workflows.utils.uuids import uuid4_from_hash
|
8
|
+
from vellum.workflows.workflows.base import BaseWorkflow
|
9
|
+
from vellum_ee.workflows.display.nodes.vellum.base_adornment_node import BaseAdornmentNodeDisplay
|
10
|
+
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
5
11
|
|
6
12
|
_RetryNodeType = TypeVar("_RetryNodeType", bound=RetryNode)
|
7
13
|
|
8
14
|
|
9
|
-
class BaseRetryNodeDisplay(
|
10
|
-
|
15
|
+
class BaseRetryNodeDisplay(BaseAdornmentNodeDisplay[_RetryNodeType], Generic[_RetryNodeType]):
|
16
|
+
def serialize(self, display_context: WorkflowDisplayContext, **kwargs: Any) -> JsonObject:
|
17
|
+
node = self._node
|
18
|
+
node_id = self.node_id
|
19
|
+
|
20
|
+
attributes: JsonArray = []
|
21
|
+
for attribute in node:
|
22
|
+
if inspect.isclass(attribute.instance) and issubclass(attribute.instance, BaseWorkflow):
|
23
|
+
# We don't need to serialize attributes that are workflows
|
24
|
+
continue
|
25
|
+
|
26
|
+
id = str(uuid4_from_hash(f"{node_id}|{attribute.name}"))
|
27
|
+
attributes.append(
|
28
|
+
{
|
29
|
+
"id": id,
|
30
|
+
"name": attribute.name,
|
31
|
+
"value": self.serialize_value(display_context, cast(BaseDescriptor, attribute.instance)),
|
32
|
+
}
|
33
|
+
)
|
34
|
+
|
35
|
+
adornment: JsonObject = {
|
36
|
+
"id": str(node_id),
|
37
|
+
"label": node.__qualname__,
|
38
|
+
"base": self.get_base().dict(),
|
39
|
+
"attributes": attributes,
|
40
|
+
}
|
41
|
+
|
42
|
+
return super().serialize(display_context, adornment=adornment)
|
@@ -7,6 +7,7 @@ from vellum.workflows.descriptors.base import BaseDescriptor
|
|
7
7
|
from vellum.workflows.inputs import BaseInputs
|
8
8
|
from vellum.workflows.nodes.bases import BaseNode
|
9
9
|
from vellum.workflows.outputs import BaseOutputs
|
10
|
+
from vellum.workflows.references import LazyReference
|
10
11
|
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
11
12
|
from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
|
12
13
|
from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input_value_pointer_rules
|
@@ -43,6 +44,10 @@ class MyNodeADisplay(BaseNodeVellumDisplay[MyNodeA]):
|
|
43
44
|
class MyNodeB(BaseNode):
|
44
45
|
example = MyNodeA.Outputs.output
|
45
46
|
fallback_example = MyNodeA.Outputs.output.coalesce(Inputs.example_workflow_input).coalesce("fallback")
|
47
|
+
constant_coalesce = Inputs.example_workflow_input.coalesce("default_value")
|
48
|
+
lazy_coalesce: BaseDescriptor[str] = LazyReference(
|
49
|
+
lambda: MyNodeA.Outputs.output.coalesce(Inputs.example_workflow_input)
|
50
|
+
)
|
46
51
|
|
47
52
|
|
48
53
|
@pytest.mark.parametrize(
|
@@ -76,6 +81,32 @@ class MyNodeB(BaseNode):
|
|
76
81
|
ConstantValuePointer(type="CONSTANT_VALUE", data=StringVellumValue(value="fallback")),
|
77
82
|
],
|
78
83
|
),
|
84
|
+
(
|
85
|
+
MyNodeB.constant_coalesce,
|
86
|
+
[
|
87
|
+
InputVariablePointer(
|
88
|
+
type="INPUT_VARIABLE",
|
89
|
+
data=InputVariableData(input_variable_id="a154c29d-fac0-4cd0-ba88-bc52034f5470"),
|
90
|
+
),
|
91
|
+
ConstantValuePointer(type="CONSTANT_VALUE", data=StringVellumValue(value="default_value")),
|
92
|
+
],
|
93
|
+
),
|
94
|
+
(
|
95
|
+
MyNodeB.lazy_coalesce,
|
96
|
+
[
|
97
|
+
NodeOutputPointer(
|
98
|
+
type="NODE_OUTPUT",
|
99
|
+
data=NodeOutputData(
|
100
|
+
node_id="b48fa5e0-d7d3-4fe3-ae48-615415011cc5",
|
101
|
+
output_id="4b16a629-11a1-4b3f-a965-a57b872d13b8",
|
102
|
+
),
|
103
|
+
),
|
104
|
+
InputVariablePointer(
|
105
|
+
type="INPUT_VARIABLE",
|
106
|
+
data=InputVariableData(input_variable_id="a154c29d-fac0-4cd0-ba88-bc52034f5470"),
|
107
|
+
),
|
108
|
+
],
|
109
|
+
),
|
79
110
|
],
|
80
111
|
)
|
81
112
|
def test_create_node_input_value_pointer_rules(
|
@@ -1,55 +1,69 @@
|
|
1
|
+
import inspect
|
1
2
|
from uuid import UUID
|
2
3
|
from typing import Any, Callable, ClassVar, Generic, Optional, Tuple, Type, TypeVar, cast
|
3
4
|
|
5
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
4
6
|
from vellum.workflows.nodes.bases.base import BaseNode
|
5
7
|
from vellum.workflows.nodes.core.try_node.node import TryNode
|
6
|
-
from vellum.workflows.nodes.utils import ADORNMENT_MODULE_NAME
|
8
|
+
from vellum.workflows.nodes.utils import ADORNMENT_MODULE_NAME
|
7
9
|
from vellum.workflows.references.output import OutputReference
|
8
|
-
from vellum.workflows.types.core import JsonObject
|
10
|
+
from vellum.workflows.types.core import JsonArray, JsonObject
|
9
11
|
from vellum.workflows.types.utils import get_original_base
|
10
12
|
from vellum.workflows.utils.uuids import uuid4_from_hash
|
13
|
+
from vellum.workflows.workflows.base import BaseWorkflow
|
11
14
|
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
12
|
-
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
13
15
|
from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
|
14
16
|
from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
|
15
|
-
from vellum_ee.workflows.display.nodes.
|
17
|
+
from vellum_ee.workflows.display.nodes.vellum.base_adornment_node import BaseAdornmentNodeDisplay
|
16
18
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
17
19
|
|
18
20
|
_TryNodeType = TypeVar("_TryNodeType", bound=TryNode)
|
19
21
|
|
20
22
|
|
21
|
-
class BaseTryNodeDisplay(
|
23
|
+
class BaseTryNodeDisplay(BaseAdornmentNodeDisplay[_TryNodeType], Generic[_TryNodeType]):
|
22
24
|
error_output_id: ClassVar[Optional[UUID]] = None
|
23
25
|
|
24
|
-
def serialize(self, display_context: WorkflowDisplayContext, **kwargs: Any) -> JsonObject:
|
26
|
+
def serialize(self, display_context: "WorkflowDisplayContext", **kwargs: Any) -> JsonObject:
|
25
27
|
node = self._node
|
28
|
+
node_id = self.node_id
|
29
|
+
|
30
|
+
# We let the inner node serialize first and then append to it
|
31
|
+
attributes: JsonArray = []
|
32
|
+
for attribute in node:
|
33
|
+
if inspect.isclass(attribute.instance) and issubclass(attribute.instance, BaseWorkflow):
|
34
|
+
# We don't need to serialize attributes that are workflows
|
35
|
+
continue
|
36
|
+
|
37
|
+
id = str(uuid4_from_hash(f"{node_id}|{attribute.name}"))
|
38
|
+
attributes.append(
|
39
|
+
{
|
40
|
+
"id": id,
|
41
|
+
"name": attribute.name,
|
42
|
+
"value": self.serialize_value(display_context, cast(BaseDescriptor, attribute.instance)),
|
43
|
+
}
|
44
|
+
)
|
26
45
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
class TryBaseNodeDisplay(BaseNodeDisplay[node]): # type: ignore[valid-type]
|
39
|
-
pass
|
40
|
-
|
41
|
-
return TryBaseNodeDisplay().serialize(display_context)
|
42
|
-
|
43
|
-
# We need the node display class of the underlying node because
|
44
|
-
# it contains the logic for serializing the node and potential display overrides
|
45
|
-
node_display_class = get_node_display_class(BaseNodeDisplay, inner_node)
|
46
|
-
node_display = node_display_class()
|
47
|
-
|
48
|
-
serialized_node = node_display.serialize(
|
46
|
+
adornment: JsonObject = {
|
47
|
+
"id": str(node_id),
|
48
|
+
"label": node.__qualname__,
|
49
|
+
"base": self.get_base().dict(),
|
50
|
+
"attributes": attributes,
|
51
|
+
}
|
52
|
+
|
53
|
+
# We need the inner node's ID to generate the error output ID
|
54
|
+
# Long term we want to hoist error_output_id append from inner node displays to this display,
|
55
|
+
# But that's a lot of work and this allows us to punt a little longer
|
56
|
+
serialized_node = super().serialize(
|
49
57
|
display_context,
|
50
|
-
|
58
|
+
adornment=adornment,
|
59
|
+
get_additional_kwargs=lambda node_id: {
|
60
|
+
"error_output_id": self.error_output_id or uuid4_from_hash(f"{node_id}|error_output_id")
|
61
|
+
},
|
51
62
|
)
|
52
63
|
|
64
|
+
if serialized_node["type"] == "GENERIC":
|
65
|
+
return serialized_node
|
66
|
+
|
53
67
|
serialized_node_definition = serialized_node.get("definition")
|
54
68
|
if isinstance(serialized_node_definition, dict):
|
55
69
|
serialized_node_definition_module = serialized_node_definition.get("module")
|
@@ -5,8 +5,10 @@ from vellum.workflows.descriptors.base import BaseDescriptor
|
|
5
5
|
from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
|
6
6
|
from vellum.workflows.nodes.displayable.bases.utils import primitive_to_vellum_value
|
7
7
|
from vellum.workflows.references import NodeReference
|
8
|
+
from vellum.workflows.references.lazy import LazyReference
|
8
9
|
from vellum.workflows.utils.uuids import uuid4_from_hash
|
9
10
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
11
|
+
from vellum_ee.workflows.display.utils.expressions import get_child_descriptor
|
10
12
|
from vellum_ee.workflows.display.utils.vellum import create_node_input_value_pointer_rule
|
11
13
|
from vellum_ee.workflows.display.vellum import (
|
12
14
|
ConstantValuePointer,
|
@@ -56,6 +58,12 @@ def create_node_input_value_pointer_rules(
|
|
56
58
|
raise ValueError(f"Expected NodeReference {value.name} to have an instance")
|
57
59
|
value = cast(BaseDescriptor, value.instance)
|
58
60
|
|
61
|
+
if isinstance(value, LazyReference):
|
62
|
+
child_descriptor = get_child_descriptor(value, display_context)
|
63
|
+
return create_node_input_value_pointer_rules(
|
64
|
+
child_descriptor, display_context, [], pointer_type=pointer_type
|
65
|
+
)
|
66
|
+
|
59
67
|
if isinstance(value, CoalesceExpression):
|
60
68
|
# Recursively handle the left-hand side
|
61
69
|
lhs_rules = create_node_input_value_pointer_rules(value.lhs, display_context, [], pointer_type=pointer_type)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import pytest
|
1
2
|
from uuid import uuid4
|
2
3
|
|
3
4
|
from deepdiff import DeepDiff
|
@@ -11,6 +12,7 @@ from vellum.workflows.workflows.base import BaseWorkflow
|
|
11
12
|
from vellum_ee.workflows.display.base import WorkflowInputsDisplay
|
12
13
|
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
13
14
|
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
15
|
+
from vellum_ee.workflows.display.nodes.vellum.retry_node import BaseRetryNodeDisplay
|
14
16
|
from vellum_ee.workflows.display.nodes.vellum.try_node import BaseTryNodeDisplay
|
15
17
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
16
18
|
from vellum_ee.workflows.display.workflows.vellum_workflow_display import VellumWorkflowDisplay
|
@@ -32,7 +34,7 @@ class InnerRetryGenericNodeDisplay(BaseNodeDisplay[InnerRetryGenericNode.__wrapp
|
|
32
34
|
pass
|
33
35
|
|
34
36
|
|
35
|
-
class OuterRetryNodeDisplay(
|
37
|
+
class OuterRetryNodeDisplay(BaseRetryNodeDisplay[InnerRetryGenericNode]): # type: ignore
|
36
38
|
pass
|
37
39
|
|
38
40
|
|
@@ -213,3 +215,25 @@ def test_serialize_node__try(serialize_node):
|
|
213
215
|
},
|
214
216
|
serialized_node,
|
215
217
|
)
|
218
|
+
|
219
|
+
|
220
|
+
@pytest.mark.skip(reason="Not implemented")
|
221
|
+
def test_serialize_node__stacked():
|
222
|
+
@TryNode.wrap()
|
223
|
+
@RetryNode.wrap(max_attempts=5)
|
224
|
+
class InnerStackedGenericNode(BaseNode):
|
225
|
+
pass
|
226
|
+
|
227
|
+
# AND a workflow that uses the adornment node
|
228
|
+
class StackedWorkflow(BaseWorkflow):
|
229
|
+
graph = InnerStackedGenericNode
|
230
|
+
|
231
|
+
# WHEN we serialize the workflow
|
232
|
+
workflow_display = get_workflow_display(
|
233
|
+
base_display_class=VellumWorkflowDisplay,
|
234
|
+
workflow_class=StackedWorkflow,
|
235
|
+
)
|
236
|
+
exec_config = workflow_display.serialize()
|
237
|
+
|
238
|
+
# THEN the workflow display is created successfully
|
239
|
+
assert exec_config is not None
|
@@ -596,6 +596,20 @@ def test_serialize_workflow__try_wrapped():
|
|
596
596
|
],
|
597
597
|
"name": "TryNode",
|
598
598
|
},
|
599
|
+
"adornments": [
|
600
|
+
{
|
601
|
+
"id": "3344083c-a32c-4a32-920b-0fb5093448fa",
|
602
|
+
"label": "TryNode",
|
603
|
+
"base": {"name": "TryNode", "module": ["vellum", "workflows", "nodes", "core", "try_node", "node"]},
|
604
|
+
"attributes": [
|
605
|
+
{
|
606
|
+
"id": "ab2fbab0-e2a0-419b-b1ef-ce11ecf11e90",
|
607
|
+
"name": "on_error_code",
|
608
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
609
|
+
}
|
610
|
+
],
|
611
|
+
}
|
612
|
+
],
|
599
613
|
}
|
600
614
|
|
601
615
|
final_output_nodes = workflow_raw_data["nodes"][2:]
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
import pytest
|
2
|
+
|
1
3
|
from deepdiff import DeepDiff
|
2
4
|
|
3
5
|
from vellum_ee.workflows.display.workflows import VellumWorkflowDisplay
|
4
6
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
5
7
|
|
6
|
-
from tests.workflows.basic_try_node.workflow import SimpleTryExample
|
8
|
+
from tests.workflows.basic_try_node.workflow import SimpleTryExample, StandaloneTryExample
|
7
9
|
|
8
10
|
|
9
11
|
def test_serialize_workflow():
|
@@ -69,3 +71,19 @@ def test_serialize_workflow():
|
|
69
71
|
|
70
72
|
try_node = workflow_raw_data["nodes"][1]
|
71
73
|
assert try_node["id"] == "1381c078-efa2-4255-89a1-7b4cb742c7fc"
|
74
|
+
|
75
|
+
|
76
|
+
def test_serialize_workflow__standalone():
|
77
|
+
# GIVEN a Workflow with a standalone TryNode
|
78
|
+
# WHEN we serialize it
|
79
|
+
with pytest.raises(NotImplementedError) as exc:
|
80
|
+
workflow_display = get_workflow_display(
|
81
|
+
base_display_class=VellumWorkflowDisplay, workflow_class=StandaloneTryExample
|
82
|
+
)
|
83
|
+
workflow_display.serialize()
|
84
|
+
|
85
|
+
# THEN we should get an error
|
86
|
+
assert (
|
87
|
+
exc.value.args[0]
|
88
|
+
== "Unable to serialize standalone adornment nodes. Please use adornment nodes as a decorator."
|
89
|
+
)
|
File without changes
|
File without changes
|
File without changes
|