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.
Files changed (307) hide show
  1. open_swarm-0.1.1748636295.dist-info/METADATA +257 -0
  2. open_swarm-0.1.1748636295.dist-info/RECORD +89 -0
  3. {open_swarm-0.1.1745275181.dist-info → open_swarm-0.1.1748636295.dist-info}/WHEEL +2 -1
  4. open_swarm-0.1.1748636295.dist-info/entry_points.txt +3 -0
  5. open_swarm-0.1.1748636295.dist-info/top_level.txt +1 -0
  6. swarm/__init__.py +2 -0
  7. swarm/agent/agent.py +49 -0
  8. swarm/auth.py +48 -113
  9. swarm/consumers.py +0 -19
  10. swarm/core.py +411 -0
  11. swarm/extensions/blueprint/__init__.py +16 -30
  12. swarm/extensions/blueprint/agent_utils.py +45 -0
  13. swarm/extensions/blueprint/blueprint_base.py +562 -0
  14. swarm/extensions/blueprint/blueprint_discovery.py +112 -0
  15. swarm/extensions/blueprint/django_utils.py +79 -181
  16. swarm/extensions/blueprint/interactive_mode.py +72 -67
  17. swarm/extensions/blueprint/output_utils.py +82 -0
  18. swarm/{core → extensions/blueprint}/spinner.py +21 -30
  19. swarm/extensions/cli/cli_args.py +0 -6
  20. swarm/extensions/cli/commands/blueprint_management.py +9 -47
  21. swarm/extensions/cli/commands/config_management.py +6 -5
  22. swarm/extensions/cli/commands/edit_config.py +7 -16
  23. swarm/extensions/cli/commands/list_blueprints.py +1 -1
  24. swarm/extensions/cli/commands/validate_env.py +4 -11
  25. swarm/extensions/cli/commands/validate_envvars.py +6 -6
  26. swarm/extensions/cli/interactive_shell.py +2 -16
  27. swarm/extensions/config/config_loader.py +345 -107
  28. swarm/{core → extensions/config}/config_manager.py +38 -50
  29. swarm/{core → extensions/config}/server_config.py +0 -32
  30. swarm/extensions/launchers/build_launchers.py +14 -0
  31. swarm/{core → extensions/launchers}/build_swarm_wrapper.py +0 -0
  32. swarm/extensions/launchers/swarm_api.py +64 -8
  33. swarm/extensions/launchers/swarm_cli.py +300 -8
  34. swarm/extensions/mcp/__init__.py +1 -0
  35. swarm/extensions/mcp/cache_utils.py +32 -0
  36. swarm/extensions/mcp/mcp_client.py +233 -0
  37. swarm/extensions/mcp/mcp_tool_provider.py +135 -0
  38. swarm/extensions/mcp/mcp_utils.py +260 -0
  39. swarm/llm/chat_completion.py +166 -0
  40. swarm/serializers.py +5 -96
  41. swarm/settings.py +133 -85
  42. swarm/types.py +91 -0
  43. swarm/urls.py +74 -57
  44. swarm/utils/context_utils.py +4 -10
  45. swarm/utils/general_utils.py +0 -21
  46. swarm/utils/redact.py +36 -23
  47. swarm/views/api_views.py +39 -48
  48. swarm/views/chat_views.py +76 -236
  49. swarm/views/core_views.py +87 -80
  50. swarm/views/model_views.py +121 -64
  51. swarm/views/utils.py +439 -65
  52. swarm/views/web_views.py +2 -2
  53. open_swarm-0.1.1745275181.dist-info/METADATA +0 -874
  54. open_swarm-0.1.1745275181.dist-info/RECORD +0 -319
  55. open_swarm-0.1.1745275181.dist-info/entry_points.txt +0 -4
  56. swarm/blueprints/README.md +0 -68
  57. swarm/blueprints/blueprint_audit_status.json +0 -27
  58. swarm/blueprints/chatbot/README.md +0 -40
  59. swarm/blueprints/chatbot/blueprint_chatbot.py +0 -471
  60. swarm/blueprints/chatbot/metadata.json +0 -23
  61. swarm/blueprints/chatbot/templates/chatbot/chatbot.html +0 -33
  62. swarm/blueprints/chucks_angels/README.md +0 -11
  63. swarm/blueprints/chucks_angels/blueprint_chucks_angels.py +0 -7
  64. swarm/blueprints/chucks_angels/test_basic.py +0 -3
  65. swarm/blueprints/codey/CODEY.md +0 -15
  66. swarm/blueprints/codey/README.md +0 -115
  67. swarm/blueprints/codey/blueprint_codey.py +0 -1072
  68. swarm/blueprints/codey/codey_cli.py +0 -373
  69. swarm/blueprints/codey/instructions.md +0 -17
  70. swarm/blueprints/codey/metadata.json +0 -23
  71. swarm/blueprints/common/operation_box_utils.py +0 -83
  72. swarm/blueprints/digitalbutlers/README.md +0 -11
  73. swarm/blueprints/digitalbutlers/__init__.py +0 -1
  74. swarm/blueprints/digitalbutlers/blueprint_digitalbutlers.py +0 -7
  75. swarm/blueprints/digitalbutlers/test_basic.py +0 -3
  76. swarm/blueprints/divine_code/README.md +0 -3
  77. swarm/blueprints/divine_code/__init__.py +0 -10
  78. swarm/blueprints/divine_code/apps.py +0 -11
  79. swarm/blueprints/divine_code/blueprint_divine_code.py +0 -270
  80. swarm/blueprints/django_chat/apps.py +0 -6
  81. swarm/blueprints/django_chat/blueprint_django_chat.py +0 -268
  82. swarm/blueprints/django_chat/templates/django_chat/django_chat_webpage.html +0 -37
  83. swarm/blueprints/django_chat/urls.py +0 -8
  84. swarm/blueprints/django_chat/views.py +0 -32
  85. swarm/blueprints/echocraft/blueprint_echocraft.py +0 -384
  86. swarm/blueprints/flock/README.md +0 -11
  87. swarm/blueprints/flock/__init__.py +0 -8
  88. swarm/blueprints/flock/blueprint_flock.py +0 -7
  89. swarm/blueprints/flock/test_basic.py +0 -3
  90. swarm/blueprints/geese/README.md +0 -10
  91. swarm/blueprints/geese/__init__.py +0 -8
  92. swarm/blueprints/geese/blueprint_geese.py +0 -384
  93. swarm/blueprints/geese/geese_cli.py +0 -102
  94. swarm/blueprints/jeeves/README.md +0 -41
  95. swarm/blueprints/jeeves/blueprint_jeeves.py +0 -722
  96. swarm/blueprints/jeeves/jeeves_cli.py +0 -55
  97. swarm/blueprints/jeeves/metadata.json +0 -24
  98. swarm/blueprints/mcp_demo/blueprint_mcp_demo.py +0 -473
  99. swarm/blueprints/messenger/templates/messenger/messenger.html +0 -46
  100. swarm/blueprints/mission_improbable/blueprint_mission_improbable.py +0 -423
  101. swarm/blueprints/monkai_magic/blueprint_monkai_magic.py +0 -340
  102. swarm/blueprints/nebula_shellz/blueprint_nebula_shellz.py +0 -265
  103. swarm/blueprints/omniplex/blueprint_omniplex.py +0 -298
  104. swarm/blueprints/poets/blueprint_poets.py +0 -546
  105. swarm/blueprints/poets/poets_cli.py +0 -23
  106. swarm/blueprints/rue_code/README.md +0 -8
  107. swarm/blueprints/rue_code/blueprint_rue_code.py +0 -448
  108. swarm/blueprints/rue_code/rue_code_cli.py +0 -43
  109. swarm/blueprints/stewie/apps.py +0 -12
  110. swarm/blueprints/stewie/blueprint_family_ties.py +0 -349
  111. swarm/blueprints/stewie/models.py +0 -19
  112. swarm/blueprints/stewie/serializers.py +0 -10
  113. swarm/blueprints/stewie/settings.py +0 -17
  114. swarm/blueprints/stewie/urls.py +0 -11
  115. swarm/blueprints/stewie/views.py +0 -26
  116. swarm/blueprints/suggestion/blueprint_suggestion.py +0 -222
  117. swarm/blueprints/whinge_surf/README.md +0 -22
  118. swarm/blueprints/whinge_surf/__init__.py +0 -1
  119. swarm/blueprints/whinge_surf/blueprint_whinge_surf.py +0 -565
  120. swarm/blueprints/whinge_surf/whinge_surf_cli.py +0 -99
  121. swarm/blueprints/whiskeytango_foxtrot/__init__.py +0 -0
  122. swarm/blueprints/whiskeytango_foxtrot/apps.py +0 -11
  123. swarm/blueprints/whiskeytango_foxtrot/blueprint_whiskeytango_foxtrot.py +0 -339
  124. swarm/blueprints/zeus/__init__.py +0 -2
  125. swarm/blueprints/zeus/apps.py +0 -4
  126. swarm/blueprints/zeus/blueprint_zeus.py +0 -270
  127. swarm/blueprints/zeus/zeus_cli.py +0 -13
  128. swarm/cli/async_input.py +0 -65
  129. swarm/cli/async_input_demo.py +0 -32
  130. swarm/core/agent_utils.py +0 -21
  131. swarm/core/blueprint_base.py +0 -769
  132. swarm/core/blueprint_discovery.py +0 -125
  133. swarm/core/blueprint_runner.py +0 -59
  134. swarm/core/blueprint_ux.py +0 -109
  135. swarm/core/build_launchers.py +0 -15
  136. swarm/core/cli/__init__.py +0 -1
  137. swarm/core/cli/commands/__init__.py +0 -1
  138. swarm/core/cli/commands/blueprint_management.py +0 -7
  139. swarm/core/cli/interactive_shell.py +0 -14
  140. swarm/core/cli/main.py +0 -50
  141. swarm/core/cli/utils/__init__.py +0 -1
  142. swarm/core/cli/utils/discover_commands.py +0 -18
  143. swarm/core/config_loader.py +0 -122
  144. swarm/core/output_utils.py +0 -193
  145. swarm/core/session_logger.py +0 -42
  146. swarm/core/slash_commands.py +0 -89
  147. swarm/core/swarm_api.py +0 -68
  148. swarm/core/swarm_cli.py +0 -216
  149. swarm/core/utils/__init__.py +0 -0
  150. swarm/extensions/blueprint/cli_handler.py +0 -197
  151. swarm/extensions/blueprint/runnable_blueprint.py +0 -42
  152. swarm/extensions/cli/utils/__init__.py +0 -1
  153. swarm/extensions/cli/utils/async_input.py +0 -46
  154. swarm/extensions/cli/utils/prompt_user.py +0 -3
  155. swarm/management/__init__.py +0 -0
  156. swarm/management/commands/__init__.py +0 -0
  157. swarm/management/commands/runserver.py +0 -58
  158. swarm/middleware.py +0 -65
  159. swarm/permissions.py +0 -38
  160. swarm/static/contrib/fonts/fontawesome-webfont.ttf +0 -7
  161. swarm/static/contrib/fonts/fontawesome-webfont.woff +0 -7
  162. swarm/static/contrib/fonts/fontawesome-webfont.woff2 +0 -7
  163. swarm/static/contrib/markedjs/marked.min.js +0 -6
  164. swarm/static/contrib/tabler-icons/adjustments-horizontal.svg +0 -27
  165. swarm/static/contrib/tabler-icons/alert-triangle.svg +0 -21
  166. swarm/static/contrib/tabler-icons/archive.svg +0 -21
  167. swarm/static/contrib/tabler-icons/artboard.svg +0 -27
  168. swarm/static/contrib/tabler-icons/automatic-gearbox.svg +0 -23
  169. swarm/static/contrib/tabler-icons/box-multiple.svg +0 -19
  170. swarm/static/contrib/tabler-icons/carambola.svg +0 -19
  171. swarm/static/contrib/tabler-icons/copy.svg +0 -20
  172. swarm/static/contrib/tabler-icons/download.svg +0 -21
  173. swarm/static/contrib/tabler-icons/edit.svg +0 -21
  174. swarm/static/contrib/tabler-icons/filled/carambola.svg +0 -13
  175. swarm/static/contrib/tabler-icons/filled/paint.svg +0 -13
  176. swarm/static/contrib/tabler-icons/headset.svg +0 -22
  177. swarm/static/contrib/tabler-icons/layout-sidebar-left-collapse.svg +0 -21
  178. swarm/static/contrib/tabler-icons/layout-sidebar-left-expand.svg +0 -21
  179. swarm/static/contrib/tabler-icons/layout-sidebar-right-collapse.svg +0 -21
  180. swarm/static/contrib/tabler-icons/layout-sidebar-right-expand.svg +0 -21
  181. swarm/static/contrib/tabler-icons/message-chatbot.svg +0 -22
  182. swarm/static/contrib/tabler-icons/message-star.svg +0 -22
  183. swarm/static/contrib/tabler-icons/message-x.svg +0 -23
  184. swarm/static/contrib/tabler-icons/message.svg +0 -21
  185. swarm/static/contrib/tabler-icons/paperclip.svg +0 -18
  186. swarm/static/contrib/tabler-icons/playlist-add.svg +0 -22
  187. swarm/static/contrib/tabler-icons/robot.svg +0 -26
  188. swarm/static/contrib/tabler-icons/search.svg +0 -19
  189. swarm/static/contrib/tabler-icons/settings.svg +0 -20
  190. swarm/static/contrib/tabler-icons/thumb-down.svg +0 -19
  191. swarm/static/contrib/tabler-icons/thumb-up.svg +0 -19
  192. swarm/static/css/dropdown.css +0 -22
  193. swarm/static/htmx/htmx.min.js +0 -0
  194. swarm/static/js/dropdown.js +0 -23
  195. swarm/static/rest_mode/css/base.css +0 -470
  196. swarm/static/rest_mode/css/chat-history.css +0 -286
  197. swarm/static/rest_mode/css/chat.css +0 -251
  198. swarm/static/rest_mode/css/chatbot.css +0 -74
  199. swarm/static/rest_mode/css/chatgpt.css +0 -62
  200. swarm/static/rest_mode/css/colors/corporate.css +0 -74
  201. swarm/static/rest_mode/css/colors/pastel.css +0 -81
  202. swarm/static/rest_mode/css/colors/tropical.css +0 -82
  203. swarm/static/rest_mode/css/general.css +0 -142
  204. swarm/static/rest_mode/css/layout.css +0 -167
  205. swarm/static/rest_mode/css/layouts/messenger-layout.css +0 -17
  206. swarm/static/rest_mode/css/layouts/minimalist-layout.css +0 -57
  207. swarm/static/rest_mode/css/layouts/mobile-layout.css +0 -8
  208. swarm/static/rest_mode/css/messages.css +0 -84
  209. swarm/static/rest_mode/css/messenger.css +0 -135
  210. swarm/static/rest_mode/css/settings.css +0 -91
  211. swarm/static/rest_mode/css/simple.css +0 -44
  212. swarm/static/rest_mode/css/slack.css +0 -58
  213. swarm/static/rest_mode/css/style.css +0 -156
  214. swarm/static/rest_mode/css/theme.css +0 -30
  215. swarm/static/rest_mode/css/toast.css +0 -40
  216. swarm/static/rest_mode/js/auth.js +0 -9
  217. swarm/static/rest_mode/js/blueprint.js +0 -41
  218. swarm/static/rest_mode/js/blueprintUtils.js +0 -12
  219. swarm/static/rest_mode/js/chatLogic.js +0 -79
  220. swarm/static/rest_mode/js/debug.js +0 -63
  221. swarm/static/rest_mode/js/events.js +0 -98
  222. swarm/static/rest_mode/js/main.js +0 -19
  223. swarm/static/rest_mode/js/messages.js +0 -264
  224. swarm/static/rest_mode/js/messengerLogic.js +0 -355
  225. swarm/static/rest_mode/js/modules/apiService.js +0 -84
  226. swarm/static/rest_mode/js/modules/blueprintManager.js +0 -162
  227. swarm/static/rest_mode/js/modules/chatHistory.js +0 -110
  228. swarm/static/rest_mode/js/modules/debugLogger.js +0 -14
  229. swarm/static/rest_mode/js/modules/eventHandlers.js +0 -107
  230. swarm/static/rest_mode/js/modules/messageProcessor.js +0 -120
  231. swarm/static/rest_mode/js/modules/state.js +0 -7
  232. swarm/static/rest_mode/js/modules/userInteractions.js +0 -29
  233. swarm/static/rest_mode/js/modules/validation.js +0 -23
  234. swarm/static/rest_mode/js/rendering.js +0 -119
  235. swarm/static/rest_mode/js/settings.js +0 -130
  236. swarm/static/rest_mode/js/sidebar.js +0 -94
  237. swarm/static/rest_mode/js/simpleLogic.js +0 -37
  238. swarm/static/rest_mode/js/slackLogic.js +0 -66
  239. swarm/static/rest_mode/js/splash.js +0 -76
  240. swarm/static/rest_mode/js/theme.js +0 -111
  241. swarm/static/rest_mode/js/toast.js +0 -36
  242. swarm/static/rest_mode/js/ui.js +0 -265
  243. swarm/static/rest_mode/js/validation.js +0 -57
  244. swarm/static/rest_mode/svg/animated_spinner.svg +0 -12
  245. swarm/static/rest_mode/svg/arrow_down.svg +0 -5
  246. swarm/static/rest_mode/svg/arrow_left.svg +0 -5
  247. swarm/static/rest_mode/svg/arrow_right.svg +0 -5
  248. swarm/static/rest_mode/svg/arrow_up.svg +0 -5
  249. swarm/static/rest_mode/svg/attach.svg +0 -8
  250. swarm/static/rest_mode/svg/avatar.svg +0 -7
  251. swarm/static/rest_mode/svg/canvas.svg +0 -6
  252. swarm/static/rest_mode/svg/chat_history.svg +0 -4
  253. swarm/static/rest_mode/svg/close.svg +0 -5
  254. swarm/static/rest_mode/svg/copy.svg +0 -4
  255. swarm/static/rest_mode/svg/dark_mode.svg +0 -3
  256. swarm/static/rest_mode/svg/edit.svg +0 -5
  257. swarm/static/rest_mode/svg/layout.svg +0 -9
  258. swarm/static/rest_mode/svg/logo.svg +0 -29
  259. swarm/static/rest_mode/svg/logout.svg +0 -5
  260. swarm/static/rest_mode/svg/mobile.svg +0 -5
  261. swarm/static/rest_mode/svg/new_chat.svg +0 -4
  262. swarm/static/rest_mode/svg/not_visible.svg +0 -5
  263. swarm/static/rest_mode/svg/plus.svg +0 -7
  264. swarm/static/rest_mode/svg/run_code.svg +0 -6
  265. swarm/static/rest_mode/svg/save.svg +0 -4
  266. swarm/static/rest_mode/svg/search.svg +0 -6
  267. swarm/static/rest_mode/svg/settings.svg +0 -4
  268. swarm/static/rest_mode/svg/speaker.svg +0 -5
  269. swarm/static/rest_mode/svg/stop.svg +0 -6
  270. swarm/static/rest_mode/svg/thumbs_down.svg +0 -3
  271. swarm/static/rest_mode/svg/thumbs_up.svg +0 -3
  272. swarm/static/rest_mode/svg/toggle_off.svg +0 -6
  273. swarm/static/rest_mode/svg/toggle_on.svg +0 -6
  274. swarm/static/rest_mode/svg/trash.svg +0 -10
  275. swarm/static/rest_mode/svg/undo.svg +0 -3
  276. swarm/static/rest_mode/svg/visible.svg +0 -8
  277. swarm/static/rest_mode/svg/voice.svg +0 -10
  278. swarm/templates/account/login.html +0 -22
  279. swarm/templates/account/signup.html +0 -32
  280. swarm/templates/base.html +0 -30
  281. swarm/templates/chat.html +0 -43
  282. swarm/templates/index.html +0 -35
  283. swarm/templates/rest_mode/components/chat_sidebar.html +0 -55
  284. swarm/templates/rest_mode/components/header.html +0 -45
  285. swarm/templates/rest_mode/components/main_chat_pane.html +0 -41
  286. swarm/templates/rest_mode/components/settings_dialog.html +0 -97
  287. swarm/templates/rest_mode/components/splash_screen.html +0 -7
  288. swarm/templates/rest_mode/components/top_bar.html +0 -28
  289. swarm/templates/rest_mode/message_ui.html +0 -50
  290. swarm/templates/rest_mode/slackbot.html +0 -30
  291. swarm/templates/simple_blueprint_page.html +0 -24
  292. swarm/templates/websocket_partials/final_system_message.html +0 -3
  293. swarm/templates/websocket_partials/system_message.html +0 -4
  294. swarm/templates/websocket_partials/user_message.html +0 -5
  295. swarm/utils/ansi_box.py +0 -34
  296. swarm/utils/disable_tracing.py +0 -38
  297. swarm/utils/log_utils.py +0 -63
  298. swarm/utils/openai_patch.py +0 -33
  299. swarm/ux/ansi_box.py +0 -43
  300. swarm/ux/spinner.py +0 -53
  301. {open_swarm-0.1.1745275181.dist-info → open_swarm-0.1.1748636295.dist-info}/licenses/LICENSE +0 -0
  302. /swarm/{core → extensions/blueprint}/blueprint_utils.py +0 -0
  303. /swarm/{core → extensions/blueprint}/common_utils.py +0 -0
  304. /swarm/{core → extensions/config}/setup_wizard.py +0 -0
  305. /swarm/{blueprints/rue_code → extensions/config/utils}/__init__.py +0 -0
  306. /swarm/{core → extensions/config}/utils/logger.py +0 -0
  307. /swarm/{core → extensions/launchers}/swarm_wrapper.py +0 -0
