vellum-ai 0.9.16rc2__py3-none-any.whl → 0.9.16rc4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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.9.16rc4.dist-info}/METADATA +2 -1
  179. {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.9.16rc4.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.9.16rc4.dist-info}/LICENSE +0 -0
  244. {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.9.16rc4.dist-info}/WHEEL +0 -0
  245. {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.9.16rc4.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)}")