vellum-ai 0.13.15__py3-none-any.whl → 0.13.18__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vellum/client/core/client_wrapper.py +1 -1
 - vellum/client/resources/workflows/client.py +0 -10
 - vellum/workflows/nodes/core/templating_node/node.py +4 -47
 - vellum/workflows/nodes/displayable/code_execution_node/node.py +29 -23
 - vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py +169 -5
 - vellum/workflows/nodes/displayable/code_execution_node/utils.py +98 -1
 - vellum/workflows/nodes/utils.py +50 -1
 - vellum/workflows/references/external_input.py +14 -0
 - vellum/workflows/state/base.py +7 -0
 - vellum/workflows/state/tests/test_state.py +42 -0
 - {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.18.dist-info}/METADATA +1 -1
 - {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.18.dist-info}/RECORD +25 -24
 - vellum_cli/pull.py +57 -20
 - vellum_cli/push.py +1 -5
 - vellum_cli/tests/test_pull.py +115 -8
 - vellum_cli/tests/test_push.py +0 -8
 - vellum_ee/workflows/display/nodes/base_node_display.py +2 -2
 - vellum_ee/workflows/display/nodes/get_node_display_class.py +16 -20
 - vellum_ee/workflows/display/nodes/vellum/__init__.py +2 -0
 - vellum_ee/workflows/display/nodes/vellum/retry_node.py +10 -0
 - vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py +23 -0
 - vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py +2 -2
 - {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.18.dist-info}/LICENSE +0 -0
 - {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.18.dist-info}/WHEEL +0 -0
 - {vellum_ai-0.13.15.dist-info → vellum_ai-0.13.18.dist-info}/entry_points.txt +0 -0
 
| 
         @@ -64,6 +64,22 @@ def test_state_snapshot__nested_dictionary_edit(): 
     | 
|
| 
       64 
64 
     | 
    
         
             
                assert snapshot_count[id(state)] == 1
         
     | 
| 
       65 
65 
     | 
    
         | 
| 
       66 
66 
     | 
    
         | 
| 
      
 67 
     | 
    
         
            +
            def test_state_snapshot__external_input_edit():
         
     | 
| 
      
 68 
     | 
    
         
            +
                # GIVEN an initial state instance
         
     | 
| 
      
 69 
     | 
    
         
            +
                state = MockState(foo="bar")
         
     | 
| 
      
 70 
     | 
    
         
            +
                assert snapshot_count[id(state)] == 0
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                # WHEN we add an external input to state
         
     | 
| 
      
 73 
     | 
    
         
            +
                class MockExternalInputs(BaseNode.ExternalInputs):
         
     | 
| 
      
 74 
     | 
    
         
            +
                    message: str
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                # WHEN we edit external inputs dictionary
         
     | 
| 
      
 77 
     | 
    
         
            +
                state.meta.external_inputs[MockExternalInputs.message] = "hello"
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                # THEN the snapshot is emitted
         
     | 
| 
      
 80 
     | 
    
         
            +
                assert snapshot_count[id(state)] == 1
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
       67 
83 
     | 
    
         
             
            def test_state_deepcopy():
         
     | 
| 
       68 
84 
     | 
    
         
             
                # GIVEN an initial state instance
         
     | 
| 
       69 
85 
     | 
    
         
             
                state = MockState(foo="bar")
         
     | 
| 
         @@ -116,6 +132,32 @@ def test_state_json_serialization__with_node_output_updates(): 
     | 
|
| 
       116 
132 
     | 
    
         
             
                assert json_state["meta"]["node_outputs"] == {"MockNode.Outputs.baz": "hello"}
         
     | 
| 
       117 
133 
     | 
    
         | 
| 
       118 
134 
     | 
    
         | 
| 
      
 135 
     | 
    
         
            +
            def test_state_deepcopy__with_external_input_updates():
         
     | 
| 
      
 136 
     | 
    
         
            +
                # GIVEN an initial state instance
         
     | 
| 
      
 137 
     | 
    
         
            +
                state = MockState(foo="bar")
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                # AND we add an external input to state
         
     | 
| 
      
 140 
     | 
    
         
            +
                class MockExternalInputs(BaseNode.ExternalInputs):
         
     | 
| 
      
 141 
     | 
    
         
            +
                    message: str
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                state.meta.external_inputs[MockExternalInputs.message] = "hello"
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                # AND we deepcopy the state
         
     | 
| 
      
 146 
     | 
    
         
            +
                deepcopied_state = deepcopy(state)
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                # AND we update the original state
         
     | 
| 
      
 149 
     | 
    
         
            +
                state.meta.external_inputs[MockExternalInputs.message] = "world"
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
                # THEN the copied state is not updated
         
     | 
| 
      
 152 
     | 
    
         
            +
                assert deepcopied_state.meta.external_inputs[MockExternalInputs.message] == "hello"
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                # AND the original state has had the correct number of snapshots
         
     | 
| 
      
 155 
     | 
    
         
            +
                assert snapshot_count[id(state)] == 2
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                # AND the copied state has had the correct number of snapshots
         
     | 
| 
      
 158 
     | 
    
         
            +
                assert snapshot_count[id(deepcopied_state)] == 0
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
       119 
161 
     | 
    
         
             
            def test_state_json_serialization__with_queue():
         
     | 
| 
       120 
162 
     | 
    
         
             
                # GIVEN an initial state instance
         
     | 
| 
       121 
163 
     | 
    
         
             
                state = MockState(foo="bar")
         
     | 
| 
         @@ -6,29 +6,29 @@ vellum_cli/config.py,sha256=LVRB-SEJcpQYfg2QGcjKHmRSAijdSFADbS90gDY4AI8,6829 
     | 
|
| 
       6 
6 
     | 
    
         
             
            vellum_cli/image_push.py,sha256=SJwhwWJsLjwGNezNVd_oCVpFMfPsAB3dfLWmriZZUtw,4419
         
     | 
| 
       7 
7 
     | 
    
         
             
            vellum_cli/logger.py,sha256=PuRFa0WCh4sAGFS5aqWB0QIYpS6nBWwPJrIXpWxugV4,1022
         
     | 
| 
       8 
8 
     | 
    
         
             
            vellum_cli/ping.py,sha256=lWyJw6sziXjyTopTYRdFF5hV-sYPVDdX0yVbG5fzcY4,585
         
     | 
| 
       9 
     | 
    
         
            -
            vellum_cli/pull.py,sha256= 
     | 
| 
       10 
     | 
    
         
            -
            vellum_cli/push.py,sha256= 
     | 
| 
      
 9 
     | 
    
         
            +
            vellum_cli/pull.py,sha256=7yvg4oBOgsbBEsgXtCpYlNR4AOR8hPICamY-4HI-3kM,9031
         
     | 
| 
      
 10 
     | 
    
         
            +
            vellum_cli/push.py,sha256=qQCI_cHvVjeDGA8FLYmSN7UE_wIJQnUXX_5cGsm9OTs,9076
         
     | 
| 
       11 
11 
     | 
    
         
             
            vellum_cli/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       12 
12 
     | 
    
         
             
            vellum_cli/tests/conftest.py,sha256=AFYZryKA2qnUuCPBxBKmHLFoPiE0WhBFFej9tNwSHdc,1526
         
     | 
| 
       13 
13 
     | 
    
         
             
            vellum_cli/tests/test_config.py,sha256=uvKGDc8BoVyT9_H0Z-g8469zVxomn6Oi3Zj-vK7O_wU,2631
         
     | 
| 
       14 
14 
     | 
    
         
             
            vellum_cli/tests/test_main.py,sha256=qDZG-aQauPwBwM6A2DIu1494n47v3pL28XakTbLGZ-k,272
         
     | 
| 
       15 
15 
     | 
    
         
             
            vellum_cli/tests/test_ping.py,sha256=QtbhYKMYn1DFnDyBij2mkQO32j9KOpZ5Pf0yek7k_Ao,1284
         
     | 
| 
       16 
     | 
    
         
            -
            vellum_cli/tests/test_pull.py,sha256= 
     | 
| 
       17 
     | 
    
         
            -
            vellum_cli/tests/test_push.py,sha256= 
     | 
| 
      
 16 
     | 
    
         
            +
            vellum_cli/tests/test_pull.py,sha256=CEnVpb9i-_I0wOSabjgJxleRuvvAHFfDB0_f4CvpwMI,23742
         
     | 
| 
      
 17 
     | 
    
         
            +
            vellum_cli/tests/test_push.py,sha256=kcM8jp6vTRBwfk6cAC_tHa4Eliuy_zZ-X1DfIpSEIW0,18299
         
     | 
| 
       18 
18 
     | 
    
         
             
            vellum_ee/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       19 
19 
     | 
    
         
             
            vellum_ee/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       20 
20 
     | 
    
         
             
            vellum_ee/workflows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       21 
21 
     | 
    
         
             
            vellum_ee/workflows/display/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       22 
22 
     | 
    
         
             
            vellum_ee/workflows/display/base.py,sha256=3ZFUYRNKL24fBqXhKpa_Dq2W1a-a86J20dmJYA3H2eY,1755
         
     | 
| 
       23 
23 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/__init__.py,sha256=5XOcZJXYUgaLS55QgRJzyQ_W1tpeprjnYAeYVezqoGw,160
         
     | 
| 
       24 
     | 
    
         
            -
            vellum_ee/workflows/display/nodes/base_node_display.py,sha256= 
     | 
