lionagi 0.18.0__py3-none-any.whl → 0.18.1__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/_errors.py +0 -5
 - lionagi/fields.py +83 -0
 - lionagi/ln/__init__.py +3 -1
 - lionagi/ln/concurrency/primitives.py +4 -4
 - lionagi/ln/concurrency/task.py +1 -0
 - lionagi/models/field_model.py +12 -4
 - lionagi/models/hashable_model.py +2 -3
 - lionagi/operations/ReAct/ReAct.py +1 -1
 - lionagi/operations/act/act.py +3 -3
 - lionagi/operations/builder.py +5 -7
 - lionagi/operations/fields.py +380 -0
 - lionagi/operations/flow.py +4 -6
 - lionagi/operations/node.py +4 -4
 - lionagi/operations/operate/operate.py +9 -7
 - lionagi/{protocols/operatives → operations/operate}/operative.py +4 -5
 - lionagi/{protocols/operatives → operations/operate}/step.py +34 -39
 - lionagi/operations/select/select.py +1 -1
 - lionagi/operations/select/utils.py +7 -1
 - lionagi/operations/types.py +1 -1
 - lionagi/protocols/action/manager.py +5 -6
 - lionagi/protocols/contracts.py +2 -2
 - lionagi/protocols/generic/__init__.py +22 -0
 - lionagi/protocols/generic/element.py +36 -127
 - lionagi/protocols/generic/pile.py +9 -10
 - lionagi/protocols/generic/progression.py +23 -22
 - lionagi/protocols/graph/edge.py +6 -5
 - lionagi/protocols/ids.py +6 -49
 - lionagi/protocols/messages/__init__.py +3 -1
 - lionagi/protocols/messages/base.py +7 -6
 - lionagi/protocols/messages/instruction.py +0 -1
 - lionagi/protocols/types.py +1 -11
 - lionagi/service/connections/__init__.py +3 -0
 - lionagi/service/connections/providers/claude_code_cli.py +3 -2
 - lionagi/service/hooks/_types.py +1 -1
 - lionagi/service/hooks/_utils.py +1 -1
 - lionagi/service/hooks/hook_event.py +3 -8
 - lionagi/service/hooks/hook_registry.py +5 -5
 - lionagi/service/hooks/hooked_event.py +61 -1
 - lionagi/service/imodel.py +24 -20
 - lionagi/service/third_party/claude_code.py +1 -2
 - lionagi/service/third_party/openai_models.py +24 -22
 - lionagi/service/token_calculator.py +1 -94
 - lionagi/session/branch.py +26 -228
 - lionagi/session/session.py +5 -90
 - lionagi/version.py +1 -1
 - {lionagi-0.18.0.dist-info → lionagi-0.18.1.dist-info}/METADATA +6 -5
 - {lionagi-0.18.0.dist-info → lionagi-0.18.1.dist-info}/RECORD +49 -76
 - lionagi/fields/__init__.py +0 -47
 - lionagi/fields/action.py +0 -188
 - lionagi/fields/base.py +0 -153
 - lionagi/fields/code.py +0 -239
 - lionagi/fields/file.py +0 -234
 - lionagi/fields/instruct.py +0 -135
 - lionagi/fields/reason.py +0 -55
 - lionagi/fields/research.py +0 -52
 - lionagi/operations/brainstorm/__init__.py +0 -2
 - lionagi/operations/brainstorm/brainstorm.py +0 -498
 - lionagi/operations/brainstorm/prompt.py +0 -11
 - lionagi/operations/instruct/__init__.py +0 -2
 - lionagi/operations/instruct/instruct.py +0 -28
 - lionagi/operations/plan/__init__.py +0 -6
 - lionagi/operations/plan/plan.py +0 -386
 - lionagi/operations/plan/prompt.py +0 -25
 - lionagi/operations/utils.py +0 -45
 - lionagi/protocols/forms/__init__.py +0 -2
 - lionagi/protocols/forms/base.py +0 -85
 - lionagi/protocols/forms/flow.py +0 -79
 - lionagi/protocols/forms/form.py +0 -86
 - lionagi/protocols/forms/report.py +0 -48
 - lionagi/protocols/mail/__init__.py +0 -2
 - lionagi/protocols/mail/exchange.py +0 -220
 - lionagi/protocols/mail/mail.py +0 -51
 - lionagi/protocols/mail/mailbox.py +0 -103
 - lionagi/protocols/mail/manager.py +0 -218
 - lionagi/protocols/mail/package.py +0 -101
 - lionagi/protocols/operatives/__init__.py +0 -2
 - {lionagi-0.18.0.dist-info → lionagi-0.18.1.dist-info}/WHEEL +0 -0
 - {lionagi-0.18.0.dist-info → lionagi-0.18.1.dist-info}/licenses/LICENSE +0 -0
 
    
        lionagi/operations/flow.py
    CHANGED
    
    | 
         @@ -10,8 +10,9 @@ using Events for synchronization and CapacityLimiter for concurrency control. 
     | 
|
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
            import os
         
     | 
| 
       12 
12 
     | 
    
         
             
            from typing import TYPE_CHECKING, Any
         
     | 
| 
      
 13 
     | 
    
         
            +
            from uuid import UUID
         
     | 
| 
       13 
14 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
            from lionagi.ln 
     | 
| 
      
 15 
     | 
    
         
            +
            from lionagi.ln import AlcallParams
         
     | 
| 
       15 
16 
     | 
    
         
             
            from lionagi.ln.concurrency import CapacityLimiter, ConcurrencyEvent
         
     | 
| 
       16 
17 
     | 
    
         
             
            from lionagi.operations.node import Operation
         
     | 
| 
       17 
18 
     | 
    
         
             
            from lionagi.protocols.types import EventStatus
         
     | 
| 
         @@ -164,13 +165,11 @@ class DependencyAwareExecutor: 
     | 
|
| 
       164 
165 
     | 
    
         
             
                            # Add to session branches collection directly
         
     | 
| 
       165 
166 
     | 
    
         
             
                            # Check if this is a real branch (not a mock)
         
     | 
| 
       166 
167 
     | 
    
         
             
                            try:
         
     | 
| 
       167 
     | 
    
         
            -
                                from lionagi.protocols.types import IDType
         
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
       169 
168 
     | 
    
         
             
                                # Try to validate the ID
         
     | 
| 
       170 
169 
     | 
    
         
             
                                if hasattr(branch_clone, "id"):
         
     | 
| 
       171 
170 
     | 
    
         
             
                                    branch_id = branch_clone.id
         
     | 
| 
       172 
171 
     | 
    
         
             
                                    # Only add to collections if it's a valid ID
         
     | 
