open-swarm 0.1.1745274976__py3-none-any.whl → 0.1.1748636259__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 (295) hide show
  1. open_swarm-0.1.1748636259.dist-info/METADATA +188 -0
  2. open_swarm-0.1.1748636259.dist-info/RECORD +82 -0
  3. {open_swarm-0.1.1745274976.dist-info → open_swarm-0.1.1748636259.dist-info}/WHEEL +2 -1
  4. open_swarm-0.1.1748636259.dist-info/entry_points.txt +3 -0
  5. open_swarm-0.1.1748636259.dist-info/top_level.txt +1 -0
  6. swarm/agent/agent.py +49 -0
  7. swarm/auth.py +48 -113
  8. swarm/consumers.py +0 -19
  9. swarm/extensions/blueprint/__init__.py +16 -30
  10. swarm/{core → extensions/blueprint}/agent_utils.py +1 -1
  11. swarm/extensions/blueprint/blueprint_base.py +458 -0
  12. swarm/extensions/blueprint/blueprint_discovery.py +112 -0
  13. swarm/extensions/blueprint/output_utils.py +95 -0
  14. swarm/{core → extensions/blueprint}/spinner.py +21 -30
  15. swarm/extensions/cli/cli_args.py +0 -6
  16. swarm/extensions/cli/commands/blueprint_management.py +9 -47
  17. swarm/extensions/cli/commands/config_management.py +6 -5
  18. swarm/extensions/cli/commands/edit_config.py +7 -16
  19. swarm/extensions/cli/commands/list_blueprints.py +1 -1
  20. swarm/extensions/cli/commands/validate_env.py +4 -11
  21. swarm/extensions/cli/commands/validate_envvars.py +6 -6
  22. swarm/extensions/cli/interactive_shell.py +2 -16
  23. swarm/extensions/config/config_loader.py +201 -107
  24. swarm/{core → extensions/config}/config_manager.py +38 -50
  25. swarm/{core → extensions/config}/server_config.py +0 -32
  26. swarm/extensions/launchers/build_launchers.py +14 -0
  27. swarm/{core → extensions/launchers}/build_swarm_wrapper.py +0 -0
  28. swarm/extensions/launchers/swarm_api.py +64 -8
  29. swarm/extensions/launchers/swarm_cli.py +300 -8
  30. swarm/llm/chat_completion.py +195 -0
  31. swarm/serializers.py +5 -96
  32. swarm/settings.py +111 -99
  33. swarm/urls.py +74 -57
  34. swarm/utils/context_utils.py +4 -10
  35. swarm/utils/general_utils.py +0 -21
  36. swarm/utils/redact.py +36 -23
  37. swarm/views/api_views.py +39 -48
  38. swarm/views/chat_views.py +70 -237
  39. swarm/views/core_views.py +87 -80
  40. swarm/views/model_views.py +121 -64
  41. swarm/views/utils.py +441 -65
  42. swarm/views/web_views.py +2 -2
  43. open_swarm-0.1.1745274976.dist-info/METADATA +0 -874
  44. open_swarm-0.1.1745274976.dist-info/RECORD +0 -318
  45. open_swarm-0.1.1745274976.dist-info/entry_points.txt +0 -4
  46. swarm/blueprints/README.md +0 -68
  47. swarm/blueprints/blueprint_audit_status.json +0 -27
  48. swarm/blueprints/chatbot/README.md +0 -40
  49. swarm/blueprints/chatbot/blueprint_chatbot.py +0 -471
  50. swarm/blueprints/chatbot/metadata.json +0 -23
  51. swarm/blueprints/chatbot/templates/chatbot/chatbot.html +0 -33
  52. swarm/blueprints/chucks_angels/README.md +0 -11
  53. swarm/blueprints/chucks_angels/blueprint_chucks_angels.py +0 -7
  54. swarm/blueprints/chucks_angels/test_basic.py +0 -3
  55. swarm/blueprints/codey/CODEY.md +0 -15
  56. swarm/blueprints/codey/README.md +0 -115
  57. swarm/blueprints/codey/blueprint_codey.py +0 -1072
  58. swarm/blueprints/codey/codey_cli.py +0 -373
  59. swarm/blueprints/codey/instructions.md +0 -17
  60. swarm/blueprints/codey/metadata.json +0 -23
  61. swarm/blueprints/common/operation_box_utils.py +0 -83
  62. swarm/blueprints/digitalbutlers/README.md +0 -11
  63. swarm/blueprints/digitalbutlers/__init__.py +0 -1
  64. swarm/blueprints/digitalbutlers/blueprint_digitalbutlers.py +0 -7
  65. swarm/blueprints/digitalbutlers/test_basic.py +0 -3
  66. swarm/blueprints/divine_code/README.md +0 -3
  67. swarm/blueprints/divine_code/__init__.py +0 -10
  68. swarm/blueprints/divine_code/apps.py +0 -11
  69. swarm/blueprints/divine_code/blueprint_divine_code.py +0 -270
  70. swarm/blueprints/django_chat/apps.py +0 -6
  71. swarm/blueprints/django_chat/blueprint_django_chat.py +0 -268
  72. swarm/blueprints/django_chat/templates/django_chat/django_chat_webpage.html +0 -37
  73. swarm/blueprints/django_chat/urls.py +0 -8
  74. swarm/blueprints/django_chat/views.py +0 -32
  75. swarm/blueprints/echocraft/blueprint_echocraft.py +0 -384
  76. swarm/blueprints/flock/README.md +0 -11
  77. swarm/blueprints/flock/__init__.py +0 -8
  78. swarm/blueprints/flock/blueprint_flock.py +0 -7
  79. swarm/blueprints/flock/test_basic.py +0 -3
  80. swarm/blueprints/geese/README.md +0 -97
  81. swarm/blueprints/geese/blueprint_geese.py +0 -803
  82. swarm/blueprints/geese/geese_cli.py +0 -102
  83. swarm/blueprints/jeeves/README.md +0 -41
  84. swarm/blueprints/jeeves/blueprint_jeeves.py +0 -722
  85. swarm/blueprints/jeeves/jeeves_cli.py +0 -55
  86. swarm/blueprints/jeeves/metadata.json +0 -24
  87. swarm/blueprints/mcp_demo/blueprint_mcp_demo.py +0 -473
  88. swarm/blueprints/messenger/templates/messenger/messenger.html +0 -46
  89. swarm/blueprints/mission_improbable/blueprint_mission_improbable.py +0 -423
  90. swarm/blueprints/monkai_magic/blueprint_monkai_magic.py +0 -340
  91. swarm/blueprints/nebula_shellz/blueprint_nebula_shellz.py +0 -265
  92. swarm/blueprints/omniplex/blueprint_omniplex.py +0 -298
  93. swarm/blueprints/poets/blueprint_poets.py +0 -546
  94. swarm/blueprints/poets/poets_cli.py +0 -23
  95. swarm/blueprints/rue_code/README.md +0 -8
  96. swarm/blueprints/rue_code/blueprint_rue_code.py +0 -448
  97. swarm/blueprints/rue_code/rue_code_cli.py +0 -43
  98. swarm/blueprints/stewie/apps.py +0 -12
  99. swarm/blueprints/stewie/blueprint_family_ties.py +0 -349
  100. swarm/blueprints/stewie/models.py +0 -19
  101. swarm/blueprints/stewie/serializers.py +0 -10
  102. swarm/blueprints/stewie/settings.py +0 -17
  103. swarm/blueprints/stewie/urls.py +0 -11
  104. swarm/blueprints/stewie/views.py +0 -26
  105. swarm/blueprints/suggestion/blueprint_suggestion.py +0 -222
  106. swarm/blueprints/whinge_surf/README.md +0 -22
  107. swarm/blueprints/whinge_surf/__init__.py +0 -1
  108. swarm/blueprints/whinge_surf/blueprint_whinge_surf.py +0 -565
  109. swarm/blueprints/whinge_surf/whinge_surf_cli.py +0 -99
  110. swarm/blueprints/whiskeytango_foxtrot/__init__.py +0 -0
  111. swarm/blueprints/whiskeytango_foxtrot/apps.py +0 -11
  112. swarm/blueprints/whiskeytango_foxtrot/blueprint_whiskeytango_foxtrot.py +0 -339
  113. swarm/blueprints/zeus/__init__.py +0 -2
  114. swarm/blueprints/zeus/apps.py +0 -4
  115. swarm/blueprints/zeus/blueprint_zeus.py +0 -270
  116. swarm/blueprints/zeus/zeus_cli.py +0 -13
  117. swarm/cli/async_input.py +0 -65
  118. swarm/cli/async_input_demo.py +0 -32
  119. swarm/core/blueprint_base.py +0 -769
  120. swarm/core/blueprint_discovery.py +0 -125
  121. swarm/core/blueprint_runner.py +0 -59
  122. swarm/core/blueprint_ux.py +0 -109
  123. swarm/core/build_launchers.py +0 -15
  124. swarm/core/cli/__init__.py +0 -1
  125. swarm/core/cli/commands/__init__.py +0 -1
  126. swarm/core/cli/commands/blueprint_management.py +0 -7
  127. swarm/core/cli/interactive_shell.py +0 -14
  128. swarm/core/cli/main.py +0 -50
  129. swarm/core/cli/utils/__init__.py +0 -1
  130. swarm/core/cli/utils/discover_commands.py +0 -18
  131. swarm/core/config_loader.py +0 -122
  132. swarm/core/output_utils.py +0 -193
  133. swarm/core/session_logger.py +0 -42
  134. swarm/core/slash_commands.py +0 -89
  135. swarm/core/swarm_api.py +0 -68
  136. swarm/core/swarm_cli.py +0 -216
  137. swarm/core/utils/__init__.py +0 -0
  138. swarm/extensions/blueprint/cli_handler.py +0 -197
  139. swarm/extensions/blueprint/runnable_blueprint.py +0 -42
  140. swarm/extensions/cli/utils/__init__.py +0 -1
  141. swarm/extensions/cli/utils/async_input.py +0 -46
  142. swarm/extensions/cli/utils/prompt_user.py +0 -3
  143. swarm/management/__init__.py +0 -0
  144. swarm/management/commands/__init__.py +0 -0
  145. swarm/management/commands/runserver.py +0 -58
  146. swarm/middleware.py +0 -65
  147. swarm/permissions.py +0 -38
  148. swarm/static/contrib/fonts/fontawesome-webfont.ttf +0 -7
  149. swarm/static/contrib/fonts/fontawesome-webfont.woff +0 -7
  150. swarm/static/contrib/fonts/fontawesome-webfont.woff2 +0 -7
  151. swarm/static/contrib/markedjs/marked.min.js +0 -6
  152. swarm/static/contrib/tabler-icons/adjustments-horizontal.svg +0 -27
  153. swarm/static/contrib/tabler-icons/alert-triangle.svg +0 -21
  154. swarm/static/contrib/tabler-icons/archive.svg +0 -21
  155. swarm/static/contrib/tabler-icons/artboard.svg +0 -27
  156. swarm/static/contrib/tabler-icons/automatic-gearbox.svg +0 -23
  157. swarm/static/contrib/tabler-icons/box-multiple.svg +0 -19
  158. swarm/static/contrib/tabler-icons/carambola.svg +0 -19
  159. swarm/static/contrib/tabler-icons/copy.svg +0 -20
  160. swarm/static/contrib/tabler-icons/download.svg +0 -21
  161. swarm/static/contrib/tabler-icons/edit.svg +0 -21
  162. swarm/static/contrib/tabler-icons/filled/carambola.svg +0 -13
  163. swarm/static/contrib/tabler-icons/filled/paint.svg +0 -13
  164. swarm/static/contrib/tabler-icons/headset.svg +0 -22
  165. swarm/static/contrib/tabler-icons/layout-sidebar-left-collapse.svg +0 -21
  166. swarm/static/contrib/tabler-icons/layout-sidebar-left-expand.svg +0 -21
  167. swarm/static/contrib/tabler-icons/layout-sidebar-right-collapse.svg +0 -21
  168. swarm/static/contrib/tabler-icons/layout-sidebar-right-expand.svg +0 -21
  169. swarm/static/contrib/tabler-icons/message-chatbot.svg +0 -22
  170. swarm/static/contrib/tabler-icons/message-star.svg +0 -22
  171. swarm/static/contrib/tabler-icons/message-x.svg +0 -23
  172. swarm/static/contrib/tabler-icons/message.svg +0 -21
  173. swarm/static/contrib/tabler-icons/paperclip.svg +0 -18
  174. swarm/static/contrib/tabler-icons/playlist-add.svg +0 -22
  175. swarm/static/contrib/tabler-icons/robot.svg +0 -26
  176. swarm/static/contrib/tabler-icons/search.svg +0 -19
  177. swarm/static/contrib/tabler-icons/settings.svg +0 -20
  178. swarm/static/contrib/tabler-icons/thumb-down.svg +0 -19
  179. swarm/static/contrib/tabler-icons/thumb-up.svg +0 -19
  180. swarm/static/css/dropdown.css +0 -22
  181. swarm/static/htmx/htmx.min.js +0 -0
  182. swarm/static/js/dropdown.js +0 -23
  183. swarm/static/rest_mode/css/base.css +0 -470
  184. swarm/static/rest_mode/css/chat-history.css +0 -286
  185. swarm/static/rest_mode/css/chat.css +0 -251
  186. swarm/static/rest_mode/css/chatbot.css +0 -74
  187. swarm/static/rest_mode/css/chatgpt.css +0 -62
  188. swarm/static/rest_mode/css/colors/corporate.css +0 -74
  189. swarm/static/rest_mode/css/colors/pastel.css +0 -81
  190. swarm/static/rest_mode/css/colors/tropical.css +0 -82
  191. swarm/static/rest_mode/css/general.css +0 -142
  192. swarm/static/rest_mode/css/layout.css +0 -167
  193. swarm/static/rest_mode/css/layouts/messenger-layout.css +0 -17
  194. swarm/static/rest_mode/css/layouts/minimalist-layout.css +0 -57
  195. swarm/static/rest_mode/css/layouts/mobile-layout.css +0 -8
  196. swarm/static/rest_mode/css/messages.css +0 -84
  197. swarm/static/rest_mode/css/messenger.css +0 -135
  198. swarm/static/rest_mode/css/settings.css +0 -91
  199. swarm/static/rest_mode/css/simple.css +0 -44
  200. swarm/static/rest_mode/css/slack.css +0 -58
  201. swarm/static/rest_mode/css/style.css +0 -156
  202. swarm/static/rest_mode/css/theme.css +0 -30
  203. swarm/static/rest_mode/css/toast.css +0 -40
  204. swarm/static/rest_mode/js/auth.js +0 -9
  205. swarm/static/rest_mode/js/blueprint.js +0 -41
  206. swarm/static/rest_mode/js/blueprintUtils.js +0 -12
  207. swarm/static/rest_mode/js/chatLogic.js +0 -79
  208. swarm/static/rest_mode/js/debug.js +0 -63
  209. swarm/static/rest_mode/js/events.js +0 -98
  210. swarm/static/rest_mode/js/main.js +0 -19
  211. swarm/static/rest_mode/js/messages.js +0 -264
  212. swarm/static/rest_mode/js/messengerLogic.js +0 -355
  213. swarm/static/rest_mode/js/modules/apiService.js +0 -84
  214. swarm/static/rest_mode/js/modules/blueprintManager.js +0 -162
  215. swarm/static/rest_mode/js/modules/chatHistory.js +0 -110
  216. swarm/static/rest_mode/js/modules/debugLogger.js +0 -14
  217. swarm/static/rest_mode/js/modules/eventHandlers.js +0 -107
  218. swarm/static/rest_mode/js/modules/messageProcessor.js +0 -120
  219. swarm/static/rest_mode/js/modules/state.js +0 -7
  220. swarm/static/rest_mode/js/modules/userInteractions.js +0 -29
  221. swarm/static/rest_mode/js/modules/validation.js +0 -23
  222. swarm/static/rest_mode/js/rendering.js +0 -119
  223. swarm/static/rest_mode/js/settings.js +0 -130
  224. swarm/static/rest_mode/js/sidebar.js +0 -94
  225. swarm/static/rest_mode/js/simpleLogic.js +0 -37
  226. swarm/static/rest_mode/js/slackLogic.js +0 -66
  227. swarm/static/rest_mode/js/splash.js +0 -76
  228. swarm/static/rest_mode/js/theme.js +0 -111
  229. swarm/static/rest_mode/js/toast.js +0 -36
  230. swarm/static/rest_mode/js/ui.js +0 -265
  231. swarm/static/rest_mode/js/validation.js +0 -57
  232. swarm/static/rest_mode/svg/animated_spinner.svg +0 -12
  233. swarm/static/rest_mode/svg/arrow_down.svg +0 -5
  234. swarm/static/rest_mode/svg/arrow_left.svg +0 -5
  235. swarm/static/rest_mode/svg/arrow_right.svg +0 -5
  236. swarm/static/rest_mode/svg/arrow_up.svg +0 -5
  237. swarm/static/rest_mode/svg/attach.svg +0 -8
  238. swarm/static/rest_mode/svg/avatar.svg +0 -7
  239. swarm/static/rest_mode/svg/canvas.svg +0 -6
  240. swarm/static/rest_mode/svg/chat_history.svg +0 -4
  241. swarm/static/rest_mode/svg/close.svg +0 -5
  242. swarm/static/rest_mode/svg/copy.svg +0 -4
  243. swarm/static/rest_mode/svg/dark_mode.svg +0 -3
  244. swarm/static/rest_mode/svg/edit.svg +0 -5
  245. swarm/static/rest_mode/svg/layout.svg +0 -9
  246. swarm/static/rest_mode/svg/logo.svg +0 -29
  247. swarm/static/rest_mode/svg/logout.svg +0 -5
  248. swarm/static/rest_mode/svg/mobile.svg +0 -5
  249. swarm/static/rest_mode/svg/new_chat.svg +0 -4
  250. swarm/static/rest_mode/svg/not_visible.svg +0 -5
  251. swarm/static/rest_mode/svg/plus.svg +0 -7
  252. swarm/static/rest_mode/svg/run_code.svg +0 -6
  253. swarm/static/rest_mode/svg/save.svg +0 -4
  254. swarm/static/rest_mode/svg/search.svg +0 -6
  255. swarm/static/rest_mode/svg/settings.svg +0 -4
  256. swarm/static/rest_mode/svg/speaker.svg +0 -5
  257. swarm/static/rest_mode/svg/stop.svg +0 -6
  258. swarm/static/rest_mode/svg/thumbs_down.svg +0 -3
  259. swarm/static/rest_mode/svg/thumbs_up.svg +0 -3
  260. swarm/static/rest_mode/svg/toggle_off.svg +0 -6
  261. swarm/static/rest_mode/svg/toggle_on.svg +0 -6
  262. swarm/static/rest_mode/svg/trash.svg +0 -10
  263. swarm/static/rest_mode/svg/undo.svg +0 -3
  264. swarm/static/rest_mode/svg/visible.svg +0 -8
  265. swarm/static/rest_mode/svg/voice.svg +0 -10
  266. swarm/templates/account/login.html +0 -22
  267. swarm/templates/account/signup.html +0 -32
  268. swarm/templates/base.html +0 -30
  269. swarm/templates/chat.html +0 -43
  270. swarm/templates/index.html +0 -35
  271. swarm/templates/rest_mode/components/chat_sidebar.html +0 -55
  272. swarm/templates/rest_mode/components/header.html +0 -45
  273. swarm/templates/rest_mode/components/main_chat_pane.html +0 -41
  274. swarm/templates/rest_mode/components/settings_dialog.html +0 -97
  275. swarm/templates/rest_mode/components/splash_screen.html +0 -7
  276. swarm/templates/rest_mode/components/top_bar.html +0 -28
  277. swarm/templates/rest_mode/message_ui.html +0 -50
  278. swarm/templates/rest_mode/slackbot.html +0 -30
  279. swarm/templates/simple_blueprint_page.html +0 -24
  280. swarm/templates/websocket_partials/final_system_message.html +0 -3
  281. swarm/templates/websocket_partials/system_message.html +0 -4
  282. swarm/templates/websocket_partials/user_message.html +0 -5
  283. swarm/utils/ansi_box.py +0 -34
  284. swarm/utils/disable_tracing.py +0 -38
  285. swarm/utils/log_utils.py +0 -63
  286. swarm/utils/openai_patch.py +0 -33
  287. swarm/ux/ansi_box.py +0 -43
  288. swarm/ux/spinner.py +0 -53
  289. {open_swarm-0.1.1745274976.dist-info → open_swarm-0.1.1748636259.dist-info}/licenses/LICENSE +0 -0
  290. /swarm/{core → extensions/blueprint}/blueprint_utils.py +0 -0
  291. /swarm/{core → extensions/blueprint}/common_utils.py +0 -0
  292. /swarm/{core → extensions/config}/setup_wizard.py +0 -0
  293. /swarm/{blueprints/rue_code → extensions/config/utils}/__init__.py +0 -0
  294. /swarm/{core → extensions/config}/utils/logger.py +0 -0
  295. /swarm/{core → extensions/launchers}/swarm_wrapper.py +0 -0
