lionagi 0.5.1__py3-none-any.whl → 0.5.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 +0 -1
- lionagi/core/action/tool.py +3 -5
- lionagi/core/communication/action_request.py +3 -3
- lionagi/core/communication/message.py +3 -3
- lionagi/core/communication/utils.py +3 -3
- lionagi/core/generic/component.py +4 -4
- lionagi/core/generic/element.py +51 -47
- lionagi/core/generic/graph.py +1 -1
- lionagi/core/generic/log.py +2 -2
- lionagi/core/generic/pile.py +10 -11
- lionagi/core/generic/progression.py +19 -12
- lionagi/core/generic/utils.py +6 -3
- lionagi/core/models/base.py +11 -68
- lionagi/core/models/field_model.py +42 -19
- lionagi/core/models/{new_model_params.py → model_params.py} +5 -6
- lionagi/core/models/note.py +2 -2
- lionagi/core/models/operable_model.py +8 -4
- lionagi/core/models/schema_model.py +9 -31
- lionagi/core/models/types.py +15 -6
- lionagi/core/session/branch.py +10 -7
- lionagi/core/session/branch_mixins.py +11 -12
- lionagi/core/session/session.py +1 -2
- lionagi/core/typing/__init__.py +4 -4
- lionagi/core/typing/{concepts.py → _concepts.py} +43 -2
- lionagi/core/typing/_id.py +104 -0
- lionagi/integrations/anthropic_/AnthropicModel.py +8 -3
- lionagi/integrations/groq_/GroqModel.py +11 -4
- lionagi/integrations/litellm_/imodel.py +6 -8
- lionagi/integrations/openai_/OpenAIModel.py +8 -3
- lionagi/integrations/openai_/image_token_calculator/image_token_calculator.py +14 -8
- lionagi/integrations/perplexity_/PerplexityModel.py +8 -3
- lionagi/libs/func/async_calls/__init__.py +6 -3
- lionagi/libs/func/async_calls/alcall.py +46 -0
- lionagi/libs/func/async_calls/bcall.py +49 -1
- lionagi/libs/func/async_calls/rcall.py +32 -0
- lionagi/libs/utils.py +12 -1
- lionagi/operations/brainstorm/brainstorm.py +3 -3
- lionagi/operations/plan/plan.py +3 -3
- lionagi/protocols/__init__.py +3 -0
- lionagi/protocols/configs/__init__.py +0 -15
- lionagi/protocols/configs/branch_config.py +1 -1
- lionagi/protocols/configs/imodel_config.py +2 -2
- lionagi/protocols/configs/log_config.py +1 -1
- lionagi/protocols/configs/types.py +15 -0
- lionagi/protocols/operatives/__init__.py +3 -15
- lionagi/protocols/operatives/action.py +4 -0
- lionagi/protocols/operatives/instruct.py +6 -2
- lionagi/protocols/operatives/operative.py +9 -21
- lionagi/protocols/operatives/prompts.py +4 -0
- lionagi/protocols/operatives/reason.py +4 -0
- lionagi/protocols/operatives/step.py +11 -23
- lionagi/protocols/operatives/types.py +19 -0
- lionagi/protocols/registries/__init__.py +3 -0
- lionagi/protocols/registries/_component_registry.py +4 -0
- lionagi/protocols/registries/_pile_registry.py +4 -0
- lionagi/service/__init__.py +3 -0
- lionagi/service/service_match_util.py +4 -4
- lionagi/settings.py +10 -18
- lionagi/strategies/base.py +4 -5
- lionagi/strategies/concurrent.py +4 -3
- lionagi/strategies/concurrent_chunk.py +3 -3
- lionagi/strategies/concurrent_sequential_chunk.py +3 -3
- lionagi/strategies/params.py +7 -4
- lionagi/version.py +1 -1
- {lionagi-0.5.1.dist-info → lionagi-0.5.2.dist-info}/METADATA +4 -2
- {lionagi-0.5.1.dist-info → lionagi-0.5.2.dist-info}/RECORD +71 -70
- lionagi/core/typing/config.py +0 -15
- lionagi/core/typing/id.py +0 -221
- /lionagi/core/typing/{pydantic_.py → _pydantic.py} +0 -0
- /lionagi/core/typing/{typing_.py → _typing.py} +0 -0
- /lionagi/integrations/{services.py → _services.py} +0 -0
- {lionagi-0.5.1.dist-info → lionagi-0.5.2.dist-info}/WHEEL +0 -0
- {lionagi-0.5.1.dist-info → lionagi-0.5.2.dist-info}/licenses/LICENSE +0 -0
lionagi/__init__.py
CHANGED
lionagi/core/action/tool.py
CHANGED
@@ -138,12 +138,10 @@ class Tool(Element):
|
|
138
138
|
Returns:
|
139
139
|
str: A detailed string representation of the Tool.
|
140
140
|
"""
|
141
|
-
timestamp_str =
|
142
|
-
timespec="minutes"
|
143
|
-
)
|
141
|
+
timestamp_str = self.created_datetime.strftime("%Y-%m-%d %H:%M:%S")
|
144
142
|
return (
|
145
|
-
f"{self.class_name()}(ln_id={self.ln_id[:6]}.., "
|
146
|
-
f"
|
143
|
+
f"{self.class_name()}(ln_id={str(self.ln_id)[:6]}.., "
|
144
|
+
f"created_timestamp={timestamp_str}), "
|
147
145
|
f"schema_={json.dumps(self.schema_, indent=4)}"
|
148
146
|
)
|
149
147
|
|
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
from typing_extensions import override
|
6
6
|
|
7
|
-
from lionagi.core.typing import ID, Any, Callable,
|
7
|
+
from lionagi.core.typing import ID, Any, Callable, IDType, Note
|
8
8
|
from lionagi.libs.parse import to_dict
|
9
9
|
from lionagi.libs.utils import copy
|
10
10
|
|
@@ -107,12 +107,12 @@ class ActionRequest(RoledMessage):
|
|
107
107
|
)
|
108
108
|
|
109
109
|
@property
|
110
|
-
def action_response_id(self) ->
|
110
|
+
def action_response_id(self) -> IDType | None:
|
111
111
|
"""
|
112
112
|
Get the ID of the corresponding action response.
|
113
113
|
|
114
114
|
Returns:
|
115
|
-
|
115
|
+
IDType | None: The ID of the action response, or None if not responded
|
116
116
|
"""
|
117
117
|
return self.content.get("action_response_id", None)
|
118
118
|
|
@@ -58,7 +58,7 @@ class MessageField(str, Enum):
|
|
58
58
|
- LION_CLASS: Class identifier for LION system
|
59
59
|
- ROLE: Message role (system/user/assistant)
|
60
60
|
- CONTENT: Message content
|
61
|
-
-
|
61
|
+
- id: Unique message identifier
|
62
62
|
- SENDER: Message sender
|
63
63
|
- RECIPIENT: Message recipient
|
64
64
|
- METADATA: Additional message metadata
|
@@ -68,7 +68,7 @@ class MessageField(str, Enum):
|
|
68
68
|
LION_CLASS = "lion_class"
|
69
69
|
ROLE = "role"
|
70
70
|
CONTENT = "content"
|
71
|
-
|
71
|
+
id = "id"
|
72
72
|
SENDER = "sender"
|
73
73
|
RECIPIENT = "recipient"
|
74
74
|
METADATA = "metadata"
|
@@ -248,7 +248,7 @@ class RoledMessage(Component, BaseMail):
|
|
248
248
|
if origin_obj and isinstance(origin_obj, Communicatable):
|
249
249
|
info_dict = {
|
250
250
|
"clone_from_info": {
|
251
|
-
"
|
251
|
+
"original_id": origin_obj.id,
|
252
252
|
"original_timestamp": origin_obj.timestamp,
|
253
253
|
"original_sender": origin_obj.sender,
|
254
254
|
"original_recipient": origin_obj.recipient,
|
@@ -8,8 +8,8 @@ from lionagi.core.typing import (
|
|
8
8
|
Any,
|
9
9
|
BaseModel,
|
10
10
|
IDError,
|
11
|
+
IDType,
|
11
12
|
Literal,
|
12
|
-
LnID,
|
13
13
|
Note,
|
14
14
|
)
|
15
15
|
from lionagi.integrations.pydantic_ import break_down_pydantic_annotation
|
@@ -229,7 +229,7 @@ def prepare_instruction_content(
|
|
229
229
|
|
230
230
|
def validate_sender_recipient(
|
231
231
|
value: Any, /
|
232
|
-
) ->
|
232
|
+
) -> IDType | Literal["system", "user", "N/A", "assistant"]:
|
233
233
|
"""
|
234
234
|
Validate sender and recipient fields for mail-like communication.
|
235
235
|
|
@@ -237,7 +237,7 @@ def validate_sender_recipient(
|
|
237
237
|
value: The value to validate
|
238
238
|
|
239
239
|
Returns:
|
240
|
-
Union[
|
240
|
+
Union[IDType, Literal]: Valid sender/recipient value
|
241
241
|
|
242
242
|
Raises:
|
243
243
|
ValueError: If value is not a valid sender or recipient
|
@@ -289,8 +289,8 @@ class Component(Element, OperableModel):
|
|
289
289
|
|
290
290
|
output_str = (
|
291
291
|
f"{self.__class__.__name__}("
|
292
|
-
f"ln_id={self.ln_id[:8]}..., "
|
293
|
-
f"
|
292
|
+
f"ln_id={str(self.ln_id)[:8]}..., "
|
293
|
+
f"created_timestamp={str(self.created_datetime)[:-6]}, "
|
294
294
|
f"content='{content_preview}', "
|
295
295
|
f"metadata_keys={list(self.metadata.keys())}, "
|
296
296
|
)
|
@@ -340,8 +340,8 @@ class Component(Element, OperableModel):
|
|
340
340
|
|
341
341
|
repr_str = (
|
342
342
|
f"{self.class_name()}("
|
343
|
-
f"ln_id={
|
344
|
-
f"
|
343
|
+
f"ln_id=IDType({str(self.ln_id)}), "
|
344
|
+
f"created_timestamp={str(self.created_datetime)[:-6]}, "
|
345
345
|
f"content={content_repr}, "
|
346
346
|
f"metadata={truncate_dict(self.metadata.content)}, "
|
347
347
|
)
|
lionagi/core/generic/element.py
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
|
5
5
|
from datetime import datetime
|
6
6
|
|
7
|
+
from pydantic import AliasChoices, field_serializer
|
8
|
+
|
7
9
|
from lionagi.core._class_registry import LION_CLASS_REGISTRY, get_class
|
8
10
|
from lionagi.core.typing import (
|
9
11
|
ID,
|
@@ -12,8 +14,7 @@ from lionagi.core.typing import (
|
|
12
14
|
ConfigDict,
|
13
15
|
Field,
|
14
16
|
IDError,
|
15
|
-
|
16
|
-
Note,
|
17
|
+
IDType,
|
17
18
|
Observable,
|
18
19
|
TypeVar,
|
19
20
|
field_validator,
|
@@ -48,32 +49,45 @@ class Element(BaseModel, Observable):
|
|
48
49
|
- String formatting
|
49
50
|
|
50
51
|
Attributes:
|
51
|
-
|
52
|
+
id (IDType): Unique identifier for the element. Generated automatically
|
52
53
|
and immutable.
|
53
54
|
timestamp (float): Creation timestamp as Unix timestamp. Generated
|
54
55
|
automatically and immutable.
|
55
56
|
"""
|
56
57
|
|
57
|
-
|
58
|
+
model_config = ConfigDict(
|
59
|
+
extra="forbid",
|
60
|
+
arbitrary_types_allowed=True,
|
61
|
+
use_enum_values=True,
|
62
|
+
populate_by_name=True,
|
63
|
+
)
|
64
|
+
|
65
|
+
ln_id: IDType = Field(
|
58
66
|
default_factory=ID.id,
|
59
67
|
title="Lion ID",
|
60
68
|
description="Unique identifier for the element",
|
61
69
|
frozen=True,
|
62
70
|
)
|
63
71
|
|
64
|
-
|
65
|
-
default_factory=lambda: time(
|
66
|
-
|
72
|
+
created_timestamp: float = Field(
|
73
|
+
default_factory=lambda: time(
|
74
|
+
tz=Settings.Config.TIMEZONE, type_="timestamp"
|
75
|
+
),
|
76
|
+
title="Creation Datetime",
|
67
77
|
frozen=True,
|
68
|
-
alias="
|
78
|
+
alias=AliasChoices("created_at", "timestamp"),
|
69
79
|
)
|
70
80
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
81
|
+
@property
|
82
|
+
def created_datetime(self) -> datetime:
|
83
|
+
"""Get the creation timestamp as a Unix timestamp.
|
84
|
+
|
85
|
+
Returns:
|
86
|
+
float: The creation timestamp.
|
87
|
+
"""
|
88
|
+
return datetime.fromtimestamp(
|
89
|
+
self.created_timestamp, tz=Settings.Config.TIMEZONE
|
90
|
+
)
|
77
91
|
|
78
92
|
@classmethod
|
79
93
|
def class_name(cls) -> str:
|
@@ -89,41 +103,39 @@ class Element(BaseModel, Observable):
|
|
89
103
|
super().__pydantic_init_subclass__(**kwargs)
|
90
104
|
LION_CLASS_REGISTRY[cls.__name__] = cls
|
91
105
|
|
92
|
-
@
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
Converts the Unix timestamp to a timezone-aware datetime object using the
|
97
|
-
timezone specified in Settings.Config.TIMEZONE.
|
98
|
-
|
99
|
-
Returns:
|
100
|
-
datetime: A timezone-aware datetime object representing when the
|
101
|
-
Element was created.
|
102
|
-
"""
|
103
|
-
return datetime.fromtimestamp(
|
104
|
-
self.timestamp, tz=Settings.Config.TIMEZONE
|
105
|
-
)
|
106
|
+
@field_serializer("ln_id")
|
107
|
+
def _serialize_id(self, value: IDType) -> str:
|
108
|
+
return str(self.ln_id)
|
106
109
|
|
107
110
|
@field_validator("ln_id", mode="before")
|
108
|
-
def _validate_id(cls, value:
|
111
|
+
def _validate_id(cls, value: str | IDType) -> str:
|
109
112
|
try:
|
110
113
|
return ID.get_id(value)
|
111
114
|
except Exception:
|
112
115
|
raise IDError(f"Invalid lion id: {value}")
|
113
116
|
|
114
|
-
@field_validator("
|
117
|
+
@field_validator("created_timestamp", mode="before")
|
115
118
|
def _validate_timestamp(cls, value: Any) -> float:
|
116
|
-
if isinstance(value, (int, float)):
|
117
|
-
return float(value)
|
118
119
|
if isinstance(value, datetime):
|
119
120
|
return value.timestamp()
|
120
|
-
|
121
|
-
|
121
|
+
|
122
|
+
if isinstance(value, int | float):
|
123
|
+
return value
|
124
|
+
|
125
|
+
if isinstance(value, str):
|
126
|
+
try:
|
127
|
+
return datetime.fromisoformat(value).timestamp()
|
128
|
+
except Exception as e:
|
122
129
|
try:
|
123
|
-
|
130
|
+
value = float(value)
|
124
131
|
except Exception:
|
125
|
-
|
126
|
-
|
132
|
+
raise ValueError(
|
133
|
+
f"Invalid datetime string format: {value}"
|
134
|
+
) from e
|
135
|
+
|
136
|
+
try:
|
137
|
+
return datetime.fromtimestamp(value, tz=Settings.Config.TIMEZONE)
|
138
|
+
|
127
139
|
except Exception as e:
|
128
140
|
raise ValueError(f"Invalid datetime string format: {value}") from e
|
129
141
|
|
@@ -170,8 +182,8 @@ class Element(BaseModel, Observable):
|
|
170
182
|
def __str__(self) -> str:
|
171
183
|
timestamp_str = self.created_datetime.isoformat(timespec="minutes")
|
172
184
|
return (
|
173
|
-
f"{self.class_name()}(ln_id={self.ln_id[:6]}.., "
|
174
|
-
f"
|
185
|
+
f"{self.class_name()}(ln_id={str(self.ln_id)[:6]}.., "
|
186
|
+
f"created_timestamp={timestamp_str})"
|
175
187
|
)
|
176
188
|
|
177
189
|
def __hash__(self) -> int:
|
@@ -183,13 +195,5 @@ class Element(BaseModel, Observable):
|
|
183
195
|
def __len__(self) -> int:
|
184
196
|
return 1
|
185
197
|
|
186
|
-
def to_note(self) -> Note:
|
187
|
-
"""Convert Log to Note.
|
188
|
-
|
189
|
-
Returns:
|
190
|
-
Note representation of the log
|
191
|
-
"""
|
192
|
-
return Note(**self.to_dict())
|
193
|
-
|
194
198
|
|
195
199
|
__all__ = ["Element"]
|
lionagi/core/generic/graph.py
CHANGED
@@ -281,7 +281,7 @@ class Graph(Node):
|
|
281
281
|
node_info.update({"class_name": node.class_name()})
|
282
282
|
if hasattr(node, "name"):
|
283
283
|
node_info.update({"name": node.name})
|
284
|
-
g.add_node(node.ln_id, **node_info)
|
284
|
+
g.add_node(str(node.ln_id), **node_info)
|
285
285
|
|
286
286
|
for _edge in self.internal_edges:
|
287
287
|
edge_info = _edge.to_dict()
|
lionagi/core/generic/log.py
CHANGED
@@ -72,7 +72,7 @@ class Log(Element):
|
|
72
72
|
if "log_id" in data:
|
73
73
|
data["ln_id"] = data.pop("log_id")
|
74
74
|
if "log_timestamp" in data:
|
75
|
-
data["
|
75
|
+
data["created_timestamp"] = data.pop("log_timestamp")
|
76
76
|
if "log_class" in data:
|
77
77
|
data["lion_class"] = data.pop("log_class")
|
78
78
|
return data
|
@@ -140,7 +140,7 @@ class Log(Element):
|
|
140
140
|
# Convert standard fields to log_* fields
|
141
141
|
dict_["log_id"] = dict_.pop("ln_id")
|
142
142
|
dict_["log_class"] = dict_.pop("lion_class")
|
143
|
-
dict_["log_timestamp"] = dict_.pop("
|
143
|
+
dict_["log_timestamp"] = dict_.pop("created_timestamp")
|
144
144
|
|
145
145
|
dict_ = to_dict(
|
146
146
|
dict_,
|
lionagi/core/generic/pile.py
CHANGED
@@ -26,6 +26,7 @@ from lionagi.core.typing import (
|
|
26
26
|
TypeVar,
|
27
27
|
field_serializer,
|
28
28
|
)
|
29
|
+
from lionagi.core.typing._concepts import IDType
|
29
30
|
from lionagi.libs.parse import is_same_dtype, to_list
|
30
31
|
from lionagi.protocols.adapters.adapter import Adapter, AdapterRegistry
|
31
32
|
from lionagi.protocols.registries._pile_registry import PileAdapterRegistry
|
@@ -38,6 +39,9 @@ T = TypeVar("T", bound=Element)
|
|
38
39
|
D = TypeVar("D")
|
39
40
|
|
40
41
|
|
42
|
+
__all__ = ("Pile", "pile")
|
43
|
+
|
44
|
+
|
41
45
|
def synchronized(func: Callable):
|
42
46
|
@wraps(func)
|
43
47
|
def wrapper(self: "Pile", *args, **kwargs):
|
@@ -72,7 +76,7 @@ class Pile(Element, Generic[T]):
|
|
72
76
|
strict_type (bool): Whether to enforce strict type checking
|
73
77
|
"""
|
74
78
|
|
75
|
-
pile_: dict[
|
79
|
+
pile_: dict[IDType, T] = Field(default_factory=dict)
|
76
80
|
item_type: set[type[T]] | None = Field(
|
77
81
|
default=None,
|
78
82
|
description="Set of allowed types for items in the pile.",
|
@@ -120,8 +124,8 @@ class Pile(Element, Generic[T]):
|
|
120
124
|
_config = {}
|
121
125
|
if "ln_id" in kwargs:
|
122
126
|
_config["ln_id"] = kwargs["ln_id"]
|
123
|
-
if "
|
124
|
-
_config["
|
127
|
+
if "created_timestamp" in kwargs:
|
128
|
+
_config["created_timestamp"] = kwargs["created_timestamp"]
|
125
129
|
|
126
130
|
super().__init__(strict_type=strict_type, **_config)
|
127
131
|
self.item_type = self._validate_item_type(item_type)
|
@@ -303,7 +307,7 @@ class Pile(Element, Generic[T]):
|
|
303
307
|
"""Get all items in order."""
|
304
308
|
return [self.pile_[key] for key in self.progress]
|
305
309
|
|
306
|
-
def items(self) -> Sequence[tuple[
|
310
|
+
def items(self) -> Sequence[tuple[IDType, T]]:
|
307
311
|
"""Get all (ID, item) pairs in order."""
|
308
312
|
return [(key, self.pile_[key]) for key in self.progress]
|
309
313
|
|
@@ -619,7 +623,7 @@ class Pile(Element, Generic[T]):
|
|
619
623
|
except Exception as e:
|
620
624
|
raise ItemNotFoundError(f"index {key}. Error: {e}")
|
621
625
|
|
622
|
-
elif isinstance(key,
|
626
|
+
elif isinstance(key, IDType):
|
623
627
|
try:
|
624
628
|
return self.pile_[key]
|
625
629
|
except Exception as e:
|
@@ -724,7 +728,7 @@ class Pile(Element, Generic[T]):
|
|
724
728
|
if isinstance(key, int | slice):
|
725
729
|
try:
|
726
730
|
pops = self.progress[key]
|
727
|
-
pops = [pops] if isinstance(pops,
|
731
|
+
pops = [pops] if isinstance(pops, IDType) else pops
|
728
732
|
result = []
|
729
733
|
for i in pops:
|
730
734
|
self.progress.remove(i)
|
@@ -965,10 +969,6 @@ class Pile(Element, Generic[T]):
|
|
965
969
|
"""Save to CSV file."""
|
966
970
|
self.adapt_to(".csv", fp=fp, **kwargs)
|
967
971
|
|
968
|
-
def to_excel(self, fp: str | Path, **kwargs: Any) -> None:
|
969
|
-
"""Save to Excel file."""
|
970
|
-
self.adapt_to(".xlsx", fp=fp, **kwargs)
|
971
|
-
|
972
972
|
|
973
973
|
def pile(
|
974
974
|
items: Any = None,
|
@@ -1013,5 +1013,4 @@ def pile(
|
|
1013
1013
|
)
|
1014
1014
|
|
1015
1015
|
|
1016
|
-
__all__ = [Pile, pile]
|
1017
1016
|
# File: autoos/generic/pile.py
|
@@ -6,15 +6,18 @@ import contextlib
|
|
6
6
|
from collections.abc import Iterator
|
7
7
|
from typing import Any, Self
|
8
8
|
|
9
|
-
from pydantic import field_validator
|
9
|
+
from pydantic import field_serializer, field_validator
|
10
10
|
from typing_extensions import override
|
11
11
|
|
12
|
-
from lionagi.core.typing import ID, Field,
|
12
|
+
from lionagi.core.typing import ID, Field, IDType, ItemNotFoundError, Ordering
|
13
|
+
from lionagi.core.typing._concepts import Observable
|
13
14
|
from lionagi.libs.parse import to_list
|
14
15
|
|
15
16
|
from .element import Element
|
16
17
|
from .utils import to_list_type, validate_order
|
17
18
|
|
19
|
+
__all__ = ("Progression", "prog")
|
20
|
+
|
18
21
|
|
19
22
|
class Progression(Element, Ordering):
|
20
23
|
"""A flexible, ordered sequence container for Lion IDs.
|
@@ -41,14 +44,18 @@ class Progression(Element, Ordering):
|
|
41
44
|
description="The name of the progression.",
|
42
45
|
)
|
43
46
|
|
44
|
-
order: list[
|
47
|
+
order: list[IDType] = Field(
|
45
48
|
default_factory=list,
|
46
49
|
title="Order",
|
47
50
|
description="The order of the progression.",
|
48
51
|
)
|
49
52
|
|
53
|
+
@field_serializer("order")
|
54
|
+
def _serialize_order(self, value: list[IDType]) -> list[str]:
|
55
|
+
return [str(i) for i in self.order]
|
56
|
+
|
50
57
|
@field_validator("order", mode="before")
|
51
|
-
def _validate_order(cls, value: ID.RefSeq) -> list[
|
58
|
+
def _validate_order(cls, value: ID.RefSeq) -> list[IDType]:
|
52
59
|
if not value:
|
53
60
|
return []
|
54
61
|
try:
|
@@ -66,15 +73,15 @@ class Progression(Element, Ordering):
|
|
66
73
|
check = False
|
67
74
|
for i in item:
|
68
75
|
check = False
|
69
|
-
if isinstance(i,
|
76
|
+
if isinstance(i, IDType):
|
70
77
|
check = i in self.order
|
71
|
-
elif isinstance(i,
|
78
|
+
elif isinstance(i, Observable):
|
72
79
|
check = i.ln_id in self.order
|
73
80
|
if not check:
|
74
81
|
return False
|
75
82
|
return check
|
76
83
|
|
77
|
-
def __list__(self) -> list[
|
84
|
+
def __list__(self) -> list[IDType]:
|
78
85
|
"""Return a copy of the order."""
|
79
86
|
return self.order[:]
|
80
87
|
|
@@ -127,11 +134,11 @@ class Progression(Element, Ordering):
|
|
127
134
|
"""Delete an item or slice of items from the progression."""
|
128
135
|
del self.order[key]
|
129
136
|
|
130
|
-
def __iter__(self) -> Iterator[
|
137
|
+
def __iter__(self) -> Iterator[IDType]:
|
131
138
|
"""Iterate over the items in the progression."""
|
132
139
|
return iter(self.order)
|
133
140
|
|
134
|
-
def __next__(self) ->
|
141
|
+
def __next__(self) -> IDType:
|
135
142
|
"""Return the next item in the progression."""
|
136
143
|
try:
|
137
144
|
return next(iter(self.order))
|
@@ -155,7 +162,7 @@ class Progression(Element, Ordering):
|
|
155
162
|
item_ = validate_order(item)
|
156
163
|
self.order.extend(item_)
|
157
164
|
|
158
|
-
def pop(self, index: int = None, /) ->
|
165
|
+
def pop(self, index: int = None, /) -> IDType:
|
159
166
|
"""Remove and return an item from the progression.
|
160
167
|
|
161
168
|
Args:
|
@@ -255,7 +262,7 @@ class Progression(Element, Ordering):
|
|
255
262
|
|
256
263
|
raise ItemNotFoundError(f"{item}")
|
257
264
|
|
258
|
-
def popleft(self) ->
|
265
|
+
def popleft(self) -> IDType:
|
259
266
|
"""Remove and return the leftmost item from the progression.
|
260
267
|
|
261
268
|
Returns:
|
@@ -371,7 +378,7 @@ class Progression(Element, Ordering):
|
|
371
378
|
return hash(self.ln_id)
|
372
379
|
|
373
380
|
|
374
|
-
def
|
381
|
+
def prog(
|
375
382
|
order: ID.RefSeq = None,
|
376
383
|
name: str = None,
|
377
384
|
/,
|
lionagi/core/generic/utils.py
CHANGED
@@ -7,6 +7,7 @@ from collections.abc import Generator
|
|
7
7
|
from typing import Any, TypeVar
|
8
8
|
|
9
9
|
from lionagi.core.typing import ID, IDError
|
10
|
+
from lionagi.core.typing._concepts import IDType, Observable
|
10
11
|
|
11
12
|
from .element import Element
|
12
13
|
|
@@ -17,8 +18,10 @@ def to_list_type(value: Any, /) -> list[Any]:
|
|
17
18
|
"""Convert input to a list format"""
|
18
19
|
if value is None:
|
19
20
|
return []
|
21
|
+
if isinstance(value, IDType):
|
22
|
+
return [value]
|
20
23
|
if isinstance(value, str):
|
21
|
-
return
|
24
|
+
return ID.get_id(value) if ID.is_id(value) else []
|
22
25
|
if isinstance(value, Element):
|
23
26
|
return [value]
|
24
27
|
if hasattr(value, "values") and callable(value.values):
|
@@ -35,8 +38,8 @@ def validate_order(value: Any, /) -> list[str]:
|
|
35
38
|
result = []
|
36
39
|
for item in to_list_type(value):
|
37
40
|
if isinstance(item, str) and ID.is_id(item):
|
38
|
-
result.append(item)
|
39
|
-
elif isinstance(item,
|
41
|
+
result.append(ID.get_id(item))
|
42
|
+
elif isinstance(item, Observable):
|
40
43
|
result.append(item.ln_id)
|
41
44
|
else:
|
42
45
|
id_ = ID.get_id(item)
|
lionagi/core/models/base.py
CHANGED
@@ -2,84 +2,27 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
4
4
|
|
5
|
-
from ..typing.
|
6
|
-
from ..typing.
|
5
|
+
from ..typing._pydantic import BaseModel
|
6
|
+
from ..typing._typing import UNDEFINED, Any, Self
|
7
7
|
|
8
|
-
|
9
|
-
"populate_by_name": True,
|
10
|
-
"arbitrary_types_allowed": True,
|
11
|
-
"use_enum_values": True,
|
12
|
-
}
|
8
|
+
__all__ = ("BaseAutoModel",)
|
13
9
|
|
14
10
|
|
15
11
|
class BaseAutoModel(BaseModel):
|
16
|
-
"""
|
12
|
+
"""a hashable pydantic model interface with to_dict and from_dict method"""
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
- Nested model serialization
|
21
|
-
- Hash generation based on model content
|
22
|
-
- Validation rules
|
23
|
-
|
24
|
-
Example:
|
25
|
-
```python
|
26
|
-
class User(BaseAutoModel):
|
27
|
-
name: str = Field(min_length=2)
|
28
|
-
age: int | None = None
|
29
|
-
settings: dict = Field(default_factory=dict)
|
30
|
-
|
31
|
-
user = User(name="John", age=30)
|
32
|
-
data = user.to_dict(clean=True) # Excludes UNDEFINED values
|
33
|
-
```
|
34
|
-
|
35
|
-
Attributes:
|
36
|
-
model_config: Default configuration for all instances
|
37
|
-
- validate_default: True to validate default values
|
38
|
-
- populate_by_name: True to allow field population by alias
|
39
|
-
- arbitrary_types_allowed: True to allow any type
|
40
|
-
- use_enum_values: True to use enum values in serialization
|
41
|
-
"""
|
42
|
-
|
43
|
-
def to_dict(self, clean: bool = False) -> dict[str, Any]:
|
44
|
-
"""Convert model to dictionary, with optional cleaning.
|
45
|
-
|
46
|
-
Args:
|
47
|
-
clean: If True, exclude UNDEFINED values from output.
|
48
|
-
If False, include all fields using model_dump().
|
49
|
-
|
50
|
-
Returns:
|
51
|
-
Dictionary representation of model with nested models serialized
|
52
|
-
"""
|
53
|
-
if not clean:
|
54
|
-
return self.model_dump()
|
14
|
+
def to_dict(self, **kwargs) -> dict[str, Any]:
|
15
|
+
"""kwargs for pydantic model_dump()"""
|
55
16
|
return {
|
56
17
|
k: v
|
57
|
-
for k, v in self.model_dump(
|
18
|
+
for k, v in self.model_dump(**kwargs).items()
|
58
19
|
if v is not UNDEFINED
|
59
20
|
}
|
60
21
|
|
61
22
|
@classmethod
|
62
|
-
def from_dict(cls, data: dict) -> Self:
|
63
|
-
"""
|
64
|
-
|
65
|
-
Args:
|
66
|
-
data: Dictionary containing field values
|
67
|
-
|
68
|
-
Returns:
|
69
|
-
New model instance
|
70
|
-
|
71
|
-
Raises:
|
72
|
-
ValueError: If required fields are missing or validation fails
|
73
|
-
"""
|
74
|
-
return cls.model_validate(data)
|
23
|
+
def from_dict(cls, data: dict, **kwargs) -> Self:
|
24
|
+
"""kwargs for model_validate"""
|
25
|
+
return cls.model_validate(data, **kwargs)
|
75
26
|
|
76
27
|
def __hash__(self) -> int:
|
77
|
-
|
78
|
-
|
79
|
-
Returns:
|
80
|
-
Hash value that uniquely identifies the model's content
|
81
|
-
"""
|
82
|
-
return hash(str(self.to_dict(True)))
|
83
|
-
|
84
|
-
|
85
|
-
__all__ = ["BaseAutoModel"]
|
28
|
+
return hash(str(self.to_dict()))
|