lionagi 0.16.0__py3-none-any.whl → 0.16.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.
Files changed (54) hide show
  1. lionagi/adapters/async_postgres_adapter.py +1 -1
  2. lionagi/libs/file/save.py +8 -1
  3. lionagi/libs/nested/ninsert.py +3 -6
  4. lionagi/libs/nested/nmerge.py +1 -2
  5. lionagi/ln/__init__.py +6 -0
  6. lionagi/ln/_json_dump.py +322 -49
  7. lionagi/models/note.py +8 -4
  8. lionagi/operations/ReAct/utils.py +1 -2
  9. lionagi/operations/brainstorm/brainstorm.py +10 -10
  10. lionagi/protocols/action/function_calling.py +1 -4
  11. lionagi/protocols/generic/element.py +6 -72
  12. lionagi/protocols/generic/log.py +2 -2
  13. lionagi/protocols/graph/graph.py +1 -2
  14. lionagi/protocols/graph/node.py +2 -4
  15. lionagi/protocols/messages/instruction.py +1 -2
  16. lionagi/protocols/messages/manager.py +1 -2
  17. lionagi/protocols/messages/message.py +9 -5
  18. lionagi/service/connections/endpoint.py +7 -0
  19. lionagi/service/connections/providers/claude_code_.py +7 -3
  20. lionagi/service/resilience.py +1 -2
  21. lionagi/session/branch.py +1 -101
  22. lionagi/session/session.py +9 -14
  23. lionagi/utils.py +2 -1
  24. lionagi/version.py +1 -1
  25. {lionagi-0.16.0.dist-info → lionagi-0.16.2.dist-info}/METADATA +3 -4
  26. {lionagi-0.16.0.dist-info → lionagi-0.16.2.dist-info}/RECORD +28 -54
  27. lionagi/libs/file/params.py +0 -175
  28. lionagi/libs/token_transform/__init__.py +0 -0
  29. lionagi/libs/token_transform/base.py +0 -54
  30. lionagi/libs/token_transform/llmlingua.py +0 -1
  31. lionagi/libs/token_transform/perplexity.py +0 -450
  32. lionagi/libs/token_transform/symbolic_compress_context.py +0 -152
  33. lionagi/libs/token_transform/synthlang.py +0 -9
  34. lionagi/libs/token_transform/synthlang_/base.py +0 -128
  35. lionagi/libs/token_transform/synthlang_/resources/frameworks/abstract_algebra.toml +0 -11
  36. lionagi/libs/token_transform/synthlang_/resources/frameworks/category_theory.toml +0 -11
  37. lionagi/libs/token_transform/synthlang_/resources/frameworks/complex_analysis.toml +0 -11
  38. lionagi/libs/token_transform/synthlang_/resources/frameworks/framework_options.json +0 -52
  39. lionagi/libs/token_transform/synthlang_/resources/frameworks/group_theory.toml +0 -11
  40. lionagi/libs/token_transform/synthlang_/resources/frameworks/math_logic.toml +0 -11
  41. lionagi/libs/token_transform/synthlang_/resources/frameworks/reflective_patterns.toml +0 -11
  42. lionagi/libs/token_transform/synthlang_/resources/frameworks/set_theory.toml +0 -11
  43. lionagi/libs/token_transform/synthlang_/resources/frameworks/topology_fundamentals.toml +0 -11
  44. lionagi/libs/token_transform/synthlang_/resources/mapping/lion_emoji_mapping.toml +0 -61
  45. lionagi/libs/token_transform/synthlang_/resources/mapping/python_math_mapping.toml +0 -41
  46. lionagi/libs/token_transform/synthlang_/resources/mapping/rust_chinese_mapping.toml +0 -60
  47. lionagi/libs/token_transform/synthlang_/resources/utility/base_synthlang_system_prompt.toml +0 -11
  48. lionagi/libs/token_transform/synthlang_/translate_to_synthlang.py +0 -140
  49. lionagi/libs/token_transform/types.py +0 -15
  50. lionagi/operations/translate/__init__.py +0 -0
  51. lionagi/operations/translate/translate.py +0 -47
  52. lionagi/tools/memory/tools.py +0 -497
  53. {lionagi-0.16.0.dist-info → lionagi-0.16.2.dist-info}/WHEEL +0 -0
  54. {lionagi-0.16.0.dist-info → lionagi-0.16.2.dist-info}/licenses/LICENSE +0 -0
