open-swarm 0.1.1745275181__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.
- open_swarm-0.1.1748636259.dist-info/METADATA +188 -0
- open_swarm-0.1.1748636259.dist-info/RECORD +82 -0
- {open_swarm-0.1.1745275181.dist-info → open_swarm-0.1.1748636259.dist-info}/WHEEL +2 -1
- open_swarm-0.1.1748636259.dist-info/entry_points.txt +3 -0
- open_swarm-0.1.1748636259.dist-info/top_level.txt +1 -0
- swarm/agent/agent.py +49 -0
- swarm/auth.py +48 -113
- swarm/consumers.py +0 -19
- swarm/extensions/blueprint/__init__.py +16 -30
- swarm/{core → extensions/blueprint}/agent_utils.py +1 -1
- swarm/extensions/blueprint/blueprint_base.py +458 -0
- swarm/extensions/blueprint/blueprint_discovery.py +112 -0
- swarm/extensions/blueprint/output_utils.py +95 -0
- swarm/{core → extensions/blueprint}/spinner.py +21 -30
- swarm/extensions/cli/cli_args.py +0 -6
- swarm/extensions/cli/commands/blueprint_management.py +9 -47
- swarm/extensions/cli/commands/config_management.py +6 -5
- swarm/extensions/cli/commands/edit_config.py +7 -16
- swarm/extensions/cli/commands/list_blueprints.py +1 -1
- swarm/extensions/cli/commands/validate_env.py +4 -11
- swarm/extensions/cli/commands/validate_envvars.py +6 -6
- swarm/extensions/cli/interactive_shell.py +2 -16
- swarm/extensions/config/config_loader.py +201 -107
- swarm/{core → extensions/config}/config_manager.py +38 -50
- swarm/{core → extensions/config}/server_config.py +0 -32
- swarm/extensions/launchers/build_launchers.py +14 -0
- swarm/{core → extensions/launchers}/build_swarm_wrapper.py +0 -0
- swarm/extensions/launchers/swarm_api.py +64 -8
- swarm/extensions/launchers/swarm_cli.py +300 -8
- swarm/llm/chat_completion.py +195 -0
- swarm/serializers.py +5 -96
- swarm/settings.py +111 -99
- swarm/urls.py +74 -57
- swarm/utils/context_utils.py +4 -10
- swarm/utils/general_utils.py +0 -21
- swarm/utils/redact.py +36 -23
- swarm/views/api_views.py +39 -48
- swarm/views/chat_views.py +70 -237
- swarm/views/core_views.py +87 -80
- swarm/views/model_views.py +121 -64
- swarm/views/utils.py +441 -65
- swarm/views/web_views.py +2 -2
- open_swarm-0.1.1745275181.dist-info/METADATA +0 -874
- open_swarm-0.1.1745275181.dist-info/RECORD +0 -319
- open_swarm-0.1.1745275181.dist-info/entry_points.txt +0 -4
- swarm/blueprints/README.md +0 -68
- swarm/blueprints/blueprint_audit_status.json +0 -27
- swarm/blueprints/chatbot/README.md +0 -40
- swarm/blueprints/chatbot/blueprint_chatbot.py +0 -471
- swarm/blueprints/chatbot/metadata.json +0 -23
- swarm/blueprints/chatbot/templates/chatbot/chatbot.html +0 -33
- swarm/blueprints/chucks_angels/README.md +0 -11
- swarm/blueprints/chucks_angels/blueprint_chucks_angels.py +0 -7
- swarm/blueprints/chucks_angels/test_basic.py +0 -3
- swarm/blueprints/codey/CODEY.md +0 -15
- swarm/blueprints/codey/README.md +0 -115
- swarm/blueprints/codey/blueprint_codey.py +0 -1072
- swarm/blueprints/codey/codey_cli.py +0 -373
- swarm/blueprints/codey/instructions.md +0 -17
- swarm/blueprints/codey/metadata.json +0 -23
- swarm/blueprints/common/operation_box_utils.py +0 -83
- swarm/blueprints/digitalbutlers/README.md +0 -11
- swarm/blueprints/digitalbutlers/__init__.py +0 -1
- swarm/blueprints/digitalbutlers/blueprint_digitalbutlers.py +0 -7
- swarm/blueprints/digitalbutlers/test_basic.py +0 -3
- swarm/blueprints/divine_code/README.md +0 -3
- swarm/blueprints/divine_code/__init__.py +0 -10
- swarm/blueprints/divine_code/apps.py +0 -11
- swarm/blueprints/divine_code/blueprint_divine_code.py +0 -270
- swarm/blueprints/django_chat/apps.py +0 -6
- swarm/blueprints/django_chat/blueprint_django_chat.py +0 -268
- swarm/blueprints/django_chat/templates/django_chat/django_chat_webpage.html +0 -37
- swarm/blueprints/django_chat/urls.py +0 -8
- swarm/blueprints/django_chat/views.py +0 -32
- swarm/blueprints/echocraft/blueprint_echocraft.py +0 -384
- swarm/blueprints/flock/README.md +0 -11
- swarm/blueprints/flock/__init__.py +0 -8
- swarm/blueprints/flock/blueprint_flock.py +0 -7
- swarm/blueprints/flock/test_basic.py +0 -3
- swarm/blueprints/geese/README.md +0 -10
- swarm/blueprints/geese/__init__.py +0 -8
- swarm/blueprints/geese/blueprint_geese.py +0 -384
- swarm/blueprints/geese/geese_cli.py +0 -102
- swarm/blueprints/jeeves/README.md +0 -41
- swarm/blueprints/jeeves/blueprint_jeeves.py +0 -722
- swarm/blueprints/jeeves/jeeves_cli.py +0 -55
- swarm/blueprints/jeeves/metadata.json +0 -24
- swarm/blueprints/mcp_demo/blueprint_mcp_demo.py +0 -473
- swarm/blueprints/messenger/templates/messenger/messenger.html +0 -46
- swarm/blueprints/mission_improbable/blueprint_mission_improbable.py +0 -423
- swarm/blueprints/monkai_magic/blueprint_monkai_magic.py +0 -340
- swarm/blueprints/nebula_shellz/blueprint_nebula_shellz.py +0 -265
- swarm/blueprints/omniplex/blueprint_omniplex.py +0 -298
- swarm/blueprints/poets/blueprint_poets.py +0 -546
- swarm/blueprints/poets/poets_cli.py +0 -23
- swarm/blueprints/rue_code/README.md +0 -8
- swarm/blueprints/rue_code/blueprint_rue_code.py +0 -448
- swarm/blueprints/rue_code/rue_code_cli.py +0 -43
- swarm/blueprints/stewie/apps.py +0 -12
- swarm/blueprints/stewie/blueprint_family_ties.py +0 -349
- swarm/blueprints/stewie/models.py +0 -19
- swarm/blueprints/stewie/serializers.py +0 -10
- swarm/blueprints/stewie/settings.py +0 -17
- swarm/blueprints/stewie/urls.py +0 -11
- swarm/blueprints/stewie/views.py +0 -26
- swarm/blueprints/suggestion/blueprint_suggestion.py +0 -222
- swarm/blueprints/whinge_surf/README.md +0 -22
- swarm/blueprints/whinge_surf/__init__.py +0 -1
- swarm/blueprints/whinge_surf/blueprint_whinge_surf.py +0 -565
- swarm/blueprints/whinge_surf/whinge_surf_cli.py +0 -99
- swarm/blueprints/whiskeytango_foxtrot/__init__.py +0 -0
- swarm/blueprints/whiskeytango_foxtrot/apps.py +0 -11
- swarm/blueprints/whiskeytango_foxtrot/blueprint_whiskeytango_foxtrot.py +0 -339
- swarm/blueprints/zeus/__init__.py +0 -2
- swarm/blueprints/zeus/apps.py +0 -4
- swarm/blueprints/zeus/blueprint_zeus.py +0 -270
- swarm/blueprints/zeus/zeus_cli.py +0 -13
- swarm/cli/async_input.py +0 -65
- swarm/cli/async_input_demo.py +0 -32
- swarm/core/blueprint_base.py +0 -769
- swarm/core/blueprint_discovery.py +0 -125
- swarm/core/blueprint_runner.py +0 -59
- swarm/core/blueprint_ux.py +0 -109
- swarm/core/build_launchers.py +0 -15
- swarm/core/cli/__init__.py +0 -1
- swarm/core/cli/commands/__init__.py +0 -1
- swarm/core/cli/commands/blueprint_management.py +0 -7
- swarm/core/cli/interactive_shell.py +0 -14
- swarm/core/cli/main.py +0 -50
- swarm/core/cli/utils/__init__.py +0 -1
- swarm/core/cli/utils/discover_commands.py +0 -18
- swarm/core/config_loader.py +0 -122
- swarm/core/output_utils.py +0 -193
- swarm/core/session_logger.py +0 -42
- swarm/core/slash_commands.py +0 -89
- swarm/core/swarm_api.py +0 -68
- swarm/core/swarm_cli.py +0 -216
- swarm/core/utils/__init__.py +0 -0
- swarm/extensions/blueprint/cli_handler.py +0 -197
- swarm/extensions/blueprint/runnable_blueprint.py +0 -42
- swarm/extensions/cli/utils/__init__.py +0 -1
- swarm/extensions/cli/utils/async_input.py +0 -46
- swarm/extensions/cli/utils/prompt_user.py +0 -3
- swarm/management/__init__.py +0 -0
- swarm/management/commands/__init__.py +0 -0
- swarm/management/commands/runserver.py +0 -58
- swarm/middleware.py +0 -65
- swarm/permissions.py +0 -38
- swarm/static/contrib/fonts/fontawesome-webfont.ttf +0 -7
- swarm/static/contrib/fonts/fontawesome-webfont.woff +0 -7
- swarm/static/contrib/fonts/fontawesome-webfont.woff2 +0 -7
- swarm/static/contrib/markedjs/marked.min.js +0 -6
- swarm/static/contrib/tabler-icons/adjustments-horizontal.svg +0 -27
- swarm/static/contrib/tabler-icons/alert-triangle.svg +0 -21
- swarm/static/contrib/tabler-icons/archive.svg +0 -21
- swarm/static/contrib/tabler-icons/artboard.svg +0 -27
- swarm/static/contrib/tabler-icons/automatic-gearbox.svg +0 -23
- swarm/static/contrib/tabler-icons/box-multiple.svg +0 -19
- swarm/static/contrib/tabler-icons/carambola.svg +0 -19
- swarm/static/contrib/tabler-icons/copy.svg +0 -20
- swarm/static/contrib/tabler-icons/download.svg +0 -21
- swarm/static/contrib/tabler-icons/edit.svg +0 -21
- swarm/static/contrib/tabler-icons/filled/carambola.svg +0 -13
- swarm/static/contrib/tabler-icons/filled/paint.svg +0 -13
- swarm/static/contrib/tabler-icons/headset.svg +0 -22
- swarm/static/contrib/tabler-icons/layout-sidebar-left-collapse.svg +0 -21
- swarm/static/contrib/tabler-icons/layout-sidebar-left-expand.svg +0 -21
- swarm/static/contrib/tabler-icons/layout-sidebar-right-collapse.svg +0 -21
- swarm/static/contrib/tabler-icons/layout-sidebar-right-expand.svg +0 -21
- swarm/static/contrib/tabler-icons/message-chatbot.svg +0 -22
- swarm/static/contrib/tabler-icons/message-star.svg +0 -22
- swarm/static/contrib/tabler-icons/message-x.svg +0 -23
- swarm/static/contrib/tabler-icons/message.svg +0 -21
- swarm/static/contrib/tabler-icons/paperclip.svg +0 -18
- swarm/static/contrib/tabler-icons/playlist-add.svg +0 -22
- swarm/static/contrib/tabler-icons/robot.svg +0 -26
- swarm/static/contrib/tabler-icons/search.svg +0 -19
- swarm/static/contrib/tabler-icons/settings.svg +0 -20
- swarm/static/contrib/tabler-icons/thumb-down.svg +0 -19
- swarm/static/contrib/tabler-icons/thumb-up.svg +0 -19
- swarm/static/css/dropdown.css +0 -22
- swarm/static/htmx/htmx.min.js +0 -0
- swarm/static/js/dropdown.js +0 -23
- swarm/static/rest_mode/css/base.css +0 -470
- swarm/static/rest_mode/css/chat-history.css +0 -286
- swarm/static/rest_mode/css/chat.css +0 -251
- swarm/static/rest_mode/css/chatbot.css +0 -74
- swarm/static/rest_mode/css/chatgpt.css +0 -62
- swarm/static/rest_mode/css/colors/corporate.css +0 -74
- swarm/static/rest_mode/css/colors/pastel.css +0 -81
- swarm/static/rest_mode/css/colors/tropical.css +0 -82
- swarm/static/rest_mode/css/general.css +0 -142
- swarm/static/rest_mode/css/layout.css +0 -167
- swarm/static/rest_mode/css/layouts/messenger-layout.css +0 -17
- swarm/static/rest_mode/css/layouts/minimalist-layout.css +0 -57
- swarm/static/rest_mode/css/layouts/mobile-layout.css +0 -8
- swarm/static/rest_mode/css/messages.css +0 -84
- swarm/static/rest_mode/css/messenger.css +0 -135
- swarm/static/rest_mode/css/settings.css +0 -91
- swarm/static/rest_mode/css/simple.css +0 -44
- swarm/static/rest_mode/css/slack.css +0 -58
- swarm/static/rest_mode/css/style.css +0 -156
- swarm/static/rest_mode/css/theme.css +0 -30
- swarm/static/rest_mode/css/toast.css +0 -40
- swarm/static/rest_mode/js/auth.js +0 -9
- swarm/static/rest_mode/js/blueprint.js +0 -41
- swarm/static/rest_mode/js/blueprintUtils.js +0 -12
- swarm/static/rest_mode/js/chatLogic.js +0 -79
- swarm/static/rest_mode/js/debug.js +0 -63
- swarm/static/rest_mode/js/events.js +0 -98
- swarm/static/rest_mode/js/main.js +0 -19
- swarm/static/rest_mode/js/messages.js +0 -264
- swarm/static/rest_mode/js/messengerLogic.js +0 -355
- swarm/static/rest_mode/js/modules/apiService.js +0 -84
- swarm/static/rest_mode/js/modules/blueprintManager.js +0 -162
- swarm/static/rest_mode/js/modules/chatHistory.js +0 -110
- swarm/static/rest_mode/js/modules/debugLogger.js +0 -14
- swarm/static/rest_mode/js/modules/eventHandlers.js +0 -107
- swarm/static/rest_mode/js/modules/messageProcessor.js +0 -120
- swarm/static/rest_mode/js/modules/state.js +0 -7
- swarm/static/rest_mode/js/modules/userInteractions.js +0 -29
- swarm/static/rest_mode/js/modules/validation.js +0 -23
- swarm/static/rest_mode/js/rendering.js +0 -119
- swarm/static/rest_mode/js/settings.js +0 -130
- swarm/static/rest_mode/js/sidebar.js +0 -94
- swarm/static/rest_mode/js/simpleLogic.js +0 -37
- swarm/static/rest_mode/js/slackLogic.js +0 -66
- swarm/static/rest_mode/js/splash.js +0 -76
- swarm/static/rest_mode/js/theme.js +0 -111
- swarm/static/rest_mode/js/toast.js +0 -36
- swarm/static/rest_mode/js/ui.js +0 -265
- swarm/static/rest_mode/js/validation.js +0 -57
- swarm/static/rest_mode/svg/animated_spinner.svg +0 -12
- swarm/static/rest_mode/svg/arrow_down.svg +0 -5
- swarm/static/rest_mode/svg/arrow_left.svg +0 -5
- swarm/static/rest_mode/svg/arrow_right.svg +0 -5
- swarm/static/rest_mode/svg/arrow_up.svg +0 -5
- swarm/static/rest_mode/svg/attach.svg +0 -8
- swarm/static/rest_mode/svg/avatar.svg +0 -7
- swarm/static/rest_mode/svg/canvas.svg +0 -6
- swarm/static/rest_mode/svg/chat_history.svg +0 -4
- swarm/static/rest_mode/svg/close.svg +0 -5
- swarm/static/rest_mode/svg/copy.svg +0 -4
- swarm/static/rest_mode/svg/dark_mode.svg +0 -3
- swarm/static/rest_mode/svg/edit.svg +0 -5
- swarm/static/rest_mode/svg/layout.svg +0 -9
- swarm/static/rest_mode/svg/logo.svg +0 -29
- swarm/static/rest_mode/svg/logout.svg +0 -5
- swarm/static/rest_mode/svg/mobile.svg +0 -5
- swarm/static/rest_mode/svg/new_chat.svg +0 -4
- swarm/static/rest_mode/svg/not_visible.svg +0 -5
- swarm/static/rest_mode/svg/plus.svg +0 -7
- swarm/static/rest_mode/svg/run_code.svg +0 -6
- swarm/static/rest_mode/svg/save.svg +0 -4
- swarm/static/rest_mode/svg/search.svg +0 -6
- swarm/static/rest_mode/svg/settings.svg +0 -4
- swarm/static/rest_mode/svg/speaker.svg +0 -5
- swarm/static/rest_mode/svg/stop.svg +0 -6
- swarm/static/rest_mode/svg/thumbs_down.svg +0 -3
- swarm/static/rest_mode/svg/thumbs_up.svg +0 -3
- swarm/static/rest_mode/svg/toggle_off.svg +0 -6
- swarm/static/rest_mode/svg/toggle_on.svg +0 -6
- swarm/static/rest_mode/svg/trash.svg +0 -10
- swarm/static/rest_mode/svg/undo.svg +0 -3
- swarm/static/rest_mode/svg/visible.svg +0 -8
- swarm/static/rest_mode/svg/voice.svg +0 -10
- swarm/templates/account/login.html +0 -22
- swarm/templates/account/signup.html +0 -32
- swarm/templates/base.html +0 -30
- swarm/templates/chat.html +0 -43
- swarm/templates/index.html +0 -35
- swarm/templates/rest_mode/components/chat_sidebar.html +0 -55
- swarm/templates/rest_mode/components/header.html +0 -45
- swarm/templates/rest_mode/components/main_chat_pane.html +0 -41
- swarm/templates/rest_mode/components/settings_dialog.html +0 -97
- swarm/templates/rest_mode/components/splash_screen.html +0 -7
- swarm/templates/rest_mode/components/top_bar.html +0 -28
- swarm/templates/rest_mode/message_ui.html +0 -50
- swarm/templates/rest_mode/slackbot.html +0 -30
- swarm/templates/simple_blueprint_page.html +0 -24
- swarm/templates/websocket_partials/final_system_message.html +0 -3
- swarm/templates/websocket_partials/system_message.html +0 -4
- swarm/templates/websocket_partials/user_message.html +0 -5
- swarm/utils/ansi_box.py +0 -34
- swarm/utils/disable_tracing.py +0 -38
- swarm/utils/log_utils.py +0 -63
- swarm/utils/openai_patch.py +0 -33
- swarm/ux/ansi_box.py +0 -43
- swarm/ux/spinner.py +0 -53
- {open_swarm-0.1.1745275181.dist-info → open_swarm-0.1.1748636259.dist-info}/licenses/LICENSE +0 -0
- /swarm/{core → extensions/blueprint}/blueprint_utils.py +0 -0
- /swarm/{core → extensions/blueprint}/common_utils.py +0 -0
- /swarm/{core → extensions/config}/setup_wizard.py +0 -0
- /swarm/{blueprints/rue_code → extensions/config/utils}/__init__.py +0 -0
- /swarm/{core → extensions/config}/utils/logger.py +0 -0
- /swarm/{core → extensions/launchers}/swarm_wrapper.py +0 -0
swarm/serializers.py
CHANGED
@@ -1,103 +1,12 @@
|
|
1
1
|
from rest_framework import serializers
|
2
|
-
from swarm.models import ChatMessage
|
3
|
-
import logging
|
4
|
-
|
5
|
-
logger = logging.getLogger(__name__)
|
6
|
-
print_logger = logging.getLogger('print_debug')
|
7
|
-
|
8
|
-
class MessageSerializer(serializers.Serializer):
|
9
|
-
role = serializers.ChoiceField(choices=["system", "user", "assistant", "tool"])
|
10
|
-
# Content is CharField, allows null/blank by default
|
11
|
-
content = serializers.CharField(allow_null=True, required=False, allow_blank=True)
|
12
|
-
name = serializers.CharField(required=False, allow_blank=True)
|
13
|
-
|
14
|
-
# Removed validate_content
|
15
|
-
|
16
|
-
def validate(self, data):
|
17
|
-
"""Validate message structure based on role."""
|
18
|
-
print_logger.debug(f"MessageSerializer.validate received data: {data}")
|
19
|
-
role = data.get('role')
|
20
|
-
content = data.get('content', None)
|
21
|
-
name = data.get('name')
|
22
|
-
|
23
|
-
# Role validation
|
24
|
-
if 'role' not in data:
|
25
|
-
raise serializers.ValidationError({"role": ["This field is required."]})
|
26
|
-
|
27
|
-
# Content requiredness validation (based on role)
|
28
|
-
content_required = role in ['system', 'user', 'assistant', 'tool']
|
29
|
-
content_present = 'content' in data
|
30
|
-
|
31
|
-
if content_required:
|
32
|
-
if not content_present:
|
33
|
-
raise serializers.ValidationError({"content": ["This field is required."]})
|
34
|
-
# Null/Blank checks are handled by field definition (allow_null/allow_blank)
|
35
|
-
# Type check will happen in ChatCompletionRequestSerializer.validate_messages
|
36
|
-
|
37
|
-
# Name validation for tool role
|
38
|
-
if role == 'tool' and not name:
|
39
|
-
raise serializers.ValidationError({"name": ["This field is required for role 'tool'."]})
|
40
|
-
|
41
|
-
print_logger.debug(f"MessageSerializer.validate PASSED for data: {data}")
|
42
|
-
return data
|
43
|
-
|
44
|
-
class ChatCompletionRequestSerializer(serializers.Serializer):
|
45
|
-
model = serializers.CharField(max_length=255)
|
46
|
-
messages = MessageSerializer(many=True, min_length=1)
|
47
|
-
stream = serializers.BooleanField(default=False)
|
48
|
-
params = serializers.JSONField(required=False, allow_null=True)
|
49
|
-
|
50
|
-
def validate(self, data):
|
51
|
-
"""Perform object-level validation."""
|
52
|
-
model_value = self.initial_data.get('model')
|
53
|
-
logger.debug(f"Top-level validate checking model type. Got: {type(model_value)}, value: {model_value}")
|
54
|
-
if model_value is not None and not isinstance(model_value, str):
|
55
|
-
raise serializers.ValidationError({"model": ["Field 'model' must be a string."]})
|
56
|
-
# Messages validation (including content type) happens in validate_messages
|
57
|
-
return data
|
58
|
-
|
59
|
-
def validate_messages(self, value):
|
60
|
-
"""
|
61
|
-
Validate the messages list itself and perform raw type checks.
|
62
|
-
'value' here is the list *after* MessageSerializer has run on each item.
|
63
|
-
We need to inspect `self.initial_data` for the raw types.
|
64
|
-
"""
|
65
|
-
if not value:
|
66
|
-
raise serializers.ValidationError("Messages list cannot be empty.")
|
67
|
-
|
68
|
-
# Access raw message data from initial_data for type checking
|
69
|
-
raw_messages = self.initial_data.get('messages', [])
|
70
|
-
if not isinstance(raw_messages, list):
|
71
|
-
# This case is handled by ListField implicitly, but good to be explicit
|
72
|
-
raise serializers.ValidationError("Expected a list of message items.")
|
73
|
-
|
74
|
-
errors = []
|
75
|
-
for i, raw_msg in enumerate(raw_messages):
|
76
|
-
msg_errors = {}
|
77
|
-
if not isinstance(raw_msg, dict):
|
78
|
-
# If the item itself isn't a dict, add error and skip further checks for it
|
79
|
-
errors.append({f"item_{i}": "Each message must be a dictionary."})
|
80
|
-
continue
|
81
|
-
|
82
|
-
# *** Check raw content type here ***
|
83
|
-
content = raw_msg.get('content', None)
|
84
|
-
if 'content' in raw_msg and content is not None and not isinstance(content, str):
|
85
|
-
msg_errors['content'] = ["Content must be a string or null."] # Match test assertion
|
86
|
-
|
87
|
-
# Add other raw checks if needed (e.g., role type)
|
88
|
-
|
89
|
-
if msg_errors:
|
90
|
-
errors.append(msg_errors) # Append errors for this specific message index
|
91
|
-
|
92
|
-
if errors:
|
93
|
-
# Raise a single validation error containing all message-specific errors
|
94
|
-
raise serializers.ValidationError(errors)
|
95
|
-
|
96
|
-
# Return the processed 'value' which passed MessageSerializer validation
|
97
|
-
return value
|
2
|
+
from swarm.models import ChatMessage, ChatConversation
|
98
3
|
|
99
4
|
class ChatMessageSerializer(serializers.ModelSerializer):
|
100
5
|
class Meta:
|
101
6
|
model = ChatMessage
|
102
7
|
fields = '__all__'
|
103
8
|
|
9
|
+
class ChatConversationSerializer(serializers.ModelSerializer):
|
10
|
+
class Meta:
|
11
|
+
model = ChatConversation
|
12
|
+
fields = '__all__'
|
swarm/settings.py
CHANGED
@@ -1,46 +1,48 @@
|
|
1
1
|
"""
|
2
2
|
Django settings for swarm project.
|
3
|
+
Includes Pydantic base settings for Swarm Core.
|
3
4
|
"""
|
4
5
|
|
6
|
+
import logging
|
5
7
|
import os
|
8
|
+
import sys
|
9
|
+
from enum import Enum
|
6
10
|
from pathlib import Path
|
7
|
-
from
|
8
|
-
import
|
11
|
+
from pydantic import Field # Import Field from Pydantic v2+
|
12
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
13
|
+
|
14
|
+
# --- Pydantic Settings for Swarm Core ---
|
15
|
+
class LogFormat(str, Enum):
|
16
|
+
standard = "[%(levelname)s] %(asctime)s - %(name)s:%(lineno)d - %(message)s"
|
17
|
+
simple = "[%(levelname)s] %(name)s - %(message)s"
|
9
18
|
|
10
|
-
|
19
|
+
class Settings(BaseSettings):
|
20
|
+
model_config = SettingsConfigDict(env_prefix='SWARM_', case_sensitive=False)
|
11
21
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
# print(f"[Settings] Attempted to load .env from: {dotenv_path}")
|
16
|
-
# ---
|
22
|
+
log_level: str = Field(default='INFO', description="Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)")
|
23
|
+
log_format: LogFormat = Field(default=LogFormat.standard, description="Logging format")
|
24
|
+
debug: bool = Field(default=False, description="Global debug flag")
|
17
25
|
|
18
|
-
|
19
|
-
DEBUG = os.getenv('DJANGO_DEBUG', 'True').lower() in ('true', '1', 't')
|
20
|
-
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')
|
26
|
+
# --- Standard Django Settings ---
|
21
27
|
|
22
|
-
#
|
23
|
-
|
24
|
-
|
28
|
+
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
29
|
+
BASE_DIR = Path(__file__).resolve().parent.parent
|
30
|
+
PROJECT_ROOT = BASE_DIR.parent
|
31
|
+
if str(PROJECT_ROOT) not in sys.path:
|
32
|
+
sys.path.insert(0, str(PROJECT_ROOT))
|
25
33
|
|
26
|
-
|
27
|
-
ENABLE_API_AUTH = bool(_raw_api_token)
|
28
|
-
SWARM_API_KEY = _raw_api_token # Assign the loaded token (or None)
|
34
|
+
BLUEPRINTS_DIR = PROJECT_ROOT / 'blueprints'
|
29
35
|
|
30
|
-
if
|
31
|
-
|
32
|
-
assert SWARM_API_KEY is not None, "SWARM_API_KEY cannot be None when ENABLE_API_AUTH is True"
|
33
|
-
# print(f"[Settings] SWARM_API_KEY loaded: {SWARM_API_KEY[:4]}...{SWARM_API_KEY[-4:]}")
|
34
|
-
# print("[Settings] ENABLE_API_AUTH is True.")
|
35
|
-
else:
|
36
|
-
# print("[Settings] API_AUTH_TOKEN env var not set. SWARM_API_KEY is None.")
|
37
|
-
# print("[Settings] ENABLE_API_AUTH is False.")
|
38
|
-
pass
|
36
|
+
# --- Determine if running under pytest ---
|
37
|
+
TESTING = 'pytest' in sys.modules
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
#
|
39
|
+
# Quick-start development settings - unsuitable for production
|
40
|
+
SECRET_KEY = os.getenv('DJANGO_SECRET_KEY', 'django-insecure-YOUR_FALLBACK_KEY_HERE_CHANGE_ME')
|
41
|
+
# Use the Pydantic setting value for Django's DEBUG
|
42
|
+
DEBUG = Settings().debug # Read from instantiated Pydantic settings
|
43
|
+
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', '*').split(',')
|
43
44
|
|
45
|
+
# --- Application definition ---
|
44
46
|
INSTALLED_APPS = [
|
45
47
|
'django.contrib.admin',
|
46
48
|
'django.contrib.auth',
|
@@ -48,20 +50,61 @@ INSTALLED_APPS = [
|
|
48
50
|
'django.contrib.sessions',
|
49
51
|
'django.contrib.messages',
|
50
52
|
'django.contrib.staticfiles',
|
53
|
+
# Third-party apps
|
51
54
|
'rest_framework',
|
52
55
|
'rest_framework.authtoken',
|
53
56
|
'drf_spectacular',
|
54
|
-
|
57
|
+
# Local apps
|
58
|
+
'swarm.apps.SwarmConfig',
|
55
59
|
]
|
56
60
|
|
61
|
+
# # --- Conditionally add blueprint apps for TESTING ---
|
62
|
+
# if TESTING:
|
63
|
+
# _test_apps_to_add = ['blueprints.university']
|
64
|
+
# for app in _test_apps_to_add:
|
65
|
+
# if app not in INSTALLED_APPS:
|
66
|
+
# INSTALLED_APPS.insert(0, app)
|
67
|
+
# logging.info(f"Settings [TESTING]: Added '{app}' to INSTALLED_APPS.")
|
68
|
+
# if 'SWARM_BLUEPRINTS' not in os.environ:
|
69
|
+
# os.environ['SWARM_BLUEPRINTS'] = 'university'
|
70
|
+
# logging.info(f"Settings [TESTING]: Set SWARM_BLUEPRINTS='university'")
|
71
|
+
# else:
|
72
|
+
# # --- Dynamic App Loading for Production/Development ---
|
73
|
+
# _INITIAL_BLUEPRINT_APPS = []
|
74
|
+
# _swarm_blueprints_env = os.getenv('SWARM_BLUEPRINTS')
|
75
|
+
# _log_source = "Not Set"
|
76
|
+
# if _swarm_blueprints_env:
|
77
|
+
# _blueprint_names = [name.strip() for name in _swarm_blueprints_env.split(',') if name.strip()]
|
78
|
+
# _INITIAL_BLUEPRINT_APPS = [f'blueprints.{name}' for name in _blueprint_names if name.replace('_', '').isidentifier()]
|
79
|
+
# _log_source = "SWARM_BLUEPRINTS env var"
|
80
|
+
# logging.info(f"Settings: Found blueprints from env var: {_INITIAL_BLUEPRINT_APPS}")
|
81
|
+
# else:
|
82
|
+
# _log_source = "directory scan"
|
83
|
+
# try:
|
84
|
+
# if BLUEPRINTS_DIR.is_dir():
|
85
|
+
# for item in BLUEPRINTS_DIR.iterdir():
|
86
|
+
# if item.is_dir() and (item / '__init__.py').exists():
|
87
|
+
# if item.name.replace('_', '').isidentifier():
|
88
|
+
# _INITIAL_BLUEPRINT_APPS.append(f'blueprints.{item.name}')
|
89
|
+
# logging.info(f"Settings: Found blueprints from directory scan: {_INITIAL_BLUEPRINT_APPS}")
|
90
|
+
# except Exception as e:
|
91
|
+
# logging.error(f"Settings: Error discovering blueprint apps during initial load: {e}")
|
92
|
+
|
93
|
+
# for app in _INITIAL_BLUEPRINT_APPS:
|
94
|
+
# if app not in INSTALLED_APPS:
|
95
|
+
# INSTALLED_APPS.append(app)
|
96
|
+
# logging.info(f"Settings [{_log_source}]: Added '{app}' to INSTALLED_APPS.")
|
97
|
+
# # --- End App Loading Logic ---
|
98
|
+
|
99
|
+
if isinstance(INSTALLED_APPS, tuple): INSTALLED_APPS = list(INSTALLED_APPS)
|
100
|
+
logging.info(f"Settings: Final INSTALLED_APPS = {INSTALLED_APPS}")
|
101
|
+
|
57
102
|
MIDDLEWARE = [
|
58
103
|
'django.middleware.security.SecurityMiddleware',
|
59
104
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
60
105
|
'django.middleware.common.CommonMiddleware',
|
61
106
|
'django.middleware.csrf.CsrfViewMiddleware',
|
62
107
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
63
|
-
# Add custom middleware to handle async user loading after standard auth
|
64
|
-
'swarm.middleware.AsyncAuthMiddleware',
|
65
108
|
'django.contrib.messages.middleware.MessageMiddleware',
|
66
109
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
67
110
|
]
|
@@ -71,7 +114,7 @@ ROOT_URLCONF = 'swarm.urls'
|
|
71
114
|
TEMPLATES = [
|
72
115
|
{
|
73
116
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
74
|
-
'DIRS': [BASE_DIR
|
117
|
+
'DIRS': [BASE_DIR / 'templates'],
|
75
118
|
'APP_DIRS': True,
|
76
119
|
'OPTIONS': {
|
77
120
|
'context_processors': [
|
@@ -85,93 +128,62 @@ TEMPLATES = [
|
|
85
128
|
]
|
86
129
|
|
87
130
|
WSGI_APPLICATION = 'swarm.wsgi.application'
|
88
|
-
|
89
|
-
|
90
|
-
DATABASES = {
|
91
|
-
|
92
|
-
'ENGINE': 'django.db.backends.sqlite3',
|
93
|
-
'NAME': os.environ.get('DJANGO_DB_NAME', '/tmp/db.sqlite3'),
|
94
|
-
'TEST': {
|
95
|
-
'NAME': os.environ.get('DJANGO_TEST_DB_NAME', '/tmp/test_db.sqlite3'),
|
96
|
-
'OPTIONS': {
|
97
|
-
'timeout': 20,
|
98
|
-
'init_command': "PRAGMA journal_mode=WAL;",
|
99
|
-
},
|
100
|
-
},
|
101
|
-
}
|
102
|
-
}
|
131
|
+
|
132
|
+
SQLITE_DB_PATH = os.getenv('SQLITE_DB_PATH', BASE_DIR / 'db.sqlite3')
|
133
|
+
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': SQLITE_DB_PATH } }
|
134
|
+
DJANGO_DATABASE = DATABASES['default']
|
103
135
|
|
104
136
|
AUTH_PASSWORD_VALIDATORS = [
|
105
|
-
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'
|
106
|
-
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'
|
107
|
-
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'
|
108
|
-
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'
|
137
|
+
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
|
138
|
+
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
|
139
|
+
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
|
140
|
+
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
|
109
141
|
]
|
110
142
|
|
111
|
-
LANGUAGE_CODE = 'en-us'
|
112
|
-
TIME_ZONE = 'UTC'
|
113
|
-
USE_I18N = True
|
114
|
-
USE_TZ = True
|
143
|
+
LANGUAGE_CODE = 'en-us'; TIME_ZONE = 'UTC'; USE_I18N = True; USE_TZ = True
|
115
144
|
|
116
|
-
STATIC_URL = 'static/'
|
117
|
-
|
118
|
-
STATICFILES_DIRS = [ BASE_DIR / "swarm" / "static", ]
|
145
|
+
STATIC_URL = '/static/'; STATIC_ROOT = BASE_DIR / 'staticfiles'
|
146
|
+
STATICFILES_DIRS = [ BASE_DIR / 'static', BASE_DIR / 'assets' ]
|
119
147
|
|
120
148
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
121
149
|
|
122
150
|
REST_FRAMEWORK = {
|
123
|
-
'DEFAULT_AUTHENTICATION_CLASSES': [
|
124
|
-
'swarm.auth.StaticTokenAuthentication',
|
125
|
-
'swarm.auth.CustomSessionAuthentication',
|
126
|
-
],
|
127
|
-
# *** IMPORTANT: Add DEFAULT_PERMISSION_CLASSES ***
|
128
|
-
# If ENABLE_API_AUTH is False, we might want to allow any access for testing.
|
129
|
-
# If ENABLE_API_AUTH is True, we require HasValidTokenOrSession.
|
130
|
-
# We need to set this dynamically based on ENABLE_API_AUTH.
|
131
|
-
# A simple way is to set it here, but a cleaner way might involve middleware
|
132
|
-
# or overriding get_permissions in views. For now, let's adjust this:
|
133
|
-
'DEFAULT_PERMISSION_CLASSES': [
|
134
|
-
# If auth is enabled, require our custom permission
|
135
|
-
'swarm.permissions.HasValidTokenOrSession' if ENABLE_API_AUTH else
|
136
|
-
# Otherwise, allow anyone (useful for dev when token isn't set)
|
137
|
-
'rest_framework.permissions.AllowAny'
|
138
|
-
],
|
139
151
|
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
|
152
|
+
'DEFAULT_AUTHENTICATION_CLASSES': (
|
153
|
+
'swarm.auth.EnvOrTokenAuthentication',
|
154
|
+
'rest_framework.authentication.TokenAuthentication',
|
155
|
+
'rest_framework.authentication.SessionAuthentication',
|
156
|
+
),
|
157
|
+
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',)
|
140
158
|
}
|
141
159
|
|
142
160
|
SPECTACULAR_SETTINGS = {
|
143
161
|
'TITLE': 'Open Swarm API',
|
144
|
-
'DESCRIPTION': 'API for
|
145
|
-
'VERSION': '0.
|
162
|
+
'DESCRIPTION': 'API for the Open Swarm multi-agent collaboration framework.',
|
163
|
+
'VERSION': '1.0.0',
|
146
164
|
'SERVE_INCLUDE_SCHEMA': False,
|
165
|
+
'SERVE_PERMISSIONS': ['rest_framework.permissions.AllowAny'],
|
147
166
|
}
|
148
167
|
|
149
168
|
LOGGING = {
|
150
|
-
'version': 1,
|
151
|
-
'
|
152
|
-
'
|
153
|
-
'verbose': { 'format': '[{levelname}] {asctime} - {name}:{lineno} - {message}', 'style': '{', },
|
154
|
-
'simple': { 'format': '[{levelname}] {message}', 'style': '{', },
|
155
|
-
},
|
156
|
-
'handlers': {
|
157
|
-
'console': { 'class': 'logging.StreamHandler', 'formatter': 'verbose', },
|
158
|
-
},
|
169
|
+
'version': 1, 'disable_existing_loggers': False,
|
170
|
+
'formatters': { 'standard': { 'format': '[%(levelname)s] %(asctime)s - %(name)s:%(lineno)d - %(message)s' }, },
|
171
|
+
'handlers': { 'console': { 'level': 'DEBUG' if DEBUG else 'INFO', 'class': 'logging.StreamHandler', 'formatter': 'standard', }, },
|
159
172
|
'loggers': {
|
160
|
-
'django': { 'handlers': ['console'], 'level':
|
161
|
-
'
|
162
|
-
'swarm
|
163
|
-
'swarm.
|
164
|
-
'
|
165
|
-
'blueprint_django_chat': { 'handlers': ['console'], 'level': 'DEBUG', 'propagate': False, },
|
166
|
-
'print_debug': { 'handlers': ['console'], 'level': 'DEBUG', 'propagate': False, },
|
173
|
+
'django': { 'handlers': ['console'], 'level': 'INFO', 'propagate': False, },
|
174
|
+
'django.request': { 'handlers': ['console'], 'level': 'WARNING', 'propagate': False, },
|
175
|
+
'swarm': { 'handlers': ['console'], 'level': 'DEBUG' if DEBUG else 'INFO', 'propagate': False, },
|
176
|
+
'swarm.extensions': { 'handlers': ['console'], 'level': 'DEBUG' if DEBUG else 'INFO', 'propagate': False, },
|
177
|
+
'blueprints': { 'handlers': ['console'], 'level': 'DEBUG' if DEBUG else 'INFO', 'propagate': False, },
|
167
178
|
},
|
168
|
-
'root': { 'handlers': ['console'], 'level': 'WARNING', },
|
169
179
|
}
|
170
180
|
|
181
|
+
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend']
|
182
|
+
LOGIN_URL = '/accounts/login/'; LOGIN_REDIRECT_URL = '/chatbot/'
|
183
|
+
|
171
184
|
REDIS_HOST = os.getenv('REDIS_HOST', 'localhost')
|
172
|
-
REDIS_PORT = int(os.getenv('REDIS_PORT',
|
185
|
+
REDIS_PORT = int(os.getenv('REDIS_PORT', 6379))
|
173
186
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
CSRF_TRUSTED_ORIGINS = os.getenv('DJANGO_CSRF_TRUSTED_ORIGINS', 'http://localhost:8000,http://127.0.0.1:8000').split(',')
|
187
|
+
if TESTING:
|
188
|
+
print("Pytest detected: Adjusting settings for testing.")
|
189
|
+
DATABASES['default']['NAME'] = ':memory:'
|
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,
|
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.
|
9
|
-
|
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
|
-
|
14
|
-
|
15
|
-
from swarm.views.
|
16
|
-
|
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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
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
|
-
|
48
|
-
|
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
|
-
|
51
|
-
|
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
|
-
|
54
|
-
|
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
|
-
|
57
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
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
|
-
#
|
66
|
-
|
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
|
-
#
|
70
|
-
|
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}")
|
swarm/utils/context_utils.py
CHANGED
@@ -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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
elif role == "
|
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
|
swarm/utils/general_utils.py
CHANGED
@@ -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
|
"""
|