vellum-ai 1.4.1__py3-none-any.whl → 1.4.2__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 (33) hide show
  1. vellum/client/core/client_wrapper.py +2 -2
  2. vellum/workflows/constants.py +4 -0
  3. vellum/workflows/emitters/base.py +8 -0
  4. vellum/workflows/emitters/vellum_emitter.py +10 -0
  5. vellum/workflows/inputs/dataset_row.py +2 -2
  6. vellum/workflows/nodes/bases/base.py +12 -1
  7. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +6 -0
  8. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +16 -2
  9. vellum/workflows/nodes/displayable/final_output_node/node.py +59 -0
  10. vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py +40 -1
  11. vellum/workflows/nodes/displayable/tool_calling_node/node.py +3 -0
  12. vellum/workflows/nodes/displayable/tool_calling_node/tests/test_utils.py +64 -0
  13. vellum/workflows/nodes/displayable/tool_calling_node/utils.py +30 -41
  14. vellum/workflows/tests/test_dataset_row.py +29 -0
  15. vellum/workflows/types/core.py +13 -2
  16. vellum/workflows/types/definition.py +13 -1
  17. vellum/workflows/utils/functions.py +63 -26
  18. vellum/workflows/utils/tests/test_functions.py +10 -6
  19. vellum/workflows/vellum_client.py +7 -1
  20. vellum/workflows/workflows/base.py +8 -0
  21. {vellum_ai-1.4.1.dist-info → vellum_ai-1.4.2.dist-info}/METADATA +1 -1
  22. {vellum_ai-1.4.1.dist-info → vellum_ai-1.4.2.dist-info}/RECORD +33 -32
  23. vellum_cli/tests/test_pull.py +1 -0
  24. vellum_cli/tests/test_push.py +2 -0
  25. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +1 -3
  26. vellum_ee/workflows/display/nodes/vellum/tests/test_final_output_node.py +78 -0
  27. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +5 -0
  28. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +5 -0
  29. vellum_ee/workflows/display/types.py +3 -0
  30. vellum_ee/workflows/display/workflows/base_workflow_display.py +6 -0
  31. {vellum_ai-1.4.1.dist-info → vellum_ai-1.4.2.dist-info}/LICENSE +0 -0
  32. {vellum_ai-1.4.1.dist-info → vellum_ai-1.4.2.dist-info}/WHEEL +0 -0
  33. {vellum_ai-1.4.1.dist-info → vellum_ai-1.4.2.dist-info}/entry_points.txt +0 -0
@@ -27,10 +27,10 @@ class BaseClientWrapper:
27
27
 
28
28
  def get_headers(self) -> typing.Dict[str, str]:
29
29
  headers: typing.Dict[str, str] = {
30
- "User-Agent": "vellum-ai/1.4.1",
30
+ "User-Agent": "vellum-ai/1.4.2",
31
31
  "X-Fern-Language": "Python",
32
32
  "X-Fern-SDK-Name": "vellum-ai",
33
- "X-Fern-SDK-Version": "1.4.1",
33
+ "X-Fern-SDK-Version": "1.4.2",
34
34
  **(self.get_custom_headers() or {}),
35
35
  }
36
36
  if self._api_version is not None:
@@ -58,3 +58,7 @@ class APIRequestMethod(Enum):
58
58
  class AuthorizationType(Enum):
59
59
  BEARER_TOKEN = "BEARER_TOKEN"
60
60
  API_KEY = "API_KEY"
61
+
62
+
63
+ class VellumIntegrationProviderType(Enum):
64
+ COMPOSIO = "COMPOSIO"
@@ -29,3 +29,11 @@ class BaseWorkflowEmitter(ABC):
29
29
  @abstractmethod
30
30
  def snapshot_state(self, state: BaseState) -> None:
31
31
  pass
32
+
33
+ @abstractmethod
34
+ def join(self) -> None:
35
+ """
36
+ Wait for any background threads or timers used by this emitter to complete.
37
+ This ensures all pending work is finished before the workflow terminates.
38
+ """
39
+ pass
@@ -135,3 +135,13 @@ class VellumEmitter(BaseWorkflowEmitter):
135
135
  request=events, # type: ignore[arg-type]
136
136
  request_options=request_options,
137
137
  )
138
+
139
+ def join(self) -> None:
140
+ """
141
+ Wait for any background threads or timers used by this emitter to complete.
142
+ This ensures all pending work is finished before the workflow terminates.
143
+ """
144
+ self._flush_events()
145
+
146
+ if self._debounce_timer and self._debounce_timer.is_alive():
147
+ self._debounce_timer.join()
@@ -1,6 +1,6 @@
1
1
  from typing import Any, Dict
2
2
 
3
- from pydantic import field_serializer
3
+ from pydantic import Field, field_serializer
4
4
 
5
5
  from vellum.client.core.pydantic_utilities import UniversalBaseModel
6
6
  from vellum.workflows.inputs.base import BaseInputs
@@ -16,7 +16,7 @@ class DatasetRow(UniversalBaseModel):
16
16
  """
17
17
 
18
18
  label: str
19
- inputs: BaseInputs
19
+ inputs: BaseInputs = Field(default_factory=BaseInputs)
20
20
 
21
21
  @field_serializer("inputs")
22
22
  def serialize_inputs(self, inputs: BaseInputs) -> Dict[str, Any]:
@@ -1,4 +1,4 @@
1
- from abc import ABC, ABCMeta
1
+ from abc import ABC, ABCMeta, abstractmethod
2
2
  from dataclasses import field
3
3
  from functools import cached_property, reduce
4
4
  import inspect
@@ -215,6 +215,17 @@ class BaseNodeMeta(ABCMeta):
215
215
  yield attr_value
216
216
  yielded_attr_names.add(attr_name)
217
217
 
218
+ @abstractmethod
219
+ def __validate__(cls) -> None:
220
+ """
221
+ Validates the node.
222
+ Subclasses can override this method to implement their specific validation logic.
223
+ Called during serialization or explicit validation.
224
+
225
+ Default implementation performs no validation.
226
+ """
227
+ pass
228
+
218
229
 
219
230
  class _BaseNodeTriggerMeta(type):
220
231
  def __eq__(self, other: Any) -> bool:
@@ -112,4 +112,10 @@ class BasePromptNode(BaseNode[StateType], Generic[StateType]):
112
112
  if not target_node_output:
113
113
  return False
114
114
 
115
+ if not isinstance(target_node_output.instance, OutputReference):
116
+ return False
117
+
118
+ if target_node_output.instance.name != "text":
119
+ return False
120
+
115
121
  return True
@@ -45,9 +45,15 @@ from vellum.workflows.nodes.displayable.bases.base_prompt_node import BasePrompt
45
45
  from vellum.workflows.nodes.displayable.bases.utils import process_additional_prompt_outputs
46
46
  from vellum.workflows.outputs import BaseOutput
47
47
  from vellum.workflows.types import MergeBehavior
48
- from vellum.workflows.types.definition import DeploymentDefinition, MCPServer
48
+ from vellum.workflows.types.definition import (
49
+ ComposioToolDefinition,
50
+ DeploymentDefinition,
51
+ MCPServer,
52
+ VellumIntegrationToolDefinition,
53
+ )
49
54
  from vellum.workflows.types.generics import StateType, is_workflow_class
50
55
  from vellum.workflows.utils.functions import (
56
+ compile_composio_tool_definition,
51
57
  compile_function_definition,
52
58
  compile_inline_workflow_function_definition,
53
59
  compile_mcp_tool_definition,
@@ -134,7 +140,7 @@ class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
134
140
  elif isinstance(function, DeploymentDefinition):
135
141
  normalized_functions.append(
136
142
  compile_workflow_deployment_function_definition(
137
- function.model_dump(),
143
+ function,
138
144
  vellum_client=self._context.vellum_client,
139
145
  )
140
146
  )
@@ -142,6 +148,14 @@ class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
142
148
  normalized_functions.append(compile_inline_workflow_function_definition(function))
143
149
  elif callable(function):
144
150
  normalized_functions.append(compile_function_definition(function))
151
+ elif isinstance(function, ComposioToolDefinition):
152
+ normalized_functions.append(compile_composio_tool_definition(function))
153
+ elif isinstance(function, VellumIntegrationToolDefinition):
154
+ # TODO: Implement compile_vellum_integration_tool_definition
155
+ raise NotImplementedError(
156
+ "VellumIntegrationToolDefinition support coming soon. "
157
+ "This will be implemented when compile_vellum_integration_tool_definition is created."
158
+ )
145
159
  elif isinstance(function, MCPServer):
146
160
  tool_definitions = compile_mcp_tool_definition(function)
147
161
  for tool_def in tool_definitions:
@@ -5,6 +5,7 @@ from vellum.workflows.nodes.bases import BaseNode
5
5
  from vellum.workflows.nodes.bases.base import BaseNodeMeta
6
6
  from vellum.workflows.nodes.utils import cast_to_output_type
7
7
  from vellum.workflows.ports import NodePorts
8
+ from vellum.workflows.references.output import OutputReference
8
9
  from vellum.workflows.types import MergeBehavior
9
10
  from vellum.workflows.types.generics import StateType
10
11
  from vellum.workflows.types.utils import get_original_base
@@ -27,6 +28,7 @@ class _FinalOutputNodeMeta(BaseNodeMeta):
27
28
  **annotations,
28
29
  "value": parent.get_output_type(),
29
30
  }
31
+
30
32
  return parent
31
33
 
32
34
  def get_output_type(cls) -> Type:
@@ -38,6 +40,63 @@ class _FinalOutputNodeMeta(BaseNodeMeta):
38
40
  else:
39
41
  return all_args[1]
40
42
 
43
+ def __validate__(cls) -> None:
44
+ cls._validate_output_type_consistency(cls)
45
+
46
+ @classmethod
47
+ def _validate_output_type_consistency(mcs, cls: Type) -> None:
48
+ """
49
+ Validates that the declared output type of FinalOutputNode matches
50
+ the type of the descriptor assigned to the 'value' attribute in its Outputs class.
51
+
52
+ Raises ValueError if there's a type mismatch.
53
+ """
54
+ if not hasattr(cls, "Outputs"):
55
+ return
56
+
57
+ outputs_class = cls.Outputs
58
+ if not hasattr(outputs_class, "value"):
59
+ return
60
+
61
+ declared_output_type = cls.get_output_type()
62
+ value_descriptor = None
63
+
64
+ if "value" in outputs_class.__dict__:
65
+ value_descriptor = outputs_class.__dict__["value"]
66
+ else:
67
+ value_descriptor = getattr(outputs_class, "value")
68
+
69
+ if isinstance(value_descriptor, OutputReference):
70
+ descriptor_types = value_descriptor.types
71
+
72
+ type_mismatch = True
73
+ for descriptor_type in descriptor_types:
74
+ if descriptor_type == declared_output_type:
75
+ type_mismatch = False
76
+ break
77
+ try:
78
+ if issubclass(descriptor_type, declared_output_type) or issubclass(
79
+ declared_output_type, descriptor_type
80
+ ):
81
+ type_mismatch = False
82
+ break
83
+ except TypeError:
84
+ # Handle cases where types aren't classes (e.g., Union)
85
+ if str(descriptor_type) == str(declared_output_type):
86
+ type_mismatch = False
87
+ break
88
+
89
+ if type_mismatch:
90
+ declared_type_name = getattr(declared_output_type, "__name__", str(declared_output_type))
91
+ descriptor_type_names = [getattr(t, "__name__", str(t)) for t in descriptor_types]
92
+
93
+ raise ValueError(
94
+ f"Output type mismatch in {cls.__name__}: "
95
+ f"FinalOutputNode is declared with output type '{declared_type_name}' "
96
+ f"but the 'value' descriptor has type(s) {descriptor_type_names}. "
97
+ f"The output descriptor type must match the declared FinalOutputNode output type."
98
+ )
99
+
41
100
 
42
101
  class FinalOutputNode(BaseNode[StateType], Generic[StateType, _OutputType], metaclass=_FinalOutputNodeMeta):
43
102
  """