@@ -313,27 +313,16 @@ class Element(BaseModel, Observable):
313
313
  if mode == "db":
314
314
  dict_ = orjson.loads(self.to_json(decode=False))
315
315
  dict_["node_metadata"] = dict_.pop("metadata", {})
316
- dict_["created_at"] = self.created_datetime.isoformat(sep=" ")
317
316
  return dict_
318
317
 
319
- def as_jsonable(self) -> dict:
320
- """Converts this Element to a JSON-serializable dictionary."""
321
- return self.to_dict(mode="json")
322
-
323
318
  @classmethod
324
- def from_dict(cls, data: dict, /, mode: str = "python") -> Element:
319
+ def from_dict(cls, data: dict) -> Element:
325
320
  """Deserializes a dictionary into an Element or subclass of Element.
326
321
 
327
322
  If `lion_class` in `metadata` refers to a subclass, this method
328
323
  is polymorphic, it will attempt to create an instance of that subclass.
329
-
330
- Args:
331
- data (dict): A dictionary of field data.
332
- mode (str): Format mode - "python" for normal dicts, "db" for database format.
333
324
  """
334
325
  # Preprocess database format if needed
335
- if mode == "db":
336
- data = cls._preprocess_db_data(data.copy())
337
326
  metadata = {}
338
327
 
339
328
  if "node_metadata" in data:
@@ -367,72 +356,17 @@ class Element(BaseModel, Observable):
367
356
  data["metadata"] = metadata
368
357
  return cls.model_validate(data)
369
358
 
370
- @classmethod
371
- def _preprocess_db_data(cls, data: dict) -> dict:
372
- """Preprocess raw database data for Element compatibility."""
373
- import datetime as dt
374
- import json
375
-
376
- # Handle created_at field - convert datetime string to timestamp
377
- if "created_at" in data and isinstance(data["created_at"], str):
378
- try:
379
- # Parse datetime string and convert to timestamp
380
- dt_obj = dt.datetime.fromisoformat(
381
- data["created_at"].replace(" ", "T")
382
- )
383
- # Treat as UTC if naive
384
- if dt_obj.tzinfo is None:
385
- dt_obj = dt_obj.replace(tzinfo=dt.timezone.utc)
386
- data["created_at"] = dt_obj.timestamp()
387
- except (ValueError, TypeError):
388
- # Keep as string if parsing fails
389
- pass
390
-
391
- # Handle JSON string fields - parse to dict/list
392
- json_fields = ["content", "node_metadata", "embedding"]
393
- for field in json_fields:
394
- if field in data and isinstance(data[field], str):
395
- if data[field] in ("null", ""):
396
- data[field] = None if field == "embedding" else {}
397
- else:
398
- try:
399
- data[field] = json.loads(data[field])
400
- except (json.JSONDecodeError, TypeError):
401
- # Keep as empty dict for metadata fields, None for embedding
402
- data[field] = {} if field != "embedding" else None
403
-
404
- # Handle node_metadata -> metadata mapping
405
- if "node_metadata" in data:
406
- if (
407
- data["node_metadata"] == "null"
408
- or data["node_metadata"] is None
409
- ):
410
- data["metadata"] = {}
411
- else:
412
- data["metadata"] = (
413
- data["node_metadata"] if data["node_metadata"] else {}
414
- )
415
- # Remove node_metadata to avoid Pydantic validation error
416
- data.pop("node_metadata", None)
417
-
418
- return data
419
-
420
359
  def to_json(self, decode: bool = True) -> str:
421
360
  """Converts this Element to a JSON string."""
422
361
  dict_ = self._to_dict()
