vellum-ai 0.13.0__py3-none-any.whl → 0.13.2__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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
+ )