vellum-ai 0.13.9__py3-none-any.whl → 0.13.11__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 (60) hide show
  1. vellum/client/core/client_wrapper.py +1 -1
  2. vellum/workflows/descriptors/utils.py +1 -1
  3. vellum/workflows/errors/types.py +21 -0
  4. vellum/workflows/nodes/bases/base.py +1 -1
  5. vellum/workflows/nodes/displayable/api_node/node.py +4 -1
  6. vellum/workflows/nodes/displayable/bases/api_node/node.py +4 -1
  7. vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +18 -2
  8. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +4 -0
  9. vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +4 -0
  10. vellum/workflows/nodes/displayable/bases/search_node.py +4 -0
  11. vellum/workflows/nodes/displayable/bases/tests/test_utils.py +18 -0
  12. vellum/workflows/nodes/displayable/bases/utils.py +8 -1
  13. vellum/workflows/nodes/displayable/code_execution_node/node.py +4 -1
  14. vellum/workflows/nodes/displayable/conditional_node/node.py +4 -0
  15. vellum/workflows/nodes/displayable/final_output_node/node.py +4 -0
  16. vellum/workflows/nodes/displayable/guardrail_node/node.py +4 -1
  17. vellum/workflows/nodes/displayable/inline_prompt_node/node.py +4 -0
  18. vellum/workflows/nodes/displayable/inline_prompt_node/tests/test_node.py +55 -0
  19. vellum/workflows/nodes/displayable/merge_node/node.py +3 -1
  20. vellum/workflows/nodes/displayable/note_node/node.py +4 -0
  21. vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +4 -0
  22. vellum/workflows/nodes/displayable/search_node/node.py +4 -0
  23. vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +4 -1
  24. {vellum_ai-0.13.9.dist-info → vellum_ai-0.13.11.dist-info}/METADATA +1 -1
  25. {vellum_ai-0.13.9.dist-info → vellum_ai-0.13.11.dist-info}/RECORD +59 -59
  26. vellum_cli/__init__.py +9 -1
  27. vellum_cli/config.py +29 -1
  28. vellum_cli/push.py +24 -3
  29. vellum_cli/tests/conftest.py +3 -0
  30. vellum_cli/tests/test_pull.py +6 -0
  31. vellum_cli/tests/test_push.py +88 -1
  32. vellum_ee/workflows/display/nodes/base_node_display.py +207 -3
  33. vellum_ee/workflows/display/nodes/base_node_vellum_display.py +16 -1
  34. vellum_ee/workflows/display/nodes/get_node_display_class.py +6 -4
  35. vellum_ee/workflows/display/nodes/vellum/__init__.py +0 -2
  36. vellum_ee/workflows/display/nodes/vellum/conditional_node.py +2 -1
  37. vellum_ee/workflows/display/nodes/vellum/error_node.py +9 -3
  38. vellum_ee/workflows/display/nodes/vellum/tests/test_error_node.py +44 -0
  39. vellum_ee/workflows/display/nodes/vellum/try_node.py +8 -2
  40. vellum_ee/workflows/display/nodes/vellum/utils.py +0 -69
  41. vellum_ee/workflows/display/tests/test_vellum_workflow_display.py +56 -0
  42. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py +4 -3
  43. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +146 -26
  44. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +11 -11
  45. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py +7 -7
  46. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py +33 -35
  47. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py +4 -4
  48. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +5 -5
  49. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +15 -1
  50. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py +1 -1
  51. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +6 -3
  52. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +6 -3
  53. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +3 -3
  54. vellum_ee/workflows/display/utils/vellum.py +74 -4
  55. vellum_ee/workflows/display/workflows/base_workflow_display.py +6 -4
  56. vellum_ee/workflows/display/workflows/vellum_workflow_display.py +26 -14
  57. vellum_ee/workflows/display/nodes/vellum/base_node.py +0 -192
  58. {vellum_ai-0.13.9.dist-info → vellum_ai-0.13.11.dist-info}/LICENSE +0 -0
  59. {vellum_ai-0.13.9.dist-info → vellum_ai-0.13.11.dist-info}/WHEEL +0 -0
  60. {vellum_ai-0.13.9.dist-info → vellum_ai-0.13.11.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.13.9",
21
+ "X-Fern-SDK-Version": "0.13.11",
22
22
  }
