mindroot 9.2.0__py3-none-any.whl → 9.5.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.
- mindroot/coreplugins/admin/__init__.py +3 -1
- mindroot/coreplugins/admin/agent_router.py +250 -7
- mindroot/coreplugins/admin/asset_manager.py +164 -0
- mindroot/coreplugins/admin/command_router.py +236 -1
- mindroot/coreplugins/admin/mcp_catalog_routes.py +156 -0
- mindroot/coreplugins/admin/mcp_publish_routes.py +450 -0
- mindroot/coreplugins/admin/mcp_registry_routes.py +495 -0
- mindroot/coreplugins/admin/mcp_routes.py +216 -0
- mindroot/coreplugins/admin/mod.py +62 -0
- mindroot/coreplugins/admin/oauth_callback_router.py +84 -0
- mindroot/coreplugins/admin/persona_handler.py +15 -6
- mindroot/coreplugins/admin/persona_router.py +158 -2
- mindroot/coreplugins/admin/plugin_manager.py +63 -0
- mindroot/coreplugins/admin/plugin_router.py +1 -1
- mindroot/coreplugins/admin/plugin_router_fixed.py +23 -0
- mindroot/coreplugins/admin/plugin_router_new_not_working.py +145 -0
- mindroot/coreplugins/admin/plugin_routes.py +114 -0
- mindroot/coreplugins/admin/registry_settings_routes.py +140 -0
- mindroot/coreplugins/admin/router.py +116 -15
- mindroot/coreplugins/admin/service_models.py +1 -1
- mindroot/coreplugins/admin/settings_router.py +1 -0
- mindroot/coreplugins/admin/static/css/admin-custom.css +357 -2
- mindroot/coreplugins/admin/static/css/dark.css +1 -0
- mindroot/coreplugins/admin/static/css/default.css +4 -0
- mindroot/coreplugins/admin/static/js/about-info.js +367 -0
- mindroot/coreplugins/admin/static/js/agent-form.js +83 -3
- mindroot/coreplugins/admin/static/js/api-key-script.js +307 -0
- mindroot/coreplugins/admin/static/js/mcp-manager.js +348 -0
- mindroot/coreplugins/admin/static/js/mcp-publisher.js +780 -0
- mindroot/coreplugins/admin/static/js/persona-editor.js +34 -5
- mindroot/coreplugins/admin/static/js/plugin-toggle.js +1 -1
- mindroot/coreplugins/admin/static/js/recommended-plugin-install.js +63 -0
- mindroot/coreplugins/admin/static/js/registry-auth-section.js +132 -0
- mindroot/coreplugins/admin/static/js/registry-manager-base.js +613 -0
- mindroot/coreplugins/admin/static/js/registry-manager-old.js +385 -0
- mindroot/coreplugins/admin/static/js/registry-manager-publish-old-delete.js +166 -0
- mindroot/coreplugins/admin/static/js/registry-manager.js +351 -0
- mindroot/coreplugins/admin/static/js/registry-publish-section.js +377 -0
- mindroot/coreplugins/admin/static/js/registry-search-section.js +400 -0
- mindroot/coreplugins/admin/static/js/registry-search-section.js.bak +3 -0
- mindroot/coreplugins/admin/static/js/registry-settings.js +69 -0
- mindroot/coreplugins/admin/static/js/registry-shared-services.js +857 -0
- mindroot/coreplugins/admin/static/js/registry-simple-sections.js +85 -0
- mindroot/coreplugins/admin/static/js/secure-widget-manager.js +438 -0
- mindroot/coreplugins/admin/static/logo.png +0 -0
- mindroot/coreplugins/admin/templates/admin.jinja2 +275 -110
- mindroot/coreplugins/agent/Assistant/agent.json +27 -11
- mindroot/coreplugins/agent/agent.py +2 -2
- mindroot/coreplugins/agent/command_parser.py +25 -10
- mindroot/coreplugins/agent/templates/system.jinja2 +0 -12
- mindroot/coreplugins/chat/__init__.py +4 -1
- mindroot/coreplugins/chat/router.py +132 -20
- mindroot/coreplugins/chat/router_dedup_patch.py +20 -0
- mindroot/coreplugins/chat/services.py +31 -1
- mindroot/coreplugins/chat/static/css/action-fix.css +32 -0
- mindroot/coreplugins/chat/static/css/admin-custom.css +5 -3
- mindroot/coreplugins/chat/static/css/dark.css +24 -3
- mindroot/coreplugins/chat/static/css/default.css +24 -3
- mindroot/coreplugins/chat/static/css/main.css +1 -0
- mindroot/coreplugins/chat/static/js/action.js +137 -60
- mindroot/coreplugins/chat/static/js/chat-history.js +3 -0
- mindroot/coreplugins/chat/static/js/chat.js +59 -16
- mindroot/coreplugins/chat/static/js/chat.js.diff +221 -0
- mindroot/coreplugins/chat/static/js/chatform.js +2 -2
- mindroot/coreplugins/chat/static/site.webmanifest +1 -1
- mindroot/coreplugins/chat/templates/chat.jinja2 +3 -3
- mindroot/coreplugins/chat/widget_manager.py +139 -0
- mindroot/coreplugins/chat/widget_routes.py +287 -0
- mindroot/coreplugins/check_list/inject/admin.jinja2 +1 -1
- mindroot/coreplugins/email/__init__.py +2 -0
- mindroot/coreplugins/email/email_provider.py +2 -2
- mindroot/coreplugins/email/mod.py +100 -0
- mindroot/coreplugins/email/services.py +5 -3
- mindroot/coreplugins/email/smtp_handler.py +9 -3
- mindroot/coreplugins/email/test_email_service.py +75 -0
- mindroot/coreplugins/env_manager/mod.py +61 -25
- mindroot/coreplugins/home/router.py +37 -2
- mindroot/coreplugins/home/static/imgs/logo.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo.png.bak +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal2.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal_detailed.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal_python.png +0 -0
- mindroot/coreplugins/home/templates/home.jinja2 +15 -6
- mindroot/coreplugins/index/handlers/plugin_ops.py +1 -1
- mindroot/coreplugins/index/indices/default/index.json +6 -6
- mindroot/coreplugins/jwt_auth/middleware.py +47 -1
- mindroot/coreplugins/jwt_auth/mod.py +40 -17
- mindroot/coreplugins/l8n/__init__.py +6 -0
- mindroot/coreplugins/l8n/debug_loader.py +85 -0
- mindroot/coreplugins/l8n/debug_middleware.py +74 -0
- mindroot/coreplugins/l8n/l8n_constants.py +19 -0
- mindroot/coreplugins/l8n/language_detection.py +183 -0
- mindroot/coreplugins/l8n/middleware.py +151 -0
- mindroot/coreplugins/l8n/mod.py +277 -0
- mindroot/coreplugins/l8n/monkey_patch_to_delete.py +186 -0
- mindroot/coreplugins/l8n/test_enhanced.py +298 -0
- mindroot/coreplugins/l8n/test_l8n.py +95 -0
- mindroot/coreplugins/l8n/test_l8n_standalone.py +251 -0
- mindroot/coreplugins/l8n/test_middleware.py +272 -0
- mindroot/coreplugins/l8n/utils.py +232 -0
- mindroot/coreplugins/mcp_/__init__.py +14 -0
- mindroot/coreplugins/mcp_/catalog_commands.py +328 -0
- mindroot/coreplugins/mcp_/catalog_manager.py +263 -0
- mindroot/coreplugins/mcp_/dynamic_commands.py +154 -0
- mindroot/coreplugins/mcp_/mcp_manager.py +1031 -0
- mindroot/coreplugins/mcp_/mod.py +367 -0
- mindroot/coreplugins/mcp_/oauth_storage.py +144 -0
- mindroot/coreplugins/mcp_/server_installer.py +79 -0
- mindroot/coreplugins/mcp_/setup.py +26 -0
- mindroot/coreplugins/mcp_/test_dynamic_commands.py +134 -0
- mindroot/coreplugins/mcp_/testmcpclient.py +92 -0
- mindroot/coreplugins/persona/mod.py +12 -7
- mindroot/coreplugins/signup/templates/signup.jinja2 +1 -1
- mindroot/coreplugins/subscriptions/__init__.py +1 -0
- mindroot/coreplugins/subscriptions/mod.py +14 -3
- mindroot/coreplugins/subscriptions/router.py +3 -0
- mindroot/coreplugins/user_service/__init__.py +1 -2
- mindroot/coreplugins/user_service/admin_init.py +1 -0
- mindroot/coreplugins/user_service/email_service.py +72 -17
- mindroot/coreplugins/user_service/mod.py +10 -2
- mindroot/coreplugins/user_service/password_reset_service.py +180 -27
- mindroot/coreplugins/user_service/router.py +84 -22
- mindroot/lib/auth/api_key.py +28 -0
- mindroot/lib/cli/plugins.py +94 -0
- mindroot/lib/plugins/default_plugin_manifest.json +20 -0
- mindroot/lib/plugins/installation.py +5 -5
- mindroot/lib/plugins/l8n_static_handler.py +225 -0
- mindroot/lib/plugins/loader.py +33 -3
- mindroot/lib/plugins/loader_with_l8n.py +281 -0
- mindroot/lib/plugins/manifest.py +238 -17
- mindroot/lib/providers/commands.py +3 -1
- mindroot/lib/route_decorators.py +5 -5
- mindroot/lib/templates.py +183 -11
- mindroot/lib/utils/merge_arrays.py +1 -1
- mindroot/migrate.py +49 -0
- mindroot/registry/data_access.py +1 -1
- mindroot/server.py +47 -13
- mindroot/server_missing_normal_args.py +197 -0
- mindroot/server_prev.py +173 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/METADATA +7 -2
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/RECORD +147 -114
- mindroot/coreplugins/admin/static/favicon/about.txt +0 -6
- mindroot/coreplugins/admin/static/favicon/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/admin/static/favicon/apple-touch-icon.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon-16x16.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon-32x32.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon.ico +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/about.txt +0 -6
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon.ico +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/site.webmanifest +0 -1
- mindroot/coreplugins/admin/static/favicon/logo.png +0 -0
- mindroot/coreplugins/admin/static/favicon/site.webmanifest +0 -1
- mindroot/coreplugins/admin/static/js/backup/agent-editor.js +0 -186
- mindroot/coreplugins/admin/static/js/backup/agent-form.js +0 -1133
- mindroot/coreplugins/admin/static/js/backup/agent-list.js +0 -94
- mindroot/coreplugins/chat/static/favicon/about.txt +0 -6
- mindroot/coreplugins/chat/static/favicon/android-chrome-192x192.png +0 -0
- mindroot/coreplugins/chat/static/favicon/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/chat/static/favicon/apple-touch-icon.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon-16x16.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon-32x32.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon.ico +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/about.txt +0 -6
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon.ico +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/site.webmanifest +0 -1
- mindroot/coreplugins/chat/static/favicon/logo.png +0 -0
- mindroot/coreplugins/chat/static/favicon/site.webmanifest +0 -1
- mindroot/coreplugins/index/default.json +0 -76
- mindroot/coreplugins/user_service/file_trigger_service.py +0 -72
- mindroot/coreplugins/user_service/hooks.py +0 -23
- /mindroot/coreplugins/{admin/static/favicon/android-chrome-192x192.png → home/static/imgs/backuplogo.png} +0 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/WHEEL +0 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/entry_points.txt +0 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Test script to verify email service functionality.
|
|
4
|
+
Run this to test if email sending works with your configuration.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
sys.path.append('/files/mindroot/src')
|
|
11
|
+
|
|
12
|
+
from mindroot.coreplugins.email.mod import init_email_provider, send_email
|
|
13
|
+
|
|
14
|
+
async def test_email_service():
|
|
15
|
+
"""Test the email service with current environment configuration"""
|
|
16
|
+
print("Testing email service...")
|
|
17
|
+
|
|
18
|
+
# Check environment variables
|
|
19
|
+
smtp_email = os.getenv('SMTP_EMAIL')
|
|
20
|
+
smtp_password = os.getenv('SMTP_PASSWORD')
|
|
21
|
+
|
|
22
|
+
if not smtp_email or not smtp_password:
|
|
23
|
+
print("❌ Missing SMTP_EMAIL or SMTP_PASSWORD environment variables")
|
|
24
|
+
print("Please set these environment variables:")
|
|
25
|
+
print(" export SMTP_EMAIL='your-email@gmail.com'")
|
|
26
|
+
print(" export SMTP_PASSWORD='your-app-password'")
|
|
27
|
+
return False
|
|
28
|
+
|
|
29
|
+
print(f"📧 Using SMTP email: {smtp_email}")
|
|
30
|
+
|
|
31
|
+
# Initialize email provider
|
|
32
|
+
print("Initializing email provider...")
|
|
33
|
+
success = await init_email_provider()
|
|
34
|
+
|
|
35
|
+
if not success:
|
|
36
|
+
print("❌ Failed to initialize email provider")
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
print("✅ Email provider initialized successfully")
|
|
40
|
+
|
|
41
|
+
# Test sending email
|
|
42
|
+
test_email = input(f"Enter test email address (or press Enter to use {smtp_email}): ").strip()
|
|
43
|
+
if not test_email:
|
|
44
|
+
test_email = smtp_email
|
|
45
|
+
|
|
46
|
+
print(f"Sending test email to {test_email}...")
|
|
47
|
+
|
|
48
|
+
# Test HTML email
|
|
49
|
+
html_body = """
|
|
50
|
+
<html>
|
|
51
|
+
<body>
|
|
52
|
+
<h1>MindRoot Email Service Test</h1>
|
|
53
|
+
<p>This is a test email from MindRoot.</p>
|
|
54
|
+
<p><strong>HTML formatting works!</strong></p>
|
|
55
|
+
<p>If you can see this styled content, HTML emails are working correctly.</p>
|
|
56
|
+
</body>
|
|
57
|
+
</html>
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
result = await send_email(
|
|
61
|
+
to=test_email,
|
|
62
|
+
subject="MindRoot Email Service Test",
|
|
63
|
+
body=html_body # HTML will be auto-detected
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if result.get('success'):
|
|
67
|
+
print("✅ Test email sent successfully!")
|
|
68
|
+
print(f"Message ID: {result.get('message_id')}")
|
|
69
|
+
return True
|
|
70
|
+
else:
|
|
71
|
+
print(f"❌ Failed to send test email: {result.get('error')}")
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
if __name__ == "__main__":
|
|
75
|
+
asyncio.run(test_email_service())
|
|
@@ -22,13 +22,12 @@ def should_skip_directory(directory):
|
|
|
22
22
|
skip_dirs = [
|
|
23
23
|
'__pycache__',
|
|
24
24
|
'node_modules',
|
|
25
|
-
'static/js',
|
|
25
|
+
'static/js',
|
|
26
26
|
'static/css',
|
|
27
27
|
'venv',
|
|
28
28
|
'env',
|
|
29
29
|
'.env',
|
|
30
30
|
'virtualenv',
|
|
31
|
-
'site-packages',
|
|
32
31
|
'dist-packages',
|
|
33
32
|
'.git',
|
|
34
33
|
'.idea',
|
|
@@ -38,6 +37,14 @@ def should_skip_directory(directory):
|
|
|
38
37
|
'egg-info'
|
|
39
38
|
]
|
|
40
39
|
|
|
40
|
+
# Special handling for site-packages - only skip if it's not mindroot related
|
|
41
|
+
if 'site-packages' in directory:
|
|
42
|
+
# Allow mindroot core plugins in site-packages
|
|
43
|
+
if 'mindroot/coreplugins' in directory or 'mindroot/lib' in directory:
|
|
44
|
+
return False
|
|
45
|
+
# Skip other site-packages content
|
|
46
|
+
return True
|
|
47
|
+
|
|
41
48
|
# Check if any part of the path contains a directory to skip
|
|
42
49
|
path_parts = Path(directory).parts
|
|
43
50
|
for skip_dir in skip_dirs:
|
|
@@ -66,7 +73,7 @@ def scan_directory_for_env_vars(directory):
|
|
|
66
73
|
# Use grep to find os.environ references - much faster than parsing each file
|
|
67
74
|
cmd = [
|
|
68
75
|
'grep', '-r',
|
|
69
|
-
'-E', r"os\.environ(\.get\(|\[)",
|
|
76
|
+
'-E', r"(os\.environ(\.get\(|\[)|os\.getenv\(|getenv\()",
|
|
70
77
|
'--include=*.py',
|
|
71
78
|
'--exclude-dir=venv',
|
|
72
79
|
'--exclude-dir=env',
|
|
@@ -85,14 +92,24 @@ def scan_directory_for_env_vars(directory):
|
|
|
85
92
|
return env_vars
|
|
86
93
|
|
|
87
94
|
# Extract variable names using regex
|
|
88
|
-
|
|
89
|
-
|
|
95
|
+
patterns = [
|
|
96
|
+
r"os\.environ\.get\(['\"]([A-Za-z0-9_]+)['\"]", # os.environ.get('VAR_NAME')
|
|
97
|
+
r"os\.environ\[['\"]([A-Za-z0-9_]+)['\"]\]", # os.environ['VAR_NAME']
|
|
98
|
+
r"os\.getenv\(['\"]([A-Za-z0-9_]+)['\"]", # os.getenv('VAR_NAME')
|
|
99
|
+
r"(?<!os\.)getenv\(['\"]([A-Za-z0-9_]+)['\"]", # getenv('VAR_NAME') without os. prefix
|
|
100
|
+
]
|
|
90
101
|
|
|
91
102
|
for line in result.stdout.splitlines():
|
|
92
|
-
|
|
103
|
+
# Skip lines that are comments containing example patterns
|
|
104
|
+
if '# os.environ.get(' in line or '# os.environ[' in line or '# os.getenv(' in line:
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
for pattern in patterns:
|
|
93
108
|
for match in re.finditer(pattern, line):
|
|
94
109
|
var_name = match.group(1)
|
|
95
|
-
|
|
110
|
+
# Filter out obvious false positives
|
|
111
|
+
if var_name not in ['VAR_NAME', 'VARIABLE_NAME', 'ENV_VAR']:
|
|
112
|
+
env_vars.add(var_name)
|
|
96
113
|
|
|
97
114
|
except Exception as e:
|
|
98
115
|
print(f"Error scanning directory {directory}: {e}")
|
|
@@ -103,28 +120,38 @@ def scan_directory_for_env_vars(directory):
|
|
|
103
120
|
async def scan_env_vars(params=None, context=None):
|
|
104
121
|
"""Scan all enabled plugins for environment variable references.
|
|
105
122
|
|
|
123
|
+
Debug logs added to help troubleshoot path resolution and scanning.
|
|
124
|
+
|
|
106
125
|
Returns:
|
|
107
126
|
dict: Dictionary with plugin names as keys and environment variable info as values
|
|
108
127
|
"""
|
|
109
128
|
results = {}
|
|
110
129
|
all_env_vars = set()
|
|
111
130
|
|
|
131
|
+
print("[ENV_MANAGER DEBUG] Starting scan_env_vars")
|
|
132
|
+
print(f"[ENV_MANAGER DEBUG] Current working directory: {os.getcwd()}")
|
|
133
|
+
|
|
112
134
|
# Get all enabled plugins
|
|
113
135
|
enabled_plugins = list_enabled()
|
|
136
|
+
print(f"[ENV_MANAGER DEBUG] Found {len(enabled_plugins)} enabled plugins: {[name for name, cat in enabled_plugins]}")
|
|
114
137
|
|
|
115
138
|
for plugin_name, category in enabled_plugins:
|
|
116
139
|
plugin_path = get_plugin_path(plugin_name)
|
|
140
|
+
print(f"[ENV_MANAGER DEBUG] Plugin {plugin_name}: path = {plugin_path}")
|
|
117
141
|
if plugin_path:
|
|
118
142
|
# If plugin_path is a file, get its directory
|
|
119
143
|
if os.path.isfile(plugin_path):
|
|
120
144
|
plugin_path = os.path.dirname(plugin_path)
|
|
145
|
+
print(f"[ENV_MANAGER DEBUG] Plugin {plugin_name}: converted to directory = {plugin_path}")
|
|
121
146
|
|
|
122
147
|
# Skip scanning if this is a directory we should ignore
|
|
123
148
|
if should_skip_directory(plugin_path):
|
|
149
|
+
print(f"[ENV_MANAGER DEBUG] Plugin {plugin_name}: skipping directory {plugin_path}")
|
|
124
150
|
continue
|
|
125
151
|
|
|
126
152
|
# Scan the plugin directory for environment variable references
|
|
127
153
|
env_vars = scan_directory_for_env_vars(plugin_path)
|
|
154
|
+
print(f"[ENV_MANAGER DEBUG] Plugin {plugin_name}: found {len(env_vars)} env vars: {sorted(env_vars)}")
|
|
128
155
|
|
|
129
156
|
if env_vars:
|
|
130
157
|
results[plugin_name] = {
|
|
@@ -133,30 +160,35 @@ async def scan_env_vars(params=None, context=None):
|
|
|
133
160
|
'env_vars': list(env_vars)
|
|
134
161
|
}
|
|
135
162
|
all_env_vars.update(env_vars)
|
|
163
|
+
else:
|
|
164
|
+
print(f"[ENV_MANAGER DEBUG] Plugin {plugin_name}: no path found")
|
|
136
165
|
|
|
137
|
-
# Also scan the
|
|
138
|
-
core_env_vars = set()
|
|
166
|
+
# Also scan the lib directory (but not coreplugins since individual plugins are already scanned)
|
|
139
167
|
lib_path = os.path.dirname(lib.__file__)
|
|
140
|
-
mindroot_path = os.path.dirname(lib_path)
|
|
141
168
|
|
|
142
|
-
|
|
169
|
+
print(f"[ENV_MANAGER DEBUG] lib.__file__ = {lib.__file__}")
|
|
170
|
+
print(f"[ENV_MANAGER DEBUG] lib_path = {lib_path}")
|
|
171
|
+
|
|
172
|
+
# Scan lib directory for additional core variables
|
|
143
173
|
if os.path.isdir(lib_path):
|
|
174
|
+
print(f"[ENV_MANAGER DEBUG] Scanning lib directory: {lib_path}")
|
|
144
175
|
lib_vars = scan_directory_for_env_vars(lib_path)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
176
|
+
print(f"[ENV_MANAGER DEBUG] Lib vars found: {sorted(lib_vars)}")
|
|
177
|
+
|
|
178
|
+
if lib_vars:
|
|
179
|
+
results['lib'] = {
|
|
180
|
+
'plugin_name': 'lib',
|
|
181
|
+
'category': 'core',
|
|
182
|
+
'env_vars': sorted(list(lib_vars))
|
|
183
|
+
}
|
|
184
|
+
all_env_vars.update(lib_vars)
|
|
185
|
+
print(f"[ENV_MANAGER DEBUG] Added lib section to results")
|
|
186
|
+
else:
|
|
187
|
+
print(f"[ENV_MANAGER DEBUG] Lib directory not found: {lib_path}")
|
|
152
188
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
'category': 'core',
|
|
157
|
-
'env_vars': sorted(list(core_env_vars))
|
|
158
|
-
}
|
|
159
|
-
all_env_vars.update(core_env_vars)
|
|
189
|
+
# Note: We don't scan the entire coreplugins directory separately because
|
|
190
|
+
# individual core plugins are already being scanned above in the enabled_plugins loop.
|
|
191
|
+
# This prevents duplicate entries that would show up as "Multiple Plugins".
|
|
160
192
|
|
|
161
193
|
# Get current environment variables
|
|
162
194
|
current_env = {}
|
|
@@ -174,6 +206,10 @@ async def scan_env_vars(params=None, context=None):
|
|
|
174
206
|
# Add current environment variables to results
|
|
175
207
|
results['current_env'] = current_env
|
|
176
208
|
|
|
209
|
+
print(f"[ENV_MANAGER DEBUG] Results structure: {[(k, len(v.get('env_vars', [])) if isinstance(v, dict) and 'env_vars' in v else 'N/A') for k, v in results.items()]}")
|
|
210
|
+
|
|
211
|
+
print(f"[ENV_MANAGER DEBUG] Final results keys: {list(results.keys())}")
|
|
212
|
+
print(f"[ENV_MANAGER DEBUG] Total unique env vars: {len(all_env_vars)}")
|
|
177
213
|
return results
|
|
178
214
|
|
|
179
215
|
|
|
@@ -5,6 +5,8 @@ from lib.templates import render
|
|
|
5
5
|
from lib.route_decorators import add_public_static
|
|
6
6
|
import os
|
|
7
7
|
import glob
|
|
8
|
+
import json
|
|
9
|
+
from lib.providers.services import service_manager
|
|
8
10
|
from datetime import datetime
|
|
9
11
|
import time
|
|
10
12
|
|
|
@@ -18,7 +20,40 @@ add_public_static('/home/static/')
|
|
|
18
20
|
@router.get("/", response_class=HTMLResponse)
|
|
19
21
|
async def home(request: Request):
|
|
20
22
|
# Get all agent directories
|
|
21
|
-
agent_dirs = [
|
|
23
|
+
agent_dirs = []
|
|
24
|
+
|
|
25
|
+
# Check local agents
|
|
26
|
+
if os.path.exists("data/agents/local"):
|
|
27
|
+
agent_dirs.extend([agent for agent in os.listdir("data/agents/local") if os.path.isdir(os.path.join("data/agents/local", agent))])
|
|
28
|
+
|
|
29
|
+
# Check shared agents
|
|
30
|
+
if os.path.exists("data/agents/shared"):
|
|
31
|
+
shared_agents = [agent for agent in os.listdir("data/agents/shared") if os.path.isdir(os.path.join("data/agents/shared", agent))]
|
|
32
|
+
agent_dirs.extend(shared_agents)
|
|
33
|
+
|
|
34
|
+
# Get agent data with persona information
|
|
35
|
+
agents_with_personas = []
|
|
36
|
+
for agent_name in agent_dirs:
|
|
37
|
+
try:
|
|
38
|
+
agent_data = await service_manager.get_agent_data(agent_name)
|
|
39
|
+
# Get the original persona reference from the agent.json file directly
|
|
40
|
+
# to preserve registry paths like "registry/owner/name"
|
|
41
|
+
agent_file_path = f"data/agents/local/{agent_name}/agent.json"
|
|
42
|
+
if not os.path.exists(agent_file_path):
|
|
43
|
+
agent_file_path = f"data/agents/shared/{agent_name}/agent.json"
|
|
44
|
+
|
|
45
|
+
with open(agent_file_path, 'r') as f:
|
|
46
|
+
raw_agent_data = json.load(f)
|
|
47
|
+
persona_path = raw_agent_data.get('persona', agent_name)
|
|
48
|
+
|
|
49
|
+
agents_with_personas.append({
|
|
50
|
+
'name': agent_name,
|
|
51
|
+
'persona': persona_path,
|
|
52
|
+
'agent_data': agent_data # Include full agent data for template
|
|
53
|
+
})
|
|
54
|
+
except Exception as e:
|
|
55
|
+
# Fallback if agent data can't be loaded
|
|
56
|
+
agents_with_personas.append({'name': agent_name, 'persona': agent_name})
|
|
22
57
|
|
|
23
58
|
# Try to sort agents by last access time
|
|
24
59
|
agent_access_times = []
|
|
@@ -50,5 +85,5 @@ async def home(request: Request):
|
|
|
50
85
|
agents = [agent for agent, _ in agent_access_times]
|
|
51
86
|
|
|
52
87
|
user = request.state.user
|
|
53
|
-
html = await render('home', {"user": user, "request": request, "agents": agents })
|
|
88
|
+
html = await render('home', {"user": user, "request": request, "agents": agents, "agents_with_personas": agents_with_personas })
|
|
54
89
|
return HTMLResponse(html)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<link rel="stylesheet" href="/home/static/css/default.css">
|
|
17
17
|
<link rel="stylesheet" href="/home/static/css/home.css">
|
|
18
18
|
<link rel="stylesheet" href="/home/static/css/enhanced.css">
|
|
19
|
-
<link rel="icon" href="/
|
|
19
|
+
<link rel="icon" href="/imgs/logo.png">
|
|
20
20
|
{% endblock %}
|
|
21
21
|
|
|
22
22
|
{% block head_css_end %}
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
|
|
43
43
|
{% block body_main %}
|
|
44
44
|
<main class="agent-container">
|
|
45
|
-
<img src="/
|
|
45
|
+
<img src="/imgs/logo.png" alt="MindRoot Logo" class="logo">
|
|
46
46
|
|
|
47
47
|
<h1>MindRoot Agent Host</h1>
|
|
48
48
|
|
|
@@ -51,12 +51,21 @@
|
|
|
51
51
|
<h2>Click an Agent to Start a Chat Session:</h2>
|
|
52
52
|
|
|
53
53
|
<div class="agent-list" role="list">
|
|
54
|
-
{% for
|
|
55
|
-
<a href="/agent/{{
|
|
56
|
-
|
|
54
|
+
{% for agent_persona in agents_with_personas %}
|
|
55
|
+
<a href="/agent/{{ agent_persona.name }}" class="agent-link" role="listitem" target="_blank">
|
|
56
|
+
{% set persona_path = agent_persona.persona %}
|
|
57
|
+
{% set has_faceref = false %}
|
|
58
|
+
{% if agent_persona.agent_data and agent_persona.agent_data.persona and agent_persona.agent_data.persona.faceref %}
|
|
59
|
+
{% set has_faceref = true %}
|
|
60
|
+
{% endif %}
|
|
61
|
+
{% if has_faceref %}
|
|
62
|
+
<img src="/chat/personas/{{ persona_path }}/faceref.png" alt="{{ agent_persona.name }} avatar" class="agent-avatar" onerror="this.src='/chat/personas/{{ persona_path }}/avatar.png'; this.onerror=function(){this.src='/chat/static/assistant.png'}">
|
|
63
|
+
{% else %}
|
|
64
|
+
<img src="/chat/personas/{{ persona_path }}/avatar.png" alt="{{ agent_persona.name }} avatar" class="agent-avatar" onerror="this.src='/chat/static/assistant.png'">
|
|
65
|
+
{% endif %}
|
|
57
66
|
<div class="agent-info">
|
|
58
67
|
<span class="agent-status" aria-hidden="true"></span>
|
|
59
|
-
<span class="agent-name">{{
|
|
68
|
+
<span class="agent-name">{{ agent_persona.name | replace('_', ' ') }}</span>
|
|
60
69
|
</div>
|
|
61
70
|
</a>
|
|
62
71
|
{% endfor %}
|
|
@@ -12,7 +12,7 @@ logger = logging.getLogger(__name__)
|
|
|
12
12
|
async def get_installed_plugin_metadata(plugin_name: str) -> dict:
|
|
13
13
|
"""Get metadata from main plugin manifest"""
|
|
14
14
|
try:
|
|
15
|
-
manifest_path = Path('plugin_manifest.json')
|
|
15
|
+
manifest_path = Path('data/plugin_manifest.json')
|
|
16
16
|
logger.debug(f"Reading main plugin manifest from: {manifest_path}")
|
|
17
17
|
|
|
18
18
|
if not manifest_path.exists():
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
"swap_face"
|
|
165
165
|
],
|
|
166
166
|
"dependencies": [],
|
|
167
|
-
"
|
|
167
|
+
"github_url": "runvnc/ah_swapface"
|
|
168
168
|
},
|
|
169
169
|
{
|
|
170
170
|
"name": "History",
|
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
"stream_chat"
|
|
187
187
|
],
|
|
188
188
|
"dependencies": [],
|
|
189
|
-
"
|
|
189
|
+
"github_url": "runvnc/ah_openrouter"
|
|
190
190
|
},
|
|
191
191
|
{
|
|
192
192
|
"name": "RunPod SD",
|
|
@@ -201,7 +201,7 @@
|
|
|
201
201
|
"select_image_model"
|
|
202
202
|
],
|
|
203
203
|
"dependencies": [],
|
|
204
|
-
"
|
|
204
|
+
"github_url": "runvnc/ah_runpod_sd"
|
|
205
205
|
},
|
|
206
206
|
{
|
|
207
207
|
"name": "Browser Use",
|
|
@@ -229,14 +229,14 @@
|
|
|
229
229
|
],
|
|
230
230
|
|
|
231
231
|
"dependencies": [],
|
|
232
|
-
"
|
|
232
|
+
"github_url": "runvnc/mr_gemini"
|
|
233
233
|
},
|
|
234
234
|
{
|
|
235
235
|
"name": "Session Data",
|
|
236
236
|
"version": "1.0.0",
|
|
237
237
|
"description": "",
|
|
238
238
|
"source": "github",
|
|
239
|
-
"
|
|
239
|
+
"github_url": "runvnc/ah_session_data",
|
|
240
240
|
"commands": [
|
|
241
241
|
"session_data_update",
|
|
242
242
|
"session_data_del",
|
|
@@ -252,7 +252,7 @@
|
|
|
252
252
|
"version": "1.0.0",
|
|
253
253
|
"description": "",
|
|
254
254
|
"source": "github",
|
|
255
|
-
"
|
|
255
|
+
"github_url": "runvnc/mr_hud",
|
|
256
256
|
"commands": [],
|
|
257
257
|
"services": [],
|
|
258
258
|
"dependencies": [],
|
|
@@ -11,6 +11,7 @@ from lib.session_files import load_session_data
|
|
|
11
11
|
from lib.utils.debug import debug_box
|
|
12
12
|
import secrets
|
|
13
13
|
from pathlib import Path
|
|
14
|
+
import re
|
|
14
15
|
|
|
15
16
|
def get_or_create_jwt_secret():
|
|
16
17
|
secret_key = os.environ.get("JWT_SECRET_KEY", None)
|
|
@@ -85,6 +86,48 @@ def decode_token(token: str):
|
|
|
85
86
|
print("Invalid token")
|
|
86
87
|
return False
|
|
87
88
|
|
|
89
|
+
def path_matches_pattern(request_path: str, route_pattern: str) -> bool:
|
|
90
|
+
"""
|
|
91
|
+
Check if a request path matches a route pattern with parameters.
|
|
92
|
+
|
|
93
|
+
Examples:
|
|
94
|
+
- path_matches_pattern('/chat/embed/abc123', '/chat/embed/{token}') -> True
|
|
95
|
+
- path_matches_pattern('/chat/widget/xyz/session', '/chat/widget/{token}/session') -> True
|
|
96
|
+
- path_matches_pattern('/login', '/login') -> True
|
|
97
|
+
"""
|
|
98
|
+
# Handle exact matches first
|
|
99
|
+
if request_path == route_pattern:
|
|
100
|
+
return True
|
|
101
|
+
|
|
102
|
+
# Convert FastAPI route pattern to regex
|
|
103
|
+
# Replace {param} with regex pattern that matches any non-slash characters
|
|
104
|
+
regex_pattern = re.sub(r'\{[^}]+\}', r'[^/]+', route_pattern)
|
|
105
|
+
# Escape other regex special characters
|
|
106
|
+
regex_pattern = regex_pattern.replace('.', '\\.')
|
|
107
|
+
# Add start and end anchors
|
|
108
|
+
regex_pattern = f'^{regex_pattern}$'
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
return bool(re.match(regex_pattern, request_path))
|
|
112
|
+
except re.error:
|
|
113
|
+
# If regex compilation fails, fall back to exact match
|
|
114
|
+
return request_path == route_pattern
|
|
115
|
+
|
|
116
|
+
def is_public_route(request_path: str) -> bool:
|
|
117
|
+
"""
|
|
118
|
+
Check if a request path matches any registered public route pattern.
|
|
119
|
+
"""
|
|
120
|
+
# Check exact matches and pattern matches
|
|
121
|
+
for route_pattern in public_routes:
|
|
122
|
+
if path_matches_pattern(request_path, route_pattern):
|
|
123
|
+
return True
|
|
124
|
+
|
|
125
|
+
# Check special cases
|
|
126
|
+
if request_path.startswith('/reset-password'):
|
|
127
|
+
return True
|
|
128
|
+
|
|
129
|
+
return False
|
|
130
|
+
|
|
88
131
|
async def middleware(request: Request, call_next):
|
|
89
132
|
try:
|
|
90
133
|
print('-------------------------- auth middleware ----------------------------')
|
|
@@ -142,13 +185,16 @@ async def middleware(request: Request, call_next):
|
|
|
142
185
|
print("Error checking for static file", e)
|
|
143
186
|
pass
|
|
144
187
|
print("Did not find static file")
|
|
145
|
-
|
|
188
|
+
|
|
189
|
+
# Use the improved public route checking
|
|
190
|
+
if is_public_route(request.url.path):
|
|
146
191
|
print('Public route: ', request.url.path)
|
|
147
192
|
return await call_next(request)
|
|
148
193
|
elif any([request.url.path.startswith(path) for path in public_static]):
|
|
149
194
|
return await call_next(request)
|
|
150
195
|
else:
|
|
151
196
|
print('Not a public route: ', request.url.path)
|
|
197
|
+
print("public routes:", public_routes)
|
|
152
198
|
|
|
153
199
|
# Check for token in cookies first
|
|
154
200
|
token = request.cookies.get("access_token")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from lib.providers.hooks import hook
|
|
2
2
|
from lib.route_decorators import public_route, public_routes
|
|
3
|
-
from starlette.routing import Mount
|
|
3
|
+
from starlette.routing import Mount, Route
|
|
4
4
|
import json
|
|
5
5
|
print("--- Hello from JWT mod ---")
|
|
6
6
|
|
|
@@ -8,19 +8,42 @@ print("--- Hello from JWT mod ---")
|
|
|
8
8
|
async def startup(app, context):
|
|
9
9
|
print('Running startup hook')
|
|
10
10
|
print('Registering public routes:')
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
11
|
+
|
|
12
|
+
def register_route(route_path, route_obj):
|
|
13
|
+
"""Helper function to register a route if it's marked as public"""
|
|
14
|
+
if hasattr(route_obj, 'endpoint') and hasattr(route_obj.endpoint, '__public_route__'):
|
|
15
|
+
print(f"Found public route: {route_path}")
|
|
16
|
+
public_routes.add(route_path)
|
|
17
|
+
return True
|
|
18
|
+
return False
|
|
19
|
+
|
|
20
|
+
def process_routes(routes, path_prefix=""):
|
|
21
|
+
"""Recursively process routes and sub-routes"""
|
|
22
|
+
for route in routes:
|
|
23
|
+
if isinstance(route, Mount):
|
|
24
|
+
# Handle mounted sub-applications
|
|
25
|
+
mount_path = path_prefix + route.path.rstrip('/')
|
|
26
|
+
print(f"Processing mount: {mount_path}")
|
|
27
|
+
|
|
28
|
+
# Process sub-routes within the mount
|
|
29
|
+
if hasattr(route, 'routes'):
|
|
30
|
+
for sub_route in route.routes:
|
|
31
|
+
if isinstance(sub_route, Route):
|
|
32
|
+
full_path = mount_path + sub_route.path
|
|
33
|
+
if not register_route(full_path, sub_route):
|
|
34
|
+
print(f"Skipping private route: {full_path}")
|
|
35
|
+
else:
|
|
36
|
+
print(f"Skipping non-route in mount: {sub_route}")
|
|
37
|
+
|
|
38
|
+
elif isinstance(route, Route):
|
|
39
|
+
# Handle direct routes
|
|
40
|
+
full_path = path_prefix + route.path
|
|
41
|
+
if not register_route(full_path, route):
|
|
42
|
+
print(f"Skipping private route: {full_path}")
|
|
43
|
+
else:
|
|
44
|
+
print(f"Skipping unknown route type: {route}")
|
|
45
|
+
|
|
46
|
+
# Process all routes
|
|
47
|
+
process_routes(app.routes)
|
|
48
|
+
|
|
49
|
+
print(f"Final public routes registered: {public_routes}")
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Debug script to simulate the plugin loader behavior.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
import importlib
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
# Add the mindroot path
|
|
12
|
+
sys.path.insert(0, '/files/mindroot/src/mindroot')
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
print("Simulating plugin loader behavior...")
|
|
16
|
+
|
|
17
|
+
# Simulate what the loader does
|
|
18
|
+
plugin_name = 'l8n'
|
|
19
|
+
category = 'core'
|
|
20
|
+
|
|
21
|
+
# Get plugin path (simulating get_plugin_path)
|
|
22
|
+
plugin_dir = '/files/mindroot/src/mindroot/coreplugins/l8n'
|
|
23
|
+
print(f"Plugin directory: {plugin_dir}")
|
|
24
|
+
|
|
25
|
+
# Check for middleware.py
|
|
26
|
+
middleware_path = os.path.join(plugin_dir, 'middleware.py')
|
|
27
|
+
print(f"Middleware path: {middleware_path}")
|
|
28
|
+
print(f"Middleware exists: {os.path.exists(middleware_path)}")
|
|
29
|
+
|
|
30
|
+
if os.path.exists(middleware_path):
|
|
31
|
+
# Simulate get_plugin_import_path
|
|
32
|
+
plugin_import_path = f'coreplugins.{plugin_name}'
|
|
33
|
+
print(f"Plugin import path: {plugin_import_path}")
|
|
34
|
+
|
|
35
|
+
# Try to import the module (this is what the loader does)
|
|
36
|
+
print("\nAttempting to import module...")
|
|
37
|
+
try:
|
|
38
|
+
module = importlib.import_module(plugin_import_path)
|
|
39
|
+
print(f"✅ Module imported: {module}")
|
|
40
|
+
except ImportError as e:
|
|
41
|
+
print(f"First import failed: {e}")
|
|
42
|
+
try:
|
|
43
|
+
module = importlib.import_module(f"{plugin_import_path}.mod")
|
|
44
|
+
print(f"✅ Module imported via .mod: {module}")
|
|
45
|
+
except ImportError as e2:
|
|
46
|
+
print(f"❌ Both imports failed: {e2}")
|
|
47
|
+
raise
|
|
48
|
+
|
|
49
|
+
# Check if module has middleware
|
|
50
|
+
print(f"\nModule has middleware: {hasattr(module, 'middleware')}")
|
|
51
|
+
|
|
52
|
+
if hasattr(module, 'middleware'):
|
|
53
|
+
middleware_func = module.middleware
|
|
54
|
+
print(f"Middleware type: {type(middleware_func)}")
|
|
55
|
+
print(f"Middleware callable: {callable(middleware_func)}")
|
|
56
|
+
|
|
57
|
+
# This is what causes the error - let's check what we're actually getting
|
|
58
|
+
print(f"Middleware repr: {repr(middleware_func)}")
|
|
59
|
+
|
|
60
|
+
# Check if it's actually a function
|
|
61
|
+
import inspect
|
|
62
|
+
print(f"Is function: {inspect.isfunction(middleware_func)}")
|
|
63
|
+
print(f"Is coroutine function: {inspect.iscoroutinefunction(middleware_func)}")
|
|
64
|
+
|
|
65
|
+
if inspect.isfunction(middleware_func):
|
|
66
|
+
print(f"Function signature: {inspect.signature(middleware_func)}")
|
|
67
|
+
|
|
68
|
+
# Try to simulate what FastAPI does
|
|
69
|
+
print("\nSimulating FastAPI middleware registration...")
|
|
70
|
+
try:
|
|
71
|
+
# This is essentially what BaseHTTPMiddleware does
|
|
72
|
+
if callable(middleware_func):
|
|
73
|
+
print("✅ Middleware function is callable")
|
|
74
|
+
else:
|
|
75
|
+
print("❌ Middleware function is not callable")
|
|
76
|
+
except Exception as e:
|
|
77
|
+
print(f"❌ Error checking callable: {e}")
|
|
78
|
+
else:
|
|
79
|
+
print("❌ Module does not have middleware attribute")
|
|
80
|
+
print(f"Module attributes: {dir(module)}")
|
|
81
|
+
|
|
82
|
+
except Exception as e:
|
|
83
|
+
print(f"❌ Error during simulation: {e}")
|
|
84
|
+
import traceback
|
|
85
|
+
traceback.print_exc()
|