lionagi 0.18.1__py3-none-any.whl → 0.18.2__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.
- lionagi/__init__.py +102 -59
 - lionagi/adapters/spec_adapters/__init__.py +9 -0
 - lionagi/adapters/spec_adapters/_protocol.py +236 -0
 - lionagi/adapters/spec_adapters/pydantic_field.py +158 -0
 - lionagi/ln/_async_call.py +2 -2
 - lionagi/ln/fuzzy/_fuzzy_match.py +2 -2
 - lionagi/ln/types/__init__.py +51 -0
 - lionagi/ln/types/_sentinel.py +154 -0
 - lionagi/ln/{types.py → types/base.py} +108 -168
 - lionagi/ln/types/operable.py +221 -0
 - lionagi/ln/types/spec.py +441 -0
 - lionagi/models/field_model.py +57 -3
 - lionagi/models/model_params.py +4 -3
 - lionagi/operations/operate/operate.py +116 -84
 - lionagi/operations/operate/operative.py +142 -305
 - lionagi/operations/operate/step.py +162 -181
 - lionagi/operations/types.py +6 -6
 - lionagi/protocols/messages/message.py +2 -2
 - lionagi/version.py +1 -1
 - {lionagi-0.18.1.dist-info → lionagi-0.18.2.dist-info}/METADATA +1 -1
 - {lionagi-0.18.1.dist-info → lionagi-0.18.2.dist-info}/RECORD +23 -16
 - {lionagi-0.18.1.dist-info → lionagi-0.18.2.dist-info}/WHEEL +0 -0
 - {lionagi-0.18.1.dist-info → lionagi-0.18.2.dist-info}/licenses/LICENSE +0 -0
 
| 
         @@ -0,0 +1,154 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            from __future__ import annotations
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            from typing import Any, Final, Literal, TypeVar, Union
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            __all__ = (
         
     | 
| 
      
 6 
     | 
    
         
            +
                "Undefined",
         
     | 
| 
      
 7 
     | 
    
         
            +
                "Unset",
         
     | 
| 
      
 8 
     | 
    
         
            +
                "MaybeUndefined",
         
     | 
| 
      
 9 
     | 
    
         
            +
                "MaybeUnset",
         
     | 
| 
      
 10 
     | 
    
         
            +
                "MaybeSentinel",
         
     | 
| 
      
 11 
     | 
    
         
            +
                "SingletonType",
         
     | 
| 
      
 12 
     | 
    
         
            +
                "UndefinedType",
         
     | 
| 
      
 13 
     | 
    
         
            +
                "UnsetType",
         
     | 
| 
      
 14 
     | 
    
         
            +
                "is_sentinel",
         
     | 
| 
      
 15 
     | 
    
         
            +
                "not_sentinel",
         
     | 
| 
      
 16 
     | 
    
         
            +
                "T",
         
     | 
| 
      
 17 
     | 
    
         
            +
            )
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            T = TypeVar("T")
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            class _SingletonMeta(type):
         
     | 
| 
      
 23 
     | 
    
         
            +
                """Metaclass that guarantees exactly one instance per subclass.
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                This ensures that sentinel values maintain identity across the entire application,
         
     | 
| 
      
 26 
     | 
    
         
            +
                allowing safe identity checks with 'is' operator.
         
     | 
| 
      
 27 
     | 
    
         
            +
                """
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                _cache: dict[type, SingletonType] = {}
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def __call__(cls, *a, **kw):
         
     | 
| 
      
 32 
     | 
    
         
            +
                    if cls not in cls._cache:
         
     | 
| 
      
 33 
     | 
    
         
            +
                        cls._cache[cls] = super().__call__(*a, **kw)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    return cls._cache[cls]
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            class SingletonType(metaclass=_SingletonMeta):
         
     | 
| 
      
 38 
     | 
    
         
            +
                """Base class for singleton sentinel types.
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                Provides consistent interface for sentinel values with:
         
     | 
| 
      
 41 
     | 
    
         
            +
                - Identity preservation across deepcopy
         
     | 
| 
      
 42 
     | 
    
         
            +
                - Falsy boolean evaluation
         
     | 
| 
      
 43 
     | 
    
         
            +
                - Clear string representation
         
     | 
| 
      
 44 
     | 
    
         
            +
                """
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                __slots__: tuple[str, ...] = ()
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                def __deepcopy__(self, memo):  # copy & deepcopy both noop
         
     | 
| 
      
 49 
     | 
    
         
            +
                    return self
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                def __copy__(self):
         
     | 
| 
      
 52 
     | 
    
         
            +
                    return self
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                # concrete classes *must* override the two methods below
         
     | 
| 
      
 55 
     | 
    
         
            +
                def __bool__(self) -> bool: ...
         
     | 
