vellum-ai 0.13.10__py3-none-any.whl → 0.13.12__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 (34) hide show
  1. vellum/client/core/client_wrapper.py +1 -1
  2. vellum/workflows/errors/types.py +21 -0
  3. vellum/workflows/nodes/bases/base.py +2 -9
  4. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +14 -1
  5. vellum/workflows/nodes/displayable/bases/tests/test_utils.py +18 -0
  6. vellum/workflows/nodes/displayable/bases/utils.py +8 -1
  7. vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py +55 -0
  8. {vellum_ai-0.13.10.dist-info → vellum_ai-0.13.12.dist-info}/METADATA +1 -1
  9. {vellum_ai-0.13.10.dist-info → vellum_ai-0.13.12.dist-info}/RECORD +33 -33
  10. vellum_cli/__init__.py +9 -1
  11. vellum_cli/config.py +29 -1
  12. vellum_cli/push.py +24 -3
  13. vellum_cli/tests/conftest.py +3 -0
  14. vellum_cli/tests/test_pull.py +6 -0
  15. vellum_cli/tests/test_push.py +88 -1
  16. vellum_ee/workflows/display/nodes/base_node_display.py +118 -6
  17. vellum_ee/workflows/display/nodes/base_node_vellum_display.py +16 -1
  18. vellum_ee/workflows/display/nodes/get_node_display_class.py +6 -4
  19. vellum_ee/workflows/display/nodes/vellum/__init__.py +0 -2
  20. vellum_ee/workflows/display/nodes/vellum/error_node.py +9 -3
  21. vellum_ee/workflows/display/nodes/vellum/tests/test_error_node.py +44 -0
  22. vellum_ee/workflows/display/nodes/vellum/try_node.py +3 -4
  23. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py +1 -1
  24. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +5 -2
  25. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +187 -6
  26. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +1 -1
  27. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +1 -1
  28. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +15 -1
  29. vellum_ee/workflows/display/utils/vellum.py +3 -0
  30. vellum_ee/workflows/display/workflows/vellum_workflow_display.py +27 -13
  31. vellum_ee/workflows/display/nodes/vellum/base_node.py +0 -121
  32. {vellum_ai-0.13.10.dist-info → vellum_ai-0.13.12.dist-info}/LICENSE +0 -0
  33. {vellum_ai-0.13.10.dist-info → vellum_ai-0.13.12.dist-info}/WHEEL +0 -0
  34. {vellum_ai-0.13.10.dist-info → vellum_ai-0.13.12.dist-info}/entry_points.txt +0 -0
@@ -4,10 +4,12 @@ from deepdiff import DeepDiff
4
4
 
5
5
  from vellum.workflows.inputs.base import BaseInputs
6
6
  from vellum.workflows.nodes.bases.base import BaseNode
7
+ from vellum.workflows.references.constant import ConstantValueReference
8
+ from vellum.workflows.references.lazy import LazyReference
7
9
  from vellum.workflows.references.vellum_secret import VellumSecretReference
8
10
  from vellum_ee.workflows.display.base import WorkflowInputsDisplay
11
+ from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
9
12
  from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
10
- from vellum_ee.workflows.display.nodes.vellum.base_node import BaseNodeDisplay
11
13
 
12
14
 
13
15
  class Inputs(BaseInputs):
@@ -19,11 +21,7 @@ class ConstantValueGenericNode(BaseNode):
19
21
 
20
22
 
21
23
  def test_serialize_node__constant_value(serialize_node):
22
- input_id = uuid4()
23
- serialized_node = serialize_node(
24
- node_class=ConstantValueGenericNode,
25
- global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=input_id)},
26
- )
24
+ serialized_node = serialize_node(ConstantValueGenericNode)
27
25
 
