vellum-ai 1.7.11__py3-none-any.whl → 1.7.13__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.

Potentially problematic release.


This version of vellum-ai might be problematic. Click here for more details.

Files changed (37) hide show
  1. vellum/__init__.py +2 -0
  2. vellum/client/core/client_wrapper.py +2 -2
  3. vellum/client/types/__init__.py +2 -0
  4. vellum/client/types/auth_type_enum.py +5 -0
  5. vellum/client/types/integration_name.py +4 -0
  6. vellum/client/types/slim_integration_auth_config_read.py +2 -0
  7. vellum/client/types/slim_workflow_execution_read.py +3 -3
  8. vellum/client/types/vellum_error_code_enum.py +1 -0
  9. vellum/client/types/vellum_sdk_error_code_enum.py +1 -0
  10. vellum/client/types/workflow_event_execution_read.py +3 -3
  11. vellum/client/types/workflow_execution_event_error_code.py +1 -0
  12. vellum/client/types/workflow_execution_snapshotted_body.py +1 -0
  13. vellum/types/auth_type_enum.py +3 -0
  14. vellum/workflows/events/workflow.py +18 -2
  15. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +3 -0
  16. vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py +3 -0
  17. vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py +52 -0
  18. vellum/workflows/nodes/displayable/tool_calling_node/utils.py +2 -0
  19. vellum/workflows/references/trigger.py +3 -9
  20. vellum/workflows/runner/runner.py +14 -8
  21. vellum/workflows/tests/triggers/test_vellum_integration_trigger.py +134 -176
  22. vellum/workflows/triggers/__init__.py +1 -2
  23. vellum/workflows/triggers/tests/test_integration.py +2 -2
  24. vellum/workflows/triggers/vellum_integration.py +133 -141
  25. vellum/workflows/types/trigger_exec_config.py +8 -11
  26. vellum/workflows/utils/uuids.py +33 -0
  27. {vellum_ai-1.7.11.dist-info → vellum_ai-1.7.13.dist-info}/METADATA +1 -1
  28. {vellum_ai-1.7.11.dist-info → vellum_ai-1.7.13.dist-info}/RECORD +34 -35
  29. vellum_ee/workflows/display/base.py +1 -3
  30. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +3 -1
  31. vellum_ee/workflows/display/workflows/base_workflow_display.py +14 -7
  32. vellum/workflows/triggers/slack.py +0 -101
  33. vellum/workflows/triggers/tests/test_slack.py +0 -180
  34. vellum_ee/workflows/display/tests/workflow_serialization/test_slack_trigger_serialization.py +0 -52
  35. {vellum_ai-1.7.11.dist-info → vellum_ai-1.7.13.dist-info}/LICENSE +0 -0
  36. {vellum_ai-1.7.11.dist-info → vellum_ai-1.7.13.dist-info}/WHEEL +0 -0
  37. {vellum_ai-1.7.11.dist-info → vellum_ai-1.7.13.dist-info}/entry_points.txt +0 -0
@@ -1,163 +1,141 @@
1
1
  import json
2
- from typing import Any, ClassVar, Dict, Optional, Type, cast
2
+ from typing import Any, ClassVar, Dict, Optional, Type
3
3
 
4
4
  from vellum.workflows.constants import VellumIntegrationProviderType
5
5
  from vellum.workflows.references.trigger import TriggerAttributeReference
6
6
  from vellum.workflows.triggers.base import BaseTriggerMeta
7
7
  from vellum.workflows.triggers.integration import IntegrationTrigger
8
8
  from vellum.workflows.types import ComposioIntegrationTriggerExecConfig
9
- from vellum.workflows.utils.uuids import uuid4_from_hash
10
9
 
11
10
 
12
11
  class VellumIntegrationTriggerMeta(BaseTriggerMeta):
