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.
Files changed (42) hide show
  1. vellum/client/core/client_wrapper.py +1 -1
  2. vellum/workflows/environment/__init__.py +2 -1
  3. vellum/workflows/environment/environment.py +5 -1
  4. vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py +77 -1
  5. vellum/workflows/nodes/experimental/tool_calling_node/utils.py +2 -2
  6. vellum/workflows/references/environment_variable.py +2 -3
  7. {vellum_ai-0.14.69.dist-info → vellum_ai-0.14.70.dist-info}/METADATA +1 -1
  8. {vellum_ai-0.14.69.dist-info → vellum_ai-0.14.70.dist-info}/RECORD +42 -38
  9. vellum_cli/__init__.py +5 -2
  10. vellum_cli/image_push.py +24 -1
  11. vellum_cli/tests/test_image_push.py +103 -12
  12. vellum_ee/workflows/display/nodes/base_node_display.py +1 -1
  13. vellum_ee/workflows/display/nodes/utils.py +2 -2
  14. vellum_ee/workflows/display/nodes/vellum/api_node.py +2 -2
  15. vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +1 -1
  16. vellum_ee/workflows/display/nodes/vellum/conditional_node.py +1 -1
  17. vellum_ee/workflows/display/nodes/vellum/error_node.py +1 -1
  18. vellum_ee/workflows/display/nodes/vellum/final_output_node.py +2 -2
  19. vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +1 -1
  20. vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +1 -1
  21. vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +9 -1
  22. vellum_ee/workflows/display/nodes/vellum/map_node.py +1 -1
  23. vellum_ee/workflows/display/nodes/vellum/merge_node.py +1 -1
  24. vellum_ee/workflows/display/nodes/vellum/note_node.py +1 -0
  25. vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +1 -1
  26. vellum_ee/workflows/display/nodes/vellum/retry_node.py +1 -1
  27. vellum_ee/workflows/display/nodes/vellum/search_node.py +1 -1
  28. vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +1 -1
  29. vellum_ee/workflows/display/nodes/vellum/templating_node.py +1 -1
  30. vellum_ee/workflows/display/nodes/vellum/tests/test_inline_subworkflow_node.py +88 -0
  31. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +16 -0
  32. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +9 -1
  33. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +59 -297
  34. vellum_ee/workflows/display/utils/auto_layout.py +130 -0
  35. vellum_ee/workflows/display/utils/expressions.py +7 -0
  36. vellum_ee/workflows/display/utils/tests/__init__.py +0 -0
  37. vellum_ee/workflows/display/utils/tests/test_auto_layout.py +56 -0
  38. vellum_ee/workflows/display/workflows/base_workflow_display.py +15 -10
  39. vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +41 -0
  40. {vellum_ai-0.14.69.dist-info → vellum_ai-0.14.70.dist-info}/LICENSE +0 -0
  41. {vellum_ai-0.14.69.dist-info → vellum_ai-0.14.70.dist-info}/WHEEL +0 -0
  42. {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.69",
21
+ "X-Fern-SDK-Version": "0.14.70",
22
22
  }
23
23
  headers["X-API-KEY"] = self.api_key
24
24
  return headers
@@ -1,5 +1,6 @@
1
- from .environment import Environment
1
+ from .environment import Environment, EnvironmentVariables
2
2
 
3
3
  __all__ = [
4
+ "EnvironmentVariables",
4
5
  "Environment",
5
6
  ]
@@ -3,7 +3,11 @@ from typing import Optional
3
3
  from vellum.workflows.references import EnvironmentVariableReference
4
4
 
5
5
 
