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
 
    
        lionagi/__init__.py
    CHANGED
    
    | 
         @@ -5,94 +5,137 @@ import logging 
     | 
|
| 
       5 
5 
     | 
    
         
             
            from typing import TYPE_CHECKING
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            from . import ln as ln
         
     | 
| 
      
 8 
     | 
    
         
            +
            from .ln.types import DataClass, Operable, Params, Spec, Undefined, Unset
         
     | 
| 
       8 
9 
     | 
    
         
             
            from .version import __version__
         
     | 
| 
       9 
10 
     | 
    
         | 
| 
       10 
11 
     | 
    
         
             
            if TYPE_CHECKING:
         
     | 
| 
       11 
12 
     | 
    
         
             
                from pydantic import BaseModel, Field
         
     | 
| 
       12 
13 
     | 
    
         | 
| 
       13 
14 
     | 
    
         
             
                from . import _types as types
         
     | 
| 
      
 15 
     | 
    
         
            +
                from .models.field_model import FieldModel
         
     | 
| 
      
 16 
     | 
    
         
            +
                from .models.operable_model import OperableModel
         
     | 
| 
       14 
17 
     | 
    
         
             
                from .operations.builder import OperationGraphBuilder as Builder
         
     | 
| 
       15 
18 
     | 
    
         
             
                from .operations.node import Operation
         
     | 
| 
       16 
19 
     | 
    
         
             
                from .protocols.action.manager import load_mcp_tools
         
     | 
| 
      
 20 
     | 
    
         
            +
                from .protocols.types import (
         
     | 
| 
      
 21 
     | 
    
         
            +
                    Edge,
         
     | 
| 
      
 22 
     | 
    
         
            +
                    Element,
         
     | 
| 
      
 23 
     | 
    
         
            +
                    Event,
         
     | 
| 
      
 24 
     | 
    
         
            +
                    Graph,
         
     | 
| 
      
 25 
     | 
    
         
            +
                    Node,
         
     | 
| 
      
 26 
     | 
    
         
            +
                    Pile,
         
     | 
| 
      
 27 
     | 
    
         
            +
                    Progression,
         
     | 
| 
      
 28 
     | 
    
         
            +
                )
         
     | 
| 
      
 29 
     | 
    
         
            +
                from .service.broadcaster import Broadcaster
         
     | 
| 
      
 30 
     | 
    
         
            +
                from .service.hooks import HookedEvent, HookRegistry
         
     | 
| 
       17 
31 
     | 
    
         
             
                from .service.imodel import iModel
         
     | 
| 
       18 
32 
     | 
    
         
             
                from .session.session import Branch, Session
         
     | 
| 
       19 
33 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
34 
     | 
    
         
             
            logger = logging.getLogger(__name__)
         
     | 
| 
       22 
35 
     | 
    
         
             
            logger.setLevel(logging.INFO)
         
     | 
| 
       23 
36 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
            # Module-level lazy loading cache
         
     | 
| 
       25 
37 
     | 
    
         
             
            _lazy_imports = {}
         
     | 
| 
       26 
38 
     | 
    
         | 
| 
       27 
39 
     | 
    
         | 
| 
      
 40 
     | 
    
         
            +
            def _get_obj(name: str, module: str):
         
     | 
| 
      
 41 
     | 
    
         
            +
                global _lazy_imports
         
     | 
| 
      
 42 
     | 
    
         
            +
                from lionagi.ln import import_module
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                obj_ = import_module("lionagi", module_name=module, import_name=name)
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                _lazy_imports[name] = obj_
         
     | 
| 
      
 47 
     | 
    
         
            +
                return obj_
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
       28 
50 
     | 
    
         
             
            def __getattr__(name: str):
         
     | 
| 
       29 
     | 
    
         
            -
                 
     | 
| 
      
 51 
     | 
    
         
            +
                global _lazy_imports
         
     | 
| 
       30 
52 
     | 
    
         
             
                if name in _lazy_imports:
         
     | 
| 
       31 
53 
     | 
    
         
             
                    return _lazy_imports[name]
         
     | 
| 
       32 
54 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
                 
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
                     
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
                     
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                     
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
                     
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
                     
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
                     
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
                     
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
                     
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
                     
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
                     
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
             
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
                     
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
                     
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
      
 55 
     | 
    
         
            +
                match name:
         
     | 
| 
      
 56 
     | 
    
         
            +
                    case "Session":
         
     | 
| 
      
 57 
     | 
    
         
            +
                        return _get_obj("Session", "session.session")
         
     | 
| 
      
 58 
     | 
    
         
            +
                    case "Branch":
         
     | 
| 
      
 59 
     | 
    
         
            +
                        return _get_obj("Branch", "session.branch")
         
     | 
| 
      
 60 
     | 
    
         
            +
                    case "iModel":
         
     | 
| 
      
 61 
     | 
    
         
            +
                        return _get_obj("iModel", "service.imodel")
         
     | 
| 
      
 62 
     | 
    
         
            +
                    case "Builder":
         
     | 
| 
      
 63 
     | 
    
         
            +
                        return _get_obj("OperationGraphBuilder", "operations.builder")
         
     | 
| 
      
 64 
     | 
    
         
            +
                    case "Operation":
         
     | 
| 
      
 65 
     | 
    
         
            +
                        return _get_obj("Operation", "operations.node")
         
     | 
| 
      
 66 
     | 
    
         
            +
                    case "load_mcp_tools":
         
     | 
| 
      
 67 
     | 
    
         
            +
                        return _get_obj("load_mcp_tools", "protocols.action.manager")
         
     | 
