vellum-ai 0.14.13__py3-none-any.whl → 0.14.14__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/plugins/utils.py +11 -3
- vellum/workflows/events/node.py +5 -0
- vellum/workflows/events/tests/test_event.py +36 -0
- vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py +16 -0
- vellum/workflows/nodes/tests/test_utils.py +133 -0
- vellum/workflows/nodes/utils.py +17 -3
- vellum/workflows/runner/runner.py +2 -1
- {vellum_ai-0.14.13.dist-info → vellum_ai-0.14.14.dist-info}/METADATA +1 -1
- {vellum_ai-0.14.13.dist-info → vellum_ai-0.14.14.dist-info}/RECORD +13 -12
- {vellum_ai-0.14.13.dist-info → vellum_ai-0.14.14.dist-info}/LICENSE +0 -0
- {vellum_ai-0.14.13.dist-info → vellum_ai-0.14.14.dist-info}/WHEEL +0 -0
- {vellum_ai-0.14.13.dist-info → vellum_ai-0.14.14.dist-info}/entry_points.txt +0 -0
| @@ -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.14",
         | 
| 22 22 | 
             
                    }
         | 
| 23 23 | 
             
                    headers["X_API_KEY"] = self.api_key
         | 
| 24 24 | 
             
                    return headers
         | 
    
        vellum/plugins/utils.py
    CHANGED
    
    | @@ -1,11 +1,19 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
            from vellum.plugins.pydantic import pydantic_plugin
         | 
| 1 | 
            +
            import pydantic
         | 
| 4 2 |  | 
| 3 | 
            +
            IS_PYDANTIC_V1 = pydantic.VERSION.startswith("1.")
         | 
| 5 4 | 
             
            _loaded = False
         | 
| 6 5 |  | 
| 7 6 |  | 
| 8 7 | 
             
            def load_runtime_plugins() -> None:
         | 
| 8 | 
            +
                if IS_PYDANTIC_V1:
         | 
| 9 | 
            +
                    # Pydantic plugins are only available in v2, so we defer the imports
         | 
| 10 | 
            +
                    # below until we confirm we are running a supported version of pydantic
         | 
| 11 | 
            +
                    return
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                from pydantic.plugin import _loader as _pydantic_plugin_loader
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                from vellum.plugins.pydantic import pydantic_plugin
         | 
| 16 | 
            +
             | 
| 9 17 | 
             
                global _loaded
         | 
| 10 18 | 
             
                if _loaded:
         | 
| 11 19 | 
             
                    return
         | 
    
        vellum/workflows/events/node.py
    CHANGED
    
    | @@ -93,6 +93,7 @@ class NodeExecutionStreamingEvent(_BaseNodeEvent): | |
| 93 93 | 
             
            class NodeExecutionFulfilledBody(_BaseNodeExecutionBody, Generic[OutputsType]):
         | 
| 94 94 | 
             
                outputs: OutputsType
         | 
| 95 95 | 
             
                invoked_ports: InvokedPorts = None
         | 
| 96 | 
            +
                mocked: Optional[bool] = None
         | 
| 96 97 |  | 
| 97 98 | 
             
                @field_serializer("outputs")
         | 
| 98 99 | 
             
                def serialize_outputs(self, outputs: OutputsType, _info: Any) -> Dict[str, Any]:
         | 
| @@ -117,6 +118,10 @@ class NodeExecutionFulfilledEvent(_BaseNodeEvent, Generic[OutputsType]): | |
| 117 118 | 
             
                def invoked_ports(self) -> InvokedPorts:
         | 
| 118 119 | 
             
                    return self.body.invoked_ports
         | 
| 119 120 |  | 
| 121 | 
            +
                @property
         | 
| 122 | 
            +
                def mocked(self) -> Optional[bool]:
         | 
| 123 | 
            +
                    return self.body.mocked
         | 
| 124 | 
            +
             | 
| 120 125 |  | 
| 121 126 | 
             
            class NodeExecutionRejectedBody(_BaseNodeExecutionBody):
         | 
| 122 127 | 
             
                error: WorkflowError
         | 
| @@ -328,6 +328,7 @@ mock_node_uuid = str(uuid4_from_hash(MockNode.__qualname__)) | |
| 328 328 | 
             
                                        "name": "default",
         | 
| 329 329 | 
             
                                    }
         | 
