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
File without changes
|
@@ -0,0 +1,251 @@
|
|
1
|
+
# src/swarm/extensions/blueprint/modes/cli_mode/blueprint_runner.py
|
2
|
+
|
3
|
+
import importlib.util
|
4
|
+
import os
|
5
|
+
import sys
|
6
|
+
import logging
|
7
|
+
from typing import Optional, Dict, Any, List
|
8
|
+
import asyncio
|
9
|
+
import argparse
|
10
|
+
|
11
|
+
from swarm.utils.general_utils import color_text
|
12
|
+
|
13
|
+
# Initialize logger for this module
|
14
|
+
from swarm.utils.logger_setup import setup_logger
|
15
|
+
|
16
|
+
logger = setup_logger(__name__)
|
17
|
+
|
18
|
+
|
19
|
+
def load_blueprint(blueprint_path: str) -> Any:
|
20
|
+
"""
|
21
|
+
Dynamically load a blueprint module from the given file path.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
blueprint_path (str): Path to the blueprint's Python file.
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
Any: The loaded blueprint module.
|
28
|
+
|
29
|
+
Raises:
|
30
|
+
ImportError: If the module cannot be imported.
|
31
|
+
"""
|
32
|
+
spec = importlib.util.spec_from_file_location("blueprint_module", blueprint_path)
|
33
|
+
print(f"DEBUG: Attempting to load blueprint at path: {blueprint_path}")
|
34
|
+
module = importlib.util.module_from_spec(spec)
|
35
|
+
try:
|
36
|
+
spec.loader.exec_module(module) # type: ignore
|
37
|
+
logger.info(f"Successfully loaded blueprint from {blueprint_path}")
|
38
|
+
except Exception as e:
|
39
|
+
logger.error(f"Failed to import blueprint at {blueprint_path}: {e}")
|
40
|
+
raise ImportError(f"Failed to import blueprint at {blueprint_path}: {e}")
|
41
|
+
return module
|
42
|
+
|
43
|
+
|
44
|
+
def run_blueprint_framework(blueprint_module: Any) -> None:
|
45
|
+
"""
|
46
|
+
Runs the blueprint in framework integration mode by invoking its execute() function.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
blueprint_module: The loaded blueprint module.
|
50
|
+
|
51
|
+
Raises:
|
52
|
+
AttributeError: If the blueprint does not have an execute() function.
|
53
|
+
"""
|
54
|
+
if not hasattr(blueprint_module, 'execute'):
|
55
|
+
logger.error("The blueprint does not have an execute() function.")
|
56
|
+
raise AttributeError("The blueprint does not have an execute() function.")
|
57
|
+
|
58
|
+
execute_func = blueprint_module.execute
|
59
|
+
|
60
|
+
# Optionally, load configuration from environment or a config file
|
61
|
+
config = {}
|
62
|
+
|
63
|
+
try:
|
64
|
+
result = execute_func(config)
|
65
|
+
print("Execution Result:")
|
66
|
+
print("Status:", result.get("status"))
|
67
|
+
print("Messages:")
|
68
|
+
for msg in result.get("messages", []):
|
69
|
+
print(f"{msg.get('role')}: {msg.get('content')}")
|
70
|
+
print("Metadata:", result.get("metadata"))
|
71
|
+
logger.info(f"Blueprint executed successfully with result: {result}")
|
72
|
+
except Exception as e:
|
73
|
+
logger.error(f"Error executing blueprint: {e}")
|
74
|
+
print(f"Error executing blueprint: {e}")
|
75
|
+
|
76
|
+
|
77
|
+
def run_blueprint_interactive(blueprint_module: Any) -> None:
|
78
|
+
"""
|
79
|
+
Runs the blueprint in interactive standalone mode by invoking its interactive_mode() function.
|
80
|
+
|
81
|
+
Args:
|
82
|
+
blueprint_module: The loaded blueprint module.
|
83
|
+
|
84
|
+
Raises:
|
85
|
+
AttributeError: If the blueprint does not have an interactive_mode() function.
|
86
|
+
"""
|
87
|
+
if not hasattr(blueprint_module, 'interactive_mode'):
|
88
|
+
logger.error("The blueprint does not have an interactive_mode() function.")
|
89
|
+
raise AttributeError("The blueprint does not have an interactive_mode() function.")
|
90
|
+
|
91
|
+
interactive_func = blueprint_module.interactive_mode
|
92
|
+
|
93
|
+
try:
|
94
|
+
interactive_func()
|
95
|
+
logger.info("Blueprint interactive mode executed successfully.")
|
96
|
+
except Exception as e:
|
97
|
+
logger.error(f"Error in interactive mode: {e}")
|
98
|
+
print(f"Error in interactive mode: {e}")
|
99
|
+
|
100
|
+
|
101
|
+
async def run_blueprint_mode(
|
102
|
+
blueprints_to_load: List[str],
|
103
|
+
config: Dict[str, Any],
|
104
|
+
blueprints_metadata: Dict[str, Dict[str, Any]],
|
105
|
+
args: Any
|
106
|
+
) -> None:
|
107
|
+
"""
|
108
|
+
Executes the selected blueprints in the specified mode.
|
109
|
+
|
110
|
+
Args:
|
111
|
+
blueprints_to_load (List[str]): List of blueprint names to load.
|
112
|
+
config (Dict[str, Any]): Configuration dictionary.
|
113
|
+
blueprints_metadata (Dict[str, Dict[str, Any]]): Metadata of available blueprints.
|
114
|
+
args (Any): Parsed command-line arguments.
|
115
|
+
"""
|
116
|
+
for blueprint_name in blueprints_to_load:
|
117
|
+
blueprint_class = blueprints_metadata[blueprint_name].get("blueprint_class")
|
118
|
+
if not blueprint_class:
|
119
|
+
logger.warning(f"No blueprint_class defined for blueprint '{blueprint_name}'. Skipping.")
|
120
|
+
continue
|
121
|
+
|
122
|
+
blueprint_instance = blueprint_class(config=config)
|
123
|
+
logger.info(f"Running blueprint '{blueprint_name}' in '{args.mode}' mode.")
|
124
|
+
|
125
|
+
if args.mode == "cli":
|
126
|
+
try:
|
127
|
+
blueprint_instance.interactive_mode(stream=False)
|
128
|
+
logger.info(f"Blueprint '{blueprint_name}' executed in CLI mode.")
|
129
|
+
except Exception as e:
|
130
|
+
logger.error(f"Error running blueprint '{blueprint_name}' in CLI mode: {e}")
|
131
|
+
elif args.mode == "rest":
|
132
|
+
try:
|
133
|
+
# Implement REST mode logic here
|
134
|
+
# Example: blueprint_instance.rest_mode()
|
135
|
+
logger.info(f"Blueprint '{blueprint_name}' executed in REST mode.")
|
136
|
+
except Exception as e:
|
137
|
+
logger.error(f"Error running blueprint '{blueprint_name}' in REST mode: {e}")
|
138
|
+
elif args.mode == "mcp-host":
|
139
|
+
try:
|
140
|
+
# Implement MCP-host mode logic here
|
141
|
+
# Example: blueprint_instance.mcp_host_mode()
|
142
|
+
logger.info(f"Blueprint '{blueprint_name}' executed in MCP-host mode.")
|
143
|
+
except Exception as e:
|
144
|
+
logger.error(f"Error running blueprint '{blueprint_name}' in MCP-host mode: {e}")
|
145
|
+
else:
|
146
|
+
logger.error(f"Unsupported mode: {args.mode}")
|
147
|
+
print(color_text(f"Unsupported mode: {args.mode}", "red"))
|
148
|
+
|
149
|
+
|
150
|
+
def prompt_user_to_select_blueprint(blueprints_metadata: Dict[str, Dict[str, Any]]) -> Optional[str]:
|
151
|
+
"""
|
152
|
+
Allow the user to select a blueprint from available options.
|
153
|
+
|
154
|
+
Args:
|
155
|
+
blueprints_metadata (Dict[str, Dict[str, Any]]): Metadata of available blueprints.
|
156
|
+
|
157
|
+
Returns:
|
158
|
+
Optional[str]: Selected blueprint name, or None if no selection is made.
|
159
|
+
"""
|
160
|
+
if not blueprints_metadata:
|
161
|
+
logger.warning("No blueprints available. Blueprint selection skipped.")
|
162
|
+
print(color_text("No blueprints available. Please add blueprints to continue.", "yellow"))
|
163
|
+
return None
|
164
|
+
|
165
|
+
print("\nAvailable Blueprints:")
|
166
|
+
for idx, (key, metadata) in enumerate(blueprints_metadata.items(), start=1):
|
167
|
+
print(f"{idx}. {metadata.get('title', key)} - {metadata.get('description', 'No description available')}")
|
168
|
+
|
169
|
+
while True:
|
170
|
+
try:
|
171
|
+
choice_input = input("\nEnter the number of the blueprint you want to run (0 to cancel): ").strip()
|
172
|
+
if not choice_input:
|
173
|
+
print(f"Please enter a number between 0 and {len(blueprints_metadata)}.")
|
174
|
+
logger.warning("User entered empty input for blueprint selection.")
|
175
|
+
continue
|
176
|
+
|
177
|
+
choice = int(choice_input)
|
178
|
+
if choice == 0:
|
179
|
+
logger.info("User chose to cancel blueprint selection.")
|
180
|
+
return None
|
181
|
+
elif 1 <= choice <= len(blueprints_metadata):
|
182
|
+
selected_key = list(blueprints_metadata.keys())[choice - 1]
|
183
|
+
logger.info(f"User selected blueprint: '{selected_key}'")
|
184
|
+
return selected_key
|
185
|
+
else:
|
186
|
+
print(f"Please enter a number between 0 and {len(blueprints_metadata)}.")
|
187
|
+
logger.warning(f"User entered invalid blueprint number: {choice}")
|
188
|
+
except ValueError:
|
189
|
+
print("Invalid input. Please enter a valid number.")
|
190
|
+
logger.warning("User entered non-integer value for blueprint selection.")
|
191
|
+
|
192
|
+
|
193
|
+
def main():
|
194
|
+
"""
|
195
|
+
Main entry point for the blueprint runner CLI.
|
196
|
+
"""
|
197
|
+
parser = argparse.ArgumentParser(description="Blueprint Runner CLI")
|
198
|
+
parser.add_argument(
|
199
|
+
"blueprint_path",
|
200
|
+
type=str,
|
201
|
+
help="Path to the blueprint's Python file."
|
202
|
+
)
|
203
|
+
parser.add_argument(
|
204
|
+
"--interactive",
|
205
|
+
action="store_true",
|
206
|
+
help="Run the blueprint in interactive mode."
|
207
|
+
)
|
208
|
+
parser.add_argument(
|
209
|
+
"--mode",
|
210
|
+
type=str,
|
211
|
+
choices=["cli", "rest", "mcp-host"],
|
212
|
+
default="cli",
|
213
|
+
help="Mode to run the blueprint."
|
214
|
+
)
|
215
|
+
|
216
|
+
args = parser.parse_args()
|
217
|
+
|
218
|
+
try:
|
219
|
+
blueprint_module = load_blueprint(args.blueprint_path)
|
220
|
+
except ImportError as e:
|
221
|
+
print(color_text(str(e), "red"))
|
222
|
+
sys.exit(1)
|
223
|
+
|
224
|
+
if args.interactive:
|
225
|
+
try:
|
226
|
+
run_blueprint_interactive(blueprint_module)
|
227
|
+
except AttributeError as e:
|
228
|
+
print(color_text(str(e), "red"))
|
229
|
+
sys.exit(1)
|
230
|
+
else:
|
231
|
+
try:
|
232
|
+
run_blueprint_framework(blueprint_module)
|
233
|
+
except AttributeError as e:
|
234
|
+
print(color_text(str(e), "red"))
|
235
|
+
sys.exit(1)
|
236
|
+
|
237
|
+
|
238
|
+
if __name__ == "__main__":
|
239
|
+
try:
|
240
|
+
main()
|
241
|
+
except KeyboardInterrupt:
|
242
|
+
print("\nReceived shutdown signal (Ctrl+C)")
|
243
|
+
logger.info("Received shutdown signal (Ctrl+C)")
|
244
|
+
sys.exit(0)
|
245
|
+
except Exception as e:
|
246
|
+
logger.error(f"Unhandled exception: {e}")
|
247
|
+
print(color_text(f"\nFatal error: {e}", "red"))
|
248
|
+
sys.exit(1)
|
249
|
+
finally:
|
250
|
+
logger.info("Blueprint runner terminated.")
|
251
|
+
sys.exit(0)
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# src/swarm/extensions/blueprint/modes/cli_mode/cli_args.py
|
2
|
+
|
3
|
+
import argparse
|
4
|
+
from typing import Namespace
|
5
|
+
|
6
|
+
def parse_arguments() -> Namespace:
|
7
|
+
"""
|
8
|
+
Parse command-line arguments for dynamic LLM configuration, MCP server management, and other overrides.
|
9
|
+
|
10
|
+
Returns:
|
11
|
+
argparse.Namespace: Parsed command-line arguments.
|
12
|
+
"""
|
13
|
+
parser = argparse.ArgumentParser(
|
14
|
+
description="Run Open Swarm MCP in various modes or manage configurations."
|
15
|
+
)
|
16
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
17
|
+
|
18
|
+
# Subparser for running modes
|
19
|
+
run_parser = subparsers.add_parser("run", help="Run Open Swarm MCP in various modes.")
|
20
|
+
run_parser.add_argument(
|
21
|
+
"--mode",
|
22
|
+
type=str,
|
23
|
+
choices=["cli", "rest", "mcp-host"],
|
24
|
+
default="cli",
|
25
|
+
help="Select the mode to run the MCP (cli, rest, mcp-host). Default is 'cli'."
|
26
|
+
)
|
27
|
+
run_parser.add_argument(
|
28
|
+
"--config",
|
29
|
+
type=str,
|
30
|
+
default=None, # Will be set dynamically in main.py
|
31
|
+
help="Path to the MCP server configuration file."
|
32
|
+
)
|
33
|
+
run_parser.add_argument(
|
34
|
+
"--llm",
|
35
|
+
type=str,
|
36
|
+
help="Override the LLM specified in the config."
|
37
|
+
)
|
38
|
+
run_parser.add_argument(
|
39
|
+
"--llm-model",
|
40
|
+
type=str,
|
41
|
+
help="Override the LLM model specified in the config."
|
42
|
+
)
|
43
|
+
run_parser.add_argument(
|
44
|
+
"--temperature",
|
45
|
+
type=float,
|
46
|
+
help="Override the LLM temperature specified in the config."
|
47
|
+
)
|
48
|
+
run_parser.add_argument(
|
49
|
+
"--blueprint",
|
50
|
+
type=str,
|
51
|
+
action='append',
|
52
|
+
help="Specify one or more blueprints to load (can be used multiple times)."
|
53
|
+
)
|
54
|
+
run_parser.add_argument(
|
55
|
+
"--setup",
|
56
|
+
action='store_true',
|
57
|
+
help="Re-run the setup wizard regardless of existing configuration."
|
58
|
+
)
|
59
|
+
|
60
|
+
# Subparser for configuration management
|
61
|
+
config_parser = subparsers.add_parser("config", help="Manage Swarm MCP configurations.")
|
62
|
+
config_subparsers = config_parser.add_subparsers(dest="config_command", help="Configuration commands")
|
63
|
+
|
64
|
+
# Add LLM
|
65
|
+
add_llm_parser = config_subparsers.add_parser("add-llm", help="Add a new LLM.")
|
66
|
+
# No additional arguments; will use interactive prompts
|
67
|
+
|
68
|
+
# Remove LLM
|
69
|
+
remove_llm_parser = config_subparsers.add_parser("remove-llm", help="Remove an existing LLM.")
|
70
|
+
remove_llm_parser.add_argument(
|
71
|
+
"llm_name",
|
72
|
+
type=str,
|
73
|
+
help="Name of the LLM to remove."
|
74
|
+
)
|
75
|
+
|
76
|
+
# Add MCP server
|
77
|
+
add_server_parser = config_subparsers.add_parser("add-server", help="Add a new MCP server.")
|
78
|
+
# No additional arguments; will use interactive prompts
|
79
|
+
|
80
|
+
# Remove MCP server
|
81
|
+
remove_server_parser = config_subparsers.add_parser("remove-server", help="Remove an existing MCP server.")
|
82
|
+
remove_server_parser.add_argument(
|
83
|
+
"server_name",
|
84
|
+
type=str,
|
85
|
+
help="Name of the MCP server to remove."
|
86
|
+
)
|
87
|
+
|
88
|
+
return parser.parse_args()
|
File without changes
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Handles blueprint discovery and validation for the CLI
|
2
|
+
|
3
|
+
from swarm.extensions.blueprint.discovery import discover_blueprints
|
4
|
+
from swarm.extensions.config.config_loader import load_server_config
|
5
|
+
|
6
|
+
def list_blueprints():
|
7
|
+
"""List available blueprints and their metadata."""
|
8
|
+
blueprints = discover_blueprints()
|
9
|
+
if not blueprints:
|
10
|
+
print("No blueprints discovered.")
|
11
|
+
return
|
12
|
+
print("Discovered Blueprints:")
|
13
|
+
for name, metadata in blueprints.items():
|
14
|
+
print(f"- {name}: {metadata.get('description', 'No description available.')}")
|
15
|
+
|
16
|
+
cat > src/swarm/extensions/cli/commands/config_management.py << 'EOF'
|
17
|
+
# Handles configuration management workflows (e.g., LLM, MCP servers)
|
18
|
+
|
19
|
+
from swarm.extensions.config.config_loader import (
|
20
|
+
load_server_config,
|
21
|
+
save_server_config,
|
22
|
+
)
|
23
|
+
|
24
|
+
def add_llm(model_name, api_key):
|
25
|
+
"""Add a new LLM configuration."""
|
26
|
+
config = load_server_config()
|
27
|
+
if "llms" not in config:
|
28
|
+
config["llms"] = {}
|
29
|
+
config["llms"][model_name] = {"api_key": api_key}
|
30
|
+
save_server_config(config)
|
31
|
+
print(f"Added LLM '{model_name}' to configuration.")
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Handles configuration management workflows (e.g., LLM, MCP servers)
|
2
|
+
|
3
|
+
from swarm.extensions.config.config_loader import (
|
4
|
+
load_server_config,
|
5
|
+
save_server_config,
|
6
|
+
)
|
7
|
+
|
8
|
+
def add_llm(model_name, api_key):
|
9
|
+
"""Add a new LLM configuration."""
|
10
|
+
config = load_server_config()
|
11
|
+
if "llms" not in config:
|
12
|
+
config["llms"] = {}
|
13
|
+
config["llms"][model_name] = {"api_key": api_key}
|
14
|
+
save_server_config(config)
|
15
|
+
print(f"Added LLM '{model_name}' to configuration.")
|
@@ -0,0 +1,77 @@
|
|
1
|
+
import argparse
|
2
|
+
import json
|
3
|
+
from swarm.extensions.config.config_loader import (
|
4
|
+
load_server_config,
|
5
|
+
save_server_config,
|
6
|
+
)
|
7
|
+
from pathlib import Path
|
8
|
+
|
9
|
+
CONFIG_PATH = Path("swarm_config.json").resolve()
|
10
|
+
|
11
|
+
def list_config(config):
|
12
|
+
"""
|
13
|
+
List current configuration settings.
|
14
|
+
|
15
|
+
Args:
|
16
|
+
config (dict): The current configuration.
|
17
|
+
"""
|
18
|
+
print(json.dumps(config, indent=4))
|
19
|
+
|
20
|
+
def edit_config_interactive(config):
|
21
|
+
"""
|
22
|
+
Interactive editing of the configuration file.
|
23
|
+
|
24
|
+
Args:
|
25
|
+
config (dict): The current configuration.
|
26
|
+
"""
|
27
|
+
print("Current configuration:")
|
28
|
+
list_config(config)
|
29
|
+
|
30
|
+
print("\nEdit the settings (leave blank to keep current value):")
|
31
|
+
for key, value in config.items():
|
32
|
+
new_value = input(f"{key} [{value}]: ").strip()
|
33
|
+
if new_value:
|
34
|
+
config[key] = new_value
|
35
|
+
|
36
|
+
print("\nUpdated configuration:")
|
37
|
+
list_config(config)
|
38
|
+
|
39
|
+
def edit_config_field(config, field, value):
|
40
|
+
"""
|
41
|
+
Edit a specific field in the configuration.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
config (dict): The current configuration.
|
45
|
+
field (str): The field to edit.
|
46
|
+
value (str): The new value for the field.
|
47
|
+
"""
|
48
|
+
if field not in config:
|
49
|
+
print(f"Field '{field}' not found in configuration.")
|
50
|
+
return
|
51
|
+
config[field] = value
|
52
|
+
print(f"Updated {field} to {value}.")
|
53
|
+
|
54
|
+
def main():
|
55
|
+
parser = argparse.ArgumentParser(description="Edit the swarm_config.json file.")
|
56
|
+
parser.add_argument("--list", action="store_true", help="List current configuration")
|
57
|
+
parser.add_argument("--field", help="The configuration field to edit")
|
58
|
+
parser.add_argument("--value", help="The new value for the specified field")
|
59
|
+
parser.add_argument("--interactive", action="store_true", help="Interactively edit the configuration")
|
60
|
+
args = parser.parse_args()
|
61
|
+
|
62
|
+
try:
|
63
|
+
config = load_server_config(str(CONFIG_PATH))
|
64
|
+
except FileNotFoundError as e:
|
65
|
+
print(f"Error: {e}")
|
66
|
+
return
|
67
|
+
|
68
|
+
if args.list:
|
69
|
+
list_config(config)
|
70
|
+
elif args.interactive:
|
71
|
+
edit_config_interactive(config)
|
72
|
+
save_server_config(str(CONFIG_PATH), config)
|
73
|
+
elif args.field and args.value:
|
74
|
+
edit_config_field(config, args.field, args.value)
|
75
|
+
save_server_config(str(CONFIG_PATH), config)
|
76
|
+
else:
|
77
|
+
parser.print_help()
|
@@ -0,0 +1,22 @@
|
|
1
|
+
"""
|
2
|
+
Command: list_blueprints
|
3
|
+
Description: Lists all blueprints available in the system.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from pathlib import Path
|
7
|
+
from swarm.extensions.blueprint.blueprint_discovery import discover_blueprints
|
8
|
+
|
9
|
+
# Metadata for dynamic registration
|
10
|
+
description = "Lists all blueprints available in the system."
|
11
|
+
usage = "list_blueprints"
|
12
|
+
|
13
|
+
def list_blueprints():
|
14
|
+
"""Returns a list of blueprints."""
|
15
|
+
blueprints_dir = Path(__file__).resolve().parent.parent.parent / "blueprints"
|
16
|
+
return discover_blueprints([str(blueprints_dir)])
|
17
|
+
|
18
|
+
def execute():
|
19
|
+
"""Execute the command to list blueprints."""
|
20
|
+
blueprints = list_blueprints()
|
21
|
+
for blueprint_id, metadata in blueprints.items():
|
22
|
+
print(f"Blueprint ID: {blueprint_id}, Title: {metadata.get('title', 'No title')}")
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import os
|
2
|
+
import argparse
|
3
|
+
from swarm.extensions.config.config_loader import load_server_config
|
4
|
+
from swarm.extensions.blueprint.blueprint_base import BlueprintBase
|
5
|
+
|
6
|
+
CONFIG_PATH = "swarm_config.json"
|
7
|
+
|
8
|
+
def validate_all_env_vars(config):
|
9
|
+
"""
|
10
|
+
Validate all environment variables for the current configuration.
|
11
|
+
"""
|
12
|
+
required_vars = config.get("required_env_vars", [])
|
13
|
+
missing_vars = [var for var in required_vars if var not in os.environ]
|
14
|
+
|
15
|
+
if missing_vars:
|
16
|
+
print(f"Missing environment variables: {', '.join(missing_vars)}")
|
17
|
+
return False
|
18
|
+
print("All required environment variables are set.")
|
19
|
+
return True
|
20
|
+
|
21
|
+
def validate_blueprint_env_vars(config, blueprint_name):
|
22
|
+
"""
|
23
|
+
Validate environment variables for a specific blueprint.
|
24
|
+
|
25
|
+
Args:
|
26
|
+
config (dict): The configuration dictionary.
|
27
|
+
blueprint_name (str): The name of the blueprint to validate.
|
28
|
+
"""
|
29
|
+
blueprint_config = config.get("blueprints", {}).get(blueprint_name, {})
|
30
|
+
blueprint = BlueprintBase(blueprint_config)
|
31
|
+
required_vars = blueprint.required_env_vars()
|
32
|
+
missing_vars = [var for var in required_vars if var not in os.environ]
|
33
|
+
|
34
|
+
if missing_vars:
|
35
|
+
print(f"Missing environment variables for blueprint '{blueprint_name}': {', '.join(missing_vars)}")
|
36
|
+
return False
|
37
|
+
print(f"All required environment variables are set for blueprint '{blueprint_name}'.")
|
38
|
+
return True
|
39
|
+
|
40
|
+
def main():
|
41
|
+
parser = argparse.ArgumentParser(description="Validate environment variables.")
|
42
|
+
parser.add_argument("--blueprint", help="Validate environment variables for a specific blueprint.")
|
43
|
+
args = parser.parse_args()
|
44
|
+
|
45
|
+
try:
|
46
|
+
config = load_server_config(CONFIG_PATH)
|
47
|
+
except FileNotFoundError as e:
|
48
|
+
print(f"Error: {e}")
|
49
|
+
return
|
50
|
+
|
51
|
+
if args.blueprint:
|
52
|
+
validate_blueprint_env_vars(config, args.blueprint)
|
53
|
+
else:
|
54
|
+
validate_all_env_vars(config)
|
55
|
+
|
56
|
+
if __name__ == "__main__":
|
57
|
+
main()
|
@@ -0,0 +1,39 @@
|
|
1
|
+
from swarm.extensions.blueprint.blueprint_discovery import discover_blueprints
|
2
|
+
from swarm.extensions.config.config_loader import load_env_config, validate_env_vars
|
3
|
+
import argparse
|
4
|
+
|
5
|
+
def validate_envvars(blueprint_name=None):
|
6
|
+
"""
|
7
|
+
Validate environment variables for blueprints.
|
8
|
+
|
9
|
+
Args:
|
10
|
+
blueprint_name (str, optional): The name of the blueprint to validate.
|
11
|
+
Validates all blueprints if None.
|
12
|
+
"""
|
13
|
+
# Discover blueprints
|
14
|
+
blueprints = discover_blueprints(["blueprints"])
|
15
|
+
|
16
|
+
if blueprint_name:
|
17
|
+
blueprint = blueprints.get(blueprint_name)
|
18
|
+
if not blueprint:
|
19
|
+
print(f"Blueprint '{blueprint_name}' not found.")
|
20
|
+
return
|
21
|
+
required_vars = blueprint.get("env_vars", [])
|
22
|
+
env_vars = load_env_config()
|
23
|
+
validation = validate_env_vars(env_vars, required_vars)
|
24
|
+
print(f"Validation for '{blueprint_name}': {validation}")
|
25
|
+
else:
|
26
|
+
# Global validation
|
27
|
+
env_vars = load_env_config()
|
28
|
+
print("Global Environment Validation:")
|
29
|
+
for blueprint_name, blueprint_data in blueprints.items():
|
30
|
+
required_vars = blueprint_data.get("env_vars", [])
|
31
|
+
validation = validate_env_vars(env_vars, required_vars)
|
32
|
+
print(f"Validation for '{blueprint_name}': {validation}")
|
33
|
+
|
34
|
+
def main():
|
35
|
+
parser = argparse.ArgumentParser(description="Validate environment variables.")
|
36
|
+
parser.add_argument("--blueprint", help="Specify a blueprint to validate")
|
37
|
+
args = parser.parse_args()
|
38
|
+
|
39
|
+
validate_envvars(blueprint_name=args.blueprint)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
"""
|
2
|
+
Interactive CLI shell for dynamic commands.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from swarm.extensions.cli.utils.discover_commands import discover_commands
|
6
|
+
import os
|
7
|
+
|
8
|
+
COMMANDS_DIR = os.path.join(os.path.dirname(__file__), "commands")
|
9
|
+
|
10
|
+
def interactive_shell():
|
11
|
+
"""Launch an interactive CLI shell."""
|
12
|
+
commands = discover_commands(COMMANDS_DIR)
|
13
|
+
|
14
|
+
print("Welcome to the Swarm CLI Interactive Shell!")
|
15
|
+
print("Type 'help' to see available commands, or 'exit' to quit.")
|
16
|
+
|
17
|
+
while True:
|
18
|
+
try:
|
19
|
+
user_input = input("swarm> ").strip()
|
20
|
+
if user_input == "exit":
|
21
|
+
print("Exiting CLI shell.")
|
22
|
+
break
|
23
|
+
elif user_input == "help":
|
24
|
+
show_help(commands)
|
25
|
+
elif user_input in commands:
|
26
|
+
command = commands[user_input]["execute"]
|
27
|
+
if command:
|
28
|
+
command()
|
29
|
+
else:
|
30
|
+
print(f"Command '{user_input}' is not executable.")
|
31
|
+
else:
|
32
|
+
print(f"Unknown command: {user_input}")
|
33
|
+
except KeyboardInterrupt:
|
34
|
+
print("\nExiting CLI shell.")
|
35
|
+
break
|
36
|
+
|
37
|
+
def show_help(commands):
|
38
|
+
"""Display available commands."""
|
39
|
+
print("Available commands:")
|
40
|
+
for cmd, metadata in commands.items():
|
41
|
+
print(f" - {cmd}: {metadata['description']}")
|
@@ -0,0 +1,36 @@
|
|
1
|
+
"""
|
2
|
+
Main entry point for Swarm CLI.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import argparse
|
6
|
+
import os
|
7
|
+
from swarm.extensions.cli.utils.discover_commands import discover_commands
|
8
|
+
from swarm.extensions.cli.interactive_shell import interactive_shell
|
9
|
+
|
10
|
+
COMMANDS_DIR = os.path.join(os.path.dirname(__file__), "commands")
|
11
|
+
|
12
|
+
def parse_args(commands):
|
13
|
+
"""Parse CLI arguments dynamically."""
|
14
|
+
parser = argparse.ArgumentParser(description="Swarm CLI Utility")
|
15
|
+
subparsers = parser.add_subparsers(dest="command")
|
16
|
+
|
17
|
+
for cmd_name, metadata in commands.items():
|
18
|
+
subparsers.add_parser(cmd_name, help=metadata["description"])
|
19
|
+
|
20
|
+
return parser.parse_args()
|
21
|
+
|
22
|
+
def main():
|
23
|
+
commands = discover_commands(COMMANDS_DIR)
|
24
|
+
args = parse_args(commands)
|
25
|
+
|
26
|
+
if args.command:
|
27
|
+
command = commands.get(args.command, {}).get("execute")
|
28
|
+
if command:
|
29
|
+
command()
|
30
|
+
else:
|
31
|
+
print(f"Command '{args.command}' is not executable.")
|
32
|
+
else:
|
33
|
+
interactive_shell()
|
34
|
+
|
35
|
+
if __name__ == "__main__":
|
36
|
+
main()
|