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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pytest
|
|
2
|
+
from unittest.mock import patch
|
|
2
3
|
from uuid import UUID, uuid4
|
|
3
4
|
from typing import List
|
|
4
5
|
|
|
@@ -8,11 +9,15 @@ from vellum.workflows.inputs import BaseInputs
|
|
|
8
9
|
from vellum.workflows.nodes.bases import BaseNode
|
|
9
10
|
from vellum.workflows.outputs import BaseOutputs
|
|
10
11
|
from vellum.workflows.references import LazyReference
|
|
11
|
-
from
|
|
12
|
+
from vellum.workflows.references.state_value import StateValueReference
|
|
13
|
+
from vellum.workflows.references.trigger import TriggerAttributeReference
|
|
14
|
+
from vellum.workflows.state import BaseState
|
|
15
|
+
from vellum.workflows.triggers.base import BaseTrigger
|
|
16
|
+
from vellum_ee.workflows.display.base import StateValueDisplay, WorkflowInputsDisplay, WorkflowMetaDisplay
|
|
12
17
|
from vellum_ee.workflows.display.editor.types import NodeDisplayData
|
|
13
18
|
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
|
14
19
|
from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
|
|
15
|
-
from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input_value_pointer_rules
|
|
20
|
+
from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input, create_node_input_value_pointer_rules
|
|
16
21
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
|
17
22
|
from vellum_ee.workflows.display.utils.vellum import (
|
|
18
23
|
ConstantValuePointer,
|
|
@@ -21,6 +26,11 @@ from vellum_ee.workflows.display.utils.vellum import (
|
|
|
21
26
|
NodeInputValuePointerRule,
|
|
22
27
|
NodeOutputData,
|
|
23
28
|
NodeOutputPointer,
|
|
29
|
+
TriggerAttributeData,
|
|
30
|
+
TriggerAttributePointer,
|
|
31
|
+
WorkflowStateData,
|
|
32
|
+
WorkflowStatePointer,
|
|
33
|
+
create_node_input_value_pointer_rule,
|
|
24
34
|
)
|
|
25
35
|
from vellum_ee.workflows.display.workflows.base_workflow_display import BaseWorkflowDisplay
|
|
26
36
|
|
|
@@ -129,5 +139,100 @@ def test_create_node_input_value_pointer_rules(
|
|
|
129
139
|
MyNodeA: MyNodeADisplay(),
|
|
130
140
|
},
|
|
131
141
|
),
|
|
142
|
+
uuid4(),
|
|
132
143
|
)
|
|
133
144
|
assert rules == expected_rules
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class MyState(BaseState):
|
|
148
|
+
my_attribute: str
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_create_node_input_value_pointer_rule__state_value_reference() -> None:
|
|
152
|
+
"""
|
|
153
|
+
Tests that StateValueReference is serialized to WorkflowStatePointer using the display override ID.
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
# GIVEN a StateValueReference
|
|
157
|
+
state_value_reference: StateValueReference[str] = MyState.my_attribute # type: ignore[assignment]
|
|
158
|
+
|
|
159
|
+
# AND a display context with a state value display override
|
|
160
|
+
override_id = uuid4()
|
|
161
|
+
display_context = WorkflowDisplayContext(
|
|
162
|
+
global_state_value_displays={
|
|
163
|
+
state_value_reference: StateValueDisplay(id=override_id),
|
|
164
|
+
},
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
# WHEN we create a node input value pointer rule
|
|
168
|
+
result = create_node_input_value_pointer_rule(state_value_reference, display_context)
|
|
169
|
+
|
|
170
|
+
# THEN we should get a WorkflowStatePointer with the overridden display ID
|
|
171
|
+
assert isinstance(result, WorkflowStatePointer)
|
|
172
|
+
assert result.type == "WORKFLOW_STATE"
|
|
173
|
+
assert isinstance(result.data, WorkflowStateData)
|
|
174
|
+
assert result.data.state_variable_id == str(override_id)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class MyTrigger(BaseTrigger):
|
|
178
|
+
my_attribute: str
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_create_node_input_value_pointer_rule__trigger_attribute_reference() -> None:
|
|
182
|
+
"""
|
|
183
|
+
Tests that TriggerAttributeReference is serialized to TriggerAttributePointer.
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
# GIVEN a TriggerAttributeReference
|
|
187
|
+
trigger_attribute_reference: TriggerAttributeReference[str] = MyTrigger.my_attribute # type: ignore[assignment]
|
|
188
|
+
|
|
189
|
+
# AND a display context
|
|
190
|
+
display_context = WorkflowDisplayContext()
|
|
191
|
+
|
|
192
|
+
# WHEN we create a node input value pointer rule
|
|
193
|
+
result = create_node_input_value_pointer_rule(trigger_attribute_reference, display_context)
|
|
194
|
+
|
|
195
|
+
# THEN we should get a TriggerAttributePointer with the correct data
|
|
196
|
+
assert isinstance(result, TriggerAttributePointer)
|
|
197
|
+
assert result.type == "TRIGGER_ATTRIBUTE"
|
|
198
|
+
assert isinstance(result.data, TriggerAttributeData)
|
|
199
|
+
assert result.data.trigger_id == str(MyTrigger.__id__)
|
|
200
|
+
assert result.data.attribute_id == str(trigger_attribute_reference.id)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def test_create_node_input__unexpected_error_returns_node_input_with_empty_rules() -> None:
|
|
204
|
+
"""
|
|
205
|
+
Tests that when create_node_input_value_pointer_rules raises an unexpected error,
|
|
206
|
+
create_node_input still returns a NodeInput with empty rules and adds the error to display context.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
# GIVEN a display context
|
|
210
|
+
display_context = WorkflowDisplayContext()
|
|
211
|
+
|
|
212
|
+
# AND a node_id and input_name
|
|
213
|
+
node_id = uuid4()
|
|
214
|
+
input_name = "test_input"
|
|
215
|
+
|
|
216
|
+
# AND create_node_input_value_pointer_rules will raise an unexpected error
|
|
217
|
+
unexpected_error = RuntimeError("Unexpected error during serialization")
|
|
218
|
+
with patch(
|
|
219
|
+
"vellum_ee.workflows.display.nodes.vellum.utils.create_node_input_value_pointer_rules",
|
|
220
|
+
side_effect=unexpected_error,
|
|
221
|
+
):
|
|
222
|
+
# WHEN we call create_node_input
|
|
223
|
+
result = create_node_input(
|
|
224
|
+
node_id=node_id,
|
|
225
|
+
input_name=input_name,
|
|
226
|
+
value="test_value",
|
|
227
|
+
display_context=display_context,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# THEN we should still get a NodeInput with empty rules
|
|
231
|
+
assert result.key == input_name
|
|
232
|
+
assert result.value.rules == []
|
|
233
|
+
assert result.value.combinator == "OR"
|
|
234
|
+
|
|
235
|
+
# AND the error should be added to the display context
|
|
236
|
+
errors = list(display_context.errors)
|
|
237
|
+
assert len(errors) == 1
|
|
238
|
+
assert errors[0] is unexpected_error
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from uuid import UUID
|
|
2
3
|
from typing import Any, List, Optional, Type, Union, cast
|
|
3
4
|
|
|
5
|
+
from vellum.client.types.json_vellum_value import JsonVellumValue
|
|
4
6
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
|
5
7
|
from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
|
|
6
8
|
from vellum.workflows.nodes.displayable.bases.utils import primitive_to_vellum_value
|
|
@@ -8,8 +10,12 @@ from vellum.workflows.references import NodeReference
|
|
|
8
10
|
from vellum.workflows.references.lazy import LazyReference
|
|
9
11
|
from vellum.workflows.utils.uuids import uuid4_from_hash
|
|
10
12
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
|
11
|
-
from vellum_ee.workflows.display.utils.exceptions import
|
|
12
|
-
|
|
13
|
+
from vellum_ee.workflows.display.utils.exceptions import (
|
|
14
|
+
InvalidOutputReferenceError,
|
|
15
|
+
UnsupportedSerializationException,
|
|
16
|
+
UserFacingException,
|
|
17
|
+
)
|
|
18
|
+
from vellum_ee.workflows.display.utils.expressions import get_child_descriptor, serialize_value
|
|
13
19
|
from vellum_ee.workflows.display.utils.vellum import (
|
|
14
20
|
ConstantValuePointer,
|
|
15
21
|
ExecutionCounterData,
|
|
@@ -23,6 +29,8 @@ from vellum_ee.workflows.display.utils.vellum import (
|
|
|
23
29
|
)
|
|
24
30
|
from vellum_ee.workflows.display.vellum import NodeInput, NodeInputValuePointer
|
|
25
31
|
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
26
34
|
|
|
27
35
|
def create_node_input(
|
|
28
36
|
node_id: UUID,
|
|
@@ -33,7 +41,13 @@ def create_node_input(
|
|
|
33
41
|
pointer_type: Optional[Type[NodeInputValuePointerRule]] = ConstantValuePointer,
|
|
34
42
|
) -> NodeInput:
|
|
35
43
|
input_id = str(input_id) if input_id else str(uuid4_from_hash(f"{node_id}|{input_name}"))
|
|
36
|
-
|
|
44
|
+
try:
|
|
45
|
+
rules = create_node_input_value_pointer_rules(value, display_context, node_id, pointer_type=pointer_type)
|
|
46
|
+
except UserFacingException:
|
|
47
|
+
raise
|
|
48
|
+
except Exception as e:
|
|
49
|
+
display_context.add_validation_error(e)
|
|
50
|
+
rules = []
|
|
37
51
|
return NodeInput(
|
|
38
52
|
id=input_id,
|
|
39
53
|
key=input_name,
|
|
@@ -44,9 +58,21 @@ def create_node_input(
|
|
|
44
58
|
)
|
|
45
59
|
|
|
46
60
|
|
|
61
|
+
def _contains_descriptor(value: Any) -> bool:
|
|
62
|
+
"""Check if a value contains any BaseDescriptor objects."""
|
|
63
|
+
if isinstance(value, BaseDescriptor):
|
|
64
|
+
return True
|
|
65
|
+
if isinstance(value, dict):
|
|
66
|
+
return any(_contains_descriptor(v) for v in value.values())
|
|
67
|
+
if isinstance(value, list):
|
|
68
|
+
return any(_contains_descriptor(item) for item in value)
|
|
69
|
+
return False
|
|
70
|
+
|
|
71
|
+
|
|
47
72
|
def create_node_input_value_pointer_rules(
|
|
48
73
|
value: Any,
|
|
49
74
|
display_context: WorkflowDisplayContext,
|
|
75
|
+
node_id: UUID,
|
|
50
76
|
existing_rules: Optional[List[NodeInputValuePointerRule]] = None,
|
|
51
77
|
pointer_type: Optional[Type[NodeInputValuePointerRule]] = None,
|
|
52
78
|
) -> List[NodeInputValuePointerRule]:
|
|
@@ -59,33 +85,49 @@ def create_node_input_value_pointer_rules(
|
|
|
59
85
|
value = cast(BaseDescriptor, value.instance)
|
|
60
86
|
|
|
61
87
|
if isinstance(value, LazyReference):
|
|
62
|
-
|
|
88
|
+
try:
|
|
89
|
+
child_descriptor = get_child_descriptor(value, display_context)
|
|
90
|
+
except InvalidOutputReferenceError as e:
|
|
91
|
+
logger.warning("Failed to parse lazy reference '%s', skipping serialization", value.name)
|
|
92
|
+
display_context.add_validation_error(e)
|
|
93
|
+
return node_input_value_pointer_rules
|
|
63
94
|
return create_node_input_value_pointer_rules(
|
|
64
|
-
child_descriptor, display_context, [], pointer_type=pointer_type
|
|
95
|
+
child_descriptor, display_context, node_id, existing_rules=[], pointer_type=pointer_type
|
|
65
96
|
)
|
|
66
97
|
|
|
67
98
|
if isinstance(value, CoalesceExpression):
|
|
68
|
-
|
|
69
|
-
|
|
99
|
+
lhs_rules = create_node_input_value_pointer_rules(
|
|
100
|
+
value.lhs, display_context, node_id, existing_rules=[], pointer_type=pointer_type
|
|
101
|
+
)
|
|
70
102
|
node_input_value_pointer_rules.extend(lhs_rules)
|
|
71
103
|
|
|
72
|
-
# Handle the right-hand side
|
|
73
104
|
if not isinstance(value.rhs, CoalesceExpression):
|
|
74
105
|
rhs_rules = create_node_input_value_pointer_rules(
|
|
75
|
-
value.rhs, display_context, [], pointer_type=pointer_type
|
|
106
|
+
value.rhs, display_context, node_id, existing_rules=[], pointer_type=pointer_type
|
|
76
107
|
)
|
|
77
108
|
node_input_value_pointer_rules.extend(rhs_rules)
|
|
78
109
|
else:
|
|
79
|
-
# Non-CoalesceExpression case
|
|
80
110
|
try:
|
|
81
111
|
rule = create_node_input_value_pointer_rule(value, display_context)
|
|
82
112
|
except UnsupportedSerializationException:
|
|
83
113
|
return node_input_value_pointer_rules
|
|
84
114
|
|
|
85
115
|
node_input_value_pointer_rules.append(rule)
|
|
116
|
+
elif isinstance(value, (dict, list)) and _contains_descriptor(value):
|
|
117
|
+
display_context.add_validation_error(
|
|
118
|
+
UnsupportedSerializationException(
|
|
119
|
+
"The Vellum UI does not support nested references for this Node attribute. "
|
|
120
|
+
"Consider flattening the references."
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
serialized = serialize_value(node_id, display_context, value)
|
|
124
|
+
serialized_pointer = ConstantValuePointer(
|
|
125
|
+
data=JsonVellumValue(value=serialized),
|
|
126
|
+
)
|
|
127
|
+
node_input_value_pointer_rules.append(serialized_pointer)
|
|
86
128
|
else:
|
|
87
|
-
|
|
88
|
-
node_input_value_pointer_rules.append(
|
|
129
|
+
constant_pointer = create_pointer(value, pointer_type)
|
|
130
|
+
node_input_value_pointer_rules.append(constant_pointer)
|
|
89
131
|
|
|
90
132
|
return node_input_value_pointer_rules
|
|
91
133
|
|
|
@@ -92,6 +92,7 @@ def test_vellum_workflow_display__serialize_input_variables_with_capitalized_var
|
|
|
92
92
|
"default": None,
|
|
93
93
|
"required": True,
|
|
94
94
|
"extensions": {"color": None},
|
|
95
|
+
"schema": {"type": "string"},
|
|
95
96
|
}
|
|
96
97
|
]
|
|
97
98
|
|
|
@@ -129,24 +130,19 @@ def test_vellum_workflow_display_serialize_valid_handle_ids_for_base_nodes():
|
|
|
129
130
|
edge_source_handle_ids = {edge.get("source_handle_id") for edge in edges if isinstance(edge, dict)}
|
|
130
131
|
edge_target_handle_ids = {edge.get("target_handle_id") for edge in edges if isinstance(edge, dict)}
|
|
131
132
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
start_node = next(
|
|
134
|
+
node for node in nodes if isinstance(node, dict) and node["type"] == "GENERIC" and node["label"] == "Start Node"
|
|
135
|
+
)
|
|
136
|
+
end_node = next(
|
|
137
|
+
node for node in nodes if isinstance(node, dict) and node["type"] == "GENERIC" and node["label"] == "End Node"
|
|
138
|
+
)
|
|
137
139
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
assert isinstance(port, dict)
|
|
142
|
-
assert (
|
|
143
|
-
port["id"] in edge_source_handle_ids
|
|
144
|
-
), f"Port {port['id']} from node {node['label']} not found in edge source handle ids"
|
|
140
|
+
assert isinstance(start_node["ports"], list)
|
|
141
|
+
assert isinstance(start_node["ports"][0], dict)
|
|
142
|
+
assert start_node["ports"][0]["id"] in edge_source_handle_ids
|
|
145
143
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
node["trigger"]["id"] in edge_target_handle_ids
|
|
149
|
-
), f"Trigger {node['trigger']['id']} from node {node['label']} not found in edge target handle ids"
|
|
144
|
+
assert isinstance(end_node["trigger"], dict)
|
|
145
|
+
assert end_node["trigger"]["id"] in edge_target_handle_ids
|
|
150
146
|
|
|
151
147
|
|
|
152
148
|
def test_vellum_workflow_display__serialize_with_unused_nodes_and_edges():
|
|
@@ -280,6 +276,7 @@ def test_vellum_workflow_display__serialize_with_parse_json_expression():
|
|
|
280
276
|
"id": "e73fd6b1-1109-4a97-8510-c9ba8e6f5dbe",
|
|
281
277
|
"name": "json_result",
|
|
282
278
|
"type": "JSON",
|
|
279
|
+
"schema": {},
|
|
283
280
|
"value": {
|
|
284
281
|
"type": "UNARY_EXPRESSION",
|
|
285
282
|
"lhs": {
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for JSON schema validation in InlinePromptNode during serialization.
|
|
3
|
+
|
|
4
|
+
This uses the jsonschema library to validate schemas against the JSON Schema meta-schema.
|
|
5
|
+
The validation is spec-compliant, meaning some schemas that might seem incomplete
|
|
6
|
+
(like arrays without items) are valid according to the JSON Schema specification.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
import jsonschema
|
|
12
|
+
|
|
13
|
+
from vellum import PromptParameters
|
|
14
|
+
from vellum.workflows.nodes import InlinePromptNode
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.mark.parametrize(
|
|
18
|
+
"json_schema",
|
|
19
|
+
[
|
|
20
|
+
pytest.param(
|
|
21
|
+
{"type": "object", "properties": "invalid"},
|
|
22
|
+
id="object with non-dict properties",
|
|
23
|
+
),
|
|
24
|
+
pytest.param(
|
|
25
|
+
{"anyOf": {"type": "string"}},
|
|
26
|
+
id="anyOf not list",
|
|
27
|
+
),
|
|
28
|
+
pytest.param(
|
|
29
|
+
{"type": "object", "properties": {"name": "string"}},
|
|
30
|
+
id="object with non-schema property value",
|
|
31
|
+
),
|
|
32
|
+
],
|
|
33
|
+
)
|
|
34
|
+
def test_inline_prompt_node_validation__invalid_schemas_raise_error(
|
|
35
|
+
json_schema: dict,
|
|
36
|
+
) -> None:
|
|
37
|
+
"""
|
|
38
|
+
Tests that InlinePromptNode validation rejects structurally invalid JSON Schemas.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
# GIVEN an InlinePromptNode configured with an invalid JSON Schema
|
|
42
|
+
class MyPromptNode(InlinePromptNode):
|
|
43
|
+
ml_model = "gpt-4"
|
|
44
|
+
blocks = []
|
|
45
|
+
parameters = PromptParameters(custom_parameters={"json_schema": json_schema})
|
|
46
|
+
|
|
47
|
+
# WHEN we call __validate__ on the node
|
|
48
|
+
# THEN it should raise a SchemaError
|
|
49
|
+
with pytest.raises(jsonschema.exceptions.SchemaError):
|
|
50
|
+
MyPromptNode.__validate__()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@pytest.mark.parametrize(
|
|
54
|
+
"json_schema",
|
|
55
|
+
[
|
|
56
|
+
pytest.param(
|
|
57
|
+
{"type": "array"},
|
|
58
|
+
id="array without items (valid per JSON Schema spec)",
|
|
59
|
+
),
|
|
60
|
+
pytest.param(
|
|
61
|
+
{
|
|
62
|
+
"type": "array",
|
|
63
|
+
"prefixItems": [{"type": "string"}, {"type": "number"}],
|
|
64
|
+
},
|
|
65
|
+
id="array with prefixItems only",
|
|
66
|
+
),
|
|
67
|
+
pytest.param(
|
|
68
|
+
{"type": "array", "items": {"type": "string"}},
|
|
69
|
+
id="valid array with items",
|
|
70
|
+
),
|
|
71
|
+
pytest.param(
|
|
72
|
+
{"type": "array", "items": {}},
|
|
73
|
+
id="array with empty items object",
|
|
74
|
+
),
|
|
75
|
+
pytest.param(
|
|
76
|
+
{"type": "array", "prefixItems": []},
|
|
77
|
+
id="array with empty prefixItems",
|
|
78
|
+
),
|
|
79
|
+
pytest.param(
|
|
80
|
+
{
|
|
81
|
+
"type": "array",
|
|
82
|
+
"prefixItems": [{"type": "string"}],
|
|
83
|
+
"items": {"type": "number"},
|
|
84
|
+
},
|
|
85
|
+
id="array with both items and prefixItems",
|
|
86
|
+
),
|
|
87
|
+
pytest.param(
|
|
88
|
+
{
|
|
89
|
+
"type": "array",
|
|
90
|
+
"prefixItems": [{"type": "array", "items": {"type": "string"}}],
|
|
91
|
+
},
|
|
92
|
+
id="valid nested array in prefixItems",
|
|
93
|
+
),
|
|
94
|
+
pytest.param(
|
|
95
|
+
{
|
|
96
|
+
"type": "array",
|
|
97
|
+
"items": [
|
|
98
|
+
{"type": "string"},
|
|
99
|
+
{"type": "array", "items": {"type": "number"}},
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
id="valid nested array in list-valued items",
|
|
103
|
+
),
|
|
104
|
+
pytest.param(
|
|
105
|
+
{
|
|
106
|
+
"type": "object",
|
|
107
|
+
"properties": {
|
|
108
|
+
"name": {"type": "string"},
|
|
109
|
+
"age": {"type": "number"},
|
|
110
|
+
"tags": {"type": "array", "items": {"type": "string"}},
|
|
111
|
+
"address": {
|
|
112
|
+
"type": "object",
|
|
113
|
+
"properties": {
|
|
114
|
+
"street": {"type": "string"},
|
|
115
|
+
"city": {"type": "string"},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
"anyOf": [{"required": ["name"]}, {"required": ["age"]}],
|
|
120
|
+
},
|
|
121
|
+
id="valid complex object schema with anyOf",
|
|
122
|
+
),
|
|
123
|
+
pytest.param(
|
|
124
|
+
{
|
|
125
|
+
"name": "match_scorer_schema",
|
|
126
|
+
"schema": {
|
|
127
|
+
"type": "object",
|
|
128
|
+
"title": "MatchScorerSchema",
|
|
129
|
+
"required": ["recommendation", "score", "remarks"],
|
|
130
|
+
"properties": {
|
|
131
|
+
"score": {
|
|
132
|
+
"type": "integer",
|
|
133
|
+
"title": "Match Score",
|
|
134
|
+
"description": "Match score out of 10",
|
|
135
|
+
},
|
|
136
|
+
"remarks": {
|
|
137
|
+
"type": "string",
|
|
138
|
+
"title": "Remarks",
|
|
139
|
+
},
|
|
140
|
+
"recommendation": {
|
|
141
|
+
"enum": ["Advance", "Defer", "Reject"],
|
|
142
|
+
"type": "string",
|
|
143
|
+
"title": "Status",
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
id="wrapper with valid nested schema",
|
|
149
|
+
),
|
|
150
|
+
pytest.param(
|
|
151
|
+
{"type": "array", "items": True},
|
|
152
|
+
id="array with boolean items (valid per JSON Schema spec)",
|
|
153
|
+
),
|
|
154
|
+
pytest.param(
|
|
155
|
+
{"anyOf": [True, {"type": "string"}]},
|
|
156
|
+
id="anyOf with boolean element (valid per JSON Schema spec)",
|
|
157
|
+
),
|
|
158
|
+
],
|
|
159
|
+
)
|
|
160
|
+
def test_inline_prompt_node_validation__valid_schemas_succeed(
|
|
161
|
+
json_schema: dict,
|
|
162
|
+
) -> None:
|
|
163
|
+
"""
|
|
164
|
+
Tests that InlinePromptNode validation accepts structurally valid JSON Schemas.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
# GIVEN an InlinePromptNode configured with a valid JSON Schema
|
|
168
|
+
class MyPromptNode(InlinePromptNode):
|
|
169
|
+
ml_model = "gpt-4"
|
|
170
|
+
blocks = []
|
|
171
|
+
parameters = PromptParameters(custom_parameters={"json_schema": json_schema})
|
|
172
|
+
|
|
173
|
+
# WHEN we call __validate__ on the node
|
|
174
|
+
# THEN it should not raise an error
|
|
175
|
+
MyPromptNode.__validate__()
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def test_inline_prompt_node_validation__no_json_schema__succeeds():
|
|
179
|
+
"""
|
|
180
|
+
Tests that InlinePromptNode without json_schema passes validation.
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
# GIVEN an InlinePromptNode that has no json_schema
|
|
184
|
+
class MyPromptNode(InlinePromptNode):
|
|
185
|
+
ml_model = "gpt-4"
|
|
186
|
+
blocks = []
|
|
187
|
+
|
|
188
|
+
# WHEN we call __validate__() on the node
|
|
189
|
+
# THEN it should not raise any errors
|
|
190
|
+
MyPromptNode.__validate__()
|