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,8 +1,13 @@
1
1
  import hashlib
2
+ import sys
2
3
  from uuid import UUID
3
4
  from typing import TYPE_CHECKING
4
5
 
6
+ from vellum.workflows.loaders.base import BaseWorkflowFinder
7
+
5
8
  if TYPE_CHECKING:
9
+ from vellum.workflows.inputs.base import BaseInputs
10
+ from vellum.workflows.state.base import BaseState
6
11
  from vellum.workflows.triggers.base import BaseTrigger
7
12
 
8
13
 
@@ -21,6 +26,59 @@ def generate_workflow_deployment_prefix(deployment_name: str, release_tag: str)
21
26
  return f"vellum_workflow_deployment_{expected_hash}"
22
27
 
23
28
 
29
+ def _normalize_module_path(module_path: str) -> str:
30
+ """
31
+ Normalize a module path by filtering out a leading ephemeral namespace segment.
32
+
33
+ When workflows are loaded dynamically (e.g., via VirtualFileFinder), the module path
34
+ may start with an ephemeral namespace that changes on each invocation. This function
35
+ strips that leading segment to ensure stable, deterministic ID generation.
36
+
37
+ The function checks if the first segment of the module path exactly matches the
38
+ namespace of any registered BaseWorkflowFinder in sys.meta_path. Only namespaces
39
+ that are actually registered are stripped, preventing accidental stripping of
40
+ legitimate module names.
41
+
42
+ Args:
43
+ module_path: The module path to normalize (e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890.workflow"
44
+ or "workflow_tmp_ABC123xyz.workflow")
45
+
46
+ Returns:
47
+ The normalized module path with the leading ephemeral segment removed if present
48
+ (e.g., "workflow")
49
+ """
50
+ parts = module_path.split(".")
51
+ if not parts:
52
+ return module_path
53
+
54
+ first_part = parts[0]
55
+
56
+ # Check if the first part matches the namespace of any registered workflow finder
57
+ for finder in sys.meta_path:
58
+ if isinstance(finder, BaseWorkflowFinder) and finder.namespace == first_part:
59
+ return ".".join(parts[1:]) if len(parts) > 1 else ""
60
+
61
+ return module_path
62
+
63
+
64
+ def generate_entity_id_from_path(path: str) -> UUID:
65
+ """
66
+ Generate a deterministic entity ID from a path string.
67
+
68
+ This function normalizes the path by filtering out any leading UUID namespace segment
69
+ (which may change on each invocation when workflows are loaded dynamically), then
70
+ generates a stable UUID from the normalized path.
71
+
72
+ Args:
73
+ path: The path string to generate an ID from (e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890.workflow.MyNode")
74
+
75
+ Returns:
76
+ A deterministic UUID based on the normalized path
77
+ """
78
+ normalized_path = _normalize_module_path(path)
79
+ return uuid4_from_hash(normalized_path)
80
+
81
+
24
82
  def uuid4_from_hash(input_str: str) -> UUID:
25
83
  # Create a SHA-256 hash of the input string
26
84
  hash_bytes = hashlib.sha256(input_str.encode()).digest()
