vellum-ai 0.9.16rc2__py3-none-any.whl → 0.10.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- vellum/plugins/__init__.py +0 -0
- vellum/plugins/pydantic.py +74 -0
- vellum/plugins/utils.py +19 -0
- vellum/plugins/vellum_mypy.py +639 -3
- vellum/workflows/README.md +90 -0
- vellum/workflows/__init__.py +5 -0
- vellum/workflows/constants.py +43 -0
- vellum/workflows/descriptors/__init__.py +0 -0
- vellum/workflows/descriptors/base.py +339 -0
- vellum/workflows/descriptors/tests/test_utils.py +83 -0
- vellum/workflows/descriptors/utils.py +90 -0
- vellum/workflows/edges/__init__.py +5 -0
- vellum/workflows/edges/edge.py +23 -0
- vellum/workflows/emitters/__init__.py +5 -0
- vellum/workflows/emitters/base.py +14 -0
- vellum/workflows/environment/__init__.py +5 -0
- vellum/workflows/environment/environment.py +7 -0
- vellum/workflows/errors/__init__.py +6 -0
- vellum/workflows/errors/types.py +20 -0
- vellum/workflows/events/__init__.py +31 -0
- vellum/workflows/events/node.py +125 -0
- vellum/workflows/events/tests/__init__.py +0 -0
- vellum/workflows/events/tests/test_event.py +216 -0
- vellum/workflows/events/types.py +52 -0
- vellum/workflows/events/utils.py +5 -0
- vellum/workflows/events/workflow.py +139 -0
- vellum/workflows/exceptions.py +15 -0
- vellum/workflows/expressions/__init__.py +0 -0
- vellum/workflows/expressions/accessor.py +52 -0
- vellum/workflows/expressions/and_.py +32 -0
- vellum/workflows/expressions/begins_with.py +31 -0
- vellum/workflows/expressions/between.py +38 -0
- vellum/workflows/expressions/coalesce_expression.py +41 -0
- vellum/workflows/expressions/contains.py +30 -0
- vellum/workflows/expressions/does_not_begin_with.py +31 -0
- vellum/workflows/expressions/does_not_contain.py +30 -0
- vellum/workflows/expressions/does_not_end_with.py +31 -0
- vellum/workflows/expressions/does_not_equal.py +25 -0
- vellum/workflows/expressions/ends_with.py +31 -0
- vellum/workflows/expressions/equals.py +25 -0
- vellum/workflows/expressions/greater_than.py +33 -0
- vellum/workflows/expressions/greater_than_or_equal_to.py +33 -0
- vellum/workflows/expressions/in_.py +31 -0
- vellum/workflows/expressions/is_blank.py +24 -0
- vellum/workflows/expressions/is_not_blank.py +24 -0
- vellum/workflows/expressions/is_not_null.py +21 -0
- vellum/workflows/expressions/is_not_undefined.py +22 -0
- vellum/workflows/expressions/is_null.py +21 -0
- vellum/workflows/expressions/is_undefined.py +22 -0
- vellum/workflows/expressions/less_than.py +33 -0
- vellum/workflows/expressions/less_than_or_equal_to.py +33 -0
- vellum/workflows/expressions/not_between.py +38 -0
- vellum/workflows/expressions/not_in.py +31 -0
- vellum/workflows/expressions/or_.py +32 -0
- vellum/workflows/graph/__init__.py +3 -0
- vellum/workflows/graph/graph.py +131 -0
- vellum/workflows/graph/tests/__init__.py +0 -0
- vellum/workflows/graph/tests/test_graph.py +437 -0
- vellum/workflows/inputs/__init__.py +5 -0
- vellum/workflows/inputs/base.py +55 -0
- vellum/workflows/logging.py +14 -0
- vellum/workflows/nodes/__init__.py +46 -0
- vellum/workflows/nodes/bases/__init__.py +7 -0
- vellum/workflows/nodes/bases/base.py +332 -0
- vellum/workflows/nodes/bases/base_subworkflow_node/__init__.py +5 -0
- vellum/workflows/nodes/bases/base_subworkflow_node/node.py +10 -0
- vellum/workflows/nodes/bases/tests/__init__.py +0 -0
- vellum/workflows/nodes/bases/tests/test_base_node.py +125 -0
- vellum/workflows/nodes/core/__init__.py +16 -0
- vellum/workflows/nodes/core/error_node/__init__.py +5 -0
- vellum/workflows/nodes/core/error_node/node.py +26 -0
- vellum/workflows/nodes/core/inline_subworkflow_node/__init__.py +5 -0
- vellum/workflows/nodes/core/inline_subworkflow_node/node.py +73 -0
- vellum/workflows/nodes/core/map_node/__init__.py +5 -0
- vellum/workflows/nodes/core/map_node/node.py +147 -0
- vellum/workflows/nodes/core/map_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/core/map_node/tests/test_node.py +65 -0
- vellum/workflows/nodes/core/retry_node/__init__.py +5 -0
- vellum/workflows/nodes/core/retry_node/node.py +106 -0
- vellum/workflows/nodes/core/retry_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/core/retry_node/tests/test_node.py +93 -0
- vellum/workflows/nodes/core/templating_node/__init__.py +5 -0
- vellum/workflows/nodes/core/templating_node/custom_filters.py +12 -0
- vellum/workflows/nodes/core/templating_node/exceptions.py +2 -0
- vellum/workflows/nodes/core/templating_node/node.py +123 -0
- vellum/workflows/nodes/core/templating_node/render.py +55 -0
- vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py +21 -0
- vellum/workflows/nodes/core/try_node/__init__.py +5 -0
- vellum/workflows/nodes/core/try_node/node.py +110 -0
- vellum/workflows/nodes/core/try_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/core/try_node/tests/test_node.py +82 -0
- vellum/workflows/nodes/displayable/__init__.py +31 -0
- vellum/workflows/nodes/displayable/api_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/api_node/node.py +44 -0
- vellum/workflows/nodes/displayable/bases/__init__.py +11 -0
- vellum/workflows/nodes/displayable/bases/api_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/bases/api_node/node.py +70 -0
- vellum/workflows/nodes/displayable/bases/base_prompt_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +60 -0
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/constants.py +13 -0
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +118 -0
- vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +98 -0
- vellum/workflows/nodes/displayable/bases/search_node.py +90 -0
- vellum/workflows/nodes/displayable/code_execution_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/code_execution_node/node.py +197 -0
- vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py +0 -0
- vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py +3 -0
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +111 -0
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +10 -0
- vellum/workflows/nodes/displayable/conditional_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/conditional_node/node.py +25 -0
- vellum/workflows/nodes/displayable/final_output_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/final_output_node/node.py +43 -0
- vellum/workflows/nodes/displayable/guardrail_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/guardrail_node/node.py +97 -0
- vellum/workflows/nodes/displayable/inline_prompt_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/inline_prompt_node/node.py +41 -0
- vellum/workflows/nodes/displayable/merge_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/merge_node/node.py +10 -0
- vellum/workflows/nodes/displayable/prompt_deployment_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +45 -0
- vellum/workflows/nodes/displayable/search_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/search_node/node.py +26 -0
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +156 -0
- vellum/workflows/nodes/displayable/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +148 -0
- vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py +134 -0
- vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +80 -0
- vellum/workflows/nodes/utils.py +27 -0
- vellum/workflows/outputs/__init__.py +6 -0
- vellum/workflows/outputs/base.py +196 -0
- vellum/workflows/ports/__init__.py +7 -0
- vellum/workflows/ports/node_ports.py +75 -0
- vellum/workflows/ports/port.py +75 -0
- vellum/workflows/ports/utils.py +40 -0
- vellum/workflows/references/__init__.py +17 -0
- vellum/workflows/references/environment_variable.py +20 -0
- vellum/workflows/references/execution_count.py +20 -0
- vellum/workflows/references/external_input.py +49 -0
- vellum/workflows/references/input.py +7 -0
- vellum/workflows/references/lazy.py +55 -0
- vellum/workflows/references/node.py +43 -0
- vellum/workflows/references/output.py +78 -0
- vellum/workflows/references/state_value.py +23 -0
- vellum/workflows/references/vellum_secret.py +15 -0
- vellum/workflows/references/workflow_input.py +41 -0
- vellum/workflows/resolvers/__init__.py +5 -0
- vellum/workflows/resolvers/base.py +15 -0
- vellum/workflows/runner/__init__.py +5 -0
- vellum/workflows/runner/runner.py +588 -0
- vellum/workflows/runner/types.py +18 -0
- vellum/workflows/state/__init__.py +5 -0
- vellum/workflows/state/base.py +327 -0
- vellum/workflows/state/context.py +18 -0
- vellum/workflows/state/encoder.py +57 -0
- vellum/workflows/state/store.py +28 -0
- vellum/workflows/state/tests/__init__.py +0 -0
- vellum/workflows/state/tests/test_state.py +113 -0
- vellum/workflows/types/__init__.py +0 -0
- vellum/workflows/types/core.py +91 -0
- vellum/workflows/types/generics.py +14 -0
- vellum/workflows/types/stack.py +39 -0
- vellum/workflows/types/tests/__init__.py +0 -0
- vellum/workflows/types/tests/test_utils.py +76 -0
- vellum/workflows/types/utils.py +164 -0
- vellum/workflows/utils/__init__.py +0 -0
- vellum/workflows/utils/names.py +13 -0
- vellum/workflows/utils/tests/__init__.py +0 -0
- vellum/workflows/utils/tests/test_names.py +15 -0
- vellum/workflows/utils/tests/test_vellum_variables.py +25 -0
- vellum/workflows/utils/vellum_variables.py +81 -0
- vellum/workflows/vellum_client.py +18 -0
- vellum/workflows/workflows/__init__.py +5 -0
- vellum/workflows/workflows/base.py +365 -0
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.10.0.dist-info}/METADATA +2 -1
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.10.0.dist-info}/RECORD +245 -7
- vellum_cli/__init__.py +72 -0
- vellum_cli/aliased_group.py +103 -0
- vellum_cli/config.py +96 -0
- vellum_cli/image_push.py +112 -0
- vellum_cli/logger.py +36 -0
- vellum_cli/pull.py +73 -0
- vellum_cli/push.py +121 -0
- vellum_cli/tests/test_config.py +100 -0
- vellum_cli/tests/test_pull.py +152 -0
- vellum_ee/workflows/__init__.py +0 -0
- vellum_ee/workflows/display/__init__.py +0 -0
- vellum_ee/workflows/display/base.py +73 -0
- vellum_ee/workflows/display/nodes/__init__.py +4 -0
- vellum_ee/workflows/display/nodes/base_node_display.py +116 -0
- vellum_ee/workflows/display/nodes/base_node_vellum_display.py +36 -0
- vellum_ee/workflows/display/nodes/get_node_display_class.py +25 -0
- vellum_ee/workflows/display/nodes/tests/__init__.py +0 -0
- vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +47 -0
- vellum_ee/workflows/display/nodes/types.py +18 -0
- vellum_ee/workflows/display/nodes/utils.py +33 -0
- vellum_ee/workflows/display/nodes/vellum/__init__.py +32 -0
- vellum_ee/workflows/display/nodes/vellum/api_node.py +205 -0
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +71 -0
- vellum_ee/workflows/display/nodes/vellum/conditional_node.py +217 -0
- vellum_ee/workflows/display/nodes/vellum/final_output_node.py +61 -0
- vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +49 -0
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +170 -0
- vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +99 -0
- vellum_ee/workflows/display/nodes/vellum/map_node.py +100 -0
- vellum_ee/workflows/display/nodes/vellum/merge_node.py +48 -0
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +68 -0
- vellum_ee/workflows/display/nodes/vellum/search_node.py +193 -0
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +58 -0
- vellum_ee/workflows/display/nodes/vellum/templating_node.py +67 -0
- vellum_ee/workflows/display/nodes/vellum/tests/__init__.py +0 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +106 -0
- vellum_ee/workflows/display/nodes/vellum/try_node.py +38 -0
- vellum_ee/workflows/display/nodes/vellum/utils.py +76 -0
- vellum_ee/workflows/display/tests/__init__.py +0 -0
- vellum_ee/workflows/display/tests/workflow_serialization/__init__.py +0 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +426 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +607 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +1175 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +235 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +511 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +372 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +272 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +289 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +354 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +123 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +84 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +233 -0
- vellum_ee/workflows/display/types.py +46 -0
- vellum_ee/workflows/display/utils/__init__.py +0 -0
- vellum_ee/workflows/display/utils/tests/__init__.py +0 -0
- vellum_ee/workflows/display/utils/tests/test_uuids.py +16 -0
- vellum_ee/workflows/display/utils/uuids.py +24 -0
- vellum_ee/workflows/display/utils/vellum.py +121 -0
- vellum_ee/workflows/display/vellum.py +357 -0
- vellum_ee/workflows/display/workflows/__init__.py +5 -0
- vellum_ee/workflows/display/workflows/base_workflow_display.py +302 -0
- vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +32 -0
- vellum_ee/workflows/display/workflows/vellum_workflow_display.py +386 -0
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.10.0.dist-info}/LICENSE +0 -0
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.10.0.dist-info}/WHEEL +0 -0
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.10.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
import pytest
|
2
|
+
from typing import ClassVar, Generic, List, TypeVar, Union
|
3
|
+
|
4
|
+
from vellum.workflows.outputs.base import BaseOutputs
|
5
|
+
from vellum.workflows.references.output import OutputReference
|
6
|
+
from vellum.workflows.types.utils import get_class_attr_names, infer_types
|
7
|
+
|
8
|
+
|
9
|
+
class ExampleClass:
|
10
|
+
alpha: str
|
11
|
+
beta = 3
|
12
|
+
gamma: Union[str, int]
|
13
|
+
epsilon = OutputReference(
|
14
|
+
name="epsilon",
|
15
|
+
types=(List[str],),
|
16
|
+
instance=None,
|
17
|
+
outputs_class=BaseOutputs,
|
18
|
+
)
|
19
|
+
zeta: ClassVar[str]
|
20
|
+
eta: List[str]
|
21
|
+
|
22
|
+
|
23
|
+
T = TypeVar("T")
|
24
|
+
|
25
|
+
|
26
|
+
class ExampleGenericClass(Generic[T]):
|
27
|
+
delta: T
|
28
|
+
|
29
|
+
|
30
|
+
class ExampleInheritedClass(ExampleClass):
|
31
|
+
theta: int
|
32
|
+
|
33
|
+
|
34
|
+
@pytest.mark.parametrize(
|
35
|
+
"cls, attr_name, expected_type",
|
36
|
+
[
|
37
|
+
(ExampleClass, "alpha", (str,)),
|
38
|
+
(ExampleClass, "beta", (int,)),
|
39
|
+
(ExampleClass, "gamma", (str, int)),
|
40
|
+
(ExampleGenericClass, "delta", ()),
|
41
|
+
(ExampleGenericClass[str], "delta", (str,)),
|
42
|
+
(ExampleClass, "epsilon", (List[str],)),
|
43
|
+
(ExampleClass, "zeta", (str,)),
|
44
|
+
(ExampleClass, "eta", (List[str],)),
|
45
|
+
(ExampleInheritedClass, "theta", (int,)),
|
46
|
+
(ExampleInheritedClass, "alpha", (str,)),
|
47
|
+
(ExampleInheritedClass, "beta", (int,)),
|
48
|
+
],
|
49
|
+
ids=[
|
50
|
+
"str",
|
51
|
+
"int",
|
52
|
+
"str_or_int",
|
53
|
+
"generic_blank",
|
54
|
+
"generic_str",
|
55
|
+
"descriptor",
|
56
|
+
"class_var",
|
57
|
+
"list_str",
|
58
|
+
"inherited_int",
|
59
|
+
"inherited_parent_annotation",
|
60
|
+
"inherited_parent_class_var",
|
61
|
+
],
|
62
|
+
)
|
63
|
+
def test_infer_types(cls, attr_name, expected_type):
|
64
|
+
assert infer_types(cls, attr_name) == expected_type
|
65
|
+
|
66
|
+
|
67
|
+
@pytest.mark.parametrize(
|
68
|
+
"cls, expected_attr_names",
|
69
|
+
[
|
70
|
+
(ExampleClass, {"alpha", "beta", "gamma", "epsilon", "zeta", "eta"}),
|
71
|
+
(ExampleGenericClass, {"delta"}),
|
72
|
+
(ExampleInheritedClass, {"alpha", "beta", "gamma", "epsilon", "zeta", "eta", "theta"}),
|
73
|
+
],
|
74
|
+
)
|
75
|
+
def test_class_attr_names(cls, expected_attr_names):
|
76
|
+
assert get_class_attr_names(cls) == expected_attr_names
|
@@ -0,0 +1,164 @@
|
|
1
|
+
from copy import deepcopy
|
2
|
+
from datetime import datetime
|
3
|
+
import importlib
|
4
|
+
from typing import (
|
5
|
+
Any,
|
6
|
+
ClassVar,
|
7
|
+
Dict,
|
8
|
+
Generic,
|
9
|
+
Optional,
|
10
|
+
Set,
|
11
|
+
Tuple,
|
12
|
+
Type,
|
13
|
+
TypeVar,
|
14
|
+
Union,
|
15
|
+
get_args,
|
16
|
+
get_origin,
|
17
|
+
get_type_hints,
|
18
|
+
)
|
19
|
+
|
20
|
+
from vellum import ArrayVellumValue, ArrayVellumValueRequest, ChatMessagePromptBlock
|
21
|
+
|
22
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
23
|
+
from vellum.workflows.types.core import Json, SpecialGenericAlias, UnderGenericAlias, UnionGenericAlias
|
24
|
+
|
25
|
+
_T = TypeVar("_T")
|
26
|
+
_LHS = TypeVar("_LHS")
|
27
|
+
_RHS = TypeVar("_RHS")
|
28
|
+
|
29
|
+
LOCAL_NS = {
|
30
|
+
"Json": Json,
|
31
|
+
"ArrayVellumValueRequest": ArrayVellumValueRequest,
|
32
|
+
"ArrayVellumValue": ArrayVellumValue,
|
33
|
+
"ChatMessagePromptBlock": ChatMessagePromptBlock,
|
34
|
+
}
|
35
|
+
|
36
|
+
|
37
|
+
def resolve_types(value: Union[BaseDescriptor[_T], _T]) -> Tuple[Type[_T], ...]:
|
38
|
+
if isinstance(value, BaseDescriptor):
|
39
|
+
return value.types
|
40
|
+
|
41
|
+
return (value.__class__,)
|
42
|
+
|
43
|
+
|
44
|
+
def resolve_combined_types(
|
45
|
+
lhs: Union[BaseDescriptor[_LHS], _LHS], rhs: Union[BaseDescriptor[_RHS], _RHS]
|
46
|
+
) -> Tuple[Union[Type[_LHS], Type[_RHS]], ...]:
|
47
|
+
lhs_types = resolve_types(lhs)
|
48
|
+
rhs_types = resolve_types(rhs)
|
49
|
+
|
50
|
+
unique_results = set(lhs_types) | set(rhs_types)
|
51
|
+
|
52
|
+
return tuple(unique_results)
|
53
|
+
|
54
|
+
|
55
|
+
def infer_types(object_: Type, attr_name: str, localns: Optional[Dict[str, Any]] = None) -> Tuple[Type, ...]:
|
56
|
+
try:
|
57
|
+
class_ = object_
|
58
|
+
type_var_mapping = {}
|
59
|
+
if isinstance(object_, UnderGenericAlias):
|
60
|
+
origin = get_origin(object_)
|
61
|
+
if origin and Generic in origin.__bases__:
|
62
|
+
class_ = origin
|
63
|
+
args = get_args(object_)
|
64
|
+
type_var_mapping = {t: a for t, a in zip(origin.__parameters__, args)}
|
65
|
+
|
66
|
+
type_hints = get_type_hints(class_, localns=LOCAL_NS if localns is None else {**LOCAL_NS, **localns})
|
67
|
+
if attr_name in type_hints:
|
68
|
+
type_hint = type_hints[attr_name]
|
69
|
+
if get_origin(type_hint) is ClassVar:
|
70
|
+
return get_args(type_hint)
|
71
|
+
if isinstance(type_hint, type):
|
72
|
+
return (type_hint,)
|
73
|
+
if isinstance(type_hint, UnionGenericAlias):
|
74
|
+
if get_origin(type_hint) is Union:
|
75
|
+
return get_args(type_hint)
|
76
|
+
if isinstance(type_hint, UnderGenericAlias):
|
77
|
+
return (type_hint,)
|
78
|
+
if isinstance(type_hint, SpecialGenericAlias):
|
79
|
+
return (type_hint,)
|
80
|
+
if isinstance(type_hint, TypeVar):
|
81
|
+
if type_hint in type_var_mapping:
|
82
|
+
return (type_var_mapping[type_hint],)
|
83
|
+
return type_hint.__constraints__
|
84
|
+
|
85
|
+
for base in reversed(class_.__mro__):
|
86
|
+
class_attributes = vars(base)
|
87
|
+
if attr_name in class_attributes:
|
88
|
+
class_attribute = class_attributes[attr_name]
|
89
|
+
return resolve_types(class_attribute)
|
90
|
+
|
91
|
+
raise AttributeError(f"Failed to infer type from attribute {attr_name} on {object_.__name__}")
|
92
|
+
except TypeError:
|
93
|
+
raise AttributeError(
|
94
|
+
f"Found 3.9+ typing syntax for field '{attr_name}' on class '{object_.__name__}' – {object_.__annotations__[attr_name]}. Type annotations must be compatible with python version 3.8. " # noqa: E501
|
95
|
+
)
|
96
|
+
|
97
|
+
|
98
|
+
def get_class_attr_names(cls: Type) -> Set[str]:
|
99
|
+
# gets type-annotated attributes `foo: int`
|
100
|
+
type_annotated_attributes: Set[str] = set()
|
101
|
+
|
102
|
+
# gets attributes declared `foo = 1`
|
103
|
+
class_attributes: Set[str] = set()
|
104
|
+
|
105
|
+
for base in reversed(cls.__mro__):
|
106
|
+
ann = base.__dict__.get("__annotations__", {})
|
107
|
+
type_annotated_attributes.update(ann.keys())
|
108
|
+
|
109
|
+
base_vars = vars(base).keys()
|
110
|
+
class_attributes.update(base_vars)
|
111
|
+
|
112
|
+
# combine and filter out private attributes
|
113
|
+
return {a for a in list(set(class_attributes) | set(type_annotated_attributes)) if not a.startswith("_")}
|
114
|
+
|
115
|
+
|
116
|
+
def deepcopy_with_exclusions(
|
117
|
+
obj: _T,
|
118
|
+
memo: Any,
|
119
|
+
exclusions: Optional[Dict[str, Any]] = None,
|
120
|
+
) -> _T:
|
121
|
+
cls = obj.__class__
|
122
|
+
new_instance = cls.__new__(cls)
|
123
|
+
new_instance.__dict__.update(obj.__dict__)
|
124
|
+
|
125
|
+
exclusions = exclusions or {}
|
126
|
+
|
127
|
+
for key, value in obj.__dict__.items():
|
128
|
+
if key in exclusions:
|
129
|
+
continue
|
130
|
+
new_instance.__dict__[key] = deepcopy(value, memo)
|
131
|
+
|
132
|
+
for key, value in exclusions.items():
|
133
|
+
new_instance.__dict__[key] = value
|
134
|
+
|
135
|
+
return new_instance
|
136
|
+
|
137
|
+
|
138
|
+
def get_class_by_qualname(qualname: str) -> Type:
|
139
|
+
module_name, class_name = qualname.rsplit(".", 1)
|
140
|
+
module = importlib.import_module(module_name)
|
141
|
+
imported_class = getattr(module, class_name)
|
142
|
+
if not isinstance(imported_class, type):
|
143
|
+
raise ValueError(f"Class {qualname} is not a valid type")
|
144
|
+
|
145
|
+
return imported_class
|
146
|
+
|
147
|
+
|
148
|
+
def datetime_now() -> datetime:
|
149
|
+
"""
|
150
|
+
There's a race condition between freezegun and pydantic that causes `PydanticSchemaGenerationError`
|
151
|
+
because freezegun monkey-patches `datetime.now` to return a frozen datetime. This helper provides
|
152
|
+
an alternative way to facilitate testing that doesn't rely on freezegun.
|
153
|
+
"""
|
154
|
+
|
155
|
+
return datetime.now()
|
156
|
+
|
157
|
+
|
158
|
+
def get_original_base(cls: Type) -> Type:
|
159
|
+
if not hasattr(cls, "__orig_bases__"):
|
160
|
+
return type(None)
|
161
|
+
|
162
|
+
# in Python 3.12, there is `from types import get_original_bases`, making this future proof
|
163
|
+
# https://docs.python.org/3/library/types.html#types.get_original_bases
|
164
|
+
return cls.__orig_bases__[0] # type: ignore[attr-defined]
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import re
|
2
|
+
|
3
|
+
|
4
|
+
def pascal_to_title_case(pascal_str: str) -> str:
|
5
|
+
# Insert space before each capital letter (except the first one)
|
6
|
+
title_case_str = re.sub(r"(?<!^)(?=[A-Z])", " ", pascal_str)
|
7
|
+
|
8
|
+
# Return the result in title case
|
9
|
+
return title_case_str.title()
|
10
|
+
|
11
|
+
|
12
|
+
def snake_to_title_case(snake_str: str) -> str:
|
13
|
+
return pascal_to_title_case(snake_str.replace("_", " "))
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from vellum.workflows.utils.names import pascal_to_title_case
|
4
|
+
|
5
|
+
|
6
|
+
@pytest.mark.parametrize(
|
7
|
+
["input_str", "expected"],
|
8
|
+
[
|
9
|
+
("MyPascalCaseString", "My Pascal Case String"),
|
10
|
+
("AnotherPascalCaseString", "Another Pascal Case String"),
|
11
|
+
],
|
12
|
+
)
|
13
|
+
def test_pascal_to_title_case(input_str, expected):
|
14
|
+
actual = pascal_to_title_case(input_str)
|
15
|
+
assert actual == expected
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import pytest
|
2
|
+
from typing import List, Optional
|
3
|
+
|
4
|
+
from vellum import ChatMessage, SearchResult
|
5
|
+
|
6
|
+
from vellum.workflows.utils.vellum_variables import primitive_type_to_vellum_variable_type
|
7
|
+
|
8
|
+
|
9
|
+
@pytest.mark.parametrize(
|
10
|
+
"type_, expected",
|
11
|
+
[
|
12
|
+
(str, "STRING"),
|
13
|
+
(Optional[str], "STRING"),
|
14
|
+
(int, "NUMBER"),
|
15
|
+
(Optional[int], "NUMBER"),
|
16
|
+
(float, "NUMBER"),
|
17
|
+
(Optional[float], "NUMBER"),
|
18
|
+
(List[ChatMessage], "CHAT_HISTORY"),
|
19
|
+
(Optional[List[ChatMessage]], "CHAT_HISTORY"),
|
20
|
+
(List[SearchResult], "SEARCH_RESULTS"),
|
21
|
+
(Optional[List[SearchResult]], "SEARCH_RESULTS"),
|
22
|
+
],
|
23
|
+
)
|
24
|
+
def test_primitive_type_to_vellum_variable_type(type_, expected):
|
25
|
+
assert primitive_type_to_vellum_variable_type(type_) == expected
|
@@ -0,0 +1,81 @@
|
|
1
|
+
from typing import List, Tuple, Type, Union, get_args, get_origin
|
2
|
+
|
3
|
+
from vellum import (
|
4
|
+
ChatMessage,
|
5
|
+
ChatMessageRequest,
|
6
|
+
FunctionCall,
|
7
|
+
FunctionCallRequest,
|
8
|
+
SearchResult,
|
9
|
+
SearchResultRequest,
|
10
|
+
VellumAudio,
|
11
|
+
VellumAudioRequest,
|
12
|
+
VellumError,
|
13
|
+
VellumErrorRequest,
|
14
|
+
VellumImage,
|
15
|
+
VellumImageRequest,
|
16
|
+
VellumValue,
|
17
|
+
VellumValueRequest,
|
18
|
+
VellumVariableType,
|
19
|
+
)
|
20
|
+
|
21
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
22
|
+
|
23
|
+
|
24
|
+
def primitive_type_to_vellum_variable_type(type_: Union[Type, BaseDescriptor]) -> VellumVariableType:
|
25
|
+
"""Converts a python primitive to a VellumVariableType"""
|
26
|
+
if isinstance(type_, BaseDescriptor):
|
27
|
+
# Ignore None because those just make types optional
|
28
|
+
types = [t for t in type_.types if t is not type(None)]
|
29
|
+
|
30
|
+
# default to JSON for typevars where the types is empty tuple
|
31
|
+
if len(types) == 0:
|
32
|
+
return "JSON"
|
33
|
+
|
34
|
+
if len(types) != 1:
|
35
|
+
raise ValueError(f"Expected Descriptor to only have one type, got {types}")
|
36
|
+
|
37
|
+
type_ = type_.types[0]
|
38
|
+
|
39
|
+
if _is_type_optionally_equal(type_, str):
|
40
|
+
return "STRING"
|
41
|
+
elif _is_type_optionally_in(type_, (int, float)):
|
42
|
+
return "NUMBER"
|
43
|
+
elif _is_type_optionally_in(type_, (FunctionCall, FunctionCallRequest)):
|
44
|
+
return "FUNCTION_CALL"
|
45
|
+
elif _is_type_optionally_in(type_, (VellumImage, VellumImageRequest)):
|
46
|
+
return "IMAGE"
|
47
|
+
elif _is_type_optionally_in(type_, (VellumAudio, VellumAudioRequest)):
|
48
|
+
return "AUDIO"
|
49
|
+
elif _is_type_optionally_in(type_, (VellumError, VellumErrorRequest)):
|
50
|
+
return "ERROR"
|
51
|
+
elif _is_type_optionally_in(type_, (List[ChatMessage], List[ChatMessageRequest])):
|
52
|
+
return "CHAT_HISTORY"
|
53
|
+
elif _is_type_optionally_in(type_, (List[SearchResult], List[SearchResultRequest])):
|
54
|
+
return "SEARCH_RESULTS"
|
55
|
+
elif _is_type_optionally_in(type_, (List[VellumValue], List[VellumValueRequest])):
|
56
|
+
return "ARRAY"
|
57
|
+
|
58
|
+
return "JSON"
|
59
|
+
|
60
|
+
|
61
|
+
def _is_type_optionally_equal(type_: Type, target_type: Type) -> bool:
|
62
|
+
if type_ == target_type:
|
63
|
+
return True
|
64
|
+
|
65
|
+
origin = get_origin(type_)
|
66
|
+
if origin is not Union:
|
67
|
+
return False
|
68
|
+
|
69
|
+
args = get_args(type_)
|
70
|
+
if len(args) != 2:
|
71
|
+
return False
|
72
|
+
|
73
|
+
source_type, none_type = args
|
74
|
+
if none_type is not type(None):
|
75
|
+
return False
|
76
|
+
|
77
|
+
return _is_type_optionally_equal(source_type, target_type)
|
78
|
+
|
79
|
+
|
80
|
+
def _is_type_optionally_in(type_: Type, target_types: Tuple[Type, ...]) -> bool:
|
81
|
+
return any(_is_type_optionally_equal(type_, target_type) for target_type in target_types)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import os
|
2
|
+
from typing import Optional
|
3
|
+
|
4
|
+
from vellum import Vellum, VellumEnvironment
|
5
|
+
|
6
|
+
|
7
|
+
def create_vellum_client(api_key: Optional[str] = None) -> Vellum:
|
8
|
+
if api_key is None:
|
9
|
+
api_key = os.getenv("VELLUM_API_KEY", default="")
|
10
|
+
|
11
|
+
return Vellum(
|
12
|
+
api_key=api_key,
|
13
|
+
environment=VellumEnvironment(
|
14
|
+
default=os.getenv("VELLUM_DEFAULT_API_URL", os.getenv("VELLUM_API_URL", "https://api.vellum.ai")),
|
15
|
+
documents=os.getenv("VELLUM_DOCUMENTS_API_URL", os.getenv("VELLUM_API_URL", "https://documents.vellum.ai")),
|
16
|
+
predict=os.getenv("VELLUM_PREDICT_API_URL", os.getenv("VELLUM_API_URL", "https://predict.vellum.ai")),
|
17
|
+
),
|
18
|
+
)
|