vellum-ai 0.13.0__py3-none-any.whl → 0.13.2__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 (53) hide show
  1. vellum/client/core/client_wrapper.py +1 -1
  2. vellum/client/core/pydantic_utilities.py +5 -0
  3. vellum/client/resources/workflows/client.py +8 -0
  4. vellum/client/types/logical_operator.py +2 -0
  5. vellum/workflows/descriptors/base.py +1 -1
  6. vellum/workflows/descriptors/tests/test_utils.py +3 -0
  7. vellum/workflows/expressions/accessor.py +8 -2
  8. vellum/workflows/nodes/core/map_node/node.py +49 -24
  9. vellum/workflows/nodes/core/map_node/tests/test_node.py +4 -4
  10. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +1 -1
  11. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +5 -3
  12. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +3 -0
  13. vellum/workflows/nodes/displayable/bases/search_node.py +37 -2
  14. vellum/workflows/nodes/displayable/bases/tests/__init__.py +0 -0
  15. vellum/workflows/nodes/displayable/bases/tests/test_utils.py +61 -0
  16. vellum/workflows/nodes/displayable/bases/types.py +42 -0
  17. vellum/workflows/nodes/displayable/bases/utils.py +112 -0
  18. vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py +0 -1
  19. vellum/workflows/nodes/displayable/search_node/tests/__init__.py +0 -0
  20. vellum/workflows/nodes/displayable/search_node/tests/test_node.py +164 -0
  21. vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +2 -3
  22. vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +0 -1
  23. vellum/workflows/runner/runner.py +37 -4
  24. vellum/workflows/types/tests/test_utils.py +5 -2
  25. vellum/workflows/types/utils.py +4 -0
  26. vellum/workflows/workflows/base.py +14 -0
  27. {vellum_ai-0.13.0.dist-info → vellum_ai-0.13.2.dist-info}/METADATA +1 -1
  28. {vellum_ai-0.13.0.dist-info → vellum_ai-0.13.2.dist-info}/RECORD +53 -42
  29. vellum_cli/__init__.py +24 -0
  30. vellum_cli/ping.py +28 -0
  31. vellum_cli/push.py +62 -12
  32. vellum_cli/tests/test_ping.py +47 -0
  33. vellum_cli/tests/test_push.py +76 -0
  34. vellum_ee/workflows/display/nodes/vellum/base_node.py +59 -11
  35. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +3 -0
  36. vellum_ee/workflows/display/nodes/vellum/map_node.py +1 -1
  37. vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +14 -10
  38. vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +2 -2
  39. vellum_ee/workflows/display/nodes/vellum/utils.py +8 -1
  40. vellum_ee/workflows/display/tests/test_vellum_workflow_display.py +48 -0
  41. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +67 -0
  42. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +286 -0
  43. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +177 -0
  44. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +666 -14
  45. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py +7 -8
  46. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +35 -2
  47. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +29 -2
  48. vellum_ee/workflows/display/utils/vellum.py +4 -42
  49. vellum_ee/workflows/display/vellum.py +7 -36
  50. vellum_ee/workflows/display/workflows/vellum_workflow_display.py +5 -2
  51. {vellum_ai-0.13.0.dist-info → vellum_ai-0.13.2.dist-info}/LICENSE +0 -0
  52. {vellum_ai-0.13.0.dist-info → vellum_ai-0.13.2.dist-info}/WHEEL +0 -0
  53. {vellum_ai-0.13.0.dist-info → vellum_ai-0.13.2.dist-info}/entry_points.txt +0 -0
@@ -1,12 +1,11 @@
1
- from typing import Any, Generic, TypeVar
1
+ from typing import Any, Generic, TypeVar, cast
2
2
 
3
+ from vellum.workflows.constants import UNDEF
3
4
  from vellum.workflows.descriptors.base import BaseDescriptor
4
- from vellum.workflows.expressions.and_ import AndExpression
5
5
  from vellum.workflows.expressions.between import BetweenExpression