| 
      
 56 
     | 
    
         
            +
                def __repr__(self) -> str: ...
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            class UndefinedType(SingletonType):
         
     | 
| 
      
 60 
     | 
    
         
            +
                """Sentinel for a key or field entirely missing from a namespace.
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                Use this when:
         
     | 
| 
      
 63 
     | 
    
         
            +
                - A field has never been set
         
     | 
| 
      
 64 
     | 
    
         
            +
                - A key doesn't exist in a mapping
         
     | 
| 
      
 65 
     | 
    
         
            +
                - A value is conceptually undefined (not just unset)
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                Example:
         
     | 
| 
      
 68 
     | 
    
         
            +
                    >>> d = {"a": 1}
         
     | 
| 
      
 69 
     | 
    
         
            +
                    >>> d.get("b", Undefined) is Undefined
         
     | 
| 
      
 70 
     | 
    
         
            +
                    True
         
     | 
| 
      
 71 
     | 
    
         
            +
                """
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                __slots__ = ()
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                def __bool__(self) -> Literal[False]:
         
     | 
| 
      
 76 
     | 
    
         
            +
                    return False
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                def __repr__(self) -> Literal["Undefined"]:
         
     | 
| 
      
 79 
     | 
    
         
            +
                    return "Undefined"
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                def __str__(self) -> Literal["Undefined"]:
         
     | 
| 
      
 82 
     | 
    
         
            +
                    return "Undefined"
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                def __reduce__(self):
         
     | 
| 
      
 85 
     | 
    
         
            +
                    """Ensure pickle preservation of singleton identity."""
         
     | 
| 
      
 86 
     | 
    
         
            +
                    return "Undefined"
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            class UnsetType(SingletonType):
         
     | 
| 
      
 90 
     | 
    
         
            +
                """Sentinel for a key present but value not yet provided.
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                Use this when:
         
     | 
| 
      
 93 
     | 
    
         
            +
                - A parameter exists but hasn't been given a value
         
     | 
| 
      
 94 
     | 
    
         
            +
                - Distinguishing between None and "not provided"
         
     | 
| 
      
 95 
     | 
    
         
            +
                - API parameters that are optional but need explicit handling
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                Example:
         
     | 
| 
      
 98 
     | 
    
         
            +
                    >>> def func(param=Unset):
         
     | 
| 
      
 99 
     | 
    
         
            +
                    ...     if param is not Unset:
         
     | 
| 
      
 100 
     | 
    
         
            +
                    ...         # param was explicitly provided
         
     | 
| 
      
 101 
     | 
    
         
            +
                    ...         process(param)
         
     | 
| 
      
 102 
     | 
    
         
            +
                """
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                __slots__ = ()
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                def __bool__(self) -> Literal[False]:
         
     | 
| 
      
 107 
     | 
    
         
            +
                    return False
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                def __repr__(self) -> Literal["Unset"]:
         
     | 
| 
      
 110 
     | 
    
         
            +
                    return "Unset"
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                def __str__(self) -> Literal["Unset"]:
         
     | 
| 
      
 113 
     | 
    
         
            +
                    return "Unset"
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                def __reduce__(self):
         
     | 
| 
      
 116 
     | 
    
         
            +
                    """Ensure pickle preservation of singleton identity."""
         
     | 
| 
      
 117 
     | 
    
         
            +
                    return "Unset"
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
            Undefined: Final = UndefinedType()
         
     | 
| 
      
 121 
     | 
    
         
            +
            """A key or field entirely missing from a namespace"""
         
     | 
| 
      
 122 
     | 
    
         
            +
            Unset: Final = UnsetType()
         
     | 
| 
      
 123 
     | 
    
         
            +
            """A key present but value not yet provided."""
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
            MaybeUndefined = Union[T, UndefinedType]
         
     | 
| 
      
 126 
     | 
    
         
            +
            MaybeUnset = Union[T, UnsetType]
         
     | 
| 
      
 127 
     | 
    
         
            +
            MaybeSentinel = Union[T, UndefinedType, UnsetType]
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
            _EMPTY_TUPLE = (tuple(), set(), frozenset(), dict(), list(), "")
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
            def is_sentinel(
         
     | 
| 
      
 133 
     | 
    
         
            +
                value: Any,
         
     | 
| 
      
 134 
     | 
    
         
            +
                *,
         
     | 
| 
      
 135 
     | 
    
         
            +
                none_as_sentinel: bool = False,
         
     | 
| 
      
 136 
     | 
    
         
            +
                empty_as_sentinel: bool = False,
         
     | 
| 
      
 137 
     | 
    
         
            +
            ) -> bool:
         
     | 
| 
      
 138 
     | 
    
         
            +
                """Check if a value is any sentinel (Undefined or Unset)."""
         
     | 
