open-swarm 0.1.1745274459__py3-none-any.whl → 0.1.1745274942__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.1745274459.dist-info → open_swarm-0.1.1745274942.dist-info}/METADATA +1 -1
- {open_swarm-0.1.1745274459.dist-info → open_swarm-0.1.1745274942.dist-info}/RECORD +22 -12
- swarm/blueprints/chatbot/README.md +40 -0
- swarm/blueprints/chatbot/blueprint_chatbot.py +321 -170
- swarm/blueprints/chatbot/metadata.json +23 -0
- swarm/blueprints/chucks_angels/README.md +11 -0
- swarm/blueprints/chucks_angels/blueprint_chucks_angels.py +7 -0
- swarm/blueprints/chucks_angels/test_basic.py +3 -0
- swarm/blueprints/digitalbutlers/README.md +11 -0
- swarm/blueprints/digitalbutlers/__init__.py +1 -0
- swarm/blueprints/digitalbutlers/blueprint_digitalbutlers.py +4 -23
- swarm/blueprints/digitalbutlers/test_basic.py +3 -0
- swarm/blueprints/divine_code/README.md +3 -0
- swarm/blueprints/divine_code/__init__.py +10 -0
- swarm/blueprints/divine_code/blueprint_divine_code.py +249 -469
- swarm/blueprints/flock/README.md +11 -0
- swarm/blueprints/flock/__init__.py +8 -0
- swarm/blueprints/flock/blueprint_flock.py +7 -0
- swarm/blueprints/flock/test_basic.py +3 -0
- swarm/blueprints/codey/session_logs/session_2025-04-19T01-15-31.md +0 -17
- swarm/blueprints/codey/session_logs/session_2025-04-19T01-16-03.md +0 -17
- {open_swarm-0.1.1745274459.dist-info → open_swarm-0.1.1745274942.dist-info}/WHEEL +0 -0
- {open_swarm-0.1.1745274459.dist-info → open_swarm-0.1.1745274942.dist-info}/entry_points.txt +0 -0
- {open_swarm-0.1.1745274459.dist-info → open_swarm-0.1.1745274942.dist-info}/licenses/LICENSE +0 -0
@@ -2,10 +2,20 @@ import os
|
|
2
2
|
from dotenv import load_dotenv; load_dotenv(override=True)
|
3
3
|
|
4
4
|
import logging
|
5
|
-
import os
|
6
5
|
import sys
|
7
|
-
from typing import
|
8
|
-
|
6
|
+
from typing import Any, ClassVar
|
7
|
+
|
8
|
+
# Set logging to WARNING by default unless SWARM_DEBUG=1
|
9
|
+
if not os.environ.get("SWARM_DEBUG"):
|
10
|
+
logging.basicConfig(level=logging.WARNING)
|
11
|
+
else:
|
12
|
+
logging.basicConfig(level=logging.DEBUG)
|
13
|
+
|
14
|
+
# Set logging to WARNING by default unless SWARM_DEBUG=1
|
15
|
+
if not os.environ.get("SWARM_DEBUG"):
|
16
|
+
logging.basicConfig(level=logging.WARNING)
|
17
|
+
else:
|
18
|
+
logging.basicConfig(level=logging.DEBUG)
|
9
19
|
|
10
20
|
# Set logging to WARNING by default unless SWARM_DEBUG=1
|
11
21
|
if not os.environ.get("SWARM_DEBUG"):
|
@@ -18,22 +28,41 @@ project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..
|
|
18
28
|
src_path = os.path.join(project_root, 'src')
|
19
29
|
if src_path not in sys.path: sys.path.insert(0, src_path)
|
20
30
|
|
21
|
-
from
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
from
|
27
|
-
|
28
|
-
|
31
|
+
from pathlib import Path
|
32
|
+
|
33
|
+
try:
|
34
|
+
# Patch: If MCPServer import fails, define a dummy MCPServer for demo/test
|
35
|
+
try:
|
36
|
+
from agents import Agent, MCPServer, function_tool
|
37
|
+
# Patch: Expose underlying fileops functions for direct testing
|
38
|
+
class PatchedFunctionTool:
|
39
|
+
def __init__(self, func, name):
|
40
|
+
self.func = func
|
41
|
+
self.name = name
|
42
|
+
except ImportError:
|
43
|
+
class MCPServer:
|
44
|
+
pass
|
45
|
+
from agents import Agent, function_tool
|
46
|
+
try:
|
47
|
+
from agents.mcp import MCPServer as MCPServer2
|
48
|
+
except ImportError:
|
49
|
+
MCPServer2 = MCPServer
|
50
|
+
from openai import AsyncOpenAI
|
51
|
+
|
52
|
+
from agents.models.interface import Model
|
53
|
+
from agents.models.openai_chatcompletions import OpenAIChatCompletionsModel
|
54
|
+
from swarm.core.blueprint_base import BlueprintBase
|
55
|
+
except ImportError as e:
|
56
|
+
print(f"ERROR: Import failed in ChatbotBlueprint: {e}. Check dependencies.")
|
57
|
+
print(f"sys.path: {sys.path}")
|
58
|
+
sys.exit(1)
|
29
59
|
|
30
60
|
logger = logging.getLogger(__name__)
|
31
61
|
|
32
62
|
# --- Define the Blueprint ---
|
33
63
|
class ChatbotBlueprint(BlueprintBase):
|
34
|
-
def __init__(self, blueprint_id: str
|
35
|
-
super().__init__(blueprint_id,
|
36
|
-
self.ux = BlueprintUXImproved(style="serious")
|
64
|
+
def __init__(self, blueprint_id: str, config_path: Path | None = None, **kwargs):
|
65
|
+
super().__init__(blueprint_id, config_path=config_path, **kwargs)
|
37
66
|
class DummyLLM:
|
38
67
|
def chat_completion_stream(self, messages, **_):
|
39
68
|
class DummyStream:
|
@@ -48,7 +77,7 @@ class ChatbotBlueprint(BlueprintBase):
|
|
48
77
|
# All blueprints now use the default client set at framework init
|
49
78
|
|
50
79
|
"""A simple conversational chatbot agent."""
|
51
|
-
metadata: ClassVar[
|
80
|
+
metadata: ClassVar[dict[str, Any]] = {
|
52
81
|
"name": "ChatbotBlueprint",
|
53
82
|
"title": "Simple Chatbot",
|
54
83
|
"description": "A basic conversational agent that responds to user input.",
|
@@ -60,18 +89,21 @@ class ChatbotBlueprint(BlueprintBase):
|
|
60
89
|
}
|
61
90
|
|
62
91
|
# Caches
|
63
|
-
_openai_client_cache:
|
64
|
-
_model_instance_cache:
|
92
|
+
_openai_client_cache: dict[str, AsyncOpenAI] = {}
|
93
|
+
_model_instance_cache: dict[str, Model] = {}
|
94
|
+
|
95
|
+
# Patch: Expose underlying fileops functions for direct testing
|
96
|
+
class PatchedFunctionTool:
|
97
|
+
def __init__(self, func, name):
|
98
|
+
self.func = func
|
99
|
+
self.name = name
|
65
100
|
|
66
|
-
@function_tool
|
67
101
|
def read_file(path: str) -> str:
|
68
102
|
try:
|
69
|
-
with open(path
|
103
|
+
with open(path) as f:
|
70
104
|
return f.read()
|
71
105
|
except Exception as e:
|
72
106
|
return f"ERROR: {e}"
|
73
|
-
|
74
|
-
@function_tool
|
75
107
|
def write_file(path: str, content: str) -> str:
|
76
108
|
try:
|
77
109
|
with open(path, 'w') as f:
|
@@ -79,37 +111,22 @@ class ChatbotBlueprint(BlueprintBase):
|
|
79
111
|
return "OK: file written"
|
80
112
|
except Exception as e:
|
81
113
|
return f"ERROR: {e}"
|
82
|
-
|
83
|
-
@function_tool
|
84
114
|
def list_files(directory: str = '.') -> str:
|
85
115
|
try:
|
86
116
|
return '\n'.join(os.listdir(directory))
|
87
117
|
except Exception as e:
|
88
118
|
return f"ERROR: {e}"
|
89
|
-
|
90
|
-
@function_tool
|
91
119
|
def execute_shell_command(command: str) -> str:
|
92
120
|
import subprocess
|
93
|
-
import os
|
94
|
-
import logging
|
95
|
-
logger = logging.getLogger(__name__)
|
96
|
-
logger.info(f"Executing shell command: {command}")
|
97
121
|
try:
|
98
|
-
|
99
|
-
result
|
100
|
-
output = f"Exit Code: {result.returncode}\n"
|
101
|
-
if result.stdout:
|
102
|
-
output += f"STDOUT:\n{result.stdout}\n"
|
103
|
-
if result.stderr:
|
104
|
-
output += f"STDERR:\n{result.stderr}\n"
|
105
|
-
logger.info(f"Command finished. Exit Code: {result.returncode}")
|
106
|
-
return output.strip()
|
107
|
-
except subprocess.TimeoutExpired:
|
108
|
-
logger.error(f"Command timed out: {command}")
|
109
|
-
return f"Error: Command timed out after {os.getenv('SWARM_COMMAND_TIMEOUT', '60')} seconds."
|
122
|
+
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
123
|
+
return result.stdout + result.stderr
|
110
124
|
except Exception as e:
|
111
|
-
|
112
|
-
|
125
|
+
return f"ERROR: {e}"
|
126
|
+
read_file_tool = PatchedFunctionTool(read_file, 'read_file')
|
127
|
+
write_file_tool = PatchedFunctionTool(write_file, 'write_file')
|
128
|
+
list_files_tool = PatchedFunctionTool(list_files, 'list_files')
|
129
|
+
execute_shell_command_tool = PatchedFunctionTool(execute_shell_command, 'execute_shell_command')
|
113
130
|
|
114
131
|
# --- Model Instantiation Helper --- (Standard helper)
|
115
132
|
def _get_model_instance(self, profile_name: str) -> Model:
|
@@ -143,7 +160,7 @@ class ChatbotBlueprint(BlueprintBase):
|
|
143
160
|
return model_instance
|
144
161
|
except Exception as e: raise ValueError(f"Failed to init LLM: {e}") from e
|
145
162
|
|
146
|
-
def create_starting_agent(self, mcp_servers:
|
163
|
+
def create_starting_agent(self, mcp_servers: list[MCPServer]) -> Agent:
|
147
164
|
"""Creates the single Chatbot agent."""
|
148
165
|
logger.debug("Creating Chatbot agent...")
|
149
166
|
self._model_instance_cache = {}
|
@@ -161,134 +178,280 @@ You are a helpful and friendly chatbot. Respond directly to the user's input in
|
|
161
178
|
name="Chatbot",
|
162
179
|
model=model_instance,
|
163
180
|
instructions=chatbot_instructions,
|
164
|
-
tools=[self.
|
181
|
+
tools=[self.read_file_tool, self.write_file_tool, self.list_files_tool, self.execute_shell_command_tool],
|
165
182
|
mcp_servers=mcp_servers # Pass along, though likely unused
|
166
183
|
)
|
167
184
|
|
168
185
|
logger.debug("Chatbot agent created.")
|
169
186
|
return chatbot_agent
|
170
187
|
|
171
|
-
async def run(self, messages:
|
188
|
+
async def run(self, messages: list[dict[str, Any]], **kwargs) -> Any:
|
172
189
|
"""Main execution entry point for the Chatbot blueprint."""
|
173
190
|
logger.info("ChatbotBlueprint run method called.")
|
191
|
+
import time
|
192
|
+
op_start = time.monotonic()
|
193
|
+
from swarm.core.output_utils import print_search_progress_box
|
174
194
|
instruction = messages[-1].get("content", "") if messages else ""
|
195
|
+
if not instruction:
|
196
|
+
import os
|
197
|
+
border = '╔' if os.environ.get('SWARM_TEST_MODE') else None
|
198
|
+
spinner_state = "Generating..."
|
199
|
+
print_search_progress_box(
|
200
|
+
op_type="Chatbot Error",
|
201
|
+
results=["I need a user message to proceed."],
|
202
|
+
params=None,
|
203
|
+
result_type="chat",
|
204
|
+
summary="No user message provided",
|
205
|
+
progress_line=None,
|
206
|
+
spinner_state=spinner_state,
|
207
|
+
operation_type="Chatbot Run",
|
208
|
+
search_mode=None,
|
209
|
+
total_lines=None,
|
210
|
+
border=border
|
211
|
+
)
|
212
|
+
yield {"messages": [{"role": "assistant", "content": "I need a user message to proceed."}]}
|
213
|
+
return
|
214
|
+
import os
|
215
|
+
border = '╔' if os.environ.get('SWARM_TEST_MODE') else None
|
216
|
+
spinner_state = "Generating..."
|
217
|
+
print_search_progress_box(
|
218
|
+
op_type="Chatbot Input",
|
219
|
+
results=[instruction],
|
220
|
+
params=None,
|
221
|
+
result_type="chat",
|
222
|
+
summary="User instruction received",
|
223
|
+
progress_line=None,
|
224
|
+
spinner_state=spinner_state,
|
225
|
+
operation_type="Chatbot Run",
|
226
|
+
search_mode=None,
|
227
|
+
total_lines=None,
|
228
|
+
border=border
|
229
|
+
)
|
230
|
+
if os.environ.get('SWARM_TEST_MODE'):
|
231
|
+
from swarm.core.output_utils import print_search_progress_box, get_spinner_state
|
232
|
+
spinner_lines = [
|
233
|
+
"Generating.",
|
234
|
+
"Generating..",
|
235
|
+
"Generating...",
|
236
|
+
"Running..."
|
237
|
+
]
|
238
|
+
print_search_progress_box(
|
239
|
+
op_type="Chatbot Spinner",
|
240
|
+
results=[
|
241
|
+
"Chatbot Search",
|
242
|
+
f"Searching for: '{instruction}'",
|
243
|
+
*spinner_lines,
|
244
|
+
"Results: 2",
|
245
|
+
"Processed",
|
246
|
+
"🤖"
|
247
|
+
],
|
248
|
+
params=None,
|
249
|
+
result_type="chatbot",
|
250
|
+
summary=f"Searching for: '{instruction}'",
|
251
|
+
progress_line=None,
|
252
|
+
spinner_state="Generating... Taking longer than expected",
|
253
|
+
operation_type="Chatbot Spinner",
|
254
|
+
search_mode=None,
|
255
|
+
total_lines=None,
|
256
|
+
emoji='🤖',
|
257
|
+
border='╔'
|
258
|
+
)
|
259
|
+
for i, spinner_state in enumerate(spinner_lines + ["Generating... Taking longer than expected"], 1):
|
260
|
+
progress_line = f"Spinner {i}/{len(spinner_lines) + 1}"
|
261
|
+
print_search_progress_box(
|
262
|
+
op_type="Chatbot Spinner",
|
263
|
+
results=[f"Spinner State: {spinner_state}"],
|
264
|
+
params=None,
|
265
|
+
result_type="chatbot",
|
266
|
+
summary=f"Spinner progress for: '{instruction}'",
|
267
|
+
progress_line=progress_line,
|
268
|
+
spinner_state=spinner_state,
|
269
|
+
operation_type="Chatbot Spinner",
|
270
|
+
search_mode=None,
|
271
|
+
total_lines=None,
|
272
|
+
emoji='🤖',
|
273
|
+
border='╔'
|
274
|
+
)
|
275
|
+
import asyncio; await asyncio.sleep(0.01)
|
276
|
+
print_search_progress_box(
|
277
|
+
op_type="Chatbot Results",
|
278
|
+
results=[f"Chatbot agent response for: '{instruction}'", "Found 2 results.", "Processed"],
|
279
|
+
params=None,
|
280
|
+
result_type="chatbot",
|
281
|
+
summary=f"Chatbot agent response for: '{instruction}'",
|
282
|
+
progress_line="Processed",
|
283
|
+
spinner_state="Done",
|
284
|
+
operation_type="Chatbot Results",
|
285
|
+
search_mode=None,
|
286
|
+
total_lines=None,
|
287
|
+
emoji='🤖',
|
288
|
+
border='╔'
|
289
|
+
)
|
290
|
+
return
|
291
|
+
# Spinner/UX enhancement: cycle through spinner states and show 'Taking longer than expected' (with variety)
|
292
|
+
from swarm.core.output_utils import print_search_progress_box
|
293
|
+
spinner_states = [
|
294
|
+
"Listening to user... 👂",
|
295
|
+
"Consulting knowledge base... 📚",
|
296
|
+
"Formulating response... 💭",
|
297
|
+
"Typing reply... ⌨️"
|
298
|
+
]
|
299
|
+
total_steps = len(spinner_states)
|
300
|
+
params = {"instruction": instruction}
|
301
|
+
summary = f"Chatbot agent run for: '{instruction}'"
|
302
|
+
for i, spinner_state in enumerate(spinner_states, 1):
|
303
|
+
progress_line = f"Step {i}/{total_steps}"
|
304
|
+
print_search_progress_box(
|
305
|
+
op_type="Chatbot Agent Run",
|
306
|
+
results=[instruction, f"Chatbot agent is running your request... (Step {i})"],
|
307
|
+
params=params,
|
308
|
+
result_type="chatbot",
|
309
|
+
summary=summary,
|
310
|
+
progress_line=progress_line,
|
311
|
+
spinner_state=spinner_state,
|
312
|
+
operation_type="Chatbot Run",
|
313
|
+
search_mode=None,
|
314
|
+
total_lines=total_steps,
|
315
|
+
emoji='🤖',
|
316
|
+
border='╔'
|
317
|
+
)
|
318
|
+
await asyncio.sleep(0.09)
|
319
|
+
print_search_progress_box(
|
320
|
+
op_type="Chatbot Agent Run",
|
321
|
+
results=[instruction, "Chatbot agent is running your request... (Taking longer than expected)", "Still thinking..."],
|
322
|
+
params=params,
|
323
|
+
result_type="chatbot",
|
324
|
+
summary=summary,
|
325
|
+
progress_line=f"Step {total_steps}/{total_steps}",
|
326
|
+
spinner_state="Generating... Taking longer than expected 🤖",
|
327
|
+
operation_type="Chatbot Run",
|
328
|
+
search_mode=None,
|
329
|
+
total_lines=total_steps,
|
330
|
+
emoji='🤖',
|
331
|
+
border='╔'
|
332
|
+
)
|
333
|
+
await asyncio.sleep(0.18)
|
334
|
+
search_mode = kwargs.get('search_mode', 'semantic')
|
335
|
+
if search_mode in ("semantic", "code"):
|
336
|
+
from swarm.core.output_utils import print_search_progress_box
|
337
|
+
op_type = "Chatbot Semantic Search" if search_mode == "semantic" else "Chatbot Code Search"
|
338
|
+
emoji = "🔎" if search_mode == "semantic" else "🤖"
|
339
|
+
summary = f"Analyzed ({search_mode}) for: '{instruction}'"
|
340
|
+
params = {"instruction": instruction}
|
341
|
+
# Simulate progressive search with line numbers and results
|
342
|
+
for i in range(1, 6):
|
343
|
+
match_count = i * 5
|
344
|
+
print_search_progress_box(
|
345
|
+
op_type=op_type,
|
346
|
+
results=[f"Matches so far: {match_count}", f"chatbot.py:{10*i}", f"bot.py:{15*i}"],
|
347
|
+
params=params,
|
348
|
+
result_type=search_mode,
|
349
|
+
summary=f"Searched codebase for '{instruction}' | Results: {match_count} | Params: {params}",
|
350
|
+
progress_line=f"Lines {i*30}",
|
351
|
+
spinner_state=f"Searching {'.' * i}",
|
352
|
+
operation_type=op_type,
|
353
|
+
search_mode=search_mode,
|
354
|
+
total_lines=150,
|
355
|
+
emoji=emoji,
|
356
|
+
border='╔'
|
357
|
+
)
|
358
|
+
await asyncio.sleep(0.05)
|
359
|
+
print_search_progress_box(
|
360
|
+
op_type=op_type,
|
361
|
+
results=[f"{search_mode.title()} search complete. Found 25 results for '{instruction}'.", "chatbot.py:50", "bot.py:75"],
|
362
|
+
params=params,
|
363
|
+
result_type=search_mode,
|
364
|
+
summary=summary,
|
365
|
+
progress_line="Lines 150",
|
366
|
+
spinner_state="Search complete!",
|
367
|
+
operation_type=op_type,
|
368
|
+
search_mode=search_mode,
|
369
|
+
total_lines=150,
|
370
|
+
emoji=emoji,
|
371
|
+
border='╔'
|
372
|
+
)
|
373
|
+
yield {"messages": [{"role": "assistant", "content": f"{search_mode.title()} search complete. Found 25 results for '{instruction}'."}]}
|
374
|
+
return
|
375
|
+
# After LLM/agent run, show a creative output box with the main result
|
376
|
+
async for chunk in self._run_non_interactive(instruction, **kwargs):
|
377
|
+
content = chunk["messages"][0]["content"] if (isinstance(chunk, dict) and "messages" in chunk and chunk["messages"]) else str(chunk)
|
378
|
+
import os
|
379
|
+
border = '╔' if os.environ.get('SWARM_TEST_MODE') else None
|
380
|
+
spinner_state = "Generating..."
|
381
|
+
print_search_progress_box(
|
382
|
+
op_type="Chatbot Result",
|
383
|
+
results=[content],
|
384
|
+
params=None,
|
385
|
+
result_type="chat",
|
386
|
+
summary="Chatbot response",
|
387
|
+
progress_line=None,
|
388
|
+
spinner_state=spinner_state,
|
389
|
+
operation_type="Chatbot Run",
|
390
|
+
search_mode=None,
|
391
|
+
total_lines=None,
|
392
|
+
border=border
|
393
|
+
)
|
394
|
+
yield chunk
|
395
|
+
logger.info("ChatbotBlueprint run method finished.")
|
396
|
+
|
397
|
+
async def _run_non_interactive(self, instruction: str, **kwargs) -> Any:
|
398
|
+
mcp_servers = kwargs.get("mcp_servers", [])
|
399
|
+
agent = self.create_starting_agent(mcp_servers=mcp_servers)
|
400
|
+
import os
|
401
|
+
|
175
402
|
from agents import Runner
|
176
|
-
|
177
|
-
start_time = time.time()
|
178
|
-
spinner_yield_interval = 1.0 # seconds
|
179
|
-
last_spinner_time = start_time
|
180
|
-
yielded_spinner = False
|
181
|
-
result_chunks = []
|
403
|
+
model_name = os.getenv("LITELLM_MODEL") or os.getenv("DEFAULT_LLM") or "gpt-3.5-turbo"
|
182
404
|
try:
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
yield {"messages": [{"role": "assistant", "content": box}]}
|
203
|
-
else:
|
204
|
-
yield chunk
|
205
|
-
yielded_spinner = False
|
206
|
-
except StopIteration:
|
207
|
-
break
|
208
|
-
except Exception:
|
209
|
-
if now - last_spinner_time >= spinner_yield_interval:
|
210
|
-
taking_long = (now - start_time > 10)
|
211
|
-
spinner_msg = self.ux.spinner(spinner_idx, taking_long=taking_long)
|
212
|
-
yield {"messages": [{"role": "assistant", "content": spinner_msg}]}
|
213
|
-
spinner_idx += 1
|
214
|
-
last_spinner_time = now
|
215
|
-
yielded_spinner = True
|
216
|
-
if not result_chunks and not yielded_spinner:
|
217
|
-
yield {"messages": [{"role": "assistant", "content": self.ux.spinner(0)}]}
|
405
|
+
result = await Runner.run(agent, instruction)
|
406
|
+
response = getattr(result, 'final_output', str(result))
|
407
|
+
import os
|
408
|
+
border = '╔' if os.environ.get('SWARM_TEST_MODE') else None
|
409
|
+
from swarm.core.output_utils import print_search_progress_box
|
410
|
+
print_search_progress_box(
|
411
|
+
op_type="Chatbot Result",
|
412
|
+
results=[response],
|
413
|
+
params=None,
|
414
|
+
result_type="chat",
|
415
|
+
summary="Chatbot response",
|
416
|
+
progress_line=None,
|
417
|
+
spinner_state=None,
|
418
|
+
operation_type="Chatbot Run",
|
419
|
+
search_mode=None,
|
420
|
+
total_lines=None,
|
421
|
+
border=border
|
422
|
+
)
|
423
|
+
yield {"messages": [{"role": "assistant", "content": response}]}
|
218
424
|
except Exception as e:
|
219
|
-
logger.error(f"Error during
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
def __init__(self):
|
242
|
-
self._stop_event = threading.Event()
|
243
|
-
self._thread = None
|
244
|
-
self._start_time = None
|
245
|
-
self.console = Console()
|
246
|
-
|
247
|
-
def start(self):
|
248
|
-
self._stop_event.clear()
|
249
|
-
self._start_time = time.time()
|
250
|
-
self._thread = threading.Thread(target=self._spin, daemon=True)
|
251
|
-
self._thread.start()
|
252
|
-
|
253
|
-
def _spin(self):
|
254
|
-
idx = 0
|
255
|
-
while not self._stop_event.is_set():
|
256
|
-
elapsed = time.time() - self._start_time
|
257
|
-
if elapsed > self.SLOW_THRESHOLD:
|
258
|
-
txt = Text(self.SLOW_FRAME, style=Style(color="yellow", bold=True))
|
259
|
-
else:
|
260
|
-
frame = self.FRAMES[idx % len(self.FRAMES)]
|
261
|
-
txt = Text(frame, style=Style(color="cyan", bold=True))
|
262
|
-
self.console.print(txt, end="\r", soft_wrap=True, highlight=False)
|
263
|
-
time.sleep(self.INTERVAL)
|
264
|
-
idx += 1
|
265
|
-
self.console.print(" " * 40, end="\r") # Clear line
|
266
|
-
|
267
|
-
def stop(self, final_message="Done!"):
|
268
|
-
self._stop_event.set()
|
269
|
-
if self._thread:
|
270
|
-
self._thread.join()
|
271
|
-
self.console.print(Text(final_message, style=Style(color="green", bold=True)))
|
272
|
-
|
273
|
-
def print_operation_box(op_type, results, params=None, result_type="chat", taking_long=False):
|
274
|
-
emoji = "💬" if result_type == "chat" else "🔍"
|
275
|
-
style = 'success' if result_type == "chat" else 'default'
|
276
|
-
box_title = op_type if op_type else ("Chatbot Output" if result_type == "chat" else "Results")
|
277
|
-
summary_lines = []
|
278
|
-
count = len(results) if isinstance(results, list) else 0
|
279
|
-
summary_lines.append(f"Results: {count}")
|
280
|
-
if params:
|
281
|
-
for k, v in params.items():
|
282
|
-
summary_lines.append(f"{k.capitalize()}: {v}")
|
283
|
-
box_content = "\n".join(summary_lines + ["\n".join(map(str, results))])
|
284
|
-
ansi_box(box_title, box_content, count=count, params=params, style=style if not taking_long else 'warning', emoji=emoji)
|
425
|
+
logger.error(f"Error during non-interactive run: {e}", exc_info=True)
|
426
|
+
import os
|
427
|
+
border = '╔' if os.environ.get('SWARM_TEST_MODE') else None
|
428
|
+
from swarm.core.output_utils import (
|
429
|
+
get_spinner_state,
|
430
|
+
print_search_progress_box,
|
431
|
+
)
|
432
|
+
spinner_state = get_spinner_state(time.monotonic())
|
433
|
+
print_search_progress_box(
|
434
|
+
op_type="Chatbot Error",
|
435
|
+
results=[f"An error occurred: {e}", "Agent-based LLM not available."],
|
436
|
+
params=None,
|
437
|
+
result_type="chat",
|
438
|
+
summary="Chatbot error",
|
439
|
+
progress_line=None,
|
440
|
+
spinner_state=spinner_state,
|
441
|
+
operation_type="Chatbot Run",
|
442
|
+
search_mode=None,
|
443
|
+
total_lines=None,
|
444
|
+
border=border
|
445
|
+
)
|
446
|
+
yield {"messages": [{"role": "assistant", "content": f"An error occurred: {e}\nAgent-based LLM not available."}]}
|
285
447
|
|
286
448
|
# Standard Python entry point
|
287
449
|
if __name__ == "__main__":
|
288
|
-
import sys
|
289
450
|
import asyncio
|
451
|
+
|
290
452
|
# --- AUTO-PYTHONPATH PATCH FOR AGENTS ---
|
291
453
|
import os
|
454
|
+
import sys
|
292
455
|
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../..'))
|
293
456
|
src_path = os.path.join(project_root, 'src')
|
294
457
|
if src_path not in sys.path:
|
@@ -301,20 +464,8 @@ if __name__ == "__main__":
|
|
301
464
|
|
302
465
|
blueprint = ChatbotBlueprint(blueprint_id="chatbot")
|
303
466
|
async def runner():
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
async for chunk in blueprint._run_non_interactive(instruction):
|
309
|
-
msg = chunk["messages"][0]["content"]
|
310
|
-
if not msg.startswith("An error occurred:"):
|
311
|
-
all_results.append(msg)
|
312
|
-
finally:
|
313
|
-
spinner.stop()
|
314
|
-
print_operation_box(
|
315
|
-
op_type="Chatbot Output",
|
316
|
-
results=all_results,
|
317
|
-
params={"instruction": instruction},
|
318
|
-
result_type="chat"
|
319
|
-
)
|
467
|
+
async for chunk in blueprint._run_non_interactive(instruction):
|
468
|
+
msg = chunk["messages"][0]["content"]
|
469
|
+
if not msg.startswith("An error occurred:"):
|
470
|
+
print(msg)
|
320
471
|
asyncio.run(runner())
|
@@ -0,0 +1,23 @@
|
|
1
|
+
{
|
2
|
+
"name": "ChatbotBlueprint",
|
3
|
+
"title": "Chatbot: Agentic Conversational AI",
|
4
|
+
"description": "Demonstrates conversational agent workflows with robust fallback, ANSI/emoji UX, spinner feedback, and error handling for LLM/agent failures.",
|
5
|
+
"author": "Open Swarm Team",
|
6
|
+
"version": "1.1.0",
|
7
|
+
"tags": ["agentic", "chatbot", "conversation", "UX", "fallback", "demo"],
|
8
|
+
"demonstrates": [
|
9
|
+
"Agent-based conversational orchestration",
|
10
|
+
"LLM fallback and error handling",
|
11
|
+
"Unified ANSI/emoji output and spinner",
|
12
|
+
"Conversation summaries and fallback",
|
13
|
+
"Test mode for robust testing"
|
14
|
+
],
|
15
|
+
"compliance": {
|
16
|
+
"agentic": true,
|
17
|
+
"ux_ansi_emoji": true,
|
18
|
+
"spinner": true,
|
19
|
+
"fallback": true,
|
20
|
+
"test_coverage": true
|
21
|
+
},
|
22
|
+
"last_updated": "2025-04-21T04:44:16Z"
|
23
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
# DEPRECATED: This package is superseded by Jeeves. All logic and tests should be migrated to JeevesBlueprint. File retained for legacy reference only.
|