lionagi 0.0.208__py3-none-any.whl → 0.0.210__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- lionagi/__init__.py +4 -6
- lionagi/api_service/base_endpoint.py +65 -0
- lionagi/api_service/base_rate_limiter.py +121 -0
- lionagi/api_service/base_service.py +146 -0
- lionagi/api_service/chat_completion.py +6 -0
- lionagi/api_service/embeddings.py +6 -0
- lionagi/api_service/payload_package.py +47 -0
- lionagi/api_service/status_tracker.py +29 -0
- lionagi/core/__init__.py +5 -9
- lionagi/core/branch.py +1191 -0
- lionagi/core/flow.py +423 -0
- lionagi/core/{instruction_set/instruction_set.py → instruction_set.py} +3 -3
- lionagi/core/session.py +872 -0
- lionagi/schema/__init__.py +5 -8
- lionagi/schema/base_schema.py +821 -0
- lionagi/{_services → services}/base_service.py +4 -4
- lionagi/{_services → services}/oai.py +4 -4
- lionagi/structures/graph.py +1 -1
- lionagi/structures/relationship.py +1 -1
- lionagi/structures/structure.py +1 -1
- lionagi/tools/tool_manager.py +0 -163
- lionagi/tools/tool_util.py +2 -1
- lionagi/utils/__init__.py +7 -14
- lionagi/utils/api_util.py +63 -2
- lionagi/utils/core_utils.py +338 -0
- lionagi/utils/sys_util.py +3 -3
- lionagi/version.py +1 -1
- {lionagi-0.0.208.dist-info → lionagi-0.0.210.dist-info}/METADATA +28 -29
- lionagi-0.0.210.dist-info/RECORD +56 -0
- lionagi/_services/anthropic.py +0 -79
- lionagi/_services/anyscale.py +0 -0
- lionagi/_services/azure.py +0 -1
- lionagi/_services/bedrock.py +0 -0
- lionagi/_services/everlyai.py +0 -0
- lionagi/_services/gemini.py +0 -0
- lionagi/_services/gpt4all.py +0 -0
- lionagi/_services/huggingface.py +0 -0
- lionagi/_services/litellm.py +0 -33
- lionagi/_services/localai.py +0 -0
- lionagi/_services/openllm.py +0 -0
- lionagi/_services/openrouter.py +0 -44
- lionagi/_services/perplexity.py +0 -0
- lionagi/_services/predibase.py +0 -0
- lionagi/_services/rungpt.py +0 -0
- lionagi/_services/vllm.py +0 -0
- lionagi/_services/xinference.py +0 -0
- lionagi/agents/planner.py +0 -1
- lionagi/agents/prompter.py +0 -1
- lionagi/agents/scorer.py +0 -1
- lionagi/agents/summarizer.py +0 -1
- lionagi/agents/validator.py +0 -1
- lionagi/bridge/__init__.py +0 -22
- lionagi/bridge/langchain.py +0 -195
- lionagi/bridge/llama_index.py +0 -266
- lionagi/core/branch/__init__.py +0 -0
- lionagi/core/branch/branch.py +0 -841
- lionagi/core/branch/cluster.py +0 -1
- lionagi/core/branch/conversation.py +0 -787
- lionagi/core/core_util.py +0 -0
- lionagi/core/flow/__init__.py +0 -0
- lionagi/core/flow/flow.py +0 -19
- lionagi/core/flow/flow_util.py +0 -62
- lionagi/core/instruction_set/__init__.py +0 -0
- lionagi/core/messages/__init__.py +0 -0
- lionagi/core/sessions/__init__.py +0 -0
- lionagi/core/sessions/session.py +0 -504
- lionagi/datastores/__init__.py +0 -1
- lionagi/datastores/chroma.py +0 -1
- lionagi/datastores/deeplake.py +0 -1
- lionagi/datastores/elasticsearch.py +0 -1
- lionagi/datastores/lantern.py +0 -1
- lionagi/datastores/pinecone.py +0 -1
- lionagi/datastores/postgres.py +0 -1
- lionagi/datastores/qdrant.py +0 -1
- lionagi/loaders/__init__.py +0 -18
- lionagi/loaders/chunker.py +0 -166
- lionagi/loaders/load_util.py +0 -240
- lionagi/loaders/reader.py +0 -122
- lionagi/models/__init__.py +0 -0
- lionagi/models/base_model.py +0 -0
- lionagi/models/imodel.py +0 -53
- lionagi/schema/async_queue.py +0 -158
- lionagi/schema/base_condition.py +0 -1
- lionagi/schema/base_node.py +0 -422
- lionagi/schema/base_tool.py +0 -44
- lionagi/schema/data_logger.py +0 -126
- lionagi/schema/data_node.py +0 -88
- lionagi/schema/status_tracker.py +0 -37
- lionagi/tests/test_utils/test_encrypt_util.py +0 -323
- lionagi/utils/encrypt_util.py +0 -283
- lionagi/utils/url_util.py +0 -55
- lionagi-0.0.208.dist-info/RECORD +0 -106
- lionagi/{agents → api_service}/__init__.py +0 -0
- lionagi/core/{branch/branch_manager.py → branch_manager.py} +0 -0
- lionagi/core/{messages/messages.py → messages.py} +3 -3
- /lionagi/{_services → services}/__init__.py +0 -0
- /lionagi/{_services → services}/mistralai.py +0 -0
- /lionagi/{_services → services}/mlx_service.py +0 -0
- /lionagi/{_services → services}/ollama.py +0 -0
- /lionagi/{_services → services}/services.py +0 -0
- /lionagi/{_services → services}/transformers.py +0 -0
- {lionagi-0.0.208.dist-info → lionagi-0.0.210.dist-info}/LICENSE +0 -0
- {lionagi-0.0.208.dist-info → lionagi-0.0.210.dist-info}/WHEEL +0 -0
- {lionagi-0.0.208.dist-info → lionagi-0.0.210.dist-info}/top_level.txt +0 -0
lionagi/core/session.py
ADDED
@@ -0,0 +1,872 @@
|
|
1
|
+
from collections import deque
|
2
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
3
|
+
|
4
|
+
import pandas as pd
|
5
|
+
from lionagi.utils.sys_util import create_path
|
6
|
+
from lionagi.utils import to_list, to_df
|
7
|
+
from lionagi.schema import Tool
|
8
|
+
from lionagi.services.base_service import BaseService
|
9
|
+
from lionagi.core.branch import Branch
|
10
|
+
from lionagi.core.branch_manager import BranchManager
|
11
|
+
from lionagi.core.messages import Instruction, System
|
12
|
+
|
13
|
+
|
14
|
+
class Session:
|
15
|
+
"""
|
16
|
+
Represents a session for managing conversations and branches.
|
17
|
+
|
18
|
+
A `Session` encapsulates the state and behavior for managing conversations and their branches.
|
19
|
+
It provides functionality for initializing and managing conversation sessions, including setting up default
|
20
|
+
branches, configuring language learning models, managing tools, and handling session data logging.
|
21
|
+
|
22
|
+
Attributes:
|
23
|
+
branches (Dict[str, Branch]): A dictionary of branch instances associated with the session.
|
24
|
+
service (Optional[BaseService]): The external service instance associated with the session.
|
25
|
+
branch_manager (BranchManager): The manager for handling branches within the session.
|
26
|
+
logger (Optional[Any]): The logger instance for session data logging.
|
27
|
+
"""
|
28
|
+
def __init__(
|
29
|
+
self,
|
30
|
+
system: Optional[Union[str, System]] = None,
|
31
|
+
sender: Optional[str] = None,
|
32
|
+
llmconfig: Optional[Dict[str, Any]] = None,
|
33
|
+
service: Optional[BaseService] = None,
|
34
|
+
branches: Optional[Dict[str, Branch]] = None,
|
35
|
+
default_branch: Optional[Branch] = None,
|
36
|
+
default_branch_name: Optional[str] = None,
|
37
|
+
tools: Optional[List[Tool]] = None,
|
38
|
+
instruction_sets: Optional[List[Instruction]] = None,
|
39
|
+
tool_manager: Optional[Any] = None,
|
40
|
+
messages: Optional[List[Dict[str, Any]]] = None,
|
41
|
+
logger: Optional[Any] = None,
|
42
|
+
dir: Optional[str] = None
|
43
|
+
):
|
44
|
+
"""Initialize a new session with optional configuration for managing conversations.
|
45
|
+
|
46
|
+
Args:
|
47
|
+
system (Optional[Union[str, System]]): The system message.
|
48
|
+
sender (Optional[str]): the default sender name for default branch
|
49
|
+
llmconfig (Optional[Dict[str, Any]]): Configuration for language learning models.
|
50
|
+
service (Optional[BaseService]): External service instance.
|
51
|
+
branches (Optional[Dict[str, Branch]]): Dictionary of branch instances.
|
52
|
+
default_branch (Optional[Branch]): The default branch for the session.
|
53
|
+
default_branch_name (Optional[str]): The name of the default branch.
|
54
|
+
tools (Optional[List[Tool]]): List of tools available for the session.
|
55
|
+
instruction_sets (Optional[List[Instruction]]): List of instruction sets.
|
56
|
+
tool_manager (Optional[Any]): Manager for handling tools.
|
57
|
+
messages (Optional[List[Dict[str, Any]]]): Initial list of messages.
|
58
|
+
logger (Optional[Any]): Logger instance for the session.
|
59
|
+
dir (Optional[str]): Directory path for saving session data.
|
60
|
+
|
61
|
+
Examples:
|
62
|
+
>>> session = Session(system="you are a helpful assistant", sender="researcher")
|
63
|
+
"""
|
64
|
+
self.branches = branches if isinstance(branches, dict) else {}
|
65
|
+
self.service = service
|
66
|
+
self.setup_default_branch(
|
67
|
+
system=system, sender=sender, default_branch=default_branch,
|
68
|
+
default_branch_name=default_branch_name, messages=messages,
|
69
|
+
instruction_sets=instruction_sets, tool_manager=tool_manager,
|
70
|
+
service=service, llmconfig=llmconfig, tools=tools,
|
71
|
+
dir=dir, logger=logger)
|
72
|
+
self.branch_manager = BranchManager(self.branches)
|
73
|
+
self.logger = self.default_branch.logger
|
74
|
+
|
75
|
+
|
76
|
+
# --- default branch methods ---- #
|
77
|
+
|
78
|
+
@property
|
79
|
+
def messages(self):
|
80
|
+
return self.default_branch.messages
|
81
|
+
|
82
|
+
@property
|
83
|
+
def messages_describe(self) -> Dict[str, Any]:
|
84
|
+
"""
|
85
|
+
Provides a descriptive summary of all messages in the branch.
|
86
|
+
|
87
|
+
Returns:
|
88
|
+
Dict[str, Any]: A dictionary containing summaries of messages by role and sender, total message count,
|
89
|
+
instruction sets, registered tools, and message details.
|
90
|
+
|
91
|
+
Examples:
|
92
|
+
>>> session.messages_describe
|
93
|
+
{'total_messages': 100, 'by_sender': {'User123': 60, 'Bot': 40}}
|
94
|
+
"""
|
95
|
+
return self.default_branch.messages_describe
|
96
|
+
|
97
|
+
@property
|
98
|
+
def has_tools(self) -> bool:
|
99
|
+
"""
|
100
|
+
Checks if there are any tools registered in the tool manager.
|
101
|
+
|
102
|
+
Returns:
|
103
|
+
bool: True if there are tools registered, False otherwise.
|
104
|
+
|
105
|
+
Examples:
|
106
|
+
>>> session.has_tools
|
107
|
+
True
|
108
|
+
"""
|
109
|
+
return self.default_branch.has_tools
|
110
|
+
|
111
|
+
@property
|
112
|
+
def last_message(self) -> pd.Series:
|
113
|
+
"""
|
114
|
+
Retrieves the last message from the conversation.
|
115
|
+
|
116
|
+
Returns:
|
117
|
+
pd.Series: The last message as a pandas Series.
|
118
|
+
"""
|
119
|
+
return self.default_branch.last_message
|
120
|
+
|
121
|
+
@property
|
122
|
+
def first_system(self) -> pd.Series:
|
123
|
+
"""
|
124
|
+
Retrieves the first system message from the conversation.
|
125
|
+
|
126
|
+
Returns:
|
127
|
+
pd.Series: The first system message as a pandas Series.
|
128
|
+
"""
|
129
|
+
return self.default_branch.first_system
|
130
|
+
|
131
|
+
@property
|
132
|
+
def last_response(self) -> pd.Series:
|
133
|
+
"""
|
134
|
+
Retrieves the last response message from the conversation.
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
pd.Series: The last response message as a pandas Series.
|
138
|
+
"""
|
139
|
+
return self.default_branch.last_response
|
140
|
+
|
141
|
+
@property
|
142
|
+
def last_response_content(self) -> Dict:
|
143
|
+
"""
|
144
|
+
Retrieves the content of the last response message from the conversation.
|
145
|
+
|
146
|
+
Returns:
|
147
|
+
Dict: The content of the last response message as a dictionary
|
148
|
+
"""
|
149
|
+
return self.default_branch.last_response_content
|
150
|
+
|
151
|
+
@property
|
152
|
+
def action_request(self) -> pd.DataFrame:
|
153
|
+
"""
|
154
|
+
Retrieves all action request messages from the conversation.
|
155
|
+
|
156
|
+
Returns:
|
157
|
+
pd.DataFrame: A DataFrame containing all action request messages.
|
158
|
+
"""
|
159
|
+
return self.default_branch.action_request
|
160
|
+
|
161
|
+
@property
|
162
|
+
def action_response(self) -> pd.DataFrame:
|
163
|
+
"""
|
164
|
+
Retrieves all action response messages from the conversation.
|
165
|
+
|
166
|
+
Returns:
|
167
|
+
pd.DataFrame: A DataFrame containing all action response messages.
|
168
|
+
"""
|
169
|
+
return self.default_branch.action_response
|
170
|
+
|
171
|
+
@property
|
172
|
+
def responses(self) -> pd.DataFrame:
|
173
|
+
"""
|
174
|
+
Retrieves all response messages from the conversation.
|
175
|
+
|
176
|
+
Returns:
|
177
|
+
pd.DataFrame: A DataFrame containing all response messages.
|
178
|
+
"""
|
179
|
+
return self.default_branch.responses
|
180
|
+
|
181
|
+
@property
|
182
|
+
def assistant_responses(self) -> pd.DataFrame:
|
183
|
+
"""
|
184
|
+
Retrieves all assistant responses from the conversation, excluding action requests and responses.
|
185
|
+
|
186
|
+
Returns:
|
187
|
+
pd.DataFrame: A DataFrame containing assistant responses excluding action requests and responses.
|
188
|
+
"""
|
189
|
+
return self.default_branch.assistant_responses
|
190
|
+
|
191
|
+
@property
|
192
|
+
def info(self) -> Dict[str, int]:
|
193
|
+
"""
|
194
|
+
Get a summary of the conversation messages categorized by role.
|
195
|
+
|
196
|
+
Returns:
|
197
|
+
Dict[str, int]: A dictionary with keys as message roles and values as counts.
|
198
|
+
"""
|
199
|
+
|
200
|
+
return self.default_branch.info
|
201
|
+
|
202
|
+
@property
|
203
|
+
def sender_info(self) -> Dict[str, int]:
|
204
|
+
"""
|
205
|
+
Provides a descriptive summary of the conversation, including total message count and summary by sender.
|
206
|
+
|
207
|
+
Returns:
|
208
|
+
Dict[str, Any]: A dictionary containing the total number of messages and a summary categorized by sender.
|
209
|
+
"""
|
210
|
+
return self.default_branch.sender_info
|
211
|
+
|
212
|
+
@classmethod
|
213
|
+
def from_csv(
|
214
|
+
cls,
|
215
|
+
filepath,
|
216
|
+
system: Optional[Union[str, System]] = None,
|
217
|
+
sender: Optional[str] = None,
|
218
|
+
llmconfig: Optional[Dict[str, Any]] = None,
|
219
|
+
service: BaseService = None,
|
220
|
+
branches: Optional[Dict[str, Branch]] = None,
|
221
|
+
default_branch: Optional[Branch] = None,
|
222
|
+
default_branch_name: str = 'main',
|
223
|
+
tools = None,
|
224
|
+
instruction_sets=None, tool_manager=None,
|
225
|
+
**kwargs) -> 'Session':
|
226
|
+
"""
|
227
|
+
Creates a Session instance from a CSV file containing messages.
|
228
|
+
|
229
|
+
Args:
|
230
|
+
filepath (str): Path to the CSV file.
|
231
|
+
name (Optional[str]): Name of the branch, default is None.
|
232
|
+
instruction_sets (Optional[Dict[str, InstructionSet]]): Instruction sets, default is None.
|
233
|
+
tool_manager (Optional[ToolManager]): Tool manager for the branch, default is None.
|
234
|
+
service (Optional[BaseService]): External service for the branch, default is None.
|
235
|
+
llmconfig (Optional[Dict]): Configuration for language learning models, default is None.
|
236
|
+
tools (Optional[List[Tool]]): Initial list of tools to register, default is None.
|
237
|
+
**kwargs: Additional keyword arguments for pd.read_csv().
|
238
|
+
|
239
|
+
Returns:
|
240
|
+
Branch: A new Branch instance created from the CSV data.
|
241
|
+
|
242
|
+
Examples:
|
243
|
+
>>> branch = Branch.from_csv("path/to/messages.csv", name="ImportedBranch")
|
244
|
+
"""
|
245
|
+
df = pd.read_csv(filepath, **kwargs)
|
246
|
+
|
247
|
+
self = cls(
|
248
|
+
system=system,
|
249
|
+
sender=sender,
|
250
|
+
llmconfig=llmconfig,
|
251
|
+
service=service,
|
252
|
+
branches=branches,
|
253
|
+
default_branch=default_branch,
|
254
|
+
default_branch_name=default_branch_name,
|
255
|
+
tools = tools,
|
256
|
+
instruction_sets=instruction_sets,
|
257
|
+
tool_manager=tool_manager,
|
258
|
+
messages=df, **kwargs
|
259
|
+
)
|
260
|
+
|
261
|
+
return self
|
262
|
+
|
263
|
+
@classmethod
|
264
|
+
def from_json(
|
265
|
+
cls,
|
266
|
+
filepath,
|
267
|
+
system: Optional[Union[str, System]] = None,
|
268
|
+
sender: Optional[str] = None,
|
269
|
+
llmconfig: Optional[Dict[str, Any]] = None,
|
270
|
+
service: BaseService = None,
|
271
|
+
branches: Optional[Dict[str, Branch]] = None,
|
272
|
+
default_branch: Optional[Branch] = None,
|
273
|
+
default_branch_name: str = 'main',
|
274
|
+
tools = None,
|
275
|
+
instruction_sets=None, tool_manager=None,
|
276
|
+
**kwargs) -> 'Session':
|
277
|
+
"""
|
278
|
+
Creates a Branch instance from a JSON file containing messages.
|
279
|
+
|
280
|
+
Args:
|
281
|
+
filepath (str): Path to the JSON file.
|
282
|
+
name (Optional[str]): Name of the branch, default is None.
|
283
|
+
instruction_sets (Optional[Dict[str, InstructionSet]]): Instruction sets, default is None.
|
284
|
+
tool_manager (Optional[ToolManager]): Tool manager for the branch, default is None.
|
285
|
+
service (Optional[BaseService]): External service for the branch, default is None.
|
286
|
+
llmconfig (Optional[Dict]): Configuration for language learning models, default is None.
|
287
|
+
**kwargs: Additional keyword arguments for pd.read_json().
|
288
|
+
|
289
|
+
Returns:
|
290
|
+
Branch: A new Branch instance created from the JSON data.
|
291
|
+
|
292
|
+
Examples:
|
293
|
+
>>> branch = Branch.from_json("path/to/messages.json", name="JSONBranch")
|
294
|
+
"""
|
295
|
+
df = pd.read_json(filepath, **kwargs)
|
296
|
+
self = cls(
|
297
|
+
system=system,
|
298
|
+
sender=sender,
|
299
|
+
llmconfig=llmconfig,
|
300
|
+
service=service,
|
301
|
+
branches=branches,
|
302
|
+
default_branch=default_branch,
|
303
|
+
default_branch_name=default_branch_name,
|
304
|
+
tools = tools,
|
305
|
+
instruction_sets=instruction_sets,
|
306
|
+
tool_manager=tool_manager,
|
307
|
+
messages=df, **kwargs
|
308
|
+
)
|
309
|
+
|
310
|
+
return self
|
311
|
+
|
312
|
+
def to_csv(self, filename: str = 'messages.csv', file_exist_ok: bool = False,
|
313
|
+
timestamp: bool = True, time_prefix: bool = False,
|
314
|
+
verbose: bool = True, clear: bool = True, **kwargs):
|
315
|
+
"""
|
316
|
+
Saves the branch's messages to a CSV file.
|
317
|
+
|
318
|
+
Args:
|
319
|
+
filename (str): The name of the output CSV file, default is 'messages.csv'.
|
320
|
+
file_exist_ok (bool): If True, does not raise an error if the directory already exists, default is False.
|
321
|
+
timestamp (bool): If True, appends a timestamp to the filename, default is True.
|
322
|
+
time_prefix (bool): If True, adds a timestamp prefix to the filename, default is False.
|
323
|
+
verbose (bool): If True, prints a message upon successful save, default is True.
|
324
|
+
clear (bool): If True, clears the messages after saving, default is True.
|
325
|
+
**kwargs: Additional keyword arguments for DataFrame.to_csv().
|
326
|
+
|
327
|
+
Examples:
|
328
|
+
>>> branch.to_csv("exported_messages.csv")
|
329
|
+
>>> branch.to_csv("timed_export.csv", timestamp=True, time_prefix=True)
|
330
|
+
"""
|
331
|
+
|
332
|
+
if not filename.endswith('.csv'):
|
333
|
+
filename += '.csv'
|
334
|
+
|
335
|
+
filepath = create_path(
|
336
|
+
self.logger.dir, filename, timestamp=timestamp,
|
337
|
+
dir_exist_ok=file_exist_ok, time_prefix=time_prefix
|
338
|
+
)
|
339
|
+
|
340
|
+
try:
|
341
|
+
self.messages.to_csv(filepath, **kwargs)
|
342
|
+
if verbose:
|
343
|
+
print(f"{len(self.messages)} messages saved to {filepath}")
|
344
|
+
if clear:
|
345
|
+
self.clear_messages()
|
346
|
+
except Exception as e:
|
347
|
+
raise ValueError(f"Error in saving to csv: {e}")
|
348
|
+
|
349
|
+
def to_json(self, filename: str = 'messages.json', file_exist_ok: bool = False,
|
350
|
+
timestamp: bool = True, time_prefix: bool = False,
|
351
|
+
verbose: bool = True, clear: bool = True, **kwargs):
|
352
|
+
"""
|
353
|
+
Saves the branch's messages to a JSON file.
|
354
|
+
|
355
|
+
Args:
|
356
|
+
filename (str): The name of the output JSON file, default is 'messages.json'.
|
357
|
+
file_exist_ok (bool): If True, does not raise an error if the directory already exists, default is False.
|
358
|
+
timestamp (bool): If True, appends a timestamp to the filename, default is True.
|
359
|
+
time_prefix (bool): If True, adds a timestamp prefix to the filename, default is False.
|
360
|
+
verbose (bool): If True, prints a message upon successful save, default is True.
|
361
|
+
clear (bool): If True, clears the messages after saving, default is True.
|
362
|
+
**kwargs: Additional keyword arguments for DataFrame.to_json().
|
363
|
+
|
364
|
+
Examples:
|
365
|
+
>>> branch.to_json("exported_messages.json")
|
366
|
+
>>> branch.to_json("timed_export.json", timestamp=True, time_prefix=True)
|
367
|
+
"""
|
368
|
+
|
369
|
+
if not filename.endswith('.json'):
|
370
|
+
filename += '.json'
|
371
|
+
|
372
|
+
filepath = create_path(
|
373
|
+
self.dir, filename, timestamp=timestamp,
|
374
|
+
dir_exist_ok=file_exist_ok, time_prefix=time_prefix
|
375
|
+
)
|
376
|
+
|
377
|
+
try:
|
378
|
+
self.messages.to_json(
|
379
|
+
filepath, orient="records", lines=True,
|
380
|
+
date_format="iso", **kwargs
|
381
|
+
)
|
382
|
+
if clear:
|
383
|
+
self.clear_messages()
|
384
|
+
if verbose:
|
385
|
+
print(f"{len(self.messages)} messages saved to {filepath}")
|
386
|
+
except Exception as e:
|
387
|
+
raise ValueError(f"Error in saving to json: {e}")
|
388
|
+
|
389
|
+
def log_to_csv(self, filename: str = 'log.csv', file_exist_ok: bool = False, timestamp: bool = True,
|
390
|
+
time_prefix: bool = False, verbose: bool = True, clear: bool = True, **kwargs):
|
391
|
+
"""
|
392
|
+
Saves the branch's log data to a CSV file.
|
393
|
+
|
394
|
+
This method is designed to export log data, potentially including operations and interactions,
|
395
|
+
to a CSV file for analysis or record-keeping.
|
396
|
+
|
397
|
+
Args:
|
398
|
+
filename (str): The name of the output CSV file. Defaults to 'log.csv'.
|
399
|
+
file_exist_ok (bool): If True, will not raise an error if the directory already exists. Defaults to False.
|
400
|
+
timestamp (bool): If True, appends a timestamp to the filename for uniqueness. Defaults to True.
|
401
|
+
time_prefix (bool): If True, adds a timestamp prefix to the filename. Defaults to False.
|
402
|
+
verbose (bool): If True, prints a success message upon completion. Defaults to True.
|
403
|
+
clear (bool): If True, clears the log after saving. Defaults to True.
|
404
|
+
**kwargs: Additional keyword arguments for `DataFrame.to_csv()`.
|
405
|
+
|
406
|
+
Examples:
|
407
|
+
>>> branch.log_to_csv("branch_log.csv")
|
408
|
+
>>> branch.log_to_csv("detailed_branch_log.csv", timestamp=True, verbose=True)
|
409
|
+
"""
|
410
|
+
self.logger.to_csv(
|
411
|
+
filename=filename, file_exist_ok=file_exist_ok, timestamp=timestamp,
|
412
|
+
time_prefix=time_prefix, verbose=verbose, clear=clear, **kwargs
|
413
|
+
)
|
414
|
+
|
415
|
+
def log_to_json(self, filename: str = 'log.json', file_exist_ok: bool = False, timestamp: bool = True,
|
416
|
+
time_prefix: bool = False, verbose: bool = True, clear: bool = True, **kwargs):
|
417
|
+
"""
|
418
|
+
Saves the branch's log data to a JSON file.
|
419
|
+
|
420
|
+
Useful for exporting log data in JSON format, allowing for easy integration with web applications
|
421
|
+
and services that consume JSON.
|
422
|
+
|
423
|
+
Args:
|
424
|
+
filename (str): The name of the output JSON file. Defaults to 'log.json'.
|
425
|
+
file_exist_ok (bool): If directory existence should not raise an error. Defaults to False.
|
426
|
+
timestamp (bool): If True, appends a timestamp to the filename. Defaults to True.
|
427
|
+
time_prefix (bool): If True, adds a timestamp prefix to the filename. Defaults to False.
|
428
|
+
verbose (bool): If True, prints a success message upon completion. Defaults to True.
|
429
|
+
clear (bool): If True, clears the log after saving. Defaults to True.
|
430
|
+
**kwargs: Additional keyword arguments for `DataFrame.to_json()`.
|
431
|
+
|
432
|
+
Examples:
|
433
|
+
>>> branch.log_to_json("branch_log.json")
|
434
|
+
>>> branch.log_to_json("detailed_branch_log.json", verbose=True, timestamp=True)
|
435
|
+
"""
|
436
|
+
self.logger.to_json(
|
437
|
+
filename=filename, file_exist_ok=file_exist_ok, timestamp=timestamp,
|
438
|
+
time_prefix=time_prefix, verbose=verbose, clear=clear, **kwargs
|
439
|
+
)
|
440
|
+
|
441
|
+
@property
|
442
|
+
def all_messages(self) -> pd.DataFrame:
|
443
|
+
"""
|
444
|
+
return all messages across branches
|
445
|
+
"""
|
446
|
+
dfs = deque()
|
447
|
+
for _, v in self.branches:
|
448
|
+
dfs.append(to_df(v.messages))
|
449
|
+
return to_df(to_list(dfs, flatten=True, dropna=True))
|
450
|
+
|
451
|
+
def register_tools(self, tools):
|
452
|
+
self.default_branch.register_tools(tools)
|
453
|
+
|
454
|
+
# ----- chatflow ----#
|
455
|
+
async def call_chatcompletion(self, branch=None, sender=None, with_sender=False, tokenizer_kwargs={}, **kwargs):
|
456
|
+
"""
|
457
|
+
Asynchronously calls the chat completion service with the current message queue.
|
458
|
+
|
459
|
+
This method prepares the messages for chat completion, sends the request to the configured service, and handles the response. The method supports additional keyword arguments that are passed directly to the service.
|
460
|
+
|
461
|
+
Args:
|
462
|
+
sender (Optional[str]): The name of the sender to be included in the chat completion request. Defaults to None.
|
463
|
+
with_sender (bool): If True, includes the sender's name in the messages. Defaults to False.
|
464
|
+
**kwargs: Arbitrary keyword arguments passed directly to the chat completion service.
|
465
|
+
|
466
|
+
Examples:
|
467
|
+
>>> await branch.call_chatcompletion()
|
468
|
+
"""
|
469
|
+
branch = self.get_branch(branch)
|
470
|
+
await branch.call_chatcompletion(
|
471
|
+
sender=sender, with_sender=with_sender,
|
472
|
+
tokenizer_kwargs=tokenizer_kwargs, **kwargs
|
473
|
+
)
|
474
|
+
|
475
|
+
async def chat(
|
476
|
+
self,
|
477
|
+
instruction: Union[Instruction, str],
|
478
|
+
branch=None,
|
479
|
+
context: Optional[Any] = None,
|
480
|
+
sender: Optional[str] = None,
|
481
|
+
system: Optional[Union[System, str, Dict[str, Any]]] = None,
|
482
|
+
tools: Union[bool, Tool, List[Tool], str, List[str]] = False,
|
483
|
+
out: bool = True,
|
484
|
+
invoke: bool = True,
|
485
|
+
**kwargs) -> Any:
|
486
|
+
"""
|
487
|
+
a chat conversation with LLM, processing instructions and system messages, optionally invoking tools.
|
488
|
+
|
489
|
+
Args:
|
490
|
+
branch: The Branch instance to perform chat operations.
|
491
|
+
instruction (Union[Instruction, str]): The instruction for the chat.
|
492
|
+
context (Optional[Any]): Additional context for the chat.
|
493
|
+
sender (Optional[str]): The sender of the chat message.
|
494
|
+
system (Optional[Union[System, str, Dict[str, Any]]]): System message to be processed.
|
495
|
+
tools (Union[bool, Tool, List[Tool], str, List[str]]): Specifies tools to be invoked.
|
496
|
+
out (bool): If True, outputs the chat response.
|
497
|
+
invoke (bool): If True, invokes tools as part of the chat.
|
498
|
+
**kwargs: Arbitrary keyword arguments for chat completion.
|
499
|
+
|
500
|
+
Examples:
|
501
|
+
>>> await ChatFlow.chat(branch, "Ask about user preferences")
|
502
|
+
"""
|
503
|
+
branch = self.get_branch(branch)
|
504
|
+
return await branch.chat(
|
505
|
+
instruction=instruction, context=context,
|
506
|
+
sender=sender, system=system, tools=tools,
|
507
|
+
out=out, invoke=invoke, **kwargs
|
508
|
+
)
|
509
|
+
|
510
|
+
async def ReAct(
|
511
|
+
self,
|
512
|
+
instruction: Union[Instruction, str],
|
513
|
+
branch=None,
|
514
|
+
context = None,
|
515
|
+
sender = None,
|
516
|
+
system = None,
|
517
|
+
tools = None,
|
518
|
+
num_rounds: int = 1,
|
519
|
+
**kwargs ):
|
520
|
+
"""
|
521
|
+
Performs a reason-action cycle with optional tool invocation over multiple rounds.
|
522
|
+
|
523
|
+
Args:
|
524
|
+
branch: The Branch instance to perform ReAct operations.
|
525
|
+
instruction (Union[Instruction, str]): Initial instruction for the cycle.
|
526
|
+
context: Context relevant to the instruction.
|
527
|
+
sender (Optional[str]): Identifier for the message sender.
|
528
|
+
system: Initial system message or configuration.
|
529
|
+
tools: Tools to be registered or used during the cycle.
|
530
|
+
num_rounds (int): Number of reason-action cycles to perform.
|
531
|
+
**kwargs: Additional keyword arguments for customization.
|
532
|
+
|
533
|
+
Examples:
|
534
|
+
>>> await ChatFlow.ReAct(branch, "Analyze user feedback", num_rounds=2)
|
535
|
+
"""
|
536
|
+
branch = self.get_branch(branch)
|
537
|
+
|
538
|
+
return await branch.ReAct(
|
539
|
+
instruction=instruction, context=context,
|
540
|
+
sender=sender, system=system, tools=tools,
|
541
|
+
num_rounds=num_rounds, **kwargs
|
542
|
+
)
|
543
|
+
|
544
|
+
async def auto_followup(
|
545
|
+
self,
|
546
|
+
instruction: Union[Instruction, str],
|
547
|
+
branch=None,
|
548
|
+
context = None,
|
549
|
+
sender = None,
|
550
|
+
system = None,
|
551
|
+
tools: Union[bool, Tool, List[Tool], str, List[str], List[Dict]] = False,
|
552
|
+
max_followup: int = 3,
|
553
|
+
out=True,
|
554
|
+
**kwargs):
|
555
|
+
"""
|
556
|
+
Automatically performs follow-up actions based on chat interactions and tool invocations.
|
557
|
+
|
558
|
+
Args:
|
559
|
+
branch: The Branch instance to perform follow-up operations.
|
560
|
+
instruction (Union[Instruction, str]): The initial instruction for follow-up.
|
561
|
+
context: Context relevant to the instruction.
|
562
|
+
sender (Optional[str]): Identifier for the message sender.
|
563
|
+
system: Initial system message or configuration.
|
564
|
+
tools: Specifies tools to be considered for follow-up actions.
|
565
|
+
max_followup (int): Maximum number of follow-up chats allowed.
|
566
|
+
out (bool): If True, outputs the result of the follow-up action.
|
567
|
+
**kwargs: Additional keyword arguments for follow-up customization.
|
568
|
+
|
569
|
+
Examples:
|
570
|
+
>>> await ChatFlow.auto_followup(branch, "Finalize report", max_followup=2)
|
571
|
+
"""
|
572
|
+
branch = self.get_branch(branch)
|
573
|
+
return await branch.auto_followup(
|
574
|
+
instruction=instruction, context=context,
|
575
|
+
sender=sender, system=system, tools=tools,
|
576
|
+
max_followup=max_followup, out=out, **kwargs
|
577
|
+
)
|
578
|
+
|
579
|
+
# ---- branch manipulation ---- #
|
580
|
+
def new_branch(
|
581
|
+
self,
|
582
|
+
branch_name: Optional[str] = None,
|
583
|
+
system=None,
|
584
|
+
sender=None,
|
585
|
+
messages: Optional[pd.DataFrame] = None,
|
586
|
+
instruction_sets = None,
|
587
|
+
tool_manager = None,
|
588
|
+
service = None,
|
589
|
+
llmconfig = None,
|
590
|
+
tools=None,
|
591
|
+
) -> None:
|
592
|
+
"""Create a new branch with the specified configurations.
|
593
|
+
|
594
|
+
Args:
|
595
|
+
branch_name (Optional[str]): Name of the new branch.
|
596
|
+
system (Optional[Union[System, str]]): System or context identifier for the new branch.
|
597
|
+
sender (Optional[str]): Default sender identifier for the new branch.
|
598
|
+
messages (Optional[pd.DataFrame]): Initial set of messages for the new branch.
|
599
|
+
instruction_sets (Optional[Any]): Instruction sets for the new branch.
|
600
|
+
tool_manager (Optional[Any]): Tool manager for handling tools in the new branch.
|
601
|
+
service (Optional[BaseService]): External service instance for the new branch.
|
602
|
+
llmconfig (Optional[Dict[str, Any]]): Configuration for language learning models in the new branch.
|
603
|
+
tools (Optional[List[Tool]]): List of tools available for the new branch.
|
604
|
+
|
605
|
+
Raises:
|
606
|
+
ValueError: If the branch name already exists.
|
607
|
+
|
608
|
+
Examples:
|
609
|
+
>>> session.new_branch("new_branch_name")
|
610
|
+
"""
|
611
|
+
if branch_name in self.branches.keys():
|
612
|
+
raise ValueError(f'Invalid new branch name {branch_name}. Branch already existed.')
|
613
|
+
new_branch = Branch(
|
614
|
+
name=branch_name,
|
615
|
+
messages=messages,
|
616
|
+
instruction_sets=instruction_sets,
|
617
|
+
tool_manager=tool_manager,
|
618
|
+
service=service,
|
619
|
+
llmconfig=llmconfig,
|
620
|
+
tools=tools
|
621
|
+
)
|
622
|
+
if system:
|
623
|
+
new_branch.add_message(system=system, sender=sender)
|
624
|
+
|
625
|
+
self.branches[branch_name] = new_branch
|
626
|
+
self.branch_manager.sources[branch_name] = new_branch
|
627
|
+
self.branch_manager.requests[branch_name] = {}
|
628
|
+
|
629
|
+
def get_branch(
|
630
|
+
self,
|
631
|
+
branch: Optional[Union[Branch, str]] = None,
|
632
|
+
get_name: bool = False
|
633
|
+
) -> Union[Branch, Tuple[Branch, str]]:
|
634
|
+
"""
|
635
|
+
Retrieve a branch by name or instance.
|
636
|
+
|
637
|
+
Args:
|
638
|
+
branch (Optional[Union[Branch, str]]): The branch name or instance to retrieve.
|
639
|
+
get_name (bool): If True, returns a tuple of the branch instance and its name.
|
640
|
+
|
641
|
+
Returns:
|
642
|
+
Union[Branch, Tuple[Branch, str]]: The branch instance or a tuple of the branch instance and its name.
|
643
|
+
|
644
|
+
Raises:
|
645
|
+
ValueError: If the branch name does not exist or the branch input is invalid.
|
646
|
+
|
647
|
+
Examples:
|
648
|
+
>>> branch_instance = session.get_branch("existing_branch_name")
|
649
|
+
>>> branch_instance, branch_name = session.get_branch("existing_branch_name", get_name=True)
|
650
|
+
"""
|
651
|
+
if isinstance(branch, str):
|
652
|
+
if branch not in self.branches.keys():
|
653
|
+
raise ValueError(f'Invalid branch name {branch}. Not exist.')
|
654
|
+
else:
|
655
|
+
if get_name:
|
656
|
+
return self.branches[branch], branch
|
657
|
+
return self.branches[branch]
|
658
|
+
|
659
|
+
elif isinstance(branch, Branch) and branch in self.branches.values():
|
660
|
+
if get_name:
|
661
|
+
return branch, [key for key, value in self.branches.items() if value == branch][0]
|
662
|
+
return branch
|
663
|
+
|
664
|
+
elif branch is None:
|
665
|
+
if get_name:
|
666
|
+
return self.default_branch, self.default_branch_name
|
667
|
+
return self.default_branch
|
668
|
+
|
669
|
+
else:
|
670
|
+
raise ValueError(f'Invalid branch input {branch}.')
|
671
|
+
|
672
|
+
def change_default_branch(self, branch: Union[str, Branch]) -> None:
|
673
|
+
"""Change the default branch of the session.
|
674
|
+
|
675
|
+
Args:
|
676
|
+
branch (Union[str, Branch]): The branch name or instance to set as the new default.
|
677
|
+
|
678
|
+
Examples:
|
679
|
+
>>> session.change_default_branch("new_default_branch")
|
680
|
+
"""
|
681
|
+
branch_, name_ = self.get_branch(branch, get_name=True)
|
682
|
+
self.default_branch = branch_
|
683
|
+
self.default_branch_name = name_
|
684
|
+
|
685
|
+
def delete_branch(self, branch: Union[Branch, str], verbose: bool = True) -> bool:
|
686
|
+
"""Delete a branch from the session.
|
687
|
+
|
688
|
+
Args:
|
689
|
+
branch (Union[Branch, str]): The branch name or instance to delete.
|
690
|
+
verbose (bool): If True, prints a message upon deletion.
|
691
|
+
|
692
|
+
Returns:
|
693
|
+
bool: True if the branch was successfully deleted.
|
694
|
+
|
695
|
+
Raises:
|
696
|
+
ValueError: If attempting to delete the current default branch.
|
697
|
+
|
698
|
+
Examples:
|
699
|
+
>>> session.delete_branch("branch_to_delete")
|
700
|
+
"""
|
701
|
+
_, branch_name = self.get_branch(branch, get_name=True)
|
702
|
+
|
703
|
+
if branch_name == self.default_branch_name:
|
704
|
+
raise ValueError(
|
705
|
+
f'{branch_name} is the current default branch, please switch to another branch before delete it.'
|
706
|
+
)
|
707
|
+
else:
|
708
|
+
self.branches.pop(branch_name)
|
709
|
+
# self.branch_manager.sources.pop(branch_name)
|
710
|
+
self.branch_manager.requests.pop(branch_name)
|
711
|
+
if verbose:
|
712
|
+
print(f'Branch {branch_name} is deleted.')
|
713
|
+
return True
|
714
|
+
|
715
|
+
def merge_branch(
|
716
|
+
self,
|
717
|
+
from_: Union[str, Branch],
|
718
|
+
to_branch: Union[str, Branch],
|
719
|
+
update: bool = True,
|
720
|
+
del_: bool = False
|
721
|
+
) -> None:
|
722
|
+
"""Merge messages and settings from one branch to another.
|
723
|
+
|
724
|
+
Args:
|
725
|
+
from_ (Union[str, Branch]): The source branch name or instance.
|
726
|
+
to_ (Union[str, Branch]): The target branch name or instance where the merge will happen.
|
727
|
+
update (bool): If True, updates the target branch with the source branch's settings.
|
728
|
+
del_ (bool): If True, deletes the source branch after merging.
|
729
|
+
|
730
|
+
Examples:
|
731
|
+
>>> session.merge_branch("source_branch", "target_branch", del_=True)
|
732
|
+
"""
|
733
|
+
from_ = self.get_branch(branch=from_)
|
734
|
+
to_branch, to_name = self.get_branch(branch=to_branch, get_name=True)
|
735
|
+
to_branch.merge_branch(from_, update=update)
|
736
|
+
|
737
|
+
if del_:
|
738
|
+
if from_ == self.default_branch:
|
739
|
+
self.default_branch_name = to_name
|
740
|
+
self.default_branch = to_branch
|
741
|
+
self.delete_branch(from_, verbose=False)
|
742
|
+
|
743
|
+
def collect(self, from_: Union[str, Branch, List[str], List[Branch]] = None):
|
744
|
+
"""
|
745
|
+
Collects requests from specified branches or from all branches if none are specified.
|
746
|
+
|
747
|
+
This method is intended to aggregate data or requests from one or more branches for processing or analysis.
|
748
|
+
|
749
|
+
Args:
|
750
|
+
from_ (Optional[Union[str, Branch, List[Union[str, Branch]]]]): The branch(es) from which to collect requests.
|
751
|
+
Can be a single branch name, a single branch instance, a list of branch names, a list of branch instances, or None.
|
752
|
+
If None, requests are collected from all branches.
|
753
|
+
|
754
|
+
Examples:
|
755
|
+
>>> session.collect("branch_name")
|
756
|
+
>>> session.collect([branch_instance_1, "branch_name_2"])
|
757
|
+
>>> session.collect() # Collects from all branches
|
758
|
+
"""
|
759
|
+
if from_ is None:
|
760
|
+
for branch in self.branches.keys():
|
761
|
+
self.branch_manager.collect(branch)
|
762
|
+
else:
|
763
|
+
if not isinstance(from_, list):
|
764
|
+
from_ = [from_]
|
765
|
+
for branch in from_:
|
766
|
+
if isinstance(branch, Branch):
|
767
|
+
branch = branch.name
|
768
|
+
if isinstance(branch, str):
|
769
|
+
self.branch_manager.collect(branch)
|
770
|
+
|
771
|
+
def send(self, to_: Union[str, Branch, List[str], List[Branch]] = None):
|
772
|
+
"""
|
773
|
+
Sends requests or data to specified branches or to all branches if none are specified.
|
774
|
+
|
775
|
+
This method facilitates the distribution of data or requests to one or more branches, potentially for further action or processing.
|
776
|
+
|
777
|
+
Args:
|
778
|
+
to_ (Optional[Union[str, Branch, List[Union[str, Branch]]]]): The target branch(es) to which to send requests.
|
779
|
+
Can be a single branch name, a single branch instance, a list of branch names, a list of branch instances, or None.
|
780
|
+
If None, requests are sent to all branches.
|
781
|
+
|
782
|
+
Examples:
|
783
|
+
>>> session.send("target_branch")
|
784
|
+
>>> session.send([branch_instance_1, "target_branch_2"])
|
785
|
+
>>> session.send() # Sends to all branches
|
786
|
+
"""
|
787
|
+
if to_ is None:
|
788
|
+
for branch in self.branches.keys():
|
789
|
+
self.branch_manager.send(branch)
|
790
|
+
else:
|
791
|
+
if not isinstance(to_, list):
|
792
|
+
to_ = [to_]
|
793
|
+
for branch in to_:
|
794
|
+
if isinstance(branch, Branch):
|
795
|
+
branch = branch.name
|
796
|
+
if isinstance(branch, str):
|
797
|
+
self.branch_manager.send(branch)
|
798
|
+
|
799
|
+
def collect_send_all(self, receive_all=False):
|
800
|
+
"""
|
801
|
+
Collects and sends requests across all branches, optionally invoking a receive operation on each branch.
|
802
|
+
|
803
|
+
This method is a convenience function for performing a full cycle of collect and send operations across all branches,
|
804
|
+
useful in scenarios where data or requests need to be aggregated and then distributed uniformly.
|
805
|
+
|
806
|
+
Args:
|
807
|
+
receive_all (bool): If True, triggers a `receive_all` method on each branch after sending requests,
|
808
|
+
which can be used to process or acknowledge the received data.
|
809
|
+
|
810
|
+
Examples:
|
811
|
+
>>> session.collect_send_all()
|
812
|
+
>>> session.collect_send_all(receive_all=True)
|
813
|
+
"""
|
814
|
+
self.collect()
|
815
|
+
self.send()
|
816
|
+
if receive_all:
|
817
|
+
for branch in self.branches.values():
|
818
|
+
branch.receive_all()
|
819
|
+
|
820
|
+
def setup_default_branch(self, **kwargs):
|
821
|
+
self._setup_default_branch(**kwargs)
|
822
|
+
self._verify_default_branch()
|
823
|
+
|
824
|
+
def _verify_default_branch(self):
|
825
|
+
if self.branches:
|
826
|
+
if self.default_branch_name not in self.branches.keys():
|
827
|
+
raise ValueError('default branch name is not in imported branches')
|
828
|
+
if self.default_branch is not self.branches[self.default_branch_name]:
|
829
|
+
raise ValueError(f'default branch does not match Branch object under {self.default_branch_name}')
|
830
|
+
|
831
|
+
if not self.branches:
|
832
|
+
self.branches[self.default_branch_name] = self.default_branch
|
833
|
+
|
834
|
+
def _setup_default_branch(
|
835
|
+
self, system, sender, default_branch, default_branch_name, messages,
|
836
|
+
instruction_sets, tool_manager, service, llmconfig, tools, dir, logger
|
837
|
+
):
|
838
|
+
|
839
|
+
branch = default_branch or Branch(
|
840
|
+
name=default_branch_name, service=service, llmconfig=llmconfig, tools=tools,
|
841
|
+
tool_manager=tool_manager, instruction_sets=instruction_sets, messages=messages, dir=dir, logger=logger
|
842
|
+
)
|
843
|
+
|
844
|
+
self.default_branch = branch
|
845
|
+
self.default_branch_name = default_branch_name or 'main'
|
846
|
+
if system:
|
847
|
+
self.default_branch.add_message(system=system, sender=sender)
|
848
|
+
|
849
|
+
self.llmconfig = self.default_branch.llmconfig
|
850
|
+
|
851
|
+
# def add_instruction_set(self, name: str, instruction_set: InstructionSet) -> None:
|
852
|
+
# """
|
853
|
+
# Adds an instruction set to the current active branch.
|
854
|
+
#
|
855
|
+
# Args:
|
856
|
+
# name (str): The name of the instruction set.
|
857
|
+
# instruction_set (InstructionSet): The instruction set to add.
|
858
|
+
# """
|
859
|
+
# self.default_branch.add_instruction_set(name, instruction_set)
|
860
|
+
#
|
861
|
+
# def remove_instruction_set(self, name: str) -> bool:
|
862
|
+
# """
|
863
|
+
# Removes an instruction set from the current active branch.
|
864
|
+
#
|
865
|
+
# Args:
|
866
|
+
# name (str): The name of the instruction set to remove.
|
867
|
+
#
|
868
|
+
# Returns:
|
869
|
+
# bool: True if the instruction set is removed, False otherwise.
|
870
|
+
# """
|
871
|
+
# return self.default_branch.remove_instruction_set(name)
|
872
|
+
|