lionagi 0.0.115__py3-none-any.whl → 0.0.204__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. lionagi/__init__.py +1 -2
  2. lionagi/_services/__init__.py +5 -0
  3. lionagi/_services/anthropic.py +79 -0
  4. lionagi/_services/base_service.py +414 -0
  5. lionagi/_services/oai.py +98 -0
  6. lionagi/_services/openrouter.py +44 -0
  7. lionagi/_services/services.py +91 -0
  8. lionagi/_services/transformers.py +46 -0
  9. lionagi/bridge/langchain.py +26 -16
  10. lionagi/bridge/llama_index.py +50 -20
  11. lionagi/configs/oai_configs.py +2 -14
  12. lionagi/configs/openrouter_configs.py +2 -2
  13. lionagi/core/__init__.py +7 -8
  14. lionagi/core/branch/branch.py +589 -0
  15. lionagi/core/branch/branch_manager.py +139 -0
  16. lionagi/core/branch/conversation.py +484 -0
  17. lionagi/core/core_util.py +59 -0
  18. lionagi/core/flow/flow.py +19 -0
  19. lionagi/core/flow/flow_util.py +62 -0
  20. lionagi/core/instruction_set/__init__.py +0 -5
  21. lionagi/core/instruction_set/instruction_set.py +343 -0
  22. lionagi/core/messages/messages.py +176 -0
  23. lionagi/core/sessions/__init__.py +0 -5
  24. lionagi/core/sessions/session.py +428 -0
  25. lionagi/loaders/chunker.py +51 -47
  26. lionagi/loaders/load_util.py +2 -2
  27. lionagi/loaders/reader.py +45 -39
  28. lionagi/models/imodel.py +53 -0
  29. lionagi/schema/async_queue.py +158 -0
  30. lionagi/schema/base_node.py +318 -147
  31. lionagi/schema/base_tool.py +31 -1
  32. lionagi/schema/data_logger.py +74 -38
  33. lionagi/schema/data_node.py +57 -6
  34. lionagi/structures/graph.py +132 -10
  35. lionagi/structures/relationship.py +58 -20
  36. lionagi/structures/structure.py +36 -25
  37. lionagi/tests/test_utils/test_api_util.py +219 -0
  38. lionagi/tests/test_utils/test_call_util.py +785 -0
  39. lionagi/tests/test_utils/test_encrypt_util.py +323 -0
  40. lionagi/tests/test_utils/test_io_util.py +238 -0
  41. lionagi/tests/test_utils/test_nested_util.py +338 -0
  42. lionagi/tests/test_utils/test_sys_util.py +358 -0
  43. lionagi/tools/tool_manager.py +186 -0
  44. lionagi/tools/tool_util.py +266 -3
  45. lionagi/utils/__init__.py +21 -61
  46. lionagi/utils/api_util.py +359 -71
  47. lionagi/utils/call_util.py +839 -264
  48. lionagi/utils/encrypt_util.py +283 -16
  49. lionagi/utils/io_util.py +178 -93
  50. lionagi/utils/nested_util.py +672 -0
  51. lionagi/utils/pd_util.py +57 -0
  52. lionagi/utils/sys_util.py +284 -156
  53. lionagi/utils/url_util.py +55 -0
  54. lionagi/version.py +1 -1
  55. {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/METADATA +21 -17
  56. lionagi-0.0.204.dist-info/RECORD +106 -0
  57. lionagi/core/conversations/__init__.py +0 -5
  58. lionagi/core/conversations/conversation.py +0 -107
  59. lionagi/core/flows/__init__.py +0 -8
  60. lionagi/core/flows/flow.py +0 -8
  61. lionagi/core/flows/flow_util.py +0 -62
  62. lionagi/core/instruction_set/instruction_sets.py +0 -7
  63. lionagi/core/sessions/sessions.py +0 -185
  64. lionagi/endpoints/__init__.py +0 -5
  65. lionagi/endpoints/audio.py +0 -17
  66. lionagi/endpoints/chatcompletion.py +0 -54
  67. lionagi/messages/__init__.py +0 -11
  68. lionagi/messages/instruction.py +0 -15
  69. lionagi/messages/message.py +0 -110
  70. lionagi/messages/response.py +0 -33
  71. lionagi/messages/system.py +0 -12
  72. lionagi/objs/__init__.py +0 -11
  73. lionagi/objs/abc_objs.py +0 -39
  74. lionagi/objs/async_queue.py +0 -135
  75. lionagi/objs/messenger.py +0 -85
  76. lionagi/objs/tool_manager.py +0 -253
  77. lionagi/services/__init__.py +0 -11
  78. lionagi/services/base_api_service.py +0 -230
  79. lionagi/services/oai.py +0 -34
  80. lionagi/services/openrouter.py +0 -31
  81. lionagi/tests/test_api_util.py +0 -46
  82. lionagi/tests/test_call_util.py +0 -115
  83. lionagi/tests/test_convert_util.py +0 -202
  84. lionagi/tests/test_encrypt_util.py +0 -33
  85. lionagi/tests/test_flat_util.py +0 -426
  86. lionagi/tests/test_sys_util.py +0 -0
  87. lionagi/utils/convert_util.py +0 -229
  88. lionagi/utils/flat_util.py +0 -599
  89. lionagi-0.0.115.dist-info/RECORD +0 -110
  90. /lionagi/{services → _services}/anyscale.py +0 -0
  91. /lionagi/{services → _services}/azure.py +0 -0
  92. /lionagi/{services → _services}/bedrock.py +0 -0
  93. /lionagi/{services → _services}/everlyai.py +0 -0
  94. /lionagi/{services → _services}/gemini.py +0 -0
  95. /lionagi/{services → _services}/gpt4all.py +0 -0
  96. /lionagi/{services → _services}/huggingface.py +0 -0
  97. /lionagi/{services → _services}/litellm.py +0 -0
  98. /lionagi/{services → _services}/localai.py +0 -0
  99. /lionagi/{services → _services}/mistralai.py +0 -0
  100. /lionagi/{services → _services}/ollama.py +0 -0
  101. /lionagi/{services → _services}/openllm.py +0 -0
  102. /lionagi/{services → _services}/perplexity.py +0 -0
  103. /lionagi/{services → _services}/predibase.py +0 -0
  104. /lionagi/{services → _services}/rungpt.py +0 -0
  105. /lionagi/{services → _services}/vllm.py +0 -0
  106. /lionagi/{services → _services}/xinference.py +0 -0
  107. /lionagi/{endpoints/assistants.py → agents/__init__.py} +0 -0
  108. /lionagi/{tools → agents}/planner.py +0 -0
  109. /lionagi/{tools → agents}/prompter.py +0 -0
  110. /lionagi/{tools → agents}/scorer.py +0 -0
  111. /lionagi/{tools → agents}/summarizer.py +0 -0
  112. /lionagi/{tools → agents}/validator.py +0 -0
  113. /lionagi/{endpoints/embeddings.py → core/branch/__init__.py} +0 -0
  114. /lionagi/{services/anthropic.py → core/branch/cluster.py} +0 -0
  115. /lionagi/{endpoints/finetune.py → core/flow/__init__.py} +0 -0
  116. /lionagi/{endpoints/image.py → core/messages/__init__.py} +0 -0
  117. /lionagi/{endpoints/moderation.py → models/__init__.py} +0 -0
  118. /lionagi/{endpoints/vision.py → models/base_model.py} +0 -0
  119. /lionagi/{objs → schema}/status_tracker.py +0 -0
  120. /lionagi/tests/{test_io_util.py → test_utils/__init__.py} +0 -0
  121. {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/LICENSE +0 -0
  122. {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/WHEEL +0 -0
  123. {lionagi-0.0.115.dist-info → lionagi-0.0.204.dist-info}/top_level.txt +0 -0
@@ -1,30 +1,32 @@
1
- # uses utils
2
1
  import json
3
2
  import xml.etree.ElementTree as ET
4
3
  from typing import Any, Dict, Optional, TypeVar, Type, List, Callable, Union
5
4
  from pydantic import BaseModel, Field, AliasChoices
6
5
 
7
- from lionagi.utils import (
8
- create_id, is_schema, change_dict_key, create_copy,
9
- encrypt, decrypt, dict_to_xml
10
- )
6
+ from ..utils.sys_util import create_id, change_dict_key, is_schema
7
+ from ..utils.encrypt_util import EncrytionUtil
11
8
 
12
9
  T = TypeVar('T', bound='BaseNode')
13
10
 
14
11
 
15
12
  class BaseNode(BaseModel):
16
13
  """
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.
14
+ The base class for nodes containing general information and metadata.
20
15
 
21
16
  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.
17
+ id_ (str): The unique identifier for the node.
18
+ metadata (Dict[str, Any]): Additional metadata for the node.
19
+ label (Optional[str]): An optional label for the node.
20
+ related_nodes (List[str]): List of related node IDs.
21
+ content (Union[str, Dict[str, Any], None, Any]): The content of the node.
22
+
23
+ Examples:
24
+ >>> node = BaseNode(content="Example content")
25
+ >>> node_dict = node.to_dict()
26
+ >>> json_str = node.to_json()
27
+ >>> same_node = BaseNode.from_json(json_str)
27
28
  """
29
+
28
30
  id_: str = Field(default_factory=lambda: str(create_id()), alias="node_id")
29
31
  metadata: Dict[str, Any] = Field(default_factory=dict)
30
32
  label: Optional[str] = None
@@ -32,22 +34,47 @@ class BaseNode(BaseModel):
32
34
  content: Union[str, Dict[str, Any], None, Any] = Field(
33
35
  default=None, validation_alias=AliasChoices('text', 'page_content', 'chunk_content')
34
36
  )
35
-
37
+
36
38
  class Config:
37
39
  extra = 'allow'
38
40
  populate_by_name = True
39
41
  validate_assignment = True
42
+ validate_return = True
40
43
  str_strip_whitespace = True
41
44
 
42
- # from-to [json, dict, xml]
43
45
  @classmethod
44
46
  def from_dict(cls, data: Dict[str, Any]) -> T:
45
- """Creates a BaseNode instance from a dictionary."""
47
+ """
48
+ Creates an instance of the class from a dictionary.
49
+
50
+ Args:
51
+ data: A dictionary containing the node's data.
52
+
53
+ Returns:
54
+ An instance of the class.
55
+
56
+ Examples:
57
+ >>> data = {"content": "Example content"}
58
+ >>> node = BaseNode.from_dict(data)
59
+ """
46
60
  return cls(**data)
47
61
 
48
62
  @classmethod
49
63
  def from_json(cls: Type[T], json_str: str, **kwargs) -> T:
50
- """Creates a BaseNode instance from a JSON string."""
64
+ """
65
+ Creates an instance of the class from a JSON string.
66
+
67
+ Args:
68
+ json_str: A JSON string containing the node's data.
69
+ **kwargs: Additional keyword arguments to pass to json.loads.
70
+
71
+ Returns:
72
+ An instance of the class.
73
+
74
+ Examples:
75
+ >>> json_str = '{"content": "Example content"}'
76
+ >>> node = BaseNode.from_json(json_str)
77
+ """
51
78
  try:
52
79
  data = json.loads(json_str, **kwargs)
53
80
  return cls(**data)
@@ -56,43 +83,183 @@ class BaseNode(BaseModel):
56
83
 
57
84
  @classmethod
58
85
  def from_xml(cls, xml_str: str) -> T:
59
- """Creates a BaseNode instance from an XML string."""
86
+ """
87
+ Creates an instance of the class from an XML string.
88
+
89
+ Args:
90
+ xml_str: An XML string containing the node's data.
91
+
92
+ Returns:
93
+ An instance of the class.
94
+
95
+ Examples:
96
+ >>> xml_str = "<BaseNode><content>Example content</content></BaseNode>"
97
+ >>> node = BaseNode.from_xml(xml_str)
98
+ """
60
99
  root = ET.fromstring(xml_str)
61
100
  data = cls._xml_to_dict(root)
62
101
  return cls(**data)
63
102
 
64
103
  def to_json(self) -> str:
65
- """Converts the BaseNode instance into a JSON string."""
104
+ """
105
+ Converts the instance to a JSON string.
106
+
107
+ Returns:
108
+ A JSON string representing the node.
109
+
110
+ Examples:
111
+ >>> node = BaseNode(content="Example content")
112
+ >>> json_str = node.to_json()
113
+ """
66
114
  return self.model_dump_json(by_alias=True)
67
115
 
68
116
  def to_dict(self) -> Dict[str, Any]:
69
- """Converts the BaseNode instance into a dictionary."""
117
+ """
118
+ Converts the instance to a dictionary.
119
+
120
+ Returns:
121
+ A dictionary representing the node.
122
+
123
+ Examples:
124
+ >>> node = BaseNode(content="Example content")
125
+ >>> node_dict = node.to_dict()
126
+ """
70
127
  return self.model_dump(by_alias=True)
71
-
128
+
72
129
  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
-
130
+ """
131
+ Converts the instance to an XML string.
132
+
133
+ Returns:
134
+ An XML string representing the node.
135
+
136
+ Examples:
137
+ >>> node = BaseNode(content="Example content")
138
+ >>> xml_str = node.to_xml()
139
+ """
140
+ root = ET.Element(self.__class__.__name__)
141
+ for attr, value in self.to_dict().items():
142
+ child = ET.SubElement(root, attr)
143
+ child.text = str(value)
144
+ return ET.tostring(root, encoding='unicode')
145
+
146
+ def validate_content(self, schema: Dict[str, type]) -> bool:
147
+ """
148
+ Validates the node's content against a schema.
149
+
150
+ Args:
151
+ schema: The schema to validate against.
152
+
153
+ Returns:
154
+ True if the content matches the schema, False otherwise.
155
+
156
+ Examples:
157
+ >>> schema = {"title": str, "body": str}
158
+ >>> node = BaseNode(content={"title": "Example", "body": "Content"})
159
+ >>> node.validate_content(schema)
160
+ """
161
+ if not isinstance(self.content, dict):
162
+ return False
163
+ return is_schema(self.content, schema)
164
+
165
+ @property
166
+ def meta_keys(self) -> List[str]:
167
+ """
168
+ List of metadata keys.
169
+
170
+ Returns:
171
+ A list of keys in the metadata dictionary.
172
+
173
+ Examples:
174
+ >>> node = BaseNode(metadata={"author": "John Doe"})
175
+ >>> node.meta_keys
176
+ """
177
+ return list(self.metadata.keys())
178
+
179
+ def has_meta_key(self, key: str) -> bool:
180
+ """
181
+ Checks if a metadata key exists.
182
+
183
+ Args:
184
+ key: The metadata key to check for.
185
+
186
+ Returns:
187
+ True if the key exists, False otherwise.
188
+
189
+ Examples:
190
+ >>> node = BaseNode(metadata={"author": "John Doe"})
191
+ >>> node.has_meta_key("author")
192
+ """
193
+ return key in self.metadata
194
+
81
195
  def get_meta_key(self, key: str) -> Any:
82
- """Retrieves a specific metadata value by key."""
196
+ """
197
+ Retrieves a value from the metadata dictionary.
198
+
199
+ Args:
200
+ key: The key for the value to retrieve.
201
+
202
+ Returns:
203
+ The value associated with the key, if it exists.
204
+
205
+ Examples:
206
+ >>> node = BaseNode(metadata={"author": "John Doe"})
207
+ >>> node.get_meta_key("author")
208
+ """
83
209
  return self.metadata.get(key)
84
210
 
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)
211
+ def change_meta_key(self, old_key: str, new_key: str) -> bool:
212
+ """
213
+ Changes a key in the metadata dictionary.
88
214
 
89
- def delete_meta_key(self, key: str) -> None:
90
- """Deletes a metadata key from the node."""
215
+ Args:
216
+ old_key: The old key name.
217
+ new_key: The new key name.
218
+
219
+ Returns:
220
+ True if the key was changed successfully, False otherwise.
221
+
222
+ Examples:
223
+ >>> node = BaseNode(metadata={"author": "John Doe"})
224
+ >>> node.change_meta_key("author", "creator")
225
+ """
226
+ if old_key in self.metadata:
227
+ change_dict_key(self.metadata, old_key=old_key, new_key=new_key)
228
+ return True
229
+ return False
230
+
231
+ def delete_meta_key(self, key: str) -> bool:
232
+ """
233
+ Deletes a key from the metadata dictionary.
234
+
235
+ Args:
236
+ key: The key to delete.
237
+
238
+ Returns:
239
+ True if the key was deleted, False otherwise.
240
+
241
+ Examples:
242
+ >>> node = BaseNode(metadata={"author": "John Doe"})
243
+ >>> node.delete_meta_key("author")
244
+ """
91
245
  if key in self.metadata:
92
246
  del self.metadata[key]
247
+ return True
248
+ return False
93
249
 
94
- def merge_metadata(self, other_metadata: Dict[str, Any], overwrite: bool = True) -> None:
95
- """Merges another metadata dictionary into the node's metadata."""
250
+ def merge_meta(self, other_metadata: Dict[str, Any], overwrite: bool = False) -> None:
251
+ """
252
+ Merges another metadata dictionary into the current metadata.
253
+
254
+ Args:
255
+ other_metadata: The metadata dictionary to merge.
256
+ overwrite: If True, existing keys will be overwritten.
257
+
258
+ Examples:
259
+ >>> node = BaseNode(metadata={"author": "John Doe"})
260
+ >>> new_meta = {"editor": "Jane Smith"}
261
+ >>> node.merge_meta(new_meta)
262
+ """
96
263
  if not overwrite:
97
264
  other_metadata = ({
98
265
  k: v for k, v in other_metadata.items()
@@ -100,152 +267,156 @@ class BaseNode(BaseModel):
100
267
  })
101
268
  self.metadata.update(other_metadata)
102
269
 
103
- def clear_metadata(self) -> None:
104
- """Clears all metadata from the node."""
105
- self.metadata.clear()
270
+ def clear_meta(self) -> None:
271
+ """
272
+ Clears the metadata dictionary.
106
273
 
107
- @property
108
- def meta_keys(self) -> List[str]:
109
- """Returns a list of all metadata keys."""
110
- return list(self.metadata.keys())
274
+ Examples:
275
+ >>> node = BaseNode(metadata={"author": "John Doe"})
276
+ >>> node.clear_meta()
277
+ """
111
278
 
112
- def has_meta_key(self, key: str) -> bool:
113
- """Checks if a specific metadata key exists."""
114
- return key in self.metadata
279
+ self.metadata.clear()
115
280
 
116
281
  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)
282
+ """
283
+ Filters the metadata dictionary based on a filter function.
128
284
 
129
- def update_meta(self, **kwargs) -> None:
130
- """Updates metadata with the provided key-value pairs."""
131
- self.metadata.update(kwargs)
285
+ Args:
286
+ filter_func: The function to filter metadata items.
132
287
 
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)
288
+ Returns:
289
+ A dictionary containing the filtered metadata items.
137
290
 
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)
291
+ Examples:
292
+ >>> node = BaseNode(metadata={"author": "John Doe", "year": 2020})
293
+ >>> filtered_meta = node.filter_meta(lambda x: isinstance(x, str))
294
+ """
295
+ return {k: v for k, v in self.metadata.items() if filter_func(v)}
163
296
 
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]
297
+ def validate_meta(self, schema: Dict[str, type]) -> bool:
298
+ """
299
+ Validates the metadata against a schema.
167
300
 
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
301
+ Args:
302
+ schema: The schema to validate against.
172
303
 
173
- def has_label(self, label: str) -> bool:
174
- """Checks if the node has a specific label."""
175
- return self.label == label
304
+ Returns:
305
+ True if the metadata matches the schema, False otherwise.
176
306
 
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
307
+ Examples:
308
+ >>> schema = {"author": str, "year": int}
309
+ >>> node = BaseNode(metadata={"author": "John Doe", "year": 2020})
310
+ >>> node.validate_meta(schema)
311
+ """
312
+ return is_schema(dict_=self.metadata, schema=schema)
180
313
 
