lionagi 0.0.104__py3-none-any.whl → 0.0.106__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,87 +2,92 @@ from .message import Message
2
2
 
3
3
  class Conversation:
4
4
  """
5
- A class modeling conversations and managing messages within the conversation.
5
+ A class representing a conversation between users and the assistant.
6
6
 
7
- This class facilitates the organization and manipulation of messages in a conversation.
8
- It includes methods for initiating a conversation, adding messages, changing the system message,
9
- appending the last response, and keeping the last N exchanges.
7
+ This class manages the exchange of messages within a conversation, including system settings,
8
+ user instructions, and assistant responses.
10
9
 
11
10
  Attributes:
12
- response_counts: A class-level attribute to track the number of responses.
13
- messages: A list containing messages in the conversation.
14
- msg: An instance of the Message class for creating and processing messages.
15
- responses: A list containing response messages.
11
+ response_counts (int): The count of assistant responses in the conversation.
12
+ messages (list): A list to store messages in the conversation.
13
+ msg (Message): An instance of the Message class for creating messages.
14
+ responses (list): A list to store assistant responses in the conversation.
16
15
 
17
16
  Methods:
18
- initiate_conversation: Start a new conversation with system and user instructions.
19
- add_messages: Add messages to the conversation.
20
- change_system: Change the system message in the conversation.
21
- append_last_response: Append the last response to the conversation.
22
- keep_last_n_exchanges: Keep only the last N exchanges in the conversation.
17
+ initiate_conversation(system, instruction, context=None, name=None):
18
+ Initiate a conversation with a system setting and user instruction.
19
+
20
+ add_messages(system, instruction, context=None, response=None, tool=None, name=None):
21
+ Add messages to the conversation, including system setting, user instruction, and assistant response.
22
+
23
+ change_system(system):
24
+ Change the system setting in the conversation.
25
+
26
+ keep_last_n_exchanges(n: int):
27
+ Keep the last n exchanges in the conversation.
23
28
  """
24
-
25
29
  response_counts = 0
26
30
 
27
31
  def __init__(self, messages=None) -> None:
28
32
  """
29
33
  Initialize a Conversation object.
30
34
 
31
- Args:
32
- messages: A list of messages to initialize the conversation.
35
+ Parameters:
36
+ messages (list): A list of messages to initialize the conversation. Default is None.
37
+
33
38
  """
34
39
  self.messages = messages or []
35
40
  self.msg = Message()
36
41
  self.responses = []
37
42
 
38
- def initiate_conversation(self, system, instruction, context=None):
43
+ def initiate_conversation(self, system=None, instruction=None, context=None, name=None):
39
44
  """
40
- Start a new conversation with a system message and an instruction.
45
+ Initiate a conversation with a system setting and user instruction.
41
46
 
42
- Args:
43
- system: The content of the system message.
44
- instruction: The content of the user instruction.
45
- context: Additional context for the user instruction.
47
+ Parameters:
48
+ system (str): The system setting for the conversation.
49
+ instruction (str): The user instruction to initiate the conversation.
50
+ context (dict): Additional context for the conversation. Default is None.
51
+ name (str): The name associated with the user. Default is None.
46
52
  """
47
53
  self.messages, self.responses = [], []
48
54
  self.add_messages(system=system)
49
- self.add_messages(instruction=instruction, context=context)
55
+ self.add_messages(instruction=instruction, context=context, name=name)
50
56
 
51
- def add_messages(self, system=None, instruction=None, context=None, response=None):
57
+ # modify the message adding to accomodate tools
58
+ def add_messages(self, system=None, instruction=None, context=None, response=None, name=None):
52
59
  """
53
- Add messages to the conversation.
60
+ Add messages to the conversation, including system setting, user instruction, and assistant response.
54
61
 
55
- Args:
56
- system: The content of the system message.
57
- instruction: The content of the user instruction.
58
- context: Additional context for the user instruction.
59
- response: The content of the assistant's response.
62
+ Parameters:
63
+ system (str): The system setting for the message. Default is None.
64
+ instruction (str): The instruction content for the message. Default is None.
65
+ context (dict): Additional context for the message. Default is None.
66
+ response (dict): The response content for the message. Default is None.
67
+ tool (dict): The tool information for the message. Default is None.
68
+ name (str): The name associated with the message. Default is None.
60
69
  """
61
- msg = self.msg(system=system, instruction=instruction, response=response, context=context)
70
+ msg = self.msg(system=system, instruction=instruction, context=context,
71
+ response=response, name=name)
62
72
  self.messages.append(msg)
63
73
 
64
74
  def change_system(self, system):
65
75
  """
66
- Change the system message in the conversation.
76
+ Change the system setting in the conversation.
67
77
 
68
- Args:
69
- system: The new content for the system message.
78
+ Parameters:
79
+ system (str): The new system setting for the conversation.
70
80
  """
71
81
  self.messages[0] = self.msg(system=system)
72
82
 
73
- def append_last_response(self):
74
- """
75
- Append the last response to the conversation.
76
- """
77
- self.add_messages(response=self.responses[-1])
78
-
79
83
  def keep_last_n_exchanges(self, n: int):
80
84
  """
81
- Keep only the last N exchanges in the conversation.
85
+ Keep the last n exchanges in the conversation.
82
86
 
83
- Args:
84
- n: The number of exchanges to keep.
87
+ Parameters:
88
+ n (int): The number of exchanges to keep.
85
89
  """
90
+ # keep last n_exchanges, one exchange is marked by one assistant response
86
91
  response_indices = [
87
92
  index for index, message in enumerate(self.messages[1:]) if message["role"] == "assistant"
88
93
  ]
@@ -1,76 +1,142 @@
1
1
  from datetime import datetime
2
2
  import json
3
- from ..utils.sys_util import create_id
3
+ from ..utils.sys_util import create_id, l_call
4
4
  from ..utils.log_util import DataLogger
5
5
 
6
6
 
7
7
  class Message:
8
8
  """
9
- A class modeling messages in conversations.
9
+ A class representing a message in a conversation.
10
10
 
11
- This class is designed to encapsulate messages exchanged between different roles
12
- (user, assistant, or system) in a conversation. It includes functionality to process,
13
- log, and manage messages.
11
+ This class encapsulates messages from users, the assistant, systems, and external tools.
14
12
 
15
13
  Attributes:
16
- role: The role of the message (user, assistant, or system).
17
- content: The content of the message.
18
- sender: The sender of the message.
19
- logger: An instance of DataLogger for logging message information.
14
+ role (str): The role of the message, indicating if it's from the user, assistant, system, or tool.
15
+ content: The content of the message, which can be an instruction, response, system setting, or tool information.
16
+ name (str): The name associated with the message, specifying the source (user, assistant, system, or tool).
17
+ metadata (dict): Additional metadata including id, timestamp, and name.
18
+ _logger (DataLogger): An instance of the DataLogger class for logging message details.
20
19
 
21
20
  Methods:
22
- __call__: Process and log a message based on its role.
21
+ create_message(system, instruction, context, response, tool, name):
22
+ Create a message based on the provided information.
23
+
24
+ to_json() -> dict:
25
+ Convert the message to a JSON format.
26
+
27
+ __call__(system, instruction, context, response, name, tool) -> dict:
28
+ Create and return a message in JSON format.
29
+
30
+ to_csv(dir, filename, verbose, timestamp, dir_exist_ok, file_exist_ok):
31
+ Save the message to a CSV file.
23
32
  """