| 
      
 68 
     | 
    
         
            +
                    case "FieldModel":
         
     | 
| 
      
 69 
     | 
    
         
            +
                        return _get_obj("FieldModel", "models.field_model")
         
     | 
| 
      
 70 
     | 
    
         
            +
                    case "OperableModel":
         
     | 
| 
      
 71 
     | 
    
         
            +
                        return _get_obj("OperableModel", "models.operable_model")
         
     | 
| 
      
 72 
     | 
    
         
            +
                    case "Element":
         
     | 
| 
      
 73 
     | 
    
         
            +
                        return _get_obj("Element", "protocols.generic.element")
         
     | 
| 
      
 74 
     | 
    
         
            +
                    case "Pile":
         
     | 
| 
      
 75 
     | 
    
         
            +
                        return _get_obj("Pile", "protocols.generic.pile")
         
     | 
| 
      
 76 
     | 
    
         
            +
                    case "Progression":
         
     | 
| 
      
 77 
     | 
    
         
            +
                        return _get_obj("Progression", "protocols.generic.progression")
         
     | 
| 
      
 78 
     | 
    
         
            +
                    case "Node":
         
     | 
| 
      
 79 
     | 
    
         
            +
                        return _get_obj("Node", "protocols.graph.node")
         
     | 
| 
      
 80 
     | 
    
         
            +
                    case "Edge":
         
     | 
| 
      
 81 
     | 
    
         
            +
                        return _get_obj("Edge", "protocols.graph.edge")
         
     | 
| 
      
 82 
     | 
    
         
            +
                    case "Graph":
         
     | 
| 
      
 83 
     | 
    
         
            +
                        return _get_obj("Graph", "protocols.graph.graph")
         
     | 
| 
      
 84 
     | 
    
         
            +
                    case "Event":
         
     | 
| 
      
 85 
     | 
    
         
            +
                        return _get_obj("Event", "protocols.generic.event")
         
     | 
| 
      
 86 
     | 
    
         
            +
                    case "HookRegistry":
         
     | 
| 
      
 87 
     | 
    
         
            +
                        return _get_obj("HookRegistry", "service.hooks.hook_registry")
         
     | 
| 
      
 88 
     | 
    
         
            +
                    case "HookedEvent":
         
     | 
| 
      
 89 
     | 
    
         
            +
                        return _get_obj("HookedEvent", "service.hooks.hooked_event")
         
     | 
| 
      
 90 
     | 
    
         
            +
                    case "Broadcaster":
         
     | 
| 
      
 91 
     | 
    
         
            +
                        return _get_obj("Broadcaster", "service.broadcaster")
         
     | 
| 
      
 92 
     | 
    
         
            +
                    case "BaseModel":
         
     | 
| 
      
 93 
     | 
    
         
            +
                        from pydantic import BaseModel
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                        _lazy_imports["BaseModel"] = BaseModel
         
     | 
| 
      
 96 
     | 
    
         
            +
                        return BaseModel
         
     | 
| 
      
 97 
     | 
    
         
            +
                    case "Field":
         
     | 
| 
      
 98 
     | 
    
         
            +
                        from pydantic import Field
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                        _lazy_imports["Field"] = Field
         
     | 
| 
      
 101 
     | 
    
         
            +
                        return Field
         
     | 
| 
      
 102 
     | 
    
         
            +
                    case "types":
         
     | 
| 
      
 103 
     | 
    
         
            +
                        from . import _types as types
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                        _lazy_imports["types"] = types
         
     | 
| 
      
 106 
     | 
    
         
            +
                        return types
         
     | 
| 
       82 
107 
     | 
    
         
             
                raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
         
     | 
| 
       83 
108 
     | 
    
         | 
| 
       84 
109 
     | 
    
         | 
| 
       85 
110 
     | 
    
         
             
            __all__ = (
         
     | 
| 
       86 
     | 
    
         
            -
                "Session",
         
     | 
| 
       87 
     | 
    
         
            -
                "Branch",
         
     | 
| 
       88 
     | 
    
         
            -
                "iModel",
         
     | 
| 
       89 
     | 
    
         
            -
                "types",
         
     | 
| 
       90 
111 
     | 
    
         
             
                "__version__",
         
     | 
| 
       91 
112 
     | 
    
         
             
                "BaseModel",
         
     | 
| 
       92 
     | 
    
         
            -
                " 
     | 
| 
       93 
     | 
    
         
            -
                " 
     | 
| 
      
 113 
     | 
    
         
            +
                "Branch",
         
     | 
| 
      
 114 
     | 
    
         
            +
                "Broadcaster",
         
     | 
| 
       94 
115 
     | 
    
         
             
                "Builder",
         
     | 
| 
      
 116 
     | 
    
         
            +
                "DataClass",
         
     | 
| 
      
 117 
     | 
    
         
            +
                "Edge",
         
     | 
| 
      
 118 
     | 
    
         
            +
                "Element",
         
     | 
| 
      
 119 
     | 
    
         
            +
                "Event",
         
     | 
| 
      
 120 
     | 
    
         
            +
                "Field",
         
     | 
| 
      
 121 
     | 
    
         
            +
                "FieldModel",
         
     | 
| 
      
 122 
     | 
    
         
            +
                "Graph",
         
     | 
| 
      
 123 
     | 
    
         
            +
                "HookRegistry",
         
     | 
| 
      
 124 
     | 
    
         
            +
                "HookedEvent",
         
     | 
| 
      
 125 
     | 
    
         
            +
                "Node",
         
     | 
| 
      
 126 
     | 
    
         
            +
                "Operable",
         
     | 
| 
      
 127 
     | 
    
         
            +
                "OperableModel",
         
     | 
| 
       95 
128 
     | 
    
         
             
                "Operation",
         
     | 
| 
       96 
     | 
    
         
            -
                " 
     | 
| 
      
 129 
     | 
    
         
            +
                "Params",
         
     | 
| 
      
 130 
     | 
    
         
            +
                "Pile",
         
     | 
| 
      
 131 
     | 
    
         
            +
                "Progression",
         
     | 
| 
      
 132 
     | 
    
         
            +
                "Session",
         
     | 
| 
      
 133 
     | 
    
         
            +
                "Spec",
         
     | 
| 
      
 134 
     | 
    
         
            +
                "Undefined",
         
     | 
| 
      
 135 
     | 
    
         
            +
                "Unset",
         
     | 
| 
      
 136 
     | 
    
         
            +
                "iModel",
         
     | 
| 
       97 
137 
     | 
    
         
             
                "ln",
         
     | 
| 
      
 138 
     | 
    
         
            +
                "load_mcp_tools",
         
     | 
| 
      
 139 
     | 
    
         
            +
                "logger",
         
     | 
| 
      
 140 
     | 
    
         
            +
                "types",
         
     | 
| 
       98 
141 
     | 
    
         
             
            )
         
     | 
