open-swarm 0.1.1745275181__py3-none-any.whl → 0.1.1748636259__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. open_swarm-0.1.1748636259.dist-info/METADATA +188 -0
  2. open_swarm-0.1.1748636259.dist-info/RECORD +82 -0
  3. {open_swarm-0.1.1745275181.dist-info → open_swarm-0.1.1748636259.dist-info}/WHEEL +2 -1
  4. open_swarm-0.1.1748636259.dist-info/entry_points.txt +3 -0
  5. open_swarm-0.1.1748636259.dist-info/top_level.txt +1 -0
  6. swarm/agent/agent.py +49 -0
  7. swarm/auth.py +48 -113
  8. swarm/consumers.py +0 -19
  9. swarm/extensions/blueprint/__init__.py +16 -30
  10. swarm/{core → extensions/blueprint}/agent_utils.py +1 -1
  11. swarm/extensions/blueprint/blueprint_base.py +458 -0
  12. swarm/extensions/blueprint/blueprint_discovery.py +112 -0
  13. swarm/extensions/blueprint/output_utils.py +95 -0
  14. swarm/{core → extensions/blueprint}/spinner.py +21 -30
  15. swarm/extensions/cli/cli_args.py +0 -6
  16. swarm/extensions/cli/commands/blueprint_management.py +9 -47
  17. swarm/extensions/cli/commands/config_management.py +6 -5
  18. swarm/extensions/cli/commands/edit_config.py +7 -16
  19. swarm/extensions/cli/commands/list_blueprints.py +1 -1
  20. swarm/extensions/cli/commands/validate_env.py +4 -11
  21. swarm/extensions/cli/commands/validate_envvars.py +6 -6
  22. swarm/extensions/cli/interactive_shell.py +2 -16
  23. swarm/extensions/config/config_loader.py +201 -107
  24. swarm/{core → extensions/config}/config_manager.py +38 -50
  25. swarm/{core → extensions/config}/server_config.py +0 -32
  26. swarm/extensions/launchers/build_launchers.py +14 -0
  27. swarm/{core → extensions/launchers}/build_swarm_wrapper.py +0 -0
  28. swarm/extensions/launchers/swarm_api.py +64 -8
  29. swarm/extensions/launchers/swarm_cli.py +300 -8
  30. swarm/llm/chat_completion.py +195 -0
  31. swarm/serializers.py +5 -96
  32. swarm/settings.py +111 -99
  33. swarm/urls.py +74 -57
  34. swarm/utils/context_utils.py +4 -10
  35. swarm/utils/general_utils.py +0 -21
  36. swarm/utils/redact.py +36 -23
  37. swarm/views/api_views.py +39 -48
  38. swarm/views/chat_views.py +70 -237
  39. swarm/views/core_views.py +87 -80
  40. swarm/views/model_views.py +121 -64
  41. swarm/views/utils.py +441 -65
  42. swarm/views/web_views.py +2 -2
  43. open_swarm-0.1.1745275181.dist-info/METADATA +0 -874
  44. open_swarm-0.1.1745275181.dist-info/RECORD +0 -319
  45. open_swarm-0.1.1745275181.dist-info/entry_points.txt +0 -4
  46. swarm/blueprints/README.md +0 -68
  47. swarm/blueprints/blueprint_audit_status.json +0 -27
  48. swarm/blueprints/chatbot/README.md +0 -40
  49. swarm/blueprints/chatbot/blueprint_chatbot.py +0 -471
  50. swarm/blueprints/chatbot/metadata.json +0 -23
  51. swarm/blueprints/chatbot/templates/chatbot/chatbot.html +0 -33
  52. swarm/blueprints/chucks_angels/README.md +0 -11
  53. swarm/blueprints/chucks_angels/blueprint_chucks_angels.py +0 -7
  54. swarm/blueprints/chucks_angels/test_basic.py +0 -3
  55. swarm/blueprints/codey/CODEY.md +0 -15
  56. swarm/blueprints/codey/README.md +0 -115
  57. swarm/blueprints/codey/blueprint_codey.py +0 -1072
  58. swarm/blueprints/codey/codey_cli.py +0 -373
  59. swarm/blueprints/codey/instructions.md +0 -17
  60. swarm/blueprints/codey/metadata.json +0 -23
  61. swarm/blueprints/common/operation_box_utils.py +0 -83
  62. swarm/blueprints/digitalbutlers/README.md +0 -11
  63. swarm/blueprints/digitalbutlers/__init__.py +0 -1
  64. swarm/blueprints/digitalbutlers/blueprint_digitalbutlers.py +0 -7
  65. swarm/blueprints/digitalbutlers/test_basic.py +0 -3
  66. swarm/blueprints/divine_code/README.md +0 -3
  67. swarm/blueprints/divine_code/__init__.py +0 -10
  68. swarm/blueprints/divine_code/apps.py +0 -11
  69. swarm/blueprints/divine_code/blueprint_divine_code.py +0 -270
  70. swarm/blueprints/django_chat/apps.py +0 -6
  71. swarm/blueprints/django_chat/blueprint_django_chat.py +0 -268
  72. swarm/blueprints/django_chat/templates/django_chat/django_chat_webpage.html +0 -37
  73. swarm/blueprints/django_chat/urls.py +0 -8
  74. swarm/blueprints/django_chat/views.py +0 -32
  75. swarm/blueprints/echocraft/blueprint_echocraft.py +0 -384
  76. swarm/blueprints/flock/README.md +0 -11
  77. swarm/blueprints/flock/__init__.py +0 -8
  78. swarm/blueprints/flock/blueprint_flock.py +0 -7
  79. swarm/blueprints/flock/test_basic.py +0 -3
  80. swarm/blueprints/geese/README.md +0 -10
  81. swarm/blueprints/geese/__init__.py +0 -8
  82. swarm/blueprints/geese/blueprint_geese.py +0 -384
  83. swarm/blueprints/geese/geese_cli.py +0 -102
  84. swarm/blueprints/jeeves/README.md +0 -41
  85. swarm/blueprints/jeeves/blueprint_jeeves.py +0 -722
  86. swarm/blueprints/jeeves/jeeves_cli.py +0 -55
  87. swarm/blueprints/jeeves/metadata.json +0 -24
  88. swarm/blueprints/mcp_demo/blueprint_mcp_demo.py +0 -473
  89. swarm/blueprints/messenger/templates/messenger/messenger.html +0 -46
  90. swarm/blueprints/mission_improbable/blueprint_mission_improbable.py +0 -423
  91. swarm/blueprints/monkai_magic/blueprint_monkai_magic.py +0 -340
  92. swarm/blueprints/nebula_shellz/blueprint_nebula_shellz.py +0 -265
  93. swarm/blueprints/omniplex/blueprint_omniplex.py +0 -298
  94. swarm/blueprints/poets/blueprint_poets.py +0 -546
  95. swarm/blueprints/poets/poets_cli.py +0 -23
  96. swarm/blueprints/rue_code/README.md +0 -8
  97. swarm/blueprints/rue_code/blueprint_rue_code.py +0 -448
  98. swarm/blueprints/rue_code/rue_code_cli.py +0 -43
  99. swarm/blueprints/stewie/apps.py +0 -12
  100. swarm/blueprints/stewie/blueprint_family_ties.py +0 -349
  101. swarm/blueprints/stewie/models.py +0 -19
  102. swarm/blueprints/stewie/serializers.py +0 -10
  103. swarm/blueprints/stewie/settings.py +0 -17
  104. swarm/blueprints/stewie/urls.py +0 -11
  105. swarm/blueprints/stewie/views.py +0 -26
  106. swarm/blueprints/suggestion/blueprint_suggestion.py +0 -222
  107. swarm/blueprints/whinge_surf/README.md +0 -22
  108. swarm/blueprints/whinge_surf/__init__.py +0 -1
  109. swarm/blueprints/whinge_surf/blueprint_whinge_surf.py +0 -565
  110. swarm/blueprints/whinge_surf/whinge_surf_cli.py +0 -99
  111. swarm/blueprints/whiskeytango_foxtrot/__init__.py +0 -0
  112. swarm/blueprints/whiskeytango_foxtrot/apps.py +0 -11
  113. swarm/blueprints/whiskeytango_foxtrot/blueprint_whiskeytango_foxtrot.py +0 -339
  114. swarm/blueprints/zeus/__init__.py +0 -2
  115. swarm/blueprints/zeus/apps.py +0 -4
  116. swarm/blueprints/zeus/blueprint_zeus.py +0 -270
  117. swarm/blueprints/zeus/zeus_cli.py +0 -13
  118. swarm/cli/async_input.py +0 -65
  119. swarm/cli/async_input_demo.py +0 -32
  120. swarm/core/blueprint_base.py +0 -769
  121. swarm/core/blueprint_discovery.py +0 -125
  122. swarm/core/blueprint_runner.py +0 -59
  123. swarm/core/blueprint_ux.py +0 -109
  124. swarm/core/build_launchers.py +0 -15
  125. swarm/core/cli/__init__.py +0 -1
  126. swarm/core/cli/commands/__init__.py +0 -1
  127. swarm/core/cli/commands/blueprint_management.py +0 -7
  128. swarm/core/cli/interactive_shell.py +0 -14
  129. swarm/core/cli/main.py +0 -50
  130. swarm/core/cli/utils/__init__.py +0 -1
  131. swarm/core/cli/utils/discover_commands.py +0 -18
  132. swarm/core/config_loader.py +0 -122
  133. swarm/core/output_utils.py +0 -193
  134. swarm/core/session_logger.py +0 -42
  135. swarm/core/slash_commands.py +0 -89
  136. swarm/core/swarm_api.py +0 -68
  137. swarm/core/swarm_cli.py +0 -216
  138. swarm/core/utils/__init__.py +0 -0
  139. swarm/extensions/blueprint/cli_handler.py +0 -197
  140. swarm/extensions/blueprint/runnable_blueprint.py +0 -42
  141. swarm/extensions/cli/utils/__init__.py +0 -1
  142. swarm/extensions/cli/utils/async_input.py +0 -46
  143. swarm/extensions/cli/utils/prompt_user.py +0 -3
  144. swarm/management/__init__.py +0 -0
  145. swarm/management/commands/__init__.py +0 -0
  146. swarm/management/commands/runserver.py +0 -58
  147. swarm/middleware.py +0 -65
  148. swarm/permissions.py +0 -38
  149. swarm/static/contrib/fonts/fontawesome-webfont.ttf +0 -7
  150. swarm/static/contrib/fonts/fontawesome-webfont.woff +0 -7
  151. swarm/static/contrib/fonts/fontawesome-webfont.woff2 +0 -7
  152. swarm/static/contrib/markedjs/marked.min.js +0 -6
  153. swarm/static/contrib/tabler-icons/adjustments-horizontal.svg +0 -27
  154. swarm/static/contrib/tabler-icons/alert-triangle.svg +0 -21
  155. swarm/static/contrib/tabler-icons/archive.svg +0 -21
  156. swarm/static/contrib/tabler-icons/artboard.svg +0 -27
  157. swarm/static/contrib/tabler-icons/automatic-gearbox.svg +0 -23
  158. swarm/static/contrib/tabler-icons/box-multiple.svg +0 -19
  159. swarm/static/contrib/tabler-icons/carambola.svg +0 -19
  160. swarm/static/contrib/tabler-icons/copy.svg +0 -20
  161. swarm/static/contrib/tabler-icons/download.svg +0 -21
  162. swarm/static/contrib/tabler-icons/edit.svg +0 -21
  163. swarm/static/contrib/tabler-icons/filled/carambola.svg +0 -13
  164. swarm/static/contrib/tabler-icons/filled/paint.svg +0 -13
  165. swarm/static/contrib/tabler-icons/headset.svg +0 -22
  166. swarm/static/contrib/tabler-icons/layout-sidebar-left-collapse.svg +0 -21
  167. swarm/static/contrib/tabler-icons/layout-sidebar-left-expand.svg +0 -21
  168. swarm/static/contrib/tabler-icons/layout-sidebar-right-collapse.svg +0 -21
  169. swarm/static/contrib/tabler-icons/layout-sidebar-right-expand.svg +0 -21
  170. swarm/static/contrib/tabler-icons/message-chatbot.svg +0 -22
  171. swarm/static/contrib/tabler-icons/message-star.svg +0 -22
  172. swarm/static/contrib/tabler-icons/message-x.svg +0 -23
  173. swarm/static/contrib/tabler-icons/message.svg +0 -21
  174. swarm/static/contrib/tabler-icons/paperclip.svg +0 -18
  175. swarm/static/contrib/tabler-icons/playlist-add.svg +0 -22
  176. swarm/static/contrib/tabler-icons/robot.svg +0 -26
  177. swarm/static/contrib/tabler-icons/search.svg +0 -19
  178. swarm/static/contrib/tabler-icons/settings.svg +0 -20
  179. swarm/static/contrib/tabler-icons/thumb-down.svg +0 -19
  180. swarm/static/contrib/tabler-icons/thumb-up.svg +0 -19
  181. swarm/static/css/dropdown.css +0 -22
  182. swarm/static/htmx/htmx.min.js +0 -0
  183. swarm/static/js/dropdown.js +0 -23
  184. swarm/static/rest_mode/css/base.css +0 -470
  185. swarm/static/rest_mode/css/chat-history.css +0 -286
  186. swarm/static/rest_mode/css/chat.css +0 -251
  187. swarm/static/rest_mode/css/chatbot.css +0 -74
  188. swarm/static/rest_mode/css/chatgpt.css +0 -62
  189. swarm/static/rest_mode/css/colors/corporate.css +0 -74
  190. swarm/static/rest_mode/css/colors/pastel.css +0 -81
  191. swarm/static/rest_mode/css/colors/tropical.css +0 -82
  192. swarm/static/rest_mode/css/general.css +0 -142
  193. swarm/static/rest_mode/css/layout.css +0 -167
  194. swarm/static/rest_mode/css/layouts/messenger-layout.css +0 -17
  195. swarm/static/rest_mode/css/layouts/minimalist-layout.css +0 -57
  196. swarm/static/rest_mode/css/layouts/mobile-layout.css +0 -8
  197. swarm/static/rest_mode/css/messages.css +0 -84
  198. swarm/static/rest_mode/css/messenger.css +0 -135
  199. swarm/static/rest_mode/css/settings.css +0 -91
  200. swarm/static/rest_mode/css/simple.css +0 -44
  201. swarm/static/rest_mode/css/slack.css +0 -58
  202. swarm/static/rest_mode/css/style.css +0 -156
  203. swarm/static/rest_mode/css/theme.css +0 -30
  204. swarm/static/rest_mode/css/toast.css +0 -40
  205. swarm/static/rest_mode/js/auth.js +0 -9
  206. swarm/static/rest_mode/js/blueprint.js +0 -41
  207. swarm/static/rest_mode/js/blueprintUtils.js +0 -12
  208. swarm/static/rest_mode/js/chatLogic.js +0 -79
  209. swarm/static/rest_mode/js/debug.js +0 -63
  210. swarm/static/rest_mode/js/events.js +0 -98
  211. swarm/static/rest_mode/js/main.js +0 -19
  212. swarm/static/rest_mode/js/messages.js +0 -264
  213. swarm/static/rest_mode/js/messengerLogic.js +0 -355
  214. swarm/static/rest_mode/js/modules/apiService.js +0 -84
  215. swarm/static/rest_mode/js/modules/blueprintManager.js +0 -162
  216. swarm/static/rest_mode/js/modules/chatHistory.js +0 -110
  217. swarm/static/rest_mode/js/modules/debugLogger.js +0 -14
  218. swarm/static/rest_mode/js/modules/eventHandlers.js +0 -107
  219. swarm/static/rest_mode/js/modules/messageProcessor.js +0 -120
  220. swarm/static/rest_mode/js/modules/state.js +0 -7
  221. swarm/static/rest_mode/js/modules/userInteractions.js +0 -29
  222. swarm/static/rest_mode/js/modules/validation.js +0 -23
  223. swarm/static/rest_mode/js/rendering.js +0 -119
  224. swarm/static/rest_mode/js/settings.js +0 -130
  225. swarm/static/rest_mode/js/sidebar.js +0 -94
  226. swarm/static/rest_mode/js/simpleLogic.js +0 -37
  227. swarm/static/rest_mode/js/slackLogic.js +0 -66
  228. swarm/static/rest_mode/js/splash.js +0 -76
  229. swarm/static/rest_mode/js/theme.js +0 -111
  230. swarm/static/rest_mode/js/toast.js +0 -36
  231. swarm/static/rest_mode/js/ui.js +0 -265
  232. swarm/static/rest_mode/js/validation.js +0 -57
  233. swarm/static/rest_mode/svg/animated_spinner.svg +0 -12
  234. swarm/static/rest_mode/svg/arrow_down.svg +0 -5
  235. swarm/static/rest_mode/svg/arrow_left.svg +0 -5
  236. swarm/static/rest_mode/svg/arrow_right.svg +0 -5
  237. swarm/static/rest_mode/svg/arrow_up.svg +0 -5
  238. swarm/static/rest_mode/svg/attach.svg +0 -8
  239. swarm/static/rest_mode/svg/avatar.svg +0 -7
  240. swarm/static/rest_mode/svg/canvas.svg +0 -6
  241. swarm/static/rest_mode/svg/chat_history.svg +0 -4
  242. swarm/static/rest_mode/svg/close.svg +0 -5
  243. swarm/static/rest_mode/svg/copy.svg +0 -4
  244. swarm/static/rest_mode/svg/dark_mode.svg +0 -3
  245. swarm/static/rest_mode/svg/edit.svg +0 -5
  246. swarm/static/rest_mode/svg/layout.svg +0 -9
  247. swarm/static/rest_mode/svg/logo.svg +0 -29
  248. swarm/static/rest_mode/svg/logout.svg +0 -5
  249. swarm/static/rest_mode/svg/mobile.svg +0 -5
  250. swarm/static/rest_mode/svg/new_chat.svg +0 -4
  251. swarm/static/rest_mode/svg/not_visible.svg +0 -5
  252. swarm/static/rest_mode/svg/plus.svg +0 -7
  253. swarm/static/rest_mode/svg/run_code.svg +0 -6
  254. swarm/static/rest_mode/svg/save.svg +0 -4
  255. swarm/static/rest_mode/svg/search.svg +0 -6
  256. swarm/static/rest_mode/svg/settings.svg +0 -4
  257. swarm/static/rest_mode/svg/speaker.svg +0 -5
  258. swarm/static/rest_mode/svg/stop.svg +0 -6
  259. swarm/static/rest_mode/svg/thumbs_down.svg +0 -3
  260. swarm/static/rest_mode/svg/thumbs_up.svg +0 -3
  261. swarm/static/rest_mode/svg/toggle_off.svg +0 -6
  262. swarm/static/rest_mode/svg/toggle_on.svg +0 -6
  263. swarm/static/rest_mode/svg/trash.svg +0 -10
  264. swarm/static/rest_mode/svg/undo.svg +0 -3
  265. swarm/static/rest_mode/svg/visible.svg +0 -8
  266. swarm/static/rest_mode/svg/voice.svg +0 -10
  267. swarm/templates/account/login.html +0 -22
  268. swarm/templates/account/signup.html +0 -32
  269. swarm/templates/base.html +0 -30
  270. swarm/templates/chat.html +0 -43
  271. swarm/templates/index.html +0 -35
  272. swarm/templates/rest_mode/components/chat_sidebar.html +0 -55
  273. swarm/templates/rest_mode/components/header.html +0 -45
  274. swarm/templates/rest_mode/components/main_chat_pane.html +0 -41
  275. swarm/templates/rest_mode/components/settings_dialog.html +0 -97
  276. swarm/templates/rest_mode/components/splash_screen.html +0 -7
  277. swarm/templates/rest_mode/components/top_bar.html +0 -28
  278. swarm/templates/rest_mode/message_ui.html +0 -50
  279. swarm/templates/rest_mode/slackbot.html +0 -30
  280. swarm/templates/simple_blueprint_page.html +0 -24
  281. swarm/templates/websocket_partials/final_system_message.html +0 -3
  282. swarm/templates/websocket_partials/system_message.html +0 -4
  283. swarm/templates/websocket_partials/user_message.html +0 -5
  284. swarm/utils/ansi_box.py +0 -34
  285. swarm/utils/disable_tracing.py +0 -38
  286. swarm/utils/log_utils.py +0 -63
  287. swarm/utils/openai_patch.py +0 -33
  288. swarm/ux/ansi_box.py +0 -43
  289. swarm/ux/spinner.py +0 -53
  290. {open_swarm-0.1.1745275181.dist-info → open_swarm-0.1.1748636259.dist-info}/licenses/LICENSE +0 -0
  291. /swarm/{core → extensions/blueprint}/blueprint_utils.py +0 -0
  292. /swarm/{core → extensions/blueprint}/common_utils.py +0 -0
  293. /swarm/{core → extensions/config}/setup_wizard.py +0 -0
  294. /swarm/{blueprints/rue_code → extensions/config/utils}/__init__.py +0 -0
  295. /swarm/{core → extensions/config}/utils/logger.py +0 -0
  296. /swarm/{core → extensions/launchers}/swarm_wrapper.py +0 -0