| 
      
 24 
     | 
    
         
            +
            vellum_ee/workflows/display/nodes/base_node_display.py,sha256=ErIK_1DYax0LlFX4AvV1oua8I7JlpXNncjGNadVe-bo,15801
         
     | 
| 
       25 
25 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/base_node_vellum_display.py,sha256=pLO0dORfRu--Ne9NgoyFT_CNjfpr5fGCsgbsMkUF5GM,2845
         
     | 
| 
       26 
     | 
    
         
            -
            vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256= 
     | 
| 
      
 26 
     | 
    
         
            +
            vellum_ee/workflows/display/nodes/get_node_display_class.py,sha256=0S6ksPp53WXWh1RQVH71nj2bkCWBj4ZaFYhTxW3N2F4,1230
         
     | 
| 
       27 
27 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       28 
28 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/tests/test_base_node_display.py,sha256=QqR3Ly0RNrXwOeLdW5nERDFt0gRPf76n1bPES6o5UN4,1093
         
     | 
| 
       29 
29 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/types.py,sha256=St1BB6no528OyELGiyRabWao0GGw6mLhstQAvEACbGk,247
         
     | 
| 
       30 
30 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/utils.py,sha256=sloya5TpXsnot1HURc9L51INwflRqUzHxRVnCS9Cd-4,973
         
     | 
| 
       31 
     | 
    
         
            -
            vellum_ee/workflows/display/nodes/vellum/__init__.py,sha256= 
     | 
| 
      
 31 
     | 
    
         
            +
            vellum_ee/workflows/display/nodes/vellum/__init__.py,sha256=Moeuvm0u7c_6wtxUWOJqTJYbrnG4Rp_5mKRoYpfewvQ,1578
         
     | 
| 
       32 
32 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/vellum/api_node.py,sha256=hoV-cUtS6H9kmRQXHd2py95GRWI_dAnnaPwvlNBkDOQ,8571
         
     | 
| 
       33 
33 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/vellum/code_execution_node.py,sha256=z00Z3L0d4PsUQo4S8FRDTtOFLtjdi17TJbatNVF4nM8,4288
         
     | 
| 
       34 
34 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/vellum/conditional_node.py,sha256=ybLIa4uclqVIy3VAQvI1ivg2tnK5Ug_1R5a69DFqL7E,11104
         
     | 
| 
         @@ -41,6 +41,7 @@ vellum_ee/workflows/display/nodes/vellum/map_node.py,sha256=VlO3UwkspCOdDQ-h3v8k 
     | 
|
| 
       41 
41 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/vellum/merge_node.py,sha256=HkNMgdQELiON42jdO-xDLmqrEKdGx1RVqrz2DXNTLS8,3239
         
     | 
| 
       42 
42 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/vellum/note_node.py,sha256=TMb8txILu2uWjzoxaghjgjlzeBAgzn4vkP_8zSh2qoE,1151
         
     | 
| 
       43 
43 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/vellum/prompt_deployment_node.py,sha256=LFjLUrH6sJ4czPnExdRqFr0PB_yKBMLXLvK5GAzIAgc,3273
         
     | 
| 
      
 44 
     | 
    
         
            +
            vellum_ee/workflows/display/nodes/vellum/retry_node.py,sha256=i0XGbKecLiHtf7mBf2rbqldPgLcs1TitIphzcHRIvkA,341
         
     | 
| 
       44 
45 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/vellum/search_node.py,sha256=TxcAGZDl_hvJ7Y1hUi9YVEVrj9Ie0hKkASdpfRL4_cs,9227
         
     | 
| 
       45 
46 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/vellum/subworkflow_deployment_node.py,sha256=lfevlHpGEX14dEDym6qmnkw3nvzQPTB1_D2ch12B_Rk,2701
         
     | 
| 
       46 
47 
     | 
    
         
             
            vellum_ee/workflows/display/nodes/vellum/templating_node.py,sha256=JVIMPR3WpveOCWZubHKZkE04mavnTdb_9QY_r3XliRg,3424
         
     | 
| 
         @@ -55,13 +56,13 @@ vellum_ee/workflows/display/tests/test_vellum_workflow_display.py,sha256=h4bE187 
     | 
|
| 
       55 
56 
     | 
    
         
             
            vellum_ee/workflows/display/tests/workflow_serialization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       56 
57 
     | 
    
         
             
            vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       57 
58 
     | 
    
         
             
            vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/conftest.py,sha256=EenmEdBtHUFQ0OS-kE7Vboax3JnDdj-K4Qixt5oR0Po,2253
         
     | 
| 
       58 
     | 
    
         
            -
            vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py,sha256= 
     | 
| 
      
 59 
     | 
    
         
            +
            vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_adornments_serialization.py,sha256=6wgLNd-Ae-33SPIYhOvQ9KJ8-5ach98v_Z3g7nrN_xs,8026
         
     | 
| 
       59 
60 
     | 
    
         
             
            vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_attributes_serialization.py,sha256=yPXhdZxEDunNl5LL5Obb0jeO34djt7F-GiaTJhp_fmo,16742
         
     | 
| 
       60 
61 
     | 
    
         
             
            vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_outputs_serialization.py,sha256=-12ZkZb3f5gyoNASV2yeQtMo5HmNsVEo8nXwL6IC-I8,6261
         
     | 
| 
       61 
62 
     | 
    
         
             
            vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_ports_serialization.py,sha256=6th6kCwzql6lddjkTQx4Jbvvs4ChqtJwctW-B4QuBhI,37352
         
     | 
| 
       62 
63 
     | 
    
         
             
            vellum_ee/workflows/display/tests/workflow_serialization/generic_nodes/test_trigger_serialization.py,sha256=EbVgg_3_ipTt3MOop4RARX0fmNjwqZtkhIXzx9nGw7Y,4487
         
     | 
| 
       63 
64 
     | 
    
         
             
            vellum_ee/workflows/display/tests/workflow_serialization/test_basic_api_node_serialization.py,sha256=bXZWxOKAVjZlbP3iLHPHGA4aPs0EguKlQqmYPNGv3cU,16391
         
     | 
| 
       64 
     | 
    
         
            -
            vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py,sha256= 
     | 
| 
      
 65 
     | 
    
         
            +
            vellum_ee/workflows/display/tests/workflow_serialization/test_basic_code_execution_node_serialization.py,sha256=s2mBoL5Vvpoc-rcWcSGQjLp4yzVVwFmkTbS3--ErzCI,29486
         
     | 
| 
       65 
66 
     | 
    
         
             
            vellum_ee/workflows/display/tests/workflow_serialization/test_basic_conditional_node_serialization.py,sha256=n3F_Eyru0DYOszBH4jplz7Mzt2FfBNxGlCkTFqvrX-M,48399
         
     | 
| 
       66 
67 
     | 
    
         
             
            vellum_ee/workflows/display/tests/workflow_serialization/test_basic_error_node_serialization.py,sha256=8LhQgW0uzVOhzz0AwdM-EYugVO-0mGWglxWo_lON4D8,6079
         
     | 
| 
       67 
68 
     | 
    
         
             
            vellum_ee/workflows/display/tests/workflow_serialization/test_basic_generic_node_serialization.py,sha256=yWDykoHUjuiVYdevcJxWmYDDmbIszpHKYBu19vqR-I8,5746
         
     | 
| 
         @@ -112,7 +113,7 @@ vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749 
     | 
|
| 
       112 
113 
     | 
    
         
             
            vellum/client/__init__.py,sha256=8nZt88C9SVwWanjLbIQMU3rzb32h5UZfFMBx3VPHB50,111887
         
     | 
| 
       113 
114 
     | 
    
         
             
            vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
         
     | 
| 
       114 
115 
     | 
    
         
             
            vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
         
     | 
| 
       115 
     | 
    
         
            -
            vellum/client/core/client_wrapper.py,sha256= 
     | 
| 
      
 116 
     | 
    
         
            +
            vellum/client/core/client_wrapper.py,sha256=JapYtCCqy-ryd-fk1i1krQS6K630bgNpUw4zE0Lct8s,1869
         
     | 
| 
       116 
117 
     | 
    
         
             
            vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
         
     | 
| 
       117 
118 
     | 
    
         
             
            vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
         
     | 
| 
       118 
119 
     | 
    
         
             
            vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
         
     | 
| 
         @@ -168,7 +169,7 @@ vellum/client/resources/workflow_deployments/types/workflow_deployments_list_req 
     | 
|
| 
       168 
169 
     | 
    
         
             
            vellum/client/resources/workflow_sandboxes/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
         
     | 
| 
       169 
170 
     | 
    
         
             
            vellum/client/resources/workflow_sandboxes/client.py,sha256=3wVQxkjrJ5bIS8fB5FpKXCP2dX38299ghWrJ8YmXxwQ,7435
         
     | 
| 
       170 
171 
     | 
    
         
             
            vellum/client/resources/workflows/__init__.py,sha256=Z4xi8Nxd9U4t35FQSepTt1p-ns0X1xtdNs168kUcuBk,153
         
     | 
| 
       171 
     | 
    
         
            -
            vellum/client/resources/workflows/client.py,sha256= 
     | 
| 
      
 172 
     | 
    
         
            +
            vellum/client/resources/workflows/client.py,sha256=hM7FDn05XHhQk599ti8CI4moIg0RVoEFil3Wp9v9UZk,11215
         
     | 
| 
       172 