| 
         @@ -0,0 +1,236 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            """Abstract base class for Spec adapters.
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Adapters convert framework-agnostic Spec objects to framework-specific
         
     | 
| 
      
 4 
     | 
    
         
            +
            field and model definitions (Pydantic, msgspec, attrs, dataclasses).
         
     | 
| 
      
 5 
     | 
    
         
            +
            """
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            from abc import ABC, abstractmethod
         
     | 
| 
      
 8 
     | 
    
         
            +
            from typing import TYPE_CHECKING, Any
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            if TYPE_CHECKING:
         
     | 
| 
      
 11 
     | 
    
         
            +
                from lionagi.ln.types import Operable, Spec
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            __all__ = ("SpecAdapter",)
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            class SpecAdapter(ABC):
         
     | 
| 
      
 17 
     | 
    
         
            +
                """Base adapter for converting Spec to framework-specific formats.
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                Abstract Methods (must implement):
         
     | 
| 
      
 20 
     | 
    
         
            +
                    - create_field: Spec → framework field
         
     | 
| 
      
 21 
     | 
    
         
            +
                    - create_model: Operable → framework model class
         
     | 
| 
      
 22 
     | 
    
         
            +
                    - validate_model: dict → validated model instance
         
     | 
| 
      
 23 
     | 
    
         
            +
                    - dump_model: model instance → dict
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                Concrete Methods (shared):
         
     | 
| 
      
 26 
     | 
    
         
            +
                    - parse_json: Extract JSON from text
         
     | 
| 
      
 27 
     | 
    
         
            +
                    - fuzzy_match_fields: Match dict keys to model fields
         
     | 
| 
      
 28 
     | 
    
         
            +
                    - validate_response: Full validation pipeline
         
     | 
| 
      
 29 
     | 
    
         
            +
                    - update_model: Update model instance (uses dump_model + validate_model)
         
     | 
| 
      
 30 
     | 
    
         
            +
                """
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                # ---- Abstract Methods ----
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 35 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
      
 36 
     | 
    
         
            +
                def create_field(cls, spec: "Spec") -> Any:
         
     | 
| 
      
 37 
     | 
    
         
            +
                    """Convert Spec to framework-specific field definition.
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 40 
     | 
    
         
            +
                        spec: Spec object
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 43 
     | 
    
         
            +
                        Framework-specific field (FieldInfo, Attribute, Field, etc.)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    """
         
     | 
| 
      
 45 
     | 
    
         
            +
                    ...
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 48 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
      
 49 
     | 
    
         
            +
                def create_model(
         
     | 
| 
      
 50 
     | 
    
         
            +
                    cls,
         
     | 
| 
      
 51 
     | 
    
         
            +
                    operable: "Operable",
         
     | 
| 
      
 52 
     | 
    
         
            +
                    model_name: str,
         
     | 
| 
      
 53 
     | 
    
         
            +
                    include: set[str] | None = None,
         
     | 
| 
      
 54 
     | 
    
         
            +
                    exclude: set[str] | None = None,
         
     | 
| 
      
 55 
     | 
    
         
            +
                    **kwargs: Any,
         
     | 
| 
      
 56 
     | 
    
         
            +
                ) -> type:
         
     | 
| 
      
 57 
     | 
    
         
            +
                    """Generate model class from Operable.
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 60 
     | 
    
         
            +
                        operable: Operable containing specs
         
     | 
| 
      
 61 
     | 
    
         
            +
                        model_name: Name for generated model
         
     | 
| 
      
 62 
     | 
    
         
            +
                        include: Only include these field names
         
     | 
| 
      
 63 
     | 
    
         
            +
                        exclude: Exclude these field names
         
     | 
| 
      
 64 
     | 
    
         
            +
                        **kwargs: Framework-specific options
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 67 
     | 
    
         
            +
                        Generated model class
         
     | 
| 
      
 68 
     | 
    
         
            +
                    """
         
     | 
| 
      
 69 
     | 
    
         
            +
                    ...
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 72 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
      
 73 
     | 
    
         
            +
                def validate_model(cls, model_cls: type, data: dict) -> Any:
         
     | 
