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,170 @@
1
+ from uuid import UUID
2
+ from typing import Any, ClassVar, Dict, Generic, List, Optional, Tuple, Type, TypeVar, Union, cast
3
+
4
+ from vellum import PromptBlock, RichTextChildBlock, VellumVariable
5
+
6
+ from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
7
+ from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
8
+ from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
9
+ from vellum_ee.workflows.display.types import WorkflowDisplayContext
10
+ from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
11
+ from vellum_ee.workflows.display.utils.vellum import infer_vellum_variable_type
12
+ from vellum_ee.workflows.display.vellum import NodeInput
13
+ from vellum.workflows.nodes import InlinePromptNode
14
+ from vellum.workflows.references import OutputReference
15
+ from vellum.workflows.types.core import JsonObject
16
+
17
+ _InlinePromptNodeType = TypeVar("_InlinePromptNodeType", bound=InlinePromptNode)
18
+
19
+
20
+ class BaseInlinePromptNodeDisplay(BaseNodeVellumDisplay[_InlinePromptNodeType], Generic[_InlinePromptNodeType]):
21
+ output_id: ClassVar[Optional[UUID]] = None
22
+ array_output_id: ClassVar[Optional[UUID]] = None
23
+ prompt_input_ids_by_name: ClassVar[Dict[str, UUID]] = {}
24
+
25
+ def serialize(
26
+ self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs: Any
27
+ ) -> JsonObject:
28
+ node = self._node
29
+ node_id = self.node_id
30
+
31
+ node_inputs, prompt_inputs = self._generate_node_and_prompt_inputs(node_id, node, display_context)
32
+ input_variable_id_by_name = {prompt_input.key: prompt_input.id for prompt_input in prompt_inputs}
33
+
34
+ _, output_display = display_context.node_output_displays[cast(OutputReference, node.Outputs.text)]
35
+ _, array_display = display_context.node_output_displays[cast(OutputReference, node.Outputs.results)]
36
+ node_blocks = raise_if_descriptor(node.blocks)
37
+
38
+ return {
39
+ "id": str(node_id),
40
+ "type": "PROMPT",
41
+ "inputs": [node_input.dict() for node_input in node_inputs],
42
+ "data": {
43
+ "label": self.label,
44
+ "output_id": str(output_display.id),
45
+ "error_output_id": str(error_output_id) if error_output_id else None,
46
+ "array_output_id": str(array_display.id),
47
+ "source_handle_id": str(self.get_source_handle_id(display_context.port_displays)),
48
+ "target_handle_id": str(self.get_target_handle_id()),
49
+ "variant": "INLINE",
50
+ "exec_config": {
51
+ "parameters": raise_if_descriptor(node.parameters).dict(),
52
+ "input_variables": [prompt_input.dict() for prompt_input in prompt_inputs],
53
+ "prompt_template_block_data": {
54
+ "version": 1,
55
+ "blocks": [
56
+ self._generate_prompt_block(block, input_variable_id_by_name, [i])
57
+ for i, block in enumerate(node_blocks)
58
+ ],
59
+ },
60
+ },
61
+ "ml_model_name": raise_if_descriptor(node.ml_model),
62
+ },
63
+ "display_data": self.get_display_data().dict(),
64
+ "definition": self.get_definition().dict(),
65
+ }
66
+
67
+ def _generate_node_and_prompt_inputs(
68
+ self,
69
+ node_id: UUID,
70
+ node: Type[InlinePromptNode],
71
+ display_context: WorkflowDisplayContext,
72
+ ) -> Tuple[List[NodeInput], List[VellumVariable]]:
73
+ value = raise_if_descriptor(node.prompt_inputs)
74
+
75
+ node_inputs: List[NodeInput] = []
76
+ prompt_inputs: List[VellumVariable] = []
77
+
78
+ for variable_name, variable_value in value.items():
79
+ node_input = create_node_input(
80
+ node_id=node_id,
81
+ input_name=variable_name,
82
+ value=variable_value,
83
+ display_context=display_context,
84
+ input_id=self.prompt_input_ids_by_name.get(variable_name),
85
+ )
86
+ vellum_variable_type = infer_vellum_variable_type(variable_value)
87
+ node_inputs.append(node_input)
88
+ prompt_inputs.append(VellumVariable(id=str(node_input.id), key=variable_name, type=vellum_variable_type))
89
+
90
+ return node_inputs, prompt_inputs
91
+
92
+ def _generate_prompt_block(
93
+ self,
94
+ prompt_block: Union[PromptBlock, RichTextChildBlock],
95
+ input_variable_id_by_name: Dict[str, str],
96
+ path: List[int],
97
+ ) -> JsonObject:
98
+ block: JsonObject
99
+ if prompt_block.block_type == "JINJA":
100
+ block = {
101
+ "block_type": "JINJA",
102
+ "properties": {"template": prompt_block.template, "template_type": "STRING"},
103
+ }
104
+
105
+ elif prompt_block.block_type == "CHAT_MESSAGE":
106
+ chat_properties: JsonObject = {
107
+ "chat_role": prompt_block.chat_role,
108
+ "chat_source": prompt_block.chat_source,
109
+ "blocks": [
110
+ self._generate_prompt_block(block, input_variable_id_by_name, path + [i])
111
+ for i, block in enumerate(prompt_block.blocks)
112
+ ],
113
+ }
114
+ if prompt_block.chat_message_unterminated is not None:
115
+ chat_properties["chat_message_unterminated"] = prompt_block.chat_message_unterminated
116
+
117
+ block = {
118
+ "block_type": "CHAT_MESSAGE",
119
+ "properties": chat_properties,
120
+ }
121
+
122
+ elif prompt_block.block_type == "FUNCTION_DEFINITION":
123
+ block = {
124
+ "block_type": "FUNCTION_DEFINITION",
125
+ "properties": {
126
+ "function_name": prompt_block.function_name,
127
+ "function_description": prompt_block.function_description,
128
+ "function_parameters": prompt_block.function_parameters,
129
+ "function_forced": prompt_block.function_forced,
130
+ "function_strict": prompt_block.function_strict,
131
+ },
132
+ }
133
+
134
+ elif prompt_block.block_type == "VARIABLE":
135
+ block = {
136
+ "block_type": "VARIABLE",
137
+ "input_variable_id": input_variable_id_by_name[prompt_block.input_variable],
138
+ }
139
+
140
+ elif prompt_block.block_type == "PLAIN_TEXT":
141
+ block = {
142
+ "block_type": "PLAIN_TEXT",
143
+ "text": prompt_block.text,
144
+ }
145
+
146
+ elif prompt_block.block_type == "RICH_TEXT":
147
+ block = {
148
+ "block_type": "RICH_TEXT",
149
+ "blocks": [
150
+ self._generate_prompt_block(child, input_variable_id_by_name, path + [i])
151
+ for i, child in enumerate(prompt_block.blocks)
152
+ ],
153
+ }
154
+ else:
155
+ raise NotImplementedError(f"Serialization for prompt block type {prompt_block.block_type} not implemented")
156
+
157
+ block["id"] = str(
158
+ uuid4_from_hash(f"{self.node_id}-{prompt_block.block_type}-{'-'.join([str(i) for i in path])}")
159
+ )
160
+ if prompt_block.cache_config:
161
+ block["cache_config"] = prompt_block.cache_config.dict()
162
+ else:
163
+ block["cache_config"] = None
164
+
165
+ if prompt_block.state:
166
+ block["state"] = prompt_block.state
167
+ else:
168
+ block["state"] = "ENABLED"
169
+
170
+ return block
@@ -0,0 +1,99 @@
1
+ from uuid import UUID
2
+ from typing import Any, ClassVar, Dict, Generic, List, Optional, Tuple, Type, TypeVar
3
+
4
+ from vellum import VellumVariable
5
+
6
+ from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
7
+ from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
8
+ from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
9
+ from vellum_ee.workflows.display.types import WorkflowDisplayContext
10
+ from vellum_ee.workflows.display.utils.vellum import infer_vellum_variable_type
11
+ from vellum_ee.workflows.display.vellum import NodeInput
12
+ from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
13
+ from vellum.workflows.nodes import InlineSubworkflowNode
14
+ from vellum.workflows.types.core import JsonObject
15
+
16
+ _InlineSubworkflowNodeType = TypeVar("_InlineSubworkflowNodeType", bound=InlineSubworkflowNode)
17
+
18
+
19
+ class BaseInlineSubworkflowNodeDisplay(
20
+ BaseNodeVellumDisplay[_InlineSubworkflowNodeType], Generic[_InlineSubworkflowNodeType]
21
+ ):
22
+ workflow_input_ids_by_name: ClassVar[Dict[str, UUID]] = {}
23
+
24
+ def serialize(
25
+ self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs: Any
26
+ ) -> JsonObject:
27
+ node = self._node
28
+ node_id = self.node_id
29
+
30
+ node_inputs, workflow_inputs = self._generate_node_and_workflow_inputs(node_id, node, display_context)
31
+ workflow_outputs = self._generate_workflow_outputs(node)
32
+
33
+ subworkflow_display = get_workflow_display(
34
+ base_display_class=display_context.workflow_display_class,
35
+ workflow_class=raise_if_descriptor(node.subworkflow),
36
+ parent_display_context=display_context,
37
+ )
38
+ serialized_subworkflow = subworkflow_display.serialize()
39
+
40
+ return {
41
+ "id": str(node_id),
42
+ "type": "SUBWORKFLOW",
43
+ "inputs": [node_input.dict() for node_input in node_inputs],
44
+ "data": {
45
+ "label": self.label,
46
+ "error_output_id": str(error_output_id) if error_output_id else None,
47
+ "source_handle_id": str(self.get_source_handle_id(display_context.port_displays)),
48
+ "target_handle_id": str(self.get_target_handle_id()),
49
+ "variant": "INLINE",
50
+ "workflow_raw_data": serialized_subworkflow["workflow_raw_data"],
51
+ "input_variables": [workflow_input.dict() for workflow_input in workflow_inputs],
52
+ "output_variables": [workflow_output.dict() for workflow_output in workflow_outputs],
53
+ },
54
+ "display_data": self.get_display_data().dict(),
55
+ "definition": self.get_definition().dict(),
56
+ }
57
+
58
+ def _generate_node_and_workflow_inputs(
59
+ self,
60
+ node_id: UUID,
61
+ node: Type[InlineSubworkflowNode],
62
+ display_context: WorkflowDisplayContext,
63
+ ) -> Tuple[List[NodeInput], List[VellumVariable]]:
64
+ subworkflow_inputs = raise_if_descriptor(node.subworkflow_inputs)
65
+ node_inputs = [
66
+ create_node_input(
67
+ node_id=node_id,
68
+ input_name=variable_name,
69
+ value=variable_value,
70
+ display_context=display_context,
71
+ input_id=self.workflow_input_ids_by_name.get(variable_name),
72
+ )
73
+ for variable_name, variable_value in subworkflow_inputs.items()
74
+ ]
75
+ node_inputs_by_key = {node_input.key: node_input for node_input in node_inputs}
76
+ workflow_inputs = [
77
+ VellumVariable(
78
+ id=node_inputs_by_key[descriptor.name].id,
79
+ key=descriptor.name,
80
+ type=infer_vellum_variable_type(descriptor),
81
+ )
82
+ for descriptor in raise_if_descriptor(node.subworkflow).get_inputs_class()
83
+ ]
84
+
85
+ return node_inputs, workflow_inputs
86
+
87
+ def _generate_workflow_outputs(
88
+ self,
89
+ node: Type[InlineSubworkflowNode],
90
+ ) -> List[VellumVariable]:
91
+ workflow_outputs: List[VellumVariable] = []
92
+ for output_descriptor in raise_if_descriptor(node.subworkflow).Outputs: # type: ignore[union-attr]
93
+ node_output_display = self.get_node_output_display(output_descriptor)
94
+ output_type = infer_vellum_variable_type(output_descriptor)
95
+ workflow_outputs.append(
96
+ VellumVariable(id=str(node_output_display.id), key=node_output_display.name, type=output_type)
97
+ )
98
+
99
+ return workflow_outputs
@@ -0,0 +1,100 @@
1
+ from uuid import UUID
2
+ from typing import Any, ClassVar, Dict, Generic, List, Optional, Type, TypeVar
3
+
4
+ from vellum import VellumVariable
5
+
6
+ from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
7
+ from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
8
+ from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
9
+ from vellum_ee.workflows.display.types import WorkflowDisplayContext
10
+ from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
11
+ from vellum_ee.workflows.display.utils.vellum import infer_vellum_variable_type
12
+ from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
13
+ from vellum.workflows.nodes import MapNode
14
+ from vellum.workflows.types.core import JsonObject
15
+
16
+ _MapNodeType = TypeVar("_MapNodeType", bound=MapNode)
17
+
18
+
19
+ class BaseMapNodeDisplay(BaseNodeVellumDisplay[_MapNodeType], Generic[_MapNodeType]):
20
+ workflow_input_ids_by_name: ClassVar[Dict[str, UUID]] = {}
21
+
22
+ def serialize(
23
+ self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs: Any
24
+ ) -> JsonObject:
25
+ node = self._node
26
+ node_id = self.node_id
27
+
28
+ workflow_inputs: List[VellumVariable] = []
29
+ subworkflow = raise_if_descriptor(node.subworkflow)
30
+ for descriptor in subworkflow.get_inputs_class():
31
+ # In WaC it's always 'all_items'
32
+ # In Vellum it's always 'items'
33
+ variable_name = descriptor.name if descriptor.name != "all_items" else "items"
34
+ variable_id = str(
35
+ self.workflow_input_ids_by_name.get(variable_name) or uuid4_from_hash(f"{self.node_id}|{variable_name}")
36
+ )
37
+ workflow_inputs.append(
38
+ VellumVariable(
39
+ id=variable_id,
40
+ key=variable_name,
41
+ type=infer_vellum_variable_type(descriptor),
42
+ )
43
+ )
44
+
45
+ items_workflow_input = next(input for input in workflow_inputs if input.key == "items")
46
+ item_workflow_input = next(input for input in workflow_inputs if input.key == "item")
47
+ index_workflow_input = next(input for input in workflow_inputs if input.key == "index")
48
+
49
+ workflow_outputs = self._generate_workflow_outputs(node)
50
+
51
+ items_node_input = create_node_input(
52
+ node_id=node_id,
53
+ input_name="items",
54
+ value=node.items,
55
+ display_context=display_context,
56
+ input_id=UUID(items_workflow_input.id),
57
+ )
58
+ node_inputs = [items_node_input]
59
+
60
+ subworkflow_display = get_workflow_display(
61
+ base_display_class=display_context.workflow_display_class,
62
+ workflow_class=subworkflow,
63
+ )
64
+ serialized_subworkflow = subworkflow_display.serialize()
65
+
66
+ return {
67
+ "id": str(node_id),
68
+ "type": "MAP",
69
+ "inputs": [node_input.dict() for node_input in node_inputs],
70
+ "data": {
71
+ "label": self.label,
72
+ "error_output_id": str(error_output_id) if error_output_id else None,
73
+ "source_handle_id": str(self.get_source_handle_id(display_context.port_displays)),
74
+ "target_handle_id": str(self.get_target_handle_id()),
75
+ "variant": "INLINE",
76
+ "workflow_raw_data": serialized_subworkflow["workflow_raw_data"],
77
+ "input_variables": [workflow_input.dict() for workflow_input in workflow_inputs],
78
+ "output_variables": [workflow_output.dict() for workflow_output in workflow_outputs],
79
+ "concurrency": raise_if_descriptor(node.concurrency),
80
+ "items_input_id": str(items_workflow_input.id),
81
+ "item_input_id": str(item_workflow_input.id),
82
+ "index_input_id": str(index_workflow_input.id),
83
+ },
84
+ "display_data": self.get_display_data().dict(),
85
+ "definition": self.get_definition().dict(),
86
+ }
87
+
88
+ def _generate_workflow_outputs(
89
+ self,
90
+ node: Type[MapNode],
91
+ ) -> List[VellumVariable]:
92
+ workflow_outputs: List[VellumVariable] = []
93
+ for output_descriptor in raise_if_descriptor(node.subworkflow).Outputs: # type: ignore[union-attr]
94
+ node_output_display = self.get_node_output_display(output_descriptor)
95
+ output_type = infer_vellum_variable_type(output_descriptor)
96
+ workflow_outputs.append(
97
+ VellumVariable(id=str(node_output_display.id), key=node_output_display.name, type=output_type)
98
+ )
99
+
100
+ return workflow_outputs
@@ -0,0 +1,48 @@
1
+ from uuid import UUID
2
+ from typing import Any, ClassVar, Generic, List, Optional, TypeVar
3
+
4
+ from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
5
+ from vellum_ee.workflows.display.types import WorkflowDisplayContext
6
+ from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
7
+ from vellum_ee.workflows.display.vellum import EdgeVellumDisplay
8
+ from vellum.workflows.nodes.displayable import MergeNode
9
+ from vellum.workflows.types.core import JsonObject
10
+
11
+ _MergeNodeType = TypeVar("_MergeNodeType", bound=MergeNode)
12
+
13
+
14
+ class BaseMergeNodeDisplay(BaseNodeVellumDisplay[_MergeNodeType], Generic[_MergeNodeType]):
15
+ target_handle_ids: ClassVar[List[UUID]]
16
+
17
+ def serialize(self, display_context: WorkflowDisplayContext, **kwargs: Any) -> JsonObject:
18
+ node = self._node
19
+ node_id = self.node_id
20
+
21
+ all_edges: List[EdgeVellumDisplay] = [edge_display for _, edge_display in display_context.edge_displays.items()]
22
+ merged_edges = [edge for edge in all_edges if edge.target_node_id == self.node_id]
23
+
24
+ target_handle_ids = self.get_target_handle_ids()
25
+
26
+ if target_handle_ids is None:
27
+ target_handle_ids = [
28
+ uuid4_from_hash(f"{node_id}|target_handle|{edge.source_node_id}") for edge in merged_edges
29
+ ]
30
+ elif len(target_handle_ids) != len(merged_edges):
31
+ raise ValueError("If you explicitly specify target_handle_ids, you must specify one for each incoming edge")
32
+
33
+ return {
34
+ "id": str(node_id),
35
+ "type": "MERGE",
36
+ "inputs": [],
37
+ "data": {
38
+ "label": self.label,
39
+ "merge_strategy": node.Trigger.merge_behavior.value,
40
+ "target_handles": [{"id": str(target_handle_id)} for target_handle_id in target_handle_ids],
41
+ "source_handle_id": str(self.get_source_handle_id(display_context.port_displays)),
42
+ },
43
+ "display_data": self.get_display_data().dict(),
44
+ "definition": self.get_definition().dict(),
45
+ }
46
+
47
+ def get_target_handle_ids(self) -> Optional[List[UUID]]:
48
+ return self._get_explicit_node_display_attr("target_handle_ids", List[UUID])
@@ -0,0 +1,68 @@
1
+ from uuid import UUID
2
+ from typing import Any, ClassVar, Dict, Generic, Optional, TypeVar, cast
3
+
4
+ from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
5
+ from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
6
+ from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
7
+ from vellum_ee.workflows.display.types import WorkflowDisplayContext
8
+ from vellum.workflows.nodes.displayable.prompt_deployment_node import PromptDeploymentNode
9
+ from vellum.workflows.references import OutputReference
10
+ from vellum.workflows.types.core import JsonObject
11
+ from vellum.workflows.vellum_client import create_vellum_client
12
+
13
+ _PromptDeploymentNodeType = TypeVar("_PromptDeploymentNodeType", bound=PromptDeploymentNode)
14
+
15
+
16
+ class BasePromptDeploymentNodeDisplay(
17
+ BaseNodeVellumDisplay[_PromptDeploymentNodeType], Generic[_PromptDeploymentNodeType]
18
+ ):
19
+ output_id: ClassVar[Optional[UUID]] = None
20
+ array_output_id: ClassVar[Optional[UUID]] = None
21
+ prompt_input_ids_by_name: ClassVar[Dict[str, UUID]] = {}
22
+
23
+ def serialize(
24
+ self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs: Any
25
+ ) -> JsonObject:
26
+ node = self._node
27
+ node_id = self.node_id
28
+
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
+ ]
40
+
41
+ _, output_display = display_context.node_output_displays[cast(OutputReference, node.Outputs.text)]
42
+ _, array_display = display_context.node_output_displays[cast(OutputReference, node.Outputs.results)]
43
+
44
+ # TODO: Pass through the name instead of retrieving the ID
45
+ # https://app.shortcut.com/vellum/story/4702
46
+ vellum_client = create_vellum_client()
47
+ deployment = vellum_client.deployments.retrieve(
48
+ id=str(raise_if_descriptor(node.deployment)),
49
+ )
50
+
51
+ return {
52
+ "id": str(node_id),
53
+ "type": "PROMPT",
54
+ "inputs": [node_input.dict() for node_input in node_inputs],
55
+ "data": {
56
+ "label": self.label,
57
+ "output_id": str(output_display.id),
58
+ "error_output_id": str(error_output_id) if error_output_id else None,
59
+ "array_output_id": str(array_display.id),
60
+ "source_handle_id": str(self.get_source_handle_id(display_context.port_displays)),
61
+ "target_handle_id": str(self.get_target_handle_id()),
62
+ "variant": "DEPLOYMENT",
63
+ "prompt_deployment_id": str(deployment.id),
64
+ "release_tag": raise_if_descriptor(node.release_tag),
65
+ },
66
+ "display_data": self.get_display_data().dict(),
67
+ "definition": self.get_definition().dict(),
68
+ }
@@ -0,0 +1,193 @@
1
+ from dataclasses import dataclass
2
+ from uuid import UUID
3
+ from typing import Any, Dict, Generic, List, Optional, Tuple, Type, TypeVar, Union, cast
4
+
5
+ from vellum import (
6
+ MetadataFilterConfigRequest,
7
+ VellumValueLogicalConditionGroupRequest,
8
+ VellumValueLogicalConditionRequest,
9
+ )
10
+
11
+ from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
12
+ from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
13
+ from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
14
+ from vellum_ee.workflows.display.types import WorkflowDisplayContext
15
+ from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
16
+ from vellum_ee.workflows.display.vellum import NodeInput
17
+ from vellum.workflows.nodes.displayable.search_node import SearchNode
18
+ from vellum.workflows.references import OutputReference
19
+ from vellum.workflows.types.core import JsonArray, JsonObject
20
+
21
+ _SearchNodeType = TypeVar("_SearchNodeType", bound=SearchNode)
22
+
23
+
24
+ @dataclass
25
+ class VariableIdMap:
26
+ id: Optional[UUID]
27
+ lhs: Optional["VariableIdMap"]
28
+ rhs: Optional["VariableIdMap"]
29
+
30
+
31
+ class BaseSearchNodeDisplay(BaseNodeVellumDisplay[_SearchNodeType], Generic[_SearchNodeType]):
32
+ variable_ids: Optional[VariableIdMap] = None
33
+
34
+ def serialize(
35
+ self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs: Any
36
+ ) -> JsonObject:
37
+ node = self._node
38
+ node_id = self.node_id
39
+ node_inputs = self._generate_search_node_inputs(node_id, node, display_context)
40
+
41
+ _, results_output_display = display_context.node_output_displays[cast(OutputReference, node.Outputs.results)]
42
+ _, text_output_display = display_context.node_output_displays[cast(OutputReference, node.Outputs.text)]
43
+
44
+ return {
45
+ "id": str(node_id),
46
+ "type": "SEARCH",
47
+ "inputs": [node_input.dict() for node_input in node_inputs.values()],
48
+ "data": {
49
+ "label": self.label,
50
+ "results_output_id": str(results_output_display.id),
51
+ "text_output_id": str(text_output_display.id),
52
+ "error_output_id": str(error_output_id) if error_output_id else None,
53
+ "source_handle_id": str(self.get_source_handle_id(display_context.port_displays)),
54
+ "target_handle_id": str(self.get_target_handle_id()),
55
+ "query_node_input_id": str(node_inputs["query"].id),
56
+ "document_index_node_input_id": str(node_inputs["document_index_id"].id),
57
+ "weights_node_input_id": str(node_inputs["weights"].id),
58
+ "limit_node_input_id": str(node_inputs["limit"].id),
59
+ "separator_node_input_id": str(node_inputs["separator"].id),
60
+ "result_merging_enabled_node_input_id": str(node_inputs["result_merging_enabled"].id),
61
+ "external_id_filters_node_input_id": str(node_inputs["external_id_filters"].id),
62
+ "metadata_filters_node_input_id": str(node_inputs["metadata_filters"].id),
63
+ },
64
+ "display_data": self.get_display_data().dict(),
65
+ "definition": self.get_definition().dict(),
66
+ }
67
+
68
+ def _generate_search_node_inputs(
69
+ self,
70
+ node_id: UUID,
71
+ node: Type[SearchNode],
72
+ display_context: WorkflowDisplayContext,
73
+ ) -> Dict[str, NodeInput]:
74
+ node_inputs: Dict[str, NodeInput] = {}
75
+
76
+ options = raise_if_descriptor(node.options)
77
+ filters = options.filters if options else None
78
+
79
+ if filters and filters.external_ids:
80
+ # TODO: Add support for serializing external ID filters
81
+ # https://app.shortcut.com/vellum/story/5563/add-support-for-serializing-external-id-in-text-search-nodes
82
+ raise NotImplementedError("Serializing External ID filters is not yet supported")
83
+
84
+ raw_metadata_filters = filters.metadata if filters else None
85
+ metadata_filters = None
86
+ metadata_filters_node_inputs: list[NodeInput] = []
87
+ if raw_metadata_filters:
88
+ if isinstance(raw_metadata_filters, MetadataFilterConfigRequest):
89
+ raise ValueError(
90
+ "MetadataFilterConfigRequest is deprecated. Please use VellumValueLogicalExpressionRequest instead."
91
+ )
92
+ metadata_filters, metadata_filters_node_inputs = self._serialize_logical_expression(
93
+ raw_metadata_filters, display_context=display_context
94
+ )
95
+
96
+ result_merging = options.result_merging if options else None
97
+ result_merging_enabled = True if result_merging and result_merging.enabled else False
98
+
99
+ weights = options.weights if options else None
100
+
101
+ node_input_names_and_values = [
102
+ ("query", node.query),
103
+ ("document_index_id", node.document_index),
104
+ ("weights", weights.dict() if weights else None),
105
+ ("limit", options.limit if options else None),
106
+ ("separator", raise_if_descriptor(node.chunk_separator)),
107
+ (
108
+ "result_merging_enabled",
109
+ ("True" if result_merging_enabled else "False"),
110
+ ),
111
+ ("external_id_filters", None),
112
+ ("metadata_filters", metadata_filters),
113
+ ]
114
+
115
+ for node_input_name, node_input_value in node_input_names_and_values:
116
+ node_input = create_node_input(
117
+ node_id,
118
+ node_input_name,
119
+ node_input_value,
120
+ display_context,
121
+ input_id=self.node_input_ids_by_name.get(node_input_name),
122
+ )
123
+ node_inputs[node_input_name] = node_input
124
+
125
+ for node_input in metadata_filters_node_inputs:
126
+ node_inputs[node_input.key] = node_input
127
+
128
+ return node_inputs
129
+
130
+ def _serialize_logical_expression(
131
+ self,
132
+ logical_expression: Union[VellumValueLogicalConditionGroupRequest, VellumValueLogicalConditionRequest],
133
+ display_context: WorkflowDisplayContext,
134
+ path: List[int] = [],
135
+ variable_id_map: Optional[VariableIdMap] = None,
136
+ ) -> Tuple[JsonObject, List[NodeInput]]:
137
+ if isinstance(logical_expression, VellumValueLogicalConditionGroupRequest):
138
+ conditions: JsonArray = []
139
+ variables = []
140
+ for idx, condition in enumerate(logical_expression.conditions):
141
+ serialized_condition, serialized_variables = self._serialize_logical_expression(
142
+ condition, display_context=display_context, path=path + [idx]
143
+ )
144
+ conditions.append(serialized_condition)
145
+ variables.extend(serialized_variables)
146
+
147
+ return (
148
+ {
149
+ "type": "LOGICAL_CONDITION_GROUP",
150
+ "combinator": logical_expression.combinator,
151
+ "conditions": conditions,
152
+ "negated": logical_expression.negated,
153
+ },
154
+ variables,
155
+ )
156
+ elif isinstance(logical_expression, VellumValueLogicalConditionRequest):
157
+ lhs_variable_id = (
158
+ variable_id_map.lhs.id
159
+ if variable_id_map and variable_id_map.lhs and variable_id_map.lhs.id
160
+ else uuid4_from_hash(f"{self.node_id}|{hash(tuple(path))}|lhs")
161
+ )
162
+ rhs_variable_id = (
163
+ variable_id_map.rhs.id
164
+ if variable_id_map and variable_id_map.rhs and variable_id_map.rhs.id
165
+ else uuid4_from_hash(f"{self.node_id}|{hash(tuple(path))}|rhs")
166
+ )
167
+
168
+ return (
169
+ {
170
+ "type": "LOGICAL_CONDITION",
171
+ "lhs": str(lhs_variable_id),
172
+ "operator": logical_expression.operator,
173
+ "rhs": str(rhs_variable_id),
174
+ },
175
+ [
176
+ create_node_input(
177
+ self.node_id,
178
+ f"vellum-query-builder-variable-{lhs_variable_id}",
179
+ logical_expression.lhs_variable.value,
180
+ display_context,
181
+ input_id=lhs_variable_id,
182
+ ),
183
+ create_node_input(
184
+ self.node_id,
185
+ f"vellum-query-builder-variable-{rhs_variable_id}",
186
+ logical_expression.rhs_variable.value,
187
+ display_context,
188
+ input_id=rhs_variable_id,
189
+ ),
190
+ ],
191
+ )
192
+ else:
193
+ raise ValueError(f"Unsupported logical expression type: {type(logical_expression)}")