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.
- vellum/client/core/client_wrapper.py +2 -2
- vellum/workflows/errors/types.py +2 -1
- vellum/workflows/integrations/tests/test_vellum_integration_service.py +14 -12
- vellum/workflows/integrations/vellum_integration_service.py +9 -9
- vellum/workflows/nodes/displayable/code_execution_node/node.py +19 -7
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_node.py +101 -0
- vellum/workflows/nodes/displayable/tool_calling_node/node.py +2 -2
- vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py +50 -0
- vellum/workflows/nodes/displayable/tool_calling_node/utils.py +27 -11
- vellum/workflows/resolvers/resolver.py +14 -9
- vellum/workflows/runner/runner.py +43 -15
- vellum/workflows/state/base.py +14 -4
- vellum/workflows/types/__init__.py +2 -1
- vellum/workflows/types/core.py +3 -24
- vellum/workflows/types/definition.py +15 -1
- {vellum_ai-1.7.1.dist-info → vellum_ai-1.7.3.dist-info}/METADATA +1 -1
- {vellum_ai-1.7.1.dist-info → vellum_ai-1.7.3.dist-info}/RECORD +20 -20
- {vellum_ai-1.7.1.dist-info → vellum_ai-1.7.3.dist-info}/LICENSE +0 -0
- {vellum_ai-1.7.1.dist-info → vellum_ai-1.7.3.dist-info}/WHEEL +0 -0
- {vellum_ai-1.7.1.dist-info → vellum_ai-1.7.3.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.7.
|
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.
|
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:
|
vellum/workflows/errors/types.py
CHANGED
@@ -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: "
|
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
|
218
|
-
"""Test
|
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
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
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
|
-
|
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
|
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
|
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
|
-
|
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
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
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(
|
vellum/workflows/state/base.py
CHANGED
@@ -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:
|
447
|
-
|
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:
|
452
|
-
|
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
|
vellum/workflows/types/core.py
CHANGED
@@ -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]
|
@@ -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=
|
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=
|
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=
|
1880
|
-
vellum/workflows/integrations/vellum_integration_service.py,sha256=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
2041
|
-
vellum/workflows/types/definition.py,sha256=
|
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.
|
2069
|
-
vellum_ai-1.7.
|
2070
|
-
vellum_ai-1.7.
|
2071
|
-
vellum_ai-1.7.
|
2072
|
-
vellum_ai-1.7.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|