swarm/views/core_views.py CHANGED
@@ -11,101 +11,108 @@ from django.http import JsonResponse, HttpResponse
11
11
  from django.conf import settings
12
12
  from django.views.decorators.csrf import csrf_exempt
13
13
  from django.contrib.auth import authenticate, login
14
- from django.contrib.auth.forms import AuthenticationForm # Use standard auth form
15
-
16
14
 
17
15
  # Assuming blueprint discovery happens elsewhere and results are available if needed
18
16
  # from .utils import blueprints_metadata # Or however metadata is accessed
19
-
20
- # Use the current config loader
21
- from swarm.core import config_loader, server_config
17
+ from swarm.extensions.config.config_loader import load_server_config # Import if needed
22
18
 
23
19
  logger = logging.getLogger(__name__)
24
20
 
25
- # --- Web UI Views (if ENABLE_WEBUI is True) ---
21
+ # Placeholder for blueprint metadata if needed by index
22
+ # In a real app, this might be loaded dynamically or passed via context
23
+ try:
24
+ # Attempt to import the discovery function if views need dynamic data
25
+ from swarm.extensions.blueprint.blueprint_discovery import discover_blueprints
26
+ # Note: Calling discover_blueprints here might be too early or cause issues.
27
+ # It's often better handled in specific views that need it (like list_models)
28
+ # or passed via Django context processors.
29
+ # For now, provide an empty dict as fallback.
30
+ try:
31
+ # Use settings.BLUEPRINTS_DIR which should be configured
32
+ blueprints_metadata = discover_blueprints(directories=[str(settings.BLUEPRINTS_DIR)])
33
+ except Exception:
34
+ blueprints_metadata = {}
35
+ except ImportError:
36
+ blueprints_metadata = {}
37
+
26
38
 
