vellum-ai 0.13.15__py3-none-any.whl → 0.13.19__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/client/resources/workflows/client.py +0 -10
- vellum/workflows/nodes/core/retry_node/node.py +13 -7
- vellum/workflows/nodes/core/templating_node/node.py +4 -47
- vellum/workflows/nodes/displayable/code_execution_node/node.py +29 -23
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +169 -5
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +98 -1
- vellum/workflows/nodes/utils.py +50 -1
- vellum/workflows/outputs/base.py +11 -0
- vellum/workflows/references/external_input.py +14 -0
- vellum/workflows/state/base.py +7 -0
- vellum/workflows/state/tests/test_state.py +42 -0
- {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.19.dist-info}/METADATA +1 -1
- {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.19.dist-info}/RECORD +28 -27
- vellum_cli/config.py +69 -11
- vellum_cli/pull.py +57 -20
- vellum_cli/push.py +1 -5
- vellum_cli/tests/test_pull.py +157 -9
- vellum_cli/tests/test_push.py +0 -8
- vellum_ee/workflows/display/nodes/base_node_display.py +2 -2
- vellum_ee/workflows/display/nodes/get_node_display_class.py +16 -20
- vellum_ee/workflows/display/nodes/vellum/__init__.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/retry_node.py +10 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +28 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +2 -2
- {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.19.dist-info}/LICENSE +0 -0
- {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.19.dist-info}/WHEEL +0 -0
- {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.19.dist-info}/entry_points.txt +0 -0
vellum/workflows/nodes/utils.py
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
from functools import cache
|
2
|
+
import json
|
2
3
|
import sys
|
3
4
|
from types import ModuleType
|
4
|
-
from typing import Any, Callable, Optional, Type, TypeVar
|
5
|
+
from typing import Any, Callable, Optional, Type, TypeVar, get_args, get_origin
|
6
|
+
|
7
|
+
from pydantic import BaseModel
|
5
8
|
|
6
9
|
from vellum.workflows.nodes import BaseNode
|
7
10
|
from vellum.workflows.nodes.bases.base_adornment_node import BaseAdornmentNode
|
8
11
|
from vellum.workflows.ports.port import Port
|
12
|
+
from vellum.workflows.types.core import Json
|
9
13
|
from vellum.workflows.types.generics import NodeType
|
10
14
|
|
11
15
|
ADORNMENT_MODULE_NAME = "<adornment>"
|
@@ -73,3 +77,48 @@ def create_adornment(
|
|
73
77
|
return WrappedNode
|
74
78
|
|
75
79
|
return decorator
|
80
|
+
|
81
|
+
|
82
|
+
def parse_type_from_str(result_as_str: str, output_type: Any) -> Any:
|
83
|
+
if output_type is str:
|
84
|
+
return result_as_str
|
85
|
+
|
86
|
+
if output_type is float:
|
87
|
+
return float(result_as_str)
|
88
|
+
|
89
|
+
if output_type is int:
|
90
|
+
return int(result_as_str)
|
91
|
+
|
92
|
+
if output_type is bool:
|
93
|
+
return bool(result_as_str)
|
94
|
+
|
95
|
+
if get_origin(output_type) is list:
|
96
|
+
try:
|
97
|
+
data = json.loads(result_as_str)
|
98
|
+
except json.JSONDecodeError:
|
99
|
+
raise ValueError("Invalid JSON Array format for result_as_str")
|
100
|
+
|
101
|
+
if not isinstance(data, list):
|
102
|
+
raise ValueError(f"Expected a list of items for result_as_str, received {data.__class__.__name__}")
|
103
|
+
|
104
|
+
inner_type = get_args(output_type)[0]
|
105
|
+
if issubclass(inner_type, BaseModel):
|
106
|
+
return [inner_type.model_validate(item) for item in data]
|
107
|
+
else:
|
108
|
+
return data
|
109
|
+
|
110
|
+
if output_type is Json:
|
111
|
+
try:
|
112
|
+
return json.loads(result_as_str)
|
113
|
+
except json.JSONDecodeError:
|
114
|
+
raise ValueError("Invalid JSON format for result_as_str")
|
115
|
+
|
116
|
+
if issubclass(output_type, BaseModel):
|
117
|
+
try:
|
118
|
+
data = json.loads(result_as_str)
|
119
|
+
except json.JSONDecodeError:
|
120
|
+
raise ValueError("Invalid JSON format for result_as_str")
|
121
|
+
|
122
|
+
return output_type.model_validate(data)
|
123
|
+
|
124
|
+
raise ValueError(f"Unsupported output type: {output_type}")
|
vellum/workflows/outputs/base.py
CHANGED
@@ -6,6 +6,8 @@ from pydantic_core import core_schema
|
|
6
6
|
|
7
7
|
from vellum.workflows.constants import UNDEF
|
8
8
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
9
|
+
from vellum.workflows.errors.types import WorkflowErrorCode
|
10
|
+
from vellum.workflows.exceptions import NodeException
|
9
11
|
from vellum.workflows.references.output import OutputReference
|
10
12
|
from vellum.workflows.types.utils import get_class_attr_names, infer_types
|
11
13
|
|
@@ -183,6 +185,15 @@ class _BaseOutputsMeta(type):
|
|
183
185
|
|
184
186
|
class BaseOutputs(metaclass=_BaseOutputsMeta):
|
185
187
|
def __init__(self, **kwargs: Any) -> None:
|
188
|
+
declared_fields = {descriptor.name for descriptor in self.__class__}
|
189
|
+
provided_fields = set(kwargs.keys())
|
190
|
+
|
191
|
+
if not provided_fields.issubset(declared_fields):
|
192
|
+
raise NodeException(
|
193
|
+
message=f"Unexpected outputs: {provided_fields - declared_fields}",
|
194
|
+
code=WorkflowErrorCode.INVALID_OUTPUTS,
|
195
|
+
)
|
196
|
+
|
186
197
|
for name, value in kwargs.items():
|
187
198
|
setattr(self, name, value)
|
188
199
|
|
@@ -42,6 +42,20 @@ class ExternalInputReference(BaseDescriptor[_InputType], Generic[_InputType]):
|
|
42
42
|
|
43
43
|
raise NodeException(f"Missing required Node Input: {self._name}", code=WorkflowErrorCode.INVALID_INPUTS)
|
44
44
|
|
45
|
+
def __eq__(self, other: object) -> bool:
|
46
|
+
if not isinstance(other, type(self)):
|
47
|
+
return False
|
48
|
+
|
49
|
+
# Check equality of the name
|
50
|
+
base_equal = super().__eq__(other)
|
51
|
+
if not base_equal:
|
52
|
+
return False
|
53
|
+
|
54
|
+
return self._inputs_class == other._inputs_class
|
55
|
+
|
56
|
+
def __hash__(self) -> int:
|
57
|
+
return hash((self._name, self._inputs_class))
|
58
|
+
|
45
59
|
@classmethod
|
46
60
|
def __get_pydantic_core_schema__(
|
47
61
|
cls, source_type: Type[Any], handler: GetCoreSchemaHandler
|
vellum/workflows/state/base.py
CHANGED
@@ -201,6 +201,7 @@ class StateMeta(UniversalBaseModel):
|
|
201
201
|
|
202
202
|
def add_snapshot_callback(self, callback: Callable[[], None]) -> None:
|
203
203
|
self.node_outputs = _make_snapshottable(self.node_outputs, callback)
|
204
|
+
self.external_inputs = _make_snapshottable(self.external_inputs, callback)
|
204
205
|
self.__snapshot_callback__ = callback
|
205
206
|
|
206
207
|
def __setattr__(self, name: str, value: Any) -> None:
|
@@ -231,7 +232,13 @@ class StateMeta(UniversalBaseModel):
|
|
231
232
|
for descriptor, value in self.node_outputs.items()
|
232
233
|
}
|
233
234
|
|
235
|
+
new_external_inputs = {
|
236
|
+
descriptor: value if isinstance(value, Queue) else deepcopy(value, memo)
|
237
|
+
for descriptor, value in self.external_inputs.items()
|
238
|
+
}
|
239
|
+
|
234
240
|
memo[id(self.node_outputs)] = new_node_outputs
|
241
|
+
memo[id(self.external_inputs)] = new_external_inputs
|
235
242
|
memo[id(self.__snapshot_callback__)] = None
|
236
243
|
|
237
244
|
return super().__deepcopy__(memo)
|
@@ -64,6 +64,22 @@ def test_state_snapshot__nested_dictionary_edit():
|
|
64
64
|
assert snapshot_count[id(state)] == 1
|
65
65
|
|
66
66
|
|
67
|
+
def test_state_snapshot__external_input_edit():
|
68
|
+
# GIVEN an initial state instance
|
69
|
+
state = MockState(foo="bar")
|
70
|
+
assert snapshot_count[id(state)] == 0
|
71
|
+
|
72
|
+
# WHEN we add an external input to state
|
73
|
+
class MockExternalInputs(BaseNode.ExternalInputs):
|
74
|
+
message: str
|
75
|
+
|
76
|
+
# WHEN we edit external inputs dictionary
|
77
|
+
state.meta.external_inputs[MockExternalInputs.message] = "hello"
|
78
|
+
|
79
|
+
# THEN the snapshot is emitted
|
80
|
+
assert snapshot_count[id(state)] == 1
|
81
|
+
|
82
|
+
|
67
83
|
def test_state_deepcopy():
|
68
84
|
# GIVEN an initial state instance
|
69
85
|
state = MockState(foo="bar")
|
@@ -116,6 +132,32 @@ def test_state_json_serialization__with_node_output_updates():
|
|
116
132
|
assert json_state["meta"]["node_outputs"] == {"MockNode.Outputs.baz": "hello"}
|
117
133
|
|
118
134
|
|
135
|
+
def test_state_deepcopy__with_external_input_updates():
|
136
|
+
# GIVEN an initial state instance
|
137
|
+
state = MockState(foo="bar")
|
138
|
+
|
139
|
+
# AND we add an external input to state
|
140
|
+
class MockExternalInputs(BaseNode.ExternalInputs):
|
141
|
+
message: str
|
142
|
+
|
143
|
+
state.meta.external_inputs[MockExternalInputs.message] = "hello"
|
144
|
+
|
145
|
+
# AND we deepcopy the state
|
146
|
+
deepcopied_state = deepcopy(state)
|
147
|
+
|
148
|
+
# AND we update the original state
|
149
|
+
state.meta.external_inputs[MockExternalInputs.message] = "world"
|
150
|
+
|
151
|
+
# THEN the copied state is not updated
|
152
|
+
assert deepcopied_state.meta.external_inputs[MockExternalInputs.message] == "hello"
|
153
|
+
|
154
|
+
# AND the original state has had the correct number of snapshots
|
155
|
+
assert snapshot_count[id(state)] == 2
|
156
|
+
|
157
|
+
# AND the copied state has had the correct number of snapshots
|
158
|
+
assert snapshot_count[id(deepcopied_state)] == 0
|
159
|
+
|
160
|
+
|
119
161
|
def test_state_json_serialization__with_queue():
|
120
162
|
# GIVEN an initial state instance
|
121
163
|
state = MockState(foo="bar")
|
@@ -2,33 +2,33 @@ vellum_cli/CONTRIBUTING.md,sha256=FtDC7BGxSeMnwCXAUssFsAIElXtmJE-O5Z7BpolcgvI,29
|
|
2
2
|
vellum_cli/README.md,sha256=2NudRoLzWxNKqnuVy1JuQ7DerIaxWGYkrH8kMd-asIE,90
|
3
3
|
vellum_cli/__init__.py,sha256=uEn2Nlt2Z0kBc79NcO4-rgOIE7H9nsMEEjWF6MLDlPo,10591
|
4
4
|
vellum_cli/aliased_group.py,sha256=ugW498j0yv4ALJ8vS9MsO7ctDW7Jlir9j6nE_uHAP8c,3363
|
5
|
-
vellum_cli/config.py,sha256=
|
5
|
+
vellum_cli/config.py,sha256=Bsb3mnvKvv3oOTcCuxpgC7lWPMqt6eJhgRA6VEE-vL4,9266
|
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
|
-
vellum_cli/pull.py,sha256=
|
10
|
-
vellum_cli/push.py,sha256=
|
9
|
+
vellum_cli/pull.py,sha256=7yvg4oBOgsbBEsgXtCpYlNR4AOR8hPICamY-4HI-3kM,9031
|
10
|
+
vellum_cli/push.py,sha256=qQCI_cHvVjeDGA8FLYmSN7UE_wIJQnUXX_5cGsm9OTs,9076
|
11
11
|
vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
12
|
vellum_cli/tests/conftest.py,sha256=AFYZryKA2qnUuCPBxBKmHLFoPiE0WhBFFej9tNwSHdc,1526
|
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
|
-
vellum_cli/tests/test_pull.py,sha256=
|
17
|
-
vellum_cli/tests/test_push.py,sha256=
|
16
|
+
vellum_cli/tests/test_pull.py,sha256=JURmgGs5lSnpzefSx4K13eF2swv7O8OF86-4df81Zjo,25241
|
17
|
+
vellum_cli/tests/test_push.py,sha256=kcM8jp6vTRBwfk6cAC_tHa4Eliuy_zZ-X1DfIpSEIW0,18299
|
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
|
21
21
|
vellum_ee/workflows/display/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
22
|
vellum_ee/workflows/display/base.py,sha256=3ZFUYRNKL24fBqXhKpa_Dq2W1a-a86J20dmJYA3H2eY,1755
|
23
23
|
vellum_ee/workflows/display/nodes/__init__.py,sha256=5XOcZJXYUgaLS55QgRJzyQ_W1tpeprjnYAeYVezqoGw,160
|
24
|
-
vellum_ee/workflows/display/nodes/base_node_display.py,sha256=
|
24
|
+
vellum_ee/workflows/display/nodes/base_node_display.py,sha256=ErIK_1DYax0LlFX4AvV1oua8I7JlpXNncjGNadVe-bo,15801
|
25
25
|
vellum_ee/workflows/display/nodes/base_node_vellum_display.py,sha256=pLO0dORfRu--Ne9NgoyFT_CNjfpr5fGCsgbsMkUF5GM,2845
|
26
|
-
vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=
|
26
|
+
vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=0S6ksPp53WXWh1RQVH71nj2bkCWBj4ZaFYhTxW3N2F4,1230
|
27
27
|
vellum_ee/workflows/display/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
28
|
vellum_ee/workflows/display/nodes/tests/test_base_node_display.py,sha256=QqR3Ly0RNrXwOeLdW5nERDFt0gRPf76n1bPES6o5UN4,1093
|
29
29
|
vellum_ee/workflows/display/nodes/types.py,sha256=St1BB6no528OyELGiyRabWao0GGw6mLhstQAvEACbGk,247
|
30
30
|
vellum_ee/workflows/display/nodes/utils.py,sha256=sloya5TpXsnot1HURc9L51INwflRqUzHxRVnCS9Cd-4,973
|
31
|
-
vellum_ee/workflows/display/nodes/vellum/__init__.py,sha256=
|
31
|
+
vellum_ee/workflows/display/nodes/vellum/__init__.py,sha256=VHx6wSs9wuuiFlZpSQSd3mhECz4SUy2wEBuTSv--_As,1578
|
32
32
|
vellum_ee/workflows/display/nodes/vellum/api_node.py,sha256=hoV-cUtS6H9kmRQXHd2py95GRWI_dAnnaPwvlNBkDOQ,8571
|
33
33
|
vellum_ee/workflows/display/nodes/vellum/code_execution_node.py,sha256=z00Z3L0d4PsUQo4S8FRDTtOFLtjdi17TJbatNVF4nM8,4288
|
34
34
|
vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=ybLIa4uclqVIy3VAQvI1ivg2tnK5Ug_1R5a69DFqL7E,11104
|
@@ -41,6 +41,7 @@ vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=VlO3UwkspCOdDQ-h3v8k
|
|
41
41
|
vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=HkNMgdQELiON42jdO-xDLmqrEKdGx1RVqrz2DXNTLS8,3239
|
42
42
|
vellum_ee/workflows/display/nodes/vellum/note_node.py,sha256=TMb8txILu2uWjzoxaghjgjlzeBAgzn4vkP_8zSh2qoE,1151
|
43
43
|
vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py,sha256=LFjLUrH6sJ4czPnExdRqFr0PB_yKBMLXLvK5GAzIAgc,3273
|
44
|
+
vellum_ee/workflows/display/nodes/vellum/retry_node.py,sha256=i0XGbKecLiHtf7mBf2rbqldPgLcs1TitIphzcHRIvkA,341
|
44
45
|
vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=TxcAGZDl_hvJ7Y1hUi9YVEVrj9Ie0hKkASdpfRL4_cs,9227
|
45
46
|
vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py,sha256=lfevlHpGEX14dEDym6qmnkw3nvzQPTB1_D2ch12B_Rk,2701
|
46
47
|
vellum_ee/workflows/display/nodes/vellum/templating_node.py,sha256=JVIMPR3WpveOCWZubHKZkE04mavnTdb_9QY_r3XliRg,3424
|
@@ -55,13 +56,13 @@ vellum_ee/workflows/display/tests/test_vellum_workflow_display.py,sha256=h4bE187
|
|
55
56
|
vellum_ee/workflows/display/tests/workflow_serialization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
57
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
58
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py,sha256=EenmEdBtHUFQ0OS-kE7Vboax3JnDdj-K4Qixt5oR0Po,2253
|
58
|
-
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py,sha256=
|
59
|
+
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py,sha256=KYdohS5pRgHM0DcUaK0tHa40f0gSvDKi2K5On0zNEU8,8305
|
59
60
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py,sha256=yPXhdZxEDunNl5LL5Obb0jeO34djt7F-GiaTJhp_fmo,16742
|
60
61
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py,sha256=-12ZkZb3f5gyoNASV2yeQtMo5HmNsVEo8nXwL6IC-I8,6261
|
61
62
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py,sha256=6th6kCwzql6lddjkTQx4Jbvvs4ChqtJwctW-B4QuBhI,37352
|
62
63
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py,sha256=EbVgg_3_ipTt3MOop4RARX0fmNjwqZtkhIXzx9nGw7Y,4487
|
63
64
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py,sha256=bXZWxOKAVjZlbP3iLHPHGA4aPs0EguKlQqmYPNGv3cU,16391
|
64
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py,sha256=
|
65
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py,sha256=s2mBoL5Vvpoc-rcWcSGQjLp4yzVVwFmkTbS3--ErzCI,29486
|
65
66
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py,sha256=n3F_Eyru0DYOszBH4jplz7Mzt2FfBNxGlCkTFqvrX-M,48399
|
66
67
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py,sha256=8LhQgW0uzVOhzz0AwdM-EYugVO-0mGWglxWo_lON4D8,6079
|
67
68
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py,sha256=yWDykoHUjuiVYdevcJxWmYDDmbIszpHKYBu19vqR-I8,5746
|
@@ -112,7 +113,7 @@ vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
|
|
112
113
|
vellum/client/__init__.py,sha256=8nZt88C9SVwWanjLbIQMU3rzb32h5UZfFMBx3VPHB50,111887
|
113
114
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
114
115
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
115
|
-
vellum/client/core/client_wrapper.py,sha256=
|
116
|
+
vellum/client/core/client_wrapper.py,sha256=rnVChhyob3hO3iXrfL4gsCAYGAOdglXQdXoLL07FKLg,1869
|
116
117
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
117
118
|
vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
|
118
119
|
vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
|
@@ -168,7 +169,7 @@ vellum/client/resources/workflow_deployments/types/workflow_deployments_list_req
|
|
168
169
|
vellum/client/resources/workflow_sandboxes/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
169
170
|
vellum/client/resources/workflow_sandboxes/client.py,sha256=3wVQxkjrJ5bIS8fB5FpKXCP2dX38299ghWrJ8YmXxwQ,7435
|
170
171
|
vellum/client/resources/workflows/__init__.py,sha256=Z4xi8Nxd9U4t35FQSepTt1p-ns0X1xtdNs168kUcuBk,153
|
171
|
-
vellum/client/resources/workflows/client.py,sha256=
|
172
|
+
vellum/client/resources/workflows/client.py,sha256=hM7FDn05XHhQk599ti8CI4moIg0RVoEFil3Wp9v9UZk,11215
|
172
173
|
vellum/client/resources/workflows/types/__init__.py,sha256=-uFca4ypncAOvfsg6sjD-5C9zWdA5qNvU6m675GphVg,177
|
173
174
|
vellum/client/resources/workflows/types/workflows_pull_request_format.py,sha256=dOWE_jnDnniIJLoeseeCms23aklghyBkoPmBFzcqqZk,165
|
174
175
|
vellum/client/resources/workspace_secrets/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
|
@@ -1322,11 +1323,11 @@ vellum/workflows/nodes/core/map_node/node.py,sha256=bjCVMAzkqJUvaLWVBObjskcutwLG
|
|
1322
1323
|
vellum/workflows/nodes/core/map_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1323
1324
|
vellum/workflows/nodes/core/map_node/tests/test_node.py,sha256=P7ImQyeLcK-aEJUYCX1gPQyuOxdxnSPpI3mNPpKQ62Y,1919
|
1324
1325
|
vellum/workflows/nodes/core/retry_node/__init__.py,sha256=lN2bIy5a3Uzhs_FYCrooADyYU6ZGShtvLKFWpelwPvo,60
|
1325
|
-
vellum/workflows/nodes/core/retry_node/node.py,sha256=
|
1326
|
+
vellum/workflows/nodes/core/retry_node/node.py,sha256=WD96o-eOj3dwEEe2nqxwBbmLTIyPRYB3Lk4T6XHRX74,4214
|
1326
1327
|
vellum/workflows/nodes/core/retry_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1327
1328
|
vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=RM_OHwxrHwyxvlQQBJPqVBxpedFuWQ9h2-Xa3kP75sc,4399
|
1328
1329
|
vellum/workflows/nodes/core/templating_node/__init__.py,sha256=GmyuYo81_A1_Bz6id69ozVFS6FKiuDsZTiA3I6MaL2U,70
|
1329
|
-
vellum/workflows/nodes/core/templating_node/node.py,sha256=
|
1330
|
+
vellum/workflows/nodes/core/templating_node/node.py,sha256=zCYhq88qLTvoC9LetVrD9sLXkwHZsaWekxMhru_nV70,3752
|
1330
1331
|
vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=5iZWQWdJKDHMXBY8bhpb-Dpy9FTfW1HXxGUTivykZAA,4621
|
1331
1332
|
vellum/workflows/nodes/core/try_node/__init__.py,sha256=JVD4DrldTIqFQQFrubs9KtWCCc0YCAc7Fzol5ZWIWeM,56
|
1332
1333
|
vellum/workflows/nodes/core/try_node/node.py,sha256=_lTmSYCiz7lktaxpNWUCglNi8_5Sfy8Rpiov5SeKVMw,3920
|
@@ -1350,12 +1351,12 @@ vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMD
|
|
1350
1351
|
vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
|
1351
1352
|
vellum/workflows/nodes/displayable/bases/utils.py,sha256=ckMUenSsNkiYmSw6FmjSMHYaCk8Y8_sUjL6lkFFEqts,5412
|
1352
1353
|
vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
|
1353
|
-
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=
|
1354
|
+
vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=KZ5d3_mdpsrPF_ScmEqSfBhfup421RscO9hNiGa52T4,9068
|
1354
1355
|
vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1355
1356
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1356
1357
|
vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
|
1357
|
-
vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=
|
1358
|
-
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=
|
1358
|
+
vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=ueVDw0GTSGzBZMFLs0NTir_0AE-pUrAYvpgg3Stex7Q,12350
|
1359
|
+
vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=zRYM7B2t7355LzaAn6LkIn4tM5K7eQ0Kvje4NO6Kq30,3443
|
1359
1360
|
vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
|
1360
1361
|
vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=Qjfl33gZ3JEgxBA1EgzSUebboGvsARthIxxcQyvx5Gg,1152
|
1361
1362
|
vellum/workflows/nodes/displayable/final_output_node/__init__.py,sha256=G7VXM4OWpubvSJtVkGmMNeqgb9GkM7qZT838eL18XU4,72
|
@@ -1386,9 +1387,9 @@ vellum/workflows/nodes/experimental/README.md,sha256=eF6DfIL8t-HbF9-mcofOMymKrra
|
|
1386
1387
|
vellum/workflows/nodes/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1387
1388
|
vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py,sha256=lsyD9laR9p7kx5-BXGH2gUTM242UhKy8SMV0SR6S2iE,90
|
1388
1389
|
vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py,sha256=1EGeiaT-Zoo6pttQFKKBcdf3dmhAbjKGaErYD5FFwlc,10185
|
1389
|
-
vellum/workflows/nodes/utils.py,sha256=
|
1390
|
+
vellum/workflows/nodes/utils.py,sha256=T7krLipDSI007JkkH2zsfyQ-tfOBH4hyFzQ0YJKYpuw,4025
|
1390
1391
|
vellum/workflows/outputs/__init__.py,sha256=AyZ4pRh_ACQIGvkf0byJO46EDnSix1ZCAXfvh-ms1QE,94
|
1391
|
-
vellum/workflows/outputs/base.py,sha256=
|
1392
|
+
vellum/workflows/outputs/base.py,sha256=Wu48tqyQoxpflBUcwzKeZjSVp1LPKrBwuIvnx__9H90,8459
|
1392
1393
|
vellum/workflows/ports/__init__.py,sha256=bZuMt-R7z5bKwpu4uPW7LlJeePOQWmCcDSXe5frUY5g,101
|
1393
1394
|
vellum/workflows/ports/node_ports.py,sha256=g4A-8iUAvEJSkaWppbvzAR8XU02R9U-qLN4rP2Kq4Aw,2743
|
1394
1395
|
vellum/workflows/ports/port.py,sha256=rc3GB7dDQCUs0IbY08a92-31YzJHQgBeww13brSJ2Js,3172
|
@@ -1397,7 +1398,7 @@ vellum/workflows/references/__init__.py,sha256=glHFC1VfXmcbNvH5VzFbkT03d8_D7MMcv
|
|
1397
1398
|
vellum/workflows/references/constant.py,sha256=6yUT4q1sMj1hkI_tzzQ9AYcmeeDYFUNCqUq_W2DN0S8,540
|
1398
1399
|
vellum/workflows/references/environment_variable.py,sha256=-gfOcdYwVp9ztSUYz6h2WI2Cg95zqxq5hhFf3Yr7aQg,791
|
1399
1400
|
vellum/workflows/references/execution_count.py,sha256=JILHqt8ELdc9ct-WsVCA5X-rKiP1rmJODw-XTf4kpHI,722
|
1400
|
-
vellum/workflows/references/external_input.py,sha256=
|
1401
|
+
vellum/workflows/references/external_input.py,sha256=WyBC6uMDu77431YVSU_WvTt-nGLC_bW65tIsplUJXa4,2056
|
1401
1402
|
vellum/workflows/references/input.py,sha256=3INu-TLTi4dziWmva6LO3WvgDlPzsjayUx61cVvqLJA,325
|
1402
1403
|
vellum/workflows/references/lazy.py,sha256=SXwZUCTzUR-R2-uK0XHALtvp1x84l-QkNY-Ds6KynYA,1932
|
1403
1404
|
vellum/workflows/references/node.py,sha256=LP854wDVs-9I_aZ7-nkbwXqL2H7W2_3LED2e9FixNS8,1418
|
@@ -1411,12 +1412,12 @@ vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8v
|
|
1411
1412
|
vellum/workflows/runner/runner.py,sha256=LvP1UwLmwV1nCZYYrsiwtCzay73voMp1TDRVVBrlMj8,29196
|
1412
1413
|
vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2235
|
1413
1414
|
vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
|
1414
|
-
vellum/workflows/state/base.py,sha256=
|
1415
|
+
vellum/workflows/state/base.py,sha256=IIl76sJtn0GfbFWBqMnpGuvtZyVyQMEXv0QKDfLy8Wg,14763
|
1415
1416
|
vellum/workflows/state/context.py,sha256=_NeGQpYo8yNuh0Tfh3OvcB_bG_-GC8b3ZLLl83Pf8-I,1279
|
1416
1417
|
vellum/workflows/state/encoder.py,sha256=WdUidpOaBDx5lilJl8V8McFDHQYiCLCJR9dmktdzdZY,1836
|
1417
1418
|
vellum/workflows/state/store.py,sha256=VYGBQgN1bpd1as5eGiouV_7scg8QsRs4_1aqZAGIsRQ,793
|
1418
1419
|
vellum/workflows/state/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1419
|
-
vellum/workflows/state/tests/test_state.py,sha256=
|
1420
|
+
vellum/workflows/state/tests/test_state.py,sha256=ucy7U8886J3CinIKQhOqv4dvkKWQk0fyK3JjTSiKZC4,5266
|
1420
1421
|
vellum/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1421
1422
|
vellum/workflows/tests/test_sandbox.py,sha256=JKwaluI-lODQo7Ek9sjDstjL_WTdSqUlVik6ZVTfVOA,1826
|
1422
1423
|
vellum/workflows/types/__init__.py,sha256=KxUTMBGzuRCfiMqzzsykOeVvrrkaZmTTo1a7SLu8gRM,68
|
@@ -1441,8 +1442,8 @@ vellum/workflows/vellum_client.py,sha256=ODrq_TSl-drX2aezXegf7pizpWDVJuTXH-j6528
|
|
1441
1442
|
vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
|
1442
1443
|
vellum/workflows/workflows/base.py,sha256=k0kUWWko4fHyCqLSU_1cBK_pXZpl9MXekWiG-bdOAo0,18353
|
1443
1444
|
vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnadGsrSZGa7t7LpJA,2008
|
1444
|
-
vellum_ai-0.13.
|
1445
|
-
vellum_ai-0.13.
|
1446
|
-
vellum_ai-0.13.
|
1447
|
-
vellum_ai-0.13.
|
1448
|
-
vellum_ai-0.13.
|
1445
|
+
vellum_ai-0.13.19.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1446
|
+
vellum_ai-0.13.19.dist-info/METADATA,sha256=NzphP-OKn-7lL7hjSD1e1eT709mTax682Cs85AT0O_4,5335
|
1447
|
+
vellum_ai-0.13.19.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1448
|
+
vellum_ai-0.13.19.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1449
|
+
vellum_ai-0.13.19.dist-info/RECORD,,
|
vellum_cli/config.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
from collections import defaultdict
|
1
2
|
from dataclasses import field
|
2
3
|
import json
|
3
4
|
import os
|
@@ -88,6 +89,50 @@ class WorkflowConfig(UniversalBaseModel):
|
|
88
89
|
)
|
89
90
|
|
90
91
|
|
92
|
+
def merge_workflows_by_sandbox_id(
|
93
|
+
workflows: List[WorkflowConfig], other_workflows: List[WorkflowConfig]
|
94
|
+
) -> List[WorkflowConfig]:
|
95
|
+
merged_workflows: List[WorkflowConfig] = []
|
96
|
+
for self_workflow in workflows:
|
97
|
+
if self_workflow.workflow_sandbox_id is None:
|
98
|
+
# If the user defines a workflow in the pyproject.toml without a sandbox_id,
|
99
|
+
# we merge the workflow with one of the ones in the lockfile.
|
100
|
+
other_workflow = next(
|
101
|
+
(
|
102
|
+
other_workflow
|
103
|
+
for other_workflow in other_workflows
|
104
|
+
if self_workflow.workspace == other_workflow.workspace
|
105
|
+
),
|
106
|
+
None,
|
107
|
+
)
|
108
|
+
if other_workflow is not None:
|
109
|
+
merged_workflows.append(self_workflow.merge(other_workflow))
|
110
|
+
else:
|
111
|
+
merged_workflows.append(self_workflow)
|
112
|
+
else:
|
113
|
+
# If the user defines a workflow in the pyproject.toml with a sandbox_id,
|
114
|
+
# we merge the workflow with one of the ones in the lockfile with the same sandbox_id.
|
115
|
+
other_workflow = next(
|
116
|
+
(
|
117
|
+
other_workflow
|
118
|
+
for other_workflow in other_workflows
|
119
|
+
if self_workflow.workflow_sandbox_id == other_workflow.workflow_sandbox_id
|
120
|
+
),
|
121
|
+
None,
|
122
|
+
)
|
123
|
+
if other_workflow is not None:
|
124
|
+
merged_workflows.append(self_workflow.merge(other_workflow))
|
125
|
+
else:
|
126
|
+
merged_workflows.append(self_workflow)
|
127
|
+
|
128
|
+
workflow_sandbox_ids_so_far = {workflow.workflow_sandbox_id for workflow in merged_workflows}
|
129
|
+
for other_workflow in other_workflows:
|
130
|
+
if other_workflow.workflow_sandbox_id not in workflow_sandbox_ids_so_far:
|
131
|
+
merged_workflows.append(other_workflow)
|
132
|
+
|
133
|
+
return merged_workflows
|
134
|
+
|
135
|
+
|
91
136
|
class VellumCliConfig(UniversalBaseModel):
|
92
137
|
version: Literal["1.0"] = "1.0"
|
93
138
|
workflows: List[WorkflowConfig] = field(default_factory=list)
|
@@ -97,24 +142,31 @@ class VellumCliConfig(UniversalBaseModel):
|
|
97
142
|
lockfile_path = os.path.join(os.getcwd(), LOCKFILE_PATH)
|
98
143
|
with open(lockfile_path, "w") as f:
|
99
144
|
json.dump(self.model_dump(), f, indent=2, cls=DefaultStateEncoder)
|
145
|
+
# Makes sure the file ends with a newline, consistent with most autoformatters
|
146
|
+
f.write("\n")
|
100
147
|
|
101
148
|
def merge(self, other: "VellumCliConfig") -> "VellumCliConfig":
|
102
149
|
if other.version != self.version:
|
103
150
|
raise ValueError("Lockfile version mismatch")
|
104
151
|
|
105
|
-
|
106
|
-
|
107
|
-
all_modules = sorted(set(
|
152
|
+
self_workflows_by_module = self.get_workflows_by_module_mapping()
|
153
|
+
other_workflows_by_module = other.get_workflows_by_module_mapping()
|
154
|
+
all_modules = sorted(set(self_workflows_by_module.keys()).union(set(other_workflows_by_module.keys())))
|
108
155
|
merged_workflows = []
|
109
156
|
for module in all_modules:
|
110
|
-
|
111
|
-
|
112
|
-
if
|
113
|
-
merged_workflows.
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
157
|
+
self_workflows = self_workflows_by_module.get(module)
|
158
|
+
other_workflows = other_workflows_by_module.get(module)
|
159
|
+
if self_workflows and other_workflows:
|
160
|
+
merged_workflows.extend(
|
161
|
+
merge_workflows_by_sandbox_id(
|
162
|
+
self_workflows,
|
163
|
+
other_workflows,
|
164
|
+
)
|
165
|
+
)
|
166
|
+
elif self_workflows:
|
167
|
+
merged_workflows.extend(self_workflows)
|
168
|
+
elif other_workflows:
|
169
|
+
merged_workflows.extend(other_workflows)
|
118
170
|
|
119
171
|
self_workspace_by_name = {workspace.name: workspace for workspace in self.workspaces}
|
120
172
|
other_workspace_by_name = {workspace.name: workspace for workspace in other.workspaces}
|
@@ -132,6 +184,12 @@ class VellumCliConfig(UniversalBaseModel):
|
|
132
184
|
|
133
185
|
return VellumCliConfig(workflows=merged_workflows, workspaces=merged_workspaces, version=self.version)
|
134
186
|
|
187
|
+
def get_workflows_by_module_mapping(self) -> Dict[str, List[WorkflowConfig]]:
|
188
|
+
workflows_by_module = defaultdict(list)
|
189
|
+
for workflow in self.workflows:
|
190
|
+
workflows_by_module[workflow.module].append(workflow)
|
191
|
+
return workflows_by_module
|
192
|
+
|
135
193
|
|
136
194
|
def load_vellum_cli_config(root_dir: Optional[str] = None) -> VellumCliConfig:
|
137
195
|
if root_dir is None:
|
vellum_cli/pull.py
CHANGED
@@ -31,6 +31,16 @@ class WorkflowConfigResolutionResult(UniversalBaseModel):
|
|
31
31
|
pk: Optional[str] = None
|
32
32
|
|
33
33
|
|
34
|
+
class RunnerConfig(UniversalBaseModel):
|
35
|
+
container_image_name: Optional[str] = None
|
36
|
+
container_image_tag: Optional[str] = None
|
37
|
+
|
38
|
+
|
39
|
+
class PullContentsMetadata(UniversalBaseModel):
|
40
|
+
label: Optional[str] = None
|
41
|
+
runner_config: Optional[RunnerConfig] = None
|
42
|
+
|
43
|
+
|
34
44
|
def _resolve_workflow_config(
|
35
45
|
config: VellumCliConfig,
|
36
46
|
module: Optional[str] = None,
|
@@ -42,14 +52,33 @@ def _resolve_workflow_config(
|
|
42
52
|
|
43
53
|
if module:
|
44
54
|
workflow_config = next((w for w in config.workflows if w.module == module), None)
|
55
|
+
if not workflow_config and workflow_sandbox_id:
|
56
|
+
workflow_config = WorkflowConfig(
|
57
|
+
workflow_sandbox_id=workflow_sandbox_id,
|
58
|
+
module=module,
|
59
|
+
)
|
60
|
+
config.workflows.append(workflow_config)
|
61
|
+
return WorkflowConfigResolutionResult(
|
62
|
+
workflow_config=workflow_config,
|
63
|
+
pk=workflow_sandbox_id,
|
64
|
+
)
|
65
|
+
|
45
66
|
return WorkflowConfigResolutionResult(
|
46
67
|
workflow_config=workflow_config,
|
47
68
|
pk=workflow_config.workflow_sandbox_id if workflow_config else None,
|
48
69
|
)
|
49
70
|
elif workflow_sandbox_id:
|
71
|
+
workflow_config = next((w for w in config.workflows if w.workflow_sandbox_id == workflow_sandbox_id), None)
|
72
|
+
if workflow_config:
|
73
|
+
return WorkflowConfigResolutionResult(
|
74
|
+
workflow_config=workflow_config,
|
75
|
+
pk=workflow_sandbox_id,
|
76
|
+
)
|
77
|
+
|
78
|
+
# We use an empty module name to indicate that we want to backfill it once we have the Workflow Sandbox Label
|
50
79
|
workflow_config = WorkflowConfig(
|
51
80
|
workflow_sandbox_id=workflow_sandbox_id,
|
52
|
-
module=
|
81
|
+
module="",
|
53
82
|
)
|
54
83
|
config.workflows.append(workflow_config)
|
55
84
|
return WorkflowConfigResolutionResult(
|
@@ -98,7 +127,6 @@ def pull_command(
|
|
98
127
|
workflow_sandbox_id=workflow_sandbox_id,
|
99
128
|
workflow_deployment=workflow_deployment,
|
100
129
|
)
|
101
|
-
save_lock_file = not module
|
102
130
|
|
103
131
|
workflow_config = workflow_config_result.workflow_config
|
104
132
|
if not workflow_config:
|
@@ -108,7 +136,11 @@ def pull_command(
|
|
108
136
|
if not pk:
|
109
137
|
raise ValueError("No workflow sandbox ID found in project to pull from.")
|
110
138
|
|
111
|
-
|
139
|
+
if workflow_config.module:
|
140
|
+
logger.info(f"Pulling workflow into {workflow_config.module}...")
|
141
|
+
else:
|
142
|
+
logger.info(f"Pulling workflow from {pk}...")
|
143
|
+
|
112
144
|
client = create_vellum_client()
|
113
145
|
query_parameters = {}
|
114
146
|
|
@@ -129,11 +161,30 @@ def pull_command(
|
|
129
161
|
zip_bytes = b"".join(response)
|
130
162
|
zip_buffer = io.BytesIO(zip_bytes)
|
131
163
|
|
132
|
-
target_dir = os.path.join(os.getcwd(), *workflow_config.module.split("."))
|
133
164
|
error_content = ""
|
134
|
-
metadata_json: Optional[dict] = None
|
135
165
|
|
136
166
|
with zipfile.ZipFile(zip_buffer) as zip_file:
|
167
|
+
if METADATA_FILE_NAME in zip_file.namelist():
|
168
|
+
metadata_json: Optional[dict] = None
|
169
|
+
with zip_file.open(METADATA_FILE_NAME) as source:
|
170
|
+
metadata_json = json.load(source)
|
171
|
+
|
172
|
+
pull_contents_metadata = PullContentsMetadata.model_validate(metadata_json)
|
173
|
+
|
174
|
+
if pull_contents_metadata.runner_config:
|
175
|
+
workflow_config.container_image_name = pull_contents_metadata.runner_config.container_image_name
|
176
|
+
workflow_config.container_image_tag = pull_contents_metadata.runner_config.container_image_tag
|
177
|
+
if workflow_config.container_image_name and not workflow_config.container_image_tag:
|
178
|
+
workflow_config.container_image_tag = "latest"
|
179
|
+
|
180
|
+
if not workflow_config.module and pull_contents_metadata.label:
|
181
|
+
workflow_config.module = snake_case(pull_contents_metadata.label)
|
182
|
+
|
183
|
+
if not workflow_config.module:
|
184
|
+
raise ValueError(f"Failed to resolve a module name for Workflow {pk}")
|
185
|
+
|
186
|
+
target_dir = os.path.join(os.getcwd(), *workflow_config.module.split("."))
|
187
|
+
|
137
188
|
# Delete files in target_dir that aren't in the zip file
|
138
189
|
if os.path.exists(target_dir):
|
139
190
|
ignore_patterns = (
|
@@ -163,7 +214,6 @@ def pull_command(
|
|
163
214
|
error_content = content
|
164
215
|
continue
|
165
216
|
if file_name == METADATA_FILE_NAME:
|
166
|
-
metadata_json = json.loads(content)
|
167
217
|
continue
|
168
218
|
|
169
219
|
target_file = os.path.join(target_dir, file_name)
|
@@ -172,15 +222,6 @@ def pull_command(
|
|
172
222
|
logger.info(f"Writing to {target_file}...")
|
173
223
|
target.write(content)
|
174
224
|
|
175
|
-
if metadata_json:
|
176
|
-
runner_config = metadata_json.get("runner_config")
|
177
|
-
|
178
|
-
if runner_config:
|
179
|
-
workflow_config.container_image_name = runner_config.get("container_image_name")
|
180
|
-
workflow_config.container_image_tag = runner_config.get("container_image_tag")
|
181
|
-
if workflow_config.container_image_name and not workflow_config.container_image_tag:
|
182
|
-
workflow_config.container_image_tag = "latest"
|
183
|
-
|
184
225
|
if include_json:
|
185
226
|
logger.warning(
|
186
227
|
"""The pulled JSON representation of the Workflow should be used for debugging purposely only. \
|
@@ -190,16 +231,12 @@ Its schema should be considered unstable and subject to change at any time."""
|
|
190
231
|
if include_sandbox:
|
191
232
|
if not workflow_config.ignore:
|
192
233
|
workflow_config.ignore = "sandbox.py"
|
193
|
-
save_lock_file = True
|
194
234
|
elif isinstance(workflow_config.ignore, str) and "sandbox.py" != workflow_config.ignore:
|
195
235
|
workflow_config.ignore = [workflow_config.ignore, "sandbox.py"]
|
196
|
-
save_lock_file = True
|
197
236
|
elif isinstance(workflow_config.ignore, list) and "sandbox.py" not in workflow_config.ignore:
|
198
237
|
workflow_config.ignore.append("sandbox.py")
|
199
|
-
save_lock_file = True
|
200
238
|
|
201
|
-
|
202
|
-
config.save()
|
239
|
+
config.save()
|
203
240
|
|
204
241
|
if error_content:
|
205
242
|
logger.error(error_content)
|