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.
Files changed (103) hide show
  1. vellum/client/core/client_wrapper.py +1 -1
  2. vellum/client/types/logical_operator.py +2 -0
  3. vellum/evaluations/resources.py +7 -12
  4. vellum/evaluations/utils/env.py +1 -3
  5. vellum/evaluations/utils/paginator.py +0 -1
  6. vellum/evaluations/utils/typing.py +1 -1
  7. vellum/evaluations/utils/uuid.py +1 -1
  8. vellum/plugins/vellum_mypy.py +3 -1
  9. vellum/workflows/descriptors/utils.py +27 -0
  10. vellum/workflows/events/__init__.py +0 -2
  11. vellum/workflows/events/node.py +7 -6
  12. vellum/workflows/events/tests/test_event.py +2 -2
  13. vellum/workflows/events/types.py +35 -30
  14. vellum/workflows/events/workflow.py +33 -8
  15. vellum/workflows/nodes/bases/base.py +49 -26
  16. vellum/workflows/nodes/bases/tests/test_base_node.py +0 -1
  17. vellum/workflows/nodes/core/templating_node/node.py +1 -0
  18. vellum/workflows/nodes/core/try_node/node.py +22 -4
  19. vellum/workflows/nodes/core/try_node/tests/test_node.py +16 -3
  20. vellum/workflows/nodes/displayable/bases/api_node/node.py +1 -1
  21. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +0 -1
  22. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +0 -1
  23. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +2 -1
  24. vellum/workflows/nodes/displayable/bases/search_node.py +0 -1
  25. vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +0 -1
  26. vellum/workflows/nodes/displayable/code_execution_node/utils.py +3 -2
  27. vellum/workflows/nodes/displayable/conditional_node/node.py +1 -1
  28. vellum/workflows/nodes/displayable/guardrail_node/node.py +0 -1
  29. vellum/workflows/nodes/displayable/inline_prompt_node/node.py +1 -0
  30. vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +3 -1
  31. vellum/workflows/nodes/displayable/search_node/node.py +1 -0
  32. vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +3 -2
  33. vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +10 -7
  34. vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py +0 -1
  35. vellum/workflows/outputs/base.py +2 -4
  36. vellum/workflows/ports/node_ports.py +1 -1
  37. vellum/workflows/runner/runner.py +185 -157
  38. vellum/workflows/state/base.py +55 -23
  39. vellum/workflows/state/context.py +26 -3
  40. vellum/workflows/types/core.py +1 -0
  41. vellum/workflows/types/tests/test_utils.py +1 -0
  42. vellum/workflows/types/utils.py +0 -1
  43. vellum/workflows/utils/functions.py +74 -0
  44. vellum/workflows/utils/tests/test_functions.py +171 -0
  45. vellum/workflows/utils/tests/test_vellum_variables.py +0 -1
  46. vellum/workflows/utils/vellum_variables.py +2 -2
  47. vellum/workflows/workflows/base.py +84 -10
  48. vellum/workflows/workflows/event_filters.py +53 -0
  49. {vellum_ai-0.10.8.dist-info → vellum_ai-0.11.0.dist-info}/METADATA +1 -1
  50. {vellum_ai-0.10.8.dist-info → vellum_ai-0.11.0.dist-info}/RECORD +101 -93
  51. vellum_cli/__init__.py +147 -13
  52. vellum_cli/config.py +0 -1
  53. vellum_cli/image_push.py +1 -1
  54. vellum_cli/pull.py +29 -19
  55. vellum_cli/push.py +9 -10
  56. vellum_cli/tests/__init__.py +0 -0
  57. vellum_cli/tests/conftest.py +40 -0
  58. vellum_cli/tests/test_main.py +11 -0
  59. vellum_cli/tests/test_pull.py +125 -71
  60. vellum_cli/tests/test_push.py +173 -0
  61. vellum_ee/workflows/display/nodes/base_node_display.py +3 -2
  62. vellum_ee/workflows/display/nodes/base_node_vellum_display.py +2 -2
  63. vellum_ee/workflows/display/nodes/get_node_display_class.py +1 -1
  64. vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +1 -1
  65. vellum_ee/workflows/display/nodes/vellum/__init__.py +5 -3
  66. vellum_ee/workflows/display/nodes/vellum/api_node.py +4 -7
  67. vellum_ee/workflows/display/nodes/vellum/conditional_node.py +39 -22
  68. vellum_ee/workflows/display/nodes/vellum/error_node.py +49 -0
  69. vellum_ee/workflows/display/nodes/vellum/final_output_node.py +0 -2
  70. vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +1 -1
  71. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +1 -1
  72. vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +4 -2
  73. vellum_ee/workflows/display/nodes/vellum/map_node.py +11 -5
  74. vellum_ee/workflows/display/nodes/vellum/merge_node.py +2 -2
  75. vellum_ee/workflows/display/nodes/vellum/note_node.py +1 -3
  76. vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +1 -1
  77. vellum_ee/workflows/display/nodes/vellum/search_node.py +1 -1
  78. vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +1 -1
  79. vellum_ee/workflows/display/nodes/vellum/templating_node.py +1 -1
  80. vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +5 -5
  81. vellum_ee/workflows/display/nodes/vellum/utils.py +4 -4
  82. vellum_ee/workflows/display/tests/test_vellum_workflow_display.py +45 -0
  83. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +13 -24
  84. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +13 -39
  85. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +203 -0
  86. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +2 -2
  87. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +62 -58
  88. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +25 -4
  89. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +2 -1
  90. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +2 -2
  91. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +2 -2
  92. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +1 -1
  93. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +2 -1
  94. vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +2 -2
  95. vellum_ee/workflows/display/types.py +4 -4
  96. vellum_ee/workflows/display/utils/vellum.py +2 -6
  97. vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +4 -1
  98. vellum_ee/workflows/display/workflows/vellum_workflow_display.py +6 -2
  99. vellum/workflows/events/utils.py +0 -5
  100. vellum/workflows/runner/types.py +0 -16
  101. {vellum_ai-0.10.8.dist-info → vellum_ai-0.11.0.dist-info}/LICENSE +0 -0
  102. {vellum_ai-0.10.8.dist-info → vellum_ai-0.11.0.dist-info}/WHEEL +0 -0
  103. {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[Union[Type[BaseNode], Graph, Set[Type[BaseNode]], Set[Graph]]]
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(code=VellumErrorCode.INTERNAL_ERROR, message="No events were emitted"),
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, message="Initiated event was never emitted"
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
- event_types: Optional[Set[WorkflowEventType]] = None,
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
- event_types = event_types or {WorkflowEventType.WORKFLOW}
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 WorkflowEventType(event.name.split(".")[0].upper()) in event_types:
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(cls) -> Tuple[Type[WorkflowInputsType], Type[StateType]]:
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(parent=self._parent_state, workflow_inputs=workflow_inputs or self.get_default_inputs())
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 0.10.8
3
+ Version: 0.11.0
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0