| 330 330 | 
             
                                ],
         | 
| 331 | 
            +
                                "mocked": None,
         | 
| 331 332 | 
             
                            },
         | 
| 332 333 | 
             
                            "parent": None,
         | 
| 333 334 | 
             
                        },
         | 
| @@ -365,6 +366,40 @@ mock_node_uuid = str(uuid4_from_hash(MockNode.__qualname__)) | |
| 365 366 | 
             
                                        "name": "default",
         | 
| 366 367 | 
             
                                    }
         | 
| 367 368 | 
             
                                ],
         | 
| 369 | 
            +
                                "mocked": None,
         | 
| 370 | 
            +
                            },
         | 
| 371 | 
            +
                            "parent": None,
         | 
| 372 | 
            +
                        },
         | 
| 373 | 
            +
                    ),
         | 
| 374 | 
            +
                    (
         | 
| 375 | 
            +
                        NodeExecutionFulfilledEvent(
         | 
| 376 | 
            +
                            id=UUID("123e4567-e89b-12d3-a456-426614174000"),
         | 
| 377 | 
            +
                            timestamp=datetime(2024, 1, 1, 12, 0, 0),
         | 
| 378 | 
            +
                            trace_id=UUID("123e4567-e89b-12d3-a456-426614174000"),
         | 
| 379 | 
            +
                            span_id=UUID("123e4567-e89b-12d3-a456-426614174000"),
         | 
| 380 | 
            +
                            body=NodeExecutionFulfilledBody(
         | 
| 381 | 
            +
                                node_definition=MockNode,
         | 
| 382 | 
            +
                                outputs=MockNode.Outputs(
         | 
| 383 | 
            +
                                    example="foo",
         | 
| 384 | 
            +
                                ),
         | 
| 385 | 
            +
                                mocked=True,
         | 
| 386 | 
            +
                            ),
         | 
| 387 | 
            +
                        ),
         | 
| 388 | 
            +
                        {
         | 
| 389 | 
            +
                            "id": "123e4567-e89b-12d3-a456-426614174000",
         | 
| 390 | 
            +
                            "api_version": "2024-10-25",
         | 
| 391 | 
            +
                            "timestamp": "2024-01-01T12:00:00",
         | 
| 392 | 
            +
                            "trace_id": "123e4567-e89b-12d3-a456-426614174000",
         | 
| 393 | 
            +
                            "span_id": "123e4567-e89b-12d3-a456-426614174000",
         | 
| 394 | 
            +
                            "name": "node.execution.fulfilled",
         | 
| 395 | 
            +
                            "body": {
         | 
| 396 | 
            +
                                "node_definition": {
         | 
| 397 | 
            +
                                    "id": mock_node_uuid,
         | 
| 398 | 
            +
                                    "name": "MockNode",
         | 
| 399 | 
            +
                                    "module": module_root + ["events", "tests", "test_event"],
         | 
| 400 | 
            +
                                },
         | 
| 401 | 
            +
                                "outputs": {"example": "foo"},
         | 
| 402 | 
            +
                                "mocked": True,
         | 
| 368 403 | 
             
                            },
         | 
| 369 404 | 
             
                            "parent": None,
         | 
| 370 405 | 
             
                        },
         | 
| @@ -379,6 +414,7 @@ mock_node_uuid = str(uuid4_from_hash(MockNode.__qualname__)) | |
| 379 414 | 
             
                    "node.execution.streaming",
         | 
| 380 415 | 
             
                    "node.execution.fulfilled",
         | 
| 381 416 | 
             
                    "fulfilled_node_with_undefined_outputs",
         | 
| 417 | 
            +
                    "mocked_node",
         | 
| 382 418 | 
             
                ],
         | 
| 383 419 | 
             
            )
         | 
| 384 420 | 
             
            def test_event_serialization(event, expected_json):
         | 
| @@ -283,3 +283,19 @@ def test_templating_node__function_call_as_json(): | |
| 283 283 | 
             
                # AND we can access fields directly
         | 
| 284 284 | 
             
                assert outputs.result["arguments"] == {"key": "value"}
         | 
| 285 285 | 
             
                assert outputs.result["name"] == "test_function"
         | 
| 286 | 
            +
             | 
| 287 | 
            +
             | 
| 288 | 
            +
            def test_templating_node__empty_string_to_list():
         | 
