lionagi 0.16.2__py3-none-any.whl → 0.17.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.
Files changed (63) hide show
  1. lionagi/adapters/_utils.py +10 -23
  2. lionagi/adapters/async_postgres_adapter.py +83 -79
  3. lionagi/ln/__init__.py +4 -4
  4. lionagi/ln/_json_dump.py +0 -6
  5. lionagi/ln/fuzzy/__init__.py +4 -1
  6. lionagi/ln/fuzzy/_fuzzy_validate.py +109 -0
  7. lionagi/ln/fuzzy/_to_dict.py +388 -0
  8. lionagi/models/__init__.py +0 -2
  9. lionagi/operations/__init__.py +0 -6
  10. lionagi/operations/_visualize_graph.py +285 -0
  11. lionagi/operations/brainstorm/brainstorm.py +14 -12
  12. lionagi/operations/builder.py +23 -302
  13. lionagi/operations/communicate/communicate.py +1 -1
  14. lionagi/operations/flow.py +14 -11
  15. lionagi/operations/node.py +14 -3
  16. lionagi/operations/operate/operate.py +5 -11
  17. lionagi/operations/parse/parse.py +2 -3
  18. lionagi/operations/types.py +0 -2
  19. lionagi/operations/utils.py +11 -5
  20. lionagi/protocols/generic/pile.py +3 -7
  21. lionagi/protocols/graph/graph.py +23 -6
  22. lionagi/protocols/graph/node.py +0 -2
  23. lionagi/protocols/messages/message.py +0 -1
  24. lionagi/protocols/operatives/operative.py +2 -2
  25. lionagi/protocols/types.py +0 -15
  26. lionagi/service/connections/endpoint.py +11 -5
  27. lionagi/service/connections/match_endpoint.py +2 -10
  28. lionagi/service/connections/providers/types.py +1 -3
  29. lionagi/service/hooks/hook_event.py +1 -1
  30. lionagi/service/hooks/hook_registry.py +1 -1
  31. lionagi/service/rate_limited_processor.py +1 -1
  32. lionagi/session/branch.py +24 -18
  33. lionagi/session/session.py +2 -18
  34. lionagi/utils.py +3 -335
  35. lionagi/version.py +1 -1
  36. {lionagi-0.16.2.dist-info → lionagi-0.17.0.dist-info}/METADATA +4 -13
  37. {lionagi-0.16.2.dist-info → lionagi-0.17.0.dist-info}/RECORD +39 -61
  38. lionagi/adapters/postgres_model_adapter.py +0 -131
  39. lionagi/libs/concurrency.py +0 -1
  40. lionagi/libs/nested/__init__.py +0 -3
  41. lionagi/libs/nested/flatten.py +0 -172
  42. lionagi/libs/nested/nfilter.py +0 -59
  43. lionagi/libs/nested/nget.py +0 -45
  44. lionagi/libs/nested/ninsert.py +0 -104
  45. lionagi/libs/nested/nmerge.py +0 -158
  46. lionagi/libs/nested/npop.py +0 -69
  47. lionagi/libs/nested/nset.py +0 -94
  48. lionagi/libs/nested/unflatten.py +0 -83
  49. lionagi/libs/nested/utils.py +0 -189
  50. lionagi/libs/parse.py +0 -31
  51. lionagi/libs/schema/json_schema.py +0 -231
  52. lionagi/libs/unstructured/__init__.py +0 -0
  53. lionagi/libs/unstructured/pdf_to_image.py +0 -45
  54. lionagi/libs/unstructured/read_image_to_base64.py +0 -33
  55. lionagi/libs/validate/fuzzy_match_keys.py +0 -7
  56. lionagi/libs/validate/fuzzy_validate_mapping.py +0 -144
  57. lionagi/libs/validate/string_similarity.py +0 -7
  58. lionagi/libs/validate/xml_parser.py +0 -203
  59. lionagi/models/note.py +0 -387
  60. lionagi/protocols/graph/_utils.py +0 -22
  61. lionagi/service/connections/providers/claude_code_.py +0 -299
  62. {lionagi-0.16.2.dist-info → lionagi-0.17.0.dist-info}/WHEEL +0 -0
  63. {lionagi-0.16.2.dist-info → lionagi-0.17.0.dist-info}/licenses/LICENSE +0 -0
lionagi/utils.py CHANGED
@@ -2,23 +2,12 @@
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
- import contextlib
6
5
  import copy as _copy