181
- def copy(self, n: int = 1) -> Union[List[T], T]:
314
+ def encrypt_content(self, key: str) -> None:
182
315
  """
183
- Creates one or multiple deep copies of the node.
316
+ Encrypts the node's content.
184
317
 
185
- Parameters:
186
- n (int): Number of copies to create.
318
+ Args:
319
+ key: The encryption key.
187
320
 
188
- Returns:
189
- Union[List[T], T]: A copy or list of copies of the node.
321
+ Examples:
322
+ >>> node = BaseNode(content="Sensitive information")
323
+ >>> node.encrypt_content("my_secret_key")
190
324
  """
191
- return create_copy(self, n)
325
+ self.content = EncrytionUtil.encrypt(self.content, key)
192
326
 
193
- def data_equals(self, other: 'BaseNode') -> bool:
327
+ def decrypt_content(self, key: str) -> None:
194
328
  """
195
- Checks if the node's data equals another node's data.
329
+ Decrypts the node's content.
196
330
 
197
- Parameters:
198
- other (BaseNode): Another node to compare with.
331
+ Args:
332
+ key: The decryption key.
199
333
 
200
- Returns:
201
- bool: True if data is equal, False otherwise.
334
+ Examples:
335
+ >>> node = BaseNode(content="Encrypted content")
336
+ >>> node.decrypt_content("my_secret_key")
202
337
  """
