vellum-ai 0.10.9__py3-none-any.whl → 0.11.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. vellum/__init__.py +16 -0
  2. vellum/client/core/client_wrapper.py +1 -1
  3. vellum/client/types/__init__.py +28 -0
  4. vellum/client/types/test_suite_run_exec_config.py +7 -1
  5. vellum/client/types/test_suite_run_exec_config_request.py +8 -0
  6. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config.py +31 -0
  7. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_data.py +27 -0
  8. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_data_request.py +27 -0
  9. vellum/client/types/test_suite_run_prompt_sandbox_history_item_exec_config_request.py +31 -0
  10. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config.py +31 -0
  11. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_data.py +27 -0
  12. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_data_request.py +27 -0
  13. vellum/client/types/test_suite_run_workflow_sandbox_history_item_exec_config_request.py +31 -0
  14. vellum/evaluations/resources.py +7 -12
  15. vellum/evaluations/utils/env.py +1 -3
  16. vellum/evaluations/utils/paginator.py +0 -1
  17. vellum/evaluations/utils/typing.py +1 -1
  18. vellum/evaluations/utils/uuid.py +1 -1
  19. vellum/plugins/vellum_mypy.py +3 -1
  20. vellum/types/test_suite_run_prompt_sandbox_history_item_exec_config.py +3 -0
  21. vellum/types/test_suite_run_prompt_sandbox_history_item_exec_config_data.py +3 -0
  22. vellum/types/test_suite_run_prompt_sandbox_history_item_exec_config_data_request.py +3 -0
  23. vellum/types/test_suite_run_prompt_sandbox_history_item_exec_config_request.py +3 -0
  24. vellum/types/test_suite_run_workflow_sandbox_history_item_exec_config.py +3 -0
  25. vellum/types/test_suite_run_workflow_sandbox_history_item_exec_config_data.py +3 -0
  26. vellum/types/test_suite_run_workflow_sandbox_history_item_exec_config_data_request.py +3 -0
  27. vellum/types/test_suite_run_workflow_sandbox_history_item_exec_config_request.py +3 -0
  28. vellum/workflows/context.py +42 -0
  29. vellum/workflows/events/node.py +7 -6
  30. vellum/workflows/events/tests/test_event.py +0 -1
  31. vellum/workflows/events/types.py +0 -1
  32. vellum/workflows/events/workflow.py +19 -1
  33. vellum/workflows/nodes/bases/base.py +17 -56
  34. vellum/workflows/nodes/bases/tests/test_base_node.py +0 -1
  35. vellum/workflows/nodes/core/inline_subworkflow_node/node.py +13 -7
  36. vellum/workflows/nodes/core/templating_node/node.py +1 -0
  37. vellum/workflows/nodes/core/try_node/node.py +2 -2
  38. vellum/workflows/nodes/core/try_node/tests/test_node.py +1 -3
  39. vellum/workflows/nodes/displayable/api_node/node.py +3 -2
  40. vellum/workflows/nodes/displayable/bases/api_node/node.py +1 -1
  41. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +0 -1
  42. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +9 -1
  43. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +12 -2
  44. vellum/workflows/nodes/displayable/bases/search_node.py +0 -1
  45. vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +0 -1
  46. vellum/workflows/nodes/displayable/code_execution_node/utils.py +3 -2
  47. vellum/workflows/nodes/displayable/conditional_node/node.py +1 -1
  48. vellum/workflows/nodes/displayable/guardrail_node/node.py +0 -1
  49. vellum/workflows/nodes/displayable/inline_prompt_node/node.py +1 -0
  50. vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +3 -1
  51. vellum/workflows/nodes/displayable/search_node/node.py +1 -0
  52. vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +13 -3
  53. vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +10 -7
  54. vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py +0 -1
  55. vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +1 -1
  56. vellum/workflows/outputs/base.py +2 -4
  57. vellum/workflows/ports/node_ports.py +1 -1
  58. vellum/workflows/runner/runner.py +167 -202
  59. vellum/workflows/state/base.py +0 -2
  60. vellum/workflows/types/core.py +1 -0
  61. vellum/workflows/types/tests/test_utils.py +1 -0
  62. vellum/workflows/types/utils.py +0 -1
  63. vellum/workflows/utils/functions.py +74 -0
  64. vellum/workflows/utils/tests/test_functions.py +171 -0
  65. vellum/workflows/utils/tests/test_vellum_variables.py +0 -1
  66. vellum/workflows/utils/vellum_variables.py +2 -2
  67. vellum/workflows/workflows/base.py +74 -34
  68. vellum/workflows/workflows/event_filters.py +7 -12
  69. {vellum_ai-0.10.9.dist-info → vellum_ai-0.11.1.dist-info}/METADATA +1 -1
  70. {vellum_ai-0.10.9.dist-info → vellum_ai-0.11.1.dist-info}/RECORD +122 -99
  71. vellum_cli/__init__.py +147 -13
  72. vellum_cli/config.py +0 -1
  73. vellum_cli/image_push.py +1 -1
  74. vellum_cli/pull.py +31 -19
  75. vellum_cli/push.py +9 -10
  76. vellum_cli/tests/__init__.py +0 -0
  77. vellum_cli/tests/conftest.py +40 -0
  78. vellum_cli/tests/test_main.py +11 -0
  79. vellum_cli/tests/test_pull.py +143 -71
  80. vellum_cli/tests/test_push.py +173 -0
  81. vellum_ee/workflows/display/base.py +1 -0
  82. vellum_ee/workflows/display/nodes/base_node_display.py +3 -2
  83. vellum_ee/workflows/display/nodes/base_node_vellum_display.py +2 -2
  84. vellum_ee/workflows/display/nodes/get_node_display_class.py +1 -1
  85. vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +1 -1
  86. vellum_ee/workflows/display/nodes/vellum/__init__.py +1 -1
  87. vellum_ee/workflows/display/nodes/vellum/api_node.py +54 -58
  88. vellum_ee/workflows/display/nodes/vellum/conditional_node.py +39 -22
  89. vellum_ee/workflows/display/nodes/vellum/error_node.py +3 -3
  90. vellum_ee/workflows/display/nodes/vellum/final_output_node.py +0 -2
  91. vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +1 -1
  92. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +1 -1
  93. vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +4 -2
  94. vellum_ee/workflows/display/nodes/vellum/map_node.py +11 -5
  95. vellum_ee/workflows/display/nodes/vellum/merge_node.py +2 -2
  96. vellum_ee/workflows/display/nodes/vellum/note_node.py +1 -3
  97. vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +1 -1
  98. vellum_ee/workflows/display/nodes/vellum/search_node.py +1 -1
  99. vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +1 -1
  100. vellum_ee/workflows/display/nodes/vellum/templating_node.py +1 -1
  101. vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +5 -5
  102. vellum_ee/workflows/display/nodes/vellum/utils.py +30 -10
  103. vellum_ee/workflows/display/tests/test_vellum_workflow_display.py +45 -0
  104. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +42 -25
  105. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +13 -39
  106. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +2 -2
  107. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +62 -58
  108. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +25 -4
  109. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +2 -1
  110. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +2 -2
  111. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +2 -2
  112. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +1 -1
  113. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +2 -1
  114. vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +2 -2
  115. vellum_ee/workflows/display/types.py +4 -4
  116. vellum_ee/workflows/display/utils/vellum.py +2 -6
  117. vellum_ee/workflows/display/vellum.py +1 -1
  118. vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +4 -1
  119. vellum_ee/workflows/display/workflows/vellum_workflow_display.py +12 -5
  120. vellum/workflows/runner/types.py +0 -16
  121. {vellum_ai-0.10.9.dist-info → vellum_ai-0.11.1.dist-info}/LICENSE +0 -0
  122. {vellum_ai-0.10.9.dist-info → vellum_ai-0.11.1.dist-info}/WHEEL +0 -0
  123. {vellum_ai-0.10.9.dist-info → vellum_ai-0.11.1.dist-info}/entry_points.txt +0 -0
