vellum-ai 0.14.72__py3-none-any.whl → 0.14.74__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vellum/__init__.py +8 -0
- vellum/client/core/client_wrapper.py +1 -1
- vellum/client/types/__init__.py +8 -0
- vellum/client/types/build_status_enum.py +5 -0
- vellum/client/types/container_image_build_config.py +20 -0
- vellum/client/types/container_image_read.py +4 -0
- vellum/client/types/execute_api_response.py +2 -2
- vellum/client/types/folder_entity.py +2 -0
- vellum/client/types/folder_entity_dataset.py +26 -0
- vellum/client/types/folder_entity_dataset_data.py +25 -0
- vellum/client/types/secret_type_enum.py +3 -1
- vellum/types/build_status_enum.py +3 -0
- vellum/types/container_image_build_config.py +3 -0
- vellum/types/folder_entity_dataset.py +3 -0
- vellum/types/folder_entity_dataset_data.py +3 -0
- vellum/workflows/nodes/core/retry_node/tests/test_node.py +1 -1
- vellum/workflows/nodes/displayable/api_node/node.py +2 -0
- vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py +43 -0
- vellum/workflows/nodes/displayable/bases/api_node/node.py +6 -0
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +30 -4
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py +43 -3
- vellum/workflows/nodes/displayable/bases/utils.py +2 -0
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +68 -58
- vellum/workflows/nodes/experimental/tool_calling_node/node.py +15 -11
- vellum/workflows/nodes/experimental/tool_calling_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/experimental/tool_calling_node/tests/test_node.py +13 -0
- vellum/workflows/nodes/experimental/tool_calling_node/tests/test_utils.py +49 -0
- vellum/workflows/nodes/experimental/tool_calling_node/utils.py +78 -7
- vellum/workflows/ports/utils.py +26 -6
- vellum/workflows/runner/runner.py +35 -3
- vellum/workflows/state/encoder.py +2 -0
- vellum/workflows/types/core.py +12 -0
- vellum/workflows/types/definition.py +6 -0
- vellum/workflows/utils/functions.py +12 -12
- vellum/workflows/utils/pydantic_schema.py +38 -0
- vellum/workflows/utils/tests/test_functions.py +18 -18
- {vellum_ai-0.14.72.dist-info → vellum_ai-0.14.74.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.72.dist-info → vellum_ai-0.14.74.dist-info}/RECORD +74 -61
- vellum_cli/push.py +6 -8
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +36 -7
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +8 -1
- vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py +102 -0
- vellum_ee/workflows/display/tests/test_base_workflow_display.py +1 -1
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +1 -1
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py +91 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +5 -5
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +12 -12
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +10 -10
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_default_state_serialization.py +3 -3
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +3 -3
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py +20 -9
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +3 -3
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_prompt_node_serialization.py +120 -3
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +8 -8
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +6 -6
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +3 -3
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +8 -8
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_search_node_serialization.py +3 -3
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +4 -4
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_templating_node_serialization.py +3 -3
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +2 -2
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +12 -5
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +8 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_workflow_deployment_serialization.py +62 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +1 -1
- vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +2 -2
- vellum_ee/workflows/display/utils/auto_layout.py +1 -1
- vellum_ee/workflows/display/utils/expressions.py +33 -2
- vellum_ee/workflows/display/workflows/base_workflow_display.py +199 -10
- vellum_ee/workflows/tests/test_display_meta.py +41 -0
- vellum_ee/workflows/tests/test_serialize_module.py +47 -0
- {vellum_ai-0.14.72.dist-info → vellum_ai-0.14.74.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.72.dist-info → vellum_ai-0.14.74.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.72.dist-info → vellum_ai-0.14.74.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.
|
21
|
+
"X-Fern-SDK-Version": "0.14.74",
|
22
22
|
}
|
23
23
|
headers["X-API-KEY"] = self.api_key
|
24
24
|
return headers
|
vellum/client/types/__init__.py
CHANGED
@@ -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,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
|
@@ -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
|
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
|
|
@@ -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
|
35
|
+
from vellum.workflows.utils.functions import (
|
36
|
+
compile_function_definition,
|
37
|
+
compile_inline_workflow_function_definition,
|
38
|
+
compile_workflow_deployment_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_workflow_deployment_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(
|
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=
|
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=
|
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})
|
vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py
CHANGED
@@ -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(
|
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=
|
340
|
+
custom_parameters=expected_custom_parameters,
|
301
341
|
),
|
302
342
|
request_options=mock.ANY,
|
303
343
|
settings=None,
|
@@ -52,6 +52,8 @@ def primitive_to_vellum_value(value: Any) -> VellumValue:
|
|
52
52
|
return StringVellumValue(value=value)
|
53
53
|
elif isinstance(value, enum.Enum):
|
54
54
|
return StringVellumValue(value=value.value)
|
55
|
+
elif isinstance(value, bool):
|
56
|
+
return JsonVellumValue(value=value)
|
55
57
|
elif isinstance(value, (int, float)):
|
56
58
|
return NumberVellumValue(value=value)
|
57
59
|
elif isinstance(value, list) and (
|