vellum-ai 0.9.16rc2__py3-none-any.whl → 0.9.16rc4__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/plugins/__init__.py +0 -0
- vellum/plugins/pydantic.py +74 -0
- vellum/plugins/utils.py +19 -0
- vellum/plugins/vellum_mypy.py +639 -3
- vellum/workflows/README.md +90 -0
- vellum/workflows/__init__.py +5 -0
- vellum/workflows/constants.py +43 -0
- vellum/workflows/descriptors/__init__.py +0 -0
- vellum/workflows/descriptors/base.py +339 -0
- vellum/workflows/descriptors/tests/test_utils.py +83 -0
- vellum/workflows/descriptors/utils.py +90 -0
- vellum/workflows/edges/__init__.py +5 -0
- vellum/workflows/edges/edge.py +23 -0
- vellum/workflows/emitters/__init__.py +5 -0
- vellum/workflows/emitters/base.py +14 -0
- vellum/workflows/environment/__init__.py +5 -0
- vellum/workflows/environment/environment.py +7 -0
- vellum/workflows/errors/__init__.py +6 -0
- vellum/workflows/errors/types.py +20 -0
- vellum/workflows/events/__init__.py +31 -0
- vellum/workflows/events/node.py +125 -0
- vellum/workflows/events/tests/__init__.py +0 -0
- vellum/workflows/events/tests/test_event.py +216 -0
- vellum/workflows/events/types.py +52 -0
- vellum/workflows/events/utils.py +5 -0
- vellum/workflows/events/workflow.py +139 -0
- vellum/workflows/exceptions.py +15 -0
- vellum/workflows/expressions/__init__.py +0 -0
- vellum/workflows/expressions/accessor.py +52 -0
- vellum/workflows/expressions/and_.py +32 -0
- vellum/workflows/expressions/begins_with.py +31 -0
- vellum/workflows/expressions/between.py +38 -0
- vellum/workflows/expressions/coalesce_expression.py +41 -0
- vellum/workflows/expressions/contains.py +30 -0
- vellum/workflows/expressions/does_not_begin_with.py +31 -0
- vellum/workflows/expressions/does_not_contain.py +30 -0
- vellum/workflows/expressions/does_not_end_with.py +31 -0
- vellum/workflows/expressions/does_not_equal.py +25 -0
- vellum/workflows/expressions/ends_with.py +31 -0
- vellum/workflows/expressions/equals.py +25 -0
- vellum/workflows/expressions/greater_than.py +33 -0
- vellum/workflows/expressions/greater_than_or_equal_to.py +33 -0
- vellum/workflows/expressions/in_.py +31 -0
- vellum/workflows/expressions/is_blank.py +24 -0
- vellum/workflows/expressions/is_not_blank.py +24 -0
- vellum/workflows/expressions/is_not_null.py +21 -0
- vellum/workflows/expressions/is_not_undefined.py +22 -0
- vellum/workflows/expressions/is_null.py +21 -0
- vellum/workflows/expressions/is_undefined.py +22 -0
- vellum/workflows/expressions/less_than.py +33 -0
- vellum/workflows/expressions/less_than_or_equal_to.py +33 -0
- vellum/workflows/expressions/not_between.py +38 -0
- vellum/workflows/expressions/not_in.py +31 -0
- vellum/workflows/expressions/or_.py +32 -0
- vellum/workflows/graph/__init__.py +3 -0
- vellum/workflows/graph/graph.py +131 -0
- vellum/workflows/graph/tests/__init__.py +0 -0
- vellum/workflows/graph/tests/test_graph.py +437 -0
- vellum/workflows/inputs/__init__.py +5 -0
- vellum/workflows/inputs/base.py +55 -0
- vellum/workflows/logging.py +14 -0
- vellum/workflows/nodes/__init__.py +46 -0
- vellum/workflows/nodes/bases/__init__.py +7 -0
- vellum/workflows/nodes/bases/base.py +332 -0
- vellum/workflows/nodes/bases/base_subworkflow_node/__init__.py +5 -0
- vellum/workflows/nodes/bases/base_subworkflow_node/node.py +10 -0
- vellum/workflows/nodes/bases/tests/__init__.py +0 -0
- vellum/workflows/nodes/bases/tests/test_base_node.py +125 -0
- vellum/workflows/nodes/core/__init__.py +16 -0
- vellum/workflows/nodes/core/error_node/__init__.py +5 -0
- vellum/workflows/nodes/core/error_node/node.py +26 -0
- vellum/workflows/nodes/core/inline_subworkflow_node/__init__.py +5 -0
- vellum/workflows/nodes/core/inline_subworkflow_node/node.py +73 -0
- vellum/workflows/nodes/core/map_node/__init__.py +5 -0
- vellum/workflows/nodes/core/map_node/node.py +147 -0
- vellum/workflows/nodes/core/map_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/core/map_node/tests/test_node.py +65 -0
- vellum/workflows/nodes/core/retry_node/__init__.py +5 -0
- vellum/workflows/nodes/core/retry_node/node.py +106 -0
- vellum/workflows/nodes/core/retry_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/core/retry_node/tests/test_node.py +93 -0
- vellum/workflows/nodes/core/templating_node/__init__.py +5 -0
- vellum/workflows/nodes/core/templating_node/custom_filters.py +12 -0
- vellum/workflows/nodes/core/templating_node/exceptions.py +2 -0
- vellum/workflows/nodes/core/templating_node/node.py +123 -0
- vellum/workflows/nodes/core/templating_node/render.py +55 -0
- vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py +21 -0
- vellum/workflows/nodes/core/try_node/__init__.py +5 -0
- vellum/workflows/nodes/core/try_node/node.py +110 -0
- vellum/workflows/nodes/core/try_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/core/try_node/tests/test_node.py +82 -0
- vellum/workflows/nodes/displayable/__init__.py +31 -0
- vellum/workflows/nodes/displayable/api_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/api_node/node.py +44 -0
- vellum/workflows/nodes/displayable/bases/__init__.py +11 -0
- vellum/workflows/nodes/displayable/bases/api_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/bases/api_node/node.py +70 -0
- vellum/workflows/nodes/displayable/bases/base_prompt_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/bases/base_prompt_node/node.py +60 -0
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/constants.py +13 -0
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +118 -0
- vellum/workflows/nodes/displayable/bases/prompt_deployment_node.py +98 -0
- vellum/workflows/nodes/displayable/bases/search_node.py +90 -0
- vellum/workflows/nodes/displayable/code_execution_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/code_execution_node/node.py +197 -0
- vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py +0 -0
- vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py +3 -0
- vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +111 -0
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +10 -0
- vellum/workflows/nodes/displayable/conditional_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/conditional_node/node.py +25 -0
- vellum/workflows/nodes/displayable/final_output_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/final_output_node/node.py +43 -0
- vellum/workflows/nodes/displayable/guardrail_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/guardrail_node/node.py +97 -0
- vellum/workflows/nodes/displayable/inline_prompt_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/inline_prompt_node/node.py +41 -0
- vellum/workflows/nodes/displayable/merge_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/merge_node/node.py +10 -0
- vellum/workflows/nodes/displayable/prompt_deployment_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +45 -0
- vellum/workflows/nodes/displayable/search_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/search_node/node.py +26 -0
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/__init__.py +5 -0
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +156 -0
- vellum/workflows/nodes/displayable/tests/__init__.py +0 -0
- vellum/workflows/nodes/displayable/tests/test_inline_text_prompt_node.py +148 -0
- vellum/workflows/nodes/displayable/tests/test_search_node_wth_text_output.py +134 -0
- vellum/workflows/nodes/displayable/tests/test_text_prompt_deployment_node.py +80 -0
- vellum/workflows/nodes/utils.py +27 -0
- vellum/workflows/outputs/__init__.py +6 -0
- vellum/workflows/outputs/base.py +196 -0
- vellum/workflows/ports/__init__.py +7 -0
- vellum/workflows/ports/node_ports.py +75 -0
- vellum/workflows/ports/port.py +75 -0
- vellum/workflows/ports/utils.py +40 -0
- vellum/workflows/references/__init__.py +17 -0
- vellum/workflows/references/environment_variable.py +20 -0
- vellum/workflows/references/execution_count.py +20 -0
- vellum/workflows/references/external_input.py +49 -0
- vellum/workflows/references/input.py +7 -0
- vellum/workflows/references/lazy.py +55 -0
- vellum/workflows/references/node.py +43 -0
- vellum/workflows/references/output.py +78 -0
- vellum/workflows/references/state_value.py +23 -0
- vellum/workflows/references/vellum_secret.py +15 -0
- vellum/workflows/references/workflow_input.py +41 -0
- vellum/workflows/resolvers/__init__.py +5 -0
- vellum/workflows/resolvers/base.py +15 -0
- vellum/workflows/runner/__init__.py +5 -0
- vellum/workflows/runner/runner.py +588 -0
- vellum/workflows/runner/types.py +18 -0
- vellum/workflows/state/__init__.py +5 -0
- vellum/workflows/state/base.py +327 -0
- vellum/workflows/state/context.py +18 -0
- vellum/workflows/state/encoder.py +57 -0
- vellum/workflows/state/store.py +28 -0
- vellum/workflows/state/tests/__init__.py +0 -0
- vellum/workflows/state/tests/test_state.py +113 -0
- vellum/workflows/types/__init__.py +0 -0
- vellum/workflows/types/core.py +91 -0
- vellum/workflows/types/generics.py +14 -0
- vellum/workflows/types/stack.py +39 -0
- vellum/workflows/types/tests/__init__.py +0 -0
- vellum/workflows/types/tests/test_utils.py +76 -0
- vellum/workflows/types/utils.py +164 -0
- vellum/workflows/utils/__init__.py +0 -0
- vellum/workflows/utils/names.py +13 -0
- vellum/workflows/utils/tests/__init__.py +0 -0
- vellum/workflows/utils/tests/test_names.py +15 -0
- vellum/workflows/utils/tests/test_vellum_variables.py +25 -0
- vellum/workflows/utils/vellum_variables.py +81 -0
- vellum/workflows/vellum_client.py +18 -0
- vellum/workflows/workflows/__init__.py +5 -0
- vellum/workflows/workflows/base.py +365 -0
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.9.16rc4.dist-info}/METADATA +2 -1
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.9.16rc4.dist-info}/RECORD +245 -7
- vellum_cli/__init__.py +72 -0
- vellum_cli/aliased_group.py +103 -0
- vellum_cli/config.py +96 -0
- vellum_cli/image_push.py +112 -0
- vellum_cli/logger.py +36 -0
- vellum_cli/pull.py +73 -0
- vellum_cli/push.py +121 -0
- vellum_cli/tests/test_config.py +100 -0
- vellum_cli/tests/test_pull.py +152 -0
- vellum_ee/workflows/__init__.py +0 -0
- vellum_ee/workflows/display/__init__.py +0 -0
- vellum_ee/workflows/display/base.py +73 -0
- vellum_ee/workflows/display/nodes/__init__.py +4 -0
- vellum_ee/workflows/display/nodes/base_node_display.py +116 -0
- vellum_ee/workflows/display/nodes/base_node_vellum_display.py +36 -0
- vellum_ee/workflows/display/nodes/get_node_display_class.py +25 -0
- vellum_ee/workflows/display/nodes/tests/__init__.py +0 -0
- vellum_ee/workflows/display/nodes/tests/test_base_node_display.py +47 -0
- vellum_ee/workflows/display/nodes/types.py +18 -0
- vellum_ee/workflows/display/nodes/utils.py +33 -0
- vellum_ee/workflows/display/nodes/vellum/__init__.py +32 -0
- vellum_ee/workflows/display/nodes/vellum/api_node.py +205 -0
- vellum_ee/workflows/display/nodes/vellum/code_execution_node.py +71 -0
- vellum_ee/workflows/display/nodes/vellum/conditional_node.py +217 -0
- vellum_ee/workflows/display/nodes/vellum/final_output_node.py +61 -0
- vellum_ee/workflows/display/nodes/vellum/guardrail_node.py +49 -0
- vellum_ee/workflows/display/nodes/vellum/inline_prompt_node.py +170 -0
- vellum_ee/workflows/display/nodes/vellum/inline_subworkflow_node.py +99 -0
- vellum_ee/workflows/display/nodes/vellum/map_node.py +100 -0
- vellum_ee/workflows/display/nodes/vellum/merge_node.py +48 -0
- vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py +68 -0
- vellum_ee/workflows/display/nodes/vellum/search_node.py +193 -0
- vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py +58 -0
- vellum_ee/workflows/display/nodes/vellum/templating_node.py +67 -0
- vellum_ee/workflows/display/nodes/vellum/tests/__init__.py +0 -0
- vellum_ee/workflows/display/nodes/vellum/tests/test_utils.py +106 -0
- vellum_ee/workflows/display/nodes/vellum/try_node.py +38 -0
- vellum_ee/workflows/display/nodes/vellum/utils.py +76 -0
- vellum_ee/workflows/display/tests/__init__.py +0 -0
- vellum_ee/workflows/display/tests/workflow_serialization/__init__.py +0 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py +426 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +607 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py +1175 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_guardrail_node_serialization.py +235 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_inline_subworkflow_serialization.py +511 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_map_node_serialization.py +372 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_merge_node_serialization.py +272 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_prompt_deployment_serialization.py +289 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_subworkflow_deployment_serialization.py +354 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_terminal_node_serialization.py +123 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_try_node_serialization.py +84 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_complex_terminal_node_serialization.py +233 -0
- vellum_ee/workflows/display/types.py +46 -0
- vellum_ee/workflows/display/utils/__init__.py +0 -0
- vellum_ee/workflows/display/utils/tests/__init__.py +0 -0
- vellum_ee/workflows/display/utils/tests/test_uuids.py +16 -0
- vellum_ee/workflows/display/utils/uuids.py +24 -0
- vellum_ee/workflows/display/utils/vellum.py +121 -0
- vellum_ee/workflows/display/vellum.py +357 -0
- vellum_ee/workflows/display/workflows/__init__.py +5 -0
- vellum_ee/workflows/display/workflows/base_workflow_display.py +302 -0
- vellum_ee/workflows/display/workflows/get_vellum_workflow_display_class.py +32 -0
- vellum_ee/workflows/display/workflows/vellum_workflow_display.py +386 -0
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.9.16rc4.dist-info}/LICENSE +0 -0
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.9.16rc4.dist-info}/WHEEL +0 -0
- {vellum_ai-0.9.16rc2.dist-info → vellum_ai-0.9.16rc4.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
import os
|
2
|
+
import tempfile
|
3
|
+
from uuid import uuid4
|
4
|
+
|
5
|
+
from vellum_cli.config import VellumCliConfig, WorkflowConfig, load_vellum_cli_config
|
6
|
+
|
7
|
+
|
8
|
+
def test_load_vellum_cli_config__pyproject_toml_only():
|
9
|
+
# GIVEN a pyproject.toml file with vellum config
|
10
|
+
cwd = tempfile.mkdtemp()
|
11
|
+
with open(os.path.join(cwd, "pyproject.toml"), "w") as f:
|
12
|
+
f.write(
|
13
|
+
"""[[tool.vellum.workflows]]
|
14
|
+
module = "module1.workflow1"
|
15
|
+
"""
|
16
|
+
)
|
17
|
+
|
18
|
+
# WHEN the config is loaded
|
19
|
+
config = load_vellum_cli_config(cwd)
|
20
|
+
|
21
|
+
# THEN the config is loaded correctly
|
22
|
+
assert config == VellumCliConfig(
|
23
|
+
workflows=[WorkflowConfig(module="module1.workflow1")],
|
24
|
+
version="1.0",
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
def test_load_vellum_cli_config__pyproject_toml_and_lockfile():
|
29
|
+
# GIVEN a pyproject.toml file with vellum config
|
30
|
+
cwd = tempfile.mkdtemp()
|
31
|
+
with open(os.path.join(cwd, "pyproject.toml"), "w") as f:
|
32
|
+
f.write(
|
33
|
+
"""[[tool.vellum.workflows]]
|
34
|
+
module = "module1.workflow1"
|
35
|
+
"""
|
36
|
+
)
|
37
|
+
|
38
|
+
# AND a lockfile
|
39
|
+
workflow_sandbox_id = uuid4()
|
40
|
+
with open(os.path.join(cwd, "vellum.lock.json"), "w") as f:
|
41
|
+
f.write(
|
42
|
+
f"""{{
|
43
|
+
"version": "1.0",
|
44
|
+
"workflows": [
|
45
|
+
{{
|
46
|
+
"workflow_sandbox_id": "{workflow_sandbox_id}",
|
47
|
+
"module": "module1.workflow1"
|
48
|
+
}}
|
49
|
+
]
|
50
|
+
}}
|
51
|
+
"""
|
52
|
+
)
|
53
|
+
|
54
|
+
# WHEN the config is loaded
|
55
|
+
config = load_vellum_cli_config(cwd)
|
56
|
+
|
57
|
+
# THEN the config is loaded correctly
|
58
|
+
assert config == VellumCliConfig(
|
59
|
+
workflows=[WorkflowConfig(module="module1.workflow1", workflow_sandbox_id=str(workflow_sandbox_id))],
|
60
|
+
version="1.0",
|
61
|
+
)
|
62
|
+
|
63
|
+
|
64
|
+
def test_load_vellum_cli_config__pyproject_toml_and_lockfile__different_modules():
|
65
|
+
# GIVEN a pyproject.toml file with vellum config
|
66
|
+
cwd = tempfile.mkdtemp()
|
67
|
+
with open(os.path.join(cwd, "pyproject.toml"), "w") as f:
|
68
|
+
f.write(
|
69
|
+
"""[[tool.vellum.workflows]]
|
70
|
+
module = "module1.workflow1"
|
71
|
+
"""
|
72
|
+
)
|
73
|
+
|
74
|
+
# AND a lockfile
|
75
|
+
workflow_sandbox_id = uuid4()
|
76
|
+
with open(os.path.join(cwd, "vellum.lock.json"), "w") as f:
|
77
|
+
f.write(
|
78
|
+
f"""{{
|
79
|
+
"version": "1.0",
|
80
|
+
"workflows": [
|
81
|
+
{{
|
82
|
+
"workflow_sandbox_id": "{workflow_sandbox_id}",
|
83
|
+
"module": "module2.workflow2"
|
84
|
+
}}
|
85
|
+
]
|
86
|
+
}}
|
87
|
+
"""
|
88
|
+
)
|
89
|
+
|
90
|
+
# WHEN the config is loaded
|
91
|
+
config = load_vellum_cli_config(cwd)
|
92
|
+
|
93
|
+
# THEN the config is loaded correctly
|
94
|
+
assert config == VellumCliConfig(
|
95
|
+
workflows=[
|
96
|
+
WorkflowConfig(module="module1.workflow1"),
|
97
|
+
WorkflowConfig(module="module2.workflow2", workflow_sandbox_id=str(workflow_sandbox_id)),
|
98
|
+
],
|
99
|
+
version="1.0",
|
100
|
+
)
|
@@ -0,0 +1,152 @@
|
|
1
|
+
import pytest
|
2
|
+
import io
|
3
|
+
import os
|
4
|
+
import shutil
|
5
|
+
import tempfile
|
6
|
+
from uuid import uuid4
|
7
|
+
import zipfile
|
8
|
+
from typing import Generator, Tuple
|
9
|
+
|
10
|
+
import tomli_w
|
11
|
+
|
12
|
+
from vellum_cli.pull import pull_command
|
13
|
+
|
14
|
+
|
15
|
+
def zip_file_map(file_map: dict[str, str]) -> bytes:
|
16
|
+
# Create an in-memory bytes buffer to store the zip
|
17
|
+
zip_buffer = io.BytesIO()
|
18
|
+
|
19
|
+
# Create zip file and add files from file_map
|
20
|
+
with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file:
|
21
|
+
for filename, content in file_map.items():
|
22
|
+
zip_file.writestr(filename, content)
|
23
|
+
|
24
|
+
# Get the bytes from the buffer
|
25
|
+
zip_bytes = zip_buffer.getvalue()
|
26
|
+
zip_buffer.close()
|
27
|
+
|
28
|
+
return zip_bytes
|
29
|
+
|
30
|
+
|
31
|
+
@pytest.fixture
|
32
|
+
def mock_module() -> Generator[Tuple[str, str], None, None]:
|
33
|
+
current_dir = os.getcwd()
|
34
|
+
temp_dir = tempfile.mkdtemp()
|
35
|
+
os.chdir(temp_dir)
|
36
|
+
module = "examples.mock"
|
37
|
+
|
38
|
+
with open(os.path.join(temp_dir, "pyproject.toml"), "wb") as f:
|
39
|
+
tomli_w.dump(
|
40
|
+
{
|
41
|
+
"tool": {
|
42
|
+
"vellum": {
|
43
|
+
"workflows": [
|
44
|
+
{
|
45
|
+
"module": module,
|
46
|
+
"workflow_sandbox_id": str(uuid4()),
|
47
|
+
}
|
48
|
+
]
|
49
|
+
}
|
50
|
+
}
|
51
|
+
},
|
52
|
+
f,
|
53
|
+
)
|
54
|
+
|
55
|
+
yield temp_dir, module
|
56
|
+
|
57
|
+
os.chdir(current_dir)
|
58
|
+
shutil.rmtree(temp_dir)
|
59
|
+
|
60
|
+
|
61
|
+
def test_pull(vellum_client, mock_module):
|
62
|
+
# GIVEN a module on the user's filesystem
|
63
|
+
temp_dir, module = mock_module
|
64
|
+
|
65
|
+
# AND the workflow pull API call returns a zip file
|
66
|
+
vellum_client.workflows.pull.return_value = iter([zip_file_map({"workflow.py": "print('hello')"})])
|
67
|
+
|
68
|
+
# WHEN the user runs the pull command
|
69
|
+
pull_command(module)
|
70
|
+
|
71
|
+
# THEN the workflow.py file is written to the module directory
|
72
|
+
assert os.path.exists(os.path.join(temp_dir, *module.split("."), "workflow.py"))
|
73
|
+
with open(os.path.join(temp_dir, *module.split("."), "workflow.py")) as f:
|
74
|
+
assert f.read() == "print('hello')"
|
75
|
+
|
76
|
+
|
77
|
+
def test_pull__remove_missing_files(vellum_client, mock_module):
|
78
|
+
# GIVEN a module on the user's filesystem
|
79
|
+
temp_dir, module = mock_module
|
80
|
+
|
81
|
+
# AND the workflow pull API call returns a zip file
|
82
|
+
vellum_client.workflows.pull.return_value = iter([zip_file_map({"workflow.py": "print('hello')"})])
|
83
|
+
|
84
|
+
# AND there is already a different file in the module directory
|
85
|
+
other_file_path = os.path.join(temp_dir, *module.split("."), "other_file.py")
|
86
|
+
os.makedirs(os.path.dirname(other_file_path), exist_ok=True)
|
87
|
+
with open(other_file_path, "w") as f:
|
88
|
+
f.write("print('hello')")
|
89
|
+
|
90
|
+
# WHEN the user runs the pull command
|
91
|
+
pull_command(module)
|
92
|
+
|
93
|
+
# THEN the workflow.py file is written to the module directory
|
94
|
+
assert os.path.exists(os.path.join(temp_dir, *module.split("."), "workflow.py"))
|
95
|
+
with open(os.path.join(temp_dir, *module.split("."), "workflow.py")) as f:
|
96
|
+
assert f.read() == "print('hello')"
|
97
|
+
|
98
|
+
# AND the other_file.py file is deleted
|
99
|
+
assert not os.path.exists(other_file_path)
|
100
|
+
|
101
|
+
|
102
|
+
def test_pull__remove_missing_files__ignore_pattern(vellum_client, mock_module):
|
103
|
+
# GIVEN a module on the user's filesystem
|
104
|
+
temp_dir, module = mock_module
|
105
|
+
|
106
|
+
# AND the workflow pull API call returns a zip file
|
107
|
+
vellum_client.workflows.pull.return_value = iter([zip_file_map({"workflow.py": "print('hello')"})])
|
108
|
+
|
109
|
+
# AND there is already a different file in the module directory
|
110
|
+
other_file_path = os.path.join(temp_dir, *module.split("."), "other_file.py")
|
111
|
+
os.makedirs(os.path.dirname(other_file_path), exist_ok=True)
|
112
|
+
with open(other_file_path, "w") as f:
|
113
|
+
f.write("print('hello')")
|
114
|
+
|
115
|
+
# AND there is already a test file
|
116
|
+
test_file_path = os.path.join(temp_dir, *module.split("."), "tests", "test_workflow.py")
|
117
|
+
os.makedirs(os.path.dirname(test_file_path), exist_ok=True)
|
118
|
+
with open(test_file_path, "w") as f:
|
119
|
+
f.write("print('hello')")
|
120
|
+
|
121
|
+
# AND the ignore pattern is set to tests
|
122
|
+
with open(os.path.join(temp_dir, "pyproject.toml"), "wb") as f:
|
123
|
+
tomli_w.dump(
|
124
|
+
{
|
125
|
+
"tool": {
|
126
|
+
"vellum": {
|
127
|
+
"workflows": [
|
128
|
+
{
|
129
|
+
"module": module,
|
130
|
+
"workflow_sandbox_id": str(uuid4()),
|
131
|
+
"ignore": "tests/*",
|
132
|
+
}
|
133
|
+
]
|
134
|
+
}
|
135
|
+
}
|
136
|
+
},
|
137
|
+
f,
|
138
|
+
)
|
139
|
+
|
140
|
+
# WHEN the user runs the pull command
|
141
|
+
pull_command(module)
|
142
|
+
|
143
|
+
# THEN the workflow.py file is written to the module directory
|
144
|
+
assert os.path.exists(os.path.join(temp_dir, *module.split("."), "workflow.py"))
|
145
|
+
with open(os.path.join(temp_dir, *module.split("."), "workflow.py")) as f:
|
146
|
+
assert f.read() == "print('hello')"
|
147
|
+
|
148
|
+
# AND the other_file.py file is deleted
|
149
|
+
assert not os.path.exists(other_file_path)
|
150
|
+
|
151
|
+
# AND the tests/test_workflow.py file is untouched
|
152
|
+
assert os.path.exists(test_file_path)
|
File without changes
|
File without changes
|
@@ -0,0 +1,73 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from uuid import UUID
|
3
|
+
from typing import TypeVar
|
4
|
+
|
5
|
+
|
6
|
+
@dataclass
|
7
|
+
class WorkflowMetaDisplayOverrides:
|
8
|
+
pass
|
9
|
+
|
10
|
+
|
11
|
+
@dataclass
|
12
|
+
class WorkflowMetaDisplay(WorkflowMetaDisplayOverrides):
|
13
|
+
pass
|
14
|
+
|
15
|
+
|
16
|
+
WorkflowMetaDisplayType = TypeVar("WorkflowMetaDisplayType", bound=WorkflowMetaDisplay)
|
17
|
+
WorkflowMetaDisplayOverridesType = TypeVar("WorkflowMetaDisplayOverridesType", bound=WorkflowMetaDisplayOverrides)
|
18
|
+
|
19
|
+
|
20
|
+
@dataclass
|
21
|
+
class WorkflowInputsDisplayOverrides:
|
22
|
+
id: UUID
|
23
|
+
|
24
|
+
|
25
|
+
@dataclass
|
26
|
+
class WorkflowInputsDisplay(WorkflowInputsDisplayOverrides):
|
27
|
+
pass
|
28
|
+
|
29
|
+
|
30
|
+
WorkflowInputsDisplayType = TypeVar("WorkflowInputsDisplayType", bound=WorkflowInputsDisplay)
|
31
|
+
WorkflowInputsDisplayOverridesType = TypeVar("WorkflowInputsDisplayOverridesType", bound=WorkflowInputsDisplayOverrides)
|
32
|
+
|
33
|
+
|
34
|
+
@dataclass
|
35
|
+
class EdgeDisplayOverrides:
|
36
|
+
id: UUID
|
37
|
+
|
38
|
+
|
39
|
+
@dataclass
|
40
|
+
class EdgeDisplay(EdgeDisplayOverrides):
|
41
|
+
pass
|
42
|
+
|
43
|
+
|
44
|
+
EdgeDisplayType = TypeVar("EdgeDisplayType", bound=EdgeDisplay)
|
45
|
+
EdgeDisplayOverridesType = TypeVar("EdgeDisplayOverridesType", bound=EdgeDisplayOverrides)
|
46
|
+
|
47
|
+
|
48
|
+
@dataclass
|
49
|
+
class EntrypointDisplayOverrides:
|
50
|
+
id: UUID
|
51
|
+
|
52
|
+
|
53
|
+
@dataclass
|
54
|
+
class EntrypointDisplay(EntrypointDisplayOverrides):
|
55
|
+
pass
|
56
|
+
|
57
|
+
|
58
|
+
EntrypointDisplayType = TypeVar("EntrypointDisplayType", bound=EntrypointDisplay)
|
59
|
+
EntrypointDisplayOverridesType = TypeVar("EntrypointDisplayOverridesType", bound=EntrypointDisplayOverrides)
|
60
|
+
|
61
|
+
|
62
|
+
@dataclass
|
63
|
+
class WorkflowOutputDisplayOverrides:
|
64
|
+
id: UUID
|
65
|
+
|
66
|
+
|
67
|
+
@dataclass
|
68
|
+
class WorkflowOutputDisplay(WorkflowOutputDisplayOverrides):
|
69
|
+
pass
|
70
|
+
|
71
|
+
|
72
|
+
WorkflowOutputDisplayType = TypeVar("WorkflowOutputDisplayType", bound=WorkflowOutputDisplay)
|
73
|
+
WorkflowOutputDisplayOverridesType = TypeVar("WorkflowOutputDisplayOverridesType", bound=WorkflowOutputDisplayOverrides)
|
@@ -0,0 +1,116 @@
|
|
1
|
+
from functools import cached_property
|
2
|
+
import inspect
|
3
|
+
from uuid import UUID
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, Generic, Optional, Type, TypeVar, get_args
|
5
|
+
|
6
|
+
from vellum_ee.workflows.display.nodes.types import NodeOutputDisplay, PortDisplay, PortDisplayOverrides
|
7
|
+
from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
|
8
|
+
from vellum_ee.workflows.display.vellum import CodeResourceDefinition, NodeDefinition
|
9
|
+
from vellum.workflows.nodes.bases.base import BaseNode
|
10
|
+
from vellum.workflows.nodes.utils import get_wrapped_node, has_wrapped_node
|
11
|
+
from vellum.workflows.ports import Port
|
12
|
+
from vellum.workflows.references import OutputReference
|
13
|
+
from vellum.workflows.types.core import JsonObject
|
14
|
+
from vellum.workflows.types.generics import NodeType
|
15
|
+
from vellum.workflows.types.utils import get_original_base
|
16
|
+
from vellum.workflows.utils.names import pascal_to_title_case
|
17
|
+
|
18
|
+
if TYPE_CHECKING:
|
19
|
+
from vellum_ee.workflows.display.types import WorkflowDisplayContext
|
20
|
+
|
21
|
+
_NodeDisplayAttrType = TypeVar("_NodeDisplayAttrType")
|
22
|
+
|
23
|
+
|
24
|
+
class BaseNodeDisplay(Generic[NodeType]):
|
25
|
+
output_display: Dict[OutputReference, NodeOutputDisplay] = {}
|
26
|
+
port_displays: Dict[Port, PortDisplayOverrides] = {}
|
27
|
+
|
28
|
+
# Used to store the mapping between node types and their display classes
|
29
|
+
_node_display_registry: Dict[Type[NodeType], Type["BaseNodeDisplay"]] = {}
|
30
|
+
|
31
|
+
def __init__(self, node: Type[NodeType]):
|
32
|
+
self._node = node
|
33
|
+
|
34
|
+
def serialize(self, display_context: "WorkflowDisplayContext", **kwargs: Any) -> JsonObject:
|
35
|
+
raise NotImplementedError(f"Serialization for nodes of type {self._node.__name__} is not supported.")
|
36
|
+
|
37
|
+
def get_definition(self) -> NodeDefinition:
|
38
|
+
node = self._node
|
39
|
+
node_definition = NodeDefinition(
|
40
|
+
name=node.__name__,
|
41
|
+
module=node.__module__.split("."),
|
42
|
+
bases=[
|
43
|
+
CodeResourceDefinition(
|
44
|
+
name=base.__name__,
|
45
|
+
module=base.__module__.split("."),
|
46
|
+
)
|
47
|
+
for base in node.__bases__
|
48
|
+
],
|
49
|
+
)
|
50
|
+
return node_definition
|
51
|
+
|
52
|
+
def get_node_output_display(self, output: OutputReference) -> NodeOutputDisplay:
|
53
|
+
explicit_display = self.output_display.get(output)
|
54
|
+
if explicit_display:
|
55
|
+
return explicit_display
|
56
|
+
|
57
|
+
return NodeOutputDisplay(id=uuid4_from_hash(f"{self.node_id}|{output.name}"), name=output.name)
|
58
|
+
|
59
|
+
def get_node_port_display(self, port: Port) -> PortDisplay:
|
60
|
+
overrides = self.port_displays.get(port)
|
61
|
+
|
62
|
+
port_id: UUID
|
63
|
+
if overrides:
|
64
|
+
port_id = overrides.id
|
65
|
+
else:
|
66
|
+
port_id = uuid4_from_hash(f"{self.node_id}|ports|{port.name}")
|
67
|
+
|
68
|
+
return PortDisplay(id=port_id, node_id=self.node_id)
|
69
|
+
|
70
|
+
@classmethod
|
71
|
+
def get_from_node_display_registry(cls, node_class: Type[NodeType]) -> Type["BaseNodeDisplay"]:
|
72
|
+
return cls._node_display_registry[node_class]
|
73
|
+
|
74
|
+
@cached_property
|
75
|
+
def node_id(self) -> UUID:
|
76
|
+
"""Can be overridden as a class attribute to specify a custom node id."""
|
77
|
+
return uuid4_from_hash(self._node.__qualname__)
|
78
|
+
|
79
|
+
@cached_property
|
80
|
+
def label(self) -> str:
|
81
|
+
"""Can be overridden as a class attribute to specify a custom label."""
|
82
|
+
return pascal_to_title_case(self._node.__name__)
|
83
|
+
|
84
|
+
@classmethod
|
85
|
+
def _get_explicit_node_display_attr(
|
86
|
+
cls,
|
87
|
+
attribute: str,
|
88
|
+
attribute_type: Type[_NodeDisplayAttrType],
|
89
|
+
) -> Optional[_NodeDisplayAttrType]:
|
90
|
+
node_display_attribute: Optional[_NodeDisplayAttrType] = getattr(cls, attribute, None)
|
91
|
+
|
92
|
+
if node_display_attribute is None:
|
93
|
+
return None
|
94
|
+
|
95
|
+
if isinstance(node_display_attribute, attribute_type):
|
96
|
+
return node_display_attribute
|
97
|
+
|
98
|
+
raise ValueError(f"Node {cls.__name__} must define an explicit {attribute} of type {attribute_type.__name__}.")
|
99
|
+
|
100
|
+
def __init_subclass__(cls, **kwargs: Any) -> None:
|
101
|
+
super().__init_subclass__(**kwargs)
|
102
|
+
|
103
|
+
original_base = get_original_base(cls)
|
104
|
+
node_class = get_args(original_base)[0]
|
105
|
+
if isinstance(node_class, TypeVar):
|
106
|
+
bounded_class = node_class.__bound__
|
107
|
+
if inspect.isclass(bounded_class) and issubclass(bounded_class, BaseNode):
|
108
|
+
cls._node_display_registry[bounded_class] = cls
|
109
|
+
elif issubclass(node_class, BaseNode):
|
110
|
+
if has_wrapped_node(node_class):
|
111
|
+
wrapped_node = get_wrapped_node(node_class)
|
112
|
+
if wrapped_node._is_wrapped_node:
|
113
|
+
cls._node_display_registry[wrapped_node] = cls
|
114
|
+
return
|
115
|
+
|
116
|
+
cls._node_display_registry[node_class] = cls
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from uuid import UUID
|
2
|
+
from typing import ClassVar, Dict, Optional
|
3
|
+
|
4
|
+
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
5
|
+
from vellum_ee.workflows.display.nodes.types import PortDisplay
|
6
|
+
from vellum_ee.workflows.display.utils.uuids import uuid4_from_hash
|
7
|
+
from vellum_ee.workflows.display.vellum import NodeDisplayData
|
8
|
+
from vellum.workflows.ports import Port
|
9
|
+
from vellum.workflows.types.generics import NodeType
|
10
|
+
|
11
|
+
|
12
|
+
class BaseNodeVellumDisplay(BaseNodeDisplay[NodeType]):
|
13
|
+
# Used to explicitly set display data for a node
|
14
|
+
display_data: ClassVar[Optional[NodeDisplayData]] = None
|
15
|
+
|
16
|
+
# Used to explicitly set the target handle id for a node
|
17
|
+
target_handle_id: ClassVar[Optional[UUID]] = None
|
18
|
+
|
19
|
+
# Used to explicitly set the node input ids by name for a node
|
20
|
+
node_input_ids_by_name: ClassVar[Dict[str, UUID]] = {}
|
21
|
+
|
22
|
+
def _get_node_display_uuid(self, attribute: str) -> UUID:
|
23
|
+
explicit_value = self._get_explicit_node_display_attr(attribute, UUID)
|
24
|
+
return explicit_value if explicit_value else uuid4_from_hash(f"{self.node_id}|{attribute}")
|
25
|
+
|
26
|
+
def get_display_data(self) -> NodeDisplayData:
|
27
|
+
explicit_value = self._get_explicit_node_display_attr("display_data", NodeDisplayData)
|
28
|
+
return explicit_value if explicit_value else NodeDisplayData()
|
29
|
+
|
30
|
+
def get_target_handle_id(self) -> UUID:
|
31
|
+
return self._get_node_display_uuid("target_handle_id")
|
32
|
+
|
33
|
+
def get_source_handle_id(self, port_displays: Dict[Port, PortDisplay]) -> UUID:
|
34
|
+
default_port = self._node.Ports.default
|
35
|
+
default_port_display = port_displays[default_port]
|
36
|
+
return default_port_display.id
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from typing import Optional, Type
|
2
|
+
|
3
|
+
from vellum_ee.workflows.display.types import NodeDisplayType
|
4
|
+
from vellum.workflows.types.generics import NodeType
|
5
|
+
|
6
|
+
|
7
|
+
def get_node_display_class(
|
8
|
+
base_class: Type[NodeDisplayType], node_class: Type[NodeType], root_node_class: Optional[Type[NodeType]] = None
|
9
|
+
) -> Type[NodeDisplayType]:
|
10
|
+
try:
|
11
|
+
node_display_class = base_class.get_from_node_display_registry(node_class)
|
12
|
+
except KeyError:
|
13
|
+
try:
|
14
|
+
return get_node_display_class(
|
15
|
+
base_class, node_class.__bases__[0], node_class if root_node_class is None else root_node_class
|
16
|
+
)
|
17
|
+
except IndexError:
|
18
|
+
return base_class
|
19
|
+
|
20
|
+
if not issubclass(node_display_class, base_class):
|
21
|
+
raise TypeError(
|
22
|
+
f"Expected to find a subclass of '{base_class.__name__}' for node class '{node_class.__name__}'"
|
23
|
+
)
|
24
|
+
|
25
|
+
return node_display_class
|
File without changes
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import pytest
|
2
|
+
from uuid import UUID
|
3
|
+
|
4
|
+
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
5
|
+
from vellum.workflows.nodes.bases import BaseNode
|
6
|
+
|
7
|
+
|
8
|
+
@pytest.fixture
|
9
|
+
def node_with_implicit_properties():
|
10
|
+
class MyNode(BaseNode):
|
11
|
+
pass
|
12
|
+
|
13
|
+
class MyNodeDisplay(BaseNodeDisplay[MyNode]):
|
14
|
+
pass
|
15
|
+
|
16
|
+
expected_id = UUID("ace7f746-4fe6-45c7-8207-fc8a4d0c7f6f")
|
17
|
+
|
18
|
+
return MyNode, MyNodeDisplay, expected_id
|
19
|
+
|
20
|
+
|
21
|
+
@pytest.fixture
|
22
|
+
def node_with_explicit_properties():
|
23
|
+
explicit_id = UUID("a422f67a-1d37-43f0-bdfc-1e4618c9496d")
|
24
|
+
|
25
|
+
class MyNode(BaseNode):
|
26
|
+
pass
|
27
|
+
|
28
|
+
class MyNodeDisplay(BaseNodeDisplay[MyNode]):
|
29
|
+
node_id = explicit_id
|
30
|
+
|
31
|
+
return MyNode, MyNodeDisplay, explicit_id
|
32
|
+
|
33
|
+
|
34
|
+
@pytest.fixture(
|
35
|
+
params=[
|
36
|
+
"node_with_implicit_properties",
|
37
|
+
"node_with_explicit_properties",
|
38
|
+
]
|
39
|
+
)
|
40
|
+
def node_info(request):
|
41
|
+
return request.getfixturevalue(request.param)
|
42
|
+
|
43
|
+
|
44
|
+
def test_get_id(node_info):
|
45
|
+
node, node_display, expected_id = node_info
|
46
|
+
|
47
|
+
assert node_display(node).node_id == expected_id
|
@@ -0,0 +1,18 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from uuid import UUID
|
3
|
+
|
4
|
+
|
5
|
+
@dataclass
|
6
|
+
class NodeOutputDisplay:
|
7
|
+
id: UUID
|
8
|
+
name: str
|
9
|
+
|
10
|
+
|
11
|
+
@dataclass
|
12
|
+
class PortDisplayOverrides:
|
13
|
+
id: UUID
|
14
|
+
|
15
|
+
|
16
|
+
@dataclass
|
17
|
+
class PortDisplay(PortDisplayOverrides):
|
18
|
+
node_id: UUID
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import re
|
2
|
+
from typing import Optional, TypeVar, Union, overload
|
3
|
+
|
4
|
+
from vellum.workflows.descriptors.base import BaseDescriptor
|
5
|
+
from vellum.workflows.references.node import NodeReference
|
6
|
+
|
7
|
+
_T = TypeVar("_T")
|
8
|
+
|
9
|
+
|
10
|
+
@overload
|
11
|
+
def raise_if_descriptor(node_attr: BaseDescriptor[_T]) -> _T: ...
|
12
|
+
|
13
|
+
|
14
|
+
@overload
|
15
|
+
def raise_if_descriptor(node_attr: _T) -> _T: ...
|
16
|
+
|
17
|
+
|
18
|
+
def raise_if_descriptor(node_attr: Union[NodeReference[_T], _T]) -> Optional[_T]:
|
19
|
+
if not isinstance(node_attr, NodeReference):
|
20
|
+
raise AttributeError(f"Expected to find a Node descriptor, but found '{node_attr.__class__.__name__}'")
|
21
|
+
|
22
|
+
return node_attr.instance
|
23
|
+
|
24
|
+
|
25
|
+
def to_kebab_case(string: str) -> str:
|
26
|
+
"""Converts a string from Capital Case to kebab-case."""
|
27
|
+
string = re.sub(r"(\s|_|-)+", " ", string)
|
28
|
+
string = re.sub(
|
29
|
+
r"[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+",
|
30
|
+
lambda mo: " " + mo.group(0).lower(),
|
31
|
+
string,
|
32
|
+
)
|
33
|
+
return "-".join(string.split())
|
@@ -0,0 +1,32 @@
|
|
1
|
+
from .api_node import BaseAPINodeDisplay
|
2
|
+
from .code_execution_node import BaseCodeExecutionNodeDisplay
|
3
|
+
from .conditional_node import BaseConditionalNodeDisplay
|
4
|
+
from .final_output_node import BaseFinalOutputNodeDisplay
|
5
|
+
from .guardrail_node import BaseGuardrailNodeDisplay
|
6
|
+
from .inline_prompt_node import BaseInlinePromptNodeDisplay
|
7
|
+
from .inline_subworkflow_node import BaseInlineSubworkflowNodeDisplay
|
8
|
+
from .map_node import BaseMapNodeDisplay
|
9
|
+
from .merge_node import BaseMergeNodeDisplay
|
10
|
+
from .prompt_deployment_node import BasePromptDeploymentNodeDisplay
|
11
|
+
from .search_node import BaseSearchNodeDisplay
|
12
|
+
from .subworkflow_deployment_node import BaseSubworkflowDeploymentNodeDisplay
|
13
|
+
from .templating_node import BaseTemplatingNodeDisplay
|
14
|
+
from .try_node import BaseTryNodeDisplay
|
15
|
+
|
16
|
+
# All node display classes must be imported here to be registered in BaseNodeDisplay's node display registry
|
17
|
+
__all__ = [
|
18
|
+
"BaseCodeExecutionNodeDisplay",
|
19
|
+
"BaseConditionalNodeDisplay",
|
20
|
+
"BaseGuardrailNodeDisplay",
|
21
|
+
"BaseInlinePromptNodeDisplay",
|
22
|
+
"BaseInlineSubworkflowNodeDisplay",
|
23
|
+
"BaseAPINodeDisplay",
|
24
|
+
"BaseMapNodeDisplay",
|
25
|
+
"BaseMergeNodeDisplay",
|
26
|
+
"BaseSearchNodeDisplay",
|
27
|
+
"BaseSubworkflowDeploymentNodeDisplay",
|
28
|
+
"BaseTemplatingNodeDisplay",
|
29
|
+
"BasePromptDeploymentNodeDisplay",
|
30
|
+
"BaseFinalOutputNodeDisplay",
|
31
|
+
"BaseTryNodeDisplay",
|
32
|
+
]
|