| 289 | 
            +
                """Test that an empty string output with list output type casts to an empty array."""
         | 
| 290 | 
            +
             | 
| 291 | 
            +
                # GIVEN a templating node that outputs an empty string but has List output type
         | 
| 292 | 
            +
                class EmptyStringToListTemplateNode(TemplatingNode[BaseState, List[str]]):
         | 
| 293 | 
            +
                    template = """{{ "" }}"""
         | 
| 294 | 
            +
                    inputs = {}
         | 
| 295 | 
            +
             | 
| 296 | 
            +
                # WHEN the node is run
         | 
| 297 | 
            +
                node = EmptyStringToListTemplateNode()
         | 
| 298 | 
            +
                outputs = node.run()
         | 
| 299 | 
            +
             | 
| 300 | 
            +
                # THEN the output should be an empty list, not raise an exception
         | 
| 301 | 
            +
                assert outputs.result == []
         | 
| @@ -0,0 +1,133 @@ | |
| 1 | 
            +
            import pytest
         | 
| 2 | 
            +
            from typing import List, Union
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            from pydantic import BaseModel
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            from vellum.workflows.errors.types import WorkflowErrorCode
         | 
| 7 | 
            +
            from vellum.workflows.exceptions import NodeException
         | 
| 8 | 
            +
            from vellum.workflows.nodes.utils import parse_type_from_str
         | 
| 9 | 
            +
            from vellum.workflows.types.core import Json
         | 
| 10 | 
            +
             | 
| 11 | 
            +
             | 
| 12 | 
            +
            class Person(BaseModel):
         | 
| 13 | 
            +
                name: str
         | 
| 14 | 
            +
                age: int
         | 
| 15 | 
            +
             | 
| 16 | 
            +
             | 
| 17 | 
            +
            class FunctionCall(BaseModel):
         | 
| 18 | 
            +
                name: str
         | 
| 19 | 
            +
                args: List[int]
         | 
| 20 | 
            +
             | 
| 21 | 
            +
             | 
| 22 | 
            +
            @pytest.mark.parametrize(
         | 
| 23 | 
            +
                "input_str, output_type, expected_result",
         | 
| 24 | 
            +
                [
         | 
| 25 | 
            +
                    ("hello", str, "hello"),
         | 
| 26 | 
            +
                    ("3.14", float, 3.14),
         | 
| 27 | 
            +
                    ("42", int, 42),
         | 
| 28 | 
            +
                    ("True", bool, True),
         | 
| 29 | 
            +
                    ("", List[str], []),  # Empty string should return an empty list
         | 
| 30 | 
            +
                    ("[1, 2, 3]", List[int], [1, 2, 3]),
         | 
| 31 | 
            +
                    ('["a", "b", "c"]', List[str], ["a", "b", "c"]),
         | 
| 32 | 
            +
                    ('{"name": "Alice", "age": 30}', Json, {"name": "Alice", "age": 30}),
         | 
| 33 | 
            +
                    (
         | 
| 34 | 
            +
                        '{"type": "FUNCTION_CALL", "value": {"name": "test", "args": [1, 2]}}',
         | 
| 35 | 
            +
                        Json,
         | 
| 36 | 
            +
                        {"name": "test", "args": [1, 2]},
         | 
| 37 | 
            +
                    ),
         | 
| 38 | 
            +
                    ("42", Union[int, str], 42),
         | 
| 39 | 
            +
                    ("hello", Union[int, str], "hello"),
         | 
| 40 | 
            +
                ],
         | 
| 41 | 
            +
                ids=[
         | 
| 42 | 
            +
                    "str",
         | 
| 43 | 
            +
                    "float",
         | 
| 44 | 
            +
                    "int",
         | 
| 45 | 
            +
                    "bool",
         | 
| 46 | 
            +
                    "empty_list",
         | 
| 47 | 
            +
                    "list_of_int",
         | 
| 48 | 
            +
                    "list_of_str",
         | 
| 49 | 
            +
                    "simple_json",
         | 
| 50 | 
            +
                    "function_call_json",
         | 
| 51 | 
            +
                    "union_int",
         | 
| 52 | 
            +
                    "union_str",
         | 
| 53 | 
            +
                ],
         | 
| 54 | 
            +
            )
         | 
| 55 | 
            +
            def test_parse_type_from_str_basic_cases(input_str, output_type, expected_result):
         | 