173 
     | 
    
         
             
            vellum/client/resources/workflows/types/__init__.py,sha256=-uFca4ypncAOvfsg6sjD-5C9zWdA5qNvU6m675GphVg,177
         
     | 
| 
       173 
174 
     | 
    
         
             
            vellum/client/resources/workflows/types/workflows_pull_request_format.py,sha256=dOWE_jnDnniIJLoeseeCms23aklghyBkoPmBFzcqqZk,165
         
     | 
| 
       174 
175 
     | 
    
         
             
            vellum/client/resources/workspace_secrets/__init__.py,sha256=FTtvy8EDg9nNNg9WCatVgKTRYV8-_v1roeGPAKoa_pw,65
         
     | 
| 
         @@ -1326,7 +1327,7 @@ vellum/workflows/nodes/core/retry_node/node.py,sha256=QEpxhKOyxDkRoAn2b0PToZWtAG 
     | 
|
| 
       1326 
1327 
     | 
    
         
             
            vellum/workflows/nodes/core/retry_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1327 
1328 
     | 
    
         
             
            vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=RM_OHwxrHwyxvlQQBJPqVBxpedFuWQ9h2-Xa3kP75sc,4399
         
     | 
| 
       1328 
1329 
     | 
    
         
             
            vellum/workflows/nodes/core/templating_node/__init__.py,sha256=GmyuYo81_A1_Bz6id69ozVFS6FKiuDsZTiA3I6MaL2U,70
         
     | 
| 
       1329 
     | 
    
         
            -
            vellum/workflows/nodes/core/templating_node/node.py,sha256= 
     | 
| 
      
 1330 
     | 
    
         
            +
            vellum/workflows/nodes/core/templating_node/node.py,sha256=zCYhq88qLTvoC9LetVrD9sLXkwHZsaWekxMhru_nV70,3752
         
     | 
| 
       1330 
1331 
     | 
    
         
             
            vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=5iZWQWdJKDHMXBY8bhpb-Dpy9FTfW1HXxGUTivykZAA,4621
         
     | 
| 
       1331 
1332 
     | 
    
         
             
            vellum/workflows/nodes/core/try_node/__init__.py,sha256=JVD4DrldTIqFQQFrubs9KtWCCc0YCAc7Fzol5ZWIWeM,56
         
     | 
| 
       1332 
1333 
     | 
    
         
             
            vellum/workflows/nodes/core/try_node/node.py,sha256=_lTmSYCiz7lktaxpNWUCglNi8_5Sfy8Rpiov5SeKVMw,3920
         
     | 
| 
         @@ -1350,12 +1351,12 @@ vellum/workflows/nodes/displayable/bases/tests/test_utils.py,sha256=eqdqbKNRWVMD 
     | 
|
| 
       1350 
1351 
     | 
    
         
             
            vellum/workflows/nodes/displayable/bases/types.py,sha256=C37B2Qh2YP7s7pUjd-EYKc2Zl1TbnCgI_mENuUSb8bo,1706
         
     | 
| 
       1351 
1352 
     | 
    
         
             
            vellum/workflows/nodes/displayable/bases/utils.py,sha256=ckMUenSsNkiYmSw6FmjSMHYaCk8Y8_sUjL6lkFFEqts,5412
         
     | 
| 
       1352 
1353 
     | 
    
         
             
            vellum/workflows/nodes/displayable/code_execution_node/__init__.py,sha256=0FLWMMktpzSnmBMizQglBpcPrP80fzVsoJwJgf822Cg,76
         
     | 
| 
       1353 
     | 
    
         
            -
            vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256= 
     | 
| 
      
 1354 
     | 
    
         
            +
            vellum/workflows/nodes/displayable/code_execution_node/node.py,sha256=KZ5d3_mdpsrPF_ScmEqSfBhfup421RscO9hNiGa52T4,9068
         
     | 
| 
       1354 
1355 
     | 
    
         
             
            vellum/workflows/nodes/displayable/code_execution_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1355 
1356 
     | 
    
         
             
            vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1356 
1357 
     | 
    
         
             
            vellum/workflows/nodes/displayable/code_execution_node/tests/fixtures/main.py,sha256=5QsbmkzSlSbcbWTG_JmIqcP-JNJzOPTKxGzdHos19W4,79
         
     | 
| 
       1357 
     | 
    
         
            -
            vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256= 
     | 
| 
       1358 
     | 
    
         
            -
            vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256= 
     | 
| 
      
 1358 
     | 
    
         
            +
            vellum/workflows/nodes/displayable/code_execution_node/tests/test_code_execution_node.py,sha256=ueVDw0GTSGzBZMFLs0NTir_0AE-pUrAYvpgg3Stex7Q,12350
         
     | 
| 
      
 1359 
     | 
    
         
            +
            vellum/workflows/nodes/displayable/code_execution_node/utils.py,sha256=zRYM7B2t7355LzaAn6LkIn4tM5K7eQ0Kvje4NO6Kq30,3443
         
     | 
| 
       1359 
1360 
     | 
    
         
             
            vellum/workflows/nodes/displayable/conditional_node/__init__.py,sha256=AS_EIqFdU1F9t8aLmbZU-rLh9ry6LCJ0uj0D8F0L5Uw,72
         
     | 
| 
       1360 
1361 
     | 
    
         
             
            vellum/workflows/nodes/displayable/conditional_node/node.py,sha256=Qjfl33gZ3JEgxBA1EgzSUebboGvsARthIxxcQyvx5Gg,1152
         
     | 
| 
       1361 
1362 
     | 
    
         
             
            vellum/workflows/nodes/displayable/final_output_node/__init__.py,sha256=G7VXM4OWpubvSJtVkGmMNeqgb9GkM7qZT838eL18XU4,72
         
     | 
| 
         @@ -1386,7 +1387,7 @@ vellum/workflows/nodes/experimental/README.md,sha256=eF6DfIL8t-HbF9-mcofOMymKrra 
     | 
|
| 
       1386 
1387 
     | 
    
         
             
            vellum/workflows/nodes/experimental/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1387 
1388 
     | 
    
         
             
            vellum/workflows/nodes/experimental/openai_chat_completion_node/__init__.py,sha256=lsyD9laR9p7kx5-BXGH2gUTM242UhKy8SMV0SR6S2iE,90
         
     | 
| 
       1388 
1389 
     | 
    
         
             
            vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py,sha256=1EGeiaT-Zoo6pttQFKKBcdf3dmhAbjKGaErYD5FFwlc,10185
         
     | 
| 
       1389 
     | 
    
         
            -
            vellum/workflows/nodes/utils.py,sha256= 
     | 
| 
      
 1390 
     | 
    
         
            +
            vellum/workflows/nodes/utils.py,sha256=T7krLipDSI007JkkH2zsfyQ-tfOBH4hyFzQ0YJKYpuw,4025
         
     | 
| 
       1390 
1391 
     | 
    
         
             
            vellum/workflows/outputs/__init__.py,sha256=AyZ4pRh_ACQIGvkf0byJO46EDnSix1ZCAXfvh-ms1QE,94
         
     | 
| 
       1391 
1392 
     | 
    
         
             
            vellum/workflows/outputs/base.py,sha256=a7W6rNSDSawwGAXYjNTF2iHb9lnZu7WFSOagZIyy__k,7976
         
     | 
| 
       1392 
1393 
     | 
    
         
             
            vellum/workflows/ports/__init__.py,sha256=bZuMt-R7z5bKwpu4uPW7LlJeePOQWmCcDSXe5frUY5g,101
         
     | 
| 
         @@ -1397,7 +1398,7 @@ vellum/workflows/references/__init__.py,sha256=glHFC1VfXmcbNvH5VzFbkT03d8_D7MMcv 
     | 
|
| 
       1397 
1398 
     | 
    
         
             
            vellum/workflows/references/constant.py,sha256=6yUT4q1sMj1hkI_tzzQ9AYcmeeDYFUNCqUq_W2DN0S8,540
         
     | 
| 
       1398 
1399 
     | 
    
         
             
            vellum/workflows/references/environment_variable.py,sha256=-gfOcdYwVp9ztSUYz6h2WI2Cg95zqxq5hhFf3Yr7aQg,791
         
     | 
| 
       1399 
1400 
     | 
    
         
             
            vellum/workflows/references/execution_count.py,sha256=JILHqt8ELdc9ct-WsVCA5X-rKiP1rmJODw-XTf4kpHI,722
         
     | 
| 
       1400 
     | 
    
         
            -
            vellum/workflows/references/external_input.py,sha256= 
     | 
| 
      
 1401 
     | 
    
         
            +
            vellum/workflows/references/external_input.py,sha256=WyBC6uMDu77431YVSU_WvTt-nGLC_bW65tIsplUJXa4,2056
         
     | 
| 
       1401 
1402 
     | 
    
         
             
            vellum/workflows/references/input.py,sha256=3INu-TLTi4dziWmva6LO3WvgDlPzsjayUx61cVvqLJA,325
         
     | 
| 
       1402 
1403 
     | 
    
         
             
            vellum/workflows/references/lazy.py,sha256=SXwZUCTzUR-R2-uK0XHALtvp1x84l-QkNY-Ds6KynYA,1932
         
     | 
| 
       1403 
1404 
     | 
    
         
             
            vellum/workflows/references/node.py,sha256=LP854wDVs-9I_aZ7-nkbwXqL2H7W2_3LED2e9FixNS8,1418
         
     | 
