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.
- lionagi/__init__.py +7 -4
- lionagi/bridge/__init__.py +19 -4
- lionagi/bridge/langchain.py +23 -3
- lionagi/bridge/llama_index.py +5 -3
- lionagi/configs/__init__.py +1 -1
- lionagi/configs/oai_configs.py +88 -1
- lionagi/core/__init__.py +6 -9
- lionagi/core/conversations/__init__.py +5 -0
- lionagi/core/conversations/conversation.py +107 -0
- lionagi/core/flows/__init__.py +8 -0
- lionagi/core/flows/flow.py +8 -0
- lionagi/core/flows/flow_util.py +62 -0
- lionagi/core/instruction_set/__init__.py +5 -0
- lionagi/core/instruction_set/instruction_sets.py +7 -0
- lionagi/core/sessions/__init__.py +5 -0
- lionagi/core/sessions/sessions.py +187 -0
- lionagi/endpoints/__init__.py +5 -0
- lionagi/endpoints/assistants.py +0 -0
- lionagi/endpoints/audio.py +17 -0
- lionagi/endpoints/chatcompletion.py +54 -0
- lionagi/endpoints/embeddings.py +0 -0
- lionagi/endpoints/finetune.py +0 -0
- lionagi/endpoints/image.py +0 -0
- lionagi/endpoints/moderation.py +0 -0
- lionagi/endpoints/vision.py +0 -0
- lionagi/{loader → loaders}/__init__.py +7 -1
- lionagi/{loader → loaders}/chunker.py +6 -12
- lionagi/{utils/load_utils.py → loaders/load_util.py} +47 -6
- lionagi/{loader → loaders}/reader.py +4 -12
- lionagi/messages/__init__.py +11 -0
- lionagi/messages/instruction.py +15 -0
- lionagi/messages/message.py +110 -0
- lionagi/messages/response.py +33 -0
- lionagi/messages/system.py +12 -0
- lionagi/objs/__init__.py +10 -6
- lionagi/objs/abc_objs.py +39 -0
- lionagi/objs/async_queue.py +135 -0
- lionagi/objs/messenger.py +70 -148
- lionagi/objs/status_tracker.py +37 -0
- lionagi/objs/{tool_registry.py → tool_manager.py} +8 -6
- lionagi/schema/__init__.py +3 -3
- lionagi/schema/base_node.py +251 -0
- lionagi/schema/base_tool.py +8 -3
- lionagi/schema/data_logger.py +2 -3
- lionagi/schema/data_node.py +37 -0
- lionagi/services/__init__.py +1 -4
- lionagi/services/base_api_service.py +15 -5
- lionagi/services/oai.py +2 -2
- lionagi/services/openrouter.py +2 -3
- lionagi/structures/graph.py +96 -0
- lionagi/{structure → structures}/relationship.py +10 -2
- lionagi/structures/structure.py +102 -0
- lionagi/tests/test_api_util.py +46 -0
- lionagi/tests/test_call_util.py +115 -0
- lionagi/tests/test_convert_util.py +202 -0
- lionagi/tests/test_encrypt_util.py +33 -0
- lionagi/tests/{test_flatten_util.py → test_flat_util.py} +1 -1
- lionagi/tests/test_io_util.py +0 -0
- lionagi/tests/test_sys_util.py +0 -0
- lionagi/tools/__init__.py +5 -0
- lionagi/tools/tool_util.py +7 -0
- lionagi/utils/__init__.py +55 -35
- lionagi/utils/api_util.py +19 -17
- lionagi/utils/call_util.py +2 -1
- lionagi/utils/convert_util.py +229 -0
- lionagi/utils/encrypt_util.py +16 -0
- lionagi/utils/flat_util.py +38 -0
- lionagi/utils/io_util.py +2 -2
- lionagi/utils/sys_util.py +45 -10
- lionagi/version.py +1 -1
- {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/METADATA +2 -2
- lionagi-0.0.116.dist-info/RECORD +110 -0
- lionagi/core/conversations.py +0 -108
- lionagi/core/flows.py +0 -1
- lionagi/core/instruction_sets.py +0 -1
- lionagi/core/messages.py +0 -166
- lionagi/core/sessions.py +0 -297
- lionagi/schema/base_schema.py +0 -252
- lionagi/services/chatcompletion.py +0 -48
- lionagi/services/service_objs.py +0 -282
- lionagi/structure/structure.py +0 -160
- lionagi/tools/coder.py +0 -1
- lionagi/tools/sandbox.py +0 -1
- lionagi/utils/tool_util.py +0 -92
- lionagi/utils/type_util.py +0 -81
- lionagi-0.0.114.dist-info/RECORD +0 -84
- /lionagi/configs/{openrouter_config.py → openrouter_configs.py} +0 -0
- /lionagi/{datastore → datastores}/__init__.py +0 -0
- /lionagi/{datastore → datastores}/chroma.py +0 -0
- /lionagi/{datastore → datastores}/deeplake.py +0 -0
- /lionagi/{datastore → datastores}/elasticsearch.py +0 -0
- /lionagi/{datastore → datastores}/lantern.py +0 -0
- /lionagi/{datastore → datastores}/pinecone.py +0 -0
- /lionagi/{datastore → datastores}/postgres.py +0 -0
- /lionagi/{datastore → datastores}/qdrant.py +0 -0
- /lionagi/{structure → structures}/__init__.py +0 -0
- {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/LICENSE +0 -0
- {lionagi-0.0.114.dist-info → lionagi-0.0.116.dist-info}/WHEEL +0 -0
- {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
|
-
|
1
|
+
from collections import deque
|
2
|
+
from typing import Optional, Any, Union, Dict, Tuple
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
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
|
-
|
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
|
-
|
19
|
-
|
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
|
-
|
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
|
-
|
20
|
+
def log_message(self, msg: Message) -> None:
|
21
|
+
self._logger(msg.to_json())
|
28
22
|
|
29
|
-
|
30
|
-
|
23
|
+
def to_csv(self, **kwargs) -> None:
|
24
|
+
self._logger.to_csv(**kwargs)
|
31
25
|
|
32
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
|
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
|
-
|
75
|
-
|
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
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
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
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
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
|
5
|
-
from
|
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
|
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.
|
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
|
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
|
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_)
|
lionagi/schema/__init__.py
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
from .
|
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()})"
|
lionagi/schema/base_tool.py
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
from typing import Any
|
2
|
-
from
|
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_:
|
10
|
+
schema_: dict
|
11
|
+
|
12
|
+
@field_serializer('func')
|
13
|
+
def serialize_func(self, func):
|
14
|
+
return func.__name__
|
lionagi/schema/data_logger.py
CHANGED
@@ -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
|
+
...
|
lionagi/services/__init__.py
CHANGED
@@ -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
|
]
|