23
23
  headers["X_API_KEY"] = self.api_key
24
24
  return headers
@@ -108,7 +108,7 @@ def is_unresolved(value: Any) -> bool:
108
108
  if isinstance(value, Mapping):
109
109
  return any(is_unresolved(item) for item in value.values())
110
110
 
111
- if isinstance(value, Sequence):
111
+ if isinstance(value, Sequence) and not isinstance(value, str):
112
112
  return any(is_unresolved(item) for item in value)
113
113
 
114
114
  if isinstance(value, Set):
@@ -61,3 +61,24 @@ def workflow_event_error_to_workflow_error(error: WorkflowEventError) -> Workflo
61
61
  message=error.message,
62
62
  code=_WORKFLOW_EVENT_ERROR_CODE_TO_WORKFLOW_ERROR_CODE.get(error.code, WorkflowErrorCode.INTERNAL_ERROR),
63
63
  )
64
+
65
+
66
+ _WORKFLOW_ERROR_CODE_TO_VELLUM_ERROR_CODE: Dict[WorkflowErrorCode, VellumErrorCodeEnum] = {
67
+ WorkflowErrorCode.INVALID_WORKFLOW: "INVALID_REQUEST",
68
+ WorkflowErrorCode.INVALID_INPUTS: "INVALID_INPUTS",
69
+ WorkflowErrorCode.INVALID_OUTPUTS: "INVALID_REQUEST",
70
+ WorkflowErrorCode.INVALID_STATE: "INVALID_REQUEST",
71
+ WorkflowErrorCode.INVALID_TEMPLATE: "INVALID_INPUTS",
72
+ WorkflowErrorCode.INTERNAL_ERROR: "INTERNAL_SERVER_ERROR",
73
+ WorkflowErrorCode.NODE_EXECUTION: "USER_DEFINED_ERROR",
74
+ WorkflowErrorCode.PROVIDER_ERROR: "PROVIDER_ERROR",
75
+ WorkflowErrorCode.USER_DEFINED_ERROR: "USER_DEFINED_ERROR",
76
+ WorkflowErrorCode.WORKFLOW_CANCELLED: "REQUEST_TIMEOUT",
77
+ }
78
+
79
+
80
+ def workflow_error_to_vellum_error(error: WorkflowError) -> VellumError:
81
+ return VellumError(
82
+ message=error.message,
83
+ code=_WORKFLOW_ERROR_CODE_TO_VELLUM_ERROR_CODE.get(error.code, "INTERNAL_SERVER_ERROR"),
84
+ )
@@ -237,7 +237,7 @@ class BaseNode(Generic[StateType], metaclass=BaseNodeMeta):
237
237
 
238
238
  class Trigger(metaclass=_BaseNodeTriggerMeta):
239
239
  node_class: Type["BaseNode"]
240
- merge_behavior = MergeBehavior.AWAIT_ANY
240
+ merge_behavior = MergeBehavior.AWAIT_ATTRIBUTES
241
241
 
242
242
  @classmethod