@@ -2,10 +2,11 @@ import pytest
2
2
 
3
3
  from vellum.workflows.exceptions import NodeException
4
4
  from vellum.workflows.nodes.displayable.final_output_node import FinalOutputNode
5
+ from vellum.workflows.nodes.displayable.inline_prompt_node import InlinePromptNode
5
6
  from vellum.workflows.state.base import BaseState
6
7
 
7
8
 
8
- def test_final_output_node__mismatched_output_type():
9
+ def test_final_output_node__mismatched_output_type_should_raise_exception_when_ran():
9
10
  # GIVEN a FinalOutputNode with a mismatched output type
10
11
  class StringOutputNode(FinalOutputNode[BaseState, str]):
11
12
  class Outputs(FinalOutputNode.Outputs):
@@ -18,3 +19,41 @@ def test_final_output_node__mismatched_output_type():
18
19
 
19
20
  # THEN an error is raised
20
21
  assert str(exc_info.value) == "Expected an output of type 'str', but received 'dict'"
22
+
23
+
24
+ def test_final_output_node__mismatched_output_type_should_raise_exception():
25
+ # GIVEN a FinalOutputNode declared with list output type but has a string value type
26
+ class Output(FinalOutputNode[BaseState, list]):
27
+ """Output the extracted invoice line items as an array of objects."""
28
+
29
+ class Outputs(FinalOutputNode.Outputs):
30
+ value = InlinePromptNode.Outputs.text
31
+
32
+ # WHEN attempting to validate the node class
33
+ # THEN a ValueError should be raised during validation
34
+ with pytest.raises(ValueError) as exc_info:
35
+ Output.__validate__()
36
+
37
+ # AND the error message should indicate the type mismatch
38
+ assert (
39
+ str(exc_info.value)
40
+ == "Output type mismatch in Output: FinalOutputNode is declared with output type 'list' but "
41
+ "the 'value' descriptor has type(s) ['str']. The output descriptor type must match the "
42
+ "declared FinalOutputNode output type."
43
+ )
44
+
45
+
46
+ def test_final_output_node__matching_output_type_should_pass_validation():
47
+ # GIVEN a FinalOutputNode declared with correct matching types
48
+ class CorrectOutput(FinalOutputNode[BaseState, str]):
49
+ """Output with correct type matching."""
50
+
51
+ class Outputs(FinalOutputNode.Outputs):
52
+ value = InlinePromptNode.Outputs.text
53
+
54
+ # WHEN attempting to validate the node class
55
+ # THEN validation should pass without raising an exception
56
+ try:
57
+ CorrectOutput.__validate__()
58
+ except ValueError:
59
+ pytest.fail("Validation should not raise an exception for correct type matching")
@@ -2,6 +2,7 @@ from typing import Any, ClassVar, Dict, Generic, Iterator, List, Optional, Set,
2
2
 
3
3
  from vellum import ChatMessage, PromptBlock
4
4
  from vellum.client.types.prompt_parameters import PromptParameters
5
+ from vellum.client.types.prompt_settings import PromptSettings
5
6
  from vellum.prompts.constants import DEFAULT_PROMPT_PARAMETERS
6
7
  from vellum.workflows.context import execution_context, get_parent_context
7
8
  from vellum.workflows.errors.types import WorkflowErrorCode
@@ -47,6 +48,7 @@ class ToolCallingNode(BaseNode[StateType], Generic[StateType]):
47
48
  prompt_inputs: ClassVar[Optional[EntityInputsInterface]] = None
48
49
  parameters: PromptParameters = DEFAULT_PROMPT_PARAMETERS
49
50
  max_prompt_iterations: ClassVar[Optional[int]] = 5
51
+ settings: ClassVar[Optional[Union[PromptSettings, Dict[str, Any]]]] = None
50
52
 
51
53
  class Outputs(BaseOutputs):
