vellum-ai 1.0.10__py3-none-any.whl → 1.0.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vellum/client/core/client_wrapper.py +2 -2
- vellum/workflows/descriptors/base.py +31 -1
- vellum/workflows/descriptors/utils.py +19 -1
- vellum/workflows/expressions/accessor.py +23 -15
- vellum/workflows/expressions/add.py +41 -0
- vellum/workflows/expressions/length.py +35 -0
- vellum/workflows/expressions/minus.py +41 -0
- vellum/workflows/expressions/tests/test_add.py +72 -0
- vellum/workflows/expressions/tests/test_length.py +38 -0
- vellum/workflows/expressions/tests/test_minus.py +72 -0
- vellum/workflows/integrations/composio_service.py +4 -0
- vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +1 -1
- vellum/workflows/nodes/displayable/inline_prompt_node/node.py +2 -2
- vellum/workflows/nodes/displayable/tool_calling_node/node.py +6 -1
- vellum/workflows/nodes/displayable/tool_calling_node/state.py +2 -0
- vellum/workflows/nodes/displayable/tool_calling_node/tests/test_composio_service.py +49 -0
- vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py +3 -8
- vellum/workflows/nodes/displayable/tool_calling_node/utils.py +92 -50
- vellum/workflows/types/definition.py +1 -6
- vellum/workflows/types/tests/test_definition.py +1 -1
- {vellum_ai-1.0.10.dist-info → vellum_ai-1.0.11.dist-info}/METADATA +1 -1
- {vellum_ai-1.0.10.dist-info → vellum_ai-1.0.11.dist-info}/RECORD +27 -21
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_composio_serialization.py +0 -4
- vellum_ee/workflows/display/utils/expressions.py +12 -0
- {vellum_ai-1.0.10.dist-info → vellum_ai-1.0.11.dist-info}/LICENSE +0 -0
- {vellum_ai-1.0.10.dist-info → vellum_ai-1.0.11.dist-info}/WHEEL +0 -0
- {vellum_ai-1.0.10.dist-info → vellum_ai-1.0.11.dist-info}/entry_points.txt +0 -0
@@ -25,10 +25,10 @@ class BaseClientWrapper:
|
|
25
25
|
|
26
26
|
def get_headers(self) -> typing.Dict[str, str]:
|
27
27
|
headers: typing.Dict[str, str] = {
|
28
|
-
"User-Agent": "vellum-ai/1.0.
|
28
|
+
"User-Agent": "vellum-ai/1.0.11",
|
29
29
|
"X-Fern-Language": "Python",
|
30
30
|
"X-Fern-SDK-Name": "vellum-ai",
|
31
|
-
"X-Fern-SDK-Version": "1.0.
|
31
|
+
"X-Fern-SDK-Version": "1.0.11",
|
32
32
|
}
|
33
33
|
if self._api_version is not None:
|
34
34
|
headers["X-API-Version"] = self._api_version
|
@@ -2,6 +2,7 @@ from typing import TYPE_CHECKING, Any, Generic, Optional, Tuple, Type, TypeVar,
|
|
2
2
|
|
3
3
|
if TYPE_CHECKING:
|
4
4
|
from vellum.workflows.expressions.accessor import AccessorExpression
|
5
|
+
from vellum.workflows.expressions.add import AddExpression
|
5
6
|
from vellum.workflows.expressions.and_ import AndExpression
|
6
7
|
from vellum.workflows.expressions.begins_with import BeginsWithExpression
|
7
8
|
from vellum.workflows.expressions.between import BetweenExpression
|
@@ -26,8 +27,10 @@ if TYPE_CHECKING:
|
|
26
27
|
from vellum.workflows.expressions.is_not_undefined import IsNotUndefinedExpression
|
27
28
|
from vellum.workflows.expressions.is_null import IsNullExpression
|
28
29
|
from vellum.workflows.expressions.is_undefined import IsUndefinedExpression
|
30
|
+
from vellum.workflows.expressions.length import LengthExpression
|
29
31
|
from vellum.workflows.expressions.less_than import LessThanExpression
|
30
32
|
from vellum.workflows.expressions.less_than_or_equal_to import LessThanOrEqualToExpression
|
33
|
+
from vellum.workflows.expressions.minus import MinusExpression
|
31
34
|
from vellum.workflows.expressions.not_between import NotBetweenExpression
|
32
35
|
from vellum.workflows.expressions.not_in import NotInExpression
|
33
36
|
from vellum.workflows.expressions.or_ import OrExpression
|
@@ -127,7 +130,7 @@ class BaseDescriptor(Generic[_T]):
|
|
127
130
|
|
128
131
|
return CoalesceExpression(lhs=self, rhs=other)
|
129
132
|
|
130
|
-
def __getitem__(self, field: Union[str, int]) -> "AccessorExpression":
|
133
|
+
def __getitem__(self, field: Union[str, int, "BaseDescriptor[str]", "BaseDescriptor[int]"]) -> "AccessorExpression":
|
131
134
|
from vellum.workflows.expressions.accessor import AccessorExpression
|
132
135
|
|
133
136
|
return AccessorExpression(base=self, field=field)
|
@@ -376,3 +379,30 @@ class BaseDescriptor(Generic[_T]):
|
|
376
379
|
from vellum.workflows.expressions.concat import ConcatExpression
|
377
380
|
|
378
381
|
return ConcatExpression(lhs=self, rhs=other)
|
382
|
+
|
383
|
+
def length(self) -> "LengthExpression[_T]":
|
384
|
+
from vellum.workflows.expressions.length import LengthExpression
|
385
|
+
|
386
|
+
return LengthExpression(expression=self)
|
387
|
+
|
388
|
+
@overload
|
389
|
+
def add(self, other: "BaseDescriptor[_O]") -> "AddExpression[_T, _O]": ...
|
390
|
+
|
391
|
+
@overload
|
392
|
+
def add(self, other: _O) -> "AddExpression[_T, _O]": ...
|
393
|
+
|
394
|
+
def add(self, other: "Union[BaseDescriptor[_O], _O]") -> "AddExpression[_T, _O]":
|
395
|
+
from vellum.workflows.expressions.add import AddExpression
|
396
|
+
|
397
|
+
return AddExpression(lhs=self, rhs=other)
|
398
|
+
|
399
|
+
@overload
|
400
|
+
def minus(self, other: "BaseDescriptor[_O]") -> "MinusExpression[_T, _O]": ...
|
401
|
+
|
402
|
+
@overload
|
403
|
+
def minus(self, other: _O) -> "MinusExpression[_T, _O]": ...
|
404
|
+
|
405
|
+
def minus(self, other: "Union[BaseDescriptor[_O], _O]") -> "MinusExpression[_T, _O]":
|
406
|
+
from vellum.workflows.expressions.minus import MinusExpression
|
407
|
+
|
408
|
+
return MinusExpression(lhs=self, rhs=other)
|
@@ -1,7 +1,8 @@
|
|
1
1
|
from collections.abc import Mapping
|
2
2
|
import dataclasses
|
3
3
|
import inspect
|
4
|
-
from typing import Any, Dict, Optional, Sequence, Set, TypeVar, Union, cast, overload
|
4
|
+
from typing import Any, Dict, Optional, Sequence, Set, Type, TypeVar, Union, cast, overload
|
5
|
+
from typing_extensions import TypeGuard
|
5
6
|
|
6
7
|
from pydantic import BaseModel
|
7
8
|
|
@@ -115,3 +116,20 @@ def is_unresolved(value: Any) -> bool:
|
|
115
116
|
return any(is_unresolved(item) for item in value)
|
116
117
|
|
117
118
|
return False
|
119
|
+
|
120
|
+
|
121
|
+
_ResolvedType = TypeVar("_ResolvedType")
|
122
|
+
|
123
|
+
|
124
|
+
def is_resolved_instance(value: Any, type_: Type[_ResolvedType]) -> TypeGuard[_ResolvedType]:
|
125
|
+
"""
|
126
|
+
Checks if a value is an instance of a type or a descriptor that resolves to that type.
|
127
|
+
"""
|
128
|
+
|
129
|
+
if isinstance(value, type_):
|
130
|
+
return True
|
131
|
+
|
132
|
+
if isinstance(value, BaseDescriptor) and value.types:
|
133
|
+
return issubclass(value.types[0], type_)
|
134
|
+
|
135
|
+
return False
|
@@ -7,10 +7,11 @@ from pydantic_core import core_schema
|
|
7
7
|
|
8
8
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
9
9
|
from vellum.workflows.descriptors.exceptions import InvalidExpressionException
|
10
|
-
from vellum.workflows.descriptors.utils import resolve_value
|
10
|
+
from vellum.workflows.descriptors.utils import is_resolved_instance, resolve_value
|
11
11
|
from vellum.workflows.state.base import BaseState
|
12
12
|
|
13
13
|
LHS = TypeVar("LHS")
|
14
|
+
AccessorField = Union[str, int, BaseDescriptor[str], BaseDescriptor[int]]
|
14
15
|
|
15
16
|
|
16
17
|
class AccessorExpression(BaseDescriptor[Any]):
|
@@ -18,7 +19,7 @@ class AccessorExpression(BaseDescriptor[Any]):
|
|
18
19
|
self,
|
19
20
|
*,
|
20
21
|
base: BaseDescriptor[LHS],
|
21
|
-
field:
|
22
|
+
field: AccessorField,
|
22
23
|
) -> None:
|
23
24
|
super().__init__(
|
24
25
|
name=f"{base.name}.{field}",
|
@@ -28,7 +29,7 @@ class AccessorExpression(BaseDescriptor[Any]):
|
|
28
29
|
self._base = base
|
29
30
|
self._field = field
|
30
31
|
|
31
|
-
def _infer_accessor_types(self, base: BaseDescriptor[LHS], field:
|
32
|
+
def _infer_accessor_types(self, base: BaseDescriptor[LHS], field: AccessorField) -> tuple[Type, ...]:
|
32
33
|
"""
|
33
34
|
Infer the types for this accessor expression based on the base descriptor's types
|
34
35
|
and the field being accessed.
|
@@ -42,7 +43,7 @@ class AccessorExpression(BaseDescriptor[Any]):
|
|
42
43
|
origin = get_origin(base_type)
|
43
44
|
args = get_args(base_type)
|
44
45
|
|
45
|
-
if
|
46
|
+
if is_resolved_instance(field, int) and origin in (list, tuple) and args:
|
46
47
|
if origin is list:
|
47
48
|
inferred_types.append(args[0])
|
48
49
|
elif origin is tuple and len(args) == 2 and args[1] is ...:
|
@@ -52,44 +53,51 @@ class AccessorExpression(BaseDescriptor[Any]):
|
|
52
53
|
inferred_types.append(args[field])
|
53
54
|
else:
|
54
55
|
inferred_types.append(args[field])
|
55
|
-
elif
|
56
|
+
elif is_resolved_instance(field, str) and origin in (dict,) and len(args) >= 2:
|
56
57
|
inferred_types.append(args[1]) # Value type from Dict[K, V]
|
57
58
|
|
58
59
|
return tuple(set(inferred_types)) if inferred_types else ()
|
59
60
|
|
60
61
|
def resolve(self, state: "BaseState") -> Any:
|
61
62
|
base = resolve_value(self._base, state)
|
63
|
+
accessor_field = resolve_value(self._field, state)
|
62
64
|
|
63
65
|
if dataclasses.is_dataclass(base):
|
64
|
-
if isinstance(
|
66
|
+
if isinstance(accessor_field, int):
|
65
67
|
raise InvalidExpressionException("Cannot access field by index on a dataclass")
|
66
68
|
|
67
69
|
try:
|
68
|
-
return getattr(base,
|
70
|
+
return getattr(base, accessor_field)
|
69
71
|
except AttributeError:
|
70
|
-
raise InvalidExpressionException(
|
72
|
+
raise InvalidExpressionException(
|
73
|
+
f"Field '{accessor_field}' not found on dataclass {type(base).__name__}"
|
74
|
+
)
|
71
75
|
|
72
76
|
if isinstance(base, BaseModel):
|
73
|
-
if isinstance(
|
77
|
+
if isinstance(accessor_field, int):
|
74
78
|
raise InvalidExpressionException("Cannot access field by index on a BaseModel")
|
75
79
|
|
76
80
|
try:
|
77
|
-
return getattr(base,
|
81
|
+
return getattr(base, accessor_field)
|
78
82
|
except AttributeError:
|
79
|
-
raise InvalidExpressionException(
|
83
|
+
raise InvalidExpressionException(
|
84
|
+
f"Field '{accessor_field}' not found on BaseModel {type(base).__name__}"
|
85
|
+
)
|
80
86
|
|
81
87
|
if isinstance(base, Mapping):
|
82
88
|
try:
|
83
|
-
return base[
|
89
|
+
return base[accessor_field]
|
84
90
|
except KeyError:
|
85
|
-
raise InvalidExpressionException(f"Key '{
|
91
|
+
raise InvalidExpressionException(f"Key '{accessor_field}' not found in mapping")
|
86
92
|
|
87
93
|
if isinstance(base, Sequence):
|
88
94
|
try:
|
89
|
-
index = int(
|
95
|
+
index = int(accessor_field)
|
90
96
|
return base[index]
|
91
97
|
except (IndexError, ValueError):
|
92
|
-
if isinstance(
|
98
|
+
if isinstance(accessor_field, int) or (
|
99
|
+
isinstance(accessor_field, str) and accessor_field.lstrip("-").isdigit()
|
100
|
+
):
|
93
101
|
raise InvalidExpressionException(
|
94
102
|
f"Index {self._field} is out of bounds for sequence of length {len(base)}"
|
95
103
|
)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
from typing import Any, Generic, Protocol, TypeVar, Union, runtime_checkable
|
2
|
+
from typing_extensions import TypeGuard
|
3
|
+
|
4
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
5
|
+
from vellum.workflows.descriptors.exceptions import InvalidExpressionException
|
6
|
+
from vellum.workflows.descriptors.utils import resolve_value
|
7
|
+
from vellum.workflows.state.base import BaseState
|
8
|
+
|
9
|
+
|
10
|
+
@runtime_checkable
|
11
|
+
class SupportsAdd(Protocol):
|
12
|
+
def __add__(self, other: Any) -> Any: ...
|
13
|
+
|
14
|
+
|
15
|
+
def has_add(obj: Any) -> TypeGuard[SupportsAdd]:
|
16
|
+
return hasattr(obj, "__add__")
|
17
|
+
|
18
|
+
|
19
|
+
LHS = TypeVar("LHS")
|
20
|
+
RHS = TypeVar("RHS")
|
21
|
+
|
22
|
+
|
23
|
+
class AddExpression(BaseDescriptor[Any], Generic[LHS, RHS]):
|
24
|
+
def __init__(
|
25
|
+
self,
|
26
|
+
*,
|
27
|
+
lhs: Union[BaseDescriptor[LHS], LHS],
|
28
|
+
rhs: Union[BaseDescriptor[RHS], RHS],
|
29
|
+
) -> None:
|
30
|
+
super().__init__(name=f"{lhs} + {rhs}", types=(object,))
|
31
|
+
self._lhs = lhs
|
32
|
+
self._rhs = rhs
|
33
|
+
|
34
|
+
def resolve(self, state: "BaseState") -> Any:
|
35
|
+
lhs = resolve_value(self._lhs, state)
|
36
|
+
rhs = resolve_value(self._rhs, state)
|
37
|
+
|
38
|
+
if not has_add(lhs):
|
39
|
+
raise InvalidExpressionException(f"'{lhs.__class__.__name__}' must support the '+' operator")
|
40
|
+
|
41
|
+
return lhs + rhs
|
@@ -0,0 +1,35 @@
|
|
1
|
+
from typing import Generic, TypeVar, Union
|
2
|
+
|
3
|
+
from vellum.workflows.constants import undefined
|
4
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
5
|
+
from vellum.workflows.descriptors.exceptions import InvalidExpressionException
|
6
|
+
from vellum.workflows.descriptors.utils import resolve_value
|
7
|
+
from vellum.workflows.state.base import BaseState
|
8
|
+
|
9
|
+
_T = TypeVar("_T")
|
10
|
+
|
11
|
+
|
12
|
+
class LengthExpression(BaseDescriptor[int], Generic[_T]):
|
13
|
+
def __init__(
|
14
|
+
self,
|
15
|
+
*,
|
16
|
+
expression: Union[BaseDescriptor[_T], _T],
|
17
|
+
) -> None:
|
18
|
+
super().__init__(name=f"length({expression})", types=(int,))
|
19
|
+
self._expression = expression
|
20
|
+
|
21
|
+
def resolve(self, state: "BaseState") -> int:
|
22
|
+
expression = resolve_value(self._expression, state)
|
23
|
+
|
24
|
+
if expression is undefined:
|
25
|
+
raise InvalidExpressionException("Cannot get length of undefined value")
|
26
|
+
|
27
|
+
if not hasattr(expression, "__len__"):
|
28
|
+
raise InvalidExpressionException(
|
29
|
+
f"Expected an object that supports `len()`, got `{expression.__class__.__name__}`"
|
30
|
+
)
|
31
|
+
|
32
|
+
try:
|
33
|
+
return len(expression)
|
34
|
+
except TypeError as e:
|
35
|
+
raise InvalidExpressionException(f"Cannot get length of `{expression.__class__.__name__}`: {str(e)}")
|
@@ -0,0 +1,41 @@
|
|
1
|
+
from typing import Any, Generic, Protocol, TypeVar, Union, runtime_checkable
|
2
|
+
from typing_extensions import TypeGuard
|
3
|
+
|
4
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
5
|
+
from vellum.workflows.descriptors.exceptions import InvalidExpressionException
|
6
|
+
from vellum.workflows.descriptors.utils import resolve_value
|
7
|
+
from vellum.workflows.state.base import BaseState
|
8
|
+
|
9
|
+
|
10
|
+
@runtime_checkable
|
11
|
+
class SupportsMinus(Protocol):
|
12
|
+
def __sub__(self, other: Any) -> Any: ...
|
13
|
+
|
14
|
+
|
15
|
+
def has_sub(obj: Any) -> TypeGuard[SupportsMinus]:
|
16
|
+
return hasattr(obj, "__sub__")
|
17
|
+
|
18
|
+
|
19
|
+
LHS = TypeVar("LHS")
|
20
|
+
RHS = TypeVar("RHS")
|
21
|
+
|
22
|
+
|
23
|
+
class MinusExpression(BaseDescriptor[Any], Generic[LHS, RHS]):
|
24
|
+
def __init__(
|
25
|
+
self,
|
26
|
+
*,
|
27
|
+
lhs: Union[BaseDescriptor[LHS], LHS],
|
28
|
+
rhs: Union[BaseDescriptor[RHS], RHS],
|
29
|
+
) -> None:
|
30
|
+
super().__init__(name=f"{lhs} - {rhs}", types=(object,))
|
31
|
+
self._lhs = lhs
|
32
|
+
self._rhs = rhs
|
33
|
+
|
34
|
+
def resolve(self, state: "BaseState") -> Any:
|
35
|
+
lhs = resolve_value(self._lhs, state)
|
36
|
+
rhs = resolve_value(self._rhs, state)
|
37
|
+
|
38
|
+
if not has_sub(lhs):
|
39
|
+
raise InvalidExpressionException(f"'{lhs.__class__.__name__}' must support the '-' operator")
|
40
|
+
|
41
|
+
return lhs - rhs
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from vellum.workflows.descriptors.exceptions import InvalidExpressionException
|
4
|
+
from vellum.workflows.expressions.add import AddExpression
|
5
|
+
from vellum.workflows.state.base import BaseState
|
6
|
+
|
7
|
+
|
8
|
+
class TestState(BaseState):
|
9
|
+
number_value: int = 5
|
10
|
+
string_value: str = "hello"
|
11
|
+
|
12
|
+
|
13
|
+
def test_add_expression_numbers():
|
14
|
+
"""
|
15
|
+
Tests that AddExpression correctly adds two numbers.
|
16
|
+
"""
|
17
|
+
|
18
|
+
state = TestState()
|
19
|
+
|
20
|
+
expression = TestState.number_value.add(10)
|
21
|
+
|
22
|
+
result = expression.resolve(state)
|
23
|
+
assert result == 15
|
24
|
+
|
25
|
+
|
26
|
+
def test_add_expression_strings():
|
27
|
+
"""
|
28
|
+
Tests that AddExpression correctly concatenates two strings.
|
29
|
+
"""
|
30
|
+
|
31
|
+
state = TestState()
|
32
|
+
|
33
|
+
expression = TestState.string_value.add(" world")
|
34
|
+
|
35
|
+
result = expression.resolve(state)
|
36
|
+
assert result == "hello world"
|
37
|
+
|
38
|
+
|
39
|
+
def test_add_expression_unsupported_type():
|
40
|
+
"""
|
41
|
+
Tests that AddExpression raises an exception for unsupported types.
|
42
|
+
"""
|
43
|
+
|
44
|
+
class NoAddSupport:
|
45
|
+
pass
|
46
|
+
|
47
|
+
no_add_obj = NoAddSupport()
|
48
|
+
expression = AddExpression(lhs=no_add_obj, rhs=5)
|
49
|
+
state = TestState()
|
50
|
+
|
51
|
+
with pytest.raises(InvalidExpressionException, match="'NoAddSupport' must support the '\\+' operator"):
|
52
|
+
expression.resolve(state)
|
53
|
+
|
54
|
+
|
55
|
+
def test_add_expression_name():
|
56
|
+
"""
|
57
|
+
Tests that AddExpression has the correct name.
|
58
|
+
"""
|
59
|
+
|
60
|
+
expression = AddExpression(lhs=5, rhs=3)
|
61
|
+
|
62
|
+
assert expression.name == "5 + 3"
|
63
|
+
|
64
|
+
|
65
|
+
def test_add_expression_types():
|
66
|
+
"""
|
67
|
+
Tests that AddExpression has the correct types.
|
68
|
+
"""
|
69
|
+
|
70
|
+
expression = AddExpression(lhs=5, rhs=3)
|
71
|
+
|
72
|
+
assert expression.types == (object,)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from vellum.workflows.constants import undefined
|
4
|
+
from vellum.workflows.descriptors.exceptions import InvalidExpressionException
|
5
|
+
from vellum.workflows.expressions.length import LengthExpression
|
6
|
+
from vellum.workflows.state.base import BaseState
|
7
|
+
|
8
|
+
|
9
|
+
class TestState(BaseState):
|
10
|
+
string_value: str = "hello world"
|
11
|
+
|
12
|
+
|
13
|
+
def test_length_expression_string():
|
14
|
+
"""
|
15
|
+
Tests that LengthExpression correctly returns the length of a string.
|
16
|
+
"""
|
17
|
+
|
18
|
+
state = TestState()
|
19
|
+
|
20
|
+
expression = TestState.string_value.length()
|
21
|
+
result = expression.resolve(state)
|
22
|
+
|
23
|
+
assert result == 11
|
24
|
+
|
25
|
+
|
26
|
+
def test_length_expression_undefined():
|
27
|
+
"""
|
28
|
+
Tests that LengthExpression raises an exception for undefined values.
|
29
|
+
"""
|
30
|
+
|
31
|
+
expression = LengthExpression(expression=undefined)
|
32
|
+
state = TestState()
|
33
|
+
|
34
|
+
# THEN we should get an InvalidExpressionException
|
35
|
+
with pytest.raises(InvalidExpressionException) as exc_info:
|
36
|
+
expression.resolve(state)
|
37
|
+
|
38
|
+
assert "Cannot get length of undefined value" in str(exc_info.value)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import pytest
|
2
|
+
|
3
|
+
from vellum.workflows.descriptors.exceptions import InvalidExpressionException
|
4
|
+
from vellum.workflows.expressions.minus import MinusExpression
|
5
|
+
from vellum.workflows.state.base import BaseState
|
6
|
+
|
7
|
+
|
8
|
+
class TestState(BaseState):
|
9
|
+
number_value: int = 10
|
10
|
+
float_value: float = 15.5
|
11
|
+
|
12
|
+
|
13
|
+
def test_minus_expression_numbers():
|
14
|
+
"""
|
15
|
+
Tests that MinusExpression correctly subtracts two numbers.
|
16
|
+
"""
|
17
|
+
|
18
|
+
state = TestState()
|
19
|
+
|
20
|
+
expression = TestState.number_value.minus(3)
|
21
|
+
|
22
|
+
result = expression.resolve(state)
|
23
|
+
assert result == 7
|
24
|
+
|
25
|
+
|
26
|
+
def test_minus_expression_floats():
|
27
|
+
"""
|
28
|
+
Tests that MinusExpression correctly subtracts two floats.
|
29
|
+
"""
|
30
|
+
|
31
|
+
state = TestState()
|
32
|
+
|
33
|
+
expression = TestState.float_value.minus(5.5)
|
34
|
+
|
35
|
+
result = expression.resolve(state)
|
36
|
+
assert result == 10.0
|
37
|
+
|
38
|
+
|
39
|
+
def test_minus_expression_unsupported_type():
|
40
|
+
"""
|
41
|
+
Tests that MinusExpression raises an exception for unsupported types.
|
42
|
+
"""
|
43
|
+
|
44
|
+
class NoSubSupport:
|
45
|
+
pass
|
46
|
+
|
47
|
+
no_sub_obj = NoSubSupport()
|
48
|
+
expression = MinusExpression(lhs=no_sub_obj, rhs=5)
|
49
|
+
state = TestState()
|
50
|
+
|
51
|
+
with pytest.raises(InvalidExpressionException, match="'NoSubSupport' must support the '-' operator"):
|
52
|
+
expression.resolve(state)
|
53
|
+
|
54
|
+
|
55
|
+
def test_minus_expression_name():
|
56
|
+
"""
|
57
|
+
Tests that MinusExpression has the correct name.
|
58
|
+
"""
|
59
|
+
|
60
|
+
expression = MinusExpression(lhs=10, rhs=3)
|
61
|
+
|
62
|
+
assert expression.name == "10 - 3"
|
63
|
+
|
64
|
+
|
65
|
+
def test_minus_expression_types():
|
66
|
+
"""
|
67
|
+
Tests that MinusExpression has the correct types.
|
68
|
+
"""
|
69
|
+
|
70
|
+
expression = MinusExpression(lhs=10, rhs=3)
|
71
|
+
|
72
|
+
assert expression.types == (object,)
|
@@ -151,4 +151,8 @@ class ComposioService:
|
|
151
151
|
if user_id is not None:
|
152
152
|
json_data["user_id"] = user_id
|
153
153
|
response = self._make_request(endpoint, method="POST", json_data=json_data)
|
154
|
+
|
155
|
+
if not response.get("successful", True):
|
156
|
+
return response.get("error", "Tool execution failed")
|
157
|
+
|
154
158
|
return response.get("data", response)
|
@@ -14,7 +14,7 @@ from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior
|
|
14
14
|
from vellum.workflows.types.generics import StateType
|
15
15
|
|
16
16
|
|
17
|
-
class BasePromptNode(BaseNode, Generic[StateType]):
|
17
|
+
class BasePromptNode(BaseNode[StateType], Generic[StateType]):
|
18
18
|
# Inputs that are passed to the Prompt
|
19
19
|
prompt_inputs: ClassVar[Optional[EntityInputsInterface]] = None
|
20
20
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import json
|
2
|
-
from typing import Any, Dict, Iterator, Type, Union
|
2
|
+
from typing import Any, Dict, Generic, Iterator, Type, Union
|
3
3
|
|
4
4
|
from vellum.workflows.constants import undefined
|
5
5
|
from vellum.workflows.errors import WorkflowErrorCode
|
@@ -10,7 +10,7 @@ from vellum.workflows.types import MergeBehavior
|
|
10
10
|
from vellum.workflows.types.generics import StateType
|
11
11
|
|
12
12
|
|
13
|
-
class InlinePromptNode(BaseInlinePromptNode[StateType]):
|
13
|
+
class InlinePromptNode(BaseInlinePromptNode[StateType], Generic[StateType]):
|
14
14
|
"""
|
15
15
|
Used to execute a Prompt defined inline.
|
16
16
|
|
@@ -12,6 +12,7 @@ from vellum.workflows.inputs.base import BaseInputs
|
|
12
12
|
from vellum.workflows.nodes.bases import BaseNode
|
13
13
|
from vellum.workflows.nodes.displayable.tool_calling_node.state import ToolCallingState
|
14
14
|
from vellum.workflows.nodes.displayable.tool_calling_node.utils import (
|
15
|
+
create_else_node,
|
15
16
|
create_function_node,
|
16
17
|
create_mcp_tool_node,
|
17
18
|
create_tool_router_node,
|
@@ -171,7 +172,11 @@ class ToolCallingNode(BaseNode[StateType], Generic[StateType]):
|
|
171
172
|
edge_graph = router_port >> FunctionNodeClass >> self.tool_router_node
|
172
173
|
graph_set.add(edge_graph)
|
173
174
|
|
174
|
-
|
175
|
+
else_node = create_else_node(self.tool_router_node)
|
176
|
+
default_port = self.tool_router_node.Ports.default >> {
|
177
|
+
else_node.Ports.loop >> self.tool_router_node,
|
178
|
+
else_node.Ports.end,
|
179
|
+
}
|
175
180
|
graph_set.add(default_port)
|
176
181
|
|
177
182
|
self._graph = Graph.from_set(graph_set)
|
@@ -44,6 +44,21 @@ def mock_tool_execution_response():
|
|
44
44
|
}
|
45
45
|
|
46
46
|
|
47
|
+
@pytest.fixture
|
48
|
+
def mock_tool_execution_error_response():
|
49
|
+
"""Mock response for failed tool execution API"""
|
50
|
+
return {
|
51
|
+
"data": {},
|
52
|
+
"successful": False,
|
53
|
+
"error": (
|
54
|
+
'Request failed error: `{"message":"Not Found",'
|
55
|
+
'"documentation_url":"https://docs.github.com/rest/pulls/pulls#get-a-pull-request",'
|
56
|
+
'"status":"404"}`'
|
57
|
+
),
|
58
|
+
"log_id": "log_raE_fIWNcDPo",
|
59
|
+
}
|
60
|
+
|
61
|
+
|
47
62
|
@pytest.fixture
|
48
63
|
def composio_service():
|
49
64
|
"""Create ComposioService with test API key"""
|
@@ -168,3 +183,37 @@ class TestComposioCoreService:
|
|
168
183
|
timeout=30,
|
169
184
|
)
|
170
185
|
assert result == {"items": [], "total": 0}
|
186
|
+
|
187
|
+
def test_execute_tool_failure_surfaces_error(
|
188
|
+
self, composio_service, mock_requests, mock_tool_execution_error_response
|
189
|
+
):
|
190
|
+
"""Test that tool execution failures surface detailed error information"""
|
191
|
+
# GIVEN a mock response indicating tool execution failure
|
192
|
+
mock_response = Mock()
|
193
|
+
mock_response.json.return_value = mock_tool_execution_error_response
|
194
|
+
mock_response.raise_for_status.return_value = None
|
195
|
+
mock_requests.post.return_value = mock_response
|
196
|
+
|
197
|
+
# WHEN we execute a tool that fails
|
198
|
+
result = composio_service.execute_tool("GITHUB_GET_PR", {"repo": "test", "pr_number": 999})
|
199
|
+
|
200
|
+
# THEN the result should contain the detailed error message from the API
|
201
|
+
assert "Request failed error" in result
|
202
|
+
assert "Not Found" in result
|
203
|
+
|
204
|
+
def test_execute_tool_failure_with_generic_error_message(self, composio_service, mock_requests):
|
205
|
+
"""Test that tool execution failures with missing error field use generic message"""
|
206
|
+
# GIVEN a mock response indicating tool execution failure without error field
|
207
|
+
mock_response = Mock()
|
208
|
+
mock_response.json.return_value = {
|
209
|
+
"data": {},
|
210
|
+
"successful": False,
|
211
|
+
}
|
212
|
+
mock_response.raise_for_status.return_value = None
|
213
|
+
mock_requests.post.return_value = mock_response
|
214
|
+
|
215
|
+
# WHEN we execute a tool that fails
|
216
|
+
result = composio_service.execute_tool("TEST_TOOL", {"param": "value"})
|
217
|
+
|
218
|
+
# THEN the result should contain the generic error message
|
219
|
+
assert result == "Tool execution failed"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
from uuid import uuid4
|
3
|
-
from typing import Any, Iterator
|
3
|
+
from typing import Any, Iterator
|
4
4
|
|
5
5
|
from vellum import ChatMessage
|
6
6
|
from vellum.client.types.fulfilled_execute_prompt_event import FulfilledExecutePromptEvent
|
@@ -15,6 +15,7 @@ from vellum.workflows import BaseWorkflow
|
|
15
15
|
from vellum.workflows.inputs.base import BaseInputs
|
16
16
|
from vellum.workflows.nodes.bases import BaseNode
|
17
17
|
from vellum.workflows.nodes.displayable.tool_calling_node.node import ToolCallingNode
|
18
|
+
from vellum.workflows.nodes.displayable.tool_calling_node.state import ToolCallingState
|
18
19
|
from vellum.workflows.nodes.displayable.tool_calling_node.utils import create_function_node, create_tool_router_node
|
19
20
|
from vellum.workflows.outputs.base import BaseOutputs
|
20
21
|
from vellum.workflows.state.base import BaseState, StateMeta
|
@@ -44,7 +45,7 @@ def test_port_condition_match_function_name():
|
|
44
45
|
)
|
45
46
|
|
46
47
|
# AND a state with a function call to the first function
|
47
|
-
state =
|
48
|
+
state = ToolCallingState(
|
48
49
|
meta=StateMeta(
|
49
50
|
node_outputs={
|
50
51
|
router_node.Outputs.results: [
|
@@ -116,12 +117,6 @@ def test_tool_calling_node_inline_workflow_context():
|
|
116
117
|
)
|
117
118
|
function_node._context = parent_context
|
118
119
|
|
119
|
-
# Create a state with chat_history for the function node
|
120
|
-
class TestState(BaseState):
|
121
|
-
chat_history: List[ChatMessage] = []
|
122
|
-
|
123
|
-
function_node.state = TestState(meta=StateMeta(node_outputs={tool_router_node.Outputs.text: '{"arguments": {}}'}))
|
124
|
-
|
125
120
|
# WHEN the function node runs
|
126
121
|
outputs = list(function_node.run())
|
127
122
|
|
@@ -5,6 +5,8 @@ from typing import Any, Callable, Dict, Iterator, List, Optional, Type, Union, c
|
|
5
5
|
from pydash import snake_case
|
6
6
|
|
7
7
|
from vellum import ChatMessage, PromptBlock
|
8
|
+
from vellum.client.types.array_chat_message_content import ArrayChatMessageContent
|
9
|
+
from vellum.client.types.array_chat_message_content_item import ArrayChatMessageContentItem
|
8
10
|
from vellum.client.types.function_call_chat_message_content import FunctionCallChatMessageContent
|
9
11
|
from vellum.client.types.function_call_chat_message_content_value import FunctionCallChatMessageContentValue
|
10
12
|
from vellum.client.types.function_definition import FunctionDefinition
|
@@ -59,6 +61,9 @@ class FunctionCallNodeMixin:
|
|
59
61
|
content=StringChatMessageContent(value=json.dumps(result, cls=DefaultStateEncoder)),
|
60
62
|
)
|
61
63
|
)
|
64
|
+
with state.__quiet__():
|
65
|
+
state.current_function_calls_processed += 1
|
66
|
+
state.current_prompt_output_index += 1
|
62
67
|
|
63
68
|
|
64
69
|
class ToolRouterNode(InlinePromptNode[ToolCallingState]):
|
@@ -73,29 +78,37 @@ class ToolRouterNode(InlinePromptNode[ToolCallingState]):
|
|
73
78
|
raise NodeException(message=max_iterations_message, code=WorkflowErrorCode.NODE_EXECUTION)
|
74
79
|
|
75
80
|
generator = super().run()
|
81
|
+
with self.state.__quiet__():
|
82
|
+
self.state.current_prompt_output_index = 0
|
83
|
+
self.state.current_function_calls_processed = 0
|
84
|
+
self.state.prompt_iterations += 1
|
76
85
|
for output in generator:
|
77
|
-
if output.name ==
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
content=FunctionCallChatMessageContent(
|
91
|
-
value=FunctionCallChatMessageContentValue(
|
92
|
-
name=function_call.name,
|
93
|
-
arguments=function_call.arguments,
|
94
|
-
id=function_call.id,
|
95
|
-
),
|
96
|
-
),
|
97
|
-
)
|
86
|
+
if output.name == InlinePromptNode.Outputs.results.name and output.value:
|
87
|
+
prompt_outputs = cast(List[PromptOutput], output.value)
|
88
|
+
chat_contents: List[ArrayChatMessageContentItem] = []
|
89
|
+
for prompt_output in prompt_outputs:
|
90
|
+
if prompt_output.type == "STRING":
|
91
|
+
chat_contents.append(StringChatMessageContent(value=prompt_output.value))
|
92
|
+
elif prompt_output.type == "FUNCTION_CALL" and prompt_output.value:
|
93
|
+
raw_function_call = prompt_output.value.model_dump()
|
94
|
+
if "state" in raw_function_call:
|
95
|
+
del raw_function_call["state"]
|
96
|
+
chat_contents.append(
|
97
|
+
FunctionCallChatMessageContent(
|
98
|
+
value=FunctionCallChatMessageContentValue.model_validate(raw_function_call)
|
98
99
|
)
|
100
|
+
)
|
101
|
+
|
102
|
+
if len(chat_contents) == 1:
|
103
|
+
if chat_contents[0].type == "STRING":
|
104
|
+
self.state.chat_history.append(ChatMessage(role="ASSISTANT", text=chat_contents[0].value))
|
105
|
+
else:
|
106
|
+
self.state.chat_history.append(ChatMessage(role="ASSISTANT", content=chat_contents[0]))
|
107
|
+
else:
|
108
|
+
self.state.chat_history.append(
|
109
|
+
ChatMessage(role="ASSISTANT", content=ArrayChatMessageContent(value=chat_contents))
|
110
|
+
)
|
111
|
+
|
99
112
|
yield output
|
100
113
|
|
101
114
|
|
@@ -225,42 +238,51 @@ class MCPNode(BaseNode[ToolCallingState], FunctionCallNodeMixin):
|
|
225
238
|
yield from []
|
226
239
|
|
227
240
|
|
228
|
-
|
241
|
+
class ElseNode(BaseNode[ToolCallingState]):
|
242
|
+
"""Node that executes when no function conditions match."""
|
243
|
+
|
244
|
+
class Ports(BaseNode.Ports):
|
245
|
+
# Redefined in the create_else_node function, but defined here to resolve mypy errors
|
246
|
+
loop = Port.on_if(
|
247
|
+
ToolCallingState.current_prompt_output_index.less_than(1)
|
248
|
+
| ToolCallingState.current_function_calls_processed.greater_than(0)
|
249
|
+
)
|
250
|
+
end = Port.on_else()
|
251
|
+
|
252
|
+
def run(self) -> BaseNode.Outputs:
|
253
|
+
with self.state.__quiet__():
|
254
|
+
self.state.current_prompt_output_index += 1
|
255
|
+
return self.Outputs()
|
256
|
+
|
257
|
+
|
258
|
+
def _hydrate_composio_tool_definition(tool_def: ComposioToolDefinition) -> FunctionDefinition:
|
229
259
|
"""Hydrate a ComposioToolDefinition with detailed information from the Composio API.
|
230
260
|
|
231
261
|
Args:
|
232
262
|
tool_def: The basic ComposioToolDefinition to enhance
|
233
263
|
|
234
264
|
Returns:
|
235
|
-
|
265
|
+
FunctionDefinition with detailed parameters and description
|
236
266
|
"""
|
237
267
|
try:
|
238
268
|
composio_service = ComposioService()
|
239
269
|
tool_details = composio_service.get_tool_by_slug(tool_def.action)
|
240
270
|
|
241
|
-
#
|
242
|
-
|
243
|
-
|
244
|
-
toolkit_info.get("slug", tool_def.toolkit) if isinstance(toolkit_info, dict) else tool_def.toolkit
|
245
|
-
)
|
246
|
-
|
247
|
-
# Create a version of the tool definition with proper field extraction
|
248
|
-
return ComposioToolDefinition(
|
249
|
-
type=tool_def.type,
|
250
|
-
toolkit=toolkit_slug.upper() if toolkit_slug else tool_def.toolkit,
|
251
|
-
action=tool_details.get("slug", tool_def.action),
|
271
|
+
# Create a FunctionDefinition directly with proper field extraction
|
272
|
+
return FunctionDefinition(
|
273
|
+
name=tool_def.name,
|
252
274
|
description=tool_details.get("description", tool_def.description),
|
253
|
-
|
254
|
-
parameters=tool_details.get("input_parameters", tool_def.parameters),
|
255
|
-
version=tool_details.get("version", tool_def.version),
|
256
|
-
tags=tool_details.get("tags", tool_def.tags),
|
257
|
-
user_id=tool_def.user_id,
|
275
|
+
parameters=tool_details.get("input_parameters", {}),
|
258
276
|
)
|
259
277
|
|
260
278
|
except Exception as e:
|
261
|
-
# If hydration fails (including no API key), log and return
|
279
|
+
# If hydration fails (including no API key), log and return basic function definition
|
262
280
|
logger.warning(f"Failed to enhance Composio tool '{tool_def.action}': {e}")
|
263
|
-
return
|
281
|
+
return FunctionDefinition(
|
282
|
+
name=tool_def.name,
|
283
|
+
description=tool_def.description,
|
284
|
+
parameters={},
|
285
|
+
)
|
264
286
|
|
265
287
|
|
266
288
|
def hydrate_mcp_tool_definitions(server_def: MCPServer) -> List[MCPToolDefinition]:
|
@@ -303,8 +325,13 @@ def create_tool_router_node(
|
|
303
325
|
return Port.on_if(
|
304
326
|
LazyReference(
|
305
327
|
lambda: (
|
306
|
-
node.Outputs.results
|
307
|
-
& node.Outputs.results[
|
328
|
+
ToolCallingState.current_prompt_output_index.less_than(node.Outputs.results.length())
|
329
|
+
& node.Outputs.results[ToolCallingState.current_prompt_output_index]["type"].equals(
|
330
|
+
"FUNCTION_CALL"
|
331
|
+
)
|
332
|
+
& node.Outputs.results[ToolCallingState.current_prompt_output_index]["value"]["name"].equals(
|
333
|
+
fn_name
|
334
|
+
)
|
308
335
|
)
|
309
336
|
)
|
310
337
|
)
|
@@ -313,13 +340,7 @@ def create_tool_router_node(
|
|
313
340
|
if isinstance(function, ComposioToolDefinition):
|
314
341
|
# Get Composio tool details and hydrate the function definition
|
315
342
|
enhanced_function = _hydrate_composio_tool_definition(function)
|
316
|
-
prompt_functions.append(
|
317
|
-
FunctionDefinition(
|
318
|
-
name=enhanced_function.name,
|
319
|
-
description=enhanced_function.description,
|
320
|
-
parameters=enhanced_function.parameters,
|
321
|
-
)
|
322
|
-
)
|
343
|
+
prompt_functions.append(enhanced_function)
|
323
344
|
# Create port for this function (using original function for get_function_name)
|
324
345
|
function_name = get_function_name(function)
|
325
346
|
port = create_port_condition(function_name)
|
@@ -485,6 +506,27 @@ def create_mcp_tool_node(
|
|
485
506
|
return node
|
486
507
|
|
487
508
|
|
509
|
+
def create_else_node(
|
510
|
+
tool_router_node: Type[ToolRouterNode],
|
511
|
+
) -> Type[ElseNode]:
|
512
|
+
class Ports(ElseNode.Ports):
|
513
|
+
loop = Port.on_if(
|
514
|
+
ToolCallingState.current_prompt_output_index.less_than(tool_router_node.Outputs.results.length())
|
515
|
+
| ToolCallingState.current_function_calls_processed.greater_than(0)
|
516
|
+
)
|
517
|
+
end = Port.on_else()
|
518
|
+
|
519
|
+
node = type(
|
520
|
+
f"{tool_router_node.__name__}_ElseNode",
|
521
|
+
(ElseNode,),
|
522
|
+
{
|
523
|
+
"Ports": Ports,
|
524
|
+
"__module__": __name__,
|
525
|
+
},
|
526
|
+
)
|
527
|
+
return node
|
528
|
+
|
529
|
+
|
488
530
|
def get_function_name(function: ToolBase) -> str:
|
489
531
|
if isinstance(function, DeploymentDefinition):
|
490
532
|
name = str(function.deployment_id or function.deployment_name)
|
@@ -2,7 +2,7 @@ import importlib
|
|
2
2
|
import inspect
|
3
3
|
from types import FrameType
|
4
4
|
from uuid import UUID
|
5
|
-
from typing import Annotated, Any, Dict,
|
5
|
+
from typing import Annotated, Any, Dict, Literal, Optional, Union
|
6
6
|
|
7
7
|
from pydantic import BeforeValidator
|
8
8
|
|
@@ -111,11 +111,6 @@ class ComposioToolDefinition(UniversalBaseModel):
|
|
111
111
|
toolkit: str # "GITHUB", "SLACK", etc.
|
112
112
|
action: str # Specific action like "GITHUB_CREATE_AN_ISSUE"
|
113
113
|
description: str
|
114
|
-
|
115
|
-
display_name: Optional[str] = None
|
116
|
-
parameters: Optional[Dict[str, Any]] = None
|
117
|
-
version: Optional[str] = None
|
118
|
-
tags: Optional[List[str]] = None
|
119
114
|
user_id: Optional[str] = None
|
120
115
|
|
121
116
|
@property
|
@@ -48,7 +48,7 @@ def test_composio_tool_definition_creation():
|
|
48
48
|
assert composio_tool.toolkit == "GITHUB"
|
49
49
|
assert composio_tool.action == "GITHUB_CREATE_AN_ISSUE"
|
50
50
|
assert composio_tool.description == "Create a new issue in a GitHub repository"
|
51
|
-
assert composio_tool.
|
51
|
+
assert composio_tool.user_id is None
|
52
52
|
assert composio_tool.name == "github_create_an_issue"
|
53
53
|
|
54
54
|
|
@@ -94,7 +94,7 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_
|
|
94
94
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py,sha256=XWrhHg_acLsRHwjstBAii9Pmes9oXFtAUWSAVF1oSBc,11225
|
95
95
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py,sha256=V8b6gKghLlO7PJI8xeNdnfn8aII0W_IFQvSQBQM62UQ,7721
|
96
96
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py,sha256=hDWtKXmGI1CKhTwTNqpu_d5RkE5n7SolMLtgd87KqTI,3856
|
97
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_composio_serialization.py,sha256=
|
97
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_composio_serialization.py,sha256=AUfULtIangNYkvLH3jd2Ar8X5ulW4tGmezeCfMmXFUU,3697
|
98
98
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py,sha256=4t1lkN2nsZF6lFqP6QnskUQWJlhasF8C2_f6atzk8ZY,26298
|
99
99
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=B0rDsCvO24qPp0gkmj8SdTDY5CxZYkvKwknsKBuAPyA,10017
|
100
100
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py,sha256=mova0sPD3evHiHIN1O0VynxlCp-uOcEIKve5Pd_oCDg,4069
|
@@ -105,7 +105,7 @@ vellum_ee/workflows/display/types.py,sha256=i4T7ElU5b5h-nA1i3scmEhO1BqmNDc4eJDHa
|
|
105
105
|
vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
106
106
|
vellum_ee/workflows/display/utils/auto_layout.py,sha256=f4GiLn_LazweupfqTpubcdtdfE_vrOcmZudSsnYIY9E,3906
|
107
107
|
vellum_ee/workflows/display/utils/exceptions.py,sha256=LSwwxCYNxFkf5XMUcFkaZKpQ13OSrI7y_bpEUwbKVk0,169
|
108
|
-
vellum_ee/workflows/display/utils/expressions.py,sha256=
|
108
|
+
vellum_ee/workflows/display/utils/expressions.py,sha256=YZjd6wrOkmmnTe5LstKaVaBqmR8Q8XS81QzSFwkLtN0,16324
|
109
109
|
vellum_ee/workflows/display/utils/registry.py,sha256=fWIm5Jj-10gNFjgn34iBu4RWv3Vd15ijtSN0V97bpW8,1513
|
110
110
|
vellum_ee/workflows/display/utils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
111
111
|
vellum_ee/workflows/display/utils/tests/test_auto_layout.py,sha256=vfXI769418s9vda5Gb5NFBH747WMOwSgHRXeLCTLVm8,2356
|
@@ -145,7 +145,7 @@ vellum/client/README.md,sha256=Dle5iytCXxP1pNeNd7uZyhFo0rl7tp7vU7s8gmi10OQ,4863
|
|
145
145
|
vellum/client/__init__.py,sha256=KmkyOgReuTsjmXF3WC_dPQ9QqJgYrB3Sr8_LcSUIQyI,125258
|
146
146
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
147
147
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
148
|
-
vellum/client/core/client_wrapper.py,sha256=
|
148
|
+
vellum/client/core/client_wrapper.py,sha256=GLUu-tM9O4VyvaRt1Uz-BgKMqUFNR3H4hdD14V7NGqM,2385
|
149
149
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
150
150
|
vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
151
151
|
vellum/client/core/http_client.py,sha256=cKs2w0ybDBk1wHQf-fTALm_MmvaMe3cZKcYJxqmCxkE,19539
|
@@ -1530,10 +1530,10 @@ vellum/workflows/__init__.py,sha256=CssPsbNvN6rDhoLuqpEv7MMKGa51vE6dvAh6U31Pcio,
|
|
1530
1530
|
vellum/workflows/constants.py,sha256=2yg4_uo5gpqViy3ZLSwfC8qTybleYCtOnhA4Rj6bacM,1310
|
1531
1531
|
vellum/workflows/context.py,sha256=jvMuyeRluay8BQa7GX1TqUlmoHLCycAVYKkp87sfXSo,1644
|
1532
1532
|
vellum/workflows/descriptors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1533
|
-
vellum/workflows/descriptors/base.py,sha256=
|
1533
|
+
vellum/workflows/descriptors/base.py,sha256=fRnRkECyDjfz2QEDCY9Q5mAerlJ6jR0R4nE-MP2VP_k,16558
|
1534
1534
|
vellum/workflows/descriptors/exceptions.py,sha256=gUy4UD9JFUKSeQnQpeuDSLiRqWjWiIsxLahB7p_q3JY,54
|
1535
1535
|
vellum/workflows/descriptors/tests/test_utils.py,sha256=HJ5DoRz0sJvViGxyZ_FtytZjxN2J8xTkGtaVwCy6Q90,6928
|
1536
|
-
vellum/workflows/descriptors/utils.py,sha256=
|
1536
|
+
vellum/workflows/descriptors/utils.py,sha256=7QvS_IOZWIoKvhNwpYBOTP3NasLSIBKTnhyASry2HCM,4320
|
1537
1537
|
vellum/workflows/edges/__init__.py,sha256=wSkmAnz9xyi4vZwtDbKxwlplt2skD7n3NsxkvR_pUus,50
|
1538
1538
|
vellum/workflows/edges/edge.py,sha256=N0SnY3gKVuxImPAdCbPMPlHJIXbkQ3fwq_LbJRvVMFc,677
|
1539
1539
|
vellum/workflows/emitters/__init__.py,sha256=d9QFOI3eVg6rzpSFLvrjkDYXWikf1tcp3ruTRa2Boyc,143
|
@@ -1553,7 +1553,8 @@ vellum/workflows/events/types.py,sha256=jc6vEcydzYETfK3u2Cx1BfUDmYh3Jxa86sdsrrQ5
|
|
1553
1553
|
vellum/workflows/events/workflow.py,sha256=cR2aG6A-JqvLMKFqonDhKjSg496qldEtuks4BXXMTrY,7768
|
1554
1554
|
vellum/workflows/exceptions.py,sha256=NiBiR3ggfmPxBVqD-H1SqmjI-7mIn0EStSN1BqApvCM,1213
|
1555
1555
|
vellum/workflows/expressions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1556
|
-
vellum/workflows/expressions/accessor.py,sha256=
|
1556
|
+
vellum/workflows/expressions/accessor.py,sha256=3lu1-_-dBfZdJvtX-q66jbmRAZtqIfdsh_3_JNuzg1E,4462
|
1557
|
+
vellum/workflows/expressions/add.py,sha256=Rr1O83nksL5Z0kam4eaQOokvDrEwlUg7LqWnXzGUW40,1226
|
1557
1558
|
vellum/workflows/expressions/and_.py,sha256=I7lNqrUM3-m_5hmjjiMhaHhJtKcLj39kEFVWPDOqwfo,916
|
1558
1559
|
vellum/workflows/expressions/begins_with.py,sha256=FnWsQXbENm0ZwkfEP7dR8Qx4_MMrzj6C1yqAV2KaNHw,1123
|
1559
1560
|
vellum/workflows/expressions/between.py,sha256=dVeddT6YA91eOAlE1Utg7C7gnCiYE7WP-dg17yXUeAY,1492
|
@@ -1578,16 +1579,21 @@ vellum/workflows/expressions/is_not_null.py,sha256=EoHXFgZScKP_BM2a5Z7YFQN6l7RME
|
|
1578
1579
|
vellum/workflows/expressions/is_not_undefined.py,sha256=9s-RUQBqM17-_nIRvwsHuarLdHVtrxVuwnqBNJEtmh0,735
|
1579
1580
|
vellum/workflows/expressions/is_null.py,sha256=C75ALGlG_sTGcxI46tm9HtgPVfJ7DwTIyKzX8qtEiDU,660
|
1580
1581
|
vellum/workflows/expressions/is_undefined.py,sha256=uUBK3rxYbwoeRq36AGFc7d61hXzTp8UacQAi-1JbaW0,724
|
1582
|
+
vellum/workflows/expressions/length.py,sha256=Gq4eBXnLLmuyhKHwERcvBd4qLHLkw_JebpZ778gw08M,1274
|
1581
1583
|
vellum/workflows/expressions/less_than.py,sha256=chY9puJ6jDB2EinjfyGNrSplJ1NJC-BB-GGSSB33bqI,1237
|
1582
1584
|
vellum/workflows/expressions/less_than_or_equal_to.py,sha256=JtTDBa8yFKy3fGaCOA1tb_5s1JkY8FFnH6kpoeXGnT4,1267
|
1585
|
+
vellum/workflows/expressions/minus.py,sha256=qTIuOF3knMwwGiA9BNGvMP6vVw3z0g5wr4LziaYMRIE,1232
|
1583
1586
|
vellum/workflows/expressions/not_between.py,sha256=ZtRJeJDSSlOvajL8YoBoh5o_khjIn9xSSeQCnXYbHFE,1506
|
1584
1587
|
vellum/workflows/expressions/not_in.py,sha256=pFvwkFPsn3WJw61ssFgM2U1dqWEeglfz4FVT4xwm5Mc,1144
|
1585
1588
|
vellum/workflows/expressions/or_.py,sha256=s-8YdMSSCDS2yijR38kguwok3iqmDMMgDYKV93b4O4s,914
|
1586
1589
|
vellum/workflows/expressions/parse_json.py,sha256=xsk6j3HF7bU1yF6fwt5P9Ugcyd5D9ZXrdng11FRilUI,1088
|
1587
1590
|
vellum/workflows/expressions/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1588
1591
|
vellum/workflows/expressions/tests/test_accessor.py,sha256=g2z0mJjuWwVKeXS0yGoFW-aRmT5n_LrhfuBorSmj9kI,7585
|
1592
|
+
vellum/workflows/expressions/tests/test_add.py,sha256=_MjlRvIGAVM5wve2ru5jc_5Ae4x_ywvh4vN0S2yQ-8M,1615
|
1589
1593
|
vellum/workflows/expressions/tests/test_concat.py,sha256=fDHXlmFvCtqPkdZQD9Qs22i6sJq_MJjbUXCnTlSMvA0,1666
|
1590
1594
|
vellum/workflows/expressions/tests/test_expressions.py,sha256=3b6k8xs-CItBBw95NygFLUNoNPKxI4VA1GyWbkMtqyI,11623
|
1595
|
+
vellum/workflows/expressions/tests/test_length.py,sha256=pQA1tYSwqxE6euclboY024NXEOs7yaVgwTKkMPYUT08,1035
|
1596
|
+
vellum/workflows/expressions/tests/test_minus.py,sha256=pq7dvdRGNhSSn95LGNzRErsYUsFk5SpOKHDcSR5QToc,1632
|
1591
1597
|
vellum/workflows/expressions/tests/test_parse_json.py,sha256=zpB_qE5_EwWQL7ULQUJm0o1PRSfWZdAqZNW6Ah13oJE,1059
|
1592
1598
|
vellum/workflows/graph/__init__.py,sha256=3sHlay5d_-uD7j3QJXiGl0WHFZZ_QScRvgyDhN2GhHY,74
|
1593
1599
|
vellum/workflows/graph/graph.py,sha256=GGR8cGpSuNWPIiTWNWsj6l70upb5nIxAyFcn7VdaJIs,5506
|
@@ -1598,7 +1604,7 @@ vellum/workflows/inputs/base.py,sha256=w3owT5B3rLBmIj-v-jL2l-HD4yd3hXK9RmHVd557B
|
|
1598
1604
|
vellum/workflows/inputs/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1599
1605
|
vellum/workflows/inputs/tests/test_inputs.py,sha256=lioA8917mFLYq7Ml69UNkqUjcWbbxkxnpIEJ4FBaYBk,2206
|
1600
1606
|
vellum/workflows/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1601
|
-
vellum/workflows/integrations/composio_service.py,sha256=
|
1607
|
+
vellum/workflows/integrations/composio_service.py,sha256=rSliaZtNiBcDSvDxz9k5i1KkyUIrbxyegu0yU9cDByU,6023
|
1602
1608
|
vellum/workflows/integrations/mcp_service.py,sha256=SaOLg76JBAiBDAMUn04mxVWmf2Btobd1kDjc8B1atng,8712
|
1603
1609
|
vellum/workflows/logging.py,sha256=_a217XogktV4Ncz6xKFz7WfYmZAzkfVRVuC0rWob8ls,437
|
1604
1610
|
vellum/workflows/nodes/__init__.py,sha256=aVdQVv7Y3Ro3JlqXGpxwaU2zrI06plDHD2aumH5WUIs,1157
|
@@ -1641,7 +1647,7 @@ vellum/workflows/nodes/displayable/bases/api_node/node.py,sha256=iUtdPsbJs1jwo3V
|
|
1641
1647
|
vellum/workflows/nodes/displayable/bases/api_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1642
1648
|
vellum/workflows/nodes/displayable/bases/api_node/tests/test_node.py,sha256=Pf51DIyhtUxx-pCu0zJYDB4Z5_IW5mRwkJIoPT53_9I,3894
|
1643
1649
|
vellum/workflows/nodes/displayable/bases/base_prompt_node/__init__.py,sha256=Org3xTvgp1pA0uUXFfnJr29D3HzCey2lEdYF4zbIUgo,70
|
1644
|
-
vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py,sha256=
|
1650
|
+
vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py,sha256=ea20icDM1HB942wkH-XtXNSNCBDcjeOiN3vowkHL4fs,4477
|
1645
1651
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/__init__.py,sha256=Hl35IAoepRpE-j4cALaXVJIYTYOF3qszyVbxTj4kS1s,82
|
1646
1652
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=hy_fy4zImhpnHuPczKtOLhv_uOmvxvJsQA9Zl9DTmSw,12851
|
1647
1653
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -1672,7 +1678,7 @@ vellum/workflows/nodes/displayable/guardrail_node/test_node.py,sha256=SAGv6hSFcB
|
|
1672
1678
|
vellum/workflows/nodes/displayable/guardrail_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1673
1679
|
vellum/workflows/nodes/displayable/guardrail_node/tests/test_node.py,sha256=X2pd6TI8miYxIa7rgvs1pHTEreyWcf77EyR0_Jsa700,2055
|
1674
1680
|
vellum/workflows/nodes/displayable/inline_prompt_node/__init__.py,sha256=gSUOoEZLlrx35-tQhSAd3An8WDwBqyiQh-sIebLU9wU,74
|
1675
|
-
vellum/workflows/nodes/displayable/inline_prompt_node/node.py,sha256=
|
1681
|
+
vellum/workflows/nodes/displayable/inline_prompt_node/node.py,sha256=3jY-2UJarVJSz2eupt7c9Mp-Mk56U2meXU0d7c0KVNk,2941
|
1676
1682
|
vellum/workflows/nodes/displayable/inline_prompt_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1677
1683
|
vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py,sha256=bBHs90mV5SZ3rJPAL0wx4WWyawUA406LgMPOdvpZC_A,10923
|
1678
1684
|
vellum/workflows/nodes/displayable/merge_node/__init__.py,sha256=J8IC08dSH7P76wKlNuxe1sn7toNGtSQdFirUbtPDEs0,60
|
@@ -1697,13 +1703,13 @@ vellum/workflows/nodes/displayable/tests/test_search_node_error_handling.py,sha2
|
|
1697
1703
|
vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py,sha256=VepO5z1277c1y5N6LLIC31nnWD1aak2m5oPFplfJHHs,6935
|
1698
1704
|
vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py,sha256=dc3EEn1sOICpr3GdS8eyeFtExaGwWWcw9eHSdkRhQJU,2584
|
1699
1705
|
vellum/workflows/nodes/displayable/tool_calling_node/__init__.py,sha256=3n0-ysmFKsr40CVxPthc0rfJgqVJeZuUEsCmYudLVRg,117
|
1700
|
-
vellum/workflows/nodes/displayable/tool_calling_node/node.py,sha256=
|
1701
|
-
vellum/workflows/nodes/displayable/tool_calling_node/state.py,sha256=
|
1706
|
+
vellum/workflows/nodes/displayable/tool_calling_node/node.py,sha256=RFoMIr4CVy50fjuXAFphwfW1oXeZo7s-JY4Bqvlphn0,7460
|
1707
|
+
vellum/workflows/nodes/displayable/tool_calling_node/state.py,sha256=CcBVb_YtwfSSka4ze678k6-qwmzMSfjfVP8_Y95feSo,302
|
1702
1708
|
vellum/workflows/nodes/displayable/tool_calling_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1703
|
-
vellum/workflows/nodes/displayable/tool_calling_node/tests/test_composio_service.py,sha256=
|
1704
|
-
vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py,sha256=
|
1709
|
+
vellum/workflows/nodes/displayable/tool_calling_node/tests/test_composio_service.py,sha256=in1fbEz5x1tx3uKv9YXdvOncsHucNL8Ro6Go7lBuuOQ,8962
|
1710
|
+
vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py,sha256=1QwfUOS26pesN6Ckqfm-RVlOSyjuF945vKC20AXedKw,8458
|
1705
1711
|
vellum/workflows/nodes/displayable/tool_calling_node/tests/test_utils.py,sha256=om4FztVQ33jFZK_lbusi6khOM7zgzNCHlUcEb5-r6pU,8361
|
1706
|
-
vellum/workflows/nodes/displayable/tool_calling_node/utils.py,sha256=
|
1712
|
+
vellum/workflows/nodes/displayable/tool_calling_node/utils.py,sha256=7B_8FY5xEjra3A3k6kcABnrgobqieCKNCEA6ijKKaW8,21284
|
1707
1713
|
vellum/workflows/nodes/experimental/README.md,sha256=eF6DfIL8t-HbF9-mcofOMymKrraiBHDLKTlnBa51ZiE,284
|
1708
1714
|
vellum/workflows/nodes/experimental/__init__.py,sha256=jCQgvZEknXKfuNhGSOou4XPfrPqZ1_XBj5F0n0fgiWM,106
|
1709
1715
|
vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py,sha256=lsyD9laR9p7kx5-BXGH2gUTM242UhKy8SMV0SR6S2iE,90
|
@@ -1751,11 +1757,11 @@ vellum/workflows/tests/test_undefined.py,sha256=zMCVliCXVNLrlC6hEGyOWDnQADJ2g83y
|
|
1751
1757
|
vellum/workflows/types/__init__.py,sha256=KxUTMBGzuRCfiMqzzsykOeVvrrkaZmTTo1a7SLu8gRM,68
|
1752
1758
|
vellum/workflows/types/code_execution_node_wrappers.py,sha256=3MNIoFZKzVzNS5qFLVuDwMV17QJw72zo7NRf52yMq5A,3074
|
1753
1759
|
vellum/workflows/types/core.py,sha256=TggDVs2lVya33xvu374EDhMC1b7RRlAAs0zWLaF46BA,1385
|
1754
|
-
vellum/workflows/types/definition.py,sha256=
|
1760
|
+
vellum/workflows/types/definition.py,sha256=ee55MvZs4scFgI7y3ykIcP_5kSTqb4ojNrtGmnvISTw,4437
|
1755
1761
|
vellum/workflows/types/generics.py,sha256=8jptbEx1fnJV0Lhj0MpCJOT6yNiEWeTOYOwrEAb5CRU,1576
|
1756
1762
|
vellum/workflows/types/stack.py,sha256=h7NE0vXR7l9DevFBIzIAk1Zh59K-kECQtDTKOUunwMY,1314
|
1757
1763
|
vellum/workflows/types/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1758
|
-
vellum/workflows/types/tests/test_definition.py,sha256=
|
1764
|
+
vellum/workflows/types/tests/test_definition.py,sha256=AM2uaADSWb6QUAP_CwjeSuNayBjoZ_yQWjYefw0mbGI,5045
|
1759
1765
|
vellum/workflows/types/tests/test_utils.py,sha256=UnZog59tR577mVwqZRqqWn2fScoOU1H6up0EzS8zYhw,2536
|
1760
1766
|
vellum/workflows/types/utils.py,sha256=mTctHITBybpt4855x32oCKALBEcMNLn-9cCmfEKgJHQ,6498
|
1761
1767
|
vellum/workflows/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -1776,8 +1782,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
|
|
1776
1782
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1777
1783
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=ptMntHzVyy8ZuzNgeTuk7hREgKQ5UBdgq8VJFSGaW4Y,20832
|
1778
1784
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1779
|
-
vellum_ai-1.0.
|
1780
|
-
vellum_ai-1.0.
|
1781
|
-
vellum_ai-1.0.
|
1782
|
-
vellum_ai-1.0.
|
1783
|
-
vellum_ai-1.0.
|
1785
|
+
vellum_ai-1.0.11.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1786
|
+
vellum_ai-1.0.11.dist-info/METADATA,sha256=8M0wZ1WdaD1OxRcbUt8a0g6566qeU-QnXRHQ6heBKiU,5555
|
1787
|
+
vellum_ai-1.0.11.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1788
|
+
vellum_ai-1.0.11.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1789
|
+
vellum_ai-1.0.11.dist-info/RECORD,,
|
@@ -53,10 +53,6 @@ def test_serialize_workflow():
|
|
53
53
|
"toolkit": "GITHUB",
|
54
54
|
"action": "GITHUB_CREATE_AN_ISSUE",
|
55
55
|
"description": "Create a new issue in a GitHub repository",
|
56
|
-
"display_name": "Create GitHub Issue",
|
57
|
-
"parameters": None,
|
58
|
-
"version": None,
|
59
|
-
"tags": None,
|
60
56
|
"user_id": None,
|
61
57
|
}
|
62
58
|
|
@@ -6,6 +6,7 @@ from pydantic import BaseModel
|
|
6
6
|
from vellum.client.types.logical_operator import LogicalOperator
|
7
7
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
8
8
|
from vellum.workflows.expressions.accessor import AccessorExpression
|
9
|
+
from vellum.workflows.expressions.add import AddExpression
|
9
10
|
from vellum.workflows.expressions.and_ import AndExpression
|
10
11
|
from vellum.workflows.expressions.begins_with import BeginsWithExpression
|
11
12
|
from vellum.workflows.expressions.between import BetweenExpression
|
@@ -26,8 +27,10 @@ from vellum.workflows.expressions.is_not_null import IsNotNullExpression
|
|
26
27
|
from vellum.workflows.expressions.is_not_undefined import IsNotUndefinedExpression
|
27
28
|
from vellum.workflows.expressions.is_null import IsNullExpression
|
28
29
|
from vellum.workflows.expressions.is_undefined import IsUndefinedExpression
|
30
|
+
from vellum.workflows.expressions.length import LengthExpression
|
29
31
|
from vellum.workflows.expressions.less_than import LessThanExpression
|
30
32
|
from vellum.workflows.expressions.less_than_or_equal_to import LessThanOrEqualToExpression
|
33
|
+
from vellum.workflows.expressions.minus import MinusExpression
|
31
34
|
from vellum.workflows.expressions.not_between import NotBetweenExpression
|
32
35
|
from vellum.workflows.expressions.not_in import NotInExpression
|
33
36
|
from vellum.workflows.expressions.or_ import OrExpression
|
@@ -96,6 +99,12 @@ def convert_descriptor_to_operator(descriptor: BaseDescriptor) -> LogicalOperato
|
|
96
99
|
return "coalesce"
|
97
100
|
elif isinstance(descriptor, ParseJsonExpression):
|
98
101
|
return "parseJson"
|
102
|
+
elif isinstance(descriptor, LengthExpression):
|
103
|
+
return "length"
|
104
|
+
elif isinstance(descriptor, AddExpression):
|
105
|
+
return "+"
|
106
|
+
elif isinstance(descriptor, MinusExpression):
|
107
|
+
return "-"
|
99
108
|
else:
|
100
109
|
raise ValueError(f"Unsupported descriptor type: {descriptor}")
|
101
110
|
|
@@ -133,6 +142,7 @@ def _serialize_condition(display_context: "WorkflowDisplayContext", condition: B
|
|
133
142
|
IsNotNilExpression,
|
134
143
|
IsUndefinedExpression,
|
135
144
|
IsNotUndefinedExpression,
|
145
|
+
LengthExpression,
|
136
146
|
ParseJsonExpression,
|
137
147
|
),
|
138
148
|
):
|
@@ -157,6 +167,7 @@ def _serialize_condition(display_context: "WorkflowDisplayContext", condition: B
|
|
157
167
|
elif isinstance(
|
158
168
|
condition,
|
159
169
|
(
|
170
|
+
AddExpression,
|
160
171
|
AndExpression,
|
161
172
|
BeginsWithExpression,
|
162
173
|
CoalesceExpression,
|
@@ -172,6 +183,7 @@ def _serialize_condition(display_context: "WorkflowDisplayContext", condition: B
|
|
172
183
|
InExpression,
|
173
184
|
LessThanExpression,
|
174
185
|
LessThanOrEqualToExpression,
|
186
|
+
MinusExpression,
|
175
187
|
NotInExpression,
|
176
188
|
OrExpression,
|
177
189
|
),
|
File without changes
|
File without changes
|
File without changes
|