7
- import dataclasses
8
- import json
9
6
  import logging
10
7
  import types
11
8
  import uuid
12
- from collections.abc import (
13
- AsyncGenerator,
14
- Callable,
15
- Iterable,
16
- Mapping,
17
- Sequence,
18
- )
9
+ from collections.abc import AsyncGenerator, Callable, Iterable, Mapping
19
10
  from datetime import datetime, timezone
20
- from enum import Enum as _Enum
21
- from functools import partial
22
11
  from inspect import isclass
23
12
  from pathlib import Path
24
13
  from typing import (
@@ -32,7 +21,6 @@ from typing import (
32
21
  )
33
22
 
34
23
  from pydantic import BaseModel
35
- from pydantic_core import PydanticUndefinedType
36
24
  from typing_extensions import deprecated
37
25
 
38
26
  from .ln import (
@@ -43,6 +31,7 @@ from .ln import (
43
31
  import_module,
44
32
  is_coro_func,
45
33
  is_import_installed,
34
+ to_dict,
46
35
  to_list,
47
36
  )
48
37
  from .ln.types import (
@@ -113,6 +102,7 @@ __all__ = (
113
102
  "MaybeUnset",
114
103
  "is_import_installed",
115
104
  "import_module",
105
+ "to_dict",
116
106
  )
117
107
 
118
108
 
@@ -531,328 +521,6 @@ def create_path(
531
521
  return full_path
532
522
 
533
523
 
534
- def to_dict(
535
- input_: Any,
536
- /,
537
- *,
538
- use_model_dump: bool = True,
539
- fuzzy_parse: bool = False,
540
- suppress: bool = False,
541
- str_type: Literal["json", "xml"] | None = "json",
542
- parser: Callable[[str], Any] | None = None,
543
- recursive: bool = False,
544
- max_recursive_depth: int = None,
545
- recursive_python_only: bool = True,
546
- use_enum_values: bool = False,
547
- **kwargs: Any,
548
- ) -> dict[str, Any]:
549
- """
550
- Convert various input types to a dictionary, with optional recursive processing.
551
-
552
- Args:
553
- input_: The input to convert.
554
- use_model_dump: Use model_dump() for Pydantic models if available.
555
- fuzzy_parse: Use fuzzy parsing for string inputs.
556
- suppress: Return empty dict on errors if True.
557
- str_type: Input string type ("json" or "xml").
558
- parser: Custom parser function for string inputs.
559
- recursive: Enable recursive conversion of nested structures.
560
- max_recursive_depth: Maximum recursion depth (default 5, max 10).
561
- recursive_python_only: If False, attempts to convert custom types recursively.
562
- use_enum_values: Use enum values instead of names.
563
- **kwargs: Additional arguments for parsing functions.
564
-
565
- Returns:
566
- dict[str, Any]: A dictionary derived from the input.
567
-
568
- Raises:
569
- ValueError: If parsing fails and suppress is False.
570
-
571
- Examples:
572
- >>> to_dict({"a": 1, "b": [2, 3]})
573
- {'a': 1, 'b': [2, 3]}
574
- >>> to_dict('{"x": 10}', str_type="json")
575
- {'x': 10}
576
- >>> to_dict({"a": {"b": {"c": 1}}}, recursive=True, max_recursive_depth=2)
577
- {'a': {'b': {'c': 1}}}
578
- """
579
-
580
- try:
581
- if recursive:
582
- input_ = recursive_to_dict(
583
- input_,
584
- use_model_dump=use_model_dump,
585
- fuzzy_parse=fuzzy_parse,
586
- str_type=str_type,
587
- parser=parser,
588
- max_recursive_depth=max_recursive_depth,
589
- recursive_custom_types=not recursive_python_only,
590
- use_enum_values=use_enum_values,
591
- **kwargs,
592
- )
593
-
594
- return _to_dict(
595
- input_,
596
- fuzzy_parse=fuzzy_parse,
597
- parser=parser,
598
- str_type=str_type,
599
- use_model_dump=use_model_dump,
600
- use_enum_values=use_enum_values,
601
- **kwargs,
602
- )
603
- except Exception as e:
604
- if suppress or input_ == "":
605
- return {}
606
- raise e
607
-
608
-
609
- def recursive_to_dict(
610
- input_: Any,
611
- /,
612
- *,
613
- max_recursive_depth: int = None,
614
- recursive_custom_types: bool = False,
615
- **kwargs: Any,
616
- ) -> Any:
617
- if not isinstance(max_recursive_depth, int):
618
- max_recursive_depth = 5
619
- else:
620
- if max_recursive_depth < 0:
621
- raise ValueError(
622
- "max_recursive_depth must be a non-negative integer"
623
- )
624
- if max_recursive_depth == 0:
625
- return input_
626
- if max_recursive_depth > 10:
627
- raise ValueError(
628
- "max_recursive_depth must be less than or equal to 10"
629
- )
630
-
631
- return _recur_to_dict(
632
- input_,
633
- max_recursive_depth=max_recursive_depth,
634
- current_depth=0,
635
- recursive_custom_types=recursive_custom_types,
636
- **kwargs,
637
- )
638
-
639
-
640
- def _recur_to_dict(
641
- input_: Any,
642
- /,
643
- *,
644
- max_recursive_depth: int,
645
- current_depth: int = 0,
646
- recursive_custom_types: bool = False,
647
- **kwargs: Any,
648
- ) -> Any:
649
- if current_depth >= max_recursive_depth:
650
- return input_
651
-
652
- if isinstance(input_, str):
653
- try:
654
- # Attempt to parse the string
655
- parsed = _to_dict(input_, **kwargs)
656
- # Recursively process the parsed result
657
- return _recur_to_dict(
658
- parsed,
659
- max_recursive_depth=max_recursive_depth,
660
- current_depth=current_depth + 1,
661
- recursive_custom_types=recursive_custom_types,
662
- **kwargs,
663
- )
664
- except Exception:
665
- # Return the original string if parsing fails
666
- return input_
667
-
668
- elif isinstance(input_, dict):
669
- # Recursively process dictionary values
670
- return {
671
- key: _recur_to_dict(
672
- value,
673
- max_recursive_depth=max_recursive_depth,
674
- current_depth=current_depth + 1,
675
- recursive_custom_types=recursive_custom_types,
676
- **kwargs,
677
- )
678
- for key, value in input_.items()
679
- }
680
-
681
- elif isinstance(input_, (list, tuple, set)):
682
- # Recursively process list or tuple elements
683
- processed = [
684
- _recur_to_dict(
685
- element,
686
- max_recursive_depth=max_recursive_depth,
687
- current_depth=current_depth + 1,
688
- recursive_custom_types=recursive_custom_types,
689
- **kwargs,
690
- )
691
- for element in input_
692
- ]
693
- return type(input_)(processed)
694
-
695
- elif isinstance(input_, type) and issubclass(input_, _Enum):
696
- try:
697
- obj_dict = _to_dict(input_, **kwargs)
698
- return _recur_to_dict(
699
- obj_dict,
700
- max_recursive_depth=max_recursive_depth,
701
- current_depth=current_depth + 1,
702
- **kwargs,
703
- )
704
- except Exception:
705
- return input_
706
-
707
- elif recursive_custom_types:
708
- # Process custom classes if enabled
709
- try:
710
- obj_dict = _to_dict(input_, **kwargs)
711
- return _recur_to_dict(
712
- obj_dict,
713
- max_recursive_depth=max_recursive_depth,
714
- current_depth=current_depth + 1,
715
- recursive_custom_types=recursive_custom_types,
716
- **kwargs,
717
- )
718
- except Exception:
719
- return input_
720
-
721
- else:
722
- # Return the input as is for other data types
723
- return input_
724
-
725
-
726
- def _enum_to_dict(input_, /, use_enum_values: bool = True):
727
- dict_ = dict(input_.__members__).copy()
728
- if use_enum_values:
729
- return {key: value.value for key, value in dict_.items()}
730
- return dict_
731
-
732
-
733
- def _str_to_dict(
734
- input_: str,
735
- /,
736
- fuzzy_parse: bool = False,
737
- str_type: Literal["json", "xml"] | None = "json",
738
- parser: Callable[[str], Any] | None = None,
739
- remove_root: bool = False,
740
- root_tag: str = "root",
741
- **kwargs: Any,
742
- ):
743
- """
744
- kwargs for parser
745
- """
746
- if not parser:
747
- if str_type == "xml" and not parser:
748
- from .libs.validate.xml_parser import xml_to_dict
749
-
750
- parser = partial(
751
- xml_to_dict, remove_root=remove_root, root_tag=root_tag
752
- )
753
-
754
- elif fuzzy_parse:
755
- parser = fuzzy_parse_json
756
- else:
757
- parser = json.loads
758
-
759
- return parser(input_, **kwargs)
760
-
761
-
762
- def _na_to_dict(input_: type[None] | UndefinedType | PydanticUndefinedType, /):
763
- return {}
764
-
765
-
766
- def _model_to_dict(input_: Any, /, use_model_dump=True, **kwargs):
767
- """
768
- kwargs: built-in serialization methods kwargs
769
- accepted built-in serialization methods:
770
- - mdoel_dump
771
- - to_dict
772
- - to_json
773
- - dict
774
- - json
775
- """
776
-
777
- if use_model_dump and hasattr(input_, "model_dump"):
778
- return input_.model_dump(**kwargs)
779
-
780
- methods = (
781
- "to_dict",
782
- "to_json",
783
- "json",
784
- "dict",
785
- )
786
- for method in methods:
787
- if hasattr(input_, method):
788
- result = getattr(input_, method)(**kwargs)
789
- return json.loads(result) if isinstance(result, str) else result
790
-
791
- if hasattr(input_, "__dict__"):
792
- return input_.__dict__
793
-
794
- try:
795
- return dict(input_)
796
- except Exception as e:
797
- raise ValueError(f"Unable to convert input to dictionary: {e}")
798
-
799
-
800
- def _set_to_dict(input_: set, /) -> dict:
801
- return {v: v for v in input_}
802
-
803
-
804
- def _iterable_to_dict(input_: Iterable, /) -> dict:
805
- return {idx: v for idx, v in enumerate(input_)}
806
-
807
-
808
- def _to_dict(
809
- input_: Any,
810
- /,
811
- *,
812
- fuzzy_parse: bool = False,
813
- str_type: Literal["json", "xml"] | None = "json",
814
- parser: Callable[[str], Any] | None = None,
815
- remove_root: bool = False,
816
- root_tag: str = "root",
817
- use_model_dump: bool = True,
818
- use_enum_values: bool = True,
819
- **kwargs: Any,
820
- ) -> dict[str, Any]:
821
- if isinstance(input_, set):
822
- return _set_to_dict(input_)
823
-
824
- if isinstance(input_, type) and issubclass(input_, _Enum):
825
- return _enum_to_dict(input_, use_enum_values=use_enum_values)
826
-
827
- if isinstance(input_, Mapping):
828
- return dict(input_)
829
-
830
- if isinstance(input_, type(None) | UndefinedType | PydanticUndefinedType):
831
- return _na_to_dict(input_)
832
-
833
- if isinstance(input_, str):
834
- return _str_to_dict(
835
- input_,
836
- fuzzy_parse=fuzzy_parse,
837
- str_type=str_type,
838
- parser=parser,
839
- remove_root=remove_root,
840
- root_tag=root_tag,
841
- **kwargs,
842
- )
843
-
844
- if isinstance(input_, BaseModel) or not isinstance(input_, Sequence):
845
- return _model_to_dict(input_, use_model_dump=use_model_dump, **kwargs)
846
-
847
- if isinstance(input_, Iterable):
848
- return _iterable_to_dict(input_)
849
-
850
- with contextlib.suppress(Exception):
851
- return dataclasses.asdict(input_)
852
-
853
- return dict(input_)
854
-
855
-
856
524
  def get_bins(input_: list[str], upper: int) -> list[list[int]]:
857
525
  """Organizes indices of strings into bins based on a cumulative upper limit.
858
526
 
lionagi/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.16.2"
1
+ __version__ = "0.17.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lionagi
3
- Version: 0.16.2
3
+ Version: 0.17.0
4
4
  Summary: An Intelligence Operating System.
5
5
  Author-email: HaiyangLi <quantocean.li@gmail.com>
6
6
  License: Apache License
@@ -226,16 +226,13 @@ Requires-Dist: backoff>=2.0.0
226
226
  Requires-Dist: jinja2>=3.0.0
227
227
  Requires-Dist: json-repair>=0.40.0
228
228
  Requires-Dist: msgspec>=0.18.0
229
- Requires-Dist: pillow>=10.0.0
230
- Requires-Dist: psutil>=6.0.0
231
229
  Requires-Dist: pydantic-settings>=2.8.0
232
230
  Requires-Dist: pydantic>=2.8.0
233
- Requires-Dist: pydapter[pandas]>=1.1.1
231
+ Requires-Dist: pydapter>=1.1.1
234
232
  Requires-Dist: python-dotenv>=1.1.0
235
233
  Requires-Dist: tiktoken>=0.9.0
236
234
  Provides-Extra: all
237
235
  Requires-Dist: aiosqlite>=0.21.0; extra == 'all'
238
- Requires-Dist: claude-code-sdk>=0.0.15; extra == 'all'
239
236
  Requires-Dist: datamodel-code-generator>=0.31.2; extra == 'all'
240
237
  Requires-Dist: docling>=2.15.0; extra == 'all'
241
238
  Requires-Dist: fastmcp>=2.10.5; extra == 'all'
@@ -244,8 +241,6 @@ Requires-Dist: networkx>=3.0.0; extra == 'all'
244
241
  Requires-Dist: ollama>=0.4.0; extra == 'all'
245
242
  Requires-Dist: pydapter[postgres]; extra == 'all'
246
243
  Requires-Dist: rich>=13.0.0; extra == 'all'
247
- Provides-Extra: claude-code
248
- Requires-Dist: claude-code-sdk>=0.0.15; extra == 'claude-code'
249
244
  Provides-Extra: graph
250
245
  Requires-Dist: matplotlib>=3.7.0; extra == 'graph'
251
246
  Requires-Dist: networkx>=3.0.0; extra == 'graph'
@@ -263,10 +258,6 @@ Provides-Extra: schema
263
258
  Requires-Dist: datamodel-code-generator>=0.31.2; extra == 'schema'
264
259
  Provides-Extra: sqlite
265
260
  Requires-Dist: aiosqlite>=0.21.0; extra == 'sqlite'
266
- Provides-Extra: tools
267
- Requires-Dist: docling>=2.15.0; extra == 'tools'
268
- Provides-Extra: unstructured
269
- Requires-Dist: opencv-python>=4.2.0.34; extra == 'unstructured'
270
261
  Provides-Extra: xml
271
262
  Requires-Dist: xmltodict>=0.12.0; extra == 'xml'
272
263
  Description-Content-Type: text/markdown
@@ -274,6 +265,7 @@ Description-Content-Type: text/markdown
274
265
  ![PyPI - Version](https://img.shields.io/pypi/v/lionagi?labelColor=233476aa&color=231fc935)
275
266
  ![PyPI - Downloads](https://img.shields.io/pypi/dm/lionagi?color=blue)
276
267
  ![Python Version](https://img.shields.io/badge/python-3.10%2B-blue)
268
+ [![codecov](https://codecov.io/github/khive-ai/lionagi/graph/badge.svg?token=FAE47FY26T)](https://codecov.io/github/khive-ai/lionagi)
277
269
 
278
270
  [Documentation](https://khive-ai.github.io/lionagi/) |
279
271
  [Discord](https://discord.gg/JDj9ENhUE8) |
@@ -416,7 +408,7 @@ Seamlessly route to different models in the same workflow.
416
408
 
417
409
  ### Claude Code Integration
418
410
 
419
- LionAGI now supports Anthropic's Claude Code [Python SDK](https://github.com/anthropics/claude-code-sdk-python), and [CLI SDK](https://docs.anthropic.com/en/docs/claude-code/sdk) enabling autonomous coding capabilities with persistent session management. The CLI endpoint
411
+ LionAGI now supports Anthropic's Claude Code [CLI SDK](https://docs.anthropic.com/en/docs/claude-code/sdk) enabling autonomous coding capabilities with persistent session management. The CLI endpoint
420
412
  directly connects to claude code, and is recommended, you can either use it via a [proxy server](https://github.com/khive-ai/lionagi/tree/main/cookbooks/claude_proxy) or directly with `query_cli` endpoint, provided you have already logged onto claude code cli in your terminal.
421
413
 
422
414
  ```python
@@ -484,7 +476,6 @@ Key features:
484
476
  ```
485
477
  "lionagi[reader]" - Reader tool for any unstructured data and web pages
486
478
  "lionagi[ollama]" - Ollama model support for local inference
487
- "lionagi[claude-code]" - Claude code python SDK integration (cli endpoint does not require this)
488
479
  "lionagi[rich]" - Rich output formatting for better console display
489
480
  "lionagi[schema]" - Convert pydantic schema to make the Model class persistent
490
481
  "lionagi[postgres]" - Postgres database support for storing and retrieving structured data