vellum-ai 0.14.63__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 (1362) hide show
  1. vellum/__init__.py +287 -4
  2. vellum/client/README.md +69 -16
  3. vellum/client/__init__.py +598 -1437
  4. vellum/client/core/__init__.py +5 -0
  5. vellum/client/core/api_error.py +13 -5
  6. vellum/client/core/client_wrapper.py +30 -4
  7. vellum/client/core/force_multipart.py +18 -0
  8. vellum/client/core/http_client.py +70 -26
  9. vellum/client/core/http_response.py +55 -0
  10. vellum/client/core/jsonable_encoder.py +0 -1
  11. vellum/client/core/pydantic_utilities.py +90 -117
  12. vellum/client/core/serialization.py +7 -3
  13. vellum/client/errors/__init__.py +14 -1
  14. vellum/client/errors/bad_request_error.py +4 -3
  15. vellum/client/errors/forbidden_error.py +4 -3
  16. vellum/client/errors/internal_server_error.py +4 -3
  17. vellum/client/errors/misdirected_request_error.py +11 -0
  18. vellum/client/errors/not_found_error.py +4 -3
  19. vellum/client/errors/too_many_requests_error.py +10 -0
  20. vellum/client/errors/unauthorized_error.py +11 -0
  21. vellum/client/raw_client.py +2725 -0
  22. vellum/client/reference.md +3160 -1217
  23. vellum/client/resources/__init__.py +16 -2
  24. vellum/client/resources/ad_hoc/__init__.py +2 -0
  25. vellum/client/resources/ad_hoc/client.py +173 -377
  26. vellum/client/resources/ad_hoc/raw_client.py +569 -0
  27. vellum/client/resources/container_images/__init__.py +2 -0
  28. vellum/client/resources/container_images/client.py +365 -185
  29. vellum/client/resources/container_images/raw_client.py +693 -0
  30. vellum/client/resources/deployments/__init__.py +2 -0
  31. vellum/client/resources/deployments/client.py +119 -463
  32. vellum/client/resources/deployments/raw_client.py +1002 -0
  33. vellum/client/resources/deployments/types/__init__.py +2 -0
  34. vellum/client/resources/document_indexes/__init__.py +2 -0
  35. vellum/client/resources/document_indexes/client.py +131 -383
  36. vellum/client/resources/document_indexes/raw_client.py +866 -0
  37. vellum/client/resources/document_indexes/types/__init__.py +2 -0
  38. vellum/client/resources/documents/__init__.py +2 -0
  39. vellum/client/resources/documents/client.py +111 -333
  40. vellum/client/resources/documents/raw_client.py +672 -0
  41. vellum/client/resources/{release_reviews → environments}/__init__.py +2 -0
  42. vellum/client/resources/environments/client.py +106 -0
  43. vellum/client/resources/environments/raw_client.py +95 -0
  44. vellum/client/resources/events/__init__.py +4 -0
  45. vellum/client/resources/events/client.py +201 -0
  46. vellum/client/resources/events/raw_client.py +211 -0
  47. vellum/client/resources/folder_entities/__init__.py +2 -0
  48. vellum/client/resources/folder_entities/client.py +56 -95
  49. vellum/client/resources/folder_entities/raw_client.py +276 -0
  50. vellum/client/resources/folder_entities/types/__init__.py +2 -0
  51. vellum/client/resources/integration_auth_configs/__init__.py +4 -0
  52. vellum/client/resources/integration_auth_configs/client.py +188 -0
  53. vellum/client/resources/integration_auth_configs/raw_client.py +173 -0
  54. vellum/client/resources/integration_providers/__init__.py +4 -0
  55. vellum/client/resources/integration_providers/client.py +325 -0
  56. vellum/client/resources/integration_providers/raw_client.py +299 -0
  57. vellum/client/resources/integrations/__init__.py +4 -0
  58. vellum/client/resources/integrations/client.py +514 -0
  59. vellum/client/resources/integrations/raw_client.py +618 -0
  60. vellum/client/resources/metric_definitions/__init__.py +2 -0
  61. vellum/client/resources/metric_definitions/client.py +60 -106
  62. vellum/client/resources/metric_definitions/raw_client.py +224 -0
  63. vellum/client/resources/ml_models/__init__.py +2 -0
  64. vellum/client/resources/ml_models/client.py +37 -46
  65. vellum/client/resources/ml_models/raw_client.py +102 -0
  66. vellum/client/resources/organizations/__init__.py +2 -0
  67. vellum/client/resources/organizations/client.py +37 -45
  68. vellum/client/resources/organizations/raw_client.py +95 -0
  69. vellum/client/resources/prompts/__init__.py +2 -0
  70. vellum/client/resources/prompts/client.py +84 -202
  71. vellum/client/resources/prompts/raw_client.py +353 -0
  72. vellum/client/resources/sandboxes/__init__.py +2 -0
  73. vellum/client/resources/sandboxes/client.py +69 -159
  74. vellum/client/resources/sandboxes/raw_client.py +392 -0
  75. vellum/client/resources/test_suite_runs/__init__.py +2 -0
  76. vellum/client/resources/test_suite_runs/client.py +65 -157
  77. vellum/client/resources/test_suite_runs/raw_client.py +354 -0
  78. vellum/client/resources/test_suites/__init__.py +2 -0
  79. vellum/client/resources/test_suites/client.py +162 -266
  80. vellum/client/resources/test_suites/raw_client.py +530 -0
  81. vellum/client/resources/uploaded_files/__init__.py +4 -0
  82. vellum/client/resources/uploaded_files/client.py +230 -0
  83. vellum/client/resources/uploaded_files/raw_client.py +316 -0
  84. vellum/client/resources/workflow_deployments/__init__.py +2 -0
  85. vellum/client/resources/workflow_deployments/client.py +456 -351
  86. vellum/client/resources/workflow_deployments/raw_client.py +1393 -0
  87. vellum/client/resources/workflow_deployments/types/__init__.py +2 -0
  88. vellum/client/resources/workflow_executions/__init__.py +4 -0
  89. vellum/client/resources/workflow_executions/client.py +140 -0
  90. vellum/client/resources/workflow_executions/raw_client.py +173 -0
  91. vellum/client/resources/workflow_sandboxes/__init__.py +2 -0
  92. vellum/client/resources/workflow_sandboxes/client.py +58 -123
  93. vellum/client/resources/workflow_sandboxes/raw_client.py +291 -0
  94. vellum/client/resources/workflow_sandboxes/types/__init__.py +2 -0
  95. vellum/client/resources/workflows/__init__.py +2 -0
  96. vellum/client/resources/workflows/client.py +464 -145
  97. vellum/client/resources/workflows/raw_client.py +884 -0
  98. vellum/client/resources/workspace_secrets/__init__.py +2 -0
  99. vellum/client/resources/workspace_secrets/client.py +43 -100
  100. vellum/client/resources/workspace_secrets/raw_client.py +219 -0
  101. vellum/client/resources/workspaces/__init__.py +2 -0
  102. vellum/client/resources/workspaces/client.py +37 -45
  103. vellum/client/resources/workspaces/raw_client.py +95 -0
  104. vellum/client/tests/__init__.py +0 -0
  105. vellum/client/tests/test_utils.py +34 -0
  106. vellum/client/types/__init__.py +260 -0
  107. vellum/client/types/ad_hoc_execute_prompt_event.py +3 -2
  108. vellum/client/types/ad_hoc_expand_meta.py +2 -2
  109. vellum/client/types/ad_hoc_fulfilled_prompt_execution_meta.py +3 -3
  110. vellum/client/types/ad_hoc_initiated_prompt_execution_meta.py +2 -2
  111. vellum/client/types/ad_hoc_rejected_prompt_execution_meta.py +3 -3
  112. vellum/client/types/ad_hoc_streaming_prompt_execution_meta.py +2 -2
  113. vellum/client/types/api_actor_type_enum.py +7 -0
  114. vellum/client/types/api_node_result.py +3 -3
  115. vellum/client/types/api_node_result_data.py +4 -4
  116. vellum/client/types/api_request_parent_context.py +17 -10
  117. vellum/client/types/api_version_enum.py +1 -1
  118. vellum/client/types/array_chat_message_content.py +3 -3
  119. vellum/client/types/array_chat_message_content_item.py +7 -4
  120. vellum/client/types/array_chat_message_content_item_request.py +7 -4
  121. vellum/client/types/array_chat_message_content_request.py +3 -3
  122. vellum/client/types/array_input.py +12 -6
  123. vellum/client/types/array_vellum_value.py +4 -4
  124. vellum/client/types/array_vellum_value_request.py +4 -4
  125. vellum/client/types/audio_chat_message_content.py +3 -3
  126. vellum/client/types/audio_chat_message_content_request.py +3 -3
  127. vellum/client/types/audio_input.py +30 -0
  128. vellum/client/types/audio_input_request.py +30 -0
  129. vellum/client/types/audio_prompt_block.py +4 -4
  130. vellum/client/types/audio_vellum_value.py +3 -3
  131. vellum/client/types/audio_vellum_value_request.py +3 -3
  132. vellum/client/types/auth_type_enum.py +5 -0
  133. vellum/client/types/base_output.py +4 -4
  134. vellum/client/types/basic_vectorizer_intfloat_multilingual_e_5_large.py +2 -2
  135. vellum/client/types/basic_vectorizer_intfloat_multilingual_e_5_large_request.py +2 -2
  136. vellum/client/types/basic_vectorizer_sentence_transformers_multi_qa_mpnet_base_cos_v_1.py +2 -2
  137. vellum/client/types/basic_vectorizer_sentence_transformers_multi_qa_mpnet_base_cos_v_1_request.py +2 -2
  138. vellum/client/types/basic_vectorizer_sentence_transformers_multi_qa_mpnet_base_dot_v_1.py +2 -2
  139. vellum/client/types/basic_vectorizer_sentence_transformers_multi_qa_mpnet_base_dot_v_1_request.py +2 -2
  140. vellum/client/types/build_status_enum.py +5 -0
  141. vellum/client/types/chat_history_input.py +3 -3
  142. vellum/client/types/chat_history_input_request.py +3 -3
  143. vellum/client/types/chat_history_vellum_value.py +3 -3
  144. vellum/client/types/chat_history_vellum_value_request.py +3 -3
  145. vellum/client/types/chat_message.py +4 -4
  146. vellum/client/types/chat_message_content.py +7 -4
  147. vellum/client/types/chat_message_content_request.py +7 -4
  148. vellum/client/types/chat_message_prompt_block.py +7 -7
  149. vellum/client/types/chat_message_request.py +4 -4
  150. vellum/client/types/check_workflow_execution_status_error.py +21 -0
  151. vellum/client/types/check_workflow_execution_status_response.py +29 -0
  152. vellum/client/types/code_execution_node_array_result.py +11 -5
  153. vellum/client/types/code_execution_node_chat_history_result.py +3 -3
  154. vellum/client/types/code_execution_node_error_result.py +3 -3
  155. vellum/client/types/code_execution_node_function_call_result.py +3 -3
  156. vellum/client/types/code_execution_node_json_result.py +2 -2
  157. vellum/client/types/code_execution_node_number_result.py +2 -2
  158. vellum/client/types/code_execution_node_result.py +10 -4
  159. vellum/client/types/code_execution_node_result_data.py +10 -4
  160. vellum/client/types/code_execution_node_result_output.py +6 -5
  161. vellum/client/types/code_execution_node_search_results_result.py +3 -3
  162. vellum/client/types/code_execution_node_string_result.py +2 -2
  163. vellum/client/types/code_execution_package.py +3 -2
  164. vellum/client/types/code_execution_package_request.py +21 -0
  165. vellum/client/types/code_executor_input.py +15 -6
  166. vellum/client/types/code_executor_response.py +11 -5
  167. vellum/client/types/code_executor_secret_input.py +3 -3
  168. vellum/client/types/code_resource_definition.py +3 -3
  169. vellum/client/types/compile_prompt_deployment_expand_meta_request.py +2 -2
  170. vellum/client/types/compile_prompt_meta.py +2 -2
  171. vellum/client/types/components_schemas_composio_execute_tool_request.py +5 -0
  172. vellum/client/types/components_schemas_composio_execute_tool_response.py +5 -0
  173. vellum/client/types/components_schemas_composio_integration_exec_config.py +5 -0
  174. vellum/client/types/components_schemas_composio_tool_definition.py +5 -0
  175. vellum/client/types/components_schemas_slim_composio_tool_definition.py +5 -0
  176. vellum/client/types/composio_execute_tool_request.py +29 -0
  177. vellum/client/types/composio_execute_tool_response.py +24 -0
  178. vellum/client/types/composio_integration_exec_config.py +21 -0
  179. vellum/client/types/composio_tool_definition.py +31 -0
  180. vellum/client/types/conditional_node_result.py +3 -3
  181. vellum/client/types/conditional_node_result_data.py +2 -2
  182. vellum/client/types/container_image_build_config.py +22 -0
  183. vellum/client/types/container_image_container_image_tag.py +3 -2
  184. vellum/client/types/container_image_read.py +8 -4
  185. vellum/client/types/create_test_suite_test_case_request.py +9 -3
  186. vellum/client/types/create_workflow_event_request.py +7 -0
  187. vellum/client/types/dataset_row_push_request.py +23 -0
  188. vellum/client/types/delimiter_chunker_config.py +20 -0
  189. vellum/client/types/delimiter_chunker_config_request.py +20 -0
  190. vellum/client/types/delimiter_chunking.py +21 -0
  191. vellum/client/types/delimiter_chunking_request.py +21 -0
  192. vellum/client/types/deployment_history_item.py +10 -4
  193. vellum/client/types/deployment_provider_payload_response.py +4 -4
  194. vellum/client/types/deployment_read.py +15 -9
  195. vellum/client/types/deployment_release_tag_deployment_history_item.py +2 -2
  196. vellum/client/types/deployment_release_tag_read.py +4 -4
  197. vellum/client/types/deprecated_prompt_request_input.py +8 -0
  198. vellum/client/types/docker_service_token.py +2 -2
  199. vellum/client/types/document_chat_message_content.py +3 -3
  200. vellum/client/types/document_chat_message_content_request.py +3 -3
  201. vellum/client/types/document_document_to_document_index.py +5 -4
  202. vellum/client/types/document_index_chunking.py +5 -1
  203. vellum/client/types/document_index_chunking_request.py +3 -1
  204. vellum/client/types/document_index_indexing_config.py +4 -4
  205. vellum/client/types/document_index_indexing_config_request.py +4 -4
  206. vellum/client/types/document_index_read.py +4 -4
  207. vellum/client/types/document_input.py +30 -0
  208. vellum/client/types/document_input_request.py +30 -0
  209. vellum/client/types/document_prompt_block.py +4 -4
  210. vellum/client/types/document_read.py +9 -5
  211. vellum/client/types/document_vellum_value.py +3 -3
  212. vellum/client/types/document_vellum_value_request.py +3 -3
  213. vellum/client/types/enriched_normalized_completion.py +3 -3
  214. vellum/client/types/environment_display_config.py +19 -0
  215. vellum/client/types/environment_read.py +23 -0
  216. vellum/client/types/ephemeral_prompt_cache_config.py +3 -3
  217. vellum/client/types/error_detail_response.py +22 -0
  218. vellum/client/types/error_input.py +3 -3
  219. vellum/client/types/error_vellum_value.py +3 -3
  220. vellum/client/types/error_vellum_value_request.py +3 -3
  221. vellum/client/types/event_create_response.py +31 -0
  222. vellum/client/types/execute_api_request_bearer_token.py +1 -0
  223. vellum/client/types/execute_api_request_headers_value.py +1 -0
  224. vellum/client/types/execute_api_response.py +6 -6
  225. vellum/client/types/execute_prompt_event.py +3 -2
  226. vellum/client/types/execute_prompt_response.py +1 -0
  227. vellum/client/types/execute_workflow_async_response.py +26 -0
  228. vellum/client/types/execute_workflow_response.py +10 -4
  229. vellum/client/types/execute_workflow_workflow_result_event.py +1 -0
  230. vellum/client/types/execution_array_vellum_value.py +12 -6
  231. vellum/client/types/execution_audio_vellum_value.py +31 -0
  232. vellum/client/types/execution_chat_history_vellum_value.py +3 -3
  233. vellum/client/types/execution_document_vellum_value.py +31 -0
  234. vellum/client/types/execution_error_vellum_value.py +3 -3
  235. vellum/client/types/execution_function_call_vellum_value.py +3 -3
  236. vellum/client/types/execution_image_vellum_value.py +31 -0
  237. vellum/client/types/execution_json_vellum_value.py +3 -3
  238. vellum/client/types/execution_number_vellum_value.py +3 -3
  239. vellum/client/types/execution_search_results_vellum_value.py +3 -3
  240. vellum/client/types/execution_string_vellum_value.py +3 -3
  241. vellum/client/types/execution_thinking_vellum_value.py +31 -0
  242. vellum/client/types/execution_vellum_value.py +16 -5
  243. vellum/client/types/execution_video_vellum_value.py +31 -0
  244. vellum/client/types/external_input_descriptor.py +3 -3
  245. vellum/client/types/external_parent_context.py +38 -0
  246. vellum/client/types/external_test_case_execution.py +10 -4
  247. vellum/client/types/external_test_case_execution_request.py +10 -4
  248. vellum/client/types/fast_embed_vectorizer_baai_bge_small_en_v_15.py +23 -0
  249. vellum/client/types/fast_embed_vectorizer_baai_bge_small_en_v_15_request.py +23 -0
  250. vellum/client/types/folder_entity.py +5 -2
  251. vellum/client/types/folder_entity_dataset.py +26 -0
  252. vellum/client/types/folder_entity_dataset_data.py +25 -0
  253. vellum/client/types/folder_entity_document_index.py +3 -3
  254. vellum/client/types/folder_entity_document_index_data.py +5 -3
  255. vellum/client/types/folder_entity_folder.py +3 -3
  256. vellum/client/types/folder_entity_folder_data.py +2 -2
  257. vellum/client/types/folder_entity_prompt_sandbox.py +3 -3
  258. vellum/client/types/folder_entity_prompt_sandbox_data.py +4 -3
  259. vellum/client/types/folder_entity_test_suite.py +3 -3
  260. vellum/client/types/folder_entity_test_suite_data.py +3 -3
  261. vellum/client/types/folder_entity_workflow_sandbox.py +3 -3
  262. vellum/client/types/folder_entity_workflow_sandbox_data.py +6 -3
  263. vellum/client/types/fulfilled_ad_hoc_execute_prompt_event.py +4 -4
  264. vellum/client/types/fulfilled_execute_prompt_event.py +4 -4
  265. vellum/client/types/fulfilled_execute_prompt_response.py +3 -3
  266. vellum/client/types/fulfilled_execute_workflow_workflow_result_event.py +11 -5
  267. vellum/client/types/fulfilled_prompt_execution_meta.py +3 -3
  268. vellum/client/types/fulfilled_workflow_node_result_event.py +12 -6
  269. vellum/client/types/function_call.py +2 -2
  270. vellum/client/types/function_call_chat_message_content.py +3 -3
  271. vellum/client/types/function_call_chat_message_content_request.py +3 -3
  272. vellum/client/types/function_call_chat_message_content_value.py +2 -2
  273. vellum/client/types/function_call_chat_message_content_value_request.py +2 -2
  274. vellum/client/types/function_call_input.py +3 -3
  275. vellum/client/types/function_call_prompt_block.py +4 -4
  276. vellum/client/types/function_call_request.py +2 -2
  277. vellum/client/types/function_call_vellum_value.py +3 -3
  278. vellum/client/types/function_call_vellum_value_request.py +3 -3
  279. vellum/client/types/function_definition.py +9 -4
  280. vellum/client/types/generate_options_request.py +3 -3
  281. vellum/client/types/generate_request.py +2 -2
  282. vellum/client/types/generate_response.py +3 -3
  283. vellum/client/types/generate_result.py +3 -3
  284. vellum/client/types/generate_result_data.py +3 -3
  285. vellum/client/types/generate_result_error.py +3 -3
  286. vellum/client/types/generate_stream_response.py +3 -3
  287. vellum/client/types/generate_stream_result.py +4 -4
  288. vellum/client/types/generate_stream_result_data.py +3 -3
  289. vellum/client/types/google_vertex_ai_vectorizer_config.py +2 -2
  290. vellum/client/types/google_vertex_ai_vectorizer_config_request.py +2 -2
  291. vellum/client/types/google_vertex_ai_vectorizer_gemini_embedding_001.py +21 -0
  292. vellum/client/types/google_vertex_ai_vectorizer_gemini_embedding_001_request.py +21 -0
  293. vellum/client/types/google_vertex_ai_vectorizer_text_embedding_004.py +3 -3
  294. vellum/client/types/google_vertex_ai_vectorizer_text_embedding_004_request.py +3 -3
  295. vellum/client/types/google_vertex_ai_vectorizer_text_multilingual_embedding_002.py +3 -3
  296. vellum/client/types/google_vertex_ai_vectorizer_text_multilingual_embedding_002_request.py +3 -3
  297. vellum/client/types/hkunlp_instructor_xl_vectorizer.py +3 -3
  298. vellum/client/types/hkunlp_instructor_xl_vectorizer_request.py +3 -3
  299. vellum/client/types/image_chat_message_content.py +3 -3
  300. vellum/client/types/image_chat_message_content_request.py +3 -3
  301. vellum/client/types/image_input.py +30 -0
  302. vellum/client/types/image_input_request.py +30 -0
  303. vellum/client/types/image_prompt_block.py +4 -4
  304. vellum/client/types/image_vellum_value.py +3 -3
  305. vellum/client/types/image_vellum_value_request.py +3 -3
  306. vellum/client/types/indexing_config_vectorizer.py +11 -4
  307. vellum/client/types/indexing_config_vectorizer_request.py +11 -4
  308. vellum/client/types/initiated_ad_hoc_execute_prompt_event.py +3 -3
  309. vellum/client/types/initiated_execute_prompt_event.py +3 -3
  310. vellum/client/types/initiated_prompt_execution_meta.py +2 -2
  311. vellum/client/types/initiated_workflow_node_result_event.py +12 -6
  312. vellum/client/types/instructor_vectorizer_config.py +2 -2
  313. vellum/client/types/instructor_vectorizer_config_request.py +2 -2
  314. vellum/client/types/integration.py +27 -0
  315. vellum/client/types/integration_auth_config_integration.py +23 -0
  316. vellum/client/types/integration_auth_config_integration_credential.py +19 -0
  317. vellum/client/types/integration_credential_access_type.py +5 -0
  318. vellum/client/types/integration_name.py +109 -0
  319. vellum/client/types/integration_provider.py +5 -0
  320. vellum/client/types/integration_read.py +30 -0
  321. vellum/client/types/integration_trigger_context.py +39 -0
  322. vellum/client/types/invoked_port.py +2 -2
  323. vellum/client/types/jinja_prompt_block.py +4 -4
  324. vellum/client/types/json_input.py +3 -3
  325. vellum/client/types/json_input_request.py +3 -3
  326. vellum/client/types/json_vellum_value.py +2 -2
  327. vellum/client/types/json_vellum_value_request.py +2 -2
  328. vellum/client/types/logical_operator.py +4 -0
  329. vellum/client/types/map_node_result.py +3 -3
  330. vellum/client/types/map_node_result_data.py +3 -3
  331. vellum/client/types/merge_node_result.py +3 -3
  332. vellum/client/types/merge_node_result_data.py +2 -2
  333. vellum/client/types/metadata_filter_config_request.py +12 -6
  334. vellum/client/types/metadata_filter_rule_request.py +5 -5
  335. vellum/client/types/metadata_filters_request.py +1 -0
  336. vellum/client/types/metric_definition_execution.py +10 -4
  337. vellum/client/types/metric_definition_history_item.py +10 -4
  338. vellum/client/types/metric_definition_input.py +3 -2
  339. vellum/client/types/metric_node_result.py +2 -2
  340. vellum/client/types/ml_model_read.py +6 -3
  341. vellum/client/types/ml_model_usage.py +2 -2
  342. vellum/client/types/ml_model_usage_wrapper.py +3 -3
  343. vellum/client/types/named_scenario_input_audio_variable_value_request.py +22 -0
  344. vellum/client/types/named_scenario_input_chat_history_variable_value_request.py +3 -3
  345. vellum/client/types/named_scenario_input_document_variable_value_request.py +22 -0
  346. vellum/client/types/named_scenario_input_image_variable_value_request.py +22 -0
  347. vellum/client/types/named_scenario_input_json_variable_value_request.py +2 -2
  348. vellum/client/types/named_scenario_input_request.py +11 -2
  349. vellum/client/types/named_scenario_input_string_variable_value_request.py +2 -2
  350. vellum/client/types/named_scenario_input_video_variable_value_request.py +22 -0
  351. vellum/client/types/named_test_case_array_variable_value.py +11 -5
  352. vellum/client/types/named_test_case_array_variable_value_request.py +11 -5
  353. vellum/client/types/named_test_case_audio_variable_value.py +26 -0
  354. vellum/client/types/named_test_case_audio_variable_value_request.py +26 -0
  355. vellum/client/types/named_test_case_chat_history_variable_value.py +3 -3
  356. vellum/client/types/named_test_case_chat_history_variable_value_request.py +3 -3
  357. vellum/client/types/named_test_case_document_variable_value.py +22 -0
  358. vellum/client/types/named_test_case_document_variable_value_request.py +22 -0
  359. vellum/client/types/named_test_case_error_variable_value.py +3 -3
  360. vellum/client/types/named_test_case_error_variable_value_request.py +3 -3
  361. vellum/client/types/named_test_case_function_call_variable_value.py +3 -3
  362. vellum/client/types/named_test_case_function_call_variable_value_request.py +3 -3
  363. vellum/client/types/named_test_case_image_variable_value.py +22 -0
  364. vellum/client/types/named_test_case_image_variable_value_request.py +22 -0
  365. vellum/client/types/named_test_case_json_variable_value.py +2 -2
  366. vellum/client/types/named_test_case_json_variable_value_request.py +2 -2
  367. vellum/client/types/named_test_case_number_variable_value.py +2 -2
  368. vellum/client/types/named_test_case_number_variable_value_request.py +2 -2
  369. vellum/client/types/named_test_case_search_results_variable_value.py +3 -3
  370. vellum/client/types/named_test_case_search_results_variable_value_request.py +3 -3
  371. vellum/client/types/named_test_case_string_variable_value.py +2 -2
  372. vellum/client/types/named_test_case_string_variable_value_request.py +2 -2
  373. vellum/client/types/named_test_case_variable_value.py +14 -5
  374. vellum/client/types/named_test_case_variable_value_request.py +14 -5
  375. vellum/client/types/named_test_case_video_variable_value.py +22 -0
  376. vellum/client/types/named_test_case_video_variable_value_request.py +22 -0
  377. vellum/client/types/node_execution_fulfilled_body.py +5 -4
  378. vellum/client/types/node_execution_fulfilled_event.py +24 -15
  379. vellum/client/types/node_execution_initiated_body.py +3 -3
  380. vellum/client/types/node_execution_initiated_event.py +24 -15
  381. vellum/client/types/node_execution_log_body.py +24 -0
  382. vellum/client/types/node_execution_log_event.py +47 -0
  383. vellum/client/types/node_execution_paused_body.py +3 -3
  384. vellum/client/types/node_execution_paused_event.py +24 -15
  385. vellum/client/types/node_execution_rejected_body.py +5 -4
  386. vellum/client/types/node_execution_rejected_event.py +24 -15
  387. vellum/client/types/node_execution_resumed_body.py +3 -3
  388. vellum/client/types/node_execution_resumed_event.py +24 -15
  389. vellum/client/types/node_execution_span.py +23 -12
  390. vellum/client/types/node_execution_span_attributes.py +4 -2
  391. vellum/client/types/node_execution_streaming_body.py +4 -4
  392. vellum/client/types/node_execution_streaming_event.py +24 -15
  393. vellum/client/types/node_input_compiled_array_value.py +11 -5
  394. vellum/client/types/node_input_compiled_audio_value.py +23 -0
  395. vellum/client/types/node_input_compiled_chat_history_value.py +3 -3
  396. vellum/client/types/node_input_compiled_document_value.py +23 -0
  397. vellum/client/types/node_input_compiled_error_value.py +3 -3
  398. vellum/client/types/node_input_compiled_function_call_value.py +3 -3
  399. vellum/client/types/node_input_compiled_image_value.py +23 -0
  400. vellum/client/types/node_input_compiled_json_value.py +2 -2
  401. vellum/client/types/node_input_compiled_number_value.py +2 -2
  402. vellum/client/types/node_input_compiled_search_results_value.py +3 -3
  403. vellum/client/types/node_input_compiled_secret_value.py +3 -3
  404. vellum/client/types/node_input_compiled_string_value.py +2 -2
  405. vellum/client/types/node_input_compiled_video_value.py +23 -0
  406. vellum/client/types/node_input_variable_compiled_value.py +14 -5
  407. vellum/client/types/node_output_compiled_array_value.py +12 -6
  408. vellum/client/types/node_output_compiled_chat_history_value.py +3 -3
  409. vellum/client/types/node_output_compiled_error_value.py +3 -3
  410. vellum/client/types/node_output_compiled_function_call_value.py +3 -3
  411. vellum/client/types/node_output_compiled_json_value.py +3 -3
  412. vellum/client/types/node_output_compiled_number_value.py +3 -3
  413. vellum/client/types/node_output_compiled_search_results_value.py +3 -3
  414. vellum/client/types/node_output_compiled_string_value.py +3 -3
  415. vellum/client/types/node_output_compiled_thinking_value.py +28 -0
  416. vellum/client/types/node_output_compiled_value.py +8 -5
  417. vellum/client/types/node_parent_context.py +14 -11
  418. vellum/client/types/normalized_log_probs.py +3 -3
  419. vellum/client/types/normalized_token_log_probs.py +2 -2
  420. vellum/client/types/number_input.py +3 -3
  421. vellum/client/types/number_vellum_value.py +2 -2
  422. vellum/client/types/number_vellum_value_request.py +2 -2
  423. vellum/client/types/open_ai_vectorizer_config.py +3 -3
  424. vellum/client/types/open_ai_vectorizer_config_request.py +3 -3
  425. vellum/client/types/open_ai_vectorizer_text_embedding_3_large.py +3 -3
  426. vellum/client/types/open_ai_vectorizer_text_embedding_3_large_request.py +3 -3
  427. vellum/client/types/open_ai_vectorizer_text_embedding_3_small.py +3 -3
  428. vellum/client/types/open_ai_vectorizer_text_embedding_3_small_request.py +3 -3
  429. vellum/client/types/open_ai_vectorizer_text_embedding_ada_002.py +3 -3
  430. vellum/client/types/open_ai_vectorizer_text_embedding_ada_002_request.py +3 -3
  431. vellum/client/types/organization_read.py +6 -3
  432. vellum/client/types/paginated_container_image_read_list.py +3 -3
  433. vellum/client/types/paginated_deployment_release_tag_read_list.py +3 -3
  434. vellum/client/types/paginated_document_index_read_list.py +3 -3
  435. vellum/client/types/paginated_folder_entity_list.py +3 -3
  436. vellum/client/types/paginated_slim_deployment_read_list.py +10 -4
  437. vellum/client/types/paginated_slim_document_list.py +3 -3
  438. vellum/client/types/paginated_slim_integration_auth_config_read_list.py +23 -0
  439. vellum/client/types/paginated_slim_integration_read_list.py +23 -0
  440. vellum/client/types/paginated_slim_tool_definition_list.py +23 -0
  441. vellum/client/types/paginated_slim_workflow_deployment_list.py +10 -4
  442. vellum/client/types/paginated_test_suite_run_execution_list.py +10 -4
  443. vellum/client/types/paginated_test_suite_test_case_list.py +10 -4
  444. vellum/client/types/paginated_workflow_deployment_release_list.py +30 -0
  445. vellum/client/types/paginated_workflow_release_tag_read_list.py +3 -3
  446. vellum/client/types/paginated_workflow_sandbox_example_list.py +3 -3
  447. vellum/client/types/parent_context.py +21 -11
  448. vellum/client/types/pdf_search_result_meta_source.py +2 -2
  449. vellum/client/types/pdf_search_result_meta_source_request.py +2 -2
  450. vellum/client/types/plain_text_prompt_block.py +4 -4
  451. vellum/client/types/price.py +3 -3
  452. vellum/client/types/private_vectorizer.py +23 -0
  453. vellum/client/types/private_vectorizer_request.py +23 -0
  454. vellum/client/types/processing_failure_reason_enum.py +3 -1
  455. vellum/client/types/prompt_block.py +9 -6
  456. vellum/client/types/prompt_deployment_expand_meta_request.py +2 -2
  457. vellum/client/types/prompt_deployment_input_request.py +16 -3
  458. vellum/client/types/prompt_deployment_parent_context.py +13 -10
  459. vellum/client/types/prompt_deployment_release.py +6 -6
  460. vellum/client/types/prompt_deployment_release_prompt_deployment.py +3 -2
  461. vellum/client/types/prompt_deployment_release_prompt_version.py +4 -4
  462. vellum/client/types/prompt_exec_config.py +15 -9
  463. vellum/client/types/prompt_execution_meta.py +3 -3
  464. vellum/client/types/prompt_node_execution_meta.py +3 -3
  465. vellum/client/types/prompt_node_result.py +3 -3
  466. vellum/client/types/prompt_node_result_data.py +3 -3
  467. vellum/client/types/prompt_output.py +7 -3
  468. vellum/client/types/prompt_parameters.py +2 -2
  469. vellum/client/types/prompt_push_response.py +2 -2
  470. vellum/client/types/prompt_request_audio_input.py +26 -0
  471. vellum/client/types/prompt_request_chat_history_input.py +3 -3
  472. vellum/client/types/prompt_request_document_input.py +26 -0
  473. vellum/client/types/prompt_request_image_input.py +26 -0
  474. vellum/client/types/prompt_request_input.py +16 -3
  475. vellum/client/types/prompt_request_json_input.py +3 -3
  476. vellum/client/types/prompt_request_string_input.py +3 -3
  477. vellum/client/types/prompt_request_video_input.py +26 -0
  478. vellum/client/types/prompt_settings.py +2 -2
  479. vellum/client/types/prompt_version_build_config_sandbox.py +2 -2
  480. vellum/client/types/raw_prompt_execution_overrides_request.py +2 -2
  481. vellum/client/types/reducto_chunker_config.py +2 -2
  482. vellum/client/types/reducto_chunker_config_request.py +2 -2
  483. vellum/client/types/reducto_chunking.py +3 -3
  484. vellum/client/types/reducto_chunking_request.py +3 -3
  485. vellum/client/types/rejected_ad_hoc_execute_prompt_event.py +4 -4
  486. vellum/client/types/rejected_execute_prompt_event.py +4 -4
  487. vellum/client/types/rejected_execute_prompt_response.py +3 -3
  488. vellum/client/types/rejected_execute_workflow_workflow_result_event.py +4 -4
  489. vellum/client/types/rejected_prompt_execution_meta.py +3 -3
  490. vellum/client/types/rejected_workflow_node_result_event.py +12 -6
  491. vellum/client/types/release_created_by.py +2 -2
  492. vellum/client/types/release_environment.py +2 -2
  493. vellum/client/types/release_release_tag.py +3 -3
  494. vellum/client/types/release_review_reviewer.py +2 -2
  495. vellum/client/types/release_tag_release.py +2 -2
  496. vellum/client/types/replace_test_suite_test_case_request.py +9 -3
  497. vellum/client/types/rich_text_child_block.py +2 -1
  498. vellum/client/types/rich_text_prompt_block.py +4 -4
  499. vellum/client/types/runner_config_request.py +24 -0
  500. vellum/client/types/sandbox_scenario.py +3 -3
  501. vellum/client/types/scenario_input.py +14 -3
  502. vellum/client/types/scenario_input_audio_variable_value.py +22 -0
  503. vellum/client/types/scenario_input_chat_history_variable_value.py +3 -3
  504. vellum/client/types/scenario_input_document_variable_value.py +22 -0
  505. vellum/client/types/scenario_input_image_variable_value.py +22 -0
  506. vellum/client/types/scenario_input_json_variable_value.py +2 -2
  507. vellum/client/types/scenario_input_string_variable_value.py +2 -2
  508. vellum/client/types/scenario_input_video_variable_value.py +22 -0
  509. vellum/client/types/scheduled_trigger_context.py +39 -0
  510. vellum/client/types/search_filters_request.py +11 -5
  511. vellum/client/types/search_node_result.py +3 -3
  512. vellum/client/types/search_node_result_data.py +3 -3
  513. vellum/client/types/search_request_options_request.py +13 -7
  514. vellum/client/types/search_response.py +3 -3
  515. vellum/client/types/search_result.py +3 -3
  516. vellum/client/types/search_result_document.py +2 -2
  517. vellum/client/types/search_result_document_request.py +2 -2
  518. vellum/client/types/search_result_merging_request.py +2 -2
  519. vellum/client/types/search_result_meta.py +3 -3
  520. vellum/client/types/search_result_meta_request.py +3 -3
  521. vellum/client/types/search_result_request.py +3 -3
  522. vellum/client/types/search_results_input.py +3 -3
  523. vellum/client/types/search_results_vellum_value.py +3 -3
  524. vellum/client/types/search_results_vellum_value_request.py +3 -3
  525. vellum/client/types/search_weights_request.py +2 -2
  526. vellum/client/types/secret_type_enum.py +3 -1
  527. vellum/client/types/sentence_chunker_config.py +2 -2
  528. vellum/client/types/sentence_chunker_config_request.py +2 -2
  529. vellum/client/types/sentence_chunking.py +3 -3
  530. vellum/client/types/sentence_chunking_request.py +3 -3
  531. vellum/client/types/severity_enum.py +5 -0
  532. vellum/client/types/slim_composio_tool_definition.py +25 -0
  533. vellum/client/types/slim_deployment_read.py +15 -9
  534. vellum/client/types/slim_document.py +6 -5
  535. vellum/client/types/slim_document_document_to_document_index.py +6 -4
  536. vellum/client/types/slim_integration_auth_config_read.py +36 -0
  537. vellum/client/types/slim_integration_read.py +25 -0
  538. vellum/client/types/slim_release_review.py +4 -4
  539. vellum/client/types/slim_workflow_deployment.py +16 -10
  540. vellum/client/types/slim_workflow_execution_read.py +24 -15
  541. vellum/client/types/span_link.py +15 -12
  542. vellum/client/types/span_link_type_enum.py +1 -1
  543. vellum/client/types/streaming_ad_hoc_execute_prompt_event.py +4 -4
  544. vellum/client/types/streaming_execute_prompt_event.py +3 -3
  545. vellum/client/types/streaming_prompt_execution_meta.py +2 -2
  546. vellum/client/types/streaming_workflow_node_result_event.py +12 -6
  547. vellum/client/types/string_chat_message_content.py +2 -2
  548. vellum/client/types/string_chat_message_content_request.py +2 -2
  549. vellum/client/types/string_input.py +3 -3
  550. vellum/client/types/string_input_request.py +3 -3
  551. vellum/client/types/string_vellum_value.py +2 -2
  552. vellum/client/types/string_vellum_value_request.py +2 -2
  553. vellum/client/types/submit_completion_actual_request.py +3 -3
  554. vellum/client/types/submit_workflow_execution_actual_request.py +3 -2
  555. vellum/client/types/subworkflow_node_result.py +3 -3
  556. vellum/client/types/subworkflow_node_result_data.py +2 -2
  557. vellum/client/types/templating_node_array_result.py +11 -5
  558. vellum/client/types/templating_node_chat_history_result.py +3 -3
  559. vellum/client/types/templating_node_error_result.py +3 -3
  560. vellum/client/types/templating_node_function_call_result.py +3 -3
  561. vellum/client/types/templating_node_json_result.py +2 -2
  562. vellum/client/types/templating_node_number_result.py +2 -2
  563. vellum/client/types/templating_node_result.py +10 -4
  564. vellum/client/types/templating_node_result_data.py +10 -4
  565. vellum/client/types/templating_node_result_output.py +6 -5
  566. vellum/client/types/templating_node_search_results_result.py +3 -3
  567. vellum/client/types/templating_node_string_result.py +2 -2
  568. vellum/client/types/terminal_node_array_result.py +11 -5
  569. vellum/client/types/terminal_node_chat_history_result.py +2 -2
  570. vellum/client/types/terminal_node_error_result.py +2 -2
  571. vellum/client/types/terminal_node_function_call_result.py +2 -2
  572. vellum/client/types/terminal_node_json_result.py +2 -2
  573. vellum/client/types/terminal_node_number_result.py +2 -2
  574. vellum/client/types/terminal_node_result.py +10 -4
  575. vellum/client/types/terminal_node_result_data.py +10 -4
  576. vellum/client/types/terminal_node_result_output.py +6 -5
  577. vellum/client/types/terminal_node_search_results_result.py +2 -2
  578. vellum/client/types/terminal_node_string_result.py +2 -2
  579. vellum/client/types/test_case_array_variable_value.py +11 -5
  580. vellum/client/types/test_case_audio_variable_value.py +27 -0
  581. vellum/client/types/test_case_chat_history_variable_value.py +3 -3
  582. vellum/client/types/test_case_document_variable_value.py +27 -0
  583. vellum/client/types/test_case_error_variable_value.py +3 -3
  584. vellum/client/types/test_case_function_call_variable_value.py +3 -3
  585. vellum/client/types/test_case_image_variable_value.py +27 -0
  586. vellum/client/types/test_case_json_variable_value.py +2 -2
  587. vellum/client/types/test_case_number_variable_value.py +2 -2
  588. vellum/client/types/test_case_search_results_variable_value.py +3 -3
  589. vellum/client/types/test_case_string_variable_value.py +2 -2
  590. vellum/client/types/test_case_variable_value.py +14 -5
  591. vellum/client/types/test_case_video_variable_value.py +27 -0
  592. vellum/client/types/test_suite_run_deployment_release_tag_exec_config.py +3 -3
  593. vellum/client/types/test_suite_run_deployment_release_tag_exec_config_data.py +3 -3
  594. vellum/client/types/test_suite_run_deployment_release_tag_exec_config_data_request.py +3 -3
  595. vellum/client/types/test_suite_run_deployment_release_tag_exec_config_request.py +3 -3
  596. vellum/client/types/test_suite_run_exec_config.py +2 -1
  597. vellum/client/types/test_suite_run_exec_config_request.py +2 -1
  598. vellum/client/types/test_suite_run_execution.py +11 -5
  599. vellum/client/types/test_suite_run_execution_array_output.py +11 -5
  600. vellum/client/types/test_suite_run_execution_chat_history_output.py +3 -3
  601. vellum/client/types/test_suite_run_execution_error_output.py +3 -3
  602. vellum/client/types/test_suite_run_execution_function_call_output.py +3 -3
  603. vellum/client/types/test_suite_run_execution_json_output.py +2 -2
  604. vellum/client/types/test_suite_run_execution_metric_definition.py +2 -2
  605. vellum/client/types/test_suite_run_execution_metric_result.py +11 -5
  606. vellum/client/types/test_suite_run_execution_number_output.py +2 -2
  607. vellum/client/types/test_suite_run_execution_output.py +6 -5
  608. vellum/client/types/test_suite_run_execution_search_results_output.py +3 -3
  609. vellum/client/types/test_suite_run_execution_string_output.py +2 -2
  610. vellum/client/types/test_suite_run_external_exec_config.py +10 -4
  611. vellum/client/types/test_suite_run_external_exec_config_data.py +10 -4
  612. vellum/client/types/test_suite_run_external_exec_config_data_request.py +10 -4
  613. vellum/client/types/test_suite_run_external_exec_config_request.py +10 -4
  614. vellum/client/types/test_suite_run_metric_array_output.py +11 -5
  615. vellum/client/types/test_suite_run_metric_error_output.py +3 -3
  616. vellum/client/types/test_suite_run_metric_json_output.py +2 -2
  617. vellum/client/types/test_suite_run_metric_number_output.py +2 -2
  618. vellum/client/types/test_suite_run_metric_output.py +5 -4
  619. vellum/client/types/test_suite_run_metric_string_output.py +2 -2
  620. vellum/client/types/test_suite_run_progress.py +2 -2
  621. vellum/client/types/test_suite_run_prompt_sandbox_exec_config_data_request.py +3 -3
  622. vellum/client/types/test_suite_run_prompt_sandbox_exec_config_request.py +3 -3
  623. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config.py +3 -3
  624. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_data.py +3 -3
  625. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_data_request.py +3 -3
  626. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_request.py +3 -3
  627. vellum/client/types/test_suite_run_read.py +12 -6
  628. vellum/client/types/test_suite_run_test_suite.py +2 -2
  629. vellum/client/types/test_suite_run_workflow_release_tag_exec_config.py +3 -3
  630. vellum/client/types/test_suite_run_workflow_release_tag_exec_config_data.py +3 -3
  631. vellum/client/types/test_suite_run_workflow_release_tag_exec_config_data_request.py +3 -3
  632. vellum/client/types/test_suite_run_workflow_release_tag_exec_config_request.py +3 -3
  633. vellum/client/types/test_suite_run_workflow_sandbox_exec_config_data_request.py +3 -3
  634. vellum/client/types/test_suite_run_workflow_sandbox_exec_config_request.py +3 -3
  635. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config.py +3 -3
  636. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_data.py +3 -3
  637. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_data_request.py +3 -3
  638. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_request.py +3 -3
  639. vellum/client/types/test_suite_test_case.py +10 -4
  640. vellum/client/types/test_suite_test_case_bulk_operation_request.py +2 -1
  641. vellum/client/types/test_suite_test_case_bulk_result.py +2 -1
  642. vellum/client/types/test_suite_test_case_create_bulk_operation_request.py +10 -4
  643. vellum/client/types/test_suite_test_case_created_bulk_result.py +3 -3
  644. vellum/client/types/test_suite_test_case_created_bulk_result_data.py +2 -2
  645. vellum/client/types/test_suite_test_case_delete_bulk_operation_data_request.py +2 -2
  646. vellum/client/types/test_suite_test_case_delete_bulk_operation_request.py +3 -3
  647. vellum/client/types/test_suite_test_case_deleted_bulk_result.py +3 -3
  648. vellum/client/types/test_suite_test_case_deleted_bulk_result_data.py +2 -2
  649. vellum/client/types/test_suite_test_case_rejected_bulk_result.py +2 -2
  650. vellum/client/types/test_suite_test_case_replace_bulk_operation_request.py +10 -4
  651. vellum/client/types/test_suite_test_case_replaced_bulk_result.py +3 -3
  652. vellum/client/types/test_suite_test_case_replaced_bulk_result_data.py +2 -2
  653. vellum/client/types/test_suite_test_case_upsert_bulk_operation_request.py +10 -4
  654. vellum/client/types/thinking_vellum_value.py +25 -0
  655. vellum/client/types/thinking_vellum_value_request.py +25 -0
  656. vellum/client/types/token_overlapping_window_chunker_config.py +2 -2
  657. vellum/client/types/token_overlapping_window_chunker_config_request.py +2 -2
  658. vellum/client/types/token_overlapping_window_chunking.py +3 -3
  659. vellum/client/types/token_overlapping_window_chunking_request.py +3 -3
  660. vellum/client/types/type_checker_enum.py +5 -0
  661. vellum/client/types/update_active_workspace_response.py +32 -0
  662. vellum/client/types/upload_document_response.py +3 -3
  663. vellum/client/types/uploaded_file_read.py +27 -0
  664. vellum/client/types/upsert_test_suite_test_case_request.py +9 -3
  665. vellum/client/types/variable_prompt_block.py +11 -4
  666. vellum/client/types/vellum_audio.py +10 -5
  667. vellum/client/types/vellum_audio_request.py +8 -4
  668. vellum/client/types/vellum_code_resource_definition.py +7 -2
  669. vellum/client/types/vellum_document.py +13 -4
  670. vellum/client/types/vellum_document_request.py +11 -3
  671. vellum/client/types/vellum_error.py +5 -4
  672. vellum/client/types/vellum_error_code_enum.py +6 -0
  673. vellum/client/types/vellum_error_request.py +5 -4
  674. vellum/client/types/vellum_image.py +13 -4
  675. vellum/client/types/vellum_image_request.py +11 -3
  676. vellum/client/types/vellum_node_execution_event.py +6 -3
  677. vellum/client/types/vellum_sdk_error.py +4 -3
  678. vellum/client/types/vellum_sdk_error_code_enum.py +5 -0
  679. vellum/client/types/vellum_secret.py +2 -2
  680. vellum/client/types/vellum_span.py +2 -1
  681. vellum/client/types/vellum_value.py +13 -8
  682. vellum/client/types/vellum_value_logical_condition_group_request.py +6 -6
  683. vellum/client/types/vellum_value_logical_condition_request.py +13 -7
  684. vellum/client/types/vellum_value_logical_expression_request.py +2 -1
  685. vellum/client/types/vellum_value_request.py +13 -8
  686. vellum/client/types/vellum_variable.py +18 -7
  687. vellum/client/types/vellum_variable_extensions.py +4 -2
  688. vellum/client/types/vellum_variable_type.py +4 -1
  689. vellum/client/types/vellum_video.py +29 -0
  690. vellum/client/types/vellum_video_request.py +28 -0
  691. vellum/client/types/vellum_workflow_execution_event.py +4 -3
  692. vellum/client/types/video_chat_message_content.py +25 -0
  693. vellum/client/types/video_chat_message_content_request.py +25 -0
  694. vellum/client/types/video_input.py +30 -0
  695. vellum/client/types/video_input_request.py +30 -0
  696. vellum/client/types/video_prompt_block.py +29 -0
  697. vellum/client/types/video_vellum_value.py +25 -0
  698. vellum/client/types/video_vellum_value_request.py +25 -0
  699. vellum/client/types/workflow_deployment_display_data.py +27 -0
  700. vellum/client/types/workflow_deployment_event_executions_response.py +20 -11
  701. vellum/client/types/workflow_deployment_history_item.py +10 -4
  702. vellum/client/types/workflow_deployment_parent_context.py +13 -10
  703. vellum/client/types/workflow_deployment_read.py +22 -10
  704. vellum/client/types/workflow_deployment_release.py +13 -7
  705. vellum/client/types/workflow_deployment_release_workflow_deployment.py +3 -2
  706. vellum/client/types/workflow_deployment_release_workflow_version.py +10 -4
  707. vellum/client/types/workflow_display_icon.py +24 -0
  708. vellum/client/types/workflow_error.py +1 -0
  709. vellum/client/types/workflow_event.py +39 -0
  710. vellum/client/types/workflow_event_error.py +5 -3
  711. vellum/client/types/workflow_event_execution_read.py +26 -16
  712. vellum/client/types/workflow_execution_actual.py +11 -5
  713. vellum/client/types/workflow_execution_actual_chat_history_request.py +2 -2
  714. vellum/client/types/workflow_execution_actual_json_request.py +2 -2
  715. vellum/client/types/workflow_execution_actual_string_request.py +2 -2
  716. vellum/client/types/workflow_execution_detail.py +51 -0
  717. vellum/client/types/workflow_execution_event_error_code.py +5 -0
  718. vellum/client/types/workflow_execution_fulfilled_body.py +6 -3
  719. vellum/client/types/workflow_execution_fulfilled_event.py +24 -15
  720. vellum/client/types/workflow_execution_initiated_body.py +3 -3
  721. vellum/client/types/workflow_execution_initiated_event.py +24 -15
  722. vellum/client/types/workflow_execution_node_result_event.py +10 -4
  723. vellum/client/types/workflow_execution_paused_body.py +4 -4
  724. vellum/client/types/workflow_execution_paused_event.py +24 -15
  725. vellum/client/types/workflow_execution_rejected_body.py +5 -4
  726. vellum/client/types/workflow_execution_rejected_event.py +24 -15
  727. vellum/client/types/workflow_execution_resumed_body.py +3 -3
  728. vellum/client/types/workflow_execution_resumed_event.py +24 -15
  729. vellum/client/types/workflow_execution_snapshotted_body.py +4 -3
  730. vellum/client/types/workflow_execution_snapshotted_event.py +24 -15
  731. vellum/client/types/workflow_execution_span.py +22 -11
  732. vellum/client/types/workflow_execution_span_attributes.py +3 -2
  733. vellum/client/types/workflow_execution_streaming_body.py +4 -4
  734. vellum/client/types/workflow_execution_streaming_event.py +24 -15
  735. vellum/client/types/workflow_execution_usage_calculation_error.py +3 -3
  736. vellum/client/types/workflow_execution_usage_calculation_fulfilled_body.py +22 -0
  737. vellum/client/types/workflow_execution_usage_result.py +3 -3
  738. vellum/client/types/workflow_execution_view_online_eval_metric_result.py +10 -4
  739. vellum/client/types/workflow_execution_workflow_result_event.py +10 -4
  740. vellum/client/types/workflow_expand_meta_request.py +2 -2
  741. vellum/client/types/workflow_initialization_error.py +2 -2
  742. vellum/client/types/workflow_input.py +31 -0
  743. vellum/client/types/workflow_node_result_data.py +8 -7
  744. vellum/client/types/workflow_node_result_event.py +3 -2
  745. vellum/client/types/workflow_output.py +12 -5
  746. vellum/client/types/workflow_output_array.py +12 -6
  747. vellum/client/types/workflow_output_audio.py +31 -0
  748. vellum/client/types/workflow_output_chat_history.py +3 -3
  749. vellum/client/types/workflow_output_document.py +31 -0
  750. vellum/client/types/workflow_output_error.py +3 -3
  751. vellum/client/types/workflow_output_function_call.py +3 -3
  752. vellum/client/types/workflow_output_image.py +3 -3
  753. vellum/client/types/workflow_output_json.py +3 -3
  754. vellum/client/types/workflow_output_number.py +3 -3
  755. vellum/client/types/workflow_output_search_results.py +3 -3
  756. vellum/client/types/workflow_output_string.py +3 -3
  757. vellum/client/types/workflow_output_video.py +31 -0
  758. vellum/client/types/workflow_parent_context.py +14 -11
  759. vellum/client/types/workflow_push_deployment_config_request.py +3 -2
  760. vellum/client/types/workflow_push_response.py +2 -2
  761. vellum/client/types/workflow_release_tag_read.py +4 -4
  762. vellum/client/types/workflow_release_tag_workflow_deployment_history_item.py +2 -2
  763. vellum/client/types/workflow_request_audio_input_request.py +30 -0
  764. vellum/client/types/workflow_request_chat_history_input_request.py +3 -3
  765. vellum/client/types/workflow_request_document_input_request.py +30 -0
  766. vellum/client/types/workflow_request_image_input_request.py +30 -0
  767. vellum/client/types/workflow_request_input_request.py +11 -2
  768. vellum/client/types/workflow_request_json_input_request.py +3 -3
  769. vellum/client/types/workflow_request_number_input_request.py +3 -3
  770. vellum/client/types/workflow_request_string_input_request.py +3 -3
  771. vellum/client/types/workflow_request_video_input_request.py +30 -0
  772. vellum/client/types/workflow_resolved_state.py +31 -0
  773. vellum/client/types/workflow_result_event.py +14 -8
  774. vellum/client/types/workflow_result_event_output_data.py +7 -6
  775. vellum/client/types/workflow_result_event_output_data_array.py +13 -7
  776. vellum/client/types/workflow_result_event_output_data_chat_history.py +4 -4
  777. vellum/client/types/workflow_result_event_output_data_error.py +4 -4
  778. vellum/client/types/workflow_result_event_output_data_function_call.py +4 -4
  779. vellum/client/types/workflow_result_event_output_data_json.py +4 -4
  780. vellum/client/types/workflow_result_event_output_data_number.py +4 -4
  781. vellum/client/types/workflow_result_event_output_data_search_results.py +4 -4
  782. vellum/client/types/workflow_result_event_output_data_string.py +4 -4
  783. vellum/client/types/workflow_result_event_state.py +7 -0
  784. vellum/client/types/workflow_sandbox_display_data.py +27 -0
  785. vellum/client/types/workflow_sandbox_example.py +4 -2
  786. vellum/client/types/workflow_sandbox_execute_node_response.py +8 -0
  787. vellum/client/types/workflow_sandbox_parent_context.py +13 -10
  788. vellum/client/types/workflow_stream_event.py +2 -1
  789. vellum/client/types/workspace_display_config.py +19 -0
  790. vellum/client/types/workspace_read.py +5 -3
  791. vellum/client/types/workspace_secret_read.py +3 -3
  792. vellum/client/utils.py +24 -0
  793. vellum/core/force_multipart.py +3 -0
  794. vellum/core/http_response.py +3 -0
  795. vellum/errors/misdirected_request_error.py +3 -0
  796. vellum/errors/too_many_requests_error.py +3 -0
  797. vellum/errors/unauthorized_error.py +3 -0
  798. vellum/evaluations/resources.py +5 -5
  799. vellum/plugins/pydantic.py +14 -3
  800. vellum/plugins/tests/__init__.py +0 -0
  801. vellum/plugins/tests/test_pydantic.py +30 -0
  802. vellum/plugins/vellum_mypy.py +68 -25
  803. vellum/prompts/__init__.py +3 -0
  804. vellum/prompts/blocks/__init__.py +3 -0
  805. vellum/prompts/blocks/compilation.py +29 -11
  806. vellum/prompts/blocks/helpers.py +31 -0
  807. vellum/prompts/blocks/tests/test_compilation.py +64 -0
  808. vellum/raw_client.py +3 -0
  809. vellum/resources/ad_hoc/raw_client.py +3 -0
  810. vellum/resources/container_images/raw_client.py +3 -0
  811. vellum/resources/deployments/raw_client.py +3 -0
  812. vellum/resources/document_indexes/raw_client.py +3 -0
  813. vellum/resources/documents/raw_client.py +3 -0
  814. vellum/resources/{release_reviews → environments}/__init__.py +1 -1
  815. vellum/resources/{release_reviews → environments}/client.py +1 -1
  816. vellum/resources/environments/raw_client.py +3 -0
  817. vellum/resources/events/__init__.py +3 -0
  818. vellum/resources/events/client.py +3 -0
  819. vellum/resources/events/raw_client.py +3 -0
  820. vellum/resources/folder_entities/raw_client.py +3 -0
  821. vellum/resources/integration_auth_configs/__init__.py +3 -0
  822. vellum/resources/integration_auth_configs/client.py +3 -0
  823. vellum/resources/integration_auth_configs/raw_client.py +3 -0
  824. vellum/resources/integration_providers/__init__.py +3 -0
  825. vellum/resources/integration_providers/client.py +3 -0
  826. vellum/resources/integration_providers/raw_client.py +3 -0
  827. vellum/resources/integrations/__init__.py +3 -0
  828. vellum/resources/integrations/client.py +3 -0
  829. vellum/resources/integrations/raw_client.py +3 -0
  830. vellum/resources/metric_definitions/raw_client.py +3 -0
  831. vellum/resources/ml_models/raw_client.py +3 -0
  832. vellum/resources/organizations/raw_client.py +3 -0
  833. vellum/resources/prompts/raw_client.py +3 -0
  834. vellum/resources/sandboxes/raw_client.py +3 -0
  835. vellum/resources/test_suite_runs/raw_client.py +3 -0
  836. vellum/resources/test_suites/raw_client.py +3 -0
  837. vellum/resources/uploaded_files/__init__.py +3 -0
  838. vellum/resources/uploaded_files/client.py +3 -0
  839. vellum/resources/uploaded_files/raw_client.py +3 -0
  840. vellum/resources/workflow_deployments/raw_client.py +3 -0
  841. vellum/resources/workflow_executions/__init__.py +3 -0
  842. vellum/resources/workflow_executions/client.py +3 -0
  843. vellum/resources/workflow_executions/raw_client.py +3 -0
  844. vellum/resources/workflow_sandboxes/raw_client.py +3 -0
  845. vellum/resources/workflows/raw_client.py +3 -0
  846. vellum/resources/workspace_secrets/raw_client.py +3 -0
  847. vellum/resources/workspaces/raw_client.py +3 -0
  848. vellum/types/api_actor_type_enum.py +3 -0
  849. vellum/types/audio_input.py +3 -0
  850. vellum/types/audio_input_request.py +3 -0
  851. vellum/types/auth_type_enum.py +3 -0
  852. vellum/types/build_status_enum.py +3 -0
  853. vellum/types/check_workflow_execution_status_error.py +3 -0
  854. vellum/types/check_workflow_execution_status_response.py +3 -0
  855. vellum/types/code_execution_package_request.py +3 -0
  856. vellum/types/components_schemas_composio_execute_tool_request.py +3 -0
  857. vellum/types/components_schemas_composio_execute_tool_response.py +3 -0
  858. vellum/types/components_schemas_composio_integration_exec_config.py +3 -0
  859. vellum/types/components_schemas_composio_tool_definition.py +3 -0
  860. vellum/types/components_schemas_slim_composio_tool_definition.py +3 -0
  861. vellum/types/composio_execute_tool_request.py +3 -0
  862. vellum/types/composio_execute_tool_response.py +3 -0
  863. vellum/types/composio_integration_exec_config.py +3 -0
  864. vellum/types/composio_tool_definition.py +3 -0
  865. vellum/types/container_image_build_config.py +3 -0
  866. vellum/types/create_workflow_event_request.py +3 -0
  867. vellum/types/dataset_row_push_request.py +3 -0
  868. vellum/types/delimiter_chunker_config.py +3 -0
  869. vellum/types/delimiter_chunker_config_request.py +3 -0
  870. vellum/types/delimiter_chunking.py +3 -0
  871. vellum/types/delimiter_chunking_request.py +3 -0
  872. vellum/types/deprecated_prompt_request_input.py +3 -0
  873. vellum/types/document_input.py +3 -0
  874. vellum/types/document_input_request.py +3 -0
  875. vellum/types/environment_display_config.py +3 -0
  876. vellum/types/environment_read.py +3 -0
  877. vellum/types/error_detail_response.py +3 -0
  878. vellum/types/event_create_response.py +3 -0
  879. vellum/types/execute_workflow_async_response.py +3 -0
  880. vellum/types/execution_audio_vellum_value.py +3 -0
  881. vellum/types/execution_document_vellum_value.py +3 -0
  882. vellum/types/execution_image_vellum_value.py +3 -0
  883. vellum/types/execution_thinking_vellum_value.py +3 -0
  884. vellum/types/execution_video_vellum_value.py +3 -0
  885. vellum/types/external_parent_context.py +3 -0
  886. vellum/types/fast_embed_vectorizer_baai_bge_small_en_v_15.py +3 -0
  887. vellum/types/fast_embed_vectorizer_baai_bge_small_en_v_15_request.py +3 -0
  888. vellum/types/folder_entity_dataset.py +3 -0
  889. vellum/types/folder_entity_dataset_data.py +3 -0
  890. vellum/types/google_vertex_ai_vectorizer_gemini_embedding_001.py +3 -0
  891. vellum/types/google_vertex_ai_vectorizer_gemini_embedding_001_request.py +3 -0
  892. vellum/types/image_input.py +3 -0
  893. vellum/types/image_input_request.py +3 -0
  894. vellum/types/integration.py +3 -0
  895. vellum/types/integration_auth_config_integration.py +3 -0
  896. vellum/types/integration_auth_config_integration_credential.py +3 -0
  897. vellum/types/integration_credential_access_type.py +3 -0
  898. vellum/types/integration_name.py +3 -0
  899. vellum/types/integration_provider.py +3 -0
  900. vellum/types/integration_read.py +3 -0
  901. vellum/types/integration_trigger_context.py +3 -0
  902. vellum/types/named_scenario_input_audio_variable_value_request.py +3 -0
  903. vellum/types/named_scenario_input_document_variable_value_request.py +3 -0
  904. vellum/types/named_scenario_input_image_variable_value_request.py +3 -0
  905. vellum/types/named_scenario_input_video_variable_value_request.py +3 -0
  906. vellum/types/named_test_case_audio_variable_value.py +3 -0
  907. vellum/types/named_test_case_audio_variable_value_request.py +3 -0
  908. vellum/types/named_test_case_document_variable_value.py +3 -0
  909. vellum/types/named_test_case_document_variable_value_request.py +3 -0
  910. vellum/types/named_test_case_image_variable_value.py +3 -0
  911. vellum/types/named_test_case_image_variable_value_request.py +3 -0
  912. vellum/types/named_test_case_video_variable_value.py +3 -0
  913. vellum/types/named_test_case_video_variable_value_request.py +3 -0
  914. vellum/types/node_execution_log_body.py +3 -0
  915. vellum/types/node_execution_log_event.py +3 -0
  916. vellum/types/node_input_compiled_audio_value.py +3 -0
  917. vellum/types/node_input_compiled_document_value.py +3 -0
  918. vellum/types/node_input_compiled_image_value.py +3 -0
  919. vellum/types/node_input_compiled_video_value.py +3 -0
  920. vellum/types/node_output_compiled_thinking_value.py +3 -0
  921. vellum/types/paginated_slim_integration_auth_config_read_list.py +3 -0
  922. vellum/types/paginated_slim_integration_read_list.py +3 -0
  923. vellum/types/paginated_slim_tool_definition_list.py +3 -0
  924. vellum/types/paginated_workflow_deployment_release_list.py +3 -0
  925. vellum/types/private_vectorizer.py +3 -0
  926. vellum/types/private_vectorizer_request.py +3 -0
  927. vellum/types/prompt_request_audio_input.py +3 -0
  928. vellum/types/prompt_request_document_input.py +3 -0
  929. vellum/types/prompt_request_image_input.py +3 -0
  930. vellum/types/prompt_request_video_input.py +3 -0
  931. vellum/types/runner_config_request.py +3 -0
  932. vellum/types/scenario_input_audio_variable_value.py +3 -0
  933. vellum/types/scenario_input_document_variable_value.py +3 -0
  934. vellum/types/scenario_input_image_variable_value.py +3 -0
  935. vellum/types/scenario_input_video_variable_value.py +3 -0
  936. vellum/types/scheduled_trigger_context.py +3 -0
  937. vellum/types/severity_enum.py +3 -0
  938. vellum/types/slim_composio_tool_definition.py +3 -0
  939. vellum/types/slim_integration_auth_config_read.py +3 -0
  940. vellum/types/slim_integration_read.py +3 -0
  941. vellum/types/test_case_audio_variable_value.py +3 -0
  942. vellum/types/test_case_document_variable_value.py +3 -0
  943. vellum/types/test_case_image_variable_value.py +3 -0
  944. vellum/types/test_case_video_variable_value.py +3 -0
  945. vellum/types/thinking_vellum_value.py +3 -0
  946. vellum/types/thinking_vellum_value_request.py +3 -0
  947. vellum/types/type_checker_enum.py +3 -0
  948. vellum/types/update_active_workspace_response.py +3 -0
  949. vellum/types/uploaded_file_read.py +3 -0
  950. vellum/types/vellum_video.py +3 -0
  951. vellum/types/vellum_video_request.py +3 -0
  952. vellum/types/video_chat_message_content.py +3 -0
  953. vellum/types/video_chat_message_content_request.py +3 -0
  954. vellum/types/video_input.py +3 -0
  955. vellum/types/video_input_request.py +3 -0
  956. vellum/types/video_prompt_block.py +3 -0
  957. vellum/types/video_vellum_value.py +3 -0
  958. vellum/types/video_vellum_value_request.py +3 -0
  959. vellum/types/workflow_deployment_display_data.py +3 -0
  960. vellum/types/workflow_display_icon.py +3 -0
  961. vellum/types/workflow_event.py +3 -0
  962. vellum/types/workflow_execution_detail.py +3 -0
  963. vellum/types/workflow_execution_usage_calculation_fulfilled_body.py +3 -0
  964. vellum/types/workflow_input.py +3 -0
  965. vellum/types/workflow_output_audio.py +3 -0
  966. vellum/types/workflow_output_document.py +3 -0
  967. vellum/types/workflow_output_video.py +3 -0
  968. vellum/types/workflow_request_audio_input_request.py +3 -0
  969. vellum/types/workflow_request_document_input_request.py +3 -0
  970. vellum/types/workflow_request_image_input_request.py +3 -0
  971. vellum/types/workflow_request_video_input_request.py +3 -0
  972. vellum/types/workflow_resolved_state.py +3 -0
  973. vellum/types/workflow_result_event_state.py +3 -0
  974. vellum/types/workflow_sandbox_display_data.py +3 -0
  975. vellum/types/workflow_sandbox_execute_node_response.py +3 -0
  976. vellum/types/workspace_display_config.py +3 -0
  977. vellum/utils/files/__init__.py +18 -0
  978. vellum/utils/files/constants.py +47 -0
  979. vellum/utils/files/exceptions.py +25 -0
  980. vellum/utils/files/extensions.py +59 -0
  981. vellum/utils/files/mixin.py +135 -0
  982. vellum/utils/files/read.py +41 -0
  983. vellum/utils/files/stream.py +135 -0
  984. vellum/utils/files/tests/__init__.py +0 -0
  985. vellum/utils/files/tests/test_extensions.py +54 -0
  986. vellum/utils/files/tests/test_mixin.py +267 -0
  987. vellum/utils/files/tests/test_read.py +204 -0
  988. vellum/utils/files/tests/test_stream.py +199 -0
  989. vellum/utils/files/tests/test_upload.py +309 -0
  990. vellum/utils/files/tests/test_urls.py +252 -0
  991. vellum/utils/files/types.py +8 -0
  992. vellum/utils/files/upload.py +151 -0
  993. vellum/utils/files/urls.py +71 -0
  994. vellum/utils/json_encoder.py +95 -0
  995. vellum/utils/templating/custom_filters.py +4 -4
  996. vellum/utils/templating/render.py +4 -4
  997. vellum/utils/tests/__init__.py +0 -0
  998. vellum/utils/tests/test_json_encoder.py +92 -0
  999. vellum/utils/tests/test_vellum_client.py +95 -0
  1000. vellum/utils/uuid.py +19 -2
  1001. vellum/utils/vellum_client.py +47 -0
  1002. vellum/workflows/__init__.py +84 -0
  1003. vellum/workflows/constants.py +7 -0
  1004. vellum/workflows/context.py +27 -9
  1005. vellum/workflows/descriptors/base.py +169 -2
  1006. vellum/workflows/descriptors/exceptions.py +18 -1
  1007. vellum/workflows/descriptors/tests/test_utils.py +66 -0
  1008. vellum/workflows/descriptors/utils.py +27 -3
  1009. vellum/workflows/edges/__init__.py +2 -0
  1010. vellum/workflows/edges/trigger_edge.py +67 -0
  1011. vellum/workflows/emitters/__init__.py +2 -0
  1012. vellum/workflows/emitters/base.py +25 -0
  1013. vellum/workflows/emitters/vellum_emitter.py +150 -0
  1014. vellum/workflows/environment/__init__.py +2 -1
  1015. vellum/workflows/environment/environment.py +10 -3
  1016. vellum/workflows/errors/tests/__init__.py +0 -0
  1017. vellum/workflows/errors/tests/test_types.py +52 -0
  1018. vellum/workflows/errors/types.py +19 -1
  1019. vellum/workflows/events/__init__.py +2 -0
  1020. vellum/workflows/events/context.py +90 -0
  1021. vellum/workflows/events/exception_handling.py +58 -0
  1022. vellum/workflows/events/node.py +51 -11
  1023. vellum/workflows/events/relational_threads.py +41 -0
  1024. vellum/workflows/events/stream.py +28 -0
  1025. vellum/workflows/events/tests/test_basic_workflow.py +50 -0
  1026. vellum/workflows/events/tests/test_event.py +268 -20
  1027. vellum/workflows/events/types.py +34 -5
  1028. vellum/workflows/events/workflow.py +138 -9
  1029. vellum/workflows/exceptions.py +46 -7
  1030. vellum/workflows/executable.py +9 -0
  1031. vellum/workflows/expressions/accessor.py +65 -11
  1032. vellum/workflows/expressions/add.py +44 -0
  1033. vellum/workflows/expressions/comparison_utils.py +38 -0
  1034. vellum/workflows/expressions/concat.py +35 -0
  1035. vellum/workflows/expressions/contains.py +7 -0
  1036. vellum/workflows/expressions/greater_than.py +8 -1
  1037. vellum/workflows/expressions/greater_than_or_equal_to.py +8 -1
  1038. vellum/workflows/expressions/is_error.py +23 -0
  1039. vellum/workflows/expressions/length.py +46 -0
  1040. vellum/workflows/expressions/less_than.py +8 -1
  1041. vellum/workflows/expressions/less_than_or_equal_to.py +8 -1
  1042. vellum/workflows/expressions/minus.py +41 -0
  1043. vellum/workflows/expressions/tests/test_accessor.py +248 -0
  1044. vellum/workflows/expressions/tests/test_add.py +96 -0
  1045. vellum/workflows/expressions/tests/test_concat.py +108 -0
  1046. vellum/workflows/expressions/tests/test_contains.py +175 -0
  1047. vellum/workflows/expressions/tests/test_expressions.py +145 -32
  1048. vellum/workflows/expressions/tests/test_length.py +38 -0
  1049. vellum/workflows/expressions/tests/test_minus.py +109 -0
  1050. vellum/workflows/graph/graph.py +281 -13
  1051. vellum/workflows/graph/tests/test_graph.py +528 -1
  1052. vellum/workflows/inputs/__init__.py +2 -0
  1053. vellum/workflows/inputs/base.py +63 -13
  1054. vellum/workflows/inputs/dataset_row.py +186 -0
  1055. vellum/workflows/inputs/tests/test_inputs.py +182 -2
  1056. vellum/workflows/integrations/__init__.py +5 -0
  1057. vellum/workflows/integrations/composio_service.py +158 -0
  1058. vellum/workflows/integrations/mcp_service.py +282 -0
  1059. vellum/workflows/integrations/tests/__init__.py +0 -0
  1060. vellum/workflows/integrations/tests/test_mcp_service.py +273 -0
  1061. vellum/workflows/integrations/tests/test_vellum_integration_service.py +383 -0
  1062. vellum/workflows/integrations/vellum_integration_service.py +147 -0
  1063. vellum/workflows/loaders/__init__.py +3 -0
  1064. vellum/workflows/loaders/base.py +38 -0
  1065. vellum/workflows/nodes/__init__.py +2 -0
  1066. vellum/workflows/nodes/bases/base.py +165 -82
  1067. vellum/workflows/nodes/bases/base_adornment_node.py +55 -1
  1068. vellum/workflows/nodes/bases/tests/test_base_node.py +153 -4
  1069. vellum/workflows/nodes/core/error_node/node.py +11 -2
  1070. vellum/workflows/nodes/core/inline_subworkflow_node/node.py +30 -3
  1071. vellum/workflows/nodes/core/inline_subworkflow_node/tests/test_node.py +36 -1
  1072. vellum/workflows/nodes/core/map_node/node.py +33 -6
  1073. vellum/workflows/nodes/core/map_node/tests/test_node.py +106 -0
  1074. vellum/workflows/nodes/core/retry_node/node.py +1 -0
  1075. vellum/workflows/nodes/core/retry_node/tests/test_node.py +2 -3
  1076. vellum/workflows/nodes/core/templating_node/node.py +7 -2
  1077. vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py +194 -1
  1078. vellum/workflows/nodes/core/try_node/node.py +1 -0
  1079. vellum/workflows/nodes/displayable/__init__.py +6 -0
  1080. vellum/workflows/nodes/displayable/api_node/node.py +13 -3
  1081. vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py +151 -2
  1082. vellum/workflows/nodes/displayable/bases/api_node/node.py +71 -17
  1083. vellum/workflows/nodes/displayable/bases/api_node/tests/__init__.py +0 -0
  1084. vellum/workflows/nodes/displayable/bases/api_node/tests/test_node.py +150 -0
  1085. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +85 -7
  1086. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +324 -19
  1087. vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py +352 -32
  1088. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +86 -3
  1089. vellum/workflows/nodes/displayable/bases/search_node.py +26 -3
  1090. vellum/workflows/nodes/displayable/bases/tests/test_prompt_deployment_node.py +90 -0
  1091. vellum/workflows/nodes/displayable/bases/utils.py +82 -5
  1092. vellum/workflows/nodes/displayable/code_execution_node/node.py +30 -10
  1093. vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py +284 -14
  1094. vellum/workflows/nodes/displayable/code_execution_node/utils.py +8 -21
  1095. vellum/workflows/nodes/displayable/conditional_node/node.py +8 -4
  1096. vellum/workflows/nodes/displayable/final_output_node/node.py +34 -0
  1097. vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py +146 -1
  1098. vellum/workflows/nodes/displayable/guardrail_node/node.py +13 -4
  1099. vellum/workflows/nodes/displayable/inline_prompt_node/node.py +9 -36
  1100. vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py +3 -0
  1101. vellum/workflows/nodes/displayable/merge_node/node.py +8 -1
  1102. vellum/workflows/nodes/displayable/note_node/node.py +11 -1
  1103. vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +7 -23
  1104. vellum/workflows/nodes/displayable/search_node/node.py +15 -2
  1105. vellum/workflows/nodes/displayable/search_node/tests/test_node.py +33 -0
  1106. vellum/workflows/nodes/displayable/set_state_node/__init__.py +5 -0
  1107. vellum/workflows/nodes/displayable/set_state_node/node.py +71 -0
  1108. vellum/workflows/nodes/displayable/set_state_node/tests/__init__.py +0 -0
  1109. vellum/workflows/nodes/displayable/set_state_node/tests/test_node.py +212 -0
  1110. vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +231 -59
  1111. vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py +1 -1
  1112. vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +4 -1
  1113. vellum/workflows/nodes/displayable/tests/test_search_node_error_handling.py +329 -0
  1114. vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +56 -14
  1115. vellum/workflows/nodes/displayable/tool_calling_node/__init__.py +3 -0
  1116. vellum/workflows/nodes/displayable/tool_calling_node/node.py +265 -0
  1117. vellum/workflows/nodes/displayable/tool_calling_node/state.py +11 -0
  1118. vellum/workflows/nodes/displayable/tool_calling_node/tests/__init__.py +0 -0
  1119. vellum/workflows/nodes/displayable/tool_calling_node/tests/test_composio_service.py +219 -0
  1120. vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py +998 -0
  1121. vellum/workflows/nodes/displayable/tool_calling_node/tests/test_utils.py +316 -0
  1122. vellum/workflows/nodes/displayable/tool_calling_node/utils.py +654 -0
  1123. vellum/workflows/nodes/displayable/web_search_node/__init__.py +3 -0
  1124. vellum/workflows/nodes/displayable/web_search_node/node.py +136 -0
  1125. vellum/workflows/nodes/displayable/web_search_node/tests/__init__.py +0 -0
  1126. vellum/workflows/nodes/displayable/web_search_node/tests/test_node.py +246 -0
  1127. vellum/workflows/nodes/experimental/__init__.py +1 -3
  1128. vellum/workflows/nodes/mocks.py +71 -206
  1129. vellum/workflows/nodes/tests/test_mocks.py +0 -177
  1130. vellum/workflows/nodes/tests/test_utils.py +34 -5
  1131. vellum/workflows/nodes/utils.py +68 -14
  1132. vellum/workflows/outputs/base.py +88 -14
  1133. vellum/workflows/ports/node_ports.py +3 -0
  1134. vellum/workflows/ports/port.py +27 -12
  1135. vellum/workflows/ports/tests/test_port.py +45 -0
  1136. vellum/workflows/ports/utils.py +26 -6
  1137. vellum/workflows/references/__init__.py +2 -0
  1138. vellum/workflows/references/constant.py +4 -1
  1139. vellum/workflows/references/environment_variable.py +17 -9
  1140. vellum/workflows/references/lazy.py +8 -0
  1141. vellum/workflows/references/output.py +4 -6
  1142. vellum/workflows/references/state_value.py +24 -1
  1143. vellum/workflows/references/tests/test_lazy.py +58 -0
  1144. vellum/workflows/references/trigger.py +82 -0
  1145. vellum/workflows/references/workflow_input.py +8 -0
  1146. vellum/workflows/resolvers/base.py +19 -1
  1147. vellum/workflows/resolvers/resolver.py +81 -0
  1148. vellum/workflows/resolvers/tests/test_resolver.py +199 -0
  1149. vellum/workflows/resolvers/types.py +11 -0
  1150. vellum/workflows/runner/runner.py +770 -143
  1151. vellum/workflows/runner/tests/__init__.py +0 -0
  1152. vellum/workflows/runner/tests/test_runner.py +170 -0
  1153. vellum/workflows/sandbox.py +54 -9
  1154. vellum/workflows/state/base.py +238 -55
  1155. vellum/workflows/state/context.py +297 -7
  1156. vellum/workflows/state/delta.py +20 -0
  1157. vellum/workflows/state/encoder.py +2 -77
  1158. vellum/workflows/state/tests/test_state.py +292 -9
  1159. vellum/workflows/tests/test_dataset_row.py +191 -0
  1160. vellum/workflows/tests/test_sandbox.py +226 -0
  1161. vellum/workflows/tests/triggers/test_integration_trigger.py +156 -0
  1162. vellum/workflows/triggers/__init__.py +7 -0
  1163. vellum/workflows/triggers/base.py +523 -0
  1164. vellum/workflows/triggers/chat_message.py +141 -0
  1165. vellum/workflows/triggers/integration.py +198 -0
  1166. vellum/workflows/triggers/manual.py +39 -0
  1167. vellum/workflows/triggers/schedule.py +20 -0
  1168. vellum/workflows/triggers/tests/__init__.py +1 -0
  1169. vellum/workflows/triggers/tests/test_base_trigger_display.py +147 -0
  1170. vellum/workflows/triggers/tests/test_chat_message.py +257 -0
  1171. vellum/workflows/triggers/tests/test_integration.py +155 -0
  1172. vellum/workflows/types/__init__.py +2 -1
  1173. vellum/workflows/types/code_execution_node_wrappers.py +5 -1
  1174. vellum/workflows/types/core.py +23 -0
  1175. vellum/workflows/types/definition.py +161 -2
  1176. vellum/workflows/types/generics.py +17 -0
  1177. vellum/workflows/types/tests/test_definition.py +183 -0
  1178. vellum/workflows/types/tests/test_utils.py +23 -0
  1179. vellum/workflows/types/utils.py +65 -5
  1180. vellum/workflows/types/workflow_metadata.py +124 -0
  1181. vellum/workflows/utils/files.py +28 -0
  1182. vellum/workflows/utils/functions.py +386 -25
  1183. vellum/workflows/utils/hmac.py +44 -0
  1184. vellum/workflows/utils/names.py +32 -4
  1185. vellum/workflows/utils/pydantic_schema.py +56 -0
  1186. vellum/workflows/utils/tests/test_functions.py +480 -23
  1187. vellum/workflows/utils/tests/test_names.py +9 -0
  1188. vellum/workflows/utils/tests/test_validate.py +79 -0
  1189. vellum/workflows/utils/tests/test_vellum_variables.py +93 -3
  1190. vellum/workflows/utils/uuids.py +125 -0
  1191. vellum/workflows/utils/validate.py +108 -0
  1192. vellum/workflows/utils/vellum_variables.py +224 -20
  1193. vellum/workflows/utils/zip.py +46 -0
  1194. vellum/workflows/vellum_client.py +3 -33
  1195. vellum/workflows/workflows/base.py +503 -50
  1196. vellum/workflows/workflows/event_filters.py +13 -0
  1197. vellum/workflows/workflows/tests/test_base_workflow.py +169 -6
  1198. vellum/workflows/workflows/tests/test_event_filters.py +126 -0
  1199. {vellum_ai-0.14.63.dist-info → vellum_ai-1.13.5.dist-info}/METADATA +17 -13
  1200. vellum_ai-1.13.5.dist-info/RECORD +2224 -0
  1201. vellum_ai-1.13.5.dist-info/entry_points.txt +4 -0
  1202. vellum_cli/__init__.py +55 -4
  1203. vellum_cli/config.py +21 -5
  1204. vellum_cli/image_push.py +106 -8
  1205. vellum_cli/move.py +56 -0
  1206. vellum_cli/ping.py +6 -0
  1207. vellum_cli/pull.py +50 -14
  1208. vellum_cli/push.py +124 -34
  1209. vellum_cli/tests/conftest.py +13 -12
  1210. vellum_cli/tests/test_image_push.py +192 -21
  1211. vellum_cli/tests/test_image_push_error_handling.py +258 -0
  1212. vellum_cli/tests/test_init.py +7 -24
  1213. vellum_cli/tests/test_move.py +154 -0
  1214. vellum_cli/tests/test_ping.py +15 -0
  1215. vellum_cli/tests/test_pull.py +125 -129
  1216. vellum_cli/tests/test_push.py +693 -12
  1217. vellum_ee/assets/node-definitions.json +1348 -0
  1218. vellum_ee/scripts/generate_node_definitions.py +101 -0
  1219. vellum_ee/workflows/display/base.py +33 -58
  1220. vellum_ee/workflows/display/editor/types.py +3 -0
  1221. vellum_ee/workflows/display/exceptions.py +3 -0
  1222. vellum_ee/workflows/display/nodes/base_node_display.py +199 -58
  1223. vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +242 -3
  1224. vellum_ee/workflows/display/nodes/types.py +1 -0
  1225. vellum_ee/workflows/display/nodes/vellum/api_node.py +26 -13
  1226. vellum_ee/workflows/display/nodes/vellum/base_adornment_node.py +8 -5
  1227. vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +23 -7
  1228. vellum_ee/workflows/display/nodes/vellum/conditional_node.py +18 -7
  1229. vellum_ee/workflows/display/nodes/vellum/error_node.py +2 -4
  1230. vellum_ee/workflows/display/nodes/vellum/final_output_node.py +3 -14
  1231. vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +2 -5
  1232. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +85 -44
  1233. vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +44 -18
  1234. vellum_ee/workflows/display/nodes/vellum/map_node.py +31 -15
  1235. vellum_ee/workflows/display/nodes/vellum/merge_node.py +2 -5
  1236. vellum_ee/workflows/display/nodes/vellum/note_node.py +20 -6
  1237. vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +13 -9
  1238. vellum_ee/workflows/display/nodes/vellum/retry_node.py +5 -6
  1239. vellum_ee/workflows/display/nodes/vellum/search_node.py +76 -19
  1240. vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +46 -12
  1241. vellum_ee/workflows/display/nodes/vellum/templating_node.py +3 -6
  1242. vellum_ee/workflows/display/nodes/vellum/tests/test_api_node.py +65 -0
  1243. vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py +236 -3
  1244. vellum_ee/workflows/display/nodes/vellum/tests/test_final_output_node.py +216 -0
  1245. vellum_ee/workflows/display/nodes/vellum/tests/test_inline_subworkflow_node.py +88 -0
  1246. vellum_ee/workflows/display/nodes/vellum/tests/test_note_node.py +44 -7
  1247. vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_deployment_node.py +71 -1
  1248. vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py +120 -26
  1249. vellum_ee/workflows/display/nodes/vellum/tests/test_retry_node.py +1 -1
  1250. vellum_ee/workflows/display/nodes/vellum/tests/test_search_node.py +104 -0
  1251. vellum_ee/workflows/display/nodes/vellum/tests/test_subworkflow_deployment_node.py +28 -18
  1252. vellum_ee/workflows/display/nodes/vellum/tests/test_templating_node.py +2 -2
  1253. vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py +649 -49
  1254. vellum_ee/workflows/display/nodes/vellum/tests/test_try_node.py +2 -2
  1255. vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +114 -10
  1256. vellum_ee/workflows/display/nodes/vellum/try_node.py +5 -6
  1257. vellum_ee/workflows/display/nodes/vellum/utils.py +54 -12
  1258. vellum_ee/workflows/display/tests/test_base_workflow_display.py +396 -25
  1259. vellum_ee/workflows/display/tests/test_json_schema_validation.py +190 -0
  1260. vellum_ee/workflows/display/tests/test_mocks.py +912 -0
  1261. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py +2 -2
  1262. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +114 -39
  1263. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +342 -90
  1264. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +24 -17
  1265. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +263 -65
  1266. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py +69 -12
  1267. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +36 -305
  1268. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +92 -431
  1269. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +143 -429
  1270. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_state_serialization.py +3 -123
  1271. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +24 -110
  1272. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py +12 -90
  1273. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +17 -86
  1274. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +363 -100
  1275. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +97 -315
  1276. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +66 -319
  1277. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +24 -99
  1278. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +54 -180
  1279. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py +32 -88
  1280. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_set_state_node_serialization.py +86 -0
  1281. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +217 -142
  1282. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py +34 -142
  1283. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +15 -8
  1284. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_composio_serialization.py +89 -0
  1285. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +184 -0
  1286. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_tool_wrapper_serialization.py +84 -0
  1287. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_mcp_serialization.py +104 -0
  1288. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_parent_input.py +89 -0
  1289. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +71 -23
  1290. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_tool_wrapper_serialization.py +71 -0
  1291. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_vellum_integration_serialization.py +187 -0
  1292. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py +107 -0
  1293. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +2 -4
  1294. vellum_ee/workflows/display/tests/workflow_serialization/test_chat_message_dict_reference_serialization.py +129 -0
  1295. vellum_ee/workflows/display/tests/workflow_serialization/test_chat_message_trigger_serialization.py +412 -0
  1296. vellum_ee/workflows/display/tests/workflow_serialization/test_code_tool_node_reference_error.py +106 -0
  1297. vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +20 -47
  1298. vellum_ee/workflows/display/tests/workflow_serialization/test_duplicate_trigger_name_validation.py +208 -0
  1299. vellum_ee/workflows/display/tests/workflow_serialization/test_final_output_node_map_reference_serialization.py +88 -0
  1300. vellum_ee/workflows/display/tests/workflow_serialization/test_final_output_node_not_referenced_by_workflow_outputs.py +45 -0
  1301. vellum_ee/workflows/display/tests/workflow_serialization/test_infinite_loop_validation.py +66 -0
  1302. vellum_ee/workflows/display/tests/workflow_serialization/test_int_input_serialization.py +40 -0
  1303. vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_serialization.py +300 -0
  1304. vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_validation.py +173 -0
  1305. vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_with_entrypoint_node_id.py +91 -0
  1306. vellum_ee/workflows/display/tests/workflow_serialization/test_list_vellum_document_serialization.py +69 -0
  1307. vellum_ee/workflows/display/tests/workflow_serialization/test_manual_trigger_serialization.py +120 -0
  1308. vellum_ee/workflows/display/tests/workflow_serialization/test_map_node_with_terminal_nodes_serialization.py +62 -0
  1309. vellum_ee/workflows/display/tests/workflow_serialization/test_multi_trigger_same_node_serialization.py +210 -0
  1310. vellum_ee/workflows/display/tests/workflow_serialization/test_no_triggers_no_entrypoint_validation.py +64 -0
  1311. vellum_ee/workflows/display/tests/workflow_serialization/test_partial_workflow_meta_display_override.py +55 -0
  1312. vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_dataset_mocks_serialization.py +268 -0
  1313. vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_invalid_pdf_data_url.py +49 -0
  1314. vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_validation_errors.py +112 -0
  1315. vellum_ee/workflows/display/tests/workflow_serialization/test_scheduled_trigger_serialization.py +276 -0
  1316. vellum_ee/workflows/display/tests/workflow_serialization/test_terminal_node_any_serialization.py +49 -0
  1317. vellum_ee/workflows/display/tests/workflow_serialization/test_terminal_node_in_unused_graphs_serialization.py +53 -0
  1318. vellum_ee/workflows/display/tests/workflow_serialization/test_trigger_display_from_display_class.py +153 -0
  1319. vellum_ee/workflows/display/tests/workflow_serialization/test_web_search_node_serialization.py +72 -0
  1320. vellum_ee/workflows/display/tests/workflow_serialization/test_workflow_input_parameterization_error.py +37 -0
  1321. vellum_ee/workflows/display/types.py +29 -2
  1322. vellum_ee/workflows/display/utils/auto_layout.py +130 -0
  1323. vellum_ee/workflows/display/utils/events.py +57 -0
  1324. vellum_ee/workflows/display/utils/exceptions.py +53 -0
  1325. vellum_ee/workflows/display/utils/expressions.py +669 -55
  1326. vellum_ee/workflows/display/utils/metadata.py +211 -0
  1327. vellum_ee/workflows/display/utils/registry.py +46 -0
  1328. vellum_ee/workflows/display/utils/tests/__init__.py +0 -0
  1329. vellum_ee/workflows/display/utils/tests/test_auto_layout.py +56 -0
  1330. vellum_ee/workflows/display/utils/tests/test_events.py +185 -0
  1331. vellum_ee/workflows/display/utils/tests/test_expressions.py +92 -0
  1332. vellum_ee/workflows/display/utils/tests/test_metadata.py +31 -0
  1333. vellum_ee/workflows/display/utils/triggers.py +153 -0
  1334. vellum_ee/workflows/display/utils/vellum.py +94 -5
  1335. vellum_ee/workflows/display/vellum.py +2 -128
  1336. vellum_ee/workflows/display/workflows/__init__.py +0 -1
  1337. vellum_ee/workflows/display/workflows/base_workflow_display.py +1224 -190
  1338. vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +26 -0
  1339. vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +379 -41
  1340. vellum_ee/workflows/server/namespaces.py +18 -0
  1341. vellum_ee/workflows/server/virtual_file_loader.py +131 -6
  1342. vellum_ee/workflows/tests/local_workflow/display/nodes/final_output.py +1 -1
  1343. vellum_ee/workflows/tests/local_workflow/display/nodes/templating_node.py +1 -1
  1344. vellum_ee/workflows/tests/local_workflow/display/workflow.py +11 -14
  1345. vellum_ee/workflows/tests/test_display_meta.py +43 -0
  1346. vellum_ee/workflows/tests/test_registry.py +169 -0
  1347. vellum_ee/workflows/tests/test_serialize_module.py +432 -0
  1348. vellum_ee/workflows/tests/test_server.py +616 -44
  1349. vellum_ee/workflows/tests/test_virtual_files.py +48 -0
  1350. vellum/client/resources/release_reviews/client.py +0 -137
  1351. vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py +0 -5
  1352. vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py +0 -266
  1353. vellum/workflows/nodes/experimental/tool_calling_node/__init__.py +0 -3
  1354. vellum/workflows/nodes/experimental/tool_calling_node/node.py +0 -135
  1355. vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py +0 -53
  1356. vellum/workflows/nodes/experimental/tool_calling_node/utils.py +0 -259
  1357. vellum_ai-0.14.63.dist-info/RECORD +0 -1719
  1358. vellum_ai-0.14.63.dist-info/entry_points.txt +0 -3
  1359. vellum_ee/workflows/display/workflows/vellum_workflow_display.py +0 -9
  1360. /vellum/{workflows/nodes/displayable/bases/inline_prompt_node → prompts}/constants.py +0 -0
  1361. {vellum_ai-0.14.63.dist-info → vellum_ai-1.13.5.dist-info}/LICENSE +0 -0
  1362. {vellum_ai-0.14.63.dist-info → vellum_ai-1.13.5.dist-info}/WHEEL +0 -0
