vellum-ai 0.13.1__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.
- vellum/client/core/client_wrapper.py +1 -1
- {vellum_ai-0.13.1.dist-info → vellum_ai-0.13.2.dist-info}/METADATA +1 -1
- {vellum_ai-0.13.1.dist-info → vellum_ai-0.13.2.dist-info}/RECORD +18 -17
- vellum_cli/__init__.py +14 -0
- vellum_cli/push.py +62 -12
- vellum_cli/tests/test_push.py +76 -0
- vellum_ee/workflows/display/nodes/vellum/base_node.py +37 -2
- vellum_ee/workflows/display/tests/test_vellum_workflow_display.py +48 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +238 -18
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +177 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +30 -38
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py +7 -8
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +35 -2
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +29 -2
- vellum_ee/workflows/display/workflows/vellum_workflow_display.py +3 -1
- {vellum_ai-0.13.1.dist-info → vellum_ai-0.13.2.dist-info}/LICENSE +0 -0
- {vellum_ai-0.13.1.dist-info → vellum_ai-0.13.2.dist-info}/WHEEL +0 -0
- {vellum_ai-0.13.1.dist-info → vellum_ai-0.13.2.dist-info}/entry_points.txt +0 -0
@@ -18,7 +18,7 @@ class BaseClientWrapper:
|
|
18
18
|
headers: typing.Dict[str, str] = {
|
19
19
|
"X-Fern-Language": "Python",
|
20
20
|
"X-Fern-SDK-Name": "vellum-ai",
|
21
|
-
"X-Fern-SDK-Version": "0.13.
|
21
|
+
"X-Fern-SDK-Version": "0.13.2",
|
22
22
|
}
|
23
23
|
headers["X_API_KEY"] = self.api_key
|
24
24
|
return headers
|
@@ -1,20 +1,20 @@
|
|
1
1
|
vellum_cli/CONTRIBUTING.md,sha256=FtDC7BGxSeMnwCXAUssFsAIElXtmJE-O5Z7BpolcgvI,2935
|
2
2
|
vellum_cli/README.md,sha256=2NudRoLzWxNKqnuVy1JuQ7DerIaxWGYkrH8kMd-asIE,90
|
3
|
-
vellum_cli/__init__.py,sha256=
|
3
|
+
vellum_cli/__init__.py,sha256=L8D7nVwC63WdAe6HTy7J_S3wCvjJBHDWaBkCrw76dtU,9573
|
4
4
|
vellum_cli/aliased_group.py,sha256=ugW498j0yv4ALJ8vS9MsO7ctDW7Jlir9j6nE_uHAP8c,3363
|
5
5
|
vellum_cli/config.py,sha256=998IZbvkrw2avjbvs8bw6NrbEgGz5UBKRbvKAcastJg,5493
|
6
6
|
vellum_cli/image_push.py,sha256=SJwhwWJsLjwGNezNVd_oCVpFMfPsAB3dfLWmriZZUtw,4419
|
7
7
|
vellum_cli/logger.py,sha256=PuRFa0WCh4sAGFS5aqWB0QIYpS6nBWwPJrIXpWxugV4,1022
|
8
8
|
vellum_cli/ping.py,sha256=lWyJw6sziXjyTopTYRdFF5hV-sYPVDdX0yVbG5fzcY4,585
|
9
9
|
vellum_cli/pull.py,sha256=zf0y22XptUYI_hMP_4Q1CEo9s2wALsTJcCXNd-_ibd8,7551
|
10
|
-
vellum_cli/push.py,sha256=
|
10
|
+
vellum_cli/push.py,sha256=KHakWiUwdeZff8QZSDF0l8xmCgMRo9ntan8kaLD02Lc,7677
|
11
11
|
vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
12
|
vellum_cli/tests/conftest.py,sha256=Jv-QUjXoCDhsvVvXEjOenNqRArO_xXhtNuCYt4wiOyE,1421
|
13
13
|
vellum_cli/tests/test_config.py,sha256=uvKGDc8BoVyT9_H0Z-g8469zVxomn6Oi3Zj-vK7O_wU,2631
|
14
14
|
vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
|
15
15
|
vellum_cli/tests/test_ping.py,sha256=QtbhYKMYn1DFnDyBij2mkQO32j9KOpZ5Pf0yek7k_Ao,1284
|
16
16
|
vellum_cli/tests/test_pull.py,sha256=6gbASF6ASy5YcdWjOCt6b5K0u2VWsFegdrTWu6sEVKs,19613
|
17
|
-
vellum_cli/tests/test_push.py,sha256=
|
17
|
+
vellum_cli/tests/test_push.py,sha256=PVxKwbWHjb1QwQ0n4tTqh2Tj6yg2cOGupOSXaXl08DI,11044
|
18
18
|
vellum_ee/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
vellum_ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
20
|
vellum_ee/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -30,7 +30,7 @@ vellum_ee/workflows/display/nodes/types.py,sha256=St1BB6no528OyELGiyRabWao0GGw6m
|
|
30
30
|
vellum_ee/workflows/display/nodes/utils.py,sha256=sloya5TpXsnot1HURc9L51INwflRqUzHxRVnCS9Cd-4,973
|
31
31
|
vellum_ee/workflows/display/nodes/vellum/__init__.py,sha256=_raKY9eKi_OvIFn6nGvf9xKSboKtYLHCWaWCwDQFbOc,1567
|
32
32
|
vellum_ee/workflows/display/nodes/vellum/api_node.py,sha256=hoV-cUtS6H9kmRQXHd2py95GRWI_dAnnaPwvlNBkDOQ,8571
|
33
|
-
vellum_ee/workflows/display/nodes/vellum/base_node.py,sha256=
|
33
|
+
vellum_ee/workflows/display/nodes/vellum/base_node.py,sha256=lbk6pWO2xRzjQmlh-3iWrc-6Hfa7cUycqCwLuVNFuW8,7623
|
34
34
|
vellum_ee/workflows/display/nodes/vellum/code_execution_node.py,sha256=z00Z3L0d4PsUQo4S8FRDTtOFLtjdi17TJbatNVF4nM8,4288
|
35
35
|
vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=UJtdeppJFrrgJi48soO1-r5eaKTOExjYCrEx_YCsvtU,10486
|
36
36
|
vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=Tyx74dUmj_ef0slptoUXHtkjLbNd3f4hXeoEozFaFcw,2023
|
@@ -50,22 +50,23 @@ vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py,sha256=Nqd6mxn0sgL4
|
|
50
50
|
vellum_ee/workflows/display/nodes/vellum/try_node.py,sha256=hB8dcGMGkuC95kk9hmZUgHsCLwEA37fHTFXj0JzbRjM,4692
|
51
51
|
vellum_ee/workflows/display/nodes/vellum/utils.py,sha256=nIZ1DYTYPRaYsVKcel9a-Fm8EniJL0N7f5PowxVGTVU,8318
|
52
52
|
vellum_ee/workflows/display/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
|
-
vellum_ee/workflows/display/tests/test_vellum_workflow_display.py,sha256=
|
53
|
+
vellum_ee/workflows/display/tests/test_vellum_workflow_display.py,sha256=4jXe7Wyspw6CxghVqKAOu-_QunKFvY4U6--zOiuXvV0,3069
|
54
54
|
vellum_ee/workflows/display/tests/workflow_serialization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
55
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
56
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py,sha256=RatRmgd1O7OX1r2QfMLPs-WvGQpPLfXIjWNGE4s0yLE,2186
|
57
57
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py,sha256=MtKRKcPJsUJ3le7PLz9H6iH3vmRBZDRy6c-4LUF76zE,1987
|
58
|
-
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py,sha256=
|
59
|
-
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/
|
60
|
-
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/
|
58
|
+
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py,sha256=apGjJgH2KrUVA5LuD9b2etjVFFG1cqYTmNATfdkngWA,10193
|
59
|
+
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py,sha256=nouAROR-L9_u6BfPbKUl20QjbbRpwPeElGS2wIWozLc,6239
|
60
|
+
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py,sha256=wZekdhIZBwbBoFNAdC9bBLwUxVKk3EnFdNmMwYIdKGA,37308
|
61
|
+
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py,sha256=os6wCZjcOyig8EJu-pTAFWXa0odMxTaR0mrbL0SS_4Y,4480
|
61
62
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py,sha256=bXZWxOKAVjZlbP3iLHPHGA4aPs0EguKlQqmYPNGv3cU,16391
|
62
63
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py,sha256=UPLEQPwsLzOqZdkXrB5Jo1FdCx0iQNf7ekfcq1byoFw,29392
|
63
64
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py,sha256=Xn8t-SpvQocKdxNofDeDETlFnkCbBxdLGiUG8m6fM6U,48399
|
64
65
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py,sha256=QVlkczxzaKuOhwbRvVP70otPDNnJcSGDfN79j92lFyk,5534
|
65
66
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py,sha256=_gv7vPxBWSOSRKMlXYv8GKj9h1JAXjXIVWkCE_XhkYE,5746
|
66
67
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py,sha256=mEkvKUrt8U6e9bN65QRG7Zd3KdCdoMvHm96LjGwy96k,7427
|
67
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py,sha256
|
68
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py,sha256=
|
68
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py,sha256=-e6svaclv068n66oLnha-CFzW4ihNnhyQuqAfUyI59k,21395
|
69
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py,sha256=luj_PdJd8e13C4JO7dkbTlNPko6N7cPFM1iAljdElW8,16043
|
69
70
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py,sha256=mGk21Wp9Gyr-rRwYqhLEyenJF-ArdXjAdj_qYqcldrE,8422
|
70
71
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py,sha256=W_d-hsjSqbqR5BA3aF3KFoEyfLV6x_yhNKmLA1ai2QY,8622
|
71
72
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py,sha256=PKJAYaEnVYZATJibqXEDysDoTtjBL2CK__WE2YyOTN4,12817
|
@@ -81,7 +82,7 @@ vellum_ee/workflows/display/vellum.py,sha256=8xXRI8b8Tt661H-iZreTQTvLNEKUr4lf-Xa
|
|
81
82
|
vellum_ee/workflows/display/workflows/__init__.py,sha256=kapXsC67VJcgSuiBMa86FdePG5A9kMB5Pi4Uy1O2ob4,207
|
82
83
|
vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=u5u_KnDp_ktLBlfkT5wiGHIloodSlUT3D3_DQXijtMA,13735
|
83
84
|
vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py,sha256=kp0u8LN_2IwshLrhMImhpZx1hRyAcD5gXY-kDuuaGMQ,1269
|
84
|
-
vellum_ee/workflows/display/workflows/vellum_workflow_display.py,sha256=
|
85
|
+
vellum_ee/workflows/display/workflows/vellum_workflow_display.py,sha256=V0edhtohqAWbaHvHkj9Sth4ieaIVejsrsRIr7aCCoVc,16871
|
85
86
|
vellum_ee/workflows/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
86
87
|
vellum_ee/workflows/server/virtual_file_loader.py,sha256=X_DdNK7MfyOjKWekk6YQpOSCT6klKcdjT6nVJcBH1sM,1481
|
87
88
|
vellum/__init__.py,sha256=iwoL3PQsiTvtX79J4qlAJ2EIqZ77zYJm3q7o1Ei3Awo,35398
|
@@ -89,7 +90,7 @@ vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
|
|
89
90
|
vellum/client/__init__.py,sha256=8nZt88C9SVwWanjLbIQMU3rzb32h5UZfFMBx3VPHB50,111887
|
90
91
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
91
92
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
92
|
-
vellum/client/core/client_wrapper.py,sha256=
|
93
|
+
vellum/client/core/client_wrapper.py,sha256=AO_2SZDUQmHi5QG-jZCS2IRnrrOAOowR3Mx8RJ0wqe4,1868
|
93
94
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
94
95
|
vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
|
95
96
|
vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
|
@@ -1418,8 +1419,8 @@ vellum/workflows/vellum_client.py,sha256=ODrq_TSl-drX2aezXegf7pizpWDVJuTXH-j6528
|
|
1418
1419
|
vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
|
1419
1420
|
vellum/workflows/workflows/base.py,sha256=k0kUWWko4fHyCqLSU_1cBK_pXZpl9MXekWiG-bdOAo0,18353
|
1420
1421
|
vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnadGsrSZGa7t7LpJA,2008
|
1421
|
-
vellum_ai-0.13.
|
1422
|
-
vellum_ai-0.13.
|
1423
|
-
vellum_ai-0.13.
|
1424
|
-
vellum_ai-0.13.
|
1425
|
-
vellum_ai-0.13.
|
1422
|
+
vellum_ai-0.13.2.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1423
|
+
vellum_ai-0.13.2.dist-info/METADATA,sha256=OZhBbZ5uJfG4C4BhBLJr-J6TiSA3GLLdwJHLss8Hm6o,5327
|
1424
|
+
vellum_ai-0.13.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1425
|
+
vellum_ai-0.13.2.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1426
|
+
vellum_ai-0.13.2.dist-info/RECORD,,
|
vellum_cli/__init__.py
CHANGED
@@ -64,6 +64,11 @@ def workflows():
|
|
64
64
|
is_flag=True,
|
65
65
|
help="Check the Workflow for errors and expected changes, without updating its state in Vellum.",
|
66
66
|
)
|
67
|
+
@click.option(
|
68
|
+
"--strict",
|
69
|
+
is_flag=True,
|
70
|
+
help="Raises an error if we detect an unexpected discrepancy in the generated artifact.",
|
71
|
+
)
|
67
72
|
def workflows_push(
|
68
73
|
module: Optional[str],
|
69
74
|
deploy: Optional[bool],
|
@@ -72,6 +77,7 @@ def workflows_push(
|
|
72
77
|
deployment_description: Optional[str],
|
73
78
|
release_tag: Optional[List[str]],
|
74
79
|
dry_run: Optional[bool],
|
80
|
+
strict: Optional[bool],
|
75
81
|
) -> None:
|
76
82
|
"""
|
77
83
|
Push Workflows to Vellum. If a module is provided, only the Workflow for that module will be pushed.
|
@@ -86,6 +92,7 @@ def workflows_push(
|
|
86
92
|
deployment_description=deployment_description,
|
87
93
|
release_tags=release_tag,
|
88
94
|
dry_run=dry_run,
|
95
|
+
strict=strict,
|
89
96
|
)
|
90
97
|
|
91
98
|
|
@@ -101,6 +108,11 @@ def workflows_push(
|
|
101
108
|
is_flag=True,
|
102
109
|
help="Check the Workflow for errors and expected changes, without updating its state in Vellum.",
|
103
110
|
)
|
111
|
+
@click.option(
|
112
|
+
"--strict",
|
113
|
+
is_flag=True,
|
114
|
+
help="Raises an error if we detect an unexpected discrepancy in the generated artifact.",
|
115
|
+
)
|
104
116
|
def push_module(
|
105
117
|
ctx: click.Context,
|
106
118
|
deploy: Optional[bool],
|
@@ -109,6 +121,7 @@ def push_module(
|
|
109
121
|
deployment_description: Optional[str],
|
110
122
|
release_tag: Optional[List[str]],
|
111
123
|
dry_run: Optional[bool],
|
124
|
+
strict: Optional[bool],
|
112
125
|
) -> None:
|
113
126
|
"""Push a specific module to Vellum"""
|
114
127
|
|
@@ -121,6 +134,7 @@ def push_module(
|
|
121
134
|
deployment_description=deployment_description,
|
122
135
|
release_tags=release_tag,
|
123
136
|
dry_run=dry_run,
|
137
|
+
strict=strict,
|
124
138
|
)
|
125
139
|
|
126
140
|
|
vellum_cli/push.py
CHANGED
@@ -9,6 +9,7 @@ from typing import List, Optional
|
|
9
9
|
|
10
10
|
from dotenv import load_dotenv
|
11
11
|
|
12
|
+
from vellum.client.core.api_error import ApiError
|
12
13
|
from vellum.resources.workflows.client import OMIT
|
13
14
|
from vellum.types import WorkflowPushDeploymentConfigRequest
|
14
15
|
from vellum.workflows.utils.names import snake_to_title_case
|
@@ -28,6 +29,7 @@ def push_command(
|
|
28
29
|
deployment_description: Optional[str] = None,
|
29
30
|
release_tags: Optional[List[str]] = None,
|
30
31
|
dry_run: Optional[bool] = None,
|
32
|
+
strict: Optional[bool] = None,
|
31
33
|
) -> None:
|
32
34
|
load_dotenv()
|
33
35
|
logger = load_cli_logger()
|
@@ -109,18 +111,66 @@ def push_command(
|
|
109
111
|
artifact.seek(0)
|
110
112
|
artifact.name = f"{workflow_config.module.replace('.', '__')}.tar.gz"
|
111
113
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
114
|
+
try:
|
115
|
+
response = client.workflows.push(
|
116
|
+
# Remove this once we could serialize using the artifact in Vembda
|
117
|
+
# https://app.shortcut.com/vellum/story/5585
|
118
|
+
exec_config=json.dumps(exec_config),
|
119
|
+
label=label,
|
120
|
+
workflow_sandbox_id=workflow_config.workflow_sandbox_id,
|
121
|
+
artifact=artifact,
|
122
|
+
# We should check with fern if we could auto-serialize typed object fields for us
|
123
|
+
# https://app.shortcut.com/vellum/story/5568
|
124
|
+
deployment_config=deployment_config_serialized, # type: ignore[arg-type]
|
125
|
+
dry_run=dry_run,
|
126
|
+
strict=strict,
|
127
|
+
)
|
128
|
+
except ApiError as e:
|
129
|
+
if e.status_code != 400 or not isinstance(e.body, dict) or "diffs" not in e.body:
|
130
|
+
raise e
|
131
|
+
|
132
|
+
diffs: dict = e.body["diffs"]
|
133
|
+
generated_only = diffs.get("generated_only", [])
|
134
|
+
generated_only_str = (
|
135
|
+
"\n".join(
|
136
|
+
["Files that were generated but not found in the original project:"]
|
137
|
+
+ [f"- {file}" for file in generated_only]
|
138
|
+
)
|
139
|
+
if generated_only
|
140
|
+
else ""
|
141
|
+
)
|
142
|
+
|
143
|
+
original_only = diffs.get("original_only", [])
|
144
|
+
original_only_str = (
|
145
|
+
"\n".join(
|
146
|
+
["Files that were found in the original project but not generated:"]
|
147
|
+
+ [f"- {file}" for file in original_only]
|
148
|
+
)
|
149
|
+
if original_only
|
150
|
+
else ""
|
151
|
+
)
|
152
|
+
|
153
|
+
modified = diffs.get("modified", {})
|
154
|
+
modified_str = (
|
155
|
+
"\n\n".join(
|
156
|
+
["Files that were different between the original project and the generated artifact:"]
|
157
|
+
+ ["\n".join(line.strip() for line in lines) for lines in modified.values()]
|
158
|
+
)
|
159
|
+
if modified
|
160
|
+
else ""
|
161
|
+
)
|
162
|
+
|
163
|
+
reported_diffs = f"""\
|
164
|
+
{e.body.get("detail")}
|
165
|
+
|
166
|
+
{generated_only_str}
|
167
|
+
|
168
|
+
{original_only_str}
|
169
|
+
|
170
|
+
{modified_str}
|
171
|
+
"""
|
172
|
+
logger.error(reported_diffs)
|
173
|
+
return
|
124
174
|
|
125
175
|
if dry_run:
|
126
176
|
error_messages = [str(e) for e in workflow_display.errors]
|
vellum_cli/tests/test_push.py
CHANGED
@@ -7,6 +7,7 @@ from uuid import uuid4
|
|
7
7
|
|
8
8
|
from click.testing import CliRunner
|
9
9
|
|
10
|
+
from vellum.client.core.api_error import ApiError
|
10
11
|
from vellum.client.types.workflow_push_response import WorkflowPushResponse
|
11
12
|
from vellum.utils.uuid import is_valid_uuid
|
12
13
|
from vellum_cli import main as cli_main
|
@@ -242,3 +243,78 @@ class ExampleWorkflow(BaseWorkflow):
|
|
242
243
|
assert "Serialization is not supported." in result.output
|
243
244
|
assert "## Proposed Diffs" in result.output
|
244
245
|
assert "iterable_item_added" in result.output
|
246
|
+
|
247
|
+
|
248
|
+
def test_push__strict_option_returns_diffs(mock_module, vellum_client):
|
249
|
+
# GIVEN a single workflow configured
|
250
|
+
temp_dir = mock_module.temp_dir
|
251
|
+
module = mock_module.module
|
252
|
+
|
253
|
+
# AND a workflow exists in the module successfully
|
254
|
+
base_dir = os.path.join(temp_dir, *module.split("."))
|
255
|
+
os.makedirs(base_dir, exist_ok=True)
|
256
|
+
workflow_py_file_content = """\
|
257
|
+
from vellum.workflows import BaseWorkflow
|
258
|
+
|
259
|
+
class ExampleWorkflow(BaseWorkflow):
|
260
|
+
pass
|
261
|
+
"""
|
262
|
+
with open(os.path.join(temp_dir, *module.split("."), "workflow.py"), "w") as f:
|
263
|
+
f.write(workflow_py_file_content)
|
264
|
+
|
265
|
+
# AND the push API call returns a 4xx response with diffs
|
266
|
+
vellum_client.workflows.push.side_effect = ApiError(
|
267
|
+
status_code=400,
|
268
|
+
body={
|
269
|
+
"detail": "Failed to push workflow due to unexpected detected differences in the generated artifact.",
|
270
|
+
"diffs": {
|
271
|
+
"generated_only": ["state.py"],
|
272
|
+
"modified": {
|
273
|
+
"workflow.py": [
|
274
|
+
"--- a/workflow.py\n",
|
275
|
+
"+++ b/workflow.py\n",
|
276
|
+
"@@ -1 +1 @@\n",
|
277
|
+
"-print('hello')",
|
278
|
+
"+print('foo')",
|
279
|
+
]
|
280
|
+
},
|
281
|
+
"original_only": ["inputs.py"],
|
282
|
+
},
|
283
|
+
},
|
284
|
+
)
|
285
|
+
|
286
|
+
# WHEN calling `vellum push` on strict mode
|
287
|
+
runner = CliRunner()
|
288
|
+
result = runner.invoke(cli_main, ["push", module, "--strict"])
|
289
|
+
|
290
|
+
# THEN it should succeed
|
291
|
+
assert result.exit_code == 0
|
292
|
+
|
293
|
+
# AND we should have called the push API with the strict option
|
294
|
+
vellum_client.workflows.push.assert_called_once()
|
295
|
+
call_args = vellum_client.workflows.push.call_args.kwargs
|
296
|
+
assert call_args["strict"] is True
|
297
|
+
|
298
|
+
# AND the report should be in the output
|
299
|
+
assert (
|
300
|
+
result.output
|
301
|
+
== """\
|
302
|
+
\x1b[38;20mLoading workflow from examples.mock.test_push__strict_option_returns_diffs\x1b[0m
|
303
|
+
\x1b[31;20mFailed to push workflow due to unexpected detected differences in the generated artifact.
|
304
|
+
|
305
|
+
Files that were generated but not found in the original project:
|
306
|
+
- state.py
|
307
|
+
|
308
|
+
Files that were found in the original project but not generated:
|
309
|
+
- inputs.py
|
310
|
+
|
311
|
+
Files that were different between the original project and the generated artifact:
|
312
|
+
|
313
|
+
--- a/workflow.py
|
314
|
+
+++ b/workflow.py
|
315
|
+
@@ -1 +1 @@
|
316
|
+
-print('hello')
|
317
|
+
+print('foo')
|
318
|
+
\x1b[0m
|
319
|
+
"""
|
320
|
+
)
|
@@ -1,5 +1,6 @@
|
|
1
|
-
from typing import Any, Generic, TypeVar
|
1
|
+
from typing import Any, Generic, TypeVar, cast
|
2
2
|
|
3
|
+
from vellum.workflows.constants import UNDEF
|
3
4
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
4
5
|
from vellum.workflows.expressions.between import BetweenExpression
|
5
6
|
from vellum.workflows.expressions.is_not_null import IsNotNullExpression
|
@@ -12,6 +13,7 @@ from vellum.workflows.references.vellum_secret import VellumSecretReference
|
|
12
13
|
from vellum.workflows.references.workflow_input import WorkflowInputReference
|
13
14
|
from vellum.workflows.types.core import JsonArray, JsonObject
|
14
15
|
from vellum.workflows.utils.uuids import uuid4_from_hash
|
16
|
+
from vellum.workflows.utils.vellum_variables import primitive_type_to_vellum_variable_type
|
15
17
|
from vellum_ee.workflows.display.nodes.base_node_vellum_display import BaseNodeVellumDisplay
|
16
18
|
from vellum_ee.workflows.display.nodes.vellum.utils import convert_descriptor_to_operator
|
17
19
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
@@ -26,6 +28,18 @@ class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeTyp
|
|
26
28
|
node = self._node
|
27
29
|
node_id = self.node_id
|
28
30
|
|
31
|
+
attributes: JsonArray = []
|
32
|
+
for attribute in node:
|
33
|
+
id = str(uuid4_from_hash(f"{node_id}|{attribute.name}"))
|
34
|
+
|
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
|
+
|
29
43
|
ports: JsonArray = []
|
30
44
|
for idx, port in enumerate(node.Ports):
|
31
45
|
id = str(uuid4_from_hash(f"{node_id}|{idx}"))
|
@@ -34,6 +48,7 @@ class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeTyp
|
|
34
48
|
ports.append(
|
35
49
|
{
|
36
50
|
"id": id,
|
51
|
+
"name": port.name,
|
37
52
|
"type": port._condition_type.value,
|
38
53
|
"expression": (
|
39
54
|
self.serialize_condition(display_context, port._condition) if port._condition else None
|
@@ -44,10 +59,29 @@ class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeTyp
|
|
44
59
|
ports.append(
|
45
60
|
{
|
46
61
|
"id": id,
|
62
|
+
"name": port.name,
|
47
63
|
"type": "DEFAULT",
|
48
64
|
}
|
49
65
|
)
|
50
66
|
|
67
|
+
outputs: JsonArray = []
|
68
|
+
for output in node.Outputs:
|
69
|
+
type = primitive_type_to_vellum_variable_type(output)
|
70
|
+
value = (
|
71
|
+
self.serialize_value(display_context, output.instance)
|
72
|
+
if output.instance is not None and output.instance != UNDEF
|
73
|
+
else None
|
74
|
+
)
|
75
|
+
|
76
|
+
outputs.append(
|
77
|
+
{
|
78
|
+
"id": str(uuid4_from_hash(f"{node_id}|{output.name}")),
|
79
|
+
"name": output.name,
|
80
|
+
"type": type,
|
81
|
+
"value": value,
|
82
|
+
}
|
83
|
+
)
|
84
|
+
|
51
85
|
return {
|
52
86
|
"id": str(node_id),
|
53
87
|
"label": node.__qualname__,
|
@@ -61,7 +95,8 @@ class BaseNodeDisplay(BaseNodeVellumDisplay[_BaseNodeType], Generic[_BaseNodeTyp
|
|
61
95
|
},
|
62
96
|
"ports": ports,
|
63
97
|
"adornments": None,
|
64
|
-
"attributes":
|
98
|
+
"attributes": attributes,
|
99
|
+
"outputs": outputs,
|
65
100
|
}
|
66
101
|
|
67
102
|
def get_generic_node_display_data(self) -> GenericNodeDisplayData:
|
@@ -1,4 +1,10 @@
|
|
1
|
+
from uuid import UUID
|
2
|
+
|
3
|
+
from vellum.workflows.inputs import BaseInputs
|
4
|
+
from vellum.workflows.nodes import BaseNode
|
5
|
+
from vellum.workflows.state import BaseState
|
1
6
|
from vellum.workflows.workflows.base import BaseWorkflow
|
7
|
+
from vellum_ee.workflows.display.vellum import WorkflowInputsVellumDisplayOverrides
|
2
8
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
3
9
|
from vellum_ee.workflows.display.workflows.vellum_workflow_display import VellumWorkflowDisplay
|
4
10
|
|
@@ -40,3 +46,45 @@ def test_vellum_workflow_display__serialize_empty_workflow():
|
|
40
46
|
],
|
41
47
|
},
|
42
48
|
}
|
49
|
+
|
50
|
+
|
51
|
+
def test_vellum_workflow_display__serialize_input_variables_with_capitalized_variable_override():
|
52
|
+
# GIVEN a workflow with input variables
|
53
|
+
class Inputs(BaseInputs):
|
54
|
+
foo: str
|
55
|
+
|
56
|
+
class StartNode(BaseNode):
|
57
|
+
class Outputs(BaseNode.Outputs):
|
58
|
+
output = Inputs.foo
|
59
|
+
|
60
|
+
class ExampleWorkflow(BaseWorkflow[Inputs, BaseState]):
|
61
|
+
graph = StartNode
|
62
|
+
|
63
|
+
class ExampleWorkflowDisplay(VellumWorkflowDisplay[ExampleWorkflow]):
|
64
|
+
inputs_display = {
|
65
|
+
Inputs.foo: WorkflowInputsVellumDisplayOverrides(
|
66
|
+
id=UUID("97b63d71-5413-417f-9cf5-49e1b4fd56e4"), name="Foo", required=True
|
67
|
+
)
|
68
|
+
}
|
69
|
+
|
70
|
+
display = get_workflow_display(
|
71
|
+
base_display_class=ExampleWorkflowDisplay,
|
72
|
+
workflow_class=ExampleWorkflow,
|
73
|
+
)
|
74
|
+
|
75
|
+
# WHEN serializing the workflow
|
76
|
+
exec_config = display.serialize()
|
77
|
+
|
78
|
+
# THEN the input variables are what we expect
|
79
|
+
input_variables = exec_config["input_variables"]
|
80
|
+
|
81
|
+
assert input_variables == [
|
82
|
+
{
|
83
|
+
"id": "97b63d71-5413-417f-9cf5-49e1b4fd56e4",
|
84
|
+
"key": "Foo",
|
85
|
+
"type": "STRING",
|
86
|
+
"default": None,
|
87
|
+
"required": True,
|
88
|
+
"extensions": {"color": None},
|
89
|
+
}
|
90
|
+
]
|