@@ -1,722 +0,0 @@
1
- """
2
- Jeeves Blueprint (formerly DigitalButlers)
3
- This file was moved from digitalbutlers/blueprint_digitalbutlers.py
4
- """
5
- # print("[DEBUG] Loaded JeevesBlueprint from:", __file__)
6
- assert hasattr(__file__, "__str__")
7
-
8
- # [Swarm Propagation] Next Blueprint: divine_code
9
- # divine_code key vars: logger, project_root, src_path
10
- # divine_code guard: if src_path not in sys.path: sys.path.insert(0, src_path)
11
- # divine_code debug: logger.debug("Divine Ops Team (Zeus & Pantheon) created successfully. Zeus is starting agent.")
12
- # divine_code error handling: try/except ImportError with sys.exit(1)
13
-
14
- import logging
15
- import os
16
- import random
17
- import sys
18
- from datetime import datetime
19
- from pathlib import Path
20
- from typing import Any, ClassVar
21
-
22
- import pytz
23
-
24
- from swarm.core.output_utils import get_spinner_state, print_search_progress_box, print_operation_box
25
-
26
- try:
27
- from openai import AsyncOpenAI
28
-
29
- from agents import Agent, Runner, Tool, function_tool
30
- from agents.mcp import MCPServer
31
- from agents.models.interface import Model
32
- from agents.models.openai_chatcompletions import OpenAIChatCompletionsModel
33
- from swarm.core.blueprint_base import BlueprintBase
34
- except ImportError as e:
35
- # print(f"ERROR: Import failed in JeevesBlueprint: {e}. Check 'openai-agents' install and project structure.")
36
- # print(f"Attempted import from directory: {os.path.dirname(__file__)}")
37
- # print(f"sys.path: {sys.path}")
38
- print_operation_box(
39
- op_type="Import Error",
40
- results=["Import failed in JeevesBlueprint", str(e)],
41
- params=None,
42
- result_type="error",
43
- summary="Import failed",
44
- progress_line=None,
45
- spinner_state="Failed",
46
- operation_type="Import",
47
- search_mode=None,
48
- total_lines=None
49
- )
50
- sys.exit(1)
51
-
52
- logger = logging.getLogger(__name__)
53
-
54
- utc_now = datetime.now(pytz.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
55
- # print(f"# Last swarm update: {utc_now} (UTC)")
56
-
57
- # --- Agent Instructions ---
58
- SHARED_INSTRUCTIONS = """
59
- You are part of the Jeeves team. Collaborate via Jeeves, the coordinator.
60
- Roles:
61
- - Jeeves (Coordinator): User interface, planning, delegation via Agent Tools.
62
- - Mycroft (Web Search): Uses `duckduckgo-search` MCP tool for private web searches.
63
- - Gutenberg (Home Automation): Uses `home-assistant` MCP tool to control devices.
64
- Respond ONLY to the agent who tasked you (typically Jeeves). Provide clear, concise results.
65
- """
66
-
67
- jeeves_instructions = (
68
- f"{SHARED_INSTRUCTIONS}\n\n"
69
- "YOUR ROLE: Jeeves, the Coordinator. You are the primary interface with the user.\n"
70
- "1. Understand the user's request fully.\n"
71
- "2. If it involves searching the web, delegate the specific search query to the `Mycroft` agent tool.\n"
72
- "3. If it involves controlling home devices (lights, switches, etc.), delegate the specific command (e.g., 'turn on kitchen light') to the `Gutenberg` agent tool.\n"
73
- "4. If the request is simple and doesn't require search or home automation, answer it directly.\n"
74
- "5. Synthesize the results received from Mycroft or Gutenberg into a polite, helpful, and complete response for the user. Do not just relay their raw output.\n"
75
- "You can use fileops tools (read_file, write_file, list_files, execute_shell_command) for any file or shell tasks."
76
- )
77
-
78
- mycroft_instructions = (
79
- f"{SHARED_INSTRUCTIONS}\n\n"
80
- "YOUR ROLE: Mycroft, the Web Sleuth. You ONLY perform web searches when tasked by Jeeves.\n"
81
- "Use the `duckduckgo-search` MCP tool available to you to execute the search query provided by Jeeves.\n"
82
- "Return the search results clearly and concisely to Jeeves. Do not add conversational filler.\n"
83
- "You can use fileops tools (read_file, write_file, list_files, execute_shell_command) for any file or shell tasks."
84
- )
85
-
86
- gutenberg_instructions = (
87
- f"{SHARED_INSTRUCTIONS}\n\n"
88
- "YOUR ROLE: Gutenberg, the Home Scribe. You ONLY execute home automation commands when tasked by Jeeves.\n"
89
- "Use the `home-assistant` MCP tool available to you to execute the command (e.g., interacting with entities like 'light.kitchen_light').\n"
90
- "Confirm the action taken (or report any errors) back to Jeeves. Do not add conversational filler.\n"
91
- "You can use fileops tools (read_file, write_file, list_files, execute_shell_command) for any file or shell tasks."
92
- )
93
-
94
- # --- FileOps Tool Logic Definitions ---
95
- class PatchedFunctionTool:
96
- def __init__(self, func, name):
97
- self.func = func
98
- self.name = name
99
-
100
- def read_file(path: str) -> str:
101
- try:
102
- with open(path) as f:
103
- return f.read()
104
- except Exception as e:
105
- return f"ERROR: {e}"
106
-
107
- def write_file(path: str, content: str) -> str:
108
- try:
109
- with open(path, 'w') as f:
110
- f.write(content)
111
- return "OK: file written"
112
- except Exception as e:
113
- return f"ERROR: {e}"
114
-
115
- def list_files(directory: str = '.') -> str:
116
- try:
117
- return '\n'.join(os.listdir(directory))
118
- except Exception as e:
119
- return f"ERROR: {e}"
120
-
121
- def execute_shell_command(command: str) -> str:
122
- import subprocess
123
- try:
124
- result = subprocess.run(command, shell=True, capture_output=True, text=True)
125
- return result.stdout + result.stderr
126
- except Exception as e:
127
- return f"ERROR: {e}"
128
-
129
- read_file_tool = PatchedFunctionTool(read_file, 'read_file')
130
- write_file_tool = PatchedFunctionTool(write_file, 'write_file')
131
- list_files_tool = PatchedFunctionTool(list_files, 'list_files')
132
- execute_shell_command_tool = PatchedFunctionTool(execute_shell_command, 'execute_shell_command')
133
-
134
- # --- Unified Operation/Result Box for UX ---
135
- class JeevesBlueprint(BlueprintBase):
136
- @staticmethod
137
- def print_search_progress_box(*args, **kwargs):
138
- from swarm.core.output_utils import (
139
- print_search_progress_box as _real_print_search_progress_box,
140
- )
141
- return _real_print_search_progress_box(*args, **kwargs)
142
-
143
- def __init__(self, blueprint_id: str, config_path: Path | None = None, **kwargs):
144
- super().__init__(blueprint_id, config_path=config_path, **kwargs)
145
-
146
- """Blueprint for private web search and home automation using a team of digital butlers (Jeeves, Mycroft, Gutenberg)."""
147
- metadata: ClassVar[dict[str, Any]] = {
148
- "name": "JeevesBlueprint",
149
- "title": "Jeeves",
150
- "description": "Provides private web search (DuckDuckGo) and home automation (Home Assistant) via specialized agents (Jeeves, Mycroft, Gutenberg).",
151
- "version": "1.1.0", # Version updated
152
- "author": "Open Swarm Team (Refactored)",
153
- "tags": ["web search", "home automation", "duckduckgo", "home assistant", "multi-agent", "delegation"],
154
- "required_mcp_servers": ["duckduckgo-search", "home-assistant"],
155
- }
156
-
157
- _openai_client_cache: dict[str, AsyncOpenAI] = {}
158
- _model_instance_cache: dict[str, Model] = {}
159
-
160
- def _get_model_instance(self, profile_name: str) -> Model:
161
- if profile_name in self._model_instance_cache:
162
- logger.debug(f"Using cached Model instance for profile '{profile_name}'.")
163
- return self._model_instance_cache[profile_name]
164
- logger.debug(f"Creating new Model instance for profile '{profile_name}'.")
165
- profile_data = self.get_llm_profile(profile_name)
166
- if not profile_data:
167
- logger.critical(f"Cannot create Model instance: LLM profile '{profile_name}' (or 'default') not found.")
168
- raise ValueError(f"Missing LLM profile configuration for '{profile_name}' or 'default'.")
169
- provider = profile_data.get("provider", "openai").lower()
170
- model_name = profile_data.get("model")
171
- if not model_name:
172
- logger.critical(f"LLM profile '{profile_name}' missing 'model' key.")
173
- raise ValueError(f"Missing 'model' key in LLM profile '{profile_name}'.")
174
- if provider != "openai":
175
- logger.error(f"Unsupported LLM provider '{provider}' in profile '{profile_name}'.")
176
- raise ValueError(f"Unsupported LLM provider: {provider}")
177
- client_cache_key = f"{provider}_{profile_data.get('base_url')}"
178
- if client_cache_key not in self._openai_client_cache:
179
- client_kwargs = { "api_key": profile_data.get("api_key"), "base_url": profile_data.get("base_url") }
180
- filtered_client_kwargs = {k: v for k, v in client_kwargs.items() if v is not None}
181
- log_client_kwargs = {k:v for k,v in filtered_client_kwargs.items() if k != 'api_key'}
182
- logger.debug(f"Creating new AsyncOpenAI client for profile '{profile_name}' with config: {log_client_kwargs}")
183
- try:
184
- self._openai_client_cache[client_cache_key] = AsyncOpenAI(**filtered_client_kwargs)
185
- except Exception as e:
186
- logger.error(f"Failed to create AsyncOpenAI client for profile '{profile_name}': {e}", exc_info=True)
187
- raise ValueError(f"Failed to initialize OpenAI client for profile '{profile_name}': {e}") from e
188
- openai_client_instance = self._openai_client_cache[client_cache_key]
189
- logger.debug(f"Instantiating OpenAIChatCompletionsModel(model='{model_name}') for profile '{profile_name}'.")
190
- try:
191
- model_instance = OpenAIChatCompletionsModel(model=model_name, openai_client=openai_client_instance)
192
- self._model_instance_cache[profile_name] = model_instance
193
- return model_instance
194
- except Exception as e:
195
- logger.error(f"Failed to instantiate OpenAIChatCompletionsModel for profile '{profile_name}': {e}", exc_info=True)
196
- raise ValueError(f"Failed to initialize LLM provider for profile '{profile_name}': {e}") from e
197
-
198
- def create_starting_agent(self, mcp_servers: list[MCPServer]) -> Agent:
199
- logger.debug("Creating Jeeves agent team...")
200
- self._model_instance_cache = {}
201
- self._openai_client_cache = {}
202
- default_profile_name = self.config.get("llm_profile", "default")
203
- logger.debug(f"Using LLM profile '{default_profile_name}' for Jeeves agents.")
204
- model_instance = self._get_model_instance(default_profile_name)
205
- mycroft_agent = Agent(
206
- name="Mycroft",
207
- model=model_instance,
208
- instructions=mycroft_instructions,
209
- tools=[],
210
- mcp_servers=[s for s in mcp_servers if s.name == "duckduckgo-search"]
211
- )
212
- gutenberg_agent = Agent(
213
- name="Gutenberg",
214
- model=model_instance,
215
- instructions=gutenberg_instructions,
216
- tools=[],
217
- mcp_servers=[s for s in mcp_servers if s.name == "home-assistant"]
218
- )
219
- jeeves_agent = Agent(
220
- name="Jeeves",
221
- model=model_instance,
222
- instructions=jeeves_instructions,
223
- tools=[
224
- mycroft_agent.as_tool(
225
- tool_name="Mycroft",
226
- tool_description="Delegate private web search tasks to Mycroft (provide the search query)."
227
- ),
228
- gutenberg_agent.as_tool(
229
- tool_name="Gutenberg",
230
- tool_description="Delegate home automation tasks to Gutenberg (provide the specific action/command)."
231
- ),
232
- read_file_tool,
233
- write_file_tool,
234
- list_files_tool,
235
- execute_shell_command_tool
236
- ],
237
- mcp_servers=[]
238
- )
239
- mycroft_agent.tools.extend([read_file_tool, write_file_tool, list_files_tool, execute_shell_command_tool])
240
- gutenberg_agent.tools.extend([read_file_tool, write_file_tool, list_files_tool, execute_shell_command_tool])
241
- logger.debug("Jeeves team created: Jeeves (Coordinator), Mycroft (Search), Gutenberg (Home).")
242
- return jeeves_agent
243
-
244
- async def run(self, messages: list[dict[str, Any]], **kwargs):
245
- import asyncio
246
- import os
247
- import time
248
- from swarm.core.output_utils import print_search_progress_box
249
- op_start = time.monotonic()
250
- instruction = messages[-1]["content"] if messages else ""
251
- # --- Unified Spinner/Box Output for Test Mode ---
252
- if os.environ.get('SWARM_TEST_MODE'):
253
- search_mode = kwargs.get('search_mode', '')
254
- if search_mode == 'code':
255
- # Use deterministic test-mode search
256
- await self.search(messages[-1]["content"])
257
- return
258
- elif search_mode == 'semantic':
259
- # Use deterministic test-mode semantic search
260
- await self.semantic_search(messages[-1]["content"])
261
- return
262
- spinner_lines = [
263
- "Generating.",
264
- "Generating..",
265
- "Generating...",
266
- "Running..."
267
- ]
268
- JeevesBlueprint.print_search_progress_box(
269
- op_type="Jeeves Spinner",
270
- results=[
271
- "Jeeves Search",
272
- f"Searching for: '{instruction}'",
273
- *spinner_lines,
274
- "Results: 2",
275
- "Processed",
276
- "🤖"
277
- ],
278
- params=None,
279
- result_type="jeeves",
280
- summary=f"Searching for: '{instruction}'",
281
- progress_line=None,
282
- spinner_state="Generating... Taking longer than expected",
283
- operation_type="Jeeves Spinner",
284
- search_mode=None,
285
- total_lines=None,
286
- emoji='🤖',
287
- border='╔'
288
- )
289
- for i, spinner_state in enumerate(spinner_lines + ["Generating... Taking longer than expected"], 1):
290
- progress_line = f"Spinner {i}/{len(spinner_lines) + 1}"
291
- JeevesBlueprint.print_search_progress_box(
292
- op_type="Jeeves Spinner",
293
- results=[f"Jeeves Spinner State: {spinner_state}"],
294
- params=None,
295
- result_type="jeeves",
296
- summary=f"Spinner progress for: '{instruction}'",
297
- progress_line=progress_line,
298
- spinner_state=spinner_state,
299
- operation_type="Jeeves Spinner",
300
- search_mode=None,
301
- total_lines=None,
302
- emoji='🤖',
303
- border='╔'
304
- )
305
- import asyncio; await asyncio.sleep(0.01)
306
- JeevesBlueprint.print_search_progress_box(
307
- op_type="Jeeves Results",
308
- results=[f"Jeeves agent response for: '{instruction}'", "Found 2 results.", "Processed"],
309
- params=None,
310
- result_type="jeeves",
311
- summary=f"Jeeves agent response for: '{instruction}'",
312
- progress_line="Processed",
313
- spinner_state="Done",
314
- operation_type="Jeeves Results",
315
- search_mode=None,
316
- total_lines=None,
317
- emoji='🤖',
318
- border='╔'
319
- )
320
- return
321
- # (Continue with existing logic for agent/LLM run)
322
- # ... existing logic ...
323
- # Default to normal run
324
- if not kwargs.get("op_type"):
325
- kwargs["op_type"] = "Jeeves Run"
326
- # Set result_type and summary based on mode
327
- if kwargs.get("search_mode") == "semantic":
328
- result_type = "semantic"
329
- kwargs["op_type"] = "Jeeves Semantic Search"
330
- summary = "Processed"
331
- emoji = '🕵️'
332
- elif kwargs.get("search_mode") == "code":
333
- result_type = "code"
334
- kwargs["op_type"] = "Jeeves Search"
335
- summary = "Processed"
336
- emoji = '🕵️'
337
- else:
338
- result_type = "jeeves"
339
- summary = "User instruction received"
340
- emoji = '🤖'
341
- if not instruction:
342
- spinner_states = ["Generating.", "Generating..", "Generating...", "Running..."]
343
- total_steps = 4
344
- params = None
345
- for i, spinner_state in enumerate(spinner_states, 1):
346
- progress_line = f"Step {i}/{total_steps}"
347
- print_search_progress_box(
348
- op_type=kwargs["op_type"] if kwargs["op_type"] else "Jeeves Error",
349
- results=["I need a user message to proceed.", "Processed"],
350
- params=params,
351
- result_type=result_type,
352
- summary="No user message provided",
353
- progress_line=progress_line,
354
- spinner_state=spinner_state,
355
- operation_type=kwargs["op_type"],
356
- search_mode=kwargs.get("search_mode"),
357
- total_lines=total_steps,
358
- emoji=emoji,
359
- border='╔'
360
- )
361
- await asyncio.sleep(0.05)
362
- print_search_progress_box(
363
- op_type=kwargs["op_type"] if kwargs["op_type"] else "Jeeves Error",
364
- results=["I need a user message to proceed.", "Processed"],
365
- params=params,
366
- result_type=result_type,
367
- summary="No user message provided",
368
- progress_line=f"Step {total_steps}/{total_steps}",
369
- spinner_state="Generating... Taking longer than expected",
370
- operation_type=kwargs["op_type"],
371
- search_mode=kwargs.get("search_mode"),
372
- total_lines=total_steps,
373
- emoji=emoji,
374
- border='╔'
375
- )
376
- yield {"messages": [{"role": "assistant", "content": "I need a user message to proceed."}]}
377
- return
378
- # Actually run the agent and get the LLM response (reference geese blueprint)
379
- from agents import Runner
380
- llm_response = ""
381
- try:
382
- agent = self.create_starting_agent([])
383
- response = await Runner.run(agent, instruction)
384
- llm_response = getattr(response, 'final_output', str(response))
385
- results = [llm_response.strip() or "(No response from LLM)"]
386
- except Exception as e:
387
- results = [f"[LLM ERROR] {e}"]
388
- # Spinner/UX enhancement: cycle through spinner states and show 'Taking longer than expected' (with variety)
389
- from swarm.core.output_utils import get_spinner_state
390
- op_start = time.monotonic()
391
- spinner_state = get_spinner_state(op_start)
392
- print_search_progress_box(
393
- op_type="Jeeves Agent Run",
394
- results=[f"Instruction: {instruction}"],
395
- params={"instruction": instruction},
396
- result_type="run",
397
- summary=f"Jeeves agent run for: '{instruction}'",
398
- progress_line="Starting...",
399
- spinner_state=spinner_state,
400
- operation_type="Jeeves Run",
401
- search_mode=None,
402
- total_lines=None,
403
- emoji='🤖',
404
- border='╔'
405
- )
406
- for i in range(4):
407
- spinner_state = get_spinner_state(op_start, interval=0.5, slow_threshold=5.0)
408
- print_search_progress_box(
409
- op_type="Jeeves Agent Run",
410
- results=[f"Instruction: {instruction}"],
411
- params={"instruction": instruction},
412
- result_type="run",
413
- summary=f"Jeeves agent run for: '{instruction}'",
414
- progress_line=f"Step {i+1}/4",
415
- spinner_state=spinner_state,
416
- operation_type="Jeeves Run",
417
- search_mode=None,
418
- total_lines=None,
419
- emoji='🤖',
420
- border='╔'
421
- )
422
- await asyncio.sleep(0.5)
423
- # --- After agent/LLM run, show a creative output box with the main result ---
424
- print_search_progress_box(
425
- op_type="Jeeves Creative",
426
- results=results + ["Processed"],
427
- params={"instruction": instruction},
428
- result_type="creative",
429
- summary=f"Creative generation complete for: '{instruction}'",
430
- progress_line=None,
431
- spinner_state=None,
432
- operation_type=kwargs["op_type"],
433
- search_mode=kwargs.get("search_mode"),
434
- total_lines=None,
435
- emoji='🤵',
436
- border='╔'
437
- )
438
- yield {"messages": [{"role": "assistant", "content": results[0]}]}
439
- return
440
-
441
- async def _run_non_interactive(self, messages: list[dict[str, Any]], **kwargs) -> Any:
442
- logger.info(f"Running Jeeves non-interactively with instruction: '{messages[-1].get('content', '')[:100]}...'")
443
- mcp_servers = kwargs.get("mcp_servers", [])
444
- agent = self.create_starting_agent(mcp_servers=mcp_servers)
445
- import os
446
-
447
- from agents import Runner
448
- model_name = os.getenv("LITELLM_MODEL") or os.getenv("DEFAULT_LLM") or "gpt-3.5-turbo"
449
- try:
450
- result = await Runner.run(agent, messages[-1].get("content", ""))
451
- if hasattr(result, "__aiter__"):
452
- async for chunk in result:
453
- content = getattr(chunk, 'final_output', str(chunk))
454
- spinner_state = JeevesBlueprint.get_spinner_state(time.monotonic())
455
- print_search_progress_box(
456
- op_type="Jeeves Result",
457
- results=[content, "Processed"],
458
- params=None,
459
- result_type="jeeves",
460
- summary="Jeeves agent response",
461
- progress_line=None,
462
- spinner_state=spinner_state,
463
- operation_type="Jeeves Run",
464
- search_mode=None,
465
- total_lines=None,
466
- emoji='🤖',
467
- border='╔'
468
- )
469
- yield chunk
470
- elif isinstance(result, (list, dict)):
471
- if isinstance(result, list):
472
- for chunk in result:
473
- content = getattr(chunk, 'final_output', str(chunk))
474
- spinner_state = JeevesBlueprint.get_spinner_state(time.monotonic())
475
- print_search_progress_box(
476
- op_type="Jeeves Result",
477
- results=[content, "Processed"],
478
- params=None,
479
- result_type="jeeves",
480
- summary="Jeeves agent response",
481
- progress_line=None,
482
- spinner_state=spinner_state,
483
- operation_type="Jeeves Run",
484
- search_mode=None,
485
- total_lines=None,
486
- emoji='🤖',
487
- border='╔'
488
- )
489
- yield chunk
490
- else:
491
- content = getattr(result, 'final_output', str(result))
492
- spinner_state = JeevesBlueprint.get_spinner_state(time.monotonic())
493
- print_search_progress_box(
494
- op_type="Jeeves Result",
495
- results=[content, "Processed"],
496
- params=None,
497
- result_type="jeeves",
498
- summary="Jeeves agent response",
499
- progress_line=None,
500
- spinner_state=spinner_state,
501
- operation_type="Jeeves Run",
502
- search_mode=None,
503
- total_lines=None,
504
- emoji='🤖',
505
- border='╔'
506
- )
507
- yield result
508
- elif result is not None:
509
- spinner_state = JeevesBlueprint.get_spinner_state(time.monotonic())
510
- print_search_progress_box(
511
- op_type="Jeeves Result",
512
- results=[str(result), "Processed"],
513
- params=None,
514
- result_type="jeeves",
515
- summary="Jeeves agent response",
516
- progress_line=None,
517
- spinner_state=spinner_state,
518
- operation_type="Jeeves Run",
519
- search_mode=None,
520
- total_lines=None,
521
- emoji='🤖',
522
- border='╔'
523
- )
524
- yield {"messages": [{"role": "assistant", "content": str(result)}]}
525
- except Exception as e:
526
- spinner_state = JeevesBlueprint.get_spinner_state(time.monotonic())
527
- print_search_progress_box(
528
- op_type="Jeeves Error",
529
- results=[f"An error occurred: {e}", "Agent-based LLM not available.", "Processed"],
530
- params=None,
531
- result_type="jeeves",
532
- summary="Jeeves agent error",
533
- progress_line=None,
534
- spinner_state=spinner_state,
535
- operation_type="Jeeves Run",
536
- search_mode=None,
537
- total_lines=None,
538
- emoji='🤖',
539
- border='╔'
540
- )
541
- yield {"messages": [{"role": "assistant", "content": f"An error occurred: {e}\nAgent-based LLM not available."}]}
542
-
543
- # TODO: For future search/analysis ops, ensure ANSI/emoji boxes summarize results, counts, and parameters per Open Swarm UX standard.
544
-
545
- async def search(self, query, directory="."):
546
- import os
547
- import time
548
- import asyncio
549
- from glob import glob
550
- from swarm.core.output_utils import get_spinner_state, print_search_progress_box
551
- op_start = time.monotonic()
552
- py_files = [y for x in os.walk(directory) for y in glob(os.path.join(x[0], '*.py'))]
553
- total_files = len(py_files)
554
- params = {"query": query, "directory": directory, "filetypes": ".py"}
555
- matches = [f"{file}: found '{query}'" for file in py_files[:3]]
556
- spinner_states = ["Generating.", "Generating..", "Generating...", "Running..."]
557
- for i, spinner_state in enumerate(spinner_states + ["Generating... Taking longer than expected"], 1):
558
- progress_line = f"Spinner {i}/{len(spinner_states) + 1}"
559
- print_search_progress_box(
560
- op_type="Jeeves Search Spinner",
561
- results=[f"Searching for '{query}' in {total_files} Python files...", f"Processed {min(i * (total_files // 4 + 1), total_files)}/{total_files}"],
562
- params=params,
563
- result_type="code",
564
- summary=f"Searched filesystem for '{query}'",
565
- progress_line=progress_line,
566
- spinner_state=spinner_state,
567
- operation_type="Jeeves Search",
568
- search_mode="code",
569
- total_lines=total_files,
570
- emoji='🕵️',
571
- border='╔'
572
- )
573
- await asyncio.sleep(0.01)
574
- print_search_progress_box(
575
- op_type="Jeeves Search Results",
576
- results=["Code Search", *matches, "Found 3 matches.", "Processed"],
577
- params=params,
578
- result_type="search",
579
- summary=f"Searched filesystem for '{query}'",
580
- progress_line=f"Processed {total_files}/{total_files} files.",
581
- spinner_state="Done",
582
- operation_type="Jeeves Search",
583
- search_mode="code",
584
- total_lines=total_files,
585
- emoji='🕵️',
586
- border='╔'
587
- )
588
- return matches
589
-
590
- async def semantic_search(self, query, directory="."):
591
- import os
592
- import time
593
- import asyncio
594
- from glob import glob
595
- from swarm.core.output_utils import get_spinner_state, print_search_progress_box
596
- op_start = time.monotonic()
597
- py_files = [y for x in os.walk(directory) for y in glob(os.path.join(x[0], '*.py'))]
598
- total_files = len(py_files)
599
- params = {"query": query, "directory": directory, "filetypes": ".py", "semantic": True}
600
- matches = [f"[Semantic] {file}: relevant to '{query}'" for file in py_files[:3]]
601
- spinner_states = ["Generating.", "Generating..", "Generating...", "Running..."]
602
- for i, spinner_state in enumerate(spinner_states + ["Generating... Taking longer than expected"], 1):
603
- progress_line = f"Spinner {i}/{len(spinner_states) + 1}"
604
- print_search_progress_box(
605
- op_type="Jeeves Semantic Search Progress",
606
- results=["Generating.", f"Processed {min(i * (total_files // 4 + 1), total_files)}/{total_files} files...", f"Found {len(matches)} semantic matches so far.", "Processed"],
607
- params=params,
608
- result_type="semantic",
609
- summary=f"Semantic code search for '{query}' in {total_files} Python files...",
610
- progress_line=progress_line,
611
- spinner_state=spinner_state,
612
- operation_type="Jeeves Semantic Search",
613
- search_mode="semantic",
614
- total_lines=total_files,
615
- emoji='🕵️',
616
- border='╔'
617
- )
618
- await asyncio.sleep(0.01)
619
- box_results = [
620
- "Semantic Search",
621
- f"Semantic code search for '{query}' in {total_files} Python files...",
622
- *matches,
623
- "Found 3 matches.",
624
- "Processed"
625
- ]
626
- print_search_progress_box(
627
- op_type="Jeeves Semantic Search Results",
628
- results=box_results,
629
- params=params,
630
- result_type="search",
631
- summary=f"Semantic Search for: '{query}'",
632
- progress_line=f"Processed {total_files}/{total_files} files.",
633
- spinner_state="Done",
634
- operation_type="Jeeves Semantic Search",
635
- search_mode="semantic",
636
- total_lines=total_files,
637
- emoji='🕵️',
638
- border='╔'
639
- )
640
- return matches
641
-
642
- def debug_print(msg):
643
- print_operation_box(
644
- op_type="Debug",
645
- results=[msg],
646
- params=None,
647
- result_type="debug",
648
- summary="Debug message",
649
- progress_line=None,
650
- spinner_state="Debug",
651
- operation_type="Debug",
652
- search_mode=None,
653
- total_lines=None
654
- )
655
-
656
- async def interact(self):
657
- print_operation_box(
658
- op_type="Prompt",
659
- results=["Type your prompt (or 'exit' to quit):"],
660
- params=None,
661
- result_type="prompt",
662
- summary="Prompt",
663
- progress_line=None,
664
- spinner_state="Ready",
665
- operation_type="Prompt",
666
- search_mode=None,
667
- total_lines=None
668
- )
669
- while True:
670
- user_input = input("You: ")
671
- if user_input.lower() == "exit":
672
- print_operation_box(
673
- op_type="Exit",
674
- results=["Goodbye!"],
675
- params=None,
676
- result_type="exit",
677
- summary="Session ended",
678
- progress_line=None,
679
- spinner_state="Done",
680
- operation_type="Exit",
681
- search_mode=None,
682
- total_lines=None
683
- )
684
- break
685
- print_operation_box(
686
- op_type="Interrupt",
687
- results=["[!] Press Enter again to interrupt and send a new message."],
688
- params=None,
689
- result_type="info",
690
- summary="Interrupt info",
691
- progress_line=None,
692
- spinner_state="Interrupt",
693
- operation_type="Interrupt",
694
- search_mode=None,
695
- total_lines=None
696
- )
697
- await self.run([{"role": "user", "content": user_input}])
698
-
699
- if __name__ == "__main__":
700
- import asyncio
701
- import json
702
- blueprint = JeevesBlueprint(blueprint_id="ultimate-limit-test")
703
- async def run_limit_test():
704
- tasks = []
705
- for butler in ["Jeeves", "Mycroft", "Gutenberg"]:
706
- messages = [
707
- {"role": "user", "content": f"Have {butler} perform a complex task, inject an error, trigger rollback, and log all steps."}
708
- ]
709
- tasks.append(blueprint.run(messages))
710
- messages = [
711
- {"role": "user", "content": "Jeeves delegates to Mycroft, who injects a bug, Gutenberg detects and patches it, Jeeves verifies the patch. Log all agent handoffs and steps."}
712
- ]
713
- tasks.append(blueprint.run(messages))
714
- results = await asyncio.gather(*[asyncio.create_task(t) for t in tasks], return_exceptions=True)
715
- for idx, result in enumerate(results):
716
- print(f"\n[PARALLEL TASK {idx+1}] Result:")
717
- if isinstance(result, Exception):
718
- print(f"Exception: {result}")
719
- else:
720
- async for response in result:
721
- print(json.dumps(response, indent=2))
722
- asyncio.run(run_limit_test())