| 
      
 139 
     | 
    
         
            +
                if none_as_sentinel and value is None:
         
     | 
| 
      
 140 
     | 
    
         
            +
                    return True
         
     | 
| 
      
 141 
     | 
    
         
            +
                if empty_as_sentinel and value in _EMPTY_TUPLE:
         
     | 
| 
      
 142 
     | 
    
         
            +
                    return True
         
     | 
| 
      
 143 
     | 
    
         
            +
                return value is Undefined or value is Unset
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
            def not_sentinel(
         
     | 
| 
      
 147 
     | 
    
         
            +
                value: Any, none_as_sentinel: bool = False, empty_as_sentinel: bool = False
         
     | 
| 
      
 148 
     | 
    
         
            +
            ) -> bool:
         
     | 
| 
      
 149 
     | 
    
         
            +
                """Check if a value is NOT a sentinel. Useful for filtering operations."""
         
     | 
| 
      
 150 
     | 
    
         
            +
                return not is_sentinel(
         
     | 
| 
      
 151 
     | 
    
         
            +
                    value,
         
     | 
| 
      
 152 
     | 
    
         
            +
                    none_as_sentinel=none_as_sentinel,
         
     | 
| 
      
 153 
     | 
    
         
            +
                    empty_as_sentinel=empty_as_sentinel,
         
     | 
| 
      
 154 
     | 
    
         
            +
                )
         
     | 
| 
         @@ -3,152 +3,26 @@ from __future__ import annotations 
     | 
|
| 
       3 
3 
     | 
    
         
             
            from collections.abc import Sequence
         
     | 
| 
       4 
4 
     | 
    
         
             
            from dataclasses import dataclass, field
         
     | 
| 
       5 
5 
     | 
    
         
             
            from enum import Enum as _Enum
         
     | 
| 
       6 
     | 
    
         
            -
            from typing import Any, ClassVar 
     | 
| 
      
 6 
     | 
    
         
            +
            from typing import Any, ClassVar
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            from typing_extensions import TypedDict, override
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
      
 10 
     | 
    
         
            +
            from ._sentinel import Undefined, Unset, is_sentinel
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
       10 
12 
     | 
    
         
             
            __all__ = (
         
     | 
| 
       11 
     | 
    
         
            -
                "Undefined",
         
     | 
| 
       12 
     | 
    
         
            -
                "Unset",
         
     | 
| 
       13 
     | 
    
         
            -
                "MaybeUndefined",
         
     | 
| 
       14 
     | 
    
         
            -
                "MaybeUnset",
         
     | 
| 
       15 
     | 
    
         
            -
                "MaybeSentinel",
         
     | 
| 
       16 
     | 
    
         
            -
                "SingletonType",
         
     | 
| 
       17 
     | 
    
         
            -
                "UndefinedType",
         
     | 
| 
       18 
     | 
    
         
            -
                "UnsetType",
         
     | 
| 
       19 
     | 
    
         
            -
                "KeysDict",
         
     | 
| 
       20 
     | 
    
         
            -
                "T",
         
     | 
| 
       21 
13 
     | 
    
         
             
                "Enum",
         
     | 
| 
       22 
     | 
    
         
            -
                " 
     | 
| 
       23 
     | 
    
         
            -
                "not_sentinel",
         
     | 
| 
      
 14 
     | 
    
         
            +
                "ModelConfig",
         
     | 
| 
       24 
15 
     | 
    
         
             
                "Params",
         
     | 
| 
       25 
16 
     | 
    
         
             
                "DataClass",
         
     | 
| 
       26 
     | 
    
         
            -
                "KeysLike",
         
     | 
| 
       27 
17 
     | 
    
         
             
                "Meta",
         
     | 
| 
      
 18 
     | 
    
         
            +
                "KeysDict",
         
     | 
| 
      
 19 
     | 
    
         
            +
                "KeysLike",
         
     | 
| 
       28 
20 
     | 
    
         
             
            )
         
     | 
| 
       29 
21 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
            T = TypeVar("T")
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
            class _SingletonMeta(type):
         
     | 
| 
       34 
     | 
    
         
            -
                """Metaclass that guarantees exactly one instance per subclass.
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
                This ensures that sentinel values maintain identity across the entire application,
         
     | 
| 
       37 
     | 
    
         
            -
                allowing safe identity checks with 'is' operator.
         
     | 
| 
       38 
     | 
    
         
            -
                """
         
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
                _cache: dict[type, SingletonType] = {}
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                def __call__(cls, *a, **kw):
         
     | 
| 
       43 
     | 
    
         
            -
                    if cls not in cls._cache:
         
     | 
| 
       44 
     | 
    
         
            -
                        cls._cache[cls] = super().__call__(*a, **kw)
         
     | 
| 
       45 
     | 
    
         
            -
                    return cls._cache[cls]
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
            class SingletonType(metaclass=_SingletonMeta):
         
     | 