28
26
  assert not DeepDiff(
29
27
  {
@@ -67,6 +65,92 @@ def test_serialize_node__constant_value(serialize_node):
67
65
  )
68
66
 
69
67
 
68
+ class ConstantValueReferenceGenericNode(BaseNode):
69
+ attr: str = ConstantValueReference("hello")
70
+
71
+
72
+ def test_serialize_node__constant_value_reference(serialize_node):
73
+ serialized_node = serialize_node(ConstantValueReferenceGenericNode)
74
+
75
+ assert not DeepDiff(
76
+ {
77
+ "id": "9271e2b1-f47e-47a4-95ae-51299dedb62f",
78
+ "label": "ConstantValueReferenceGenericNode",
79
+ "type": "GENERIC",
80
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
81
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
82
+ "definition": {
83
+ "name": "ConstantValueReferenceGenericNode",
84
+ "module": [
85
+ "vellum_ee",
86
+ "workflows",
87
+ "display",
88
+ "tests",
89
+ "workflow_serialization",
90
+ "generic_nodes",
91
+ "test_attributes_serialization",
92
+ ],
93
+ },
94
+ "trigger": {"id": "8cc0b4c4-4ae4-4248-8fd5-bfb2e658eb51", "merge_behavior": "AWAIT_ATTRIBUTES"},
95
+ "ports": [{"id": "fe696d84-47c2-4325-8020-34a1c586a759", "name": "default", "type": "DEFAULT"}],
96
+ "adornments": None,
97
+ "attributes": [
98
+ {
99
+ "id": "460aeb68-7369-43d2-9d3d-37caa425611f",
100
+ "name": "attr",
101
+ "value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "hello"}},
102
+ }
103
+ ],
104
+ "outputs": [],
105
+ },
106
+ serialized_node,
107
+ ignore_order=True,
108
+ )
109
+
110
+
111
+ class LazyReferenceGenericNode(BaseNode):
112
+ attr: str = LazyReference(lambda: ConstantValueReference("hello"))
113
+
114
+
115
+ def test_serialize_node__lazy_reference(serialize_node):
116
+ serialized_node = serialize_node(LazyReferenceGenericNode)
117
+
118
+ assert not DeepDiff(
119
+ {
120
+ "id": "29563b11-bd4d-47b0-b017-372f78aeaef5",
121
+ "label": "LazyReferenceGenericNode",
122
+ "type": "GENERIC",
123
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
124
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
125
+ "definition": {
126
+ "name": "LazyReferenceGenericNode",
127
+ "module": [
128
+ "vellum_ee",
129
+ "workflows",
130
+ "display",
131
+ "tests",
132
+ "workflow_serialization",
133
+ "generic_nodes",
134
+ "test_attributes_serialization",
135
+ ],
136
+ },
137
+ "trigger": {"id": "56e9791a-078a-4bb7-90bc-a26c3991c70f", "merge_behavior": "AWAIT_ATTRIBUTES"},
138
+ "ports": [{"id": "acb761a0-fcc2-4d21-bc8c-d0d560912c04", "name": "default", "type": "DEFAULT"}],
139
+ "adornments": None,
140
+ "attributes": [
141
+ {
142
+ "id": "4370b381-9165-4fb4-881e-480507abe069",
143
+ "name": "attr",
144
+ "value": {"type": "CONSTANT_VALUE", "value": {"type": "STRING", "value": "hello"}},
145
+ }
146
+ ],
147
+ "outputs": [],
148
+ },
149
+ serialized_node,
150
+ ignore_order=True,
151
+ )
152
+
153
+
70
154
  class WorkflowInputGenericNode(BaseNode):
71
155
  attr: str = Inputs.input
72
156
 
@@ -284,3 +368,100 @@ def test_serialize_node__node_execution(serialize_node):
284
368
  serialized_node,
285
369
  ignore_order=True,
286
370
  )