39
+ @csrf_exempt
27
40
  def index(request):
28
- """Render the main index page (likely the chat UI)."""
29
- # This view might need context data like available models/blueprints
30
- # It should only be active if ENABLE_WEBUI is true (checked in urls.py)
31
- logger.debug(f"Index view called for user: {request.user}")
41
+ """Render the main index page with blueprint options."""
42
+ logger.debug("Rendering index page")
43
+ # Get blueprint names from the potentially loaded metadata
44
+ blueprint_names_list = list(blueprints_metadata.keys())
32
45
  context = {
33
- 'title': settings.SWARM_TITLE or "Open Swarm",
34
- 'description': settings.SWARM_DESCRIPTION or "A Swarm Framework Interface",
35
- # Add other context needed by the template
46
+ "dark_mode": request.session.get('dark_mode', True),
47
+ "enable_admin": os.getenv("ENABLE_ADMIN", "false").lower() in ("true", "1", "t"),
48
+ "blueprints": blueprint_names_list # Pass the list of names
36
49
  }
37
- # Ensure the template exists
38
- template_name = "swarm/index.html"
39
- # Check if template exists? Django handles TemplateDoesNotExist.
40
- return render(request, template_name, context)
41
-
42
- def custom_login(request):
43
- """Handles user login."""
44
- if request.method == 'POST':
45
- form = AuthenticationForm(request, data=request.POST)
46
- if form.is_valid():
47
- username = form.cleaned_data.get('username')
48
- password = form.cleaned_data.get('password')
49
- user = authenticate(username=username, password=password)
50
- if user is not None:
51
- login(request, user)
52
- logger.info(f"User '{username}' logged in successfully.")
53
- return redirect('/') # Redirect to index after login
54
- else:
55
- logger.warning(f"Login failed for user '{username}': Invalid credentials.")
56
- # Return form with error (AuthenticationForm handles this)
57
- else:
58
- logger.warning(f"Login form invalid: {form.errors.as_json()}")
59
- else:
60
- form = AuthenticationForm()
61
-
62
- # Only render if ENABLE_WEBUI is true (checked in urls.py)
63
- return render(request, 'swarm/login.html', {'form': form})
50
+ return render(request, "index.html", context)
64
51
 