6
- class Environment:
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.workflows.nodes.experimental.tool_calling_node.utils import create_tool_router_node
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
- # Fetch Vellum Environment Variable named `self.name` once that project is done
24
- raise ValueError(f"No environment variable named '{self.name}' found")
23
+ return ""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 0.14.69
3
+ Version: 0.14.70
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0
@@ -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=2_6oGoVcLFUh4L63Kz4SBL4Y6XevJ70oYbg7BJ3cb5Q,12569
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=mjK3Fj3_MIhIGmurYVz_OC-hCoAef5LqDb0OppKJIJc,9909
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=QM-JlR_aJappvwbCLteQZZf76sd7SE1sRj3armvFK-I,5706
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=2VyAk9SjBpt_b2fp81KlFxS5ddk2JhcldEI1S4crPj0,16921
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=sloya5TpXsnot1HURc9L51INwflRqUzHxRVnCS9Cd-4,973
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=ZiOJsSovftbH1eVFdU0-UE4DUliIHPQZkwrFcooN-Vk,8856
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=L308T4U6eaL0WUJ_hQ0qrH-i8IuMBCm5XjRO2_b-Mro,4507
40
- vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=MrvyiYD0qgQf3-ZYFcurQtin3FagAHGRoT7zYGiIao0,11150
41
- vellum_ee/workflows/display/nodes/vellum/error_node.py,sha256=m2DmOXm9-jiiIl6zwkXHNfsYp5PTpBHEdt5xaIsabWo,2363
42
- vellum_ee/workflows/display/nodes/vellum/final_output_node.py,sha256=jUDI2FwVaw0Or4zJL58J_g0S--i59Hzik60s_Es_M-8,3098
43
- vellum_ee/workflows/display/nodes/vellum/guardrail_node.py,sha256=5_5D5PMzBOeUdVtRlANbfEsu7Gv3r37dLvpfjGAqYac,2330
44
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py,sha256=2qp3J1nZ4R4szTynakwT9gL51SZEjIiLLdTvA_wIQu0,10954
45
- vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py,sha256=fQV5o83BPTwGX6o-ThN4r7BcIhySyqwpW1JGYWpvSJI,5625
46
- vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=2teCYQSX8g-b8aaC_MY4XSC4GRMTJigPFWNTQEkC_gk,3907
47
- vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=yBWeN4T_lOsDVnNOKWRiT7JYKu0IR5Fx2z99iq6QKSA,3273
48
- vellum_ee/workflows/display/nodes/vellum/note_node.py,sha256=3E0UqmgVYdtbj4nyq8gKju8EpMsRHMCQ0KLrJhug3XU,1084
49
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py,sha256=1NxFddxWCFtMe_je1cutP7qnoASoG94LJqKhRkoQwvw,3535
50
- vellum_ee/workflows/display/nodes/vellum/retry_node.py,sha256=X3xnlAU5JisL0jRvaG_V9RvTF7ZlGufTO8tXLLVhGIg,3280
51
- vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=3n1qa-zWIk0p_H94u0hjfDtGkanldC6EXVhg0xgLmE4,9544
52
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py,sha256=MWLZBXHsmj5vKgqOgI2HHcHAJzLS0sqybn6idhwug8Y,2669
53
- vellum_ee/workflows/display/nodes/vellum/templating_node.py,sha256=J84_EUfwWwpeOfUFBdRorrD1Bod0jDBFdQ6xnRyp9Ho,3338
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=MdjWgD8yZhv0MnpI-Ak5EqMzh2joVz3z5WFqr42PgZc,21508
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=u2nquKoO3o2xIkU_uFPOb_s5YoLmULiq09vb6Ee0Cqw,21415
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=DzoDdmAwabMTuNu2gCgAyO0KjZxFr9JlkQRz2koUAJ8,46504
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=Y0WMn0V3GjVTJShMSWIe3Z75NzrRfs4_qPytUTiqbhQ,13489
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=dVOe3TOV00uvllxsDziM3pFfL2HYTkWRq9iKDlj_xyU,33162
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=o0bHG9gi6RKlyccuCyow-YbCY8ejcvS1f4VJ6ozjUVA,30234
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=dnusvY6O2THB1zDdl_1dPfH3fL9UKVhqz1Gp1UtaEck,1869
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=wGHslgSEZ7Octe4C-hNtl84EFelNimgmWQoi7px4-uw,71
1503
- vellum/workflows/environment/environment.py,sha256=0XhJPBs8YASWmvPx8bkSdCvcbDmzpe9stfs2kgtNDRU,296
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=sxG26mOwt4N36RLoPJ-ngginPqC5qFzD_kGj9izdCFI,1833
1657
- vellum/workflows/nodes/experimental/tool_calling_node/utils.py,sha256=vB-tdN-44iVrTFvwGLVZW3dv62imIp5fPo0FYCW0l3M,9815
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=-gfOcdYwVp9ztSUYz6h2WI2Cg95zqxq5hhFf3Yr7aQg,791
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.69.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1724
- vellum_ai-0.14.69.dist-info/METADATA,sha256=kD1Yw09evk1wBzHUC1nBcnmpRGuK1v5ccyY_woFDV38,5556
1725
- vellum_ai-0.14.69.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1726
- vellum_ai-0.14.69.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1727
- vellum_ai-0.14.69.dist-info/RECORD,,
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
- def image_push(image: str, tag: Optional[List[str]] = None, workspace: Optional[str] = None) -> None:
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(image: str, tags: Optional[List[str]] = None, workspace: Optional[str] = None) -> None:
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, patch
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
- @patch("subprocess.run")
30
- @patch("docker.from_env")
31
- def test_image_push__self_hosted_happy_path(mock_docker_from_env, mock_run, vellum_client, monkeypatch):
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
- mock_run.side_effect = [
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, mock_run, mock_httpx_transport, mock_temp_dir
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
- mock_run.side_effect = [
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
- @patch("subprocess.run")
148
- @patch("docker.from_env")
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, source_node_id: UUID) -> UUID:
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(node_attr: BaseDescriptor[_T]) -> _T: ...
11
+ def raise_if_descriptor(_node_attr: BaseDescriptor[_T]) -> _T: ...
12
12
 
13
13
 
14
14
  @overload
15
- def raise_if_descriptor(node_attr: _T) -> _T: ...
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 Any, ClassVar, Dict, Generic, Optional, TypeVar, cast
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, **kwargs: Any
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, **kwargs
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, **kwargs: Any) -> JsonObject:
48
+ def serialize(self, display_context: WorkflowDisplayContext, **_kwargs) -> JsonObject:
49
49
  node = self._node
50
50
  node_id = self.node_id
51
51