| 56 | 
            +
                result = parse_type_from_str(input_str, output_type)
         | 
| 57 | 
            +
                assert result == expected_result
         | 
| 58 | 
            +
             | 
| 59 | 
            +
             | 
| 60 | 
            +
            def test_parse_type_from_str_pydantic_models():
         | 
| 61 | 
            +
                person_json = '{"name": "Alice", "age": 30}'
         | 
| 62 | 
            +
                person = parse_type_from_str(person_json, Person)
         | 
| 63 | 
            +
                assert isinstance(person, Person)
         | 
| 64 | 
            +
                assert person.name == "Alice"
         | 
| 65 | 
            +
                assert person.age == 30
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                function_json = '{"name": "test", "args": [1, 2]}'
         | 
| 68 | 
            +
                function = parse_type_from_str(function_json, FunctionCall)
         | 
| 69 | 
            +
                assert isinstance(function, FunctionCall)
         | 
| 70 | 
            +
                assert function.name == "test"
         | 
| 71 | 
            +
                assert function.args == [1, 2]
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                function_call_json = '{"value": {"name": "test", "args": [1, 2]}}'
         | 
| 74 | 
            +
                function = parse_type_from_str(function_call_json, FunctionCall)
         | 
| 75 | 
            +
                assert isinstance(function, FunctionCall)
         | 
| 76 | 
            +
                assert function.name == "test"
         | 
| 77 | 
            +
                assert function.args == [1, 2]
         | 
| 78 | 
            +
             | 
| 79 | 
            +
             | 
| 80 | 
            +
            def test_parse_type_from_str_list_of_models():
         | 
| 81 | 
            +
                person_list_json = '[{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]'
         | 
| 82 | 
            +
                persons = parse_type_from_str(person_list_json, List[Person])
         | 
| 83 | 
            +
                assert len(persons) == 2
         | 
| 84 | 
            +
                assert all(isinstance(p, Person) for p in persons)
         | 
| 85 | 
            +
                assert persons[0].name == "Alice"
         | 
| 86 | 
            +
                assert persons[0].age == 30
         | 
| 87 | 
            +
                assert persons[1].name == "Bob"
         | 
| 88 | 
            +
                assert persons[1].age == 25
         | 
| 89 | 
            +
             | 
| 90 | 
            +
             | 
| 91 | 
            +
            @pytest.mark.parametrize(
         | 
| 92 | 
            +
                "input_str, output_type, expected_exception, expected_code, expected_message",
         | 
| 93 | 
            +
                [
         | 
| 94 | 
            +
                    (
         | 
| 95 | 
            +
                        "{invalid json}",
         | 
| 96 | 
            +
                        List[str],
         | 
| 97 | 
            +
                        NodeException,
         | 
| 98 | 
            +
                        WorkflowErrorCode.INVALID_OUTPUTS,
         | 
| 99 | 
            +
                        "Invalid JSON Array format for result_as_str",
         | 
| 100 | 
            +
                    ),
         | 
| 101 | 
            +
                    (
         | 
| 102 | 
            +
                        "{invalid json}",
         | 
| 103 | 
            +
                        Person,
         | 
| 104 | 
            +
                        NodeException,
         | 
| 105 | 
            +
                        WorkflowErrorCode.INVALID_OUTPUTS,
         | 
| 106 | 
            +
                        "Invalid JSON format for result_as_str",
         | 
| 107 | 
            +
                    ),
         | 
| 108 | 
            +
                    (
         | 
| 109 | 
            +
                        "{invalid json}",
         | 
| 110 | 
            +
                        Json,
         | 
| 111 | 
            +
                        NodeException,
         | 
| 112 | 
            +
                        WorkflowErrorCode.INVALID_OUTPUTS,
         | 
| 113 | 
            +
                        "Invalid JSON format for result_as_str",
         | 
| 114 | 
            +
                    ),
         | 
| 115 | 
            +
                    ('{"name": "Alice"}', List[str], ValueError, None, "Expected a list of items for result_as_str, received dict"),
         | 
| 116 | 
            +
                    ("data", object, ValueError, None, "Unsupported output type: <class 'object'>"),
         | 
| 117 | 
            +
                ],
         | 
| 118 | 
            +
                ids=[
         | 
| 119 | 
            +
                    "invalid_json_list",
         | 
| 120 | 
            +
                    "invalid_json_model",
         | 
| 121 | 
            +
                    "invalid_json_json_type",
         | 
| 122 | 
            +
                    "non_list_for_list",
         | 
| 123 | 
            +
                    "unsupported_type",
         | 
| 124 | 
            +
                ],
         | 
| 125 | 
            +
            )
         | 