423
- if decode:
424
- return orjson.dumps(
425
- dict_,
426
- default=DEFAULT_ELEMENT_SERIALIZER,
427
- option=ln.DEFAULT_SERIALIZER_OPTION,
428
- ).decode()
429
- return orjson.dumps(dict_, default=DEFAULT_ELEMENT_SERIALIZER)
362
+ return ln.json_dumps(
363
+ dict_, default=DEFAULT_ELEMENT_SERIALIZER, decode=decode
364
+ )
430
365
 
431
366
  @classmethod
432
- def from_json(cls, json_str: str, mode: str = "python") -> Element:
367
+ def from_json(cls, json_str: str) -> Element:
433
368
  """Deserializes a JSON string into an Element or subclass of Element."""
434
- data = orjson.loads(json_str)
435
- return cls.from_dict(data, mode=mode)
369
+ return cls.from_dict(orjson.loads(json_str))
436
370
 
437
371
 
438
372
  DEFAULT_ELEMENT_SERIALIZER = ln.get_orjson_default(
@@ -176,9 +176,9 @@ class DataLogger:
176
176
  suffix = fp.suffix.lower()
177
177
  try:
178
178
  if suffix == ".csv":
179
- self.logs.to_csv_file(fp)
179
+ self.logs.dump(fp, "csv")
180
180
  elif suffix == ".json":
181
- self.logs.to_json_file(fp)
181
+ self.logs.dump(fp, "json")
182
182
  else:
183
183
  raise ValueError(f"Unsupported file extension: {suffix}")
184
184
 
@@ -87,8 +87,7 @@ class Graph(Element, Relational, Generic[T]):
87
87
  or edge.tail not in self.internal_nodes
88
88
  ):
89
89
  raise RelationError(
90
- "Failed to add edge: Either edge head or tail node does"
91
- " not exist in the graph."
90
+ "Failed to add edge: Either edge head or tail node does not exist in the graph."
92
91
  )
93
92
  try:
94
93
  self.internal_edges.insert(len(self.internal_edges), edge)
@@ -63,7 +63,7 @@ class Node(Element, Relational, AsyncAdaptable, Adaptable):
63
63
  self, obj_key: str, many=False, **kwargs: Any
64
64
  ) -> Any:
65
65
  kwargs["adapt_meth"] = "to_dict"
66
- kwargs["mode"] = "db"
66
+ kwargs["adapt_kw"] = {"mode": "db"}
67
67
  return await super().adapt_to_async(
68
68
  obj_key=obj_key, many=many, **kwargs
69
69
  )
@@ -77,7 +77,6 @@ class Node(Element, Relational, AsyncAdaptable, Adaptable):
77
77
  **kwargs: Any,
78
78
  ) -> Node:
79
79
  kwargs["adapt_meth"] = "from_dict"
80
- kwargs["mode"] = "db"
81
80
  return await super().adapt_from_async(
82
81
  obj, obj_key=obj_key, many=many, **kwargs
83
82
  )
@@ -87,7 +86,7 @@ class Node(Element, Relational, AsyncAdaptable, Adaptable):
87
86
  Convert this Node to another format using a registered adapter.
88
87
  """
89
88
  kwargs["adapt_meth"] = "to_dict"
90
- kwargs["mode"] = "db"
89
+ kwargs["adapt_kw"] = {"mode": "db"}
91
90
  return super().adapt_to(obj_key=obj_key, many=many, **kwargs)
92
91
 
93
92
  @classmethod
@@ -104,7 +103,6 @@ class Node(Element, Relational, AsyncAdaptable, Adaptable):
104
103
  auto-delegate to the correct subclass via from_dict.
105
104
  """
106
105
  kwargs["adapt_meth"] = "from_dict"
107
- kwargs["mode"] = "db"
108
106
  return super().adapt_from(obj, obj_key=obj_key, many=many, **kwargs)
109
107
 
110
108
  @field_serializer("content")
@@ -587,8 +587,7 @@ class Instruction(RoledMessage):
587
587
 
588
588
  if request_model and request_fields:
589
589
  raise ValueError(
590
- "You cannot pass both request_model and request_fields "
591
- "to create_instruction"
590
+ "You cannot pass both request_model and request_fields to create_instruction"
592
591
  )
593
592
  if guidance:
594
593
  self.guidance = guidance
@@ -216,8 +216,7 @@ class MessageManager(Manager):
216
216
  """
217
217
  if not isinstance(action_request, ActionRequest):
218
218
  raise ValueError(
219
- "Error: please provide a corresponding action request for an "
220
- "action response."
219
+ "Error: please provide a corresponding action request for an action response."
221
220
  )
222
221
  params = {
223
222
  "action_request": action_request,
@@ -116,7 +116,14 @@ class RoledMessage(Node, Sendable):
116
116
  if isinstance(self.template, Template):
117
117
  return self.template.render(**self.content)
118
118
  except Exception:
119
- return ln.json_dumps(self.content)
119
+ return ln.json_dumps(
120
+ self.content,
121
+ pretty=True,
122
+ sort_keys=True,
123
+ append_newline=True,
124
+ deterministic_sets=True,
125
+ decimal_as_float=True,
126
+ )
120
127
 
121
128
  @classmethod
122
129
  def create(cls, **kwargs):
@@ -241,10 +248,7 @@ class RoledMessage(Node, Sendable):
241
248
  if len(str(self.content)) > 75
242
249
  else str(self.content)
243
250
  )
244
- return (
245
- f"Message(role={self.role}, sender={self.sender}, "
246
- f"content='{content_preview}')"
247
- )
251
+ return f"Message(role={self.role}, sender={self.sender}, content='{content_preview}')"
248
252
 
249
253
 
250
254
  # File: lionagi/protocols/messages/message.py
@@ -150,6 +150,13 @@ class Endpoint:
150
150
  "branch",
151
151
  "aggregation_sources",
152
152
  "aggregation_count",
153
+ "action_strategy",
154
+ "parse_model",
155
+ "reason",
156
+ "actions",
157
+ "return_operative",
158
+ "operative_model",
159
+ "request_model",
153
160
  }
154
161
  payload = {
155
162
  k: v for k, v in payload.items() if k not in non_api_params
@@ -56,8 +56,7 @@ class ClaudeCodeEndpoint(Endpoint):
56
56
  "Please install it with `uv pip install lionagi[claude_code_sdk]`."
57
57
  )
58
58
  warnings.warn(
59
- "The claude_code `query` endpoint is deprecated. "
60
- "Use `query_cli` endpoint instead.",
59
+ "The claude_code `query` endpoint is deprecated. Use `query_cli` endpoint instead.",
61
60
  DeprecationWarning,
62
61
  )
63
62
 
@@ -267,7 +266,12 @@ def _verbose_output(res) -> str:
267
266
  inp_ = None
268
267
 
269
268
  if isinstance(block.input, dict | list):
270
- inp_ = ln.json_dumps(block.input)
269
+ inp_ = ln.json_dumps(
270
+ block.input,
271
+ pretty=True,
272
+ sort_keys=True,
273
+ append_newline=True,
274
+ )
271
275
  else:
272
276
  inp_ = str(block.input)
273
277
 
@@ -216,8 +216,7 @@ class CircuitBreaker:
216
216
  self._metrics["rejected_count"] += 1
217
217
 
218
218
  logger.warning(
219
- f"Circuit '{self.name}' is HALF_OPEN and at capacity. "
220
- f"Try again later."
219
+ f"Circuit '{self.name}' is HALF_OPEN and at capacity. Try again later."
221
220
  )
222
221
 
223
222
  return False
lionagi/session/branch.py CHANGED
@@ -50,7 +50,7 @@ from lionagi.settings import Settings
50
50
  from lionagi.tools.base import LionTool
51
51
  from lionagi.utils import UNDEFINED
52
52
  from lionagi.utils import alcall as alcall_legacy
53
- from lionagi.utils import copy, is_coro_func
53
+ from lionagi.utils import copy
54
54
 
55
55
  from .prompts import LION_SYSTEM_MESSAGE
56
56
 
@@ -1307,68 +1307,6 @@ class Branch(Element, Communicatable, Relational):
1307
1307
  )
1308
1308
  return results
1309
1309
 
1310
- async def translate(
1311
- self,
1312
- text: str,
1313
- technique: Literal["SynthLang"] = "SynthLang",
1314
- technique_kwargs: dict = None,
1315
- compress: bool = False,
1316
- chat_model: iModel = None,
1317
- compress_model: iModel = None,
1318
- compression_ratio: float = 0.2,
1319
- compress_kwargs=None,
1320
- verbose: bool = True,
1321
- new_branch: bool = True,
1322
- **kwargs,
1323
- ) -> str:
1324
- """
1325
- An example "translate" operation that transforms text using a chosen technique
1326
- (e.g., "SynthLang"). Optionally compresses text with a custom `compress_model`.
1327
-
1328
- Args:
1329
- text (str):
1330
- The text to be translated or transformed.
1331
- technique (Literal["SynthLang"]):
1332
- The translation/transform technique (currently only "SynthLang").
1333
- technique_kwargs (dict, optional):
1334
- Additional parameters for the chosen technique.
1335
- compress (bool):
1336
- Whether to compress the resulting text further.
1337
- chat_model (iModel, optional):
1338
- A custom model for the translation step (defaults to self.chat_model).
1339
- compress_model (iModel, optional):
1340
- A separate model for compression (if `compress=True`).
1341
- compression_ratio (float):
1342
- Desired compression ratio if compressing text (0.0 - 1.0).
1343
- compress_kwargs (dict, optional):
1344
- Additional arguments for the compression step.
1345
- verbose (bool):
1346
- If True, prints debug/logging info.
1347
- new_branch (bool):
1348
- If True, performs the translation in a new branch context.
1349
- **kwargs:
1350
- Additional parameters passed through to the technique function.
1351
-
1352
- Returns:
1353
- str: The transformed (and optionally compressed) text.
1354
- """
1355
- from lionagi.operations.translate.translate import translate
1356
-
1357
- return await translate(
1358
- branch=self,
1359
- text=text,
1360
- technique=technique,
1361
- technique_kwargs=technique_kwargs,
1362
- compress=compress,
1363
- chat_model=chat_model,
1364
- compress_model=compress_model,
1365
- compression_ratio=compression_ratio,
1366
- compress_kwargs=compress_kwargs,
1367
- verbose=verbose,
1368
- new_branch=new_branch,
1369
- **kwargs,
1370
- )
1371
-
1372
1310
  async def select(
1373
1311
  self,
1374
1312
  instruct: Instruct | dict[str, Any],
@@ -1411,44 +1349,6 @@ class Branch(Element, Communicatable, Relational):
1411
1349
  **kwargs,
1412
1350
  )
1413
1351
 
1414
- async def compress(
1415
- self,
1416
- text: str,
1417
- system: str = None,
1418
- compression_ratio: float = 0.2,
1419
- n_samples: int = 5,
1420
- max_tokens_per_sample=80,
1421
- verbose=True,
1422
- ) -> str:
1423
- """
1424
- Uses the `chat_model`'s built-in compression routine to shorten text.
1425
-
1426
- Args:
1427
- text (str):
1428
- The text to compress.
1429
- system (str, optional):
1430
- System-level instructions, appended to the prompt.
1431
- compression_ratio (float):
1432
- Desired compression ratio (0.0-1.0).
1433
- n_samples (int):
1434
- How many compression attempts to combine or evaluate.
1435
- max_tokens_per_sample (int):
1436
- Max token count per sample chunk.
1437
- verbose (bool):
1438
- If True, logs or prints progress.
1439
-
1440
- Returns:
1441
- str: The compressed text.
1442
- """
1443
- return await self.chat_model.compress_text(
1444
- text=text,
1445
- system=system,
1446
- compression_ratio=compression_ratio,
1447
- n_samples=n_samples,
1448
- max_tokens_per_sample=max_tokens_per_sample,
1449
- verbose=verbose,
1450
- )
1451
-
1452
1352
  async def interpret(
1453
1353
  self,
1454
1354
  text: str,
@@ -79,7 +79,7 @@ class Session(Node, Communicatable, Relational):
79
79
 
80
80
  def include_branches(self, branches: ID[Branch].ItemSeq):
81
81
  def _take_in_branch(branch: Branch):
82
- if not branch in self.branches:
82
+ if branch not in self.branches:
83
83
  self.branches.include(branch)
84
84
  self.mail_manager.add_sources(branch)
85
85
 
@@ -171,19 +171,14 @@ class Session(Node, Communicatable, Relational):
171
171
  as_default_branch: bool = False,
172
172
  **kwargs,
173
173
  ) -> Branch:
174
- kwargs["system"] = system
175
- kwargs["system_sender"] = system_sender
176
- kwargs["system_datetime"] = system_datetime
177
- kwargs["user"] = user
178
- kwargs["name"] = name
179
- kwargs["imodel"] = imodel
180
- kwargs["messages"] = messages
181
- kwargs["progress"] = progress
182
- kwargs["tool_manager"] = tool_manager
183
- kwargs["tools"] = tools
184
- kwargs = {k: v for k, v in kwargs.items() if v is not None}
185
-
186
- branch = Branch(**kwargs) # type: ignore
174
+ """Create and include a new branch in the session."""
175
+ params = {
176
+ k: v
177
+ for k, v in locals().items()
178
+ if k not in ("self", "as_default_branch", "kwargs")
179
+ and v is not None
180
+ }
181
+ branch = Branch(**params, **kwargs) # type: ignore
187
182
  self.include_branches(branch)
188
183
  if as_default_branch:
189
184
  self.default_branch = branch
lionagi/utils.py CHANGED
@@ -35,7 +35,6 @@ from pydantic import BaseModel
35
35
  from pydantic_core import PydanticUndefinedType
36
36
  from typing_extensions import deprecated
37
37
 
38
- from .libs.validate.xml_parser import xml_to_dict
39
38
  from .ln import (
40
39
  extract_json,
41
40
  fuzzy_json,
@@ -746,6 +745,8 @@ def _str_to_dict(
746
745
  """