| 
       173 
     | 
    
         
            -
                                    if isinstance(branch_id, (str,  
     | 
| 
      
 172 
     | 
    
         
            +
                                    if isinstance(branch_id, (str, UUID)) or (
         
     | 
| 
       174 
173 
     | 
    
         
             
                                        hasattr(branch_id, "__str__")
         
     | 
| 
       175 
174 
     | 
    
         
             
                                        and not hasattr(branch_id, "_mock_name")
         
     | 
| 
       176 
175 
     | 
    
         
             
                                    ):
         
     | 
| 
         @@ -334,7 +333,7 @@ class DependencyAwareExecutor: 
     | 
|
| 
       334 
333 
     | 
    
         | 
| 
       335 
334 
     | 
    
         
             
                        # Wait for ALL sources (sources are now strings from builder.py)
         
     | 
| 
       336 
335 
     | 
    
         
             
                        for source_id_str in sources:
         
     | 
| 
       337 
     | 
    
         
            -
                            # Convert string back to  
     | 
| 
      
 336 
     | 
    
         
            +
                            # Convert string back to UUID for lookup
         
     | 
| 
       338 
337 
     | 
    
         
             
                            # Check all operations to find matching ID
         
     | 
| 
       339 
338 
     | 
    
         
             
                            for op_id in self.completion_events.keys():
         
     | 
| 
       340 
339 
     | 
    
         
             
                                if str(op_id) == source_id_str:
         
     | 
| 
         @@ -367,7 +366,6 @@ class DependencyAwareExecutor: 
     | 
|
| 
       367 
366 
     | 
    
         
             
                                    result, (str, int, float, bool)
         
     | 
| 
       368 
367 
     | 
    
         
             
                                ):
         
     | 
| 
       369 
368 
     | 
    
         
             
                                    result = to_dict(result, recursive=True)
         
     | 
| 
       370 
     | 
    
         
            -
                                # Use string representation of IDType for JSON serialization
         
     | 
| 
       371 
369 
     | 
    
         
             
                                pred_context[f"{str(pred.id)}_result"] = result
         
     | 
| 
       372 
370 
     | 
    
         | 
| 
       373 
371 
     | 
    
         
             
                        if "context" not in operation.parameters:
         
     | 
    
        lionagi/operations/node.py
    CHANGED
    
    | 
         @@ -6,7 +6,7 @@ from uuid import UUID 
     | 
|
| 
       6 
6 
     | 
    
         
             
            from anyio import get_cancelled_exc_class
         
     | 
| 
       7 
7 
     | 
    
         
             
            from pydantic import BaseModel, Field
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            from lionagi.protocols.types import ID, Event, EventStatus,  
     | 
| 
      
 9 
     | 
    
         
            +
            from lionagi.protocols.types import ID, Event, EventStatus, Node
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
            if TYPE_CHECKING:
         
     | 
| 
       12 
12 
     | 
    
         
             
                from lionagi.session.branch import Branch
         
     | 
| 
         @@ -37,12 +37,12 @@ class Operation(Node, Event): 
     | 
|
| 
       37 
37 
     | 
    
         
             
                )
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
39 
     | 
    
         
             
                @property
         
     | 
| 
       40 
     | 
    
         
            -
                def branch_id(self) ->  
     | 
| 
      
 40 
     | 
    
         
            +
                def branch_id(self) -> UUID | None:
         
     | 
| 
       41 
41 
     | 
    
         
             
                    if a := self.metadata.get("branch_id"):
         
     | 
| 
       42 
42 
     | 
    
         
             
                        return ID.get_id(a)
         
     | 
| 
       43 
43 
     | 
    
         | 
| 
       44 
44 
     | 
    
         
             
                @branch_id.setter
         
     | 
