vellum-ai 0.13.22__py3-none-any.whl → 0.13.24__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 +1 -1
- vellum/client/types/execute_api_response.py +3 -1
- vellum/workflows/nodes/displayable/api_node/node.py +12 -3
- vellum/workflows/nodes/displayable/api_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py +34 -0
- vellum/workflows/nodes/displayable/bases/api_node/node.py +25 -4
- vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +11 -2
- vellum/workflows/nodes/displayable/code_execution_node/node.py +2 -2
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +89 -9
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +14 -12
- vellum/workflows/nodes/displayable/prompt_deployment_node/tests/test_node.py +5 -2
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +10 -1
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py +5 -2
- {vellum_ai-0.13.22.dist-info → vellum_ai-0.13.24.dist-info}/METADATA +1 -1
- {vellum_ai-0.13.22.dist-info → vellum_ai-0.13.24.dist-info}/RECORD +19 -17
- vellum_ee/workflows/display/vellum.py +1 -1
- {vellum_ai-0.13.22.dist-info → vellum_ai-0.13.24.dist-info}/LICENSE +0 -0
- {vellum_ai-0.13.22.dist-info → vellum_ai-0.13.24.dist-info}/WHEEL +0 -0
- {vellum_ai-0.13.22.dist-info → vellum_ai-0.13.24.dist-info}/entry_points.txt +0 -0
@@ -18,7 +18,7 @@ class BaseClientWrapper:
|
|
18
18
|
headers: typing.Dict[str, str] = {
|
19
19
|
"X-Fern-Language": "Python",
|
20
20
|
"X-Fern-SDK-Name": "vellum-ai",
|
21
|
-
"X-Fern-SDK-Version": "0.13.
|
21
|
+
"X-Fern-SDK-Version": "0.13.24",
|
22
22
|
}
|
23
23
|
headers["X_API_KEY"] = self.api_key
|
24
24
|
return headers
|
@@ -11,7 +11,9 @@ import pydantic
|
|
11
11
|
class ExecuteApiResponse(UniversalBaseModel):
|
12
12
|
status_code: int
|
13
13
|
text: str
|
14
|
-
json_: typing_extensions.Annotated[
|
14
|
+
json_: typing_extensions.Annotated[
|
15
|
+
typing.Optional[typing.Dict[str, typing.Optional[typing.Any]]], FieldMetadata(alias="json")
|
16
|
+
] = None
|
15
17
|
headers: typing.Dict[str, str]
|
16
18
|
|
17
19
|
if IS_PYDANTIC_V2:
|
@@ -33,6 +33,7 @@ class APINode(BaseAPINode):
|
|
33
33
|
def run(self) -> BaseAPINode.Outputs:
|
34
34
|
headers = self.headers or {}
|
35
35
|
header_overrides = {}
|
36
|
+
bearer_token = None
|
36
37
|
|
37
38
|
if (
|
38
39
|
self.authorization_type == AuthorizationType.API_KEY
|
@@ -40,9 +41,17 @@ class APINode(BaseAPINode):
|
|
40
41
|
and self.api_key_header_value
|
41
42
|
):
|
42
43
|
header_overrides[self.api_key_header_key] = self.api_key_header_value
|
43
|
-
elif self.authorization_type == AuthorizationType.BEARER_TOKEN:
|
44
|
+
elif self.authorization_type == AuthorizationType.BEARER_TOKEN and isinstance(self.bearer_token_value, str):
|
44
45
|
header_overrides["Authorization"] = f"Bearer {self.bearer_token_value}"
|
45
|
-
|
46
|
+
elif self.authorization_type == AuthorizationType.BEARER_TOKEN and isinstance(
|
47
|
+
self.bearer_token_value, VellumSecret
|
48
|
+
):
|
49
|
+
bearer_token = self.bearer_token_value
|
46
50
|
return self._run(
|
47
|
-
method=self.method,
|
51
|
+
method=self.method,
|
52
|
+
url=self.url,
|
53
|
+
data=self.data or self.json,
|
54
|
+
json=self.json,
|
55
|
+
headers={**headers, **header_overrides},
|
56
|
+
bearer_token=bearer_token,
|
48
57
|
)
|
File without changes
|
@@ -0,0 +1,34 @@
|
|
1
|
+
from vellum import ExecuteApiResponse, VellumSecret as ClientVellumSecret
|
2
|
+
from vellum.workflows.constants import APIRequestMethod, AuthorizationType
|
3
|
+
from vellum.workflows.nodes import APINode
|
4
|
+
from vellum.workflows.state import BaseState
|
5
|
+
from vellum.workflows.types.core import VellumSecret
|
6
|
+
|
7
|
+
|
8
|
+
def test_run_workflow__secrets(vellum_client):
|
9
|
+
vellum_client.execute_api.return_value = ExecuteApiResponse(
|
10
|
+
status_code=200,
|
11
|
+
text='{"status": 200, "data": [1, 2, 3]}',
|
12
|
+
json_={"data": [1, 2, 3]},
|
13
|
+
headers={"X-Response-Header": "bar"},
|
14
|
+
)
|
15
|
+
|
16
|
+
class SimpleBaseAPINode(APINode):
|
17
|
+
method = APIRequestMethod.POST
|
18
|
+
authorization_type = AuthorizationType.BEARER_TOKEN
|
19
|
+
url = "https://api.vellum.ai"
|
20
|
+
body = {
|
21
|
+
"key": "value",
|
22
|
+
}
|
23
|
+
headers = {
|
24
|
+
"X-Test-Header": "foo",
|
25
|
+
}
|
26
|
+
bearer_token_value = VellumSecret(name="secret")
|
27
|
+
|
28
|
+
node = SimpleBaseAPINode(state=BaseState())
|
29
|
+
terminal = node.run()
|
30
|
+
|
31
|
+
assert vellum_client.execute_api.call_count == 1
|
32
|
+
bearer_token = vellum_client.execute_api.call_args.kwargs["bearer_token"]
|
33
|
+
assert bearer_token == ClientVellumSecret(name="secret")
|
34
|
+
assert terminal.headers == {"X-Response-Header": "bar"}
|
@@ -3,6 +3,7 @@ from typing import Any, Dict, Generic, Optional, Union
|
|
3
3
|
from requests import Request, RequestException, Session
|
4
4
|
from requests.exceptions import JSONDecodeError
|
5
5
|
|
6
|
+
from vellum.client.types.vellum_secret import VellumSecret as ClientVellumSecret
|
6
7
|
from vellum.workflows.constants import APIRequestMethod
|
7
8
|
from vellum.workflows.errors.types import WorkflowErrorCode
|
8
9
|
from vellum.workflows.exceptions import NodeException
|
@@ -45,29 +46,49 @@ class BaseAPINode(BaseNode, Generic[StateType]):
|
|
45
46
|
self,
|
46
47
|
method: APIRequestMethod,
|
47
48
|
url: str,
|
48
|
-
data: Optional[str] = None,
|
49
|
+
data: Optional[Union[str, Any]] = None,
|
49
50
|
json: Any = None,
|
50
51
|
headers: Any = None,
|
52
|
+
bearer_token: Optional[VellumSecret] = None,
|
51
53
|
) -> Outputs:
|
54
|
+
vellum_instance = False
|
55
|
+
for header in headers or {}:
|
56
|
+
if isinstance(headers[header], VellumSecret):
|
57
|
+
vellum_instance = True
|
58
|
+
if vellum_instance or bearer_token:
|
59
|
+
return self._vellum_execute_api(bearer_token, data, headers, method, url)
|
60
|
+
else:
|
61
|
+
return self._local_execute_api(data, headers, json, method, url)
|
62
|
+
|
63
|
+
def _local_execute_api(self, data, headers, json, method, url):
|
52
64
|
try:
|
53
65
|
prepped = Request(method=method.value, url=url, data=data, json=json, headers=headers).prepare()
|
54
66
|
except Exception as e:
|
55
67
|
raise NodeException(f"Failed to prepare HTTP request: {e}", code=WorkflowErrorCode.PROVIDER_ERROR)
|
56
|
-
|
57
68
|
try:
|
58
69
|
with Session() as session:
|
59
70
|
response = session.send(prepped)
|
60
71
|
except RequestException as e:
|
61
72
|
raise NodeException(f"HTTP request failed: {e}", code=WorkflowErrorCode.PROVIDER_ERROR)
|
62
|
-
|
63
73
|
try:
|
64
74
|
json = response.json()
|
65
75
|
except JSONDecodeError:
|
66
76
|
json = None
|
67
|
-
|
68
77
|
return self.Outputs(
|
69
78
|
json=json,
|
70
79
|
headers={header: value for header, value in response.headers.items()},
|
71
80
|
status_code=response.status_code,
|
72
81
|
text=response.text,
|
73
82
|
)
|
83
|
+
|
84
|
+
def _vellum_execute_api(self, bearer_token, data, headers, method, url):
|
85
|
+
client_vellum_secret = ClientVellumSecret(name=bearer_token.name) if bearer_token else None
|
86
|
+
vellum_response = self._context.vellum_client.execute_api(
|
87
|
+
url=url, method=method.value, body=data, headers=headers, bearer_token=client_vellum_secret
|
88
|
+
)
|
89
|
+
return self.Outputs(
|
90
|
+
json=vellum_response.json_,
|
91
|
+
headers={header: value for header, value in vellum_response.headers.items()},
|
92
|
+
status_code=vellum_response.status_code,
|
93
|
+
text=vellum_response.text,
|
94
|
+
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
from uuid import UUID
|
3
|
-
from typing import Any, ClassVar, Dict, Generic, Iterator, List, Optional, Sequence, Union
|
3
|
+
from typing import Any, ClassVar, Dict, Generic, Iterator, List, Optional, Sequence, Union
|
4
4
|
|
5
5
|
from vellum import (
|
6
6
|
ChatHistoryInputRequest,
|
@@ -95,10 +95,19 @@ class BasePromptDeploymentNode(BasePromptNode, Generic[StateType]):
|
|
95
95
|
elif isinstance(input_value, list) and all(
|
96
96
|
isinstance(message, (ChatMessage, ChatMessageRequest)) for message in input_value
|
97
97
|
):
|
98
|
+
chat_history = [
|
99
|
+
(
|
100
|
+
message
|
101
|
+
if isinstance(message, ChatMessageRequest)
|
102
|
+
else ChatMessageRequest.model_validate(message.model_dump())
|
103
|
+
)
|
104
|
+
for message in input_value
|
105
|
+
if isinstance(message, (ChatMessage, ChatMessageRequest))
|
106
|
+
]
|
98
107
|
compiled_inputs.append(
|
99
108
|
ChatHistoryInputRequest(
|
100
109
|
name=input_name,
|
101
|
-
value=
|
110
|
+
value=chat_history,
|
102
111
|
)
|
103
112
|
)
|
104
113
|
else:
|
@@ -170,11 +170,11 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
|
|
170
170
|
value=cast(Dict[str, Any], input_value),
|
171
171
|
)
|
172
172
|
)
|
173
|
-
elif isinstance(input_value, float):
|
173
|
+
elif isinstance(input_value, (float, int)):
|
174
174
|
compiled_inputs.append(
|
175
175
|
NumberInput(
|
176
176
|
name=input_name,
|
177
|
-
value=input_value,
|
177
|
+
value=float(input_value),
|
178
178
|
)
|
179
179
|
)
|
180
180
|
elif isinstance(input_value, FunctionCall):
|
@@ -1,10 +1,12 @@
|
|
1
1
|
import pytest
|
2
2
|
import os
|
3
|
+
from typing import Any
|
3
4
|
|
4
5
|
from vellum import CodeExecutorResponse, NumberVellumValue, StringInput
|
5
6
|
from vellum.client.types.code_execution_package import CodeExecutionPackage
|
6
7
|
from vellum.client.types.code_executor_secret_input import CodeExecutorSecretInput
|
7
8
|
from vellum.client.types.function_call import FunctionCall
|
9
|
+
from vellum.client.types.number_input import NumberInput
|
8
10
|
from vellum.workflows.exceptions import NodeException
|
9
11
|
from vellum.workflows.inputs.base import BaseInputs
|
10
12
|
from vellum.workflows.nodes.displayable.code_execution_node import CodeExecutionNode
|
@@ -12,7 +14,7 @@ from vellum.workflows.references.vellum_secret import VellumSecretReference
|
|
12
14
|
from vellum.workflows.state.base import BaseState, StateMeta
|
13
15
|
|
14
16
|
|
15
|
-
def
|
17
|
+
def test_run_node__happy_path(vellum_client):
|
16
18
|
"""Confirm that CodeExecutionNodes output the expected text and results when run."""
|
17
19
|
|
18
20
|
# GIVEN a node that subclasses CodeExecutionNode
|
@@ -78,7 +80,7 @@ def main(word: str) -> int:
|
|
78
80
|
)
|
79
81
|
|
80
82
|
|
81
|
-
def
|
83
|
+
def test_run_node__code_attribute(vellum_client):
|
82
84
|
"""Confirm that CodeExecutionNodes can use the `code` attribute to specify the code to execute."""
|
83
85
|
|
84
86
|
# GIVEN a node that subclasses CodeExecutionNode
|
@@ -146,7 +148,7 @@ def main(word: str) -> int:
|
|
146
148
|
)
|
147
149
|
|
148
150
|
|
149
|
-
def
|
151
|
+
def test_run_node__code_and_filepath_defined(vellum_client):
|
150
152
|
"""Confirm that CodeExecutionNodes raise an error if both `code` and `filepath` are defined."""
|
151
153
|
|
152
154
|
# GIVEN a node that subclasses CodeExecutionNode
|
@@ -197,7 +199,7 @@ def main(word: str) -> int:
|
|
197
199
|
assert exc_info.value.message == "Cannot specify both `code` and `filepath` for a CodeExecutionNode"
|
198
200
|
|
199
201
|
|
200
|
-
def
|
202
|
+
def test_run_node__code_and_filepath_not_defined(vellum_client):
|
201
203
|
"""Confirm that CodeExecutionNodes raise an error if neither `code` nor `filepath` are defined."""
|
202
204
|
|
203
205
|
# GIVEN a node that subclasses CodeExecutionNode
|
@@ -240,7 +242,7 @@ def test_run_workflow__code_and_filepath_not_defined(vellum_client):
|
|
240
242
|
assert exc_info.value.message == "Must specify either `code` or `filepath` for a CodeExecutionNode"
|
241
243
|
|
242
244
|
|
243
|
-
def
|
245
|
+
def test_run_node__vellum_secret(vellum_client):
|
244
246
|
"""Confirm that CodeExecutionNodes can use Vellum Secrets"""
|
245
247
|
|
246
248
|
# GIVEN a node that subclasses CodeExecutionNode that references a Vellum Secret
|
@@ -302,7 +304,53 @@ def main(word: str) -> int:
|
|
302
304
|
)
|
303
305
|
|
304
306
|
|
305
|
-
def
|
307
|
+
def test_run_node__int_input(vellum_client):
|
308
|
+
"""Confirm that CodeExecutionNodes can use int's as inputs"""
|
309
|
+
|
310
|
+
# GIVEN a node that subclasses CodeExecutionNode that references an int
|
311
|
+
class State(BaseState):
|
312
|
+
pass
|
313
|
+
|
314
|
+
fixture = os.path.abspath(os.path.join(__file__, "../fixtures/main.py"))
|
315
|
+
|
316
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[State, int]):
|
317
|
+
filepath = fixture
|
318
|
+
runtime = "PYTHON_3_11_6"
|
319
|
+
packages = [
|
320
|
+
CodeExecutionPackage(
|
321
|
+
name="openai",
|
322
|
+
version="1.0.0",
|
323
|
+
)
|
324
|
+
]
|
325
|
+
|
326
|
+
code_inputs = {
|
327
|
+
"counter": 1,
|
328
|
+
}
|
329
|
+
|
330
|
+
# AND we know what the Code Execution Node will respond with
|
331
|
+
mock_code_execution = CodeExecutorResponse(
|
332
|
+
log="",
|
333
|
+
output=NumberVellumValue(value=0),
|
334
|
+
)
|
335
|
+
vellum_client.execute_code.return_value = mock_code_execution
|
336
|
+
|
337
|
+
# WHEN we run the node
|
338
|
+
node = ExampleCodeExecutionNode(state=State())
|
339
|
+
outputs = node.run()
|
340
|
+
|
341
|
+
# THEN the node should have produced the outputs we expect
|
342
|
+
assert outputs == {"result": 0, "log": ""}
|
343
|
+
|
344
|
+
# AND we should have invoked the Code with the correct inputs
|
345
|
+
assert vellum_client.execute_code.call_args_list[0].kwargs["input_values"] == [
|
346
|
+
NumberInput(
|
347
|
+
name="counter",
|
348
|
+
value=1.0,
|
349
|
+
)
|
350
|
+
]
|
351
|
+
|
352
|
+
|
353
|
+
def test_run_node__run_inline(vellum_client):
|
306
354
|
"""Confirm that CodeExecutionNodes run the code inline instead of through Vellum under certain conditions."""
|
307
355
|
|
308
356
|
# GIVEN a node that subclasses CodeExecutionNode
|
@@ -329,7 +377,7 @@ def main(word: str) -> int:
|
|
329
377
|
vellum_client.execute_code.assert_not_called()
|
330
378
|
|
331
379
|
|
332
|
-
def
|
380
|
+
def test_run_node__run_inline__incorrect_output_type():
|
333
381
|
"""Confirm that CodeExecutionNodes raise an error if the output type is incorrect during inline execution."""
|
334
382
|
|
335
383
|
# GIVEN a node that subclasses CodeExecutionNode that returns a string but is defined to return an int
|
@@ -353,7 +401,7 @@ def main(word: str) -> int:
|
|
353
401
|
assert exc_info.value.message == "Expected an output of type 'int', but received 'str'"
|
354
402
|
|
355
403
|
|
356
|
-
def
|
404
|
+
def test_run_node__run_inline__valid_dict_to_pydantic():
|
357
405
|
"""Confirm that CodeExecutionNodes can convert a dict to a Pydantic model during inline execution."""
|
358
406
|
|
359
407
|
# GIVEN a node that subclasses CodeExecutionNode that returns a dict matching a Pydantic model
|
@@ -379,7 +427,7 @@ def main(word: str) -> int:
|
|
379
427
|
assert outputs == {"result": FunctionCall(name="hello", arguments={}), "log": ""}
|
380
428
|
|
381
429
|
|
382
|
-
def
|
430
|
+
def test_run_node__run_inline__invalid_dict_to_pydantic():
|
383
431
|
"""Confirm that CodeExecutionNodes raise an error if the Pydantic validation fails during inline execution."""
|
384
432
|
|
385
433
|
# GIVEN a node that subclasses CodeExecutionNode that returns a dict not matching a Pydantic model
|
@@ -413,3 +461,35 @@ name
|
|
413
461
|
Field required [type=missing, input_value={'n': 'hello', 'a': {}}, input_type=dict]\
|
414
462
|
"""
|
415
463
|
)
|
464
|
+
|
465
|
+
|
466
|
+
def test_run_node__run_inline__valid_dict_to_pydantic_any_type():
|
467
|
+
"""Confirm that CodeExecutionNodes can convert a dict to a Pydantic model during inline execution."""
|
468
|
+
|
469
|
+
# GIVEN a node that subclasses CodeExecutionNode that returns a dict matching Any
|
470
|
+
class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, Any]):
|
471
|
+
code = """\
|
472
|
+
def main(word: str) -> dict:
|
473
|
+
return {
|
474
|
+
"name": "word",
|
475
|
+
"arguments": {},
|
476
|
+
}
|
477
|
+
"""
|
478
|
+
runtime = "PYTHON_3_11_6"
|
479
|
+
|
480
|
+
code_inputs = {
|
481
|
+
"word": "hello",
|
482
|
+
}
|
483
|
+
|
484
|
+
# WHEN we run the node
|
485
|
+
node = ExampleCodeExecutionNode()
|
486
|
+
outputs = node.run()
|
487
|
+
|
488
|
+
# THEN the node should have produced the outputs we expect
|
489
|
+
assert outputs == {
|
490
|
+
"result": {
|
491
|
+
"name": "word",
|
492
|
+
"arguments": {},
|
493
|
+
},
|
494
|
+
"log": "",
|
495
|
+
}
|
@@ -91,19 +91,21 @@ __arg__out = main({", ".join(run_args)})
|
|
91
91
|
logs = log_buffer.getvalue()
|
92
92
|
result = exec_globals["__arg__out"]
|
93
93
|
|
94
|
-
if
|
95
|
-
|
96
|
-
|
97
|
-
|
94
|
+
if output_type != Any:
|
95
|
+
if issubclass(output_type, BaseModel) and not isinstance(result, output_type):
|
96
|
+
try:
|
97
|
+
result = output_type.model_validate(result)
|
98
|
+
except ValidationError as e:
|
99
|
+
raise NodeException(
|
100
|
+
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
101
|
+
message=re.sub(r"\s+For further information visit [^\s]+", "", str(e)),
|
102
|
+
) from e
|
103
|
+
|
104
|
+
if not isinstance(result, output_type):
|
98
105
|
raise NodeException(
|
99
106
|
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
100
|
-
message=
|
101
|
-
|
102
|
-
|
103
|
-
if not isinstance(result, output_type):
|
104
|
-
raise NodeException(
|
105
|
-
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
106
|
-
message=f"Expected an output of type '{output_type.__name__}', but received '{result.__class__.__name__}'",
|
107
|
-
)
|
107
|
+
message=f"Expected an output of type '{output_type.__name__}',"
|
108
|
+
f" but received '{result.__class__.__name__}'",
|
109
|
+
)
|
108
110
|
|
109
111
|
return logs, result
|
@@ -1,7 +1,9 @@
|
|
1
|
+
import pytest
|
1
2
|
from uuid import uuid4
|
2
3
|
from typing import Any, Iterator, List
|
3
4
|
|
4
5
|
from vellum.client.types.chat_history_input_request import ChatHistoryInputRequest
|
6
|
+
from vellum.client.types.chat_message import ChatMessage
|
5
7
|
from vellum.client.types.chat_message_request import ChatMessageRequest
|
6
8
|
from vellum.client.types.execute_prompt_event import ExecutePromptEvent
|
7
9
|
from vellum.client.types.fulfilled_execute_prompt_event import FulfilledExecutePromptEvent
|
@@ -11,14 +13,15 @@ from vellum.client.types.string_vellum_value import StringVellumValue
|
|
11
13
|
from vellum.workflows.nodes.displayable.prompt_deployment_node.node import PromptDeploymentNode
|
12
14
|
|
13
15
|
|
14
|
-
|
16
|
+
@pytest.mark.parametrize("ChatMessageClass", [ChatMessageRequest, ChatMessage])
|
17
|
+
def test_run_node__chat_history_input(vellum_client, ChatMessageClass):
|
15
18
|
"""Confirm that we can successfully invoke a Prompt Deployment Node that uses Chat History Inputs"""
|
16
19
|
|
17
20
|
# GIVEN a Prompt Deployment Node
|
18
21
|
class ExamplePromptDeploymentNode(PromptDeploymentNode):
|
19
22
|
deployment = "example_prompt_deployment"
|
20
23
|
prompt_inputs = {
|
21
|
-
"chat_history": [
|
24
|
+
"chat_history": [ChatMessageClass(role="USER", text="Hello, how are you?")],
|
22
25
|
}
|
23
26
|
|
24
27
|
# AND we know what the Prompt Deployment will respond with
|
@@ -72,10 +72,19 @@ class SubworkflowDeploymentNode(BaseNode[StateType], Generic[StateType]):
|
|
72
72
|
elif isinstance(input_value, list) and all(
|
73
73
|
isinstance(message, (ChatMessage, ChatMessageRequest)) for message in input_value
|
74
74
|
):
|
75
|
+
chat_history = [
|
76
|
+
(
|
77
|
+
message
|
78
|
+
if isinstance(message, ChatMessageRequest)
|
79
|
+
else ChatMessageRequest.model_validate(message.model_dump())
|
80
|
+
)
|
81
|
+
for message in input_value
|
82
|
+
if isinstance(message, (ChatMessage, ChatMessageRequest))
|
83
|
+
]
|
75
84
|
compiled_inputs.append(
|
76
85
|
WorkflowRequestChatHistoryInputRequest(
|
77
86
|
name=input_name,
|
78
|
-
value=
|
87
|
+
value=chat_history,
|
79
88
|
)
|
80
89
|
)
|
81
90
|
elif isinstance(input_value, dict):
|
@@ -1,7 +1,9 @@
|
|
1
|
+
import pytest
|
1
2
|
from datetime import datetime
|
2
3
|
from uuid import uuid4
|
3
4
|
from typing import Any, Iterator, List
|
4
5
|
|
6
|
+
from vellum.client.types.chat_message import ChatMessage
|
5
7
|
from vellum.client.types.chat_message_request import ChatMessageRequest
|
6
8
|
from vellum.client.types.workflow_execution_workflow_result_event import WorkflowExecutionWorkflowResultEvent
|
7
9
|
from vellum.client.types.workflow_output_string import WorkflowOutputString
|
@@ -12,14 +14,15 @@ from vellum.client.types.workflow_stream_event import WorkflowStreamEvent
|
|
12
14
|
from vellum.workflows.nodes.displayable.subworkflow_deployment_node.node import SubworkflowDeploymentNode
|
13
15
|
|
14
16
|
|
15
|
-
|
17
|
+
@pytest.mark.parametrize("ChatMessageClass", [ChatMessageRequest, ChatMessage])
|
18
|
+
def test_run_workflow__chat_history_input(vellum_client, ChatMessageClass):
|
16
19
|
"""Confirm that we can successfully invoke a Subworkflow Deployment Node that uses Chat History Inputs"""
|
17
20
|
|
18
21
|
# GIVEN a Subworkflow Deployment Node
|
19
22
|
class ExampleSubworkflowDeploymentNode(SubworkflowDeploymentNode):
|
20
23
|
deployment = "example_subworkflow_deployment"
|
21
24
|
subworkflow_inputs = {
|
22
|
-
"chat_history": [
|
25
|
+
"chat_history": [ChatMessageClass(role="USER", text="Hello, how are you?")],
|
23
26
|
}
|
24
27
|
|
25
28
|
# AND we know what the Subworkflow Deployment will respond with
|
@@ -80,7 +80,7 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_n
|
|
80
80
|
vellum_ee/workflows/display/types.py,sha256=s1w2KELKI2kde4G2M3iniOEdPObNKYgYtr31sAgZqRI,2644
|
81
81
|
vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
82
82
|
vellum_ee/workflows/display/utils/vellum.py,sha256=IGHobHz0QG8TWdJNxlQ81khCmJv7piLjE64l4zc33kI,7743
|
83
|
-
vellum_ee/workflows/display/vellum.py,sha256
|
83
|
+
vellum_ee/workflows/display/vellum.py,sha256=1mcZQQ4gd5GYrVKgIQ3ejy8SqRss2CWUL0KMf44zgUc,8122
|
84
84
|
vellum_ee/workflows/display/workflows/__init__.py,sha256=kapXsC67VJcgSuiBMa86FdePG5A9kMB5Pi4Uy1O2ob4,207
|
85
85
|
vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=8inuxnxeJbysEhJIGdxLZTvQ2aPJj-OSGmSeotwe7fo,15782
|
86
86
|
vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py,sha256=kp0u8LN_2IwshLrhMImhpZx1hRyAcD5gXY-kDuuaGMQ,1269
|
@@ -115,7 +115,7 @@ vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
|
|
115
115
|
vellum/client/__init__.py,sha256=j6zi0NZ4BMC6JrwckvzMWuG5x8KoOvO4KqsLhvVCa68,117624
|
116
116
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
117
117
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
118
|
-
vellum/client/core/client_wrapper.py,sha256=
|
118
|
+
vellum/client/core/client_wrapper.py,sha256=CHUMF1rAO0mKKIpxyLeUmpjLICY4ZwyiCpiYCjAnHwE,1869
|
119
119
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
120
120
|
vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
|
121
121
|
vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
|
@@ -270,7 +270,7 @@ vellum/client/types/error_vellum_value_request.py,sha256=o0aSn34dRcpnAwAfwW_sgwP
|
|
270
270
|
vellum/client/types/execute_api_request_bearer_token.py,sha256=agAhp9lzfzZcYGZdzg2jHAEHCaHlqzbgp6qeeNebcto,183
|
271
271
|
vellum/client/types/execute_api_request_body.py,sha256=MArsO_-H41lU8Lz0dB78MVcFupjWtRV7UBEljY3Dnwk,169
|
272
272
|
vellum/client/types/execute_api_request_headers_value.py,sha256=bHtGwOpknQDcQo6qtMKqJxaYpvbinDfwx2uaPzyuZ9s,184
|
273
|
-
vellum/client/types/execute_api_response.py,sha256=
|
273
|
+
vellum/client/types/execute_api_response.py,sha256=1_wGY1eIF6Drwx5FEwnwBRLUxonXX7dOjhkvQakE-bw,842
|
274
274
|
vellum/client/types/execute_prompt_event.py,sha256=wq_TZBDJcmXQhSj25jR9nMTnN-mP8Ku5Vq3rLqmwE5Q,521
|
275
275
|
vellum/client/types/execute_prompt_response.py,sha256=n6ODveXcO8uWG-kr_B9wXziHH8JUaVTUcUAZKifClEo,334
|
276
276
|
vellum/client/types/execute_workflow_response.py,sha256=0Q-NGPv5jpxjq6xNlHa3qUNK7yOmkU8h6Z2vQb6bHsU,1022
|
@@ -1351,28 +1351,30 @@ vellum/workflows/nodes/core/try_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW
|
|
1351
1351
|
vellum/workflows/nodes/core/try_node/tests/test_node.py,sha256=Wc2kLl-MkffsBxl3IiFaqLd16e2Iosxhk7qBnojPvQg,4092
|
1352
1352
|
vellum/workflows/nodes/displayable/__init__.py,sha256=6F_4DlSwvHuilWnIalp8iDjjDXl0Nmz4QzJV2PYe5RI,1023
|
1353
1353
|
vellum/workflows/nodes/displayable/api_node/__init__.py,sha256=MoxdQSnidIj1Nf_d-hTxlOxcZXaZnsWFDbE-PkTK24o,56
|
1354
|
-
vellum/workflows/nodes/displayable/api_node/node.py,sha256=
|
1354
|
+
vellum/workflows/nodes/displayable/api_node/node.py,sha256=QdpsyGVxo5PcN8nwGZpcpW_YMKHr3_VvmbK1BlrdOFk,2547
|
1355
|
+
vellum/workflows/nodes/displayable/api_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1356
|
+
vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py,sha256=yo3zTMRxgpSdWmJ68X610A5rrtCchyfqhcDd2X-GJiU,1249
|
1355
1357
|
vellum/workflows/nodes/displayable/bases/__init__.py,sha256=0mWIx3qUrzllV7jqt7wN03vWGMuI1WrrLZeMLT2Cl2c,304
|
1356
1358
|
vellum/workflows/nodes/displayable/bases/api_node/__init__.py,sha256=1jwx4WC358CLA1jgzl_UD-rZmdMm2v9Mps39ndwCD7U,64
|
1357
|
-
vellum/workflows/nodes/displayable/bases/api_node/node.py,sha256=
|
1359
|
+
vellum/workflows/nodes/displayable/bases/api_node/node.py,sha256=nIFkP7eeXXSzOVUoQgjPPCzy3_P083X_F5fCm2OAjdU,3798
|
1358
1360
|
vellum/workflows/nodes/displayable/bases/base_prompt_node/__init__.py,sha256=Org3xTvgp1pA0uUXFfnJr29D3HzCey2lEdYF4zbIUgo,70
|
1359
1361
|
vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py,sha256=r_gOmeGFQQfzhAc1_bmzcwUvH-Xllc93gE7miTV4rQE,2824
|
1360
1362
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/__init__.py,sha256=Hl35IAoepRpE-j4cALaXVJIYTYOF3qszyVbxTj4kS1s,82
|
1361
1363
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/constants.py,sha256=fnjiRWLoRlC4Puo5oQcpZD5Hd-EesxsAo9l5tGAkpZQ,270
|
1362
1364
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=UrmI8NkNJFGq9f59gD12S1e8D_R3ROHc934JmtfQk9I,6841
|
1363
|
-
vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py,sha256=
|
1365
|
+
vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py,sha256=NbwLOoWG5VVcnwL63WmaYck87y2QW36-JQWerOlKyx4,5713
|
1364
1366
|
vellum/workflows/nodes/displayable/bases/search_node.py,sha256=3UtbqY3QO4kzfJHbmUNZGnEEfJmaoiF892u8H6TGjp8,5381
|
1365
1367
|
vellum/workflows/nodes/displayable/bases/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1366
1368
|
vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMDPevgwLg1i6YK0g4L4bCy-7xCBN5yYZI,3156
|
1367
1369
|
vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
|
1368
1370
|
vellum/workflows/nodes/displayable/bases/utils.py,sha256=ckMUenSsNkiYmSw6FmjSMHYaCk8Y8_sUjL6lkFFEqts,5412
|
1369
1371
|
vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
|
1370
|
-
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=
|
1372
|
+
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=wgtqPljUqan9SILMysPCdSmZ0HoCpTTTNNaW0y9nQQI,9082
|
1371
1373
|
vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1372
1374
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1373
1375
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
|
1374
|
-
vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=
|
1375
|
-
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=
|
1376
|
+
vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=y_j4PieOpRYFmTqIEg1IPg-x-y_ezOcjcWCWPXYp1hI,14582
|
1377
|
+
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=hF9tdCpta7WN1ANz467Q9LNlISOSmp79jDIkR5d2iQM,3542
|
1376
1378
|
vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
|
1377
1379
|
vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=Qjfl33gZ3JEgxBA1EgzSUebboGvsARthIxxcQyvx5Gg,1152
|
1378
1380
|
vellum/workflows/nodes/displayable/final_output_node/__init__.py,sha256=G7VXM4OWpubvSJtVkGmMNeqgb9GkM7qZT838eL18XU4,72
|
@@ -1390,15 +1392,15 @@ vellum/workflows/nodes/displayable/note_node/node.py,sha256=sIN1VBQ7zeT3GhN0kupX
|
|
1390
1392
|
vellum/workflows/nodes/displayable/prompt_deployment_node/__init__.py,sha256=krX1Hds-TSVYZsx0wJFX4wsAKkEFYOX1ifwRGiIM-EA,82
|
1391
1393
|
vellum/workflows/nodes/displayable/prompt_deployment_node/node.py,sha256=ruOgvpg_9KV_HkovPQeu6TKpur9DT_J4CYQo50tULCY,2680
|
1392
1394
|
vellum/workflows/nodes/displayable/prompt_deployment_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1393
|
-
vellum/workflows/nodes/displayable/prompt_deployment_node/tests/test_node.py,sha256=
|
1395
|
+
vellum/workflows/nodes/displayable/prompt_deployment_node/tests/test_node.py,sha256=ymEwMwrwRuQGyvkTnqeRZvfK7dhnf-kmRJTuwlycNjI,3939
|
1394
1396
|
vellum/workflows/nodes/displayable/search_node/__init__.py,sha256=hpBpvbrDYf43DElRZFLzieSn8weXiwNiiNOJurERQbs,62
|
1395
1397
|
vellum/workflows/nodes/displayable/search_node/node.py,sha256=_VHHuTNN4icZBgc7O5U9SVKrv1zgKipU72fOtxTyrQU,1453
|
1396
1398
|
vellum/workflows/nodes/displayable/search_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1397
1399
|
vellum/workflows/nodes/displayable/search_node/tests/test_node.py,sha256=2-QCV7Vk_-YMls33p0GOUtCv3f2uPNZCjkB2CRjek7o,6562
|
1398
1400
|
vellum/workflows/nodes/displayable/subworkflow_deployment_node/__init__.py,sha256=9yYM6001YZeqI1VOk1QuEM_yrffk_EdsO7qaPzINKds,92
|
1399
|
-
vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py,sha256=
|
1401
|
+
vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py,sha256=sSRo_zX5QVI7V0qmReWMBkEa78HfQfjNIKwvKh7-Om8,8307
|
1400
1402
|
vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1401
|
-
vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py,sha256=
|
1403
|
+
vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py,sha256=c8RP-QnsERzIinVytAc0jVZ9nd7Jl3hbc9-_yG91Ros,5445
|
1402
1404
|
vellum/workflows/nodes/displayable/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1403
1405
|
vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py,sha256=CI7iMyyIlnds1rkVSjICOFg2UY0yV51NTKtKpfeEME4,4677
|
1404
1406
|
vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py,sha256=VepO5z1277c1y5N6LLIC31nnWD1aak2m5oPFplfJHHs,6935
|
@@ -1462,8 +1464,8 @@ vellum/workflows/vellum_client.py,sha256=ODrq_TSl-drX2aezXegf7pizpWDVJuTXH-j6528
|
|
1462
1464
|
vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
|
1463
1465
|
vellum/workflows/workflows/base.py,sha256=uYT0TQnEDtVaH3pErq785FhxxEEmk7C5ZGfuSO3QK8c,18537
|
1464
1466
|
vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnadGsrSZGa7t7LpJA,2008
|
1465
|
-
vellum_ai-0.13.
|
1466
|
-
vellum_ai-0.13.
|
1467
|
-
vellum_ai-0.13.
|
1468
|
-
vellum_ai-0.13.
|
1469
|
-
vellum_ai-0.13.
|
1467
|
+
vellum_ai-0.13.24.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1468
|
+
vellum_ai-0.13.24.dist-info/METADATA,sha256=6i1_pGA_JzLwbgGSvPKSioG96wTBmf5XnTrvtVKPcZM,5335
|
1469
|
+
vellum_ai-0.13.24.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1470
|
+
vellum_ai-0.13.24.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1471
|
+
vellum_ai-0.13.24.dist-info/RECORD,,
|
@@ -113,8 +113,8 @@ class WorkflowOutputVellumDisplayOverrides(WorkflowOutputDisplay, WorkflowOutput
|
|
113
113
|
name: str
|
114
114
|
label: str
|
115
115
|
node_id: UUID
|
116
|
-
target_handle_id: UUID
|
117
116
|
display_data: NodeDisplayData
|
117
|
+
target_handle_id: Optional[UUID] = None
|
118
118
|
|
119
119
|
|
120
120
|
@dataclass
|
File without changes
|
File without changes
|
File without changes
|