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,16 +1,34 @@
|
|
|
1
1
|
import dataclasses
|
|
2
|
+
from datetime import datetime
|
|
2
3
|
import inspect
|
|
3
|
-
from typing import
|
|
4
|
+
from typing import (
|
|
5
|
+
TYPE_CHECKING,
|
|
6
|
+
Annotated,
|
|
7
|
+
Any,
|
|
8
|
+
Callable,
|
|
9
|
+
ForwardRef,
|
|
10
|
+
List,
|
|
11
|
+
Literal,
|
|
12
|
+
Optional,
|
|
13
|
+
Type,
|
|
14
|
+
TypeVar,
|
|
15
|
+
Union,
|
|
16
|
+
get_args,
|
|
17
|
+
get_origin,
|
|
18
|
+
)
|
|
4
19
|
|
|
5
20
|
from pydantic import BaseModel
|
|
6
21
|
from pydantic_core import PydanticUndefined
|
|
7
22
|
from pydash import snake_case
|
|
8
23
|
|
|
9
24
|
from vellum import Vellum
|
|
25
|
+
from vellum.client.types.array_chat_message_content_item import ArrayChatMessageContentItem
|
|
10
26
|
from vellum.client.types.function_definition import FunctionDefinition
|
|
27
|
+
from vellum.workflows.constants import undefined
|
|
11
28
|
from vellum.workflows.integrations.composio_service import ComposioService
|
|
12
29
|
from vellum.workflows.integrations.mcp_service import MCPService
|
|
13
30
|
from vellum.workflows.integrations.vellum_integration_service import VellumIntegrationService
|
|
31
|
+
from vellum.workflows.types.core import is_json_type
|
|
14
32
|
from vellum.workflows.types.definition import (
|
|
15
33
|
ComposioToolDefinition,
|
|
16
34
|
DeploymentDefinition,
|
|
@@ -41,12 +59,51 @@ for k, v in list(type_map.items()):
|
|
|
41
59
|
type_map[k.__name__] = v
|
|
42
60
|
|
|
43
61
|
|
|
62
|
+
def _get_def_name(annotation: Type) -> str:
|
|
63
|
+
return f"{annotation.__module__}.{annotation.__qualname__}"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
recorded_unions = {
|
|
67
|
+
ArrayChatMessageContentItem: "vellum.client.types.array_chat_message_content_item.ArrayChatMessageContentItem",
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
44
71
|
def compile_annotation(annotation: Optional[Any], defs: dict[str, Any]) -> dict:
|
|
45
72
|
if annotation is None:
|
|
46
73
|
return {"type": "null"}
|
|
47
74
|
|
|
75
|
+
if annotation is Any:
|
|
76
|
+
return {}
|
|
77
|
+
|
|
78
|
+
# Handle type variables (e.g., MapNodeItemType) - return empty schema since we can't determine the type
|
|
79
|
+
if isinstance(annotation, TypeVar):
|
|
80
|
+
return {}
|
|
81
|
+
|
|
82
|
+
if annotation is datetime:
|
|
83
|
+
return {"type": "string", "format": "date-time"}
|
|
84
|
+
|
|
48
85
|
if get_origin(annotation) is Union:
|
|
49
|
-
|
|
86
|
+
if is_json_type(get_args(annotation)):
|
|
87
|
+
return {"$ref": "#/$defs/vellum.workflows.types.core.Json"}
|
|
88
|
+
|
|
89
|
+
if annotation in recorded_unions:
|
|
90
|
+
return {"$ref": f"#/$defs/{recorded_unions[annotation]}"}
|
|
91
|
+
|
|
92
|
+
# Filter out Type[undefined] from union args - it just makes the property optional
|
|
93
|
+
filtered_args = [
|
|
94
|
+
a
|
|
95
|
+
for a in get_args(annotation)
|
|
96
|
+
if not (get_origin(a) is type and get_args(a) and get_args(a)[0] is undefined)
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
if len(filtered_args) == 0:
|
|
100
|
+
# Edge case: all union members were Type[undefined], return empty schema
|
|
101
|
+
return {}
|
|
102
|
+
|
|
103
|
+
if len(filtered_args) == 1:
|
|
104
|
+
return compile_annotation(filtered_args[0], defs)
|
|
105
|
+
|
|
106
|
+
return {"anyOf": [compile_annotation(a, defs) for a in filtered_args]}
|
|
50
107
|
|
|
51
108
|
if get_origin(annotation) is Literal:
|
|
52
109
|
values = list(get_args(annotation))
|
|
@@ -84,7 +141,8 @@ def compile_annotation(annotation: Optional[Any], defs: dict[str, Any]) -> dict:
|
|
|
84
141
|
return result
|
|
85
142
|
|
|
86
143
|
if dataclasses.is_dataclass(annotation) and isinstance(annotation, type):
|
|
87
|
-
|
|
144
|
+
def_name = _get_def_name(annotation)
|
|
145
|
+
if def_name not in defs:
|
|
88
146
|
properties = {}
|
|
89
147
|
required = []
|
|
90
148
|
for field in dataclasses.fields(annotation):
|
|
@@ -93,11 +151,12 @@ def compile_annotation(annotation: Optional[Any], defs: dict[str, Any]) -> dict:
|
|
|
93
151
|
required.append(field.name)
|
|
94
152
|
else:
|
|
95
153
|
properties[field.name]["default"] = _compile_default_value(field.default)
|
|
96
|
-
defs[
|
|
97
|
-
return {"$ref": f"#/$defs/{
|
|
154
|
+
defs[def_name] = {"type": "object", "properties": properties, "required": required}
|
|
155
|
+
return {"$ref": f"#/$defs/{def_name}"}
|
|
98
156
|
|
|
99
157
|
if inspect.isclass(annotation) and issubclass(annotation, BaseModel):
|
|
100
|
-
|
|
158
|
+
def_name = _get_def_name(annotation)
|
|
159
|
+
if def_name not in defs:
|
|
101
160
|
properties = {}
|
|
102
161
|
required = []
|
|
103
162
|
for field_name, field_info in annotation.model_fields.items():
|
|
@@ -111,9 +170,22 @@ def compile_annotation(annotation: Optional[Any], defs: dict[str, Any]) -> dict:
|
|
|
111
170
|
required.append(field_name)
|
|
112
171
|
else:
|
|
113
172
|
properties[field_name]["default"] = _compile_default_value(field_info.default)
|
|
114
|
-
defs[
|
|
173
|
+
defs[def_name] = {"type": "object", "properties": properties, "required": required}
|
|
174
|
+
|
|
175
|
+
return {"$ref": f"#/$defs/{def_name}"}
|
|
176
|
+
|
|
177
|
+
if type(annotation) is ForwardRef:
|
|
178
|
+
# Ignore forward references for now
|
|
179
|
+
return {}
|
|
180
|
+
|
|
181
|
+
# Handle Type[undefined] - skip it as it just makes the property optional
|
|
182
|
+
if get_origin(annotation) is type:
|
|
183
|
+
args = get_args(annotation)
|
|
184
|
+
if args and args[0] is undefined:
|
|
185
|
+
return {}
|
|
115
186
|
|
|
116
|
-
|
|
187
|
+
if annotation not in type_map:
|
|
188
|
+
raise ValueError(f"Failed to compile type: {annotation}")
|
|
117
189
|
|
|
118
190
|
return {"type": type_map[annotation]}
|
|
119
191
|
|
|
@@ -161,6 +233,7 @@ def compile_function_definition(function: Callable) -> FunctionDefinition:
|
|
|
161
233
|
|
|
162
234
|
# Get inputs from the decorator if present
|
|
163
235
|
inputs = getattr(function, "__vellum_inputs__", {})
|
|
236
|
+
examples = getattr(function, "__vellum_examples__", None)
|
|
164
237
|
exclude_params = set(inputs.keys())
|
|
165
238
|
|
|
166
239
|
properties = {}
|
|
@@ -192,6 +265,8 @@ def compile_function_definition(function: Callable) -> FunctionDefinition:
|
|
|
192
265
|
parameters = {"type": "object", "properties": properties, "required": required}
|
|
193
266
|
if defs:
|
|
194
267
|
parameters["$defs"] = defs
|
|
268
|
+
if examples is not None:
|
|
269
|
+
parameters["examples"] = examples
|
|
195
270
|
|
|
196
271
|
return FunctionDefinition(
|
|
197
272
|
name=function.__name__,
|
|
@@ -208,6 +283,11 @@ def compile_inline_workflow_function_definition(workflow_class: Type["BaseWorkfl
|
|
|
208
283
|
inputs_class = workflow_class.get_inputs_class()
|
|
209
284
|
vars_inputs_class = vars(inputs_class)
|
|
210
285
|
|
|
286
|
+
# Get inputs from the decorator if present (to exclude from schema)
|
|
287
|
+
inputs = getattr(workflow_class, "__vellum_inputs__", {})
|
|
288
|
+
examples = getattr(workflow_class, "__vellum_examples__", None)
|
|
289
|
+
exclude_params = set(inputs.keys())
|
|
290
|
+
|
|
211
291
|
properties = {}
|
|
212
292
|
required = []
|
|
213
293
|
defs: dict[str, Any] = {}
|
|
@@ -216,6 +296,10 @@ def compile_inline_workflow_function_definition(workflow_class: Type["BaseWorkfl
|
|
|
216
296
|
if name.startswith("__"):
|
|
217
297
|
continue
|
|
218
298
|
|
|
299
|
+
# Skip parameters that are in the exclude_params set
|
|
300
|
+
if exclude_params and name in exclude_params:
|
|
301
|
+
continue
|
|
302
|
+
|
|
219
303
|
properties[name] = compile_annotation(field_type, defs)
|
|
220
304
|
|
|
221
305
|
# Check if the field has a default value
|
|
@@ -228,6 +312,8 @@ def compile_inline_workflow_function_definition(workflow_class: Type["BaseWorkfl
|
|
|
228
312
|
parameters = {"type": "object", "properties": properties, "required": required}
|
|
229
313
|
if defs:
|
|
230
314
|
parameters["$defs"] = defs
|
|
315
|
+
if examples is not None:
|
|
316
|
+
parameters["examples"] = examples
|
|
231
317
|
|
|
232
318
|
return FunctionDefinition(
|
|
233
319
|
name=snake_case(workflow_class.__name__),
|
|
@@ -342,6 +428,7 @@ def compile_vellum_integration_tool_definition(
|
|
|
342
428
|
integration=tool_def.integration_name,
|
|
343
429
|
provider=tool_def.provider.value,
|
|
344
430
|
tool_name=tool_def.name,
|
|
431
|
+
toolkit_version=tool_def.toolkit_version,
|
|
345
432
|
)
|
|
346
433
|
|
|
347
434
|
return FunctionDefinition(
|
|
@@ -354,11 +441,66 @@ def compile_vellum_integration_tool_definition(
|
|
|
354
441
|
return FunctionDefinition(name=tool_def.name, description=tool_def.description, parameters={})
|
|
355
442
|
|
|
356
443
|
|
|
357
|
-
|
|
444
|
+
ToolType = Union[Callable[..., Any], Type["BaseWorkflow"]]
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
def tool(
|
|
448
|
+
*,
|
|
449
|
+
inputs: Optional[dict[str, Any]] = None,
|
|
450
|
+
examples: Optional[List[dict[str, Any]]] = None,
|
|
451
|
+
) -> Callable[[ToolType], ToolType]:
|
|
452
|
+
"""
|
|
453
|
+
Decorator to configure a tool function or inline workflow.
|
|
454
|
+
|
|
455
|
+
Currently supports specifying which parameters should come from parent workflow inputs
|
|
456
|
+
via the `inputs` mapping. Also supports providing `examples` which will be hoisted
|
|
457
|
+
into the JSON Schema `examples` keyword for this tool's parameters.
|
|
458
|
+
|
|
459
|
+
Args:
|
|
460
|
+
inputs: Mapping of parameter names to parent input references
|
|
461
|
+
examples: List of example argument objects for the tool
|
|
462
|
+
|
|
463
|
+
Example with function:
|
|
464
|
+
@tool(inputs={
|
|
465
|
+
"parent_input": ParentInputs.parent_input,
|
|
466
|
+
}, examples=[{"location": "San Francisco"}])
|
|
467
|
+
def get_string(parent_input: str, user_query: str) -> str:
|
|
468
|
+
return f"Parent: {parent_input}, Query: {user_query}"
|
|
469
|
+
|
|
470
|
+
Example with inline workflow:
|
|
471
|
+
@tool(inputs={
|
|
472
|
+
"context": ParentInputs.context,
|
|
473
|
+
})
|
|
474
|
+
class MyInlineWorkflow(BaseWorkflow):
|
|
475
|
+
graph = MyNode
|
|
476
|
+
|
|
477
|
+
class Outputs(BaseWorkflow.Outputs):
|
|
478
|
+
result = MyNode.Outputs.result
|
|
479
|
+
"""
|
|
480
|
+
|
|
481
|
+
def decorator(func: ToolType) -> ToolType:
|
|
482
|
+
# Store the inputs mapping on the function/workflow for later use
|
|
483
|
+
if inputs is not None:
|
|
484
|
+
setattr(func, "__vellum_inputs__", inputs)
|
|
485
|
+
# Store the examples on the function/workflow for later use
|
|
486
|
+
if examples is not None:
|
|
487
|
+
setattr(func, "__vellum_examples__", examples)
|
|
488
|
+
return func
|
|
489
|
+
|
|
490
|
+
return decorator
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def use_tool_inputs(**inputs: Any) -> Callable[[Callable], Callable]:
|
|
358
494
|
"""
|
|
359
495
|
Decorator to specify which parameters of a tool function should be provided
|
|
360
496
|
from the parent workflow inputs rather than from the LLM.
|
|
361
497
|
|
|
498
|
+
.. deprecated:: 2.0.0
|
|
499
|
+
This function is deprecated and will be removed in version 2.0.0.
|
|
500
|
+
Use :func:`tool` with the ``inputs`` parameter instead.
|
|
501
|
+
|
|
502
|
+
This is a backward-compatible helper equivalent to @tool(inputs={...}).
|
|
503
|
+
|
|
362
504
|
Args:
|
|
363
505
|
**inputs: Mapping of parameter names to parent input references
|
|
364
506
|
|
|
@@ -369,10 +511,4 @@ def use_tool_inputs(**inputs):
|
|
|
369
511
|
def get_string(parent_input: str, user_query: str) -> str:
|
|
370
512
|
return f"Parent: {parent_input}, Query: {user_query}"
|
|
371
513
|
"""
|
|
372
|
-
|
|
373
|
-
def decorator(func: Callable) -> Callable:
|
|
374
|
-
# Store the inputs mapping on the function for later use
|
|
375
|
-
setattr(func, "__vellum_inputs__", inputs)
|
|
376
|
-
return func
|
|
377
|
-
|
|
378
|
-
return decorator
|
|
514
|
+
return tool(inputs=inputs)
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import inspect
|
|
2
|
-
from typing import Any, Dict
|
|
2
|
+
from typing import Any, Dict, Type, TypeVar
|
|
3
3
|
|
|
4
|
+
import pydantic
|
|
4
5
|
from pydantic import BaseModel
|
|
5
6
|
|
|
6
7
|
from vellum.workflows.utils.functions import compile_annotation
|
|
7
8
|
|
|
9
|
+
T = TypeVar("T")
|
|
10
|
+
IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
|
|
11
|
+
_type_adapter_cache: Dict[Type, "pydantic.TypeAdapter"] = {} # type: ignore[type-arg]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def validate_obj_as(type_: Type[T], object_: Any) -> T:
|
|
15
|
+
"""Validate an object as a given type using pydantic's TypeAdapter (v2) or parse_obj_as (v1).
|
|
16
|
+
|
|
17
|
+
This is similar to parse_obj_as but without the convert_and_respect_annotation_metadata step,
|
|
18
|
+
making it suitable for simple type validation without annotation metadata handling.
|
|
19
|
+
"""
|
|
20
|
+
if IS_PYDANTIC_V2:
|
|
21
|
+
if type_ not in _type_adapter_cache:
|
|
22
|
+
_type_adapter_cache[type_] = pydantic.TypeAdapter(type_) # type: ignore[attr-defined]
|
|
23
|
+
return _type_adapter_cache[type_].validate_python(object_)
|
|
24
|
+
return pydantic.parse_obj_as(type_, object_) # type: ignore[attr-defined]
|
|
25
|
+
|
|
8
26
|
|
|
9
27
|
def normalize_json(schema_input: Any) -> Any:
|
|
10
28
|
"""
|
|
@@ -18,6 +18,8 @@ from vellum.workflows.utils.functions import (
|
|
|
18
18
|
compile_function_definition,
|
|
19
19
|
compile_inline_workflow_function_definition,
|
|
20
20
|
compile_workflow_deployment_function_definition,
|
|
21
|
+
tool,
|
|
22
|
+
use_tool_inputs,
|
|
21
23
|
)
|
|
22
24
|
|
|
23
25
|
|
|
@@ -187,14 +189,15 @@ def test_compile_function_definition__dataclasses():
|
|
|
187
189
|
compiled_function = compile_function_definition(my_function)
|
|
188
190
|
|
|
189
191
|
# THEN it should return the compiled function definition
|
|
192
|
+
ref_name = f"{__name__}.test_compile_function_definition__dataclasses.<locals>.MyDataClass"
|
|
190
193
|
assert compiled_function == FunctionDefinition(
|
|
191
194
|
name="my_function",
|
|
192
195
|
parameters={
|
|
193
196
|
"type": "object",
|
|
194
|
-
"properties": {"c": {"$ref": "#/$defs/
|
|
197
|
+
"properties": {"c": {"$ref": f"#/$defs/{ref_name}"}},
|
|
195
198
|
"required": ["c"],
|
|
196
199
|
"$defs": {
|
|
197
|
-
|
|
200
|
+
ref_name: {
|
|
198
201
|
"type": "object",
|
|
199
202
|
"properties": {"a": {"type": "integer"}, "b": {"type": "string"}},
|
|
200
203
|
"required": ["a", "b"],
|
|
@@ -217,14 +220,15 @@ def test_compile_function_definition__pydantic():
|
|
|
217
220
|
compiled_function = compile_function_definition(my_function)
|
|
218
221
|
|
|
219
222
|
# THEN it should return the compiled function definition
|
|
223
|
+
ref_name = f"{__name__}.test_compile_function_definition__pydantic.<locals>.MyPydanticModel"
|
|
220
224
|
assert compiled_function == FunctionDefinition(
|
|
221
225
|
name="my_function",
|
|
222
226
|
parameters={
|
|
223
227
|
"type": "object",
|
|
224
|
-
"properties": {"c": {"$ref": "#/$defs/
|
|
228
|
+
"properties": {"c": {"$ref": f"#/$defs/{ref_name}"}},
|
|
225
229
|
"required": ["c"],
|
|
226
230
|
"$defs": {
|
|
227
|
-
|
|
231
|
+
ref_name: {
|
|
228
232
|
"type": "object",
|
|
229
233
|
"properties": {
|
|
230
234
|
"a": {"type": "integer", "description": "The first number"},
|
|
@@ -251,14 +255,15 @@ def test_compile_function_definition__default_dataclass():
|
|
|
251
255
|
compiled_function = compile_function_definition(my_function)
|
|
252
256
|
|
|
253
257
|
# THEN it should return the compiled function definition
|
|
258
|
+
ref_name = f"{__name__}.test_compile_function_definition__default_dataclass.<locals>.MyDataClass"
|
|
254
259
|
assert compiled_function == FunctionDefinition(
|
|
255
260
|
name="my_function",
|
|
256
261
|
parameters={
|
|
257
262
|
"type": "object",
|
|
258
|
-
"properties": {"c": {"$ref": "#/$defs/
|
|
263
|
+
"properties": {"c": {"$ref": f"#/$defs/{ref_name}", "default": {"a": 1, "b": "hello"}}},
|
|
259
264
|
"required": [],
|
|
260
265
|
"$defs": {
|
|
261
|
-
|
|
266
|
+
ref_name: {
|
|
262
267
|
"type": "object",
|
|
263
268
|
"properties": {"a": {"type": "integer"}, "b": {"type": "string"}},
|
|
264
269
|
"required": ["a", "b"],
|
|
@@ -281,14 +286,15 @@ def test_compile_function_definition__default_pydantic():
|
|
|
281
286
|
compiled_function = compile_function_definition(my_function)
|
|
282
287
|
|
|
283
288
|
# THEN it should return the compiled function definition
|
|
289
|
+
ref_name = f"{__name__}.test_compile_function_definition__default_pydantic.<locals>.MyPydanticModel"
|
|
284
290
|
assert compiled_function == FunctionDefinition(
|
|
285
291
|
name="my_function",
|
|
286
292
|
parameters={
|
|
287
293
|
"type": "object",
|
|
288
|
-
"properties": {"c": {"$ref": "#/$defs/
|
|
294
|
+
"properties": {"c": {"$ref": f"#/$defs/{ref_name}", "default": {"a": 1, "b": "hello"}}},
|
|
289
295
|
"required": [],
|
|
290
296
|
"$defs": {
|
|
291
|
-
|
|
297
|
+
ref_name: {
|
|
292
298
|
"type": "object",
|
|
293
299
|
"properties": {"a": {"type": "integer"}, "b": {"type": "string"}},
|
|
294
300
|
"required": ["a", "b"],
|
|
@@ -773,3 +779,112 @@ def test_compile_function_definition__string_annotations_with_future_imports():
|
|
|
773
779
|
"required": ["a", "b", "c", "d", "e", "f", "g"],
|
|
774
780
|
},
|
|
775
781
|
)
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
def test_use_tool_inputs__inline_vs_decorator():
|
|
785
|
+
"""
|
|
786
|
+
Tests that inline use_tool_inputs(...)(func) behaves the same as @use_tool_inputs(...) decorator.
|
|
787
|
+
"""
|
|
788
|
+
|
|
789
|
+
# GIVEN a function with some parameters
|
|
790
|
+
def my_function(a: str, b: int, c: float) -> str:
|
|
791
|
+
"""A test function."""
|
|
792
|
+
return f"{a}-{b}-{c}"
|
|
793
|
+
|
|
794
|
+
# WHEN using use_tool_inputs as a decorator
|
|
795
|
+
@use_tool_inputs(a="fixed_a", b=42)
|
|
796
|
+
def decorated_function(a: str, b: int, c: float) -> str:
|
|
797
|
+
"""A test function."""
|
|
798
|
+
return f"{a}-{b}-{c}"
|
|
799
|
+
|
|
800
|
+
# AND using use_tool_inputs inline
|
|
801
|
+
inline_function = use_tool_inputs(a="fixed_a", b=42)(my_function)
|
|
802
|
+
|
|
803
|
+
# THEN both should have the same __vellum_inputs__ attribute
|
|
804
|
+
assert hasattr(decorated_function, "__vellum_inputs__")
|
|
805
|
+
assert hasattr(inline_function, "__vellum_inputs__")
|
|
806
|
+
|
|
807
|
+
# AND the inputs should be identical
|
|
808
|
+
assert decorated_function.__vellum_inputs__ == inline_function.__vellum_inputs__
|
|
809
|
+
assert decorated_function.__vellum_inputs__ == {"a": "fixed_a", "b": 42}
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
def test_tool__inline_vs_decorator():
|
|
813
|
+
"""
|
|
814
|
+
Tests that inline tool(inputs={...})(func) behaves the same as @tool(inputs={...}) decorator.
|
|
815
|
+
"""
|
|
816
|
+
|
|
817
|
+
# GIVEN a function with some parameters
|
|
818
|
+
def my_function(a: str, b: int, c: float) -> str:
|
|
819
|
+
"""A test function."""
|
|
820
|
+
return f"{a}-{b}-{c}"
|
|
821
|
+
|
|
822
|
+
# WHEN using tool as a decorator
|
|
823
|
+
@tool(inputs={"a": "fixed_a", "b": 42})
|
|
824
|
+
def decorated_function(a: str, b: int, c: float) -> str:
|
|
825
|
+
"""A test function."""
|
|
826
|
+
return f"{a}-{b}-{c}"
|
|
827
|
+
|
|
828
|
+
# AND using tool inline
|
|
829
|
+
inline_function = tool(inputs={"a": "fixed_a", "b": 42})(my_function)
|
|
830
|
+
|
|
831
|
+
# THEN both should have the same __vellum_inputs__ attribute
|
|
832
|
+
assert hasattr(decorated_function, "__vellum_inputs__")
|
|
833
|
+
assert hasattr(inline_function, "__vellum_inputs__")
|
|
834
|
+
|
|
835
|
+
# AND the inputs should be identical
|
|
836
|
+
assert decorated_function.__vellum_inputs__ == inline_function.__vellum_inputs__
|
|
837
|
+
assert decorated_function.__vellum_inputs__ == {"a": "fixed_a", "b": 42}
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
def test_tool__backward_compatibility_with_use_tool_inputs():
|
|
841
|
+
"""
|
|
842
|
+
Tests that tool(inputs={...}) and use_tool_inputs(**inputs) produce the same __vellum_inputs__ attribute.
|
|
843
|
+
"""
|
|
844
|
+
|
|
845
|
+
# GIVEN a function with some parameters
|
|
846
|
+
def my_function(a: str, b: int) -> str:
|
|
847
|
+
"""A test function."""
|
|
848
|
+
return f"{a}-{b}"
|
|
849
|
+
|
|
850
|
+
# WHEN using tool as a decorator with inputs dict
|
|
851
|
+
@tool(inputs={"a": "value_a"})
|
|
852
|
+
def tool_decorated(a: str, b: int) -> str:
|
|
853
|
+
"""A test function."""
|
|
854
|
+
return f"{a}-{b}"
|
|
855
|
+
|
|
856
|
+
# AND using use_tool_inputs as a decorator with kwargs
|
|
857
|
+
@use_tool_inputs(a="value_a")
|
|
858
|
+
def use_tool_inputs_decorated(a: str, b: int) -> str:
|
|
859
|
+
"""A test function."""
|
|
860
|
+
return f"{a}-{b}"
|
|
861
|
+
|
|
862
|
+
# THEN both should have identical __vellum_inputs__ attributes
|
|
863
|
+
assert getattr(tool_decorated, "__vellum_inputs__") == getattr(use_tool_inputs_decorated, "__vellum_inputs__")
|
|
864
|
+
assert getattr(tool_decorated, "__vellum_inputs__") == {"a": "value_a"}
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
def test_tool_examples_included_in_schema():
|
|
868
|
+
@tool(
|
|
869
|
+
examples=[
|
|
870
|
+
{"location": "San Francisco"},
|
|
871
|
+
{"location": "New York", "units": "celsius"},
|
|
872
|
+
]
|
|
873
|
+
)
|
|
874
|
+
def get_current_weather(location: str, units: str = "fahrenheit") -> str:
|
|
875
|
+
return "sunny"
|
|
876
|
+
|
|
877
|
+
compiled = compile_function_definition(get_current_weather)
|
|
878
|
+
assert isinstance(compiled.parameters, dict)
|
|
879
|
+
assert compiled.parameters == {
|
|
880
|
+
"type": "object",
|
|
881
|
+
"properties": {
|
|
882
|
+
"location": {"type": "string"},
|
|
883
|
+
"units": {"type": "string", "default": "fahrenheit"},
|
|
884
|
+
},
|
|
885
|
+
"required": ["location"],
|
|
886
|
+
"examples": [
|
|
887
|
+
{"location": "San Francisco"},
|
|
888
|
+
{"location": "New York", "units": "celsius"},
|
|
889
|
+
],
|
|
890
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from typing import Any, Union
|
|
3
|
+
|
|
4
|
+
from vellum.workflows.utils.validate import validate_target_type
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@pytest.mark.parametrize(
|
|
8
|
+
["declared_type", "target_type"],
|
|
9
|
+
[
|
|
10
|
+
(str, int),
|
|
11
|
+
(list[str], list[int]),
|
|
12
|
+
(str, Union[str, int]),
|
|
13
|
+
(int, Union[str, int]),
|
|
14
|
+
(list[str], Union[list[str], list[int]]),
|
|
15
|
+
(Union[str, int], Union[bool, float]),
|
|
16
|
+
],
|
|
17
|
+
ids=[
|
|
18
|
+
"str_int",
|
|
19
|
+
"list_str_int",
|
|
20
|
+
"str_union_str_int",
|
|
21
|
+
"int_union_str_int",
|
|
22
|
+
"list_str_union",
|
|
23
|
+
"union_str_int_union_bool_float",
|
|
24
|
+
],
|
|
25
|
+
)
|
|
26
|
+
def test_validate__should_raise_exception(
|
|
27
|
+
declared_type,
|
|
28
|
+
target_type,
|
|
29
|
+
):
|
|
30
|
+
"""
|
|
31
|
+
Tests that validate_target_type raises an exception for mismatched types.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
# WHEN validating the target type
|
|
35
|
+
with pytest.raises(ValueError) as exc_info:
|
|
36
|
+
validate_target_type(declared_type, target_type)
|
|
37
|
+
|
|
38
|
+
# THEN an exception should be raised
|
|
39
|
+
assert "Output type mismatch" in str(exc_info.value)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.mark.parametrize(
|
|
43
|
+
["declared_type", "target_type"],
|
|
44
|
+
[
|
|
45
|
+
(str, str),
|
|
46
|
+
(list[str], list[str]),
|
|
47
|
+
(dict, dict[str, str]),
|
|
48
|
+
(str, Any),
|
|
49
|
+
(Any, str),
|
|
50
|
+
(Union[str, int], str),
|
|
51
|
+
(Union[str, int], int),
|
|
52
|
+
(Union[str, int], Union[str, int]),
|
|
53
|
+
(Union[str, int], Union[int, str]),
|
|
54
|
+
(Union[str, int], Union[str, bool]),
|
|
55
|
+
],
|
|
56
|
+
ids=[
|
|
57
|
+
"str",
|
|
58
|
+
"list_str",
|
|
59
|
+
"bare_dict_params_dict",
|
|
60
|
+
"str_any",
|
|
61
|
+
"any_str",
|
|
62
|
+
"union_str_int_str",
|
|
63
|
+
"union_str_int_int",
|
|
64
|
+
"union_str_int_union_str_int",
|
|
65
|
+
"union_str_int_union_int_str",
|
|
66
|
+
"union_str_int_union_str_bool",
|
|
67
|
+
],
|
|
68
|
+
)
|
|
69
|
+
def test_validate__should_validate(
|
|
70
|
+
declared_type,
|
|
71
|
+
target_type,
|
|
72
|
+
):
|
|
73
|
+
"""
|
|
74
|
+
Tests that validate_target_type accepts matching types.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
# WHEN validating the target type
|
|
78
|
+
# THEN no exception should be raised
|
|
79
|
+
validate_target_type(declared_type, target_type)
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import pytest
|
|
2
|
-
from
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import List, Optional, Union
|
|
3
4
|
|
|
4
|
-
from vellum import
|
|
5
|
+
from vellum import (
|
|
6
|
+
ArrayChatMessageContentItem,
|
|
7
|
+
ChatMessage,
|
|
8
|
+
SearchResult,
|
|
9
|
+
VellumAudio,
|
|
10
|
+
VellumDocument,
|
|
11
|
+
VellumImage,
|
|
12
|
+
VellumValue,
|
|
13
|
+
)
|
|
14
|
+
import vellum.client.types as vellum_types
|
|
5
15
|
from vellum.workflows.types.core import Json
|
|
6
16
|
from vellum.workflows.utils.vellum_variables import (
|
|
17
|
+
_is_vellum_value_subtype,
|
|
7
18
|
primitive_type_to_vellum_variable_type,
|
|
8
19
|
vellum_variable_type_to_openapi_type,
|
|
9
20
|
)
|
|
@@ -14,6 +25,8 @@ from vellum.workflows.utils.vellum_variables import (
|
|
|
14
25
|
[
|
|
15
26
|
(str, "STRING"),
|
|
16
27
|
(Optional[str], "STRING"),
|
|
28
|
+
(datetime, "STRING"),
|
|
29
|
+
(Optional[datetime], "STRING"),
|
|
17
30
|
(int, "NUMBER"),
|
|
18
31
|
(Optional[int], "NUMBER"),
|
|
19
32
|
(float, "NUMBER"),
|
|
@@ -36,6 +49,8 @@ from vellum.workflows.utils.vellum_variables import (
|
|
|
36
49
|
(Optional[list[SearchResult]], "SEARCH_RESULTS"),
|
|
37
50
|
(list[VellumValue], "ARRAY"),
|
|
38
51
|
(Optional[list[VellumValue]], "ARRAY"),
|
|
52
|
+
(List[ArrayChatMessageContentItem], "ARRAY"),
|
|
53
|
+
(Optional[List[ArrayChatMessageContentItem]], "ARRAY"),
|
|
39
54
|
],
|
|
40
55
|
)
|
|
41
56
|
def test_primitive_type_to_vellum_variable_type(type_, expected):
|
|
@@ -61,3 +76,48 @@ def test_primitive_type_to_vellum_variable_type(type_, expected):
|
|
|
61
76
|
)
|
|
62
77
|
def test_vellum_variable_type_to_openapi_type(vellum_type, expected):
|
|
63
78
|
assert vellum_variable_type_to_openapi_type(vellum_type) == expected
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class _SomeType:
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
_STRING_OR_NUMBER_VELLUM_VALUE = Union[vellum_types.StringVellumValue, vellum_types.NumberVellumValue]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@pytest.mark.parametrize(
|
|
89
|
+
["type_", "expected_is_vellum_value_subtype"],
|
|
90
|
+
[
|
|
91
|
+
# Individual union members
|
|
92
|
+
(vellum_types.StringVellumValue, True),
|
|
93
|
+
(vellum_types.NumberVellumValue, True),
|
|
94
|
+
(vellum_types.JsonVellumValue, True),
|
|
95
|
+
(vellum_types.AudioVellumValue, True),
|
|
96
|
+
(vellum_types.VideoVellumValue, True),
|
|
97
|
+
(vellum_types.ImageVellumValue, True),
|
|
98
|
+
(vellum_types.DocumentVellumValue, True),
|
|
99
|
+
(vellum_types.FunctionCallVellumValue, True),
|
|
100
|
+
(vellum_types.ErrorVellumValue, True),
|
|
101
|
+
(vellum_types.ArrayVellumValue, True),
|
|
102
|
+
(vellum_types.ChatHistoryVellumValue, True),
|
|
103
|
+
(vellum_types.SearchResultsVellumValue, True),
|
|
104
|
+
(vellum_types.ThinkingVellumValue, True),
|
|
105
|
+
# Misc union types
|
|
106
|
+
(Union[vellum_types.StringVellumValue, vellum_types.NumberVellumValue], True),
|
|
107
|
+
(_STRING_OR_NUMBER_VELLUM_VALUE, True),
|
|
108
|
+
(Union[vellum_types.StringVellumValue], True),
|
|
109
|
+
(Union["vellum_types.StringVellumValue"], False),
|
|
110
|
+
# Random types
|
|
111
|
+
(int, False),
|
|
112
|
+
(_SomeType, False),
|
|
113
|
+
(List[int], False),
|
|
114
|
+
(Union[int, str], False),
|
|
115
|
+
(Optional[int], False),
|
|
116
|
+
(List["_SomeType"], False),
|
|
117
|
+
# Handle non-types gracefully
|
|
118
|
+
(1, False),
|
|
119
|
+
(_SomeType(), False),
|
|
120
|
+
],
|
|
121
|
+
)
|
|
122
|
+
def test_is_vellum_value_subtype(type_, expected_is_vellum_value_subtype):
|
|
123
|
+
assert _is_vellum_value_subtype(type_) == expected_is_vellum_value_subtype
|