@@ -1,27 +1,60 @@
1
1
  from copy import copy
2
+ from enum import Enum
3
+ import fnmatch
2
4
  from functools import cached_property
3
5
  import importlib
4
6
  import inspect
5
7
  import logging
8
+ import os
9
+ import pkgutil
10
+ import re
11
+ import traceback
6
12
  from uuid import UUID
7
- from typing import Any, Dict, ForwardRef, Generic, Iterator, List, Optional, Tuple, Type, TypeVar, Union, cast, get_args
13
+ from typing import (
14
+ Any,
15
+ Dict,
16
+ ForwardRef,
17
+ FrozenSet,
18
+ Generic,
19
+ List,
20
+ Literal,
21
+ Optional,
22
+ Set,
23
+ Tuple,
24
+ Type,
25
+ TypeVar,
26
+ Union,
27
+ cast,
28
+ get_args,
29
+ )
30
+
31
+ import jsonschema
8
32
 
9
33
  from vellum.client import Vellum as VellumClient
34
+ from vellum.client.core.pydantic_utilities import UniversalBaseModel
10
35
  from vellum.workflows import BaseWorkflow
11
36
  from vellum.workflows.constants import undefined
12
37
  from vellum.workflows.descriptors.base import BaseDescriptor
13
38
  from vellum.workflows.edges import Edge
