open-swarm 0.1.1743070217__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.1743070217.dist-info/METADATA +258 -0
- open_swarm-0.1.1743070217.dist-info/RECORD +89 -0
- open_swarm-0.1.1743070217.dist-info/WHEEL +5 -0
- open_swarm-0.1.1743070217.dist-info/entry_points.txt +3 -0
- open_swarm-0.1.1743070217.dist-info/licenses/LICENSE +21 -0
- open_swarm-0.1.1743070217.dist-info/top_level.txt +1 -0
- swarm/__init__.py +3 -0
- swarm/agent/__init__.py +7 -0
- swarm/agent/agent.py +49 -0
- swarm/apps.py +53 -0
- swarm/auth.py +56 -0
- swarm/consumers.py +141 -0
- swarm/core.py +326 -0
- swarm/extensions/__init__.py +1 -0
- swarm/extensions/blueprint/__init__.py +36 -0
- swarm/extensions/blueprint/agent_utils.py +45 -0
- swarm/extensions/blueprint/blueprint_base.py +562 -0
- swarm/extensions/blueprint/blueprint_discovery.py +112 -0
- swarm/extensions/blueprint/blueprint_utils.py +17 -0
- swarm/extensions/blueprint/common_utils.py +12 -0
- swarm/extensions/blueprint/django_utils.py +203 -0
- swarm/extensions/blueprint/interactive_mode.py +102 -0
- swarm/extensions/blueprint/modes/rest_mode.py +37 -0
- swarm/extensions/blueprint/output_utils.py +95 -0
- swarm/extensions/blueprint/spinner.py +91 -0
- swarm/extensions/cli/__init__.py +0 -0
- swarm/extensions/cli/blueprint_runner.py +251 -0
- swarm/extensions/cli/cli_args.py +88 -0
- swarm/extensions/cli/commands/__init__.py +0 -0
- swarm/extensions/cli/commands/blueprint_management.py +31 -0
- swarm/extensions/cli/commands/config_management.py +15 -0
- swarm/extensions/cli/commands/edit_config.py +77 -0
- swarm/extensions/cli/commands/list_blueprints.py +22 -0
- swarm/extensions/cli/commands/validate_env.py +57 -0
- swarm/extensions/cli/commands/validate_envvars.py +39 -0
- swarm/extensions/cli/interactive_shell.py +41 -0
- swarm/extensions/cli/main.py +36 -0
- swarm/extensions/cli/selection.py +43 -0
- swarm/extensions/cli/utils/discover_commands.py +32 -0
- swarm/extensions/cli/utils/env_setup.py +15 -0
- swarm/extensions/cli/utils.py +105 -0
- swarm/extensions/config/__init__.py +6 -0
- swarm/extensions/config/config_loader.py +208 -0
- swarm/extensions/config/config_manager.py +258 -0
- swarm/extensions/config/server_config.py +49 -0
- swarm/extensions/config/setup_wizard.py +103 -0
- swarm/extensions/config/utils/__init__.py +0 -0
- swarm/extensions/config/utils/logger.py +36 -0
- swarm/extensions/launchers/__init__.py +1 -0
- swarm/extensions/launchers/build_launchers.py +14 -0
- swarm/extensions/launchers/build_swarm_wrapper.py +12 -0
- swarm/extensions/launchers/swarm_api.py +68 -0
- swarm/extensions/launchers/swarm_cli.py +304 -0
- swarm/extensions/launchers/swarm_wrapper.py +29 -0
- swarm/extensions/mcp/__init__.py +1 -0
- swarm/extensions/mcp/cache_utils.py +36 -0
- swarm/extensions/mcp/mcp_client.py +341 -0
- swarm/extensions/mcp/mcp_constants.py +7 -0
- swarm/extensions/mcp/mcp_tool_provider.py +110 -0
- swarm/llm/chat_completion.py +195 -0
- swarm/messages.py +132 -0
- swarm/migrations/0010_initial_chat_models.py +51 -0
- swarm/migrations/__init__.py +0 -0
- swarm/models.py +45 -0
- swarm/repl/__init__.py +1 -0
- swarm/repl/repl.py +87 -0
- swarm/serializers.py +12 -0
- swarm/settings.py +189 -0
- swarm/tool_executor.py +239 -0
- swarm/types.py +126 -0
- swarm/urls.py +89 -0
- swarm/util.py +124 -0
- swarm/utils/color_utils.py +40 -0
- swarm/utils/context_utils.py +272 -0
- swarm/utils/general_utils.py +162 -0
- swarm/utils/logger.py +61 -0
- swarm/utils/logger_setup.py +25 -0
- swarm/utils/message_sequence.py +173 -0
- swarm/utils/message_utils.py +95 -0
- swarm/utils/redact.py +68 -0
- swarm/views/__init__.py +41 -0
- swarm/views/api_views.py +46 -0
- swarm/views/chat_views.py +76 -0
- swarm/views/core_views.py +118 -0
- swarm/views/message_views.py +40 -0
- swarm/views/model_views.py +135 -0
- swarm/views/utils.py +457 -0
- swarm/views/web_views.py +149 -0
- swarm/wsgi.py +16 -0
swarm/views/web_views.py
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
"""
|
2
|
+
Web UI views for Open Swarm MCP Core.
|
3
|
+
Handles rendering index, blueprint pages, login, and serving config.
|
4
|
+
"""
|
5
|
+
import os
|
6
|
+
import json
|
7
|
+
from pathlib import Path
|
8
|
+
from django.shortcuts import render, redirect
|
9
|
+
from django.http import JsonResponse, HttpResponse
|
10
|
+
from django.conf import settings
|
11
|
+
from django.views.decorators.csrf import csrf_exempt
|
12
|
+
from django.contrib.auth import authenticate, login
|
13
|
+
from django.contrib.auth.models import User
|
14
|
+
|
15
|
+
from swarm.utils.logger_setup import setup_logger
|
16
|
+
# Import the function to discover blueprints dynamically
|
17
|
+
from swarm.extensions.blueprint.blueprint_discovery import discover_blueprints
|
18
|
+
# Import the setting for the blueprints directory
|
19
|
+
from swarm.settings import BLUEPRINTS_DIR
|
20
|
+
# Import config loader if needed, or assume config is loaded elsewhere
|
21
|
+
from swarm.extensions.config.config_loader import load_server_config
|
22
|
+
|
23
|
+
logger = setup_logger(__name__)
|
24
|
+
|
25
|
+
@csrf_exempt
|
26
|
+
def index(request):
|
27
|
+
"""Render the main index page with dynamically discovered blueprint options."""
|
28
|
+
logger.debug("Rendering index page")
|
29
|
+
try:
|
30
|
+
# Discover blueprints dynamically each time the index is loaded
|
31
|
+
# Consider caching this if performance becomes an issue
|
32
|
+
discovered_metadata = discover_blueprints(directories=[BLUEPRINTS_DIR])
|
33
|
+
blueprint_names = list(discovered_metadata.keys())
|
34
|
+
logger.debug(f"Rendering index with blueprints: {blueprint_names}")
|
35
|
+
except Exception as e:
|
36
|
+
logger.error(f"Error discovering blueprints for index page: {e}", exc_info=True)
|
37
|
+
blueprint_names = [] # Show empty list on error
|
38
|
+
|
39
|
+
context = {
|
40
|
+
"dark_mode": request.session.get('dark_mode', True),
|
41
|
+
"enable_admin": os.getenv("ENABLE_ADMIN", "false").lower() in ("true", "1", "t"),
|
42
|
+
"blueprints": blueprint_names # Use the dynamically discovered list
|
43
|
+
}
|
44
|
+
return render(request, "index.html", context)
|
45
|
+
|
46
|
+
@csrf_exempt
|
47
|
+
def blueprint_webpage(request, blueprint_name):
|
48
|
+
"""Render a simple webpage for querying agents of a specific blueprint."""
|
49
|
+
logger.debug(f"Received request for blueprint webpage: '{blueprint_name}'")
|
50
|
+
try:
|
51
|
+
# Discover blueprints to check if the requested one exists
|
52
|
+
discovered_metadata = discover_blueprints(directories=[BLUEPRINTS_DIR])
|
53
|
+
if blueprint_name not in discovered_metadata:
|
54
|
+
logger.warning(f"Blueprint '{blueprint_name}' not found during discovery.")
|
55
|
+
available_blueprints = "".join(f"<li>{bp}</li>" for bp in discovered_metadata.keys())
|
56
|
+
return HttpResponse(
|
57
|
+
f"<h1>Blueprint '{blueprint_name}' not found.</h1><p>Available blueprints:</p><ul>{available_blueprints}</ul>",
|
58
|
+
status=404,
|
59
|
+
)
|
60
|
+
# Blueprint exists, render the page
|
61
|
+
context = {
|
62
|
+
"blueprint_name": blueprint_name,
|
63
|
+
"dark_mode": request.session.get('dark_mode', True),
|
64
|
+
"is_chatbot": False # Adjust if needed based on blueprint type
|
65
|
+
}
|
66
|
+
return render(request, "simple_blueprint_page.html", context)
|
67
|
+
except Exception as e:
|
68
|
+
logger.error(f"Error processing blueprint page for '{blueprint_name}': {e}", exc_info=True)
|
69
|
+
return HttpResponse("<h1>Error loading blueprint page.</h1>", status=500)
|
70
|
+
|
71
|
+
|
72
|
+
@csrf_exempt
|
73
|
+
def custom_login(request):
|
74
|
+
"""Handle custom login at /accounts/login/, redirecting to 'next' URL on success."""
|
75
|
+
if request.method == "POST":
|
76
|
+
username = request.POST.get("username")
|
77
|
+
password = request.POST.get("password")
|
78
|
+
user = authenticate(request, username=username, password=password)
|
79
|
+
|
80
|
+
if user is not None:
|
81
|
+
# User authenticated successfully
|
82
|
+
login(request, user)
|
83
|
+
next_url = request.GET.get("next", "/chatbot/") # Default redirect
|
84
|
+
logger.info(f"User '{username}' logged in successfully. Redirecting to '{next_url}'.")
|
85
|
+
return redirect(next_url)
|
86
|
+
else:
|
87
|
+
# Authentication failed
|
88
|
+
logger.warning(f"Failed login attempt for user '{username}'.")
|
89
|
+
# Check if auto-login for 'testuser' is enabled (ONLY for development/testing)
|
90
|
+
enable_auth = os.getenv("ENABLE_API_AUTH", "true").lower() in ("true", "1", "t") # Default to TRUE
|
91
|
+
if not enable_auth:
|
92
|
+
logger.info("API Auth is disabled. Attempting auto-login for 'testuser'.")
|
93
|
+
try:
|
94
|
+
# Attempt to log in 'testuser' with a known password (e.g., 'testpass')
|
95
|
+
# Ensure this user/password exists in your DB or fixture
|
96
|
+
test_user = authenticate(request, username="testuser", password="testpass")
|
97
|
+
if test_user is not None:
|
98
|
+
login(request, test_user)
|
99
|
+
next_url = request.GET.get("next", "/chatbot/")
|
100
|
+
logger.info("Auto-logged in as 'testuser' because API auth is disabled. Redirecting.")
|
101
|
+
return redirect(next_url)
|
102
|
+
else:
|
103
|
+
logger.warning("Auto-login for 'testuser' failed (user/password incorrect or user doesn't exist).")
|
104
|
+
except Exception as auto_login_err:
|
105
|
+
logger.error(f"Error during 'testuser' auto-login attempt: {auto_login_err}")
|
106
|
+
|
107
|
+
# If authentication failed and auto-login didn't happen/failed
|
108
|
+
return render(request, "account/login.html", {"error": "Invalid username or password."})
|
109
|
+
|
110
|
+
# If GET request, just render the login form
|
111
|
+
return render(request, "account/login.html")
|
112
|
+
|
113
|
+
# Default config structure to return if the actual file is missing/invalid
|
114
|
+
DEFAULT_CONFIG = {
|
115
|
+
"llm": {
|
116
|
+
"default": {
|
117
|
+
"provider": "openai",
|
118
|
+
"model": "gpt-4o", # More modern default
|
119
|
+
"base_url": "https://api.openai.com/v1", # Standard OpenAI endpoint
|
120
|
+
"api_key": "", # API key should usually come from env vars
|
121
|
+
"temperature": 0.7
|
122
|
+
}
|
123
|
+
},
|
124
|
+
"mcpServers": {},
|
125
|
+
"blueprints": {}
|
126
|
+
}
|
127
|
+
|
128
|
+
@csrf_exempt # Usually not needed for GET, but doesn't hurt
|
129
|
+
def serve_swarm_config(request):
|
130
|
+
"""Serve the main swarm configuration file (swarm_config.json) as JSON."""
|
131
|
+
# Construct path relative to Django settings.BASE_DIR
|
132
|
+
config_path = Path(settings.BASE_DIR) / "swarm_config.json"
|
133
|
+
logger.debug(f"Attempting to serve swarm config from: {config_path}")
|
134
|
+
try:
|
135
|
+
# Use Path object's read_text method for cleaner file reading
|
136
|
+
config_content = config_path.read_text(encoding='utf-8')
|
137
|
+
config_data = json.loads(config_content)
|
138
|
+
logger.debug("Successfully loaded and parsed swarm_config.json")
|
139
|
+
return JsonResponse(config_data)
|
140
|
+
except FileNotFoundError:
|
141
|
+
logger.error(f"Configuration file swarm_config.json not found at {config_path}. Serving default config.")
|
142
|
+
return JsonResponse(DEFAULT_CONFIG, status=404) # Return 404 maybe? Or just default?
|
143
|
+
except json.JSONDecodeError as e:
|
144
|
+
logger.error(f"Error decoding JSON from {config_path}: {e}")
|
145
|
+
# Return an error response instead of default config on parse error
|
146
|
+
return JsonResponse({"error": f"Invalid JSON format in configuration file: {e}"}, status=500)
|
147
|
+
except Exception as e:
|
148
|
+
logger.error(f"Unexpected error serving swarm config: {e}", exc_info=True)
|
149
|
+
return JsonResponse({"error": "An unexpected error occurred."}, status=500)
|
swarm/wsgi.py
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# src/swarm/wsgi.py
|
2
|
+
|
3
|
+
import os
|
4
|
+
from pathlib import Path
|
5
|
+
from dotenv import load_dotenv
|
6
|
+
from django.core.wsgi import get_wsgi_application
|
7
|
+
|
8
|
+
# Define the base directory
|
9
|
+
BASE_DIR = Path(__file__).resolve().parent.parent
|
10
|
+
|
11
|
+
# Load environment variables from .env file
|
12
|
+
load_dotenv(dotenv_path=BASE_DIR / '.env')
|
13
|
+
|
14
|
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'swarm.settings')
|
15
|
+
|
16
|
+
application = get_wsgi_application()
|