13
12
  """
14
- Custom metaclass for VellumIntegrationTrigger that supports dynamic attribute discovery.
15
-
16
- This metaclass extends BaseTriggerMeta to enable class-level access to attributes
17
- that aren't statically defined. When accessing an undefined attribute on a
18
- VellumIntegrationTrigger class, this metaclass will create a TriggerAttributeReference
19
- dynamically, allowing triggers to work with attributes discovered from integration
20
- APIs or event payloads.
21
-
22
- Note: This metaclass intentionally deviates from the standard metaclass pattern used
23
- in BaseNodeMeta and BaseWorkflowMeta, which generate nested classes (Outputs, Inputs)
24
- in __new__. Since VellumIntegrationTrigger uses a factory pattern with dynamic
25
- attributes rather than predefined nested classes, this metaclass focuses on
26
- attribute discovery via __getattribute__ during workflow definition (when the
27
- developer references trigger attributes in their workflow code) instead of class
28
- generation in __new__. This architectural difference is necessary to support the
29
- dynamic nature of integration triggers where attributes are not known until the
30
- integration is queried or event data is received.
31
- """
13
+ Custom metaclass for VellumIntegrationTrigger.
32
14
 
33
- def __getattribute__(cls, name: str) -> Any:
34
- """
35
- Override attribute access to support dynamic attribute discovery.
15
+ This metaclass extends BaseTriggerMeta to automatically convert type annotations
16
+ into TriggerAttributeReference objects during class creation. This enables trigger
17
+ attributes to be referenced in workflow graphs while maintaining type safety.
18
+ """
36
19
 
37
- For VellumIntegrationTrigger classes generated by the factory, this method
38
- allows access to any attribute name, creating TriggerAttributeReference objects
39
- on demand. This enables usage like:
20
+ def __new__(mcs, name: str, bases: tuple, namespace: dict, **kwargs: Any) -> "VellumIntegrationTriggerMeta":
21
+ """Create a new trigger class and set up attribute references."""
22
+ cls = super().__new__(mcs, name, bases, namespace, **kwargs)
40
23
 
41
- SlackMessage = VellumIntegrationTrigger.for_trigger(
42
- integration_name="SLACK",
43
- slug="slack_new_message",
44
- trigger_nano_id="abc123"
45
- )
46
- text = SlackMessage.message # Creates reference even though 'message' isn't pre-defined
24
+ # Process __annotations__ to create TriggerAttributeReference for each attribute
25
+ # Only process if class has Config and annotations
26
+ has_config = hasattr(cls, "Config") and "Config" in namespace
27
+ if has_config and hasattr(cls, "__annotations__"):
28
+ # Create TriggerAttributeReference for each annotated attribute
29
+ for attr_name, attr_type in cls.__annotations__.items():
30
+ # Skip special attributes and Config
31
+ if attr_name.startswith("_") or attr_name == "Config":
32
+ continue
47
33
 
48
- Args:
49
- name: The attribute name being accessed
34
+ # Create reference with proper type
35
+ reference = TriggerAttributeReference(
36
+ name=attr_name, types=(attr_type,), instance=None, trigger_class=cls
37
+ )
38
+ # Set as class attribute so it's directly accessible
39
+ setattr(cls, attr_name, reference)
50
40
 