203
- return (
204
- self.content == other.content and
205
- self.metadata == other.metadata and
206
- self.related_nodes == other.related_nodes
207
- )
338
+ self.content = EncrytionUtil.decrypt(self.content, key)
208
339
 
209
- def is_copy_of(self, other: 'BaseNode') -> bool:
340
+ def add_related_node(self, node_id: str) -> bool:
210
341
  """
211
- Checks if the node is a copy of another node.
342
+ Adds a related node ID to the list of related nodes.
212
343
 
213
- Parameters:
214
- other (BaseNode): Another node to compare with.
344
+ Args:
345
+ node_id: The ID of the related node to add.
215
346
 
216
347
  Returns:
217
- bool: True if it is a copy, False otherwise.
348
+ True if the ID was added, False if it was already in the list.
349
+
350
+ Examples:
351
+ >>> node = BaseNode()
352
+ >>> related_node_id = "123456"
353
+ >>> node.add_related_node(related_node_id)
218
354
  """
219
- return (
220
- self.data_equals(other) and
221
- self is not other
222
- )
355
+ if node_id not in self.related_nodes:
356
+ self.related_nodes.append(node_id)
357
+ return True
358
+ return False
223
359
 
224
- def __eq__(self, other: 'BaseNode') -> bool:
360
+ def remove_related_node(self, node_id: str) -> bool:
225
361
  """
226
- Overrides the equality operator to compare nodes.
362
+ Removes a related node ID from the list of related nodes.
227
363
 
228
- Parameters:
229
- other (BaseNode): Another node to compare with.
364
+ Args:
365
+ node_id: The ID of the related node to remove.
230
366
 
231
367
  Returns:
232
- bool: True if nodes are equal, False otherwise.
233
- """
234
- return (self.id_ == other.id_ and self.data_equals(other))
368
+ True if the ID was removed, False if it was not in the list.
235
369
 
