vellum-ai 0.13.0__py3-none-any.whl → 0.13.2__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 (53) hide show
  1. vellum/client/core/client_wrapper.py +1 -1
  2. vellum/client/core/pydantic_utilities.py +5 -0
  3. vellum/client/resources/workflows/client.py +8 -0
  4. vellum/client/types/logical_operator.py +2 -0
  5. vellum/workflows/descriptors/base.py +1 -1
  6. vellum/workflows/descriptors/tests/test_utils.py +3 -0
  7. vellum/workflows/expressions/accessor.py +8 -2
  8. vellum/workflows/nodes/core/map_node/node.py +49 -24
  9. vellum/workflows/nodes/core/map_node/tests/test_node.py +4 -4
  10. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +1 -1
  11. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +5 -3
  12. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +3 -0
  13. vellum/workflows/nodes/displayable/bases/search_node.py +37 -2
  14. vellum/workflows/nodes/displayable/bases/tests/__init__.py +0 -0
  15. vellum/workflows/nodes/displayable/bases/tests/test_utils.py +61 -0
  16. vellum/workflows/nodes/displayable/bases/types.py +42 -0
  17. vellum/workflows/nodes/displayable/bases/utils.py +112 -0
  18. vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py +0 -1
  19. vellum/workflows/nodes/displayable/search_node/tests/__init__.py +0 -0
  20. vellum/workflows/nodes/displayable/search_node/tests/test_node.py +164 -0
  21. vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +2 -3
  22. vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +0 -1
  23. vellum/workflows/runner/runner.py +37 -4
  24. vellum/workflows/types/tests/test_utils.py +5 -2
  25. vellum/workflows/types/utils.py +4 -0
  26. vellum/workflows/workflows/base.py +14 -0
  27. {vellum_ai-0.13.0.dist-info → vellum_ai-0.13.2.dist-info}/METADATA +1 -1
  28. {vellum_ai-0.13.0.dist-info → vellum_ai-0.13.2.dist-info}/RECORD +53 -42
  29. vellum_cli/__init__.py +24 -0
  30. vellum_cli/ping.py +28 -0
  31. vellum_cli/push.py +62 -12
  32. vellum_cli/tests/test_ping.py +47 -0
  33. vellum_cli/tests/test_push.py +76 -0
  34. vellum_ee/workflows/display/nodes/vellum/base_node.py +59 -11
  35. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +3 -0
  36. vellum_ee/workflows/display/nodes/vellum/map_node.py +1 -1
  37. vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +14 -10
  38. vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +2 -2
  39. vellum_ee/workflows/display/nodes/vellum/utils.py +8 -1
  40. vellum_ee/workflows/display/tests/test_vellum_workflow_display.py +48 -0
  41. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +67 -0
  42. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +286 -0
  43. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +177 -0
  44. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +666 -14
  45. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py +7 -8
  46. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +35 -2
  47. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +29 -2
  48. vellum_ee/workflows/display/utils/vellum.py +4 -42
  49. vellum_ee/workflows/display/vellum.py +7 -36
  50. vellum_ee/workflows/display/workflows/vellum_workflow_display.py +5 -2
  51. {vellum_ai-0.13.0.dist-info → vellum_ai-0.13.2.dist-info}/LICENSE +0 -0
  52. {vellum_ai-0.13.0.dist-info → vellum_ai-0.13.2.dist-info}/WHEEL +0 -0
  53. {vellum_ai-0.13.0.dist-info → vellum_ai-0.13.2.dist-info}/entry_points.txt +0 -0
@@ -5,6 +5,7 @@ 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.workflows.ports.port import Port
8
+ from vellum.workflows.references.vellum_secret import VellumSecretReference
8
9
  from vellum_ee.workflows.display.base import WorkflowInputsDisplay
9
10
  from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
10
11
  from vellum_ee.workflows.display.nodes.vellum.base_node import BaseNodeDisplay
@@ -15,8 +16,7 @@ class Inputs(BaseInputs):
15
16
 
16
17
 
17
18
  class BasicGenericNode(BaseNode):