| 
       49 
     | 
    
         
            -
                """Base class for singleton sentinel types.
         
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
                Provides consistent interface for sentinel values with:
         
     | 
| 
       52 
     | 
    
         
            -
                - Identity preservation across deepcopy
         
     | 
| 
       53 
     | 
    
         
            -
                - Falsy boolean evaluation
         
     | 
| 
       54 
     | 
    
         
            -
                - Clear string representation
         
     | 
| 
       55 
     | 
    
         
            -
                """
         
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
                __slots__: tuple[str, ...] = ()
         
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
                def __deepcopy__(self, memo):  # copy & deepcopy both noop
         
     | 
| 
       60 
     | 
    
         
            -
                    return self
         
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
                def __copy__(self):
         
     | 
| 
       63 
     | 
    
         
            -
                    return self
         
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
                # concrete classes *must* override the two methods below
         
     | 
| 
       66 
     | 
    
         
            -
                def __bool__(self) -> bool: ...
         
     | 
| 
       67 
     | 
    
         
            -
                def __repr__(self) -> str: ...
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
            class UndefinedType(SingletonType):
         
     | 
| 
       71 
     | 
    
         
            -
                """Sentinel for a key or field entirely missing from a namespace.
         
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
                Use this when:
         
     | 
| 
       74 
     | 
    
         
            -
                - A field has never been set
         
     | 
| 
       75 
     | 
    
         
            -
                - A key doesn't exist in a mapping
         
     | 
| 
       76 
     | 
    
         
            -
                - A value is conceptually undefined (not just unset)
         
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
                Example:
         
     | 
| 
       79 
     | 
    
         
            -
                    >>> d = {"a": 1}
         
     | 
| 
       80 
     | 
    
         
            -
                    >>> d.get("b", Undefined) is Undefined
         
     | 
| 
       81 
     | 
    
         
            -
                    True
         
     | 
| 
       82 
     | 
    
         
            -
                """
         
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
                __slots__ = ()
         
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
                def __bool__(self) -> Literal[False]:
         
     | 
| 
       87 
     | 
    
         
            -
                    return False
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
                def __repr__(self) -> Literal["Undefined"]:
         
     | 
| 
       90 
     | 
    
         
            -
                    return "Undefined"
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
                def __str__(self) -> Literal["Undefined"]:
         
     | 
| 
       93 
     | 
    
         
            -
                    return "Undefined"
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
                def __reduce__(self):
         
     | 
| 
       96 
     | 
    
         
            -
                    """Ensure pickle preservation of singleton identity."""
         
     | 
| 
       97 
     | 
    
         
            -
                    return "Undefined"
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
            class UnsetType(SingletonType):
         
     | 
| 
       101 
     | 
    
         
            -
                """Sentinel for a key present but value not yet provided.
         
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
                Use this when:
         
     | 
| 
       104 
     | 
    
         
            -
                - A parameter exists but hasn't been given a value
         
     | 
| 
       105 
     | 
    
         
            -
                - Distinguishing between None and "not provided"
         
     | 
| 
       106 
     | 
    
         
            -
                - API parameters that are optional but need explicit handling
         
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
                Example:
         
     | 
| 
       109 
     | 
    
         
            -
                    >>> def func(param=Unset):
         
     | 
| 
       110 
     | 
    
         
            -
                    ...     if param is not Unset:
         
     | 
| 
       111 
     | 
    
         
            -
                    ...         # param was explicitly provided
         
     | 
| 
       112 
     | 
    
         
            -
                    ...         process(param)
         
     | 
| 
       113 
     | 
    
         
            -
                """
         
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
                __slots__ = ()
         
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
                def __bool__(self) -> Literal[False]:
         
     | 
| 
       118 
     | 
    
         
            -
                    return False
         
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
                def __repr__(self) -> Literal["Unset"]:
         
     | 
| 
       121 
     | 
    
         
            -
                    return "Unset"
         
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
                def __str__(self) -> Literal["Unset"]:
         
     | 
| 
       124 
     | 
    
         
            -
                    return "Unset"
         
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
                def __reduce__(self):
         
     | 
| 
       127 
     | 
    
         
            -
                    """Ensure pickle preservation of singleton identity."""
         
     | 
| 
       128 
     | 
    
         
            -
                    return "Unset"
         
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
            Undefined: Final = UndefinedType()
         
     | 
| 
       132 
     | 
    
         
            -
            """A key or field entirely missing from a namespace"""
         
     | 
| 
       133 
     | 
    
         
            -
            Unset: Final = UnsetType()
         
     | 
| 
       134 
     | 
    
         
            -
            """A key present but value not yet provided."""
         
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
       136 
     | 
    
         
            -
            MaybeUndefined = Union[T, UndefinedType]
         
     | 