24
33
  def __init__(self) -> None:
25
34
  """
26
- Initialize a Message object with attributes for role, content, sender, and a DataLogger.
35
+ Initialize a Message object.
27
36
  """
28
37
  self.role = None
29
38
  self.content = None
30
- self.sender = None
31
- self.logger = DataLogger()
39
+ self.name = None
40
+ self.metadata = None
41
+ self._logger = DataLogger()
42
+
43
+ def create_message(self, system=None, instruction=None, context=None, response=None, name=None):
32
44
 
33
- def __call__(self, system=None, instruction=None, response=None, context=None, sender=None):
34
45
  """
35
- Process and log a message based on the specified role (system, instruction, or response).
46
+ Create a message based on the provided information.
36
47
 
37
- Args:
38
- system: The content of the message in the system role.
39
- instruction: The content of the message in the user role.
40
- response: The content of the message in the assistant role.
41
- context: Additional context for the user instruction.
42
- sender: The sender of the message.
48
+ Parameters:
49
+ system (str): The system setting for the message. Default is None.
50
+ instruction (str): The instruction content for the message. Default is None.
51
+ context (dict): Additional context for the message. Default is None.
52
+ response (dict): The response content for the message. Default is None.
53
+ tool (dict): The tool information for the message. Default is None.
54
+ name (str): The name associated with the message. Default is None.
43
55
  """
56
+ if sum(l_call([system, instruction, response], bool)) > 1:
57
+ raise ValueError("Error: Message cannot have more than one role.")
44
58
 
45
- if sum(map(bool, [system, instruction, response])) > 1:
46
- raise ValueError("Message cannot have more than one role.")
47
- else:
59
+ else:
48
60
  if response:
49
61
  self.role = "assistant"
50
- self.sender = sender or "assistant"
51
- self.content = response['content']
62
+ try:
63
+ response = response["message"]
64
+ if str(response['content']) == "None":
65
+ try:
66
+ if response['tool_calls'][0]['type'] == 'function':
67
+ self.name = name or ("func_" + response['tool_calls'][0]['function']['name'])
68
+ content = response['tool_calls'][0]['function']['arguments']
69
+ self.content = {"function":self.name, "arguments": content}
70
+ except:
71
+ raise ValueError("Response message must be one of regular response or function calling")
72
+ else:
73
+ self.content = response['content']
74
+ self.name = name or "assistant"
75
+ except:
76
+ self.name = name or "func_call"
77
+ self.content = {"function call result": response}
78
+
52
79
  elif instruction:
53
80
  self.role = "user"
54
- self.sender = sender or "user"
55
81
  self.content = {"instruction": instruction}
82
+ self.name = name or "user"
56
83
  if context:
57
- self.content.update(context)
84
+ self.content.update({"context": context})
58
85
  elif system:
59
86
  self.role = "system"
60
- self.sender = sender or "system"
61
87
  self.content = system
88
+ self.name = name or "system"
89
+
90
+ def to_json(self):
91
+ """
92
+ Convert the message to a JSON format.
93
+
94
+ Returns:
95
+ - dict: The message in JSON format.
96
+ """
62
97
  out = {
63
98
  "role": self.role,
64
99
  "content": json.dumps(self.content) if isinstance(self.content, dict) else self.content
65
100
  }
66
-
67
- a = {**{
101
+
102
+ self.metadata = {
68
103
  "id": create_id(),
69
104
  "timestamp": datetime.now().isoformat(),
70
- "sender": self.sender
71
- }, **out}
72
- self.logger(a)
105
+ "name": self.name}
106
+
107
+ self._logger({**self.metadata, **out})
73
108
  return out
109
+
110
+ def __call__(self, system=None, instruction=None, context=None,
111
+ response=None, name=None):
112
+ """
113
+ Create and return a message in JSON format.
114
+
115
+ Parameters:
116
+ system (str): The system setting for the message. Default is None.
117
+ instruction (str): The instruction content for the message. Default is None.
118
+ context (dict): Additional context for the message. Default is None.
119
+ response (dict): The response content for the message. Default is None.
120
+ name (str): The name associated with the message. Default is None.
121
+ tool (dict): The tool information for the message. Default is None.
122
+
123
+ Returns:
124
+ dict: The message in JSON format.
125
+ """
126
+ self.create_message(system=system, instruction=instruction,
127
+ context=context, response=response, name=name)
128
+ return self.to_json()
74
129
 
75
- def _to_csv(self, dir, filename, verbose=True, timestamp=True, dir_exist_ok=True, file_exist_ok=False):
76
- self.logger.to_csv(dir, filename, verbose, timestamp, dir_exist_ok, file_exist_ok)
130
+ def to_csv(self, dir=None, filename=None, verbose=True, timestamp=True, dir_exist_ok=True, file_exist_ok=False):
131
+ """
132
+ Save the message to a CSV file.
133
+
134
+ Parameters:
135
+ dir (str): The directory path for saving the CSV file. Default is None.
136
+ filename (str): The filename for the CSV file. Default is None.
137
+ verbose (bool): Whether to include verbose information in the CSV. Default is True.
138
+ timestamp (bool): Whether to include timestamps in the CSV. Default is True.
139
+ dir_exist_ok (bool): Whether to allow the directory to exist. Default is True.
140
+ file_exist_ok (bool): Whether to allow the file to exist. Default is False.
141
+ """
142
+ self._logger.to_csv(dir, filename, verbose, timestamp, dir_exist_ok, file_exist_ok)
@@ -1,110 +1,225 @@
1
1
  import aiohttp
2
2
  import asyncio
3
+ import json
3
4
  from typing import Any
4
5
 
5
6
  from .conversation import Conversation
6
- from ..api.oai_config import oai_llmconfig
7
+ from ..utils.sys_util import to_list
7
8
  from ..utils.log_util import DataLogger
8
9
  from ..utils.api_util import StatusTracker
10
+ from ..utils.tool_util import ToolManager
9
11
  from ..api.oai_service import OpenAIService
10
12
 
13
+ from ..api.oai_config import oai_llmconfig
14
+
11
15
 
12
16
  status_tracker = StatusTracker()
