vellum-ai 1.8.1__py3-none-any.whl → 1.8.3__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.
Files changed (25) hide show
  1. vellum/client/core/client_wrapper.py +2 -2
  2. vellum/client/types/integration_name.py +1 -0
  3. vellum/workflows/expressions/concat.py +6 -3
  4. vellum/workflows/expressions/tests/test_concat.py +63 -8
  5. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +20 -5
  6. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +11 -7
  7. vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py +42 -0
  8. vellum/workflows/nodes/displayable/final_output_node/node.py +7 -1
  9. vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py +28 -0
  10. vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +84 -56
  11. vellum/workflows/nodes/experimental/__init__.py +1 -3
  12. vellum/workflows/runner/runner.py +144 -0
  13. vellum/workflows/state/context.py +59 -7
  14. vellum/workflows/workflows/base.py +17 -0
  15. vellum/workflows/workflows/event_filters.py +13 -0
  16. vellum/workflows/workflows/tests/test_event_filters.py +126 -0
  17. {vellum_ai-1.8.1.dist-info → vellum_ai-1.8.3.dist-info}/METADATA +1 -1
  18. {vellum_ai-1.8.1.dist-info → vellum_ai-1.8.3.dist-info}/RECORD +23 -23
  19. vellum_ee/workflows/display/utils/expressions.py +4 -0
  20. vellum_ee/workflows/display/utils/tests/test_expressions.py +86 -0
  21. vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py +0 -5
  22. vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py +0 -266
  23. {vellum_ai-1.8.1.dist-info → vellum_ai-1.8.3.dist-info}/LICENSE +0 -0
  24. {vellum_ai-1.8.1.dist-info → vellum_ai-1.8.3.dist-info}/WHEEL +0 -0
  25. {vellum_ai-1.8.1.dist-info → vellum_ai-1.8.3.dist-info}/entry_points.txt +0 -0
@@ -74,6 +74,9 @@ from vellum.workflows.references import ExternalInputReference, OutputReference
74
74
  from vellum.workflows.references.state_value import StateValueReference
75
75
  from vellum.workflows.state.base import BaseState
76
76
  from vellum.workflows.state.delta import StateDelta
77
+ from vellum.workflows.triggers.base import BaseTrigger
78
+ from vellum.workflows.triggers.integration import IntegrationTrigger
79
+ from vellum.workflows.triggers.manual import ManualTrigger
77
80
  from vellum.workflows.types.core import CancelSignal
78
81
  from vellum.workflows.types.generics import InputsType, OutputsType, StateType
79
82
 
@@ -109,6 +112,7 @@ class WorkflowRunner(Generic[StateType]):
109
112
  max_concurrency: Optional[int] = None,
110
113
  timeout: Optional[float] = None,
111
114
  init_execution_context: Optional[ExecutionContext] = None,
115
+ trigger: Optional[BaseTrigger] = None,
112
116
  ):
113
117
  if state and external_inputs:
114
118
  raise ValueError("Can only run a Workflow providing one of state or external inputs, not both")
@@ -198,7 +202,24 @@ class WorkflowRunner(Generic[StateType]):
198
202
  )
199
203
 
200
204
  self._entrypoints = self.workflow.get_entrypoints()
205
+ elif trigger:
206
+ # When trigger is provided, set up default state and filter entrypoints by trigger type
207
+ normalized_inputs = deepcopy(inputs) if inputs else self.workflow.get_default_inputs()
208
+ if state:
209
+ self._initial_state = deepcopy(state)
210
+ self._initial_state.meta.workflow_inputs = normalized_inputs
211
+ self._initial_state.meta.span_id = uuid4()
212
+ self._initial_state.meta.workflow_definition = self.workflow.__class__
213
+ else:
214
+ self._initial_state = self.workflow.get_default_state(normalized_inputs)
215
+ self._should_emit_initial_state = False
216
+
217
+ # Validate and bind trigger, then filter entrypoints
218
+ self._validate_and_bind_trigger(trigger)
219
+ self._entrypoints = self.workflow.get_entrypoints()
220
+ self._filter_entrypoints_for_trigger(trigger)
201
221
  else:
222
+ # Default case: no entrypoint overrides and no trigger
202
223
  normalized_inputs = deepcopy(inputs) if inputs else self.workflow.get_default_inputs()
203
224
  if state:
204
225
  self._initial_state = deepcopy(state)
@@ -213,6 +234,9 @@ class WorkflowRunner(Generic[StateType]):
213
234
  self._should_emit_initial_state = False
214
235
  self._entrypoints = self.workflow.get_entrypoints()
215
236
 
237
+ # Check if workflow requires a trigger but none was provided
238
+ self._validate_no_trigger_provided()
239
+
216
240
  # This queue is responsible for sending events from WorkflowRunner to the outside world
217
241
  self._workflow_event_outer_queue: Queue[WorkflowEvent] = Queue()
218
242
 
@@ -250,6 +274,126 @@ class WorkflowRunner(Generic[StateType]):
250
274
  self._cancel_thread: Optional[Thread] = None
251
275
  self._timeout_thread: Optional[Thread] = None
252
276
 
