vellum-ai 1.3.2__py3-none-any.whl → 1.3.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.
- vellum/client/core/client_wrapper.py +2 -2
- vellum/workflows/emitters/vellum_emitter.py +55 -9
- vellum/workflows/nodes/core/retry_node/tests/test_node.py +1 -2
- vellum/workflows/nodes/displayable/tool_calling_node/utils.py +6 -13
- vellum/workflows/state/tests/test_state.py +14 -0
- vellum/workflows/types/code_execution_node_wrappers.py +3 -0
- vellum/workflows/utils/vellum_variables.py +11 -2
- {vellum_ai-1.3.2.dist-info → vellum_ai-1.3.3.dist-info}/METADATA +1 -1
- {vellum_ai-1.3.2.dist-info → vellum_ai-1.3.3.dist-info}/RECORD +19 -17
- vellum_cli/__init__.py +21 -0
- vellum_cli/move.py +56 -0
- vellum_cli/tests/test_move.py +154 -0
- vellum_ee/workflows/display/base.py +1 -0
- vellum_ee/workflows/display/editor/types.py +1 -0
- vellum_ee/workflows/display/nodes/base_node_display.py +1 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +16 -5
- {vellum_ai-1.3.2.dist-info → vellum_ai-1.3.3.dist-info}/LICENSE +0 -0
- {vellum_ai-1.3.2.dist-info → vellum_ai-1.3.3.dist-info}/WHEEL +0 -0
- {vellum_ai-1.3.2.dist-info → vellum_ai-1.3.3.dist-info}/entry_points.txt +0 -0
@@ -27,10 +27,10 @@ class BaseClientWrapper:
|
|
27
27
|
|
28
28
|
def get_headers(self) -> typing.Dict[str, str]:
|
29
29
|
headers: typing.Dict[str, str] = {
|
30
|
-
"User-Agent": "vellum-ai/1.3.
|
30
|
+
"User-Agent": "vellum-ai/1.3.3",
|
31
31
|
"X-Fern-Language": "Python",
|
32
32
|
"X-Fern-SDK-Name": "vellum-ai",
|
33
|
-
"X-Fern-SDK-Version": "1.3.
|
33
|
+
"X-Fern-SDK-Version": "1.3.3",
|
34
34
|
**(self.get_custom_headers() or {}),
|
35
35
|
}
|
36
36
|
if self._api_version is not None:
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import logging
|
2
|
-
|
2
|
+
import threading
|
3
|
+
from typing import List, Optional
|
3
4
|
|
4
5
|
from vellum.core.request_options import RequestOptions
|
5
6
|
from vellum.workflows.emitters.base import BaseWorkflowEmitter
|
@@ -29,6 +30,7 @@ class VellumEmitter(BaseWorkflowEmitter):
|
|
29
30
|
*,
|
30
31
|
timeout: Optional[float] = 30.0,
|
31
32
|
max_retries: int = 3,
|
33
|
+
debounce_timeout: float = 0.1,
|
32
34
|
):
|
33
35
|
"""
|
34
36
|
Initialize the VellumEmitter.
|
@@ -36,14 +38,19 @@ class VellumEmitter(BaseWorkflowEmitter):
|
|
36
38
|
Args:
|
37
39
|
timeout: Request timeout in seconds.
|
38
40
|
max_retries: Maximum number of retry attempts for failed requests.
|
41
|
+
debounce_timeout: Time in seconds to wait before sending batched events.
|
39
42
|
"""
|
40
43
|
super().__init__()
|
41
44
|
self._timeout = timeout
|
42
45
|
self._max_retries = max_retries
|
46
|
+
self._debounce_timeout = debounce_timeout
|
47
|
+
self._event_queue: List[SDKWorkflowEvent] = []
|
48
|
+
self._queue_lock = threading.Lock()
|
49
|
+
self._debounce_timer: Optional[threading.Timer] = None
|
43
50
|
|
44
51
|
def emit_event(self, event: SDKWorkflowEvent) -> None:
|
45
52
|
"""
|
46
|
-
|
53
|
+
Queue a workflow event for batched emission to Vellum's infrastructure.
|
47
54
|
|
48
55
|
Args:
|
49
56
|
event: The workflow event to emit.
|
@@ -55,10 +62,45 @@ class VellumEmitter(BaseWorkflowEmitter):
|
|
55
62
|
return
|
56
63
|
|
57
64
|
try:
|
58
|
-
self.
|
65
|
+
with self._queue_lock:
|
66
|
+
self._event_queue.append(event)
|
59
67
|
|
68
|
+
if self._debounce_timer:
|
69
|
+
self._debounce_timer.cancel()
|
70
|
+
|
71
|
+
self._debounce_timer = threading.Timer(self._debounce_timeout, self._flush_events)
|
72
|
+
self._debounce_timer.start()
|
73
|
+
|
74
|
+
except Exception as e:
|
75
|
+
logger.exception(f"Failed to queue event {event.name}: {e}")
|
76
|
+
|
77
|
+
def _flush_events(self) -> None:
|
78
|
+
"""
|
79
|
+
Send all queued events as a batch to Vellum's infrastructure.
|
80
|
+
"""
|
81
|
+
with self._queue_lock:
|
82
|
+
if not self._event_queue:
|
83
|
+
return
|
84
|
+
|
85
|
+
events_to_send = self._event_queue.copy()
|
86
|
+
self._event_queue.clear()
|
87
|
+
self._debounce_timer = None
|
88
|
+
|
89
|
+
try:
|
90
|
+
self._send_events(events_to_send)
|
60
91
|
except Exception as e:
|
61
|
-
logger.exception(f"Failed to
|
92
|
+
logger.exception(f"Failed to send batched events: {e}")
|
93
|
+
|
94
|
+
def __del__(self) -> None:
|
95
|
+
"""
|
96
|
+
Cleanup: flush any pending events and cancel timer.
|
97
|
+
"""
|
98
|
+
try:
|
99
|
+
if self._debounce_timer:
|
100
|
+
self._debounce_timer.cancel()
|
101
|
+
self._flush_events()
|
102
|
+
except Exception:
|
103
|
+
pass
|
62
104
|
|
63
105
|
def snapshot_state(self, state: BaseState) -> None:
|
64
106
|
"""
|
@@ -69,23 +111,27 @@ class VellumEmitter(BaseWorkflowEmitter):
|
|
69
111
|
"""
|
70
112
|
pass
|
71
113
|
|
72
|
-
def
|
114
|
+
def _send_events(self, events: List[SDKWorkflowEvent]) -> None:
|
73
115
|
"""
|
74
|
-
Send
|
116
|
+
Send events to Vellum's events endpoint using client.events.create.
|
75
117
|
|
76
118
|
Args:
|
77
|
-
|
119
|
+
events: List of WorkflowEvent objects to send.
|
78
120
|
"""
|
79
121
|
if not self._context:
|
80
|
-
logger.warning("Cannot send
|
122
|
+
logger.warning("Cannot send events: No workflow context registered")
|
123
|
+
return
|
124
|
+
|
125
|
+
if not events:
|
81
126
|
return
|
82
127
|
|
83
128
|
client = self._context.vellum_client
|
84
129
|
request_options = RequestOptions(timeout_in_seconds=self._timeout, max_retries=self._max_retries)
|
130
|
+
|
85
131
|
client.events.create(
|
86
132
|
# The API accepts a ClientWorkflowEvent but our SDK emits an SDKWorkflowEvent. These shapes are
|
87
133
|
# meant to be identical, just with different helper methods. We may consolidate the two in the future.
|
88
134
|
# But for now, the type ignore allows us to avoid an additional Model -> json -> Model conversion.
|
89
|
-
request=
|
135
|
+
request=events, # type: ignore[arg-type]
|
90
136
|
request_options=request_options,
|
91
137
|
)
|
@@ -6,7 +6,6 @@ from vellum.workflows.inputs.base import BaseInputs
|
|
6
6
|
from vellum.workflows.nodes.bases import BaseNode
|
7
7
|
from vellum.workflows.nodes.core.retry_node.node import RetryNode
|
8
8
|
from vellum.workflows.outputs import BaseOutputs
|
9
|
-
from vellum.workflows.references.lazy import LazyReference
|
10
9
|
from vellum.workflows.state.base import BaseState, StateMeta
|
11
10
|
|
12
11
|
|
@@ -102,7 +101,7 @@ def test_retry_node__condition_arg_successfully_retries():
|
|
102
101
|
# AND a retry node that retries on a condition
|
103
102
|
@RetryNode.wrap(
|
104
103
|
max_attempts=5,
|
105
|
-
retry_on_condition=
|
104
|
+
retry_on_condition=State.count.less_than(3),
|
106
105
|
)
|
107
106
|
class TestNode(BaseNode[State]):
|
108
107
|
attempt_number = RetryNode.SubworkflowInputs.attempt_number
|
@@ -27,7 +27,6 @@ from vellum.workflows.nodes.displayable.subworkflow_deployment_node.node import
|
|
27
27
|
from vellum.workflows.nodes.displayable.tool_calling_node.state import ToolCallingState
|
28
28
|
from vellum.workflows.outputs.base import BaseOutput
|
29
29
|
from vellum.workflows.ports.port import Port
|
30
|
-
from vellum.workflows.references.lazy import LazyReference
|
31
30
|
from vellum.workflows.state import BaseState
|
32
31
|
from vellum.workflows.state.encoder import DefaultStateEncoder
|
33
32
|
from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior, Tool, ToolBase
|
@@ -421,19 +420,13 @@ def create_router_node(
|
|
421
420
|
# and if the function_name is changed, the port_condition will also change.
|
422
421
|
def create_port_condition(fn_name):
|
423
422
|
return Port.on_if(
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
tool_prompt_node.Outputs.results.length()
|
428
|
-
)
|
429
|
-
& tool_prompt_node.Outputs.results[ToolCallingState.current_prompt_output_index]["type"].equals(
|
430
|
-
"FUNCTION_CALL"
|
431
|
-
)
|
432
|
-
& tool_prompt_node.Outputs.results[ToolCallingState.current_prompt_output_index]["value"][
|
433
|
-
"name"
|
434
|
-
].equals(fn_name)
|
435
|
-
)
|
423
|
+
ToolCallingState.current_prompt_output_index.less_than(tool_prompt_node.Outputs.results.length())
|
424
|
+
& tool_prompt_node.Outputs.results[ToolCallingState.current_prompt_output_index]["type"].equals(
|
425
|
+
"FUNCTION_CALL"
|
436
426
|
)
|
427
|
+
& tool_prompt_node.Outputs.results[ToolCallingState.current_prompt_output_index]["value"][
|
428
|
+
"name"
|
429
|
+
].equals(fn_name)
|
437
430
|
)
|
438
431
|
|
439
432
|
for function in functions:
|
@@ -4,11 +4,13 @@ import json
|
|
4
4
|
from queue import Queue
|
5
5
|
from typing import Dict, List, cast
|
6
6
|
|
7
|
+
from vellum.workflows.constants import undefined
|
7
8
|
from vellum.workflows.nodes.bases import BaseNode
|
8
9
|
from vellum.workflows.outputs.base import BaseOutputs
|
9
10
|
from vellum.workflows.state.base import BaseState
|
10
11
|
from vellum.workflows.state.delta import SetStateDelta, StateDelta
|
11
12
|
from vellum.workflows.state.encoder import DefaultStateEncoder
|
13
|
+
from vellum.workflows.types.code_execution_node_wrappers import DictWrapper
|
12
14
|
|
13
15
|
|
14
16
|
@pytest.fixture()
|
@@ -229,3 +231,15 @@ def test_state_snapshot__deepcopy_fails__logs_error(mock_deepcopy, mock_logger):
|
|
229
231
|
|
230
232
|
# AND alert sentry once
|
231
233
|
assert mock_logger.exception.call_count == 1
|
234
|
+
|
235
|
+
|
236
|
+
def test_state_deepcopy_handles_undefined_values():
|
237
|
+
# GIVEN a state with undefined values in node outputs
|
238
|
+
state = MockState(foo="bar")
|
239
|
+
state.meta.node_outputs[MockNode.Outputs.baz] = DictWrapper({"foo": undefined})
|
240
|
+
|
241
|
+
# WHEN we deepcopy the state
|
242
|
+
deepcopied_state = deepcopy(state)
|
243
|
+
|
244
|
+
# THEN the undefined values are preserved
|
245
|
+
assert deepcopied_state.meta.node_outputs[MockNode.Outputs.baz] == {"foo": undefined}
|
@@ -72,6 +72,9 @@ class DictWrapper(dict):
|
|
72
72
|
# several values as VellumValue objects, we use the "value" key to return itself
|
73
73
|
return self
|
74
74
|
|
75
|
+
if attr.startswith("__") and attr.endswith("__"):
|
76
|
+
return super().__getattribute__(attr)
|
77
|
+
|
75
78
|
return undefined
|
76
79
|
|
77
80
|
item = super().__getitem__(attr)
|
@@ -22,6 +22,7 @@ from vellum import (
|
|
22
22
|
VellumVideo,
|
23
23
|
VellumVideoRequest,
|
24
24
|
)
|
25
|
+
from vellum.workflows.constants import undefined
|
25
26
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
26
27
|
from vellum.workflows.types.core import Json
|
27
28
|
|
@@ -29,8 +30,16 @@ from vellum.workflows.types.core import Json
|
|
29
30
|
def primitive_type_to_vellum_variable_type(type_: Union[Type, BaseDescriptor]) -> VellumVariableType:
|
30
31
|
"""Converts a python primitive to a VellumVariableType"""
|
31
32
|
if isinstance(type_, BaseDescriptor):
|
32
|
-
# Ignore None because those just make types optional
|
33
|
-
types = [
|
33
|
+
# Ignore None and undefined because those just make types optional
|
34
|
+
types = []
|
35
|
+
for t in type_.types:
|
36
|
+
if t is type(None):
|
37
|
+
continue
|
38
|
+
if t is undefined or t is type(undefined):
|
39
|
+
continue
|
40
|
+
if get_origin(t) is type and len(get_args(t)) == 1 and get_args(t)[0] is undefined:
|
41
|
+
continue
|
42
|
+
types.append(t)
|
34
43
|
|
35
44
|
# default to JSON for typevars where the types is empty tuple
|
36
45
|
if len(types) == 0:
|
@@ -1,11 +1,12 @@
|
|
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=CCTCiCvwxjFHXVSKhzUtZ3GE_h4HrbLEX_XC3qjPuAk,13618
|
4
4
|
vellum_cli/aliased_group.py,sha256=ugW498j0yv4ALJ8vS9MsO7ctDW7Jlir9j6nE_uHAP8c,3363
|
5
5
|
vellum_cli/config.py,sha256=qJrd8W__UZZaUMAG6BO3sxfkgpCoOS4NA3QfqneW-jE,9588
|
6
6
|
vellum_cli/image_push.py,sha256=eeOBqKtKkPu6Kgm_jQCVCivogzAcdlIlkv61-QxH67c,11006
|
7
7
|
vellum_cli/init.py,sha256=WpnMXPItPmh0f0bBGIer3p-e5gu8DUGwSArT_FuoMEw,5093
|
8
8
|
vellum_cli/logger.py,sha256=dcM_OmgqXLo93vDYswO5ylyUQQcTfnA5GTd5tbIt3wM,1446
|
9
|
+
vellum_cli/move.py,sha256=lCHQ-U4BspgS512GxFFvUrglitaHkWfuKn1Hpfcn7-Q,2053
|
9
10
|
vellum_cli/ping.py,sha256=p_BCCRjgPhng6JktuECtkDQLbhopt6JpmrtGoLnLJT8,1161
|
10
11
|
vellum_cli/pull.py,sha256=udYyPlJ6VKDdh78rApNJOZgxHl82fcV6iGnRPSdX1LY,14750
|
11
12
|
vellum_cli/push.py,sha256=KpBGq7B-ffwa9QTHsTRSk73l-tfKc3gyiBSn9Pwlsak,11878
|
@@ -16,6 +17,7 @@ vellum_cli/tests/test_image_push.py,sha256=X0YOPdoaAnWtK9IQTxaN_wWpw08-5G3v76k1W
|
|
16
17
|
vellum_cli/tests/test_image_push_error_handling.py,sha256=QRH0eYNEEIkD2-EVFQWYexOKlhMB6puh1GouovrE-VU,7647
|
17
18
|
vellum_cli/tests/test_init.py,sha256=C_rV4lu-ab5iFoLRizs1XAUnSPdMf7oFuc1i4N4udOU,18285
|
18
19
|
vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
|
20
|
+
vellum_cli/tests/test_move.py,sha256=FIrL1xlH5oFKGX2MugcTKL8JilpopmUC7hP5OaqF5zw,5213
|
19
21
|
vellum_cli/tests/test_ping.py,sha256=b3aQLd-N59_8w2rRiWqwpB1rlHaKEYVbAj1Y3hi7A-g,2605
|
20
22
|
vellum_cli/tests/test_pull.py,sha256=f7dK61y82LlJm-FAv-IpfmscJijIfZZrR-rzN1TKkU0,49421
|
21
23
|
vellum_cli/tests/test_push.py,sha256=10G-H88tdiYvg9CaC8OXOf25UEzWkWWB01vNhuxzjog,41944
|
@@ -23,12 +25,12 @@ vellum_ee/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
25
|
vellum_ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
26
|
vellum_ee/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
25
27
|
vellum_ee/workflows/display/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
26
|
-
vellum_ee/workflows/display/base.py,sha256=
|
28
|
+
vellum_ee/workflows/display/base.py,sha256=R3f2T8FlZrXn2FawAmpVuLB3fKFWw11mCUulWAyIKA0,1912
|
27
29
|
vellum_ee/workflows/display/editor/__init__.py,sha256=MSAgY91xCEg2neH5d8jXx5wRdR962ftZVa6vO9BGq9k,167
|
28
|
-
vellum_ee/workflows/display/editor/types.py,sha256=
|
30
|
+
vellum_ee/workflows/display/editor/types.py,sha256=JXpd8E7dsInbDp5T7ra0-T6XvdQB9RAHhZ1Lc8_0Fk4,601
|
29
31
|
vellum_ee/workflows/display/exceptions.py,sha256=Oys39dHoW-s-1dnlRSZxTntMq8_macj-b2CT_6dqzJs,355
|
30
32
|
vellum_ee/workflows/display/nodes/__init__.py,sha256=jI1aPBQf8DkmrYoZ4O-wR1duqZByOf5mDFmo_wFJPE4,307
|
31
|
-
vellum_ee/workflows/display/nodes/base_node_display.py,sha256=
|
33
|
+
vellum_ee/workflows/display/nodes/base_node_display.py,sha256=98vszulLRvYz0kAh7ZEOeWOqzMtlpnOZM2lAViOUieA,18393
|
32
34
|
vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=jI_kUi9LnNLDpY63QtlC4TfN8P571VN4LpzH0I1ZtLk,1149
|
33
35
|
vellum_ee/workflows/display/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
36
|
vellum_ee/workflows/display/nodes/tests/test_base_node_display.py,sha256=wBoCqULS4XO3s9Vwhd9v4g10opfBFqeZgRqB8CoFz0c,3015
|
@@ -86,7 +88,7 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_stat
|
|
86
88
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py,sha256=03Mk8OE3kWcoZW9lNBe7v4KThCYN-pXg5Rjbkfx-jOQ,6031
|
87
89
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py,sha256=-T0cd2jx1bC0ZNtAESF78fnYD_0nOqo8zMMLwRHUTRM,6227
|
88
90
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py,sha256=LnZp1YXDn-AaaxiYgxrhCQeH-rLgmlu_r_lvM65EQ5w,7517
|
89
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py,sha256=
|
91
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py,sha256=fze2nu8UlH36giAxu60YQzmYwOm8QK3tv_v7MYBm3WY,26306
|
90
92
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py,sha256=yKmOyunzt5_0cUcqhvCmV2pu81TTkshVi_uN3yt76Wc,21816
|
91
93
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py,sha256=W4--Ldih7mRMnfyJ9G7kdyeoKkeebSu_5d33TJQzShU,16735
|
92
94
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py,sha256=UnfWTfKN8DrOLpjCfWMgENJBjgNLWcRVfexbwERKY-c,8501
|
@@ -151,7 +153,7 @@ vellum/client/README.md,sha256=b6XKeYBBbhQx0v1sHWfM0gIJeJhUFF-aqL2ig7ADa08,5564
|
|
151
153
|
vellum/client/__init__.py,sha256=T5Ht_w-Mk_9nzGqdadhQB8V20M0vYj7am06ut0A3P1o,73401
|
152
154
|
vellum/client/core/__init__.py,sha256=lTcqUPXcx4112yLDd70RAPeqq6tu3eFMe1pKOqkW9JQ,1562
|
153
155
|
vellum/client/core/api_error.py,sha256=44vPoTyWN59gonCIZMdzw7M1uspygiLnr3GNFOoVL2Q,614
|
154
|
-
vellum/client/core/client_wrapper.py,sha256=
|
156
|
+
vellum/client/core/client_wrapper.py,sha256=8my-Ir86AssDOMCGyePyF0hcUkPe6DsVFwW880WD_c8,2840
|
155
157
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
156
158
|
vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
157
159
|
vellum/client/core/force_multipart.py,sha256=awxh5MtcRYe74ehY8U76jzv6fYM_w_D3Rur7KQQzSDk,429
|
@@ -1720,7 +1722,7 @@ vellum/workflows/edges/__init__.py,sha256=wSkmAnz9xyi4vZwtDbKxwlplt2skD7n3NsxkvR
|
|
1720
1722
|
vellum/workflows/edges/edge.py,sha256=N0SnY3gKVuxImPAdCbPMPlHJIXbkQ3fwq_LbJRvVMFc,677
|
1721
1723
|
vellum/workflows/emitters/__init__.py,sha256=d9QFOI3eVg6rzpSFLvrjkDYXWikf1tcp3ruTRa2Boyc,143
|
1722
1724
|
vellum/workflows/emitters/base.py,sha256=Tcp13VMB-GMwEJdl-6XTPckspdOdwpMgBx22-PcQxds,892
|
1723
|
-
vellum/workflows/emitters/vellum_emitter.py,sha256=
|
1725
|
+
vellum/workflows/emitters/vellum_emitter.py,sha256=ECBIRA48WS5rIJd1iWUfye7B5Up7ujL98BTlZwWALKs,4430
|
1724
1726
|
vellum/workflows/environment/__init__.py,sha256=TJz0m9dwIs6YOwCTeuN0HHsU-ecyjc1OJXx4AFy83EQ,121
|
1725
1727
|
vellum/workflows/environment/environment.py,sha256=Ck3RPKXJvtMGx_toqYQQQF-ZwXm5ijVwJpEPTeIJ4_Q,471
|
1726
1728
|
vellum/workflows/errors/__init__.py,sha256=tWGPu5xyAU8gRb8_bl0fL7OfU3wxQ9UH6qVwy4X4P_Q,113
|
@@ -1814,7 +1816,7 @@ vellum/workflows/nodes/core/map_node/tests/test_node.py,sha256=Xc2xZY5ShSy-bsIQe
|
|
1814
1816
|
vellum/workflows/nodes/core/retry_node/__init__.py,sha256=lN2bIy5a3Uzhs_FYCrooADyYU6ZGShtvLKFWpelwPvo,60
|
1815
1817
|
vellum/workflows/nodes/core/retry_node/node.py,sha256=EM4ya8Myr7ADllpjt9q-BAhB3hGrsF8MLZhp5eh4lyo,5590
|
1816
1818
|
vellum/workflows/nodes/core/retry_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1817
|
-
vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=
|
1819
|
+
vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=XyMtL_ZI6zcqCe0mG4DYjeuZGqX9zm35lnpLUZxsNUk,4368
|
1818
1820
|
vellum/workflows/nodes/core/templating_node/__init__.py,sha256=GmyuYo81_A1_Bz6id69ozVFS6FKiuDsZTiA3I6MaL2U,70
|
1819
1821
|
vellum/workflows/nodes/core/templating_node/node.py,sha256=mn0JEbORWaM-mR7fgUZy-BItZCup8CaxZQaY_g3TSEE,3855
|
1820
1822
|
vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=gfLi8lJpTU5jGO1Kt6UuzVz1fQN8dcNhHBZG90enP-s,15013
|
@@ -1895,7 +1897,7 @@ vellum/workflows/nodes/displayable/tool_calling_node/tests/__init__.py,sha256=47
|
|
1895
1897
|
vellum/workflows/nodes/displayable/tool_calling_node/tests/test_composio_service.py,sha256=in1fbEz5x1tx3uKv9YXdvOncsHucNL8Ro6Go7lBuuOQ,8962
|
1896
1898
|
vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py,sha256=GZoeybB9uM7ai8sBLAtUMHrMVgh-WrJDWrKZci6feDs,11892
|
1897
1899
|
vellum/workflows/nodes/displayable/tool_calling_node/tests/test_utils.py,sha256=SIu5GCj4tIE4fz-cAcdULtQfqZIhrcc3Doo6TWLXBws,8804
|
1898
|
-
vellum/workflows/nodes/displayable/tool_calling_node/utils.py,sha256=
|
1900
|
+
vellum/workflows/nodes/displayable/tool_calling_node/utils.py,sha256=wymqUCytUHiWKJxJDvMc7cLdJ69zfxNrHXAmXkFSUiQ,23189
|
1899
1901
|
vellum/workflows/nodes/displayable/web_search_node/__init__.py,sha256=8FOnEP-n-U68cvxTlJW9wphIAGHq5aqjzLM-DoSSXnU,61
|
1900
1902
|
vellum/workflows/nodes/displayable/web_search_node/node.py,sha256=NQYux2bOtuBF5E4tn-fXi5y3btURPRrNqMSM9MAZYI4,5091
|
1901
1903
|
vellum/workflows/nodes/displayable/web_search_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -1943,12 +1945,12 @@ vellum/workflows/state/delta.py,sha256=7h8wR10lRCm15SykaPj-gSEvvsMjCwYLPsOx3nsvB
|
|
1943
1945
|
vellum/workflows/state/encoder.py,sha256=HdNlabmBOcFSeY_dgn4LNtQEugyzsw3p4mvn2ChC1Io,3380
|
1944
1946
|
vellum/workflows/state/store.py,sha256=uVe-oN73KwGV6M6YLhwZMMUQhzTQomsVfVnb8V91gVo,1147
|
1945
1947
|
vellum/workflows/state/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1946
|
-
vellum/workflows/state/tests/test_state.py,sha256=
|
1948
|
+
vellum/workflows/state/tests/test_state.py,sha256=zEVFIY2any41X2BA5Us_qqKpzH5HRqmyrUJ04GTO0pU,7484
|
1947
1949
|
vellum/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1948
1950
|
vellum/workflows/tests/test_sandbox.py,sha256=JKwaluI-lODQo7Ek9sjDstjL_WTdSqUlVik6ZVTfVOA,1826
|
1949
1951
|
vellum/workflows/tests/test_undefined.py,sha256=zMCVliCXVNLrlC6hEGyOWDnQADJ2g83yc5FIM33zuo8,353
|
1950
1952
|
vellum/workflows/types/__init__.py,sha256=KxUTMBGzuRCfiMqzzsykOeVvrrkaZmTTo1a7SLu8gRM,68
|
1951
|
-
vellum/workflows/types/code_execution_node_wrappers.py,sha256=
|
1953
|
+
vellum/workflows/types/code_execution_node_wrappers.py,sha256=fewX9bqF_4TZuK-gZYIn12s31-k03vHMGRpvFAPm11Y,3206
|
1952
1954
|
vellum/workflows/types/core.py,sha256=TggDVs2lVya33xvu374EDhMC1b7RRlAAs0zWLaF46BA,1385
|
1953
1955
|
vellum/workflows/types/definition.py,sha256=2vq3uGT-m994zRcla0yTUsMiPLKSDuzEZs7H6U9QbiE,4993
|
1954
1956
|
vellum/workflows/types/generics.py,sha256=8jptbEx1fnJV0Lhj0MpCJOT6yNiEWeTOYOwrEAb5CRU,1576
|
@@ -1968,7 +1970,7 @@ vellum/workflows/utils/tests/test_names.py,sha256=aOqpyvMsOEK_9mg_-yaNxQDW7QQfwq
|
|
1968
1970
|
vellum/workflows/utils/tests/test_uuids.py,sha256=i77ABQ0M3S-aFLzDXHJq_yr5FPkJEWCMBn1HJ3DObrE,437
|
1969
1971
|
vellum/workflows/utils/tests/test_vellum_variables.py,sha256=vbnKgm41aB5OXlO-ZIPbhQ6xDiZkT8KMxCLqz4zocWY,1791
|
1970
1972
|
vellum/workflows/utils/uuids.py,sha256=IaZQANz7fhF7la0_J1O50Y6D2PIYv_taRDTRzBT9aWw,1284
|
1971
|
-
vellum/workflows/utils/vellum_variables.py,sha256
|
1973
|
+
vellum/workflows/utils/vellum_variables.py,sha256=YHLNiQGWDNssGH1FQoG9Z1jUFZ-zYebWqTLBG4cS-Fg,5837
|
1972
1974
|
vellum/workflows/utils/zip.py,sha256=HVg_YZLmBOTXKaDV3Xhaf3V6sYnfqqZXQ8CpuafkbPY,1181
|
1973
1975
|
vellum/workflows/vellum_client.py,sha256=xkfoucodxNK5JR2-lbRqZx3xzDgExWkP6kySrpi_Ubc,1079
|
1974
1976
|
vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
|
@@ -1977,8 +1979,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
|
|
1977
1979
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1978
1980
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=ptMntHzVyy8ZuzNgeTuk7hREgKQ5UBdgq8VJFSGaW4Y,20832
|
1979
1981
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1980
|
-
vellum_ai-1.3.
|
1981
|
-
vellum_ai-1.3.
|
1982
|
-
vellum_ai-1.3.
|
1983
|
-
vellum_ai-1.3.
|
1984
|
-
vellum_ai-1.3.
|
1982
|
+
vellum_ai-1.3.3.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1983
|
+
vellum_ai-1.3.3.dist-info/METADATA,sha256=bNuEdxi3O1ua5f1Q56poP2dIfUnw_dHq58lIVX6pMds,5547
|
1984
|
+
vellum_ai-1.3.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1985
|
+
vellum_ai-1.3.3.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1986
|
+
vellum_ai-1.3.3.dist-info/RECORD,,
|
vellum_cli/__init__.py
CHANGED
@@ -5,6 +5,7 @@ import click
|
|
5
5
|
from vellum_cli.aliased_group import ClickAliasedGroup
|
6
6
|
from vellum_cli.image_push import image_push_command
|
7
7
|
from vellum_cli.init import init_command
|
8
|
+
from vellum_cli.move import move_command
|
8
9
|
from vellum_cli.ping import ping_command
|
9
10
|
from vellum_cli.pull import pull_command
|
10
11
|
from vellum_cli.push import push_command
|
@@ -376,6 +377,26 @@ def image_push(
|
|
376
377
|
image_push_command(image, tag, workspace, source)
|
377
378
|
|
378
379
|
|
380
|
+
@workflows.command(name="move")
|
381
|
+
@click.argument("old_module", required=True)
|
382
|
+
@click.argument("new_module", required=True)
|
383
|
+
@click.option("--workspace", type=str, help="The specific Workspace config to use when moving")
|
384
|
+
def workflows_move(
|
385
|
+
old_module: str,
|
386
|
+
new_module: str,
|
387
|
+
workspace: Optional[str],
|
388
|
+
) -> None:
|
389
|
+
"""
|
390
|
+
Move/rename a Workflow module. Updates both the filesystem structure and configuration.
|
391
|
+
"""
|
392
|
+
|
393
|
+
move_command(
|
394
|
+
old_module=old_module,
|
395
|
+
new_module=new_module,
|
396
|
+
workspace=workspace,
|
397
|
+
)
|
398
|
+
|
399
|
+
|
379
400
|
@workflows.command(name="init")
|
380
401
|
@click.argument("template_name", required=False)
|
381
402
|
@click.option(
|
vellum_cli/move.py
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
import os
|
2
|
+
import shutil
|
3
|
+
from typing import Optional
|
4
|
+
|
5
|
+
from dotenv import load_dotenv
|
6
|
+
|
7
|
+
from vellum_cli.config import DEFAULT_WORKSPACE_CONFIG, load_vellum_cli_config
|
8
|
+
from vellum_cli.logger import load_cli_logger
|
9
|
+
from vellum_cli.push import module_exists
|
10
|
+
|
11
|
+
|
12
|
+
def move_command(
|
13
|
+
old_module: str,
|
14
|
+
new_module: str,
|
15
|
+
workspace: Optional[str] = None,
|
16
|
+
) -> None:
|
17
|
+
load_dotenv(dotenv_path=os.path.join(os.getcwd(), ".env"))
|
18
|
+
logger = load_cli_logger()
|
19
|
+
config = load_vellum_cli_config()
|
20
|
+
|
21
|
+
if not module_exists(old_module):
|
22
|
+
raise ValueError(f"Module '{old_module}' does not exist in the filesystem.")
|
23
|
+
|
24
|
+
if module_exists(new_module):
|
25
|
+
raise ValueError(f"Module '{new_module}' already exists. Cannot move to existing module.")
|
26
|
+
|
27
|
+
matching_configs = [w for w in config.workflows if w.module == old_module]
|
28
|
+
|
29
|
+
if workspace:
|
30
|
+
matching_configs = [w for w in matching_configs if w.workspace == workspace]
|
31
|
+
else:
|
32
|
+
matching_configs = [w for w in matching_configs if w.workspace == DEFAULT_WORKSPACE_CONFIG.name]
|
33
|
+
|
34
|
+
if not matching_configs:
|
35
|
+
workspace_msg = (
|
36
|
+
f" in workspace '{workspace}'" if workspace else f" in workspace '{DEFAULT_WORKSPACE_CONFIG.name}'"
|
37
|
+
)
|
38
|
+
raise ValueError(f"No workflow configuration found for module '{old_module}'{workspace_msg}.")
|
39
|
+
|
40
|
+
logger.info(f"Moving module from '{old_module}' to '{new_module}'...")
|
41
|
+
|
42
|
+
old_path = os.path.join(os.getcwd(), *old_module.split("."))
|
43
|
+
new_path = os.path.join(os.getcwd(), *new_module.split("."))
|
44
|
+
|
45
|
+
os.makedirs(os.path.dirname(new_path), exist_ok=True)
|
46
|
+
|
47
|
+
shutil.move(old_path, new_path)
|
48
|
+
logger.info(f"Moved filesystem directory from '{old_path}' to '{new_path}'")
|
49
|
+
|
50
|
+
for workflow_config in matching_configs:
|
51
|
+
workflow_config.module = new_module
|
52
|
+
logger.info(f"Updated workflow configuration: {workflow_config.workflow_sandbox_id}")
|
53
|
+
|
54
|
+
config.save()
|
55
|
+
logger.info("Updated vellum.lock.json file.")
|
56
|
+
logger.info(f"Successfully moved module from '{old_module}' to '{new_module}'")
|
@@ -0,0 +1,154 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
from click.testing import CliRunner
|
4
|
+
|
5
|
+
from vellum_cli import main
|
6
|
+
from vellum_cli.config import load_vellum_cli_config
|
7
|
+
|
8
|
+
|
9
|
+
def test_move__happy_path(mock_module):
|
10
|
+
"""
|
11
|
+
Test that the move command successfully moves a module and updates configuration.
|
12
|
+
"""
|
13
|
+
|
14
|
+
temp_dir = mock_module.temp_dir
|
15
|
+
old_module = mock_module.module
|
16
|
+
new_module = "examples.new.workflow"
|
17
|
+
|
18
|
+
old_module_dir = os.path.join(temp_dir, *old_module.split("."))
|
19
|
+
os.makedirs(old_module_dir, exist_ok=True)
|
20
|
+
with open(os.path.join(old_module_dir, "workflow.py"), "w") as f:
|
21
|
+
f.write("# test workflow")
|
22
|
+
|
23
|
+
runner = CliRunner()
|
24
|
+
result = runner.invoke(main, ["workflows", "move", old_module, new_module])
|
25
|
+
|
26
|
+
assert result.exit_code == 0
|
27
|
+
|
28
|
+
assert not os.path.exists(old_module_dir)
|
29
|
+
|
30
|
+
new_module_dir = os.path.join(temp_dir, *new_module.split("."))
|
31
|
+
assert os.path.exists(new_module_dir)
|
32
|
+
assert os.path.exists(os.path.join(new_module_dir, "workflow.py"))
|
33
|
+
|
34
|
+
config = load_vellum_cli_config()
|
35
|
+
workflow_config = next((w for w in config.workflows if w.module == new_module), None)
|
36
|
+
assert workflow_config is not None
|
37
|
+
assert workflow_config.workflow_sandbox_id == mock_module.workflow_sandbox_id
|
38
|
+
|
39
|
+
|
40
|
+
def test_move__old_module_not_exists(mock_module):
|
41
|
+
"""
|
42
|
+
Test that the move command fails when the old module doesn't exist.
|
43
|
+
"""
|
44
|
+
|
45
|
+
old_module = "nonexistent.module"
|
46
|
+
new_module = "examples.new.workflow"
|
47
|
+
|
48
|
+
runner = CliRunner()
|
49
|
+
result = runner.invoke(main, ["workflows", "move", old_module, new_module])
|
50
|
+
|
51
|
+
assert result.exit_code != 0
|
52
|
+
assert "does not exist in the filesystem" in str(result.exception)
|
53
|
+
|
54
|
+
|
55
|
+
def test_move__new_module_already_exists(mock_module):
|
56
|
+
"""
|
57
|
+
Test that the move command fails when the new module already exists.
|
58
|
+
"""
|
59
|
+
|
60
|
+
temp_dir = mock_module.temp_dir
|
61
|
+
old_module = mock_module.module
|
62
|
+
new_module = "examples.existing.workflow"
|
63
|
+
|
64
|
+
old_module_dir = os.path.join(temp_dir, *old_module.split("."))
|
65
|
+
new_module_dir = os.path.join(temp_dir, *new_module.split("."))
|
66
|
+
os.makedirs(old_module_dir, exist_ok=True)
|
67
|
+
os.makedirs(new_module_dir, exist_ok=True)
|
68
|
+
|
69
|
+
runner = CliRunner()
|
70
|
+
result = runner.invoke(main, ["workflows", "move", old_module, new_module])
|
71
|
+
|
72
|
+
assert result.exit_code != 0
|
73
|
+
assert "already exists" in str(result.exception)
|
74
|
+
|
75
|
+
|
76
|
+
def test_move__no_workflow_config_found(mock_module):
|
77
|
+
"""
|
78
|
+
Test that the move command fails when no workflow config is found.
|
79
|
+
"""
|
80
|
+
|
81
|
+
temp_dir = mock_module.temp_dir
|
82
|
+
old_module = "examples.unconfigured.workflow"
|
83
|
+
new_module = "examples.new.workflow"
|
84
|
+
|
85
|
+
old_module_dir = os.path.join(temp_dir, *old_module.split("."))
|
86
|
+
os.makedirs(old_module_dir, exist_ok=True)
|
87
|
+
|
88
|
+
runner = CliRunner()
|
89
|
+
result = runner.invoke(main, ["workflows", "move", old_module, new_module])
|
90
|
+
|
91
|
+
assert result.exit_code != 0
|
92
|
+
assert "No workflow configuration found" in str(result.exception)
|
93
|
+
|
94
|
+
|
95
|
+
def test_move__with_workspace_filter(mock_module):
|
96
|
+
"""
|
97
|
+
Test that the move command works with workspace filtering.
|
98
|
+
"""
|
99
|
+
|
100
|
+
temp_dir = mock_module.temp_dir
|
101
|
+
old_module = mock_module.module
|
102
|
+
new_module = "examples.new.workflow"
|
103
|
+
workspace = "default"
|
104
|
+
|
105
|
+
old_module_dir = os.path.join(temp_dir, *old_module.split("."))
|
106
|
+
os.makedirs(old_module_dir, exist_ok=True)
|
107
|
+
with open(os.path.join(old_module_dir, "workflow.py"), "w") as f:
|
108
|
+
f.write("# test workflow")
|
109
|
+
|
110
|
+
runner = CliRunner()
|
111
|
+
result = runner.invoke(main, ["workflows", "move", old_module, new_module, "--workspace", workspace])
|
112
|
+
|
113
|
+
assert result.exit_code == 0
|
114
|
+
|
115
|
+
config = load_vellum_cli_config()
|
116
|
+
workflow_config = next((w for w in config.workflows if w.module == new_module), None)
|
117
|
+
assert workflow_config is not None
|
118
|
+
assert workflow_config.workspace == workspace
|
119
|
+
|
120
|
+
|
121
|
+
def test_move__preserves_workflow_metadata(mock_module):
|
122
|
+
"""
|
123
|
+
Test that the move command preserves all workflow metadata except the module name.
|
124
|
+
"""
|
125
|
+
|
126
|
+
temp_dir = mock_module.temp_dir
|
127
|
+
old_module = mock_module.module
|
128
|
+
new_module = "examples.new.workflow"
|
129
|
+
|
130
|
+
config = load_vellum_cli_config()
|
131
|
+
original_config = next((w for w in config.workflows if w.module == old_module), None)
|
132
|
+
assert original_config is not None
|
133
|
+
original_config.container_image_name = "test-image"
|
134
|
+
original_config.container_image_tag = "v1.0"
|
135
|
+
original_config.ignore = "sandbox.py"
|
136
|
+
config.save()
|
137
|
+
|
138
|
+
old_module_dir = os.path.join(temp_dir, *old_module.split("."))
|
139
|
+
os.makedirs(old_module_dir, exist_ok=True)
|
140
|
+
with open(os.path.join(old_module_dir, "workflow.py"), "w") as f:
|
141
|
+
f.write("# test workflow")
|
142
|
+
|
143
|
+
runner = CliRunner()
|
144
|
+
result = runner.invoke(main, ["workflows", "move", old_module, new_module])
|
145
|
+
|
146
|
+
assert result.exit_code == 0
|
147
|
+
|
148
|
+
config = load_vellum_cli_config()
|
149
|
+
workflow_config = next((w for w in config.workflows if w.module == new_module), None)
|
150
|
+
assert workflow_config is not None
|
151
|
+
assert workflow_config.workflow_sandbox_id == mock_module.workflow_sandbox_id
|
152
|
+
assert workflow_config.container_image_name == "test-image"
|
153
|
+
assert workflow_config.container_image_tag == "v1.0"
|
154
|
+
assert workflow_config.ignore == "sandbox.py"
|
@@ -17,6 +17,7 @@ class NodeDisplayComment(UniversalBaseModel):
|
|
17
17
|
|
18
18
|
class NodeDisplayData(UniversalBaseModel):
|
19
19
|
position: NodeDisplayPosition = Field(default_factory=NodeDisplayPosition)
|
20
|
+
z_index: Optional[int] = None
|
20
21
|
width: Optional[int] = None
|
21
22
|
height: Optional[int] = None
|
22
23
|
comment: Optional[NodeDisplayComment] = None
|
@@ -431,6 +431,7 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
|
|
431
431
|
)
|
432
432
|
return NodeDisplayData(
|
433
433
|
position=explicit_value.position,
|
434
|
+
z_index=explicit_value.z_index,
|
434
435
|
width=explicit_value.width,
|
435
436
|
height=explicit_value.height,
|
436
437
|
comment=comment,
|
@@ -47,17 +47,20 @@ def test_serialize_workflow():
|
|
47
47
|
|
48
48
|
# AND its output variables should be what we expect
|
49
49
|
output_variables = serialized_workflow["output_variables"]
|
50
|
-
assert len(output_variables) ==
|
50
|
+
assert len(output_variables) == 2
|
51
51
|
assert not DeepDiff(
|
52
|
-
[
|
52
|
+
[
|
53
|
+
{"id": "15a0ab89-8ed4-43b9-afa2-3c0b29d4dc3e", "key": "results", "type": "JSON"},
|
54
|
+
{"id": "0ef1608e-1737-41cc-9b90-a8e124138f70", "key": "json", "type": "JSON"},
|
55
|
+
],
|
53
56
|
output_variables,
|
54
57
|
ignore_order=True,
|
55
58
|
)
|
56
59
|
|
57
60
|
# AND its raw data should be what we expect
|
58
61
|
workflow_raw_data = serialized_workflow["workflow_raw_data"]
|
59
|
-
assert len(workflow_raw_data["edges"]) ==
|
60
|
-
assert len(workflow_raw_data["nodes"]) ==
|
62
|
+
assert len(workflow_raw_data["edges"]) == 3
|
63
|
+
assert len(workflow_raw_data["nodes"]) == 4
|
61
64
|
|
62
65
|
# AND each node should be serialized correctly
|
63
66
|
entrypoint_node = workflow_raw_data["nodes"][0]
|
@@ -305,7 +308,7 @@ def test_serialize_workflow():
|
|
305
308
|
},
|
306
309
|
}
|
307
310
|
],
|
308
|
-
"display_data": {"position": {"x": 400.0, "y":
|
311
|
+
"display_data": {"position": {"x": 400.0, "y": 75.0}},
|
309
312
|
"base": {
|
310
313
|
"name": "FinalOutputNode",
|
311
314
|
"module": ["vellum", "workflows", "nodes", "displayable", "final_output_node", "node"],
|
@@ -336,6 +339,14 @@ def test_serialize_workflow():
|
|
336
339
|
"target_handle_id": "46c99277-2b4b-477d-851c-ea497aef6b16",
|
337
340
|
"type": "DEFAULT",
|
338
341
|
},
|
342
|
+
{
|
343
|
+
"id": "0b1a2960-4cd5-4045-844f-42b6c87487aa",
|
344
|
+
"source_node_id": "8450dd06-975a-41a4-a564-808ee8808fe6",
|
345
|
+
"source_handle_id": "d4a097ab-e22d-42f1-b6bc-2ed96856377a",
|
346
|
+
"target_node_id": "1f4e3b7b-6af1-42c8-ab33-05b0f01e2b62",
|
347
|
+
"target_handle_id": "7d94907f-c840-4ced-b813-ee3b17f2a8a9",
|
348
|
+
"type": "DEFAULT",
|
349
|
+
},
|
339
350
|
],
|
340
351
|
serialized_edges,
|
341
352
|
ignore_order=True,
|
File without changes
|
File without changes
|
File without changes
|