vellum-ai 1.11.2__py3-none-any.whl → 1.13.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of vellum-ai might be problematic. Click here for more details.
- vellum/__init__.py +18 -0
- vellum/client/README.md +1 -1
- vellum/client/core/client_wrapper.py +2 -2
- vellum/client/core/force_multipart.py +4 -2
- vellum/client/core/http_response.py +1 -1
- vellum/client/core/pydantic_utilities.py +7 -4
- vellum/client/errors/too_many_requests_error.py +1 -2
- vellum/client/reference.md +677 -76
- vellum/client/resources/container_images/client.py +299 -0
- vellum/client/resources/container_images/raw_client.py +286 -0
- vellum/client/resources/documents/client.py +20 -10
- vellum/client/resources/documents/raw_client.py +20 -10
- vellum/client/resources/events/raw_client.py +4 -4
- vellum/client/resources/integration_auth_configs/client.py +2 -0
- vellum/client/resources/integration_auth_configs/raw_client.py +2 -0
- vellum/client/resources/integration_providers/client.py +28 -2
- vellum/client/resources/integration_providers/raw_client.py +24 -0
- vellum/client/resources/integrations/client.py +52 -4
- vellum/client/resources/integrations/raw_client.py +61 -0
- vellum/client/resources/workflow_deployments/client.py +156 -0
- vellum/client/resources/workflow_deployments/raw_client.py +334 -0
- vellum/client/resources/workflows/client.py +212 -8
- vellum/client/resources/workflows/raw_client.py +343 -6
- vellum/client/types/__init__.py +18 -0
- vellum/client/types/api_actor_type_enum.py +1 -1
- 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_package_request.py +21 -0
- vellum/client/types/composio_execute_tool_request.py +5 -0
- vellum/client/types/composio_tool_definition.py +1 -0
- vellum/client/types/container_image_build_config.py +1 -0
- vellum/client/types/container_image_container_image_tag.py +1 -0
- vellum/client/types/dataset_row_push_request.py +3 -0
- vellum/client/types/document_document_to_document_index.py +1 -0
- vellum/client/types/integration_name.py +24 -0
- vellum/client/types/node_execution_fulfilled_body.py +1 -0
- vellum/client/types/node_execution_log_body.py +24 -0
- vellum/client/types/node_execution_log_event.py +47 -0
- vellum/client/types/prompt_deployment_release_prompt_deployment.py +1 -0
- vellum/client/types/runner_config_request.py +24 -0
- vellum/client/types/severity_enum.py +5 -0
- vellum/client/types/slim_composio_tool_definition.py +1 -0
- vellum/client/types/slim_document_document_to_document_index.py +2 -0
- vellum/client/types/type_checker_enum.py +5 -0
- vellum/client/types/vellum_audio.py +5 -1
- vellum/client/types/vellum_audio_request.py +5 -1
- vellum/client/types/vellum_document.py +5 -1
- vellum/client/types/vellum_document_request.py +5 -1
- vellum/client/types/vellum_image.py +5 -1
- vellum/client/types/vellum_image_request.py +5 -1
- vellum/client/types/vellum_node_execution_event.py +2 -0
- vellum/client/types/vellum_variable.py +5 -0
- vellum/client/types/vellum_variable_extensions.py +1 -0
- vellum/client/types/vellum_variable_type.py +1 -0
- vellum/client/types/vellum_video.py +5 -1
- vellum/client/types/vellum_video_request.py +5 -1
- vellum/client/types/workflow_deployment_release_workflow_deployment.py +1 -0
- vellum/client/types/workflow_event.py +2 -0
- vellum/client/types/workflow_execution_fulfilled_body.py +1 -0
- vellum/client/types/workflow_result_event_output_data_array.py +1 -1
- vellum/client/types/workflow_result_event_output_data_chat_history.py +1 -1
- vellum/client/types/workflow_result_event_output_data_error.py +1 -1
- vellum/client/types/workflow_result_event_output_data_function_call.py +1 -1
- vellum/client/types/workflow_result_event_output_data_json.py +1 -1
- vellum/client/types/workflow_result_event_output_data_number.py +1 -1
- vellum/client/types/workflow_result_event_output_data_search_results.py +1 -1
- vellum/client/types/workflow_result_event_output_data_string.py +1 -1
- vellum/client/types/workflow_sandbox_execute_node_response.py +8 -0
- vellum/plugins/vellum_mypy.py +37 -2
- 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/node_execution_log_body.py +3 -0
- vellum/types/node_execution_log_event.py +3 -0
- vellum/types/runner_config_request.py +3 -0
- vellum/types/severity_enum.py +3 -0
- vellum/types/type_checker_enum.py +3 -0
- vellum/types/workflow_sandbox_execute_node_response.py +3 -0
- vellum/utils/files/mixin.py +26 -0
- vellum/utils/files/tests/test_mixin.py +62 -0
- vellum/utils/tests/test_vellum_client.py +95 -0
- vellum/utils/uuid.py +19 -2
- vellum/utils/vellum_client.py +10 -3
- vellum/workflows/__init__.py +7 -1
- vellum/workflows/descriptors/base.py +86 -0
- vellum/workflows/descriptors/tests/test_utils.py +9 -0
- vellum/workflows/errors/tests/__init__.py +0 -0
- vellum/workflows/errors/tests/test_types.py +52 -0
- vellum/workflows/errors/types.py +1 -0
- vellum/workflows/events/node.py +24 -0
- vellum/workflows/events/tests/test_event.py +123 -0
- vellum/workflows/events/types.py +2 -1
- vellum/workflows/events/workflow.py +28 -2
- vellum/workflows/expressions/add.py +3 -0
- vellum/workflows/expressions/tests/test_add.py +24 -0
- vellum/workflows/graph/graph.py +26 -5
- vellum/workflows/graph/tests/test_graph.py +228 -1
- vellum/workflows/inputs/base.py +22 -6
- vellum/workflows/inputs/dataset_row.py +121 -16
- vellum/workflows/inputs/tests/test_inputs.py +3 -3
- vellum/workflows/integrations/tests/test_vellum_integration_service.py +84 -0
- vellum/workflows/integrations/vellum_integration_service.py +12 -1
- vellum/workflows/loaders/base.py +2 -0
- vellum/workflows/nodes/bases/base.py +37 -16
- vellum/workflows/nodes/bases/tests/test_base_node.py +104 -1
- vellum/workflows/nodes/core/inline_subworkflow_node/node.py +1 -0
- vellum/workflows/nodes/core/inline_subworkflow_node/tests/test_node.py +1 -1
- vellum/workflows/nodes/core/map_node/node.py +7 -5
- vellum/workflows/nodes/core/map_node/tests/test_node.py +33 -0
- vellum/workflows/nodes/core/retry_node/node.py +1 -0
- vellum/workflows/nodes/core/try_node/node.py +1 -0
- vellum/workflows/nodes/displayable/api_node/node.py +3 -2
- vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py +38 -0
- vellum/workflows/nodes/displayable/bases/api_node/node.py +1 -1
- vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +18 -1
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +109 -2
- vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +13 -2
- vellum/workflows/nodes/displayable/code_execution_node/node.py +9 -15
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py +65 -24
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +3 -0
- vellum/workflows/nodes/displayable/final_output_node/node.py +24 -69
- vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py +53 -3
- vellum/workflows/nodes/displayable/note_node/node.py +4 -1
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +16 -5
- vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +47 -0
- vellum/workflows/nodes/displayable/tool_calling_node/node.py +74 -34
- vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py +204 -8
- vellum/workflows/nodes/displayable/tool_calling_node/utils.py +92 -71
- vellum/workflows/nodes/mocks.py +47 -213
- vellum/workflows/nodes/tests/test_mocks.py +0 -177
- vellum/workflows/nodes/utils.py +23 -8
- vellum/workflows/outputs/base.py +36 -3
- vellum/workflows/references/environment_variable.py +1 -11
- vellum/workflows/references/lazy.py +8 -0
- vellum/workflows/references/state_value.py +24 -1
- vellum/workflows/references/tests/test_lazy.py +58 -0
- vellum/workflows/references/trigger.py +8 -3
- vellum/workflows/references/workflow_input.py +8 -0
- vellum/workflows/resolvers/resolver.py +13 -3
- vellum/workflows/resolvers/tests/test_resolver.py +31 -0
- vellum/workflows/runner/runner.py +159 -14
- vellum/workflows/runner/tests/__init__.py +0 -0
- vellum/workflows/runner/tests/test_runner.py +170 -0
- vellum/workflows/sandbox.py +7 -8
- vellum/workflows/state/base.py +89 -30
- vellum/workflows/state/context.py +74 -3
- vellum/workflows/state/tests/test_state.py +269 -1
- vellum/workflows/tests/test_dataset_row.py +8 -7
- vellum/workflows/tests/test_sandbox.py +97 -8
- vellum/workflows/triggers/__init__.py +2 -1
- vellum/workflows/triggers/base.py +160 -28
- vellum/workflows/triggers/chat_message.py +141 -0
- vellum/workflows/triggers/integration.py +12 -0
- vellum/workflows/triggers/manual.py +3 -1
- vellum/workflows/triggers/schedule.py +3 -1
- vellum/workflows/triggers/tests/test_chat_message.py +257 -0
- vellum/workflows/types/core.py +18 -0
- vellum/workflows/types/definition.py +6 -13
- vellum/workflows/types/generics.py +12 -0
- vellum/workflows/types/tests/test_utils.py +12 -0
- vellum/workflows/types/utils.py +32 -2
- vellum/workflows/types/workflow_metadata.py +124 -0
- vellum/workflows/utils/functions.py +152 -16
- vellum/workflows/utils/pydantic_schema.py +19 -1
- vellum/workflows/utils/tests/test_functions.py +123 -8
- vellum/workflows/utils/tests/test_validate.py +79 -0
- vellum/workflows/utils/tests/test_vellum_variables.py +62 -2
- vellum/workflows/utils/uuids.py +90 -0
- vellum/workflows/utils/validate.py +108 -0
- vellum/workflows/utils/vellum_variables.py +96 -16
- vellum/workflows/workflows/base.py +177 -35
- vellum/workflows/workflows/tests/test_base_workflow.py +51 -0
- {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/METADATA +6 -1
- {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/RECORD +274 -227
- vellum_cli/__init__.py +21 -0
- vellum_cli/config.py +16 -2
- vellum_cli/pull.py +2 -0
- vellum_cli/push.py +23 -10
- vellum_cli/tests/conftest.py +8 -13
- vellum_cli/tests/test_image_push.py +4 -11
- vellum_cli/tests/test_pull.py +83 -68
- vellum_cli/tests/test_push.py +251 -2
- vellum_ee/assets/node-definitions.json +225 -12
- vellum_ee/scripts/generate_node_definitions.py +15 -3
- vellum_ee/workflows/display/base.py +4 -3
- vellum_ee/workflows/display/nodes/base_node_display.py +44 -11
- vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +93 -0
- vellum_ee/workflows/display/nodes/types.py +1 -0
- vellum_ee/workflows/display/nodes/vellum/__init__.py +0 -2
- vellum_ee/workflows/display/nodes/vellum/base_adornment_node.py +5 -2
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +10 -2
- vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +17 -14
- vellum_ee/workflows/display/nodes/vellum/map_node.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/note_node.py +18 -3
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +37 -14
- vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py +62 -2
- vellum_ee/workflows/display/nodes/vellum/tests/test_final_output_node.py +136 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_note_node.py +44 -7
- vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py +5 -13
- vellum_ee/workflows/display/nodes/vellum/tests/test_subworkflow_deployment_node.py +27 -17
- vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py +145 -22
- vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +107 -2
- vellum_ee/workflows/display/nodes/vellum/utils.py +54 -12
- vellum_ee/workflows/display/tests/test_base_workflow_display.py +13 -16
- 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/test_adornments_serialization.py +14 -2
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +109 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +3 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +187 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +34 -325
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +42 -393
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +13 -315
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_state_serialization.py +2 -122
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +24 -115
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py +4 -93
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +7 -80
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +9 -101
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +77 -308
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +62 -324
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +3 -82
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +4 -142
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py +1 -61
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_set_state_node_serialization.py +4 -4
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +205 -134
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py +34 -146
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +2 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_composio_serialization.py +8 -6
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +137 -266
- 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 +55 -16
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +15 -1
- 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 +119 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py +1 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +0 -2
- vellum_ee/workflows/display/tests/workflow_serialization/test_chat_message_dict_reference_serialization.py +22 -1
- 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 +9 -41
- 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_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 +8 -14
- 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 +16 -13
- vellum_ee/workflows/display/tests/workflow_serialization/test_list_vellum_document_serialization.py +5 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_manual_trigger_serialization.py +12 -2
- vellum_ee/workflows/display/tests/workflow_serialization/test_multi_trigger_same_node_serialization.py +111 -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 +25 -16
- vellum_ee/workflows/display/tests/workflow_serialization/test_terminal_node_in_unused_graphs_serialization.py +53 -0
- vellum_ee/workflows/display/utils/exceptions.py +34 -0
- vellum_ee/workflows/display/utils/expressions.py +463 -52
- vellum_ee/workflows/display/utils/metadata.py +98 -33
- 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 +59 -5
- vellum_ee/workflows/display/workflows/base_workflow_display.py +656 -254
- vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +26 -0
- vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +77 -29
- vellum_ee/workflows/server/namespaces.py +18 -0
- vellum_ee/workflows/tests/test_display_meta.py +2 -0
- vellum_ee/workflows/tests/test_serialize_module.py +174 -7
- vellum_ee/workflows/tests/test_server.py +0 -3
- vellum_ee/workflows/display/nodes/vellum/function_node.py +0 -14
- {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/LICENSE +0 -0
- {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/WHEEL +0 -0
- {vellum_ai-1.11.2.dist-info → vellum_ai-1.13.5.dist-info}/entry_points.txt +0 -0
vellum/workflows/utils/uuids.py
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import hashlib
|
|
2
|
+
import sys
|
|
2
3
|
from uuid import UUID
|
|
3
4
|
from typing import TYPE_CHECKING
|
|
4
5
|
|
|
6
|
+
from vellum.workflows.loaders.base import BaseWorkflowFinder
|
|
7
|
+
|
|
5
8
|
if TYPE_CHECKING:
|
|
9
|
+
from vellum.workflows.inputs.base import BaseInputs
|
|
10
|
+
from vellum.workflows.state.base import BaseState
|
|
6
11
|
from vellum.workflows.triggers.base import BaseTrigger
|
|
7
12
|
|
|
8
13
|
|
|
@@ -21,6 +26,59 @@ def generate_workflow_deployment_prefix(deployment_name: str, release_tag: str)
|
|
|
21
26
|
return f"vellum_workflow_deployment_{expected_hash}"
|
|
22
27
|
|
|
23
28
|
|
|
29
|
+
def _normalize_module_path(module_path: str) -> str:
|
|
30
|
+
"""
|
|
31
|
+
Normalize a module path by filtering out a leading ephemeral namespace segment.
|
|
32
|
+
|
|
33
|
+
When workflows are loaded dynamically (e.g., via VirtualFileFinder), the module path
|
|
34
|
+
may start with an ephemeral namespace that changes on each invocation. This function
|
|
35
|
+
strips that leading segment to ensure stable, deterministic ID generation.
|
|
36
|
+
|
|
37
|
+
The function checks if the first segment of the module path exactly matches the
|
|
38
|
+
namespace of any registered BaseWorkflowFinder in sys.meta_path. Only namespaces
|
|
39
|
+
that are actually registered are stripped, preventing accidental stripping of
|
|
40
|
+
legitimate module names.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
module_path: The module path to normalize (e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890.workflow"
|
|
44
|
+
or "workflow_tmp_ABC123xyz.workflow")
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
The normalized module path with the leading ephemeral segment removed if present
|
|
48
|
+
(e.g., "workflow")
|
|
49
|
+
"""
|
|
50
|
+
parts = module_path.split(".")
|
|
51
|
+
if not parts:
|
|
52
|
+
return module_path
|
|
53
|
+
|
|
54
|
+
first_part = parts[0]
|
|
55
|
+
|
|
56
|
+
# Check if the first part matches the namespace of any registered workflow finder
|
|
57
|
+
for finder in sys.meta_path:
|
|
58
|
+
if isinstance(finder, BaseWorkflowFinder) and finder.namespace == first_part:
|
|
59
|
+
return ".".join(parts[1:]) if len(parts) > 1 else ""
|
|
60
|
+
|
|
61
|
+
return module_path
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def generate_entity_id_from_path(path: str) -> UUID:
|
|
65
|
+
"""
|
|
66
|
+
Generate a deterministic entity ID from a path string.
|
|
67
|
+
|
|
68
|
+
This function normalizes the path by filtering out any leading UUID namespace segment
|
|
69
|
+
(which may change on each invocation when workflows are loaded dynamically), then
|
|
70
|
+
generates a stable UUID from the normalized path.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
path: The path string to generate an ID from (e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890.workflow.MyNode")
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
A deterministic UUID based on the normalized path
|
|
77
|
+
"""
|
|
78
|
+
normalized_path = _normalize_module_path(path)
|
|
79
|
+
return uuid4_from_hash(normalized_path)
|
|
80
|
+
|
|
81
|
+
|
|
24
82
|
def uuid4_from_hash(input_str: str) -> UUID:
|
|
25
83
|
# Create a SHA-256 hash of the input string
|
|
26
84
|
hash_bytes = hashlib.sha256(input_str.encode()).digest()
|
|
@@ -57,3 +115,35 @@ def get_trigger_attribute_id(trigger_class: "type[BaseTrigger]", attribute_name:
|
|
|
57
115
|
"""
|
|
58
116
|
trigger_id = trigger_class.__id__
|
|
59
117
|
return uuid4_from_hash(f"{trigger_id}|{attribute_name}")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def get_workflow_input_id(inputs_class: "type[BaseInputs]", input_name: str) -> UUID:
|
|
121
|
+
"""
|
|
122
|
+
Generate a deterministic workflow input ID from an inputs class and input name
|
|
123
|
+
using the class's parent workflow ID and input name to ensure stability and uniqueness.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
inputs_class: The inputs class containing the input
|
|
127
|
+
input_name: The name of the input
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
A deterministic UUID based on the workflow ID and input name
|
|
131
|
+
"""
|
|
132
|
+
workflow_class = inputs_class.__parent_class__
|
|
133
|
+
workflow_id = workflow_class.__id__
|
|
134
|
+
return uuid4_from_hash(f"{workflow_id}|inputs|id|{input_name}")
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def get_state_value_id(state_class: "type[BaseState]", state_value_name: str) -> UUID:
|
|
138
|
+
"""
|
|
139
|
+
Generate a deterministic state value ID from a state class and state value name
|
|
140
|
+
using the class's module name, qualname, and state value name to ensure stability and uniqueness.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
state_class: The state class containing the state value
|
|
144
|
+
state_value_name: The name of the state value
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
A deterministic UUID based on the state class module, qualname, and state value name
|
|
148
|
+
"""
|
|
149
|
+
return uuid4_from_hash(f"{state_class.__module__}.{state_class.__qualname__}|state_values|id|{state_value_name}")
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from typing import Any, Union, get_args, get_origin
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TypeValidationError(ValueError):
|
|
5
|
+
"""Exception raised when type validation fails."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, declared_type: type, target_type: type) -> None:
|
|
8
|
+
declared_type_name = getattr(declared_type, "__name__", str(declared_type))
|
|
9
|
+
target_type_name = getattr(target_type, "__name__", str(target_type))
|
|
10
|
+
super().__init__(
|
|
11
|
+
f"Output type mismatch: declared type '{declared_type_name}' "
|
|
12
|
+
f"but the 'value' Output has type(s) '{target_type_name}'. "
|
|
13
|
+
)
|
|
14
|
+
self.declared_type = declared_type
|
|
15
|
+
self.target_type = target_type
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def validate_target_type(declared_type: type, target_type: type) -> None:
|
|
19
|
+
# If either type is Any, validation always passes
|
|
20
|
+
if declared_type is Any or target_type is Any:
|
|
21
|
+
return
|
|
22
|
+
|
|
23
|
+
declared_origin = get_origin(declared_type)
|
|
24
|
+
target_origin = get_origin(target_type)
|
|
25
|
+
|
|
26
|
+
# Special case: both are Unions
|
|
27
|
+
# Each target union member must be compatible with at least one declared union member
|
|
28
|
+
if declared_origin is Union and target_origin is Union:
|
|
29
|
+
declared_union_args = get_args(declared_type)
|
|
30
|
+
target_union_args = get_args(target_type)
|
|
31
|
+
for target_member in target_union_args:
|
|
32
|
+
is_compatible = False
|
|
33
|
+
for declared_member in declared_union_args:
|
|
34
|
+
try:
|
|
35
|
+
validate_target_type(declared_member, target_member)
|
|
36
|
+
is_compatible = True
|
|
37
|
+
break
|
|
38
|
+
except TypeValidationError:
|
|
39
|
+
continue
|
|
40
|
+
if not is_compatible:
|
|
41
|
+
# This target member is not compatible with any declared member
|
|
42
|
+
raise TypeValidationError(declared_type, target_type)
|
|
43
|
+
# All target members are compatible with at least one declared member
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
# If declared_type is a Union, target_type must be compatible with at least one union member
|
|
47
|
+
if declared_origin is Union:
|
|
48
|
+
declared_union_args = get_args(declared_type)
|
|
49
|
+
for union_member in declared_union_args:
|
|
50
|
+
try:
|
|
51
|
+
validate_target_type(union_member, target_type)
|
|
52
|
+
# If any union member is compatible, validation passes
|
|
53
|
+
return
|
|
54
|
+
except TypeValidationError:
|
|
55
|
+
# This union member is incompatible, try the next one
|
|
56
|
+
continue
|
|
57
|
+
# None of the union members are compatible with target_type
|
|
58
|
+
raise TypeValidationError(declared_type, target_type)
|
|
59
|
+
|
|
60
|
+
# If target_type is a Union, ALL union members must be compatible with declared_type
|
|
61
|
+
if target_origin is Union:
|
|
62
|
+
target_union_args = get_args(target_type)
|
|
63
|
+
for union_member in target_union_args:
|
|
64
|
+
try:
|
|
65
|
+
validate_target_type(declared_type, union_member)
|
|
66
|
+
except TypeValidationError:
|
|
67
|
+
# At least one union member is incompatible with declared_type
|
|
68
|
+
raise TypeValidationError(declared_type, target_type)
|
|
69
|
+
# All union members are compatible with declared_type
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
# Check for exact type match
|
|
73
|
+
if target_type == declared_type:
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
# Check for subclass relationships
|
|
77
|
+
try:
|
|
78
|
+
if issubclass(target_type, declared_type) or issubclass(declared_type, target_type):
|
|
79
|
+
return
|
|
80
|
+
except TypeError:
|
|
81
|
+
# Handle cases where types aren't classes (e.g., generic types)
|
|
82
|
+
if str(target_type) == str(declared_type):
|
|
83
|
+
return
|
|
84
|
+
|
|
85
|
+
# Check for generic type compatibility
|
|
86
|
+
declared_origin = get_origin(declared_type)
|
|
87
|
+
|
|
88
|
+
if target_origin is None and declared_origin is None:
|
|
89
|
+
# Neither is a generic type, and they don't match
|
|
90
|
+
raise TypeValidationError(declared_type, target_type)
|
|
91
|
+
|
|
92
|
+
if target_origin == declared_type or declared_origin == target_type or target_origin == declared_origin:
|
|
93
|
+
target_args = get_args(target_type)
|
|
94
|
+
declared_args = get_args(declared_type)
|
|
95
|
+
|
|
96
|
+
if len(declared_args) == 0:
|
|
97
|
+
return
|
|
98
|
+
|
|
99
|
+
if len(target_args) != len(declared_args):
|
|
100
|
+
raise TypeValidationError(declared_type, target_type)
|
|
101
|
+
|
|
102
|
+
for target_arg, declared_arg in zip(target_args, declared_args):
|
|
103
|
+
validate_target_type(declared_arg, target_arg)
|
|
104
|
+
|
|
105
|
+
return
|
|
106
|
+
|
|
107
|
+
# If we reach here, types don't match
|
|
108
|
+
raise TypeValidationError(declared_type, target_type)
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
import sys
|
|
1
3
|
import typing
|
|
2
4
|
from typing import Any, List, Tuple, Type, Union, get_args, get_origin
|
|
3
5
|
|
|
4
6
|
from vellum import (
|
|
7
|
+
ArrayChatMessageContentItem,
|
|
5
8
|
ChatMessage,
|
|
6
9
|
ChatMessageRequest,
|
|
7
10
|
FunctionCall,
|
|
@@ -24,7 +27,7 @@ from vellum import (
|
|
|
24
27
|
)
|
|
25
28
|
from vellum.workflows.constants import undefined
|
|
26
29
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
|
27
|
-
from vellum.workflows.types.core import
|
|
30
|
+
from vellum.workflows.types.core import is_json_type
|
|
28
31
|
|
|
29
32
|
|
|
30
33
|
def primitive_type_to_vellum_variable_type(type_: Union[Type, BaseDescriptor]) -> VellumVariableType:
|
|
@@ -46,17 +49,7 @@ def primitive_type_to_vellum_variable_type(type_: Union[Type, BaseDescriptor]) -
|
|
|
46
49
|
return "JSON"
|
|
47
50
|
|
|
48
51
|
if len(types) != 1:
|
|
49
|
-
|
|
50
|
-
# Matches the type found at vellum.workflows.utils.vellum_variables.Json
|
|
51
|
-
actual_types_with_explicit_ref = [
|
|
52
|
-
bool,
|
|
53
|
-
int,
|
|
54
|
-
float,
|
|
55
|
-
str,
|
|
56
|
-
typing.List[Json],
|
|
57
|
-
typing.Dict[str, Json],
|
|
58
|
-
]
|
|
59
|
-
if types == actual_types_with_explicit_ref:
|
|
52
|
+
if is_json_type(types):
|
|
60
53
|
return "JSON"
|
|
61
54
|
# Number now supports float and int
|
|
62
55
|
elif types == [float, int]:
|
|
@@ -66,11 +59,15 @@ def primitive_type_to_vellum_variable_type(type_: Union[Type, BaseDescriptor]) -
|
|
|
66
59
|
if len(collapse_types) == 1:
|
|
67
60
|
return primitive_type_to_vellum_variable_type(collapse_types[0])
|
|
68
61
|
|
|
62
|
+
# Handle Union[str, List[ArrayChatMessageContentItem]] for ChatMessageTrigger.message
|
|
63
|
+
if _is_string_and_array_chat_message_content_union(types):
|
|
64
|
+
return "ARRAY"
|
|
65
|
+
|
|
69
66
|
raise ValueError(f"Expected Descriptor to only have one type, got {types}")
|
|
70
67
|
|
|
71
68
|
type_ = type_.types[0]
|
|
72
69
|
|
|
73
|
-
if
|
|
70
|
+
if _is_type_optionally_in(type_, (str, datetime)):
|
|
74
71
|
return "STRING"
|
|
75
72
|
elif _is_type_optionally_in(type_, (int, float)):
|
|
76
73
|
return "NUMBER"
|
|
@@ -218,8 +215,91 @@ def _builtin_list_to_vellum_type(type_: Type) -> Union[str, None]:
|
|
|
218
215
|
item_type, SearchResultRequest
|
|
219
216
|
):
|
|
220
217
|
return "SEARCH_RESULTS"
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
):
|
|
218
|
+
|
|
219
|
+
if _is_vellum_value_subtype(item_type):
|
|
224
220
|
return "ARRAY"
|
|
221
|
+
|
|
222
|
+
if _is_array_chat_message_content_item(item_type):
|
|
223
|
+
return "ARRAY"
|
|
224
|
+
|
|
225
225
|
return None
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _is_array_chat_message_content_item(type_: Type) -> bool:
|
|
229
|
+
"""Check if the type is ArrayChatMessageContentItem or a union of its subtypes."""
|
|
230
|
+
array_content_item_types = list(typing.get_args(ArrayChatMessageContentItem))
|
|
231
|
+
|
|
232
|
+
origin = get_origin(type_)
|
|
233
|
+
if not origin:
|
|
234
|
+
if isinstance(type_, type):
|
|
235
|
+
return any(issubclass(type_, t) for t in array_content_item_types if isinstance(t, type))
|
|
236
|
+
return False
|
|
237
|
+
|
|
238
|
+
if origin is typing.Union:
|
|
239
|
+
args = get_args(type_)
|
|
240
|
+
return all(_is_array_chat_message_content_item(arg) for arg in args)
|
|
241
|
+
|
|
242
|
+
return type_ == ArrayChatMessageContentItem
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _is_string_and_array_chat_message_content_union(types: List[Type]) -> bool:
|
|
246
|
+
"""Check if types represent Union[str, List[ArrayChatMessageContentItem]]."""
|
|
247
|
+
if len(types) != 2:
|
|
248
|
+
return False
|
|
249
|
+
|
|
250
|
+
has_str = str in types
|
|
251
|
+
has_list_array_content = any(
|
|
252
|
+
get_origin(t) in (list, typing.List)
|
|
253
|
+
and len(get_args(t)) == 1
|
|
254
|
+
and _is_array_chat_message_content_item(get_args(t)[0])
|
|
255
|
+
for t in types
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
return has_str and has_list_array_content
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _is_vellum_value_subtype(type_: Type) -> bool:
|
|
262
|
+
# This logic is here primarily for `ArrayVellumValue`, which is defined recursively.
|
|
263
|
+
# At class definition time, we invoke some Pydantic helpers to resolve its forward references.
|
|
264
|
+
vellum_value_types = [
|
|
265
|
+
(
|
|
266
|
+
t.__forward_value__
|
|
267
|
+
if isinstance(t, typing.ForwardRef) and t.__forward_evaluated__ and t.__forward_value__ is not None
|
|
268
|
+
else t
|
|
269
|
+
)
|
|
270
|
+
for t in typing.get_args(VellumValue)
|
|
271
|
+
]
|
|
272
|
+
origin = get_origin(type_)
|
|
273
|
+
if not origin:
|
|
274
|
+
if isinstance(type_, type):
|
|
275
|
+
return any(issubclass(type_, vellum_value_type) for vellum_value_type in vellum_value_types)
|
|
276
|
+
elif isinstance(type_, typing.ForwardRef):
|
|
277
|
+
# If the forward ref hasn't been resolved yet, do the simple stupid thing and
|
|
278
|
+
# assume it's not a VellumValue subtype.
|
|
279
|
+
# This means user-defined types should use the fully resolved types!
|
|
280
|
+
if not type_.__forward_evaluated__ or type_.__forward_value__ is None:
|
|
281
|
+
return False
|
|
282
|
+
|
|
283
|
+
type_ = type_.__forward_value__
|
|
284
|
+
if isinstance(type_, type):
|
|
285
|
+
return any(issubclass(type_, vellum_value_type) for vellum_value_type in vellum_value_types)
|
|
286
|
+
else:
|
|
287
|
+
return False
|
|
288
|
+
else:
|
|
289
|
+
return False
|
|
290
|
+
|
|
291
|
+
if sys.version_info >= (3, 10) and sys.version_info < (3, 14):
|
|
292
|
+
# See https://docs.python.org/3/library/types.html#types.UnionType.
|
|
293
|
+
# In Python 3.10, `types.UnionType` was introduced to support X | Y union type expressions.
|
|
294
|
+
# In Python 3.14, `types.UnionType` is just an alias for `typing.Union`.
|
|
295
|
+
from types import UnionType
|
|
296
|
+
|
|
297
|
+
union_types = (typing.Union, UnionType)
|
|
298
|
+
else:
|
|
299
|
+
union_types = (typing.Union,)
|
|
300
|
+
|
|
301
|
+
if origin in union_types:
|
|
302
|
+
args = get_args(type_)
|
|
303
|
+
return all(_is_vellum_value_subtype(arg) for arg in args)
|
|
304
|
+
|
|
305
|
+
return False
|