@@ -57,3 +115,35 @@ def get_trigger_attribute_id(trigger_class: "type[BaseTrigger]", attribute_name:
57
115
  """
58
116
  trigger_id = trigger_class.__id__
59
117
  return uuid4_from_hash(f"{trigger_id}|{attribute_name}")
118
+
119
+
120
+ def get_workflow_input_id(inputs_class: "type[BaseInputs]", input_name: str) -> UUID:
121
+ """
122
+ Generate a deterministic workflow input ID from an inputs class and input name
123
+ using the class's parent workflow ID and input name to ensure stability and uniqueness.
124
+
125
+ Args:
126
+ inputs_class: The inputs class containing the input
127
+ input_name: The name of the input
128
+
129
+ Returns:
130
+ A deterministic UUID based on the workflow ID and input name
131
+ """
132
+ workflow_class = inputs_class.__parent_class__
133
+ workflow_id = workflow_class.__id__
134
+ return uuid4_from_hash(f"{workflow_id}|inputs|id|{input_name}")
135
+
136
+
137
+ def get_state_value_id(state_class: "type[BaseState]", state_value_name: str) -> UUID:
138
+ """
139
+ Generate a deterministic state value ID from a state class and state value name
140
+ using the class's module name, qualname, and state value name to ensure stability and uniqueness.
141
+
142
+ Args:
143
+ state_class: The state class containing the state value
144
+ state_value_name: The name of the state value
145
+
146
+ Returns:
147
+ A deterministic UUID based on the state class module, qualname, and state value name
148
+ """
149
+ return uuid4_from_hash(f"{state_class.__module__}.{state_class.__qualname__}|state_values|id|{state_value_name}")
@@ -0,0 +1,108 @@
1
+ from typing import Any, Union, get_args, get_origin
2
+
3
+
4
+ class TypeValidationError(ValueError):
5
+ """Exception raised when type validation fails."""
6
+
7
+ def __init__(self, declared_type: type, target_type: type) -> None:
8
+ declared_type_name = getattr(declared_type, "__name__", str(declared_type))
9
+ target_type_name = getattr(target_type, "__name__", str(target_type))
10
+ super().__init__(
11
+ f"Output type mismatch: declared type '{declared_type_name}' "
12
+ f"but the 'value' Output has type(s) '{target_type_name}'. "
13
+ )
14
+ self.declared_type = declared_type
15
+ self.target_type = target_type
16
+
17
+
18
+ def validate_target_type(declared_type: type, target_type: type) -> None:
19
+ # If either type is Any, validation always passes
20
+ if declared_type is Any or target_type is Any:
21
+ return
22
+
23
+ declared_origin = get_origin(declared_type)
24
+ target_origin = get_origin(target_type)
25
+
26
+ # Special case: both are Unions
27
+ # Each target union member must be compatible with at least one declared union member
28
+ if declared_origin is Union and target_origin is Union:
29
+ declared_union_args = get_args(declared_type)
30
+ target_union_args = get_args(target_type)
31
+ for target_member in target_union_args:
32
+ is_compatible = False
33
+ for declared_member in declared_union_args:
34
+ try:
35
+ validate_target_type(declared_member, target_member)
36
+ is_compatible = True
37
+ break
38
+ except TypeValidationError:
39
+ continue
40
+ if not is_compatible:
41
+ # This target member is not compatible with any declared member
42
+ raise TypeValidationError(declared_type, target_type)
43
+ # All target members are compatible with at least one declared member
44
+ return
45
+
46
+ # If declared_type is a Union, target_type must be compatible with at least one union member
47
+ if declared_origin is Union:
48
+ declared_union_args = get_args(declared_type)
49
+ for union_member in declared_union_args:
50
+ try:
51
+ validate_target_type(union_member, target_type)
52
+ # If any union member is compatible, validation passes
53
+ return
54
+ except TypeValidationError:
55
+ # This union member is incompatible, try the next one
56
+ continue
57
+ # None of the union members are compatible with target_type
58
+ raise TypeValidationError(declared_type, target_type)
59
+
60
+ # If target_type is a Union, ALL union members must be compatible with declared_type
61
+ if target_origin is Union:
62
+ target_union_args = get_args(target_type)
63
+ for union_member in target_union_args:
64
+ try:
65
+ validate_target_type(declared_type, union_member)
66
+ except TypeValidationError:
67
+ # At least one union member is incompatible with declared_type
68
+ raise TypeValidationError(declared_type, target_type)
69
+ # All union members are compatible with declared_type
70
+ return
71
+
72
+ # Check for exact type match
73
+ if target_type == declared_type:
74
+ return
75
+
76
+ # Check for subclass relationships
77
+ try:
78
+ if issubclass(target_type, declared_type) or issubclass(declared_type, target_type):
79
+ return
80
+ except TypeError:
81
+ # Handle cases where types aren't classes (e.g., generic types)
82
+ if str(target_type) == str(declared_type):
83
+ return
84
+
85
+ # Check for generic type compatibility
86
+ declared_origin = get_origin(declared_type)
87
+
88
+ if target_origin is None and declared_origin is None:
89
+ # Neither is a generic type, and they don't match
90
+ raise TypeValidationError(declared_type, target_type)
91
+
92
+ if target_origin == declared_type or declared_origin == target_type or target_origin == declared_origin:
93
+ target_args = get_args(target_type)
94
+ declared_args = get_args(declared_type)
95
+
96
+ if len(declared_args) == 0:
97
+ return
98
+
99
+ if len(target_args) != len(declared_args):
100
+ raise TypeValidationError(declared_type, target_type)
101
+
102
+ for target_arg, declared_arg in zip(target_args, declared_args):
103
+ validate_target_type(declared_arg, target_arg)
104
+
105
+ return
106
+
107
+ # If we reach here, types don't match
108
+ raise TypeValidationError(declared_type, target_type)
@@ -1,7 +1,10 @@
1
+ from datetime import datetime
2
+ import sys
1
3
  import typing
2
4
  from typing import Any, List, Tuple, Type, Union, get_args, get_origin
3
5
 
4
6
  from vellum import (
7
+ ArrayChatMessageContentItem,
5
8
  ChatMessage,
6
9
  ChatMessageRequest,
7
10
  FunctionCall,
@@ -24,7 +27,7 @@ from vellum import (
24
27
  )
25
28
  from vellum.workflows.constants import undefined
26
29
  from vellum.workflows.descriptors.base import BaseDescriptor
27
- from vellum.workflows.types.core import Json
30
+ from vellum.workflows.types.core import is_json_type
28
31
 
29
32
 
30
33
  def primitive_type_to_vellum_variable_type(type_: Union[Type, BaseDescriptor]) -> VellumVariableType:
@@ -46,17 +49,7 @@ def primitive_type_to_vellum_variable_type(type_: Union[Type, BaseDescriptor]) -
46
49
  return "JSON"
47
50
 
48
51
  if len(types) != 1:
49
- # Check explicitly for our internal JSON type.
50
- # Matches the type found at vellum.workflows.utils.vellum_variables.Json
51
- actual_types_with_explicit_ref = [
52
- bool,
53
- int,
54
- float,
55
- str,
56
- typing.List[Json],
57
- typing.Dict[str, Json],
58
- ]
59
- if types == actual_types_with_explicit_ref:
52
+ if is_json_type(types):
60
53
  return "JSON"
61
54
  # Number now supports float and int
62
55
  elif types == [float, int]:
@@ -66,11 +59,15 @@ def primitive_type_to_vellum_variable_type(type_: Union[Type, BaseDescriptor]) -
66
59
  if len(collapse_types) == 1:
67
60
  return primitive_type_to_vellum_variable_type(collapse_types[0])
68
61
 
62
+ # Handle Union[str, List[ArrayChatMessageContentItem]] for ChatMessageTrigger.message
63
+ if _is_string_and_array_chat_message_content_union(types):
64
+ return "ARRAY"
65
+
69
66
  raise ValueError(f"Expected Descriptor to only have one type, got {types}")
70
67
 
71
68
  type_ = type_.types[0]
72
69
 
73
- if _is_type_optionally_equal(type_, str):
70
+ if _is_type_optionally_in(type_, (str, datetime)):
74
71
  return "STRING"
75
72
  elif _is_type_optionally_in(type_, (int, float)):
76
73
  return "NUMBER"
@@ -218,8 +215,91 @@ def _builtin_list_to_vellum_type(type_: Type) -> Union[str, None]:
218
215
  item_type, SearchResultRequest
219
216
  ):
220
217
  return "SEARCH_RESULTS"
221
- if _is_type_optionally_equal(item_type, VellumValue) or _is_type_optionally_equal(
222
- item_type, VellumValueRequest
223
- ):
218
+
219
+ if _is_vellum_value_subtype(item_type):
224
220
  return "ARRAY"
221
+
222
+ if _is_array_chat_message_content_item(item_type):
223
+ return "ARRAY"
224
+
225
225
  return None
226
+
227
+
228
+ def _is_array_chat_message_content_item(type_: Type) -> bool:
229
+ """Check if the type is ArrayChatMessageContentItem or a union of its subtypes."""
230
+ array_content_item_types = list(typing.get_args(ArrayChatMessageContentItem))
231
+
232
+ origin = get_origin(type_)
233
+ if not origin:
234
+ if isinstance(type_, type):
235
+ return any(issubclass(type_, t) for t in array_content_item_types if isinstance(t, type))
236
+ return False
237
+
238
+ if origin is typing.Union:
239
+ args = get_args(type_)
240
+ return all(_is_array_chat_message_content_item(arg) for arg in args)
241
+
242
+ return type_ == ArrayChatMessageContentItem
243
+
244
+
245
+ def _is_string_and_array_chat_message_content_union(types: List[Type]) -> bool:
246
+ """Check if types represent Union[str, List[ArrayChatMessageContentItem]]."""
247
+ if len(types) != 2:
248
+ return False
249
+
250
+ has_str = str in types
251
+ has_list_array_content = any(
252
+ get_origin(t) in (list, typing.List)
253
+ and len(get_args(t)) == 1
254
+ and _is_array_chat_message_content_item(get_args(t)[0])
255
+ for t in types
256
+ )
257
+
258
+ return has_str and has_list_array_content
259
+
260
+
261
+ def _is_vellum_value_subtype(type_: Type) -> bool:
262
+ # This logic is here primarily for `ArrayVellumValue`, which is defined recursively.
263
+ # At class definition time, we invoke some Pydantic helpers to resolve its forward references.
264
+ vellum_value_types = [
265
+ (
266
+ t.__forward_value__
267
+ if isinstance(t, typing.ForwardRef) and t.__forward_evaluated__ and t.__forward_value__ is not None
268
+ else t
269
+ )
270
+ for t in typing.get_args(VellumValue)
271
+ ]
272
+ origin = get_origin(type_)
273
+ if not origin:
274
+ if isinstance(type_, type):
275
+ return any(issubclass(type_, vellum_value_type) for vellum_value_type in vellum_value_types)
276
+ elif isinstance(type_, typing.ForwardRef):
277
+ # If the forward ref hasn't been resolved yet, do the simple stupid thing and
278
+ # assume it's not a VellumValue subtype.
279
+ # This means user-defined types should use the fully resolved types!
280
+ if not type_.__forward_evaluated__ or type_.__forward_value__ is None:
281
+ return False
282
+
283
+ type_ = type_.__forward_value__
284
+ if isinstance(type_, type):
285
+ return any(issubclass(type_, vellum_value_type) for vellum_value_type in vellum_value_types)
286
+ else:
287
+ return False
288
+ else:
289
+ return False
290
+
291
+ if sys.version_info >= (3, 10) and sys.version_info < (3, 14):
292
+ # See https://docs.python.org/3/library/types.html#types.UnionType.
293
+ # In Python 3.10, `types.UnionType` was introduced to support X | Y union type expressions.
294
+ # In Python 3.14, `types.UnionType` is just an alias for `typing.Union`.
295
+ from types import UnionType
296
+
297
+ union_types = (typing.Union, UnionType)
298
+ else:
299
+ union_types = (typing.Union,)
300
+
301
+ if origin in union_types:
302
+ args = get_args(type_)
303
+ return all(_is_vellum_value_subtype(arg) for arg in args)
304
+
305
+ return False