13
17
  OAIService = OpenAIService()
14
18
 
15
19
  class Session():
16
20
  """
17
- A class representing a conversation session with chat completion capabilities.
21
+ A class representing a conversation session with a conversational AI system.
18
22
 
19
- This class manages conversations, interacts with chat completion services (currently OpenAI),
20
- and logs the interactions using a DataLogger.
23
+ This class manages the flow of conversation, system settings, and interactions with external tools.
21
24
 
22
25
  Attributes:
23
- conversation: An instance of the Conversation class for managing messages.
24
- system: The system identifier for the conversation session.
25
- llmconfig: Configuration parameters for language models.
26
- logger: An instance of DataLogger for logging conversation interactions.
27
- api_service: An instance of the API service for making asynchronous API calls.
26
+ conversation (Conversation): An instance of the Conversation class to manage messages.
27
+ system (str): The current system setting for the conversation.
28
+ llmconfig (dict): Configuration settings for the language model.
29
+ _logger (DataLogger): An instance of the DataLogger class for logging conversation details.
30
+ api_service: An instance of the API service for making calls to the conversational AI model.
31
+ toolmanager (ToolManager): An instance of the ToolManager class for managing external tools.
28
32
 
29
33
  Methods:
30
- initiate: Initiate a conversation session with the given instruction.
31
- followup: Continue the conversation session with a follow-up instruction.
32
- create_payload_chatcompletion: Create a payload for chat completion API calls.
33
- call_chatcompletion: Make an asynchronous call to the chat completion API.
34
+ set_dir(dir):
35
+ Set the directory for logging.
36
+
37
+ set_system(system):
38
+ Set the system for the conversation.
39
+
40
+ set_llmconfig(llmconfig):
41
+ Set the language model configuration.
42
+
43
+ set_api_service(api_service):
44
+ Set the API service for making model calls.
45
+
46
+ _output(output, invoke=True, out=True) -> Any:
47
+ Process the output, invoke tools if needed, and optionally return the output.
48
+
49
+ register_tools(tools, funcs, update=False, new=False, prefix=None, postfix=None):
50
+ Register tools and their corresponding functions.
51
+
52
+ initiate(instruction, system=None, context=None, out=True, name=None, invoke=True, **kwargs) -> Any:
53
+ Start a new conversation session with the provided instruction.
54
+
55
+ followup(instruction, system=None, context=None, out=True, name=None, invoke=True, **kwargs) -> Any:
56
+ Continue the conversation with the provided instruction.
57
+
58
+ create_payload_chatcompletion(**kwargs) -> dict:
59
+ Create a payload for chat completion based on the conversation state and configuration.
60
+
61
+ call_chatcompletion(sleep=0.1, **kwargs) -> None:
62
+ Make a call to the chat completion API and process the response.
63
+
64
+ messages_to_csv(dir=None, filename="_messages.csv", **kwargs) -> None:
65
+ Save conversation messages to a CSV file.
66
+
67
+ log_to_csv(dir=None, filename="_llmlog.csv", **kwargs) -> None:
68
+ Save conversation logs to a CSV file.
34
69
  """
35
70
 
36
71
  def __init__(self, system, dir=None, llmconfig=oai_llmconfig, api_service=OAIService):
37
72
  """
38
- Initialize a Session object.
73
+ Initialize a Session object with default or provided settings.
39
74
 
40
- Args:
41
- system: The system identifier for the conversation session.
42
- dir: The directory for logging interactions.
43
- llmconfig: Configuration parameters for language models.
44
- api_service: An instance of the API service for making asynchronous API calls.
75
+ Parameters:
76
+ system (str): The initial system setting for the conversation.
77
+ dir (Optional[str]): The directory for logging. Default is None.
78
+ llmconfig (Optional[dict]): Configuration settings for the language model. Default is oai_llmconfig.
79
+ api_service: An instance of the API service for making calls to the conversational AI model.
45
80
  """
46
81
  self.conversation = Conversation()
47
82
  self.system = system
48
83
  self.llmconfig = llmconfig
49
- self.logger = DataLogger(dir=dir)
84
+ self._logger = DataLogger(dir=dir)
50
85
  self.api_service = api_service
86
+ self.toolmanager = ToolManager()
51
87
 
52
- async def initiate(self, instruction, system=None, context=None, out=True, **kwargs) -> Any:
88
+ def set_dir(self, dir):
53
89
  """
54
- Initiate a conversation session with the given instruction.
90
+ Set the directory for logging.
55
91
 
56
- Args:
57
- instruction: The user's instruction to initiate the conversation.
58
- system: The content of the system message.
59
- context: Additional context for the user instruction.
60
- out: Whether to return the output content.
92
+ Parameters:
93
+ dir (str): The directory path.
94
+ """
95
+ self._logger.dir = dir
96
+
97
+ def set_system(self, system):
98
+ """
99
+ Set the system for the conversation.
100
+
101
+ Parameters:
102
+ system (str): The system setting.
103
+ """
104
+ self.conversation.change_system(system)
105
+
106
+ def set_llmconfig(self, llmconfig):
107
+ """
108
+ Set the language model configuration.
109
+
110
+ Parameters:
111
+ llmconfig (dict): Configuration settings for the language model.
112
+ """
113
+ self.llmconfig = llmconfig
114
+
115
+ def set_api_service(self, api_service):
116
+ """
117
+ Set the API service for making model calls.
118
+
119
+ Parameters:
120
+ api_service: An instance of the API service.
121
+ """
122
+ self.api_service = api_service
123
+
124
+ async def _output(self, invoke=True, out=True, tool_parser=None):
125
+ """
126
+ Process the output, invoke tools if needed, and optionally return the output.
127
+
128
+ Parameters:
129
+ output: The output to process.
130
+ invoke (bool): Whether to invoke tools based on the output. Default is True.
131
+ out (bool): Whether to return the output. Default is True.
61
132
 
62
133
  Returns:
63
- Any: The output content if 'out' is True, otherwise None.
134
+ Any: The processed output.
135
+ """
136
+ if invoke:
137
+ try:
138
+ func, args = self.toolmanager._get_function_call(self.conversation.responses[-1]['content'])
139
+ outs = await self.toolmanager.ainvoke(func, args)
140
+ outs = tool_parser(outs) if tool_parser else outs
141
+ self.conversation.add_messages(response=outs)
142
+ except:
143
+ pass
144
+ if out:
145
+ return self.conversation.responses[-1]['content']
146
+
147
+ def register_tools(self, tools, funcs, update=False, new=False, prefix=None, postfix=None):
148
+ """
149
+ Register tools and their corresponding functions.
150
+
151
+ Parameters:
152
+ tools (list): The list of tool information dictionaries.
153
+ funcs (list): The list of corresponding functions.
154
+ update (bool): Whether to update existing functions.
155
+ new (bool): Whether to create new registries for existing functions.
156
+ prefix (Optional[str]): A prefix to add to the function names.
157
+ postfix (Optional[str]): A postfix to add to the function names.
158
+ """
159
+ funcs = to_list(funcs)
160
+ self.toolmanager.register_tools(tools, funcs, update, new, prefix, postfix)
161
+
162
+ async def initiate(self, instruction, system=None, context=None, name=None, invoke=True, out=True, tool_parser=None, **kwargs) -> Any:
163
+ """
164
+ Start a new conversation session with the provided instruction.
165
+
166
+ Parameters:
167
+ instruction (str): The instruction to initiate the conversation.
168
+ system (Optional[str]): The system setting for the conversation. Default is None.
169
+ context (Optional[dict]): Additional context for the instruction. Default is None.
170
+ out (bool): Whether to return the output. Default is True.
171
+ name (Optional[str]): The name associated with the instruction. Default is None.
172
+ invoke (bool): Whether to invoke tools based on the output. Default is True.
173
+ kwargs: Additional keyword arguments for configuration.
174
+
175
+ Returns:
176
+ Any: The processed output.
64
177
  """
