open-swarm 0.1.1745274976__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.1745274976.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.1745274976.dist-info/METADATA +0 -874
- open_swarm-0.1.1745274976.dist-info/RECORD +0 -318
- open_swarm-0.1.1745274976.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 -97
- swarm/blueprints/geese/blueprint_geese.py +0 -803
- 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.1745274976.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
@@ -1,55 +0,0 @@
|
|
1
|
-
import argparse
|
2
|
-
import asyncio
|
3
|
-
from swarm.blueprints.jeeves.blueprint_jeeves import JeevesBlueprint, JeevesSpinner, display_operation_box, SPINNER_STATES
|
4
|
-
|
5
|
-
def main():
|
6
|
-
parser = argparse.ArgumentParser(description="Jeeves: Home automation and web search butler")
|
7
|
-
parser.add_argument("--instruction", type=str, help="Instruction for Jeeves to execute", default=None)
|
8
|
-
parser.add_argument("--message", dest='instruction', type=str, help="Instruction for Jeeves agent (alias --message)")
|
9
|
-
args = parser.parse_args()
|
10
|
-
bp = JeevesBlueprint(blueprint_id="jeeves")
|
11
|
-
|
12
|
-
async def run_instruction(instruction):
|
13
|
-
spinner = JeevesSpinner()
|
14
|
-
spinner.start()
|
15
|
-
try:
|
16
|
-
messages = [{"role": "user", "content": instruction}]
|
17
|
-
spinner_idx = 0
|
18
|
-
import time
|
19
|
-
spinner_start = time.time()
|
20
|
-
async for chunk in bp.run(messages):
|
21
|
-
if isinstance(chunk, dict) and (chunk.get("progress") or chunk.get("matches")):
|
22
|
-
elapsed = time.time() - spinner_start
|
23
|
-
spinner_state = spinner.current_spinner_state()
|
24
|
-
display_operation_box(
|
25
|
-
title="Progressive Operation",
|
26
|
-
content="\n".join(chunk.get("matches", [])),
|
27
|
-
style="bold cyan" if chunk.get("type") == "code_search" else "bold magenta",
|
28
|
-
result_count=len(chunk.get('matches', [])) if chunk.get("matches") is not None else None,
|
29
|
-
params={k: v for k, v in chunk.items() if k not in {'matches', 'progress', 'total', 'truncated', 'done'}},
|
30
|
-
progress_line=chunk.get('progress'),
|
31
|
-
total_lines=chunk.get('total'),
|
32
|
-
spinner_state=spinner_state,
|
33
|
-
op_type=chunk.get("type", "search"),
|
34
|
-
emoji="🔍" if chunk.get("type") == "code_search" else "🧠"
|
35
|
-
)
|
36
|
-
else:
|
37
|
-
print(chunk)
|
38
|
-
finally:
|
39
|
-
spinner.stop()
|
40
|
-
|
41
|
-
if args.instruction:
|
42
|
-
messages = [{"role": "user", "content": args.instruction}]
|
43
|
-
asyncio.run(run_instruction(args.instruction))
|
44
|
-
else:
|
45
|
-
print("[Jeeves CLI] Type your instruction and press Enter. Ctrl+C to exit.")
|
46
|
-
try:
|
47
|
-
while True:
|
48
|
-
user_input = input("You: ")
|
49
|
-
if user_input.strip():
|
50
|
-
asyncio.run(run_instruction(user_input.strip()))
|
51
|
-
except (KeyboardInterrupt, EOFError):
|
52
|
-
print("\nExiting Jeeves CLI.")
|
53
|
-
|
54
|
-
if __name__ == "__main__":
|
55
|
-
main()
|
@@ -1,24 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"name": "JeevesBlueprint",
|
3
|
-
"title": "Jeeves: Multi-Agent Home & Web Orchestration",
|
4
|
-
"description": "Demonstrates agent-based delegation for web search and home automation, with ANSI/emoji UX, spinner feedback, and robust fallback for agent/LLM errors.",
|
5
|
-
"author": "Open Swarm Team",
|
6
|
-
"version": "1.1.0",
|
7
|
-
"tags": ["agentic", "multi-agent", "home automation", "web search", "UX", "fallback", "demo"],
|
8
|
-
"demonstrates": [
|
9
|
-
"Multi-agent delegation and orchestration",
|
10
|
-
"Web search and home automation via agents",
|
11
|
-
"LLM fallback and error handling",
|
12
|
-
"Unified ANSI/emoji output and spinner",
|
13
|
-
"Result summaries and fallback",
|
14
|
-
"Test mode for robust testing"
|
15
|
-
],
|
16
|
-
"compliance": {
|
17
|
-
"agentic": true,
|
18
|
-
"ux_ansi_emoji": true,
|
19
|
-
"spinner": true,
|
20
|
-
"fallback": true,
|
21
|
-
"test_coverage": true
|
22
|
-
},
|
23
|
-
"last_updated": "2025-04-21T04:44:16Z"
|
24
|
-
}
|
@@ -1,473 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
MCPDemo Blueprint
|
3
|
-
|
4
|
-
Viral docstring update: Operational as of 2025-04-18T10:14:18Z (UTC).
|
5
|
-
Self-healing, fileops-enabled, swarm-scalable.
|
6
|
-
"""
|
7
|
-
# [Swarm Propagation] Next Blueprint: mission_improbable
|
8
|
-
# mission_improbable key vars: logger, project_root, src_path
|
9
|
-
# mission_improbable guard: if src_path not in sys.path: sys.path.insert(0, src_path)
|
10
|
-
# mission_improbable debug: logger.debug("Mission Improbable agent created: JimFlimsy (Coordinator)")
|
11
|
-
# mission_improbable error handling: try/except ImportError with sys.exit(1)
|
12
|
-
|
13
|
-
import logging
|
14
|
-
import os
|
15
|
-
import sys
|
16
|
-
import glob
|
17
|
-
import json
|
18
|
-
import concurrent.futures
|
19
|
-
from typing import Dict, Any, List, ClassVar, Optional
|
20
|
-
from datetime import datetime
|
21
|
-
import pytz
|
22
|
-
|
23
|
-
# Ensure src is in path for BlueprintBase import
|
24
|
-
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
25
|
-
src_path = os.path.join(project_root, 'src')
|
26
|
-
if src_path not in sys.path: sys.path.insert(0, src_path)
|
27
|
-
|
28
|
-
try:
|
29
|
-
from agents import Agent, Tool, function_tool, Runner
|
30
|
-
from agents.mcp import MCPServer
|
31
|
-
from agents.models.interface import Model
|
32
|
-
from agents.models.openai_chatcompletions import OpenAIChatCompletionsModel
|
33
|
-
from openai import AsyncOpenAI
|
34
|
-
from swarm.core.blueprint_base import BlueprintBase
|
35
|
-
from swarm.core.blueprint_discovery import discover_blueprints
|
36
|
-
except ImportError as e:
|
37
|
-
print(f"ERROR: Import failed in MCPDemoBlueprint: {e}. Check dependencies.")
|
38
|
-
print(f"sys.path: {sys.path}")
|
39
|
-
sys.exit(1)
|
40
|
-
|
41
|
-
logger = logging.getLogger(__name__)
|
42
|
-
|
43
|
-
# Last swarm update: 2025-04-18T10:15:21Z (UTC)
|
44
|
-
last_swarm_update = datetime.now(pytz.utc).strftime("%Y-%m-%dT%H:%M:%SZ (UTC)")
|
45
|
-
logger.info(f"Last swarm update: {last_swarm_update}")
|
46
|
-
|
47
|
-
# --- Agent Instructions ---
|
48
|
-
|
49
|
-
sage_instructions_template = """
|
50
|
-
You are Sage, an agent demonstrating capabilities provided by MCP servers.
|
51
|
-
You have access to the following external capabilities via implicitly available MCP tools:
|
52
|
-
{mcp_tool_descriptions}
|
53
|
-
|
54
|
-
Your goal is to understand the user's request and utilize the appropriate MCP tool to fulfill it.
|
55
|
-
For example:
|
56
|
-
- To write to a file, use the 'filesystem' tool's 'write' function.
|
57
|
-
- To read from memory, use the 'memory' tool's 'get' function.
|
58
|
-
- To store in memory, use the 'memory' tool's 'set' function.
|
59
|
-
- To perform viral file operations, provide a comma-separated list of paths or wildcard patterns.
|
60
|
-
|
61
|
-
You can scale file operations horizontally across multiple targets for performance.
|
62
|
-
Explain what action you are taking via which tool and report the result.
|
63
|
-
"""
|
64
|
-
|
65
|
-
# --- FileOps Tool Logic Definitions ---
|
66
|
-
# Patch: Expose underlying fileops functions for direct testing
|
67
|
-
class PatchedFunctionTool:
|
68
|
-
def __init__(self, func, name):
|
69
|
-
self.func = func
|
70
|
-
self.name = name
|
71
|
-
def read_file(path: str) -> str:
|
72
|
-
"""
|
73
|
-
Read contents of one or more files.
|
74
|
-
Supports wildcard patterns (e.g., '*.txt') and comma-separated lists of paths.
|
75
|
-
Returns a JSON mapping of paths to contents or error messages.
|
76
|
-
"""
|
77
|
-
try:
|
78
|
-
# Determine file paths
|
79
|
-
if ',' in path:
|
80
|
-
paths = [p.strip() for p in path.split(',')]
|
81
|
-
elif any(pat in path for pat in ['*', '?', '[']):
|
82
|
-
paths = glob.glob(path)
|
83
|
-
else:
|
84
|
-
paths = [path]
|
85
|
-
results: Dict[str, str] = {}
|
86
|
-
for p in paths:
|
87
|
-
try:
|
88
|
-
with open(p, 'r') as f:
|
89
|
-
results[p] = f.read()
|
90
|
-
except Exception as e:
|
91
|
-
results[p] = f"ERROR: {e}"
|
92
|
-
return json.dumps(results)
|
93
|
-
except Exception as e:
|
94
|
-
return f"ERROR: {e}"
|
95
|
-
def write_file(path: str, content: str) -> str:
|
96
|
-
"""
|
97
|
-
Write content to one or more files.
|
98
|
-
Supports wildcard patterns and comma-separated lists for viral file operations.
|
99
|
-
Returns a JSON mapping of paths to status ('OK' or error message).
|
100
|
-
"""
|
101
|
-
try:
|
102
|
-
# Determine file paths
|
103
|
-
if ',' in path:
|
104
|
-
paths = [p.strip() for p in path.split(',')]
|
105
|
-
elif any(pat in path for pat in ['*', '?', '[']):
|
106
|
-
paths = glob.glob(path)
|
107
|
-
else:
|
108
|
-
paths = [path]
|
109
|
-
results: Dict[str, str] = {}
|
110
|
-
# Write to all targets concurrently
|
111
|
-
def _write_single(p: str):
|
112
|
-
try:
|
113
|
-
with open(p, 'w') as f:
|
114
|
-
f.write(content)
|
115
|
-
return p, 'OK'
|
116
|
-
except Exception as e:
|
117
|
-
return p, f"ERROR: {e}"
|
118
|
-
with concurrent.futures.ThreadPoolExecutor() as executor:
|
119
|
-
futures = {executor.submit(_write_single, p): p for p in paths}
|
120
|
-
for fut in concurrent.futures.as_completed(futures):
|
121
|
-
p, status = fut.result()
|
122
|
-
results[p] = status
|
123
|
-
return json.dumps(results)
|
124
|
-
except Exception as e:
|
125
|
-
return f"ERROR: {e}"
|
126
|
-
def list_files(directory: str = '.') -> str:
|
127
|
-
"""
|
128
|
-
List files in one or more directories.
|
129
|
-
Supports wildcard patterns and comma-separated directory lists.
|
130
|
-
Returns a JSON mapping of directory to list of entries or error message.
|
131
|
-
"""
|
132
|
-
try:
|
133
|
-
# Determine directories
|
134
|
-
if ',' in directory:
|
135
|
-
dirs = [d.strip() for d in directory.split(',')]
|
136
|
-
elif any(pat in directory for pat in ['*', '?', '[']):
|
137
|
-
dirs = glob.glob(directory)
|
138
|
-
else:
|
139
|
-
dirs = [directory]
|
140
|
-
results: Dict[str, Any] = {}
|
141
|
-
for d in dirs:
|
142
|
-
try:
|
143
|
-
results[d] = os.listdir(d)
|
144
|
-
except Exception as e:
|
145
|
-
results[d] = f"ERROR: {e}"
|
146
|
-
return json.dumps(results)
|
147
|
-
except Exception as e:
|
148
|
-
return f"ERROR: {e}"
|
149
|
-
def execute_shell_command(command: str) -> str:
|
150
|
-
"""
|
151
|
-
Executes a shell command and returns its stdout and stderr.
|
152
|
-
Timeout is configurable via SWARM_COMMAND_TIMEOUT (default: 60s).
|
153
|
-
"""
|
154
|
-
logger.info(f"Executing shell command: {command}")
|
155
|
-
try:
|
156
|
-
import os
|
157
|
-
timeout = int(os.getenv("SWARM_COMMAND_TIMEOUT", "60"))
|
158
|
-
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=timeout)
|
159
|
-
output = f"Exit Code: {result.returncode}\n"
|
160
|
-
if result.stdout:
|
161
|
-
output += f"STDOUT:\n{result.stdout}\n"
|
162
|
-
if result.stderr:
|
163
|
-
output += f"STDERR:\n{result.stderr}\n"
|
164
|
-
logger.info(f"Command finished. Exit Code: {result.returncode}")
|
165
|
-
return output.strip()
|
166
|
-
except subprocess.TimeoutExpired:
|
167
|
-
logger.error(f"Command timed out: {command}")
|
168
|
-
return f"Error: Command timed out after {os.getenv('SWARM_COMMAND_TIMEOUT', '60')} seconds."
|
169
|
-
except Exception as e:
|
170
|
-
logger.error(f"Error executing command '{command}': {e}", exc_info=True)
|
171
|
-
return f"Error executing command: {e}"
|
172
|
-
read_file_tool = PatchedFunctionTool(read_file, 'read_file')
|
173
|
-
write_file_tool = PatchedFunctionTool(write_file, 'write_file')
|
174
|
-
list_files_tool = PatchedFunctionTool(list_files, 'list_files')
|
175
|
-
execute_shell_command_tool = PatchedFunctionTool(execute_shell_command, 'execute_shell_command')
|
176
|
-
|
177
|
-
# --- Spinner and ANSI/emoji operation box for unified UX (for CLI/dev runs) ---
|
178
|
-
from swarm.ux.ansi_box import ansi_box
|
179
|
-
from rich.console import Console
|
180
|
-
from rich.style import Style
|
181
|
-
from rich.text import Text
|
182
|
-
import threading
|
183
|
-
import time
|
184
|
-
|
185
|
-
class MCPDemoSpinner:
|
186
|
-
FRAMES = [
|
187
|
-
"Generating.", "Generating..", "Generating...", "Running...",
|
188
|
-
"⠋ Generating...", "⠙ Generating...", "⠹ Generating...", "⠸ Generating...",
|
189
|
-
"⠼ Generating...", "⠴ Generating...", "⠦ Generating...", "⠧ Generating...",
|
190
|
-
"⠇ Generating...", "⠏ Generating...", "🤖 Generating...", "💡 Generating...", "✨ Generating..."
|
191
|
-
]
|
192
|
-
SLOW_FRAME = "Generating... Taking longer than expected"
|
193
|
-
INTERVAL = 0.12
|
194
|
-
SLOW_THRESHOLD = 10 # seconds
|
195
|
-
|
196
|
-
def __init__(self):
|
197
|
-
self._stop_event = threading.Event()
|
198
|
-
self._thread = None
|
199
|
-
self._start_time = None
|
200
|
-
self.console = Console()
|
201
|
-
self._last_frame = None
|
202
|
-
self._last_slow = False
|
203
|
-
|
204
|
-
def start(self):
|
205
|
-
self._stop_event.clear()
|
206
|
-
self._start_time = time.time()
|
207
|
-
self._thread = threading.Thread(target=self._spin, daemon=True)
|
208
|
-
self._thread.start()
|
209
|
-
|
210
|
-
def _spin(self):
|
211
|
-
idx = 0
|
212
|
-
while not self._stop_event.is_set():
|
213
|
-
elapsed = time.time() - self._start_time
|
214
|
-
if elapsed > self.SLOW_THRESHOLD:
|
215
|
-
txt = Text(self.SLOW_FRAME, style=Style(color="yellow", bold=True))
|
216
|
-
self._last_frame = self.SLOW_FRAME
|
217
|
-
self._last_slow = True
|
218
|
-
else:
|
219
|
-
frame = self.FRAMES[idx % len(self.FRAMES)]
|
220
|
-
txt = Text(frame, style=Style(color="cyan", bold=True))
|
221
|
-
self._last_frame = frame
|
222
|
-
self._last_slow = False
|
223
|
-
self.console.print(txt, end="\r", soft_wrap=True, highlight=False)
|
224
|
-
time.sleep(self.INTERVAL)
|
225
|
-
idx += 1
|
226
|
-
self.console.print(" " * 40, end="\r") # Clear line
|
227
|
-
|
228
|
-
def stop(self, final_message="Done!"):
|
229
|
-
self._stop_event.set()
|
230
|
-
if self._thread:
|
231
|
-
self._thread.join()
|
232
|
-
self.console.print(Text(final_message, style=Style(color="green", bold=True)))
|
233
|
-
|
234
|
-
def current_spinner_state(self):
|
235
|
-
if self._last_slow:
|
236
|
-
return self.SLOW_FRAME
|
237
|
-
return self._last_frame or self.FRAMES[0]
|
238
|
-
|
239
|
-
|
240
|
-
def print_operation_box(op_type, results, params=None, result_type="mcp", taking_long=False):
|
241
|
-
emoji = "🧠" if result_type == "mcp" else "🔍"
|
242
|
-
style = 'success' if result_type == "mcp" else 'default'
|
243
|
-
box_title = op_type if op_type else ("MCPDemo Output" if result_type == "mcp" else "Results")
|
244
|
-
summary_lines = []
|
245
|
-
count = len(results) if isinstance(results, list) else 0
|
246
|
-
summary_lines.append(f"Results: {count}")
|
247
|
-
if params:
|
248
|
-
for k, v in params.items():
|
249
|
-
summary_lines.append(f"{k.capitalize()}: {v}")
|
250
|
-
box_content = "\n".join(summary_lines + ["\n".join(map(str, results))])
|
251
|
-
ansi_box(box_title, box_content, count=count, params=params, style=style if not taking_long else 'warning', emoji=emoji)
|
252
|
-
|
253
|
-
# --- Define the Blueprint ---
|
254
|
-
class MCPDemoBlueprint(BlueprintBase):
|
255
|
-
"""Demonstrates using filesystem and memory MCP servers."""
|
256
|
-
metadata: ClassVar[Dict[str, Any]] = {
|
257
|
-
"name": "MCPDemoBlueprint",
|
258
|
-
"title": "MCP Demo (Filesystem & Memory, Scalable & Viral FileOps)",
|
259
|
-
"description": "A scalable agent (Sage) demonstrating interaction with filesystem and memory MCP servers, supporting horizontal scaling and viral file operations.",
|
260
|
-
"version": "1.2.0", # Updated for scaling & viral fileops
|
261
|
-
"author": "Open Swarm Team (Refactored)",
|
262
|
-
"tags": ["mcp", "filesystem", "memory", "demo", "scaling", "viral-fileops"],
|
263
|
-
"required_mcp_servers": ["filesystem", "memory"],
|
264
|
-
"env_vars": ["ALLOWED_PATH"], # For filesystem MCP
|
265
|
-
}
|
266
|
-
|
267
|
-
# Caches
|
268
|
-
_openai_client_cache: Dict[str, AsyncOpenAI] = {}
|
269
|
-
_model_instance_cache: Dict[str, Model] = {}
|
270
|
-
|
271
|
-
def __init__(self, *args, **kwargs):
|
272
|
-
super().__init__(*args, **kwargs)
|
273
|
-
class DummyLLM:
|
274
|
-
def chat_completion_stream(self, messages, **_):
|
275
|
-
class DummyStream:
|
276
|
-
def __aiter__(self): return self
|
277
|
-
async def __anext__(self):
|
278
|
-
raise StopAsyncIteration
|
279
|
-
return DummyStream()
|
280
|
-
self.llm = DummyLLM()
|
281
|
-
|
282
|
-
# --- Model Instantiation Helper --- (Standard helper)
|
283
|
-
def _get_model_instance(self, profile_name: str) -> Model:
|
284
|
-
"""Retrieves or creates an LLM Model instance."""
|
285
|
-
# ... (Implementation is the same as in previous refactors) ...
|
286
|
-
if profile_name in self._model_instance_cache:
|
287
|
-
logger.debug(f"Using cached Model instance for profile '{profile_name}'.")
|
288
|
-
return self._model_instance_cache[profile_name]
|
289
|
-
logger.debug(f"Creating new Model instance for profile '{profile_name}'.")
|
290
|
-
profile_data = self.get_llm_profile(profile_name)
|
291
|
-
if not profile_data: raise ValueError(f"Missing LLM profile '{profile_name}'.")
|
292
|
-
provider = profile_data.get("provider", "openai").lower()
|
293
|
-
model_name = profile_data.get("model")
|
294
|
-
if not model_name: raise ValueError(f"Missing 'model' in profile '{profile_name}'.")
|
295
|
-
if provider != "openai": raise ValueError(f"Unsupported provider: {provider}")
|
296
|
-
client_cache_key = f"{provider}_{profile_data.get('base_url')}"
|
297
|
-
if client_cache_key not in self._openai_client_cache:
|
298
|
-
client_kwargs = { "api_key": profile_data.get("api_key"), "base_url": profile_data.get("base_url") }
|
299
|
-
filtered_kwargs = {k: v for k, v in client_kwargs.items() if v is not None}
|
300
|
-
log_kwargs = {k:v for k,v in filtered_kwargs.items() if k != 'api_key'}
|
301
|
-
logger.debug(f"Creating new AsyncOpenAI client for '{profile_name}': {log_kwargs}")
|
302
|
-
try: self._openai_client_cache[client_cache_key] = AsyncOpenAI(**filtered_kwargs)
|
303
|
-
except Exception as e: raise ValueError(f"Failed to init client: {e}") from e
|
304
|
-
client = self._openai_client_cache[client_cache_key]
|
305
|
-
logger.debug(f"Instantiating OpenAIChatCompletionsModel(model='{model_name}') for '{profile_name}'.")
|
306
|
-
try:
|
307
|
-
model_instance = OpenAIChatCompletionsModel(model=model_name, openai_client=client)
|
308
|
-
self._model_instance_cache[profile_name] = model_instance
|
309
|
-
return model_instance
|
310
|
-
except Exception as e: raise ValueError(f"Failed to init LLM: {e}") from e
|
311
|
-
|
312
|
-
def render_prompt(self, template_name: str, context: dict) -> str:
|
313
|
-
return f"User request: {context.get('user_request', '')}\nHistory: {context.get('history', '')}\nAvailable tools: {', '.join(context.get('available_tools', []))}"
|
314
|
-
|
315
|
-
# --- Agent Creation ---
|
316
|
-
def create_starting_agent(self, mcp_servers: List[MCPServer]) -> Agent:
|
317
|
-
"""Creates the Sage agent, dynamically adding MCP server descriptions to its prompt."""
|
318
|
-
logger.debug("Creating MCP Demo agent (Sage)...")
|
319
|
-
self._model_instance_cache = {}
|
320
|
-
self._openai_client_cache = {}
|
321
|
-
|
322
|
-
default_profile_name = self.config.get("llm_profile", "default")
|
323
|
-
logger.debug(f"Using LLM profile '{default_profile_name}' for Sage.")
|
324
|
-
model_instance = self._get_model_instance(default_profile_name)
|
325
|
-
|
326
|
-
# Filter for required MCPs and get descriptions
|
327
|
-
required_names = self.metadata["required_mcp_servers"]
|
328
|
-
agent_mcps: List[MCPServer] = []
|
329
|
-
mcp_descriptions = []
|
330
|
-
for server in mcp_servers:
|
331
|
-
if server.name in required_names:
|
332
|
-
agent_mcps.append(server)
|
333
|
-
description = self.get_mcp_server_description(server.name)
|
334
|
-
mcp_descriptions.append(f"- {server.name}: {description or 'No description available.'}")
|
335
|
-
|
336
|
-
if len(agent_mcps) != len(required_names):
|
337
|
-
missing = set(required_names) - {s.name for s in agent_mcps}
|
338
|
-
logger.warning(f"Sage agent created, but missing required MCP server(s): {', '.join(missing)}. Functionality will be limited.")
|
339
|
-
# Continue with available servers
|
340
|
-
|
341
|
-
# Format descriptions for the prompt
|
342
|
-
mcp_tool_desc_str = "\n".join(mcp_descriptions) if mcp_descriptions else "No external tools available."
|
343
|
-
sage_instructions = sage_instructions_template.format(mcp_tool_descriptions=mcp_tool_desc_str)
|
344
|
-
logger.debug(f"Sage instructions generated:\n{sage_instructions}")
|
345
|
-
|
346
|
-
# Instantiate Sage
|
347
|
-
sage_agent = Agent(
|
348
|
-
name="Sage",
|
349
|
-
model=model_instance,
|
350
|
-
instructions=sage_instructions,
|
351
|
-
tools=[read_file_tool, write_file_tool, list_files_tool, execute_shell_command_tool], # Tools come implicitly from assigned MCP servers
|
352
|
-
mcp_servers=agent_mcps # Pass the list of *started* server objects
|
353
|
-
)
|
354
|
-
|
355
|
-
logger.debug("Sage agent created.")
|
356
|
-
return sage_agent
|
357
|
-
|
358
|
-
async def _original_run(self, messages: List[dict]) -> object:
|
359
|
-
last_user_message = next((m['content'] for m in reversed(messages) if m['role'] == 'user'), None)
|
360
|
-
if not last_user_message:
|
361
|
-
yield {"messages": [{"role": "assistant", "content": "I need a user message to proceed."}]}
|
362
|
-
return
|
363
|
-
prompt_context = {
|
364
|
-
"user_request": last_user_message,
|
365
|
-
"history": messages[:-1],
|
366
|
-
"available_tools": ["demo"]
|
367
|
-
}
|
368
|
-
rendered_prompt = self.render_prompt("mcp_demo_prompt.j2", prompt_context)
|
369
|
-
yield {
|
370
|
-
"messages": [
|
371
|
-
{
|
372
|
-
"role": "assistant",
|
373
|
-
"content": f"[MCPDemo LLM] Would respond to: {rendered_prompt}"
|
374
|
-
}
|
375
|
-
]
|
376
|
-
}
|
377
|
-
return
|
378
|
-
|
379
|
-
async def run(self, messages: List[dict]) -> object:
|
380
|
-
last_result = None
|
381
|
-
async for result in self._original_run(messages):
|
382
|
-
last_result = result
|
383
|
-
yield result
|
384
|
-
if last_result is not None:
|
385
|
-
await self.reflect_and_learn(messages, last_result)
|
386
|
-
return
|
387
|
-
|
388
|
-
async def reflect_and_learn(self, messages, result):
|
389
|
-
log = {
|
390
|
-
'task': messages,
|
391
|
-
'result': result,
|
392
|
-
'reflection': 'Success' if self.success_criteria(result) else 'Needs improvement',
|
393
|
-
'alternatives': self.consider_alternatives(messages, result),
|
394
|
-
'swarm_lessons': self.query_swarm_knowledge(messages)
|
395
|
-
}
|
396
|
-
self.write_to_swarm_log(log)
|
397
|
-
|
398
|
-
def success_criteria(self, result):
|
399
|
-
if not result or (isinstance(result, dict) and 'error' in result):
|
400
|
-
return False
|
401
|
-
if isinstance(result, list) and result and 'error' in result[0].get('messages', [{}])[0].get('content', '').lower():
|
402
|
-
return False
|
403
|
-
return True
|
404
|
-
|
405
|
-
def consider_alternatives(self, messages, result):
|
406
|
-
alternatives = []
|
407
|
-
if not self.success_criteria(result):
|
408
|
-
alternatives.append('Try a different agent for the task.')
|
409
|
-
alternatives.append('Fallback to a simpler command.')
|
410
|
-
else:
|
411
|
-
alternatives.append('Add more agent-to-agent coordination.')
|
412
|
-
return alternatives
|
413
|
-
|
414
|
-
def query_swarm_knowledge(self, messages):
|
415
|
-
import json, os
|
416
|
-
path = os.path.join(os.path.dirname(__file__), '../../../swarm_knowledge.json')
|
417
|
-
if not os.path.exists(path):
|
418
|
-
return []
|
419
|
-
with open(path, 'r') as f:
|
420
|
-
knowledge = json.load(f)
|
421
|
-
task_str = json.dumps(messages)
|
422
|
-
return [entry for entry in knowledge if entry.get('task_str') == task_str]
|
423
|
-
|
424
|
-
def write_to_swarm_log(self, log):
|
425
|
-
import json, os, time
|
426
|
-
from filelock import FileLock, Timeout
|
427
|
-
path = os.path.join(os.path.dirname(__file__), '../../../swarm_log.json')
|
428
|
-
lock_path = path + '.lock'
|
429
|
-
log['task_str'] = json.dumps(log['task'])
|
430
|
-
for attempt in range(10):
|
431
|
-
try:
|
432
|
-
with FileLock(lock_path, timeout=5):
|
433
|
-
if os.path.exists(path):
|
434
|
-
with open(path, 'r') as f:
|
435
|
-
try:
|
436
|
-
logs = json.load(f)
|
437
|
-
except json.JSONDecodeError:
|
438
|
-
logs = []
|
439
|
-
else:
|
440
|
-
logs = []
|
441
|
-
logs.append(log)
|
442
|
-
with open(path, 'w') as f:
|
443
|
-
json.dump(logs, f, indent=2)
|
444
|
-
break
|
445
|
-
except Timeout:
|
446
|
-
time.sleep(0.2 * (attempt + 1))
|
447
|
-
|
448
|
-
# Standard Python entry point
|
449
|
-
if __name__ == "__main__":
|
450
|
-
import asyncio
|
451
|
-
import json
|
452
|
-
print("\033[1;36m\n╔══════════════════════════════════════════════════════════════╗\n║ 🧠 MCP DEMO: AGENT INTERACTION & SWARM DEBUG DEMO ║\n╠══════════════════════════════════════════════════════════════╣\n║ This blueprint showcases viral swarm propagation, ║\n║ agent-to-agent interaction, and advanced debug logging. ║\n║ Try running: python blueprint_mcp_demo.py ║\n╚══════════════════════════════════════════════════════════════╝\033[0m")
|
453
|
-
messages = [
|
454
|
-
{"role": "user", "content": "Show me how MCP Demo enables agent interaction and swarm debug logging."}
|
455
|
-
]
|
456
|
-
blueprint = MCPDemoBlueprint(blueprint_id="demo-1")
|
457
|
-
async def run_and_print():
|
458
|
-
spinner = MCPDemoSpinner()
|
459
|
-
spinner.start()
|
460
|
-
try:
|
461
|
-
all_results = []
|
462
|
-
async for response in blueprint.run(messages):
|
463
|
-
content = response["messages"][0]["content"]
|
464
|
-
all_results.append(content)
|
465
|
-
finally:
|
466
|
-
spinner.stop()
|
467
|
-
print_operation_box(
|
468
|
-
op_type="MCPDemo Output",
|
469
|
-
results=all_results,
|
470
|
-
params={"prompt": messages[0]["content"]},
|
471
|
-
result_type="mcp"
|
472
|
-
)
|
473
|
-
asyncio.run(run_and_print())
|
@@ -1,46 +0,0 @@
|
|
1
|
-
{% load static %}
|
2
|
-
<!DOCTYPE html>
|
3
|
-
<html lang="en">
|
4
|
-
<head>
|
5
|
-
{% include 'rest_mode/components/header.html' %}
|
6
|
-
<link rel="stylesheet" href="{% static 'rest_mode/css/messenger.css' %}">
|
7
|
-
<script>
|
8
|
-
window.STATIC_URLS = {
|
9
|
-
layoutSidebarLeftExpand: "{% static 'contrib/tabler-icons/layout-sidebar-left-expand.svg' %}",
|
10
|
-
layoutSidebarLeftCollapse: "{% static 'contrib/tabler-icons/layout-sidebar-left-collapse.svg' %}"
|
11
|
-
};
|
12
|
-
</script>
|
13
|
-
</head>
|
14
|
-
<body>
|
15
|
-
{% include 'rest_mode/components/top_bar.html' %}
|
16
|
-
{% include 'rest_mode/components/settings_dialog.html' %}
|
17
|
-
<div class="container" data-theme-color="corporate" data-theme-dark="false" data-theme-layout="messenger-layout">
|
18
|
-
<div class="side-panes chat-history-pane" id="channelPane">
|
19
|
-
<div class="chat-history-header">
|
20
|
-
<button class="input-button chat-history-button" id="toggleSidebar" aria-label="Toggle Sidebar">
|
21
|
-
<img src="{% static 'contrib/tabler-icons/layout-sidebar-left-collapse.svg' %}" alt="Collapse Sidebar">
|
22
|
-
</button>
|
23
|
-
<button class="input-button upload-button" id="settingsToggleButton" aria-label="Toggle Settings">
|
24
|
-
<img src="{% static 'contrib/tabler-icons/settings.svg' %}" alt="Settings">
|
25
|
-
</button>
|
26
|
-
<button class="input-button search-button" title="Search" aria-label="Search Channels">
|
27
|
-
<img src="{% static 'contrib/tabler-icons/search.svg' %}" alt="Search">
|
28
|
-
</button>
|
29
|
-
</div>
|
30
|
-
<h3>Channels</h3>
|
31
|
-
<ul id="channelList" class="chat-history-list">
|
32
|
-
<li data-blueprint-id="welcome">#Welcome to Open-Swarm</li>
|
33
|
-
</ul>
|
34
|
-
</div>
|
35
|
-
<div class="vertical-divider" id="divider-left"></div>
|
36
|
-
<div class="main-pane">
|
37
|
-
{% include 'rest_mode/components/main_chat_pane.html' %}
|
38
|
-
</div>
|
39
|
-
<div id="toastContainer"></div>
|
40
|
-
</div>
|
41
|
-
<div class="settings-overlay"></div>
|
42
|
-
<script type="module" src="{% static 'contrib/markedjs/marked.min.js' %}"></script>
|
43
|
-
<script type="module" src="{% static 'rest_mode/js/settings.js' %}"></script>
|
44
|
-
<script type="module" src="{% static 'rest_mode/js/messengerLogic.js' %}"></script>
|
45
|
-
</body>
|
46
|
-
</html>
|