vellum-ai 0.14.1__py3-none-any.whl → 0.14.2__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.
@@ -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.1",
21
+ "X-Fern-SDK-Version": "0.14.2",
22
22
  }
23
23
  headers["X_API_KEY"] = self.api_key
24
24
  return headers
@@ -10,7 +10,7 @@ import pydash
10
10
  import pytz
11
11
  import yaml
12
12
 
13
- from vellum.utils.templating.custom_filters import is_valid_json_string
13
+ from vellum.utils.templating.custom_filters import is_valid_json_string, replace
14
14
 
15
15
  DEFAULT_JINJA_GLOBALS: Dict[str, Any] = {
16
16
  "datetime": datetime,
@@ -23,6 +23,10 @@ DEFAULT_JINJA_GLOBALS: Dict[str, Any] = {
23
23
  "re": re,
24
24
  "yaml": yaml,
25
25
  }
26
- DEFAULT_JINJA_CUSTOM_FILTERS: Dict[str, Callable[[Union[str, bytes]], bool]] = {
26
+
27
+ FilterFunc = Union[Callable[[Union[str, bytes]], bool], Callable[[Any, Any, Any], str]]
28
+
29
+ DEFAULT_JINJA_CUSTOM_FILTERS: Dict[str, FilterFunc] = {
27
30
  "is_valid_json_string": is_valid_json_string,
31
+ "replace": replace,
28
32
  }
@@ -1,5 +1,7 @@
1
1
  import json
2
- from typing import Union
2
+ from typing import Any, Union
3
+
4
+ from vellum.workflows.state.encoder import DefaultStateEncoder
3
5
 
4
6
 
5
7
  def is_valid_json_string(value: Union[str, bytes]) -> bool:
@@ -10,3 +12,22 @@ def is_valid_json_string(value: Union[str, bytes]) -> bool:
10
12
  except ValueError:
11
13
  return False
12
14
  return True
15
+
16
+
17
+ def replace(s: Any, old: Any, new: Any) -> str:
18
+ def encode_to_str(obj: Any) -> str:
19
+ """Encode an object for template rendering using DefaultStateEncoder."""
20
+ try:
21
+ if isinstance(obj, str):
22
+ return obj
23
+ return json.dumps(obj, cls=DefaultStateEncoder)
24
+ except TypeError:
25
+ return str(obj)
26
+
27
+ if old == "":
28
+ return encode_to_str(s)
29
+
30
+ s_str = encode_to_str(s)
31
+ old_str = encode_to_str(old)
32
+ new_str = encode_to_str(new)
33
+ return s_str.replace(old_str, new_str)
@@ -1,8 +1,9 @@
1
1
  import json
2
- from typing import Any, Callable, Dict, Optional, Union
2
+ from typing import Any, Dict, Optional
3
3
 
4
4
  from jinja2.sandbox import SandboxedEnvironment
5
5
 
6
+ from vellum.utils.templating.constants import FilterFunc
6
7
  from vellum.utils.templating.exceptions import JinjaTemplateError
7
8
  from vellum.workflows.state.encoder import DefaultStateEncoder
8
9
 
@@ -18,7 +19,7 @@ def render_sandboxed_jinja_template(
18
19
  *,
19
20
  template: str,
20
21
  input_values: Dict[str, Any],
21
- jinja_custom_filters: Optional[Dict[str, Callable[[Union[str, bytes]], bool]]] = None,
22
+ jinja_custom_filters: Optional[Dict[str, FilterFunc]] = None,
22
23
  jinja_globals: Optional[Dict[str, Any]] = None,
23
24
  ) -> str:
24
25
  """Render a Jinja template within a sandboxed environment."""
File without changes
@@ -0,0 +1,19 @@
1
+ import pytest
2
+
3
+ from vellum.utils.templating.custom_filters import replace
4
+
5
+
6
+ @pytest.mark.parametrize(
7
+ ["input_str", "old", "new", "expected"],
8
+ [
9
+ ("foo", "foo", "bar", "bar"),
10
+ ({"message": "hello"}, "hello", "world", '{"message": "world"}'),
11
+ ("Value: 123", 123, 456, "Value: 456"),
12
+ (123, 2, 4, "143"),
13
+ ("", "", "", ""),
14
+ ("foo", "", "bar", "foo"),
15
+ ],
16
+ )
17
+ def test_replace(input_str, old, new, expected):
18
+ actual = replace(input_str, old, new)
19
+ assert actual == expected
@@ -13,6 +13,7 @@ class WorkflowErrorCode(Enum):
13
13
  INVALID_INPUTS = "INVALID_INPUTS"
14
14
  INVALID_OUTPUTS = "INVALID_OUTPUTS"
15
15
  INVALID_STATE = "INVALID_STATE"
16
+ INVALID_CODE = "INVALID_CODE"
16
17
  INVALID_TEMPLATE = "INVALID_TEMPLATE"
17
18
  INTERNAL_ERROR = "INTERNAL_ERROR"
18
19
  NODE_EXECUTION = "NODE_EXECUTION"
@@ -54,6 +55,7 @@ _WORKFLOW_EVENT_ERROR_CODE_TO_WORKFLOW_ERROR_CODE: Dict[WorkflowExecutionEventEr
54
55
  "INTERNAL_SERVER_ERROR": WorkflowErrorCode.INTERNAL_ERROR,
55
56
  "NODE_EXECUTION": WorkflowErrorCode.NODE_EXECUTION,
56
57
  "LLM_PROVIDER": WorkflowErrorCode.PROVIDER_ERROR,
58
+ "INVALID_CODE": WorkflowErrorCode.INVALID_CODE,
57
59
  "INVALID_TEMPLATE": WorkflowErrorCode.INVALID_TEMPLATE,
58
60
  "USER_DEFINED_ERROR": WorkflowErrorCode.USER_DEFINED_ERROR,
59
61
  }
@@ -71,6 +73,7 @@ _WORKFLOW_ERROR_CODE_TO_VELLUM_ERROR_CODE: Dict[WorkflowErrorCode, VellumErrorCo
71
73
  WorkflowErrorCode.INVALID_INPUTS: "INVALID_INPUTS",
72
74
  WorkflowErrorCode.INVALID_OUTPUTS: "INVALID_REQUEST",
73
75
  WorkflowErrorCode.INVALID_STATE: "INVALID_REQUEST",
76
+ WorkflowErrorCode.INVALID_CODE: "INVALID_CODE",
74
77
  WorkflowErrorCode.INVALID_TEMPLATE: "INVALID_INPUTS",
75
78
  WorkflowErrorCode.INTERNAL_ERROR: "INTERNAL_SERVER_ERROR",
76
79
  WorkflowErrorCode.NODE_EXECUTION: "USER_DEFINED_ERROR",
@@ -1,6 +1,6 @@
1
- from typing import Any, Callable, ClassVar, Dict, Generic, Mapping, Tuple, Type, TypeVar, Union, get_args
1
+ from typing import Any, ClassVar, Dict, Generic, Mapping, Tuple, Type, TypeVar, get_args
2
2
 
3
- from vellum.utils.templating.constants import DEFAULT_JINJA_CUSTOM_FILTERS, DEFAULT_JINJA_GLOBALS
3
+ from vellum.utils.templating.constants import DEFAULT_JINJA_CUSTOM_FILTERS, DEFAULT_JINJA_GLOBALS, FilterFunc
4
4
  from vellum.utils.templating.exceptions import JinjaTemplateError
5
5
  from vellum.utils.templating.render import render_sandboxed_jinja_template
6
6
  from vellum.workflows.errors import WorkflowErrorCode
@@ -54,7 +54,7 @@ class TemplatingNode(BaseNode[StateType], Generic[StateType, _OutputType], metac
54
54
  inputs: ClassVar[EntityInputsInterface]
55
55
 
56
56
  jinja_globals: Dict[str, Any] = DEFAULT_JINJA_GLOBALS
57
- jinja_custom_filters: Mapping[str, Callable[[Union[str, bytes]], bool]] = DEFAULT_JINJA_CUSTOM_FILTERS
57
+ jinja_custom_filters: Mapping[str, FilterFunc] = DEFAULT_JINJA_CUSTOM_FILTERS
58
58
 
59
59
  class Outputs(BaseNode.Outputs):
60
60
  """
@@ -4,6 +4,7 @@ from typing import List, Union
4
4
 
5
5
  from vellum.client.types.chat_message import ChatMessage
6
6
  from vellum.client.types.function_call import FunctionCall
7
+ from vellum.client.types.function_call_vellum_value import FunctionCallVellumValue
7
8
  from vellum.workflows.exceptions import NodeException
8
9
  from vellum.workflows.nodes.bases.base import BaseNode
9
10
  from vellum.workflows.nodes.core.templating_node.node import TemplatingNode
@@ -193,3 +194,29 @@ def test_templating_node__union_float_int_output():
193
194
 
194
195
  # THEN it should correctly parse as a float
195
196
  assert outputs.result == 42.5
197
+
198
+
199
+ def test_templating_node__replace_filter():
200
+ # GIVEN a templating node that outputs a complex object
201
+ class ReplaceFilterTemplateNode(TemplatingNode[BaseState, Json]):
202
+ template = """{{- prompt_outputs | selectattr(\'type\', \'equalto\', \'FUNCTION_CALL\') \
203
+ | list | replace(\"\\n\",\",\") -}}"""
204
+ inputs = {
205
+ "prompt_outputs": [FunctionCallVellumValue(value=FunctionCall(name="test", arguments={"key": "value"}))]
206
+ }
207
+
208
+ # WHEN the node is run
209
+ node = ReplaceFilterTemplateNode()
210
+ outputs = node.run()
211
+
212
+ # THEN the output is the expected JSON
213
+ assert outputs.result == [
214
+ {
215
+ "type": "FUNCTION_CALL",
216
+ "value": {
217
+ "name": "test",
218
+ "arguments": {"key": "value"},
219
+ "id": None,
220
+ },
221
+ }
222
+ ]
@@ -93,13 +93,14 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
93
93
  log: str
94
94
 
95
95
  def run(self) -> Outputs:
96
- input_values = self._compile_code_inputs()
97
96
  output_type = self.__class__.get_output_type()
98
97
  code = self._resolve_code()
99
98
  if not self.packages and self.runtime == "PYTHON_3_11_6":
100
- logs, result = run_code_inline(code, input_values, output_type)
99
+ logs, result = run_code_inline(code, self.code_inputs, output_type)
101
100
  return self.Outputs(result=result, log=logs)
101
+
102
102
  else:
103
+ input_values = self._compile_code_inputs()
103
104
  expected_output_type = primitive_type_to_vellum_variable_type(output_type)
104
105
 
105
106
  code_execution_result = self._context.vellum_client.execute_code(
@@ -131,7 +132,7 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
131
132
  compiled_inputs.append(
132
133
  StringInput(
133
134
  name=input_name,
134
- value=str(input_value),
135
+ value=input_value,
135
136
  )
136
137
  )
137
138
  elif isinstance(input_value, VellumSecret):
@@ -193,7 +194,7 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
193
194
  )
194
195
  else:
195
196
  raise NodeException(
196
- message=f"Unrecognized input type for input '{input_name}'",
197
+ message=f"Unrecognized input type for input '{input_name}': {input_value.__class__.__name__}",
197
198
  code=WorkflowErrorCode.INVALID_INPUTS,
198
199
  )
199
200
 
@@ -7,6 +7,7 @@ from vellum.client.types.code_execution_package import CodeExecutionPackage
7
7
  from vellum.client.types.code_executor_secret_input import CodeExecutorSecretInput
8
8
  from vellum.client.types.function_call import FunctionCall
9
9
  from vellum.client.types.number_input import NumberInput
10
+ from vellum.workflows.errors import WorkflowErrorCode
10
11
  from vellum.workflows.exceptions import NodeException
11
12
  from vellum.workflows.inputs.base import BaseInputs
12
13
  from vellum.workflows.nodes.displayable.code_execution_node import CodeExecutionNode
@@ -559,3 +560,53 @@ def main(arg1: List[Dict]) -> float:
559
560
 
560
561
  # AND we should not have invoked the Code via Vellum since it's running inline
561
562
  vellum_client.execute_code.assert_not_called()
563
+
564
+
565
+ def test_run_node__code_execution_error():
566
+ # GIVEN a node that will raise an error during execution
567
+ class State(BaseState):
568
+ pass
569
+
570
+ class ExampleCodeExecutionNode(CodeExecutionNode[State, int]):
571
+ code = """\
572
+ def main(arg1: int, arg2: int) -> int:
573
+ return arg1 + arg2 + arg3
574
+ """
575
+ runtime = "PYTHON_3_11_6"
576
+ code_inputs = {
577
+ "arg1": 1,
578
+ "arg2": 2,
579
+ }
580
+
581
+ # WHEN we run the node
582
+ node = ExampleCodeExecutionNode(state=State())
583
+
584
+ # THEN it should raise a NodeException with the execution error
585
+ with pytest.raises(NodeException) as exc_info:
586
+ node.run()
587
+
588
+ # AND the error should contain the execution error details
589
+ assert "name 'arg3' is not defined" in str(exc_info.value)
590
+ assert exc_info.value.code == WorkflowErrorCode.INVALID_CODE
591
+
592
+
593
+ def test_run_node__array_of_bools_input():
594
+ # GIVEN a node that will raise an error during execution
595
+ class ExampleCodeExecutionNode(CodeExecutionNode[BaseState, int]):
596
+ code = """\
597
+ def main(arg1: list[bool]) -> int:
598
+ return len(arg1)
599
+ """
600
+ runtime = "PYTHON_3_11_6"
601
+ code_inputs = {
602
+ "arg1": [True, False, True],
603
+ }
604
+
605
+ # WHEN we run the node
606
+ node = ExampleCodeExecutionNode()
607
+
608
+ # THEN it should raise a NodeException with the execution error
609
+ outputs = node.run()
610
+
611
+ # AND the error should contain the execution error details
612
+ assert outputs == {"result": 3, "log": ""}
@@ -1,14 +1,13 @@
1
1
  import io
2
2
  import os
3
3
  import re
4
- from typing import Any, List, Tuple, Union, get_args, get_origin
4
+ from typing import Any, Tuple, Union, get_args, get_origin
5
5
 
6
6
  from pydantic import BaseModel, ValidationError
7
7
 
8
- from vellum import VellumValue
9
- from vellum.client.types.code_executor_input import CodeExecutorInput
10
8
  from vellum.workflows.errors.types import WorkflowErrorCode
11
9
  from vellum.workflows.exceptions import NodeException
10
+ from vellum.workflows.types.core import EntityInputsInterface
12
11
 
13
12
 
14
13
  def read_file_from_path(node_filepath: str, script_filepath: str) -> Union[str, None]:
@@ -70,13 +69,11 @@ def _clean_for_dict_wrapper(obj):
70
69
 
71
70
  def run_code_inline(
72
71
  code: str,
73
- input_values: List[CodeExecutorInput],
72
+ inputs: EntityInputsInterface,
74
73
  output_type: Any,
75
74
  ) -> Tuple[str, Any]:
76
75
  log_buffer = io.StringIO()
77
76
 
78
- VELLUM_TYPES = get_args(VellumValue)
79
-
80
77
  def wrap_value(value):
81
78
  if isinstance(value, list):
82
79
  return ListWrapper(
@@ -84,7 +81,7 @@ def run_code_inline(
84
81
  # Convert VellumValue to dict with its fields
85
82
  (
86
83
  item.model_dump()
87
- if isinstance(item, VELLUM_TYPES)
84
+ if isinstance(item, BaseModel)
88
85
  else _clean_for_dict_wrapper(item) if isinstance(item, (dict, list)) else item
89
86
  )
90
87
  for item in value
@@ -93,18 +90,23 @@ def run_code_inline(
93
90
  return _clean_for_dict_wrapper(value)
94
91
 
95
92
  exec_globals = {
96
- "__arg__inputs": {input_value.name: wrap_value(input_value.value) for input_value in input_values},
93
+ "__arg__inputs": {name: wrap_value(value) for name, value in inputs.items()},
97
94
  "__arg__out": None,
98
95
  "print": lambda *args, **kwargs: log_buffer.write(f"{' '.join(args)}\n"),
99
96
  }
100
- run_args = [f"{input_value.name}=__arg__inputs['{input_value.name}']" for input_value in input_values]
97
+ run_args = [f"{name}=__arg__inputs['{name}']" for name in inputs.keys()]
101
98
  execution_code = f"""\
102
99
  {code}
103
100
 
104
101
  __arg__out = main({", ".join(run_args)})
105
102
  """
106
-
107
- exec(execution_code, exec_globals)
103
+ try:
104
+ exec(execution_code, exec_globals)
105
+ except Exception as e:
106
+ raise NodeException(
107
+ code=WorkflowErrorCode.INVALID_CODE,
108
+ message=str(e),
109
+ )
108
110
 
109
111
  logs = log_buffer.getvalue()
110
112
  result = exec_globals["__arg__out"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 0.14.1
3
+ Version: 0.14.2
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0
@@ -6,7 +6,7 @@ vellum_cli/config.py,sha256=Bsb3mnvKvv3oOTcCuxpgC7lWPMqt6eJhgRA6VEE-vL4,9266
6
6
  vellum_cli/image_push.py,sha256=SJwhwWJsLjwGNezNVd_oCVpFMfPsAB3dfLWmriZZUtw,4419
7
7
  vellum_cli/logger.py,sha256=PuRFa0WCh4sAGFS5aqWB0QIYpS6nBWwPJrIXpWxugV4,1022
8
8
  vellum_cli/ping.py,sha256=lWyJw6sziXjyTopTYRdFF5hV-sYPVDdX0yVbG5fzcY4,585
9
- vellum_cli/pull.py,sha256=7yvg4oBOgsbBEsgXtCpYlNR4AOR8hPICamY-4HI-3kM,9031
9
+ vellum_cli/pull.py,sha256=SA2EOHXbLO_jGKhzUHNrLyxEwaPbeLiU3TeRY5oeX_Y,8877
10
10
  vellum_cli/push.py,sha256=xjTNbLwOVFNU3kpBrm56Bk5QkSRrJ9z86qceghCzfIA,9655
11
11
  vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  vellum_cli/tests/conftest.py,sha256=AFYZryKA2qnUuCPBxBKmHLFoPiE0WhBFFej9tNwSHdc,1526
@@ -84,12 +84,12 @@ vellum_ee/workflows/display/types.py,sha256=bm355ZcZ-7WaesBvIB8RbWDD7qiFmazfcNb6
84
84
  vellum_ee/workflows/display/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
85
  vellum_ee/workflows/display/utils/expressions.py,sha256=9FpOslDI-RCR5m4TgAu9KCHh4aTVnh7CHR2ykyMUDw0,1151
86
86
  vellum_ee/workflows/display/utils/vellum.py,sha256=UjK_RxnSEmlIu9klGCPWU5RAQBmgZ7cRbRdgxaTbubE,8081
87
- vellum_ee/workflows/display/vellum.py,sha256=PVte2gcp1_4g-8ZaM0XVAaDwf3O-kSHy7-5Q-Co-YG0,8463
87
+ vellum_ee/workflows/display/vellum.py,sha256=iiBzMIHTnRb-Xb4Q9-26vOxPpK_rDPKBlky3dBew8Gg,8480
88
88
  vellum_ee/workflows/display/workflows/__init__.py,sha256=kapXsC67VJcgSuiBMa86FdePG5A9kMB5Pi4Uy1O2ob4,207
89
89
  vellum_ee/workflows/display/workflows/base_workflow_display.py,sha256=Amow11LhE-GL3j8bNZ8rK1iYKjkNOhH1ECMQ-dvyLAU,17204
90
90
  vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py,sha256=kp0u8LN_2IwshLrhMImhpZx1hRyAcD5gXY-kDuuaGMQ,1269
91
91
  vellum_ee/workflows/display/workflows/tests/test_workflow_display.py,sha256=yl1ytpl9_lijOGeDPWSypWYRJ7aOEVA7NgUg81jTuCs,2229
92
- vellum_ee/workflows/display/workflows/vellum_workflow_display.py,sha256=12miGvHL9_ZzXaU5r1u1TVTGSBrs8LHBVJU-DKfS0JE,18802
92
+ vellum_ee/workflows/display/workflows/vellum_workflow_display.py,sha256=8roVFJ4SWrMRNpptwwneVcE6kJmoVtJPN-fmkfDNb7Q,19102
93
93
  vellum_ee/workflows/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
94
  vellum_ee/workflows/server/virtual_file_loader.py,sha256=X_DdNK7MfyOjKWekk6YQpOSCT6klKcdjT6nVJcBH1sM,1481
95
95
  vellum_ee/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -104,7 +104,7 @@ vellum_ee/workflows/tests/local_workflow/display/__init__.py,sha256=xo75Uqb4aErO
104
104
  vellum_ee/workflows/tests/local_workflow/display/nodes/__init__.py,sha256=szW_mgOUriyZ6v1vlnevBgkzNi8g83-ihS98UOLHVcE,155
105
105
  vellum_ee/workflows/tests/local_workflow/display/nodes/final_output.py,sha256=Kv92TCREiZsB9531KZYaBIq83uHn7e_ECw_yAbD1qfk,1017
106
106
  vellum_ee/workflows/tests/local_workflow/display/nodes/templating_node.py,sha256=5cankEe1rDZlXKgILFSPbmN0tUZhIdmcFgz_AguXTJc,1229
107
- vellum_ee/workflows/tests/local_workflow/display/workflow.py,sha256=I0uc9hmeQGMxUJMiOu1btBpUb2aSvIXUSNS05WiPeNA,2336
107
+ vellum_ee/workflows/tests/local_workflow/display/workflow.py,sha256=XJCmx64TCsD2Zt55Q5SISdXSr1NO7n5xenkOtCk0WXI,2151
108
108
  vellum_ee/workflows/tests/local_workflow/inputs.py,sha256=4cgsZBoUbIY0Rs8gknC9yqxQ-sSoULclx_SAm1FT2RA,96
109
109
  vellum_ee/workflows/tests/local_workflow/metadata.json,sha256=rdu3h5qkFZiqhCAMxoyoWyMI0O8QALC5-URvSIW6F00,24
110
110
  vellum_ee/workflows/tests/local_workflow/nodes/__init__.py,sha256=1F6jxUpSKfPXPj4ZZKSbnX6Mg-VwF3euLJSZfGn6xkM,127
@@ -119,7 +119,7 @@ vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
119
119
  vellum/client/__init__.py,sha256=j6zi0NZ4BMC6JrwckvzMWuG5x8KoOvO4KqsLhvVCa68,117624
120
120
  vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
121
121
  vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
122
- vellum/client/core/client_wrapper.py,sha256=AN4UTP8OvOr6qMSP_VqGlHKGOVsUnQj3CLqFDhB3p5E,1868
122
+ vellum/client/core/client_wrapper.py,sha256=r8ZNshVLkA2wiH4k5knCrjqc-qjeEZ06Cpf5iE7nQ-g,1868
123
123
  vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
124
124
  vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
125
125
  vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
@@ -1259,10 +1259,12 @@ vellum/types/workspace_read.py,sha256=9CvgvK8Li8vL6qC5KX7f3-nEHslJ4lw2w07bvXcrjA
1259
1259
  vellum/types/workspace_secret_read.py,sha256=Z6QNXHxVHRdrLXSI31KxngePRwJTVoJYMXVbtPQwrxs,159
1260
1260
  vellum/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1261
1261
  vellum/utils/templating/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1262
- vellum/utils/templating/constants.py,sha256=XTNmDsKa7byjw4GMZmzx2dUeYUTeMLZrPgRHcc80Kvc,613
1263
- vellum/utils/templating/custom_filters.py,sha256=Q0DahYRHP4KfaUXDt9XxN-DFLBrAxlv90yaVqxScoUw,264
1262
+ vellum/utils/templating/constants.py,sha256=8OHMO6WFAEimbIaiHc5gy6s91D7_KvW-vTlEMWwvl_M,711
1263
+ vellum/utils/templating/custom_filters.py,sha256=XVHriwazejRZmxB_eg4xHgCxl7AiQQ2sx-hRLMmylfU,885
1264
1264
  vellum/utils/templating/exceptions.py,sha256=cDp140PP4OnInW4qAvg3KqiSiF70C71UyEAKRBR1Abo,46
1265
- vellum/utils/templating/render.py,sha256=2n6M10p2WtM2_6I10PKOIyH_gTmAo5EkxDYL2DR7F4U,2014
1265
+ vellum/utils/templating/render.py,sha256=ooQxCiBMAizPVfwJsIPS2feSBUuoalR1UeJMO0Df-3s,2029
1266
+ vellum/utils/templating/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1267
+ vellum/utils/templating/tests/test_custom_filters.py,sha256=mkJwc7t1gE13SKgPxhF-lN_m2XGCkphCB9Te81dGekI,532
1266
1268
  vellum/utils/typing.py,sha256=wx_daFqD69cYkuJTVnvNrpjhqC3uuhbnyJ9_bIwC9OU,327
1267
1269
  vellum/utils/uuid.py,sha256=Ch6wWRgwICxLxJCTl5iE3EdRlZj2zADR-zUMUtjcMWM,214
1268
1270
  vellum/version.py,sha256=jq-1PlAYxN9AXuaZqbYk9ak27SgE2lw9Ia5gx1b1gVI,76
@@ -1282,7 +1284,7 @@ vellum/workflows/emitters/base.py,sha256=D5SADKIvnbgKwIBgYm77jaqvpo1o0rz4MmuX_mu
1282
1284
  vellum/workflows/environment/__init__.py,sha256=wGHslgSEZ7Octe4C-hNtl84EFelNimgmWQoi7px4-uw,71
1283
1285
  vellum/workflows/environment/environment.py,sha256=0XhJPBs8YASWmvPx8bkSdCvcbDmzpe9stfs2kgtNDRU,296
1284
1286
  vellum/workflows/errors/__init__.py,sha256=tWGPu5xyAU8gRb8_bl0fL7OfU3wxQ9UH6qVwy4X4P_Q,113
1285
- vellum/workflows/errors/types.py,sha256=85tmSBt4d9OjUA4AdM5MvIy1vwVLpEu2MhkJhFF1q9k,3502
1287
+ vellum/workflows/errors/types.py,sha256=tVW7Il9zalnwWzdoDLqYPIvRTOhXIv6FPORZAbU7n5Q,3640
1286
1288
  vellum/workflows/events/__init__.py,sha256=6pxxceJo2dcaRkWtkDAYlUQZ-PHBQSZytIoyuUK48Qw,759
1287
1289
  vellum/workflows/events/node.py,sha256=uHT6If0esgZ3nLjrjmUPTKf3qbjGhoV_x5YKpjDBDcU,5280
1288
1290
  vellum/workflows/events/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1348,8 +1350,8 @@ vellum/workflows/nodes/core/retry_node/node.py,sha256=loIZJUcCsN0y3mr4pw7f23l4eD
1348
1350
  vellum/workflows/nodes/core/retry_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1349
1351
  vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=RM_OHwxrHwyxvlQQBJPqVBxpedFuWQ9h2-Xa3kP75sc,4399
1350
1352
  vellum/workflows/nodes/core/templating_node/__init__.py,sha256=GmyuYo81_A1_Bz6id69ozVFS6FKiuDsZTiA3I6MaL2U,70
1351
- vellum/workflows/nodes/core/templating_node/node.py,sha256=zCYhq88qLTvoC9LetVrD9sLXkwHZsaWekxMhru_nV70,3752
1352
- vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=j6v3TTD4Fjq-sWcuOZOzX-okFUC18q2VKiPT9ot1bk8,5830
1353
+ vellum/workflows/nodes/core/templating_node/node.py,sha256=Vqlg4L-5XNuIdbZKQe-GEYqTIV7iXNjLO7QIRgz4ujc,3722
1354
+ vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=-53Vh0YOnk8sAcmZ7drdKgBcSCj68DYts5-jFNNsPRE,6755
1353
1355
  vellum/workflows/nodes/core/try_node/__init__.py,sha256=JVD4DrldTIqFQQFrubs9KtWCCc0YCAc7Fzol5ZWIWeM,56
1354
1356
  vellum/workflows/nodes/core/try_node/node.py,sha256=bk2uhYUl10yaPJlOBWxiL7igTUrL_7mM9S2nvsdWB68,4242
1355
1357
  vellum/workflows/nodes/core/try_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1374,12 +1376,12 @@ vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMD
1374
1376
  vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
1375
1377
  vellum/workflows/nodes/displayable/bases/utils.py,sha256=ckMUenSsNkiYmSw6FmjSMHYaCk8Y8_sUjL6lkFFEqts,5412
1376
1378
  vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
1377
- vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=wgtqPljUqan9SILMysPCdSmZ0HoCpTTTNNaW0y9nQQI,9082
1379
+ vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=_yrQn_uLwy8zVW1RjFMoeomDEsbpbbKK7ifMGEBfNlk,9120
1378
1380
  vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1379
1381
  vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1380
1382
  vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
1381
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=1i48vpyFZ-zR5DD9wCu4Ekd-aq4gLOsSWnn0BMdJIAs,16810
1382
- vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=m5y6_sRX5P9icmneNhT_DkXYDNz7l_8Q_Aa8-U5dWsQ,4529
1383
+ vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=5WHsW_uEKDn1ukM9_O2FsGCYELfONz-2h_kYnNRNYHE,18333
1384
+ vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=rdWD1wtxPKHbdHRHEdTeRMSJi9sgAm2t0FqeAWuQHlQ,4534
1383
1385
  vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
1384
1386
  vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=Qjfl33gZ3JEgxBA1EgzSUebboGvsARthIxxcQyvx5Gg,1152
1385
1387
  vellum/workflows/nodes/displayable/final_output_node/__init__.py,sha256=G7VXM4OWpubvSJtVkGmMNeqgb9GkM7qZT838eL18XU4,72
@@ -1471,8 +1473,8 @@ vellum/workflows/workflows/base.py,sha256=tBivLLLPtMyMi2Bd5WjbwQ2_zZFpG8rNfEidfQ
1471
1473
  vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnadGsrSZGa7t7LpJA,2008
1472
1474
  vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1473
1475
  vellum/workflows/workflows/tests/test_base_workflow.py,sha256=dz5F3DuGOk9qUMjmNd-GdEE3320G5ko5nJ6J0QJyVcY,2659
1474
- vellum_ai-0.14.1.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1475
- vellum_ai-0.14.1.dist-info/METADATA,sha256=TGCti5BkhYzjafUugASpEkqaT-cfB5-0K0zWZQPi3II,5407
1476
- vellum_ai-0.14.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1477
- vellum_ai-0.14.1.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1478
- vellum_ai-0.14.1.dist-info/RECORD,,
1476
+ vellum_ai-0.14.2.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
1477
+ vellum_ai-0.14.2.dist-info/METADATA,sha256=w083H2Gds-z_b4DPwlYGdnCjD-UXv1q_3CqQAZtSLvI,5407
1478
+ vellum_ai-0.14.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
1479
+ vellum_ai-0.14.2.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
1480
+ vellum_ai-0.14.2.dist-info/RECORD,,
vellum_cli/pull.py CHANGED
@@ -2,14 +2,14 @@ import io
2
2
  import json
3
3
  import os
4
4
  from pathlib import Path
5
- from uuid import UUID
6
5
  import zipfile
7
- from typing import Optional, Union
6
+ from typing import Optional
8
7
 
9
8
  from dotenv import load_dotenv
10
9
  from pydash import snake_case
11
10
 
12
11
  from vellum.client.core.pydantic_utilities import UniversalBaseModel
12
+ from vellum.utils.uuid import is_valid_uuid
13
13
  from vellum.workflows.vellum_client import create_vellum_client
14
14
  from vellum_cli.config import VellumCliConfig, WorkflowConfig, load_vellum_cli_config
15
15
  from vellum_cli.logger import load_cli_logger
@@ -18,14 +18,6 @@ ERROR_LOG_FILE_NAME = "error.log"
18
18
  METADATA_FILE_NAME = "metadata.json"
19
19
 
20
20
 
21
- def _is_valid_uuid(val: Union[str, UUID, None]) -> bool:
22
- try:
23
- UUID(str(val))
24
- return True
25
- except (ValueError, TypeError):
26
- return False
27
-
28
-
29
21
  class WorkflowConfigResolutionResult(UniversalBaseModel):
30
22
  workflow_config: Optional[WorkflowConfig] = None
31
23
  pk: Optional[str] = None
@@ -88,7 +80,7 @@ def _resolve_workflow_config(
88
80
  elif workflow_deployment:
89
81
  module = (
90
82
  f"workflow_{workflow_deployment.split('-')[0]}"
91
- if _is_valid_uuid(workflow_deployment)
83
+ if is_valid_uuid(workflow_deployment)
92
84
  else snake_case(workflow_deployment)
93
85
  )
94
86
  workflow_config = WorkflowConfig(
@@ -127,7 +127,7 @@ class WorkflowOutputVellumDisplayOverrides(WorkflowOutputDisplay, WorkflowOutput
127
127
  name: str
128
128
  label: str
129
129
  node_id: UUID
130
- display_data: NodeDisplayData
130
+ display_data: Optional[NodeDisplayData] = None
131
131
  target_handle_id: Optional[UUID] = None
132
132
 
133
133
 
@@ -176,6 +176,16 @@ class VellumWorkflowDisplay(
176
176
  except IndexError:
177
177
  source_node_display = None
178
178
 
179
+ synthetic_target_handle_id = (
180
+ str(workflow_output_display.target_handle_id)
181
+ if workflow_output_display.target_handle_id
182
+ else str(uuid4_from_hash(f"{self.workflow_id}|target_handle_id|{workflow_output_display.name}"))
183
+ )
184
+ synthetic_display_data = (
185
+ workflow_output_display.display_data.dict()
186
+ if workflow_output_display.display_data
187
+ else NodeDisplayData().dict()
188
+ )
179
189
  nodes.append(
180
190
  {
181
191
  "id": str(final_output_node_id),
@@ -183,13 +193,13 @@ class VellumWorkflowDisplay(
183
193
  "data": {
184
194
  "label": workflow_output_display.label,
185
195
  "name": workflow_output_display.name,
186
- "target_handle_id": str(workflow_output_display.target_handle_id),
196
+ "target_handle_id": synthetic_target_handle_id,
187
197
  "output_id": str(workflow_output_display.id),
188
198
  "output_type": inferred_type,
189
199
  "node_input_id": str(node_input.id),
190
200
  },
191
201
  "inputs": [node_input.dict()],
192
- "display_data": workflow_output_display.display_data.dict(),
202
+ "display_data": synthetic_display_data,
193
203
  "base": final_output_node_base,
194
204
  "definition": None,
195
205
  }
@@ -211,7 +221,7 @@ class VellumWorkflowDisplay(
211
221
  "source_node_id": str(source_node_display.node_id),
212
222
  "source_handle_id": str(source_handle_id),
213
223
  "target_node_id": str(workflow_output_display.node_id),
214
- "target_handle_id": str(workflow_output_display.target_handle_id),
224
+ "target_handle_id": synthetic_target_handle_id,
215
225
  "type": "DEFAULT",
216
226
  }
217
227
  )
@@ -372,15 +382,12 @@ class VellumWorkflowDisplay(
372
382
 
373
383
  output_id = uuid4_from_hash(f"{self.workflow_id}|id|{output.name}")
374
384
  node_id = uuid4_from_hash(f"{self.workflow_id}|node_id|{output.name}")
375
- target_handle_id = uuid4_from_hash(f"{self.workflow_id}|target_handle_id|{output.name}")
376
385
 
377
386
  return WorkflowOutputVellumDisplay(
378
387
  id=output_id,
379
388
  node_id=node_id,
380
389
  name=output.name,
381
390
  label="Final Output",
382
- target_handle_id=target_handle_id,
383
- display_data=NodeDisplayData(),
384
391
  )
385
392
 
386
393
  def _generate_edge_display(
@@ -50,7 +50,5 @@ class WorkflowDisplay(VellumWorkflowDisplay[Workflow]):
50
50
  node_id=UUID("f3ef4b2b-fec9-4026-9cc6-e5eac295307f"),
51
51
  name="final-output",
52
52
  label="Final Output",
53
- target_handle_id=UUID("3ec34f6e-da48-40d5-a65b-a48fefa75763"),
54
- display_data=NodeDisplayData(position=NodeDisplayPosition(x=2750, y=210), width=459, height=234),
55
53
  )
56
54
  }