| 
         @@ -1411,12 +1412,12 @@ vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8v 
     | 
|
| 
       1411 
1412 
     | 
    
         
             
            vellum/workflows/runner/runner.py,sha256=LvP1UwLmwV1nCZYYrsiwtCzay73voMp1TDRVVBrlMj8,29196
         
     | 
| 
       1412 
1413 
     | 
    
         
             
            vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2235
         
     | 
| 
       1413 
1414 
     | 
    
         
             
            vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
         
     | 
| 
       1414 
     | 
    
         
            -
            vellum/workflows/state/base.py,sha256= 
     | 
| 
      
 1415 
     | 
    
         
            +
            vellum/workflows/state/base.py,sha256=IIl76sJtn0GfbFWBqMnpGuvtZyVyQMEXv0QKDfLy8Wg,14763
         
     | 
| 
       1415 
1416 
     | 
    
         
             
            vellum/workflows/state/context.py,sha256=_NeGQpYo8yNuh0Tfh3OvcB_bG_-GC8b3ZLLl83Pf8-I,1279
         
     | 
| 
       1416 
1417 
     | 
    
         
             
            vellum/workflows/state/encoder.py,sha256=WdUidpOaBDx5lilJl8V8McFDHQYiCLCJR9dmktdzdZY,1836
         
     | 
| 
       1417 
1418 
     | 
    
         
             
            vellum/workflows/state/store.py,sha256=VYGBQgN1bpd1as5eGiouV_7scg8QsRs4_1aqZAGIsRQ,793
         
     | 
| 
       1418 
1419 
     | 
    
         
             
            vellum/workflows/state/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1419 
     | 
    
         
            -
            vellum/workflows/state/tests/test_state.py,sha256= 
     | 
| 
      
 1420 
     | 
    
         
            +
            vellum/workflows/state/tests/test_state.py,sha256=ucy7U8886J3CinIKQhOqv4dvkKWQk0fyK3JjTSiKZC4,5266
         
     | 
| 
       1420 
1421 
     | 
    
         
             
            vellum/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       1421 
1422 
     | 
    
         
             
            vellum/workflows/tests/test_sandbox.py,sha256=JKwaluI-lODQo7Ek9sjDstjL_WTdSqUlVik6ZVTfVOA,1826
         
     | 
| 
       1422 
1423 
     | 
    
         
             
            vellum/workflows/types/__init__.py,sha256=KxUTMBGzuRCfiMqzzsykOeVvrrkaZmTTo1a7SLu8gRM,68
         
     | 
| 
         @@ -1441,8 +1442,8 @@ vellum/workflows/vellum_client.py,sha256=ODrq_TSl-drX2aezXegf7pizpWDVJuTXH-j6528 
     | 
|
| 
       1441 
1442 
     | 
    
         
             
            vellum/workflows/workflows/__init__.py,sha256=KY45TqvavCCvXIkyCFMEc0dc6jTMOUci93U2DUrlZYc,66
         
     | 
| 
       1442 
1443 
     | 
    
         
             
            vellum/workflows/workflows/base.py,sha256=k0kUWWko4fHyCqLSU_1cBK_pXZpl9MXekWiG-bdOAo0,18353
         
     | 
| 
       1443 
1444 
     | 
    
         
             
            vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnadGsrSZGa7t7LpJA,2008
         
     | 
| 
       1444 
     | 
    
         
            -
            vellum_ai-0.13. 
     | 
| 
       1445 
     | 
    
         
            -
            vellum_ai-0.13. 
     | 
| 
       1446 
     | 
    
         
            -
            vellum_ai-0.13. 
     | 
| 
       1447 
     | 
    
         
            -
            vellum_ai-0.13. 
     | 
| 
       1448 
     | 
    
         
            -
            vellum_ai-0.13. 
     | 
| 
      
 1445 
     | 
    
         
            +
            vellum_ai-0.13.18.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
         
     | 
| 
      
 1446 
     | 
    
         
            +
            vellum_ai-0.13.18.dist-info/METADATA,sha256=aLUy-xu3bfn69UAWushKWy3YWWoMMruLabea-UEOO1o,5335
         
     | 
| 
      
 1447 
     | 
    
         
            +
            vellum_ai-0.13.18.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
         
     | 
| 
      
 1448 
     | 
    
         
            +
            vellum_ai-0.13.18.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
         
     | 
| 
      
 1449 
     | 
    
         
            +
            vellum_ai-0.13.18.dist-info/RECORD,,
         
     | 
    
        vellum_cli/pull.py
    CHANGED
    
    | 
         @@ -31,6 +31,16 @@ class WorkflowConfigResolutionResult(UniversalBaseModel): 
     | 
|
| 
       31 
31 
     | 
    
         
             
                pk: Optional[str] = None
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         | 
| 
      
 34 
     | 
    
         
            +
            class RunnerConfig(UniversalBaseModel):
         
     | 
| 
      
 35 
     | 
    
         
            +
                container_image_name: Optional[str] = None
         
     | 
| 
      
 36 
     | 
    
         
            +
                container_image_tag: Optional[str] = None
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            class PullContentsMetadata(UniversalBaseModel):
         
     | 
| 
      
 40 
     | 
    
         
            +
                label: Optional[str] = None
         
     | 
| 
      
 41 
     | 
    
         
            +
                runner_config: Optional[RunnerConfig] = None
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
       34 
