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.
Files changed (21) hide show
  1. vellum/client/core/client_wrapper.py +1 -1
  2. vellum/workflows/errors/types.py +11 -1
  3. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +4 -0
  4. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +4 -0
  5. vellum/workflows/nodes/displayable/code_execution_node/node.py +5 -1
  6. vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py +68 -2
  7. vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py +25 -0
  8. vellum/workflows/nodes/experimental/tool_calling_node/node.py +18 -7
  9. vellum/workflows/nodes/experimental/tool_calling_node/utils.py +102 -28
  10. vellum/workflows/types/code_execution_node_wrappers.py +0 -4
  11. {vellum_ai-0.14.61.dist-info → vellum_ai-0.14.63.dist-info}/METADATA +1 -1
  12. {vellum_ai-0.14.61.dist-info → vellum_ai-0.14.63.dist-info}/RECORD +21 -21
  13. vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +9 -4
  14. vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py +93 -0
  15. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +337 -18
  16. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +8 -3
  17. vellum_ee/workflows/display/utils/expressions.py +13 -3
  18. /vellum/workflows/nodes/experimental/tool_calling_node/tests/{test_tool_calling_node.py → test_node.py} +0 -0
  19. {vellum_ai-0.14.61.dist-info → vellum_ai-0.14.63.dist-info}/LICENSE +0 -0
  20. {vellum_ai-0.14.61.dist-info → vellum_ai-0.14.63.dist-info}/WHEEL +0 -0
  21. {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.61",
21
+ "X-Fern-SDK-Version": "0.14.63",
22
22
  }
23
23
  headers["X-API-KEY"] = self.api_key
24
24
  return headers
@@ -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=_VELLUM_ERROR_CODE_TO_WORKFLOW_ERROR_CODE.get(error.code, WorkflowErrorCode.INTERNAL_ERROR),
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=cast(List[VellumValue], input_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
- # TODO: https://linear.app/vellum/issue/APO-342/support-tool-call-max-retries
38
- max_tool_calls: ClassVar[int] = 1
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
- snake_case(function.__name__): create_function_node(
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(function: Callable[..., Any], tool_router_node: Type[ToolRouterNode]) -> Type[FunctionNode]:
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
- This ensures the callable is properly registered and can be called with the expected arguments.
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
- # Create a class-level wrapper that calls the original function
132
- def execute_function(self) -> BaseNode.Outputs:
133
- outputs = self.state.meta.node_outputs.get(tool_router_node.Outputs.text)
134
- # first parse into json
135
- outputs = json.loads(outputs)
136
- arguments = outputs["arguments"]
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
- else:
164
- # If it's a regular callable, call it directly
165
- result = function(**arguments)
166
-
167
- self.state.chat_history.append(
168
- ChatMessage(
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
- return self.Outputs()
201
+ _code = f'''
202
+ {function_source}
175
203
 
176
- node = type(
177
- f"FunctionNode_{function.__name__}",
178
- (FunctionNode,),
179
- {
180
- "run": execute_function,
181
- "__module__": __name__,
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
@@ -82,10 +82,6 @@ class DictWrapper(dict):
82
82
  def __setattr__(self, name, value):
83
83
  self[name] = value
84
84
 
85
- def __iter__(self):
86
- for key in super().keys():
87
- yield self[key]
88
-
89
85
 
90
86
  def clean_for_dict_wrapper(obj):
91
87
  if isinstance(obj, dict):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 0.14.61
3
+ Version: 0.14.63
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0
@@ -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=dVb3ONkuovK8xE5MdDLVSBCoZoKPrCnhdcWLYcl14mw,3307
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=NewHcTseNE2ogPzEDJ6KEDD9EYLn9RBZIClMwijIs0I,4581
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=mLr_1Ow5NZYSLzzEZPup14LckuT8ivOvq9Lz85pGj0c,8602
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=RPv0bJGwgzBDK_f16VrplPjSZbTisANSH08BGzaHwmk,8341
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=u-sIH_hDxJdSjq_0BTP3QmbIDvA-OI1GxyPtmNvxxKc,12595
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=Y50hXu4pkEmrPDb1Vq6PeuiVG0NavAoEk1Dexp7lgSE,1869
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=_A0J3ACjg5dAR2TLI1KHSNPI-oDGkt_9nDk5a0NAjTY,3714
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=K2jwAjgG2Qaq7tfDlCckojhAjir962fcIT3eKgjTAEM,11555
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=T99UWACTD9ytVDVHa6W2go00V7HNwDxOyBFyMM2GnhQ,9567
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=U21jXW8XZoC51vP0pvbbUQzQidR6Ej2lMdGypIUyF3I,9708
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=mOVOD9UL2X0BpURn3vTI0ZPE7MGyVNo0XIwNKqxxbrM,34723
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=2KdPh1TeIeW_3xJq4QzAwfcuqL6PmMTLNPz4nSaDLmY,18030
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=4MUlTTAJdFDYA5ybRGaqAQX9XTaOsH48Sr8rJ49oatw,4892
1648
- vellum/workflows/nodes/experimental/tool_calling_node/tests/test_tool_calling_node.py,sha256=sxG26mOwt4N36RLoPJ-ngginPqC5qFzD_kGj9izdCFI,1833
1649
- vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=Z9zCnvZBE7tT4iwsiG5YgPLFhAKeDJjPs-8JYAi3n8o,7203
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=sPo7fLSyf92n6OFsrNLAsaNs0_I3AH-fXkEw3KrbWmc,3162
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.61.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1716
- vellum_ai-0.14.61.dist-info/METADATA,sha256=6rjJiOUgei1EVdl_iiBzai45u8cWbO3pjeKrt4RBB2E,5484
1717
- vellum_ai-0.14.61.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1718
- vellum_ai-0.14.61.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1719
- vellum_ai-0.14.61.dist-info/RECORD,,
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, cast
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
- _, output_display = display_context.global_node_output_displays[cast(OutputReference, node.Outputs.text)]
44
- _, array_display = display_context.global_node_output_displays[cast(OutputReference, node.Outputs.results)]
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
- "input_variable_id": "52995b50-84c9-465f-8a4b-a4ee2a92e388",
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
- "input_variable_id": "aa3ca842-250c-4a3f-853f-23928c28d0f8",
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": "5c041b7d-732c-4773-a93a-32211f2af0b3",
172
- "name": "max_tool_calls",
173
- "value": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 1.0}},
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()