52
54
  """
@@ -150,6 +152,7 @@ class ToolCallingNode(BaseNode[StateType], Generic[StateType]):
150
152
  max_prompt_iterations=self.max_prompt_iterations,
151
153
  process_parameters_method=process_parameters_method,
152
154
  process_blocks_method=process_blocks_method,
155
+ settings=self.settings,
153
156
  )
154
157
 
155
158
  # Create the router node (handles routing logic only)
@@ -5,6 +5,7 @@ from vellum.client.types.chat_message_prompt_block import ChatMessagePromptBlock
5
5
  from vellum.client.types.fulfilled_execute_prompt_event import FulfilledExecutePromptEvent
6
6
  from vellum.client.types.initiated_execute_prompt_event import InitiatedExecutePromptEvent
7
7
  from vellum.client.types.plain_text_prompt_block import PlainTextPromptBlock
8
+ from vellum.client.types.prompt_settings import PromptSettings
8
9
  from vellum.client.types.rich_text_prompt_block import RichTextPromptBlock
9
10
  from vellum.client.types.string_vellum_value import StringVellumValue
10
11
  from vellum.client.types.variable_prompt_block import VariablePromptBlock
@@ -250,3 +251,66 @@ def test_get_mcp_tool_name_snake_case():
250
251
 
251
252
  result = get_mcp_tool_name(mcp_tool)
252
253
  assert result == "github_server__create_repository"
254
+
255
+
256
+ def test_create_tool_prompt_node_settings_dict_stream_disabled(vellum_adhoc_prompt_client):
257
+ # GIVEN settings provided as dict with stream disabled
258
+ tool_prompt_node = create_tool_prompt_node(
259
+ ml_model="gpt-4o-mini",
260
+ blocks=[],
261
+ functions=[],
262
+ prompt_inputs=None,
263
+ parameters=DEFAULT_PROMPT_PARAMETERS,
264
+ max_prompt_iterations=1,
265
+ settings={"stream_enabled": False},
266
+ )
267
+
268
+ # AND the API mocks
269
+ def generate_non_stream_response(*args, **kwargs):
270
+ return FulfilledExecutePromptEvent(execution_id=str(uuid4()), outputs=[StringVellumValue(value="ok")])
271
+
272
+ vellum_adhoc_prompt_client.adhoc_execute_prompt.side_effect = generate_non_stream_response
273
+
274
+ # WHEN we run the node
275
+ node_instance = tool_prompt_node()
276
+ list(node_instance.run())
277
+
278
+ # THEN the node should have called the API correctly
279
+ assert node_instance.settings is not None
280
+ assert node_instance.settings.stream_enabled is False
281
+ assert vellum_adhoc_prompt_client.adhoc_execute_prompt.call_count == 1
282
+ assert vellum_adhoc_prompt_client.adhoc_execute_prompt_stream.call_count == 0
283
+
284
+
285
+ def test_create_tool_prompt_node_settings_model_stream_enabled(vellum_adhoc_prompt_client):
286
+ # GIVEN settings provided as PromptSettings with stream enabled
287
+ tool_prompt_node = create_tool_prompt_node(
288
+ ml_model="gpt-4o-mini",
289
+ blocks=[],
290
+ functions=[],
291
+ prompt_inputs=None,
292
+ parameters=DEFAULT_PROMPT_PARAMETERS,
293
+ max_prompt_iterations=1,
294
+ settings=PromptSettings(stream_enabled=True),
295
+ )
296
+
297
+ # AND the API mocks
298
+ def generate_stream_events(*args, **kwargs):
299
+ execution_id = str(uuid4())
300
+ events = [
301
+ InitiatedExecutePromptEvent(execution_id=execution_id),
302
+ FulfilledExecutePromptEvent(execution_id=execution_id, outputs=[StringVellumValue(value="ok")]),
303
+ ]
304
+ yield from events
305
+
306
+ vellum_adhoc_prompt_client.adhoc_execute_prompt_stream.side_effect = generate_stream_events
307
+
308
+ # WHEN we run the node
309
+ node_instance = tool_prompt_node()
310
+ list(node_instance.run())
311
+
312
+ # THEN the node should have called the API correctly
313
+ assert node_instance.settings is not None
314
+ assert node_instance.settings.stream_enabled is True
315
+ assert vellum_adhoc_prompt_client.adhoc_execute_prompt_stream.call_count == 1
316
+ assert vellum_adhoc_prompt_client.adhoc_execute_prompt.call_count == 0
@@ -9,9 +9,9 @@ from vellum.client.types.array_chat_message_content import ArrayChatMessageConte
9
9
  from vellum.client.types.array_chat_message_content_item import ArrayChatMessageContentItem
10
10
  from vellum.client.types.function_call_chat_message_content import FunctionCallChatMessageContent
11
11
  from vellum.client.types.function_call_chat_message_content_value import FunctionCallChatMessageContentValue
12
- from vellum.client.types.function_definition import FunctionDefinition
13
12
  from vellum.client.types.prompt_output import PromptOutput
14
13
  from vellum.client.types.prompt_parameters import PromptParameters
14
+ from vellum.client.types.prompt_settings import PromptSettings
15
15
  from vellum.client.types.string_chat_message_content import StringChatMessageContent
16
16
  from vellum.client.types.variable_prompt_block import VariablePromptBlock
17
17
  from vellum.workflows.descriptors.base import BaseDescriptor
@@ -31,7 +31,13 @@ from vellum.workflows.ports.port import Port
31
31
  from vellum.workflows.state import BaseState
32
32
  from vellum.workflows.state.encoder import DefaultStateEncoder
33
33
  from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior, Tool, ToolBase
34
- from vellum.workflows.types.definition import ComposioToolDefinition, DeploymentDefinition, MCPServer, MCPToolDefinition
34
+ from vellum.workflows.types.definition import (
35
+ ComposioToolDefinition,
36
+ DeploymentDefinition,
37
+ MCPServer,
38
+ MCPToolDefinition,
39
+ VellumIntegrationToolDefinition,
40
+ )
35
41
  from vellum.workflows.types.generics import is_workflow_class
36
42
  from vellum.workflows.utils.functions import compile_mcp_tool_definition, get_mcp_tool_name
37
43
 
@@ -274,36 +280,6 @@ class ElseNode(BaseNode[ToolCallingState]):
274
280
  return self.Outputs()
275
281
 
276
282
 
277
- def _hydrate_composio_tool_definition(tool_def: ComposioToolDefinition) -> FunctionDefinition:
278
- """Hydrate a ComposioToolDefinition with detailed information from the Composio API.
279
-
280
- Args:
281
- tool_def: The basic ComposioToolDefinition to enhance
282
-
283
- Returns:
284
- FunctionDefinition with detailed parameters and description
285
- """
286
- try:
287
- composio_service = ComposioService()
288
- tool_details = composio_service.get_tool_by_slug(tool_def.action)
289
-
290
- # Create a FunctionDefinition directly with proper field extraction
291
- return FunctionDefinition(
292
- name=tool_def.name,
293
- description=tool_details.get("description", tool_def.description),
294
- parameters=tool_details.get("input_parameters", {}),
295
- )
296
-
297
- except Exception as e:
298
- # If hydration fails (including no API key), log and return basic function definition
299
- logger.warning(f"Failed to enhance Composio tool '{tool_def.action}': {e}")
300
- return FunctionDefinition(
301
- name=tool_def.name,
302
- description=tool_def.description,
303
- parameters={},
304
- )
305
-
306
-
307
283
  def create_tool_prompt_node(
308
284
  ml_model: str,
309
285
  blocks: List[Union[PromptBlock, Dict[str, Any]]],
@@ -313,17 +289,10 @@ def create_tool_prompt_node(
313
289
  max_prompt_iterations: Optional[int] = None,
314
290
  process_parameters_method: Optional[Callable] = None,
315
291
  process_blocks_method: Optional[Callable] = None,
292
+ settings: Optional[Union[PromptSettings, Dict[str, Any]]] = None,
316
293
  ) -> Type[ToolPromptNode]:
317
294
  if functions and len(functions) > 0:
318
- prompt_functions: List[Union[Tool, FunctionDefinition]] = []
319
-
320
- for function in functions:
321
- if isinstance(function, ComposioToolDefinition):
322
- # Get Composio tool details and hydrate the function definition
323
- enhanced_function = _hydrate_composio_tool_definition(function)
324
- prompt_functions.append(enhanced_function)
325
- else:
326
- prompt_functions.append(function)
295
+ prompt_functions: List[Tool] = functions
327
296
  else:
328
297
  prompt_functions = []
329
298
 
@@ -359,6 +328,13 @@ def create_tool_prompt_node(
359
328
  ),
360
329
  }
361
330
 
331
+ # Normalize settings to PromptSettings if provided as a dict
332
+ normalized_settings: Optional[PromptSettings]
333
+ if isinstance(settings, dict):
334
+ normalized_settings = PromptSettings.model_validate(settings)
335
+ else:
336
+ normalized_settings = settings
337
+
362
338
  node = cast(
363
339
  Type[ToolPromptNode],
364
340
  type(
@@ -371,6 +347,7 @@ def create_tool_prompt_node(
371
347
  "prompt_inputs": node_prompt_inputs,
372
348
  "parameters": parameters,
373
349
  "max_prompt_iterations": max_prompt_iterations,
350
+ "settings": normalized_settings,
374
351
  **({"process_parameters": process_parameters_method} if process_parameters_method is not None else {}),
375
352
  **({"process_blocks": process_blocks_method} if process_blocks_method is not None else {}),
376
353
  "__module__": __name__,
@@ -409,6 +386,10 @@ def create_router_node(
409
386
  function_name = get_function_name(function)
410
387
  port = create_port_condition(function_name)
411
388
  setattr(Ports, function_name, port)
389
+ elif isinstance(function, VellumIntegrationToolDefinition):
390
+ function_name = get_function_name(function)
391
+ port = create_port_condition(function_name)
392
+ setattr(Ports, function_name, port)
412
393
  elif isinstance(function, MCPServer):
413
394
  tool_functions: List[MCPToolDefinition] = compile_mcp_tool_definition(function)
414
395
  for tool_function in tool_functions:
@@ -483,6 +464,12 @@ def create_function_node(
483
464
  },
484
465
  )
485
466
  return node
467
+ elif isinstance(function, VellumIntegrationToolDefinition):
468
+ # TODO: Implement VellumIntegrationNode
469
+ raise NotImplementedError(
470
+ "VellumIntegrationToolDefinition support coming soon. "
471
+ "This will be implemented when the VellumIntegrationService is created."
472
+ )
486
473
  elif is_workflow_class(function):
487
474
  function.is_dynamic = True
488
475
  node = type(
@@ -572,5 +559,7 @@ def get_function_name(function: ToolBase) -> str:
572
559
  elif isinstance(function, ComposioToolDefinition):
573
560
  # model post init sets the name to the action if it's not set
574
561
  return function.name # type: ignore[return-value]
562
+ elif isinstance(function, VellumIntegrationToolDefinition):
563
+ return function.name
575
564
  else:
576
565
  return snake_case(function.__name__)
@@ -97,3 +97,32 @@ def test_dataset_row_with_default_inputs():
97
97
  assert serialized_dict["label"] == "defaults_test"
98
98
  assert serialized_dict["inputs"]["required_field"] == "required_value"
99
99
  assert serialized_dict["inputs"]["optional_with_default"] == "default_value"
100
+
101
+
102
+ def test_dataset_row_without_inputs():
103
+ """
104
+ Test that DatasetRow can be created with only a label (no inputs parameter).
105
+ """
106
+
107
+ dataset_row = DatasetRow(label="test_label_only")
108
+
109
+ serialized_dict = dataset_row.model_dump()
110
+
111
+ assert serialized_dict["label"] == "test_label_only"
112
+ assert serialized_dict["inputs"] == {}
113
+
114
+ assert isinstance(dataset_row.inputs, BaseInputs)
115
+
116
+
117
+ def test_dataset_row_with_empty_inputs():
118
+ """
119
+ Test that DatasetRow can be created with explicitly empty BaseInputs.
120
+ """
121
+
122
+ # GIVEN a DatasetRow with explicitly empty BaseInputs
123
+ dataset_row = DatasetRow(label="test_label", inputs=BaseInputs())
124
+
125
+ serialized_dict = dataset_row.model_dump()
126
+
127
+ assert serialized_dict["label"] == "test_label"
128
+ assert serialized_dict["inputs"] == {}
@@ -13,7 +13,12 @@ from typing import ( # type: ignore[attr-defined]
13
13
  )
14
14
 
15
15
  from vellum.client.core.pydantic_utilities import UniversalBaseModel
16
- from vellum.workflows.types.definition import ComposioToolDefinition, DeploymentDefinition, MCPServer
16
+ from vellum.workflows.types.definition import (
17
+ ComposioToolDefinition,
18
+ DeploymentDefinition,
19
+ MCPServer,
20
+ VellumIntegrationToolDefinition,
21
+ )
17
22
 
18
23
  if TYPE_CHECKING:
19
24
  from vellum.workflows.workflows.base import BaseWorkflow
@@ -51,5 +56,11 @@ class ConditionType(Enum):
51
56
 
52
57
 
53
58
  # Type alias for functions that can be called in tool calling nodes
54
- ToolBase = Union[Callable[..., Any], DeploymentDefinition, Type["BaseWorkflow"], ComposioToolDefinition]
59
+ ToolBase = Union[
60
+ Callable[..., Any],
61
+ DeploymentDefinition,
62
+ Type["BaseWorkflow"],
63
+ ComposioToolDefinition,
64
+ VellumIntegrationToolDefinition,
65
+ ]
55
66
  Tool = Union[ToolBase, MCPServer]
@@ -10,7 +10,7 @@ from vellum import Vellum
10
10
  from vellum.client.core.pydantic_utilities import UniversalBaseModel
11
11
  from vellum.client.types.code_resource_definition import CodeResourceDefinition as ClientCodeResourceDefinition
12
12
  from vellum.client.types.vellum_variable import VellumVariable
13
- from vellum.workflows.constants import AuthorizationType
13
+ from vellum.workflows.constants import AuthorizationType, VellumIntegrationProviderType
14
14
  from vellum.workflows.references.environment_variable import EnvironmentVariableReference
15
15
 
16
16
 
@@ -165,6 +165,18 @@ class ComposioToolDefinition(UniversalBaseModel):
165
165
  self.name = self.action.lower()
166
166
 
167
167
 
168
+ class VellumIntegrationToolDefinition(UniversalBaseModel):
169
+ type: Literal["INTEGRATION"] = "INTEGRATION"
170
+
171
+ # Core identification
172
+ provider: VellumIntegrationProviderType
173
+ integration: str # "GITHUB", "SLACK", etc.
174
+ name: str # Specific action like "GITHUB_CREATE_AN_ISSUE"
175
+
176
+ # Required for tool base consistency
177
+ description: str
178
+
179
+
168
180
  class MCPServer(UniversalBaseModel):
169
181
  type: Literal["MCP_SERVER"] = "MCP_SERVER"
170
182
  name: str
@@ -1,19 +1,6 @@
1
1
  import dataclasses
2
2
  import inspect
3
- from typing import (
4
- TYPE_CHECKING,
5
- Annotated,
6
- Any,
7
- Callable,
8
- Dict,
9
- List,
10
- Literal,
11
- Optional,
12
- Type,
13
- Union,
14
- get_args,
15
- get_origin,
16
- )
3
+ from typing import TYPE_CHECKING, Annotated, Any, Callable, List, Literal, Optional, Type, Union, get_args, get_origin
17
4
 
18
5
  from pydantic import BaseModel
19
6
  from pydantic_core import PydanticUndefined
@@ -21,8 +8,15 @@ from pydash import snake_case
21
8
 
22
9
  from vellum import Vellum
23
10
  from vellum.client.types.function_definition import FunctionDefinition
11
+ from vellum.workflows.integrations.composio_service import ComposioService
24
12
  from vellum.workflows.integrations.mcp_service import MCPService
25
- from vellum.workflows.types.definition import MCPServer, MCPToolDefinition
13
+ from vellum.workflows.types.definition import (
14
+ ComposioToolDefinition,
15
+ DeploymentDefinition,
16
+ MCPServer,
17
+ MCPToolDefinition,
18
+ VellumIntegrationToolDefinition,
19
+ )
26
20
  from vellum.workflows.utils.vellum_variables import vellum_variable_type_to_openapi_type
27
21
 
28
22
  if TYPE_CHECKING:
@@ -238,25 +232,21 @@ def compile_inline_workflow_function_definition(workflow_class: Type["BaseWorkfl
238
232
 
239
233
 
240
234
  def compile_workflow_deployment_function_definition(
241
- deployment_config: Dict[str, str],
235
+ deployment_definition: DeploymentDefinition,
242
236
  vellum_client: Vellum,
243
237
  ) -> FunctionDefinition:
244
238
  """
