open-swarm 0.1.1745275181__py3-none-any.whl → 0.1.1748636295__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 (307) hide show
  1. open_swarm-0.1.1748636295.dist-info/METADATA +257 -0
  2. open_swarm-0.1.1748636295.dist-info/RECORD +89 -0
  3. {open_swarm-0.1.1745275181.dist-info → open_swarm-0.1.1748636295.dist-info}/WHEEL +2 -1
  4. open_swarm-0.1.1748636295.dist-info/entry_points.txt +3 -0
  5. open_swarm-0.1.1748636295.dist-info/top_level.txt +1 -0
  6. swarm/__init__.py +2 -0
  7. swarm/agent/agent.py +49 -0
  8. swarm/auth.py +48 -113
  9. swarm/consumers.py +0 -19
  10. swarm/core.py +411 -0
  11. swarm/extensions/blueprint/__init__.py +16 -30
  12. swarm/extensions/blueprint/agent_utils.py +45 -0
  13. swarm/extensions/blueprint/blueprint_base.py +562 -0
  14. swarm/extensions/blueprint/blueprint_discovery.py +112 -0
  15. swarm/extensions/blueprint/django_utils.py +79 -181
  16. swarm/extensions/blueprint/interactive_mode.py +72 -67
  17. swarm/extensions/blueprint/output_utils.py +82 -0
  18. swarm/{core → extensions/blueprint}/spinner.py +21 -30
  19. swarm/extensions/cli/cli_args.py +0 -6
  20. swarm/extensions/cli/commands/blueprint_management.py +9 -47
  21. swarm/extensions/cli/commands/config_management.py +6 -5
  22. swarm/extensions/cli/commands/edit_config.py +7 -16
  23. swarm/extensions/cli/commands/list_blueprints.py +1 -1
  24. swarm/extensions/cli/commands/validate_env.py +4 -11
  25. swarm/extensions/cli/commands/validate_envvars.py +6 -6
  26. swarm/extensions/cli/interactive_shell.py +2 -16
  27. swarm/extensions/config/config_loader.py +345 -107
  28. swarm/{core → extensions/config}/config_manager.py +38 -50
  29. swarm/{core → extensions/config}/server_config.py +0 -32
  30. swarm/extensions/launchers/build_launchers.py +14 -0
  31. swarm/{core → extensions/launchers}/build_swarm_wrapper.py +0 -0
  32. swarm/extensions/launchers/swarm_api.py +64 -8
  33. swarm/extensions/launchers/swarm_cli.py +300 -8
  34. swarm/extensions/mcp/__init__.py +1 -0
  35. swarm/extensions/mcp/cache_utils.py +32 -0
  36. swarm/extensions/mcp/mcp_client.py +233 -0
  37. swarm/extensions/mcp/mcp_tool_provider.py +135 -0
  38. swarm/extensions/mcp/mcp_utils.py +260 -0
  39. swarm/llm/chat_completion.py +166 -0
  40. swarm/serializers.py +5 -96
  41. swarm/settings.py +133 -85
  42. swarm/types.py +91 -0
  43. swarm/urls.py +74 -57
  44. swarm/utils/context_utils.py +4 -10
  45. swarm/utils/general_utils.py +0 -21
  46. swarm/utils/redact.py +36 -23
  47. swarm/views/api_views.py +39 -48
  48. swarm/views/chat_views.py +76 -236
  49. swarm/views/core_views.py +87 -80
  50. swarm/views/model_views.py +121 -64
  51. swarm/views/utils.py +439 -65
  52. swarm/views/web_views.py +2 -2
  53. open_swarm-0.1.1745275181.dist-info/METADATA +0 -874
  54. open_swarm-0.1.1745275181.dist-info/RECORD +0 -319
  55. open_swarm-0.1.1745275181.dist-info/entry_points.txt +0 -4
  56. swarm/blueprints/README.md +0 -68
  57. swarm/blueprints/blueprint_audit_status.json +0 -27
  58. swarm/blueprints/chatbot/README.md +0 -40
  59. swarm/blueprints/chatbot/blueprint_chatbot.py +0 -471
  60. swarm/blueprints/chatbot/metadata.json +0 -23
  61. swarm/blueprints/chatbot/templates/chatbot/chatbot.html +0 -33
  62. swarm/blueprints/chucks_angels/README.md +0 -11
  63. swarm/blueprints/chucks_angels/blueprint_chucks_angels.py +0 -7
  64. swarm/blueprints/chucks_angels/test_basic.py +0 -3
  65. swarm/blueprints/codey/CODEY.md +0 -15
  66. swarm/blueprints/codey/README.md +0 -115
  67. swarm/blueprints/codey/blueprint_codey.py +0 -1072
  68. swarm/blueprints/codey/codey_cli.py +0 -373
  69. swarm/blueprints/codey/instructions.md +0 -17
  70. swarm/blueprints/codey/metadata.json +0 -23
  71. swarm/blueprints/common/operation_box_utils.py +0 -83
  72. swarm/blueprints/digitalbutlers/README.md +0 -11
  73. swarm/blueprints/digitalbutlers/__init__.py +0 -1
  74. swarm/blueprints/digitalbutlers/blueprint_digitalbutlers.py +0 -7
  75. swarm/blueprints/digitalbutlers/test_basic.py +0 -3
  76. swarm/blueprints/divine_code/README.md +0 -3
  77. swarm/blueprints/divine_code/__init__.py +0 -10
  78. swarm/blueprints/divine_code/apps.py +0 -11
  79. swarm/blueprints/divine_code/blueprint_divine_code.py +0 -270
  80. swarm/blueprints/django_chat/apps.py +0 -6
  81. swarm/blueprints/django_chat/blueprint_django_chat.py +0 -268
  82. swarm/blueprints/django_chat/templates/django_chat/django_chat_webpage.html +0 -37
  83. swarm/blueprints/django_chat/urls.py +0 -8
  84. swarm/blueprints/django_chat/views.py +0 -32
  85. swarm/blueprints/echocraft/blueprint_echocraft.py +0 -384
  86. swarm/blueprints/flock/README.md +0 -11
  87. swarm/blueprints/flock/__init__.py +0 -8
  88. swarm/blueprints/flock/blueprint_flock.py +0 -7
  89. swarm/blueprints/flock/test_basic.py +0 -3
  90. swarm/blueprints/geese/README.md +0 -10
  91. swarm/blueprints/geese/__init__.py +0 -8
  92. swarm/blueprints/geese/blueprint_geese.py +0 -384
  93. swarm/blueprints/geese/geese_cli.py +0 -102
  94. swarm/blueprints/jeeves/README.md +0 -41
  95. swarm/blueprints/jeeves/blueprint_jeeves.py +0 -722
  96. swarm/blueprints/jeeves/jeeves_cli.py +0 -55
  97. swarm/blueprints/jeeves/metadata.json +0 -24
  98. swarm/blueprints/mcp_demo/blueprint_mcp_demo.py +0 -473
  99. swarm/blueprints/messenger/templates/messenger/messenger.html +0 -46
  100. swarm/blueprints/mission_improbable/blueprint_mission_improbable.py +0 -423
  101. swarm/blueprints/monkai_magic/blueprint_monkai_magic.py +0 -340
  102. swarm/blueprints/nebula_shellz/blueprint_nebula_shellz.py +0 -265
  103. swarm/blueprints/omniplex/blueprint_omniplex.py +0 -298
  104. swarm/blueprints/poets/blueprint_poets.py +0 -546
  105. swarm/blueprints/poets/poets_cli.py +0 -23
  106. swarm/blueprints/rue_code/README.md +0 -8
  107. swarm/blueprints/rue_code/blueprint_rue_code.py +0 -448
  108. swarm/blueprints/rue_code/rue_code_cli.py +0 -43
  109. swarm/blueprints/stewie/apps.py +0 -12
  110. swarm/blueprints/stewie/blueprint_family_ties.py +0 -349
  111. swarm/blueprints/stewie/models.py +0 -19
  112. swarm/blueprints/stewie/serializers.py +0 -10
  113. swarm/blueprints/stewie/settings.py +0 -17
  114. swarm/blueprints/stewie/urls.py +0 -11
  115. swarm/blueprints/stewie/views.py +0 -26
  116. swarm/blueprints/suggestion/blueprint_suggestion.py +0 -222
  117. swarm/blueprints/whinge_surf/README.md +0 -22
  118. swarm/blueprints/whinge_surf/__init__.py +0 -1
  119. swarm/blueprints/whinge_surf/blueprint_whinge_surf.py +0 -565
  120. swarm/blueprints/whinge_surf/whinge_surf_cli.py +0 -99
  121. swarm/blueprints/whiskeytango_foxtrot/__init__.py +0 -0
  122. swarm/blueprints/whiskeytango_foxtrot/apps.py +0 -11
  123. swarm/blueprints/whiskeytango_foxtrot/blueprint_whiskeytango_foxtrot.py +0 -339
  124. swarm/blueprints/zeus/__init__.py +0 -2
  125. swarm/blueprints/zeus/apps.py +0 -4
  126. swarm/blueprints/zeus/blueprint_zeus.py +0 -270
  127. swarm/blueprints/zeus/zeus_cli.py +0 -13
  128. swarm/cli/async_input.py +0 -65
  129. swarm/cli/async_input_demo.py +0 -32
  130. swarm/core/agent_utils.py +0 -21
  131. swarm/core/blueprint_base.py +0 -769
  132. swarm/core/blueprint_discovery.py +0 -125
  133. swarm/core/blueprint_runner.py +0 -59
  134. swarm/core/blueprint_ux.py +0 -109
  135. swarm/core/build_launchers.py +0 -15
  136. swarm/core/cli/__init__.py +0 -1
  137. swarm/core/cli/commands/__init__.py +0 -1
  138. swarm/core/cli/commands/blueprint_management.py +0 -7
  139. swarm/core/cli/interactive_shell.py +0 -14
  140. swarm/core/cli/main.py +0 -50
  141. swarm/core/cli/utils/__init__.py +0 -1
  142. swarm/core/cli/utils/discover_commands.py +0 -18
  143. swarm/core/config_loader.py +0 -122
  144. swarm/core/output_utils.py +0 -193
  145. swarm/core/session_logger.py +0 -42
  146. swarm/core/slash_commands.py +0 -89
  147. swarm/core/swarm_api.py +0 -68
  148. swarm/core/swarm_cli.py +0 -216
  149. swarm/core/utils/__init__.py +0 -0
  150. swarm/extensions/blueprint/cli_handler.py +0 -197
  151. swarm/extensions/blueprint/runnable_blueprint.py +0 -42
  152. swarm/extensions/cli/utils/__init__.py +0 -1
  153. swarm/extensions/cli/utils/async_input.py +0 -46
  154. swarm/extensions/cli/utils/prompt_user.py +0 -3
  155. swarm/management/__init__.py +0 -0
  156. swarm/management/commands/__init__.py +0 -0
  157. swarm/management/commands/runserver.py +0 -58
  158. swarm/middleware.py +0 -65
  159. swarm/permissions.py +0 -38
  160. swarm/static/contrib/fonts/fontawesome-webfont.ttf +0 -7
  161. swarm/static/contrib/fonts/fontawesome-webfont.woff +0 -7
  162. swarm/static/contrib/fonts/fontawesome-webfont.woff2 +0 -7
  163. swarm/static/contrib/markedjs/marked.min.js +0 -6
  164. swarm/static/contrib/tabler-icons/adjustments-horizontal.svg +0 -27
  165. swarm/static/contrib/tabler-icons/alert-triangle.svg +0 -21
  166. swarm/static/contrib/tabler-icons/archive.svg +0 -21
  167. swarm/static/contrib/tabler-icons/artboard.svg +0 -27
  168. swarm/static/contrib/tabler-icons/automatic-gearbox.svg +0 -23
  169. swarm/static/contrib/tabler-icons/box-multiple.svg +0 -19
  170. swarm/static/contrib/tabler-icons/carambola.svg +0 -19
  171. swarm/static/contrib/tabler-icons/copy.svg +0 -20
  172. swarm/static/contrib/tabler-icons/download.svg +0 -21
  173. swarm/static/contrib/tabler-icons/edit.svg +0 -21
  174. swarm/static/contrib/tabler-icons/filled/carambola.svg +0 -13
  175. swarm/static/contrib/tabler-icons/filled/paint.svg +0 -13
  176. swarm/static/contrib/tabler-icons/headset.svg +0 -22
  177. swarm/static/contrib/tabler-icons/layout-sidebar-left-collapse.svg +0 -21
  178. swarm/static/contrib/tabler-icons/layout-sidebar-left-expand.svg +0 -21
  179. swarm/static/contrib/tabler-icons/layout-sidebar-right-collapse.svg +0 -21
  180. swarm/static/contrib/tabler-icons/layout-sidebar-right-expand.svg +0 -21
  181. swarm/static/contrib/tabler-icons/message-chatbot.svg +0 -22
  182. swarm/static/contrib/tabler-icons/message-star.svg +0 -22
  183. swarm/static/contrib/tabler-icons/message-x.svg +0 -23
  184. swarm/static/contrib/tabler-icons/message.svg +0 -21
  185. swarm/static/contrib/tabler-icons/paperclip.svg +0 -18
  186. swarm/static/contrib/tabler-icons/playlist-add.svg +0 -22
  187. swarm/static/contrib/tabler-icons/robot.svg +0 -26
  188. swarm/static/contrib/tabler-icons/search.svg +0 -19
  189. swarm/static/contrib/tabler-icons/settings.svg +0 -20
  190. swarm/static/contrib/tabler-icons/thumb-down.svg +0 -19
  191. swarm/static/contrib/tabler-icons/thumb-up.svg +0 -19
  192. swarm/static/css/dropdown.css +0 -22
  193. swarm/static/htmx/htmx.min.js +0 -0
  194. swarm/static/js/dropdown.js +0 -23
  195. swarm/static/rest_mode/css/base.css +0 -470
  196. swarm/static/rest_mode/css/chat-history.css +0 -286
  197. swarm/static/rest_mode/css/chat.css +0 -251
  198. swarm/static/rest_mode/css/chatbot.css +0 -74
  199. swarm/static/rest_mode/css/chatgpt.css +0 -62
  200. swarm/static/rest_mode/css/colors/corporate.css +0 -74
  201. swarm/static/rest_mode/css/colors/pastel.css +0 -81
  202. swarm/static/rest_mode/css/colors/tropical.css +0 -82
  203. swarm/static/rest_mode/css/general.css +0 -142
  204. swarm/static/rest_mode/css/layout.css +0 -167
  205. swarm/static/rest_mode/css/layouts/messenger-layout.css +0 -17
  206. swarm/static/rest_mode/css/layouts/minimalist-layout.css +0 -57
  207. swarm/static/rest_mode/css/layouts/mobile-layout.css +0 -8
  208. swarm/static/rest_mode/css/messages.css +0 -84
  209. swarm/static/rest_mode/css/messenger.css +0 -135
  210. swarm/static/rest_mode/css/settings.css +0 -91
  211. swarm/static/rest_mode/css/simple.css +0 -44
  212. swarm/static/rest_mode/css/slack.css +0 -58
  213. swarm/static/rest_mode/css/style.css +0 -156
  214. swarm/static/rest_mode/css/theme.css +0 -30
  215. swarm/static/rest_mode/css/toast.css +0 -40
  216. swarm/static/rest_mode/js/auth.js +0 -9
  217. swarm/static/rest_mode/js/blueprint.js +0 -41
  218. swarm/static/rest_mode/js/blueprintUtils.js +0 -12
  219. swarm/static/rest_mode/js/chatLogic.js +0 -79
  220. swarm/static/rest_mode/js/debug.js +0 -63
  221. swarm/static/rest_mode/js/events.js +0 -98
  222. swarm/static/rest_mode/js/main.js +0 -19
  223. swarm/static/rest_mode/js/messages.js +0 -264
  224. swarm/static/rest_mode/js/messengerLogic.js +0 -355
  225. swarm/static/rest_mode/js/modules/apiService.js +0 -84
  226. swarm/static/rest_mode/js/modules/blueprintManager.js +0 -162
  227. swarm/static/rest_mode/js/modules/chatHistory.js +0 -110
  228. swarm/static/rest_mode/js/modules/debugLogger.js +0 -14
  229. swarm/static/rest_mode/js/modules/eventHandlers.js +0 -107
  230. swarm/static/rest_mode/js/modules/messageProcessor.js +0 -120
  231. swarm/static/rest_mode/js/modules/state.js +0 -7
  232. swarm/static/rest_mode/js/modules/userInteractions.js +0 -29
  233. swarm/static/rest_mode/js/modules/validation.js +0 -23
  234. swarm/static/rest_mode/js/rendering.js +0 -119
  235. swarm/static/rest_mode/js/settings.js +0 -130
  236. swarm/static/rest_mode/js/sidebar.js +0 -94
  237. swarm/static/rest_mode/js/simpleLogic.js +0 -37
  238. swarm/static/rest_mode/js/slackLogic.js +0 -66
  239. swarm/static/rest_mode/js/splash.js +0 -76
  240. swarm/static/rest_mode/js/theme.js +0 -111
  241. swarm/static/rest_mode/js/toast.js +0 -36
  242. swarm/static/rest_mode/js/ui.js +0 -265
  243. swarm/static/rest_mode/js/validation.js +0 -57
  244. swarm/static/rest_mode/svg/animated_spinner.svg +0 -12
  245. swarm/static/rest_mode/svg/arrow_down.svg +0 -5
  246. swarm/static/rest_mode/svg/arrow_left.svg +0 -5
  247. swarm/static/rest_mode/svg/arrow_right.svg +0 -5
  248. swarm/static/rest_mode/svg/arrow_up.svg +0 -5
  249. swarm/static/rest_mode/svg/attach.svg +0 -8
  250. swarm/static/rest_mode/svg/avatar.svg +0 -7
  251. swarm/static/rest_mode/svg/canvas.svg +0 -6
  252. swarm/static/rest_mode/svg/chat_history.svg +0 -4
  253. swarm/static/rest_mode/svg/close.svg +0 -5
  254. swarm/static/rest_mode/svg/copy.svg +0 -4
  255. swarm/static/rest_mode/svg/dark_mode.svg +0 -3
  256. swarm/static/rest_mode/svg/edit.svg +0 -5
  257. swarm/static/rest_mode/svg/layout.svg +0 -9
  258. swarm/static/rest_mode/svg/logo.svg +0 -29
  259. swarm/static/rest_mode/svg/logout.svg +0 -5
  260. swarm/static/rest_mode/svg/mobile.svg +0 -5
  261. swarm/static/rest_mode/svg/new_chat.svg +0 -4
  262. swarm/static/rest_mode/svg/not_visible.svg +0 -5
  263. swarm/static/rest_mode/svg/plus.svg +0 -7
  264. swarm/static/rest_mode/svg/run_code.svg +0 -6
  265. swarm/static/rest_mode/svg/save.svg +0 -4
  266. swarm/static/rest_mode/svg/search.svg +0 -6
  267. swarm/static/rest_mode/svg/settings.svg +0 -4
  268. swarm/static/rest_mode/svg/speaker.svg +0 -5
  269. swarm/static/rest_mode/svg/stop.svg +0 -6
  270. swarm/static/rest_mode/svg/thumbs_down.svg +0 -3
  271. swarm/static/rest_mode/svg/thumbs_up.svg +0 -3
  272. swarm/static/rest_mode/svg/toggle_off.svg +0 -6
  273. swarm/static/rest_mode/svg/toggle_on.svg +0 -6
  274. swarm/static/rest_mode/svg/trash.svg +0 -10
  275. swarm/static/rest_mode/svg/undo.svg +0 -3
  276. swarm/static/rest_mode/svg/visible.svg +0 -8
  277. swarm/static/rest_mode/svg/voice.svg +0 -10
  278. swarm/templates/account/login.html +0 -22
  279. swarm/templates/account/signup.html +0 -32
  280. swarm/templates/base.html +0 -30
  281. swarm/templates/chat.html +0 -43
  282. swarm/templates/index.html +0 -35
  283. swarm/templates/rest_mode/components/chat_sidebar.html +0 -55
  284. swarm/templates/rest_mode/components/header.html +0 -45
  285. swarm/templates/rest_mode/components/main_chat_pane.html +0 -41
  286. swarm/templates/rest_mode/components/settings_dialog.html +0 -97
  287. swarm/templates/rest_mode/components/splash_screen.html +0 -7
  288. swarm/templates/rest_mode/components/top_bar.html +0 -28
  289. swarm/templates/rest_mode/message_ui.html +0 -50
  290. swarm/templates/rest_mode/slackbot.html +0 -30
  291. swarm/templates/simple_blueprint_page.html +0 -24
  292. swarm/templates/websocket_partials/final_system_message.html +0 -3
  293. swarm/templates/websocket_partials/system_message.html +0 -4
  294. swarm/templates/websocket_partials/user_message.html +0 -5
  295. swarm/utils/ansi_box.py +0 -34
  296. swarm/utils/disable_tracing.py +0 -38
  297. swarm/utils/log_utils.py +0 -63
  298. swarm/utils/openai_patch.py +0 -33
  299. swarm/ux/ansi_box.py +0 -43
  300. swarm/ux/spinner.py +0 -53
  301. {open_swarm-0.1.1745275181.dist-info → open_swarm-0.1.1748636295.dist-info}/licenses/LICENSE +0 -0
  302. /swarm/{core → extensions/blueprint}/blueprint_utils.py +0 -0
  303. /swarm/{core → extensions/blueprint}/common_utils.py +0 -0
  304. /swarm/{core → extensions/config}/setup_wizard.py +0 -0
  305. /swarm/{blueprints/rue_code → extensions/config/utils}/__init__.py +0 -0
  306. /swarm/{core → extensions/config}/utils/logger.py +0 -0
  307. /swarm/{core → extensions/launchers}/swarm_wrapper.py +0 -0