236
- def __str__(self) -> str:
370
+ Examples:
371
+ >>> node = BaseNode(related_nodes=["123456"])
372
+ >>> related_node_id = "123456"
373
+ >>> node.remove_related_node(related_node_id)
237
374
  """
238
- Returns a user-friendly string representation of the BaseNode.
375
+ if node_id in self.related_nodes:
376
+ self.related_nodes.remove(node_id)
377
+ return True
378
+ return False
239
379
 
240
- Returns:
241
- str: A string representation of the BaseNode.
242
- """
380
+ def __str__(self) -> str:
381
+ """String representation of the BaseNode instance."""
243
382
  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}')"
383
+ metadata_preview = str(self.metadata)[:75] + '...' if len(str(self.metadata)) > 75 else str(self.metadata)
384
+ related_nodes_preview = ', '.join(self.related_nodes[:3]) + ('...' if len(self.related_nodes) > 3 else '')
385
+ return (f"{self.__class__.__name__}(id={self.id_}, label={self.label}, "
386
+ f"content='{content_preview}', metadata='{metadata_preview}', "
387
+ f"related_nodes=[{related_nodes_preview}])")
245
388
 
246
389
  def __repr__(self):
247
- """
248
- Official string representation of Message object.
249
- Utilizes the json representation of the object for clarity.
250
- """
390
+ """Machine-readable representation of the BaseNode instance."""
251
391
  return f"{self.__class__.__name__}({self.to_json()})"
