vellum-ai 1.7.1__py3-none-any.whl → 1.7.3__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.
@@ -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.7.1",
30
+ "User-Agent": "vellum-ai/1.7.3",
31
31
  "X-Fern-Language": "Python",
32
32
  "X-Fern-SDK-Name": "vellum-ai",
33
- "X-Fern-SDK-Version": "1.7.1",
33
+ "X-Fern-SDK-Version": "1.7.3",
34
34
  **(self.get_custom_headers() or {}),
35
35
  }
36
36
  if self._api_version is not None:
@@ -43,6 +43,7 @@ _VELLUM_ERROR_CODE_TO_WORKFLOW_ERROR_CODE: Dict[VellumErrorCodeEnum, WorkflowErr
43
43
  "INVALID_INPUTS": WorkflowErrorCode.INVALID_INPUTS,
44
44
  "PROVIDER_ERROR": WorkflowErrorCode.PROVIDER_ERROR,
45
45
  "PROVIDER_CREDENTIALS_UNAVAILABLE": WorkflowErrorCode.PROVIDER_CREDENTIALS_UNAVAILABLE,
46
+ "INTEGRATION_CREDENTIALS_UNAVAILABLE": WorkflowErrorCode.INTEGRATION_CREDENTIALS_UNAVAILABLE,
46
47
  "REQUEST_TIMEOUT": WorkflowErrorCode.PROVIDER_ERROR,
47
48
  "INTERNAL_SERVER_ERROR": WorkflowErrorCode.INTERNAL_ERROR,
48
49
  "USER_DEFINED_ERROR": WorkflowErrorCode.USER_DEFINED_ERROR,
@@ -95,7 +96,7 @@ _WORKFLOW_ERROR_CODE_TO_VELLUM_ERROR_CODE: Dict[WorkflowErrorCode, VellumErrorCo
95
96
  WorkflowErrorCode.NODE_EXECUTION: "USER_DEFINED_ERROR",
96
97
  WorkflowErrorCode.PROVIDER_ERROR: "PROVIDER_ERROR",
97
98
  WorkflowErrorCode.PROVIDER_CREDENTIALS_UNAVAILABLE: "PROVIDER_CREDENTIALS_UNAVAILABLE",
98
- WorkflowErrorCode.INTEGRATION_CREDENTIALS_UNAVAILABLE: "PROVIDER_CREDENTIALS_UNAVAILABLE",
99
+ WorkflowErrorCode.INTEGRATION_CREDENTIALS_UNAVAILABLE: "INTEGRATION_CREDENTIALS_UNAVAILABLE",
99
100
  WorkflowErrorCode.USER_DEFINED_ERROR: "USER_DEFINED_ERROR",
100
101
  WorkflowErrorCode.WORKFLOW_CANCELLED: "REQUEST_TIMEOUT",
101
102
  }
@@ -12,6 +12,7 @@ from vellum.workflows.types.definition import VellumIntegrationToolDetails
12
12
 
13
13
  def test_vellum_integration_service_get_tool_definition_success(vellum_client):
14
14
  """Test that tool definitions are successfully retrieved from Vellum API"""
15
+ # GIVEN a mock client configured to return a tool definition
15
16
  mock_client = vellum_client
16
17
  tool_definition_response = ComponentsSchemasComposioToolDefinition(
17
18
  integration=ToolDefinitionIntegration(
@@ -33,7 +34,6 @@ def test_vellum_integration_service_get_tool_definition_success(vellum_client):
33
34
  },
34
35
  output_parameters={},
35
36
  )
36
-
37
37
  mock_client.integrations.retrieve_integration_tool_definition.return_value = tool_definition_response
38
38
 
39
39
  # WHEN we request a tool definition
@@ -66,6 +66,7 @@ def test_vellum_integration_service_get_tool_definition_success(vellum_client):
66
66
 
67
67
  def test_vellum_integration_service_get_tool_definition_api_error(vellum_client):
68
68
  """Test that API errors are properly handled when retrieving tool definitions"""
69
+ # GIVEN a mock client configured to raise an exception
69
70
  mock_client = vellum_client
70
71
  mock_client.integrations = mock.MagicMock()
71
72
  mock_client.integrations.retrieve_integration_tool_definition.side_effect = Exception("Tool not found")
@@ -87,6 +88,7 @@ def test_vellum_integration_service_get_tool_definition_api_error(vellum_client)
87
88
 
88
89
  def test_vellum_integration_service_execute_tool_success(vellum_client):
89
90
  """Test that tools are successfully executed via Vellum API"""
91
+ # GIVEN a mock client configured to return a successful response
90
92
  mock_client = vellum_client
91
93
  mock_client.integrations = mock.MagicMock()
92
94
 
@@ -96,7 +98,6 @@ def test_vellum_integration_service_execute_tool_success(vellum_client):
96
98
  "issue_id": 123,
97
99
  "issue_url": "https://github.com/user/repo/issues/123",
98
100
  }
99
-
100
101
  mock_client.integrations.execute_integration_tool.return_value = mock_response
101
102
 
102
103
  # WHEN we execute a tool with valid arguments
@@ -132,6 +133,7 @@ def test_vellum_integration_service_execute_tool_success(vellum_client):
132
133
 
133
134
  def test_vellum_integration_service_execute_tool_api_error(vellum_client):
134
135
  """Test that execution errors are properly handled"""
136
+ # GIVEN a mock client configured to raise an exception
135
137
  mock_client = vellum_client
136
138
  mock_client.integrations = mock.MagicMock()
137
139
  mock_client.integrations.execute_integration_tool.side_effect = Exception("Authentication failed")
@@ -154,12 +156,12 @@ def test_vellum_integration_service_execute_tool_api_error(vellum_client):
154
156
 
155
157
  def test_vellum_integration_service_execute_tool_empty_response(vellum_client):
156
158
  """Test that empty response data is handled gracefully"""
159
+ # GIVEN a mock client configured to return an empty response
157
160
  mock_client = vellum_client
158
161
  mock_client.integrations = mock.MagicMock()
159
162
 
160
163
  mock_response = mock.MagicMock()
161
164
  mock_response.data = {}
162
-
163
165
  mock_client.integrations.execute_integration_tool.return_value = mock_response
164
166
 
165
167
  # WHEN we execute a tool that returns empty data
@@ -180,6 +182,7 @@ def test_vellum_integration_service_execute_tool_empty_response(vellum_client):
180
182
 
181
183
  def test_vellum_integration_service_multiple_tool_executions(vellum_client):
182
184
  """Test that the service handles multiple sequential tool executions"""
