vellum-ai 1.3.0__py3-none-any.whl → 1.3.1__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/events/workflow.py +9 -2
- vellum/workflows/nodes/displayable/tool_calling_node/utils.py +11 -0
- vellum/workflows/nodes/displayable/web_search_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/web_search_node/tests/test_node.py +319 -0
- {vellum_ai-1.3.0.dist-info → vellum_ai-1.3.1.dist-info}/METADATA +1 -1
- {vellum_ai-1.3.0.dist-info → vellum_ai-1.3.1.dist-info}/RECORD +11 -9
- vellum_ee/workflows/display/utils/events.py +3 -0
- {vellum_ai-1.3.0.dist-info → vellum_ai-1.3.1.dist-info}/LICENSE +0 -0
- {vellum_ai-1.3.0.dist-info → vellum_ai-1.3.1.dist-info}/WHEEL +0 -0
- {vellum_ai-1.3.0.dist-info → vellum_ai-1.3.1.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.3.
|
30
|
+
"User-Agent": "vellum-ai/1.3.1",
|
31
31
|
"X-Fern-Language": "Python",
|
32
32
|
"X-Fern-SDK-Name": "vellum-ai",
|
33
|
-
"X-Fern-SDK-Version": "1.3.
|
33
|
+
"X-Fern-SDK-Version": "1.3.1",
|
34
34
|
**(self.get_custom_headers() or {}),
|
35
35
|
}
|
36
36
|
if self._api_version is not None:
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import logging
|
1
2
|
from uuid import UUID
|
2
3
|
from typing import TYPE_CHECKING, Any, Dict, Generic, Iterable, Literal, Optional, Type, Union
|
3
4
|
from typing_extensions import TypeGuard
|
@@ -25,6 +26,8 @@ from .types import BaseEvent, default_serializer
|
|
25
26
|
if TYPE_CHECKING:
|
26
27
|
from vellum.workflows.workflows.base import BaseWorkflow
|
27
28
|
|
29
|
+
logger = logging.getLogger(__name__)
|
30
|
+
|
28
31
|
|
29
32
|
class _BaseWorkflowExecutionBody(UniversalBaseModel):
|
30
33
|
workflow_definition: Type["BaseWorkflow"]
|
@@ -107,8 +110,12 @@ class WorkflowExecutionInitiatedEvent(_BaseWorkflowEvent, Generic[InputsType, St
|
|
107
110
|
) -> WorkflowExecutionInitiatedBody[InputsType, StateType]:
|
108
111
|
context = info.context if info and hasattr(info, "context") else {}
|
109
112
|
if context and "event_enricher" in context and callable(context["event_enricher"]):
|
110
|
-
|
111
|
-
|
113
|
+
try:
|
114
|
+
event = context["event_enricher"](self)
|
115
|
+
return event.body
|
116
|
+
except Exception as e:
|
117
|
+
logger.exception(f"Error in event_enricher: {e}")
|
118
|
+
return body
|
112
119
|
else:
|
113
120
|
return body
|
114
121
|
|
@@ -54,12 +54,23 @@ class FunctionCallNodeMixin:
|
|
54
54
|
return function_call.value.arguments or {}
|
55
55
|
return {}
|
56
56
|
|
57
|
+
def _extract_function_call_id(self) -> Optional[str]:
|
58
|
+
"""Extract function call ID from function call output."""
|
59
|
+
current_index = getattr(self, "state").current_prompt_output_index
|
60
|
+
if self.function_call_output and len(self.function_call_output) > current_index:
|
61
|
+
function_call = self.function_call_output[current_index]
|
62
|
+
if function_call.type == "FUNCTION_CALL" and function_call.value is not None:
|
63
|
+
return function_call.value.id
|
64
|
+
return None
|
65
|
+
|
57
66
|
def _add_function_result_to_chat_history(self, result: Any, state: ToolCallingState) -> None:
|
58
67
|
"""Add function execution result to chat history."""
|
68
|
+
function_call_id = self._extract_function_call_id()
|
59
69
|
state.chat_history.append(
|
60
70
|
ChatMessage(
|
61
71
|
role="FUNCTION",
|
62
72
|
content=StringChatMessageContent(value=json.dumps(result, cls=DefaultStateEncoder)),
|
73
|
+
source=function_call_id,
|
63
74
|
)
|
64
75
|
)
|
65
76
|
with state.__quiet__():
|
File without changes
|
@@ -0,0 +1,319 @@
|
|
1
|
+
import pytest
|
2
|
+
from unittest.mock import MagicMock
|
3
|
+
|
4
|
+
import requests
|
5
|
+
|
6
|
+
from vellum.workflows.errors.types import WorkflowErrorCode
|
7
|
+
from vellum.workflows.exceptions import NodeException
|
8
|
+
from vellum.workflows.inputs import BaseInputs
|
9
|
+
from vellum.workflows.state import BaseState
|
10
|
+
from vellum.workflows.state.base import StateMeta
|
11
|
+
|
12
|
+
from ..node import WebSearchNode
|
13
|
+
|
14
|
+
|
15
|
+
@pytest.fixture
|
16
|
+
def base_node_setup(vellum_client):
|
17
|
+
"""Basic node setup with required inputs."""
|
18
|
+
|
19
|
+
class Inputs(BaseInputs):
|
20
|
+
query: str
|
21
|
+
api_key: str
|
22
|
+
num_results: int
|
23
|
+
|
24
|
+
class State(BaseState):
|
25
|
+
pass
|
26
|
+
|
27
|
+
class TestableWebSearchNode(WebSearchNode):
|
28
|
+
query = Inputs.query
|
29
|
+
api_key = Inputs.api_key
|
30
|
+
num_results = Inputs.num_results
|
31
|
+
|
32
|
+
state = State(meta=StateMeta(workflow_inputs=Inputs(query="test query", api_key="test_api_key", num_results=3)))
|
33
|
+
context = MagicMock()
|
34
|
+
context.vellum_client = vellum_client
|
35
|
+
node = TestableWebSearchNode(state=state, context=context)
|
36
|
+
return node
|
37
|
+
|
38
|
+
|
39
|
+
def test_successful_search_with_results(base_node_setup, requests_mock):
|
40
|
+
"""Test successful SerpAPI search with typical organic results."""
|
41
|
+
# GIVEN a mock SerpAPI response with organic results
|
42
|
+
mock_response = {
|
43
|
+
"organic_results": [
|
44
|
+
{
|
45
|
+
"title": "First Result",
|
46
|
+
"snippet": "This is the first search result snippet",
|
47
|
+
"link": "https://example1.com",
|
48
|
+
"position": 1,
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"title": "Second Result",
|
52
|
+
"snippet": "This is the second search result snippet",
|
53
|
+
"link": "https://example2.com",
|
54
|
+
"position": 2,
|
55
|
+
},
|
56
|
+
{
|
57
|
+
"title": "Third Result",
|
58
|
+
"snippet": "This is the third search result snippet",
|
59
|
+
"link": "https://example3.com",
|
60
|
+
"position": 3,
|
61
|
+
},
|
62
|
+
]
|
63
|
+
}
|
64
|
+
|
65
|
+
requests_mock.get("https://serpapi.com/search", json=mock_response)
|
66
|
+
|
67
|
+
# WHEN we run the node
|
68
|
+
outputs = base_node_setup.run()
|
69
|
+
|
70
|
+
# THEN the text output should be properly formatted
|
71
|
+
expected_text = (
|
72
|
+
"First Result: This is the first search result snippet\n\n"
|
73
|
+
"Second Result: This is the second search result snippet\n\n"
|
74
|
+
"Third Result: This is the third search result snippet"
|
75
|
+
)
|
76
|
+
assert outputs.text == expected_text
|
77
|
+
|
78
|
+
# AND URLs should be extracted correctly
|
79
|
+
assert outputs.urls == ["https://example1.com", "https://example2.com", "https://example3.com"]
|
80
|
+
|
81
|
+
# AND raw results should be preserved
|
82
|
+
assert outputs.results == mock_response["organic_results"]
|
83
|
+
|
84
|
+
# AND the request should have the correct parameters
|
85
|
+
assert requests_mock.last_request.qs == {
|
86
|
+
"q": ["test query"],
|
87
|
+
"api_key": ["test_api_key"],
|
88
|
+
"num": ["3"],
|
89
|
+
"engine": ["google"],
|
90
|
+
}
|
91
|
+
|
92
|
+
|
93
|
+
def test_search_with_location_parameter(base_node_setup, requests_mock):
|
94
|
+
"""Test that location parameter is properly passed to SerpAPI."""
|
95
|
+
# GIVEN a location parameter is set
|
96
|
+
base_node_setup.location = "New York, NY"
|
97
|
+
|
98
|
+
requests_mock.get("https://serpapi.com/search", json={"organic_results": []})
|
99
|
+
|
100
|
+
# WHEN we run the node
|
101
|
+
base_node_setup.run()
|
102
|
+
|
103
|
+
# THEN the location parameter should be included (URL encoding may lowercase)
|
104
|
+
assert "location" in requests_mock.last_request.qs
|
105
|
+
assert requests_mock.last_request.qs["location"][0].lower() == "new york, ny"
|
106
|
+
|
107
|
+
|
108
|
+
def test_authentication_error_401(base_node_setup, requests_mock):
|
109
|
+
"""Test 401 authentication error raises NodeException with INVALID_INPUTS."""
|
110
|
+
# GIVEN SerpAPI returns a 401 authentication error
|
111
|
+
requests_mock.get("https://serpapi.com/search", status_code=401)
|
112
|
+
|
113
|
+
# WHEN we run the node
|
114
|
+
with pytest.raises(NodeException) as exc_info:
|
115
|
+
base_node_setup.run()
|
116
|
+
|
117
|
+
# THEN it should raise the appropriate error
|
118
|
+
assert exc_info.value.code == WorkflowErrorCode.INVALID_INPUTS
|
119
|
+
assert "Invalid API key" in str(exc_info.value)
|
120
|
+
|
121
|
+
|
122
|
+
def test_rate_limit_error_429(base_node_setup, requests_mock):
|
123
|
+
"""Test 429 rate limit error raises NodeException with PROVIDER_ERROR."""
|
124
|
+
# GIVEN SerpAPI returns a 429 rate limit error
|
125
|
+
requests_mock.get("https://serpapi.com/search", status_code=429)
|
126
|
+
|
127
|
+
# WHEN we run the node
|
128
|
+
with pytest.raises(NodeException) as exc_info:
|
129
|
+
base_node_setup.run()
|
130
|
+
|
131
|
+
# THEN it should raise the appropriate error
|
132
|
+
assert exc_info.value.code == WorkflowErrorCode.PROVIDER_ERROR
|
133
|
+
assert "Rate limit exceeded" in str(exc_info.value)
|
134
|
+
|
135
|
+
|
136
|
+
def test_server_error_500(base_node_setup, requests_mock):
|
137
|
+
"""Test 500+ server errors raise NodeException with PROVIDER_ERROR."""
|
138
|
+
# GIVEN SerpAPI returns a 500 server error
|
139
|
+
requests_mock.get("https://serpapi.com/search", status_code=500)
|
140
|
+
|
141
|
+
# WHEN we run the node
|
142
|
+
with pytest.raises(NodeException) as exc_info:
|
143
|
+
base_node_setup.run()
|
144
|
+
|
145
|
+
# THEN it should raise the appropriate error
|
146
|
+
assert exc_info.value.code == WorkflowErrorCode.PROVIDER_ERROR
|
147
|
+
assert "SerpAPI error: HTTP 500" in str(exc_info.value)
|
148
|
+
|
149
|
+
|
150
|
+
def test_invalid_json_response(base_node_setup, requests_mock):
|
151
|
+
"""Test non-JSON response raises appropriate NodeException."""
|
152
|
+
# GIVEN SerpAPI returns non-JSON content
|
153
|
+
requests_mock.get("https://serpapi.com/search", text="Not JSON")
|
154
|
+
|
155
|
+
# WHEN we run the node
|
156
|
+
with pytest.raises(NodeException) as exc_info:
|
157
|
+
base_node_setup.run()
|
158
|
+
|
159
|
+
# THEN it should raise the appropriate error
|
160
|
+
assert exc_info.value.code == WorkflowErrorCode.PROVIDER_ERROR
|
161
|
+
assert "Invalid JSON response" in str(exc_info.value)
|
162
|
+
|
163
|
+
|
164
|
+
def test_serpapi_error_in_response(base_node_setup, requests_mock):
|
165
|
+
"""Test SerpAPI error field in response raises NodeException."""
|
166
|
+
# GIVEN SerpAPI returns an error in the response body
|
167
|
+
requests_mock.get("https://serpapi.com/search", json={"error": "Invalid search parameters"})
|
168
|
+
|
169
|
+
# WHEN we run the node
|
170
|
+
with pytest.raises(NodeException) as exc_info:
|
171
|
+
base_node_setup.run()
|
172
|
+
|
173
|
+
# THEN it should raise the appropriate error
|
174
|
+
assert exc_info.value.code == WorkflowErrorCode.PROVIDER_ERROR
|
175
|
+
assert "Invalid search parameters" in str(exc_info.value)
|
176
|
+
|
177
|
+
|
178
|
+
def test_empty_query_validation(vellum_client):
|
179
|
+
"""Test empty query raises validation error."""
|
180
|
+
|
181
|
+
# GIVEN a node with an empty query
|
182
|
+
class TestNode(WebSearchNode):
|
183
|
+
query = ""
|
184
|
+
api_key = "test_key"
|
185
|
+
num_results = 10
|
186
|
+
|
187
|
+
context = MagicMock()
|
188
|
+
context.vellum_client = vellum_client
|
189
|
+
node = TestNode(state=BaseState(meta=StateMeta(workflow_inputs=BaseInputs())), context=context)
|
190
|
+
|
191
|
+
# WHEN we run the node
|
192
|
+
with pytest.raises(NodeException) as exc_info:
|
193
|
+
node.run()
|
194
|
+
|
195
|
+
# THEN it should raise a validation error
|
196
|
+
assert exc_info.value.code == WorkflowErrorCode.INVALID_INPUTS
|
197
|
+
assert "Query is required" in str(exc_info.value)
|
198
|
+
|
199
|
+
|
200
|
+
def test_missing_api_key_validation(vellum_client):
|
201
|
+
"""Test missing API key raises validation error."""
|
202
|
+
|
203
|
+
# GIVEN a node with no API key
|
204
|
+
class TestNode(WebSearchNode):
|
205
|
+
query = "test query"
|
206
|
+
api_key = None
|
207
|
+
num_results = 10
|
208
|
+
|
209
|
+
context = MagicMock()
|
210
|
+
context.vellum_client = vellum_client
|
211
|
+
node = TestNode(state=BaseState(meta=StateMeta(workflow_inputs=BaseInputs())), context=context)
|
212
|
+
|
213
|
+
# WHEN we run the node
|
214
|
+
with pytest.raises(NodeException) as exc_info:
|
215
|
+
node.run()
|
216
|
+
|
217
|
+
# THEN it should raise a validation error
|
218
|
+
assert exc_info.value.code == WorkflowErrorCode.INVALID_INPUTS
|
219
|
+
assert "API key is required" in str(exc_info.value)
|
220
|
+
|
221
|
+
|
222
|
+
def test_invalid_num_results_validation(vellum_client):
|
223
|
+
"""Test invalid num_results raises validation error."""
|
224
|
+
|
225
|
+
# GIVEN a node with invalid num_results
|
226
|
+
class TestNode(WebSearchNode):
|
227
|
+
query = "test query"
|
228
|
+
api_key = "test_key"
|
229
|
+
num_results = -1
|
230
|
+
|
231
|
+
context = MagicMock()
|
232
|
+
context.vellum_client = vellum_client
|
233
|
+
node = TestNode(state=BaseState(meta=StateMeta(workflow_inputs=BaseInputs())), context=context)
|
234
|
+
|
235
|
+
# WHEN we run the node
|
236
|
+
with pytest.raises(NodeException) as exc_info:
|
237
|
+
node.run()
|
238
|
+
|
239
|
+
# THEN it should raise a validation error
|
240
|
+
assert exc_info.value.code == WorkflowErrorCode.INVALID_INPUTS
|
241
|
+
assert "num_results must be a positive integer" in str(exc_info.value)
|
242
|
+
|
243
|
+
|
244
|
+
def test_empty_organic_results(base_node_setup, requests_mock):
|
245
|
+
"""Test handling of empty search results."""
|
246
|
+
# GIVEN SerpAPI returns no organic results
|
247
|
+
requests_mock.get("https://serpapi.com/search", json={"organic_results": []})
|
248
|
+
|
249
|
+
# WHEN we run the node
|
250
|
+
outputs = base_node_setup.run()
|
251
|
+
|
252
|
+
# THEN all outputs should be empty
|
253
|
+
assert outputs.text == ""
|
254
|
+
assert outputs.urls == []
|
255
|
+
assert outputs.results == []
|
256
|
+
|
257
|
+
|
258
|
+
def test_missing_fields_in_results(base_node_setup, requests_mock):
|
259
|
+
"""Test handling of missing title, snippet, or link fields."""
|
260
|
+
# GIVEN SerpAPI returns results with missing fields
|
261
|
+
mock_response = {
|
262
|
+
"organic_results": [
|
263
|
+
{
|
264
|
+
"title": "Only Title",
|
265
|
+
# Missing snippet and link
|
266
|
+
},
|
267
|
+
{
|
268
|
+
"snippet": "Only snippet, no title or link"
|
269
|
+
# Missing title and link
|
270
|
+
},
|
271
|
+
{
|
272
|
+
"title": "Title with link",
|
273
|
+
"link": "https://example.com",
|
274
|
+
# Missing snippet
|
275
|
+
},
|
276
|
+
{
|
277
|
+
# All fields missing - should be skipped
|
278
|
+
"position": 4
|
279
|
+
},
|
280
|
+
]
|
281
|
+
}
|
282
|
+
|
283
|
+
requests_mock.get("https://serpapi.com/search", json=mock_response)
|
284
|
+
|
285
|
+
# WHEN we run the node
|
286
|
+
outputs = base_node_setup.run()
|
287
|
+
|
288
|
+
# THEN text should handle missing fields gracefully
|
289
|
+
expected_text = "Only Title\n\n" "Only snippet, no title or link\n\n" "Title with link"
|
290
|
+
assert outputs.text == expected_text
|
291
|
+
|
292
|
+
# AND URLs should only include valid links
|
293
|
+
assert outputs.urls == ["https://example.com"]
|
294
|
+
|
295
|
+
|
296
|
+
def test_request_timeout_handling(base_node_setup, requests_mock):
|
297
|
+
"""Test network timeout raises appropriate error."""
|
298
|
+
# GIVEN a network timeout occurs
|
299
|
+
requests_mock.get("https://serpapi.com/search", exc=requests.exceptions.Timeout("Connection timed out"))
|
300
|
+
|
301
|
+
# WHEN we run the node
|
302
|
+
with pytest.raises(NodeException) as exc_info:
|
303
|
+
base_node_setup.run()
|
304
|
+
|
305
|
+
# THEN it should raise a provider error
|
306
|
+
assert exc_info.value.code == WorkflowErrorCode.PROVIDER_ERROR
|
307
|
+
assert "HTTP request failed" in str(exc_info.value)
|
308
|
+
|
309
|
+
|
310
|
+
def test_user_agent_header_included(base_node_setup, requests_mock):
|
311
|
+
"""Test that User-Agent header from vellum_client is included."""
|
312
|
+
# GIVEN a successful request
|
313
|
+
requests_mock.get("https://serpapi.com/search", json={"organic_results": []})
|
314
|
+
|
315
|
+
# WHEN we run the node
|
316
|
+
base_node_setup.run()
|
317
|
+
|
318
|
+
# THEN the User-Agent header should be included
|
319
|
+
assert requests_mock.last_request.headers["User-Agent"] == "vellum-python-sdk/1.0.0"
|
@@ -106,7 +106,7 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_workflow_input_par
|
|
106
106
|
vellum_ee/workflows/display/types.py,sha256=cyZruu4sXAdHjwuFc7dydM4DcFNf-pp_CmulXItxac4,3679
|
107
107
|
vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
108
108
|
vellum_ee/workflows/display/utils/auto_layout.py,sha256=f4GiLn_LazweupfqTpubcdtdfE_vrOcmZudSsnYIY9E,3906
|
109
|
-
vellum_ee/workflows/display/utils/events.py,sha256=
|
109
|
+
vellum_ee/workflows/display/utils/events.py,sha256=KC684ZWODHRGgJtik_KjGXIjM5x4_58_1dGuco_9O8c,1748
|
110
110
|
vellum_ee/workflows/display/utils/exceptions.py,sha256=LSwwxCYNxFkf5XMUcFkaZKpQ13OSrI7y_bpEUwbKVk0,169
|
111
111
|
vellum_ee/workflows/display/utils/expressions.py,sha256=yPrUIEQKL5fDwUC9NpVO9yjL6emTOdFJw8VjoZgZ0E0,16942
|
112
112
|
vellum_ee/workflows/display/utils/registry.py,sha256=1qXiBTdsnro6FeCX0FGBEK7CIf6wa--Jt50iZ_nEp_M,3460
|
@@ -150,7 +150,7 @@ vellum/client/README.md,sha256=Uwq9qIFZAHOVCgEfatfWe4YoW-QYYy6xVA1bMjPvx3k,5601
|
|
150
150
|
vellum/client/__init__.py,sha256=LOu_TklkJG01SgXIpPWDhOX2QvKDyd2ZbQyr5H0m31I,72349
|
151
151
|
vellum/client/core/__init__.py,sha256=lTcqUPXcx4112yLDd70RAPeqq6tu3eFMe1pKOqkW9JQ,1562
|
152
152
|
vellum/client/core/api_error.py,sha256=44vPoTyWN59gonCIZMdzw7M1uspygiLnr3GNFOoVL2Q,614
|
153
|
-
vellum/client/core/client_wrapper.py,sha256=
|
153
|
+
vellum/client/core/client_wrapper.py,sha256=yjqDTK-pFWVYr-n4F1kmy-TuBlGzXJBmaztIfr5uBF0,2840
|
154
154
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
155
155
|
vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
156
156
|
vellum/client/core/force_multipart.py,sha256=awxh5MtcRYe74ehY8U76jzv6fYM_w_D3Rur7KQQzSDk,429
|
@@ -1727,7 +1727,7 @@ vellum/workflows/events/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
|
|
1727
1727
|
vellum/workflows/events/tests/test_basic_workflow.py,sha256=Pj6orHsXz37jWC5FARi0Sx2Gjf99Owri2Cvr6Chb79k,1765
|
1728
1728
|
vellum/workflows/events/tests/test_event.py,sha256=c2pM8ZOuES_8XjLYP4cU4cChrZUZ1ZZ3HUNIaaPAxXk,18411
|
1729
1729
|
vellum/workflows/events/types.py,sha256=mVrqAH9Hs9SpXm08Hcxdyap_ImQPwGsxRr56rSNMP34,5043
|
1730
|
-
vellum/workflows/events/workflow.py,sha256=
|
1730
|
+
vellum/workflows/events/workflow.py,sha256=rAj2jH94t-bWqtQRtG8mkxXpQxIfqux06QtKdFK_L54,8960
|
1731
1731
|
vellum/workflows/exceptions.py,sha256=NiBiR3ggfmPxBVqD-H1SqmjI-7mIn0EStSN1BqApvCM,1213
|
1732
1732
|
vellum/workflows/expressions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1733
1733
|
vellum/workflows/expressions/accessor.py,sha256=3lu1-_-dBfZdJvtX-q66jbmRAZtqIfdsh_3_JNuzg1E,4462
|
@@ -1888,9 +1888,11 @@ vellum/workflows/nodes/displayable/tool_calling_node/tests/__init__.py,sha256=47
|
|
1888
1888
|
vellum/workflows/nodes/displayable/tool_calling_node/tests/test_composio_service.py,sha256=in1fbEz5x1tx3uKv9YXdvOncsHucNL8Ro6Go7lBuuOQ,8962
|
1889
1889
|
vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py,sha256=GZoeybB9uM7ai8sBLAtUMHrMVgh-WrJDWrKZci6feDs,11892
|
1890
1890
|
vellum/workflows/nodes/displayable/tool_calling_node/tests/test_utils.py,sha256=SIu5GCj4tIE4fz-cAcdULtQfqZIhrcc3Doo6TWLXBws,8804
|
1891
|
-
vellum/workflows/nodes/displayable/tool_calling_node/utils.py,sha256=
|
1891
|
+
vellum/workflows/nodes/displayable/tool_calling_node/utils.py,sha256=ACEfl2pY65sO0DaMYxuecx2Kxg32HpSh7XXpp8U1J84,23459
|
1892
1892
|
vellum/workflows/nodes/displayable/web_search_node/__init__.py,sha256=8FOnEP-n-U68cvxTlJW9wphIAGHq5aqjzLM-DoSSXnU,61
|
1893
1893
|
vellum/workflows/nodes/displayable/web_search_node/node.py,sha256=NQYux2bOtuBF5E4tn-fXi5y3btURPRrNqMSM9MAZYI4,5091
|
1894
|
+
vellum/workflows/nodes/displayable/web_search_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1895
|
+
vellum/workflows/nodes/displayable/web_search_node/tests/test_node.py,sha256=H3titxCYFsfIJ3EDeRL6Pe9I-tdKMRt1axOwb2qIw6U,10983
|
1894
1896
|
vellum/workflows/nodes/experimental/README.md,sha256=eF6DfIL8t-HbF9-mcofOMymKrraiBHDLKTlnBa51ZiE,284
|
1895
1897
|
vellum/workflows/nodes/experimental/__init__.py,sha256=jCQgvZEknXKfuNhGSOou4XPfrPqZ1_XBj5F0n0fgiWM,106
|
1896
1898
|
vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py,sha256=lsyD9laR9p7kx5-BXGH2gUTM242UhKy8SMV0SR6S2iE,90
|
@@ -1968,8 +1970,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
|
|
1968
1970
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1969
1971
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=ptMntHzVyy8ZuzNgeTuk7hREgKQ5UBdgq8VJFSGaW4Y,20832
|
1970
1972
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1971
|
-
vellum_ai-1.3.
|
1972
|
-
vellum_ai-1.3.
|
1973
|
-
vellum_ai-1.3.
|
1974
|
-
vellum_ai-1.3.
|
1975
|
-
vellum_ai-1.3.
|
1973
|
+
vellum_ai-1.3.1.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1974
|
+
vellum_ai-1.3.1.dist-info/METADATA,sha256=8eP8UQcNY66V3X1QK8GmDgvQnyi_hHztrZQNUMTCT1M,5547
|
1975
|
+
vellum_ai-1.3.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1976
|
+
vellum_ai-1.3.1.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1977
|
+
vellum_ai-1.3.1.dist-info/RECORD,,
|
@@ -26,6 +26,9 @@ def _should_mark_workflow_dynamic(event: WorkflowExecutionInitiatedEvent) -> boo
|
|
26
26
|
|
27
27
|
|
28
28
|
def event_enricher(event: WorkflowExecutionInitiatedEvent) -> WorkflowExecutionInitiatedEvent:
|
29
|
+
if event.name != "workflow.execution.initiated":
|
30
|
+
return event
|
31
|
+
|
29
32
|
workflow_definition = event.body.workflow_definition
|
30
33
|
workflow_display = get_workflow_display(
|
31
34
|
workflow_class=workflow_definition,
|
File without changes
|
File without changes
|
File without changes
|