vellum-ai 0.14.69__py3-none-any.whl → 0.14.70__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/workflows/environment/__init__.py +2 -1
- vellum/workflows/environment/environment.py +5 -1
- vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py +77 -1
- vellum/workflows/nodes/experimental/tool_calling_node/utils.py +2 -2
- vellum/workflows/references/environment_variable.py +2 -3
- {vellum_ai-0.14.69.dist-info → vellum_ai-0.14.70.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.69.dist-info → vellum_ai-0.14.70.dist-info}/RECORD +42 -38
- vellum_cli/__init__.py +5 -2
- vellum_cli/image_push.py +24 -1
- vellum_cli/tests/test_image_push.py +103 -12
- vellum_ee/workflows/display/nodes/base_node_display.py +1 -1
- vellum_ee/workflows/display/nodes/utils.py +2 -2
- vellum_ee/workflows/display/nodes/vellum/api_node.py +2 -2
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/conditional_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/error_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/final_output_node.py +2 -2
- vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +9 -1
- vellum_ee/workflows/display/nodes/vellum/map_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/merge_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/note_node.py +1 -0
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/retry_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/search_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/templating_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/tests/test_inline_subworkflow_node.py +88 -0
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +16 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +9 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +59 -297
- vellum_ee/workflows/display/utils/auto_layout.py +130 -0
- vellum_ee/workflows/display/utils/expressions.py +7 -0
- vellum_ee/workflows/display/utils/tests/__init__.py +0 -0
- vellum_ee/workflows/display/utils/tests/test_auto_layout.py +56 -0
- vellum_ee/workflows/display/workflows/base_workflow_display.py +15 -10
- vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +41 -0
- {vellum_ai-0.14.69.dist-info → vellum_ai-0.14.70.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.69.dist-info → vellum_ai-0.14.70.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.69.dist-info → vellum_ai-0.14.70.dist-info}/entry_points.txt +0 -0
@@ -18,7 +18,7 @@ class BaseClientWrapper:
|
|
18
18
|
headers: typing.Dict[str, str] = {
|
19
19
|
"X-Fern-Language": "Python",
|
20
20
|
"X-Fern-SDK-Name": "vellum-ai",
|
21
|
-
"X-Fern-SDK-Version": "0.14.
|
21
|
+
"X-Fern-SDK-Version": "0.14.70",
|
22
22
|
}
|
23
23
|
headers["X-API-KEY"] = self.api_key
|
24
24
|
return headers
|
@@ -3,7 +3,11 @@ from typing import Optional
|
|
3
3
|
from vellum.workflows.references import EnvironmentVariableReference
|
4
4
|
|
5
5
|
|
6
|
-
class
|
6
|
+
class EnvironmentVariables:
|
7
7
|
@staticmethod
|
8
8
|
def get(name: str, default: Optional[str] = None) -> EnvironmentVariableReference:
|
9
9
|
return EnvironmentVariableReference(name=name, default=default)
|
10
|
+
|
11
|
+
|
12
|
+
# Deprecated: Use EnvironmentVariables instead. Will be removed in v0.15.0
|
13
|
+
Environment = EnvironmentVariables
|
@@ -1,7 +1,17 @@
|
|
1
|
+
import json
|
2
|
+
from typing import Any, List
|
3
|
+
|
4
|
+
from vellum import ChatMessage
|
1
5
|
from vellum.client.types.function_call import FunctionCall
|
2
6
|
from vellum.client.types.function_call_vellum_value import FunctionCallVellumValue
|
3
|
-
from vellum.
|
7
|
+
from vellum.client.types.string_chat_message_content import StringChatMessageContent
|
8
|
+
from vellum.workflows import BaseWorkflow
|
9
|
+
from vellum.workflows.inputs.base import BaseInputs
|
10
|
+
from vellum.workflows.nodes.bases import BaseNode
|
11
|
+
from vellum.workflows.nodes.experimental.tool_calling_node.utils import create_function_node, create_tool_router_node
|
12
|
+
from vellum.workflows.outputs.base import BaseOutputs
|
4
13
|
from vellum.workflows.state.base import BaseState, StateMeta
|
14
|
+
from vellum.workflows.state.context import WorkflowContext
|
5
15
|
|
6
16
|
|
7
17
|
def first_function() -> str:
|
@@ -51,3 +61,69 @@ def test_port_condition_match_function_name():
|
|
51
61
|
# AND the default port should be false
|
52
62
|
default_port = getattr(router_node.Ports, "default")
|
53
63
|
assert default_port.resolve_condition(state) is False
|
64
|
+
|
65
|
+
|
66
|
+
def test_tool_calling_node_inline_workflow_context():
|
67
|
+
"""
|
68
|
+
Test that the tool calling node correctly passes the context to the inline workflow.
|
69
|
+
This specifically tests that inline workflows receive the correct context.
|
70
|
+
"""
|
71
|
+
|
72
|
+
# GIVEN a test workflow that captures its context
|
73
|
+
class MyNode(BaseNode):
|
74
|
+
class Outputs(BaseOutputs):
|
75
|
+
generated_files: Any
|
76
|
+
|
77
|
+
def run(self) -> Outputs:
|
78
|
+
return self.Outputs(generated_files=self._context.generated_files)
|
79
|
+
|
80
|
+
class MyWorkflow(BaseWorkflow[BaseInputs, BaseState]):
|
81
|
+
graph = MyNode
|
82
|
+
|
83
|
+
class Outputs(BaseOutputs):
|
84
|
+
generated_files = MyNode.Outputs.generated_files
|
85
|
+
|
86
|
+
# GIVEN a tool router node
|
87
|
+
tool_router_node = create_tool_router_node(
|
88
|
+
ml_model="test-model",
|
89
|
+
blocks=[],
|
90
|
+
functions=[MyWorkflow],
|
91
|
+
prompt_inputs=None,
|
92
|
+
)
|
93
|
+
|
94
|
+
# WHEN we create a function node for the workflow
|
95
|
+
function_node_class = create_function_node(
|
96
|
+
function=MyWorkflow,
|
97
|
+
tool_router_node=tool_router_node,
|
98
|
+
)
|
99
|
+
|
100
|
+
# AND we create an instance with a context containing generated_files
|
101
|
+
function_node = function_node_class()
|
102
|
+
|
103
|
+
# Create a parent context with test data
|
104
|
+
parent_context = WorkflowContext(
|
105
|
+
generated_files={"script.py": "print('hello world')"},
|
106
|
+
)
|
107
|
+
function_node._context = parent_context
|
108
|
+
|
109
|
+
# Create a state with chat_history for the function node
|
110
|
+
class TestState(BaseState):
|
111
|
+
chat_history: List[ChatMessage] = []
|
112
|
+
|
113
|
+
function_node.state = TestState(meta=StateMeta(node_outputs={tool_router_node.Outputs.text: '{"arguments": {}}'}))
|
114
|
+
|
115
|
+
# WHEN the function node runs
|
116
|
+
outputs = function_node.run()
|
117
|
+
|
118
|
+
# THEN the workflow should have run successfully
|
119
|
+
assert outputs is not None
|
120
|
+
|
121
|
+
# AND the chat history should contain a function response
|
122
|
+
assert len(function_node.state.chat_history) == 1
|
123
|
+
function_response = function_node.state.chat_history[0]
|
124
|
+
assert function_response.role == "FUNCTION"
|
125
|
+
|
126
|
+
# AND the response should contain the generated files
|
127
|
+
assert isinstance(function_response.content, StringChatMessageContent)
|
128
|
+
data = json.loads(function_response.content.value)
|
129
|
+
assert data["generated_files"] == {"script.py": "print('hello world')"}
|
@@ -22,6 +22,7 @@ from vellum.workflows.outputs.base import BaseOutput
|
|
22
22
|
from vellum.workflows.ports.port import Port
|
23
23
|
from vellum.workflows.references.lazy import LazyReference
|
24
24
|
from vellum.workflows.state.base import BaseState
|
25
|
+
from vellum.workflows.state.context import WorkflowContext
|
25
26
|
from vellum.workflows.state.encoder import DefaultStateEncoder
|
26
27
|
from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior
|
27
28
|
from vellum.workflows.types.generics import is_workflow_class
|
@@ -152,8 +153,7 @@ def create_function_node(
|
|
152
153
|
|
153
154
|
# Call the function based on its type
|
154
155
|
inputs_instance = function.get_inputs_class()(**arguments)
|
155
|
-
|
156
|
-
workflow = function()
|
156
|
+
workflow = function(context=WorkflowContext.create_from(self._context))
|
157
157
|
terminal_event = workflow.run(
|
158
158
|
inputs=inputs_instance,
|
159
159
|
)
|
@@ -8,7 +8,7 @@ if TYPE_CHECKING:
|
|
8
8
|
|
9
9
|
|
10
10
|
class EnvironmentVariableReference(BaseDescriptor[str]):
|
11
|
-
def __init__(self, *, name: str, default: Optional[str]):
|
11
|
+
def __init__(self, *, name: str, default: Optional[str] = None):
|
12
12
|
super().__init__(name=name, types=(str,))
|
13
13
|
self._default = default
|
14
14
|
|
@@ -20,5 +20,4 @@ class EnvironmentVariableReference(BaseDescriptor[str]):
|
|
20
20
|
if self._default is not None:
|
21
21
|
return self._default
|
22
22
|
|
23
|
-
|
24
|
-
raise ValueError(f"No environment variable named '{self.name}' found")
|
23
|
+
return ""
|
@@ -1,9 +1,9 @@
|
|
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=oi-vvNVepu23IBBjhA5uUIDVYBPqQ3EzxWZAPn2S64c,12700
|
4
4
|
vellum_cli/aliased_group.py,sha256=ugW498j0yv4ALJ8vS9MsO7ctDW7Jlir9j6nE_uHAP8c,3363
|
5
5
|
vellum_cli/config.py,sha256=v5BmZ-t_v4Jmqd7KVuQMZF2pRI-rbMspSkVYXIRoTmI,9448
|
6
|
-
vellum_cli/image_push.py,sha256=
|
6
|
+
vellum_cli/image_push.py,sha256=Xw_IlItZ27OM5XrWcaqRxXCx4rroV3IaUByl8Ela6U8,10730
|
7
7
|
vellum_cli/init.py,sha256=WpnMXPItPmh0f0bBGIer3p-e5gu8DUGwSArT_FuoMEw,5093
|
8
8
|
vellum_cli/logger.py,sha256=dcM_OmgqXLo93vDYswO5ylyUQQcTfnA5GTd5tbIt3wM,1446
|
9
9
|
vellum_cli/ping.py,sha256=p_BCCRjgPhng6JktuECtkDQLbhopt6JpmrtGoLnLJT8,1161
|
@@ -12,7 +12,7 @@ vellum_cli/push.py,sha256=wxRlFu2mYW9SvwODYxwajri1mDQ2be0n-9i0d9QAc30,10194
|
|
12
12
|
vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
13
|
vellum_cli/tests/conftest.py,sha256=AFYZryKA2qnUuCPBxBKmHLFoPiE0WhBFFej9tNwSHdc,1526
|
14
14
|
vellum_cli/tests/test_config.py,sha256=uvKGDc8BoVyT9_H0Z-g8469zVxomn6Oi3Zj-vK7O_wU,2631
|
15
|
-
vellum_cli/tests/test_image_push.py,sha256=
|
15
|
+
vellum_cli/tests/test_image_push.py,sha256=QGbhCB2DhkepoBUdfhv_ovks-HQ164jmjKFuYvPmJt8,9141
|
16
16
|
vellum_cli/tests/test_image_push_error_handling.py,sha256=_Wjfkn1orI2K4Ahzqz4u8T13or7NOX01K4BtcTuTIOM,7107
|
17
17
|
vellum_cli/tests/test_init.py,sha256=8UOc_ThfouR4ja5cCl_URuLk7ohr9JXfCnG4yka1OUQ,18754
|
18
18
|
vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
|
@@ -27,33 +27,34 @@ vellum_ee/workflows/display/base.py,sha256=EqlQFD56kpqMY02ZBJBQajzJKh33Dwi60Wo77
|
|
27
27
|
vellum_ee/workflows/display/editor/__init__.py,sha256=MSAgY91xCEg2neH5d8jXx5wRdR962ftZVa6vO9BGq9k,167
|
28
28
|
vellum_ee/workflows/display/editor/types.py,sha256=x-tOOCJ6CF4HmiKDfCmcc3bOVfc1EBlP5o6u5WEfLoY,567
|
29
29
|
vellum_ee/workflows/display/nodes/__init__.py,sha256=jI1aPBQf8DkmrYoZ4O-wR1duqZByOf5mDFmo_wFJPE4,307
|
30
|
-
vellum_ee/workflows/display/nodes/base_node_display.py,sha256=
|
30
|
+
vellum_ee/workflows/display/nodes/base_node_display.py,sha256=8Iio5O2Lu7XA5EfCWhXNZVzEOiaXO4eMdssczGBKXxU,16922
|
31
31
|
vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=jI_kUi9LnNLDpY63QtlC4TfN8P571VN4LpzH0I1ZtLk,1149
|
32
32
|
vellum_ee/workflows/display/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
33
|
vellum_ee/workflows/display/nodes/tests/test_base_node_display.py,sha256=Z4Mf7xLCNiblSbpKI0BrV5modQr-ZcFzhfir_OSyTTs,2997
|
34
34
|
vellum_ee/workflows/display/nodes/types.py,sha256=St1BB6no528OyELGiyRabWao0GGw6mLhstQAvEACbGk,247
|
35
|
-
vellum_ee/workflows/display/nodes/utils.py,sha256=
|
35
|
+
vellum_ee/workflows/display/nodes/utils.py,sha256=gxiixuiJi6jrYTV2jmsPsyQfeuwKmrULRb-Lg9c0Aqw,975
|
36
36
|
vellum_ee/workflows/display/nodes/vellum/__init__.py,sha256=nUIgH2s0-7IbQRNrBhLPyRNe8YIrx3Yo9HeeW-aXXFk,1668
|
37
|
-
vellum_ee/workflows/display/nodes/vellum/api_node.py,sha256=
|
37
|
+
vellum_ee/workflows/display/nodes/vellum/api_node.py,sha256=5Uq8x08F64yrBcqbfsVeuoGnTa9eoOPumYzZZrDPmr0,8847
|
38
38
|
vellum_ee/workflows/display/nodes/vellum/base_adornment_node.py,sha256=rJbHZBg9A_v2bjk-R6MfWzShcrS2gcKIOyYGoqwTx8s,6353
|
39
|
-
vellum_ee/workflows/display/nodes/vellum/code_execution_node.py,sha256=
|
40
|
-
vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=
|
41
|
-
vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=
|
42
|
-
vellum_ee/workflows/display/nodes/vellum/final_output_node.py,sha256=
|
43
|
-
vellum_ee/workflows/display/nodes/vellum/guardrail_node.py,sha256=
|
44
|
-
vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=
|
45
|
-
vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py,sha256=
|
46
|
-
vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=
|
47
|
-
vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=
|
48
|
-
vellum_ee/workflows/display/nodes/vellum/note_node.py,sha256=
|
49
|
-
vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py,sha256=
|
50
|
-
vellum_ee/workflows/display/nodes/vellum/retry_node.py,sha256=
|
51
|
-
vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=
|
52
|
-
vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py,sha256=
|
53
|
-
vellum_ee/workflows/display/nodes/vellum/templating_node.py,sha256=
|
39
|
+
vellum_ee/workflows/display/nodes/vellum/code_execution_node.py,sha256=6lavdBw297GwAQqyxjnPUtx5pHv6k5V9Vkuq7s2D0TM,4508
|
40
|
+
vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=9GtbvSJUNF626tCYxnMxETVZm3Fq84vOZ3Nkdkl3n-M,11146
|
41
|
+
vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=YhMsi2TG1zSR8E7IpxzzSncOyVLcvqTuGa3mr4RqHd8,2364
|
42
|
+
vellum_ee/workflows/display/nodes/vellum/final_output_node.py,sha256=zo-nalsuayMqeb2GwR2OB9SFK3y2U5aG-rtwrsjdasQ,3089
|
43
|
+
vellum_ee/workflows/display/nodes/vellum/guardrail_node.py,sha256=IniO5KvO0Rw9zghFg3RFvbXBTv6Zi1iuQhaA1DLazqU,2331
|
44
|
+
vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=W_ijZBO9EsiyLM_tKyBkVu3V5h3QDx2JB-Tfs1xb-BE,10955
|
45
|
+
vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py,sha256=f7MeoxgKrdyb1dSJsvdDtZPlp1J2Pa4njPvN3qHVktA,6028
|
46
|
+
vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=uaZ2wcZR1J9C9iI0QWAsgNK9IlcuCz1808oxXmiYsLY,3908
|
47
|
+
vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=RTP_raQWL8ZKoRKLpxLfpyXzw61TZeTCkTuM1uRLIkI,3274
|
48
|
+
vellum_ee/workflows/display/nodes/vellum/note_node.py,sha256=6xf8MJ684KecKPJrGlCJuJYLPtYImXmqN85Y_6KPjW4,1141
|
49
|
+
vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py,sha256=cT5qT7Nd2v6rSsIErpSAWaxta7txGOSFOZz2AQYQmWE,3536
|
50
|
+
vellum_ee/workflows/display/nodes/vellum/retry_node.py,sha256=Gos8F1yKN69GmegDO2q3NlGTamibd4rpuTasSU0mK8c,3281
|
51
|
+
vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=fkkn36UtjovrXYguAermgB5wm2WYakqBNaIiO0BPirI,9545
|
52
|
+
vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py,sha256=Ub6XDdVtVarqoqQrIXpJxNbp3xvz37vwpuf93DhLvX8,2670
|
53
|
+
vellum_ee/workflows/display/nodes/vellum/templating_node.py,sha256=TdIJWh2l8p4tw7ejRexGOFQKnviirUqie3WYwsrVQ4g,3339
|
54
54
|
vellum_ee/workflows/display/nodes/vellum/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
55
|
vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py,sha256=ZasoqG8FmqnZDj2FfL5BGPq9fafOTJqV_4xjOKLi1gc,5434
|
56
56
|
vellum_ee/workflows/display/nodes/vellum/tests/test_error_node.py,sha256=540FoWMpJ3EN_DPjHsr9ODJWCRVcUa5hZBn-5T2GiHU,1665
|
57
|
+
vellum_ee/workflows/display/nodes/vellum/tests/test_inline_subworkflow_node.py,sha256=SKOYan-dxY4gsO0R4JyQUyWrABHBN8XImKw9Eeo4wGo,3535
|
57
58
|
vellum_ee/workflows/display/nodes/vellum/tests/test_note_node.py,sha256=uiMB0cOxKZzos7YKnj4ef4DFa2bOvZJWIv-hfbUV6Go,1218
|
58
59
|
vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_deployment_node.py,sha256=G-qJyTNJkpqJiEZ3kCJl86CXJINLeFyf2lM0bQHCCOs,3822
|
59
60
|
vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py,sha256=TtzUj3Zk3ZhwtXE_WyctCC-CmcLB1RxntyF7u-a3i6I,10077
|
@@ -71,7 +72,7 @@ vellum_ee/workflows/display/tests/workflow_serialization/__init__.py,sha256=47DE
|
|
71
72
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
72
73
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py,sha256=XOQDDRiG46etxTC7-_RUEutoNumXc02fo7oho4GYM0c,1900
|
73
74
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py,sha256=tsjGM-jOurPSkDIbrDFdjNLmkI1fPNPAw3J9-l9knCw,12848
|
74
|
-
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py,sha256=
|
75
|
+
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py,sha256=xrekxgRlZrNIF-bkvfIzGGN3vKgTKNttNz3tfLanzd4,22062
|
75
76
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py,sha256=s6_mnk0pkztU59wYpSfOFpMhAJaRjmyfxM6WJGtnD4Y,6456
|
76
77
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py,sha256=PkSgghJDz0fpDB72HHPjLjo8LkZk-HpUkCQzRLX-iVw,40611
|
77
78
|
vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py,sha256=dsJr8I9AdPwMOGszirfNDzZP2Ychd94aAKuPXAzknMk,4632
|
@@ -83,7 +84,7 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_s
|
|
83
84
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py,sha256=kLOnUNn-r1w1JXNQcVKe-Vp-fKhSfuDBuDqrjGkFZ3U,5544
|
84
85
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py,sha256=v07cILUzS5iFYDrSOAXK93yz50-FtxLaMYMwoaPOv20,7374
|
85
86
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py,sha256=Jcuzu_zjS4ATrPg-pKvrU9WeUFAWMmPQVIcYltG6NfA,14930
|
86
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py,sha256=
|
87
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py,sha256=1ND_6lfPNUQjSc72k_sxydeeOU5f_kHkRXO65boYFok,21631
|
87
88
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py,sha256=3gZuNM8sT6ovVaeoAvd2JoyKwuxokvowlhH8kwDUoZ8,16559
|
88
89
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py,sha256=IIJt7YZBzkhNtbmaMwCX4ENs58QtSIIoBHlMR6OwGU8,8342
|
89
90
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py,sha256=QXiRjwtiTPeMUl40Pvh_geeU99C3mv1aVS85oeIUwY4,21052
|
@@ -91,21 +92,24 @@ vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_
|
|
91
92
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py,sha256=KkYZc_bZuq1lmDcvUz3QxIqJLpQPCZioD1FHUNsMJY8,11211
|
92
93
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py,sha256=aZaqRDrkO3ytcmdM2eKJqHSt60MF070NMj6M2vgzOKc,7711
|
93
94
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py,sha256=r748dpS13HtwY7t_KQFExFssxRy0xI2d-wxmhiUHRe0,3850
|
94
|
-
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py,sha256=
|
95
|
+
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py,sha256=7UWh_8dKiRL7AochCcIvOsWvC0G3yp8aEup1wIIPo9k,25256
|
95
96
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py,sha256=Cx3oY6vPVap0xm_mChqfQw4zzR4pqV36o_SyD8g6jPY,8727
|
96
97
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py,sha256=EL5kfakuoEcwD85dGjhMta-J-PpCHRSDoc80SdbBrQk,2769
|
97
98
|
vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py,sha256=RmFUDx8dYdfsOE2CGLvdXqNNRtLLpVzXDN8dqZyMcZ8,5822
|
98
99
|
vellum_ee/workflows/display/types.py,sha256=i4T7ElU5b5h-nA1i3scmEhO1BqmNDc4eJDHavATD88w,2821
|
99
100
|
vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
101
|
+
vellum_ee/workflows/display/utils/auto_layout.py,sha256=R_BLSZjdanj3UIR4cS6WVT6ek0i7AKJyHSjK1wPiois,3877
|
100
102
|
vellum_ee/workflows/display/utils/exceptions.py,sha256=LSwwxCYNxFkf5XMUcFkaZKpQ13OSrI7y_bpEUwbKVk0,169
|
101
|
-
vellum_ee/workflows/display/utils/expressions.py,sha256=
|
103
|
+
vellum_ee/workflows/display/utils/expressions.py,sha256=Ef1KfY7SmM2mvBDDag2fnU_55Ei_uz5EPDbYPQkI7Zo,13755
|
102
104
|
vellum_ee/workflows/display/utils/registry.py,sha256=fWIm5Jj-10gNFjgn34iBu4RWv3Vd15ijtSN0V97bpW8,1513
|
105
|
+
vellum_ee/workflows/display/utils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
106
|
+
vellum_ee/workflows/display/utils/tests/test_auto_layout.py,sha256=vfXI769418s9vda5Gb5NFBH747WMOwSgHRXeLCTLVm8,2356
|
103
107
|
vellum_ee/workflows/display/utils/vellum.py,sha256=mtoXmSYwR7rvrq-d6CzCW_auaJXTct0Mi1F0xpRCiNQ,5627
|
104
108
|
vellum_ee/workflows/display/vellum.py,sha256=o7mq_vk2Yapu9DDKRz5l76h8EmCAypWGQYe6pryrbB8,3576
|
105
109
|
vellum_ee/workflows/display/workflows/__init__.py,sha256=kapXsC67VJcgSuiBMa86FdePG5A9kMB5Pi4Uy1O2ob4,207
|
106
|
-
vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=
|
110
|
+
vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=LKM8MnrezrBHU1W5gZ2y82UqkBwnKQ2OBQZD56g-XmI,33399
|
107
111
|
vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py,sha256=gxz76AeCqgAZ9D2lZeTiZzxY9eMgn3qOSfVgiqYcOh8,2028
|
108
|
-
vellum_ee/workflows/display/workflows/tests/test_workflow_display.py,sha256=
|
112
|
+
vellum_ee/workflows/display/workflows/tests/test_workflow_display.py,sha256=L7SKWJ26Ex-XXTNfHYXux7KP6I-dxE1EMQylap4Mhjs,31762
|
109
113
|
vellum_ee/workflows/display/workflows/vellum_workflow_display.py,sha256=aaKdmWrgEe5YyV4zuDY_4E3y-l59rIHQnNGiPj2OWxQ,359
|
110
114
|
vellum_ee/workflows/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
111
115
|
vellum_ee/workflows/server/virtual_file_loader.py,sha256=7JphJcSO3H85qiC2DpFfBWjC3JjrbRmoynBC6KKHVsA,2710
|
@@ -136,7 +140,7 @@ vellum/client/README.md,sha256=CuGUYnaE0Imt0KqQ4sIPaUghCjLHkF3DdEvZWu14-8s,4807
|
|
136
140
|
vellum/client/__init__.py,sha256=AYopGv2ZRVn3zsU8_km6KOvEHDbXiTPCVuYVI7bWvdA,120166
|
137
141
|
vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
|
138
142
|
vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
|
139
|
-
vellum/client/core/client_wrapper.py,sha256=
|
143
|
+
vellum/client/core/client_wrapper.py,sha256=69WJ9aMFe9t-07plHgGcN8V68mijPCXTtGsp7QmE6I4,1869
|
140
144
|
vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
|
141
145
|
vellum/client/core/file.py,sha256=d4NNbX8XvXP32z8KpK2Xovv33nFfruIrpz0QWxlgpZk,2663
|
142
146
|
vellum/client/core/http_client.py,sha256=Z77OIxIbL4OAB2IDqjRq_sYa5yNYAWfmdhdCSSvh6Y4,19552
|
@@ -1499,8 +1503,8 @@ vellum/workflows/edges/__init__.py,sha256=wSkmAnz9xyi4vZwtDbKxwlplt2skD7n3NsxkvR
|
|
1499
1503
|
vellum/workflows/edges/edge.py,sha256=N0SnY3gKVuxImPAdCbPMPlHJIXbkQ3fwq_LbJRvVMFc,677
|
1500
1504
|
vellum/workflows/emitters/__init__.py,sha256=YyOgaoLtVW8eFNEWODzCYb0HzL0PoSeNRf4diJ1Y0dk,80
|
1501
1505
|
vellum/workflows/emitters/base.py,sha256=D5SADKIvnbgKwIBgYm77jaqvpo1o0rz4MmuX_muRqQU,359
|
1502
|
-
vellum/workflows/environment/__init__.py,sha256=
|
1503
|
-
vellum/workflows/environment/environment.py,sha256=
|
1506
|
+
vellum/workflows/environment/__init__.py,sha256=TJz0m9dwIs6YOwCTeuN0HHsU-ecyjc1OJXx4AFy83EQ,121
|
1507
|
+
vellum/workflows/environment/environment.py,sha256=7BThIBSRKDkBebgGTYJiPZ_Bx7c8mUigZUypyqF7inM,417
|
1504
1508
|
vellum/workflows/errors/__init__.py,sha256=tWGPu5xyAU8gRb8_bl0fL7OfU3wxQ9UH6qVwy4X4P_Q,113
|
1505
1509
|
vellum/workflows/errors/types.py,sha256=nUWuniEfrhdtb-_2GzoDGlYnSJ_yuNUGjVkaKLNr-rM,4049
|
1506
1510
|
vellum/workflows/events/__init__.py,sha256=6pxxceJo2dcaRkWtkDAYlUQZ-PHBQSZytIoyuUK48Qw,759
|
@@ -1653,8 +1657,8 @@ vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py,sha2
|
|
1653
1657
|
vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py,sha256=cKI2Ls25L-JVt4z4a2ozQa-YBeVy21Z7BQ32Sj7iBPE,10460
|
1654
1658
|
vellum/workflows/nodes/experimental/tool_calling_node/__init__.py,sha256=S7OzT3I4cyOU5Beoz87nPwCejCMP2FsHBFL8OcVmxJ4,118
|
1655
1659
|
vellum/workflows/nodes/experimental/tool_calling_node/node.py,sha256=FkhaJccpCbx2be_IZ5V2v6Lo-jPJ0WgSC5tveLvAW4A,5774
|
1656
|
-
vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py,sha256=
|
1657
|
-
vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=
|
1660
|
+
vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py,sha256=7x_o81vT7gWtVw3zDppcWnlJbakgxx_oI1esqhs2gpI,4551
|
1661
|
+
vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=iiB_Tm3zvElispx_DhnW4eQH1MnK-Y9k44X_PSpp7p8,9923
|
1658
1662
|
vellum/workflows/nodes/mocks.py,sha256=a1FjWEIocseMfjzM-i8DNozpUsaW0IONRpZmXBoWlyc,10455
|
1659
1663
|
vellum/workflows/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1660
1664
|
vellum/workflows/nodes/tests/test_mocks.py,sha256=mfPvrs75PKcsNsbJLQAN6PDFoVqs9TmQxpdyFKDdO60,7837
|
@@ -1668,7 +1672,7 @@ vellum/workflows/ports/port.py,sha256=j_qiZlpx-a1cK5E7sxXwPcb_9NS-KUM-JoP8mgqg32
|
|
1668
1672
|
vellum/workflows/ports/utils.py,sha256=cWJ9xX1KrHBTiU3xe6t7Rs0yaOy9RV18GMtHaAshAsc,3094
|
1669
1673
|
vellum/workflows/references/__init__.py,sha256=glHFC1VfXmcbNvH5VzFbkT03d8_D7MMcvEcsUBrzLIs,591
|
1670
1674
|
vellum/workflows/references/constant.py,sha256=6yUT4q1sMj1hkI_tzzQ9AYcmeeDYFUNCqUq_W2DN0S8,540
|
1671
|
-
vellum/workflows/references/environment_variable.py,sha256=-
|
1675
|
+
vellum/workflows/references/environment_variable.py,sha256=-RGql8dSrhimfCdrT_G_LSYz6VlKpfAf-N7XEyvgbBk,649
|
1672
1676
|
vellum/workflows/references/execution_count.py,sha256=JILHqt8ELdc9ct-WsVCA5X-rKiP1rmJODw-XTf4kpHI,722
|
1673
1677
|
vellum/workflows/references/external_input.py,sha256=c_4SojTpykCSbGS1Pjmx9FfquyYGMPksoj0AbrWv7Go,2064
|
1674
1678
|
vellum/workflows/references/input.py,sha256=3INu-TLTi4dziWmva6LO3WvgDlPzsjayUx61cVvqLJA,325
|
@@ -1720,8 +1724,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad
|
|
1720
1724
|
vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
1721
1725
|
vellum/workflows/workflows/tests/test_base_workflow.py,sha256=fROqff6AZpCIzaSwOKSdtYy4XR0UZQ6ejxL3RJOSJVs,20447
|
1722
1726
|
vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
|
1723
|
-
vellum_ai-0.14.
|
1724
|
-
vellum_ai-0.14.
|
1725
|
-
vellum_ai-0.14.
|
1726
|
-
vellum_ai-0.14.
|
1727
|
-
vellum_ai-0.14.
|
1727
|
+
vellum_ai-0.14.70.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
|
1728
|
+
vellum_ai-0.14.70.dist-info/METADATA,sha256=qt_owPpRPSEfBhHgLJGnUPlKvtDCCmMBkMLu1UcwUfQ,5556
|
1729
|
+
vellum_ai-0.14.70.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
1730
|
+
vellum_ai-0.14.70.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
|
1731
|
+
vellum_ai-0.14.70.dist-info/RECORD,,
|
vellum_cli/__init__.py
CHANGED
@@ -362,9 +362,12 @@ def images() -> None:
|
|
362
362
|
"This field does not push multiple local tags of the passed in image.",
|
363
363
|
)
|
364
364
|
@click.option("--workspace", type=str, help="The specific Workspace config to use when pushing")
|
365
|
-
|
365
|
+
@click.option("--source", type=str, help="Path to Dockerfile to build before pushing")
|
366
|
+
def image_push(
|
367
|
+
image: str, tag: Optional[List[str]] = None, workspace: Optional[str] = None, source: Optional[str] = None
|
368
|
+
) -> None:
|
366
369
|
"""Push Docker image to Vellum"""
|
367
|
-
image_push_command(image, tag, workspace)
|
370
|
+
image_push_command(image, tag, workspace, source)
|
368
371
|
|
369
372
|
|
370
373
|
@workflows.command(name="init")
|
vellum_cli/image_push.py
CHANGED
@@ -17,10 +17,33 @@ from vellum_cli.logger import handle_cli_error, load_cli_logger
|
|
17
17
|
_SUPPORTED_ARCHITECTURE = "amd64"
|
18
18
|
|
19
19
|
|
20
|
-
def image_push_command(
|
20
|
+
def image_push_command(
|
21
|
+
image: str, tags: Optional[List[str]] = None, workspace: Optional[str] = None, source: Optional[str] = None
|
22
|
+
) -> None:
|
21
23
|
load_dotenv(dotenv_path=os.path.join(os.getcwd(), ".env"))
|
22
24
|
logger = load_cli_logger()
|
23
25
|
config = load_vellum_cli_config()
|
26
|
+
|
27
|
+
if source:
|
28
|
+
logger.info(f"Building Docker image from Dockerfile: {source}")
|
29
|
+
|
30
|
+
if not os.path.exists(source):
|
31
|
+
handle_cli_error(logger, "Dockerfile not found", f"Dockerfile does not exist: {source}")
|
32
|
+
|
33
|
+
source_dir = os.path.dirname(source)
|
34
|
+
dockerfile_name = os.path.basename(source)
|
35
|
+
|
36
|
+
build_result = subprocess.run(
|
37
|
+
["docker", "buildx", "build", "-f", dockerfile_name, "--platform=linux/amd64", "-t", image, "."],
|
38
|
+
cwd=source_dir,
|
39
|
+
stdout=subprocess.PIPE,
|
40
|
+
stderr=subprocess.PIPE,
|
41
|
+
)
|
42
|
+
|
43
|
+
if build_result.returncode != 0:
|
44
|
+
handle_cli_error(logger, "Docker build failed", build_result.stderr.decode("utf-8"))
|
45
|
+
|
46
|
+
logger.info("Docker build completed successfully")
|
24
47
|
workspace_config = next((w for w in config.workspaces if w.name == workspace), DEFAULT_WORKSPACE_CONFIG)
|
25
48
|
|
26
49
|
api_key = os.getenv(workspace_config.api_key, None)
|
@@ -4,13 +4,14 @@ import os
|
|
4
4
|
import shutil
|
5
5
|
import subprocess
|
6
6
|
import tempfile
|
7
|
-
from unittest.mock import MagicMock
|
7
|
+
from unittest.mock import MagicMock
|
8
8
|
from uuid import uuid4
|
9
9
|
from typing import Generator
|
10
10
|
|
11
11
|
from click.testing import CliRunner
|
12
12
|
from httpx import Response
|
13
13
|
|
14
|
+
from vellum.client.types.docker_service_token import DockerServiceToken
|
14
15
|
from vellum_cli import main as cli_main
|
15
16
|
|
16
17
|
|
@@ -26,9 +27,18 @@ def mock_temp_dir() -> Generator[str, None, None]:
|
|
26
27
|
shutil.rmtree(temp_dir)
|
27
28
|
|
28
29
|
|
29
|
-
@
|
30
|
-
|
31
|
-
|
30
|
+
@pytest.fixture
|
31
|
+
def mock_docker_from_env(mocker):
|
32
|
+
return mocker.patch("docker.from_env")
|
33
|
+
|
34
|
+
|
35
|
+
@pytest.fixture
|
36
|
+
def mock_subprocess_run(mocker):
|
37
|
+
return mocker.patch("subprocess.run")
|
38
|
+
|
39
|
+
|
40
|
+
@pytest.mark.usefixtures("vellum_client")
|
41
|
+
def test_image_push__self_hosted_happy_path(mock_docker_from_env, mock_subprocess_run, monkeypatch):
|
32
42
|
# GIVEN a self hosted vellum api URL env var
|
33
43
|
monkeypatch.setenv("VELLUM_API_URL", "mycompany.api.com")
|
34
44
|
monkeypatch.setenv("VELLUM_API_KEY", "123456abcdef")
|
@@ -37,7 +47,7 @@ def test_image_push__self_hosted_happy_path(mock_docker_from_env, mock_run, vell
|
|
37
47
|
mock_docker_client = MagicMock()
|
38
48
|
mock_docker_from_env.return_value = mock_docker_client
|
39
49
|
|
40
|
-
|
50
|
+
mock_subprocess_run.side_effect = [
|
41
51
|
subprocess.CompletedProcess(
|
42
52
|
args="", returncode=0, stdout=b'{"manifests": [{"platform": {"architecture": "amd64"}}]}'
|
43
53
|
),
|
@@ -56,10 +66,8 @@ def test_image_push__self_hosted_happy_path(mock_docker_from_env, mock_run, vell
|
|
56
66
|
assert "Image successfully pushed" in result.output
|
57
67
|
|
58
68
|
|
59
|
-
@patch("subprocess.run")
|
60
|
-
@patch("docker.from_env")
|
61
69
|
def test_image_push__self_hosted_happy_path__workspace_option(
|
62
|
-
mock_docker_from_env,
|
70
|
+
mock_docker_from_env, mock_subprocess_run, mock_httpx_transport, mock_temp_dir
|
63
71
|
):
|
64
72
|
# GIVEN a workspace config with a new env for url
|
65
73
|
with open(os.path.join(mock_temp_dir, "vellum.lock.json"), "w") as f:
|
@@ -90,7 +98,7 @@ def test_image_push__self_hosted_happy_path__workspace_option(
|
|
90
98
|
mock_docker_client = MagicMock()
|
91
99
|
mock_docker_from_env.return_value = mock_docker_client
|
92
100
|
|
93
|
-
|
101
|
+
mock_subprocess_run.side_effect = [
|
94
102
|
subprocess.CompletedProcess(
|
95
103
|
args="", returncode=0, stdout=b'{"manifests": [{"platform": {"architecture": "amd64"}}]}'
|
96
104
|
),
|
@@ -144,9 +152,8 @@ def test_image_push__self_hosted_happy_path__workspace_option(
|
|
144
152
|
assert str(request.url) == "https://api.vellum.mycompany.ai/v1/container-images/push"
|
145
153
|
|
146
154
|
|
147
|
-
@
|
148
|
-
|
149
|
-
def test_image_push__self_hosted_blocks_repo(mock_docker_from_env, mock_run, vellum_client, monkeypatch):
|
155
|
+
@pytest.mark.usefixtures("vellum_client", "mock_subprocess_run")
|
156
|
+
def test_image_push__self_hosted_blocks_repo(mock_docker_from_env, monkeypatch):
|
150
157
|
# GIVEN a self hosted vellum api URL env var
|
151
158
|
monkeypatch.setenv("VELLUM_API_URL", "mycompany.api.com")
|
152
159
|
|
@@ -163,3 +170,87 @@ def test_image_push__self_hosted_blocks_repo(mock_docker_from_env, mock_run, vel
|
|
163
170
|
|
164
171
|
# AND gives the error message for self hosted installs not including the repo
|
165
172
|
assert "For adding images to your self hosted install you must include" in result.output
|
173
|
+
|
174
|
+
|
175
|
+
def test_image_push_with_source_success(
|
176
|
+
mock_docker_from_env, mock_subprocess_run, vellum_client, monkeypatch, mock_temp_dir
|
177
|
+
):
|
178
|
+
monkeypatch.setenv("VELLUM_API_URL", "https://api.vellum.ai")
|
179
|
+
monkeypatch.setenv("VELLUM_API_KEY", "123456abcdef")
|
180
|
+
|
181
|
+
dockerfile_path = os.path.join(mock_temp_dir, "Dockerfile")
|
182
|
+
with open(dockerfile_path, "w") as f:
|
183
|
+
f.write("FROM alpine:latest\n")
|
184
|
+
|
185
|
+
mock_docker_client = MagicMock()
|
186
|
+
mock_docker_from_env.return_value = mock_docker_client
|
187
|
+
mock_docker_client.images.push.return_value = [b'{"status": "Pushed"}']
|
188
|
+
|
189
|
+
mock_subprocess_run.side_effect = [
|
190
|
+
subprocess.CompletedProcess(args="", returncode=0, stdout=b"Build successful"),
|
191
|
+
subprocess.CompletedProcess(
|
192
|
+
args="", returncode=0, stdout=b'{"manifests": [{"platform": {"architecture": "amd64"}}]}'
|
193
|
+
),
|
194
|
+
subprocess.CompletedProcess(args="", returncode=0, stdout=b"sha256:hellosha"),
|
195
|
+
]
|
196
|
+
|
197
|
+
vellum_client.container_images.docker_service_token.return_value = DockerServiceToken(
|
198
|
+
access_token="345678mnopqr", organization_id="test-org", repository="myrepo.net"
|
199
|
+
)
|
200
|
+
|
201
|
+
runner = CliRunner()
|
202
|
+
result = runner.invoke(cli_main, ["image", "push", "myimage:latest", "--source", dockerfile_path])
|
203
|
+
|
204
|
+
assert result.exit_code == 0, result.output
|
205
|
+
|
206
|
+
build_call = mock_subprocess_run.call_args_list[0]
|
207
|
+
assert build_call[0][0] == [
|
208
|
+
"docker",
|
209
|
+
"buildx",
|
210
|
+
"build",
|
211
|
+
"-f",
|
212
|
+
"Dockerfile",
|
213
|
+
"--platform=linux/amd64",
|
214
|
+
"-t",
|
215
|
+
"myimage:latest",
|
216
|
+
".",
|
217
|
+
]
|
218
|
+
assert build_call[1]["cwd"] == mock_temp_dir
|
219
|
+
|
220
|
+
assert "Docker build completed successfully" in result.output
|
221
|
+
assert "Image successfully pushed" in result.output
|
222
|
+
|
223
|
+
|
224
|
+
@pytest.mark.usefixtures("mock_docker_from_env", "mock_subprocess_run", "vellum_client")
|
225
|
+
def test_image_push_with_source_dockerfile_not_exists(monkeypatch, mock_temp_dir):
|
226
|
+
monkeypatch.setenv("VELLUM_API_URL", "https://api.vellum.ai")
|
227
|
+
monkeypatch.setenv("VELLUM_API_KEY", "123456abcdef")
|
228
|
+
|
229
|
+
nonexistent_dockerfile = os.path.join(mock_temp_dir, "nonexistent_dockerfile")
|
230
|
+
|
231
|
+
runner = CliRunner()
|
232
|
+
result = runner.invoke(cli_main, ["image", "push", "myimage:latest", "--source", nonexistent_dockerfile])
|
233
|
+
|
234
|
+
assert result.exit_code == 1
|
235
|
+
assert "Dockerfile does not exist" in result.output
|
236
|
+
|
237
|
+
|
238
|
+
@pytest.mark.usefixtures("mock_docker_from_env", "vellum_client")
|
239
|
+
def test_image_push_with_source_build_fails(mock_subprocess_run, monkeypatch, mock_temp_dir):
|
240
|
+
monkeypatch.setenv("VELLUM_API_URL", "https://api.vellum.ai")
|
241
|
+
monkeypatch.setenv("VELLUM_API_KEY", "123456abcdef")
|
242
|
+
|
243
|
+
dockerfile_path = os.path.join(mock_temp_dir, "Dockerfile")
|
244
|
+
with open(dockerfile_path, "w") as f:
|
245
|
+
f.write("FROM alpine:latest\n")
|
246
|
+
|
247
|
+
mock_subprocess_run.side_effect = [
|
248
|
+
subprocess.CompletedProcess(args="", returncode=1, stderr=b"Build failed: missing dependency"),
|
249
|
+
]
|
250
|
+
|
251
|
+
runner = CliRunner()
|
252
|
+
result = runner.invoke(cli_main, ["image", "push", "myimage:latest", "--source", dockerfile_path])
|
253
|
+
|
254
|
+
assert result.exit_code == 1
|
255
|
+
assert "Docker build failed" in result.output
|
256
|
+
assert "Build failed: missing dependency" in result.output
|
@@ -310,7 +310,7 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
|
|
310
310
|
|
311
311
|
return self._get_node_display_uuid("target_handle_id")
|
312
312
|
|
313
|
-
def get_target_handle_id_by_source_node_id(self,
|
313
|
+
def get_target_handle_id_by_source_node_id(self, _source_node_id: UUID) -> UUID:
|
314
314
|
"""
|
315
315
|
In the vast majority of cases, nodes will only have a single target handle and can be retrieved independently
|
316
316
|
of the source node. However, in rare cases (such as legacy Merge nodes), this method can be overridden to
|
@@ -8,11 +8,11 @@ _T = TypeVar("_T")
|
|
8
8
|
|
9
9
|
|
10
10
|
@overload
|
11
|
-
def raise_if_descriptor(
|
11
|
+
def raise_if_descriptor(_node_attr: BaseDescriptor[_T]) -> _T: ...
|
12
12
|
|
13
13
|
|
14
14
|
@overload
|
15
|
-
def raise_if_descriptor(
|
15
|
+
def raise_if_descriptor(_node_attr: _T) -> _T: ...
|
16
16
|
|
17
17
|
|
18
18
|
def raise_if_descriptor(node_attr: Union[NodeReference[_T], _T]) -> Optional[_T]:
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from uuid import UUID
|
2
|
-
from typing import
|
2
|
+
from typing import ClassVar, Dict, Generic, Optional, TypeVar, cast
|
3
3
|
|
4
4
|
from vellum.workflows.nodes.displayable import APINode
|
5
5
|
from vellum.workflows.references.output import OutputReference
|
@@ -32,7 +32,7 @@ class BaseAPINodeDisplay(BaseNodeDisplay[_APINodeType], Generic[_APINodeType]):
|
|
32
32
|
}
|
33
33
|
|
34
34
|
def serialize(
|
35
|
-
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **
|
35
|
+
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **_kwargs
|
36
36
|
) -> JsonObject:
|
37
37
|
node = self._node
|
38
38
|
node_id = self.node_id
|
@@ -24,7 +24,7 @@ class BaseCodeExecutionNodeDisplay(BaseNodeDisplay[_CodeExecutionNodeType], Gene
|
|
24
24
|
}
|
25
25
|
|
26
26
|
def serialize(
|
27
|
-
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **
|
27
|
+
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **_kwargs
|
28
28
|
) -> JsonObject:
|
29
29
|
node = self._node
|
30
30
|
node_id = self.node_id
|
@@ -45,7 +45,7 @@ class BaseConditionalNodeDisplay(BaseNodeDisplay[_ConditionalNodeType], Generic[
|
|
45
45
|
rule_ids: ClassVar[List[RuleIdMap]]
|
46
46
|
condition_ids: ClassVar[list[ConditionId]]
|
47
47
|
|
48
|
-
def serialize(self, display_context: WorkflowDisplayContext, **
|
48
|
+
def serialize(self, display_context: WorkflowDisplayContext, **_kwargs) -> JsonObject:
|
49
49
|
node = self._node
|
50
50
|
node_id = self.node_id
|
51
51
|
|