vellum-ai 1.3.8__py3-none-any.whl → 1.3.9__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 (33) hide show
  1. vellum/client/core/client_wrapper.py +2 -2
  2. vellum/client/reference.md +71 -0
  3. vellum/client/resources/workflows/client.py +80 -0
  4. vellum/client/resources/workflows/raw_client.py +98 -0
  5. vellum/client/types/vellum_error.py +2 -1
  6. vellum/client/types/vellum_error_request.py +2 -1
  7. vellum/workflows/utils/tests/test_vellum_variables.py +7 -1
  8. vellum/workflows/utils/vellum_variables.py +42 -3
  9. {vellum_ai-1.3.8.dist-info → vellum_ai-1.3.9.dist-info}/METADATA +1 -1
  10. {vellum_ai-1.3.8.dist-info → vellum_ai-1.3.9.dist-info}/RECORD +33 -33
  11. vellum_ee/workflows/display/editor/types.py +2 -0
  12. vellum_ee/workflows/display/nodes/base_node_display.py +42 -14
  13. vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +64 -0
  14. vellum_ee/workflows/display/nodes/vellum/final_output_node.py +1 -1
  15. vellum_ee/workflows/display/nodes/vellum/retry_node.py +1 -1
  16. vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py +12 -12
  17. vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py +4 -4
  18. vellum_ee/workflows/display/nodes/vellum/try_node.py +1 -1
  19. vellum_ee/workflows/display/tests/test_base_workflow_display.py +46 -0
  20. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +1 -1
  21. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +8 -8
  22. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +1 -0
  23. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +1 -0
  24. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +2 -1
  25. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +2 -1
  26. vellum_ee/workflows/display/utils/events.py +7 -1
  27. vellum_ee/workflows/display/utils/expressions.py +33 -19
  28. vellum_ee/workflows/display/utils/tests/test_events.py +4 -4
  29. vellum_ee/workflows/display/workflows/base_workflow_display.py +1 -1
  30. vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +10 -10
  31. {vellum_ai-1.3.8.dist-info → vellum_ai-1.3.9.dist-info}/LICENSE +0 -0
  32. {vellum_ai-1.3.8.dist-info → vellum_ai-1.3.9.dist-info}/WHEEL +0 -0
  33. {vellum_ai-1.3.8.dist-info → vellum_ai-1.3.9.dist-info}/entry_points.txt +0 -0
@@ -162,7 +162,7 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
162
162
  {
163
163
  "id": id,
164
164
  "name": attribute.name,
165
- "value": serialize_value(display_context, attribute.instance),
165
+ "value": serialize_value(node_id, display_context, attribute.instance),
166
166
  }
167
167
  )
168
168
  except ValueError as e:
@@ -187,7 +187,7 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
187
187
  for output in node.Outputs:
188
188
  type = primitive_type_to_vellum_variable_type(output)
189
189
  value = (
190
- serialize_value(display_context, output.instance)
190
+ serialize_value(node_id, display_context, output.instance)
191
191
  if output.instance is not None and output.instance != undefined
192
192
  else None
193
193
  )
@@ -214,6 +214,7 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
214
214
  def serialize_ports(self, display_context: "WorkflowDisplayContext") -> JsonArray:
215
215
  """Serialize the ports of the node."""
216
216
  node = self._node
217
+ node_id = self.node_id
217
218
  ports: JsonArray = []
218
219
 
219
220
  for port in node.Ports:
@@ -224,7 +225,9 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
224
225
  "id": id,
225
226
  "name": port.name,
226
227
  "type": port._condition_type.value,
227
- "expression": (serialize_value(display_context, port._condition) if port._condition else None),
228
+ "expression": (
229
+ serialize_value(node_id, display_context, port._condition) if port._condition else None
230
+ ),
228
231
  }
229
232
  )
230
233
  else:
@@ -248,21 +251,23 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
248
251
 