52
+ DEFAULT_CONFIG = {
53
+ "llm": {
54
+ "default": {
55
+ "provider": "openai",
56
+ "model": "gpt-4o", # Example fallback model
57
+ "base_url": "https://api.openai.com/v1",
58
+ "api_key": "",
59
+ "temperature": 0.3
60
+ }
61
+ },
62
+ "blueprints": {},
63
+ "mcpServers": {}
64
+ }
65
65
 
66
66
  def serve_swarm_config(request):
67
- """Serves the swarm_config.json content."""
68
- # Find the config file used by the blueprint base or config loader
69
- # This logic might need refinement depending on where config is reliably found
70
- config_path = None
67
+ """Serve the swarm configuration file as JSON."""
71
68
  try:
72
- # Use the same logic as BlueprintBase if possible, or find_config_file
73
- config_path = config_loader.find_config_file(filename=config_loader.DEFAULT_CONFIG_FILENAME, start_dir=Path(settings.BASE_DIR).parent) # Search from project root
74
- if not config_path:
75
- # Fallback to location relative to settings? Unlikely to be correct.
76
- config_path = Path(settings.BASE_DIR) / '..' / config_loader.DEFAULT_CONFIG_FILENAME # Adjust relative path if needed
77
- config_path = config_path.resolve()
69
+ # Use load_server_config which handles finding the file
70
+ config_data = load_server_config()
71
+ return JsonResponse(config_data)
72
+ except (FileNotFoundError, ValueError, Exception) as e:
73
+ logger.error(f"Error serving swarm_config.json: {e}. Serving default.")
74
+ # Return a default config on error
75
+ return JsonResponse(DEFAULT_CONFIG, status=500)
76
+
78
77
 
