vellum-ai 0.14.61__py3-none-any.whl → 0.14.63__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/errors/types.py +11 -1
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +4 -0
- vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +4 -0
- vellum/workflows/nodes/displayable/code_execution_node/node.py +5 -1
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py +68 -2
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py +25 -0
- vellum/workflows/nodes/experimental/tool_calling_node/node.py +18 -7
- vellum/workflows/nodes/experimental/tool_calling_node/utils.py +102 -28
- vellum/workflows/types/code_execution_node_wrappers.py +0 -4
- {vellum_ai-0.14.61.dist-info → vellum_ai-0.14.63.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.61.dist-info → vellum_ai-0.14.63.dist-info}/RECORD +21 -21
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +9 -4
- vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py +93 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +337 -18
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +8 -3
- vellum_ee/workflows/display/utils/expressions.py +13 -3
- /vellum/workflows/nodes/experimental/tool_calling_node/tests/{test_tool_calling_node.py → test_node.py} +0 -0
- {vellum_ai-0.14.61.dist-info → vellum_ai-0.14.63.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.61.dist-info → vellum_ai-0.14.63.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.61.dist-info → vellum_ai-0.14.63.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.63",
|
22
22
|
}
|
23
23
|
headers["X-API-KEY"] = self.api_key
|
24
24
|
return headers
|
vellum/workflows/errors/types.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
2
|
from enum import Enum
|
3
|
+
import logging
|
3
4
|
from typing import Any, Dict
|
4
5
|
|
5
6
|
from vellum.client.types.vellum_error import VellumError
|
@@ -7,6 +8,8 @@ from vellum.client.types.vellum_error_code_enum import VellumErrorCodeEnum
|
|
7
8
|
from vellum.client.types.workflow_event_error import WorkflowEventError
|
8
9
|
from vellum.client.types.workflow_execution_event_error_code import WorkflowExecutionEventErrorCode
|
9
10
|
|
11
|
+
logger = logging.getLogger(__name__)
|
12
|
+
|
10
13
|
|
11
14
|
class WorkflowErrorCode(Enum):
|
12
15
|
INVALID_WORKFLOW = "INVALID_WORKFLOW"
|
@@ -43,9 +46,15 @@ _VELLUM_ERROR_CODE_TO_WORKFLOW_ERROR_CODE: Dict[VellumErrorCodeEnum, WorkflowErr
|
|
43
46
|
|
44
47
|
|
45
48
|
def vellum_error_to_workflow_error(error: VellumError) -> WorkflowError:
|
49
|
+
workflow_error_code = _VELLUM_ERROR_CODE_TO_WORKFLOW_ERROR_CODE.get(error.code)
|
50
|
+
|
51
|
+
if workflow_error_code is None:
|
52
|
+
logger.warning(f"Unknown Vellum error code '{error.code}' encountered. Falling back to INTERNAL_ERROR.")
|
53
|
+
workflow_error_code = WorkflowErrorCode.INTERNAL_ERROR
|
54
|
+
|
46
55
|
return WorkflowError(
|
47
56
|
message=error.message,
|
48
|
-
code=
|
57
|
+
code=workflow_error_code,
|
49
58
|
)
|
50
59
|
|
51
60
|
|
@@ -57,6 +66,7 @@ _WORKFLOW_EVENT_ERROR_CODE_TO_WORKFLOW_ERROR_CODE: Dict[WorkflowExecutionEventEr
|
|
57
66
|
"NODE_EXECUTION": WorkflowErrorCode.NODE_EXECUTION,
|
58
67
|
"LLM_PROVIDER": WorkflowErrorCode.PROVIDER_ERROR,
|
59
68
|
"INVALID_CODE": WorkflowErrorCode.INVALID_CODE,
|
69
|
+
"INVALID_INPUTS": WorkflowErrorCode.INVALID_INPUTS,
|
60
70
|
"INVALID_TEMPLATE": WorkflowErrorCode.INVALID_TEMPLATE,
|
61
71
|
"USER_DEFINED_ERROR": WorkflowErrorCode.USER_DEFINED_ERROR,
|
62
72
|
}
|
@@ -193,6 +193,10 @@ class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
|
|
193
193
|
return input_variables, input_values
|
194
194
|
|
195
195
|
for input_name, input_value in self.prompt_inputs.items():
|
196
|
+
# Exclude inputs that resolved to be null. This ensure that we don't pass input values
|
197
|
+
# to optional prompt inputs whose values were unresolved.
|
198
|
+
if input_value is None:
|
199
|
+
continue
|
196
200
|
if isinstance(input_value, str):
|
197
201
|
input_variables.append(
|
198
202
|
VellumVariable(
|
@@ -171,6 +171,10 @@ class BasePromptDeploymentNode(BasePromptNode, Generic[StateType]):
|
|
171
171
|
return compiled_inputs
|
172
172
|
|
173
173
|
for input_name, input_value in self.prompt_inputs.items():
|
174
|
+
# Exclude inputs that resolved to be null. This ensure that we don't pass input values
|
175
|
+
# to optional prompt inputs whose values were unresolved.
|
176
|
+
if input_value is None:
|
177
|
+
continue
|
174
178
|
if isinstance(input_value, str):
|
175
179
|
compiled_inputs.append(
|
176
180
|
StringInputRequest(
|
@@ -27,6 +27,7 @@ from vellum.workflows.errors.types import WorkflowErrorCode
|
|
27
27
|
from vellum.workflows.exceptions import NodeException
|
28
28
|
from vellum.workflows.nodes.bases import BaseNode
|
29
29
|
from vellum.workflows.nodes.bases.base import BaseNodeMeta
|
30
|
+
from vellum.workflows.nodes.displayable.bases.utils import primitive_to_vellum_value
|
30
31
|
from vellum.workflows.nodes.displayable.code_execution_node.utils import read_file_from_path, run_code_inline
|
31
32
|
from vellum.workflows.outputs.base import BaseOutputs
|
32
33
|
from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior, VellumSecret
|
@@ -169,10 +170,13 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
|
|
169
170
|
)
|
170
171
|
)
|
171
172
|
else:
|
173
|
+
# Convert primitive values to VellumValue objects
|
174
|
+
vellum_values: List[VellumValue] = [primitive_to_vellum_value(item) for item in input_value]
|
175
|
+
|
172
176
|
compiled_inputs.append(
|
173
177
|
ArrayInput(
|
174
178
|
name=input_name,
|
175
|
-
value=
|
179
|
+
value=vellum_values,
|
176
180
|
)
|
177
181
|
)
|
178
182
|
elif isinstance(input_value, dict):
|
@@ -5,7 +5,7 @@ from typing import Any, List, Union
|
|
5
5
|
|
6
6
|
from pydantic import BaseModel
|
7
7
|
|
8
|
-
from vellum import CodeExecutorResponse, NumberVellumValue, StringInput, StringVellumValue
|
8
|
+
from vellum import ArrayInput, CodeExecutorResponse, NumberVellumValue, StringInput, StringVellumValue
|
9
9
|
from vellum.client.errors.bad_request_error import BadRequestError
|
10
10
|
from vellum.client.types.chat_message import ChatMessage
|
11
11
|
from vellum.client.types.code_execution_package import CodeExecutionPackage
|
@@ -1099,7 +1099,7 @@ def test_run_node__iter_dict():
|
|
1099
1099
|
class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, list[str]]):
|
1100
1100
|
code = """\
|
1101
1101
|
def main(input_dict: dict) -> list[str]:
|
1102
|
-
return [item.value for item in input_dict]
|
1102
|
+
return [item.value for item in input_dict.values()]
|
1103
1103
|
"""
|
1104
1104
|
runtime = "PYTHON_3_11_6"
|
1105
1105
|
code_inputs = {
|
@@ -1167,3 +1167,69 @@ def main(input: str) -> str:
|
|
1167
1167
|
|
1168
1168
|
# THEN the node should return default function call
|
1169
1169
|
assert outputs == {"result": FunctionCall(name="", arguments={}), "log": ""}
|
1170
|
+
|
1171
|
+
|
1172
|
+
def test_run_node__array_input_with_primitive_values(vellum_client):
|
1173
|
+
# GIVEN a node that subclasses CodeExecutionNode that processes an array of primitive values
|
1174
|
+
class State(BaseState):
|
1175
|
+
pass
|
1176
|
+
|
1177
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[State, str]):
|
1178
|
+
code = """\
|
1179
|
+
from typing import List
|
1180
|
+
def main(numbers: List[str]) -> str:
|
1181
|
+
return " ".join(numbers)
|
1182
|
+
"""
|
1183
|
+
runtime = "PYTHON_3_11_6"
|
1184
|
+
packages = [
|
1185
|
+
CodeExecutionPackage(
|
1186
|
+
name="openai",
|
1187
|
+
version="1.0.0",
|
1188
|
+
)
|
1189
|
+
]
|
1190
|
+
|
1191
|
+
code_inputs = {
|
1192
|
+
"numbers": ["6", "4", "2"],
|
1193
|
+
}
|
1194
|
+
|
1195
|
+
# AND we know what the Code Execution Node will respond with
|
1196
|
+
mock_code_execution = CodeExecutorResponse(
|
1197
|
+
log="",
|
1198
|
+
output=StringVellumValue(value="6 4 2"),
|
1199
|
+
)
|
1200
|
+
vellum_client.execute_code.return_value = mock_code_execution
|
1201
|
+
|
1202
|
+
# WHEN we run the node
|
1203
|
+
node = ExampleCodeExecutionNode(state=State())
|
1204
|
+
outputs = node.run()
|
1205
|
+
|
1206
|
+
# THEN the node should have produced the outputs we expect
|
1207
|
+
assert outputs == {"result": "6 4 2", "log": ""}
|
1208
|
+
|
1209
|
+
# AND we should have invoked the Code with the expected inputs
|
1210
|
+
vellum_client.execute_code.assert_called_once_with(
|
1211
|
+
input_values=[
|
1212
|
+
ArrayInput(
|
1213
|
+
name="numbers",
|
1214
|
+
value=[
|
1215
|
+
StringVellumValue(value="6"),
|
1216
|
+
StringVellumValue(value="4"),
|
1217
|
+
StringVellumValue(value="2"),
|
1218
|
+
],
|
1219
|
+
)
|
1220
|
+
],
|
1221
|
+
code="""\
|
1222
|
+
from typing import List
|
1223
|
+
def main(numbers: List[str]) -> str:
|
1224
|
+
return " ".join(numbers)
|
1225
|
+
""",
|
1226
|
+
runtime="PYTHON_3_11_6",
|
1227
|
+
output_type="STRING",
|
1228
|
+
packages=[
|
1229
|
+
CodeExecutionPackage(
|
1230
|
+
name="openai",
|
1231
|
+
version="1.0.0",
|
1232
|
+
)
|
1233
|
+
],
|
1234
|
+
request_options=None,
|
1235
|
+
)
|
@@ -468,3 +468,28 @@ def test_prompt_deployment_node__parent_context_serialization(mock_httpx_transpo
|
|
468
468
|
request_execution_context = json.loads(call_request_args.read().decode("utf-8"))["execution_context"]
|
469
469
|
assert request_execution_context["trace_id"] == str(trace_id)
|
470
470
|
assert request_execution_context["parent_context"]
|
471
|
+
|
472
|
+
|
473
|
+
def test_run_workflow__missing_required_input(vellum_client):
|
474
|
+
"""Confirm that we get an error when a required input is not provided to a Subworkflow Deployment Node"""
|
475
|
+
|
476
|
+
# GIVEN a Subworkflow Deployment Node missing a required input
|
477
|
+
class ExampleSubworkflowDeploymentNode(SubworkflowDeploymentNode):
|
478
|
+
deployment = "example_subworkflow_deployment"
|
479
|
+
subworkflow_inputs = {}
|
480
|
+
|
481
|
+
# AND the Subworkflow Deployment API call fails due to missing required input
|
482
|
+
vellum_client.execute_workflow_stream.side_effect = ApiError(
|
483
|
+
status_code=400, body={"detail": "Missing required input for 'my_var_1'"}
|
484
|
+
)
|
485
|
+
|
486
|
+
# WHEN we run the node
|
487
|
+
node = ExampleSubworkflowDeploymentNode()
|
488
|
+
|
489
|
+
# THEN we should get a NodeException for invalid inputs
|
490
|
+
with pytest.raises(NodeException) as exc_info:
|
491
|
+
list(node.run())
|
492
|
+
|
493
|
+
# AND the error should indicate the missing required input
|
494
|
+
assert exc_info.value.code == WorkflowErrorCode.INVALID_INPUTS
|
495
|
+
assert exc_info.value.message == "Missing required input for 'my_var_1'"
|
@@ -1,9 +1,10 @@
|
|
1
1
|
from collections.abc import Callable
|
2
|
-
from typing import Any, ClassVar, List, Optional
|
2
|
+
from typing import Any, ClassVar, Dict, List, Optional, cast
|
3
3
|
|
4
4
|
from pydash import snake_case
|
5
5
|
|
6
6
|
from vellum import ChatMessage, PromptBlock
|
7
|
+
from vellum.client.types.code_execution_package import CodeExecutionPackage
|
7
8
|
from vellum.workflows.context import execution_context, get_parent_context
|
8
9
|
from vellum.workflows.errors.types import WorkflowErrorCode
|
9
10
|
from vellum.workflows.exceptions import NodeException
|
@@ -28,14 +29,16 @@ class ToolCallingNode(BaseNode):
|
|
28
29
|
functions: List[FunctionDefinition] - The functions that can be called
|
29
30
|
function_callables: List[Callable] - The callables that can be called
|
30
31
|
prompt_inputs: Optional[EntityInputsInterface] - Mapping of input variable names to values
|
32
|
+
function_packages: Optional[Dict[Callable, List[CodeExecutionPackage]]] - Mapping of functions to their packages
|
33
|
+
runtime: str - The runtime to use for code execution (default: "PYTHON_3_11_6")
|
31
34
|
"""
|
32
35
|
|
33
36
|
ml_model: ClassVar[str] = "gpt-4o-mini"
|
34
37
|
blocks: ClassVar[List[PromptBlock]] = []
|
35
38
|
functions: ClassVar[List[Callable[..., Any]]] = []
|
36
39
|
prompt_inputs: ClassVar[Optional[EntityInputsInterface]] = None
|
37
|
-
|
38
|
-
|
40
|
+
function_packages: ClassVar[Optional[Dict[Callable[..., Any], List[CodeExecutionPackage]]]] = None
|
41
|
+
runtime: ClassVar[str] = "PYTHON_3_11_6"
|
39
42
|
|
40
43
|
class Outputs(BaseOutputs):
|
41
44
|
"""
|
@@ -102,13 +105,21 @@ class ToolCallingNode(BaseNode):
|
|
102
105
|
prompt_inputs=self.prompt_inputs,
|
103
106
|
)
|
104
107
|
|
105
|
-
self._function_nodes = {
|
106
|
-
|
108
|
+
self._function_nodes = {}
|
109
|
+
for function in self.functions:
|
110
|
+
function_name = snake_case(function.__name__)
|
111
|
+
# Get packages for this function if specified
|
112
|
+
packages = None
|
113
|
+
if self.function_packages and function in self.function_packages:
|
114
|
+
# Cast to tell mypy this is a plain list, not a descriptor
|
115
|
+
packages = cast(List[CodeExecutionPackage], self.function_packages[function])
|
116
|
+
|
117
|
+
self._function_nodes[function_name] = create_function_node(
|
107
118
|
function=function,
|
108
119
|
tool_router_node=self.tool_router_node,
|
120
|
+
packages=packages,
|
121
|
+
runtime=self.runtime,
|
109
122
|
)
|
110
|
-
for function in self.functions
|
111
|
-
}
|
112
123
|
|
113
124
|
graph_set = set()
|
114
125
|
|
@@ -1,10 +1,13 @@
|
|
1
1
|
from collections.abc import Callable
|
2
|
+
import inspect
|
2
3
|
import json
|
4
|
+
import types
|
3
5
|
from typing import Any, Iterator, List, Optional, Type, cast
|
4
6
|
|
5
7
|
from pydash import snake_case
|
6
8
|
|
7
9
|
from vellum import ChatMessage, PromptBlock
|
10
|
+
from vellum.client.types.code_execution_package import CodeExecutionPackage
|
8
11
|
from vellum.client.types.function_call_chat_message_content import FunctionCallChatMessageContent
|
9
12
|
from vellum.client.types.function_call_chat_message_content_value import FunctionCallChatMessageContentValue
|
10
13
|
from vellum.client.types.string_chat_message_content import StringChatMessageContent
|
@@ -13,10 +16,12 @@ from vellum.workflows.errors.types import WorkflowErrorCode
|
|
13
16
|
from vellum.workflows.exceptions import NodeException
|
14
17
|
from vellum.workflows.inputs.base import BaseInputs
|
15
18
|
from vellum.workflows.nodes.bases import BaseNode
|
19
|
+
from vellum.workflows.nodes.displayable.code_execution_node.node import CodeExecutionNode
|
16
20
|
from vellum.workflows.nodes.displayable.inline_prompt_node.node import InlinePromptNode
|
17
21
|
from vellum.workflows.outputs.base import BaseOutput
|
18
22
|
from vellum.workflows.ports.port import Port
|
19
23
|
from vellum.workflows.references.lazy import LazyReference
|
24
|
+
from vellum.workflows.state.base import BaseState
|
20
25
|
from vellum.workflows.state.encoder import DefaultStateEncoder
|
21
26
|
from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior
|
22
27
|
from vellum.workflows.types.generics import is_workflow_class
|
@@ -117,26 +122,35 @@ def create_tool_router_node(
|
|
117
122
|
},
|
118
123
|
),
|
119
124
|
)
|
120
|
-
|
121
125
|
return node
|
122
126
|
|
123
127
|
|
124
|
-
def create_function_node(
|
128
|
+
def create_function_node(
|
129
|
+
function: Callable[..., Any],
|
130
|
+
tool_router_node: Type[ToolRouterNode],
|
131
|
+
packages: Optional[List[CodeExecutionPackage]] = None,
|
132
|
+
runtime: str = "PYTHON_3_11_6",
|
133
|
+
) -> Type[FunctionNode]:
|
125
134
|
"""
|
126
135
|
Create a FunctionNode class for a given function.
|
127
136
|
|
128
|
-
|
137
|
+
For workflow functions: BaseNode
|
138
|
+
For regular functions: CodeExecutionNode with embedded function
|
139
|
+
Args:
|
140
|
+
function: The function to create a node for
|
141
|
+
tool_router_node: The tool router node class
|
142
|
+
packages: Optional list of packages to install for code execution (only used for regular functions)
|
143
|
+
runtime: The runtime to use for code execution (default: "PYTHON_3_11_6")
|
129
144
|
"""
|
130
145
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
146
|
+
if is_workflow_class(function):
|
147
|
+
|
148
|
+
def execute_function(self) -> BaseNode.Outputs:
|
149
|
+
outputs = self.state.meta.node_outputs.get(tool_router_node.Outputs.text)
|
150
|
+
# first parse into json
|
151
|
+
outputs = json.loads(outputs)
|
152
|
+
arguments = outputs["arguments"]
|
137
153
|
|
138
|
-
# Call the function based on its type
|
139
|
-
if is_workflow_class(function):
|
140
154
|
# Dynamically define an Inputs subclass of BaseInputs
|
141
155
|
Inputs = type(
|
142
156
|
"Inputs",
|
@@ -160,26 +174,86 @@ def create_function_node(function: Callable[..., Any], tool_router_node: Type[To
|
|
160
174
|
result = terminal_event.outputs
|
161
175
|
elif terminal_event.name == "workflow.execution.rejected":
|
162
176
|
raise Exception(f"Workflow execution rejected: {terminal_event.error}")
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
role="FUNCTION",
|
170
|
-
content=StringChatMessageContent(value=json.dumps(result, cls=DefaultStateEncoder)),
|
177
|
+
|
178
|
+
self.state.chat_history.append(
|
179
|
+
ChatMessage(
|
180
|
+
role="FUNCTION",
|
181
|
+
content=StringChatMessageContent(value=json.dumps(result, cls=DefaultStateEncoder)),
|
182
|
+
)
|
171
183
|
)
|
184
|
+
|
185
|
+
return self.Outputs()
|
186
|
+
|
187
|
+
# Create BaseNode for workflow functions
|
188
|
+
node = type(
|
189
|
+
f"InlineWorkflowNode_{function.__name__}",
|
190
|
+
(FunctionNode,),
|
191
|
+
{
|
192
|
+
"run": execute_function,
|
193
|
+
"__module__": __name__,
|
194
|
+
},
|
172
195
|
)
|
196
|
+
else:
|
197
|
+
# For regular functions, use CodeExecutionNode approach
|
198
|
+
function_source = inspect.getsource(function)
|
199
|
+
function_name = function.__name__
|
173
200
|
|
174
|
-
|
201
|
+
_code = f'''
|
202
|
+
{function_source}
|
175
203
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
204
|
+
def main(arguments):
|
205
|
+
"""Main function that calls the original function with the provided arguments."""
|
206
|
+
return {function_name}(**arguments)
|
207
|
+
'''
|
208
|
+
_packages = packages
|
209
|
+
_tool_router_node = tool_router_node
|
210
|
+
_runtime = runtime
|
211
|
+
|
212
|
+
def execute_code_execution_function(self) -> BaseNode.Outputs:
|
213
|
+
# Get the function call from the tool router output
|
214
|
+
function_call_output = self.state.meta.node_outputs.get(_tool_router_node.Outputs.results)
|
215
|
+
if function_call_output and len(function_call_output) > 0:
|
216
|
+
function_call = function_call_output[0]
|
217
|
+
arguments = function_call.value.arguments
|
218
|
+
else:
|
219
|
+
arguments = {}
|
220
|
+
|
221
|
+
self.code_inputs = {"arguments": arguments}
|
222
|
+
|
223
|
+
outputs = base_class.run(self)
|
224
|
+
|
225
|
+
self.state.chat_history.append(
|
226
|
+
ChatMessage(
|
227
|
+
role="FUNCTION",
|
228
|
+
content=StringChatMessageContent(value=json.dumps(outputs.result, cls=DefaultStateEncoder)),
|
229
|
+
)
|
230
|
+
)
|
231
|
+
|
232
|
+
return self.Outputs()
|
233
|
+
|
234
|
+
# Create the properly typed base class with explicit type annotation
|
235
|
+
def get_function_output_type() -> Type:
|
236
|
+
return function.__annotations__.get("return", Any)
|
237
|
+
|
238
|
+
output_type = get_function_output_type()
|
239
|
+
|
240
|
+
base_class: Type[CodeExecutionNode] = CodeExecutionNode[BaseState, output_type] # type: ignore[valid-type]
|
241
|
+
|
242
|
+
# Create the class with basic attributes
|
243
|
+
node = types.new_class(
|
244
|
+
f"CodeExecutionNode_{function.__name__}",
|
245
|
+
(base_class,),
|
246
|
+
{},
|
247
|
+
lambda ns: ns.update(
|
248
|
+
{
|
249
|
+
"code": _code,
|
250
|
+
"code_inputs": {}, # No inputs needed since we handle function call extraction in run()
|
251
|
+
"run": execute_code_execution_function,
|
252
|
+
"runtime": _runtime,
|
253
|
+
"packages": _packages,
|
254
|
+
"__module__": __name__,
|
255
|
+
}
|
256
|
+
),
|
257
|
+
)
|
184
258
|
|
185
259
|
return node
|
@@ -45,7 +45,7 @@ vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py,sha256=fQV5o
|
|
45
45
|
vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=CiklGf5_tDbqE1XQm2mnbtoL01_2JYjcnB4FDTpMImQ,3824
|
46
46
|
vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=yBWeN4T_lOsDVnNOKWRiT7JYKu0IR5Fx2z99iq6QKSA,3273
|
47
47
|
vellum_ee/workflows/display/nodes/vellum/note_node.py,sha256=3E0UqmgVYdtbj4nyq8gKju8EpMsRHMCQ0KLrJhug3XU,1084
|
48
|
-
vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py,sha256=
|
48
|
+
vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py,sha256=1NxFddxWCFtMe_je1cutP7qnoASoG94LJqKhRkoQwvw,3535
|
49
49
|
vellum_ee/workflows/display/nodes/vellum/retry_node.py,sha256=X3xnlAU5JisL0jRvaG_V9RvTF7ZlGufTO8tXLLVhGIg,3280
|
50
50
|
vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=3n1qa-zWIk0p_H94u0hjfDtGkanldC6EXVhg0xgLmE4,9544
|
51
51
|
vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py,sha256=MWLZBXHsmj5vKgqOgI2HHcHAJzLS0sqybn6idhwug8Y,2669
|
@@ -59,7 +59,7 @@ vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py,sha256=TtzUj3
|
|
59
59
|
vellum_ee/workflows/display/nodes/vellum/tests/test_retry_node.py,sha256=h93ysolmbo2viisyhRnXKHPxiDK0I_dSAbYoHFYIoO4,1953
|
60
60
|
vellum_ee/workflows/display/nodes/vellum/tests/test_subworkflow_deployment_node.py,sha256=BUzHJgjdWnPeZxjFjHfDBKnbFjYjnbXPjc-1hne1B2Y,3965
|
61
61
|
vellum_ee/workflows/display/nodes/vellum/tests/test_templating_node.py,sha256=LSk2gx9TpGXbAqKe8dggQW8yJZqj-Cf0EGJFeGGlEcw,3321
|
62
|
-
vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py,sha256=
|
62
|
+
vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py,sha256=fvatG73wpHU4CN29YFchvir8K4uLEPMsVhvssehNJ7I,7651
|
63
63
|
vellum_ee/workflows/display/nodes/vellum/tests/test_try_node.py,sha256=Khjsb53PKpZuyhKoRMgKAL45eGp5hZqXvHmVeQWRw4w,2289
|
64
64
|
vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py,sha256=3LS1O4DGPWit05oj_ubeW8AlHGnoBxdUMferGQuAiZs,4851
|
65
65
|
vellum_ee/workflows/display/nodes/vellum/try_node.py,sha256=z9Omo676RRc7mQjLoL7hjiHhUj0OWVLhrrb97YTN4QA,4086
|
@@ -85,18 +85,18 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_promp
|
|
85
85
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py,sha256=u2nquKoO3o2xIkU_uFPOb_s5YoLmULiq09vb6Ee0Cqw,21415
|
86
86
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py,sha256=3gZuNM8sT6ovVaeoAvd2JoyKwuxokvowlhH8kwDUoZ8,16559
|
87
87
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py,sha256=IIJt7YZBzkhNtbmaMwCX4ENs58QtSIIoBHlMR6OwGU8,8342
|
88
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py,sha256=
|
88
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py,sha256=QXiRjwtiTPeMUl40Pvh_geeU99C3mv1aVS85oeIUwY4,21052
|
89
89
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py,sha256=K0mECBUyTNX4I468goeaRf93N7Qfizoc1ctCH5_nNys,12936
|
90
90
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py,sha256=KkYZc_bZuq1lmDcvUz3QxIqJLpQPCZioD1FHUNsMJY8,11211
|
91
91
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py,sha256=aZaqRDrkO3ytcmdM2eKJqHSt60MF070NMj6M2vgzOKc,7711
|
92
92
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py,sha256=r748dpS13HtwY7t_KQFExFssxRy0xI2d-wxmhiUHRe0,3850
|
93
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=
|
93
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=4h_rc28L_tzaTrFKXhuPptGDGNEIeD_OjhIJb3rHTIc,8577
|
94
94
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py,sha256=EL5kfakuoEcwD85dGjhMta-J-PpCHRSDoc80SdbBrQk,2769
|
95
95
|
vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py,sha256=RmFUDx8dYdfsOE2CGLvdXqNNRtLLpVzXDN8dqZyMcZ8,5822
|
96
96
|
vellum_ee/workflows/display/types.py,sha256=i4T7ElU5b5h-nA1i3scmEhO1BqmNDc4eJDHavATD88w,2821
|
97
97
|
vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
98
98
|
vellum_ee/workflows/display/utils/exceptions.py,sha256=LSwwxCYNxFkf5XMUcFkaZKpQ13OSrI7y_bpEUwbKVk0,169
|
99
|
-
vellum_ee/workflows/display/utils/expressions.py,sha256=
|
99
|
+
vellum_ee/workflows/display/utils/expressions.py,sha256=7gWOsow_fkayY7GnByv1cN_XhbI24dJT-VQ5-WP46FU,12894
|
100
100
|
vellum_ee/workflows/display/utils/registry.py,sha256=fWIm5Jj-10gNFjgn34iBu4RWv3Vd15ijtSN0V97bpW8,1513
|
101
101
|
vellum_ee/workflows/display/utils/vellum.py,sha256=mtoXmSYwR7rvrq-d6CzCW_auaJXTct0Mi1F0xpRCiNQ,5627
|
102
102
|
vellum_ee/workflows/display/vellum.py,sha256=o7mq_vk2Yapu9DDKRz5l76h8EmCAypWGQYe6pryrbB8,3576
|
@@ -134,7 +134,7 @@ vellum/client/README.md,sha256=qmaVIP42MnxAu8jV7u-CsgVFfs3-pHQODrXdZdFxtaw,4749
|
|
134
134
|
vellum/client/__init__.py,sha256=AYopGv2ZRVn3zsU8_km6KOvEHDbXiTPCVuYVI7bWvdA,120166
|
135
135
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
136
136
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
137
|
-
vellum/client/core/client_wrapper.py,sha256=
|
137
|
+
vellum/client/core/client_wrapper.py,sha256=ikQHyukVNBgDFhkMt29SwknlEfXdS0GnAPctHIOoSpc,1869
|
138
138
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
139
139
|
vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
140
140
|
vellum/client/core/http_client.py,sha256=Z77OIxIbL4OAB2IDqjRq_sYa5yNYAWfmdhdCSSvh6Y4,19552
|
@@ -1496,7 +1496,7 @@ vellum/workflows/emitters/base.py,sha256=D5SADKIvnbgKwIBgYm77jaqvpo1o0rz4MmuX_mu
|
|
1496
1496
|
vellum/workflows/environment/__init__.py,sha256=wGHslgSEZ7Octe4C-hNtl84EFelNimgmWQoi7px4-uw,71
|
1497
1497
|
vellum/workflows/environment/environment.py,sha256=0XhJPBs8YASWmvPx8bkSdCvcbDmzpe9stfs2kgtNDRU,296
|
1498
1498
|
vellum/workflows/errors/__init__.py,sha256=tWGPu5xyAU8gRb8_bl0fL7OfU3wxQ9UH6qVwy4X4P_Q,113
|
1499
|
-
vellum/workflows/errors/types.py,sha256=
|
1499
|
+
vellum/workflows/errors/types.py,sha256=nUWuniEfrhdtb-_2GzoDGlYnSJ_yuNUGjVkaKLNr-rM,4049
|
1500
1500
|
vellum/workflows/events/__init__.py,sha256=6pxxceJo2dcaRkWtkDAYlUQZ-PHBQSZytIoyuUK48Qw,759
|
1501
1501
|
vellum/workflows/events/node.py,sha256=TaawUxKaZG8cv_GkiKnJmjOmC4Ic0wMlsxUduF2Rbpw,5446
|
1502
1502
|
vellum/workflows/events/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -1587,21 +1587,21 @@ vellum/workflows/nodes/displayable/bases/base_prompt_node/__init__.py,sha256=Org
|
|
1587
1587
|
vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py,sha256=amBXi7Tv50AbGLhfWbwX83PlOdV1XyYRyQmpa6_afE4,3511
|
1588
1588
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/__init__.py,sha256=Hl35IAoepRpE-j4cALaXVJIYTYOF3qszyVbxTj4kS1s,82
|
1589
1589
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/constants.py,sha256=fnjiRWLoRlC4Puo5oQcpZD5Hd-EesxsAo9l5tGAkpZQ,270
|
1590
|
-
vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=
|
1590
|
+
vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=cD2RzOX9WE6xTKgm09dsEw4xHATZbOjeGyYCSdl8fjU,11785
|
1591
1591
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1592
1592
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py,sha256=5CNag1_aEFZbCL0nrOC5e1L-t90-4rp2xDwh0h52hVI,21407
|
1593
|
-
vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py,sha256=
|
1593
|
+
vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py,sha256=0a40fkkZkFMmZN0CsWf6EP_y1H6x36EGa3WcfVNyOsM,9797
|
1594
1594
|
vellum/workflows/nodes/displayable/bases/search_node.py,sha256=3UtbqY3QO4kzfJHbmUNZGnEEfJmaoiF892u8H6TGjp8,5381
|
1595
1595
|
vellum/workflows/nodes/displayable/bases/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1596
1596
|
vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMDPevgwLg1i6YK0g4L4bCy-7xCBN5yYZI,3156
|
1597
1597
|
vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
|
1598
1598
|
vellum/workflows/nodes/displayable/bases/utils.py,sha256=ckMUenSsNkiYmSw6FmjSMHYaCk8Y8_sUjL6lkFFEqts,5412
|
1599
1599
|
vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
|
1600
|
-
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=
|
1600
|
+
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=o2hP4tWad3-qXY_QtodtGiOGrO8HjeQnqYrxxpxeJVo,9954
|
1601
1601
|
vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1602
1602
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1603
1603
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
|
1604
|
-
vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py,sha256=
|
1604
|
+
vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py,sha256=DRd-nOC04RGjXz-ctxADVq7b-hgdiFN3ZfhK6Ld7J8I,36634
|
1605
1605
|
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=VRTKms59vrSR9mDk99cojParZVAP4lzjEeDwDNXU1tk,3837
|
1606
1606
|
vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
|
1607
1607
|
vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=Qjfl33gZ3JEgxBA1EgzSUebboGvsARthIxxcQyvx5Gg,1152
|
@@ -1634,7 +1634,7 @@ vellum/workflows/nodes/displayable/search_node/tests/test_node.py,sha256=OserVd6
|
|
1634
1634
|
vellum/workflows/nodes/displayable/subworkflow_deployment_node/__init__.py,sha256=9yYM6001YZeqI1VOk1QuEM_yrffk_EdsO7qaPzINKds,92
|
1635
1635
|
vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py,sha256=biv1H4gIX4B4VMFJ3Rp82NjE65GhmzLq7pREL0ozB2E,9484
|
1636
1636
|
vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1637
|
-
vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py,sha256=
|
1637
|
+
vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py,sha256=c98nMPogZ6iN_pTvVUMTB3J72Hj--H-XVgvvRXhdSQE,19085
|
1638
1638
|
vellum/workflows/nodes/displayable/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1639
1639
|
vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py,sha256=MHuIolSsrY9ziwoXWsye3XOODncL9DLZOkNYzQMLhRw,4696
|
1640
1640
|
vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py,sha256=VepO5z1277c1y5N6LLIC31nnWD1aak2m5oPFplfJHHs,6935
|
@@ -1644,9 +1644,9 @@ vellum/workflows/nodes/experimental/__init__.py,sha256=_tpZGWAZLydcKxfrj1-plrZeT
|
|
1644
1644
|
vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py,sha256=lsyD9laR9p7kx5-BXGH2gUTM242UhKy8SMV0SR6S2iE,90
|
1645
1645
|
vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py,sha256=cKI2Ls25L-JVt4z4a2ozQa-YBeVy21Z7BQ32Sj7iBPE,10460
|
1646
1646
|
vellum/workflows/nodes/experimental/tool_calling_node/__init__.py,sha256=S7OzT3I4cyOU5Beoz87nPwCejCMP2FsHBFL8OcVmxJ4,118
|
1647
|
-
vellum/workflows/nodes/experimental/tool_calling_node/node.py,sha256=
|
1648
|
-
vellum/workflows/nodes/experimental/tool_calling_node/tests/
|
1649
|
-
vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=
|
1647
|
+
vellum/workflows/nodes/experimental/tool_calling_node/node.py,sha256=XPMVnjlsO_ueCygEsbw9UbP4H2ZX_SvJuZHqEb88jj4,5677
|
1648
|
+
vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py,sha256=sxG26mOwt4N36RLoPJ-ngginPqC5qFzD_kGj9izdCFI,1833
|
1649
|
+
vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=lcjJU-tMCNo-qUjWI_twPqaf3tGjIVrf6NJQQffCF5E,10054
|
1650
1650
|
vellum/workflows/nodes/mocks.py,sha256=a1FjWEIocseMfjzM-i8DNozpUsaW0IONRpZmXBoWlyc,10455
|
1651
1651
|
vellum/workflows/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1652
1652
|
vellum/workflows/nodes/tests/test_mocks.py,sha256=mfPvrs75PKcsNsbJLQAN6PDFoVqs9TmQxpdyFKDdO60,7837
|
@@ -1687,7 +1687,7 @@ vellum/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
1687
1687
|
vellum/workflows/tests/test_sandbox.py,sha256=JKwaluI-lODQo7Ek9sjDstjL_WTdSqUlVik6ZVTfVOA,1826
|
1688
1688
|
vellum/workflows/tests/test_undefined.py,sha256=zMCVliCXVNLrlC6hEGyOWDnQADJ2g83yc5FIM33zuo8,353
|
1689
1689
|
vellum/workflows/types/__init__.py,sha256=KxUTMBGzuRCfiMqzzsykOeVvrrkaZmTTo1a7SLu8gRM,68
|
1690
|
-
vellum/workflows/types/code_execution_node_wrappers.py,sha256=
|
1690
|
+
vellum/workflows/types/code_execution_node_wrappers.py,sha256=3MNIoFZKzVzNS5qFLVuDwMV17QJw72zo7NRf52yMq5A,3074
|
1691
1691
|
vellum/workflows/types/core.py,sha256=kMQremh_I8egXpiKmtMQbB6e3OczAWiRnnTq5V6xlD0,928
|
1692
1692
|
vellum/workflows/types/definition.py,sha256=z81CL_u0FJol-9yUIqoXNTYAARtU8x__c6s-f4rb5c8,2335
|
1693
1693
|
vellum/workflows/types/generics.py,sha256=tKXz0LwWJGKw1YGudyl9_yFDrRgU6yYV1yJV1Zv-LTw,1430
|
@@ -1712,8 +1712,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
|
|
1712
1712
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1713
1713
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=fROqff6AZpCIzaSwOKSdtYy4XR0UZQ6ejxL3RJOSJVs,20447
|
1714
1714
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1715
|
-
vellum_ai-0.14.
|
1716
|
-
vellum_ai-0.14.
|
1717
|
-
vellum_ai-0.14.
|
1718
|
-
vellum_ai-0.14.
|
1719
|
-
vellum_ai-0.14.
|
1715
|
+
vellum_ai-0.14.63.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1716
|
+
vellum_ai-0.14.63.dist-info/METADATA,sha256=QEDirKfQq3koN0R5mtzFvHqWaO09TC6VFQRFgwjDqdY,5484
|
1717
|
+
vellum_ai-0.14.63.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1718
|
+
vellum_ai-0.14.63.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1719
|
+
vellum_ai-0.14.63.dist-info/RECORD,,
|
@@ -1,8 +1,7 @@
|
|
1
1
|
from uuid import UUID
|
2
|
-
from typing import Generic, Optional, TypeVar
|
2
|
+
from typing import Generic, Optional, TypeVar
|
3
3
|
|
4
4
|
from vellum.workflows.nodes.displayable.prompt_deployment_node import PromptDeploymentNode
|
5
|
-
from vellum.workflows.references import OutputReference
|
6
5
|
from vellum.workflows.types.core import JsonObject
|
7
6
|
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
8
7
|
from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
|
@@ -40,8 +39,9 @@ class BasePromptDeploymentNodeDisplay(BaseNodeDisplay[_PromptDeploymentNodeType]
|
|
40
39
|
else []
|
41
40
|
)
|
42
41
|
|
43
|
-
|
44
|
-
|
42
|
+
output_display = self.output_display[node.Outputs.text]
|
43
|
+
array_display = self.output_display[node.Outputs.results]
|
44
|
+
json_display = self.output_display[node.Outputs.json]
|
45
45
|
|
46
46
|
deployment = display_context.client.deployments.retrieve(
|
47
47
|
id=str(raise_if_descriptor(node.deployment)),
|
@@ -68,4 +68,9 @@ class BasePromptDeploymentNodeDisplay(BaseNodeDisplay[_PromptDeploymentNodeType]
|
|
68
68
|
"base": self.get_base().dict(),
|
69
69
|
"definition": self.get_definition().dict(),
|
70
70
|
"ports": self.serialize_ports(display_context),
|
71
|
+
"outputs": [
|
72
|
+
{"id": str(json_display.id), "name": "json", "type": "JSON", "value": None},
|
73
|
+
{"id": str(output_display.id), "name": "text", "type": "STRING", "value": None},
|
74
|
+
{"id": str(array_display.id), "name": "results", "type": "ARRAY", "value": None},
|
75
|
+
],
|
71
76
|
}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
from vellum.client.types.code_execution_package import CodeExecutionPackage
|
1
2
|
from vellum.workflows import BaseWorkflow
|
2
3
|
from vellum.workflows.inputs import BaseInputs
|
3
4
|
from vellum.workflows.nodes.displayable.inline_prompt_node.node import InlinePromptNode
|
@@ -122,3 +123,95 @@ def test_serialize_node__prompt_inputs__mixed_values():
|
|
122
123
|
],
|
123
124
|
},
|
124
125
|
}
|
126
|
+
|
127
|
+
|
128
|
+
def test_serialize_node__function_packages():
|
129
|
+
# GIVEN a tool calling node with function packages
|
130
|
+
def foo():
|
131
|
+
pass
|
132
|
+
|
133
|
+
def bar():
|
134
|
+
pass
|
135
|
+
|
136
|
+
class MyToolCallingNode(ToolCallingNode):
|
137
|
+
functions = [foo, bar]
|
138
|
+
function_packages = {
|
139
|
+
foo: [
|
140
|
+
CodeExecutionPackage(name="first_package", version="1.0.0"),
|
141
|
+
CodeExecutionPackage(name="second_package", version="2.0.0"),
|
142
|
+
],
|
143
|
+
bar: [
|
144
|
+
CodeExecutionPackage(name="third_package", version="3.0.0"),
|
145
|
+
],
|
146
|
+
}
|
147
|
+
|
148
|
+
# AND a workflow with the tool calling node
|
149
|
+
class Workflow(BaseWorkflow):
|
150
|
+
graph = MyToolCallingNode
|
151
|
+
|
152
|
+
# WHEN the workflow is serialized
|
153
|
+
workflow_display = get_workflow_display(workflow_class=Workflow)
|
154
|
+
serialized_workflow: dict = workflow_display.serialize()
|
155
|
+
|
156
|
+
# THEN the node should properly serialize the function packages
|
157
|
+
my_tool_calling_node = next(
|
158
|
+
node
|
159
|
+
for node in serialized_workflow["workflow_raw_data"]["nodes"]
|
160
|
+
if node["id"] == str(MyToolCallingNode.__id__)
|
161
|
+
)
|
162
|
+
|
163
|
+
function_packages_attribute = next(
|
164
|
+
attribute for attribute in my_tool_calling_node["attributes"] if attribute["name"] == "function_packages"
|
165
|
+
)
|
166
|
+
|
167
|
+
assert function_packages_attribute == {
|
168
|
+
"id": "c315228f-870a-4288-abf7-a217b5b8c253",
|
169
|
+
"name": "function_packages",
|
170
|
+
"value": {
|
171
|
+
"type": "CONSTANT_VALUE",
|
172
|
+
"value": {
|
173
|
+
"type": "JSON",
|
174
|
+
"value": {
|
175
|
+
"foo": [
|
176
|
+
{"version": "1.0.0", "name": "first_package"},
|
177
|
+
{"version": "2.0.0", "name": "second_package"},
|
178
|
+
],
|
179
|
+
"bar": [{"version": "3.0.0", "name": "third_package"}],
|
180
|
+
},
|
181
|
+
},
|
182
|
+
},
|
183
|
+
}
|
184
|
+
|
185
|
+
|
186
|
+
def test_serialize_node__none_function_packages():
|
187
|
+
# GIVEN a tool calling node with no function packages
|
188
|
+
def foo():
|
189
|
+
pass
|
190
|
+
|
191
|
+
class MyToolCallingNode(ToolCallingNode):
|
192
|
+
functions = [foo]
|
193
|
+
|
194
|
+
# AND a workflow with the tool calling node
|
195
|
+
class Workflow(BaseWorkflow):
|
196
|
+
graph = MyToolCallingNode
|
197
|
+
|
198
|
+
# WHEN the workflow is serialized
|
199
|
+
workflow_display = get_workflow_display(workflow_class=Workflow)
|
200
|
+
serialized_workflow: dict = workflow_display.serialize()
|
201
|
+
|
202
|
+
# THEN the node should properly serialize the functions
|
203
|
+
my_tool_calling_node = next(
|
204
|
+
node
|
205
|
+
for node in serialized_workflow["workflow_raw_data"]["nodes"]
|
206
|
+
if node["id"] == str(MyToolCallingNode.__id__)
|
207
|
+
)
|
208
|
+
|
209
|
+
function_packages_attribute = next(
|
210
|
+
attribute for attribute in my_tool_calling_node["attributes"] if attribute["name"] == "function_packages"
|
211
|
+
)
|
212
|
+
|
213
|
+
assert function_packages_attribute == {
|
214
|
+
"id": "05c86dea-ea4b-46c4-883b-7912a6680491",
|
215
|
+
"name": "function_packages",
|
216
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
217
|
+
}
|
@@ -7,6 +7,9 @@ from vellum import DeploymentRead
|
|
7
7
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
8
8
|
|
9
9
|
from tests.workflows.basic_text_prompt_deployment.workflow import BasicTextPromptDeployment
|
10
|
+
from tests.workflows.basic_text_prompt_deployment.workflow_with_prompt_deployment_json_reference import (
|
11
|
+
WorkflowWithPromptDeploymentJsonReferenceWorkflow,
|
12
|
+
)
|
10
13
|
|
11
14
|
|
12
15
|
def test_serialize_workflow(vellum_client):
|
@@ -103,30 +106,26 @@ def test_serialize_workflow(vellum_client):
|
|
103
106
|
"id": "947d7ead-0fad-4e5f-aa3a-d06029ac94bc",
|
104
107
|
"key": "city",
|
105
108
|
"value": {
|
106
|
-
"combinator": "OR",
|
107
109
|
"rules": [
|
108
110
|
{
|
109
111
|
"type": "INPUT_VARIABLE",
|
110
|
-
"data": {
|
111
|
-
|
112
|
-
},
|
113
|
-
},
|
112
|
+
"data": {"input_variable_id": "52995b50-84c9-465f-8a4b-a4ee2a92e388"},
|
113
|
+
}
|
114
114
|
],
|
115
|
+
"combinator": "OR",
|
115
116
|
},
|
116
117
|
},
|
117
118
|
{
|
118
119
|
"id": "3deebdd7-2900-4d8c-93f2-e5b90649ac42",
|
119
120
|
"key": "date",
|
120
121
|
"value": {
|
121
|
-
"combinator": "OR",
|
122
122
|
"rules": [
|
123
123
|
{
|
124
124
|
"type": "INPUT_VARIABLE",
|
125
|
-
"data": {
|
126
|
-
|
127
|
-
},
|
128
|
-
},
|
125
|
+
"data": {"input_variable_id": "aa3ca842-250c-4a3f-853f-23928c28d0f8"},
|
126
|
+
}
|
129
127
|
],
|
128
|
+
"combinator": "OR",
|
130
129
|
},
|
131
130
|
},
|
132
131
|
],
|
@@ -142,21 +141,21 @@ def test_serialize_workflow(vellum_client):
|
|
142
141
|
"release_tag": "LATEST",
|
143
142
|
"ml_model_fallbacks": ["gpt-4o", "gemini-1.5-pro"],
|
144
143
|
},
|
145
|
-
"display_data": {
|
146
|
-
"position": {
|
147
|
-
"x": 0.0,
|
148
|
-
"y": 0.0,
|
149
|
-
},
|
150
|
-
},
|
144
|
+
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
151
145
|
"base": {
|
152
|
-
"module": ["vellum", "workflows", "nodes", "displayable", "prompt_deployment_node", "node"],
|
153
146
|
"name": "PromptDeploymentNode",
|
147
|
+
"module": ["vellum", "workflows", "nodes", "displayable", "prompt_deployment_node", "node"],
|
154
148
|
},
|
155
149
|
"definition": {
|
156
|
-
"module": ["tests", "workflows", "basic_text_prompt_deployment", "workflow"],
|
157
150
|
"name": "ExamplePromptDeploymentNode",
|
151
|
+
"module": ["tests", "workflows", "basic_text_prompt_deployment", "workflow"],
|
158
152
|
},
|
159
153
|
"ports": [{"id": "2f26c7e0-283d-4f04-b639-adebb56bc679", "name": "default", "type": "DEFAULT"}],
|
154
|
+
"outputs": [
|
155
|
+
{"id": "180355a8-e67c-4ce6-9ac3-e5dbb75a6629", "name": "json", "type": "JSON", "value": None},
|
156
|
+
{"id": "4d38b850-79e3-4b85-9158-a41d0c535410", "name": "text", "type": "STRING", "value": None},
|
157
|
+
{"id": "0cf47d33-6d5f-466f-b826-e814f1d0348b", "name": "results", "type": "ARRAY", "value": None},
|
158
|
+
],
|
160
159
|
}
|
161
160
|
|
162
161
|
final_output_node = workflow_raw_data["nodes"][2]
|
@@ -251,3 +250,323 @@ def test_serialize_workflow(vellum_client):
|
|
251
250
|
"workflow",
|
252
251
|
],
|
253
252
|
}
|
253
|
+
|
254
|
+
|
255
|
+
def test_serialize_workflow_with_prompt_and_templating(vellum_client):
|
256
|
+
# GIVEN a Workflow with stubbed out API calls
|
257
|
+
deployment = DeploymentRead(
|
258
|
+
id=str(uuid4()),
|
259
|
+
created=datetime.now(),
|
260
|
+
label="JSON Prompt Deployment",
|
261
|
+
name="json_prompt_deployment",
|
262
|
+
last_deployed_on=datetime.now(),
|
263
|
+
input_variables=[],
|
264
|
+
active_model_version_ids=[],
|
265
|
+
last_deployed_history_item_id=str(uuid4()),
|
266
|
+
)
|
267
|
+
vellum_client.deployments.retrieve.return_value = deployment
|
268
|
+
|
269
|
+
# WHEN we serialize it
|
270
|
+
workflow_display = get_workflow_display(workflow_class=WorkflowWithPromptDeploymentJsonReferenceWorkflow)
|
271
|
+
serialized_workflow: dict = workflow_display.serialize()
|
272
|
+
|
273
|
+
# THEN we should get a serialized representation of the Workflow
|
274
|
+
assert serialized_workflow.keys() == {
|
275
|
+
"workflow_raw_data",
|
276
|
+
"input_variables",
|
277
|
+
"state_variables",
|
278
|
+
"output_variables",
|
279
|
+
}
|
280
|
+
|
281
|
+
# AND its input variables should be what we expect
|
282
|
+
input_variables = serialized_workflow["input_variables"]
|
283
|
+
assert len(input_variables) == 2
|
284
|
+
assert not DeepDiff(
|
285
|
+
[
|
286
|
+
{
|
287
|
+
"id": "ad577aca-0797-4deb-a484-574ef1a1f0c7",
|
288
|
+
"key": "city",
|
289
|
+
"type": "STRING",
|
290
|
+
"default": None,
|
291
|
+
"required": True,
|
292
|
+
"extensions": {"color": None},
|
293
|
+
},
|
294
|
+
{
|
295
|
+
"id": "066124c4-42bd-4764-aa75-6f230dbbed4a",
|
296
|
+
"key": "date",
|
297
|
+
"type": "STRING",
|
298
|
+
"default": None,
|
299
|
+
"required": True,
|
300
|
+
"extensions": {"color": None},
|
301
|
+
},
|
302
|
+
],
|
303
|
+
input_variables,
|
304
|
+
ignore_order=True,
|
305
|
+
)
|
306
|
+
|
307
|
+
# AND its output variables should be what we expect
|
308
|
+
output_variables = serialized_workflow["output_variables"]
|
309
|
+
assert len(output_variables) == 1
|
310
|
+
assert output_variables == [{"id": "a7e4b449-5879-4d0c-8f00-d5d4985eb65c", "key": "text", "type": "STRING"}]
|
311
|
+
|
312
|
+
# AND its raw data should be what we expect
|
313
|
+
workflow_raw_data = serialized_workflow["workflow_raw_data"]
|
314
|
+
assert len(workflow_raw_data["edges"]) == 3
|
315
|
+
assert len(workflow_raw_data["nodes"]) == 4
|
316
|
+
|
317
|
+
# AND each node should be serialized correctly
|
318
|
+
entrypoint_node = workflow_raw_data["nodes"][0]
|
319
|
+
assert entrypoint_node == {
|
320
|
+
"id": "32c7f398-277c-456b-9279-aa1f867fb637",
|
321
|
+
"type": "ENTRYPOINT",
|
322
|
+
"inputs": [],
|
323
|
+
"data": {"label": "Entrypoint Node", "source_handle_id": "cc0f4028-1039-4063-971d-7dacbb01b379"},
|
324
|
+
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
325
|
+
"base": None,
|
326
|
+
"definition": None,
|
327
|
+
}
|
328
|
+
|
329
|
+
prompt_node = workflow_raw_data["nodes"][1]
|
330
|
+
assert prompt_node == {
|
331
|
+
"id": "56c74024-19a3-4c0d-a5f5-23e1e9f11b21",
|
332
|
+
"type": "PROMPT",
|
333
|
+
"inputs": [
|
334
|
+
{
|
335
|
+
"id": "947d7ead-0fad-4e5f-aa3a-d06029ac94bc",
|
336
|
+
"key": "city",
|
337
|
+
"value": {
|
338
|
+
"rules": [
|
339
|
+
{
|
340
|
+
"type": "INPUT_VARIABLE",
|
341
|
+
"data": {"input_variable_id": "ad577aca-0797-4deb-a484-574ef1a1f0c7"},
|
342
|
+
}
|
343
|
+
],
|
344
|
+
"combinator": "OR",
|
345
|
+
},
|
346
|
+
},
|
347
|
+
{
|
348
|
+
"id": "3deebdd7-2900-4d8c-93f2-e5b90649ac42",
|
349
|
+
"key": "date",
|
350
|
+
"value": {
|
351
|
+
"rules": [
|
352
|
+
{
|
353
|
+
"type": "INPUT_VARIABLE",
|
354
|
+
"data": {"input_variable_id": "066124c4-42bd-4764-aa75-6f230dbbed4a"},
|
355
|
+
}
|
356
|
+
],
|
357
|
+
"combinator": "OR",
|
358
|
+
},
|
359
|
+
},
|
360
|
+
],
|
361
|
+
"data": {
|
362
|
+
"label": "Example Prompt Deployment Node",
|
363
|
+
"output_id": "4d38b850-79e3-4b85-9158-a41d0c535410",
|
364
|
+
"error_output_id": None,
|
365
|
+
"array_output_id": "0cf47d33-6d5f-466f-b826-e814f1d0348b",
|
366
|
+
"source_handle_id": "2f26c7e0-283d-4f04-b639-adebb56bc679",
|
367
|
+
"target_handle_id": "b7605c48-0937-4ecc-914e-0d1058130e65",
|
368
|
+
"variant": "DEPLOYMENT",
|
369
|
+
"prompt_deployment_id": deployment.id,
|
370
|
+
"release_tag": "LATEST",
|
371
|
+
"ml_model_fallbacks": None,
|
372
|
+
},
|
373
|
+
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
374
|
+
"base": {
|
375
|
+
"name": "PromptDeploymentNode",
|
376
|
+
"module": ["vellum", "workflows", "nodes", "displayable", "prompt_deployment_node", "node"],
|
377
|
+
},
|
378
|
+
"definition": {
|
379
|
+
"name": "ExamplePromptDeploymentNode",
|
380
|
+
"module": [
|
381
|
+
"tests",
|
382
|
+
"workflows",
|
383
|
+
"basic_text_prompt_deployment",
|
384
|
+
"workflow_with_prompt_deployment_json_reference",
|
385
|
+
],
|
386
|
+
},
|
387
|
+
"ports": [{"id": "2f26c7e0-283d-4f04-b639-adebb56bc679", "name": "default", "type": "DEFAULT"}],
|
388
|
+
"outputs": [
|
389
|
+
{"id": "180355a8-e67c-4ce6-9ac3-e5dbb75a6629", "name": "json", "type": "JSON", "value": None},
|
390
|
+
{"id": "4d38b850-79e3-4b85-9158-a41d0c535410", "name": "text", "type": "STRING", "value": None},
|
391
|
+
{"id": "0cf47d33-6d5f-466f-b826-e814f1d0348b", "name": "results", "type": "ARRAY", "value": None},
|
392
|
+
],
|
393
|
+
}
|
394
|
+
|
395
|
+
templating_node = workflow_raw_data["nodes"][2]
|
396
|
+
assert templating_node == {
|
397
|
+
"id": "51cbe21d-0232-4362-bc54-5bc283297aa6",
|
398
|
+
"type": "TEMPLATING",
|
399
|
+
"inputs": [
|
400
|
+
{
|
401
|
+
"id": "7c775379-d589-4d79-b876-dcd224d72966",
|
402
|
+
"key": "template",
|
403
|
+
"value": {
|
404
|
+
"rules": [
|
405
|
+
{
|
406
|
+
"type": "CONSTANT_VALUE",
|
407
|
+
"data": {
|
408
|
+
"type": "STRING",
|
409
|
+
"value": "The weather in {{ city }} on {{ date }} is {{ weather }}.",
|
410
|
+
},
|
411
|
+
}
|
412
|
+
],
|
413
|
+
"combinator": "OR",
|
414
|
+
},
|
415
|
+
},
|
416
|
+
{
|
417
|
+
"id": "dec1317a-6900-4858-a5fb-c849254b2c91",
|
418
|
+
"key": "city",
|
419
|
+
"value": {
|
420
|
+
"rules": [
|
421
|
+
{
|
422
|
+
"type": "INPUT_VARIABLE",
|
423
|
+
"data": {"input_variable_id": "ad577aca-0797-4deb-a484-574ef1a1f0c7"},
|
424
|
+
}
|
425
|
+
],
|
426
|
+
"combinator": "OR",
|
427
|
+
},
|
428
|
+
},
|
429
|
+
{
|
430
|
+
"id": "4cc5b9f1-075d-45fd-a978-f530c29c5682",
|
431
|
+
"key": "date",
|
432
|
+
"value": {
|
433
|
+
"rules": [
|
434
|
+
{
|
435
|
+
"type": "INPUT_VARIABLE",
|
436
|
+
"data": {"input_variable_id": "066124c4-42bd-4764-aa75-6f230dbbed4a"},
|
437
|
+
}
|
438
|
+
],
|
439
|
+
"combinator": "OR",
|
440
|
+
},
|
441
|
+
},
|
442
|
+
{
|
443
|
+
"id": "77b352e0-1b77-4d48-9f6f-04ce17fe7286",
|
444
|
+
"key": "weather",
|
445
|
+
"value": {
|
446
|
+
"rules": [
|
447
|
+
{
|
448
|
+
"type": "NODE_OUTPUT",
|
449
|
+
"data": {
|
450
|
+
"node_id": "56c74024-19a3-4c0d-a5f5-23e1e9f11b21",
|
451
|
+
"output_id": "180355a8-e67c-4ce6-9ac3-e5dbb75a6629",
|
452
|
+
},
|
453
|
+
}
|
454
|
+
],
|
455
|
+
"combinator": "OR",
|
456
|
+
},
|
457
|
+
},
|
458
|
+
],
|
459
|
+
"data": {
|
460
|
+
"label": "Example Templating Node",
|
461
|
+
"output_id": "6834cae4-8173-4fa6-88f7-bc09d335bdd1",
|
462
|
+
"error_output_id": None,
|
463
|
+
"source_handle_id": "39317827-df43-4f5a-bfbc-20bffc839748",
|
464
|
+
"target_handle_id": "58427684-3848-498a-8299-c6b0fc70265d",
|
465
|
+
"template_node_input_id": "7c775379-d589-4d79-b876-dcd224d72966",
|
466
|
+
"output_type": "STRING",
|
467
|
+
},
|
468
|
+
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
469
|
+
"base": {
|
470
|
+
"name": "TemplatingNode",
|
471
|
+
"module": ["vellum", "workflows", "nodes", "core", "templating_node", "node"],
|
472
|
+
},
|
473
|
+
"definition": {
|
474
|
+
"name": "ExampleTemplatingNode",
|
475
|
+
"module": [
|
476
|
+
"tests",
|
477
|
+
"workflows",
|
478
|
+
"basic_text_prompt_deployment",
|
479
|
+
"workflow_with_prompt_deployment_json_reference",
|
480
|
+
],
|
481
|
+
},
|
482
|
+
"ports": [{"id": "39317827-df43-4f5a-bfbc-20bffc839748", "name": "default", "type": "DEFAULT"}],
|
483
|
+
}
|
484
|
+
|
485
|
+
final_output_node = workflow_raw_data["nodes"][3]
|
486
|
+
assert final_output_node == {
|
487
|
+
"id": "53de824d-a41d-4294-b511-c969932b05af",
|
488
|
+
"type": "TERMINAL",
|
489
|
+
"data": {
|
490
|
+
"label": "Final Output",
|
491
|
+
"name": "text",
|
492
|
+
"target_handle_id": "fee3d395-38c3-485f-ab61-1a0fdf71c4ce",
|
493
|
+
"output_id": "a7e4b449-5879-4d0c-8f00-d5d4985eb65c",
|
494
|
+
"output_type": "STRING",
|
495
|
+
"node_input_id": "cf380f81-c5ee-4bc9-8e26-ecf1307733a9",
|
496
|
+
},
|
497
|
+
"inputs": [
|
498
|
+
{
|
499
|
+
"id": "cf380f81-c5ee-4bc9-8e26-ecf1307733a9",
|
500
|
+
"key": "node_input",
|
501
|
+
"value": {
|
502
|
+
"rules": [
|
503
|
+
{
|
504
|
+
"type": "NODE_OUTPUT",
|
505
|
+
"data": {
|
506
|
+
"node_id": "51cbe21d-0232-4362-bc54-5bc283297aa6",
|
507
|
+
"output_id": "6834cae4-8173-4fa6-88f7-bc09d335bdd1",
|
508
|
+
},
|
509
|
+
}
|
510
|
+
],
|
511
|
+
"combinator": "OR",
|
512
|
+
},
|
513
|
+
}
|
514
|
+
],
|
515
|
+
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
516
|
+
"base": {
|
517
|
+
"name": "FinalOutputNode",
|
518
|
+
"module": ["vellum", "workflows", "nodes", "displayable", "final_output_node", "node"],
|
519
|
+
},
|
520
|
+
"definition": None,
|
521
|
+
}
|
522
|
+
|
523
|
+
# AND each edge should be serialized correctly
|
524
|
+
serialized_edges = workflow_raw_data["edges"]
|
525
|
+
assert serialized_edges == [
|
526
|
+
{
|
527
|
+
"id": "2c49ffa6-7b9a-49a0-a932-009534556480",
|
528
|
+
"source_node_id": "32c7f398-277c-456b-9279-aa1f867fb637",
|
529
|
+
"source_handle_id": "cc0f4028-1039-4063-971d-7dacbb01b379",
|
530
|
+
"target_node_id": "56c74024-19a3-4c0d-a5f5-23e1e9f11b21",
|
531
|
+
"target_handle_id": "b7605c48-0937-4ecc-914e-0d1058130e65",
|
532
|
+
"type": "DEFAULT",
|
533
|
+
},
|
534
|
+
{
|
535
|
+
"id": "a46909ec-9572-43c6-a134-0bd7e2c09f99",
|
536
|
+
"source_node_id": "56c74024-19a3-4c0d-a5f5-23e1e9f11b21",
|
537
|
+
"source_handle_id": "2f26c7e0-283d-4f04-b639-adebb56bc679",
|
538
|
+
"target_node_id": "51cbe21d-0232-4362-bc54-5bc283297aa6",
|
539
|
+
"target_handle_id": "58427684-3848-498a-8299-c6b0fc70265d",
|
540
|
+
"type": "DEFAULT",
|
541
|
+
},
|
542
|
+
{
|
543
|
+
"id": "1f720900-e5e1-49b7-9910-6ede79f6afd2",
|
544
|
+
"source_node_id": "51cbe21d-0232-4362-bc54-5bc283297aa6",
|
545
|
+
"source_handle_id": "39317827-df43-4f5a-bfbc-20bffc839748",
|
546
|
+
"target_node_id": "53de824d-a41d-4294-b511-c969932b05af",
|
547
|
+
"target_handle_id": "fee3d395-38c3-485f-ab61-1a0fdf71c4ce",
|
548
|
+
"type": "DEFAULT",
|
549
|
+
},
|
550
|
+
]
|
551
|
+
|
552
|
+
# AND the display data should be what we expect
|
553
|
+
display_data = workflow_raw_data["display_data"]
|
554
|
+
assert display_data == {
|
555
|
+
"viewport": {
|
556
|
+
"x": 0.0,
|
557
|
+
"y": 0.0,
|
558
|
+
"zoom": 1.0,
|
559
|
+
}
|
560
|
+
}
|
561
|
+
|
562
|
+
# AND the definition should be what we expect
|
563
|
+
definition = workflow_raw_data["definition"]
|
564
|
+
assert definition == {
|
565
|
+
"name": "WorkflowWithPromptDeploymentJsonReferenceWorkflow",
|
566
|
+
"module": [
|
567
|
+
"tests",
|
568
|
+
"workflows",
|
569
|
+
"basic_text_prompt_deployment",
|
570
|
+
"workflow_with_prompt_deployment_json_reference",
|
571
|
+
],
|
572
|
+
}
|
@@ -168,9 +168,14 @@ def test_serialize_workflow():
|
|
168
168
|
},
|
169
169
|
},
|
170
170
|
{
|
171
|
-
"id": "
|
172
|
-
"name": "
|
173
|
-
"value": {"type": "CONSTANT_VALUE", "value": {"type": "
|
171
|
+
"id": "b31575f0-633b-4bd0-ba6a-960532f3887a",
|
172
|
+
"name": "function_packages",
|
173
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
|
174
|
+
},
|
175
|
+
{
|
176
|
+
"id": "d316c45c-97ea-4f39-9a2d-5c43e2d355de",
|
177
|
+
"name": "runtime",
|
178
|
+
"value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "PYTHON_3_11_6"}},
|
174
179
|
},
|
175
180
|
],
|
176
181
|
"outputs": [
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import TYPE_CHECKING, Any, Dict, cast
|
1
|
+
from typing import TYPE_CHECKING, Any, Dict, List, cast
|
2
2
|
|
3
3
|
from vellum.client.types.logical_operator import LogicalOperator
|
4
4
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
@@ -190,6 +190,16 @@ def _serialize_condition(display_context: "WorkflowDisplayContext", condition: B
|
|
190
190
|
raise UnsupportedSerializationException(f"Unsupported condition type: {condition.__class__.__name__}")
|
191
191
|
|
192
192
|
|
193
|
+
def serialize_key(key: Any) -> str:
|
194
|
+
"""Serialize dictionary keys to strings, handling function objects properly."""
|
195
|
+
if callable(key):
|
196
|
+
return key.__name__
|
197
|
+
elif isinstance(key, str):
|
198
|
+
return key
|
199
|
+
else:
|
200
|
+
return str(key)
|
201
|
+
|
202
|
+
|
193
203
|
def serialize_value(display_context: "WorkflowDisplayContext", value: Any) -> JsonObject:
|
194
204
|
if isinstance(value, ConstantValueReference):
|
195
205
|
return serialize_value(display_context, value._value)
|
@@ -264,10 +274,10 @@ def serialize_value(display_context: "WorkflowDisplayContext", value: Any) -> Js
|
|
264
274
|
}
|
265
275
|
|
266
276
|
if isinstance(value, dict):
|
267
|
-
serialized_entries = [
|
277
|
+
serialized_entries: List[Dict[str, Any]] = [
|
268
278
|
{
|
269
279
|
"id": str(uuid4_from_hash(f"{key}|{val}")),
|
270
|
-
"key": key,
|
280
|
+
"key": serialize_key(key),
|
271
281
|
"value": serialize_value(display_context, val),
|
272
282
|
}
|
273
283
|
for key, val in value.items()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|