249
252
  def _serialize_attributes(self, display_context: "WorkflowDisplayContext") -> JsonArray:
250
253
  """Serialize node attributes, skipping unserializable ones."""
254
+ node = self._node
255
+ node_id = self.node_id
251
256
  attributes: JsonArray = []
252
- for attribute in self._node:
257
+ for attribute in node:
253
258
  if attribute in self.__unserializable_attributes__:
254
259
  continue
255
260
 
256
261
  id = (
257
262
  str(self.attribute_ids_by_name[attribute.name])
258
263
  if self.attribute_ids_by_name.get(attribute.name)
259
- else str(uuid4_from_hash(f"{self.node_id}|{attribute.name}"))
264
+ else str(uuid4_from_hash(f"{node_id}|{attribute.name}"))
260
265
  )
261
266
  try:
262
267
  attribute_dict: JsonObject = {
263
268
  "id": id,
264
269
  "name": attribute.name,
265
- "value": serialize_value(display_context, attribute.instance),
270
+ "value": serialize_value(node_id, display_context, attribute.instance),
266
271
  }
267
272
  attributes.append(attribute_dict)
268
273
  except ValueError as e:
@@ -272,7 +277,7 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
272
277
 
273
278
  def serialize_generic_fields(self, display_context: "WorkflowDisplayContext") -> JsonObject:
274
279
  """Serialize generic fields that are common to all nodes."""
275
- return {
280
+ result: JsonObject = {
276
281
  "display_data": self.get_display_data().dict(),
277
282
  "base": self.get_base().dict(),
278
283
  "definition": self.get_definition().dict(),
@@ -280,6 +285,22 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
280
285
  "ports": self.serialize_ports(display_context),
281
286
  }
282
287
 
288
+ # Only include should_file_merge if there are custom methods defined
289
+ try:
290
+ node_class = self.__class__.infer_node_class()
291
+ has_custom_methods = any(
292
+ callable(getattr(node_class, name, None)) and inspect.isfunction(getattr(node_class, name, None))
293
+ for name in node_class.__dict__.keys()
294
+ if not name.startswith("__")
295
+ )
296
+
297
+ if has_custom_methods:
298
+ result["should_file_merge"] = True
299
+ except Exception:
300
+ pass
301
+
302
+ return result
303
+
283
304
  def get_base(self) -> CodeResourceDefinition:
284
305
  node = self._node
285
306
 
@@ -429,13 +450,20 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
429
450
  if explicit_value.comment.expanded is not None
430
451
  else NodeDisplayComment(value=docstring, expanded=True)
431
452
  )
432
- return NodeDisplayData(
433
- position=explicit_value.position,
434
- z_index=explicit_value.z_index,
435
- width=explicit_value.width,
436
- height=explicit_value.height,
437
- comment=comment,
438
- )
453
+ from typing import Any, Dict
454
+
455
+ kwargs: Dict[str, Any] = {
456
+ "position": explicit_value.position,
457
+ "z_index": explicit_value.z_index,
458
+ "width": explicit_value.width,
459
+ "height": explicit_value.height,
460
+ "comment": comment,
461
+ }
462
+ if explicit_value.icon is not None:
463
+ kwargs["icon"] = explicit_value.icon
464
+ if explicit_value.color is not None:
465
+ kwargs["color"] = explicit_value.color
466
+ return NodeDisplayData(**kwargs)
439
467
 
440
468
  if explicit_value:
441
469
  return explicit_value
@@ -4,6 +4,7 @@ from uuid import UUID
4
4
  from vellum.workflows.nodes.bases import BaseNode
5
5
  from vellum.workflows.ports.port import Port
6
6
  from vellum.workflows.references.constant import ConstantValueReference
7
+ from vellum_ee.workflows.display.editor.types import NodeDisplayData, NodeDisplayPosition
7
8
  from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
8
9
  from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
9
10
  from vellum_ee.workflows.display.types import WorkflowDisplayContext
