mindroot 9.0.0__py3-none-any.whl → 9.1.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/chat/router.py +3 -2
- mindroot/coreplugins/env_manager/mod.py +32 -1
- mindroot/coreplugins/home/router.py +3 -1
- mindroot/coreplugins/startup/mod.py +3 -1
- mindroot/coreplugins/user_service/__init__.py +5 -0
- mindroot/coreplugins/user_service/file_trigger_service.py +72 -0
- mindroot/coreplugins/user_service/hooks.py +23 -0
- mindroot/coreplugins/user_service/models.py +7 -0
- mindroot/coreplugins/user_service/password_reset_service.py +79 -0
- mindroot/coreplugins/user_service/router.py +36 -0
- mindroot/coreplugins/user_service/templates/reset_password.jinja2 +39 -0
- mindroot/lib/chatcontext.py +8 -4
- mindroot/server.py +3 -1
- {mindroot-9.0.0.dist-info → mindroot-9.1.0.dist-info}/METADATA +1 -1
- {mindroot-9.0.0.dist-info → mindroot-9.1.0.dist-info}/RECORD +19 -14
- {mindroot-9.0.0.dist-info → mindroot-9.1.0.dist-info}/WHEEL +0 -0
- {mindroot-9.0.0.dist-info → mindroot-9.1.0.dist-info}/entry_points.txt +0 -0
- {mindroot-9.0.0.dist-info → mindroot-9.1.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-9.0.0.dist-info → mindroot-9.1.0.dist-info}/top_level.txt +0 -0
|
@@ -258,8 +258,9 @@ async def delete_chat_session(request: Request, log_id: str, user=Depends(requir
|
|
|
258
258
|
try:
|
|
259
259
|
# Try to determine the agent name from the context file first
|
|
260
260
|
agent_name = "unknown"
|
|
261
|
-
|
|
262
|
-
|
|
261
|
+
context_dir = os.environ.get('CHATCONTEXT_DIR', 'data/context')
|
|
262
|
+
context_file_path = f"{context_dir}/{user.username}/context_{log_id}.json"
|
|
263
|
+
|
|
263
264
|
if os.path.exists(context_file_path):
|
|
264
265
|
try:
|
|
265
266
|
with open(context_file_path, 'r') as f:
|
|
@@ -64,7 +64,7 @@ def scan_directory_for_env_vars(directory):
|
|
|
64
64
|
# Use grep to find os.environ references - much faster than parsing each file
|
|
65
65
|
cmd = [
|
|
66
66
|
'grep', '-r',
|
|
67
|
-
'-E', "
|
|
67
|
+
'-E', r"os\.environ(\.get\(|\[)",
|
|
68
68
|
'--include=*.py',
|
|
69
69
|
'--exclude-dir=venv',
|
|
70
70
|
'--exclude-dir=env',
|
|
@@ -132,6 +132,37 @@ async def scan_env_vars(params=None, context=None):
|
|
|
132
132
|
}
|
|
133
133
|
all_env_vars.update(env_vars)
|
|
134
134
|
|
|
135
|
+
# Also scan the coreplugins directory
|
|
136
|
+
coreplugins_path = '/files/mindroot/src/mindroot/coreplugins'
|
|
137
|
+
if os.path.isdir(coreplugins_path):
|
|
138
|
+
env_vars = scan_directory_for_env_vars(coreplugins_path)
|
|
139
|
+
if env_vars:
|
|
140
|
+
if 'core' not in results:
|
|
141
|
+
results['core'] = {
|
|
142
|
+
'plugin_name': 'core',
|
|
143
|
+
'category': 'core',
|
|
144
|
+
'env_vars': []
|
|
145
|
+
}
|
|
146
|
+
results['core']['env_vars'].extend(list(env_vars))
|
|
147
|
+
all_env_vars.update(env_vars)
|
|
148
|
+
|
|
149
|
+
# Also scan the lib directory
|
|
150
|
+
lib_path = '/files/mindroot/src/mindroot/lib'
|
|
151
|
+
if os.path.isdir(lib_path):
|
|
152
|
+
env_vars = scan_directory_for_env_vars(lib_path)
|
|
153
|
+
if env_vars:
|
|
154
|
+
if 'core' not in results:
|
|
155
|
+
results['core'] = {
|
|
156
|
+
'plugin_name': 'core',
|
|
157
|
+
'category': 'core',
|
|
158
|
+
'env_vars': []
|
|
159
|
+
}
|
|
160
|
+
# Add only new variables to avoid duplicates
|
|
161
|
+
existing_vars = set(results['core']['env_vars'])
|
|
162
|
+
new_vars = env_vars - existing_vars
|
|
163
|
+
results['core']['env_vars'].extend(list(new_vars))
|
|
164
|
+
all_env_vars.update(new_vars)
|
|
165
|
+
|
|
135
166
|
# Get current environment variables
|
|
136
167
|
current_env = {}
|
|
137
168
|
for var_name in all_env_vars:
|
|
@@ -22,9 +22,11 @@ async def home(request: Request):
|
|
|
22
22
|
|
|
23
23
|
# Try to sort agents by last access time
|
|
24
24
|
agent_access_times = []
|
|
25
|
+
chatlog_dir = os.environ.get('CHATLOG_DIR', 'data/chat')
|
|
25
26
|
for agent in agent_dirs:
|
|
26
27
|
# Look for the most recent log file for this agent
|
|
27
|
-
|
|
28
|
+
# Search across all user directories for this agent's logs
|
|
29
|
+
log_pattern = f"{chatlog_dir}/*/{agent}/chatlog_*.json"
|
|
28
30
|
log_files = glob.glob(log_pattern)
|
|
29
31
|
|
|
30
32
|
if log_files:
|
|
@@ -10,7 +10,9 @@ print("--- AH Startup ---")
|
|
|
10
10
|
async def on_load(app):
|
|
11
11
|
print(termcolor.colored("startup plugin calling startup() hook...", 'yellow', 'on_green'))
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
context_dir = os.environ.get('CHATCONTEXT_DIR', 'data/context')
|
|
14
|
+
chatlog_dir = os.environ.get('CHATLOG_DIR', 'data/chat')
|
|
15
|
+
for dirs in [context_dir, chatlog_dir]:
|
|
14
16
|
os.makedirs(dirs, exist_ok=True)
|
|
15
17
|
|
|
16
18
|
context = ChatContext(user='startup')
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import logging
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from lib.providers.services import service, ServiceProvider
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
# Use paths relative to the process working directory
|
|
11
|
+
REQUEST_DIR = "data/password_resets/requests"
|
|
12
|
+
GENERATED_DIR = "data/password_resets/generated"
|
|
13
|
+
CHECK_INTERVAL_SECONDS = 30
|
|
14
|
+
|
|
15
|
+
@service()
|
|
16
|
+
async def process_password_reset_requests(context=None):
|
|
17
|
+
"""Processes password reset request files from a directory."""
|
|
18
|
+
# Ensure directories exist
|
|
19
|
+
os.makedirs(REQUEST_DIR, exist_ok=True)
|
|
20
|
+
os.makedirs(GENERATED_DIR, exist_ok=True)
|
|
21
|
+
|
|
22
|
+
sp = ServiceProvider()
|
|
23
|
+
initiate_reset = sp.get('user_service.initiate_password_reset')
|
|
24
|
+
|
|
25
|
+
if not (initiate_reset and callable(initiate_reset)):
|
|
26
|
+
logger.error("Could not get 'user_service.initiate_password_reset' service.")
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
for filename in os.listdir(REQUEST_DIR):
|
|
30
|
+
request_file_path = os.path.join(REQUEST_DIR, filename)
|
|
31
|
+
if not os.path.isfile(request_file_path):
|
|
32
|
+
continue
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
with open(request_file_path, 'r') as f:
|
|
36
|
+
data = json.load(f)
|
|
37
|
+
|
|
38
|
+
username = data.get("username")
|
|
39
|
+
is_admin_reset = data.get("is_admin_reset", False)
|
|
40
|
+
|
|
41
|
+
if not username:
|
|
42
|
+
raise ValueError("Username is missing from request file.")
|
|
43
|
+
|
|
44
|
+
logger.info(f"Processing password reset request for user: {username}")
|
|
45
|
+
token = await initiate_reset(username=username, is_admin_reset=is_admin_reset)
|
|
46
|
+
|
|
47
|
+
reset_link = f"/user_service/reset-password/{token}"
|
|
48
|
+
generated_file_path = os.path.join(GENERATED_DIR, f"{username}_{datetime.utcnow().strftime('%Y%m%d%H%M%S')}.json")
|
|
49
|
+
with open(generated_file_path, 'w') as f:
|
|
50
|
+
json.dump({"username": username, "reset_link": reset_link, "token": token}, f, indent=2)
|
|
51
|
+
|
|
52
|
+
logger.info(f"Successfully generated password reset link for {username}.")
|
|
53
|
+
os.remove(request_file_path)
|
|
54
|
+
|
|
55
|
+
except Exception as e:
|
|
56
|
+
logger.error(f"Failed to process reset request file {filename}: {e}")
|
|
57
|
+
error_file_path = os.path.join(REQUEST_DIR, f"{filename}.error")
|
|
58
|
+
os.rename(request_file_path, error_file_path)
|
|
59
|
+
|
|
60
|
+
@service()
|
|
61
|
+
async def start_file_watcher_service(context=None):
|
|
62
|
+
"""Starts a background task to watch for password reset request files."""
|
|
63
|
+
logger.info("Starting password reset file watcher service.")
|
|
64
|
+
async def watcher_loop():
|
|
65
|
+
while True:
|
|
66
|
+
try:
|
|
67
|
+
await process_password_reset_requests()
|
|
68
|
+
except Exception as e:
|
|
69
|
+
logger.error(f"Error in password reset watcher loop: {e}")
|
|
70
|
+
await asyncio.sleep(CHECK_INTERVAL_SECONDS)
|
|
71
|
+
|
|
72
|
+
asyncio.create_task(watcher_loop())
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
from lib.providers.hooks import hook
|
|
4
|
+
from lib.providers.services import ServiceProvider
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
@hook('startup')
|
|
9
|
+
async def on_user_service_startup(app, context=None):
|
|
10
|
+
"""
|
|
11
|
+
Startup hook for the user_service plugin.
|
|
12
|
+
"""
|
|
13
|
+
logger.info("User service startup hook triggered.")
|
|
14
|
+
try:
|
|
15
|
+
sp = ServiceProvider()
|
|
16
|
+
start_watcher = sp.get('user_service.start_file_watcher_service')
|
|
17
|
+
if start_watcher and callable(start_watcher):
|
|
18
|
+
logger.info("Starting the password reset file watcher service via startup hook.")
|
|
19
|
+
asyncio.create_task(start_watcher())
|
|
20
|
+
else:
|
|
21
|
+
logger.error("Could not find 'user_service.start_file_watcher_service' during startup.")
|
|
22
|
+
except Exception as e:
|
|
23
|
+
logger.error(f"Error starting file watcher service from hook: {e}")
|
|
@@ -26,3 +26,10 @@ class UserCreate(BaseModel):
|
|
|
26
26
|
class UserInRequest(UserBase):
|
|
27
27
|
"""User data as attached to request.state.user"""
|
|
28
28
|
token_data: dict
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class PasswordResetToken(BaseModel):
|
|
32
|
+
"""Data for password reset tokens"""
|
|
33
|
+
token: str
|
|
34
|
+
expires_at: str
|
|
35
|
+
is_admin_reset: bool = False
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from lib.providers.services import service
|
|
2
|
+
from .models import UserAuth, PasswordResetToken
|
|
3
|
+
import bcrypt
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import secrets
|
|
7
|
+
from datetime import datetime, timedelta
|
|
8
|
+
|
|
9
|
+
USER_DATA_ROOT = "data/users"
|
|
10
|
+
RESET_TOKEN_VALIDITY_HOURS = 1
|
|
11
|
+
|
|
12
|
+
@service()
|
|
13
|
+
async def initiate_password_reset(username: str, is_admin_reset: bool = False, context=None) -> str:
|
|
14
|
+
"""Initiates a password reset, generates a token, and stores it."""
|
|
15
|
+
user_dir = os.path.join(USER_DATA_ROOT, username)
|
|
16
|
+
if not os.path.exists(user_dir):
|
|
17
|
+
raise ValueError("User not found")
|
|
18
|
+
|
|
19
|
+
token = secrets.token_urlsafe(32)
|
|
20
|
+
expires_at = datetime.utcnow() + timedelta(hours=RESET_TOKEN_VALIDITY_HOURS)
|
|
21
|
+
|
|
22
|
+
reset_data = PasswordResetToken(
|
|
23
|
+
token=token,
|
|
24
|
+
expires_at=expires_at.isoformat(),
|
|
25
|
+
is_admin_reset=is_admin_reset
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
reset_file_path = os.path.join(user_dir, "password_reset.json")
|
|
29
|
+
with open(reset_file_path, 'w') as f:
|
|
30
|
+
json.dump(reset_data.dict(), f, indent=2)
|
|
31
|
+
|
|
32
|
+
# In a real application, you would email this token to the user.
|
|
33
|
+
# For this implementation, we return it directly.
|
|
34
|
+
return token
|
|
35
|
+
|
|
36
|
+
@service()
|
|
37
|
+
async def reset_password_with_token(token: str, new_password: str, context=None) -> bool:
|
|
38
|
+
"""Resets a user's password using a valid reset token."""
|
|
39
|
+
for username in os.listdir(USER_DATA_ROOT):
|
|
40
|
+
user_dir = os.path.join(USER_DATA_ROOT, username)
|
|
41
|
+
reset_file_path = os.path.join(user_dir, "password_reset.json")
|
|
42
|
+
|
|
43
|
+
if not os.path.exists(reset_file_path):
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
with open(reset_file_path, 'r') as f:
|
|
47
|
+
try:
|
|
48
|
+
reset_data = PasswordResetToken(**json.load(f))
|
|
49
|
+
except (json.JSONDecodeError, TypeError):
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
if reset_data.token == token:
|
|
53
|
+
if datetime.fromisoformat(reset_data.expires_at) < datetime.utcnow():
|
|
54
|
+
os.remove(reset_file_path) # Expired token
|
|
55
|
+
raise ValueError("Password reset token has expired.")
|
|
56
|
+
|
|
57
|
+
auth_file_path = os.path.join(user_dir, "auth.json")
|
|
58
|
+
if not os.path.exists(auth_file_path):
|
|
59
|
+
os.remove(reset_file_path)
|
|
60
|
+
raise FileNotFoundError("User auth file not found.")
|
|
61
|
+
|
|
62
|
+
with open(auth_file_path, 'r+') as auth_file:
|
|
63
|
+
auth_data_dict = json.load(auth_file)
|
|
64
|
+
auth_data = UserAuth(**auth_data_dict)
|
|
65
|
+
|
|
66
|
+
new_password_hash = bcrypt.hashpw(new_password.encode(), bcrypt.gensalt()).decode()
|
|
67
|
+
auth_data.password_hash = new_password_hash
|
|
68
|
+
|
|
69
|
+
if reset_data.is_admin_reset and 'admin' not in auth_data.roles:
|
|
70
|
+
auth_data.roles.append('admin')
|
|
71
|
+
|
|
72
|
+
auth_file.seek(0)
|
|
73
|
+
json.dump(auth_data.dict(), auth_file, indent=2, default=str)
|
|
74
|
+
auth_file.truncate()
|
|
75
|
+
|
|
76
|
+
os.remove(reset_file_path) # Invalidate token after use
|
|
77
|
+
return True
|
|
78
|
+
|
|
79
|
+
raise ValueError("Invalid password reset token.")
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from fastapi import APIRouter, Request, Form, Depends
|
|
2
|
+
from fastapi.responses import HTMLResponse, RedirectResponse
|
|
3
|
+
from lib.templates import render
|
|
4
|
+
from .password_reset_service import reset_password_with_token, initiate_password_reset
|
|
5
|
+
from lib.providers.services import service_manager
|
|
6
|
+
from lib.providers import ProviderManager
|
|
7
|
+
|
|
8
|
+
router = APIRouter()
|
|
9
|
+
|
|
10
|
+
@router.get("/reset-password/{token}")
|
|
11
|
+
async def get_reset_password_form(request: Request, token: str):
|
|
12
|
+
return await render('reset_password', {"request": request, "token": token, "error": None, "success": False})
|
|
13
|
+
|
|
14
|
+
@router.post("/reset-password/{token}")
|
|
15
|
+
async def handle_reset_password(request: Request, token: str, password: str = Form(...), confirm_password: str = Form(...), services: ProviderManager = Depends(lambda: service_manager)):
|
|
16
|
+
if password != confirm_password:
|
|
17
|
+
return await render('reset_password', {"request": request, "token": token, "error": "Passwords do not match.", "success": False})
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
success = await services.get('user_service.reset_password_with_token')(token=token, new_password=password)
|
|
21
|
+
if success:
|
|
22
|
+
return await render('reset_password', {"request": request, "token": token, "error": None, "success": True})
|
|
23
|
+
else:
|
|
24
|
+
return await render('reset_password', {"request": request, "token": token, "error": "Invalid or expired token.", "success": False})
|
|
25
|
+
except ValueError as e:
|
|
26
|
+
return await render('reset_password', {"request": request, "token": token, "error": str(e), "success": False})
|
|
27
|
+
|
|
28
|
+
# This is an admin-only function to generate a reset link.
|
|
29
|
+
# In a real app, this would be more protected.
|
|
30
|
+
@router.get("/admin/initiate-reset/{username}")
|
|
31
|
+
async def admin_initiate_reset(username: str, services: ProviderManager = Depends(lambda: service_manager)):
|
|
32
|
+
try:
|
|
33
|
+
token = await services.get('user_service.initiate_password_reset')(username=username)
|
|
34
|
+
return HTMLResponse(f'<h1>Password Reset Link</h1><p>Share this link with the user: <a href="/user_service/reset-password/{token}">/user_service/reset-password/{token}</a></p>')
|
|
35
|
+
except ValueError as e:
|
|
36
|
+
return HTMLResponse(f'<h1>Error</h1><p>{str(e)}</p>', status_code=404)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Reset Password</title>
|
|
7
|
+
<style>
|
|
8
|
+
body { font-family: sans-serif; background-color: #1a1a1a; color: #f0f0f0; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
|
|
9
|
+
.container { background-color: #2a2a2a; padding: 2rem; border-radius: 8px; box-shadow: 0 4px 8px rgba(0,0,0,0.3); width: 100%; max-width: 400px; }
|
|
10
|
+
h1 { text-align: center; color: #fff; }
|
|
11
|
+
form { display: flex; flex-direction: column; gap: 1rem; }
|
|
12
|
+
label { font-weight: bold; }
|
|
13
|
+
input[type="password"] { padding: 0.75rem; border-radius: 4px; border: 1px solid #444; background-color: #333; color: #f0f0f0; }
|
|
14
|
+
button { padding: 0.75rem; border: none; border-radius: 4px; background-color: #007bff; color: white; font-size: 1rem; cursor: pointer; }
|
|
15
|
+
button:hover { background-color: #0056b3; }
|
|
16
|
+
.error { color: #ff4d4d; background-color: #402a2a; padding: 1rem; border-radius: 4px; text-align: center; }
|
|
17
|
+
.success { color: #4dff4d; background-color: #2a402a; padding: 1rem; border-radius: 4px; text-align: center; }
|
|
18
|
+
</style>
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<div class="container">
|
|
22
|
+
<h1>Reset Your Password</h1>
|
|
23
|
+
{% if success %}
|
|
24
|
+
<div class="success">Your password has been reset successfully. You can now log in with your new password.</div>
|
|
25
|
+
{% else %}
|
|
26
|
+
<form method="post">
|
|
27
|
+
<label for="password">New Password</label>
|
|
28
|
+
<input type="password" id="password" name="password" required minlength="8">
|
|
29
|
+
<label for="confirm_password">Confirm New Password</label>
|
|
30
|
+
<input type="password" id="confirm_password" name="confirm_password" required minlength="8">
|
|
31
|
+
<button type="submit">Reset Password</button>
|
|
32
|
+
</form>
|
|
33
|
+
{% if error %}
|
|
34
|
+
<p class="error">{{ error }}</p>
|
|
35
|
+
{% endif %}
|
|
36
|
+
{% endif %}
|
|
37
|
+
</div>
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|
mindroot/lib/chatcontext.py
CHANGED
|
@@ -93,7 +93,8 @@ class ChatContext:
|
|
|
93
93
|
raise ValueError('log_id is not set for the context.')
|
|
94
94
|
else:
|
|
95
95
|
pass
|
|
96
|
-
|
|
96
|
+
context_dir = os.environ.get('CHATCONTEXT_DIR', 'data/context')
|
|
97
|
+
context_file = f'{context_dir}/{self.username}/context_{self.log_id}.json'
|
|
97
98
|
await aiofiles.os.makedirs(os.path.dirname(context_file), exist_ok=True)
|
|
98
99
|
try:
|
|
99
100
|
async with aiofiles.open(context_file, 'r') as f:
|
|
@@ -112,7 +113,8 @@ class ChatContext:
|
|
|
112
113
|
raise ValueError('log_id is not set for the context.')
|
|
113
114
|
else:
|
|
114
115
|
pass
|
|
115
|
-
|
|
116
|
+
context_dir = os.environ.get('CHATCONTEXT_DIR', 'data/context')
|
|
117
|
+
context_file = f'{context_dir}/{self.username}/context_{self.log_id}.json'
|
|
116
118
|
await aiofiles.os.makedirs(os.path.dirname(context_file), exist_ok=True)
|
|
117
119
|
self.data['log_id'] = self.log_id
|
|
118
120
|
context_data = {'data': self.data, 'chat_log': self.chat_log._get_log_data()}
|
|
@@ -133,7 +135,8 @@ class ChatContext:
|
|
|
133
135
|
|
|
134
136
|
async def load_context(self, log_id):
|
|
135
137
|
self.log_id = log_id
|
|
136
|
-
|
|
138
|
+
context_dir = os.environ.get('CHATCONTEXT_DIR', 'data/context')
|
|
139
|
+
context_file = f'{context_dir}/{self.username}/context_{log_id}.json'
|
|
137
140
|
if await aiofiles.os.path.exists(context_file):
|
|
138
141
|
async with aiofiles.open(context_file, 'r') as f:
|
|
139
142
|
content = await f.read()
|
|
@@ -238,7 +241,8 @@ class ChatContext:
|
|
|
238
241
|
print(f"Chatlog file not found for deletion: {chatlog_file_to_delete}")
|
|
239
242
|
|
|
240
243
|
# ChatContext File (Agent is not part of the context file path structure)
|
|
241
|
-
|
|
244
|
+
context_dir = os.environ.get('CHATCONTEXT_DIR', 'data/context')
|
|
245
|
+
context_file_to_delete = os.path.join(context_dir, user, f'context_{log_id}.json')
|
|
242
246
|
if await aiofiles.os.path.exists(context_file_to_delete):
|
|
243
247
|
try:
|
|
244
248
|
await aiofiles.os.remove(context_file_to_delete)
|
mindroot/server.py
CHANGED
|
@@ -36,7 +36,6 @@ def create_directories():
|
|
|
36
36
|
root = get_project_root()
|
|
37
37
|
directories = [
|
|
38
38
|
"imgs",
|
|
39
|
-
"data/chat",
|
|
40
39
|
"models",
|
|
41
40
|
"models/face",
|
|
42
41
|
"models/llm",
|
|
@@ -46,6 +45,9 @@ def create_directories():
|
|
|
46
45
|
"personas/shared",
|
|
47
46
|
"data/sessions"
|
|
48
47
|
]
|
|
48
|
+
chatlog_dir = os.environ.get('CHATLOG_DIR', 'data/chat')
|
|
49
|
+
directories.append(chatlog_dir)
|
|
50
|
+
|
|
49
51
|
for directory in directories:
|
|
50
52
|
(root / directory).mkdir(parents=True, exist_ok=True)
|
|
51
53
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
mindroot/__init__.py,sha256=OrFRGt_fdSYjolLXUzjSX2CIn1cOAm6l47ENNAkwmgQ,83
|
|
2
|
-
mindroot/server.py,sha256=
|
|
2
|
+
mindroot/server.py,sha256=vFJSZ4FPI7YBWDlBfGihNMh1IiwBo9R0Sz8dM15cm4k,4888
|
|
3
3
|
mindroot/coreplugins/admin/__init__.py,sha256=388n_hMskU0TnZ4xT10US_kFkya-EPBjWcv7AZf_HOk,74
|
|
4
4
|
mindroot/coreplugins/admin/agent_importer.py,sha256=8hQLO64iKtPA5gv9-mLUfUCcnRp3IH9-sTfgkPsrmqo,6376
|
|
5
5
|
mindroot/coreplugins/admin/agent_router.py,sha256=mstYUURNRb9MpfNwqMYC7WY3FOQJ-5H0TNNz4mDSjFM,9220
|
|
@@ -452,7 +452,7 @@ mindroot/coreplugins/chat/commands.py,sha256=vlgGOvwvjpCbSsW25x4HaeFzeRNWXoEKrdq
|
|
|
452
452
|
mindroot/coreplugins/chat/format_result_msgs.py,sha256=daEdpEyAJIa8b2VkCqSKcw8PaExcB6Qro80XNes_sHA,2
|
|
453
453
|
mindroot/coreplugins/chat/mod.py,sha256=Xydjv3feKJJRbwdiB7raqiQnWtaS_2GcdC9bXYQX3nE,425
|
|
454
454
|
mindroot/coreplugins/chat/models.py,sha256=GRcRuDUAJFpyWERPMxkxUaZ21igNlWeeamriruEKiEQ,692
|
|
455
|
-
mindroot/coreplugins/chat/router.py,sha256=
|
|
455
|
+
mindroot/coreplugins/chat/router.py,sha256=pj2-zmlNyPxsqb7kY1iWeK9eMYHoaGcVN1oQY26Jl0I,11337
|
|
456
456
|
mindroot/coreplugins/chat/services.py,sha256=MNFuRs6g2IF6hyo2rqa4aU8U2N7Z_7ZJbstv7sCfIYw,17968
|
|
457
457
|
mindroot/coreplugins/chat/utils.py,sha256=BiE14PpsAcQSO5vbU88klHGm8cAXJDXxgVgva-EXybU,155
|
|
458
458
|
mindroot/coreplugins/chat/static/assistant.png,sha256=oAt1ctkFKLSPBoAZGNnSixooW9ANVIk1GwniauVWDXo,215190
|
|
@@ -913,7 +913,7 @@ mindroot/coreplugins/email/test_batch.py,sha256=gCe_E02K0sCrOWi4meEELx0rckeCRXaF
|
|
|
913
913
|
mindroot/coreplugins/email/test_email.py,sha256=SrG6Luts0r9YbDqSsBT8I45gIKZi3s3Q5d_dPNxj1Q0,5328
|
|
914
914
|
mindroot/coreplugins/email/backup/mod.py,sha256=6vvFGpOzCCfEDYlaJBEixRgNRIfvp-mcD6siCwvtxcI,2118
|
|
915
915
|
mindroot/coreplugins/env_manager/__init__.py,sha256=zcQypdwauAdtsj1Be-QZcPeLU_T3LiYaoWKWmIRKsnY,100
|
|
916
|
-
mindroot/coreplugins/env_manager/mod.py,sha256=
|
|
916
|
+
mindroot/coreplugins/env_manager/mod.py,sha256=fcap4fmo1c_mW8ED8V6W6QErg8_RwfzWIPuZL6vHw1o,8176
|
|
917
917
|
mindroot/coreplugins/env_manager/router.py,sha256=f0d3BoeuwdUXBVJ4Kco8PURIWue5g_xI-5PGi6_6pF8,1185
|
|
918
918
|
mindroot/coreplugins/env_manager/inject/admin.jinja2,sha256=BLGzp3Osc1aKo5-4rOwM3Gy4-FdoJQh7oYcTMrkaW-s,462
|
|
919
919
|
mindroot/coreplugins/env_manager/static/css/env-manager.css,sha256=Y-538HHrkYtiyX-l15sYUJ6mmspbJVJZniHQKz6sL9g,4288
|
|
@@ -924,7 +924,7 @@ mindroot/coreplugins/events/router.py,sha256=a-77306_fQPNHPXP5aYtbpfC0gbqMBNRu04
|
|
|
924
924
|
mindroot/coreplugins/events/backup/mod.py,sha256=9QeJpg6WKwxRdjiKVHD1froguTe86FS2-2wWm1B9xa8,1832
|
|
925
925
|
mindroot/coreplugins/events/backup/router_backup.py,sha256=ImU8xoxdSd45V1yOFVqdtDQ614V6CMsDZQ1gtJj0Mnk,254
|
|
926
926
|
mindroot/coreplugins/home/mod.py,sha256=MsSFjiLMLJZ7QhUPpVBWKiyDnCzryquRyr329NoCACI,2
|
|
927
|
-
mindroot/coreplugins/home/router.py,sha256=
|
|
927
|
+
mindroot/coreplugins/home/router.py,sha256=VZN9dDm70NTXgP_u-6Yi8lcEEgx6wocI3brqb898Ons,2120
|
|
928
928
|
mindroot/coreplugins/home/static/css/dark.css,sha256=Q9FHaEsf9xeJjtouyKgr1Su6vTzsN07NHxxqDrDfyx8,14259
|
|
929
929
|
mindroot/coreplugins/home/static/css/default.css,sha256=zlQjpwNvuJP_zULCWkFycWudF1GRQz9Y5mvdKpzXXFc,13354
|
|
930
930
|
mindroot/coreplugins/home/static/css/enhanced.css,sha256=oYGR_abXN5-wTmabQ3_QfSOoZ8sDRajsJJAfBgk-voE,3800
|
|
@@ -1725,7 +1725,7 @@ mindroot/coreplugins/signup/static/imgs/logo.png,sha256=ZfPlCqCjU0_TXte5gvEx81zR
|
|
|
1725
1725
|
mindroot/coreplugins/signup/templates/signup.html,sha256=RdG-s-P2JvUcN8AFOdCFGVei71ijs0ZEE4_LRsWGEf8,5814
|
|
1726
1726
|
mindroot/coreplugins/signup/templates/signup.jinja2,sha256=Fzq0fZVQFM7tpi4Y5kumxv9Nis8FLpVTUAIawHck4ZQ,6051
|
|
1727
1727
|
mindroot/coreplugins/startup/__init__.py,sha256=ciWKt5NdIobetUMqXqctfsSSLKw2lwhQDB2PVhvc2Ak,21
|
|
1728
|
-
mindroot/coreplugins/startup/mod.py,sha256=
|
|
1728
|
+
mindroot/coreplugins/startup/mod.py,sha256=6NsrpuVFvLeKGjgV3erCBBeYhy5Y3pT8gJmI64Eq8DM,698
|
|
1729
1729
|
mindroot/coreplugins/subscriptions/__init__.py,sha256=hW2m-zjPerMEqUFEcv265zjMr1TIms2Ofnni4MvKDes,95
|
|
1730
1730
|
mindroot/coreplugins/subscriptions/credit_integration.py,sha256=X92tUNcWxvJXv2uCzmhLKTnjbhZC_pLlWYEPLlhQbCY,2103
|
|
1731
1731
|
mindroot/coreplugins/subscriptions/default_templates.py,sha256=S32UkKZLbLyEYUn1Js34TWTvwVA7paYP72UYRJiqv6Y,9749
|
|
@@ -1759,19 +1759,24 @@ mindroot/coreplugins/usage/router.py,sha256=gXxpbA3HL_jV1Ngi0TlET_mXRawBmK2-4huo
|
|
|
1759
1759
|
mindroot/coreplugins/usage/storage.py,sha256=zJLq7e3Od7w8K0OCzf3ANenFCeqMbi88BsXy2wQQ6L4,5931
|
|
1760
1760
|
mindroot/coreplugins/usage/templates/base.jinja2,sha256=Rcr4i-9luLZW7jDKzBBelUKpEPmzCCBqQmXVQTAX8QE,1441
|
|
1761
1761
|
mindroot/coreplugins/usage/templates/usage.jinja2,sha256=bSAjGbgx-hgzkPR0u1OIoJiOdajHgCCDRa7RVUOywJs,7722
|
|
1762
|
-
mindroot/coreplugins/user_service/__init__.py,sha256=
|
|
1762
|
+
mindroot/coreplugins/user_service/__init__.py,sha256=YdQYM2GS6I2vB6r4ilODQjcV6LKTnKlCmo1EbfCQeVE,171
|
|
1763
1763
|
mindroot/coreplugins/user_service/admin_init.py,sha256=wQ28wmohiER0iMEyz4kypSbSDkD38LE7WXSgZyo0-pA,3923
|
|
1764
1764
|
mindroot/coreplugins/user_service/email_service.py,sha256=ptcnvPIxF7kY9NgdDlNZYGirzi6ruY8sWmuMp-fHLgA,1591
|
|
1765
|
+
mindroot/coreplugins/user_service/file_trigger_service.py,sha256=HyIvY_6UHE1oJgxDx-PsPcQa1l2cG9Cg4P_EvsnMVCI,2853
|
|
1766
|
+
mindroot/coreplugins/user_service/hooks.py,sha256=4di2j0tVhEKplDaG9fTlRtErIflZPYBfC3iHGBtUgh0,875
|
|
1765
1767
|
mindroot/coreplugins/user_service/mod.py,sha256=CW0CtNp4EOg3HsNS-PlwVVy4F5q0v0RJyAvifKVhFRM,4856
|
|
1766
|
-
mindroot/coreplugins/user_service/models.py,sha256=
|
|
1768
|
+
mindroot/coreplugins/user_service/models.py,sha256=s_dy881Ob8Ng94PQ-Iw9lYq306l3QsnDLVk7e3OED5w,1137
|
|
1769
|
+
mindroot/coreplugins/user_service/password_reset_service.py,sha256=K77GPP-APQOsqRxMzoaOb5OA7MCwubSMdRNcau7BJ3M,2992
|
|
1767
1770
|
mindroot/coreplugins/user_service/role_service.py,sha256=e6XrxhMC4903C-Y515XSC544uXAik6-CSee-TIPGIwA,2329
|
|
1771
|
+
mindroot/coreplugins/user_service/router.py,sha256=IH89Ahk9T9WyAkvEi7Kgv6EIJ0jKOuN6u6sZ32mfDRs,2201
|
|
1768
1772
|
mindroot/coreplugins/user_service/backup/admin_service.py,sha256=scc59rxlZz4uuVvgjf-9HL2gKi7-uiCdSt6LjWJILR8,4259
|
|
1769
1773
|
mindroot/coreplugins/user_service/backup/admin_setup.py,sha256=JGszAw8nVtnNiisSUGu9jtoStKGyN44KpbRlKAhDJho,3001
|
|
1774
|
+
mindroot/coreplugins/user_service/templates/reset_password.jinja2,sha256=GE2rHNmSUlAS5EoJuu9g3KsUel5RNMKMVYTfxhi2IPM,2097
|
|
1770
1775
|
mindroot/lib/__init__.py,sha256=388n_hMskU0TnZ4xT10US_kFkya-EPBjWcv7AZf_HOk,74
|
|
1771
1776
|
mindroot/lib/buchatlog.py,sha256=LJZc3ksKgJcStltmHrrwNLaON3EDzhOKVAWj0Wl22wk,5861
|
|
1772
1777
|
mindroot/lib/buchatlog2.py,sha256=Va9FteBWePEjWD9OZcw-OtQfEb-IoCVGTmJeMRaX9is,13729
|
|
1773
1778
|
mindroot/lib/butemplates.py,sha256=gfHGPTOjvoEenXsR7xokNuqMjOAPuC2DawheH1Ae4bU,12196
|
|
1774
|
-
mindroot/lib/chatcontext.py,sha256=
|
|
1779
|
+
mindroot/lib/chatcontext.py,sha256=CXk-pX-7RG3NiRFsAZWERWxnuFJOHH7FHtOLm-kGRXE,12437
|
|
1775
1780
|
mindroot/lib/chatlog.py,sha256=QbUNPgCnr9KhreQt4A_kXNICy1-JsVjpLKYt6URYhaQ,19390
|
|
1776
1781
|
mindroot/lib/chatlog_optimized.py,sha256=rL7KBP-V4_cGgMLihxPm3HoKcjFEyA1uEtPtqvkOa3A,20011
|
|
1777
1782
|
mindroot/lib/json_escape.py,sha256=5cAmAdNbnYX2uyfQcnse2fFtNI0CdB-AfZ23RwaDm-k,884
|
|
@@ -1821,9 +1826,9 @@ mindroot/protocols/services/stream_chat.py,sha256=fMnPfwaB5fdNMBLTEg8BXKAGvrELKH
|
|
|
1821
1826
|
mindroot/registry/__init__.py,sha256=40Xy9bmPHsgdIrOzbtBGzf4XMqXVi9P8oZTJhn0r654,151
|
|
1822
1827
|
mindroot/registry/component_manager.py,sha256=WZFNPg4SNvpqsM5NFiC2DpgmrJQCyR9cNhrCBpp30Qk,995
|
|
1823
1828
|
mindroot/registry/data_access.py,sha256=NgNMamxIjaKeYxzxnVaQz1Y-Rm0AI51si3788_JHUTM,5316
|
|
1824
|
-
mindroot-9.
|
|
1825
|
-
mindroot-9.
|
|
1826
|
-
mindroot-9.
|
|
1827
|
-
mindroot-9.
|
|
1828
|
-
mindroot-9.
|
|
1829
|
-
mindroot-9.
|
|
1829
|
+
mindroot-9.1.0.dist-info/licenses/LICENSE,sha256=8plAmZh8y9ccuuqFFz4kp7G-cO_qsPgAOoHNvabSB4U,1070
|
|
1830
|
+
mindroot-9.1.0.dist-info/METADATA,sha256=ydC57sIWRLy3f2wJXLGSW3Fzhn2lVqsS1KqQbGuPO1g,891
|
|
1831
|
+
mindroot-9.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
1832
|
+
mindroot-9.1.0.dist-info/entry_points.txt,sha256=0bpyjMccLttx6VcjDp6zfJPN0Kk0rffor6IdIbP0j4c,50
|
|
1833
|
+
mindroot-9.1.0.dist-info/top_level.txt,sha256=gwKm7DmNjhdrCJTYCrxa9Szne4lLpCtrEBltfsX-Mm8,9
|
|
1834
|
+
mindroot-9.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|