vellum-ai 0.11.9__py3-none-any.whl → 0.11.10__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/nodes/displayable/code_execution_node/node.py +17 -1
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +141 -0
- {vellum_ai-0.11.9.dist-info → vellum_ai-0.11.10.dist-info}/METADATA +1 -1
- {vellum_ai-0.11.9.dist-info → vellum_ai-0.11.10.dist-info}/RECORD +11 -11
- {vellum_ai-0.11.9.dist-info → vellum_ai-0.11.10.dist-info}/WHEEL +1 -1
- vellum_ee/workflows/display/nodes/base_node_vellum_display.py +9 -0
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +4 -1
- vellum_ee/workflows/display/workflows/vellum_workflow_display.py +1 -5
- {vellum_ai-0.11.9.dist-info → vellum_ai-0.11.10.dist-info}/LICENSE +0 -0
- {vellum_ai-0.11.9.dist-info → vellum_ai-0.11.10.dist-info}/entry_points.txt +0 -0
@@ -17,7 +17,7 @@ class BaseClientWrapper:
|
|
17
17
|
headers: typing.Dict[str, str] = {
|
18
18
|
"X-Fern-Language": "Python",
|
19
19
|
"X-Fern-SDK-Name": "vellum-ai",
|
20
|
-
"X-Fern-SDK-Version": "0.11.
|
20
|
+
"X-Fern-SDK-Version": "0.11.10",
|
21
21
|
}
|
22
22
|
headers["X_API_KEY"] = self.api_key
|
23
23
|
return headers
|
@@ -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"
|
@@ -190,6 +191,21 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
|
|
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=VellumErrorCode.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=VellumErrorCode.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:
|
@@ -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
|
|
@@ -20,7 +20,7 @@ vellum_ee/workflows/display/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
|
|
20
20
|
vellum_ee/workflows/display/base.py,sha256=3ZFUYRNKL24fBqXhKpa_Dq2W1a-a86J20dmJYA3H2eY,1755
|
21
21
|
vellum_ee/workflows/display/nodes/__init__.py,sha256=5XOcZJXYUgaLS55QgRJzyQ_W1tpeprjnYAeYVezqoGw,160
|
22
22
|
vellum_ee/workflows/display/nodes/base_node_display.py,sha256=3W7X1V2Lv0k6djYp60LDu-0lYVMNsEjPXmNmIQ4UW6s,5961
|
23
|
-
vellum_ee/workflows/display/nodes/base_node_vellum_display.py,sha256=
|
23
|
+
vellum_ee/workflows/display/nodes/base_node_vellum_display.py,sha256=F30B7L3HJLdeYzQmn17KVduWWXPb3KFvFFEVltYWxvY,2124
|
24
24
|
vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=xg6DWEm8CDiOn_fX74fT2XtSEDCnq06dHKj7HX9JnJw,907
|
25
25
|
vellum_ee/workflows/display/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
26
26
|
vellum_ee/workflows/display/nodes/tests/test_base_node_display.py,sha256=0y20AAqDivg58hQjHbiCPjEdEghfWmWr-NdYw3u-AwM,1054
|
@@ -28,7 +28,7 @@ vellum_ee/workflows/display/nodes/types.py,sha256=St1BB6no528OyELGiyRabWao0GGw6m
|
|
28
28
|
vellum_ee/workflows/display/nodes/utils.py,sha256=sloya5TpXsnot1HURc9L51INwflRqUzHxRVnCS9Cd-4,973
|
29
29
|
vellum_ee/workflows/display/nodes/vellum/__init__.py,sha256=nmPLj8vkbVCS46XQqmHq8Xj8Mr36wCK_vWf26A9KIkw,1505
|
30
30
|
vellum_ee/workflows/display/nodes/vellum/api_node.py,sha256=4SSQGecKWHuoGy5YIGJeOZVHGKwTs_8Y-gf3GvsHb0M,8506
|
31
|
-
vellum_ee/workflows/display/nodes/vellum/code_execution_node.py,sha256=
|
31
|
+
vellum_ee/workflows/display/nodes/vellum/code_execution_node.py,sha256=qJXUTVGfL88Katxu6HQb4yCPUzBFTBFDXcf8pdId3U8,4076
|
32
32
|
vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=gUbSP8_oSAMNIb0CGiefd2FMYgoO6wMoG6iA1FakMjk,13293
|
33
33
|
vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=ygTjSjYDI4DtkxADWub5rhBnRWItMKWF6fezBrgpOKA,1979
|
34
34
|
vellum_ee/workflows/display/nodes/vellum/final_output_node.py,sha256=UezalObmZ3mcg7Nou2RgiI_0cmc7_tSdZLNB591iCcI,2772
|
@@ -73,13 +73,13 @@ vellum_ee/workflows/display/vellum.py,sha256=OSv0ZS50h1zJbunJ9TH7VEWFw-exXdK_Zsd
|
|
73
73
|
vellum_ee/workflows/display/workflows/__init__.py,sha256=kapXsC67VJcgSuiBMa86FdePG5A9kMB5Pi4Uy1O2ob4,207
|
74
74
|
vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=HkakkrNgVFoHlUP7yHlQjHOvii3CZ90iyU1062PfoW4,12819
|
75
75
|
vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py,sha256=AMxNnTm2z3LIR5rqxoCAfuy37F2FTuSRDVtKUoezO8M,1184
|
76
|
-
vellum_ee/workflows/display/workflows/vellum_workflow_display.py,sha256=
|
76
|
+
vellum_ee/workflows/display/workflows/vellum_workflow_display.py,sha256=DWaiYdP138kN3fbQvloh6VEBPlxzd6zSLydc6NpYu3s,17145
|
77
77
|
vellum/__init__.py,sha256=QmGeEPXeFxgkZa849KKK3wH3Y641wyt00Rytfay6KiM,35520
|
78
78
|
vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
|
79
79
|
vellum/client/__init__.py,sha256=o4m7iRZWEV8rP3GkdaztHAjNmjxjWERlarviFoHzuKI,110927
|
80
80
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
81
81
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
82
|
-
vellum/client/core/client_wrapper.py,sha256=
|
82
|
+
vellum/client/core/client_wrapper.py,sha256=6zb4goHdzGRX1BY9bkyHFFaNstiWKUbnXvOxT_2cidM,1891
|
83
83
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
84
84
|
vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
|
85
85
|
vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
|
@@ -1302,11 +1302,11 @@ vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=1_OXD
|
|
1302
1302
|
vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py,sha256=MdrAKN8QGPk_JnNjbEBaVVKwVLPE2judbBcWuYJgbkY,4964
|
1303
1303
|
vellum/workflows/nodes/displayable/bases/search_node.py,sha256=S7J8tTW681O4wcWYerGOfH6h-_BlE8-JMJHpW8eCVG0,3564
|
1304
1304
|
vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
|
1305
|
-
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=
|
1305
|
+
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=OHU9SnB0JDTTSFIp7io-9Jckelqtq84AP-QOcZBRNXY,8640
|
1306
1306
|
vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1307
1307
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1308
1308
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
|
1309
|
-
vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=
|
1309
|
+
vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=s93M_EnU-4n60iSKv3FCf0kppwzFH5FNi9o9E58fQ3I,7510
|
1310
1310
|
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=LfI3kj2zQz6UGMld_uA9z2LjZobqRcgxQO4jdUWkg7o,376
|
1311
1311
|
vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
|
1312
1312
|
vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=REFZdEVetXGyOK1RbIN1T6yRblrP0hfyZUls2KfjTKg,1016
|
@@ -1378,8 +1378,8 @@ vellum/workflows/vellum_client.py,sha256=ODrq_TSl-drX2aezXegf7pizpWDVJuTXH-j6528
|
|
1378
1378
|
vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
|
1379
1379
|
vellum/workflows/workflows/base.py,sha256=mnI-kZ78yt7u6NFSTUo-tYjDnarP-RJ7uZjwjCn6PCQ,16795
|
1380
1380
|
vellum/workflows/workflows/event_filters.py,sha256=-uQcMB7IpPd-idMku8f2QNVhPXPFWo6FZLlGjRf8rCo,1996
|
1381
|
-
vellum_ai-0.11.
|
1382
|
-
vellum_ai-0.11.
|
1383
|
-
vellum_ai-0.11.
|
1384
|
-
vellum_ai-0.11.
|
1385
|
-
vellum_ai-0.11.
|
1381
|
+
vellum_ai-0.11.10.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1382
|
+
vellum_ai-0.11.10.dist-info/METADATA,sha256=mPMns1QolQ74Dw64M1w0SbtZXWFMMpEfK7VBYRrAmj8,5129
|
1383
|
+
vellum_ai-0.11.10.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1384
|
+
vellum_ai-0.11.10.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1385
|
+
vellum_ai-0.11.10.dist-info/RECORD,,
|
@@ -30,6 +30,15 @@ class BaseNodeVellumDisplay(BaseNodeDisplay[NodeType]):
|
|
30
30
|
def get_target_handle_id(self) -> UUID:
|
31
31
|
return self._get_node_display_uuid("target_handle_id")
|
32
32
|
|
33
|
+
def get_target_handle_id_by_source_node_id(self, source_node_id: UUID) -> UUID:
|
34
|
+
"""
|
35
|
+
In the vast majority of cases, nodes will only have a single target handle and can be retrieved independently
|
36
|
+
of the source node. However, in rare cases (such as legacy Merge nodes), this method can be overridden to
|
37
|
+
account for the case of retrieving one amongst multiple target handles on a node.
|
38
|
+
"""
|
39
|
+
|
40
|
+
return self.get_target_handle_id()
|
41
|
+
|
33
42
|
def get_source_handle_id(self, port_displays: Dict[Port, PortDisplay]) -> UUID:
|
34
43
|
default_port = self._node.Ports.default
|
35
44
|
default_port_display = port_displays[default_port]
|
@@ -30,7 +30,10 @@ class BaseCodeExecutionNodeDisplay(BaseNodeVellumDisplay[_CodeExecutionNodeType]
|
|
30
30
|
node_id = self.node_id
|
31
31
|
|
32
32
|
node_file_path = inspect.getfile(node)
|
33
|
-
code = read_file_from_path(
|
33
|
+
code = read_file_from_path(
|
34
|
+
node_filepath=node_file_path,
|
35
|
+
script_filepath=(raise_if_descriptor(node.filepath)), # type: ignore
|
36
|
+
)
|
34
37
|
code_inputs = raise_if_descriptor(node.code_inputs)
|
35
38
|
|
36
39
|
inputs = [
|
@@ -12,7 +12,6 @@ from vellum.workflows.references import WorkflowInputReference
|
|
12
12
|
from vellum.workflows.references.output import OutputReference
|
13
13
|
from vellum.workflows.types.core import JsonArray, JsonObject
|
14
14
|
from vellum.workflows.types.generics import WorkflowType
|
15
|
-
from vellum_ee.workflows.display.nodes import BaseMergeNodeDisplay
|
16
15
|
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
17
16
|
from vellum_ee.workflows.display.nodes.types import PortDisplay
|
18
17
|
from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
|
@@ -369,10 +368,7 @@ class VellumWorkflowDisplay(
|
|
369
368
|
target_node_id = target_node_display.node_id
|
370
369
|
|
371
370
|
target_handle_id: UUID
|
372
|
-
|
373
|
-
target_handle_id = target_node_display.get_target_handle_id_by_source_node_id(source_node_id)
|
374
|
-
else:
|
375
|
-
target_handle_id = target_node_display.get_target_handle_id()
|
371
|
+
target_handle_id = target_node_display.get_target_handle_id_by_source_node_id(source_node_id)
|
376
372
|
|
377
373
|
return self._generate_edge_display_from_source(
|
378
374
|
source_node_id, source_handle_id, target_node_id, target_handle_id, overrides
|
File without changes
|
File without changes
|