lionagi 0.17.11__py3-none-any.whl → 0.18.0__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/libs/schema/minimal_yaml.py +98 -0
- lionagi/ln/types.py +32 -5
- lionagi/models/field_model.py +9 -0
- lionagi/operations/ReAct/ReAct.py +474 -237
- lionagi/operations/ReAct/utils.py +3 -0
- lionagi/operations/act/act.py +206 -0
- lionagi/operations/chat/chat.py +130 -114
- lionagi/operations/communicate/communicate.py +101 -42
- lionagi/operations/flow.py +4 -4
- lionagi/operations/interpret/interpret.py +65 -20
- lionagi/operations/operate/operate.py +212 -106
- lionagi/operations/parse/parse.py +170 -142
- lionagi/operations/select/select.py +78 -17
- lionagi/operations/select/utils.py +1 -1
- lionagi/operations/types.py +119 -23
- lionagi/protocols/generic/log.py +3 -2
- lionagi/protocols/messages/__init__.py +27 -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 +26 -18
- lionagi/protocols/messages/instruction.py +281 -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 +0 -2
- lionagi/service/connections/endpoint.py +0 -8
- lionagi/service/connections/providers/oai_.py +29 -94
- lionagi/service/connections/providers/ollama_.py +3 -2
- lionagi/service/hooks/hooked_event.py +2 -2
- lionagi/service/third_party/claude_code.py +3 -2
- lionagi/service/third_party/openai_models.py +433 -0
- lionagi/session/branch.py +170 -178
- lionagi/session/session.py +3 -9
- lionagi/tools/file/reader.py +2 -2
- lionagi/version.py +1 -1
- {lionagi-0.17.11.dist-info → lionagi-0.18.0.dist-info}/METADATA +1 -2
- {lionagi-0.17.11.dist-info → lionagi-0.18.0.dist-info}/RECORD +41 -49
- lionagi/operations/_act/act.py +0 -86
- 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/service/connections/providers/types.py +0 -28
- lionagi/service/third_party/openai_model_names.py +0 -198
- lionagi/service/types.py +0 -58
- /lionagi/operations/{_act → act}/__init__.py +0 -0
- {lionagi-0.17.11.dist-info → lionagi-0.18.0.dist-info}/WHEEL +0 -0
- {lionagi-0.17.11.dist-info → lionagi-0.18.0.dist-info}/licenses/LICENSE +0 -0
@@ -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/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
@@ -513,6 +513,15 @@ class FieldModel(Params):
|
|
513
513
|
# These are FieldTemplate markers, don't pass to FieldInfo
|
514
514
|
pass
|
515
515
|
else:
|
516
|
+
# Filter out unserializable objects from json_schema_extra
|
517
|
+
# to avoid Pydantic serialization errors when generating JSON schema
|
518
|
+
from pydantic import BaseModel
|
519
|
+
|
520
|
+
# Skip model classes and other unserializable types
|
521
|
+
if isinstance(meta.value, type):
|
522
|
+
# Skip type objects (including model classes) - they can't be serialized
|
523
|
+
continue
|
524
|
+
|
516
525
|
# Any other metadata goes in json_schema_extra
|
517
526
|
if "json_schema_extra" not in field_kwargs:
|
518
527
|
field_kwargs["json_schema_extra"] = {}
|