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.
Files changed (186) hide show
  1. mindroot/coreplugins/admin/__init__.py +3 -1
  2. mindroot/coreplugins/admin/agent_router.py +250 -7
  3. mindroot/coreplugins/admin/asset_manager.py +164 -0
  4. mindroot/coreplugins/admin/command_router.py +236 -1
  5. mindroot/coreplugins/admin/mcp_catalog_routes.py +156 -0
  6. mindroot/coreplugins/admin/mcp_publish_routes.py +450 -0
  7. mindroot/coreplugins/admin/mcp_registry_routes.py +495 -0
  8. mindroot/coreplugins/admin/mcp_routes.py +216 -0
  9. mindroot/coreplugins/admin/mod.py +62 -0
  10. mindroot/coreplugins/admin/oauth_callback_router.py +84 -0
  11. mindroot/coreplugins/admin/persona_handler.py +15 -6
  12. mindroot/coreplugins/admin/persona_router.py +158 -2
  13. mindroot/coreplugins/admin/plugin_manager.py +63 -0
  14. mindroot/coreplugins/admin/plugin_router.py +1 -1
  15. mindroot/coreplugins/admin/plugin_router_fixed.py +23 -0
  16. mindroot/coreplugins/admin/plugin_router_new_not_working.py +145 -0
  17. mindroot/coreplugins/admin/plugin_routes.py +114 -0
  18. mindroot/coreplugins/admin/registry_settings_routes.py +140 -0
  19. mindroot/coreplugins/admin/router.py +116 -15
  20. mindroot/coreplugins/admin/service_models.py +1 -1
  21. mindroot/coreplugins/admin/settings_router.py +1 -0
  22. mindroot/coreplugins/admin/static/css/admin-custom.css +357 -2
  23. mindroot/coreplugins/admin/static/css/dark.css +1 -0
  24. mindroot/coreplugins/admin/static/css/default.css +4 -0
  25. mindroot/coreplugins/admin/static/js/about-info.js +367 -0
  26. mindroot/coreplugins/admin/static/js/agent-form.js +83 -3
  27. mindroot/coreplugins/admin/static/js/api-key-script.js +307 -0
  28. mindroot/coreplugins/admin/static/js/mcp-manager.js +348 -0
  29. mindroot/coreplugins/admin/static/js/mcp-publisher.js +780 -0
  30. mindroot/coreplugins/admin/static/js/persona-editor.js +34 -5
  31. mindroot/coreplugins/admin/static/js/plugin-toggle.js +1 -1
  32. mindroot/coreplugins/admin/static/js/recommended-plugin-install.js +63 -0
  33. mindroot/coreplugins/admin/static/js/registry-auth-section.js +132 -0
  34. mindroot/coreplugins/admin/static/js/registry-manager-base.js +613 -0
  35. mindroot/coreplugins/admin/static/js/registry-manager-old.js +385 -0
  36. mindroot/coreplugins/admin/static/js/registry-manager-publish-old-delete.js +166 -0
  37. mindroot/coreplugins/admin/static/js/registry-manager.js +351 -0
  38. mindroot/coreplugins/admin/static/js/registry-publish-section.js +377 -0
  39. mindroot/coreplugins/admin/static/js/registry-search-section.js +400 -0
  40. mindroot/coreplugins/admin/static/js/registry-search-section.js.bak +3 -0
  41. mindroot/coreplugins/admin/static/js/registry-settings.js +69 -0
  42. mindroot/coreplugins/admin/static/js/registry-shared-services.js +857 -0
  43. mindroot/coreplugins/admin/static/js/registry-simple-sections.js +85 -0
  44. mindroot/coreplugins/admin/static/js/secure-widget-manager.js +438 -0
  45. mindroot/coreplugins/admin/static/logo.png +0 -0
  46. mindroot/coreplugins/admin/templates/admin.jinja2 +275 -110
  47. mindroot/coreplugins/agent/Assistant/agent.json +27 -11
  48. mindroot/coreplugins/agent/agent.py +2 -2
  49. mindroot/coreplugins/agent/command_parser.py +25 -10
  50. mindroot/coreplugins/agent/templates/system.jinja2 +0 -12
  51. mindroot/coreplugins/chat/__init__.py +4 -1
  52. mindroot/coreplugins/chat/router.py +132 -20
  53. mindroot/coreplugins/chat/router_dedup_patch.py +20 -0
  54. mindroot/coreplugins/chat/services.py +31 -1
  55. mindroot/coreplugins/chat/static/css/action-fix.css +32 -0
  56. mindroot/coreplugins/chat/static/css/admin-custom.css +5 -3
  57. mindroot/coreplugins/chat/static/css/dark.css +24 -3
  58. mindroot/coreplugins/chat/static/css/default.css +24 -3
  59. mindroot/coreplugins/chat/static/css/main.css +1 -0
  60. mindroot/coreplugins/chat/static/js/action.js +137 -60
  61. mindroot/coreplugins/chat/static/js/chat-history.js +3 -0
  62. mindroot/coreplugins/chat/static/js/chat.js +59 -16
  63. mindroot/coreplugins/chat/static/js/chat.js.diff +221 -0
  64. mindroot/coreplugins/chat/static/js/chatform.js +2 -2
  65. mindroot/coreplugins/chat/static/site.webmanifest +1 -1
  66. mindroot/coreplugins/chat/templates/chat.jinja2 +3 -3
  67. mindroot/coreplugins/chat/widget_manager.py +139 -0
  68. mindroot/coreplugins/chat/widget_routes.py +287 -0
  69. mindroot/coreplugins/check_list/inject/admin.jinja2 +1 -1
  70. mindroot/coreplugins/email/__init__.py +2 -0
  71. mindroot/coreplugins/email/email_provider.py +2 -2
  72. mindroot/coreplugins/email/mod.py +100 -0
  73. mindroot/coreplugins/email/services.py +5 -3
  74. mindroot/coreplugins/email/smtp_handler.py +9 -3
  75. mindroot/coreplugins/email/test_email_service.py +75 -0
  76. mindroot/coreplugins/env_manager/mod.py +61 -25
  77. mindroot/coreplugins/home/router.py +37 -2
  78. mindroot/coreplugins/home/static/imgs/logo.png +0 -0
  79. mindroot/coreplugins/home/static/imgs/logo.png.bak +0 -0
  80. mindroot/coreplugins/home/static/imgs/logo_teal.png +0 -0
  81. mindroot/coreplugins/home/static/imgs/logo_teal2.png +0 -0
  82. mindroot/coreplugins/home/static/imgs/logo_teal_detailed.png +0 -0
  83. mindroot/coreplugins/home/static/imgs/logo_teal_python.png +0 -0
  84. mindroot/coreplugins/home/templates/home.jinja2 +15 -6
  85. mindroot/coreplugins/index/handlers/plugin_ops.py +1 -1
  86. mindroot/coreplugins/index/indices/default/index.json +6 -6
  87. mindroot/coreplugins/jwt_auth/middleware.py +47 -1
  88. mindroot/coreplugins/jwt_auth/mod.py +40 -17
  89. mindroot/coreplugins/l8n/__init__.py +6 -0
  90. mindroot/coreplugins/l8n/debug_loader.py +85 -0
  91. mindroot/coreplugins/l8n/debug_middleware.py +74 -0
  92. mindroot/coreplugins/l8n/l8n_constants.py +19 -0
  93. mindroot/coreplugins/l8n/language_detection.py +183 -0
  94. mindroot/coreplugins/l8n/middleware.py +151 -0
  95. mindroot/coreplugins/l8n/mod.py +277 -0
  96. mindroot/coreplugins/l8n/monkey_patch_to_delete.py +186 -0
  97. mindroot/coreplugins/l8n/test_enhanced.py +298 -0
  98. mindroot/coreplugins/l8n/test_l8n.py +95 -0
  99. mindroot/coreplugins/l8n/test_l8n_standalone.py +251 -0
  100. mindroot/coreplugins/l8n/test_middleware.py +272 -0
  101. mindroot/coreplugins/l8n/utils.py +232 -0
  102. mindroot/coreplugins/mcp_/__init__.py +14 -0
  103. mindroot/coreplugins/mcp_/catalog_commands.py +328 -0
  104. mindroot/coreplugins/mcp_/catalog_manager.py +263 -0
  105. mindroot/coreplugins/mcp_/dynamic_commands.py +154 -0
  106. mindroot/coreplugins/mcp_/mcp_manager.py +1031 -0
  107. mindroot/coreplugins/mcp_/mod.py +367 -0
  108. mindroot/coreplugins/mcp_/oauth_storage.py +144 -0
  109. mindroot/coreplugins/mcp_/server_installer.py +79 -0
  110. mindroot/coreplugins/mcp_/setup.py +26 -0
  111. mindroot/coreplugins/mcp_/test_dynamic_commands.py +134 -0
  112. mindroot/coreplugins/mcp_/testmcpclient.py +92 -0
  113. mindroot/coreplugins/persona/mod.py +12 -7
  114. mindroot/coreplugins/signup/templates/signup.jinja2 +1 -1
  115. mindroot/coreplugins/subscriptions/__init__.py +1 -0
  116. mindroot/coreplugins/subscriptions/mod.py +14 -3
  117. mindroot/coreplugins/subscriptions/router.py +3 -0
  118. mindroot/coreplugins/user_service/__init__.py +1 -2
  119. mindroot/coreplugins/user_service/admin_init.py +1 -0
  120. mindroot/coreplugins/user_service/email_service.py +72 -17
  121. mindroot/coreplugins/user_service/mod.py +10 -2
  122. mindroot/coreplugins/user_service/password_reset_service.py +180 -27
  123. mindroot/coreplugins/user_service/router.py +84 -22
  124. mindroot/lib/auth/api_key.py +28 -0
  125. mindroot/lib/cli/plugins.py +94 -0
  126. mindroot/lib/plugins/default_plugin_manifest.json +20 -0
  127. mindroot/lib/plugins/installation.py +5 -5
  128. mindroot/lib/plugins/l8n_static_handler.py +225 -0
  129. mindroot/lib/plugins/loader.py +33 -3
  130. mindroot/lib/plugins/loader_with_l8n.py +281 -0
  131. mindroot/lib/plugins/manifest.py +238 -17
  132. mindroot/lib/providers/commands.py +3 -1
  133. mindroot/lib/route_decorators.py +5 -5
  134. mindroot/lib/templates.py +183 -11
  135. mindroot/lib/utils/merge_arrays.py +1 -1
  136. mindroot/migrate.py +49 -0
  137. mindroot/registry/data_access.py +1 -1
  138. mindroot/server.py +47 -13
  139. mindroot/server_missing_normal_args.py +197 -0
  140. mindroot/server_prev.py +173 -0
  141. {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/METADATA +7 -2
  142. {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/RECORD +147 -114
  143. mindroot/coreplugins/admin/static/favicon/about.txt +0 -6
  144. mindroot/coreplugins/admin/static/favicon/android-chrome-512x512.png +0 -0
  145. mindroot/coreplugins/admin/static/favicon/apple-touch-icon.png +0 -0
  146. mindroot/coreplugins/admin/static/favicon/favicon-16x16.png +0 -0
  147. mindroot/coreplugins/admin/static/favicon/favicon-32x32.png +0 -0
  148. mindroot/coreplugins/admin/static/favicon/favicon.ico +0 -0
  149. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/about.txt +0 -6
  150. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
  151. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
  152. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
  153. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
  154. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
  155. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon.ico +0 -0
  156. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/site.webmanifest +0 -1
  157. mindroot/coreplugins/admin/static/favicon/logo.png +0 -0
  158. mindroot/coreplugins/admin/static/favicon/site.webmanifest +0 -1
  159. mindroot/coreplugins/admin/static/js/backup/agent-editor.js +0 -186
  160. mindroot/coreplugins/admin/static/js/backup/agent-form.js +0 -1133
  161. mindroot/coreplugins/admin/static/js/backup/agent-list.js +0 -94
  162. mindroot/coreplugins/chat/static/favicon/about.txt +0 -6
  163. mindroot/coreplugins/chat/static/favicon/android-chrome-192x192.png +0 -0
  164. mindroot/coreplugins/chat/static/favicon/android-chrome-512x512.png +0 -0
  165. mindroot/coreplugins/chat/static/favicon/apple-touch-icon.png +0 -0
  166. mindroot/coreplugins/chat/static/favicon/favicon-16x16.png +0 -0
  167. mindroot/coreplugins/chat/static/favicon/favicon-32x32.png +0 -0
  168. mindroot/coreplugins/chat/static/favicon/favicon.ico +0 -0
  169. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/about.txt +0 -6
  170. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
  171. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
  172. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
  173. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
  174. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
  175. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon.ico +0 -0
  176. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/site.webmanifest +0 -1
  177. mindroot/coreplugins/chat/static/favicon/logo.png +0 -0
  178. mindroot/coreplugins/chat/static/favicon/site.webmanifest +0 -1
  179. mindroot/coreplugins/index/default.json +0 -76
  180. mindroot/coreplugins/user_service/file_trigger_service.py +0 -72
  181. mindroot/coreplugins/user_service/hooks.py +0 -23
  182. /mindroot/coreplugins/{admin/static/favicon/android-chrome-192x192.png → home/static/imgs/backuplogo.png} +0 -0
  183. {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/WHEEL +0 -0
  184. {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/entry_points.txt +0 -0
  185. {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/licenses/LICENSE +0 -0
  186. {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/top_level.txt +0 -0
mindroot/server.py CHANGED
@@ -8,12 +8,18 @@ from .lib.chatcontext import ChatContext
8
8
  from .lib.providers.hooks import hook_manager
9
9
  from .lib.utils.debug import debug_box
10
10
  import asyncio
11
+ import sys
11
12
  import uvicorn
12
13
  from termcolor import colored
13
14
  import socket
14
15
  from fastapi.middleware.cors import CORSMiddleware
15
16
  from starlette.middleware.base import BaseHTTPMiddleware
17
+ from .lib.cli.plugins import install_plugins_from_cli
16
18
  from dotenv import load_dotenv
19
+ from .migrate import run_migrations
20
+
21
+ # import for file copy
22
+ from shutil import copyfile
17
23
 
18
24
  # Load environment variables from .env file at the start
19
25
  # Set override=True to make .env variables override existing environment variables
@@ -21,11 +27,25 @@ load_dotenv(override=True)
21
27
 
22
28
  def parse_args():
23
29
  import argparse
24
- parser = argparse.ArgumentParser(description="Run the server")
30
+ parser = argparse.ArgumentParser(description="Run the MindRoot server or manage plugins.", allow_abbrev=False)
31
+
32
+ # Server arguments are top-level
25
33
  parser.add_argument("-p", "--port", type=int, help="Port to run the server on")
26
- # need to include optional admin-user and admin-password
27
34
  parser.add_argument("-u", "--admin-user", type=str, help="Admin username")
28
35
  parser.add_argument("-pw", "--admin-password", type=str, help="Admin password")
36
+
37
+ subparsers = parser.add_subparsers(dest='command', help='sub-command help')
38
+
39
+ # Explicit 'server' command for clarity in help, but it's the default action
40
+ server_parser = subparsers.add_parser('server', help='Run the web server (default action)')
41
+
42
+ # Plugin command group
43
+ plugin_parser = subparsers.add_parser('plugin', help='Manage plugins')
44
+ plugin_subparsers = plugin_parser.add_subparsers(dest='plugin_command', required=True)
45
+ install_parser = plugin_subparsers.add_parser('install', help='Install or update one or more plugins')
46
+ install_parser.add_argument('plugins', nargs='+', help='List of plugins to install (e.g., runvnc/plugin-name)')
47
+ install_parser.add_argument('--reinstall', action='store_true', help='Force reinstall of the plugin if it already exists.')
48
+
29
49
  return parser.parse_args()
30
50
 
31
51
  def get_project_root():
@@ -35,6 +55,7 @@ def get_project_root():
35
55
  def create_directories():
36
56
  root = get_project_root()
37
57
  directories = [
58
+ "data",
38
59
  "imgs",
39
60
  "models",
40
61
  "models/face",
@@ -66,10 +87,13 @@ async def setup_app_internal(app_):
66
87
  app = app_
67
88
 
68
89
  root = get_project_root()
90
+ source_root = Path(__file__).parent
69
91
  await plugins.load(app=app)
70
92
  app.mount("/static", StaticFiles(directory=str(root / "static"), follow_symlink=True), name="static")
71
93
  app.mount("/imgs", StaticFiles(directory=str(root / "imgs"), follow_symlink=True), name="imgs")
72
-
94
+ if not os.path.exists(root / "imgs/logo.png"):
95
+ print(colored("No logo found, copying default logo from coreplugins", "yellow"))
96
+ copyfile(str(source_root / "coreplugins/home/static/imgs/logo.png"), str(root / "imgs/logo.png"))
73
97
  return app
74
98
 
75
99
  def is_port_in_use(port):
@@ -95,28 +119,38 @@ class HeaderMiddleware(BaseHTTPMiddleware):
95
119
 
96
120
  # Add security headers
97
121
  response.headers["X-Content-Type-Options"] = "nosniff"
98
- response.headers["X-Frame-Options"] = "SAMEORIGIN"
122
+
123
+ #chat widgets don't work if we do this
124
+ if os.environ.get('MR_X_FRAME_SAMEORIGIN', 'false').lower() == 'true':
125
+ response.headers["X-Frame-Options"] = "SAMEORIGIN"
126
+
99
127
  response.headers["X-XSS-Protection"] = "1; mode=block"
100
128
 
101
129
  return response
102
130
 
103
131
  def main():
104
132
  global app
133
+
134
+ # Run migrations first, before anything else
135
+ run_migrations()
136
+
137
+ args = parse_args()
105
138
 
106
- cmd_args = parse_args()
107
- # save ALL parsed args in app state
139
+ # If the command is 'plugin', handle it and exit.
140
+ if args.command == 'plugin':
141
+ if args.plugin_command == 'install':
142
+ asyncio.run(install_plugins_from_cli(args.plugins, reinstall=args.reinstall))
143
+ sys.exit(0)
144
+
145
+ # Default action: run the server. The server arguments are on the main 'args' object.
146
+ cmd_args = args
108
147
  port = 8010
109
148
  if cmd_args.port:
110
149
  port = cmd_args.port
111
150
  else:
112
- cmd_args.port = port
113
-
114
- app = FastAPI()
151
+ cmd_args.port = port
115
152
 
116
- #app.add_middleware(
117
- # CORSMiddleware,
118
- # allow_origins=["*"] # This one line is all you need to allow all origins
119
- #)
153
+ app = FastAPI()
120
154
 
121
155
  app.state.cmd_args = cmd_args
122
156
 
@@ -0,0 +1,197 @@
1
+ from fastapi import FastAPI, Response, Request
2
+ from fastapi.staticfiles import StaticFiles
3
+ from fastapi.templating import Jinja2Templates
4
+ import os
5
+ from pathlib import Path
6
+ from .lib import plugins
7
+ from .lib.chatcontext import ChatContext
8
+ from .lib.providers.hooks import hook_manager
9
+ from .lib.utils.debug import debug_box
10
+ import asyncio
11
+ import uvicorn
12
+ import sys
13
+ from termcolor import colored
14
+ import socket
15
+ from fastapi.middleware.cors import CORSMiddleware
16
+ from starlette.middleware.base import BaseHTTPMiddleware
17
+ from .lib.cli.plugins import install_plugins_from_cli
18
+ from dotenv import load_dotenv
19
+ from .migrate import run_migrations
20
+
21
+ # import for file copy
22
+ from shutil import copyfile
23
+
24
+ # Load environment variables from .env file at the start
25
+ # Set override=True to make .env variables override existing environment variables
26
+ load_dotenv(override=True)
27
+
28
+ def parse_args():
29
+ import argparse
30
+ parser = argparse.ArgumentParser(description="Run the server")
31
+ subparsers = parser.add_subparsers(dest='command', help='sub-command help')
32
+
33
+ # Server command (default)
34
+ server_parser = subparsers.add_parser('server', help='Run the web server (default)')
35
+ server_parser.add_argument("-p", "--port", type=int, help="Port to run the server on")
36
+ server_parser.add_argument("-u", "--admin-user", type=str, help="Admin username")
37
+ server_parser.add_argument("-pw", "--admin-password", type=str, help="Admin password")
38
+
39
+ # Plugin command
40
+ plugin_parser = subparsers.add_parser('plugin', help='Manage plugins')
41
+ plugin_subparsers = plugin_parser.add_subparsers(dest='plugin_command', required=True)
42
+ install_parser = plugin_subparsers.add_parser('install', help='Install one or more plugins')
43
+ install_parser.add_argument('plugins', nargs='+', help='List of plugins to install (e.g., runvnc/plugin-name or pypi-package-name)')
44
+
45
+ return parser.parse_args()
46
+
47
+ def get_project_root():
48
+ return Path(os.getcwd())
49
+ #return Path(__file__).parent
50
+
51
+ def create_directories():
52
+ root = get_project_root()
53
+ directories = [
54
+ "data",
55
+ "imgs",
56
+ "models",
57
+ "models/face",
58
+ "models/llm",
59
+ "static/personas",
60
+ "personas",
61
+ "personas/local",
62
+ "personas/shared",
63
+ "data/sessions"
64
+ ]
65
+ chatlog_dir = os.environ.get('CHATLOG_DIR', 'data/chat')
66
+ directories.append(chatlog_dir)
67
+
68
+ for directory in directories:
69
+ (root / directory).mkdir(parents=True, exist_ok=True)
70
+
71
+ create_directories()
72
+
73
+ import mimetypes
74
+ mimetypes.add_type('application/javascript', '.js')
75
+ mimetypes.add_type('text/css', '.css')
76
+
77
+ templates = None
78
+ app = None
79
+ failed_plugins = []
80
+
81
+ async def setup_app_internal(app_):
82
+ global app, templates
83
+ app = app_
84
+
85
+ root = get_project_root()
86
+ source_root = Path(__file__).parent
87
+ await plugins.load(app=app)
88
+ app.mount("/static", StaticFiles(directory=str(root / "static"), follow_symlink=True), name="static")
89
+ app.mount("/imgs", StaticFiles(directory=str(root / "imgs"), follow_symlink=True), name="imgs")
90
+ if not os.path.exists(root / "imgs/logo.png"):
91
+ print(colored("No logo found, copying default logo from coreplugins", "yellow"))
92
+ copyfile(str(source_root / "coreplugins/home/static/imgs/logo.png"), str(root / "imgs/logo.png"))
93
+ return app
94
+
95
+ def is_port_in_use(port):
96
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
97
+ try:
98
+ s.bind(('0.0.0.0', port))
99
+ return False
100
+ except socket.error:
101
+ return True
102
+
103
+ def find_available_port(start_port=8010, max_attempts=100):
104
+ port = start_port
105
+ while port < start_port + max_attempts:
106
+ if not is_port_in_use(port):
107
+ return port
108
+ port += 1
109
+ raise RuntimeError(f"Could not find an available port after {max_attempts} attempts")
110
+
111
+ class HeaderMiddleware(BaseHTTPMiddleware):
112
+ async def dispatch(self, request: Request, call_next):
113
+ # First get the response from other middleware and routes
114
+ response = await call_next(request)
115
+
116
+ # Add security headers
117
+ response.headers["X-Content-Type-Options"] = "nosniff"
118
+
119
+ #chat widgets don't work if we do this
120
+ if os.environ.get('MR_X_FRAME_SAMEORIGIN', 'false').lower() == 'true':
121
+ response.headers["X-Frame-Options"] = "SAMEORIGIN"
122
+
123
+ response.headers["X-XSS-Protection"] = "1; mode=block"
124
+
125
+ return response
126
+
127
+ def main():
128
+ global app
129
+
130
+ # Run migrations first, before anything else
131
+ run_migrations()
132
+
133
+ args = parse_args()
134
+
135
+ # If no command is specified, default to 'server'
136
+ if args.command is None:
137
+ args.command = 'server'
138
+
139
+ if args.command == 'plugin' and args.plugin_command == 'install':
140
+ asyncio.run(install_plugins_from_cli(args.plugins))
141
+ sys.exit(0)
142
+
143
+ # Proceed with server startup
144
+ cmd_args = args
145
+ port = 8010
146
+ if cmd_args.port:
147
+ port = cmd_args.port
148
+ else:
149
+ # Add a default port to the args namespace if not provided
150
+ # to avoid AttributeError later.
151
+ setattr(cmd_args, 'port', port)
152
+
153
+ app = FastAPI()
154
+
155
+ #app.add_middleware(
156
+ # CORSMiddleware,
157
+ # allow_origins=["*"] # This one line is all you need to allow all origins
158
+ #)
159
+
160
+ app.state.cmd_args = cmd_args
161
+
162
+ debug_box("pre_load")
163
+ loop = asyncio.get_event_loop()
164
+ loop.run_until_complete(plugins.pre_load(app)) # middleware
165
+
166
+ debug_box("finished with pre_load, now calling uvicorn.run")
167
+
168
+ @app.on_event("startup")
169
+ async def setup_app():
170
+ global app
171
+ await setup_app_internal(app)
172
+ print(colored("Plugin setup complete", "green"))
173
+
174
+ @app.on_event("shutdown")
175
+ async def shutdown_event():
176
+ print("Shutting down MindRoot")
177
+ hook_manager.eject()
178
+
179
+ app.add_middleware(
180
+ CORSMiddleware,
181
+ allow_origins=["*"], # Replace with your specific origins for production
182
+ allow_credentials=True,
183
+ allow_methods=["*"], # Or specify: ["GET", "POST", "PUT", "DELETE", etc.]
184
+ allow_headers=["*"], # Or specify required headers
185
+ expose_headers=["*"] # Headers that browsers are allowed to access
186
+ )
187
+
188
+ app.add_middleware(HeaderMiddleware)
189
+
190
+ try:
191
+ print(colored(f"Starting server on port {port}", "green"))
192
+ uvicorn.run(app, host="0.0.0.0", port=port, lifespan="on", timeout_graceful_shutdown=2)
193
+ except Exception as e:
194
+ print(colored(f"Error starting server: {str(e)}", "red"))
195
+
196
+ if __name__ == "__main__":
197
+ main()
@@ -0,0 +1,173 @@
1
+ from fastapi import FastAPI, Response, Request
2
+ from fastapi.staticfiles import StaticFiles
3
+ from fastapi.templating import Jinja2Templates
4
+ import os
5
+ from pathlib import Path
6
+ from .lib import plugins
7
+ from .lib.chatcontext import ChatContext
8
+ from .lib.providers.hooks import hook_manager
9
+ from .lib.utils.debug import debug_box
10
+ import asyncio
11
+ import uvicorn
12
+ from termcolor import colored
13
+ import socket
14
+ from fastapi.middleware.cors import CORSMiddleware
15
+ from starlette.middleware.base import BaseHTTPMiddleware
16
+ from dotenv import load_dotenv
17
+ from .migrate import run_migrations
18
+
19
+ # import for file copy
20
+ from shutil import copyfile
21
+
22
+ # Load environment variables from .env file at the start
23
+ # Set override=True to make .env variables override existing environment variables
24
+ load_dotenv(override=True)
25
+
26
+ def parse_args():
27
+ import argparse
28
+ parser = argparse.ArgumentParser(description="Run the server")
29
+ parser.add_argument("-p", "--port", type=int, help="Port to run the server on")
30
+ # need to include optional admin-user and admin-password
31
+ parser.add_argument("-u", "--admin-user", type=str, help="Admin username")
32
+ parser.add_argument("-pw", "--admin-password", type=str, help="Admin password")
33
+ return parser.parse_args()
34
+
35
+ def get_project_root():
36
+ return Path(os.getcwd())
37
+ #return Path(__file__).parent
38
+
39
+ def create_directories():
40
+ root = get_project_root()
41
+ directories = [
42
+ "data",
43
+ "imgs",
44
+ "models",
45
+ "models/face",
46
+ "models/llm",
47
+ "static/personas",
48
+ "personas",
49
+ "personas/local",
50
+ "personas/shared",
51
+ "data/sessions"
52
+ ]
53
+ chatlog_dir = os.environ.get('CHATLOG_DIR', 'data/chat')
54
+ directories.append(chatlog_dir)
55
+
56
+ for directory in directories:
57
+ (root / directory).mkdir(parents=True, exist_ok=True)
58
+
59
+ create_directories()
60
+
61
+ import mimetypes
62
+ mimetypes.add_type('application/javascript', '.js')
63
+ mimetypes.add_type('text/css', '.css')
64
+
65
+ templates = None
66
+ app = None
67
+ failed_plugins = []
68
+
69
+ async def setup_app_internal(app_):
70
+ global app, templates
71
+ app = app_
72
+
73
+ root = get_project_root()
74
+ source_root = Path(__file__).parent
75
+ await plugins.load(app=app)
76
+ app.mount("/static", StaticFiles(directory=str(root / "static"), follow_symlink=True), name="static")
77
+ app.mount("/imgs", StaticFiles(directory=str(root / "imgs"), follow_symlink=True), name="imgs")
78
+ if not os.path.exists(root / "imgs/logo.png"):
79
+ print(colored("No logo found, copying default logo from coreplugins", "yellow"))
80
+ copyfile(str(source_root / "coreplugins/home/static/imgs/logo.png"), str(root / "imgs/logo.png"))
81
+ return app
82
+
83
+ def is_port_in_use(port):
84
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
85
+ try:
86
+ s.bind(('0.0.0.0', port))
87
+ return False
88
+ except socket.error:
89
+ return True
90
+
91
+ def find_available_port(start_port=8010, max_attempts=100):
92
+ port = start_port
93
+ while port < start_port + max_attempts:
94
+ if not is_port_in_use(port):
95
+ return port
96
+ port += 1
97
+ raise RuntimeError(f"Could not find an available port after {max_attempts} attempts")
98
+
99
+ class HeaderMiddleware(BaseHTTPMiddleware):
100
+ async def dispatch(self, request: Request, call_next):
101
+ # First get the response from other middleware and routes
102
+ response = await call_next(request)
103
+
104
+ # Add security headers
105
+ response.headers["X-Content-Type-Options"] = "nosniff"
106
+
107
+ #chat widgets don't work if we do this
108
+ if os.environ.get('MR_X_FRAME_SAMEORIGIN', 'false').lower() == 'true':
109
+ response.headers["X-Frame-Options"] = "SAMEORIGIN"
110
+
111
+ response.headers["X-XSS-Protection"] = "1; mode=block"
112
+
113
+ return response
114
+
115
+ def main():
116
+ global app
117
+
118
+ # Run migrations first, before anything else
119
+ run_migrations()
120
+
121
+ cmd_args = parse_args()
122
+ # save ALL parsed args in app state
123
+ port = 8010
124
+ if cmd_args.port:
125
+ port = cmd_args.port
126
+ else:
127
+ cmd_args.port = port
128
+
129
+ app = FastAPI()
130
+
131
+ #app.add_middleware(
132
+ # CORSMiddleware,
133
+ # allow_origins=["*"] # This one line is all you need to allow all origins
134
+ #)
135
+
136
+ app.state.cmd_args = cmd_args
137
+
138
+ debug_box("pre_load")
139
+ loop = asyncio.get_event_loop()
140
+ loop.run_until_complete(plugins.pre_load(app)) # middleware
141
+
142
+ debug_box("finished with pre_load, now calling uvicorn.run")
143
+
144
+ @app.on_event("startup")
145
+ async def setup_app():
146
+ global app
147
+ await setup_app_internal(app)
148
+ print(colored("Plugin setup complete", "green"))
149
+
150
+ @app.on_event("shutdown")
151
+ async def shutdown_event():
152
+ print("Shutting down MindRoot")
153
+ hook_manager.eject()
154
+
155
+ app.add_middleware(
156
+ CORSMiddleware,
157
+ allow_origins=["*"], # Replace with your specific origins for production
158
+ allow_credentials=True,
159
+ allow_methods=["*"], # Or specify: ["GET", "POST", "PUT", "DELETE", etc.]
160
+ allow_headers=["*"], # Or specify required headers
161
+ expose_headers=["*"] # Headers that browsers are allowed to access
162
+ )
163
+
164
+ app.add_middleware(HeaderMiddleware)
165
+
166
+ try:
167
+ print(colored(f"Starting server on port {port}", "green"))
168
+ uvicorn.run(app, host="0.0.0.0", port=port, lifespan="on", timeout_graceful_shutdown=2)
169
+ except Exception as e:
170
+ print(colored(f"Error starting server: {str(e)}", "red"))
171
+
172
+ if __name__ == "__main__":
173
+ main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mindroot
3
- Version: 9.2.0
3
+ Version: 9.5.0
4
4
  Summary: MindRoot AI Agent Framework
5
5
  Requires-Python: >=3.9
6
6
  License-File: LICENSE
@@ -18,7 +18,6 @@ Requires-Dist: PyJWT
18
18
  Requires-Dist: pluggy
19
19
  Requires-Dist: sse_starlette
20
20
  Requires-Dist: partial-json-parser
21
- Requires-Dist: pydantic
22
21
  Requires-Dist: setuptools
23
22
  Requires-Dist: requests
24
23
  Requires-Dist: aiohttp
@@ -33,4 +32,10 @@ Requires-Dist: python-dotenv
33
32
  Requires-Dist: google-auth
34
33
  Requires-Dist: google-auth-oauthlib
35
34
  Requires-Dist: google-auth-httplib2
35
+ Requires-Dist: chardet
36
+ Requires-Dist: mcp>=1.12.3
37
+ Requires-Dist: httpx>=0.24.0
38
+ Requires-Dist: pydantic>=2.0.0
39
+ Requires-Dist: aiofiles>=23.0.0
40
+ Requires-Dist: uv>=0.7.0
36
41
  Dynamic: license-file