245
239
  Converts a deployment workflow config into our Vellum-native FunctionDefinition type.
246
240
 
247
241
  Args:
248
- deployment_config: Dict with 'deployment' and 'release_tag' keys
242
+ deployment_definition: DeploymentDefinition instance
249
243
  vellum_client: Vellum client instance
250
244
  """
251
- deployment = deployment_config["deployment"]
252
- release_tag = deployment_config["release_tag"]
253
-
254
- workflow_deployment_release = vellum_client.workflow_deployments.retrieve_workflow_deployment_release(
255
- deployment, release_tag
256
- )
245
+ release_info = deployment_definition.get_release_info(vellum_client)
257
246
 
258
- input_variables = workflow_deployment_release.workflow_version.input_variables
259
- description = workflow_deployment_release.description
247
+ name = release_info["name"]
248
+ description = release_info["description"]
249
+ input_variables = release_info["input_variables"]
260
250
 
261
251
  properties = {}
262
252
  required = []
@@ -270,7 +260,7 @@ def compile_workflow_deployment_function_definition(
270
260
  parameters = {"type": "object", "properties": properties, "required": required}
271
261
 
272
262
  return FunctionDefinition(
273
- name=deployment.replace("-", ""),
263
+ name=name.replace("-", ""),
274
264
  description=description,
275
265
  parameters=parameters,
276
266
  )
@@ -300,6 +290,53 @@ def compile_mcp_tool_definition(server_def: MCPServer) -> List[MCPToolDefinition
300
290
  return []
301
291
 
302
292
 
293
+ def compile_composio_tool_definition(tool_def: ComposioToolDefinition) -> FunctionDefinition:
294
+ """Hydrate a ComposioToolDefinition with detailed information from the Composio API.
295
+
296
+ Args:
297
+ tool_def: The basic ComposioToolDefinition to enhance
298
+
299
+ Returns:
300
+ FunctionDefinition with detailed parameters and description
301
+ """
302
+ try:
303
+ composio_service = ComposioService()
304
+ tool_details = composio_service.get_tool_by_slug(tool_def.action)
305
+
306
+ # Create a FunctionDefinition directly with proper field extraction
307
+ return FunctionDefinition(
308
+ name=tool_def.name,
309
+ description=tool_details.get("description", tool_def.description),
310
+ parameters=tool_details.get("input_parameters", {}),
311
+ )
312
+ except Exception:
313
+ # If hydration fails (including no API key), return basic function definition
314
+ return FunctionDefinition(
315
+ name=tool_def.name,
316
+ description=tool_def.description,
317
+ parameters={},
318
+ )
319
+
320
+
321
+ def compile_vellum_integration_tool_definition(tool_def: VellumIntegrationToolDefinition) -> FunctionDefinition:
322
+ """Compile a VellumIntegrationToolDefinition into a FunctionDefinition.
323
+
324
+ TODO: Implement when VellumIntegrationService is created.
325
+
326
+ Args:
327
+ tool_def: The VellumIntegrationToolDefinition to compile
328
+
329
+ Returns:
330
+ FunctionDefinition with tool parameters and description
331
+ """
332
+ # TODO: Implement when VellumIntegrationService is available
333
+ # This will eventually use VellumIntegrationService to fetch tool details
334
+ raise NotImplementedError(
335
+ "VellumIntegrationToolDefinition compilation coming soon. "
336
+ "This will be implemented when the VellumIntegrationService is created."
337
+ )
338
+
339
+
303
340
  def use_tool_inputs(**inputs):
304
341
  """
305
342
  Decorator to specify which parameters of a tool function should be provided
@@ -13,6 +13,7 @@ from vellum.workflows import BaseWorkflow
13
13
  from vellum.workflows.inputs.base import BaseInputs
14
14
  from vellum.workflows.nodes.bases.base import BaseNode
15
15
  from vellum.workflows.state.base import BaseState
