vellum-ai 1.2.5__py3-none-any.whl → 1.3.0__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/__init__.py +8 -0
- vellum/client/README.md +1 -1
- vellum/client/core/client_wrapper.py +2 -2
- vellum/client/reference.md +0 -9
- vellum/client/resources/workflow_sandboxes/client.py +0 -12
- vellum/client/resources/workflow_sandboxes/raw_client.py +2 -10
- vellum/client/types/__init__.py +8 -0
- vellum/client/types/deployment_read.py +5 -5
- vellum/client/types/slim_deployment_read.py +5 -5
- vellum/client/types/slim_workflow_deployment.py +5 -5
- vellum/client/types/workflow_deployment_read.py +5 -5
- vellum/client/types/workflow_request_audio_input_request.py +30 -0
- vellum/client/types/workflow_request_document_input_request.py +30 -0
- vellum/client/types/workflow_request_image_input_request.py +30 -0
- vellum/client/types/workflow_request_input_request.py +8 -0
- vellum/client/types/workflow_request_video_input_request.py +30 -0
- vellum/types/workflow_request_audio_input_request.py +3 -0
- vellum/types/workflow_request_document_input_request.py +3 -0
- vellum/types/workflow_request_image_input_request.py +3 -0
- vellum/types/workflow_request_video_input_request.py +3 -0
- vellum/workflows/events/types.py +6 -1
- vellum/workflows/integrations/tests/test_mcp_service.py +106 -1
- vellum/workflows/nodes/__init__.py +2 -0
- vellum/workflows/nodes/displayable/__init__.py +2 -0
- vellum/workflows/nodes/displayable/web_search_node/__init__.py +3 -0
- vellum/workflows/nodes/displayable/web_search_node/node.py +133 -0
- vellum/workflows/resolvers/base.py +3 -2
- vellum/workflows/resolvers/resolver.py +62 -7
- vellum/workflows/resolvers/tests/test_resolver.py +79 -7
- vellum/workflows/resolvers/types.py +11 -0
- vellum/workflows/runner/runner.py +49 -1
- vellum/workflows/state/context.py +41 -7
- vellum/workflows/utils/zip.py +46 -0
- vellum/workflows/workflows/base.py +10 -0
- {vellum_ai-1.2.5.dist-info → vellum_ai-1.3.0.dist-info}/METADATA +1 -1
- {vellum_ai-1.2.5.dist-info → vellum_ai-1.3.0.dist-info}/RECORD +43 -31
- vellum_cli/tests/test_init.py +7 -24
- vellum_cli/tests/test_pull.py +27 -52
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +7 -33
- vellum_ee/workflows/tests/test_server.py +115 -0
- {vellum_ai-1.2.5.dist-info → vellum_ai-1.3.0.dist-info}/LICENSE +0 -0
- {vellum_ai-1.2.5.dist-info → vellum_ai-1.3.0.dist-info}/WHEEL +0 -0
- {vellum_ai-1.2.5.dist-info → vellum_ai-1.3.0.dist-info}/entry_points.txt +0 -0
vellum/__init__.py
CHANGED
@@ -643,11 +643,15 @@ from .client.types import (
|
|
643
643
|
WorkflowPushResponse,
|
644
644
|
WorkflowReleaseTagRead,
|
645
645
|
WorkflowReleaseTagWorkflowDeploymentHistoryItem,
|
646
|
+
WorkflowRequestAudioInputRequest,
|
646
647
|
WorkflowRequestChatHistoryInputRequest,
|
648
|
+
WorkflowRequestDocumentInputRequest,
|
649
|
+
WorkflowRequestImageInputRequest,
|
647
650
|
WorkflowRequestInputRequest,
|
648
651
|
WorkflowRequestJsonInputRequest,
|
649
652
|
WorkflowRequestNumberInputRequest,
|
650
653
|
WorkflowRequestStringInputRequest,
|
654
|
+
WorkflowRequestVideoInputRequest,
|
651
655
|
WorkflowResultEvent,
|
652
656
|
WorkflowResultEventOutputData,
|
653
657
|
WorkflowResultEventOutputDataArray,
|
@@ -1359,11 +1363,15 @@ __all__ = [
|
|
1359
1363
|
"WorkflowPushResponse",
|
1360
1364
|
"WorkflowReleaseTagRead",
|
1361
1365
|
"WorkflowReleaseTagWorkflowDeploymentHistoryItem",
|
1366
|
+
"WorkflowRequestAudioInputRequest",
|
1362
1367
|
"WorkflowRequestChatHistoryInputRequest",
|
1368
|
+
"WorkflowRequestDocumentInputRequest",
|
1369
|
+
"WorkflowRequestImageInputRequest",
|
1363
1370
|
"WorkflowRequestInputRequest",
|
1364
1371
|
"WorkflowRequestJsonInputRequest",
|
1365
1372
|
"WorkflowRequestNumberInputRequest",
|
1366
1373
|
"WorkflowRequestStringInputRequest",
|
1374
|
+
"WorkflowRequestVideoInputRequest",
|
1367
1375
|
"WorkflowResultEvent",
|
1368
1376
|
"WorkflowResultEventOutputData",
|
1369
1377
|
"WorkflowResultEventOutputDataArray",
|
vellum/client/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[](https://buildwithfern.com?utm_source=github&utm_medium=github&utm_campaign=readme&utm_source=https%3A%2F%2Fgithub.com%2Fvellum-ai%2Fvellum-python-sdks)
|
4
4
|
[](https://pypi.python.org/pypi/vellum-ai)
|
5
5
|
|
6
|
-
The Vellum Python library provides convenient access to the Vellum
|
6
|
+
The Vellum Python library provides convenient access to the Vellum APIs from Python.
|
7
7
|
|
8
8
|
## API Docs
|
9
9
|
You can find Vellum's complete API docs at [docs.vellum.ai](https://docs.vellum.ai/api-reference/introduction/getting-started).
|
@@ -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.
|
30
|
+
"User-Agent": "vellum-ai/1.3.0",
|
31
31
|
"X-Fern-Language": "Python",
|
32
32
|
"X-Fern-SDK-Name": "vellum-ai",
|
33
|
-
"X-Fern-SDK-Version": "1.
|
33
|
+
"X-Fern-SDK-Version": "1.3.0",
|
34
34
|
**(self.get_custom_headers() or {}),
|
35
35
|
}
|
36
36
|
if self._api_version is not None:
|
vellum/client/reference.md
CHANGED
@@ -6222,7 +6222,6 @@ client = Vellum(
|
|
6222
6222
|
)
|
6223
6223
|
client.workflow_sandboxes.deploy_workflow(
|
6224
6224
|
id="id",
|
6225
|
-
workflow_id="workflow_id",
|
6226
6225
|
)
|
6227
6226
|
|
6228
6227
|
```
|
@@ -6247,14 +6246,6 @@ client.workflow_sandboxes.deploy_workflow(
|
|
6247
6246
|
<dl>
|
6248
6247
|
<dd>
|
6249
6248
|
|
6250
|
-
**workflow_id:** `str` — An ID identifying the Workflow you'd like to deploy.
|
6251
|
-
|
6252
|
-
</dd>
|
6253
|
-
</dl>
|
6254
|
-
|
6255
|
-
<dl>
|
6256
|
-
<dd>
|
6257
|
-
|
6258
6249
|
**workflow_deployment_id:** `typing.Optional[str]` — The Vellum-generated ID of the Workflow Deployment you'd like to update. Cannot specify both this and workflow_deployment_name. Leave null to create a new Workflow Deployment.
|
6259
6250
|
|
6260
6251
|
</dd>
|
@@ -35,7 +35,6 @@ class WorkflowSandboxesClient:
|
|
35
35
|
def deploy_workflow(
|
36
36
|
self,
|
37
37
|
id: str,
|
38
|
-
workflow_id: str,
|
39
38
|
*,
|
40
39
|
workflow_deployment_id: typing.Optional[str] = OMIT,
|
41
40
|
workflow_deployment_name: typing.Optional[str] = OMIT,
|
@@ -50,9 +49,6 @@ class WorkflowSandboxesClient:
|
|
50
49
|
id : str
|
51
50
|
A UUID string identifying this workflow sandbox.
|
52
51
|
|
53
|
-
workflow_id : str
|
54
|
-
An ID identifying the Workflow you'd like to deploy.
|
55
|
-
|
56
52
|
workflow_deployment_id : typing.Optional[str]
|
57
53
|
The Vellum-generated ID of the Workflow Deployment you'd like to update. Cannot specify both this and workflow_deployment_name. Leave null to create a new Workflow Deployment.
|
58
54
|
|
@@ -86,12 +82,10 @@ class WorkflowSandboxesClient:
|
|
86
82
|
)
|
87
83
|
client.workflow_sandboxes.deploy_workflow(
|
88
84
|
id="id",
|
89
|
-
workflow_id="workflow_id",
|
90
85
|
)
|
91
86
|
"""
|
92
87
|
_response = self._raw_client.deploy_workflow(
|
93
88
|
id,
|
94
|
-
workflow_id,
|
95
89
|
workflow_deployment_id=workflow_deployment_id,
|
96
90
|
workflow_deployment_name=workflow_deployment_name,
|
97
91
|
label=label,
|
@@ -168,7 +162,6 @@ class AsyncWorkflowSandboxesClient:
|
|
168
162
|
async def deploy_workflow(
|
169
163
|
self,
|
170
164
|
id: str,
|
171
|
-
workflow_id: str,
|
172
165
|
*,
|
173
166
|
workflow_deployment_id: typing.Optional[str] = OMIT,
|
174
167
|
workflow_deployment_name: typing.Optional[str] = OMIT,
|
@@ -183,9 +176,6 @@ class AsyncWorkflowSandboxesClient:
|
|
183
176
|
id : str
|
184
177
|
A UUID string identifying this workflow sandbox.
|
185
178
|
|
186
|
-
workflow_id : str
|
187
|
-
An ID identifying the Workflow you'd like to deploy.
|
188
|
-
|
189
179
|
workflow_deployment_id : typing.Optional[str]
|
190
180
|
The Vellum-generated ID of the Workflow Deployment you'd like to update. Cannot specify both this and workflow_deployment_name. Leave null to create a new Workflow Deployment.
|
191
181
|
|
@@ -224,7 +214,6 @@ class AsyncWorkflowSandboxesClient:
|
|
224
214
|
async def main() -> None:
|
225
215
|
await client.workflow_sandboxes.deploy_workflow(
|
226
216
|
id="id",
|
227
|
-
workflow_id="workflow_id",
|
228
217
|
)
|
229
218
|
|
230
219
|
|
@@ -232,7 +221,6 @@ class AsyncWorkflowSandboxesClient:
|
|
232
221
|
"""
|
233
222
|
_response = await self._raw_client.deploy_workflow(
|
234
223
|
id,
|
235
|
-
workflow_id,
|
236
224
|
workflow_deployment_id=workflow_deployment_id,
|
237
225
|
workflow_deployment_name=workflow_deployment_name,
|
238
226
|
label=label,
|
@@ -24,7 +24,6 @@ class RawWorkflowSandboxesClient:
|
|
24
24
|
def deploy_workflow(
|
25
25
|
self,
|
26
26
|
id: str,
|
27
|
-
workflow_id: str,
|
28
27
|
*,
|
29
28
|
workflow_deployment_id: typing.Optional[str] = OMIT,
|
30
29
|
workflow_deployment_name: typing.Optional[str] = OMIT,
|
@@ -39,9 +38,6 @@ class RawWorkflowSandboxesClient:
|
|
39
38
|
id : str
|
40
39
|
A UUID string identifying this workflow sandbox.
|
41
40
|
|
42
|
-
workflow_id : str
|
43
|
-
An ID identifying the Workflow you'd like to deploy.
|
44
|
-
|
45
41
|
workflow_deployment_id : typing.Optional[str]
|
46
42
|
The Vellum-generated ID of the Workflow Deployment you'd like to update. Cannot specify both this and workflow_deployment_name. Leave null to create a new Workflow Deployment.
|
47
43
|
|
@@ -66,7 +62,7 @@ class RawWorkflowSandboxesClient:
|
|
66
62
|
|
67
63
|
"""
|
68
64
|
_response = self._client_wrapper.httpx_client.request(
|
69
|
-
f"v1/workflow-sandboxes/{jsonable_encoder(id)}/
|
65
|
+
f"v1/workflow-sandboxes/{jsonable_encoder(id)}/deploy",
|
70
66
|
base_url=self._client_wrapper.get_environment().default,
|
71
67
|
method="POST",
|
72
68
|
json={
|
@@ -165,7 +161,6 @@ class AsyncRawWorkflowSandboxesClient:
|
|
165
161
|
async def deploy_workflow(
|
166
162
|
self,
|
167
163
|
id: str,
|
168
|
-
workflow_id: str,
|
169
164
|
*,
|
170
165
|
workflow_deployment_id: typing.Optional[str] = OMIT,
|
171
166
|
workflow_deployment_name: typing.Optional[str] = OMIT,
|
@@ -180,9 +175,6 @@ class AsyncRawWorkflowSandboxesClient:
|
|
180
175
|
id : str
|
181
176
|
A UUID string identifying this workflow sandbox.
|
182
177
|
|
183
|
-
workflow_id : str
|
184
|
-
An ID identifying the Workflow you'd like to deploy.
|
185
|
-
|
186
178
|
workflow_deployment_id : typing.Optional[str]
|
187
179
|
The Vellum-generated ID of the Workflow Deployment you'd like to update. Cannot specify both this and workflow_deployment_name. Leave null to create a new Workflow Deployment.
|
188
180
|
|
@@ -207,7 +199,7 @@ class AsyncRawWorkflowSandboxesClient:
|
|
207
199
|
|
208
200
|
"""
|
209
201
|
_response = await self._client_wrapper.httpx_client.request(
|
210
|
-
f"v1/workflow-sandboxes/{jsonable_encoder(id)}/
|
202
|
+
f"v1/workflow-sandboxes/{jsonable_encoder(id)}/deploy",
|
211
203
|
base_url=self._client_wrapper.get_environment().default,
|
212
204
|
method="POST",
|
213
205
|
json={
|
vellum/client/types/__init__.py
CHANGED
@@ -667,11 +667,15 @@ from .workflow_push_exec_config import WorkflowPushExecConfig
|
|
667
667
|
from .workflow_push_response import WorkflowPushResponse
|
668
668
|
from .workflow_release_tag_read import WorkflowReleaseTagRead
|
669
669
|
from .workflow_release_tag_workflow_deployment_history_item import WorkflowReleaseTagWorkflowDeploymentHistoryItem
|
670
|
+
from .workflow_request_audio_input_request import WorkflowRequestAudioInputRequest
|
670
671
|
from .workflow_request_chat_history_input_request import WorkflowRequestChatHistoryInputRequest
|
672
|
+
from .workflow_request_document_input_request import WorkflowRequestDocumentInputRequest
|
673
|
+
from .workflow_request_image_input_request import WorkflowRequestImageInputRequest
|
671
674
|
from .workflow_request_input_request import WorkflowRequestInputRequest
|
672
675
|
from .workflow_request_json_input_request import WorkflowRequestJsonInputRequest
|
673
676
|
from .workflow_request_number_input_request import WorkflowRequestNumberInputRequest
|
674
677
|
from .workflow_request_string_input_request import WorkflowRequestStringInputRequest
|
678
|
+
from .workflow_request_video_input_request import WorkflowRequestVideoInputRequest
|
675
679
|
from .workflow_result_event import WorkflowResultEvent
|
676
680
|
from .workflow_result_event_output_data import WorkflowResultEventOutputData
|
677
681
|
from .workflow_result_event_output_data_array import WorkflowResultEventOutputDataArray
|
@@ -1326,11 +1330,15 @@ __all__ = [
|
|
1326
1330
|
"WorkflowPushResponse",
|
1327
1331
|
"WorkflowReleaseTagRead",
|
1328
1332
|
"WorkflowReleaseTagWorkflowDeploymentHistoryItem",
|
1333
|
+
"WorkflowRequestAudioInputRequest",
|
1329
1334
|
"WorkflowRequestChatHistoryInputRequest",
|
1335
|
+
"WorkflowRequestDocumentInputRequest",
|
1336
|
+
"WorkflowRequestImageInputRequest",
|
1330
1337
|
"WorkflowRequestInputRequest",
|
1331
1338
|
"WorkflowRequestJsonInputRequest",
|
1332
1339
|
"WorkflowRequestNumberInputRequest",
|
1333
1340
|
"WorkflowRequestStringInputRequest",
|
1341
|
+
"WorkflowRequestVideoInputRequest",
|
1334
1342
|
"WorkflowResultEvent",
|
1335
1343
|
"WorkflowResultEventOutputData",
|
1336
1344
|
"WorkflowResultEventOutputDataArray",
|
@@ -13,6 +13,10 @@ from .vellum_variable import VellumVariable
|
|
13
13
|
|
14
14
|
|
15
15
|
class DeploymentRead(UniversalBaseModel):
|
16
|
+
"""
|
17
|
+
A Prompt Deployment's full details.
|
18
|
+
"""
|
19
|
+
|
16
20
|
id: str
|
17
21
|
created: dt.datetime
|
18
22
|
label: str = pydantic.Field()
|
@@ -35,11 +39,7 @@ class DeploymentRead(UniversalBaseModel):
|
|
35
39
|
|
36
40
|
environment: typing.Optional[EnvironmentEnum] = pydantic.Field(default=None)
|
37
41
|
"""
|
38
|
-
The
|
39
|
-
|
40
|
-
* `DEVELOPMENT` - Development
|
41
|
-
* `STAGING` - Staging
|
42
|
-
* `PRODUCTION` - Production
|
42
|
+
Deprecated. The value returned will always be 'PRODUCTION'.
|
43
43
|
"""
|
44
44
|
|
45
45
|
last_deployed_on: dt.datetime
|
@@ -13,6 +13,10 @@ from .vellum_variable import VellumVariable
|
|
13
13
|
|
14
14
|
|
15
15
|
class SlimDeploymentRead(UniversalBaseModel):
|
16
|
+
"""
|
17
|
+
A subset of a Prompt Deployment's full details.
|
18
|
+
"""
|
19
|
+
|
16
20
|
id: str
|
17
21
|
created: dt.datetime
|
18
22
|
label: str = pydantic.Field()
|
@@ -35,11 +39,7 @@ class SlimDeploymentRead(UniversalBaseModel):
|
|
35
39
|
|
36
40
|
environment: typing.Optional[EnvironmentEnum] = pydantic.Field(default=None)
|
37
41
|
"""
|
38
|
-
The
|
39
|
-
|
40
|
-
* `DEVELOPMENT` - Development
|
41
|
-
* `STAGING` - Staging
|
42
|
-
* `PRODUCTION` - Production
|
42
|
+
Deprecated. The value returned will always be 'PRODUCTION'.
|
43
43
|
"""
|
44
44
|
|
45
45
|
last_deployed_on: dt.datetime
|
@@ -13,6 +13,10 @@ from .vellum_variable import VellumVariable
|
|
13
13
|
|
14
14
|
|
15
15
|
class SlimWorkflowDeployment(UniversalBaseModel):
|
16
|
+
"""
|
17
|
+
A subset of a Workflow Deployment's full details.
|
18
|
+
"""
|
19
|
+
|
16
20
|
id: str
|
17
21
|
name: str = pydantic.Field()
|
18
22
|
"""
|
@@ -34,11 +38,7 @@ class SlimWorkflowDeployment(UniversalBaseModel):
|
|
34
38
|
|
35
39
|
environment: typing.Optional[EnvironmentEnum] = pydantic.Field(default=None)
|
36
40
|
"""
|
37
|
-
The
|
38
|
-
|
39
|
-
* `DEVELOPMENT` - Development
|
40
|
-
* `STAGING` - Staging
|
41
|
-
* `PRODUCTION` - Production
|
41
|
+
Deprecated. The value returned will always be 'PRODUCTION'.
|
42
42
|
"""
|
43
43
|
|
44
44
|
created: dt.datetime
|
@@ -13,6 +13,10 @@ from .vellum_variable import VellumVariable
|
|
13
13
|
|
14
14
|
|
15
15
|
class WorkflowDeploymentRead(UniversalBaseModel):
|
16
|
+
"""
|
17
|
+
A Workflow Deployment's full details.
|
18
|
+
"""
|
19
|
+
|
16
20
|
id: str
|
17
21
|
name: str = pydantic.Field()
|
18
22
|
"""
|
@@ -34,11 +38,7 @@ class WorkflowDeploymentRead(UniversalBaseModel):
|
|
34
38
|
|
35
39
|
environment: typing.Optional[EnvironmentEnum] = pydantic.Field(default=None)
|
36
40
|
"""
|
37
|
-
The
|
38
|
-
|
39
|
-
* `DEVELOPMENT` - Development
|
40
|
-
* `STAGING` - Staging
|
41
|
-
* `PRODUCTION` - Production
|
41
|
+
Deprecated. The value returned will always be 'PRODUCTION'.
|
42
42
|
"""
|
43
43
|
|
44
44
|
created: dt.datetime
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
import typing
|
4
|
+
|
5
|
+
import pydantic
|
6
|
+
from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
|
7
|
+
from .vellum_audio_request import VellumAudioRequest
|
8
|
+
|
9
|
+
|
10
|
+
class WorkflowRequestAudioInputRequest(UniversalBaseModel):
|
11
|
+
"""
|
12
|
+
The input for an audio variable in a Workflow.
|
13
|
+
"""
|
14
|
+
|
15
|
+
name: str = pydantic.Field()
|
16
|
+
"""
|
17
|
+
The variable's name, as defined in the Workflow.
|
18
|
+
"""
|
19
|
+
|
20
|
+
type: typing.Literal["AUDIO"] = "AUDIO"
|
21
|
+
value: VellumAudioRequest
|
22
|
+
|
23
|
+
if IS_PYDANTIC_V2:
|
24
|
+
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
25
|
+
else:
|
26
|
+
|
27
|
+
class Config:
|
28
|
+
frozen = True
|
29
|
+
smart_union = True
|
30
|
+
extra = pydantic.Extra.allow
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
import typing
|
4
|
+
|
5
|
+
import pydantic
|
6
|
+
from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
|
7
|
+
from .vellum_document_request import VellumDocumentRequest
|
8
|
+
|
9
|
+
|
10
|
+
class WorkflowRequestDocumentInputRequest(UniversalBaseModel):
|
11
|
+
"""
|
12
|
+
The input for a document variable in a Workflow.
|
13
|
+
"""
|
14
|
+
|
15
|
+
name: str = pydantic.Field()
|
16
|
+
"""
|
17
|
+
The variable's name, as defined in the Workflow.
|
18
|
+
"""
|
19
|
+
|
20
|
+
type: typing.Literal["DOCUMENT"] = "DOCUMENT"
|
21
|
+
value: VellumDocumentRequest
|
22
|
+
|
23
|
+
if IS_PYDANTIC_V2:
|
24
|
+
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
25
|
+
else:
|
26
|
+
|
27
|
+
class Config:
|
28
|
+
frozen = True
|
29
|
+
smart_union = True
|
30
|
+
extra = pydantic.Extra.allow
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
import typing
|
4
|
+
|
5
|
+
import pydantic
|
6
|
+
from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
|
7
|
+
from .vellum_image_request import VellumImageRequest
|
8
|
+
|
9
|
+
|
10
|
+
class WorkflowRequestImageInputRequest(UniversalBaseModel):
|
11
|
+
"""
|
12
|
+
The input for an image variable in a Workflow.
|
13
|
+
"""
|
14
|
+
|
15
|
+
name: str = pydantic.Field()
|
16
|
+
"""
|
17
|
+
The variable's name, as defined in the Workflow.
|
18
|
+
"""
|
19
|
+
|
20
|
+
type: typing.Literal["IMAGE"] = "IMAGE"
|
21
|
+
value: VellumImageRequest
|
22
|
+
|
23
|
+
if IS_PYDANTIC_V2:
|
24
|
+
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
25
|
+
else:
|
26
|
+
|
27
|
+
class Config:
|
28
|
+
frozen = True
|
29
|
+
smart_union = True
|
30
|
+
extra = pydantic.Extra.allow
|
@@ -2,14 +2,22 @@
|
|
2
2
|
|
3
3
|
import typing
|
4
4
|
|
5
|
+
from .workflow_request_audio_input_request import WorkflowRequestAudioInputRequest
|
5
6
|
from .workflow_request_chat_history_input_request import WorkflowRequestChatHistoryInputRequest
|
7
|
+
from .workflow_request_document_input_request import WorkflowRequestDocumentInputRequest
|
8
|
+
from .workflow_request_image_input_request import WorkflowRequestImageInputRequest
|
6
9
|
from .workflow_request_json_input_request import WorkflowRequestJsonInputRequest
|
7
10
|
from .workflow_request_number_input_request import WorkflowRequestNumberInputRequest
|
8
11
|
from .workflow_request_string_input_request import WorkflowRequestStringInputRequest
|
12
|
+
from .workflow_request_video_input_request import WorkflowRequestVideoInputRequest
|
9
13
|
|
10
14
|
WorkflowRequestInputRequest = typing.Union[
|
11
15
|
WorkflowRequestStringInputRequest,
|
12
16
|
WorkflowRequestJsonInputRequest,
|
13
17
|
WorkflowRequestChatHistoryInputRequest,
|
14
18
|
WorkflowRequestNumberInputRequest,
|
19
|
+
WorkflowRequestAudioInputRequest,
|
20
|
+
WorkflowRequestVideoInputRequest,
|
21
|
+
WorkflowRequestImageInputRequest,
|
22
|
+
WorkflowRequestDocumentInputRequest,
|
15
23
|
]
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
import typing
|
4
|
+
|
5
|
+
import pydantic
|
6
|
+
from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
|
7
|
+
from .vellum_video_request import VellumVideoRequest
|
8
|
+
|
9
|
+
|
10
|
+
class WorkflowRequestVideoInputRequest(UniversalBaseModel):
|
11
|
+
"""
|
12
|
+
The input for a video variable in a Workflow.
|
13
|
+
"""
|
14
|
+
|
15
|
+
name: str = pydantic.Field()
|
16
|
+
"""
|
17
|
+
The variable's name, as defined in the Workflow.
|
18
|
+
"""
|
19
|
+
|
20
|
+
type: typing.Literal["VIDEO"] = "VIDEO"
|
21
|
+
value: VellumVideoRequest
|
22
|
+
|
23
|
+
if IS_PYDANTIC_V2:
|
24
|
+
model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
|
25
|
+
else:
|
26
|
+
|
27
|
+
class Config:
|
28
|
+
frozen = True
|
29
|
+
smart_union = True
|
30
|
+
extra = pydantic.Extra.allow
|
vellum/workflows/events/types.py
CHANGED
@@ -7,7 +7,6 @@ from pydantic import Field, GetCoreSchemaHandler, Tag, ValidationInfo
|
|
7
7
|
from pydantic_core import CoreSchema, core_schema
|
8
8
|
|
9
9
|
from vellum.client.core.pydantic_utilities import UniversalBaseModel
|
10
|
-
from vellum.client.types.span_link import SpanLink
|
11
10
|
from vellum.workflows.state.encoder import DefaultStateEncoder
|
12
11
|
from vellum.workflows.types.definition import VellumCodeResourceDefinition
|
13
12
|
from vellum.workflows.types.utils import datetime_now
|
@@ -86,6 +85,12 @@ class ExternalParentContext(BaseParentContext):
|
|
86
85
|
type: Literal["EXTERNAL"] = "EXTERNAL"
|
87
86
|
|
88
87
|
|
88
|
+
class SpanLink(UniversalBaseModel):
|
89
|
+
trace_id: str
|
90
|
+
type: Literal["TRIGGERED_BY", "PREVIOUS_SPAN", "ROOT_SPAN"]
|
91
|
+
span_context: "ParentContext"
|
92
|
+
|
93
|
+
|
89
94
|
def _cast_parent_context_discriminator(v: Any) -> Any:
|
90
95
|
if v in PARENT_CONTEXT_TYPES:
|
91
96
|
return v
|
@@ -1,10 +1,11 @@
|
|
1
|
+
import pytest
|
1
2
|
import asyncio
|
2
3
|
import json
|
3
4
|
from unittest import mock
|
4
5
|
|
5
6
|
from vellum.workflows.constants import AuthorizationType
|
6
7
|
from vellum.workflows.integrations.mcp_service import MCPHttpClient, MCPService
|
7
|
-
from vellum.workflows.types.definition import MCPServer
|
8
|
+
from vellum.workflows.types.definition import MCPServer, MCPToolDefinition
|
8
9
|
|
9
10
|
|
10
11
|
def test_mcp_http_client_sse_response():
|
@@ -118,3 +119,107 @@ def test_mcp_service_api_key_auth():
|
|
118
119
|
|
119
120
|
# THEN the custom API key header should be set correctly
|
120
121
|
assert headers == {"X-API-Key": "api-key-123"}
|
122
|
+
|
123
|
+
|
124
|
+
@pytest.mark.asyncio
|
125
|
+
async def test_mcp_http_client_empty_response():
|
126
|
+
"""Test that empty responses are handled gracefully"""
|
127
|
+
# GIVEN a mock response that returns empty content
|
128
|
+
mock_response = mock.Mock()
|
129
|
+
mock_response.headers = {"content-type": "application/json"}
|
130
|
+
mock_response.text = ""
|
131
|
+
|
132
|
+
# AND a mock httpx client that returns this response
|
133
|
+
with mock.patch("vellum.workflows.integrations.mcp_service.httpx.AsyncClient") as mock_client_class:
|
134
|
+
mock_client = mock.AsyncMock()
|
135
|
+
mock_client.post.return_value = mock_response
|
136
|
+
mock_client_class.return_value = mock_client
|
137
|
+
|
138
|
+
# WHEN we call initialize with an empty response
|
139
|
+
# THEN it should raise an exception about empty response
|
140
|
+
async with MCPHttpClient("https://test.server.com", {}) as client:
|
141
|
+
with pytest.raises(Exception, match="Empty response received from server"):
|
142
|
+
await client.initialize()
|
143
|
+
|
144
|
+
|
145
|
+
@pytest.mark.asyncio
|
146
|
+
async def test_mcp_http_client_invalid_sse_json():
|
147
|
+
"""Test that invalid JSON in SSE data is handled"""
|
148
|
+
# GIVEN an SSE response with invalid JSON
|
149
|
+
invalid_sse = """event: message
|
150
|
+
data: {invalid json}
|
151
|
+
|
152
|
+
"""
|
153
|
+
|
154
|
+
mock_response = mock.Mock()
|
155
|
+
mock_response.headers = {"content-type": "text/event-stream"}
|
156
|
+
mock_response.text = invalid_sse
|
157
|
+
|
158
|
+
with mock.patch("vellum.workflows.integrations.mcp_service.httpx.AsyncClient") as mock_client_class:
|
159
|
+
mock_client = mock.AsyncMock()
|
160
|
+
mock_client.post.return_value = mock_response
|
161
|
+
mock_client_class.return_value = mock_client
|
162
|
+
|
163
|
+
# WHEN we call initialize with invalid SSE data
|
164
|
+
# THEN it should raise an exception about no valid JSON
|
165
|
+
async with MCPHttpClient("https://test.server.com", {}) as client:
|
166
|
+
with pytest.raises(Exception, match="No valid JSON data found in SSE response"):
|
167
|
+
await client.initialize()
|
168
|
+
|
169
|
+
|
170
|
+
def test_mcp_service_hydrate_tool_definitions():
|
171
|
+
"""Test tool definition hydration with SSE responses"""
|
172
|
+
# GIVEN an MCP server configuration
|
173
|
+
sample_mcp_server = MCPServer(
|
174
|
+
name="test-server",
|
175
|
+
url="https://test.mcp.server.com/mcp",
|
176
|
+
authorization_type=AuthorizationType.BEARER_TOKEN,
|
177
|
+
bearer_token_value="test-token-123",
|
178
|
+
)
|
179
|
+
|
180
|
+
# AND a mock MCP service that returns tools via SSE
|
181
|
+
with mock.patch("vellum.workflows.integrations.mcp_service.asyncio.run") as mock_run:
|
182
|
+
mock_run.return_value = [
|
183
|
+
{
|
184
|
+
"name": "resolve-library-id",
|
185
|
+
"description": "Resolves library names to IDs",
|
186
|
+
"inputSchema": {
|
187
|
+
"type": "object",
|
188
|
+
"properties": {"libraryName": {"type": "string"}},
|
189
|
+
"required": ["libraryName"],
|
190
|
+
},
|
191
|
+
}
|
192
|
+
]
|
193
|
+
|
194
|
+
# WHEN we hydrate tool definitions
|
195
|
+
service = MCPService()
|
196
|
+
tool_definitions = service.hydrate_tool_definitions(sample_mcp_server)
|
197
|
+
|
198
|
+
# THEN we should get properly formatted MCPToolDefinition objects
|
199
|
+
assert len(tool_definitions) == 1
|
200
|
+
assert isinstance(tool_definitions[0], MCPToolDefinition)
|
201
|
+
assert tool_definitions[0].name == "resolve-library-id"
|
202
|
+
assert tool_definitions[0].description == "Resolves library names to IDs"
|
203
|
+
assert tool_definitions[0].server == sample_mcp_server
|
204
|
+
assert tool_definitions[0].parameters == {
|
205
|
+
"type": "object",
|
206
|
+
"properties": {"libraryName": {"type": "string"}},
|
207
|
+
"required": ["libraryName"],
|
208
|
+
}
|
209
|
+
|
210
|
+
|
211
|
+
def test_mcp_service_list_tools_handles_errors():
|
212
|
+
"""Test that SSE parsing errors are handled gracefully"""
|
213
|
+
# GIVEN an MCP server configuration
|
214
|
+
sample_mcp_server = MCPServer(name="test-server", url="https://test.mcp.server.com/mcp")
|
215
|
+
|
216
|
+
# AND a mock that raises an exception during SSE parsing
|
217
|
+
with mock.patch("vellum.workflows.integrations.mcp_service.asyncio.run") as mock_run:
|
218
|
+
mock_run.side_effect = Exception("SSE parsing failed")
|
219
|
+
|
220
|
+
# WHEN we try to list tools
|
221
|
+
service = MCPService()
|
222
|
+
tools = service.list_tools(sample_mcp_server)
|
223
|
+
|
224
|
+
# THEN we should get an empty list instead of crashing
|
225
|
+
assert tools == []
|
@@ -11,6 +11,7 @@ from vellum.workflows.nodes.displayable import (
|
|
11
11
|
PromptDeploymentNode,
|
12
12
|
SearchNode,
|
13
13
|
SubworkflowDeploymentNode,
|
14
|
+
WebSearchNode,
|
14
15
|
)
|
15
16
|
from vellum.workflows.nodes.displayable.bases import (
|
16
17
|
BaseInlinePromptNode as BaseInlinePromptNode,
|
@@ -43,4 +44,5 @@ __all__ = [
|
|
43
44
|
"PromptDeploymentNode",
|
44
45
|
"SearchNode",
|
45
46
|
"SubworkflowDeploymentNode",
|
47
|
+
"WebSearchNode",
|
46
48
|
]
|
@@ -14,6 +14,7 @@ from .prompt_deployment_node import PromptDeploymentNode
|
|
14
14
|
from .search_node import SearchNode
|
15
15
|
from .subworkflow_deployment_node import SubworkflowDeploymentNode
|
16
16
|
from .tool_calling_node import ToolCallingNode
|
17
|
+
from .web_search_node import WebSearchNode
|
17
18
|
|
18
19
|
__all__ = [
|
19
20
|
"APINode",
|
@@ -31,5 +32,6 @@ __all__ = [
|
|
31
32
|
"SearchNode",
|
32
33
|
"TemplatingNode",
|
33
34
|
"ToolCallingNode",
|
35
|
+
"WebSearchNode",
|
34
36
|
"FinalOutputNode",
|
35
37
|
]
|