swarm/urls.py CHANGED
@@ -1,72 +1,89 @@
1
- """
2
- Swarm URL Configuration
3
- """
4
- import logging
5
1
  from django.contrib import admin
6
- from django.urls import path, include, reverse_lazy
2
+ from django.urls import path, re_path, include
3
+ from django.http import HttpResponse
7
4
  from django.conf import settings
8
- from django.views.generic import RedirectView
9
- from django.contrib.auth import views as auth_views
10
-
11
- from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
5
+ from django.conf.urls.static import static
6
+ import os
7
+ import logging
12
8
 
13
- from swarm.views.chat_views import ChatCompletionsView, HealthCheckView
14
- # *** Uncomment and correct the import path ***
15
- from swarm.views.api_views import ModelsListView
16
- # from swarm.views.webui_views import index as webui_index # Rename to avoid conflict
9
+ # Import specific views from their modules
10
+ from swarm.views.core_views import index as core_index_view, serve_swarm_config, custom_login
11
+ from swarm.views.chat_views import chat_completions
12
+ from swarm.views.model_views import list_models
13
+ from swarm.views.message_views import ChatMessageViewSet
14
+ from drf_spectacular.views import SpectacularSwaggerView, SpectacularAPIView as HiddenSpectacularAPIView
15
+ from rest_framework.routers import DefaultRouter
17
16
 
