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/nodes/mocks.py
CHANGED
|
@@ -1,108 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
from
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Literal, Optional, Sequence, Type, Union
|
|
1
|
+
import logging
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Sequence, Type, Union
|
|
4
3
|
|
|
5
4
|
from pydantic import ConfigDict, SerializationInfo, ValidationError, field_serializer, model_serializer
|
|
6
5
|
|
|
7
6
|
from vellum.client.core.pydantic_utilities import UniversalBaseModel
|
|
8
7
|
from vellum.client.types.array_vellum_value import ArrayVellumValue
|
|
9
|
-
from vellum.client.types.vellum_value import VellumValue
|
|
10
8
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
|
11
9
|
from vellum.workflows.errors.types import WorkflowErrorCode
|
|
12
10
|
from vellum.workflows.events.types import default_serializer
|
|
13
|
-
from vellum.workflows.exceptions import WorkflowInitializationException
|
|
11
|
+
from vellum.workflows.exceptions import NodeException, WorkflowInitializationException
|
|
12
|
+
from vellum.workflows.nodes.utils import get_unadorned_node
|
|
14
13
|
from vellum.workflows.outputs.base import BaseOutputs
|
|
15
14
|
from vellum.workflows.references.constant import ConstantValueReference
|
|
16
15
|
|
|
17
16
|
if TYPE_CHECKING:
|
|
18
17
|
from vellum.workflows import BaseWorkflow
|
|
19
18
|
|
|
20
|
-
import logging
|
|
21
|
-
|
|
22
19
|
logger = logging.getLogger(__name__)
|
|
23
20
|
|
|
24
21
|
|
|
25
|
-
class _RawLogicalCondition(UniversalBaseModel):
|
|
26
|
-
type: Literal["LOGICAL_CONDITION"] = "LOGICAL_CONDITION"
|
|
27
|
-
lhs_variable_id: UUID
|
|
28
|
-
operator: Literal["==", ">", ">=", "<", "<=", "!="]
|
|
29
|
-
rhs_variable_id: UUID
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class _RawLogicalConditionGroup(UniversalBaseModel):
|
|
33
|
-
type: Literal["LOGICAL_CONDITION_GROUP"] = "LOGICAL_CONDITION_GROUP"
|
|
34
|
-
conditions: List["_RawLogicalExpression"]
|
|
35
|
-
combinator: Literal["AND", "OR"]
|
|
36
|
-
negated: bool
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
_RawLogicalExpression = Union[_RawLogicalCondition, _RawLogicalConditionGroup]
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class _RawLogicalExpressionVariable(UniversalBaseModel):
|
|
43
|
-
id: UUID
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class _RawMockWorkflowNodeExecutionConstantValuePointer(_RawLogicalExpressionVariable):
|
|
47
|
-
type: Literal["CONSTANT_VALUE"] = "CONSTANT_VALUE"
|
|
48
|
-
variable_value: VellumValue
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class _RawMockWorkflowNodeExecutionNodeExecutionCounterPointer(_RawLogicalExpressionVariable):
|
|
52
|
-
type: Literal["EXECUTION_COUNTER"] = "EXECUTION_COUNTER"
|
|
53
|
-
node_id: UUID
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
class _RawMockWorkflowNodeExecutionInputVariablePointer(_RawLogicalExpressionVariable):
|
|
57
|
-
type: Literal["INPUT_VARIABLE"] = "INPUT_VARIABLE"
|
|
58
|
-
input_variable_id: UUID
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
class _RawMockWorkflowNodeExecutionNodeOutputPointer(_RawLogicalExpressionVariable):
|
|
62
|
-
type: Literal["NODE_OUTPUT"] = "NODE_OUTPUT"
|
|
63
|
-
node_id: UUID
|
|
64
|
-
input_id: UUID
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class _RawMockWorkflowNodeExecutionNodeInputPointer(_RawLogicalExpressionVariable):
|
|
68
|
-
type: Literal["NODE_INPUT"] = "NODE_INPUT"
|
|
69
|
-
node_id: UUID
|
|
70
|
-
input_id: UUID
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
_RawMockWorkflowNodeExecutionValuePointer = Union[
|
|
74
|
-
_RawMockWorkflowNodeExecutionConstantValuePointer,
|
|
75
|
-
_RawMockWorkflowNodeExecutionNodeExecutionCounterPointer,
|
|
76
|
-
_RawMockWorkflowNodeExecutionInputVariablePointer,
|
|
77
|
-
_RawMockWorkflowNodeExecutionNodeOutputPointer,
|
|
78
|
-
_RawMockWorkflowNodeExecutionNodeInputPointer,
|
|
79
|
-
]
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
class _RawMockWorkflowNodeWhenCondition(UniversalBaseModel):
|
|
83
|
-
expression: _RawLogicalExpression
|
|
84
|
-
variables: List[_RawMockWorkflowNodeExecutionValuePointer]
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
class _RawMockWorkflowNodeThenOutput(UniversalBaseModel):
|
|
88
|
-
output_id: UUID
|
|
89
|
-
value: _RawMockWorkflowNodeExecutionValuePointer
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
class _RawMockWorkflowNodeExecution(UniversalBaseModel):
|
|
93
|
-
when_condition: _RawMockWorkflowNodeWhenCondition
|
|
94
|
-
then_outputs: List[_RawMockWorkflowNodeThenOutput]
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
class _RawMockWorkflowNodeConfig(UniversalBaseModel):
|
|
98
|
-
type: Literal["WORKFLOW_NODE_OUTPUT"] = "WORKFLOW_NODE_OUTPUT"
|
|
99
|
-
node_id: UUID
|
|
100
|
-
mock_executions: List[_RawMockWorkflowNodeExecution]
|
|
101
|
-
|
|
102
|
-
|
|
103
22
|
class MockNodeExecution(UniversalBaseModel):
|
|
104
23
|
when_condition: BaseDescriptor
|
|
105
24
|
then_outputs: BaseOutputs
|
|
25
|
+
disabled: Optional[bool] = None
|
|
106
26
|
|
|
107
27
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
|
108
28
|
|
|
@@ -110,7 +30,12 @@ class MockNodeExecution(UniversalBaseModel):
|
|
|
110
30
|
def serialize_full_model(self, handler: Callable[[Any], Any], info: SerializationInfo) -> Dict[str, Any]:
|
|
111
31
|
"""Serialize the model and add node_id field computed from then_outputs."""
|
|
112
32
|
serialized = handler(self)
|
|
113
|
-
|
|
33
|
+
node_class = self.then_outputs.__class__.__parent_class__
|
|
34
|
+
unadorned_node = get_unadorned_node(node_class) # type: ignore[arg-type]
|
|
35
|
+
serialized["node_id"] = str(unadorned_node.__id__)
|
|
36
|
+
serialized["type"] = "NODE_EXECUTION"
|
|
37
|
+
if self.disabled is None:
|
|
38
|
+
del serialized["disabled"]
|
|
114
39
|
return serialized
|
|
115
40
|
|
|
116
41
|
@field_serializer("then_outputs")
|
|
@@ -129,145 +54,54 @@ class MockNodeExecution(UniversalBaseModel):
|
|
|
129
54
|
def validate_all(
|
|
130
55
|
raw_mock_workflow_node_configs: Optional[List[Any]],
|
|
131
56
|
workflow: Type["BaseWorkflow"],
|
|
57
|
+
descriptor_validator: Optional[Callable[[dict, Type["BaseWorkflow"]], BaseDescriptor]] = None,
|
|
132
58
|
) -> Optional[List["MockNodeExecution"]]:
|
|
133
59
|
if not raw_mock_workflow_node_configs:
|
|
134
60
|
return None
|
|
135
61
|
|
|
136
62
|
ArrayVellumValue.model_rebuild()
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
for raw_mock_workflow_node_config in raw_mock_workflow_node_configs
|
|
141
|
-
]
|
|
142
|
-
except ValidationError as e:
|
|
143
|
-
raise WorkflowInitializationException(
|
|
144
|
-
message="Failed to validate mock node executions",
|
|
145
|
-
code=WorkflowErrorCode.INVALID_INPUTS,
|
|
146
|
-
workflow_definition=workflow,
|
|
147
|
-
) from e
|
|
148
|
-
|
|
149
|
-
nodes = {node.__id__: node for node in workflow.get_nodes()}
|
|
150
|
-
node_output_name_by_id = {
|
|
151
|
-
node.__output_ids__[output.name]: output.name for node in workflow.get_nodes() for output in node.Outputs
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
# We need to support the old way that the Vellum App's WorkflowRunner used to define Node Mocks in order to
|
|
155
|
-
# avoid needing to update the mock resolution strategy that it and the frontend uses. The path towards
|
|
156
|
-
# cleaning this up will go as follows:
|
|
157
|
-
# 1. ✅ Release Mock support in SDK-Enabled Workflows
|
|
158
|
-
# 2. ✅ Deprecate Mock support in non-SDK enabled Workflows, encouraging users to migrate to SDK Workflows
|
|
159
|
-
# 3. ✅ Remove the old mock resolution strategy
|
|
160
|
-
# 4. Update this SDK to handle the new mock resolution strategy with WorkflowValueDescriptors
|
|
161
|
-
# 5. Cutover the Vellum App to the new mock resolution strategy
|
|
162
|
-
# 6. Remove the old mock resolution strategy from this SDK
|
|
163
|
-
def _translate_raw_logical_expression(
|
|
164
|
-
raw_logical_expression: _RawLogicalExpression,
|
|
165
|
-
raw_variables: List[_RawMockWorkflowNodeExecutionValuePointer],
|
|
166
|
-
) -> BaseDescriptor:
|
|
167
|
-
if raw_logical_expression.type == "LOGICAL_CONDITION":
|
|
168
|
-
return _translate_raw_logical_condition(raw_logical_expression, raw_variables)
|
|
169
|
-
else:
|
|
170
|
-
return _translate_raw_logical_condition_group(raw_logical_expression, raw_variables)
|
|
171
|
-
|
|
172
|
-
def _translate_raw_logical_condition_group(
|
|
173
|
-
raw_logical_condition_group: _RawLogicalConditionGroup,
|
|
174
|
-
raw_variables: List[_RawMockWorkflowNodeExecutionValuePointer],
|
|
175
|
-
) -> BaseDescriptor:
|
|
176
|
-
if not raw_logical_condition_group.conditions:
|
|
177
|
-
return ConstantValueReference(True)
|
|
178
|
-
|
|
179
|
-
conditions = [
|
|
180
|
-
_translate_raw_logical_expression(condition, raw_variables)
|
|
181
|
-
for condition in raw_logical_condition_group.conditions
|
|
182
|
-
]
|
|
183
|
-
return reduce(
|
|
184
|
-
lambda acc, condition: (
|
|
185
|
-
acc and condition if raw_logical_condition_group.combinator == "AND" else acc or condition
|
|
186
|
-
),
|
|
187
|
-
conditions,
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
def _translate_raw_logical_condition(
|
|
191
|
-
raw_logical_condition: _RawLogicalCondition,
|
|
192
|
-
raw_variables: List[_RawMockWorkflowNodeExecutionValuePointer],
|
|
193
|
-
) -> BaseDescriptor:
|
|
194
|
-
variable_by_id = {v.id: v for v in raw_variables}
|
|
195
|
-
lhs = _translate_raw_logical_expression_variable(variable_by_id[raw_logical_condition.lhs_variable_id])
|
|
196
|
-
rhs = _translate_raw_logical_expression_variable(variable_by_id[raw_logical_condition.rhs_variable_id])
|
|
197
|
-
if raw_logical_condition.operator == ">":
|
|
198
|
-
return lhs.greater_than(rhs)
|
|
199
|
-
elif raw_logical_condition.operator == ">=":
|
|
200
|
-
return lhs.greater_than_or_equal_to(rhs)
|
|
201
|
-
elif raw_logical_condition.operator == "<":
|
|
202
|
-
return lhs.less_than(rhs)
|
|
203
|
-
elif raw_logical_condition.operator == "<=":
|
|
204
|
-
return lhs.less_than_or_equal_to(rhs)
|
|
205
|
-
elif raw_logical_condition.operator == "==":
|
|
206
|
-
return lhs.equals(rhs)
|
|
207
|
-
elif raw_logical_condition.operator == "!=":
|
|
208
|
-
return lhs.does_not_equal(rhs)
|
|
209
|
-
else:
|
|
210
|
-
raise WorkflowInitializationException(
|
|
211
|
-
message=f"Unsupported logical operator: {raw_logical_condition.operator}",
|
|
212
|
-
workflow_definition=workflow,
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
def _translate_raw_logical_expression_variable(
|
|
216
|
-
raw_variable: _RawMockWorkflowNodeExecutionValuePointer,
|
|
217
|
-
) -> BaseDescriptor:
|
|
218
|
-
if raw_variable.type == "CONSTANT_VALUE":
|
|
219
|
-
return ConstantValueReference(raw_variable.variable_value.value)
|
|
220
|
-
elif raw_variable.type == "EXECUTION_COUNTER":
|
|
221
|
-
node = nodes[raw_variable.node_id]
|
|
222
|
-
return node.Execution.count
|
|
223
|
-
else:
|
|
63
|
+
mock_node_executions: list[MockNodeExecution] = []
|
|
64
|
+
for raw_mock_workflow_node_config in raw_mock_workflow_node_configs:
|
|
65
|
+
if not isinstance(raw_mock_workflow_node_config, dict):
|
|
224
66
|
raise WorkflowInitializationException(
|
|
225
|
-
message=f"
|
|
67
|
+
message=f"Invalid mock node execution type: {type(raw_mock_workflow_node_config)}",
|
|
68
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
|
226
69
|
workflow_definition=workflow,
|
|
227
70
|
)
|
|
228
71
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
72
|
+
try:
|
|
73
|
+
mock_node_executions.append(
|
|
74
|
+
MockNodeExecution.model_validate(
|
|
75
|
+
raw_mock_workflow_node_config,
|
|
76
|
+
context={
|
|
77
|
+
"workflow": workflow,
|
|
78
|
+
"node_id": raw_mock_workflow_node_config.get("node_id"),
|
|
79
|
+
"descriptor_validator": lambda value: (
|
|
80
|
+
descriptor_validator(value, workflow)
|
|
81
|
+
if descriptor_validator
|
|
82
|
+
else ConstantValueReference(False)
|
|
83
|
+
),
|
|
84
|
+
},
|
|
236
85
|
)
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
resolved_output_reference = _translate_raw_logical_expression_variable(then_output.value)
|
|
249
|
-
if isinstance(resolved_output_reference, ConstantValueReference):
|
|
250
|
-
setattr(
|
|
251
|
-
then_outputs,
|
|
252
|
-
node_output_name,
|
|
253
|
-
resolved_output_reference._value,
|
|
254
|
-
)
|
|
255
|
-
else:
|
|
256
|
-
ref_type = type(resolved_output_reference)
|
|
257
|
-
raise WorkflowInitializationException(
|
|
258
|
-
message=f"Unsupported resolved output reference type: {ref_type}",
|
|
259
|
-
workflow_definition=workflow,
|
|
260
|
-
)
|
|
261
|
-
|
|
262
|
-
mock_node_executions.append(
|
|
263
|
-
MockNodeExecution(
|
|
264
|
-
when_condition=when_condition,
|
|
265
|
-
then_outputs=then_outputs,
|
|
266
|
-
)
|
|
86
|
+
)
|
|
87
|
+
except WorkflowInitializationException as e:
|
|
88
|
+
# If the node is not found in the workflow, skip it with a warning
|
|
89
|
+
node_id = raw_mock_workflow_node_config.get("node_id")
|
|
90
|
+
raw_data = e.raw_data or {}
|
|
91
|
+
if raw_data.get("node_ref") == node_id:
|
|
92
|
+
logger.warning(
|
|
93
|
+
"Skipping mock for node %s: node not found in workflow %s",
|
|
94
|
+
node_id,
|
|
95
|
+
workflow.__name__,
|
|
267
96
|
)
|
|
268
|
-
except Exception as e:
|
|
269
|
-
logger.exception("Failed to validate mock node execution", exc_info=e)
|
|
270
97
|
continue
|
|
98
|
+
raise
|
|
99
|
+
except (ValidationError, NodeException) as e:
|
|
100
|
+
raise WorkflowInitializationException(
|
|
101
|
+
message="Failed to validate mock node executions",
|
|
102
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
|
103
|
+
workflow_definition=workflow,
|
|
104
|
+
) from e
|
|
271
105
|
|
|
272
106
|
return mock_node_executions
|
|
273
107
|
|
|
@@ -1,98 +1,6 @@
|
|
|
1
|
-
import uuid
|
|
2
|
-
|
|
3
|
-
from vellum.client.types.string_vellum_value import StringVellumValue
|
|
4
1
|
from vellum.workflows import BaseWorkflow
|
|
5
|
-
from vellum.workflows.nodes import InlinePromptNode
|
|
6
2
|
from vellum.workflows.nodes.bases.base import BaseNode
|
|
7
3
|
from vellum.workflows.nodes.mocks import MockNodeExecution
|
|
8
|
-
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
|
9
|
-
from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def test_mocks__parse_from_app():
|
|
13
|
-
# GIVEN a PromptNode
|
|
14
|
-
class PromptNode(InlinePromptNode):
|
|
15
|
-
pass
|
|
16
|
-
|
|
17
|
-
# AND a workflow class with that PromptNode
|
|
18
|
-
class MyWorkflow(BaseWorkflow):
|
|
19
|
-
graph = PromptNode
|
|
20
|
-
|
|
21
|
-
# AND a mock workflow node execution from the app
|
|
22
|
-
raw_mock_workflow_node_execution = [
|
|
23
|
-
{
|
|
24
|
-
"type": "WORKFLOW_NODE_OUTPUT",
|
|
25
|
-
"node_id": str(PromptNode.__id__),
|
|
26
|
-
"mock_executions": [
|
|
27
|
-
{
|
|
28
|
-
"when_condition": {
|
|
29
|
-
"expression": {
|
|
30
|
-
"type": "LOGICAL_CONDITION_GROUP",
|
|
31
|
-
"combinator": "AND",
|
|
32
|
-
"negated": False,
|
|
33
|
-
"conditions": [
|
|
34
|
-
{
|
|
35
|
-
"type": "LOGICAL_CONDITION",
|
|
36
|
-
"lhs_variable_id": "e60902d5-6892-4916-80c1-f0130af52322",
|
|
37
|
-
"operator": ">=",
|
|
38
|
-
"rhs_variable_id": "5c1bbb24-c288-49cb-a9b7-0c6f38a86037",
|
|
39
|
-
}
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
"variables": [
|
|
43
|
-
{
|
|
44
|
-
"type": "EXECUTION_COUNTER",
|
|
45
|
-
"node_id": str(PromptNode.__id__),
|
|
46
|
-
"id": "e60902d5-6892-4916-80c1-f0130af52322",
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"type": "CONSTANT_VALUE",
|
|
50
|
-
"variable_value": {"type": "NUMBER", "value": 0},
|
|
51
|
-
"id": "5c1bbb24-c288-49cb-a9b7-0c6f38a86037",
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
},
|
|
55
|
-
"then_outputs": [
|
|
56
|
-
{
|
|
57
|
-
"output_id": "bbd955e8-b939-45f9-8617-f1405dddd2b3",
|
|
58
|
-
"value": {
|
|
59
|
-
"id": "27006b2a-fa81-430c-a0b2-c66a9351fc68",
|
|
60
|
-
"type": "CONSTANT_VALUE",
|
|
61
|
-
"variable_value": {"type": "STRING", "value": "Hello"},
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
"output_id": "e50bf6e9-417b-4c04-babb-94e7dccb9f2c",
|
|
66
|
-
"value": {
|
|
67
|
-
"id": "4559c778-6e27-4cfe-a460-734ba62a5082",
|
|
68
|
-
"type": "CONSTANT_VALUE",
|
|
69
|
-
"variable_value": {"type": "ARRAY", "value": [{"type": "STRING", "value": "Hello"}]},
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
],
|
|
73
|
-
}
|
|
74
|
-
],
|
|
75
|
-
}
|
|
76
|
-
]
|
|
77
|
-
|
|
78
|
-
# WHEN we parse the mock workflow node execution
|
|
79
|
-
node_output_mocks = MockNodeExecution.validate_all(
|
|
80
|
-
raw_mock_workflow_node_execution,
|
|
81
|
-
MyWorkflow,
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
# THEN we get a list of MockNodeExecution objects
|
|
85
|
-
assert node_output_mocks
|
|
86
|
-
assert len(node_output_mocks) == 1
|
|
87
|
-
assert node_output_mocks[0] == MockNodeExecution(
|
|
88
|
-
when_condition=PromptNode.Execution.count.greater_than_or_equal_to(0.0),
|
|
89
|
-
then_outputs=PromptNode.Outputs(
|
|
90
|
-
text="Hello",
|
|
91
|
-
results=[
|
|
92
|
-
StringVellumValue(value="Hello"),
|
|
93
|
-
],
|
|
94
|
-
),
|
|
95
|
-
)
|
|
96
4
|
|
|
97
5
|
|
|
98
6
|
def test_mocks__parse_none_still_runs():
|
|
@@ -120,88 +28,3 @@ def test_mocks__parse_none_still_runs():
|
|
|
120
28
|
|
|
121
29
|
# THEN it was successful
|
|
122
30
|
assert final_event.name == "workflow.execution.fulfilled"
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def test_mocks__use_id_from_display():
|
|
126
|
-
# GIVEN a Base Node
|
|
127
|
-
class StartNode(BaseNode):
|
|
128
|
-
class Outputs(BaseNode.Outputs):
|
|
129
|
-
foo: str
|
|
130
|
-
|
|
131
|
-
# AND a workflow class with that Node
|
|
132
|
-
class MyWorkflow(BaseWorkflow):
|
|
133
|
-
graph = StartNode
|
|
134
|
-
|
|
135
|
-
class Outputs(BaseWorkflow.Outputs):
|
|
136
|
-
final_value = StartNode.Outputs.foo
|
|
137
|
-
|
|
138
|
-
# AND a display class on that Base Node
|
|
139
|
-
node_output_id = uuid.uuid4()
|
|
140
|
-
|
|
141
|
-
class StartNodeDisplay(BaseNodeDisplay[StartNode]):
|
|
142
|
-
output_display = {StartNode.Outputs.foo: NodeOutputDisplay(id=node_output_id, name="foo")}
|
|
143
|
-
|
|
144
|
-
# AND a mock workflow node execution from the app
|
|
145
|
-
raw_mock_workflow_node_execution = [
|
|
146
|
-
{
|
|
147
|
-
"type": "WORKFLOW_NODE_OUTPUT",
|
|
148
|
-
"node_id": str(StartNode.__id__),
|
|
149
|
-
"mock_executions": [
|
|
150
|
-
{
|
|
151
|
-
"when_condition": {
|
|
152
|
-
"expression": {
|
|
153
|
-
"type": "LOGICAL_CONDITION_GROUP",
|
|
154
|
-
"combinator": "AND",
|
|
155
|
-
"negated": False,
|
|
156
|
-
"conditions": [
|
|
157
|
-
{
|
|
158
|
-
"type": "LOGICAL_CONDITION",
|
|
159
|
-
"lhs_variable_id": "e60902d5-6892-4916-80c1-f0130af52322",
|
|
160
|
-
"operator": ">=",
|
|
161
|
-
"rhs_variable_id": "5c1bbb24-c288-49cb-a9b7-0c6f38a86037",
|
|
162
|
-
}
|
|
163
|
-
],
|
|
164
|
-
},
|
|
165
|
-
"variables": [
|
|
166
|
-
{
|
|
167
|
-
"type": "EXECUTION_COUNTER",
|
|
168
|
-
"node_id": str(StartNode.__id__),
|
|
169
|
-
"id": "e60902d5-6892-4916-80c1-f0130af52322",
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
"type": "CONSTANT_VALUE",
|
|
173
|
-
"variable_value": {"type": "NUMBER", "value": 0},
|
|
174
|
-
"id": "5c1bbb24-c288-49cb-a9b7-0c6f38a86037",
|
|
175
|
-
},
|
|
176
|
-
],
|
|
177
|
-
},
|
|
178
|
-
"then_outputs": [
|
|
179
|
-
{
|
|
180
|
-
"output_id": str(node_output_id),
|
|
181
|
-
"value": {
|
|
182
|
-
"id": "27006b2a-fa81-430c-a0b2-c66a9351fc68",
|
|
183
|
-
"type": "CONSTANT_VALUE",
|
|
184
|
-
"variable_value": {"type": "STRING", "value": "Hello"},
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
|
-
],
|
|
188
|
-
}
|
|
189
|
-
],
|
|
190
|
-
}
|
|
191
|
-
]
|
|
192
|
-
|
|
193
|
-
# WHEN we parsed the raw data on `MockNodeExecution`
|
|
194
|
-
node_output_mocks = MockNodeExecution.validate_all(
|
|
195
|
-
raw_mock_workflow_node_execution,
|
|
196
|
-
MyWorkflow,
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
# THEN we get the expected list of MockNodeExecution objects
|
|
200
|
-
assert node_output_mocks
|
|
201
|
-
assert len(node_output_mocks) == 1
|
|
202
|
-
assert node_output_mocks[0] == MockNodeExecution(
|
|
203
|
-
when_condition=StartNode.Execution.count.greater_than_or_equal_to(0.0),
|
|
204
|
-
then_outputs=StartNode.Outputs(
|
|
205
|
-
foo="Hello",
|
|
206
|
-
),
|
|
207
|
-
)
|
vellum/workflows/nodes/utils.py
CHANGED
|
@@ -3,7 +3,20 @@ import inspect
|
|
|
3
3
|
import json
|
|
4
4
|
import sys
|
|
5
5
|
from types import ModuleType
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import (
|
|
7
|
+
TYPE_CHECKING,
|
|
8
|
+
Any,
|
|
9
|
+
Callable,
|
|
10
|
+
Dict,
|
|
11
|
+
ForwardRef,
|
|
12
|
+
List,
|
|
13
|
+
Optional,
|
|
14
|
+
Type,
|
|
15
|
+
TypeVar,
|
|
16
|
+
Union,
|
|
17
|
+
get_args,
|
|
18
|
+
get_origin,
|
|
19
|
+
)
|
|
7
20
|
|
|
8
21
|
from pydantic import BaseModel, create_model
|
|
9
22
|
|
|
@@ -12,8 +25,6 @@ from vellum.workflows.constants import undefined
|
|
|
12
25
|
from vellum.workflows.errors.types import WorkflowErrorCode
|
|
13
26
|
from vellum.workflows.exceptions import NodeException
|
|
14
27
|
from vellum.workflows.inputs.base import BaseInputs
|
|
15
|
-
from vellum.workflows.nodes import BaseNode
|
|
16
|
-
from vellum.workflows.nodes.bases.base_adornment_node import BaseAdornmentNode
|
|
17
28
|
from vellum.workflows.ports.port import Port
|
|
18
29
|
from vellum.workflows.state.base import BaseState
|
|
19
30
|
from vellum.workflows.types.code_execution_node_wrappers import (
|
|
@@ -23,13 +34,16 @@ from vellum.workflows.types.code_execution_node_wrappers import (
|
|
|
23
34
|
clean_for_dict_wrapper,
|
|
24
35
|
)
|
|
25
36
|
from vellum.workflows.types.core import Json
|
|
26
|
-
from vellum.workflows.types.generics import NodeType
|
|
37
|
+
from vellum.workflows.types.generics import NodeType, import_base_adornment_node
|
|
38
|
+
|
|
39
|
+
if TYPE_CHECKING:
|
|
40
|
+
from vellum.workflows.nodes import BaseNode
|
|
27
41
|
|
|
28
42
|
ADORNMENT_MODULE_NAME = "<adornment>"
|
|
29
43
|
|
|
30
44
|
|
|
31
45
|
@cache
|
|
32
|
-
def get_unadorned_node(node: Type[BaseNode]) -> Type[BaseNode]:
|
|
46
|
+
def get_unadorned_node(node: Type["BaseNode"]) -> Type["BaseNode"]:
|
|
33
47
|
wrapped_node = get_wrapped_node(node)
|
|
34
48
|
if wrapped_node is not None:
|
|
35
49
|
return get_unadorned_node(wrapped_node)
|
|
@@ -46,20 +60,21 @@ def get_unadorned_port(port: Port) -> Port:
|
|
|
46
60
|
return getattr(unadorned_node.Ports, port.name)
|
|
47
61
|
|
|
48
62
|
|
|
49
|
-
def get_wrapped_node(node: Type[NodeType]) -> Optional[Type[BaseNode]]:
|
|
63
|
+
def get_wrapped_node(node: Type[NodeType]) -> Optional[Type["BaseNode"]]:
|
|
64
|
+
BaseAdornmentNode = import_base_adornment_node()
|
|
50
65
|
if not issubclass(node, BaseAdornmentNode):
|
|
51
66
|
return None
|
|
52
67
|
|
|
53
68
|
return node.__wrapped_node__
|
|
54
69
|
|
|
55
70
|
|
|
56
|
-
AdornableNode = TypeVar("AdornableNode", bound=BaseNode)
|
|
71
|
+
AdornableNode = TypeVar("AdornableNode", bound="BaseNode")
|
|
57
72
|
|
|
58
73
|
|
|
59
74
|
def create_adornment(
|
|
60
75
|
adornable_cls: Type[AdornableNode], attributes: Optional[dict[str, Any]] = None
|
|
61
76
|
) -> Callable[..., Type["AdornableNode"]]:
|
|
62
|
-
def decorator(inner_cls: Type[BaseNode]) -> Type["AdornableNode"]:
|
|
77
|
+
def decorator(inner_cls: Type["BaseNode"]) -> Type["AdornableNode"]:
|
|
63
78
|
# Investigate how to use dependency injection to avoid circular imports
|
|
64
79
|
# https://app.shortcut.com/vellum/story/4116
|
|
65
80
|
from vellum.workflows import BaseWorkflow
|
vellum/workflows/outputs/base.py
CHANGED
|
@@ -3,7 +3,7 @@ import inspect
|
|
|
3
3
|
from typing import Any, Dict, Generic, Iterator, Set, Tuple, Type, TypeVar, Union, cast
|
|
4
4
|
from typing_extensions import dataclass_transform
|
|
5
5
|
|
|
6
|
-
from pydantic import GetCoreSchemaHandler
|
|
6
|
+
from pydantic import GetCoreSchemaHandler, ValidationInfo
|
|
7
7
|
from pydantic_core import core_schema
|
|
8
8
|
|
|
9
9
|
from vellum.workflows.constants import undefined
|
|
@@ -12,7 +12,7 @@ from vellum.workflows.errors.types import WorkflowErrorCode
|
|
|
12
12
|
from vellum.workflows.exceptions import NodeException
|
|
13
13
|
from vellum.workflows.executable import BaseExecutable
|
|
14
14
|
from vellum.workflows.references.output import OutputReference
|
|
15
|
-
from vellum.workflows.types.generics import is_node_instance
|
|
15
|
+
from vellum.workflows.types.generics import import_workflow_class, is_node_instance
|
|
16
16
|
from vellum.workflows.types.utils import get_class_attr_names, infer_types
|
|
17
17
|
|
|
18
18
|
_Delta = TypeVar("_Delta")
|
|
@@ -268,4 +268,37 @@ class BaseOutputs(metaclass=_BaseOutputsMeta):
|
|
|
268
268
|
def __get_pydantic_core_schema__(
|
|
269
269
|
cls, source_type: Type[Any], handler: GetCoreSchemaHandler
|
|
270
270
|
) -> core_schema.CoreSchema:
|
|
271
|
-
|
|
271
|
+
def validate(value: Any, info: ValidationInfo) -> Any:
|
|
272
|
+
if isinstance(value, cls):
|
|
273
|
+
return value
|
|
274
|
+
|
|
275
|
+
if not isinstance(value, dict):
|
|
276
|
+
raise TypeError(f"Value must be an instance of {cls.__name__} or a dict")
|
|
277
|
+
|
|
278
|
+
context = info.context
|
|
279
|
+
if not isinstance(context, dict):
|
|
280
|
+
raise TypeError(f"Unexpected type for context: {type(context)}")
|
|
281
|
+
|
|
282
|
+
workflow = context.get("workflow")
|
|
283
|
+
node_id = context.get("node_id")
|
|
284
|
+
base_workflow_class = import_workflow_class()
|
|
285
|
+
if (
|
|
286
|
+
not workflow
|
|
287
|
+
or not node_id
|
|
288
|
+
or not isinstance(node_id, str)
|
|
289
|
+
or not isinstance(workflow, type)
|
|
290
|
+
or not issubclass(workflow, base_workflow_class)
|
|
291
|
+
):
|
|
292
|
+
return cls(**value)
|
|
293
|
+
|
|
294
|
+
node_class = workflow.resolve_node_ref(node_id)
|
|
295
|
+
declared_fields = {descriptor.name for descriptor in node_class.Outputs}
|
|
296
|
+
filtered_value = {k: v for k, v in value.items() if k in declared_fields}
|
|
297
|
+
return node_class.Outputs(**filtered_value)
|
|
298
|
+
|
|
299
|
+
return core_schema.union_schema(
|
|
300
|
+
[
|
|
301
|
+
core_schema.is_instance_schema(cls),
|
|
302
|
+
core_schema.with_info_after_validator_function(validate, core_schema.dict_schema()),
|
|
303
|
+
]
|
|
304
|
+
)
|
|
@@ -13,12 +13,10 @@ class EnvironmentVariableReference(BaseDescriptor[str]):
|
|
|
13
13
|
self,
|
|
14
14
|
*,
|
|
15
15
|
name: str,
|
|
16
|
-
# DEPRECATED - to be removed in
|
|
16
|
+
# DEPRECATED - to be removed in 2.0 release
|
|
17
17
|
default: Optional[str] = None,
|
|
18
|
-
serialize_as_constant: bool = False,
|
|
19
18
|
):
|
|
20
19
|
super().__init__(name=name, types=(str,), is_sensitive=True)
|
|
21
|
-
self._serialize_as_constant = serialize_as_constant
|
|
22
20
|
|
|
23
21
|
def resolve(self, state: "BaseState") -> Any:
|
|
24
22
|
env_value = os.environ.get(self.name)
|
|
@@ -32,11 +30,3 @@ class EnvironmentVariableReference(BaseDescriptor[str]):
|
|
|
32
30
|
"type": "ENVIRONMENT_VARIABLE",
|
|
33
31
|
"environment_variable": self.name,
|
|
34
32
|
}
|
|
35
|
-
|
|
36
|
-
@property
|
|
37
|
-
def serialize_as_constant(self) -> bool:
|
|
38
|
-
return self._serialize_as_constant
|
|
39
|
-
|
|
40
|
-
@serialize_as_constant.setter
|
|
41
|
-
def serialize_as_constant(self, value: bool):
|
|
42
|
-
self._serialize_as_constant = value
|
|
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Callable, Generic, TypeVar, Union, get_args
|
|
|
5
5
|
|
|
6
6
|
from vellum.workflows.constants import undefined
|
|
7
7
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
|
8
|
+
from vellum.workflows.types.generics import is_workflow_class
|
|
8
9
|
|
|
9
10
|
if TYPE_CHECKING:
|
|
10
11
|
from vellum.workflows.state.base import BaseState
|
|
@@ -36,6 +37,13 @@ class LazyReference(BaseDescriptor[_T], Generic[_T]):
|
|
|
36
37
|
if str(output_reference) == self._get:
|
|
37
38
|
return value
|
|
38
39
|
|
|
40
|
+
# Check workflow outputs
|
|
41
|
+
workflow_definition = state.meta.workflow_definition
|
|
42
|
+
if is_workflow_class(workflow_definition):
|
|
43
|
+
for output_reference in workflow_definition.Outputs:
|
|
44
|
+
if str(output_reference) == self._get:
|
|
45
|
+
return resolve_value(output_reference.instance, state) # type: ignore[return-value]
|
|
46
|
+
|
|
39
47
|
child_reference = self.resolve(state.meta.parent) if state.meta.parent else None
|
|
40
48
|
|
|
41
49
|
# Fix typing surrounding the return value of node outputs/output descriptors
|