371
+
372
+
373
+ class CoalesceNodeA(BaseNode):
374
+ class Outputs(BaseNode.Outputs):
375
+ output: str
376
+
377
+
378
+ class CoalesceNodeADisplay(BaseNodeDisplay[CoalesceNodeA]):
379
+ pass
380
+
381
+
382
+ class CoalesceNodeB(BaseNode):
383
+ class Outputs(BaseNode.Outputs):
384
+ output: str
385
+
386
+
387
+ class CoalesceNodeBDisplay(BaseNodeDisplay[CoalesceNodeB]):
388
+ pass
389
+
390
+
391
+ class CoalesceNodeFinal(BaseNode):
392
+ attr = CoalesceNodeA.Outputs.output.coalesce(CoalesceNodeB.Outputs.output)
393
+
394
+
395
+ class CoalesceNodeFinalDisplay(BaseNodeDisplay[CoalesceNodeFinal]):
396
+ pass
397
+
398
+
399
+ def test_serialize_node__coalesce(serialize_node):
400
+ coalesce_node_a_output_id = uuid4()
401
+ coalesce_node_b_output_id = uuid4()
402
+ serialized_node = serialize_node(
403
+ node_class=CoalesceNodeFinal,
404
+ global_node_displays={
405
+ CoalesceNodeA: CoalesceNodeADisplay(),
406
+ CoalesceNodeB: CoalesceNodeBDisplay(),
407
+ CoalesceNodeFinal: CoalesceNodeFinalDisplay(),
408
+ },
409
+ global_node_output_displays={
410
+ CoalesceNodeA.Outputs.output: (
411
+ CoalesceNodeA,
412
+ NodeOutputDisplay(id=coalesce_node_a_output_id, name="output"),
413
+ ),
414
+ CoalesceNodeB.Outputs.output: (
415
+ CoalesceNodeB,
416
+ NodeOutputDisplay(id=coalesce_node_b_output_id, name="output"),
417
+ ),
418
+ },
419
+ )
420
+
421
+ assert not DeepDiff(
422
+ {
423
+ "id": "84d0ce62-afd1-4186-b0e3-5dd8e5ca8b65",
424
+ "label": "CoalesceNodeFinal",
425
+ "type": "GENERIC",
426
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
427
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
428
+ "definition": {
429
+ "name": "CoalesceNodeFinal",
430
+ "module": [
431
+ "vellum_ee",
432
+ "workflows",
433
+ "display",
434
+ "tests",
435
+ "workflow_serialization",
436
+ "generic_nodes",
437
+ "test_attributes_serialization",
438
+ ],
439
+ },
440
+ "trigger": {"id": "5165f887-153b-4ecd-9219-1beb3cf4f906", "merge_behavior": "AWAIT_ATTRIBUTES"},
441
+ "ports": [{"id": "08ab456d-f541-4400-8305-e97f30cbe745", "name": "default", "type": "DEFAULT"}],
442
+ "adornments": None,
443
+ "attributes": [
444
+ {
445
+ "id": "5a22dd48-9ef3-456b-85b8-7662cf7823eb",
446
+ "name": "attr",
447
+ "value": {
448
+ "type": "BINARY_EXPRESSION",
449
+ "lhs": {
450
+ "type": "NODE_OUTPUT",
451
+ "node_id": "20c340f2-409c-4d31-b44b-eeffd76938d5",
452
+ "node_output_id": str(coalesce_node_a_output_id),
453
+ },
454
+ "operator": "coalesce",
455
+ "rhs": {
456
+ "type": "NODE_OUTPUT",
457
+ "node_id": "9fac3c54-4e75-46ca-a1f2-a80fc6d8ad3f",
458
+ "node_output_id": str(coalesce_node_b_output_id),
459
+ },
460
+ },
461
+ }
462
+ ],
463
+ "outputs": [],
464
+ },
465
+ serialized_node,
466
+ ignore_order=True,
467
+ )
@@ -5,8 +5,8 @@ from deepdiff import DeepDiff
5
5
  from vellum.workflows.inputs.base import BaseInputs
6
6
  from vellum.workflows.nodes.bases.base import BaseNode
7
7
  from vellum_ee.workflows.display.base import WorkflowInputsDisplay
8
+ from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
8
9
  from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
9
- from vellum_ee.workflows.display.nodes.vellum.base_node import BaseNodeDisplay
10
10
 
11
11
 
12
12
  class Inputs(BaseInputs):
@@ -7,8 +7,8 @@ from vellum.workflows.nodes.bases.base import BaseNode
7
7
  from vellum.workflows.ports.port import Port
8
8
  from vellum.workflows.references.vellum_secret import VellumSecretReference
9
9
  from vellum_ee.workflows.display.base import WorkflowInputsDisplay
10
+ from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
10
11
  from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