185
+ # GIVEN a mock client configured to return different responses for multiple calls
183
186
  mock_client = vellum_client
184
187
  mock_client.integrations = mock.MagicMock()
185
188
 
@@ -214,16 +217,18 @@ def test_vellum_integration_service_multiple_tool_executions(vellum_client):
214
217
  assert mock_client.integrations.execute_integration_tool.call_count == 2
215
218
 
216
219
 
217
- def test_vellum_integration_service_execute_tool_structured_403_error(vellum_client):
218
- """Test that structured 403 responses with integration details are properly parsed"""
220
+ def test_vellum_integration_service_execute_tool_structured_403_with_integration(vellum_client):
221
+ """Test structured 403 responses with integration field (current backend format)"""
219
222
  from vellum.client.core.api_error import ApiError
220
223
  from vellum.workflows.errors.types import WorkflowErrorCode
221
224
 
225
+ # GIVEN a mock client configured to raise a structured 403 error with integration
222
226
  mock_client = vellum_client
223
227
  mock_client.integrations = mock.MagicMock()
224
228
 
225
- # Mock structured 403 response matching PR #14857 format
229
+ # Mock current backend structure with integration as direct field
226
230
  structured_error_body = {
231
+ "code": "INTEGRATION_CREDENTIALS_UNAVAILABLE",
227
232
  "message": "You must authenticate with this integration before you can execute this tool.",
228
233
  "integration": {
229
234
  "id": "550e8400-e29b-41d4-a716-446655440000",
@@ -231,15 +236,13 @@ def test_vellum_integration_service_execute_tool_structured_403_error(vellum_cli
231
236
  "name": "GITHUB",
232
237
  },
233
238
  }
234
-
235
239
  mock_client.integrations.execute_integration_tool.side_effect = ApiError(
236
240
  status_code=403,
237
241
  body=structured_error_body,
238
242
  )
239
243
 
240
- service = VellumIntegrationService(client=mock_client)
241
-
242
244
  # WHEN we attempt to execute a tool without credentials
245
+ service = VellumIntegrationService(client=mock_client)
243
246
  with pytest.raises(NodeException) as exc_info:
244
247
  service.execute_tool(
245
248
  integration="GITHUB",
@@ -266,19 +269,18 @@ def test_vellum_integration_service_execute_tool_legacy_403_error(vellum_client)
266
269
  from vellum.client.core.api_error import ApiError
267
270
  from vellum.workflows.errors.types import WorkflowErrorCode
268
271
 
272
+ # GIVEN a mock client configured to raise a legacy 403 error
269
273
  mock_client = vellum_client
270
274
  mock_client.integrations = mock.MagicMock()
271
275
 
272
- # Mock legacy 403 response format (just detail field)
273
276
  legacy_error_body = {"detail": "You do not have permission to execute this tool."}
274
-
275
277
  mock_client.integrations.execute_integration_tool.side_effect = ApiError(
276
278
  status_code=403,
277
279
  body=legacy_error_body,
278
280
  )
279
281
 
282
+ # WHEN we attempt to execute a tool that returns a legacy 403 error
280
283
  service = VellumIntegrationService(client=mock_client)
281
-
282
284
  with pytest.raises(NodeException) as exc_info:
283
285
  service.execute_tool(
284
286
  integration="GITHUB",
@@ -95,15 +95,15 @@ class VellumIntegrationService:
95
95
  except ApiError as e:
96
96
  # Handle structured 403 credential error responses
97
97
  if e.status_code == 403 and isinstance(e.body, dict):
98
- if "integration" in e.body and "message" in e.body:
99
- integration_details = e.body["integration"]
100
- error_message = e.body["message"]
101
-
102
- # Keep integration details nested under "integration" key to keep raw_data raw
103
- # and allow for future expansion
104
- raw_data = {
105
- "integration": integration_details,
106
- }
98
+ # Check for backend structure with integration as direct field
99
+ integration_from_backend = e.body.get("integration")
100
+ if integration_from_backend:
101
+ error_message = e.body.get(
102
+ "message", "You must authenticate with this integration before you can execute this tool."
103
+ )
104
+
105
+ # Wrap integration in raw_data for frontend consumption
106
+ raw_data = {"integration": integration_from_backend}
107
107
 
108
108
  raise NodeException(
109
109
  message=error_message,
@@ -117,13 +117,7 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
117
117
  request_options=self.request_options,
118
118
  )
119
119
  except ApiError as e:
120
- if e.status_code == 400 and isinstance(e.body, dict) and "message" in e.body:
121
- raise NodeException(
122
- message=e.body["message"],
123
- code=WorkflowErrorCode.INVALID_INPUTS,
124
- )
125
-
126
- raise
120
+ self._handle_api_error(e)
127
121
 
128
122
  if code_execution_result.output.type != expected_output_type:
129
123
  actual_type = code_execution_result.output.type
@@ -134,6 +128,24 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
134
128
 
135
129
  return self.Outputs(result=code_execution_result.output.value, log=code_execution_result.log)
136
130
 
131
+ def _handle_api_error(self, e: ApiError) -> None:
132
+ if e.status_code and e.status_code == 403 and isinstance(e.body, dict):
133
+ raise NodeException(
134
+ message=e.body.get("detail", "Provider credentials is missing or unavailable"),
135
+ code=WorkflowErrorCode.PROVIDER_CREDENTIALS_UNAVAILABLE,
136
+ ) from e
137
+
138
+ if e.status_code and e.status_code >= 400 and e.status_code < 500 and isinstance(e.body, dict):
139
+ raise NodeException(
140
+ message=e.body.get("message", e.body.get("detail", "Failed to execute code")),
141
+ code=WorkflowErrorCode.INVALID_INPUTS,
142
+ ) from e
143
+
144
+ raise NodeException(
145
+ message="Failed to execute code",
146
+ code=WorkflowErrorCode.INTERNAL_ERROR,
147
+ ) from e
148
+
137
149
  def _has_secrets_in_code_inputs(self) -> bool:
138
150
  """Check if any code_inputs contain VellumSecret instances that require API execution."""
139
151
  for input_value in self.code_inputs.values():
@@ -6,7 +6,11 @@ from typing import Any, List, Union
6
6
  from pydantic import BaseModel
7
7
 
8
8
  from vellum import ArrayInput, CodeExecutorResponse, NumberVellumValue, StringInput, StringVellumValue
9
+ from vellum.client.core.api_error import ApiError
9
10
  from vellum.client.errors.bad_request_error import BadRequestError
11
+ from vellum.client.errors.forbidden_error import ForbiddenError
12
+ from vellum.client.errors.internal_server_error import InternalServerError
13
+ from vellum.client.errors.not_found_error import NotFoundError
10
14
  from vellum.client.types.chat_message import ChatMessage
11
15
  from vellum.client.types.code_execution_package import CodeExecutionPackage
12
16
  from vellum.client.types.code_executor_secret_input import CodeExecutorSecretInput
@@ -792,6 +796,103 @@ Node.js v21.7.3
792
796
  assert exc_info.value.message == message
793
797
 
794
798
 
799
+ def test_run_node__execute_code_api_fails_403__provider_credentials_unavailable(vellum_client):
800
+ """
801
+ Tests that a 403 error from the API is handled with PROVIDER_CREDENTIALS_UNAVAILABLE error code.
802
+ """
803
+
804
+ class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, str]):
805
+ code = "def main(): return 'test'"
806
+ runtime = "PYTHON_3_11_6"
807
+ packages = [CodeExecutionPackage(name="requests", version="2.28.0")]
808
+
809
+ vellum_client.execute_code.side_effect = ForbiddenError(
810
+ body={
811
+ "detail": "Provider credentials is missing or unavailable",
812
+ }
813
+ )
814
+
815
+ node = ExampleCodeExecutionNode()
816
+ with pytest.raises(NodeException) as exc_info:
817
+ node.run()
818
+
819
+ assert exc_info.value.code == WorkflowErrorCode.PROVIDER_CREDENTIALS_UNAVAILABLE
820
+ assert "Provider credentials is missing or unavailable" in exc_info.value.message
821
+
822
+
823
+ def test_run_node__execute_code_api_fails_404__invalid_inputs(vellum_client):
824
+ """
825
+ Tests that a 404 error from the API is handled with INVALID_INPUTS error code.
826
+ """
827
+
828
+ class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, str]):
829
+ code = "def main(): return 'test'"
830
+ runtime = "PYTHON_3_11_6"
831
+ packages = [CodeExecutionPackage(name="requests", version="2.28.0")]
832
+
833
+ vellum_client.execute_code.side_effect = NotFoundError(
834
+ body={
835
+ "detail": "Resource not found",
836
+ }
837
+ )
838
+
839
+ node = ExampleCodeExecutionNode()
840
+ with pytest.raises(NodeException) as exc_info:
841
+ node.run()
842
+
843
+ assert exc_info.value.code == WorkflowErrorCode.INVALID_INPUTS
844
+ assert "Resource not found" in exc_info.value.message
845
+
846
+
847
+ def test_run_node__execute_code_api_fails_500__internal_error(vellum_client):
848
+ """
849
+ Tests that a 500 error from the API is handled with INTERNAL_ERROR error code.
850
+ """
851
+
852
+ class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, str]):
853
+ code = "def main(): return 'test'"
854
+ runtime = "PYTHON_3_11_6"
855
+ packages = [CodeExecutionPackage(name="requests", version="2.28.0")]
856
+
857
+ vellum_client.execute_code.side_effect = InternalServerError(
858
+ body={
859
+ "detail": "Internal server error occurred",
860
+ }
861
+ )
862
+
863
+ node = ExampleCodeExecutionNode()
864
+ with pytest.raises(NodeException) as exc_info:
865
+ node.run()
866
+
867
+ assert exc_info.value.code == WorkflowErrorCode.INTERNAL_ERROR
868
+ assert exc_info.value.message == "Failed to execute code"
869
+
870
+
871
+ def test_run_node__execute_code_api_fails_4xx_no_message__uses_detail(vellum_client):
872
+ """
873
+ Tests that a 4xx error without a 'message' field falls back to 'detail' field.
874
+ """
875
+
876
+ class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, str]):
877
+ code = "def main(): return 'test'"
878
+ runtime = "PYTHON_3_11_6"
879
+ packages = [CodeExecutionPackage(name="requests", version="2.28.0")]
880
+
881
+ vellum_client.execute_code.side_effect = ApiError(
882
+ status_code=422,
883
+ body={
884
+ "detail": "Invalid request parameters",
885
+ },
886
+ )
887
+
888
+ node = ExampleCodeExecutionNode()
889
+ with pytest.raises(NodeException) as exc_info:
890
+ node.run()
891
+
892
+ assert exc_info.value.code == WorkflowErrorCode.INVALID_INPUTS
893
+ assert "Invalid request parameters" in exc_info.value.message
894
+
895
+
795
896
  def test_run_node__execute_code__list_extends():
