vellum-ai 0.12.16__py3-none-any.whl → 0.12.17__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- vellum/client/core/client_wrapper.py +1 -1
- vellum/plugins/vellum_mypy.py +80 -11
- vellum/utils/templating/render.py +3 -0
- vellum/workflows/nodes/bases/base.py +4 -0
- vellum/workflows/nodes/core/retry_node/node.py +24 -3
- vellum/workflows/nodes/core/retry_node/tests/test_node.py +40 -0
- vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py +20 -1
- vellum/workflows/nodes/displayable/api_node/node.py +3 -3
- {vellum_ai-0.12.16.dist-info → vellum_ai-0.12.17.dist-info}/METADATA +1 -1
- {vellum_ai-0.12.16.dist-info → vellum_ai-0.12.17.dist-info}/RECORD +16 -16
- vellum_cli/pull.py +7 -4
- vellum_cli/tests/conftest.py +4 -2
- vellum_cli/tests/test_push.py +13 -5
- {vellum_ai-0.12.16.dist-info → vellum_ai-0.12.17.dist-info}/LICENSE +0 -0
- {vellum_ai-0.12.16.dist-info → vellum_ai-0.12.17.dist-info}/WHEEL +0 -0
- {vellum_ai-0.12.16.dist-info → vellum_ai-0.12.17.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.12.
|
21
|
+
"X-Fern-SDK-Version": "0.12.17",
|
22
22
|
}
|
23
23
|
headers["X_API_KEY"] = self.api_key
|
24
24
|
return headers
|
vellum/plugins/vellum_mypy.py
CHANGED
@@ -4,6 +4,7 @@ from typing import Callable, Dict, List, Optional, Set, Type
|
|
4
4
|
from mypy.nodes import (
|
5
5
|
AssignmentStmt,
|
6
6
|
CallExpr,
|
7
|
+
ClassDef,
|
7
8
|
Decorator,
|
8
9
|
MemberExpr,
|
9
10
|
NameExpr,
|
@@ -198,13 +199,27 @@ class VellumMypyPlugin(Plugin):
|
|
198
199
|
return
|
199
200
|
|
200
201
|
current_node_outputs = node_info.names.get("Outputs")
|
201
|
-
if not current_node_outputs:
|
202
|
+
if not current_node_outputs and isinstance(base_node_outputs.node, TypeInfo):
|
202
203
|
node_info.names["Outputs"] = base_node_outputs.copy()
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
204
|
+
|
205
|
+
new_outputs_fullname = f"{node_info.fullname}.Outputs"
|
206
|
+
new_outputs_defn_raw = base_node_outputs.node.defn.serialize()
|
207
|
+
new_outputs_defn_raw["fullname"] = new_outputs_fullname
|
208
|
+
new_outputs_defn = ClassDef.deserialize(new_outputs_defn_raw)
|
209
|
+
new_outputs_sym = TypeInfo(
|
210
|
+
names=base_node_outputs.node.names.copy(),
|
211
|
+
defn=new_outputs_defn,
|
212
|
+
module_name=node_info.module_name,
|
213
|
+
)
|
214
|
+
|
215
|
+
base_result_sym = base_node_outputs.node.names[attribute_name].node
|
216
|
+
if isinstance(base_result_sym, Var):
|
217
|
+
new_result_sym = Var.deserialize(base_result_sym.serialize())
|
218
|
+
new_result_sym._fullname = f"{new_outputs_fullname}.{attribute_name}"
|
219
|
+
new_result_sym.type = base_node_resolved_type
|
220
|
+
new_outputs_sym.names[attribute_name].node = new_result_sym
|
221
|
+
new_outputs_sym.bases.append(Instance(base_node_outputs.node, []))
|
222
|
+
node_info.names["Outputs"].node = new_outputs_sym
|
208
223
|
|
209
224
|
def _base_node_class_hook(self, ctx: ClassDefContext) -> None:
|
210
225
|
"""
|
@@ -472,10 +487,22 @@ class VellumMypyPlugin(Plugin):
|
|
472
487
|
|
473
488
|
def _run_method_hook(self, ctx: MethodContext) -> MypyType:
|
474
489
|
"""
|
475
|
-
We use this to target
|
476
|
-
|
490
|
+
We use this to target:
|
491
|
+
- `BaseWorkflow.run()`, so that the WorkflowExecutionFulfilledEvent is properly typed
|
492
|
+
using the `Outputs` class defined on the user-defined subclass of `Workflow`.
|
493
|
+
- `BaseNode.run()`, so that the `Outputs` class defined on the user-defined subclass of `Node`
|
494
|
+
is properly typed.
|
477
495
|
"""
|
478
496
|
|
497
|
+
if isinstance(ctx.default_return_type, TypeAliasType):
|
498
|
+
return self._workflow_run_method_hook(ctx)
|
499
|
+
|
500
|
+
if isinstance(ctx.default_return_type, Instance):
|
501
|
+
return self._node_run_method_hook(ctx)
|
502
|
+
|
503
|
+
return ctx.default_return_type
|
504
|
+
|
505
|
+
def _workflow_run_method_hook(self, ctx: MethodContext) -> MypyType:
|
479
506
|
if not isinstance(ctx.default_return_type, TypeAliasType):
|
480
507
|
return ctx.default_return_type
|
481
508
|
|
@@ -494,7 +521,7 @@ class VellumMypyPlugin(Plugin):
|
|
494
521
|
if fulfilled_event.type.fullname != "vellum.workflows.events.workflow.WorkflowExecutionFulfilledEvent":
|
495
522
|
return ctx.default_return_type
|
496
523
|
|
497
|
-
outputs_node = self.
|
524
|
+
outputs_node = self._get_workflow_outputs_type_info(ctx)
|
498
525
|
if not outputs_node:
|
499
526
|
return ctx.default_return_type
|
500
527
|
|
@@ -513,6 +540,19 @@ class VellumMypyPlugin(Plugin):
|
|
513
540
|
column=ctx.default_return_type.column,
|
514
541
|
)
|
515
542
|
|
543
|
+
def _node_run_method_hook(self, ctx: MethodContext) -> MypyType:
|
544
|
+
if not isinstance(ctx.default_return_type, Instance):
|
545
|
+
return ctx.default_return_type
|
546
|
+
|
547
|
+
if not _is_subclass(ctx.default_return_type.type, "vellum.workflows.nodes.bases.base.BaseNode.Outputs"):
|
548
|
+
return ctx.default_return_type
|
549
|
+
|
550
|
+
outputs_node = self._get_node_outputs_type_info(ctx)
|
551
|
+
if not outputs_node:
|
552
|
+
return ctx.default_return_type
|
553
|
+
|
554
|
+
return Instance(outputs_node, [])
|
555
|
+
|
516
556
|
def _stream_method_hook(self, ctx: MethodContext) -> MypyType:
|
517
557
|
"""
|
518
558
|
We use this to target `Workflow.stream()` so that the WorkflowExecutionFulfilledEvent is properly typed
|
@@ -557,7 +597,7 @@ class VellumMypyPlugin(Plugin):
|
|
557
597
|
if fulfilled_event_index == -1 or not fulfilled_event:
|
558
598
|
return ctx.default_return_type
|
559
599
|
|
560
|
-
outputs_node = self.
|
600
|
+
outputs_node = self._get_workflow_outputs_type_info(ctx)
|
561
601
|
if not outputs_node:
|
562
602
|
return ctx.default_return_type
|
563
603
|
|
@@ -594,7 +634,7 @@ class VellumMypyPlugin(Plugin):
|
|
594
634
|
column=ctx.default_return_type.column,
|
595
635
|
)
|
596
636
|
|
597
|
-
def
|
637
|
+
def _get_workflow_outputs_type_info(self, ctx: MethodContext) -> Optional[TypeInfo]:
|
598
638
|
if not isinstance(ctx.context, CallExpr):
|
599
639
|
return None
|
600
640
|
|
@@ -624,6 +664,35 @@ class VellumMypyPlugin(Plugin):
|
|
624
664
|
|
625
665
|
return resolved_outputs_node.node
|
626
666
|
|
667
|
+
def _get_node_outputs_type_info(self, ctx: MethodContext) -> Optional[TypeInfo]:
|
668
|
+
if not isinstance(ctx.context, CallExpr):
|
669
|
+
return None
|
670
|
+
|
671
|
+
if not isinstance(ctx.context.callee, MemberExpr):
|
672
|
+
return None
|
673
|
+
|
674
|
+
expr = ctx.context.callee.expr
|
675
|
+
instance = ctx.api.get_expression_type(expr)
|
676
|
+
if not isinstance(instance, Instance) or not _is_subclass(
|
677
|
+
instance.type, "vellum.workflows.nodes.bases.base.BaseNode"
|
678
|
+
):
|
679
|
+
return None
|
680
|
+
|
681
|
+
outputs_node = instance.type.names.get("Outputs")
|
682
|
+
|
683
|
+
if (
|
684
|
+
not outputs_node
|
685
|
+
or not isinstance(outputs_node.node, TypeInfo)
|
686
|
+
or not _is_subclass(outputs_node.node, "vellum.workflows.outputs.base.BaseOutputs")
|
687
|
+
):
|
688
|
+
return None
|
689
|
+
|
690
|
+
# TODO: For some reason, returning the correct Outputs type info is causing `result` to not
|
691
|
+
# be found. `test_templating_node.py` is the best place to test this.
|
692
|
+
# https://app.shortcut.com/vellum/story/6132
|
693
|
+
# return outputs_node.node
|
694
|
+
return None
|
695
|
+
|
627
696
|
def _resolve_descriptors_in_outputs(self, type_info: SymbolTableNode) -> SymbolTableNode:
|
628
697
|
new_type_info = type_info.copy()
|
629
698
|
if not isinstance(new_type_info.node, TypeInfo):
|
@@ -28,6 +28,9 @@ def render_sandboxed_jinja_template(
|
|
28
28
|
keep_trailing_newline=True,
|
29
29
|
finalize=finalize,
|
30
30
|
)
|
31
|
+
environment.policies["json.dumps_kwargs"] = {
|
32
|
+
"cls": DefaultStateEncoder,
|
33
|
+
}
|
31
34
|
|
32
35
|
if jinja_custom_filters:
|
33
36
|
environment.filters.update(jinja_custom_filters)
|
@@ -324,6 +324,10 @@ class BaseNode(Generic[StateType], metaclass=BaseNodeMeta):
|
|
324
324
|
if not descriptor.instance:
|
325
325
|
continue
|
326
326
|
|
327
|
+
if any(isinstance(t, type) and issubclass(t, BaseDescriptor) for t in descriptor.types):
|
328
|
+
# We don't want to resolve attributes that are _meant_ to be descriptors
|
329
|
+
continue
|
330
|
+
|
327
331
|
resolved_value = resolve_value(descriptor.instance, self.state, path=descriptor.name, memo=inputs)
|
328
332
|
setattr(self, descriptor.name, resolved_value)
|
329
333
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
from typing import Callable, Generic, Optional, Type
|
2
2
|
|
3
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
4
|
+
from vellum.workflows.descriptors.utils import resolve_value
|
3
5
|
from vellum.workflows.errors.types import WorkflowErrorCode
|
4
6
|
from vellum.workflows.exceptions import NodeException
|
5
7
|
from vellum.workflows.inputs.base import BaseInputs
|
@@ -21,6 +23,7 @@ class RetryNode(BaseAdornmentNode[StateType], Generic[StateType]):
|
|
21
23
|
|
22
24
|
max_attempts: int
|
23
25
|
retry_on_error_code: Optional[WorkflowErrorCode] = None
|
26
|
+
retry_on_condition: Optional[BaseDescriptor] = None
|
24
27
|
|
25
28
|
class SubworkflowInputs(BaseInputs):
|
26
29
|
attempt_number: int
|
@@ -55,18 +58,36 @@ class RetryNode(BaseAdornmentNode[StateType], Generic[StateType]):
|
|
55
58
|
last_exception = NodeException(
|
56
59
|
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
57
60
|
message=f"""Unexpected rejection on attempt {attempt_number}: {terminal_event.error.code.value}.
|
61
|
+
Message: {terminal_event.error.message}""",
|
62
|
+
)
|
63
|
+
break
|
64
|
+
elif self.retry_on_condition and not resolve_value(self.retry_on_condition, self.state):
|
65
|
+
last_exception = NodeException(
|
66
|
+
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
67
|
+
message=f"""Rejection failed on attempt {attempt_number}: {terminal_event.error.code.value}.
|
58
68
|
Message: {terminal_event.error.message}""",
|
59
69
|
)
|
60
70
|
break
|
61
71
|
else:
|
62
|
-
last_exception =
|
72
|
+
last_exception = NodeException(
|
73
|
+
terminal_event.error.message,
|
74
|
+
code=terminal_event.error.code,
|
75
|
+
)
|
63
76
|
|
64
77
|
raise last_exception
|
65
78
|
|
66
79
|
@classmethod
|
67
80
|
def wrap(
|
68
|
-
cls,
|
81
|
+
cls,
|
82
|
+
max_attempts: int,
|
83
|
+
retry_on_error_code: Optional[WorkflowErrorCode] = None,
|
84
|
+
retry_on_condition: Optional[BaseDescriptor] = None,
|
69
85
|
) -> Callable[..., Type["RetryNode"]]:
|
70
86
|
return create_adornment(
|
71
|
-
cls,
|
87
|
+
cls,
|
88
|
+
attributes={
|
89
|
+
"max_attempts": max_attempts,
|
90
|
+
"retry_on_error_code": retry_on_error_code,
|
91
|
+
"retry_on_condition": retry_on_condition,
|
92
|
+
},
|
72
93
|
)
|
@@ -6,6 +6,7 @@ from vellum.workflows.inputs.base import BaseInputs
|
|
6
6
|
from vellum.workflows.nodes.bases import BaseNode
|
7
7
|
from vellum.workflows.nodes.core.retry_node.node import RetryNode
|
8
8
|
from vellum.workflows.outputs import BaseOutputs
|
9
|
+
from vellum.workflows.references.lazy import LazyReference
|
9
10
|
from vellum.workflows.state.base import BaseState, StateMeta
|
10
11
|
|
11
12
|
|
@@ -91,3 +92,42 @@ def test_retry_node__use_parent_inputs_and_state():
|
|
91
92
|
|
92
93
|
# THEN the data is used successfully
|
93
94
|
assert outputs.value == "foo bar"
|
95
|
+
|
96
|
+
|
97
|
+
def test_retry_node__condition_arg_successfully_retries():
|
98
|
+
# GIVEN workflow Inputs and State
|
99
|
+
class State(BaseState):
|
100
|
+
count = 0
|
101
|
+
|
102
|
+
# AND a retry node that retries on a condition
|
103
|
+
@RetryNode.wrap(
|
104
|
+
max_attempts=5,
|
105
|
+
retry_on_condition=LazyReference(lambda: State.count.less_than(3)),
|
106
|
+
)
|
107
|
+
class TestNode(BaseNode[State]):
|
108
|
+
attempt_number = RetryNode.SubworkflowInputs.attempt_number
|
109
|
+
|
110
|
+
class Outputs(BaseOutputs):
|
111
|
+
value: str
|
112
|
+
|
113
|
+
def run(self) -> Outputs:
|
114
|
+
if not isinstance(self.state.meta.parent, State):
|
115
|
+
raise NodeException(message="Failed to resolve parent state")
|
116
|
+
|
117
|
+
self.state.meta.parent.count += 1
|
118
|
+
raise NodeException(message=f"This is failure attempt {self.attempt_number}")
|
119
|
+
|
120
|
+
# WHEN the node is run
|
121
|
+
node = TestNode(state=State())
|
122
|
+
with pytest.raises(NodeException) as exc_info:
|
123
|
+
node.run()
|
124
|
+
|
125
|
+
# THEN the exception raised is the last one
|
126
|
+
assert (
|
127
|
+
exc_info.value.message
|
128
|
+
== """Rejection failed on attempt 3: INTERNAL_ERROR.
|
129
|
+
Message: This is failure attempt 3"""
|
130
|
+
)
|
131
|
+
|
132
|
+
# AND the state was updated each time
|
133
|
+
assert node.state.count == 3
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
|
3
|
+
from vellum.client.types.function_call import FunctionCall
|
3
4
|
from vellum.workflows.nodes.bases.base import BaseNode
|
4
5
|
from vellum.workflows.nodes.core.templating_node.node import TemplatingNode
|
5
6
|
from vellum.workflows.state import BaseState
|
@@ -21,7 +22,9 @@ def test_templating_node__dict_output():
|
|
21
22
|
outputs = node.run()
|
22
23
|
|
23
24
|
# THEN the output is json serializable
|
24
|
-
|
25
|
+
# https://app.shortcut.com/vellum/story/6132
|
26
|
+
dump: str = outputs.result # type: ignore[assignment]
|
27
|
+
assert json.loads(dump) == {"key": "value"}
|
25
28
|
|
26
29
|
|
27
30
|
def test_templating_node__int_output():
|
@@ -106,3 +109,19 @@ def test_templating_node__execution_count_reference():
|
|
106
109
|
|
107
110
|
# THEN the output is just the total
|
108
111
|
assert outputs.result == "0"
|
112
|
+
|
113
|
+
|
114
|
+
def test_templating_node__pydantic_to_json():
|
115
|
+
# GIVEN a templating node that uses tojson on a pydantic model
|
116
|
+
class JSONTemplateNode(TemplatingNode[BaseState, Json]):
|
117
|
+
template = "{{ function_call | tojson }}"
|
118
|
+
inputs = {
|
119
|
+
"function_call": FunctionCall(name="test", arguments={"key": "value"}),
|
120
|
+
}
|
121
|
+
|
122
|
+
# WHEN the node is run
|
123
|
+
node = JSONTemplateNode()
|
124
|
+
outputs = node.run()
|
125
|
+
|
126
|
+
# THEN the output is the expected JSON
|
127
|
+
assert outputs.result == {"name": "test", "arguments": {"key": "value"}, "id": None}
|
@@ -2,7 +2,7 @@ from typing import Optional, Union
|
|
2
2
|
|
3
3
|
from vellum.workflows.constants import AuthorizationType
|
4
4
|
from vellum.workflows.nodes.displayable.bases.api_node import BaseAPINode
|
5
|
-
from vellum.workflows.
|
5
|
+
from vellum.workflows.types.core import VellumSecret
|
6
6
|
|
7
7
|
|
8
8
|
class APINode(BaseAPINode):
|
@@ -24,8 +24,8 @@ class APINode(BaseAPINode):
|
|
24
24
|
|
25
25
|
authorization_type: Optional[AuthorizationType] = None
|
26
26
|
api_key_header_key: Optional[str] = None
|
27
|
-
api_key_header_value: Optional[Union[str,
|
28
|
-
bearer_token_value: Optional[Union[str,
|
27
|
+
api_key_header_value: Optional[Union[str, VellumSecret]] = None
|
28
|
+
bearer_token_value: Optional[Union[str, VellumSecret]] = None
|
29
29
|
|
30
30
|
def run(self) -> BaseAPINode.Outputs:
|
31
31
|
headers = self.headers or {}
|
@@ -5,14 +5,14 @@ vellum_cli/aliased_group.py,sha256=ugW498j0yv4ALJ8vS9MsO7ctDW7Jlir9j6nE_uHAP8c,3
|
|
5
5
|
vellum_cli/config.py,sha256=998IZbvkrw2avjbvs8bw6NrbEgGz5UBKRbvKAcastJg,5493
|
6
6
|
vellum_cli/image_push.py,sha256=SJwhwWJsLjwGNezNVd_oCVpFMfPsAB3dfLWmriZZUtw,4419
|
7
7
|
vellum_cli/logger.py,sha256=PuRFa0WCh4sAGFS5aqWB0QIYpS6nBWwPJrIXpWxugV4,1022
|
8
|
-
vellum_cli/pull.py,sha256=
|
8
|
+
vellum_cli/pull.py,sha256=zf0y22XptUYI_hMP_4Q1CEo9s2wALsTJcCXNd-_ibd8,7551
|
9
9
|
vellum_cli/push.py,sha256=iQ2H-vY8njqiYgIifGooqopqkb1BUUA3I7IN7VIHKv8,6149
|
10
10
|
vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
-
vellum_cli/tests/conftest.py,sha256=
|
11
|
+
vellum_cli/tests/conftest.py,sha256=Jv-QUjXoCDhsvVvXEjOenNqRArO_xXhtNuCYt4wiOyE,1421
|
12
12
|
vellum_cli/tests/test_config.py,sha256=uvKGDc8BoVyT9_H0Z-g8469zVxomn6Oi3Zj-vK7O_wU,2631
|
13
13
|
vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
|
14
14
|
vellum_cli/tests/test_pull.py,sha256=6gbASF6ASy5YcdWjOCt6b5K0u2VWsFegdrTWu6sEVKs,19613
|
15
|
-
vellum_cli/tests/test_push.py,sha256=
|
15
|
+
vellum_cli/tests/test_push.py,sha256=8o8DFW9HCakhfZMS1Iql13RC90hF9pM630Y-rQbo234,8593
|
16
16
|
vellum_ee/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
17
|
vellum_ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
18
|
vellum_ee/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -84,7 +84,7 @@ vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
|
|
84
84
|
vellum/client/__init__.py,sha256=7yb5YnhvHQUJusa1WyUZcAKGol3z-Lfu07EfD03eEW4,111291
|
85
85
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
86
86
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
87
|
-
vellum/client/core/client_wrapper.py,sha256=
|
87
|
+
vellum/client/core/client_wrapper.py,sha256=Ip_JnKYTedcuVV4puh0iLeYLzPtHAxgnmwqZyCKXSCY,1869
|
88
88
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
89
89
|
vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
|
90
90
|
vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
|
@@ -668,7 +668,7 @@ vellum/evaluations/utils/paginator.py,sha256=rEED_BJAXAM6tM1yMwHePNzszjq_tTq4NbQ
|
|
668
668
|
vellum/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
669
669
|
vellum/plugins/pydantic.py,sha256=dNtZWHo-IdseG52C2RoTanxyTJg0AhPZrH-9lbNqwYg,2604
|
670
670
|
vellum/plugins/utils.py,sha256=U9ZY9KdE3RRvbcG01hXxu9CvfJD6Fo7nJDgcHjQn0FI,606
|
671
|
-
vellum/plugins/vellum_mypy.py,sha256=
|
671
|
+
vellum/plugins/vellum_mypy.py,sha256=7JmyuTX723-XWnWoE6afiUNOkHyAufCUZwxck9BP2aI,27784
|
672
672
|
vellum/prompts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
673
673
|
vellum/prompts/blocks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
674
674
|
vellum/prompts/blocks/compilation.py,sha256=ISuvDHaeVCPb1L7l4umORCECkDn0-rvE49hopz6c2gM,9222
|
@@ -1221,7 +1221,7 @@ vellum/utils/templating/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
1221
1221
|
vellum/utils/templating/constants.py,sha256=XTNmDsKa7byjw4GMZmzx2dUeYUTeMLZrPgRHcc80Kvc,613
|
1222
1222
|
vellum/utils/templating/custom_filters.py,sha256=Q0DahYRHP4KfaUXDt9XxN-DFLBrAxlv90yaVqxScoUw,264
|
1223
1223
|
vellum/utils/templating/exceptions.py,sha256=cDp140PP4OnInW4qAvg3KqiSiF70C71UyEAKRBR1Abo,46
|
1224
|
-
vellum/utils/templating/render.py,sha256=
|
1224
|
+
vellum/utils/templating/render.py,sha256=OwdZTJlQv_qsygMX3LOFr4d1_2oz3r9vGKyj7cX05VE,1876
|
1225
1225
|
vellum/utils/typing.py,sha256=wx_daFqD69cYkuJTVnvNrpjhqC3uuhbnyJ9_bIwC9OU,327
|
1226
1226
|
vellum/utils/uuid.py,sha256=Ch6wWRgwICxLxJCTl5iE3EdRlZj2zADR-zUMUtjcMWM,214
|
1227
1227
|
vellum/version.py,sha256=jq-1PlAYxN9AXuaZqbYk9ak27SgE2lw9Ia5gx1b1gVI,76
|
@@ -1286,7 +1286,7 @@ vellum/workflows/inputs/base.py,sha256=1kMgr0WqCYdWUqgFvgSoAMw2067FAlgwhGXLgbIOr
|
|
1286
1286
|
vellum/workflows/logging.py,sha256=_a217XogktV4Ncz6xKFz7WfYmZAzkfVRVuC0rWob8ls,437
|
1287
1287
|
vellum/workflows/nodes/__init__.py,sha256=aVdQVv7Y3Ro3JlqXGpxwaU2zrI06plDHD2aumH5WUIs,1157
|
1288
1288
|
vellum/workflows/nodes/bases/__init__.py,sha256=cniHuz_RXdJ4TQgD8CBzoiKDiPxg62ErdVpCbWICX64,58
|
1289
|
-
vellum/workflows/nodes/bases/base.py,sha256=
|
1289
|
+
vellum/workflows/nodes/bases/base.py,sha256=CcWQBMR3cx5vftqQp_oJ_GncULJIbOLMyNP4KZNgU10,14487
|
1290
1290
|
vellum/workflows/nodes/bases/base_adornment_node.py,sha256=eFTgsPCYb3eyGS0-kw7C6crFnwFx437R5wh9-8bWYts,2905
|
1291
1291
|
vellum/workflows/nodes/bases/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1292
1292
|
vellum/workflows/nodes/bases/tests/test_base_node.py,sha256=51CueFVty9XYASC0rKr1cXWejho5WElmhfhp6cCONy0,3811
|
@@ -1302,19 +1302,19 @@ vellum/workflows/nodes/core/map_node/node.py,sha256=DTMoGqtR8MyfZ8jy8apNoN-4KFFF
|
|
1302
1302
|
vellum/workflows/nodes/core/map_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1303
1303
|
vellum/workflows/nodes/core/map_node/tests/test_node.py,sha256=RHSZs7t6mW3UWvRrXnHZqaXVdRT2ZquOK_YHJ-gzXsU,1871
|
1304
1304
|
vellum/workflows/nodes/core/retry_node/__init__.py,sha256=lN2bIy5a3Uzhs_FYCrooADyYU6ZGShtvLKFWpelwPvo,60
|
1305
|
-
vellum/workflows/nodes/core/retry_node/node.py,sha256=
|
1305
|
+
vellum/workflows/nodes/core/retry_node/node.py,sha256=QEpxhKOyxDkRoAn2b0PToZWtAGQetSQYVTpb9yCOLlw,4028
|
1306
1306
|
vellum/workflows/nodes/core/retry_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1307
|
-
vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=
|
1307
|
+
vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=RM_OHwxrHwyxvlQQBJPqVBxpedFuWQ9h2-Xa3kP75sc,4399
|
1308
1308
|
vellum/workflows/nodes/core/templating_node/__init__.py,sha256=GmyuYo81_A1_Bz6id69ozVFS6FKiuDsZTiA3I6MaL2U,70
|
1309
1309
|
vellum/workflows/nodes/core/templating_node/node.py,sha256=N-NOBd-UY91qO9orCcW4KEbhNvDQivZPA-PCxs-M0RM,4204
|
1310
|
-
vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=
|
1310
|
+
vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=3rN5Ncwq87Y2YKyobNXALCih6OnUTJf55otnR4V20C8,3557
|
1311
1311
|
vellum/workflows/nodes/core/try_node/__init__.py,sha256=JVD4DrldTIqFQQFrubs9KtWCCc0YCAc7Fzol5ZWIWeM,56
|
1312
1312
|
vellum/workflows/nodes/core/try_node/node.py,sha256=_lTmSYCiz7lktaxpNWUCglNi8_5Sfy8Rpiov5SeKVMw,3920
|
1313
1313
|
vellum/workflows/nodes/core/try_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1314
1314
|
vellum/workflows/nodes/core/try_node/tests/test_node.py,sha256=Wc2kLl-MkffsBxl3IiFaqLd16e2Iosxhk7qBnojPvQg,4092
|
1315
1315
|
vellum/workflows/nodes/displayable/__init__.py,sha256=6F_4DlSwvHuilWnIalp8iDjjDXl0Nmz4QzJV2PYe5RI,1023
|
1316
1316
|
vellum/workflows/nodes/displayable/api_node/__init__.py,sha256=MoxdQSnidIj1Nf_d-hTxlOxcZXaZnsWFDbE-PkTK24o,56
|
1317
|
-
vellum/workflows/nodes/displayable/api_node/node.py,sha256=
|
1317
|
+
vellum/workflows/nodes/displayable/api_node/node.py,sha256=ocXjg0Sp52V6DllTDZXUgOp9qBw6l_KbtWcaxowsDM4,2070
|
1318
1318
|
vellum/workflows/nodes/displayable/bases/__init__.py,sha256=0mWIx3qUrzllV7jqt7wN03vWGMuI1WrrLZeMLT2Cl2c,304
|
1319
1319
|
vellum/workflows/nodes/displayable/bases/api_node/__init__.py,sha256=1jwx4WC358CLA1jgzl_UD-rZmdMm2v9Mps39ndwCD7U,64
|
1320
1320
|
vellum/workflows/nodes/displayable/bases/api_node/node.py,sha256=ywPwCxDesgnE86Wjyf2ZyG2Dr2O7xW8D4tPHZB5Se_s,2477
|
@@ -1415,8 +1415,8 @@ vellum/workflows/vellum_client.py,sha256=ODrq_TSl-drX2aezXegf7pizpWDVJuTXH-j6528
|
|
1415
1415
|
vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
|
1416
1416
|
vellum/workflows/workflows/base.py,sha256=qdZYQq-jjdr0fYT0FCfmFuI5ypE3pANupgYcOqqML0o,18884
|
1417
1417
|
vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnadGsrSZGa7t7LpJA,2008
|
1418
|
-
vellum_ai-0.12.
|
1419
|
-
vellum_ai-0.12.
|
1420
|
-
vellum_ai-0.12.
|
1421
|
-
vellum_ai-0.12.
|
1422
|
-
vellum_ai-0.12.
|
1418
|
+
vellum_ai-0.12.17.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1419
|
+
vellum_ai-0.12.17.dist-info/METADATA,sha256=01ujt39Or2zqLaKV_VsarQ9H_hkgSc1YfrsEOMokUUk,5328
|
1420
|
+
vellum_ai-0.12.17.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1421
|
+
vellum_ai-0.12.17.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1422
|
+
vellum_ai-0.12.17.dist-info/RECORD,,
|
vellum_cli/pull.py
CHANGED
@@ -173,10 +173,13 @@ def pull_command(
|
|
173
173
|
target.write(content)
|
174
174
|
|
175
175
|
if metadata_json:
|
176
|
-
|
177
|
-
|
178
|
-
if
|
179
|
-
workflow_config.
|
176
|
+
runner_config = metadata_json.get("runner_config")
|
177
|
+
|
178
|
+
if runner_config:
|
179
|
+
workflow_config.container_image_name = runner_config.get("container_image_name")
|
180
|
+
workflow_config.container_image_tag = runner_config.get("container_image_tag")
|
181
|
+
if workflow_config.container_image_name and not workflow_config.container_image_tag:
|
182
|
+
workflow_config.container_image_tag = "latest"
|
180
183
|
|
181
184
|
if include_json:
|
182
185
|
logger.warning(
|
vellum_cli/tests/conftest.py
CHANGED
@@ -18,11 +18,13 @@ class MockModuleResult:
|
|
18
18
|
|
19
19
|
|
20
20
|
@pytest.fixture
|
21
|
-
def mock_module() -> Generator[MockModuleResult, None, None]:
|
21
|
+
def mock_module(request) -> Generator[MockModuleResult, None, None]:
|
22
22
|
current_dir = os.getcwd()
|
23
23
|
temp_dir = tempfile.mkdtemp()
|
24
24
|
os.chdir(temp_dir)
|
25
|
-
|
25
|
+
|
26
|
+
# Use the test name to create a unique module path
|
27
|
+
module = f"examples.mock.{request.node.name}"
|
26
28
|
workflow_sandbox_id = str(uuid4())
|
27
29
|
|
28
30
|
def set_pyproject_toml(vellum_config: Dict[str, Any]) -> None:
|
vellum_cli/tests/test_push.py
CHANGED
@@ -110,13 +110,17 @@ class ExampleWorkflow(BaseWorkflow):
|
|
110
110
|
# THEN it should succeed
|
111
111
|
assert result.exit_code == 0
|
112
112
|
|
113
|
+
# Get the last part of the module path and format it
|
114
|
+
expected_label = mock_module.module.split(".")[-1].replace("_", " ").title()
|
115
|
+
expected_artifact_name = f"{mock_module.module.replace('.', '__')}.tar.gz"
|
116
|
+
|
113
117
|
# AND we should have called the push API with the correct args
|
114
118
|
vellum_client.workflows.push.assert_called_once()
|
115
119
|
call_args = vellum_client.workflows.push.call_args.kwargs
|
116
120
|
assert json.loads(call_args["exec_config"])["workflow_raw_data"]["definition"]["name"] == "ExampleWorkflow"
|
117
|
-
assert call_args["label"] ==
|
121
|
+
assert call_args["label"] == expected_label
|
118
122
|
assert is_valid_uuid(call_args["workflow_sandbox_id"])
|
119
|
-
assert call_args["artifact"].name ==
|
123
|
+
assert call_args["artifact"].name == expected_artifact_name
|
120
124
|
assert "deplyment_config" not in call_args
|
121
125
|
|
122
126
|
extracted_files = _extract_tar_gz(call_args["artifact"].read())
|
@@ -160,13 +164,17 @@ class ExampleWorkflow(BaseWorkflow):
|
|
160
164
|
# THEN it should succeed
|
161
165
|
assert result.exit_code == 0
|
162
166
|
|
167
|
+
# Get the last part of the module path and format it
|
168
|
+
expected_label = mock_module.module.split(".")[-1].replace("_", " ").title()
|
169
|
+
expected_artifact_name = f"{mock_module.module.replace('.', '__')}.tar.gz"
|
170
|
+
|
163
171
|
# AND we should have called the push API with the correct args
|
164
172
|
vellum_client.workflows.push.assert_called_once()
|
165
173
|
call_args = vellum_client.workflows.push.call_args.kwargs
|
166
174
|
assert json.loads(call_args["exec_config"])["workflow_raw_data"]["definition"]["name"] == "ExampleWorkflow"
|
167
|
-
assert call_args["label"] ==
|
175
|
+
assert call_args["label"] == expected_label
|
168
176
|
assert is_valid_uuid(call_args["workflow_sandbox_id"])
|
169
|
-
assert call_args["artifact"].name ==
|
177
|
+
assert call_args["artifact"].name == expected_artifact_name
|
170
178
|
assert call_args["deployment_config"] == "{}"
|
171
179
|
|
172
180
|
extracted_files = _extract_tar_gz(call_args["artifact"].read())
|
@@ -231,6 +239,6 @@ class ExampleWorkflow(BaseWorkflow):
|
|
231
239
|
|
232
240
|
# AND the report should be in the output
|
233
241
|
assert "## Errors" in result.output
|
234
|
-
|
242
|
+
assert "Serialization is not supported." in result.output
|
235
243
|
assert "## Proposed Diffs" in result.output
|
236
244
|
assert "iterable_item_added" in result.output
|
File without changes
|
File without changes
|
File without changes
|