vellum-ai 0.9.16rc2__py3-none-any.whl → 0.9.16rc4__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.9.16rc4.dist-info}/METADATA +2 -1
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.9.16rc4.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.9.16rc4.dist-info}/LICENSE +0 -0
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.9.16rc4.dist-info}/WHEEL +0 -0
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.9.16rc4.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<h1 align="center">
|
3
|
+
Vellum Workflows SDK
|
4
|
+
</h1>
|
5
|
+
<p align="center">
|
6
|
+
<a href="https://docs.vellum.ai/developers/workflows-sdk">Learn more</a>
|
7
|
+
·
|
8
|
+
<a href="https://www.vellum.ai/landing-pages/request-demo">Talk to us</a>
|
9
|
+
</p>
|
10
|
+
</p>
|
11
|
+
|
12
|
+
# Introduction
|
13
|
+
|
14
|
+
The Vellum Workflows SDK is a framework for defining and executing complex AI systems as graphs.
|
15
|
+
|
16
|
+
The Vellum Workflows SDK provides a declarative python syntax for both defining and executing the control flow of graphs.
|
17
|
+
Unlike other graph execution frameworks, which are functional or event-driven in nature, Vellum's Workflows SDK defines the control flow of a graph
|
18
|
+
statically and makes use of strict typing. This means that the structure of the graph is known ahead of time, and you get all the benefits of type
|
19
|
+
safety and intellisense. This ultimately makes it easier to build more predictable and robust AI systems.
|
20
|
+
|
21
|
+
Unique amongst other frameworks, Vellum's Workflows SDK also allows you to _visualize, edit, and execute_ your graph in a UI, pushing and pulling changes from
|
22
|
+
code to UI and vice versa.
|
23
|
+
|
24
|
+
|
25
|
+
## Core Features
|
26
|
+
- **Nodes**: Nodes are the basic building blocks of a graph. They represent a single task or function that can be executed.
|
27
|
+
- **Graph Syntax**: An intuitive declarative syntax for defining the control flow of a graph.
|
28
|
+
- **Inputs and Outputs**: Both the Workflow itslef and individual Nodes can take in inputs and produce outputs, which can be used to pass information between nodes.
|
29
|
+
- **State**: Nodes can read and write to the graph's global state, which can be used to share information between nodes without defining explicit inputs and outputs.
|
30
|
+
- **Advanced Control Flow**: Support for looping, conditionals, paralellism, state forking, and more.
|
31
|
+
- **Streaming**: Nodes can stream output values back to the runner, allowing for long-running tasks like chat completions to return partial results.
|
32
|
+
- **Human-in-the-loop**: Nodes can wait for External Inputs, allowing for a pause in the Workflow until a human or external system provides input.
|
33
|
+
- **UI Integration**: Push and pull changes from code to Vellum's UI and vice versa, allowing for rapid testing and iteration.
|
34
|
+
|
35
|
+
## Quickstart
|
36
|
+
|
37
|
+
1. Install the Vellum Workflows SDK:
|
38
|
+
|
39
|
+
```bash
|
40
|
+
pip install vellum-ai
|
41
|
+
```
|
42
|
+
|
43
|
+
2. Import the Vellum Workflows SDK and define your first Workflow:
|
44
|
+
|
45
|
+
```python
|
46
|
+
# my_workflow.py
|
47
|
+
|
48
|
+
from workflows import BaseWorkflow
|
49
|
+
from workflows.nodes import BaseNode
|
50
|
+
|
51
|
+
|
52
|
+
class MyNode(BaseNode):
|
53
|
+
|
54
|
+
class Outputs(BaseNode.Outputs):
|
55
|
+
result: str
|
56
|
+
|
57
|
+
def run(self):
|
58
|
+
return self.Outputs(result="Hello, World!")
|
59
|
+
|
60
|
+
|
61
|
+
class MyWorkflow(BaseWorkflow):
|
62
|
+
graph = MyNode
|
63
|
+
|
64
|
+
class Outputs(BaseWorkflow.Outputs):
|
65
|
+
result = MyNode.Outputs.result
|
66
|
+
|
67
|
+
|
68
|
+
if __name__ == "__main__":
|
69
|
+
workflow = MyWorkflow()
|
70
|
+
result = workflow.run()
|
71
|
+
|
72
|
+
print(result.outputs.result)
|
73
|
+
|
74
|
+
```
|
75
|
+
3. Run it!
|
76
|
+
|
77
|
+
```bash
|
78
|
+
python my_workflow.py
|
79
|
+
|
80
|
+
Note: To use most out-of-box Nodes, and to push/pull to/from the Velłum UI, you'll need a Vellum account and API key. [Talk to us](https://www.vellum.ai/landing-pages/request-demo) or visit our [pricing page](https://www.vellum.ai/pricing) for more information.
|
81
|
+
|
82
|
+
|
83
|
+
## Documentation
|
84
|
+
Complete documentation for the Vellum Workflows SDK can be found at https://docs.vellum.ai/developers/workflows-sdk.
|
85
|
+
|
86
|
+
|
87
|
+
## Stability
|
88
|
+
|
89
|
+
This SDK is currently in <Availability type="beta" /> and is subject to change. If you'd like to pariticpate in
|
90
|
+
our beta program, please [contact us](https://docs.vellum.ai/home/getting-started/support).
|
@@ -0,0 +1,43 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
from typing import Any, cast
|
3
|
+
|
4
|
+
|
5
|
+
class _UndefMeta(type):
|
6
|
+
def __repr__(cls) -> str:
|
7
|
+
return "UNDEF"
|
8
|
+
|
9
|
+
def __getattribute__(cls, name: str) -> Any:
|
10
|
+
if name == "__class__":
|
11
|
+
# ensures that UNDEF.__class__ == UNDEF
|
12
|
+
return cls
|
13
|
+
|
14
|
+
return super().__getattribute__(name)
|
15
|
+
|
16
|
+
def __bool__(cls) -> bool:
|
17
|
+
return False
|
18
|
+
|
19
|
+
|
20
|
+
class UNDEF(metaclass=_UndefMeta):
|
21
|
+
pass
|
22
|
+
|
23
|
+
|
24
|
+
LATEST_RELEASE_TAG = "LATEST"
|
25
|
+
|
26
|
+
OMIT = cast(Any, ...)
|
27
|
+
|
28
|
+
|
29
|
+
class APIRequestMethod(Enum):
|
30
|
+
GET = "GET"
|
31
|
+
POST = "POST"
|
32
|
+
PUT = "PUT"
|
33
|
+
DELETE = "DELETE"
|
34
|
+
PATCH = "PATCH"
|
35
|
+
OPTIONS = "OPTIONS"
|
36
|
+
HEAD = "HEAD"
|
37
|
+
CONNECT = "CONNECT"
|
38
|
+
TRACE = "TRACE"
|
39
|
+
|
40
|
+
|
41
|
+
class AuthorizationType(Enum):
|
42
|
+
BEARER_TOKEN = "BEARER_TOKEN"
|
43
|
+
API_KEY = "API_KEY"
|
File without changes
|
@@ -0,0 +1,339 @@
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Generic, Optional, Tuple, Type, TypeVar, Union, cast, overload
|
2
|
+
|
3
|
+
if TYPE_CHECKING:
|
4
|
+
from vellum.workflows.expressions.accessor import AccessorExpression
|
5
|
+
from vellum.workflows.expressions.and_ import AndExpression
|
6
|
+
from vellum.workflows.expressions.begins_with import BeginsWithExpression
|
7
|
+
from vellum.workflows.expressions.between import BetweenExpression
|
8
|
+
from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
|
9
|
+
from vellum.workflows.expressions.contains import ContainsExpression
|
10
|
+
from vellum.workflows.expressions.does_not_begin_with import DoesNotBeginWithExpression
|
11
|
+
from vellum.workflows.expressions.does_not_contain import DoesNotContainExpression
|
12
|
+
from vellum.workflows.expressions.does_not_end_with import DoesNotEndWithExpression
|
13
|
+
from vellum.workflows.expressions.does_not_equal import DoesNotEqualExpression
|
14
|
+
from vellum.workflows.expressions.ends_with import EndsWithExpression
|
15
|
+
from vellum.workflows.expressions.equals import EqualsExpression
|
16
|
+
from vellum.workflows.expressions.greater_than import GreaterThanExpression
|
17
|
+
from vellum.workflows.expressions.greater_than_or_equal_to import GreaterThanOrEqualToExpression
|
18
|
+
from vellum.workflows.expressions.in_ import InExpression
|
19
|
+
from vellum.workflows.expressions.is_blank import IsBlankExpression
|
20
|
+
from vellum.workflows.expressions.is_not_blank import IsNotBlankExpression
|
21
|
+
from vellum.workflows.expressions.is_not_null import IsNotNullExpression
|
22
|
+
from vellum.workflows.expressions.is_not_undefined import IsNotUndefinedExpression
|
23
|
+
from vellum.workflows.expressions.is_null import IsNullExpression
|
24
|
+
from vellum.workflows.expressions.is_undefined import IsUndefinedExpression
|
25
|
+
from vellum.workflows.expressions.less_than import LessThanExpression
|
26
|
+
from vellum.workflows.expressions.less_than_or_equal_to import LessThanOrEqualToExpression
|
27
|
+
from vellum.workflows.expressions.not_between import NotBetweenExpression
|
28
|
+
from vellum.workflows.expressions.not_in import NotInExpression
|
29
|
+
from vellum.workflows.expressions.or_ import OrExpression
|
30
|
+
from vellum.workflows.nodes.bases import BaseNode
|
31
|
+
from vellum.workflows.state.base import BaseState
|
32
|
+
|
33
|
+
_T = TypeVar("_T")
|
34
|
+
_O = TypeVar("_O")
|
35
|
+
_O2 = TypeVar("_O2")
|
36
|
+
|
37
|
+
|
38
|
+
class BaseDescriptor(Generic[_T]):
|
39
|
+
_name: str
|
40
|
+
_types: Tuple[Type[_T], ...]
|
41
|
+
_instance: Optional[_T]
|
42
|
+
|
43
|
+
def __init__(self, *, name: str, types: Tuple[Type[_T], ...], instance: Optional[_T] = None) -> None:
|
44
|
+
self._name = name
|
45
|
+
self._types = types
|
46
|
+
self._instance = instance
|
47
|
+
|
48
|
+
@property
|
49
|
+
def name(self) -> str:
|
50
|
+
return self._name
|
51
|
+
|
52
|
+
@property
|
53
|
+
def types(self) -> Tuple[Type[_T], ...]:
|
54
|
+
return self._types
|
55
|
+
|
56
|
+
@property
|
57
|
+
def instance(self) -> Optional[_T]:
|
58
|
+
return self._instance
|
59
|
+
|
60
|
+
def resolve(self, state: "BaseState") -> _T:
|
61
|
+
raise NotImplementedError("Descriptor must implement resolve method")
|
62
|
+
|
63
|
+
def __eq__(self, other: object) -> bool:
|
64
|
+
if not isinstance(other, type(self)):
|
65
|
+
return False
|
66
|
+
return self._name == other._name
|
67
|
+
|
68
|
+
def __hash__(self) -> int:
|
69
|
+
return hash(self._name)
|
70
|
+
|
71
|
+
@overload
|
72
|
+
def __get__(self, instance: "BaseNode", owner: Type["BaseNode"]) -> _T: ...
|
73
|
+
|
74
|
+
@overload
|
75
|
+
def __get__(self, instance: Any, owner: Optional[Type]) -> "BaseDescriptor[_T]": ...
|
76
|
+
|
77
|
+
def __get__(self, instance: Any, owner: Optional[Type]) -> Union["BaseDescriptor[_T]", _T]:
|
78
|
+
if not instance:
|
79
|
+
return self
|
80
|
+
|
81
|
+
if instance.__class__.__name__ == "BaseNode":
|
82
|
+
node = cast("BaseNode", instance)
|
83
|
+
return self.resolve(node.state)
|
84
|
+
|
85
|
+
return self
|
86
|
+
|
87
|
+
# TODO: We should figure out how to remove these dynamic imports
|
88
|
+
# https://app.shortcut.com/vellum/story/4504
|
89
|
+
@overload
|
90
|
+
def __or__(self, other: "BaseDescriptor[_O]") -> "OrExpression[_T, _O]": ...
|
91
|
+
|
92
|
+
@overload
|
93
|
+
def __or__(self, other: _O) -> "OrExpression[_T, _O]": ...
|
94
|
+
|
95
|
+
def __or__(self, other: "Union[BaseDescriptor[_O], _O]") -> "OrExpression[_T, _O]":
|
96
|
+
from vellum.workflows.expressions.or_ import OrExpression
|
97
|
+
|
98
|
+
return OrExpression(lhs=self, rhs=other)
|
99
|
+
|
100
|
+
@overload
|
101
|
+
def __and__(self, other: "BaseDescriptor[_O]") -> "AndExpression[_T, _O]": ...
|
102
|
+
|
103
|
+
@overload
|
104
|
+
def __and__(self, other: _O) -> "AndExpression[_T, _O]": ...
|
105
|
+
|
106
|
+
def __and__(self, other: "Union[BaseDescriptor[_O], _O]") -> "AndExpression[_T, _O]":
|
107
|
+
from vellum.workflows.expressions.and_ import AndExpression
|
108
|
+
|
109
|
+
return AndExpression(lhs=self, rhs=other)
|
110
|
+
|
111
|
+
@overload
|
112
|
+
def coalesce(self, other: "BaseDescriptor[_O]") -> "CoalesceExpression[_T, _O]": ...
|
113
|
+
|
114
|
+
@overload
|
115
|
+
def coalesce(self, other: _O) -> "CoalesceExpression[_T, _O]": ...
|
116
|
+
|
117
|
+
def coalesce(self, other: "Union[BaseDescriptor[_O], _O]") -> "CoalesceExpression[_T, _O]":
|
118
|
+
from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
|
119
|
+
|
120
|
+
return CoalesceExpression(lhs=self, rhs=other)
|
121
|
+
|
122
|
+
def __getitem__(self, field: str) -> "AccessorExpression":
|
123
|
+
from vellum.workflows.expressions.accessor import AccessorExpression
|
124
|
+
|
125
|
+
return AccessorExpression(base=self, field=field)
|
126
|
+
|
127
|
+
@overload
|
128
|
+
def equals(self, other: "BaseDescriptor[_O]") -> "EqualsExpression[_T, _O]": ...
|
129
|
+
|
130
|
+
@overload
|
131
|
+
def equals(self, other: _O) -> "EqualsExpression[_T, _O]": ...
|
132
|
+
|
133
|
+
def equals(self, other: "Union[BaseDescriptor[_O], _O]") -> "EqualsExpression[_T, _O]":
|
134
|
+
from vellum.workflows.expressions.equals import EqualsExpression
|
135
|
+
|
136
|
+
return EqualsExpression(lhs=self, rhs=other)
|
137
|
+
|
138
|
+
@overload
|
139
|
+
def does_not_equal(self, other: "BaseDescriptor[_O]") -> "DoesNotEqualExpression[_T, _O]": ...
|
140
|
+
|
141
|
+
@overload
|
142
|
+
def does_not_equal(self, other: _O) -> "DoesNotEqualExpression[_T, _O]": ...
|
143
|
+
|
144
|
+
def does_not_equal(self, other: "Union[BaseDescriptor[_O], _O]") -> "DoesNotEqualExpression[_T, _O]":
|
145
|
+
from vellum.workflows.expressions.does_not_equal import DoesNotEqualExpression
|
146
|
+
|
147
|
+
return DoesNotEqualExpression(lhs=self, rhs=other)
|
148
|
+
|
149
|
+
@overload
|
150
|
+
def less_than(self, other: "BaseDescriptor[_O]") -> "LessThanExpression[_T, _O]": ...
|
151
|
+
|
152
|
+
@overload
|
153
|
+
def less_than(self, other: _O) -> "LessThanExpression[_T, _O]": ...
|
154
|
+
|
155
|
+
def less_than(self, other: "Union[BaseDescriptor[_O], _O]") -> "LessThanExpression[_T, _O]":
|
156
|
+
from vellum.workflows.expressions.less_than import LessThanExpression
|
157
|
+
|
158
|
+
return LessThanExpression(lhs=self, rhs=other)
|
159
|
+
|
160
|
+
@overload
|
161
|
+
def greater_than(self, other: "BaseDescriptor[_O]") -> "GreaterThanExpression[_T, _O]": ...
|
162
|
+
|
163
|
+
@overload
|
164
|
+
def greater_than(self, other: _O) -> "GreaterThanExpression[_T, _O]": ...
|
165
|
+
|
166
|
+
def greater_than(self, other: "Union[BaseDescriptor[_O], _O]") -> "GreaterThanExpression[_T, _O]":
|
167
|
+
from vellum.workflows.expressions.greater_than import GreaterThanExpression
|
168
|
+
|
169
|
+
return GreaterThanExpression(lhs=self, rhs=other)
|
170
|
+
|
171
|
+
@overload
|
172
|
+
def less_than_or_equal_to(self, other: "BaseDescriptor[_O]") -> "LessThanOrEqualToExpression[_T, _O]": ...
|
173
|
+
|
174
|
+
@overload
|
175
|
+
def less_than_or_equal_to(self, other: _O) -> "LessThanOrEqualToExpression[_T, _O]": ...
|
176
|
+
|
177
|
+
def less_than_or_equal_to(self, other: "Union[BaseDescriptor[_O], _O]") -> "LessThanOrEqualToExpression[_T, _O]":
|
178
|
+
from vellum.workflows.expressions.less_than_or_equal_to import LessThanOrEqualToExpression
|
179
|
+
|
180
|
+
return LessThanOrEqualToExpression(lhs=self, rhs=other)
|
181
|
+
|
182
|
+
@overload
|
183
|
+
def greater_than_or_equal_to(self, other: "BaseDescriptor[_O]") -> "GreaterThanOrEqualToExpression[_T, _O]": ...
|
184
|
+
|
185
|
+
@overload
|
186
|
+
def greater_than_or_equal_to(self, other: _O) -> "GreaterThanOrEqualToExpression[_T, _O]": ...
|
187
|
+
|
188
|
+
def greater_than_or_equal_to(
|
189
|
+
self, other: "Union[BaseDescriptor[_O], _O]"
|
190
|
+
) -> "GreaterThanOrEqualToExpression[_T, _O]":
|
191
|
+
from vellum.workflows.expressions.greater_than_or_equal_to import GreaterThanOrEqualToExpression
|
192
|
+
|
193
|
+
return GreaterThanOrEqualToExpression(lhs=self, rhs=other)
|
194
|
+
|
195
|
+
@overload
|
196
|
+
def contains(self, other: "BaseDescriptor[_O]") -> "ContainsExpression[_T, _O]": ...
|
197
|
+
|
198
|
+
@overload
|
199
|
+
def contains(self, other: _O) -> "ContainsExpression[_T, _O]": ...
|
200
|
+
|
201
|
+
def contains(self, other: "Union[BaseDescriptor[_O], _O]") -> "ContainsExpression[_T, _O]":
|
202
|
+
from vellum.workflows.expressions.contains import ContainsExpression
|
203
|
+
|
204
|
+
return ContainsExpression(lhs=self, rhs=other)
|
205
|
+
|
206
|
+
@overload
|
207
|
+
def begins_with(self, other: "BaseDescriptor[_O]") -> "BeginsWithExpression[_T, _O]": ...
|
208
|
+
|
209
|
+
@overload
|
210
|
+
def begins_with(self, other: _O) -> "BeginsWithExpression[_T, _O]": ...
|
211
|
+
|
212
|
+
def begins_with(self, other: "Union[BaseDescriptor[_O], _O]") -> "BeginsWithExpression[_T, _O]":
|
213
|
+
from vellum.workflows.expressions.begins_with import BeginsWithExpression
|
214
|
+
|
215
|
+
return BeginsWithExpression(lhs=self, rhs=other)
|
216
|
+
|
217
|
+
@overload
|
218
|
+
def ends_with(self, other: "BaseDescriptor[_O]") -> "EndsWithExpression[_T, _O]": ...
|
219
|
+
|
220
|
+
@overload
|
221
|
+
def ends_with(self, other: _O) -> "EndsWithExpression[_T, _O]": ...
|
222
|
+
|
223
|
+
def ends_with(self, other: "Union[BaseDescriptor[_O], _O]") -> "EndsWithExpression[_T, _O]":
|
224
|
+
from vellum.workflows.expressions.ends_with import EndsWithExpression
|
225
|
+
|
226
|
+
return EndsWithExpression(lhs=self, rhs=other)
|
227
|
+
|
228
|
+
@overload
|
229
|
+
def does_not_contain(self, other: "BaseDescriptor[_O]") -> "DoesNotContainExpression[_T, _O]": ...
|
230
|
+
|
231
|
+
@overload
|
232
|
+
def does_not_contain(self, other: _O) -> "DoesNotContainExpression[_T, _O]": ...
|
233
|
+
|
234
|
+
def does_not_contain(self, other: "Union[BaseDescriptor[_O], _O]") -> "DoesNotContainExpression[_T, _O]":
|
235
|
+
from vellum.workflows.expressions.does_not_contain import DoesNotContainExpression
|
236
|
+
|
237
|
+
return DoesNotContainExpression(lhs=self, rhs=other)
|
238
|
+
|
239
|
+
@overload
|
240
|
+
def does_not_begin_with(self, other: "BaseDescriptor[_O]") -> "DoesNotBeginWithExpression[_T, _O]": ...
|
241
|
+
|
242
|
+
@overload
|
243
|
+
def does_not_begin_with(self, other: _O) -> "DoesNotBeginWithExpression[_T, _O]": ...
|
244
|
+
|
245
|
+
def does_not_begin_with(self, other: "Union[BaseDescriptor[_O], _O]") -> "DoesNotBeginWithExpression[_T, _O]":
|
246
|
+
from vellum.workflows.expressions.does_not_begin_with import DoesNotBeginWithExpression
|
247
|
+
|
248
|
+
return DoesNotBeginWithExpression(lhs=self, rhs=other)
|
249
|
+
|
250
|
+
@overload
|
251
|
+
def does_not_end_with(self, other: "BaseDescriptor[_O]") -> "DoesNotEndWithExpression[_T, _O]": ...
|
252
|
+
|
253
|
+
@overload
|
254
|
+
def does_not_end_with(self, other: _O) -> "DoesNotEndWithExpression[_T, _O]": ...
|
255
|
+
|
256
|
+
def does_not_end_with(self, other: "Union[BaseDescriptor[_O], _O]") -> "DoesNotEndWithExpression[_T, _O]":
|
257
|
+
from vellum.workflows.expressions.does_not_end_with import DoesNotEndWithExpression
|
258
|
+
|
259
|
+
return DoesNotEndWithExpression(lhs=self, rhs=other)
|
260
|
+
|
261
|
+
def is_none(self) -> "IsNullExpression":
|
262
|
+
from vellum.workflows.expressions.is_null import IsNullExpression
|
263
|
+
|
264
|
+
return IsNullExpression(expression=self)
|
265
|
+
|
266
|
+
def is_not_none(self) -> "IsNotNullExpression":
|
267
|
+
from vellum.workflows.expressions.is_not_null import IsNotNullExpression
|
268
|
+
|
269
|
+
return IsNotNullExpression(expression=self)
|
270
|
+
|
271
|
+
def is_undefined(self) -> "IsUndefinedExpression":
|
272
|
+
from vellum.workflows.expressions.is_undefined import IsUndefinedExpression
|
273
|
+
|
274
|
+
return IsUndefinedExpression(expression=self)
|
275
|
+
|
276
|
+
def is_not_undefined(self) -> "IsNotUndefinedExpression":
|
277
|
+
from vellum.workflows.expressions.is_not_undefined import IsNotUndefinedExpression
|
278
|
+
|
279
|
+
return IsNotUndefinedExpression(expression=self)
|
280
|
+
|
281
|
+
@overload
|
282
|
+
def in_(self, other: "BaseDescriptor[_O]") -> "InExpression[_T, _O]": ...
|
283
|
+
|
284
|
+
@overload
|
285
|
+
def in_(self, other: _O) -> "InExpression[_T, _O]": ...
|
286
|
+
|
287
|
+
def in_(self, other: "Union[BaseDescriptor[_O], _O]") -> "InExpression[_T, _O]":
|
288
|
+
from vellum.workflows.expressions.in_ import InExpression
|
289
|
+
|
290
|
+
return InExpression(lhs=self, rhs=other)
|
291
|
+
|
292
|
+
@overload
|
293
|
+
def not_in(self, other: "BaseDescriptor[_O]") -> "NotInExpression[_T, _O]": ...
|
294
|
+
|
295
|
+
@overload
|
296
|
+
def not_in(self, other: _O) -> "NotInExpression[_T, _O]": ...
|
297
|
+
|
298
|
+
def not_in(self, other: "Union[BaseDescriptor[_O], _O]") -> "NotInExpression[_T, _O]":
|
299
|
+
from vellum.workflows.expressions.not_in import NotInExpression
|
300
|
+
|
301
|
+
return NotInExpression(lhs=self, rhs=other)
|
302
|
+
|
303
|
+
@overload
|
304
|
+
def between(self, start: "BaseDescriptor[_O]", end: "BaseDescriptor[_O2]") -> "BetweenExpression[_T, _O, _O2]": ...
|
305
|
+
|
306
|
+
@overload
|
307
|
+
def between(self, start: _O, end: _O2) -> "BetweenExpression[_T, _O, _O2]": ...
|
308
|
+
|
309
|
+
def between(
|
310
|
+
self, start: "Union[BaseDescriptor[_O], _O]", end: "Union[BaseDescriptor[_O2], _O2]"
|
311
|
+
) -> "BetweenExpression[_T, _O, _O2]":
|
312
|
+
from vellum.workflows.expressions.between import BetweenExpression
|
313
|
+
|
314
|
+
return BetweenExpression(value=self, start=start, end=end)
|
315
|
+
|
316
|
+
@overload
|
317
|
+
def not_between(
|
318
|
+
self, start: "BaseDescriptor[_O]", end: "BaseDescriptor[_O2]"
|
319
|
+
) -> "NotBetweenExpression[_T, _O, _O2]": ...
|
320
|
+
|
321
|
+
@overload
|
322
|
+
def not_between(self, start: _O, end: _O2) -> "NotBetweenExpression[_T, _O, _O2]": ...
|
323
|
+
|
324
|
+
def not_between(
|
325
|
+
self, start: "Union[BaseDescriptor[_O], _O]", end: "Union[BaseDescriptor[_O2], _O2]"
|
326
|
+
) -> "NotBetweenExpression[_T, _O, _O2]":
|
327
|
+
from vellum.workflows.expressions.not_between import NotBetweenExpression
|
328
|
+
|
329
|
+
return NotBetweenExpression(value=self, start=start, end=end)
|
330
|
+
|
331
|
+
def is_blank(self) -> "IsBlankExpression":
|
332
|
+
from vellum.workflows.expressions.is_blank import IsBlankExpression
|
333
|
+
|
334
|
+
return IsBlankExpression(expression=self)
|
335
|
+
|
336
|
+
def is_not_blank(self) -> "IsNotBlankExpression":
|
337
|
+
from vellum.workflows.expressions.is_not_blank import IsNotBlankExpression
|
338
|
+
|
339
|
+
return IsNotBlankExpression(expression=self)
|
@@ -0,0 +1,83 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from vellum.workflows.descriptors.utils import resolve_value
|
4
|
+
from vellum.workflows.state.base import BaseState
|
5
|
+
|
6
|
+
|
7
|
+
class FixtureState(BaseState):
|
8
|
+
alpha = 1
|
9
|
+
beta = 2
|
10
|
+
|
11
|
+
gamma = "hello"
|
12
|
+
delta = "el"
|
13
|
+
|
14
|
+
epsilon = 3
|
15
|
+
zeta = {
|
16
|
+
"foo": "bar",
|
17
|
+
}
|
18
|
+
|
19
|
+
|
20
|
+
@pytest.mark.parametrize(
|
21
|
+
["descriptor", "expected_value"],
|
22
|
+
[
|
23
|
+
(FixtureState.alpha | FixtureState.beta, 1),
|
24
|
+
(FixtureState.alpha & FixtureState.beta, 2),
|
25
|
+
(FixtureState.beta.coalesce(FixtureState.alpha), 2),
|
26
|
+
(FixtureState.alpha.equals(FixtureState.beta), False),
|
27
|
+
(FixtureState.alpha.does_not_equal(FixtureState.beta), True),
|
28
|
+
(FixtureState.alpha.less_than(FixtureState.beta), True),
|
29
|
+
(FixtureState.alpha.greater_than(FixtureState.beta), False),
|
30
|
+
(FixtureState.alpha.less_than_or_equal_to(FixtureState.beta), True),
|
31
|
+
(FixtureState.alpha.greater_than_or_equal_to(FixtureState.beta), False),
|
32
|
+
(FixtureState.gamma.contains(FixtureState.delta), True),
|
33
|
+
(FixtureState.gamma.begins_with(FixtureState.delta), False),
|
34
|
+
(FixtureState.gamma.ends_with(FixtureState.delta), False),
|
35
|
+
(FixtureState.gamma.does_not_contain(FixtureState.delta), False),
|
36
|
+
(FixtureState.gamma.does_not_begin_with(FixtureState.delta), True),
|
37
|
+
(FixtureState.gamma.does_not_end_with(FixtureState.delta), True),
|
38
|
+
(FixtureState.alpha.is_none(), False),
|
39
|
+
(FixtureState.alpha.is_not_none(), True),
|
40
|
+
(FixtureState.delta.in_(FixtureState.gamma), True),
|
41
|
+
(FixtureState.delta.not_in(FixtureState.gamma), False),
|
42
|
+
(FixtureState.alpha.between(FixtureState.beta, FixtureState.epsilon), False),
|
43
|
+
(FixtureState.alpha.not_between(FixtureState.beta, FixtureState.epsilon), True),
|
44
|
+
(FixtureState.delta.is_blank(), False),
|
45
|
+
(FixtureState.delta.is_not_blank(), True),
|
46
|
+
(
|
47
|
+
FixtureState.alpha.equals(FixtureState.alpha)
|
48
|
+
| FixtureState.alpha.equals(FixtureState.beta) & FixtureState.alpha.equals(FixtureState.beta),
|
49
|
+
True,
|
50
|
+
),
|
51
|
+
(FixtureState.zeta["foo"], "bar"),
|
52
|
+
],
|
53
|
+
ids=[
|
54
|
+
"or",
|
55
|
+
"and",
|
56
|
+
"coalesce",
|
57
|
+
"eq",
|
58
|
+
"dne",
|
59
|
+
"less_than",
|
60
|
+
"greater_than",
|
61
|
+
"less_than_or_equal_to",
|
62
|
+
"greater_than_or_equal_to",
|
63
|
+
"contains",
|
64
|
+
"begins_with",
|
65
|
+
"ends_with",
|
66
|
+
"does_not_contain",
|
67
|
+
"does_not_begin_with",
|
68
|
+
"does_not_end_with",
|
69
|
+
"is_none",
|
70
|
+
"is_not_none",
|
71
|
+
"in_",
|
72
|
+
"not_in",
|
73
|
+
"between",
|
74
|
+
"not_between",
|
75
|
+
"is_blank",
|
76
|
+
"is_not_blank",
|
77
|
+
"or_and",
|
78
|
+
"accessor",
|
79
|
+
],
|
80
|
+
)
|
81
|
+
def test_resolve_value__happy_path(descriptor, expected_value):
|
82
|
+
actual_value = resolve_value(descriptor, FixtureState())
|
83
|
+
assert actual_value == expected_value
|
@@ -0,0 +1,90 @@
|
|
1
|
+
from collections.abc import Mapping
|
2
|
+
import dataclasses
|
3
|
+
import inspect
|
4
|
+
from typing import Any, Dict, Optional, Sequence, Set, TypeVar, Union, cast, overload
|
5
|
+
|
6
|
+
from pydantic import BaseModel
|
7
|
+
|
8
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
9
|
+
from vellum.workflows.state.base import BaseState
|
10
|
+
|
11
|
+
_T = TypeVar("_T")
|
12
|
+
|
13
|
+
|
14
|
+
@overload
|
15
|
+
def resolve_value(
|
16
|
+
value: BaseDescriptor[_T], state: BaseState, path: str = "", memo: Optional[Dict[str, Any]] = None
|
17
|
+
) -> _T: ...
|
18
|
+
|
19
|
+
|
20
|
+
@overload
|
21
|
+
def resolve_value(value: _T, state: BaseState, path: str = "", memo: Optional[Dict[str, Any]] = None) -> _T: ...
|
22
|
+
|
23
|
+
|
24
|
+
def resolve_value(
|
25
|
+
value: Union[BaseDescriptor[_T], _T], state: BaseState, path: str = "", memo: Optional[Dict[str, Any]] = None
|
26
|
+
) -> _T:
|
27
|
+
"""
|
28
|
+
Recursively resolves Descriptor's until we have a constant value, using BaseState.
|
29
|
+
|
30
|
+
The nonideal casts in this method are due to the `isinstance` calls detaching types
|
31
|
+
from the `_T` generic.
|
32
|
+
"""
|
33
|
+
|
34
|
+
if inspect.isclass(value):
|
35
|
+
return cast(_T, value)
|
36
|
+
|
37
|
+
if isinstance(value, BaseDescriptor):
|
38
|
+
resolved_value = value.resolve(state)
|
39
|
+
if memo is not None:
|
40
|
+
memo[path] = resolved_value
|
41
|
+
return resolved_value
|
42
|
+
|
43
|
+
if isinstance(value, property) or callable(value):
|
44
|
+
return cast(_T, value)
|
45
|
+
|
46
|
+
if isinstance(value, (str, bytes)):
|
47
|
+
return cast(_T, value)
|
48
|
+
|
49
|
+
if dataclasses.is_dataclass(value):
|
50
|
+
# The `inspect.isclass` check above prevents `value` from being a class.
|
51
|
+
dataclass_value = dataclasses.replace( # type: ignore[type-var]
|
52
|
+
value,
|
53
|
+
**{
|
54
|
+
field.name: resolve_value(getattr(value, field.name), state, path=f"{path}.{field.name}", memo=memo)
|
55
|
+
for field in dataclasses.fields(value)
|
56
|
+
},
|
57
|
+
)
|
58
|
+
return cast(_T, dataclass_value)
|
59
|
+
|
60
|
+
if isinstance(value, BaseModel):
|
61
|
+
pydantic_value = value.model_copy(
|
62
|
+
update={
|
63
|
+
key: resolve_value(getattr(value, key), state, path=f"{path}.{key}", memo=memo)
|
64
|
+
for key in value.dict().keys()
|
65
|
+
}
|
66
|
+
)
|
67
|
+
return cast(_T, pydantic_value)
|
68
|
+
|
69
|
+
if isinstance(value, Mapping):
|
70
|
+
mapped_value = type(value)( # type: ignore[call-arg]
|
71
|
+
{
|
72
|
+
dict_key: resolve_value(dict_value, state, path=f"{path}.{dict_key}", memo=memo)
|
73
|
+
for dict_key, dict_value in value.items()
|
74
|
+
}
|
75
|
+
)
|
76
|
+
return cast(_T, mapped_value)
|
77
|
+
|
78
|
+
if isinstance(value, Sequence):
|
79
|
+
sequence_value = type(value)(
|
80
|
+
resolve_value(seq_value, state, path=f"{path}.{index}", memo=memo) for index, seq_value in enumerate(value)
|
81
|
+
) # type: ignore[call-arg]
|
82
|
+
return cast(_T, sequence_value)
|
83
|
+
|
84
|
+
if isinstance(value, Set):
|
85
|
+
set_value = type(value)(
|
86
|
+
resolve_value(set_value, state, path=f"{path}.{index}", memo=memo) for index, set_value in enumerate(value)
|
87
|
+
)
|
88
|
+
return cast(_T, set_value)
|
89
|
+
|
90
|
+
return value
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Type
|
2
|
+
|
3
|
+
if TYPE_CHECKING:
|
4
|
+
from vellum.workflows.nodes.bases import BaseNode
|
5
|
+
from vellum.workflows.ports.port import Port
|
6
|
+
|
7
|
+
|
8
|
+
class Edge:
|
9
|
+
def __init__(self, from_port: "Port", to_node: Type["BaseNode"]):
|
10
|
+
self.from_port = from_port
|
11
|
+
self.to_node = to_node
|
12
|
+
|
13
|
+
def __eq__(self, other: Any) -> bool:
|
14
|
+
if not isinstance(other, Edge):
|
15
|
+
return False
|
16
|
+
|
17
|
+
return self.from_port == other.from_port and self.to_node == other.to_node
|
18
|
+
|
19
|
+
def __hash__(self) -> int:
|
20
|
+
return hash((self.from_port, self.to_node))
|
21
|
+
|
22
|
+
def __repr__(self) -> str:
|
23
|
+
return f"{self.from_port} >> {self.to_node}"
|