lionagi 0.0.305__py3-none-any.whl → 0.0.307__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 +2 -5
- lionagi/core/__init__.py +7 -4
- lionagi/core/agent/__init__.py +3 -0
- lionagi/core/agent/base_agent.py +46 -0
- lionagi/core/branch/__init__.py +4 -0
- lionagi/core/branch/base/__init__.py +0 -0
- lionagi/core/branch/base_branch.py +100 -78
- lionagi/core/branch/branch.py +22 -34
- lionagi/core/branch/branch_flow_mixin.py +3 -7
- lionagi/core/branch/executable_branch.py +192 -0
- lionagi/core/branch/util.py +77 -162
- lionagi/core/direct/__init__.py +13 -0
- lionagi/core/direct/parallel_predict.py +127 -0
- lionagi/core/direct/parallel_react.py +0 -0
- lionagi/core/direct/parallel_score.py +0 -0
- lionagi/core/direct/parallel_select.py +0 -0
- lionagi/core/direct/parallel_sentiment.py +0 -0
- lionagi/core/direct/predict.py +174 -0
- lionagi/core/direct/react.py +33 -0
- lionagi/core/direct/score.py +163 -0
- lionagi/core/direct/select.py +144 -0
- lionagi/core/direct/sentiment.py +51 -0
- lionagi/core/direct/utils.py +83 -0
- lionagi/core/flow/__init__.py +0 -3
- lionagi/core/flow/monoflow/{mono_react.py → ReAct.py} +52 -9
- lionagi/core/flow/monoflow/__init__.py +9 -0
- lionagi/core/flow/monoflow/{mono_chat.py → chat.py} +11 -11
- lionagi/core/flow/monoflow/{mono_chat_mixin.py → chat_mixin.py} +33 -27
- lionagi/core/flow/monoflow/{mono_followup.py → followup.py} +7 -6
- lionagi/core/flow/polyflow/__init__.py +1 -0
- lionagi/core/flow/polyflow/{polychat.py → chat.py} +15 -3
- lionagi/core/mail/__init__.py +8 -0
- lionagi/core/mail/mail_manager.py +88 -40
- lionagi/core/mail/schema.py +32 -6
- lionagi/core/messages/__init__.py +3 -0
- lionagi/core/messages/schema.py +56 -25
- lionagi/core/prompt/__init__.py +0 -0
- lionagi/core/prompt/prompt_template.py +0 -0
- lionagi/core/schema/__init__.py +7 -5
- lionagi/core/schema/action_node.py +29 -0
- lionagi/core/schema/base_mixin.py +56 -59
- lionagi/core/schema/base_node.py +35 -38
- lionagi/core/schema/condition.py +24 -0
- lionagi/core/schema/data_logger.py +98 -98
- lionagi/core/schema/data_node.py +19 -19
- lionagi/core/schema/prompt_template.py +0 -0
- lionagi/core/schema/structure.py +293 -190
- lionagi/core/session/__init__.py +1 -3
- lionagi/core/session/session.py +196 -214
- lionagi/core/tool/tool_manager.py +95 -103
- lionagi/integrations/__init__.py +1 -3
- lionagi/integrations/bridge/langchain_/documents.py +17 -18
- lionagi/integrations/bridge/langchain_/langchain_bridge.py +14 -14
- lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +22 -22
- lionagi/integrations/bridge/llamaindex_/node_parser.py +12 -12
- lionagi/integrations/bridge/llamaindex_/reader.py +11 -11
- lionagi/integrations/bridge/llamaindex_/textnode.py +7 -7
- lionagi/integrations/config/openrouter_configs.py +0 -1
- lionagi/integrations/provider/oai.py +26 -26
- lionagi/integrations/provider/services.py +38 -38
- lionagi/libs/__init__.py +34 -1
- lionagi/libs/ln_api.py +211 -221
- lionagi/libs/ln_async.py +53 -60
- lionagi/libs/ln_convert.py +118 -120
- lionagi/libs/ln_dataframe.py +32 -33
- lionagi/libs/ln_func_call.py +334 -342
- lionagi/libs/ln_nested.py +99 -107
- lionagi/libs/ln_parse.py +175 -158
- lionagi/libs/sys_util.py +52 -52
- lionagi/tests/test_core/test_base_branch.py +427 -427
- lionagi/tests/test_core/test_branch.py +292 -292
- lionagi/tests/test_core/test_mail_manager.py +57 -57
- lionagi/tests/test_core/test_session.py +254 -266
- lionagi/tests/test_core/test_session_base_util.py +299 -300
- lionagi/tests/test_core/test_tool_manager.py +70 -74
- lionagi/tests/test_libs/test_nested.py +2 -7
- lionagi/tests/test_libs/test_parse.py +2 -2
- lionagi/version.py +1 -1
- {lionagi-0.0.305.dist-info → lionagi-0.0.307.dist-info}/METADATA +4 -2
- lionagi-0.0.307.dist-info/RECORD +115 -0
- lionagi-0.0.305.dist-info/RECORD +0 -94
- {lionagi-0.0.305.dist-info → lionagi-0.0.307.dist-info}/LICENSE +0 -0
- {lionagi-0.0.305.dist-info → lionagi-0.0.307.dist-info}/WHEEL +0 -0
- {lionagi-0.0.305.dist-info → lionagi-0.0.307.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,9 @@
|
|
1
1
|
from abc import ABC
|
2
2
|
from typing import Any, Optional, Union, TypeVar
|
3
3
|
|
4
|
-
from
|
5
|
-
from
|
6
|
-
from
|
7
|
-
from lionagi.core.flow.monoflow.mono_react import MonoReAct
|
8
|
-
|
9
|
-
from lionagi.core.messages.schema import Instruction, System
|
4
|
+
from ..schema import TOOL_TYPE, Tool
|
5
|
+
from ..messages import Instruction, System
|
6
|
+
from ..flow.monoflow import MonoChat, MonoFollowup, MonoReAct
|
10
7
|
|
11
8
|
T = TypeVar("T", bound=Tool)
|
12
9
|
|
@@ -25,7 +22,6 @@ class BranchFlowMixin(ABC):
|
|
25
22
|
output_fields=None,
|
26
23
|
**kwargs,
|
27
24
|
) -> Any:
|
28
|
-
|
29
25
|
flow = MonoChat(self)
|
30
26
|
return await flow.chat(
|
31
27
|
instruction=instruction,
|
@@ -0,0 +1,192 @@
|
|
1
|
+
import contextlib
|
2
|
+
from collections import deque
|
3
|
+
from typing import Any
|
4
|
+
|
5
|
+
from lionagi.libs import convert, AsyncUtil, ParseUtil
|
6
|
+
|
7
|
+
from ..schema import BaseRelatableNode, ActionNode
|
8
|
+
from ..mail import BaseMail
|
9
|
+
from ..messages import System, Instruction
|
10
|
+
from ..agent import BaseAgent
|
11
|
+
|
12
|
+
from .branch import Branch
|
13
|
+
|
14
|
+
|
15
|
+
class ExecutableBranch(BaseRelatableNode):
|
16
|
+
|
17
|
+
def __init__(self, verbose=True, **kwargs):
|
18
|
+
super().__init__()
|
19
|
+
self.branch: Branch = Branch(**kwargs)
|
20
|
+
self.pending_ins = {} # needed
|
21
|
+
self.pending_outs = deque() # needed
|
22
|
+
self.responses = []
|
23
|
+
self.execute_stop = False # needed
|
24
|
+
self.context = None # needed
|
25
|
+
self.context_log = []
|
26
|
+
self.verbose = verbose
|
27
|
+
|
28
|
+
def send(self, recipient_id: str, category: str, package: Any) -> None:
|
29
|
+
mail = BaseMail(
|
30
|
+
sender_id=self.id_,
|
31
|
+
recipient_id=recipient_id,
|
32
|
+
category=category,
|
33
|
+
package=package,
|
34
|
+
)
|
35
|
+
self.pending_outs.append(mail)
|
36
|
+
|
37
|
+
async def forward(self):
|
38
|
+
for key in list(self.pending_ins.keys()):
|
39
|
+
while self.pending_ins[key]:
|
40
|
+
mail = self.pending_ins[key].popleft()
|
41
|
+
if mail.category == "start": # needed
|
42
|
+
self._process_start(mail)
|
43
|
+
elif mail.category == "node":
|
44
|
+
await self._process_node(mail)
|
45
|
+
elif mail.category == "node_list":
|
46
|
+
self._process_node_list(mail)
|
47
|
+
elif mail.category == "condition":
|
48
|
+
self._process_condition(mail)
|
49
|
+
elif mail.category == "end": # needed
|
50
|
+
self._process_end(mail)
|
51
|
+
|
52
|
+
async def execute(self, refresh_time=1): # needed
|
53
|
+
while not self.execute_stop:
|
54
|
+
await self.forward()
|
55
|
+
await AsyncUtil.sleep(refresh_time)
|
56
|
+
|
57
|
+
async def _process_node(self, mail: BaseMail):
|
58
|
+
|
59
|
+
if isinstance(mail.package, System):
|
60
|
+
self._system_process(mail.package, verbose=self.verbose)
|
61
|
+
self.send(mail.sender_id, "node_id", mail.package.id_)
|
62
|
+
|
63
|
+
elif isinstance(mail.package, Instruction):
|
64
|
+
await self._instruction_process(mail.package, verbose=self.verbose)
|
65
|
+
self.send(mail.sender_id, "node_id", mail.package.id_)
|
66
|
+
|
67
|
+
elif isinstance(mail.package, ActionNode):
|
68
|
+
await self._action_process(mail.package, verbose=self.verbose)
|
69
|
+
self.send(mail.sender_id, "node_id", mail.package.instruction.id_)
|
70
|
+
else:
|
71
|
+
try:
|
72
|
+
await self._agent_process(mail.package, verbose=self.verbose)
|
73
|
+
self.send(mail.sender_id, "node_id", mail.package.id_)
|
74
|
+
except:
|
75
|
+
raise ValueError(f"Invalid mail to process. Mail:{mail}")
|
76
|
+
|
77
|
+
def _process_node_list(self, mail: BaseMail):
|
78
|
+
self.send(mail.sender_id, "end", "end")
|
79
|
+
self.execute_stop = True
|
80
|
+
raise ValueError("Multiple path selection is currently not supported")
|
81
|
+
|
82
|
+
def _process_condition(self, mail: BaseMail):
|
83
|
+
relationship = mail.package
|
84
|
+
check_result = relationship.condition(self)
|
85
|
+
back_mail = {"relationship_id": mail.package.id_, "check_result": check_result}
|
86
|
+
self.send(mail.sender_id, "condition", back_mail)
|
87
|
+
|
88
|
+
def _system_process(self, system: System, verbose=True, context_verbose=False):
|
89
|
+
from lionagi.libs import SysUtil
|
90
|
+
SysUtil.check_import('IPython')
|
91
|
+
from IPython.display import Markdown, display
|
92
|
+
if verbose:
|
93
|
+
print(f"------------------Welcome: {system.sender}--------------------")
|
94
|
+
display(Markdown(f"system: {convert.to_str(system.system_info)}"))
|
95
|
+
if self.context and context_verbose:
|
96
|
+
display(Markdown(f"context: {convert.to_str(self.context)}"))
|
97
|
+
|
98
|
+
self.branch.add_message(system=system)
|
99
|
+
|
100
|
+
async def _instruction_process(
|
101
|
+
self, instruction: Instruction, verbose=True, **kwargs
|
102
|
+
):
|
103
|
+
from lionagi.libs import SysUtil
|
104
|
+
SysUtil.check_import('IPython')
|
105
|
+
from IPython.display import Markdown, display
|
106
|
+
if verbose:
|
107
|
+
display(
|
108
|
+
Markdown(
|
109
|
+
f"{instruction.sender}: {convert.to_str(instruction.instruct)}"
|
110
|
+
)
|
111
|
+
)
|
112
|
+
|
113
|
+
if self.context:
|
114
|
+
instruction.content.update({"context": self.context})
|
115
|
+
self.context = None
|
116
|
+
|
117
|
+
result = await self.branch.chat(instruction, **kwargs)
|
118
|
+
with contextlib.suppress(Exception):
|
119
|
+
result = ParseUtil.fuzzy_parse_json(result)
|
120
|
+
if "response" in result.keys():
|
121
|
+
result = result["response"]
|
122
|
+
if verbose and len(self.branch.assistant_responses) != 0:
|
123
|
+
display(
|
124
|
+
Markdown(
|
125
|
+
f"{self.branch.last_assistant_response.sender}: {convert.to_str(result)}"
|
126
|
+
)
|
127
|
+
)
|
128
|
+
print("-----------------------------------------------------")
|
129
|
+
|
130
|
+
self.responses.append(result)
|
131
|
+
|
132
|
+
async def _action_process(self, action: ActionNode, verbose=True):
|
133
|
+
from lionagi.libs import SysUtil
|
134
|
+
SysUtil.check_import('IPython')
|
135
|
+
from IPython.display import Markdown, display
|
136
|
+
try:
|
137
|
+
func = getattr(self.branch, action.action)
|
138
|
+
except:
|
139
|
+
raise ValueError(f"{action.action} is not a valid action")
|
140
|
+
|
141
|
+
if verbose:
|
142
|
+
display(
|
143
|
+
Markdown(
|
144
|
+
f"{action.instruction.sender}: {convert.to_str(action.instruction.instruct)}"
|
145
|
+
)
|
146
|
+
)
|
147
|
+
|
148
|
+
if action.tools:
|
149
|
+
self.branch.register_tools(action.tools)
|
150
|
+
if self.context:
|
151
|
+
result = await func(
|
152
|
+
action.instruction.content["instruction"],
|
153
|
+
context=self.context,
|
154
|
+
tools=action.tools,
|
155
|
+
**action.action_kwargs,
|
156
|
+
)
|
157
|
+
self.context = None
|
158
|
+
else:
|
159
|
+
result = await func(
|
160
|
+
action.instruction.content, tools=action.tools, **action.action_kwargs
|
161
|
+
)
|
162
|
+
|
163
|
+
if verbose and len(self.branch.assistant_responses) != 0:
|
164
|
+
display(
|
165
|
+
Markdown(
|
166
|
+
f"{self.branch.last_assistant_response.sender}: {convert.to_str(result)}"
|
167
|
+
)
|
168
|
+
)
|
169
|
+
print("-----------------------------------------------------")
|
170
|
+
|
171
|
+
self.responses.append(result)
|
172
|
+
|
173
|
+
async def _agent_process(self, agent, verbose=True):
|
174
|
+
context = self.responses
|
175
|
+
if verbose:
|
176
|
+
print("*****************************************************")
|
177
|
+
result = await agent.execute(context)
|
178
|
+
|
179
|
+
if verbose:
|
180
|
+
print("*****************************************************")
|
181
|
+
|
182
|
+
self.context = result
|
183
|
+
self.responses.append(result)
|
184
|
+
|
185
|
+
def _process_start(self, mail):
|
186
|
+
start_mail_content = mail.package
|
187
|
+
self.context = start_mail_content["context"]
|
188
|
+
self.send(start_mail_content["structure_id"], "start", "start")
|
189
|
+
|
190
|
+
def _process_end(self, mail):
|
191
|
+
self.execute_stop = True
|
192
|
+
self.send(mail.sender_id, "end", "end")
|
lionagi/core/branch/util.py
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
+
import contextlib
|
1
2
|
from datetime import datetime
|
2
3
|
from typing import Any
|
3
4
|
|
4
|
-
from lionagi.libs import
|
5
|
-
from lionagi.libs import ln_nested as nested
|
6
|
-
from lionagi.libs import ln_func_call as func_call
|
7
|
-
from lionagi.libs import ln_dataframe as dataframe
|
5
|
+
from lionagi.libs import convert, nested, func_call, dataframe
|
8
6
|
|
9
7
|
from lionagi.core.messages.schema import (
|
10
8
|
System,
|
@@ -14,7 +12,6 @@ from lionagi.core.messages.schema import (
|
|
14
12
|
BranchColumns,
|
15
13
|
)
|
16
14
|
|
17
|
-
|
18
15
|
CUSTOM_TYPE = dict[str, Any] | str | list[Any] | None
|
19
16
|
|
20
17
|
|
@@ -33,42 +30,41 @@ class MessageUtil:
|
|
33
30
|
Creates a message object based on the input parameters, ensuring only one message role is present.
|
34
31
|
|
35
32
|
Args:
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
system: Information for creating a System message.
|
34
|
+
instruction: Information for creating an Instruction message.
|
35
|
+
context: Context information for the message.
|
36
|
+
response: Response data for creating a message.
|
37
|
+
**kwargs: Additional keyword arguments for message creation.
|
41
38
|
|
42
39
|
Returns:
|
43
|
-
|
40
|
+
A message object of the appropriate type based on provided inputs.
|
44
41
|
|
45
42
|
Raises:
|
46
|
-
|
43
|
+
ValueError: If more than one of the role-specific parameters are provided.
|
47
44
|
"""
|
48
45
|
if sum(func_call.lcall([system, instruction, response], bool)) != 1:
|
49
46
|
raise ValueError("Error: Message must have one and only one role.")
|
50
47
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
return msg
|
48
|
+
if isinstance(system, System):
|
49
|
+
return system
|
50
|
+
elif isinstance(instruction, Instruction):
|
51
|
+
return instruction
|
52
|
+
elif isinstance(response, Response):
|
53
|
+
return response
|
54
|
+
|
55
|
+
msg = 0
|
56
|
+
if response:
|
57
|
+
msg = Response(response=response, **kwargs)
|
58
|
+
elif instruction:
|
59
|
+
msg = Instruction(
|
60
|
+
instruction=instruction,
|
61
|
+
context=context,
|
62
|
+
output_fields=output_fields,
|
63
|
+
**kwargs,
|
64
|
+
)
|
65
|
+
elif system:
|
66
|
+
msg = System(system=system, **kwargs)
|
67
|
+
return msg
|
72
68
|
|
73
69
|
@staticmethod
|
74
70
|
def validate_messages(messages: dataframe.ln_DataFrame) -> bool:
|
@@ -76,21 +72,21 @@ class MessageUtil:
|
|
76
72
|
Validates the format and content of a DataFrame containing messages.
|
77
73
|
|
78
74
|
Args:
|
79
|
-
|
75
|
+
messages: A DataFrame with message information.
|
80
76
|
|
81
77
|
Returns:
|
82
|
-
|
78
|
+
True if the messages DataFrame is correctly formatted, False otherwise.
|
83
79
|
|
84
80
|
Raises:
|
85
|
-
|
81
|
+
ValueError: If the DataFrame does not match expected schema or content requirements.
|
86
82
|
"""
|
87
83
|
|
88
84
|
if list(messages.columns) != BranchColumns.COLUMNS.value:
|
89
85
|
raise ValueError("Invalid messages dataframe. Unmatched columns.")
|
90
86
|
if messages.isnull().values.any():
|
91
87
|
raise ValueError("Invalid messages dataframe. Cannot have null.")
|
92
|
-
if
|
93
|
-
role in ["system", "user", "assistant"]
|
88
|
+
if any(
|
89
|
+
role not in ["system", "user", "assistant"]
|
94
90
|
for role in messages["role"].unique()
|
95
91
|
):
|
96
92
|
raise ValueError(
|
@@ -115,14 +111,14 @@ class MessageUtil:
|
|
115
111
|
Appends a sender prefix to the 'content' field of each message in a DataFrame.
|
116
112
|
|
117
113
|
Args:
|
118
|
-
|
119
|
-
|
114
|
+
messages: A DataFrame containing message data.
|
115
|
+
sender: The identifier of the sender to prefix to message contents.
|
120
116
|
|
121
117
|
Returns:
|
122
|
-
|
118
|
+
A DataFrame with sender-prefixed message contents.
|
123
119
|
|
124
120
|
Raises:
|
125
|
-
|
121
|
+
ValueError: If the sender is None or the value is 'none'.
|
126
122
|
"""
|
127
123
|
|
128
124
|
if sender is None or convert.strip_lower(sender) == "none":
|
@@ -152,16 +148,16 @@ class MessageUtil:
|
|
152
148
|
Filters messages in a DataFrame based on specified criteria.
|
153
149
|
|
154
150
|
Args:
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
151
|
+
messages: The DataFrame to filter.
|
152
|
+
role: The role to filter by.
|
153
|
+
sender: The sender to filter by.
|
154
|
+
start_time: The minimum timestamp for messages.
|
155
|
+
end_time: The maximum timestamp for messages.
|
156
|
+
content_keywords: Keywords to look for in message content.
|
157
|
+
case_sensitive: Whether the keyword search should be case-sensitive.
|
162
158
|
|
163
159
|
Returns:
|
164
|
-
|
160
|
+
A filtered DataFrame based on the specified criteria.
|
165
161
|
"""
|
166
162
|
|
167
163
|
try:
|
@@ -180,7 +176,7 @@ class MessageUtil:
|
|
180
176
|
return convert.to_df(outs)
|
181
177
|
|
182
178
|
except Exception as e:
|
183
|
-
raise ValueError(f"Error in filtering messages: {e}")
|
179
|
+
raise ValueError(f"Error in filtering messages: {e}") from e
|
184
180
|
|
185
181
|
@staticmethod
|
186
182
|
def remove_message(messages: dataframe.ln_DataFrame, node_id: str) -> bool:
|
@@ -188,15 +184,15 @@ class MessageUtil:
|
|
188
184
|
Removes a message from the DataFrame based on its node ID.
|
189
185
|
|
190
186
|
Args:
|
191
|
-
|
192
|
-
|
187
|
+
messages: The DataFrame containing messages.
|
188
|
+
node_id: The unique identifier of the message to be removed.
|
193
189
|
|
194
190
|
Returns:
|
195
|
-
|
191
|
+
If any messages are removed.
|
196
192
|
|
197
193
|
Examples:
|
198
|
-
|
199
|
-
|
194
|
+
>>> messages = dataframe.ln_DataFrame([...])
|
195
|
+
>>> updated_messages = MessageUtil.remove_message(messages, "node_id_123")
|
200
196
|
"""
|
201
197
|
|
202
198
|
initial_length = len(messages)
|
@@ -218,15 +214,15 @@ class MessageUtil:
|
|
218
214
|
Retrieves a specified number of message rows based on sender and role.
|
219
215
|
|
220
216
|
Args:
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
217
|
+
messages: The DataFrame containing messages.
|
218
|
+
sender: Filter messages by the sender.
|
219
|
+
role: Filter messages by the role.
|
220
|
+
n: The number of messages to retrieve.
|
221
|
+
sign_: If True, sign the message with the sender.
|
222
|
+
from_: Specify retrieval from the 'front' or 'last' of the DataFrame.
|
227
223
|
|
228
224
|
Returns:
|
229
|
-
|
225
|
+
A DataFrame containing the filtered messages.
|
230
226
|
"""
|
231
227
|
|
232
228
|
outs = ""
|
@@ -266,17 +262,17 @@ class MessageUtil:
|
|
266
262
|
Extends a DataFrame with another DataFrame's rows, ensuring no duplicate 'node_id'.
|
267
263
|
|
268
264
|
Args:
|
269
|
-
|
270
|
-
|
271
|
-
|
265
|
+
df1: The primary DataFrame.
|
266
|
+
df2: The DataFrame to merge with the primary DataFrame.
|
267
|
+
**kwargs: Additional keyword arguments for `drop_duplicates`.
|
272
268
|
|
273
269
|
Returns:
|
274
|
-
|
270
|
+
A DataFrame combined from df1 and df2 with duplicates removed based on 'node_id'.
|
275
271
|
|
276
272
|
Examples:
|
277
|
-
|
278
|
-
|
279
|
-
|
273
|
+
>>> df_main = dataframe.ln_DataFrame([...])
|
274
|
+
>>> df_additional = dataframe.ln_DataFrame([...])
|
275
|
+
>>> combined_df = MessageUtil.extend(df_main, df_additional, keep='first')
|
280
276
|
"""
|
281
277
|
|
282
278
|
MessageUtil.validate_messages(df2)
|
@@ -288,7 +284,7 @@ class MessageUtil:
|
|
288
284
|
)
|
289
285
|
return convert.to_df(df)
|
290
286
|
except Exception as e:
|
291
|
-
raise ValueError(f"Error in extending messages: {e}")
|
287
|
+
raise ValueError(f"Error in extending messages: {e}") from e
|
292
288
|
|
293
289
|
@staticmethod
|
294
290
|
def to_markdown_string(messages: dataframe.ln_DataFrame) -> str:
|
@@ -296,11 +292,11 @@ class MessageUtil:
|
|
296
292
|
Converts messages in a DataFrame to a Markdown-formatted string for easy reading.
|
297
293
|
|
298
294
|
Args:
|
299
|
-
|
295
|
+
messages: A DataFrame containing messages with columns for 'role' and 'content'.
|
300
296
|
|
301
297
|
Returns:
|
302
|
-
|
303
|
-
|
298
|
+
A string formatted in Markdown, where each message's content is presented
|
299
|
+
according to its role in a readable format.
|
304
300
|
"""
|
305
301
|
|
306
302
|
answers = []
|
@@ -308,101 +304,20 @@ class MessageUtil:
|
|
308
304
|
content = convert.to_dict(i.content)
|
309
305
|
|
310
306
|
if i.role == "assistant":
|
311
|
-
|
307
|
+
with contextlib.suppress(Exception):
|
312
308
|
a = nested.nget(content, ["action_response", "func"])
|
313
309
|
b = nested.nget(content, ["action_response", "arguments"])
|
314
310
|
c = nested.nget(content, ["action_response", "output"])
|
315
311
|
if a is not None:
|
316
|
-
answers.
|
317
|
-
|
318
|
-
|
312
|
+
answers.extend(
|
313
|
+
(f"Function: {a}", f"Arguments: {b}", f"Output: {c}")
|
314
|
+
)
|
319
315
|
else:
|
320
316
|
answers.append(nested.nget(content, ["assistant_response"]))
|
321
|
-
except:
|
322
|
-
pass
|
323
317
|
elif i.role == "user":
|
324
|
-
|
318
|
+
with contextlib.suppress(Exception):
|
325
319
|
answers.append(nested.nget(content, ["instruction"]))
|
326
|
-
except:
|
327
|
-
pass
|
328
320
|
else:
|
329
|
-
|
321
|
+
with contextlib.suppress(Exception):
|
330
322
|
answers.append(nested.nget(content, ["system_info"]))
|
331
|
-
|
332
|
-
pass
|
333
|
-
|
334
|
-
out_ = "\n".join(answers)
|
335
|
-
return out_
|
336
|
-
|
337
|
-
# @staticmethod
|
338
|
-
# def to_json_content(value):
|
339
|
-
# if isinstance(value, dict):
|
340
|
-
# for key, val in value.items():
|
341
|
-
# value[key] = MessageUtil.to_json_content(val)
|
342
|
-
# value = json.dumps(value)
|
343
|
-
# if isinstance(value, list):
|
344
|
-
# for i in range(len(value)):
|
345
|
-
# value[i] = MessageUtil.to_json_content(value[i])
|
346
|
-
# return value
|
347
|
-
|
348
|
-
# @staticmethod
|
349
|
-
# def to_dict_content(value):
|
350
|
-
# try:
|
351
|
-
# value = json.loads(value)
|
352
|
-
# if isinstance(value, dict):
|
353
|
-
# for key, val in value.items():
|
354
|
-
# value[key] = MessageUtil.to_dict_content(val)
|
355
|
-
# if isinstance(value, list):
|
356
|
-
# for i in range(len(value)):
|
357
|
-
# value[i] = MessageUtil.to_dict_content(value[i])
|
358
|
-
# return value
|
359
|
-
# except:
|
360
|
-
# return value
|
361
|
-
|
362
|
-
# @staticmethod
|
363
|
-
# def response_to_message(response: dict[str, Any], **kwargs) -> Any:
|
364
|
-
# """
|
365
|
-
# Processes a message response dictionary to generate an appropriate message object.
|
366
|
-
|
367
|
-
# Args:
|
368
|
-
# response: A dictionary potentially containing message information.
|
369
|
-
# **kwargs: Additional keyword arguments to pass to the message constructors.
|
370
|
-
|
371
|
-
# Returns:
|
372
|
-
# An instance of a message class, such as ActionRequest or AssistantResponse,
|
373
|
-
# depending on the content of the response.
|
374
|
-
# """
|
375
|
-
# try:
|
376
|
-
# response = response["message"]
|
377
|
-
# if .strip_lower(response['content']) == "none":
|
378
|
-
|
379
|
-
# content = ActionRequest._handle_action_request(response)
|
380
|
-
# return ActionRequest(action_request=content, **kwargs)
|
381
|
-
|
382
|
-
# else:
|
383
|
-
|
384
|
-
# try:
|
385
|
-
# if 'tool_uses' in to_dict(response[MessageField.CONTENT.value]):
|
386
|
-
# content_ = to_dict(response[MessageField.CONTENT.value])[
|
387
|
-
# 'tool_uses']
|
388
|
-
# return ActionRequest(action_request=content_, **kwargs)
|
389
|
-
|
390
|
-
# elif MessageContentKey.RESPONSE.value in to_dict(
|
391
|
-
# response[MessageField.CONTENT.value]):
|
392
|
-
# content_ = to_dict(response[MessageField.CONTENT.value])[
|
393
|
-
# MessageContentKey.RESPONSE.value]
|
394
|
-
# return AssistantResponse(assistant_response=content_, **kwargs)
|
395
|
-
|
396
|
-
# elif MessageContentKey.ACTION_REQUEST.value in to_dict(
|
397
|
-
# response[MessageField.CONTENT.value]):
|
398
|
-
# content_ = to_dict(response[MessageField.CONTENT.value])[
|
399
|
-
# MessageContentKey.ACTION_REQUEST.value]
|
400
|
-
# return ActionRequest(action_request=content_, **kwargs)
|
401
|
-
|
402
|
-
# else:
|
403
|
-
# return AssistantResponse(assistant_response=response, **kwargs)
|
404
|
-
|
405
|
-
# except:
|
406
|
-
# return AssistantResponse(assistant_response=response, **kwargs)
|
407
|
-
# except:
|
408
|
-
# return ActionResponse(action_response=response, **kwargs)
|
323
|
+
return "\n".join(answers)
|