vellum-ai 0.13.1__py3-none-any.whl → 0.13.3__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 (20) hide show
  1. vellum/client/core/client_wrapper.py +1 -1
  2. vellum/workflows/nodes/core/templating_node/node.py +27 -1
  3. vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py +30 -0
  4. {vellum_ai-0.13.1.dist-info → vellum_ai-0.13.3.dist-info}/METADATA +2 -2
  5. {vellum_ai-0.13.1.dist-info → vellum_ai-0.13.3.dist-info}/RECORD +20 -19
  6. vellum_cli/__init__.py +14 -0
  7. vellum_cli/push.py +62 -12
  8. vellum_cli/tests/test_push.py +76 -0
  9. vellum_ee/workflows/display/nodes/vellum/base_node.py +37 -2
  10. vellum_ee/workflows/display/tests/test_vellum_workflow_display.py +48 -0
  11. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +238 -18
  12. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +177 -0
  13. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +30 -38
  14. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py +7 -8
  15. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +35 -2
  16. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +29 -2
  17. vellum_ee/workflows/display/workflows/vellum_workflow_display.py +3 -1
  18. {vellum_ai-0.13.1.dist-info → vellum_ai-0.13.3.dist-info}/LICENSE +0 -0
  19. {vellum_ai-0.13.1.dist-info → vellum_ai-0.13.3.dist-info}/WHEEL +0 -0
  20. {vellum_ai-0.13.1.dist-info → vellum_ai-0.13.3.dist-info}/entry_points.txt +0 -0
@@ -16,8 +16,7 @@ class Inputs(BaseInputs):
16
16
 
17
17
 
18
18
  class BasicGenericNode(BaseNode):
19
- class Outputs(BaseNode.Outputs):
20
- output = Inputs.input
19
+ pass
21
20
 
22
21
 
23
22
  def test_serialize_node__basic(serialize_node):
@@ -45,11 +44,13 @@ def test_serialize_node__basic(serialize_node):
45
44
  "ports": [
46
45
  {
47
46
  "id": "4fbf0fff-a42e-4410-852a-238b5059198e",
47
+ "name": "default",
48
48
  "type": "DEFAULT",
49
49
  }
50
50
  ],
51
51
  "adornments": None,
52
52
  "attributes": [],
53
+ "outputs": [],
53
54
  },
54
55
  serialized_node,
55
56
  ignore_order=True,
@@ -57,9 +58,6 @@ def test_serialize_node__basic(serialize_node):
57
58
 
58
59
 
59
60
  class IfGenericNode(BaseNode):
60
- class Outputs(BaseNode.Outputs):
61
- output = Inputs.input
62
-
63
61
  class Ports(BaseNode.Ports):
64
62
  if_branch = Port.on_if(Inputs.input.equals("hello"))
65
63
 