6
6
  from vellum.workflows.expressions.is_not_null import IsNotNullExpression
7
7
  from vellum.workflows.expressions.is_null import IsNullExpression
8
8
  from vellum.workflows.expressions.not_between import NotBetweenExpression
9
- from vellum.workflows.expressions.or_ import OrExpression
10
9
  from vellum.workflows.nodes.bases.base import BaseNode
11
10
  from vellum.workflows.references.execution_count import ExecutionCountReference
12
11
  from vellum.workflows.references.output import OutputReference
@@ -14,6 +13,7 @@ from vellum.workflows.references.vellum_secret import VellumSecretReference
14
13
  from vellum.workflows.references.workflow_input import WorkflowInputReference
15
14
  from vellum.workflows.types.core import JsonArray, JsonObject
16
15
  from vellum.workflows.utils.uuids import uuid4_from_hash
16
+ from vellum.workflows.utils.vellum_variables import primitive_type_to_vellum_variable_type
17
17
  from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
18
18
  from vellum_ee.workflows.display.nodes.vellum.utils import convert_descriptor_to_operator
19
19
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
@@ -28,6 +28,18 @@ class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeTyp
28
28
  node = self._node
29
29
  node_id = self.node_id
30
30
 
31
+ attributes: JsonArray = []
32
+ for attribute in node:
33
+ id = str(uuid4_from_hash(f"{node_id}|{attribute.name}"))
34
+
35
+ attributes.append(
36
+ {
37
+ "id": id,
38
+ "name": attribute.name,
39
+ "value": self.serialize_value(display_context, cast(BaseDescriptor, attribute.instance)),
40
+ }
41
+ )
42
+
31
43
  ports: JsonArray = []
32
44
  for idx, port in enumerate(node.Ports):
33
45
  id = str(uuid4_from_hash(f"{node_id}|{idx}"))
