lionagi 0.0.201__py3-none-any.whl → 0.0.204__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/_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
|