@@ -1,423 +0,0 @@
1
- """
2
- MissionImprobable Blueprint
3
-
4
- Viral docstring update: Operational as of 2025-04-18T10:14:18Z (UTC).
5
- Self-healing, fileops-enabled, swarm-scalable.
6
- """
7
- import logging
8
- import os
9
- import sys
10
- import json
11
- import sqlite3 # Use standard sqlite3 module
12
- from pathlib import Path
13
- from typing import Dict, Any, List, ClassVar, Optional
14
- from datetime import datetime
15
- import pytz
16
-
17
- # Last swarm update: 2025-04-18T10:15:21Z (UTC)
18
-
19
- # Ensure src is in path for BlueprintBase import
20
- project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
21
- src_path = os.path.join(project_root, 'src')
22
- if src_path not in sys.path: sys.path.insert(0, src_path)
23
-
24
- try:
25
- from agents import Agent, Tool, function_tool, Runner
26
- from agents.mcp import MCPServer
27
- from agents.models.interface import Model
28
- from agents.models.openai_chatcompletions import OpenAIChatCompletionsModel
29
- from openai import AsyncOpenAI
30
- from swarm.core.blueprint_base import BlueprintBase
31
- from swarm.core.blueprint_ux import BlueprintUXImproved
32
- except ImportError as e:
33
- print(f"ERROR: Import failed in MissionImprobableBlueprint: {e}. Check dependencies.")
34
- print(f"sys.path: {sys.path}")
35
- sys.exit(1)
36
-
37
- logger = logging.getLogger(__name__)
38
-
39
- # Patch: Expose underlying fileops functions for direct testing
40
- class PatchedFunctionTool:
41
- def __init__(self, func, name):
42
- self.func = func
43
- self.name = name
44
-
45
- def read_file(path: str) -> str:
46
- try:
47
- with open(path, 'r') as f:
48
- return f.read()
49
- except Exception as e:
50
- return f"ERROR: {e}"
51
- def write_file(path: str, content: str) -> str:
52
- try:
53
- with open(path, 'w') as f:
54
- f.write(content)
55
- return "OK: file written"
56
- except Exception as e:
57
- return f"ERROR: {e}"
58
- def list_files(directory: str = '.') -> str:
59
- try:
60
- return '\n'.join(os.listdir(directory))
61
- except Exception as e:
62
- return f"ERROR: {e}"
63
- def execute_shell_command(command: str) -> str:
64
- """
65
- Executes a shell command and returns its stdout and stderr.
66
- Timeout is configurable via SWARM_COMMAND_TIMEOUT (default: 60s).
67
- """
68
- logger.info(f"Executing shell command: {command}")
69
- try:
70
- import os
71
- timeout = int(os.getenv("SWARM_COMMAND_TIMEOUT", "60"))
72
- result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=timeout)
73
- output = f"Exit Code: {result.returncode}\n"
74
- if result.stdout:
75
- output += f"STDOUT:\n{result.stdout}\n"
76
- if result.stderr:
77
- output += f"STDERR:\n{result.stderr}\n"
78
- logger.info(f"Command finished. Exit Code: {result.returncode}")
79
- return output.strip()
80
- except subprocess.TimeoutExpired:
81
- logger.error(f"Command timed out: {command}")
82
- return f"Error: Command timed out after {os.getenv('SWARM_COMMAND_TIMEOUT', '60')} seconds."
83
- except Exception as e:
84
- logger.error(f"Error executing command '{command}': {e}", exc_info=True)
85
- return f"Error executing command: {e}"
86
- read_file_tool = PatchedFunctionTool(read_file, 'read_file')
87
- write_file_tool = PatchedFunctionTool(write_file, 'write_file')
88
- list_files_tool = PatchedFunctionTool(list_files, 'list_files')
89
- execute_shell_command_tool = PatchedFunctionTool(execute_shell_command, 'execute_shell_command')
90
-
91
- # --- Database Constants ---
92
- # Using the same DB file as dilbot_universe
93
- DB_FILE_NAME = "swarm_instructions.db"
94
- DB_PATH = Path(project_root) / DB_FILE_NAME
95
- TABLE_NAME = "agent_instructions" # agent_name TEXT PRIMARY KEY, instruction_text TEXT, model_profile TEXT
96
-
97
- # Spinner UX enhancement (Open Swarm TODO)
98
- SPINNER_STATES = ['Generating.', 'Generating..', 'Generating...', 'Running...']
99
-
100
- # --- Define the Blueprint ---
101
- # Renamed class for consistency
102
- class MissionImprobableBlueprint(BlueprintBase):
103
- """A cheeky team on a mission: led by JimFlimsy with support from CinnamonToast and RollinFumble."""
104
- metadata: ClassVar[Dict[str, Any]] = {
105
- "name": "MissionImprobableBlueprint",
106
- "title": "Mission: Improbable",
107
- "description": "A cheeky team led by JimFlimsy (coordinator), CinnamonToast (strategist/filesystem), and RollinFumble (operative/shell). Uses SQLite for instructions.",
108
- "version": "1.1.0", # Refactored version
109
- "author": "Open Swarm Team (Refactored)",
110
- "tags": ["comedy", "multi-agent", "filesystem", "shell", "sqlite"],
111
- "required_mcp_servers": ["memory", "filesystem", "mcp-shell"], # Servers needed by the agents
112
- "env_vars": ["ALLOWED_PATH"], # Informational: filesystem MCP likely needs this
113
- }
114
-
115
- # Caches
116
- _openai_client_cache: Dict[str, AsyncOpenAI] = {}
117
- _model_instance_cache: Dict[str, Model] = {}
118
- _db_initialized = False # Flag to ensure DB init runs only once per instance
119
-
120
- def __init__(self, blueprint_id: str = "mission_improbable", config=None, config_path=None, **kwargs):
121
- super().__init__(blueprint_id, config=config, config_path=config_path, **kwargs)
122
- self.blueprint_id = blueprint_id
123
- self.config_path = config_path
124
- self._config = config if config is not None else None
125
- self._llm_profile_name = None
126
- self._llm_profile_data = None
127
- self._markdown_output = None
128
- # Add other attributes as needed for MissionImprobable
129
- # ...
130
-
131
- # --- Database Interaction ---
132
- def _init_db_and_load_data(self) -> None:
133
- """Initializes the SQLite DB, creates table, and loads sample data if needed."""
134
- """Initializes the SQLite DB file and loads sample instruction for JimFlimsy."""
135
- if self._db_initialized:
136
- return
137
- # Create parent directory if needed
138
- try:
139
- DB_PATH.parent.mkdir(parents=True, exist_ok=True)
140
- # Create or open the database file
141
- with open(DB_PATH, 'a'):
142
- pass
143
- # Initialize DB and table
144
- conn = sqlite3.connect(str(DB_PATH))
145
- cursor = conn.cursor()
146
- cursor.execute(f"CREATE TABLE IF NOT EXISTS {TABLE_NAME} (agent_name TEXT PRIMARY KEY, instruction_text TEXT NOT NULL, model_profile TEXT DEFAULT 'default')")
147
- # Load sample data for JimFlimsy if not present
148
- cursor.execute("SELECT COUNT(*) FROM " + TABLE_NAME + " WHERE agent_name = ?", ("JimFlimsy",))
149
- count = cursor.fetchone()[0]
150
- if count == 0:
151
- cursor.execute(
152
- "INSERT OR IGNORE INTO " + TABLE_NAME + " (agent_name, instruction_text, model_profile) VALUES (?, ?, ?)",
153
- ("JimFlimsy", "You’re JimFlimsy, the fearless leader.", "default")
154
- )
155
- conn.commit()
156
- conn.close()
157
- self._db_initialized = True
158
- except Exception as e:
159
- logger.error(f"Error during DB initialization/loading: {e}", exc_info=True)
160
- self._db_initialized = False
161
-
162
- def get_agent_config(self, agent_name: str) -> Dict[str, Any]:
163
- """Fetches agent config from SQLite DB or returns defaults."""
164
- if self._db_initialized:
165
- try:
166
- with sqlite3.connect(DB_PATH) as conn:
167
- conn.row_factory = sqlite3.Row
168
- cursor = conn.cursor()
169
- cursor.execute(f"SELECT instruction_text, model_profile FROM {TABLE_NAME} WHERE agent_name = ?", (agent_name,))
170
- row = cursor.fetchone()
171
- if row:
172
- logger.debug(f"Loaded config for agent '{agent_name}' from SQLite.")
173
- return {"instructions": row["instruction_text"], "model_profile": row["model_profile"] or "default"}
174
- else:
175
- logger.warning(f"No config found for agent '{agent_name}' in SQLite. Using defaults.")
176
- except sqlite3.Error as e:
177
- logger.error(f"SQLite error fetching config for '{agent_name}': {e}. Using defaults.", exc_info=True)
178
- except Exception as e:
179
- logger.error(f"Unexpected error fetching config for '{agent_name}': {e}. Using defaults.", exc_info=True)
180
-
181
- # --- Fallback Hardcoded Defaults ---
182
- logger.warning(f"Using hardcoded default config for agent '{agent_name}'.")
183
- default_instructions = {
184
- "JimFlimsy": "You are JimFlimsy, the leader. Delegate tasks. [Default - DB Failed]",
185
- "CinnamonToast": "You are CinnamonToast, strategist. Use filesystem. [Default - DB Failed]",
186
- "RollinFumble": "You are RollinFumble, operative. Use shell. [Default - DB Failed]",
187
- }
188
- return {
189
- "instructions": default_instructions.get(agent_name, f"Default instructions for {agent_name}."),
190
- "model_profile": "default",
191
- }
192
-
193
- # --- Model Instantiation Helper --- (Standard helper)
194
- def _get_model_instance(self, profile_name: str) -> Model:
195
- """Retrieves or creates an LLM Model instance."""
196
- # ... (Implementation is the same as previous refactors) ...
197
- if profile_name in self._model_instance_cache:
198
- logger.debug(f"Using cached Model instance for profile '{profile_name}'.")
199
- return self._model_instance_cache[profile_name]
200
- logger.debug(f"Creating new Model instance for profile '{profile_name}'.")
201
- profile_data = self.get_llm_profile(profile_name)
202
- if not profile_data:
203
- logger.critical(f"LLM profile '{profile_name}' (or 'default') not found.")
204
- raise ValueError(f"Missing LLM profile configuration for '{profile_name}' or 'default'.")
205
- provider = profile_data.get("provider", "openai").lower()
206
- model_name = profile_data.get("model")
207
- if not model_name:
208
- logger.critical(f"LLM profile '{profile_name}' missing 'model' key.")
209
- raise ValueError(f"Missing 'model' key in LLM profile '{profile_name}'.")
210
- if provider != "openai":
211
- logger.error(f"Unsupported LLM provider '{provider}'.")
212
- raise ValueError(f"Unsupported LLM provider: {provider}")
213
- client_cache_key = f"{provider}_{profile_data.get('base_url')}"
214
- if client_cache_key not in self._openai_client_cache:
215
- client_kwargs = { "api_key": profile_data.get("api_key"), "base_url": profile_data.get("base_url") }
216
- filtered_kwargs = {k: v for k, v in client_kwargs.items() if v is not None}
217
- log_kwargs = {k:v for k,v in filtered_kwargs.items() if k != 'api_key'}
218
- logger.debug(f"Creating new AsyncOpenAI client for '{profile_name}': {log_kwargs}")
219
- try: self._openai_client_cache[client_cache_key] = AsyncOpenAI(**filtered_kwargs)
220
- except Exception as e: raise ValueError(f"Failed to init OpenAI client: {e}") from e
221
- client = self._openai_client_cache[client_cache_key]
222
- logger.debug(f"Instantiating OpenAIChatCompletionsModel(model='{model_name}') for '{profile_name}'.")
223
- try:
224
- model_instance = OpenAIChatCompletionsModel(model=model_name, openai_client=client)
225
- self._model_instance_cache[profile_name] = model_instance
226
- return model_instance
227
- except Exception as e: raise ValueError(f"Failed to init LLM provider: {e}") from e
228
-
229
- # --- Agent Creation ---
230
- def create_starting_agent(self, mcp_servers: List[MCPServer]) -> Agent:
231
- """Creates the Mission Improbable agent team and returns JimFlimsy (Coordinator)."""
232
- # Initialize DB and load data if needed
233
- self._init_db_and_load_data()
234
-
235
- logger.debug("Creating Mission Improbable agent team...")
236
- self._model_instance_cache = {}
237
- self._openai_client_cache = {}
238
-
239
- # Helper to filter MCP servers
240
- def get_agent_mcps(names: List[str]) -> List[MCPServer]:
241
- return [s for s in mcp_servers if s.name in names]
242
-
243
- # Create agents, fetching config and assigning MCPs
244
- agents: Dict[str, Agent] = {}
245
- for name in ["JimFlimsy", "CinnamonToast", "RollinFumble"]:
246
- config = self.get_agent_config(name)
247
- model_instance = self._get_model_instance(config["model_profile"])
248
- agent_mcps = []
249
- if name == "JimFlimsy": agent_mcps = get_agent_mcps(["memory"])
250
- elif name == "CinnamonToast": agent_mcps = get_agent_mcps(["filesystem"])
251
- elif name == "RollinFumble": agent_mcps = get_agent_mcps(["mcp-shell"])
252
-
253
- agents[name] = Agent(
254
- name=name,
255
- instructions=config["instructions"] + "\nYou can use fileops tools (read_file, write_file, list_files, execute_shell_command) for any file or shell tasks.",
256
- model=model_instance,
257
- tools=[read_file_tool, write_file_tool, list_files_tool, execute_shell_command_tool],
258
- mcp_servers=agent_mcps
259
- )
260
-
261
- # Add agent tools to the coordinator (JimFlimsy)
262
- agents["JimFlimsy"].tools.extend([
263
- agents["CinnamonToast"].as_tool(tool_name="CinnamonToast", tool_description="Delegate file management or strategic planning tasks."),
264
- agents["RollinFumble"].as_tool(tool_name="RollinFumble", tool_description="Delegate shell command execution tasks.")
265
- ])
266
-
267
- logger.debug("Mission Improbable agents created. Starting with JimFlimsy.")
268
- return agents["JimFlimsy"] # Jim is the coordinator
269
-
270
- async def run(self, messages: list, **kwargs):
271
- """Main execution entry point for the MissionImprobable blueprint."""
272
- logger.info("MissionImprobableBlueprint run method called.")
273
- instruction = messages[-1].get("content", "") if messages else ""
274
- from agents import Runner
275
- ux = BlueprintUXImproved(style="serious")
276
- spinner_idx = 0
277
- start_time = time.time()
278
- spinner_yield_interval = 1.0 # seconds
279
- last_spinner_time = start_time
280
- yielded_spinner = False
281
- result_chunks = []
282
- try:
283
- runner_gen = Runner.run(self.create_starting_agent([]), instruction)
284
- while True:
285
- now = time.time()
286
- try:
287
- chunk = next(runner_gen)
288
- result_chunks.append(chunk)
289
- # If chunk is a final result, wrap and yield
290
- if chunk and isinstance(chunk, dict) and "messages" in chunk:
291
- content = chunk["messages"][0]["content"] if chunk["messages"] else ""
292
- summary = ux.summary("Operation", len(result_chunks), {"instruction": instruction[:40]})
293
- box = ux.ansi_emoji_box(
294
- title="MissionImprobable Result",
295
- content=content,
296
- summary=summary,
297
- params={"instruction": instruction[:40]},
298
- result_count=len(result_chunks),
299
- op_type="run",
300
- status="success"
301
- )
302
- yield {"messages": [{"role": "assistant", "content": box}]}
303
- else:
304
- yield chunk
305
- yielded_spinner = False
306
- except StopIteration:
307
- break
308
- except Exception:
309
- if now - last_spinner_time >= spinner_yield_interval:
310
- taking_long = (now - start_time > 10)
311
- spinner_msg = ux.spinner(spinner_idx, taking_long=taking_long)
312
- yield {"messages": [{"role": "assistant", "content": spinner_msg}]}
313
- spinner_idx += 1
314
- last_spinner_time = now
315
- yielded_spinner = True
316
- if not result_chunks and not yielded_spinner:
317
- yield {"messages": [{"role": "assistant", "content": ux.spinner(0)}]}
318
- except Exception as e:
319
- logger.error(f"Error during MissionImprobable run: {e}", exc_info=True)
320
- yield {"messages": [{"role": "assistant", "content": f"An error occurred: {e}"}]}
321
-
322
- # --- Spinner and ANSI/emoji operation box for unified UX (for CLI/dev runs) ---
323
- from swarm.ux.ansi_box import ansi_box
324
- from rich.console import Console
325
- from rich.style import Style
326
- from rich.text import Text
327
- import threading
328
- import time
329
-
330
- class MissionImprobableSpinner:
331
- FRAMES = [
332
- "Generating.", "Generating..", "Generating...", "Running...",
333
- "⠋ Generating...", "⠙ Generating...", "⠹ Generating...", "⠸ Generating...",
334
- "⠼ Generating...", "⠴ Generating...", "⠦ Generating...", "⠧ Generating...",
335
- "⠇ Generating...", "⠏ Generating...", "🤖 Generating...", "💡 Generating...", "✨ Generating..."
336
- ]
337
- SLOW_FRAME = "Generating... Taking longer than expected"
338
- INTERVAL = 0.12
339
- SLOW_THRESHOLD = 10 # seconds
340
-
341
- def __init__(self):
342
- self._stop_event = threading.Event()
343
- self._thread = None
344
- self._start_time = None
345
- self.console = Console()
346
- self._last_frame = None
347
- self._last_slow = False
348
-
349
- def start(self):
350
- self._stop_event.clear()
351
- self._start_time = time.time()
352
- self._thread = threading.Thread(target=self._spin, daemon=True)
353
- self._thread.start()
354
-
355
- def _spin(self):
356
- idx = 0
357
- while not self._stop_event.is_set():
358
- elapsed = time.time() - self._start_time
359
- if elapsed > self.SLOW_THRESHOLD:
360
- txt = Text(self.SLOW_FRAME, style=Style(color="yellow", bold=True))
361
- self._last_frame = self.SLOW_FRAME
362
- self._last_slow = True
363
- else:
364
- frame = self.FRAMES[idx % len(self.FRAMES)]
365
- txt = Text(frame, style=Style(color="cyan", bold=True))
366
- self._last_frame = frame
367
- self._last_slow = False
368
- self.console.print(txt, end="\r", soft_wrap=True, highlight=False)
369
- time.sleep(self.INTERVAL)
370
- idx += 1
371
- self.console.print(" " * 40, end="\r") # Clear line
372
-
373
- def stop(self, final_message="Done!"):
374
- self._stop_event.set()
375
- if self._thread:
376
- self._thread.join()
377
- self.console.print(Text(final_message, style=Style(color="green", bold=True)))
378
-
379
- def current_spinner_state(self):
380
- if self._last_slow:
381
- return self.SLOW_FRAME
382
- return self._last_frame or self.FRAMES[0]
383
-
384
-
385
- def print_operation_box(op_type, results, params=None, result_type="mission", taking_long=False):
386
- emoji = "🕵️" if result_type == "mission" else "🔍"
387
- style = 'success' if result_type == "mission" else 'default'
388
- box_title = op_type if op_type else ("MissionImprobable Output" if result_type == "mission" else "Results")
389
- summary_lines = []
390
- count = len(results) if isinstance(results, list) else 0
391
- summary_lines.append(f"Results: {count}")
392
- if params:
393
- for k, v in params.items():
394
- summary_lines.append(f"{k.capitalize()}: {v}")
395
- box_content = "\n".join(summary_lines + ["\n".join(map(str, results))])
396
- ansi_box(box_title, box_content, count=count, params=params, style=style if not taking_long else 'warning', emoji=emoji)
397
-
398
- # Standard Python entry point
399
- if __name__ == "__main__":
400
- import asyncio
401
- import json
402
- print("\033[1;36m\n╔══════════════════════════════════════════════════════════════╗\n║ 🕵️ MISSION IMPROBABLE: SWARM STRATEGY & TASK DEMO ║\n╠══════════════════════════════════════════════════════════════╣\n║ This blueprint demonstrates viral swarm propagation, ║\n║ strategic task planning, and agent collaboration. ║\n║ Try running: python blueprint_mission_improbable.py ║\n╚══════════════════════════════════════════════════════════════╝\033[0m")
403
- messages = [
404
- {"role": "user", "content": "Show me how Mission Improbable plans tasks and leverages swarm strategy."}
405
- ]
406
- blueprint = MissionImprobableBlueprint(blueprint_id="demo-1")
407
- async def run_and_print():
408
- spinner = MissionImprobableSpinner()
409
- spinner.start()
410
- try:
411
- all_results = []
412
- async for response in blueprint.run(messages):
413
- content = response["messages"][0]["content"]
414
- all_results.append(content)
415
- finally:
416
- spinner.stop()
417
- print_operation_box(
418
- op_type="MissionImprobable Output",
419
- results=all_results,
420
- params={"prompt": messages[0]["content"]},
421
- result_type="mission"
422
- )
423
- asyncio.run(run_and_print())