51
- Returns:
52
- The attribute value or a dynamically created TriggerAttributeReference
53
- """
54
- # Let BaseTriggerMeta handle internal attributes and known attributes
55
- try:
56
- return super().__getattribute__(name)
57
- except AttributeError:
58
- # For VellumIntegrationTrigger factory-generated classes, create dynamic references
59
- # Only enable dynamic attribute creation for factory-generated classes, not the base
60
- # VellumIntegrationTrigger class itself. We check the internal __name__ attribute
61
- # (e.g., "VellumIntegrationTrigger_COMPOSIO_SLACK_slack_new_message"), not the user-facing
62
- # variable name (e.g., "SlackNewMessage").
63
- try:
64
- is_factory_class = super().__getattribute__("__name__").startswith(
65
- "VellumIntegrationTrigger_"
66
- ) and not name.startswith("_")
67
- except AttributeError:
68
- is_factory_class = False
69
-
70
- if is_factory_class:
71
- trigger_cls = cast(Type["VellumIntegrationTrigger"], cls)
72
-
73
- # Check cache first
74
- cache = super().__getattribute__("__trigger_attribute_cache__")
75
- if name in cache:
76
- return cache[name]
77
-
78
- # Generate and store deterministic UUID for this attribute if not already present.
79
- # This ensures consistent IDs across multiple accesses to the same attribute,
80
- # which is critical for serialization and state resolution.
81
- # Use semantic identity (provider|integration|slug) instead of __qualname__ for stability.
82
- attribute_ids = super().__getattribute__("__trigger_attribute_ids__")
83
- if name not in attribute_ids:
84
- # Generate stable ID from trigger semantics, not class naming
85
- provider = super().__getattribute__("provider")
86
- integration_name = super().__getattribute__("integration_name")
87
- slug = super().__getattribute__("slug")
88
- trigger_identity = f"{provider.value}|{integration_name}|{slug}"
89
- attribute_ids[name] = uuid4_from_hash(f"{trigger_identity}|{name}")
90
-
91
- # Create a new dynamic reference for this attribute
92
- types = (object,)
93
- reference = TriggerAttributeReference(name=name, types=types, instance=None, trigger_class=trigger_cls)
94
- cache[name] = reference
95
- return reference
96
-
97
- # Not a factory class or starts with _, re-raise the AttributeError
98
- raise
41
+ return cls
99
42
 
100
43
 
101
44
  class VellumIntegrationTrigger(IntegrationTrigger, metaclass=VellumIntegrationTriggerMeta):
102
45
  """
103
- Factory-based trigger for Vellum-managed integration events.
46
+ Base class for Vellum-managed integration triggers.
104
47
 
105
- VellumIntegrationTrigger provides a pure factory pattern for creating trigger
106
- classes dynamically based on integration provider, integration name, slug, and
107
- trigger nano ID. Unlike predefined trigger classes, these triggers are created
108
- on-demand and support dynamic attribute discovery from the integration API.
109
-
110
- This design ensures parity with VellumIntegrationToolDefinition and allows users to
111
- work with any integration trigger without requiring SDK updates for new integrations.
48
+ Subclasses define two types of attributes:
49
+ 1. **Config class**: Specifies how the trigger is configured (provider, integration_name, slug)
50
+ - These are configuration details users shouldn't need to interact with directly
51
+ 2. **Top-level type annotations**: Define the webhook event payload structure (message, user, channel, etc.)
52
+ - These become TriggerAttributeReference that can be referenced in workflow nodes
112
53
 
113
54
  Examples:
114
- Create triggers dynamically for different integrations:
115
- >>> SlackNewMessage = VellumIntegrationTrigger.for_trigger(
116
- ... integration_name="SLACK",
117
- ... slug="slack_new_message",
118
- ... trigger_nano_id="abc123def456"
119
- ... )
120
- >>>
121
- >>> GithubPush = VellumIntegrationTrigger.for_trigger(
122
- ... integration_name="GITHUB",
123
- ... slug="github_push_event",
124
- ... trigger_nano_id="xyz789ghi012"
125
- ... )
55
+ Create a Slack trigger:
56
+ >>> class SlackNewMessageTrigger(VellumIntegrationTrigger):
57
+ ... # Event attributes (webhook payload structure)
58
+ ... message: str
59
+ ... user: str
60
+ ... channel: str
61
+ ... timestamp: float
62
+ ...
63
+ ... # Configuration (how trigger is set up)
64
+ ... class Config(VellumIntegrationTrigger.Config):
65
+ ... provider = VellumIntegrationProviderType.COMPOSIO
66
+ ... integration_name = "SLACK"
67
+ ... slug = "slack_new_message"
126
68
 
127
69
  Use in workflow graph:
128
70
  >>> class MyWorkflow(BaseWorkflow):
129
- ... graph = SlackNewMessage >> ProcessMessageNode
71
+ ... graph = SlackNewMessageTrigger >> ProcessMessageNode
130
72
 
131
73
  Reference trigger attributes in nodes:
132
74
  >>> class ProcessNode(BaseNode):
133
75
  ... class Outputs(BaseNode.Outputs):
134
- ... text = SlackNewMessage.message
135
- ... channel = SlackNewMessage.channel
76
+ ... text = SlackNewMessageTrigger.message
77
+ ... channel = SlackNewMessageTrigger.channel
136
78
 
