vellum-ai 0.14.46__py3-none-any.whl → 0.14.47__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/client/README.md +2 -2
- vellum/client/__init__.py +72 -6
- vellum/client/core/client_wrapper.py +1 -1
- vellum/client/core/file.py +13 -8
- vellum/client/core/http_client.py +26 -14
- vellum/client/core/pydantic_utilities.py +2 -2
- vellum/client/core/request_options.py +3 -0
- vellum/client/resources/ad_hoc/client.py +14 -2
- vellum/client/resources/container_images/client.py +6 -0
- vellum/client/resources/deployments/client.py +12 -0
- vellum/client/resources/document_indexes/client.py +18 -0
- vellum/client/resources/documents/client.py +6 -0
- vellum/client/resources/folder_entities/client.py +6 -0
- vellum/client/resources/metric_definitions/client.py +6 -0
- vellum/client/resources/prompts/client.py +6 -0
- vellum/client/resources/sandboxes/client.py +12 -0
- vellum/client/resources/test_suite_runs/client.py +6 -0
- vellum/client/resources/test_suites/client.py +2 -2
- vellum/client/resources/workflow_deployments/client.py +6 -0
- vellum/client/resources/workflow_sandboxes/client.py +6 -0
- vellum/client/resources/workflows/client.py +6 -4
- vellum/client/resources/workspace_secrets/client.py +6 -0
- vellum/client/types/api_request_parent_context.py +0 -6
- vellum/client/types/array_input.py +0 -5
- vellum/client/types/code_execution_node_array_result.py +0 -5
- vellum/client/types/code_execution_node_result.py +0 -5
- vellum/client/types/code_execution_node_result_data.py +0 -5
- vellum/client/types/code_executor_response.py +0 -5
- vellum/client/types/create_test_suite_test_case_request.py +0 -5
- vellum/client/types/deployment_history_item.py +0 -5
- vellum/client/types/deployment_read.py +0 -5
- vellum/client/types/execute_workflow_response.py +0 -5
- vellum/client/types/execution_array_vellum_value.py +0 -5
- vellum/client/types/external_test_case_execution.py +0 -5
- vellum/client/types/external_test_case_execution_request.py +0 -5
- vellum/client/types/fulfilled_execute_workflow_workflow_result_event.py +0 -7
- vellum/client/types/fulfilled_workflow_node_result_event.py +0 -5
- vellum/client/types/initiated_workflow_node_result_event.py +0 -5
- vellum/client/types/metadata_filter_config_request.py +0 -5
- vellum/client/types/metric_definition_execution.py +0 -5
- vellum/client/types/metric_definition_history_item.py +0 -5
- vellum/client/types/named_test_case_array_variable_value.py +0 -5
- vellum/client/types/named_test_case_array_variable_value_request.py +0 -7
- vellum/client/types/node_execution_fulfilled_event.py +0 -11
- vellum/client/types/node_execution_initiated_event.py +0 -11
- vellum/client/types/node_execution_paused_event.py +0 -11
- vellum/client/types/node_execution_rejected_event.py +0 -11
- vellum/client/types/node_execution_resumed_event.py +0 -11
- vellum/client/types/node_execution_span.py +0 -11
- vellum/client/types/node_execution_streaming_event.py +0 -11
- vellum/client/types/node_input_compiled_array_value.py +0 -5
- vellum/client/types/node_output_compiled_array_value.py +0 -5
- vellum/client/types/node_parent_context.py +0 -6
- vellum/client/types/paginated_slim_deployment_read_list.py +0 -5
- vellum/client/types/paginated_slim_workflow_deployment_list.py +0 -5
- vellum/client/types/paginated_test_suite_run_execution_list.py +0 -5
- vellum/client/types/paginated_test_suite_test_case_list.py +0 -5
- vellum/client/types/prompt_deployment_parent_context.py +0 -6
- vellum/client/types/prompt_exec_config.py +0 -6
- vellum/client/types/rejected_workflow_node_result_event.py +0 -5
- vellum/client/types/replace_test_suite_test_case_request.py +0 -5
- vellum/client/types/search_filters_request.py +0 -7
- vellum/client/types/search_request_options_request.py +0 -7
- vellum/client/types/slim_deployment_read.py +0 -5
- vellum/client/types/slim_workflow_deployment.py +0 -5
- vellum/client/types/slim_workflow_execution_read.py +0 -12
- vellum/client/types/span_link.py +0 -6
- vellum/client/types/streaming_workflow_node_result_event.py +0 -5
- vellum/client/types/templating_node_array_result.py +0 -5
- vellum/client/types/templating_node_result.py +0 -5
- vellum/client/types/templating_node_result_data.py +0 -5
- vellum/client/types/terminal_node_array_result.py +0 -5
- vellum/client/types/terminal_node_result.py +0 -5
- vellum/client/types/terminal_node_result_data.py +0 -5
- vellum/client/types/test_case_array_variable_value.py +0 -5
- vellum/client/types/test_suite_run_execution.py +0 -5
- vellum/client/types/test_suite_run_execution_array_output.py +0 -5
- vellum/client/types/test_suite_run_execution_metric_result.py +0 -5
- vellum/client/types/test_suite_run_external_exec_config.py +0 -5
- vellum/client/types/test_suite_run_external_exec_config_data.py +0 -5
- vellum/client/types/test_suite_run_external_exec_config_data_request.py +0 -7
- vellum/client/types/test_suite_run_external_exec_config_request.py +0 -7
- vellum/client/types/test_suite_run_metric_array_output.py +0 -5
- vellum/client/types/test_suite_run_read.py +0 -5
- vellum/client/types/test_suite_test_case.py +0 -5
- vellum/client/types/test_suite_test_case_create_bulk_operation_request.py +0 -7
- vellum/client/types/test_suite_test_case_replace_bulk_operation_request.py +0 -7
- vellum/client/types/test_suite_test_case_upsert_bulk_operation_request.py +0 -7
- vellum/client/types/upsert_test_suite_test_case_request.py +0 -5
- vellum/client/types/vellum_value_logical_condition_group_request.py +0 -3
- vellum/client/types/vellum_value_logical_condition_request.py +0 -5
- vellum/client/types/vellum_variable.py +0 -5
- vellum/client/types/workflow_deployment_event_executions_response.py +0 -26
- vellum/client/types/workflow_deployment_history_item.py +0 -5
- vellum/client/types/workflow_deployment_parent_context.py +0 -6
- vellum/client/types/workflow_deployment_read.py +0 -5
- vellum/client/types/workflow_deployment_release.py +0 -5
- vellum/client/types/workflow_deployment_release_workflow_version.py +0 -5
- vellum/client/types/workflow_event_execution_read.py +0 -12
- vellum/client/types/workflow_execution_actual.py +0 -5
- vellum/client/types/workflow_execution_fulfilled_event.py +0 -11
- vellum/client/types/workflow_execution_initiated_event.py +0 -11
- vellum/client/types/workflow_execution_node_result_event.py +0 -5
- vellum/client/types/workflow_execution_paused_event.py +0 -11
- vellum/client/types/workflow_execution_rejected_event.py +0 -11
- vellum/client/types/workflow_execution_resumed_event.py +0 -11
- vellum/client/types/workflow_execution_snapshotted_event.py +0 -13
- vellum/client/types/workflow_execution_span.py +0 -11
- vellum/client/types/workflow_execution_streaming_event.py +0 -11
- vellum/client/types/workflow_execution_view_online_eval_metric_result.py +0 -7
- vellum/client/types/workflow_execution_workflow_result_event.py +0 -5
- vellum/client/types/workflow_output_array.py +0 -5
- vellum/client/types/workflow_parent_context.py +0 -6
- vellum/client/types/workflow_result_event.py +0 -5
- vellum/client/types/workflow_result_event_output_data_array.py +0 -5
- vellum/client/types/workflow_sandbox_parent_context.py +0 -6
- vellum/workflows/nodes/bases/base.py +26 -6
- vellum/workflows/nodes/bases/tests/test_base_node.py +30 -0
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +50 -0
- vellum/workflows/nodes/utils.py +5 -1
- vellum/workflows/types/code_execution_node_wrappers.py +5 -0
- {vellum_ai-0.14.46.dist-info → vellum_ai-0.14.47.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.46.dist-info → vellum_ai-0.14.47.dist-info}/RECORD +148 -148
- vellum_ee/workflows/display/nodes/base_node_display.py +17 -6
- vellum_ee/workflows/display/nodes/get_node_display_class.py +4 -5
- vellum_ee/workflows/display/nodes/vellum/api_node.py +11 -0
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +5 -0
- vellum_ee/workflows/display/nodes/vellum/error_node.py +22 -16
- vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +46 -12
- vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/map_node.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/search_node.py +8 -0
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +1 -0
- vellum_ee/workflows/display/nodes/vellum/templating_node.py +2 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_code_execution_node.py +1 -1
- vellum_ee/workflows/display/nodes/vellum/tests/test_error_node.py +4 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_deployment_node.py +4 -3
- vellum_ee/workflows/display/nodes/vellum/tests/test_prompt_node.py +36 -2
- vellum_ee/workflows/display/nodes/vellum/tests/test_subworkflow_deployment_node.py +5 -4
- vellum_ee/workflows/display/nodes/vellum/tests/test_templating_node.py +1 -1
- vellum_ee/workflows/display/tests/test_base_workflow_display.py +44 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py +2 -4
- vellum_ee/workflows/display/utils/expressions.py +2 -2
- {vellum_ai-0.14.46.dist-info → vellum_ai-0.14.47.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.46.dist-info → vellum_ai-0.14.47.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.46.dist-info → vellum_ai-0.14.47.dist-info}/entry_points.txt +0 -0
@@ -9,6 +9,7 @@ from typing import (
|
|
9
9
|
ForwardRef,
|
10
10
|
Generic,
|
11
11
|
Optional,
|
12
|
+
Set,
|
12
13
|
Tuple,
|
13
14
|
Type,
|
14
15
|
TypeVar,
|
@@ -24,6 +25,7 @@ from vellum.workflows.nodes.bases.base import BaseNode
|
|
24
25
|
from vellum.workflows.nodes.utils import get_unadorned_node, get_wrapped_node
|
25
26
|
from vellum.workflows.ports import Port
|
26
27
|
from vellum.workflows.references import OutputReference
|
28
|
+
from vellum.workflows.references.node import NodeReference
|
27
29
|
from vellum.workflows.types.core import JsonArray, JsonObject
|
28
30
|
from vellum.workflows.types.generics import NodeType
|
29
31
|
from vellum.workflows.types.utils import get_original_base
|
@@ -33,7 +35,7 @@ from vellum.workflows.utils.vellum_variables import primitive_type_to_vellum_var
|
|
33
35
|
from vellum_ee.workflows.display.editor.types import NodeDisplayComment, NodeDisplayData
|
34
36
|
from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
|
35
37
|
from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay, PortDisplay, PortDisplayOverrides
|
36
|
-
from vellum_ee.workflows.display.utils.expressions import
|
38
|
+
from vellum_ee.workflows.display.utils.expressions import serialize_value
|
37
39
|
from vellum_ee.workflows.display.utils.registry import register_node_display_class
|
38
40
|
|
39
41
|
if TYPE_CHECKING:
|
@@ -98,11 +100,18 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
|
|
98
100
|
# Default values set by the metaclass
|
99
101
|
output_display: Dict[OutputReference, NodeOutputDisplay]
|
100
102
|
port_displays: Dict[Port, PortDisplayOverrides] = {}
|
101
|
-
|
103
|
+
attribute_ids_by_name: ClassVar[Dict[str, UUID]] = {}
|
102
104
|
|
105
|
+
# START: Attributes for backwards compatible serialization
|
103
106
|
# Used to explicitly set the target handle id for a node
|
104
107
|
# Once all nodes are Generic Nodes, we may replace this with a trigger_id or trigger attribute
|
105
108
|
target_handle_id: ClassVar[Optional[UUID]] = None
|
109
|
+
# Used to explicitly set the input ids for each node input
|
110
|
+
node_input_ids_by_name: ClassVar[Dict[str, UUID]] = {}
|
111
|
+
# Used by each class extending BaseNodeDisplay to specify which attributes are meant to be serialized
|
112
|
+
# as the former `"inputs"` field
|
113
|
+
__serializable_inputs__: Set[NodeReference] = set()
|
114
|
+
# END: Attributes for backwards compatible serialization
|
106
115
|
|
107
116
|
def serialize(self, display_context: "WorkflowDisplayContext", **kwargs: Any) -> JsonObject:
|
108
117
|
node = self._node
|
@@ -114,7 +123,11 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
|
|
114
123
|
# We don't need to serialize generic node attributes containing a subworkflow
|
115
124
|
continue
|
116
125
|
|
117
|
-
id =
|
126
|
+
id = (
|
127
|
+
str(self.attribute_ids_by_name[attribute.name])
|
128
|
+
if self.attribute_ids_by_name
|
129
|
+
else str(uuid4_from_hash(f"{node_id}|{attribute.name}"))
|
130
|
+
)
|
118
131
|
try:
|
119
132
|
attributes.append(
|
120
133
|
{
|
@@ -191,9 +204,7 @@ class BaseNodeDisplay(Generic[NodeType], metaclass=BaseNodeDisplayMeta):
|
|
191
204
|
"id": id,
|
192
205
|
"name": port.name,
|
193
206
|
"type": port._condition_type.value,
|
194
|
-
"expression": (
|
195
|
-
serialize_condition(display_context, port._condition) if port._condition else None
|
196
|
-
),
|
207
|
+
"expression": (serialize_value(display_context, port._condition) if port._condition else None),
|
197
208
|
}
|
198
209
|
)
|
199
210
|
else:
|
@@ -2,7 +2,6 @@ import types
|
|
2
2
|
from uuid import UUID
|
3
3
|
from typing import TYPE_CHECKING, Any, Dict, Generic, Type, TypeVar
|
4
4
|
|
5
|
-
from vellum.workflows.descriptors.base import BaseDescriptor
|
6
5
|
from vellum.workflows.types.generics import NodeType
|
7
6
|
from vellum.workflows.utils.uuids import uuid4_from_hash
|
8
7
|
from vellum_ee.workflows.display.utils.registry import get_from_node_display_registry
|
@@ -30,14 +29,14 @@ def get_node_display_class(node_class: Type[NodeType]) -> Type["BaseNodeDisplay"
|
|
30
29
|
node_input_ids_by_name.update(_get_node_input_ids_by_ref(f"{path}.{key}", value))
|
31
30
|
return node_input_ids_by_name
|
32
31
|
|
33
|
-
|
34
|
-
return {path: uuid4_from_hash(f"{node_class.__id__}|{path}")}
|
35
|
-
|
36
|
-
return {}
|
32
|
+
return {path: uuid4_from_hash(f"{node_class.__id__}|{path}")}
|
37
33
|
|
38
34
|
def exec_body(ns: Dict):
|
39
35
|
node_input_ids_by_name: Dict[str, UUID] = {}
|
40
36
|
for ref in node_class:
|
37
|
+
if ref not in base_node_display_class.__serializable_inputs__:
|
38
|
+
continue
|
39
|
+
|
41
40
|
node_input_ids_by_name.update(_get_node_input_ids_by_ref(ref.name, ref.instance))
|
42
41
|
|
43
42
|
if node_input_ids_by_name:
|
@@ -20,6 +20,17 @@ class BaseAPINodeDisplay(BaseNodeDisplay[_APINodeType], Generic[_APINodeType]):
|
|
20
20
|
# A mapping between node input keys and their ids for inputs representing additional header values
|
21
21
|
additional_header_value_input_ids: ClassVar[Optional[Dict[str, UUID]]] = None
|
22
22
|
|
23
|
+
__serializable_inputs__ = {
|
24
|
+
APINode.url,
|
25
|
+
APINode.method,
|
26
|
+
APINode.json,
|
27
|
+
APINode.headers,
|
28
|
+
APINode.api_key_header_key,
|
29
|
+
APINode.api_key_header_value,
|
30
|
+
APINode.bearer_token_value,
|
31
|
+
APINode.authorization_type,
|
32
|
+
}
|
33
|
+
|
23
34
|
def serialize(
|
24
35
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs: Any
|
25
36
|
) -> JsonObject:
|
@@ -18,6 +18,11 @@ class BaseCodeExecutionNodeDisplay(BaseNodeDisplay[_CodeExecutionNodeType], Gene
|
|
18
18
|
output_id: ClassVar[Optional[UUID]] = None
|
19
19
|
log_output_id: ClassVar[Optional[UUID]] = None
|
20
20
|
|
21
|
+
__serializable_inputs__ = {
|
22
|
+
CodeExecutionNode.code,
|
23
|
+
CodeExecutionNode.code_inputs,
|
24
|
+
}
|
25
|
+
|
21
26
|
def serialize(
|
22
27
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
23
28
|
) -> JsonObject:
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from uuid import UUID
|
2
|
-
from typing import ClassVar, Generic, Optional, TypeVar
|
2
|
+
from typing import Any, ClassVar, Generic, Optional, TypeVar
|
3
3
|
|
4
4
|
from vellum.workflows.nodes import ErrorNode
|
5
5
|
from vellum.workflows.types.core import JsonObject
|
@@ -9,47 +9,53 @@ from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
|
|
9
9
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
10
10
|
|
11
11
|
_ErrorNodeType = TypeVar("_ErrorNodeType", bound=ErrorNode)
|
12
|
+
LEGACY_INPUT_NAME = "error_source_input_id"
|
12
13
|
|
13
14
|
|
14
15
|
class BaseErrorNodeDisplay(BaseNodeDisplay[_ErrorNodeType], Generic[_ErrorNodeType]):
|
16
|
+
# DEPRECATED: Remove in 0.15.0 once removed from the vellum-side
|
15
17
|
error_output_id: ClassVar[Optional[UUID]] = None
|
18
|
+
# DEPRECATED: Remove in 0.15.0 once removed from the vellum-side
|
19
|
+
name: ClassVar[Optional[str]] = None
|
16
20
|
|
17
|
-
|
21
|
+
__serializable_inputs__ = {ErrorNode.error}
|
18
22
|
|
19
|
-
def serialize(
|
20
|
-
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
21
|
-
) -> JsonObject:
|
23
|
+
def serialize(self, display_context: WorkflowDisplayContext, **kwargs) -> JsonObject:
|
22
24
|
node_id = self.node_id
|
23
|
-
error_source_input_id = self.node_input_ids_by_name.get(
|
25
|
+
error_source_input_id = self.node_input_ids_by_name.get(
|
26
|
+
ErrorNode.error.name,
|
27
|
+
) or self.node_input_ids_by_name.get(LEGACY_INPUT_NAME)
|
24
28
|
|
25
29
|
error_attribute = raise_if_descriptor(self._node.error)
|
26
|
-
input_values_by_name = {
|
27
|
-
"error_source_input_id": error_attribute,
|
28
|
-
}
|
29
30
|
|
30
31
|
node_inputs = [
|
31
32
|
create_node_input(
|
32
33
|
node_id=node_id,
|
33
|
-
input_name=
|
34
|
-
value=
|
34
|
+
input_name=LEGACY_INPUT_NAME,
|
35
|
+
value=error_attribute,
|
35
36
|
display_context=display_context,
|
36
|
-
input_id=
|
37
|
+
input_id=error_source_input_id,
|
37
38
|
)
|
38
|
-
for variable_name, variable_value in input_values_by_name.items()
|
39
39
|
]
|
40
40
|
|
41
|
-
|
41
|
+
node_data: dict[str, Any] = {
|
42
42
|
"id": str(node_id),
|
43
43
|
"type": "ERROR",
|
44
44
|
"inputs": [node_input.dict() for node_input in node_inputs],
|
45
45
|
"data": {
|
46
|
-
"name": self.name,
|
47
46
|
"label": self.label,
|
48
47
|
"target_handle_id": str(self.get_target_handle_id()),
|
49
48
|
"error_source_input_id": str(error_source_input_id),
|
50
|
-
"error_output_id": str(self.error_output_id),
|
51
49
|
},
|
52
50
|
"display_data": self.get_display_data().dict(),
|
53
51
|
"base": self.get_base().dict(),
|
54
52
|
"definition": self.get_definition().dict(),
|
55
53
|
}
|
54
|
+
|
55
|
+
if self.name:
|
56
|
+
node_data["data"]["name"] = self.name
|
57
|
+
|
58
|
+
if self.error_output_id:
|
59
|
+
node_data["data"]["error_output_id"] = str(self.error_output_id)
|
60
|
+
|
61
|
+
return node_data
|
@@ -12,6 +12,8 @@ _GuardrailNodeType = TypeVar("_GuardrailNodeType", bound=GuardrailNode)
|
|
12
12
|
|
13
13
|
|
14
14
|
class BaseGuardrailNodeDisplay(BaseNodeDisplay[_GuardrailNodeType], Generic[_GuardrailNodeType]):
|
15
|
+
__serializable_inputs__ = {GuardrailNode.metric_inputs}
|
16
|
+
|
15
17
|
def serialize(
|
16
18
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
17
19
|
) -> JsonObject:
|
@@ -10,6 +10,7 @@ from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
|
10
10
|
from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
|
11
11
|
from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
|
12
12
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
13
|
+
from vellum_ee.workflows.display.utils.expressions import serialize_value
|
13
14
|
from vellum_ee.workflows.display.utils.vellum import infer_vellum_variable_type
|
14
15
|
from vellum_ee.workflows.display.vellum import NodeInput
|
15
16
|
|
@@ -17,6 +18,8 @@ _InlinePromptNodeType = TypeVar("_InlinePromptNodeType", bound=InlinePromptNode)
|
|
17
18
|
|
18
19
|
|
19
20
|
class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generic[_InlinePromptNodeType]):
|
21
|
+
__serializable_inputs__ = {InlinePromptNode.prompt_inputs}
|
22
|
+
|
20
23
|
def serialize(
|
21
24
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
22
25
|
) -> JsonObject:
|
@@ -26,12 +29,14 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
26
29
|
node_inputs, prompt_inputs = self._generate_node_and_prompt_inputs(node_id, node, display_context)
|
27
30
|
input_variable_id_by_name = {prompt_input.key: prompt_input.id for prompt_input in prompt_inputs}
|
28
31
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
+
output_display = self.output_display[node.Outputs.text]
|
33
|
+
array_display = self.output_display[node.Outputs.results]
|
34
|
+
json_display = self.output_display[node.Outputs.json]
|
32
35
|
node_blocks = raise_if_descriptor(node.blocks)
|
33
36
|
function_definitions = raise_if_descriptor(node.functions)
|
34
37
|
|
38
|
+
ml_model = str(raise_if_descriptor(node.ml_model))
|
39
|
+
|
35
40
|
blocks: list = [
|
36
41
|
self._generate_prompt_block(block, input_variable_id_by_name, [i]) for i, block in enumerate(node_blocks)
|
37
42
|
]
|
@@ -42,7 +47,7 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
42
47
|
)
|
43
48
|
blocks.extend(functions)
|
44
49
|
|
45
|
-
|
50
|
+
serialized_node: JsonObject = {
|
46
51
|
"id": str(node_id),
|
47
52
|
"type": "PROMPT",
|
48
53
|
"inputs": [node_input.dict() for node_input in node_inputs],
|
@@ -62,7 +67,7 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
62
67
|
"blocks": blocks,
|
63
68
|
},
|
64
69
|
},
|
65
|
-
"ml_model_name":
|
70
|
+
"ml_model_name": ml_model,
|
66
71
|
},
|
67
72
|
"display_data": self.get_display_data().dict(),
|
68
73
|
"base": self.get_base().dict(),
|
@@ -74,6 +79,10 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
74
79
|
],
|
75
80
|
"ports": self.serialize_ports(display_context),
|
76
81
|
}
|
82
|
+
attributes = self._serialize_attributes(display_context)
|
83
|
+
if attributes:
|
84
|
+
serialized_node["attributes"] = attributes
|
85
|
+
return serialized_node
|
77
86
|
|
78
87
|
def _generate_node_and_prompt_inputs(
|
79
88
|
self,
|
@@ -127,6 +136,7 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
127
136
|
path: List[int],
|
128
137
|
) -> JsonObject:
|
129
138
|
block: JsonObject
|
139
|
+
block_id = uuid4_from_hash(f"{self.node_id}-{prompt_block.block_type}-{'-'.join([str(i) for i in path])}")
|
130
140
|
if prompt_block.block_type == "JINJA":
|
131
141
|
block = {
|
132
142
|
"block_type": "JINJA",
|
@@ -162,10 +172,21 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
162
172
|
}
|
163
173
|
|
164
174
|
elif prompt_block.block_type == "VARIABLE":
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
175
|
+
input_variable_id = input_variable_id_by_name.get(prompt_block.input_variable)
|
176
|
+
if input_variable_id:
|
177
|
+
block = {
|
178
|
+
"block_type": "VARIABLE",
|
179
|
+
"input_variable_id": input_variable_id,
|
180
|
+
}
|
181
|
+
else:
|
182
|
+
# Even though this will likely fail in runtime, we want to allow serialization to succeed
|
183
|
+
# in case the block is work in progress or the node is not yet part of the graph
|
184
|
+
block = {
|
185
|
+
"block_type": "VARIABLE",
|
186
|
+
"input_variable_id": str(
|
187
|
+
uuid4_from_hash(f"{block_id}-input_variable-{prompt_block.input_variable}")
|
188
|
+
),
|
189
|
+
}
|
169
190
|
|
170
191
|
elif prompt_block.block_type == "PLAIN_TEXT":
|
171
192
|
block = {
|
@@ -184,9 +205,7 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
184
205
|
else:
|
185
206
|
raise NotImplementedError(f"Serialization for prompt block type {prompt_block.block_type} not implemented")
|
186
207
|
|
187
|
-
block["id"] = str(
|
188
|
-
uuid4_from_hash(f"{self.node_id}-{prompt_block.block_type}-{'-'.join([str(i) for i in path])}")
|
189
|
-
)
|
208
|
+
block["id"] = str(block_id)
|
190
209
|
if prompt_block.cache_config:
|
191
210
|
block["cache_config"] = prompt_block.cache_config.dict()
|
192
211
|
else:
|
@@ -198,3 +217,18 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
198
217
|
block["state"] = "ENABLED"
|
199
218
|
|
200
219
|
return block
|
220
|
+
|
221
|
+
def _serialize_attributes(self, display_context: "WorkflowDisplayContext"):
|
222
|
+
attribute_instances_by_name = {}
|
223
|
+
for attribute in self._node:
|
224
|
+
if attribute.name in self.attribute_ids_by_name:
|
225
|
+
attribute_instances_by_name[attribute.name] = attribute.instance
|
226
|
+
|
227
|
+
return [
|
228
|
+
{
|
229
|
+
"id": str(attr_id),
|
230
|
+
"name": attr_name,
|
231
|
+
"value": serialize_value(display_context, attribute_instances_by_name[attr_name]),
|
232
|
+
}
|
233
|
+
for attr_name, attr_id in self.attribute_ids_by_name.items()
|
234
|
+
]
|
@@ -21,6 +21,8 @@ class BaseInlineSubworkflowNodeDisplay(
|
|
21
21
|
):
|
22
22
|
workflow_input_ids_by_name: ClassVar[Dict[str, UUID]] = {}
|
23
23
|
|
24
|
+
__serializable_inputs__ = {InlineSubworkflowNode.subworkflow_inputs}
|
25
|
+
|
24
26
|
def serialize(
|
25
27
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
26
28
|
) -> JsonObject:
|
@@ -13,6 +13,8 @@ _MapNodeType = TypeVar("_MapNodeType", bound=MapNode)
|
|
13
13
|
|
14
14
|
|
15
15
|
class BaseMapNodeDisplay(BaseAdornmentNodeDisplay[_MapNodeType], Generic[_MapNodeType]):
|
16
|
+
__serializable_inputs__ = {MapNode.items} # type: ignore[misc]
|
17
|
+
|
16
18
|
def serialize(
|
17
19
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
18
20
|
) -> JsonObject:
|
@@ -13,6 +13,8 @@ _PromptDeploymentNodeType = TypeVar("_PromptDeploymentNodeType", bound=PromptDep
|
|
13
13
|
|
14
14
|
|
15
15
|
class BasePromptDeploymentNodeDisplay(BaseNodeDisplay[_PromptDeploymentNodeType], Generic[_PromptDeploymentNodeType]):
|
16
|
+
__serializable_inputs__ = {PromptDeploymentNode.prompt_inputs}
|
17
|
+
|
16
18
|
def serialize(
|
17
19
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
18
20
|
) -> JsonObject:
|
@@ -32,6 +32,14 @@ class BaseSearchNodeDisplay(BaseNodeDisplay[_SearchNodeType], Generic[_SearchNod
|
|
32
32
|
# A mapping between the id of the operand (e.g. "lhs_variable_id" or "rhs_variable_id") and the id of the node input
|
33
33
|
# that the operand is pointing to.
|
34
34
|
metadata_filter_input_id_by_operand_id: Dict[UUID, UUID] = {}
|
35
|
+
__serializable_inputs__ = {
|
36
|
+
SearchNode.query,
|
37
|
+
SearchNode.document_index,
|
38
|
+
SearchNode.weights,
|
39
|
+
SearchNode.chunk_separator,
|
40
|
+
SearchNode.limit,
|
41
|
+
SearchNode.result_merging,
|
42
|
+
}
|
35
43
|
|
36
44
|
def serialize(
|
37
45
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
@@ -14,6 +14,7 @@ _SubworkflowDeploymentNodeType = TypeVar("_SubworkflowDeploymentNodeType", bound
|
|
14
14
|
class BaseSubworkflowDeploymentNodeDisplay(
|
15
15
|
BaseNodeDisplay[_SubworkflowDeploymentNodeType], Generic[_SubworkflowDeploymentNodeType]
|
16
16
|
):
|
17
|
+
__serializable_inputs__ = {SubworkflowDeploymentNode.subworkflow_inputs}
|
17
18
|
|
18
19
|
def serialize(
|
19
20
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
@@ -15,6 +15,8 @@ TEMPLATE_INPUT_NAME = TemplatingNode.template.name
|
|
15
15
|
|
16
16
|
|
17
17
|
class BaseTemplatingNodeDisplay(BaseNodeDisplay[_TemplatingNodeType], Generic[_TemplatingNodeType]):
|
18
|
+
__serializable_inputs__ = {TemplatingNode.inputs}
|
19
|
+
|
18
20
|
def serialize(
|
19
21
|
self, display_context: WorkflowDisplayContext, error_output_id: Optional[UUID] = None, **kwargs
|
20
22
|
) -> JsonObject:
|
@@ -29,7 +29,7 @@ def _display_class_with_node_input_ids_by_name_with_inputs_prefix(Node: Type[Cod
|
|
29
29
|
@pytest.mark.parametrize(
|
30
30
|
["GetDisplayClass", "expected_input_id"],
|
31
31
|
[
|
32
|
-
(_no_display_class, "
|
32
|
+
(_no_display_class, "a5dbe403-0b00-4df6-b8f7-ed5f7794b003"),
|
33
33
|
(_display_class_with_node_input_ids_by_name, "fba6a4d5-835a-4e99-afb7-f6a4aed15110"),
|
34
34
|
(_display_class_with_node_input_ids_by_name_with_inputs_prefix, "fba6a4d5-835a-4e99-afb7-f6a4aed15110"),
|
35
35
|
],
|
@@ -5,6 +5,7 @@ from typing import Type
|
|
5
5
|
|
6
6
|
from vellum.workflows import BaseWorkflow
|
7
7
|
from vellum.workflows.nodes import PromptDeploymentNode
|
8
|
+
from vellum_ee.workflows.display.nodes.vellum.prompt_deployment_node import BasePromptDeploymentNodeDisplay
|
8
9
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
9
10
|
|
10
11
|
|
@@ -13,14 +14,14 @@ def _no_display_class(Node: Type[PromptDeploymentNode]): # type: ignore
|
|
13
14
|
|
14
15
|
|
15
16
|
def _display_class_with_node_input_ids_by_name(Node: Type[PromptDeploymentNode]):
|
16
|
-
class PromptDeploymentNodeDisplay(
|
17
|
+
class PromptDeploymentNodeDisplay(BasePromptDeploymentNodeDisplay[Node]): # type: ignore[valid-type]
|
17
18
|
node_input_ids_by_name = {"foo": UUID("6037747a-1d35-4094-b363-4369fc92c5d4")}
|
18
19
|
|
19
20
|
return PromptDeploymentNodeDisplay
|
20
21
|
|
21
22
|
|
22
23
|
def _display_class_with_node_input_ids_by_name_with_inputs_prefix(Node: Type[PromptDeploymentNode]):
|
23
|
-
class PromptDeploymentNodeDisplay(
|
24
|
+
class PromptDeploymentNodeDisplay(BasePromptDeploymentNodeDisplay[Node]): # type: ignore[valid-type]
|
24
25
|
node_input_ids_by_name = {"prompt_inputs.foo": UUID("6037747a-1d35-4094-b363-4369fc92c5d4")}
|
25
26
|
|
26
27
|
return PromptDeploymentNodeDisplay
|
@@ -51,7 +52,7 @@ def mock_fetch_deployment(mocker):
|
|
51
52
|
@pytest.mark.parametrize(
|
52
53
|
["GetDisplayClass", "expected_input_id"],
|
53
54
|
[
|
54
|
-
(_no_display_class, "
|
55
|
+
(_no_display_class, "016187d6-2830-4256-a61d-e52f9bf6355e"),
|
55
56
|
(_display_class_with_node_input_ids_by_name, "6037747a-1d35-4094-b363-4369fc92c5d4"),
|
56
57
|
(_display_class_with_node_input_ids_by_name_with_inputs_prefix, "6037747a-1d35-4094-b363-4369fc92c5d4"),
|
57
58
|
],
|
@@ -2,6 +2,7 @@ import pytest
|
|
2
2
|
from uuid import UUID
|
3
3
|
from typing import Type
|
4
4
|
|
5
|
+
from vellum.client.types.variable_prompt_block import VariablePromptBlock
|
5
6
|
from vellum.workflows import BaseWorkflow
|
6
7
|
from vellum.workflows.nodes import BaseNode
|
7
8
|
from vellum.workflows.nodes.displayable.inline_prompt_node.node import InlinePromptNode
|
@@ -78,7 +79,7 @@ def _display_class_with_node_input_ids_by_name_with_inputs_prefix(Node: Type[Inl
|
|
78
79
|
@pytest.mark.parametrize(
|
79
80
|
["GetDisplayClass", "expected_input_id"],
|
80
81
|
[
|
81
|
-
(_no_display_class, "
|
82
|
+
(_no_display_class, "9b036991-67ff-4cd0-a4d7-b4ed581e8b6d"),
|
82
83
|
(_display_class_with_node_input_ids_by_name, "fba6a4d5-835a-4e99-afb7-f6a4aed15110"),
|
83
84
|
(_display_class_with_node_input_ids_by_name_with_inputs_prefix, "fba6a4d5-835a-4e99-afb7-f6a4aed15110"),
|
84
85
|
],
|
@@ -165,7 +166,7 @@ def test_serialize_node__prompt_inputs__state_reference():
|
|
165
166
|
},
|
166
167
|
},
|
167
168
|
{
|
168
|
-
"id": "
|
169
|
+
"id": "b83c40f7-0159-442f-af03-e80870363c52",
|
169
170
|
"key": "bar",
|
170
171
|
"value": {
|
171
172
|
"rules": [
|
@@ -181,3 +182,36 @@ def test_serialize_node__prompt_inputs__state_reference():
|
|
181
182
|
},
|
182
183
|
},
|
183
184
|
]
|
185
|
+
|
186
|
+
|
187
|
+
def test_serialize_node__unreferenced_variable_block__still_serializes():
|
188
|
+
# GIVEN a prompt node with an unreferenced variable block
|
189
|
+
class MyPromptNode(InlinePromptNode):
|
190
|
+
blocks = [VariablePromptBlock(input_variable="foo")]
|
191
|
+
|
192
|
+
# AND a workflow with the prompt node
|
193
|
+
class MyWorkflow(BaseWorkflow):
|
194
|
+
graph = MyPromptNode
|
195
|
+
|
196
|
+
# WHEN the prompt node is serialized
|
197
|
+
workflow_display = get_workflow_display(workflow_class=MyWorkflow)
|
198
|
+
serialized_workflow: dict = workflow_display.serialize()
|
199
|
+
|
200
|
+
# THEN the node should skip the state reference input rule
|
201
|
+
assert serialized_workflow["workflow_raw_data"]["nodes"][1]["data"]["exec_config"]["prompt_template_block_data"][
|
202
|
+
"blocks"
|
203
|
+
] == [
|
204
|
+
{
|
205
|
+
"id": "fecbb5f3-e0a3-42ed-9774-6c68fd5db50c",
|
206
|
+
"block_type": "VARIABLE",
|
207
|
+
"input_variable_id": "ea3f6348-8553-4375-bd27-527df4e4f3c2",
|
208
|
+
"state": "ENABLED",
|
209
|
+
"cache_config": None,
|
210
|
+
}
|
211
|
+
]
|
212
|
+
|
213
|
+
# AND we should have a warning of the invalid reference
|
214
|
+
# TODO: Come up with a proposal for how nodes should propagate warnings
|
215
|
+
# warnings = list(workflow_display.errors)
|
216
|
+
# assert len(warnings) == 1
|
217
|
+
# assert "Missing input variable 'foo' for prompt block 0" in str(warnings[0])
|
@@ -4,7 +4,8 @@ from uuid import UUID, uuid4
|
|
4
4
|
from typing import Type
|
5
5
|
|
6
6
|
from vellum.workflows import BaseWorkflow
|
7
|
-
from vellum.workflows.nodes import SubworkflowDeploymentNode
|
7
|
+
from vellum.workflows.nodes.displayable.subworkflow_deployment_node.node import SubworkflowDeploymentNode
|
8
|
+
from vellum_ee.workflows.display.nodes.vellum.subworkflow_deployment_node import BaseSubworkflowDeploymentNodeDisplay
|
8
9
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
9
10
|
|
10
11
|
|
@@ -13,14 +14,14 @@ def _no_display_class(Node: Type[SubworkflowDeploymentNode]): # type: ignore
|
|
13
14
|
|
14
15
|
|
15
16
|
def _display_class_with_node_input_ids_by_name(Node: Type[SubworkflowDeploymentNode]):
|
16
|
-
class SubworkflowNodeDisplay(
|
17
|
+
class SubworkflowNodeDisplay(BaseSubworkflowDeploymentNodeDisplay[Node]): # type: ignore[valid-type]
|
17
18
|
node_input_ids_by_name = {"foo": UUID("aff4f838-577e-44b9-ac5c-6d8213abbb9c")}
|
18
19
|
|
19
20
|
return SubworkflowNodeDisplay
|
20
21
|
|
21
22
|
|
22
23
|
def _display_class_with_node_input_ids_by_name_with_inputs_prefix(Node: Type[SubworkflowDeploymentNode]):
|
23
|
-
class SubworkflowNodeDisplay(
|
24
|
+
class SubworkflowNodeDisplay(BaseSubworkflowDeploymentNodeDisplay[Node]): # type: ignore[valid-type]
|
24
25
|
node_input_ids_by_name = {"subworkflow_inputs.foo": UUID("aff4f838-577e-44b9-ac5c-6d8213abbb9c")}
|
25
26
|
|
26
27
|
return SubworkflowNodeDisplay
|
@@ -55,7 +56,7 @@ def mock_fetch_deployment(mocker):
|
|
55
56
|
@pytest.mark.parametrize(
|
56
57
|
["GetDisplayClass", "expected_input_id"],
|
57
58
|
[
|
58
|
-
(_no_display_class, "
|
59
|
+
(_no_display_class, "394132c2-1817-455e-9f3f-b7073eb63a2b"),
|
59
60
|
(_display_class_with_node_input_ids_by_name, "aff4f838-577e-44b9-ac5c-6d8213abbb9c"),
|
60
61
|
(_display_class_with_node_input_ids_by_name_with_inputs_prefix, "aff4f838-577e-44b9-ac5c-6d8213abbb9c"),
|
61
62
|
],
|
@@ -29,7 +29,7 @@ def _display_class_with_node_input_ids_by_name_with_inputs_prefix(Node: Type[Tem
|
|
29
29
|
@pytest.mark.parametrize(
|
30
30
|
["GetDisplayClass", "expected_input_id"],
|
31
31
|
[
|
32
|
-
(_no_display_class, "
|
32
|
+
(_no_display_class, "91d982a9-6c41-42ac-aff9-7b623c450a55"),
|
33
33
|
(_display_class_with_node_input_ids_by_name, "fba6a4d5-835a-4e99-afb7-f6a4aed15110"),
|
34
34
|
(_display_class_with_node_input_ids_by_name_with_inputs_prefix, "fba6a4d5-835a-4e99-afb7-f6a4aed15110"),
|
35
35
|
],
|
@@ -3,6 +3,8 @@ from typing import Dict
|
|
3
3
|
|
4
4
|
from vellum.workflows.inputs import BaseInputs
|
5
5
|
from vellum.workflows.nodes import BaseNode
|
6
|
+
from vellum.workflows.ports.port import Port
|
7
|
+
from vellum.workflows.references.lazy import LazyReference
|
6
8
|
from vellum.workflows.state import BaseState
|
7
9
|
from vellum.workflows.workflows.base import BaseWorkflow
|
8
10
|
from vellum_ee.workflows.display.vellum import WorkflowInputsVellumDisplayOverrides
|
@@ -285,3 +287,45 @@ def test_vellum_workflow_display__serialize_with_parse_json_expression():
|
|
285
287
|
"operator": "parseJson",
|
286
288
|
},
|
287
289
|
}
|
290
|
+
|
291
|
+
|
292
|
+
def test_serialize__port_with_lazy_reference():
|
293
|
+
# GIVEN a node with a lazy reference in a Port
|
294
|
+
class MyNode(BaseNode):
|
295
|
+
class Ports(BaseNode.Ports):
|
296
|
+
foo = Port.on_if(LazyReference(lambda: MyNode.Outputs.bar))
|
297
|
+
|
298
|
+
class Outputs(BaseNode.Outputs):
|
299
|
+
bar: bool
|
300
|
+
|
301
|
+
# AND a workflow that uses the node
|
302
|
+
class Workflow(BaseWorkflow):
|
303
|
+
graph = MyNode
|
304
|
+
|
305
|
+
# WHEN we serialize the workflow
|
306
|
+
workflow_display = get_workflow_display(workflow_class=Workflow)
|
307
|
+
exec_config = workflow_display.serialize()
|
308
|
+
|
309
|
+
# THEN the lazy reference should be serialized correctly
|
310
|
+
raw_data = exec_config["workflow_raw_data"]
|
311
|
+
assert isinstance(raw_data, dict)
|
312
|
+
|
313
|
+
nodes = raw_data["nodes"]
|
314
|
+
assert isinstance(nodes, list)
|
315
|
+
|
316
|
+
my_node = nodes[1]
|
317
|
+
assert isinstance(my_node, dict)
|
318
|
+
ports = my_node.get("ports")
|
319
|
+
assert isinstance(ports, list)
|
320
|
+
assert ports == [
|
321
|
+
{
|
322
|
+
"id": "6c26bc2b-6469-47c1-b858-d63f0d311ea6",
|
323
|
+
"name": "foo",
|
324
|
+
"type": "IF",
|
325
|
+
"expression": {
|
326
|
+
"type": "NODE_OUTPUT",
|
327
|
+
"node_id": str(MyNode.__id__),
|
328
|
+
"node_output_id": str(MyNode.__output_ids__["bar"]),
|
329
|
+
},
|
330
|
+
}
|
331
|
+
]
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py
CHANGED
@@ -87,7 +87,7 @@ def test_serialize_workflow():
|
|
87
87
|
"type": "ERROR",
|
88
88
|
"inputs": [
|
89
89
|
{
|
90
|
-
"id": "
|
90
|
+
"id": "8e4c8d76-2e02-4d7e-a7bf-d71af392dc49",
|
91
91
|
"key": "error_source_input_id",
|
92
92
|
"value": {
|
93
93
|
"rules": [
|
@@ -101,11 +101,9 @@ def test_serialize_workflow():
|
|
101
101
|
}
|
102
102
|
],
|
103
103
|
"data": {
|
104
|
-
"name": "error-node",
|
105
104
|
"label": "Fail Node",
|
106
105
|
"target_handle_id": "70c19f1c-309c-4a5d-ba65-664c0bb2fedf",
|
107
|
-
"error_source_input_id": "
|
108
|
-
"error_output_id": "None",
|
106
|
+
"error_source_input_id": "8e4c8d76-2e02-4d7e-a7bf-d71af392dc49",
|
109
107
|
},
|
110
108
|
"display_data": {"position": {"x": 0.0, "y": 0.0}},
|
111
109
|
"base": {
|