796
897
  # GIVEN a node that will return a list with output type Json
797
898
  class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, Json]):
@@ -22,8 +22,8 @@ from vellum.workflows.nodes.displayable.tool_calling_node.utils import (
22
22
  )
23
23
  from vellum.workflows.outputs.base import BaseOutput, BaseOutputs
24
24
  from vellum.workflows.state.context import WorkflowContext
25
- from vellum.workflows.types.core import EntityInputsInterface, Tool
26
- from vellum.workflows.types.definition import MCPServer
25
+ from vellum.workflows.types.core import EntityInputsInterface
26
+ from vellum.workflows.types.definition import MCPServer, Tool
27
27
  from vellum.workflows.types.generics import StateType
28
28
  from vellum.workflows.utils.functions import compile_mcp_tool_definition, get_mcp_tool_name
29
29
  from vellum.workflows.workflows.event_filters import all_workflow_event_filter
@@ -24,6 +24,7 @@ from vellum.workflows.nodes.displayable.tool_calling_node.utils import (
24
24
  create_tool_prompt_node,
25
25
  )
26
26
  from vellum.workflows.outputs.base import BaseOutputs
27
+ from vellum.workflows.ports.utils import validate_ports
27
28
  from vellum.workflows.state.base import BaseState, StateMeta
28
29
  from vellum.workflows.state.context import WorkflowContext
29
30
  from vellum.workflows.types.definition import DeploymentDefinition
@@ -38,6 +39,55 @@ def second_function() -> str:
38
39
  return "second_function"
39
40
 
40
41
 