18
17
  logger = logging.getLogger(__name__)
19
18
 
20
- # ==============================================================================
21
- # API URL Patterns (v1)
22
- # ==============================================================================
23
- api_urlpatterns = [
24
- path('chat/completions', ChatCompletionsView.as_view(), name='chat_completions'),
25
- # *** Uncomment this URL pattern ***
26
- path('models', ModelsListView.as_view(), name='list_models'),
27
- path('health', HealthCheckView.as_view(), name='health_check'),
28
- # Add other v1 API endpoints here
29
- ]
30
-
31
- # ==============================================================================
32
- # Schema URL Patterns
33
- # ==============================================================================
34
- schema_urlpatterns = [
35
- path('schema/', SpectacularAPIView.as_view(), name='schema'),
36
- path('schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
37
- path('schema/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
38
- ]
19
+ def favicon(request):
20
+ favicon_path = settings.BASE_DIR / 'assets' / 'images' / 'favicon.ico'
21
+ try:
22
+ with open(favicon_path, 'rb') as f:
23
+ favicon_data = f.read()
24
+ return HttpResponse(favicon_data, content_type="image/x-icon")
25
+ except FileNotFoundError:
26
+ logger.warning("Favicon not found.")
27
+ return HttpResponse(status=404)
39
28
 
40
- # ==============================================================================
41
- # Main URL Patterns
42
- # ==============================================================================
43
- urlpatterns = [
44
- # Redirect root based on DEBUG setting
45
- path('', RedirectView.as_view(pattern_name='swagger-ui', permanent=False) if settings.DEBUG else RedirectView.as_view(pattern_name='login', permanent=False)),
29
+ ENABLE_ADMIN = os.getenv("ENABLE_ADMIN", "false").lower() in ("true", "1", "t")
30
+ ENABLE_WEBUI = os.getenv("ENABLE_WEBUI", "true").lower() in ("true", "1", "t")
46
31
 
47
- # API v1 endpoints
48
- path('v1/', include(api_urlpatterns)),
32
+ logger.debug(f"ENABLE_WEBUI={'true' if ENABLE_WEBUI else 'false'}")
33
+ logger.debug(f"ENABLE_ADMIN={'true' if ENABLE_ADMIN else 'false'}")
49
34
 
50
- # Schema endpoints
51
- path('api/', include(schema_urlpatterns)),
35
+ router = DefaultRouter()
36
+ # Ensure ChatMessageViewSet is available before registering
37
+ if ChatMessageViewSet:
38
+ router.register(r'v1/chat/messages', ChatMessageViewSet, basename='chatmessage')
39
+ else:
40
+ logger.warning("ChatMessageViewSet not imported correctly, skipping API registration.")
52
41
 
53
- # Django Admin (Optional)
54
- path('admin/', admin.site.urls) if getattr(settings, 'ENABLE_ADMIN', False) else path('admin/', RedirectView.as_view(url=reverse_lazy('login'))),
42
+ # Base URL patterns required by Swarm core
43
+ # Use the imported view functions directly
44
+ base_urlpatterns = [
45
+ re_path(r'^health/?$', lambda request: HttpResponse("OK"), name='health_check'),
46
+ re_path(r'^v1/chat/completions/?$', chat_completions, name='chat_completions'),
47
+ re_path(r'^v1/models/?$', list_models, name='list_models'),
48
+ re_path(r'^schema/?$', HiddenSpectacularAPIView.as_view(), name='schema'),
49
+ re_path(r'^swagger-ui/?$', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
50
+ ]
55
51
 
56
- # Authentication Views (Django Built-in)
57
- path('login/', auth_views.LoginView.as_view(template_name='swarm/login.html'), name='login'),
58
- path('logout/', auth_views.LogoutView.as_view(next_page=reverse_lazy('login')), name='logout'),
52
+ # Optional Admin URLs
53
+ admin_urlpatterns = [path('admin/', admin.site.urls)] if ENABLE_ADMIN else []
59
54
 
60
- # Web UI (Optional) - Conditionally include based on settings
61
- # *** Ensure this line remains commented out or removed if webui_index is not defined ***
62
- # path('webui/', webui_index, name='webui_index') if getattr(settings, 'ENABLE_WEBUI', False) else path('webui/', RedirectView.as_view(url=reverse_lazy('login'))),
63
- ]
55
+ # Optional Web UI URLs
56
+ webui_urlpatterns = []
57
+ if ENABLE_WEBUI:
58
+ webui_urlpatterns = [
59
+ path('', core_index_view, name='index'),
60
+ path('favicon.ico', favicon, name='favicon'),
61
+ path('config/swarm_config.json', serve_swarm_config, name='serve_swarm_config'),
62
+ path('accounts/login/', custom_login, name='custom_login'),
63
+ ]
64
+ if settings.DEBUG:
65
+ if settings.STATIC_URL and settings.STATIC_ROOT:
66
+ webui_urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
67
+ else:
68
+ logger.warning("STATIC_URL or STATIC_ROOT not configured, static files may not serve correctly in DEBUG mode.")
64
69
 
65
- # Debug logging (optional)
66
- logger.debug(f"ENABLE_ADMIN={getattr(settings, 'ENABLE_ADMIN', False)}")
67
- logger.debug(f"ENABLE_WEBUI={getattr(settings, 'ENABLE_WEBUI', False)}")
70
+ # --- Blueprint URLs are now added dynamically via blueprint_base.py -> django_utils.py ---
71
+ blueprint_urlpatterns = [] # Start with empty list, populated by utils
68
72
 
69
- # Example of how to conditionally add URLs based on settings
70
- # if getattr(settings, 'ENABLE_SOMETHING', False):
71
- # urlpatterns.append(path('something/', include('something.urls')))
73
+ # Combine all URL patterns
74
+ urlpatterns = webui_urlpatterns + admin_urlpatterns + base_urlpatterns + blueprint_urlpatterns + router.urls
72
75
 
76
+ # Log final URL patterns (consider moving this to where patterns are finalized if issues persist)
77
+ if settings.DEBUG:
78
+ try:
79
+ from django.urls import get_resolver
80
+ # Note: get_resolver(None) might not reflect dynamically added URLs perfectly here.
81
+ # Logging within django_utils might be more accurate for dynamic additions.
82
+ final_patterns = get_resolver(None).url_patterns
83
+ logger.debug(f"Initial resolved URL patterns ({len(final_patterns)} total):")
84
+ # for pattern in final_patterns:
85
+ # try: pattern_repr = str(pattern)
86
+ # except: pattern_repr = f"[Pattern for {getattr(pattern, 'name', 'unnamed')}]"
87
+ # logger.debug(f" {pattern_repr}")
88
+ except Exception as e:
89
+ logger.error(f"Could not log initial URL patterns: {e}")
@@ -23,16 +23,10 @@ def _is_valid_message(msg: Any) -> bool:
23
23
  role = msg.get("role")
24
24
  if not role or not isinstance(role, str): logger.warning(f"Skipping msg missing role: {str(msg)[:150]}"); return False
25
25
  content = msg.get("content"); tool_calls = msg.get("tool_calls"); tool_call_id = msg.get("tool_call_id")
26
- # Validate based on role: content must be a string for system/user/tool; assistant may have tool calls
27
- if role == "system":
28
- is_valid = isinstance(content, str)
29
- elif role == "user":
30
- is_valid = isinstance(content, str)
31
- elif role == "assistant":
32
- # Assistant valid if it has string content or at least one tool call
33
- is_valid = isinstance(content, str) or (isinstance(tool_calls, list) and len(tool_calls) > 0)
34
- elif role == "tool":
35
- is_valid = isinstance(content, str) and tool_call_id is not None
26
+ if role == "system": is_valid = content is not None
27
+ elif role == "user": is_valid = content is not None
28
+ elif role == "assistant": is_valid = content is not None or (isinstance(tool_calls, list) and len(tool_calls) > 0)
29
+ elif role == "tool": is_valid = content is not None and tool_call_id is not None
36
30
  else: is_valid = False
37
31
  if not is_valid: logger.warning(f"Skipping msg failing validity check for role '{role}': {str(msg)[:150]}")
38
32
  return is_valid
@@ -118,27 +118,6 @@ def _search_and_process_jmespath(expression: str, payload: dict) -> str:
118
118
 
119
119
  return str(chat_id) if chat_id is not None else ""
120
120
 
121
- # ---------------------------------------------------------------------------
122
- # Debug utilities
123
- # ---------------------------------------------------------------------------
124
-
125
- _DEBUG_ENV_VARS = ("SWARM_DEBUG", "DEBUG", "OPEN_SWARM_DEBUG")
126
-
127
-
128
- def is_debug_enabled() -> bool:
129
- """Return True if any recognised debug environment variable is truthy.
130
-
131
- A value is considered *truthy* when it is set and **not** one of
132
- "0", "false", "off" (case‑insensitive).
133
- """
134
- import os
135
-
136
- for var in _DEBUG_ENV_VARS:
137
- val = os.getenv(var)
138
- if val and val.lower() not in ("0", "false", "off"):
139
- return True
140
- return False
141
-
142
121
 
143
122
  def extract_chat_id(payload: dict) -> str:
144
123
  """
swarm/utils/redact.py CHANGED
@@ -13,43 +13,56 @@ DEFAULT_SENSITIVE_KEYS = ["secret", "password", "api_key", "apikey", "token", "a
13
13
  def redact_sensitive_data(
14
14
  data: Union[str, Dict, List],
15
15
  sensitive_keys: Optional[List[str]] = None,
16
- reveal_chars: int = 0,
16
+ reveal_chars: int = 4,
17
17
  mask: str = "[REDACTED]"
18
18
  ) -> Union[str, Dict, List]:
19
19
  """
20
20
  Recursively redact sensitive information from dictionaries or lists based on keys.
21
- By default, fully masks sensitive values (returns only the mask).
22
- If reveal_chars > 0, partially masks (preserves reveal_chars at start/end).
23
- If a custom mask is provided, always use it (for test compatibility).
21
+ Applies partial redaction to string values associated with sensitive keys.
24
22
  Does NOT redact standalone strings.
23
+
24
+ Args:
25
+ data: Input data to redact (dict or list). Other types returned as is.
26
+ sensitive_keys: List of dictionary keys to treat as sensitive. Defaults to common keys.
27
+ reveal_chars: Number of initial/trailing characters to reveal (0 means full redaction).
28
+ mask: String used for redaction in the middle or for full redaction of strings.
29
+
30
+ Returns:
31
+ Redacted data structure of the same type as input.
25
32
  """
26
- keys_to_redact = set((k.lower() for k in (sensitive_keys or DEFAULT_SENSITIVE_KEYS)))
27
- def smart_mask(val: str) -> str:
28
- if not isinstance(val, str):
29
- return val
30
- if mask != "[REDACTED]":
31
- return mask
32
- if reveal_chars == 0:
33
- return mask
34
- if len(val) >= 2 * reveal_chars + 1:
35
- return val[:reveal_chars] + mask + val[-reveal_chars:]
36
- return mask
33
+ keys_to_redact = sensitive_keys if sensitive_keys is not None else DEFAULT_SENSITIVE_KEYS
34
+ keys_to_redact_lower = {key.lower() for key in keys_to_redact}
35
+
37
36
  if isinstance(data, dict):
38
37
  redacted_dict = {}
39
- for k, v in data.items():
40
- if isinstance(k, str) and k.lower() in keys_to_redact:
41
- redacted_dict[k] = smart_mask(v)
42
- elif isinstance(v, (dict, list)):
43
- redacted_dict[k] = redact_sensitive_data(v, sensitive_keys, reveal_chars, mask)
38
+ for key, value in data.items():
39
+ if isinstance(key, str) and key.lower() in keys_to_redact_lower:
40
+ if isinstance(value, str):
41
+ val_len = len(value)
42
+ if reveal_chars > 0 and val_len > reveal_chars * 2:
43
+ redacted_dict[key] = f"{value[:reveal_chars]}{mask}{value[-reveal_chars:]}"
44
+ elif val_len > 0:
45
+ # Use the provided mask string directly for full redaction
46
+ redacted_dict[key] = mask
47
+ else:
48
+ redacted_dict[key] = "" # Redact empty string as empty
49
+ else:
50
+ # Use specific placeholder for non-strings
51
+ redacted_dict[key] = "[REDACTED NON-STRING]"
44
52
  else:
45
- redacted_dict[k] = v
53
+ # Recursively redact nested structures if key is not sensitive
54
+ redacted_dict[key] = redact_sensitive_data(value, keys_to_redact, reveal_chars, mask)
46
55
  return redacted_dict
56
+
47
57
  elif isinstance(data, list):
58
+ # Recursively redact items in a list ONLY if they are dicts or lists themselves.
48
59
  processed_list = []
49
60
  for item in data:
50
61
  if isinstance(item, (dict, list)):
51
- processed_list.append(redact_sensitive_data(item, sensitive_keys, reveal_chars, mask))
62
+ processed_list.append(redact_sensitive_data(item, keys_to_redact, reveal_chars, mask))
52
63
  else:
53
- processed_list.append(item)
64
+ processed_list.append(item) # Keep non-dict/list items (like strings) unchanged
54
65
  return processed_list
66
+
67
+ # Return data unchanged if it's not a dict or list (including standalone strings)
55
68
  return data
swarm/views/api_views.py CHANGED
@@ -1,55 +1,46 @@
1
- import time
2
- import logging
3
- from rest_framework.views import APIView
4
- from rest_framework.response import Response
5
- from rest_framework import status
1
+ """
2
+ API-specific views and viewsets for Open Swarm MCP Core.
3
+ """
4
+ from rest_framework.viewsets import ModelViewSet
6
5
  from rest_framework.permissions import AllowAny
7
- # *** Import async_to_sync ***
8
- from asgiref.sync import async_to_sync
6
+ from drf_spectacular.views import SpectacularAPIView as BaseSpectacularAPIView
7
+ from drf_spectacular.utils import extend_schema
8
+ from swarm.utils.logger_setup import setup_logger
9
+ from swarm.models import ChatMessage
10
+ from swarm.serializers import ChatMessageSerializer
9
11
 
10
- from swarm.views.utils import get_available_blueprints
12
+ logger = setup_logger(__name__)
11
13
 
12
- logger = logging.getLogger(__name__)
14
+ class HiddenSpectacularAPIView(BaseSpectacularAPIView):
15
+ exclude_from_schema = True
13
16
 
14
- class ModelsListView(APIView):
15
- """
16
- API view to list available models (blueprints) compatible with OpenAI's /v1/models format.
17
- """
17
+ class ChatMessageViewSet(ModelViewSet):
18
+ """API viewset for managing chat messages."""
19
+ authentication_classes = []
18
20
  permission_classes = [AllowAny]
21
+ queryset = ChatMessage.objects.all()
22
+ serializer_class = ChatMessageSerializer
19
23
 
20
- def get(self, request, *args, **kwargs):
21
- try:
22
- # *** Use async_to_sync to call the async function ***
23
- available_blueprints = async_to_sync(get_available_blueprints)()
24
-
25
- models_data = []
26
- current_time = int(time.time())
27
- if isinstance(available_blueprints, dict):
28
- blueprint_ids = available_blueprints.keys()
29
- elif isinstance(available_blueprints, list):
30
- blueprint_ids = available_blueprints
31
- else:
32
- logger.error(f"Unexpected type from get_available_blueprints: {type(available_blueprints)}")
33
- blueprint_ids = []
34
-
35
- for blueprint_id in blueprint_ids:
36
- models_data.append({
37
- "id": blueprint_id,
38
- "object": "model",
39
- "created": current_time,
40
- "owned_by": "open-swarm",
41
- })
42
-
43
- response_payload = {
44
- "object": "list",
45
- "data": models_data,
46
- }
47
- return Response(response_payload, status=status.HTTP_200_OK)
48
-
49
- except Exception as e:
50
- logger.exception("Error retrieving available models.")
51
- return Response(
52
- {"error": "Failed to retrieve models list."},
53
- status=status.HTTP_500_INTERNAL_SERVER_ERROR
54
- )
24
+ @extend_schema(summary="List all chat messages")
25
+ def list(self, request, *args, **kwargs):
26
+ return super().list(request, *args, **kwargs)
55
27
 
28
+ @extend_schema(summary="Retrieve a chat message by its unique id")
29
+ def retrieve(self, request, *args, **kwargs):
30
+ return super().retrieve(request, *args, **kwargs)
31
+
32
+ @extend_schema(summary="Create a new chat message")
33
+ def create(self, request, *args, **kwargs):
34
+ return super().create(request, *args, **kwargs)
35
+
36
+ @extend_schema(summary="Update an existing chat message")
37
+ def update(self, request, *args, **kwargs):
38
+ return super().update(request, *args, **kwargs)
39
+
40
+ @extend_schema(summary="Partially update a chat message")
41
+ def partial_update(self, request, *args, **kwargs):
42
+ return super().partial_update(request, *args, **kwargs)
43
+
44
+ @extend_schema(summary="Delete a chat message by its unique id")
45
+ def destroy(self, request, *args, **kwargs):
46
+ return super().destroy(request, *args, **kwargs)