vellum-ai 1.11.2__py3-none-any.whl → 1.13.5__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.

Potentially problematic release.


This version of vellum-ai might be problematic. Click here for more details.

Files changed (275) hide show
  1. vellum/__init__.py +18 -0
  2. vellum/client/README.md +1 -1
  3. vellum/client/core/client_wrapper.py +2 -2
  4. vellum/client/core/force_multipart.py +4 -2
  5. vellum/client/core/http_response.py +1 -1
  6. vellum/client/core/pydantic_utilities.py +7 -4
  7. vellum/client/errors/too_many_requests_error.py +1 -2
  8. vellum/client/reference.md +677 -76
  9. vellum/client/resources/container_images/client.py +299 -0
  10. vellum/client/resources/container_images/raw_client.py +286 -0
  11. vellum/client/resources/documents/client.py +20 -10
  12. vellum/client/resources/documents/raw_client.py +20 -10
  13. vellum/client/resources/events/raw_client.py +4 -4
  14. vellum/client/resources/integration_auth_configs/client.py +2 -0
  15. vellum/client/resources/integration_auth_configs/raw_client.py +2 -0
  16. vellum/client/resources/integration_providers/client.py +28 -2
  17. vellum/client/resources/integration_providers/raw_client.py +24 -0
  18. vellum/client/resources/integrations/client.py +52 -4
  19. vellum/client/resources/integrations/raw_client.py +61 -0
  20. vellum/client/resources/workflow_deployments/client.py +156 -0
  21. vellum/client/resources/workflow_deployments/raw_client.py +334 -0
  22. vellum/client/resources/workflows/client.py +212 -8
  23. vellum/client/resources/workflows/raw_client.py +343 -6
  24. vellum/client/types/__init__.py +18 -0
  25. vellum/client/types/api_actor_type_enum.py +1 -1
  26. vellum/client/types/check_workflow_execution_status_error.py +21 -0
  27. vellum/client/types/check_workflow_execution_status_response.py +29 -0
  28. vellum/client/types/code_execution_package_request.py +21 -0
  29. vellum/client/types/composio_execute_tool_request.py +5 -0
  30. vellum/client/types/composio_tool_definition.py +1 -0
  31. vellum/client/types/container_image_build_config.py +1 -0
  32. vellum/client/types/container_image_container_image_tag.py +1 -0
  33. vellum/client/types/dataset_row_push_request.py +3 -0
  34. vellum/client/types/document_document_to_document_index.py +1 -0
  35. vellum/client/types/integration_name.py +24 -0
  36. vellum/client/types/node_execution_fulfilled_body.py +1 -0
  37. vellum/client/types/node_execution_log_body.py +24 -0
  38. vellum/client/types/node_execution_log_event.py +47 -0
  39. vellum/client/types/prompt_deployment_release_prompt_deployment.py +1 -0
  40. vellum/client/types/runner_config_request.py +24 -0
  41. vellum/client/types/severity_enum.py +5 -0
  42. vellum/client/types/slim_composio_tool_definition.py +1 -0
  43. vellum/client/types/slim_document_document_to_document_index.py +2 -0
  44. vellum/client/types/type_checker_enum.py +5 -0
  45. vellum/client/types/vellum_audio.py +5 -1
  46. vellum/client/types/vellum_audio_request.py +5 -1
  47. vellum/client/types/vellum_document.py +5 -1
  48. vellum/client/types/vellum_document_request.py +5 -1
  49. vellum/client/types/vellum_image.py +5 -1
  50. vellum/client/types/vellum_image_request.py +5 -1
  51. vellum/client/types/vellum_node_execution_event.py +2 -0
  52. vellum/client/types/vellum_variable.py +5 -0
  53. vellum/client/types/vellum_variable_extensions.py +1 -0
  54. vellum/client/types/vellum_variable_type.py +1 -0
  55. vellum/client/types/vellum_video.py +5 -1
  56. vellum/client/types/vellum_video_request.py +5 -1
  57. vellum/client/types/workflow_deployment_release_workflow_deployment.py +1 -0
  58. vellum/client/types/workflow_event.py +2 -0
  59. vellum/client/types/workflow_execution_fulfilled_body.py +1 -0
  60. vellum/client/types/workflow_result_event_output_data_array.py +1 -1
  61. vellum/client/types/workflow_result_event_output_data_chat_history.py +1 -1
  62. vellum/client/types/workflow_result_event_output_data_error.py +1 -1
  63. vellum/client/types/workflow_result_event_output_data_function_call.py +1 -1
  64. vellum/client/types/workflow_result_event_output_data_json.py +1 -1
  65. vellum/client/types/workflow_result_event_output_data_number.py +1 -1
  66. vellum/client/types/workflow_result_event_output_data_search_results.py +1 -1
  67. vellum/client/types/workflow_result_event_output_data_string.py +1 -1
  68. vellum/client/types/workflow_sandbox_execute_node_response.py +8 -0
  69. vellum/plugins/vellum_mypy.py +37 -2
  70. vellum/types/check_workflow_execution_status_error.py +3 -0
  71. vellum/types/check_workflow_execution_status_response.py +3 -0
  72. vellum/types/code_execution_package_request.py +3 -0
  73. vellum/types/node_execution_log_body.py +3 -0
  74. vellum/types/node_execution_log_event.py +3 -0
  75. vellum/types/runner_config_request.py +3 -0
  76. vellum/types/severity_enum.py +3 -0
  77. vellum/types/type_checker_enum.py +3 -0
  78. vellum/types/workflow_sandbox_execute_node_response.py +3 -0
  79. vellum/utils/files/mixin.py +26 -0
  80. vellum/utils/files/tests/test_mixin.py +62 -0
  81. vellum/utils/tests/test_vellum_client.py +95 -0
  82. vellum/utils/uuid.py +19 -2
  83. vellum/utils/vellum_client.py +10 -3
  84. vellum/workflows/__init__.py +7 -1
  85. vellum/workflows/descriptors/base.py +86 -0
  86. vellum/workflows/descriptors/tests/test_utils.py +9 -0
  87. vellum/workflows/errors/tests/__init__.py +0 -0
  88. vellum/workflows/errors/tests/test_types.py +52 -0
  89. vellum/workflows/errors/types.py +1 -0
  90. vellum/workflows/events/node.py +24 -0
  91. vellum/workflows/events/tests/test_event.py +123 -0
  92. vellum/workflows/events/types.py +2 -1
  93. vellum/workflows/events/workflow.py +28 -2
  94. vellum/workflows/expressions/add.py +3 -0
  95. vellum/workflows/expressions/tests/test_add.py +24 -0
  96. vellum/workflows/graph/graph.py +26 -5
  97. vellum/workflows/graph/tests/test_graph.py +228 -1
  98. vellum/workflows/inputs/base.py +22 -6
  99. vellum/workflows/inputs/dataset_row.py +121 -16
  100. vellum/workflows/inputs/tests/test_inputs.py +3 -3
  101. vellum/workflows/integrations/tests/test_vellum_integration_service.py +84 -0
  102. vellum/workflows/integrations/vellum_integration_service.py +12 -1
  103. vellum/workflows/loaders/base.py +2 -0
  104. vellum/workflows/nodes/bases/base.py +37 -16
  105. vellum/workflows/nodes/bases/tests/test_base_node.py +104 -1
  106. vellum/workflows/nodes/core/inline_subworkflow_node/node.py +1 -0
  107. vellum/workflows/nodes/core/inline_subworkflow_node/tests/test_node.py +1 -1
  108. vellum/workflows/nodes/core/map_node/node.py +7 -5
  109. vellum/workflows/nodes/core/map_node/tests/test_node.py +33 -0
  110. vellum/workflows/nodes/core/retry_node/node.py +1 -0
  111. vellum/workflows/nodes/core/try_node/node.py +1 -0
  112. vellum/workflows/nodes/displayable/api_node/node.py +3 -2
  113. vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py +38 -0
  114. vellum/workflows/nodes/displayable/bases/api_node/node.py +1 -1
  115. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +18 -1
  116. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +109 -2
  117. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +13 -2
  118. vellum/workflows/nodes/displayable/code_execution_node/node.py +9 -15
  119. vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py +65 -24
  120. vellum/workflows/nodes/displayable/code_execution_node/utils.py +3 -0
  121. vellum/workflows/nodes/displayable/final_output_node/node.py +24 -69
  122. vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py +53 -3
  123. vellum/workflows/nodes/displayable/note_node/node.py +4 -1
  124. vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +16 -5
  125. vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +47 -0
  126. vellum/workflows/nodes/displayable/tool_calling_node/node.py +74 -34
  127. vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py +204 -8
  128. vellum/workflows/nodes/displayable/tool_calling_node/utils.py +92 -71
  129. vellum/workflows/nodes/mocks.py +47 -213
  130. vellum/workflows/nodes/tests/test_mocks.py +0 -177
  131. vellum/workflows/nodes/utils.py +23 -8
  132. vellum/workflows/outputs/base.py +36 -3
  133. vellum/workflows/references/environment_variable.py +1 -11
  134. vellum/workflows/references/lazy.py +8 -0
  135. vellum/workflows/references/state_value.py +24 -1
  136. vellum/workflows/references/tests/test_lazy.py +58 -0
  137. vellum/workflows/references/trigger.py +8 -3
  138. vellum/workflows/references/workflow_input.py +8 -0
  139. vellum/workflows/resolvers/resolver.py +13 -3
  140. vellum/workflows/resolvers/tests/test_resolver.py +31 -0
  141. vellum/workflows/runner/runner.py +159 -14
  142. vellum/workflows/runner/tests/__init__.py +0 -0
  143. vellum/workflows/runner/tests/test_runner.py +170 -0
  144. vellum/workflows/sandbox.py +7 -8
  145. vellum/workflows/state/base.py +89 -30
  146. vellum/workflows/state/context.py +74 -3
  147. vellum/workflows/state/tests/test_state.py +269 -1
  148. vellum/workflows/tests/test_dataset_row.py +8 -7
  149. vellum/workflows/tests/test_sandbox.py +97 -8
  150. vellum/workflows/triggers/__init__.py +2 -1
  151. vellum/workflows/triggers/base.py +160 -28
  152. vellum/workflows/triggers/chat_message.py +141 -0
  153. vellum/workflows/triggers/integration.py +12 -0
  154. vellum/workflows/triggers/manual.py +3 -1
  155. vellum/workflows/triggers/schedule.py +3 -1
  156. vellum/workflows/triggers/tests/test_chat_message.py +257 -0
  157. vellum/workflows/types/core.py +18 -0
  158. vellum/workflows/types/definition.py +6 -13
  159. vellum/workflows/types/generics.py +12 -0
  160. vellum/workflows/types/tests/test_utils.py +12 -0
  161. vellum/workflows/types/utils.py +32 -2
  162. vellum/workflows/types/workflow_metadata.py +124 -0
  163. vellum/workflows/utils/functions.py +152 -16
  164. vellum/workflows/utils/pydantic_schema.py +19 -1
  165. vellum/workflows/utils/tests/test_functions.py +123 -8
  166. vellum/workflows/utils/tests/test_validate.py +79 -0
  167. vellum/workflows/utils/tests/test_vellum_variables.py +62 -2
  168. vellum/workflows/utils/uuids.py +90 -0
  169. vellum/workflows/utils/validate.py +108 -0
  170. vellum/workflows/utils/vellum_variables.py +96 -16
  171. vellum/workflows/workflows/base.py +177 -35
  172. vellum/workflows/workflows/tests/test_base_workflow.py +51 -0
  173. {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/METADATA +6 -1
  174. {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/RECORD +274 -227
  175. vellum_cli/__init__.py +21 -0
  176. vellum_cli/config.py +16 -2
  177. vellum_cli/pull.py +2 -0
  178. vellum_cli/push.py +23 -10
  179. vellum_cli/tests/conftest.py +8 -13
  180. vellum_cli/tests/test_image_push.py +4 -11
  181. vellum_cli/tests/test_pull.py +83 -68
  182. vellum_cli/tests/test_push.py +251 -2
  183. vellum_ee/assets/node-definitions.json +225 -12
  184. vellum_ee/scripts/generate_node_definitions.py +15 -3
  185. vellum_ee/workflows/display/base.py +4 -3
  186. vellum_ee/workflows/display/nodes/base_node_display.py +44 -11
  187. vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +93 -0
  188. vellum_ee/workflows/display/nodes/types.py +1 -0
  189. vellum_ee/workflows/display/nodes/vellum/__init__.py +0 -2
  190. vellum_ee/workflows/display/nodes/vellum/base_adornment_node.py +5 -2
  191. vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +1 -1
  192. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +10 -2
  193. vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +17 -14
  194. vellum_ee/workflows/display/nodes/vellum/map_node.py +2 -0
  195. vellum_ee/workflows/display/nodes/vellum/note_node.py +18 -3
  196. vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +37 -14
  197. vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py +62 -2
  198. vellum_ee/workflows/display/nodes/vellum/tests/test_final_output_node.py +136 -0
  199. vellum_ee/workflows/display/nodes/vellum/tests/test_note_node.py +44 -7
  200. vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py +5 -13
  201. vellum_ee/workflows/display/nodes/vellum/tests/test_subworkflow_deployment_node.py +27 -17
  202. vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py +145 -22
  203. vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +107 -2
  204. vellum_ee/workflows/display/nodes/vellum/utils.py +54 -12
  205. vellum_ee/workflows/display/tests/test_base_workflow_display.py +13 -16
  206. vellum_ee/workflows/display/tests/test_json_schema_validation.py +190 -0
  207. vellum_ee/workflows/display/tests/test_mocks.py +912 -0
  208. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +14 -2
  209. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +109 -0
  210. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +3 -0
  211. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +187 -1
  212. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +34 -325
  213. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +42 -393
  214. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +13 -315
  215. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_state_serialization.py +2 -122
  216. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +24 -115
  217. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py +4 -93
  218. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +7 -80
  219. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +9 -101
  220. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +77 -308
  221. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +62 -324
  222. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +3 -82
  223. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +4 -142
  224. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py +1 -61
  225. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_set_state_node_serialization.py +4 -4
  226. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +205 -134
  227. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py +34 -146
  228. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +2 -0
  229. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_composio_serialization.py +8 -6
  230. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +137 -266
  231. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_tool_wrapper_serialization.py +84 -0
  232. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_mcp_serialization.py +55 -16
  233. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +15 -1
  234. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_tool_wrapper_serialization.py +71 -0
  235. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_vellum_integration_serialization.py +119 -0
  236. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py +1 -1
  237. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +0 -2
  238. vellum_ee/workflows/display/tests/workflow_serialization/test_chat_message_dict_reference_serialization.py +22 -1
  239. vellum_ee/workflows/display/tests/workflow_serialization/test_chat_message_trigger_serialization.py +412 -0
  240. vellum_ee/workflows/display/tests/workflow_serialization/test_code_tool_node_reference_error.py +106 -0
  241. vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +9 -41
  242. vellum_ee/workflows/display/tests/workflow_serialization/test_duplicate_trigger_name_validation.py +208 -0
  243. vellum_ee/workflows/display/tests/workflow_serialization/test_final_output_node_not_referenced_by_workflow_outputs.py +45 -0
  244. vellum_ee/workflows/display/tests/workflow_serialization/test_infinite_loop_validation.py +66 -0
  245. vellum_ee/workflows/display/tests/workflow_serialization/test_int_input_serialization.py +40 -0
  246. vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_serialization.py +8 -14
  247. vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_validation.py +173 -0
  248. vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_with_entrypoint_node_id.py +16 -13
  249. vellum_ee/workflows/display/tests/workflow_serialization/test_list_vellum_document_serialization.py +5 -1
  250. vellum_ee/workflows/display/tests/workflow_serialization/test_manual_trigger_serialization.py +12 -2
  251. vellum_ee/workflows/display/tests/workflow_serialization/test_multi_trigger_same_node_serialization.py +111 -0
  252. vellum_ee/workflows/display/tests/workflow_serialization/test_no_triggers_no_entrypoint_validation.py +64 -0
  253. vellum_ee/workflows/display/tests/workflow_serialization/test_partial_workflow_meta_display_override.py +55 -0
  254. vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_dataset_mocks_serialization.py +268 -0
  255. vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_invalid_pdf_data_url.py +49 -0
  256. vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_validation_errors.py +112 -0
  257. vellum_ee/workflows/display/tests/workflow_serialization/test_scheduled_trigger_serialization.py +25 -16
  258. vellum_ee/workflows/display/tests/workflow_serialization/test_terminal_node_in_unused_graphs_serialization.py +53 -0
  259. vellum_ee/workflows/display/utils/exceptions.py +34 -0
  260. vellum_ee/workflows/display/utils/expressions.py +463 -52
  261. vellum_ee/workflows/display/utils/metadata.py +98 -33
  262. vellum_ee/workflows/display/utils/tests/test_metadata.py +31 -0
  263. vellum_ee/workflows/display/utils/triggers.py +153 -0
  264. vellum_ee/workflows/display/utils/vellum.py +59 -5
  265. vellum_ee/workflows/display/workflows/base_workflow_display.py +656 -254
  266. vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +26 -0
  267. vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +77 -29
  268. vellum_ee/workflows/server/namespaces.py +18 -0
  269. vellum_ee/workflows/tests/test_display_meta.py +2 -0
  270. vellum_ee/workflows/tests/test_serialize_module.py +174 -7
  271. vellum_ee/workflows/tests/test_server.py +0 -3
  272. vellum_ee/workflows/display/nodes/vellum/function_node.py +0 -14
  273. {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/LICENSE +0 -0
  274. {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/WHEEL +0 -0
  275. {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,10 @@
1
+ import importlib
2
+ import re
1
3
  import types
2
4
  from typing import TYPE_CHECKING, Generic, Optional, Type, TypeVar
3
5
 
4
6
  from vellum.client import Vellum as VellumClient
7
+ from vellum.workflows import BaseWorkflow
5
8
  from vellum.workflows.types.generics import WorkflowType
6
9
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
7
10
  from vellum_ee.workflows.display.utils.registry import get_from_workflow_display_registry
@@ -10,6 +13,28 @@ if TYPE_CHECKING:
10
13
  from vellum_ee.workflows.display.workflows import BaseWorkflowDisplay
11
14
 
12
15
 
16
+ def _ensure_display_module_imported(workflow_class: Type[WorkflowType]) -> None:
17
+ """
18
+ Best-effort import of the workflow's display module to ensure any custom
19
+ WorkflowDisplay subclass is registered before we look it up in the registry.
20
+
21
+ This allows workflows to work without a display/__init__.py file that
22
+ re-exports from .workflow and .nodes.
23
+ """
24
+ module_name = workflow_class.__module__
25
+
26
+ if module_name == BaseWorkflow.__module__:
27
+ return
28
+
29
+ if module_name.endswith(".workflow"):
30
+ root = re.sub(r"\.workflow$", "", module_name)
31
+ display_workflow_module = f"{root}.display.workflow"
32
+ try:
33
+ importlib.import_module(display_workflow_module)
34
+ except ImportError:
35
+ pass
36
+
37
+
13
38
  def _get_workflow_display_class(*, workflow_class: Type[WorkflowType]) -> Type["BaseWorkflowDisplay"]:
14
39
  workflow_display_class = get_from_workflow_display_registry(workflow_class)
15
40
  if workflow_display_class:
@@ -42,6 +67,7 @@ def get_workflow_display(
42
67
  root_workflow_class: Optional[Type[WorkflowType]] = None,
43
68
  base_display_class: Optional[Type["BaseWorkflowDisplay"]] = None,
44
69
  ) -> "BaseWorkflowDisplay":
70
+ _ensure_display_module_imported(workflow_class)
45
71
  return _get_workflow_display_class(workflow_class=workflow_class)(
46
72
  parent_display_context=parent_display_context,
47
73
  client=client,
@@ -11,6 +11,7 @@ from vellum.workflows.nodes.core.try_node.node import TryNode
11
11
  from vellum.workflows.nodes.displayable.final_output_node.node import FinalOutputNode
12
12
  from vellum.workflows.references.lazy import LazyReference
13
13
  from vellum.workflows.state.base import BaseState
14
+ from vellum.workflows.triggers.integration import IntegrationTrigger
14
15
  from vellum.workflows.types.core import JsonObject
15
16
  from vellum.workflows.workflows.base import BaseWorkflow
16
17
  from vellum_ee.workflows.display.editor.types import NodeDisplayData, NodeDisplayPosition
@@ -18,6 +19,7 @@ from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
18
19
  from vellum_ee.workflows.display.nodes.vellum.retry_node import BaseRetryNodeDisplay
19
20
  from vellum_ee.workflows.display.nodes.vellum.try_node import BaseTryNodeDisplay
20
21
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
22
+ from vellum_ee.workflows.display.utils.exceptions import UserFacingException
21
23
  from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
22
24
 
23
25
 
@@ -41,7 +43,7 @@ def test_serialize_workflow__node_referenced_in_workflow_outputs_not_in_graph():
41
43
  workflow_display = get_workflow_display(workflow_class=Workflow)
42
44
 
43
45
  # THEN it should raise an error
44
- with pytest.raises(ValueError) as exc_info:
46
+ with pytest.raises(UserFacingException) as exc_info:
45
47
  workflow_display.serialize()
46
48
 
47
49
  # AND the error message should be user friendly
@@ -61,17 +63,31 @@ def test_serialize_workflow__workflow_outputs_reference_non_node_outputs():
61
63
 
62
64
  # WHEN we serialize it
63
65
  workflow_display = get_workflow_display(workflow_class=Workflow)
66
+ serialized_workflow = workflow_display.serialize()
67
+
68
+ # THEN it should successfully serialize the workflow output reference to a constant
69
+ assert isinstance(serialized_workflow, dict)
70
+ output_variables = serialized_workflow["output_variables"]
71
+ assert isinstance(output_variables, list)
72
+ assert output_variables == [{"id": "2b32416b-ccfc-4231-a3a6-d08e76327815", "key": "final", "type": "STRING"}]
73
+
74
+ # AND the output value should be a constant value
75
+ workflow_raw_data = serialized_workflow["workflow_raw_data"]
76
+ assert isinstance(workflow_raw_data, dict)
77
+ output_values = workflow_raw_data["output_values"]
78
+ assert isinstance(output_values, list)
79
+ assert output_values == [
80
+ {
81
+ "output_variable_id": "2b32416b-ccfc-4231-a3a6-d08e76327815",
82
+ "value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "bar"}},
83
+ }
84
+ ]
64
85
 
65
- # THEN it should raise an error
66
- with pytest.raises(ValueError) as exc_info:
67
- workflow_display.serialize()
68
-
69
- # AND the error message should be user friendly
70
- assert (
71
- str(exc_info.value)
72
- == """Failed to serialize output 'final': Reference to outputs \
73
- 'test_serialize_workflow__workflow_outputs_reference_non_node_outputs.<locals>.FirstWorkflow.Outputs' is invalid."""
74
- )
86
+ first_output_variable = output_variables[0]
87
+ assert isinstance(first_output_variable, dict)
88
+ first_output_value = output_values[0]
89
+ assert isinstance(first_output_value, dict)
90
+ assert first_output_variable["id"] == first_output_value["output_variable_id"]
75
91
 
76
92
 
77
93
  def test_serialize_workflow__node_display_class_not_registered():
@@ -288,6 +304,38 @@ def test_get_event_display_context__workflow_output_display_with_none():
288
304
  assert display_context.workflow_outputs.keys() == {"foo", "bar"}
289
305
 
290
306
 
307
+ def test_get_event_display_context__trigger_attributes_included():
308
+ """Trigger attributes should be included in workflow_inputs for display in executions list."""
309
+
310
+ # GIVEN a workflow with an integration trigger that has attributes
311
+ class SlackTrigger(IntegrationTrigger):
312
+ message: str
313
+ channel: str
314
+
315
+ class Config:
316
+ provider = "COMPOSIO"
317
+ integration_name = "SLACK"
318
+ slug = "slack_new_message"
319
+
320
+ class ProcessNode(BaseNode):
321
+ pass
322
+
323
+ class MyWorkflow(BaseWorkflow):
324
+ graph = SlackTrigger >> ProcessNode
325
+
326
+ # WHEN we gather the event display context
327
+ display_context = get_workflow_display(workflow_class=MyWorkflow).get_event_display_context()
328
+
329
+ # THEN the trigger attributes should be included in workflow_inputs
330
+ assert "message" in display_context.workflow_inputs
331
+ assert "channel" in display_context.workflow_inputs
332
+
333
+ # AND the IDs should match the trigger attribute IDs
334
+ trigger_attr_refs = SlackTrigger.attribute_references()
335
+ assert display_context.workflow_inputs["message"] == trigger_attr_refs["message"].id
336
+ assert display_context.workflow_inputs["channel"] == trigger_attr_refs["channel"].id
337
+
338
+
291
339
  def test_serialize_workflow__inherited_node_display_class_not_registered():
292
340
  # GIVEN a node meant to be used as a base
293
341
  class StartNode(BaseNode):
@@ -528,8 +576,14 @@ def test_serialize_workflow__array_reference():
528
576
  # THEN it should serialize as an ARRAY_REFERENCE
529
577
  assert isinstance(data["workflow_raw_data"], dict)
530
578
  assert isinstance(data["workflow_raw_data"]["nodes"], list)
531
- assert len(data["workflow_raw_data"]["nodes"]) == 5
532
- second_node = data["workflow_raw_data"]["nodes"][2]
579
+ second_node = next(
580
+ node
581
+ for node in data["workflow_raw_data"]["nodes"]
582
+ if isinstance(node, dict)
583
+ and "definition" in node
584
+ and isinstance(node["definition"], dict)
585
+ and node["definition"]["name"] == "SecondNode"
586
+ )
533
587
  assert isinstance(second_node, dict)
534
588
 
535
589
  assert "outputs" in second_node
@@ -828,17 +882,6 @@ def test_serialize_workflow__empty_rules_indexerror():
828
882
  assert len(output_variables) == 1
829
883
  assert output_variables[0]["key"] == "problematic_output"
830
884
 
831
- # AND the workflow raw data should contain nodes including terminal node
832
- workflow_raw_data = result["workflow_raw_data"]
833
- assert "nodes" in workflow_raw_data
834
- nodes = workflow_raw_data["nodes"]
835
-
836
- assert len(nodes) >= 3
837
-
838
- terminal_nodes = [node for node in nodes if node.get("type") == "TERMINAL"]
839
- assert len(terminal_nodes) == 1
840
- assert terminal_nodes[0]["data"]["name"] == "problematic_output"
841
-
842
885
 
843
886
  def test_serialize_workflow__input_variables():
844
887
  # GIVEN a workflow with inputs
@@ -870,6 +913,7 @@ def test_serialize_workflow__input_variables():
870
913
  "default": {"type": "STRING", "value": ""},
871
914
  "required": False,
872
915
  "extensions": {"color": None},
916
+ "schema": {"type": "string"},
873
917
  }
874
918
 
875
919
  input_1 = next(var for var in input_variables if isinstance(var, dict) and var["key"] == "input_1")
@@ -880,6 +924,7 @@ def test_serialize_workflow__input_variables():
880
924
  "default": None,
881
925
  "required": True,
882
926
  "extensions": {"color": None},
927
+ "schema": {"type": "string"},
883
928
  }
884
929
 
885
930
  input_2 = next(var for var in input_variables if isinstance(var, dict) and var["key"] == "input_2")
@@ -890,6 +935,7 @@ def test_serialize_workflow__input_variables():
890
935
  "default": None,
891
936
  "required": False,
892
937
  "extensions": {"color": None},
938
+ "schema": {"anyOf": [{"type": "string"}, {"type": "null"}]},
893
939
  }
894
940
 
895
941
  input_3 = next(var for var in input_variables if isinstance(var, dict) and var["key"] == "input_3")
@@ -900,6 +946,7 @@ def test_serialize_workflow__input_variables():
900
946
  "default": {"type": "NUMBER", "value": 1.0},
901
947
  "required": False,
902
948
  "extensions": {"color": None},
949
+ "schema": {"type": "integer"},
903
950
  }
904
951
 
905
952
  input_4 = next(var for var in input_variables if isinstance(var, dict) and var["key"] == "input_4")
@@ -910,6 +957,7 @@ def test_serialize_workflow__input_variables():
910
957
  "default": {"type": "NUMBER", "value": 2.0},
911
958
  "required": False,
912
959
  "extensions": {"color": None},
960
+ "schema": {"anyOf": [{"type": "integer"}, {"type": "null"}]},
913
961
  }
914
962
 
915
963
 
@@ -937,7 +985,7 @@ def test_serialize_workflow__state_variables():
937
985
 
938
986
  empty_string = next(var for var in state_variables if isinstance(var, dict) and var["key"] == "empty_string")
939
987
  assert empty_string == {
940
- "id": "0ed1f179-1734-487f-b3ed-9e6026390d90",
988
+ "id": "c69e2507-f610-4a6f-84cc-a5bc2aa48551",
941
989
  "key": "empty_string",
942
990
  "type": "STRING",
943
991
  "default": {"type": "STRING", "value": ""},
@@ -947,7 +995,7 @@ def test_serialize_workflow__state_variables():
947
995
 
948
996
  state_1 = next(var for var in state_variables if isinstance(var, dict) and var["key"] == "state_1")
949
997
  assert state_1 == {
950
- "id": "83c5b71d-56eb-42a5-84df-97e3591370c2",
998
+ "id": "151113d2-9bbf-428d-a1c1-0a9cf4fdedf3",
951
999
  "key": "state_1",
952
1000
  "type": "STRING",
953
1001
  "default": {"type": "STRING", "value": "hello"},
@@ -957,7 +1005,7 @@ def test_serialize_workflow__state_variables():
957
1005
 
958
1006
  state_2 = next(var for var in state_variables if isinstance(var, dict) and var["key"] == "state_2")
959
1007
  assert state_2 == {
960
- "id": "9b0cfeec-aa66-42b3-8f31-aa7eb8ac30ea",
1008
+ "id": "9a8d7a55-8bd2-497d-820c-dee665144a48",
961
1009
  "key": "state_2",
962
1010
  "type": "STRING",
963
1011
  "default": None,
@@ -967,7 +1015,7 @@ def test_serialize_workflow__state_variables():
967
1015
 
968
1016
  state_3 = next(var for var in state_variables if isinstance(var, dict) and var["key"] == "state_3")
969
1017
  assert state_3 == {
970
- "id": "3e19c570-6b46-4eab-ad81-d8d97028496f",
1018
+ "id": "ffde4327-12c4-4c55-82d6-3ab88f0b1037",
971
1019
  "key": "state_3",
972
1020
  "type": "NUMBER",
973
1021
  "default": {"type": "NUMBER", "value": 1.0},
@@ -977,7 +1025,7 @@ def test_serialize_workflow__state_variables():
977
1025
 
978
1026
  state_4 = next(var for var in state_variables if isinstance(var, dict) and var["key"] == "state_4")
979
1027
  assert state_4 == {
980
- "id": "50c735de-f269-4d0a-b511-c9a1104451bb",
1028
+ "id": "2467c1e6-b6aa-42d7-b079-84c8a650fbca",
981
1029
  "key": "state_4",
982
1030
  "type": "NUMBER",
983
1031
  "default": {"type": "NUMBER", "value": 2.0},
@@ -0,0 +1,18 @@
1
+ """Namespace utilities for workflow server."""
2
+
3
+ import random
4
+ import string
5
+
6
+
7
+ def get_random_namespace() -> str:
8
+ """
9
+ Generate a random namespace for virtual file loading.
10
+
11
+ This generates a workflow_tmp_* namespace like vembda uses for loading
12
+ workflows dynamically.
13
+
14
+ Returns:
15
+ A random namespace string in the format "workflow_tmp_{random_suffix}"
16
+ """
17
+ random_suffix = "".join(random.choices(string.ascii_letters + string.digits, k=16))
18
+ return f"workflow_tmp_{random_suffix}"
@@ -16,6 +16,8 @@ def files() -> dict[str, str]:
16
16
 
17
17
  for root, _, filenames in os.walk(base_directory):
18
18
  for filename in filenames:
19
+ if filename.endswith(".pyc"):
20
+ continue
19
21
  file_path = os.path.join(root, filename)
20
22
  # Key will be the relative path inside `local_files`
21
23
  relative_path = str(os.path.relpath(file_path, start=base_directory))
@@ -11,6 +11,8 @@ from pytest_mock import MockerFixture
11
11
  from vellum.workflows.exceptions import WorkflowInitializationException
12
12
  from vellum_ee.workflows.display.workflows.base_workflow_display import BaseWorkflowDisplay
13
13
 
14
+ from tests.workflows.test_node_output_mock_when_conditions.workflow import ProcessNode
15
+
14
16
 
15
17
  @pytest.fixture
16
18
  def temp_module_path():
@@ -66,7 +68,7 @@ def test_serialize_module_with_actual_dataset():
66
68
  assert result.dataset[1]["inputs"]["message"] == "DatasetRow Test"
67
69
 
68
70
 
69
- def test_serialize_module_with_actual_dataset_with_trigger(metadata_trigger_factory):
71
+ def test_serialize_module_with_actual_dataset_with_scheduled_trigger(metadata_trigger_factory):
70
72
  """Test that serialize_module correctly serializes dataset with trigger"""
71
73
  module_path = "tests.workflows.test_dataset_with_trigger_serialization"
72
74
 
@@ -84,6 +86,12 @@ def test_serialize_module_with_actual_dataset_with_trigger(metadata_trigger_fact
84
86
  assert result.dataset[0]["label"] == "Scenario 1"
85
87
  assert result.dataset[0]["workflow_trigger_id"] == str(metadata_trigger_id)
86
88
 
89
+ inputs = result.dataset[0]["inputs"]
90
+ assert len(inputs) == 2
91
+
92
+ assert "current_run_at" in inputs
93
+ assert "next_run_at" in inputs
94
+
87
95
 
88
96
  def test_serialize_module_happy_path():
89
97
  """Test that serialize_module works with a valid module path."""
@@ -100,34 +108,82 @@ def test_serialize_module_happy_path():
100
108
  assert "output_variables" in result.exec_config
101
109
 
102
110
 
111
+ def test_serialize_module__includes_runner_config():
112
+ """
113
+ Tests that serialize_module includes runner_config in exec_config.
114
+ """
115
+ # GIVEN a valid module path without metadata.json runner_config
116
+ module_path = "tests.workflows.trivial"
117
+
118
+ # WHEN we serialize the module
119
+ result = BaseWorkflowDisplay.serialize_module(module_path)
120
+
121
+ # THEN the exec_config should contain runner_config
122
+ assert "runner_config" in result.exec_config
123
+
124
+ # AND runner_config should be an empty dict when no metadata.json runner_config exists
125
+ runner_config = result.exec_config["runner_config"]
126
+ assert isinstance(runner_config, dict)
127
+
128
+
129
+ def test_serialize_module__runner_config_from_metadata():
130
+ """
131
+ Tests that serialize_module reads runner_config from metadata.json.
132
+ """
133
+ # GIVEN a module path with metadata.json containing runner_config
134
+ module_path = "ee.vellum_ee.workflows.tests.local_workflow"
135
+
136
+ # WHEN we serialize the module
137
+ result = BaseWorkflowDisplay.serialize_module(module_path)
138
+
139
+ # THEN the exec_config should contain runner_config
140
+ assert "runner_config" in result.exec_config
141
+
142
+ # AND runner_config should be a dict (loaded from metadata.json)
143
+ runner_config = result.exec_config["runner_config"]
144
+ assert isinstance(runner_config, dict)
145
+
146
+
103
147
  def test_serialize_module_includes_additional_files():
104
- """Test that serialize_module includes additional files from the module directory."""
148
+ """
149
+ Tests that serialize_module includes only Python files from the module directory.
150
+
151
+ Non-Python files (like .txt) should be excluded from additional_files.
152
+ """
153
+ # GIVEN a module path with additional files including both .py and non-.py files
105
154
  module_path = "tests.workflows.module_with_additional_files"
106
155
 
156
+ # WHEN we serialize the module
107
157
  result = BaseWorkflowDisplay.serialize_module(module_path)
108
158
 
159
+ # THEN the result should have the expected structure
109
160
  assert hasattr(result, "exec_config")
110
161
  assert hasattr(result, "errors")
111
162
  assert isinstance(result.exec_config, dict)
112
163
  assert isinstance(result.errors, list)
113
164
 
165
+ # AND module_data should contain additional_files
114
166
  assert "module_data" in result.exec_config
115
167
  assert "additional_files" in result.exec_config["module_data"]
116
168
 
117
169
  additional_files = result.exec_config["module_data"]["additional_files"]
118
170
  assert isinstance(additional_files, dict)
119
171
 
172
+ # AND Python helper files should be included
120
173
  assert "helper.py" in additional_files
121
- assert "data.txt" in additional_files
122
174
  assert "utils/constants.py" in additional_files
175
+ assert "utils/__init__.py" in additional_files
176
+
177
+ # AND non-Python files should NOT be included
178
+ assert "data.txt" not in additional_files
123
179
 
180
+ # AND serialized workflow files should NOT be included
124
181
  assert "workflow.py" not in additional_files
125
182
  assert "__init__.py" not in additional_files
126
- assert "utils/__init__.py" in additional_files
127
183
  assert "nodes/test_node.py" not in additional_files
128
184
 
185
+ # AND the Python file contents should be correct
129
186
  assert "def helper_function():" in additional_files["helper.py"]
130
- assert "sample data file" in additional_files["data.txt"]
131
187
  assert "CONSTANT_VALUE" in additional_files["utils/constants.py"]
132
188
 
133
189
 
@@ -154,7 +210,11 @@ def test_serialize_module_with_pydantic_array():
154
210
  items_input = input_variables[0]
155
211
  assert items_input["key"] == "items"
156
212
  assert items_input["type"] == "JSON"
157
- # TODO: In the future, this should be a custom type based on an OpenAPI schema (important-comment)
213
+ # The schema field now includes the OpenAPI spec for the input type
214
+ assert items_input["schema"] == {
215
+ "type": "array",
216
+ "items": {"$ref": "#/$defs/tests.workflows.pydantic_array_serialization.workflow.CustomItem"},
217
+ }
158
218
 
159
219
  assert result.dataset is not None
160
220
  assert isinstance(result.dataset, list)
@@ -204,7 +264,8 @@ def test_serialize_module_with_dataset_row_id_from_metadata():
204
264
 
205
265
  assert result.dataset[2]["label"] == "Scenario 3 without ID"
206
266
  assert result.dataset[2]["inputs"]["message"] == "No ID"
207
- assert "id" not in result.dataset[2]
267
+ # AND the third row should have a deterministic hash-based ID since it has no explicit ID
268
+ assert result.dataset[2]["id"] == "cc40aa9b-179a-43fc-8fda-d40ea8a8e300"
208
269
 
209
270
 
210
271
  def test_serialize_module_with_base_inputs_and_metadata():
@@ -231,6 +292,112 @@ def test_serialize_module_with_base_inputs_and_metadata():
231
292
  assert result.dataset[1]["id"] == "base-inputs-id-2"
232
293
 
233
294
 
295
+ def test_serialize_module_with_node_output_mock_when_conditions():
296
+ """
297
+ Tests that serialize_module correctly serializes node output mocks with when conditions.
298
+
299
+ Verifies that when conditions involving workflow inputs and node execution counters
300
+ are properly serialized in the dataset.
301
+ """
302
+ module_path = "tests.workflows.test_node_output_mock_when_conditions"
303
+
304
+ # WHEN we serialize the module
305
+ result = BaseWorkflowDisplay.serialize_module(module_path)
306
+
307
+ assert hasattr(result, "dataset")
308
+ assert result.dataset is not None
309
+ assert isinstance(result.dataset, list)
310
+ assert len(result.dataset) == 2
311
+
312
+ first_scenario = result.dataset[0]
313
+ assert first_scenario["label"] == "Scenario 1"
314
+ assert first_scenario["inputs"]["threshold"] == 5
315
+
316
+ assert "mocks" in first_scenario
317
+ assert isinstance(first_scenario["mocks"], list)
318
+ assert len(first_scenario["mocks"]) == 2
319
+
320
+ first_mock = first_scenario["mocks"][0]
321
+ workflow_input_id = first_mock["when_condition"]["lhs"]["lhs"]["input_variable_id"]
322
+ node_id = str(ProcessNode.__id__)
323
+
324
+ assert first_mock == {
325
+ "type": "NODE_EXECUTION",
326
+ "node_id": node_id,
327
+ "when_condition": {
328
+ "type": "BINARY_EXPRESSION",
329
+ "lhs": {
330
+ "type": "BINARY_EXPRESSION",
331
+ "lhs": {"type": "WORKFLOW_INPUT", "input_variable_id": workflow_input_id},
332
+ "operator": "=",
333
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 5.0}},
334
+ },
335
+ "operator": "and",
336
+ "rhs": {
337
+ "type": "BINARY_EXPRESSION",
338
+ "lhs": {"type": "EXECUTION_COUNTER", "node_id": node_id},
339
+ "operator": "=",
340
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 0.0}},
341
+ },
342
+ },
343
+ "then_outputs": {"result": "first_execution_threshold_5"},
344
+ }
345
+
346
+ second_mock = first_scenario["mocks"][1]
347
+ assert second_mock == {
348
+ "type": "NODE_EXECUTION",
349
+ "node_id": node_id,
350
+ "when_condition": {
351
+ "type": "BINARY_EXPRESSION",
352
+ "lhs": {
353
+ "type": "BINARY_EXPRESSION",
354
+ "lhs": {"type": "WORKFLOW_INPUT", "input_variable_id": workflow_input_id},
355
+ "operator": "=",
356
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 5.0}},
357
+ },
358
+ "operator": "and",
359
+ "rhs": {
360
+ "type": "BINARY_EXPRESSION",
361
+ "lhs": {"type": "EXECUTION_COUNTER", "node_id": node_id},
362
+ "operator": "=",
363
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 1.0}},
364
+ },
365
+ },
366
+ "then_outputs": {"result": "second_execution_threshold_5"},
367
+ }
368
+
369
+ second_scenario = result.dataset[1]
370
+ assert second_scenario["label"] == "Scenario 2"
371
+ assert second_scenario["inputs"]["threshold"] == 10
372
+
373
+ assert "mocks" in second_scenario
374
+ assert isinstance(second_scenario["mocks"], list)
375
+ assert len(second_scenario["mocks"]) == 1
376
+
377
+ third_mock = second_scenario["mocks"][0]
378
+ assert third_mock == {
379
+ "type": "NODE_EXECUTION",
380
+ "node_id": node_id,
381
+ "when_condition": {
382
+ "type": "BINARY_EXPRESSION",
383
+ "lhs": {
384
+ "type": "BINARY_EXPRESSION",
385
+ "lhs": {"type": "WORKFLOW_INPUT", "input_variable_id": workflow_input_id},
386
+ "operator": "=",
387
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 10.0}},
388
+ },
389
+ "operator": "and",
390
+ "rhs": {
391
+ "type": "BINARY_EXPRESSION",
392
+ "lhs": {"type": "EXECUTION_COUNTER", "node_id": node_id},
393
+ "operator": "=",
394
+ "rhs": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 0.0}},
395
+ },
396
+ },
397
+ "then_outputs": {"result": "first_execution_threshold_10"},
398
+ }
399
+
400
+
234
401
  def test_serialize_module__with_invalid_nested_set_graph(temp_module_path):
235
402
  """
236
403
  Tests that serialize_module raises a clear user-facing exception for workflows with nested sets in graph attribute.
@@ -945,9 +945,6 @@ from vellum.workflows.nodes import BaseNode
945
945
  class StartNode(BaseNode):
946
946
  class Outputs(BaseNode.Outputs):
947
947
  result: str = "test output"
948
- """,
949
- "display/nodes/__init__.py": """\
950
- from .start_node import StartNodeDisplay
951
948
  """,
952
949
  "display/nodes/start_node.py": """\
953
950
  from uuid import UUID
@@ -1,14 +0,0 @@
1
- from typing import Generic, TypeVar
2
-
3
- from vellum.workflows.nodes.displayable.tool_calling_node.utils import FunctionNode
4
- from vellum_ee.workflows.display.editor.types import NodeDisplayData
5
- from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
6
-
7
- _FunctionNodeType = TypeVar("_FunctionNodeType", bound=FunctionNode)
8
-
9
-
10
- class FunctionNodeDisplay(BaseNodeDisplay[_FunctionNodeType], Generic[_FunctionNodeType]):
11
- display_data = NodeDisplayData(
12
- icon="vellum:icon:rectangle-code",
13
- color="purple",
14
- )