79
- if config_path and config_path.exists():
80
- logger.info(f"Serving config from: {config_path}")
81
- # Load config to potentially redact sensitive info before serving
82
- config_data = config_loader.load_config(config_path)
83
- # Redact sensitive keys (e.g., api_key)
84
- if 'llm' in config_data:
85
- for profile in config_data['llm']: config_data['llm'][profile].pop('api_key', None)
86
- return JsonResponse(config_data)
87
- else:
88
- logger.error(f"Swarm config file not found at expected locations (tried: {config_path})")
89
- return JsonResponse({"error": "Configuration file not found."}, status=404)
78
+ @csrf_exempt
79
+ def custom_login(request):
80
+ """Handle custom login at /accounts/login/, redirecting to 'next' URL on success."""
81
+ from django.contrib.auth.models import User # Import here to avoid potential early init issues
82
+ if request.method == "POST":
83
+ username = request.POST.get("username")
84
+ password = request.POST.get("password")
85
+ user = authenticate(request, username=username, password=password)
86
+ if user is not None:
87
+ login(request, user)
88
+ next_url = request.GET.get("next", getattr(settings, 'LOGIN_REDIRECT_URL', '/')) # Use setting or fallback
89
+ logger.info(f"User '{username}' logged in successfully. Redirecting to {next_url}")
90
+ return redirect(next_url)
91
+ else:
92
+ # If ENABLE_API_AUTH is false, auto-login as testuser (for dev/test convenience)
93
+ enable_auth = os.getenv("ENABLE_API_AUTH", "true").lower() in ("true", "1", "t") # Default to TRUE
94
+ if not enable_auth:
95
+ try:
96
+ # Ensure test user exists and has a known password
97
+ user, created = User.objects.get_or_create(username="testuser")
98
+ if created or not user.has_usable_password():
99
+ user.set_password("testpass") # Set a default password
100
+ user.save()
90
101
 