11
- from vellum_ee.workflows.display.nodes.vellum.base_node import BaseNodeDisplay
12
12
 
13
13
 
14
14
  class Inputs(BaseInputs):
@@ -88,7 +88,21 @@ def test_serialize_workflow():
88
88
  {
89
89
  "id": "5cf9c5e3-0eae-4daf-8d73-8b9536258eb9",
90
90
  "type": "ERROR",
91
- "inputs": [],
91
+ "inputs": [
92
+ {
93
+ "id": "690d825f-6ffd-493e-8141-c86d384e6150",
94
+ "key": "error_source_input_id",
95
+ "value": {
96
+ "rules": [
97
+ {
98
+ "type": "CONSTANT_VALUE",
99
+ "data": {"type": "STRING", "value": "Input threshold was too low"},
100
+ }
101
+ ],
102
+ "combinator": "OR",
103
+ },
104
+ }
105
+ ],
92
106
  "data": {
93
107
  "name": "error-node",
94
108
  "label": "Fail Node",
@@ -6,6 +6,7 @@ from vellum.workflows.descriptors.base import BaseDescriptor
6
6
  from vellum.workflows.expressions.and_ import AndExpression
7
7
  from vellum.workflows.expressions.begins_with import BeginsWithExpression
8
8
  from vellum.workflows.expressions.between import BetweenExpression
9
+ from vellum.workflows.expressions.coalesce_expression import CoalesceExpression
9
10
  from vellum.workflows.expressions.contains import ContainsExpression
10
11
  from vellum.workflows.expressions.does_not_begin_with import DoesNotBeginWithExpression
11
12
  from vellum.workflows.expressions.does_not_contain import DoesNotContainExpression
@@ -150,5 +151,7 @@ def convert_descriptor_to_operator(descriptor: BaseDescriptor) -> LogicalOperato
150
151
  return "and"
151
152
  elif isinstance(descriptor, OrExpression):
152
153
  return "or"
154
+ elif isinstance(descriptor, CoalesceExpression):
155
+ return "coalesce"
153
156
  else:
154
157
  raise ValueError(f"Unsupported descriptor type: {descriptor}")
@@ -14,6 +14,7 @@ from vellum.workflows.references.output import OutputReference
14
14
  from vellum.workflows.types.core import JsonArray, JsonObject
15
15
  from vellum.workflows.types.generics import WorkflowType
16
16
  from vellum.workflows.utils.uuids import uuid4_from_hash
17
+ from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
17
18
  from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
18
19
  from vellum_ee.workflows.display.nodes.types import PortDisplay
19
20
  from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
@@ -43,7 +44,7 @@ class VellumWorkflowDisplay(
43
44
  WorkflowMetaVellumDisplayOverrides,
44
45
  WorkflowInputsVellumDisplay,
45
46
  WorkflowInputsVellumDisplayOverrides,
46
- BaseNodeVellumDisplay,
47
+ BaseNodeDisplay,
47
48
  EntrypointVellumDisplay,
48
49
  EntrypointVellumDisplayOverrides,
49
50
  EdgeVellumDisplay,
@@ -52,7 +53,7 @@ class VellumWorkflowDisplay(
52
53
  WorkflowOutputVellumDisplayOverrides,
53
54
  ]
54
55
  ):
55
- node_display_base_class = BaseNodeVellumDisplay
56
+ node_display_base_class = BaseNodeDisplay
56
57
 
57
58
  def serialize(self) -> JsonObject:
58
59
  input_variables: JsonArray = []
@@ -137,7 +138,7 @@ class VellumWorkflowDisplay(
137
138
  workflow_output_display.node_input_id,
138
139
  )
139
140
 
140
- source_node_display: Optional[BaseNodeVellumDisplay]
141
+ source_node_display: Optional[BaseNodeDisplay]
141
142
  first_rule = node_input.value.rules[0]
142
143
  if first_rule.type == "NODE_OUTPUT":
143
144
  source_node_id = UUID(first_rule.data.node_id)
@@ -170,15 +171,20 @@ class VellumWorkflowDisplay(
170
171
  )
171
172
 
172
173
  if source_node_display:
174
+ if isinstance(source_node_display, BaseNodeVellumDisplay):
175
+ source_handle_id = source_node_display.get_source_handle_id(
176
+ port_displays=self.display_context.port_displays
177
+ )
178
+ else:
179
+ source_handle_id = source_node_display.get_node_port_display(
180
+ source_node_display._node.Ports.default
181
+ ).id
182
+
173
183
  synthetic_output_edges.append(
174
184
  {
175
185
  "id": str(workflow_output_display.edge_id),
176
186
  "source_node_id": str(source_node_display.node_id),
177
- "source_handle_id": str(
178
- source_node_display.get_source_handle_id(
179
- port_displays=self.display_context.port_displays
180
- )
181
- ),
187
+ "source_handle_id": str(source_handle_id),
182
188
  "target_node_id": str(workflow_output_display.node_id),
183
189
  "target_handle_id": str(workflow_output_display.target_handle_id),
184
190
  "type": "DEFAULT",
@@ -279,7 +285,7 @@ class VellumWorkflowDisplay(
279
285
  self,
280
286
  entrypoint: Type[BaseNode],
281
287
  workflow_display: WorkflowMetaVellumDisplay,
282
- node_displays: Dict[Type[BaseNode], BaseNodeVellumDisplay],
288
+ node_displays: Dict[Type[BaseNode], BaseNodeDisplay],
283
289
  overrides: Optional[EntrypointVellumDisplayOverrides] = None,
284
290
  ) -> EntrypointVellumDisplay:
285
291
  entrypoint_node_id = workflow_display.entrypoint_node_id
@@ -293,8 +299,12 @@ class VellumWorkflowDisplay(
293
299
  )
294
300
 
295
301
  entrypoint_target = get_unadorned_node(entrypoint)
296
- target_node_id = node_displays[entrypoint_target].node_id
297
- target_handle_id = node_displays[entrypoint_target].get_target_handle_id()
302
+ target_node_display = node_displays[entrypoint_target]
303
+ target_node_id = target_node_display.node_id
304
+ if isinstance(target_node_display, BaseNodeVellumDisplay):
305
+ target_handle_id = target_node_display.get_target_handle_id_by_source_node_id(entrypoint_node_id)
306
+ else:
307
+ target_handle_id = target_node_display.get_trigger_id()
298
308
 
299
309
  edge_display = self._generate_edge_display_from_source(
300
310
  entrypoint_node_id, source_handle_id, target_node_id, target_handle_id, overrides=edge_display_overrides
@@ -339,7 +349,7 @@ class VellumWorkflowDisplay(
339
349
  def _generate_edge_display(
340
350
  self,
341
351
  edge: Edge,
342
- node_displays: Dict[Type[BaseNode], BaseNodeVellumDisplay],
352
+ node_displays: Dict[Type[BaseNode], BaseNodeDisplay],
343
353
  port_displays: Dict[Port, PortDisplay],
344
354
  overrides: Optional[EdgeVellumDisplayOverrides] = None,
345
355
  ) -> EdgeVellumDisplay:
@@ -352,7 +362,11 @@ class VellumWorkflowDisplay(
352
362
 
353
363
  target_node_display = node_displays[target_node]
354
364
  target_node_id = target_node_display.node_id
355
- target_handle_id = target_node_display.get_target_handle_id_by_source_node_id(source_node_id)
365
+
366
+ if isinstance(target_node_display, BaseNodeVellumDisplay):
367
+ target_handle_id = target_node_display.get_target_handle_id_by_source_node_id(source_node_id)
368
+ else:
369
+ target_handle_id = target_node_display.get_trigger_id()
356
370
 
357
371
  return self._generate_edge_display_from_source(
358
372
  source_node_id, source_handle_id, target_node_id, target_handle_id, overrides
@@ -1,121 +0,0 @@
1
- import inspect
2
- from uuid import UUID
3
- from typing import Any, Generic, Optional, TypeVar, cast
4
-
5
- from vellum.workflows.constants import UNDEF
6
- from vellum.workflows.descriptors.base import BaseDescriptor
7
- from vellum.workflows.nodes.bases.base import BaseNode
8
- from vellum.workflows.nodes.utils import get_wrapped_node
9
- from vellum.workflows.types.core import JsonArray, JsonObject
10
- from vellum.workflows.utils.uuids import uuid4_from_hash
11
- from vellum.workflows.utils.vellum_variables import primitive_type_to_vellum_variable_type
12
- from vellum.workflows.workflows.base import BaseWorkflow
13
- from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
14
- from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
15
- from vellum_ee.workflows.display.types import WorkflowDisplayContext
16
- from vellum_ee.workflows.display.vellum import GenericNodeDisplayData
17
-
18
- _BaseNodeType = TypeVar("_BaseNodeType", bound=BaseNode)
19
-
20
-
21
- class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeType]):
22
- def serialize(
23
- self, display_context: WorkflowDisplayContext, adornments: Optional[JsonArray] = None, **kwargs: Any
24
- ) -> JsonObject:
25
- node = self._node
26
- node_id = self.node_id
27
-
28
- attributes: JsonArray = []
29
- for attribute in node:
30
- if inspect.isclass(attribute.instance) and issubclass(attribute.instance, BaseWorkflow):
31
- # We don't need to serialize generic node attributes containing a subworkflow
32
- continue
33
-
34
- id = str(uuid4_from_hash(f"{node_id}|{attribute.name}"))
35
- attributes.append(
36
- {
37
- "id": id,
38
- "name": attribute.name,
39
- "value": self.serialize_value(display_context, cast(BaseDescriptor, attribute.instance)),
40
- }
41
- )
42
-
43
- wrapped_node = get_wrapped_node(node)
44
- if wrapped_node is not None:
45
- display_class = get_node_display_class(BaseNodeDisplay, wrapped_node)
46
-
47
- adornment: JsonObject = {
48
- "id": str(node_id),
49
- "label": node.__qualname__,
50
- "base": self.get_base().dict(),
51
- "attributes": attributes,
52
- }
53
-
54
- existing_adornments = adornments if adornments is not None else []
55
- return display_class().serialize(display_context, adornments=existing_adornments + [adornment])
56
-
57
- ports: JsonArray = []
58
- for port in node.Ports:
59
- id = str(self.get_node_port_display(port).id)
60
-
61
- if port._condition_type:
62
- ports.append(
63
- {
64
- "id": id,
65
- "name": port.name,
66
- "type": port._condition_type.value,
67
- "expression": (
68
- self.serialize_condition(display_context, port._condition) if port._condition else None
69
- ),
70
- }
71
- )
72
- else:
73
- ports.append(
74
- {
75
- "id": id,
76
- "name": port.name,
77
- "type": "DEFAULT",
78
- }
79
- )
80
-
81
- outputs: JsonArray = []
82
- for output in node.Outputs:
83
- type = primitive_type_to_vellum_variable_type(output)
84
- value = (
85
- self.serialize_value(display_context, output.instance)
86
- if output.instance is not None and output.instance != UNDEF
87
- else None
88
- )
89
-
90
- outputs.append(
91
- {
92
- "id": str(uuid4_from_hash(f"{node_id}|{output.name}")),
93
- "name": output.name,
94
- "type": type,
95
- "value": value,
96
- }
97
- )
98
-
99
- return {
100
- "id": str(node_id),
101
- "label": node.__qualname__,
102
- "type": "GENERIC",
103
- "display_data": self.get_generic_node_display_data().dict(),
104
- "base": self.get_base().dict(),
105
- "definition": self.get_definition().dict(),
106
- "trigger": {
107
- "id": str(self.get_trigger_id()),
108
- "merge_behavior": node.Trigger.merge_behavior.value,
109
- },
110
- "ports": ports,
111
- "adornments": adornments,
112
- "attributes": attributes,
113
- "outputs": outputs,
114
- }
115
-
116
- def get_target_handle_id(self) -> UUID:
117
- return self.get_trigger_id()
118
-
119
- def get_generic_node_display_data(self) -> GenericNodeDisplayData:
120
- explicit_value = self._get_explicit_node_display_attr("display_data", GenericNodeDisplayData)
121
- return explicit_value if explicit_value else GenericNodeDisplayData()