39
+ from vellum.workflows.edges.trigger_edge import TriggerEdge
14
40
  from vellum.workflows.events.workflow import NodeEventDisplayContext, WorkflowEventDisplayContext
41
+ from vellum.workflows.exceptions import WorkflowInitializationException
42
+ from vellum.workflows.inputs.base import BaseInputs
43
+ from vellum.workflows.inputs.dataset_row import DatasetRow
15
44
  from vellum.workflows.nodes.bases import BaseNode
16
45
  from vellum.workflows.nodes.displayable.bases.utils import primitive_to_vellum_value
17
46
  from vellum.workflows.nodes.displayable.final_output_node.node import FinalOutputNode
18
47
  from vellum.workflows.nodes.utils import get_unadorned_node, get_unadorned_port, get_wrapped_node
19
48
  from vellum.workflows.ports import Port
20
- from vellum.workflows.references import OutputReference, WorkflowInputReference
21
- from vellum.workflows.types.core import JsonArray, JsonObject
49
+ from vellum.workflows.references import OutputReference, StateValueReference, WorkflowInputReference
50
+ from vellum.workflows.triggers.base import BaseTrigger
51
+ from vellum.workflows.triggers.chat_message import ChatMessageTrigger
52
+ from vellum.workflows.triggers.integration import IntegrationTrigger
53
+ from vellum.workflows.triggers.manual import ManualTrigger
54
+ from vellum.workflows.types.core import Json, JsonArray, JsonObject
22
55
  from vellum.workflows.types.generics import WorkflowType