@@ -94,6 +92,7 @@ def test_serialize_node__if(serialize_node):
94
92
  {
95
93
  "id": "7605b4c0-a432-4517-b759-5858045a5146",
96
94
  "type": "IF",
95
+ "name": "if_branch",
97
96
  "expression": {
98
97
  "type": "BINARY_EXPRESSION",
99
98
  "lhs": {
@@ -113,6 +112,7 @@ def test_serialize_node__if(serialize_node):
113
112
  ],
114
113
  "adornments": None,
115
114
  "attributes": [],
115
+ "outputs": [],
116
116
  },
117
117
  serialized_node,
118
118
  ignore_order=True,
@@ -120,9 +120,6 @@ def test_serialize_node__if(serialize_node):
120
120
 
121
121
 
122
122
  class IfElseGenericNode(BaseNode):
123
- class Outputs(BaseNode.Outputs):
124
- output = Inputs.input
125
-
126
123
  class Ports(BaseNode.Ports):
127
124
  if_branch = Port.on_if(Inputs.input.equals("hello"))
128
125
  else_branch = Port.on_else()
@@ -158,6 +155,7 @@ def test_serialize_node__if_else(serialize_node):
158
155
  {
159
156
  "id": "3eeb7f03-7d65-45aa-b0e5-c7a453f5cbdf",
160
157
  "type": "IF",
158
+ "name": "if_branch",
161
159
  "expression": {
162
160
  "type": "BINARY_EXPRESSION",
163
161
  "lhs": {
@@ -177,11 +175,13 @@ def test_serialize_node__if_else(serialize_node):
177
175
  {
178
176
  "id": "b8472c77-74d5-4432-bf8b-6cd65d3dde06",
179
177
  "type": "ELSE",
178
+ "name": "else_branch",
180
179
  "expression": None,
181
180
  },
182
181
  ],
183
182
  "adornments": None,
184
183
  "attributes": [],
184
+ "outputs": [],
185
185
  },
186
186
  serialized_node,
187
187
  ignore_order=True,
@@ -189,9 +189,6 @@ def test_serialize_node__if_else(serialize_node):
189
189
 
190
190
 
191
191
  class IfElifElseGenericNode(BaseNode):
192
- class Outputs(BaseNode.Outputs):
193
- output = Inputs.input
194
-
195
192
  class Ports(BaseNode.Ports):
196
193
  if_branch = Port.on_if(Inputs.input.equals("hello"))
197
194
  elif_branch = Port.on_elif(Inputs.input.equals("world"))
@@ -228,6 +225,7 @@ def test_serialize_node__if_elif_else(serialize_node):
228
225
  {
229
226
  "id": "f6e0a2c0-192d-452f-bde4-32fb938e91bc",
230
227
  "type": "IF",
228
+ "name": "if_branch",
231
229
  "expression": {
232
230
  "type": "BINARY_EXPRESSION",
233
231
  "lhs": {
@@ -247,6 +245,7 @@ def test_serialize_node__if_elif_else(serialize_node):
247
245
  {
248
246
  "id": "7e44de04-e816-4da8-9251-cf389442a5d6",
249
247
  "type": "ELIF",
248
+ "name": "elif_branch",
250
249
  "expression": {
251
250
  "type": "BINARY_EXPRESSION",
252
251
  "lhs": {
@@ -267,10 +266,12 @@ def test_serialize_node__if_elif_else(serialize_node):
267
266
  "id": "00db3698-ddf5-413b-8408-fff664c212d7",
268
267
  "type": "ELSE",
269
268
  "expression": None,
269
+ "name": "else_branch",
270
270
  },
271
271
  ],
272
272
  "adornments": None,
273
273
  "attributes": [],
274
+ "outputs": [],
274
275
  },
275
276
  serialized_node,
276
277
  ignore_order=True,
@@ -287,9 +288,6 @@ class NodeWithOutputDisplay(BaseNodeDisplay[NodeWithOutput]):
287
288
 
288
289
 
289
290
  class GenericNodeReferencingOutput(BaseNode):
290
- class Outputs(BaseNode.Outputs):
291
- output = NodeWithOutput.Outputs.output
292
-
293
291
  class Ports(BaseNode.Ports):
294
292
  if_branch = Port.on_if(NodeWithOutput.Outputs.output.equals("hello"))
295
293
 
@@ -330,6 +328,7 @@ def test_serialize_node__node_output_reference(serialize_node):
330
328
  {
331
329
  "id": "ec9a79b8-65c3-4de8-bd29-42c914d72d4f",
332
330
  "type": "IF",
331
+ "name": "if_branch",
333
332
  "expression": {
334
333
  "type": "BINARY_EXPRESSION",
335
334
  "lhs": {
@@ -350,6 +349,7 @@ def test_serialize_node__node_output_reference(serialize_node):
350
349
  ],
351
350
  "adornments": None,
352
351
  "attributes": [],
352
+ "outputs": [],
353
353
  },
354
354
  serialized_node,
355
355
  ignore_order=True,
@@ -357,9 +357,6 @@ def test_serialize_node__node_output_reference(serialize_node):
357
357
 
358
358
 
359
359
  class GenericNodeReferencingSecret(BaseNode):
360
- class Outputs(BaseNode.Outputs):
361
- output = Inputs.input
362
-
363
360
  class Ports(BaseNode.Ports):
364
361
  if_branch = Port.on_if(VellumSecretReference(name="hello").equals("hello"))
365
362
 
@@ -395,6 +392,7 @@ def test_serialize_node__vellum_secret_reference(serialize_node):
395
392
  {
396
393
  "id": "a353d3f6-2a1f-457c-b8d1-13db5b45be8f",
397
394
  "type": "IF",
395
+ "name": "if_branch",
398
396
  "expression": {
399
397
  "type": "BINARY_EXPRESSION",
400
398
  "lhs": {"type": "VELLUM_SECRET", "vellum_secret_name": "hello"},
@@ -411,6 +409,7 @@ def test_serialize_node__vellum_secret_reference(serialize_node):
411
409
  ],
412
410
  "adornments": None,
413
411
  "attributes": [],
412
+ "outputs": [],
414
413
  },
415
414
  serialized_node,
416
415
  ignore_order=True,
@@ -426,9 +425,6 @@ class NodeWithExecutionsDisplay(BaseNodeDisplay[NodeWithExecutions]):
426
425
 
427
426
 
428
427
  class GenericNodeReferencingExecutions(BaseNode):
429
- class Outputs(BaseNode.Outputs):
430
- output = NodeWithExecutions.Execution.count
431
-
432
428
  class Ports(BaseNode.Ports):
433
429
  if_branch = Port.on_if(NodeWithExecutions.Execution.count.equals(5))
434
430
 
@@ -465,6 +461,7 @@ def test_serialize_node__execution_count_reference(serialize_node):
465
461
  {
466
462
  "id": "1794c2eb-5cab-49fe-9354-dfc29f11b374",
467
463
  "type": "IF",
464
+ "name": "if_branch",
468
465
  "expression": {
469
466
  "type": "BINARY_EXPRESSION",
470
467
  "lhs": {
@@ -484,6 +481,7 @@ def test_serialize_node__execution_count_reference(serialize_node):
484
481
  ],
485
482
  "adornments": None,
486
483
  "attributes": [],
484
+ "outputs": [],
487
485
  },
488
486
  serialized_node,
489
487
  ignore_order=True,
@@ -491,9 +489,6 @@ def test_serialize_node__execution_count_reference(serialize_node):
491
489
 
492
490
 
493
491
  class NullGenericNode(BaseNode):
494
- class Outputs(BaseNode.Outputs):
495
- output = Inputs.input
496
-
497
492
  class Ports(BaseNode.Ports):
498
493
  if_branch = Port.on_if(Inputs.input.is_null())
499
494
 
@@ -528,6 +523,7 @@ def test_serialize_node__null(serialize_node):
528
523
  {
529
524
  "id": "51932d23-492e-4b3b-8b03-6ad7303a80c9",
530
525
  "type": "IF",
526
+ "name": "if_branch",
531
527
  "expression": {
532
528
  "type": "UNARY_EXPRESSION",
533
529
  "lhs": {
@@ -540,6 +536,7 @@ def test_serialize_node__null(serialize_node):
540
536
  ],
541
537
  "adornments": None,
542
538
  "attributes": [],
539
+ "outputs": [],
543
540
  },
544
541
  serialized_node,
545
542
  ignore_order=True,
@@ -551,9 +548,6 @@ class IntegerInputs(BaseInputs):
551
548
 
552
549
 
553
550
  class BetweenGenericNode(BaseNode):
554
- class Outputs(BaseNode.Outputs):
555
- output = IntegerInputs.input
556
-
557
551
  class Ports(BaseNode.Ports):
558
552
  if_branch = Port.on_if(IntegerInputs.input.between(1, 10))
559
553
 
@@ -589,6 +583,7 @@ def test_serialize_node__between(serialize_node):
589
583
  {
590
584
  "id": "a86bd19f-a9f7-45c3-80ff-73330b1b75af",
591
585
  "type": "IF",
586
+ "name": "if_branch",
592
587
  "expression": {
593
588
  "type": "TERNARY_EXPRESSION",
594
589
  "base": {
@@ -615,6 +610,7 @@ def test_serialize_node__between(serialize_node):
615
610
  ],
616
611
  "adornments": None,
617
612
  "attributes": [],
613
+ "outputs": [],
618
614
  },
619
615
  serialized_node,
620
616
  ignore_order=True,
@@ -622,9 +618,6 @@ def test_serialize_node__between(serialize_node):
622
618
 
623
619
 
624
620
  class OrGenericNode(BaseNode):
625
- class Outputs(BaseNode.Outputs):
626
- output = Inputs.input
627
-
628
621
  class Ports(BaseNode.Ports):
629
622
  if_branch = Port.on_if(Inputs.input.equals("hello") | Inputs.input.equals("world"))
630
623
 
@@ -659,6 +652,7 @@ def test_serialize_node__or(serialize_node):
659
652
  {
660
653
  "id": "652a42f9-f4e7-4791-8167-8903ff839520",
661
654
  "type": "IF",
655
+ "name": "if_branch",
662
656
  "expression": {
663
657
  "type": "BINARY_EXPRESSION",
664
658
  "lhs": {
@@ -697,6 +691,7 @@ def test_serialize_node__or(serialize_node):
697
691
  ],
698
692
  "adornments": None,
699
693
  "attributes": [],
694
+ "outputs": [],
700
695
  },
701
696
  serialized_node,
702
697
  ignore_order=True,
@@ -704,9 +699,6 @@ def test_serialize_node__or(serialize_node):
704
699
 
705
700
 
706
701
  class AndThenOrGenericNode(BaseNode):
707
- class Outputs(BaseNode.Outputs):
708
- output = Inputs.input
709
-
710
702
  class Ports(BaseNode.Ports):
711
703
  if_branch = Port.on_if(
712
704
  Inputs.input.equals("hello") & Inputs.input.equals("then") | Inputs.input.equals("world")
@@ -744,6 +736,7 @@ def test_serialize_node__and_then_or(serialize_node):
744
736
  {
745
737
  "id": "42c89e95-6bbf-4e85-8f26-d4b6fc55d99c",
746
738
  "type": "IF",
739
+ "name": "if_branch",
747
740
  "expression": {
748
741
  "type": "BINARY_EXPRESSION",
749
742
  "lhs": {
@@ -801,6 +794,7 @@ def test_serialize_node__and_then_or(serialize_node):
801
794
  ],
802
795
  "adornments": None,
803
796
  "attributes": [],
797
+ "outputs": [],
804
798
  },
805
799
  serialized_node,
806
800
  ignore_order=True,
@@ -808,9 +802,6 @@ def test_serialize_node__and_then_or(serialize_node):
808
802
 
809
803
 
810
804
  class ParenthesizedAndThenOrGenericNode(BaseNode):
811
- class Outputs(BaseNode.Outputs):
812
- output = Inputs.input
813
-
814
805
  class Ports(BaseNode.Ports):
815
806
  if_branch = Port.on_if(
816
807
  Inputs.input.equals("hello") & (Inputs.input.equals("then") | Inputs.input.equals("world"))
@@ -848,6 +839,7 @@ def test_serialize_node__parenthesized_and_then_or(serialize_node):
848
839
  {
849
840
  "id": "cc07394b-f20b-4370-8a5b-af90e847a73f",
850
841
  "type": "IF",
842
+ "name": "if_branch",
851
843
  "expression": {
852
844
  "type": "BINARY_EXPRESSION",
853
845
  "lhs": {
@@ -905,6 +897,7 @@ def test_serialize_node__parenthesized_and_then_or(serialize_node):
905
897
  ],
906
898
  "adornments": None,
907
899
  "attributes": [],
900
+ "outputs": [],
908
901
  },
909
902
  serialized_node,
910
903
  ignore_order=True,
@@ -912,9 +905,6 @@ def test_serialize_node__parenthesized_and_then_or(serialize_node):
912
905
 
913
906
 
914
907
  class OrThenAndGenericNode(BaseNode):
915
- class Outputs(BaseNode.Outputs):
916
- output = Inputs.input
917
-
918
908
  class Ports(BaseNode.Ports):
919
909
  if_branch = Port.on_if(
920
910
  Inputs.input.equals("hello") | Inputs.input.equals("then") & Inputs.input.equals("world")
@@ -952,6 +942,7 @@ def test_serialize_node__or_then_and(serialize_node):
952
942
  {
953
943
  "id": "daaff604-da1e-45e6-b3df-5bc8de8d55fe",
954
944
  "type": "IF",
945
+ "name": "if_branch",
955
946
  "expression": {
956
947
  "type": "BINARY_EXPRESSION",
957
948
  "lhs": {
@@ -1009,6 +1000,7 @@ def test_serialize_node__or_then_and(serialize_node):
1009
1000
  ],
1010
1001
  "adornments": None,
1011
1002
  "attributes": [],
1003
+ "outputs": [],
1012
1004
  },
1013
1005
  serialized_node,
1014
1006
  ignore_order=True,
@@ -10,8 +10,7 @@ class Inputs(BaseInputs):
10
10
 
11
11
 
12
12
  class BasicGenericNode(BaseNode):
13
- class Outputs(BaseNode.Outputs):
14
- output = Inputs.input
13
+ pass
15
14
 
16
15
 
17
16
  def test_serialize_node__basic(serialize_node):
@@ -39,11 +38,13 @@ def test_serialize_node__basic(serialize_node):
39
38
  "ports": [
40
39
  {
41
40
  "id": "4fbf0fff-a42e-4410-852a-238b5059198e",
41
+ "name": "default",
42
42
  "type": "DEFAULT",
43
43
  }
44
44
  ],
45
45
  "adornments": None,
46
46
  "attributes": [],
47
+ "outputs": [],
47
48
  },
48
49
  serialized_node,
49
50
  ignore_order=True,
@@ -51,9 +52,6 @@ def test_serialize_node__basic(serialize_node):
51
52
 
52
53
 
53
54
  class AwaitAnyGenericNode(BaseNode):
54
- class Outputs(BaseNode.Outputs):
55
- output = Inputs.input
56
-
57
55
  class Trigger(BaseNode.Trigger):
58
56
  merge_behavior = MergeBehavior.AWAIT_ANY
59
57
 
@@ -83,11 +81,13 @@ def test_serialize_node__await_any(serialize_node):
83
81
  "ports": [
84
82
  {
85
83
  "id": "3e219c0a-e5f8-443a-ac78-1a458b189009",
84
+ "name": "default",
86
85
  "type": "DEFAULT",
87
86
  }
88
87
  ],
89
88
  "adornments": None,
90
89
  "attributes": [],
90
+ "outputs": [],
91
91
  },
92
92
  serialized_node,
93
93
  ignore_order=True,
@@ -95,9 +95,6 @@ def test_serialize_node__await_any(serialize_node):
95
95
 
96
96
 
97
97
  class AwaitAllGenericNode(BaseNode):
98
- class Outputs(BaseNode.Outputs):
99
- output = Inputs.input
100
-
101
98
  class Trigger(BaseNode.Trigger):
102
99
  merge_behavior = MergeBehavior.AWAIT_ALL
103
100
 
@@ -127,11 +124,13 @@ def test_serialize_node__await_all(serialize_node):
127
124
  "ports": [
128
125
  {
129
126
  "id": "9797e93f-9fe6-48b2-a48e-476abbd20e32",
127
+ "name": "default",
130
128
  "type": "DEFAULT",
131
129
  }
132
130
  ],
133
131
  "adornments": None,
134
132
  "attributes": [],
133
+ "outputs": [],
135
134
  },
136
135
  serialized_node,
137
136
  ignore_order=True,
@@ -141,9 +141,42 @@ def test_serialize_workflow():
141
141
  "module": ["tests", "workflows", "basic_inline_subworkflow", "workflow"],
142
142
  },
143
143
  "trigger": {"id": "a95a34f2-e894-4fb6-a2c9-15d12c1e3135", "merge_behavior": "AWAIT_ANY"},
144
- "ports": [{"id": "4a62dea3-6a4a-4390-88d8-4af5d2c81474", "type": "DEFAULT"}],
144
+ "ports": [
145
+ {"id": "4a62dea3-6a4a-4390-88d8-4af5d2c81474", "type": "DEFAULT", "name": "default"}
146
+ ],
145
147
  "adornments": None,
146
- "attributes": [],
148
+ "attributes": [
149
+ {
150
+ "id": "b0ac6b50-22a8-42ba-a707-1aa09a653205",
151
+ "name": "metro",
152
+ "value": {
153
+ "type": "WORKFLOW_INPUT",
154
+ "input_variable_id": "f2f5da15-026d-4905-bfe7-7d16bda20eed",
155
+ },
156
+ },
157
+ {
158
+ "id": "c5f2d66c-5bb6-4d2a-8e4d-5356318cd3ba",
159
+ "name": "date",
160
+ "value": {
161
+ "type": "WORKFLOW_INPUT",
162
+ "input_variable_id": "aba1e6e0-dfa7-4c15-a4e6-aec6feebfaca",
163
+ },
164
+ },
165
+ ],
166
+ "outputs": [
167
+ {
168
+ "id": "3f4c753e-f057-47bb-9748-7968283cc8aa",
169
+ "name": "temperature",
170
+ "type": "NUMBER",
171
+ "value": None,
172
+ },
173
+ {
174
+ "id": "2a4a62b3-cd26-4d2c-b3f1-eaa5f9dd22dd",
175
+ "name": "reasoning",
176
+ "type": "STRING",
177
+ "value": None,
178
+ },
179
+ ],
147
180
  },
148
181
  {
149
182
  "id": "a773c3a5-78cb-4250-8d29-7282e8a579d3",
@@ -130,9 +130,36 @@ def test_serialize_workflow():
130
130
  "module": ["tests", "workflows", "basic_map_node", "workflow"],
131
131
  },
132
132
  "trigger": {"id": "01324747-9bc0-4ecd-a8ab-40dca5a94e2e", "merge_behavior": "AWAIT_ANY"},
133
- "ports": [{"id": "36791877-95b0-4390-a794-10accd8f548e", "type": "DEFAULT"}],
133
+ "ports": [
134
+ {"id": "36791877-95b0-4390-a794-10accd8f548e", "type": "DEFAULT", "name": "default"}
135
+ ],
134
136
  "adornments": None,
135
- "attributes": [],
137
+ "attributes": [
138
+ {
139
+ "id": "4306b0ce-f31c-4c8f-8122-659d40e60ffe",
140
+ "name": "item",
141
+ "value": {
142
+ "type": "WORKFLOW_INPUT",
143
+ "input_variable_id": "b29bb546-9bc8-4136-857d-8c7a464ba9d4",
144
+ },
145
+ },
146
+ {
147
+ "id": "bca02056-0fd9-44c6-8aa9-743dd1180d48",
148
+ "name": "index",
149
+ "value": {
150
+ "type": "WORKFLOW_INPUT",
151
+ "input_variable_id": "17e7ca49-668f-450d-a792-e1f97d13db67",
152
+ },
153
+ },
154
+ ],
155
+ "outputs": [
156
+ {
157
+ "id": "a7bcb362-a2b8-4476-b0de-a361efeec204",
158
+ "name": "count",
159
+ "type": "NUMBER",
160
+ "value": None,
161
+ }
162
+ ],
136
163
  },
137
164
  {
138
165
  "id": "6f4883b2-70b1-4e1c-ae15-7d0f5aec810b",
@@ -265,16 +265,18 @@ class VellumWorkflowDisplay(
265
265
  self, workflow_input: WorkflowInputReference, overrides: Optional[WorkflowInputsVellumDisplayOverrides] = None
266
266
  ) -> WorkflowInputsVellumDisplay:
267
267
  workflow_input_id: UUID
268
+ name = None
268
269
  required = None
269
270
  color = None
270
271
  if overrides:
271
272
  workflow_input_id = overrides.id
273
+ name = overrides.name
272
274
  required = overrides.required
273
275
  color = overrides.color
274
276
  else:
275
277
  workflow_input_id = uuid4_from_hash(f"{self.workflow_id}|inputs|id|{workflow_input.name}")
276
278
 
277
- return WorkflowInputsVellumDisplay(id=workflow_input_id, required=required, color=color)
279
+ return WorkflowInputsVellumDisplay(id=workflow_input_id, name=name, required=required, color=color)
278
280
 
279
281
  def _generate_entrypoint_display(
280
282
  self,