vellum-ai 0.14.89__py3-none-any.whl → 1.0.1__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 +7 -1
- vellum/client/__init__.py +2 -2
- vellum/client/core/client_wrapper.py +2 -2
- vellum/client/types/__init__.py +6 -0
- vellum/client/types/organization_limit_config.py +24 -0
- vellum/client/types/organization_read.py +2 -0
- vellum/client/types/quota.py +21 -0
- vellum/client/types/vembda_service_tier_enum.py +5 -0
- vellum/client/types/workflow_execution_actual.py +1 -1
- vellum/evaluations/resources.py +5 -5
- vellum/types/organization_limit_config.py +3 -0
- vellum/types/quota.py +3 -0
- vellum/types/vembda_service_tier_enum.py +3 -0
- vellum/workflows/events/node.py +1 -1
- vellum/workflows/events/types.py +1 -1
- vellum/workflows/events/workflow.py +1 -1
- vellum/workflows/nodes/bases/tests/test_base_node.py +1 -1
- vellum/workflows/nodes/displayable/api_node/node.py +1 -0
- vellum/workflows/nodes/displayable/api_node/tests/test_api_node.py +30 -0
- vellum/workflows/nodes/displayable/bases/api_node/node.py +27 -10
- vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +1 -1
- vellum/workflows/nodes/displayable/bases/search_node.py +1 -1
- vellum/workflows/nodes/displayable/code_execution_node/node.py +1 -1
- vellum/workflows/nodes/displayable/guardrail_node/node.py +1 -1
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +1 -1
- vellum/workflows/nodes/displayable/tool_calling_node/node.py +5 -0
- vellum/workflows/nodes/displayable/tool_calling_node/tests/test_node.py +3 -0
- vellum/workflows/nodes/displayable/tool_calling_node/utils.py +86 -114
- vellum/workflows/nodes/experimental/__init__.py +2 -2
- vellum/workflows/state/base.py +1 -1
- vellum/workflows/state/delta.py +1 -1
- {vellum_ai-0.14.89.dist-info → vellum_ai-1.0.1.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.89.dist-info → vellum_ai-1.0.1.dist-info}/RECORD +59 -55
- vellum_cli/config.py +1 -1
- vellum_cli/push.py +1 -1
- vellum_cli/tests/test_ping.py +1 -0
- vellum_ee/workflows/display/base.py +0 -54
- vellum_ee/workflows/display/nodes/base_node_display.py +24 -0
- vellum_ee/workflows/display/nodes/vellum/api_node.py +20 -1
- vellum_ee/workflows/display/nodes/vellum/conditional_node.py +16 -2
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +0 -26
- vellum_ee/workflows/display/nodes/vellum/tests/test_api_node.py +31 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +3 -3
- vellum_ee/workflows/display/tests/test_base_workflow_display.py +2 -4
- vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py +2 -2
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +10 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +11 -11
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_inline_workflow_serialization.py +21 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_serialization.py +21 -0
- vellum_ee/workflows/display/vellum.py +2 -128
- vellum_ee/workflows/display/workflows/__init__.py +0 -1
- vellum_ee/workflows/display/workflows/base_workflow_display.py +15 -3
- vellum_ee/workflows/display/workflows/tests/test_workflow_display.py +127 -0
- vellum_ee/workflows/tests/local_workflow/display/nodes/final_output.py +1 -1
- vellum_ee/workflows/tests/local_workflow/display/nodes/templating_node.py +1 -1
- vellum_ee/workflows/tests/local_workflow/display/workflow.py +11 -14
- vellum/workflows/nodes/experimental/tool_calling_node/__init__.py +0 -3
- vellum/workflows/nodes/experimental/tool_calling_node/node.py +0 -3
- vellum_ee/workflows/display/workflows/vellum_workflow_display.py +0 -9
- {vellum_ai-0.14.89.dist-info → vellum_ai-1.0.1.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.89.dist-info → vellum_ai-1.0.1.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.89.dist-info → vellum_ai-1.0.1.dist-info}/entry_points.txt +0 -0
@@ -11,7 +11,6 @@ from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
|
11
11
|
from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
|
12
12
|
from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
|
13
13
|
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
14
|
-
from vellum_ee.workflows.display.utils.expressions import serialize_value
|
15
14
|
from vellum_ee.workflows.display.utils.vellum import infer_vellum_variable_type
|
16
15
|
from vellum_ee.workflows.display.vellum import NodeInput
|
17
16
|
|
@@ -173,7 +172,6 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
173
172
|
}
|
174
173
|
|
175
174
|
elif prompt_block.block_type == "CHAT_MESSAGE":
|
176
|
-
|
177
175
|
chat_properties: JsonObject = {
|
178
176
|
"chat_role": prompt_block.chat_role,
|
179
177
|
"chat_source": prompt_block.chat_source,
|
@@ -248,30 +246,6 @@ class BaseInlinePromptNodeDisplay(BaseNodeDisplay[_InlinePromptNodeType], Generi
|
|
248
246
|
|
249
247
|
return block
|
250
248
|
|
251
|
-
def _serialize_attributes(self, display_context: "WorkflowDisplayContext"):
|
252
|
-
attributes = []
|
253
|
-
for attribute in self._node:
|
254
|
-
if attribute in self.__unserializable_attributes__:
|
255
|
-
continue
|
256
|
-
|
257
|
-
id = (
|
258
|
-
str(self.attribute_ids_by_name[attribute.name])
|
259
|
-
if self.attribute_ids_by_name.get(attribute.name)
|
260
|
-
else str(uuid4_from_hash(f"{self.node_id}|{attribute.name}"))
|
261
|
-
)
|
262
|
-
try:
|
263
|
-
attributes.append(
|
264
|
-
{
|
265
|
-
"id": id,
|
266
|
-
"name": attribute.name,
|
267
|
-
"value": serialize_value(display_context, attribute.instance),
|
268
|
-
}
|
269
|
-
)
|
270
|
-
except ValueError as e:
|
271
|
-
raise ValueError(f"Failed to serialize attribute '{attribute.name}': {e}")
|
272
|
-
|
273
|
-
return attributes
|
274
|
-
|
275
249
|
def _serialize_parameters(self, parameters, display_context: "WorkflowDisplayContext") -> JsonObject:
|
276
250
|
"""Serialize parameters, returning empty object when nested descriptors are detected."""
|
277
251
|
params = raise_if_descriptor(parameters)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
from vellum.workflows.constants import APIRequestMethod
|
2
|
+
from vellum.workflows.nodes.displayable.api_node.node import APINode
|
3
|
+
from vellum.workflows.workflows.base import BaseWorkflow
|
4
|
+
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
5
|
+
|
6
|
+
|
7
|
+
def test_serialize_node__api_node_with_timeout():
|
8
|
+
# GIVEN an API node with timeout specified
|
9
|
+
class MyAPINode(APINode):
|
10
|
+
url = "https://api.example.com"
|
11
|
+
method = APIRequestMethod.GET
|
12
|
+
timeout = 30 # This is the key attribute we're testing
|
13
|
+
|
14
|
+
# AND a workflow with the API node
|
15
|
+
class Workflow(BaseWorkflow):
|
16
|
+
graph = MyAPINode
|
17
|
+
|
18
|
+
# WHEN the workflow is serialized
|
19
|
+
workflow_display = get_workflow_display(workflow_class=Workflow)
|
20
|
+
serialized_workflow: dict = workflow_display.serialize()
|
21
|
+
|
22
|
+
# THEN the node should properly serialize the timeout
|
23
|
+
my_api_node = next(node for node in serialized_workflow["workflow_raw_data"]["nodes"] if node["type"] == "API")
|
24
|
+
|
25
|
+
# Assert that timeout is present in the serialized attributes
|
26
|
+
timeout_attribute = next((attr for attr in my_api_node.get("attributes", []) if attr["name"] == "timeout"), None)
|
27
|
+
|
28
|
+
assert timeout_attribute is not None, "timeout attribute should be present in serialized attributes"
|
29
|
+
assert timeout_attribute["value"]["type"] == "CONSTANT_VALUE"
|
30
|
+
assert timeout_attribute["value"]["value"]["type"] == "NUMBER"
|
31
|
+
assert timeout_attribute["value"]["value"]["value"] == 30.0
|
@@ -8,6 +8,7 @@ from vellum.workflows.inputs import BaseInputs
|
|
8
8
|
from vellum.workflows.nodes.bases import BaseNode
|
9
9
|
from vellum.workflows.outputs import BaseOutputs
|
10
10
|
from vellum.workflows.references import LazyReference
|
11
|
+
from vellum_ee.workflows.display.base import WorkflowInputsDisplay, WorkflowMetaDisplay
|
11
12
|
from vellum_ee.workflows.display.editor.types import NodeDisplayData
|
12
13
|
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
13
14
|
from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay
|
@@ -21,7 +22,6 @@ from vellum_ee.workflows.display.utils.vellum import (
|
|
21
22
|
NodeOutputData,
|
22
23
|
NodeOutputPointer,
|
23
24
|
)
|
24
|
-
from vellum_ee.workflows.display.vellum import WorkflowInputsVellumDisplayOverrides, WorkflowMetaVellumDisplay
|
25
25
|
from vellum_ee.workflows.display.workflows.base_workflow_display import BaseWorkflowDisplay
|
26
26
|
|
27
27
|
|
@@ -110,13 +110,13 @@ def test_create_node_input_value_pointer_rules(
|
|
110
110
|
descriptor,
|
111
111
|
WorkflowDisplayContext(
|
112
112
|
workflow_display_class=BaseWorkflowDisplay,
|
113
|
-
workflow_display=
|
113
|
+
workflow_display=WorkflowMetaDisplay(
|
114
114
|
entrypoint_node_id=uuid4(),
|
115
115
|
entrypoint_node_source_handle_id=uuid4(),
|
116
116
|
entrypoint_node_display=NodeDisplayData(),
|
117
117
|
),
|
118
118
|
global_workflow_input_displays={
|
119
|
-
Inputs.example_workflow_input:
|
119
|
+
Inputs.example_workflow_input: WorkflowInputsDisplay(
|
120
120
|
id=UUID("a154c29d-fac0-4cd0-ba88-bc52034f5470"),
|
121
121
|
),
|
122
122
|
},
|
@@ -7,7 +7,7 @@ from vellum.workflows.ports.port import Port
|
|
7
7
|
from vellum.workflows.references.lazy import LazyReference
|
8
8
|
from vellum.workflows.state import BaseState
|
9
9
|
from vellum.workflows.workflows.base import BaseWorkflow
|
10
|
-
from vellum_ee.workflows.display.
|
10
|
+
from vellum_ee.workflows.display.base import WorkflowInputsDisplay
|
11
11
|
from vellum_ee.workflows.display.workflows.base_workflow_display import BaseWorkflowDisplay
|
12
12
|
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
13
13
|
|
@@ -64,9 +64,7 @@ def test_vellum_workflow_display__serialize_input_variables_with_capitalized_var
|
|
64
64
|
|
65
65
|
class ExampleWorkflowDisplay(BaseWorkflowDisplay[ExampleWorkflow]):
|
66
66
|
inputs_display = {
|
67
|
-
Inputs.foo:
|
68
|
-
id=UUID("97b63d71-5413-417f-9cf5-49e1b4fd56e4"), name="Foo", required=True
|
69
|
-
)
|
67
|
+
Inputs.foo: WorkflowInputsDisplay(id=UUID("97b63d71-5413-417f-9cf5-49e1b4fd56e4"), name="Foo")
|
70
68
|
}
|
71
69
|
|
72
70
|
display = get_workflow_display(
|
@@ -4,6 +4,7 @@ from typing import Type
|
|
4
4
|
|
5
5
|
from vellum.workflows.types.core import JsonObject
|
6
6
|
from vellum.workflows.types.generics import NodeType
|
7
|
+
from vellum_ee.workflows.display.base import WorkflowMetaDisplay
|
7
8
|
from vellum_ee.workflows.display.editor.types import NodeDisplayData
|
8
9
|
from vellum_ee.workflows.display.nodes.get_node_display_class import get_node_display_class
|
9
10
|
from vellum_ee.workflows.display.types import (
|
@@ -13,7 +14,6 @@ from vellum_ee.workflows.display.types import (
|
|
13
14
|
WorkflowDisplayContext,
|
14
15
|
WorkflowInputsDisplays,
|
15
16
|
)
|
16
|
-
from vellum_ee.workflows.display.vellum import WorkflowMetaVellumDisplay
|
17
17
|
from vellum_ee.workflows.display.workflows.base_workflow_display import BaseWorkflowDisplay
|
18
18
|
|
19
19
|
|
@@ -31,7 +31,7 @@ def serialize_node():
|
|
31
31
|
|
32
32
|
context: WorkflowDisplayContext = WorkflowDisplayContext(
|
33
33
|
workflow_display_class=BaseWorkflowDisplay,
|
34
|
-
workflow_display=
|
34
|
+
workflow_display=WorkflowMetaDisplay(
|
35
35
|
entrypoint_node_id=uuid4(),
|
36
36
|
entrypoint_node_source_handle_id=uuid4(),
|
37
37
|
entrypoint_node_display=NodeDisplayData(),
|
vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py
CHANGED
@@ -162,6 +162,16 @@ def test_serialize_workflow(vellum_client):
|
|
162
162
|
},
|
163
163
|
},
|
164
164
|
],
|
165
|
+
"attributes": [
|
166
|
+
{
|
167
|
+
"id": "ad719e65-0032-4012-a0bd-9b5162194bce",
|
168
|
+
"name": "timeout",
|
169
|
+
"value": {
|
170
|
+
"type": "CONSTANT_VALUE",
|
171
|
+
"value": {"type": "JSON", "value": None},
|
172
|
+
},
|
173
|
+
},
|
174
|
+
],
|
165
175
|
"data": {
|
166
176
|
"label": "Simple A P I Node",
|
167
177
|
"error_output_id": None,
|
@@ -285,7 +285,7 @@ def test_serialize_workflow():
|
|
285
285
|
{
|
286
286
|
"id": "de7b0b4e-7803-4d36-a275-2e7e3f60342b",
|
287
287
|
"type": "IF",
|
288
|
-
"source_handle_id": "
|
288
|
+
"source_handle_id": "3a45b81f-95e4-4cbd-8997-bfdbe30251e8",
|
289
289
|
"data": {
|
290
290
|
"id": "2ccd0730-26d1-4fb4-baa9-1a2a182dd9a0",
|
291
291
|
"rules": [
|
@@ -309,7 +309,7 @@ def test_serialize_workflow():
|
|
309
309
|
{
|
310
310
|
"id": "5e783d17-6808-441a-ac6c-33a4e184f4e0",
|
311
311
|
"type": "ELIF",
|
312
|
-
"source_handle_id": "
|
312
|
+
"source_handle_id": "7202f702-1ebc-4067-ab1e-ec67e49158ee",
|
313
313
|
"data": {
|
314
314
|
"id": "cc3f0d92-b603-42cc-b2e9-83e3b23b3bcb",
|
315
315
|
"rules": [
|
@@ -333,7 +333,7 @@ def test_serialize_workflow():
|
|
333
333
|
{
|
334
334
|
"id": "6bd2f643-9cf5-4e7f-9113-f90e5c8057be",
|
335
335
|
"type": "ELIF",
|
336
|
-
"source_handle_id": "
|
336
|
+
"source_handle_id": "cf45705d-1a47-43a6-9d24-a7fdf78baae0",
|
337
337
|
"data": {
|
338
338
|
"id": "a5a0f391-7052-452f-9fe1-a5781a491591",
|
339
339
|
"rules": [
|
@@ -357,7 +357,7 @@ def test_serialize_workflow():
|
|
357
357
|
{
|
358
358
|
"id": "0a058485-18a4-4e20-8a30-6da8196ac46f",
|
359
359
|
"type": "ELIF",
|
360
|
-
"source_handle_id": "
|
360
|
+
"source_handle_id": "f04610dd-61cf-41b0-b337-2235e101cdb0",
|
361
361
|
"data": {
|
362
362
|
"id": "efe7a851-2a67-4189-99ec-bc193242b270",
|
363
363
|
"rules": [
|
@@ -409,7 +409,7 @@ def test_serialize_workflow():
|
|
409
409
|
{
|
410
410
|
"id": "c2fa8a44-923b-462a-b0d2-fa800a152e52",
|
411
411
|
"type": "ELSE",
|
412
|
-
"source_handle_id": "
|
412
|
+
"source_handle_id": "f9dde637-ea90-465f-a871-caf8380ae377",
|
413
413
|
"data": None,
|
414
414
|
},
|
415
415
|
],
|
@@ -913,7 +913,7 @@ def test_conditional_node_serialize_all_operators_with_lhs_and_rhs(descriptor, o
|
|
913
913
|
{
|
914
914
|
"id": "a4c32611-fd58-4b98-9d08-313cfd1c214e",
|
915
915
|
"type": "IF",
|
916
|
-
"source_handle_id": "
|
916
|
+
"source_handle_id": "2ff87aa6-37cf-43dd-af9d-13b9198ab70a",
|
917
917
|
"data": {
|
918
918
|
"id": "650e7105-3e76-43ca-858f-b290970b438b",
|
919
919
|
"rules": [
|
@@ -937,7 +937,7 @@ def test_conditional_node_serialize_all_operators_with_lhs_and_rhs(descriptor, o
|
|
937
937
|
{
|
938
938
|
"id": "342e5497-ea2b-4e5c-99cf-e6492f133a3c",
|
939
939
|
"type": "ELSE",
|
940
|
-
"source_handle_id": "
|
940
|
+
"source_handle_id": "9a7e8c2e-0228-4321-8f74-61cb5778f3df",
|
941
941
|
"data": None,
|
942
942
|
},
|
943
943
|
],
|
@@ -1024,7 +1024,7 @@ def test_conditional_node_serialize_all_operators_with_expression(descriptor, op
|
|
1024
1024
|
{
|
1025
1025
|
"id": "a4c32611-fd58-4b98-9d08-313cfd1c214e",
|
1026
1026
|
"type": "IF",
|
1027
|
-
"source_handle_id": "
|
1027
|
+
"source_handle_id": "2ff87aa6-37cf-43dd-af9d-13b9198ab70a",
|
1028
1028
|
"data": {
|
1029
1029
|
"id": "650e7105-3e76-43ca-858f-b290970b438b",
|
1030
1030
|
"rules": [
|
@@ -1048,7 +1048,7 @@ def test_conditional_node_serialize_all_operators_with_expression(descriptor, op
|
|
1048
1048
|
{
|
1049
1049
|
"id": "342e5497-ea2b-4e5c-99cf-e6492f133a3c",
|
1050
1050
|
"type": "ELSE",
|
1051
|
-
"source_handle_id": "
|
1051
|
+
"source_handle_id": "9a7e8c2e-0228-4321-8f74-61cb5778f3df",
|
1052
1052
|
"data": None,
|
1053
1053
|
},
|
1054
1054
|
],
|
@@ -1147,7 +1147,7 @@ def test_conditional_node_serialize_all_operators_with_value_and_start_and_end(d
|
|
1147
1147
|
{
|
1148
1148
|
"id": "a4c32611-fd58-4b98-9d08-313cfd1c214e",
|
1149
1149
|
"type": "IF",
|
1150
|
-
"source_handle_id": "
|
1150
|
+
"source_handle_id": "2ff87aa6-37cf-43dd-af9d-13b9198ab70a",
|
1151
1151
|
"data": {
|
1152
1152
|
"id": "650e7105-3e76-43ca-858f-b290970b438b",
|
1153
1153
|
"rules": [
|
@@ -1171,7 +1171,7 @@ def test_conditional_node_serialize_all_operators_with_value_and_start_and_end(d
|
|
1171
1171
|
{
|
1172
1172
|
"id": "342e5497-ea2b-4e5c-99cf-e6492f133a3c",
|
1173
1173
|
"type": "ELSE",
|
1174
|
-
"source_handle_id": "
|
1174
|
+
"source_handle_id": "9a7e8c2e-0228-4321-8f74-61cb5778f3df",
|
1175
1175
|
"data": None,
|
1176
1176
|
},
|
1177
1177
|
],
|
@@ -407,6 +407,27 @@ def test_serialize_workflow():
|
|
407
407
|
],
|
408
408
|
},
|
409
409
|
},
|
410
|
+
{
|
411
|
+
"id": "229cd1ca-dc2f-4586-b933-c4d4966f7bd1",
|
412
|
+
"name": "parameters",
|
413
|
+
"value": {
|
414
|
+
"type": "CONSTANT_VALUE",
|
415
|
+
"value": {
|
416
|
+
"type": "JSON",
|
417
|
+
"value": {
|
418
|
+
"stop": [],
|
419
|
+
"temperature": 0.0,
|
420
|
+
"max_tokens": 4096.0,
|
421
|
+
"top_p": 1.0,
|
422
|
+
"top_k": 0.0,
|
423
|
+
"frequency_penalty": 0.0,
|
424
|
+
"presence_penalty": 0.0,
|
425
|
+
"logit_bias": None,
|
426
|
+
"custom_parameters": None,
|
427
|
+
},
|
428
|
+
},
|
429
|
+
},
|
430
|
+
},
|
410
431
|
{
|
411
432
|
"id": "1668419e-a193-43a5-8a97-3394e89bf278",
|
412
433
|
"name": "max_prompt_iterations",
|
@@ -169,6 +169,27 @@ def test_serialize_workflow():
|
|
169
169
|
],
|
170
170
|
},
|
171
171
|
},
|
172
|
+
{
|
173
|
+
"id": "229cd1ca-dc2f-4586-b933-c4d4966f7bd1",
|
174
|
+
"name": "parameters",
|
175
|
+
"value": {
|
176
|
+
"type": "CONSTANT_VALUE",
|
177
|
+
"value": {
|
178
|
+
"type": "JSON",
|
179
|
+
"value": {
|
180
|
+
"stop": [],
|
181
|
+
"temperature": 0.0,
|
182
|
+
"max_tokens": 4096.0,
|
183
|
+
"top_p": 1.0,
|
184
|
+
"top_k": 0.0,
|
185
|
+
"frequency_penalty": 0.0,
|
186
|
+
"presence_penalty": 0.0,
|
187
|
+
"logit_bias": None,
|
188
|
+
"custom_parameters": None,
|
189
|
+
},
|
190
|
+
},
|
191
|
+
},
|
192
|
+
},
|
172
193
|
{
|
173
194
|
"id": "1668419e-a193-43a5-8a97-3394e89bf278",
|
174
195
|
"name": "max_prompt_iterations",
|
@@ -1,135 +1,9 @@
|
|
1
|
-
from
|
2
|
-
from uuid import UUID
|
3
|
-
from typing import List, Literal, Optional
|
1
|
+
from typing import List, Literal
|
4
2
|
|
5
|
-
from vellum.core import UniversalBaseModel
|
6
|
-
from vellum_ee.workflows.display.base import (
|
7
|
-
EdgeDisplayOverrides,
|
8
|
-
EntrypointDisplayOverrides,
|
9
|
-
StateValueDisplayOverrides,
|
10
|
-
WorkflowInputsDisplay,
|
11
|
-
WorkflowMetaDisplayOverrides,
|
12
|
-
WorkflowOutputDisplayOverrides,
|
13
|
-
)
|
14
|
-
from vellum_ee.workflows.display.base import WorkflowDisplayData # noqa: F401 - Remove in 0.15.0
|
15
|
-
from vellum_ee.workflows.display.base import WorkflowDisplayDataViewport # noqa: F401 - Remove in 0.15.0
|
16
|
-
from vellum_ee.workflows.display.editor.types import NodeDisplayComment # noqa: F401 - Remove in 0.15.0
|
17
|
-
from vellum_ee.workflows.display.editor.types import NodeDisplayData
|
18
|
-
from vellum_ee.workflows.display.editor.types import NodeDisplayPosition # noqa: F401 - Remove in 0.15.0
|
3
|
+
from vellum.client.core import UniversalBaseModel
|
19
4
|
from vellum_ee.workflows.display.utils.vellum import NodeInputValuePointerRule
|
20
5
|
|
21
6
|
|
22
|
-
@dataclass
|
23
|
-
class WorkflowMetaVellumDisplayOverrides(WorkflowMetaDisplayOverrides):
|
24
|
-
"""
|
25
|
-
DEPRECATED: Use WorkflowMetaDisplay instead. Will be removed in 0.15.0
|
26
|
-
"""
|
27
|
-
|
28
|
-
pass
|
29
|
-
|
30
|
-
|
31
|
-
@dataclass
|
32
|
-
class WorkflowMetaVellumDisplay(WorkflowMetaVellumDisplayOverrides):
|
33
|
-
"""
|
34
|
-
DEPRECATED: Use WorkflowMetaDisplay instead. Will be removed in 0.15.0
|
35
|
-
"""
|
36
|
-
|
37
|
-
pass
|
38
|
-
|
39
|
-
|
40
|
-
@dataclass
|
41
|
-
class WorkflowInputsVellumDisplayOverrides(WorkflowInputsDisplay):
|
42
|
-
"""
|
43
|
-
DEPRECATED: Use WorkflowInputsDisplay instead. Will be removed in 0.15.0
|
44
|
-
"""
|
45
|
-
|
46
|
-
required: Optional[bool] = None
|
47
|
-
|
48
|
-
|
49
|
-
@dataclass
|
50
|
-
class WorkflowInputsVellumDisplay(WorkflowInputsVellumDisplayOverrides):
|
51
|
-
pass
|
52
|
-
|
53
|
-
|
54
|
-
@dataclass
|
55
|
-
class StateValueVellumDisplayOverrides(StateValueDisplayOverrides):
|
56
|
-
"""
|
57
|
-
DEPRECATED: Use StateValueDisplay instead. Will be removed in 0.15.0
|
58
|
-
"""
|
59
|
-
|
60
|
-
required: Optional[bool] = None
|
61
|
-
|
62
|
-
|
63
|
-
@dataclass
|
64
|
-
class StateValueVellumDisplay(StateValueVellumDisplayOverrides):
|
65
|
-
"""
|
66
|
-
DEPRECATED: Use StateValueDisplay instead. Will be removed in 0.15.0
|
67
|
-
"""
|
68
|
-
|
69
|
-
pass
|
70
|
-
|
71
|
-
|
72
|
-
@dataclass
|
73
|
-
class EdgeVellumDisplayOverrides(EdgeDisplayOverrides):
|
74
|
-
"""
|
75
|
-
DEPRECATED: Use EdgeDisplay instead. Will be removed in 0.15.0
|
76
|
-
"""
|
77
|
-
|
78
|
-
pass
|
79
|
-
|
80
|
-
|
81
|
-
@dataclass
|
82
|
-
class EdgeVellumDisplay(EdgeVellumDisplayOverrides):
|
83
|
-
"""
|
84
|
-
DEPRECATED: Use EdgeDisplay instead. Will be removed in 0.15.0
|
85
|
-
"""
|
86
|
-
|
87
|
-
source_node_id: UUID
|
88
|
-
source_handle_id: UUID
|
89
|
-
target_node_id: UUID
|
90
|
-
target_handle_id: UUID
|
91
|
-
type: Literal["DEFAULT"] = "DEFAULT"
|
92
|
-
|
93
|
-
|
94
|
-
@dataclass
|
95
|
-
class EntrypointVellumDisplayOverrides(EntrypointDisplayOverrides):
|
96
|
-
"""
|
97
|
-
DEPRECATED: Use EntrypointDisplay instead. Will be removed in 0.15.0
|
98
|
-
"""
|
99
|
-
|
100
|
-
pass
|
101
|
-
|
102
|
-
|
103
|
-
@dataclass
|
104
|
-
class EntrypointVellumDisplay(EntrypointVellumDisplayOverrides):
|
105
|
-
"""
|
106
|
-
DEPRECATED: Use EntrypointDisplay instead. Will be removed in 0.15.0
|
107
|
-
"""
|
108
|
-
|
109
|
-
pass
|
110
|
-
|
111
|
-
|
112
|
-
@dataclass
|
113
|
-
class WorkflowOutputVellumDisplayOverrides(WorkflowOutputDisplayOverrides):
|
114
|
-
"""
|
115
|
-
DEPRECATED: Use WorkflowOutputDisplay instead. Will be removed in 0.15.0
|
116
|
-
"""
|
117
|
-
|
118
|
-
label: Optional[str] = None
|
119
|
-
node_id: Optional[UUID] = None
|
120
|
-
display_data: Optional[NodeDisplayData] = None
|
121
|
-
target_handle_id: Optional[UUID] = None
|
122
|
-
|
123
|
-
|
124
|
-
@dataclass
|
125
|
-
class WorkflowOutputVellumDisplay(WorkflowOutputVellumDisplayOverrides):
|
126
|
-
"""
|
127
|
-
DEPRECATED: Use WorkflowOutputDisplay instead. Will be removed in 0.15.0
|
128
|
-
"""
|
129
|
-
|
130
|
-
pass
|
131
|
-
|
132
|
-
|
133
7
|
class NodeInputValuePointer(UniversalBaseModel):
|
134
8
|
rules: List[NodeInputValuePointerRule]
|
135
9
|
combinator: Literal["OR"] = "OR"
|
@@ -9,7 +9,7 @@ from uuid import UUID
|
|
9
9
|
from typing import Any, Dict, ForwardRef, Generic, Iterator, List, Optional, Tuple, Type, TypeVar, Union, cast, get_args
|
10
10
|
|
11
11
|
from vellum.client import Vellum as VellumClient
|
12
|
-
from vellum.core.pydantic_utilities import UniversalBaseModel
|
12
|
+
from vellum.client.core.pydantic_utilities import UniversalBaseModel
|
13
13
|
from vellum.workflows import BaseWorkflow
|
14
14
|
from vellum.workflows.constants import undefined
|
15
15
|
from vellum.workflows.descriptors.base import BaseDescriptor
|
@@ -136,13 +136,19 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
|
|
136
136
|
if workflow_input_reference.instance
|
137
137
|
else None
|
138
138
|
)
|
139
|
+
|
140
|
+
# An input is required if it has no default value AND is not optional
|
141
|
+
has_default = workflow_input_reference.instance is not undefined
|
142
|
+
is_optional = type(None) in workflow_input_reference.types
|
143
|
+
is_required = not has_default and not is_optional
|
144
|
+
|
139
145
|
input_variables.append(
|
140
146
|
{
|
141
147
|
"id": str(workflow_input_display.id),
|
142
148
|
"key": workflow_input_display.name or workflow_input_reference.name,
|
143
149
|
"type": infer_vellum_variable_type(workflow_input_reference),
|
144
150
|
"default": default.dict() if default else None,
|
145
|
-
"required":
|
151
|
+
"required": is_required,
|
146
152
|
"extensions": {"color": workflow_input_display.color},
|
147
153
|
}
|
148
154
|
)
|
@@ -152,13 +158,19 @@ class BaseWorkflowDisplay(Generic[WorkflowType]):
|
|
152
158
|
default = (
|
153
159
|
primitive_to_vellum_value(state_value_reference.instance) if state_value_reference.instance else None
|
154
160
|
)
|
161
|
+
|
162
|
+
# A state variable is required if it has no default value AND is not optional
|
163
|
+
has_default = state_value_reference.instance is not undefined
|
164
|
+
is_optional = type(None) in state_value_reference.types
|
165
|
+
is_required = not has_default and not is_optional
|
166
|
+
|
155
167
|
state_variables.append(
|
156
168
|
{
|
157
169
|
"id": str(state_value_display.id),
|
158
170
|
"key": state_value_display.name or state_value_reference.name,
|
159
171
|
"type": infer_vellum_variable_type(state_value_reference),
|
160
172
|
"default": default.dict() if default else None,
|
161
|
-
"required":
|
173
|
+
"required": is_required,
|
162
174
|
"extensions": {"color": state_value_display.color},
|
163
175
|
}
|
164
176
|
)
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import pytest
|
2
2
|
from uuid import uuid4
|
3
|
+
from typing import Optional
|
3
4
|
|
5
|
+
from vellum.workflows.inputs import BaseInputs
|
4
6
|
from vellum.workflows.nodes.bases.base import BaseNode
|
5
7
|
from vellum.workflows.nodes.core.inline_subworkflow_node.node import InlineSubworkflowNode
|
6
8
|
from vellum.workflows.nodes.core.retry_node.node import RetryNode
|
@@ -8,6 +10,7 @@ from vellum.workflows.nodes.core.templating_node.node import TemplatingNode
|
|
8
10
|
from vellum.workflows.nodes.core.try_node.node import TryNode
|
9
11
|
from vellum.workflows.nodes.displayable.final_output_node.node import FinalOutputNode
|
10
12
|
from vellum.workflows.references.lazy import LazyReference
|
13
|
+
from vellum.workflows.state.base import BaseState
|
11
14
|
from vellum.workflows.workflows.base import BaseWorkflow
|
12
15
|
from vellum_ee.workflows.display.editor.types import NodeDisplayData, NodeDisplayPosition
|
13
16
|
from vellum_ee.workflows.display.nodes import BaseNodeDisplay
|
@@ -828,3 +831,127 @@ def test_serialize_workflow__empty_rules_indexerror():
|
|
828
831
|
terminal_nodes = [node for node in nodes if node.get("type") == "TERMINAL"]
|
829
832
|
assert len(terminal_nodes) == 1
|
830
833
|
assert terminal_nodes[0]["data"]["name"] == "problematic_output"
|
834
|
+
|
835
|
+
|
836
|
+
def test_serialize_workflow__input_variables():
|
837
|
+
# GIVEN a workflow with inputs
|
838
|
+
class Inputs(BaseInputs):
|
839
|
+
input_1: str
|
840
|
+
input_2: Optional[str]
|
841
|
+
input_3: int = 1
|
842
|
+
input_4: Optional[int] = 2
|
843
|
+
|
844
|
+
class MyWorkflow(BaseWorkflow[Inputs, BaseState]):
|
845
|
+
pass
|
846
|
+
|
847
|
+
# WHEN we serialize it
|
848
|
+
workflow_display = get_workflow_display(workflow_class=MyWorkflow)
|
849
|
+
data = workflow_display.serialize()
|
850
|
+
|
851
|
+
# THEN the inputs should be serialized correctly
|
852
|
+
assert "input_variables" in data
|
853
|
+
input_variables = data["input_variables"]
|
854
|
+
assert isinstance(input_variables, list)
|
855
|
+
assert len(input_variables) == 4
|
856
|
+
|
857
|
+
input_1 = next(var for var in input_variables if isinstance(var, dict) and var["key"] == "input_1")
|
858
|
+
assert input_1 == {
|
859
|
+
"id": "13bd7980-3fbd-486c-9ebd-a29d84f7bda0",
|
860
|
+
"key": "input_1",
|
861
|
+
"type": "STRING",
|
862
|
+
"default": None,
|
863
|
+
"required": True,
|
864
|
+
"extensions": {"color": None},
|
865
|
+
}
|
866
|
+
|
867
|
+
input_2 = next(var for var in input_variables if isinstance(var, dict) and var["key"] == "input_2")
|
868
|
+
assert input_2 == {
|
869
|
+
"id": "13847952-beab-408d-945e-cfa079e6e124",
|
870
|
+
"key": "input_2",
|
871
|
+
"type": "STRING",
|
872
|
+
"default": None,
|
873
|
+
"required": False,
|
874
|
+
"extensions": {"color": None},
|
875
|
+
}
|
876
|
+
|
877
|
+
input_3 = next(var for var in input_variables if isinstance(var, dict) and var["key"] == "input_3")
|
878
|
+
assert input_3 == {
|
879
|
+
"id": "2e38e1a4-09ff-4bb8-a12e-9bf54d4f3a5e",
|
880
|
+
"key": "input_3",
|
881
|
+
"type": "NUMBER",
|
882
|
+
"default": {"type": "NUMBER", "value": 1.0},
|
883
|
+
"required": False,
|
884
|
+
"extensions": {"color": None},
|
885
|
+
}
|
886
|
+
|
887
|
+
input_4 = next(var for var in input_variables if isinstance(var, dict) and var["key"] == "input_4")
|
888
|
+
assert input_4 == {
|
889
|
+
"id": "d945b6ae-2490-4bfb-9b1c-b1e484dfd4f6",
|
890
|
+
"key": "input_4",
|
891
|
+
"type": "NUMBER",
|
892
|
+
"default": {"type": "NUMBER", "value": 2.0},
|
893
|
+
"required": False,
|
894
|
+
"extensions": {"color": None},
|
895
|
+
}
|
896
|
+
|
897
|
+
|
898
|
+
def test_serialize_workflow__state_variables():
|
899
|
+
# GIVEN a workflow with state variables
|
900
|
+
class State(BaseState):
|
901
|
+
state_1: str = "hello"
|
902
|
+
state_2: Optional[str] = None
|
903
|
+
state_3: int = 1
|
904
|
+
state_4: Optional[int] = 2
|
905
|
+
|
906
|
+
class MyWorkflow(BaseWorkflow[BaseInputs, State]):
|
907
|
+
pass
|
908
|
+
|
909
|
+
# WHEN we serialize it
|
910
|
+
workflow_display = get_workflow_display(workflow_class=MyWorkflow)
|
911
|
+
data = workflow_display.serialize()
|
912
|
+
|
913
|
+
# THEN the state variables should be serialized correctly
|
914
|
+
assert "state_variables" in data
|
915
|
+
state_variables = data["state_variables"]
|
916
|
+
assert isinstance(state_variables, list)
|
917
|
+
assert len(state_variables) == 4
|
918
|
+
|
919
|
+
state_1 = next(var for var in state_variables if isinstance(var, dict) and var["key"] == "state_1")
|
920
|
+
assert state_1 == {
|
921
|
+
"id": "83c5b71d-56eb-42a5-84df-97e3591370c2",
|
922
|
+
"key": "state_1",
|
923
|
+
"type": "STRING",
|
924
|
+
"default": {"type": "STRING", "value": "hello"},
|
925
|
+
"required": False,
|
926
|
+
"extensions": {"color": None},
|
927
|
+
}
|
928
|
+
|
929
|
+
state_2 = next(var for var in state_variables if isinstance(var, dict) and var["key"] == "state_2")
|
930
|
+
assert state_2 == {
|
931
|
+
"id": "9b0cfeec-aa66-42b3-8f31-aa7eb8ac30ea",
|
932
|
+
"key": "state_2",
|
933
|
+
"type": "STRING",
|
934
|
+
"default": None,
|
935
|
+
"required": False,
|
936
|
+
"extensions": {"color": None},
|
937
|
+
}
|
938
|
+
|
939
|
+
state_3 = next(var for var in state_variables if isinstance(var, dict) and var["key"] == "state_3")
|
940
|
+
assert state_3 == {
|
941
|
+
"id": "3e19c570-6b46-4eab-ad81-d8d97028496f",
|
942
|
+
"key": "state_3",
|
943
|
+
"type": "NUMBER",
|
944
|
+
"default": {"type": "NUMBER", "value": 1.0},
|
945
|
+
"required": False,
|
946
|
+
"extensions": {"color": None},
|
947
|
+
}
|
948
|
+
|
949
|
+
state_4 = next(var for var in state_variables if isinstance(var, dict) and var["key"] == "state_4")
|
950
|
+
assert state_4 == {
|
951
|
+
"id": "50c735de-f269-4d0a-b511-c9a1104451bb",
|
952
|
+
"key": "state_4",
|
953
|
+
"type": "NUMBER",
|
954
|
+
"default": {"type": "NUMBER", "value": 2.0},
|
955
|
+
"required": False,
|
956
|
+
"extensions": {"color": None},
|
957
|
+
}
|