@@ -117,3 +118,66 @@ def test_serialize_node_label_with_pascal_case():
117
118
 
118
119
  # THEN the label should be converted to proper title case with spaces
119
120
  assert data["label"] == "My Custom Node"
121
+
122
+
123
+ def test_serialize_display_data_with_icon_and_color():
124
+ """
125
+ Tests that nodes with icon and color serialize display_data correctly.
126
+ """
127
+
128
+ # GIVEN a node with icon and color in display data
129
+ class MyNode(BaseNode):
130
+ pass
131
+
132
+ class MyNodeDisplay(BaseNodeDisplay[MyNode]):
133
+ display_data = NodeDisplayData(
134
+ position=NodeDisplayPosition(x=100, y=200), icon="vellum:icon:star", color="navy"
135
+ )
136
+
137
+ # WHEN we serialize the node
138
+ data = MyNodeDisplay().serialize(WorkflowDisplayContext())
139
+
140
+ # THEN the display_data should include icon and color
141
+ assert data["display_data"] == {"position": {"x": 100, "y": 200}, "icon": "vellum:icon:star", "color": "navy"}
142
+
143
+
144
+ def test_serialize_display_data_with_various_icon_formats():
145
+ """
146
+ Tests that different icon formats are serialized correctly.
147
+ """
148
+
149
+ # GIVEN a node with a vellum icon format
150
+ class MyNode(BaseNode):
151
+ pass
152
+
153
+ class MyNodeDisplay(BaseNodeDisplay[MyNode]):
154
+ display_data = NodeDisplayData(icon="vellum:icon:home")
155
+
156
+ # WHEN we serialize the node
157
+ data = MyNodeDisplay().serialize(WorkflowDisplayContext())
158
+
159
+ # THEN the icon should be preserved as-is
160
+ display_data = data["display_data"]
161
+ assert isinstance(display_data, dict)
162
+ assert display_data["icon"] == "vellum:icon:home"
163
+
164
+
165
+ def test_serialize_display_data_with_navy_color():
166
+ """
167
+ Tests that navy color values are serialized correctly.
168
+ """
169
+
170
+ # GIVEN a node with a navy color
171
+ class MyNode(BaseNode):
172
+ pass
173
+
174
+ class MyNodeDisplay(BaseNodeDisplay[MyNode]):
175
+ display_data = NodeDisplayData(color="navy")
176
+
177
+ # WHEN we serialize the node
178
+ data = MyNodeDisplay().serialize(WorkflowDisplayContext())
179
+
180
+ # THEN the color should be preserved as-is
181
+ display_data = data["display_data"]
182
+ assert isinstance(display_data, dict)
183
+ assert display_data["color"] == "navy"
@@ -51,7 +51,7 @@ class BaseFinalOutputNodeDisplay(BaseNodeDisplay[_FinalOutputNodeType], Generic[
51
51
  "id": str(self._get_output_id()),
52
52
  "name": node.Outputs.value.name,
53
53
  "type": inferred_type,
54
- "value": serialize_value(display_context, node.Outputs.value.instance),
54
+ "value": serialize_value(node_id, display_context, node.Outputs.value.instance),
55
55
  }
56
56
  ],
57
57
  }
