vellum-ai 0.13.1__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.
- 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
|
+
]
|