@@ -36,6 +48,7 @@ class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeTyp
36
48
  ports.append(
37
49
  {
38
50
  "id": id,
51
+ "name": port.name,
39
52
  "type": port._condition_type.value,
40
53
  "expression": (
41
54
  self.serialize_condition(display_context, port._condition) if port._condition else None
@@ -46,10 +59,29 @@ class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeTyp
46
59
  ports.append(
47
60
  {
48
61
  "id": id,
62
+ "name": port.name,
49
63
  "type": "DEFAULT",
50
64
  }
51
65
  )
52
66
 
67
+ outputs: JsonArray = []
68
+ for output in node.Outputs:
69
+ type = primitive_type_to_vellum_variable_type(output)
70
+ value = (
71
+ self.serialize_value(display_context, output.instance)
72
+ if output.instance is not None and output.instance != UNDEF
73
+ else None
74
+ )
75
+
76
+ outputs.append(
77
+ {
78
+ "id": str(uuid4_from_hash(f"{node_id}|{output.name}")),
79
+ "name": output.name,
80
+ "type": type,
81
+ "value": value,
82
+ }
83
+ )
84
+
53
85
  return {
54
86
  "id": str(node_id),
55
87
  "label": node.__qualname__,
@@ -63,7 +95,8 @@ class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeTyp
63
95
  },
64
96
  "ports": ports,
65
97
  "adornments": None,
66
- "attributes": [],
98
+ "attributes": attributes,
99
+ "outputs": outputs,
67
100
  }
68
101
 
69
102
  def get_generic_node_display_data(self) -> GenericNodeDisplayData:
@@ -71,12 +104,25 @@ class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeTyp
71
104
  return explicit_value if explicit_value else GenericNodeDisplayData()
72
105
 
73
106
  def serialize_condition(self, display_context: WorkflowDisplayContext, condition: BaseDescriptor) -> JsonObject:
74
- if isinstance(condition, (AndExpression, OrExpression)):
75
- return {}
76
- elif isinstance(condition, (IsNullExpression, IsNotNullExpression)):
77
- return {}
107
+ if isinstance(condition, (IsNullExpression, IsNotNullExpression)):
108
+ lhs = self.serialize_value(display_context, condition._expression) # type: ignore[attr-defined]
109
+ return {
110
+ "type": "UNARY_EXPRESSION",
111
+ "lhs": lhs,
112
+ "operator": convert_descriptor_to_operator(condition),
113
+ }
78
114
  elif isinstance(condition, (BetweenExpression, NotBetweenExpression)):
79
- return {}
115
+ base = self.serialize_value(display_context, condition._value) # type: ignore[attr-defined]
116
+ lhs = self.serialize_value(display_context, condition._start) # type: ignore[attr-defined]
117
+ rhs = self.serialize_value(display_context, condition._end) # type: ignore[attr-defined]
118
+
119
+ return {
120
+ "type": "TERNARY_EXPRESSION",
121
+ "base": base,
122
+ "operator": convert_descriptor_to_operator(condition),
123
+ "lhs": lhs,
124
+ "rhs": rhs,
125
+ }
80
126
  else:
81
127
  lhs = self.serialize_value(display_context, condition._lhs) # type: ignore[attr-defined]
82
128
  rhs = self.serialize_value(display_context, condition._rhs) # type: ignore[attr-defined]
@@ -113,7 +159,7 @@ class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeTyp
113
159
  }
114
160
 
115
161
  if isinstance(value, ExecutionCountReference):
116
- node_class_display = display_context.node_displays[value.node_class]
162
+ node_class_display = display_context.global_node_displays[value.node_class]
117
163
 
118
164
  return {
119
165
  "type": "EXECUTION_COUNTER",
@@ -127,4 +173,6 @@ class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeTyp
127
173
  "value": vellum_value.dict(),
128
174
  }
129
175
 
130
- raise ValueError(f"Unsupported descriptor type: {value.__class__.__name__}")
176
+ # If it's not any of the references we know about,
177
+ # then try to serialize it as a nested value
178
+ return self.serialize_condition(display_context, value)
@@ -74,6 +74,9 @@ class BaseInlinePromptNodeDisplay(BaseNodeVellumDisplay[_InlinePromptNodeType],
74
74
  node_inputs: List[NodeInput] = []
75
75
  prompt_inputs: List[VellumVariable] = []
76
76
 
77
+ if not value:
78
+ return node_inputs, prompt_inputs
79
+
77
80
  for variable_name, variable_value in value.items():
78
81
  node_input = create_node_input(
79
82
  node_id=node_id,
@@ -69,7 +69,7 @@ class BaseMapNodeDisplay(BaseNodeVellumDisplay[_MapNodeType], Generic[_MapNodeTy
69
69
  "workflow_raw_data": serialized_subworkflow["workflow_raw_data"],
70
70
  "input_variables": cast(JsonObject, renamed_input_variables),
71
71
  "output_variables": serialized_subworkflow["output_variables"],
72
- "concurrency": raise_if_descriptor(node.concurrency),
72
+ "concurrency": raise_if_descriptor(node.max_concurrency),
73
73
  "items_input_id": items_workflow_input_id,
74
74
  "item_input_id": item_workflow_input_id,
75
75
  "index_input_id": index_workflow_input_id,
@@ -27,16 +27,20 @@ class BasePromptDeploymentNodeDisplay(
27
27
  node_id = self.node_id
28
28
 
29
29
  prompt_inputs = raise_if_descriptor(node.prompt_inputs)
30
- node_inputs = [
31
- create_node_input(
32
- node_id=node_id,
33
- input_name=variable_name,
34
- value=variable_value,
35
- display_context=display_context,
36
- input_id=self.prompt_input_ids_by_name.get(variable_name),
37
- )
38
- for variable_name, variable_value in prompt_inputs.items()
39
- ]
30
+ node_inputs = (
31
+ [
32
+ create_node_input(
33
+ node_id=node_id,
34
+ input_name=variable_name,
35
+ value=variable_value,
36
+ display_context=display_context,
37
+ input_id=self.prompt_input_ids_by_name.get(variable_name),
38
+ )
39
+ for variable_name, variable_value in prompt_inputs.items()
40
+ ]
41
+ if prompt_inputs
42
+ else []
43
+ )
40
44
 
41
45
  _, output_display = display_context.global_node_output_displays[cast(OutputReference, node.Outputs.text)]
42
46
  _, array_display = display_context.global_node_output_displays[cast(OutputReference, node.Outputs.results)]
@@ -2,6 +2,7 @@ import pytest
2
2
  from uuid import UUID, uuid4
3
3
  from typing import List, cast
4
4
 
5
+ from vellum.client.types.string_vellum_value import StringVellumValue
5
6
  from vellum.workflows.descriptors.base import BaseDescriptor
6
7
  from vellum.workflows.inputs import BaseInputs
7
8
  from vellum.workflows.nodes.bases import BaseNode
@@ -19,7 +20,6 @@ from vellum_ee.workflows.display.vellum import (
19
20
  NodeInputValuePointerRule,
20
21
  NodeOutputData,
21
22
  NodeOutputPointer,
22
- StringVellumValue,
23
23
  WorkflowInputsVellumDisplayOverrides,
24
24
  WorkflowMetaVellumDisplay,
25
25
  )
@@ -74,7 +74,7 @@ class MyNodeB(BaseNode):
74
74
  type="INPUT_VARIABLE",
75
75
  data=InputVariableData(input_variable_id="a154c29d-fac0-4cd0-ba88-bc52034f5470"),
76
76
  ),
77
- ConstantValuePointer(type="CONSTANT_VALUE", data=StringVellumValue(type="STRING", value="fallback")),
77
+ ConstantValuePointer(type="CONSTANT_VALUE", data=StringVellumValue(value="fallback")),
78
78
  ],
79
79
  ),
80
80
  ],
@@ -2,6 +2,7 @@ from uuid import UUID
2
2
  from typing import Any, List, Optional, Type, Union, cast
3
3
 
4
4
  from vellum.workflows.descriptors.base import BaseDescriptor
5
+ from vellum.workflows.expressions.and_ import AndExpression
5
6
  from vellum.workflows.expressions.begins_with import BeginsWithExpression
6
7
  from vellum.workflows.expressions.between import BetweenExpression
7
8
  from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
@@ -25,11 +26,13 @@ from vellum.workflows.expressions.less_than import LessThanExpression
25
26
  from vellum.workflows.expressions.less_than_or_equal_to import LessThanOrEqualToExpression
26
27
  from vellum.workflows.expressions.not_between import NotBetweenExpression
27
28
  from vellum.workflows.expressions.not_in import NotInExpression
29
+ from vellum.workflows.expressions.or_ import OrExpression
30
+ from vellum.workflows.nodes.displayable.bases.utils import primitive_to_vellum_value
28
31
  from vellum.workflows.nodes.utils import get_wrapped_node, has_wrapped_node
29
32
  from vellum.workflows.references import NodeReference, OutputReference
30
33
  from vellum.workflows.utils.uuids import uuid4_from_hash
31
34
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
32
- from vellum_ee.workflows.display.utils.vellum import create_node_input_value_pointer_rule, primitive_to_vellum_value
35
+ from vellum_ee.workflows.display.utils.vellum import create_node_input_value_pointer_rule
33
36
  from vellum_ee.workflows.display.vellum import (
34
37
  ConstantValuePointer,
35
38
  ExecutionCounterData,
@@ -170,5 +173,9 @@ def convert_descriptor_to_operator(descriptor: BaseDescriptor) -> str:
170
173
  return "between"
171
174
  elif isinstance(descriptor, NotBetweenExpression):
172
175
  return "notBetween"
176
+ elif isinstance(descriptor, AndExpression):
177
+ return "and"
178
+ elif isinstance(descriptor, OrExpression):
179
+ return "or"
173
180
  else:
174
181
  raise ValueError(f"Unsupported descriptor type: {descriptor}")
@@ -1,4 +1,10 @@
1
+ from uuid import UUID
2
+
3
+ from vellum.workflows.inputs import BaseInputs
4
+ from vellum.workflows.nodes import BaseNode
5
+ from vellum.workflows.state import BaseState
1
6
  from vellum.workflows.workflows.base import BaseWorkflow
7
+ from vellum_ee.workflows.display.vellum import WorkflowInputsVellumDisplayOverrides
2
8
  from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
3
9
  from vellum_ee.workflows.display.workflows.vellum_workflow_display import VellumWorkflowDisplay
4
10
 
@@ -40,3 +46,45 @@ def test_vellum_workflow_display__serialize_empty_workflow():
40
46
  ],
41
47
  },
42
48
  }