@@ -33,7 +33,7 @@ class BaseRetryNodeDisplay(BaseAdornmentNodeDisplay[_RetryNodeType], Generic[_Re
33
33
  {
34
34
  "id": id,
35
35
  "name": attribute.name,
36
- "value": serialize_value(display_context, attribute.instance),
36
+ "value": serialize_value(node_id, display_context, attribute.instance),
37
37
  }
38
38
  )
39
39
 
@@ -197,7 +197,7 @@ def test_serialize_node__prompt_inputs__state_reference():
197
197
  "type": "DICTIONARY_REFERENCE",
198
198
  "entries": [
199
199
  {
200
- "id": "feadab18-07c6-4790-adf0-28be20a5447a",
200
+ "id": "52559b9e-4e8e-438a-8246-cfa30c98d5d1",
201
201
  "key": "foo",
202
202
  "value": {
203
203
  "type": "WORKFLOW_STATE",
@@ -205,7 +205,7 @@ def test_serialize_node__prompt_inputs__state_reference():
205
205
  },
206
206
  },
207
207
  {
208
- "id": "4f252277-d0a5-48ad-8cc5-be03bf0dbd19",
208
+ "id": "3750feb9-5d5c-4150-b62d-a9924f466888",
209
209
  "key": "bar",
210
210
  "value": {
211
211
  "type": "CONSTANT_VALUE",
@@ -325,52 +325,52 @@ def test_serialize_node__prompt_parameters__dynamic_references():
325
325
  assert parameters_attribute["value"]["type"] == "DICTIONARY_REFERENCE"
326
326
  assert parameters_attribute["value"]["entries"] == [
327
327
  {
328
- "id": "6b63ff96-a2eb-4c6e-bad1-bde01605fa86",
328
+ "id": "24703d3a-ee6c-4b1b-80f8-6c19ef16723a",
329
329
  "key": "stop",
330
330
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
331
331
  },
332
332
  {
333
- "id": "265a1c17-2089-4ac1-b2ce-361b6b9a3335",
333
+ "id": "88a3bf5d-f42b-4895-850e-ad843945a003",
334
334
  "key": "temperature",
335
335
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
336
336
  },
337
337
  {
338
- "id": "699976ec-8ec2-476a-a011-7cf810a8a307",
338
+ "id": "ede3e0c2-3033-4d0a-bd72-e52595bdc916",
339
339
  "key": "max_tokens",
340
340
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
341
341
  },
342
342
  {
343
- "id": "a87e23da-9794-41ff-ba80-c3a77e976e75",
343
+ "id": "0013cd8f-7658-4908-80fc-b8995d8ca4cc",
344
344
  "key": "top_p",
345
345
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
346
346
  },
347
347
  {
348
- "id": "18eb53c2-ec1a-4115-9f21-083af430df67",
348
+ "id": "98eb2e57-d4ec-4c27-b39b-0b8086918a0f",
349
349
  "key": "top_k",
350
350
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
351
351
  },
352
352
  {
353
- "id": "295509a2-5837-452c-893d-f47b67c63c8a",
353
+ "id": "04accc66-888c-4145-8b4f-d8ff99e38172",
354
354
  "key": "frequency_penalty",
355
355
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
356
356
  },
357
357
  {
358
- "id": "5fc64379-5566-426a-a909-dd56c3305aa5",
358
+ "id": "9236d564-0637-48de-8423-cdf3617dd6b4",
359
359
  "key": "presence_penalty",
360
360
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
361
361
  },
362
362
  {
363
- "id": "5d326da0-c096-4425-8bf1-3a18764e96e3",
363
+ "id": "74f3e80a-3935-45af-a9b3-d49e310a4c03",
364
364
  "key": "logit_bias",
365
365
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
366
366
  },
367
367
  {
368
- "id": "cd1a0e1b-6667-48a0-9964-257e1ec8851d",
368
+ "id": "69a7ebf7-d21a-44e9-a0fa-43eb9b2815df",
369
369
  "key": "custom_parameters",
370
370
  "value": {
371
371
  "entries": [
372
372
  {
373
- "id": "a9a3092e-dd18-4533-b6b5-24588ebd8f7f",
373
+ "id": "e709dc4d-f2db-4dc9-b912-401b52fbb7b4",
374
374
  "key": "json_schema",
375
375
  "value": {
376
376
  "input_variable_id": "c02d1201-86d1-4364-b3b3-4fc6824db8a4",
@@ -92,7 +92,7 @@ def test_serialize_node__prompt_inputs__input_reference():
92
92
  "type": "DICTIONARY_REFERENCE",
93
93
  "entries": [
94
94
  {
95
- "id": "ab7902ef-de14-4edc-835c-366d3ef6a70e",
95
+ "id": "845009c8-03f8-4de4-b956-841309457d37",
96
96
  "key": "foo",
97
97
  "value": {"type": "WORKFLOW_INPUT", "input_variable_id": "e3657390-fd3c-4fea-8cdd-fc5ea79f3278"},
98
98
  }
@@ -134,12 +134,12 @@ def test_serialize_node__prompt_inputs__mixed_values():
134
134
  "type": "DICTIONARY_REFERENCE",
135
135
  "entries": [
136
136
  {
137
- "id": "0fc7e25e-075c-4849-b89b-9729d1aeada1",
137
+ "id": "a4016385-3cab-4c01-b9d2-7865cd54bdb0",
138
138
  "key": "foo",
139
139
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "bar"}},
140
140
  },
141
141
  {
142
- "id": "bba42c89-fa7b-4cb7-bc16-0d21ce060a4b",
142
+ "id": "828928b1-24e3-4457-9d6f-4f0692dfa355",
143
143
  "key": "baz",
144
144
  "value": {"type": "WORKFLOW_INPUT", "input_variable_id": "8d57cf1d-147c-427b-9a5e-e5f6ab76e2eb"},
145
145
  },
@@ -540,7 +540,7 @@ def test_serialize_tool_prompt_node_with_inline_workflow():
540
540
  "type": "DICTIONARY_REFERENCE",
541
541
  "entries": [
542
542
  {
543
- "id": "76ceec7b-ec37-474f-ba38-2bfd27cecc5d",
543
+ "id": "b1dfaf2b-b9fb-4fea-ad04-a988e5223d06",
544
544
  "key": "chat_history",
545
545
  "value": {
546
546
  "type": "BINARY_EXPRESSION",
@@ -37,7 +37,7 @@ class BaseTryNodeDisplay(BaseAdornmentNodeDisplay[_TryNodeType], Generic[_TryNod
37
37
  {
38
38
  "id": id,
39
39
  "name": attribute.name,
40
- "value": serialize_value(display_context, attribute.instance),
40
+ "value": serialize_value(node_id, display_context, attribute.instance),
41
41
  }
42
42
  )
43
43
 
@@ -476,3 +476,49 @@ def test_serialize_workflow_with_node_display_data():
476
476
 
477
477
  assert test_node is not None, "TestNode not found in serialized nodes"
478
478
  assert test_node["display_data"] == {"position": {"x": 100, "y": 200}, "z_index": 10, "width": 300, "height": 150}
479
+
480
+
481
+ def test_serialize_workflow_with_node_icon_and_color():
482
+ """
483
+ Tests that nodes with icon and color serialize correctly in workflow context.
484
+ """
485
+
486
+ # GIVEN a workflow with a node that has icon and color
487
+ class TestNode(BaseNode):
488
+ class Outputs(BaseNode.Outputs):
489
+ result: str
490
+
491
+ class TestWorkflow(BaseWorkflow):
492
+ graph = TestNode
493
+
494
+ class Outputs(BaseWorkflow.Outputs):
495
+ final_result = TestNode.Outputs.result
496
+
497
+ class TestNodeDisplay(BaseNodeDisplay[TestNode]):
498
+ display_data = NodeDisplayData(position=NodeDisplayPosition(x=100, y=200), icon="vellum:icon:cog", color="navy")
499
+
500
+ class TestWorkflowDisplay(BaseWorkflowDisplay[TestWorkflow]):
501
+ pass
502
+
503
+ # WHEN we serialize the workflow
504
+ display = get_workflow_display(
505
+ base_display_class=TestWorkflowDisplay,
506
+ workflow_class=TestWorkflow,
507
+ )
508
+ serialized_workflow = display.serialize()
509
+
510
+ # THEN the node should include icon and color in display_data
511
+ workflow_raw_data = cast(Dict[str, Any], serialized_workflow["workflow_raw_data"])
512
+ nodes = cast(List[Dict[str, Any]], workflow_raw_data["nodes"])
513
+
514
+ test_node = None
515
+ for node in nodes:
516
+ if node.get("type") == "GENERIC":
517
+ definition = node.get("definition")
518
+ if isinstance(definition, dict) and definition.get("name") == "TestNode":
519
+ test_node = node
520
+ break
521
+
522
+ assert test_node is not None, "TestNode not found in serialized nodes"
523
+ assert test_node["display_data"]["icon"] == "vellum:icon:cog"
524
+ assert test_node["display_data"]["color"] == "navy"
@@ -293,7 +293,7 @@ def test_serialize_node__workflow_input_as_nested_chat_history():
293
293
  "type": "DICTIONARY_REFERENCE",
294
294
  "entries": [
295
295
  {
296
- "id": "52d98e78-5c2a-488e-be3e-f3b487d94ad3",
296
+ "id": "07513ab1-cf47-490e-8b43-5da226332a00",
297
297
  "key": "hello",
298
298
  "value": {
299
299
  "type": "WORKFLOW_INPUT",
@@ -219,7 +219,7 @@ def test_serialize_workflow():
219
219
  "type": "DICTIONARY_REFERENCE",
220
220
  "entries": [
221
221
  {
222
- "id": "0bfa70a2-164f-460c-9e9a-4d62221eadf4",
222
+ "id": "6eb6687c-f894-4398-8e62-7dc89e96a0a4",
223
223
  "key": "noun",
224
224
  "value": {
225
225
  "type": "WORKFLOW_INPUT",
@@ -521,37 +521,37 @@ def test_serialize_workflow_with_nested_descriptor_blocks():
521
521
  {
522
522
  "entries": [
523
523
  {
524
- "id": "24a203be-3cba-4b20-bc84-9993a476c120",
524
+ "id": "4e61fbcf-13b3-4d5f-b5fb-2bf919a92045",
525
525
  "key": "block_type",
526
526
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "CHAT_MESSAGE"}},
527
527
  },
528
528
  {
529
- "id": "c06269e6-f74c-4860-8fa5-22dcbdc89399",
529
+ "id": "79dd757e-46db-4c36-9ffc-ddb763d14f27",
530
530
  "key": "state",
531
531
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
532
532
  },
533
533
  {
534
- "id": "dd9c0d43-b931-4dc8-8b3a-a7507ddff0c1",
534
+ "id": "2f8164e8-5495-4b9c-8268-d75618cd0842",
535
535
  "key": "cache_config",
536
536
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
537
537
  },
538
538
  {
539
- "id": "bef22f2b-0b6e-4910-88cc-6df736d2e20e",
539
+ "id": "0e8dc132-de9a-40dc-9845-336bc957df5a",
540
540
  "key": "chat_role",
541
541
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "SYSTEM"}},
542
542
  },
543
543
  {
544
- "id": "c0beec30-f85e-4a78-a3fb-baee54a692f8",
544
+ "id": "755a45d2-2420-4414-b318-5790880f84ec",
545
545
  "key": "chat_source",
546
546
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
547
547
  },
548
548
  {
549
- "id": "f601f4f2-62fe-4697-9fe0-99ca8aa64500",
549
+ "id": "3a563cdb-d130-497f-bac6-c324a4349a3c",
550
550
  "key": "chat_message_unterminated",
551
551
  "value": {"type": "CONSTANT_VALUE", "value": {"type": "JSON", "value": None}},
552
552
  },
553
553
  {
554
- "id": "ad550008-64e3-44a3-a32a-84ec226db31c",
554
+ "id": "2d0c084e-c54f-48f5-9444-a17f8aeb8f76",
555
555
  "key": "blocks",
556
556
  "value": {
557
557
  "items": [
@@ -131,6 +131,7 @@ def test_serialize_workflow():
131
131
  "id": "1381c078-efa2-4255-89a1-7b4cb742c7fc",
132
132
  "label": "Start Node",
133
133
  "type": "GENERIC",
134
+ "should_file_merge": True,
134
135
  "display_data": {"position": {"x": 200.0, "y": -50.0}},
135
136
  "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
136
137
  "definition": {
@@ -118,6 +118,7 @@ def test_serialize_workflow():
118
118
  "id": "baf6d316-dc75-41e8-96c0-015aede96309",
119
119
  "label": "Iteration",
120
120
  "type": "GENERIC",
121
+ "should_file_merge": True,
121
122
  "display_data": {"position": {"x": 200.0, "y": -50.0}},
122
123
  "base": {
123
124
  "name": "BaseNode",
@@ -155,6 +155,7 @@ def test_serialize_workflow():
155
155
  "id": "1381c078-efa2-4255-89a1-7b4cb742c7fc",
156
156
  "label": "Start Node",
157
157
  "type": "GENERIC",
158
+ "should_file_merge": True,
158
159
  "display_data": {"position": {"x": 200.0, "y": -50.0}},
159
160
  "base": {
160
161
  "name": "BaseNode",
@@ -400,7 +401,7 @@ def test_serialize_workflow():
400
401
  "type": "DICTIONARY_REFERENCE",
401
402
  "entries": [
402
403
  {
403
- "id": "d5c4d578-6ef1-4786-88f6-1ab0892d0798",
404
+ "id": "8eb8b551-9b48-43b3-861f-52adb5c585a8",
404
405
  "key": "question",
405
406
  "value": {
406
407
  "type": "WORKFLOW_INPUT",
@@ -42,6 +42,7 @@ def test_serialize_workflow():
42
42
  "id": "21f29cac-da87-495f-bba1-093d423f4e46",
43
43
  "label": "Get Current Weather Node",
44
44
  "type": "GENERIC",
45
+ "should_file_merge": True,
45
46
  "display_data": {
46
47
  "position": {"x": 200.0, "y": -50.0},
47
48
  "comment": {
@@ -169,7 +170,7 @@ def test_serialize_workflow():
169
170
  "type": "DICTIONARY_REFERENCE",
170
171
  "entries": [
171
172
  {
172
- "id": "b6d4427d-16dd-478a-9780-f88d60d2263d",
173
+ "id": "8eb8b551-9b48-43b3-861f-52adb5c585a8",
173
174
  "key": "question",
174
175
  "value": {
175
176
  "type": "WORKFLOW_INPUT",
@@ -1,3 +1,6 @@
1
+ from typing import Optional
2
+
3
+ from vellum import Vellum
1
4
  from vellum.workflows.events.workflow import WorkflowExecutionInitiatedEvent
2
5
  from vellum_ee.workflows.display.utils.registry import (
3
6
  get_parent_display_context_from_event,
@@ -25,7 +28,9 @@ def _should_mark_workflow_dynamic(event: WorkflowExecutionInitiatedEvent) -> boo
25
28
  return True
26
29
 
27
30
 
28
- def event_enricher(event: WorkflowExecutionInitiatedEvent) -> WorkflowExecutionInitiatedEvent:
31
+ def event_enricher(
32
+ event: WorkflowExecutionInitiatedEvent, client: Optional[Vellum] = None
33
+ ) -> WorkflowExecutionInitiatedEvent:
29
34
  if event.name != "workflow.execution.initiated":
30
35
  return event
31
36
 
@@ -33,6 +38,7 @@ def event_enricher(event: WorkflowExecutionInitiatedEvent) -> WorkflowExecutionI
33
38
  workflow_display = get_workflow_display(
34
39
  workflow_class=workflow_definition,
35
40
  parent_display_context=get_parent_display_context_from_event(event),
41
+ client=client,
36
42
  dry_run=True,
37
43
  )
38
44
  register_workflow_display_context(event.span_id, workflow_display.display_context)