| 126 | 
            +
            def test_parse_type_from_str_error_cases(input_str, output_type, expected_exception, expected_code, expected_message):
         | 
| 127 | 
            +
                with pytest.raises(expected_exception) as excinfo:
         | 
| 128 | 
            +
                    parse_type_from_str(input_str, output_type)
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                if expected_code:
         | 
| 131 | 
            +
                    assert excinfo.value.code == expected_code
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                assert expected_message in str(excinfo.value)
         | 
    
        vellum/workflows/nodes/utils.py
    CHANGED
    
    | @@ -95,10 +95,18 @@ def parse_type_from_str(result_as_str: str, output_type: Any) -> Any: | |
| 95 95 | 
             
                    return bool(result_as_str)
         | 
| 96 96 |  | 
| 97 97 | 
             
                if get_origin(output_type) is list:
         | 
| 98 | 
            +
                    # Handle empty string case for list types by returning an empty list
         | 
| 99 | 
            +
                    if not result_as_str.strip():
         | 
| 100 | 
            +
                        return []
         | 
| 101 | 
            +
             | 
| 98 102 | 
             
                    try:
         | 
| 99 103 | 
             
                        data = json.loads(result_as_str)
         | 
| 100 104 | 
             
                    except json.JSONDecodeError:
         | 
| 101 | 
            -
                        raise ValueError("Invalid JSON Array format for result_as_str")
         | 
| 105 | 
            +
                        # raise ValueError("Invalid JSON Array format for result_as_str")
         | 
| 106 | 
            +
                        raise NodeException(
         | 
| 107 | 
            +
                            code=WorkflowErrorCode.INVALID_OUTPUTS,
         | 
| 108 | 
            +
                            message="Invalid JSON Array format for result_as_str",
         | 
| 109 | 
            +
                        )
         | 
| 102 110 |  | 
| 103 111 | 
             
                    if not isinstance(data, list):
         | 
| 104 112 | 
             
                        raise ValueError(f"Expected a list of items for result_as_str, received {data.__class__.__name__}")
         | 
| @@ -117,7 +125,10 @@ def parse_type_from_str(result_as_str: str, output_type: Any) -> Any: | |
| 117 125 | 
             
                            return data["value"]
         | 
| 118 126 | 
             
                        return data
         | 
| 119 127 | 
             
                    except json.JSONDecodeError:
         | 
| 120 | 
            -
                        raise  | 
| 128 | 
            +
                        raise NodeException(
         | 
| 129 | 
            +
                            code=WorkflowErrorCode.INVALID_OUTPUTS,
         | 
| 130 | 
            +
                            message="Invalid JSON format for result_as_str",
         | 
| 131 | 
            +
                        )
         | 
| 121 132 |  | 
| 122 133 | 
             
                if get_origin(output_type) is Union:
         | 
| 123 134 | 
             
                    for inner_type in get_args(output_type):
         | 
| @@ -140,7 +151,10 @@ def parse_type_from_str(result_as_str: str, output_type: Any) -> Any: | |
| 140 151 | 
             
                            data = data["value"]
         | 
| 141 152 | 
             
                        return output_type.model_validate(data)
         | 
| 142 153 | 
             
                    except json.JSONDecodeError:
         | 
| 143 | 
            -
                        raise  | 
| 154 | 
            +
                        raise NodeException(
         | 
| 155 | 
            +
                            code=WorkflowErrorCode.INVALID_OUTPUTS,
         | 
| 156 | 
            +
                            message="Invalid JSON format for result_as_str",
         | 
| 157 | 
            +
                        )
         | 
| 144 158 |  | 
| 145 159 | 
             
                raise ValueError(f"Unsupported output type: {output_type}")
         | 
| 146 160 |  | 
| @@ -200,7 +200,7 @@ class WorkflowRunner(Generic[StateType]): | |
| 200 200 | 
             
                            parent=parent_context,
         | 
| 201 201 | 
             
                        )
         | 
