lionagi 0.0.114__py3-none-any.whl → 0.0.116__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 (99) hide show
  1. lionagi/__init__.py +7 -4
  2. lionagi/bridge/__init__.py +19 -4
  3. lionagi/bridge/langchain.py +23 -3
  4. lionagi/bridge/llama_index.py +5 -3
  5. lionagi/configs/__init__.py +1 -1
  6. lionagi/configs/oai_configs.py +88 -1
  7. lionagi/core/__init__.py +6 -9
  8. lionagi/core/conversations/__init__.py +5 -0
  9. lionagi/core/conversations/conversation.py +107 -0
  10. lionagi/core/flows/__init__.py +8 -0
  11. lionagi/core/flows/flow.py +8 -0
  12. lionagi/core/flows/flow_util.py +62 -0
  13. lionagi/core/instruction_set/__init__.py +5 -0
  14. lionagi/core/instruction_set/instruction_sets.py +7 -0
  15. lionagi/core/sessions/__init__.py +5 -0
  16. lionagi/core/sessions/sessions.py +187 -0
  17. lionagi/endpoints/__init__.py +5 -0
  18. lionagi/endpoints/assistants.py +0 -0
  19. lionagi/endpoints/audio.py +17 -0
  20. lionagi/endpoints/chatcompletion.py +54 -0
  21. lionagi/endpoints/embeddings.py +0 -0
  22. lionagi/endpoints/finetune.py +0 -0
  23. lionagi/endpoints/image.py +0 -0
  24. lionagi/endpoints/moderation.py +0 -0
  25. lionagi/endpoints/vision.py +0 -0
  26. lionagi/{loader → loaders}/__init__.py +7 -1
  27. lionagi/{loader → loaders}/chunker.py +6 -12
  28. lionagi/{utils/load_utils.py → loaders/load_util.py} +47 -6
  29. lionagi/{loader → loaders}/reader.py +4 -12
  30. lionagi/messages/__init__.py +11 -0
  31. lionagi/messages/instruction.py +15 -0
  32. lionagi/messages/message.py +110 -0
  33. lionagi/messages/response.py +33 -0
  34. lionagi/messages/system.py +12 -0
  35. lionagi/objs/__init__.py +10 -6
  36. lionagi/objs/abc_objs.py +39 -0
  37. lionagi/objs/async_queue.py +135 -0
  38. lionagi/objs/messenger.py +70 -148
  39. lionagi/objs/status_tracker.py +37 -0
  40. lionagi/objs/{tool_registry.py → tool_manager.py} +8 -6
  41. lionagi/schema/__init__.py +3 -3
  42. lionagi/schema/base_node.py +251 -0
  43. lionagi/schema/base_tool.py +8 -3
  44. lionagi/schema/data_logger.py +2 -3
  45. lionagi/schema/data_node.py +37 -0
  46. lionagi/services/__init__.py +1 -4
  47. lionagi/services/base_api_service.py +15 -5
  48. lionagi/services/oai.py +2 -2
  49. lionagi/services/openrouter.py +2 -3
  50. lionagi/structures/graph.py +96 -0
  51. lionagi/{structure → structures}/relationship.py +10 -2
  52. lionagi/structures/structure.py +102 -0
  53. lionagi/tests/test_api_util.py +46 -0
  54. lionagi/tests/test_call_util.py +115 -0
  55. lionagi/tests/test_convert_util.py +202 -0
  56. lionagi/tests/test_encrypt_util.py +33 -0
  57. lionagi/tests/{test_flatten_util.py → test_flat_util.py} +1 -1
  58. lionagi/tests/test_io_util.py +0 -0
  59. lionagi/tests/test_sys_util.py +0 -0
  60. lionagi/tools/__init__.py +5 -0
  61. lionagi/tools/tool_util.py +7 -0
  62. lionagi/utils/__init__.py +55 -35
  63. lionagi/utils/api_util.py +19 -17
  64. lionagi/utils/call_util.py +2 -1
  65. lionagi/utils/convert_util.py +229 -0
  66. lionagi/utils/encrypt_util.py +16 -0
  67. lionagi/utils/flat_util.py +38 -0
  68. lionagi/utils/io_util.py +2 -2
  69. lionagi/utils/sys_util.py +45 -10
  70. lionagi/version.py +1 -1
  71. {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/METADATA +2 -2
  72. lionagi-0.0.116.dist-info/RECORD +110 -0
  73. lionagi/core/conversations.py +0 -108
  74. lionagi/core/flows.py +0 -1
  75. lionagi/core/instruction_sets.py +0 -1
  76. lionagi/core/messages.py +0 -166
  77. lionagi/core/sessions.py +0 -297
  78. lionagi/schema/base_schema.py +0 -252
  79. lionagi/services/chatcompletion.py +0 -48
  80. lionagi/services/service_objs.py +0 -282
  81. lionagi/structure/structure.py +0 -160
  82. lionagi/tools/coder.py +0 -1
  83. lionagi/tools/sandbox.py +0 -1
  84. lionagi/utils/tool_util.py +0 -92
  85. lionagi/utils/type_util.py +0 -81
  86. lionagi-0.0.114.dist-info/RECORD +0 -84
  87. /lionagi/configs/{openrouter_config.py → openrouter_configs.py} +0 -0
  88. /lionagi/{datastore → datastores}/__init__.py +0 -0
  89. /lionagi/{datastore → datastores}/chroma.py +0 -0
  90. /lionagi/{datastore → datastores}/deeplake.py +0 -0
  91. /lionagi/{datastore → datastores}/elasticsearch.py +0 -0
  92. /lionagi/{datastore → datastores}/lantern.py +0 -0
  93. /lionagi/{datastore → datastores}/pinecone.py +0 -0
  94. /lionagi/{datastore → datastores}/postgres.py +0 -0
  95. /lionagi/{datastore → datastores}/qdrant.py +0 -0
  96. /lionagi/{structure → structures}/__init__.py +0 -0
  97. {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/LICENSE +0 -0
  98. {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/WHEEL +0 -0
  99. {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/top_level.txt +0 -0
lionagi/objs/messenger.py CHANGED
@@ -1,163 +1,85 @@
1
- # from typing import Optional, Any, Union, Dict, Tuple
1
+ from collections import deque
2
+ from typing import Optional, Any, Union, Dict, Tuple
2
3
 
3
- # from lionagi.utils.call_util import lcall
4
- # from lionagi.schema.data_logger import DataLogger
5
- # from lionagi.core.messages import Message, Response, Instruction, System
4
+ from lionagi.utils.call_util import lcall
5
+ from lionagi.schema.data_logger import DataLogger
6
+ from lionagi.messages import Message, Response, Instruction, System
6
7
 
7
8
 
8
- # class Messenger:
9
- # """
10
- # Messenger handles the creation, logging, and exporting of messages.
11
-
12
- # This class is responsible for creating various types of messages (system, instruction, response),
13
- # logging them, and optionally exporting the log to a CSV file.
14
-
15
- # Attributes:
16
- # _logger (DataLogger): An instance of DataLogger to manage message logging.
9
+ class Messenger:
17
10
 
18
- # Methods:
19
- # set_dir: Sets the directory for the DataLogger to save CSV files.
20
-
21
- # set_log: Sets the log object for the DataLogger.
22
-
23
- # log_message: Logs a message in JSON format.
11
+ def __init__(self) -> None:
12
+ self._logger = DataLogger()
24
13
 
25
- # to_csv: Exports logged messages to a CSV file.
14
+ def set_dir(self, dir: str) -> None:
15
+ self._logger.dir = dir
16
+
17
+ def set_log(self, log) -> None:
18
+ self._logger.log = log
26
19
 
27
- # _create_message: Internal method to create a specific type of message.
20
+ def log_message(self, msg: Message) -> None:
21
+ self._logger(msg.to_json())
28
22
 
29
- # create_message: Public interface to create messages, log them, and optionally return them in different formats.
30
- # """
23
+ def to_csv(self, **kwargs) -> None:
24
+ self._logger.to_csv(**kwargs)
31
25
 
32
- # def __init__(self) -> None:
33
- # """
34
- # Initializes the Messenger with a DataLogger instance.
35
- # """
36
- # self._logger = DataLogger()
37
-
38
- # def set_dir(self, dir: str) -> None:
39
- # """
40
- # Sets the directory where the DataLogger will save CSV files.
41
-
42
- # Parameters:
43
- # dir (str): The directory path to set for the DataLogger.
44
- # """
45
- # self._logger.dir = dir
26
+ def clear_log(self):
27
+ self._logger.log = deque()
46
28
 
47
- # def set_log(self, log) -> None:
48
- # """
49
- # Sets the log object for the DataLogger.
50
-
51
- # Parameters:
52
- # log: The log object to be used by the DataLogger.
53
- # """
54
- # self._logger.log = log
29
+ def _create_message(
30
+ self,
31
+ system: Optional[Any] = None,
32
+ instruction: Optional[Any] = None,
33
+ context: Optional[Any] = None,
34
+ response: Optional[Any] = None,
35
+ name: Optional[str] = None
36
+ ) -> Message:
55
37
 
56
- # def log_message(self, msg: Message) -> None:
57
- # """
58
- # Logs a message in JSON format using the DataLogger.
59
-
60
- # Parameters:
61
- # msg (Message): The message object to be logged.
62
- # """
63
- # self._logger(msg.to_json())
64
-
65
- # def to_csv(self, **kwargs) -> None:
66
- # """
67
- # Exports the logged messages to a CSV file.
68
-
69
- # Parameters:
70
- # **kwargs: Additional keyword arguments to be passed to the DataLogger's to_csv method.
71
- # """
72
- # self._logger.to_csv(**kwargs)
38
+ if sum(lcall([system, instruction, response], bool)) != 1:
39
+ raise ValueError("Error: Message must have one and only one role.")
73
40
 
74
- # def _create_message(self,
75
- # system: Optional[Any] = None,
76
- # instruction: Optional[Any] = None,
77
- # context: Optional[Any] = None,
78
- # response: Optional[Any] = None,
79
- # name: Optional[str] = None) -> Message:
80
- # """
81
- # Creates a specific type of message based on the provided parameters.
82
-
83
- # Parameters:
84
- # system (Optional[Any]): System message content.
85
-
86
- # instruction (Optional[Any]): Instruction message content.
87
-
88
- # context (Optional[Any]): Context for the instruction message.
89
-
90
- # response (Optional[Any]): Response message content.
41
+ else:
42
+ msg = 0
91
43
 
92
- # name (Optional[str]): Name associated with the message.
93
-
94
- # Returns:
95
- # Message: The created message object of type Response, Instruction, or System.
96
-
97
- # Raises:
98
- # ValueError: If more than one or none of the message content parameters (system, instruction, response) are provided.
99
- # """
100
-
101
- # if sum(lcall([system, instruction, response], bool)) != 1:
102
- # raise ValueError("Error: Message must have one and only one role.")
103
-
104
- # else:
105
- # msg = 0
106
-
107
- # if response:
108
- # msg = Response()
109
- # msg.create_message(response=response,
110
- # name=name,)
111
- # elif instruction:
112
- # msg = Instruction()
113
- # msg.create_message(instruction=instruction,
114
- # context=context,
115
- # name=name,)
116
- # elif system:
117
- # msg = System()
118
- # msg.create_message(system=system,
119
- # name=name,)
120
- # return msg
44
+ if response:
45
+ msg = Response()
46
+ msg._create_message(
47
+ response=response, name=name,
48
+ )
49
+ elif instruction:
50
+ msg = Instruction()
51
+ msg._create_message(
52
+ instruction=instruction, context=context,
53
+ name=name,
54
+ )
55
+ elif system:
56
+ msg = System()
57
+ msg._create_message(
58
+ system=system, name=name,
59
+ )
60
+ return msg
121
61
 
122
- # def create_message(self,
123
- # system: Optional[Any] = None,
124
- # instruction: Optional[Any] = None,
125
- # context: Optional[Any] = None,
126
- # response: Optional[Any] = None,
127
- # name: Optional[str] = None,
128
- # obj: bool = False,
129
- # log_: bool = True) -> Union[Message, Tuple[Message, Dict]]:
130
- # """
131
- # Creates and optionally logs a message, returning it in different formats based on parameters.
132
-
133
- # Parameters:
134
- # system (Optional[Any]): System message content.
135
-
136
- # instruction (Optional[Any]): Instruction message content.
137
-
138
- # context (Optional[Any]): Context for the instruction message.
139
-
140
- # response (Optional[Any]): Response message content.
141
-
142
- # name (Optional[str]): Name associated with the message.
143
-
144
- # obj (bool): If True, returns the Message object and its dictionary representation. Defaults to False.
145
-
146
- # log_ (bool): If True, logs the created message. Defaults to True.
147
-
148
- # Returns:
149
- # Union[Message, Tuple[Message, Dict]]: The created message in the specified format.
150
- # """
62
+ def create_message(
63
+ self,
64
+ system: Optional[Any] = None,
65
+ instruction: Optional[Any] = None,
66
+ context: Optional[Any] = None,
67
+ response: Optional[Any] = None,
68
+ name: Optional[str] = None,
69
+ obj: bool = True,
70
+ log_: bool = True
71
+ ) -> Union[Message, Tuple[Message, Dict]]:
72
+
73
+ msg = self._create_message(
74
+ system=system,
75
+ instruction=instruction,
76
+ context=context,
77
+ response=response,
78
+ name=name
79
+ )
151
80
 
152
- # msg = self._create_message(system=system,
153
- # instruction=instruction,
154
- # context=context,
155
- # response=response,
156
- # name=name)
157
- # if log_:
158
- # self.log_message(msg)
159
- # if obj:
160
- # return (msg, msg._to_message())
161
- # else:
162
- # return msg._to_message()
81
+ if log_:
82
+ self.log_message(msg)
83
+ if obj:
84
+ return msg
163
85
 
@@ -0,0 +1,37 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ # credit to OpenAI for the following object
5
+ @dataclass
6
+ class StatusTracker:
7
+ """
8
+ Class for keeping track of various task statuses.
9
+
10
+ This class serves as a simple way to monitor different types of task
11
+ outcomes and errors within a system. It uses dataclasses for easy
12
+ creation and management of state.
13
+
14
+ Attributes:
15
+ num_tasks_started:
16
+ The number of tasks that have been initiated.
17
+ num_tasks_in_progress:
18
+ The number of tasks currently being processed.
19
+ num_tasks_succeeded:
20
+ The number of tasks that have completed successfully.
21
+ num_tasks_failed:
22
+ The number of tasks that have failed.
23
+ num_rate_limit_errors:
24
+ The number of tasks that failed due to rate limiting.
25
+ num_api_errors:
26
+ The number of tasks that failed due to API errors.
27
+ num_other_errors:
28
+ The number of tasks that failed due to other errors.
29
+ """
30
+ num_tasks_started: int = 0
31
+ num_tasks_in_progress: int = 0
32
+ num_tasks_succeeded: int = 0
33
+ num_tasks_failed: int = 0
34
+ num_rate_limit_errors: int = 0
35
+ num_api_errors: int = 0
36
+ num_other_errors: int = 0
37
+
@@ -1,14 +1,14 @@
1
1
  import json
2
2
  import asyncio
3
3
  from typing import Dict
4
- from ..utils import lcall, str_to_num
5
- from ..schema import BaseNode
4
+ from lionagi.utils import lcall
5
+ from lionagi.schema import BaseNode, Tool
6
6
 
7
7
 
8
8
  class ToolManager(BaseNode):
9
9
  registry: Dict = {}
10
10
 
11
- def _name_existed(self, name: str):
11
+ def name_existed(self, name: str):
12
12
  return True if name in self.registry.keys() else False
13
13
 
14
14
  def _register_tool(self, tool): #,update=False, new=False, prefix=None, postfix=None):
@@ -28,12 +28,14 @@ class ToolManager(BaseNode):
28
28
 
29
29
  # name = f"{prefix or ''}{name}{postfix}" if new else tool.func.__name__
30
30
 
31
+ if not isinstance(tool, Tool):
32
+ raise TypeError('Please register a Tool object.')
31
33
  name = tool.schema_['function']['name']
32
34
  self.registry.update({name: tool})
33
35
 
34
36
  async def invoke(self, func_call):
35
37
  name, kwargs = func_call
36
- if self._name_existed(name):
38
+ if self.name_existed(name):
37
39
  tool = self.registry[name]
38
40
  func = tool.func
39
41
  parser = tool.parser
@@ -48,7 +50,7 @@ class ToolManager(BaseNode):
48
50
  raise ValueError(f"Function {name} is not registered.")
49
51
 
50
52
  @staticmethod
51
- def _get_function_call(response):
53
+ def get_function_call(response):
52
54
  """
53
55
  Extract function name and arguments from a response JSON.
54
56
 
@@ -73,7 +75,7 @@ class ToolManager(BaseNode):
73
75
  def register_tools(self, tools): #, update=False, new=False, prefix=None, postfix=None ):
74
76
  lcall(tools, self._register_tool) #, update=update, new=new, prefix=prefix, postfix=postfix)
75
77
 
76
- def to_tool_schema(self):
78
+ def to_tool_schema_list(self):
77
79
  schema_list = []
78
80
  for tool in self.registry.values():
79
81
  schema_list.append(tool.schema_)
@@ -1,11 +1,11 @@
1
- from .base_schema import BaseNode, DataNode, Message
1
+ from .base_node import BaseNode
2
2
  from .base_tool import Tool
3
3
  from .data_logger import DataLogger
4
+ from .data_node import DataNode
4
5
 
5
6
  __all__ = [
6
7
  "BaseNode",
7
8
  "DataNode",
8
- "Message",
9
9
  "Tool",
10
- "DataLogger"
10
+ "DataLogger",
11
11
  ]
@@ -0,0 +1,251 @@
1
+ # uses utils
2
+ import json
3
+ import xml.etree.ElementTree as ET
4
+ from typing import Any, Dict, Optional, TypeVar, Type, List, Callable, Union
5
+ from pydantic import BaseModel, Field, AliasChoices
6
+
7
+ from lionagi.utils import (
8
+ create_id, is_schema, change_dict_key, create_copy,
9
+ encrypt, decrypt, dict_to_xml
10
+ )
11
+
12
+ T = TypeVar('T', bound='BaseNode')
13
+
14
+
15
+ class BaseNode(BaseModel):
16
+ """
17
+ A foundational building block for representing a node in a graph-like structure.
18
+ This class includes functionalities for serialization, metadata manipulation,
19
+ content encryption/decryption, and utility methods.
20
+
21
+ Attributes:
22
+ id_ (str): Unique identifier for the node, aliased as 'node_id'.
23
+ metadata (Dict[str, Any]): Dictionary of metadata related to the node.
24
+ label (Optional[str]): Label categorizing or identifying the node.
25
+ related_nodes (List[str]): Identifiers for nodes related to this node.
26
+ content (Union[str, Dict[str, Any], None, Any]): Content of the node.
27
+ """
28
+ id_: str = Field(default_factory=lambda: str(create_id()), alias="node_id")
29
+ metadata: Dict[str, Any] = Field(default_factory=dict)
30
+ label: Optional[str] = None
31
+ related_nodes: List[str] = Field(default_factory=list)
32
+ content: Union[str, Dict[str, Any], None, Any] = Field(
33
+ default=None, validation_alias=AliasChoices('text', 'page_content', 'chunk_content')
34
+ )
35
+
36
+ class Config:
37
+ extra = 'allow'
38
+ populate_by_name = True
39
+ validate_assignment = True
40
+ str_strip_whitespace = True
41
+
42
+ # from-to [json, dict, xml]
43
+ @classmethod
44
+ def from_dict(cls, data: Dict[str, Any]) -> T:
45
+ """Creates a BaseNode instance from a dictionary."""
46
+ return cls(**data)
47
+
48
+ @classmethod
49
+ def from_json(cls: Type[T], json_str: str, **kwargs) -> T:
50
+ """Creates a BaseNode instance from a JSON string."""
51
+ try:
52
+ data = json.loads(json_str, **kwargs)
53
+ return cls(**data)
54
+ except json.JSONDecodeError as e:
55
+ raise ValueError("Invalid JSON string provided for deserialization.") from e
56
+
57
+ @classmethod
58
+ def from_xml(cls, xml_str: str) -> T:
59
+ """Creates a BaseNode instance from an XML string."""
60
+ root = ET.fromstring(xml_str)
61
+ data = cls._xml_to_dict(root)
62
+ return cls(**data)
63
+
64
+ def to_json(self) -> str:
65
+ """Converts the BaseNode instance into a JSON string."""
66
+ return self.model_dump_json(by_alias=True)
67
+
68
+ def to_dict(self) -> Dict[str, Any]:
69
+ """Converts the BaseNode instance into a dictionary."""
70
+ return self.model_dump(by_alias=True)
71
+
72
+ def to_xml(self) -> str:
73
+ """Converts the BaseNode instance into an XML string."""
74
+ return dict_to_xml(self.to_dict())
75
+
76
+ # Metadata manipulation methods
77
+ def set_meta(self, metadata_: Dict[str, Any]) -> None:
78
+ """Sets the metadata for the node."""
79
+ self.metadata = metadata_
80
+
81
+ def get_meta_key(self, key: str) -> Any:
82
+ """Retrieves a specific metadata value by key."""
83
+ return self.metadata.get(key)
84
+
85
+ def change_meta_key(self, old_key: str, new_key: str) -> None:
86
+ """Changes a metadata key from old_key to new_key."""
87
+ change_dict_key(self.metadata,old_key=old_key, new_key=new_key)
88
+
89
+ def delete_meta_key(self, key: str) -> None:
90
+ """Deletes a metadata key from the node."""
91
+ if key in self.metadata:
92
+ del self.metadata[key]
93
+
94
+ def merge_metadata(self, other_metadata: Dict[str, Any], overwrite: bool = True) -> None:
95
+ """Merges another metadata dictionary into the node's metadata."""
96
+ if not overwrite:
97
+ other_metadata = ({
98
+ k: v for k, v in other_metadata.items()
99
+ if k not in self.metadata
100
+ })
101
+ self.metadata.update(other_metadata)
102
+
103
+ def clear_metadata(self) -> None:
104
+ """Clears all metadata from the node."""
105
+ self.metadata.clear()
106
+
107
+ @property
108
+ def meta_keys(self) -> List[str]:
109
+ """Returns a list of all metadata keys."""
110
+ return list(self.metadata.keys())
111
+
112
+ def has_meta_key(self, key: str) -> bool:
113
+ """Checks if a specific metadata key exists."""
114
+ return key in self.metadata
115
+
116
+ def filter_meta(self, filter_func: Callable[[Any], bool]) -> Dict[str, Any]:
117
+ """Filters metadata based on a provided function."""
118
+ return {k: v for k, v in self.metadata.items() if filter_func(v)}
119
+
120
+ def apply_to_meta(self, apply_func: Callable[[Any], Any]) -> None:
121
+ """Applies a function to each metadata value."""
122
+ for key in self.metadata:
123
+ self.metadata[key] = apply_func(self.metadata[key])
124
+
125
+ def meta_schema_is_valid(self, schema: Dict[str, type]) -> bool:
126
+ """Checks if the metadata matches a given schema."""
127
+ return is_schema(dict_=self.metadata, schema=schema)
128
+
129
+ def update_meta(self, **kwargs) -> None:
130
+ """Updates metadata with the provided key-value pairs."""
131
+ self.metadata.update(kwargs)
132
+
133
+ # Encryption methods
134
+ def encrypt_content(self, key: str) -> None:
135
+ """Encrypts the content of the node."""
136
+ self.content = encrypt(self.content, key)
137
+
138
+ def decrypt_content(self, key: str) -> None:
139
+ """Decrypts the content of the node."""
140
+ self.content = decrypt(self.content, key)
141
+
142
+ # Getters and setters
143
+ def set_content(self, content: Optional[Any]) -> None:
144
+ """Sets the content of the node."""
145
+ self.content = content
146
+
147
+ def get_content(self) -> Optional[Any]:
148
+ """Retrieves the content of the node."""
149
+ return self.content
150
+
151
+ def set_id(self, id_: str) -> None:
152
+ """Sets the ID of the node."""
153
+ self.id_ = id_
154
+
155
+ def get_id(self) -> str:
156
+ """Retrieves the ID of the node."""
157
+ return self.id_
158
+
159
+ def add_related_node(self, node_id: str) -> None:
160
+ """Adds a related node ID."""
161
+ if node_id not in self.related_nodes:
162
+ self.related_nodes.append(node_id)
163
+
164
+ def remove_related_node(self, node_id: str) -> None:
165
+ """Removes a related node ID."""
166
+ self.related_nodes = [id_ for id_ in self.related_nodes if id_ != node_id]
167
+
168
+ # Utility methods
169
+ def is_empty(self) -> bool:
170
+ """Checks if the node is empty (no content and metadata)."""
171
+ return not self.content and not self.metadata
172
+
173
+ def has_label(self, label: str) -> bool:
174
+ """Checks if the node has a specific label."""
175
+ return self.label == label
176
+
177
+ def is_metadata_key_present(self, key: str) -> bool:
178
+ """Checks if a specific key is present in the metadata."""
179
+ return key in self.metadata
180
+
181
+ def copy(self, n: int = 1) -> Union[List[T], T]:
182
+ """
183
+ Creates one or multiple deep copies of the node.
184
+
185
+ Parameters:
186
+ n (int): Number of copies to create.
187
+
188
+ Returns:
189
+ Union[List[T], T]: A copy or list of copies of the node.
190
+ """
191
+ return create_copy(self, n)
192
+
193
+ def data_equals(self, other: 'BaseNode') -> bool:
194
+ """
195
+ Checks if the node's data equals another node's data.
196
+
197
+ Parameters:
198
+ other (BaseNode): Another node to compare with.
199
+
200
+ Returns:
201
+ bool: True if data is equal, False otherwise.
202
+ """
203
+ return (
204
+ self.content == other.content and
205
+ self.metadata == other.metadata and
206
+ self.related_nodes == other.related_nodes
207
+ )
208
+
209
+ def is_copy_of(self, other: 'BaseNode') -> bool:
210
+ """
211
+ Checks if the node is a copy of another node.
212
+
213
+ Parameters:
214
+ other (BaseNode): Another node to compare with.
215
+
216
+ Returns:
217
+ bool: True if it is a copy, False otherwise.
218
+ """
219
+ return (
220
+ self.data_equals(other) and
221
+ self is not other
222
+ )
223
+
224
+ def __eq__(self, other: 'BaseNode') -> bool:
225
+ """
226
+ Overrides the equality operator to compare nodes.
227
+
228
+ Parameters:
229
+ other (BaseNode): Another node to compare with.
230
+
231
+ Returns:
232
+ bool: True if nodes are equal, False otherwise.
233
+ """
234
+ return (self.id_ == other.id_ and self.data_equals(other))
235
+
236
+ def __str__(self) -> str:
237
+ """
238
+ Returns a user-friendly string representation of the BaseNode.
239
+
240
+ Returns:
241
+ str: A string representation of the BaseNode.
242
+ """
243
+ content_preview = (str(self.content)[:75] + '...') if len(str(self.content)) > 75 else str(self.content)
244
+ return f"{self.__class__.__name__}(id={self.id_}, label={self.label}, content='{content_preview}')"
245
+
246
+ def __repr__(self):
247
+ """
248
+ Official string representation of Message object.
249
+ Utilizes the json representation of the object for clarity.
250
+ """
251
+ return f"{self.__class__.__name__}({self.to_json()})"
@@ -1,9 +1,14 @@
1
1
  from typing import Any
2
- from .base_schema import BaseNode
2
+ from pydantic import field_serializer
3
+ from .base_node import BaseNode
3
4
 
4
5
  class Tool(BaseNode):
5
- name: str = None
6
+ # name: str = None
6
7
  func: Any
7
8
  content: Any = None
8
9
  parser: Any = None
9
- schema_: Any
10
+ schema_: dict
11
+
12
+ @field_serializer('func')
13
+ def serialize_func(self, func):
14
+ return func.__name__
@@ -1,7 +1,6 @@
1
1
  from collections import deque
2
- from typing import List, Optional
3
- from ..utils.sys_util import create_path
4
- from ..utils.io_util import to_csv
2
+ from typing import Optional
3
+ from lionagi.utils import create_path, to_csv
5
4
 
6
5
 
7
6
  class DataLogger:
@@ -0,0 +1,37 @@
1
+ from .base_node import BaseNode
2
+ from typing import Any
3
+
4
+
5
+ class DataNode(BaseNode):
6
+
7
+ def to_llama_index(self, **kwargs):
8
+ # to llama_index textnode
9
+ from lionagi.bridge.llama_index import to_llama_index_textnode
10
+ return to_llama_index_textnode(self, **kwargs)
11
+
12
+ def to_langchain(self, **kwargs):
13
+ # to langchain document
14
+ from lionagi.bridge.langchain import to_langchain_document
15
+ return to_langchain_document(self, **kwargs)
16
+
17
+ @classmethod
18
+ def from_llama_index(cls, llama_node: Any, **kwargs):
19
+ llama_dict = llama_node.to_dict(**kwargs)
20
+ return cls.from_dict(llama_dict)
21
+
22
+ @classmethod
23
+ def from_langchain(cls, lc_doc: Any):
24
+ info_json = lc_doc.to_json()
25
+ info_node = {'lc_id': info_json['id']}
26
+ info_node = {**info_node, **info_json['kwargs']}
27
+ return cls(**info_node)
28
+
29
+
30
+ class File(DataNode):
31
+
32
+ ...
33
+
34
+
35
+ class Chunk(DataNode):
36
+
37
+ ...
@@ -1,14 +1,11 @@
1
- from .chatcompletion import ChatCompletion
2
1
  from .base_api_service import BaseAPIService, BaseAPIRateLimiter
3
2
  from .oai import OpenAIService
4
3
  from .openrouter import OpenRouterService
5
4
 
6
5
 
7
-
8
6
  __all__ = [
9
7
  "BaseAPIService",
8
+ "BaseAPIRateLimiter",
10
9
  "OpenAIService",
11
10
  "OpenRouterService",
12
- "ChatCompletion",
13
- "BaseAPIRateLimiter"
14
11
  ]