243
243
  def should_initiate(
@@ -2,7 +2,7 @@ from typing import Optional, Union
2
2
 
3
3
  from vellum.workflows.constants import AuthorizationType
4
4
  from vellum.workflows.nodes.displayable.bases.api_node import BaseAPINode
5
- from vellum.workflows.types.core import VellumSecret
5
+ from vellum.workflows.types.core import MergeBehavior, VellumSecret
6
6
 
7
7
 
8
8
  class APINode(BaseAPINode):
@@ -27,6 +27,9 @@ class APINode(BaseAPINode):
27
27
  api_key_header_value: Optional[Union[str, VellumSecret]] = None
28
28
  bearer_token_value: Optional[Union[str, VellumSecret]] = None
29
29
 
30
+ class Trigger(BaseAPINode.Trigger):
31
+ merge_behavior = MergeBehavior.AWAIT_ANY
32
+
30
33
  def run(self) -> BaseAPINode.Outputs:
31
34
  headers = self.headers or {}
32
35
  header_overrides = {}
@@ -8,7 +8,7 @@ from vellum.workflows.errors.types import WorkflowErrorCode
8
8
  from vellum.workflows.exceptions import NodeException
9
9
  from vellum.workflows.nodes.bases import BaseNode
10
10
  from vellum.workflows.outputs import BaseOutputs
11
- from vellum.workflows.types.core import Json, VellumSecret
11
+ from vellum.workflows.types.core import Json, MergeBehavior, VellumSecret
12
12
  from vellum.workflows.types.generics import StateType
13
13
 
14
14
 
@@ -23,6 +23,9 @@ class BaseAPINode(BaseNode, Generic[StateType]):
23
23
  headers: Optional[Dict[str, Union[str, VellumSecret]]] - The headers to send in the request.
24
24
  """
25
25
 
26
+ class Trigger(BaseNode.Trigger):
27
+ merge_behavior = MergeBehavior.AWAIT_ANY
28
+
26
29
  url: str
27
30
  method: APIRequestMethod
28
31
  data: Optional[str] = None
@@ -2,12 +2,13 @@ from abc import abstractmethod
2
2
  from typing import ClassVar, Generator, Generic, Iterator, List, Optional, Union
3
3
 
4
4
  from vellum import AdHocExecutePromptEvent, ExecutePromptEvent, PromptOutput
5
+ from vellum.client.core.api_error import ApiError
5
6
  from vellum.core import RequestOptions
6
7
  from vellum.workflows.errors.types import WorkflowErrorCode, vellum_error_to_workflow_error
7
8
  from vellum.workflows.exceptions import NodeException
8
9
  from vellum.workflows.nodes.bases import BaseNode
9
10
  from vellum.workflows.outputs.base import BaseOutput, BaseOutputs
10
- from vellum.workflows.types.core import EntityInputsInterface
11
+ from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior
11
12
  from vellum.workflows.types.generics import StateType
12
13
 
13
14
 
@@ -17,6 +18,9 @@ class BasePromptNode(BaseNode, Generic[StateType]):
17
18
 
18
19
  request_options: Optional[RequestOptions] = None
19
20
 
21
+ class Trigger(BaseNode.Trigger):
22
+ merge_behavior = MergeBehavior.AWAIT_ANY
23
+
20
24
  class Outputs(BaseOutputs):
21
25
  results: List[PromptOutput]
22
26
 
@@ -33,7 +37,19 @@ class BasePromptNode(BaseNode, Generic[StateType]):
33
37
  )
34
38
 
35
39
  def _process_prompt_event_stream(self) -> Generator[BaseOutput, None, Optional[List[PromptOutput]]]:
36
- prompt_event_stream = self._get_prompt_event_stream()
40
+ try:
41
+ prompt_event_stream = self._get_prompt_event_stream()
42
+ except ApiError as e:
43
+ if e.status_code and e.status_code >= 400 and e.status_code < 500 and isinstance(e.body, dict):
44
+ raise NodeException(
45
+ message=e.body.get("detail", "Failed to execute prompt"),
46
+ code=WorkflowErrorCode.INVALID_INPUTS,
47
+ ) from e
48
+
49
+ raise NodeException(
50
+ message="Failed to execute prompt",
51
+ code=WorkflowErrorCode.INTERNAL_ERROR,
52
+ ) from e
37
53
 
38
54
  outputs: Optional[List[PromptOutput]] = None
39
55
  for event in prompt_event_stream:
@@ -23,6 +23,7 @@ from vellum.workflows.events.types import default_serializer
23
23
  from vellum.workflows.exceptions import NodeException
24
24
  from vellum.workflows.nodes.displayable.bases.base_prompt_node import BasePromptNode
25
25
  from vellum.workflows.nodes.displayable.bases.inline_prompt_node.constants import DEFAULT_PROMPT_PARAMETERS
26
+ from vellum.workflows.types import MergeBehavior
26
27
  from vellum.workflows.types.generics import StateType
27
28
  from vellum.workflows.utils.functions import compile_function_definition
28
29
 
@@ -51,6 +52,9 @@ class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
51
52
  parameters: PromptParameters = DEFAULT_PROMPT_PARAMETERS
52
53
  expand_meta: Optional[AdHocExpandMeta] = OMIT
53
54
 
55
+ class Trigger(BasePromptNode.Trigger):
56
+ merge_behavior = MergeBehavior.AWAIT_ANY
57
+
54
58
  def _get_prompt_event_stream(self) -> Iterator[AdHocExecutePromptEvent]:
55
59
  input_variables, input_values = self._compile_prompt_inputs()
56
60
  parent_context = get_parent_context()
@@ -17,6 +17,7 @@ from vellum.workflows.context import get_parent_context
17
17
  from vellum.workflows.errors import WorkflowErrorCode
18
18
  from vellum.workflows.exceptions import NodeException
19
19
  from vellum.workflows.nodes.displayable.bases.base_prompt_node import BasePromptNode
20
+ from vellum.workflows.types import MergeBehavior
20
21
  from vellum.workflows.types.generics import StateType
21
22
 
22
23
 
@@ -47,6 +48,9 @@ class BasePromptDeploymentNode(BasePromptNode, Generic[StateType]):
47
48
  expand_raw: Optional[Sequence[str]] = OMIT
48
49
  metadata: Optional[Dict[str, Optional[Any]]] = OMIT
49
50
 
51
+ class Trigger(BasePromptNode.Trigger):
52
+ merge_behavior = MergeBehavior.AWAIT_ANY
53
+
50
54
  def _get_prompt_event_stream(self) -> Iterator[ExecutePromptEvent]:
51
55
  current_parent_context = get_parent_context()
52
56
  parent_context = current_parent_context.model_dump() if current_parent_context else None
@@ -17,6 +17,7 @@ from vellum.workflows.exceptions import NodeException
17
17
  from vellum.workflows.nodes.bases import BaseNode
18
18
  from vellum.workflows.nodes.displayable.bases.types import SearchFilters
19
19
  from vellum.workflows.outputs import BaseOutputs
20
+ from vellum.workflows.types import MergeBehavior
20
21
  from vellum.workflows.types.generics import StateType
21
22
 
22
23
  DEFAULT_SEARCH_WEIGHTS = 0.8
@@ -81,6 +82,9 @@ class BaseSearchNode(BaseNode[StateType], Generic[StateType]):
81
82
 
82
83
  request_options: Optional[RequestOptions] = None
83
84
 
85
+ class Trigger(BaseNode.Trigger):
86
+ merge_behavior = MergeBehavior.AWAIT_ANY
87
+
84
88
  class Outputs(BaseOutputs):
85
89
  """
86
90
  The outputs of the SearchNode.
@@ -1,8 +1,11 @@
1
1
  import pytest
2
2
  import enum
3
3
 
4
+ from pydantic import BaseModel
5
+
4
6
  from vellum.client.types.chat_history_vellum_value import ChatHistoryVellumValue
5
7
  from vellum.client.types.chat_message import ChatMessage
8
+ from vellum.client.types.error_vellum_value import ErrorVellumValue
6
9
  from vellum.client.types.json_vellum_value import JsonVellumValue
7
10
  from vellum.client.types.number_vellum_value import NumberVellumValue
8
11
  from vellum.client.types.search_result import SearchResult
@@ -10,6 +13,8 @@ from vellum.client.types.search_result_document import SearchResultDocument
10
13
  from vellum.client.types.search_results_vellum_value import SearchResultsVellumValue
11
14
  from vellum.client.types.string_vellum_value import StringVellumValue
12
15
  from vellum.client.types.string_vellum_value_request import StringVellumValueRequest
16
+ from vellum.client.types.vellum_error import VellumError
17
+ from vellum.workflows.errors.types import WorkflowError, WorkflowErrorCode
13
18
  from vellum.workflows.nodes.displayable.bases.utils import primitive_to_vellum_value, primitive_to_vellum_value_request
14
19
 
15
20
 
@@ -17,6 +22,10 @@ class MockEnum(enum.Enum):
17
22
  FOO = "foo"
18
23
 
19
24
 
25
+ class RandomPydanticModel(BaseModel):
26
+ foo: str
27
+
28
+
20
29
  @pytest.mark.parametrize(
21
30
  ["value", "expected_output"],
22
31
  [
@@ -51,6 +60,15 @@ class MockEnum(enum.Enum):
51
60
  (StringVellumValue(value="hello"), StringVellumValue(value="hello")),
52
61
  (StringVellumValueRequest(value="hello"), StringVellumValueRequest(value="hello")),
53
62
  ({"foo": "bar"}, JsonVellumValue(value={"foo": "bar"})),
63
+ (
64
+ VellumError(message="hello", code="USER_DEFINED_ERROR"),
65
+ ErrorVellumValue(value=VellumError(message="hello", code="USER_DEFINED_ERROR")),
66
+ ),
67
+ (
68
+ WorkflowError(message="hello", code=WorkflowErrorCode.USER_DEFINED_ERROR),
69
+ ErrorVellumValue(value=VellumError(message="hello", code="USER_DEFINED_ERROR")),
70
+ ),
71
+ (RandomPydanticModel(foo="bar"), JsonVellumValue(value={"foo": "bar"})),
54
72
  ],
55
73
  )
56
74
  def test_primitive_to_vellum_value(value, expected_output):
@@ -25,8 +25,11 @@ from vellum.client.types.search_results_vellum_value import SearchResultsVellumV
25
25
  from vellum.client.types.search_results_vellum_value_request import SearchResultsVellumValueRequest
26
26
  from vellum.client.types.string_vellum_value import StringVellumValue
27
27
  from vellum.client.types.string_vellum_value_request import StringVellumValueRequest
28
+ from vellum.client.types.vellum_error import VellumError
28
29
  from vellum.client.types.vellum_value import VellumValue
29
30
  from vellum.client.types.vellum_value_request import VellumValueRequest
31
+ from vellum.workflows.errors.types import WorkflowError, workflow_error_to_vellum_error
32
+ from vellum.workflows.state.encoder import DefaultStateEncoder
30
33
 
31
34
  VELLUM_VALUE_REQUEST_TUPLE = (
32
35
  StringVellumValueRequest,
@@ -63,6 +66,10 @@ def primitive_to_vellum_value(value: Any) -> VellumValue:
63
66
  ):
64
67
  search_results = cast(Union[List[SearchResultRequest], List[SearchResult]], value)
65
68
  return SearchResultsVellumValue(value=search_results)
69
+ elif isinstance(value, VellumError):
70
+ return ErrorVellumValue(value=value)
71
+ elif isinstance(value, WorkflowError):
72
+ return ErrorVellumValue(value=workflow_error_to_vellum_error(value))
66
73
  elif isinstance(
67
74
  value,
68
75
  (
@@ -88,7 +95,7 @@ def primitive_to_vellum_value(value: Any) -> VellumValue:
88
95
  return value # type: ignore
89
96
 
90
97
  try:
91
- json_value = json.dumps(value)
98
+ json_value = json.dumps(value, cls=DefaultStateEncoder)
92
99
  except json.JSONDecodeError:
93
100
  raise ValueError(f"Unsupported variable type: {value.__class__.__name__}")
94
101
 
@@ -26,7 +26,7 @@ from vellum.workflows.nodes.bases import BaseNode
26
26
  from vellum.workflows.nodes.bases.base import BaseNodeMeta
27
27
  from vellum.workflows.nodes.displayable.code_execution_node.utils import read_file_from_path
28
28
  from vellum.workflows.outputs.base import BaseOutputs
29
- from vellum.workflows.types.core import EntityInputsInterface, VellumSecret
29
+ from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior, VellumSecret
30
30
  from vellum.workflows.types.generics import StateType
31
31
  from vellum.workflows.types.utils import get_original_base
32
32
  from vellum.workflows.utils.vellum_variables import primitive_type_to_vellum_variable_type
@@ -82,6 +82,9 @@ class CodeExecutionNode(BaseNode[StateType], Generic[StateType, _OutputType], me
82
82
 
83
83
  request_options: Optional[RequestOptions] = None
84
84
 
85
+ class Trigger(BaseNode.Trigger):
86
+ merge_behavior = MergeBehavior.AWAIT_ANY
87
+
85
88
  class Outputs(BaseOutputs):
86
89
  # We use our mypy plugin to override the _OutputType with the actual output type
87
90
  # for downstream references to this output.
@@ -6,6 +6,7 @@ from vellum.workflows.ports.node_ports import NodePorts
6
6
  from vellum.workflows.ports.port import Port
7
7
  from vellum.workflows.ports.utils import validate_ports
8
8
  from vellum.workflows.state.base import BaseState
9
+ from vellum.workflows.types import MergeBehavior
9
10
 
10
11
 
11
12
  class ConditionalNode(BaseNode):
@@ -14,6 +15,9 @@ class ConditionalNode(BaseNode):
14
15
  Vellum's Conditional Node, and for most cases, you should extend `BaseNode.Ports` directly.
15
16
  """
16
17
 
18
+ class Trigger(BaseNode.Trigger):
19
+ merge_behavior = MergeBehavior.AWAIT_ANY
20
+
17
21
  class Ports(NodePorts):
18
22
  def __call__(self, outputs: BaseOutputs, state: BaseState) -> Set[Port]:
19
23
  all_ports = [port for port in self.__class__]
@@ -2,6 +2,7 @@ from typing import Any, Dict, Generic, Tuple, Type, TypeVar, get_args
2
2
 
3
3
  from vellum.workflows.nodes.bases import BaseNode
4
4
  from vellum.workflows.nodes.bases.base import BaseNodeMeta
5
+ from vellum.workflows.types import MergeBehavior
5
6
  from vellum.workflows.types.generics import StateType
6
7
  from vellum.workflows.types.utils import get_original_base
7
8
 
@@ -41,6 +42,9 @@ class FinalOutputNode(BaseNode[StateType], Generic[StateType, _OutputType], meta
41
42
  This provides backward compatibility with Vellum's Final Output Node.
42
43
  """
43
44
 
45
+ class Trigger(BaseNode.Trigger):
46
+ merge_behavior = MergeBehavior.AWAIT_ANY
47
+
44
48
  class Outputs(BaseNode.Outputs):
45
49
  # We use our mypy plugin to override the _OutputType with the actual output type
46
50
  # for downstream references to this output.
@@ -8,7 +8,7 @@ from vellum.workflows.errors.types import WorkflowErrorCode
8
8
  from vellum.workflows.exceptions import NodeException
9
9
  from vellum.workflows.nodes.bases import BaseNode
10
10
  from vellum.workflows.outputs.base import BaseOutputs
11
- from vellum.workflows.types.core import EntityInputsInterface
11
+ from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior
12
12
  from vellum.workflows.types.generics import StateType
13
13
 
14
14
 
@@ -29,6 +29,9 @@ class GuardrailNode(BaseNode[StateType], Generic[StateType]):
29
29
 
30
30
  request_options: Optional[RequestOptions] = None
31
31
 
32
+ class Trigger(BaseNode.Trigger):
33
+ merge_behavior = MergeBehavior.AWAIT_ANY
34
+
32
35
  class Outputs(BaseOutputs):
33
36
  score: float
34
37
 
@@ -5,6 +5,7 @@ from vellum.workflows.errors import WorkflowErrorCode
5
5
  from vellum.workflows.exceptions import NodeException
6
6
  from vellum.workflows.nodes.displayable.bases import BaseInlinePromptNode as BaseInlinePromptNode
7
7
  from vellum.workflows.outputs import BaseOutput
8
+ from vellum.workflows.types import MergeBehavior
8
9
  from vellum.workflows.types.generics import StateType
9
10
 
10
11
 
@@ -21,6 +22,9 @@ class InlinePromptNode(BaseInlinePromptNode[StateType]):
21
22
  request_options: Optional[RequestOptions] - The request options to use for the Prompt Execution
22
23
  """
23
24
 
25
+ class Trigger(BaseInlinePromptNode.Trigger):
26
+ merge_behavior = MergeBehavior.AWAIT_ANY
27
+
24
28
  class Outputs(BaseInlinePromptNode.Outputs):
25
29
  """
26
30
  The outputs of the InlinePromptNode.
@@ -1,7 +1,9 @@
1
+ import pytest
1
2
  from dataclasses import dataclass
2
3
  from uuid import uuid4
3
4
  from typing import Any, Iterator, List
4
5
 
6
+ from vellum.client.core.api_error import ApiError
5
7
  from vellum.client.core.pydantic_utilities import UniversalBaseModel
6
8
  from vellum.client.types.execute_prompt_event import ExecutePromptEvent
7
9
  from vellum.client.types.fulfilled_execute_prompt_event import FulfilledExecutePromptEvent
@@ -12,6 +14,8 @@ from vellum.client.types.initiated_execute_prompt_event import InitiatedExecuteP
12
14
  from vellum.client.types.prompt_output import PromptOutput
13
15
  from vellum.client.types.prompt_request_json_input import PromptRequestJsonInput
14
16
  from vellum.client.types.string_vellum_value import StringVellumValue
17
+ from vellum.workflows.errors.types import WorkflowErrorCode
18
+ from vellum.workflows.exceptions import NodeException
15
19
  from vellum.workflows.nodes.displayable.inline_prompt_node.node import InlinePromptNode
16
20
 
17
21
 
@@ -126,3 +130,54 @@ def test_inline_prompt_node__function_definitions(vellum_adhoc_prompt_client):
126
130
  "name": "my_function"
127
131
  }"""
128
132
  )
133
+
134
+
135
+ @pytest.mark.parametrize(
136
+ ["exception", "expected_code", "expected_message"],
137
+ [
138
+ (
139
+ ApiError(status_code=404, body={"detail": "Model not found"}),
140
+ WorkflowErrorCode.INVALID_INPUTS,
141
+ "Model not found",
142
+ ),
143
+ (
144
+ ApiError(status_code=404, body={"message": "Model not found"}),
145
+ WorkflowErrorCode.INVALID_INPUTS,
146
+ "Failed to execute prompt",
147
+ ),
148
+ (
149
+ ApiError(status_code=404, body="Model not found"),
150
+ WorkflowErrorCode.INTERNAL_ERROR,
151
+ "Failed to execute prompt",
152
+ ),
153
+ (
154
+ ApiError(status_code=None, body={"detail": "Model not found"}),
155
+ WorkflowErrorCode.INTERNAL_ERROR,
156
+ "Failed to execute prompt",
157
+ ),
158
+ (
159
+ ApiError(status_code=500, body={"detail": "Model not found"}),
160
+ WorkflowErrorCode.INTERNAL_ERROR,
161
+ "Failed to execute prompt",
162
+ ),
163
+ ],
164
+ ids=["404", "invalid_dict", "invalid_body", "no_status_code", "500"],
165
+ )
166
+ def test_inline_prompt_node__api_error__invalid_inputs_node_exception(
167
+ vellum_adhoc_prompt_client, exception, expected_code, expected_message
168
+ ):
169
+ # GIVEN a prompt node with an invalid model name
170
+ class MyNode(InlinePromptNode):
171
+ ml_model = "my-invalid-model"
172
+ blocks = []
173
+
174
+ # AND the adhoc prompt client raises a 4xx error
175
+ vellum_adhoc_prompt_client.adhoc_execute_prompt_stream.side_effect = exception
176
+
177
+ # WHEN the node is run
178
+ with pytest.raises(NodeException) as e:
179
+ list(MyNode().run())
180
+
181
+ # THEN the node raises the correct NodeException
182
+ assert e.value.code == expected_code
183
+ assert e.value.message == expected_message
@@ -1,4 +1,5 @@
1
1
  from vellum.workflows.nodes.bases import BaseNode
2
+ from vellum.workflows.types import MergeBehavior
2
3
 
3
4
 
4
5
  class MergeNode(BaseNode):
@@ -7,4 +8,5 @@ class MergeNode(BaseNode):
7
8
  with Vellum's Merge Node, and for most cases, you should extend from `BaseNode.Trigger` directly.
8
9
  """
9
10
 
10
- pass
11
+ class Trigger(BaseNode.Trigger):
12
+ merge_behavior = MergeBehavior.AWAIT_ANY
@@ -1,4 +1,5 @@
1
1
  from vellum.workflows.nodes.bases import BaseNode
2
+ from vellum.workflows.types import MergeBehavior
2
3
 
3
4
 
4
5
  class NoteNode(BaseNode):
@@ -6,5 +7,8 @@ class NoteNode(BaseNode):
6
7
  A no-op Node purely used to display a note in the Vellum UI.
7
8
  """
8
9
 
10
+ class Trigger(BaseNode.Trigger):
11
+ merge_behavior = MergeBehavior.AWAIT_ANY
12
+
9
13
  def run(self) -> BaseNode.Outputs:
10
14
  raise RuntimeError("NoteNode should never be run")
@@ -4,6 +4,7 @@ from vellum.workflows.errors import WorkflowErrorCode
4
4
  from vellum.workflows.exceptions import NodeException
5
5
  from vellum.workflows.nodes.displayable.bases import BasePromptDeploymentNode as BasePromptDeploymentNode
6
6
  from vellum.workflows.outputs import BaseOutput
7
+ from vellum.workflows.types import MergeBehavior
7
8
  from vellum.workflows.types.generics import StateType
8
9
 
9
10
 
@@ -23,6 +24,9 @@ class PromptDeploymentNode(BasePromptDeploymentNode[StateType]):
23
24
  request_options: Optional[RequestOptions] - The request options to use for the Prompt Execution
24
25
  """
25
26
 
27
+ class Trigger(BasePromptDeploymentNode.Trigger):
28
+ merge_behavior = MergeBehavior.AWAIT_ANY
29
+
26
30
  class Outputs(BasePromptDeploymentNode.Outputs):
27
31
  """
28
32
  The outputs of the PromptDeploymentNode.
@@ -1,6 +1,7 @@
1
1
  from typing import ClassVar
2
2
 
3
3
  from vellum.workflows.nodes.displayable.bases import BaseSearchNode as BaseSearchNode
4
+ from vellum.workflows.types import MergeBehavior
4
5
  from vellum.workflows.types.generics import StateType
5
6
 
6
7
 
@@ -18,6 +19,9 @@ class SearchNode(BaseSearchNode[StateType]):
18
19
 
19
20
  chunk_separator: ClassVar[str] = "\n\n#####\n\n"
20
21
 
22
+ class Trigger(BaseSearchNode.Trigger):
23
+ merge_behavior = MergeBehavior.AWAIT_ANY
24
+
21
25
  class Outputs(BaseSearchNode.Outputs):
22
26
  """
23
27
  The outputs of the SearchNode.
@@ -19,7 +19,7 @@ from vellum.workflows.errors.types import workflow_event_error_to_workflow_error
19
19
  from vellum.workflows.exceptions import NodeException
20
20
  from vellum.workflows.nodes.bases.base import BaseNode
21
21
  from vellum.workflows.outputs.base import BaseOutput
22
- from vellum.workflows.types.core import EntityInputsInterface
22
+ from vellum.workflows.types.core import EntityInputsInterface, MergeBehavior
23
23
  from vellum.workflows.types.generics import StateType
24
24
 
25
25
 
@@ -49,6 +49,9 @@ class SubworkflowDeploymentNode(BaseNode[StateType], Generic[StateType]):
49
49
 
50
50
  request_options: Optional[RequestOptions] = None
51
51
 
52
+ class Trigger(BaseNode.Trigger):
53
+ merge_behavior = MergeBehavior.AWAIT_ANY
54
+
52
55
  def _compile_subworkflow_inputs(self) -> List[WorkflowRequestInputRequest]:
53
56
  # TODO: We may want to consolidate with prompt deployment input compilation
54
57
  # https://app.shortcut.com/vellum/story/4117
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vellum-ai
3
- Version: 0.13.9
3
+ Version: 0.13.11
4
4
  Summary:
5
5
  License: MIT
6
6
  Requires-Python: >=3.9,<4.0