| 
      
 74 
     | 
    
         
            +
                    """Validate dict data into model instance.
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                    Framework-agnostic validation hook. Each adapter implements
         
     | 
| 
      
 77 
     | 
    
         
            +
                    the appropriate validation mechanism:
         
     | 
| 
      
 78 
     | 
    
         
            +
                        - Pydantic: model_cls.model_validate(data)
         
     | 
| 
      
 79 
     | 
    
         
            +
                        - msgspec: msgspec.convert(data, type=model_cls)
         
     | 
| 
      
 80 
     | 
    
         
            +
                        - attrs: model_cls(**data)
         
     | 
| 
      
 81 
     | 
    
         
            +
                        - dataclasses: model_cls(**data)
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 84 
     | 
    
         
            +
                        model_cls: Model class
         
     | 
| 
      
 85 
     | 
    
         
            +
                        data: Dictionary data to validate
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 88 
     | 
    
         
            +
                        Validated model instance
         
     | 
| 
      
 89 
     | 
    
         
            +
                    """
         
     | 
| 
      
 90 
     | 
    
         
            +
                    ...
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 93 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
      
 94 
     | 
    
         
            +
                def dump_model(cls, instance: Any) -> dict:
         
     | 
| 
      
 95 
     | 
    
         
            +
                    """Dump model instance to dictionary.
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                    Framework-agnostic serialization hook. Each adapter implements
         
     | 
| 
      
 98 
     | 
    
         
            +
                    the appropriate serialization mechanism:
         
     | 
| 
      
 99 
     | 
    
         
            +
                        - Pydantic: instance.model_dump()
         
     | 
| 
      
 100 
     | 
    
         
            +
                        - msgspec: msgspec.to_builtins(instance)
         
     | 
| 
      
 101 
     | 
    
         
            +
                        - attrs: attr.asdict(instance)
         
     | 
| 
      
 102 
     | 
    
         
            +
                        - dataclasses: dataclasses.asdict(instance)
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 105 
     | 
    
         
            +
                        instance: Model instance
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 108 
     | 
    
         
            +
                        Dictionary representation
         
     | 
| 
      
 109 
     | 
    
         
            +
                    """
         
     | 
| 
      
 110 
     | 
    
         
            +
                    ...
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 113 
     | 
    
         
            +
                def create_validator(cls, spec: "Spec") -> Any:
         
     | 
| 
      
 114 
     | 
    
         
            +
                    """Generate framework-specific validators from Spec metadata.
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 117 
     | 
    
         
            +
                        spec: Spec with validator metadata
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 120 
     | 
    
         
            +
                        Framework-specific validator, or None if not supported
         
     | 
| 
      
 121 
     | 
    
         
            +
                    """
         
     | 
| 
      
 122 
     | 
    
         
            +
                    return None
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                # ---- Concrete Methods (Shared) ----
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 127 
     | 
    
         
            +
                def parse_json(cls, text: str, fuzzy: bool = True) -> dict | list | Any:
         
     | 
| 
      
 128 
     | 
    
         
            +
                    """Extract and parse JSON from text.
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 131 
     | 
    
         
            +
                        text: Raw text potentially containing JSON
         
     | 
| 
      
 132 
     | 
    
         
            +
                        fuzzy: Use fuzzy parsing (markdown extraction)
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 135 
     | 
    
         
            +
                        Parsed JSON object
         
     | 
| 
      
 136 
     | 
    
         
            +
                    """
         
     | 
| 
      
 137 
     | 
    
         
            +
                    from lionagi.ln import extract_json
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                    data = extract_json(text, fuzzy_parse=fuzzy)
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                    # Unwrap single-item lists/tuples
         
     | 
| 
      
 142 
     | 
    
         
            +
                    if isinstance(data, (list, tuple)) and len(data) == 1:
         
     | 
| 
      
 143 
     | 
    
         
            +
                        data = data[0]
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                    return data
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 148 
     | 
    
         
            +
                @abstractmethod
         
     | 
| 
      
 149 
     | 
    
         
            +
                def fuzzy_match_fields(
         
     | 
| 
      
 150 
     | 
    
         
            +
                    cls, data: dict, model_cls: type, strict: bool = False
         
     | 
| 
      
 151 
     | 
    
         
            +
                ) -> dict:
         
     | 
| 
      
 152 
     | 
    
         
            +
                    """Match data keys to model fields with fuzzy matching.
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                    Framework-specific method - each adapter must implement based on how
         
     | 
| 
      
 155 
     | 
    
         
            +
                    their framework exposes field definitions.
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 158 
     | 
    
         
            +
                        data: Raw data dictionary
         
     | 
| 
      
 159 
     | 
    
         
            +
                        model_cls: Target model class
         
     | 
| 
      
 160 
     | 
    
         
            +
                        strict: If True, raise on unmatched; if False, force coercion
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 163 
     | 
    
         
            +
                        Dictionary with keys matched to model fields
         
     | 
| 
      
 164 
     | 
    
         
            +
                    """
         
     | 
| 
      
 165 
     | 
    
         
            +
                    ...
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 168 
     | 
    
         
            +
                def validate_response(
         
     | 
| 
      
 169 
     | 
    
         
            +
                    cls,
         
     | 
| 
      
 170 
     | 
    
         
            +
                    text: str,
         
     | 
| 
      
 171 
     | 
    
         
            +
                    model_cls: type,
         
     | 
| 
      
 172 
     | 
    
         
            +
                    strict: bool = False,
         
     | 
| 
      
 173 
     | 
    
         
            +
                    fuzzy_parse: bool = True,
         
     | 
| 
      
 174 
     | 
    
         
            +
                ) -> Any | None:
         
     | 