| 
       45 
     | 
    
         
            -
                def branch_id(self, value: str | UUID |  
     | 
| 
      
 45 
     | 
    
         
            +
                def branch_id(self, value: str | UUID | None):
         
     | 
| 
       46 
46 
     | 
    
         
             
                    if value is None:
         
     | 
| 
       47 
47 
     | 
    
         
             
                        self.metadata.pop("branch_id", None)
         
     | 
| 
       48 
48 
     | 
    
         
             
                    else:
         
     | 
| 
         @@ -54,7 +54,7 @@ class Operation(Node, Event): 
     | 
|
| 
       54 
54 
     | 
    
         
             
                        return ID.get_id(a)
         
     | 
| 
       55 
55 
     | 
    
         | 
| 
       56 
56 
     | 
    
         
             
                @graph_id.setter
         
     | 
| 
       57 
     | 
    
         
            -
                def graph_id(self, value: str | UUID |  
     | 
| 
      
 57 
     | 
    
         
            +
                def graph_id(self, value: str | UUID | None):
         
     | 
| 
       58 
58 
     | 
    
         
             
                    if value is None:
         
     | 
| 
       59 
59 
     | 
    
         
             
                        self.metadata.pop("graph_id", None)
         
     | 
| 
       60 
60 
     | 
    
         
             
                    else:
         
     | 
| 
         @@ -6,19 +6,21 @@ from typing import TYPE_CHECKING, Literal 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            from pydantic import BaseModel, JsonValue
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            from lionagi. 
     | 
| 
      
 9 
     | 
    
         
            +
            from lionagi.ln import AlcallParams
         
     | 
| 
       10 
10 
     | 
    
         
             
            from lionagi.ln.fuzzy import FuzzyMatchKeysParams
         
     | 
| 
       11 
11 
     | 
    
         
             
            from lionagi.models import FieldModel, ModelParams
         
     | 
| 
       12 
     | 
    
         
            -
            from lionagi.protocols. 
     | 
| 
       13 
     | 
    
         
            -
            from lionagi. 
     | 
| 
      
 12 
     | 
    
         
            +
            from lionagi.protocols.generic import Progression
         
     | 
| 
      
 13 
     | 
    
         
            +
            from lionagi.protocols.messages import Instruction, SenderRecipient
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
      
 15 
     | 
    
         
            +
            from ..fields import Instruct
         
     | 
| 
       15 
16 
     | 
    
         
             
            from ..types import ActionParam, ChatParam, HandleValidation, ParseParam
         
     | 
| 
       16 
17 
     | 
    
         | 
| 
       17 
18 
     | 
    
         
             
            if TYPE_CHECKING:
         
     | 
| 
       18 
     | 
    
         
            -
                from lionagi.protocols.operatives.step import Operative
         
     | 
| 
       19 
19 
     | 
    
         
             
                from lionagi.service.imodel import iModel
         
     | 
| 
       20 
20 
     | 
    
         
             
                from lionagi.session.branch import Branch, ToolRef
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
      
 22 
     | 
    
         
            +
                from .operative import Operative
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
       22 
24 
     | 
    
         | 
| 
       23 
25 
     | 
    
         
             
            def prepare_operate_kw(
         
     | 
| 
       24 
26 
     | 
    
         
             
                branch: "Branch",
         
     | 
| 
         @@ -105,7 +107,7 @@ def prepare_operate_kw( 
     | 
|
| 
       105 
107 
     | 
    
         
             
                        instruct.action_strategy = action_strategy
         
     | 
| 
       106 
108 
     | 
    
         | 
| 
       107 
109 
     | 
    
         
             
                # Build the Operative - always create it for backwards compatibility
         
     | 
| 
       108 
     | 
    
         
            -
                from  
     | 
| 
      
 110 
     | 
    
         
            +
                from .step import Step
         
     | 
| 
       109 
111 
     | 
    
         | 
| 
       110 
112 
     | 
    
         
             
                operative = Step.request_operative(
         
     | 
| 
       111 
113 
     | 
    
         
             
                    request_params=request_params,
         
     | 
| 
         @@ -229,7 +231,7 @@ async def operate( 
     | 
|
| 
       229 
231 
     | 
    
         
             
                operative = None
         
     | 
| 
       230 
232 
     | 
    
         | 
| 
       231 
233 
     | 
    
         
             
                if model_class:
         
     | 
| 
       232 
     | 
    
         
            -
                    from  
     | 
| 
      
 234 
     | 
    
         
            +
                    from .step import Step
         
     | 
| 
       233 
235 
     | 
    
         | 
| 
       234 
236 
     | 
    
         
             
                    operative = Step.request_operative(
         
     | 
| 
       235 
237 
     | 
    
         
             
                        reason=reason,
         
     | 
| 
         @@ -306,7 +308,7 @@ async def operate( 
     | 
|
| 
       306 
308 
     | 
    
         
             
                    result.update({"action_responses": action_response_models})
         
     | 
| 
       307 
309 
     | 
    
         
             
                    return result
         
     | 
| 
       308 
310 
     | 
    
         | 
| 
       309 
     | 
    
         
            -
                from  
     | 
| 
      
 311 
     | 
    
         
            +
                from .step import Step
         
     | 
| 
       310 
312 
     | 
    
         | 
| 
       311 
313 
     | 
    
         
             
                operative.response_model = result
         
     | 
| 
       312 
314 
     | 
    
         
             
                operative = Step.respond_operative(
         
     | 
| 
         @@ -6,10 +6,9 @@ from typing import Any 
     | 
|
| 
       6 
6 
     | 
    
         
             
            from pydantic import BaseModel
         
     | 
| 
       7 
7 
     | 
    
         
             
            from pydantic.fields import FieldInfo
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            from lionagi.ln import extract_json
         
     | 
| 
       10 
     | 
    
         
            -
            from lionagi.ln. 
     | 
| 
      
 9 
     | 
    
         
            +
            from lionagi.ln import extract_json, fuzzy_match_keys
         
     | 
| 
      
 10 
     | 
    
         
            +
            from lionagi.ln.types import Undefined
         
     | 
| 
       11 
11 
     | 
    
         
             
            from lionagi.models import FieldModel, ModelParams, OperableModel
         
     | 
| 
       12 
     | 
    
         
            -
            from lionagi.utils import UNDEFINED
         
     | 
| 
       13 
12 
     | 
    
         | 
| 
       14 
13 
     | 
    
         | 
| 
       15 
14 
     | 
    
         
             
            class Operative:
         
     | 
| 
         @@ -169,7 +168,7 @@ class Operative: 
     | 
|
| 
       169 
168 
     | 
    
         
             
                        d_ = fuzzy_match_keys(
         
     | 
| 
       170 
169 
     | 
    
         
             
                            d_, self.request_type.model_fields, handle_unmatched="raise"
         
     | 
| 
       171 
170 
     | 
    
         
             
                        )
         
     | 
| 
       172 
     | 
    
         
            -
                        d_ = {k: v for k, v in d_.items() if v !=  
     | 
| 
      
 171 
     | 
    
         
            +
                        d_ = {k: v for k, v in d_.items() if v != Undefined}
         
     | 
| 
       173 
172 
     | 
    
         
             
                        self.response_model = self.request_type.model_validate(d_)
         
     | 
| 
       174 
173 
     | 
    
         
             
                        self._should_retry = False
         
     | 
| 
       175 
174 
     | 
    
         
             
                    except Exception:
         
     | 
| 
         @@ -190,7 +189,7 @@ class Operative: 
     | 
|
| 
       190 
189 
     | 
    
         
             
                        d_ = fuzzy_match_keys(
         
     | 
| 
       191 
190 
     | 
    
         
             
                            d_, self.request_type.model_fields, handle_unmatched="force"
         
     | 
| 
       192 
191 
     | 
    
         
             
                        )
         
     | 
| 
       193 
     | 
    
         
            -
                        d_ = {k: v for k, v in d_.items() if v !=  
     | 
| 
      
 192 
     | 
    
         
            +
                        d_ = {k: v for k, v in d_.items() if v != Undefined}
         
     | 
| 
       194 
193 
     | 
    
         
             
                        self.response_model = self.request_type.model_validate(d_)
         
     | 
| 
       195 
194 
     | 
    
         
             
                        self._should_retry = False
         
     | 
| 
       196 
195 
     | 
    
         
             
                    except Exception:
         
     | 
| 
         @@ -4,14 +4,10 @@ 
     | 
|
| 
       4 
4 
     | 
    
         
             
            from pydantic import BaseModel
         
     | 
| 
       5 
5 
     | 
    
         
             
            from pydantic.fields import FieldInfo
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
            from lionagi.fields.action import (
         
     | 
| 
       8 
     | 
    
         
            -
                ACTION_REQUESTS_FIELD,
         
     | 
| 
       9 
     | 
    
         
            -
                ACTION_REQUIRED_FIELD,
         
     | 
| 
       10 
     | 
    
         
            -
                ACTION_RESPONSES_FIELD,
         
     | 
| 
       11 
     | 
    
         
            -
            )
         
     | 
| 
       12 
     | 
    
         
            -
            from lionagi.fields.reason import REASON_FIELD
         
     | 
| 
       13 
7 
     | 
    
         
             
            from lionagi.models import FieldModel, ModelParams
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            from ..fields import get_default_field
         
     | 
| 
      
 10 
     | 
    
         
            +
            from .operative import Operative
         
     | 
| 
       15 
11 
     | 
    
         | 
| 
       16 
12 
     | 
    
         | 
| 
       17 
13 
     | 
    
         
             
            class Step:
         
     | 
| 
         @@ -71,18 +67,17 @@ class Step: 
     | 
|
| 
       71 
67 
     | 
    
         
             
                    field_models = field_models or []
         
     | 
| 
       72 
68 
     | 
    
         
             
                    exclude_fields = exclude_fields or []
         
     | 
| 
       73 
69 
     | 
    
         
             
                    field_descriptions = field_descriptions or {}
         
     | 
| 
       74 
     | 
    
         
            -
                    if reason and  
     | 
| 
       75 
     | 
    
         
            -
                        field_models.append( 
     | 
| 
       76 
     | 
    
         
            -
                    if  
     | 
| 
       77 
     | 
    
         
            -
                         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
                        )
         
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
      
 70 
     | 
    
         
            +
                    if reason and (fm := get_default_field("reason")) not in field_models:
         
     | 
| 
      
 71 
     | 
    
         
            +
                        field_models.append(fm)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    if (
         
     | 
| 
      
 73 
     | 
    
         
            +
                        actions
         
     | 
| 
      
 74 
     | 
    
         
            +
                        and (fm := get_default_field("action_requests"))
         
     | 
| 
      
 75 
     | 
    
         
            +
                        not in field_models
         
     | 
| 
      
 76 
     | 
    
         
            +
                    ):
         
     | 
| 
      
 77 
     | 
    
         
            +
                        fm2 = get_default_field("action_required")
         
     | 
| 
      
 78 
     | 
    
         
            +
                        field_models.extend([fm, fm2])
         
     | 
| 
       84 
79 
     | 
    
         
             
                    if isinstance(request_params, ModelParams):
         
     | 
| 
       85 
     | 
    
         
            -
                        request_params = request_params. 
     | 
| 
      
 80 
     | 
    
         
            +
                        request_params = request_params.to_dict()
         
     | 
| 
       86 
81 
     | 
    
         | 
| 
       87 
82 
     | 
    
         
             
                    request_params = request_params or {}
         
     | 
| 
       88 
83 
     | 
    
         
             
                    request_params_fields = {
         
     | 
| 
         @@ -143,15 +138,17 @@ class Step: 
     | 
|
| 
       143 
138 
     | 
    
         
             
                    additional_data = additional_data or {}
         
     | 
| 
       144 
139 
     | 
    
         
             
                    field_models = field_models or []
         
     | 
| 
       145 
140 
     | 
    
         
             
                    if hasattr(operative.response_model, "action_required"):
         
     | 
| 
       146 
     | 
    
         
            -
                         
     | 
| 
       147 
     | 
    
         
            -
                             
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
     | 
    
         
            -
             
     | 
| 
       151 
     | 
    
         
            -
                             
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
      
 141 
     | 
    
         
            +
                        for i in {
         
     | 
| 
      
 142 
     | 
    
         
            +
                            "action_requests",
         
     | 
| 
      
 143 
     | 
    
         
            +
                            "action_required",
         
     | 
| 
      
 144 
     | 
    
         
            +
                            "action_responses",
         
     | 
| 
      
 145 
     | 
    
         
            +
                        }:
         
     | 
| 
      
 146 
     | 
    
         
            +
                            fm = get_default_field(i)
         
     | 
| 
      
 147 
     | 
    
         
            +
                            if fm not in field_models:
         
     | 
| 
      
 148 
     | 
    
         
            +
                                field_models.append(fm)
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
       153 
150 
     | 
    
         
             
                    if "reason" in type(operative.response_model).model_fields:
         
     | 
| 
       154 
     | 
    
         
            -
                        field_models. 
     | 
| 
      
 151 
     | 
    
         
            +
                        field_models.append(get_default_field("reason"))
         
     | 
| 
       155 
152 
     | 
    
         | 
| 
       156 
153 
     | 
    
         
             
                    operative = Step._create_response_type(
         
     | 
| 
       157 
154 
     | 
    
         
             
                        operative=operative,
         
     | 
| 
         @@ -201,24 +198,22 @@ class Step: 
     | 
|
| 
       201 
198 
     | 
    
         
             
                        hasattr(operative.request_type, "action_required")
         
     | 
| 
       202 
199 
     | 
    
         
             
                        and operative.response_model.action_required
         
     | 
| 
       203 
200 
     | 
    
         
             
                    ):
         
     | 
| 
       204 
     | 
    
         
            -
                         
     | 
| 
       205 
     | 
    
         
            -
                             
     | 
| 
       206 
     | 
    
         
            -
             
     | 
| 
       207 
     | 
    
         
            -
             
     | 
| 
       208 
     | 
    
         
            -
             
     | 
| 
       209 
     | 
    
         
            -
                             
     | 
| 
       210 
     | 
    
         
            -
             
     | 
| 
       211 
     | 
    
         
            -
             
     | 
| 
       212 
     | 
    
         
            -
                        field_models.extend([REASON_FIELD])
         
     | 
| 
      
 201 
     | 
    
         
            +
                        for i in {
         
     | 
| 
      
 202 
     | 
    
         
            +
                            "action_requests",
         
     | 
| 
      
 203 
     | 
    
         
            +
                            "action_required",
         
     | 
| 
      
 204 
     | 
    
         
            +
                            "action_responses",
         
     | 
| 
      
 205 
     | 
    
         
            +
                        }:
         
     | 
| 
      
 206 
     | 
    
         
            +
                            fm = get_default_field(i)
         
     | 
| 
      
 207 
     | 
    
         
            +
                            if fm not in field_models:
         
     | 
| 
      
 208 
     | 
    
         
            +
                                field_models.append(fm)
         
     | 
| 
       213 
209 
     | 
    
         | 
| 
       214 
     | 
    
         
            -
                     
     | 
| 
       215 
     | 
    
         
            -
             
     | 
| 
       216 
     | 
    
         
            -
                    # since Operative doesn't store ModelParams anymore
         
     | 
| 
      
 210 
     | 
    
         
            +
                    if hasattr(operative.request_type, "reason"):
         
     | 
| 
      
 211 
     | 
    
         
            +
                        field_models.append(get_default_field("reason"))
         
     | 
| 
       217 
212 
     | 
    
         | 
| 
       218 
213 
     | 
    
         
             
                    operative.create_response_type(
         
     | 
| 
       219 
214 
     | 
    
         
             
                        response_params=response_params,
         
     | 
| 
       220 
215 
     | 
    
         
             
                        field_models=field_models,
         
     | 
| 
       221 
     | 
    
         
            -
                        exclude_fields=exclude_fields,
         
     | 
| 
      
 216 
     | 
    
         
            +
                        exclude_fields=exclude_fields or [],
         
     | 
| 
       222 
217 
     | 
    
         
             
                        doc=response_doc,
         
     | 
| 
       223 
218 
     | 
    
         
             
                        config_dict=response_config_dict,
         
     | 
| 
       224 
219 
     | 
    
         
             
                        frozen=frozen_response,
         
     | 
| 
         @@ -68,11 +68,17 @@ def get_choice_representation(choice: Any) -> str: 
     | 
|
| 
       68 
68 
     | 
    
         
             
                    return choice
         
     | 
| 
       69 
69 
     | 
    
         | 
| 
       70 
70 
     | 
    
         
             
                if isinstance(choice, BaseModel):
         
     | 
| 
       71 
     | 
    
         
            -
                     
     | 
| 
      
 71 
     | 
    
         
            +
                    import json
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    schema = choice.model_json_schema()
         
     | 
| 
      
 74 
     | 
    
         
            +
                    return f"{choice.__class__.__name__}:\n{json.dumps(schema, indent=2)}"
         
     | 
| 
       72 
75 
     | 
    
         | 
| 
       73 
76 
     | 
    
         
             
                if isinstance(choice, Enum):
         
     | 
| 
       74 
77 
     | 
    
         
             
                    return get_choice_representation(choice.value)
         
     | 
| 
       75 
78 
     | 
    
         | 
| 
      
 79 
     | 
    
         
            +
                # Handle other types (int, dict, etc.) by converting to string
         
     | 
| 
      
 80 
     | 
    
         
            +
                return str(choice)
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
       76 
82 
     | 
    
         | 
| 
       77 
83 
     | 
    
         
             
            def parse_selection(selection_str: str, choices: Any):
         
     | 
| 
       78 
84 
     | 
    
         
             
                select_from = []
         
     | 
    
        lionagi/operations/types.py
    CHANGED
    
    | 
         @@ -7,7 +7,7 @@ from typing import ClassVar, Literal 
     | 
|
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            from pydantic import BaseModel, JsonValue
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
            from lionagi.ln 
     | 
| 
      
 10 
     | 
    
         
            +
            from lionagi.ln import AlcallParams
         
     | 
| 
       11 
11 
     | 
    
         
             
            from lionagi.ln.fuzzy import FuzzyMatchKeysParams
         
     | 
| 
       12 
12 
     | 
    
         
             
            from lionagi.ln.types import Params
         
     | 
| 
       13 
13 
     | 
    
         
             
            from lionagi.protocols.action.tool import ToolRef
         
     | 
| 
         @@ -4,7 +4,8 @@ 
     | 
|
| 
       4 
4 
     | 
    
         
             
            import logging
         
     | 
| 
       5 
5 
     | 
    
         
             
            from typing import Any
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
            from  
     | 
| 
      
 7 
     | 
    
         
            +
            from pydantic import BaseModel
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
       8 
9 
     | 
    
         
             
            from lionagi.protocols._concepts import Manager
         
     | 
| 
       9 
10 
     | 
    
         
             
            from lionagi.protocols.messages.action_request import ActionRequest
         
     | 
| 
       10 
11 
     | 
    
         
             
            from lionagi.utils import to_list
         
     | 
| 
         @@ -121,7 +122,7 @@ class ActionManager(Manager): 
     | 
|
| 
       121 
122 
     | 
    
         
             
                        self.register_tool(t, update=update)
         
     | 
| 
       122 
123 
     | 
    
         | 
| 
       123 
124 
     | 
    
         
             
                def match_tool(
         
     | 
| 
       124 
     | 
    
         
            -
                    self, action_request: ActionRequest |  
     | 
| 
      
 125 
     | 
    
         
            +
                    self, action_request: ActionRequest | BaseModel | dict
         
     | 
| 
       125 
126 
     | 
    
         
             
                ) -> FunctionCalling:
         
     | 
| 
       126 
127 
     | 
    
         
             
                    """
         
     | 
| 
       127 
128 
     | 
    
         
             
                    Convert an ActionRequest (or dict with "function"/"arguments")
         
     | 
| 
         @@ -134,9 +135,7 @@ class ActionManager(Manager): 
     | 
|
| 
       134 
135 
     | 
    
         
             
                    Returns:
         
     | 
| 
       135 
136 
     | 
    
         
             
                        FunctionCalling: The event object that can be invoked.
         
     | 
| 
       136 
137 
     | 
    
         
             
                    """
         
     | 
| 
       137 
     | 
    
         
            -
                    if not isinstance(
         
     | 
| 
       138 
     | 
    
         
            -
                        action_request, ActionRequest | ActionRequestModel | dict
         
     | 
| 
       139 
     | 
    
         
            -
                    ):
         
     | 
| 
      
 138 
     | 
    
         
            +
                    if not isinstance(action_request, ActionRequest | BaseModel | dict):
         
     | 
| 
       140 
139 
     | 
    
         
             
                        raise TypeError(f"Unsupported type {type(action_request)}")
         
     | 
| 
       141 
140 
     | 
    
         | 
| 
       142 
141 
     | 
    
         
             
                    func, args = None, None
         
     | 
| 
         @@ -155,7 +154,7 @@ class ActionManager(Manager): 
     | 
|
| 
       155 
154 
     | 
    
         | 
| 
       156 
155 
     | 
    
         
             
                async def invoke(
         
     | 
| 
       157 
156 
     | 
    
         
             
                    self,
         
     | 
| 
       158 
     | 
    
         
            -
                    func_call:  
     | 
| 
      
 157 
     | 
    
         
            +
                    func_call: BaseModel | ActionRequest,
         
     | 
| 
       159 
158 
     | 
    
         
             
                ) -> FunctionCalling:
         
     | 
| 
       160 
159 
     | 
    
         
             
                    """
         
     | 
| 
       161 
160 
     | 
    
         
             
                    High-level API to parse and run a function call.
         
     | 
    
        lionagi/protocols/contracts.py
    CHANGED
    
    | 
         @@ -24,7 +24,7 @@ class ObservableProto(Protocol): 
     | 
|
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
                This protocol defines the minimal contract for observable objects:
         
     | 
| 
       26 
26 
     | 
    
         
             
                they must have an 'id' property. The return type is permissive (Any)
         
     | 
| 
       27 
     | 
    
         
            -
                to maintain compatibility with V0's  
     | 
| 
      
 27 
     | 
    
         
            +
                to maintain compatibility with V0's UUID wrapper while enabling
         
     | 
| 
       28 
28 
     | 
    
         
             
                V1 evolution.
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                All V0 Element subclasses automatically satisfy this protocol without
         
     | 
| 
         @@ -33,7 +33,7 @@ class ObservableProto(Protocol): 
     | 
|
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
                @property
         
     | 
| 
       35 
35 
     | 
    
         
             
                def id(self) -> object:
         
     | 
| 
       36 
     | 
    
         
            -
                    """Unique identifier. Accepts  
     | 
| 
      
 36 
     | 
    
         
            +
                    """Unique identifier. Accepts UUID, UUID, or string."""
         
     | 
| 
       37 
37 
     | 
    
         
             
                    ...
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
39 
     | 
    
         | 
| 
         @@ -1,2 +1,24 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # Copyright (c) 2023-2025, HaiyangLi <quantocean.li at gmail dot com>
         
     | 
| 
       2 
2 
     | 
    
         
             
            # SPDX-License-Identifier: Apache-2.0
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            from .element import ID, Element
         
     | 
| 
      
 5 
     | 
    
         
            +
            from .event import Event, EventStatus, Execution
         
     | 
| 
      
 6 
     | 
    
         
            +
            from .log import DataLogger, DataLoggerConfig, Log
         
     | 
| 
      
 7 
     | 
    
         
            +
            from .pile import Pile
         
     | 
| 
      
 8 
     | 
    
         
            +
            from .processor import Executor, Processor
         
     | 
| 
      
 9 
     | 
    
         
            +
            from .progression import Progression
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            __all__ = (
         
     | 
| 
      
 12 
     | 
    
         
            +
                "Element",
         
     | 
| 
      
 13 
     | 
    
         
            +
                "ID",
         
     | 
| 
      
 14 
     | 
    
         
            +
                "Event",
         
     | 
| 
      
 15 
     | 
    
         
            +
                "Execution",
         
     | 
| 
      
 16 
     | 
    
         
            +
                "Log",
         
     | 
| 
      
 17 
     | 
    
         
            +
                "DataLogger",
         
     | 
| 
      
 18 
     | 
    
         
            +
                "DataLoggerConfig",
         
     | 
| 
      
 19 
     | 
    
         
            +
                "Pile",
         
     | 
| 
      
 20 
     | 
    
         
            +
                "Progression",
         
     | 
| 
      
 21 
     | 
    
         
            +
                "Processor",
         
     | 
| 
      
 22 
     | 
    
         
            +
                "Executor",
         
     | 
| 
      
 23 
     | 
    
         
            +
                "EventStatus",
         
     | 
| 
      
 24 
     | 
    
         
            +
            )
         
     | 
| 
         @@ -19,98 +19,16 @@ from pydantic import ( 
     | 
|
| 
       19 
19 
     | 
    
         | 
| 
       20 
20 
     | 
    
         
             
            from lionagi import ln
         
     | 
| 
       21 
21 
     | 
    
         
             
            from lionagi._class_registry import get_class
         
     | 
| 
       22 
     | 
    
         
            -
            from lionagi._errors import IDError
         
     | 
| 
       23 
22 
     | 
    
         
             
            from lionagi.utils import import_module, to_dict
         
     | 
| 
       24 
23 
     | 
    
         | 
| 
       25 
24 
     | 
    
         
             
            from .._concepts import Collective, Observable, Ordering
         
     | 
| 
       26 
25 
     | 
    
         | 
| 
       27 
26 
     | 
    
         
             
            __all__ = (
         
     | 
| 
       28 
     | 
    
         
            -
                "IDType",
         
     | 
| 
       29 
27 
     | 
    
         
             
                "Element",
         
     | 
| 
       30 
     | 
    
         
            -
                "ID",
         
     | 
| 
       31 
28 
     | 
    
         
             
                "validate_order",
         
     | 
| 
       32 
     | 
    
         
            -
                "DEFAULT_ELEMENT_SERIALIZER",
         
     | 
| 
       33 
29 
     | 
    
         
             
            )
         
     | 
| 
       34 
30 
     | 
    
         | 
| 
       35 
31 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
            class IDType:
         
     | 
| 
       37 
     | 
    
         
            -
                """Represents a UUIDv4-based identifier.
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                This class wraps a UUID object and provides helper methods for
         
     | 
| 
       40 
     | 
    
         
            -
                validating and creating UUID version 4. It also implements equality
         
     | 
| 
       41 
     | 
    
         
            -
                and hashing so that it can be used as dictionary keys or in sets.
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                Attributes:
         
     | 
| 
       44 
     | 
    
         
            -
                    _id (UUID): The wrapped UUID object.
         
     | 
| 
       45 
     | 
    
         
            -
                """
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
                __slots__ = ("_id",)
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
                def __init__(self, id: UUID) -> None:
         
     | 
| 
       50 
     | 
    
         
            -
                    """Initializes an IDType instance."""
         
     | 
| 
       51 
     | 
    
         
            -
                    self._id = id
         
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
                @classmethod
         
     | 
| 
       54 
     | 
    
         
            -
                def validate(cls, value: str | UUID | IDType) -> IDType:
         
     | 
| 
       55 
     | 
    
         
            -
                    """Validates and converts a value into an IDType.
         
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
                    Returns:
         
     | 
| 
       58 
     | 
    
         
            -
                        IDType: The validated IDType object.
         
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
                    Raises:
         
     | 
| 
       61 
     | 
    
         
            -
                        IDError: If the provided value is not a valid UUIDv4.
         
     | 
| 
       62 
     | 
    
         
            -
                    """
         
     | 
| 
       63 
     | 
    
         
            -
                    if isinstance(value, IDType):
         
     | 
| 
       64 
     | 
    
         
            -
                        return value
         
     | 
| 
       65 
     | 
    
         
            -
                    try:
         
     | 
| 
       66 
     | 
    
         
            -
                        return cls(UUID(str(value), version=4))
         
     | 
| 
       67 
     | 
    
         
            -
                    except ValueError:
         
     | 
| 
       68 
     | 
    
         
            -
                        raise IDError(f"Invalid ID: {value}") from None
         
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
                @classmethod
         
     | 
| 
       71 
     | 
    
         
            -
                def create(cls) -> IDType:
         
     | 
| 
       72 
     | 
    
         
            -
                    """Creates a new IDType with a randomly generated UUIDv4.
         
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
                    Returns:
         
     | 
| 
       75 
     | 
    
         
            -
                        IDType: A new IDType instance with a random UUIDv4.
         
     | 
| 
       76 
     | 
    
         
            -
                    """
         
     | 
| 
       77 
     | 
    
         
            -
                    return cls(uuid4())
         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
                def __str__(self) -> str:
         
     | 
| 
       80 
     | 
    
         
            -
                    """Returns the string representation of the underlying UUID.
         
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
                    Returns:
         
     | 
| 
       83 
     | 
    
         
            -
                        str: The string form of this IDType's UUID.
         
     | 
| 
       84 
     | 
    
         
            -
                    """
         
     | 
| 
       85 
     | 
    
         
            -
                    return str(self._id)
         
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
                def __repr__(self) -> str:
         
     | 
| 
       88 
     | 
    
         
            -
                    """Returns the unambiguous string representation of this IDType.
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
                    Returns:
         
     | 
| 
       91 
     | 
    
         
            -
                        str: A developer-friendly string for debugging.
         
     | 
| 
       92 
     | 
    
         
            -
                    """
         
     | 
| 
       93 
     | 
    
         
            -
                    return f"IDType({self._id})"
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
                def __eq__(self, other: Any) -> bool:
         
     | 
| 
       96 
     | 
    
         
            -
                    """Checks equality with another IDType based on UUID value.
         
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
                    Returns:
         
     | 
| 
       99 
     | 
    
         
            -
                        bool: True if both have the same underlying UUID; False otherwise.
         
     | 
| 
       100 
     | 
    
         
            -
                    """
         
     | 
| 
       101 
     | 
    
         
            -
                    if not isinstance(other, IDType):
         
     | 
| 
       102 
     | 
    
         
            -
                        return NotImplemented
         
     | 
| 
       103 
     | 
    
         
            -
                    return self._id == other._id
         
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
                def __hash__(self) -> int:
         
     | 
| 
       106 
     | 
    
         
            -
                    """Returns a hash based on the underlying UUID.
         
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
                    Returns:
         
     | 
| 
       109 
     | 
    
         
            -
                        int: The hash of this object, allowing IDType to be dictionary keys.
         
     | 
| 
       110 
     | 
    
         
            -
                    """
         
     | 
| 
       111 
     | 
    
         
            -
                    return hash(self._id)
         
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
32 
     | 
    
         
             
            class Element(BaseModel, Observable):
         
     | 
| 
       115 
33 
     | 
    
         
             
                """Basic identifiable, timestamped element.
         
     | 
| 
       116 
34 
     | 
    
         | 
| 
         @@ -119,7 +37,7 @@ class Element(BaseModel, Observable): 
     | 
|
| 
       119 
37 
     | 
    
         
             
                dictionary.
         
     | 
| 
       120 
38 
     | 
    
         | 
| 
       121 
39 
     | 
    
         
             
                Attributes:
         
     | 
| 
       122 
     | 
    
         
            -
                    id ( 
     | 
| 
      
 40 
     | 
    
         
            +
                    id (UUID):
         
     | 
| 
       123 
41 
     | 
    
         
             
                        A unique ID based on UUIDv4 (defaults to a newly generated one).
         
     | 
| 
       124 
42 
     | 
    
         
             
                    created_at (float):
         
     | 
| 
       125 
43 
     | 
    
         
             
                        The creation timestamp as a float (Unix epoch). Defaults to
         
     | 
| 
         @@ -135,8 +53,8 @@ class Element(BaseModel, Observable): 
     | 
|
| 
       135 
53 
     | 
    
         
             
                    extra="forbid",
         
     | 
| 
       136 
54 
     | 
    
         
             
                )
         
     | 
| 
       137 
55 
     | 
    
         | 
| 
       138 
     | 
    
         
            -
                id:  
     | 
| 
       139 
     | 
    
         
            -
                    default_factory= 
     | 
| 
      
 56 
     | 
    
         
            +
                id: UUID = Field(
         
     | 
| 
      
 57 
     | 
    
         
            +
                    default_factory=uuid4,
         
     | 
| 
       140 
58 
     | 
    
         
             
                    title="ID",
         
     | 
| 
       141 
59 
     | 
    
         
             
                    description="Unique identifier for this element.",
         
     | 
| 
       142 
60 
     | 
    
         
             
                    frozen=True,
         
     | 
| 
         @@ -211,12 +129,14 @@ class Element(BaseModel, Observable): 
     | 
|
| 
       211 
129 
     | 
    
         
             
                        raise ValueError(f"Invalid created_at: {val}") from None
         
     | 
| 
       212 
130 
     | 
    
         | 
| 
       213 
131 
     | 
    
         
             
                @field_validator("id", mode="before")
         
     | 
| 
       214 
     | 
    
         
            -
                def  
     | 
| 
       215 
     | 
    
         
            -
                    """Ensures `id` is validated as an  
     | 
| 
       216 
     | 
    
         
            -
                     
     | 
| 
      
 132 
     | 
    
         
            +
                def _ensure_UUID(cls, val: UUID | str) -> UUID:
         
     | 
| 
      
 133 
     | 
    
         
            +
                    """Ensures `id` is validated as an UUID."""
         
     | 
| 
      
 134 
     | 
    
         
            +
                    if isinstance(val, UUID):
         
     | 
| 
      
 135 
     | 
    
         
            +
                        return val
         
     | 
| 
      
 136 
     | 
    
         
            +
                    return UUID(str(val))
         
     | 
| 
       217 
137 
     | 
    
         | 
| 
       218 
138 
     | 
    
         
             
                @field_serializer("id")
         
     | 
| 
       219 
     | 
    
         
            -
                def _serialize_id_type(self, val:  
     | 
| 
      
 139 
     | 
    
         
            +
                def _serialize_id_type(self, val: UUID) -> str:
         
     | 
| 
       220 
140 
     | 
    
         
             
                    """Serializes the `id` field to a string."""
         
     | 
| 
       221 
141 
     | 
    
         
             
                    return str(val)
         
     | 
| 
       222 
142 
     | 
    
         | 
| 
         @@ -328,28 +248,27 @@ class Element(BaseModel, Observable): 
     | 
|
| 
       328 
248 
     | 
    
         | 
| 
       329 
249 
     | 
    
         | 
| 
       330 
250 
     | 
    
         
             
            DEFAULT_ELEMENT_SERIALIZER = ln.get_orjson_default(
         
     | 
| 
       331 
     | 
    
         
            -
                order=[ 
     | 
| 
      
 251 
     | 
    
         
            +
                order=[Element, BaseModel],
         
     | 
| 
       332 
252 
     | 
    
         
             
                additional={
         
     | 
| 
       333 
     | 
    
         
            -
                    IDType: lambda o: str(o),
         
     | 
| 
       334 
253 
     | 
    
         
             
                    Element: lambda o: o.to_dict(),
         
     | 
| 
       335 
254 
     | 
    
         
             
                    BaseModel: lambda o: o.model_dump(mode="json"),
         
     | 
| 
       336 
255 
     | 
    
         
             
                },
         
     | 
| 
       337 
256 
     | 
    
         
             
            )
         
     | 
| 
       338 
257 
     | 
    
         | 
| 
       339 
258 
     | 
    
         | 
| 
       340 
     | 
    
         
            -
            def validate_order(order: Any) -> list[ 
     | 
| 
       341 
     | 
    
         
            -
                """Validates and flattens an ordering into a list of  
     | 
| 
      
 259 
     | 
    
         
            +
            def validate_order(order: Any) -> list[UUID]:
         
     | 
| 
      
 260 
     | 
    
         
            +
                """Validates and flattens an ordering into a list of UUID objects.
         
     | 
| 
       342 
261 
     | 
    
         | 
| 
       343 
262 
     | 
    
         
             
                This function accepts a variety of possible representations for ordering
         
     | 
| 
       344 
263 
     | 
    
         
             
                (e.g., a single Element, a list of Elements, a dictionary with ID keys,
         
     | 
| 
       345 
     | 
    
         
            -
                or a nested structure) and returns a flat list of  
     | 
| 
      
 264 
     | 
    
         
            +
                or a nested structure) and returns a flat list of UUID objects.
         
     | 
| 
       346 
265 
     | 
    
         | 
| 
       347 
266 
     | 
    
         
             
                Returns:
         
     | 
| 
       348 
     | 
    
         
            -
                    list[ 
     | 
| 
      
 267 
     | 
    
         
            +
                    list[UUID]: A flat list of validated UUID objects.
         
     | 
| 
       349 
268 
     | 
    
         | 
| 
       350 
269 
     | 
    
         
             
                Raises:
         
     | 
| 
       351 
270 
     | 
    
         
             
                    ValueError: If an invalid item is encountered or if there's a mixture
         
     | 
| 
       352 
     | 
    
         
            -
                        of types not all convertible to  
     | 
| 
      
 271 
     | 
    
         
            +
                        of types not all convertible to UUID.
         
     | 
| 
       353 
272 
     | 
    
         
             
                """
         
     | 
| 
       354 
273 
     | 
    
         
             
                if isinstance(order, Element):
         
     | 
| 
       355 
274 
     | 
    
         
             
                    return [order.id]
         
     | 
| 
         @@ -357,89 +276,79 @@ def validate_order(order: Any) -> list[IDType]: 
     | 
|
| 
       357 
276 
     | 
    
         
             
                    order = list(order.keys())
         
     | 
| 
       358 
277 
     | 
    
         | 
| 
       359 
278 
     | 
    
         
             
                stack = [order]
         
     | 
| 
       360 
     | 
    
         
            -
                out: list[ 
     | 
| 
      
 279 
     | 
    
         
            +
                out: list[UUID] = []
         
     | 
| 
       361 
280 
     | 
    
         
             
                while stack:
         
     | 
| 
       362 
281 
     | 
    
         
             
                    cur = stack.pop()
         
     | 
| 
       363 
282 
     | 
    
         
             
                    if cur is None:
         
     | 
| 
       364 
283 
     | 
    
         
             
                        continue
         
     | 
| 
       365 
284 
     | 
    
         
             
                    if isinstance(cur, Element):
         
     | 
| 
       366 
285 
     | 
    
         
             
                        out.append(cur.id)
         
     | 
| 
       367 
     | 
    
         
            -
                    elif isinstance(cur, IDType):
         
     | 
| 
       368 
     | 
    
         
            -
                        out.append(cur)
         
     | 
| 
       369 
286 
     | 
    
         
             
                    elif isinstance(cur, UUID):
         
     | 
| 
       370 
     | 
    
         
            -
                        out.append( 
     | 
| 
      
 287 
     | 
    
         
            +
                        out.append(cur)
         
     | 
| 
       371 
288 
     | 
    
         
             
                    elif isinstance(cur, str):
         
     | 
| 
       372 
     | 
    
         
            -
                        out.append( 
     | 
| 
      
 289 
     | 
    
         
            +
                        out.append(UUID(cur))
         
     | 
| 
       373 
290 
     | 
    
         
             
                    elif isinstance(cur, (list, tuple, set)):
         
     | 
| 
       374 
291 
     | 
    
         
             
                        stack.extend(reversed(cur))
         
     | 
| 
       375 
292 
     | 
    
         
             
                    else:
         
     | 
| 
       376 
293 
     | 
    
         
             
                        raise ValueError("Invalid item in order.")
         
     | 
| 
       377 
294 
     | 
    
         | 
| 
       378 
     | 
    
         
            -
                if not out 
     | 
| 
       379 
     | 
    
         
            -
                    return []
         
     | 
| 
       380 
     | 
    
         
            -
             
     | 
| 
       381 
     | 
    
         
            -
                # Check for consistent IDType usage
         
     | 
| 
       382 
     | 
    
         
            -
                first_type = type(out[0])
         
     | 
| 
       383 
     | 
    
         
            -
                if first_type is IDType:
         
     | 
| 
       384 
     | 
    
         
            -
                    for item in out:
         
     | 
| 
       385 
     | 
    
         
            -
                        if not isinstance(item, IDType):
         
     | 
| 
       386 
     | 
    
         
            -
                            raise ValueError("Mixed types in order.")
         
     | 
| 
       387 
     | 
    
         
            -
                    return out
         
     | 
| 
       388 
     | 
    
         
            -
                raise ValueError("Unrecognized type(s) in order.")
         
     | 
| 
      
 295 
     | 
    
         
            +
                return [] if not out else out
         
     | 
| 
       389 
296 
     | 
    
         | 
| 
       390 
297 
     | 
    
         | 
| 
       391 
298 
     | 
    
         
             
            E = TypeVar("E", bound=Element)
         
     | 
| 
       392 
299 
     | 
    
         | 
| 
       393 
300 
     | 
    
         | 
| 
       394 
301 
     | 
    
         
             
            class ID(Generic[E]):
         
     | 
| 
       395 
     | 
    
         
            -
                """Utility class for working with  
     | 
| 
      
 302 
     | 
    
         
            +
                """Utility class for working with UUID objects and Elements.
         
     | 
| 
       396 
303 
     | 
    
         | 
| 
       397 
304 
     | 
    
         
             
                This class provides helper methods to extract IDs from Elements, strings,
         
     | 
| 
       398 
305 
     | 
    
         
             
                or UUIDs, and to test whether a given object can be interpreted as
         
     | 
| 
       399 
306 
     | 
    
         
             
                an ID.
         
     | 
| 
       400 
307 
     | 
    
         
             
                """
         
     | 
| 
       401 
308 
     | 
    
         | 
| 
       402 
     | 
    
         
            -
                ID: TypeAlias =  
     | 
| 
      
 309 
     | 
    
         
            +
                ID: TypeAlias = UUID
         
     | 
| 
       403 
310 
     | 
    
         
             
                Item: TypeAlias = E | Element  # type: ignore
         
     | 
| 
       404 
     | 
    
         
            -
                Ref: TypeAlias =  
     | 
| 
       405 
     | 
    
         
            -
                IDSeq: TypeAlias = Sequence[ 
     | 
| 
      
 311 
     | 
    
         
            +
                Ref: TypeAlias = UUID | E | str  # type: ignore
         
     | 
| 
      
 312 
     | 
    
         
            +
                IDSeq: TypeAlias = Sequence[UUID] | Ordering[E]  # type: ignore
         
     | 
| 
       406 
313 
     | 
    
         
             
                ItemSeq: TypeAlias = Sequence[E] | Collective[E]  # type: ignore
         
     | 
| 
       407 
314 
     | 
    
         
             
                RefSeq: TypeAlias = ItemSeq | Sequence[Ref] | Ordering[E]  # type: ignore
         
     | 
| 
       408 
315 
     | 
    
         | 
| 
       409 
316 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       410 
     | 
    
         
            -
                def get_id(item: E) ->  
     | 
| 
       411 
     | 
    
         
            -
                    """Retrieves an  
     | 
| 
      
 317 
     | 
    
         
            +
                def get_id(item: E) -> UUID:
         
     | 
| 
      
 318 
     | 
    
         
            +
                    """Retrieves an UUID from multiple possible item forms.
         
     | 
| 
       412 
319 
     | 
    
         | 
| 
       413 
320 
     | 
    
         
             
                    Acceptable item types include:
         
     | 
| 
       414 
321 
     | 
    
         
             
                    - Element: Uses its `id` attribute.
         
     | 
| 
       415 
     | 
    
         
            -
                    -  
     | 
| 
      
 322 
     | 
    
         
            +
                    - UUID: Returns it directly.
         
     | 
| 
       416 
323 
     | 
    
         
             
                    - UUID: Validates and wraps it.
         
     | 
| 
       417 
324 
     | 
    
         
             
                    - str: Interpreted as a UUID if possible.
         
     | 
| 
       418 
325 
     | 
    
         | 
| 
       419 
326 
     | 
    
         
             
                    Returns:
         
     | 
| 
       420 
     | 
    
         
            -
                         
     | 
| 
      
 327 
     | 
    
         
            +
                        UUID: The validated ID.
         
     | 
| 
       421 
328 
     | 
    
         | 
| 
       422 
329 
     | 
    
         
             
                    Raises:
         
     | 
| 
       423 
     | 
    
         
            -
                        ValueError: If the item cannot be converted to an  
     | 
| 
      
 330 
     | 
    
         
            +
                        ValueError: If the item cannot be converted to an UUID.
         
     | 
| 
       424 
331 
     | 
    
         
             
                    """
         
     | 
| 
      
 332 
     | 
    
         
            +
                    if isinstance(item, UUID):
         
     | 
| 
      
 333 
     | 
    
         
            +
                        return item
         
     | 
| 
       425 
334 
     | 
    
         
             
                    if isinstance(item, Element):
         
     | 
| 
       426 
335 
     | 
    
         
             
                        return item.id
         
     | 
| 
       427 
     | 
    
         
            -
                    if isinstance(item,  
     | 
| 
       428 
     | 
    
         
            -
                        return  
     | 
| 
      
 336 
     | 
    
         
            +
                    if isinstance(item, str):
         
     | 
| 
      
 337 
     | 
    
         
            +
                        return UUID(item)
         
     | 
| 
       429 
338 
     | 
    
         
             
                    raise ValueError("Cannot get ID from item.")
         
     | 
| 
       430 
339 
     | 
    
         | 
| 
       431 
340 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       432 
341 
     | 
    
         
             
                def is_id(item: Any) -> bool:
         
     | 
| 
       433 
     | 
    
         
            -
                    """Checks if an item can be validated as an  
     | 
| 
      
 342 
     | 
    
         
            +
                    """Checks if an item can be validated as an UUID.
         
     | 
| 
       434 
343 
     | 
    
         | 
| 
       435 
344 
     | 
    
         
             
                    Returns:
         
     | 
| 
       436 
     | 
    
         
            -
                        bool: True if `item` is or can be validated as an  
     | 
| 
      
 345 
     | 
    
         
            +
                        bool: True if `item` is or can be validated as an UUID;
         
     | 
| 
       437 
346 
     | 
    
         
             
                            otherwise, False.
         
     | 
| 
       438 
347 
     | 
    
         
             
                    """
         
     | 
| 
       439 
348 
     | 
    
         
             
                    try:
         
     | 
| 
       440 
     | 
    
         
            -
                         
     | 
| 
      
 349 
     | 
    
         
            +
                        ID.get_id(item)  # type: ignore
         
     | 
| 
       441 
350 
     | 
    
         
             
                        return True
         
     | 
| 
       442 
     | 
    
         
            -
                    except  
     | 
| 
      
 351 
     | 
    
         
            +
                    except ValueError:
         
     | 
| 
       443 
352 
     | 
    
         
             
                        return False
         
     | 
| 
       444 
353 
     | 
    
         | 
| 
       445 
354 
     | 
    
         |