vellum-ai 0.11.3__py3-none-any.whl → 0.11.5__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- vellum/client/core/client_wrapper.py +1 -1
- vellum/workflows/events/types.py +8 -0
- vellum/workflows/graph/graph.py +23 -4
- vellum/workflows/graph/tests/test_graph.py +25 -0
- vellum/workflows/nodes/bases/base.py +1 -1
- vellum/workflows/nodes/core/try_node/node.py +1 -0
- vellum/workflows/ports/port.py +11 -0
- vellum/workflows/runner/runner.py +1 -1
- {vellum_ai-0.11.3.dist-info → vellum_ai-0.11.5.dist-info}/METADATA +1 -1
- {vellum_ai-0.11.3.dist-info → vellum_ai-0.11.5.dist-info}/RECORD +22 -22
- vellum_cli/config.py +36 -0
- vellum_cli/push.py +4 -0
- vellum_cli/tests/conftest.py +19 -4
- vellum_cli/tests/test_pull.py +85 -7
- vellum_cli/tests/test_push.py +8 -8
- vellum_ee/workflows/display/nodes/vellum/error_node.py +0 -1
- vellum_ee/workflows/display/nodes/vellum/search_node.py +20 -17
- vellum_ee/workflows/display/nodes/vellum/utils.py +16 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +0 -1
- {vellum_ai-0.11.3.dist-info → vellum_ai-0.11.5.dist-info}/LICENSE +0 -0
- {vellum_ai-0.11.3.dist-info → vellum_ai-0.11.5.dist-info}/WHEEL +0 -0
- {vellum_ai-0.11.3.dist-info → vellum_ai-0.11.5.dist-info}/entry_points.txt +0 -0
@@ -17,7 +17,7 @@ class BaseClientWrapper:
|
|
17
17
|
headers: typing.Dict[str, str] = {
|
18
18
|
"X-Fern-Language": "Python",
|
19
19
|
"X-Fern-SDK-Name": "vellum-ai",
|
20
|
-
"X-Fern-SDK-Version": "0.11.
|
20
|
+
"X-Fern-SDK-Version": "0.11.5",
|
21
21
|
}
|
22
22
|
headers["X_API_KEY"] = self.api_key
|
23
23
|
return headers
|
vellum/workflows/events/types.py
CHANGED
@@ -87,6 +87,13 @@ class WorkflowParentContext(BaseParentContext):
|
|
87
87
|
workflow_definition: VellumCodeResourceDefinition
|
88
88
|
|
89
89
|
|
90
|
+
class WorkflowSandboxParentContext(BaseParentContext):
|
91
|
+
type: Literal["WORKFLOW_SANDBOX"] = "WORKFLOW_SANDBOX"
|
92
|
+
sandbox_id: UUID
|
93
|
+
sandbox_history_item_id: UUID
|
94
|
+
scenario_id: UUID
|
95
|
+
|
96
|
+
|
90
97
|
# Define the discriminated union
|
91
98
|
ParentContext = Annotated[
|
92
99
|
Union[
|
@@ -94,6 +101,7 @@ ParentContext = Annotated[
|
|
94
101
|
NodeParentContext,
|
95
102
|
WorkflowDeploymentParentContext,
|
96
103
|
PromptDeploymentParentContext,
|
104
|
+
WorkflowSandboxParentContext,
|
97
105
|
],
|
98
106
|
Field(discriminator="type"),
|
99
107
|
]
|
vellum/workflows/graph/graph.py
CHANGED
@@ -12,11 +12,13 @@ if TYPE_CHECKING:
|
|
12
12
|
GraphTargetOfSets = Union[
|
13
13
|
Set[NodeType],
|
14
14
|
Set["Graph"],
|
15
|
-
Set[
|
15
|
+
Set["Port"],
|
16
|
+
Set[Union[Type["BaseNode"], "Graph", "Port"]],
|
16
17
|
]
|
17
18
|
|
18
19
|
GraphTarget = Union[
|
19
20
|
Type["BaseNode"],
|
21
|
+
"Port",
|
20
22
|
"Graph",
|
21
23
|
GraphTargetOfSets,
|
22
24
|
]
|
@@ -53,9 +55,13 @@ class Graph:
|
|
53
55
|
entrypoints.update(target._entrypoints)
|
54
56
|
edges.update(target._edges)
|
55
57
|
terminals.update(target._terminals)
|
56
|
-
|
58
|
+
elif hasattr(target, "Ports"):
|
57
59
|
entrypoints.update({port for port in target.Ports})
|
58
60
|
terminals.update({port for port in target.Ports})
|
61
|
+
else:
|
62
|
+
# target is a Port
|
63
|
+
entrypoints.update({target})
|
64
|
+
terminals.update({target})
|
59
65
|
|
60
66
|
return Graph(entrypoints=entrypoints, edges=list(edges), terminals=terminals)
|
61
67
|
|
@@ -77,11 +83,16 @@ class Graph:
|
|
77
83
|
self._extend_edges(elem.edges)
|
78
84
|
for other_terminal in elem._terminals:
|
79
85
|
new_terminals.add(other_terminal)
|
80
|
-
|
86
|
+
elif hasattr(elem, "Ports"):
|
81
87
|
midgraph = final_output_node >> elem
|
82
88
|
self._extend_edges(midgraph.edges)
|
83
89
|
for other_terminal in elem.Ports:
|
84
90
|
new_terminals.add(other_terminal)
|
91
|
+
else:
|
92
|
+
# elem is a Port
|
93
|
+
midgraph = final_output_node >> elem
|
94
|
+
self._extend_edges(midgraph.edges)
|
95
|
+
new_terminals.add(elem)
|
85
96
|
self._terminals = new_terminals
|
86
97
|
return self
|
87
98
|
|
@@ -93,10 +104,18 @@ class Graph:
|
|
93
104
|
self._terminals = other._terminals
|
94
105
|
return self
|
95
106
|
|
107
|
+
if hasattr(other, "Ports"):
|
108
|
+
for final_output_node in self._terminals:
|
109
|
+
subgraph = final_output_node >> other
|
110
|
+
self._extend_edges(subgraph.edges)
|
111
|
+
self._terminals = {port for port in other.Ports}
|
112
|
+
return self
|
113
|
+
|
114
|
+
# other is a Port
|
96
115
|
for final_output_node in self._terminals:
|
97
116
|
subgraph = final_output_node >> other
|
98
117
|
self._extend_edges(subgraph.edges)
|
99
|
-
self._terminals = {
|
118
|
+
self._terminals = {other}
|
100
119
|
return self
|
101
120
|
|
102
121
|
@property
|
@@ -435,3 +435,28 @@ def test_graph__set_to_node():
|
|
435
435
|
|
436
436
|
# AND two edges
|
437
437
|
assert len(list(graph.edges)) == 2
|
438
|
+
|
439
|
+
|
440
|
+
def test_graph__node_to_port():
|
441
|
+
# GIVEN two nodes, one with a port
|
442
|
+
class SourceNode(BaseNode):
|
443
|
+
pass
|
444
|
+
|
445
|
+
class MiddleNode(BaseNode):
|
446
|
+
class Ports(BaseNode.Ports):
|
447
|
+
custom = Port.on_else()
|
448
|
+
|
449
|
+
class TargetNode(BaseNode):
|
450
|
+
pass
|
451
|
+
|
452
|
+
# WHEN we create a graph from the source node to the target node
|
453
|
+
graph = SourceNode >> MiddleNode.Ports.custom >> TargetNode
|
454
|
+
|
455
|
+
# THEN the graph has the source node as the entrypoint
|
456
|
+
assert set(graph.entrypoints) == {SourceNode}
|
457
|
+
|
458
|
+
# AND three nodes
|
459
|
+
assert len(list(graph.nodes)) == 3
|
460
|
+
|
461
|
+
# AND two edges
|
462
|
+
assert len(list(graph.edges)) == 2
|
@@ -160,6 +160,7 @@ Message: {event.error.message}""",
|
|
160
160
|
"__module__": dynamic_module,
|
161
161
|
"on_error_code": _on_error_code,
|
162
162
|
"subworkflow": Subworkflow,
|
163
|
+
"Ports": type("Ports", (TryNode.Ports,), {port.name: port.copy() for port in inner_cls.Ports}),
|
163
164
|
},
|
164
165
|
)
|
165
166
|
return WrappedNode
|
vellum/workflows/ports/port.py
CHANGED
@@ -40,6 +40,14 @@ class Port:
|
|
40
40
|
def __repr__(self) -> str:
|
41
41
|
return f"{self.node_class}.Ports.{self.name}"
|
42
42
|
|
43
|
+
def copy(self) -> "Port":
|
44
|
+
return Port(
|
45
|
+
default=self.default,
|
46
|
+
fork_state=self._fork_state,
|
47
|
+
condition=self._condition,
|
48
|
+
condition_type=self._condition_type,
|
49
|
+
)
|
50
|
+
|
43
51
|
@property
|
44
52
|
def fork_state(self) -> bool:
|
45
53
|
return self._fork_state
|
@@ -52,6 +60,9 @@ class Port:
|
|
52
60
|
if isinstance(other, set) or isinstance(other, Graph):
|
53
61
|
return Graph.from_port(self) >> other
|
54
62
|
|
63
|
+
if isinstance(other, Port):
|
64
|
+
return Graph.from_port(self) >> Graph.from_port(other)
|
65
|
+
|
55
66
|
edge = Edge(from_port=self, to_node=other)
|
56
67
|
if edge not in self._edges:
|
57
68
|
self._edges.append(edge)
|
@@ -264,7 +264,6 @@ class WorkflowRunner(Generic[StateType]):
|
|
264
264
|
)
|
265
265
|
)
|
266
266
|
|
267
|
-
invoked_ports = ports(outputs, node.state)
|
268
267
|
node.state.meta.node_execution_cache.fulfill_node_execution(node.__class__, span_id)
|
269
268
|
|
270
269
|
for descriptor, output_value in outputs:
|
@@ -275,6 +274,7 @@ class WorkflowRunner(Generic[StateType]):
|
|
275
274
|
|
276
275
|
node.state.meta.node_outputs[descriptor] = output_value
|
277
276
|
|
277
|
+
invoked_ports = ports(outputs, node.state)
|
278
278
|
self._workflow_event_inner_queue.put(
|
279
279
|
NodeExecutionFulfilledEvent(
|
280
280
|
trace_id=node.state.meta.trace_id,
|
@@ -2,17 +2,17 @@ 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=pftUQ6FiyfebNEB8xcfwzLjpfFDCAiH15xHBU6xr_wY,6733
|
4
4
|
vellum_cli/aliased_group.py,sha256=ugW498j0yv4ALJ8vS9MsO7ctDW7Jlir9j6nE_uHAP8c,3363
|
5
|
-
vellum_cli/config.py,sha256=
|
5
|
+
vellum_cli/config.py,sha256=wJQnv3tCgu1BOugg0AOP94yQ-x1yAg8juX_QoFN9Y7w,5223
|
6
6
|
vellum_cli/image_push.py,sha256=SJwhwWJsLjwGNezNVd_oCVpFMfPsAB3dfLWmriZZUtw,4419
|
7
7
|
vellum_cli/logger.py,sha256=PuRFa0WCh4sAGFS5aqWB0QIYpS6nBWwPJrIXpWxugV4,1022
|
8
8
|
vellum_cli/pull.py,sha256=6wIiorqSx2rmR6atZJHHBuLSviocxK_n0DQxEDGmCzo,4008
|
9
|
-
vellum_cli/push.py,sha256=
|
9
|
+
vellum_cli/push.py,sha256=kbvlzZ9KnkS5DxxKHQP5ZvHHk1-CbCDg9LqnIRAWyt4,5258
|
10
10
|
vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
-
vellum_cli/tests/conftest.py,sha256=
|
11
|
+
vellum_cli/tests/conftest.py,sha256=eFGwBxib3Nki830lIFintB0b6r4x8T_KMnmzhlTY5x0,1337
|
12
12
|
vellum_cli/tests/test_config.py,sha256=uvKGDc8BoVyT9_H0Z-g8469zVxomn6Oi3Zj-vK7O_wU,2631
|
13
13
|
vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
|
14
|
-
vellum_cli/tests/test_pull.py,sha256=
|
15
|
-
vellum_cli/tests/test_push.py,sha256=
|
14
|
+
vellum_cli/tests/test_pull.py,sha256=N6ZphvHYGokclbpbTpgOmpu_m2GtocDEesbdeHFjO5Y,13194
|
15
|
+
vellum_cli/tests/test_push.py,sha256=V2iGcskh2X3OHj2uV5Vx_BhmtyfmUkyx0lrp8DDOExc,5824
|
16
16
|
vellum_ee/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
17
|
vellum_ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
18
|
vellum_ee/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -30,7 +30,7 @@ vellum_ee/workflows/display/nodes/vellum/__init__.py,sha256=nmPLj8vkbVCS46XQqmHq
|
|
30
30
|
vellum_ee/workflows/display/nodes/vellum/api_node.py,sha256=4SSQGecKWHuoGy5YIGJeOZVHGKwTs_8Y-gf3GvsHb0M,8506
|
31
31
|
vellum_ee/workflows/display/nodes/vellum/code_execution_node.py,sha256=MASV7u0X4eiS3SzRWeBcbWZ_YgNlwwg5cM2vaFWjpqk,3915
|
32
32
|
vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=gUbSP8_oSAMNIb0CGiefd2FMYgoO6wMoG6iA1FakMjk,13293
|
33
|
-
vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=
|
33
|
+
vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=ygTjSjYDI4DtkxADWub5rhBnRWItMKWF6fezBrgpOKA,1979
|
34
34
|
vellum_ee/workflows/display/nodes/vellum/final_output_node.py,sha256=UezalObmZ3mcg7Nou2RgiI_0cmc7_tSdZLNB591iCcI,2772
|
35
35
|
vellum_ee/workflows/display/nodes/vellum/guardrail_node.py,sha256=3TJvHX_Uuf_gr94VkYc_zmNH8I5p71ChIeoAbJZ3ddY,2158
|
36
36
|
vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=sj-pySLVYGt032debhcQhHc5JwrALQrNCEKh3DXc8F8,7386
|
@@ -39,20 +39,20 @@ vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=AqUlItgSZij12qRKguKV
|
|
39
39
|
vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=BM3nfL0-D8x91xW0MGhnJFo45ZgGLXDqdbiSGoSuXN0,3244
|
40
40
|
vellum_ee/workflows/display/nodes/vellum/note_node.py,sha256=9VpC3h0RYOxJuRbjDwidBYlLKakkmlEnDMBh2C7lHcY,1107
|
41
41
|
vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py,sha256=gLRkizwyw21-Z12IyDbdOJpXayiZZd4HWd6qgZQg8sc,3106
|
42
|
-
vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=
|
42
|
+
vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=BQEqi6_65h7PmP-FhBF0zUB3MBLA65DkZLU9IdS3iyA,8668
|
43
43
|
vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py,sha256=zOp4voBSgB3MR1R93wTOrsiiara_hxEAYFupLl_SvTA,2657
|
44
44
|
vellum_ee/workflows/display/nodes/vellum/templating_node.py,sha256=UNYxoE-89agE8ugK0aWg_uN61jPqlC2VSxWHk568sN4,3324
|
45
45
|
vellum_ee/workflows/display/nodes/vellum/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
46
46
|
vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py,sha256=ZUp2fmDF4JTni1NjJOIV8dJoxx22eMBskmBJFsjtEvE,3809
|
47
47
|
vellum_ee/workflows/display/nodes/vellum/try_node.py,sha256=m4d6hi6oD-jSW_bjrlN8coVwb6ivC2amPHpePHJ-Htg,2278
|
48
|
-
vellum_ee/workflows/display/nodes/vellum/utils.py,sha256=
|
48
|
+
vellum_ee/workflows/display/nodes/vellum/utils.py,sha256=golxvSM6HIZ4uYKbfcI7muVJuckFZQcGFCAFvfx4Cls,4654
|
49
49
|
vellum_ee/workflows/display/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
50
50
|
vellum_ee/workflows/display/tests/test_vellum_workflow_display.py,sha256=TEg3QbdE7rLbEhml9pMWmay--phsekGlfGVhTblxCGE,1727
|
51
51
|
vellum_ee/workflows/display/tests/workflow_serialization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
52
52
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py,sha256=e__ae2yepB5vlgVT08sr1DDB8pYjax6VQLo5FtRk-nA,17934
|
53
53
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py,sha256=0McMPIPnIwE8iGh7fzFZL3dc6Q7NCQ_wUVFpl14YATo,22846
|
54
54
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py,sha256=d6xWDvi-Uo1KcMHVj_e8TujKhTwMKXAlT8H3P2V0gQU,53693
|
55
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py,sha256=
|
55
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py,sha256=MGwIwhCBCVYZmE_8Srts3fEs0BcRqXFFVbqiHiBQ55Q,6798
|
56
56
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py,sha256=vA8cd7PJYhf949OUGeYP_moKtMogSyfHN2Z-qzNQLwM,8294
|
57
57
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py,sha256=N2ACycHn-EwP5paxHwDu2fufABssE293wiunhm-bCGg,22076
|
58
58
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py,sha256=H1bVDG_mFPokJ7OYrnl9rM9M3gEa5bctGmhUuKccB4U,15950
|
@@ -78,7 +78,7 @@ vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
|
|
78
78
|
vellum/client/__init__.py,sha256=o4m7iRZWEV8rP3GkdaztHAjNmjxjWERlarviFoHzuKI,110927
|
79
79
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
80
80
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
81
|
-
vellum/client/core/client_wrapper.py,sha256=
|
81
|
+
vellum/client/core/client_wrapper.py,sha256=Lchp9CqqaSiM_CP0YETtEwr4rvjUV6p2Y7s0tL_-n6Q,1890
|
82
82
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
83
83
|
vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
|
84
84
|
vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
|
@@ -1220,7 +1220,7 @@ vellum/workflows/events/__init__.py,sha256=6pxxceJo2dcaRkWtkDAYlUQZ-PHBQSZytIoyu
|
|
1220
1220
|
vellum/workflows/events/node.py,sha256=3_NPVhXR-XMnNj5QVA_ycebs_-jRuGSLf5H7XjLQh8o,5258
|
1221
1221
|
vellum/workflows/events/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1222
1222
|
vellum/workflows/events/tests/test_event.py,sha256=IBP_fCT_kPDdSCdgDCo7eaG7MYUR6aF4EFxwFIr9lbA,12717
|
1223
|
-
vellum/workflows/events/types.py,sha256=
|
1223
|
+
vellum/workflows/events/types.py,sha256=7sBSMNstsibqq93Klu4A-GInzo4IB23xWel595Uyi_Y,3077
|
1224
1224
|
vellum/workflows/events/workflow.py,sha256=02UZE4sBpWrG2A3xddu8v0S9kPfo7YetX6xTvzKg-2w,5218
|
1225
1225
|
vellum/workflows/exceptions.py,sha256=Dc7mxstsaMDRmS91QEOiZCbZ1ZIRacnm0l5lQmC6WkA,401
|
1226
1226
|
vellum/workflows/expressions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -1251,15 +1251,15 @@ vellum/workflows/expressions/not_between.py,sha256=H2huRR95D9Qb7lCHmK7BcK-Ug-E1g
|
|
1251
1251
|
vellum/workflows/expressions/not_in.py,sha256=OQkN5G1E6VoTDpoLvx7X3GbohLlqEAYHV0rVVUV7ow4,1049
|
1252
1252
|
vellum/workflows/expressions/or_.py,sha256=s-8YdMSSCDS2yijR38kguwok3iqmDMMgDYKV93b4O4s,914
|
1253
1253
|
vellum/workflows/graph/__init__.py,sha256=3sHlay5d_-uD7j3QJXiGl0WHFZZ_QScRvgyDhN2GhHY,74
|
1254
|
-
vellum/workflows/graph/graph.py,sha256=
|
1254
|
+
vellum/workflows/graph/graph.py,sha256=rmPPs2gtQhaYIuZKETdWrdacgwQRvT6soj12UOl1Tm0,5316
|
1255
1255
|
vellum/workflows/graph/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1256
|
-
vellum/workflows/graph/tests/test_graph.py,sha256=
|
1256
|
+
vellum/workflows/graph/tests/test_graph.py,sha256=PQI1lO2IY-izBSbkwxjKR5a1z-aN-ieHV_p0m-g5eAM,11256
|
1257
1257
|
vellum/workflows/inputs/__init__.py,sha256=AbFEteIYEvCb14fM3EK7bhM-40-6s494rSlIhQ4Dsss,62
|
1258
1258
|
vellum/workflows/inputs/base.py,sha256=1kMgr0WqCYdWUqgFvgSoAMw2067FAlgwhGXLgbIOrLY,2391
|
1259
1259
|
vellum/workflows/logging.py,sha256=_a217XogktV4Ncz6xKFz7WfYmZAzkfVRVuC0rWob8ls,437
|
1260
1260
|
vellum/workflows/nodes/__init__.py,sha256=aVdQVv7Y3Ro3JlqXGpxwaU2zrI06plDHD2aumH5WUIs,1157
|
1261
1261
|
vellum/workflows/nodes/bases/__init__.py,sha256=Ll1Ti6t3e_HKtGLsQTHAJevDmfo0QtfgPZUZ9FCRduI,140
|
1262
|
-
vellum/workflows/nodes/bases/base.py,sha256=
|
1262
|
+
vellum/workflows/nodes/bases/base.py,sha256=atWeRf3BgTZpy5L3Mm47D6dca_sYKfSr5D3-fruwX_k,14056
|
1263
1263
|
vellum/workflows/nodes/bases/base_subworkflow_node/__init__.py,sha256=0nkHQiFC4IpA1ZGx60XG0BLUWF6hwUpgqmS3ZrlFGhg,80
|
1264
1264
|
vellum/workflows/nodes/bases/base_subworkflow_node/node.py,sha256=vC0gUBQewAUNtP3i2G0-LUpE_kY-r_ijBD_tS1XkQ1E,383
|
1265
1265
|
vellum/workflows/nodes/bases/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -1284,7 +1284,7 @@ vellum/workflows/nodes/core/templating_node/node.py,sha256=19OFvRimrp1YuUO7H4rU7
|
|
1284
1284
|
vellum/workflows/nodes/core/templating_node/render.py,sha256=OpJp0NAH6qcEL6K9lxR0qjpFb75TYNttJR5iCos8tmg,1792
|
1285
1285
|
vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=0BtXeSix7KGIuKzlPFTMLATpNnFPhut1UV_srGptkt0,1120
|
1286
1286
|
vellum/workflows/nodes/core/try_node/__init__.py,sha256=JVD4DrldTIqFQQFrubs9KtWCCc0YCAc7Fzol5ZWIWeM,56
|
1287
|
-
vellum/workflows/nodes/core/try_node/node.py,sha256=
|
1287
|
+
vellum/workflows/nodes/core/try_node/node.py,sha256=XS-xZaJ_tM3sS-FjWU-FCk9x4Id2lrniyknORgg0KjA,6654
|
1288
1288
|
vellum/workflows/nodes/core/try_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1289
1289
|
vellum/workflows/nodes/core/try_node/tests/test_node.py,sha256=iD_ZjgB-v7pOYS6VjsqC-FWAFw8xvnEb-xXeau1Cuk0,4053
|
1290
1290
|
vellum/workflows/nodes/displayable/__init__.py,sha256=6F_4DlSwvHuilWnIalp8iDjjDXl0Nmz4QzJV2PYe5RI,1023
|
@@ -1334,7 +1334,7 @@ vellum/workflows/outputs/__init__.py,sha256=AyZ4pRh_ACQIGvkf0byJO46EDnSix1ZCAXfv
|
|
1334
1334
|
vellum/workflows/outputs/base.py,sha256=a7W6rNSDSawwGAXYjNTF2iHb9lnZu7WFSOagZIyy__k,7976
|
1335
1335
|
vellum/workflows/ports/__init__.py,sha256=bZuMt-R7z5bKwpu4uPW7LlJeePOQWmCcDSXe5frUY5g,101
|
1336
1336
|
vellum/workflows/ports/node_ports.py,sha256=g4A-8iUAvEJSkaWppbvzAR8XU02R9U-qLN4rP2Kq4Aw,2743
|
1337
|
-
vellum/workflows/ports/port.py,sha256=
|
1337
|
+
vellum/workflows/ports/port.py,sha256=rc3GB7dDQCUs0IbY08a92-31YzJHQgBeww13brSJ2Js,3172
|
1338
1338
|
vellum/workflows/ports/utils.py,sha256=pEjVNJKw9LhD_cFN-o0MWBOW2ejno7jv26qqzjLxwS4,1662
|
1339
1339
|
vellum/workflows/references/__init__.py,sha256=glHFC1VfXmcbNvH5VzFbkT03d8_D7MMcvEcsUBrzLIs,591
|
1340
1340
|
vellum/workflows/references/environment_variable.py,sha256=7FFtiKfc4eyVkkfUbhc666OBNDqvFlMoNQEYmGpEVVE,661
|
@@ -1350,7 +1350,7 @@ vellum/workflows/references/workflow_input.py,sha256=epspVRZ9n_nxoTxI5Am3GDd2fpU
|
|
1350
1350
|
vellum/workflows/resolvers/__init__.py,sha256=eH6hTvZO4IciDaf_cf7aM2vs-DkBDyJPycOQevJxQnI,82
|
1351
1351
|
vellum/workflows/resolvers/base.py,sha256=WHra9LRtlTuB1jmuNqkfVE2JUgB61Cyntn8f0b0WZg4,411
|
1352
1352
|
vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8vyT-bqM,72
|
1353
|
-
vellum/workflows/runner/runner.py,sha256=
|
1353
|
+
vellum/workflows/runner/runner.py,sha256=7mSVaqJjyVljuuy3-bIO56mzXXMeQwKcYzZOuo8aC8E,27573
|
1354
1354
|
vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
|
1355
1355
|
vellum/workflows/state/base.py,sha256=jpSzF1OQd3-fqi6dMGlNsQl-7JnJxCdzWIigmX8Wz-I,14425
|
1356
1356
|
vellum/workflows/state/context.py,sha256=oXiEdNsWJi1coRB85IreTgUeR6_CrWWBXndtLff9S7M,1272
|
@@ -1377,8 +1377,8 @@ vellum/workflows/vellum_client.py,sha256=ODrq_TSl-drX2aezXegf7pizpWDVJuTXH-j6528
|
|
1377
1377
|
vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
|
1378
1378
|
vellum/workflows/workflows/base.py,sha256=mnI-kZ78yt7u6NFSTUo-tYjDnarP-RJ7uZjwjCn6PCQ,16795
|
1379
1379
|
vellum/workflows/workflows/event_filters.py,sha256=-uQcMB7IpPd-idMku8f2QNVhPXPFWo6FZLlGjRf8rCo,1996
|
1380
|
-
vellum_ai-0.11.
|
1381
|
-
vellum_ai-0.11.
|
1382
|
-
vellum_ai-0.11.
|
1383
|
-
vellum_ai-0.11.
|
1384
|
-
vellum_ai-0.11.
|
1380
|
+
vellum_ai-0.11.5.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1381
|
+
vellum_ai-0.11.5.dist-info/METADATA,sha256=8CXclMT8Nu3M7czzPkH0K0toXno3RpXdZIBlhrasKME,5128
|
1382
|
+
vellum_ai-0.11.5.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
|
1383
|
+
vellum_ai-0.11.5.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1384
|
+
vellum_ai-0.11.5.dist-info/RECORD,,
|
vellum_cli/config.py
CHANGED
@@ -20,6 +20,15 @@ class WorkflowDeploymentConfig(UniversalBaseModel):
|
|
20
20
|
description: Optional[str] = None
|
21
21
|
release_tags: Optional[List[str]] = None
|
22
22
|
|
23
|
+
def merge(self, other: "WorkflowDeploymentConfig") -> "WorkflowDeploymentConfig":
|
24
|
+
return WorkflowDeploymentConfig(
|
25
|
+
id=self.id or other.id,
|
26
|
+
label=self.label or other.label,
|
27
|
+
name=self.name or other.name,
|
28
|
+
description=self.description or other.description,
|
29
|
+
release_tags=self.release_tags or other.release_tags,
|
30
|
+
)
|
31
|
+
|
23
32
|
|
24
33
|
class WorkflowConfig(UniversalBaseModel):
|
25
34
|
module: str
|
@@ -28,10 +37,37 @@ class WorkflowConfig(UniversalBaseModel):
|
|
28
37
|
deployments: List[WorkflowDeploymentConfig] = field(default_factory=list)
|
29
38
|
|
30
39
|
def merge(self, other: "WorkflowConfig") -> "WorkflowConfig":
|
40
|
+
self_deployment_by_id = {
|
41
|
+
deployment.id: deployment for deployment in self.deployments if deployment.id is not None
|
42
|
+
}
|
43
|
+
other_deployment_by_id = {
|
44
|
+
deployment.id: deployment for deployment in other.deployments if deployment.id is not None
|
45
|
+
}
|
46
|
+
all_ids = sorted(set(self_deployment_by_id.keys()).union(set(other_deployment_by_id.keys())))
|
47
|
+
merged_deployments = []
|
48
|
+
for id in all_ids:
|
49
|
+
self_deployment = self_deployment_by_id.get(id)
|
50
|
+
other_deployment = other_deployment_by_id.get(id)
|
51
|
+
if self_deployment and other_deployment:
|
52
|
+
merged_deployments.append(self_deployment.merge(other_deployment))
|
53
|
+
elif self_deployment:
|
54
|
+
merged_deployments.append(self_deployment)
|
55
|
+
elif other_deployment:
|
56
|
+
merged_deployments.append(other_deployment)
|
57
|
+
|
58
|
+
for deployment in self.deployments:
|
59
|
+
if deployment.id is None:
|
60
|
+
merged_deployments.append(deployment)
|
61
|
+
|
62
|
+
for deployment in other.deployments:
|
63
|
+
if deployment.id is None:
|
64
|
+
merged_deployments.append(deployment)
|
65
|
+
|
31
66
|
return WorkflowConfig(
|
32
67
|
module=self.module,
|
33
68
|
workflow_sandbox_id=self.workflow_sandbox_id or other.workflow_sandbox_id,
|
34
69
|
ignore=self.ignore or other.ignore,
|
70
|
+
deployments=merged_deployments,
|
35
71
|
)
|
36
72
|
|
37
73
|
|
vellum_cli/push.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
from importlib import metadata
|
1
2
|
import io
|
2
3
|
import json
|
3
4
|
import os
|
@@ -50,6 +51,9 @@ def push_command(
|
|
50
51
|
workflow = BaseWorkflow.load_from_module(workflow_config.module)
|
51
52
|
workflow_display = get_workflow_display(base_display_class=VellumWorkflowDisplay, workflow_class=workflow)
|
52
53
|
exec_config = workflow_display.serialize()
|
54
|
+
exec_config["runner_config"] = {
|
55
|
+
"sdk_version": metadata.version("vellum-ai"),
|
56
|
+
}
|
53
57
|
|
54
58
|
label = snake_to_title_case(workflow_config.module.split(".")[-1])
|
55
59
|
|
vellum_cli/tests/conftest.py
CHANGED
@@ -1,19 +1,29 @@
|
|
1
1
|
import pytest
|
2
|
+
from dataclasses import dataclass
|
2
3
|
import os
|
3
4
|
import shutil
|
4
5
|
import tempfile
|
5
6
|
from uuid import uuid4
|
6
|
-
from typing import Any, Callable, Dict, Generator
|
7
|
+
from typing import Any, Callable, Dict, Generator
|
7
8
|
|
8
9
|
import tomli_w
|
9
10
|
|
10
11
|
|
12
|
+
@dataclass
|
13
|
+
class MockModuleResult:
|
14
|
+
temp_dir: str
|
15
|
+
module: str
|
16
|
+
set_pyproject_toml: Callable[[Dict[str, Any]], None]
|
17
|
+
workflow_sandbox_id: str
|
18
|
+
|
19
|
+
|
11
20
|
@pytest.fixture
|
12
|
-
def mock_module() -> Generator[
|
21
|
+
def mock_module() -> Generator[MockModuleResult, None, None]:
|
13
22
|
current_dir = os.getcwd()
|
14
23
|
temp_dir = tempfile.mkdtemp()
|
15
24
|
os.chdir(temp_dir)
|
16
25
|
module = "examples.mock"
|
26
|
+
workflow_sandbox_id = str(uuid4())
|
17
27
|
|
18
28
|
def set_pyproject_toml(vellum_config: Dict[str, Any]) -> None:
|
19
29
|
pyproject_toml_path = os.path.join(temp_dir, "pyproject.toml")
|
@@ -28,13 +38,18 @@ def mock_module() -> Generator[Tuple[str, str, Callable[[Dict[str, Any]], None]]
|
|
28
38
|
"workflows": [
|
29
39
|
{
|
30
40
|
"module": module,
|
31
|
-
"workflow_sandbox_id":
|
41
|
+
"workflow_sandbox_id": workflow_sandbox_id,
|
32
42
|
}
|
33
43
|
]
|
34
44
|
}
|
35
45
|
)
|
36
46
|
|
37
|
-
yield
|
47
|
+
yield MockModuleResult(
|
48
|
+
temp_dir=temp_dir,
|
49
|
+
module=module,
|
50
|
+
set_pyproject_toml=set_pyproject_toml,
|
51
|
+
workflow_sandbox_id=workflow_sandbox_id,
|
52
|
+
)
|
38
53
|
|
39
54
|
os.chdir(current_dir)
|
40
55
|
shutil.rmtree(temp_dir)
|
vellum_cli/tests/test_pull.py
CHANGED
@@ -37,7 +37,8 @@ def _zip_file_map(file_map: dict[str, str]) -> bytes:
|
|
37
37
|
)
|
38
38
|
def test_pull(vellum_client, mock_module, base_command):
|
39
39
|
# GIVEN a module on the user's filesystem
|
40
|
-
temp_dir
|
40
|
+
temp_dir = mock_module.temp_dir
|
41
|
+
module = mock_module.module
|
41
42
|
|
42
43
|
# AND the workflow pull API call returns a zip file
|
43
44
|
vellum_client.workflows.pull.return_value = iter([_zip_file_map({"workflow.py": "print('hello')"})])
|
@@ -58,7 +59,9 @@ def test_pull(vellum_client, mock_module, base_command):
|
|
58
59
|
|
59
60
|
def test_pull__second_module(vellum_client, mock_module):
|
60
61
|
# GIVEN a module on the user's filesystem
|
61
|
-
temp_dir
|
62
|
+
temp_dir = mock_module.temp_dir
|
63
|
+
module = mock_module.module
|
64
|
+
set_pyproject_toml = mock_module.set_pyproject_toml
|
62
65
|
|
63
66
|
# AND the workflow pull API call returns a zip file
|
64
67
|
vellum_client.workflows.pull.return_value = iter([_zip_file_map({"workflow.py": "print('hello')"})])
|
@@ -134,7 +137,7 @@ def test_pull__sandbox_id_with_no_config(vellum_client):
|
|
134
137
|
|
135
138
|
def test_pull__sandbox_id_with_other_workflow_configured(vellum_client, mock_module):
|
136
139
|
# GIVEN a pyproject.toml with a workflow configured
|
137
|
-
temp_dir
|
140
|
+
temp_dir = mock_module.temp_dir
|
138
141
|
|
139
142
|
# AND a different workflow sandbox id
|
140
143
|
workflow_sandbox_id = "87654321-0000-0000-0000-000000000000"
|
@@ -163,7 +166,8 @@ def test_pull__sandbox_id_with_other_workflow_configured(vellum_client, mock_mod
|
|
163
166
|
|
164
167
|
def test_pull__remove_missing_files(vellum_client, mock_module):
|
165
168
|
# GIVEN a module on the user's filesystem
|
166
|
-
temp_dir
|
169
|
+
temp_dir = mock_module.temp_dir
|
170
|
+
module = mock_module.module
|
167
171
|
|
168
172
|
# AND the workflow pull API call returns a zip file
|
169
173
|
vellum_client.workflows.pull.return_value = iter([_zip_file_map({"workflow.py": "print('hello')"})])
|
@@ -192,7 +196,9 @@ def test_pull__remove_missing_files(vellum_client, mock_module):
|
|
192
196
|
|
193
197
|
def test_pull__remove_missing_files__ignore_pattern(vellum_client, mock_module):
|
194
198
|
# GIVEN a module on the user's filesystem
|
195
|
-
temp_dir
|
199
|
+
temp_dir = mock_module.temp_dir
|
200
|
+
module = mock_module.module
|
201
|
+
set_pyproject_toml = mock_module.set_pyproject_toml
|
196
202
|
|
197
203
|
# AND the workflow pull API call returns a zip file
|
198
204
|
vellum_client.workflows.pull.return_value = iter([_zip_file_map({"workflow.py": "print('hello')"})])
|
@@ -243,7 +249,7 @@ def test_pull__remove_missing_files__ignore_pattern(vellum_client, mock_module):
|
|
243
249
|
|
244
250
|
def test_pull__include_json(vellum_client, mock_module):
|
245
251
|
# GIVEN a module on the user's filesystem
|
246
|
-
|
252
|
+
module = mock_module.module
|
247
253
|
|
248
254
|
# AND the workflow pull API call returns a zip file
|
249
255
|
vellum_client.workflows.pull.return_value = iter(
|
@@ -265,7 +271,7 @@ def test_pull__include_json(vellum_client, mock_module):
|
|
265
271
|
|
266
272
|
def test_pull__exclude_code(vellum_client, mock_module):
|
267
273
|
# GIVEN a module on the user's filesystem
|
268
|
-
|
274
|
+
module = mock_module.module
|
269
275
|
|
270
276
|
# AND the workflow pull API call returns a zip file
|
271
277
|
vellum_client.workflows.pull.return_value = iter(
|
@@ -283,3 +289,75 @@ def test_pull__exclude_code(vellum_client, mock_module):
|
|
283
289
|
vellum_client.workflows.pull.assert_called_once()
|
284
290
|
call_args = vellum_client.workflows.pull.call_args.kwargs
|
285
291
|
assert call_args["request_options"]["additional_query_parameters"] == {"exclude_code": True}
|
292
|
+
|
293
|
+
|
294
|
+
def test_pull__sandbox_id_with_other_workflow_deployment_in_lock(vellum_client, mock_module):
|
295
|
+
# GIVEN a pyproject.toml with a workflow configured
|
296
|
+
temp_dir = mock_module.temp_dir
|
297
|
+
module = mock_module.module
|
298
|
+
workflow_sandbox_id = mock_module.workflow_sandbox_id
|
299
|
+
|
300
|
+
# AND there's a workflow deployment in the lock file
|
301
|
+
vellum_lock_json = os.path.join(temp_dir, "vellum.lock.json")
|
302
|
+
with open(vellum_lock_json, "w") as f:
|
303
|
+
json.dump(
|
304
|
+
{
|
305
|
+
"version": "1.0",
|
306
|
+
"workflows": [
|
307
|
+
{
|
308
|
+
"module": module,
|
309
|
+
"workflow_sandbox_id": "0edc07cd-45b9-43e8-99bc-1f181972a857",
|
310
|
+
"ignore": "tests/*",
|
311
|
+
"deployments": [
|
312
|
+
{
|
313
|
+
"id": "7e5a7610-4c46-4bc9-b06e-0fc6a9e28959",
|
314
|
+
"label": None,
|
315
|
+
"name": None,
|
316
|
+
"description": None,
|
317
|
+
"release_tags": None,
|
318
|
+
}
|
319
|
+
],
|
320
|
+
}
|
321
|
+
],
|
322
|
+
},
|
323
|
+
f,
|
324
|
+
)
|
325
|
+
|
326
|
+
# AND a different workflow sandbox id
|
327
|
+
new_workflow_sandbox_id = "87654321-0000-0000-0000-000000000000"
|
328
|
+
|
329
|
+
# AND the workflow pull API call returns a zip file
|
330
|
+
vellum_client.workflows.pull.return_value = iter([_zip_file_map({"workflow.py": "print('hello')"})])
|
331
|
+
|
332
|
+
# WHEN the user runs the pull command with the new workflow sandbox id
|
333
|
+
runner = CliRunner()
|
334
|
+
result = runner.invoke(cli_main, ["workflows", "pull", "--workflow-sandbox-id", new_workflow_sandbox_id])
|
335
|
+
|
336
|
+
# THEN the command returns successfully
|
337
|
+
assert result.exit_code == 0
|
338
|
+
|
339
|
+
# AND the lock file is updated to preserve the deployment and include the new workflow
|
340
|
+
with open(vellum_lock_json) as f:
|
341
|
+
lock_data = json.load(f)
|
342
|
+
assert lock_data["workflows"] == [
|
343
|
+
{
|
344
|
+
"module": module,
|
345
|
+
"workflow_sandbox_id": workflow_sandbox_id,
|
346
|
+
"ignore": "tests/*",
|
347
|
+
"deployments": [
|
348
|
+
{
|
349
|
+
"id": "7e5a7610-4c46-4bc9-b06e-0fc6a9e28959",
|
350
|
+
"label": None,
|
351
|
+
"name": None,
|
352
|
+
"description": None,
|
353
|
+
"release_tags": None,
|
354
|
+
},
|
355
|
+
],
|
356
|
+
},
|
357
|
+
{
|
358
|
+
"module": "workflow_87654321",
|
359
|
+
"workflow_sandbox_id": new_workflow_sandbox_id,
|
360
|
+
"ignore": None,
|
361
|
+
"deployments": [],
|
362
|
+
},
|
363
|
+
]
|
vellum_cli/tests/test_push.py
CHANGED
@@ -29,8 +29,7 @@ def _extract_tar_gz(tar_gz_bytes: bytes) -> dict[str, str]:
|
|
29
29
|
|
30
30
|
def test_push__no_config(mock_module):
|
31
31
|
# GIVEN no config file set
|
32
|
-
|
33
|
-
set_pyproject_toml({"workflows": []})
|
32
|
+
mock_module.set_pyproject_toml({"workflows": []})
|
34
33
|
|
35
34
|
# WHEN calling `vellum push`
|
36
35
|
runner = CliRunner()
|
@@ -44,8 +43,7 @@ def test_push__no_config(mock_module):
|
|
44
43
|
|
45
44
|
def test_push__multiple_workflows_configured__no_module_specified(mock_module):
|
46
45
|
# GIVEN multiple workflows configured
|
47
|
-
|
48
|
-
set_pyproject_toml({"workflows": [{"module": "examples.mock"}, {"module": "examples.mock2"}]})
|
46
|
+
mock_module.set_pyproject_toml({"workflows": [{"module": "examples.mock"}, {"module": "examples.mock2"}]})
|
49
47
|
|
50
48
|
# WHEN calling `vellum push` without a module specified
|
51
49
|
runner = CliRunner()
|
@@ -62,8 +60,8 @@ def test_push__multiple_workflows_configured__no_module_specified(mock_module):
|
|
62
60
|
|
63
61
|
def test_push__multiple_workflows_configured__not_found_module(mock_module):
|
64
62
|
# GIVEN multiple workflows configured
|
65
|
-
|
66
|
-
set_pyproject_toml({"workflows": [{"module": "examples.mock2"}, {"module": "examples.mock3"}]})
|
63
|
+
module = mock_module.module
|
64
|
+
mock_module.set_pyproject_toml({"workflows": [{"module": "examples.mock2"}, {"module": "examples.mock3"}]})
|
67
65
|
|
68
66
|
# WHEN calling `vellum push` with a module that doesn't exist
|
69
67
|
runner = CliRunner()
|
@@ -85,7 +83,8 @@ def test_push__multiple_workflows_configured__not_found_module(mock_module):
|
|
85
83
|
)
|
86
84
|
def test_push__happy_path(mock_module, vellum_client, base_command):
|
87
85
|
# GIVEN a single workflow configured
|
88
|
-
temp_dir
|
86
|
+
temp_dir = mock_module.temp_dir
|
87
|
+
module = mock_module.module
|
89
88
|
|
90
89
|
# AND a workflow exists in the module successfully
|
91
90
|
base_dir = os.path.join(temp_dir, *module.split("."))
|
@@ -134,7 +133,8 @@ class ExampleWorkflow(BaseWorkflow):
|
|
134
133
|
)
|
135
134
|
def test_push__deployment(mock_module, vellum_client, base_command):
|
136
135
|
# GIVEN a single workflow configured
|
137
|
-
temp_dir
|
136
|
+
temp_dir = mock_module.temp_dir
|
137
|
+
module = mock_module.module
|
138
138
|
|
139
139
|
# AND a workflow exists in the module successfully
|
140
140
|
base_dir = os.path.join(temp_dir, *module.split("."))
|
@@ -39,7 +39,6 @@ class BaseErrorNodeDisplay(BaseNodeVellumDisplay[_ErrorNodeType], Generic[_Error
|
|
39
39
|
"data": {
|
40
40
|
"name": self.name,
|
41
41
|
"label": self.label,
|
42
|
-
"source_handle_id": str(self.get_source_handle_id(display_context.port_displays)),
|
43
42
|
"target_handle_id": str(self.get_target_handle_id()),
|
44
43
|
"error_source_input_id": str(error_source_input_id),
|
45
44
|
"error_output_id": str(self.error_output_id),
|
@@ -15,7 +15,7 @@ from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
|
|
15
15
|
from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
|
16
16
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
17
17
|
from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
|
18
|
-
from vellum_ee.workflows.display.vellum import NodeInput
|
18
|
+
from vellum_ee.workflows.display.vellum import InputVariablePointer, NodeInput
|
19
19
|
|
20
20
|
_SearchNodeType = TypeVar("_SearchNodeType", bound=SearchNode)
|
21
21
|
|
@@ -28,7 +28,7 @@ class VariableIdMap:
|
|
28
28
|
|
29
29
|
|
30
30
|
class BaseSearchNodeDisplay(BaseNodeVellumDisplay[_SearchNodeType], Generic[_SearchNodeType]):
|
31
|
-
|
31
|
+
input_variable_ids_by_logical_id: Optional[Dict[str, str]] = None
|
32
32
|
|
33
33
|
def serialize(
|
34
34
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
@@ -128,7 +128,6 @@ class BaseSearchNodeDisplay(BaseNodeVellumDisplay[_SearchNodeType], Generic[_Sea
|
|
128
128
|
logical_expression: Union[VellumValueLogicalConditionGroupRequest, VellumValueLogicalConditionRequest],
|
129
129
|
display_context: WorkflowDisplayContext,
|
130
130
|
path: List[int] = [],
|
131
|
-
variable_id_map: Optional[VariableIdMap] = None,
|
132
131
|
) -> Tuple[JsonObject, List[NodeInput]]:
|
133
132
|
if isinstance(logical_expression, VellumValueLogicalConditionGroupRequest):
|
134
133
|
conditions: JsonArray = []
|
@@ -150,38 +149,42 @@ class BaseSearchNodeDisplay(BaseNodeVellumDisplay[_SearchNodeType], Generic[_Sea
|
|
150
149
|
variables,
|
151
150
|
)
|
152
151
|
elif isinstance(logical_expression, VellumValueLogicalConditionRequest):
|
153
|
-
lhs_variable_id = (
|
154
|
-
|
155
|
-
|
156
|
-
|
152
|
+
lhs_variable_id = str(logical_expression.lhs_variable.value)
|
153
|
+
rhs_variable_id = str(logical_expression.rhs_variable.value)
|
154
|
+
lhs_query_input_id = (
|
155
|
+
self.input_variable_ids_by_logical_id[lhs_variable_id]
|
156
|
+
if self.input_variable_ids_by_logical_id
|
157
|
+
else uuid4_from_hash(f"{self.node_id}|{hash(path)}")
|
157
158
|
)
|
158
|
-
|
159
|
-
|
160
|
-
if
|
161
|
-
else uuid4_from_hash(f"{self.node_id}|{hash(
|
159
|
+
rhs_query_input_id = (
|
160
|
+
self.input_variable_ids_by_logical_id[rhs_variable_id]
|
161
|
+
if self.input_variable_ids_by_logical_id
|
162
|
+
else uuid4_from_hash(f"{self.node_id}|{hash(path)}")
|
162
163
|
)
|
163
164
|
|
164
165
|
return (
|
165
166
|
{
|
166
167
|
"type": "LOGICAL_CONDITION",
|
167
|
-
"
|
168
|
+
"lhs_variable_id": str(lhs_variable_id),
|
168
169
|
"operator": logical_expression.operator,
|
169
|
-
"
|
170
|
+
"rhs_variable_id": str(rhs_variable_id),
|
170
171
|
},
|
171
172
|
[
|
172
173
|
create_node_input(
|
173
174
|
self.node_id,
|
174
175
|
f"vellum-query-builder-variable-{lhs_variable_id}",
|
175
|
-
|
176
|
+
lhs_query_input_id,
|
176
177
|
display_context,
|
177
|
-
input_id=lhs_variable_id,
|
178
|
+
input_id=UUID(lhs_variable_id),
|
179
|
+
pointer_type=InputVariablePointer,
|
178
180
|
),
|
179
181
|
create_node_input(
|
180
182
|
self.node_id,
|
181
183
|
f"vellum-query-builder-variable-{rhs_variable_id}",
|
182
|
-
|
184
|
+
rhs_query_input_id,
|
183
185
|
display_context,
|
184
|
-
input_id=rhs_variable_id,
|
186
|
+
input_id=UUID(rhs_variable_id),
|
187
|
+
pointer_type=InputVariablePointer,
|
185
188
|
),
|
186
189
|
],
|
187
190
|
)
|
@@ -10,6 +10,10 @@ from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
|
|
10
10
|
from vellum_ee.workflows.display.utils.vellum import create_node_input_value_pointer_rule, primitive_to_vellum_value
|
11
11
|
from vellum_ee.workflows.display.vellum import (
|
12
12
|
ConstantValuePointer,
|
13
|
+
ExecutionCounterData,
|
14
|
+
ExecutionCounterPointer,
|
15
|
+
InputVariableData,
|
16
|
+
InputVariablePointer,
|
13
17
|
NodeInput,
|
14
18
|
NodeInputValuePointer,
|
15
19
|
NodeInputValuePointerRule,
|
@@ -93,4 +97,15 @@ def create_pointer(
|
|
93
97
|
)
|
94
98
|
|
95
99
|
vellum_variable_value = primitive_to_vellum_value(value)
|
96
|
-
|
100
|
+
if pointer_type is InputVariablePointer:
|
101
|
+
return InputVariablePointer(type="INPUT_VARIABLE", data=InputVariableData(input_variable_id=value))
|
102
|
+
elif pointer_type is WorkspaceSecretPointer:
|
103
|
+
return WorkspaceSecretPointer(
|
104
|
+
type="WORKSPACE_SECRET", data=WorkspaceSecretData(type="STRING", workspace_secret_id=value)
|
105
|
+
)
|
106
|
+
elif pointer_type is ExecutionCounterPointer:
|
107
|
+
return ExecutionCounterPointer(type="EXECUTION_COUNTER", data=ExecutionCounterData(node_id=value))
|
108
|
+
elif pointer_type is ConstantValuePointer or pointer_type is None:
|
109
|
+
return ConstantValuePointer(type="CONSTANT_VALUE", data=vellum_variable_value)
|
110
|
+
else:
|
111
|
+
raise ValueError(f"Pointer type {pointer_type} not supported")
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py
CHANGED
@@ -102,7 +102,6 @@ def test_serialize_workflow():
|
|
102
102
|
"data": {
|
103
103
|
"name": "error-node",
|
104
104
|
"label": "Fail Node",
|
105
|
-
"source_handle_id": "ca17d318-a0f5-4f7c-be6c-59c9dc1dd7ed",
|
106
105
|
"target_handle_id": "70c19f1c-309c-4a5d-ba65-664c0bb2fedf",
|
107
106
|
"error_source_input_id": "None",
|
108
107
|
"error_output_id": "None",
|
File without changes
|
File without changes
|
File without changes
|