747
746
  if not parser:
748
747
  if str_type == "xml" and not parser:
748
+ from .libs.validate.xml_parser import xml_to_dict
749
+
749
750
  parser = partial(
750
751
  xml_to_dict, remove_root=remove_root, root_tag=root_tag
751
752
  )
lionagi/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.16.0"
1
+ __version__ = "0.16.2"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lionagi
3
- Version: 0.16.0
3
+ Version: 0.16.2
4
4
  Summary: An Intelligence Operating System.
5
5
  Author-email: HaiyangLi <quantocean.li@gmail.com>
6
6
  License: Apache License
@@ -223,17 +223,16 @@ Requires-Dist: aiocache>=0.12.0
223
223
  Requires-Dist: aiohttp>=3.11.0
224
224
  Requires-Dist: anyio>=4.7.0
225
225
  Requires-Dist: backoff>=2.0.0
226
- Requires-Dist: exceptiongroup>=1.3.0
227
226
  Requires-Dist: jinja2>=3.0.0
228
227
  Requires-Dist: json-repair>=0.40.0
229
228
  Requires-Dist: msgspec>=0.18.0
230
229
  Requires-Dist: pillow>=10.0.0
231
230
  Requires-Dist: psutil>=6.0.0
232
231
  Requires-Dist: pydantic-settings>=2.8.0
233
- Requires-Dist: pydapter[pandas]>=1.0.5
232
+ Requires-Dist: pydantic>=2.8.0
233
+ Requires-Dist: pydapter[pandas]>=1.1.1
234
234
  Requires-Dist: python-dotenv>=1.1.0
235
235
  Requires-Dist: tiktoken>=0.9.0
236
- Requires-Dist: toml>=0.8.0
237
236
  Provides-Extra: all
238
237
  Requires-Dist: aiosqlite>=0.21.0; extra == 'all'
239
238
  Requires-Dist: claude-code-sdk>=0.0.15; extra == 'all'