vellum-ai 0.13.0__py3-none-any.whl → 0.13.2__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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,