lionagi 0.17.11__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/libs/schema/minimal_yaml.py +98 -0
- lionagi/ln/__init__.py +3 -1
- lionagi/ln/concurrency/primitives.py +4 -4
- lionagi/ln/concurrency/task.py +1 -0
- lionagi/ln/types.py +32 -5
- lionagi/models/field_model.py +21 -4
- lionagi/models/hashable_model.py +2 -3
- lionagi/operations/ReAct/ReAct.py +475 -238
- lionagi/operations/ReAct/utils.py +3 -0
- lionagi/operations/act/act.py +206 -0
- lionagi/operations/builder.py +5 -7
- lionagi/operations/chat/chat.py +130 -114
- lionagi/operations/communicate/communicate.py +101 -42
- lionagi/operations/fields.py +380 -0
- lionagi/operations/flow.py +8 -10
- lionagi/operations/interpret/interpret.py +65 -20
- lionagi/operations/node.py +4 -4
- lionagi/operations/operate/operate.py +216 -108
- lionagi/{protocols/operatives → operations/operate}/operative.py +4 -5
- lionagi/{protocols/operatives → operations/operate}/step.py +34 -39
- lionagi/operations/parse/parse.py +170 -142
- lionagi/operations/select/select.py +79 -18
- lionagi/operations/select/utils.py +8 -2
- lionagi/operations/types.py +119 -23
- 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/log.py +3 -2
- 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 +29 -0
- lionagi/protocols/messages/action_request.py +86 -184
- lionagi/protocols/messages/action_response.py +73 -131
- lionagi/protocols/messages/assistant_response.py +130 -159
- lionagi/protocols/messages/base.py +31 -22
- lionagi/protocols/messages/instruction.py +280 -625
- lionagi/protocols/messages/manager.py +112 -62
- lionagi/protocols/messages/message.py +87 -197
- lionagi/protocols/messages/system.py +52 -123
- lionagi/protocols/types.py +1 -13
- lionagi/service/connections/__init__.py +3 -0
- lionagi/service/connections/endpoint.py +0 -8
- lionagi/service/connections/providers/claude_code_cli.py +3 -2
- lionagi/service/connections/providers/oai_.py +29 -94
- lionagi/service/connections/providers/ollama_.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 +63 -3
- lionagi/service/imodel.py +24 -20
- lionagi/service/third_party/claude_code.py +3 -3
- lionagi/service/third_party/openai_models.py +435 -0
- lionagi/service/token_calculator.py +1 -94
- lionagi/session/branch.py +190 -400
- lionagi/session/session.py +8 -99
- lionagi/tools/file/reader.py +2 -2
- lionagi/version.py +1 -1
- {lionagi-0.17.11.dist-info → lionagi-0.18.1.dist-info}/METADATA +6 -6
- lionagi-0.18.1.dist-info/RECORD +164 -0
- 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/_act/act.py +0 -86
- 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/messages/templates/README.md +0 -28
- lionagi/protocols/messages/templates/action_request.jinja2 +0 -5
- lionagi/protocols/messages/templates/action_response.jinja2 +0 -9
- lionagi/protocols/messages/templates/assistant_response.jinja2 +0 -6
- lionagi/protocols/messages/templates/instruction_message.jinja2 +0 -61
- lionagi/protocols/messages/templates/system_message.jinja2 +0 -11
- lionagi/protocols/messages/templates/tool_schemas.jinja2 +0 -7
- lionagi/protocols/operatives/__init__.py +0 -2
- lionagi/service/connections/providers/types.py +0 -28
- lionagi/service/third_party/openai_model_names.py +0 -198
- lionagi/service/types.py +0 -58
- lionagi-0.17.11.dist-info/RECORD +0 -199
- /lionagi/operations/{_act → act}/__init__.py +0 -0
- {lionagi-0.17.11.dist-info → lionagi-0.18.1.dist-info}/WHEEL +0 -0
- {lionagi-0.17.11.dist-info → lionagi-0.18.1.dist-info}/licenses/LICENSE +0 -0
lionagi/_errors.py
CHANGED
|
@@ -13,7 +13,6 @@ __all__ = (
|
|
|
13
13
|
"ObservationError",
|
|
14
14
|
"ResourceError",
|
|
15
15
|
"RateLimitError",
|
|
16
|
-
"IDError",
|
|
17
16
|
"RelationError",
|
|
18
17
|
"OperationError",
|
|
19
18
|
"ExecutionError",
|
|
@@ -127,10 +126,6 @@ class RateLimitError(LionError):
|
|
|
127
126
|
object.__setattr__(self, "retry_after", retry_after)
|
|
128
127
|
|
|
129
128
|
|
|
130
|
-
class IDError(LionError):
|
|
131
|
-
pass
|
|
132
|
-
|
|
133
|
-
|
|
134
129
|
class RelationError(LionError):
|
|
135
130
|
pass
|
|
136
131
|
|
lionagi/fields.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from .operations.fields import (
|
|
5
|
+
ActionRequestModel,
|
|
6
|
+
ActionResponseModel,
|
|
7
|
+
Instruct,
|
|
8
|
+
Reason,
|
|
9
|
+
get_default_field,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
_lazy_imports = {}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def __getattr__(name: str):
|
|
16
|
+
if name in _lazy_imports:
|
|
17
|
+
return _lazy_imports[name]
|
|
18
|
+
|
|
19
|
+
if name == "ActionRequestModel":
|
|
20
|
+
from .operations.fields import ActionRequestModel
|
|
21
|
+
|
|
22
|
+
_lazy_imports[name] = ActionRequestModel
|
|
23
|
+
return ActionRequestModel
|
|
24
|
+
|
|
25
|
+
if name == "ActionResponseModel":
|
|
26
|
+
from .operations.fields import ActionResponseModel
|
|
27
|
+
|
|
28
|
+
_lazy_imports[name] = ActionResponseModel
|
|
29
|
+
return ActionResponseModel
|
|
30
|
+
|
|
31
|
+
if name == "Instruct":
|
|
32
|
+
from .operations.fields import Instruct
|
|
33
|
+
|
|
34
|
+
_lazy_imports[name] = Instruct
|
|
35
|
+
return Instruct
|
|
36
|
+
|
|
37
|
+
if name == "Reason":
|
|
38
|
+
from .operations.fields import Reason
|
|
39
|
+
|
|
40
|
+
_lazy_imports[name] = Reason
|
|
41
|
+
return Reason
|
|
42
|
+
|
|
43
|
+
from .operations.fields import get_default_field
|
|
44
|
+
|
|
45
|
+
if name == "get_default_field":
|
|
46
|
+
|
|
47
|
+
_lazy_imports[name] = get_default_field
|
|
48
|
+
return get_default_field
|
|
49
|
+
|
|
50
|
+
if name == "ACTION_REQUESTS_FIELD":
|
|
51
|
+
return get_default_field("action_requests")
|
|
52
|
+
|
|
53
|
+
if name == "ACTION_RESPONSES_FIELD":
|
|
54
|
+
return get_default_field("action_responses")
|
|
55
|
+
|
|
56
|
+
if name == "ACTION_REQUIRED_FIELD":
|
|
57
|
+
return get_default_field("action_required")
|
|
58
|
+
|
|
59
|
+
if name == "INSTRUCT_FIELD":
|
|
60
|
+
return get_default_field("instruct")
|
|
61
|
+
|
|
62
|
+
if name == "LIST_INSTRUCT_FIELD_MODEL":
|
|
63
|
+
return get_default_field("instruct", listable=True)
|
|
64
|
+
|
|
65
|
+
if name == "REASON_FIELD":
|
|
66
|
+
return get_default_field("reason")
|
|
67
|
+
|
|
68
|
+
raise AttributeError(f"module {__name__} has no attribute {name}")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
__all__ = (
|
|
72
|
+
"ACTION_REQUESTS_FIELD",
|
|
73
|
+
"ACTION_RESPONSES_FIELD",
|
|
74
|
+
"ACTION_REQUIRED_FIELD",
|
|
75
|
+
"INSTRUCT_FIELD",
|
|
76
|
+
"LIST_INSTRUCT_FIELD_MODEL",
|
|
77
|
+
"REASON_FIELD",
|
|
78
|
+
"ActionRequestModel",
|
|
79
|
+
"ActionResponseModel",
|
|
80
|
+
"Instruct",
|
|
81
|
+
"Reason",
|
|
82
|
+
"get_default_field",
|
|
83
|
+
)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import orjson
|
|
6
|
+
import yaml
|
|
7
|
+
|
|
8
|
+
# --- YAML Dumper with minimal, readable settings --------------------------------
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MinimalDumper(yaml.SafeDumper):
|
|
12
|
+
# Disable anchors/aliases (&id001, *id001) for repeated objects.
|
|
13
|
+
def ignore_aliases(self, data: Any) -> bool: # type: ignore[override]
|
|
14
|
+
return True
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _represent_str(dumper: yaml.SafeDumper, data: str):
|
|
18
|
+
# Use block scalars for multiline text; plain style otherwise.
|
|
19
|
+
if "\n" in data:
|
|
20
|
+
return dumper.represent_scalar(
|
|
21
|
+
"tag:yaml.org,2002:str", data, style="|"
|
|
22
|
+
)
|
|
23
|
+
return dumper.represent_scalar("tag:yaml.org,2002:str", data)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
MinimalDumper.add_representer(str, _represent_str)
|
|
27
|
+
|
|
28
|
+
# --- Optional pruning of empty values -------------------------------------------
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _is_empty(x: Any) -> bool:
|
|
32
|
+
"""
|
|
33
|
+
Define 'empty' for pruning. Keeps 0 and False.
|
|
34
|
+
- None or '' (after strip) are empty
|
|
35
|
+
- Empty containers are empty
|
|
36
|
+
"""
|
|
37
|
+
if x is None:
|
|
38
|
+
return True
|
|
39
|
+
if isinstance(x, str):
|
|
40
|
+
return x.strip() == ""
|
|
41
|
+
if isinstance(x, dict):
|
|
42
|
+
return len(x) == 0
|
|
43
|
+
if isinstance(x, (list, tuple, set)):
|
|
44
|
+
return len(x) == 0
|
|
45
|
+
# Keep numbers (including 0) and booleans (including False)
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _prune(x: Any) -> Any:
|
|
50
|
+
"""Recursively remove empty leaves and empty containers produced thereby."""
|
|
51
|
+
if isinstance(x, dict):
|
|
52
|
+
pruned = {k: _prune(v) for k, v in x.items() if not _is_empty(v)}
|
|
53
|
+
# Remove keys that became empty after recursion
|
|
54
|
+
return {k: v for k, v in pruned.items() if not _is_empty(v)}
|
|
55
|
+
if isinstance(x, list):
|
|
56
|
+
pruned_list = [_prune(v) for v in x if not _is_empty(v)]
|
|
57
|
+
return [v for v in pruned_list if not _is_empty(v)]
|
|
58
|
+
if isinstance(x, tuple):
|
|
59
|
+
pruned_list = [_prune(v) for v in x if not _is_empty(v)]
|
|
60
|
+
return tuple(v for v in pruned_list if not _is_empty(v))
|
|
61
|
+
if isinstance(x, set):
|
|
62
|
+
pruned_set = {_prune(v) for v in x if not _is_empty(v)}
|
|
63
|
+
return {v for v in pruned_set if not _is_empty(v)}
|
|
64
|
+
return x
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# --- Public API ------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def minimal_yaml(
|
|
71
|
+
value: Any,
|
|
72
|
+
*,
|
|
73
|
+
drop_empties: bool = True,
|
|
74
|
+
indent: int = 2,
|
|
75
|
+
line_width: int = 2**31 - 1, # avoid PyYAML inserting line-wraps
|
|
76
|
+
sort_keys: bool = False,
|
|
77
|
+
) -> str:
|
|
78
|
+
"""
|
|
79
|
+
Convert any Python value (dict/list/scalars) to a minimal, readable YAML string.
|
|
80
|
+
- Lists -> YAML sequences with '- '
|
|
81
|
+
- Dicts -> 'key: value' mappings
|
|
82
|
+
- Multiline strings -> block scalars (|)
|
|
83
|
+
- Optional pruning of empty values (keeps 0 and False)
|
|
84
|
+
- No aliases/anchors
|
|
85
|
+
"""
|
|
86
|
+
if isinstance(value, str):
|
|
87
|
+
value = orjson.loads(value)
|
|
88
|
+
|
|
89
|
+
data = _prune(value) if drop_empties else value
|
|
90
|
+
return yaml.dump(
|
|
91
|
+
data,
|
|
92
|
+
Dumper=MinimalDumper,
|
|
93
|
+
default_flow_style=False, # block style
|
|
94
|
+
sort_keys=sort_keys, # preserve insertion order
|
|
95
|
+
allow_unicode=True,
|
|
96
|
+
indent=indent,
|
|
97
|
+
width=line_width,
|
|
98
|
+
)
|
lionagi/ln/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from ._async_call import alcall, bcall
|
|
1
|
+
from ._async_call import AlcallParams, BcallParams, alcall, bcall
|
|
2
2
|
from ._hash import hash_dict
|
|
3
3
|
from ._json_dump import (
|
|
4
4
|
get_orjson_default,
|
|
@@ -80,4 +80,6 @@ __all__ = (
|
|
|
80
80
|
"not_sentinel",
|
|
81
81
|
"to_dict",
|
|
82
82
|
"fuzzy_validate_mapping",
|
|
83
|
+
"AlcallParams",
|
|
84
|
+
"BcallParams",
|
|
83
85
|
)
|
|
@@ -142,15 +142,15 @@ class CapacityLimiter:
|
|
|
142
142
|
"""Get the number of currently available tokens."""
|
|
143
143
|
return self._lim.available_tokens
|
|
144
144
|
|
|
145
|
-
def acquire_on_behalf_of(self, borrower: object) -> None:
|
|
146
|
-
"""
|
|
145
|
+
async def acquire_on_behalf_of(self, borrower: object) -> None:
|
|
146
|
+
"""Asynchronously acquire capacity on behalf of another object.
|
|
147
147
|
|
|
148
148
|
For resource pooling where the acquirer differs from the releaser.
|
|
149
149
|
|
|
150
150
|
Args:
|
|
151
151
|
borrower: Object that will be responsible for releasing.
|
|
152
152
|
"""
|
|
153
|
-
self._lim.acquire_on_behalf_of(borrower)
|
|
153
|
+
await self._lim.acquire_on_behalf_of(borrower)
|
|
154
154
|
|
|
155
155
|
def release_on_behalf_of(self, borrower: object) -> None:
|
|
156
156
|
"""Release capacity that was acquired on behalf of an object.
|
|
@@ -326,6 +326,6 @@ class Condition:
|
|
|
326
326
|
"""Wake up all tasks waiting on this condition."""
|
|
327
327
|
self._condition.notify_all()
|
|
328
328
|
|
|
329
|
-
def statistics(self) -> anyio.
|
|
329
|
+
def statistics(self) -> anyio.ConditionStatistics:
|
|
330
330
|
"""Return statistics about waiting tasks."""
|
|
331
331
|
return self._condition.statistics()
|
lionagi/ln/concurrency/task.py
CHANGED
lionagi/ln/types.py
CHANGED
|
@@ -232,10 +232,13 @@ class Params:
|
|
|
232
232
|
dict_.update(kw_)
|
|
233
233
|
return dict_
|
|
234
234
|
|
|
235
|
-
def to_dict(self) -> dict[str, str]:
|
|
235
|
+
def to_dict(self, exclude: set[str] = None) -> dict[str, str]:
|
|
236
236
|
data = {}
|
|
237
|
+
exclude = exclude or set()
|
|
237
238
|
for k in self.allowed():
|
|
238
|
-
if not self._is_sentinel(
|
|
239
|
+
if k not in exclude and not self._is_sentinel(
|
|
240
|
+
v := getattr(self, k, Undefined)
|
|
241
|
+
):
|
|
239
242
|
data[k] = v
|
|
240
243
|
return data
|
|
241
244
|
|
|
@@ -249,6 +252,12 @@ class Params:
|
|
|
249
252
|
return False
|
|
250
253
|
return hash(self) == hash(other)
|
|
251
254
|
|
|
255
|
+
def with_updates(self, **kwargs: Any) -> DataClass:
|
|
256
|
+
"""Return a new instance with updated fields."""
|
|
257
|
+
dict_ = self.to_dict()
|
|
258
|
+
dict_.update(kwargs)
|
|
259
|
+
return type(self)(**dict_)
|
|
260
|
+
|
|
252
261
|
|
|
253
262
|
@dataclass(slots=True)
|
|
254
263
|
class DataClass:
|
|
@@ -296,11 +305,13 @@ class DataClass:
|
|
|
296
305
|
for k in self.allowed():
|
|
297
306
|
_validate_strict(k)
|
|
298
307
|
|
|
299
|
-
def to_dict(self) -> dict[str, str]:
|
|
308
|
+
def to_dict(self, exclude: set[str] = None) -> dict[str, str]:
|
|
300
309
|
data = {}
|
|
301
|
-
|
|
310
|
+
exclude = exclude or set()
|
|
302
311
|
for k in type(self).allowed():
|
|
303
|
-
if not self._is_sentinel(
|
|
312
|
+
if k not in exclude and not self._is_sentinel(
|
|
313
|
+
v := getattr(self, k)
|
|
314
|
+
):
|
|
304
315
|
data[k] = v
|
|
305
316
|
return data
|
|
306
317
|
|
|
@@ -311,6 +322,22 @@ class DataClass:
|
|
|
311
322
|
return True
|
|
312
323
|
return is_sentinel(value)
|
|
313
324
|
|
|
325
|
+
def with_updates(self, **kwargs: Any) -> DataClass:
|
|
326
|
+
"""Return a new instance with updated fields."""
|
|
327
|
+
dict_ = self.to_dict()
|
|
328
|
+
dict_.update(kwargs)
|
|
329
|
+
return type(self)(**dict_)
|
|
330
|
+
|
|
331
|
+
def __hash__(self) -> int:
|
|
332
|
+
from ._hash import hash_dict
|
|
333
|
+
|
|
334
|
+
return hash_dict(self.to_dict())
|
|
335
|
+
|
|
336
|
+
def __eq__(self, other: Any) -> bool:
|
|
337
|
+
if not isinstance(other, DataClass):
|
|
338
|
+
return False
|
|
339
|
+
return hash(self) == hash(other)
|
|
340
|
+
|
|
314
341
|
|
|
315
342
|
KeysLike = Sequence[str] | KeysDict
|
|
316
343
|
|
lionagi/models/field_model.py
CHANGED
|
@@ -84,7 +84,7 @@ class FieldModel(Params):
|
|
|
84
84
|
base_type: type[Any]
|
|
85
85
|
metadata: tuple[Meta, ...]
|
|
86
86
|
|
|
87
|
-
def __init__(self, **kwargs: Any) -> None:
|
|
87
|
+
def __init__(self, base_type: type[Any] = None, **kwargs: Any) -> None:
|
|
88
88
|
"""Initialize FieldModel with legacy compatibility.
|
|
89
89
|
|
|
90
90
|
Handles backward compatibility by converting old-style kwargs to the new
|
|
@@ -94,6 +94,8 @@ class FieldModel(Params):
|
|
|
94
94
|
**kwargs: Arbitrary keyword arguments, including legacy ones
|
|
95
95
|
"""
|
|
96
96
|
# Convert legacy kwargs to proper format
|
|
97
|
+
if base_type is not None:
|
|
98
|
+
kwargs["base_type"] = base_type
|
|
97
99
|
converted = self._convert_kwargs_to_params(**kwargs)
|
|
98
100
|
|
|
99
101
|
# Set fields directly and validate
|
|
@@ -513,6 +515,15 @@ class FieldModel(Params):
|
|
|
513
515
|
# These are FieldTemplate markers, don't pass to FieldInfo
|
|
514
516
|
pass
|
|
515
517
|
else:
|
|
518
|
+
# Filter out unserializable objects from json_schema_extra
|
|
519
|
+
# to avoid Pydantic serialization errors when generating JSON schema
|
|
520
|
+
from pydantic import BaseModel
|
|
521
|
+
|
|
522
|
+
# Skip model classes and other unserializable types
|
|
523
|
+
if isinstance(meta.value, type):
|
|
524
|
+
# Skip type objects (including model classes) - they can't be serialized
|
|
525
|
+
continue
|
|
526
|
+
|
|
516
527
|
# Any other metadata goes in json_schema_extra
|
|
517
528
|
if "json_schema_extra" not in field_kwargs:
|
|
518
529
|
field_kwargs["json_schema_extra"] = {}
|
|
@@ -529,7 +540,7 @@ class FieldModel(Params):
|
|
|
529
540
|
field_info = PydanticField(**field_kwargs)
|
|
530
541
|
|
|
531
542
|
# Set the annotation from base_type for backward compatibility
|
|
532
|
-
field_info.annotation = self.
|
|
543
|
+
field_info.annotation = self.annotation
|
|
533
544
|
|
|
534
545
|
return field_info
|
|
535
546
|
|
|
@@ -736,8 +747,14 @@ class FieldModel(Params):
|
|
|
736
747
|
|
|
737
748
|
@property
|
|
738
749
|
def annotation(self) -> type[Any]:
|
|
739
|
-
|
|
740
|
-
|
|
750
|
+
if self._is_sentinel(self.base_type):
|
|
751
|
+
return Any
|
|
752
|
+
t_ = self.base_type
|
|
753
|
+
if self.is_listable:
|
|
754
|
+
t_ = list[t_]
|
|
755
|
+
if self.is_nullable:
|
|
756
|
+
t_ = t_ | None
|
|
757
|
+
return t_
|
|
741
758
|
|
|
742
759
|
def to_dict(self) -> dict[str, Any]:
|
|
743
760
|
"""Convert field model to dictionary for backward compatibility.
|
lionagi/models/hashable_model.py
CHANGED
|
@@ -94,12 +94,11 @@ class HashableModel(BaseModel):
|
|
|
94
94
|
def _get_default_hashable_serializer():
|
|
95
95
|
global _DEFAULT_HASHABLE_SERIALIZER
|
|
96
96
|
if _DEFAULT_HASHABLE_SERIALIZER is None:
|
|
97
|
-
from lionagi.protocols.ids import Element
|
|
97
|
+
from lionagi.protocols.ids import Element
|
|
98
98
|
|
|
99
99
|
_DEFAULT_HASHABLE_SERIALIZER = ln.get_orjson_default(
|
|
100
|
-
order=[
|
|
100
|
+
order=[Element, BaseModel],
|
|
101
101
|
additional={
|
|
102
|
-
IDType: lambda o: str(o),
|
|
103
102
|
Element: lambda o: o.to_dict(),
|
|
104
103
|
BaseModel: lambda o: o.model_dump(mode="json"),
|
|
105
104
|
},
|