392
+
393
+ @staticmethod
394
+ def _xml_to_dict(root: ET.Element) -> Dict[str, Any]:
395
+ data = {}
396
+ for child in root:
397
+ data[child.tag] = child.text
398
+ return data
399
+
400
+
401
+ # def is_empty(self) -> bool:
402
+ # return not self.content and not self.metadata
403
+
404
+ # def copy(self, n: int = 1) -> Union[List[T], T]:
405
+ # return create_copy(self, n)
406
+
407
+ # def data_equals(self, other: 'BaseNode') -> bool:
408
+ # return (
409
+ # self.content == other.content and
410
+ # self.metadata == other.metadata and
411
+ # self.related_nodes == other.related_nodes
412
+ # )
413
+
414
+ # def is_copy_of(self, other: 'BaseNode') -> bool:
415
+ # return (
416
+ # self.data_equals(other) and
417
+ # self is not other
418
+ # )
419
+
420
+ # def __eq__(self, other: 'BaseNode') -> bool:
421
+ # # return (self.id_ == other.id_ and self.data_equals(other))
422
+ # return self.id_ == other.id_
@@ -3,7 +3,22 @@ from pydantic import field_serializer
3
3
  from .base_node import BaseNode
4
4
 
5
5
  class Tool(BaseNode):