18
- class Outputs(BaseNode.Outputs):
19
- output = Inputs.input
19
+ pass
20
20
 
21
21
 
22
22
  def test_serialize_node__basic(serialize_node):
@@ -44,11 +44,13 @@ def test_serialize_node__basic(serialize_node):
44
44
  "ports": [
45
45
  {
46
46
  "id": "4fbf0fff-a42e-4410-852a-238b5059198e",
47
+ "name": "default",
47
48
  "type": "DEFAULT",
48
49
  }
49
50
  ],
50
51
  "adornments": None,
51
52
  "attributes": [],
53
+ "outputs": [],
52
54
  },
53
55
  serialized_node,
54
56
  ignore_order=True,
@@ -56,9 +58,6 @@ def test_serialize_node__basic(serialize_node):
56
58
 
57
59
 
58
60
  class IfGenericNode(BaseNode):
59
- class Outputs(BaseNode.Outputs):
60
- output = Inputs.input
61
-
62
61
  class Ports(BaseNode.Ports):
63
62
  if_branch = Port.on_if(Inputs.input.equals("hello"))
64
63
 
@@ -93,6 +92,7 @@ def test_serialize_node__if(serialize_node):
93
92
  {
94
93
  "id": "7605b4c0-a432-4517-b759-5858045a5146",
95
94
  "type": "IF",
95
+ "name": "if_branch",
96
96
  "expression": {
97
97
  "type": "BINARY_EXPRESSION",
98
98
  "lhs": {
@@ -112,6 +112,7 @@ def test_serialize_node__if(serialize_node):
112
112
  ],
113
113
  "adornments": None,
114
114
  "attributes": [],
115
+ "outputs": [],
115
116
  },
116
117
  serialized_node,
117
118
  ignore_order=True,
@@ -119,9 +120,6 @@ def test_serialize_node__if(serialize_node):
119
120
 
120
121
 
121
122
  class IfElseGenericNode(BaseNode):
122
- class Outputs(BaseNode.Outputs):
123
- output = Inputs.input
124
-
125
123
  class Ports(BaseNode.Ports):
126
124
  if_branch = Port.on_if(Inputs.input.equals("hello"))
127
125
  else_branch = Port.on_else()
@@ -157,6 +155,7 @@ def test_serialize_node__if_else(serialize_node):
157
155
  {
158
156
  "id": "3eeb7f03-7d65-45aa-b0e5-c7a453f5cbdf",
159
157
  "type": "IF",
158
+ "name": "if_branch",
160
159
  "expression": {
161
160
  "type": "BINARY_EXPRESSION",
162
161
  "lhs": {
@@ -176,11 +175,13 @@ def test_serialize_node__if_else(serialize_node):
176
175
  {
177
176
  "id": "b8472c77-74d5-4432-bf8b-6cd65d3dde06",
178
177
  "type": "ELSE",
178
+ "name": "else_branch",
179
179
  "expression": None,
180
180
  },
181
181
  ],
182
182
  "adornments": None,
183
183
  "attributes": [],
184
+ "outputs": [],
184
185
  },
185
186
  serialized_node,
186
187
  ignore_order=True,
@@ -188,9 +189,6 @@ def test_serialize_node__if_else(serialize_node):
188
189
 
189
190
 
190
191
  class IfElifElseGenericNode(BaseNode):
191
- class Outputs(BaseNode.Outputs):
192
- output = Inputs.input
193
-
194
192
  class Ports(BaseNode.Ports):
195
193
  if_branch = Port.on_if(Inputs.input.equals("hello"))
196
194
  elif_branch = Port.on_elif(Inputs.input.equals("world"))
@@ -227,6 +225,7 @@ def test_serialize_node__if_elif_else(serialize_node):
227
225
  {
228
226
  "id": "f6e0a2c0-192d-452f-bde4-32fb938e91bc",
229
227
  "type": "IF",
228
+ "name": "if_branch",
230
229
  "expression": {
231
230
  "type": "BINARY_EXPRESSION",
232
231
  "lhs": {
@@ -246,6 +245,7 @@ def test_serialize_node__if_elif_else(serialize_node):
246
245
  {
247
246
  "id": "7e44de04-e816-4da8-9251-cf389442a5d6",
248
247
  "type": "ELIF",
248
+ "name": "elif_branch",
249
249
  "expression": {
250
250
  "type": "BINARY_EXPRESSION",
251
251
  "lhs": {
@@ -266,10 +266,12 @@ def test_serialize_node__if_elif_else(serialize_node):
266
266
  "id": "00db3698-ddf5-413b-8408-fff664c212d7",
267
267
  "type": "ELSE",
268
268
  "expression": None,
269
+ "name": "else_branch",
269
270
  },
270
271
  ],
271
272
  "adornments": None,
272
273
  "attributes": [],
274
+ "outputs": [],
273
275
  },
274
276
  serialized_node,
275
277
  ignore_order=True,
@@ -286,9 +288,6 @@ class NodeWithOutputDisplay(BaseNodeDisplay[NodeWithOutput]):
286
288
 
287
289
 
288
290
  class GenericNodeReferencingOutput(BaseNode):
289
- class Outputs(BaseNode.Outputs):
290
- output = NodeWithOutput.Outputs.output
291
-
292
291
  class Ports(BaseNode.Ports):
293
292
  if_branch = Port.on_if(NodeWithOutput.Outputs.output.equals("hello"))
294
293
 
@@ -329,6 +328,7 @@ def test_serialize_node__node_output_reference(serialize_node):
329
328
  {
330
329
  "id": "ec9a79b8-65c3-4de8-bd29-42c914d72d4f",
331
330
  "type": "IF",
331
+ "name": "if_branch",
332
332
  "expression": {
333
333
  "type": "BINARY_EXPRESSION",
334
334
  "lhs": {
@@ -349,6 +349,658 @@ def test_serialize_node__node_output_reference(serialize_node):
349
349
  ],
350
350
  "adornments": None,
351
351
  "attributes": [],
352
+ "outputs": [],
353
+ },
354
+ serialized_node,
355
+ ignore_order=True,
356
+ )
357
+
358
+
359
+ class GenericNodeReferencingSecret(BaseNode):
360
+ class Ports(BaseNode.Ports):
361
+ if_branch = Port.on_if(VellumSecretReference(name="hello").equals("hello"))
362
+
363
+
364
+ def test_serialize_node__vellum_secret_reference(serialize_node):
365
+ workflow_input_id = uuid4()
366
+ serialized_node = serialize_node(
367
+ node_class=GenericNodeReferencingSecret,
368
+ global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=workflow_input_id)},
369
+ )
370
+
371
+ assert not DeepDiff(
372
+ {
373
+ "id": "88272edd-fc81-403b-bb87-a116ef8f269e",
374
+ "label": "GenericNodeReferencingSecret",
375
+ "type": "GENERIC",
376
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
377
+ "definition": {
378
+ "name": "GenericNodeReferencingSecret",
379
+ "module": [
380
+ "vellum_ee",
381
+ "workflows",
382
+ "display",
383
+ "tests",
384
+ "workflow_serialization",
385
+ "generic_nodes",
386
+ "test_ports_serialization",
387
+ ],
388
+ },
389
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
390
+ "trigger": {"id": "2709539b-352d-455a-bb86-dba070b59aa1", "merge_behavior": "AWAIT_ANY"},
391
+ "ports": [
392
+ {
393
+ "id": "a353d3f6-2a1f-457c-b8d1-13db5b45be8f",
394
+ "type": "IF",
395
+ "name": "if_branch",
396
+ "expression": {
397
+ "type": "BINARY_EXPRESSION",
398
+ "lhs": {"type": "VELLUM_SECRET", "vellum_secret_name": "hello"},
399
+ "operator": "=",
400
+ "rhs": {
401
+ "type": "CONSTANT_VALUE",
402
+ "value": {
403
+ "type": "STRING",
404
+ "value": "hello",
405
+ },
406
+ },
407
+ },
408
+ }
409
+ ],
410
+ "adornments": None,
411
+ "attributes": [],
412
+ "outputs": [],
413
+ },
414
+ serialized_node,
415
+ ignore_order=True,
416
+ )
417
+
418
+
419
+ class NodeWithExecutions(BaseNode):
420
+ pass
421
+
422
+
423
+ class NodeWithExecutionsDisplay(BaseNodeDisplay[NodeWithExecutions]):
424
+ pass
425
+
426
+
427
+ class GenericNodeReferencingExecutions(BaseNode):
428
+ class Ports(BaseNode.Ports):
429
+ if_branch = Port.on_if(NodeWithExecutions.Execution.count.equals(5))
430
+
431
+
432
+ def test_serialize_node__execution_count_reference(serialize_node):
433
+ workflow_input_id = uuid4()
434
+ serialized_node = serialize_node(
435
+ node_class=GenericNodeReferencingExecutions,
436
+ global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=workflow_input_id)},
437
+ global_node_displays={NodeWithExecutions: NodeWithExecutionsDisplay()},
438
+ )
439
+
440
+ assert not DeepDiff(
441
+ {
442
+ "id": "6e4d2fb7-891e-492e-97a1-adf44693f518",
443
+ "label": "GenericNodeReferencingExecutions",
444
+ "type": "GENERIC",
445
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
446
+ "definition": {
447
+ "name": "GenericNodeReferencingExecutions",
448
+ "module": [
449
+ "vellum_ee",
450
+ "workflows",
451
+ "display",
452
+ "tests",
453
+ "workflow_serialization",
454
+ "generic_nodes",
455
+ "test_ports_serialization",
456
+ ],
457
+ },
458
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
459
+ "trigger": {"id": "68a91426-4c30-4194-a4c0-cff224d3c0f3", "merge_behavior": "AWAIT_ANY"},
460
+ "ports": [
461
+ {
462
+ "id": "1794c2eb-5cab-49fe-9354-dfc29f11b374",
463
+ "type": "IF",
464
+ "name": "if_branch",
465
+ "expression": {
466
+ "type": "BINARY_EXPRESSION",
467
+ "lhs": {
468
+ "type": "EXECUTION_COUNTER",
469
+ "node_id": "c09bd5a6-dc04-4036-90d4-580acd43c71f",
470
+ },
471
+ "operator": "=",
472
+ "rhs": {
473
+ "type": "CONSTANT_VALUE",
474
+ "value": {
475
+ "type": "NUMBER",
476
+ "value": 5,
477
+ },
478
+ },
479
+ },
480
+ }
481
+ ],
482
+ "adornments": None,
483
+ "attributes": [],
484
+ "outputs": [],
485
+ },
486
+ serialized_node,
487
+ ignore_order=True,
488
+ )
489
+
490
+
491
+ class NullGenericNode(BaseNode):
492
+ class Ports(BaseNode.Ports):
493
+ if_branch = Port.on_if(Inputs.input.is_null())
494
+
495
+
496
+ def test_serialize_node__null(serialize_node):
497
+ input_id = uuid4()
498
+ serialized_node = serialize_node(
499
+ node_class=NullGenericNode, global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=input_id)}
500
+ )
501
+
502
+ assert not DeepDiff(
503
+ {
504
+ "id": "d5fe72cd-a2bd-4f91-ae13-44e4c617815e",
505
+ "label": "NullGenericNode",
506
+ "type": "GENERIC",
507
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
508
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
509
+ "definition": {
510
+ "name": "NullGenericNode",
511
+ "module": [
512
+ "vellum_ee",
513
+ "workflows",
514
+ "display",
515
+ "tests",
516
+ "workflow_serialization",
517
+ "generic_nodes",
518
+ "test_ports_serialization",
519
+ ],
520
+ },
521
+ "trigger": {"id": "26b257ed-6a7d-4ca3-a5c8-d17ba1e776ba", "merge_behavior": "AWAIT_ANY"},
522
+ "ports": [
523
+ {
524
+ "id": "51932d23-492e-4b3b-8b03-6ad7303a80c9",
525
+ "type": "IF",
526
+ "name": "if_branch",
527
+ "expression": {
528
+ "type": "UNARY_EXPRESSION",
529
+ "lhs": {
530
+ "type": "WORKFLOW_INPUT",
531
+ "input_variable_id": str(input_id),
532
+ },
533
+ "operator": "null",
534
+ },
535
+ }
536
+ ],
537
+ "adornments": None,
538
+ "attributes": [],
539
+ "outputs": [],
540
+ },
541
+ serialized_node,
542
+ ignore_order=True,
543
+ )
544
+
545
+
546
+ class IntegerInputs(BaseInputs):
547
+ input: int
548
+
549
+
550
+ class BetweenGenericNode(BaseNode):
551
+ class Ports(BaseNode.Ports):
552
+ if_branch = Port.on_if(IntegerInputs.input.between(1, 10))
553
+
554
+
555
+ def test_serialize_node__between(serialize_node):
556
+ input_id = uuid4()
557
+ serialized_node = serialize_node(
558
+ node_class=BetweenGenericNode,
559
+ global_workflow_input_displays={IntegerInputs.input: WorkflowInputsDisplay(id=input_id)},
560
+ )
561
+
562
+ assert not DeepDiff(
563
+ {
564
+ "id": "3ef33a2a-6ad5-415c-be75-f38cc1403dfc",
565
+ "label": "BetweenGenericNode",
566
+ "type": "GENERIC",
567
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
568
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
569
+ "definition": {
570
+ "name": "BetweenGenericNode",
571
+ "module": [
572
+ "vellum_ee",
573
+ "workflows",
574
+ "display",
575
+ "tests",
576
+ "workflow_serialization",
577
+ "generic_nodes",
578
+ "test_ports_serialization",
579
+ ],
580
+ },
581
+ "trigger": {"id": "086a355e-d9ef-4039-af35-9f1211497b32", "merge_behavior": "AWAIT_ANY"},
582
+ "ports": [
583
+ {
584
+ "id": "a86bd19f-a9f7-45c3-80ff-73330b1b75af",
585
+ "type": "IF",
586
+ "name": "if_branch",
587
+ "expression": {
588
+ "type": "TERNARY_EXPRESSION",
589
+ "base": {
590
+ "type": "WORKFLOW_INPUT",
591
+ "input_variable_id": str(input_id),
592
+ },
593
+ "operator": "between",
594
+ "lhs": {
595
+ "type": "CONSTANT_VALUE",
596
+ "value": {
597
+ "type": "NUMBER",
598
+ "value": 1,
599
+ },
600
+ },
601
+ "rhs": {
602
+ "type": "CONSTANT_VALUE",
603
+ "value": {
604
+ "type": "NUMBER",
605
+ "value": 10,
606
+ },
607
+ },
608
+ },
609
+ }
610
+ ],
611
+ "adornments": None,
612
+ "attributes": [],
613
+ "outputs": [],
614
+ },
615
+ serialized_node,
616
+ ignore_order=True,
617
+ )
618
+
619
+
620
+ class OrGenericNode(BaseNode):
621
+ class Ports(BaseNode.Ports):
622
+ if_branch = Port.on_if(Inputs.input.equals("hello") | Inputs.input.equals("world"))
623
+
624
+
625
+ def test_serialize_node__or(serialize_node):
626
+ input_id = uuid4()
627
+ serialized_node = serialize_node(
628
+ node_class=OrGenericNode, global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=input_id)}
629
+ )
630
+
631
+ assert not DeepDiff(
632
+ {
633
+ "id": "63900268-b9d0-4285-8ea4-7c478f4abf88",
634
+ "label": "OrGenericNode",
635
+ "type": "GENERIC",
636
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
637
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
638
+ "definition": {
639
+ "name": "OrGenericNode",
640
+ "module": [
641
+ "vellum_ee",
642
+ "workflows",
643
+ "display",
644
+ "tests",
645
+ "workflow_serialization",
646
+ "generic_nodes",
647
+ "test_ports_serialization",
648
+ ],
649
+ },
650
+ "trigger": {"id": "dc245f37-9be7-4097-a50a-4f7196e24313", "merge_behavior": "AWAIT_ANY"},
651
+ "ports": [
652
+ {
653
+ "id": "652a42f9-f4e7-4791-8167-8903ff839520",
654
+ "type": "IF",
655
+ "name": "if_branch",
656
+ "expression": {
657
+ "type": "BINARY_EXPRESSION",
658
+ "lhs": {
659
+ "type": "BINARY_EXPRESSION",
660
+ "lhs": {
661
+ "type": "WORKFLOW_INPUT",
662
+ "input_variable_id": str(input_id),
663
+ },
664
+ "operator": "=",
665
+ "rhs": {
666
+ "type": "CONSTANT_VALUE",
667
+ "value": {
668
+ "type": "STRING",
669
+ "value": "hello",
670
+ },
671
+ },
672
+ },
673
+ "operator": "or",
674
+ "rhs": {
675
+ "type": "BINARY_EXPRESSION",
676
+ "lhs": {
677
+ "type": "WORKFLOW_INPUT",
678
+ "input_variable_id": str(input_id),
679
+ },
680
+ "operator": "=",
681
+ "rhs": {
682
+ "type": "CONSTANT_VALUE",
683
+ "value": {
684
+ "type": "STRING",
685
+ "value": "world",
686
+ },
687
+ },
688
+ },
689
+ },
690
+ }
691
+ ],
692
+ "adornments": None,
693
+ "attributes": [],
694
+ "outputs": [],
695
+ },
696
+ serialized_node,
697
+ ignore_order=True,
698
+ )
699
+
700
+
701
+ class AndThenOrGenericNode(BaseNode):
702
+ class Ports(BaseNode.Ports):
703
+ if_branch = Port.on_if(
704
+ Inputs.input.equals("hello") & Inputs.input.equals("then") | Inputs.input.equals("world")
705
+ )
706
+
707
+
708
+ def test_serialize_node__and_then_or(serialize_node):
709
+ input_id = uuid4()
710
+ serialized_node = serialize_node(
711
+ node_class=AndThenOrGenericNode,
712
+ global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=input_id)},
713
+ )
714
+
715
+ assert not DeepDiff(
716
+ {
717
+ "id": "b3908206-e540-4dac-9c64-a2e12b847b15",
718
+ "label": "AndThenOrGenericNode",
719
+ "type": "GENERIC",
720
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
721
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
722
+ "definition": {
723
+ "name": "AndThenOrGenericNode",
724
+ "module": [
725
+ "vellum_ee",
726
+ "workflows",
727
+ "display",
728
+ "tests",
729
+ "workflow_serialization",
730
+ "generic_nodes",
731
+ "test_ports_serialization",
732
+ ],
733
+ },
734
+ "trigger": {"id": "33cfa8f4-bfc5-40b3-8df8-ab86371c26e0", "merge_behavior": "AWAIT_ANY"},
735
+ "ports": [
736
+ {
737
+ "id": "42c89e95-6bbf-4e85-8f26-d4b6fc55d99c",
738
+ "type": "IF",
739
+ "name": "if_branch",
740
+ "expression": {
741
+ "type": "BINARY_EXPRESSION",
742
+ "lhs": {
743
+ "type": "BINARY_EXPRESSION",
744
+ "lhs": {
745
+ "type": "BINARY_EXPRESSION",
746
+ "lhs": {
747
+ "type": "WORKFLOW_INPUT",
748
+ "input_variable_id": str(input_id),
749
+ },
750
+ "operator": "=",
751
+ "rhs": {
752
+ "type": "CONSTANT_VALUE",
753
+ "value": {
754
+ "type": "STRING",
755
+ "value": "hello",
756
+ },
757
+ },
758
+ },
759
+ "operator": "and",
760
+ "rhs": {
761
+ "type": "BINARY_EXPRESSION",
762
+ "lhs": {
763
+ "type": "WORKFLOW_INPUT",
764
+ "input_variable_id": str(input_id),
765
+ },
766
+ "operator": "=",
767
+ "rhs": {
768
+ "type": "CONSTANT_VALUE",
769
+ "value": {
770
+ "type": "STRING",
771
+ "value": "then",
772
+ },
773
+ },
774
+ },
775
+ },
776
+ "operator": "or",
777
+ "rhs": {
778
+ "type": "BINARY_EXPRESSION",
779
+ "lhs": {
780
+ "type": "WORKFLOW_INPUT",
781
+ "input_variable_id": str(input_id),
782
+ },
783
+ "operator": "=",
784
+ "rhs": {
785
+ "type": "CONSTANT_VALUE",
786
+ "value": {
787
+ "type": "STRING",
788
+ "value": "world",
789
+ },
790
+ },
791
+ },
792
+ },
793
+ }
794
+ ],
795
+ "adornments": None,
796
+ "attributes": [],
797
+ "outputs": [],
798
+ },
799
+ serialized_node,
800
+ ignore_order=True,
801
+ )
802
+
803
+
804
+ class ParenthesizedAndThenOrGenericNode(BaseNode):
805
+ class Ports(BaseNode.Ports):
806
+ if_branch = Port.on_if(
807
+ Inputs.input.equals("hello") & (Inputs.input.equals("then") | Inputs.input.equals("world"))
808
+ )
809
+
810
+
811
+ def test_serialize_node__parenthesized_and_then_or(serialize_node):
812
+ input_id = uuid4()
813
+ serialized_node = serialize_node(
814
+ node_class=ParenthesizedAndThenOrGenericNode,
815
+ global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=input_id)},
816
+ )
817
+
818
+ assert not DeepDiff(
819
+ {
820
+ "id": "6ed0373a-13b1-4edb-b0c4-31642cf312f8",
821
+ "label": "ParenthesizedAndThenOrGenericNode",
822
+ "type": "GENERIC",
823
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
824
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
825
+ "definition": {
826
+ "name": "ParenthesizedAndThenOrGenericNode",
827
+ "module": [
828
+ "vellum_ee",
829
+ "workflows",
830
+ "display",
831
+ "tests",
832
+ "workflow_serialization",
833
+ "generic_nodes",
834
+ "test_ports_serialization",
835
+ ],
836
+ },
837
+ "trigger": {"id": "91ac3b05-c931-4a4c-bb48-c2ba0e883867", "merge_behavior": "AWAIT_ANY"},
838
+ "ports": [
839
+ {
840
+ "id": "cc07394b-f20b-4370-8a5b-af90e847a73f",
841
+ "type": "IF",
842
+ "name": "if_branch",
843
+ "expression": {
844
+ "type": "BINARY_EXPRESSION",
845
+ "lhs": {
846
+ "type": "BINARY_EXPRESSION",
847
+ "lhs": {
848
+ "type": "WORKFLOW_INPUT",
849
+ "input_variable_id": str(input_id),
850
+ },
851
+ "operator": "=",
852
+ "rhs": {
853
+ "type": "CONSTANT_VALUE",
854
+ "value": {
855
+ "type": "STRING",
856
+ "value": "hello",
857
+ },
858
+ },
859
+ },
860
+ "operator": "and",
861
+ "rhs": {
862
+ "type": "BINARY_EXPRESSION",
863
+ "lhs": {
864
+ "type": "BINARY_EXPRESSION",
865
+ "lhs": {
866
+ "type": "WORKFLOW_INPUT",
867
+ "input_variable_id": str(input_id),
868
+ },
869
+ "operator": "=",
870
+ "rhs": {
871
+ "type": "CONSTANT_VALUE",
872
+ "value": {
873
+ "type": "STRING",
874
+ "value": "then",
875
+ },
876
+ },
877
+ },
878
+ "operator": "or",
879
+ "rhs": {
880
+ "type": "BINARY_EXPRESSION",
881
+ "lhs": {
882
+ "type": "WORKFLOW_INPUT",
883
+ "input_variable_id": str(input_id),
884
+ },
885
+ "operator": "=",
886
+ "rhs": {
887
+ "type": "CONSTANT_VALUE",
888
+ "value": {
889
+ "type": "STRING",
890
+ "value": "world",
891
+ },
892
+ },
893
+ },
894
+ },
895
+ },
896
+ }
897
+ ],
898
+ "adornments": None,
899
+ "attributes": [],
900
+ "outputs": [],
901
+ },
902
+ serialized_node,
903
+ ignore_order=True,
904
+ )
905
+
906
+
907
+ class OrThenAndGenericNode(BaseNode):
908
+ class Ports(BaseNode.Ports):
909
+ if_branch = Port.on_if(
910
+ Inputs.input.equals("hello") | Inputs.input.equals("then") & Inputs.input.equals("world")
911
+ )
912
+
913
+
914
+ def test_serialize_node__or_then_and(serialize_node):
915
+ input_id = uuid4()
916
+ serialized_node = serialize_node(
917
+ node_class=OrThenAndGenericNode,
918
+ global_workflow_input_displays={Inputs.input: WorkflowInputsDisplay(id=input_id)},
919
+ )
920
+
921
+ assert not DeepDiff(
922
+ {
923
+ "id": "a0e0a35b-132e-4168-ad7d-ceb04f3203f2",
924
+ "label": "OrThenAndGenericNode",
925
+ "type": "GENERIC",
926
+ "display_data": {"position": {"x": 0.0, "y": 0.0}},
927
+ "base": {"name": "BaseNode", "module": ["vellum", "workflows", "nodes", "bases", "base"]},
928
+ "definition": {
929
+ "name": "OrThenAndGenericNode",
930
+ "module": [
931
+ "vellum_ee",
932
+ "workflows",
933
+ "display",
934
+ "tests",
935
+ "workflow_serialization",
936
+ "generic_nodes",
937
+ "test_ports_serialization",
938
+ ],
939
+ },
940
+ "trigger": {"id": "dfa53d32-36cc-4b1d-adad-d4de21ac1e5a", "merge_behavior": "AWAIT_ANY"},
941
+ "ports": [
942
+ {
943
+ "id": "daaff604-da1e-45e6-b3df-5bc8de8d55fe",
944
+ "type": "IF",
945
+ "name": "if_branch",
946
+ "expression": {
947
+ "type": "BINARY_EXPRESSION",
948
+ "lhs": {
949
+ "type": "BINARY_EXPRESSION",
950
+ "lhs": {
951
+ "type": "WORKFLOW_INPUT",
952
+ "input_variable_id": str(input_id),
953
+ },
954
+ "operator": "=",
955
+ "rhs": {
956
+ "type": "CONSTANT_VALUE",
957
+ "value": {
958
+ "type": "STRING",
959
+ "value": "hello",
960
+ },
961
+ },
962
+ },
963
+ "operator": "or",
964
+ "rhs": {
965
+ "type": "BINARY_EXPRESSION",
966
+ "lhs": {
967
+ "type": "BINARY_EXPRESSION",
968
+ "lhs": {
969
+ "type": "WORKFLOW_INPUT",
970
+ "input_variable_id": str(input_id),
971
+ },
972
+ "operator": "=",
973
+ "rhs": {
974
+ "type": "CONSTANT_VALUE",
975
+ "value": {
976
+ "type": "STRING",
977
+ "value": "then",
978
+ },
979
+ },
980
+ },
981
+ "operator": "and",
982
+ "rhs": {
983
+ "type": "BINARY_EXPRESSION",
984
+ "lhs": {
985
+ "type": "WORKFLOW_INPUT",
986
+ "input_variable_id": str(input_id),
987
+ },
988
+ "operator": "=",
989
+ "rhs": {
990
+ "type": "CONSTANT_VALUE",
991
+ "value": {
992
+ "type": "STRING",
993
+ "value": "world",
994
+ },
995
+ },
996
+ },
997
+ },
998
+ },
999
+ }
1000
+ ],
1001
+ "adornments": None,
1002
+ "attributes": [],
1003
+ "outputs": [],
352
1004
  },
353
1005
  serialized_node,
354
1006
  ignore_order=True,