vellum-ai 0.11.9__py3-none-any.whl → 0.12.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- vellum/client/core/client_wrapper.py +1 -1
- vellum/workflows/descriptors/base.py +2 -2
- vellum/workflows/descriptors/tests/test_utils.py +4 -4
- vellum/workflows/errors/__init__.py +3 -3
- vellum/workflows/errors/types.py +46 -3
- vellum/workflows/events/node.py +3 -3
- vellum/workflows/events/tests/test_event.py +3 -3
- vellum/workflows/events/workflow.py +3 -3
- vellum/workflows/exceptions.py +8 -4
- vellum/workflows/nodes/bases/base.py +9 -2
- vellum/workflows/nodes/bases/tests/test_base_node.py +13 -0
- vellum/workflows/nodes/core/error_node/node.py +9 -5
- vellum/workflows/nodes/core/inline_subworkflow_node/node.py +3 -13
- vellum/workflows/nodes/core/map_node/node.py +2 -2
- vellum/workflows/nodes/core/retry_node/node.py +5 -5
- vellum/workflows/nodes/core/retry_node/tests/test_node.py +6 -6
- vellum/workflows/nodes/core/templating_node/node.py +2 -2
- vellum/workflows/nodes/core/try_node/node.py +7 -7
- vellum/workflows/nodes/core/try_node/tests/test_node.py +9 -7
- vellum/workflows/nodes/displayable/bases/api_node/node.py +3 -3
- vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +4 -12
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +2 -2
- vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +2 -2
- vellum/workflows/nodes/displayable/bases/search_node.py +3 -3
- vellum/workflows/nodes/displayable/code_execution_node/node.py +21 -5
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +141 -0
- vellum/workflows/nodes/displayable/guardrail_node/node.py +3 -3
- vellum/workflows/nodes/displayable/inline_prompt_node/node.py +3 -3
- vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +3 -3
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +7 -14
- vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +4 -4
- vellum/workflows/nodes/utils.py +5 -9
- vellum/workflows/references/external_input.py +2 -2
- vellum/workflows/references/node.py +2 -2
- vellum/workflows/references/state_value.py +2 -2
- vellum/workflows/references/workflow_input.py +2 -2
- vellum/workflows/runner/runner.py +15 -15
- {vellum_ee/workflows/display → vellum/workflows}/utils/tests/test_uuids.py +1 -1
- vellum/workflows/workflows/base.py +7 -7
- {vellum_ai-0.11.9.dist-info → vellum_ai-0.12.0.dist-info}/METADATA +1 -1
- {vellum_ai-0.11.9.dist-info → vellum_ai-0.12.0.dist-info}/RECORD +61 -62
- {vellum_ai-0.11.9.dist-info → vellum_ai-0.12.0.dist-info}/WHEEL +1 -1
- vellum_ee/workflows/display/nodes/base_node_display.py +50 -21
- vellum_ee/workflows/display/nodes/base_node_vellum_display.py +10 -1
- vellum_ee/workflows/display/nodes/get_node_display_class.py +10 -1
- vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +5 -4
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +13 -3
- vellum_ee/workflows/display/nodes/vellum/conditional_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/final_output_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/merge_node.py +4 -4
- vellum_ee/workflows/display/nodes/vellum/search_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +5 -1
- vellum_ee/workflows/display/nodes/vellum/try_node.py +12 -6
- vellum_ee/workflows/display/nodes/vellum/utils.py +1 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +269 -85
- vellum_ee/workflows/display/workflows/base_workflow_display.py +2 -2
- vellum_ee/workflows/display/workflows/vellum_workflow_display.py +2 -6
- vellum_ee/workflows/display/utils/tests/__init__.py +0 -0
- {vellum_ee/workflows/display → vellum/workflows}/utils/uuids.py +0 -0
- {vellum_ai-0.11.9.dist-info → vellum_ai-0.12.0.dist-info}/LICENSE +0 -0
- {vellum_ai-0.11.9.dist-info → vellum_ai-0.12.0.dist-info}/entry_points.txt +0 -0
@@ -3,7 +3,7 @@ from typing import ClassVar, Generator, Generic, Iterator, List, Optional, Union
|
|
3
3
|
|
4
4
|
from vellum import AdHocExecutePromptEvent, ExecutePromptEvent, PromptOutput
|
5
5
|
from vellum.core import RequestOptions
|
6
|
-
from vellum.workflows.errors.types import
|
6
|
+
from vellum.workflows.errors.types import WorkflowErrorCode, vellum_error_to_workflow_error
|
7
7
|
from vellum.workflows.exceptions import NodeException
|
8
8
|
from vellum.workflows.nodes.bases import BaseNode
|
9
9
|
from vellum.workflows.outputs.base import BaseOutput, BaseOutputs
|
@@ -29,7 +29,7 @@ class BasePromptNode(BaseNode, Generic[StateType]):
|
|
29
29
|
if outputs is None:
|
30
30
|
raise NodeException(
|
31
31
|
message="Expected to receive outputs from Prompt",
|
32
|
-
code=
|
32
|
+
code=WorkflowErrorCode.INTERNAL_ERROR,
|
33
33
|
)
|
34
34
|
|
35
35
|
def _process_prompt_event_stream(self) -> Generator[BaseOutput, None, Optional[List[PromptOutput]]]:
|
@@ -45,15 +45,7 @@ class BasePromptNode(BaseNode, Generic[StateType]):
|
|
45
45
|
outputs = event.outputs
|
46
46
|
yield BaseOutput(name="results", value=event.outputs)
|
47
47
|
elif event.state == "REJECTED":
|
48
|
-
|
49
|
-
|
50
|
-
message=event.error.message,
|
51
|
-
code=VellumErrorCode(event.error.code),
|
52
|
-
)
|
53
|
-
else:
|
54
|
-
raise NodeException(
|
55
|
-
message=event.error.message,
|
56
|
-
code=VellumErrorCode.INTERNAL_ERROR,
|
57
|
-
)
|
48
|
+
workflow_error = vellum_error_to_workflow_error(event.error)
|
49
|
+
raise NodeException.of(workflow_error)
|
58
50
|
|
59
51
|
return outputs
|
@@ -17,7 +17,7 @@ from vellum import (
|
|
17
17
|
from vellum.client import RequestOptions
|
18
18
|
from vellum.workflows.constants import OMIT
|
19
19
|
from vellum.workflows.context import get_parent_context
|
20
|
-
from vellum.workflows.errors import
|
20
|
+
from vellum.workflows.errors import WorkflowErrorCode
|
21
21
|
from vellum.workflows.exceptions import NodeException
|
22
22
|
from vellum.workflows.nodes.displayable.bases.base_prompt_node import BasePromptNode
|
23
23
|
from vellum.workflows.nodes.displayable.bases.inline_prompt_node.constants import DEFAULT_PROMPT_PARAMETERS
|
@@ -120,7 +120,7 @@ class BaseInlinePromptNode(BasePromptNode, Generic[StateType]):
|
|
120
120
|
else:
|
121
121
|
raise NodeException(
|
122
122
|
message=f"Unrecognized input type for input '{input_name}': {input_value.__class__}",
|
123
|
-
code=
|
123
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
124
124
|
)
|
125
125
|
|
126
126
|
return input_variables, input_values
|
@@ -14,7 +14,7 @@ from vellum import (
|
|
14
14
|
from vellum.client import RequestOptions
|
15
15
|
from vellum.workflows.constants import LATEST_RELEASE_TAG, OMIT
|
16
16
|
from vellum.workflows.context import get_parent_context
|
17
|
-
from vellum.workflows.errors import
|
17
|
+
from vellum.workflows.errors import WorkflowErrorCode
|
18
18
|
from vellum.workflows.exceptions import NodeException
|
19
19
|
from vellum.workflows.nodes.displayable.bases.base_prompt_node import BasePromptNode
|
20
20
|
from vellum.workflows.types.generics import StateType
|
@@ -101,7 +101,7 @@ class BasePromptDeploymentNode(BasePromptNode, Generic[StateType]):
|
|
101
101
|
else:
|
102
102
|
raise NodeException(
|
103
103
|
message=f"Unrecognized input type for input '{input_name}': {input_value.__class__}",
|
104
|
-
code=
|
104
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
105
105
|
)
|
106
106
|
|
107
107
|
return compiled_inputs
|
@@ -12,7 +12,7 @@ from vellum import (
|
|
12
12
|
SearchWeightsRequest,
|
13
13
|
)
|
14
14
|
from vellum.core import ApiError, RequestOptions
|
15
|
-
from vellum.workflows.errors import
|
15
|
+
from vellum.workflows.errors import WorkflowErrorCode
|
16
16
|
from vellum.workflows.exceptions import NodeException
|
17
17
|
from vellum.workflows.nodes.bases import BaseNode
|
18
18
|
from vellum.workflows.outputs import BaseOutputs
|
@@ -83,12 +83,12 @@ class BaseSearchNode(BaseNode[StateType], Generic[StateType]):
|
|
83
83
|
except NotFoundError:
|
84
84
|
raise NodeException(
|
85
85
|
message=f"Document Index '{self.document_index}' not found",
|
86
|
-
code=
|
86
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
87
87
|
)
|
88
88
|
except ApiError:
|
89
89
|
raise NodeException(
|
90
90
|
message=f"An error occurred while searching against Document Index '{self.document_index}'", # noqa: E501
|
91
|
-
code=
|
91
|
+
code=WorkflowErrorCode.INTERNAL_ERROR,
|
92
92
|
)
|
93
93
|
|
94
94
|
def run(self) -> Outputs:
|
@@ -20,7 +20,7 @@ from vellum import (
|
|
20
20
|
VellumValue,
|
21
21
|
)
|
22
22
|
from vellum.core import RequestOptions
|
23
|
-
from vellum.workflows.errors.types import
|
23
|
+
from vellum.workflows.errors.types import WorkflowErrorCode
|
24
24
|
from vellum.workflows.exceptions import NodeException
|
25
25
|
from vellum.workflows.nodes.bases import BaseNode
|
26
26
|
from vellum.workflows.nodes.bases.base import BaseNodeMeta
|
@@ -73,7 +73,8 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
|
|
73
73
|
request_options: Optional[RequestOptions] = None - The request options to use for the custom script.
|
74
74
|
"""
|
75
75
|
|
76
|
-
filepath: ClassVar[str]
|
76
|
+
filepath: ClassVar[Optional[str]] = None
|
77
|
+
code: ClassVar[Optional[str]] = None
|
77
78
|
|
78
79
|
code_inputs: ClassVar[EntityInputsInterface]
|
79
80
|
runtime: CodeExecutionRuntime = "PYTHON_3_11_6"
|
@@ -101,7 +102,7 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
|
|
101
102
|
|
102
103
|
if code_execution.output.type != expected_output_type:
|
103
104
|
raise NodeException(
|
104
|
-
code=
|
105
|
+
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
105
106
|
message=f"Expected an output of type '{expected_output_type}', received '{code_execution.output.type}'",
|
106
107
|
)
|
107
108
|
|
@@ -184,18 +185,33 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
|
|
184
185
|
else:
|
185
186
|
raise NodeException(
|
186
187
|
message=f"Unrecognized input type for input '{input_name}'",
|
187
|
-
code=
|
188
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
188
189
|
)
|
189
190
|
|
190
191
|
return compiled_inputs
|
191
192
|
|
192
193
|
def _resolve_code(self) -> str:
|
194
|
+
if self.code and self.filepath:
|
195
|
+
raise NodeException(
|
196
|
+
message="Cannot specify both `code` and `filepath` for a CodeExecutionNode",
|
197
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
198
|
+
)
|
199
|
+
|
200
|
+
if self.code:
|
201
|
+
return self.code
|
202
|
+
|
203
|
+
if not self.filepath:
|
204
|
+
raise NodeException(
|
205
|
+
message="Must specify either `code` or `filepath` for a CodeExecutionNode",
|
206
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
207
|
+
)
|
208
|
+
|
193
209
|
root = inspect.getfile(self.__class__)
|
194
210
|
code = read_file_from_path(node_filepath=root, script_filepath=self.filepath)
|
195
211
|
if not code:
|
196
212
|
raise NodeException(
|
197
213
|
message=f"Filepath '{self.filepath}' does not exist",
|
198
|
-
code=
|
214
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
199
215
|
)
|
200
216
|
|
201
217
|
return code
|
@@ -1,6 +1,8 @@
|
|
1
|
+
import pytest
|
1
2
|
import os
|
2
3
|
|
3
4
|
from vellum import CodeExecutorResponse, NumberVellumValue, StringInput
|
5
|
+
from vellum.workflows.exceptions import NodeException
|
4
6
|
from vellum.workflows.inputs.base import BaseInputs
|
5
7
|
from vellum.workflows.nodes.displayable.code_execution_node import CodeExecutionNode
|
6
8
|
from vellum.workflows.references.vellum_secret import VellumSecretReference
|
@@ -62,6 +64,145 @@ def main(word: str) -> int:
|
|
62
64
|
)
|
63
65
|
|
64
66
|
|
67
|
+
def test_run_workflow__code_attribute(vellum_client):
|
68
|
+
"""Confirm that CodeExecutionNodes can use the `code` attribute to specify the code to execute."""
|
69
|
+
|
70
|
+
# GIVEN a node that subclasses CodeExecutionNode
|
71
|
+
class Inputs(BaseInputs):
|
72
|
+
word: str
|
73
|
+
|
74
|
+
class State(BaseState):
|
75
|
+
pass
|
76
|
+
|
77
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[State, int]):
|
78
|
+
code = """\
|
79
|
+
def main(word: str) -> int:
|
80
|
+
print(word) # noqa: T201
|
81
|
+
return len(word)
|
82
|
+
"""
|
83
|
+
runtime = "PYTHON_3_11_6"
|
84
|
+
|
85
|
+
code_inputs = {
|
86
|
+
"word": Inputs.word,
|
87
|
+
}
|
88
|
+
|
89
|
+
# AND we know what the Code Execution Node will respond with
|
90
|
+
mock_code_execution = CodeExecutorResponse(
|
91
|
+
log="hello",
|
92
|
+
output=NumberVellumValue(value=5),
|
93
|
+
)
|
94
|
+
vellum_client.execute_code.return_value = mock_code_execution
|
95
|
+
|
96
|
+
# WHEN we run the node
|
97
|
+
node = ExampleCodeExecutionNode(
|
98
|
+
state=State(
|
99
|
+
meta=StateMeta(workflow_inputs=Inputs(word="hello")),
|
100
|
+
)
|
101
|
+
)
|
102
|
+
outputs = node.run()
|
103
|
+
|
104
|
+
# THEN the node should have produced the outputs we expect
|
105
|
+
assert outputs == {"result": 5, "log": "hello"}
|
106
|
+
|
107
|
+
# AND we should have invoked the Code with the expected inputs
|
108
|
+
vellum_client.execute_code.assert_called_once_with(
|
109
|
+
input_values=[
|
110
|
+
StringInput(name="word", value="hello"),
|
111
|
+
],
|
112
|
+
code="""\
|
113
|
+
def main(word: str) -> int:
|
114
|
+
print(word) # noqa: T201
|
115
|
+
return len(word)
|
116
|
+
""",
|
117
|
+
runtime="PYTHON_3_11_6",
|
118
|
+
output_type="NUMBER",
|
119
|
+
packages=[],
|
120
|
+
request_options=None,
|
121
|
+
)
|
122
|
+
|
123
|
+
|
124
|
+
def test_run_workflow__code_and_filepath_defined(vellum_client):
|
125
|
+
"""Confirm that CodeExecutionNodes raise an error if both `code` and `filepath` are defined."""
|
126
|
+
|
127
|
+
# GIVEN a node that subclasses CodeExecutionNode
|
128
|
+
class Inputs(BaseInputs):
|
129
|
+
word: str
|
130
|
+
|
131
|
+
class State(BaseState):
|
132
|
+
pass
|
133
|
+
|
134
|
+
fixture = os.path.abspath(os.path.join(__file__, "../fixtures/main.py"))
|
135
|
+
|
136
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[State, int]):
|
137
|
+
filepath = fixture
|
138
|
+
code = """\
|
139
|
+
def main(word: str) -> int:
|
140
|
+
print(word) # noqa: T201
|
141
|
+
return len(word)
|
142
|
+
"""
|
143
|
+
runtime = "PYTHON_3_11_6"
|
144
|
+
|
145
|
+
code_inputs = {
|
146
|
+
"word": Inputs.word,
|
147
|
+
}
|
148
|
+
|
149
|
+
# AND we know what the Code Execution Node will respond with
|
150
|
+
mock_code_execution = CodeExecutorResponse(
|
151
|
+
log="hello",
|
152
|
+
output=NumberVellumValue(value=5),
|
153
|
+
)
|
154
|
+
vellum_client.execute_code.return_value = mock_code_execution
|
155
|
+
|
156
|
+
# WHEN we run the node
|
157
|
+
node = ExampleCodeExecutionNode(
|
158
|
+
state=State(
|
159
|
+
meta=StateMeta(workflow_inputs=Inputs(word="hello")),
|
160
|
+
)
|
161
|
+
)
|
162
|
+
with pytest.raises(NodeException) as exc_info:
|
163
|
+
node.run()
|
164
|
+
|
165
|
+
# THEN the node should have produced the exception we expected
|
166
|
+
assert exc_info.value.message == "Cannot specify both `code` and `filepath` for a CodeExecutionNode"
|
167
|
+
|
168
|
+
|
169
|
+
def test_run_workflow__code_and_filepath_not_defined(vellum_client):
|
170
|
+
"""Confirm that CodeExecutionNodes raise an error if neither `code` nor `filepath` are defined."""
|
171
|
+
|
172
|
+
# GIVEN a node that subclasses CodeExecutionNode
|
173
|
+
class Inputs(BaseInputs):
|
174
|
+
word: str
|
175
|
+
|
176
|
+
class State(BaseState):
|
177
|
+
pass
|
178
|
+
|
179
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[State, int]):
|
180
|
+
runtime = "PYTHON_3_11_6"
|
181
|
+
|
182
|
+
code_inputs = {
|
183
|
+
"word": Inputs.word,
|
184
|
+
}
|
185
|
+
|
186
|
+
# AND we know what the Code Execution Node will respond with
|
187
|
+
mock_code_execution = CodeExecutorResponse(
|
188
|
+
log="hello",
|
189
|
+
output=NumberVellumValue(value=5),
|
190
|
+
)
|
191
|
+
vellum_client.execute_code.return_value = mock_code_execution
|
192
|
+
|
193
|
+
# WHEN we run the node
|
194
|
+
node = ExampleCodeExecutionNode(
|
195
|
+
state=State(
|
196
|
+
meta=StateMeta(workflow_inputs=Inputs(word="hello")),
|
197
|
+
)
|
198
|
+
)
|
199
|
+
with pytest.raises(NodeException) as exc_info:
|
200
|
+
node.run()
|
201
|
+
|
202
|
+
# THEN the node should have produced the exception we expected
|
203
|
+
assert exc_info.value.message == "Must specify either `code` or `filepath` for a CodeExecutionNode"
|
204
|
+
|
205
|
+
|
65
206
|
def test_run_workflow__vellum_secret(vellum_client):
|
66
207
|
"""Confirm that CodeExecutionNodes can use Vellum Secrets"""
|
67
208
|
|
@@ -4,7 +4,7 @@ from typing import Any, ClassVar, Dict, Generic, List, Optional, Union, cast
|
|
4
4
|
from vellum import ChatHistoryInput, ChatMessage, JsonInput, MetricDefinitionInput, NumberInput, StringInput
|
5
5
|
from vellum.core import RequestOptions
|
6
6
|
from vellum.workflows.constants import LATEST_RELEASE_TAG
|
7
|
-
from vellum.workflows.errors.types import
|
7
|
+
from vellum.workflows.errors.types import WorkflowErrorCode
|
8
8
|
from vellum.workflows.exceptions import NodeException
|
9
9
|
from vellum.workflows.nodes.bases import BaseNode
|
10
10
|
from vellum.workflows.outputs.base import BaseOutputs
|
@@ -46,7 +46,7 @@ class GuardrailNode(BaseNode[StateType], Generic[StateType]):
|
|
46
46
|
if not isinstance(score, float):
|
47
47
|
raise NodeException(
|
48
48
|
message="Metric execution must have one output named 'score' with type 'float'",
|
49
|
-
code=
|
49
|
+
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
50
50
|
)
|
51
51
|
|
52
52
|
metric_outputs.pop("score")
|
@@ -90,7 +90,7 @@ class GuardrailNode(BaseNode[StateType], Generic[StateType]):
|
|
90
90
|
else:
|
91
91
|
raise NodeException(
|
92
92
|
message=f"Unrecognized input type for input '{input_name}'",
|
93
|
-
code=
|
93
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
94
94
|
)
|
95
95
|
|
96
96
|
return compiled_inputs
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import Iterator
|
2
2
|
|
3
|
-
from vellum.workflows.errors import
|
3
|
+
from vellum.workflows.errors import WorkflowErrorCode
|
4
4
|
from vellum.workflows.exceptions import NodeException
|
5
5
|
from vellum.workflows.nodes.displayable.bases import BaseInlinePromptNode as BaseInlinePromptNode
|
6
6
|
from vellum.workflows.outputs import BaseOutput
|
@@ -34,7 +34,7 @@ class InlinePromptNode(BaseInlinePromptNode[StateType]):
|
|
34
34
|
if not outputs:
|
35
35
|
raise NodeException(
|
36
36
|
message="Expected to receive outputs from Prompt",
|
37
|
-
code=
|
37
|
+
code=WorkflowErrorCode.INTERNAL_ERROR,
|
38
38
|
)
|
39
39
|
|
40
40
|
string_output = next((output for output in outputs if output.type == "STRING"), None)
|
@@ -43,7 +43,7 @@ class InlinePromptNode(BaseInlinePromptNode[StateType]):
|
|
43
43
|
is_plural = len(output_types) > 1
|
44
44
|
raise NodeException(
|
45
45
|
message=f"Expected to receive a non-null string output from Prompt. Only found outputs of type{'s' if is_plural else ''}: {', '.join(output_types)}", # noqa: E501
|
46
|
-
code=
|
46
|
+
code=WorkflowErrorCode.INTERNAL_ERROR,
|
47
47
|
)
|
48
48
|
|
49
49
|
yield BaseOutput(name="text", value=string_output.value)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import Iterator
|
2
2
|
|
3
|
-
from vellum.workflows.errors import
|
3
|
+
from vellum.workflows.errors import WorkflowErrorCode
|
4
4
|
from vellum.workflows.exceptions import NodeException
|
5
5
|
from vellum.workflows.nodes.displayable.bases import BasePromptDeploymentNode as BasePromptDeploymentNode
|
6
6
|
from vellum.workflows.outputs import BaseOutput
|
@@ -37,7 +37,7 @@ class PromptDeploymentNode(BasePromptDeploymentNode[StateType]):
|
|
37
37
|
if not outputs:
|
38
38
|
raise NodeException(
|
39
39
|
message="Expected to receive outputs from Prompt",
|
40
|
-
code=
|
40
|
+
code=WorkflowErrorCode.INTERNAL_ERROR,
|
41
41
|
)
|
42
42
|
|
43
43
|
string_output = next((output for output in outputs if output.type == "STRING"), None)
|
@@ -46,7 +46,7 @@ class PromptDeploymentNode(BasePromptDeploymentNode[StateType]):
|
|
46
46
|
is_plural = len(output_types) > 1
|
47
47
|
raise NodeException(
|
48
48
|
message=f"Expected to receive a non-null string output from Prompt. Only found outputs of type{'s' if is_plural else ''}: {', '.join(output_types)}", # noqa: E501
|
49
|
-
code=
|
49
|
+
code=WorkflowErrorCode.INTERNAL_ERROR,
|
50
50
|
)
|
51
51
|
|
52
52
|
yield BaseOutput(name="text", value=string_output.value)
|
@@ -14,7 +14,8 @@ from vellum import (
|
|
14
14
|
from vellum.core import RequestOptions
|
15
15
|
from vellum.workflows.constants import LATEST_RELEASE_TAG, OMIT
|
16
16
|
from vellum.workflows.context import get_parent_context
|
17
|
-
from vellum.workflows.errors import
|
17
|
+
from vellum.workflows.errors import WorkflowErrorCode
|
18
|
+
from vellum.workflows.errors.types import workflow_event_error_to_workflow_error
|
18
19
|
from vellum.workflows.exceptions import NodeException
|
19
20
|
from vellum.workflows.nodes.bases.base_subworkflow_node.node import BaseSubworkflowNode
|
20
21
|
from vellum.workflows.outputs.base import BaseOutput
|
@@ -84,7 +85,7 @@ class SubworkflowDeploymentNode(BaseSubworkflowNode[StateType], Generic[StateTyp
|
|
84
85
|
else:
|
85
86
|
raise NodeException(
|
86
87
|
message=f"Unrecognized input type for input '{input_name}'",
|
87
|
-
code=
|
88
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
88
89
|
)
|
89
90
|
|
90
91
|
return compiled_inputs
|
@@ -136,23 +137,15 @@ class SubworkflowDeploymentNode(BaseSubworkflowNode[StateType], Generic[StateTyp
|
|
136
137
|
if not error:
|
137
138
|
raise NodeException(
|
138
139
|
message="Expected to receive an error from REJECTED event",
|
139
|
-
code=
|
140
|
-
)
|
141
|
-
elif error.code in VellumErrorCode._value2member_map_:
|
142
|
-
raise NodeException(
|
143
|
-
message=error.message,
|
144
|
-
code=VellumErrorCode(error.code),
|
145
|
-
)
|
146
|
-
else:
|
147
|
-
raise NodeException(
|
148
|
-
message=error.message,
|
149
|
-
code=VellumErrorCode.INTERNAL_ERROR,
|
140
|
+
code=WorkflowErrorCode.INTERNAL_ERROR,
|
150
141
|
)
|
142
|
+
workflow_error = workflow_event_error_to_workflow_error(error)
|
143
|
+
raise NodeException.of(workflow_error)
|
151
144
|
|
152
145
|
if outputs is None:
|
153
146
|
raise NodeException(
|
154
147
|
message="Expected to receive outputs from Workflow Deployment",
|
155
|
-
code=
|
148
|
+
code=WorkflowErrorCode.INTERNAL_ERROR,
|
156
149
|
)
|
157
150
|
|
158
151
|
# For any outputs somehow in our final fulfilled outputs array,
|
@@ -11,8 +11,8 @@ from vellum import (
|
|
11
11
|
StringVellumValue,
|
12
12
|
VellumError,
|
13
13
|
)
|
14
|
-
from vellum.workflows.errors import
|
15
|
-
from vellum.workflows.errors.types import
|
14
|
+
from vellum.workflows.errors import WorkflowError as SdkVellumError
|
15
|
+
from vellum.workflows.errors.types import WorkflowErrorCode
|
16
16
|
from vellum.workflows.inputs import BaseInputs
|
17
17
|
from vellum.workflows.nodes import InlinePromptNode
|
18
18
|
from vellum.workflows.nodes.core.try_node.node import TryNode
|
@@ -104,7 +104,7 @@ def test_inline_text_prompt_node__catch_provider_error(vellum_adhoc_prompt_clien
|
|
104
104
|
class State(BaseState):
|
105
105
|
pass
|
106
106
|
|
107
|
-
@TryNode.wrap(on_error_code=
|
107
|
+
@TryNode.wrap(on_error_code=WorkflowErrorCode.PROVIDER_ERROR)
|
108
108
|
class MyInlinePromptNode(InlinePromptNode):
|
109
109
|
ml_model = "gpt-4o"
|
110
110
|
prompt_inputs = {}
|
@@ -143,7 +143,7 @@ def test_inline_text_prompt_node__catch_provider_error(vellum_adhoc_prompt_clien
|
|
143
143
|
name="error",
|
144
144
|
value=SdkVellumError(
|
145
145
|
message="OpenAI failed",
|
146
|
-
code=
|
146
|
+
code=WorkflowErrorCode.PROVIDER_ERROR,
|
147
147
|
),
|
148
148
|
)
|
149
149
|
in outputs
|
vellum/workflows/nodes/utils.py
CHANGED
@@ -2,7 +2,6 @@ from functools import cache
|
|
2
2
|
from typing import Type
|
3
3
|
|
4
4
|
from vellum.workflows.nodes import BaseNode
|
5
|
-
from vellum.workflows.references import NodeReference
|
6
5
|
from vellum.workflows.types.generics import NodeType
|
7
6
|
|
8
7
|
ADORNMENT_MODULE_NAME = "<adornment>"
|
@@ -10,20 +9,17 @@ ADORNMENT_MODULE_NAME = "<adornment>"
|
|
10
9
|
|
11
10
|
@cache
|
12
11
|
def get_wrapped_node(node: Type[NodeType]) -> Type[BaseNode]:
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
graph = subworkflow.instance.graph
|
17
|
-
if issubclass(graph, BaseNode):
|
18
|
-
return graph
|
12
|
+
wrapped_node = getattr(node, "__wrapped_node__", None)
|
13
|
+
if wrapped_node is None:
|
14
|
+
raise AttributeError("Wrapped node not found")
|
19
15
|
|
20
|
-
|
16
|
+
return wrapped_node
|
21
17
|
|
22
18
|
|
23
19
|
def has_wrapped_node(node: Type[NodeType]) -> bool:
|
24
20
|
try:
|
25
21
|
get_wrapped_node(node)
|
26
|
-
except
|
22
|
+
except AttributeError:
|
27
23
|
return False
|
28
24
|
|
29
25
|
return True
|
@@ -5,7 +5,7 @@ from pydantic_core import core_schema
|
|
5
5
|
|
6
6
|
from vellum.workflows.constants import UNDEF
|
7
7
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
8
|
-
from vellum.workflows.errors.types import
|
8
|
+
from vellum.workflows.errors.types import WorkflowErrorCode
|
9
9
|
from vellum.workflows.exceptions import NodeException
|
10
10
|
|
11
11
|
if TYPE_CHECKING:
|
@@ -40,7 +40,7 @@ class ExternalInputReference(BaseDescriptor[_InputType], Generic[_InputType]):
|
|
40
40
|
if state.meta.parent:
|
41
41
|
return self.resolve(state.meta.parent)
|
42
42
|
|
43
|
-
raise NodeException(f"Missing required Node Input: {self._name}", code=
|
43
|
+
raise NodeException(f"Missing required Node Input: {self._name}", code=WorkflowErrorCode.INVALID_INPUTS)
|
44
44
|
|
45
45
|
@classmethod
|
46
46
|
def __get_pydantic_core_schema__(
|
@@ -4,7 +4,7 @@ from pydantic import GetCoreSchemaHandler
|
|
4
4
|
from pydantic_core import core_schema
|
5
5
|
|
6
6
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
7
|
-
from vellum.workflows.errors.types import
|
7
|
+
from vellum.workflows.errors.types import WorkflowErrorCode
|
8
8
|
from vellum.workflows.exceptions import NodeException
|
9
9
|
|
10
10
|
if TYPE_CHECKING:
|
@@ -30,7 +30,7 @@ class NodeReference(BaseDescriptor[_T]):
|
|
30
30
|
def resolve(self, state: "BaseState") -> _T:
|
31
31
|
raise NodeException(
|
32
32
|
f"NodeDescriptors cannot be resolved during runtime. Got: {self._name}",
|
33
|
-
code=
|
33
|
+
code=WorkflowErrorCode.INTERNAL_ERROR,
|
34
34
|
)
|
35
35
|
|
36
36
|
def __repr__(self) -> str:
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from typing import TYPE_CHECKING, TypeVar, cast
|
2
2
|
|
3
3
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
4
|
-
from vellum.workflows.errors.types import
|
4
|
+
from vellum.workflows.errors.types import WorkflowErrorCode
|
5
5
|
from vellum.workflows.exceptions import NodeException
|
6
6
|
|
7
7
|
if TYPE_CHECKING:
|
@@ -20,4 +20,4 @@ class StateValueReference(BaseDescriptor[_T]):
|
|
20
20
|
if state.meta.parent:
|
21
21
|
return self.resolve(state.meta.parent)
|
22
22
|
|
23
|
-
raise NodeException(f"Missing required Workflow state: {self._name}", code=
|
23
|
+
raise NodeException(f"Missing required Workflow state: {self._name}", code=WorkflowErrorCode.INVALID_STATE)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from typing import TYPE_CHECKING, Generic, Optional, Tuple, Type, TypeVar, cast
|
2
2
|
|
3
3
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
4
|
-
from vellum.workflows.errors.types import
|
4
|
+
from vellum.workflows.errors.types import WorkflowErrorCode
|
5
5
|
from vellum.workflows.exceptions import NodeException
|
6
6
|
|
7
7
|
if TYPE_CHECKING:
|
@@ -35,7 +35,7 @@ class WorkflowInputReference(BaseDescriptor[_InputType], Generic[_InputType]):
|
|
35
35
|
if state.meta.parent:
|
36
36
|
return self.resolve(state.meta.parent)
|
37
37
|
|
38
|
-
raise NodeException(f"Missing required Workflow input: {self._name}", code=
|
38
|
+
raise NodeException(f"Missing required Workflow input: {self._name}", code=WorkflowErrorCode.INVALID_INPUTS)
|
39
39
|
|
40
40
|
def __repr__(self) -> str:
|
41
41
|
return f"{self._inputs_class.__qualname__}.{self.name}"
|