@@ -8,6 +8,7 @@ from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeV
8
8
  from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
9
9
  from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
10
10
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
11
+ from vellum_ee.workflows.display.vellum import WorkspaceSecretPointer
11
12
 
12
13
  _APINodeType = TypeVar("_APINodeType", bound=APINode)
13
14
 
@@ -22,10 +23,6 @@ class BaseAPINodeDisplay(BaseNodeVellumDisplay[_APINodeType], Generic[_APINodeTy
22
23
  api_key_header_key_input_id: ClassVar[Optional[UUID]] = None
23
24
  api_key_header_value_input_id: ClassVar[Optional[UUID]] = None
24
25
 
25
- text_output_id: ClassVar[Optional[UUID]] = None
26
- json_output_id: ClassVar[Optional[UUID]] = None
27
- status_code_output_id: ClassVar[Optional[UUID]] = None
28
-
29
26
  # A mapping between node input keys and their ids for inputs representing additional header keys
30
27
  additional_header_key_input_ids: ClassVar[Optional[Dict[str, UUID]]] = None
31
28
 
@@ -68,6 +65,7 @@ class BaseAPINodeDisplay(BaseNodeVellumDisplay[_APINodeType], Generic[_APINodeTy
68
65
 
69
66
  headers = raise_if_descriptor(node.headers)
70
67
  api_key_header_key = raise_if_descriptor(node.api_key_header_key)
68
+ api_key_header_value = raise_if_descriptor(node.api_key_header_value)
71
69
  authorization_type = raise_if_descriptor(node.authorization_type)
72
70
  bearer_token_value = raise_if_descriptor(node.bearer_token_value)
73
71
 
@@ -82,16 +80,13 @@ class BaseAPINodeDisplay(BaseNodeVellumDisplay[_APINodeType], Generic[_APINodeTy
82
80
  if authorization_type
83
81
  else None
84
82
  )
85
- bearer_token_value_node_input = (
86
- create_node_input(
87
- node_id=node_id,
88
- input_name="bearer_token_value",
89
- value=bearer_token_value,
90
- display_context=display_context,
91
- input_id=self.bearer_token_value_input_id,
92
- )
93
- if bearer_token_value
94
- else None
83
+ bearer_token_value_node_input = create_node_input(
84
+ node_id=node_id,
85
+ input_name="bearer_token_value",
86
+ value=bearer_token_value,
87
+ display_context=display_context,
88
+ input_id=self.bearer_token_value_input_id,
89
+ pointer_type=WorkspaceSecretPointer,
95
90
  )
96
91
  api_key_header_key_node_input = (
97
92
  create_node_input(
@@ -104,52 +99,52 @@ class BaseAPINodeDisplay(BaseNodeVellumDisplay[_APINodeType], Generic[_APINodeTy
104
99
  if api_key_header_key
105
100
  else None
106
101
  )
107
- api_key_header_value_node_input = (
108
- create_node_input(
109
- node_id=node_id,
110
- input_name="api_key_header_value",
111
- value=node.api_key_header_value,
112
- display_context=display_context,
113
- input_id=self.api_key_header_value_input_id,
114
- )
115
- if headers and api_key_header_key
116
- else None
102
+ api_key_header_value_node_input = create_node_input(
103
+ node_id=node_id,
104
+ input_name="api_key_header_value",
105
+ value=api_key_header_value,
106
+ display_context=display_context,
107
+ input_id=self.api_key_header_value_input_id,
108
+ pointer_type=WorkspaceSecretPointer,
117
109
  )
118
110
 
119
- # TODO: Add stable IDs for additional headers
120
- # https://app.shortcut.com/vellum/story/5083
121
- additional_headers: JsonArray = (
122
- [
123
- {
124
- "header_key_input_id": create_node_input(
125
- node_id=node_id,
126
- input_name=f"additional_header_key_{key}",
127
- value=key,
128
- display_context=display_context,
129
- input_id=(
130
- self.additional_header_key_input_ids.get(key)
131
- if self.additional_header_key_input_ids
132
- else None
133
- ),
134
- ).id,
135
- "header_value_input_id": create_node_input(
136
- node_id=node_id,
137
- input_name=f"additional_header_value_{key}",
138
- value=value,
139
- display_context=display_context,
140
- input_id=(
141
- self.additional_header_value_input_ids.get(key)
142
- if self.additional_header_value_input_ids
143
- else None
144
- ),
145
- ).id,
146
- }
147
- for key, value in headers.items()
148
- if key not in {api_key_header_key, "Authorization"}
149
- ]
150
- if headers
151
- else []
152
- )
111
+ additional_header_inputs = []
112
+
113
+ additional_headers: JsonArray = []
114
+ if headers:
115
+ for key, value in headers.items():
116
+ if key in {api_key_header_key, "Authorization"}:
117
+ continue
118
+
119
+ header_key_input = create_node_input(
120
+ node_id=node_id,
121
+ input_name="additional_header_key",
122
+ value=key,
123
+ display_context=display_context,
124
+ input_id=(
125
+ self.additional_header_key_input_ids.get(key) if self.additional_header_key_input_ids else None
126
+ ),
127
+ )
128
+ header_value_input = create_node_input(
129
+ node_id=node_id,
130
+ input_name="additional_header_value",
131
+ value=value,
132
+ display_context=display_context,
133
+ input_id=(
134
+ self.additional_header_value_input_ids.get(key)
135
+ if self.additional_header_value_input_ids
136
+ else None
137
+ ),
138
+ )
139
+
140
+ additional_header_inputs.extend([header_key_input, header_value_input])
141
+
142
+ additional_headers.append(
143
+ {
144
+ "header_key_input_id": header_key_input.id,
145
+ "header_value_input_id": header_value_input.id,
146
+ }
147
+ )
153
148
 
154
149
  inputs = [
155
150
  input
@@ -164,6 +159,7 @@ class BaseAPINodeDisplay(BaseNodeVellumDisplay[_APINodeType], Generic[_APINodeTy
164
159
  ]
165
160
  if input is not None
166
161
  ]
162
+ inputs.extend(additional_header_inputs)
167
163
 
168
164
  _, text_output_display = display_context.node_output_displays[cast(OutputReference, node.Outputs.text)]
169
165
  _, json_output_display = display_context.node_output_displays[cast(OutputReference, node.Outputs.json)]
@@ -1,12 +1,7 @@
1
1
  from dataclasses import dataclass
2
2
  from uuid import UUID
3
- from typing import Any, ClassVar, Dict, Generic, List, Optional, TypeVar, Union, Tuple
3
+ from typing import Any, ClassVar, Dict, Generic, List, Optional, Tuple, TypeVar, Union
4
4
 
5
- from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
6
- from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
7
- from vellum_ee.workflows.display.types import WorkflowDisplayContext
8
- from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
9
- from vellum_ee.workflows.display.vellum import NodeInput
10
5
  from vellum.workflows.descriptors.base import BaseDescriptor
11
6
  from vellum.workflows.expressions.and_ import AndExpression
12
7
  from vellum.workflows.expressions.begins_with import BeginsWithExpression
@@ -29,7 +24,12 @@ from vellum.workflows.expressions.not_between import NotBetweenExpression
29
24
  from vellum.workflows.expressions.not_in import NotInExpression
30
25
  from vellum.workflows.expressions.or_ import OrExpression
31
26
  from vellum.workflows.nodes.displayable import ConditionalNode
32
- from vellum.workflows.types.core import JsonObject, ConditionType
27
+ from vellum.workflows.types.core import ConditionType, JsonObject
28
+ from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
29
+ from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
30
+ from vellum_ee.workflows.display.types import WorkflowDisplayContext
31
+ from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
32
+ from vellum_ee.workflows.display.vellum import NodeInput
33
33
 
34
34
  _ConditionalNodeType = TypeVar("_ConditionalNodeType", bound=ConditionalNode)
35
35
 
@@ -42,6 +42,7 @@ class RuleIdMap:
42
42
  field_node_input_id: Optional[UUID]
43
43
  value_node_input_id: Optional[UUID]
44
44
 
45
+
45
46
  @dataclass
46
47
  class ConditionId:
47
48
  id: UUID
@@ -65,7 +66,9 @@ class BaseConditionalNodeDisplay(BaseNodeVellumDisplay[_ConditionalNodeType], Ge
65
66
 
66
67
  if len(condition_ids) > ports_size:
67
68
  raise ValueError(
68
- f"Too many defined condition ids. Ports are size {ports_size} but the defined conditions have length {len(condition_ids)}")
69
+ f"""Too many defined condition ids. Ports are size {ports_size} \
70
+ but the defined conditions have length {len(condition_ids)}"""
71
+ )
69
72
 
70
73
  def serialize_rule(
71
74
  descriptor: BaseDescriptor, path: List[int], rule_id_map: Optional[RuleIdMap]
@@ -113,7 +116,11 @@ class BaseConditionalNodeDisplay(BaseNodeVellumDisplay[_ConditionalNodeType], Ge
113
116
  node_id, f"{current_id}.field", descriptor._value, display_context, field_node_input_id
114
117
  )
115
118
  value_node_input = create_node_input(
116
- node_id, f"{current_id}.value", f"{descriptor._start},{descriptor._end}", display_context, value_node_input_id
119
+ node_id,
120
+ f"{current_id}.value",
121
+ f"{descriptor._start},{descriptor._end}",
122
+ display_context,
123
+ value_node_input_id,
117
124
  )
118
125
  node_inputs.extend([field_node_input, value_node_input])
119
126
  operator = self._convert_descriptor_to_operator(descriptor)
@@ -124,11 +131,15 @@ class BaseConditionalNodeDisplay(BaseNodeVellumDisplay[_ConditionalNodeType], Ge
124
131
  lhs = descriptor._lhs # type: ignore[attr-defined]
125
132
  rhs = descriptor._rhs # type: ignore[attr-defined]
126
133
 
127
- lhs_node_input = create_node_input(node_id, f"{current_id}.field", lhs, display_context, field_node_input_id)
134
+ lhs_node_input = create_node_input(
135
+ node_id, f"{current_id}.field", lhs, display_context, field_node_input_id
136
+ )
128
137
  node_inputs.append(lhs_node_input)
129
138
 
130
139
  if descriptor._rhs is not None: # type: ignore[attr-defined]
131
- rhs_node_input = create_node_input(node_id, f"{current_id}.value", rhs, display_context, value_node_input_id)
140
+ rhs_node_input = create_node_input(
141
+ node_id, f"{current_id}.value", rhs, display_context, value_node_input_id
142
+ )
132
143
  node_inputs.append(rhs_node_input)
133
144
  value_node_input_id = UUID(rhs_node_input.id)
134
145
 
@@ -148,18 +159,24 @@ class BaseConditionalNodeDisplay(BaseNodeVellumDisplay[_ConditionalNodeType], Ge
148
159
  conditions = []
149
160
  for idx, port in enumerate(node.Ports):
150
161
 
151
- condition_id = str(condition_ids[idx].id if condition_ids else uuid4_from_hash(f"{node_id}|conditions|{idx}"))
152
- rule_group_id = str(condition_ids[idx].rule_group_id if condition_ids else uuid4_from_hash(f"{condition_id}|rule_group"))
162
+ condition_id = str(
163
+ condition_ids[idx].id if condition_ids else uuid4_from_hash(f"{node_id}|conditions|{idx}")
164
+ )
165
+ rule_group_id = str(
166
+ condition_ids[idx].rule_group_id if condition_ids else uuid4_from_hash(f"{condition_id}|rule_group")
167
+ )
153
168
  source_handle_id = str(source_handle_ids.get(idx) or uuid4_from_hash(f"{node_id}|handles|{idx}"))
154
169
 
155
170
  if port._condition is None:
156
171
  if port._condition_type == ConditionType.ELSE:
157
- conditions.append({
158
- "id": condition_id,
159
- "type": ConditionType.ELSE.value,
160
- "source_handle_id": source_handle_id,
161
- "data": None
162
- })
172
+ conditions.append(
173
+ {
174
+ "id": condition_id,
175
+ "type": ConditionType.ELSE.value,
176
+ "source_handle_id": source_handle_id,
177
+ "data": None,
178
+ }
179
+ )
163
180
  else:
164
181
  continue
165
182
 
@@ -241,7 +258,7 @@ class BaseConditionalNodeDisplay(BaseNodeVellumDisplay[_ConditionalNodeType], Ge
241
258
  raise ValueError(f"Unsupported descriptor type: {descriptor}")
242
259
 
243
260
  def get_nested_rule_details_by_path(
244
- self, rule_ids: List[RuleIdMap], path: List[int]
261
+ self, rule_ids: List[RuleIdMap], path: List[int]
245
262
  ) -> Union[Tuple[UUID, Optional[UUID], Optional[UUID]], None]:
246
263
  current_rule = rule_ids[path[0]]
247
264
 
@@ -267,7 +284,7 @@ class BaseConditionalNodeDisplay(BaseNodeVellumDisplay[_ConditionalNodeType], Ge
267
284
  return (
268
285
  uuid4_from_hash(f"{node_id}|{rule_id}|current"),
269
286
  uuid4_from_hash(f"{node_id}|{rule_id}||field"),
270
- uuid4_from_hash(f"{node_id}|{rule_id}||value")
287
+ uuid4_from_hash(f"{node_id}|{rule_id}||value"),
271
288
  )
272
289
 
273
290
  def _get_source_handle_ids(self) -> Dict[int, UUID]:
@@ -276,5 +293,5 @@ class BaseConditionalNodeDisplay(BaseNodeVellumDisplay[_ConditionalNodeType], Ge
276
293
  def _get_rule_ids(self) -> List[RuleIdMap]:
277
294
  return self._get_explicit_node_display_attr("rule_ids", List[RuleIdMap]) or []
278
295
 
279
- def _get_condition_ids(self)-> List[ConditionId]:
296
+ def _get_condition_ids(self) -> List[ConditionId]:
280
297
  return self._get_explicit_node_display_attr("condition_ids", List[ConditionId]) or []
@@ -2,22 +2,22 @@ from uuid import UUID
2
2
  from typing import Any, ClassVar, Dict, Generic, Optional, TypeVar
3
3
 
4
4
  from vellum.workflows.nodes import ErrorNode
5
- from vellum.workflows.types.core import EntityInputsInterface, Json, JsonObject
5
+ from vellum.workflows.types.core import JsonObject
6
6
  from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
7
7
  from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
8
8
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
9
9
 
10
10
  _ErrorNodeType = TypeVar("_ErrorNodeType", bound=ErrorNode)
11
11
 
12
+
12
13
  class BaseErrorNodeDisplay(BaseNodeVellumDisplay[_ErrorNodeType], Generic[_ErrorNodeType]):
13
14
  error_output_id: ClassVar[Optional[UUID]] = None
14
15
  error_inputs_by_name: ClassVar[Dict[str, Any]] = {}
15
16
  name: ClassVar[str] = "error-node"
16
17
 
17
18
  def serialize(
18
- self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
19
+ self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
19
20
  ) -> JsonObject:
20
- node = self._node
21
21
  node_id = self.node_id
22
22
  error_source_input_id = self.node_input_ids_by_name.get("error_source_input_id")
23
23
 
@@ -1,9 +1,7 @@
1
1
  from uuid import UUID
2
2
  from typing import Any, ClassVar, Generic, Optional, TypeVar
3
3
 
4
- from vellum.workflows.nodes.core.map_node.node import MapNode
5
4
  from vellum.workflows.nodes.displayable.final_output_node import FinalOutputNode
6
- from vellum.workflows.references.output import OutputReference
7
5
  from vellum.workflows.types.core import JsonObject
8
6
  from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
9
7
  from vellum_ee.workflows.display.nodes.utils import to_kebab_case
@@ -1,5 +1,5 @@
1
1
  from uuid import UUID
2
- from typing import Any, ClassVar, Dict, Generic, Optional, TypeVar
2
+ from typing import ClassVar, Dict, Generic, Optional, TypeVar
3
3
 
4
4
  from vellum.workflows.nodes import GuardrailNode
5
5
  from vellum.workflows.types.core import JsonObject
@@ -1,5 +1,5 @@
1
1
  from uuid import UUID
2
- from typing import Any, ClassVar, Dict, Generic, List, Optional, Tuple, Type, TypeVar, Union, cast
2
+ from typing import ClassVar, Dict, Generic, List, Optional, Tuple, Type, TypeVar, Union, cast
3
3
 
4
4
  from vellum import PromptBlock, RichTextChildBlock, VellumVariable
5
5
  from vellum.workflows.nodes import InlinePromptNode
@@ -1,5 +1,5 @@
1
1
  from uuid import UUID
2
- from typing import Any, ClassVar, Dict, Generic, List, Optional, Tuple, Type, TypeVar, cast
2
+ from typing import ClassVar, Dict, Generic, List, Optional, Tuple, Type, TypeVar, cast
3
3
 
4
4
  from vellum import VellumVariable
5
5
  from vellum.workflows.nodes import InlineSubworkflowNode
@@ -90,7 +90,9 @@ class BaseInlineSubworkflowNodeDisplay(
90
90
  ) -> List[VellumVariable]:
91
91
  workflow_outputs: List[VellumVariable] = []
92
92
  for output_descriptor in raise_if_descriptor(node.subworkflow).Outputs: # type: ignore[union-attr]
93
- workflow_output_display = cast(WorkflowOutputVellumDisplay, display_context.workflow_output_displays[output_descriptor])
93
+ workflow_output_display = cast(
94
+ WorkflowOutputVellumDisplay, display_context.workflow_output_displays[output_descriptor]
95
+ )
94
96
  output_type = infer_vellum_variable_type(output_descriptor)
95
97
  workflow_outputs.append(
96
98
  VellumVariable(id=str(workflow_output_display.id), key=workflow_output_display.name, type=output_type)
@@ -1,5 +1,5 @@
1
1
  from uuid import UUID
2
- from typing import Collection, Dict, Generic, List, Optional, TypeVar, cast
2
+ from typing import Dict, Generic, List, Optional, TypeVar, cast
3
3
 
4
4
  from vellum.workflows.nodes import MapNode
5
5
  from vellum.workflows.types.core import JsonObject
@@ -39,15 +39,21 @@ class BaseMapNodeDisplay(BaseNodeVellumDisplay[_MapNodeType], Generic[_MapNodeTy
39
39
  renamed_input_variables = []
40
40
  for input_variable in cast(List[Dict[str, str]], serialized_subworkflow["input_variables"]):
41
41
  if input_variable["key"] == "all_items":
42
- renamed_item = { **input_variable, "key": "items" }
42
+ renamed_item = {**input_variable, "key": "items"}
43
43
  renamed_input_variables.append(renamed_item)
44
44
  else:
45
45
  renamed_input_variables.append(input_variable)
46
46
 
47
47
  # Note: This must match the items input ID for the map node's node input
48
- items_workflow_input_id = next(input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "items")
49
- item_workflow_input_id = next(input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "item")
50
- index_workflow_input_id = next(input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "index")
48
+ items_workflow_input_id = next(
49
+ input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "items"
50
+ )
51
+ item_workflow_input_id = next(
52
+ input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "item"
53
+ )
54
+ index_workflow_input_id = next(
55
+ input_variable["id"] for input_variable in renamed_input_variables if input_variable["key"] == "index"
56
+ )
51
57
 
52
58
  return {
53
59
  "id": str(node_id),
@@ -1,12 +1,12 @@
1
1
  from uuid import UUID
2
2
  from typing import Any, ClassVar, Generic, List, Optional, TypeVar
3
3
 
4
+ from vellum.workflows.nodes.displayable import MergeNode
5
+ from vellum.workflows.types.core import JsonObject
4
6
  from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
5
7
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
6
8
  from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
7
9
  from vellum_ee.workflows.display.vellum import EdgeVellumDisplay
8
- from vellum.workflows.nodes.displayable import MergeNode
9
- from vellum.workflows.types.core import JsonObject
10
10
 
11
11
  _MergeNodeType = TypeVar("_MergeNodeType", bound=MergeNode)
12
12
 
@@ -13,9 +13,7 @@ class BaseNoteNodeDisplay(BaseNodeVellumDisplay[_NoteNodeType], Generic[_NoteNod
13
13
  text: ClassVar[str] = ""
14
14
  style: ClassVar[Union[Dict[str, Any], None]] = None
15
15
 
16
- def serialize(
17
- self, display_context: WorkflowDisplayContext, **kwargs: Any
18
- ) -> JsonObject:
16
+ def serialize(self, display_context: WorkflowDisplayContext, **kwargs: Any) -> JsonObject:
19
17
  node_id = self.node_id
20
18
 
21
19
  return {
@@ -1,5 +1,5 @@
1
1
  from uuid import UUID
2
- from typing import Any, ClassVar, Dict, Generic, Optional, TypeVar, cast
2
+ from typing import ClassVar, Dict, Generic, Optional, TypeVar, cast
3
3
 
4
4
  from vellum.workflows.nodes.displayable.prompt_deployment_node import PromptDeploymentNode
5
5
  from vellum.workflows.references import OutputReference
@@ -1,6 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from uuid import UUID
3
- from typing import Any, Dict, Generic, List, Optional, Tuple, Type, TypeVar, Union, cast
3
+ from typing import Dict, Generic, List, Optional, Tuple, Type, TypeVar, Union, cast
4
4
 
5
5
  from vellum import (
6
6
  MetadataFilterConfigRequest,
@@ -1,5 +1,5 @@
1
1
  from uuid import UUID
2
- from typing import Any, ClassVar, Dict, Generic, Optional, TypeVar
2
+ from typing import ClassVar, Dict, Generic, Optional, TypeVar
3
3
 
4
4
  from vellum.workflows.nodes import SubworkflowDeploymentNode
5
5
  from vellum.workflows.types.core import JsonObject
@@ -1,5 +1,5 @@
1
1
  from uuid import UUID
2
- from typing import Any, ClassVar, Dict, Generic, Optional, TypeVar
2
+ from typing import ClassVar, Dict, Generic, Optional, TypeVar
3
3
 
4
4
  from vellum.workflows.nodes.core.templating_node import TemplatingNode
5
5
  from vellum.workflows.types.core import JsonObject
@@ -2,6 +2,11 @@ import pytest
2
2
  from uuid import UUID, uuid4
3
3
  from typing import List, cast
4
4
 
5
+ from vellum.workflows.descriptors.base import BaseDescriptor
6
+ from vellum.workflows.inputs import BaseInputs
7
+ from vellum.workflows.nodes.bases import BaseNode
8
+ from vellum.workflows.outputs import BaseOutputs
9
+ from vellum.workflows.references import OutputReference, WorkflowInputReference
5
10
  from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
6
11
  from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
7
12
  from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input_value_pointer_rules
@@ -19,11 +24,6 @@ from vellum_ee.workflows.display.vellum import (
19
24
  WorkflowMetaVellumDisplay,
20
25
  )
21
26
  from vellum_ee.workflows.display.workflows.vellum_workflow_display import VellumWorkflowDisplay
22
- from vellum.workflows.descriptors.base import BaseDescriptor
23
- from vellum.workflows.inputs import BaseInputs
24
- from vellum.workflows.nodes.bases import BaseNode
25
- from vellum.workflows.outputs import BaseOutputs
26
- from vellum.workflows.references import OutputReference, WorkflowInputReference
27
27
 
28
28
 
29
29
  class Inputs(BaseInputs):
@@ -1,6 +1,10 @@
1
1
  from uuid import UUID
2
- from typing import Any, List, Optional, cast
2
+ from typing import Any, List, Optional, Type, cast
3
3
 
4
+ from vellum.workflows.descriptors.base import BaseDescriptor
5
+ from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
6
+ from vellum.workflows.nodes.utils import get_wrapped_node, has_wrapped_node
7
+ from vellum.workflows.references import NodeReference, OutputReference
4
8
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
5
9
  from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
6
10
  from vellum_ee.workflows.display.utils.vellum import create_node_input_value_pointer_rule, primitive_to_vellum_value
@@ -9,11 +13,9 @@ from vellum_ee.workflows.display.vellum import (
9
13
  NodeInput,
10
14
  NodeInputValuePointer,
11
15
  NodeInputValuePointerRule,
16
+ WorkspaceSecretData,
17
+ WorkspaceSecretPointer,
12
18
  )
13
- from vellum.workflows.descriptors.base import BaseDescriptor
14
- from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
15
- from vellum.workflows.nodes.utils import get_wrapped_node, has_wrapped_node
16
- from vellum.workflows.references import NodeReference, OutputReference
17
19
 
18
20
 
19
21
  def create_node_input(
@@ -22,6 +24,7 @@ def create_node_input(
22
24
  value: Any,
23
25
  display_context: WorkflowDisplayContext,
24
26
  input_id: Optional[UUID],
27
+ pointer_type: Optional[Type[NodeInputValuePointerRule]] = ConstantValuePointer,
25
28
  ) -> NodeInput:
26
29
  input_id = input_id or uuid4_from_hash(f"{node_id}|{input_name}")
27
30
  if (
@@ -33,7 +36,7 @@ def create_node_input(
33
36
  if wrapped_node._is_wrapped_node:
34
37
  value = getattr(wrapped_node.Outputs, value.name)
35
38
 
36
- rules = create_node_input_value_pointer_rules(value, display_context)
39
+ rules = create_node_input_value_pointer_rules(value, display_context, pointer_type=pointer_type)
37
40
  return NodeInput(
38
41
  id=str(input_id),
39
42
  key=input_name,
@@ -48,6 +51,7 @@ def create_node_input_value_pointer_rules(
48
51
  value: Any,
49
52
  display_context: WorkflowDisplayContext,
50
53
  existing_rules: Optional[List[NodeInputValuePointerRule]] = None,
54
+ pointer_type: Optional[Type[NodeInputValuePointerRule]] = None,
51
55
  ) -> List[NodeInputValuePointerRule]:
52
56
  node_input_value_pointer_rules: List[NodeInputValuePointerRule] = existing_rules or []
53
57
 
@@ -59,18 +63,34 @@ def create_node_input_value_pointer_rules(
59
63
 
60
64
  if isinstance(value, CoalesceExpression):
61
65
  # Recursively handle the left-hand side
62
- lhs_rules = create_node_input_value_pointer_rules(value.lhs, display_context, [])
66
+ lhs_rules = create_node_input_value_pointer_rules(value.lhs, display_context, [], pointer_type=pointer_type)
63
67
  node_input_value_pointer_rules.extend(lhs_rules)
64
68
 
65
69
  # Handle the right-hand side
66
70
  if not isinstance(value.rhs, CoalesceExpression):
67
- rhs_rules = create_node_input_value_pointer_rules(value.rhs, display_context, [])
71
+ rhs_rules = create_node_input_value_pointer_rules(
72
+ value.rhs, display_context, [], pointer_type=pointer_type
73
+ )
68
74
  node_input_value_pointer_rules.extend(rhs_rules)
69
75
  else:
70
76
  # Non-CoalesceExpression case
71
77
  node_input_value_pointer_rules.append(create_node_input_value_pointer_rule(value, display_context))
72
78
  else:
73
- vellum_variable_value = primitive_to_vellum_value(value)
74
- node_input_value_pointer_rules.append(ConstantValuePointer(type="CONSTANT_VALUE", data=vellum_variable_value))
79
+ pointer = create_pointer(value, pointer_type)
80
+ node_input_value_pointer_rules.append(pointer)
75
81
 
76
82
  return node_input_value_pointer_rules
83
+
84
+
85
+ def create_pointer(
86
+ value: Any,
87
+ pointer_type: Optional[Type[NodeInputValuePointerRule]] = None,
88
+ ) -> NodeInputValuePointerRule:
89
+ if value is None:
90
+ if pointer_type is WorkspaceSecretPointer:
91
+ return WorkspaceSecretPointer(
92
+ type="WORKSPACE_SECRET", data=WorkspaceSecretData(type="STRING", workspace_secret_id=None)
93
+ )
94
+
95
+ vellum_variable_value = primitive_to_vellum_value(value)
96
+ return ConstantValuePointer(type="CONSTANT_VALUE", data=vellum_variable_value)
@@ -0,0 +1,45 @@
1
+ from vellum.workflows.workflows.base import BaseWorkflow
2
+ from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
3
+ from vellum_ee.workflows.display.workflows.vellum_workflow_display import VellumWorkflowDisplay
4
+
5
+
6
+ def test_vellum_workflow_display__serialize_empty_workflow():
7
+ # GIVEN an empty workflow
8
+ class ExampleWorkflow(BaseWorkflow):
9
+ pass
10
+
11
+ display = get_workflow_display(
12
+ base_display_class=VellumWorkflowDisplay,
13
+ workflow_class=ExampleWorkflow,
14
+ )
15
+
16
+ # WHEN serializing the workflow
17
+ exec_config = display.serialize()
18
+
19
+ # THEN it should return the expected config
20
+ assert exec_config == {
21
+ "input_variables": [],
22
+ "output_variables": [],
23
+ "workflow_raw_data": {
24
+ "definition": {
25
+ "module": ["vellum_ee", "workflows", "display", "tests", "test_vellum_workflow_display"],
26
+ "name": "ExampleWorkflow",
27
+ },
28
+ "display_data": {"viewport": {"x": 0.0, "y": 0.0, "zoom": 1.0}},
29
+ "edges": [],
30
+ "nodes": [
31
+ {
32
+ "data": {"label": "Entrypoint Node", "source_handle_id": "508b8b82-3517-4672-a155-18c9c7b9c545"},
33
+ "definition": {
34
+ "bases": [],
35
+ "module": ["vellum", "workflows", "nodes", "bases", "base"],
36
+ "name": "BaseNode",
37
+ },
38
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
39
+ "id": "9eef0c18-f322-4d56-aa89-f088d3e53f6a",
40
+ "inputs": [],
41
+ "type": "ENTRYPOINT",
42
+ }
43
+ ],
44
+ },
45
+ }