44 
     | 
    
         
             
            def _resolve_workflow_config(
         
     | 
| 
       35 
45 
     | 
    
         
             
                config: VellumCliConfig,
         
     | 
| 
       36 
46 
     | 
    
         
             
                module: Optional[str] = None,
         
     | 
| 
         @@ -42,14 +52,33 @@ def _resolve_workflow_config( 
     | 
|
| 
       42 
52 
     | 
    
         | 
| 
       43 
53 
     | 
    
         
             
                if module:
         
     | 
| 
       44 
54 
     | 
    
         
             
                    workflow_config = next((w for w in config.workflows if w.module == module), None)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    if not workflow_config and workflow_sandbox_id:
         
     | 
| 
      
 56 
     | 
    
         
            +
                        workflow_config = WorkflowConfig(
         
     | 
| 
      
 57 
     | 
    
         
            +
                            workflow_sandbox_id=workflow_sandbox_id,
         
     | 
| 
      
 58 
     | 
    
         
            +
                            module=module,
         
     | 
| 
      
 59 
     | 
    
         
            +
                        )
         
     | 
| 
      
 60 
     | 
    
         
            +
                        config.workflows.append(workflow_config)
         
     | 
| 
      
 61 
     | 
    
         
            +
                        return WorkflowConfigResolutionResult(
         
     | 
| 
      
 62 
     | 
    
         
            +
                            workflow_config=workflow_config,
         
     | 
| 
      
 63 
     | 
    
         
            +
                            pk=workflow_sandbox_id,
         
     | 
| 
      
 64 
     | 
    
         
            +
                        )
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
       45 
66 
     | 
    
         
             
                    return WorkflowConfigResolutionResult(
         
     | 
| 
       46 
67 
     | 
    
         
             
                        workflow_config=workflow_config,
         
     | 
| 
       47 
68 
     | 
    
         
             
                        pk=workflow_config.workflow_sandbox_id if workflow_config else None,
         
     | 
| 
       48 
69 
     | 
    
         
             
                    )
         
     | 
| 
       49 
70 
     | 
    
         
             
                elif workflow_sandbox_id:
         
     | 
| 
      
 71 
     | 
    
         
            +
                    workflow_config = next((w for w in config.workflows if w.workflow_sandbox_id == workflow_sandbox_id), None)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    if workflow_config:
         
     | 
| 
      
 73 
     | 
    
         
            +
                        return WorkflowConfigResolutionResult(
         
     | 
| 
      
 74 
     | 
    
         
            +
                            workflow_config=workflow_config,
         
     | 
| 
      
 75 
     | 
    
         
            +
                            pk=workflow_sandbox_id,
         
     | 
| 
      
 76 
     | 
    
         
            +
                        )
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    # We use an empty module name to indicate that we want to backfill it once we have the Workflow Sandbox Label
         
     | 
| 
       50 
79 
     | 
    
         
             
                    workflow_config = WorkflowConfig(
         
     | 
| 
       51 
80 
     | 
    
         
             
                        workflow_sandbox_id=workflow_sandbox_id,
         
     | 
| 
       52 
     | 
    
         
            -
                        module= 
     | 
| 
      
 81 
     | 
    
         
            +
                        module="",
         
     | 
| 
       53 
82 
     | 
    
         
             
                    )
         
     | 
| 
       54 
83 
     | 
    
         
             
                    config.workflows.append(workflow_config)
         
     | 
| 
       55 
84 
     | 
    
         
             
                    return WorkflowConfigResolutionResult(
         
     | 
| 
         @@ -98,7 +127,6 @@ def pull_command( 
     | 
|
| 
       98 
127 
     | 
    
         
             
                    workflow_sandbox_id=workflow_sandbox_id,
         
     | 
| 
       99 
128 
     | 
    
         
             
                    workflow_deployment=workflow_deployment,
         
     | 
| 
       100 
129 
     | 
    
         
             
                )
         
     | 
| 
       101 
     | 
    
         
            -
                save_lock_file = not module
         
     | 
| 
       102 
130 
     | 
    
         | 
| 
       103 
131 
     | 
    
         
             
                workflow_config = workflow_config_result.workflow_config
         
     | 
| 
       104 
132 
     | 
    
         
             
                if not workflow_config:
         
     | 
| 
         @@ -108,7 +136,11 @@ def pull_command( 
     | 
|
| 
       108 
136 
     | 
    
         
             
                if not pk:
         
     | 
| 
       109 
137 
     | 
    
         
             
                    raise ValueError("No workflow sandbox ID found in project to pull from.")
         
     | 
| 
       110 
138 
     | 
    
         | 
| 
       111 
     | 
    
         
            -
                 
     | 
| 
      
 139 
     | 
    
         
            +
                if workflow_config.module:
         
     | 
| 
      
 140 
     | 
    
         
            +
                    logger.info(f"Pulling workflow into {workflow_config.module}...")
         
     | 
| 
      
 141 
     | 
    
         
            +
                else:
         
     | 
| 
      
 142 
     | 
    
         
            +
                    logger.info(f"Pulling workflow from {pk}...")
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
       112 
144 
     | 
    
         
             
                client = create_vellum_client()
         
     | 
| 
       113 
145 
     | 
    
         
             
                query_parameters = {}
         
     | 
| 
       114 
146 
     | 
    
         | 
| 
         @@ -129,11 +161,30 @@ def pull_command( 
     | 
|
| 
       129 
161 
     | 
    
         
             
                zip_bytes = b"".join(response)
         
     | 
| 
       130 
162 
     | 
    
         
             
                zip_buffer = io.BytesIO(zip_bytes)
         
     | 
| 
       131 
163 
     | 
    
         | 
| 
       132 
     | 
    
         
            -
                target_dir = os.path.join(os.getcwd(), *workflow_config.module.split("."))
         
     | 
| 
       133 
164 
     | 
    
         
             
                error_content = ""
         
     | 
| 
       134 
     | 
    
         
            -
                metadata_json: Optional[dict] = None
         
     | 
| 
       135 
165 
     | 
    
         | 
| 
       136 
166 
     | 
    
         
             
                with zipfile.ZipFile(zip_buffer) as zip_file:
         
     | 
| 
      
 167 
     | 
    
         
            +
                    if METADATA_FILE_NAME in zip_file.namelist():
         
     | 
| 
      
 168 
     | 
    
         
            +
                        metadata_json: Optional[dict] = None
         
     | 
| 
      
 169 
     | 
    
         
            +
                        with zip_file.open(METADATA_FILE_NAME) as source:
         
     | 
| 
      
 170 
     | 
    
         
            +
                            metadata_json = json.load(source)
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                        pull_contents_metadata = PullContentsMetadata.model_validate(metadata_json)
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                        if pull_contents_metadata.runner_config:
         
     | 
| 
      
 175 
     | 
    
         
            +
                            workflow_config.container_image_name = pull_contents_metadata.runner_config.container_image_name
         
     | 
| 
      
 176 
     | 
    
         
            +
                            workflow_config.container_image_tag = pull_contents_metadata.runner_config.container_image_tag
         
     | 
| 
      
 177 
     | 
    
         
            +
                            if workflow_config.container_image_name and not workflow_config.container_image_tag:
         
     | 
| 
      
 178 
     | 
    
         
            +
                                workflow_config.container_image_tag = "latest"
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                        if not workflow_config.module and pull_contents_metadata.label:
         
     | 
| 
      
 181 
     | 
    
         
            +
                            workflow_config.module = snake_case(pull_contents_metadata.label)
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                    if not workflow_config.module:
         
     | 
| 
      
 184 
     | 
    
         
            +
                        raise ValueError(f"Failed to resolve a module name for Workflow {pk}")
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                    target_dir = os.path.join(os.getcwd(), *workflow_config.module.split("."))
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
       137 
188 
     | 
    
         
             
                    # Delete files in target_dir that aren't in the zip file
         
     | 
| 
       138 
189 
     | 
    
         
             
                    if os.path.exists(target_dir):
         
     | 
| 
       139 
190 
     | 
    
         
             
                        ignore_patterns = (
         
     | 
| 
         @@ -163,7 +214,6 @@ def pull_command( 
     | 
|
| 
       163 
214 
     | 
    
         
             
                                error_content = content
         
     | 
| 
       164 
215 
     | 
    
         
             
                                continue
         
     | 
| 
       165 
216 
     | 
    
         
             
                            if file_name == METADATA_FILE_NAME:
         
     | 
| 
       166 
     | 
    
         
            -
                                metadata_json = json.loads(content)
         
     | 
| 
       167 
217 
     | 
    
         
             
                                continue
         
     | 
| 
       168 
218 
     | 
    
         | 
| 
       169 
219 
     | 
    
         
             
                            target_file = os.path.join(target_dir, file_name)
         
     | 
| 
         @@ -172,15 +222,6 @@ def pull_command( 
     | 
|
| 
       172 
222 
     | 
    
         
             
                                logger.info(f"Writing to {target_file}...")
         
     | 
| 
       173 
223 
     | 
    
         
             
                                target.write(content)
         
     | 
| 
       174 
224 
     | 
    
         | 
| 
       175 
     | 
    
         
            -
                if metadata_json:
         
     | 
| 
       176 
     | 
    
         
            -
                    runner_config = metadata_json.get("runner_config")
         
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
     | 
    
         
            -
                    if runner_config:
         
     | 
| 
       179 
     | 
    
         
            -
                        workflow_config.container_image_name = runner_config.get("container_image_name")
         
     | 
| 
       180 
     | 
    
         
            -
                        workflow_config.container_image_tag = runner_config.get("container_image_tag")
         
     | 
| 
       181 
     | 
    
         
            -
                        if workflow_config.container_image_name and not workflow_config.container_image_tag:
         
     | 
| 
       182 
     | 
    
         
            -
                            workflow_config.container_image_tag = "latest"
         
     | 
| 
       183 
     | 
    
         
            -
             
     | 
| 
       184 
225 
     | 
    
         
             
                if include_json:
         
     | 
| 
       185 
226 
     | 
    
         
             
                    logger.warning(
         
     | 
| 
       186 
227 
     | 
    
         
             
                        """The pulled JSON representation of the Workflow should be used for debugging purposely only. \
         
     | 
| 
         @@ -190,16 +231,12 @@ Its schema should be considered unstable and subject to change at any time.""" 
     | 
|
| 
       190 
231 
     | 
    
         
             
                if include_sandbox:
         
     | 
| 
       191 
232 
     | 
    
         
             
                    if not workflow_config.ignore:
         
     | 
| 
       192 
233 
     | 
    
         
             
                        workflow_config.ignore = "sandbox.py"
         
     | 
| 
       193 
     | 
    
         
            -
                        save_lock_file = True
         
     | 
| 
       194 
234 
     | 
    
         
             
                    elif isinstance(workflow_config.ignore, str) and "sandbox.py" != workflow_config.ignore:
         
     | 
| 
       195 
235 
     | 
    
         
             
                        workflow_config.ignore = [workflow_config.ignore, "sandbox.py"]
         
     | 
| 
       196 
     | 
    
         
            -
                        save_lock_file = True
         
     | 
| 
       197 
236 
     | 
    
         
             
                    elif isinstance(workflow_config.ignore, list) and "sandbox.py" not in workflow_config.ignore:
         
     | 
| 
       198 
237 
     | 
    
         
             
                        workflow_config.ignore.append("sandbox.py")
         
     | 
| 
       199 
     | 
    
         
            -
                        save_lock_file = True
         
     | 
| 
       200 
238 
     | 
    
         | 
| 
       201 
     | 
    
         
            -
                 
     | 
| 
       202 
     | 
    
         
            -
                    config.save()
         
     | 
| 
      
 239 
     | 
    
         
            +
                config.save()
         
     | 
| 
       203 
240 
     | 
    
         | 
| 
       204 
241 
     | 
    
         
             
                if error_content:
         
     | 
| 
       205 
242 
     | 
    
         
             
                    logger.error(error_content)
         
     | 
    
        vellum_cli/push.py
    CHANGED
    
    | 
         @@ -12,7 +12,6 @@ from dotenv import load_dotenv 
     | 
|
| 
       12 
12 
     | 
    
         
             
            from vellum.client.core.api_error import ApiError
         
     | 
| 
       13 
13 
     | 
    
         
             
            from vellum.resources.workflows.client import OMIT
         
     | 
| 
       14 
14 
     | 
    
         
             
            from vellum.types import WorkflowPushDeploymentConfigRequest
         
     | 
| 
       15 
     | 
    
         
            -
            from vellum.workflows.utils.names import snake_to_title_case
         
     | 
| 
       16 
15 
     | 
    
         
             
            from vellum.workflows.vellum_client import create_vellum_client
         
     | 
| 
       17 
16 
     | 
    
         
             
            from vellum.workflows.workflows.base import BaseWorkflow
         
     | 
| 
       18 
17 
     | 
    
         
             
            from vellum_cli.config import DEFAULT_WORKSPACE_CONFIG, WorkflowConfig, WorkflowDeploymentConfig, load_vellum_cli_config
         
     | 
| 
         @@ -111,8 +110,6 @@ def push_command( 
     | 
|
| 
       111 
110 
     | 
    
         
             
                    "container_image_name": workflow_config.container_image_name,
         
     | 
| 
       112 
111 
     | 
    
         
             
                }
         
     | 
| 
       113 
112 
     | 
    
         | 
| 
       114 
     | 
    
         
            -
                label = snake_to_title_case(workflow_config.module.split(".")[-1])
         
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
113 
     | 
    
         
             
                deployment_config: WorkflowPushDeploymentConfigRequest = OMIT
         
     | 
| 
       117 
114 
     | 
    
         
             
                deployment_config_serialized: str = OMIT
         
     | 
| 
       118 
115 
     | 
    
         
             
                if deploy:
         
     | 
| 
         @@ -158,7 +155,6 @@ def push_command( 
     | 
|
| 
       158 
155 
     | 
    
         
             
                        # Remove this once we could serialize using the artifact in Vembda
         
     | 
| 
       159 
156 
     | 
    
         
             
                        # https://app.shortcut.com/vellum/story/5585
         
     | 
| 
       160 
157 
     | 
    
         
             
                        exec_config=json.dumps(exec_config),
         
     | 
| 
       161 
     | 
    
         
            -
                        label=label,
         
     | 
| 
       162 
158 
     | 
    
         
             
                        workflow_sandbox_id=workflow_config.workflow_sandbox_id or workflow_sandbox_id,
         
     | 
| 
       163 
159 
     | 
    
         
             
                        artifact=artifact,
         
     | 
| 
       164 
160 
     | 
    
         
             
                        # We should check with fern if we could auto-serialize typed object fields for us
         
     | 
| 
         @@ -230,7 +226,7 @@ def push_command( 
     | 
|
| 
       230 
226 
     | 
    
         
             
                    )  # type: ignore[attr-defined]
         
     | 
| 
       231 
227 
     | 
    
         
             
                else:
         
     | 
| 
       232 
228 
     | 
    
         
             
                    logger.info(
         
     | 
| 
       233 
     | 
    
         
            -
                        f"""Successfully pushed { 
     | 
| 
      
 229 
     | 
    
         
            +
                        f"""Successfully pushed {workflow_config.module} to Vellum!
         
     | 
| 
       234 
230 
     | 
    
         
             
            Visit at: https://app.vellum.ai/workflow-sandboxes/{response.workflow_sandbox_id}"""
         
     | 
| 
       235 
231 
     | 
    
         
             
                    )
         
     | 
| 
       236 
232 
     | 
    
         | 
    
        vellum_cli/tests/test_pull.py
    CHANGED
    
    | 
         @@ -39,6 +39,7 @@ def test_pull(vellum_client, mock_module, base_command): 
     | 
|
| 
       39 
39 
     | 
    
         
             
                # GIVEN a module on the user's filesystem
         
     | 
| 
       40 
40 
     | 
    
         
             
                temp_dir = mock_module.temp_dir
         
     | 
| 
       41 
41 
     | 
    
         
             
                module = mock_module.module
         
     | 
| 
      
 42 
     | 
    
         
            +
                workflow_sandbox_id = mock_module.workflow_sandbox_id
         
     | 
| 
       42 
43 
     | 
    
         | 
| 
       43 
44 
     | 
    
         
             
                # AND the workflow pull API call returns a zip file
         
     | 
| 
       44 
45 
     | 
    
         
             
                vellum_client.workflows.pull.return_value = iter([_zip_file_map({"workflow.py": "print('hello')"})])
         
     | 
| 
         @@ -56,6 +57,27 @@ def test_pull(vellum_client, mock_module, base_command): 
     | 
|
| 
       56 
57 
     | 
    
         
             
                with open(workflow_py) as f:
         
     | 
| 
       57 
58 
     | 
    
         
             
                    assert f.read() == "print('hello')"
         
     | 
| 
       58 
59 
     | 
    
         | 
| 
      
 60 
     | 
    
         
            +
                # AND the vellum.lock.json file is created
         
     | 
| 
      
 61 
     | 
    
         
            +
                vellum_lock_json = os.path.join(temp_dir, "vellum.lock.json")
         
     | 
| 
      
 62 
     | 
    
         
            +
                assert os.path.exists(vellum_lock_json)
         
     | 
| 
      
 63 
     | 
    
         
            +
                with open(vellum_lock_json) as f:
         
     | 
| 
      
 64 
     | 
    
         
            +
                    lock_data = json.load(f)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    assert lock_data == {
         
     | 
| 
      
 66 
     | 
    
         
            +
                        "version": "1.0",
         
     | 
| 
      
 67 
     | 
    
         
            +
                        "workflows": [
         
     | 
| 
      
 68 
     | 
    
         
            +
                            {
         
     | 
| 
      
 69 
     | 
    
         
            +
                                "module": module,
         
     | 
| 
      
 70 
     | 
    
         
            +
                                "workflow_sandbox_id": workflow_sandbox_id,
         
     | 
| 
      
 71 
     | 
    
         
            +
                                "container_image_name": None,
         
     | 
| 
      
 72 
     | 
    
         
            +
                                "container_image_tag": None,
         
     | 
| 
      
 73 
     | 
    
         
            +
                                "ignore": None,
         
     | 
| 
      
 74 
     | 
    
         
            +
                                "deployments": [],
         
     | 
| 
      
 75 
     | 
    
         
            +
                                "workspace": "default",
         
     | 
| 
      
 76 
     | 
    
         
            +
                            }
         
     | 
| 
      
 77 
     | 
    
         
            +
                        ],
         
     | 
| 
      
 78 
     | 
    
         
            +
                        "workspaces": [],
         
     | 
| 
      
 79 
     | 
    
         
            +
                    }
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
       59 
81 
     | 
    
         | 
| 
       60 
82 
     | 
    
         
             
            def test_pull__second_module(vellum_client, mock_module):
         
     | 
| 
       61 
83 
     | 
    
         
             
                # GIVEN a module on the user's filesystem
         
     | 
| 
         @@ -95,7 +117,13 @@ def test_pull__sandbox_id_with_no_config(vellum_client): 
     | 
|
| 
       95 
117 
     | 
    
         
             
                workflow_sandbox_id = "87654321-0000-0000-0000-000000000000"
         
     | 
| 
       96 
118 
     | 
    
         | 
| 
       97 
119 
     | 
    
         
             
                # AND the workflow pull API call returns a zip file
         
     | 
| 
       98 
     | 
    
         
            -
                vellum_client.workflows.pull.return_value = iter( 
     | 
| 
      
 120 
     | 
    
         
            +
                vellum_client.workflows.pull.return_value = iter(
         
     | 
| 
      
 121 
     | 
    
         
            +
                    [
         
     | 
| 
      
 122 
     | 
    
         
            +
                        _zip_file_map(
         
     | 
| 
      
 123 
     | 
    
         
            +
                            {"workflow.py": "print('hello')", "metadata.json": json.dumps({"label": "Super Cool Workflow"})}
         
     | 
| 
      
 124 
     | 
    
         
            +
                        )
         
     | 
| 
      
 125 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 126 
     | 
    
         
            +
                )
         
     | 
| 
       99 
127 
     | 
    
         | 
| 
       100 
128 
     | 
    
         
             
                # AND we are currently in a new directory
         
     | 
| 
       101 
129 
     | 
    
         
             
                current_dir = os.getcwd()
         
     | 
| 
         @@ -112,7 +140,7 @@ def test_pull__sandbox_id_with_no_config(vellum_client): 
     | 
|
| 
       112 
140 
     | 
    
         | 
| 
       113 
141 
     | 
    
         
             
                # AND the pull api is called with the workflow sandbox id
         
     | 
| 
       114 
142 
     | 
    
         
             
                vellum_client.workflows.pull.assert_called_once()
         
     | 
| 
       115 
     | 
    
         
            -
                workflow_py = os.path.join(temp_dir, " 
     | 
| 
      
 143 
     | 
    
         
            +
                workflow_py = os.path.join(temp_dir, "super_cool_workflow", "workflow.py")
         
     | 
| 
       116 
144 
     | 
    
         
             
                assert os.path.exists(workflow_py)
         
     | 
| 
       117 
145 
     | 
    
         
             
                with open(workflow_py) as f:
         
     | 
| 
       118 
146 
     | 
    
         
             
                    assert f.read() == "print('hello')"
         
     | 
| 
         @@ -127,7 +155,7 @@ def test_pull__sandbox_id_with_no_config(vellum_client): 
     | 
|
| 
       127 
155 
     | 
    
         
             
                        "workspaces": [],
         
     | 
| 
       128 
156 
     | 
    
         
             
                        "workflows": [
         
     | 
| 
       129 
157 
     | 
    
         
             
                            {
         
     | 
| 
       130 
     | 
    
         
            -
                                "module": " 
     | 
| 
      
 158 
     | 
    
         
            +
                                "module": "super_cool_workflow",
         
     | 
| 
       131 
159 
     | 
    
         
             
                                "workflow_sandbox_id": "87654321-0000-0000-0000-000000000000",
         
     | 
| 
       132 
160 
     | 
    
         
             
                                "ignore": None,
         
     | 
| 
       133 
161 
     | 
    
         
             
                                "deployments": [],
         
     | 
| 
         @@ -147,7 +175,13 @@ def test_pull__sandbox_id_with_other_workflow_configured(vellum_client, mock_mod 
     | 
|
| 
       147 
175 
     | 
    
         
             
                workflow_sandbox_id = "87654321-0000-0000-0000-000000000000"
         
     | 
| 
       148 
176 
     | 
    
         | 
| 
       149 
177 
     | 
    
         
             
                # AND the workflow pull API call returns a zip file
         
     | 
| 
       150 
     | 
    
         
            -
                vellum_client.workflows.pull.return_value = iter( 
     | 
| 
      
 178 
     | 
    
         
            +
                vellum_client.workflows.pull.return_value = iter(
         
     | 
| 
      
 179 
     | 
    
         
            +
                    [
         
     | 
| 
      
 180 
     | 
    
         
            +
                        _zip_file_map(
         
     | 
| 
      
 181 
     | 
    
         
            +
                            {"workflow.py": "print('hello')", "metadata.json": json.dumps({"label": "Super Cool Workflow"})}
         
     | 
| 
      
 182 
     | 
    
         
            +
                        )
         
     | 
| 
      
 183 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 184 
     | 
    
         
            +
                )
         
     | 
| 
       151 
185 
     | 
    
         | 
| 
       152 
186 
     | 
    
         
             
                # WHEN the user runs the pull command with the new workflow sandbox id
         
     | 
| 
       153 
187 
     | 
    
         
             
                runner = CliRunner()
         
     | 
| 
         @@ -162,7 +196,7 @@ def test_pull__sandbox_id_with_other_workflow_configured(vellum_client, mock_mod 
     | 
|
| 
       162 
196 
     | 
    
         
             
                assert call_args[0] == workflow_sandbox_id
         
     | 
| 
       163 
197 
     | 
    
         | 
| 
       164 
198 
     | 
    
         
             
                # AND the workflow.py file is written to the module directory
         
     | 
| 
       165 
     | 
    
         
            -
                workflow_py = os.path.join(temp_dir, " 
     | 
| 
      
 199 
     | 
    
         
            +
                workflow_py = os.path.join(temp_dir, "super_cool_workflow", "workflow.py")
         
     | 
| 
       166 
200 
     | 
    
         
             
                assert os.path.exists(workflow_py)
         
     | 
| 
       167 
201 
     | 
    
         
             
                with open(workflow_py) as f:
         
     | 
| 
       168 
202 
     | 
    
         
             
                    assert f.read() == "print('hello')"
         
     | 
| 
         @@ -420,8 +454,12 @@ def test_pull__sandbox_id_with_other_workflow_deployment_in_lock(vellum_client, 
     | 
|
| 
       420 
454 
     | 
    
         
             
                        _zip_file_map(
         
     | 
| 
       421 
455 
     | 
    
         
             
                            {
         
     | 
| 
       422 
456 
     | 
    
         
             
                                "workflow.py": "print('hello')",
         
     | 
| 
       423 
     | 
    
         
            -
                                "metadata.json":  
     | 
| 
       424 
     | 
    
         
            -
             
     | 
| 
      
 457 
     | 
    
         
            +
                                "metadata.json": json.dumps(
         
     | 
| 
      
 458 
     | 
    
         
            +
                                    {
         
     | 
| 
      
 459 
     | 
    
         
            +
                                        "runner_config": {"container_image_name": "test", "container_image_tag": "1.0"},
         
     | 
| 
      
 460 
     | 
    
         
            +
                                        "label": "Super Cool Workflow",
         
     | 
| 
      
 461 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 462 
     | 
    
         
            +
                                ),
         
     | 
| 
       425 
463 
     | 
    
         
             
                            }
         
     | 
| 
       426 
464 
     | 
    
         
             
                        )
         
     | 
| 
       427 
465 
     | 
    
         
             
                    ]
         
     | 
| 
         @@ -456,7 +494,7 @@ def test_pull__sandbox_id_with_other_workflow_deployment_in_lock(vellum_client, 
     | 
|
| 
       456 
494 
     | 
    
         
             
                            "workspace": "default",
         
     | 
| 
       457 
495 
     | 
    
         
             
                        },
         
     | 
| 
       458 
496 
     | 
    
         
             
                        {
         
     | 
| 
       459 
     | 
    
         
            -
                            "module": " 
     | 
| 
      
 497 
     | 
    
         
            +
                            "module": "super_cool_workflow",
         
     | 
| 
       460 
498 
     | 
    
         
             
                            "workflow_sandbox_id": new_workflow_sandbox_id,
         
     | 
| 
       461 
499 
     | 
    
         
             
                            "ignore": None,
         
     | 
| 
       462 
500 
     | 
    
         
             
                            "deployments": [],
         
     | 
| 
         @@ -539,3 +577,72 @@ def test_pull__include_sandbox(vellum_client, mock_module): 
     | 
|
| 
       539 
577 
     | 
    
         
             
                with open(lock_json) as f:
         
     | 
| 
       540 
578 
     | 
    
         
             
                    lock_data = json.load(f)
         
     | 
| 
       541 
579 
     | 
    
         
             
                    assert lock_data["workflows"][0]["ignore"] == "sandbox.py"
         
     | 
| 
      
 580 
     | 
    
         
            +
             
     | 
| 
      
 581 
     | 
    
         
            +
             
     | 
| 
      
 582 
     | 
    
         
            +
            def test_pull__same_pull_twice__one_entry_in_lockfile(vellum_client, mock_module):
         
     | 
| 
      
 583 
     | 
    
         
            +
                # GIVEN a module on the user's filesystem
         
     | 
| 
      
 584 
     | 
    
         
            +
                module = mock_module.module
         
     | 
| 
      
 585 
     | 
    
         
            +
                temp_dir = mock_module.temp_dir
         
     | 
| 
      
 586 
     | 
    
         
            +
                workflow_sandbox_id = mock_module.workflow_sandbox_id
         
     | 
| 
      
 587 
     | 
    
         
            +
             
     | 
| 
      
 588 
     | 
    
         
            +
                # AND the workflow pull API call returns a zip file both times
         
     | 
| 
      
 589 
     | 
    
         
            +
                zip_contents = _zip_file_map({"workflow.py": "print('hello')"})
         
     | 
| 
      
 590 
     | 
    
         
            +
                responses = iter([zip_contents, zip_contents])
         
     | 
| 
      
 591 
     | 
    
         
            +
             
     | 
| 
      
 592 
     | 
    
         
            +
                def workflows_pull_side_effect(*args, **kwargs):
         
     | 
| 
      
 593 
     | 
    
         
            +
                    return iter([next(responses)])
         
     | 
| 
      
 594 
     | 
    
         
            +
             
     | 
| 
      
 595 
     | 
    
         
            +
                vellum_client.workflows.pull.side_effect = workflows_pull_side_effect
         
     | 
| 
      
 596 
     | 
    
         
            +
             
     | 
| 
      
 597 
     | 
    
         
            +
                # AND the user runs the pull command once
         
     | 
| 
      
 598 
     | 
    
         
            +
                runner = CliRunner()
         
     | 
| 
      
 599 
     | 
    
         
            +
                runner.invoke(cli_main, ["pull", module])
         
     | 
| 
      
 600 
     | 
    
         
            +
             
     | 
| 
      
 601 
     | 
    
         
            +
                # WHEN the user runs the pull command again but with the workflow sandbox id
         
     | 
| 
      
 602 
     | 
    
         
            +
                result = runner.invoke(cli_main, ["workflows", "pull", "--workflow-sandbox-id", workflow_sandbox_id])
         
     | 
| 
      
 603 
     | 
    
         
            +
             
     | 
| 
      
 604 
     | 
    
         
            +
                # THEN the command returns successfully
         
     | 
| 
      
 605 
     | 
    
         
            +
                assert result.exit_code == 0, (result.output, result.exception)
         
     | 
| 
      
 606 
     | 
    
         
            +
             
     | 
| 
      
 607 
     | 
    
         
            +
                # AND the lockfile should only have one entry
         
     | 
| 
      
 608 
     | 
    
         
            +
                lock_json = os.path.join(temp_dir, "vellum.lock.json")
         
     | 
| 
      
 609 
     | 
    
         
            +
                with open(lock_json) as f:
         
     | 
| 
      
 610 
     | 
    
         
            +
                    lock_data = json.load(f)
         
     | 
| 
      
 611 
     | 
    
         
            +
                    assert len(lock_data["workflows"]) == 1
         
     | 
| 
      
 612 
     | 
    
         
            +
             
     | 
| 
      
 613 
     | 
    
         
            +
             
     | 
| 
      
 614 
     | 
    
         
            +
            def test_pull__module_not_in_config(vellum_client, mock_module):
         
     | 
| 
      
 615 
     | 
    
         
            +
                # GIVEN a module on the user's filesystem
         
     | 
| 
      
 616 
     | 
    
         
            +
                module = mock_module.module
         
     | 
| 
      
 617 
     | 
    
         
            +
                temp_dir = mock_module.temp_dir
         
     | 
| 
      
 618 
     | 
    
         
            +
                workflow_sandbox_id = mock_module.workflow_sandbox_id
         
     | 
| 
      
 619 
     | 
    
         
            +
                set_pyproject_toml = mock_module.set_pyproject_toml
         
     | 
| 
      
 620 
     | 
    
         
            +
             
     | 
| 
      
 621 
     | 
    
         
            +
                # AND the pyproject.toml does not have the module configured
         
     | 
| 
      
 622 
     | 
    
         
            +
                set_pyproject_toml({"workflows": []})
         
     | 
| 
      
 623 
     | 
    
         
            +
             
     | 
| 
      
 624 
     | 
    
         
            +
                # AND the workflow pull API call returns a zip file
         
     | 
| 
      
 625 
     | 
    
         
            +
                vellum_client.workflows.pull.return_value = iter([_zip_file_map({"workflow.py": "print('hello')"})])
         
     | 
| 
      
 626 
     | 
    
         
            +
             
     | 
| 
      
 627 
     | 
    
         
            +
                # WHEN the user runs the pull command again with the workflow sandbox id and module
         
     | 
| 
      
 628 
     | 
    
         
            +
                runner = CliRunner()
         
     | 
| 
      
 629 
     | 
    
         
            +
                result = runner.invoke(cli_main, ["workflows", "pull", module, "--workflow-sandbox-id", workflow_sandbox_id])
         
     | 
| 
      
 630 
     | 
    
         
            +
             
     | 
| 
      
 631 
     | 
    
         
            +
                # THEN the command returns successfully
         
     | 
| 
      
 632 
     | 
    
         
            +
                assert result.exit_code == 0, (result.output, result.exception)
         
     | 
| 
      
 633 
     | 
    
         
            +
             
     | 
| 
      
 634 
     | 
    
         
            +
                # AND the lockfile should have the new entry
         
     | 
| 
      
 635 
     | 
    
         
            +
                lock_json = os.path.join(temp_dir, "vellum.lock.json")
         
     | 
| 
      
 636 
     | 
    
         
            +
                with open(lock_json) as f:
         
     | 
| 
      
 637 
     | 
    
         
            +
                    lock_data = json.load(f)
         
     | 
| 
      
 638 
     | 
    
         
            +
                    assert lock_data["workflows"] == [
         
     | 
| 
      
 639 
     | 
    
         
            +
                        {
         
     | 
| 
      
 640 
     | 
    
         
            +
                            "module": module,
         
     | 
| 
      
 641 
     | 
    
         
            +
                            "workflow_sandbox_id": workflow_sandbox_id,
         
     | 
| 
      
 642 
     | 
    
         
            +
                            "ignore": None,
         
     | 
| 
      
 643 
     | 
    
         
            +
                            "deployments": [],
         
     | 
| 
      
 644 
     | 
    
         
            +
                            "container_image_name": None,
         
     | 
| 
      
 645 
     | 
    
         
            +
                            "container_image_tag": None,
         
     | 
| 
      
 646 
     | 
    
         
            +
                            "workspace": "default",
         
     | 
| 
      
 647 
     | 
    
         
            +
                        }
         
     | 
| 
      
 648 
     | 
    
         
            +
                    ]
         
     | 
    
        vellum_cli/tests/test_push.py
    CHANGED
    
    | 
         @@ -119,14 +119,12 @@ def test_push__happy_path(mock_module, vellum_client, base_command): 
     | 
|
| 
       119 
119 
     | 
    
         
             
                assert result.exit_code == 0
         
     | 
| 
       120 
120 
     | 
    
         | 
| 
       121 
121 
     | 
    
         
             
                # Get the last part of the module path and format it
         
     | 
| 
       122 
     | 
    
         
            -
                expected_label = mock_module.module.split(".")[-1].replace("_", " ").title()
         
     | 
| 
       123 
122 
     | 
    
         
             
                expected_artifact_name = f"{mock_module.module.replace('.', '__')}.tar.gz"
         
     | 
| 
       124 
123 
     | 
    
         | 
| 
       125 
124 
     | 
    
         
             
                # AND we should have called the push API with the correct args
         
     | 
| 
       126 
125 
     | 
    
         
             
                vellum_client.workflows.push.assert_called_once()
         
     | 
| 
       127 
126 
     | 
    
         
             
                call_args = vellum_client.workflows.push.call_args.kwargs
         
     | 
| 
       128 
127 
     | 
    
         
             
                assert json.loads(call_args["exec_config"])["workflow_raw_data"]["definition"]["name"] == "ExampleWorkflow"
         
     | 
| 
       129 
     | 
    
         
            -
                assert call_args["label"] == expected_label
         
     | 
| 
       130 
128 
     | 
    
         
             
                assert is_valid_uuid(call_args["workflow_sandbox_id"])
         
     | 
| 
       131 
129 
     | 
    
         
             
                assert call_args["artifact"].name == expected_artifact_name
         
     | 
| 
       132 
130 
     | 
    
         
             
                assert "deplyment_config" not in call_args
         
     | 
| 
         @@ -165,14 +163,12 @@ def test_push__workflow_sandbox_option__existing_id(mock_module, vellum_client, 
     | 
|
| 
       165 
163 
     | 
    
         
             
                assert result.exit_code == 0
         
     | 
| 
       166 
164 
     | 
    
         | 
| 
       167 
165 
     | 
    
         
             
                # Get the last part of the module path and format it
         
     | 
| 
       168 
     | 
    
         
            -
                expected_label = mock_module.module.split(".")[-1].replace("_", " ").title()
         
     | 
| 
       169 
166 
     | 
    
         
             
                expected_artifact_name = f"{mock_module.module.replace('.', '__')}.tar.gz"
         
     | 
| 
       170 
167 
     | 
    
         | 
| 
       171 
168 
     | 
    
         
             
                # AND we should have called the push API with the correct args
         
     | 
| 
       172 
169 
     | 
    
         
             
                vellum_client.workflows.push.assert_called_once()
         
     | 
| 
       173 
170 
     | 
    
         
             
                call_args = vellum_client.workflows.push.call_args.kwargs
         
     | 
| 
       174 
171 
     | 
    
         
             
                assert json.loads(call_args["exec_config"])["workflow_raw_data"]["definition"]["name"] == "ExampleWorkflow"
         
     | 
| 
       175 
     | 
    
         
            -
                assert call_args["label"] == expected_label
         
     | 
| 
       176 
172 
     | 
    
         
             
                assert call_args["workflow_sandbox_id"] == existing_workflow_sandbox_id
         
     | 
| 
       177 
173 
     | 
    
         
             
                assert call_args["artifact"].name == expected_artifact_name
         
     | 
| 
       178 
174 
     | 
    
         
             
                assert "deplyment_config" not in call_args
         
     | 
| 
         @@ -216,14 +212,12 @@ def test_push__workflow_sandbox_option__existing_no_module(mock_module, vellum_c 
     | 
|
| 
       216 
212 
     | 
    
         
             
                assert result.exit_code == 0
         
     | 
| 
       217 
213 
     | 
    
         | 
| 
       218 
214 
     | 
    
         
             
                # Get the last part of the module path and format it
         
     | 
| 
       219 
     | 
    
         
            -
                expected_label = second_module.split(".")[-1].replace("_", " ").title()
         
     | 
| 
       220 
215 
     | 
    
         
             
                expected_artifact_name = f"{second_module.replace('.', '__')}.tar.gz"
         
     | 
| 
       221 
216 
     | 
    
         | 
| 
       222 
217 
     | 
    
         
             
                # AND we should have called the push API with the correct args
         
     | 
| 
       223 
218 
     | 
    
         
             
                vellum_client.workflows.push.assert_called_once()
         
     | 
| 
       224 
219 
     | 
    
         
             
                call_args = vellum_client.workflows.push.call_args.kwargs
         
     | 
| 
       225 
220 
     | 
    
         
             
                assert json.loads(call_args["exec_config"])["workflow_raw_data"]["definition"]["name"] == "ExampleWorkflow"
         
     | 
| 
       226 
     | 
    
         
            -
                assert call_args["label"] == expected_label
         
     | 
| 
       227 
221 
     | 
    
         
             
                assert call_args["workflow_sandbox_id"] == second_workflow_sandbox_id
         
     | 
| 
       228 
222 
     | 
    
         
             
                assert call_args["artifact"].name == expected_artifact_name
         
     | 
| 
       229 
223 
     | 
    
         
             
                assert "deplyment_config" not in call_args
         
     | 
| 
         @@ -297,14 +291,12 @@ def test_push__deployment(mock_module, vellum_client, base_command): 
     | 
|
| 
       297 
291 
     | 
    
         
             
                assert result.exit_code == 0
         
     | 
| 
       298 
292 
     | 
    
         | 
| 
       299 
293 
     | 
    
         
             
                # Get the last part of the module path and format it
         
     | 
| 
       300 
     | 
    
         
            -
                expected_label = mock_module.module.split(".")[-1].replace("_", " ").title()
         
     | 
| 
       301 
294 
     | 
    
         
             
                expected_artifact_name = f"{mock_module.module.replace('.', '__')}.tar.gz"
         
     | 
| 
       302 
295 
     | 
    
         | 
| 
       303 
296 
     | 
    
         
             
                # AND we should have called the push API with the correct args
         
     | 
| 
       304 
297 
     | 
    
         
             
                vellum_client.workflows.push.assert_called_once()
         
     | 
| 
       305 
298 
     | 
    
         
             
                call_args = vellum_client.workflows.push.call_args.kwargs
         
     | 
| 
       306 
299 
     | 
    
         
             
                assert json.loads(call_args["exec_config"])["workflow_raw_data"]["definition"]["name"] == "ExampleWorkflow"
         
     | 
| 
       307 
     | 
    
         
            -
                assert call_args["label"] == expected_label
         
     | 
| 
       308 
300 
     | 
    
         
             
                assert is_valid_uuid(call_args["workflow_sandbox_id"])
         
     | 
| 
       309 
301 
     | 
    
         
             
                assert call_args["artifact"].name == expected_artifact_name
         
     | 
| 
       310 
302 
     | 
    
         
             
                assert call_args["deployment_config"] == "{}"
         
     |