65
178
  config = {**self.llmconfig, **kwargs}
66
179
  system = system or self.system
67
- self.conversation.initiate_conversation(system=system, instruction=instruction, context=context)
68
-
180
+ self.conversation.initiate_conversation(system=system, instruction=instruction, context=context, name=name)
69
181
  await self.call_chatcompletion(**config)
70
- if out:
71
- return self.conversation.responses[-1]['content']
182
+
183
+ return await self._output(invoke, out, tool_parser)
72
184
 
73
- async def followup(self, instruction, system=None, context=None, out=True, **kwargs) -> Any:
185
+ async def followup(self, instruction, system=None, context=None, out=True, name=None, invoke=True, tool_parser=None, **kwargs) -> Any:
74
186
  """
75
- Continue the conversation session with a follow-up instruction.
187
+ Continue the conversation with the provided instruction.
76
188
 
77
- Args:
78
- instruction: The user's follow-up instruction.
79
- system: The content of the system message.
80
- context: Additional context for the user instruction.
81
- out: Whether to return the output content.
189
+ Parameters:
190
+ instruction (str): The instruction to continue the conversation.
191
+ system (Optional[str]): The system setting for the conversation. Default is None.
192
+ context (Optional[dict]): Additional context for the instruction. Default is None.
193
+ out (bool): Whether to return the output. Default is True.
194
+ name (Optional[str]): The name associated with the instruction. Default is None.
195
+ invoke (bool): Whether to invoke tools based on the output. Default is True.
196
+ kwargs: Additional keyword arguments for configuration.
82
197
 
83
198
  Returns:
84
- Any: The output content if 'out' is True, otherwise None.
199
+ Any: The processed output.
85
200
  """
86
- self.conversation.append_last_response()
87
201
  if system:
88
202
  self.conversation.change_system(system)
89
- self.conversation.add_messages(instruction=instruction, context=context)
90
-
203
+ self.conversation.add_messages(instruction=instruction, context=context, name=name)
91
204
  config = {**self.llmconfig, **kwargs}
92
205
  await self.call_chatcompletion(**config)
93
- if out:
94
- return self.conversation.responses[-1]['content']
206
+
207
+
208
+ return await self._output(invoke, out, tool_parser)
95
209
 
96
210
  def create_payload_chatcompletion(self, **kwargs):
97
211
  """
98
- Create a payload for chat completion API calls.
212
+ Create a payload for chat completion based on the conversation state and configuration.
99
213
 
100
- Args:
101
- kwargs: Additional keyword arguments for customization.
214
+ Parameters:
215
+ kwargs: Additional keyword arguments for configuration.
216
+
217
+ Returns:
218
+ dict: The payload for chat completion.
102
219
  """
103
220
  # currently only openai chat completions are supported
104
221
  messages = self.conversation.messages
105
-
106
222
  config = {**self.llmconfig, **kwargs}
107
-
108
223
  payload = {
109
224
  "messages": messages,
110
225
  "model": config.get('model'),
@@ -117,34 +232,30 @@ class Session():
117
232
  }
118
233
 
119
234
  for key in ["seed", "stop", "stream", "tools", "tool_choice", "user", "max_tokens"]:
120
- if config[key] is True:
235
+ if bool(config[key]) is True and str(config[key]) != "none":
121
236
  payload.update({key: config[key]})
122
-
123
237
  return payload
124
-
125
- async def call_chatcompletion(self, delay=1, **kwargs):
238
+
239
+ async def call_chatcompletion(self, sleep=0.1, **kwargs):
126
240
  """
127
- Make an asynchronous call to the chat completion API.
241
+ Make a call to the chat completion API and process the response.
128
242
 
129
- Args:
130
- delay: The delay (in seconds) between API calls.
131
- kwargs: Additional keyword arguments for customization.
243
+ Parameters:
244
+ sleep (float): The sleep duration after making the API call. Default is 0.1.
245
+ kwargs: Additional keyword arguments for configuration.
132
246
  """
133
- # currently only openai chat completions are supported
134
-
135
247
  endpoint = f"chat/completions"
136
248
  try:
137
249
  async with aiohttp.ClientSession() as session:
250
+ payload = self.create_payload_chatcompletion(**kwargs)
138
251
  completion = await self.api_service.call_api(
139
- session, endpoint,
140
- self.create_payload_chatcompletion(**kwargs))
252
+ session, endpoint, payload)
141
253
  if "choices" in completion:
142
- completion = completion['choices'][0] # currently can only call one completion at a time, n has to be 1
143
- self.logger({"input":self.conversation.messages, "output": completion})
144
- response = {"role": "assistant", "content": completion['message']["content"]}
145
- self.conversation.responses.append(response)
254
+ self._logger({"input":payload, "output": completion})
255
+ self.conversation.add_messages(response=completion['choices'][0])
256
+ self.conversation.responses.append(self.conversation.messages[-1])
146
257
  self.conversation.response_counts += 1
147
- await asyncio.sleep(delay=delay)
258
+ await asyncio.sleep(sleep)
148
259
  status_tracker.num_tasks_succeeded += 1
149
260
  else:
150
261
  status_tracker.num_tasks_failed += 1
@@ -153,13 +264,46 @@ class Session():
153
264
  raise e
154
265
 
155
266
  def messages_to_csv(self, dir=None, filename="_messages.csv", **kwags):
156
- dir = dir or self.logger.dir
267
+ """
268
+ Save conversation messages to a CSV file.
269
+
270
+ Parameters:
271
+ dir (Optional[str]): The directory path for saving the CSV file. Default is None.
272
+ filename (Optional[str]): The filename for the CSV file. Default is "_messages.csv".
273
+ kwargs: Additional keyword arguments for CSV file settings.
274
+ """
275
+ dir = dir or self._logger.dir
157
276
  if dir is None:
158
277
  raise ValueError("No directory specified.")
159
- self.conversation.msg._to_csv(dir=dir, filename=filename, **kwags)
278
+ self.conversation.msg.to_csv(dir=dir, filename=filename, **kwags)
160
279
 
161
280
  def log_to_csv(self, dir=None, filename="_llmlog.csv", **kwags):
162
- dir = dir or self.logger.dir
281
+ """
282
+ Save conversation logs to a CSV file.
283
+
284
+ Parameters:
285
+ dir (Optional[str]): The directory path for saving the CSV file. Default is None.
286
+ filename (Optional[str]): The filename for the CSV file. Default is "_llmlog.csv".
287
+ kwargs: Additional keyword arguments for CSV file settings.
288
+ """
289
+ dir = dir or self._logger.dir
163
290
  if dir is None:
164
291
  raise ValueError("No directory specified.")
165
- self.logger.to_csv(dir=dir, filename=filename, **kwags)
292
+ self._logger.to_csv(dir=dir, filename=filename, **kwags)
293
+
294
+ def is_invoked(self):
295
+ msg = self.conversation.messages[-1]
296
+ try:
297
+ if "function call result" in json.loads(msg['content']).keys():
298
+ return True
299
+ except:
300
+ return False
301
+
302
+ async def auto_followup(self, instruct, num=3, tool_parser=None, **kwags):
303
+ cont_ = True
304
+ while num > 0 and cont_ is True:
305
+ await self.followup(instruct,tool_parser=tool_parser, tool_choice="auto", **kwags)
306
+ num -= 1
307
+ cont_ = True if self.is_invoked() else False
308
+ if num == 0:
309
+ await self.followup(instruct, **kwags)
File without changes
lionagi/utils/__init__.py CHANGED
@@ -1,9 +1,10 @@
1
1
  from .sys_util import to_flat_dict, append_to_jsonl, to_list, str_to_num, make_copy, to_temp, to_csv, hold_call, ahold_call, l_call, al_call, m_call, am_call, e_call, ae_call, get_timestamp, create_path
2
2
  from .doc_util import dir_to_path, read_text, dir_to_files, chunk_text, file_to_chunks, file_to_chunks, get_bins
3
3
  from .log_util import DataLogger
4
+ from .tool_util import ToolManager
4
5
 
5
6
  __all__ = [
6
7
  "to_list", "str_to_num", "make_copy", "to_temp", "to_csv", "hold_call", "ahold_call", "l_call", "al_call", "m_call", "am_call", "e_call", "ae_call", "get_timestamp", "create_path", "to_flat_dict", "append_to_jsonl",
7
8
  "dir_to_path", "read_text", "dir_to_files", "chunk_text", "file_to_chunks", "file_to_chunks", "get_bins",
8
- "DataLogger"
9
+ "DataLogger", "ToolManager"
9
10
  ]
lionagi/utils/doc_util.py CHANGED
@@ -26,7 +26,7 @@ def dir_to_path(dir: str, ext, recursive: bool = False, flat: bool = True):
26
26
  def _dir_to_path(ext, recursive=recursive):
27
27
  tem = '**/*' if recursive else '*'
28
28
  return list(Path(dir).glob(tem + ext))
29
-
29
+
30
30
  return to_list(l_call(ext, _dir_to_path, flat=True), flat=flat)
31
31
 
32
32
  def read_text(filepath: str, clean: bool = True) -> str:
@@ -48,15 +48,15 @@ def read_text(filepath: str, clean: bool = True) -> str:
48
48
  content = f.read()
49
49
  if clean:
50
50
  # Define characters to replace and their replacements
51
- replacements = {'\\': ' ', '\\\n': ' ', '\\\t': ' ', ' ': ' ', '\'': ' '}
51
+ replacements = {'\\': ' ', '\n': ' ', '\t': ' ', ' ': ' ', '\'': ' '}
52
52
  for old, new in replacements.items():
53
53
  content = content.replace(old, new)
54
54
  return content
55
55
 