23
56
  from vellum.workflows.types.utils import get_original_base
24
- from vellum.workflows.utils.uuids import uuid4_from_hash
57
+ from vellum.workflows.utils.uuids import generate_entity_id_from_path, uuid4_from_hash
25
58
  from vellum.workflows.vellum_client import create_vellum_client
26
59
  from vellum_ee.workflows.display.base import (
27
60
  EdgeDisplay,
@@ -30,13 +63,14 @@ from vellum_ee.workflows.display.base import (
30
63
  WorkflowInputsDisplay,
31
64
  WorkflowMetaDisplay,
32
65
  WorkflowOutputDisplay,
66
+ WorkflowTriggerType,
67
+ get_trigger_type_mapping,
33
68
  )
34
- from vellum_ee.workflows.display.editor.types import NodeDisplayData
69
+ from vellum_ee.workflows.display.editor.types import NodeDisplayData, NodeDisplayPosition
35
70
  from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
36
71
  from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
37
72
  from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay, PortDisplay
38
73
  from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
39
- from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
40
74
  from vellum_ee.workflows.display.types import (
41
75
  EdgeDisplays,
42
76
  EntrypointDisplays,
@@ -48,15 +82,86 @@ from vellum_ee.workflows.display.types import (
48
82
  WorkflowInputsDisplays,
49
83
  WorkflowOutputDisplays,
50
84
  )
85
+ from vellum_ee.workflows.display.utils.auto_layout import auto_layout_nodes
86
+ from vellum_ee.workflows.display.utils.exceptions import (
87
+ StateValidationError,
88
+ TriggerValidationError,
89
+ UserFacingException,
90
+ WorkflowValidationError,
91
+ )
51
92
  from vellum_ee.workflows.display.utils.expressions import serialize_value
93
+ from vellum_ee.workflows.display.utils.metadata import (
94
+ get_entrypoint_edge_id,
95
+ get_regular_edge_id,
96
+ get_trigger_edge_id,
97
+ load_dataset_row_index_to_id_mapping,
98
+ load_runner_config,
99
+ )
52
100
  from vellum_ee.workflows.display.utils.registry import register_workflow_display_class
53
- from vellum_ee.workflows.display.utils.vellum import infer_vellum_variable_type
101
+ from vellum_ee.workflows.display.utils.triggers import (
102
+ get_trigger_type,
103
+ serialize_trigger_attributes,
104
+ serialize_trigger_display_data,
105
+ )
106
+ from vellum_ee.workflows.display.utils.vellum import compile_descriptor_annotation, infer_vellum_variable_type
54
107
  from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
55
108
 
56
109
  logger = logging.getLogger(__name__)
57
110
 
111
+ IGNORE_PATTERNS = [
112
+ "*.pyc",
113
+ "__pycache__",
114
+ ".*",
115
+ "node_modules/*",
116
+ "*.log",
117
+ "metadata.json",
118
+ ]
119
+
120
+
121
+ class WorkflowSerializationError(UniversalBaseModel):
122
+ message: str
123
+ stacktrace: str
124
+
125
+
126
+ class WorkflowSerializationResult(UniversalBaseModel):
127
+ exec_config: Dict[str, Any]
128
+ errors: List[WorkflowSerializationError]
129
+ dataset: Optional[List[Dict[str, Any]]] = None
130
+
131
+
132
+ BASE_MODULE_PATH = __name__
133
+
134
+
135
+ class _BaseWorkflowDisplayMeta(type):
136
+ def __new__(mcs, name: str, bases: Tuple[Type[Any], ...], attrs: Dict[str, Any]) -> Type[Any]:
137
+ cls = super().__new__(mcs, name, bases, attrs)
138
+
139
+ # Automatically import all of the node displays now that we don't require the __init__.py file
140
+ # to do so for us.
141
+ module_path = cls.__module__
142
+ if module_path.startswith(BASE_MODULE_PATH):
143
+ return cls
144
+
145
+ nodes_module_path = re.sub(r"\.workflow$", ".nodes", module_path)
146
+ try:
147
+ nodes_module = importlib.import_module(nodes_module_path)
148
+ except Exception:
149
+ # likely because there are no `.nodes` module in the display workflow's module path
150
+ return cls
151
+
152
+ if not hasattr(nodes_module, "__path__") or not hasattr(nodes_module, "__name__"):
153
+ return cls
154
+
155
+ for info in pkgutil.iter_modules(nodes_module.__path__, nodes_module.__name__ + "."):
156
+ try:
157
+ importlib.import_module(info.name)
158
+ except Exception:
159
+ continue
160
+
161
+ return cls
162
+
58
163
 
59
- class BaseWorkflowDisplay(Generic[WorkflowType]):
164
+ class BaseWorkflowDisplay(Generic[WorkflowType], metaclass=_BaseWorkflowDisplayMeta):
60
165
  # Used to specify the display data for a workflow.
61
166
  workflow_display: Optional[WorkflowMetaDisplay] = None
62
167
 
@@ -78,7 +183,7 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
78
183
  # Used to explicitly specify display data for a workflow's ports.
79
184
  port_displays: PortDisplays = {}
80
185
 
81
- _errors: List[Exception]
186
+ _serialized_files: List[str]
82
187
 
83
188
  _dry_run: bool
84
189
 
@@ -96,40 +201,68 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
96
201
  if self._parent_display_context
97
202
  else create_vellum_client()
98
203
  )
99
- self._errors: List[Exception] = []
204
+ self._serialized_files = []
100
205
  self._dry_run = dry_run
101
206
 
102
207
  def serialize(self) -> JsonObject:
208
+ try:
209
+ self._workflow.validate()
210
+ except WorkflowInitializationException as e:
211
+ self.display_context.add_error(
212
+ WorkflowValidationError(message=e.message, workflow_class_name=self._workflow.__name__)
213
+ )
214
+
215
+ self._serialized_files = [
216
+ "__init__.py",
217
+ "display/*",
218
+ "inputs.py",
219
+ "nodes/*",
220
+ "state.py",
221
+ "workflow.py",
222
+ "triggers/*",
223
+ ]
224
+
103
225
  input_variables: JsonArray = []
104
226
  for workflow_input_reference, workflow_input_display in self.display_context.workflow_input_displays.items():
105
227
  default = (
106
228
  primitive_to_vellum_value(workflow_input_reference.instance)
107
- if workflow_input_reference.instance
229
+ if workflow_input_reference.instance is not None and workflow_input_reference.instance is not undefined
108
230
  else None
109
231
  )
232
+
233
+ is_required = self._is_reference_required(workflow_input_reference)
234
+
235
+ schema = compile_descriptor_annotation(workflow_input_reference)
236
+
110
237
  input_variables.append(
111
238
  {
112
239
  "id": str(workflow_input_display.id),
113
240
  "key": workflow_input_display.name or workflow_input_reference.name,
114
241
  "type": infer_vellum_variable_type(workflow_input_reference),
115
242
  "default": default.dict() if default else None,
116
- "required": workflow_input_reference.instance is undefined,
243
+ "required": is_required,
117
244
  "extensions": {"color": workflow_input_display.color},
245
+ "schema": schema,
118
246
  }
119
247
  )
120
248
 
121
249
  state_variables: JsonArray = []
122
250
  for state_value_reference, state_value_display in self.display_context.state_value_displays.items():
123
251
  default = (
124
- primitive_to_vellum_value(state_value_reference.instance) if state_value_reference.instance else None
252
+ primitive_to_vellum_value(state_value_reference.instance)
253
+ if state_value_reference.instance is not None and state_value_reference.instance is not undefined
254
+ else None
125
255
  )
256
+
257
+ is_required = self._is_reference_required(state_value_reference)
258
+
126
259
  state_variables.append(
127
260
  {
128
261
  "id": str(state_value_display.id),
129
262
  "key": state_value_display.name or state_value_reference.name,
130
263
  "type": infer_vellum_variable_type(state_value_reference),
131
264
  "default": default.dict() if default else None,
132
- "required": state_value_reference.instance is undefined,
265
+ "required": is_required,
133
266
  "extensions": {"color": state_value_display.color},
134
267
  }
135
268
  )
@@ -137,35 +270,147 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
137
270
  serialized_nodes: Dict[UUID, JsonObject] = {}
138
271
  edges: JsonArray = []
139
272
 
140
- # Add a single synthetic node for the workflow entrypoint
141
- entrypoint_node_id = self.display_context.workflow_display.entrypoint_node_id
142
- entrypoint_node_source_handle_id = self.display_context.workflow_display.entrypoint_node_source_handle_id
143
- serialized_nodes[entrypoint_node_id] = {
144
- "id": str(entrypoint_node_id),
145
- "type": "ENTRYPOINT",
146
- "inputs": [],
147
- "data": {
148
- "label": "Entrypoint Node",
149
- "source_handle_id": str(entrypoint_node_source_handle_id),
150
- },
151
- "display_data": self.display_context.workflow_display.entrypoint_node_display.dict(),
152
- "base": None,
153
- "definition": None,
154
- }
273
+ # Detect duplicate graph paths in the top-level set
274
+ # Signature includes: regular edges (with port identity) + trigger edges
275
+ seen_graph_signatures: Set[FrozenSet[Tuple[Literal["regular", "trigger"], int, Type[BaseNode]]]] = set()
276
+ seen_trigger_edges: Set[Tuple[Type[BaseTrigger], Type[BaseNode]]] = set()
277
+ trigger_edges: List[TriggerEdge] = []
278
+ for subgraph in self._workflow.get_subgraphs():
279
+ # Build signature from regular edges (include port identity to distinguish different ports)
280
+ edge_signature: Set[Tuple[Any, ...]] = set()
281
+ for edge in subgraph.edges:
282
+ # Use port identity (id(port)) to distinguish different ports from the same node
283
+ edge_signature.add(("regular", id(edge.from_port), get_unadorned_node(edge.to_node)))
284
+
285
+ # Include trigger edges in the signature
286
+ for trigger_edge in subgraph.trigger_edges:
287
+ edge_signature.add(
288
+ ("trigger", id(trigger_edge.trigger_class), get_unadorned_node(trigger_edge.to_node))
289
+ )
290
+
291
+ frozen_signature = frozenset(edge_signature)
292
+ if frozen_signature and frozen_signature in seen_graph_signatures:
293
+ self.display_context.add_validation_error(
294
+ WorkflowValidationError(
295
+ message="Duplicate graph path detected in workflow",
296
+ workflow_class_name=self._workflow.__name__,
297
+ )
298
+ )
299
+ elif frozen_signature:
300
+ seen_graph_signatures.add(frozen_signature)
301
+
302
+ # Collect and deduplicate trigger edges (for the trigger_edges list only)
303
+ for trigger_edge in subgraph.trigger_edges:
304
+ edge_key = (trigger_edge.trigger_class, get_unadorned_node(trigger_edge.to_node))
305
+ if edge_key not in seen_trigger_edges:
306
+ seen_trigger_edges.add(edge_key)
307
+ trigger_edges.append(trigger_edge)
308
+
309
+ # Determine if we need an ENTRYPOINT node and what ID to use
310
+ manual_trigger_edges = [edge for edge in trigger_edges if issubclass(edge.trigger_class, ManualTrigger)]
311
+ has_manual_trigger = len(manual_trigger_edges) > 0
312
+
313
+ # Determine which nodes have explicit non-trigger entrypoints in the graph
314
+ # This is used to decide whether to create an ENTRYPOINT node and skip entrypoint edges
315
+ non_trigger_entrypoint_nodes: Set[Type[BaseNode]] = set()
316
+ for subgraph in self._workflow.get_subgraphs():
317
+ if any(True for _ in subgraph.trigger_edges):
318
+ continue
319
+ for entrypoint in subgraph.entrypoints:
320
+ try:
321
+ non_trigger_entrypoint_nodes.add(get_unadorned_node(entrypoint))
322
+ except Exception:
323
+ continue
324
+
325
+ # Determine if we need an ENTRYPOINT node:
326
+ # - ManualTrigger: always need ENTRYPOINT (backward compatibility)
327
+ # - No triggers: always need ENTRYPOINT (traditional workflows)
328
+ # - Non-trigger entrypoints exist: need ENTRYPOINT for those branches
329
+ # - Only non-manual triggers with no regular entrypoints: skip ENTRYPOINT
330
+ has_triggers = len(trigger_edges) > 0
331
+ needs_entrypoint_node = has_manual_trigger or not has_triggers or len(non_trigger_entrypoint_nodes) > 0
332
+
333
+ # Validate that the workflow has at least one trigger or entrypoint node
334
+ if not has_triggers and len(non_trigger_entrypoint_nodes) == 0:
335
+ self.display_context.add_validation_error(
336
+ WorkflowValidationError(
337
+ message="Workflow has no triggers and no entrypoint nodes. "
338
+ "A workflow must have at least one trigger or one node in its graph.",
339
+ workflow_class_name=self._workflow.__name__,
340
+ )
341
+ )
342
+
343
+ entrypoint_node_id: Optional[UUID] = None
344
+ entrypoint_node_source_handle_id: Optional[UUID] = None
345
+ entrypoint_node_display = self.display_context.workflow_display.entrypoint_node_display
346
+
347
+ if has_manual_trigger:
348
+ # ManualTrigger: use trigger ID for ENTRYPOINT node (backward compatibility)
349
+ trigger_class = manual_trigger_edges[0].trigger_class
350
+ entrypoint_node_id = trigger_class.__id__
351
+ entrypoint_node_source_handle_id = self.display_context.workflow_display.entrypoint_node_source_handle_id
352
+
353
+ # Add ENTRYPOINT node for ManualTrigger workflows
354
+ serialized_nodes[entrypoint_node_id] = {
355
+ "id": str(entrypoint_node_id),
356
+ "type": "ENTRYPOINT",
357
+ "inputs": [],
358
+ "data": {
359
+ "label": "Entrypoint Node",
360
+ "source_handle_id": str(entrypoint_node_source_handle_id),
361
+ },
362
+ "display_data": entrypoint_node_display.dict() if entrypoint_node_display else NodeDisplayData().dict(),
363
+ "base": None,
364
+ "definition": None,
365
+ }
366
+ elif needs_entrypoint_node:
367
+ # No triggers or non-trigger entrypoints exist: use workflow_display ENTRYPOINT node
368
+ entrypoint_node_id = self.display_context.workflow_display.entrypoint_node_id
369
+ entrypoint_node_source_handle_id = self.display_context.workflow_display.entrypoint_node_source_handle_id
370
+
371
+ if entrypoint_node_id is not None and entrypoint_node_source_handle_id is not None:
372
+ display_data = entrypoint_node_display.dict() if entrypoint_node_display else NodeDisplayData().dict()
373
+ serialized_nodes[entrypoint_node_id] = {
374
+ "id": str(entrypoint_node_id),
375
+ "type": "ENTRYPOINT",
376
+ "inputs": [],
377
+ "data": {
378
+ "label": "Entrypoint Node",
379
+ "source_handle_id": str(entrypoint_node_source_handle_id),
380
+ },
381
+ "display_data": display_data,
382
+ "base": None,
383
+ "definition": None,
384
+ }
385
+ # else: only non-manual triggers with no regular entrypoints - skip ENTRYPOINT node
155
386
 
156
387
  # Add all the nodes in the workflows
157
388
  for node in self._workflow.get_all_nodes():
158
389
  node_display = self.display_context.node_displays[node]
159
390
 
160
391
  try:
392
+ try:
393
+ node.__validate__()
394
+ except (ValueError, jsonschema.exceptions.SchemaError) as validation_error:
395
+ # Only collect node validation errors directly to errors list, don't raise them
396
+ self.display_context.add_validation_error(validation_error)
397
+
161
398
  serialized_node = node_display.serialize(self.display_context)
162
- except NotImplementedError as e:
163
- self.add_error(e)
399
+ except (NotImplementedError, UserFacingException) as e:
400
+ self.display_context.add_error(e)
401
+ self.display_context.add_invalid_node(node)
164
402
  continue
165
403
 
166
- serialized_nodes[node_display.node_id] = serialized_node
404
+ # Use wrapped node's ID as dict key for adornment wrappers to prevent overwrites
405
+ wrapped_node = get_wrapped_node(node)
406
+ if wrapped_node:
407
+ wrapped_node_display = self.display_context.node_displays[wrapped_node]
408
+ dict_key = wrapped_node_display.node_id
409
+ else:
410
+ dict_key = node_display.node_id
411
+
412
+ serialized_nodes[dict_key] = serialized_node
167
413
 
168
- synthetic_output_edges: JsonArray = []
169
414
  output_variables: JsonArray = []
170
415
  output_values: JsonArray = []
171
416
  final_output_nodes = [
@@ -173,93 +418,37 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
173
418
  ]
174
419
  final_output_node_outputs = {node.Outputs.value for node in final_output_nodes}
175
420
  unreferenced_final_output_node_outputs = final_output_node_outputs.copy()
176
- final_output_node_base: JsonObject = {
177
- "name": FinalOutputNode.__name__,
178
- "module": cast(JsonArray, FinalOutputNode.__module__.split(".")),
179
- }
180
421
 
181
- # Add a synthetic Terminal Node and track the Workflow's output variables for each Workflow output
422
+ # Track the Workflow's output variables for each Workflow output
182
423
  for workflow_output, workflow_output_display in self.display_context.workflow_output_displays.items():
183
- final_output_node_id = uuid4_from_hash(f"{self.workflow_id}|node_id|{workflow_output.name}")
184
424
  inferred_type = infer_vellum_variable_type(workflow_output)
185
425
  # Remove the terminal node output from the unreferenced set
186
426
  if isinstance(workflow_output.instance, OutputReference):
187
427
  unreferenced_final_output_node_outputs.discard(workflow_output.instance)
188
428
 
189
- if workflow_output.instance not in final_output_node_outputs:
190
- # Create a synthetic terminal node only if there is no terminal node for this output
191
- try:
192
- node_input = create_node_input(
193
- final_output_node_id,
194
- "node_input",
195
- # This is currently the wrapper node's output, but we want the wrapped node
196
- workflow_output.instance,
197
- self.display_context,
198
- )
199
- except ValueError as e:
200
- raise ValueError(f"Failed to serialize output '{workflow_output.name}': {str(e)}") from e
201
-
202
- source_node_display: Optional[BaseNodeDisplay]
203
- first_rule = node_input.value.rules[0]
204
- if first_rule.type == "NODE_OUTPUT":
205
- source_node_id = UUID(first_rule.data.node_id)
206
- try:
207
- source_node_display = [
208
- node_display
209
- for node_display in self.display_context.node_displays.values()
210
- if node_display.node_id == source_node_id
211
- ][0]
212
- except IndexError:
213
- source_node_display = None
214
-
215
- synthetic_target_handle_id = str(
216
- uuid4_from_hash(f"{self.workflow_id}|target_handle_id|{workflow_output_display.name}")
217
- )
218
- synthetic_display_data = NodeDisplayData().dict()
219
- synthetic_node_label = "Final Output"
220
- serialized_nodes[final_output_node_id] = {
221
- "id": str(final_output_node_id),
222
- "type": "TERMINAL",
223
- "data": {
224
- "label": synthetic_node_label,
225
- "name": workflow_output_display.name,
226
- "target_handle_id": synthetic_target_handle_id,
227
- "output_id": str(workflow_output_display.id),
228
- "output_type": inferred_type,
229
- "node_input_id": str(node_input.id),
230
- },
231
- "inputs": [node_input.dict()],
232
- "display_data": synthetic_display_data,
233
- "base": final_output_node_base,
234
- "definition": None,
235
- }
236
-
237
- if source_node_display:
238
- source_handle_id = source_node_display.get_source_handle_id(
239
- port_displays=self.display_context.port_displays
240
- )
241
-
242
- synthetic_output_edges.append(
243
- {
244
- "id": str(uuid4_from_hash(f"{self.workflow_id}|edge_id|{workflow_output_display.name}")),
245
- "source_node_id": str(source_node_display.node_id),
246
- "source_handle_id": str(source_handle_id),
247
- "target_node_id": str(final_output_node_id),
248
- "target_handle_id": synthetic_target_handle_id,
249
- "type": "DEFAULT",
250
- }
251
- )
252
-
253
- elif isinstance(workflow_output.instance, OutputReference):
254
- terminal_node_id = workflow_output.instance.outputs_class._node_class.__id__
429
+ # Update the name of the terminal node if this output references a FinalOutputNode
430
+ if workflow_output.instance in final_output_node_outputs:
431
+ terminal_node_id = workflow_output.instance.outputs_class.__parent_class__.__id__
255
432
  serialized_terminal_node = serialized_nodes.get(terminal_node_id)
256
- if serialized_terminal_node and isinstance(serialized_terminal_node["data"], dict):
433
+ if (
434
+ serialized_terminal_node
435
+ and "data" in serialized_terminal_node
436
+ and isinstance(serialized_terminal_node["data"], dict)
437
+ ):
257
438
  serialized_terminal_node["data"]["name"] = workflow_output_display.name
258
439
 
440
+ try:
441
+ output_value = self.serialize_value(workflow_output.instance)
442
+ except UserFacingException as e:
443
+ self.display_context.add_error(
444
+ UserFacingException(f"Failed to serialize output '{workflow_output.name}': {e}")
445
+ )
446
+ continue
447
+
259
448
  output_values.append(
260
449
  {
261
450
  "output_variable_id": str(workflow_output_display.id),
262
- "value": serialize_value(self.display_context, workflow_output.instance),
451
+ "value": output_value,
263
452
  }
264
453
  )
265
454
 
@@ -274,91 +463,602 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
274
463
  # If there are terminal nodes with no workflow output reference,
275
464
  # raise a serialization error
276
465
  if len(unreferenced_final_output_node_outputs) > 0:
277
- self.add_error(
278
- ValueError("Unable to serialize terminal nodes that are not referenced by workflow outputs.")
466
+ self.display_context.add_error(
467
+ WorkflowValidationError(
468
+ message="Unable to serialize terminal nodes that are not referenced by workflow outputs.",
469
+ workflow_class_name=self._workflow.__name__,
470
+ )
279
471
  )
280
472
 
281
- # Add an edge for each edge in the workflow
473
+ # Identify nodes that already have trigger edges so we can avoid duplicating entrypoint edges
474
+ nodes_with_manual_trigger_edges: Set[Type[BaseNode]] = set()
475
+ nodes_with_non_manual_trigger_edges: Set[Type[BaseNode]] = set()
476
+ for trigger_edge in trigger_edges:
477
+ try:
478
+ unadorned_target_node = get_unadorned_node(trigger_edge.to_node)
479
+ except Exception:
480
+ continue
481
+
482
+ if issubclass(trigger_edge.trigger_class, ManualTrigger):
483
+ nodes_with_manual_trigger_edges.add(unadorned_target_node)
484
+ else:
485
+ nodes_with_non_manual_trigger_edges.add(unadorned_target_node)
486
+
487
+ # Track nodes with explicit entrypoint overrides so we retain their edges even if they have triggers
488
+ entrypoint_override_nodes: Set[Type[BaseNode]] = set()
489
+ for entrypoint_node in self.entrypoint_displays.keys():
490
+ try:
491
+ entrypoint_override_nodes.add(get_unadorned_node(entrypoint_node))
492
+ except Exception:
493
+ continue
494
+
495
+ # Add edges from entrypoint first to preserve expected ordering
496
+ # Note: non_trigger_entrypoint_nodes was computed earlier to determine if we need an ENTRYPOINT node
497
+
282
498
  for target_node, entrypoint_display in self.display_context.entrypoint_displays.items():
283
499
  unadorned_target_node = get_unadorned_node(target_node)
500
+
501
+ # Skip the auto-generated entrypoint edge when a manual trigger already targets this node or when a
502
+ # non-manual trigger targets it without an explicit entrypoint override, unless the graph explicitly
503
+ # defines a non-trigger entrypoint for it.
504
+ has_manual_trigger = unadorned_target_node in nodes_with_manual_trigger_edges
505
+ has_non_manual_trigger = unadorned_target_node in nodes_with_non_manual_trigger_edges
506
+ has_override = unadorned_target_node in entrypoint_override_nodes
507
+ if (
508
+ has_manual_trigger or (has_non_manual_trigger and not has_override)
509
+ ) and unadorned_target_node not in non_trigger_entrypoint_nodes:
510
+ continue
511
+
512
+ # Skip edges to invalid nodes
513
+ if self._is_node_invalid(unadorned_target_node):
514
+ continue
515
+
516
+ if entrypoint_node_id is None:
517
+ continue
518
+
284
519
  target_node_display = self.display_context.node_displays[unadorned_target_node]
285
- edges.append(
286
- {
287
- "id": str(entrypoint_display.edge_display.id),
288
- "source_node_id": str(entrypoint_node_id),
289
- "source_handle_id": str(entrypoint_node_source_handle_id),
290
- "target_node_id": str(target_node_display.node_id),
291
- "target_handle_id": str(target_node_display.get_trigger_id()),
292
- "type": "DEFAULT",
293
- }
520
+
521
+ stable_edge_id = get_entrypoint_edge_id(unadorned_target_node, self._workflow.__module__)
522
+
523
+ entrypoint_edge_dict: Dict[str, Json] = {
524
+ "id": str(stable_edge_id) if stable_edge_id else str(entrypoint_display.edge_display.id),
525
+ "source_node_id": str(entrypoint_node_id),
526
+ "source_handle_id": str(entrypoint_node_source_handle_id),
527
+ "target_node_id": str(target_node_display.node_id),
528
+ "target_handle_id": str(target_node_display.get_trigger_id()),
529
+ "type": "DEFAULT",
530
+ }
531
+ edge_display_data = self._serialize_edge_display_data(entrypoint_display.edge_display)
532
+ if edge_display_data is not None:
533
+ entrypoint_edge_dict["display_data"] = edge_display_data
534
+ edges.append(entrypoint_edge_dict)
535
+
536
+ # Then add trigger edges
537
+ for trigger_edge in trigger_edges:
538
+ target_node = trigger_edge.to_node
539
+ unadorned_target_node = get_unadorned_node(target_node)
540
+ if issubclass(trigger_edge.trigger_class, ManualTrigger):
541
+ nodes_with_manual_trigger_edges.add(unadorned_target_node)
542
+ else:
543
+ nodes_with_non_manual_trigger_edges.add(unadorned_target_node)
544
+
545
+ # Skip edges to invalid nodes
546
+ if self._is_node_invalid(unadorned_target_node):
547
+ continue
548
+
549
+ target_node_display = self.display_context.node_displays[unadorned_target_node]
550
+
551
+ # Get the entrypoint display for this target node (if it exists)
552
+ target_entrypoint_display = self.display_context.entrypoint_displays.get(target_node)
553
+ if target_entrypoint_display is None:
554
+ continue
555
+
556
+ trigger_class = trigger_edge.trigger_class
557
+ trigger_id = trigger_class.__id__
558
+
559
+ # Determine source node ID and handle ID based on trigger type
560
+ if issubclass(trigger_class, ManualTrigger):
561
+ source_node_id = entrypoint_node_id
562
+ source_handle_id = entrypoint_node_source_handle_id
563
+ else:
564
+ source_node_id = trigger_id
565
+ source_handle_id = trigger_id
566
+
567
+ # Prefer stable id from metadata mapping if present
568
+ stable_edge_id = get_trigger_edge_id(trigger_class, unadorned_target_node, self._workflow.__module__)
569
+
570
+ # Generate a unique fallback edge ID using trigger_id and target_node_id
571
+ # This ensures multiple triggers targeting the same node get unique edge IDs
572
+ fallback_edge_id = uuid4_from_hash(
573
+ f"{self.workflow_id}|trigger_edge|{trigger_id}|{target_node_display.node_id}"
294
574
  )
295
575
 
576
+ trigger_edge_dict: Dict[str, Json] = {
577
+ "id": str(stable_edge_id) if stable_edge_id else str(fallback_edge_id),
578
+ "source_node_id": str(source_node_id),
579
+ "source_handle_id": str(source_handle_id),
580
+ "target_node_id": str(target_node_display.node_id),
581
+ "target_handle_id": str(target_node_display.get_trigger_id()),
582
+ "type": "DEFAULT",
583
+ }
584
+ trigger_edge_display_data = self._serialize_edge_display_data(target_entrypoint_display.edge_display)
585
+ if trigger_edge_display_data is not None:
586
+ trigger_edge_dict["display_data"] = trigger_edge_display_data
587
+ edges.append(trigger_edge_dict)
588
+
296
589
  for (source_node_port, target_node), edge_display in self.display_context.edge_displays.items():
297
590
  unadorned_source_node_port = get_unadorned_port(source_node_port)
298
591
  unadorned_target_node = get_unadorned_node(target_node)
299
592
 
593
+ # Skip edges that reference invalid nodes
594
+ if self._is_node_invalid(unadorned_target_node) or self._is_node_invalid(
595
+ unadorned_source_node_port.node_class
596
+ ):
597
+ continue
598
+
300
599
  source_node_port_display = self.display_context.port_displays[unadorned_source_node_port]
301
600
  target_node_display = self.display_context.node_displays[unadorned_target_node]
302
601
 
303
- edges.append(
304
- {
305
- "id": str(edge_display.id),
306
- "source_node_id": str(source_node_port_display.node_id),
307
- "source_handle_id": str(source_node_port_display.id),
308
- "target_node_id": str(target_node_display.node_id),
309
- "target_handle_id": str(
310
- target_node_display.get_target_handle_id_by_source_node_id(source_node_port_display.node_id)
311
- ),
312
- "type": "DEFAULT",
313
- }
602
+ stable_edge_id = get_regular_edge_id(
603
+ unadorned_source_node_port.node_class,
604
+ source_node_port_display.id,
605
+ unadorned_target_node,
606
+ self._workflow.__module__,
607
+ )
608
+
609
+ regular_edge_dict: Dict[str, Json] = {
610
+ "id": str(stable_edge_id) if stable_edge_id else str(edge_display.id),
611
+ "source_node_id": str(source_node_port_display.node_id),
612
+ "source_handle_id": str(source_node_port_display.id),
613
+ "target_node_id": str(target_node_display.node_id),
614
+ "target_handle_id": str(
615
+ target_node_display.get_target_handle_id_by_source_node_id(source_node_port_display.node_id)
616
+ ),
617
+ "type": "DEFAULT",
618
+ }
619
+ regular_edge_display_data = self._serialize_edge_display_data(edge_display)
620
+ if regular_edge_display_data is not None:
621
+ regular_edge_dict["display_data"] = regular_edge_display_data
622
+ edges.append(regular_edge_dict)
623
+
624
+ nodes_list = list(serialized_nodes.values())
625
+ nodes_dict_list = [cast(Dict[str, Any], node) for node in nodes_list if isinstance(node, dict)]
626
+
627
+ all_nodes_at_zero = all(
628
+ (
629
+ isinstance(node.get("display_data"), dict)
630
+ and isinstance(node["display_data"].get("position"), dict)
631
+ and node["display_data"]["position"].get("x", 0) == 0.0
632
+ and node["display_data"]["position"].get("y", 0) == 0.0
314
633
  )
634
+ for node in nodes_dict_list
635
+ )
315
636
 
316
- edges.extend(synthetic_output_edges)
637
+ should_apply_auto_layout = all_nodes_at_zero and len(nodes_dict_list) > 0
317
638
 
318
- return {
319
- "workflow_raw_data": {
320
- "nodes": list(serialized_nodes.values()),
321
- "edges": edges,
322
- "display_data": self.display_context.workflow_display.display_data.dict(),
323
- "definition": {
324
- "name": self._workflow.__name__,
325
- "module": cast(JsonArray, self._workflow.__module__.split(".")),
326
- },
327
- "output_values": output_values,
639
+ if should_apply_auto_layout:
640
+ try:
641
+ self._apply_auto_layout(nodes_dict_list, edges)
642
+ except Exception as e:
643
+ self.display_context.add_error(e)
644
+
645
+ # Serialize workflow-level trigger if present
646
+ triggers: Optional[JsonArray] = self._serialize_workflow_trigger()
647
+
648
+ workflow_raw_data: JsonObject = {
649
+ "nodes": cast(JsonArray, nodes_dict_list),
650
+ "edges": edges,
651
+ "display_data": self.display_context.workflow_display.display_data.dict(),
652
+ "definition": {
653
+ "name": self._workflow.__name__,
654
+ "module": cast(JsonArray, self._workflow.__module__.split(".")),
328
655
  },
656
+ "output_values": output_values,
657
+ }
658
+
659
+ result: JsonObject = {
660
+ "workflow_raw_data": workflow_raw_data,
329
661
  "input_variables": input_variables,
330
662
  "state_variables": state_variables,
331
663
  "output_variables": output_variables,
332
664
  }
333
665
 
334
- @cached_property
335
- def workflow_id(self) -> UUID:
336
- """Can be overridden as a class attribute to specify a custom workflow id."""
337
- return self._workflow.__id__
666
+ if triggers is not None:
667
+ result["triggers"] = triggers
668
+
669
+ return result
670
+
671
+ def _serialize_workflow_trigger(self) -> Optional[JsonArray]:
672
+ """
673
+ Serialize workflow-level trigger information.
674
+
675
+ Returns:
676
+ JsonArray with trigger data if a trigger is present, None otherwise.
677
+ Each trigger in the array has: id (UUID), type (str), name (str), attributes (list)
678
+ """
679
+ # Get all trigger edges from the workflow's subgraphs
680
+ trigger_edges = []
681
+ for subgraph in self._workflow.get_subgraphs():
682
+ trigger_edges.extend(list(subgraph.trigger_edges))
683
+
684
+ if not trigger_edges:
685
+ # No workflow-level trigger defined
686
+ return None
687
+
688
+ unique_trigger_classes = list(dict.fromkeys(edge.trigger_class for edge in trigger_edges))
689
+
690
+ trigger_type_mapping = get_trigger_type_mapping()
691
+ serialized_triggers: List[JsonObject] = []
692
+ seen_trigger_names: Set[str] = set()
693
+
694
+ for trigger_class in unique_trigger_classes:
695
+ # Get the trigger type from the mapping, or use the utility function
696
+ trigger_type = trigger_type_mapping.get(trigger_class)
697
+ if trigger_type is None:
698
+ trigger_type = get_trigger_type(trigger_class)
699
+
700
+ trigger_id = trigger_class.__id__
701
+
702
+ # Determine trigger name from the trigger class's __trigger_name__ attribute
703
+ trigger_name = trigger_class.__trigger_name__
704
+
705
+ # Validate that trigger names are unique
706
+ if trigger_name in seen_trigger_names:
707
+ self.display_context.add_validation_error(
708
+ TriggerValidationError(
709
+ message=f"Duplicate trigger name '{trigger_name}' found. Each trigger must have a unique name.",
710
+ trigger_class_name=trigger_class.__name__,
711
+ )
712
+ )
713
+ seen_trigger_names.add(trigger_name)
714
+
715
+ # Serialize trigger attributes using the shared utility
716
+ trigger_attributes = serialize_trigger_attributes(trigger_class)
717
+
718
+ trigger_data: JsonObject
719
+ if trigger_type == WorkflowTriggerType.SCHEDULED:
720
+ # For scheduled triggers, include cron/timezone at top level
721
+ config_class = trigger_class.Config
722
+ cron_value = getattr(config_class, "cron", None)
723
+ timezone_value = getattr(config_class, "timezone", None)
724
+
725
+ trigger_data = {
726
+ "id": str(trigger_id),
727
+ "type": trigger_type.value,
728
+ "name": trigger_name,
729
+ "cron": cron_value,
730
+ "timezone": timezone_value,
731
+ "attributes": trigger_attributes,
732
+ }
733
+ else:
734
+ # For other triggers (integration, etc.)
735
+ trigger_data = {
736
+ "id": str(trigger_id),
737
+ "type": trigger_type.value,
738
+ "name": trigger_name,
739
+ "attributes": trigger_attributes,
740
+ }
741
+
742
+ if trigger_type == WorkflowTriggerType.INTEGRATION and issubclass(trigger_class, IntegrationTrigger):
743
+ exec_config = self._serialize_integration_trigger_exec_config(trigger_class)
744
+ trigger_data["exec_config"] = exec_config
745
+
746
+ # Validate trigger attributes against the expected types from the API
747
+ self._validate_integration_trigger_attributes(trigger_class, trigger_attributes)
748
+
749
+ if trigger_type == WorkflowTriggerType.CHAT_MESSAGE and issubclass(trigger_class, ChatMessageTrigger):
750
+ chat_exec_config = self._serialize_chat_message_trigger_exec_config(trigger_class)
751
+ if chat_exec_config:
752
+ trigger_data["exec_config"] = chat_exec_config
753
+
754
+ # Serialize display_data using the shared utility
755
+ display_data = serialize_trigger_display_data(trigger_class, trigger_type)
756
+
757
+ # Don't include display_data for manual triggers
758
+ if display_data and trigger_type != WorkflowTriggerType.MANUAL:
759
+ trigger_data["display_data"] = display_data
760
+
761
+ serialized_triggers.append(trigger_data)
338
762
 
339
- def add_error(self, error: Exception) -> None:
340
- if self._dry_run:
341
- self._errors.append(error)
763
+ return cast(JsonArray, serialized_triggers)
764
+
765
+ def _serialize_edge_display_data(self, edge_display: EdgeDisplay) -> Optional[JsonObject]:
766
+ """Serialize edge display data, returning None if no display data is present."""
767
+ if edge_display.z_index is not None:
768
+ return {"z_index": edge_display.z_index}
769
+ return None
770
+
771
+ def _serialize_integration_trigger_exec_config(self, trigger_class: Type[IntegrationTrigger]) -> JsonObject:
772
+ config_class = trigger_class.Config
773
+
774
+ provider = getattr(config_class, "provider", None)
775
+ if isinstance(provider, Enum):
776
+ provider = provider.value
777
+ elif provider is not None:
778
+ provider = str(provider)
779
+ slug = getattr(config_class, "slug", None)
780
+ integration_name = getattr(config_class, "integration_name", None)
781
+
782
+ setup_attributes: List[JsonObject] = []
783
+ raw_setup_attributes = getattr(config_class, "setup_attributes", None)
784
+
785
+ if isinstance(raw_setup_attributes, dict):
786
+ for key, value in raw_setup_attributes.items():
787
+ attribute_id = str(uuid4_from_hash(f"{trigger_class.__id__}|setup_attribute|{key}"))
788
+
789
+ default_json: Optional[JsonObject] = None
790
+ attribute_type = "STRING"
791
+
792
+ if value is not None:
793
+ try:
794
+ vellum_value = primitive_to_vellum_value(value)
795
+ default_json = cast(JsonObject, self._model_dump(vellum_value))
796
+ attribute_type = cast(str, default_json.get("type", attribute_type))
797
+ except ValueError:
798
+ default_json = None
799
+
800
+ setup_attributes.append(
801
+ cast(
802
+ JsonObject,
803
+ {
804
+ "id": attribute_id,
805
+ "key": str(key),
806
+ "type": attribute_type,
807
+ "required": True,
808
+ "default": default_json,
809
+ "extensions": {"color": None, "description": None},
810
+ },
811
+ )
812
+ )
813
+
814
+ return cast(
815
+ JsonObject,
816
+ {
817
+ "type": provider,
818
+ "slug": slug,
819
+ "integration_name": integration_name,
820
+ "setup_attributes": setup_attributes,
821
+ },
822
+ )
823
+
824
+ def _fetch_integration_trigger_definition(
825
+ self, provider: str, integration_name: str, trigger_slug: str
826
+ ) -> Optional[JsonObject]:
827
+ """
828
+ Fetch the trigger/tool definition from the API to get the expected attribute types.
829
+
830
+ Uses the client's integrations.retrieve_integration_tool_definition method.
831
+
832
+ Returns the tool definition with output_parameters (payload schema) if found, None otherwise.
833
+ For triggers, output_parameters contains the webhook payload schema, while input_parameters
834
+ contains setup/config arguments.
835
+ """
836
+ try:
837
+ tool_definition = self._client.integrations.retrieve_integration_tool_definition(
838
+ integration_name=integration_name,
839
+ integration_provider=provider,
840
+ tool_name=trigger_slug,
841
+ )
842
+ return cast(
843
+ JsonObject,
844
+ {
845
+ "name": tool_definition.name,
846
+ "output_parameters": tool_definition.output_parameters,
847
+ },
848
+ )
849
+ except Exception as e:
850
+ logger.warning(f"Error fetching tool definition for {trigger_slug}: {e}")
851
+ return None
852
+
853
+ def _validate_integration_trigger_attributes(
854
+ self,
855
+ trigger_class: Type[IntegrationTrigger],
856
+ trigger_attributes: JsonArray,
857
+ ) -> None:
858
+ """
859
+ Validate that the trigger attributes match the expected types from the API.
860
+
861
+ Raises TriggerValidationError if there's a type mismatch.
862
+ """
863
+ config_class = trigger_class.Config
864
+ provider = getattr(config_class, "provider", None)
865
+ if isinstance(provider, Enum):
866
+ provider = provider.value
867
+ elif provider is not None:
868
+ provider = str(provider)
869
+
870
+ slug = getattr(config_class, "slug", None)
871
+ integration_name = getattr(config_class, "integration_name", None)
872
+
873
+ if not provider or not slug or not integration_name:
342
874
  return
343
875
 
344
- raise error
876
+ trigger_def = self._fetch_integration_trigger_definition(provider, integration_name, slug)
877
+ if not trigger_def:
878
+ return
345
879
 
346
- @property
347
- def errors(self) -> Iterator[Exception]:
348
- return iter(self._errors)
880
+ # output_parameters contains the webhook payload schema for triggers
881
+ # (input_parameters contains setup/config arguments like team_id)
882
+ output_parameters = trigger_def.get("output_parameters", {})
883
+ if not output_parameters or not isinstance(output_parameters, dict):
884
+ return
885
+
886
+ # output_parameters is a JSON Schema object with structure:
887
+ # {"type": "object", "properties": {"key": {"type": "string"}, ...}, "required": [...]}
888
+ properties = output_parameters.get("properties", {})
889
+ if not properties or not isinstance(properties, dict):
890
+ return
891
+
892
+ # Map JSON Schema types to Vellum attribute types
893
+ json_schema_to_vellum_type: Dict[str, str] = {
894
+ "string": "STRING",
895
+ "number": "NUMBER",
896
+ "integer": "NUMBER",
897
+ "boolean": "BOOLEAN",
898
+ "object": "JSON",
899
+ "array": "ARRAY",
900
+ }
901
+
902
+ expected_types_by_key: Dict[str, str] = {}
903
+ for key, param_info in properties.items():
904
+ if not isinstance(param_info, dict):
905
+ continue
906
+ param_type = param_info.get("type")
907
+ if isinstance(param_type, str):
908
+ vellum_type = json_schema_to_vellum_type.get(param_type)
909
+ if vellum_type:
910
+ expected_types_by_key[key] = vellum_type
911
+
912
+ for attr in trigger_attributes:
913
+ if not isinstance(attr, dict):
914
+ continue
915
+ attr_key = attr.get("key")
916
+ actual_type = attr.get("type")
917
+ if isinstance(attr_key, str) and isinstance(actual_type, str) and attr_key in expected_types_by_key:
918
+ expected_type = expected_types_by_key[attr_key]
919
+ if actual_type != expected_type:
920
+ raise TriggerValidationError(
921
+ message=f"Attribute '{attr_key}' has type '{actual_type}' but expected type '{expected_type}'. "
922
+ "The trigger configuration is invalid or contains unsupported values.",
923
+ trigger_class_name=trigger_class.__name__,
924
+ )
925
+
926
+ def _serialize_chat_message_trigger_exec_config(
927
+ self, trigger_class: Type[ChatMessageTrigger]
928
+ ) -> Optional[JsonObject]:
929
+ config_class = trigger_class.Config
930
+ output = getattr(config_class, "output", None)
931
+
932
+ if output is None:
933
+ self.display_context.add_validation_error(
934
+ TriggerValidationError(
935
+ message="Chat Trigger output must be specified.",
936
+ trigger_class_name=trigger_class.__name__,
937
+ )
938
+ )
939
+ return None
940
+
941
+ self._validate_chat_history_state(trigger_class)
942
+
943
+ serialized_output = serialize_value(
944
+ executable_id=trigger_class.__id__,
945
+ display_context=self.display_context,
946
+ value=output,
947
+ )
948
+
949
+ return cast(
950
+ JsonObject,
951
+ {
952
+ "output": serialized_output,
953
+ },
954
+ )
955
+
956
+ def _validate_chat_history_state(self, trigger_class: Type[ChatMessageTrigger]) -> None:
957
+ state_class = self._workflow.get_state_class()
958
+
959
+ if not hasattr(state_class, "chat_history"):
960
+ self.display_context.add_validation_error(
961
+ StateValidationError(
962
+ message=(
963
+ "Chat triggers require a `chat_history` state variable. "
964
+ "Add `chat_history: List[ChatMessage] = Field(default_factory=list)` to your state class."
965
+ ),
966
+ state_class_name=state_class.__name__,
967
+ attribute_name="chat_history",
968
+ )
969
+ )
970
+ return
971
+
972
+ chat_history_ref = getattr(state_class, "chat_history")
973
+ if chat_history_ref.instance is None:
974
+ self.display_context.add_validation_error(
975
+ StateValidationError(
976
+ message=(
977
+ "Chat triggers expect chat_history to default to an empty array. "
978
+ "Use `Field(default_factory=list)` instead of `= None`."
979
+ ),
980
+ state_class_name=state_class.__name__,
981
+ attribute_name="chat_history",
982
+ )
983
+ )
984
+
985
+ @staticmethod
986
+ def _model_dump(value: Any) -> Any:
987
+ if hasattr(value, "model_dump"):
988
+ return value.model_dump(mode="json")
989
+ if hasattr(value, "dict"):
990
+ return value.dict()
991
+ return value
992
+
993
+ def _apply_auto_layout(self, nodes_dict_list: List[Dict[str, Any]], edges: List[Json]) -> None:
994
+ """Apply auto-layout to nodes that are all positioned at (0,0)."""
995
+ nodes_for_layout: List[Tuple[str, NodeDisplayData]] = []
996
+ for node_dict in nodes_dict_list:
997
+ if isinstance(node_dict.get("id"), str) and isinstance(node_dict.get("display_data"), dict):
998
+ display_data = node_dict["display_data"]
999
+ position = display_data.get("position", {})
1000
+ if isinstance(position, dict):
1001
+ nodes_for_layout.append(
1002
+ (
1003
+ str(node_dict["id"]),
1004
+ NodeDisplayData(
1005
+ position=NodeDisplayPosition(
1006
+ x=float(position.get("x", 0.0)), y=float(position.get("y", 0.0))
1007
+ ),
1008
+ width=display_data.get("width"),
1009
+ height=display_data.get("height"),
1010
+ comment=display_data.get("comment"),
1011
+ ),
1012
+ )
1013
+ )
1014
+
1015
+ edges_for_layout: List[Tuple[str, str, EdgeDisplay]] = []
1016
+ for edge in edges:
1017
+ if isinstance(edge, dict):
1018
+ edge_dict = cast(Dict[str, Any], edge)
1019
+ edge_source_node_id: Optional[Any] = edge_dict.get("source_node_id")
1020
+ edge_target_node_id: Optional[Any] = edge_dict.get("target_node_id")
1021
+ edge_id_raw: Optional[Any] = edge_dict.get("id")
1022
+ if (
1023
+ isinstance(edge_source_node_id, str)
1024
+ and isinstance(edge_target_node_id, str)
1025
+ and isinstance(edge_id_raw, str)
1026
+ ):
1027
+ edges_for_layout.append(
1028
+ (edge_source_node_id, edge_target_node_id, EdgeDisplay(id=UUID(edge_id_raw)))
1029
+ )
1030
+
1031
+ positioned_nodes = auto_layout_nodes(nodes_for_layout, edges_for_layout)
1032
+
1033
+ for node_id, positioned_data in positioned_nodes:
1034
+ for node_dict in nodes_dict_list:
1035
+ node_id_val = node_dict.get("id")
1036
+ display_data = node_dict.get("display_data")
1037
+ if isinstance(node_id_val, str) and node_id_val == node_id and isinstance(display_data, dict):
1038
+ display_data_dict = cast(Dict[str, Any], display_data)
1039
+ display_data_dict["position"] = positioned_data.position.dict()
1040
+
1041
+ @cached_property
1042
+ def workflow_id(self) -> UUID:
1043
+ """Can be overridden as a class attribute to specify a custom workflow id."""
1044
+ return self._workflow.__id__
349
1045
 
350
1046
  def _enrich_global_node_output_displays(
351
1047
  self,
352
1048
  node: Type[BaseNode],
353
1049
  node_display: BaseNodeDisplay,
354
- node_output_displays: Dict[OutputReference, Tuple[Type[BaseNode], NodeOutputDisplay]],
1050
+ node_output_displays: Dict[OutputReference, NodeOutputDisplay],
1051
+ node_displays: NodeDisplays,
1052
+ errors: List[Exception],
355
1053
  ):
356
1054
  """This method recursively adds nodes wrapped in decorators to the node_output_displays dictionary."""
357
1055
 
358
1056
  inner_node = get_wrapped_node(node)
359
1057
  if inner_node:
360
- inner_node_display = self._get_node_display(inner_node)
361
- self._enrich_global_node_output_displays(inner_node, inner_node_display, node_output_displays)
1058
+ inner_node_display = node_displays.get(inner_node) or self._get_node_display(inner_node, errors)
1059
+ self._enrich_global_node_output_displays(
1060
+ inner_node, inner_node_display, node_output_displays, node_displays, errors
1061
+ )
362
1062
 
363
1063
  for node_output in node.Outputs:
364
1064
  if node_output in node_output_displays:
@@ -371,13 +1071,15 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
371
1071
  node: Type[BaseNode],
372
1072
  node_display: BaseNodeDisplay,
373
1073
  port_displays: Dict[Port, PortDisplay],
1074
+ node_displays: NodeDisplays,
1075
+ errors: List[Exception],
374
1076
  ):
375
1077
  """This method recursively adds nodes wrapped in decorators to the port_displays dictionary."""
376
1078
 
377
1079
  inner_node = get_wrapped_node(node)
378
1080
  if inner_node:
379
- inner_node_display = self._get_node_display(inner_node)
380
- self._enrich_node_port_displays(inner_node, inner_node_display, port_displays)
1081
+ inner_node_display = node_displays.get(inner_node) or self._get_node_display(inner_node, errors)
1082
+ self._enrich_node_port_displays(inner_node, inner_node_display, port_displays, node_displays, errors)
381
1083
 
382
1084
  for port in node.Ports:
383
1085
  if port in port_displays:
@@ -385,12 +1087,18 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
385
1087
 
386
1088
  port_displays[port] = node_display.get_node_port_display(port)
387
1089
 
388
- def _get_node_display(self, node: Type[BaseNode]) -> BaseNodeDisplay:
1090
+ def _get_node_display(self, node: Type[BaseNode], errors: List[Exception]) -> BaseNodeDisplay:
389
1091
  node_display_class = get_node_display_class(node)
390
- return node_display_class()
1092
+ node_display = node_display_class()
1093
+ try:
1094
+ node_display.build(client=self._client)
1095
+ except Exception as e:
1096
+ errors.append(e)
1097
+ return node_display
391
1098
 
392
1099
  @cached_property
393
1100
  def display_context(self) -> WorkflowDisplayContext:
1101
+ errors: List[Exception] = []
394
1102
  workflow_meta_display = self._generate_workflow_meta_display()
395
1103
 
396
1104
  global_node_output_displays: NodeOutputDisplays = (
@@ -412,12 +1120,13 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
412
1120
  global_node_displays=global_node_displays,
413
1121
  global_node_output_displays=global_node_output_displays,
414
1122
  port_displays=port_displays,
1123
+ errors=errors,
415
1124
  )
416
1125
 
417
1126
  workflow_input_displays: WorkflowInputsDisplays = {}
418
1127
  # If we're dealing with a nested workflow, then it should have access to the inputs of its parents.
419
1128
  global_workflow_input_displays = (
420
- copy(self._parent_display_context.workflow_input_displays) if self._parent_display_context else {}
1129
+ copy(self._parent_display_context.global_workflow_input_displays) if self._parent_display_context else {}
421
1130
  )
422
1131
  for workflow_input in self._workflow.get_inputs_class():
423
1132
  workflow_input_display_overrides = self.inputs_display.get(workflow_input)
@@ -433,6 +1142,7 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
433
1142
  )
434
1143
  for state_value in self._workflow.get_state_class():
435
1144
  state_value_display_overrides = self.state_value_displays.get(state_value)
1145
+ self._validate_state_value_default(state_value, errors)
436
1146
  state_value_display = self._generate_state_value_display(
437
1147
  state_value, overrides=state_value_display_overrides
438
1148
  )
@@ -496,19 +1206,38 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
496
1206
  edge_displays=edge_displays,
497
1207
  port_displays=port_displays,
498
1208
  workflow_display_class=self.__class__,
1209
+ dry_run=self._dry_run,
1210
+ _errors=errors,
499
1211
  )
500
1212
 
501
1213
  def _generate_workflow_meta_display(self) -> WorkflowMetaDisplay:
1214
+ defaults = WorkflowMetaDisplay.get_default(self._workflow)
502
1215
  overrides = self.workflow_display
503
- if overrides:
504
- return WorkflowMetaDisplay(
505
- entrypoint_node_id=overrides.entrypoint_node_id,
506
- entrypoint_node_source_handle_id=overrides.entrypoint_node_source_handle_id,
507
- entrypoint_node_display=overrides.entrypoint_node_display,
508
- display_data=overrides.display_data,
509
- )
510
1216
 
511
- return WorkflowMetaDisplay.get_default(self._workflow)
1217
+ if not overrides:
1218
+ return defaults
1219
+
1220
+ # Merge overrides with defaults - if override provides None, fall back to default
1221
+ entrypoint_node_id = (
1222
+ overrides.entrypoint_node_id if overrides.entrypoint_node_id is not None else defaults.entrypoint_node_id
1223
+ )
1224
+ entrypoint_node_source_handle_id = (
1225
+ overrides.entrypoint_node_source_handle_id
1226
+ if overrides.entrypoint_node_source_handle_id is not None
1227
+ else defaults.entrypoint_node_source_handle_id
1228
+ )
1229
+ entrypoint_node_display = (
1230
+ overrides.entrypoint_node_display
1231
+ if overrides.entrypoint_node_display is not None
1232
+ else defaults.entrypoint_node_display
1233
+ )
1234
+
1235
+ return WorkflowMetaDisplay(
1236
+ entrypoint_node_id=entrypoint_node_id,
1237
+ entrypoint_node_source_handle_id=entrypoint_node_source_handle_id,
1238
+ entrypoint_node_display=entrypoint_node_display,
1239
+ display_data=overrides.display_data,
1240
+ )
512
1241
 
513
1242
  def _generate_workflow_input_display(
514
1243
  self, workflow_input: WorkflowInputReference, overrides: Optional[WorkflowInputsDisplay] = None
@@ -521,12 +1250,12 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
521
1250
  name = overrides.name
522
1251
  color = overrides.color
523
1252
  else:
524
- workflow_input_id = uuid4_from_hash(f"{self.workflow_id}|inputs|id|{workflow_input.name}")
1253
+ workflow_input_id = workflow_input.id
525
1254
 
526
1255
  return WorkflowInputsDisplay(id=workflow_input_id, name=name, color=color)
527
1256
 
528
1257
  def _generate_state_value_display(
529
- self, state_value: BaseDescriptor, overrides: Optional[StateValueDisplay] = None
1258
+ self, state_value: StateValueReference, overrides: Optional[StateValueDisplay] = None
530
1259
  ) -> StateValueDisplay:
531
1260
  state_value_id: UUID
532
1261
  name = None
@@ -536,10 +1265,25 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
536
1265
  name = overrides.name
537
1266
  color = overrides.color
538
1267
  else:
539
- state_value_id = uuid4_from_hash(f"{self.workflow_id}|state_values|id|{state_value.name}")
1268
+ state_value_id = state_value.id
540
1269
 
541
1270
  return StateValueDisplay(id=state_value_id, name=name, color=color)
542
1271
 
1272
+ def _validate_state_value_default(self, state_value: StateValueReference, errors: List[Exception]) -> None:
1273
+ default_value = state_value.instance
1274
+
1275
+ if isinstance(default_value, (list, dict, set)):
1276
+ errors.append(
1277
+ StateValidationError(
1278
+ message=(
1279
+ "Mutable default value detected. Use Field(default_factory=list) instead of = [] "
1280
+ "to avoid shared mutable state between instances."
1281
+ ),
1282
+ state_class_name=state_value.state_class.__name__,
1283
+ attribute_name=state_value.name,
1284
+ )
1285
+ )
1286
+
543
1287
  def _generate_entrypoint_display(
544
1288
  self,
545
1289
  entrypoint: Type[BaseNode],
@@ -560,16 +1304,17 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
560
1304
  target_node_display = node_displays[entrypoint_target]
561
1305
  target_node_id = target_node_display.node_id
562
1306
 
563
- edge_display = edge_display_overrides or self._generate_edge_display_from_source(
564
- entrypoint_node_id, target_node_id
565
- )
1307
+ if edge_display_overrides:
1308
+ edge_display = edge_display_overrides
1309
+ elif entrypoint_node_id is not None:
1310
+ edge_display = self._generate_edge_display_from_source(entrypoint_node_id, target_node_id)
1311
+ else:
1312
+ edge_display = EdgeDisplay(id=uuid4_from_hash(f"{self.workflow_id}|id|{target_node_id}"))
566
1313
 
567
1314
  return EntrypointDisplay(id=entrypoint_id, edge_display=edge_display)
568
1315
 
569
- def _generate_workflow_output_display(self, output: BaseDescriptor) -> WorkflowOutputDisplay:
570
- output_id = uuid4_from_hash(f"{self.workflow_id}|id|{output.name}")
571
-
572
- return WorkflowOutputDisplay(id=output_id, name=output.name)
1316
+ def _generate_workflow_output_display(self, output: OutputReference) -> WorkflowOutputDisplay:
1317
+ return WorkflowOutputDisplay(id=output.id, name=output.name)
573
1318
 
574
1319
  def __init_subclass__(cls, **kwargs: Any) -> None:
575
1320
  super().__init_subclass__(**kwargs)
@@ -587,8 +1332,7 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
587
1332
  try:
588
1333
  display_module = importlib.import_module(full_workflow_display_module_path)
589
1334
  except ModuleNotFoundError:
590
- logger.exception("Failed to import workflow display module: %s", full_workflow_display_module_path)
591
- return None
1335
+ return BaseWorkflowDisplay._gather_event_display_context_from_workflow_crawling(module_path, workflow_class)
592
1336
 
593
1337
  WorkflowDisplayClass: Optional[Type[BaseWorkflowDisplay]] = None
594
1338
  for name, definition in display_module.__dict__.items():
@@ -605,11 +1349,26 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
605
1349
  WorkflowDisplayClass = definition
606
1350
  break
607
1351
 
608
- if not WorkflowDisplayClass:
609
- logger.exception("No workflow display class found in module: %s", full_workflow_display_module_path)
610
- return None
1352
+ if WorkflowDisplayClass:
1353
+ return WorkflowDisplayClass().get_event_display_context()
1354
+
1355
+ return BaseWorkflowDisplay._gather_event_display_context_from_workflow_crawling(module_path, workflow_class)
1356
+
1357
+ @staticmethod
1358
+ def _gather_event_display_context_from_workflow_crawling(
1359
+ module_path: str,
1360
+ workflow_class: Optional[Type[BaseWorkflow]] = None,
1361
+ ) -> Union[WorkflowEventDisplayContext, None]:
1362
+ try:
1363
+ if workflow_class is None:
1364
+ workflow_class = BaseWorkflow.load_from_module(module_path)
1365
+
1366
+ workflow_display = get_workflow_display(workflow_class=workflow_class)
1367
+ return workflow_display.get_event_display_context()
611
1368
 
612
- return WorkflowDisplayClass().get_event_display_context()
1369
+ except ModuleNotFoundError:
1370
+ logger.exception("Failed to load workflow from module %s", module_path)
1371
+ return None
613
1372
 
614
1373
  def get_event_display_context(self):
615
1374
  display_context = self.display_context
@@ -622,6 +1381,13 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
622
1381
  input.name: display_context.workflow_input_displays[input].id
623
1382
  for input in display_context.workflow_input_displays
624
1383
  }
1384
+
1385
+ # Include trigger attributes in workflow_inputs so they appear in the executions list UI
1386
+ for subgraph in self._workflow.get_subgraphs():
1387
+ for trigger_class in subgraph.triggers:
1388
+ for trigger_attr_ref in trigger_class:
1389
+ if trigger_attr_ref.name not in workflow_inputs:
1390
+ workflow_inputs[trigger_attr_ref.name] = trigger_attr_ref.id
625
1391
  node_displays = {
626
1392
  node.__id__: (node, display_context.node_displays[node]) for node in display_context.node_displays
627
1393
  }
@@ -670,8 +1436,12 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
670
1436
  global_node_displays: NodeDisplays,
671
1437
  global_node_output_displays: NodeOutputDisplays,
672
1438
  port_displays: PortDisplays,
1439
+ errors: List[Exception],
673
1440
  ) -> None:
674
- extracted_node_displays = self._extract_node_displays(node)
1441
+ if node in node_displays:
1442
+ return
1443
+
1444
+ extracted_node_displays = self._extract_node_displays(node, errors)
675
1445
 
676
1446
  for extracted_node, extracted_node_display in extracted_node_displays.items():
677
1447
  if extracted_node not in node_displays:
@@ -680,11 +1450,15 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
680
1450
  if extracted_node not in global_node_displays:
681
1451
  global_node_displays[extracted_node] = extracted_node_display
682
1452
 
683
- self._enrich_global_node_output_displays(node, extracted_node_displays[node], global_node_output_displays)
684
- self._enrich_node_port_displays(node, extracted_node_displays[node], port_displays)
1453
+ self._enrich_global_node_output_displays(
1454
+ node, extracted_node_displays[node], global_node_output_displays, node_displays, errors
1455
+ )
1456
+ self._enrich_node_port_displays(node, extracted_node_displays[node], port_displays, node_displays, errors)
685
1457
 
686
- def _extract_node_displays(self, node: Type[BaseNode]) -> Dict[Type[BaseNode], BaseNodeDisplay]:
687
- node_display = self._get_node_display(node)
1458
+ def _extract_node_displays(
1459
+ self, node: Type[BaseNode], errors: List[Exception]
1460
+ ) -> Dict[Type[BaseNode], BaseNodeDisplay]:
1461
+ node_display = self._get_node_display(node, errors)
688
1462
  additional_node_displays: Dict[Type[BaseNode], BaseNodeDisplay] = {
689
1463
  node: node_display,
690
1464
  }
@@ -692,7 +1466,7 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
692
1466
  # Nodes wrapped in a decorator need to be in our node display dictionary for later retrieval
693
1467
  inner_node = get_wrapped_node(node)
694
1468
  if inner_node:
695
- inner_node_displays = self._extract_node_displays(inner_node)
1469
+ inner_node_displays = self._extract_node_displays(inner_node, errors)
696
1470
 
697
1471
  for node, display in inner_node_displays.items():
698
1472
  if node not in additional_node_displays:
@@ -739,5 +1513,265 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
739
1513
  def _workflow(self) -> Type[WorkflowType]:
740
1514
  return cast(Type[WorkflowType], self.__class__.infer_workflow_class())
741
1515
 
1516
+ @staticmethod
1517
+ def _collect_node_classes_from_module(
1518
+ module: Any,
1519
+ expected_module_prefix: str,
1520
+ ) -> List[Type[BaseNode]]:
1521
+ """
1522
+ Collect BaseNode subclasses defined in a module.
1523
+
1524
+ Args:
1525
+ module: The imported module to scan
1526
+ expected_module_prefix: Module path prefix to filter by (e.g., "my_module")
1527
+
1528
+ Returns:
1529
+ List of BaseNode subclasses defined in the module
1530
+ """
1531
+ node_classes: List[Type[BaseNode]] = []
1532
+ for name, attr in vars(module).items():
1533
+ if name.startswith("_"):
1534
+ continue
1535
+
1536
+ if not (inspect.isclass(attr) and issubclass(attr, BaseNode) and attr is not BaseNode):
1537
+ continue
1538
+
1539
+ if not attr.__module__.startswith(expected_module_prefix):
1540
+ continue
1541
+
1542
+ if "<locals>" in attr.__qualname__:
1543
+ continue
1544
+
1545
+ node_classes.append(attr)
1546
+
1547
+ return node_classes
1548
+
1549
+ @staticmethod
1550
+ def _find_orphan_nodes(
1551
+ base_module: str,
1552
+ workflow: Type[BaseWorkflow],
1553
+ ) -> List[Type[BaseNode]]:
1554
+ """
1555
+ Find nodes defined in the workflow package but not included in graph or unused_graphs.
1556
+
1557
+ Scans both the workflow.py file and the nodes/ subpackage for BaseNode subclasses.
1558
+
1559
+ Args:
1560
+ base_module: The base module path (e.g., "my_module")
1561
+ workflow: The workflow class to check
1562
+
1563
+ Returns:
1564
+ List of orphan node classes
1565
+ """
1566
+ workflow_nodes = set(workflow.get_all_nodes())
1567
+ candidate_nodes: List[Type[BaseNode]] = []
1568
+
1569
+ workflow_module_path = f"{base_module}.workflow"
1570
+ try:
1571
+ workflow_module = importlib.import_module(workflow_module_path)
1572
+ candidate_nodes.extend(BaseWorkflowDisplay._collect_node_classes_from_module(workflow_module, base_module))
1573
+ except ImportError:
1574
+ pass
1575
+
1576
+ nodes_package_path = f"{base_module}.nodes"
1577
+ try:
1578
+ nodes_package = importlib.import_module(nodes_package_path)
1579
+ if hasattr(nodes_package, "__path__"):
1580
+ for module_info in pkgutil.walk_packages(nodes_package.__path__, nodes_package.__name__ + "."):
1581
+ try:
1582
+ submodule = importlib.import_module(module_info.name)
1583
+ candidate_nodes.extend(
1584
+ BaseWorkflowDisplay._collect_node_classes_from_module(submodule, base_module)
1585
+ )
1586
+ except Exception:
1587
+ continue
1588
+ except ImportError:
1589
+ pass
1590
+
1591
+ seen: Set[Type[BaseNode]] = set()
1592
+ orphan_nodes: List[Type[BaseNode]] = []
1593
+ for node in candidate_nodes:
1594
+ if node in seen:
1595
+ continue
1596
+ seen.add(node)
1597
+ if node not in workflow_nodes:
1598
+ orphan_nodes.append(node)
1599
+
1600
+ return orphan_nodes
1601
+
1602
+ @staticmethod
1603
+ def serialize_module(
1604
+ module: str,
1605
+ *,
1606
+ client: Optional[VellumClient] = None,
1607
+ dry_run: bool = False,
1608
+ ) -> WorkflowSerializationResult:
1609
+ """
1610
+ Load a workflow from a module and serialize it to JSON.
1611
+
1612
+ Args:
1613
+ module: The module path to load the workflow from
1614
+ client: Optional Vellum client to use for serialization
1615
+ dry_run: Whether to run in dry-run mode
1616
+
1617
+ Returns:
1618
+ WorkflowSerializationResult containing exec_config and errors
1619
+ """
1620
+ workflow = BaseWorkflow.load_from_module(module)
1621
+ workflow_display = get_workflow_display(
1622
+ workflow_class=workflow,
1623
+ client=client,
1624
+ dry_run=dry_run,
1625
+ )
1626
+
1627
+ orphan_nodes = BaseWorkflowDisplay._find_orphan_nodes(module, workflow)
1628
+ for orphan_node in orphan_nodes:
1629
+ workflow_display.display_context.add_validation_error(
1630
+ WorkflowValidationError(
1631
+ message=f"Node '{orphan_node.__name__}' is defined in the module but not included in "
1632
+ "the workflow's graph or unused_graphs.",
1633
+ workflow_class_name=workflow.__name__,
1634
+ )
1635
+ )
1636
+
1637
+ exec_config = workflow_display.serialize()
1638
+ additional_files = workflow_display._gather_additional_module_files(module)
1639
+
1640
+ if additional_files:
1641
+ exec_config["module_data"] = {"additional_files": cast(JsonObject, additional_files)}
1642
+
1643
+ exec_config["runner_config"] = load_runner_config(module)
1644
+
1645
+ dataset = None
1646
+ try:
1647
+ sandbox_module_path = f"{module}.sandbox"
1648
+ sandbox_module = importlib.import_module(sandbox_module_path)
1649
+ if hasattr(sandbox_module, "dataset"):
1650
+ dataset_attr = getattr(sandbox_module, "dataset")
1651
+ if dataset_attr and isinstance(dataset_attr, list):
1652
+ dataset = []
1653
+ dataset_row_index_to_id = load_dataset_row_index_to_id_mapping(module)
1654
+ for i, inputs_obj in enumerate(dataset_attr):
1655
+ normalized_row = (
1656
+ DatasetRow(label=f"Scenario {i + 1}", inputs=inputs_obj)
1657
+ if isinstance(inputs_obj, BaseInputs)
1658
+ else inputs_obj
1659
+ )
1660
+
1661
+ row_data = normalized_row.model_dump(
1662
+ mode="json",
1663
+ by_alias=True,
1664
+ exclude_none=True,
1665
+ context={
1666
+ "add_error": workflow_display.display_context.add_validation_error,
1667
+ "serializer": workflow_display.serialize_value,
1668
+ },
1669
+ )
1670
+
1671
+ if i in dataset_row_index_to_id:
1672
+ row_data["id"] = dataset_row_index_to_id[i]
1673
+ elif isinstance(inputs_obj, DatasetRow) and inputs_obj.id is not None:
1674
+ row_data["id"] = inputs_obj.id
1675
+ else:
1676
+ row_data["id"] = str(generate_entity_id_from_path(f"{module}.sandbox.dataset.{i}"))
1677
+
1678
+ dataset.append(row_data)
1679
+ except ImportError:
1680
+ # No sandbox module exists, which is fine
1681
+ pass
1682
+ except Exception as e:
1683
+ # Capture any other errors (AttributeError, TypeError, etc.) from sandbox module
1684
+ workflow_display.display_context.add_validation_error(e)
1685
+
1686
+ all_errors = list(workflow_display.display_context.errors)
1687
+ return WorkflowSerializationResult(
1688
+ exec_config=exec_config,
1689
+ errors=[
1690
+ WorkflowSerializationError(
1691
+ message=str(error),
1692
+ stacktrace="".join(traceback.format_exception(type(error), error, error.__traceback__)),
1693
+ )
1694
+ for error in all_errors
1695
+ ],
1696
+ dataset=dataset,
1697
+ )
1698
+
1699
+ def serialize_value(self, value: Any) -> Any:
1700
+ return serialize_value(self.workflow_id, self.display_context, value)
1701
+
1702
+ _INCLUDED_FILE_EXTENSIONS = [".py"]
1703
+ _INCLUDED_FILENAMES = ["metadata.json"]
1704
+
1705
+ @staticmethod
1706
+ def should_include_file(filename: str) -> bool:
1707
+ """Check if a file should be included based on its extension or filename.
1708
+
1709
+ This is used by both the serialization logic and the push API to ensure
1710
+ consistency in which files are included in workflow artifacts.
1711
+ """
1712
+ if filename in BaseWorkflowDisplay._INCLUDED_FILENAMES:
1713
+ return True
1714
+ return any(filename.endswith(ext) for ext in BaseWorkflowDisplay._INCLUDED_FILE_EXTENSIONS)
1715
+
1716
+ def _gather_additional_module_files(self, module_path: str) -> Dict[str, str]:
1717
+ workflow_module_path = f"{module_path}.workflow"
1718
+ workflow_module = importlib.import_module(workflow_module_path)
1719
+
1720
+ workflow_file_path = workflow_module.__file__
1721
+ if not workflow_file_path:
1722
+ return {}
1723
+
1724
+ module_dir = os.path.dirname(workflow_file_path)
1725
+ additional_files = {}
1726
+
1727
+ for root, _, filenames in os.walk(module_dir):
1728
+ for filename in filenames:
1729
+ if not self.should_include_file(filename):
1730
+ continue
1731
+
1732
+ file_path = os.path.join(root, filename)
1733
+ relative_path = os.path.relpath(file_path, start=module_dir)
1734
+
1735
+ should_ignore = False
1736
+ for ignore_pattern in IGNORE_PATTERNS:
1737
+ if fnmatch.fnmatch(filename, ignore_pattern) or fnmatch.fnmatch(relative_path, ignore_pattern):
1738
+ should_ignore = True
1739
+ break
1740
+
1741
+ if not should_ignore:
1742
+ for serialized_pattern in self._serialized_files:
1743
+ if "*" in serialized_pattern:
1744
+ if fnmatch.fnmatch(relative_path, serialized_pattern) or fnmatch.fnmatch(
1745
+ filename, serialized_pattern
1746
+ ):
1747
+ should_ignore = True
1748
+ break
1749
+ else:
1750
+ if relative_path == serialized_pattern:
1751
+ should_ignore = True
1752
+ break
1753
+
1754
+ if should_ignore:
1755
+ continue
1756
+
1757
+ try:
1758
+ with open(file_path, encoding="utf-8") as f:
1759
+ additional_files[relative_path] = f.read()
1760
+ except (UnicodeDecodeError, PermissionError):
1761
+ continue
1762
+
1763
+ return additional_files
1764
+
1765
+ @staticmethod
1766
+ def _is_reference_required(reference: BaseDescriptor) -> bool:
1767
+ has_default = reference.instance is not undefined
1768
+ is_optional = type(None) in reference.types
1769
+ is_required = not has_default and not is_optional
1770
+ return is_required
1771
+
1772
+ def _is_node_invalid(self, node: Type[BaseNode]) -> bool:
1773
+ """Check if a node failed to serialize and should be considered invalid."""
1774
+ return node in self.display_context.invalid_nodes
1775
+
742
1776
 
743
1777
  register_workflow_display_class(workflow_class=BaseWorkflow, workflow_display_class=BaseWorkflowDisplay)