vellum-ai 1.11.2__py3-none-any.whl → 1.13.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (275) hide show
  1. vellum/__init__.py +18 -0
  2. vellum/client/README.md +1 -1
  3. vellum/client/core/client_wrapper.py +2 -2
  4. vellum/client/core/force_multipart.py +4 -2
  5. vellum/client/core/http_response.py +1 -1
  6. vellum/client/core/pydantic_utilities.py +7 -4
  7. vellum/client/errors/too_many_requests_error.py +1 -2
  8. vellum/client/reference.md +677 -76
  9. vellum/client/resources/container_images/client.py +299 -0
  10. vellum/client/resources/container_images/raw_client.py +286 -0
  11. vellum/client/resources/documents/client.py +20 -10
  12. vellum/client/resources/documents/raw_client.py +20 -10
  13. vellum/client/resources/events/raw_client.py +4 -4
  14. vellum/client/resources/integration_auth_configs/client.py +2 -0
  15. vellum/client/resources/integration_auth_configs/raw_client.py +2 -0
  16. vellum/client/resources/integration_providers/client.py +28 -2
  17. vellum/client/resources/integration_providers/raw_client.py +24 -0
  18. vellum/client/resources/integrations/client.py +52 -4
  19. vellum/client/resources/integrations/raw_client.py +61 -0
  20. vellum/client/resources/workflow_deployments/client.py +156 -0
  21. vellum/client/resources/workflow_deployments/raw_client.py +334 -0
  22. vellum/client/resources/workflows/client.py +212 -8
  23. vellum/client/resources/workflows/raw_client.py +343 -6
  24. vellum/client/types/__init__.py +18 -0
  25. vellum/client/types/api_actor_type_enum.py +1 -1
  26. vellum/client/types/check_workflow_execution_status_error.py +21 -0
  27. vellum/client/types/check_workflow_execution_status_response.py +29 -0
  28. vellum/client/types/code_execution_package_request.py +21 -0
  29. vellum/client/types/composio_execute_tool_request.py +5 -0
  30. vellum/client/types/composio_tool_definition.py +1 -0
  31. vellum/client/types/container_image_build_config.py +1 -0
  32. vellum/client/types/container_image_container_image_tag.py +1 -0
  33. vellum/client/types/dataset_row_push_request.py +3 -0
  34. vellum/client/types/document_document_to_document_index.py +1 -0
  35. vellum/client/types/integration_name.py +24 -0
  36. vellum/client/types/node_execution_fulfilled_body.py +1 -0
  37. vellum/client/types/node_execution_log_body.py +24 -0
  38. vellum/client/types/node_execution_log_event.py +47 -0
  39. vellum/client/types/prompt_deployment_release_prompt_deployment.py +1 -0
  40. vellum/client/types/runner_config_request.py +24 -0
  41. vellum/client/types/severity_enum.py +5 -0
  42. vellum/client/types/slim_composio_tool_definition.py +1 -0
  43. vellum/client/types/slim_document_document_to_document_index.py +2 -0
  44. vellum/client/types/type_checker_enum.py +5 -0
  45. vellum/client/types/vellum_audio.py +5 -1
  46. vellum/client/types/vellum_audio_request.py +5 -1
  47. vellum/client/types/vellum_document.py +5 -1
  48. vellum/client/types/vellum_document_request.py +5 -1
  49. vellum/client/types/vellum_image.py +5 -1
  50. vellum/client/types/vellum_image_request.py +5 -1
  51. vellum/client/types/vellum_node_execution_event.py +2 -0
  52. vellum/client/types/vellum_variable.py +5 -0
  53. vellum/client/types/vellum_variable_extensions.py +1 -0
  54. vellum/client/types/vellum_variable_type.py +1 -0
  55. vellum/client/types/vellum_video.py +5 -1
  56. vellum/client/types/vellum_video_request.py +5 -1
  57. vellum/client/types/workflow_deployment_release_workflow_deployment.py +1 -0
  58. vellum/client/types/workflow_event.py +2 -0
  59. vellum/client/types/workflow_execution_fulfilled_body.py +1 -0
  60. vellum/client/types/workflow_result_event_output_data_array.py +1 -1
  61. vellum/client/types/workflow_result_event_output_data_chat_history.py +1 -1
  62. vellum/client/types/workflow_result_event_output_data_error.py +1 -1
  63. vellum/client/types/workflow_result_event_output_data_function_call.py +1 -1
  64. vellum/client/types/workflow_result_event_output_data_json.py +1 -1
  65. vellum/client/types/workflow_result_event_output_data_number.py +1 -1
  66. vellum/client/types/workflow_result_event_output_data_search_results.py +1 -1
  67. vellum/client/types/workflow_result_event_output_data_string.py +1 -1
  68. vellum/client/types/workflow_sandbox_execute_node_response.py +8 -0
  69. vellum/plugins/vellum_mypy.py +37 -2
  70. vellum/types/check_workflow_execution_status_error.py +3 -0
  71. vellum/types/check_workflow_execution_status_response.py +3 -0
  72. vellum/types/code_execution_package_request.py +3 -0
  73. vellum/types/node_execution_log_body.py +3 -0
  74. vellum/types/node_execution_log_event.py +3 -0
  75. vellum/types/runner_config_request.py +3 -0
  76. vellum/types/severity_enum.py +3 -0
  77. vellum/types/type_checker_enum.py +3 -0
  78. vellum/types/workflow_sandbox_execute_node_response.py +3 -0
  79. vellum/utils/files/mixin.py +26 -0
  80. vellum/utils/files/tests/test_mixin.py +62 -0
  81. vellum/utils/tests/test_vellum_client.py +95 -0
  82. vellum/utils/uuid.py +19 -2
  83. vellum/utils/vellum_client.py +10 -3
  84. vellum/workflows/__init__.py +7 -1
  85. vellum/workflows/descriptors/base.py +86 -0
  86. vellum/workflows/descriptors/tests/test_utils.py +9 -0
  87. vellum/workflows/errors/tests/__init__.py +0 -0
  88. vellum/workflows/errors/tests/test_types.py +52 -0
  89. vellum/workflows/errors/types.py +1 -0
  90. vellum/workflows/events/node.py +24 -0
  91. vellum/workflows/events/tests/test_event.py +123 -0
  92. vellum/workflows/events/types.py +2 -1
  93. vellum/workflows/events/workflow.py +28 -2
  94. vellum/workflows/expressions/add.py +3 -0
  95. vellum/workflows/expressions/tests/test_add.py +24 -0
  96. vellum/workflows/graph/graph.py +26 -5
  97. vellum/workflows/graph/tests/test_graph.py +228 -1
  98. vellum/workflows/inputs/base.py +22 -6
  99. vellum/workflows/inputs/dataset_row.py +121 -16
  100. vellum/workflows/inputs/tests/test_inputs.py +3 -3
  101. vellum/workflows/integrations/tests/test_vellum_integration_service.py +84 -0
  102. vellum/workflows/integrations/vellum_integration_service.py +12 -1
  103. vellum/workflows/loaders/base.py +2 -0
  104. vellum/workflows/nodes/bases/base.py +37 -16
  105. vellum/workflows/nodes/bases/tests/test_base_node.py +104 -1
  106. vellum/workflows/nodes/core/inline_subworkflow_node/node.py +1 -0
  107. vellum/workflows/nodes/core/inline_subworkflow_node/tests/test_node.py +1 -1
  108. vellum/workflows/nodes/core/map_node/node.py +7 -5
  109. vellum/workflows/nodes/core/map_node/tests/test_node.py +33 -0
  110. vellum/workflows/nodes/core/retry_node/node.py +1 -0
  111. vellum/workflows/nodes/core/try_node/node.py +1 -0
  112. vellum/workflows/nodes/displayable/api_node/node.py +3 -2
  113. vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py +38 -0
  114. vellum/workflows/nodes/displayable/bases/api_node/node.py +1 -1
  115. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +18 -1
  116. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +109 -2
  117. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +13 -2
  118. vellum/workflows/nodes/displayable/code_execution_node/node.py +9 -15
  119. vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py +65 -24
  120. vellum/workflows/nodes/displayable/code_execution_node/utils.py +3 -0
  121. vellum/workflows/nodes/displayable/final_output_node/node.py +24 -69
  122. vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py +53 -3
  123. vellum/workflows/nodes/displayable/note_node/node.py +4 -1
  124. vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +16 -5
  125. vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +47 -0
  126. vellum/workflows/nodes/displayable/tool_calling_node/node.py +74 -34
  127. vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py +204 -8
  128. vellum/workflows/nodes/displayable/tool_calling_node/utils.py +92 -71
  129. vellum/workflows/nodes/mocks.py +47 -213
  130. vellum/workflows/nodes/tests/test_mocks.py +0 -177
  131. vellum/workflows/nodes/utils.py +23 -8
  132. vellum/workflows/outputs/base.py +36 -3
  133. vellum/workflows/references/environment_variable.py +1 -11
  134. vellum/workflows/references/lazy.py +8 -0
  135. vellum/workflows/references/state_value.py +24 -1
  136. vellum/workflows/references/tests/test_lazy.py +58 -0
  137. vellum/workflows/references/trigger.py +8 -3
  138. vellum/workflows/references/workflow_input.py +8 -0
  139. vellum/workflows/resolvers/resolver.py +13 -3
  140. vellum/workflows/resolvers/tests/test_resolver.py +31 -0
  141. vellum/workflows/runner/runner.py +159 -14
  142. vellum/workflows/runner/tests/__init__.py +0 -0
  143. vellum/workflows/runner/tests/test_runner.py +170 -0
  144. vellum/workflows/sandbox.py +7 -8
  145. vellum/workflows/state/base.py +89 -30
  146. vellum/workflows/state/context.py +74 -3
  147. vellum/workflows/state/tests/test_state.py +269 -1
  148. vellum/workflows/tests/test_dataset_row.py +8 -7
  149. vellum/workflows/tests/test_sandbox.py +97 -8
  150. vellum/workflows/triggers/__init__.py +2 -1
  151. vellum/workflows/triggers/base.py +160 -28
  152. vellum/workflows/triggers/chat_message.py +141 -0
  153. vellum/workflows/triggers/integration.py +12 -0
  154. vellum/workflows/triggers/manual.py +3 -1
  155. vellum/workflows/triggers/schedule.py +3 -1
  156. vellum/workflows/triggers/tests/test_chat_message.py +257 -0
  157. vellum/workflows/types/core.py +18 -0
  158. vellum/workflows/types/definition.py +6 -13
  159. vellum/workflows/types/generics.py +12 -0
  160. vellum/workflows/types/tests/test_utils.py +12 -0
  161. vellum/workflows/types/utils.py +32 -2
  162. vellum/workflows/types/workflow_metadata.py +124 -0
  163. vellum/workflows/utils/functions.py +152 -16
  164. vellum/workflows/utils/pydantic_schema.py +19 -1
  165. vellum/workflows/utils/tests/test_functions.py +123 -8
  166. vellum/workflows/utils/tests/test_validate.py +79 -0
  167. vellum/workflows/utils/tests/test_vellum_variables.py +62 -2
  168. vellum/workflows/utils/uuids.py +90 -0
  169. vellum/workflows/utils/validate.py +108 -0
  170. vellum/workflows/utils/vellum_variables.py +96 -16
  171. vellum/workflows/workflows/base.py +177 -35
  172. vellum/workflows/workflows/tests/test_base_workflow.py +51 -0
  173. {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/METADATA +6 -1
  174. {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/RECORD +274 -227
  175. vellum_cli/__init__.py +21 -0
  176. vellum_cli/config.py +16 -2
  177. vellum_cli/pull.py +2 -0
  178. vellum_cli/push.py +23 -10
  179. vellum_cli/tests/conftest.py +8 -13
  180. vellum_cli/tests/test_image_push.py +4 -11
  181. vellum_cli/tests/test_pull.py +83 -68
  182. vellum_cli/tests/test_push.py +251 -2
  183. vellum_ee/assets/node-definitions.json +225 -12
  184. vellum_ee/scripts/generate_node_definitions.py +15 -3
  185. vellum_ee/workflows/display/base.py +4 -3
  186. vellum_ee/workflows/display/nodes/base_node_display.py +44 -11
  187. vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +93 -0
  188. vellum_ee/workflows/display/nodes/types.py +1 -0
  189. vellum_ee/workflows/display/nodes/vellum/__init__.py +0 -2
  190. vellum_ee/workflows/display/nodes/vellum/base_adornment_node.py +5 -2
  191. vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +1 -1
  192. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +10 -2
  193. vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +17 -14
  194. vellum_ee/workflows/display/nodes/vellum/map_node.py +2 -0
  195. vellum_ee/workflows/display/nodes/vellum/note_node.py +18 -3
  196. vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +37 -14
  197. vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py +62 -2
  198. vellum_ee/workflows/display/nodes/vellum/tests/test_final_output_node.py +136 -0
  199. vellum_ee/workflows/display/nodes/vellum/tests/test_note_node.py +44 -7
  200. vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py +5 -13
  201. vellum_ee/workflows/display/nodes/vellum/tests/test_subworkflow_deployment_node.py +27 -17
  202. vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py +145 -22
  203. vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +107 -2
  204. vellum_ee/workflows/display/nodes/vellum/utils.py +54 -12
  205. vellum_ee/workflows/display/tests/test_base_workflow_display.py +13 -16
  206. vellum_ee/workflows/display/tests/test_json_schema_validation.py +190 -0
  207. vellum_ee/workflows/display/tests/test_mocks.py +912 -0
  208. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +14 -2
  209. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +109 -0
  210. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +3 -0
  211. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +187 -1
  212. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +34 -325
  213. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +42 -393
  214. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +13 -315
  215. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_state_serialization.py +2 -122
  216. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +24 -115
  217. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py +4 -93
  218. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +7 -80
  219. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +9 -101
  220. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +77 -308
  221. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +62 -324
  222. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +3 -82
  223. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +4 -142
  224. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py +1 -61
  225. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_set_state_node_serialization.py +4 -4
  226. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +205 -134
  227. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py +34 -146
  228. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +2 -0
  229. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_composio_serialization.py +8 -6
  230. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +137 -266
  231. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_tool_wrapper_serialization.py +84 -0
  232. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_mcp_serialization.py +55 -16
  233. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +15 -1
  234. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_tool_wrapper_serialization.py +71 -0
  235. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_vellum_integration_serialization.py +119 -0
  236. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py +1 -1
  237. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +0 -2
  238. vellum_ee/workflows/display/tests/workflow_serialization/test_chat_message_dict_reference_serialization.py +22 -1
  239. vellum_ee/workflows/display/tests/workflow_serialization/test_chat_message_trigger_serialization.py +412 -0
  240. vellum_ee/workflows/display/tests/workflow_serialization/test_code_tool_node_reference_error.py +106 -0
  241. vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +9 -41
  242. vellum_ee/workflows/display/tests/workflow_serialization/test_duplicate_trigger_name_validation.py +208 -0
  243. vellum_ee/workflows/display/tests/workflow_serialization/test_final_output_node_not_referenced_by_workflow_outputs.py +45 -0
  244. vellum_ee/workflows/display/tests/workflow_serialization/test_infinite_loop_validation.py +66 -0
  245. vellum_ee/workflows/display/tests/workflow_serialization/test_int_input_serialization.py +40 -0
  246. vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_serialization.py +8 -14
  247. vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_validation.py +173 -0
  248. vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_with_entrypoint_node_id.py +16 -13
  249. vellum_ee/workflows/display/tests/workflow_serialization/test_list_vellum_document_serialization.py +5 -1
  250. vellum_ee/workflows/display/tests/workflow_serialization/test_manual_trigger_serialization.py +12 -2
  251. vellum_ee/workflows/display/tests/workflow_serialization/test_multi_trigger_same_node_serialization.py +111 -0
  252. vellum_ee/workflows/display/tests/workflow_serialization/test_no_triggers_no_entrypoint_validation.py +64 -0
  253. vellum_ee/workflows/display/tests/workflow_serialization/test_partial_workflow_meta_display_override.py +55 -0
  254. vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_dataset_mocks_serialization.py +268 -0
  255. vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_invalid_pdf_data_url.py +49 -0
  256. vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_validation_errors.py +112 -0
  257. vellum_ee/workflows/display/tests/workflow_serialization/test_scheduled_trigger_serialization.py +25 -16
  258. vellum_ee/workflows/display/tests/workflow_serialization/test_terminal_node_in_unused_graphs_serialization.py +53 -0
  259. vellum_ee/workflows/display/utils/exceptions.py +34 -0
  260. vellum_ee/workflows/display/utils/expressions.py +463 -52
  261. vellum_ee/workflows/display/utils/metadata.py +98 -33
  262. vellum_ee/workflows/display/utils/tests/test_metadata.py +31 -0
  263. vellum_ee/workflows/display/utils/triggers.py +153 -0
  264. vellum_ee/workflows/display/utils/vellum.py +59 -5
  265. vellum_ee/workflows/display/workflows/base_workflow_display.py +656 -254
  266. vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +26 -0
  267. vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +77 -29
  268. vellum_ee/workflows/server/namespaces.py +18 -0
  269. vellum_ee/workflows/tests/test_display_meta.py +2 -0
  270. vellum_ee/workflows/tests/test_serialize_module.py +174 -7
  271. vellum_ee/workflows/tests/test_server.py +0 -3
  272. vellum_ee/workflows/display/nodes/vellum/function_node.py +0 -14
  273. {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/LICENSE +0 -0
  274. {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/WHEEL +0 -0
  275. {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/entry_points.txt +0 -0
@@ -1,108 +1,28 @@
1
- from functools import reduce
2
- from uuid import UUID
3
- from typing import TYPE_CHECKING, Any, Callable, Dict, List, Literal, Optional, Sequence, Type, Union
1
+ import logging
2
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Sequence, Type, Union
4
3
 
5
4
  from pydantic import ConfigDict, SerializationInfo, ValidationError, field_serializer, model_serializer
6
5
 
7
6
  from vellum.client.core.pydantic_utilities import UniversalBaseModel
8
7
  from vellum.client.types.array_vellum_value import ArrayVellumValue
9
- from vellum.client.types.vellum_value import VellumValue
10
8
  from vellum.workflows.descriptors.base import BaseDescriptor
11
9
  from vellum.workflows.errors.types import WorkflowErrorCode
12
10
  from vellum.workflows.events.types import default_serializer
13
- from vellum.workflows.exceptions import WorkflowInitializationException
11
+ from vellum.workflows.exceptions import NodeException, WorkflowInitializationException
12
+ from vellum.workflows.nodes.utils import get_unadorned_node
14
13
  from vellum.workflows.outputs.base import BaseOutputs
15
14
  from vellum.workflows.references.constant import ConstantValueReference
16
15
 
17
16
  if TYPE_CHECKING:
18
17
  from vellum.workflows import BaseWorkflow
19
18
 
20
- import logging
21
-
22
19
  logger = logging.getLogger(__name__)
23
20
 
24
21
 
25
- class _RawLogicalCondition(UniversalBaseModel):
26
- type: Literal["LOGICAL_CONDITION"] = "LOGICAL_CONDITION"
27
- lhs_variable_id: UUID
28
- operator: Literal["==", ">", ">=", "<", "<=", "!="]
29
- rhs_variable_id: UUID
30
-
31
-
32
- class _RawLogicalConditionGroup(UniversalBaseModel):
33
- type: Literal["LOGICAL_CONDITION_GROUP"] = "LOGICAL_CONDITION_GROUP"
34
- conditions: List["_RawLogicalExpression"]
35
- combinator: Literal["AND", "OR"]
36
- negated: bool
37
-
38
-
39
- _RawLogicalExpression = Union[_RawLogicalCondition, _RawLogicalConditionGroup]
40
-
41
-
42
- class _RawLogicalExpressionVariable(UniversalBaseModel):
43
- id: UUID
44
-
45
-
46
- class _RawMockWorkflowNodeExecutionConstantValuePointer(_RawLogicalExpressionVariable):
47
- type: Literal["CONSTANT_VALUE"] = "CONSTANT_VALUE"
48
- variable_value: VellumValue
49
-
50
-
51
- class _RawMockWorkflowNodeExecutionNodeExecutionCounterPointer(_RawLogicalExpressionVariable):
52
- type: Literal["EXECUTION_COUNTER"] = "EXECUTION_COUNTER"
53
- node_id: UUID
54
-
55
-
56
- class _RawMockWorkflowNodeExecutionInputVariablePointer(_RawLogicalExpressionVariable):
57
- type: Literal["INPUT_VARIABLE"] = "INPUT_VARIABLE"
58
- input_variable_id: UUID
59
-
60
-
61
- class _RawMockWorkflowNodeExecutionNodeOutputPointer(_RawLogicalExpressionVariable):
62
- type: Literal["NODE_OUTPUT"] = "NODE_OUTPUT"
63
- node_id: UUID
64
- input_id: UUID
65
-
66
-
67
- class _RawMockWorkflowNodeExecutionNodeInputPointer(_RawLogicalExpressionVariable):
68
- type: Literal["NODE_INPUT"] = "NODE_INPUT"
69
- node_id: UUID
70
- input_id: UUID
71
-
72
-
73
- _RawMockWorkflowNodeExecutionValuePointer = Union[
74
- _RawMockWorkflowNodeExecutionConstantValuePointer,
75
- _RawMockWorkflowNodeExecutionNodeExecutionCounterPointer,
76
- _RawMockWorkflowNodeExecutionInputVariablePointer,
77
- _RawMockWorkflowNodeExecutionNodeOutputPointer,
78
- _RawMockWorkflowNodeExecutionNodeInputPointer,
79
- ]
80
-
81
-
82
- class _RawMockWorkflowNodeWhenCondition(UniversalBaseModel):
83
- expression: _RawLogicalExpression
84
- variables: List[_RawMockWorkflowNodeExecutionValuePointer]
85
-
86
-
87
- class _RawMockWorkflowNodeThenOutput(UniversalBaseModel):
88
- output_id: UUID
89
- value: _RawMockWorkflowNodeExecutionValuePointer
90
-
91
-
92
- class _RawMockWorkflowNodeExecution(UniversalBaseModel):
93
- when_condition: _RawMockWorkflowNodeWhenCondition
94
- then_outputs: List[_RawMockWorkflowNodeThenOutput]
95
-
96
-
97
- class _RawMockWorkflowNodeConfig(UniversalBaseModel):
98
- type: Literal["WORKFLOW_NODE_OUTPUT"] = "WORKFLOW_NODE_OUTPUT"
99
- node_id: UUID
100
- mock_executions: List[_RawMockWorkflowNodeExecution]
101
-
102
-
103
22
  class MockNodeExecution(UniversalBaseModel):
104
23
  when_condition: BaseDescriptor
105
24
  then_outputs: BaseOutputs
25
+ disabled: Optional[bool] = None
106
26
 
107
27
  model_config = ConfigDict(arbitrary_types_allowed=True)
108
28
 
@@ -110,7 +30,12 @@ class MockNodeExecution(UniversalBaseModel):
110
30
  def serialize_full_model(self, handler: Callable[[Any], Any], info: SerializationInfo) -> Dict[str, Any]:
111
31
  """Serialize the model and add node_id field computed from then_outputs."""
112
32
  serialized = handler(self)
113
- serialized["node_id"] = str(self.then_outputs.__class__.__parent_class__.__id__)
33
+ node_class = self.then_outputs.__class__.__parent_class__
34
+ unadorned_node = get_unadorned_node(node_class) # type: ignore[arg-type]
35
+ serialized["node_id"] = str(unadorned_node.__id__)
36
+ serialized["type"] = "NODE_EXECUTION"
37
+ if self.disabled is None:
38
+ del serialized["disabled"]
114
39
  return serialized
115
40
 
116
41
  @field_serializer("then_outputs")
@@ -129,145 +54,54 @@ class MockNodeExecution(UniversalBaseModel):
129
54
  def validate_all(
130
55
  raw_mock_workflow_node_configs: Optional[List[Any]],
131
56
  workflow: Type["BaseWorkflow"],
57
+ descriptor_validator: Optional[Callable[[dict, Type["BaseWorkflow"]], BaseDescriptor]] = None,
132
58
  ) -> Optional[List["MockNodeExecution"]]:
133
59
  if not raw_mock_workflow_node_configs:
134
60
  return None
135
61
 
136
62
  ArrayVellumValue.model_rebuild()
137
- try:
138
- mock_workflow_node_configs = [
139
- _RawMockWorkflowNodeConfig.model_validate(raw_mock_workflow_node_config)
140
- for raw_mock_workflow_node_config in raw_mock_workflow_node_configs
141
- ]
142
- except ValidationError as e:
143
- raise WorkflowInitializationException(
144
- message="Failed to validate mock node executions",
145
- code=WorkflowErrorCode.INVALID_INPUTS,
146
- workflow_definition=workflow,
147
- ) from e
148
-
149
- nodes = {node.__id__: node for node in workflow.get_nodes()}
150
- node_output_name_by_id = {
151
- node.__output_ids__[output.name]: output.name for node in workflow.get_nodes() for output in node.Outputs
152
- }
153
-
154
- # We need to support the old way that the Vellum App's WorkflowRunner used to define Node Mocks in order to
155
- # avoid needing to update the mock resolution strategy that it and the frontend uses. The path towards
156
- # cleaning this up will go as follows:
157
- # 1. ✅ Release Mock support in SDK-Enabled Workflows
158
- # 2. ✅ Deprecate Mock support in non-SDK enabled Workflows, encouraging users to migrate to SDK Workflows
159
- # 3. ✅ Remove the old mock resolution strategy
160
- # 4. Update this SDK to handle the new mock resolution strategy with WorkflowValueDescriptors
161
- # 5. Cutover the Vellum App to the new mock resolution strategy
162
- # 6. Remove the old mock resolution strategy from this SDK
163
- def _translate_raw_logical_expression(
164
- raw_logical_expression: _RawLogicalExpression,
165
- raw_variables: List[_RawMockWorkflowNodeExecutionValuePointer],
166
- ) -> BaseDescriptor:
167
- if raw_logical_expression.type == "LOGICAL_CONDITION":
168
- return _translate_raw_logical_condition(raw_logical_expression, raw_variables)
169
- else:
170
- return _translate_raw_logical_condition_group(raw_logical_expression, raw_variables)
171
-
172
- def _translate_raw_logical_condition_group(
173
- raw_logical_condition_group: _RawLogicalConditionGroup,
174
- raw_variables: List[_RawMockWorkflowNodeExecutionValuePointer],
175
- ) -> BaseDescriptor:
176
- if not raw_logical_condition_group.conditions:
177
- return ConstantValueReference(True)
178
-
179
- conditions = [
180
- _translate_raw_logical_expression(condition, raw_variables)
181
- for condition in raw_logical_condition_group.conditions
182
- ]
183
- return reduce(
184
- lambda acc, condition: (
185
- acc and condition if raw_logical_condition_group.combinator == "AND" else acc or condition
186
- ),
187
- conditions,
188
- )
189
-
190
- def _translate_raw_logical_condition(
191
- raw_logical_condition: _RawLogicalCondition,
192
- raw_variables: List[_RawMockWorkflowNodeExecutionValuePointer],
193
- ) -> BaseDescriptor:
194
- variable_by_id = {v.id: v for v in raw_variables}
195
- lhs = _translate_raw_logical_expression_variable(variable_by_id[raw_logical_condition.lhs_variable_id])
196
- rhs = _translate_raw_logical_expression_variable(variable_by_id[raw_logical_condition.rhs_variable_id])
197
- if raw_logical_condition.operator == ">":
198
- return lhs.greater_than(rhs)
199
- elif raw_logical_condition.operator == ">=":
200
- return lhs.greater_than_or_equal_to(rhs)
201
- elif raw_logical_condition.operator == "<":
202
- return lhs.less_than(rhs)
203
- elif raw_logical_condition.operator == "<=":
204
- return lhs.less_than_or_equal_to(rhs)
205
- elif raw_logical_condition.operator == "==":
206
- return lhs.equals(rhs)
207
- elif raw_logical_condition.operator == "!=":
208
- return lhs.does_not_equal(rhs)
209
- else:
210
- raise WorkflowInitializationException(
211
- message=f"Unsupported logical operator: {raw_logical_condition.operator}",
212
- workflow_definition=workflow,
213
- )
214
-
215
- def _translate_raw_logical_expression_variable(
216
- raw_variable: _RawMockWorkflowNodeExecutionValuePointer,
217
- ) -> BaseDescriptor:
218
- if raw_variable.type == "CONSTANT_VALUE":
219
- return ConstantValueReference(raw_variable.variable_value.value)
220
- elif raw_variable.type == "EXECUTION_COUNTER":
221
- node = nodes[raw_variable.node_id]
222
- return node.Execution.count
223
- else:
63
+ mock_node_executions: list[MockNodeExecution] = []
64
+ for raw_mock_workflow_node_config in raw_mock_workflow_node_configs:
65
+ if not isinstance(raw_mock_workflow_node_config, dict):
224
66
  raise WorkflowInitializationException(
225
- message=f"Unsupported logical expression type: {raw_variable.type}",
67
+ message=f"Invalid mock node execution type: {type(raw_mock_workflow_node_config)}",
68
+ code=WorkflowErrorCode.INVALID_INPUTS,
226
69
  workflow_definition=workflow,
227
70
  )
228
71
 
229
- mock_node_executions = []
230
- for mock_workflow_node_config in mock_workflow_node_configs:
231
- for mock_execution in mock_workflow_node_config.mock_executions:
232
- try:
233
- when_condition = _translate_raw_logical_expression(
234
- mock_execution.when_condition.expression,
235
- mock_execution.when_condition.variables,
72
+ try:
73
+ mock_node_executions.append(
74
+ MockNodeExecution.model_validate(
75
+ raw_mock_workflow_node_config,
76
+ context={
77
+ "workflow": workflow,
78
+ "node_id": raw_mock_workflow_node_config.get("node_id"),
79
+ "descriptor_validator": lambda value: (
80
+ descriptor_validator(value, workflow)
81
+ if descriptor_validator
82
+ else ConstantValueReference(False)
83
+ ),
84
+ },
236
85
  )
237
-
238
- then_outputs = nodes[mock_workflow_node_config.node_id].Outputs()
239
- for then_output in mock_execution.then_outputs:
240
- node_output_name = node_output_name_by_id.get(then_output.output_id)
241
- if node_output_name is None:
242
- node_id = mock_workflow_node_config.node_id
243
- raise WorkflowInitializationException(
244
- message=f"Output {then_output.output_id} not found in node {node_id}",
245
- workflow_definition=workflow,
246
- )
247
-
248
- resolved_output_reference = _translate_raw_logical_expression_variable(then_output.value)
249
- if isinstance(resolved_output_reference, ConstantValueReference):
250
- setattr(
251
- then_outputs,
252
- node_output_name,
253
- resolved_output_reference._value,
254
- )
255
- else:
256
- ref_type = type(resolved_output_reference)
257
- raise WorkflowInitializationException(
258
- message=f"Unsupported resolved output reference type: {ref_type}",
259
- workflow_definition=workflow,
260
- )
261
-
262
- mock_node_executions.append(
263
- MockNodeExecution(
264
- when_condition=when_condition,
265
- then_outputs=then_outputs,
266
- )
86
+ )
87
+ except WorkflowInitializationException as e:
88
+ # If the node is not found in the workflow, skip it with a warning
89
+ node_id = raw_mock_workflow_node_config.get("node_id")
90
+ raw_data = e.raw_data or {}
91
+ if raw_data.get("node_ref") == node_id:
92
+ logger.warning(
93
+ "Skipping mock for node %s: node not found in workflow %s",
94
+ node_id,
95
+ workflow.__name__,
267
96
  )
268
- except Exception as e:
269
- logger.exception("Failed to validate mock node execution", exc_info=e)
270
97
  continue
98
+ raise
99
+ except (ValidationError, NodeException) as e:
100
+ raise WorkflowInitializationException(
101
+ message="Failed to validate mock node executions",
102
+ code=WorkflowErrorCode.INVALID_INPUTS,
103
+ workflow_definition=workflow,
104
+ ) from e
271
105
 
272
106
  return mock_node_executions
273
107
 
@@ -1,98 +1,6 @@
1
- import uuid
2
-
3
- from vellum.client.types.string_vellum_value import StringVellumValue
4
1
  from vellum.workflows import BaseWorkflow
5
- from vellum.workflows.nodes import InlinePromptNode
6
2
  from vellum.workflows.nodes.bases.base import BaseNode
7
3
  from vellum.workflows.nodes.mocks import MockNodeExecution
8
- from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
9
- from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
10
-
11
-
12
- def test_mocks__parse_from_app():
13
- # GIVEN a PromptNode
14
- class PromptNode(InlinePromptNode):
15
- pass
16
-
17
- # AND a workflow class with that PromptNode
18
- class MyWorkflow(BaseWorkflow):
19
- graph = PromptNode
20
-
21
- # AND a mock workflow node execution from the app
22
- raw_mock_workflow_node_execution = [
23
- {
24
- "type": "WORKFLOW_NODE_OUTPUT",
25
- "node_id": str(PromptNode.__id__),
26
- "mock_executions": [
27
- {
28
- "when_condition": {
29
- "expression": {
30
- "type": "LOGICAL_CONDITION_GROUP",
31
- "combinator": "AND",
32
- "negated": False,
33
- "conditions": [
34
- {
35
- "type": "LOGICAL_CONDITION",
36
- "lhs_variable_id": "e60902d5-6892-4916-80c1-f0130af52322",
37
- "operator": ">=",
38
- "rhs_variable_id": "5c1bbb24-c288-49cb-a9b7-0c6f38a86037",
39
- }
40
- ],
41
- },
42
- "variables": [
43
- {
44
- "type": "EXECUTION_COUNTER",
45
- "node_id": str(PromptNode.__id__),
46
- "id": "e60902d5-6892-4916-80c1-f0130af52322",
47
- },
48
- {
49
- "type": "CONSTANT_VALUE",
50
- "variable_value": {"type": "NUMBER", "value": 0},
51
- "id": "5c1bbb24-c288-49cb-a9b7-0c6f38a86037",
52
- },
53
- ],
54
- },
55
- "then_outputs": [
56
- {
57
- "output_id": "bbd955e8-b939-45f9-8617-f1405dddd2b3",
58
- "value": {
59
- "id": "27006b2a-fa81-430c-a0b2-c66a9351fc68",
60
- "type": "CONSTANT_VALUE",
61
- "variable_value": {"type": "STRING", "value": "Hello"},
62
- },
63
- },
64
- {
65
- "output_id": "e50bf6e9-417b-4c04-babb-94e7dccb9f2c",
66
- "value": {
67
- "id": "4559c778-6e27-4cfe-a460-734ba62a5082",
68
- "type": "CONSTANT_VALUE",
69
- "variable_value": {"type": "ARRAY", "value": [{"type": "STRING", "value": "Hello"}]},
70
- },
71
- },
72
- ],
73
- }
74
- ],
75
- }
76
- ]
77
-
78
- # WHEN we parse the mock workflow node execution
79
- node_output_mocks = MockNodeExecution.validate_all(
80
- raw_mock_workflow_node_execution,
81
- MyWorkflow,
82
- )
83
-
84
- # THEN we get a list of MockNodeExecution objects
85
- assert node_output_mocks
86
- assert len(node_output_mocks) == 1
87
- assert node_output_mocks[0] == MockNodeExecution(
88
- when_condition=PromptNode.Execution.count.greater_than_or_equal_to(0.0),
89
- then_outputs=PromptNode.Outputs(
90
- text="Hello",
91
- results=[
92
- StringVellumValue(value="Hello"),
93
- ],
94
- ),
95
- )
96
4
 
97
5
 
98
6
  def test_mocks__parse_none_still_runs():
@@ -120,88 +28,3 @@ def test_mocks__parse_none_still_runs():
120
28
 
121
29
  # THEN it was successful
122
30
  assert final_event.name == "workflow.execution.fulfilled"
123
-
124
-
125
- def test_mocks__use_id_from_display():
126
- # GIVEN a Base Node
127
- class StartNode(BaseNode):
128
- class Outputs(BaseNode.Outputs):
129
- foo: str
130
-
131
- # AND a workflow class with that Node
132
- class MyWorkflow(BaseWorkflow):
133
- graph = StartNode
134
-
135
- class Outputs(BaseWorkflow.Outputs):
136
- final_value = StartNode.Outputs.foo
137
-
138
- # AND a display class on that Base Node
139
- node_output_id = uuid.uuid4()
140
-
141
- class StartNodeDisplay(BaseNodeDisplay[StartNode]):
142
- output_display = {StartNode.Outputs.foo: NodeOutputDisplay(id=node_output_id, name="foo")}
143
-
144
- # AND a mock workflow node execution from the app
145
- raw_mock_workflow_node_execution = [
146
- {
147
- "type": "WORKFLOW_NODE_OUTPUT",
148
- "node_id": str(StartNode.__id__),
149
- "mock_executions": [
150
- {
151
- "when_condition": {
152
- "expression": {
153
- "type": "LOGICAL_CONDITION_GROUP",
154
- "combinator": "AND",
155
- "negated": False,
156
- "conditions": [
157
- {
158
- "type": "LOGICAL_CONDITION",
159
- "lhs_variable_id": "e60902d5-6892-4916-80c1-f0130af52322",
160
- "operator": ">=",
161
- "rhs_variable_id": "5c1bbb24-c288-49cb-a9b7-0c6f38a86037",
162
- }
163
- ],
164
- },
165
- "variables": [
166
- {
167
- "type": "EXECUTION_COUNTER",
168
- "node_id": str(StartNode.__id__),
169
- "id": "e60902d5-6892-4916-80c1-f0130af52322",
170
- },
171
- {
172
- "type": "CONSTANT_VALUE",
173
- "variable_value": {"type": "NUMBER", "value": 0},
174
- "id": "5c1bbb24-c288-49cb-a9b7-0c6f38a86037",
175
- },
176
- ],
177
- },
178
- "then_outputs": [
179
- {
180
- "output_id": str(node_output_id),
181
- "value": {
182
- "id": "27006b2a-fa81-430c-a0b2-c66a9351fc68",
183
- "type": "CONSTANT_VALUE",
184
- "variable_value": {"type": "STRING", "value": "Hello"},
185
- },
186
- },
187
- ],
188
- }
189
- ],
190
- }
191
- ]
192
-
193
- # WHEN we parsed the raw data on `MockNodeExecution`
194
- node_output_mocks = MockNodeExecution.validate_all(
195
- raw_mock_workflow_node_execution,
196
- MyWorkflow,
197
- )
198
-
199
- # THEN we get the expected list of MockNodeExecution objects
200
- assert node_output_mocks
201
- assert len(node_output_mocks) == 1
202
- assert node_output_mocks[0] == MockNodeExecution(
203
- when_condition=StartNode.Execution.count.greater_than_or_equal_to(0.0),
204
- then_outputs=StartNode.Outputs(
205
- foo="Hello",
206
- ),
207
- )
@@ -3,7 +3,20 @@ import inspect
3
3
  import json
4
4
  import sys
5
5
  from types import ModuleType
6
- from typing import Any, Callable, Dict, ForwardRef, List, Optional, Type, TypeVar, Union, get_args, get_origin
6
+ from typing import (
7
+ TYPE_CHECKING,
8
+ Any,
9
+ Callable,
10
+ Dict,
11
+ ForwardRef,
12
+ List,
13
+ Optional,
14
+ Type,
15
+ TypeVar,
16
+ Union,
17
+ get_args,
18
+ get_origin,
19
+ )
7
20
 
8
21
  from pydantic import BaseModel, create_model
9
22
 
@@ -12,8 +25,6 @@ from vellum.workflows.constants import undefined
12
25
  from vellum.workflows.errors.types import WorkflowErrorCode
13
26
  from vellum.workflows.exceptions import NodeException
14
27
  from vellum.workflows.inputs.base import BaseInputs
15
- from vellum.workflows.nodes import BaseNode
16
- from vellum.workflows.nodes.bases.base_adornment_node import BaseAdornmentNode
17
28
  from vellum.workflows.ports.port import Port
18
29
  from vellum.workflows.state.base import BaseState
19
30
  from vellum.workflows.types.code_execution_node_wrappers import (
@@ -23,13 +34,16 @@ from vellum.workflows.types.code_execution_node_wrappers import (
23
34
  clean_for_dict_wrapper,
24
35
  )
25
36
  from vellum.workflows.types.core import Json
26
- from vellum.workflows.types.generics import NodeType
37
+ from vellum.workflows.types.generics import NodeType, import_base_adornment_node
38
+
39
+ if TYPE_CHECKING:
40
+ from vellum.workflows.nodes import BaseNode
27
41
 
28
42
  ADORNMENT_MODULE_NAME = "<adornment>"
29
43
 
30
44
 
31
45
  @cache
32
- def get_unadorned_node(node: Type[BaseNode]) -> Type[BaseNode]:
46
+ def get_unadorned_node(node: Type["BaseNode"]) -> Type["BaseNode"]:
33
47
  wrapped_node = get_wrapped_node(node)
34
48
  if wrapped_node is not None:
35
49
  return get_unadorned_node(wrapped_node)
@@ -46,20 +60,21 @@ def get_unadorned_port(port: Port) -> Port:
46
60
  return getattr(unadorned_node.Ports, port.name)
47
61
 
48
62
 
49
- def get_wrapped_node(node: Type[NodeType]) -> Optional[Type[BaseNode]]:
63
+ def get_wrapped_node(node: Type[NodeType]) -> Optional[Type["BaseNode"]]:
64
+ BaseAdornmentNode = import_base_adornment_node()
50
65
  if not issubclass(node, BaseAdornmentNode):
51
66
  return None
52
67
 
53
68
  return node.__wrapped_node__
54
69
 
55
70
 
56
- AdornableNode = TypeVar("AdornableNode", bound=BaseNode)
71
+ AdornableNode = TypeVar("AdornableNode", bound="BaseNode")
57
72
 
58
73
 
59
74
  def create_adornment(
60
75
  adornable_cls: Type[AdornableNode], attributes: Optional[dict[str, Any]] = None
61
76
  ) -> Callable[..., Type["AdornableNode"]]:
62
- def decorator(inner_cls: Type[BaseNode]) -> Type["AdornableNode"]:
77
+ def decorator(inner_cls: Type["BaseNode"]) -> Type["AdornableNode"]:
63
78
  # Investigate how to use dependency injection to avoid circular imports
64
79
  # https://app.shortcut.com/vellum/story/4116
65
80
  from vellum.workflows import BaseWorkflow
@@ -3,7 +3,7 @@ import inspect
3
3
  from typing import Any, Dict, Generic, Iterator, Set, Tuple, Type, TypeVar, Union, cast
4
4
  from typing_extensions import dataclass_transform
5
5
 
6
- from pydantic import GetCoreSchemaHandler
6
+ from pydantic import GetCoreSchemaHandler, ValidationInfo
7
7
  from pydantic_core import core_schema
8
8
 
9
9
  from vellum.workflows.constants import undefined
@@ -12,7 +12,7 @@ from vellum.workflows.errors.types import WorkflowErrorCode
12
12
  from vellum.workflows.exceptions import NodeException
13
13
  from vellum.workflows.executable import BaseExecutable
14
14
  from vellum.workflows.references.output import OutputReference
15
- from vellum.workflows.types.generics import is_node_instance
15
+ from vellum.workflows.types.generics import import_workflow_class, is_node_instance
16
16
  from vellum.workflows.types.utils import get_class_attr_names, infer_types
17
17
 
18
18
  _Delta = TypeVar("_Delta")
@@ -268,4 +268,37 @@ class BaseOutputs(metaclass=_BaseOutputsMeta):
268
268
  def __get_pydantic_core_schema__(
269
269
  cls, source_type: Type[Any], handler: GetCoreSchemaHandler
270
270
  ) -> core_schema.CoreSchema:
271
- return core_schema.is_instance_schema(cls)
271
+ def validate(value: Any, info: ValidationInfo) -> Any:
272
+ if isinstance(value, cls):
273
+ return value
274
+
275
+ if not isinstance(value, dict):
276
+ raise TypeError(f"Value must be an instance of {cls.__name__} or a dict")
277
+
278
+ context = info.context
279
+ if not isinstance(context, dict):
280
+ raise TypeError(f"Unexpected type for context: {type(context)}")
281
+
282
+ workflow = context.get("workflow")
283
+ node_id = context.get("node_id")
284
+ base_workflow_class = import_workflow_class()
285
+ if (
286
+ not workflow
287
+ or not node_id
288
+ or not isinstance(node_id, str)
289
+ or not isinstance(workflow, type)
290
+ or not issubclass(workflow, base_workflow_class)
291
+ ):
292
+ return cls(**value)
293
+
294
+ node_class = workflow.resolve_node_ref(node_id)
295
+ declared_fields = {descriptor.name for descriptor in node_class.Outputs}
296
+ filtered_value = {k: v for k, v in value.items() if k in declared_fields}
297
+ return node_class.Outputs(**filtered_value)
298
+
299
+ return core_schema.union_schema(
300
+ [
301
+ core_schema.is_instance_schema(cls),
302
+ core_schema.with_info_after_validator_function(validate, core_schema.dict_schema()),
303
+ ]
304
+ )
@@ -13,12 +13,10 @@ class EnvironmentVariableReference(BaseDescriptor[str]):
13
13
  self,
14
14
  *,
15
15
  name: str,
16
- # DEPRECATED - to be removed in 0.15.0 release
16
+ # DEPRECATED - to be removed in 2.0 release
17
17
  default: Optional[str] = None,
18
- serialize_as_constant: bool = False,
19
18
  ):
20
19
  super().__init__(name=name, types=(str,), is_sensitive=True)
21
- self._serialize_as_constant = serialize_as_constant
22
20
 
23
21
  def resolve(self, state: "BaseState") -> Any:
24
22
  env_value = os.environ.get(self.name)
@@ -32,11 +30,3 @@ class EnvironmentVariableReference(BaseDescriptor[str]):
32
30
  "type": "ENVIRONMENT_VARIABLE",
33
31
  "environment_variable": self.name,
34
32
  }
35
-
36
- @property
37
- def serialize_as_constant(self) -> bool:
38
- return self._serialize_as_constant
39
-
40
- @serialize_as_constant.setter
41
- def serialize_as_constant(self, value: bool):
42
- self._serialize_as_constant = value
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Callable, Generic, TypeVar, Union, get_args
5
5
 
6
6
  from vellum.workflows.constants import undefined
7
7
  from vellum.workflows.descriptors.base import BaseDescriptor
8
+ from vellum.workflows.types.generics import is_workflow_class
8
9
 
9
10
  if TYPE_CHECKING:
10
11
  from vellum.workflows.state.base import BaseState
@@ -36,6 +37,13 @@ class LazyReference(BaseDescriptor[_T], Generic[_T]):
36
37
  if str(output_reference) == self._get:
37
38
  return value
38
39
 
40
+ # Check workflow outputs
41
+ workflow_definition = state.meta.workflow_definition
42
+ if is_workflow_class(workflow_definition):
43
+ for output_reference in workflow_definition.Outputs:
44
+ if str(output_reference) == self._get:
45
+ return resolve_value(output_reference.instance, state) # type: ignore[return-value]
46
+
39
47
  child_reference = self.resolve(state.meta.parent) if state.meta.parent else None
40
48
 
41
49
  # Fix typing surrounding the return value of node outputs/output descriptors