vellum-ai 0.14.76__py3-none-any.whl → 0.14.78__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/plugins/pydantic.py +4 -1
- vellum/plugins/tests/__init__.py +0 -0
- vellum/plugins/tests/test_pydantic.py +30 -0
- vellum/prompts/__init__.py +3 -0
- vellum/prompts/blocks/__init__.py +3 -0
- vellum/prompts/blocks/helpers.py +31 -0
- vellum/workflows/expressions/accessor.py +31 -2
- vellum/workflows/expressions/tests/test_accessor.py +59 -0
- vellum/workflows/nodes/experimental/tool_calling_node/utils.py +6 -1
- vellum/workflows/state/encoder.py +10 -3
- vellum/workflows/utils/vellum_variables.py +37 -0
- {vellum_ai-0.14.76.dist-info → vellum_ai-0.14.78.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.76.dist-info → vellum_ai-0.14.78.dist-info}/RECORD +21 -18
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +52 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +1 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py +48 -3
- vellum_ee/workflows/display/utils/expressions.py +8 -2
- {vellum_ai-0.14.76.dist-info → vellum_ai-0.14.78.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.76.dist-info → vellum_ai-0.14.78.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.76.dist-info → vellum_ai-0.14.78.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.14.
|
21
|
+
"X-Fern-SDK-Version": "0.14.78",
|
22
22
|
}
|
23
23
|
headers["X-API-KEY"] = self.api_key
|
24
24
|
return headers
|
vellum/plugins/pydantic.py
CHANGED
@@ -71,7 +71,10 @@ class OnValidatePython(ValidatePythonHandlerProtocol):
|
|
71
71
|
self.tracked_descriptors[key] = value
|
72
72
|
# TODO: This does not yet work for descriptors that map to more complex types
|
73
73
|
# https://app.shortcut.com/vellum/story/4636
|
74
|
-
|
74
|
+
if len(value.types) == 0:
|
75
|
+
input[key] = dict()
|
76
|
+
else:
|
77
|
+
input[key] = value.types[0]()
|
75
78
|
|
76
79
|
def on_success(self, result: Any) -> None:
|
77
80
|
if self.tracked_descriptors:
|
File without changes
|
@@ -0,0 +1,30 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
from pydantic import BaseModel
|
4
|
+
|
5
|
+
from vellum.workflows.expressions.accessor import AccessorExpression
|
6
|
+
from vellum.workflows.references.constant import ConstantValueReference
|
7
|
+
from vellum.workflows.state.base import BaseState
|
8
|
+
|
9
|
+
|
10
|
+
class TestState(BaseState):
|
11
|
+
pass
|
12
|
+
|
13
|
+
|
14
|
+
class TestModel(BaseModel):
|
15
|
+
field: Any
|
16
|
+
|
17
|
+
|
18
|
+
def test_pydantic_plugin__empty_types_descriptor():
|
19
|
+
"""
|
20
|
+
Test that the pydantic plugin handles BaseDescriptor with empty types gracefully.
|
21
|
+
"""
|
22
|
+
|
23
|
+
base_ref = ConstantValueReference({"name": "test"})
|
24
|
+
accessor = AccessorExpression(base=base_ref, field="name")
|
25
|
+
|
26
|
+
model = TestModel(field=accessor)
|
27
|
+
|
28
|
+
assert model is not None
|
29
|
+
assert hasattr(model, "field")
|
30
|
+
assert model.field == accessor
|
vellum/prompts/__init__.py
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
from vellum import ChatMessagePromptBlock, PlainTextPromptBlock, RichTextPromptBlock
|
2
|
+
|
3
|
+
|
4
|
+
def TextSystemMessage(content: str) -> ChatMessagePromptBlock:
|
5
|
+
"""
|
6
|
+
Create a text system message that autocasts to ChatMessagePromptBlock.
|
7
|
+
|
8
|
+
Args:
|
9
|
+
content: The text content for the system message
|
10
|
+
|
11
|
+
Returns:
|
12
|
+
ChatMessagePromptBlock configured as a system message
|
13
|
+
"""
|
14
|
+
return ChatMessagePromptBlock(
|
15
|
+
chat_role="SYSTEM", blocks=[RichTextPromptBlock(blocks=[PlainTextPromptBlock(text=content)])]
|
16
|
+
)
|
17
|
+
|
18
|
+
|
19
|
+
def TextUserMessage(content: str) -> ChatMessagePromptBlock:
|
20
|
+
"""
|
21
|
+
Create a text user message that autocasts to ChatMessagePromptBlock.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
content: The text content for the user message
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
ChatMessagePromptBlock configured as a user message
|
28
|
+
"""
|
29
|
+
return ChatMessagePromptBlock(
|
30
|
+
chat_role="USER", blocks=[RichTextPromptBlock(blocks=[PlainTextPromptBlock(text=content)])]
|
31
|
+
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
2
|
import dataclasses
|
3
|
-
from typing import Any, Sequence, Type, TypeVar, Union
|
3
|
+
from typing import Any, Sequence, Type, TypeVar, Union, get_args, get_origin
|
4
4
|
|
5
5
|
from pydantic import BaseModel, GetCoreSchemaHandler
|
6
6
|
from pydantic_core import core_schema
|
@@ -22,12 +22,41 @@ class AccessorExpression(BaseDescriptor[Any]):
|
|
22
22
|
) -> None:
|
23
23
|
super().__init__(
|
24
24
|
name=f"{base.name}.{field}",
|
25
|
-
types=(),
|
25
|
+
types=self._infer_accessor_types(base, field),
|
26
26
|
instance=None,
|
27
27
|
)
|
28
28
|
self._base = base
|
29
29
|
self._field = field
|
30
30
|
|
31
|
+
def _infer_accessor_types(self, base: BaseDescriptor[LHS], field: Union[str, int]) -> tuple[Type, ...]:
|
32
|
+
"""
|
33
|
+
Infer the types for this accessor expression based on the base descriptor's types
|
34
|
+
and the field being accessed.
|
35
|
+
"""
|
36
|
+
if not base.types:
|
37
|
+
return ()
|
38
|
+
|
39
|
+
inferred_types = []
|
40
|
+
|
41
|
+
for base_type in base.types:
|
42
|
+
origin = get_origin(base_type)
|
43
|
+
args = get_args(base_type)
|
44
|
+
|
45
|
+
if isinstance(field, int) and origin in (list, tuple) and args:
|
46
|
+
if origin is list:
|
47
|
+
inferred_types.append(args[0])
|
48
|
+
elif origin is tuple and len(args) == 2 and args[1] is ...:
|
49
|
+
inferred_types.append(args[0])
|
50
|
+
elif origin is tuple and len(args) > abs(field):
|
51
|
+
if field >= 0:
|
52
|
+
inferred_types.append(args[field])
|
53
|
+
else:
|
54
|
+
inferred_types.append(args[field])
|
55
|
+
elif isinstance(field, str) and origin in (dict,) and len(args) >= 2:
|
56
|
+
inferred_types.append(args[1]) # Value type from Dict[K, V]
|
57
|
+
|
58
|
+
return tuple(set(inferred_types)) if inferred_types else ()
|
59
|
+
|
31
60
|
def resolve(self, state: "BaseState") -> Any:
|
32
61
|
base = resolve_value(self._base, state)
|
33
62
|
|
@@ -1,11 +1,14 @@
|
|
1
1
|
import pytest
|
2
2
|
from dataclasses import dataclass
|
3
|
+
from typing import Dict, List
|
3
4
|
|
4
5
|
from pydantic import BaseModel
|
5
6
|
|
6
7
|
from vellum.workflows.descriptors.exceptions import InvalidExpressionException
|
7
8
|
from vellum.workflows.expressions.accessor import AccessorExpression
|
9
|
+
from vellum.workflows.outputs.base import BaseOutputs
|
8
10
|
from vellum.workflows.references.constant import ConstantValueReference
|
11
|
+
from vellum.workflows.references.output import OutputReference
|
9
12
|
from vellum.workflows.state.base import BaseState
|
10
13
|
|
11
14
|
|
@@ -187,3 +190,59 @@ def test_accessor_expression_unsupported_type():
|
|
187
190
|
accessor.resolve(state)
|
188
191
|
|
189
192
|
assert "Cannot get field field from 42" in str(exc_info.value)
|
193
|
+
|
194
|
+
|
195
|
+
def test_accessor_expression_list_type_inference():
|
196
|
+
"""Test that accessor expressions correctly infer element types from List[str]."""
|
197
|
+
base_ref: OutputReference = OutputReference(
|
198
|
+
name="test_list",
|
199
|
+
types=(List[str],),
|
200
|
+
instance=None,
|
201
|
+
outputs_class=BaseOutputs,
|
202
|
+
)
|
203
|
+
|
204
|
+
accessor = AccessorExpression(base=base_ref, field=0)
|
205
|
+
|
206
|
+
assert accessor.types == (str,)
|
207
|
+
|
208
|
+
|
209
|
+
def test_accessor_expression_tuple_type_inference():
|
210
|
+
"""Test that accessor expressions correctly infer element types from Tuple types."""
|
211
|
+
base_ref: OutputReference = OutputReference(
|
212
|
+
name="test_tuple",
|
213
|
+
types=(tuple,),
|
214
|
+
instance=None,
|
215
|
+
outputs_class=BaseOutputs,
|
216
|
+
)
|
217
|
+
|
218
|
+
accessor = AccessorExpression(base=base_ref, field=0)
|
219
|
+
|
220
|
+
assert accessor.types == ()
|
221
|
+
|
222
|
+
|
223
|
+
def test_accessor_expression_dict_type_inference():
|
224
|
+
"""Test that accessor expressions correctly infer value types from Dict types."""
|
225
|
+
base_ref: OutputReference = OutputReference(
|
226
|
+
name="test_dict",
|
227
|
+
types=(Dict[str, int],),
|
228
|
+
instance=None,
|
229
|
+
outputs_class=BaseOutputs,
|
230
|
+
)
|
231
|
+
|
232
|
+
accessor = AccessorExpression(base=base_ref, field="some_key")
|
233
|
+
|
234
|
+
assert accessor.types == (int,)
|
235
|
+
|
236
|
+
|
237
|
+
def test_accessor_expression_empty_base_types():
|
238
|
+
"""Test that accessor expressions handle empty base types gracefully."""
|
239
|
+
base_ref: OutputReference = OutputReference(
|
240
|
+
name="test_empty",
|
241
|
+
types=(),
|
242
|
+
instance=None,
|
243
|
+
outputs_class=BaseOutputs,
|
244
|
+
)
|
245
|
+
|
246
|
+
accessor = AccessorExpression(base=base_ref, field=0)
|
247
|
+
|
248
|
+
assert accessor.types == ()
|
@@ -251,7 +251,12 @@ def create_function_node(
|
|
251
251
|
)
|
252
252
|
else:
|
253
253
|
# For regular functions, use CodeExecutionNode approach
|
254
|
-
|
254
|
+
# function tool must be put in another file (no need to have the same name)
|
255
|
+
source_path = inspect.getmodule(function)
|
256
|
+
if source_path is not None:
|
257
|
+
function_source = inspect.getsource(source_path)
|
258
|
+
else:
|
259
|
+
function_source = f"<source code not available for {function.__name__}>"
|
255
260
|
function_name = function.__name__
|
256
261
|
|
257
262
|
code = f'''
|
@@ -10,6 +10,7 @@ from typing import Any, Callable, Dict, Type
|
|
10
10
|
from pydantic import BaseModel
|
11
11
|
|
12
12
|
from vellum.workflows.constants import undefined
|
13
|
+
from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
|
13
14
|
from vellum.workflows.inputs.base import BaseInputs
|
14
15
|
from vellum.workflows.outputs.base import BaseOutput, BaseOutputs
|
15
16
|
from vellum.workflows.ports.port import Port
|
@@ -21,6 +22,10 @@ class DefaultStateEncoder(JSONEncoder):
|
|
21
22
|
encoders: Dict[Type, Callable] = {}
|
22
23
|
|
23
24
|
def default(self, obj: Any) -> Any:
|
25
|
+
if isinstance(obj, CoalesceExpression):
|
26
|
+
empty_state = BaseState()
|
27
|
+
return self.default(obj.resolve(empty_state))
|
28
|
+
|
24
29
|
if isinstance(obj, BaseState):
|
25
30
|
return dict(obj)
|
26
31
|
|
@@ -61,9 +66,11 @@ class DefaultStateEncoder(JSONEncoder):
|
|
61
66
|
|
62
67
|
if callable(obj):
|
63
68
|
function_definition = compile_function_definition(obj)
|
64
|
-
|
65
|
-
|
66
|
-
|
69
|
+
source_path = inspect.getsourcefile(obj)
|
70
|
+
if source_path is not None:
|
71
|
+
with open(source_path, "r") as f:
|
72
|
+
source_code = f.read()
|
73
|
+
else:
|
67
74
|
source_code = f"<source code not available for {obj.__name__}>"
|
68
75
|
|
69
76
|
return {
|
@@ -50,6 +50,11 @@ def primitive_type_to_vellum_variable_type(type_: Union[Type, BaseDescriptor]) -
|
|
50
50
|
# Number now supports float and int
|
51
51
|
elif types == [float, int]:
|
52
52
|
return "NUMBER"
|
53
|
+
|
54
|
+
collapse_types = _collapse_types(types)
|
55
|
+
if len(collapse_types) == 1:
|
56
|
+
return primitive_type_to_vellum_variable_type(collapse_types[0])
|
57
|
+
|
53
58
|
raise ValueError(f"Expected Descriptor to only have one type, got {types}")
|
54
59
|
|
55
60
|
type_ = type_.types[0]
|
@@ -129,3 +134,35 @@ def _is_type_optionally_equal(type_: Type, target_type: Type) -> bool:
|
|
129
134
|
|
130
135
|
def _is_type_optionally_in(type_: Type, target_types: Tuple[Type, ...]) -> bool:
|
131
136
|
return any(_is_type_optionally_equal(type_, target_type) for target_type in target_types)
|
137
|
+
|
138
|
+
|
139
|
+
def _collapse_types(types: List[Type]) -> List[Type]:
|
140
|
+
"""
|
141
|
+
Collapses a list of types into a list of types that are not subtypes of each other.
|
142
|
+
What remains are the "most specific" types.
|
143
|
+
"""
|
144
|
+
|
145
|
+
new_types: List[Type] = []
|
146
|
+
for target_type in types:
|
147
|
+
if any(_is_subtype(source_type, target_type) for source_type in new_types):
|
148
|
+
continue
|
149
|
+
|
150
|
+
new_types.append(target_type)
|
151
|
+
|
152
|
+
return new_types
|
153
|
+
|
154
|
+
|
155
|
+
def _is_subtype(source_type: Type, target_type: Type) -> bool:
|
156
|
+
"""
|
157
|
+
Checks if `source_type` is a strict subtype of `target_type`. Meaning all values that are
|
158
|
+
of type `source_type` are also of type `target_type`.
|
159
|
+
"""
|
160
|
+
|
161
|
+
if source_type == target_type:
|
162
|
+
return True
|
163
|
+
|
164
|
+
source_origin = get_origin(source_type)
|
165
|
+
if source_origin == target_type:
|
166
|
+
return True
|
167
|
+
|
168
|
+
return False
|
@@ -84,7 +84,7 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_stat
|
|
84
84
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py,sha256=w1BYEZXIMjWmcKGQXzhelHnKFlEAXmsgjkI9fcgqKXA,5850
|
85
85
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py,sha256=-T0cd2jx1bC0ZNtAESF78fnYD_0nOqo8zMMLwRHUTRM,6227
|
86
86
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py,sha256=PZ9Yec8D6e9wM2kh5eWtNvK5BghTf1RdvoSW5_pw3FM,7384
|
87
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py,sha256=
|
87
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py,sha256=vVqxXHieRUPP1Rt4ITnjMxuGU52WBfifoEzPyHQnd7w,25618
|
88
88
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py,sha256=3Djct7lIr2TPW-wDd_t6eoNdsE0hBOj9OwKWRroXMUo,21659
|
89
89
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py,sha256=91u9FWLErrNGfUkZ22ifk6IazGtaYoDFbZYjhxEESgI,16579
|
90
90
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py,sha256=rtkAQw5awOFX3pWh0qz3f766-tTnPhToGsXVSHO4M4U,8352
|
@@ -94,8 +94,8 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_
|
|
94
94
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py,sha256=V8b6gKghLlO7PJI8xeNdnfn8aII0W_IFQvSQBQM62UQ,7721
|
95
95
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py,sha256=hDWtKXmGI1CKhTwTNqpu_d5RkE5n7SolMLtgd87KqTI,3856
|
96
96
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py,sha256=6q-lTGMp5HbQba3NsHUFSit8_zEBxIVPGE8yCw4SVx0,25720
|
97
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=
|
98
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py,sha256=
|
97
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=nG5orqTpRwx_jJDaf0Z3rPXe0SD8i4Rrp29GVmKCPBQ,9328
|
98
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py,sha256=mova0sPD3evHiHIN1O0VynxlCp-uOcEIKve5Pd_oCDg,4069
|
99
99
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py,sha256=pLCyMScV88DTBXRH7jXaXOEA1GBq8NIipCUFwIAWnwI,2771
|
100
100
|
vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py,sha256=J4ouI8KxbMfxQP2Zq_9cWMGYgbjCWmKzjCJEtnSJb0I,5829
|
101
101
|
vellum_ee/workflows/display/tests/workflow_serialization/test_workflow_input_parameterization_error.py,sha256=vAdmn3YTBDpo55znbydQxsgg9ASqHcvsUPwiBR_7wfo,1461
|
@@ -103,7 +103,7 @@ vellum_ee/workflows/display/types.py,sha256=i4T7ElU5b5h-nA1i3scmEhO1BqmNDc4eJDHa
|
|
103
103
|
vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
104
104
|
vellum_ee/workflows/display/utils/auto_layout.py,sha256=f4GiLn_LazweupfqTpubcdtdfE_vrOcmZudSsnYIY9E,3906
|
105
105
|
vellum_ee/workflows/display/utils/exceptions.py,sha256=LSwwxCYNxFkf5XMUcFkaZKpQ13OSrI7y_bpEUwbKVk0,169
|
106
|
-
vellum_ee/workflows/display/utils/expressions.py,sha256=
|
106
|
+
vellum_ee/workflows/display/utils/expressions.py,sha256=H5_yWpX4QQNr83iIIocOHddTpktsHbVDp1ylayvjjTE,15840
|
107
107
|
vellum_ee/workflows/display/utils/registry.py,sha256=fWIm5Jj-10gNFjgn34iBu4RWv3Vd15ijtSN0V97bpW8,1513
|
108
108
|
vellum_ee/workflows/display/utils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
109
109
|
vellum_ee/workflows/display/utils/tests/test_auto_layout.py,sha256=vfXI769418s9vda5Gb5NFBH747WMOwSgHRXeLCTLVm8,2356
|
@@ -144,7 +144,7 @@ vellum/client/README.md,sha256=CuGUYnaE0Imt0KqQ4sIPaUghCjLHkF3DdEvZWu14-8s,4807
|
|
144
144
|
vellum/client/__init__.py,sha256=AYopGv2ZRVn3zsU8_km6KOvEHDbXiTPCVuYVI7bWvdA,120166
|
145
145
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
146
146
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
147
|
-
vellum/client/core/client_wrapper.py,sha256=
|
147
|
+
vellum/client/core/client_wrapper.py,sha256=WsBBC0YLC-9nYHit_KXXwpCcD6m2VY4xxUFnXvAE9Zw,1869
|
148
148
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
149
149
|
vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
150
150
|
vellum/client/core/http_client.py,sha256=Z77OIxIbL4OAB2IDqjRq_sYa5yNYAWfmdhdCSSvh6Y4,19552
|
@@ -834,13 +834,16 @@ vellum/evaluations/utils/env.py,sha256=Xj_nxsoU5ox06EOTjRopR4lrigQI6Le6qbWGltYoE
|
|
834
834
|
vellum/evaluations/utils/exceptions.py,sha256=dXMAkzqbHV_AP5FjjbegPlfUE0zQDlpA3qOsoOJUxfg,49
|
835
835
|
vellum/evaluations/utils/paginator.py,sha256=rEED_BJAXAM6tM1yMwHePNzszjq_tTq4NbQvi1jWQ_Q,697
|
836
836
|
vellum/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
837
|
-
vellum/plugins/pydantic.py,sha256=
|
837
|
+
vellum/plugins/pydantic.py,sha256=GmNsxupKskbqpe4N5NBmSnLo680EATqhXJHABgf1NO0,3727
|
838
|
+
vellum/plugins/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
839
|
+
vellum/plugins/tests/test_pydantic.py,sha256=S6bLqs3Y5DGA012QV_7f6hk4e6Bz-iJ9py9DEKuo4fM,746
|
838
840
|
vellum/plugins/utils.py,sha256=cPmxE9R2CK1bki2jKE8rB-G9zMf2pzHjSPDHFPXwd3Q,878
|
839
841
|
vellum/plugins/vellum_mypy.py,sha256=hfjC2rIxNdQuJa6fIN4PDgODnQ3YaUszyaV2eNbLJlE,27952
|
840
|
-
vellum/prompts/__init__.py,sha256=
|
841
|
-
vellum/prompts/blocks/__init__.py,sha256=
|
842
|
+
vellum/prompts/__init__.py,sha256=kn-btvQOMNnnBuyQiUpie48_VBJAk7tFFU-ul5dwK60,107
|
843
|
+
vellum/prompts/blocks/__init__.py,sha256=Zwvncjd8sUCPmT-8pFpgLYsKJl0xB6td1GTQzjV9hYA,108
|
842
844
|
vellum/prompts/blocks/compilation.py,sha256=qeC_4La5auQkm4EyzCMpN34F5R8mjiGcLV7IxKgVf3k,9973
|
843
845
|
vellum/prompts/blocks/exceptions.py,sha256=vmk5PV6Vyw9nKjZYQDUDW0LH8MfQNIgFvFb_mFWdIRI,50
|
846
|
+
vellum/prompts/blocks/helpers.py,sha256=7G1Qi6N3V1K73iqTypMTcl6Rum7wk449yHStkakLy-U,961
|
844
847
|
vellum/prompts/blocks/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
845
848
|
vellum/prompts/blocks/tests/test_compilation.py,sha256=EOUtdzJDFGbGhoc_y5XTMyO0HOpOM7FYJssPzd_yRVg,5235
|
846
849
|
vellum/prompts/blocks/types.py,sha256=6aSJQco-5kKeadfKVVXF_SrQPlIJgMYVNc-C7so1sY8,975
|
@@ -1528,7 +1531,7 @@ vellum/workflows/events/types.py,sha256=LwgFlMRbptJvdPtPO1POUtGtbhGw7BSuvgHxNSgS
|
|
1528
1531
|
vellum/workflows/events/workflow.py,sha256=7rb1evKsTCRUdCnisAM5Anc19ZKGxnsmzwOOv6jwWEI,7761
|
1529
1532
|
vellum/workflows/exceptions.py,sha256=NiBiR3ggfmPxBVqD-H1SqmjI-7mIn0EStSN1BqApvCM,1213
|
1530
1533
|
vellum/workflows/expressions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1531
|
-
vellum/workflows/expressions/accessor.py,sha256=
|
1534
|
+
vellum/workflows/expressions/accessor.py,sha256=4OvF9JQKHSyYLTz7gGprcw3Da5-zA8D0Co0j1eIeer0,4141
|
1532
1535
|
vellum/workflows/expressions/and_.py,sha256=I7lNqrUM3-m_5hmjjiMhaHhJtKcLj39kEFVWPDOqwfo,916
|
1533
1536
|
vellum/workflows/expressions/begins_with.py,sha256=FnWsQXbENm0ZwkfEP7dR8Qx4_MMrzj6C1yqAV2KaNHw,1123
|
1534
1537
|
vellum/workflows/expressions/between.py,sha256=dVeddT6YA91eOAlE1Utg7C7gnCiYE7WP-dg17yXUeAY,1492
|
@@ -1559,7 +1562,7 @@ vellum/workflows/expressions/not_in.py,sha256=pFvwkFPsn3WJw61ssFgM2U1dqWEeglfz4F
|
|
1559
1562
|
vellum/workflows/expressions/or_.py,sha256=s-8YdMSSCDS2yijR38kguwok3iqmDMMgDYKV93b4O4s,914
|
1560
1563
|
vellum/workflows/expressions/parse_json.py,sha256=xsk6j3HF7bU1yF6fwt5P9Ugcyd5D9ZXrdng11FRilUI,1088
|
1561
1564
|
vellum/workflows/expressions/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1562
|
-
vellum/workflows/expressions/tests/test_accessor.py,sha256=
|
1565
|
+
vellum/workflows/expressions/tests/test_accessor.py,sha256=g2z0mJjuWwVKeXS0yGoFW-aRmT5n_LrhfuBorSmj9kI,7585
|
1563
1566
|
vellum/workflows/expressions/tests/test_expressions.py,sha256=3b6k8xs-CItBBw95NygFLUNoNPKxI4VA1GyWbkMtqyI,11623
|
1564
1567
|
vellum/workflows/expressions/tests/test_parse_json.py,sha256=zpB_qE5_EwWQL7ULQUJm0o1PRSfWZdAqZNW6Ah13oJE,1059
|
1565
1568
|
vellum/workflows/graph/__init__.py,sha256=3sHlay5d_-uD7j3QJXiGl0WHFZZ_QScRvgyDhN2GhHY,74
|
@@ -1674,7 +1677,7 @@ vellum/workflows/nodes/experimental/tool_calling_node/node.py,sha256=jwL1sbitmm1
|
|
1674
1677
|
vellum/workflows/nodes/experimental/tool_calling_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1675
1678
|
vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py,sha256=XK1H_QAT_nVFmFP442RYyPvpTfSgtU6kSGu3-OQPBNU,5072
|
1676
1679
|
vellum/workflows/nodes/experimental/tool_calling_node/tests/test_utils.py,sha256=-g90SdXscuikF7JP0lFGvSvPc8jl2vBuHwBeiYJIiXk,1719
|
1677
|
-
vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=
|
1680
|
+
vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=t18ye2wY9jtTjKXJs8oChNGI5xCdxlUUyVYbRJfJLFI,12959
|
1678
1681
|
vellum/workflows/nodes/mocks.py,sha256=a1FjWEIocseMfjzM-i8DNozpUsaW0IONRpZmXBoWlyc,10455
|
1679
1682
|
vellum/workflows/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1680
1683
|
vellum/workflows/nodes/tests/test_mocks.py,sha256=mfPvrs75PKcsNsbJLQAN6PDFoVqs9TmQxpdyFKDdO60,7837
|
@@ -1707,7 +1710,7 @@ vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2
|
|
1707
1710
|
vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
|
1708
1711
|
vellum/workflows/state/base.py,sha256=WIMJYyuHUrP4zt0Nudk66HAK1L6GgGmsU_GQp7BGE2U,22189
|
1709
1712
|
vellum/workflows/state/context.py,sha256=KOAI1wEGn8dGmhmAemJaf4SZbitP3jpIBcwKfznQaRE,3076
|
1710
|
-
vellum/workflows/state/encoder.py,sha256=
|
1713
|
+
vellum/workflows/state/encoder.py,sha256=xtKpDAR5qWbxIN61dz3X_5_D47MTrbvvas8n15jys18,2881
|
1711
1714
|
vellum/workflows/state/store.py,sha256=uVe-oN73KwGV6M6YLhwZMMUQhzTQomsVfVnb8V91gVo,1147
|
1712
1715
|
vellum/workflows/state/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1713
1716
|
vellum/workflows/state/tests/test_state.py,sha256=YOiC9qZAzkdiqb7nRarNWeDwxo7xHv3y3czlHl81ezg,6741
|
@@ -1734,7 +1737,7 @@ vellum/workflows/utils/tests/test_names.py,sha256=aOqpyvMsOEK_9mg_-yaNxQDW7QQfwq
|
|
1734
1737
|
vellum/workflows/utils/tests/test_uuids.py,sha256=i77ABQ0M3S-aFLzDXHJq_yr5FPkJEWCMBn1HJ3DObrE,437
|
1735
1738
|
vellum/workflows/utils/tests/test_vellum_variables.py,sha256=vbnKgm41aB5OXlO-ZIPbhQ6xDiZkT8KMxCLqz4zocWY,1791
|
1736
1739
|
vellum/workflows/utils/uuids.py,sha256=DFzPv9RCvsKhvdTEIQyfSek2A31D6S_QcmeLPbgrgTY,739
|
1737
|
-
vellum/workflows/utils/vellum_variables.py,sha256=
|
1740
|
+
vellum/workflows/utils/vellum_variables.py,sha256=zVzZSRWKV64fmu9MaoEVebW9r8UsXPvRPMvOuBmwI24,5307
|
1738
1741
|
vellum/workflows/vellum_client.py,sha256=xkfoucodxNK5JR2-lbRqZx3xzDgExWkP6kySrpi_Ubc,1079
|
1739
1742
|
vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
|
1740
1743
|
vellum/workflows/workflows/base.py,sha256=ehJSHDf1vuNjJtKryqKgb5HKGtx_D-wWUiJNBWZ50JU,24347
|
@@ -1742,8 +1745,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
|
|
1742
1745
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1743
1746
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=fROqff6AZpCIzaSwOKSdtYy4XR0UZQ6ejxL3RJOSJVs,20447
|
1744
1747
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1745
|
-
vellum_ai-0.14.
|
1746
|
-
vellum_ai-0.14.
|
1747
|
-
vellum_ai-0.14.
|
1748
|
-
vellum_ai-0.14.
|
1749
|
-
vellum_ai-0.14.
|
1748
|
+
vellum_ai-0.14.78.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1749
|
+
vellum_ai-0.14.78.dist-info/METADATA,sha256=xCf9xhdMAXgdPDg2CNV4V4OD2yv1oviC8QRS5hi8IIk,5556
|
1750
|
+
vellum_ai-0.14.78.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1751
|
+
vellum_ai-0.14.78.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1752
|
+
vellum_ai-0.14.78.dist-info/RECORD,,
|
@@ -1,6 +1,9 @@
|
|
1
|
+
from typing import List
|
2
|
+
|
1
3
|
from deepdiff import DeepDiff
|
2
4
|
|
3
5
|
from vellum import ChatMessagePromptBlock, FunctionDefinition, JinjaPromptBlock
|
6
|
+
from vellum.client.types.chat_message import ChatMessage
|
4
7
|
from vellum.workflows import BaseWorkflow
|
5
8
|
from vellum.workflows.inputs import BaseInputs
|
6
9
|
from vellum.workflows.nodes import InlinePromptNode
|
@@ -554,3 +557,52 @@ def test_serialize_workflow_with_nested_descriptor_blocks():
|
|
554
557
|
"type": "DICTIONARY_REFERENCE",
|
555
558
|
}
|
556
559
|
]
|
560
|
+
|
561
|
+
|
562
|
+
def test_inline_prompt_node__coalesce_expression_serialization():
|
563
|
+
"""
|
564
|
+
Tests that prompt nodes can serialize coalesce expressions like State.chat_history.coalesce([]).
|
565
|
+
"""
|
566
|
+
|
567
|
+
# GIVEN a custom state with chat_history
|
568
|
+
class MyState(BaseState):
|
569
|
+
chat_history: List[ChatMessage] = []
|
570
|
+
|
571
|
+
# AND a prompt node that uses a coalesce expression as input
|
572
|
+
class MyNode(InlinePromptNode[MyState]):
|
573
|
+
ml_model = "gpt-4o"
|
574
|
+
blocks = []
|
575
|
+
prompt_inputs = {
|
576
|
+
"chat_history": MyState.chat_history.coalesce([]),
|
577
|
+
}
|
578
|
+
|
579
|
+
class TestWorkflow(BaseWorkflow[BaseInputs, MyState]):
|
580
|
+
graph = MyNode
|
581
|
+
|
582
|
+
# WHEN the node is serialized
|
583
|
+
workflow_display = get_workflow_display(workflow_class=TestWorkflow)
|
584
|
+
serialized: dict = workflow_display.serialize()
|
585
|
+
|
586
|
+
# THEN the prompt is serialized with the correct inputs
|
587
|
+
prompt_nodes = [node for node in serialized["workflow_raw_data"]["nodes"] if node["type"] == "PROMPT"]
|
588
|
+
prompt_node = prompt_nodes[0]
|
589
|
+
|
590
|
+
prompt_inputs_attr = next((attr for attr in prompt_node["attributes"] if attr["name"] == "prompt_inputs"), None)
|
591
|
+
assert prompt_inputs_attr
|
592
|
+
assert prompt_inputs_attr["value"]["type"] == "DICTIONARY_REFERENCE"
|
593
|
+
chat_history_entry = prompt_inputs_attr["value"]["entries"][0]
|
594
|
+
|
595
|
+
assert chat_history_entry["key"] == "chat_history"
|
596
|
+
assert chat_history_entry["value"]["type"] == "BINARY_EXPRESSION"
|
597
|
+
assert chat_history_entry["value"]["operator"] == "coalesce"
|
598
|
+
assert chat_history_entry["value"]["lhs"] == {
|
599
|
+
"type": "WORKFLOW_STATE",
|
600
|
+
"state_variable_id": "6012a4f7-a8ff-464d-bd62-7c41fde06fa4",
|
601
|
+
}
|
602
|
+
assert chat_history_entry["value"]["rhs"] == {
|
603
|
+
"type": "CONSTANT_VALUE",
|
604
|
+
"value": {
|
605
|
+
"type": "JSON",
|
606
|
+
"value": [],
|
607
|
+
},
|
608
|
+
}
|
@@ -146,7 +146,7 @@ def test_serialize_workflow():
|
|
146
146
|
"forced": None,
|
147
147
|
"strict": None,
|
148
148
|
},
|
149
|
-
"src": '
|
149
|
+
"src": 'import math\n\n\ndef get_current_weather(location: str, unit: str) -> str:\n """\n Get the current weather in a given location.\n """\n return f"The current weather in {location} is sunny with a temperature of {get_temperature(70.1)} degrees {unit}."\n\n\ndef get_temperature(temperature: float) -> int:\n """\n Get the temperature in a given location.\n """\n return math.floor(temperature)\n', # noqa: E501
|
150
150
|
}
|
151
151
|
],
|
152
152
|
},
|
@@ -1,5 +1,16 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
|
1
3
|
from deepdiff import DeepDiff
|
2
4
|
|
5
|
+
from vellum.client.types.release_environment import ReleaseEnvironment
|
6
|
+
from vellum.client.types.release_release_tag import ReleaseReleaseTag
|
7
|
+
from vellum.client.types.release_review_reviewer import ReleaseReviewReviewer
|
8
|
+
from vellum.client.types.slim_release_review import SlimReleaseReview
|
9
|
+
from vellum.client.types.workflow_deployment_release import WorkflowDeploymentRelease
|
10
|
+
from vellum.client.types.workflow_deployment_release_workflow_deployment import (
|
11
|
+
WorkflowDeploymentReleaseWorkflowDeployment,
|
12
|
+
)
|
13
|
+
from vellum.client.types.workflow_deployment_release_workflow_version import WorkflowDeploymentReleaseWorkflowVersion
|
3
14
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
4
15
|
|
5
16
|
from tests.workflows.basic_tool_calling_node_workflow_deployment.workflow import (
|
@@ -7,7 +18,41 @@ from tests.workflows.basic_tool_calling_node_workflow_deployment.workflow import
|
|
7
18
|
)
|
8
19
|
|
9
20
|
|
10
|
-
def test_serialize_workflow():
|
21
|
+
def test_serialize_workflow(vellum_client):
|
22
|
+
vellum_client.release_reviews.retrieve_workflow_deployment_release.return_value = WorkflowDeploymentRelease(
|
23
|
+
id="test-id",
|
24
|
+
created=datetime.now(),
|
25
|
+
environment=ReleaseEnvironment(
|
26
|
+
id="test-id",
|
27
|
+
name="test-name",
|
28
|
+
label="test-label",
|
29
|
+
),
|
30
|
+
created_by=None,
|
31
|
+
workflow_version=WorkflowDeploymentReleaseWorkflowVersion(
|
32
|
+
id="test-id",
|
33
|
+
input_variables=[],
|
34
|
+
output_variables=[],
|
35
|
+
),
|
36
|
+
deployment=WorkflowDeploymentReleaseWorkflowDeployment(name="test-name"),
|
37
|
+
description="test-description", # main mock
|
38
|
+
release_tags=[
|
39
|
+
ReleaseReleaseTag(
|
40
|
+
name="test-name",
|
41
|
+
source="USER",
|
42
|
+
)
|
43
|
+
],
|
44
|
+
reviews=[
|
45
|
+
SlimReleaseReview(
|
46
|
+
id="test-id",
|
47
|
+
created=datetime.now(),
|
48
|
+
reviewer=ReleaseReviewReviewer(
|
49
|
+
id="test-id",
|
50
|
+
full_name="test-name",
|
51
|
+
),
|
52
|
+
state="APPROVED",
|
53
|
+
)
|
54
|
+
],
|
55
|
+
)
|
11
56
|
# GIVEN a Workflow that uses a generic node
|
12
57
|
# WHEN we serialize it
|
13
58
|
workflow_display = get_workflow_display(workflow_class=BasicToolCallingNodeWorkflowDeploymentWorkflow)
|
@@ -51,8 +96,8 @@ def test_serialize_workflow():
|
|
51
96
|
"value": [
|
52
97
|
{
|
53
98
|
"type": "WORKFLOW_DEPLOYMENT",
|
54
|
-
"name": "
|
55
|
-
"description": "
|
99
|
+
"name": "test-name",
|
100
|
+
"description": "test-description",
|
56
101
|
"deployment": "deployment_1",
|
57
102
|
"release_tag": "LATEST",
|
58
103
|
}
|
@@ -346,14 +346,20 @@ def serialize_value(display_context: "WorkflowDisplayContext", value: Any) -> Js
|
|
346
346
|
}
|
347
347
|
|
348
348
|
if isinstance(value, DeploymentDefinition):
|
349
|
+
workflow_deployment_release = display_context.client.release_reviews.retrieve_workflow_deployment_release(
|
350
|
+
value.deployment, value.release_tag
|
351
|
+
)
|
352
|
+
name = workflow_deployment_release.deployment.name or value.deployment
|
353
|
+
description = workflow_deployment_release.description or f"Workflow Deployment for {name}"
|
354
|
+
|
349
355
|
return {
|
350
356
|
"type": "CONSTANT_VALUE",
|
351
357
|
"value": {
|
352
358
|
"type": "JSON",
|
353
359
|
"value": {
|
354
360
|
"type": "WORKFLOW_DEPLOYMENT",
|
355
|
-
"name":
|
356
|
-
"description":
|
361
|
+
"name": name,
|
362
|
+
"description": description,
|
357
363
|
"deployment": value.deployment,
|
358
364
|
"release_tag": value.release_tag,
|
359
365
|
},
|
File without changes
|
File without changes
|
File without changes
|