91
- except Exception as e:
92
- logger.error(f"Error serving swarm config: {e}", exc_info=True)
93
- return JsonResponse({"error": "Failed to load or serve configuration."}, status=500)
102
+ if user.check_password("testpass"): # Check against the known password
103
+ login(request, user)
104
+ next_url = request.GET.get("next", getattr(settings, 'LOGIN_REDIRECT_URL', '/'))
105
+ logger.info(f"Auto-logged in as 'testuser' since ENABLE_API_AUTH is false")
106
+ return redirect(next_url)
107
+ else:
108
+ logger.warning("Auto-login failed: 'testuser' exists but password incorrect.")
94
109
 
95
- # --- Potentially other core API views if needed ---
96
- # Example: A view to list available blueprints (might duplicate CLI list command logic)
110
+ except Exception as auto_login_err:
111
+ logger.error(f"Error during testuser auto-login attempt: {auto_login_err}")
112
+ # If authentication failed (and auto-login didn't happen or failed)
113
+ logger.warning(f"Login failed for user '{username}'.")
114
+ return render(request, "account/login.html", {"error": "Invalid credentials"})
115
+ # If GET request
116
+ return render(request, "account/login.html")
97
117
 
98
- @csrf_exempt # If POST is needed and no CSRF token available from UI
99
- def list_available_blueprints_api(request):
100
- """API endpoint to list discoverable blueprints."""
101
- # Re-use discovery logic if possible, or adapt from CLI
102
- from swarm.extensions.blueprint.discovery import discover_blueprints # Assuming this exists
103
- try:
104
- bp_dir = Path(settings.BLUEPRINTS_DIR) # Assuming settings has BLUEPRINTS_DIR
105
- discovered = discover_blueprints(directories=[str(bp_dir)])
106
- # Format the response
107
- blueprint_list = [{"name": name, "description": meta.get("description", "N/A")} for name, meta in discovered.items()]
108
- return JsonResponse({"blueprints": blueprint_list})
109
- except Exception as e:
110
- logger.error(f"Error listing blueprints via API: {e}", exc_info=True)
111
- return JsonResponse({"error": "Failed to list blueprints."}, status=500)
118
+ # Add any other views that were originally in the main views.py if needed
@@ -1,78 +1,135 @@
1
1
  """
2
- Views related to listing and describing available models (Blueprints).
2
+ Model listing views for Open Swarm MCP Core.
3
+ Dynamically discovers blueprints and lists them alongside configured LLMs.
3
4
  """