42
+ def test_router_node_port_ordering_with_multiple_tools():
43
+ """
44
+ Test that router node ports are created in the correct order: on_if, on_elif, ..., on_else.
45
+
46
+ This test validates the fix for the bug where multiple tools would create multiple on_if
47
+ ports instead of on_if followed by on_elif ports, which violates port validation rules.
48
+ """
49
+
50
+ # GIVEN three functions to ensure we test multiple elif cases
51
+ def third_function() -> str:
52
+ return "third_function"
53
+
54
+ # AND a tool prompt node
55
+ tool_prompt_node = create_tool_prompt_node(
56
+ ml_model="test-model",
57
+ blocks=[],
58
+ functions=[first_function, second_function, third_function],
59
+ prompt_inputs=None,
60
+ parameters=DEFAULT_PROMPT_PARAMETERS,
61
+ )
62
+
63
+ # WHEN a router node is created with multiple functions
64
+ router_node = create_router_node(
65
+ functions=[first_function, second_function, third_function],
66
+ tool_prompt_node=tool_prompt_node,
67
+ )
68
+
69
+ # THEN the first function port should be an on_if port
70
+ first_function_port = getattr(router_node.Ports, "first_function")
71
+ assert first_function_port._condition_type.value == "IF"
72
+
73
+ # AND the second function port should be an on_elif port
74
+ second_function_port = getattr(router_node.Ports, "second_function")
75
+ assert second_function_port._condition_type.value == "ELIF"
76
+
77
+ # AND the third function port should also be an on_elif port
78
+ third_function_port = getattr(router_node.Ports, "third_function")
79
+ assert third_function_port._condition_type.value == "ELIF"
80
+
81
+ # AND the default port should be an on_else port
82
+ default_port = getattr(router_node.Ports, "default")
83
+ assert default_port._condition_type.value == "ELSE"
84
+
85
+ # AND the ports should pass validation
86
+ ports = [first_function_port, second_function_port, third_function_port, default_port]
87
+ # This should not raise an exception
88
+ validate_ports(ports)
89
+
90
+
41
91
  def test_port_condition_match_function_name():
