mindroot 8.9.0__py3-none-any.whl → 8.11.0__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.
Potentially problematic release.
This version of mindroot might be problematic. Click here for more details.
- mindroot/coreplugins/admin/plugin_manager.py +21 -3
- mindroot/coreplugins/admin/static/js/agent-form.js +38 -22
- mindroot/coreplugins/admin/static/js/plugin-advanced-install.js +8 -0
- mindroot/coreplugins/agent/templates/system.jinja2 +18 -0
- mindroot/coreplugins/chat/commands.py +11 -2
- mindroot/coreplugins/chat/router.py +48 -1
- mindroot/coreplugins/chat/services.py +4 -2
- mindroot/coreplugins/index/default.json +21 -15
- mindroot/coreplugins/index/handlers/plugin_ops.py +13 -0
- mindroot/coreplugins/index/indices/default/index.json +9 -6
- mindroot/coreplugins/index/static/js/plugin-section.js +42 -5
- mindroot/coreplugins/login/templates/login.jinja2 +4 -1
- mindroot/lib/chatcontext.py +100 -4
- mindroot/lib/chatlog.py +52 -14
- mindroot/lib/chatlog_optimized.py +509 -0
- mindroot/lib/plugins/default_plugin_manifest.json +1 -1
- {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/METADATA +1 -1
- {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/RECORD +22 -26
- {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/WHEEL +1 -1
- mindroot/coreplugins/google_auth/README.md +0 -76
- mindroot/coreplugins/google_auth/__init__.py +0 -1
- mindroot/coreplugins/google_auth/inject/login.jinja2 +0 -69
- mindroot/coreplugins/google_auth/mod.py +0 -1
- mindroot/coreplugins/google_auth/router.py +0 -170
- {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/entry_points.txt +0 -0
- {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-8.9.0.dist-info → mindroot-8.11.0.dist-info}/top_level.txt +0 -0
mindroot/lib/chatcontext.py
CHANGED
|
@@ -3,7 +3,8 @@ from .providers.commands import command_manager
|
|
|
3
3
|
import os
|
|
4
4
|
import json
|
|
5
5
|
from .chatlog import ChatLog
|
|
6
|
-
from
|
|
6
|
+
from .chatlog import extract_delegate_task_log_ids, find_child_logs_by_parent_id, find_chatlog_file
|
|
7
|
+
from typing import TypeVar, Type, Protocol, runtime_checkable, Set
|
|
7
8
|
from .utils.debug import debug_box
|
|
8
9
|
contexts = {}
|
|
9
10
|
|
|
@@ -29,7 +30,7 @@ CommandSetT = TypeVar('CommandSetT', bound=BaseCommandSet)
|
|
|
29
30
|
|
|
30
31
|
class ChatContext:
|
|
31
32
|
|
|
32
|
-
def __init__(self, command_manager_=None, service_manager_=None, user=None, log_id=None):
|
|
33
|
+
def __init__(self, command_manager_=None, service_manager_=None, user=None, log_id=None, parent_log_id=None):
|
|
33
34
|
if not user:
|
|
34
35
|
raise ValueError('User is required to create a chat context')
|
|
35
36
|
else:
|
|
@@ -39,6 +40,7 @@ class ChatContext:
|
|
|
39
40
|
self._commands = command_manager.functions
|
|
40
41
|
self._services = service_manager.functions
|
|
41
42
|
self.response_started = False
|
|
43
|
+
self.current_model = None
|
|
42
44
|
self.uncensored = False
|
|
43
45
|
if user is None:
|
|
44
46
|
raise ValueError('User is required to create a chat context. Use SYSTEM if no user')
|
|
@@ -66,6 +68,7 @@ class ChatContext:
|
|
|
66
68
|
self.agent_name = None
|
|
67
69
|
self.name = None
|
|
68
70
|
self.log_id = None
|
|
71
|
+
self.parent_log_id = None
|
|
69
72
|
if log_id is not None:
|
|
70
73
|
self.log_id = log_id
|
|
71
74
|
else:
|
|
@@ -142,7 +145,10 @@ class ChatContext:
|
|
|
142
145
|
pass
|
|
143
146
|
self.flags = self.agent.get('flags', [])
|
|
144
147
|
self.data['log_id'] = log_id
|
|
145
|
-
|
|
148
|
+
parent_log_id = None
|
|
149
|
+
if self.parent_log_id:
|
|
150
|
+
parent_log_id = self.parent_log_id
|
|
151
|
+
self.chat_log = ChatLog(log_id=log_id, agent=self.agent_name, user=self.username, parent_log_id=parent_log_id)
|
|
146
152
|
self.uncensored = True
|
|
147
153
|
else:
|
|
148
154
|
raise ValueError('Context file not found for id:', log_id)
|
|
@@ -160,5 +166,95 @@ class ChatContext:
|
|
|
160
166
|
if name in self._commands:
|
|
161
167
|
self.command_manager.context = self
|
|
162
168
|
return getattr(self.command_manager, name)
|
|
169
|
+
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
|
|
170
|
+
|
|
171
|
+
@classmethod
|
|
172
|
+
async def delete_session_by_id(cls, log_id: str, user: str, agent: str, cascade: bool = True, visited_log_ids: Set[str] = None):
|
|
173
|
+
if visited_log_ids is None:
|
|
174
|
+
visited_log_ids = set()
|
|
175
|
+
|
|
176
|
+
if log_id in visited_log_ids:
|
|
177
|
+
print(f"Skipping already visited log_id for deletion: {log_id}")
|
|
178
|
+
return
|
|
179
|
+
visited_log_ids.add(log_id)
|
|
180
|
+
|
|
181
|
+
print(f"Attempting to delete session: log_id={log_id}, user={user}, agent={agent}")
|
|
182
|
+
|
|
183
|
+
# --- Cascading Deletion ---
|
|
184
|
+
if cascade:
|
|
185
|
+
messages_for_child_finding = []
|
|
186
|
+
chatlog_dir_base = os.environ.get('CHATLOG_DIR', 'data/chat')
|
|
187
|
+
chatlog_file_path_current = os.path.join(chatlog_dir_base, user, agent, f'chatlog_{log_id}.json')
|
|
188
|
+
|
|
189
|
+
if os.path.exists(chatlog_file_path_current):
|
|
190
|
+
try:
|
|
191
|
+
with open(chatlog_file_path_current, 'r') as f:
|
|
192
|
+
log_data = json.load(f)
|
|
193
|
+
messages_for_child_finding = log_data.get('messages', [])
|
|
194
|
+
except Exception as e:
|
|
195
|
+
print(f"Error reading chatlog {chatlog_file_path_current} for child finding: {e}")
|
|
196
|
+
|
|
197
|
+
delegated_child_ids = extract_delegate_task_log_ids(messages_for_child_finding)
|
|
198
|
+
parented_child_ids = find_child_logs_by_parent_id(log_id)
|
|
199
|
+
all_child_log_ids = set(delegated_child_ids) | set(parented_child_ids)
|
|
200
|
+
|
|
201
|
+
for child_id in all_child_log_ids:
|
|
202
|
+
if child_id in visited_log_ids: # Check again before processing child
|
|
203
|
+
continue
|
|
204
|
+
child_log_path = find_chatlog_file(child_id) # This searches across all users/agents
|
|
205
|
+
if child_log_path:
|
|
206
|
+
try:
|
|
207
|
+
relative_path = os.path.relpath(child_log_path, chatlog_dir_base)
|
|
208
|
+
path_components = relative_path.split(os.sep)
|
|
209
|
+
# Expecting {user}/{agent}/chatlog_{child_id}.json
|
|
210
|
+
if len(path_components) >= 3 and path_components[-1] == f"chatlog_{child_id}.json":
|
|
211
|
+
child_user = path_components[0]
|
|
212
|
+
child_agent = path_components[1]
|
|
213
|
+
print(f"Recursively deleting child session: log_id={child_id}, user={child_user}, agent={child_agent}")
|
|
214
|
+
await cls.delete_session_by_id(child_id, child_user, child_agent, cascade=True, visited_log_ids=visited_log_ids)
|
|
215
|
+
else:
|
|
216
|
+
print(f"Could not parse user/agent from child log path: {child_log_path} relative to {chatlog_dir_base}")
|
|
217
|
+
except Exception as e:
|
|
218
|
+
print(f"Error processing child log {child_id} (path: {child_log_path}): {e}")
|
|
219
|
+
else:
|
|
220
|
+
print(f"Could not find chatlog file for child_id: {child_id} during cascade.")
|
|
221
|
+
|
|
222
|
+
# --- Delete Current Session's Files ---
|
|
223
|
+
# ChatLog File
|
|
224
|
+
chatlog_file_to_delete = os.path.join(os.environ.get('CHATLOG_DIR', 'data/chat'), user, agent, f'chatlog_{log_id}.json')
|
|
225
|
+
if os.path.exists(chatlog_file_to_delete):
|
|
226
|
+
try:
|
|
227
|
+
os.remove(chatlog_file_to_delete)
|
|
228
|
+
print(f"Deleted chatlog file: {chatlog_file_to_delete}")
|
|
229
|
+
except Exception as e:
|
|
230
|
+
print(f"Error deleting chatlog file {chatlog_file_to_delete}: {e}")
|
|
163
231
|
else:
|
|
164
|
-
|
|
232
|
+
print(f"Chatlog file not found for deletion: {chatlog_file_to_delete}")
|
|
233
|
+
|
|
234
|
+
# ChatContext File (Agent is not part of the context file path structure)
|
|
235
|
+
context_file_to_delete = os.path.join('data/context', user, f'context_{log_id}.json')
|
|
236
|
+
if os.path.exists(context_file_to_delete):
|
|
237
|
+
try:
|
|
238
|
+
os.remove(context_file_to_delete)
|
|
239
|
+
print(f"Deleted context file: {context_file_to_delete}")
|
|
240
|
+
except Exception as e:
|
|
241
|
+
print(f"Error deleting context file {context_file_to_delete}: {e}")
|
|
242
|
+
else:
|
|
243
|
+
print(f"Context file not found for deletion: {context_file_to_delete}")
|
|
244
|
+
|
|
245
|
+
# --- Clear In-Memory Cache ---
|
|
246
|
+
if log_id in contexts: # 'contexts' is the global dict at module level
|
|
247
|
+
try:
|
|
248
|
+
del contexts[log_id]
|
|
249
|
+
print(f"Removed log_id {log_id} from in-memory contexts cache.")
|
|
250
|
+
except Exception as e:
|
|
251
|
+
print(f"Error removing log_id {log_id} from in-memory contexts cache: {e}")
|
|
252
|
+
|
|
253
|
+
async def delete(self, cascade: bool = True):
|
|
254
|
+
if not self.log_id or not self.username or not self.agent_name:
|
|
255
|
+
error_msg = "log_id, username, or agent_name not set on ChatContext instance. Cannot call instance delete."
|
|
256
|
+
print(f"Error: {error_msg}")
|
|
257
|
+
raise ValueError(error_msg)
|
|
258
|
+
|
|
259
|
+
print(f"Instance delete called for log_id={self.log_id}, user={self.username}, agent={self.agent_name}")
|
|
260
|
+
await ChatContext.delete_session_by_id(self.log_id, self.username, self.agent_name, cascade=cascade)
|
mindroot/lib/chatlog.py
CHANGED
|
@@ -8,9 +8,10 @@ import time
|
|
|
8
8
|
from mindroot.lib.utils.debug import debug_box
|
|
9
9
|
|
|
10
10
|
class ChatLog:
|
|
11
|
-
def __init__(self, log_id=0, agent=None, context_length: int = 4096, user: str = None):
|
|
11
|
+
def __init__(self, log_id=0, agent=None, parent_log_id=None, context_length: int = 4096, user: str = None):
|
|
12
12
|
self.log_id = log_id
|
|
13
13
|
self.messages = []
|
|
14
|
+
self.parent_log_id = parent_log_id
|
|
14
15
|
self.agent = agent
|
|
15
16
|
if user is None or user == '' or user == 'None':
|
|
16
17
|
raise ValueError('User must be provided')
|
|
@@ -32,10 +33,13 @@ class ChatLog:
|
|
|
32
33
|
if not os.path.exists(self.log_dir):
|
|
33
34
|
os.makedirs(self.log_dir)
|
|
34
35
|
self.load_log()
|
|
36
|
+
|
|
35
37
|
def _get_log_data(self) -> Dict[str, any]:
|
|
36
38
|
return {
|
|
37
39
|
'agent': self.agent,
|
|
38
|
-
'
|
|
40
|
+
'log_id': self.log_id,
|
|
41
|
+
'messages': self.messages,
|
|
42
|
+
'parent_log_id': self.parent_log_id
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
def _calculate_message_length(self, message: Dict[str, str]) -> int:
|
|
@@ -124,20 +128,13 @@ class ChatLog:
|
|
|
124
128
|
log_data = json.load(f)
|
|
125
129
|
self.agent = log_data.get('agent')
|
|
126
130
|
self.messages = log_data.get('messages', [])
|
|
131
|
+
self.parent_log_id = log_data.get('parent_log_id', None)
|
|
127
132
|
print("Loaded log file at ", log_file)
|
|
128
133
|
print("Message length: ", len(self.messages))
|
|
129
134
|
else:
|
|
130
135
|
print("Could not find log file at ", log_file)
|
|
131
136
|
self.messages = []
|
|
132
137
|
|
|
133
|
-
def delete_log(self) -> None:
|
|
134
|
-
log_file = os.path.join(self.log_dir, f'chatlog_{self.log_id}.json')
|
|
135
|
-
if os.path.exists(log_file):
|
|
136
|
-
os.remove(log_file)
|
|
137
|
-
print("Deleted log file at ", log_file)
|
|
138
|
-
else:
|
|
139
|
-
print("Could not find log file at ", log_file)
|
|
140
|
-
|
|
141
138
|
def count_tokens(self) -> Dict[str, int]:
|
|
142
139
|
"""
|
|
143
140
|
Count tokens in the chat log, providing both sequence totals and cumulative request totals.
|
|
@@ -198,6 +195,34 @@ def find_chatlog_file(log_id: str) -> str:
|
|
|
198
195
|
|
|
199
196
|
return None
|
|
200
197
|
|
|
198
|
+
def find_child_logs_by_parent_id(parent_log_id: str) -> List[str]:
|
|
199
|
+
"""
|
|
200
|
+
Find all chat logs that have the given parent_log_id.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
parent_log_id: The parent log ID to search for
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
List of log IDs that have this parent_log_id
|
|
207
|
+
"""
|
|
208
|
+
child_log_ids = []
|
|
209
|
+
chat_dir = os.environ.get('CHATLOG_DIR', 'data/chat')
|
|
210
|
+
|
|
211
|
+
# Search through all chatlog files
|
|
212
|
+
for root, dirs, files in os.walk(chat_dir):
|
|
213
|
+
for file in files:
|
|
214
|
+
if file.startswith("chatlog_") and file.endswith(".json"):
|
|
215
|
+
try:
|
|
216
|
+
with open(os.path.join(root, file), 'r') as f:
|
|
217
|
+
log_data = json.load(f)
|
|
218
|
+
if log_data.get('parent_log_id') == parent_log_id:
|
|
219
|
+
# Extract log_id from the data
|
|
220
|
+
child_log_ids.append(log_data.get('log_id'))
|
|
221
|
+
except (json.JSONDecodeError, IOError):
|
|
222
|
+
continue
|
|
223
|
+
|
|
224
|
+
return child_log_ids
|
|
225
|
+
|
|
201
226
|
def extract_delegate_task_log_ids(messages: List[Dict]) -> List[str]:
|
|
202
227
|
"""
|
|
203
228
|
Extract log IDs from delegate_task commands in messages.
|
|
@@ -331,6 +356,9 @@ def count_tokens_for_log_id(log_id: str) -> Dict[str, int]:
|
|
|
331
356
|
# Load the chat log
|
|
332
357
|
with open(chatlog_path, 'r') as f:
|
|
333
358
|
log_data = json.load(f)
|
|
359
|
+
|
|
360
|
+
# Get parent_log_id if it exists
|
|
361
|
+
parent_log_id = log_data.get('parent_log_id')
|
|
334
362
|
|
|
335
363
|
# Create a temporary ChatLog instance to count tokens
|
|
336
364
|
temp_log = ChatLog(log_id=log_id, user="system", agent=log_data.get('agent', 'unknown'))
|
|
@@ -349,9 +377,19 @@ def count_tokens_for_log_id(log_id: str) -> Dict[str, int]:
|
|
|
349
377
|
# Find delegated task log IDs
|
|
350
378
|
delegated_log_ids = extract_delegate_task_log_ids(temp_log.messages)
|
|
351
379
|
|
|
352
|
-
#
|
|
353
|
-
|
|
354
|
-
|
|
380
|
+
# Also find child logs by parent_log_id
|
|
381
|
+
child_logs_by_parent = find_child_logs_by_parent_id(log_id)
|
|
382
|
+
|
|
383
|
+
# Combine all child log IDs (delegated tasks and parent_log_id children)
|
|
384
|
+
all_child_log_ids = set(delegated_log_ids) | set(child_logs_by_parent)
|
|
385
|
+
|
|
386
|
+
# If this log has a parent_log_id, we should not double-count it
|
|
387
|
+
# (it will be counted as part of its parent's cumulative total)
|
|
388
|
+
# But we still want to count its own children
|
|
389
|
+
|
|
390
|
+
# Recursively count tokens for all child tasks
|
|
391
|
+
for child_id in all_child_log_ids:
|
|
392
|
+
delegated_counts = count_tokens_for_log_id(child_id)
|
|
355
393
|
if delegated_counts:
|
|
356
394
|
combined_counts['input_tokens_sequence'] += delegated_counts['input_tokens_sequence']
|
|
357
395
|
combined_counts['output_tokens_sequence'] += delegated_counts['output_tokens_sequence']
|
|
@@ -372,4 +410,4 @@ def count_tokens_for_log_id(log_id: str) -> Dict[str, int]:
|
|
|
372
410
|
# Save to cache
|
|
373
411
|
save_token_counts_to_cache(log_id, token_counts)
|
|
374
412
|
|
|
375
|
-
return token_counts
|
|
413
|
+
return token_counts
|