56
- def dir_to_files(dir: str, ext: str, recursive: bool = False,
57
- reader: Callable = read_text, clean: bool = True,
56
+ def dir_to_files(dir: str, ext: str, recursive: bool = False,
57
+ reader: Callable = read_text, clean: bool = True,
58
58
  to_csv: bool = False, project: str = 'project',
59
- output_dir: str = 'data/logs/sources/', filename: Optional[str] = None,
59
+ output_dir: str = 'data/logs/sources/', filename: Optional[str] = None,
60
60
  verbose: bool = True, timestamp: bool = True, logger: Optional[DataLogger] = None):
61
61
  """
62
62
  Reads and processes files in a specified directory with the given extension.
@@ -81,9 +81,9 @@ def dir_to_files(dir: str, ext: str, recursive: bool = False,
81
81
  Examples:
82
82
  >>> logs = dir_to_files(dir='my_directory', ext='.txt', to_csv=True)
83
83
  """
84
-
84
+
85
85
  sources = dir_to_path(dir, ext, recursive)
86
-
86
+
87
87
  def split_path(path: Path) -> tuple:
88
88
  folder_name = path.parent.name
89
89
  file_name = path.name
@@ -99,9 +99,9 @@ def dir_to_files(dir: str, ext: str, recursive: bool = False,
99
99
  "file_size": len(str(content)),
100
100
  'content': content
101
101
  } if content else None
102
-
102
+
103
103
  logs = to_list(l_call(sources, to_dict, flat=True), dropna=True)
104
-
104
+
105
105
  if to_csv:
106
106
  filename = filename or f"{project}_sources.csv"
107
107
  logger = DataLogger(dir=output_dir, log=logs) if not logger else logger
@@ -109,7 +109,7 @@ def dir_to_files(dir: str, ext: str, recursive: bool = False,
109
109
 
110
110
  return logs
111
111
 
112
- def chunk_text(input: str, chunk_size: int, overlap: float,
112
+ def chunk_text(input: str, chunk_size: int, overlap: float,
113
113
  threshold: int) -> List[Union[str, None]]:
114
114
  """
115
115
  Splits a string into chunks of a specified size, allowing for optional overlap between chunks.
@@ -127,19 +127,19 @@ def chunk_text(input: str, chunk_size: int, overlap: float,
127
127
  Returns:
128
128
  List[Union[str, None]]: List of text chunks.
129
129
  """
130
-
130
+
131
131
  try:
132
132
  # Ensure text is a string
133
133
  if not isinstance(input, str):
134
134
  input = str(input)
135
-
135
+
136
136
  chunks = []
137
137
  n_chunks = math.ceil(len(input) / chunk_size)
138
138
  overlap_size = int(chunk_size * overlap / 2)
139
-
139
+
140
140
  if n_chunks == 1:
141
141
  return [input]
142
-
142
+
143
143
  elif n_chunks == 2:
144
144
  chunks.append(input[:chunk_size + overlap_size])
145
145
  if len(input) - chunk_size > threshold:
@@ -147,28 +147,28 @@ def chunk_text(input: str, chunk_size: int, overlap: float,
147
147
  else:
148
148
  return [input]
149
149
  return chunks
150
-
150
+
151
151
  elif n_chunks > 2:
152
152
  chunks.append(input[:chunk_size + overlap_size])
153
153
  for i in range(1, n_chunks - 1):
154
154
  start_idx = chunk_size * i - overlap_size
155
155
  end_idx = chunk_size * (i + 1) + overlap_size
156
156
  chunks.append(input[start_idx:end_idx])
157
-
157
+
158
158
  if len(input) - chunk_size * (n_chunks - 1) > threshold:
159
159
  chunks.append(input[chunk_size * (n_chunks - 1) - overlap_size:])
160
160
  else:
161
- chunks[-1] += input[chunk_size * (n_chunks - 1):]
162
-
161
+ chunks[-1] += input[chunk_size * (n_chunks - 1) + overlap_size:]
162
+
163
163
  return chunks
164
-
164
+
165
165
  except Exception as e:
166
166
  raise ValueError(f"An error occurred while chunking the text. {e}")
167
167
 
168
- def _file_to_chunks(input: Dict[str, Any],
169
- field: str = 'content',
170
- chunk_size: int = 1500,
171
- overlap: float = 0.2,
168
+ def _file_to_chunks(input: Dict[str, Any],
169
+ field: str = 'content',
170
+ chunk_size: int = 1500,
171
+ overlap: float = 0.2,
172
172
  threshold: int = 200) -> List[Dict[str, Any]]:
173
173
  """
174
174
  Splits text from a specified dictionary field into chunks and returns a list of dictionaries.
@@ -195,7 +195,7 @@ def _file_to_chunks(input: Dict[str, Any],
195
195
  try:
196
196
  out = {key: value for key, value in input.items() if key != field}
197
197
  out.update({"chunk_overlap": overlap, "chunk_threshold": threshold})
198
-
198
+
199
199
  chunks = chunk_text(input[field], chunk_size=chunk_size, overlap=overlap, threshold=threshold)
200
200
  logs = []
201
201
  for i, chunk in enumerate(chunks):
@@ -209,22 +209,22 @@ def _file_to_chunks(input: Dict[str, Any],
209
209
  logs.append(chunk_dict)
210
210
 
211
211
  return logs
212
-
212
+
213
213
  except Exception as e:
214
214
  raise ValueError(f"An error occurred while chunking the file. {e}")
215
-
216
- def file_to_chunks(input,
217
- field: str = 'content',
218
- chunk_size: int = 1500,
219
- overlap: float = 0.2,
220
- threshold: int = 200,
221
- to_csv=False,
215
+
216
+ def file_to_chunks(input,
217
+ field: str = 'content',
218
+ chunk_size: int = 1500,
219
+ overlap: float = 0.2,
220
+ threshold: int = 200,
221
+ to_csv=False,
222
222
  project='project',
223
- output_dir='data/logs/sources/',
223
+ output_dir='data/logs/sources/',
224
224
  chunk_func = _file_to_chunks,
225
- filename=None,
226
- verbose=True,
227
- timestamp=True,
225
+ filename=None,
226
+ verbose=True,
227
+ timestamp=True,
228
228
  logger=None):
229
229
  """
230
230
  Splits text from a specified dictionary field into chunks and returns a list of dictionaries.
@@ -243,10 +243,10 @@ def file_to_chunks(input,
243
243
  timestamp: If True, include a timestamp in the exported file name.
244
244
  logger: An optional DataLogger instance for logging.
245
245
  """
246
-
246
+
247
247
  f = lambda x: chunk_func(x, field=field, chunk_size=chunk_size, overlap=overlap, threshold=threshold)
248
248
  logs = to_list(l_call(input, f), flat=True)
249
-
249
+
250
250
  if to_csv:
251
251
  filename = filename if filename else f"{project}_sources.csv"
252
252
  logger = DataLogger(log=logs) if not logger else logger
lionagi/utils/sys_util.py CHANGED
@@ -670,7 +670,7 @@ def create_id() -> str:
670
670
  random_bytes = os.urandom(16)
671
671
  return hashlib.sha256(current_time + random_bytes).hexdigest()[:16]
672
672
 
673
- def create_path(dir: str, filename: str, timestamp: bool = True, dir_exist_ok: bool = True) -> str:
673
+ def create_path(dir: str, filename: str, timestamp: bool = True, dir_exist_ok: bool = True, time_prefix=False) -> str:
674
674
  """
675
675
  Creates a file path by optionally appending a timestamp to the filename.
676
676
 
@@ -690,10 +690,14 @@ def create_path(dir: str, filename: str, timestamp: bool = True, dir_exist_ok: b
690
690
  >>> create_path('/tmp/', 'log.txt', timestamp=False)
691
691
  '/tmp/log.txt'
692
692
  """
693
+
694
+ dir = dir + '/' if str(dir)[-1] != '/' else dir
695
+ filename, ext = filename.split('.')
693
696
  os.makedirs(dir, exist_ok=dir_exist_ok)
697
+
694
698
  if timestamp:
695
699
  timestamp = get_timestamp()
696
- return f"{dir}{timestamp}{filename}"
700
+ return f"{dir}{timestamp}_{filename}.{ext}" if time_prefix else f"{dir}{filename}_{timestamp}.{ext}"
697
701
  else:
698
702
  return f"{dir}{filename}"
699
703
 
@@ -0,0 +1,194 @@
1
+ import json
2
+ import asyncio
3
+ from .sys_util import l_call
4
+
5
+
6
+ class ToolManager:
7
+ """
8
+ A manager class for handling and invoking registered tools and functions.
9
+
10
+ This class allows the registration of tools and functions, enabling their invocation.
11
+
12
+ Attributes:
13
+ registry (dict): A dictionary storing the registered tools and their corresponding functions.
14
+
15
+ Methods:
16
+ _to_dict(name, function, content=None) -> dict:
17
+ Convert tool information to a dictionary entry.
18
+
19
+ _name_existed(name) -> bool:
20
+ Check if a given name exists in the registry.
21
+
22
+ _register_function(name, function, content=None, update=False, new=False, prefix=None, postfix=None) -> None:
23
+ Register a function with a specified name in the registry.
24
+
25
+ invoke(name, args) -> Any:
26
+ Invoke a registered function with the provided arguments.
27
+
28
+ ainvoke(name, args) -> Any:
29
+ Asynchronously invoke a registered function with the provided arguments.
30
+
31
+ _get_function_call(response) -> Tuple[str, dict]:
32
+ Extract function name and arguments from a response JSON.
33
+
34
+ _from_tool(tool, func) -> Tuple[str, callable, list]:
35
+ Convert tool information to function registration parameters.
36
+
37
+ register_tools(tools, functions, update=False, new=False, prefix=None, postfix=None) -> None:
38
+ Register multiple tools and their corresponding functions.
39
+ """
40
+ def __init__(self):
41
+ """
42
+ Initialize a ToolManager object with an empty registry.
43
+ """
44
+ self.registry = {}
45
+
46
+ @staticmethod
47
+ def _to_dict(name, function, content=None):
48
+ """
49
+ Convert tool information to a dictionary entry.
50
+
51
+ Parameters:
52
+ name (str): The name of the tool.
53
+ function (callable): The function associated with the tool.
54
+ content (Optional[str]): Additional content for the tool.
55
+
56
+ Returns:
57
+ dict: A dictionary entry representing the tool.
58
+ """
59
+ return {name: {"function": function, "content": content or "none"}}
60
+
61
+ def _name_existed(self, name):
62
+ """
63
+ Check if a given name exists in the registry.
64
+
65
+ Parameters:
66
+ name (str): The name to check.
67
+
68
+ Returns:
69
+ bool: True if the name exists in the registry, False otherwise.
70
+
71
+ """
72
+ return True if name in self.registry.keys() else False
73
+
74
+ def _register_function(self, name, function, content=None, update=False, new=False, prefix=None, postfix=None):
75
+ """
76
+ Register a function with a specified name in the registry.
77
+
78
+ Parameters:
79
+ name (str): The name of the function.
80
+ function (callable): The function to register.
81
+ content (Optional[str]): Additional content for the function.
82
+ update (bool): Whether to update an existing function with the same name.
83
+ new (bool): Whether to create a new registry for an existing function.
84
+ prefix (Optional[str]): A prefix to add to the function name.
85
+ postfix (Optional[str]): A postfix to add to the function name.
86
+
87
+ """
88
+ if self._name_existed(name):
89
+ if update and new:
90
+ raise ValueError(f"Cannot both update and create new registry for existing function {name} at the same time")
91
+
92
+ name = f"{prefix or ''}{name}{postfix or '1'}" if new else name
93
+ self.registry.update(self._to_dict(name, function, content))
94
+
95
+ def invoke(self, name, kwargs):
96
+ """
97
+ Invoke a registered function with the provided arguments.
98
+
99
+ Parameters:
100
+ name (str): The name of the function to invoke.
101
+ kwargs (dict): The arguments to pass to the function.
102
+
103
+ Returns:
104
+ Any: The result of invoking the function.
105
+ """
106
+ if self._name_existed(name):
107
+ try:
108
+ return self.registry[name](**kwargs)
109
+ except Exception as e:
110
+ raise ValueError(f"Error when invoking function {name} with arguments {kwargs} with error message {e}")
111
+ else:
112
+ raise ValueError(f"Function {name} is not registered.")
113
+
114
+ async def ainvoke(self, name, kwargs):
115
+ """
116
+ Asynchronously invoke a registered function with the provided arguments.
117
+
118
+ Parameters:
119
+ name (str): The name of the function to invoke.
120
+ kwargs (dict): The arguments to pass to the function.
121
+
122
+ Returns:
123
+ Any: The result of invoking the function asynchronously.
124
+
125
+ """
126
+ if self._name_existed(name):
127
+ function = self.registry[name]["function"]
128
+ try:
129
+ if asyncio.iscoroutinefunction(function):
130
+ return await function(**kwargs)
131
+ else:
132
+ return function(**kwargs)
133
+ except Exception as e:
134
+ raise ValueError(f"Error when invoking function {name} with arguments {kwargs} with error message {e}")
135
+ else:
136
+ raise ValueError(f"Function {name} is not registered.")
137
+
138
+ @staticmethod
139
+ def _get_function_call(response):
140
+ """
141
+ Extract function name and arguments from a response JSON.
142
+
143
+ Parameters:
144
+ response (str): The JSON response containing function information.
145
+
146
+ Returns:
147
+ Tuple[str, dict]: The function name and its arguments.
148
+ """
149
+ try:
150
+ out = json.loads(response)
151
+ func = out['function'][5:]
152
+ args = json.loads(out['arguments'])
153
+ return (func, args)
154
+ except:
155
+ try:
156
+ out = json.loads(response)
157
+ out = out['tool_uses'][0]
158
+ func = out['recipient_name'].split('.')[-1]
159
+ args = out['parameters']
160
+ return (func, args)
161
+ except:
162
+ raise ValueError('response is not a valid function call')
163
+
164
+ @staticmethod
165
+ def _from_tool(tool, func):
166
+ """
167
+ Convert tool information to function registration parameters.
168
+
169
+ Parameters:
170
+ tool (dict): The tool information.
171
+ func (callable): The function associated with the tool.
172
+
173
+ Returns:
174
+ Tuple[str, callable, list]: The function name, the function, and the list of function parameters.
175
+
176
+ """
177
+ return (tool['function']['name'], func,
178
+ tool['function']['parameters']['properties'].keys())
179
+
180
+ def register_tools(self, tools, functions, update=False, new=False, prefix=None, postfix=None):
181
+ """
182
+ Register multiple tools and their corresponding functions.
183
+
184
+ Parameters:
185
+ tools (list): The list of tool information dictionaries.
186
+ functions (list): The list of corresponding functions.
187
+ update (bool): Whether to update existing functions.
188
+ new (bool): Whether to create new registries for existing functions.
189
+ prefix (Optional[str]): A prefix to add to the function names.
190
+ postfix (Optional[str]): A postfix to add to the function names.
191
+
192
+ """
193
+ funcs = l_call(range(len(tools)), lambda i: self._from_tool(tools[i], functions[i]))
194
+ l_call(range(len(tools)), lambda i: self._register_function(funcs[i][0], funcs[i][1], update=update, new=new, prefix=prefix, postfix=postfix))
lionagi/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.0.104"
1
+ __version__ = "0.0.106"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lionagi
3
- Version: 0.0.104
3
+ Version: 0.0.106
4
4
  Summary: Towards automated general intelligence.
5
5
  Author: HaiyangLi
6
6
  Author-email: Haiyang Li <ocean@lionagi.ai>
@@ -227,7 +227,8 @@ Requires-Dist: httpx ==0.25.1
227
227
  - PyPI: https://pypi.org/project/lionagi/
228
228
  - Documentation: https://lionagi.readthedocs.io/en/latest/ (still a lot TODO)
229
229
  - Website: TODO
230
- - Discord: [Join Our Discord](https://discord.gg/ACnynvvPjt)
230
+ - Discord: [Join Our Discord](https://discord.gg/7RGWqpSxze)
231
+
231
232
 
232
233
  # LionAGI
233
234
  **Towards Automated General Intelligence**
@@ -286,7 +287,7 @@ Visit our notebooks for our examples.
286
287
 
287
288
  ### Community
288
289
 
289
- We encourage contributions to LionAGI and invite you to enrich its features and capabilities. Engage with us and other community members on [Discord](https://discord.gg/ACnynvvPjt)
290
+ We encourage contributions to LionAGI and invite you to enrich its features and capabilities. Engage with us and other community members [Join Our Discord](https://discord.gg/7RGWqpSxze)
290
291
 
291
292
  ### Citation
292
293
 
@@ -0,0 +1,21 @@
1
+ lionagi/__init__.py,sha256=2Rko3tw94ZFVN_GSvcxAY1O77FxswcaMxNHKH5Bj7jc,788
2
+ lionagi/version.py,sha256=PNgUABlGb7ny9DJoPWFQ_4l3TkVF8MMbJNWWeHy9dGY,24
3
+ lionagi/api/__init__.py,sha256=RcmOxPnbaj5R6JYqQzQZ67KyVByJfyUw6QSw22KSo8g,134
4
+ lionagi/api/oai_config.py,sha256=yhyZ4aEaF6r3XBbhxI47r8CL2-amc-4IKJhbXv2W9CM,356
5
+ lionagi/api/oai_service.py,sha256=ctX4k3du_sl52n2LilSxXGHdce-igHXtEfpB6RrKbwQ,11209
6
+ lionagi/session/__init__.py,sha256=hbM6VwWz0Oh-Vld79JDFo5eYaCIqAn_OswmLiT0z4UA,58
7
+ lionagi/session/conversation.py,sha256=SOZK8c6P48GqbXTnSiHbB9mROo6VrLwhdD_CHGagQfM,4069
8
+ lionagi/session/message.py,sha256=R2J5uXuDkMYGxjUKD0fJIdummlsZccId7nw4V8li5Ro,6217
9
+ lionagi/session/session.py,sha256=_1kAijUrclzKhqZfGxTAuJ55qEhGcORJe2vpRkfoU9w,12904
10
+ lionagi/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ lionagi/utils/__init__.py,sha256=jTZigmOboszESjWr9dP8PKtZ8XF_RqVd4Ni8s-GkaVs,760
12
+ lionagi/utils/api_util.py,sha256=WE51kMpKzmBwRqD0dkzxAMWzK04_k_5dth2kiOjVkMA,14837
13
+ lionagi/utils/doc_util.py,sha256=uT2paXguEs26kkW7oe2rR3CozQmpP2P9eJJdnZ9uM_E,12338
14
+ lionagi/utils/log_util.py,sha256=qbmaZxiX_bKY-LLaZcpMbTwi3aeBcK9-Lc93vkLIBuk,3103
15
+ lionagi/utils/sys_util.py,sha256=K4dumJ0th082RITpoz_F_eUw-OwkaLOz-BHoezuxwlU,28045
16
+ lionagi/utils/tool_util.py,sha256=HxBkHAu7Ema-HTmfRgnD4k4jyBJdsKd6ZiedosFwSDU,7479
17
+ lionagi-0.0.106.dist-info/LICENSE,sha256=TBnSyG8fs_tMRtK805GzA1cIyExleKyzoN_kuVxT9IY,11358
18
+ lionagi-0.0.106.dist-info/METADATA,sha256=50DYFq9K5kPlSKKmovP-a1z-12q0Lj4N9Sngcj0fFKE,17370
19
+ lionagi-0.0.106.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
20
+ lionagi-0.0.106.dist-info/top_level.txt,sha256=szvch_d2jE1Lu9ZIKsl26Ll6BGfYfbOgt5lm-UpFSo4,8
21
+ lionagi-0.0.106.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- lionagi/__init__.py,sha256=2Rko3tw94ZFVN_GSvcxAY1O77FxswcaMxNHKH5Bj7jc,788
2
- lionagi/version.py,sha256=m9tOf0gVCkqN3dmK4Ruh3l4dO8KbQ-WtCnvEBME8wSU,24
3
- lionagi/api/__init__.py,sha256=RcmOxPnbaj5R6JYqQzQZ67KyVByJfyUw6QSw22KSo8g,134
4
- lionagi/api/oai_config.py,sha256=yhyZ4aEaF6r3XBbhxI47r8CL2-amc-4IKJhbXv2W9CM,356
5
- lionagi/api/oai_service.py,sha256=ctX4k3du_sl52n2LilSxXGHdce-igHXtEfpB6RrKbwQ,11209
6
- lionagi/session/__init__.py,sha256=hbM6VwWz0Oh-Vld79JDFo5eYaCIqAn_OswmLiT0z4UA,58
7
- lionagi/session/conversation.py,sha256=dedqlGEfIT26WfTJhBOlYWpz_-BFad1BkzIya2mkFwA,3436
8
- lionagi/session/message.py,sha256=bxvJbR0z9z97suz4sMKbNYIuJYsHuAXuTDgj3CI0qnM,2851
9
- lionagi/session/session.py,sha256=zTRMNaV8R3DKD10hm-wOAW8dSRVobu_aa7_lAT8I9kg,6812
10
- lionagi/utils/__init__.py,sha256=-9k5ILJjZ9bTq6U4NA3vNURG2HS7wsUdE1fEWItTGqM,710
11
- lionagi/utils/api_util.py,sha256=WE51kMpKzmBwRqD0dkzxAMWzK04_k_5dth2kiOjVkMA,14837
12
- lionagi/utils/doc_util.py,sha256=kZ3qRIKc5kAXFjeR8Z6oDzM4vRQVDw6rG5YDavme2zQ,12461
13
- lionagi/utils/log_util.py,sha256=qbmaZxiX_bKY-LLaZcpMbTwi3aeBcK9-Lc93vkLIBuk,3103
14
- lionagi/utils/sys_util.py,sha256=8S1S7V3Sk_Yyp2pfqrGyO_9w-wDHQ3Kzpez4yGvpZuM,27860
15
- lionagi-0.0.104.dist-info/LICENSE,sha256=TBnSyG8fs_tMRtK805GzA1cIyExleKyzoN_kuVxT9IY,11358
16
- lionagi-0.0.104.dist-info/METADATA,sha256=640tGgNFlJ91RYqHBU2B4VLx1dcGVlMztLmbXBPXeEs,17363
17
- lionagi-0.0.104.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
18
- lionagi-0.0.104.dist-info/top_level.txt,sha256=szvch_d2jE1Lu9ZIKsl26Ll6BGfYfbOgt5lm-UpFSo4,8
19
- lionagi-0.0.104.dist-info/RECORD,,