vellum-ai 0.9.16rc2__py3-none-any.whl → 0.10.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (245) hide show
  1. vellum/plugins/__init__.py +0 -0
  2. vellum/plugins/pydantic.py +74 -0
  3. vellum/plugins/utils.py +19 -0
  4. vellum/plugins/vellum_mypy.py +639 -3
  5. vellum/workflows/README.md +90 -0
  6. vellum/workflows/__init__.py +5 -0
  7. vellum/workflows/constants.py +43 -0
  8. vellum/workflows/descriptors/__init__.py +0 -0
  9. vellum/workflows/descriptors/base.py +339 -0
  10. vellum/workflows/descriptors/tests/test_utils.py +83 -0
  11. vellum/workflows/descriptors/utils.py +90 -0
  12. vellum/workflows/edges/__init__.py +5 -0
  13. vellum/workflows/edges/edge.py +23 -0
  14. vellum/workflows/emitters/__init__.py +5 -0
  15. vellum/workflows/emitters/base.py +14 -0
  16. vellum/workflows/environment/__init__.py +5 -0
  17. vellum/workflows/environment/environment.py +7 -0
  18. vellum/workflows/errors/__init__.py +6 -0
  19. vellum/workflows/errors/types.py +20 -0
  20. vellum/workflows/events/__init__.py +31 -0
  21. vellum/workflows/events/node.py +125 -0
  22. vellum/workflows/events/tests/__init__.py +0 -0
  23. vellum/workflows/events/tests/test_event.py +216 -0
  24. vellum/workflows/events/types.py +52 -0
  25. vellum/workflows/events/utils.py +5 -0
  26. vellum/workflows/events/workflow.py +139 -0
  27. vellum/workflows/exceptions.py +15 -0
  28. vellum/workflows/expressions/__init__.py +0 -0
  29. vellum/workflows/expressions/accessor.py +52 -0
  30. vellum/workflows/expressions/and_.py +32 -0
  31. vellum/workflows/expressions/begins_with.py +31 -0
  32. vellum/workflows/expressions/between.py +38 -0
  33. vellum/workflows/expressions/coalesce_expression.py +41 -0
  34. vellum/workflows/expressions/contains.py +30 -0
  35. vellum/workflows/expressions/does_not_begin_with.py +31 -0
  36. vellum/workflows/expressions/does_not_contain.py +30 -0
  37. vellum/workflows/expressions/does_not_end_with.py +31 -0
  38. vellum/workflows/expressions/does_not_equal.py +25 -0
  39. vellum/workflows/expressions/ends_with.py +31 -0
  40. vellum/workflows/expressions/equals.py +25 -0
  41. vellum/workflows/expressions/greater_than.py +33 -0
  42. vellum/workflows/expressions/greater_than_or_equal_to.py +33 -0
  43. vellum/workflows/expressions/in_.py +31 -0
  44. vellum/workflows/expressions/is_blank.py +24 -0
  45. vellum/workflows/expressions/is_not_blank.py +24 -0
  46. vellum/workflows/expressions/is_not_null.py +21 -0
  47. vellum/workflows/expressions/is_not_undefined.py +22 -0
  48. vellum/workflows/expressions/is_null.py +21 -0
  49. vellum/workflows/expressions/is_undefined.py +22 -0
  50. vellum/workflows/expressions/less_than.py +33 -0
  51. vellum/workflows/expressions/less_than_or_equal_to.py +33 -0
  52. vellum/workflows/expressions/not_between.py +38 -0
  53. vellum/workflows/expressions/not_in.py +31 -0
  54. vellum/workflows/expressions/or_.py +32 -0
  55. vellum/workflows/graph/__init__.py +3 -0
  56. vellum/workflows/graph/graph.py +131 -0
  57. vellum/workflows/graph/tests/__init__.py +0 -0
  58. vellum/workflows/graph/tests/test_graph.py +437 -0
  59. vellum/workflows/inputs/__init__.py +5 -0
  60. vellum/workflows/inputs/base.py +55 -0
  61. vellum/workflows/logging.py +14 -0
  62. vellum/workflows/nodes/__init__.py +46 -0
  63. vellum/workflows/nodes/bases/__init__.py +7 -0
  64. vellum/workflows/nodes/bases/base.py +332 -0
  65. vellum/workflows/nodes/bases/base_subworkflow_node/__init__.py +5 -0
  66. vellum/workflows/nodes/bases/base_subworkflow_node/node.py +10 -0
  67. vellum/workflows/nodes/bases/tests/__init__.py +0 -0
  68. vellum/workflows/nodes/bases/tests/test_base_node.py +125 -0
  69. vellum/workflows/nodes/core/__init__.py +16 -0
  70. vellum/workflows/nodes/core/error_node/__init__.py +5 -0
  71. vellum/workflows/nodes/core/error_node/node.py +26 -0
  72. vellum/workflows/nodes/core/inline_subworkflow_node/__init__.py +5 -0
  73. vellum/workflows/nodes/core/inline_subworkflow_node/node.py +73 -0
  74. vellum/workflows/nodes/core/map_node/__init__.py +5 -0
  75. vellum/workflows/nodes/core/map_node/node.py +147 -0
  76. vellum/workflows/nodes/core/map_node/tests/__init__.py +0 -0
  77. vellum/workflows/nodes/core/map_node/tests/test_node.py +65 -0
  78. vellum/workflows/nodes/core/retry_node/__init__.py +5 -0
  79. vellum/workflows/nodes/core/retry_node/node.py +106 -0
  80. vellum/workflows/nodes/core/retry_node/tests/__init__.py +0 -0
  81. vellum/workflows/nodes/core/retry_node/tests/test_node.py +93 -0
  82. vellum/workflows/nodes/core/templating_node/__init__.py +5 -0
  83. vellum/workflows/nodes/core/templating_node/custom_filters.py +12 -0
  84. vellum/workflows/nodes/core/templating_node/exceptions.py +2 -0
  85. vellum/workflows/nodes/core/templating_node/node.py +123 -0
  86. vellum/workflows/nodes/core/templating_node/render.py +55 -0
  87. vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py +21 -0
  88. vellum/workflows/nodes/core/try_node/__init__.py +5 -0
  89. vellum/workflows/nodes/core/try_node/node.py +110 -0
  90. vellum/workflows/nodes/core/try_node/tests/__init__.py +0 -0
  91. vellum/workflows/nodes/core/try_node/tests/test_node.py +82 -0
  92. vellum/workflows/nodes/displayable/__init__.py +31 -0
  93. vellum/workflows/nodes/displayable/api_node/__init__.py +5 -0
  94. vellum/workflows/nodes/displayable/api_node/node.py +44 -0
  95. vellum/workflows/nodes/displayable/bases/__init__.py +11 -0
  96. vellum/workflows/nodes/displayable/bases/api_node/__init__.py +5 -0
  97. vellum/workflows/nodes/displayable/bases/api_node/node.py +70 -0
  98. vellum/workflows/nodes/displayable/bases/base_prompt_node/__init__.py +5 -0
  99. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +60 -0
  100. vellum/workflows/nodes/displayable/bases/inline_prompt_node/__init__.py +5 -0
  101. vellum/workflows/nodes/displayable/bases/inline_prompt_node/constants.py +13 -0
  102. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +118 -0
  103. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +98 -0
  104. vellum/workflows/nodes/displayable/bases/search_node.py +90 -0
  105. vellum/workflows/nodes/displayable/code_execution_node/__init__.py +5 -0
  106. vellum/workflows/nodes/displayable/code_execution_node/node.py +197 -0
  107. vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py +0 -0
  108. vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py +0 -0
  109. vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py +3 -0
  110. vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +111 -0
  111. vellum/workflows/nodes/displayable/code_execution_node/utils.py +10 -0
  112. vellum/workflows/nodes/displayable/conditional_node/__init__.py +5 -0
  113. vellum/workflows/nodes/displayable/conditional_node/node.py +25 -0
  114. vellum/workflows/nodes/displayable/final_output_node/__init__.py +5 -0
  115. vellum/workflows/nodes/displayable/final_output_node/node.py +43 -0
  116. vellum/workflows/nodes/displayable/guardrail_node/__init__.py +5 -0
  117. vellum/workflows/nodes/displayable/guardrail_node/node.py +97 -0
  118. vellum/workflows/nodes/displayable/inline_prompt_node/__init__.py +5 -0
  119. vellum/workflows/nodes/displayable/inline_prompt_node/node.py +41 -0
  120. vellum/workflows/nodes/displayable/merge_node/__init__.py +5 -0
  121. vellum/workflows/nodes/displayable/merge_node/node.py +10 -0
  122. vellum/workflows/nodes/displayable/prompt_deployment_node/__init__.py +5 -0
  123. vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +45 -0
  124. vellum/workflows/nodes/displayable/search_node/__init__.py +5 -0
  125. vellum/workflows/nodes/displayable/search_node/node.py +26 -0
  126. vellum/workflows/nodes/displayable/subworkflow_deployment_node/__init__.py +5 -0
  127. vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +156 -0
  128. vellum/workflows/nodes/displayable/tests/__init__.py +0 -0
  129. vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +148 -0
  130. vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py +134 -0
  131. vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +80 -0
  132. vellum/workflows/nodes/utils.py +27 -0
  133. vellum/workflows/outputs/__init__.py +6 -0
  134. vellum/workflows/outputs/base.py +196 -0
  135. vellum/workflows/ports/__init__.py +7 -0
  136. vellum/workflows/ports/node_ports.py +75 -0
  137. vellum/workflows/ports/port.py +75 -0
  138. vellum/workflows/ports/utils.py +40 -0
  139. vellum/workflows/references/__init__.py +17 -0
  140. vellum/workflows/references/environment_variable.py +20 -0
  141. vellum/workflows/references/execution_count.py +20 -0
  142. vellum/workflows/references/external_input.py +49 -0
  143. vellum/workflows/references/input.py +7 -0
  144. vellum/workflows/references/lazy.py +55 -0
  145. vellum/workflows/references/node.py +43 -0
  146. vellum/workflows/references/output.py +78 -0
  147. vellum/workflows/references/state_value.py +23 -0
  148. vellum/workflows/references/vellum_secret.py +15 -0
  149. vellum/workflows/references/workflow_input.py +41 -0
  150. vellum/workflows/resolvers/__init__.py +5 -0
  151. vellum/workflows/resolvers/base.py +15 -0
  152. vellum/workflows/runner/__init__.py +5 -0
  153. vellum/workflows/runner/runner.py +588 -0
  154. vellum/workflows/runner/types.py +18 -0
  155. vellum/workflows/state/__init__.py +5 -0
  156. vellum/workflows/state/base.py +327 -0
  157. vellum/workflows/state/context.py +18 -0
  158. vellum/workflows/state/encoder.py +57 -0
  159. vellum/workflows/state/store.py +28 -0
  160. vellum/workflows/state/tests/__init__.py +0 -0
  161. vellum/workflows/state/tests/test_state.py +113 -0
  162. vellum/workflows/types/__init__.py +0 -0
  163. vellum/workflows/types/core.py +91 -0
  164. vellum/workflows/types/generics.py +14 -0
  165. vellum/workflows/types/stack.py +39 -0
  166. vellum/workflows/types/tests/__init__.py +0 -0
  167. vellum/workflows/types/tests/test_utils.py +76 -0
  168. vellum/workflows/types/utils.py +164 -0
  169. vellum/workflows/utils/__init__.py +0 -0
  170. vellum/workflows/utils/names.py +13 -0
  171. vellum/workflows/utils/tests/__init__.py +0 -0
  172. vellum/workflows/utils/tests/test_names.py +15 -0
  173. vellum/workflows/utils/tests/test_vellum_variables.py +25 -0
  174. vellum/workflows/utils/vellum_variables.py +81 -0
  175. vellum/workflows/vellum_client.py +18 -0
  176. vellum/workflows/workflows/__init__.py +5 -0
  177. vellum/workflows/workflows/base.py +365 -0
  178. {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.10.0.dist-info}/METADATA +2 -1
  179. {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.10.0.dist-info}/RECORD +245 -7
  180. vellum_cli/__init__.py +72 -0
  181. vellum_cli/aliased_group.py +103 -0
  182. vellum_cli/config.py +96 -0
  183. vellum_cli/image_push.py +112 -0
  184. vellum_cli/logger.py +36 -0
  185. vellum_cli/pull.py +73 -0
  186. vellum_cli/push.py +121 -0
  187. vellum_cli/tests/test_config.py +100 -0
  188. vellum_cli/tests/test_pull.py +152 -0
  189. vellum_ee/workflows/__init__.py +0 -0
  190. vellum_ee/workflows/display/__init__.py +0 -0
  191. vellum_ee/workflows/display/base.py +73 -0
  192. vellum_ee/workflows/display/nodes/__init__.py +4 -0
  193. vellum_ee/workflows/display/nodes/base_node_display.py +116 -0
  194. vellum_ee/workflows/display/nodes/base_node_vellum_display.py +36 -0
  195. vellum_ee/workflows/display/nodes/get_node_display_class.py +25 -0
  196. vellum_ee/workflows/display/nodes/tests/__init__.py +0 -0
  197. vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +47 -0
  198. vellum_ee/workflows/display/nodes/types.py +18 -0
  199. vellum_ee/workflows/display/nodes/utils.py +33 -0
  200. vellum_ee/workflows/display/nodes/vellum/__init__.py +32 -0
  201. vellum_ee/workflows/display/nodes/vellum/api_node.py +205 -0
  202. vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +71 -0
  203. vellum_ee/workflows/display/nodes/vellum/conditional_node.py +217 -0
  204. vellum_ee/workflows/display/nodes/vellum/final_output_node.py +61 -0
  205. vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +49 -0
  206. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +170 -0
  207. vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +99 -0
  208. vellum_ee/workflows/display/nodes/vellum/map_node.py +100 -0
  209. vellum_ee/workflows/display/nodes/vellum/merge_node.py +48 -0
  210. vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +68 -0
  211. vellum_ee/workflows/display/nodes/vellum/search_node.py +193 -0
  212. vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +58 -0
  213. vellum_ee/workflows/display/nodes/vellum/templating_node.py +67 -0
  214. vellum_ee/workflows/display/nodes/vellum/tests/__init__.py +0 -0
  215. vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +106 -0
  216. vellum_ee/workflows/display/nodes/vellum/try_node.py +38 -0
  217. vellum_ee/workflows/display/nodes/vellum/utils.py +76 -0
  218. vellum_ee/workflows/display/tests/__init__.py +0 -0
  219. vellum_ee/workflows/display/tests/workflow_serialization/__init__.py +0 -0
  220. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +426 -0
  221. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +607 -0
  222. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +1175 -0
  223. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +235 -0
  224. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +511 -0
  225. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +372 -0
  226. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +272 -0
  227. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +289 -0
  228. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +354 -0
  229. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +123 -0
  230. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +84 -0
  231. vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +233 -0
  232. vellum_ee/workflows/display/types.py +46 -0
  233. vellum_ee/workflows/display/utils/__init__.py +0 -0
  234. vellum_ee/workflows/display/utils/tests/__init__.py +0 -0
  235. vellum_ee/workflows/display/utils/tests/test_uuids.py +16 -0
  236. vellum_ee/workflows/display/utils/uuids.py +24 -0
  237. vellum_ee/workflows/display/utils/vellum.py +121 -0
  238. vellum_ee/workflows/display/vellum.py +357 -0
  239. vellum_ee/workflows/display/workflows/__init__.py +5 -0
  240. vellum_ee/workflows/display/workflows/base_workflow_display.py +302 -0
  241. vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +32 -0
  242. vellum_ee/workflows/display/workflows/vellum_workflow_display.py +386 -0
  243. {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.10.0.dist-info}/LICENSE +0 -0
  244. {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.10.0.dist-info}/WHEEL +0 -0
  245. {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.10.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,1175 @@
1
+ import pytest
2
+ from unittest import mock
3
+
4
+ from deepdiff import DeepDiff
5
+
6
+ from tests.workflows.basic_conditional_node.workflow import CategoryWorkflow
7
+ from tests.workflows.basic_conditional_node.workflow_with_only_one_conditional_node import create_simple_workflow
8
+ from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
9
+ from vellum_ee.workflows.display.workflows import VellumWorkflowDisplay
10
+ from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
11
+ from vellum.workflows.expressions.begins_with import BeginsWithExpression
12
+ from vellum.workflows.expressions.between import BetweenExpression
13
+ from vellum.workflows.expressions.contains import ContainsExpression
14
+ from vellum.workflows.expressions.does_not_begin_with import DoesNotBeginWithExpression
15
+ from vellum.workflows.expressions.does_not_contain import DoesNotContainExpression
16
+ from vellum.workflows.expressions.does_not_end_with import DoesNotEndWithExpression
17
+ from vellum.workflows.expressions.does_not_equal import DoesNotEqualExpression
18
+ from vellum.workflows.expressions.ends_with import EndsWithExpression
19
+ from vellum.workflows.expressions.equals import EqualsExpression
20
+ from vellum.workflows.expressions.greater_than import GreaterThanExpression
21
+ from vellum.workflows.expressions.greater_than_or_equal_to import GreaterThanOrEqualToExpression
22
+ from vellum.workflows.expressions.in_ import InExpression
23
+ from vellum.workflows.expressions.is_not_null import IsNotNullExpression
24
+ from vellum.workflows.expressions.is_null import IsNullExpression
25
+ from vellum.workflows.expressions.less_than import LessThanExpression
26
+ from vellum.workflows.expressions.less_than_or_equal_to import LessThanOrEqualToExpression
27
+ from vellum.workflows.expressions.not_between import NotBetweenExpression
28
+ from vellum.workflows.expressions.not_in import NotInExpression
29
+
30
+
31
+ def test_serialize_workflow():
32
+ # GIVEN a Workflow that uses a ConditionalNode
33
+ # WHEN we serialize it
34
+ workflow_display = get_workflow_display(base_display_class=VellumWorkflowDisplay, workflow_class=CategoryWorkflow)
35
+
36
+ # TODO: Support serialization of BaseNode
37
+ # https://app.shortcut.com/vellum/story/4871/support-serialization-of-base-node
38
+ with mock.patch.object(BaseNodeVellumDisplay, "serialize") as mocked_serialize:
39
+ mocked_serialize.return_value = {"type": "MOCKED"}
40
+ serialized_workflow: dict = workflow_display.serialize()
41
+
42
+ # THEN we should get a serialized representation of the Workflow
43
+ assert serialized_workflow.keys() == {
44
+ "workflow_raw_data",
45
+ "input_variables",
46
+ "output_variables",
47
+ }
48
+
49
+ # AND its input variables should be what we expect
50
+ input_variables = serialized_workflow["input_variables"]
51
+ assert len(input_variables) == 1
52
+ assert not DeepDiff(
53
+ [
54
+ {
55
+ "id": "eece050a-432e-4a2c-8c87-9480397e4cbf",
56
+ "key": "category",
57
+ "type": "STRING",
58
+ "required": None,
59
+ "default": None,
60
+ "extensions": None,
61
+ },
62
+ ],
63
+ input_variables,
64
+ ignore_order=True,
65
+ )
66
+
67
+ # AND its output variables should be what we expect
68
+ output_variables = serialized_workflow["output_variables"]
69
+ assert len(output_variables) == 5
70
+ assert not DeepDiff(
71
+ [
72
+ {"id": "c05f7d96-59a0-4d58-93d7-d451afd3f630", "key": "question", "type": "STRING"},
73
+ {"id": "93f2cb75-6fa2-4e46-9488-c0bcd29153c0", "key": "compliment", "type": "STRING"},
74
+ {"id": "f936ae31-ba15-4864-8961-86231022a4d7", "key": "complaint", "type": "STRING"},
75
+ {"id": "cdbe2adf-9951-409a-b9a8-b8b349037f4f", "key": "statement", "type": "STRING"},
76
+ {"id": "62ad462f-f819-4940-99ab-b3f145507f57", "key": "fallthrough", "type": "STRING"},
77
+ ],
78
+ output_variables,
79
+ ignore_order=True,
80
+ )
81
+
82
+ # AND its raw data should be what we expect
83
+ workflow_raw_data = serialized_workflow["workflow_raw_data"]
84
+ assert workflow_raw_data.keys() == {"edges", "nodes", "display_data", "definition"}
85
+ assert len(workflow_raw_data["edges"]) == 11
86
+ assert len(workflow_raw_data["nodes"]) == 12
87
+
88
+ # AND each node should be serialized correctly
89
+ entrypoint_node = workflow_raw_data["nodes"][0]
90
+ assert entrypoint_node == {
91
+ "id": "089b3201-537a-4ed7-8d15-2524a00e8534",
92
+ "type": "ENTRYPOINT",
93
+ "definition": {
94
+ "bases": [],
95
+ "module": [
96
+ "vellum",
97
+ "workflows",
98
+ "nodes",
99
+ "bases",
100
+ "base",
101
+ ],
102
+ "name": "BaseNode",
103
+ },
104
+ "inputs": [],
105
+ "data": {
106
+ "label": "Entrypoint Node",
107
+ "source_handle_id": "c2f0871d-0d9d-417f-8b0e-c813ccf880ac",
108
+ },
109
+ "display_data": {
110
+ "position": {"x": 0.0, "y": 0.0},
111
+ },
112
+ }
113
+
114
+ conditional_node = workflow_raw_data["nodes"][1]
115
+ assert not DeepDiff(
116
+ {
117
+ "id": "9b619e4d-b0a7-4121-9060-100d457868cb",
118
+ "type": "CONDITIONAL",
119
+ "inputs": [
120
+ {
121
+ "id": "eb8f9320-7030-45bc-81fb-fb45017b6a89",
122
+ "key": "708bb538-4c77-4ae9-8e87-0706346e2947.field",
123
+ "value": {
124
+ "rules": [
125
+ {
126
+ "type": "INPUT_VARIABLE",
127
+ "data": {"input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf"},
128
+ }
129
+ ],
130
+ "combinator": "OR",
131
+ },
132
+ },
133
+ {
134
+ "id": "1fb4cf46-f8b3-418f-be30-f7ec57f92285",
135
+ "key": "708bb538-4c77-4ae9-8e87-0706346e2947.value",
136
+ "value": {
137
+ "rules": [{"type": "CONSTANT_VALUE", "data": {"type": "STRING", "value": "question"}}],
138
+ "combinator": "OR",
139
+ },
140
+ },
141
+ {
142
+ "id": "ca3a865e-e99a-43b7-a649-18df57180a4f",
143
+ "key": "ddee5d1d-46e9-4ae8-b0a8-311747ebadd4.field",
144
+ "value": {
145
+ "rules": [
146
+ {
147
+ "type": "INPUT_VARIABLE",
148
+ "data": {"input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf"},
149
+ }
150
+ ],
151
+ "combinator": "OR",
152
+ },
153
+ },
154
+ {
155
+ "id": "40957176-de6e-4131-bfa7-55c633312af0",
156
+ "key": "ddee5d1d-46e9-4ae8-b0a8-311747ebadd4.value",
157
+ "value": {
158
+ "rules": [{"type": "CONSTANT_VALUE", "data": {"type": "STRING", "value": "complaint"}}],
159
+ "combinator": "OR",
160
+ },
161
+ },
162
+ {
163
+ "id": "9a685f10-f849-445b-9b26-f1a99e1bc625",
164
+ "key": "73157578-205a-4816-8985-cf726063647c.field",
165
+ "value": {
166
+ "rules": [
167
+ {
168
+ "type": "INPUT_VARIABLE",
169
+ "data": {"input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf"},
170
+ }
171
+ ],
172
+ "combinator": "OR",
173
+ },
174
+ },
175
+ {
176
+ "id": "93f06582-aff7-4ce5-8c60-f923090ffebc",
177
+ "key": "73157578-205a-4816-8985-cf726063647c.value",
178
+ "value": {
179
+ "rules": [{"type": "CONSTANT_VALUE", "data": {"type": "STRING", "value": "compliment"}}],
180
+ "combinator": "OR",
181
+ },
182
+ },
183
+ {
184
+ "id": "965010fa-5f14-4f3c-92cb-ede4fad35b92",
185
+ "key": "e805add5-7f7f-443d-b9bc-11ad15eeb49c.field",
186
+ "value": {
187
+ "rules": [
188
+ {
189
+ "type": "INPUT_VARIABLE",
190
+ "data": {"input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf"},
191
+ }
192
+ ],
193
+ "combinator": "OR",
194
+ },
195
+ },
196
+ {
197
+ "id": "e759091b-3609-4581-9014-5f46f438a4c9",
198
+ "key": "e805add5-7f7f-443d-b9bc-11ad15eeb49c.value",
199
+ "value": {
200
+ "rules": [{"type": "CONSTANT_VALUE", "data": {"type": "STRING", "value": "statement"}}],
201
+ "combinator": "OR",
202
+ },
203
+ },
204
+ {
205
+ "id": "6b592d70-93ab-4dcf-aeae-03834f37ef83",
206
+ "key": "f47d72ff-665f-4143-ada3-6fa66f5bda42.field",
207
+ "value": {
208
+ "rules": [
209
+ {
210
+ "type": "INPUT_VARIABLE",
211
+ "data": {"input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf"},
212
+ }
213
+ ],
214
+ "combinator": "OR",
215
+ },
216
+ },
217
+ {
218
+ "id": "e915cd85-ae55-48be-b31c-f2285db9db10",
219
+ "key": "f47d72ff-665f-4143-ada3-6fa66f5bda42.value",
220
+ "value": {
221
+ "rules": [{"type": "CONSTANT_VALUE", "data": {"type": "STRING", "value": "statement"}}],
222
+ "combinator": "OR",
223
+ },
224
+ },
225
+ {
226
+ "id": "deb43b7d-d084-4453-bed9-0f0b940d0639",
227
+ "key": "d3359d60-9bb4-4c6e-8009-b7ea46ab28a7.field",
228
+ "value": {
229
+ "rules": [
230
+ {
231
+ "type": "INPUT_VARIABLE",
232
+ "data": {"input_variable_id": "eece050a-432e-4a2c-8c87-9480397e4cbf"},
233
+ }
234
+ ],
235
+ "combinator": "OR",
236
+ },
237
+ },
238
+ {
239
+ "id": "e5d75ae4-cd46-437e-9695-9df2d79578b4",
240
+ "key": "d3359d60-9bb4-4c6e-8009-b7ea46ab28a7.value",
241
+ "value": {
242
+ "rules": [{"type": "CONSTANT_VALUE", "data": {"type": "STRING", "value": "statement"}}],
243
+ "combinator": "OR",
244
+ },
245
+ },
246
+ ],
247
+ "data": {
248
+ "label": "Category Conditional Node",
249
+ "target_handle_id": "dd89e228-a23e-422b-80b2-34362c1c050e",
250
+ "conditions": [
251
+ {
252
+ "id": "de7b0b4e-7803-4d36-a275-2e7e3f60342b",
253
+ "type": "IF",
254
+ "source_handle_id": "561b4e3a-8db3-448a-8933-1115937082ff",
255
+ "data": {
256
+ "id": "2ccd0730-26d1-4fb4-baa9-1a2a182dd9a0",
257
+ "rules": [
258
+ {
259
+ "id": "708bb538-4c77-4ae9-8e87-0706346e2947",
260
+ "rules": None,
261
+ "combinator": None,
262
+ "negated": False,
263
+ "field_node_input_id": "eb8f9320-7030-45bc-81fb-fb45017b6a89",
264
+ "operator": "=",
265
+ "value_node_input_id": "1fb4cf46-f8b3-418f-be30-f7ec57f92285",
266
+ }
267
+ ],
268
+ "combinator": "AND",
269
+ "negated": False,
270
+ "field_node_input_id": None,
271
+ "operator": None,
272
+ "value_node_input_id": None,
273
+ },
274
+ },
275
+ {
276
+ "id": "5e783d17-6808-441a-ac6c-33a4e184f4e0",
277
+ "type": "ELIF",
278
+ "source_handle_id": "0644f22e-2680-441a-9554-eedf1d3d22a9",
279
+ "data": {
280
+ "id": "cc3f0d92-b603-42cc-b2e9-83e3b23b3bcb",
281
+ "rules": [
282
+ {
283
+ "id": "ddee5d1d-46e9-4ae8-b0a8-311747ebadd4",
284
+ "rules": None,
285
+ "combinator": None,
286
+ "negated": False,
287
+ "field_node_input_id": "ca3a865e-e99a-43b7-a649-18df57180a4f",
288
+ "operator": "=",
289
+ "value_node_input_id": "40957176-de6e-4131-bfa7-55c633312af0",
290
+ }
291
+ ],
292
+ "combinator": "AND",
293
+ "negated": False,
294
+ "field_node_input_id": None,
295
+ "operator": None,
296
+ "value_node_input_id": None,
297
+ },
298
+ },
299
+ {
300
+ "id": "6bd2f643-9cf5-4e7f-9113-f90e5c8057be",
301
+ "type": "ELIF",
302
+ "source_handle_id": "2a48d274-ecfc-4f40-95ac-bc697663f10c",
303
+ "data": {
304
+ "id": "a5a0f391-7052-452f-9fe1-a5781a491591",
305
+ "rules": [
306
+ {
307
+ "id": "73157578-205a-4816-8985-cf726063647c",
308
+ "rules": None,
309
+ "combinator": None,
310
+ "negated": False,
311
+ "field_node_input_id": "9a685f10-f849-445b-9b26-f1a99e1bc625",
312
+ "operator": "=",
313
+ "value_node_input_id": "93f06582-aff7-4ce5-8c60-f923090ffebc",
314
+ }
315
+ ],
316
+ "combinator": "AND",
317
+ "negated": False,
318
+ "field_node_input_id": None,
319
+ "operator": None,
320
+ "value_node_input_id": None,
321
+ },
322
+ },
323
+ {
324
+ "id": "0a058485-18a4-4e20-8a30-6da8196ac46f",
325
+ "type": "ELIF",
326
+ "source_handle_id": "90fc9dc8-0a74-4a98-b6ac-55ffce4a2881",
327
+ "data": {
328
+ "id": "efe7a851-2a67-4189-99ec-bc193242b270",
329
+ "rules": [
330
+ {
331
+ "id": "e805add5-7f7f-443d-b9bc-11ad15eeb49c",
332
+ "rules": None,
333
+ "combinator": None,
334
+ "negated": False,
335
+ "field_node_input_id": "965010fa-5f14-4f3c-92cb-ede4fad35b92",
336
+ "operator": "=",
337
+ "value_node_input_id": "e759091b-3609-4581-9014-5f46f438a4c9",
338
+ },
339
+ {
340
+ "id": "2c78817b-8b73-43fd-8dab-a8923018da9d",
341
+ "rules": [
342
+ {
343
+ "id": "f47d72ff-665f-4143-ada3-6fa66f5bda42",
344
+ "rules": None,
345
+ "combinator": None,
346
+ "negated": False,
347
+ "field_node_input_id": "6b592d70-93ab-4dcf-aeae-03834f37ef83",
348
+ "operator": "=",
349
+ "value_node_input_id": "e915cd85-ae55-48be-b31c-f2285db9db10",
350
+ },
351
+ {
352
+ "id": "d3359d60-9bb4-4c6e-8009-b7ea46ab28a7",
353
+ "rules": None,
354
+ "combinator": None,
355
+ "negated": False,
356
+ "field_node_input_id": "deb43b7d-d084-4453-bed9-0f0b940d0639",
357
+ "operator": "=",
358
+ "value_node_input_id": "e5d75ae4-cd46-437e-9695-9df2d79578b4",
359
+ },
360
+ ],
361
+ "combinator": "AND",
362
+ "negated": False,
363
+ "field_node_input_id": None,
364
+ "operator": None,
365
+ "value_node_input_id": None,
366
+ },
367
+ ],
368
+ "combinator": "AND",
369
+ "negated": False,
370
+ "field_node_input_id": None,
371
+ "operator": None,
372
+ "value_node_input_id": None,
373
+ },
374
+ },
375
+ ],
376
+ "version": "2",
377
+ },
378
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
379
+ "definition": {
380
+ "bases": [
381
+ {
382
+ "module": [
383
+ "vellum",
384
+ "workflows",
385
+ "nodes",
386
+ "displayable",
387
+ "conditional_node",
388
+ "node",
389
+ ],
390
+ "name": "ConditionalNode",
391
+ }
392
+ ],
393
+ "module": [
394
+ "tests",
395
+ "workflows",
396
+ "basic_conditional_node",
397
+ "workflow",
398
+ ],
399
+ "name": "CategoryConditionalNode",
400
+ },
401
+ },
402
+ conditional_node,
403
+ ignore_order=True,
404
+ )
405
+
406
+ assert not DeepDiff(
407
+ [
408
+ {
409
+ "type": "MOCKED",
410
+ },
411
+ {
412
+ "type": "MOCKED",
413
+ },
414
+ {
415
+ "type": "MOCKED",
416
+ },
417
+ {
418
+ "type": "MOCKED",
419
+ },
420
+ {
421
+ "type": "MOCKED",
422
+ },
423
+ ],
424
+ workflow_raw_data["nodes"][2:7],
425
+ )
426
+
427
+ assert not DeepDiff(
428
+ [
429
+ {
430
+ "id": "9c22ee47-01da-4e4e-863d-b4a6874bed66",
431
+ "type": "TERMINAL",
432
+ "definition": {
433
+ "bases": [
434
+ {
435
+ "bases": [],
436
+ "module": [
437
+ "vellum",
438
+ "workflows",
439
+ "nodes",
440
+ "bases",
441
+ "base",
442
+ ],
443
+ "name": "BaseNode",
444
+ },
445
+ ],
446
+ "module": [
447
+ "vellum",
448
+ "workflows",
449
+ "nodes",
450
+ "displayable",
451
+ "final_output_node",
452
+ "node",
453
+ ],
454
+ "name": "FinalOutputNode",
455
+ },
456
+ "data": {
457
+ "label": "Final Output",
458
+ "name": "statement",
459
+ "target_handle_id": "f02a8971-e9a4-4716-bfb4-d08f5614b5d8",
460
+ "output_id": "cdbe2adf-9951-409a-b9a8-b8b349037f4f",
461
+ "output_type": "STRING",
462
+ "node_input_id": "bed69f8a-3a83-4e52-beba-8eb14f4b0ca9",
463
+ },
464
+ "inputs": [
465
+ {
466
+ "id": "bed69f8a-3a83-4e52-beba-8eb14f4b0ca9",
467
+ "key": "node_input",
468
+ "value": {
469
+ "rules": [
470
+ {
471
+ "type": "NODE_OUTPUT",
472
+ "data": {
473
+ "node_id": "ed7caf01-9ae7-47a3-b15a-16697abaf486",
474
+ "output_id": "74ea6af1-8934-4e3c-b68d-b93092b4be73",
475
+ },
476
+ }
477
+ ],
478
+ "combinator": "OR",
479
+ },
480
+ }
481
+ ],
482
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
483
+ },
484
+ {
485
+ "id": "47f0931c-41f6-4b84-bf39-0c486941f599",
486
+ "type": "TERMINAL",
487
+ "definition": {
488
+ "bases": [
489
+ {
490
+ "bases": [],
491
+ "module": [
492
+ "vellum",
493
+ "workflows",
494
+ "nodes",
495
+ "bases",
496
+ "base",
497
+ ],
498
+ "name": "BaseNode",
499
+ },
500
+ ],
501
+ "module": [
502
+ "vellum",
503
+ "workflows",
504
+ "nodes",
505
+ "displayable",
506
+ "final_output_node",
507
+ "node",
508
+ ],
509
+ "name": "FinalOutputNode",
510
+ },
511
+ "data": {
512
+ "label": "Final Output",
513
+ "name": "compliment",
514
+ "target_handle_id": "a4d57adc-58c1-40c6-810b-ee5fd923bfc5",
515
+ "output_id": "93f2cb75-6fa2-4e46-9488-c0bcd29153c0",
516
+ "output_type": "STRING",
517
+ "node_input_id": "e3f2d793-31a7-4670-8155-bd034d9f25e2",
518
+ },
519
+ "inputs": [
520
+ {
521
+ "id": "e3f2d793-31a7-4670-8155-bd034d9f25e2",
522
+ "key": "node_input",
523
+ "value": {
524
+ "rules": [
525
+ {
526
+ "type": "NODE_OUTPUT",
527
+ "data": {
528
+ "node_id": "8df781b1-ff28-48a5-98a2-d7d796b932b0",
529
+ "output_id": "61c357a1-41d8-4adf-bfe1-ce615c4d7d23",
530
+ },
531
+ }
532
+ ],
533
+ "combinator": "OR",
534
+ },
535
+ }
536
+ ],
537
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
538
+ },
539
+ {
540
+ "id": "e3d29229-f746-4125-819e-f847acbed307",
541
+ "type": "TERMINAL",
542
+ "definition": {
543
+ "bases": [
544
+ {
545
+ "bases": [],
546
+ "module": [
547
+ "vellum",
548
+ "workflows",
549
+ "nodes",
550
+ "bases",
551
+ "base",
552
+ ],
553
+ "name": "BaseNode",
554
+ },
555
+ ],
556
+ "module": [
557
+ "vellum",
558
+ "workflows",
559
+ "nodes",
560
+ "displayable",
561
+ "final_output_node",
562
+ "node",
563
+ ],
564
+ "name": "FinalOutputNode",
565
+ },
566
+ "data": {
567
+ "label": "Final Output",
568
+ "name": "complaint",
569
+ "target_handle_id": "c5dd9bf5-9e18-4dbc-8c20-2c0baf969ebe",
570
+ "output_id": "f936ae31-ba15-4864-8961-86231022a4d7",
571
+ "output_type": "STRING",
572
+ "node_input_id": "9b35cc61-5887-478a-814d-9693ead5932f",
573
+ },
574
+ "inputs": [
575
+ {
576
+ "id": "9b35cc61-5887-478a-814d-9693ead5932f",
577
+ "key": "node_input",
578
+ "value": {
579
+ "rules": [
580
+ {
581
+ "type": "NODE_OUTPUT",
582
+ "data": {
583
+ "node_id": "68c02b7c-5077-4087-803d-841474a8081f",
584
+ "output_id": "0ec68ffe-cbb7-4dbb-aaff-f6025bd62efa",
585
+ },
586
+ }
587
+ ],
588
+ "combinator": "OR",
589
+ },
590
+ }
591
+ ],
592
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
593
+ },
594
+ {
595
+ "id": "6efa7b45-0580-406d-85aa-439117ba8021",
596
+ "type": "TERMINAL",
597
+ "definition": {
598
+ "bases": [
599
+ {
600
+ "bases": [],
601
+ "module": [
602
+ "vellum",
603
+ "workflows",
604
+ "nodes",
605
+ "bases",
606
+ "base",
607
+ ],
608
+ "name": "BaseNode",
609
+ },
610
+ ],
611
+ "module": [
612
+ "vellum",
613
+ "workflows",
614
+ "nodes",
615
+ "displayable",
616
+ "final_output_node",
617
+ "node",
618
+ ],
619
+ "name": "FinalOutputNode",
620
+ },
621
+ "data": {
622
+ "label": "Final Output",
623
+ "name": "fallthrough",
624
+ "target_handle_id": "2283cd2c-b077-4b5d-a96f-aa2cd6023eda",
625
+ "output_id": "62ad462f-f819-4940-99ab-b3f145507f57",
626
+ "output_type": "STRING",
627
+ "node_input_id": "cee5378a-9011-4d03-bd3c-a32421bd093f",
628
+ },
629
+ "inputs": [
630
+ {
631
+ "id": "cee5378a-9011-4d03-bd3c-a32421bd093f",
632
+ "key": "node_input",
633
+ "value": {
634
+ "rules": [
635
+ {
636
+ "type": "NODE_OUTPUT",
637
+ "data": {
638
+ "node_id": "148c61bd-e8b0-4d4b-8734-b043a72b90ed",
639
+ "output_id": "fafa0bde-8508-43d5-a9c8-db5d49f307f6",
640
+ },
641
+ }
642
+ ],
643
+ "combinator": "OR",
644
+ },
645
+ }
646
+ ],
647
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
648
+ },
649
+ {
650
+ "id": "fa11b84b-1d76-4adc-ab28-cbbaa933c267",
651
+ "type": "TERMINAL",
652
+ "definition": {
653
+ "bases": [
654
+ {
655
+ "bases": [],
656
+ "module": [
657
+ "vellum",
658
+ "workflows",
659
+ "nodes",
660
+ "bases",
661
+ "base",
662
+ ],
663
+ "name": "BaseNode",
664
+ },
665
+ ],
666
+ "module": [
667
+ "vellum",
668
+ "workflows",
669
+ "nodes",
670
+ "displayable",
671
+ "final_output_node",
672
+ "node",
673
+ ],
674
+ "name": "FinalOutputNode",
675
+ },
676
+ "data": {
677
+ "label": "Final Output",
678
+ "name": "question",
679
+ "target_handle_id": "e1a6da28-02c5-40d7-8ac5-9fb07e2e3e1d",
680
+ "output_id": "c05f7d96-59a0-4d58-93d7-d451afd3f630",
681
+ "output_type": "STRING",
682
+ "node_input_id": "1c1d34d9-0cda-471f-ac9a-40ac351c9aca",
683
+ },
684
+ "inputs": [
685
+ {
686
+ "id": "1c1d34d9-0cda-471f-ac9a-40ac351c9aca",
687
+ "key": "node_input",
688
+ "value": {
689
+ "rules": [
690
+ {
691
+ "type": "NODE_OUTPUT",
692
+ "data": {
693
+ "node_id": "0d959311-c836-4641-a867-58f63df9dfea",
694
+ "output_id": "db9f7ff3-77e2-4b0a-9c39-bb4bb50e3ad5",
695
+ },
696
+ }
697
+ ],
698
+ "combinator": "OR",
699
+ },
700
+ }
701
+ ],
702
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
703
+ },
704
+ ],
705
+ workflow_raw_data["nodes"][7:12],
706
+ ignore_order=True,
707
+ )
708
+
709
+ # AND each edge should be serialized correctly
710
+ serialized_edges = workflow_raw_data["edges"]
711
+ assert not DeepDiff(
712
+ [
713
+ {
714
+ "id": "32263c88-d725-4d03-a500-fadc34e10c9a",
715
+ "source_node_id": "089b3201-537a-4ed7-8d15-2524a00e8534",
716
+ "source_handle_id": "c2f0871d-0d9d-417f-8b0e-c813ccf880ac",
717
+ "target_node_id": "9b619e4d-b0a7-4121-9060-100d457868cb",
718
+ "target_handle_id": "dd89e228-a23e-422b-80b2-34362c1c050e",
719
+ "type": "DEFAULT",
720
+ },
721
+ {
722
+ "id": "1ae3cdb6-5b52-4ad3-bcfe-6997c86083f8",
723
+ "source_node_id": "9b619e4d-b0a7-4121-9060-100d457868cb",
724
+ "source_handle_id": "3a45b81f-95e4-4cbd-8997-bfdbe30251e8",
725
+ "target_node_id": "0d959311-c836-4641-a867-58f63df9dfea",
726
+ "target_handle_id": "7beba198-c452-4749-a38a-ea9420d84e14",
727
+ "type": "DEFAULT",
728
+ },
729
+ {
730
+ "id": "5704cb9c-9d01-4809-9d91-8014276e6574",
731
+ "source_node_id": "9b619e4d-b0a7-4121-9060-100d457868cb",
732
+ "source_handle_id": "7202f702-1ebc-4067-ab1e-ec67e49158ee",
733
+ "target_node_id": "68c02b7c-5077-4087-803d-841474a8081f",
734
+ "target_handle_id": "1dc4eebe-b6db-4229-96e5-115ff8cedb76",
735
+ "type": "DEFAULT",
736
+ },
737
+ {
738
+ "id": "c923e009-06c9-4978-b789-6ae995dcc81c",
739
+ "source_node_id": "9b619e4d-b0a7-4121-9060-100d457868cb",
740
+ "source_handle_id": "cf45705d-1a47-43a6-9d24-a7fdf78baae0",
741
+ "target_node_id": "8df781b1-ff28-48a5-98a2-d7d796b932b0",
742
+ "target_handle_id": "b73c39be-cbfe-4225-86e6-e6e4c161881e",
743
+ "type": "DEFAULT",
744
+ },
745
+ {
746
+ "id": "e487c031-fd5b-41b3-94d7-eb3f7ce8e25c",
747
+ "source_node_id": "9b619e4d-b0a7-4121-9060-100d457868cb",
748
+ "source_handle_id": "f04610dd-61cf-41b0-b337-2235e101cdb0",
749
+ "target_node_id": "ed7caf01-9ae7-47a3-b15a-16697abaf486",
750
+ "target_handle_id": "76fe7aec-5cd4-4c1a-b386-cfe09ebe66e4",
751
+ "type": "DEFAULT",
752
+ },
753
+ {
754
+ "id": "6a1c379d-bbe4-4034-8ac9-0353901ebc21",
755
+ "source_node_id": "9b619e4d-b0a7-4121-9060-100d457868cb",
756
+ "source_handle_id": "f9dde637-ea90-465f-a871-caf8380ae377",
757
+ "target_node_id": "148c61bd-e8b0-4d4b-8734-b043a72b90ed",
758
+ "target_handle_id": "c88839af-3a79-4310-abbd-e1553d981dce",
759
+ "type": "DEFAULT",
760
+ },
761
+ {
762
+ "id": "8a554637-e382-4a66-9b77-4eadce45a25a",
763
+ "source_node_id": "ed7caf01-9ae7-47a3-b15a-16697abaf486",
764
+ "source_handle_id": "cde43aef-f607-4b5d-87f6-9238dd4a3a2b",
765
+ "target_node_id": "9c22ee47-01da-4e4e-863d-b4a6874bed66",
766
+ "target_handle_id": "f02a8971-e9a4-4716-bfb4-d08f5614b5d8",
767
+ "type": "DEFAULT",
768
+ },
769
+ {
770
+ "id": "af083f7d-226c-4341-bb6f-756f00846b42",
771
+ "source_node_id": "68c02b7c-5077-4087-803d-841474a8081f",
772
+ "source_handle_id": "ef032cf7-c8df-4a98-827c-386dd8a5a346",
773
+ "target_node_id": "e3d29229-f746-4125-819e-f847acbed307",
774
+ "target_handle_id": "c5dd9bf5-9e18-4dbc-8c20-2c0baf969ebe",
775
+ "type": "DEFAULT",
776
+ },
777
+ {
778
+ "id": "47758209-70cb-4f12-b71f-dc28df0f6d0b",
779
+ "source_node_id": "0d959311-c836-4641-a867-58f63df9dfea",
780
+ "source_handle_id": "69a2121d-fc21-47a1-af49-6200aad836de",
781
+ "target_node_id": "fa11b84b-1d76-4adc-ab28-cbbaa933c267",
782
+ "target_handle_id": "e1a6da28-02c5-40d7-8ac5-9fb07e2e3e1d",
783
+ "type": "DEFAULT",
784
+ },
785
+ {
786
+ "id": "f08a49f8-8bfd-4c05-8f28-dfa536654af8",
787
+ "source_node_id": "8df781b1-ff28-48a5-98a2-d7d796b932b0",
788
+ "source_handle_id": "aeb6805d-2c9f-4d52-a690-341ea0e869b3",
789
+ "target_node_id": "47f0931c-41f6-4b84-bf39-0c486941f599",
790
+ "target_handle_id": "a4d57adc-58c1-40c6-810b-ee5fd923bfc5",
791
+ "type": "DEFAULT",
792
+ },
793
+ {
794
+ "id": "c45e03b4-dba6-4620-bc02-3847ad90086b",
795
+ "source_node_id": "148c61bd-e8b0-4d4b-8734-b043a72b90ed",
796
+ "source_handle_id": "26f50353-85ae-462f-b82d-9fd736900bd6",
797
+ "target_node_id": "6efa7b45-0580-406d-85aa-439117ba8021",
798
+ "target_handle_id": "2283cd2c-b077-4b5d-a96f-aa2cd6023eda",
799
+ "type": "DEFAULT",
800
+ },
801
+ ],
802
+ serialized_edges,
803
+ ignore_order=True,
804
+ )
805
+
806
+ # AND the display data should be what we expect
807
+ display_data = workflow_raw_data["display_data"]
808
+ assert display_data == {
809
+ "viewport": {
810
+ "x": 0.0,
811
+ "y": 0.0,
812
+ "zoom": 1.0,
813
+ }
814
+ }
815
+
816
+ # AND the definition should be what we expect
817
+ definition = workflow_raw_data["definition"]
818
+ assert definition == {
819
+ "name": "CategoryWorkflow",
820
+ "module": [
821
+ "tests",
822
+ "workflows",
823
+ "basic_conditional_node",
824
+ "workflow",
825
+ ],
826
+ }
827
+
828
+
829
+ def descriptors_with_lhs_and_rhs():
830
+ return [
831
+ (EqualsExpression(lhs="123", rhs="123"), "="),
832
+ (DoesNotEqualExpression(lhs="123", rhs="123"), "!="),
833
+ (LessThanExpression(lhs="123", rhs="123"), "<"),
834
+ (GreaterThanExpression(lhs="123", rhs="123"), ">"),
835
+ (LessThanOrEqualToExpression(lhs="123", rhs="123"), "<="),
836
+ (GreaterThanOrEqualToExpression(lhs="123", rhs="123"), ">="),
837
+ (ContainsExpression(lhs="123", rhs="123"), "contains"),
838
+ (BeginsWithExpression(lhs="123", rhs="123"), "beginsWith"),
839
+ (EndsWithExpression(lhs="123", rhs="123"), "endsWith"),
840
+ (DoesNotContainExpression(lhs="123", rhs="123"), "doesNotContain"),
841
+ (DoesNotBeginWithExpression(lhs="123", rhs="123"), "doesNotBeginWith"),
842
+ (DoesNotEndWithExpression(lhs="123", rhs="123"), "doesNotEndWith"),
843
+ (InExpression(lhs="123", rhs="123"), "in"),
844
+ (NotInExpression(lhs="123", rhs="123"), "notIn"),
845
+ ]
846
+
847
+
848
+ def descriptors_with_expression():
849
+ return [
850
+ (IsNullExpression(expression="123"), "null"),
851
+ (IsNotNullExpression(expression="123"), "notNull"),
852
+ ]
853
+
854
+
855
+ def descriptors_with_value_and_start_and_end():
856
+ return [
857
+ (BetweenExpression(value="123", start="123", end="123"), "between"),
858
+ (NotBetweenExpression(value="123", start="123", end="123"), "notBetween"),
859
+ ]
860
+
861
+
862
+ @pytest.mark.parametrize("descriptor, operator", descriptors_with_lhs_and_rhs())
863
+ def test_conditional_node_serialize_all_operators_with_lhs_and_rhs(descriptor, operator):
864
+ # GIVEN a simple workflow with one conditional node
865
+ workflow_cls = create_simple_workflow(descriptor)
866
+
867
+ workflow_display = get_workflow_display(base_display_class=VellumWorkflowDisplay, workflow_class=workflow_cls)
868
+
869
+ # TODO: Support serialization of BaseNode
870
+ # https://app.shortcut.com/vellum/story/4871/support-serialization-of-base-node
871
+ with mock.patch.object(BaseNodeVellumDisplay, "serialize") as mocked_serialize:
872
+ mocked_serialize.return_value = {"type": "MOCKED"}
873
+ serialized_workflow: dict = workflow_display.serialize()
874
+
875
+ # THEN we should get a serialized representation of the Workflow
876
+ assert serialized_workflow.keys() == {
877
+ "workflow_raw_data",
878
+ "input_variables",
879
+ "output_variables",
880
+ }
881
+
882
+ # AND its raw data should be what we expect
883
+ workflow_raw_data = serialized_workflow["workflow_raw_data"]
884
+ assert workflow_raw_data.keys() == {"edges", "nodes", "display_data", "definition"}
885
+
886
+ # AND the conditional node should be what we expect
887
+ conditional_node = workflow_raw_data["nodes"][1]
888
+ assert not DeepDiff(
889
+ {
890
+ "id": "a9143814-6bb0-4cb3-a817-4fc076417121",
891
+ "type": "CONDITIONAL",
892
+ "inputs": [
893
+ {
894
+ "id": "2262b7b4-a2f2-408b-9d4d-362940ca1ed3",
895
+ "key": "abe7afac-952f-4cfc-ab07-47b47f34105f.field",
896
+ "value": {
897
+ "rules": [{"type": "CONSTANT_VALUE", "data": {"type": "STRING", "value": "123"}}],
898
+ "combinator": "OR",
899
+ },
900
+ },
901
+ {
902
+ "id": "aadade8a-c253-483a-8620-31fe8171c0fd",
903
+ "key": "abe7afac-952f-4cfc-ab07-47b47f34105f.value",
904
+ "value": {
905
+ "rules": [{"type": "CONSTANT_VALUE", "data": {"type": "STRING", "value": "123"}}],
906
+ "combinator": "OR",
907
+ },
908
+ },
909
+ ],
910
+ "data": {
911
+ "label": "Simple Conditional Node",
912
+ "target_handle_id": "c6e99e94-bc8e-47a4-b75c-cc96c6bedbb0",
913
+ "conditions": [
914
+ {
915
+ "id": "a4c32611-fd58-4b98-9d08-313cfd1c214e",
916
+ "type": "IF",
917
+ "source_handle_id": "8124a6cf-4a34-4149-adc0-68696c11bd4e",
918
+ "data": {
919
+ "id": "650e7105-3e76-43ca-858f-b290970b438b",
920
+ "rules": [
921
+ {
922
+ "id": "abe7afac-952f-4cfc-ab07-47b47f34105f",
923
+ "rules": None,
924
+ "combinator": None,
925
+ "negated": False,
926
+ "field_node_input_id": "2262b7b4-a2f2-408b-9d4d-362940ca1ed3",
927
+ "operator": f"{operator}",
928
+ "value_node_input_id": "aadade8a-c253-483a-8620-31fe8171c0fd",
929
+ }
930
+ ],
931
+ "combinator": "AND",
932
+ "negated": False,
933
+ "field_node_input_id": None,
934
+ "operator": None,
935
+ "value_node_input_id": None,
936
+ },
937
+ }
938
+ ],
939
+ "version": "2",
940
+ },
941
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
942
+ "definition": {
943
+ "bases": [
944
+ {
945
+ "module": [
946
+ "vellum",
947
+ "workflows",
948
+ "nodes",
949
+ "displayable",
950
+ "conditional_node",
951
+ "node",
952
+ ],
953
+ "name": "ConditionalNode",
954
+ }
955
+ ],
956
+ "module": [
957
+ "tests",
958
+ "workflows",
959
+ "basic_conditional_node",
960
+ "workflow_with_only_one_conditional_node",
961
+ ],
962
+ "name": "SimpleConditionalNode",
963
+ },
964
+ },
965
+ conditional_node,
966
+ ignore_order=True,
967
+ )
968
+
969
+
970
+ @pytest.mark.parametrize("descriptor, operator", descriptors_with_expression())
971
+ def test_conditional_node_serialize_all_operators_with_expression(descriptor, operator):
972
+ # GIVEN a simple workflow with one conditional node
973
+ workflow_cls = create_simple_workflow(descriptor)
974
+
975
+ workflow_display = get_workflow_display(base_display_class=VellumWorkflowDisplay, workflow_class=workflow_cls)
976
+
977
+ # TODO: Support serialization of BaseNode
978
+ # https://app.shortcut.com/vellum/story/4871/support-serialization-of-base-node
979
+ with mock.patch.object(BaseNodeVellumDisplay, "serialize") as mocked_serialize:
980
+ mocked_serialize.return_value = {"type": "MOCKED"}
981
+ serialized_workflow: dict = workflow_display.serialize()
982
+
983
+ # THEN we should get a serialized representation of the Workflow
984
+ assert serialized_workflow.keys() == {
985
+ "workflow_raw_data",
986
+ "input_variables",
987
+ "output_variables",
988
+ }
989
+
990
+ # AND its raw data should be what we expect
991
+ workflow_raw_data = serialized_workflow["workflow_raw_data"]
992
+ assert workflow_raw_data.keys() == {"edges", "nodes", "display_data", "definition"}
993
+
994
+ # AND the conditional node should be what we expect
995
+ conditional_node = workflow_raw_data["nodes"][1]
996
+ assert not DeepDiff(
997
+ {
998
+ "id": "a9143814-6bb0-4cb3-a817-4fc076417121",
999
+ "type": "CONDITIONAL",
1000
+ "inputs": [
1001
+ {
1002
+ "id": "2262b7b4-a2f2-408b-9d4d-362940ca1ed3",
1003
+ "key": "abe7afac-952f-4cfc-ab07-47b47f34105f.field",
1004
+ "value": {
1005
+ "rules": [{"type": "CONSTANT_VALUE", "data": {"type": "STRING", "value": "123"}}],
1006
+ "combinator": "OR",
1007
+ },
1008
+ }
1009
+ ],
1010
+ "data": {
1011
+ "label": "Simple Conditional Node",
1012
+ "target_handle_id": "c6e99e94-bc8e-47a4-b75c-cc96c6bedbb0",
1013
+ "conditions": [
1014
+ {
1015
+ "id": "a4c32611-fd58-4b98-9d08-313cfd1c214e",
1016
+ "type": "IF",
1017
+ "source_handle_id": "8124a6cf-4a34-4149-adc0-68696c11bd4e",
1018
+ "data": {
1019
+ "id": "650e7105-3e76-43ca-858f-b290970b438b",
1020
+ "rules": [
1021
+ {
1022
+ "id": "abe7afac-952f-4cfc-ab07-47b47f34105f",
1023
+ "rules": None,
1024
+ "combinator": None,
1025
+ "negated": False,
1026
+ "field_node_input_id": "2262b7b4-a2f2-408b-9d4d-362940ca1ed3",
1027
+ "operator": f"{operator}",
1028
+ "value_node_input_id": None,
1029
+ }
1030
+ ],
1031
+ "combinator": "AND",
1032
+ "negated": False,
1033
+ "field_node_input_id": None,
1034
+ "operator": None,
1035
+ "value_node_input_id": None,
1036
+ },
1037
+ }
1038
+ ],
1039
+ "version": "2",
1040
+ },
1041
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
1042
+ "definition": {
1043
+ "bases": [
1044
+ {
1045
+ "module": [
1046
+ "vellum",
1047
+ "workflows",
1048
+ "nodes",
1049
+ "displayable",
1050
+ "conditional_node",
1051
+ "node",
1052
+ ],
1053
+ "name": "ConditionalNode",
1054
+ }
1055
+ ],
1056
+ "module": [
1057
+ "tests",
1058
+ "workflows",
1059
+ "basic_conditional_node",
1060
+ "workflow_with_only_one_conditional_node",
1061
+ ],
1062
+ "name": "SimpleConditionalNode",
1063
+ },
1064
+ },
1065
+ conditional_node,
1066
+ ignore_order=True,
1067
+ )
1068
+
1069
+
1070
+ @pytest.mark.parametrize("descriptor, operator", descriptors_with_value_and_start_and_end())
1071
+ def test_conditional_node_serialize_all_operators_with_value_and_start_and_end(descriptor, operator):
1072
+ # GIVEN a simple workflow with one conditional node
1073
+ workflow_cls = create_simple_workflow(descriptor)
1074
+
1075
+ workflow_display = get_workflow_display(base_display_class=VellumWorkflowDisplay, workflow_class=workflow_cls)
1076
+
1077
+ # TODO: Support serialization of BaseNode
1078
+ # https://app.shortcut.com/vellum/story/4871/support-serialization-of-base-node
1079
+ with mock.patch.object(BaseNodeVellumDisplay, "serialize") as mocked_serialize:
1080
+ mocked_serialize.return_value = {"type": "MOCKED"}
1081
+ serialized_workflow: dict = workflow_display.serialize()
1082
+
1083
+ # THEN we should get a serialized representation of the Workflow
1084
+ assert serialized_workflow.keys() == {
1085
+ "workflow_raw_data",
1086
+ "input_variables",
1087
+ "output_variables",
1088
+ }
1089
+
1090
+ # AND its raw data should be what we expect
1091
+ workflow_raw_data = serialized_workflow["workflow_raw_data"]
1092
+ assert workflow_raw_data.keys() == {"edges", "nodes", "display_data", "definition"}
1093
+
1094
+ # AND the conditional node should be what we expect
1095
+ conditional_node = workflow_raw_data["nodes"][1]
1096
+ assert not DeepDiff(
1097
+ {
1098
+ "id": "a9143814-6bb0-4cb3-a817-4fc076417121",
1099
+ "type": "CONDITIONAL",
1100
+ "inputs": [
1101
+ {
1102
+ "id": "2262b7b4-a2f2-408b-9d4d-362940ca1ed3",
1103
+ "key": "abe7afac-952f-4cfc-ab07-47b47f34105f.field",
1104
+ "value": {
1105
+ "rules": [{"type": "CONSTANT_VALUE", "data": {"type": "STRING", "value": "123"}}],
1106
+ "combinator": "OR",
1107
+ },
1108
+ },
1109
+ {
1110
+ "id": "aadade8a-c253-483a-8620-31fe8171c0fd",
1111
+ "key": "abe7afac-952f-4cfc-ab07-47b47f34105f.value",
1112
+ "value": {
1113
+ "rules": [{"type": "CONSTANT_VALUE", "data": {"type": "STRING", "value": "123,123"}}],
1114
+ "combinator": "OR",
1115
+ },
1116
+ },
1117
+ ],
1118
+ "data": {
1119
+ "label": "Simple Conditional Node",
1120
+ "target_handle_id": "c6e99e94-bc8e-47a4-b75c-cc96c6bedbb0",
1121
+ "conditions": [
1122
+ {
1123
+ "id": "a4c32611-fd58-4b98-9d08-313cfd1c214e",
1124
+ "type": "IF",
1125
+ "source_handle_id": "8124a6cf-4a34-4149-adc0-68696c11bd4e",
1126
+ "data": {
1127
+ "id": "650e7105-3e76-43ca-858f-b290970b438b",
1128
+ "rules": [
1129
+ {
1130
+ "id": "abe7afac-952f-4cfc-ab07-47b47f34105f",
1131
+ "rules": None,
1132
+ "combinator": None,
1133
+ "negated": False,
1134
+ "field_node_input_id": "2262b7b4-a2f2-408b-9d4d-362940ca1ed3",
1135
+ "operator": f"{operator}",
1136
+ "value_node_input_id": "aadade8a-c253-483a-8620-31fe8171c0fd",
1137
+ }
1138
+ ],
1139
+ "combinator": "AND",
1140
+ "negated": False,
1141
+ "field_node_input_id": None,
1142
+ "operator": None,
1143
+ "value_node_input_id": None,
1144
+ },
1145
+ }
1146
+ ],
1147
+ "version": "2",
1148
+ },
1149
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
1150
+ "definition": {
1151
+ "bases": [
1152
+ {
1153
+ "module": [
1154
+ "vellum",
1155
+ "workflows",
1156
+ "nodes",
1157
+ "displayable",
1158
+ "conditional_node",
1159
+ "node",
1160
+ ],
1161
+ "name": "ConditionalNode",
1162
+ }
1163
+ ],
1164
+ "module": [
1165
+ "tests",
1166
+ "workflows",
1167
+ "basic_conditional_node",
1168
+ "workflow_with_only_one_conditional_node",
1169
+ ],
1170
+ "name": "SimpleConditionalNode",
1171
+ },
1172
+ },
1173
+ conditional_node,
1174
+ ignore_order=True,
1175
+ )