lionagi 0.0.201__py3-none-any.whl → 0.0.204__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- lionagi/_services/anthropic.py +79 -1
- lionagi/_services/base_service.py +1 -1
- lionagi/_services/services.py +61 -25
- lionagi/_services/transformers.py +46 -0
- lionagi/agents/__init__.py +0 -0
- lionagi/configs/oai_configs.py +1 -1
- lionagi/configs/openrouter_configs.py +1 -1
- lionagi/core/__init__.py +3 -7
- lionagi/core/branch/__init__.py +0 -0
- lionagi/core/branch/branch.py +589 -0
- lionagi/core/branch/branch_manager.py +139 -0
- lionagi/core/branch/cluster.py +1 -0
- lionagi/core/branch/conversation.py +484 -0
- lionagi/core/core_util.py +59 -0
- lionagi/core/flow/__init__.py +0 -0
- lionagi/core/flow/flow.py +19 -0
- lionagi/core/instruction_set/__init__.py +0 -0
- lionagi/core/instruction_set/instruction_set.py +343 -0
- lionagi/core/messages/__init__.py +0 -0
- lionagi/core/messages/messages.py +176 -0
- lionagi/core/sessions/__init__.py +0 -0
- lionagi/core/sessions/session.py +428 -0
- lionagi/models/__init__.py +0 -0
- lionagi/models/base_model.py +0 -0
- lionagi/models/imodel.py +53 -0
- lionagi/schema/data_logger.py +75 -155
- lionagi/tests/test_utils/test_call_util.py +658 -657
- lionagi/tools/tool_manager.py +121 -188
- lionagi/utils/__init__.py +5 -10
- lionagi/utils/call_util.py +667 -585
- lionagi/utils/io_util.py +3 -0
- lionagi/utils/nested_util.py +17 -211
- lionagi/utils/pd_util.py +57 -0
- lionagi/utils/sys_util.py +220 -184
- lionagi/utils/url_util.py +55 -0
- lionagi/version.py +1 -1
- {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/METADATA +12 -8
- {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/RECORD +47 -32
- lionagi/core/branch.py +0 -193
- lionagi/core/conversation.py +0 -341
- lionagi/core/flow.py +0 -8
- lionagi/core/instruction_set.py +0 -150
- lionagi/core/messages.py +0 -243
- lionagi/core/sessions.py +0 -474
- /lionagi/{tools → agents}/planner.py +0 -0
- /lionagi/{tools → agents}/prompter.py +0 -0
- /lionagi/{tools → agents}/scorer.py +0 -0
- /lionagi/{tools → agents}/summarizer.py +0 -0
- /lionagi/{tools → agents}/validator.py +0 -0
- /lionagi/core/{flow_util.py → flow/flow_util.py} +0 -0
- {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/LICENSE +0 -0
- {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/WHEEL +0 -0
- {lionagi-0.0.201.dist-info → lionagi-0.0.204.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
"""async def critic_workflow():
|
2
|
+
|
3
|
+
@ cd.max_concurrency(limit=3)
|
4
|
+
async def run_critic_stage(critic_idx=None, step_num=None, outs=None, max_num_tool_uses=5):
|
5
|
+
|
6
|
+
async def inner_func_():
|
7
|
+
critic_ = f"critic{critic_idx}"
|
8
|
+
name_ = li.nget(critics, [critic_, "name"])
|
9
|
+
tool = li.nget(critics, [critic_, "tool"])
|
10
|
+
instruction_ = li.nget(critics, [critic_, f"step{step_num}"])
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
out = await researcher.auto_followup(branch=name_, instruction=instruction_, tools=tool, num=max_num_tool_uses)
|
15
|
+
add_name_to_messages(name_)
|
16
|
+
last_response = last_response_row(df=researcher.branches[name_].messages, name_=name_)
|
17
|
+
outs.append(last_response)
|
18
|
+
|
19
|
+
return out"""
|
File without changes
|
@@ -0,0 +1,343 @@
|
|
1
|
+
from typing import List, Union
|
2
|
+
from ...schema import Tool
|
3
|
+
from ...structures import Relationship, Structure
|
4
|
+
from ..messages.messages import Instruction
|
5
|
+
|
6
|
+
|
7
|
+
class InstructionSet(Structure):
|
8
|
+
"""
|
9
|
+
Represents a set of instructions and their relationships to tools.
|
10
|
+
|
11
|
+
Attributes:
|
12
|
+
last_instruct (Optional[str]): ID of the last instruction added.
|
13
|
+
first_instruct (Optional[str]): ID of the first instruction added.
|
14
|
+
instruct_len (int): The total number of instructions.
|
15
|
+
|
16
|
+
Example usage:
|
17
|
+
>>> instruction_set = InstructionSet()
|
18
|
+
>>> instruction = Instruction(...)
|
19
|
+
>>> tool = Tool(...)
|
20
|
+
>>> instruction_set.add_instruction(instruction)
|
21
|
+
>>> instruction_set.add_instruction(instruction, tools=tool)
|
22
|
+
>>> instruction_set.pop_instruction()
|
23
|
+
>>> instruction_node = instruction_set.get_instruction_by_id('node_id')
|
24
|
+
>>> next_instruction = instruction_set.get_next_instruction(instruction_node)
|
25
|
+
>>> tools = instruction_set.get_associated_tools(instruction_node)
|
26
|
+
"""
|
27
|
+
last_instruct: str = None
|
28
|
+
first_instruct: str = None
|
29
|
+
instruct_len: int = 0
|
30
|
+
|
31
|
+
def add_instruction(self, instruction: Instruction, tools: Union[Tool, List[Tool]] = None):
|
32
|
+
"""
|
33
|
+
Add an instruction to the instruction set.
|
34
|
+
|
35
|
+
Args:
|
36
|
+
instruction (Instruction): The instruction to add.
|
37
|
+
tools (Union[Tool, List[Tool]], optional): The tool or list of tools related to the instruction.
|
38
|
+
|
39
|
+
Example usage:
|
40
|
+
>>> instruction_set = InstructionSet()
|
41
|
+
>>> instruction = Instruction(...)
|
42
|
+
>>> tool = Tool(...)
|
43
|
+
>>> instruction_set.push_instruction(instruction)
|
44
|
+
>>> instruction_set.push_instruction(instruction, tools=tool)
|
45
|
+
"""
|
46
|
+
|
47
|
+
if self.graph.is_empty():
|
48
|
+
self.graph.add_node(instruction)
|
49
|
+
self.last_instruct = instruction.id_
|
50
|
+
self.first_instruct = instruction.id_
|
51
|
+
else:
|
52
|
+
relationship = Relationship(source_node_id=self.last_instruct, target_node_id=instruction.id_, label='instruction')
|
53
|
+
self.graph.add_node(instruction)
|
54
|
+
self.graph.add_relationship(relationship)
|
55
|
+
self.last_instruct = instruction.id_
|
56
|
+
self.instruct_len += 1
|
57
|
+
|
58
|
+
if tools:
|
59
|
+
if isinstance(tools, Tool):
|
60
|
+
tools = [tools]
|
61
|
+
for tool in tools:
|
62
|
+
relationship = Relationship(source_node_id=tool.id_, target_node_id=self.last_instruct, label='tool')
|
63
|
+
self.graph.add_node(tool)
|
64
|
+
self.graph.add_relationship(relationship)
|
65
|
+
|
66
|
+
def pop_instruction(self):
|
67
|
+
"""
|
68
|
+
Remove the last instruction from the instruction set.
|
69
|
+
|
70
|
+
Example usage:
|
71
|
+
>>> instruction_set = InstructionSet()
|
72
|
+
>>> instruction_set.pop_instruction()
|
73
|
+
"""
|
74
|
+
if self.graph.is_empty():
|
75
|
+
return
|
76
|
+
elif self.instruct_len == 1:
|
77
|
+
self.graph.clear()
|
78
|
+
self.last_instruct = None
|
79
|
+
self.first_instruct = None
|
80
|
+
self.instruct_len -= 1
|
81
|
+
else:
|
82
|
+
relationships = self.get_node_relationships(self.graph.nodes[self.last_instruct], out_edge=False)
|
83
|
+
prev_instruct = None
|
84
|
+
for r in relationships:
|
85
|
+
if r.label != 'instruction':
|
86
|
+
self.graph.remove_node(self.graph.nodes[r.source_node_id])
|
87
|
+
else:
|
88
|
+
prev_instruct = r.source_node_id
|
89
|
+
|
90
|
+
self.graph.remove_node(self.graph.nodes[self.last_instruct])
|
91
|
+
self.last_instruct = prev_instruct
|
92
|
+
self.instruct_len -= 1
|
93
|
+
|
94
|
+
def get_instruction_by_id(self, node_id):
|
95
|
+
"""
|
96
|
+
Retrieve an instruction by its ID.
|
97
|
+
|
98
|
+
Args:
|
99
|
+
node_id (str): The ID of the instruction node.
|
100
|
+
|
101
|
+
Returns:
|
102
|
+
Instruction: The instruction node associated with the given ID.
|
103
|
+
|
104
|
+
Example usage:
|
105
|
+
>>> instruction_set = InstructionSet()
|
106
|
+
>>> instruction_node = instruction_set.get_instruction_by_id('node_id')
|
107
|
+
"""
|
108
|
+
return self.graph.nodes[node_id]
|
109
|
+
|
110
|
+
def get_next_instruction(self, instruct_node: Instruction):
|
111
|
+
"""
|
112
|
+
Retrieve the next instruction following the given instruction node.
|
113
|
+
|
114
|
+
Args:
|
115
|
+
instruct_node (Instruction): The current instruction node.
|
116
|
+
|
117
|
+
Returns:
|
118
|
+
Optional[Instruction]: The next instruction node in the sequence, if it exists.
|
119
|
+
|
120
|
+
Example usage:
|
121
|
+
>>> instruction_set = InstructionSet()
|
122
|
+
>>> current_node = Instruction(...)
|
123
|
+
>>> next_node = instruction_set.get_next_instruction(current_node)
|
124
|
+
"""
|
125
|
+
relationship = self.get_node_relationships(instruct_node)
|
126
|
+
if relationship:
|
127
|
+
return self.graph.nodes[relationship[0].target_node_id]
|
128
|
+
|
129
|
+
def get_tools(self, instruct_node: Instruction):
|
130
|
+
"""
|
131
|
+
Retrieve the tools associated with a given instruction node.
|
132
|
+
|
133
|
+
Args:
|
134
|
+
instruct_node (Instruction): The instruction node to retrieve tools for.
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
List[Tool]: The tools associated with the instruction node.
|
138
|
+
|
139
|
+
Example usage:
|
140
|
+
>>> instruction_set = InstructionSet()
|
141
|
+
>>> instruction_node = Instruction(...)
|
142
|
+
>>> tools = instruction_set.get_tools(instruction_node)
|
143
|
+
"""
|
144
|
+
relationships = self.get_node_relationships(instruct_node, out_edge=False, labels=['tool'])
|
145
|
+
tools = []
|
146
|
+
for r in relationships:
|
147
|
+
tool = self.graph.nodes[r.source_node_id]
|
148
|
+
tools.append(tool)
|
149
|
+
return tools
|
150
|
+
|
151
|
+
# # new methods
|
152
|
+
# def insert_instruction(self, index: int, instruction: Instruction, tools: Union[Tool, List[Tool]] = None):
|
153
|
+
# """
|
154
|
+
# Insert an instruction at a specified index in the instruction set.
|
155
|
+
#
|
156
|
+
# Args:
|
157
|
+
# index (int): The index to insert the instruction at.
|
158
|
+
# instruction (Instruction): The instruction to insert.
|
159
|
+
# tools (Union[Tool, List[Tool]], optional): The tool or list of tools related to the instruction.
|
160
|
+
# """
|
161
|
+
# if index < 0 or index > self.instruct_len:
|
162
|
+
# raise IndexError("Index out of bounds.")
|
163
|
+
#
|
164
|
+
# if index == self.instruct_len:
|
165
|
+
# self.add_instruction(instruction, tools)
|
166
|
+
# return
|
167
|
+
#
|
168
|
+
# # Adjust relationships and insert the new instruction
|
169
|
+
# current_node = self.first_instruct
|
170
|
+
# for _ in range(index):
|
171
|
+
# next_node = self.get_next_instruction(self.graph.nodes[current_node])
|
172
|
+
# current_node = next_node.id_
|
173
|
+
#
|
174
|
+
# prev_node = self.graph.get_node_relationships(current_node, out_edge=False)
|
175
|
+
# prev_node_id = prev_node[0].source_node_id if prev_node else None
|
176
|
+
#
|
177
|
+
# if prev_node_id:
|
178
|
+
# self.graph.remove_relationship_between(prev_node_id, current_node)
|
179
|
+
#
|
180
|
+
# new_rel = Relationship(prev_node_id, instruction.id_, 'instruction')
|
181
|
+
# self.graph.add_node(instruction)
|
182
|
+
# self.graph.add_relationship(new_rel)
|
183
|
+
# self.graph.add_relationship(Relationship(instruction.id_, current_node, 'instruction'))
|
184
|
+
#
|
185
|
+
# self.instruct_len += 1
|
186
|
+
# self._add_tools_to_instruction(instruction, tools)
|
187
|
+
#
|
188
|
+
# def replace_instruction(self, instruction_id: str, new_instruction: Instruction):
|
189
|
+
# """
|
190
|
+
# Replace an existing instruction with a new instruction.
|
191
|
+
#
|
192
|
+
# Args:
|
193
|
+
# instruction_id (str): The ID of the instruction to replace.
|
194
|
+
# new_instruction (Instruction): The new instruction to replace with.
|
195
|
+
# """
|
196
|
+
# if not self.graph.node_exist(instruction_id):
|
197
|
+
# return False
|
198
|
+
#
|
199
|
+
# prev_rel = self.graph.get_node_relationships(instruction_id, out_edge=False)
|
200
|
+
# next_rel = self.graph.get_node_relationships(instruction_id)
|
201
|
+
#
|
202
|
+
# if prev_rel:
|
203
|
+
# self.graph.remove_relationship(prev_rel[0])
|
204
|
+
# self.graph.add_relationship(Relationship(prev_rel[0].source_node_id, new_instruction.id_, 'instruction'))
|
205
|
+
#
|
206
|
+
# if next_rel:
|
207
|
+
# self.graph.remove_relationship(next_rel[0])
|
208
|
+
# self.graph.add_relationship(Relationship(new_instruction.id_, next_rel[0].target_node_id, 'instruction'))
|
209
|
+
#
|
210
|
+
# self.graph.replace_node(instruction_id, new_instruction)
|
211
|
+
# return True
|
212
|
+
#
|
213
|
+
# def move_instruction(self, instruction_id: str, new_index: int):
|
214
|
+
# """
|
215
|
+
# Move an instruction to a new index within the instruction set.
|
216
|
+
#
|
217
|
+
# Args:
|
218
|
+
# instruction_id (str): The ID of the instruction to move.
|
219
|
+
# new_index (int): The new index to move the instruction to.
|
220
|
+
# """
|
221
|
+
# if not self.graph.node_exist(instruction_id) or new_index < 0 or new_index >= self.instruct_len:
|
222
|
+
# return False
|
223
|
+
#
|
224
|
+
# # Remove the instruction from its current position
|
225
|
+
# removed_instruction = self.graph.remove_node(instruction_id)
|
226
|
+
# if removed_instruction:
|
227
|
+
# # Reinsert at the new position
|
228
|
+
# self.insert_instruction(new_index, removed_instruction)
|
229
|
+
# return True
|
230
|
+
# return False
|
231
|
+
#
|
232
|
+
# def clear_instructions(self):
|
233
|
+
# """
|
234
|
+
# Clear all instructions from the instruction set.
|
235
|
+
# """
|
236
|
+
# self.graph.clear()
|
237
|
+
# self.last_instruct = None
|
238
|
+
# self.first_instruct = None
|
239
|
+
# self.instruct_len = 0
|
240
|
+
#
|
241
|
+
# def _add_tools_to_instruction(self, instruction: Instruction, tools: Union[Tool, List[Tool]]):
|
242
|
+
# """
|
243
|
+
# Helper method to add tools to an instruction.
|
244
|
+
#
|
245
|
+
# Args:
|
246
|
+
# instruction (Instruction): The instruction to associate tools with.
|
247
|
+
# tools (Union[Tool, List[Tool]]): The tool or list of tools to associate.
|
248
|
+
# """
|
249
|
+
# if tools:
|
250
|
+
# if isinstance(tools, Tool):
|
251
|
+
# tools = [tools]
|
252
|
+
# for tool in tools:
|
253
|
+
# relationship = Relationship(source_node_id=tool.id_, target_node_id=instruction.id_, label='tool')
|
254
|
+
# self.graph.add_node(tool)
|
255
|
+
# self.graph.add_relationship(relationship)
|
256
|
+
#
|
257
|
+
#
|
258
|
+
# def get_previous_instruction(self, instruct_node: Instruction):
|
259
|
+
# """
|
260
|
+
# Retrieve the previous instruction before the given instruction node.
|
261
|
+
#
|
262
|
+
# Args:
|
263
|
+
# instruct_node (Instruction): The current instruction node.
|
264
|
+
#
|
265
|
+
# Returns:
|
266
|
+
# Optional[Instruction]: The previous instruction node, if it exists.
|
267
|
+
#
|
268
|
+
# Example usage:
|
269
|
+
# >>> instruction_set = InstructionSet()
|
270
|
+
# >>> current_node = Instruction(...)
|
271
|
+
# >>> prev_node = instruction_set.get_previous_instruction(current_node)
|
272
|
+
# """
|
273
|
+
# relationship = self.get_node_relationships(instruct_node, out_edge=False)
|
274
|
+
# if relationship:
|
275
|
+
# return self.graph.nodes[relationship[0].source_node_id]
|
276
|
+
#
|
277
|
+
# def get_all_instructions(self):
|
278
|
+
# """
|
279
|
+
# Retrieve all instructions in the set.
|
280
|
+
#
|
281
|
+
# Returns:
|
282
|
+
# List[Instruction]: List of all instructions in the set.
|
283
|
+
#
|
284
|
+
# Example usage:
|
285
|
+
# >>> instruction_set = InstructionSet()
|
286
|
+
# >>> all_instructions = instruction_set.get_all_instructions()
|
287
|
+
# """
|
288
|
+
# instructions = []
|
289
|
+
# current_node_id = self.first_instruct
|
290
|
+
# while current_node_id:
|
291
|
+
# current_node = self.graph.nodes[current_node_id]
|
292
|
+
# instructions.append(current_node)
|
293
|
+
# next_rel = self.get_node_relationships(current_node)
|
294
|
+
# current_node_id = next_rel[0].target_node_id if next_rel else None
|
295
|
+
# return instructions
|
296
|
+
#
|
297
|
+
# def find_instructions_by_label(self, label: str):
|
298
|
+
# """
|
299
|
+
# Find all instructions that have a specific label.
|
300
|
+
#
|
301
|
+
# Args:
|
302
|
+
# label (str): The label to search for in instructions.
|
303
|
+
#
|
304
|
+
# Returns:
|
305
|
+
# List[Instruction]: List of instructions that have the specified label.
|
306
|
+
#
|
307
|
+
# Example usage:
|
308
|
+
# >>> instruction_set = InstructionSet()
|
309
|
+
# >>> specific_instructions = instruction_set.find_instructions_by_label('label_name')
|
310
|
+
# """
|
311
|
+
# return [node for node in self.graph.nodes.values() if isinstance(node, Instruction) and node.label == label]
|
312
|
+
|
313
|
+
# def remove_instruction_by_id(self, instruction_id: str):
|
314
|
+
# """
|
315
|
+
# Remove an instruction from the set by its ID.
|
316
|
+
#
|
317
|
+
# Args:
|
318
|
+
# instruction_id (str): The ID of the instruction to remove.
|
319
|
+
#
|
320
|
+
# Returns:
|
321
|
+
# bool: True if the instruction was removed, False otherwise.
|
322
|
+
#
|
323
|
+
# Example usage:
|
324
|
+
# >>> instruction_set = InstructionSet()
|
325
|
+
# >>> instruction_set.remove_instruction_by_id('instruction_id')
|
326
|
+
# """
|
327
|
+
# if instruction_id not in self.graph.nodes:
|
328
|
+
# return False
|
329
|
+
# to_remove = self.graph.nodes[instruction_id]
|
330
|
+
# prev_rel = self.graph.get_node_relationships(instruction_id, out_edge=False)
|
331
|
+
# next_rel = self.graph.get_node_relationships(instruction_id)
|
332
|
+
#
|
333
|
+
# if prev_rel and next_rel:
|
334
|
+
# self.graph.add_relationship(Relationship(prev_rel[0].source_node_id, next_rel[0].target_node_id, 'instruction'))
|
335
|
+
#
|
336
|
+
# self.graph.remove_node(to_remove)
|
337
|
+
# self.instruct_len -= 1
|
338
|
+
# if instruction_id == self.first_instruct:
|
339
|
+
# self.first_instruct = next_rel[0].target_node_id if next_rel else None
|
340
|
+
# if instruction_id == self.last_instruct:
|
341
|
+
# self.last_instruct = prev_rel[0].source_node_id if prev_rel else None
|
342
|
+
#
|
343
|
+
# return True
|
File without changes
|
@@ -0,0 +1,176 @@
|
|
1
|
+
from typing import Any, Dict, Optional
|
2
|
+
from lionagi.schema.base_node import BaseNode
|
3
|
+
|
4
|
+
from lionagi.utils.sys_util import strip_lower
|
5
|
+
from lionagi.utils.nested_util import nget
|
6
|
+
|
7
|
+
import json
|
8
|
+
|
9
|
+
|
10
|
+
class Message(BaseNode):
|
11
|
+
"""
|
12
|
+
Represents a message in a chatbot-like system, inheriting from BaseNode.
|
13
|
+
|
14
|
+
Attributes:
|
15
|
+
role (Optional[str]): The role of the entity sending the message, e.g., 'user', 'system'.
|
16
|
+
sender (Optional[str]): The identifier of the sender of the message.
|
17
|
+
content (Any): The actual content of the message.
|
18
|
+
"""
|
19
|
+
|
20
|
+
|
21
|
+
role: Optional[str] = None
|
22
|
+
sender: Optional[str] = None
|
23
|
+
|
24
|
+
@property
|
25
|
+
def msg(self) -> Dict[str, Any]:
|
26
|
+
"""
|
27
|
+
Constructs and returns a dictionary representation of the message.
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
A dictionary representation of the message with 'role' and 'content' keys.
|
31
|
+
"""
|
32
|
+
return self._to_message()
|
33
|
+
|
34
|
+
@property
|
35
|
+
def msg_content(self) -> Any:
|
36
|
+
"""
|
37
|
+
Gets the 'content' field of the message.
|
38
|
+
|
39
|
+
Returns:
|
40
|
+
The 'content' part of the message.
|
41
|
+
"""
|
42
|
+
return self.msg['content']
|
43
|
+
|
44
|
+
@property
|
45
|
+
def sender(self) -> str:
|
46
|
+
return self.sender
|
47
|
+
|
48
|
+
def _to_message(self):
|
49
|
+
"""
|
50
|
+
Constructs and returns a dictionary representation of the message.
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
dict: A dictionary representation of the message with 'role' and 'content' keys.
|
54
|
+
"""
|
55
|
+
out = {
|
56
|
+
"role": self.role,
|
57
|
+
"content": json.dumps(self.content) if isinstance(self.content, dict) else self.content
|
58
|
+
}
|
59
|
+
return out
|
60
|
+
|
61
|
+
def __str__(self):
|
62
|
+
content_preview = (
|
63
|
+
(str(self.content)[:75] + '...') if self.content and len(self.content) > 75
|
64
|
+
else str(self.content)
|
65
|
+
)
|
66
|
+
return f"Message(role={self.role}, sender={self.sender}, content='{content_preview}')"
|
67
|
+
|
68
|
+
class Instruction(Message):
|
69
|
+
"""
|
70
|
+
Represents an instruction message, a specialized subclass of Message.
|
71
|
+
|
72
|
+
This class is specifically used for creating messages that are instructions from the user,
|
73
|
+
including any associated context. It sets the message role to 'user'.
|
74
|
+
"""
|
75
|
+
|
76
|
+
def __init__(self, instruction: Any, context=None, sender: Optional[str] = None):
|
77
|
+
super().__init__(
|
78
|
+
role="user", sender=sender or 'user', content={"instruction": instruction}
|
79
|
+
)
|
80
|
+
if context:
|
81
|
+
self.content.update({"context": context})
|
82
|
+
|
83
|
+
class System(Message):
|
84
|
+
"""
|
85
|
+
Represents a system-related message, a specialized subclass of Message.
|
86
|
+
|
87
|
+
Designed for messages containing system information, this class sets the message role to 'system'.
|
88
|
+
"""
|
89
|
+
def __init__(self, system: Any, sender: Optional[str] = None):
|
90
|
+
super().__init__(
|
91
|
+
role="system", sender=sender or 'system', content={"system_info": system}
|
92
|
+
)
|
93
|
+
|
94
|
+
class Response(Message):
|
95
|
+
"""
|
96
|
+
Represents a response message, a specialized subclass of Message.
|
97
|
+
|
98
|
+
Used for various types of response messages including regular responses, action requests,
|
99
|
+
and action responses. It sets the message role to 'assistant'.
|
100
|
+
|
101
|
+
"""
|
102
|
+
|
103
|
+
def __init__(self, response: Any, sender: Optional[str] = None) -> None:
|
104
|
+
content_key = ''
|
105
|
+
try:
|
106
|
+
response = response["message"]
|
107
|
+
if strip_lower(response['content']) == "none":
|
108
|
+
content_ = self._handle_action_request(response)
|
109
|
+
sender = sender or "action_request"
|
110
|
+
content_key = content_key or "action_list"
|
111
|
+
|
112
|
+
else:
|
113
|
+
try:
|
114
|
+
if 'tool_uses' in json.loads(response['content']):
|
115
|
+
content_ = json.loads(response['content'])['tool_uses']
|
116
|
+
content_key = content_key or "action_list"
|
117
|
+
sender = sender or "action_request"
|
118
|
+
elif 'response' in json.loads(response['content']):
|
119
|
+
sender = sender or "assistant"
|
120
|
+
content_key = content_key or "response"
|
121
|
+
content_ = json.loads(response['content'])['response']
|
122
|
+
elif 'action_list' in json.loads(response['content']):
|
123
|
+
sender = sender or "action_request"
|
124
|
+
content_key = content_key or "action_list"
|
125
|
+
content_ = json.loads(response['content'])['action_list']
|
126
|
+
else:
|
127
|
+
content_ = response['content']
|
128
|
+
content_key = content_key or "response"
|
129
|
+
sender = sender or "assistant"
|
130
|
+
except:
|
131
|
+
content_ = response['content']
|
132
|
+
content_key = content_key or "response"
|
133
|
+
sender = sender or "assistant"
|
134
|
+
|
135
|
+
except:
|
136
|
+
sender = sender or "action_response"
|
137
|
+
content_ = response
|
138
|
+
content_key = content_key or "action_response"
|
139
|
+
|
140
|
+
super().__init__(role="assistant", sender=sender, content={content_key: content_})
|
141
|
+
|
142
|
+
@staticmethod
|
143
|
+
def _handle_action_request(response):
|
144
|
+
"""
|
145
|
+
Processes an action request response and extracts relevant information.
|
146
|
+
|
147
|
+
Args:
|
148
|
+
response (dict): The response dictionary containing tool calls and other information.
|
149
|
+
|
150
|
+
Returns:
|
151
|
+
list: A list of dictionaries, each representing a function call with action and arguments.
|
152
|
+
|
153
|
+
Raises:
|
154
|
+
ValueError: If the response does not conform to the expected format for action requests.
|
155
|
+
"""
|
156
|
+
try:
|
157
|
+
tool_count = 0
|
158
|
+
func_list = []
|
159
|
+
while tool_count < len(response['tool_calls']):
|
160
|
+
_path = ['tool_calls', tool_count, 'type']
|
161
|
+
|
162
|
+
if nget(response, _path) == 'function':
|
163
|
+
_path1 = ['tool_calls', tool_count, 'function', 'name']
|
164
|
+
_path2 = ['tool_calls', tool_count, 'function', 'arguments']
|
165
|
+
|
166
|
+
func_content = {
|
167
|
+
"action": ("action_" + nget(response, _path1)),
|
168
|
+
"arguments": nget(response, _path2)
|
169
|
+
}
|
170
|
+
func_list.append(func_content)
|
171
|
+
tool_count += 1
|
172
|
+
return func_list
|
173
|
+
except:
|
174
|
+
raise ValueError(
|
175
|
+
"Response message must be one of regular response or function calling"
|
176
|
+
)
|
File without changes
|