137
79
  Instantiate for testing:
138
- >>> trigger = SlackNewMessage(event_data={
80
+ >>> trigger = SlackNewMessageTrigger(event_data={
139
81
  ... "message": "Hello world",
140
- ... "channel": "C123456"
82
+ ... "channel": "C123456",
83
+ ... "user": "U123",
84
+ ... "timestamp": 1234567890.0,
141
85
  ... })
142
86
  >>> trigger.message
143
87
  'Hello world'
144
-
145
- Note:
146
- The factory method generates unique classes with proper __name__ and __module__
147
- for correct attribute ID generation and serialization. Each factory call with
148
- the same parameters returns the same class instance (cached).
149
88
  """
150
89
 
151
- # Class variables that identify this trigger
152
- provider: ClassVar[VellumIntegrationProviderType]
153
- integration_name: ClassVar[str]
154
- slug: ClassVar[str]
155
- trigger_nano_id: ClassVar[str]
156
- attributes: ClassVar[Dict[str, Any]]
90
+ class Config:
91
+ """
92
+ Configuration for VellumIntegrationTrigger subclasses.
93
+
94
+ Defines how the trigger connects to the integration provider. These settings
95
+ specify which integration and which specific trigger type to use.
96
+ """
97
+
98
+ provider: ClassVar[VellumIntegrationProviderType]
99
+ integration_name: ClassVar[str]
100
+ slug: ClassVar[str]
157
101
 
158
102
  # Cache for generated trigger classes to ensure consistency
159
103
  _trigger_class_cache: ClassVar[Dict[tuple, Type["VellumIntegrationTrigger"]]] = {}
160
104
 
105
+ def __init_subclass__(cls, **kwargs: Any) -> None:
106
+ """Validate that subclasses define required Config class with all required fields."""
107
+ super().__init_subclass__(**kwargs)
108
+
109
+ # Skip validation for the base class itself
110
+ if cls.__name__ == "VellumIntegrationTrigger":
111
+ return
112
+
113
+ # Skip validation for dynamically created classes (they use dynamic attributes)
114
+ if cls.__name__.startswith("VellumIntegrationTrigger_"):
115
+ return
116
+
117
+ # Require Config class with required fields
118
+ if not hasattr(cls, "Config") or cls.Config is VellumIntegrationTrigger.Config:
119
+ raise TypeError(
120
+ f"{cls.__name__} must define a nested Config class. "
121
+ f"Example:\n"
122
+ f" class {cls.__name__}(VellumIntegrationTrigger):\n"
123
+ f" message: str\n"
124
+ f" class Config(VellumIntegrationTrigger.Config):\n"
125
+ f" provider = VellumIntegrationProviderType.COMPOSIO\n"
126
+ f" integration_name = 'SLACK'\n"
127
+ f" slug = 'slack_new_message'"
128
+ )
129
+
130
+ # Validate Config class has required fields
131
+ config_cls = cls.Config
132
+ required_fields = ["provider", "integration_name", "slug"]
133
+ for field in required_fields:
134
+ if not hasattr(config_cls, field):
135
+ raise TypeError(
136
+ f"{cls.__name__}.Config must define '{field}'. " f"Required fields: {', '.join(required_fields)}"
137
+ )
138
+
161
139
  @classmethod
162
140
  def _freeze_attributes(cls, attributes: Dict[str, Any]) -> str:
163
141
  """
@@ -236,9 +214,10 @@ class VellumIntegrationTrigger(IntegrationTrigger, metaclass=VellumIntegrationTr
236
214
  # The base class approach: for reference in type(self)
237
215
  # Our approach: for attr_name in self._event_data.keys()
238
216
  for attr_name in self._event_data.keys():
239
- # Get the class-level reference for this attribute
240
- # This will create it via our custom metaclass if it doesn't exist
241
- reference = getattr(type(self), attr_name)
217
+ # Get the class-level reference for this attribute (created by __new__ from annotations)
218
+ # Unknown keys can appear in webhook payloads, so gracefully skip them if the
219
+ # trigger class doesn't expose a corresponding reference.
220
+ reference = getattr(type(self), attr_name, None)
242
221
  if isinstance(reference, TriggerAttributeReference):
243
222
  attribute_values[reference] = getattr(self, attr_name)
244
223
 
@@ -250,39 +229,52 @@ class VellumIntegrationTrigger(IntegrationTrigger, metaclass=VellumIntegrationTr
250
229
  Generate execution configuration for serialization.
251
230
 
252
231
  This method creates a ComposioIntegrationTriggerExecConfig from the trigger
253
- class's configuration, which is used during serialization to the backend.
232
+ class's configuration (from Config class) and event attributes (from top-level
233
+ type annotations), which is used during serialization to the backend.
254
234
 
255
235
  Returns:
256
- ComposioIntegrationTriggerExecConfig with all required fields
236
+ ComposioIntegrationTriggerExecConfig with configuration and event attribute schema
257
237
 
258
238
  Raises:
259
- AttributeError: If called on base VellumIntegrationTrigger (not factory class)
239
+ AttributeError: If called on base VellumIntegrationTrigger
260
240
 
261
241
  Examples:
262
- >>> SlackMessage = VellumIntegrationTrigger.for_trigger(
263
- ... integration_name="SLACK",
264
- ... slug="slack_new_message",
265
- ... trigger_nano_id="abc123",
266
- ... attributes={"channel": "C123456"}
267
- ... )
268
- >>> exec_config = SlackMessage.to_exec_config()
242
+ >>> class SlackTrigger(VellumIntegrationTrigger):
243
+ ... # Event attributes
244
+ ... message: str
245
+ ... user: str
246
+ ...
247
+ ... # Configuration
248
+ ... class Config(VellumIntegrationTrigger.Config):
249
+ ... provider = VellumIntegrationProviderType.COMPOSIO
250
+ ... integration_name = "SLACK"
251
+ ... slug = "slack_new_message"
252
+ >>> exec_config = SlackTrigger.to_exec_config()
269
253
  >>> exec_config.slug
270
254
  'slack_new_message'
271
- >>> exec_config.attributes
272
- {'channel': 'C123456'}
255
+ >>> exec_config.event_attributes
256
+ {'message': <class 'str'>, 'user': <class 'str'>}
273
257
  """
274
- if not hasattr(cls, "slug"):
258
+ if not hasattr(cls, "Config") or cls.Config is VellumIntegrationTrigger.Config:
275
259
  raise AttributeError(
276
- "to_exec_config() can only be called on factory-generated trigger classes. "
277
- "Use VellumIntegrationTrigger.for_trigger() to create a trigger class first."
260
+ "to_exec_config() can only be called on configured VellumIntegrationTrigger subclasses, "
261
+ "not on the base class."
278
262
  )
279
263
 
264
+ # Build event_attributes from annotations
265
+ event_attributes: Dict[str, Any] = {}
266
+ if hasattr(cls, "__annotations__"):
267
+ event_attributes = {
268
+ name: type_
269
+ for name, type_ in cls.__annotations__.items()
270
+ if not name.startswith("_") and name != "Config"
271
+ }
272
+
280
273
  return ComposioIntegrationTriggerExecConfig(
281
- provider=cls.provider,
282
- integration_name=cls.integration_name,
283
- slug=cls.slug,
284
- trigger_nano_id=cls.trigger_nano_id,
285
- attributes=cls.attributes,
274
+ provider=cls.Config.provider,
275
+ integration_name=cls.Config.integration_name,
276
+ slug=cls.Config.slug,
277
+ event_attributes=event_attributes,
286
278
  )
287
279
 
288
280
  @classmethod
@@ -6,7 +6,7 @@ sent to/from the backend for integration triggers. They are used during
6
6
  serialization and deserialization of trigger configurations.
7
7
  """
8
8
 
9
- from typing import Any, Dict, Literal, Optional
9
+ from typing import Any, Dict, Literal
10
10
 
11
11
  from pydantic import Field
12
12
 
@@ -31,33 +31,30 @@ class ComposioIntegrationTriggerExecConfig(BaseIntegrationTriggerExecConfig):
31
31
 
32
32
  This configuration is used to identify and execute triggers through the Composio
33
33
  integration provider. It includes the provider type, integration name, slug,
34
- trigger nano ID, and optional attributes for filtering.
34
+ trigger nano ID, and event schema.
35
35
 
36
36
  Examples:
37
37
  >>> config = ComposioIntegrationTriggerExecConfig(
38
38
  ... provider="COMPOSIO",
39
39
  ... integration_name="SLACK",
40
40
  ... slug="slack_new_message",
41
- ... trigger_nano_id="abc123def456",
42
- ... attributes={"channel": "C123456"}
41
+ ... event_attributes={"message": str, "user": str}
43
42
  ... )
44
43
  >>> config.provider
45
44
  <VellumIntegrationProviderType.COMPOSIO: 'COMPOSIO'>
46
45
 
47
46
  Attributes:
48
- type: Always "COMPOSIO_INTEGRATION_TRIGGER" for this config type
47
+ type: Always "INTEGRATION" for this config type
49
48
  provider: The integration provider (e.g., COMPOSIO)
50
49
  integration_name: The integration identifier (e.g., "SLACK", "GITHUB")
51
50
  slug: The slug of the integration trigger in Composio
52
- trigger_nano_id: Composio's unique trigger identifier used for event matching
53
- attributes: Optional dictionary of trigger-specific configuration attributes for filtering
51
+ event_attributes: Dictionary mapping attribute names to their types (schema for event data)
54
52
  """
55
53
 
56
- type: Literal["COMPOSIO_INTEGRATION_TRIGGER"] = "COMPOSIO_INTEGRATION_TRIGGER"
54
+ type: Literal["INTEGRATION"] = "INTEGRATION"
57
55
  provider: VellumIntegrationProviderType = Field(..., description="The integration provider (e.g., COMPOSIO)")
58
56
  integration_name: str = Field(..., description="The integration name (e.g., 'SLACK', 'GITHUB')")
59
57
  slug: str = Field(..., description="The slug of the integration trigger in Composio")
60
- trigger_nano_id: str = Field(..., description="Composio's unique trigger identifier used for event matching")
61
- attributes: Optional[Dict[str, Any]] = Field(
62
- default=None, description="Optional trigger-specific configuration attributes for filtering"
58
+ event_attributes: Dict[str, Any] = Field(
59
+ default_factory=dict, description="Schema of event attributes with their types"
63
60
  )
@@ -1,5 +1,9 @@
1
1
  import hashlib
2
2
  from uuid import UUID
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from vellum.workflows.triggers.base import BaseTrigger
3
7
 
4
8
 
5
9
  def generate_workflow_deployment_prefix(deployment_name: str, release_tag: str) -> str:
@@ -37,3 +41,32 @@ def uuid4_from_hash(input_str: str) -> UUID:
37
41
 
38
42
  # Create a UUID from the modified bytes
39
43
  return UUID(bytes=bytes(hash_list))
44
+
45
+
46
+ def get_trigger_id(trigger_class: "type[BaseTrigger]") -> UUID:
47
+ """
48
+ Generate a deterministic trigger ID from a trigger class using
49
+ the class's __qualname__ to ensure stability across different import paths.
50
+
51
+ Args:
52
+ trigger_class: The trigger class to generate an ID for
53
+
54
+ Returns:
55
+ A deterministic UUID based on the trigger class qualname
56
+ """
57
+ return uuid4_from_hash(trigger_class.__qualname__)
58
+
59
+
60
+ def get_trigger_attribute_id(trigger_class: "type[BaseTrigger]", attribute_name: str) -> UUID:
61
+ """
62
+ Generate a deterministic trigger attribute ID from a trigger class and attribute name
63
+ using the class's __qualname__ and attribute name to ensure stability.
64
+
65
+ Args:
66
+ trigger_class: The trigger class containing the attribute
67
+ attribute_name: The name of the attribute
68
+
69
+ Returns:
70
+ A deterministic UUID based on the trigger class qualname and attribute name
71
+ """
72
+ return uuid4_from_hash(f"{trigger_class.__qualname__}|{attribute_name}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 1.7.11
3
+ Version: 1.7.13
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0