vellum-ai 0.14.72__py3-none-any.whl → 0.14.73__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 (66) hide show
  1. vellum/__init__.py +8 -0
  2. vellum/client/core/client_wrapper.py +1 -1
  3. vellum/client/core/serialization.py +1 -0
  4. vellum/client/types/__init__.py +8 -0
  5. vellum/client/types/build_status_enum.py +5 -0
  6. vellum/client/types/container_image_build_config.py +20 -0
  7. vellum/client/types/container_image_read.py +4 -0
  8. vellum/client/types/execute_api_response.py +2 -2
  9. vellum/client/types/folder_entity.py +2 -0
  10. vellum/client/types/folder_entity_dataset.py +26 -0
  11. vellum/client/types/folder_entity_dataset_data.py +25 -0
  12. vellum/types/build_status_enum.py +3 -0
  13. vellum/types/container_image_build_config.py +3 -0
  14. vellum/types/folder_entity_dataset.py +3 -0
  15. vellum/types/folder_entity_dataset_data.py +3 -0
  16. vellum/workflows/nodes/core/retry_node/tests/test_node.py +1 -1
  17. vellum/workflows/nodes/displayable/api_node/node.py +2 -0
  18. vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py +43 -0
  19. vellum/workflows/nodes/displayable/bases/api_node/node.py +6 -0
  20. vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +30 -4
  21. vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py +43 -3
  22. vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +68 -58
  23. vellum/workflows/nodes/experimental/tool_calling_node/node.py +10 -10
  24. vellum/workflows/nodes/experimental/tool_calling_node/tests/__init__.py +0 -0
  25. vellum/workflows/nodes/experimental/tool_calling_node/tests/test_utils.py +49 -0
  26. vellum/workflows/nodes/experimental/tool_calling_node/utils.py +67 -6
  27. vellum/workflows/ports/utils.py +26 -6
  28. vellum/workflows/runner/runner.py +35 -3
  29. vellum/workflows/types/core.py +12 -0
  30. vellum/workflows/types/definition.py +6 -0
  31. vellum/workflows/utils/functions.py +9 -9
  32. vellum/workflows/utils/pydantic_schema.py +38 -0
  33. vellum/workflows/utils/tests/test_functions.py +11 -11
  34. {vellum_ai-0.14.72.dist-info → vellum_ai-0.14.73.dist-info}/METADATA +1 -1
  35. {vellum_ai-0.14.72.dist-info → vellum_ai-0.14.73.dist-info}/RECORD +66 -54
  36. vellum_cli/push.py +6 -8
  37. vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +8 -1
  38. vellum_ee/workflows/display/tests/test_base_workflow_display.py +1 -1
  39. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +1 -1
  40. vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +1 -1
  41. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +5 -5
  42. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +12 -12
  43. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +10 -10
  44. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_state_serialization.py +3 -3
  45. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +3 -3
  46. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py +20 -9
  47. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +3 -3
  48. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +3 -3
  49. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +8 -8
  50. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +6 -6
  51. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +3 -3
  52. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +8 -8
  53. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py +3 -3
  54. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +4 -4
  55. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py +3 -3
  56. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +2 -2
  57. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +5 -5
  58. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +1 -1
  59. vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +1 -1
  60. vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +2 -2
  61. vellum_ee/workflows/display/utils/auto_layout.py +1 -1
  62. vellum_ee/workflows/display/workflows/base_workflow_display.py +179 -4
  63. vellum_ee/workflows/tests/test_serialize_module.py +47 -0
  64. {vellum_ai-0.14.72.dist-info → vellum_ai-0.14.73.dist-info}/LICENSE +0 -0
  65. {vellum_ai-0.14.72.dist-info → vellum_ai-0.14.73.dist-info}/WHEEL +0 -0
  66. {vellum_ai-0.14.72.dist-info → vellum_ai-0.14.73.dist-info}/entry_points.txt +0 -0