6
- # name: str = None
6
+ """
7
+ A class representing a tool with a function, content, parser, and schema.
8
+
9
+ Attributes:
10
+ func (Callable): The function associated with the tool.
11
+ content (Any, optional): The content to be processed by the tool. Defaults to None.
12
+ parser (Any, optional): The parser to be used with the tool. Defaults to None.
13
+ schema_ (Dict): The schema definition for the tool.
14
+
15
+ Examples:
16
+ >>> tool = Tool(func=my_function, schema_={'type': 'string'})
17
+ >>> serialized_func = tool.serialize_func()
18
+ >>> print(serialized_func)
19
+ 'my_function'
20
+ """
21
+
7
22
  func: Any
8
23
  content: Any = None
9
24
  parser: Any = None
@@ -11,4 +26,19 @@ class Tool(BaseNode):
11
26
 
12
27
  @field_serializer('func')
13
28
  def serialize_func(self, func):
29
+ """
30
+ Serialize the function to its name.
31
+
32
+ Args:
33
+ func (Callable): The function to serialize.
34
+
35
+ Returns:
36
+ str: The name of the function.
37
+
38
+ Examples:
39
+ >>> def my_function():
40
+ ... pass
41
+ >>> Tool.serialize_func(my_function)
42
+ 'my_function'
43
+ """
14
44
  return func.__name__