vellum-ai 1.2.2__py3-none-any.whl → 1.2.4__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 +40 -0
- vellum/client/core/client_wrapper.py +2 -2
- vellum/client/core/pydantic_utilities.py +3 -2
- vellum/client/reference.md +16 -0
- vellum/client/resources/workflow_executions/client.py +28 -4
- vellum/client/resources/workflow_executions/raw_client.py +32 -2
- vellum/client/types/__init__.py +40 -0
- vellum/client/types/audio_input_request.py +30 -0
- vellum/client/types/delimiter_chunker_config.py +20 -0
- vellum/client/types/delimiter_chunker_config_request.py +20 -0
- vellum/client/types/delimiter_chunking.py +21 -0
- vellum/client/types/delimiter_chunking_request.py +21 -0
- vellum/client/types/document_index_chunking.py +4 -1
- vellum/client/types/document_index_chunking_request.py +2 -1
- vellum/client/types/document_input_request.py +30 -0
- vellum/client/types/execution_audio_vellum_value.py +31 -0
- vellum/client/types/execution_document_vellum_value.py +31 -0
- vellum/client/types/execution_image_vellum_value.py +31 -0
- vellum/client/types/execution_vellum_value.py +8 -0
- vellum/client/types/execution_video_vellum_value.py +31 -0
- vellum/client/types/image_input_request.py +30 -0
- vellum/client/types/logical_operator.py +1 -0
- vellum/client/types/node_input_compiled_audio_value.py +23 -0
- vellum/client/types/node_input_compiled_document_value.py +23 -0
- vellum/client/types/node_input_compiled_image_value.py +23 -0
- vellum/client/types/node_input_compiled_video_value.py +23 -0
- vellum/client/types/node_input_variable_compiled_value.py +8 -0
- vellum/client/types/prompt_deployment_input_request.py +13 -1
- vellum/client/types/prompt_request_audio_input.py +26 -0
- vellum/client/types/prompt_request_document_input.py +26 -0
- vellum/client/types/prompt_request_image_input.py +26 -0
- vellum/client/types/prompt_request_input.py +13 -1
- vellum/client/types/prompt_request_video_input.py +26 -0
- vellum/client/types/video_input_request.py +30 -0
- vellum/types/audio_input_request.py +3 -0
- vellum/types/delimiter_chunker_config.py +3 -0
- vellum/types/delimiter_chunker_config_request.py +3 -0
- vellum/types/delimiter_chunking.py +3 -0
- vellum/types/delimiter_chunking_request.py +3 -0
- vellum/types/document_input_request.py +3 -0
- vellum/types/execution_audio_vellum_value.py +3 -0
- vellum/types/execution_document_vellum_value.py +3 -0
- vellum/types/execution_image_vellum_value.py +3 -0
- vellum/types/execution_video_vellum_value.py +3 -0
- vellum/types/image_input_request.py +3 -0
- vellum/types/node_input_compiled_audio_value.py +3 -0
- vellum/types/node_input_compiled_document_value.py +3 -0
- vellum/types/node_input_compiled_image_value.py +3 -0
- vellum/types/node_input_compiled_video_value.py +3 -0
- vellum/types/prompt_request_audio_input.py +3 -0
- vellum/types/prompt_request_document_input.py +3 -0
- vellum/types/prompt_request_image_input.py +3 -0
- vellum/types/prompt_request_video_input.py +3 -0
- vellum/types/video_input_request.py +3 -0
- vellum/workflows/context.py +27 -9
- vellum/workflows/events/context.py +53 -78
- vellum/workflows/events/node.py +5 -5
- vellum/workflows/events/relational_threads.py +41 -0
- vellum/workflows/events/tests/test_basic_workflow.py +50 -0
- vellum/workflows/events/tests/test_event.py +9 -0
- vellum/workflows/events/types.py +3 -1
- vellum/workflows/events/workflow.py +12 -1
- vellum/workflows/expressions/contains.py +7 -0
- vellum/workflows/expressions/tests/test_contains.py +175 -0
- vellum/workflows/graph/graph.py +52 -8
- vellum/workflows/graph/tests/test_graph.py +17 -0
- vellum/workflows/integrations/mcp_service.py +35 -5
- vellum/workflows/integrations/tests/test_mcp_service.py +120 -0
- vellum/workflows/nodes/core/error_node/node.py +4 -0
- vellum/workflows/nodes/core/map_node/node.py +7 -0
- vellum/workflows/nodes/core/map_node/tests/test_node.py +19 -0
- vellum/workflows/nodes/core/templating_node/node.py +3 -2
- vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py +129 -0
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/node.py +12 -0
- vellum/workflows/nodes/displayable/bases/inline_prompt_node/tests/test_inline_prompt_node.py +41 -0
- vellum/workflows/nodes/displayable/bases/utils.py +38 -1
- vellum/workflows/nodes/displayable/code_execution_node/utils.py +3 -20
- vellum/workflows/nodes/displayable/final_output_node/node.py +4 -0
- vellum/workflows/nodes/displayable/inline_prompt_node/node.py +3 -26
- vellum/workflows/nodes/displayable/prompt_deployment_node/node.py +3 -25
- vellum/workflows/nodes/displayable/subworkflow_deployment_node/node.py +1 -1
- vellum/workflows/nodes/utils.py +26 -1
- vellum/workflows/ports/node_ports.py +3 -0
- vellum/workflows/ports/port.py +7 -0
- vellum/workflows/state/context.py +35 -4
- vellum/workflows/types/definition.py +1 -0
- vellum/workflows/utils/functions.py +4 -0
- vellum/workflows/utils/tests/test_functions.py +6 -3
- vellum/workflows/utils/uuids.py +15 -0
- {vellum_ai-1.2.2.dist-info → vellum_ai-1.2.4.dist-info}/METADATA +1 -1
- {vellum_ai-1.2.2.dist-info → vellum_ai-1.2.4.dist-info}/RECORD +106 -60
- vellum_cli/__init__.py +6 -0
- vellum_cli/config.py +2 -0
- vellum_cli/push.py +3 -0
- vellum_cli/tests/test_pull.py +2 -0
- vellum_cli/tests/test_push.py +39 -0
- vellum_ee/workflows/display/nodes/vellum/error_node.py +1 -5
- vellum_ee/workflows/display/nodes/vellum/final_output_node.py +1 -5
- vellum_ee/workflows/display/nodes/vellum/tests/test_tool_calling_node.py +2 -0
- vellum_ee/workflows/display/tests/workflow_serialization/test_basic_tool_calling_node_mcp_serialization.py +1 -0
- vellum_ee/workflows/display/utils/events.py +24 -0
- vellum_ee/workflows/display/utils/tests/test_events.py +69 -0
- vellum_ee/workflows/tests/test_server.py +95 -0
- {vellum_ai-1.2.2.dist-info → vellum_ai-1.2.4.dist-info}/LICENSE +0 -0
- {vellum_ai-1.2.2.dist-info → vellum_ai-1.2.4.dist-info}/WHEEL +0 -0
- {vellum_ai-1.2.2.dist-info → vellum_ai-1.2.4.dist-info}/entry_points.txt +0 -0
vellum_cli/__init__.py
CHANGED
@@ -68,6 +68,7 @@ with the provided module or be available for use. The Workflow Sandbox must also
|
|
68
68
|
@click.option("--deployment-name", type=str, help="Unique name for the Deployment")
|
69
69
|
@click.option("--deployment-description", type=str, help="Description for the Deployment")
|
70
70
|
@click.option("--release-tag", help="Release Tag for the Deployment", multiple=True)
|
71
|
+
@click.option("--release-description", type=str, help="Description for the Release")
|
71
72
|
@click.option(
|
72
73
|
"--dry-run",
|
73
74
|
is_flag=True,
|
@@ -87,6 +88,7 @@ def workflows_push(
|
|
87
88
|
deployment_name: Optional[str],
|
88
89
|
deployment_description: Optional[str],
|
89
90
|
release_tag: Optional[List[str]],
|
91
|
+
release_description: Optional[str],
|
90
92
|
dry_run: Optional[bool],
|
91
93
|
strict: Optional[bool],
|
92
94
|
workspace: Optional[str],
|
@@ -104,6 +106,7 @@ def workflows_push(
|
|
104
106
|
deployment_name=deployment_name,
|
105
107
|
deployment_description=deployment_description,
|
106
108
|
release_tags=release_tag,
|
109
|
+
release_description=release_description,
|
107
110
|
dry_run=dry_run,
|
108
111
|
strict=strict,
|
109
112
|
workspace=workspace,
|
@@ -118,6 +121,7 @@ def workflows_push(
|
|
118
121
|
@click.option("--deployment-name", type=str, help="Unique name for the Deployment")
|
119
122
|
@click.option("--deployment-description", type=str, help="Description for the Deployment")
|
120
123
|
@click.option("--release-tag", help="Release Tag for the Deployment", multiple=True)
|
124
|
+
@click.option("--release-description", type=str, help="Description for the Release")
|
121
125
|
@click.option(
|
122
126
|
"--dry-run",
|
123
127
|
is_flag=True,
|
@@ -137,6 +141,7 @@ def push_module(
|
|
137
141
|
deployment_name: Optional[str],
|
138
142
|
deployment_description: Optional[str],
|
139
143
|
release_tag: Optional[List[str]],
|
144
|
+
release_description: Optional[str],
|
140
145
|
dry_run: Optional[bool],
|
141
146
|
strict: Optional[bool],
|
142
147
|
workspace: Optional[str],
|
@@ -152,6 +157,7 @@ def push_module(
|
|
152
157
|
deployment_name=deployment_name,
|
153
158
|
deployment_description=deployment_description,
|
154
159
|
release_tags=release_tag,
|
160
|
+
release_description=release_description,
|
155
161
|
dry_run=dry_run,
|
156
162
|
strict=strict,
|
157
163
|
workspace=workspace,
|
vellum_cli/config.py
CHANGED
@@ -36,6 +36,7 @@ class WorkflowDeploymentConfig(UniversalBaseModel):
|
|
36
36
|
name: Optional[str] = None
|
37
37
|
description: Optional[str] = None
|
38
38
|
release_tags: Optional[List[str]] = None
|
39
|
+
release_description: Optional[str] = None
|
39
40
|
|
40
41
|
def merge(self, other: "WorkflowDeploymentConfig") -> "WorkflowDeploymentConfig":
|
41
42
|
return WorkflowDeploymentConfig(
|
@@ -44,6 +45,7 @@ class WorkflowDeploymentConfig(UniversalBaseModel):
|
|
44
45
|
name=self.name or other.name,
|
45
46
|
description=self.description or other.description,
|
46
47
|
release_tags=self.release_tags or other.release_tags,
|
48
|
+
release_description=self.release_description or other.release_description,
|
47
49
|
)
|
48
50
|
|
49
51
|
|
vellum_cli/push.py
CHANGED
@@ -28,6 +28,7 @@ def push_command(
|
|
28
28
|
deployment_name: Optional[str] = None,
|
29
29
|
deployment_description: Optional[str] = None,
|
30
30
|
release_tags: Optional[List[str]] = None,
|
31
|
+
release_description: Optional[str] = None,
|
31
32
|
dry_run: Optional[bool] = None,
|
32
33
|
strict: Optional[bool] = None,
|
33
34
|
workspace: Optional[str] = None,
|
@@ -142,6 +143,7 @@ def push_command(
|
|
142
143
|
name=deployment_name or cli_deployment_config.name or to_kebab_case(module_name),
|
143
144
|
description=deployment_description or cli_deployment_config.description,
|
144
145
|
release_tags=release_tags or cli_deployment_config.release_tags,
|
146
|
+
release_description=release_description or cli_deployment_config.release_description,
|
145
147
|
)
|
146
148
|
except ValidationError as e:
|
147
149
|
for error in e.errors():
|
@@ -286,6 +288,7 @@ Visit at: {base_url}/workflow-sandboxes/{response.workflow_sandbox_id}"""
|
|
286
288
|
name=deployment_config.name if deploy else None,
|
287
289
|
description=deployment_config.description if deploy else None,
|
288
290
|
release_tags=deployment_config.release_tags if deploy else None,
|
291
|
+
release_description=getattr(deployment_config, "release_description", None) if deploy else None,
|
289
292
|
)
|
290
293
|
workflow_config.deployments.append(stored_deployment_config)
|
291
294
|
|
vellum_cli/tests/test_pull.py
CHANGED
@@ -393,6 +393,7 @@ def test_pull__workflow_deployment_with_no_config(vellum_client):
|
|
393
393
|
"name": "my-deployment",
|
394
394
|
"description": None,
|
395
395
|
"release_tags": None,
|
396
|
+
"release_description": None,
|
396
397
|
}
|
397
398
|
],
|
398
399
|
"container_image_tag": None,
|
@@ -641,6 +642,7 @@ def test_pull__sandbox_id_with_other_workflow_deployment_in_lock(vellum_client,
|
|
641
642
|
"name": None,
|
642
643
|
"description": None,
|
643
644
|
"release_tags": None,
|
645
|
+
"release_description": None,
|
644
646
|
},
|
645
647
|
],
|
646
648
|
"container_image_name": None,
|
vellum_cli/tests/test_push.py
CHANGED
@@ -1042,6 +1042,45 @@ def test_push__deploy_with_release_tags_success(mock_module, vellum_client):
|
|
1042
1042
|
assert "Updated vellum.lock.json file." in result.output
|
1043
1043
|
|
1044
1044
|
|
1045
|
+
@pytest.mark.usefixtures("info_log_level")
|
1046
|
+
def test_push__deploy_with_release_description_success(mock_module, vellum_client):
|
1047
|
+
# GIVEN a single workflow configured
|
1048
|
+
temp_dir = mock_module.temp_dir
|
1049
|
+
module = mock_module.module
|
1050
|
+
|
1051
|
+
# AND a workflow exists in the module successfully
|
1052
|
+
_ensure_workflow_py(temp_dir, module)
|
1053
|
+
|
1054
|
+
# AND the push API call returns successfully
|
1055
|
+
workflow_deployment_id = str(uuid4())
|
1056
|
+
vellum_client.workflows.push.return_value = WorkflowPushResponse(
|
1057
|
+
workflow_sandbox_id=str(uuid4()),
|
1058
|
+
workflow_deployment_id=workflow_deployment_id,
|
1059
|
+
)
|
1060
|
+
|
1061
|
+
# WHEN calling `vellum workflows push` with --deploy and --release-description
|
1062
|
+
runner = CliRunner()
|
1063
|
+
result = runner.invoke(
|
1064
|
+
cli_main, ["workflows", "push", module, "--deploy", "--release-description", "This is a test release"]
|
1065
|
+
)
|
1066
|
+
|
1067
|
+
# THEN it should succeed
|
1068
|
+
assert result.exit_code == 0, result.output
|
1069
|
+
|
1070
|
+
# AND we should have called the push API with the correct deployment config
|
1071
|
+
vellum_client.workflows.push.assert_called_once()
|
1072
|
+
call_args = vellum_client.workflows.push.call_args.kwargs
|
1073
|
+
|
1074
|
+
# AND the deployment_config should contain the release description
|
1075
|
+
deployment_config_str = call_args["deployment_config"]
|
1076
|
+
deployment_config = json.loads(deployment_config_str)
|
1077
|
+
assert deployment_config["release_description"] == "This is a test release"
|
1078
|
+
|
1079
|
+
# AND should show success message
|
1080
|
+
assert "Successfully pushed" in result.output
|
1081
|
+
assert "Updated vellum.lock.json file." in result.output
|
1082
|
+
|
1083
|
+
|
1045
1084
|
def test_push__deploy_stores_deployment_config_in_lock_file(mock_module, vellum_client):
|
1046
1085
|
# GIVEN a single workflow
|
1047
1086
|
temp_dir = mock_module.temp_dir
|
@@ -2,7 +2,7 @@ from uuid import UUID
|
|
2
2
|
from typing import Any, ClassVar, Generic, Optional, TypeVar
|
3
3
|
|
4
4
|
from vellum.workflows.nodes import ErrorNode
|
5
|
-
from vellum.workflows.types.core import
|
5
|
+
from vellum.workflows.types.core import JsonObject
|
6
6
|
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
7
7
|
from vellum_ee.workflows.display.nodes.utils import raise_if_descriptor
|
8
8
|
from vellum_ee.workflows.display.nodes.vellum.utils import create_node_input
|
@@ -20,10 +20,6 @@ class BaseErrorNodeDisplay(BaseNodeDisplay[_ErrorNodeType], Generic[_ErrorNodeTy
|
|
20
20
|
|
21
21
|
__serializable_inputs__ = {ErrorNode.error}
|
22
22
|
|
23
|
-
def serialize_ports(self, display_context: "WorkflowDisplayContext") -> JsonArray:
|
24
|
-
"""Error nodes have no ports."""
|
25
|
-
return []
|
26
|
-
|
27
23
|
def serialize(self, display_context: WorkflowDisplayContext, **_kwargs) -> JsonObject:
|
28
24
|
node_id = self.node_id
|
29
25
|
error_source_input_id = self.node_input_ids_by_name.get(
|
@@ -2,7 +2,7 @@ from uuid import UUID
|
|
2
2
|
from typing import ClassVar, Generic, Optional, TypeVar
|
3
3
|
|
4
4
|
from vellum.workflows.nodes.displayable.final_output_node import FinalOutputNode
|
5
|
-
from vellum.workflows.types.core import
|
5
|
+
from vellum.workflows.types.core import JsonObject
|
6
6
|
from vellum.workflows.utils.uuids import uuid4_from_hash
|
7
7
|
from vellum_ee.workflows.display.nodes.base_node_display import BaseNodeDisplay
|
8
8
|
from vellum_ee.workflows.display.nodes.utils import to_kebab_case
|
@@ -19,10 +19,6 @@ NODE_INPUT_KEY = "node_input"
|
|
19
19
|
class BaseFinalOutputNodeDisplay(BaseNodeDisplay[_FinalOutputNodeType], Generic[_FinalOutputNodeType]):
|
20
20
|
output_name: ClassVar[Optional[str]] = None
|
21
21
|
|
22
|
-
def serialize_ports(self, display_context: "WorkflowDisplayContext") -> JsonArray:
|
23
|
-
"""Final output nodes have no ports."""
|
24
|
-
return []
|
25
|
-
|
26
22
|
def serialize(self, display_context: WorkflowDisplayContext, **_kwargs) -> JsonObject:
|
27
23
|
node = self._node
|
28
24
|
node_id = self.node_id
|
@@ -191,6 +191,7 @@ def test_serialize_node__tool_calling_node__mcp_server_api_key():
|
|
191
191
|
{
|
192
192
|
"type": "MCP_SERVER",
|
193
193
|
"name": "my-mcp-server",
|
194
|
+
"description": "",
|
194
195
|
"url": "https://my-mcp-server.com",
|
195
196
|
"authorization_type": "API_KEY",
|
196
197
|
"bearer_token_value": None,
|
@@ -243,6 +244,7 @@ def test_serialize_node__tool_calling_node__mcp_server_no_authorization():
|
|
243
244
|
{
|
244
245
|
"type": "MCP_SERVER",
|
245
246
|
"name": "my-mcp-server",
|
247
|
+
"description": "",
|
246
248
|
"url": "https://my-mcp-server.com",
|
247
249
|
"authorization_type": None,
|
248
250
|
"bearer_token_value": None,
|
@@ -0,0 +1,24 @@
|
|
1
|
+
from vellum.workflows.events.workflow import WorkflowExecutionInitiatedEvent
|
2
|
+
from vellum_ee.workflows.display.utils.registry import (
|
3
|
+
get_parent_display_context_from_event,
|
4
|
+
register_workflow_display_class,
|
5
|
+
register_workflow_display_context,
|
6
|
+
)
|
7
|
+
from vellum_ee.workflows.display.workflows.get_vellum_workflow_display_class import get_workflow_display
|
8
|
+
|
9
|
+
|
10
|
+
def event_enricher(event: WorkflowExecutionInitiatedEvent) -> WorkflowExecutionInitiatedEvent:
|
11
|
+
workflow_definition = event.body.workflow_definition
|
12
|
+
workflow_display = get_workflow_display(
|
13
|
+
workflow_class=workflow_definition,
|
14
|
+
parent_display_context=get_parent_display_context_from_event(event),
|
15
|
+
dry_run=True,
|
16
|
+
)
|
17
|
+
register_workflow_display_context(event.span_id, workflow_display.display_context)
|
18
|
+
|
19
|
+
if event.body.workflow_definition.is_dynamic:
|
20
|
+
register_workflow_display_class(workflow_definition, workflow_display.__class__)
|
21
|
+
workflow_version_exec_config = workflow_display.serialize()
|
22
|
+
setattr(event.body, "workflow_version_exec_config", workflow_version_exec_config)
|
23
|
+
|
24
|
+
return event
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import pytest
|
2
|
+
from uuid import uuid4
|
3
|
+
from typing import Optional
|
4
|
+
|
5
|
+
from vellum.workflows.events.workflow import WorkflowExecutionInitiatedBody, WorkflowExecutionInitiatedEvent
|
6
|
+
from vellum.workflows.inputs.base import BaseInputs
|
7
|
+
from vellum.workflows.workflows.base import BaseWorkflow
|
8
|
+
from vellum_ee.workflows.display.utils.events import event_enricher
|
9
|
+
|
10
|
+
|
11
|
+
@pytest.mark.parametrize(
|
12
|
+
"is_dynamic,expected_config",
|
13
|
+
[
|
14
|
+
(False, None),
|
15
|
+
(
|
16
|
+
True,
|
17
|
+
{
|
18
|
+
"workflow_raw_data": {
|
19
|
+
"nodes": [
|
20
|
+
{
|
21
|
+
"id": "86607b18-7872-49f3-a592-fda1428f70aa",
|
22
|
+
"type": "ENTRYPOINT",
|
23
|
+
"inputs": [],
|
24
|
+
"data": {
|
25
|
+
"label": "Entrypoint Node",
|
26
|
+
"source_handle_id": "d1fe8f4c-53d7-43a0-b210-73ebdc60bf57",
|
27
|
+
},
|
28
|
+
"display_data": {"position": {"x": 0.0, "y": -50.0}},
|
29
|
+
"base": None,
|
30
|
+
"definition": None,
|
31
|
+
}
|
32
|
+
],
|
33
|
+
"edges": [],
|
34
|
+
"display_data": {"viewport": {"x": 0.0, "y": 0.0, "zoom": 1.0}},
|
35
|
+
"definition": {
|
36
|
+
"name": "TestWorkflow",
|
37
|
+
"module": ["vellum_ee", "workflows", "display", "utils", "tests", "test_events"],
|
38
|
+
},
|
39
|
+
"output_values": [],
|
40
|
+
},
|
41
|
+
"input_variables": [],
|
42
|
+
"state_variables": [],
|
43
|
+
"output_variables": [],
|
44
|
+
},
|
45
|
+
),
|
46
|
+
],
|
47
|
+
)
|
48
|
+
def test_event_enricher_static_workflow(is_dynamic: bool, expected_config: Optional[dict]):
|
49
|
+
"""Test event_enricher with a static workflow (is_dynamic=False)."""
|
50
|
+
# GIVEN a workflow class with the specified is_dynamic value
|
51
|
+
_is_dynamic = is_dynamic
|
52
|
+
|
53
|
+
class TestWorkflow(BaseWorkflow):
|
54
|
+
is_dynamic = _is_dynamic
|
55
|
+
|
56
|
+
event: WorkflowExecutionInitiatedEvent = WorkflowExecutionInitiatedEvent(
|
57
|
+
trace_id=uuid4(),
|
58
|
+
span_id=uuid4(),
|
59
|
+
body=WorkflowExecutionInitiatedBody(
|
60
|
+
workflow_definition=TestWorkflow,
|
61
|
+
inputs=BaseInputs(),
|
62
|
+
),
|
63
|
+
)
|
64
|
+
|
65
|
+
# WHEN the event_enricher is called with mocked dependencies
|
66
|
+
event_enricher(event)
|
67
|
+
|
68
|
+
# AND workflow_version_exec_config is set to the expected config
|
69
|
+
assert event.body.workflow_version_exec_config == expected_config
|
@@ -8,6 +8,7 @@ from vellum.client.types.number_vellum_value import NumberVellumValue
|
|
8
8
|
from vellum.workflows import BaseWorkflow
|
9
9
|
from vellum.workflows.nodes import BaseNode
|
10
10
|
from vellum.workflows.state.context import WorkflowContext
|
11
|
+
from vellum.workflows.utils.uuids import generate_workflow_deployment_prefix
|
11
12
|
from vellum_ee.workflows.display.workflows.base_workflow_display import BaseWorkflowDisplay
|
12
13
|
from vellum_ee.workflows.server.virtual_file_loader import VirtualFileFinder
|
13
14
|
|
@@ -566,3 +567,97 @@ class Workflow(BaseWorkflow[Inputs, BaseState]):
|
|
566
567
|
|
567
568
|
# THEN the serialization should complete successfully
|
568
569
|
assert result is not None
|
570
|
+
|
571
|
+
|
572
|
+
def test_resolve_workflow_deployment__returns_workflow_with_generated_files():
|
573
|
+
"""
|
574
|
+
Test that resolve_workflow_deployment returns a workflow with artifacts
|
575
|
+
in generated_files using the correct prefix format.
|
576
|
+
"""
|
577
|
+
# GIVEN a deployment name and release tag
|
578
|
+
deployment_name = "test_deployment"
|
579
|
+
release_tag = "LATEST"
|
580
|
+
|
581
|
+
expected_prefix = generate_workflow_deployment_prefix(deployment_name, release_tag)
|
582
|
+
|
583
|
+
# Create a simple test node for the resolved workflow
|
584
|
+
test_node_code = """
|
585
|
+
from vellum.workflows.nodes.bases.base import BaseNode
|
586
|
+
from vellum.workflows.outputs import BaseOutputs
|
587
|
+
|
588
|
+
class TestNode(BaseNode):
|
589
|
+
template = "Hello"
|
590
|
+
|
591
|
+
class Outputs(BaseOutputs):
|
592
|
+
result: str
|
593
|
+
|
594
|
+
def run(self):
|
595
|
+
return self.Outputs(result="Hello, {template}")
|
596
|
+
"""
|
597
|
+
|
598
|
+
mock_workflow_code = """
|
599
|
+
from vellum.workflows import BaseWorkflow
|
600
|
+
from .nodes.test_node import TestNode
|
601
|
+
|
602
|
+
class ResolvedWorkflow(BaseWorkflow):
|
603
|
+
graph = TestNode
|
604
|
+
"""
|
605
|
+
|
606
|
+
# Create parent workflow files that reference the subworkflow deployment
|
607
|
+
parent_workflow_code = """
|
608
|
+
from vellum.workflows import BaseWorkflow
|
609
|
+
from .nodes.subworkflow_deployment_node import TestSubworkflowDeploymentNode
|
610
|
+
|
611
|
+
class ParentWorkflow(BaseWorkflow):
|
612
|
+
graph = TestSubworkflowDeploymentNode
|
613
|
+
"""
|
614
|
+
|
615
|
+
parent_node_code = """
|
616
|
+
from vellum.workflows.nodes import SubworkflowDeploymentNode
|
617
|
+
from vellum.workflows.outputs import BaseOutputs
|
618
|
+
|
619
|
+
class TestSubworkflowDeploymentNode(SubworkflowDeploymentNode):
|
620
|
+
deployment = "test_deployment"
|
621
|
+
|
622
|
+
class Outputs(BaseOutputs):
|
623
|
+
result: str
|
624
|
+
|
625
|
+
subworkflow_inputs = {"message": "test"}
|
626
|
+
"""
|
627
|
+
|
628
|
+
files = {
|
629
|
+
"__init__.py": "",
|
630
|
+
"workflow.py": parent_workflow_code,
|
631
|
+
"nodes/__init__.py": """
|
632
|
+
from .subworkflow_deployment_node import TestSubworkflowDeploymentNode
|
633
|
+
|
634
|
+
__all__ = ["TestSubworkflowDeploymentNode"]
|
635
|
+
""",
|
636
|
+
"nodes/subworkflow_deployment_node.py": parent_node_code,
|
637
|
+
f"{expected_prefix}/__init__.py": "",
|
638
|
+
f"{expected_prefix}/workflow.py": mock_workflow_code,
|
639
|
+
f"{expected_prefix}/nodes/__init__.py": """
|
640
|
+
from .test_node import TestNode
|
641
|
+
|
642
|
+
__all__ = ["TestNode"]
|
643
|
+
""",
|
644
|
+
f"{expected_prefix}/nodes/test_node.py": test_node_code,
|
645
|
+
}
|
646
|
+
|
647
|
+
namespace = str(uuid4())
|
648
|
+
|
649
|
+
# AND the virtual file loader is registered
|
650
|
+
finder = VirtualFileFinder(files, namespace)
|
651
|
+
sys.meta_path.append(finder)
|
652
|
+
|
653
|
+
# WHEN we execute the root workflow
|
654
|
+
Workflow = BaseWorkflow.load_from_module(namespace)
|
655
|
+
workflow = Workflow(context=WorkflowContext(generated_files=files, namespace=namespace))
|
656
|
+
|
657
|
+
# THEN the workflow should be successfully initialized
|
658
|
+
assert workflow
|
659
|
+
|
660
|
+
event = workflow.run()
|
661
|
+
|
662
|
+
# AND the method should return a workflow (not None) - this will pass once implemented
|
663
|
+
assert event.name == "workflow.execution.fulfilled"
|
File without changes
|
File without changes
|
File without changes
|