vellum-ai 0.10.8__py3-none-any.whl → 0.11.0__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/client/types/logical_operator.py +2 -0
- vellum/evaluations/resources.py +7 -12
- vellum/evaluations/utils/env.py +1 -3
- vellum/evaluations/utils/paginator.py +0 -1
- vellum/evaluations/utils/typing.py +1 -1
- vellum/evaluations/utils/uuid.py +1 -1
- vellum/plugins/vellum_mypy.py +3 -1
- vellum/workflows/descriptors/utils.py +27 -0
- vellum/workflows/events/__init__.py +0 -2
- vellum/workflows/events/node.py +7 -6
- vellum/workflows/events/tests/test_event.py +2 -2
- vellum/workflows/events/types.py +35 -30
- vellum/workflows/events/workflow.py +33 -8
- vellum/workflows/nodes/bases/base.py +49 -26
- vellum/workflows/nodes/bases/tests/test_base_node.py +0 -1
- vellum/workflows/nodes/core/templating_node/node.py +1 -0
- vellum/workflows/nodes/core/try_node/node.py +22 -4
- vellum/workflows/nodes/core/try_node/tests/test_node.py +16 -3
- vellum/workflows/nodes/displayable/bases/api_node/node.py +1 -1
- vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +0 -1
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +0 -1
- vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +2 -1
- vellum/workflows/nodes/displayable/bases/search_node.py +0 -1
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +0 -1
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +3 -2
- vellum/workflows/nodes/displayable/conditional_node/node.py +1 -1
- vellum/workflows/nodes/displayable/guardrail_node/node.py +0 -1
- vellum/workflows/nodes/displayable/inline_prompt_node/node.py +1 -0
- vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +3 -1
- vellum/workflows/nodes/displayable/search_node/node.py +1 -0
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +3 -2
- vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +10 -7
- vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py +0 -1
- vellum/workflows/outputs/base.py +2 -4
- vellum/workflows/ports/node_ports.py +1 -1
- vellum/workflows/runner/runner.py +185 -157
- vellum/workflows/state/base.py +55 -23
- vellum/workflows/state/context.py +26 -3
- vellum/workflows/types/core.py +1 -0
- vellum/workflows/types/tests/test_utils.py +1 -0
- vellum/workflows/types/utils.py +0 -1
- vellum/workflows/utils/functions.py +74 -0
- vellum/workflows/utils/tests/test_functions.py +171 -0
- vellum/workflows/utils/tests/test_vellum_variables.py +0 -1
- vellum/workflows/utils/vellum_variables.py +2 -2
- vellum/workflows/workflows/base.py +84 -10
- vellum/workflows/workflows/event_filters.py +53 -0
- {vellum_ai-0.10.8.dist-info → vellum_ai-0.11.0.dist-info}/METADATA +1 -1
- {vellum_ai-0.10.8.dist-info → vellum_ai-0.11.0.dist-info}/RECORD +101 -93
- vellum_cli/__init__.py +147 -13
- vellum_cli/config.py +0 -1
- vellum_cli/image_push.py +1 -1
- vellum_cli/pull.py +29 -19
- vellum_cli/push.py +9 -10
- vellum_cli/tests/__init__.py +0 -0
- vellum_cli/tests/conftest.py +40 -0
- vellum_cli/tests/test_main.py +11 -0
- vellum_cli/tests/test_pull.py +125 -71
- vellum_cli/tests/test_push.py +173 -0
- vellum_ee/workflows/display/nodes/base_node_display.py +3 -2
- vellum_ee/workflows/display/nodes/base_node_vellum_display.py +2 -2
- vellum_ee/workflows/display/nodes/get_node_display_class.py +1 -1
- vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/__init__.py +5 -3
- vellum_ee/workflows/display/nodes/vellum/api_node.py +4 -7
- vellum_ee/workflows/display/nodes/vellum/conditional_node.py +39 -22
- vellum_ee/workflows/display/nodes/vellum/error_node.py +49 -0
- vellum_ee/workflows/display/nodes/vellum/final_output_node.py +0 -2
- vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +4 -2
- vellum_ee/workflows/display/nodes/vellum/map_node.py +11 -5
- vellum_ee/workflows/display/nodes/vellum/merge_node.py +2 -2
- vellum_ee/workflows/display/nodes/vellum/note_node.py +1 -3
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/search_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/templating_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +5 -5
- vellum_ee/workflows/display/nodes/vellum/utils.py +4 -4
- vellum_ee/workflows/display/tests/test_vellum_workflow_display.py +45 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +13 -24
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +13 -39
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +203 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +2 -2
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +62 -58
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +25 -4
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +2 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +2 -2
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +2 -2
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +1 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +2 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +2 -2
- vellum_ee/workflows/display/types.py +4 -4
- vellum_ee/workflows/display/utils/vellum.py +2 -6
- vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +4 -1
- vellum_ee/workflows/display/workflows/vellum_workflow_display.py +6 -2
- vellum/workflows/events/utils.py +0 -5
- vellum/workflows/runner/types.py +0 -16
- {vellum_ai-0.10.8.dist-info → vellum_ai-0.11.0.dist-info}/LICENSE +0 -0
- {vellum_ai-0.10.8.dist-info → vellum_ai-0.11.0.dist-info}/WHEEL +0 -0
- {vellum_ai-0.10.8.dist-info → vellum_ai-0.11.0.dist-info}/entry_points.txt +0 -0
@@ -4,6 +4,7 @@ import importlib
|
|
4
4
|
import inspect
|
5
5
|
|
6
6
|
from vellum.plugins.utils import load_runtime_plugins
|
7
|
+
from vellum.workflows.workflows.event_filters import workflow_event_filter
|
7
8
|
|
8
9
|
load_runtime_plugins()
|
9
10
|
|
@@ -13,6 +14,7 @@ from threading import Event as ThreadingEvent
|
|
13
14
|
from uuid import uuid4
|
14
15
|
from typing import (
|
15
16
|
Any,
|
17
|
+
Callable,
|
16
18
|
ClassVar,
|
17
19
|
Dict,
|
18
20
|
Generator,
|
@@ -47,7 +49,6 @@ from vellum.workflows.events.node import (
|
|
47
49
|
NodeExecutionStreamingBody,
|
48
50
|
NodeExecutionStreamingEvent,
|
49
51
|
)
|
50
|
-
from vellum.workflows.events.types import WorkflowEventType
|
51
52
|
from vellum.workflows.events.workflow import (
|
52
53
|
GenericWorkflowEvent,
|
53
54
|
WorkflowExecutionFulfilledBody,
|
@@ -60,6 +61,8 @@ from vellum.workflows.events.workflow import (
|
|
60
61
|
WorkflowExecutionRejectedEvent,
|
61
62
|
WorkflowExecutionResumedBody,
|
62
63
|
WorkflowExecutionResumedEvent,
|
64
|
+
WorkflowExecutionSnapshottedBody,
|
65
|
+
WorkflowExecutionSnapshottedEvent,
|
63
66
|
WorkflowExecutionStreamingBody,
|
64
67
|
WorkflowExecutionStreamingEvent,
|
65
68
|
)
|
@@ -80,13 +83,16 @@ from vellum.workflows.types.utils import get_original_base
|
|
80
83
|
class _BaseWorkflowMeta(type):
|
81
84
|
def __new__(mcs, name: str, bases: Tuple[Type, ...], dct: Dict[str, Any]) -> Any:
|
82
85
|
if "graph" not in dct:
|
83
|
-
dct["graph"] =
|
86
|
+
dct["graph"] = set()
|
84
87
|
|
85
88
|
return super().__new__(mcs, name, bases, dct)
|
86
89
|
|
87
90
|
|
91
|
+
GraphAttribute = Union[Type[BaseNode], Graph, Set[Type[BaseNode]], Set[Graph]]
|
92
|
+
|
93
|
+
|
88
94
|
class BaseWorkflow(Generic[WorkflowInputsType, StateType], metaclass=_BaseWorkflowMeta):
|
89
|
-
graph: ClassVar[
|
95
|
+
graph: ClassVar[GraphAttribute]
|
90
96
|
emitters: List[BaseWorkflowEmitter]
|
91
97
|
resolvers: List[BaseWorkflowResolver]
|
92
98
|
|
@@ -97,6 +103,7 @@ class BaseWorkflow(Generic[WorkflowInputsType, StateType], metaclass=_BaseWorkfl
|
|
97
103
|
GenericWorkflowEvent,
|
98
104
|
WorkflowExecutionInitiatedEvent[WorkflowInputsType], # type: ignore[valid-type]
|
99
105
|
WorkflowExecutionFulfilledEvent[Outputs],
|
106
|
+
WorkflowExecutionSnapshottedEvent[StateType], # type: ignore[valid-type]
|
100
107
|
]
|
101
108
|
|
102
109
|
TerminalWorkflowEvent = Union[
|
@@ -181,6 +188,31 @@ class BaseWorkflow(Generic[WorkflowInputsType, StateType], metaclass=_BaseWorkfl
|
|
181
188
|
external_inputs: Optional[ExternalInputsArg] = None,
|
182
189
|
cancel_signal: Optional[ThreadingEvent] = None,
|
183
190
|
) -> TerminalWorkflowEvent:
|
191
|
+
"""
|
192
|
+
Invoke a Workflow, returning the last event emitted, which should be one of:
|
193
|
+
- `WorkflowExecutionFulfilledEvent` if the Workflow Execution was successful
|
194
|
+
- `WorkflowExecutionRejectedEvent` if the Workflow Execution was rejected
|
195
|
+
- `WorkflowExecutionPausedEvent` if the Workflow Execution was paused
|
196
|
+
|
197
|
+
Parameters
|
198
|
+
----------
|
199
|
+
inputs: Optional[WorkflowInputsType] = None
|
200
|
+
The Inputs instance used to initiate the Workflow Execution.
|
201
|
+
|
202
|
+
state: Optional[StateType] = None
|
203
|
+
The State instance to run the Workflow with. Workflows maintain a global state that can be used to
|
204
|
+
deterministically resume execution from any point.
|
205
|
+
|
206
|
+
entrypoint_nodes: Optional[RunFromNodeArg] = None
|
207
|
+
The entrypoint nodes to run the Workflow with. Useful for resuming execution from a specific node.
|
208
|
+
|
209
|
+
external_inputs: Optional[ExternalInputsArg] = None
|
210
|
+
External inputs to pass to the Workflow. Useful for providing human-in-the-loop behavior to the Workflow.
|
211
|
+
|
212
|
+
cancel_signal: Optional[ThreadingEvent] = None
|
213
|
+
A threading event that can be used to cancel the Workflow Execution.
|
214
|
+
"""
|
215
|
+
|
184
216
|
events = WorkflowRunner(
|
185
217
|
self,
|
186
218
|
inputs=inputs,
|
@@ -188,6 +220,7 @@ class BaseWorkflow(Generic[WorkflowInputsType, StateType], metaclass=_BaseWorkfl
|
|
188
220
|
entrypoint_nodes=entrypoint_nodes,
|
189
221
|
external_inputs=external_inputs,
|
190
222
|
cancel_signal=cancel_signal,
|
223
|
+
parent_context=self._context.parent_context,
|
191
224
|
).stream()
|
192
225
|
first_event: Optional[Union[WorkflowExecutionInitiatedEvent, WorkflowExecutionResumedEvent]] = None
|
193
226
|
last_event = None
|
@@ -201,7 +234,10 @@ class BaseWorkflow(Generic[WorkflowInputsType, StateType], metaclass=_BaseWorkfl
|
|
201
234
|
trace_id=uuid4(),
|
202
235
|
span_id=uuid4(),
|
203
236
|
body=WorkflowExecutionRejectedBody(
|
204
|
-
error=VellumError(
|
237
|
+
error=VellumError(
|
238
|
+
code=VellumErrorCode.INTERNAL_ERROR,
|
239
|
+
message="No events were emitted",
|
240
|
+
),
|
205
241
|
workflow_definition=self.__class__,
|
206
242
|
),
|
207
243
|
)
|
@@ -212,7 +248,8 @@ class BaseWorkflow(Generic[WorkflowInputsType, StateType], metaclass=_BaseWorkfl
|
|
212
248
|
span_id=uuid4(),
|
213
249
|
body=WorkflowExecutionRejectedBody(
|
214
250
|
error=VellumError(
|
215
|
-
code=VellumErrorCode.INTERNAL_ERROR,
|
251
|
+
code=VellumErrorCode.INTERNAL_ERROR,
|
252
|
+
message="Initiated event was never emitted",
|
216
253
|
),
|
217
254
|
workflow_definition=self.__class__,
|
218
255
|
),
|
@@ -239,14 +276,40 @@ class BaseWorkflow(Generic[WorkflowInputsType, StateType], metaclass=_BaseWorkfl
|
|
239
276
|
|
240
277
|
def stream(
|
241
278
|
self,
|
242
|
-
|
279
|
+
event_filter: Optional[Callable[[Type["BaseWorkflow"], WorkflowEvent], bool]] = None,
|
243
280
|
inputs: Optional[WorkflowInputsType] = None,
|
244
281
|
state: Optional[StateType] = None,
|
245
282
|
entrypoint_nodes: Optional[RunFromNodeArg] = None,
|
246
283
|
external_inputs: Optional[ExternalInputsArg] = None,
|
247
284
|
cancel_signal: Optional[ThreadingEvent] = None,
|
248
285
|
) -> WorkflowEventStream:
|
249
|
-
|
286
|
+
"""
|
287
|
+
Invoke a Workflow, yielding events as they are emitted.
|
288
|
+
|
289
|
+
Parameters
|
290
|
+
----------
|
291
|
+
event_filter: Optional[Callable[[Type["BaseWorkflow"], WorkflowEvent], bool]] = None
|
292
|
+
A filter that can be used to filter events based on the Workflow Class and the event itself. If the method
|
293
|
+
returns `False`, the event will not be yielded.
|
294
|
+
|
295
|
+
inputs: Optional[WorkflowInputsType] = None
|
296
|
+
The Inputs instance used to initiate the Workflow Execution.
|
297
|
+
|
298
|
+
state: Optional[StateType] = None
|
299
|
+
The State instance to run the Workflow with. Workflows maintain a global state that can be used to
|
300
|
+
deterministically resume execution from any point.
|
301
|
+
|
302
|
+
entrypoint_nodes: Optional[RunFromNodeArg] = None
|
303
|
+
The entrypoint nodes to run the Workflow with. Useful for resuming execution from a specific node.
|
304
|
+
|
305
|
+
external_inputs: Optional[ExternalInputsArg] = None
|
306
|
+
External inputs to pass to the Workflow. Useful for providing human-in-the-loop behavior to the Workflow.
|
307
|
+
|
308
|
+
cancel_signal: Optional[ThreadingEvent] = None
|
309
|
+
A threading event that can be used to cancel the Workflow Execution.
|
310
|
+
"""
|
311
|
+
|
312
|
+
should_yield = event_filter or workflow_event_filter
|
250
313
|
for event in WorkflowRunner(
|
251
314
|
self,
|
252
315
|
inputs=inputs,
|
@@ -254,8 +317,9 @@ class BaseWorkflow(Generic[WorkflowInputsType, StateType], metaclass=_BaseWorkfl
|
|
254
317
|
entrypoint_nodes=entrypoint_nodes,
|
255
318
|
external_inputs=external_inputs,
|
256
319
|
cancel_signal=cancel_signal,
|
320
|
+
parent_context=self.context.parent_context,
|
257
321
|
).stream():
|
258
|
-
if
|
322
|
+
if should_yield(self.__class__, event):
|
259
323
|
yield event
|
260
324
|
|
261
325
|
def validate(self) -> None:
|
@@ -268,7 +332,9 @@ class BaseWorkflow(Generic[WorkflowInputsType, StateType], metaclass=_BaseWorkfl
|
|
268
332
|
|
269
333
|
@classmethod
|
270
334
|
@lru_cache
|
271
|
-
def _get_parameterized_classes(
|
335
|
+
def _get_parameterized_classes(
|
336
|
+
cls,
|
337
|
+
) -> Tuple[Type[WorkflowInputsType], Type[StateType]]:
|
272
338
|
original_base = get_original_base(cls)
|
273
339
|
|
274
340
|
inputs_type, state_type = get_args(original_base)
|
@@ -299,7 +365,10 @@ class BaseWorkflow(Generic[WorkflowInputsType, StateType], metaclass=_BaseWorkfl
|
|
299
365
|
|
300
366
|
def get_default_state(self, workflow_inputs: Optional[WorkflowInputsType] = None) -> StateType:
|
301
367
|
return self.get_state_class()(
|
302
|
-
meta=StateMeta(
|
368
|
+
meta=StateMeta(
|
369
|
+
parent=self._parent_state,
|
370
|
+
workflow_inputs=workflow_inputs or self.get_default_inputs(),
|
371
|
+
)
|
303
372
|
)
|
304
373
|
|
305
374
|
def get_state_at_node(self, node: Type[BaseNode]) -> StateType:
|
@@ -342,6 +411,9 @@ class BaseWorkflow(Generic[WorkflowInputsType, StateType], metaclass=_BaseWorkfl
|
|
342
411
|
|
343
412
|
workflows: List[Type[BaseWorkflow]] = []
|
344
413
|
for name in dir(module):
|
414
|
+
if name.startswith("__"):
|
415
|
+
continue
|
416
|
+
|
345
417
|
attr = getattr(module, name)
|
346
418
|
if (
|
347
419
|
inspect.isclass(attr)
|
@@ -365,6 +437,7 @@ WorkflowExecutionRejectedBody.model_rebuild()
|
|
365
437
|
WorkflowExecutionPausedBody.model_rebuild()
|
366
438
|
WorkflowExecutionResumedBody.model_rebuild()
|
367
439
|
WorkflowExecutionStreamingBody.model_rebuild()
|
440
|
+
WorkflowExecutionSnapshottedBody.model_rebuild()
|
368
441
|
|
369
442
|
NodeExecutionInitiatedBody.model_rebuild()
|
370
443
|
NodeExecutionFulfilledBody.model_rebuild()
|
@@ -379,6 +452,7 @@ WorkflowExecutionRejectedEvent.model_rebuild()
|
|
379
452
|
WorkflowExecutionPausedEvent.model_rebuild()
|
380
453
|
WorkflowExecutionResumedEvent.model_rebuild()
|
381
454
|
WorkflowExecutionStreamingEvent.model_rebuild()
|
455
|
+
WorkflowExecutionSnapshottedEvent.model_rebuild()
|
382
456
|
|
383
457
|
NodeExecutionInitiatedEvent.model_rebuild()
|
384
458
|
NodeExecutionFulfilledEvent.model_rebuild()
|
@@ -0,0 +1,53 @@
|
|
1
|
+
from typing import TYPE_CHECKING, Type
|
2
|
+
|
3
|
+
from vellum.workflows.events.types import CodeResourceDefinition
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from vellum.workflows.events.workflow import WorkflowEvent
|
7
|
+
from vellum.workflows.workflows.base import BaseWorkflow
|
8
|
+
|
9
|
+
|
10
|
+
def workflow_event_filter(workflow_definition: Type["BaseWorkflow"], event: "WorkflowEvent") -> bool:
|
11
|
+
"""
|
12
|
+
Filters for only Workflow events that were emitted by the `workflow_definition` parameter.
|
13
|
+
"""
|
14
|
+
|
15
|
+
if (
|
16
|
+
event.name == "workflow.execution.initiated"
|
17
|
+
or event.name == "workflow.execution.resumed"
|
18
|
+
or event.name == "workflow.execution.fulfilled"
|
19
|
+
or event.name == "workflow.execution.rejected"
|
20
|
+
or event.name == "workflow.execution.paused"
|
21
|
+
or event.name == "workflow.execution.streaming"
|
22
|
+
):
|
23
|
+
return event.workflow_definition == workflow_definition
|
24
|
+
|
25
|
+
return False
|
26
|
+
|
27
|
+
|
28
|
+
def root_workflow_event_filter(workflow_definition: Type["BaseWorkflow"], event: "WorkflowEvent") -> bool:
|
29
|
+
"""
|
30
|
+
Filters for Workflow and Node events that were emitted by the `workflow_definition` parameter.
|
31
|
+
"""
|
32
|
+
|
33
|
+
if (
|
34
|
+
event.name == "workflow.execution.initiated"
|
35
|
+
or event.name == "workflow.execution.resumed"
|
36
|
+
or event.name == "workflow.execution.fulfilled"
|
37
|
+
or event.name == "workflow.execution.rejected"
|
38
|
+
or event.name == "workflow.execution.paused"
|
39
|
+
or event.name == "workflow.execution.streaming"
|
40
|
+
):
|
41
|
+
return event.workflow_definition == workflow_definition
|
42
|
+
|
43
|
+
if not event.parent:
|
44
|
+
return False
|
45
|
+
|
46
|
+
if event.parent.type != "WORKFLOW":
|
47
|
+
return False
|
48
|
+
|
49
|
+
return event.parent.workflow_definition == CodeResourceDefinition.encode(workflow_definition)
|
50
|
+
|
51
|
+
|
52
|
+
def all_workflow_event_filter(workflow_definition: Type["BaseWorkflow"], event: "WorkflowEvent") -> bool:
|
53
|
+
return True
|