49
+
50
+
51
+ def test_vellum_workflow_display__serialize_input_variables_with_capitalized_variable_override():
52
+ # GIVEN a workflow with input variables
53
+ class Inputs(BaseInputs):
54
+ foo: str
55
+
56
+ class StartNode(BaseNode):
57
+ class Outputs(BaseNode.Outputs):
58
+ output = Inputs.foo
59
+
60
+ class ExampleWorkflow(BaseWorkflow[Inputs, BaseState]):
61
+ graph = StartNode
62
+
63
+ class ExampleWorkflowDisplay(VellumWorkflowDisplay[ExampleWorkflow]):
64
+ inputs_display = {
65
+ Inputs.foo: WorkflowInputsVellumDisplayOverrides(
66
+ id=UUID("97b63d71-5413-417f-9cf5-49e1b4fd56e4"), name="Foo", required=True
67
+ )
68
+ }
69
+
70
+ display = get_workflow_display(
71
+ base_display_class=ExampleWorkflowDisplay,
72
+ workflow_class=ExampleWorkflow,
73
+ )
74
+
75
+ # WHEN serializing the workflow
76
+ exec_config = display.serialize()
77
+
78
+ # THEN the input variables are what we expect
79
+ input_variables = exec_config["input_variables"]
80
+
81
+ assert input_variables == [
82
+ {
83
+ "id": "97b63d71-5413-417f-9cf5-49e1b4fd56e4",
84
+ "key": "Foo",
85
+ "type": "STRING",
86
+ "default": None,
87
+ "required": True,
88
+ "extensions": {"color": None},
89
+ }
90
+ ]
@@ -0,0 +1,67 @@
1
+ import pytest
2
+
3
+ from deepdiff import DeepDiff
4
+
5
+ from vellum.workflows.inputs.base import BaseInputs
6
+ from vellum.workflows.nodes.bases.base import BaseNode
7
+ from vellum.workflows.nodes.core.map_node.node import MapNode
8
+ from vellum.workflows.outputs.base import BaseOutputs
9
+ from vellum.workflows.state.base import BaseState
10
+
11
+
12
+ class Inputs(BaseInputs):
13
+ foo: str
14
+
15
+
16
+ class State(BaseState):
17
+ bar: str
18
+
19
+
20
+ @MapNode.wrap(items=[1, 2, 3])
21
+ class MapGenericNode(BaseNode):
22
+ item = MapNode.SubworkflowInputs.item
23
+ foo = Inputs.foo
24
+ bar = State.bar
25
+
26
+ class Outputs(BaseOutputs):
27
+ value: str
28
+
29
+ def run(self) -> Outputs:
30
+ return self.Outputs(value=f"{self.foo} {self.bar} {self.item}")
31
+
32
+
33
+ @pytest.mark.skip(reason="not implemented")
34
+ def test_serialize_node__try(serialize_node):
35
+ serialized_node = serialize_node(MapGenericNode)
36
+ assert not DeepDiff(
37
+ {
38
+ "id": "c2ed23f7-f6cb-4a56-a91c-2e5f9d8fda7f",
39
+ "label": "BasicGenericNode",
40
+ "type": "GENERIC",
41
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
42
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
43
+ "definition": {
44
+ "name": "BasicGenericNode",
45
+ "module": [
46
+ "vellum_ee",
47
+ "workflows",
48
+ "display",
49
+ "tests",
50
+ "workflow_serialization",
51
+ "generic_nodes",
52
+ "test_adornments_serialization",
53
+ ],
54
+ },
55
+ "trigger": {"id": "9d3a1b3d-4a38-4f2e-bbf1-dd8be152bce8", "merge_behavior": "AWAIT_ANY"},
56
+ "ports": [
57
+ {
58
+ "id": "4fbf0fff-a42e-4410-852a-238b5059198e",
59
+ "type": "DEFAULT",
60
+ }
61
+ ],
62
+ "adornments": None,
63
+ "attributes": [],
64
+ },
65
+ serialized_node,
66
+ ignore_order=True,
67
+ )
@@ -0,0 +1,286 @@
1
+ from uuid import uuid4
2
+
3
+ from deepdiff import DeepDiff
4
+
5
+ from vellum.workflows.inputs.base import BaseInputs
6
+ from vellum.workflows.nodes.bases.base import BaseNode
7
+ from vellum.workflows.references.vellum_secret import VellumSecretReference
8
+ from vellum_ee.workflows.display.base import WorkflowInputsDisplay
9
+ from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
10
+ from vellum_ee.workflows.display.nodes.vellum.base_node import BaseNodeDisplay
11
+
12
+
13
+ class Inputs(BaseInputs):
14
+ input: str
15
+
16
+
17
+ class ConstantValueGenericNode(BaseNode):
18
+ attr: str = "hello"
19
+
20
+
21
+ def test_serialize_node__constant_value(serialize_node):
22
+ input_id = uuid4()
23
+ serialized_node = serialize_node(
24
+ node_class=ConstantValueGenericNode,
25
+ global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=input_id)},
26
+ )
27
+
28
+ assert not DeepDiff(
29
+ {
30
+ "id": "be892bc8-e4de-47ef-ab89-dc9d869af1fe",
31
+ "label": "ConstantValueGenericNode",
32
+ "type": "GENERIC",
33
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
34
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
35
+ "definition": {
36
+ "name": "ConstantValueGenericNode",
37
+ "module": [
38
+ "vellum_ee",
39
+ "workflows",
40
+ "display",
41
+ "tests",
42
+ "workflow_serialization",
43
+ "generic_nodes",
44
+ "test_attributes_serialization",
45
+ ],
46
+ },
47
+ "trigger": {"id": "279e8228-9b82-43a3-8c31-affc036e3a0b", "merge_behavior": "AWAIT_ANY"},
48
+ "ports": [{"id": "e6cf13b0-5590-421c-84f2-5a0b169677e1", "type": "DEFAULT", "name": "default"}],
49
+ "adornments": None,
50
+ "attributes": [
51
+ {
52
+ "id": "4cbbfd98-9ab6-41a8-bf4e-ae65f0eafe47",
53
+ "name": "attr",
54
+ "value": {
55
+ "type": "CONSTANT_VALUE",
56
+ "value": {
57
+ "type": "STRING",
58
+ "value": "hello",
59
+ },
60
+ },
61
+ }
62
+ ],
63
+ "outputs": [],
64
+ },
65
+ serialized_node,
66
+ ignore_order=True,
67
+ )
68
+
69
+
70
+ class WorkflowInputGenericNode(BaseNode):
71
+ attr: str = Inputs.input
72
+
73
+
74
+ def test_serialize_node__workflow_input(serialize_node):
75
+ input_id = uuid4()
76
+ serialized_node = serialize_node(
77
+ node_class=WorkflowInputGenericNode,
78
+ global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=input_id)},
79
+ )
80
+ assert not DeepDiff(
81
+ {
82
+ "id": "ddfa947f-0830-476b-b07e-ac573968f9a7",
83
+ "label": "WorkflowInputGenericNode",
84
+ "type": "GENERIC",
85
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
86
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
87
+ "definition": {
88
+ "name": "WorkflowInputGenericNode",
89
+ "module": [
90
+ "vellum_ee",
91
+ "workflows",
92
+ "display",
93
+ "tests",
94
+ "workflow_serialization",
95
+ "generic_nodes",
96
+ "test_attributes_serialization",
97
+ ],
98
+ },
99
+ "trigger": {"id": "b1a5d749-bac0-4f11-8427-191febb2198e", "merge_behavior": "AWAIT_ANY"},
100
+ "ports": [{"id": "f013bf3f-49f6-41cd-ac13-7439b71a304a", "type": "DEFAULT", "name": "default"}],
101
+ "adornments": None,
102
+ "attributes": [
103
+ {
104
+ "id": "56d44313-cfdd-4d75-9b19-0beb94e59c4e",
105
+ "name": "attr",
106
+ "value": {
107
+ "type": "WORKFLOW_INPUT",
108
+ "input_variable_id": str(input_id),
109
+ },
110
+ }
111
+ ],
112
+ "outputs": [],
113
+ },
114
+ serialized_node,
115
+ ignore_order=True,
116
+ )
117
+
118
+
119
+ class NodeWithOutput(BaseNode):
120
+ class Outputs(BaseNode.Outputs):
121
+ output = Inputs.input
122
+
123
+
124
+ class NodeWithOutputDisplay(BaseNodeDisplay[NodeWithOutput]):
125
+ pass
126
+
127
+
128
+ class GenericNodeReferencingOutput(BaseNode):
129
+ attr = NodeWithOutput.Outputs.output
130
+
131
+
132
+ def test_serialize_node__node_output(serialize_node):
133
+ workflow_input_id = uuid4()
134
+ node_output_id = uuid4()
135
+ serialized_node = serialize_node(
136
+ node_class=GenericNodeReferencingOutput,
137
+ global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=workflow_input_id)},
138
+ global_node_displays={NodeWithOutput: NodeWithOutputDisplay()},
139
+ global_node_output_displays={
140
+ NodeWithOutput.Outputs.output: (NodeWithOutput, NodeOutputDisplay(id=node_output_id, name="output"))
141
+ },
142
+ )
143
+
144
+ assert not DeepDiff(
145
+ {
146
+ "id": "c1e2ce60-ac3a-4b17-915e-abe861734e03",
147
+ "label": "GenericNodeReferencingOutput",
148
+ "type": "GENERIC",
149
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
150
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
151
+ "definition": {
152
+ "name": "GenericNodeReferencingOutput",
153
+ "module": [
154
+ "vellum_ee",
155
+ "workflows",
156
+ "display",
157
+ "tests",
158
+ "workflow_serialization",
159
+ "generic_nodes",
160
+ "test_attributes_serialization",
161
+ ],
162
+ },
163
+ "trigger": {"id": "449072ba-f7b6-4314-ac96-682123f225e5", "merge_behavior": "AWAIT_ANY"},
164
+ "ports": [{"id": "ec9a79b8-65c3-4de8-bd29-42c914d72d4f", "type": "DEFAULT", "name": "default"}],
165
+ "adornments": None,
166
+ "attributes": [
167
+ {
168
+ "id": "73e6a103-1339-41ec-a245-42d43b0637c1",
169
+ "name": "attr",
170
+ "value": {
171
+ "type": "NODE_OUTPUT",
172
+ "node_id": "cd954d76-0b0a-4d9b-9bdf-347179c38cb6",
173
+ "node_output_id": str(node_output_id),
174
+ },
175
+ }
176
+ ],
177
+ "outputs": [],
178
+ },
179
+ serialized_node,
180
+ ignore_order=True,
181
+ )
182
+
183
+
184
+ class VellumSecretGenericNode(BaseNode):
185
+ attr = VellumSecretReference(name="hello")
186
+
187
+
188
+ def test_serialize_node__vellum_secret(serialize_node):
189
+ input_id = uuid4()
190
+ serialized_node = serialize_node(
191
+ node_class=VellumSecretGenericNode,
192
+ global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=input_id)},
193
+ )
194
+ assert not DeepDiff(
195
+ {
196
+ "id": "89aa6faa-b533-4179-8912-70a048bf0712",
197
+ "label": "VellumSecretGenericNode",
198
+ "type": "GENERIC",
199
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
200
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
201
+ "definition": {
202
+ "name": "VellumSecretGenericNode",
203
+ "module": [
204
+ "vellum_ee",
205
+ "workflows",
206
+ "display",
207
+ "tests",
208
+ "workflow_serialization",
209
+ "generic_nodes",
210
+ "test_attributes_serialization",
211
+ ],
212
+ },
213
+ "trigger": {"id": "3ea0305d-d8ea-45fe-8cf1-f6c1c85e6979", "merge_behavior": "AWAIT_ANY"},
214
+ "ports": [{"id": "69e49322-8f8a-42d2-b36f-3fbe53dad616", "type": "DEFAULT", "name": "default"}],
215
+ "adornments": None,
216
+ "attributes": [
217
+ {
218
+ "id": "8edd27da-eec1-4539-8bec-629b5ef7a9f9",
219
+ "name": "attr",
220
+ "value": {"type": "VELLUM_SECRET", "vellum_secret_name": "hello"},
221
+ }
222
+ ],
223
+ "outputs": [],
224
+ },
225
+ serialized_node,
226
+ ignore_order=True,
227
+ )
228
+
229
+
230
+ class NodeWithExecutions(BaseNode):
231
+ pass
232
+
233
+
234
+ class NodeWithExecutionsDisplay(BaseNodeDisplay[NodeWithExecutions]):
235
+ pass
236
+
237
+
238
+ class GenericNodeReferencingExecutions(BaseNode):
239
+ attr: int = NodeWithExecutions.Execution.count
240
+
241
+
242
+ def test_serialize_node__node_execution(serialize_node):
243
+ workflow_input_id = uuid4()
244
+ serialized_node = serialize_node(
245
+ node_class=GenericNodeReferencingExecutions,
246
+ global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=workflow_input_id)},
247
+ global_node_displays={NodeWithExecutions: NodeWithExecutionsDisplay()},
248
+ )
249
+
250
+ assert not DeepDiff(
251
+ {
252
+ "id": "6e4d2fb7-891e-492e-97a1-adf44693f518",
253
+ "label": "GenericNodeReferencingExecutions",
254
+ "type": "GENERIC",
255
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
256
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
257
+ "definition": {
258
+ "name": "GenericNodeReferencingExecutions",
259
+ "module": [
260
+ "vellum_ee",
261
+ "workflows",
262
+ "display",
263
+ "tests",
264
+ "workflow_serialization",
265
+ "generic_nodes",
266
+ "test_attributes_serialization",
267
+ ],
268
+ },
269
+ "trigger": {"id": "68a91426-4c30-4194-a4c0-cff224d3c0f3", "merge_behavior": "AWAIT_ANY"},
270
+ "ports": [{"id": "1794c2eb-5cab-49fe-9354-dfc29f11b374", "type": "DEFAULT", "name": "default"}],
271
+ "adornments": None,
272
+ "attributes": [
273
+ {
274
+ "id": "090e18d7-d5b9-4d5f-9aec-0f562e4b33a8",
275
+ "name": "attr",
276
+ "value": {
277
+ "type": "EXECUTION_COUNTER",
278
+ "node_id": "c09bd5a6-dc04-4036-90d4-580acd43c71f",
279
+ },
280
+ }
281
+ ],
282
+ "outputs": [],
283
+ },
284
+ serialized_node,
285
+ ignore_order=True,
286
+ )