| 
       137 
     | 
    
         
            -
            MaybeUnset = Union[T, UnsetType]
         
     | 
| 
       138 
     | 
    
         
            -
            MaybeSentinel = Union[T, UndefinedType, UnsetType]
         
     | 
| 
       139 
     | 
    
         
            -
             
     | 
| 
       140 
     | 
    
         
            -
             
     | 
| 
       141 
     | 
    
         
            -
            def is_sentinel(value: Any) -> bool:
         
     | 
| 
       142 
     | 
    
         
            -
                """Check if a value is any sentinel (Undefined or Unset)."""
         
     | 
| 
       143 
     | 
    
         
            -
                return value is Undefined or value is Unset
         
     | 
| 
       144 
     | 
    
         
            -
             
     | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
            def not_sentinel(value: Any) -> bool:
         
     | 
| 
       147 
     | 
    
         
            -
                """Check if a value is NOT a sentinel. Useful for filtering operations."""
         
     | 
| 
       148 
     | 
    
         
            -
                return value is not Undefined and value is not Unset
         
     | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
22 
     | 
    
         | 
| 
       151 
23 
     | 
    
         
             
            class Enum(_Enum):
         
     | 
| 
      
 24 
     | 
    
         
            +
                """Enhanced Enum with allowed() classmethod."""
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
       152 
26 
     | 
    
         
             
                @classmethod
         
     | 
| 
       153 
27 
     | 
    
         
             
                def allowed(cls) -> tuple[str, ...]:
         
     | 
| 
       154 
28 
     | 
    
         
             
                    return tuple(e.value for e in cls)
         
     | 
| 
         @@ -160,18 +34,46 @@ class KeysDict(TypedDict, total=False): 
     | 
|
| 
       160 
34 
     | 
    
         
             
                key: Any  # Represents any key-type pair
         
     | 
| 
       161 
35 
     | 
    
         | 
| 
       162 
36 
     | 
    
         | 
| 
      
 37 
     | 
    
         
            +
            @dataclass(slots=True, frozen=True)
         
     | 
| 
      
 38 
     | 
    
         
            +
            class ModelConfig:
         
     | 
| 
      
 39 
     | 
    
         
            +
                """Configuration for Params and DataClass behavior.
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                Attributes:
         
     | 
| 
      
 42 
     | 
    
         
            +
                    none_as_sentinel: If True, None is treated as a sentinel value (excluded from to_dict).
         
     | 
| 
      
 43 
     | 
    
         
            +
                    empty_as_sentinel: If True, empty collections are treated as sentinels (excluded from to_dict).
         
     | 
| 
      
 44 
     | 
    
         
            +
                    strict: If True, no sentinels allowed (all fields must have values).
         
     | 
| 
      
 45 
     | 
    
         
            +
                    prefill_unset: If True, unset fields are prefilled with Unset.
         
     | 
| 
      
 46 
     | 
    
         
            +
                    use_enum_values: If True, use enum values instead of enum instances in to_dict().
         
     | 
| 
      
 47 
     | 
    
         
            +
                """
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                # Sentinel handling (controls what gets excluded from to_dict)
         
     | 
| 
      
 50 
     | 
    
         
            +
                none_as_sentinel: bool = False
         
     | 
| 
      
 51 
     | 
    
         
            +
                empty_as_sentinel: bool = False
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                # Validation
         
     | 
| 
      
 54 
     | 
    
         
            +
                strict: bool = False
         
     | 
| 
      
 55 
     | 
    
         
            +
                prefill_unset: bool = True
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                # Serialization
         
     | 
| 
      
 58 
     | 
    
         
            +
                use_enum_values: bool = False
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
       163 
61 
     | 
    
         
             
            @dataclass(slots=True, frozen=True, init=False)
         
     | 
| 
       164 
62 
     | 
    
         
             
            class Params:
         
     | 
| 
       165 
     | 
    
         
            -
                """Base class for parameters used in various functions. 
     | 
| 
      
 63 
     | 
    
         
            +
                """Base class for parameters used in various functions.
         
     | 
| 
       166 
64 
     | 
    
         | 
| 
       167 
     | 
    
         
            -
                 
     | 
| 
       168 
     | 
    
         
            -
                """If True, None is treated as a sentinel value."""
         
     | 
| 
      
 65 
     | 
    
         
            +
                Use the ModelConfig class attribute to customize behavior:
         
     | 
| 
       169 
66 
     | 
    
         | 
| 
       170 
     | 
    
         
            -
                 
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
      
 67 
     | 
    
         
            +
                Example:
         
     | 
| 
      
 68 
     | 
    
         
            +
                    @dataclass(slots=True, frozen=True, init=False)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    class MyParams(Params):
         
     | 