| 
      
 175 
     | 
    
         
            +
                    """Validate and parse response text into model instance.
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
                    Pipeline: parse_json → fuzzy_match_fields → validate_model
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 180 
     | 
    
         
            +
                        text: Raw response text
         
     | 
| 
      
 181 
     | 
    
         
            +
                        model_cls: Target model class
         
     | 
| 
      
 182 
     | 
    
         
            +
                        strict: If True, raise on errors; if False, return None
         
     | 
| 
      
 183 
     | 
    
         
            +
                        fuzzy_parse: Use fuzzy JSON parsing
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 186 
     | 
    
         
            +
                        Validated model instance, or None if validation fails (strict=False)
         
     | 
| 
      
 187 
     | 
    
         
            +
                    """
         
     | 
| 
      
 188 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 189 
     | 
    
         
            +
                        # Step 1: Parse JSON
         
     | 
| 
      
 190 
     | 
    
         
            +
                        data = cls.parse_json(text, fuzzy=fuzzy_parse)
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                        # Step 2: Fuzzy match fields
         
     | 
| 
      
 193 
     | 
    
         
            +
                        matched_data = cls.fuzzy_match_fields(
         
     | 
| 
      
 194 
     | 
    
         
            +
                            data, model_cls, strict=strict
         
     | 
| 
      
 195 
     | 
    
         
            +
                        )
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                        # Step 3: Validate with framework-specific method
         
     | 
| 
      
 198 
     | 
    
         
            +
                        instance = cls.validate_model(model_cls, matched_data)
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                        return instance
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                    except (ValueError, TypeError, KeyError, AttributeError) as e:
         
     | 
| 
      
 203 
     | 
    
         
            +
                        # Catch validation-related exceptions only
         
     | 
| 
      
 204 
     | 
    
         
            +
                        # ValueError: JSON/parsing errors, validation failures
         
     | 
| 
      
 205 
     | 
    
         
            +
                        # TypeError: Type mismatches during validation
         
     | 
| 
      
 206 
     | 
    
         
            +
                        # KeyError: Missing required fields
         
     | 
| 
      
 207 
     | 
    
         
            +
                        # AttributeError: Field access errors
         
     | 
| 
      
 208 
     | 
    
         
            +
                        if strict:
         
     | 
| 
      
 209 
     | 
    
         
            +
                            raise
         
     | 
| 
      
 210 
     | 
    
         
            +
                        return None
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 213 
     | 
    
         
            +
                def update_model(
         
     | 
| 
      
 214 
     | 
    
         
            +
                    cls,
         
     | 
| 
      
 215 
     | 
    
         
            +
                    instance: Any,
         
     | 
| 
      
 216 
     | 
    
         
            +
                    updates: dict,
         
     | 
| 
      
 217 
     | 
    
         
            +
                    model_cls: type | None = None,
         
     | 
| 
      
 218 
     | 
    
         
            +
                ) -> Any:
         
     | 
| 
      
 219 
     | 
    
         
            +
                    """Update existing model instance with new data.
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 222 
     | 
    
         
            +
                        instance: Existing model instance
         
     | 
| 
      
 223 
     | 
    
         
            +
                        updates: Dictionary of updates
         
     | 
| 
      
 224 
     | 
    
         
            +
                        model_cls: Optional model class (defaults to instance's class)
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 227 
     | 
    
         
            +
                        New validated model instance with updates applied
         
     | 
| 
      
 228 
     | 
    
         
            +
                    """
         
     | 
| 
      
 229 
     | 
    
         
            +
                    model_cls = model_cls or type(instance)
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
                    # Merge existing data with updates
         
     | 
| 
      
 232 
     | 
    
         
            +
                    current_data = cls.dump_model(instance)
         
     | 
| 
      
 233 
     | 
    
         
            +
                    current_data.update(updates)
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                    # Validate merged data
         
     | 
| 
      
 236 
     | 
    
         
            +
                    return cls.validate_model(model_cls, current_data)
         
     | 
| 
         @@ -0,0 +1,158 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            """Pydantic adapter for Spec system."""
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            import functools
         
     | 
| 
      
 4 
     | 
    
         
            +
            from typing import TYPE_CHECKING, Any
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            from lionagi.ln.types import Unset, is_sentinel
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            from ._protocol import SpecAdapter
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            if TYPE_CHECKING:
         
     | 
| 
      
 11 
     | 
    
         
            +
                from pydantic import BaseModel
         
     | 
| 
      
 12 
     | 
    
         
            +
                from pydantic.fields import FieldInfo
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                from lionagi.ln.types import Operable, Spec
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            @functools.lru_cache(maxsize=1)
         
     | 
| 
      
 18 
     | 
    
         
            +
            def _get_pydantic_field_params() -> set[str]:
         
     | 
| 
      
 19 
     | 
    
         
            +
                """Get valid Pydantic Field parameters (cached, thread-safe)."""
         
     | 
| 
      
 20 
     | 
    
         
            +
                import inspect
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                from pydantic import Field as PydanticField
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                params = set(inspect.signature(PydanticField).parameters.keys())
         
     | 
| 
      
 25 
     | 
    
         
            +
                params.discard("kwargs")
         
     | 
| 
      
 26 
     | 
    
         
            +
                return params
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            class PydanticSpecAdapter(SpecAdapter):
         
     | 
