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
@@ -3,7 +3,7 @@
3
3
  import json
4
4
  import os
5
5
  from uuid import UUID
6
- from typing import Dict, Optional, Type
6
+ from typing import Any, Dict, Optional, Tuple, Type
7
7
 
8
8
  from vellum.workflows.nodes.bases.base import BaseNode
9
9
  from vellum.workflows.utils.files import virtual_open
@@ -33,30 +33,69 @@ def find_workflow_root_with_metadata(module_path: str) -> Optional[str]:
33
33
  return None
34
34
 
35
35
 
36
- def load_edges_to_id_mapping(module_path: str) -> Dict[str, str]:
36
+ def _load_workflow_metadata(module_path: str) -> Tuple[Optional[str], Optional[Dict]]:
37
37
  """
38
- Load edge path to ID mapping from metadata.json for a given module.
38
+ Load the full metadata.json content for a given module.
39
39
 
40
- This function searches up the module hierarchy for metadata.json and extracts
41
- the edges_to_id_mapping.
40
+ This function searches up the module hierarchy for metadata.json and loads its content.
42
41
 
43
42
  Args:
44
43
  module_path: The module path to search from (e.g., "workflows.my_workflow")
45
44
 
46
45
  Returns:
47
- Dictionary mapping edge keys to their UUID strings
46
+ A tuple of (workflow_root, metadata_dict). Returns (None, None) if not found.
48
47
  """
49
48
  try:
50
- root = find_workflow_root_with_metadata(module_path)
51
- if not root:
52
- return {}
53
- file_path = os.path.join(root.replace(".", os.path.sep), "metadata.json")
49
+ workflow_root = find_workflow_root_with_metadata(module_path)
50
+ if not workflow_root:
51
+ return None, None
52
+ file_path = os.path.join(workflow_root.replace(".", os.path.sep), "metadata.json")
54
53
  with virtual_open(file_path) as f:
55
54
  data = json.load(f)
56
- edges_map = data.get("edges_to_id_mapping")
57
- return edges_map if isinstance(edges_map, dict) else {}
55
+ return workflow_root, data
58
56
  except Exception:
59
- return {}
57
+ return None, None
58
+
59
+
60
+ def _load_edges_mapping(module_path: str) -> Tuple[Optional[str], Dict[str, str]]:
61
+ """
62
+ Load edge path to ID mapping from metadata.json for a given module.
63
+
64
+ This function searches up the module hierarchy for metadata.json and extracts
65
+ the edges_to_id_mapping.
66
+
67
+ Args:
68
+ module_path: The module path to search from (e.g., "workflows.my_workflow")
69
+
70
+ Returns:
71
+ Dictionary mapping edge keys to their UUID strings
72
+ """
73
+ workflow_root, data = _load_workflow_metadata(module_path)
74
+ if data is None:
75
+ return None, {}
76
+ edges_map = data.get("edges_to_id_mapping")
77
+ if isinstance(edges_map, dict):
78
+ return workflow_root, edges_map
79
+ return workflow_root, {}
80
+
81
+
82
+ def load_edges_to_id_mapping(module_path: str) -> Dict[str, str]:
83
+ _, mapping = _load_edges_mapping(module_path)
84
+ return mapping
85
+
86
+
87
+ def _build_metadata_class_path(module: str, class_name: str, workflow_root: Optional[str]) -> str:
88
+ """
89
+ Format a class path so that it matches the metadata.json key structure.
90
+ """
91
+ if workflow_root:
92
+ if module == workflow_root:
93
+ return f".{class_name}"
94
+ prefix = f"{workflow_root}."
95
+ if module.startswith(prefix):
96
+ relative = module[len(prefix) :]
97
+ return f".{relative}.{class_name}" if relative else f".{class_name}"
98
+ return f"{module}.{class_name}"
60
99
 
61
100
 
62
101
  def get_trigger_edge_id(trigger_cls: Type, target_node: Type[BaseNode], module_path: str) -> Optional[str]:
@@ -71,9 +110,12 @@ def get_trigger_edge_id(trigger_cls: Type, target_node: Type[BaseNode], module_p
71
110
  Returns:
72
111
  The stable edge ID if found in metadata.json, None otherwise
73
112
  """
74
- edges_mapping = load_edges_to_id_mapping(module_path)
75
- trigger_path = f"{trigger_cls.__module__}.{trigger_cls.__name__}"
76
- target_path = f"{target_node.__module__}.{target_node.__name__}.Trigger"
113
+ workflow_root, edges_mapping = _load_edges_mapping(module_path)
114
+ if not edges_mapping:
115
+ return None
116
+ trigger_path = _build_metadata_class_path(trigger_cls.__module__, trigger_cls.__name__, workflow_root)
117
+ target_base = _build_metadata_class_path(target_node.__module__, target_node.__name__, workflow_root)
118
+ target_path = f"{target_base}.Trigger"
77
119
  edge_key = f"{trigger_path}|{target_path}"
78
120
  return edges_mapping.get(edge_key)
79
121
 
@@ -89,9 +131,12 @@ def get_entrypoint_edge_id(target_node: Type[BaseNode], module_path: str) -> Opt
89
131
  Returns:
90
132
  The stable edge ID if found in metadata.json, None otherwise
91
133
  """
92
- edges_mapping = load_edges_to_id_mapping(module_path)
134
+ workflow_root, edges_mapping = _load_edges_mapping(module_path)
135
+ if not edges_mapping:
136
+ return None
93
137
  manual_path = "vellum.workflows.triggers.manual.Manual"
94
- target_path = f"{target_node.__module__}.{target_node.__name__}.Trigger"
138
+ target_base = _build_metadata_class_path(target_node.__module__, target_node.__name__, workflow_root)
139
+ target_path = f"{target_base}.Trigger"
95
140
  edge_key = f"{manual_path}|{target_path}"
96
141
  return edges_mapping.get(edge_key)
97
142
 
@@ -111,9 +156,13 @@ def get_regular_edge_id(
111
156
  Returns:
112
157
  The stable edge ID if found in metadata.json, None otherwise
113
158
  """
114
- edges_mapping = load_edges_to_id_mapping(module_path)
115
- source_path = f"{source_node_cls.__module__}.{source_node_cls.__name__}.Ports.{str(source_handle_id)}"
116
- target_path = f"{target_node.__module__}.{target_node.__name__}.Trigger"
159
+ workflow_root, edges_mapping = _load_edges_mapping(module_path)
160
+ if not edges_mapping:
161
+ return None
162
+ source_base = _build_metadata_class_path(source_node_cls.__module__, source_node_cls.__name__, workflow_root)
163
+ source_path = f"{source_base}.Ports.{str(source_handle_id)}"
164
+ target_base = _build_metadata_class_path(target_node.__module__, target_node.__name__, workflow_root)
165
+ target_path = f"{target_base}.Trigger"
117
166
  edge_key = f"{source_path}|{target_path}"
118
167
  return edges_mapping.get(edge_key)
119
168
 
@@ -131,16 +180,32 @@ def load_dataset_row_index_to_id_mapping(module_path: str) -> Dict[int, str]:
131
180
  Returns:
132
181
  Dictionary mapping dataset row indices (as integers) to their ID strings
133
182
  """
134
- try:
135
- root = find_workflow_root_with_metadata(module_path)
136
- if not root:
137
- return {}
138
- file_path = os.path.join(root.replace(".", os.path.sep), "metadata.json")
139
- with virtual_open(file_path) as f:
140
- data = json.load(f)
141
- mapping = data.get("dataset_row_index_to_id_mapping")
142
- if isinstance(mapping, dict):
143
- return {int(k): v for k, v in mapping.items()}
144
- return {}
145
- except Exception:
183
+ _, data = _load_workflow_metadata(module_path)
184
+ if data is None:
185
+ return {}
186
+ mapping = data.get("dataset_row_index_to_id_mapping")
187
+ if isinstance(mapping, dict):
188
+ return {int(k): v for k, v in mapping.items()}
189
+ return {}
190
+
191
+
192
+ def load_runner_config(module_path: str) -> Dict[str, Any]:
193
+ """
194
+ Load runner_config from metadata.json for a given module.
195
+
196
+ This function searches up the module hierarchy for metadata.json and extracts
197
+ the runner_config.
198
+
199
+ Args:
200
+ module_path: The module path to search from (e.g., "workflows.my_workflow")
201
+
202
+ Returns:
203
+ The runner_config dictionary if found in metadata.json, empty dict otherwise
204
+ """
205
+ _, data = _load_workflow_metadata(module_path)
206
+ if data is None:
146
207
  return {}
208
+ runner_config = data.get("runner_config")
209
+ if isinstance(runner_config, dict):
210
+ return runner_config
211
+ return {}
@@ -0,0 +1,31 @@
1
+ import pytest
2
+
3
+ from vellum_ee.workflows.display.utils.metadata import _build_metadata_class_path
4
+
5
+
6
+ def build_metadata_class_path_test_cases():
7
+ return [
8
+ # (module, class_name, workflow_root, expected)
9
+ ("my_workflow.nodes.my_node", "MyNode", "my_workflow", ".nodes.my_node.MyNode"),
10
+ ("my_workflow", "MyWorkflow", "my_workflow", ".MyWorkflow"),
11
+ ("my_workflow.triggers.scheduled", "ScheduleTrigger", "my_workflow", ".triggers.scheduled.ScheduleTrigger"),
12
+ ("external.module", "ExternalClass", "my_workflow", "external.module.ExternalClass"),
13
+ ("vellum.workflows.triggers.manual", "Manual", "my_workflow", "vellum.workflows.triggers.manual.Manual"),
14
+ ("my_workflow.nodes.my_node", "MyNode", None, "my_workflow.nodes.my_node.MyNode"),
15
+ ]
16
+
17
+
18
+ @pytest.mark.parametrize(
19
+ "module, class_name, workflow_root, expected",
20
+ build_metadata_class_path_test_cases(),
21
+ )
22
+ def test_build_metadata_class_path(module, class_name, workflow_root, expected):
23
+ """
24
+ Tests that _build_metadata_class_path correctly formats class paths relative to workflow root.
25
+ """
26
+ # GIVEN a module path, class name, and workflow root
27
+ # WHEN we build the metadata class path
28
+ result = _build_metadata_class_path(module, class_name, workflow_root)
29
+
30
+ # THEN we should get the expected formatted path
31
+ assert result == expected
@@ -0,0 +1,153 @@
1
+ from typing import Any, Dict, List, Type, cast
2
+
3
+ from vellum.workflows.triggers.base import BaseTrigger
4
+ from vellum.workflows.triggers.chat_message import ChatMessageTrigger
5
+ from vellum.workflows.triggers.integration import IntegrationTrigger
6
+ from vellum.workflows.triggers.manual import ManualTrigger
7
+ from vellum.workflows.triggers.schedule import ScheduleTrigger
8
+ from vellum.workflows.types.core import JsonArray, JsonObject
9
+ from vellum.workflows.utils.vellum_variables import primitive_type_to_vellum_variable_type
10
+ from vellum_ee.workflows.display.base import WorkflowTriggerType
11
+ from vellum_ee.workflows.display.utils.vellum import compile_descriptor_annotation
12
+
13
+
14
+ def get_trigger_type(trigger_class: Type[BaseTrigger]) -> WorkflowTriggerType:
15
+ """Get the WorkflowTriggerType for a trigger class."""
16
+ if issubclass(trigger_class, ManualTrigger):
17
+ return WorkflowTriggerType.MANUAL
18
+ elif issubclass(trigger_class, IntegrationTrigger):
19
+ return WorkflowTriggerType.INTEGRATION
20
+ elif issubclass(trigger_class, ScheduleTrigger):
21
+ return WorkflowTriggerType.SCHEDULED
22
+ elif issubclass(trigger_class, ChatMessageTrigger):
23
+ return WorkflowTriggerType.CHAT_MESSAGE
24
+ else:
25
+ raise ValueError(
26
+ f"Unknown trigger type: {trigger_class.__name__}. "
27
+ f"Please add it to the trigger type mapping in get_trigger_type_mapping()."
28
+ )
29
+
30
+
31
+ def serialize_trigger_attributes(trigger_class: Type[BaseTrigger]) -> JsonArray:
32
+ """Serialize trigger attributes from attribute_references as VellumVariables."""
33
+ attribute_references = trigger_class.attribute_references().values()
34
+
35
+ def get_attribute_type(reference: Any) -> str:
36
+ # We can remove this type ignore with some mypy plugin changes
37
+ message_name = ChatMessageTrigger.message.name # type: ignore[union-attr]
38
+ # For ChatMessageTrigger.message, always return ARRAY to maintain backwards compatibility
39
+ if issubclass(trigger_class, ChatMessageTrigger) and reference.name == message_name:
40
+ return "ARRAY"
41
+ try:
42
+ return primitive_type_to_vellum_variable_type(reference)
43
+ except ValueError:
44
+ return "JSON"
45
+
46
+ trigger_attributes: JsonArray = cast(
47
+ JsonArray,
48
+ [
49
+ cast(
50
+ JsonObject,
51
+ {
52
+ "id": str(reference.id),
53
+ "key": reference.name,
54
+ "type": get_attribute_type(reference),
55
+ "required": type(None) not in reference.types,
56
+ "default": {
57
+ "type": get_attribute_type(reference),
58
+ "value": None,
59
+ },
60
+ "extensions": None,
61
+ "schema": compile_descriptor_annotation(reference),
62
+ },
63
+ )
64
+ for reference in sorted(attribute_references, key=lambda ref: ref.name)
65
+ ],
66
+ )
67
+
68
+ return trigger_attributes
69
+
70
+
71
+ def serialize_trigger_display_data(trigger_class: Type[BaseTrigger], trigger_type: WorkflowTriggerType) -> JsonObject:
72
+ """Serialize display_data from trigger's Display class."""
73
+ display_class = trigger_class.Display
74
+ display_data: JsonObject = {}
75
+
76
+ if hasattr(display_class, "label") and display_class.label is not None:
77
+ display_data["label"] = display_class.label
78
+
79
+ if (
80
+ hasattr(display_class, "x")
81
+ and display_class.x is not None
82
+ and hasattr(display_class, "y")
83
+ and display_class.y is not None
84
+ ):
85
+ display_data["position"] = {
86
+ "x": display_class.x,
87
+ "y": display_class.y,
88
+ }
89
+
90
+ if hasattr(display_class, "z_index") and display_class.z_index is not None:
91
+ display_data["z_index"] = display_class.z_index
92
+
93
+ if hasattr(display_class, "icon") and display_class.icon is not None:
94
+ display_data["icon"] = display_class.icon
95
+
96
+ if hasattr(display_class, "color") and display_class.color is not None:
97
+ display_data["color"] = display_class.color
98
+
99
+ if hasattr(display_class, "comment") and display_class.comment is not None:
100
+ display_data["comment"] = {
101
+ "value": display_class.comment.value,
102
+ "expanded": display_class.comment.expanded,
103
+ }
104
+
105
+ return display_data
106
+
107
+
108
+ def serialize_trigger_definition(trigger_class: Type[BaseTrigger]) -> Dict[str, Any]:
109
+ """
110
+ Serialize a trigger class definition for use in node-definitions.json.
111
+
112
+ This produces a simplified trigger definition that includes:
113
+ - type: The WorkflowTriggerType enum value
114
+ - name: The trigger class name
115
+ - module: The module path as an array
116
+ - attributes: The trigger's attribute references
117
+ - display_data: Optional display metadata (label, icon, color)
118
+ """
119
+ trigger_type = get_trigger_type(trigger_class)
120
+
121
+ definition: Dict[str, Any] = {
122
+ "type": trigger_type.value,
123
+ "name": trigger_class.__name__,
124
+ "module": trigger_class.__module__.split("."),
125
+ "attributes": serialize_trigger_attributes(trigger_class),
126
+ }
127
+
128
+ display_data = serialize_trigger_display_data(trigger_class, trigger_type)
129
+
130
+ # Don't include display_data for manual triggers (consistent with workflow serialization)
131
+ if display_data and trigger_type != WorkflowTriggerType.MANUAL:
132
+ definition["display_data"] = display_data
133
+
134
+ return definition
135
+
136
+
137
+ def get_all_trigger_classes() -> List[Type[BaseTrigger]]:
138
+ """
139
+ Get all trigger classes dynamically from the triggers module.
140
+
141
+ This mirrors the approach used by get_all_displayable_node_classes for nodes.
142
+ """
143
+ import vellum.workflows.triggers as triggers_module
144
+
145
+ trigger_classes = []
146
+ for class_name in triggers_module.__all__:
147
+ trigger_class = getattr(triggers_module, class_name)
148
+ # Skip BaseTrigger itself - we only want concrete trigger types
149
+ if trigger_class is BaseTrigger:
150
+ continue
151
+ if isinstance(trigger_class, type) and issubclass(trigger_class, BaseTrigger):
152
+ trigger_classes.append(trigger_class)
153
+ return trigger_classes
@@ -1,3 +1,4 @@
1
+ import logging
1
2
  from typing import TYPE_CHECKING, Any, Literal, Optional, Union
2
3
 
3
4
  from vellum.client.core.api_error import ApiError
@@ -14,14 +15,23 @@ from vellum.workflows.references.environment_variable import EnvironmentVariable
14
15
  from vellum.workflows.references.execution_count import ExecutionCountReference
15
16
  from vellum.workflows.references.lazy import LazyReference
16
17
  from vellum.workflows.references.node import NodeReference
18
+ from vellum.workflows.references.state_value import StateValueReference
19
+ from vellum.workflows.references.trigger import TriggerAttributeReference
17
20
  from vellum.workflows.references.vellum_secret import VellumSecretReference
21
+ from vellum.workflows.utils.functions import compile_annotation
18
22
  from vellum.workflows.utils.vellum_variables import primitive_type_to_vellum_variable_type
19
- from vellum_ee.workflows.display.utils.exceptions import InvalidInputReferenceError, UnsupportedSerializationException
23
+ from vellum_ee.workflows.display.utils.exceptions import (
24
+ InvalidInputReferenceError,
25
+ InvalidOutputReferenceError,
26
+ UnsupportedSerializationException,
27
+ )
20
28
  from vellum_ee.workflows.display.utils.expressions import get_child_descriptor
21
29
 
22
30
  if TYPE_CHECKING:
23
31
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
24
32
 
33
+ logger = logging.getLogger(__name__)
34
+
25
35
 
26
36
  class ConstantValuePointer(UniversalBaseModel):
27
37
  type: Literal["CONSTANT_VALUE"] = "CONSTANT_VALUE"
@@ -78,6 +88,25 @@ class EnvironmentVariablePointer(UniversalBaseModel):
78
88
  data: EnvironmentVariableData
79
89
 
80
90
 
91
+ class WorkflowStateData(UniversalBaseModel):
92
+ state_variable_id: str
93
+
94
+
95
+ class WorkflowStatePointer(UniversalBaseModel):
96
+ type: Literal["WORKFLOW_STATE"] = "WORKFLOW_STATE"
97
+ data: WorkflowStateData
98
+
99
+
100
+ class TriggerAttributeData(UniversalBaseModel):
101
+ trigger_id: str
102
+ attribute_id: str
103
+
104
+
105
+ class TriggerAttributePointer(UniversalBaseModel):
106
+ type: Literal["TRIGGER_ATTRIBUTE"] = "TRIGGER_ATTRIBUTE"
107
+ data: TriggerAttributeData
108
+
109
+
81
110
  NodeInputValuePointerRule = Union[
82
111
  NodeOutputPointer,
83
112
  InputVariablePointer,
@@ -85,6 +114,8 @@ NodeInputValuePointerRule = Union[
85
114
  WorkspaceSecretPointer,
86
115
  ExecutionCounterPointer,
87
116
  EnvironmentVariablePointer,
117
+ WorkflowStatePointer,
118
+ TriggerAttributePointer,
88
119
  ]
89
120
 
90
121
 
@@ -108,6 +139,13 @@ def infer_vellum_variable_type(value: Any) -> VellumVariableType:
108
139
  return inferred_type
109
140
 
110
141
 
142
+ def compile_descriptor_annotation(descriptor: BaseDescriptor) -> dict:
143
+ """Compile a BaseDescriptor's type annotation to a JSON schema."""
144
+ if not descriptor.types:
145
+ return {}
146
+ return compile_annotation(descriptor.normalized_type, {})
147
+
148
+
111
149
  def create_node_input_value_pointer_rule(
112
150
  value: Any, display_context: "WorkflowDisplayContext"
113
151
  ) -> NodeInputValuePointerRule:
@@ -132,7 +170,12 @@ def create_node_input_value_pointer_rule(
132
170
  data=NodeOutputData(node_id=str(upstream_node_display.node_id), output_id=str(output_display.id)),
133
171
  )
134
172
  if isinstance(value, LazyReference):
135
- child_descriptor = get_child_descriptor(value, display_context)
173
+ try:
174
+ child_descriptor = get_child_descriptor(value, display_context)
175
+ except InvalidOutputReferenceError as e:
176
+ logger.warning("Failed to parse lazy reference '%s', skipping serialization", value.name)
177
+ display_context.add_validation_error(e)
178
+ raise UnsupportedSerializationException(f"Failed to parse lazy reference: {value.name}")
136
179
  return create_node_input_value_pointer_rule(child_descriptor, display_context)
137
180
  if isinstance(value, WorkflowInputReference):
138
181
  if value not in display_context.global_workflow_input_displays:
@@ -164,14 +207,25 @@ def create_node_input_value_pointer_rule(
164
207
  data=ExecutionCounterData(node_id=str(node_class_display.node_id)),
165
208
  )
166
209
  if isinstance(value, EnvironmentVariableReference):
167
- if value.serialize_as_constant:
168
- vellum_value = primitive_to_vellum_value(value.name)
169
- return ConstantValuePointer(type="CONSTANT_VALUE", data=vellum_value)
170
210
  return EnvironmentVariablePointer(
171
211
  data=EnvironmentVariableData(
172
212
  environment_variable=value.name,
173
213
  ),
174
214
  )
215
+ if isinstance(value, StateValueReference):
216
+ state_value_display = display_context.global_state_value_displays[value]
217
+ return WorkflowStatePointer(
218
+ data=WorkflowStateData(
219
+ state_variable_id=str(state_value_display.id),
220
+ ),
221
+ )
222
+ if isinstance(value, TriggerAttributeReference):
223
+ return TriggerAttributePointer(
224
+ data=TriggerAttributeData(
225
+ trigger_id=str(value.trigger_class.__id__),
226
+ attribute_id=str(value.id),
227
+ ),
228
+ )
175
229
 
176
230
  if not isinstance(value, BaseDescriptor):
177
231
  vellum_value = primitive_to_vellum_value(value)