vellum/__init__.py CHANGED
@@ -34,6 +34,7 @@ from .types import (
34
34
  BasicVectorizerSentenceTransformersMultiQaMpnetBaseCosV1Request,
35
35
  BasicVectorizerSentenceTransformersMultiQaMpnetBaseDotV1,
36
36
  BasicVectorizerSentenceTransformersMultiQaMpnetBaseDotV1Request,
37
+ BuildStatusEnum,
37
38
  ChatHistoryInput,
38
39
  ChatHistoryInputRequest,
39
40
  ChatHistoryVellumValue,
@@ -69,6 +70,7 @@ from .types import (
69
70
  ConditionCombinator,
70
71
  ConditionalNodeResult,
71
72
  ConditionalNodeResultData,
73
+ ContainerImageBuildConfig,
72
74
  ContainerImageContainerImageTag,
73
75
  ContainerImageRead,
74
76
  CreateTestSuiteTestCaseRequest,
@@ -127,6 +129,8 @@ from .types import (
127
129
  FastEmbedVectorizerBaaiBgeSmallEnV15Request,
128
130
  FinishReasonEnum,
129
131
  FolderEntity,
132
+ FolderEntityDataset,
133
+ FolderEntityDatasetData,
130
134
  FolderEntityDocumentIndex,
131
135
  FolderEntityDocumentIndexData,
132
136
  FolderEntityFolder,
@@ -661,6 +665,7 @@ __all__ = [
661
665
  "BasicVectorizerSentenceTransformersMultiQaMpnetBaseCosV1Request",
662
666
  "BasicVectorizerSentenceTransformersMultiQaMpnetBaseDotV1",
663
667
  "BasicVectorizerSentenceTransformersMultiQaMpnetBaseDotV1Request",
668
+ "BuildStatusEnum",
664
669
  "ChatHistoryInput",
665
670
  "ChatHistoryInputRequest",
666
671
  "ChatHistoryVellumValue",
@@ -696,6 +701,7 @@ __all__ = [
696
701
  "ConditionCombinator",
697
702
  "ConditionalNodeResult",
698
703
  "ConditionalNodeResultData",
704
+ "ContainerImageBuildConfig",
699
705
  "ContainerImageContainerImageTag",
700
706
  "ContainerImageRead",
701
707
  "CreateTestSuiteTestCaseRequest",
@@ -757,6 +763,8 @@ __all__ = [
757
763
  "FinishReasonEnum",
758
764
  "FolderEntitiesListRequestEntityStatus",
759
765
  "FolderEntity",
766
+ "FolderEntityDataset",
767
+ "FolderEntityDatasetData",
760
768
  "FolderEntityDocumentIndex",
761
769
  "FolderEntityDocumentIndexData",
762
770
  "FolderEntityFolder",
@@ -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.72",
21
+ "X-Fern-SDK-Version": "0.14.73",
22
22
  }
23
23
  headers["X-API-KEY"] = self.api_key
24
24
  return headers
@@ -184,6 +184,7 @@ def _convert_mapping(
184
184
  converted_object[_alias_key(key, type_, direction, aliases_to_field_names)] = (
185
185
  convert_and_respect_annotation_metadata(object_=value, annotation=type_, direction=direction)
186
186
  )
187
+
187
188
  return converted_object
188
189
 
189
190
 
@@ -38,6 +38,7 @@ from .basic_vectorizer_sentence_transformers_multi_qa_mpnet_base_dot_v_1 import
38
38
  from .basic_vectorizer_sentence_transformers_multi_qa_mpnet_base_dot_v_1_request import (
39
39
  BasicVectorizerSentenceTransformersMultiQaMpnetBaseDotV1Request,
40
40
  )
41
+ from .build_status_enum import BuildStatusEnum
41
42
  from .chat_history_input import ChatHistoryInput
42
43
  from .chat_history_input_request import ChatHistoryInputRequest
43
44
  from .chat_history_vellum_value import ChatHistoryVellumValue
@@ -73,6 +74,7 @@ from .components_schemas_prompt_version_build_config_sandbox import ComponentsSc
73
74
  from .condition_combinator import ConditionCombinator
74
75
  from .conditional_node_result import ConditionalNodeResult
75
76
  from .conditional_node_result_data import ConditionalNodeResultData
77
+ from .container_image_build_config import ContainerImageBuildConfig
76
78
  from .container_image_container_image_tag import ContainerImageContainerImageTag
77
79
  from .container_image_read import ContainerImageRead
78
80
  from .create_test_suite_test_case_request import CreateTestSuiteTestCaseRequest
@@ -131,6 +133,8 @@ from .fast_embed_vectorizer_baai_bge_small_en_v_15 import FastEmbedVectorizerBaa
131
133
  from .fast_embed_vectorizer_baai_bge_small_en_v_15_request import FastEmbedVectorizerBaaiBgeSmallEnV15Request
132
134
  from .finish_reason_enum import FinishReasonEnum
133
135
  from .folder_entity import FolderEntity
136
+ from .folder_entity_dataset import FolderEntityDataset
137
+ from .folder_entity_dataset_data import FolderEntityDatasetData
134
138
  from .folder_entity_document_index import FolderEntityDocumentIndex
135
139
  from .folder_entity_document_index_data import FolderEntityDocumentIndexData
136
140
  from .folder_entity_folder import FolderEntityFolder
@@ -650,6 +654,7 @@ __all__ = [
650
654
  "BasicVectorizerSentenceTransformersMultiQaMpnetBaseCosV1Request",
651
655
  "BasicVectorizerSentenceTransformersMultiQaMpnetBaseDotV1",
652
656
  "BasicVectorizerSentenceTransformersMultiQaMpnetBaseDotV1Request",
657
+ "BuildStatusEnum",
653
658
  "ChatHistoryInput",
654
659
  "ChatHistoryInputRequest",
655
660
  "ChatHistoryVellumValue",
@@ -685,6 +690,7 @@ __all__ = [
685
690
  "ConditionCombinator",
686
691
  "ConditionalNodeResult",
687
692
  "ConditionalNodeResultData",
693
+ "ContainerImageBuildConfig",
688
694
  "ContainerImageContainerImageTag",
689
695
  "ContainerImageRead",
690
696
  "CreateTestSuiteTestCaseRequest",
@@ -743,6 +749,8 @@ __all__ = [
743
749
  "FastEmbedVectorizerBaaiBgeSmallEnV15Request",
744
750
  "FinishReasonEnum",
745
751
  "FolderEntity",
752
+ "FolderEntityDataset",
753
+ "FolderEntityDatasetData",
746
754
  "FolderEntityDocumentIndex",
747
755
  "FolderEntityDocumentIndexData",
748
756
  "FolderEntityFolder",
@@ -0,0 +1,5 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ BuildStatusEnum = typing.Union[typing.Literal["QUEUED", "BUILDING", "AVAILABLE", "FAILED", "UNKNOWN"], typing.Any]
@@ -0,0 +1,20 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ import typing
5
+ from .code_execution_package import CodeExecutionPackage
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
7
+ import pydantic
8
+
9
+
10
+ class ContainerImageBuildConfig(UniversalBaseModel):
11
+ packages: typing.List[CodeExecutionPackage]
12
+
13
+ if IS_PYDANTIC_V2:
14
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
15
+ else:
16
+
17
+ class Config:
18
+ frozen = True
19
+ smart_union = True
20
+ extra = pydantic.Extra.allow
@@ -5,6 +5,8 @@ from .entity_visibility import EntityVisibility
5
5
  import datetime as dt
6
6
  import typing
7
7
  from .container_image_container_image_tag import ContainerImageContainerImageTag
8
+ from .build_status_enum import BuildStatusEnum
9
+ from .container_image_build_config import ContainerImageBuildConfig
8
10
  from ..core.pydantic_utilities import IS_PYDANTIC_V2
9
11
  import pydantic
10
12
 
@@ -18,6 +20,8 @@ class ContainerImageRead(UniversalBaseModel):
18
20
  repository: str
19
21
  sha: str
20
22
  tags: typing.List[ContainerImageContainerImageTag]
23
+ build_status: typing.Optional[BuildStatusEnum] = None
24
+ build_config: typing.Optional[ContainerImageBuildConfig] = None
21
25
 
22
26
  if IS_PYDANTIC_V2:
23
27
  model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
@@ -2,9 +2,9 @@
2
2
 
3
3
  from ..core.pydantic_utilities import UniversalBaseModel
4
4
  import typing_extensions
5
+ import typing
5
6
  from .execute_api_response_json import ExecuteApiResponseJson
6
7
  from ..core.serialization import FieldMetadata
7
- import typing
8
8
  from ..core.pydantic_utilities import IS_PYDANTIC_V2
9
9
  import pydantic
10
10
 
@@ -12,7 +12,7 @@ import pydantic
12
12
  class ExecuteApiResponse(UniversalBaseModel):
13
13
  status_code: int
14
14
  text: str
15
- json_: typing_extensions.Annotated[ExecuteApiResponseJson, FieldMetadata(alias="json")]
15
+ json_: typing_extensions.Annotated[typing.Optional[ExecuteApiResponseJson], FieldMetadata(alias="json")] = None
16
16
  headers: typing.Dict[str, str]
17
17
 
18
18
  if IS_PYDANTIC_V2:
@@ -6,6 +6,7 @@ from .folder_entity_prompt_sandbox import FolderEntityPromptSandbox
6
6
  from .folder_entity_workflow_sandbox import FolderEntityWorkflowSandbox
7
7
  from .folder_entity_document_index import FolderEntityDocumentIndex
8
8
  from .folder_entity_test_suite import FolderEntityTestSuite
9
+ from .folder_entity_dataset import FolderEntityDataset
9
10
 
10
11
  FolderEntity = typing.Union[
11
12
  FolderEntityFolder,
@@ -13,4 +14,5 @@ FolderEntity = typing.Union[
13
14
  FolderEntityWorkflowSandbox,
14
15
  FolderEntityDocumentIndex,
15
16
  FolderEntityTestSuite,
17
+ FolderEntityDataset,
16
18
  ]
@@ -0,0 +1,26 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ import typing
5
+ from .folder_entity_dataset_data import FolderEntityDatasetData
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
7
+ import pydantic
8
+
9
+
10
+ class FolderEntityDataset(UniversalBaseModel):
11
+ """
12
+ A slim representation of a Dataset, as it exists within a Folder.
13
+ """
14
+
15
+ id: str
16
+ type: typing.Literal["DATASET"] = "DATASET"
17
+ data: FolderEntityDatasetData
18
+
19
+ if IS_PYDANTIC_V2:
20
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
21
+ else:
22
+
23
+ class Config:
24
+ frozen = True
25
+ smart_union = True
26
+ extra = pydantic.Extra.allow
@@ -0,0 +1,25 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ from ..core.pydantic_utilities import UniversalBaseModel
4
+ import typing
5
+ import datetime as dt
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2
7
+ import pydantic
8
+
9
+
10
+ class FolderEntityDatasetData(UniversalBaseModel):
11
+ id: str
12
+ label: str
13
+ name: str
14
+ description: typing.Optional[str] = None
15
+ created: dt.datetime
16
+ modified: dt.datetime
17
+
18
+ if IS_PYDANTIC_V2:
19
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
20
+ else:
21
+
22
+ class Config:
23
+ frozen = True
24
+ smart_union = True
25
+ extra = pydantic.Extra.allow
@@ -0,0 +1,3 @@
1
+ # WARNING: This file will be removed in a future release. Please import from "vellum.client" instead.
2
+
3
+ from vellum.client.types.build_status_enum import *
@@ -0,0 +1,3 @@
1
+ # WARNING: This file will be removed in a future release. Please import from "vellum.client" instead.
2
+
3
+ from vellum.client.types.container_image_build_config import *
@@ -0,0 +1,3 @@
1
+ # WARNING: This file will be removed in a future release. Please import from "vellum.client" instead.
2
+
3
+ from vellum.client.types.folder_entity_dataset import *
@@ -0,0 +1,3 @@
1
+ # WARNING: This file will be removed in a future release. Please import from "vellum.client" instead.
2
+
3
+ from vellum.client.types.folder_entity_dataset_data import *
@@ -44,7 +44,7 @@ def test_retry_node__retry_on_error_code__missed():
44
44
 
45
45
  def run(self) -> Outputs:
46
46
  if self.attempt_number < 3:
47
- raise Exception("This will not be retried")
47
+ raise NodeException(message="This will not be retried", code=WorkflowErrorCode.INTERNAL_ERROR)
48
48
 
49
49
  return self.Outputs(execution_count=self.attempt_number)
50
50
 
@@ -31,6 +31,8 @@ class APINode(BaseAPINode):
31
31
  merge_behavior = MergeBehavior.AWAIT_ANY
32
32
 
33
33
  def run(self) -> BaseAPINode.Outputs:
34
+ self._validate()
35
+
34
36
  headers = self.headers or {}
35
37
  header_overrides = {}
36
38
  bearer_token = None
@@ -3,6 +3,7 @@ import pytest
3
3
  from vellum import ExecuteApiResponse, VellumSecret as ClientVellumSecret
4
4
  from vellum.client.core.api_error import ApiError
5
5
  from vellum.workflows.constants import APIRequestMethod, AuthorizationType
6
+ from vellum.workflows.errors.types import WorkflowErrorCode
6
7
  from vellum.workflows.exceptions import NodeException
7
8
  from vellum.workflows.nodes import APINode
8
9
  from vellum.workflows.types.core import VellumSecret
@@ -190,3 +191,45 @@ def test_api_node__detects_client_environment_urls__legacy_does_not_override_hea
190
191
  # AND the vellum API should have been called with the correct headers
191
192
  assert mock_response.last_request
192
193
  assert mock_response.last_request.headers["X_API_KEY"] == "vellum-api-key-5678"
194
+
195
+
196
+ def test_api_node_raises_error_for_empty_url():
197
+ class APINodeWithEmptyURL(APINode):
198
+ method = APIRequestMethod.GET
199
+ url = ""
200
+
201
+ node = APINodeWithEmptyURL()
202
+
203
+ with pytest.raises(NodeException) as excinfo:
204
+ node.run()
205
+
206
+ assert excinfo.value.code == WorkflowErrorCode.INVALID_INPUTS
207
+ assert "URL is required and must be a non-empty string" in str(excinfo.value)
208
+
209
+
210
+ def test_api_node_raises_error_for_none_url():
211
+ class APINodeWithNoneURL(APINode):
212
+ method = APIRequestMethod.GET
213
+ url = None # type: ignore
214
+
215
+ node = APINodeWithNoneURL()
216
+
217
+ with pytest.raises(NodeException) as excinfo:
218
+ node.run()
219
+
220
+ assert excinfo.value.code == WorkflowErrorCode.INVALID_INPUTS
221
+ assert "URL is required and must be a non-empty string" in str(excinfo.value)
222
+
223
+
224
+ def test_api_node_raises_error_for_whitespace_url():
225
+ class APINodeWithWhitespaceURL(APINode):
226
+ method = APIRequestMethod.GET
227
+ url = " "
228
+
229
+ node = APINodeWithWhitespaceURL()
230
+
231
+ with pytest.raises(NodeException) as excinfo:
232
+ node.run()
233
+
234
+ assert excinfo.value.code == WorkflowErrorCode.INVALID_INPUTS
235
+ assert "URL is required and must be a non-empty string" in str(excinfo.value)
@@ -40,6 +40,10 @@ class BaseAPINode(BaseNode, Generic[StateType]):
40
40
  status_code: int
41
41
  text: str
42
42
 
43
+ def _validate(self) -> None:
44
+ if not self.url or not isinstance(self.url, str) or not self.url.strip():
45
+ raise NodeException("URL is required and must be a non-empty string", code=WorkflowErrorCode.INVALID_INPUTS)
46
+
43
47
  def run(self) -> Outputs:
44
48
  return self._run(method=self.method, url=self.url, data=self.data, json=self.json, headers=self.headers)
45
49
 
@@ -52,6 +56,8 @@ class BaseAPINode(BaseNode, Generic[StateType]):
52
56
  headers: Any = None,
53
57
  bearer_token: Optional[VellumSecret] = None,
54
58
  ) -> Outputs:
59
+ self._validate()
60
+
55
61
  vellum_instance = False
56
62
  for header in headers or {}:
57
63
  if isinstance(headers[header], VellumSecret):
@@ -30,8 +30,14 @@ from vellum.workflows.nodes.displayable.bases.base_prompt_node import BasePrompt
30
30
  from vellum.workflows.nodes.displayable.bases.inline_prompt_node.constants import DEFAULT_PROMPT_PARAMETERS
31
31
  from vellum.workflows.outputs import BaseOutput
32
32
  from vellum.workflows.types import MergeBehavior
33
+ from vellum.workflows.types.definition import DeploymentDefinition
33
34
  from vellum.workflows.types.generics import StateType, is_workflow_class
34
- from vellum.workflows.utils.functions import compile_function_definition, compile_workflow_function_definition
35
+ from vellum.workflows.utils.functions import (
36
+ compile_deployment_workflow_function_definition,
37
+ compile_function_definition,
38
+ compile_inline_workflow_function_definition,
39
+ )
40
+ from vellum.workflows.utils.pydantic_schema import normalize_json
35
41
 
36
42
 
37
43
  class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
@@ -93,6 +99,8 @@ class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
93
99
  execution_context = get_execution_context()
94
100
  request_options = self.request_options or RequestOptions()
95
101
 
102
+ processed_parameters = self._process_parameters(self.parameters)
103
+
96
104
  request_options["additional_body_parameters"] = {
97
105
  "execution_context": execution_context.model_dump(mode="json"),
98
106
  **request_options.get("additional_body_parameters", {}),
@@ -105,8 +113,15 @@ class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
105
113
  for function in self.functions:
106
114
  if isinstance(function, FunctionDefinition):
107
115
  normalized_functions.append(function)
116
+ elif isinstance(function, DeploymentDefinition):
117
+ normalized_functions.append(
118
+ compile_deployment_workflow_function_definition(
119
+ function.model_dump(),
120
+ vellum_client=self._context.vellum_client,
121
+ )
122
+ )
108
123
  elif is_workflow_class(function):
109
- normalized_functions.append(compile_workflow_function_definition(function))
124
+ normalized_functions.append(compile_inline_workflow_function_definition(function))
110
125
  else:
111
126
  normalized_functions.append(compile_function_definition(function))
112
127
 
@@ -117,7 +132,7 @@ class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
117
132
  ml_model=self.ml_model,
118
133
  input_values=input_values,
119
134
  input_variables=input_variables,
120
- parameters=self.parameters,
135
+ parameters=processed_parameters,
121
136
  blocks=self.blocks,
122
137
  settings=self.settings,
123
138
  functions=normalized_functions,
@@ -130,7 +145,7 @@ class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
130
145
  ml_model=self.ml_model,
131
146
  input_values=input_values,
132
147
  input_variables=input_variables,
133
- parameters=self.parameters,
148
+ parameters=processed_parameters,
134
149
  blocks=self.blocks,
135
150
  settings=self.settings,
136
151
  functions=normalized_functions,
@@ -267,3 +282,14 @@ class BaseInlinePromptNode(BasePromptNode[StateType], Generic[StateType]):
267
282
  )
268
283
 
269
284
  return input_variables, input_values
285
+
286
+ def _process_parameters(self, parameters: PromptParameters) -> PromptParameters:
287
+ """
288
+ Process parameters to recursively convert any Pydantic models to JSON schema dictionaries.
289
+ """
290
+ if not parameters.custom_parameters:
291
+ return parameters
292
+
293
+ processed_custom_params = normalize_json(parameters.custom_parameters)
294
+
295
+ return parameters.model_copy(update={"custom_parameters": processed_custom_params})
@@ -4,6 +4,8 @@ from unittest import mock
4
4
  from uuid import uuid4
5
5
  from typing import Any, Iterator, List
6
6
 
7
+ from pydantic import BaseModel
8
+
7
9
  from vellum import (
8
10
  AdHocExecutePromptEvent,
9
11
  ChatMessagePromptBlock,
@@ -192,10 +194,26 @@ def test_validation_with_extra_variables(vellum_adhoc_prompt_client):
192
194
  ]
193
195
 
194
196
 
197
+ class TestPydanticModel(BaseModel):
198
+ result: str
199
+ confidence: float = 0.9
200
+
201
+
195
202
  @pytest.mark.parametrize(
196
- "custom_parameters,test_description",
203
+ "custom_parameters,expected_custom_parameters,test_description",
197
204
  [
198
205
  (
206
+ {
207
+ "json_mode": False,
208
+ "json_schema": {
209
+ "name": "get_result",
210
+ "schema": {
211
+ "type": "object",
212
+ "required": ["result"],
213
+ "properties": {"result": {"type": "string", "description": ""}},
214
+ },
215
+ },
216
+ },
199
217
  {
200
218
  "json_mode": False,
201
219
  "json_schema": {
@@ -209,13 +227,34 @@ def test_validation_with_extra_variables(vellum_adhoc_prompt_client):
209
227
  },
210
228
  "with json_schema configured",
211
229
  ),
230
+ (
231
+ {
232
+ "json_mode": False,
233
+ "json_schema": {"name": "get_result_pydantic", "schema": TestPydanticModel},
234
+ },
235
+ {
236
+ "json_mode": False,
237
+ "json_schema": {
238
+ "name": "get_result_pydantic",
239
+ "schema": {
240
+ "type": "object",
241
+ "properties": {"result": {"type": "string"}, "confidence": {"type": "number", "default": 0.9}},
242
+ "required": ["result"],
243
+ },
244
+ },
245
+ },
246
+ "with json_schema configured using Pydantic model",
247
+ ),
212
248
  (
249
+ {},
213
250
  {},
214
251
  "without json_mode or json_schema configured",
215
252
  ),
216
253
  ],
217
254
  )
218
- def test_inline_prompt_node__json_output(vellum_adhoc_prompt_client, custom_parameters, test_description):
255
+ def test_inline_prompt_node__json_output(
256
+ vellum_adhoc_prompt_client, custom_parameters, expected_custom_parameters, test_description
257
+ ):
219
258
  """Confirm that InlinePromptNodes output the expected JSON when run."""
220
259
 
221
260
  # GIVEN a node that subclasses InlinePromptNode
@@ -281,6 +320,7 @@ def test_inline_prompt_node__json_output(vellum_adhoc_prompt_client, custom_para
281
320
  assert json_output.value == expected_json
282
321
 
283
322
  # AND we should have made the expected call to Vellum search
323
+
284
324
  vellum_adhoc_prompt_client.adhoc_execute_prompt_stream.assert_called_once_with(
285
325
  blocks=[],
286
326
  expand_meta=None,
@@ -297,7 +337,7 @@ def test_inline_prompt_node__json_output(vellum_adhoc_prompt_client, custom_para
297
337
  frequency_penalty=0.0,
298
338
  presence_penalty=0.0,
299
339
  logit_bias=None,
300
- custom_parameters=custom_parameters,
340
+ custom_parameters=expected_custom_parameters,
301
341
  ),
302
342
  request_options=mock.ANY,
303
343
  settings=None,