vellum-ai 0.14.33__py3-none-any.whl → 0.14.35__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 +2 -0
 - vellum/client/core/client_wrapper.py +1 -1
 - vellum/client/types/__init__.py +2 -0
 - vellum/client/types/workflow_deployment_release.py +8 -0
 - vellum/client/types/workflow_deployment_release_workflow_deployment.py +19 -0
 - vellum/client/types/workflow_deployment_release_workflow_version.py +10 -1
 - vellum/types/workflow_deployment_release_workflow_deployment.py +3 -0
 - vellum/workflows/nodes/core/inline_subworkflow_node/node.py +1 -3
 - vellum/workflows/nodes/core/map_node/node.py +1 -3
 - vellum/workflows/nodes/core/retry_node/node.py +1 -3
 - vellum/workflows/nodes/core/try_node/node.py +1 -3
 - vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +4 -1
 - vellum/workflows/state/context.py +4 -0
 - {vellum_ai-0.14.33.dist-info → vellum_ai-0.14.35.dist-info}/METADATA +1 -1
 - {vellum_ai-0.14.33.dist-info → vellum_ai-0.14.35.dist-info}/RECORD +21 -19
 - vellum_cli/pull.py +45 -1
 - vellum_cli/tests/test_pull.py +324 -2
 - vellum_ee/workflows/tests/test_server.py +356 -2
 - {vellum_ai-0.14.33.dist-info → vellum_ai-0.14.35.dist-info}/LICENSE +0 -0
 - {vellum_ai-0.14.33.dist-info → vellum_ai-0.14.35.dist-info}/WHEEL +0 -0
 - {vellum_ai-0.14.33.dist-info → vellum_ai-0.14.35.dist-info}/entry_points.txt +0 -0
 
    
        vellum/__init__.py
    CHANGED
    
    | 
         @@ -507,6 +507,7 @@ from .types import ( 
     | 
|
| 
       507 
507 
     | 
    
         
             
                WorkflowDeploymentParentContext,
         
     | 
| 
       508 
508 
     | 
    
         
             
                WorkflowDeploymentRead,
         
     | 
| 
       509 
509 
     | 
    
         
             
                WorkflowDeploymentRelease,
         
     | 
| 
      
 510 
     | 
    
         
            +
                WorkflowDeploymentReleaseWorkflowDeployment,
         
     | 
| 
       510 
511 
     | 
    
         
             
                WorkflowDeploymentReleaseWorkflowVersion,
         
     | 
| 
       511 
512 
     | 
    
         
             
                WorkflowError,
         
     | 
| 
       512 
513 
     | 
    
         
             
                WorkflowEventDisplayContext,
         
     | 
| 
         @@ -1130,6 +1131,7 @@ __all__ = [ 
     | 
|
| 
       1130 
1131 
     | 
    
         
             
                "WorkflowDeploymentParentContext",
         
     | 
| 
       1131 
1132 
     | 
    
         
             
                "WorkflowDeploymentRead",
         
     | 
| 
       1132 
1133 
     | 
    
         
             
                "WorkflowDeploymentRelease",
         
     | 
| 
      
 1134 
     | 
    
         
            +
                "WorkflowDeploymentReleaseWorkflowDeployment",
         
     | 
| 
       1133 
1135 
     | 
    
         
             
                "WorkflowDeploymentReleaseWorkflowVersion",
         
     | 
| 
       1134 
1136 
     | 
    
         
             
                "WorkflowDeploymentsListRequestStatus",
         
     | 
| 
       1135 
1137 
     | 
    
         
             
                "WorkflowError",
         
     | 
| 
         @@ -18,7 +18,7 @@ class BaseClientWrapper: 
     | 
|
| 
       18 
18 
     | 
    
         
             
                    headers: typing.Dict[str, str] = {
         
     | 
| 
       19 
19 
     | 
    
         
             
                        "X-Fern-Language": "Python",
         
     | 
| 
       20 
20 
     | 
    
         
             
                        "X-Fern-SDK-Name": "vellum-ai",
         
     | 
| 
       21 
     | 
    
         
            -
                        "X-Fern-SDK-Version": "0.14. 
     | 
| 
      
 21 
     | 
    
         
            +
                        "X-Fern-SDK-Version": "0.14.35",
         
     | 
| 
       22 
22 
     | 
    
         
             
                    }
         
     | 
| 
       23 
23 
     | 
    
         
             
                    headers["X_API_KEY"] = self.api_key
         
     | 
| 
       24 
24 
     | 
    
         
             
                    return headers
         
     | 
    
        vellum/client/types/__init__.py
    CHANGED
    
    | 
         @@ -531,6 +531,7 @@ from .workflow_deployment_history_item import WorkflowDeploymentHistoryItem 
     | 
|
| 
       531 
531 
     | 
    
         
             
            from .workflow_deployment_parent_context import WorkflowDeploymentParentContext
         
     | 
| 
       532 
532 
     | 
    
         
             
            from .workflow_deployment_read import WorkflowDeploymentRead
         
     | 
| 
       533 
533 
     | 
    
         
             
            from .workflow_deployment_release import WorkflowDeploymentRelease
         
     | 
| 
      
 534 
     | 
    
         
            +
            from .workflow_deployment_release_workflow_deployment import WorkflowDeploymentReleaseWorkflowDeployment
         
     | 
| 
       534 
535 
     | 
    
         
             
            from .workflow_deployment_release_workflow_version import WorkflowDeploymentReleaseWorkflowVersion
         
     | 
| 
       535 
536 
     | 
    
         
             
            from .workflow_error import WorkflowError
         
     | 
| 
       536 
537 
     | 
    
         
             
            from .workflow_event_display_context import WorkflowEventDisplayContext
         
     | 
| 
         @@ -1108,6 +1109,7 @@ __all__ = [ 
     | 
|
| 
       1108 
1109 
     | 
    
         
             
                "WorkflowDeploymentParentContext",
         
     | 
| 
       1109 
1110 
     | 
    
         
             
                "WorkflowDeploymentRead",
         
     | 
| 
       1110 
1111 
     | 
    
         
             
                "WorkflowDeploymentRelease",
         
     | 
| 
      
 1112 
     | 
    
         
            +
                "WorkflowDeploymentReleaseWorkflowDeployment",
         
     | 
| 
       1111 
1113 
     | 
    
         
             
                "WorkflowDeploymentReleaseWorkflowVersion",
         
     | 
| 
       1112 
1114 
     | 
    
         
             
                "WorkflowError",
         
     | 
| 
       1113 
1115 
     | 
    
         
             
                "WorkflowEventDisplayContext",
         
     | 
| 
         @@ -1,15 +1,19 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # This file was auto-generated by Fern from our API Definition.
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            from __future__ import annotations
         
     | 
| 
       3 
4 
     | 
    
         
             
            from ..core.pydantic_utilities import UniversalBaseModel
         
     | 
| 
      
 5 
     | 
    
         
            +
            from .array_vellum_value import ArrayVellumValue
         
     | 
| 
       4 
6 
     | 
    
         
             
            import datetime as dt
         
     | 
| 
       5 
7 
     | 
    
         
             
            from .release_environment import ReleaseEnvironment
         
     | 
| 
       6 
8 
     | 
    
         
             
            import typing
         
     | 
| 
       7 
9 
     | 
    
         
             
            from .release_created_by import ReleaseCreatedBy
         
     | 
| 
       8 
10 
     | 
    
         
             
            from .workflow_deployment_release_workflow_version import WorkflowDeploymentReleaseWorkflowVersion
         
     | 
| 
      
 11 
     | 
    
         
            +
            from .workflow_deployment_release_workflow_deployment import WorkflowDeploymentReleaseWorkflowDeployment
         
     | 
| 
       9 
12 
     | 
    
         
             
            from .release_release_tag import ReleaseReleaseTag
         
     | 
| 
       10 
13 
     | 
    
         
             
            from .slim_release_review import SlimReleaseReview
         
     | 
| 
       11 
14 
     | 
    
         
             
            from ..core.pydantic_utilities import IS_PYDANTIC_V2
         
     | 
| 
       12 
15 
     | 
    
         
             
            import pydantic
         
     | 
| 
      
 16 
     | 
    
         
            +
            from ..core.pydantic_utilities import update_forward_refs
         
     | 
| 
       13 
17 
     | 
    
         | 
| 
       14 
18 
     | 
    
         | 
| 
       15 
19 
     | 
    
         
             
            class WorkflowDeploymentRelease(UniversalBaseModel):
         
     | 
| 
         @@ -18,6 +22,7 @@ class WorkflowDeploymentRelease(UniversalBaseModel): 
     | 
|
| 
       18 
22 
     | 
    
         
             
                environment: ReleaseEnvironment
         
     | 
| 
       19 
23 
     | 
    
         
             
                created_by: typing.Optional[ReleaseCreatedBy] = None
         
     | 
| 
       20 
24 
     | 
    
         
             
                workflow_version: WorkflowDeploymentReleaseWorkflowVersion
         
     | 
| 
      
 25 
     | 
    
         
            +
                deployment: WorkflowDeploymentReleaseWorkflowDeployment
         
     | 
| 
       21 
26 
     | 
    
         
             
                description: typing.Optional[str] = None
         
     | 
| 
       22 
27 
     | 
    
         
             
                release_tags: typing.List[ReleaseReleaseTag]
         
     | 
| 
       23 
28 
     | 
    
         
             
                reviews: typing.List[SlimReleaseReview]
         
     | 
| 
         @@ -30,3 +35,6 @@ class WorkflowDeploymentRelease(UniversalBaseModel): 
     | 
|
| 
       30 
35 
     | 
    
         
             
                        frozen = True
         
     | 
| 
       31 
36 
     | 
    
         
             
                        smart_union = True
         
     | 
| 
       32 
37 
     | 
    
         
             
                        extra = pydantic.Extra.allow
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            update_forward_refs(ArrayVellumValue, WorkflowDeploymentRelease=WorkflowDeploymentRelease)
         
     | 
| 
         @@ -0,0 +1,19 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # This file was auto-generated by Fern from our API Definition.
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            from ..core.pydantic_utilities import UniversalBaseModel
         
     | 
| 
      
 4 
     | 
    
         
            +
            from ..core.pydantic_utilities import IS_PYDANTIC_V2
         
     | 
| 
      
 5 
     | 
    
         
            +
            import typing
         
     | 
| 
      
 6 
     | 
    
         
            +
            import pydantic
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            class WorkflowDeploymentReleaseWorkflowDeployment(UniversalBaseModel):
         
     | 
| 
      
 10 
     | 
    
         
            +
                name: str
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                if IS_PYDANTIC_V2:
         
     | 
| 
      
 13 
     | 
    
         
            +
                    model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True)  # type: ignore # Pydantic v2
         
     | 
| 
      
 14 
     | 
    
         
            +
                else:
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    class Config:
         
     | 
| 
      
 17 
     | 
    
         
            +
                        frozen = True
         
     | 
| 
      
 18 
     | 
    
         
            +
                        smart_union = True
         
     | 
| 
      
 19 
     | 
    
         
            +
                        extra = pydantic.Extra.allow
         
     | 
| 
         @@ -1,13 +1,19 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # This file was auto-generated by Fern from our API Definition.
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            from __future__ import annotations
         
     | 
| 
       3 
4 
     | 
    
         
             
            from ..core.pydantic_utilities import UniversalBaseModel
         
     | 
| 
       4 
     | 
    
         
            -
            from  
     | 
| 
      
 5 
     | 
    
         
            +
            from .array_vellum_value import ArrayVellumValue
         
     | 
| 
       5 
6 
     | 
    
         
             
            import typing
         
     | 
| 
      
 7 
     | 
    
         
            +
            from .vellum_variable import VellumVariable
         
     | 
| 
      
 8 
     | 
    
         
            +
            from ..core.pydantic_utilities import IS_PYDANTIC_V2
         
     | 
| 
       6 
9 
     | 
    
         
             
            import pydantic
         
     | 
| 
      
 10 
     | 
    
         
            +
            from ..core.pydantic_utilities import update_forward_refs
         
     | 
| 
       7 
11 
     | 
    
         | 
| 
       8 
12 
     | 
    
         | 
| 
       9 
13 
     | 
    
         
             
            class WorkflowDeploymentReleaseWorkflowVersion(UniversalBaseModel):
         
     | 
| 
       10 
14 
     | 
    
         
             
                id: str
         
     | 
| 
      
 15 
     | 
    
         
            +
                input_variables: typing.List[VellumVariable]
         
     | 
| 
      
 16 
     | 
    
         
            +
                output_variables: typing.List[VellumVariable]
         
     | 
| 
       11 
17 
     | 
    
         | 
| 
       12 
18 
     | 
    
         
             
                if IS_PYDANTIC_V2:
         
     | 
| 
       13 
19 
     | 
    
         
             
                    model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True)  # type: ignore # Pydantic v2
         
     | 
| 
         @@ -17,3 +23,6 @@ class WorkflowDeploymentReleaseWorkflowVersion(UniversalBaseModel): 
     | 
|
| 
       17 
23 
     | 
    
         
             
                        frozen = True
         
     | 
| 
       18 
24 
     | 
    
         
             
                        smart_union = True
         
     | 
| 
       19 
25 
     | 
    
         
             
                        extra = pydantic.Extra.allow
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            update_forward_refs(ArrayVellumValue, WorkflowDeploymentReleaseWorkflowVersion=WorkflowDeploymentReleaseWorkflowVersion)
         
     | 
| 
         @@ -75,9 +75,7 @@ class InlineSubworkflowNode( 
     | 
|
| 
       75 
75 
     | 
    
         
             
                    with execution_context(parent_context=get_parent_context()):
         
     | 
| 
       76 
76 
     | 
    
         
             
                        subworkflow = self.subworkflow(
         
     | 
| 
       77 
77 
     | 
    
         
             
                            parent_state=self.state,
         
     | 
| 
       78 
     | 
    
         
            -
                            context=WorkflowContext(
         
     | 
| 
       79 
     | 
    
         
            -
                                vellum_client=self._context.vellum_client, generated_files=self._context.generated_files
         
     | 
| 
       80 
     | 
    
         
            -
                            ),
         
     | 
| 
      
 78 
     | 
    
         
            +
                            context=WorkflowContext.create_from(self._context),
         
     | 
| 
       81 
79 
     | 
    
         
             
                        )
         
     | 
| 
       82 
80 
     | 
    
         
             
                        subworkflow_stream = subworkflow.stream(
         
     | 
| 
       83 
81 
     | 
    
         
             
                            inputs=self._compile_subworkflow_inputs(),
         
     | 
| 
         @@ -171,9 +171,7 @@ class MapNode(BaseAdornmentNode[StateType], Generic[StateType, MapNodeItemType]) 
     | 
|
| 
       171 
171 
     | 
    
         
             
                        self._run_subworkflow(item=item, index=index)
         
     | 
| 
       172 
172 
     | 
    
         | 
| 
       173 
173 
     | 
    
         
             
                def _run_subworkflow(self, *, item: MapNodeItemType, index: int) -> None:
         
     | 
| 
       174 
     | 
    
         
            -
                    context = WorkflowContext(
         
     | 
| 
       175 
     | 
    
         
            -
                        vellum_client=self._context.vellum_client, generated_files=self._context.generated_files
         
     | 
| 
       176 
     | 
    
         
            -
                    )
         
     | 
| 
      
 174 
     | 
    
         
            +
                    context = WorkflowContext.create_from(self._context)
         
     | 
| 
       177 
175 
     | 
    
         
             
                    subworkflow = self.subworkflow(
         
     | 
| 
       178 
176 
     | 
    
         
             
                        parent_state=self.state,
         
     | 
| 
       179 
177 
     | 
    
         
             
                        context=context,
         
     | 
| 
         @@ -45,9 +45,7 @@ class RetryNode(BaseAdornmentNode[StateType], Generic[StateType]): 
     | 
|
| 
       45 
45 
     | 
    
         
             
                        with execution_context(parent_context=parent_context):
         
     | 
| 
       46 
46 
     | 
    
         
             
                            subworkflow = self.subworkflow(
         
     | 
| 
       47 
47 
     | 
    
         
             
                                parent_state=self.state,
         
     | 
| 
       48 
     | 
    
         
            -
                                context=WorkflowContext(
         
     | 
| 
       49 
     | 
    
         
            -
                                    vellum_client=self._context.vellum_client, generated_files=self._context.generated_files
         
     | 
| 
       50 
     | 
    
         
            -
                                ),
         
     | 
| 
      
 48 
     | 
    
         
            +
                                context=WorkflowContext.create_from(self._context),
         
     | 
| 
       51 
49 
     | 
    
         
             
                            )
         
     | 
| 
       52 
50 
     | 
    
         
             
                            subworkflow_stream = subworkflow.stream(
         
     | 
| 
       53 
51 
     | 
    
         
             
                                inputs=self.SubworkflowInputs(attempt_number=attempt_number),
         
     | 
| 
         @@ -32,9 +32,7 @@ class TryNode(BaseAdornmentNode[StateType], Generic[StateType]): 
     | 
|
| 
       32 
32 
     | 
    
         
             
                    with execution_context(parent_context=parent_context):
         
     | 
| 
       33 
33 
     | 
    
         
             
                        subworkflow = self.subworkflow(
         
     | 
| 
       34 
34 
     | 
    
         
             
                            parent_state=self.state,
         
     | 
| 
       35 
     | 
    
         
            -
                            context=WorkflowContext(
         
     | 
| 
       36 
     | 
    
         
            -
                                vellum_client=self._context.vellum_client, generated_files=self._context.generated_files
         
     | 
| 
       37 
     | 
    
         
            -
                            ),
         
     | 
| 
      
 35 
     | 
    
         
            +
                            context=WorkflowContext.create_from(self._context),
         
     | 
| 
       38 
36 
     | 
    
         
             
                        )
         
     | 
| 
       39 
37 
     | 
    
         
             
                        subworkflow_stream = subworkflow.stream(
         
     | 
| 
       40 
38 
     | 
    
         
             
                            event_filter=all_workflow_event_filter,
         
     | 
| 
         @@ -1,5 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            import pytest
         
     | 
| 
       2 
2 
     | 
    
         
             
            import os
         
     | 
| 
      
 3 
     | 
    
         
            +
            import re
         
     | 
| 
       3 
4 
     | 
    
         
             
            from typing import Any, List, Union
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
       5 
6 
     | 
    
         
             
            from pydantic import BaseModel
         
     | 
| 
         @@ -653,7 +654,9 @@ def main(): 
     | 
|
| 
       653 
654 
     | 
    
         
             
                    node.run()
         
     | 
| 
       654 
655 
     | 
    
         | 
| 
       655 
656 
     | 
    
         
             
                # AND the error should contain the execution error details
         
     | 
| 
       656 
     | 
    
         
            -
                assert  
     | 
| 
      
 657 
     | 
    
         
            +
                assert re.match(
         
     | 
| 
      
 658 
     | 
    
         
            +
                    r"Expected an output of type '(int \| float|float \| int)', but received 'str'", exc_info.value.message
         
     | 
| 
      
 659 
     | 
    
         
            +
                )
         
     | 
| 
       657 
660 
     | 
    
         | 
| 
       658 
661 
     | 
    
         | 
| 
       659 
662 
     | 
    
         
             
            def test_run_node__chat_history_output_type():
         
     | 
| 
         @@ -74,3 +74,7 @@ class WorkflowContext: 
     | 
|
| 
       74 
74 
     | 
    
         | 
| 
       75 
75 
     | 
    
         
             
                def _get_all_node_output_mocks(self) -> List[MockNodeExecution]:
         
     | 
| 
       76 
76 
     | 
    
         
             
                    return [mock for mocks in self._node_output_mocks_map.values() for mock in mocks]
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 79 
     | 
    
         
            +
                def create_from(cls, context):
         
     | 
| 
      
 80 
     | 
    
         
            +
                    return cls(vellum_client=context.vellum_client, generated_files=context.generated_files)
         
     | 
| 
         @@ -7,7 +7,7 @@ vellum_cli/image_push.py,sha256=8DDvRDJEZ-FukUCqGW1827bg1ybF4xBbx9WyqWYQE-g,6816 
     | 
|
| 
       7 
7 
     | 
    
         
             
            vellum_cli/init.py,sha256=WpnMXPItPmh0f0bBGIer3p-e5gu8DUGwSArT_FuoMEw,5093
         
     | 
| 
       8 
8 
     | 
    
         
             
            vellum_cli/logger.py,sha256=PuRFa0WCh4sAGFS5aqWB0QIYpS6nBWwPJrIXpWxugV4,1022
         
     | 
| 
       9 
9 
     | 
    
         
             
            vellum_cli/ping.py,sha256=p_BCCRjgPhng6JktuECtkDQLbhopt6JpmrtGoLnLJT8,1161
         
     | 
| 
       10 
     | 
    
         
            -
            vellum_cli/pull.py,sha256= 
     | 
| 
      
 10 
     | 
    
         
            +
            vellum_cli/pull.py,sha256=YTo5cVCcp7RjS9lHednOuud4rW4bH7jqV3GMdbic_Uk,12002
         
     | 
| 
       11 
11 
     | 
    
         
             
            vellum_cli/push.py,sha256=xjTNbLwOVFNU3kpBrm56Bk5QkSRrJ9z86qceghCzfIA,9655
         
     | 
| 
       12 
12 
     | 
    
         
             
            vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       13 
13 
     | 
    
         
             
            vellum_cli/tests/conftest.py,sha256=AFYZryKA2qnUuCPBxBKmHLFoPiE0WhBFFej9tNwSHdc,1526
         
     | 
| 
         @@ -16,7 +16,7 @@ vellum_cli/tests/test_image_push.py,sha256=i3lJuW8nFRwL1M1OF6752IZYvGAFgKmkB2hd_ 
     | 
|
| 
       16 
16 
     | 
    
         
             
            vellum_cli/tests/test_init.py,sha256=8UOc_ThfouR4ja5cCl_URuLk7ohr9JXfCnG4yka1OUQ,18754
         
     | 
| 
       17 
17 
     | 
    
         
             
            vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
         
     | 
| 
       18 
18 
     | 
    
         
             
            vellum_cli/tests/test_ping.py,sha256=3ucVRThEmTadlV9LrJdCCrr1Ofj3rOjG6ue0BNR2UC0,2523
         
     | 
| 
       19 
     | 
    
         
            -
            vellum_cli/tests/test_pull.py,sha256= 
     | 
| 
      
 19 
     | 
    
         
            +
            vellum_cli/tests/test_pull.py,sha256=3eZJASQ4UbPXmqnbg-5w1Q3gyasVMFiA2Pr5RFPID1o,46495
         
     | 
| 
       20 
20 
     | 
    
         
             
            vellum_cli/tests/test_push.py,sha256=zDv_Q1hbXtLwmTJDPRAvwDjbuHC09uNRYOy4FQujUow,23476
         
     | 
| 
       21 
21 
     | 
    
         
             
            vellum_ee/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       22 
22 
     | 
    
         
             
            vellum_ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
         @@ -121,14 +121,14 @@ vellum_ee/workflows/tests/local_workflow/nodes/final_output.py,sha256=ZX7zBv87zi 
     | 
|
| 
       121 
121 
     | 
    
         
             
            vellum_ee/workflows/tests/local_workflow/nodes/templating_node.py,sha256=NQwFN61QkHfI3Vssz-B0NKGfupK8PU0FDSAIAhYBLi0,325
         
     | 
| 
       122 
122 
     | 
    
         
             
            vellum_ee/workflows/tests/local_workflow/workflow.py,sha256=A4qOzOPNwePYxWbcAgIPLsmrVS_aVEZEc-wULSv787Q,393
         
     | 
| 
       123 
123 
     | 
    
         
             
            vellum_ee/workflows/tests/test_display_meta.py,sha256=C25dErwghPNXio49pvSRxyOuc96srH6eYEwTAWdE2zY,2258
         
     | 
| 
       124 
     | 
    
         
            -
            vellum_ee/workflows/tests/test_server.py,sha256= 
     | 
| 
      
 124 
     | 
    
         
            +
            vellum_ee/workflows/tests/test_server.py,sha256=SsOkS6sGO7uGC4mxvk4iv8AtcXs058P9hgFHzTWmpII,14519
         
     | 
| 
       125 
125 
     | 
    
         
             
            vellum_ee/workflows/tests/test_virtual_files.py,sha256=TJEcMR0v2S8CkloXNmCHA0QW0K6pYNGaIjraJz7sFvY,2762
         
     | 
| 
       126 
     | 
    
         
            -
            vellum/__init__.py,sha256= 
     | 
| 
      
 126 
     | 
    
         
            +
            vellum/__init__.py,sha256=YKN2trB0s1J3jSQSKsT6vQjdVM7RRdSTvKGJLvaQ1PU,41070
         
     | 
| 
       127 
127 
     | 
    
         
             
            vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749
         
     | 
| 
       128 
128 
     | 
    
         
             
            vellum/client/__init__.py,sha256=ki-TDOmYzC0FePN7swDyE6UpHFQV_4dK7lqy4h-3s1Y,118148
         
     | 
| 
       129 
129 
     | 
    
         
             
            vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
         
     | 
| 
       130 
130 
     | 
    
         
             
            vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
         
     | 
| 
       131 
     | 
    
         
            -
            vellum/client/core/client_wrapper.py,sha256= 
     | 
| 
      
 131 
     | 
    
         
            +
            vellum/client/core/client_wrapper.py,sha256=ETlev1Qgt8SDpGgtdiJftsiPBOUFLk93P_WgpT1msN0,1869
         
     | 
| 
       132 
132 
     | 
    
         
             
            vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
         
     | 
| 
       133 
133 
     | 
    
         
             
            vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
         
     | 
| 
       134 
134 
     | 
    
         
             
            vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
         
     | 
| 
         @@ -195,7 +195,7 @@ vellum/client/resources/workspace_secrets/__init__.py,sha256=FTtvy8EDg9nNNg9WCat 
     | 
|
| 
       195 
195 
     | 
    
         
             
            vellum/client/resources/workspace_secrets/client.py,sha256=h7UzXLyTttPq1t-JZGMg1BWxypxJvBGUdqg7KGT7MK4,8027
         
     | 
| 
       196 
196 
     | 
    
         
             
            vellum/client/resources/workspaces/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
         
     | 
| 
       197 
197 
     | 
    
         
             
            vellum/client/resources/workspaces/client.py,sha256=RthwzN1o-Jxwg5yyNNodavFyNUSxfLoTv26w3mRR5g8,3595
         
     | 
| 
       198 
     | 
    
         
            -
            vellum/client/types/__init__.py,sha256= 
     | 
| 
      
 198 
     | 
    
         
            +
            vellum/client/types/__init__.py,sha256=rvwKofaHwLpRT0shxW3yUXkEorD3QurXnqSicG_2Or4,62132
         
     | 
| 
       199 
199 
     | 
    
         
             
            vellum/client/types/ad_hoc_execute_prompt_event.py,sha256=bCjujA2XsOgyF3bRZbcEqV2rOIymRgsLoIRtZpB14xg,607
         
     | 
| 
       200 
200 
     | 
    
         
             
            vellum/client/types/ad_hoc_expand_meta.py,sha256=1gv-NCsy_6xBYupLvZH979yf2VMdxAU-l0y0ynMKZaw,1331
         
     | 
| 
       201 
201 
     | 
    
         
             
            vellum/client/types/ad_hoc_fulfilled_prompt_execution_meta.py,sha256=Bfvf1d_dkmshxRACVM5vcxbH_7AQY23RmrrnPc0ytYY,939
         
     | 
| 
         @@ -698,8 +698,9 @@ vellum/client/types/workflow_deployment_event_executions_response.py,sha256=x7mZ 
     | 
|
| 
       698 
698 
     | 
    
         
             
            vellum/client/types/workflow_deployment_history_item.py,sha256=4WUPzcthBvEZ7iaisKfEg0soUtHjcTEnL_VUVaKpTyw,1420
         
     | 
| 
       699 
699 
     | 
    
         
             
            vellum/client/types/workflow_deployment_parent_context.py,sha256=QNyPj2o-jauaC48KrRjCWan1IKIbDgyuxLxURmhXsXM,2347
         
     | 
| 
       700 
700 
     | 
    
         
             
            vellum/client/types/workflow_deployment_read.py,sha256=tp1WaojTVE_dz1oiZ97h8ixMbIWDgy2yRu08A7wPMpw,2363
         
     | 
| 
       701 
     | 
    
         
            -
            vellum/client/types/workflow_deployment_release.py,sha256= 
     | 
| 
       702 
     | 
    
         
            -
            vellum/client/types/ 
     | 
| 
      
 701 
     | 
    
         
            +
            vellum/client/types/workflow_deployment_release.py,sha256=1OveujSLRID7B6aGGjqsN5R8MbEHn3SS0sp3dj22DQs,1609
         
     | 
| 
      
 702 
     | 
    
         
            +
            vellum/client/types/workflow_deployment_release_workflow_deployment.py,sha256=irWt901SImKChLayz7_52C1W7JldKiQHweqkjuMUoNQ,586
         
     | 
| 
      
 703 
     | 
    
         
            +
            vellum/client/types/workflow_deployment_release_workflow_version.py,sha256=NP3FoxLpgMUIK1OAPf_ei58mxE9F7BLAuw7q55CIcT8,989
         
     | 
| 
       703 
704 
     | 
    
         
             
            vellum/client/types/workflow_error.py,sha256=EQajkEmLS64T0wYm0goHQl0rT7Lguurk8pLwkhjsgAI,282
         
     | 
| 
       704 
705 
     | 
    
         
             
            vellum/client/types/workflow_event_display_context.py,sha256=tnO9lgIJKnLtuS6xum_QilI83LjOmnWCLtnSHLn1oNo,929
         
     | 
| 
       705 
706 
     | 
    
         
             
            vellum/client/types/workflow_event_error.py,sha256=HIewu_kh3KNPpWegAQArvAGHCp-cBIXqlUAAc_dBZhc,687
         
     | 
| 
         @@ -1364,6 +1365,7 @@ vellum/types/workflow_deployment_history_item.py,sha256=dp5pwzOVO83KPwAbYeO3NXlK 
     | 
|
| 
       1364 
1365 
     | 
    
         
             
            vellum/types/workflow_deployment_parent_context.py,sha256=kB0eeRXagHqRnuDVA9B8aDlvBZVOmQ702JYXD8evh24,172
         
     | 
| 
       1365 
1366 
     | 
    
         
             
            vellum/types/workflow_deployment_read.py,sha256=dDGG27VP0bvC565JzeSOHJ-5Pvs7eCF4R8F9k8316bo,162
         
     | 
| 
       1366 
1367 
     | 
    
         
             
            vellum/types/workflow_deployment_release.py,sha256=lBnOc5Tw2-jLGWmthzkwdaLGvylcDiarO-maZSote0A,165
         
     | 
| 
      
 1368 
     | 
    
         
            +
            vellum/types/workflow_deployment_release_workflow_deployment.py,sha256=8qT32r--NyJppqBizD9QP6jvM5YdcsdpGEtaKMG1RbE,185
         
     | 
| 
       1367 
1369 
     | 
    
         
             
            vellum/types/workflow_deployment_release_workflow_version.py,sha256=l5SJrY9z3lG5K82V2wY2sY50V40CQWKl95nDjnHu4Dc,182
         
     | 
| 
       1368 
1370 
     | 
    
         
             
            vellum/types/workflow_error.py,sha256=7rZcYJG5jYr4IbEvgv57G6Lxutrdg43SD8mUerd58_A,152
         
     | 
| 
       1369 
1371 
     | 
    
         
             
            vellum/types/workflow_event_display_context.py,sha256=jiH4vHlWYdT_2zM8yxPox3fXjnFStzIO46N90B2TdNA,168
         
     | 
| 
         @@ -1523,22 +1525,22 @@ vellum/workflows/nodes/core/__init__.py,sha256=5zDMCmyt1v0HTJzlUBwq3U9L825yZGZhT 
     | 
|
| 
       1523 
1525 
     | 
    
         
             
            vellum/workflows/nodes/core/error_node/__init__.py,sha256=g7RRnlHhqu4qByfLjBwCunmgGA8dI5gNsjS3h6TwlSI,60
         
     | 
| 
       1524 
1526 
     | 
    
         
             
            vellum/workflows/nodes/core/error_node/node.py,sha256=MFHU5vITYSK-L9CuMZ49In2ZeNLWnhZD0f8r5dWvb5Y,1270
         
     | 
| 
       1525 
1527 
     | 
    
         
             
            vellum/workflows/nodes/core/inline_subworkflow_node/__init__.py,sha256=nKNEH1QTl-1PcvmYoqSWEl0-t6gAur8GLTXHzklRQfM,84
         
     | 
| 
       1526 
     | 
    
         
            -
            vellum/workflows/nodes/core/inline_subworkflow_node/node.py,sha256= 
     | 
| 
      
 1528 
     | 
    
         
            +
            vellum/workflows/nodes/core/inline_subworkflow_node/node.py,sha256=rgcjc3gaCEX9uSfkLSErHjSnNQEeqREVZk-7TEr9hUo,6595
         
     | 
| 
       1527 
1529 
     | 
    
         
             
            vellum/workflows/nodes/core/inline_subworkflow_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1528 
1530 
     | 
    
         
             
            vellum/workflows/nodes/core/inline_subworkflow_node/tests/test_node.py,sha256=kUqwcRMMxjTHALbwGUXCJT_aJBrHS1bkg49oL8R0JO8,4337
         
     | 
| 
       1529 
1531 
     | 
    
         
             
            vellum/workflows/nodes/core/map_node/__init__.py,sha256=MXpZYmGfhsMJHqqlpd64WiJRtbAtAMQz-_3fCU_cLV0,56
         
     | 
| 
       1530 
     | 
    
         
            -
            vellum/workflows/nodes/core/map_node/node.py,sha256= 
     | 
| 
      
 1532 
     | 
    
         
            +
            vellum/workflows/nodes/core/map_node/node.py,sha256=RER4mLOXSe1BSpjEYCoJq83ZeydQ5Q5uKCZAsqhlOW8,9227
         
     | 
| 
       1531 
1533 
     | 
    
         
             
            vellum/workflows/nodes/core/map_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1532 
1534 
     | 
    
         
             
            vellum/workflows/nodes/core/map_node/tests/test_node.py,sha256=uMR0AyIFn539LqTKHdwuBswnx1i-PHyqPpgtYrnmYMY,3496
         
     | 
| 
       1533 
1535 
     | 
    
         
             
            vellum/workflows/nodes/core/retry_node/__init__.py,sha256=lN2bIy5a3Uzhs_FYCrooADyYU6ZGShtvLKFWpelwPvo,60
         
     | 
| 
       1534 
     | 
    
         
            -
            vellum/workflows/nodes/core/retry_node/node.py,sha256= 
     | 
| 
      
 1536 
     | 
    
         
            +
            vellum/workflows/nodes/core/retry_node/node.py,sha256=at7RjwUmlBeUv-tHvqeOhCAxkyuSw47ySmIQKC0fJf8,5245
         
     | 
| 
       1535 
1537 
     | 
    
         
             
            vellum/workflows/nodes/core/retry_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1536 
1538 
     | 
    
         
             
            vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=RM_OHwxrHwyxvlQQBJPqVBxpedFuWQ9h2-Xa3kP75sc,4399
         
     | 
| 
       1537 
1539 
     | 
    
         
             
            vellum/workflows/nodes/core/templating_node/__init__.py,sha256=GmyuYo81_A1_Bz6id69ozVFS6FKiuDsZTiA3I6MaL2U,70
         
     | 
| 
       1538 
1540 
     | 
    
         
             
            vellum/workflows/nodes/core/templating_node/node.py,sha256=iqBmr2i-f-BqhisNQJiDfewjol0ur7-XpupLStyMJsg,3731
         
     | 
| 
       1539 
1541 
     | 
    
         
             
            vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=nXkgGDBg4wP36NwykdMEVWwx_xjv8oGT2rYkwuCB_VU,10075
         
     | 
| 
       1540 
1542 
     | 
    
         
             
            vellum/workflows/nodes/core/try_node/__init__.py,sha256=JVD4DrldTIqFQQFrubs9KtWCCc0YCAc7Fzol5ZWIWeM,56
         
     | 
| 
       1541 
     | 
    
         
            -
            vellum/workflows/nodes/core/try_node/node.py,sha256 
     | 
| 
      
 1543 
     | 
    
         
            +
            vellum/workflows/nodes/core/try_node/node.py,sha256=2r2I70j30IyZPvn3Q3zP2VgLbx3WQ1DdOr8NUlXjcq0,4429
         
     | 
| 
       1542 
1544 
     | 
    
         
             
            vellum/workflows/nodes/core/try_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1543 
1545 
     | 
    
         
             
            vellum/workflows/nodes/core/try_node/tests/test_node.py,sha256=h6eUc3SggvhzBWlOD0PrPUlkoCSQHwjqYn81VkxSIxU,4948
         
     | 
| 
       1544 
1546 
     | 
    
         
             
            vellum/workflows/nodes/displayable/__init__.py,sha256=6F_4DlSwvHuilWnIalp8iDjjDXl0Nmz4QzJV2PYe5RI,1023
         
     | 
| 
         @@ -1567,7 +1569,7 @@ vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=Ko_Dy17Ajf 
     | 
|
| 
       1567 
1569 
     | 
    
         
             
            vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1568 
1570 
     | 
    
         
             
            vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1569 
1571 
     | 
    
         
             
            vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
         
     | 
| 
       1570 
     | 
    
         
            -
            vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256= 
     | 
| 
      
 1572 
     | 
    
         
            +
            vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=AzgTK2YSvVj7zr6gWZfz0-YGf1cVQ9DiSx9fe5BR4uE,24690
         
     | 
| 
       1571 
1573 
     | 
    
         
             
            vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=G-sc7yOL5g6rLk99X8HAbXNcLxRaqpju9IXq1iUwnQI,4470
         
     | 
| 
       1572 
1574 
     | 
    
         
             
            vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
         
     | 
| 
       1573 
1575 
     | 
    
         
             
            vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=Qjfl33gZ3JEgxBA1EgzSUebboGvsARthIxxcQyvx5Gg,1152
         
     | 
| 
         @@ -1638,7 +1640,7 @@ vellum/workflows/runner/runner.py,sha256=ww4fjZJBENkB5HJxdj92kTz7k_EyifCeAreupy5 
     | 
|
| 
       1638 
1640 
     | 
    
         
             
            vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2235
         
     | 
| 
       1639 
1641 
     | 
    
         
             
            vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
         
     | 
| 
       1640 
1642 
     | 
    
         
             
            vellum/workflows/state/base.py,sha256=Vkhneko3VlQrPsMLU1PYSzXU_W1u7_AraJsghiv5O-4,15512
         
     | 
| 
       1641 
     | 
    
         
            -
            vellum/workflows/state/context.py,sha256= 
     | 
| 
      
 1643 
     | 
    
         
            +
            vellum/workflows/state/context.py,sha256=KOAI1wEGn8dGmhmAemJaf4SZbitP3jpIBcwKfznQaRE,3076
         
     | 
| 
       1642 
1644 
     | 
    
         
             
            vellum/workflows/state/encoder.py,sha256=TnOQojc5lTQ83g9QbpA4UCqShJvutmTMxbpKt-9gNe4,1911
         
     | 
| 
       1643 
1645 
     | 
    
         
             
            vellum/workflows/state/store.py,sha256=uVe-oN73KwGV6M6YLhwZMMUQhzTQomsVfVnb8V91gVo,1147
         
     | 
| 
       1644 
1646 
     | 
    
         
             
            vellum/workflows/state/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
         @@ -1670,8 +1672,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad 
     | 
|
| 
       1670 
1672 
     | 
    
         
             
            vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1671 
1673 
     | 
    
         
             
            vellum/workflows/workflows/tests/test_base_workflow.py,sha256=tCxrV3QBHL8wfdEO3bvKteDdw32xBlUl1_WxkAwaONw,8344
         
     | 
| 
       1672 
1674 
     | 
    
         
             
            vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
         
     | 
| 
       1673 
     | 
    
         
            -
            vellum_ai-0.14. 
     | 
| 
       1674 
     | 
    
         
            -
            vellum_ai-0.14. 
     | 
| 
       1675 
     | 
    
         
            -
            vellum_ai-0.14. 
     | 
| 
       1676 
     | 
    
         
            -
            vellum_ai-0.14. 
     | 
| 
       1677 
     | 
    
         
            -
            vellum_ai-0.14. 
     | 
| 
      
 1675 
     | 
    
         
            +
            vellum_ai-0.14.35.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
         
     | 
| 
      
 1676 
     | 
    
         
            +
            vellum_ai-0.14.35.dist-info/METADATA,sha256=p35Qzrtnz0-GxWWkLD1zb0nMfyoFki46Og2RE-q9c8E,5484
         
     | 
| 
      
 1677 
     | 
    
         
            +
            vellum_ai-0.14.35.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
         
     | 
| 
      
 1678 
     | 
    
         
            +
            vellum_ai-0.14.35.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
         
     | 
| 
      
 1679 
     | 
    
         
            +
            vellum_ai-0.14.35.dist-info/RECORD,,
         
     | 
    
        vellum_cli/pull.py
    CHANGED
    
    | 
         @@ -2,6 +2,7 @@ import io 
     | 
|
| 
       2 
2 
     | 
    
         
             
            import json
         
     | 
| 
       3 
3 
     | 
    
         
             
            import os
         
     | 
| 
       4 
4 
     | 
    
         
             
            from pathlib import Path
         
     | 
| 
      
 5 
     | 
    
         
            +
            from uuid import UUID
         
     | 
| 
       5 
6 
     | 
    
         
             
            import zipfile
         
     | 
| 
       6 
7 
     | 
    
         
             
            from typing import Optional
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
         @@ -10,8 +11,9 @@ from pydash import snake_case 
     | 
|
| 
       10 
11 
     | 
    
         | 
| 
       11 
12 
     | 
    
         
             
            from vellum.client.core.api_error import ApiError
         
     | 
| 
       12 
13 
     | 
    
         
             
            from vellum.client.core.pydantic_utilities import UniversalBaseModel
         
     | 
| 
      
 14 
     | 
    
         
            +
            from vellum.utils.uuid import is_valid_uuid
         
     | 
| 
       13 
15 
     | 
    
         
             
            from vellum.workflows.vellum_client import create_vellum_client
         
     | 
| 
       14 
     | 
    
         
            -
            from vellum_cli.config import VellumCliConfig, WorkflowConfig, load_vellum_cli_config
         
     | 
| 
      
 16 
     | 
    
         
            +
            from vellum_cli.config import VellumCliConfig, WorkflowConfig, WorkflowDeploymentConfig, load_vellum_cli_config
         
     | 
| 
       15 
17 
     | 
    
         
             
            from vellum_cli.logger import load_cli_logger
         
     | 
| 
       16 
18 
     | 
    
         | 
| 
       17 
19 
     | 
    
         
             
            ERROR_LOG_FILE_NAME = "error.log"
         
     | 
| 
         @@ -31,6 +33,7 @@ class RunnerConfig(UniversalBaseModel): 
     | 
|
| 
       31 
33 
     | 
    
         
             
            class PullContentsMetadata(UniversalBaseModel):
         
     | 
| 
       32 
34 
     | 
    
         
             
                label: Optional[str] = None
         
     | 
| 
       33 
35 
     | 
    
         
             
                runner_config: Optional[RunnerConfig] = None
         
     | 
| 
      
 36 
     | 
    
         
            +
                deployment_id: Optional[UUID] = None
         
     | 
| 
       34 
37 
     | 
    
         
             
                deployment_name: Optional[str] = None
         
     | 
| 
       35 
38 
     | 
    
         | 
| 
       36 
39 
     | 
    
         | 
| 
         @@ -79,6 +82,29 @@ def _resolve_workflow_config( 
     | 
|
| 
       79 
82 
     | 
    
         
             
                        pk=workflow_config.workflow_sandbox_id,
         
     | 
| 
       80 
83 
     | 
    
         
             
                    )
         
     | 
| 
       81 
84 
     | 
    
         
             
                elif workflow_deployment:
         
     | 
| 
      
 85 
     | 
    
         
            +
                    if is_valid_uuid(workflow_deployment):
         
     | 
| 
      
 86 
     | 
    
         
            +
                        # name may also be a valid UUID
         
     | 
| 
      
 87 
     | 
    
         
            +
                        workflow_config = next(
         
     | 
| 
      
 88 
     | 
    
         
            +
                            (
         
     | 
| 
      
 89 
     | 
    
         
            +
                                w
         
     | 
| 
      
 90 
     | 
    
         
            +
                                for w in config.workflows
         
     | 
| 
      
 91 
     | 
    
         
            +
                                if w.deployments
         
     | 
| 
      
 92 
     | 
    
         
            +
                                and (
         
     | 
| 
      
 93 
     | 
    
         
            +
                                    str(w.deployments[0].id) == workflow_deployment or w.deployments[0].name == workflow_deployment
         
     | 
| 
      
 94 
     | 
    
         
            +
                                )
         
     | 
| 
      
 95 
     | 
    
         
            +
                            ),
         
     | 
| 
      
 96 
     | 
    
         
            +
                            None,
         
     | 
| 
      
 97 
     | 
    
         
            +
                        )
         
     | 
| 
      
 98 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 99 
     | 
    
         
            +
                        workflow_config = next(
         
     | 
| 
      
 100 
     | 
    
         
            +
                            (w for w in config.workflows if w.deployments and w.deployments[0].name == workflow_deployment), None
         
     | 
| 
      
 101 
     | 
    
         
            +
                        )
         
     | 
| 
      
 102 
     | 
    
         
            +
                    if workflow_config:
         
     | 
| 
      
 103 
     | 
    
         
            +
                        return WorkflowConfigResolutionResult(
         
     | 
| 
      
 104 
     | 
    
         
            +
                            workflow_config=workflow_config,
         
     | 
| 
      
 105 
     | 
    
         
            +
                            pk=workflow_deployment,
         
     | 
| 
      
 106 
     | 
    
         
            +
                        )
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
       82 
108 
     | 
    
         
             
                    workflow_config = WorkflowConfig(
         
     | 
| 
       83 
109 
     | 
    
         
             
                        module="",
         
     | 
| 
       84 
110 
     | 
    
         
             
                    )
         
     | 
| 
         @@ -177,6 +203,24 @@ def pull_command( 
     | 
|
| 
       177 
203 
     | 
    
         
             
                            if not workflow_config.module and pull_contents_metadata.label:
         
     | 
| 
       178 
204 
     | 
    
         
             
                                workflow_config.module = snake_case(pull_contents_metadata.label)
         
     | 
| 
       179 
205 
     | 
    
         | 
| 
      
 206 
     | 
    
         
            +
                            # Save or update the deployment info when pulling with --workflow-deployment
         
     | 
| 
      
 207 
     | 
    
         
            +
                            if workflow_deployment:
         
     | 
| 
      
 208 
     | 
    
         
            +
                                workflow_deployment_id = pull_contents_metadata.deployment_id
         
     | 
| 
      
 209 
     | 
    
         
            +
                                existing_deployment = next(
         
     | 
| 
      
 210 
     | 
    
         
            +
                                    (d for d in workflow_config.deployments if d.id == workflow_deployment_id), None
         
     | 
| 
      
 211 
     | 
    
         
            +
                                )
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                                if existing_deployment:
         
     | 
| 
      
 214 
     | 
    
         
            +
                                    if pull_contents_metadata.label:
         
     | 
| 
      
 215 
     | 
    
         
            +
                                        existing_deployment.label = pull_contents_metadata.label
         
     | 
| 
      
 216 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 217 
     | 
    
         
            +
                                    deployment_config = WorkflowDeploymentConfig(
         
     | 
| 
      
 218 
     | 
    
         
            +
                                        id=workflow_deployment_id,
         
     | 
| 
      
 219 
     | 
    
         
            +
                                        label=pull_contents_metadata.label,
         
     | 
| 
      
 220 
     | 
    
         
            +
                                        name=pull_contents_metadata.deployment_name,
         
     | 
| 
      
 221 
     | 
    
         
            +
                                    )
         
     | 
| 
      
 222 
     | 
    
         
            +
                                    workflow_config.deployments.append(deployment_config)
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
       180 
224 
     | 
    
         
             
                        if not workflow_config.module:
         
     | 
| 
       181 
225 
     | 
    
         
             
                            raise ValueError(f"Failed to resolve a module name for Workflow {pk}")
         
     | 
| 
       182 
226 
     | 
    
         | 
    
        vellum_cli/tests/test_pull.py
    CHANGED
    
    | 
         @@ -337,6 +337,7 @@ def test_pull__sandbox_id_with_other_workflow_configured(vellum_client, mock_mod 
     | 
|
| 
       337 
337 
     | 
    
         
             
            def test_pull__workflow_deployment_with_no_config(vellum_client):
         
     | 
| 
       338 
338 
     | 
    
         
             
                # GIVEN a workflow deployment
         
     | 
| 
       339 
339 
     | 
    
         
             
                workflow_deployment = "my-deployment"
         
     | 
| 
      
 340 
     | 
    
         
            +
                deployment_id = str(uuid4())
         
     | 
| 
       340 
341 
     | 
    
         | 
| 
       341 
342 
     | 
    
         
             
                # AND the workflow pull API call returns a zip file
         
     | 
| 
       342 
343 
     | 
    
         
             
                vellum_client.workflows.pull.return_value = iter(
         
     | 
| 
         @@ -344,7 +345,9 @@ def test_pull__workflow_deployment_with_no_config(vellum_client): 
     | 
|
| 
       344 
345 
     | 
    
         
             
                        _zip_file_map(
         
     | 
| 
       345 
346 
     | 
    
         
             
                            {
         
     | 
| 
       346 
347 
     | 
    
         
             
                                "workflow.py": "print('hello')",
         
     | 
| 
       347 
     | 
    
         
            -
                                "metadata.json": json.dumps( 
     | 
| 
      
 348 
     | 
    
         
            +
                                "metadata.json": json.dumps(
         
     | 
| 
      
 349 
     | 
    
         
            +
                                    {"deployment_id": deployment_id, "deployment_name": workflow_deployment, "label": "Some Label"}
         
     | 
| 
      
 350 
     | 
    
         
            +
                                ),
         
     | 
| 
       348 
351 
     | 
    
         
             
                            }
         
     | 
| 
       349 
352 
     | 
    
         
             
                        )
         
     | 
| 
       350 
353 
     | 
    
         
             
                    ]
         
     | 
| 
         @@ -382,7 +385,15 @@ def test_pull__workflow_deployment_with_no_config(vellum_client): 
     | 
|
| 
       382 
385 
     | 
    
         
             
                                "module": "my_deployment",
         
     | 
| 
       383 
386 
     | 
    
         
             
                                "workflow_sandbox_id": None,
         
     | 
| 
       384 
387 
     | 
    
         
             
                                "ignore": None,
         
     | 
| 
       385 
     | 
    
         
            -
                                "deployments": [ 
     | 
| 
      
 388 
     | 
    
         
            +
                                "deployments": [
         
     | 
| 
      
 389 
     | 
    
         
            +
                                    {
         
     | 
| 
      
 390 
     | 
    
         
            +
                                        "id": deployment_id,
         
     | 
| 
      
 391 
     | 
    
         
            +
                                        "label": "Some Label",
         
     | 
| 
      
 392 
     | 
    
         
            +
                                        "name": "my-deployment",
         
     | 
| 
      
 393 
     | 
    
         
            +
                                        "description": None,
         
     | 
| 
      
 394 
     | 
    
         
            +
                                        "release_tags": None,
         
     | 
| 
      
 395 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 396 
     | 
    
         
            +
                                ],
         
     | 
| 
       386 
397 
     | 
    
         
             
                                "container_image_tag": None,
         
     | 
| 
       387 
398 
     | 
    
         
             
                                "container_image_name": None,
         
     | 
| 
       388 
399 
     | 
    
         
             
                                "workspace": "default",
         
     | 
| 
         @@ -937,3 +948,314 @@ def test_pull__unauthorized_error_path(vellum_client): 
     | 
|
| 
       937 
948 
     | 
    
         
             
                # THEN the command returns an error
         
     | 
| 
       938 
949 
     | 
    
         
             
                assert result.exit_code == 1
         
     | 
| 
       939 
950 
     | 
    
         
             
                assert str(result.exception) == "Please make sure your `VELLUM_API_KEY` environment variable is set correctly."
         
     | 
| 
      
 951 
     | 
    
         
            +
             
     | 
| 
      
 952 
     | 
    
         
            +
             
     | 
| 
      
 953 
     | 
    
         
            +
            @pytest.mark.parametrize(
         
     | 
| 
      
 954 
     | 
    
         
            +
                "workflow_deployment",
         
     | 
| 
      
 955 
     | 
    
         
            +
                [
         
     | 
| 
      
 956 
     | 
    
         
            +
                    "test-workflow-deployment-id",
         
     | 
| 
      
 957 
     | 
    
         
            +
                    str(uuid4()),
         
     | 
| 
      
 958 
     | 
    
         
            +
                ],
         
     | 
| 
      
 959 
     | 
    
         
            +
            )
         
     | 
| 
      
 960 
     | 
    
         
            +
            def test_pull__workflow_deployment_adds_deployment_to_config(vellum_client, workflow_deployment):
         
     | 
| 
      
 961 
     | 
    
         
            +
                # GIVEN a workflow deployment ID
         
     | 
| 
      
 962 
     | 
    
         
            +
                deployment_id = str(uuid4())  # config will always use the deployment_id return from the API
         
     | 
| 
      
 963 
     | 
    
         
            +
                deployment_name = "Test Deployment"
         
     | 
| 
      
 964 
     | 
    
         
            +
                deployment_label = "Test Label"
         
     | 
| 
      
 965 
     | 
    
         
            +
             
     | 
| 
      
 966 
     | 
    
         
            +
                # AND the workflow pull API call returns a zip file with metadata
         
     | 
| 
      
 967 
     | 
    
         
            +
                vellum_client.workflows.pull.return_value = iter(
         
     | 
| 
      
 968 
     | 
    
         
            +
                    [
         
     | 
| 
      
 969 
     | 
    
         
            +
                        _zip_file_map(
         
     | 
| 
      
 970 
     | 
    
         
            +
                            {
         
     | 
| 
      
 971 
     | 
    
         
            +
                                "workflow.py": "print('hello')",
         
     | 
| 
      
 972 
     | 
    
         
            +
                                "metadata.json": json.dumps(
         
     | 
| 
      
 973 
     | 
    
         
            +
                                    {
         
     | 
| 
      
 974 
     | 
    
         
            +
                                        "deployment_id": deployment_id,
         
     | 
| 
      
 975 
     | 
    
         
            +
                                        "deployment_name": deployment_name,
         
     | 
| 
      
 976 
     | 
    
         
            +
                                        "label": deployment_label,
         
     | 
| 
      
 977 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 978 
     | 
    
         
            +
                                ),
         
     | 
| 
      
 979 
     | 
    
         
            +
                            }
         
     | 
| 
      
 980 
     | 
    
         
            +
                        )
         
     | 
| 
      
 981 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 982 
     | 
    
         
            +
                )
         
     | 
| 
      
 983 
     | 
    
         
            +
             
     | 
| 
      
 984 
     | 
    
         
            +
                # AND we are currently in a new directory
         
     | 
| 
      
 985 
     | 
    
         
            +
                current_dir = os.getcwd()
         
     | 
| 
      
 986 
     | 
    
         
            +
                temp_dir = tempfile.mkdtemp()
         
     | 
| 
      
 987 
     | 
    
         
            +
                os.chdir(temp_dir)
         
     | 
| 
      
 988 
     | 
    
         
            +
             
     | 
| 
      
 989 
     | 
    
         
            +
                # WHEN the user runs the pull command with the workflow deployment
         
     | 
| 
      
 990 
     | 
    
         
            +
                runner = CliRunner()
         
     | 
| 
      
 991 
     | 
    
         
            +
                result = runner.invoke(cli_main, ["workflows", "pull", "--workflow-deployment", workflow_deployment])
         
     | 
| 
      
 992 
     | 
    
         
            +
             
     | 
| 
      
 993 
     | 
    
         
            +
                # THEN the command returns successfully
         
     | 
| 
      
 994 
     | 
    
         
            +
                assert result.exit_code == 0
         
     | 
| 
      
 995 
     | 
    
         
            +
             
     | 
| 
      
 996 
     | 
    
         
            +
                # AND the deployment is saved in the config
         
     | 
| 
      
 997 
     | 
    
         
            +
                vellum_lock_json = os.path.join(temp_dir, "vellum.lock.json")
         
     | 
| 
      
 998 
     | 
    
         
            +
                assert os.path.exists(vellum_lock_json)
         
     | 
| 
      
 999 
     | 
    
         
            +
                with open(vellum_lock_json) as f:
         
     | 
| 
      
 1000 
     | 
    
         
            +
                    lock_data = json.loads(f.read())
         
     | 
| 
      
 1001 
     | 
    
         
            +
                    assert len(lock_data["workflows"]) == 1
         
     | 
| 
      
 1002 
     | 
    
         
            +
                    assert len(lock_data["workflows"][0]["deployments"]) == 1
         
     | 
| 
      
 1003 
     | 
    
         
            +
                    deployment = lock_data["workflows"][0]["deployments"][0]
         
     | 
| 
      
 1004 
     | 
    
         
            +
                    assert str(deployment["id"]) == deployment_id
         
     | 
| 
      
 1005 
     | 
    
         
            +
                    assert deployment["name"] == deployment_name
         
     | 
| 
      
 1006 
     | 
    
         
            +
                    assert deployment["label"] == deployment_label
         
     | 
| 
      
 1007 
     | 
    
         
            +
             
     | 
| 
      
 1008 
     | 
    
         
            +
                os.chdir(current_dir)
         
     | 
| 
      
 1009 
     | 
    
         
            +
             
     | 
| 
      
 1010 
     | 
    
         
            +
             
     | 
| 
      
 1011 
     | 
    
         
            +
            def test_pull__workflow_deployment_name_is_uuid(vellum_client):
         
     | 
| 
      
 1012 
     | 
    
         
            +
                # GIVEN a workflow deployment name that is a valid UUID
         
     | 
| 
      
 1013 
     | 
    
         
            +
                deployment_id = str(uuid4())
         
     | 
| 
      
 1014 
     | 
    
         
            +
                deployment_name = str(uuid4())
         
     | 
| 
      
 1015 
     | 
    
         
            +
             
     | 
| 
      
 1016 
     | 
    
         
            +
                # AND an existing configuration with this deployment
         
     | 
| 
      
 1017 
     | 
    
         
            +
                current_dir = os.getcwd()
         
     | 
| 
      
 1018 
     | 
    
         
            +
                temp_dir = tempfile.mkdtemp()
         
     | 
| 
      
 1019 
     | 
    
         
            +
                os.chdir(temp_dir)
         
     | 
| 
      
 1020 
     | 
    
         
            +
             
     | 
| 
      
 1021 
     | 
    
         
            +
                # Create initial config with a deployment
         
     | 
| 
      
 1022 
     | 
    
         
            +
                vellum_lock_json = os.path.join(temp_dir, "vellum.lock.json")
         
     | 
| 
      
 1023 
     | 
    
         
            +
                with open(vellum_lock_json, "w") as f:
         
     | 
| 
      
 1024 
     | 
    
         
            +
                    json.dump(
         
     | 
| 
      
 1025 
     | 
    
         
            +
                        {
         
     | 
| 
      
 1026 
     | 
    
         
            +
                            "version": "1.0",
         
     | 
| 
      
 1027 
     | 
    
         
            +
                            "workflows": [
         
     | 
| 
      
 1028 
     | 
    
         
            +
                                {
         
     | 
| 
      
 1029 
     | 
    
         
            +
                                    "module": "test_workflow",
         
     | 
| 
      
 1030 
     | 
    
         
            +
                                    "workflow_sandbox_id": None,
         
     | 
| 
      
 1031 
     | 
    
         
            +
                                    "ignore": None,
         
     | 
| 
      
 1032 
     | 
    
         
            +
                                    "deployments": [
         
     | 
| 
      
 1033 
     | 
    
         
            +
                                        {
         
     | 
| 
      
 1034 
     | 
    
         
            +
                                            "id": deployment_id,
         
     | 
| 
      
 1035 
     | 
    
         
            +
                                            "label": "Test Label",
         
     | 
| 
      
 1036 
     | 
    
         
            +
                                            "name": deployment_name,
         
     | 
| 
      
 1037 
     | 
    
         
            +
                                            "description": None,
         
     | 
| 
      
 1038 
     | 
    
         
            +
                                            "release_tags": None,
         
     | 
| 
      
 1039 
     | 
    
         
            +
                                        }
         
     | 
| 
      
 1040 
     | 
    
         
            +
                                    ],
         
     | 
| 
      
 1041 
     | 
    
         
            +
                                    "container_image_name": None,
         
     | 
| 
      
 1042 
     | 
    
         
            +
                                    "container_image_tag": None,
         
     | 
| 
      
 1043 
     | 
    
         
            +
                                    "workspace": "default",
         
     | 
| 
      
 1044 
     | 
    
         
            +
                                    "target_directory": None,
         
     | 
| 
      
 1045 
     | 
    
         
            +
                                }
         
     | 
| 
      
 1046 
     | 
    
         
            +
                            ],
         
     | 
| 
      
 1047 
     | 
    
         
            +
                            "workspaces": [],
         
     | 
| 
      
 1048 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1049 
     | 
    
         
            +
                        f,
         
     | 
| 
      
 1050 
     | 
    
         
            +
                    )
         
     | 
| 
      
 1051 
     | 
    
         
            +
             
     | 
| 
      
 1052 
     | 
    
         
            +
                # AND the workflow pull API call returns a zip file with updated metadata
         
     | 
| 
      
 1053 
     | 
    
         
            +
                updated_label = "Updated Label"
         
     | 
| 
      
 1054 
     | 
    
         
            +
                vellum_client.workflows.pull.return_value = iter(
         
     | 
| 
      
 1055 
     | 
    
         
            +
                    [
         
     | 
| 
      
 1056 
     | 
    
         
            +
                        _zip_file_map(
         
     | 
| 
      
 1057 
     | 
    
         
            +
                            {
         
     | 
| 
      
 1058 
     | 
    
         
            +
                                "workflow.py": "print('hello')",
         
     | 
| 
      
 1059 
     | 
    
         
            +
                                "metadata.json": json.dumps(
         
     | 
| 
      
 1060 
     | 
    
         
            +
                                    {
         
     | 
| 
      
 1061 
     | 
    
         
            +
                                        "deployment_id": deployment_id,
         
     | 
| 
      
 1062 
     | 
    
         
            +
                                        "deployment_name": deployment_name,
         
     | 
| 
      
 1063 
     | 
    
         
            +
                                        "label": updated_label,
         
     | 
| 
      
 1064 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 1065 
     | 
    
         
            +
                                ),
         
     | 
| 
      
 1066 
     | 
    
         
            +
                            }
         
     | 
| 
      
 1067 
     | 
    
         
            +
                        )
         
     | 
| 
      
 1068 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 1069 
     | 
    
         
            +
                )
         
     | 
| 
      
 1070 
     | 
    
         
            +
             
     | 
| 
      
 1071 
     | 
    
         
            +
                # WHEN the user runs the pull command with the workflow deployment
         
     | 
| 
      
 1072 
     | 
    
         
            +
                runner = CliRunner()
         
     | 
| 
      
 1073 
     | 
    
         
            +
                result = runner.invoke(cli_main, ["workflows", "pull", "--workflow-deployment", deployment_name])
         
     | 
| 
      
 1074 
     | 
    
         
            +
             
     | 
| 
      
 1075 
     | 
    
         
            +
                # THEN the command returns successfully
         
     | 
| 
      
 1076 
     | 
    
         
            +
                assert result.exit_code == 0
         
     | 
| 
      
 1077 
     | 
    
         
            +
             
     | 
| 
      
 1078 
     | 
    
         
            +
                # AND the deployment info is updated in the config
         
     | 
| 
      
 1079 
     | 
    
         
            +
                with open(vellum_lock_json) as f:
         
     | 
| 
      
 1080 
     | 
    
         
            +
                    lock_data = json.loads(f.read())
         
     | 
| 
      
 1081 
     | 
    
         
            +
                    assert len(lock_data["workflows"]) == 1
         
     | 
| 
      
 1082 
     | 
    
         
            +
                    assert len(lock_data["workflows"][0]["deployments"]) == 1
         
     | 
| 
      
 1083 
     | 
    
         
            +
                    deployment = lock_data["workflows"][0]["deployments"][0]
         
     | 
| 
      
 1084 
     | 
    
         
            +
                    assert str(deployment["id"]) == deployment_id
         
     | 
| 
      
 1085 
     | 
    
         
            +
                    assert deployment["name"] == deployment_name
         
     | 
| 
      
 1086 
     | 
    
         
            +
                    assert deployment["label"] == updated_label
         
     | 
| 
      
 1087 
     | 
    
         
            +
             
     | 
| 
      
 1088 
     | 
    
         
            +
                os.chdir(current_dir)
         
     | 
| 
      
 1089 
     | 
    
         
            +
             
     | 
| 
      
 1090 
     | 
    
         
            +
             
     | 
| 
      
 1091 
     | 
    
         
            +
            @pytest.mark.parametrize("get_identifier", [(lambda d: d), (lambda d: "Test Name")])
         
     | 
| 
      
 1092 
     | 
    
         
            +
            def test_pull__workflow_deployment_updates_existing_deployment(vellum_client, get_identifier):
         
     | 
| 
      
 1093 
     | 
    
         
            +
                """
         
     | 
| 
      
 1094 
     | 
    
         
            +
                This test is to ensure that the deployment info is updated in the config
         
     | 
| 
      
 1095 
     | 
    
         
            +
                when the user runs the pull command with the workflow deployment
         
     | 
| 
      
 1096 
     | 
    
         
            +
             
     | 
| 
      
 1097 
     | 
    
         
            +
                get_identifier is a function that returns the identifier to use for the deployment
         
     | 
| 
      
 1098 
     | 
    
         
            +
                it can be the deployment_id or the deployment_name
         
     | 
| 
      
 1099 
     | 
    
         
            +
                """
         
     | 
| 
      
 1100 
     | 
    
         
            +
                # GIVEN a workflow deployment id and name
         
     | 
| 
      
 1101 
     | 
    
         
            +
                deployment_id = str(uuid4())
         
     | 
| 
      
 1102 
     | 
    
         
            +
                deployment_name = "Test Name"
         
     | 
| 
      
 1103 
     | 
    
         
            +
             
     | 
| 
      
 1104 
     | 
    
         
            +
                # AND an existing configuration with this deployment
         
     | 
| 
      
 1105 
     | 
    
         
            +
                current_dir = os.getcwd()
         
     | 
| 
      
 1106 
     | 
    
         
            +
                temp_dir = tempfile.mkdtemp()
         
     | 
| 
      
 1107 
     | 
    
         
            +
                os.chdir(temp_dir)
         
     | 
| 
      
 1108 
     | 
    
         
            +
             
     | 
| 
      
 1109 
     | 
    
         
            +
                # Create initial config with a deployment
         
     | 
| 
      
 1110 
     | 
    
         
            +
                vellum_lock_json = os.path.join(temp_dir, "vellum.lock.json")
         
     | 
| 
      
 1111 
     | 
    
         
            +
                with open(vellum_lock_json, "w") as f:
         
     | 
| 
      
 1112 
     | 
    
         
            +
                    json.dump(
         
     | 
| 
      
 1113 
     | 
    
         
            +
                        {
         
     | 
| 
      
 1114 
     | 
    
         
            +
                            "version": "1.0",
         
     | 
| 
      
 1115 
     | 
    
         
            +
                            "workflows": [
         
     | 
| 
      
 1116 
     | 
    
         
            +
                                {
         
     | 
| 
      
 1117 
     | 
    
         
            +
                                    "module": "test_workflow",
         
     | 
| 
      
 1118 
     | 
    
         
            +
                                    "workflow_sandbox_id": None,
         
     | 
| 
      
 1119 
     | 
    
         
            +
                                    "ignore": None,
         
     | 
| 
      
 1120 
     | 
    
         
            +
                                    "deployments": [
         
     | 
| 
      
 1121 
     | 
    
         
            +
                                        {
         
     | 
| 
      
 1122 
     | 
    
         
            +
                                            "id": deployment_id,
         
     | 
| 
      
 1123 
     | 
    
         
            +
                                            "label": "Test Label",
         
     | 
| 
      
 1124 
     | 
    
         
            +
                                            "name": deployment_name,
         
     | 
| 
      
 1125 
     | 
    
         
            +
                                            "description": None,
         
     | 
| 
      
 1126 
     | 
    
         
            +
                                            "release_tags": None,
         
     | 
| 
      
 1127 
     | 
    
         
            +
                                        }
         
     | 
| 
      
 1128 
     | 
    
         
            +
                                    ],
         
     | 
| 
      
 1129 
     | 
    
         
            +
                                    "container_image_name": None,
         
     | 
| 
      
 1130 
     | 
    
         
            +
                                    "container_image_tag": None,
         
     | 
| 
      
 1131 
     | 
    
         
            +
                                    "workspace": "default",
         
     | 
| 
      
 1132 
     | 
    
         
            +
                                    "target_directory": None,
         
     | 
| 
      
 1133 
     | 
    
         
            +
                                }
         
     | 
| 
      
 1134 
     | 
    
         
            +
                            ],
         
     | 
| 
      
 1135 
     | 
    
         
            +
                            "workspaces": [],
         
     | 
| 
      
 1136 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1137 
     | 
    
         
            +
                        f,
         
     | 
| 
      
 1138 
     | 
    
         
            +
                    )
         
     | 
| 
      
 1139 
     | 
    
         
            +
             
     | 
| 
      
 1140 
     | 
    
         
            +
                # AND the workflow pull API call returns a zip file with updated metadata
         
     | 
| 
      
 1141 
     | 
    
         
            +
                updated_label = "Updated Label"
         
     | 
| 
      
 1142 
     | 
    
         
            +
                vellum_client.workflows.pull.return_value = iter(
         
     | 
| 
      
 1143 
     | 
    
         
            +
                    [
         
     | 
| 
      
 1144 
     | 
    
         
            +
                        _zip_file_map(
         
     | 
| 
      
 1145 
     | 
    
         
            +
                            {
         
     | 
| 
      
 1146 
     | 
    
         
            +
                                "workflow.py": "print('hello')",
         
     | 
| 
      
 1147 
     | 
    
         
            +
                                "metadata.json": json.dumps(
         
     | 
| 
      
 1148 
     | 
    
         
            +
                                    {
         
     | 
| 
      
 1149 
     | 
    
         
            +
                                        "deployment_id": deployment_id,
         
     | 
| 
      
 1150 
     | 
    
         
            +
                                        "deployment_name": deployment_name,
         
     | 
| 
      
 1151 
     | 
    
         
            +
                                        "label": updated_label,
         
     | 
| 
      
 1152 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 1153 
     | 
    
         
            +
                                ),
         
     | 
| 
      
 1154 
     | 
    
         
            +
                            }
         
     | 
| 
      
 1155 
     | 
    
         
            +
                        )
         
     | 
| 
      
 1156 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 1157 
     | 
    
         
            +
                )
         
     | 
| 
      
 1158 
     | 
    
         
            +
             
     | 
| 
      
 1159 
     | 
    
         
            +
                # WHEN the user runs the pull command with the workflow deployment
         
     | 
| 
      
 1160 
     | 
    
         
            +
                runner = CliRunner()
         
     | 
| 
      
 1161 
     | 
    
         
            +
                identifier_to_use = get_identifier(deployment_id)
         
     | 
| 
      
 1162 
     | 
    
         
            +
                result = runner.invoke(cli_main, ["workflows", "pull", "--workflow-deployment", identifier_to_use])
         
     | 
| 
      
 1163 
     | 
    
         
            +
             
     | 
| 
      
 1164 
     | 
    
         
            +
                # THEN the command returns successfully
         
     | 
| 
      
 1165 
     | 
    
         
            +
                assert result.exit_code == 0
         
     | 
| 
      
 1166 
     | 
    
         
            +
             
     | 
| 
      
 1167 
     | 
    
         
            +
                # AND the deployment info is updated in the config
         
     | 
| 
      
 1168 
     | 
    
         
            +
                with open(vellum_lock_json) as f:
         
     | 
| 
      
 1169 
     | 
    
         
            +
                    lock_data = json.loads(f.read())
         
     | 
| 
      
 1170 
     | 
    
         
            +
                    assert len(lock_data["workflows"]) == 1
         
     | 
| 
      
 1171 
     | 
    
         
            +
                    assert len(lock_data["workflows"][0]["deployments"]) == 1
         
     | 
| 
      
 1172 
     | 
    
         
            +
                    deployment = lock_data["workflows"][0]["deployments"][0]
         
     | 
| 
      
 1173 
     | 
    
         
            +
                    assert str(deployment["id"]) == deployment_id
         
     | 
| 
      
 1174 
     | 
    
         
            +
                    assert deployment["name"] == deployment_name
         
     | 
| 
      
 1175 
     | 
    
         
            +
                    assert deployment["label"] == updated_label
         
     | 
| 
      
 1176 
     | 
    
         
            +
             
     | 
| 
      
 1177 
     | 
    
         
            +
                os.chdir(current_dir)
         
     | 
| 
      
 1178 
     | 
    
         
            +
             
     | 
| 
      
 1179 
     | 
    
         
            +
             
     | 
| 
      
 1180 
     | 
    
         
            +
            def test_pull__workflow_deployment_with_name_and_id(vellum_client):
         
     | 
| 
      
 1181 
     | 
    
         
            +
                """
         
     | 
| 
      
 1182 
     | 
    
         
            +
                This test is to ensure that pulling with id and name will not add a new deployment to the config
         
     | 
| 
      
 1183 
     | 
    
         
            +
                """
         
     | 
| 
      
 1184 
     | 
    
         
            +
                # GIVEN a workflow deployment ID
         
     | 
| 
      
 1185 
     | 
    
         
            +
                deployment_id = str(uuid4())  # config will always use the deployment_id return from the API
         
     | 
| 
      
 1186 
     | 
    
         
            +
                deployment_name = "Test Deployment"
         
     | 
| 
      
 1187 
     | 
    
         
            +
                deployment_label = "Test Label"
         
     | 
| 
      
 1188 
     | 
    
         
            +
             
     | 
| 
      
 1189 
     | 
    
         
            +
                # AND the workflow pull API call returns a zip file with metadata
         
     | 
| 
      
 1190 
     | 
    
         
            +
                vellum_client.workflows.pull.return_value = iter(
         
     | 
| 
      
 1191 
     | 
    
         
            +
                    [
         
     | 
| 
      
 1192 
     | 
    
         
            +
                        _zip_file_map(
         
     | 
| 
      
 1193 
     | 
    
         
            +
                            {
         
     | 
| 
      
 1194 
     | 
    
         
            +
                                "workflow.py": "print('hello')",
         
     | 
| 
      
 1195 
     | 
    
         
            +
                                "metadata.json": json.dumps(
         
     | 
| 
      
 1196 
     | 
    
         
            +
                                    {
         
     | 
| 
      
 1197 
     | 
    
         
            +
                                        "deployment_id": deployment_id,
         
     | 
| 
      
 1198 
     | 
    
         
            +
                                        "deployment_name": deployment_name,
         
     | 
| 
      
 1199 
     | 
    
         
            +
                                        "label": deployment_label,
         
     | 
| 
      
 1200 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 1201 
     | 
    
         
            +
                                ),
         
     | 
| 
      
 1202 
     | 
    
         
            +
                            }
         
     | 
| 
      
 1203 
     | 
    
         
            +
                        )
         
     | 
| 
      
 1204 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 1205 
     | 
    
         
            +
                )
         
     | 
| 
      
 1206 
     | 
    
         
            +
             
     | 
| 
      
 1207 
     | 
    
         
            +
                # AND we are currently in a new directory
         
     | 
| 
      
 1208 
     | 
    
         
            +
                current_dir = os.getcwd()
         
     | 
| 
      
 1209 
     | 
    
         
            +
                temp_dir = tempfile.mkdtemp()
         
     | 
| 
      
 1210 
     | 
    
         
            +
                os.chdir(temp_dir)
         
     | 
| 
      
 1211 
     | 
    
         
            +
             
     | 
| 
      
 1212 
     | 
    
         
            +
                # WHEN the user runs the pull command with the workflow deployment
         
     | 
| 
      
 1213 
     | 
    
         
            +
                runner = CliRunner()
         
     | 
| 
      
 1214 
     | 
    
         
            +
                result = runner.invoke(cli_main, ["workflows", "pull", "--workflow-deployment", deployment_id])
         
     | 
| 
      
 1215 
     | 
    
         
            +
             
     | 
| 
      
 1216 
     | 
    
         
            +
                # THEN the command returns successfully
         
     | 
| 
      
 1217 
     | 
    
         
            +
                assert result.exit_code == 0
         
     | 
| 
      
 1218 
     | 
    
         
            +
             
     | 
| 
      
 1219 
     | 
    
         
            +
                # AND the deployment is saved in the config
         
     | 
| 
      
 1220 
     | 
    
         
            +
                vellum_lock_json = os.path.join(temp_dir, "vellum.lock.json")
         
     | 
| 
      
 1221 
     | 
    
         
            +
                assert os.path.exists(vellum_lock_json)
         
     | 
| 
      
 1222 
     | 
    
         
            +
                with open(vellum_lock_json) as f:
         
     | 
| 
      
 1223 
     | 
    
         
            +
                    lock_data = json.loads(f.read())
         
     | 
| 
      
 1224 
     | 
    
         
            +
                    assert len(lock_data["workflows"]) == 1
         
     | 
| 
      
 1225 
     | 
    
         
            +
                    assert len(lock_data["workflows"][0]["deployments"]) == 1
         
     | 
| 
      
 1226 
     | 
    
         
            +
                    deployment = lock_data["workflows"][0]["deployments"][0]
         
     | 
| 
      
 1227 
     | 
    
         
            +
                    assert str(deployment["id"]) == deployment_id
         
     | 
| 
      
 1228 
     | 
    
         
            +
                    assert deployment["name"] == deployment_name
         
     | 
| 
      
 1229 
     | 
    
         
            +
                    assert deployment["label"] == deployment_label
         
     | 
| 
      
 1230 
     | 
    
         
            +
             
     | 
| 
      
 1231 
     | 
    
         
            +
                os.chdir(current_dir)
         
     | 
| 
      
 1232 
     | 
    
         
            +
             
     | 
| 
      
 1233 
     | 
    
         
            +
                # AND pull with name will not add a new deployment to the config
         
     | 
| 
      
 1234 
     | 
    
         
            +
                vellum_client.workflows.pull.return_value = iter(
         
     | 
| 
      
 1235 
     | 
    
         
            +
                    [
         
     | 
| 
      
 1236 
     | 
    
         
            +
                        _zip_file_map(
         
     | 
| 
      
 1237 
     | 
    
         
            +
                            {
         
     | 
| 
      
 1238 
     | 
    
         
            +
                                "workflow.py": "print('hello')",
         
     | 
| 
      
 1239 
     | 
    
         
            +
                                "metadata.json": json.dumps(
         
     | 
| 
      
 1240 
     | 
    
         
            +
                                    {
         
     | 
| 
      
 1241 
     | 
    
         
            +
                                        "deployment_id": deployment_id,
         
     | 
| 
      
 1242 
     | 
    
         
            +
                                        "deployment_name": deployment_name,
         
     | 
| 
      
 1243 
     | 
    
         
            +
                                        "label": deployment_label,
         
     | 
| 
      
 1244 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 1245 
     | 
    
         
            +
                                ),
         
     | 
| 
      
 1246 
     | 
    
         
            +
                            }
         
     | 
| 
      
 1247 
     | 
    
         
            +
                        )
         
     | 
| 
      
 1248 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 1249 
     | 
    
         
            +
                )
         
     | 
| 
      
 1250 
     | 
    
         
            +
             
     | 
| 
      
 1251 
     | 
    
         
            +
                os.chdir(temp_dir)
         
     | 
| 
      
 1252 
     | 
    
         
            +
                result = runner.invoke(cli_main, ["workflows", "pull", "--workflow-deployment", deployment_name])
         
     | 
| 
      
 1253 
     | 
    
         
            +
                assert result.exit_code == 0
         
     | 
| 
      
 1254 
     | 
    
         
            +
                with open(vellum_lock_json) as f:
         
     | 
| 
      
 1255 
     | 
    
         
            +
                    lock_data = json.loads(f.read())
         
     | 
| 
      
 1256 
     | 
    
         
            +
                    assert len(lock_data["workflows"][0]["deployments"]) == 1
         
     | 
| 
      
 1257 
     | 
    
         
            +
                    assert lock_data["workflows"][0]["deployments"][0]["id"] == deployment_id
         
     | 
| 
      
 1258 
     | 
    
         
            +
                    assert lock_data["workflows"][0]["deployments"][0]["name"] == deployment_name
         
     | 
| 
      
 1259 
     | 
    
         
            +
                    assert lock_data["workflows"][0]["deployments"][0]["label"] == deployment_label
         
     | 
| 
      
 1260 
     | 
    
         
            +
             
     | 
| 
      
 1261 
     | 
    
         
            +
                os.chdir(current_dir)
         
     | 
| 
         @@ -12,8 +12,7 @@ from vellum_ee.workflows.server.virtual_file_loader import VirtualFileFinder 
     | 
|
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
            def test_load_workflow_event_display_context():
         
     | 
| 
       15 
     | 
    
         
            -
                 
     | 
| 
       16 
     | 
    
         
            -
                from vellum_ee.workflows.display.types import WorkflowEventDisplayContext
         
     | 
| 
      
 15 
     | 
    
         
            +
                from vellum.workflows.events.workflow import WorkflowEventDisplayContext
         
     | 
| 
       17 
16 
     | 
    
         | 
| 
       18 
17 
     | 
    
         
             
                # We are actually just ensuring there are no circular dependencies when
         
     | 
| 
       19 
18 
     | 
    
         
             
                # our Workflow Server imports this class.
         
     | 
| 
         @@ -140,3 +139,358 @@ class CodeExecutionNode(BaseCodeExecutionNode[BaseState, int]): 
     | 
|
| 
       140 
139 
     | 
    
         | 
| 
       141 
140 
     | 
    
         
             
                # AND we get the code execution result
         
     | 
| 
       142 
141 
     | 
    
         
             
                assert event.body.outputs == {"final_output": 5.0}
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
            def test_load_from_module__simple_code_execution_node_with_try(
         
     | 
| 
      
 145 
     | 
    
         
            +
                vellum_client,
         
     | 
| 
      
 146 
     | 
    
         
            +
            ):
         
     | 
| 
      
 147 
     | 
    
         
            +
                # GIVEN a simple Python script
         
     | 
| 
      
 148 
     | 
    
         
            +
                py_code = """def main() -> int:
         
     | 
| 
      
 149 
     | 
    
         
            +
                print("Hello")
         
     | 
| 
      
 150 
     | 
    
         
            +
                return 1
         
     | 
| 
      
 151 
     | 
    
         
            +
            """
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                # AND a workflow module with only a code execution node
         
     | 
| 
      
 154 
     | 
    
         
            +
                files = {
         
     | 
| 
      
 155 
     | 
    
         
            +
                    "__init__.py": "",
         
     | 
| 
      
 156 
     | 
    
         
            +
                    "workflow.py": """
         
     | 
| 
      
 157 
     | 
    
         
            +
            from vellum.workflows import BaseWorkflow
         
     | 
| 
      
 158 
     | 
    
         
            +
            from vellum.workflows.state import BaseState
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
            from .nodes.code_execution_node import CodeExecutionNode
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
            class Workflow(BaseWorkflow):
         
     | 
| 
      
 163 
     | 
    
         
            +
                graph = CodeExecutionNode
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
                class Outputs(BaseWorkflow.Outputs):
         
     | 
| 
      
 166 
     | 
    
         
            +
                   final_output = CodeExecutionNode.Outputs.result
         
     | 
| 
      
 167 
     | 
    
         
            +
            """,
         
     | 
| 
      
 168 
     | 
    
         
            +
                    "nodes/__init__.py": """
         
     | 
| 
      
 169 
     | 
    
         
            +
            from .code_execution_node import CodeExecutionNode
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
            __all__ = ["CodeExecutionNode"]
         
     | 
| 
      
 172 
     | 
    
         
            +
            """,
         
     | 
| 
      
 173 
     | 
    
         
            +
                    "nodes/code_execution_node/__init__.py": """
         
     | 
| 
      
 174 
     | 
    
         
            +
            from typing import Union
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
            from vellum.workflows.nodes.core import TryNode
         
     | 
| 
      
 177 
     | 
    
         
            +
            from vellum.workflows.nodes.displayable import CodeExecutionNode as BaseCodeExecutionNode
         
     | 
| 
      
 178 
     | 
    
         
            +
            from vellum.workflows.state import BaseState
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
            @TryNode.wrap()
         
     | 
| 
      
 181 
     | 
    
         
            +
            class CodeExecutionNode(BaseCodeExecutionNode[BaseState, Union[float, int]]):
         
     | 
| 
      
 182 
     | 
    
         
            +
                filepath = "./script.py"
         
     | 
| 
      
 183 
     | 
    
         
            +
                code_inputs = {}
         
     | 
| 
      
 184 
     | 
    
         
            +
                runtime = "PYTHON_3_11_6"
         
     | 
| 
      
 185 
     | 
    
         
            +
                packages = []
         
     | 
| 
      
 186 
     | 
    
         
            +
            """,
         
     | 
| 
      
 187 
     | 
    
         
            +
                    "nodes/code_execution_node/script.py": py_code,
         
     | 
| 
      
 188 
     | 
    
         
            +
                }
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
                namespace = str(uuid4())
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                # AND the virtual file loader is registered
         
     | 
| 
      
 193 
     | 
    
         
            +
                finder = VirtualFileFinder(files, namespace)
         
     | 
| 
      
 194 
     | 
    
         
            +
                sys.meta_path.append(finder)
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
                # AND we know what the Code Execution Node will respond with
         
     | 
| 
      
 197 
     | 
    
         
            +
                mock_code_execution = CodeExecutorResponse(
         
     | 
| 
      
 198 
     | 
    
         
            +
                    log="hello",
         
     | 
| 
      
 199 
     | 
    
         
            +
                    output=NumberVellumValue(value=1),
         
     | 
| 
      
 200 
     | 
    
         
            +
                )
         
     | 
| 
      
 201 
     | 
    
         
            +
                vellum_client.execute_code.return_value = mock_code_execution
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
                # WHEN the workflow is loaded
         
     | 
| 
      
 204 
     | 
    
         
            +
                Workflow = BaseWorkflow.load_from_module(namespace)
         
     | 
| 
      
 205 
     | 
    
         
            +
                workflow = Workflow(context=WorkflowContext(generated_files=files))
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
                # THEN the workflow is successfully initialized
         
     | 
| 
      
 208 
     | 
    
         
            +
                assert workflow
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
                # WHEN we run the workflow
         
     | 
| 
      
 211 
     | 
    
         
            +
                event = workflow.run()
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                # THEN the execution is fulfilled
         
     | 
| 
      
 214 
     | 
    
         
            +
                assert event.name == "workflow.execution.fulfilled"
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
                # AND we get the code execution result
         
     | 
| 
      
 217 
     | 
    
         
            +
                assert event.body.outputs == {"final_output": 1.0}
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
            def test_load_from_module__simple_code_execution_node_with_retry(
         
     | 
| 
      
 221 
     | 
    
         
            +
                vellum_client,
         
     | 
| 
      
 222 
     | 
    
         
            +
            ):
         
     | 
| 
      
 223 
     | 
    
         
            +
                # GIVEN a simple Python script
         
     | 
| 
      
 224 
     | 
    
         
            +
                py_code = """def main() -> int:
         
     | 
| 
      
 225 
     | 
    
         
            +
                print("Hello")
         
     | 
| 
      
 226 
     | 
    
         
            +
                return 1
         
     | 
| 
      
 227 
     | 
    
         
            +
            """
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
                # AND a workflow module with only a code execution node wrapped with RetryNode
         
     | 
| 
      
 230 
     | 
    
         
            +
                files = {
         
     | 
| 
      
 231 
     | 
    
         
            +
                    "__init__.py": "",
         
     | 
| 
      
 232 
     | 
    
         
            +
                    "workflow.py": """
         
     | 
| 
      
 233 
     | 
    
         
            +
            from vellum.workflows import BaseWorkflow
         
     | 
| 
      
 234 
     | 
    
         
            +
            from vellum.workflows.state import BaseState
         
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
      
 236 
     | 
    
         
            +
            from .nodes.code_execution_node import CodeExecutionNode
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
            class Workflow(BaseWorkflow):
         
     | 
| 
      
 239 
     | 
    
         
            +
                graph = CodeExecutionNode
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
                class Outputs(BaseWorkflow.Outputs):
         
     | 
| 
      
 242 
     | 
    
         
            +
                   final_output = CodeExecutionNode.Outputs.result
         
     | 
| 
      
 243 
     | 
    
         
            +
            """,
         
     | 
| 
      
 244 
     | 
    
         
            +
                    "nodes/__init__.py": """
         
     | 
| 
      
 245 
     | 
    
         
            +
            from .code_execution_node import CodeExecutionNode
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
            __all__ = ["CodeExecutionNode"]
         
     | 
| 
      
 248 
     | 
    
         
            +
            """,
         
     | 
| 
      
 249 
     | 
    
         
            +
                    "nodes/code_execution_node/__init__.py": """
         
     | 
| 
      
 250 
     | 
    
         
            +
            from typing import Union
         
     | 
| 
      
 251 
     | 
    
         
            +
             
     | 
| 
      
 252 
     | 
    
         
            +
            from vellum.workflows.nodes.core.retry_node.node import RetryNode
         
     | 
| 
      
 253 
     | 
    
         
            +
            from vellum.workflows.nodes.displayable import CodeExecutionNode as BaseCodeExecutionNode
         
     | 
| 
      
 254 
     | 
    
         
            +
            from vellum.workflows.state import BaseState
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
            @RetryNode.wrap(max_attempts=3)
         
     | 
| 
      
 257 
     | 
    
         
            +
            class CodeExecutionNode(BaseCodeExecutionNode[BaseState, Union[float, int]]):
         
     | 
| 
      
 258 
     | 
    
         
            +
                filepath = "./script.py"
         
     | 
| 
      
 259 
     | 
    
         
            +
                code_inputs = {}
         
     | 
| 
      
 260 
     | 
    
         
            +
                runtime = "PYTHON_3_11_6"
         
     | 
| 
      
 261 
     | 
    
         
            +
                packages = []
         
     | 
| 
      
 262 
     | 
    
         
            +
            """,
         
     | 
| 
      
 263 
     | 
    
         
            +
                    "nodes/code_execution_node/script.py": py_code,
         
     | 
| 
      
 264 
     | 
    
         
            +
                }
         
     | 
| 
      
 265 
     | 
    
         
            +
             
     | 
| 
      
 266 
     | 
    
         
            +
                namespace = str(uuid4())
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
                # AND the virtual file loader is registered
         
     | 
| 
      
 269 
     | 
    
         
            +
                finder = VirtualFileFinder(files, namespace)
         
     | 
| 
      
 270 
     | 
    
         
            +
                sys.meta_path.append(finder)
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
                # AND we know what the Code Execution Node will respond with
         
     | 
| 
      
 273 
     | 
    
         
            +
                mock_code_execution = CodeExecutorResponse(
         
     | 
| 
      
 274 
     | 
    
         
            +
                    log="hello",
         
     | 
| 
      
 275 
     | 
    
         
            +
                    output=NumberVellumValue(value=1),
         
     | 
| 
      
 276 
     | 
    
         
            +
                )
         
     | 
| 
      
 277 
     | 
    
         
            +
                vellum_client.execute_code.return_value = mock_code_execution
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
                # WHEN the workflow is loaded
         
     | 
| 
      
 280 
     | 
    
         
            +
                Workflow = BaseWorkflow.load_from_module(namespace)
         
     | 
| 
      
 281 
     | 
    
         
            +
                workflow = Workflow(context=WorkflowContext(generated_files=files))
         
     | 
| 
      
 282 
     | 
    
         
            +
             
     | 
| 
      
 283 
     | 
    
         
            +
                # THEN the workflow is successfully initialized
         
     | 
| 
      
 284 
     | 
    
         
            +
                assert workflow
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
      
 286 
     | 
    
         
            +
                # WHEN we run the workflow
         
     | 
| 
      
 287 
     | 
    
         
            +
                event = workflow.run()
         
     | 
| 
      
 288 
     | 
    
         
            +
             
     | 
| 
      
 289 
     | 
    
         
            +
                # THEN the execution is fulfilled
         
     | 
| 
      
 290 
     | 
    
         
            +
                assert event.name == "workflow.execution.fulfilled"
         
     | 
| 
      
 291 
     | 
    
         
            +
             
     | 
| 
      
 292 
     | 
    
         
            +
                # AND we get the code execution result
         
     | 
| 
      
 293 
     | 
    
         
            +
                assert event.body.outputs == {"final_output": 1.0}
         
     | 
| 
      
 294 
     | 
    
         
            +
             
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
            def test_load_from_module__code_execution_within_subworkflow(
         
     | 
| 
      
 297 
     | 
    
         
            +
                vellum_client,
         
     | 
| 
      
 298 
     | 
    
         
            +
            ):
         
     | 
| 
      
 299 
     | 
    
         
            +
                # GIVEN a simple Python script
         
     | 
| 
      
 300 
     | 
    
         
            +
                py_code = """def main() -> int:
         
     | 
| 
      
 301 
     | 
    
         
            +
                print("Hello")
         
     | 
| 
      
 302 
     | 
    
         
            +
                return 1
         
     | 
| 
      
 303 
     | 
    
         
            +
            """
         
     | 
| 
      
 304 
     | 
    
         
            +
             
     | 
| 
      
 305 
     | 
    
         
            +
                # AND a workflow module with a subworkflow containing a code execution node
         
     | 
| 
      
 306 
     | 
    
         
            +
                files = {
         
     | 
| 
      
 307 
     | 
    
         
            +
                    "__init__.py": "",
         
     | 
| 
      
 308 
     | 
    
         
            +
                    "workflow.py": """
         
     | 
| 
      
 309 
     | 
    
         
            +
            from vellum.workflows import BaseWorkflow
         
     | 
| 
      
 310 
     | 
    
         
            +
            from vellum.workflows.state import BaseState
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
            from .nodes.subworkflow import Subworkflow
         
     | 
| 
      
 313 
     | 
    
         
            +
             
     | 
| 
      
 314 
     | 
    
         
            +
            class Workflow(BaseWorkflow):
         
     | 
| 
      
 315 
     | 
    
         
            +
                graph = Subworkflow
         
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
      
 317 
     | 
    
         
            +
                class Outputs(BaseWorkflow.Outputs):
         
     | 
| 
      
 318 
     | 
    
         
            +
                   final_output = Subworkflow.Outputs.result
         
     | 
| 
      
 319 
     | 
    
         
            +
            """,
         
     | 
| 
      
 320 
     | 
    
         
            +
                    "nodes/__init__.py": """
         
     | 
| 
      
 321 
     | 
    
         
            +
            from .subworkflow import Subworkflow
         
     | 
| 
      
 322 
     | 
    
         
            +
             
     | 
| 
      
 323 
     | 
    
         
            +
            __all__ = ["Subworkflow"]
         
     | 
| 
      
 324 
     | 
    
         
            +
            """,
         
     | 
| 
      
 325 
     | 
    
         
            +
                    "nodes/subworkflow/__init__.py": """
         
     | 
| 
      
 326 
     | 
    
         
            +
            from vellum.workflows.nodes.displayable import InlineSubworkflowNode
         
     | 
| 
      
 327 
     | 
    
         
            +
             
     | 
| 
      
 328 
     | 
    
         
            +
            from .workflow import SubworkflowWorkflow
         
     | 
| 
      
 329 
     | 
    
         
            +
             
     | 
| 
      
 330 
     | 
    
         
            +
            class Subworkflow(InlineSubworkflowNode):
         
     | 
| 
      
 331 
     | 
    
         
            +
                subworkflow = SubworkflowWorkflow
         
     | 
| 
      
 332 
     | 
    
         
            +
            """,
         
     | 
| 
      
 333 
     | 
    
         
            +
                    "nodes/subworkflow/nodes/__init__.py": """
         
     | 
| 
      
 334 
     | 
    
         
            +
            from .code_execution_node import CodeExecutionNode
         
     | 
| 
      
 335 
     | 
    
         
            +
             
     | 
| 
      
 336 
     | 
    
         
            +
            __all__ = ["CodeExecutionNode"]
         
     | 
| 
      
 337 
     | 
    
         
            +
            """,
         
     | 
| 
      
 338 
     | 
    
         
            +
                    "nodes/subworkflow/nodes/code_execution_node/__init__.py": """
         
     | 
| 
      
 339 
     | 
    
         
            +
            from typing import Union
         
     | 
| 
      
 340 
     | 
    
         
            +
             
     | 
| 
      
 341 
     | 
    
         
            +
            from vellum.workflows.nodes.displayable import CodeExecutionNode as BaseCodeExecutionNode
         
     | 
| 
      
 342 
     | 
    
         
            +
            from vellum.workflows.state import BaseState
         
     | 
| 
      
 343 
     | 
    
         
            +
             
     | 
| 
      
 344 
     | 
    
         
            +
            class CodeExecutionNode(BaseCodeExecutionNode[BaseState, Union[float, int]]):
         
     | 
| 
      
 345 
     | 
    
         
            +
                filepath = "./script.py"
         
     | 
| 
      
 346 
     | 
    
         
            +
                code_inputs = {}
         
     | 
| 
      
 347 
     | 
    
         
            +
                runtime = "PYTHON_3_11_6"
         
     | 
| 
      
 348 
     | 
    
         
            +
                packages = []
         
     | 
| 
      
 349 
     | 
    
         
            +
            """,
         
     | 
| 
      
 350 
     | 
    
         
            +
                    "nodes/subworkflow/nodes/code_execution_node/script.py": py_code,
         
     | 
| 
      
 351 
     | 
    
         
            +
                    "nodes/subworkflow/workflow.py": """
         
     | 
| 
      
 352 
     | 
    
         
            +
            from vellum.workflows import BaseWorkflow
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
            from .nodes.code_execution_node import CodeExecutionNode
         
     | 
| 
      
 355 
     | 
    
         
            +
             
     | 
| 
      
 356 
     | 
    
         
            +
            class SubworkflowWorkflow(BaseWorkflow):
         
     | 
| 
      
 357 
     | 
    
         
            +
                graph = CodeExecutionNode
         
     | 
| 
      
 358 
     | 
    
         
            +
             
     | 
| 
      
 359 
     | 
    
         
            +
                class Outputs(BaseWorkflow.Outputs):
         
     | 
| 
      
 360 
     | 
    
         
            +
                    result = CodeExecutionNode.Outputs.result
         
     | 
| 
      
 361 
     | 
    
         
            +
            """,
         
     | 
| 
      
 362 
     | 
    
         
            +
                }
         
     | 
| 
      
 363 
     | 
    
         
            +
             
     | 
| 
      
 364 
     | 
    
         
            +
                namespace = str(uuid4())
         
     | 
| 
      
 365 
     | 
    
         
            +
             
     | 
| 
      
 366 
     | 
    
         
            +
                # AND the virtual file loader is registered
         
     | 
| 
      
 367 
     | 
    
         
            +
                finder = VirtualFileFinder(files, namespace)
         
     | 
| 
      
 368 
     | 
    
         
            +
                sys.meta_path.append(finder)
         
     | 
| 
      
 369 
     | 
    
         
            +
             
     | 
| 
      
 370 
     | 
    
         
            +
                # AND we know what the Code Execution Node will respond with
         
     | 
| 
      
 371 
     | 
    
         
            +
                mock_code_execution = CodeExecutorResponse(
         
     | 
| 
      
 372 
     | 
    
         
            +
                    log="hello",
         
     | 
| 
      
 373 
     | 
    
         
            +
                    output=NumberVellumValue(value=1),
         
     | 
| 
      
 374 
     | 
    
         
            +
                )
         
     | 
| 
      
 375 
     | 
    
         
            +
                vellum_client.execute_code.return_value = mock_code_execution
         
     | 
| 
      
 376 
     | 
    
         
            +
             
     | 
| 
      
 377 
     | 
    
         
            +
                # WHEN the workflow is loaded
         
     | 
| 
      
 378 
     | 
    
         
            +
                Workflow = BaseWorkflow.load_from_module(namespace)
         
     | 
| 
      
 379 
     | 
    
         
            +
                workflow = Workflow(context=WorkflowContext(generated_files=files))
         
     | 
| 
      
 380 
     | 
    
         
            +
             
     | 
| 
      
 381 
     | 
    
         
            +
                # THEN the workflow is successfully initialized
         
     | 
| 
      
 382 
     | 
    
         
            +
                assert workflow
         
     | 
| 
      
 383 
     | 
    
         
            +
             
     | 
| 
      
 384 
     | 
    
         
            +
                # WHEN we run the workflow
         
     | 
| 
      
 385 
     | 
    
         
            +
                event = workflow.run()
         
     | 
| 
      
 386 
     | 
    
         
            +
             
     | 
| 
      
 387 
     | 
    
         
            +
                # THEN the execution is fulfilled
         
     | 
| 
      
 388 
     | 
    
         
            +
                assert event.name == "workflow.execution.fulfilled"
         
     | 
| 
      
 389 
     | 
    
         
            +
             
     | 
| 
      
 390 
     | 
    
         
            +
                # AND we get the code execution result from the subworkflow
         
     | 
| 
      
 391 
     | 
    
         
            +
                assert event.body.outputs == {"final_output": 1.0}
         
     | 
| 
      
 392 
     | 
    
         
            +
             
     | 
| 
      
 393 
     | 
    
         
            +
             
     | 
| 
      
 394 
     | 
    
         
            +
            def test_load_from_module__code_execution_within_map_node(
         
     | 
| 
      
 395 
     | 
    
         
            +
                vellum_client,
         
     | 
| 
      
 396 
     | 
    
         
            +
            ):
         
     | 
| 
      
 397 
     | 
    
         
            +
                # GIVEN a simple Python script
         
     | 
| 
      
 398 
     | 
    
         
            +
                py_code = """def main() -> int:
         
     | 
| 
      
 399 
     | 
    
         
            +
                print("Hello")
         
     | 
| 
      
 400 
     | 
    
         
            +
                return 1
         
     | 
| 
      
 401 
     | 
    
         
            +
            """
         
     | 
| 
      
 402 
     | 
    
         
            +
             
     | 
| 
      
 403 
     | 
    
         
            +
                # AND a workflow module with a map node containing a code execution node
         
     | 
| 
      
 404 
     | 
    
         
            +
                files = {
         
     | 
| 
      
 405 
     | 
    
         
            +
                    "__init__.py": "",
         
     | 
| 
      
 406 
     | 
    
         
            +
                    "workflow.py": """
         
     | 
| 
      
 407 
     | 
    
         
            +
            from vellum.workflows import BaseWorkflow
         
     | 
| 
      
 408 
     | 
    
         
            +
            from vellum.workflows.state import BaseState
         
     | 
| 
      
 409 
     | 
    
         
            +
             
     | 
| 
      
 410 
     | 
    
         
            +
            from .nodes.map_node import MapNode
         
     | 
| 
      
 411 
     | 
    
         
            +
             
     | 
| 
      
 412 
     | 
    
         
            +
            class Workflow(BaseWorkflow):
         
     | 
| 
      
 413 
     | 
    
         
            +
                graph = MapNode
         
     | 
| 
      
 414 
     | 
    
         
            +
                
         
     | 
| 
      
 415 
     | 
    
         
            +
                class Outputs(BaseWorkflow.Outputs):  # noqa: W293
         
     | 
| 
      
 416 
     | 
    
         
            +
                   results = MapNode.Outputs.final_output
         
     | 
| 
      
 417 
     | 
    
         
            +
            """,
         
     | 
| 
      
 418 
     | 
    
         
            +
                    "nodes/__init__.py": """
         
     | 
| 
      
 419 
     | 
    
         
            +
            from .map_node import MapNode
         
     | 
| 
      
 420 
     | 
    
         
            +
             
     | 
| 
      
 421 
     | 
    
         
            +
            __all__ = ["MapNode"]
         
     | 
| 
      
 422 
     | 
    
         
            +
            """,
         
     | 
| 
      
 423 
     | 
    
         
            +
                    "nodes/map_node/__init__.py": """
         
     | 
| 
      
 424 
     | 
    
         
            +
            from vellum.workflows.nodes.core.map_node import MapNode as BaseMapNode
         
     | 
| 
      
 425 
     | 
    
         
            +
             
     | 
| 
      
 426 
     | 
    
         
            +
            from .workflow import MapNodeWorkflow
         
     | 
| 
      
 427 
     | 
    
         
            +
             
     | 
| 
      
 428 
     | 
    
         
            +
            class MapNode(BaseMapNode):
         
     | 
| 
      
 429 
     | 
    
         
            +
                items = ["foo", "bar", "baz"]
         
     | 
| 
      
 430 
     | 
    
         
            +
                subworkflow = MapNodeWorkflow
         
     | 
| 
      
 431 
     | 
    
         
            +
                max_concurrency = 4
         
     | 
| 
      
 432 
     | 
    
         
            +
            """,
         
     | 
| 
      
 433 
     | 
    
         
            +
                    "nodes/map_node/nodes/__init__.py": """
         
     | 
| 
      
 434 
     | 
    
         
            +
            from .code_execution_node import CodeExecutionNode
         
     | 
| 
      
 435 
     | 
    
         
            +
             
     | 
| 
      
 436 
     | 
    
         
            +
            __all__ = ["CodeExecutionNode"]
         
     | 
| 
      
 437 
     | 
    
         
            +
            """,
         
     | 
| 
      
 438 
     | 
    
         
            +
                    "nodes/map_node/nodes/code_execution_node/__init__.py": """
         
     | 
| 
      
 439 
     | 
    
         
            +
            from typing import Union
         
     | 
| 
      
 440 
     | 
    
         
            +
             
     | 
| 
      
 441 
     | 
    
         
            +
            from vellum.workflows.nodes.displayable import CodeExecutionNode as BaseCodeExecutionNode
         
     | 
| 
      
 442 
     | 
    
         
            +
            from vellum.workflows.state import BaseState
         
     | 
| 
      
 443 
     | 
    
         
            +
             
     | 
| 
      
 444 
     | 
    
         
            +
            class CodeExecutionNode(BaseCodeExecutionNode[BaseState, Union[float, int]]):
         
     | 
| 
      
 445 
     | 
    
         
            +
                filepath = "./script.py"
         
     | 
| 
      
 446 
     | 
    
         
            +
                code_inputs = {}
         
     | 
| 
      
 447 
     | 
    
         
            +
                runtime = "PYTHON_3_11_6"
         
     | 
| 
      
 448 
     | 
    
         
            +
                packages = []
         
     | 
| 
      
 449 
     | 
    
         
            +
            """,
         
     | 
| 
      
 450 
     | 
    
         
            +
                    "nodes/map_node/nodes/code_execution_node/script.py": py_code,
         
     | 
| 
      
 451 
     | 
    
         
            +
                    "nodes/map_node/workflow.py": """
         
     | 
| 
      
 452 
     | 
    
         
            +
            from vellum.workflows import BaseWorkflow
         
     | 
| 
      
 453 
     | 
    
         
            +
            from vellum.workflows.state import BaseState
         
     | 
| 
      
 454 
     | 
    
         
            +
             
     | 
| 
      
 455 
     | 
    
         
            +
            from .nodes.code_execution_node import CodeExecutionNode
         
     | 
| 
      
 456 
     | 
    
         
            +
             
     | 
| 
      
 457 
     | 
    
         
            +
            class MapNodeInputs:
         
     | 
| 
      
 458 
     | 
    
         
            +
                item: str
         
     | 
| 
      
 459 
     | 
    
         
            +
                index: int
         
     | 
| 
      
 460 
     | 
    
         
            +
             
     | 
| 
      
 461 
     | 
    
         
            +
            class MapNodeWorkflow(BaseWorkflow):
         
     | 
| 
      
 462 
     | 
    
         
            +
                graph = CodeExecutionNode
         
     | 
| 
      
 463 
     | 
    
         
            +
                
         
     | 
| 
      
 464 
     | 
    
         
            +
                class Outputs(BaseWorkflow.Outputs):  # noqa: W293
         
     | 
| 
      
 465 
     | 
    
         
            +
                    final_output = CodeExecutionNode.Outputs.result
         
     | 
| 
      
 466 
     | 
    
         
            +
            """,
         
     | 
| 
      
 467 
     | 
    
         
            +
                }
         
     | 
| 
      
 468 
     | 
    
         
            +
             
     | 
| 
      
 469 
     | 
    
         
            +
                namespace = str(uuid4())
         
     | 
| 
      
 470 
     | 
    
         
            +
             
     | 
| 
      
 471 
     | 
    
         
            +
                # AND the virtual file loader is registered
         
     | 
| 
      
 472 
     | 
    
         
            +
                finder = VirtualFileFinder(files, namespace)
         
     | 
| 
      
 473 
     | 
    
         
            +
                sys.meta_path.append(finder)
         
     | 
| 
      
 474 
     | 
    
         
            +
             
     | 
| 
      
 475 
     | 
    
         
            +
                # AND we know what the Code Execution Node will respond with
         
     | 
| 
      
 476 
     | 
    
         
            +
                mock_code_execution = CodeExecutorResponse(
         
     | 
| 
      
 477 
     | 
    
         
            +
                    log="hello",
         
     | 
| 
      
 478 
     | 
    
         
            +
                    output=NumberVellumValue(value=3),
         
     | 
| 
      
 479 
     | 
    
         
            +
                )
         
     | 
| 
      
 480 
     | 
    
         
            +
                vellum_client.execute_code.return_value = mock_code_execution
         
     | 
| 
      
 481 
     | 
    
         
            +
             
     | 
| 
      
 482 
     | 
    
         
            +
                # WHEN the workflow is loaded
         
     | 
| 
      
 483 
     | 
    
         
            +
                Workflow = BaseWorkflow.load_from_module(namespace)
         
     | 
| 
      
 484 
     | 
    
         
            +
                workflow = Workflow(context=WorkflowContext(generated_files=files))
         
     | 
| 
      
 485 
     | 
    
         
            +
             
     | 
| 
      
 486 
     | 
    
         
            +
                # THEN the workflow is successfully initialized
         
     | 
| 
      
 487 
     | 
    
         
            +
                assert workflow
         
     | 
| 
      
 488 
     | 
    
         
            +
             
     | 
| 
      
 489 
     | 
    
         
            +
                # WHEN we run the workflow
         
     | 
| 
      
 490 
     | 
    
         
            +
                event = workflow.run()
         
     | 
| 
      
 491 
     | 
    
         
            +
             
     | 
| 
      
 492 
     | 
    
         
            +
                # THEN the execution is fulfilled
         
     | 
| 
      
 493 
     | 
    
         
            +
                assert event.name == "workflow.execution.fulfilled"
         
     | 
| 
      
 494 
     | 
    
         
            +
             
     | 
| 
      
 495 
     | 
    
         
            +
                # AND we get the map node results as a list
         
     | 
| 
      
 496 
     | 
    
         
            +
                assert event.body.outputs == {"results": [1.0, 1.0, 1.0]}
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     |