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.
- open_swarm-0.1.1748636295.dist-info/METADATA +257 -0
- open_swarm-0.1.1748636295.dist-info/RECORD +89 -0
- {open_swarm-0.1.1745275181.dist-info → open_swarm-0.1.1748636295.dist-info}/WHEEL +2 -1
- open_swarm-0.1.1748636295.dist-info/entry_points.txt +3 -0
- open_swarm-0.1.1748636295.dist-info/top_level.txt +1 -0
- swarm/__init__.py +2 -0
- swarm/agent/agent.py +49 -0
- swarm/auth.py +48 -113
- swarm/consumers.py +0 -19
- swarm/core.py +411 -0
- swarm/extensions/blueprint/__init__.py +16 -30
- 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/django_utils.py +79 -181
- swarm/extensions/blueprint/interactive_mode.py +72 -67
- swarm/extensions/blueprint/output_utils.py +82 -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 +345 -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/extensions/mcp/__init__.py +1 -0
- swarm/extensions/mcp/cache_utils.py +32 -0
- swarm/extensions/mcp/mcp_client.py +233 -0
- swarm/extensions/mcp/mcp_tool_provider.py +135 -0
- swarm/extensions/mcp/mcp_utils.py +260 -0
- swarm/llm/chat_completion.py +166 -0
- swarm/serializers.py +5 -96
- swarm/settings.py +133 -85
- swarm/types.py +91 -0
- 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 +76 -236
- swarm/views/core_views.py +87 -80
- swarm/views/model_views.py +121 -64
- swarm/views/utils.py +439 -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/agent_utils.py +0 -21
- 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.1748636295.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
@@ -3,10 +3,12 @@ Interactive mode logic for blueprint extensions.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import logging
|
6
|
-
from typing import List, Dict
|
6
|
+
from typing import List, Dict
|
7
7
|
|
8
8
|
# Import the standalone output function
|
9
9
|
from .output_utils import pretty_print_response
|
10
|
+
# Assuming spinner is managed by the blueprint instance passed in
|
11
|
+
# from .spinner import Spinner # Not needed directly here
|
10
12
|
|
11
13
|
logger = logging.getLogger(__name__)
|
12
14
|
|
@@ -14,32 +16,24 @@ def run_interactive_mode(blueprint, stream: bool = False) -> None:
|
|
14
16
|
"""
|
15
17
|
Run the interactive mode for a blueprint instance.
|
16
18
|
|
17
|
-
This function implements the interactive loop where the user is
|
18
|
-
|
19
|
-
and responses are generated and printed using the blueprint inst
|
20
|
-
ance's methods.
|
19
|
+
This function implements the interactive loop where the user is prompted for input,
|
20
|
+
and responses are generated and printed using the blueprint instance's methods.
|
21
21
|
"""
|
22
22
|
logger.debug("Starting interactive mode.")
|
23
|
-
if not blueprint.starting_agent:
|
23
|
+
if not blueprint.starting_agent or not blueprint.swarm:
|
24
24
|
logger.error("Starting agent or Swarm not initialized.")
|
25
|
-
# --- FIX: Terminate string literal correctly ---
|
26
25
|
raise ValueError("Starting agent and Swarm must be initialized.")
|
27
|
-
# --- End FIX ---
|
28
|
-
|
29
26
|
print("Blueprint Interactive Mode 🐝")
|
30
|
-
messages: List[Dict[str,
|
27
|
+
messages: List[Dict[str, str]] = []
|
31
28
|
first_input = True
|
32
29
|
message_count = 0
|
33
30
|
while True:
|
31
|
+
# Use the blueprint's spinner instance if it exists
|
34
32
|
spinner = getattr(blueprint, 'spinner', None)
|
35
|
-
if spinner:
|
36
|
-
|
37
|
-
try:
|
38
|
-
user_input = input(blueprint.prompt).strip()
|
39
|
-
except (EOFError, KeyboardInterrupt):
|
40
|
-
print("\nExiting interactive mode.")
|
41
|
-
break
|
33
|
+
if spinner:
|
34
|
+
spinner.stop()
|
42
35
|
|
36
|
+
user_input = input(blueprint.prompt).strip()
|
43
37
|
if user_input.lower() in {"exit", "quit", "/quit"}:
|
44
38
|
print("Exiting interactive mode.")
|
45
39
|
break
|
@@ -49,54 +43,65 @@ ance's methods.
|
|
49
43
|
messages.append({"role": "user", "content": user_input})
|
50
44
|
message_count += 1
|
51
45
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
46
|
+
# run_with_context should handle its own spinner start/stop now
|
47
|
+
result = blueprint.run_with_context(messages, blueprint.context_variables)
|
48
|
+
swarm_response = result["response"]
|
49
|
+
|
50
|
+
# Determine response messages
|
51
|
+
response_messages = []
|
52
|
+
if hasattr(swarm_response, 'messages'):
|
53
|
+
response_messages = swarm_response.messages
|
54
|
+
elif isinstance(swarm_response, dict) and 'messages' in swarm_response:
|
55
|
+
response_messages = swarm_response.get('messages', [])
|
56
|
+
|
57
|
+
# Process output
|
58
|
+
if stream:
|
59
|
+
# Assuming _process_and_print_streaming_response_async exists on blueprint
|
60
|
+
# This might also need updating if it relies on the old print method
|
61
|
+
try:
|
62
|
+
import asyncio
|
63
|
+
asyncio.run(blueprint._process_and_print_streaming_response_async(swarm_response))
|
64
|
+
except AttributeError:
|
65
|
+
logger.error("Blueprint instance missing '_process_and_print_streaming_response_async' method for streaming.")
|
66
|
+
print("[Error: Streaming output failed]")
|
67
|
+
except Exception as e:
|
68
|
+
logger.error(f"Error during streaming output: {e}", exc_info=True)
|
69
|
+
print("[Error during streaming output]")
|
70
|
+
|
71
|
+
else:
|
72
|
+
# Use the imported pretty_print_response function
|
73
|
+
pretty_print_response(
|
74
|
+
response_messages,
|
75
|
+
use_markdown=getattr(blueprint, 'use_markdown', False),
|
76
|
+
spinner=spinner # Pass the spinner instance
|
77
|
+
)
|
78
|
+
|
79
|
+
# Extend history and handle post-response logic
|
80
|
+
messages.extend(response_messages)
|
81
|
+
|
82
|
+
# Check for goal update logic
|
83
|
+
if getattr(blueprint, 'update_user_goal', False) and \
|
84
|
+
(message_count - getattr(blueprint, 'last_goal_update_count', 0)) >= \
|
85
|
+
getattr(blueprint, 'update_user_goal_frequency', 5):
|
86
|
+
# Assume _update_user_goal is an async method on blueprint
|
87
|
+
try:
|
88
|
+
import asyncio
|
89
|
+
asyncio.run(blueprint._update_user_goal_async(messages))
|
90
|
+
blueprint.last_goal_update_count = message_count
|
91
|
+
except AttributeError:
|
92
|
+
logger.warning("Blueprint instance missing '_update_user_goal_async' method.")
|
93
|
+
except Exception as e:
|
94
|
+
logger.error(f"Error updating user goal: {e}", exc_info=True)
|
95
|
+
|
96
|
+
|
97
|
+
# Check for auto-complete logic
|
98
|
+
if getattr(blueprint, 'auto_complete_task', False):
|
99
|
+
# Assume _auto_complete_task is an async method on blueprint
|
100
|
+
try:
|
101
|
+
import asyncio
|
102
|
+
asyncio.run(blueprint._auto_complete_task_async(messages, stream))
|
103
|
+
except AttributeError:
|
104
|
+
logger.warning("Blueprint instance missing '_auto_complete_task_async' method.")
|
105
|
+
except Exception as e:
|
106
|
+
logger.error(f"Error during auto-complete task: {e}", exc_info=True)
|
102
107
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
"""
|
2
|
+
Output utilities for Swarm blueprints.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import json
|
6
|
+
import logging
|
7
|
+
import sys
|
8
|
+
from typing import List, Dict, Any
|
9
|
+
|
10
|
+
# Optional import for markdown rendering
|
11
|
+
try:
|
12
|
+
from rich.markdown import Markdown
|
13
|
+
from rich.console import Console
|
14
|
+
RICH_AVAILABLE = True
|
15
|
+
except ImportError:
|
16
|
+
RICH_AVAILABLE = False
|
17
|
+
|
18
|
+
logger = logging.getLogger(__name__)
|
19
|
+
|
20
|
+
def render_markdown(content: str) -> None:
|
21
|
+
"""Render markdown content using rich, if available."""
|
22
|
+
if not RICH_AVAILABLE:
|
23
|
+
print(content)
|
24
|
+
return
|
25
|
+
console = Console()
|
26
|
+
md = Markdown(content)
|
27
|
+
console.print(md)
|
28
|
+
|
29
|
+
def pretty_print_response(messages: List[Dict[str, Any]], use_markdown: bool = False, spinner=None) -> None:
|
30
|
+
"""Format and print messages, optionally rendering assistant content as markdown."""
|
31
|
+
if spinner:
|
32
|
+
spinner.stop()
|
33
|
+
sys.stdout.write("\r\033[K")
|
34
|
+
sys.stdout.flush()
|
35
|
+
|
36
|
+
if not messages:
|
37
|
+
logger.debug("No messages to print in pretty_print_response.")
|
38
|
+
return
|
39
|
+
|
40
|
+
for msg in messages:
|
41
|
+
if not isinstance(msg, dict):
|
42
|
+
continue
|
43
|
+
|
44
|
+
role = msg.get("role")
|
45
|
+
sender = msg.get("sender", role if role else "Unknown")
|
46
|
+
msg_content = msg.get("content")
|
47
|
+
tool_calls = msg.get("tool_calls")
|
48
|
+
|
49
|
+
if role == "assistant":
|
50
|
+
print(f"\033[94m{sender}\033[0m: ", end="")
|
51
|
+
if msg_content:
|
52
|
+
if use_markdown and RICH_AVAILABLE:
|
53
|
+
render_markdown(msg_content)
|
54
|
+
else:
|
55
|
+
print(msg_content)
|
56
|
+
elif not tool_calls:
|
57
|
+
print()
|
58
|
+
|
59
|
+
if tool_calls and isinstance(tool_calls, list):
|
60
|
+
print(" \033[92mTool Calls:\033[0m")
|
61
|
+
for tc in tool_calls:
|
62
|
+
if not isinstance(tc, dict):
|
63
|
+
continue
|
64
|
+
func = tc.get("function", {})
|
65
|
+
tool_name = func.get("name", "Unnamed Tool")
|
66
|
+
args_str = func.get("arguments", "{}")
|
67
|
+
try:
|
68
|
+
args_obj = json.loads(args_str)
|
69
|
+
args_pretty = ", ".join(f"{k}={v!r}" for k, v in args_obj.items())
|
70
|
+
except json.JSONDecodeError:
|
71
|
+
args_pretty = args_str
|
72
|
+
print(f" \033[95m{tool_name}\033[0m({args_pretty})")
|
73
|
+
|
74
|
+
elif role == "tool":
|
75
|
+
tool_name = msg.get("tool_name", msg.get("name", "tool"))
|
76
|
+
tool_id = msg.get("tool_call_id", "N/A")
|
77
|
+
try:
|
78
|
+
content_obj = json.loads(msg_content)
|
79
|
+
pretty_content = json.dumps(content_obj, indent=2)
|
80
|
+
except (json.JSONDecodeError, TypeError):
|
81
|
+
pretty_content = msg_content
|
82
|
+
print(f" \033[93m[{tool_name} Result ID: {tool_id}]\033[0m:\n {pretty_content.replace(chr(10), chr(10) + ' ')}")
|
@@ -6,36 +6,29 @@ import os
|
|
6
6
|
import sys
|
7
7
|
import threading
|
8
8
|
import time
|
9
|
-
from typing import Optional
|
10
9
|
|
11
10
|
class Spinner:
|
12
11
|
"""Simple terminal spinner for interactive feedback."""
|
13
12
|
# Define spinner characters (can be customized)
|
14
13
|
SPINNER_CHARS = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
|
15
|
-
#
|
16
|
-
STATUS_SEQUENCES = {
|
17
|
-
'generating': ['Generating.', 'Generating..', 'Generating...'],
|
18
|
-
'running': ['Running...']
|
19
|
-
}
|
14
|
+
# SPINNER_CHARS = ['|', '/', '-', '\\'] # Simpler alternative
|
20
15
|
|
21
|
-
def __init__(self, interactive: bool
|
16
|
+
def __init__(self, interactive: bool):
|
22
17
|
"""
|
23
18
|
Initialize the spinner.
|
24
19
|
|
25
20
|
Args:
|
26
21
|
interactive (bool): Hint whether the environment is interactive.
|
27
22
|
Spinner is disabled if False or if output is not a TTY.
|
28
|
-
custom_sequence (str): Optional name for a custom status sequence (e.g., 'generating', 'running').
|
29
23
|
"""
|
30
24
|
self.interactive = interactive
|
25
|
+
# Check if output is a TTY (terminal) and interactive flag is True
|
31
26
|
self.is_tty = sys.stdout.isatty()
|
32
27
|
self.enabled = self.interactive and self.is_tty
|
33
28
|
self.running = False
|
34
29
|
self.thread: Optional[threading.Thread] = None
|
35
30
|
self.status = ""
|
36
31
|
self.index = 0
|
37
|
-
self.custom_sequence = custom_sequence
|
38
|
-
self.sequence_idx = 0
|
39
32
|
|
40
33
|
def start(self, status: str = "Processing..."):
|
41
34
|
"""Start the spinner with an optional status message."""
|
@@ -43,7 +36,7 @@ class Spinner:
|
|
43
36
|
return # Do nothing if disabled or already running
|
44
37
|
self.status = status
|
45
38
|
self.running = True
|
46
|
-
|
39
|
+
# Run the spinner animation in a separate daemon thread
|
47
40
|
self.thread = threading.Thread(target=self._spin, daemon=True)
|
48
41
|
self.thread.start()
|
49
42
|
|
@@ -54,33 +47,30 @@ class Spinner:
|
|
54
47
|
self.running = False
|
55
48
|
if self.thread is not None:
|
56
49
|
self.thread.join() # Wait for the thread to finish
|
50
|
+
# Clear the spinner line using ANSI escape codes
|
51
|
+
# \r: Carriage return (move cursor to beginning of line)
|
52
|
+
# \033[K: Clear line from cursor to end
|
57
53
|
sys.stdout.write("\r\033[K")
|
58
54
|
sys.stdout.flush()
|
59
|
-
self.thread = None
|
55
|
+
self.thread = None # Reset thread
|
60
56
|
|
61
57
|
def _spin(self):
|
62
58
|
"""Internal method running in the spinner thread to animate."""
|
63
|
-
start_time = time.time()
|
64
|
-
warned = False
|
65
59
|
while self.running:
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
msg = f"{seq[-1]} Taking longer than expected"
|
72
|
-
warned = True
|
73
|
-
else:
|
74
|
-
msg = seq[self.sequence_idx % len(seq)]
|
75
|
-
sys.stdout.write(f"\r{msg}\033[K")
|
76
|
-
sys.stdout.flush()
|
77
|
-
self.sequence_idx += 1
|
78
|
-
else:
|
79
|
-
char = self.SPINNER_CHARS[self.index % len(self.SPINNER_CHARS)]
|
60
|
+
# Get the next spinner character
|
61
|
+
char = self.SPINNER_CHARS[self.index % len(self.SPINNER_CHARS)]
|
62
|
+
# Write spinner char and status, overwrite previous line content
|
63
|
+
try:
|
64
|
+
# \r moves cursor to beginning, \033[K clears the rest of the line
|
80
65
|
sys.stdout.write(f"\r{char} {self.status}\033[K")
|
81
66
|
sys.stdout.flush()
|
82
|
-
|
83
|
-
|
67
|
+
except BlockingIOError:
|
68
|
+
# Handle potential issues if stdout is blocked (less likely for TTY)
|
69
|
+
time.sleep(0.1)
|
70
|
+
continue
|
71
|
+
self.index += 1
|
72
|
+
# Pause for animation effect
|
73
|
+
time.sleep(0.1)
|
84
74
|
|
85
75
|
# Example usage (if run directly)
|
86
76
|
if __name__ == "__main__":
|
@@ -98,3 +88,4 @@ if __name__ == "__main__":
|
|
98
88
|
finally:
|
99
89
|
s.stop() # Ensure spinner stops on exit/error
|
100
90
|
print("Test finished.")
|
91
|
+
|
swarm/extensions/cli/cli_args.py
CHANGED
@@ -1,14 +1,8 @@
|
|
1
1
|
# src/swarm/extensions/blueprint/modes/cli_mode/cli_args.py
|
2
2
|
|
3
3
|
import argparse
|
4
|
-
import os
|
5
|
-
import sys
|
6
4
|
from typing import Namespace
|
7
5
|
|
8
|
-
# --- DEBUG PRINTS REMOVED BY CASCADE ---
|
9
|
-
# print(f"[DEBUG] cli_args.py startup: sys.argv={sys.argv}")
|
10
|
-
# print(f"[DEBUG] cli_args.py startup: LITELLM_MODEL={os.environ.get('LITELLM_MODEL')}, DEFAULT_LLM={os.environ.get('DEFAULT_LLM')}")
|
11
|
-
|
12
6
|
def parse_arguments() -> Namespace:
|
13
7
|
"""
|
14
8
|
Parse command-line arguments for dynamic LLM configuration, MCP server management, and other overrides.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Handles blueprint discovery and validation for the CLI
|
2
2
|
|
3
|
-
from swarm.
|
4
|
-
|
3
|
+
from swarm.extensions.blueprint.discovery import discover_blueprints
|
4
|
+
from swarm.extensions.config.config_loader import load_server_config
|
5
5
|
|
6
6
|
def list_blueprints():
|
7
7
|
"""List available blueprints and their metadata."""
|
@@ -13,57 +13,19 @@ def list_blueprints():
|
|
13
13
|
for name, metadata in blueprints.items():
|
14
14
|
print(f"- {name}: {metadata.get('description', 'No description available.')}")
|
15
15
|
|
16
|
-
|
17
|
-
"""
|
18
|
-
Enable a blueprint by adding it to config and creating a CLI symlink.
|
19
|
-
"""
|
20
|
-
import json
|
21
|
-
import os
|
22
|
-
from pathlib import Path
|
23
|
-
CONFIG_PATH = os.path.expanduser("~/.config/swarm/swarm_config.json")
|
24
|
-
BIN_DIR = os.path.expanduser("~/.local/bin")
|
25
|
-
BP_RUNNER = os.path.join(os.path.dirname(__file__), "../../../../src/swarm/blueprints/{}/blueprint_{}.py".format(blueprint_name, blueprint_name))
|
26
|
-
CLI_SYMLINK = os.path.join(BIN_DIR, blueprint_name)
|
27
|
-
|
28
|
-
# Load config
|
29
|
-
with open(CONFIG_PATH, "r") as f:
|
30
|
-
config = json.load(f)
|
31
|
-
enabled = config.get("blueprints", {}).get("enabled", [])
|
32
|
-
if blueprint_name in enabled:
|
33
|
-
print(f"Blueprint '{blueprint_name}' is already enabled.")
|
34
|
-
return
|
35
|
-
# Add to config
|
36
|
-
enabled.append(blueprint_name)
|
37
|
-
if "blueprints" not in config:
|
38
|
-
config["blueprints"] = {}
|
39
|
-
config["blueprints"]["enabled"] = enabled
|
40
|
-
with open(CONFIG_PATH, "w") as f:
|
41
|
-
json.dump(config, f, indent=2)
|
42
|
-
# Ensure bin dir exists
|
43
|
-
os.makedirs(BIN_DIR, exist_ok=True)
|
44
|
-
# Create symlink (Python runner)
|
45
|
-
if not os.path.isfile(BP_RUNNER):
|
46
|
-
print(f"Blueprint runner not found: {BP_RUNNER}")
|
47
|
-
return
|
48
|
-
# Write a .sh launcher wrapper for .py if not present
|
49
|
-
CLI_WRAPPER = CLI_SYMLINK
|
50
|
-
with open(CLI_WRAPPER, "w") as f:
|
51
|
-
f.write(f"#!/usr/bin/env bash\nexec python3 '{os.path.abspath(BP_RUNNER)}' \"$@\"")
|
52
|
-
os.chmod(CLI_WRAPPER, 0o755)
|
53
|
-
print(f"Enabled blueprint '{blueprint_name}'. CLI utility installed at {CLI_WRAPPER}.")
|
54
|
-
|
16
|
+
cat > src/swarm/extensions/cli/commands/config_management.py << 'EOF'
|
55
17
|
# Handles configuration management workflows (e.g., LLM, MCP servers)
|
56
18
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
19
|
+
from swarm.extensions.config.config_loader import (
|
20
|
+
load_server_config,
|
21
|
+
save_server_config,
|
22
|
+
)
|
61
23
|
|
62
24
|
def add_llm(model_name, api_key):
|
63
25
|
"""Add a new LLM configuration."""
|
64
|
-
config =
|
26
|
+
config = load_server_config()
|
65
27
|
if "llms" not in config:
|
66
28
|
config["llms"] = {}
|
67
29
|
config["llms"][model_name] = {"api_key": api_key}
|
68
|
-
|
30
|
+
save_server_config(config)
|
69
31
|
print(f"Added LLM '{model_name}' to configuration.")
|
@@ -1,14 +1,15 @@
|
|
1
1
|
# Handles configuration management workflows (e.g., LLM, MCP servers)
|
2
2
|
|
3
|
-
from swarm.
|
4
|
-
|
5
|
-
|
3
|
+
from swarm.extensions.config.config_loader import (
|
4
|
+
load_server_config,
|
5
|
+
save_server_config,
|
6
|
+
)
|
6
7
|
|
7
8
|
def add_llm(model_name, api_key):
|
8
9
|
"""Add a new LLM configuration."""
|
9
|
-
config =
|
10
|
+
config = load_server_config()
|
10
11
|
if "llms" not in config:
|
11
12
|
config["llms"] = {}
|
12
13
|
config["llms"][model_name] = {"api_key": api_key}
|
13
|
-
|
14
|
+
save_server_config(config)
|
14
15
|
print(f"Added LLM '{model_name}' to configuration.")
|
@@ -1,21 +1,12 @@
|
|
1
1
|
import argparse
|
2
2
|
import json
|
3
|
-
from swarm.
|
4
|
-
|
5
|
-
|
6
|
-
server_config,
|
7
|
-
setup_wizard,
|
3
|
+
from swarm.extensions.config.config_loader import (
|
4
|
+
load_server_config,
|
5
|
+
save_server_config,
|
8
6
|
)
|
9
7
|
from pathlib import Path
|
10
|
-
import os
|
11
8
|
|
12
|
-
|
13
|
-
config_home = os.environ.get("XDG_CONFIG_HOME", str(Path.home() / ".config"))
|
14
|
-
config_dir = Path(config_home) / "swarm"
|
15
|
-
config_dir.mkdir(parents=True, exist_ok=True)
|
16
|
-
return config_dir / "swarm_config.json"
|
17
|
-
|
18
|
-
CONFIG_PATH = get_xdg_config_path()
|
9
|
+
CONFIG_PATH = Path("swarm_config.json").resolve()
|
19
10
|
|
20
11
|
def list_config(config):
|
21
12
|
"""
|
@@ -69,7 +60,7 @@ def main():
|
|
69
60
|
args = parser.parse_args()
|
70
61
|
|
71
62
|
try:
|
72
|
-
config =
|
63
|
+
config = load_server_config(str(CONFIG_PATH))
|
73
64
|
except FileNotFoundError as e:
|
74
65
|
print(f"Error: {e}")
|
75
66
|
return
|
@@ -78,9 +69,9 @@ def main():
|
|
78
69
|
list_config(config)
|
79
70
|
elif args.interactive:
|
80
71
|
edit_config_interactive(config)
|
81
|
-
|
72
|
+
save_server_config(str(CONFIG_PATH), config)
|
82
73
|
elif args.field and args.value:
|
83
74
|
edit_config_field(config, args.field, args.value)
|
84
|
-
|
75
|
+
save_server_config(str(CONFIG_PATH), config)
|
85
76
|
else:
|
86
77
|
parser.print_help()
|
@@ -4,7 +4,7 @@ Description: Lists all blueprints available in the system.
|
|
4
4
|
"""
|
5
5
|
|
6
6
|
from pathlib import Path
|
7
|
-
from swarm.
|
7
|
+
from swarm.extensions.blueprint.blueprint_discovery import discover_blueprints
|
8
8
|
|
9
9
|
# Metadata for dynamic registration
|
10
10
|
description = "Lists all blueprints available in the system."
|
@@ -1,16 +1,9 @@
|
|
1
1
|
import os
|
2
2
|
import argparse
|
3
|
-
from
|
4
|
-
from swarm.
|
5
|
-
from swarm.core.blueprint_base import BlueprintBase
|
3
|
+
from swarm.extensions.config.config_loader import load_server_config
|
4
|
+
from swarm.extensions.blueprint.blueprint_base import BlueprintBase
|
6
5
|
|
7
|
-
|
8
|
-
config_home = os.environ.get("XDG_CONFIG_HOME", str(Path.home() / ".config"))
|
9
|
-
config_dir = Path(config_home) / "swarm"
|
10
|
-
config_dir.mkdir(parents=True, exist_ok=True)
|
11
|
-
return config_dir / "swarm_config.json"
|
12
|
-
|
13
|
-
CONFIG_PATH = str(get_xdg_config_path())
|
6
|
+
CONFIG_PATH = "swarm_config.json"
|
14
7
|
|
15
8
|
def validate_all_env_vars(config):
|
16
9
|
"""
|
@@ -50,7 +43,7 @@ def main():
|
|
50
43
|
args = parser.parse_args()
|
51
44
|
|
52
45
|
try:
|
53
|
-
config =
|
46
|
+
config = load_server_config(CONFIG_PATH)
|
54
47
|
except FileNotFoundError as e:
|
55
48
|
print(f"Error: {e}")
|
56
49
|
return
|
@@ -1,5 +1,5 @@
|
|
1
|
-
from swarm.
|
2
|
-
from swarm.
|
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
3
|
import argparse
|
4
4
|
|
5
5
|
def validate_envvars(blueprint_name=None):
|
@@ -19,16 +19,16 @@ def validate_envvars(blueprint_name=None):
|
|
19
19
|
print(f"Blueprint '{blueprint_name}' not found.")
|
20
20
|
return
|
21
21
|
required_vars = blueprint.get("env_vars", [])
|
22
|
-
env_vars =
|
23
|
-
validation =
|
22
|
+
env_vars = load_env_config()
|
23
|
+
validation = validate_env_vars(env_vars, required_vars)
|
24
24
|
print(f"Validation for '{blueprint_name}': {validation}")
|
25
25
|
else:
|
26
26
|
# Global validation
|
27
|
-
env_vars =
|
27
|
+
env_vars = load_env_config()
|
28
28
|
print("Global Environment Validation:")
|
29
29
|
for blueprint_name, blueprint_data in blueprints.items():
|
30
30
|
required_vars = blueprint_data.get("env_vars", [])
|
31
|
-
validation =
|
31
|
+
validation = validate_env_vars(env_vars, required_vars)
|
32
32
|
print(f"Validation for '{blueprint_name}': {validation}")
|
33
33
|
|
34
34
|
def main():
|
@@ -35,21 +35,7 @@ def interactive_shell():
|
|
35
35
|
break
|
36
36
|
|
37
37
|
def show_help(commands):
|
38
|
-
"""Display available commands
|
39
|
-
print("\n\033[1;36mSwarm CLI Help\033[0m")
|
40
|
-
print("Type the command name to run it, or 'exit' to quit.")
|
41
|
-
print("Commands can be used to manage your Swarm config, blueprints, LLMs, MCP servers, and more.\n")
|
38
|
+
"""Display available commands."""
|
42
39
|
print("Available commands:")
|
43
40
|
for cmd, metadata in commands.items():
|
44
|
-
|
45
|
-
usage = metadata.get('usage', None)
|
46
|
-
print(f" \033[1;33m{cmd}\033[0m: {desc}")
|
47
|
-
if usage:
|
48
|
-
print(f" Usage: {usage}")
|
49
|
-
print("\nExamples:")
|
50
|
-
print(" validate_envvars # Check required environment variables")
|
51
|
-
print(" edit_config # Edit your Swarm config interactively")
|
52
|
-
print(" list_blueprints # List all available blueprints")
|
53
|
-
print(" blueprint_management # Advanced blueprint management")
|
54
|
-
print(" config_management # Manage LLMs, MCP servers, blueprints")
|
55
|
-
print("\nType 'exit' to leave the shell.\n")
|
41
|
+
print(f" - {cmd}: {metadata['description']}")
|