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.
- vellum/__init__.py +287 -4
- vellum/client/README.md +69 -16
- vellum/client/__init__.py +598 -1437
- vellum/client/core/__init__.py +5 -0
- vellum/client/core/api_error.py +13 -5
- vellum/client/core/client_wrapper.py +30 -4
- vellum/client/core/force_multipart.py +18 -0
- vellum/client/core/http_client.py +70 -26
- vellum/client/core/http_response.py +55 -0
- vellum/client/core/jsonable_encoder.py +0 -1
- vellum/client/core/pydantic_utilities.py +90 -117
- vellum/client/core/serialization.py +7 -3
- vellum/client/errors/__init__.py +14 -1
- vellum/client/errors/bad_request_error.py +4 -3
- vellum/client/errors/forbidden_error.py +4 -3
- vellum/client/errors/internal_server_error.py +4 -3
- vellum/client/errors/misdirected_request_error.py +11 -0
- vellum/client/errors/not_found_error.py +4 -3
- vellum/client/errors/too_many_requests_error.py +10 -0
- vellum/client/errors/unauthorized_error.py +11 -0
- vellum/client/raw_client.py +2725 -0
- vellum/client/reference.md +3160 -1217
- vellum/client/resources/__init__.py +16 -2
- vellum/client/resources/ad_hoc/__init__.py +2 -0
- vellum/client/resources/ad_hoc/client.py +173 -377
- vellum/client/resources/ad_hoc/raw_client.py +569 -0
- vellum/client/resources/container_images/__init__.py +2 -0
- vellum/client/resources/container_images/client.py +365 -185
- vellum/client/resources/container_images/raw_client.py +693 -0
- vellum/client/resources/deployments/__init__.py +2 -0
- vellum/client/resources/deployments/client.py +119 -463
- vellum/client/resources/deployments/raw_client.py +1002 -0
- vellum/client/resources/deployments/types/__init__.py +2 -0
- vellum/client/resources/document_indexes/__init__.py +2 -0
- vellum/client/resources/document_indexes/client.py +131 -383
- vellum/client/resources/document_indexes/raw_client.py +866 -0
- vellum/client/resources/document_indexes/types/__init__.py +2 -0
- vellum/client/resources/documents/__init__.py +2 -0
- vellum/client/resources/documents/client.py +111 -333
- vellum/client/resources/documents/raw_client.py +672 -0
- vellum/client/resources/{release_reviews → environments}/__init__.py +2 -0
- vellum/client/resources/environments/client.py +106 -0
- vellum/client/resources/environments/raw_client.py +95 -0
- vellum/client/resources/events/__init__.py +4 -0
- vellum/client/resources/events/client.py +201 -0
- vellum/client/resources/events/raw_client.py +211 -0
- vellum/client/resources/folder_entities/__init__.py +2 -0
- vellum/client/resources/folder_entities/client.py +56 -95
- vellum/client/resources/folder_entities/raw_client.py +276 -0
- vellum/client/resources/folder_entities/types/__init__.py +2 -0
- vellum/client/resources/integration_auth_configs/__init__.py +4 -0
- vellum/client/resources/integration_auth_configs/client.py +188 -0
- vellum/client/resources/integration_auth_configs/raw_client.py +173 -0
- vellum/client/resources/integration_providers/__init__.py +4 -0
- vellum/client/resources/integration_providers/client.py +325 -0
- vellum/client/resources/integration_providers/raw_client.py +299 -0
- vellum/client/resources/integrations/__init__.py +4 -0
- vellum/client/resources/integrations/client.py +514 -0
- vellum/client/resources/integrations/raw_client.py +618 -0
- vellum/client/resources/metric_definitions/__init__.py +2 -0
- vellum/client/resources/metric_definitions/client.py +60 -106
- vellum/client/resources/metric_definitions/raw_client.py +224 -0
- vellum/client/resources/ml_models/__init__.py +2 -0
- vellum/client/resources/ml_models/client.py +37 -46
- vellum/client/resources/ml_models/raw_client.py +102 -0
- vellum/client/resources/organizations/__init__.py +2 -0
- vellum/client/resources/organizations/client.py +37 -45
- vellum/client/resources/organizations/raw_client.py +95 -0
- vellum/client/resources/prompts/__init__.py +2 -0
- vellum/client/resources/prompts/client.py +84 -202
- vellum/client/resources/prompts/raw_client.py +353 -0
- vellum/client/resources/sandboxes/__init__.py +2 -0
- vellum/client/resources/sandboxes/client.py +69 -159
- vellum/client/resources/sandboxes/raw_client.py +392 -0
- vellum/client/resources/test_suite_runs/__init__.py +2 -0
- vellum/client/resources/test_suite_runs/client.py +65 -157
- vellum/client/resources/test_suite_runs/raw_client.py +354 -0
- vellum/client/resources/test_suites/__init__.py +2 -0
- vellum/client/resources/test_suites/client.py +162 -266
- vellum/client/resources/test_suites/raw_client.py +530 -0
- vellum/client/resources/uploaded_files/__init__.py +4 -0
- vellum/client/resources/uploaded_files/client.py +230 -0
- vellum/client/resources/uploaded_files/raw_client.py +316 -0
- vellum/client/resources/workflow_deployments/__init__.py +2 -0
- vellum/client/resources/workflow_deployments/client.py +456 -351
- vellum/client/resources/workflow_deployments/raw_client.py +1393 -0
- vellum/client/resources/workflow_deployments/types/__init__.py +2 -0
- vellum/client/resources/workflow_executions/__init__.py +4 -0
- vellum/client/resources/workflow_executions/client.py +140 -0
- vellum/client/resources/workflow_executions/raw_client.py +173 -0
- vellum/client/resources/workflow_sandboxes/__init__.py +2 -0
- vellum/client/resources/workflow_sandboxes/client.py +58 -123
- vellum/client/resources/workflow_sandboxes/raw_client.py +291 -0
- vellum/client/resources/workflow_sandboxes/types/__init__.py +2 -0
- vellum/client/resources/workflows/__init__.py +2 -0
- vellum/client/resources/workflows/client.py +464 -145
- vellum/client/resources/workflows/raw_client.py +884 -0
- vellum/client/resources/workspace_secrets/__init__.py +2 -0
- vellum/client/resources/workspace_secrets/client.py +43 -100
- vellum/client/resources/workspace_secrets/raw_client.py +219 -0
- vellum/client/resources/workspaces/__init__.py +2 -0
- vellum/client/resources/workspaces/client.py +37 -45
- vellum/client/resources/workspaces/raw_client.py +95 -0
- vellum/client/tests/__init__.py +0 -0
- vellum/client/tests/test_utils.py +34 -0
- vellum/client/types/__init__.py +260 -0
- vellum/client/types/ad_hoc_execute_prompt_event.py +3 -2
- vellum/client/types/ad_hoc_expand_meta.py +2 -2
- vellum/client/types/ad_hoc_fulfilled_prompt_execution_meta.py +3 -3
- vellum/client/types/ad_hoc_initiated_prompt_execution_meta.py +2 -2
- vellum/client/types/ad_hoc_rejected_prompt_execution_meta.py +3 -3
- vellum/client/types/ad_hoc_streaming_prompt_execution_meta.py +2 -2
- vellum/client/types/api_actor_type_enum.py +7 -0
- vellum/client/types/api_node_result.py +3 -3
- vellum/client/types/api_node_result_data.py +4 -4
- vellum/client/types/api_request_parent_context.py +17 -10
- vellum/client/types/api_version_enum.py +1 -1
- vellum/client/types/array_chat_message_content.py +3 -3
- vellum/client/types/array_chat_message_content_item.py +7 -4
- vellum/client/types/array_chat_message_content_item_request.py +7 -4
- vellum/client/types/array_chat_message_content_request.py +3 -3
- vellum/client/types/array_input.py +12 -6
- vellum/client/types/array_vellum_value.py +4 -4
- vellum/client/types/array_vellum_value_request.py +4 -4
- vellum/client/types/audio_chat_message_content.py +3 -3
- vellum/client/types/audio_chat_message_content_request.py +3 -3
- vellum/client/types/audio_input.py +30 -0
- vellum/client/types/audio_input_request.py +30 -0
- vellum/client/types/audio_prompt_block.py +4 -4
- vellum/client/types/audio_vellum_value.py +3 -3
- vellum/client/types/audio_vellum_value_request.py +3 -3
- vellum/client/types/auth_type_enum.py +5 -0
- vellum/client/types/base_output.py +4 -4
- vellum/client/types/basic_vectorizer_intfloat_multilingual_e_5_large.py +2 -2
- vellum/client/types/basic_vectorizer_intfloat_multilingual_e_5_large_request.py +2 -2
- vellum/client/types/basic_vectorizer_sentence_transformers_multi_qa_mpnet_base_cos_v_1.py +2 -2
- vellum/client/types/basic_vectorizer_sentence_transformers_multi_qa_mpnet_base_cos_v_1_request.py +2 -2
- vellum/client/types/basic_vectorizer_sentence_transformers_multi_qa_mpnet_base_dot_v_1.py +2 -2
- vellum/client/types/basic_vectorizer_sentence_transformers_multi_qa_mpnet_base_dot_v_1_request.py +2 -2
- vellum/client/types/build_status_enum.py +5 -0
- vellum/client/types/chat_history_input.py +3 -3
- vellum/client/types/chat_history_input_request.py +3 -3
- vellum/client/types/chat_history_vellum_value.py +3 -3
- vellum/client/types/chat_history_vellum_value_request.py +3 -3
- vellum/client/types/chat_message.py +4 -4
- vellum/client/types/chat_message_content.py +7 -4
- vellum/client/types/chat_message_content_request.py +7 -4
- vellum/client/types/chat_message_prompt_block.py +7 -7
- vellum/client/types/chat_message_request.py +4 -4
- vellum/client/types/check_workflow_execution_status_error.py +21 -0
- vellum/client/types/check_workflow_execution_status_response.py +29 -0
- vellum/client/types/code_execution_node_array_result.py +11 -5
- vellum/client/types/code_execution_node_chat_history_result.py +3 -3
- vellum/client/types/code_execution_node_error_result.py +3 -3
- vellum/client/types/code_execution_node_function_call_result.py +3 -3
- vellum/client/types/code_execution_node_json_result.py +2 -2
- vellum/client/types/code_execution_node_number_result.py +2 -2
- vellum/client/types/code_execution_node_result.py +10 -4
- vellum/client/types/code_execution_node_result_data.py +10 -4
- vellum/client/types/code_execution_node_result_output.py +6 -5
- vellum/client/types/code_execution_node_search_results_result.py +3 -3
- vellum/client/types/code_execution_node_string_result.py +2 -2
- vellum/client/types/code_execution_package.py +3 -2
- vellum/client/types/code_execution_package_request.py +21 -0
- vellum/client/types/code_executor_input.py +15 -6
- vellum/client/types/code_executor_response.py +11 -5
- vellum/client/types/code_executor_secret_input.py +3 -3
- vellum/client/types/code_resource_definition.py +3 -3
- vellum/client/types/compile_prompt_deployment_expand_meta_request.py +2 -2
- vellum/client/types/compile_prompt_meta.py +2 -2
- vellum/client/types/components_schemas_composio_execute_tool_request.py +5 -0
- vellum/client/types/components_schemas_composio_execute_tool_response.py +5 -0
- vellum/client/types/components_schemas_composio_integration_exec_config.py +5 -0
- vellum/client/types/components_schemas_composio_tool_definition.py +5 -0
- vellum/client/types/components_schemas_slim_composio_tool_definition.py +5 -0
- vellum/client/types/composio_execute_tool_request.py +29 -0
- vellum/client/types/composio_execute_tool_response.py +24 -0
- vellum/client/types/composio_integration_exec_config.py +21 -0
- vellum/client/types/composio_tool_definition.py +31 -0
- vellum/client/types/conditional_node_result.py +3 -3
- vellum/client/types/conditional_node_result_data.py +2 -2
- vellum/client/types/container_image_build_config.py +22 -0
- vellum/client/types/container_image_container_image_tag.py +3 -2
- vellum/client/types/container_image_read.py +8 -4
- vellum/client/types/create_test_suite_test_case_request.py +9 -3
- vellum/client/types/create_workflow_event_request.py +7 -0
- vellum/client/types/dataset_row_push_request.py +23 -0
- vellum/client/types/delimiter_chunker_config.py +20 -0
- vellum/client/types/delimiter_chunker_config_request.py +20 -0
- vellum/client/types/delimiter_chunking.py +21 -0
- vellum/client/types/delimiter_chunking_request.py +21 -0
- vellum/client/types/deployment_history_item.py +10 -4
- vellum/client/types/deployment_provider_payload_response.py +4 -4
- vellum/client/types/deployment_read.py +15 -9
- vellum/client/types/deployment_release_tag_deployment_history_item.py +2 -2
- vellum/client/types/deployment_release_tag_read.py +4 -4
- vellum/client/types/deprecated_prompt_request_input.py +8 -0
- vellum/client/types/docker_service_token.py +2 -2
- vellum/client/types/document_chat_message_content.py +3 -3
- vellum/client/types/document_chat_message_content_request.py +3 -3
- vellum/client/types/document_document_to_document_index.py +5 -4
- vellum/client/types/document_index_chunking.py +5 -1
- vellum/client/types/document_index_chunking_request.py +3 -1
- vellum/client/types/document_index_indexing_config.py +4 -4
- vellum/client/types/document_index_indexing_config_request.py +4 -4
- vellum/client/types/document_index_read.py +4 -4
- vellum/client/types/document_input.py +30 -0
- vellum/client/types/document_input_request.py +30 -0
- vellum/client/types/document_prompt_block.py +4 -4
- vellum/client/types/document_read.py +9 -5
- vellum/client/types/document_vellum_value.py +3 -3
- vellum/client/types/document_vellum_value_request.py +3 -3
- vellum/client/types/enriched_normalized_completion.py +3 -3
- vellum/client/types/environment_display_config.py +19 -0
- vellum/client/types/environment_read.py +23 -0
- vellum/client/types/ephemeral_prompt_cache_config.py +3 -3
- vellum/client/types/error_detail_response.py +22 -0
- vellum/client/types/error_input.py +3 -3
- vellum/client/types/error_vellum_value.py +3 -3
- vellum/client/types/error_vellum_value_request.py +3 -3
- vellum/client/types/event_create_response.py +31 -0
- vellum/client/types/execute_api_request_bearer_token.py +1 -0
- vellum/client/types/execute_api_request_headers_value.py +1 -0
- vellum/client/types/execute_api_response.py +6 -6
- vellum/client/types/execute_prompt_event.py +3 -2
- vellum/client/types/execute_prompt_response.py +1 -0
- vellum/client/types/execute_workflow_async_response.py +26 -0
- vellum/client/types/execute_workflow_response.py +10 -4
- vellum/client/types/execute_workflow_workflow_result_event.py +1 -0
- vellum/client/types/execution_array_vellum_value.py +12 -6
- vellum/client/types/execution_audio_vellum_value.py +31 -0
- vellum/client/types/execution_chat_history_vellum_value.py +3 -3
- vellum/client/types/execution_document_vellum_value.py +31 -0
- vellum/client/types/execution_error_vellum_value.py +3 -3
- vellum/client/types/execution_function_call_vellum_value.py +3 -3
- vellum/client/types/execution_image_vellum_value.py +31 -0
- vellum/client/types/execution_json_vellum_value.py +3 -3
- vellum/client/types/execution_number_vellum_value.py +3 -3
- vellum/client/types/execution_search_results_vellum_value.py +3 -3
- vellum/client/types/execution_string_vellum_value.py +3 -3
- vellum/client/types/execution_thinking_vellum_value.py +31 -0
- vellum/client/types/execution_vellum_value.py +16 -5
- vellum/client/types/execution_video_vellum_value.py +31 -0
- vellum/client/types/external_input_descriptor.py +3 -3
- vellum/client/types/external_parent_context.py +38 -0
- vellum/client/types/external_test_case_execution.py +10 -4
- vellum/client/types/external_test_case_execution_request.py +10 -4
- vellum/client/types/fast_embed_vectorizer_baai_bge_small_en_v_15.py +23 -0
- vellum/client/types/fast_embed_vectorizer_baai_bge_small_en_v_15_request.py +23 -0
- vellum/client/types/folder_entity.py +5 -2
- vellum/client/types/folder_entity_dataset.py +26 -0
- vellum/client/types/folder_entity_dataset_data.py +25 -0
- vellum/client/types/folder_entity_document_index.py +3 -3
- vellum/client/types/folder_entity_document_index_data.py +5 -3
- vellum/client/types/folder_entity_folder.py +3 -3
- vellum/client/types/folder_entity_folder_data.py +2 -2
- vellum/client/types/folder_entity_prompt_sandbox.py +3 -3
- vellum/client/types/folder_entity_prompt_sandbox_data.py +4 -3
- vellum/client/types/folder_entity_test_suite.py +3 -3
- vellum/client/types/folder_entity_test_suite_data.py +3 -3
- vellum/client/types/folder_entity_workflow_sandbox.py +3 -3
- vellum/client/types/folder_entity_workflow_sandbox_data.py +6 -3
- vellum/client/types/fulfilled_ad_hoc_execute_prompt_event.py +4 -4
- vellum/client/types/fulfilled_execute_prompt_event.py +4 -4
- vellum/client/types/fulfilled_execute_prompt_response.py +3 -3
- vellum/client/types/fulfilled_execute_workflow_workflow_result_event.py +11 -5
- vellum/client/types/fulfilled_prompt_execution_meta.py +3 -3
- vellum/client/types/fulfilled_workflow_node_result_event.py +12 -6
- vellum/client/types/function_call.py +2 -2
- vellum/client/types/function_call_chat_message_content.py +3 -3
- vellum/client/types/function_call_chat_message_content_request.py +3 -3
- vellum/client/types/function_call_chat_message_content_value.py +2 -2
- vellum/client/types/function_call_chat_message_content_value_request.py +2 -2
- vellum/client/types/function_call_input.py +3 -3
- vellum/client/types/function_call_prompt_block.py +4 -4
- vellum/client/types/function_call_request.py +2 -2
- vellum/client/types/function_call_vellum_value.py +3 -3
- vellum/client/types/function_call_vellum_value_request.py +3 -3
- vellum/client/types/function_definition.py +9 -4
- vellum/client/types/generate_options_request.py +3 -3
- vellum/client/types/generate_request.py +2 -2
- vellum/client/types/generate_response.py +3 -3
- vellum/client/types/generate_result.py +3 -3
- vellum/client/types/generate_result_data.py +3 -3
- vellum/client/types/generate_result_error.py +3 -3
- vellum/client/types/generate_stream_response.py +3 -3
- vellum/client/types/generate_stream_result.py +4 -4
- vellum/client/types/generate_stream_result_data.py +3 -3
- vellum/client/types/google_vertex_ai_vectorizer_config.py +2 -2
- vellum/client/types/google_vertex_ai_vectorizer_config_request.py +2 -2
- vellum/client/types/google_vertex_ai_vectorizer_gemini_embedding_001.py +21 -0
- vellum/client/types/google_vertex_ai_vectorizer_gemini_embedding_001_request.py +21 -0
- vellum/client/types/google_vertex_ai_vectorizer_text_embedding_004.py +3 -3
- vellum/client/types/google_vertex_ai_vectorizer_text_embedding_004_request.py +3 -3
- vellum/client/types/google_vertex_ai_vectorizer_text_multilingual_embedding_002.py +3 -3
- vellum/client/types/google_vertex_ai_vectorizer_text_multilingual_embedding_002_request.py +3 -3
- vellum/client/types/hkunlp_instructor_xl_vectorizer.py +3 -3
- vellum/client/types/hkunlp_instructor_xl_vectorizer_request.py +3 -3
- vellum/client/types/image_chat_message_content.py +3 -3
- vellum/client/types/image_chat_message_content_request.py +3 -3
- vellum/client/types/image_input.py +30 -0
- vellum/client/types/image_input_request.py +30 -0
- vellum/client/types/image_prompt_block.py +4 -4
- vellum/client/types/image_vellum_value.py +3 -3
- vellum/client/types/image_vellum_value_request.py +3 -3
- vellum/client/types/indexing_config_vectorizer.py +11 -4
- vellum/client/types/indexing_config_vectorizer_request.py +11 -4
- vellum/client/types/initiated_ad_hoc_execute_prompt_event.py +3 -3
- vellum/client/types/initiated_execute_prompt_event.py +3 -3
- vellum/client/types/initiated_prompt_execution_meta.py +2 -2
- vellum/client/types/initiated_workflow_node_result_event.py +12 -6
- vellum/client/types/instructor_vectorizer_config.py +2 -2
- vellum/client/types/instructor_vectorizer_config_request.py +2 -2
- vellum/client/types/integration.py +27 -0
- vellum/client/types/integration_auth_config_integration.py +23 -0
- vellum/client/types/integration_auth_config_integration_credential.py +19 -0
- vellum/client/types/integration_credential_access_type.py +5 -0
- vellum/client/types/integration_name.py +109 -0
- vellum/client/types/integration_provider.py +5 -0
- vellum/client/types/integration_read.py +30 -0
- vellum/client/types/integration_trigger_context.py +39 -0
- vellum/client/types/invoked_port.py +2 -2
- vellum/client/types/jinja_prompt_block.py +4 -4
- vellum/client/types/json_input.py +3 -3
- vellum/client/types/json_input_request.py +3 -3
- vellum/client/types/json_vellum_value.py +2 -2
- vellum/client/types/json_vellum_value_request.py +2 -2
- vellum/client/types/logical_operator.py +4 -0
- vellum/client/types/map_node_result.py +3 -3
- vellum/client/types/map_node_result_data.py +3 -3
- vellum/client/types/merge_node_result.py +3 -3
- vellum/client/types/merge_node_result_data.py +2 -2
- vellum/client/types/metadata_filter_config_request.py +12 -6
- vellum/client/types/metadata_filter_rule_request.py +5 -5
- vellum/client/types/metadata_filters_request.py +1 -0
- vellum/client/types/metric_definition_execution.py +10 -4
- vellum/client/types/metric_definition_history_item.py +10 -4
- vellum/client/types/metric_definition_input.py +3 -2
- vellum/client/types/metric_node_result.py +2 -2
- vellum/client/types/ml_model_read.py +6 -3
- vellum/client/types/ml_model_usage.py +2 -2
- vellum/client/types/ml_model_usage_wrapper.py +3 -3
- vellum/client/types/named_scenario_input_audio_variable_value_request.py +22 -0
- vellum/client/types/named_scenario_input_chat_history_variable_value_request.py +3 -3
- vellum/client/types/named_scenario_input_document_variable_value_request.py +22 -0
- vellum/client/types/named_scenario_input_image_variable_value_request.py +22 -0
- vellum/client/types/named_scenario_input_json_variable_value_request.py +2 -2
- vellum/client/types/named_scenario_input_request.py +11 -2
- vellum/client/types/named_scenario_input_string_variable_value_request.py +2 -2
- vellum/client/types/named_scenario_input_video_variable_value_request.py +22 -0
- vellum/client/types/named_test_case_array_variable_value.py +11 -5
- vellum/client/types/named_test_case_array_variable_value_request.py +11 -5
- vellum/client/types/named_test_case_audio_variable_value.py +26 -0
- vellum/client/types/named_test_case_audio_variable_value_request.py +26 -0
- vellum/client/types/named_test_case_chat_history_variable_value.py +3 -3
- vellum/client/types/named_test_case_chat_history_variable_value_request.py +3 -3
- vellum/client/types/named_test_case_document_variable_value.py +22 -0
- vellum/client/types/named_test_case_document_variable_value_request.py +22 -0
- vellum/client/types/named_test_case_error_variable_value.py +3 -3
- vellum/client/types/named_test_case_error_variable_value_request.py +3 -3
- vellum/client/types/named_test_case_function_call_variable_value.py +3 -3
- vellum/client/types/named_test_case_function_call_variable_value_request.py +3 -3
- vellum/client/types/named_test_case_image_variable_value.py +22 -0
- vellum/client/types/named_test_case_image_variable_value_request.py +22 -0
- vellum/client/types/named_test_case_json_variable_value.py +2 -2
- vellum/client/types/named_test_case_json_variable_value_request.py +2 -2
- vellum/client/types/named_test_case_number_variable_value.py +2 -2
- vellum/client/types/named_test_case_number_variable_value_request.py +2 -2
- vellum/client/types/named_test_case_search_results_variable_value.py +3 -3
- vellum/client/types/named_test_case_search_results_variable_value_request.py +3 -3
- vellum/client/types/named_test_case_string_variable_value.py +2 -2
- vellum/client/types/named_test_case_string_variable_value_request.py +2 -2
- vellum/client/types/named_test_case_variable_value.py +14 -5
- vellum/client/types/named_test_case_variable_value_request.py +14 -5
- vellum/client/types/named_test_case_video_variable_value.py +22 -0
- vellum/client/types/named_test_case_video_variable_value_request.py +22 -0
- vellum/client/types/node_execution_fulfilled_body.py +5 -4
- vellum/client/types/node_execution_fulfilled_event.py +24 -15
- vellum/client/types/node_execution_initiated_body.py +3 -3
- vellum/client/types/node_execution_initiated_event.py +24 -15
- vellum/client/types/node_execution_log_body.py +24 -0
- vellum/client/types/node_execution_log_event.py +47 -0
- vellum/client/types/node_execution_paused_body.py +3 -3
- vellum/client/types/node_execution_paused_event.py +24 -15
- vellum/client/types/node_execution_rejected_body.py +5 -4
- vellum/client/types/node_execution_rejected_event.py +24 -15
- vellum/client/types/node_execution_resumed_body.py +3 -3
- vellum/client/types/node_execution_resumed_event.py +24 -15
- vellum/client/types/node_execution_span.py +23 -12
- vellum/client/types/node_execution_span_attributes.py +4 -2
- vellum/client/types/node_execution_streaming_body.py +4 -4
- vellum/client/types/node_execution_streaming_event.py +24 -15
- vellum/client/types/node_input_compiled_array_value.py +11 -5
- vellum/client/types/node_input_compiled_audio_value.py +23 -0
- vellum/client/types/node_input_compiled_chat_history_value.py +3 -3
- vellum/client/types/node_input_compiled_document_value.py +23 -0
- vellum/client/types/node_input_compiled_error_value.py +3 -3
- vellum/client/types/node_input_compiled_function_call_value.py +3 -3
- vellum/client/types/node_input_compiled_image_value.py +23 -0
- vellum/client/types/node_input_compiled_json_value.py +2 -2
- vellum/client/types/node_input_compiled_number_value.py +2 -2
- vellum/client/types/node_input_compiled_search_results_value.py +3 -3
- vellum/client/types/node_input_compiled_secret_value.py +3 -3
- vellum/client/types/node_input_compiled_string_value.py +2 -2
- vellum/client/types/node_input_compiled_video_value.py +23 -0
- vellum/client/types/node_input_variable_compiled_value.py +14 -5
- vellum/client/types/node_output_compiled_array_value.py +12 -6
- vellum/client/types/node_output_compiled_chat_history_value.py +3 -3
- vellum/client/types/node_output_compiled_error_value.py +3 -3
- vellum/client/types/node_output_compiled_function_call_value.py +3 -3
- vellum/client/types/node_output_compiled_json_value.py +3 -3
- vellum/client/types/node_output_compiled_number_value.py +3 -3
- vellum/client/types/node_output_compiled_search_results_value.py +3 -3
- vellum/client/types/node_output_compiled_string_value.py +3 -3
- vellum/client/types/node_output_compiled_thinking_value.py +28 -0
- vellum/client/types/node_output_compiled_value.py +8 -5
- vellum/client/types/node_parent_context.py +14 -11
- vellum/client/types/normalized_log_probs.py +3 -3
- vellum/client/types/normalized_token_log_probs.py +2 -2
- vellum/client/types/number_input.py +3 -3
- vellum/client/types/number_vellum_value.py +2 -2
- vellum/client/types/number_vellum_value_request.py +2 -2
- vellum/client/types/open_ai_vectorizer_config.py +3 -3
- vellum/client/types/open_ai_vectorizer_config_request.py +3 -3
- vellum/client/types/open_ai_vectorizer_text_embedding_3_large.py +3 -3
- vellum/client/types/open_ai_vectorizer_text_embedding_3_large_request.py +3 -3
- vellum/client/types/open_ai_vectorizer_text_embedding_3_small.py +3 -3
- vellum/client/types/open_ai_vectorizer_text_embedding_3_small_request.py +3 -3
- vellum/client/types/open_ai_vectorizer_text_embedding_ada_002.py +3 -3
- vellum/client/types/open_ai_vectorizer_text_embedding_ada_002_request.py +3 -3
- vellum/client/types/organization_read.py +6 -3
- vellum/client/types/paginated_container_image_read_list.py +3 -3
- vellum/client/types/paginated_deployment_release_tag_read_list.py +3 -3
- vellum/client/types/paginated_document_index_read_list.py +3 -3
- vellum/client/types/paginated_folder_entity_list.py +3 -3
- vellum/client/types/paginated_slim_deployment_read_list.py +10 -4
- vellum/client/types/paginated_slim_document_list.py +3 -3
- vellum/client/types/paginated_slim_integration_auth_config_read_list.py +23 -0
- vellum/client/types/paginated_slim_integration_read_list.py +23 -0
- vellum/client/types/paginated_slim_tool_definition_list.py +23 -0
- vellum/client/types/paginated_slim_workflow_deployment_list.py +10 -4
- vellum/client/types/paginated_test_suite_run_execution_list.py +10 -4
- vellum/client/types/paginated_test_suite_test_case_list.py +10 -4
- vellum/client/types/paginated_workflow_deployment_release_list.py +30 -0
- vellum/client/types/paginated_workflow_release_tag_read_list.py +3 -3
- vellum/client/types/paginated_workflow_sandbox_example_list.py +3 -3
- vellum/client/types/parent_context.py +21 -11
- vellum/client/types/pdf_search_result_meta_source.py +2 -2
- vellum/client/types/pdf_search_result_meta_source_request.py +2 -2
- vellum/client/types/plain_text_prompt_block.py +4 -4
- vellum/client/types/price.py +3 -3
- vellum/client/types/private_vectorizer.py +23 -0
- vellum/client/types/private_vectorizer_request.py +23 -0
- vellum/client/types/processing_failure_reason_enum.py +3 -1
- vellum/client/types/prompt_block.py +9 -6
- vellum/client/types/prompt_deployment_expand_meta_request.py +2 -2
- vellum/client/types/prompt_deployment_input_request.py +16 -3
- vellum/client/types/prompt_deployment_parent_context.py +13 -10
- vellum/client/types/prompt_deployment_release.py +6 -6
- vellum/client/types/prompt_deployment_release_prompt_deployment.py +3 -2
- vellum/client/types/prompt_deployment_release_prompt_version.py +4 -4
- vellum/client/types/prompt_exec_config.py +15 -9
- vellum/client/types/prompt_execution_meta.py +3 -3
- vellum/client/types/prompt_node_execution_meta.py +3 -3
- vellum/client/types/prompt_node_result.py +3 -3
- vellum/client/types/prompt_node_result_data.py +3 -3
- vellum/client/types/prompt_output.py +7 -3
- vellum/client/types/prompt_parameters.py +2 -2
- vellum/client/types/prompt_push_response.py +2 -2
- vellum/client/types/prompt_request_audio_input.py +26 -0
- vellum/client/types/prompt_request_chat_history_input.py +3 -3
- vellum/client/types/prompt_request_document_input.py +26 -0
- vellum/client/types/prompt_request_image_input.py +26 -0
- vellum/client/types/prompt_request_input.py +16 -3
- vellum/client/types/prompt_request_json_input.py +3 -3
- vellum/client/types/prompt_request_string_input.py +3 -3
- vellum/client/types/prompt_request_video_input.py +26 -0
- vellum/client/types/prompt_settings.py +2 -2
- vellum/client/types/prompt_version_build_config_sandbox.py +2 -2
- vellum/client/types/raw_prompt_execution_overrides_request.py +2 -2
- vellum/client/types/reducto_chunker_config.py +2 -2
- vellum/client/types/reducto_chunker_config_request.py +2 -2
- vellum/client/types/reducto_chunking.py +3 -3
- vellum/client/types/reducto_chunking_request.py +3 -3
- vellum/client/types/rejected_ad_hoc_execute_prompt_event.py +4 -4
- vellum/client/types/rejected_execute_prompt_event.py +4 -4
- vellum/client/types/rejected_execute_prompt_response.py +3 -3
- vellum/client/types/rejected_execute_workflow_workflow_result_event.py +4 -4
- vellum/client/types/rejected_prompt_execution_meta.py +3 -3
- vellum/client/types/rejected_workflow_node_result_event.py +12 -6
- vellum/client/types/release_created_by.py +2 -2
- vellum/client/types/release_environment.py +2 -2
- vellum/client/types/release_release_tag.py +3 -3
- vellum/client/types/release_review_reviewer.py +2 -2
- vellum/client/types/release_tag_release.py +2 -2
- vellum/client/types/replace_test_suite_test_case_request.py +9 -3
- vellum/client/types/rich_text_child_block.py +2 -1
- vellum/client/types/rich_text_prompt_block.py +4 -4
- vellum/client/types/runner_config_request.py +24 -0
- vellum/client/types/sandbox_scenario.py +3 -3
- vellum/client/types/scenario_input.py +14 -3
- vellum/client/types/scenario_input_audio_variable_value.py +22 -0
- vellum/client/types/scenario_input_chat_history_variable_value.py +3 -3
- vellum/client/types/scenario_input_document_variable_value.py +22 -0
- vellum/client/types/scenario_input_image_variable_value.py +22 -0
- vellum/client/types/scenario_input_json_variable_value.py +2 -2
- vellum/client/types/scenario_input_string_variable_value.py +2 -2
- vellum/client/types/scenario_input_video_variable_value.py +22 -0
- vellum/client/types/scheduled_trigger_context.py +39 -0
- vellum/client/types/search_filters_request.py +11 -5
- vellum/client/types/search_node_result.py +3 -3
- vellum/client/types/search_node_result_data.py +3 -3
- vellum/client/types/search_request_options_request.py +13 -7
- vellum/client/types/search_response.py +3 -3
- vellum/client/types/search_result.py +3 -3
- vellum/client/types/search_result_document.py +2 -2
- vellum/client/types/search_result_document_request.py +2 -2
- vellum/client/types/search_result_merging_request.py +2 -2
- vellum/client/types/search_result_meta.py +3 -3
- vellum/client/types/search_result_meta_request.py +3 -3
- vellum/client/types/search_result_request.py +3 -3
- vellum/client/types/search_results_input.py +3 -3
- vellum/client/types/search_results_vellum_value.py +3 -3
- vellum/client/types/search_results_vellum_value_request.py +3 -3
- vellum/client/types/search_weights_request.py +2 -2
- vellum/client/types/secret_type_enum.py +3 -1
- vellum/client/types/sentence_chunker_config.py +2 -2
- vellum/client/types/sentence_chunker_config_request.py +2 -2
- vellum/client/types/sentence_chunking.py +3 -3
- vellum/client/types/sentence_chunking_request.py +3 -3
- vellum/client/types/severity_enum.py +5 -0
- vellum/client/types/slim_composio_tool_definition.py +25 -0
- vellum/client/types/slim_deployment_read.py +15 -9
- vellum/client/types/slim_document.py +6 -5
- vellum/client/types/slim_document_document_to_document_index.py +6 -4
- vellum/client/types/slim_integration_auth_config_read.py +36 -0
- vellum/client/types/slim_integration_read.py +25 -0
- vellum/client/types/slim_release_review.py +4 -4
- vellum/client/types/slim_workflow_deployment.py +16 -10
- vellum/client/types/slim_workflow_execution_read.py +24 -15
- vellum/client/types/span_link.py +15 -12
- vellum/client/types/span_link_type_enum.py +1 -1
- vellum/client/types/streaming_ad_hoc_execute_prompt_event.py +4 -4
- vellum/client/types/streaming_execute_prompt_event.py +3 -3
- vellum/client/types/streaming_prompt_execution_meta.py +2 -2
- vellum/client/types/streaming_workflow_node_result_event.py +12 -6
- vellum/client/types/string_chat_message_content.py +2 -2
- vellum/client/types/string_chat_message_content_request.py +2 -2
- vellum/client/types/string_input.py +3 -3
- vellum/client/types/string_input_request.py +3 -3
- vellum/client/types/string_vellum_value.py +2 -2
- vellum/client/types/string_vellum_value_request.py +2 -2
- vellum/client/types/submit_completion_actual_request.py +3 -3
- vellum/client/types/submit_workflow_execution_actual_request.py +3 -2
- vellum/client/types/subworkflow_node_result.py +3 -3
- vellum/client/types/subworkflow_node_result_data.py +2 -2
- vellum/client/types/templating_node_array_result.py +11 -5
- vellum/client/types/templating_node_chat_history_result.py +3 -3
- vellum/client/types/templating_node_error_result.py +3 -3
- vellum/client/types/templating_node_function_call_result.py +3 -3
- vellum/client/types/templating_node_json_result.py +2 -2
- vellum/client/types/templating_node_number_result.py +2 -2
- vellum/client/types/templating_node_result.py +10 -4
- vellum/client/types/templating_node_result_data.py +10 -4
- vellum/client/types/templating_node_result_output.py +6 -5
- vellum/client/types/templating_node_search_results_result.py +3 -3
- vellum/client/types/templating_node_string_result.py +2 -2
- vellum/client/types/terminal_node_array_result.py +11 -5
- vellum/client/types/terminal_node_chat_history_result.py +2 -2
- vellum/client/types/terminal_node_error_result.py +2 -2
- vellum/client/types/terminal_node_function_call_result.py +2 -2
- vellum/client/types/terminal_node_json_result.py +2 -2
- vellum/client/types/terminal_node_number_result.py +2 -2
- vellum/client/types/terminal_node_result.py +10 -4
- vellum/client/types/terminal_node_result_data.py +10 -4
- vellum/client/types/terminal_node_result_output.py +6 -5
- vellum/client/types/terminal_node_search_results_result.py +2 -2
- vellum/client/types/terminal_node_string_result.py +2 -2
- vellum/client/types/test_case_array_variable_value.py +11 -5
- vellum/client/types/test_case_audio_variable_value.py +27 -0
- vellum/client/types/test_case_chat_history_variable_value.py +3 -3
- vellum/client/types/test_case_document_variable_value.py +27 -0
- vellum/client/types/test_case_error_variable_value.py +3 -3
- vellum/client/types/test_case_function_call_variable_value.py +3 -3
- vellum/client/types/test_case_image_variable_value.py +27 -0
- vellum/client/types/test_case_json_variable_value.py +2 -2
- vellum/client/types/test_case_number_variable_value.py +2 -2
- vellum/client/types/test_case_search_results_variable_value.py +3 -3
- vellum/client/types/test_case_string_variable_value.py +2 -2
- vellum/client/types/test_case_variable_value.py +14 -5
- vellum/client/types/test_case_video_variable_value.py +27 -0
- vellum/client/types/test_suite_run_deployment_release_tag_exec_config.py +3 -3
- vellum/client/types/test_suite_run_deployment_release_tag_exec_config_data.py +3 -3
- vellum/client/types/test_suite_run_deployment_release_tag_exec_config_data_request.py +3 -3
- vellum/client/types/test_suite_run_deployment_release_tag_exec_config_request.py +3 -3
- vellum/client/types/test_suite_run_exec_config.py +2 -1
- vellum/client/types/test_suite_run_exec_config_request.py +2 -1
- vellum/client/types/test_suite_run_execution.py +11 -5
- vellum/client/types/test_suite_run_execution_array_output.py +11 -5
- vellum/client/types/test_suite_run_execution_chat_history_output.py +3 -3
- vellum/client/types/test_suite_run_execution_error_output.py +3 -3
- vellum/client/types/test_suite_run_execution_function_call_output.py +3 -3
- vellum/client/types/test_suite_run_execution_json_output.py +2 -2
- vellum/client/types/test_suite_run_execution_metric_definition.py +2 -2
- vellum/client/types/test_suite_run_execution_metric_result.py +11 -5
- vellum/client/types/test_suite_run_execution_number_output.py +2 -2
- vellum/client/types/test_suite_run_execution_output.py +6 -5
- vellum/client/types/test_suite_run_execution_search_results_output.py +3 -3
- vellum/client/types/test_suite_run_execution_string_output.py +2 -2
- vellum/client/types/test_suite_run_external_exec_config.py +10 -4
- vellum/client/types/test_suite_run_external_exec_config_data.py +10 -4
- vellum/client/types/test_suite_run_external_exec_config_data_request.py +10 -4
- vellum/client/types/test_suite_run_external_exec_config_request.py +10 -4
- vellum/client/types/test_suite_run_metric_array_output.py +11 -5
- vellum/client/types/test_suite_run_metric_error_output.py +3 -3
- vellum/client/types/test_suite_run_metric_json_output.py +2 -2
- vellum/client/types/test_suite_run_metric_number_output.py +2 -2
- vellum/client/types/test_suite_run_metric_output.py +5 -4
- vellum/client/types/test_suite_run_metric_string_output.py +2 -2
- vellum/client/types/test_suite_run_progress.py +2 -2
- vellum/client/types/test_suite_run_prompt_sandbox_exec_config_data_request.py +3 -3
- vellum/client/types/test_suite_run_prompt_sandbox_exec_config_request.py +3 -3
- vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config.py +3 -3
- vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_data.py +3 -3
- vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_data_request.py +3 -3
- vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_request.py +3 -3
- vellum/client/types/test_suite_run_read.py +12 -6
- vellum/client/types/test_suite_run_test_suite.py +2 -2
- vellum/client/types/test_suite_run_workflow_release_tag_exec_config.py +3 -3
- vellum/client/types/test_suite_run_workflow_release_tag_exec_config_data.py +3 -3
- vellum/client/types/test_suite_run_workflow_release_tag_exec_config_data_request.py +3 -3
- vellum/client/types/test_suite_run_workflow_release_tag_exec_config_request.py +3 -3
- vellum/client/types/test_suite_run_workflow_sandbox_exec_config_data_request.py +3 -3
- vellum/client/types/test_suite_run_workflow_sandbox_exec_config_request.py +3 -3
- vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config.py +3 -3
- vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_data.py +3 -3
- vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_data_request.py +3 -3
- vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_request.py +3 -3
- vellum/client/types/test_suite_test_case.py +10 -4
- vellum/client/types/test_suite_test_case_bulk_operation_request.py +2 -1
- vellum/client/types/test_suite_test_case_bulk_result.py +2 -1
- vellum/client/types/test_suite_test_case_create_bulk_operation_request.py +10 -4
- vellum/client/types/test_suite_test_case_created_bulk_result.py +3 -3
- vellum/client/types/test_suite_test_case_created_bulk_result_data.py +2 -2
- vellum/client/types/test_suite_test_case_delete_bulk_operation_data_request.py +2 -2
- vellum/client/types/test_suite_test_case_delete_bulk_operation_request.py +3 -3
- vellum/client/types/test_suite_test_case_deleted_bulk_result.py +3 -3
- vellum/client/types/test_suite_test_case_deleted_bulk_result_data.py +2 -2
- vellum/client/types/test_suite_test_case_rejected_bulk_result.py +2 -2
- vellum/client/types/test_suite_test_case_replace_bulk_operation_request.py +10 -4
- vellum/client/types/test_suite_test_case_replaced_bulk_result.py +3 -3
- vellum/client/types/test_suite_test_case_replaced_bulk_result_data.py +2 -2
- vellum/client/types/test_suite_test_case_upsert_bulk_operation_request.py +10 -4
- vellum/client/types/thinking_vellum_value.py +25 -0
- vellum/client/types/thinking_vellum_value_request.py +25 -0
- vellum/client/types/token_overlapping_window_chunker_config.py +2 -2
- vellum/client/types/token_overlapping_window_chunker_config_request.py +2 -2
- vellum/client/types/token_overlapping_window_chunking.py +3 -3
- vellum/client/types/token_overlapping_window_chunking_request.py +3 -3
- vellum/client/types/type_checker_enum.py +5 -0
- vellum/client/types/update_active_workspace_response.py +32 -0
- vellum/client/types/upload_document_response.py +3 -3
- vellum/client/types/uploaded_file_read.py +27 -0
- vellum/client/types/upsert_test_suite_test_case_request.py +9 -3
- vellum/client/types/variable_prompt_block.py +11 -4
- vellum/client/types/vellum_audio.py +10 -5
- vellum/client/types/vellum_audio_request.py +8 -4
- vellum/client/types/vellum_code_resource_definition.py +7 -2
- vellum/client/types/vellum_document.py +13 -4
- vellum/client/types/vellum_document_request.py +11 -3
- vellum/client/types/vellum_error.py +5 -4
- vellum/client/types/vellum_error_code_enum.py +6 -0
- vellum/client/types/vellum_error_request.py +5 -4
- vellum/client/types/vellum_image.py +13 -4
- vellum/client/types/vellum_image_request.py +11 -3
- vellum/client/types/vellum_node_execution_event.py +6 -3
- vellum/client/types/vellum_sdk_error.py +4 -3
- vellum/client/types/vellum_sdk_error_code_enum.py +5 -0
- vellum/client/types/vellum_secret.py +2 -2
- vellum/client/types/vellum_span.py +2 -1
- vellum/client/types/vellum_value.py +13 -8
- vellum/client/types/vellum_value_logical_condition_group_request.py +6 -6
- vellum/client/types/vellum_value_logical_condition_request.py +13 -7
- vellum/client/types/vellum_value_logical_expression_request.py +2 -1
- vellum/client/types/vellum_value_request.py +13 -8
- vellum/client/types/vellum_variable.py +18 -7
- vellum/client/types/vellum_variable_extensions.py +4 -2
- vellum/client/types/vellum_variable_type.py +4 -1
- vellum/client/types/vellum_video.py +29 -0
- vellum/client/types/vellum_video_request.py +28 -0
- vellum/client/types/vellum_workflow_execution_event.py +4 -3
- vellum/client/types/video_chat_message_content.py +25 -0
- vellum/client/types/video_chat_message_content_request.py +25 -0
- vellum/client/types/video_input.py +30 -0
- vellum/client/types/video_input_request.py +30 -0
- vellum/client/types/video_prompt_block.py +29 -0
- vellum/client/types/video_vellum_value.py +25 -0
- vellum/client/types/video_vellum_value_request.py +25 -0
- vellum/client/types/workflow_deployment_display_data.py +27 -0
- vellum/client/types/workflow_deployment_event_executions_response.py +20 -11
- vellum/client/types/workflow_deployment_history_item.py +10 -4
- vellum/client/types/workflow_deployment_parent_context.py +13 -10
- vellum/client/types/workflow_deployment_read.py +22 -10
- vellum/client/types/workflow_deployment_release.py +13 -7
- vellum/client/types/workflow_deployment_release_workflow_deployment.py +3 -2
- vellum/client/types/workflow_deployment_release_workflow_version.py +10 -4
- vellum/client/types/workflow_display_icon.py +24 -0
- vellum/client/types/workflow_error.py +1 -0
- vellum/client/types/workflow_event.py +39 -0
- vellum/client/types/workflow_event_error.py +5 -3
- vellum/client/types/workflow_event_execution_read.py +26 -16
- vellum/client/types/workflow_execution_actual.py +11 -5
- vellum/client/types/workflow_execution_actual_chat_history_request.py +2 -2
- vellum/client/types/workflow_execution_actual_json_request.py +2 -2
- vellum/client/types/workflow_execution_actual_string_request.py +2 -2
- vellum/client/types/workflow_execution_detail.py +51 -0
- vellum/client/types/workflow_execution_event_error_code.py +5 -0
- vellum/client/types/workflow_execution_fulfilled_body.py +6 -3
- vellum/client/types/workflow_execution_fulfilled_event.py +24 -15
- vellum/client/types/workflow_execution_initiated_body.py +3 -3
- vellum/client/types/workflow_execution_initiated_event.py +24 -15
- vellum/client/types/workflow_execution_node_result_event.py +10 -4
- vellum/client/types/workflow_execution_paused_body.py +4 -4
- vellum/client/types/workflow_execution_paused_event.py +24 -15
- vellum/client/types/workflow_execution_rejected_body.py +5 -4
- vellum/client/types/workflow_execution_rejected_event.py +24 -15
- vellum/client/types/workflow_execution_resumed_body.py +3 -3
- vellum/client/types/workflow_execution_resumed_event.py +24 -15
- vellum/client/types/workflow_execution_snapshotted_body.py +4 -3
- vellum/client/types/workflow_execution_snapshotted_event.py +24 -15
- vellum/client/types/workflow_execution_span.py +22 -11
- vellum/client/types/workflow_execution_span_attributes.py +3 -2
- vellum/client/types/workflow_execution_streaming_body.py +4 -4
- vellum/client/types/workflow_execution_streaming_event.py +24 -15
- vellum/client/types/workflow_execution_usage_calculation_error.py +3 -3
- vellum/client/types/workflow_execution_usage_calculation_fulfilled_body.py +22 -0
- vellum/client/types/workflow_execution_usage_result.py +3 -3
- vellum/client/types/workflow_execution_view_online_eval_metric_result.py +10 -4
- vellum/client/types/workflow_execution_workflow_result_event.py +10 -4
- vellum/client/types/workflow_expand_meta_request.py +2 -2
- vellum/client/types/workflow_initialization_error.py +2 -2
- vellum/client/types/workflow_input.py +31 -0
- vellum/client/types/workflow_node_result_data.py +8 -7
- vellum/client/types/workflow_node_result_event.py +3 -2
- vellum/client/types/workflow_output.py +12 -5
- vellum/client/types/workflow_output_array.py +12 -6
- vellum/client/types/workflow_output_audio.py +31 -0
- vellum/client/types/workflow_output_chat_history.py +3 -3
- vellum/client/types/workflow_output_document.py +31 -0
- vellum/client/types/workflow_output_error.py +3 -3
- vellum/client/types/workflow_output_function_call.py +3 -3
- vellum/client/types/workflow_output_image.py +3 -3
- vellum/client/types/workflow_output_json.py +3 -3
- vellum/client/types/workflow_output_number.py +3 -3
- vellum/client/types/workflow_output_search_results.py +3 -3
- vellum/client/types/workflow_output_string.py +3 -3
- vellum/client/types/workflow_output_video.py +31 -0
- vellum/client/types/workflow_parent_context.py +14 -11
- vellum/client/types/workflow_push_deployment_config_request.py +3 -2
- vellum/client/types/workflow_push_response.py +2 -2
- vellum/client/types/workflow_release_tag_read.py +4 -4
- vellum/client/types/workflow_release_tag_workflow_deployment_history_item.py +2 -2
- vellum/client/types/workflow_request_audio_input_request.py +30 -0
- vellum/client/types/workflow_request_chat_history_input_request.py +3 -3
- vellum/client/types/workflow_request_document_input_request.py +30 -0
- vellum/client/types/workflow_request_image_input_request.py +30 -0
- vellum/client/types/workflow_request_input_request.py +11 -2
- vellum/client/types/workflow_request_json_input_request.py +3 -3
- vellum/client/types/workflow_request_number_input_request.py +3 -3
- vellum/client/types/workflow_request_string_input_request.py +3 -3
- vellum/client/types/workflow_request_video_input_request.py +30 -0
- vellum/client/types/workflow_resolved_state.py +31 -0
- vellum/client/types/workflow_result_event.py +14 -8
- vellum/client/types/workflow_result_event_output_data.py +7 -6
- vellum/client/types/workflow_result_event_output_data_array.py +13 -7
- vellum/client/types/workflow_result_event_output_data_chat_history.py +4 -4
- vellum/client/types/workflow_result_event_output_data_error.py +4 -4
- vellum/client/types/workflow_result_event_output_data_function_call.py +4 -4
- vellum/client/types/workflow_result_event_output_data_json.py +4 -4
- vellum/client/types/workflow_result_event_output_data_number.py +4 -4
- vellum/client/types/workflow_result_event_output_data_search_results.py +4 -4
- vellum/client/types/workflow_result_event_output_data_string.py +4 -4
- vellum/client/types/workflow_result_event_state.py +7 -0
- vellum/client/types/workflow_sandbox_display_data.py +27 -0
- vellum/client/types/workflow_sandbox_example.py +4 -2
- vellum/client/types/workflow_sandbox_execute_node_response.py +8 -0
- vellum/client/types/workflow_sandbox_parent_context.py +13 -10
- vellum/client/types/workflow_stream_event.py +2 -1
- vellum/client/types/workspace_display_config.py +19 -0
- vellum/client/types/workspace_read.py +5 -3
- vellum/client/types/workspace_secret_read.py +3 -3
- vellum/client/utils.py +24 -0
- vellum/core/force_multipart.py +3 -0
- vellum/core/http_response.py +3 -0
- vellum/errors/misdirected_request_error.py +3 -0
- vellum/errors/too_many_requests_error.py +3 -0
- vellum/errors/unauthorized_error.py +3 -0
- vellum/evaluations/resources.py +5 -5
- vellum/plugins/pydantic.py +14 -3
- vellum/plugins/tests/__init__.py +0 -0
- vellum/plugins/tests/test_pydantic.py +30 -0
- vellum/plugins/vellum_mypy.py +68 -25
- vellum/prompts/__init__.py +3 -0
- vellum/prompts/blocks/__init__.py +3 -0
- vellum/prompts/blocks/compilation.py +29 -11
- vellum/prompts/blocks/helpers.py +31 -0
- vellum/prompts/blocks/tests/test_compilation.py +64 -0
- vellum/raw_client.py +3 -0
- vellum/resources/ad_hoc/raw_client.py +3 -0
- vellum/resources/container_images/raw_client.py +3 -0
- vellum/resources/deployments/raw_client.py +3 -0
- vellum/resources/document_indexes/raw_client.py +3 -0
- vellum/resources/documents/raw_client.py +3 -0
- vellum/resources/{release_reviews → environments}/__init__.py +1 -1
- vellum/resources/{release_reviews → environments}/client.py +1 -1
- vellum/resources/environments/raw_client.py +3 -0
- vellum/resources/events/__init__.py +3 -0
- vellum/resources/events/client.py +3 -0
- vellum/resources/events/raw_client.py +3 -0
- vellum/resources/folder_entities/raw_client.py +3 -0
- vellum/resources/integration_auth_configs/__init__.py +3 -0
- vellum/resources/integration_auth_configs/client.py +3 -0
- vellum/resources/integration_auth_configs/raw_client.py +3 -0
- vellum/resources/integration_providers/__init__.py +3 -0
- vellum/resources/integration_providers/client.py +3 -0
- vellum/resources/integration_providers/raw_client.py +3 -0
- vellum/resources/integrations/__init__.py +3 -0
- vellum/resources/integrations/client.py +3 -0
- vellum/resources/integrations/raw_client.py +3 -0
- vellum/resources/metric_definitions/raw_client.py +3 -0
- vellum/resources/ml_models/raw_client.py +3 -0
- vellum/resources/organizations/raw_client.py +3 -0
- vellum/resources/prompts/raw_client.py +3 -0
- vellum/resources/sandboxes/raw_client.py +3 -0
- vellum/resources/test_suite_runs/raw_client.py +3 -0
- vellum/resources/test_suites/raw_client.py +3 -0
- vellum/resources/uploaded_files/__init__.py +3 -0
- vellum/resources/uploaded_files/client.py +3 -0
- vellum/resources/uploaded_files/raw_client.py +3 -0
- vellum/resources/workflow_deployments/raw_client.py +3 -0
- vellum/resources/workflow_executions/__init__.py +3 -0
- vellum/resources/workflow_executions/client.py +3 -0
- vellum/resources/workflow_executions/raw_client.py +3 -0
- vellum/resources/workflow_sandboxes/raw_client.py +3 -0
- vellum/resources/workflows/raw_client.py +3 -0
- vellum/resources/workspace_secrets/raw_client.py +3 -0
- vellum/resources/workspaces/raw_client.py +3 -0
- vellum/types/api_actor_type_enum.py +3 -0
- vellum/types/audio_input.py +3 -0
- vellum/types/audio_input_request.py +3 -0
- vellum/types/auth_type_enum.py +3 -0
- vellum/types/build_status_enum.py +3 -0
- vellum/types/check_workflow_execution_status_error.py +3 -0
- vellum/types/check_workflow_execution_status_response.py +3 -0
- vellum/types/code_execution_package_request.py +3 -0
- vellum/types/components_schemas_composio_execute_tool_request.py +3 -0
- vellum/types/components_schemas_composio_execute_tool_response.py +3 -0
- vellum/types/components_schemas_composio_integration_exec_config.py +3 -0
- vellum/types/components_schemas_composio_tool_definition.py +3 -0
- vellum/types/components_schemas_slim_composio_tool_definition.py +3 -0
- vellum/types/composio_execute_tool_request.py +3 -0
- vellum/types/composio_execute_tool_response.py +3 -0
- vellum/types/composio_integration_exec_config.py +3 -0
- vellum/types/composio_tool_definition.py +3 -0
- vellum/types/container_image_build_config.py +3 -0
- vellum/types/create_workflow_event_request.py +3 -0
- vellum/types/dataset_row_push_request.py +3 -0
- vellum/types/delimiter_chunker_config.py +3 -0
- vellum/types/delimiter_chunker_config_request.py +3 -0
- vellum/types/delimiter_chunking.py +3 -0
- vellum/types/delimiter_chunking_request.py +3 -0
- vellum/types/deprecated_prompt_request_input.py +3 -0
- vellum/types/document_input.py +3 -0
- vellum/types/document_input_request.py +3 -0
- vellum/types/environment_display_config.py +3 -0
- vellum/types/environment_read.py +3 -0
- vellum/types/error_detail_response.py +3 -0
- vellum/types/event_create_response.py +3 -0
- vellum/types/execute_workflow_async_response.py +3 -0
- vellum/types/execution_audio_vellum_value.py +3 -0
- vellum/types/execution_document_vellum_value.py +3 -0
- vellum/types/execution_image_vellum_value.py +3 -0
- vellum/types/execution_thinking_vellum_value.py +3 -0
- vellum/types/execution_video_vellum_value.py +3 -0
- vellum/types/external_parent_context.py +3 -0
- vellum/types/fast_embed_vectorizer_baai_bge_small_en_v_15.py +3 -0
- vellum/types/fast_embed_vectorizer_baai_bge_small_en_v_15_request.py +3 -0
- vellum/types/folder_entity_dataset.py +3 -0
- vellum/types/folder_entity_dataset_data.py +3 -0
- vellum/types/google_vertex_ai_vectorizer_gemini_embedding_001.py +3 -0
- vellum/types/google_vertex_ai_vectorizer_gemini_embedding_001_request.py +3 -0
- vellum/types/image_input.py +3 -0
- vellum/types/image_input_request.py +3 -0
- vellum/types/integration.py +3 -0
- vellum/types/integration_auth_config_integration.py +3 -0
- vellum/types/integration_auth_config_integration_credential.py +3 -0
- vellum/types/integration_credential_access_type.py +3 -0
- vellum/types/integration_name.py +3 -0
- vellum/types/integration_provider.py +3 -0
- vellum/types/integration_read.py +3 -0
- vellum/types/integration_trigger_context.py +3 -0
- vellum/types/named_scenario_input_audio_variable_value_request.py +3 -0
- vellum/types/named_scenario_input_document_variable_value_request.py +3 -0
- vellum/types/named_scenario_input_image_variable_value_request.py +3 -0
- vellum/types/named_scenario_input_video_variable_value_request.py +3 -0
- vellum/types/named_test_case_audio_variable_value.py +3 -0
- vellum/types/named_test_case_audio_variable_value_request.py +3 -0
- vellum/types/named_test_case_document_variable_value.py +3 -0
- vellum/types/named_test_case_document_variable_value_request.py +3 -0
- vellum/types/named_test_case_image_variable_value.py +3 -0
- vellum/types/named_test_case_image_variable_value_request.py +3 -0
- vellum/types/named_test_case_video_variable_value.py +3 -0
- vellum/types/named_test_case_video_variable_value_request.py +3 -0
- vellum/types/node_execution_log_body.py +3 -0
- vellum/types/node_execution_log_event.py +3 -0
- vellum/types/node_input_compiled_audio_value.py +3 -0
- vellum/types/node_input_compiled_document_value.py +3 -0
- vellum/types/node_input_compiled_image_value.py +3 -0
- vellum/types/node_input_compiled_video_value.py +3 -0
- vellum/types/node_output_compiled_thinking_value.py +3 -0
- vellum/types/paginated_slim_integration_auth_config_read_list.py +3 -0
- vellum/types/paginated_slim_integration_read_list.py +3 -0
- vellum/types/paginated_slim_tool_definition_list.py +3 -0
- vellum/types/paginated_workflow_deployment_release_list.py +3 -0
- vellum/types/private_vectorizer.py +3 -0
- vellum/types/private_vectorizer_request.py +3 -0
- vellum/types/prompt_request_audio_input.py +3 -0
- vellum/types/prompt_request_document_input.py +3 -0
- vellum/types/prompt_request_image_input.py +3 -0
- vellum/types/prompt_request_video_input.py +3 -0
- vellum/types/runner_config_request.py +3 -0
- vellum/types/scenario_input_audio_variable_value.py +3 -0
- vellum/types/scenario_input_document_variable_value.py +3 -0
- vellum/types/scenario_input_image_variable_value.py +3 -0
- vellum/types/scenario_input_video_variable_value.py +3 -0
- vellum/types/scheduled_trigger_context.py +3 -0
- vellum/types/severity_enum.py +3 -0
- vellum/types/slim_composio_tool_definition.py +3 -0
- vellum/types/slim_integration_auth_config_read.py +3 -0
- vellum/types/slim_integration_read.py +3 -0
- vellum/types/test_case_audio_variable_value.py +3 -0
- vellum/types/test_case_document_variable_value.py +3 -0
- vellum/types/test_case_image_variable_value.py +3 -0
- vellum/types/test_case_video_variable_value.py +3 -0
- vellum/types/thinking_vellum_value.py +3 -0
- vellum/types/thinking_vellum_value_request.py +3 -0
- vellum/types/type_checker_enum.py +3 -0
- vellum/types/update_active_workspace_response.py +3 -0
- vellum/types/uploaded_file_read.py +3 -0
- vellum/types/vellum_video.py +3 -0
- vellum/types/vellum_video_request.py +3 -0
- vellum/types/video_chat_message_content.py +3 -0
- vellum/types/video_chat_message_content_request.py +3 -0
- vellum/types/video_input.py +3 -0
- vellum/types/video_input_request.py +3 -0
- vellum/types/video_prompt_block.py +3 -0
- vellum/types/video_vellum_value.py +3 -0
- vellum/types/video_vellum_value_request.py +3 -0
- vellum/types/workflow_deployment_display_data.py +3 -0
- vellum/types/workflow_display_icon.py +3 -0
- vellum/types/workflow_event.py +3 -0
- vellum/types/workflow_execution_detail.py +3 -0
- vellum/types/workflow_execution_usage_calculation_fulfilled_body.py +3 -0
- vellum/types/workflow_input.py +3 -0
- vellum/types/workflow_output_audio.py +3 -0
- vellum/types/workflow_output_document.py +3 -0
- vellum/types/workflow_output_video.py +3 -0
- vellum/types/workflow_request_audio_input_request.py +3 -0
- vellum/types/workflow_request_document_input_request.py +3 -0
- vellum/types/workflow_request_image_input_request.py +3 -0
- vellum/types/workflow_request_video_input_request.py +3 -0
- vellum/types/workflow_resolved_state.py +3 -0
- vellum/types/workflow_result_event_state.py +3 -0
- vellum/types/workflow_sandbox_display_data.py +3 -0
- vellum/types/workflow_sandbox_execute_node_response.py +3 -0
- vellum/types/workspace_display_config.py +3 -0
- vellum/utils/files/__init__.py +18 -0
- vellum/utils/files/constants.py +47 -0
- vellum/utils/files/exceptions.py +25 -0
- vellum/utils/files/extensions.py +59 -0
- vellum/utils/files/mixin.py +135 -0
- vellum/utils/files/read.py +41 -0
- vellum/utils/files/stream.py +135 -0
- vellum/utils/files/tests/__init__.py +0 -0
- vellum/utils/files/tests/test_extensions.py +54 -0
- vellum/utils/files/tests/test_mixin.py +267 -0
- vellum/utils/files/tests/test_read.py +204 -0
- vellum/utils/files/tests/test_stream.py +199 -0
- vellum/utils/files/tests/test_upload.py +309 -0
- vellum/utils/files/tests/test_urls.py +252 -0
- vellum/utils/files/types.py +8 -0
- vellum/utils/files/upload.py +151 -0
- vellum/utils/files/urls.py +71 -0
- vellum/utils/json_encoder.py +95 -0
- vellum/utils/templating/custom_filters.py +4 -4
- vellum/utils/templating/render.py +4 -4
- vellum/utils/tests/__init__.py +0 -0
- vellum/utils/tests/test_json_encoder.py +92 -0
- vellum/utils/tests/test_vellum_client.py +95 -0
- vellum/utils/uuid.py +19 -2
- vellum/utils/vellum_client.py +47 -0
- vellum/workflows/__init__.py +84 -0
- vellum/workflows/constants.py +7 -0
- vellum/workflows/context.py +27 -9
- vellum/workflows/descriptors/base.py +169 -2
- vellum/workflows/descriptors/exceptions.py +18 -1
- vellum/workflows/descriptors/tests/test_utils.py +66 -0
- vellum/workflows/descriptors/utils.py +27 -3
- vellum/workflows/edges/__init__.py +2 -0
- vellum/workflows/edges/trigger_edge.py +67 -0
- vellum/workflows/emitters/__init__.py +2 -0
- vellum/workflows/emitters/base.py +25 -0
- vellum/workflows/emitters/vellum_emitter.py +150 -0
- vellum/workflows/environment/__init__.py +2 -1
- vellum/workflows/environment/environment.py +10 -3
- vellum/workflows/errors/tests/__init__.py +0 -0
- vellum/workflows/errors/tests/test_types.py +52 -0
- vellum/workflows/errors/types.py +19 -1
- vellum/workflows/events/__init__.py +2 -0
- vellum/workflows/events/context.py +90 -0
- vellum/workflows/events/exception_handling.py +58 -0
- vellum/workflows/events/node.py +51 -11
- vellum/workflows/events/relational_threads.py +41 -0
- vellum/workflows/events/stream.py +28 -0
- vellum/workflows/events/tests/test_basic_workflow.py +50 -0
- vellum/workflows/events/tests/test_event.py +268 -20
- vellum/workflows/events/types.py +34 -5
- vellum/workflows/events/workflow.py +138 -9
- vellum/workflows/exceptions.py +46 -7
- vellum/workflows/executable.py +9 -0
- vellum/workflows/expressions/accessor.py +65 -11
- vellum/workflows/expressions/add.py +44 -0
- vellum/workflows/expressions/comparison_utils.py +38 -0
- vellum/workflows/expressions/concat.py +35 -0
- vellum/workflows/expressions/contains.py +7 -0
- vellum/workflows/expressions/greater_than.py +8 -1
- vellum/workflows/expressions/greater_than_or_equal_to.py +8 -1
- vellum/workflows/expressions/is_error.py +23 -0
- vellum/workflows/expressions/length.py +46 -0
- vellum/workflows/expressions/less_than.py +8 -1
- vellum/workflows/expressions/less_than_or_equal_to.py +8 -1
- vellum/workflows/expressions/minus.py +41 -0
- vellum/workflows/expressions/tests/test_accessor.py +248 -0
- vellum/workflows/expressions/tests/test_add.py +96 -0
- vellum/workflows/expressions/tests/test_concat.py +108 -0
- vellum/workflows/expressions/tests/test_contains.py +175 -0
- vellum/workflows/expressions/tests/test_expressions.py +145 -32
- vellum/workflows/expressions/tests/test_length.py +38 -0
- vellum/workflows/expressions/tests/test_minus.py +109 -0
- vellum/workflows/graph/graph.py +281 -13
- vellum/workflows/graph/tests/test_graph.py +528 -1
- vellum/workflows/inputs/__init__.py +2 -0
- vellum/workflows/inputs/base.py +63 -13
- vellum/workflows/inputs/dataset_row.py +186 -0
- vellum/workflows/inputs/tests/test_inputs.py +182 -2
- vellum/workflows/integrations/__init__.py +5 -0
- vellum/workflows/integrations/composio_service.py +158 -0
- vellum/workflows/integrations/mcp_service.py +282 -0
- vellum/workflows/integrations/tests/__init__.py +0 -0
- vellum/workflows/integrations/tests/test_mcp_service.py +273 -0
- vellum/workflows/integrations/tests/test_vellum_integration_service.py +383 -0
- vellum/workflows/integrations/vellum_integration_service.py +147 -0
- vellum/workflows/loaders/__init__.py +3 -0
- vellum/workflows/loaders/base.py +38 -0
- vellum/workflows/nodes/__init__.py +2 -0
- vellum/workflows/nodes/bases/base.py +165 -82
- vellum/workflows/nodes/bases/base_adornment_node.py +55 -1
- vellum/workflows/nodes/bases/tests/test_base_node.py +153 -4
- vellum/workflows/nodes/core/error_node/node.py +11 -2
- vellum/workflows/nodes/core/inline_subworkflow_node/node.py +30 -3
- vellum/workflows/nodes/core/inline_subworkflow_node/tests/test_node.py +36 -1
- vellum/workflows/nodes/core/map_node/node.py +33 -6
- vellum/workflows/nodes/core/map_node/tests/test_node.py +106 -0
- vellum/workflows/nodes/core/retry_node/node.py +1 -0
- vellum/workflows/nodes/core/retry_node/tests/test_node.py +2 -3
- vellum/workflows/nodes/core/templating_node/node.py +7 -2
- vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py +194 -1
- vellum/workflows/nodes/core/try_node/node.py +1 -0
- vellum/workflows/nodes/displayable/__init__.py +6 -0
- vellum/workflows/nodes/displayable/api_node/node.py +13 -3
- vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py +151 -2
- vellum/workflows/nodes/displayable/bases/api_node/node.py +71 -17
- vellum/workflows/nodes/displayable/bases/api_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/bases/api_node/tests/test_node.py +150 -0
- vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +85 -7
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +324 -19
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py +352 -32
- vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +86 -3
- vellum/workflows/nodes/displayable/bases/search_node.py +26 -3
- vellum/workflows/nodes/displayable/bases/tests/test_prompt_deployment_node.py +90 -0
- vellum/workflows/nodes/displayable/bases/utils.py +82 -5
- vellum/workflows/nodes/displayable/code_execution_node/node.py +30 -10
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py +284 -14
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +8 -21
- vellum/workflows/nodes/displayable/conditional_node/node.py +8 -4
- vellum/workflows/nodes/displayable/final_output_node/node.py +34 -0
- vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py +146 -1
- vellum/workflows/nodes/displayable/guardrail_node/node.py +13 -4
- vellum/workflows/nodes/displayable/inline_prompt_node/node.py +9 -36
- vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py +3 -0
- vellum/workflows/nodes/displayable/merge_node/node.py +8 -1
- vellum/workflows/nodes/displayable/note_node/node.py +11 -1
- vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +7 -23
- vellum/workflows/nodes/displayable/search_node/node.py +15 -2
- vellum/workflows/nodes/displayable/search_node/tests/test_node.py +33 -0
- vellum/workflows/nodes/displayable/set_state_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/set_state_node/node.py +71 -0
- vellum/workflows/nodes/displayable/set_state_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/set_state_node/tests/test_node.py +212 -0
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +231 -59
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py +1 -1
- vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +4 -1
- vellum/workflows/nodes/displayable/tests/test_search_node_error_handling.py +329 -0
- vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +56 -14
- vellum/workflows/nodes/displayable/tool_calling_node/__init__.py +3 -0
- vellum/workflows/nodes/displayable/tool_calling_node/node.py +265 -0
- vellum/workflows/nodes/displayable/tool_calling_node/state.py +11 -0
- vellum/workflows/nodes/displayable/tool_calling_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/tool_calling_node/tests/test_composio_service.py +219 -0
- vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py +998 -0
- vellum/workflows/nodes/displayable/tool_calling_node/tests/test_utils.py +316 -0
- vellum/workflows/nodes/displayable/tool_calling_node/utils.py +654 -0
- vellum/workflows/nodes/displayable/web_search_node/__init__.py +3 -0
- vellum/workflows/nodes/displayable/web_search_node/node.py +136 -0
- vellum/workflows/nodes/displayable/web_search_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/web_search_node/tests/test_node.py +246 -0
- vellum/workflows/nodes/experimental/__init__.py +1 -3
- vellum/workflows/nodes/mocks.py +71 -206
- vellum/workflows/nodes/tests/test_mocks.py +0 -177
- vellum/workflows/nodes/tests/test_utils.py +34 -5
- vellum/workflows/nodes/utils.py +68 -14
- vellum/workflows/outputs/base.py +88 -14
- vellum/workflows/ports/node_ports.py +3 -0
- vellum/workflows/ports/port.py +27 -12
- vellum/workflows/ports/tests/test_port.py +45 -0
- vellum/workflows/ports/utils.py +26 -6
- vellum/workflows/references/__init__.py +2 -0
- vellum/workflows/references/constant.py +4 -1
- vellum/workflows/references/environment_variable.py +17 -9
- vellum/workflows/references/lazy.py +8 -0
- vellum/workflows/references/output.py +4 -6
- vellum/workflows/references/state_value.py +24 -1
- vellum/workflows/references/tests/test_lazy.py +58 -0
- vellum/workflows/references/trigger.py +82 -0
- vellum/workflows/references/workflow_input.py +8 -0
- vellum/workflows/resolvers/base.py +19 -1
- vellum/workflows/resolvers/resolver.py +81 -0
- vellum/workflows/resolvers/tests/test_resolver.py +199 -0
- vellum/workflows/resolvers/types.py +11 -0
- vellum/workflows/runner/runner.py +770 -143
- vellum/workflows/runner/tests/__init__.py +0 -0
- vellum/workflows/runner/tests/test_runner.py +170 -0
- vellum/workflows/sandbox.py +54 -9
- vellum/workflows/state/base.py +238 -55
- vellum/workflows/state/context.py +297 -7
- vellum/workflows/state/delta.py +20 -0
- vellum/workflows/state/encoder.py +2 -77
- vellum/workflows/state/tests/test_state.py +292 -9
- vellum/workflows/tests/test_dataset_row.py +191 -0
- vellum/workflows/tests/test_sandbox.py +226 -0
- vellum/workflows/tests/triggers/test_integration_trigger.py +156 -0
- vellum/workflows/triggers/__init__.py +7 -0
- vellum/workflows/triggers/base.py +523 -0
- vellum/workflows/triggers/chat_message.py +141 -0
- vellum/workflows/triggers/integration.py +198 -0
- vellum/workflows/triggers/manual.py +39 -0
- vellum/workflows/triggers/schedule.py +20 -0
- vellum/workflows/triggers/tests/__init__.py +1 -0
- vellum/workflows/triggers/tests/test_base_trigger_display.py +147 -0
- vellum/workflows/triggers/tests/test_chat_message.py +257 -0
- vellum/workflows/triggers/tests/test_integration.py +155 -0
- vellum/workflows/types/__init__.py +2 -1
- vellum/workflows/types/code_execution_node_wrappers.py +5 -1
- vellum/workflows/types/core.py +23 -0
- vellum/workflows/types/definition.py +161 -2
- vellum/workflows/types/generics.py +17 -0
- vellum/workflows/types/tests/test_definition.py +183 -0
- vellum/workflows/types/tests/test_utils.py +23 -0
- vellum/workflows/types/utils.py +65 -5
- vellum/workflows/types/workflow_metadata.py +124 -0
- vellum/workflows/utils/files.py +28 -0
- vellum/workflows/utils/functions.py +386 -25
- vellum/workflows/utils/hmac.py +44 -0
- vellum/workflows/utils/names.py +32 -4
- vellum/workflows/utils/pydantic_schema.py +56 -0
- vellum/workflows/utils/tests/test_functions.py +480 -23
- vellum/workflows/utils/tests/test_names.py +9 -0
- vellum/workflows/utils/tests/test_validate.py +79 -0
- vellum/workflows/utils/tests/test_vellum_variables.py +93 -3
- vellum/workflows/utils/uuids.py +125 -0
- vellum/workflows/utils/validate.py +108 -0
- vellum/workflows/utils/vellum_variables.py +224 -20
- vellum/workflows/utils/zip.py +46 -0
- vellum/workflows/vellum_client.py +3 -33
- vellum/workflows/workflows/base.py +503 -50
- vellum/workflows/workflows/event_filters.py +13 -0
- vellum/workflows/workflows/tests/test_base_workflow.py +169 -6
- vellum/workflows/workflows/tests/test_event_filters.py +126 -0
- {vellum_ai-0.14.63.dist-info → vellum_ai-1.13.5.dist-info}/METADATA +17 -13
- vellum_ai-1.13.5.dist-info/RECORD +2224 -0
- vellum_ai-1.13.5.dist-info/entry_points.txt +4 -0
- vellum_cli/__init__.py +55 -4
- vellum_cli/config.py +21 -5
- vellum_cli/image_push.py +106 -8
- vellum_cli/move.py +56 -0
- vellum_cli/ping.py +6 -0
- vellum_cli/pull.py +50 -14
- vellum_cli/push.py +124 -34
- vellum_cli/tests/conftest.py +13 -12
- vellum_cli/tests/test_image_push.py +192 -21
- vellum_cli/tests/test_image_push_error_handling.py +258 -0
- vellum_cli/tests/test_init.py +7 -24
- vellum_cli/tests/test_move.py +154 -0
- vellum_cli/tests/test_ping.py +15 -0
- vellum_cli/tests/test_pull.py +125 -129
- vellum_cli/tests/test_push.py +693 -12
- vellum_ee/assets/node-definitions.json +1348 -0
- vellum_ee/scripts/generate_node_definitions.py +101 -0
- vellum_ee/workflows/display/base.py +33 -58
- vellum_ee/workflows/display/editor/types.py +3 -0
- vellum_ee/workflows/display/exceptions.py +3 -0
- vellum_ee/workflows/display/nodes/base_node_display.py +199 -58
- vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +242 -3
- vellum_ee/workflows/display/nodes/types.py +1 -0
- vellum_ee/workflows/display/nodes/vellum/api_node.py +26 -13
- vellum_ee/workflows/display/nodes/vellum/base_adornment_node.py +8 -5
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +23 -7
- vellum_ee/workflows/display/nodes/vellum/conditional_node.py +18 -7
- vellum_ee/workflows/display/nodes/vellum/error_node.py +2 -4
- vellum_ee/workflows/display/nodes/vellum/final_output_node.py +3 -14
- vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +2 -5
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +85 -44
- vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +44 -18
- vellum_ee/workflows/display/nodes/vellum/map_node.py +31 -15
- vellum_ee/workflows/display/nodes/vellum/merge_node.py +2 -5
- vellum_ee/workflows/display/nodes/vellum/note_node.py +20 -6
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +13 -9
- vellum_ee/workflows/display/nodes/vellum/retry_node.py +5 -6
- vellum_ee/workflows/display/nodes/vellum/search_node.py +76 -19
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +46 -12
- vellum_ee/workflows/display/nodes/vellum/templating_node.py +3 -6
- vellum_ee/workflows/display/nodes/vellum/tests/test_api_node.py +65 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py +236 -3
- vellum_ee/workflows/display/nodes/vellum/tests/test_final_output_node.py +216 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_inline_subworkflow_node.py +88 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_note_node.py +44 -7
- vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_deployment_node.py +71 -1
- vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py +120 -26
- vellum_ee/workflows/display/nodes/vellum/tests/test_retry_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/tests/test_search_node.py +104 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_subworkflow_deployment_node.py +28 -18
- vellum_ee/workflows/display/nodes/vellum/tests/test_templating_node.py +2 -2
- vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py +649 -49
- vellum_ee/workflows/display/nodes/vellum/tests/test_try_node.py +2 -2
- vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +114 -10
- vellum_ee/workflows/display/nodes/vellum/try_node.py +5 -6
- vellum_ee/workflows/display/nodes/vellum/utils.py +54 -12
- vellum_ee/workflows/display/tests/test_base_workflow_display.py +396 -25
- vellum_ee/workflows/display/tests/test_json_schema_validation.py +190 -0
- vellum_ee/workflows/display/tests/test_mocks.py +912 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py +2 -2
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +114 -39
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +342 -90
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +24 -17
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +263 -65
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py +69 -12
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +36 -305
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +92 -431
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +143 -429
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_state_serialization.py +3 -123
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +24 -110
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py +12 -90
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +17 -86
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +363 -100
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +97 -315
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +66 -319
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +24 -99
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +54 -180
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py +32 -88
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_set_state_node_serialization.py +86 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +217 -142
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py +34 -142
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +15 -8
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_composio_serialization.py +89 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +184 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_tool_wrapper_serialization.py +84 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_mcp_serialization.py +104 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_parent_input.py +89 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +71 -23
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_tool_wrapper_serialization.py +71 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_vellum_integration_serialization.py +187 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py +107 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +2 -4
- vellum_ee/workflows/display/tests/workflow_serialization/test_chat_message_dict_reference_serialization.py +129 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_chat_message_trigger_serialization.py +412 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_code_tool_node_reference_error.py +106 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +20 -47
- vellum_ee/workflows/display/tests/workflow_serialization/test_duplicate_trigger_name_validation.py +208 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_final_output_node_map_reference_serialization.py +88 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_final_output_node_not_referenced_by_workflow_outputs.py +45 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_infinite_loop_validation.py +66 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_int_input_serialization.py +40 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_serialization.py +300 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_validation.py +173 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_integration_trigger_with_entrypoint_node_id.py +91 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_list_vellum_document_serialization.py +69 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_manual_trigger_serialization.py +120 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_map_node_with_terminal_nodes_serialization.py +62 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_multi_trigger_same_node_serialization.py +210 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_no_triggers_no_entrypoint_validation.py +64 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_partial_workflow_meta_display_override.py +55 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_dataset_mocks_serialization.py +268 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_invalid_pdf_data_url.py +49 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_sandbox_validation_errors.py +112 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_scheduled_trigger_serialization.py +276 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_terminal_node_any_serialization.py +49 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_terminal_node_in_unused_graphs_serialization.py +53 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_trigger_display_from_display_class.py +153 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_web_search_node_serialization.py +72 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_workflow_input_parameterization_error.py +37 -0
- vellum_ee/workflows/display/types.py +29 -2
- vellum_ee/workflows/display/utils/auto_layout.py +130 -0
- vellum_ee/workflows/display/utils/events.py +57 -0
- vellum_ee/workflows/display/utils/exceptions.py +53 -0
- vellum_ee/workflows/display/utils/expressions.py +669 -55
- vellum_ee/workflows/display/utils/metadata.py +211 -0
- vellum_ee/workflows/display/utils/registry.py +46 -0
- vellum_ee/workflows/display/utils/tests/__init__.py +0 -0
- vellum_ee/workflows/display/utils/tests/test_auto_layout.py +56 -0
- vellum_ee/workflows/display/utils/tests/test_events.py +185 -0
- vellum_ee/workflows/display/utils/tests/test_expressions.py +92 -0
- vellum_ee/workflows/display/utils/tests/test_metadata.py +31 -0
- vellum_ee/workflows/display/utils/triggers.py +153 -0
- vellum_ee/workflows/display/utils/vellum.py +94 -5
- vellum_ee/workflows/display/vellum.py +2 -128
- vellum_ee/workflows/display/workflows/__init__.py +0 -1
- vellum_ee/workflows/display/workflows/base_workflow_display.py +1224 -190
- vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +26 -0
- vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +379 -41
- vellum_ee/workflows/server/namespaces.py +18 -0
- vellum_ee/workflows/server/virtual_file_loader.py +131 -6
- vellum_ee/workflows/tests/local_workflow/display/nodes/final_output.py +1 -1
- vellum_ee/workflows/tests/local_workflow/display/nodes/templating_node.py +1 -1
- vellum_ee/workflows/tests/local_workflow/display/workflow.py +11 -14
- vellum_ee/workflows/tests/test_display_meta.py +43 -0
- vellum_ee/workflows/tests/test_registry.py +169 -0
- vellum_ee/workflows/tests/test_serialize_module.py +432 -0
- vellum_ee/workflows/tests/test_server.py +616 -44
- vellum_ee/workflows/tests/test_virtual_files.py +48 -0
- vellum/client/resources/release_reviews/client.py +0 -137
- vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py +0 -5
- vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py +0 -266
- vellum/workflows/nodes/experimental/tool_calling_node/__init__.py +0 -3
- vellum/workflows/nodes/experimental/tool_calling_node/node.py +0 -135
- vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py +0 -53
- vellum/workflows/nodes/experimental/tool_calling_node/utils.py +0 -259
- vellum_ai-0.14.63.dist-info/RECORD +0 -1719
- vellum_ai-0.14.63.dist-info/entry_points.txt +0 -3
- vellum_ee/workflows/display/workflows/vellum_workflow_display.py +0 -9
- /vellum/{workflows/nodes/displayable/bases/inline_prompt_node → prompts}/constants.py +0 -0
- {vellum_ai-0.14.63.dist-info → vellum_ai-1.13.5.dist-info}/LICENSE +0 -0
- {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
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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":
|
|
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)
|
|
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":
|
|
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
|
-
#
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
|
190
|
-
|
|
191
|
-
|
|
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
|
|
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":
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
-
|
|
637
|
+
should_apply_auto_layout = all_nodes_at_zero and len(nodes_dict_list) > 0
|
|
317
638
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
return
|
|
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
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
-
|
|
876
|
+
trigger_def = self._fetch_integration_trigger_definition(provider, integration_name, slug)
|
|
877
|
+
if not trigger_def:
|
|
878
|
+
return
|
|
345
879
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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,
|
|
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(
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
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 =
|
|
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
|
-
|
|
564
|
-
|
|
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:
|
|
570
|
-
|
|
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
|
-
|
|
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
|
|
609
|
-
|
|
610
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
684
|
-
|
|
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(
|
|
687
|
-
|
|
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)
|