| 
      
 30 
     | 
    
         
            +
                """Pydantic implementation of SpecAdapter."""
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 33 
     | 
    
         
            +
                def create_field(cls, spec: "Spec") -> "FieldInfo":
         
     | 
| 
      
 34 
     | 
    
         
            +
                    """Create a Pydantic FieldInfo object from Spec."""
         
     | 
| 
      
 35 
     | 
    
         
            +
                    from pydantic import Field as PydanticField
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    # Get valid Pydantic Field parameters (cached)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    pydantic_field_params = _get_pydantic_field_params()
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    # Extract metadata for FieldInfo
         
     | 
| 
      
 41 
     | 
    
         
            +
                    field_kwargs = {}
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    if not is_sentinel(spec.metadata, none_as_sentinel=True):
         
     | 
| 
      
 44 
     | 
    
         
            +
                        for meta in spec.metadata:
         
     | 
| 
      
 45 
     | 
    
         
            +
                            if meta.key == "default":
         
     | 
| 
      
 46 
     | 
    
         
            +
                                # Handle callable defaults as default_factory
         
     | 
| 
      
 47 
     | 
    
         
            +
                                if callable(meta.value):
         
     | 
| 
      
 48 
     | 
    
         
            +
                                    field_kwargs["default_factory"] = meta.value
         
     | 
| 
      
 49 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 50 
     | 
    
         
            +
                                    field_kwargs["default"] = meta.value
         
     | 
| 
      
 51 
     | 
    
         
            +
                            elif meta.key == "validator":
         
     | 
| 
      
 52 
     | 
    
         
            +
                                # Validators are handled separately in create_model
         
     | 
| 
      
 53 
     | 
    
         
            +
                                continue
         
     | 
| 
      
 54 
     | 
    
         
            +
                            elif meta.key in pydantic_field_params:
         
     | 
| 
      
 55 
     | 
    
         
            +
                                # Pass through standard Pydantic field attributes
         
     | 
| 
      
 56 
     | 
    
         
            +
                                field_kwargs[meta.key] = meta.value
         
     | 
| 
      
 57 
     | 
    
         
            +
                            elif meta.key in {"nullable", "listable"}:
         
     | 
| 
      
 58 
     | 
    
         
            +
                                # These are FieldTemplate markers, don't pass to FieldInfo
         
     | 
| 
      
 59 
     | 
    
         
            +
                                pass
         
     | 
| 
      
 60 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 61 
     | 
    
         
            +
                                # Filter out unserializable objects from json_schema_extra
         
     | 
| 
      
 62 
     | 
    
         
            +
                                if isinstance(meta.value, type):
         
     | 
| 
      
 63 
     | 
    
         
            +
                                    # Skip type objects - can't be serialized
         
     | 
| 
      
 64 
     | 
    
         
            +
                                    continue
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                                # Any other metadata goes in json_schema_extra
         
     | 
| 
      
 67 
     | 
    
         
            +
                                if "json_schema_extra" not in field_kwargs:
         
     | 
| 
      
 68 
     | 
    
         
            +
                                    field_kwargs["json_schema_extra"] = {}
         
     | 
| 
      
 69 
     | 
    
         
            +
                                field_kwargs["json_schema_extra"][meta.key] = meta.value
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    # Handle nullable case - ensure default is set if not already
         
     | 
| 
      
 72 
     | 
    
         
            +
                    if (
         
     | 
| 
      
 73 
     | 
    
         
            +
                        spec.is_nullable
         
     | 
| 
      
 74 
     | 
    
         
            +
                        and "default" not in field_kwargs
         
     | 
| 
      
 75 
     | 
    
         
            +
                        and "default_factory" not in field_kwargs
         
     | 
| 
      
 76 
     | 
    
         
            +
                    ):
         
     | 
| 
      
 77 
     | 
    
         
            +
                        field_kwargs["default"] = None
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    field_info = PydanticField(**field_kwargs)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    field_info.annotation = spec.annotation
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                    return field_info
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 85 
     | 
    
         
            +
                def create_validator(cls, spec: "Spec") -> dict | None:
         
     | 
| 
      
 86 
     | 
    
         
            +
                    """Create Pydantic field_validator from Spec metadata."""
         
     | 
| 
      
 87 
     | 
    
         
            +
                    if (v := spec.get("validator")) is Unset:
         
     | 
| 
      
 88 
     | 
    
         
            +
                        return None
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                    from pydantic import field_validator
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                    field_name = spec.name or "field"
         
     | 
| 
      
 93 
     | 
    
         
            +
                    return {f"{field_name}_validator": field_validator(field_name)(v)}
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 96 
     | 
    
         
            +
                def create_model(
         
     | 
| 
      
 97 
     | 
    
         
            +
                    cls,
         
     | 
| 
      
 98 
     | 
    
         
            +
                    op: "Operable",
         
     | 
| 
      
 99 
     | 
    
         
            +
                    model_name: str,
         
     | 
| 
      
 100 
     | 
    
         
            +
                    include: set[str] | None = None,
         
     | 
| 
      
 101 
     | 
    
         
            +
                    exclude: set[str] | None = None,
         
     | 
| 
      
 102 
     | 
    
         
            +
                    base_type: type["BaseModel"] | None = None,
         
     | 
| 
      
 103 
     | 
    
         
            +
                    doc: str | None = None,
         
     | 
| 
      
 104 
     | 
    
         
            +
                ) -> type["BaseModel"]:
         
     | 
| 
      
 105 
     | 
    
         
            +
                    """Generate Pydantic BaseModel from Operable."""
         
     | 