277
+ def _has_manual_trigger(self) -> bool:
278
+ """Check if workflow has ManualTrigger."""
279
+ for subgraph in self.workflow.get_subgraphs():
280
+ for trigger in subgraph.triggers:
281
+ if issubclass(trigger, ManualTrigger):
282
+ return True
283
+ return False
284
+
285
+ def _get_entrypoints_for_trigger_type(self, trigger_class: Type) -> List[Type[BaseNode]]:
286
+ """Get all entrypoints connected to a specific trigger type.
287
+
288
+ Allows subclasses: if trigger_class is a subclass of any declared trigger,
289
+ returns those entrypoints.
290
+ """
291
+ entrypoints: List[Type[BaseNode]] = []
292
+ for subgraph in self.workflow.get_subgraphs():
293
+ for trigger in subgraph.triggers:
294
+ # Check if the provided trigger_class is a subclass of the declared trigger
295
+ # This allows runtime instances to be subclasses of what's declared in the workflow
296
+ if issubclass(trigger_class, trigger):
297
+ entrypoints.extend(subgraph.entrypoints)
298
+ return entrypoints
299
+
300
+ def _validate_and_bind_trigger(self, trigger: BaseTrigger) -> None:
301
+ """
302
+ Validate that trigger is compatible with workflow and bind it to state.
303
+
304
+ Supports all trigger types derived from BaseTrigger:
305
+ - IntegrationTrigger instances (Slack, Gmail, etc.)
306
+ - ManualTrigger instances (explicit manual execution)
307
+ - ScheduledTrigger instances (time-based triggers)
308
+ - Any future trigger types
309
+
310
+ Raises:
311
+ WorkflowInitializationException: If trigger type is not compatible with workflow
312
+ """
313
+ trigger_class = type(trigger)
314
+
315
+ # Search for a compatible trigger type in the workflow
316
+ found_compatible_trigger = False
317
+ has_any_triggers = False
318
+ incompatible_trigger_names: List[str] = []
319
+
320
+ for subgraph in self.workflow.get_subgraphs():
321
+ for declared_trigger in subgraph.triggers:
322
+ has_any_triggers = True
323
+ # Allow subclasses: if workflow declares BaseSlackTrigger, accept SpecificSlackTrigger instances
324
+ if issubclass(trigger_class, declared_trigger):
325
+ found_compatible_trigger = True
326
+ break
327
+ else:
328
+ incompatible_trigger_names.append(declared_trigger.__name__)
329
+
330
+ if found_compatible_trigger:
331
+ break
332
+
333
+ # Special case: workflows with no explicit triggers implicitly support ManualTrigger
334
+ if not has_any_triggers and not isinstance(trigger, ManualTrigger):
335
+ raise WorkflowInitializationException(
336
+ message=f"Provided trigger type {trigger_class.__name__} is not compatible with workflow. "
337
+ f"Workflow has no explicit triggers and only supports ManualTrigger.",
338
+ workflow_definition=self.workflow.__class__,
339
+ code=WorkflowErrorCode.INVALID_INPUTS,
340
+ )
341
+
342
+ # Validate that we found a compatible trigger type
343
+ if has_any_triggers and not found_compatible_trigger:
344
+ raise WorkflowInitializationException(
345
+ message=f"Provided trigger type {trigger_class.__name__} is not compatible with workflow triggers. "
346
+ f"Workflow has: {sorted(set(incompatible_trigger_names))}",
347
+ workflow_definition=self.workflow.__class__,
348
+ code=WorkflowErrorCode.INVALID_INPUTS,
349
+ )
350
+
351
+ # Bind trigger to state (works for all trigger types via BaseTrigger.bind_to_state)
352
+ trigger.bind_to_state(self._initial_state)
353
+
354
+ def _filter_entrypoints_for_trigger(self, trigger: BaseTrigger) -> None:
355
+ """
356
+ Filter entrypoints to those connected to the specific trigger type.
357
+
358
+ Uses the specific trigger subclass, not the parent class, allowing workflows
359
+ with multiple triggers to route to the correct path.
360
+ """
361
+ trigger_class = type(trigger)
362
+ specific_entrypoints = self._get_entrypoints_for_trigger_type(trigger_class)
363
+ if specific_entrypoints:
364
+ self._entrypoints = specific_entrypoints
365
+
366
+ def _validate_no_trigger_provided(self) -> None:
367
+ """
368
+ Validate that workflow can run without a trigger.
369
+
370
+ If workflow has IntegrationTrigger(s) but no ManualTrigger, it requires a trigger instance.
371
+ If workflow has both, filter entrypoints to ManualTrigger path only.
372
+
373
+ Raises:
374
+ WorkflowInitializationException: If workflow requires trigger but none was provided
375
+ """
376
+ # Collect all IntegrationTrigger types in the workflow
377
+ workflow_integration_triggers = []
378
+ for subgraph in self.workflow.get_subgraphs():
379
+ for trigger_type in subgraph.triggers:
380
+ if issubclass(trigger_type, IntegrationTrigger):
381
+ workflow_integration_triggers.append(trigger_type)
382
+
383
+ if workflow_integration_triggers:
384
+ if not self._has_manual_trigger():
385
+ # Workflow has ONLY IntegrationTrigger - this is an error
386
+ raise WorkflowInitializationException(
387
+ message="Workflow has IntegrationTrigger which requires trigger parameter",
388
+ workflow_definition=self.workflow.__class__,
389
+ code=WorkflowErrorCode.INVALID_INPUTS,
390
+ )
391
+
392
+ # Workflow has both IntegrationTrigger and ManualTrigger - filter to ManualTrigger path
393
+ manual_entrypoints = self._get_entrypoints_for_trigger_type(ManualTrigger)
394
+ if manual_entrypoints:
395
+ self._entrypoints = manual_entrypoints
396
+
253
397
  @contextmanager
254
398
  def _httpx_logger_with_span_id(self) -> Iterator[None]:
255
399
  """
@@ -1,7 +1,8 @@
1
+ from dataclasses import dataclass
1
2
  from functools import cached_property
2
3
  from queue import Queue
3
4
  from uuid import UUID, uuid4
4
- from typing import TYPE_CHECKING, Dict, List, Optional, Type
5
+ from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Type
5
6
 
6
7
  from vellum import Vellum, __version__
7
8
  from vellum.workflows.context import ExecutionContext, get_execution_context, set_execution_context
@@ -19,6 +20,18 @@ if TYPE_CHECKING:
19
20
  from vellum.workflows.workflows.base import BaseWorkflow
20
21
 
21
22
 
23
+ @dataclass
24
+ class WorkflowDeploymentMetadata:
25
+ """Metadata about a workflow deployment needed for parent context construction."""
26
+
27
+ deployment_id: UUID
28
+ deployment_name: str
29
+ deployment_history_item_id: UUID
30
+ release_tag_id: UUID
31
+ release_tag_name: str
32
+ workflow_version_id: UUID
33
+
34
+
22
35
  class WorkflowContext:
23
36
  def __init__(
24
37
  self,
@@ -148,7 +161,7 @@ class WorkflowContext:
148
161
 
149
162
  def resolve_workflow_deployment(
150
163
  self, deployment_name: str, release_tag: str, state: "BaseState"
151
- ) -> Optional["BaseWorkflow"]:
164
+ ) -> Optional[Tuple[Type["BaseWorkflow"], Optional[WorkflowDeploymentMetadata]]]:
152
165
  """
153
166
  Resolve a workflow deployment by name and release tag.
154
167
 
@@ -158,20 +171,22 @@ class WorkflowContext:
158
171
  state: The base state to pass to the workflow
159
172
 
160
173
  Returns:
161
- BaseWorkflow instance if found, None otherwise
174
+ Tuple of (BaseWorkflow class, deployment metadata) if found
162
175
  """
163
176
  if not self._generated_files or not self._namespace:
164
177
  return None
165
178
 
166
179
  expected_prefix = generate_workflow_deployment_prefix(deployment_name, release_tag)
167
180
 
181
+ deployment_metadata = self._fetch_deployment_metadata(deployment_name, release_tag)
182
+
168
183
  try:
169
184
  from vellum.workflows.workflows.base import BaseWorkflow
170
185
 
171
186
  WorkflowClass = BaseWorkflow.load_from_module(f"{self.namespace}.{expected_prefix}")
172
187
  WorkflowClass.is_dynamic = True
173
- workflow_instance = WorkflowClass(context=WorkflowContext.create_from(self), parent_state=state)
174
- return workflow_instance
188
+ # Return the class, not an instance, so caller can instantiate within proper execution context
189
+ return (WorkflowClass, deployment_metadata)
175
190
  except Exception:
176
191
  pass
177
192
 
@@ -200,14 +215,51 @@ class WorkflowContext:
200
215
 
201
216
  WorkflowClass = BaseWorkflow.load_from_module(f"{self.namespace}.{expected_prefix}")
202
217
  WorkflowClass.is_dynamic = True
203
- workflow_instance = WorkflowClass(context=WorkflowContext.create_from(self), parent_state=state)
204
- return workflow_instance
218
+ # Return the class, not an instance, so caller can instantiate within proper execution context
219
+ return (WorkflowClass, deployment_metadata)
205
220
 
206
221
  except Exception:
207
222
  pass
208
223
 
209
224
  return None
210
225
 
226
+ def _fetch_deployment_metadata(
227
+ self, deployment_name: str, release_tag: str
228
+ ) -> Optional[WorkflowDeploymentMetadata]:
229
+ """
230
+ Fetch deployment metadata from the Vellum API.
231
+
232
+ Args:
233
+ deployment_name: The name of the workflow deployment
234
+ release_tag: The release tag name
235
+
236
+ Returns:
237
+ WorkflowDeploymentMetadata if successful, None otherwise
238
+ """
239
+ try:
240
+ # Fetch deployment details
241
+ deployment = self.vellum_client.workflow_deployments.retrieve(deployment_name)
242
+
243
+ deployment_id = UUID(deployment.id)
244
+
245
+ # Fetch release tag details
246
+ release_tag_info = self.vellum_client.workflow_deployments.retrieve_workflow_release_tag(
247
+ deployment.id, release_tag
248
+ )
249
+
250
+ return WorkflowDeploymentMetadata(
251
+ deployment_id=deployment_id,
252
+ deployment_name=deployment.name,
253
+ deployment_history_item_id=UUID(deployment.last_deployed_history_item_id),
254
+ release_tag_id=UUID(release_tag_info.release.id),
255
+ release_tag_name=release_tag_info.name,
256
+ workflow_version_id=uuid4(),
257
+ )
258
+ except Exception:
259
+ # If we fail to fetch metadata, return None - the workflow can still run
260
+ # but won't have the full parent context hierarchy
261
+ return None
262
+
211
263
  @classmethod
212
264
  def create_from(cls, context):
213
265
  return cls(
@@ -79,6 +79,7 @@ from vellum.workflows.runner.runner import ExternalInputsArg, RunFromNodeArg
79
79
  from vellum.workflows.state.base import BaseState, StateMeta
80
80
  from vellum.workflows.state.context import WorkflowContext
81
81
  from vellum.workflows.state.store import Store
82
+ from vellum.workflows.triggers.base import BaseTrigger
82
83
  from vellum.workflows.types import CancelSignal
83
84
  from vellum.workflows.types.generics import InputsType, StateType
84
85
  from vellum.workflows.types.utils import get_original_base
@@ -382,6 +383,7 @@ class BaseWorkflow(Generic[InputsType, StateType], BaseExecutable, metaclass=_Ba
382
383
  node_output_mocks: Optional[MockNodeExecutionArg] = None,
383
384
  max_concurrency: Optional[int] = None,
384
385
  timeout: Optional[float] = None,
386
+ trigger: Optional[BaseTrigger] = None,
385
387
  ) -> TerminalWorkflowEvent:
386
388
  """
387
389
  Invoke a Workflow, returning the last event emitted, which should be one of:
@@ -422,6 +424,12 @@ class BaseWorkflow(Generic[InputsType, StateType], BaseExecutable, metaclass=_Ba
422
424
  timeout: Optional[float] = None
423
425
  The maximum time in seconds to allow the Workflow to run. If the timeout is exceeded, the Workflow
424
426
  will be rejected with a WORKFLOW_TIMEOUT error code and any nodes in flight will be rejected.
427
+
428
+ trigger: Optional[BaseTrigger] = None
429
+ A trigger instance for workflows with triggers (e.g., IntegrationTrigger, ManualTrigger, ScheduledTrigger).
430
+ The trigger instance is bound to the workflow state, making its attributes accessible to downstream nodes.
431
+ Required for workflows that only have IntegrationTrigger; optional for workflows with both ManualTrigger
432
+ and IntegrationTrigger.
425
433
  """
426
434
 
427
435
  runner = WorkflowRunner(
@@ -436,6 +444,7 @@ class BaseWorkflow(Generic[InputsType, StateType], BaseExecutable, metaclass=_Ba
436
444
  max_concurrency=max_concurrency,
437
445
  timeout=timeout,
438
446
  init_execution_context=self._execution_context,
447
+ trigger=trigger,
439
448
  )
440
449
  self._current_runner = runner
441
450
  events = runner.stream()
@@ -507,6 +516,7 @@ class BaseWorkflow(Generic[InputsType, StateType], BaseExecutable, metaclass=_Ba
507
516
  node_output_mocks: Optional[MockNodeExecutionArg] = None,
508
517
  max_concurrency: Optional[int] = None,
509
518
  timeout: Optional[float] = None,
519
+ trigger: Optional[BaseTrigger] = None,
510
520
  ) -> WorkflowEventStream:
511
521
  """
512
522
  Invoke a Workflow, yielding events as they are emitted.
@@ -548,6 +558,12 @@ class BaseWorkflow(Generic[InputsType, StateType], BaseExecutable, metaclass=_Ba
548
558
  timeout: Optional[float] = None
549
559
  The maximum time in seconds to allow the Workflow to run. If the timeout is exceeded, the Workflow
550
560
  will be rejected with a WORKFLOW_TIMEOUT error code and any nodes in flight will be rejected.
561
+
562
+ trigger: Optional[BaseTrigger] = None
563
+ A trigger instance for workflows with triggers (e.g., IntegrationTrigger, ManualTrigger, ScheduledTrigger).
564
+ The trigger instance is bound to the workflow state, making its attributes accessible to downstream nodes.
565
+ Required for workflows that only have IntegrationTrigger; optional for workflows with both ManualTrigger
566
+ and IntegrationTrigger.
551
567
  """
552
568
 
553
569
  should_yield = event_filter or workflow_event_filter
@@ -563,6 +579,7 @@ class BaseWorkflow(Generic[InputsType, StateType], BaseExecutable, metaclass=_Ba
563
579
  max_concurrency=max_concurrency,
564
580
  timeout=timeout,
565
581
  init_execution_context=self._execution_context,
582
+ trigger=trigger,
566
583
  )
567
584
  self._current_runner = runner
568
585
  runner_stream = runner.stream()
@@ -52,5 +52,18 @@ def root_workflow_event_filter(workflow_definition: Type["BaseWorkflow"], event:
52
52
  return event_parent_definition.model_dump() == current_workflow_definition.model_dump()
53
53
 
54
54
 
55
+ def workflow_sandbox_event_filter(workflow_definition: Type["BaseWorkflow"], event: "WorkflowEvent") -> bool:
56
+ """
57
+ Filter designed for Workflow Sandbox interfaces: include all events except
58
+ workflow.execution.snapshotted events from nested/subworkflows. Only allow
59
+ snapshotted events when they belong to the root workflow definition.
60
+ """
61
+
62
+ if event.name == "workflow.execution.snapshotted":
63
+ return event.workflow_definition == workflow_definition
64
+
65
+ return True
66
+
67
+
55
68
  def all_workflow_event_filter(workflow_definition: Type["BaseWorkflow"], event: "WorkflowEvent") -> bool:
56
69
  return True
@@ -0,0 +1,126 @@
1
+ from vellum.workflows.inputs import BaseInputs
2
+ from vellum.workflows.nodes import BaseNode, InlineSubworkflowNode
3
+ from vellum.workflows.outputs.base import BaseOutputs
4
+ from vellum.workflows.state.base import BaseState
5
+ from vellum.workflows.workflows.base import BaseWorkflow
6
+ from vellum.workflows.workflows.event_filters import workflow_sandbox_event_filter
7
+
8
+
9
+ class NestedInputs(BaseInputs):
10
+ value: str
11
+
12
+
13
+ class NestedNode(BaseNode):
14
+ value = NestedInputs.value
15
+
16
+ class Outputs(BaseOutputs):
17
+ result: str
18
+
19
+ def run(self) -> Outputs:
20
+ return self.Outputs(result=f"nested: {self.value}")
21
+
22
+
23
+ class NestedWorkflow(BaseWorkflow[NestedInputs, BaseState]):
24
+ graph = NestedNode
25
+
26
+ class Outputs(BaseOutputs):
27
+ result = NestedNode.Outputs.result
28
+
29
+
30
+ class ParentInputs(BaseInputs):
31
+ value: str
32
+
33
+
34
+ class SubworkflowNode(InlineSubworkflowNode):
35
+ subworkflow_inputs = {
36
+ "value": ParentInputs.value,
37
+ }
38
+ subworkflow = NestedWorkflow
39
+
40
+
41
+ class ParentWorkflow(BaseWorkflow[ParentInputs, BaseState]):
42
+ graph = SubworkflowNode
43
+
44
+ class Outputs(BaseOutputs):
45
+ result = SubworkflowNode.Outputs.result
46
+
47
+
48
+ def test_workflow_sandbox_event_filter__filters_nested_workflow_snapshotted_events():
49
+ """
50
+ Tests that workflow_sandbox_event_filter filters out snapshotted events from nested workflows.
51
+ """
52
+
53
+ workflow = ParentWorkflow()
54
+
55
+ # WHEN we stream the workflow with workflow_sandbox_event_filter
56
+ events = list(
57
+ workflow.stream(
58
+ inputs=ParentInputs(value="test"),
59
+ event_filter=workflow_sandbox_event_filter,
60
+ )
61
+ )
62
+
63
+ snapshotted_events = [e for e in events if e.name == "workflow.execution.snapshotted"]
64
+ assert len(snapshotted_events) > 0
65
+
66
+ for event in snapshotted_events:
67
+ assert event.workflow_definition == ParentWorkflow
68
+
69
+
70
+ def test_workflow_sandbox_event_filter__includes_root_workflow_snapshotted_events():
71
+ """
72
+ Tests that workflow_sandbox_event_filter includes snapshotted events from the root workflow.
73
+ """
74
+
75
+ class SimpleNode(BaseNode):
76
+ class Outputs(BaseOutputs):
77
+ result: str = "simple"
78
+
79
+ def run(self) -> Outputs:
80
+ return self.Outputs()
81
+
82
+ class SimpleWorkflow(BaseWorkflow[BaseInputs, BaseState]):
83
+ graph = SimpleNode
84
+
85
+ class Outputs(BaseOutputs):
86
+ result = SimpleNode.Outputs.result
87
+
88
+ workflow = SimpleWorkflow()
89
+
90
+ # WHEN we stream the workflow with workflow_sandbox_event_filter
91
+ events = list(
92
+ workflow.stream(
93
+ inputs=BaseInputs(),
94
+ event_filter=workflow_sandbox_event_filter,
95
+ )
96
+ )
97
+
98
+ snapshotted_events = [e for e in events if e.name == "workflow.execution.snapshotted"]
99
+ assert len(snapshotted_events) > 0
100
+
101
+ for event in snapshotted_events:
102
+ assert event.workflow_definition == SimpleWorkflow
103
+
104
+
105
+ def test_workflow_sandbox_event_filter__includes_nested_workflow_non_snapshotted_events():
106
+ """
107
+ Tests that workflow_sandbox_event_filter includes non-snapshotted events from nested workflows.
108
+ """
109
+
110
+ workflow = ParentWorkflow()
111
+
112
+ # WHEN we stream the workflow with workflow_sandbox_event_filter
113
+ events = list(
114
+ workflow.stream(
115
+ inputs=ParentInputs(value="test"),
116
+ event_filter=workflow_sandbox_event_filter,
117
+ )
118
+ )
119
+
120
+ nested_workflow_events = [
121
+ e for e in events if hasattr(e, "workflow_definition") and e.workflow_definition == NestedWorkflow
122
+ ]
123
+ assert len(nested_workflow_events) > 0
124
+
125
+ for event in nested_workflow_events:
126
+ assert event.name != "workflow.execution.snapshotted"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 1.8.1
3
+ Version: 1.8.3
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0
@@ -121,11 +121,12 @@ vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeR
121
121
  vellum_ee/workflows/display/utils/auto_layout.py,sha256=f4GiLn_LazweupfqTpubcdtdfE_vrOcmZudSsnYIY9E,3906
122
122
  vellum_ee/workflows/display/utils/events.py,sha256=XcaQSfmk2s9ZNiU8__ZqH_zfp6KUVACczz9TBWVy7Jc,2208
123
123
  vellum_ee/workflows/display/utils/exceptions.py,sha256=E8Lvo7LY1BoZ54M_NR_opDjJsAAiCUfow1HgoHcTHmg,989
124
- vellum_ee/workflows/display/utils/expressions.py,sha256=9rcpoXhUIxcWy407Ziu-zJfP5OEFq3pHIh7XSZZ1Y6E,21169
124
+ vellum_ee/workflows/display/utils/expressions.py,sha256=q6jgr13gET3rsAtz9XAPqtWQ2RKq_ZMq2OwrtyPhlRg,21345
125
125
  vellum_ee/workflows/display/utils/registry.py,sha256=1qXiBTdsnro6FeCX0FGBEK7CIf6wa--Jt50iZ_nEp_M,3460
126
126
  vellum_ee/workflows/display/utils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
127
127
  vellum_ee/workflows/display/utils/tests/test_auto_layout.py,sha256=vfXI769418s9vda5Gb5NFBH747WMOwSgHRXeLCTLVm8,2356
128
128
  vellum_ee/workflows/display/utils/tests/test_events.py,sha256=CiBx4WxeNAf1WGfgRdJ_I-Hc12RDfza73CMLB5HkOFg,6688
129
+ vellum_ee/workflows/display/utils/tests/test_expressions.py,sha256=s8aHAwuuJS1_WI1B9geJCpTVKPk83XqrCI_ofVG80TI,4268
129
130
  vellum_ee/workflows/display/utils/vellum.py,sha256=Bt7kdLdXoBsHn5dVEY2uKcF542VL09jwu8J_30rl2vk,6413
130
131
  vellum_ee/workflows/display/vellum.py,sha256=J2mdJZ1sdLW535DDUkq_Vm8Z572vhuxHxVZF9deKSdk,391
131
132
  vellum_ee/workflows/display/workflows/__init__.py,sha256=JTB9ObEV3l4gGGdtfBHwVJtTTKC22uj-a-XjTVwXCyA,148
@@ -163,7 +164,7 @@ vellum/client/README.md,sha256=flqu57ubZNTfpq60CdLtJC9gp4WEkyjb_n_eZ4OYf9w,6497
163
164
  vellum/client/__init__.py,sha256=-nugZzQKoUJsStXe6PnOD__8kbDLKKokceDgpGxQ_q0,74576
164
165
  vellum/client/core/__init__.py,sha256=lTcqUPXcx4112yLDd70RAPeqq6tu3eFMe1pKOqkW9JQ,1562
165
166
  vellum/client/core/api_error.py,sha256=44vPoTyWN59gonCIZMdzw7M1uspygiLnr3GNFOoVL2Q,614
166
- vellum/client/core/client_wrapper.py,sha256=Nc6y6FZVXFJVLzna3Fwov3q7K_kZe-vhjAth09SQMUI,2840
167
+ vellum/client/core/client_wrapper.py,sha256=llC4_oYnck1KfRr1_t-bhr-vbslTBI_bKlGt64fTYQY,2840
167
168
  vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
168
169
  vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
169
170
  vellum/client/core/force_multipart.py,sha256=awxh5MtcRYe74ehY8U76jzv6fYM_w_D3Rur7KQQzSDk,429
@@ -497,7 +498,7 @@ vellum/client/types/integration.py,sha256=WqfHEskiMzNxuy5mmcXTARPQ4F3r99Jf-g-wVl
497
498
  vellum/client/types/integration_auth_config_integration.py,sha256=W3DrzVPwLrqm0wCYVF-sHyQPoKNxoliFgFJWEwW_Yqc,710
498
499
  vellum/client/types/integration_auth_config_integration_credential.py,sha256=lUNuJ1GyFps3M85Mff1C-SAeEacCMkJdmayFfYrTFXA,547
499
500
  vellum/client/types/integration_credential_access_type.py,sha256=sWkuDjW3aD7ApZ1xQ7Bu8g5kCIwqUqzm1TDliUQWeRI,178
500
- vellum/client/types/integration_name.py,sha256=Lccmj64V1h5PZT5nmyqtJ6WmcpkDOtpYzsqdrZx19WA,1207
501
+ vellum/client/types/integration_name.py,sha256=5YatDLwjK5QttKIAgwc662WVJZyfVmK7D7DIqkmNZdw,1226
501
502
  vellum/client/types/integration_provider.py,sha256=lIh3yPyPEzmSAu8L4Gsd-iDkmDSNobo0_TB75zMtIXk,129
502
503
  vellum/client/types/integration_read.py,sha256=sUNCS01TIlHPJHEH3ZheIbPi-CplbFQ5XAV1QtOO1Gg,1035
503
504
  vellum/client/types/invoked_port.py,sha256=nw2k-y7NrpcH6T1V96U3F8_pbrsceqBPIz3RQXN8gJY,518
@@ -1846,7 +1847,7 @@ vellum/workflows/expressions/begins_with.py,sha256=FnWsQXbENm0ZwkfEP7dR8Qx4_MMrz
1846
1847
  vellum/workflows/expressions/between.py,sha256=dVeddT6YA91eOAlE1Utg7C7gnCiYE7WP-dg17yXUeAY,1492
1847
1848
  vellum/workflows/expressions/coalesce_expression.py,sha256=s4pcfu8KkUaUlQkB6BoQUKitGmV1FIQfV4agHHZtd98,1194
1848
1849
  vellum/workflows/expressions/comparison_utils.py,sha256=99eioXIMvqqSvm0iqluCtwzMkJGLq-bkVSaJ4LtZYBQ,1206
1849
- vellum/workflows/expressions/concat.py,sha256=bFiHeCpZWfMMO_nvFmM5RgN-hoh-5ThBtxP0EJ2F7BE,1105
1850
+ vellum/workflows/expressions/concat.py,sha256=6FWnlBf-sSCelGVa922Tyh2u7A4VD6LGBwVgjUT7DkA,1167
1850
1851
  vellum/workflows/expressions/contains.py,sha256=6QET3cuGTj_OF5GCYgOZUh7-_l3lsDiaOYsEEuHV-9E,1642
1851
1852
  vellum/workflows/expressions/does_not_begin_with.py,sha256=qcnIJsxg4Jt82i2L-PW6ZhKP3C-OlEiXbiIgwHQc5RE,1137
1852
1853
  vellum/workflows/expressions/does_not_contain.py,sha256=ZdHVewTe_pbPGB0cGv_gIq_4jKkv_oG2tX3RBdEGWoA,1266
@@ -1877,7 +1878,7 @@ vellum/workflows/expressions/parse_json.py,sha256=xsk6j3HF7bU1yF6fwt5P9Ugcyd5D9Z
1877
1878
  vellum/workflows/expressions/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1878
1879
  vellum/workflows/expressions/tests/test_accessor.py,sha256=g2z0mJjuWwVKeXS0yGoFW-aRmT5n_LrhfuBorSmj9kI,7585
1879
1880
  vellum/workflows/expressions/tests/test_add.py,sha256=_MjlRvIGAVM5wve2ru5jc_5Ae4x_ywvh4vN0S2yQ-8M,1615
1880
- vellum/workflows/expressions/tests/test_concat.py,sha256=fDHXlmFvCtqPkdZQD9Qs22i6sJq_MJjbUXCnTlSMvA0,1666
1881
+ vellum/workflows/expressions/tests/test_concat.py,sha256=KE4fFRh96K_vuIZid2bZ-4kxaW3jTxyQ578UIrsLkPE,3205
1881
1882
  vellum/workflows/expressions/tests/test_contains.py,sha256=9jO9U0Idcjwxb9gnK1f_CFsn-vahAKE7TG45xNWWcmg,4878
1882
1883
  vellum/workflows/expressions/tests/test_expressions.py,sha256=e5CMwcOPQPvvDerhJ5Zm3TaXv84oyOYKu7oRRtQnmSA,17192
1883
1884
  vellum/workflows/expressions/tests/test_length.py,sha256=pQA1tYSwqxE6euclboY024NXEOs7yaVgwTKkMPYUT08,1035
@@ -1942,11 +1943,11 @@ vellum/workflows/nodes/displayable/bases/api_node/node.py,sha256=cOYaIqimzDL6TuX
1942
1943
  vellum/workflows/nodes/displayable/bases/api_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1943
1944
  vellum/workflows/nodes/displayable/bases/api_node/tests/test_node.py,sha256=5C59vn_yg4r5EWioKIr658Jr1MSGX3YF4yKJokY37Xc,4726
1944
1945
  vellum/workflows/nodes/displayable/bases/base_prompt_node/__init__.py,sha256=Org3xTvgp1pA0uUXFfnJr29D3HzCey2lEdYF4zbIUgo,70
1945
- vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py,sha256=oN1GF47DPj1WgED1c5SO2XBInU7Gqaa6rAZGKsTFgv8,5299
1946
+ vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py,sha256=Qzy8ZJ_2jnRk6p4FVrSj7MJ0hQu9vdVP41OslH2PsHA,5825
1946
1947
  vellum/workflows/nodes/displayable/bases/inline_prompt_node/__init__.py,sha256=Hl35IAoepRpE-j4cALaXVJIYTYOF3qszyVbxTj4kS1s,82
1947
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=ctl2KeCpdA7Wb32Rpw4EhwHNctADek2ijYFtv1LmdwQ,19352
1948
+ vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py,sha256=3juPEPESTztVMHm6zj534_1SZs7k91Z39MjsLF2MJX4,19470
1948
1949
  vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1949
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py,sha256=V2lDma5G4f-u-9xeCB3oH5KtJBZIIHKb4b9niwJGHuo,30381
1950
+ vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py,sha256=5xaGT7YsfYI5gpoL0ggHvY8JiDkj9Do4vCRq9M_NRZ8,31785
1950
1951
  vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py,sha256=iwYZBxrZsbJnifBV11ANPOnVLGhWIlJZaOt7br6srqQ,12620
1951
1952
  vellum/workflows/nodes/displayable/bases/search_node.py,sha256=9TtFn6oNpEkpCL59QdBViUe4WPjcITajbiS7EOjOGag,6114
1952
1953
  vellum/workflows/nodes/displayable/bases/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1965,9 +1966,9 @@ vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU
1965
1966
  vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=2g32hWosE3zwVaK2UPFnVEer1Nbn04s3friF2rGztmE,1195
1966
1967
  vellum/workflows/nodes/displayable/conftest.py,sha256=K2kLM2JGAfcrmmd92u8DXInUO5klFdggPWblg5RVcx4,5729
1967
1968
  vellum/workflows/nodes/displayable/final_output_node/__init__.py,sha256=G7VXM4OWpubvSJtVkGmMNeqgb9GkM7qZT838eL18XU4,72
1968
- vellum/workflows/nodes/displayable/final_output_node/node.py,sha256=1_F9S7w-gIEUoXIdilgpqDeCKxJ0_J0oTYvE35dbjHk,4908
1969
+ vellum/workflows/nodes/displayable/final_output_node/node.py,sha256=ypetAGBaTjVozKqAos-C1LG5HHZ3iUekw7v2mnnUlOw,5175
1969
1970
  vellum/workflows/nodes/displayable/final_output_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1970
- vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py,sha256=FR7lWUJlcWW1e9q_3vefi-b8_LA7CayZgTWZAnlAiLg,2387
1971
+ vellum/workflows/nodes/displayable/final_output_node/tests/test_node.py,sha256=Drj7tMNEBDzHIYQ5iLkIK0zHHj-NxiswCtefVbfDFRo,3418
1971
1972
  vellum/workflows/nodes/displayable/guardrail_node/__init__.py,sha256=Ab5eXmOoBhyV4dMWdzh32HLUmnPIBEK_zFCT38C4Fng,68
1972
1973
  vellum/workflows/nodes/displayable/guardrail_node/node.py,sha256=axYUojar_kdB3gi4LG3g9euJ8VkOxNtiFxJNI46v-SQ,5869
1973
1974
  vellum/workflows/nodes/displayable/guardrail_node/test_node.py,sha256=SAGv6hSFcBwQkudn1VxtaKNsXSXWWELl3eK05zM6tS0,5410
@@ -1990,7 +1991,7 @@ vellum/workflows/nodes/displayable/search_node/node.py,sha256=hbPsZhyXfq9dx0mfBK
1990
1991
  vellum/workflows/nodes/displayable/search_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1991
1992
  vellum/workflows/nodes/displayable/search_node/tests/test_node.py,sha256=YXgIIAJHVQxrfyJ0gxeJC0fAJaic10_zbqvsS8hyZSc,9368
1992
1993
  vellum/workflows/nodes/displayable/subworkflow_deployment_node/__init__.py,sha256=9yYM6001YZeqI1VOk1QuEM_yrffk_EdsO7qaPzINKds,92
1993
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py,sha256=sDrRgk4xY7HaDQHXbF-7nmEWHArSB1nqEFXgH-qKfZU,14522
1994
+ vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py,sha256=_4aJxlnSEQKUlL9DAXYdrv1ic0tC7IyvYV389HHGyvE,16281
1994
1995
  vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1995
1996
  vellum/workflows/nodes/displayable/subworkflow_deployment_node/tests/test_node.py,sha256=PII44speqT4fJvj60y_3KDAnH1L6Ivtq9R4BykY-X_A,19092
1996
1997
  vellum/workflows/nodes/displayable/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -2011,9 +2012,7 @@ vellum/workflows/nodes/displayable/web_search_node/node.py,sha256=NQYux2bOtuBF5E
2011
2012
  vellum/workflows/nodes/displayable/web_search_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2012
2013
  vellum/workflows/nodes/displayable/web_search_node/tests/test_node.py,sha256=H3titxCYFsfIJ3EDeRL6Pe9I-tdKMRt1axOwb2qIw6U,10983
2013
2014
  vellum/workflows/nodes/experimental/README.md,sha256=eF6DfIL8t-HbF9-mcofOMymKrraiBHDLKTlnBa51ZiE,284
2014
- vellum/workflows/nodes/experimental/__init__.py,sha256=jCQgvZEknXKfuNhGSOou4XPfrPqZ1_XBj5F0n0fgiWM,106
2015
- vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py,sha256=lsyD9laR9p7kx5-BXGH2gUTM242UhKy8SMV0SR6S2iE,90
2016
- vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py,sha256=cKI2Ls25L-JVt4z4a2ozQa-YBeVy21Z7BQ32Sj7iBPE,10460
2015
+ vellum/workflows/nodes/experimental/__init__.py,sha256=juqd9PbXs4yg45zMJ7BHAOPQjb7sgEbWE9InBtGZhfo,24
2017
2016
  vellum/workflows/nodes/mocks.py,sha256=FXvP049s1KuilDqjUub12Y81rjR9vgPdX8pu6oBSjoE,10931
2018
2017
  vellum/workflows/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2019
2018
  vellum/workflows/nodes/tests/test_mocks.py,sha256=mfPvrs75PKcsNsbJLQAN6PDFoVqs9TmQxpdyFKDdO60,7837
@@ -2046,11 +2045,11 @@ vellum/workflows/resolvers/resolver.py,sha256=3uEYscB_2PHTazc0Y9SzOe_yiQZhVLfey1
2046
2045
  vellum/workflows/resolvers/tests/test_resolver.py,sha256=PnUGzsulo1It_LjjhHsRNiILvvl5G_IaK8ZX56zKC28,6204
2047
2046
  vellum/workflows/resolvers/types.py,sha256=Hndhlk69g6EKLh_LYg5ILepW5U_h_BYNllfzhS9k8p4,237
2048
2047
  vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8vyT-bqM,72
2049
- vellum/workflows/runner/runner.py,sha256=agF7TeqUBcXFuiQrCpevSJvQKnpMSdfLy6o-P0EZZXs,47813
2048
+ vellum/workflows/runner/runner.py,sha256=mMJzRT1iMsJ8YLYcbTsrKH8l2VDxqlC-sD8xY7pIoGY,54834
2050
2049
  vellum/workflows/sandbox.py,sha256=mezSZmilR_fwR8164n8CEfzlMeQ55IqfapHp4ftImvQ,3212
2051
2050
  vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
2052
2051
  vellum/workflows/state/base.py,sha256=8Zr7UIM_eC0O2N6w_1gYqyrjgJ9D9z-VqLFnBETEF7Q,26753
2053
- vellum/workflows/state/context.py,sha256=khM30U1iDNts5Xp8LXa_WfpkITNITexrDUUFJ5wZ2W4,8445
2052
+ vellum/workflows/state/context.py,sha256=wMp6g23V1RNGWMksogfYIg8PqtFE9UxlfLfLpvhD9EU,10412
2054
2053
  vellum/workflows/state/delta.py,sha256=7h8wR10lRCm15SykaPj-gSEvvsMjCwYLPsOx3nsvBQg,440
2055
2054
  vellum/workflows/state/encoder.py,sha256=elZ70SEUTxhGa3vpxdrfjUotDT6NvhDCPWtP-VSjCH0,2029
2056
2055
  vellum/workflows/state/store.py,sha256=uVe-oN73KwGV6M6YLhwZMMUQhzTQomsVfVnb8V91gVo,1147
@@ -2093,13 +2092,14 @@ vellum/workflows/utils/vellum_variables.py,sha256=X3lZn-EoWengRWBWRhTNW7hqbj7LkV
2093
2092
  vellum/workflows/utils/zip.py,sha256=HVg_YZLmBOTXKaDV3Xhaf3V6sYnfqqZXQ8CpuafkbPY,1181
2094
2093
  vellum/workflows/vellum_client.py,sha256=3iDR7VV_NgLSm1iZQCKDvrmfEaX1bOJiU15QrxyHpv0,1237
2095
2094
  vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
2096
- vellum/workflows/workflows/base.py,sha256=uG17grQ3zvAl4ZbddPjfftZOCw1qjTo_LLjISixmU7g,32276
2097
- vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnadGsrSZGa7t7LpJA,2008
2095
+ vellum/workflows/workflows/base.py,sha256=jeIjmHclZtBG9I5uh0H0rqHOF6nVpxoF0bomvOHK2sU,33361
2096
+ vellum/workflows/workflows/event_filters.py,sha256=OzaS1y_z1f7H4f4M914HttAfAuTiN0jXUmo1TUQagCY,2504
2098
2097
  vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2099
2098
  vellum/workflows/workflows/tests/test_base_workflow.py,sha256=Boa-_m9ii2Qsa1RvVM-VYniF7zCpzGgEGy-OnPZkrHg,23941
2100
2099
  vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
2101
- vellum_ai-1.8.1.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
2102
- vellum_ai-1.8.1.dist-info/METADATA,sha256=DWOrpnEfvfz7WdwnejydRvKJau7iQDUFZZCSpLQZ3xE,5547
2103
- vellum_ai-1.8.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
2104
- vellum_ai-1.8.1.dist-info/entry_points.txt,sha256=xVavzAKN4iF_NbmhWOlOkHluka0YLkbN_pFQ9pW3gLI,117
2105
- vellum_ai-1.8.1.dist-info/RECORD,,
2100
+ vellum/workflows/workflows/tests/test_event_filters.py,sha256=CPsgtn2F8QMuNMxN5MB6IwTY0y_8JWBCZsio75vxp6c,3638
2101
+ vellum_ai-1.8.3.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
2102
+ vellum_ai-1.8.3.dist-info/METADATA,sha256=hc54GAN5QhytozkoojSXEZ30tE_YUqvfOFrOUy-OK_Y,5547
2103
+ vellum_ai-1.8.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
2104
+ vellum_ai-1.8.3.dist-info/entry_points.txt,sha256=xVavzAKN4iF_NbmhWOlOkHluka0YLkbN_pFQ9pW3gLI,117
2105
+ vellum_ai-1.8.3.dist-info/RECORD,,