| 202 202 | 
             
                        node_run_response: NodeRunResponse
         | 
| 203 | 
            -
                        was_mocked =  | 
| 203 | 
            +
                        was_mocked: Optional[bool] = None
         | 
| 204 204 | 
             
                        mock_candidates = self.workflow.context.node_output_mocks_map.get(node.Outputs) or []
         | 
| 205 205 | 
             
                        for mock_candidate in mock_candidates:
         | 
| 206 206 | 
             
                            if mock_candidate.when_condition.resolve(node.state):
         | 
| @@ -315,6 +315,7 @@ class WorkflowRunner(Generic[StateType]): | |
| 315 315 | 
             
                                    node_definition=node.__class__,
         | 
| 316 316 | 
             
                                    outputs=outputs,
         | 
| 317 317 | 
             
                                    invoked_ports=invoked_ports,
         | 
| 318 | 
            +
                                    mocked=was_mocked,
         | 
| 318 319 | 
             
                                ),
         | 
| 319 320 | 
             
                                parent=parent_context,
         | 
| 320 321 | 
             
                            )
         | 
| @@ -123,7 +123,7 @@ vellum/client/README.md,sha256=JkCJjmMZl4jrPj46pkmL9dpK4gSzQQmP5I7z4aME4LY,4749 | |
| 123 123 | 
             
            vellum/client/__init__.py,sha256=tKtdM1_GqmGq1gpi9ydWD_T-MM7fPn8QdHh8ww19cNI,117564
         | 
| 124 124 | 
             
            vellum/client/core/__init__.py,sha256=SQ85PF84B9MuKnBwHNHWemSGuy-g_515gFYNFhvEE0I,1438
         | 
| 125 125 | 
             
            vellum/client/core/api_error.py,sha256=RE8LELok2QCjABadECTvtDp7qejA1VmINCh6TbqPwSE,426
         | 
| 126 | 
            -
            vellum/client/core/client_wrapper.py,sha256= | 
| 126 | 
            +
            vellum/client/core/client_wrapper.py,sha256=F65g9wG6SXfGPkAao7k0GN7doBs1E434iyOswOpG3iE,1869
         | 
| 127 127 | 
             
            vellum/client/core/datetime_utils.py,sha256=nBys2IsYrhPdszxGKCNRPSOCwa-5DWOHG95FB8G9PKo,1047
         | 
| 128 128 | 
             
            vellum/client/core/file.py,sha256=X9IbmkZmB2bB_DpmZAO3crWdXagOakAyn6UCOCImCPg,2322
         | 
| 129 129 | 
             
            vellum/client/core/http_client.py,sha256=R0pQpCppnEtxccGvXl4uJ76s7ro_65Fo_erlNNLp_AI,19228
         | 
| @@ -720,7 +720,7 @@ vellum/evaluations/utils/exceptions.py,sha256=dXMAkzqbHV_AP5FjjbegPlfUE0zQDlpA3q | |
| 720 720 | 
             
            vellum/evaluations/utils/paginator.py,sha256=rEED_BJAXAM6tM1yMwHePNzszjq_tTq4NbQvi1jWQ_Q,697
         | 
| 721 721 | 
             
            vellum/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 722 722 | 
             
            vellum/plugins/pydantic.py,sha256=BMUwC4OkxtNf6hpLwb0T4MBUKgkGy55T_5Ww7GHpHYo,3068
         | 
| 723 | 
            -
            vellum/plugins/utils.py,sha256= | 
| 723 | 
            +
            vellum/plugins/utils.py,sha256=cPmxE9R2CK1bki2jKE8rB-G9zMf2pzHjSPDHFPXwd3Q,878
         | 
| 724 724 | 
             
            vellum/plugins/vellum_mypy.py,sha256=QTuMSq6PiZW1dyTUZ5Bf1d4XkgFj0TKAgZLP8f4UgL4,27914
         | 
| 725 725 | 
             
            vellum/prompts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 726 726 | 
             
            vellum/prompts/blocks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| @@ -1312,9 +1312,9 @@ vellum/workflows/environment/environment.py,sha256=0XhJPBs8YASWmvPx8bkSdCvcbDmzp | |
| 1312 1312 | 
             
            vellum/workflows/errors/__init__.py,sha256=tWGPu5xyAU8gRb8_bl0fL7OfU3wxQ9UH6qVwy4X4P_Q,113
         | 