| 
      
 106 
     | 
    
         
            +
                    from lionagi.models.model_params import ModelParams
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                    use_specs = op.get_specs(include=include, exclude=exclude)
         
     | 
| 
      
 109 
     | 
    
         
            +
                    use_fields = {i.name: cls.create_field(i) for i in use_specs if i.name}
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                    model_cls = ModelParams(
         
     | 
| 
      
 112 
     | 
    
         
            +
                        name=model_name,
         
     | 
| 
      
 113 
     | 
    
         
            +
                        parameter_fields=use_fields,
         
     | 
| 
      
 114 
     | 
    
         
            +
                        base_type=base_type,
         
     | 
| 
      
 115 
     | 
    
         
            +
                        inherit_base=True,
         
     | 
| 
      
 116 
     | 
    
         
            +
                        doc=doc,
         
     | 
| 
      
 117 
     | 
    
         
            +
                    ).create_new_model()
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                    model_cls.model_rebuild()
         
     | 
| 
      
 120 
     | 
    
         
            +
                    return model_cls
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 123 
     | 
    
         
            +
                def fuzzy_match_fields(
         
     | 
| 
      
 124 
     | 
    
         
            +
                    cls, data: dict, model_cls: type["BaseModel"], strict: bool = False
         
     | 
| 
      
 125 
     | 
    
         
            +
                ) -> dict:
         
     | 
| 
      
 126 
     | 
    
         
            +
                    """Match data keys to Pydantic model fields with fuzzy matching.
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 129 
     | 
    
         
            +
                        data: Raw data dictionary
         
     | 
| 
      
 130 
     | 
    
         
            +
                        model_cls: Pydantic model class
         
     | 
| 
      
 131 
     | 
    
         
            +
                        strict: If True, raise on unmatched; if False, force coercion
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 134 
     | 
    
         
            +
                        Dictionary with keys matched to model fields
         
     | 
| 
      
 135 
     | 
    
         
            +
                    """
         
     | 
| 
      
 136 
     | 
    
         
            +
                    from lionagi.ln import fuzzy_match_keys
         
     | 
| 
      
 137 
     | 
    
         
            +
                    from lionagi.ln.types import Undefined
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                    handle_mode = "raise" if strict else "force"
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                    matched = fuzzy_match_keys(
         
     | 
| 
      
 142 
     | 
    
         
            +
                        data, model_cls.model_fields, handle_unmatched=handle_mode
         
     | 
| 
      
 143 
     | 
    
         
            +
                    )
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                    # Filter out undefined values
         
     | 
| 
      
 146 
     | 
    
         
            +
                    return {k: v for k, v in matched.items() if v != Undefined}
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 149 
     | 
    
         
            +
                def validate_model(
         
     | 
| 
      
 150 
     | 
    
         
            +
                    cls, model_cls: type["BaseModel"], data: dict
         
     | 
| 
      
 151 
     | 
    
         
            +
                ) -> "BaseModel":
         
     | 
| 
      
 152 
     | 
    
         
            +
                    """Validate dict data into Pydantic model instance."""
         
     | 
| 
      
 153 
     | 
    
         
            +
                    return model_cls.model_validate(data)
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 156 
     | 
    
         
            +
                def dump_model(cls, instance: "BaseModel") -> dict:
         
     | 
| 
      
 157 
     | 
    
         
            +
                    """Dump Pydantic model instance to dictionary."""
         
     | 
| 
      
 158 
     | 
    
         
            +
                    return instance.model_dump()
         
     | 
    
        lionagi/ln/_async_call.py
    CHANGED
    
    | 
         @@ -15,7 +15,7 @@ from .concurrency import ( 
     | 
|
| 
       15 
15 
     | 
    
         
             
                is_coro_func,
         
     | 
| 
       16 
16 
     | 
    
         
             
                move_on_after,
         
     | 
| 
       17 
17 
     | 
    
         
             
            )
         
     | 
| 
       18 
     | 
    
         
            -
            from .types import Params, T, Unset, not_sentinel
         
     | 
| 
      
 18 
     | 
    
         
            +
            from .types import ModelConfig, Params, T, Unset, not_sentinel
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
       20 
20 
     | 
    
         
             
            _INITIALIZED = False
         
     | 
| 
       21 
21 
     | 
    
         
             
            _MODEL_LIKE = None
         
     | 
