lionagi 0.0.114__py3-none-any.whl → 0.0.116__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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
  ]