4
- import logging
5
- from django.conf import settings
6
- from django.http import JsonResponse # Not used directly, Response is preferred
7
- from django.utils.decorators import method_decorator
8
- from django.views.decorators.csrf import csrf_exempt
9
-
10
- from rest_framework.views import APIView
11
- from rest_framework.response import Response
12
- from rest_framework.permissions import AllowAny, IsAuthenticated
13
- from rest_framework import status
14
-
5
+ import os
6
+ from django.http import JsonResponse
7
+ from rest_framework.decorators import api_view, permission_classes, authentication_classes
8
+ from rest_framework.permissions import AllowAny # Import AllowAny
15
9
  from drf_spectacular.utils import extend_schema
16
10
 
17
- # *** Import async_to_sync ***
18
- from asgiref.sync import async_to_sync
11
+ from swarm.utils.logger_setup import setup_logger
12
+ # Import the function to discover blueprints, not the metadata variable
13
+ from swarm.extensions.blueprint.blueprint_discovery import discover_blueprints
14
+ # Import utility to filter blueprints if needed
15
+ from swarm.extensions.blueprint.blueprint_utils import filter_blueprints
16
+ # Import config loader or access config globally if set up
17
+ # Using utils seems less direct, let's assume config needs loading or is globally available
18
+ # from swarm.views.utils import config # This import might be problematic, load directly if needed
19
+ from swarm.extensions.config.config_loader import load_server_config
20
+ from swarm.settings import BLUEPRINTS_DIR # Import the directory setting
19
21
 
20
- # Import the utility function
21
- from .utils import get_available_blueprints
22
- from ..permissions import HasValidTokenOrSession
22
+ logger = setup_logger(__name__)
23
23
 