| 1313 1313 | 
             
            vellum/workflows/errors/types.py,sha256=tVW7Il9zalnwWzdoDLqYPIvRTOhXIv6FPORZAbU7n5Q,3640
         | 
| 1314 1314 | 
             
            vellum/workflows/events/__init__.py,sha256=6pxxceJo2dcaRkWtkDAYlUQZ-PHBQSZytIoyuUK48Qw,759
         | 
| 1315 | 
            -
            vellum/workflows/events/node.py,sha256= | 
| 1315 | 
            +
            vellum/workflows/events/node.py,sha256=jbmNHjdp331Q1IRK-AWtAxwF6Lidb9R7__N5rQuilE8,5401
         | 
| 1316 1316 | 
             
            vellum/workflows/events/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 1317 | 
            -
            vellum/workflows/events/tests/test_event.py,sha256= | 
| 1317 | 
            +
            vellum/workflows/events/tests/test_event.py,sha256=sHcKhZPDPtzZfTmehL4NORA_StR4M6nZDcx9kz3Avo0,16866
         | 
| 1318 1318 | 
             
            vellum/workflows/events/types.py,sha256=AeTJaQt_fNHDLI4nyBzo7XrW9QQybRC09AKzu3kEYEE,3575
         | 
| 1319 1319 | 
             
            vellum/workflows/events/workflow.py,sha256=QoSHyIOpuVacbR7POf7h104miTOhCjtO2udnYximJGs,6851
         | 
| 1320 1320 | 
             
            vellum/workflows/exceptions.py,sha256=NiBiR3ggfmPxBVqD-H1SqmjI-7mIn0EStSN1BqApvCM,1213
         | 
| @@ -1383,7 +1383,7 @@ vellum/workflows/nodes/core/retry_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TI | |
| 1383 1383 | 
             
            vellum/workflows/nodes/core/retry_node/tests/test_node.py,sha256=RM_OHwxrHwyxvlQQBJPqVBxpedFuWQ9h2-Xa3kP75sc,4399
         | 
| 1384 1384 | 
             
            vellum/workflows/nodes/core/templating_node/__init__.py,sha256=GmyuYo81_A1_Bz6id69ozVFS6FKiuDsZTiA3I6MaL2U,70
         | 
| 1385 1385 | 
             
            vellum/workflows/nodes/core/templating_node/node.py,sha256=-JIqLUv6Xpx_LTVZt7whQ2X2VatgHDdTxjMrz64luEs,3721
         | 
| 1386 | 
            -
            vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256= | 
| 1386 | 
            +
            vellum/workflows/nodes/core/templating_node/tests/test_templating_node.py,sha256=MHofz-BwAgt7EXkab8VIyacYznDEIJ7Er7MJUaxNQQo,9614
         | 
| 1387 1387 | 
             
            vellum/workflows/nodes/core/try_node/__init__.py,sha256=JVD4DrldTIqFQQFrubs9KtWCCc0YCAc7Fzol5ZWIWeM,56
         | 
| 1388 1388 | 
             
            vellum/workflows/nodes/core/try_node/node.py,sha256=5ux1l2HO12FBFFyhz6j-4yfBYVrqgT2maTAne_GnNDk,4434
         | 
| 1389 1389 | 
             
            vellum/workflows/nodes/core/try_node/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| @@ -1453,7 +1453,8 @@ vellum/workflows/nodes/experimental/openai_chat_completion_node/node.py,sha256=1 | |
| 1453 1453 | 
             
            vellum/workflows/nodes/mocks.py,sha256=a1FjWEIocseMfjzM-i8DNozpUsaW0IONRpZmXBoWlyc,10455
         | 
| 1454 1454 | 
             
            vellum/workflows/nodes/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 1455 1455 | 
             
            vellum/workflows/nodes/tests/test_mocks.py,sha256=mfPvrs75PKcsNsbJLQAN6PDFoVqs9TmQxpdyFKDdO60,7837
         | 
| 1456 | 
            -
            vellum/workflows/nodes/ | 
| 1456 | 
            +
            vellum/workflows/nodes/tests/test_utils.py,sha256=7PtdV_fzl56agx0IDitdqOmqUO9cQZmJww-3ToxzSqA,4174
         | 