| 
      
 70 
     | 
    
         
            +
                        _config: ClassVar[ModelConfig] = ModelConfig(strict=True)
         
     | 
| 
      
 71 
     | 
    
         
            +
                        param1: str
         
     | 
| 
      
 72 
     | 
    
         
            +
                        param2: int
         
     | 
| 
      
 73 
     | 
    
         
            +
                """
         
     | 
| 
       172 
74 
     | 
    
         | 
| 
       173 
     | 
    
         
            -
                 
     | 
| 
       174 
     | 
    
         
            -
                """ 
     | 
| 
      
 75 
     | 
    
         
            +
                _config: ClassVar[ModelConfig] = ModelConfig()
         
     | 
| 
      
 76 
     | 
    
         
            +
                """Configuration for this Params class."""
         
     | 
| 
       175 
77 
     | 
    
         | 
| 
       176 
78 
     | 
    
         
             
                _allowed_keys: ClassVar[set[str]] = field(
         
     | 
| 
       177 
79 
     | 
    
         
             
                    default=set(), init=False, repr=False
         
     | 
| 
         @@ -193,9 +95,23 @@ class Params: 
     | 
|
| 
       193 
95 
     | 
    
         
             
                @classmethod
         
     | 
| 
       194 
96 
     | 
    
         
             
                def _is_sentinel(cls, value: Any) -> bool:
         
     | 
| 
       195 
97 
     | 
    
         
             
                    """Check if a value is a sentinel (Undefined or Unset)."""
         
     | 
| 
       196 
     | 
    
         
            -
                     
     | 
| 
       197 
     | 
    
         
            -
                         
     | 
| 
       198 
     | 
    
         
            -
             
     | 
| 
      
 98 
     | 
    
         
            +
                    return is_sentinel(
         
     | 
| 
      
 99 
     | 
    
         
            +
                        value,
         
     | 
| 
      
 100 
     | 
    
         
            +
                        none_as_sentinel=cls._config.none_as_sentinel,
         
     | 
| 
      
 101 
     | 
    
         
            +
                        empty_as_sentinel=cls._config.empty_as_sentinel,
         
     | 
| 
      
 102 
     | 
    
         
            +
                    )
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 105 
     | 
    
         
            +
                def _normalize_value(cls, value: Any) -> Any:
         
     | 
| 
      
 106 
     | 
    
         
            +
                    """Normalize a value for serialization.
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                    Handles:
         
     | 
| 
      
 109 
     | 
    
         
            +
                    - Enum values if use_enum_values is True
         
     | 
| 
      
 110 
     | 
    
         
            +
                    - Can be extended for other transformations
         
     | 
| 
      
 111 
     | 
    
         
            +
                    """
         
     | 
| 
      
 112 
     | 
    
         
            +
                    if cls._config.use_enum_values and isinstance(value, _Enum):
         
     | 
| 
      
 113 
     | 
    
         
            +
                        return value.value
         
     | 
| 
      
 114 
     | 
    
         
            +
                    return value
         
     | 
| 
       199 
115 
     | 
    
         | 
| 
       200 
116 
     | 
    
         
             
                @classmethod
         
     | 
| 
       201 
117 
     | 
    
         
             
                def allowed(cls) -> set[str]:
         
     | 
| 
         @@ -210,10 +126,12 @@ class Params: 
     | 
|
| 
       210 
126 
     | 
    
         
             
                @override
         
     | 
| 
       211 
127 
     | 
    
         
             
                def _validate(self) -> None:
         
     | 
| 
       212 
128 
     | 
    
         
             
                    def _validate_strict(k):
         
     | 
| 
       213 
     | 
    
         
            -
                        if self. 
     | 
| 
      
 129 
     | 
    
         
            +
                        if self._config.strict and self._is_sentinel(
         
     | 
| 
      
 130 
     | 
    
         
            +
                            getattr(self, k, Unset)
         
     | 
| 
      
 131 
     | 
    
         
            +
                        ):
         
     | 
| 
       214 
132 
     | 
    
         
             
                            raise ValueError(f"Missing required parameter: {k}")
         
     | 
| 
       215 
133 
     | 
    
         
             
                        if (
         
     | 
| 
       216 
     | 
    
         
            -
                            self. 
     | 
| 
      
 134 
     | 
    
         
            +
                            self._config.prefill_unset
         
     | 
| 
       217 
135 
     | 
    
         
             
                            and getattr(self, k, Undefined) is Undefined
         
     | 
| 
       218 
136 
     | 
    
         
             
                        ):
         
     | 
| 
       219 
137 
     | 
    
         
             
                            object.__setattr__(self, k, Unset)
         
     | 
| 
         @@ -236,14 +154,14 @@ class Params: 
     | 
|
| 
       236 
154 
     | 
    
         
             
                    data = {}
         
     | 
| 
       237 
155 
     | 
    
         
             
                    exclude = exclude or set()
         
     | 
| 
       238 
156 
     | 
    
         
             
                    for k in self.allowed():
         
     | 
| 
       239 
     | 
    
         
            -
                        if k not in exclude 
     | 
| 
       240 
     | 
    
         
            -
                            v  
     | 
| 
       241 
     | 
    
         
            -
             
     | 
| 
       242 
     | 
    
         
            -
             
     | 
| 
      
 157 
     | 
    
         
            +
                        if k not in exclude:
         
     | 
| 
      
 158 
     | 
    
         
            +
                            v = getattr(self, k, Undefined)
         
     | 
| 
      
 159 
     | 
    
         
            +
                            if not self._is_sentinel(v):
         
     | 
| 
      
 160 
     | 
    
         
            +
                                data[k] = self._normalize_value(v)
         
     | 
| 
       243 
161 
     | 
    
         
             
                    return data
         
     | 
| 
       244 
162 
     | 
    
         | 
| 
       245 
163 
     | 
    
         
             
                def __hash__(self) -> int:
         
     | 
| 
       246 
     | 
    
         
            -
                    from  
     | 
| 
      
 164 
     | 
    
         
            +
                    from .._hash import hash_dict
         
     | 
| 
       247 
165 
     | 
    
         | 
| 
       248 
166 
     | 
    
         
             
                    return hash_dict(self.to_dict())
         
     | 
| 
       249 
167 
     | 
    
         | 
| 
         @@ -261,16 +179,20 @@ class Params: 
     | 
|
| 
       261 
179 
     | 
    
         | 
| 
       262 
180 
     | 
    
         
             
            @dataclass(slots=True)
         
     | 
| 
       263 
181 
     | 
    
         
             
            class DataClass:
         
     | 
| 
       264 
     | 
    
         
            -
                """A base class for data classes with strict parameter handling. 
     | 
| 
      
 182 
     | 
    
         
            +
                """A base class for data classes with strict parameter handling.
         
     | 
| 
       265 
183 
     | 
    
         | 
| 
       266 
     | 
    
         
            -
                 
     | 
| 
       267 
     | 
    
         
            -
                """If True, None is treated as a sentinel value."""
         
     | 
| 
      
 184 
     | 
    
         
            +
                Use the ModelConfig class attribute to customize behavior:
         
     | 
| 
       268 
185 
     | 
    
         | 
| 
       269 
     | 
    
         
            -
                 
     | 
| 
       270 
     | 
    
         
            -
             
     | 
| 
      
 186 
     | 
    
         
            +
                Example:
         
     | 
| 
      
 187 
     | 
    
         
            +
                    @dataclass(slots=True)
         
     | 
| 
      
 188 
     | 
    
         
            +
                    class MyDataClass(DataClass):
         
     | 
| 
      
 189 
     | 
    
         
            +
                        _config: ClassVar[ModelConfig] = ModelConfig(strict=True, prefill_unset=False)
         
     | 
| 
      
 190 
     | 
    
         
            +
                        field1: str
         
     | 
| 
      
 191 
     | 
    
         
            +
                        field2: int
         
     | 
| 
      
 192 
     | 
    
         
            +
                """
         
     | 
| 
       271 
193 
     | 
    
         | 
| 
       272 
     | 
    
         
            -
                 
     | 
| 
       273 
     | 
    
         
            -
                """ 
     | 
| 
      
 194 
     | 
    
         
            +
                _config: ClassVar[ModelConfig] = ModelConfig()
         
     | 
| 
      
 195 
     | 
    
         
            +
                """Configuration for this DataClass."""
         
     | 
| 
       274 
196 
     | 
    
         | 
| 
       275 
197 
     | 
    
         
             
                _allowed_keys: ClassVar[set[str]] = field(
         
     | 
| 
       276 
198 
     | 
    
         
             
                    default=set(), init=False, repr=False
         
     | 
| 
         @@ -294,10 +216,12 @@ class DataClass: 
     | 
|
| 
       294 
216 
     | 
    
         
             
                @override
         
     | 
| 
       295 
217 
     | 
    
         
             
                def _validate(self) -> None:
         
     | 
| 
       296 
218 
     | 
    
         
             
                    def _validate_strict(k):
         
     | 
| 
       297 
     | 
    
         
            -
                        if self. 
     | 
| 
      
 219 
     | 
    
         
            +
                        if self._config.strict and self._is_sentinel(
         
     | 
| 
      
 220 
     | 
    
         
            +
                            getattr(self, k, Unset)
         
     | 
| 
      
 221 
     | 
    
         
            +
                        ):
         
     | 
| 
       298 
222 
     | 
    
         
             
                            raise ValueError(f"Missing required parameter: {k}")
         
     | 
| 
       299 
223 
     | 
    
         
             
                        if (
         
     | 
| 
       300 
     | 
    
         
            -
                            self. 
     | 
| 
      
 224 
     | 
    
         
            +
                            self._config.prefill_unset
         
     | 
| 
       301 
225 
     | 
    
         
             
                            and getattr(self, k, Undefined) is Undefined
         
     | 
| 
       302 
226 
     | 
    
         
             
                        ):
         
     | 
| 
       303 
227 
     | 
    
         
             
                            self.__setattr__(k, Unset)
         
     | 
| 
         @@ -309,18 +233,34 @@ class DataClass: 
     | 
|
| 
       309 
233 
     | 
    
         
             
                    data = {}
         
     | 
| 
       310 
234 
     | 
    
         
             
                    exclude = exclude or set()
         
     | 
| 
       311 
235 
     | 
    
         
             
                    for k in type(self).allowed():
         
     | 
| 
       312 
     | 
    
         
            -
                        if k not in exclude 
     | 
| 
       313 
     | 
    
         
            -
                            v  
     | 
| 
       314 
     | 
    
         
            -
             
     | 
| 
       315 
     | 
    
         
            -
             
     | 
| 
      
 236 
     | 
    
         
            +
                        if k not in exclude:
         
     | 
| 
      
 237 
     | 
    
         
            +
                            v = getattr(self, k)
         
     | 
| 
      
 238 
     | 
    
         
            +
                            if not self._is_sentinel(v):
         
     | 
| 
      
 239 
     | 
    
         
            +
                                data[k] = self._normalize_value(v)
         
     | 
| 
       316 
240 
     | 
    
         
             
                    return data
         
     | 
| 
       317 
241 
     | 
    
         | 
| 
       318 
242 
     | 
    
         
             
                @classmethod
         
     | 
| 
       319 
243 
     | 
    
         
             
                def _is_sentinel(cls, value: Any) -> bool:
         
     | 
| 
       320 
244 
     | 
    
         
             
                    """Check if a value is a sentinel (Undefined or Unset)."""
         
     | 
| 
       321 
     | 
    
         
            -
                     
     | 
| 
       322 
     | 
    
         
            -
                         
     | 
| 
       323 
     | 
    
         
            -
             
     | 
| 
      
 245 
     | 
    
         
            +
                    return is_sentinel(
         
     | 
| 
      
 246 
     | 
    
         
            +
                        value,
         
     | 
| 
      
 247 
     | 
    
         
            +
                        none_as_sentinel=cls._config.none_as_sentinel,
         
     | 
| 
      
 248 
     | 
    
         
            +
                        empty_as_sentinel=cls._config.empty_as_sentinel,
         
     | 
| 
      
 249 
     | 
    
         
            +
                    )
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 252 
     | 
    
         
            +
                def _normalize_value(cls, value: Any) -> Any:
         
     | 
| 
      
 253 
     | 
    
         
            +
                    """Normalize a value for serialization.
         
     | 
| 
      
 254 
     | 
    
         
            +
             
     | 
| 
      
 255 
     | 
    
         
            +
                    Handles:
         
     | 
| 
      
 256 
     | 
    
         
            +
                    - Enum values if use_enum_values is True
         
     | 
| 
      
 257 
     | 
    
         
            +
                    - Can be extended for other transformations
         
     | 
| 
      
 258 
     | 
    
         
            +
                    """
         
     | 
| 
      
 259 
     | 
    
         
            +
                    from enum import Enum as _Enum
         
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
      
 261 
     | 
    
         
            +
                    if cls._config.use_enum_values and isinstance(value, _Enum):
         
     | 
| 
      
 262 
     | 
    
         
            +
                        return value.value
         
     | 
| 
      
 263 
     | 
    
         
            +
                    return value
         
     | 
| 
       324 
264 
     | 
    
         | 
| 
       325 
265 
     | 
    
         
             
                def with_updates(self, **kwargs: Any) -> DataClass:
         
     | 
| 
       326 
266 
     | 
    
         
             
                    """Return a new instance with updated fields."""
         
     | 
| 
         @@ -329,7 +269,7 @@ class DataClass: 
     | 
|
| 
       329 
269 
     | 
    
         
             
                    return type(self)(**dict_)
         
     | 
| 
       330 
270 
     | 
    
         | 
| 
       331 
271 
     | 
    
         
             
                def __hash__(self) -> int:
         
     | 
| 
       332 
     | 
    
         
            -
                    from  
     | 
| 
      
 272 
     | 
    
         
            +
                    from .._hash import hash_dict
         
     | 
| 
       333 
273 
     | 
    
         | 
| 
       334 
274 
     | 
    
         
             
                    return hash_dict(self.to_dict())
         
     | 
| 
       335 
275 
     | 
    
         |