42
92
  """
43
93
  Test that the port condition correctly matches the function name.
@@ -31,12 +31,14 @@ from vellum.workflows.outputs.base import BaseOutput
31
31
  from vellum.workflows.ports.port import Port
32
32
  from vellum.workflows.state import BaseState
33
33
  from vellum.workflows.state.encoder import DefaultStateEncoder
34
- from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior, Tool, ToolBase
34
+ from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior
35
35
  from vellum.workflows.types.definition import (
36
36
  ComposioToolDefinition,
37
37
  DeploymentDefinition,
38
38
  MCPServer,
39
39
  MCPToolDefinition,
40
+ Tool,
41
+ ToolBase,
40
42
  VellumIntegrationToolDefinition,
41
43
  )
42
44
  from vellum.workflows.types.generics import is_workflow_class
@@ -203,7 +205,7 @@ class FunctionNode(BaseNode[ToolCallingState], FunctionCallNodeMixin):
203
205
  raise NodeException(
204
206
  message=f"Error executing function '{function_name}': {str(e)}",
205
207
  code=WorkflowErrorCode.NODE_EXECUTION,
206
- )
208
+ ) from e
207
209
 
208
210
  # Add the result to the chat history
209
211
  self._add_function_result_to_chat_history(result, self.state)
@@ -233,7 +235,7 @@ class ComposioNode(BaseNode[ToolCallingState], FunctionCallNodeMixin):
233
235
  raise NodeException(
234
236
  message=f"Error executing Composio tool '{self.composio_tool.action}': {str(e)}",
235
237
  code=WorkflowErrorCode.NODE_EXECUTION,
236
- )
238
+ ) from e
237
239
 
238
240
  # Add result to chat history
239
241
  self._add_function_result_to_chat_history(result, self.state)
@@ -256,7 +258,7 @@ class MCPNode(BaseNode[ToolCallingState], FunctionCallNodeMixin):
256
258
  raise NodeException(
257
259
  message=f"Error executing MCP tool '{self.mcp_tool.name}': {str(e)}",
258
260
  code=WorkflowErrorCode.NODE_EXECUTION,
259
- )
261
+ ) from e
260
262
 
261
263
  # Add result to chat history
262
264
  self._add_function_result_to_chat_history(result, self.state)
@@ -281,11 +283,18 @@ class VellumIntegrationNode(BaseNode[ToolCallingState], FunctionCallNodeMixin):
281
283
  tool_name=self.vellum_integration_tool.name,
282
284
  arguments=arguments,
283
285
  )
286
+ except NodeException as e:
287
+ # Preserve original error code and raw_data while adding context
288
+ raise NodeException(
289
+ message=f"Error executing Vellum Integration tool '{self.vellum_integration_tool.name}': {e.message}",
290
+ code=e.code,
291
+ raw_data=e.raw_data,
292
+ ) from e
284
293
  except Exception as e:
285
294
  raise NodeException(
286
295
  message=f"Error executing Vellum Integration tool '{self.vellum_integration_tool.name}': {str(e)}",
287
296
  code=WorkflowErrorCode.NODE_EXECUTION,
288
- )
297
+ ) from e
289
298
 
290
299
  # Add result to chat history
291
300
  self._add_function_result_to_chat_history(result, self.state)
@@ -400,8 +409,8 @@ def create_router_node(
400
409
  # Avoid using lambda to capture function_name
401
410
  # lambda will capture the function_name by reference,
402
411
  # and if the function_name is changed, the port_condition will also change.
403
- def create_port_condition(fn_name):
404
- return Port.on_if(
412
+ def create_port_condition(fn_name, is_first):
413
+ condition = (
405
414
  ToolCallingState.current_prompt_output_index.less_than(tool_prompt_node.Outputs.results.length())
406
415
  & tool_prompt_node.Outputs.results[ToolCallingState.current_prompt_output_index]["type"].equals(
407
416
  "FUNCTION_CALL"
@@ -410,26 +419,33 @@ def create_router_node(
410
419
  "name"
411
420
  ].equals(fn_name)
412
421
  )
422
+ # First port should be on_if, subsequent ports should be on_elif
423
+ return Port.on_if(condition) if is_first else Port.on_elif(condition)
413
424
 
425
+ is_first_port = True
414
426
  for function in functions:
415
427
  if isinstance(function, ComposioToolDefinition):
416
428
  function_name = get_function_name(function)
417
- port = create_port_condition(function_name)
429
+ port = create_port_condition(function_name, is_first_port)
418
430
  setattr(Ports, function_name, port)
431
+ is_first_port = False
419
432
  elif isinstance(function, VellumIntegrationToolDefinition):
420
433
  function_name = get_function_name(function)
421
- port = create_port_condition(function_name)
434
+ port = create_port_condition(function_name, is_first_port)
422
435
  setattr(Ports, function_name, port)
436
+ is_first_port = False
423
437
  elif isinstance(function, MCPServer):
424
438
  tool_functions: List[MCPToolDefinition] = compile_mcp_tool_definition(function)
425
439
  for tool_function in tool_functions:
426
440
  name = get_mcp_tool_name(tool_function)
427
- port = create_port_condition(name)
441
+ port = create_port_condition(name, is_first_port)
428
442
  setattr(Ports, name, port)
443
+ is_first_port = False
429
444
  else:
430
445
  function_name = get_function_name(function)
431
- port = create_port_condition(function_name)
446
+ port = create_port_condition(function_name, is_first_port)
432
447
  setattr(Ports, function_name, port)
448
+ is_first_port = False
433
449
 
434
450
  # Add the else port for when no function conditions match
435
451
  setattr(Ports, "default", Port.on_else())
@@ -52,15 +52,6 @@ class VellumResolver(BaseWorkflowResolver):
52
52
  if response.state is None:
53
53
  return None
54
54
 
55
- if (
56
- response.previous_trace_id is None
57
- or response.root_trace_id is None
58
- or response.previous_span_id is None
59
- or response.root_span_id is None
60
- ):
61
- logger.warning("Could not find required execution events for state loading")
62
- return None
63
-
64
55
  if "meta" in response.state:
65
56
  response.state.pop("meta")
66
57
 
@@ -71,6 +62,20 @@ class VellumResolver(BaseWorkflowResolver):
71
62
  logger.warning("No workflow class registered, falling back to BaseState")
72
63
  state = BaseState(**response.state)
73
64
 
65
+ if (
66
+ response.previous_trace_id is None
67
+ or response.root_trace_id is None
68
+ or response.previous_span_id is None
69
+ or response.root_span_id is None
70
+ ):
71
+ return LoadStateResult(
72
+ state=state,
73
+ previous_trace_id=response.trace_id,
74
+ previous_span_id=response.span_id,
75
+ root_trace_id=response.trace_id,
76
+ root_span_id=response.span_id,
77
+ )
78
+
74
79
  return LoadStateResult(
75
80
  state=state,
76
81
  previous_trace_id=response.previous_trace_id,
@@ -695,6 +695,34 @@ class WorkflowRunner(Generic[StateType]):
695
695
 
696
696
  return None
697
697
 
698
+ def _emit_node_cancellation_events(
699
+ self,
700
+ error_message: str,
701
+ parent_context: Optional[ParentContext],
702
+ ) -> None:
703
+ """
704
+ Emit node cancellation events for all active nodes.
705
+
706
+ Args:
707
+ error_message: The error message to include in the cancellation events
708
+ parent_context: The parent context for the cancellation events
709
+ """
710
+ for span_id, active_node in list(self._active_nodes_by_execution_id.items()):
711
+ rejection_event = NodeExecutionRejectedEvent(
712
+ trace_id=self._execution_context.trace_id,
713
+ span_id=span_id,
714
+ body=NodeExecutionRejectedBody(
715
+ node_definition=active_node.node.__class__,
716
+ error=WorkflowError(
717
+ code=WorkflowErrorCode.NODE_CANCELLED,
718
+ message=error_message,
719
+ ),
720
+ ),
721
+ parent=parent_context,
722
+ )
723
+ self._workflow_event_outer_queue.put(rejection_event)
724
+ self._active_nodes_by_execution_id.pop(span_id)
725
+
698
726
  def _initiate_workflow_event(self) -> WorkflowExecutionInitiatedEvent:
699
727
  links: Optional[List[SpanLink]] = None
700
728
 
@@ -848,21 +876,10 @@ class WorkflowRunner(Generic[StateType]):
848
876
 
849
877
  if rejection_event:
850
878
  failed_node_name = rejection_event.body.node_definition.__name__
851
- for active_span_id, active_node_data in list(self._active_nodes_by_execution_id.items()):
852
- cancellation_event = NodeExecutionRejectedEvent(
853
- trace_id=self._execution_context.trace_id,
854
- span_id=active_span_id,
855
- body=NodeExecutionRejectedBody(
856
- node_definition=active_node_data.node.__class__,
857
- error=WorkflowError(
858
- message=f"Node execution cancelled due to {failed_node_name} failure",
859
- code=WorkflowErrorCode.NODE_CANCELLED,
860
- ),
861
- ),
862
- parent=self._execution_context.parent_context,
863
- )
864
- self._workflow_event_outer_queue.put(cancellation_event)
865
- self._active_nodes_by_execution_id.pop(active_span_id)
879
+ self._emit_node_cancellation_events(
880
+ error_message=f"Node execution cancelled due to {failed_node_name} failure",
881
+ parent_context=self._execution_context.parent_context,
882
+ )
866
883
  break
867
884
 
868
885
  # Handle any remaining events
@@ -932,6 +949,17 @@ class WorkflowRunner(Generic[StateType]):
932
949
 
933
950
  while not kill_switch.wait(timeout=0.1):
934
951
  if self._cancel_signal.is_set():
952
+ parent_context = WorkflowParentContext(
953
+ span_id=self._initial_state.meta.span_id,
954
+ workflow_definition=self.workflow.__class__,
955
+ parent=self._execution_context.parent_context,
956
+ )
957
+
958
+ self._emit_node_cancellation_events(
959
+ error_message="Workflow run cancelled",
960
+ parent_context=parent_context,
961
+ )
962
+
935
963
  self._workflow_event_outer_queue.put(
936
964
  self._reject_workflow_event(
937
965
  WorkflowError(
@@ -442,14 +442,24 @@ class StateMeta(UniversalBaseModel):
442
442
  if not memo:
443
443
  memo = {}
444
444
 
445
+ node_output_keys = list(self.node_outputs.keys())
445
446
  new_node_outputs = {
446
- descriptor: value if isinstance(value, Queue) else deepcopy(value, memo)
447
- for descriptor, value in self.node_outputs.items()
447
+ descriptor: (
448
+ self.node_outputs[descriptor]
449
+ if isinstance(self.node_outputs[descriptor], Queue)
450
+ else deepcopy(self.node_outputs[descriptor], memo)
451
+ )
452
+ for descriptor in node_output_keys
448
453
  }
449
454
 
455
+ external_input_keys = list(self.external_inputs.keys())
450
456
  new_external_inputs = {
451
- descriptor: value if isinstance(value, Queue) else deepcopy(value, memo)
452
- for descriptor, value in self.external_inputs.items()
457
+ descriptor: (
458
+ self.external_inputs[descriptor]
459
+ if isinstance(self.external_inputs[descriptor], Queue)
460
+ else deepcopy(self.external_inputs[descriptor], memo)
461
+ )
462
+ for descriptor in external_input_keys
453
463
  }
454
464
 
455
465
  memo[id(self.node_outputs)] = new_node_outputs
@@ -1,5 +1,6 @@
1
- from .core import MergeBehavior
1
+ from .core import CancelSignal, MergeBehavior
2
2
 
3
3
  __all__ = [
4
+ "CancelSignal",
4
5
  "MergeBehavior",
5
6
  ]
@@ -1,11 +1,9 @@
1
1
  from enum import Enum
2
+ from threading import Event as ThreadingEvent
2
3
  from typing import ( # type: ignore[attr-defined]
3
- TYPE_CHECKING,
4
4
  Any,
5
- Callable,
6
5
  Dict,
7
6
  List,
8
- Type,
9
7
  Union,
10
8
  _GenericAlias,
11
9
  _SpecialGenericAlias,
@@ -13,21 +11,13 @@ from typing import ( # type: ignore[attr-defined]
13
11
  )
14
12
 
15
13
  from vellum.client.core.pydantic_utilities import UniversalBaseModel
16
- from vellum.workflows.types.definition import (
17
- ComposioToolDefinition,
18
- DeploymentDefinition,
19
- MCPServer,
20
- VellumIntegrationToolDefinition,
21
- )
22
-
23
- if TYPE_CHECKING:
24
- from vellum.workflows.workflows.base import BaseWorkflow
25
-
26
14
 
27
15
  JsonArray = List["Json"]
28
16
  JsonObject = Dict[str, "Json"]
29
17
  Json = Union[None, bool, int, float, str, JsonArray, JsonObject]
30
18
 
19
+ CancelSignal = ThreadingEvent
20
+
31
21
  # Unions and Generics inherit from `_GenericAlias` instead of `type`
32
22
  # In future versions of python, we'll see `_UnionGenericAlias`
33
23
  UnderGenericAlias = _GenericAlias
@@ -53,14 +43,3 @@ class ConditionType(Enum):
53
43
  IF = "IF"
54
44
  ELIF = "ELIF"
55
45
  ELSE = "ELSE"
56
-
57
-
58
- # Type alias for functions that can be called in tool calling nodes
59
- ToolBase = Union[
60
- Callable[..., Any],
61
- DeploymentDefinition,
62
- Type["BaseWorkflow"],
63
- ComposioToolDefinition,
64
- VellumIntegrationToolDefinition,
65
- ]
66
- Tool = Union[ToolBase, MCPServer]
@@ -2,7 +2,7 @@ import importlib
2
2
  import inspect
3
3
  from types import FrameType
4
4
  from uuid import UUID
5
- from typing import Annotated, Any, Dict, List, Literal, Optional, Union
5
+ from typing import TYPE_CHECKING, Annotated, Any, Callable, Dict, List, Literal, Optional, Type, Union
6
6
 
7
7
  from pydantic import BeforeValidator, SerializationInfo, model_serializer
8
8
 
@@ -13,6 +13,9 @@ from vellum.client.types.vellum_variable import VellumVariable
13
13
  from vellum.workflows.constants import AuthorizationType, VellumIntegrationProviderType
14
14
  from vellum.workflows.references.environment_variable import EnvironmentVariableReference
15
15
 
16
+ if TYPE_CHECKING:
17
+ from vellum.workflows.workflows.base import BaseWorkflow
18
+
16
19
 
17
20
  def serialize_type_encoder(obj: type) -> Dict[str, Any]:
18
21
  return {
@@ -216,3 +219,14 @@ class MCPToolDefinition(UniversalBaseModel):
216
219
  server: MCPServer
217
220
  description: Optional[str] = None
218
221
  parameters: Dict[str, Any] = {}
222
+
223
+
224
+ # Type alias for functions that can be called in tool calling nodes
225
+ ToolBase = Union[
226
+ Callable[..., Any],
227
+ DeploymentDefinition,
228
+ Type["BaseWorkflow"],
229
+ ComposioToolDefinition,
230
+ VellumIntegrationToolDefinition,
231
+ ]
232
+ Tool = Union[ToolBase, MCPServer]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 1.7.1
3
+ Version: 1.7.3
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0
@@ -160,7 +160,7 @@ vellum/client/README.md,sha256=flqu57ubZNTfpq60CdLtJC9gp4WEkyjb_n_eZ4OYf9w,6497
160
160
  vellum/client/__init__.py,sha256=rMnKRqL5-356SBc-rfm56MkO87PuAi2mtcfBszcJU1M,74316
161
161
  vellum/client/core/__init__.py,sha256=lTcqUPXcx4112yLDd70RAPeqq6tu3eFMe1pKOqkW9JQ,1562
162
162
  vellum/client/core/api_error.py,sha256=44vPoTyWN59gonCIZMdzw7M1uspygiLnr3GNFOoVL2Q,614
163
- vellum/client/core/client_wrapper.py,sha256=9h4pM282vdjaHkk3Un2KTjxOCDbg7xu7r__5qwxzPZ8,2840
163
+ vellum/client/core/client_wrapper.py,sha256=_OdpOQxXZT7UdFB0twb2X_9YF8z4xjZfVD-9hV_mXao,2840
164
164
  vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
165
165
  vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
166
166
  vellum/client/core/force_multipart.py,sha256=awxh5MtcRYe74ehY8U76jzv6fYM_w_D3Rur7KQQzSDk,429
@@ -1804,7 +1804,7 @@ vellum/workflows/emitters/vellum_emitter.py,sha256=t4ixrN0NNXrydMP9PVKYvcOMxoMqs
1804
1804
  vellum/workflows/environment/__init__.py,sha256=TJz0m9dwIs6YOwCTeuN0HHsU-ecyjc1OJXx4AFy83EQ,121
1805
1805
  vellum/workflows/environment/environment.py,sha256=Ck3RPKXJvtMGx_toqYQQQF-ZwXm5ijVwJpEPTeIJ4_Q,471
1806
1806
  vellum/workflows/errors/__init__.py,sha256=tWGPu5xyAU8gRb8_bl0fL7OfU3wxQ9UH6qVwy4X4P_Q,113
1807
- vellum/workflows/errors/types.py,sha256=dmIYCJl2OdQnU5CW_fgKcQy7tERAeddLQ1FSp7gIKeA,4541
1807
+ vellum/workflows/errors/types.py,sha256=AW1lkWeC2MlAHf-N-KcYiyiWa0IKhVD_N2WSqFyY3-s,4642
1808
1808
  vellum/workflows/events/__init__.py,sha256=V4mh766fyA70WvHelm9kfVZGrUgEKcJ9tJt8EepfQYU,832
1809
1809
  vellum/workflows/events/context.py,sha256=vCfMIPmz4j9Om36rRWa35A_JU_VccWWS52_mZkkqxak,3345
1810
1810
  vellum/workflows/events/exception_handling.py,sha256=2okFtCzrOzaCP-HEwBPMvHn-evlyyE1zRkmIYjR__jQ,1975
@@ -1876,8 +1876,8 @@ vellum/workflows/integrations/composio_service.py,sha256=rSliaZtNiBcDSvDxz9k5i1K
1876
1876
  vellum/workflows/integrations/mcp_service.py,sha256=9DYb8dg2_kgc1UOu830kxhaFlt9yTbhKPhK3L6kb1t4,9831
1877
1877
  vellum/workflows/integrations/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1878
1878
  vellum/workflows/integrations/tests/test_mcp_service.py,sha256=q_DYrDkIqI4sQBNgID4YdbM4e9tneLVWY8YmI4R26d8,8859
1879
- vellum/workflows/integrations/tests/test_vellum_integration_service.py,sha256=n_n42FnwbR7YMd1sEVMphdOUWsWXCPw_caY6FnxNxAU,11322
1880
- vellum/workflows/integrations/vellum_integration_service.py,sha256=JFkrXBhkTEn_tXnRbjt289Z56_SLDSsuU7Msx2Nh9AM,5192
1879
+ vellum/workflows/integrations/tests/test_vellum_integration_service.py,sha256=QGJmaW5EF7E2fkZotd4rc2HItQc-1z3cpgwaKUFWpgg,11956
1880
+ vellum/workflows/integrations/vellum_integration_service.py,sha256=qhFoLzHlMli1PC8oh5phvWuSpJ9IqL1g2eaGhypBTqs,5266
1881
1881
  vellum/workflows/logging.py,sha256=_a217XogktV4Ncz6xKFz7WfYmZAzkfVRVuC0rWob8ls,437
1882
1882
  vellum/workflows/nodes/__init__.py,sha256=zymtc3_iW2rFmMR-sayTLuN6ZsAw8VnJweWPsjQk2-Q,1197
1883
1883
  vellum/workflows/nodes/bases/__init__.py,sha256=cniHuz_RXdJ4TQgD8CBzoiKDiPxg62ErdVpCbWICX64,58
@@ -1931,11 +1931,11 @@ vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMD
1931
1931
  vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
1932
1932
  vellum/workflows/nodes/displayable/bases/utils.py,sha256=X1YSPmbBlxDrTAw6dy2-9HrIG8Vb_J-2k1lP3i-SOsk,6951
1933
1933
  vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
1934
- vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=t4AuqyGOSgitYUUs6Tqzo7lDeyOyJ5g8x7Q9j4UkH7M,10426
1934
+ vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=JkJ_p9KKmrkUqc8TPcxfPoZ1AiEnWWwrdzLj-0TS9ds,10985
1935
1935
  vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1936
1936
  vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1937
1937
  vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
1938
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py,sha256=RQy7SsA39kTJAudzpYNN3jK_kuq6bWNZUld54H5pRZA,40966
1938
+ vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py,sha256=eCWBaAPzneDiOQe1xFyyb9h9LeQQOAdjRY1RJS0z8sE,44500
1939
1939
  vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=0F_4PVvB7vjsV0RS48Brv_4djebWOMR_zgzHxzA9iV4,3308
1940
1940
  vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
1941
1941
  vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=2g32hWosE3zwVaK2UPFnVEer1Nbn04s3friF2rGztmE,1195
@@ -1975,13 +1975,13 @@ vellum/workflows/nodes/displayable/tests/test_search_node_error_handling.py,sha2
1975
1975
  vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py,sha256=VepO5z1277c1y5N6LLIC31nnWD1aak2m5oPFplfJHHs,6935
1976
1976
  vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py,sha256=Bjv-wZyFgNaVZb9KEMMZd9lFoLzbPEPjEMpANizMZw4,2413
1977
1977
  vellum/workflows/nodes/displayable/tool_calling_node/__init__.py,sha256=3n0-ysmFKsr40CVxPthc0rfJgqVJeZuUEsCmYudLVRg,117
1978
- vellum/workflows/nodes/displayable/tool_calling_node/node.py,sha256=RxwBjNMmpRBu2G6fnu37MvqRVxa7ZQzOPtqccCYlCqI,8420
1978
+ vellum/workflows/nodes/displayable/tool_calling_node/node.py,sha256=pwK9q1blgRv9Mz_LY-fv_hxHfOOkuKxJ6AgRlorUrXk,8420
1979
1979
  vellum/workflows/nodes/displayable/tool_calling_node/state.py,sha256=CcBVb_YtwfSSka4ze678k6-qwmzMSfjfVP8_Y95feSo,302
1980
1980
  vellum/workflows/nodes/displayable/tool_calling_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1981
1981
  vellum/workflows/nodes/displayable/tool_calling_node/tests/test_composio_service.py,sha256=in1fbEz5x1tx3uKv9YXdvOncsHucNL8Ro6Go7lBuuOQ,8962
1982
- vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py,sha256=GZoeybB9uM7ai8sBLAtUMHrMVgh-WrJDWrKZci6feDs,11892
1982
+ vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py,sha256=Idjtlly6GTotNa4isXJ23RxKzQA2oE10MOm793aipLA,13892
1983
1983
  vellum/workflows/nodes/displayable/tool_calling_node/tests/test_utils.py,sha256=EmKFA-ELdTzlK0xMqWnuSZPoGNLYCwk6b0amTqirZo0,11305
1984
- vellum/workflows/nodes/displayable/tool_calling_node/utils.py,sha256=7xNiNPD4vzd-4NuIaeCZhs0AshkuxlWVdx1NnbX-fdg,23722
1984
+ vellum/workflows/nodes/displayable/tool_calling_node/utils.py,sha256=yIo7xwI43M8wQO8UN4uYxWBWafgcC9e8Ucsp6PZDva4,24518
1985
1985
  vellum/workflows/nodes/displayable/web_search_node/__init__.py,sha256=8FOnEP-n-U68cvxTlJW9wphIAGHq5aqjzLM-DoSSXnU,61
1986
1986
  vellum/workflows/nodes/displayable/web_search_node/node.py,sha256=NQYux2bOtuBF5E4tn-fXi5y3btURPRrNqMSM9MAZYI4,5091
1987
1987
  vellum/workflows/nodes/displayable/web_search_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -2017,14 +2017,14 @@ vellum/workflows/references/vellum_secret.py,sha256=Od4d19a5yletWMqNfJR5d_mZQUkV
2017
2017
  vellum/workflows/references/workflow_input.py,sha256=W3rOK1EPd2gYHb04WJwmNm1CUSdvZ9LKrs8RMKxACBs,1751
2018
2018
  vellum/workflows/resolvers/__init__.py,sha256=eH6hTvZO4IciDaf_cf7aM2vs-DkBDyJPycOQevJxQnI,82
2019
2019
  vellum/workflows/resolvers/base.py,sha256=wrQiSC02Bw4-dBwgFjJIHsjpe-4xz4rUJs_1RdErKA0,1164
2020
- vellum/workflows/resolvers/resolver.py,sha256=EIIiA2OlaVUPiKiSh6egQZxPA6ny1GDMdPq1AuN-mV8,2961
2020
+ vellum/workflows/resolvers/resolver.py,sha256=3uEYscB_2PHTazc0Y9SzOe_yiQZhVLfey19hU1HzBaU,3127
2021
2021
  vellum/workflows/resolvers/tests/test_resolver.py,sha256=PnUGzsulo1It_LjjhHsRNiILvvl5G_IaK8ZX56zKC28,6204
2022
2022
  vellum/workflows/resolvers/types.py,sha256=Hndhlk69g6EKLh_LYg5ILepW5U_h_BYNllfzhS9k8p4,237
2023
2023
  vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8vyT-bqM,72
2024
- vellum/workflows/runner/runner.py,sha256=rwMZlQBkzK-EfewC6OysNCeuDeTCfpNuzaUlgYoFJMw,43329
2024
+ vellum/workflows/runner/runner.py,sha256=NWmjGn8Unv3GjA-DF6e7sAEJhZptWqYqNOohZ4gy8Ko,44199
2025
2025
  vellum/workflows/sandbox.py,sha256=mezSZmilR_fwR8164n8CEfzlMeQ55IqfapHp4ftImvQ,3212
2026
2026
  vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
2027
- vellum/workflows/state/base.py,sha256=m9fCqbZn21GshCVCjJTD1dPZEQjFrsMXqlg7tM9fIwM,24283
2027
+ vellum/workflows/state/base.py,sha256=A8s0PC8UvFjPpkHDY6u-yIeb2KHjoAmu-GW-GYrDl0E,24654
2028
2028
  vellum/workflows/state/context.py,sha256=khM30U1iDNts5Xp8LXa_WfpkITNITexrDUUFJ5wZ2W4,8445
2029
2029
  vellum/workflows/state/delta.py,sha256=7h8wR10lRCm15SykaPj-gSEvvsMjCwYLPsOx3nsvBQg,440
2030
2030
  vellum/workflows/state/encoder.py,sha256=EynuS9aCt9Neb-H6HRCinEVZX5olCzME03W1TSXfpxs,1961
@@ -2035,10 +2035,10 @@ vellum/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
2035
2035
  vellum/workflows/tests/test_dataset_row.py,sha256=S8aIiYU9TRzJ8GTl5qCjnJ-fuHdxatHJFGLlKTVHPr4,4174
2036
2036
  vellum/workflows/tests/test_sandbox.py,sha256=JKwaluI-lODQo7Ek9sjDstjL_WTdSqUlVik6ZVTfVOA,1826
2037
2037
  vellum/workflows/tests/test_undefined.py,sha256=zMCVliCXVNLrlC6hEGyOWDnQADJ2g83yc5FIM33zuo8,353
2038
- vellum/workflows/types/__init__.py,sha256=KxUTMBGzuRCfiMqzzsykOeVvrrkaZmTTo1a7SLu8gRM,68
2038
+ vellum/workflows/types/__init__.py,sha256=fZ3Xxly7YSsu4kCIYD5aYpYucNM97zTyInb9CA24mf0,102
2039
2039
  vellum/workflows/types/code_execution_node_wrappers.py,sha256=fewX9bqF_4TZuK-gZYIn12s31-k03vHMGRpvFAPm11Y,3206
2040
- vellum/workflows/types/core.py,sha256=yKm3sE02ult969q80DTmawiwYqodVjcAW-zlaUIgIv4,1495
2041
- vellum/workflows/types/definition.py,sha256=PWJF1SAopdOZcLcxz1ZtGYOa0oH0-dxjFaa_tuGb6SI,7682
2040
+ vellum/workflows/types/core.py,sha256=B8d5spKNlHfXu5sWo72Jl1l1IOYdHaKGqgEr_lvBUqA,1027
2041
+ vellum/workflows/types/definition.py,sha256=Qof2MAjSNB0AN2XkSKmk-owuY59YcxDVHYpno6-StPA,8058
2042
2042
  vellum/workflows/types/generics.py,sha256=8jptbEx1fnJV0Lhj0MpCJOT6yNiEWeTOYOwrEAb5CRU,1576
2043
2043
  vellum/workflows/types/stack.py,sha256=h7NE0vXR7l9DevFBIzIAk1Zh59K-kECQtDTKOUunwMY,1314
2044
2044
  vellum/workflows/types/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -2065,8 +2065,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
2065
2065
  vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2066
2066
  vellum/workflows/workflows/tests/test_base_workflow.py,sha256=Boa-_m9ii2Qsa1RvVM-VYniF7zCpzGgEGy-OnPZkrHg,23941
2067
2067
  vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
2068
- vellum_ai-1.7.1.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
2069
- vellum_ai-1.7.1.dist-info/METADATA,sha256=M80DXrz0TQVVr0BUKSFDyCqBpCHtXk3_c4M6vTqK-eQ,5547
2070
- vellum_ai-1.7.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
2071
- vellum_ai-1.7.1.dist-info/entry_points.txt,sha256=xVavzAKN4iF_NbmhWOlOkHluka0YLkbN_pFQ9pW3gLI,117
2072
- vellum_ai-1.7.1.dist-info/RECORD,,
2068
+ vellum_ai-1.7.3.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
2069
+ vellum_ai-1.7.3.dist-info/METADATA,sha256=CeGDMnbsse5v1VkYVs8u9mZ7GzXcny1eQ_J5GBNOZwg,5547
2070
+ vellum_ai-1.7.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
2071
+ vellum_ai-1.7.3.dist-info/entry_points.txt,sha256=xVavzAKN4iF_NbmhWOlOkHluka0YLkbN_pFQ9pW3gLI,117
2072
+ vellum_ai-1.7.3.dist-info/RECORD,,