16
+ from vellum.workflows.types.definition import DeploymentDefinition
16
17
  from vellum.workflows.utils.functions import (
17
18
  compile_function_definition,
18
19
  compile_inline_workflow_function_definition,
@@ -449,14 +450,15 @@ def test_compile_workflow_deployment_function_definition__just_name():
449
450
  # GIVEN a mock Vellum client and deployment
450
451
  mock_client = Mock()
451
452
  mock_release = Mock()
453
+ mock_release.deployment.name = "my_deployment"
452
454
  mock_release.workflow_version.input_variables = []
453
455
  mock_release.description = "This is a test deployment"
454
456
  mock_client.workflow_deployments.retrieve_workflow_deployment_release.return_value = mock_release
455
457
 
456
- deployment_config = {"deployment": "my_deployment", "release_tag": "latest"}
458
+ deployment_definition = DeploymentDefinition(deployment="my_deployment", release_tag="LATEST")
457
459
 
458
460
  # WHEN compiling the deployment workflow function
459
- compiled_function = compile_workflow_deployment_function_definition(deployment_config, mock_client)
461
+ compiled_function = compile_workflow_deployment_function_definition(deployment_definition, mock_client)
460
462
 
461
463
  # THEN it should return the compiled function definition (same structure as function test)
462
464
  assert compiled_function == FunctionDefinition(
@@ -496,13 +498,14 @@ def test_compile_workflow_deployment_function_definition__all_args():
496
498
  mock_inputs.append(mock_input)
497
499
 
498
500
  mock_release.workflow_version.input_variables = mock_inputs
501
+ mock_release.deployment.name = "my_deployment"
499
502
  mock_release.description = "This is a test deployment"
500
503
  mock_client.workflow_deployments.retrieve_workflow_deployment_release.return_value = mock_release
501
504
 
502
- deployment_config = {"deployment": "my_deployment", "release_tag": "latest"}
505
+ deployment_definition = DeploymentDefinition(deployment="my_deployment", release_tag="latest")
503
506
 
504
507
  # WHEN compiling the deployment workflow function
505
- compiled_function = compile_workflow_deployment_function_definition(deployment_config, mock_client)
508
+ compiled_function = compile_workflow_deployment_function_definition(deployment_definition, mock_client)
506
509
 
507
510
  # THEN it should return the compiled function definition
508
511
  assert compiled_function == FunctionDefinition(
@@ -564,13 +567,14 @@ def test_compile_workflow_deployment_function_definition__defaults():
564
567
  mock_inputs.append(mock_input_actual_default)
565
568
 
566
569
  mock_release.workflow_version.input_variables = mock_inputs
570
+ mock_release.deployment.name = "my_deployment"
567
571
  mock_release.description = "This is a test deployment"
568
572
  mock_client.workflow_deployments.retrieve_workflow_deployment_release.return_value = mock_release
569
573
 
570
- deployment_config = {"deployment": "my_deployment", "release_tag": "latest"}
574
+ deployment_definition = DeploymentDefinition(deployment="my_deployment", release_tag="LATEST")
571
575
 
572
576
  # WHEN compiling the deployment workflow function
573
- compiled_function = compile_workflow_deployment_function_definition(deployment_config, mock_client)
577
+ compiled_function = compile_workflow_deployment_function_definition(deployment_definition, mock_client)
574
578
 
575
579
  # THEN it should return the compiled function definition with proper default handling
576
580
  assert compiled_function == FunctionDefinition(
@@ -2,15 +2,21 @@ import os
2
2
  from typing import List, Optional
3
3
 
4
4
  from vellum import Vellum, VellumEnvironment
5
+ from vellum.client.types.api_version_enum import ApiVersionEnum
5
6
 
6
7
 
7
- def create_vellum_client(api_key: Optional[str] = None, api_url: Optional[str] = None) -> Vellum:
8
+ def create_vellum_client(
9
+ api_key: Optional[str] = None,
10
+ api_url: Optional[str] = None,
11
+ api_version: Optional[ApiVersionEnum] = None,
12
+ ) -> Vellum:
8
13
  if api_key is None:
9
14
  api_key = os.getenv("VELLUM_API_KEY", default="")
10
15
 
11
16
  return Vellum(
12
17
  api_key=api_key,
13
18
  environment=create_vellum_environment(api_url),
19
+ api_version=api_version,
14
20
  )
15
21
 
16
22
 
@@ -687,6 +687,14 @@ class BaseWorkflow(Generic[InputsType, StateType], BaseExecutable, metaclass=_Ba
687
687
  raise ValueError(f"Multiple workflows found in {module_path}")
688
688
  return workflows[0]
689
689
 
690
+ def join(self) -> None:
691
+ """
692
+ Wait for all emitters to complete their background work.
693
+ This ensures all pending events are processed before the workflow terminates.
694
+ """
695
+ for emitter in self.emitters:
696
+ emitter.join()
697
+
690
698
 
691
699
  WorkflowExecutionInitiatedBody.model_rebuild()
692
700
  WorkflowExecutionFulfilledBody.model_rebuild()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 1.4.1
3
+ Version: 1.4.2
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0
@@ -19,8 +19,8 @@ vellum_cli/tests/test_init.py,sha256=C_rV4lu-ab5iFoLRizs1XAUnSPdMf7oFuc1i4N4udOU
19
19
  vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
20
20
  vellum_cli/tests/test_move.py,sha256=FIrL1xlH5oFKGX2MugcTKL8JilpopmUC7hP5OaqF5zw,5213
21
21
  vellum_cli/tests/test_ping.py,sha256=b3aQLd-N59_8w2rRiWqwpB1rlHaKEYVbAj1Y3hi7A-g,2605
22
- vellum_cli/tests/test_pull.py,sha256=f7dK61y82LlJm-FAv-IpfmscJijIfZZrR-rzN1TKkU0,49421
23
- vellum_cli/tests/test_push.py,sha256=10G-H88tdiYvg9CaC8OXOf25UEzWkWWB01vNhuxzjog,41944
22
+ vellum_cli/tests/test_pull.py,sha256=e2XHzcHIx9k-FyuNAl7wMSNsSSebPGyP6U05JGcddFs,49447
23
+ vellum_cli/tests/test_push.py,sha256=2MjkNKr_9Guv5Exjsm3L1BeVXmPkKUcCSiKnp90HgW4,41996
24
24
  vellum_ee/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  vellum_ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  vellum_ee/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -44,7 +44,7 @@ vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=dtO9A-rjbDEJ
44
44
  vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=8tSb8qGVoRIELubu0qPeoDlt1LpiIqc6d9_30GWRd_k,2266
45
45
  vellum_ee/workflows/display/nodes/vellum/final_output_node.py,sha256=z4oeTgKnMGVaGig8XOZm5B_xYL4H7zweYlFweCbhnyA,3000
46
46
  vellum_ee/workflows/display/nodes/vellum/guardrail_node.py,sha256=9_AslWjzj4RHH2sq3SIaq9FU0NCg7ex5TIWrNMybqXg,2173
47
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=20tahU75zKImm6sAwLIYA9VEC6aNATjZdwA2beNnCIk,11949
47
+ vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=muyLv3KMIsUnnXhiPbPhw5B0TO1Z8LUwytpVQKlz4tM,11906
48
48
  vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py,sha256=qy_EtBIAHIhju68PA-skm-WbFnaNEuDoxkSMWRl2SpQ,5870
49
49
  vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=kwLqptup7bzYUDkGDbpcJPMMusMezsYrG5rSUYl5TlQ,3750
50
50
  vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=xMHaPfTSZWYprQenlHm2g47u0a5O9Me_dhAjfqo8nKQ,3116
@@ -58,6 +58,7 @@ vellum_ee/workflows/display/nodes/vellum/tests/__init__.py,sha256=47DEQpj8HBSa-_
58
58
  vellum_ee/workflows/display/nodes/vellum/tests/test_api_node.py,sha256=DQAtsabvn6BE6xWwKNHzMOppzoy1-1dssNnrwbHUdRU,1490
59
59
  vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py,sha256=oEH9myRn-NAP_mRstV0LifX3ncbmAOjCvyIVCZhACk0,10885
60
60
  vellum_ee/workflows/display/nodes/vellum/tests/test_error_node.py,sha256=540FoWMpJ3EN_DPjHsr9ODJWCRVcUa5hZBn-5T2GiHU,1665
61
+ vellum_ee/workflows/display/nodes/vellum/tests/test_final_output_node.py,sha256=KVftEQxXARlcr-Uuo1ZK_wEHTcTH64OZJ3Ub3mN8x7I,3006
61
62
  vellum_ee/workflows/display/nodes/vellum/tests/test_inline_subworkflow_node.py,sha256=SKOYan-dxY4gsO0R4JyQUyWrABHBN8XImKw9Eeo4wGo,3535
62
63
  vellum_ee/workflows/display/nodes/vellum/tests/test_note_node.py,sha256=uiMB0cOxKZzos7YKnj4ef4DFa2bOvZJWIv-hfbUV6Go,1218
63
64
  vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_deployment_node.py,sha256=54oatuBB98Dfbr08NqZU8ZNhfQdJWhODIwjsegPPJJw,6376
@@ -98,17 +99,17 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_
98
99
  vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py,sha256=ddPa8gNBYH2tWk92ymngY7M8n74J-8CEre50HISP_-g,7877
99
100
  vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py,sha256=A7Ef8P1-Nyvsb97bumKT9W2R1LuZaY9IKFV-7iRueog,4010
100
101
  vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_composio_serialization.py,sha256=oVXCjkU0G56QJmqnd_xIwF3D9bhJwALFibM2wmRhwUk,3739
101
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py,sha256=UD1HU8aEAXSo43JGhjBGE2FGsknHj_zOsIHTo2TLEW0,26470
102
+ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py,sha256=K7r5hivC3-599oqbkLgj5WMBcrix1znmuhAxs0w0EAE,26692
102
103
  vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_mcp_serialization.py,sha256=QhQbijeCnFeX1i3SMjHJg2WVAEt5JEO3dhFRv-mofdA,2458
103
104
  vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_parent_input.py,sha256=__LX4cuzbyZp_1wc-SI8X_J0tnhOkCEmRVUWLKI5aQM,4578
104
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=tyRlb6ozcsvkeHOC9dsHc4jg3HrHQITDGadi8qbNGns,10215
105
+ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=5yaoN5aM6VZZtsleQcSWpbNyWLE1nTnMF6KbLmCrlc8,10437
105
106
  vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py,sha256=XIZZr5POo2NLn2uEWm9EC3rejeBMoO4X-JtzTH6mvp4,4074
106
107
  vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py,sha256=pLCyMScV88DTBXRH7jXaXOEA1GBq8NIipCUFwIAWnwI,2771
107
108
  vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py,sha256=exT7U-axwtYgFylagScflSQLJEND51qIAx2UATju6JM,6023
108
109
  vellum_ee/workflows/display/tests/workflow_serialization/test_final_output_node_map_reference_serialization.py,sha256=vl3pxUJlrYRA8zzFJ-gRm7fe-5fviLNSIsUC7imnMqk,3502
109
110
  vellum_ee/workflows/display/tests/workflow_serialization/test_web_search_node_serialization.py,sha256=vbDFBrWUPeeW7cxjNA6SXrsHlYcbOAhlQ4C45Vdnr1c,3428
110
111
  vellum_ee/workflows/display/tests/workflow_serialization/test_workflow_input_parameterization_error.py,sha256=vAdmn3YTBDpo55znbydQxsgg9ASqHcvsUPwiBR_7wfo,1461
111
- vellum_ee/workflows/display/types.py,sha256=cyZruu4sXAdHjwuFc7dydM4DcFNf-pp_CmulXItxac4,3679
112
+ vellum_ee/workflows/display/types.py,sha256=Yko3zPXRjkkPjpx3gCSdNNjegh3CQYsoXFoQWWiTxWU,3777
112
113
  vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
113
114
  vellum_ee/workflows/display/utils/auto_layout.py,sha256=f4GiLn_LazweupfqTpubcdtdfE_vrOcmZudSsnYIY9E,3906
114
115
  vellum_ee/workflows/display/utils/events.py,sha256=DE33uoKW78BZtITJ6L22dMZN3KR1BuZBVC98C_gIyzU,1943
@@ -121,7 +122,7 @@ vellum_ee/workflows/display/utils/tests/test_events.py,sha256=42IEBnMbaQrH8gigw5
121
122
  vellum_ee/workflows/display/utils/vellum.py,sha256=sZwU0KdmZZTKWW62SyxJTl2tC8tN6p_BpZ-lDoinV-U,5670
122
123
  vellum_ee/workflows/display/vellum.py,sha256=J2mdJZ1sdLW535DDUkq_Vm8Z572vhuxHxVZF9deKSdk,391
123
124
  vellum_ee/workflows/display/workflows/__init__.py,sha256=JTB9ObEV3l4gGGdtfBHwVJtTTKC22uj-a-XjTVwXCyA,148
124
- vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=tlhtdNFT4_NJlBDkcn13CQOA49iy6d1F7kl5ONq21Rw,44032
125
+ vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=x8HQK9AN2ql0_PFQAIilS4VEc_6h6Vd5tjhGYy7Hbs8,44329
125
126
  vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py,sha256=gxz76AeCqgAZ9D2lZeTiZzxY9eMgn3qOSfVgiqYcOh8,2028
126
127
  vellum_ee/workflows/display/workflows/tests/test_workflow_display.py,sha256=OKf_WVoPkYPrielOz8CyI5AjWt9MS2nSbWQKpF7HSLI,37847
127
128
  vellum_ee/workflows/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -155,7 +156,7 @@ vellum/client/README.md,sha256=flqu57ubZNTfpq60CdLtJC9gp4WEkyjb_n_eZ4OYf9w,6497
155
156
  vellum/client/__init__.py,sha256=T5Ht_w-Mk_9nzGqdadhQB8V20M0vYj7am06ut0A3P1o,73401
156
157
  vellum/client/core/__init__.py,sha256=lTcqUPXcx4112yLDd70RAPeqq6tu3eFMe1pKOqkW9JQ,1562
157
158
  vellum/client/core/api_error.py,sha256=44vPoTyWN59gonCIZMdzw7M1uspygiLnr3GNFOoVL2Q,614
158
- vellum/client/core/client_wrapper.py,sha256=llxvaMOp54YJE6Vhu9cPaMURRdf9SIRPapzoEfyMqi0,2840
159
+ vellum/client/core/client_wrapper.py,sha256=3LRRCUmekHH5eSClvUo_1GvPVridWvzGOYcx_DPDVZQ,2840
159
160
  vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
160
161
  vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
161
162
  vellum/client/core/force_multipart.py,sha256=awxh5MtcRYe74ehY8U76jzv6fYM_w_D3Rur7KQQzSDk,429
@@ -1716,7 +1717,7 @@ vellum/utils/uuid.py,sha256=Ch6wWRgwICxLxJCTl5iE3EdRlZj2zADR-zUMUtjcMWM,214
1716
1717
  vellum/version.py,sha256=jq-1PlAYxN9AXuaZqbYk9ak27SgE2lw9Ia5gx1b1gVI,76
1717
1718
  vellum/workflows/README.md,sha256=hZdTKBIcsTKPofK68oPkBhyt0nnRh0csqC12k4FMHHA,3597
1718
1719
  vellum/workflows/__init__.py,sha256=gd5AiZqVTcvqelhysG0jOWYfC6pJKRAVhS7qwf0bHU4,132
1719
- vellum/workflows/constants.py,sha256=xweiPRUSVEnGz9BJvpIWu96Gfok89QneARu4K7wj7f8,1358
1720
+ vellum/workflows/constants.py,sha256=ApFp3fm_DOuakvZV-c0ybieyVp-wELgHk-GTzDJoDCg,1429
1720
1721
  vellum/workflows/context.py,sha256=ViyIeMDhUv-MhnynLaXPlvlbYxRU45ySvYidCNSbFZU,2458
1721
1722
  vellum/workflows/descriptors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1722
1723
  vellum/workflows/descriptors/base.py,sha256=fRnRkECyDjfz2QEDCY9Q5mAerlJ6jR0R4nE-MP2VP_k,16558
@@ -1726,8 +1727,8 @@ vellum/workflows/descriptors/utils.py,sha256=7QvS_IOZWIoKvhNwpYBOTP3NasLSIBKTnhy
1726
1727
  vellum/workflows/edges/__init__.py,sha256=wSkmAnz9xyi4vZwtDbKxwlplt2skD7n3NsxkvR_pUus,50
1727
1728
  vellum/workflows/edges/edge.py,sha256=N0SnY3gKVuxImPAdCbPMPlHJIXbkQ3fwq_LbJRvVMFc,677
1728
1729
  vellum/workflows/emitters/__init__.py,sha256=d9QFOI3eVg6rzpSFLvrjkDYXWikf1tcp3ruTRa2Boyc,143
1729
- vellum/workflows/emitters/base.py,sha256=Tcp13VMB-GMwEJdl-6XTPckspdOdwpMgBx22-PcQxds,892
1730
- vellum/workflows/emitters/vellum_emitter.py,sha256=ECBIRA48WS5rIJd1iWUfye7B5Up7ujL98BTlZwWALKs,4430
1730
+ vellum/workflows/emitters/base.py,sha256=4hClzI-ue0kWiEnZ1T1zvGz2ZWnoWLCVF-seqHBMUC8,1144
1731
+ vellum/workflows/emitters/vellum_emitter.py,sha256=T77LuU31TBU75GOFyrWuJWyW5RzRNNH1_PFWcgdWMg0,4788
1731
1732
  vellum/workflows/environment/__init__.py,sha256=TJz0m9dwIs6YOwCTeuN0HHsU-ecyjc1OJXx4AFy83EQ,121
1732
1733
  vellum/workflows/environment/environment.py,sha256=Ck3RPKXJvtMGx_toqYQQQF-ZwXm5ijVwJpEPTeIJ4_Q,471
1733
1734
  vellum/workflows/errors/__init__.py,sha256=tWGPu5xyAU8gRb8_bl0fL7OfU3wxQ9UH6qVwy4X4P_Q,113
@@ -1795,7 +1796,7 @@ vellum/workflows/graph/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
1795
1796
  vellum/workflows/graph/tests/test_graph.py,sha256=0Pov0sCsxjzUDL9wy7xy9jFD-F2GsMJnZVEVFXzQGdM,15433
1796
1797
  vellum/workflows/inputs/__init__.py,sha256=02pj0IbJkN1AxTreswK39cNi45tA8GWcAAdRJve4cuM,116
1797
1798
  vellum/workflows/inputs/base.py,sha256=4kCRVz8AOqL6NgWZlfsBMnmCeDGDCTU0ImyBLlB0oaE,5203
1798
- vellum/workflows/inputs/dataset_row.py,sha256=T8lcn9qyC7IY0w3EIfnn4AwZ3pYw9sf4kdIi0VkX_Sw,1033
1799
+ vellum/workflows/inputs/dataset_row.py,sha256=Szdb_RKysCEBRfy4B5LoXoPiTZPEFp_0_RqRZUZRGbU,1076
1799
1800
  vellum/workflows/inputs/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1800
1801
  vellum/workflows/inputs/tests/test_inputs.py,sha256=lioA8917mFLYq7Ml69UNkqUjcWbbxkxnpIEJ4FBaYBk,2206
1801
1802
  vellum/workflows/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1805,7 +1806,7 @@ vellum/workflows/integrations/tests/test_mcp_service.py,sha256=q_DYrDkIqI4sQBNgI
1805
1806
  vellum/workflows/logging.py,sha256=_a217XogktV4Ncz6xKFz7WfYmZAzkfVRVuC0rWob8ls,437
1806
1807
  vellum/workflows/nodes/__init__.py,sha256=zymtc3_iW2rFmMR-sayTLuN6ZsAw8VnJweWPsjQk2-Q,1197
1807
1808
  vellum/workflows/nodes/bases/__init__.py,sha256=cniHuz_RXdJ4TQgD8CBzoiKDiPxg62ErdVpCbWICX64,58
1808
- vellum/workflows/nodes/bases/base.py,sha256=i4tuPo_KyFI1ZJh__AI-oxRkDGch9pNTmOqt69HTcE0,20478
1809
+ vellum/workflows/nodes/bases/base.py,sha256=WWRHbCk9Xf6FzY82af7WwGasF_h6nQAjMXjDDzHTVOs,20821
1809
1810
  vellum/workflows/nodes/bases/base_adornment_node.py,sha256=hrgzuTetM4ynPd9YGHoK8Vwwn4XITi3aZZ_OCnQrq4Y,3433
1810
1811
  vellum/workflows/nodes/bases/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1811
1812
  vellum/workflows/nodes/bases/tests/test_base_adornment_node.py,sha256=fXZI9KqpS4XMBrBnIEkK3foHaBVvyHwYcQWWDKay7ic,1148
@@ -1843,9 +1844,9 @@ vellum/workflows/nodes/displayable/bases/api_node/node.py,sha256=cOYaIqimzDL6TuX
1843
1844
  vellum/workflows/nodes/displayable/bases/api_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1844
1845
  vellum/workflows/nodes/displayable/bases/api_node/tests/test_node.py,sha256=5C59vn_yg4r5EWioKIr658Jr1MSGX3YF4yKJokY37Xc,4726
1845
1846
  vellum/workflows/nodes/displayable/bases/base_prompt_node/__init__.py,sha256=Org3xTvgp1pA0uUXFfnJr29D3HzCey2lEdYF4zbIUgo,70
1846
- vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py,sha256=ea20icDM1HB942wkH-XtXNSNCBDcjeOiN3vowkHL4fs,4477
1847
+ vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py,sha256=w02vgydiwNoKru324QLSkH3BiGUvHTgKbf05BEx945s,4657
1847
1848
  vellum/workflows/nodes/displayable/bases/inline_prompt_node/__init__.py,sha256=Hl35IAoepRpE-j4cALaXVJIYTYOF3qszyVbxTj4kS1s,82
1848
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=eRhqxpkqcP5S4jx-vnnyHZvZAVQxKyCQ9kYxQCyWNvY,17921
1849
+ vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=ucbfX1HttsRDgngYnbS5MTytky-MAJW2ZkWgK4B-jI8,18600
1849
1850
  vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1850
1851
  vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py,sha256=xc53wGwVqxBnN7eoyWkJ-RJ-FeUpHKekkKjViASHAFg,27495
1851
1852
  vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py,sha256=H9mM75EQpP6PUvsXCTbwjw4CqMMLf36m1G2XqiPEvH4,12139
@@ -1865,9 +1866,9 @@ vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU
1865
1866
  vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=71ZUNfTiD7t2Kai2ypw0tmv1lSf1brQaHAQD-SeUrGE,1101
1866
1867
  vellum/workflows/nodes/displayable/conftest.py,sha256=K2kLM2JGAfcrmmd92u8DXInUO5klFdggPWblg5RVcx4,5729
1867
1868
  vellum/workflows/nodes/displayable/final_output_node/__init__.py,sha256=G7VXM4OWpubvSJtVkGmMNeqgb9GkM7qZT838eL18XU4,72
1868
- vellum/workflows/nodes/displayable/final_output_node/node.py,sha256=6SMaGeBlHQ5rdBq_AJ75bHUS4iizoT4Q9gEBVu6DWHM,2497
1869
+ vellum/workflows/nodes/displayable/final_output_node/node.py,sha256=1_F9S7w-gIEUoXIdilgpqDeCKxJ0_J0oTYvE35dbjHk,4908
1869
1870
  vellum/workflows/nodes/displayable/final_output_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1870
- vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py,sha256=E6LQ74qZjY4Xi4avx2qdOCgGhF8pEcNLBh8cqYRkzMI,709
1871
+ vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py,sha256=FR7lWUJlcWW1e9q_3vefi-b8_LA7CayZgTWZAnlAiLg,2387
1871
1872
  vellum/workflows/nodes/displayable/guardrail_node/__init__.py,sha256=Ab5eXmOoBhyV4dMWdzh32HLUmnPIBEK_zFCT38C4Fng,68
1872
1873
  vellum/workflows/nodes/displayable/guardrail_node/node.py,sha256=axYUojar_kdB3gi4LG3g9euJ8VkOxNtiFxJNI46v-SQ,5869
1873
1874
  vellum/workflows/nodes/displayable/guardrail_node/test_node.py,sha256=SAGv6hSFcBwQkudn1VxtaKNsXSXWWELl3eK05zM6tS0,5410
@@ -1899,13 +1900,13 @@ vellum/workflows/nodes/displayable/tests/test_search_node_error_handling.py,sha2
1899
1900
  vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py,sha256=VepO5z1277c1y5N6LLIC31nnWD1aak2m5oPFplfJHHs,6935
1900
1901
  vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py,sha256=Bjv-wZyFgNaVZb9KEMMZd9lFoLzbPEPjEMpANizMZw4,2413
1901
1902
  vellum/workflows/nodes/displayable/tool_calling_node/__init__.py,sha256=3n0-ysmFKsr40CVxPthc0rfJgqVJeZuUEsCmYudLVRg,117
1902
- vellum/workflows/nodes/displayable/tool_calling_node/node.py,sha256=Exw0_5-bzphKF42pKwHF-tH25s8MD6wSbGcp7jZuBFg,8236
1903
+ vellum/workflows/nodes/displayable/tool_calling_node/node.py,sha256=WXpCYhZ_wlyF_q0T769fw6CI_6-I9kvTiy1yfBGXjvE,8414
1903
1904
  vellum/workflows/nodes/displayable/tool_calling_node/state.py,sha256=CcBVb_YtwfSSka4ze678k6-qwmzMSfjfVP8_Y95feSo,302
1904
1905
  vellum/workflows/nodes/displayable/tool_calling_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1905
1906
  vellum/workflows/nodes/displayable/tool_calling_node/tests/test_composio_service.py,sha256=in1fbEz5x1tx3uKv9YXdvOncsHucNL8Ro6Go7lBuuOQ,8962
1906
1907
  vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py,sha256=GZoeybB9uM7ai8sBLAtUMHrMVgh-WrJDWrKZci6feDs,11892
1907
- vellum/workflows/nodes/displayable/tool_calling_node/tests/test_utils.py,sha256=SIu5GCj4tIE4fz-cAcdULtQfqZIhrcc3Doo6TWLXBws,8804
1908
- vellum/workflows/nodes/displayable/tool_calling_node/utils.py,sha256=6XsvA77wF9MI6KBQNN1JMdpQwhK8pKUQtXgsPmq_I3Q,22837
1908
+ vellum/workflows/nodes/displayable/tool_calling_node/tests/test_utils.py,sha256=EmKFA-ELdTzlK0xMqWnuSZPoGNLYCwk6b0amTqirZo0,11305
1909
+ vellum/workflows/nodes/displayable/tool_calling_node/utils.py,sha256=jqFpPDLZ463i2Lt7w_IN0fPypl1vrzZiYq2_1q9OyPo,22388
1909
1910
  vellum/workflows/nodes/displayable/web_search_node/__init__.py,sha256=8FOnEP-n-U68cvxTlJW9wphIAGHq5aqjzLM-DoSSXnU,61
1910
1911
  vellum/workflows/nodes/displayable/web_search_node/node.py,sha256=NQYux2bOtuBF5E4tn-fXi5y3btURPRrNqMSM9MAZYI4,5091
1911
1912
  vellum/workflows/nodes/displayable/web_search_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1955,13 +1956,13 @@ vellum/workflows/state/store.py,sha256=uVe-oN73KwGV6M6YLhwZMMUQhzTQomsVfVnb8V91g
1955
1956
  vellum/workflows/state/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1956
1957
  vellum/workflows/state/tests/test_state.py,sha256=zEVFIY2any41X2BA5Us_qqKpzH5HRqmyrUJ04GTO0pU,7484
1957
1958
  vellum/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1958
- vellum/workflows/tests/test_dataset_row.py,sha256=qtz3cEcppCtr96co_8MmX4Jh1ro6bKZd_FGtRyFncRA,3370
1959
+ vellum/workflows/tests/test_dataset_row.py,sha256=S8aIiYU9TRzJ8GTl5qCjnJ-fuHdxatHJFGLlKTVHPr4,4174
1959
1960
  vellum/workflows/tests/test_sandbox.py,sha256=JKwaluI-lODQo7Ek9sjDstjL_WTdSqUlVik6ZVTfVOA,1826
1960
1961
  vellum/workflows/tests/test_undefined.py,sha256=zMCVliCXVNLrlC6hEGyOWDnQADJ2g83yc5FIM33zuo8,353
1961
1962
  vellum/workflows/types/__init__.py,sha256=KxUTMBGzuRCfiMqzzsykOeVvrrkaZmTTo1a7SLu8gRM,68
1962
1963
  vellum/workflows/types/code_execution_node_wrappers.py,sha256=fewX9bqF_4TZuK-gZYIn12s31-k03vHMGRpvFAPm11Y,3206
1963
- vellum/workflows/types/core.py,sha256=TggDVs2lVya33xvu374EDhMC1b7RRlAAs0zWLaF46BA,1385
1964
- vellum/workflows/types/definition.py,sha256=727tDk-XzLAlpK2_OuPICz2VnFLW5WZd-WcZQrd2lvY,6854
1964
+ vellum/workflows/types/core.py,sha256=yKm3sE02ult969q80DTmawiwYqodVjcAW-zlaUIgIv4,1495
1965
+ vellum/workflows/types/definition.py,sha256=rVoiXhj7xcQS793qjt2gdv64ywfQrRvujURjIWeC6gA,7240
1965
1966
  vellum/workflows/types/generics.py,sha256=8jptbEx1fnJV0Lhj0MpCJOT6yNiEWeTOYOwrEAb5CRU,1576
1966
1967
  vellum/workflows/types/stack.py,sha256=h7NE0vXR7l9DevFBIzIAk1Zh59K-kECQtDTKOUunwMY,1314
1967
1968
  vellum/workflows/types/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1969,27 +1970,27 @@ vellum/workflows/types/tests/test_definition.py,sha256=rvDYjdJ1rvAv0qHBN7i7s-_WA
1969
1970
  vellum/workflows/types/tests/test_utils.py,sha256=UnZog59tR577mVwqZRqqWn2fScoOU1H6up0EzS8zYhw,2536
1970
1971
  vellum/workflows/types/utils.py,sha256=mTctHITBybpt4855x32oCKALBEcMNLn-9cCmfEKgJHQ,6498
1971
1972
  vellum/workflows/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1972
- vellum/workflows/utils/functions.py,sha256=z1V_HujCZI-pfOLIEwkd0_ZeeR1MNqq3fvgDke62NRo,11016
1973
+ vellum/workflows/utils/functions.py,sha256=CmdyfICCs0ZWmdrRpX8oITHkYcDrGu61Rrd_pVwl6ks,12723
1973
1974
  vellum/workflows/utils/hmac.py,sha256=JJCczc6pyV6DuE1Oa0QVfYPUN_of3zEYmGFib3OZnrE,1135
1974
1975
  vellum/workflows/utils/names.py,sha256=QtHquoaGqRseu5gg2OcVGI2d_CMcEOvjb9KspwH4C-A,552
1975
1976
  vellum/workflows/utils/pydantic_schema.py,sha256=eR_bBtY-T0pttJP-ARwagSdCOnwPUtiT3cegm2lzDTQ,1310
1976
1977
  vellum/workflows/utils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1977
- vellum/workflows/utils/tests/test_functions.py,sha256=TlNhD0OBJ-aeYn4qUqmApuajkx9sJx0lIQRMfT8Xf0w,23688
1978
+ vellum/workflows/utils/tests/test_functions.py,sha256=PClZVGKTx4zLJwDmMM-NpLjat2M64B8rq26Nu4MEEIM,23974
1978
1979
  vellum/workflows/utils/tests/test_names.py,sha256=DnRRnuORxQXx9ESegCzkxiWcHy2_bBi7lXgbFi3FZK8,757
1979
1980
  vellum/workflows/utils/tests/test_uuids.py,sha256=i77ABQ0M3S-aFLzDXHJq_yr5FPkJEWCMBn1HJ3DObrE,437
1980
1981
  vellum/workflows/utils/tests/test_vellum_variables.py,sha256=X7b-bbN3bFRx0WG31bowcaOgsXxEPYnh2sgpsqgKIsQ,2096
1981
1982
  vellum/workflows/utils/uuids.py,sha256=IaZQANz7fhF7la0_J1O50Y6D2PIYv_taRDTRzBT9aWw,1284
1982
1983
  vellum/workflows/utils/vellum_variables.py,sha256=Tgv09yYROgq8QZbrKKIOEdg0IQ8Vfgz_vRjY4tYzaTQ,7152
1983
1984
  vellum/workflows/utils/zip.py,sha256=HVg_YZLmBOTXKaDV3Xhaf3V6sYnfqqZXQ8CpuafkbPY,1181
1984
- vellum/workflows/vellum_client.py,sha256=xkfoucodxNK5JR2-lbRqZx3xzDgExWkP6kySrpi_Ubc,1079
1985
+ vellum/workflows/vellum_client.py,sha256=3iDR7VV_NgLSm1iZQCKDvrmfEaX1bOJiU15QrxyHpv0,1237
1985
1986
  vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
1986
- vellum/workflows/workflows/base.py,sha256=4_-kEebUBCn7d4N0TxF-sQejM2gAF8N6FbGabV2t6Pw,28346
1987
+ vellum/workflows/workflows/base.py,sha256=PvrsKCEGsnBzKalYymErGmdnYUNBs7pJ5NEOCKL90CY,28615
1987
1988
  vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnadGsrSZGa7t7LpJA,2008
1988
1989
  vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1989
1990
  vellum/workflows/workflows/tests/test_base_workflow.py,sha256=ptMntHzVyy8ZuzNgeTuk7hREgKQ5UBdgq8VJFSGaW4Y,20832
1990
1991
  vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
1991
- vellum_ai-1.4.1.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1992
- vellum_ai-1.4.1.dist-info/METADATA,sha256=le27kYJhHlVpQr0IVs13TF46G-7YTLPVPtVPQtHsANk,5547
1993
- vellum_ai-1.4.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1994
- vellum_ai-1.4.1.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1995
- vellum_ai-1.4.1.dist-info/RECORD,,
1992
+ vellum_ai-1.4.2.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1993
+ vellum_ai-1.4.2.dist-info/METADATA,sha256=2O0UVBAX-fWKzUzs1b8dWnKnfK2gpUNOTM1ZAz5alk0,5547
1994
+ vellum_ai-1.4.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1995
+ vellum_ai-1.4.2.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1996
+ vellum_ai-1.4.2.dist-info/RECORD,,
@@ -1323,6 +1323,7 @@ MY_OTHER_VELLUM_API_KEY=aaabbbcccddd
1323
1323
  vellum_client_class.assert_called_once_with(
1324
1324
  api_key="aaabbbcccddd",
1325
1325
  environment=mock.ANY,
1326
+ api_version=None,
1326
1327
  )
1327
1328
 
1328
1329
  # AND the vellum lock file should have been updated with the correct workspace
@@ -721,6 +721,7 @@ MY_OTHER_VELLUM_API_KEY=aaabbbcccddd
721
721
  vellum_client_class.assert_called_once_with(
722
722
  api_key="aaabbbcccddd",
723
723
  environment=mock.ANY,
724
+ api_version=None,
724
725
  )
725
726
 
726
727
  # AND the vellum lock file should have been updated with the correct workspace
@@ -882,6 +883,7 @@ MY_OTHER_VELLUM_API_KEY=aaabbbcccddd
882
883
  vellum_client_class.assert_called_once_with(
883
884
  api_key="aaabbbcccddd",
884
885
  environment=mock.ANY,
886
+ api_version=None,
885
887
  )
886
888
 
887
889
  # AND the vellum lock file should have the same two workflows
@@ -163,9 +163,7 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
163
163
  elif callable(function):
164
164
  normalized_functions = compile_function_definition(function)
165
165
  elif isinstance(function, DeploymentDefinition):
166
- normalized_functions = compile_workflow_deployment_function_definition(
167
- function.model_dump(), display_context.client
168
- )
166
+ normalized_functions = compile_workflow_deployment_function_definition(function, display_context.client)
169
167
  else:
170
168
  raise ValueError(f"Unsupported function type: {type(function)}")
171
169
  return {
@@ -0,0 +1,78 @@
1
+ from vellum.workflows import BaseWorkflow
2
+ from vellum.workflows.nodes import BaseNode
3
+ from vellum.workflows.nodes.displayable.final_output_node import FinalOutputNode
4
+ from vellum.workflows.state.base import BaseState
5
+ from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
6
+
7
+
8
+ def test_final_output_node_display__serialize_with_valid_types():
9
+ # GIVEN a node that outputs a str
10
+ class StringNode(BaseNode):
11
+ class Outputs:
12
+ result: str
13
+
14
+ # AND a FinalOutputNode with matching type to that node
15
+ class CorrectOutput(FinalOutputNode[BaseState, str]):
16
+ class Outputs(FinalOutputNode.Outputs):
17
+ value = StringNode.Outputs.result
18
+
19
+ # AND a workflow referencing the node
20
+ class MyWorkflow(BaseWorkflow):
21
+ graph = StringNode >> CorrectOutput
22
+
23
+ class Outputs(BaseWorkflow.Outputs):
24
+ final_result = CorrectOutput.Outputs.value
25
+
26
+ # WHEN we serialize the workflow
27
+ workflow_display = get_workflow_display(workflow_class=MyWorkflow)
28
+
29
+ # THEN serialization should succeed without raising validation errors
30
+ serialized_workflow: dict = workflow_display.serialize()
31
+
32
+ # AND the node should be properly serialized
33
+ assert "workflow_raw_data" in serialized_workflow
34
+ assert "nodes" in serialized_workflow["workflow_raw_data"]
35
+
36
+ # Find the terminal node in the serialized output
37
+ terminal_node = next(
38
+ node for node in serialized_workflow["workflow_raw_data"]["nodes"] if node["type"] == "TERMINAL"
39
+ )
40
+ assert terminal_node is not None
41
+ assert terminal_node["id"] == str(CorrectOutput.__id__)
42
+
43
+
44
+ def test_final_output_node_display__serialize_with_invalid_types_should_raise_error():
45
+ # GIVEN a node that outputs a str
46
+ class StringNode(BaseNode):
47
+ class Outputs:
48
+ result: str
49
+
50
+ # AND a FinalOutputNode with mismatched types (expects list but gets str)
51
+ class BadOutput(FinalOutputNode[BaseState, list]):
52
+ """Output with type mismatch."""
53
+
54
+ class Outputs(FinalOutputNode.Outputs):
55
+ value = StringNode.Outputs.result # str type, conflicts with list
56
+
57
+ # AND a workflow referencing the node
58
+ class MyWorkflow(BaseWorkflow):
59
+ graph = StringNode >> BadOutput
60
+
61
+ class Outputs(BaseWorkflow.Outputs):
62
+ final_result = BadOutput.Outputs.value
63
+
64
+ # WHEN we attempt to serialize the workflow
65
+ workflow_display = get_workflow_display(workflow_class=MyWorkflow)
66
+
67
+ # THEN serialization should complete without raising an exception
68
+ serialized_workflow = workflow_display.serialize()
69
+
70
+ # AND the error should be captured in workflow_display.errors
71
+ errors = list(workflow_display.display_context.errors)
72
+ assert len(errors) == 1
73
+ assert "Output type mismatch" in str(errors[0])
74
+ assert "list" in str(errors[0])
75
+ assert "str" in str(errors[0])
76
+
77
+ # AND the serialized workflow should still be created
78
+ assert "workflow_raw_data" in serialized_workflow
@@ -437,6 +437,11 @@ def test_serialize_workflow():
437
437
  "name": "max_prompt_iterations",
438
438
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 5.0}},
439
439
  },
440
+ {
441
+ "id": "f92dc3ec-a19a-4491-a98a-2b2df322e2e3",
442
+ "name": "settings",
443
+ "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
444
+ },
440
445
  ],
441
446
  "outputs": [
442
447
  {"id": "e62bc785-a914-4066-b79e-8c89a5d0ec6c", "name": "text", "type": "STRING", "value": None},
@@ -206,6 +206,11 @@ def test_serialize_workflow():
206
206
  "name": "max_prompt_iterations",
207
207
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "NUMBER", "value": 5.0}},
208
208
  },