| 1457 | 
            +
            vellum/workflows/nodes/utils.py,sha256=b-U8xjUpGswaoEiav5tU_OFKB26GkYFzuko9XCMU_Fo,7627
         | 
| 1457 1458 | 
             
            vellum/workflows/outputs/__init__.py,sha256=AyZ4pRh_ACQIGvkf0byJO46EDnSix1ZCAXfvh-ms1QE,94
         | 
| 1458 1459 | 
             
            vellum/workflows/outputs/base.py,sha256=b4Dnha1miKu3uFJYptKKflIHNuajPF2BNKy0BTt8Tjc,8622
         | 
| 1459 1460 | 
             
            vellum/workflows/ports/__init__.py,sha256=bZuMt-R7z5bKwpu4uPW7LlJeePOQWmCcDSXe5frUY5g,101
         | 
| @@ -1475,7 +1476,7 @@ vellum/workflows/references/workflow_input.py,sha256=86IuhlBz-9cGxeUzizyjdp482aj | |
| 1475 1476 | 
             
            vellum/workflows/resolvers/__init__.py,sha256=eH6hTvZO4IciDaf_cf7aM2vs-DkBDyJPycOQevJxQnI,82
         | 
| 1476 1477 | 
             
            vellum/workflows/resolvers/base.py,sha256=WHra9LRtlTuB1jmuNqkfVE2JUgB61Cyntn8f0b0WZg4,411
         | 
| 1477 1478 | 
             
            vellum/workflows/runner/__init__.py,sha256=i1iG5sAhtpdsrlvwgH6B-m49JsINkiWyPWs8vyT-bqM,72
         | 
| 1478 | 
            -
            vellum/workflows/runner/runner.py,sha256= | 
| 1479 | 
            +
            vellum/workflows/runner/runner.py,sha256=fS21u0LIyhxT4T6YQPgonVuH8X8TgD5BrsbVxPUWfuM,31071
         | 
| 1479 1480 | 
             
            vellum/workflows/sandbox.py,sha256=GVJzVjMuYzOBnSrboB0_6MMRZWBluAyQ2o7syeaeBd0,2235
         | 
| 1480 1481 | 
             
            vellum/workflows/state/__init__.py,sha256=yUUdR-_Vl7UiixNDYQZ-GEM_kJI9dnOia75TtuNEsnE,60
         | 
| 1481 1482 | 
             
            vellum/workflows/state/base.py,sha256=Vkhneko3VlQrPsMLU1PYSzXU_W1u7_AraJsghiv5O-4,15512
         | 
| @@ -1511,8 +1512,8 @@ vellum/workflows/workflows/event_filters.py,sha256=GSxIgwrX26a1Smfd-6yss2abGCnad | |
| 1511 1512 | 
             
            vellum/workflows/workflows/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 1512 1513 | 
             
            vellum/workflows/workflows/tests/test_base_workflow.py,sha256=NRteiICyJvDM5zrtUfq2fZoXcGQVaWC9xmNlLLVW0cU,7979
         | 
| 1513 1514 | 
             
            vellum/workflows/workflows/tests/test_context.py,sha256=VJBUcyWVtMa_lE5KxdhgMu0WYNYnUQUDvTF7qm89hJ0,2333
         | 
| 1514 | 
            -
            vellum_ai-0.14. | 
| 1515 | 
            -
            vellum_ai-0.14. | 
| 1516 | 
            -
            vellum_ai-0.14. | 
| 1517 | 
            -
            vellum_ai-0.14. | 
| 1518 | 
            -
            vellum_ai-0.14. | 
| 1515 | 
            +
            vellum_ai-0.14.14.dist-info/LICENSE,sha256=hOypcdt481qGNISA784bnAGWAE6tyIf9gc2E78mYC3E,1574
         | 
| 1516 | 
            +
            vellum_ai-0.14.14.dist-info/METADATA,sha256=UKCcEJ4XtYH1PteNKqVZjzrWn3-WMYYFFEl9SLs_lF4,5408
         | 
| 1517 | 
            +
            vellum_ai-0.14.14.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
         | 
| 1518 | 
            +
            vellum_ai-0.14.14.dist-info/entry_points.txt,sha256=HCH4yc_V3J_nDv3qJzZ_nYS8llCHZViCDP1ejgCc5Ak,42
         | 
| 1519 | 
            +
            vellum_ai-0.14.14.dist-info/RECORD,,
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         |