vellum-ai 1.6.2__py3-none-any.whl → 1.6.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vellum/client/core/client_wrapper.py +2 -2
- vellum/workflows/exceptions.py +16 -2
- vellum/workflows/nodes/displayable/code_execution_node/node.py +3 -0
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py +83 -0
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +2 -1
- vellum/workflows/runner/runner.py +17 -0
- vellum/workflows/utils/vellum_variables.py +3 -0
- vellum/workflows/workflows/base.py +11 -1
- {vellum_ai-1.6.2.dist-info → vellum_ai-1.6.3.dist-info}/METADATA +1 -1
- {vellum_ai-1.6.2.dist-info → vellum_ai-1.6.3.dist-info}/RECORD +17 -16
- vellum_cli/image_push.py +14 -0
- vellum_cli/tests/test_image_push_error_handling.py +68 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_terminal_node_any_serialization.py +49 -0
- vellum_ee/workflows/tests/test_serialize_module.py +53 -0
- {vellum_ai-1.6.2.dist-info → vellum_ai-1.6.3.dist-info}/LICENSE +0 -0
- {vellum_ai-1.6.2.dist-info → vellum_ai-1.6.3.dist-info}/WHEEL +0 -0
- {vellum_ai-1.6.2.dist-info → vellum_ai-1.6.3.dist-info}/entry_points.txt +0 -0
@@ -27,10 +27,10 @@ class BaseClientWrapper:
|
|
27
27
|
|
28
28
|
def get_headers(self) -> typing.Dict[str, str]:
|
29
29
|
headers: typing.Dict[str, str] = {
|
30
|
-
"User-Agent": "vellum-ai/1.6.
|
30
|
+
"User-Agent": "vellum-ai/1.6.3",
|
31
31
|
"X-Fern-Language": "Python",
|
32
32
|
"X-Fern-SDK-Name": "vellum-ai",
|
33
|
-
"X-Fern-SDK-Version": "1.6.
|
33
|
+
"X-Fern-SDK-Version": "1.6.3",
|
34
34
|
**(self.get_custom_headers() or {}),
|
35
35
|
}
|
36
36
|
if self._api_version is not None:
|
vellum/workflows/exceptions.py
CHANGED
@@ -6,6 +6,19 @@ if TYPE_CHECKING:
|
|
6
6
|
from vellum.workflows.workflows.base import BaseWorkflow
|
7
7
|
|
8
8
|
|
9
|
+
def import_workflow_class() -> Type["BaseWorkflow"]:
|
10
|
+
"""
|
11
|
+
Helper function to help avoid circular imports.
|
12
|
+
|
13
|
+
Ideally, we use the one in types.generics, but _that_ causes circular imports
|
14
|
+
due to the `src/vellum/workflows/types/definition.py` module's import of `EnvironmentVariableReference`
|
15
|
+
"""
|
16
|
+
|
17
|
+
from vellum.workflows.workflows import BaseWorkflow
|
18
|
+
|
19
|
+
return BaseWorkflow
|
20
|
+
|
21
|
+
|
9
22
|
class NodeException(Exception):
|
10
23
|
def __init__(
|
11
24
|
self,
|
@@ -35,12 +48,13 @@ class WorkflowInitializationException(Exception):
|
|
35
48
|
def __init__(
|
36
49
|
self,
|
37
50
|
message: str,
|
38
|
-
workflow_definition: Type["BaseWorkflow"],
|
51
|
+
workflow_definition: Optional[Type["BaseWorkflow"]] = None,
|
39
52
|
code: WorkflowErrorCode = WorkflowErrorCode.INVALID_INPUTS,
|
40
53
|
):
|
54
|
+
|
41
55
|
self.message = message
|
42
56
|
self.code = code
|
43
|
-
self.definition = workflow_definition
|
57
|
+
self.definition = workflow_definition if workflow_definition is not None else import_workflow_class()
|
44
58
|
super().__init__(message)
|
45
59
|
|
46
60
|
@property
|
@@ -23,6 +23,7 @@ from vellum import (
|
|
23
23
|
from vellum.client.core import RequestOptions
|
24
24
|
from vellum.client.core.api_error import ApiError
|
25
25
|
from vellum.client.types.code_executor_secret_input import CodeExecutorSecretInput
|
26
|
+
from vellum.workflows.constants import undefined
|
26
27
|
from vellum.workflows.errors.types import WorkflowErrorCode
|
27
28
|
from vellum.workflows.exceptions import NodeException
|
28
29
|
from vellum.workflows.nodes.bases import BaseNode
|
@@ -147,6 +148,8 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
|
|
147
148
|
compiled_inputs: List[CodeExecutorInput] = []
|
148
149
|
|
149
150
|
for input_name, input_value in self.code_inputs.items():
|
151
|
+
if input_value is undefined:
|
152
|
+
continue
|
150
153
|
if isinstance(input_value, str):
|
151
154
|
compiled_inputs.append(
|
152
155
|
StringInput(
|
@@ -13,6 +13,7 @@ from vellum.client.types.code_executor_secret_input import CodeExecutorSecretInp
|
|
13
13
|
from vellum.client.types.function_call import FunctionCall
|
14
14
|
from vellum.client.types.number_input import NumberInput
|
15
15
|
from vellum.client.types.string_chat_message_content import StringChatMessageContent
|
16
|
+
from vellum.workflows.constants import undefined
|
16
17
|
from vellum.workflows.errors import WorkflowErrorCode
|
17
18
|
from vellum.workflows.exceptions import NodeException
|
18
19
|
from vellum.workflows.inputs.base import BaseInputs
|
@@ -1278,3 +1279,85 @@ def main(secret: str) -> str:
|
|
1278
1279
|
packages=[],
|
1279
1280
|
request_options=None,
|
1280
1281
|
)
|
1282
|
+
|
1283
|
+
|
1284
|
+
def test_run_node__undefined_input_skipped():
|
1285
|
+
"""
|
1286
|
+
Confirm that when an undefined value is passed as an input, it is skipped rather than raising an error.
|
1287
|
+
The function should use the default parameter value when undefined input is skipped.
|
1288
|
+
"""
|
1289
|
+
|
1290
|
+
# GIVEN a node with both a valid input and an undefined input that runs inline
|
1291
|
+
class State(BaseState):
|
1292
|
+
pass
|
1293
|
+
|
1294
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[State, int]):
|
1295
|
+
code = """\
|
1296
|
+
def main(word: str, undefined_input: str = "default") -> int:
|
1297
|
+
return len(word) + len(undefined_input)
|
1298
|
+
"""
|
1299
|
+
runtime = "PYTHON_3_11_6"
|
1300
|
+
packages = []
|
1301
|
+
|
1302
|
+
code_inputs = {
|
1303
|
+
"word": "hello",
|
1304
|
+
"undefined_input": undefined,
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
# WHEN we run the node
|
1308
|
+
node = ExampleCodeExecutionNode(state=State())
|
1309
|
+
outputs = node.run()
|
1310
|
+
|
1311
|
+
# THEN the node should run successfully without raising an error
|
1312
|
+
assert outputs == {"result": 12, "log": ""} # len("hello") + len("default") = 5 + 7 = 12
|
1313
|
+
|
1314
|
+
|
1315
|
+
def test_run_node__undefined_input_skipped_api_execution(vellum_client):
|
1316
|
+
"""
|
1317
|
+
Confirm that when an undefined value is passed as an input in API execution mode,
|
1318
|
+
it is skipped rather than raising an error.
|
1319
|
+
"""
|
1320
|
+
|
1321
|
+
# GIVEN a node with both a valid input and an undefined input that forces API execution
|
1322
|
+
class State(BaseState):
|
1323
|
+
pass
|
1324
|
+
|
1325
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[State, int]):
|
1326
|
+
code = """\
|
1327
|
+
def main(word: str) -> int:
|
1328
|
+
return len(word)
|
1329
|
+
"""
|
1330
|
+
runtime = "PYTHON_3_11_6"
|
1331
|
+
packages = [CodeExecutionPackage(name="requests", version="2.0.0")]
|
1332
|
+
|
1333
|
+
code_inputs = {
|
1334
|
+
"word": "hello",
|
1335
|
+
"undefined_input": undefined,
|
1336
|
+
}
|
1337
|
+
|
1338
|
+
# AND we know what the Code Execution Node will respond with
|
1339
|
+
mock_code_execution = CodeExecutorResponse(
|
1340
|
+
log="",
|
1341
|
+
output=NumberVellumValue(value=5),
|
1342
|
+
)
|
1343
|
+
vellum_client.execute_code.return_value = mock_code_execution
|
1344
|
+
|
1345
|
+
# WHEN we run the node
|
1346
|
+
node = ExampleCodeExecutionNode(state=State())
|
1347
|
+
outputs = node.run()
|
1348
|
+
|
1349
|
+
# THEN the node should run successfully without raising an error
|
1350
|
+
assert outputs == {"result": 5, "log": ""}
|
1351
|
+
|
1352
|
+
# AND the API should be called with only the non-undefined input
|
1353
|
+
vellum_client.execute_code.assert_called_once_with(
|
1354
|
+
input_values=[StringInput(name="word", value="hello")],
|
1355
|
+
code="""\
|
1356
|
+
def main(word: str) -> int:
|
1357
|
+
return len(word)
|
1358
|
+
""",
|
1359
|
+
runtime="PYTHON_3_11_6",
|
1360
|
+
output_type="NUMBER",
|
1361
|
+
packages=[CodeExecutionPackage(name="requests", version="2.0.0")],
|
1362
|
+
request_options=None,
|
1363
|
+
)
|
@@ -4,6 +4,7 @@ import sys
|
|
4
4
|
import traceback
|
5
5
|
from typing import Any, Optional, Tuple, Union
|
6
6
|
|
7
|
+
from vellum.workflows.constants import undefined
|
7
8
|
from vellum.workflows.errors.types import WorkflowErrorCode
|
8
9
|
from vellum.workflows.exceptions import NodeException
|
9
10
|
from vellum.workflows.nodes.utils import cast_to_output_type, wrap_inputs_for_backward_compatibility
|
@@ -54,7 +55,7 @@ def run_code_inline(
|
|
54
55
|
"__arg__out": None,
|
55
56
|
"print": _inline_print,
|
56
57
|
}
|
57
|
-
run_args = [f"{name}=__arg__inputs['{name}']" for name in inputs.
|
58
|
+
run_args = [f"{name}=__arg__inputs['{name}']" for name, value in inputs.items() if value is not undefined]
|
58
59
|
execution_code = f"""\
|
59
60
|
{code}
|
60
61
|
|
@@ -145,6 +145,14 @@ class WorkflowRunner(Generic[StateType]):
|
|
145
145
|
]
|
146
146
|
self._is_resuming = True
|
147
147
|
elif previous_execution_id:
|
148
|
+
if not self.workflow.resolvers:
|
149
|
+
raise WorkflowInitializationException(
|
150
|
+
message=f"No resolvers configured to load initial state for execution ID: {previous_execution_id}",
|
151
|
+
workflow_definition=self.workflow.__class__,
|
152
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
153
|
+
)
|
154
|
+
|
155
|
+
resolver_failed = True
|
148
156
|
for resolver in self.workflow.resolvers:
|
149
157
|
try:
|
150
158
|
load_state_result = resolver.load_state(previous_execution_id)
|
@@ -161,10 +169,19 @@ class WorkflowRunner(Generic[StateType]):
|
|
161
169
|
load_state_result.root_trace_id,
|
162
170
|
load_state_result.root_span_id,
|
163
171
|
)
|
172
|
+
resolver_failed = False
|
164
173
|
break
|
165
174
|
except Exception as e:
|
166
175
|
logger.warning(f"Failed to load state from resolver {type(resolver).__name__}: {e}")
|
167
176
|
continue
|
177
|
+
|
178
|
+
if resolver_failed:
|
179
|
+
raise WorkflowInitializationException(
|
180
|
+
message=f"All resolvers failed to load initial state for execution ID: {previous_execution_id}",
|
181
|
+
workflow_definition=self.workflow.__class__,
|
182
|
+
code=WorkflowErrorCode.INVALID_INPUTS,
|
183
|
+
)
|
184
|
+
|
168
185
|
self._entrypoints = self.workflow.get_entrypoints()
|
169
186
|
else:
|
170
187
|
normalized_inputs = deepcopy(inputs) if inputs else self.workflow.get_default_inputs()
|
@@ -87,6 +87,9 @@ def primitive_type_to_vellum_variable_type(type_: Union[Type, BaseDescriptor]) -
|
|
87
87
|
elif _is_type_optionally_in(type_, (VellumError, VellumErrorRequest)):
|
88
88
|
return "ERROR"
|
89
89
|
|
90
|
+
if type_ is typing.Any:
|
91
|
+
return "JSON"
|
92
|
+
|
90
93
|
builtin_list_type = _builtin_list_to_vellum_type(type_)
|
91
94
|
if builtin_list_type:
|
92
95
|
return builtin_list_type
|
@@ -63,6 +63,7 @@ from vellum.workflows.events.workflow import (
|
|
63
63
|
WorkflowExecutionStreamingBody,
|
64
64
|
WorkflowExecutionStreamingEvent,
|
65
65
|
)
|
66
|
+
from vellum.workflows.exceptions import WorkflowInitializationException
|
66
67
|
from vellum.workflows.executable import BaseExecutable
|
67
68
|
from vellum.workflows.graph import Graph
|
68
69
|
from vellum.workflows.inputs.base import BaseInputs
|
@@ -681,7 +682,16 @@ class BaseWorkflow(Generic[InputsType, StateType], BaseExecutable, metaclass=_Ba
|
|
681
682
|
@staticmethod
|
682
683
|
def load_from_module(module_path: str) -> Type["BaseWorkflow"]:
|
683
684
|
workflow_path = f"{module_path}.workflow"
|
684
|
-
|
685
|
+
try:
|
686
|
+
module = importlib.import_module(workflow_path)
|
687
|
+
except TypeError as e:
|
688
|
+
if "Unexpected graph type" in str(e) or "unhashable type: 'set'" in str(e):
|
689
|
+
raise WorkflowInitializationException(
|
690
|
+
message="Invalid graph structure detected. Nested sets or unsupported graph types are not allowed. "
|
691
|
+
"Please contact Vellum support for assistance with Workflow configuration."
|
692
|
+
) from e
|
693
|
+
else:
|
694
|
+
raise
|
685
695
|
workflows: List[Type[BaseWorkflow]] = []
|
686
696
|
for name in dir(module):
|
687
697
|
if name.startswith("__"):
|
@@ -3,7 +3,7 @@ vellum_cli/README.md,sha256=2NudRoLzWxNKqnuVy1JuQ7DerIaxWGYkrH8kMd-asIE,90
|
|
3
3
|
vellum_cli/__init__.py,sha256=CCTCiCvwxjFHXVSKhzUtZ3GE_h4HrbLEX_XC3qjPuAk,13618
|
4
4
|
vellum_cli/aliased_group.py,sha256=ugW498j0yv4ALJ8vS9MsO7ctDW7Jlir9j6nE_uHAP8c,3363
|
5
5
|
vellum_cli/config.py,sha256=qJrd8W__UZZaUMAG6BO3sxfkgpCoOS4NA3QfqneW-jE,9588
|
6
|
-
vellum_cli/image_push.py,sha256=
|
6
|
+
vellum_cli/image_push.py,sha256=OLHfIlhKpqfaU2L2DhSkk0J_hQPUZ111lN2tqVDAywo,11554
|
7
7
|
vellum_cli/init.py,sha256=WpnMXPItPmh0f0bBGIer3p-e5gu8DUGwSArT_FuoMEw,5093
|
8
8
|
vellum_cli/logger.py,sha256=dcM_OmgqXLo93vDYswO5ylyUQQcTfnA5GTd5tbIt3wM,1446
|
9
9
|
vellum_cli/move.py,sha256=lCHQ-U4BspgS512GxFFvUrglitaHkWfuKn1Hpfcn7-Q,2053
|
@@ -14,7 +14,7 @@ vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
14
14
|
vellum_cli/tests/conftest.py,sha256=wx3PlJjVB0HRf5dr2b_idOIw27WPPl0J0FNbhIJJaVk,1689
|
15
15
|
vellum_cli/tests/test_config.py,sha256=uvKGDc8BoVyT9_H0Z-g8469zVxomn6Oi3Zj-vK7O_wU,2631
|
16
16
|
vellum_cli/tests/test_image_push.py,sha256=X0YOPdoaAnWtK9IQTxaN_wWpw08-5G3v76k1Wu53JpU,12801
|
17
|
-
vellum_cli/tests/test_image_push_error_handling.py,sha256=
|
17
|
+
vellum_cli/tests/test_image_push_error_handling.py,sha256=iKtbvii9sP1aFTlfm0fFBVeYltHf7RMGPPt_d4Te73A,10375
|
18
18
|
vellum_cli/tests/test_init.py,sha256=C_rV4lu-ab5iFoLRizs1XAUnSPdMf7oFuc1i4N4udOU,18285
|
19
19
|
vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
|
20
20
|
vellum_cli/tests/test_move.py,sha256=FIrL1xlH5oFKGX2MugcTKL8JilpopmUC7hP5OaqF5zw,5213
|
@@ -110,6 +110,7 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling
|
|
110
110
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py,sha256=pLCyMScV88DTBXRH7jXaXOEA1GBq8NIipCUFwIAWnwI,2771
|
111
111
|
vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py,sha256=exT7U-axwtYgFylagScflSQLJEND51qIAx2UATju6JM,6023
|
112
112
|
vellum_ee/workflows/display/tests/workflow_serialization/test_final_output_node_map_reference_serialization.py,sha256=vl3pxUJlrYRA8zzFJ-gRm7fe-5fviLNSIsUC7imnMqk,3502
|
113
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_terminal_node_any_serialization.py,sha256=4WAmSEJZlDBLPhsD1f4GwY9ahB9F6qJKGnL6j7ZYlzQ,1740
|
113
114
|
vellum_ee/workflows/display/tests/workflow_serialization/test_web_search_node_serialization.py,sha256=vbDFBrWUPeeW7cxjNA6SXrsHlYcbOAhlQ4C45Vdnr1c,3428
|
114
115
|
vellum_ee/workflows/display/tests/workflow_serialization/test_workflow_input_parameterization_error.py,sha256=vAdmn3YTBDpo55znbydQxsgg9ASqHcvsUPwiBR_7wfo,1461
|
115
116
|
vellum_ee/workflows/display/types.py,sha256=LgRIZeEtV7bQe-nvrC4A0T6vMooSWT1rFtw-uTn45BQ,3752
|
@@ -151,7 +152,7 @@ vellum_ee/workflows/tests/local_workflow/nodes/templating_node.py,sha256=NQwFN61
|
|
151
152
|
vellum_ee/workflows/tests/local_workflow/workflow.py,sha256=A4qOzOPNwePYxWbcAgIPLsmrVS_aVEZEc-wULSv787Q,393
|
152
153
|
vellum_ee/workflows/tests/test_display_meta.py,sha256=PkXJVnMZs9GNooDkd59n4YTBAX3XGPQWeSSVbhehVFM,5112
|
153
154
|
vellum_ee/workflows/tests/test_registry.py,sha256=B8xRIuEyLWfSqrYoPldNQXhKPfe50PllvtAZoI8-uPs,6066
|
154
|
-
vellum_ee/workflows/tests/test_serialize_module.py,sha256=
|
155
|
+
vellum_ee/workflows/tests/test_serialize_module.py,sha256=zleQTcGZa5_nzwu4zpFoqEHhk7pb64hGrhObR4anhPQ,4471
|
155
156
|
vellum_ee/workflows/tests/test_server.py,sha256=dXFBraU99Y6cKp2aBhLFXQTScSRcE9WaWjo1z9piqdU,23344
|
156
157
|
vellum_ee/workflows/tests/test_virtual_files.py,sha256=TJEcMR0v2S8CkloXNmCHA0QW0K6pYNGaIjraJz7sFvY,2762
|
157
158
|
vellum/__init__.py,sha256=i7aah42VTp3735JX69uHUipLZBD8PwX_CXUY_9t-zuY,49356
|
@@ -159,7 +160,7 @@ vellum/client/README.md,sha256=flqu57ubZNTfpq60CdLtJC9gp4WEkyjb_n_eZ4OYf9w,6497
|
|
159
160
|
vellum/client/__init__.py,sha256=rMnKRqL5-356SBc-rfm56MkO87PuAi2mtcfBszcJU1M,74316
|
160
161
|
vellum/client/core/__init__.py,sha256=lTcqUPXcx4112yLDd70RAPeqq6tu3eFMe1pKOqkW9JQ,1562
|
161
162
|
vellum/client/core/api_error.py,sha256=44vPoTyWN59gonCIZMdzw7M1uspygiLnr3GNFOoVL2Q,614
|
162
|
-
vellum/client/core/client_wrapper.py,sha256=
|
163
|
+
vellum/client/core/client_wrapper.py,sha256=sFGuikZMgPFZOHfH3muMMTew0bqB89ar8-4OrulZHu0,2840
|
163
164
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
164
165
|
vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
165
166
|
vellum/client/core/force_multipart.py,sha256=awxh5MtcRYe74ehY8U76jzv6fYM_w_D3Rur7KQQzSDk,429
|
@@ -1813,7 +1814,7 @@ vellum/workflows/events/tests/test_basic_workflow.py,sha256=Pj6orHsXz37jWC5FARi0
|
|
1813
1814
|
vellum/workflows/events/tests/test_event.py,sha256=jsC8APdrddLs5ejk9NO0waPLLslsJlBMIvN0M_vpAHI,19692
|
1814
1815
|
vellum/workflows/events/types.py,sha256=mVrqAH9Hs9SpXm08Hcxdyap_ImQPwGsxRr56rSNMP34,5043
|
1815
1816
|
vellum/workflows/events/workflow.py,sha256=kLSWFXiDZH0TELWoDjQ_kHVomFnw8MVVUPDGIzgyosw,8997
|
1816
|
-
vellum/workflows/exceptions.py,sha256=
|
1817
|
+
vellum/workflows/exceptions.py,sha256=nb05hAh-afzZ9hek7vhegq-zDtmHopv-4No3aZ-gKO4,1941
|
1817
1818
|
vellum/workflows/executable.py,sha256=um-gLJMVYfGJwGJfZIPlCRHhHIYm6pn8PUEfeqrNx5k,218
|
1818
1819
|
vellum/workflows/expressions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1819
1820
|
vellum/workflows/expressions/accessor.py,sha256=3lu1-_-dBfZdJvtX-q66jbmRAZtqIfdsh_3_JNuzg1E,4462
|
@@ -1928,12 +1929,12 @@ vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMD
|
|
1928
1929
|
vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
|
1929
1930
|
vellum/workflows/nodes/displayable/bases/utils.py,sha256=X1YSPmbBlxDrTAw6dy2-9HrIG8Vb_J-2k1lP3i-SOsk,6951
|
1930
1931
|
vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
|
1931
|
-
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=
|
1932
|
+
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=t4AuqyGOSgitYUUs6Tqzo7lDeyOyJ5g8x7Q9j4UkH7M,10426
|
1932
1933
|
vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1933
1934
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1934
1935
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
|
1935
|
-
vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py,sha256=
|
1936
|
-
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=
|
1936
|
+
vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py,sha256=RQy7SsA39kTJAudzpYNN3jK_kuq6bWNZUld54H5pRZA,40966
|
1937
|
+
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=0F_4PVvB7vjsV0RS48Brv_4djebWOMR_zgzHxzA9iV4,3308
|
1937
1938
|
vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
|
1938
1939
|
vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=71ZUNfTiD7t2Kai2ypw0tmv1lSf1brQaHAQD-SeUrGE,1101
|
1939
1940
|
vellum/workflows/nodes/displayable/conftest.py,sha256=K2kLM2JGAfcrmmd92u8DXInUO5klFdggPWblg5RVcx4,5729
|
@@ -2018,7 +2019,7 @@ vellum/workflows/resolvers/resolver.py,sha256=yK-oY0HDsFJcjlNKAm3vpsPKRIFerIh59F
|
|
2018
2019
|
vellum/workflows/resolvers/tests/test_resolver.py,sha256=jXkJBb9SwtoH__bBN-ECohpyD0aTIB9ErEvtFhuTMQM,9750
|
2019
2020
|
vellum/workflows/resolvers/types.py,sha256=Hndhlk69g6EKLh_LYg5ILepW5U_h_BYNllfzhS9k8p4,237
|
2020
2021
|
vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8vyT-bqM,72
|
2021
|
-
vellum/workflows/runner/runner.py,sha256
|
2022
|
+
vellum/workflows/runner/runner.py,sha256=-x4Ud63HwH81LufNJXzUDP1LTv6yJZ9bBG-OLkPRHMA,42299
|
2022
2023
|
vellum/workflows/sandbox.py,sha256=mezSZmilR_fwR8164n8CEfzlMeQ55IqfapHp4ftImvQ,3212
|
2023
2024
|
vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
|
2024
2025
|
vellum/workflows/state/base.py,sha256=m9fCqbZn21GshCVCjJTD1dPZEQjFrsMXqlg7tM9fIwM,24283
|
@@ -2053,17 +2054,17 @@ vellum/workflows/utils/tests/test_names.py,sha256=DnRRnuORxQXx9ESegCzkxiWcHy2_bB
|
|
2053
2054
|
vellum/workflows/utils/tests/test_uuids.py,sha256=i77ABQ0M3S-aFLzDXHJq_yr5FPkJEWCMBn1HJ3DObrE,437
|
2054
2055
|
vellum/workflows/utils/tests/test_vellum_variables.py,sha256=X7b-bbN3bFRx0WG31bowcaOgsXxEPYnh2sgpsqgKIsQ,2096
|
2055
2056
|
vellum/workflows/utils/uuids.py,sha256=IaZQANz7fhF7la0_J1O50Y6D2PIYv_taRDTRzBT9aWw,1284
|
2056
|
-
vellum/workflows/utils/vellum_variables.py,sha256=
|
2057
|
+
vellum/workflows/utils/vellum_variables.py,sha256=X3lZn-EoWengRWBWRhTNW7hqbj7LkV-6NSMwCskWEbg,7203
|
2057
2058
|
vellum/workflows/utils/zip.py,sha256=HVg_YZLmBOTXKaDV3Xhaf3V6sYnfqqZXQ8CpuafkbPY,1181
|
2058
2059
|
vellum/workflows/vellum_client.py,sha256=3iDR7VV_NgLSm1iZQCKDvrmfEaX1bOJiU15QrxyHpv0,1237
|
2059
2060
|
vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
|
2060
|
-
vellum/workflows/workflows/base.py,sha256=
|
2061
|
+
vellum/workflows/workflows/base.py,sha256=gV3qMaN1hMNEoO3s1Q1G7lMeacTObYDs9LHEwXNTYHE,29819
|
2061
2062
|
vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnadGsrSZGa7t7LpJA,2008
|
2062
2063
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2063
2064
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=Boa-_m9ii2Qsa1RvVM-VYniF7zCpzGgEGy-OnPZkrHg,23941
|
2064
2065
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
2065
|
-
vellum_ai-1.6.
|
2066
|
-
vellum_ai-1.6.
|
2067
|
-
vellum_ai-1.6.
|
2068
|
-
vellum_ai-1.6.
|
2069
|
-
vellum_ai-1.6.
|
2066
|
+
vellum_ai-1.6.3.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
2067
|
+
vellum_ai-1.6.3.dist-info/METADATA,sha256=4U7TNEZ9YCRzcEOlmFSgbJuzwscBVf182IlYSFW2kOc,5547
|
2068
|
+
vellum_ai-1.6.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
2069
|
+
vellum_ai-1.6.3.dist-info/entry_points.txt,sha256=xVavzAKN4iF_NbmhWOlOkHluka0YLkbN_pFQ9pW3gLI,117
|
2070
|
+
vellum_ai-1.6.3.dist-info/RECORD,,
|
vellum_cli/image_push.py
CHANGED
@@ -123,6 +123,13 @@ def image_push_command(
|
|
123
123
|
suggestion="Make sure your VELLUM_API_KEY environment variable is set correctly.",
|
124
124
|
)
|
125
125
|
return
|
126
|
+
elif e.status_code == 400 and isinstance(e.body, dict) and "detail" in e.body:
|
127
|
+
handle_cli_error(
|
128
|
+
logger,
|
129
|
+
title="API request failed",
|
130
|
+
message=e.body["detail"],
|
131
|
+
)
|
132
|
+
return
|
126
133
|
elif e.status_code == 500:
|
127
134
|
handle_cli_error(
|
128
135
|
logger,
|
@@ -215,6 +222,13 @@ def image_push_command(
|
|
215
222
|
suggestion="Make sure your VELLUM_API_KEY environment variable is set correctly.",
|
216
223
|
)
|
217
224
|
return
|
225
|
+
elif e.status_code == 400 and isinstance(e.body, dict) and "detail" in e.body:
|
226
|
+
handle_cli_error(
|
227
|
+
logger,
|
228
|
+
title="API request failed",
|
229
|
+
message=e.body["detail"],
|
230
|
+
)
|
231
|
+
return
|
218
232
|
elif e.status_code == 500:
|
219
233
|
handle_cli_error(
|
220
234
|
logger,
|
@@ -62,6 +62,37 @@ def test_image_push_docker_service_token_500_error(mock_docker_from_env, mock_ru
|
|
62
62
|
assert "try again later" in result.output
|
63
63
|
|
64
64
|
|
65
|
+
@patch("subprocess.run")
|
66
|
+
@patch("docker.from_env")
|
67
|
+
def test_image_push_docker_service_token_400_error(mock_docker_from_env, mock_run, vellum_client, monkeypatch):
|
68
|
+
monkeypatch.setenv("VELLUM_API_URL", "https://api.vellum.ai")
|
69
|
+
monkeypatch.setenv("VELLUM_API_KEY", "123456abcdef")
|
70
|
+
|
71
|
+
mock_docker_client = mock_docker_from_env.return_value
|
72
|
+
mock_docker_client.images.get.return_value.id = "test-image-id"
|
73
|
+
|
74
|
+
mock_run.side_effect = [
|
75
|
+
subprocess.CompletedProcess(args="", returncode=0, stdout=b"Pruning successful"),
|
76
|
+
subprocess.CompletedProcess(
|
77
|
+
args="", returncode=0, stdout=b'{"manifests": [{"platform": {"architecture": "amd64"}}]}'
|
78
|
+
),
|
79
|
+
]
|
80
|
+
|
81
|
+
vellum_client.container_images.docker_service_token.side_effect = ApiError(
|
82
|
+
status_code=400,
|
83
|
+
body={
|
84
|
+
"detail": "Invalid image configuration: missing required metadata",
|
85
|
+
},
|
86
|
+
)
|
87
|
+
|
88
|
+
runner = CliRunner()
|
89
|
+
result = runner.invoke(cli_main, ["image", "push", "myimage:latest"])
|
90
|
+
|
91
|
+
assert result.exit_code == 1
|
92
|
+
assert "API request failed" in result.output
|
93
|
+
assert "Invalid image configuration: missing required metadata" in result.output
|
94
|
+
|
95
|
+
|
65
96
|
@patch("subprocess.run")
|
66
97
|
@patch("docker.from_env")
|
67
98
|
def test_image_push_docker_service_token_other_error(mock_docker_from_env, mock_run, vellum_client, monkeypatch):
|
@@ -156,6 +187,43 @@ def test_image_push_container_image_500_error(mock_docker_from_env, mock_run, ve
|
|
156
187
|
assert "try again later" in result.output
|
157
188
|
|
158
189
|
|
190
|
+
@patch("subprocess.run")
|
191
|
+
@patch("docker.from_env")
|
192
|
+
def test_image_push_container_image_400_error(mock_docker_from_env, mock_run, vellum_client, monkeypatch):
|
193
|
+
monkeypatch.setenv("VELLUM_API_URL", "https://api.vellum.ai")
|
194
|
+
monkeypatch.setenv("VELLUM_API_KEY", "123456abcdef")
|
195
|
+
|
196
|
+
mock_docker_client = mock_docker_from_env.return_value
|
197
|
+
mock_docker_client.images.get.return_value.id = "test-image-id"
|
198
|
+
mock_docker_client.images.push.return_value = ["pushed"]
|
199
|
+
|
200
|
+
mock_run.side_effect = [
|
201
|
+
subprocess.CompletedProcess(args="", returncode=0, stdout=b"Pruning successful"),
|
202
|
+
subprocess.CompletedProcess(
|
203
|
+
args="", returncode=0, stdout=b'{"manifests": [{"platform": {"architecture": "amd64"}}]}'
|
204
|
+
),
|
205
|
+
subprocess.CompletedProcess(args="", returncode=0, stdout=b'[{"RepoDigests": ["test-repo@sha256:abcd1234"]}]'),
|
206
|
+
]
|
207
|
+
|
208
|
+
vellum_client.container_images.docker_service_token.return_value = type(
|
209
|
+
"obj", (object,), {"access_token": "345678mnopqr", "organization_id": str(uuid4()), "repository": "myrepo.net"}
|
210
|
+
)()
|
211
|
+
|
212
|
+
vellum_client.container_images.push_container_image.side_effect = ApiError(
|
213
|
+
status_code=400,
|
214
|
+
body={
|
215
|
+
"detail": "Image validation failed: unsupported architecture",
|
216
|
+
},
|
217
|
+
)
|
218
|
+
|
219
|
+
runner = CliRunner()
|
220
|
+
result = runner.invoke(cli_main, ["image", "push", "myimage:latest"])
|
221
|
+
|
222
|
+
assert result.exit_code == 1
|
223
|
+
assert "API request failed" in result.output
|
224
|
+
assert "Image validation failed: unsupported architecture" in result.output
|
225
|
+
|
226
|
+
|
159
227
|
@patch("subprocess.run")
|
160
228
|
@patch("docker.from_env")
|
161
229
|
def test_image_push_container_image_other_error(mock_docker_from_env, mock_run, vellum_client, monkeypatch):
|
vellum_ee/workflows/display/tests/workflow_serialization/test_terminal_node_any_serialization.py
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
from vellum.workflows.inputs.base import BaseInputs
|
4
|
+
from vellum.workflows.nodes.displayable.final_output_node import FinalOutputNode
|
5
|
+
from vellum.workflows.state.base import BaseState
|
6
|
+
from vellum.workflows.workflows.base import BaseWorkflow
|
7
|
+
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
8
|
+
|
9
|
+
|
10
|
+
class Inputs(BaseInputs):
|
11
|
+
input: Any
|
12
|
+
|
13
|
+
|
14
|
+
class AnyFinalOutputNode(FinalOutputNode[BaseState, Any]):
|
15
|
+
class Outputs(FinalOutputNode.Outputs):
|
16
|
+
value: Any = Inputs.input
|
17
|
+
|
18
|
+
|
19
|
+
class AnyFinalOutputNodeWorkflow(BaseWorkflow[Inputs, BaseState]):
|
20
|
+
graph = AnyFinalOutputNode
|
21
|
+
|
22
|
+
class Outputs(BaseWorkflow.Outputs):
|
23
|
+
value = AnyFinalOutputNode.Outputs.value
|
24
|
+
|
25
|
+
|
26
|
+
def test_serialize_workflow_with_any_output_type():
|
27
|
+
"""
|
28
|
+
Tests that a terminal node with Any output type can be serialized correctly.
|
29
|
+
"""
|
30
|
+
# GIVEN a Workflow that uses a Final Output Node with Any type
|
31
|
+
# WHEN we serialize it
|
32
|
+
workflow_display = get_workflow_display(workflow_class=AnyFinalOutputNodeWorkflow)
|
33
|
+
serialized_workflow: dict = workflow_display.serialize()
|
34
|
+
|
35
|
+
# THEN we should get a serialized representation of the Workflow
|
36
|
+
assert serialized_workflow.keys() == {
|
37
|
+
"workflow_raw_data",
|
38
|
+
"input_variables",
|
39
|
+
"state_variables",
|
40
|
+
"output_variables",
|
41
|
+
}
|
42
|
+
|
43
|
+
workflow_raw_data = serialized_workflow["workflow_raw_data"]
|
44
|
+
terminal_node = next(node for node in workflow_raw_data["nodes"] if node["type"] == "TERMINAL")
|
45
|
+
assert terminal_node["data"]["output_type"] == "JSON"
|
46
|
+
|
47
|
+
output_variables = serialized_workflow["output_variables"]
|
48
|
+
assert len(output_variables) == 1
|
49
|
+
assert output_variables[0]["type"] == "JSON"
|
@@ -1,6 +1,25 @@
|
|
1
|
+
import pytest
|
2
|
+
from pathlib import Path
|
3
|
+
import shutil
|
4
|
+
import sys
|
5
|
+
import tempfile
|
6
|
+
|
7
|
+
from vellum.workflows.exceptions import WorkflowInitializationException
|
1
8
|
from vellum_ee.workflows.display.workflows.base_workflow_display import BaseWorkflowDisplay
|
2
9
|
|
3
10
|
|
11
|
+
@pytest.fixture
|
12
|
+
def temp_module_path():
|
13
|
+
"""Fixture to manage sys.path for temporary modules."""
|
14
|
+
temp_dir = tempfile.mkdtemp()
|
15
|
+
sys.path.insert(0, temp_dir)
|
16
|
+
try:
|
17
|
+
yield temp_dir
|
18
|
+
finally:
|
19
|
+
sys.path.remove(temp_dir)
|
20
|
+
shutil.rmtree(temp_dir)
|
21
|
+
|
22
|
+
|
4
23
|
def test_serialize_module_with_dataset():
|
5
24
|
"""Test that serialize_module correctly serializes dataset from sandbox modules."""
|
6
25
|
module_path = "tests.workflows.basic_inputs_and_outputs"
|
@@ -75,3 +94,37 @@ def test_serialize_module_includes_additional_files():
|
|
75
94
|
assert "def helper_function():" in additional_files["helper.py"]
|
76
95
|
assert "sample data file" in additional_files["data.txt"]
|
77
96
|
assert "CONSTANT_VALUE" in additional_files["utils/constants.py"]
|
97
|
+
|
98
|
+
|
99
|
+
def test_serialize_module__with_invalid_nested_set_graph(temp_module_path):
|
100
|
+
"""
|
101
|
+
Tests that serialize_module raises a clear user-facing exception for workflows with nested sets in graph attribute.
|
102
|
+
"""
|
103
|
+
module_dir = Path(temp_module_path) / "test_invalid_workflow"
|
104
|
+
module_dir.mkdir()
|
105
|
+
|
106
|
+
(module_dir / "__init__.py").write_text("")
|
107
|
+
|
108
|
+
workflow_content = """
|
109
|
+
from vellum.workflows import BaseWorkflow
|
110
|
+
from vellum.workflows.nodes import BaseNode
|
111
|
+
|
112
|
+
class TestNode(BaseNode):
|
113
|
+
class Outputs(BaseNode.Outputs):
|
114
|
+
value = "test"
|
115
|
+
|
116
|
+
class InvalidWorkflow(BaseWorkflow):
|
117
|
+
graph = {TestNode, {TestNode}}
|
118
|
+
|
119
|
+
class Outputs(BaseWorkflow.Outputs):
|
120
|
+
result = TestNode.Outputs.value
|
121
|
+
"""
|
122
|
+
(module_dir / "workflow.py").write_text(workflow_content)
|
123
|
+
|
124
|
+
with pytest.raises(WorkflowInitializationException) as exc_info:
|
125
|
+
BaseWorkflowDisplay.serialize_module("test_invalid_workflow")
|
126
|
+
|
127
|
+
error_message = str(exc_info.value)
|
128
|
+
assert "Invalid graph structure detected" in error_message
|
129
|
+
assert "Nested sets or unsupported graph types are not allowed" in error_message
|
130
|
+
assert "contact Vellum support" in error_message
|
File without changes
|
File without changes
|
File without changes
|