209
+ {
210
+ "id": "f92dc3ec-a19a-4491-a98a-2b2df322e2e3",
211
+ "name": "settings",
212
+ "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
213
+ },
209
214
  ],
210
215
  "outputs": [
211
216
  {"id": "e62bc785-a914-4066-b79e-8c89a5d0ec6c", "name": "text", "type": "STRING", "value": None},
@@ -62,6 +62,9 @@ class WorkflowDisplayContext:
62
62
 
63
63
  raise error
64
64
 
65
+ def add_validation_error(self, error: Exception) -> None:
66
+ self._errors.append(error)
67
+
65
68
  def add_invalid_node(self, node: Type[BaseNode]) -> None:
66
69
  """Track a node that failed to serialize."""
67
70
  if node not in self._invalid_nodes:
@@ -196,6 +196,12 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
196
196
  node_display = self.display_context.node_displays[node]
197
197
 
198
198
  try:
199
+ try:
200
+ node.__validate__()
201
+ except ValueError as validation_error:
202
+ # Only collect node validation errors directly to errors list, don't raise them
203
+ self.display_context.add_validation_error(validation_error)
204
+
199
205
  serialized_node = node_display.serialize(self.display_context)
200
206
  except (NotImplementedError, NodeValidationError) as e:
201
207
  self.display_context.add_error(e)