| 
         @@ -262,7 +262,7 @@ async def bcall( 
     | 
|
| 
       262 
262 
     | 
    
         
             
            @dataclass(slots=True, init=False, frozen=True)
         
     | 
| 
       263 
263 
     | 
    
         
             
            class AlcallParams(Params):
         
     | 
| 
       264 
264 
     | 
    
         
             
                # ClassVar attributes
         
     | 
| 
       265 
     | 
    
         
            -
                 
     | 
| 
      
 265 
     | 
    
         
            +
                _config: ClassVar[ModelConfig] = ModelConfig(none_as_sentinel=True)
         
     | 
| 
       266 
266 
     | 
    
         
             
                _func: ClassVar[Any] = alcall
         
     | 
| 
       267 
267 
     | 
    
         | 
| 
       268 
268 
     | 
    
         
             
                # input processing
         
     | 
    
        lionagi/ln/fuzzy/_fuzzy_match.py
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            from dataclasses import dataclass
         
     | 
| 
       2 
2 
     | 
    
         
             
            from typing import Any, ClassVar, Literal
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
     | 
    
         
            -
            from ..types import KeysLike, Params, Unset
         
     | 
| 
      
 4 
     | 
    
         
            +
            from ..types import KeysLike, ModelConfig, Params, Unset
         
     | 
| 
       5 
5 
     | 
    
         
             
            from ._string_similarity import (
         
     | 
| 
       6 
6 
     | 
    
         
             
                SIMILARITY_ALGO_MAP,
         
     | 
| 
       7 
7 
     | 
    
         
             
                SIMILARITY_TYPE,
         
     | 
| 
         @@ -152,7 +152,7 @@ def fuzzy_match_keys( 
     | 
|
| 
       152 
152 
     | 
    
         | 
| 
       153 
153 
     | 
    
         
             
            @dataclass(slots=True, init=False, frozen=True)
         
     | 
| 
       154 
154 
     | 
    
         
             
            class FuzzyMatchKeysParams(Params):
         
     | 
| 
       155 
     | 
    
         
            -
                 
     | 
| 
      
 155 
     | 
    
         
            +
                _config: ClassVar[ModelConfig] = ModelConfig(none_as_sentinel=False)
         
     | 
| 
       156 
156 
     | 
    
         
             
                _func: ClassVar[Any] = fuzzy_match_keys
         
     | 
| 
       157 
157 
     | 
    
         | 
| 
       158 
158 
     | 
    
         
             
                similarity_algo: SIMILARITY_TYPE | SimilarityFunc = "jaro_winkler"
         
     | 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            from ._sentinel import (
         
     | 
| 
      
 2 
     | 
    
         
            +
                MaybeSentinel,
         
     | 
| 
      
 3 
     | 
    
         
            +
                MaybeUndefined,
         
     | 
| 
      
 4 
     | 
    
         
            +
                MaybeUnset,
         
     | 
| 
      
 5 
     | 
    
         
            +
                SingletonType,
         
     | 
| 
      
 6 
     | 
    
         
            +
                T,
         
     | 
| 
      
 7 
     | 
    
         
            +
                Undefined,
         
     | 
| 
      
 8 
     | 
    
         
            +
                UndefinedType,
         
     | 
| 
      
 9 
     | 
    
         
            +
                Unset,
         
     | 
| 
      
 10 
     | 
    
         
            +
                UnsetType,
         
     | 
| 
      
 11 
     | 
    
         
            +
                is_sentinel,
         
     | 
| 
      
 12 
     | 
    
         
            +
                not_sentinel,
         
     | 
| 
      
 13 
     | 
    
         
            +
            )
         
     | 
| 
      
 14 
     | 
    
         
            +
            from .base import (
         
     | 
| 
      
 15 
     | 
    
         
            +
                DataClass,
         
     | 
| 
      
 16 
     | 
    
         
            +
                Enum,
         
     | 
| 
      
 17 
     | 
    
         
            +
                KeysDict,
         
     | 
| 
      
 18 
     | 
    
         
            +
                KeysLike,
         
     | 
| 
      
 19 
     | 
    
         
            +
                Meta,
         
     | 
| 
      
 20 
     | 
    
         
            +
                ModelConfig,
         
     | 
| 
      
 21 
     | 
    
         
            +
                Params,
         
     | 
| 
      
 22 
     | 
    
         
            +
            )
         
     | 
| 
      
 23 
     | 
    
         
            +
            from .operable import Operable
         
     | 
| 
      
 24 
     | 
    
         
            +
            from .spec import CommonMeta, Spec
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            __all__ = (
         
     | 
| 
      
 27 
     | 
    
         
            +
                # Sentinel types
         
     | 
| 
      
 28 
     | 
    
         
            +
                "Undefined",
         
     | 
| 
      
 29 
     | 
    
         
            +
                "Unset",
         
     | 
| 
      
 30 
     | 
    
         
            +
                "MaybeUndefined",
         
     | 
| 
      
 31 
     | 
    
         
            +
                "MaybeUnset",
         
     | 
| 
      
 32 
     | 
    
         
            +
                "MaybeSentinel",
         
     | 
| 
      
 33 
     | 
    
         
            +
                "SingletonType",
         
     | 
| 
      
 34 
     | 
    
         
            +
                "UndefinedType",
         
     | 
| 
      
 35 
     | 
    
         
            +
                "UnsetType",
         
     | 
| 
      
 36 
     | 
    
         
            +
                "is_sentinel",
         
     | 
| 
      
 37 
     | 
    
         
            +
                "not_sentinel",
         
     | 
| 
      
 38 
     | 
    
         
            +
                # Base classes
         
     | 
| 
      
 39 
     | 
    
         
            +
                "ModelConfig",
         
     | 
| 
      
 40 
     | 
    
         
            +
                "Enum",
         
     | 
| 
      
 41 
     | 
    
         
            +
                "Params",
         
     | 
| 
      
 42 
     | 
    
         
            +
                "DataClass",
         
     | 
| 
      
 43 
     | 
    
         
            +
                "Meta",
         
     | 
| 
      
 44 
     | 
    
         
            +
                "KeysDict",
         
     | 
| 
      
 45 
     | 
    
         
            +
                "KeysLike",
         
     | 
| 
      
 46 
     | 
    
         
            +
                "T",
         
     | 
| 
      
 47 
     | 
    
         
            +
                # Spec system
         
     | 
| 
      
 48 
     | 
    
         
            +
                "Spec",
         
     | 
| 
      
 49 
     | 
    
         
            +
                "CommonMeta",
         
     | 
| 
      
 50 
     | 
    
         
            +
                "Operable",
         
     | 
| 
      
 51 
     | 
    
         
            +
            )
         
     |