24
- logger = logging.getLogger(__name__)
24
+ @extend_schema(
25
+ responses={
26
+ 200: {
27
+ "type": "object",
28
+ "properties": {
29
+ "object": {"type": "string"},
30
+ "data": {
31
+ "type": "array",
32
+ "items": {
33
+ "type": "object",
34
+ "properties": {
35
+ "id": {"type": "string"},
36
+ "object": {"type": "string"},
37
+ "title": {"type": "string"},
38
+ "description": {"type": "string"}
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ },
45
+ summary="Lists LLMs, config-defined blueprints, and discovered blueprints as models."
46
+ )
47
+ @api_view(["GET"])
48
+ @permission_classes([AllowAny]) # Use AllowAny directly
49
+ @authentication_classes([]) # No authentication required for listing models
50
+ def list_models(request):
51
+ """List available LLMs, config-defined blueprints, and discovered blueprints."""
52
+ if request.method != "GET":
53
+ return JsonResponse({"error": "Method not allowed. Use GET."}, status=405)
25
54
 
26
- # ==============================================================================
27
- # API Views (DRF based) for Models
28
- # ==============================================================================
55
+ try:
56
+ # Load configuration each time or ensure it's loaded globally/cached
57
+ config = load_server_config() # Load config to get LLMs and config blueprints
29
58
 
30
- class ListModelsView(APIView):
31
- """
32
- API view to list available models (Blueprints).
33
- Compliant with OpenAI API's /v1/models endpoint structure.
34
- """
35
- permission_classes = [HasValidTokenOrSession]
59
+ # 1. LLMs from config (marked as passthrough)
60
+ llm_config = config.get("llm", {})
61
+ llm_data = [
62
+ {
63
+ "id": key,
64
+ "object": "llm", # Mark as llm type
65
+ "title": conf.get("model", key), # Use model name or key as title
66
+ "description": f"Provider: {conf.get('provider', 'N/A')}, Model: {conf.get('model', 'N/A')}"
67
+ }
68
+ for key, conf in llm_config.items() if conf.get("passthrough")
69
+ ]
36
70
 
37
- @extend_schema(
38
- responses={ # Simplified schema for brevity
39
- 200: {"description": "A list of available models."}
40
- }
41
- )
42
- # *** Make the handler synchronous ***
43
- def get(self, request, *args, **kwargs):
44
- """
45
- Handles GET requests to list available models.
46
- """
71
+ # 2. Blueprints defined directly in swarm_config.json
72
+ config_blueprints = config.get("blueprints", {})
73
+ config_bp_data = [
74
+ {
75
+ "id": key,
76
+ "object": "blueprint", # Mark as blueprint type
77
+ "title": bp.get("title", key),
78
+ "description": bp.get("description", f"Blueprint '{key}' from configuration file.")
79
+ }
80
+ for key, bp in config_blueprints.items()
81
+ ]
82
+
83
+ # 3. Dynamically discovered blueprints from the blueprints directory
84
+ # Ensure BLUEPRINTS_DIR is correctly pointing to your blueprints location relative to project root
47
85
  try:
48
- # *** Call the async utility function using async_to_sync ***
49
- # Ensure get_available_blueprints is awaitable (async def or wrapped)
50
- available_blueprints_dict = async_to_sync(get_available_blueprints)()
86
+ # Call discover_blueprints function to get the metadata dictionary
87
+ discovered_blueprints_metadata = discover_blueprints(directories=[BLUEPRINTS_DIR])
88
+ except FileNotFoundError:
89
+ logger.warning(f"Blueprints directory '{BLUEPRINTS_DIR}' not found. No blueprints discovered dynamically.")
90
+ discovered_blueprints_metadata = {}
91
+ except Exception as discover_err:
92
+ logger.error(f"Error discovering blueprints: {discover_err}", exc_info=True)
93
+ discovered_blueprints_metadata = {}
51
94
 
52
- models_data = [
53
- {
54
- "id": model_id,
55
- "object": "model",
56
- "created": 0, # Placeholder
57
- "owned_by": "open-swarm",
58
- # Access metadata safely
59
- "profile_name": metadata.get('profile_name', 'unknown') if isinstance(metadata, dict) else 'unknown'
60
- }
61
- # Ensure iteration works correctly
62
- for model_id, metadata in (available_blueprints_dict.items() if isinstance(available_blueprints_dict, dict) else [])
63
- ]
64
95
 
65
- response_data = {
66
- "object": "list",
67
- "data": models_data,
96
+ # Filter discovered blueprints based on environment variable if set
97
+ allowed_blueprints_str = os.getenv("SWARM_BLUEPRINTS")
98
+ if allowed_blueprints_str and allowed_blueprints_str.strip():
99
+ # Use the imported filter_blueprints utility
100
+ final_discovered_metadata = filter_blueprints(discovered_blueprints_metadata, allowed_blueprints_str)
101
+ logger.info(f"Filtering discovered blueprints based on SWARM_BLUEPRINTS env var. Kept: {list(final_discovered_metadata.keys())}")
102
+ else:
103
+ final_discovered_metadata = discovered_blueprints_metadata # Use all discovered if no filter
104
+
105
+ # Format discovered blueprint data
106
+ discovered_bp_data = [
107
+ {
108
+ "id": key,
109
+ "object": "blueprint", # Mark as blueprint type
110
+ "title": meta.get("title", key),
111
+ "description": meta.get("description", f"Discovered blueprint '{key}'.")
68
112
  }
69
- # Return the standard sync Response
70
- return Response(response_data, status=status.HTTP_200_OK)
113
+ for key, meta in final_discovered_metadata.items()
114
+ ]
115
+
116
+ # 4. Merge all data sources
117
+ # Start with LLMs and config blueprints
118
+ merged_data = llm_data + config_bp_data
119
+ # Keep track of IDs already added
120
+ seen_ids = {item["id"] for item in merged_data}
121
+ # Add discovered blueprints only if their ID hasn't been used by config/LLMs
122
+ for bp_item in discovered_bp_data:
123
+ if bp_item["id"] not in seen_ids:
124
+ merged_data.append(bp_item)
125
+ seen_ids.add(bp_item["id"]) # Mark ID as seen
126
+
127
+ logger.debug(f"Returning {len(merged_data)} models (LLMs + Blueprints).")
128
+ # Return the merged list in the expected OpenAI-like format
129
+ return JsonResponse({"object": "list", "data": merged_data}, status=200)
130
+
131
+ except Exception as e:
132
+ # Catch-all for unexpected errors during the process
133
+ logger.error(f"Error listing models: {e}", exc_info=True)
134
+ return JsonResponse({"error": "Internal Server Error while listing models."}, status=500)
71
135
 
72
- except Exception as e:
73
- logger.error(f"Error retrieving available blueprints: {e}", exc_info=True)
74
- # Return the standard sync Response
75
- return Response(
76
- {"error": "Internal server error retrieving models."},
77
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
78
- )