vellum-ai 0.14.70__py3-none-any.whl → 0.14.71__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 +1 -1
- vellum/workflows/environment/environment.py +5 -2
- vellum/workflows/nodes/displayable/code_execution_node/node.py +8 -1
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py +53 -0
- vellum/workflows/references/environment_variable.py +11 -8
- {vellum_ai-0.14.70.dist-info → vellum_ai-0.14.71.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.70.dist-info → vellum_ai-0.14.71.dist-info}/RECORD +17 -15
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +7 -3
- vellum_ee/workflows/display/nodes/vellum/search_node.py +69 -6
- vellum_ee/workflows/display/nodes/vellum/tests/test_search_node.py +104 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +82 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py +4 -4
- vellum_ee/workflows/display/tests/workflow_serialization/test_workflow_input_parameterization_error.py +37 -0
- vellum_ee/workflows/display/utils/expressions.py +10 -1
- {vellum_ai-0.14.70.dist-info → vellum_ai-0.14.71.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.70.dist-info → vellum_ai-0.14.71.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.70.dist-info → vellum_ai-0.14.71.dist-info}/entry_points.txt +0 -0
@@ -18,7 +18,7 @@ class BaseClientWrapper:
|
|
18
18
|
headers: typing.Dict[str, str] = {
|
19
19
|
"X-Fern-Language": "Python",
|
20
20
|
"X-Fern-SDK-Name": "vellum-ai",
|
21
|
-
"X-Fern-SDK-Version": "0.14.
|
21
|
+
"X-Fern-SDK-Version": "0.14.71",
|
22
22
|
}
|
23
23
|
headers["X-API-KEY"] = self.api_key
|
24
24
|
return headers
|
@@ -5,8 +5,11 @@ from vellum.workflows.references import EnvironmentVariableReference
|
|
5
5
|
|
6
6
|
class EnvironmentVariables:
|
7
7
|
@staticmethod
|
8
|
-
def get(name: str, default: Optional[str] = None)
|
9
|
-
|
8
|
+
def get(name: str, default: Optional[str] = None):
|
9
|
+
env_ref = EnvironmentVariableReference(name=name)
|
10
|
+
if default is not None:
|
11
|
+
return env_ref.coalesce(default)
|
12
|
+
return env_ref
|
10
13
|
|
11
14
|
|
12
15
|
# Deprecated: Use EnvironmentVariables instead. Will be removed in v0.15.0
|
@@ -98,7 +98,7 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
|
|
98
98
|
def run(self) -> Outputs:
|
99
99
|
output_type = self.__class__.get_output_type()
|
100
100
|
code, filepath = self._resolve_code()
|
101
|
-
if not self.packages and self.runtime == "PYTHON_3_11_6":
|
101
|
+
if not self.packages and self.runtime == "PYTHON_3_11_6" and not self._has_secrets_in_code_inputs():
|
102
102
|
logs, result = run_code_inline(code, self.code_inputs, output_type, filepath)
|
103
103
|
return self.Outputs(result=result, log=logs)
|
104
104
|
|
@@ -133,6 +133,13 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
|
|
133
133
|
|
134
134
|
return self.Outputs(result=code_execution_result.output.value, log=code_execution_result.log)
|
135
135
|
|
136
|
+
def _has_secrets_in_code_inputs(self) -> bool:
|
137
|
+
"""Check if any code_inputs contain VellumSecret instances that require API execution."""
|
138
|
+
for input_value in self.code_inputs.values():
|
139
|
+
if isinstance(input_value, VellumSecret):
|
140
|
+
return True
|
141
|
+
return False
|
142
|
+
|
136
143
|
def _compile_code_inputs(self) -> List[CodeExecutorInput]:
|
137
144
|
# TODO: We may want to consolidate with prompt deployment input compilation
|
138
145
|
# https://app.shortcut.com/vellum/story/4117
|
@@ -1233,3 +1233,56 @@ def main(numbers: List[str]) -> str:
|
|
1233
1233
|
],
|
1234
1234
|
request_options=None,
|
1235
1235
|
)
|
1236
|
+
|
1237
|
+
|
1238
|
+
def test_run_node__vellum_secret_forces_api_execution(vellum_client):
|
1239
|
+
"""Test that CodeExecutionNode with VellumSecretReference forces API execution instead of inline execution."""
|
1240
|
+
|
1241
|
+
# GIVEN a node that subclasses CodeExecutionNode with VellumSecretReference but no packages
|
1242
|
+
# This should normally run inline, but the presence of secrets should force API execution
|
1243
|
+
class State(BaseState):
|
1244
|
+
pass
|
1245
|
+
|
1246
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[State, str]):
|
1247
|
+
code = """
|
1248
|
+
def main(secret: str) -> str:
|
1249
|
+
return f"Secret value: {secret}"
|
1250
|
+
"""
|
1251
|
+
runtime = "PYTHON_3_11_6"
|
1252
|
+
# Note: No packages specified, which would normally trigger inline execution
|
1253
|
+
|
1254
|
+
code_inputs = {
|
1255
|
+
"secret": VellumSecretReference("MY_SECRET"),
|
1256
|
+
}
|
1257
|
+
|
1258
|
+
# AND we know what the Code Execution Node will respond with
|
1259
|
+
mock_code_execution = CodeExecutorResponse(
|
1260
|
+
log="",
|
1261
|
+
output=StringVellumValue(value="Secret value: my_secret_value"),
|
1262
|
+
)
|
1263
|
+
vellum_client.execute_code.return_value = mock_code_execution
|
1264
|
+
|
1265
|
+
# WHEN we run the node
|
1266
|
+
node = ExampleCodeExecutionNode(state=State())
|
1267
|
+
outputs = node.run()
|
1268
|
+
|
1269
|
+
# THEN the node should have produced the outputs we expect
|
1270
|
+
assert outputs == {"result": "Secret value: my_secret_value", "log": ""}
|
1271
|
+
|
1272
|
+
# AND we should have invoked the Code via API (not inline) due to the secret
|
1273
|
+
vellum_client.execute_code.assert_called_once_with(
|
1274
|
+
input_values=[
|
1275
|
+
CodeExecutorSecretInput(
|
1276
|
+
name="secret",
|
1277
|
+
value="MY_SECRET",
|
1278
|
+
)
|
1279
|
+
],
|
1280
|
+
code="""
|
1281
|
+
def main(secret: str) -> str:
|
1282
|
+
return f"Secret value: {secret}"
|
1283
|
+
""",
|
1284
|
+
runtime="PYTHON_3_11_6",
|
1285
|
+
output_type="STRING",
|
1286
|
+
packages=[],
|
1287
|
+
request_options=None,
|
1288
|
+
)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import os
|
2
|
-
from typing import TYPE_CHECKING, Optional
|
2
|
+
from typing import TYPE_CHECKING, Any, Optional
|
3
3
|
|
4
|
+
from vellum.workflows.constants import undefined
|
4
5
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
5
6
|
|
6
7
|
if TYPE_CHECKING:
|
@@ -8,16 +9,18 @@ if TYPE_CHECKING:
|
|
8
9
|
|
9
10
|
|
10
11
|
class EnvironmentVariableReference(BaseDescriptor[str]):
|
11
|
-
def __init__(
|
12
|
+
def __init__(
|
13
|
+
self,
|
14
|
+
*,
|
15
|
+
name: str,
|
16
|
+
# DEPRECATED - to be removed in 0.15.0 release
|
17
|
+
default: Optional[str] = None,
|
18
|
+
):
|
12
19
|
super().__init__(name=name, types=(str,))
|
13
|
-
self._default = default
|
14
20
|
|
15
|
-
def resolve(self, state: "BaseState") ->
|
21
|
+
def resolve(self, state: "BaseState") -> Any:
|
16
22
|
env_value = os.environ.get(self.name)
|
17
23
|
if env_value is not None:
|
18
24
|
return env_value
|
19
25
|
|
20
|
-
|
21
|
-
return self._default
|
22
|
-
|
23
|
-
return ""
|
26
|
+
return undefined
|
@@ -41,14 +41,14 @@ vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=9GtbvSJUNF62
|
|
41
41
|
vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=YhMsi2TG1zSR8E7IpxzzSncOyVLcvqTuGa3mr4RqHd8,2364
|
42
42
|
vellum_ee/workflows/display/nodes/vellum/final_output_node.py,sha256=zo-nalsuayMqeb2GwR2OB9SFK3y2U5aG-rtwrsjdasQ,3089
|
43
43
|
vellum_ee/workflows/display/nodes/vellum/guardrail_node.py,sha256=IniO5KvO0Rw9zghFg3RFvbXBTv6Zi1iuQhaA1DLazqU,2331
|
44
|
-
vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=
|
44
|
+
vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=1ydd1-SXCuJdPDquMrvV5JXIIhf7eBdvY2dXqDz_r5o,11035
|
45
45
|
vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py,sha256=f7MeoxgKrdyb1dSJsvdDtZPlp1J2Pa4njPvN3qHVktA,6028
|
46
46
|
vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=uaZ2wcZR1J9C9iI0QWAsgNK9IlcuCz1808oxXmiYsLY,3908
|
47
47
|
vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=RTP_raQWL8ZKoRKLpxLfpyXzw61TZeTCkTuM1uRLIkI,3274
|
48
48
|
vellum_ee/workflows/display/nodes/vellum/note_node.py,sha256=6xf8MJ684KecKPJrGlCJuJYLPtYImXmqN85Y_6KPjW4,1141
|
49
49
|
vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py,sha256=cT5qT7Nd2v6rSsIErpSAWaxta7txGOSFOZz2AQYQmWE,3536
|
50
50
|
vellum_ee/workflows/display/nodes/vellum/retry_node.py,sha256=Gos8F1yKN69GmegDO2q3NlGTamibd4rpuTasSU0mK8c,3281
|
51
|
-
vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=
|
51
|
+
vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=bF07csUFSQlAeOayPPws5pz3tBTp1PdwgHb8WItgXmY,12319
|
52
52
|
vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py,sha256=Ub6XDdVtVarqoqQrIXpJxNbp3xvz37vwpuf93DhLvX8,2670
|
53
53
|
vellum_ee/workflows/display/nodes/vellum/templating_node.py,sha256=TdIJWh2l8p4tw7ejRexGOFQKnviirUqie3WYwsrVQ4g,3339
|
54
54
|
vellum_ee/workflows/display/nodes/vellum/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -59,6 +59,7 @@ vellum_ee/workflows/display/nodes/vellum/tests/test_note_node.py,sha256=uiMB0cOx
|
|
59
59
|
vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_deployment_node.py,sha256=G-qJyTNJkpqJiEZ3kCJl86CXJINLeFyf2lM0bQHCCOs,3822
|
60
60
|
vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py,sha256=TtzUj3Zk3ZhwtXE_WyctCC-CmcLB1RxntyF7u-a3i6I,10077
|
61
61
|
vellum_ee/workflows/display/nodes/vellum/tests/test_retry_node.py,sha256=h93ysolmbo2viisyhRnXKHPxiDK0I_dSAbYoHFYIoO4,1953
|
62
|
+
vellum_ee/workflows/display/nodes/vellum/tests/test_search_node.py,sha256=KvByxgbUkVyfPIVxTUBUk6a92JiJMi8eReZWxzfPExU,3864
|
62
63
|
vellum_ee/workflows/display/nodes/vellum/tests/test_subworkflow_deployment_node.py,sha256=BUzHJgjdWnPeZxjFjHfDBKnbFjYjnbXPjc-1hne1B2Y,3965
|
63
64
|
vellum_ee/workflows/display/nodes/vellum/tests/test_templating_node.py,sha256=LSk2gx9TpGXbAqKe8dggQW8yJZqj-Cf0EGJFeGGlEcw,3321
|
64
65
|
vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py,sha256=ZsLIGnJ9QKrXjYeDW8LEN8M9FnWRQ9TohHFyB6144HY,7970
|
@@ -83,12 +84,12 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_stat
|
|
83
84
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py,sha256=MNnQ51ZWOQGVfBdpIqvr4OZF0tWdfrh2bsHP3xkTwQw,5841
|
84
85
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py,sha256=kLOnUNn-r1w1JXNQcVKe-Vp-fKhSfuDBuDqrjGkFZ3U,5544
|
85
86
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py,sha256=v07cILUzS5iFYDrSOAXK93yz50-FtxLaMYMwoaPOv20,7374
|
86
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py,sha256=
|
87
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py,sha256=glOPy9y_GOLGMxc7glfo7IGq5iuCDbz9-TE_6Krha2U,18426
|
87
88
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py,sha256=1ND_6lfPNUQjSc72k_sxydeeOU5f_kHkRXO65boYFok,21631
|
88
89
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py,sha256=3gZuNM8sT6ovVaeoAvd2JoyKwuxokvowlhH8kwDUoZ8,16559
|
89
90
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py,sha256=IIJt7YZBzkhNtbmaMwCX4ENs58QtSIIoBHlMR6OwGU8,8342
|
90
91
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py,sha256=QXiRjwtiTPeMUl40Pvh_geeU99C3mv1aVS85oeIUwY4,21052
|
91
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py,sha256=
|
92
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py,sha256=JuosR1Xvyy2-0UKuCxx0P_3QH3OXgU88llxpyQ7NScM,12936
|
92
93
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py,sha256=KkYZc_bZuq1lmDcvUz3QxIqJLpQPCZioD1FHUNsMJY8,11211
|
93
94
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py,sha256=aZaqRDrkO3ytcmdM2eKJqHSt60MF070NMj6M2vgzOKc,7711
|
94
95
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py,sha256=r748dpS13HtwY7t_KQFExFssxRy0xI2d-wxmhiUHRe0,3850
|
@@ -96,11 +97,12 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling
|
|
96
97
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=Cx3oY6vPVap0xm_mChqfQw4zzR4pqV36o_SyD8g6jPY,8727
|
97
98
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py,sha256=EL5kfakuoEcwD85dGjhMta-J-PpCHRSDoc80SdbBrQk,2769
|
98
99
|
vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py,sha256=RmFUDx8dYdfsOE2CGLvdXqNNRtLLpVzXDN8dqZyMcZ8,5822
|
100
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_workflow_input_parameterization_error.py,sha256=vAdmn3YTBDpo55znbydQxsgg9ASqHcvsUPwiBR_7wfo,1461
|
99
101
|
vellum_ee/workflows/display/types.py,sha256=i4T7ElU5b5h-nA1i3scmEhO1BqmNDc4eJDHavATD88w,2821
|
100
102
|
vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
101
103
|
vellum_ee/workflows/display/utils/auto_layout.py,sha256=R_BLSZjdanj3UIR4cS6WVT6ek0i7AKJyHSjK1wPiois,3877
|
102
104
|
vellum_ee/workflows/display/utils/exceptions.py,sha256=LSwwxCYNxFkf5XMUcFkaZKpQ13OSrI7y_bpEUwbKVk0,169
|
103
|
-
vellum_ee/workflows/display/utils/expressions.py,sha256=
|
105
|
+
vellum_ee/workflows/display/utils/expressions.py,sha256=bSZ-sRByLCsut8XcRkCFbbqYvw9p7tlIeF-HFnEm664,14354
|
104
106
|
vellum_ee/workflows/display/utils/registry.py,sha256=fWIm5Jj-10gNFjgn34iBu4RWv3Vd15ijtSN0V97bpW8,1513
|
105
107
|
vellum_ee/workflows/display/utils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
106
108
|
vellum_ee/workflows/display/utils/tests/test_auto_layout.py,sha256=vfXI769418s9vda5Gb5NFBH747WMOwSgHRXeLCTLVm8,2356
|
@@ -140,7 +142,7 @@ vellum/client/README.md,sha256=CuGUYnaE0Imt0KqQ4sIPaUghCjLHkF3DdEvZWu14-8s,4807
|
|
140
142
|
vellum/client/__init__.py,sha256=AYopGv2ZRVn3zsU8_km6KOvEHDbXiTPCVuYVI7bWvdA,120166
|
141
143
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
142
144
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
143
|
-
vellum/client/core/client_wrapper.py,sha256=
|
145
|
+
vellum/client/core/client_wrapper.py,sha256=3ZqkR_DngkaI-fY5PAgWW2c7RZ88oONDwDkWfxAKLBc,1869
|
144
146
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
145
147
|
vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
146
148
|
vellum/client/core/http_client.py,sha256=Z77OIxIbL4OAB2IDqjRq_sYa5yNYAWfmdhdCSSvh6Y4,19552
|
@@ -1504,7 +1506,7 @@ vellum/workflows/edges/edge.py,sha256=N0SnY3gKVuxImPAdCbPMPlHJIXbkQ3fwq_LbJRvVMF
|
|
1504
1506
|
vellum/workflows/emitters/__init__.py,sha256=YyOgaoLtVW8eFNEWODzCYb0HzL0PoSeNRf4diJ1Y0dk,80
|
1505
1507
|
vellum/workflows/emitters/base.py,sha256=D5SADKIvnbgKwIBgYm77jaqvpo1o0rz4MmuX_muRqQU,359
|
1506
1508
|
vellum/workflows/environment/__init__.py,sha256=TJz0m9dwIs6YOwCTeuN0HHsU-ecyjc1OJXx4AFy83EQ,121
|
1507
|
-
vellum/workflows/environment/environment.py,sha256=
|
1509
|
+
vellum/workflows/environment/environment.py,sha256=Ck3RPKXJvtMGx_toqYQQQF-ZwXm5ijVwJpEPTeIJ4_Q,471
|
1508
1510
|
vellum/workflows/errors/__init__.py,sha256=tWGPu5xyAU8gRb8_bl0fL7OfU3wxQ9UH6qVwy4X4P_Q,113
|
1509
1511
|
vellum/workflows/errors/types.py,sha256=nUWuniEfrhdtb-_2GzoDGlYnSJ_yuNUGjVkaKLNr-rM,4049
|
1510
1512
|
vellum/workflows/events/__init__.py,sha256=6pxxceJo2dcaRkWtkDAYlUQZ-PHBQSZytIoyuUK48Qw,759
|
@@ -1608,11 +1610,11 @@ vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMD
|
|
1608
1610
|
vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
|
1609
1611
|
vellum/workflows/nodes/displayable/bases/utils.py,sha256=ckMUenSsNkiYmSw6FmjSMHYaCk8Y8_sUjL6lkFFEqts,5412
|
1610
1612
|
vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
|
1611
|
-
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=
|
1613
|
+
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=Qh4SPafzdRKbVKQH3h9SgH4vKeQQjvHAfP8ttUxLA2M,10304
|
1612
1614
|
vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1613
1615
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1614
1616
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
|
1615
|
-
vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py,sha256=
|
1617
|
+
vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py,sha256=47W5fPLpDcaKhCVuauKOwcivx1NfhpbsRMPrs-WBnlY,38441
|
1616
1618
|
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=VRTKms59vrSR9mDk99cojParZVAP4lzjEeDwDNXU1tk,3837
|
1617
1619
|
vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
|
1618
1620
|
vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=71ZUNfTiD7t2Kai2ypw0tmv1lSf1brQaHAQD-SeUrGE,1101
|
@@ -1672,7 +1674,7 @@ vellum/workflows/ports/port.py,sha256=j_qiZlpx-a1cK5E7sxXwPcb_9NS-KUM-JoP8mgqg32
|
|
1672
1674
|
vellum/workflows/ports/utils.py,sha256=cWJ9xX1KrHBTiU3xe6t7Rs0yaOy9RV18GMtHaAshAsc,3094
|
1673
1675
|
vellum/workflows/references/__init__.py,sha256=glHFC1VfXmcbNvH5VzFbkT03d8_D7MMcvEcsUBrzLIs,591
|
1674
1676
|
vellum/workflows/references/constant.py,sha256=6yUT4q1sMj1hkI_tzzQ9AYcmeeDYFUNCqUq_W2DN0S8,540
|
1675
|
-
vellum/workflows/references/environment_variable.py,sha256
|
1677
|
+
vellum/workflows/references/environment_variable.py,sha256=evpxiBKzBk74JzxBXWkfTrZe4Kx-fuUG1W6XjtXzaUw,700
|
1676
1678
|
vellum/workflows/references/execution_count.py,sha256=JILHqt8ELdc9ct-WsVCA5X-rKiP1rmJODw-XTf4kpHI,722
|
1677
1679
|
vellum/workflows/references/external_input.py,sha256=c_4SojTpykCSbGS1Pjmx9FfquyYGMPksoj0AbrWv7Go,2064
|
1678
1680
|
vellum/workflows/references/input.py,sha256=3INu-TLTi4dziWmva6LO3WvgDlPzsjayUx61cVvqLJA,325
|
@@ -1724,8 +1726,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
|
|
1724
1726
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1725
1727
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=fROqff6AZpCIzaSwOKSdtYy4XR0UZQ6ejxL3RJOSJVs,20447
|
1726
1728
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1727
|
-
vellum_ai-0.14.
|
1728
|
-
vellum_ai-0.14.
|
1729
|
-
vellum_ai-0.14.
|
1730
|
-
vellum_ai-0.14.
|
1731
|
-
vellum_ai-0.14.
|
1729
|
+
vellum_ai-0.14.71.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1730
|
+
vellum_ai-0.14.71.dist-info/METADATA,sha256=C5GX4tfVPU2-YXu_9tu4RToI1a6SafllfrsjW6SiM9c,5556
|
1731
|
+
vellum_ai-0.14.71.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1732
|
+
vellum_ai-0.14.71.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1733
|
+
vellum_ai-0.14.71.dist-info/RECORD,,
|
@@ -2,6 +2,7 @@ from uuid import UUID
|
|
2
2
|
from typing import Callable, Dict, Generic, List, Optional, Tuple, Type, TypeVar, Union
|
3
3
|
|
4
4
|
from vellum import FunctionDefinition, PromptBlock, RichTextChildBlock, VellumVariable
|
5
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
5
6
|
from vellum.workflows.nodes import InlinePromptNode
|
6
7
|
from vellum.workflows.types.core import JsonObject
|
7
8
|
from vellum.workflows.utils.functions import compile_function_definition
|
@@ -18,9 +19,10 @@ _InlinePromptNodeType = TypeVar("_InlinePromptNodeType", bound=InlinePromptNode)
|
|
18
19
|
|
19
20
|
|
20
21
|
class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generic[_InlinePromptNodeType]):
|
21
|
-
__serializable_inputs__ = {
|
22
|
+
__serializable_inputs__ = {
|
23
|
+
InlinePromptNode.prompt_inputs,
|
24
|
+
}
|
22
25
|
__unserializable_attributes__ = {
|
23
|
-
InlinePromptNode.blocks,
|
24
26
|
InlinePromptNode.parameters,
|
25
27
|
InlinePromptNode.settings,
|
26
28
|
InlinePromptNode.expand_meta,
|
@@ -45,7 +47,9 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
45
47
|
ml_model = str(raise_if_descriptor(node.ml_model))
|
46
48
|
|
47
49
|
blocks: list = [
|
48
|
-
self._generate_prompt_block(block, input_variable_id_by_name, [i])
|
50
|
+
self._generate_prompt_block(block, input_variable_id_by_name, [i])
|
51
|
+
for i, block in enumerate(node_blocks)
|
52
|
+
if not isinstance(block, BaseDescriptor)
|
49
53
|
]
|
50
54
|
|
51
55
|
functions = (
|
@@ -7,6 +7,7 @@ from vellum import (
|
|
7
7
|
VellumValueLogicalConditionGroupRequest,
|
8
8
|
VellumValueLogicalConditionRequest,
|
9
9
|
)
|
10
|
+
from vellum.workflows.nodes.displayable.bases.types import MetadataLogicalCondition, MetadataLogicalConditionGroup
|
10
11
|
from vellum.workflows.nodes.displayable.search_node import SearchNode
|
11
12
|
from vellum.workflows.references import OutputReference
|
12
13
|
from vellum.workflows.types.core import JsonArray, JsonObject
|
@@ -88,7 +89,8 @@ class BaseSearchNodeDisplay(BaseNodeDisplay[_SearchNodeType], Generic[_SearchNod
|
|
88
89
|
node_inputs: Dict[str, NodeInput] = {}
|
89
90
|
|
90
91
|
options = raise_if_descriptor(node.options)
|
91
|
-
|
92
|
+
raw_filters = raise_if_descriptor(node.filters)
|
93
|
+
filters = raw_filters if raw_filters else options.filters if options else None
|
92
94
|
|
93
95
|
external_id_filters = filters.external_ids if filters else None
|
94
96
|
|
@@ -104,17 +106,21 @@ class BaseSearchNodeDisplay(BaseNodeDisplay[_SearchNodeType], Generic[_SearchNod
|
|
104
106
|
raw_metadata_filters, display_context=display_context
|
105
107
|
)
|
106
108
|
|
107
|
-
|
109
|
+
raw_result_merging = raise_if_descriptor(node.result_merging)
|
110
|
+
result_merging = raw_result_merging if raw_result_merging else options.result_merging if options else None
|
108
111
|
result_merging_enabled = True if result_merging and result_merging.enabled else False
|
109
112
|
|
110
113
|
raw_weights = raise_if_descriptor(node.weights)
|
111
114
|
weights = raw_weights if raw_weights is not None else options.weights if options is not None else None
|
112
115
|
|
116
|
+
raw_limit = raise_if_descriptor(node.limit)
|
117
|
+
limit = raw_limit if raw_limit is not None else options.limit if options is not None else None
|
118
|
+
|
113
119
|
node_input_names_and_values = [
|
114
120
|
("query", node.query),
|
115
121
|
("document_index_id", node.document_index),
|
116
122
|
("weights", weights.dict() if weights else None),
|
117
|
-
("limit",
|
123
|
+
("limit", limit),
|
118
124
|
("separator", raise_if_descriptor(node.chunk_separator)),
|
119
125
|
(
|
120
126
|
"result_merging_enabled",
|
@@ -141,7 +147,12 @@ class BaseSearchNodeDisplay(BaseNodeDisplay[_SearchNodeType], Generic[_SearchNod
|
|
141
147
|
|
142
148
|
def _serialize_logical_expression(
|
143
149
|
self,
|
144
|
-
logical_expression: Union[
|
150
|
+
logical_expression: Union[
|
151
|
+
VellumValueLogicalConditionGroupRequest,
|
152
|
+
VellumValueLogicalConditionRequest,
|
153
|
+
MetadataLogicalConditionGroup,
|
154
|
+
MetadataLogicalCondition,
|
155
|
+
],
|
145
156
|
display_context: WorkflowDisplayContext,
|
146
157
|
path: List[int] = [],
|
147
158
|
) -> Tuple[JsonObject, List[NodeInput]]:
|
@@ -175,10 +186,10 @@ class BaseSearchNodeDisplay(BaseNodeDisplay[_SearchNodeType], Generic[_SearchNod
|
|
175
186
|
|
176
187
|
lhs_query_input_id: UUID = self.metadata_filter_input_id_by_operand_id.get(
|
177
188
|
UUID(lhs_variable_id)
|
178
|
-
) or uuid4_from_hash(f"{self.node_id}|{hash(tuple(path))}")
|
189
|
+
) or uuid4_from_hash(f"{self.node_id}|lhs|{hash(tuple(path))}")
|
179
190
|
rhs_query_input_id: UUID = self.metadata_filter_input_id_by_operand_id.get(
|
180
191
|
UUID(rhs_variable_id)
|
181
|
-
) or uuid4_from_hash(f"{self.node_id}|{hash(tuple(path))}")
|
192
|
+
) or uuid4_from_hash(f"{self.node_id}|rhs|{hash(tuple(path))}")
|
182
193
|
|
183
194
|
return (
|
184
195
|
{
|
@@ -206,5 +217,57 @@ class BaseSearchNodeDisplay(BaseNodeDisplay[_SearchNodeType], Generic[_SearchNod
|
|
206
217
|
),
|
207
218
|
],
|
208
219
|
)
|
220
|
+
|
221
|
+
elif isinstance(logical_expression, MetadataLogicalConditionGroup):
|
222
|
+
conditions = []
|
223
|
+
variables = []
|
224
|
+
for idx, metadata_condition in enumerate(logical_expression.conditions):
|
225
|
+
serialized_condition, serialized_variables = self._serialize_logical_expression(
|
226
|
+
metadata_condition, display_context=display_context, path=path + [idx]
|
227
|
+
)
|
228
|
+
conditions.append(serialized_condition)
|
229
|
+
variables.extend(serialized_variables)
|
230
|
+
|
231
|
+
return (
|
232
|
+
{
|
233
|
+
"type": "LOGICAL_CONDITION_GROUP",
|
234
|
+
"combinator": logical_expression.combinator,
|
235
|
+
"conditions": conditions,
|
236
|
+
"negated": logical_expression.negated,
|
237
|
+
},
|
238
|
+
variables,
|
239
|
+
)
|
240
|
+
|
241
|
+
elif isinstance(logical_expression, MetadataLogicalCondition):
|
242
|
+
lhs_variable = logical_expression.lhs_variable
|
243
|
+
rhs_variable = logical_expression.rhs_variable
|
244
|
+
|
245
|
+
lhs_query_input_id = uuid4_from_hash(f"{self.node_id}|lhs|{hash(tuple(path))}")
|
246
|
+
rhs_query_input_id = uuid4_from_hash(f"{self.node_id}|rhs|{hash(tuple(path))}")
|
247
|
+
|
248
|
+
return (
|
249
|
+
{
|
250
|
+
"type": "LOGICAL_CONDITION",
|
251
|
+
"lhs_variable_id": str(lhs_query_input_id),
|
252
|
+
"operator": logical_expression.operator,
|
253
|
+
"rhs_variable_id": str(rhs_query_input_id),
|
254
|
+
},
|
255
|
+
[
|
256
|
+
create_node_input(
|
257
|
+
self.node_id,
|
258
|
+
f"vellum-query-builder-variable-{lhs_query_input_id}",
|
259
|
+
lhs_variable,
|
260
|
+
display_context,
|
261
|
+
input_id=lhs_query_input_id,
|
262
|
+
),
|
263
|
+
create_node_input(
|
264
|
+
self.node_id,
|
265
|
+
f"vellum-query-builder-variable-{rhs_query_input_id}",
|
266
|
+
rhs_variable,
|
267
|
+
display_context,
|
268
|
+
input_id=rhs_query_input_id,
|
269
|
+
),
|
270
|
+
],
|
271
|
+
)
|
209
272
|
else:
|
210
273
|
raise ValueError(f"Unsupported logical expression type: {type(logical_expression)}")
|
@@ -0,0 +1,104 @@
|
|
1
|
+
from vellum.workflows import BaseWorkflow
|
2
|
+
from vellum.workflows.inputs import BaseInputs
|
3
|
+
from vellum.workflows.nodes.displayable import SearchNode
|
4
|
+
from vellum.workflows.nodes.displayable.bases.types import (
|
5
|
+
MetadataLogicalCondition,
|
6
|
+
MetadataLogicalConditionGroup,
|
7
|
+
SearchFilters,
|
8
|
+
)
|
9
|
+
from vellum.workflows.state.base import BaseState
|
10
|
+
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
11
|
+
|
12
|
+
|
13
|
+
def test_search_filters_with_input_reference():
|
14
|
+
"""Test that SearchFilters with MetadataLogicalCondition using input references can be serialized"""
|
15
|
+
|
16
|
+
# GIVEN a search node with a metadata filter that uses an input reference
|
17
|
+
class TestInputs(BaseInputs):
|
18
|
+
file_id: str
|
19
|
+
|
20
|
+
class MySearchNode(SearchNode):
|
21
|
+
query = "my query"
|
22
|
+
document_index = "document_index"
|
23
|
+
filters = SearchFilters(
|
24
|
+
external_ids=None,
|
25
|
+
metadata=MetadataLogicalConditionGroup(
|
26
|
+
combinator="AND",
|
27
|
+
negated=False,
|
28
|
+
conditions=[MetadataLogicalCondition(lhs_variable="ID", operator="=", rhs_variable=TestInputs.file_id)],
|
29
|
+
),
|
30
|
+
)
|
31
|
+
|
32
|
+
# AND a workflow with the Search Node
|
33
|
+
class Workflow(BaseWorkflow[TestInputs, BaseState]):
|
34
|
+
graph = MySearchNode
|
35
|
+
|
36
|
+
# WHEN the workflow is serialized
|
37
|
+
workflow_display = get_workflow_display(workflow_class=Workflow)
|
38
|
+
serialized_workflow: dict = workflow_display.serialize()
|
39
|
+
|
40
|
+
# THEN the node should properly serialize the filter reference
|
41
|
+
serialized_search_node = next(
|
42
|
+
node for node in serialized_workflow["workflow_raw_data"]["nodes"] if node["id"] == str(MySearchNode.__id__)
|
43
|
+
)
|
44
|
+
|
45
|
+
serialized_metadata_filter = next(
|
46
|
+
inp for inp in serialized_search_node["inputs"] if inp["key"] == "metadata_filters"
|
47
|
+
)
|
48
|
+
|
49
|
+
assert serialized_metadata_filter == {
|
50
|
+
"id": "4a9f96aa-ba3b-4c4e-9ce4-370fe64f717f",
|
51
|
+
"key": "metadata_filters",
|
52
|
+
"value": {
|
53
|
+
"combinator": "OR",
|
54
|
+
"rules": [
|
55
|
+
{
|
56
|
+
"data": {
|
57
|
+
"type": "JSON",
|
58
|
+
"value": {
|
59
|
+
"combinator": "AND",
|
60
|
+
"conditions": [
|
61
|
+
{
|
62
|
+
"lhs_variable_id": "9aedaffa-c2a4-4c37-9969-184e1ff43ded",
|
63
|
+
"operator": "=",
|
64
|
+
"rhs_variable_id": "c2151ef1-ad98-4940-b0e9-28dabe47a951",
|
65
|
+
"type": "LOGICAL_CONDITION",
|
66
|
+
}
|
67
|
+
],
|
68
|
+
"negated": False,
|
69
|
+
"type": "LOGICAL_CONDITION_GROUP",
|
70
|
+
},
|
71
|
+
},
|
72
|
+
"type": "CONSTANT_VALUE",
|
73
|
+
}
|
74
|
+
],
|
75
|
+
},
|
76
|
+
}
|
77
|
+
|
78
|
+
# AND the LHS filter references should be present as node inputs
|
79
|
+
serialized_lhs_input = next(
|
80
|
+
inp for inp in serialized_search_node["inputs"] if inp["id"] == "9aedaffa-c2a4-4c37-9969-184e1ff43ded"
|
81
|
+
)
|
82
|
+
assert serialized_lhs_input["value"] == {
|
83
|
+
"combinator": "OR",
|
84
|
+
"rules": [
|
85
|
+
{
|
86
|
+
"data": {"type": "STRING", "value": "ID"},
|
87
|
+
"type": "CONSTANT_VALUE",
|
88
|
+
}
|
89
|
+
],
|
90
|
+
}
|
91
|
+
|
92
|
+
# AND the RHS filter references should be present as node inputs
|
93
|
+
serialized_rhs_input = next(
|
94
|
+
inp for inp in serialized_search_node["inputs"] if inp["id"] == "c2151ef1-ad98-4940-b0e9-28dabe47a951"
|
95
|
+
)
|
96
|
+
assert serialized_rhs_input["value"] == {
|
97
|
+
"combinator": "OR",
|
98
|
+
"rules": [
|
99
|
+
{
|
100
|
+
"data": {"input_variable_id": "e2f4fff9-1277-47cb-8988-12f8ada450ba"},
|
101
|
+
"type": "INPUT_VARIABLE",
|
102
|
+
}
|
103
|
+
],
|
104
|
+
}
|
@@ -174,6 +174,34 @@ def test_serialize_workflow():
|
|
174
174
|
"name": "ml_model",
|
175
175
|
"value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "gpt-4o"}},
|
176
176
|
},
|
177
|
+
{
|
178
|
+
"id": "25f935f3-363f-4ead-a5a0-db234ca67e1e",
|
179
|
+
"name": "blocks",
|
180
|
+
"value": {
|
181
|
+
"type": "CONSTANT_VALUE",
|
182
|
+
"value": {
|
183
|
+
"type": "JSON",
|
184
|
+
"value": [
|
185
|
+
{
|
186
|
+
"block_type": "CHAT_MESSAGE",
|
187
|
+
"state": None,
|
188
|
+
"cache_config": None,
|
189
|
+
"chat_role": "SYSTEM",
|
190
|
+
"chat_source": None,
|
191
|
+
"chat_message_unterminated": None,
|
192
|
+
"blocks": [
|
193
|
+
{
|
194
|
+
"block_type": "JINJA",
|
195
|
+
"state": None,
|
196
|
+
"cache_config": None,
|
197
|
+
"template": "What's your favorite {{noun}}?",
|
198
|
+
}
|
199
|
+
],
|
200
|
+
}
|
201
|
+
],
|
202
|
+
},
|
203
|
+
},
|
204
|
+
},
|
177
205
|
{
|
178
206
|
"id": "ffabe7d2-8ab6-4201-9d41-c4d7be1386e1",
|
179
207
|
"name": "prompt_inputs",
|
@@ -355,3 +383,57 @@ def test_serialize_workflow_with_descriptor_functions():
|
|
355
383
|
"node_output_id": "470fadb9-b8b5-477e-a502-5209d398bcf9",
|
356
384
|
"type": "NODE_OUTPUT",
|
357
385
|
}
|
386
|
+
|
387
|
+
|
388
|
+
def test_serialize_workflow_with_descriptor_blocks():
|
389
|
+
"""Test that serialization handles BaseDescriptor instances in blocks list."""
|
390
|
+
|
391
|
+
class TestInputs(BaseInputs):
|
392
|
+
noun: str
|
393
|
+
|
394
|
+
class UpstreamNode(BaseNode):
|
395
|
+
class Outputs(BaseNode.Outputs):
|
396
|
+
results: list
|
397
|
+
|
398
|
+
def run(self) -> Outputs:
|
399
|
+
return self.Outputs(results=["test"])
|
400
|
+
|
401
|
+
class TestInlinePromptNodeWithDescriptorBlocks(InlinePromptNode):
|
402
|
+
ml_model = "gpt-4o"
|
403
|
+
blocks = [UpstreamNode.Outputs.results[0]] # type: ignore
|
404
|
+
prompt_inputs = {"noun": TestInputs.noun}
|
405
|
+
|
406
|
+
class TestWorkflow(BaseWorkflow[TestInputs, BaseState]):
|
407
|
+
graph = UpstreamNode >> TestInlinePromptNodeWithDescriptorBlocks
|
408
|
+
|
409
|
+
workflow_display = get_workflow_display(workflow_class=TestWorkflow)
|
410
|
+
serialized: dict = workflow_display.serialize()
|
411
|
+
|
412
|
+
prompt_nodes = [node for node in serialized["workflow_raw_data"]["nodes"] if node["type"] == "PROMPT"]
|
413
|
+
prompt_node = prompt_nodes[0]
|
414
|
+
|
415
|
+
blocks = prompt_node["data"]["exec_config"]["prompt_template_block_data"]["blocks"]
|
416
|
+
descriptor_blocks = [block for block in blocks if not isinstance(block, dict) or not block.get("block_type")]
|
417
|
+
assert len(descriptor_blocks) == 0, "BaseDescriptor blocks should not appear in serialized blocks"
|
418
|
+
|
419
|
+
blocks_attr = next((attr for attr in prompt_node["attributes"] if attr["name"] == "blocks"), None)
|
420
|
+
assert blocks_attr is not None, "blocks attribute should be present when blocks contain BaseDescriptor"
|
421
|
+
assert blocks_attr["value"]["type"] == "ARRAY_REFERENCE", "blocks attribute should be serialized as ARRAY_REFERENCE"
|
422
|
+
assert blocks_attr["value"]["items"] == [
|
423
|
+
{
|
424
|
+
"type": "BINARY_EXPRESSION",
|
425
|
+
"lhs": {
|
426
|
+
"type": "NODE_OUTPUT",
|
427
|
+
"node_id": str(UpstreamNode.__id__),
|
428
|
+
"node_output_id": str(UpstreamNode.__output_ids__["results"]),
|
429
|
+
},
|
430
|
+
"operator": "accessField",
|
431
|
+
"rhs": {
|
432
|
+
"type": "CONSTANT_VALUE",
|
433
|
+
"value": {
|
434
|
+
"type": "NUMBER",
|
435
|
+
"value": 0.0,
|
436
|
+
},
|
437
|
+
},
|
438
|
+
}
|
439
|
+
]
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py
CHANGED
@@ -167,7 +167,7 @@ def test_serialize_workflow():
|
|
167
167
|
"rules": [
|
168
168
|
{
|
169
169
|
"type": "INPUT_VARIABLE",
|
170
|
-
"data": {"input_variable_id": "
|
170
|
+
"data": {"input_variable_id": "b118247f-96dd-4b3e-8289-9f277483c520"},
|
171
171
|
}
|
172
172
|
],
|
173
173
|
"combinator": "OR",
|
@@ -180,7 +180,7 @@ def test_serialize_workflow():
|
|
180
180
|
"rules": [
|
181
181
|
{
|
182
182
|
"type": "INPUT_VARIABLE",
|
183
|
-
"data": {"input_variable_id": "
|
183
|
+
"data": {"input_variable_id": "aae2c10a-88b7-40bd-87a2-5e1e60c1e906"},
|
184
184
|
}
|
185
185
|
],
|
186
186
|
"combinator": "OR",
|
@@ -193,7 +193,7 @@ def test_serialize_workflow():
|
|
193
193
|
"rules": [
|
194
194
|
{
|
195
195
|
"type": "INPUT_VARIABLE",
|
196
|
-
"data": {"input_variable_id": "
|
196
|
+
"data": {"input_variable_id": "c9611a62-d1f5-4b41-bf9c-1aa3355760b4"},
|
197
197
|
}
|
198
198
|
],
|
199
199
|
"combinator": "OR",
|
@@ -206,7 +206,7 @@ def test_serialize_workflow():
|
|
206
206
|
"rules": [
|
207
207
|
{
|
208
208
|
"type": "INPUT_VARIABLE",
|
209
|
-
"data": {"input_variable_id": "
|
209
|
+
"data": {"input_variable_id": "f374640e-a5c0-470e-ac71-c36c2b198c00"},
|
210
210
|
}
|
211
211
|
],
|
212
212
|
"combinator": "OR",
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from vellum.workflows import BaseWorkflow
|
4
|
+
from vellum.workflows.inputs.base import BaseInputs
|
5
|
+
from vellum.workflows.nodes.bases.base import BaseNode
|
6
|
+
from vellum_ee.workflows.display.utils.exceptions import UnsupportedSerializationException
|
7
|
+
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
8
|
+
|
9
|
+
|
10
|
+
def test_workflow_serialization_error_when_node_references_unparameterized_inputs():
|
11
|
+
"""Test that a helpful error is raised when a node references inputs not parameterized by the workflow."""
|
12
|
+
|
13
|
+
class CustomInputs(BaseInputs):
|
14
|
+
custom_input: str
|
15
|
+
|
16
|
+
class TestNode(BaseNode):
|
17
|
+
class Outputs(BaseNode.Outputs):
|
18
|
+
output = CustomInputs.custom_input
|
19
|
+
|
20
|
+
class TestWorkflow(BaseWorkflow):
|
21
|
+
graph = TestNode
|
22
|
+
|
23
|
+
class Outputs(BaseWorkflow.Outputs):
|
24
|
+
result = TestNode.Outputs.output
|
25
|
+
|
26
|
+
workflow_display = get_workflow_display(workflow_class=TestWorkflow)
|
27
|
+
|
28
|
+
with pytest.raises(UnsupportedSerializationException) as exc_info:
|
29
|
+
workflow_display.serialize()
|
30
|
+
|
31
|
+
error_message = str(exc_info.value)
|
32
|
+
expected_message = (
|
33
|
+
"Inputs class 'CustomInputs' referenced during serialization of 'TestWorkflow' "
|
34
|
+
"without parameterizing this Workflow with this Inputs definition. "
|
35
|
+
"Update your Workflow definition to 'TestWorkflow(BaseWorkflow[CustomInputs, BaseState])'."
|
36
|
+
)
|
37
|
+
assert error_message == expected_message
|
@@ -211,7 +211,16 @@ def serialize_value(display_context: "WorkflowDisplayContext", value: Any) -> Js
|
|
211
211
|
return serialize_value(display_context, child_descriptor)
|
212
212
|
|
213
213
|
if isinstance(value, WorkflowInputReference):
|
214
|
-
|
214
|
+
try:
|
215
|
+
workflow_input_display = display_context.global_workflow_input_displays[value]
|
216
|
+
except KeyError:
|
217
|
+
inputs_class_name = value.inputs_class.__name__
|
218
|
+
workflow_class_name = display_context.workflow_display_class.infer_workflow_class().__name__
|
219
|
+
raise UnsupportedSerializationException(
|
220
|
+
f"Inputs class '{inputs_class_name}' referenced during serialization of '{workflow_class_name}' "
|
221
|
+
f"without parameterizing this Workflow with this Inputs definition. Update your Workflow "
|
222
|
+
f"definition to '{workflow_class_name}(BaseWorkflow[{inputs_class_name}, BaseState])'."
|
223
|
+
)
|
215
224
|
return {
|
216
225
|
"type": "WORKFLOW_INPUT",
|
217
226
|
"input_variable_id": str(workflow_input_display.id),
|
File without changes
|
File without changes
|
File without changes
|