swarms 7.7.1__py3-none-any.whl → 7.7.3__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.
- swarms/prompts/ag_prompt.py +51 -19
- swarms/prompts/agent_system_prompts.py +13 -4
- swarms/prompts/multi_agent_collab_prompt.py +18 -0
- swarms/prompts/prompt.py +6 -10
- swarms/schemas/__init__.py +0 -3
- swarms/structs/__init__.py +3 -8
- swarms/structs/agent.py +211 -163
- swarms/structs/aop.py +8 -1
- swarms/structs/auto_swarm_builder.py +271 -210
- swarms/structs/conversation.py +23 -56
- swarms/structs/hiearchical_swarm.py +93 -122
- swarms/structs/ma_utils.py +96 -0
- swarms/structs/mixture_of_agents.py +20 -103
- swarms/structs/{multi_agent_orchestrator.py → multi_agent_router.py} +32 -95
- swarms/structs/output_types.py +3 -16
- swarms/structs/stopping_conditions.py +30 -0
- swarms/structs/swarm_router.py +57 -5
- swarms/structs/swarming_architectures.py +576 -185
- swarms/telemetry/main.py +6 -2
- swarms/tools/mcp_client.py +209 -53
- swarms/tools/mcp_integration.py +1 -53
- swarms/utils/formatter.py +15 -1
- swarms/utils/generate_keys.py +64 -0
- swarms/utils/history_output_formatter.py +2 -0
- {swarms-7.7.1.dist-info → swarms-7.7.3.dist-info}/METADATA +98 -263
- {swarms-7.7.1.dist-info → swarms-7.7.3.dist-info}/RECORD +29 -38
- swarms/schemas/agent_input_schema.py +0 -149
- swarms/structs/agents_available.py +0 -87
- swarms/structs/async_workflow.py +0 -818
- swarms/structs/graph_swarm.py +0 -612
- swarms/structs/octotools.py +0 -844
- swarms/structs/pulsar_swarm.py +0 -469
- swarms/structs/queue_swarm.py +0 -193
- swarms/structs/swarm_builder.py +0 -395
- swarms/structs/swarm_load_balancer.py +0 -344
- swarms/structs/swarm_output_type.py +0 -23
- swarms/structs/talk_hier.py +0 -729
- {swarms-7.7.1.dist-info → swarms-7.7.3.dist-info}/LICENSE +0 -0
- {swarms-7.7.1.dist-info → swarms-7.7.3.dist-info}/WHEEL +0 -0
- {swarms-7.7.1.dist-info → swarms-7.7.3.dist-info}/entry_points.txt +0 -0
swarms/structs/conversation.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import datetime
|
2
2
|
import json
|
3
|
-
from typing import Any, Optional, Union
|
3
|
+
from typing import Any, List, Optional, Union
|
4
4
|
|
5
5
|
import yaml
|
6
6
|
from swarms.structs.base_structure import BaseStructure
|
@@ -93,7 +93,7 @@ class Conversation(BaseStructure):
|
|
93
93
|
|
94
94
|
# If system prompt is not None, add it to the conversation history
|
95
95
|
if self.system_prompt is not None:
|
96
|
-
self.add("System
|
96
|
+
self.add("System", self.system_prompt)
|
97
97
|
|
98
98
|
if self.rules is not None:
|
99
99
|
self.add("User", rules)
|
@@ -118,8 +118,6 @@ class Conversation(BaseStructure):
|
|
118
118
|
role (str): The role of the speaker (e.g., 'User', 'System').
|
119
119
|
content (Union[str, dict, list]): The content of the message to be added.
|
120
120
|
"""
|
121
|
-
now = datetime.datetime.now()
|
122
|
-
now.strftime("%Y-%m-%d %H:%M:%S")
|
123
121
|
|
124
122
|
# Base message with role
|
125
123
|
message = {
|
@@ -131,7 +129,7 @@ class Conversation(BaseStructure):
|
|
131
129
|
message["content"] = content
|
132
130
|
elif self.time_enabled:
|
133
131
|
message["content"] = (
|
134
|
-
f"Time: {now.strftime('%Y-%m-%d %H:%M:%S')} \n {content}"
|
132
|
+
f"Time: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')} \n {content}"
|
135
133
|
)
|
136
134
|
else:
|
137
135
|
message["content"] = content
|
@@ -139,8 +137,19 @@ class Conversation(BaseStructure):
|
|
139
137
|
# Add the message to history immediately without waiting for token count
|
140
138
|
self.conversation_history.append(message)
|
141
139
|
|
140
|
+
if self.token_count is True:
|
141
|
+
self._count_tokens(content, message)
|
142
|
+
|
143
|
+
def add_multiple_messages(
|
144
|
+
self, roles: List[str], contents: List[Union[str, dict, list]]
|
145
|
+
):
|
146
|
+
for role, content in zip(roles, contents):
|
147
|
+
self.add(role, content)
|
148
|
+
|
149
|
+
def _count_tokens(self, content: str, message: dict):
|
142
150
|
# If token counting is enabled, do it in a separate thread
|
143
151
|
if self.token_count is True:
|
152
|
+
|
144
153
|
# Define a function to count tokens and update the message
|
145
154
|
def count_tokens_thread():
|
146
155
|
tokens = count_tokens(any_to_str(content))
|
@@ -159,9 +168,6 @@ class Conversation(BaseStructure):
|
|
159
168
|
True # Make thread terminate when main program exits
|
160
169
|
)
|
161
170
|
token_thread.start()
|
162
|
-
elif self.autosave:
|
163
|
-
# If token counting is disabled but autosave is enabled, save immediately
|
164
|
-
self.save_as_json(self.save_filepath)
|
165
171
|
|
166
172
|
def delete(self, index: str):
|
167
173
|
"""Delete a message from the conversation history.
|
@@ -314,53 +320,6 @@ class Conversation(BaseStructure):
|
|
314
320
|
if keyword in msg["content"]
|
315
321
|
]
|
316
322
|
|
317
|
-
def pretty_print_conversation(self, messages):
|
318
|
-
"""Pretty print the conversation history.
|
319
|
-
|
320
|
-
Args:
|
321
|
-
messages (list): List of messages to print.
|
322
|
-
"""
|
323
|
-
role_to_color = {
|
324
|
-
"system": "red",
|
325
|
-
"user": "green",
|
326
|
-
"assistant": "blue",
|
327
|
-
"tool": "magenta",
|
328
|
-
}
|
329
|
-
|
330
|
-
for message in messages:
|
331
|
-
if message["role"] == "system":
|
332
|
-
formatter.print_panel(
|
333
|
-
f"system: {message['content']}\n",
|
334
|
-
role_to_color[message["role"]],
|
335
|
-
)
|
336
|
-
elif message["role"] == "user":
|
337
|
-
formatter.print_panel(
|
338
|
-
f"user: {message['content']}\n",
|
339
|
-
role_to_color[message["role"]],
|
340
|
-
)
|
341
|
-
elif message["role"] == "assistant" and message.get(
|
342
|
-
"function_call"
|
343
|
-
):
|
344
|
-
formatter.print_panel(
|
345
|
-
f"assistant: {message['function_call']}\n",
|
346
|
-
role_to_color[message["role"]],
|
347
|
-
)
|
348
|
-
elif message["role"] == "assistant" and not message.get(
|
349
|
-
"function_call"
|
350
|
-
):
|
351
|
-
formatter.print_panel(
|
352
|
-
f"assistant: {message['content']}\n",
|
353
|
-
role_to_color[message["role"]],
|
354
|
-
)
|
355
|
-
elif message["role"] == "tool":
|
356
|
-
formatter.print_panel(
|
357
|
-
(
|
358
|
-
f"function ({message['name']}):"
|
359
|
-
f" {message['content']}\n"
|
360
|
-
),
|
361
|
-
role_to_color[message["role"]],
|
362
|
-
)
|
363
|
-
|
364
323
|
def truncate_memory_with_tokenizer(self):
|
365
324
|
"""
|
366
325
|
Truncates the conversation history based on the total number of tokens using a tokenizer.
|
@@ -540,11 +499,19 @@ class Conversation(BaseStructure):
|
|
540
499
|
"""
|
541
500
|
return "\n".join(
|
542
501
|
[
|
543
|
-
f"{msg['
|
502
|
+
f"{msg['content']}"
|
544
503
|
for msg in self.conversation_history[2:]
|
545
504
|
]
|
546
505
|
)
|
547
506
|
|
507
|
+
def batch_add(self, messages: List[dict]):
|
508
|
+
"""Batch add messages to the conversation history.
|
509
|
+
|
510
|
+
Args:
|
511
|
+
messages (List[dict]): List of messages to add.
|
512
|
+
"""
|
513
|
+
self.conversation_history.extend(messages)
|
514
|
+
|
548
515
|
|
549
516
|
# # Example usage
|
550
517
|
# # conversation = Conversation()
|
@@ -1,4 +1,3 @@
|
|
1
|
-
from concurrent.futures import ThreadPoolExecutor
|
2
1
|
import json
|
3
2
|
import os
|
4
3
|
from typing import Any, List, Optional, Union, Dict
|
@@ -9,10 +8,15 @@ from swarms.structs.agent import Agent
|
|
9
8
|
from swarms.structs.base_swarm import BaseSwarm
|
10
9
|
from swarms.structs.conversation import Conversation
|
11
10
|
from swarms.structs.output_types import OutputType
|
11
|
+
from swarms.utils.any_to_str import any_to_str
|
12
12
|
from swarms.utils.formatter import formatter
|
13
13
|
|
14
14
|
from swarms.utils.function_caller_model import OpenAIFunctionCaller
|
15
15
|
from swarms.utils.loguru_logger import initialize_logger
|
16
|
+
from swarms.utils.history_output_formatter import (
|
17
|
+
history_output_formatter,
|
18
|
+
)
|
19
|
+
from swarms.structs.ma_utils import list_all_agents
|
16
20
|
|
17
21
|
logger = initialize_logger(log_folder="hierarchical_swarm")
|
18
22
|
|
@@ -48,9 +52,6 @@ class SwarmSpec(BaseModel):
|
|
48
52
|
|
49
53
|
|
50
54
|
HIEARCHICAL_SWARM_SYSTEM_PROMPT = """
|
51
|
-
Below is a comprehensive production-grade hierarchical agent director prompt that is designed to break down orders, distribute tasks, and select the best worker agents to achieve the overall objectives. This prompt follows the schematic provided by the HierarchicalOrder and SwarmSpec classes and is composed of nearly 2,000 words. You can use this as your system prompt for the director agent in a multi-agent swarm system.
|
52
|
-
|
53
|
-
---
|
54
55
|
|
55
56
|
**SYSTEM PROMPT: HIERARCHICAL AGENT DIRECTOR**
|
56
57
|
|
@@ -211,6 +212,27 @@ Remember: the success of the swarm depends on your ability to manage complexity,
|
|
211
212
|
"""
|
212
213
|
|
213
214
|
|
215
|
+
class TeamUnit(BaseModel):
|
216
|
+
"""Represents a team within a department."""
|
217
|
+
|
218
|
+
name: Optional[str] = Field(
|
219
|
+
None, description="The name of the team."
|
220
|
+
)
|
221
|
+
description: Optional[str] = Field(
|
222
|
+
None, description="A brief description of the team's purpose."
|
223
|
+
)
|
224
|
+
agents: Optional[List[Union[Agent, Any]]] = Field(
|
225
|
+
None,
|
226
|
+
description="A list of agents that are part of the team.",
|
227
|
+
)
|
228
|
+
team_leader: Optional[Union[Agent, Any]] = Field(
|
229
|
+
None, description="The team leader of the team."
|
230
|
+
)
|
231
|
+
|
232
|
+
class Config:
|
233
|
+
arbitrary_types_allowed = True
|
234
|
+
|
235
|
+
|
214
236
|
class HierarchicalSwarm(BaseSwarm):
|
215
237
|
"""
|
216
238
|
_Representer a hierarchical swarm of agents, with a director that orchestrates tasks among the agents.
|
@@ -230,8 +252,9 @@ class HierarchicalSwarm(BaseSwarm):
|
|
230
252
|
agents: List[Union[Agent, Any]] = None,
|
231
253
|
max_loops: int = 1,
|
232
254
|
output_type: OutputType = "dict",
|
233
|
-
return_all_history: bool = False,
|
234
255
|
director_model_name: str = "gpt-4o",
|
256
|
+
teams: Optional[List[TeamUnit]] = None,
|
257
|
+
inter_agent_loops: int = 1,
|
235
258
|
*args,
|
236
259
|
**kwargs,
|
237
260
|
):
|
@@ -244,7 +267,6 @@ class HierarchicalSwarm(BaseSwarm):
|
|
244
267
|
:param agents: A list of agents within the swarm.
|
245
268
|
:param max_loops: The maximum number of feedback loops between the director and agents.
|
246
269
|
:param output_type: The format in which to return the output (dict, str, or list).
|
247
|
-
:param return_all_history: A flag indicating whether to return all conversation history.
|
248
270
|
"""
|
249
271
|
super().__init__(
|
250
272
|
name=name,
|
@@ -254,18 +276,46 @@ class HierarchicalSwarm(BaseSwarm):
|
|
254
276
|
self.director = director
|
255
277
|
self.agents = agents
|
256
278
|
self.max_loops = max_loops
|
257
|
-
self.return_all_history = return_all_history
|
258
279
|
self.output_type = output_type
|
259
280
|
self.director_model_name = director_model_name
|
281
|
+
self.teams = teams
|
282
|
+
self.inter_agent_loops = inter_agent_loops
|
283
|
+
|
260
284
|
self.conversation = Conversation(time_enabled=False)
|
261
285
|
self.current_loop = 0
|
262
286
|
self.agent_outputs = {} # Store agent outputs for each loop
|
263
287
|
|
264
288
|
self.add_name_and_description()
|
265
|
-
|
266
|
-
|
289
|
+
|
290
|
+
# Reliability checks
|
291
|
+
self.reliability_checks()
|
292
|
+
|
293
|
+
# Handle teams
|
294
|
+
self.handle_teams()
|
295
|
+
|
296
|
+
# List all agents
|
297
|
+
list_all_agents(self.agents, self.conversation, self.name)
|
298
|
+
|
267
299
|
self.director = self.setup_director()
|
268
300
|
|
301
|
+
def handle_teams(self):
|
302
|
+
if not self.teams:
|
303
|
+
return
|
304
|
+
|
305
|
+
# Use list comprehension for faster team processing
|
306
|
+
team_list = [team.model_dump() for team in self.teams]
|
307
|
+
|
308
|
+
# Use extend() instead of append() in a loop for better performance
|
309
|
+
self.agents.extend(
|
310
|
+
agent for team in team_list for agent in team["agents"]
|
311
|
+
)
|
312
|
+
|
313
|
+
# Add conversation message
|
314
|
+
self.conversation.add(
|
315
|
+
role="System",
|
316
|
+
content=f"Teams Available: {any_to_str(team_list)}",
|
317
|
+
)
|
318
|
+
|
269
319
|
def setup_director(self):
|
270
320
|
director = OpenAIFunctionCaller(
|
271
321
|
model_name=self.director_model_name,
|
@@ -278,12 +328,15 @@ class HierarchicalSwarm(BaseSwarm):
|
|
278
328
|
|
279
329
|
return director
|
280
330
|
|
281
|
-
def
|
331
|
+
def reliability_checks(self):
|
282
332
|
"""
|
283
333
|
Checks if there are any agents and a director set for the swarm.
|
284
334
|
Raises ValueError if either condition is not met.
|
285
335
|
"""
|
286
|
-
|
336
|
+
|
337
|
+
logger.info(f"🔍 CHECKING RELIABILITY OF SWARM: {self.name}")
|
338
|
+
|
339
|
+
if len(self.agents) == 0:
|
287
340
|
raise ValueError(
|
288
341
|
"No agents found in the swarm. At least one agent must be provided to create a hierarchical swarm."
|
289
342
|
)
|
@@ -301,9 +354,7 @@ class HierarchicalSwarm(BaseSwarm):
|
|
301
354
|
"Director not set for the swarm. A director agent is required to coordinate and orchestrate tasks among the agents."
|
302
355
|
)
|
303
356
|
|
304
|
-
logger.info(
|
305
|
-
"Reliability checks have passed. Swarm is ready to execute."
|
306
|
-
)
|
357
|
+
logger.info(f"🔍 RELIABILITY CHECKS PASSED: {self.name}")
|
307
358
|
|
308
359
|
def run_director(
|
309
360
|
self, task: str, loop_context: str = "", img: str = None
|
@@ -327,12 +378,6 @@ class HierarchicalSwarm(BaseSwarm):
|
|
327
378
|
# Run the director with the context
|
328
379
|
function_call = self.director.run(task=director_context)
|
329
380
|
|
330
|
-
print(function_call)
|
331
|
-
|
332
|
-
# function_call = self.check_director_agent_output(
|
333
|
-
# function_call
|
334
|
-
# )
|
335
|
-
|
336
381
|
formatter.print_panel(
|
337
382
|
f"Director Output (Loop {self.current_loop}/{self.max_loops}):\n{function_call}",
|
338
383
|
title="Director's Orders",
|
@@ -374,10 +419,6 @@ class HierarchicalSwarm(BaseSwarm):
|
|
374
419
|
logger.info(
|
375
420
|
f"Starting loop {self.current_loop}/{self.max_loops}"
|
376
421
|
)
|
377
|
-
formatter.print_panel(
|
378
|
-
f"⚡ EXECUTING LOOP {self.current_loop}/{self.max_loops}",
|
379
|
-
title="SWARM EXECUTION CYCLE",
|
380
|
-
)
|
381
422
|
|
382
423
|
# Get director's orders
|
383
424
|
swarm_spec = self.run_director(
|
@@ -416,7 +457,9 @@ class HierarchicalSwarm(BaseSwarm):
|
|
416
457
|
break
|
417
458
|
|
418
459
|
# Return the results in the specified format
|
419
|
-
return
|
460
|
+
return history_output_formatter(
|
461
|
+
self.conversation, self.output_type
|
462
|
+
)
|
420
463
|
|
421
464
|
def compile_loop_context(self, loop_number: int) -> str:
|
422
465
|
"""
|
@@ -437,74 +480,41 @@ class HierarchicalSwarm(BaseSwarm):
|
|
437
480
|
|
438
481
|
return context
|
439
482
|
|
440
|
-
def format_output(self) -> Union[str, Dict, List]:
|
441
|
-
"""
|
442
|
-
Formats the output according to the specified output_type.
|
443
|
-
|
444
|
-
:return: The formatted output.
|
445
|
-
"""
|
446
|
-
if self.output_type == "str" or self.return_all_history:
|
447
|
-
return self.conversation.get_str()
|
448
|
-
elif self.output_type == "dict":
|
449
|
-
return self.conversation.return_messages_as_dictionary()
|
450
|
-
elif self.output_type == "list":
|
451
|
-
return self.conversation.return_messages_as_list()
|
452
|
-
else:
|
453
|
-
return self.conversation.get_str()
|
454
|
-
|
455
483
|
def add_name_and_description(self):
|
456
484
|
"""
|
457
485
|
Adds the swarm's name and description to the conversation.
|
458
486
|
"""
|
459
487
|
self.conversation.add(
|
460
488
|
role="System",
|
461
|
-
content=f"
|
489
|
+
content=f"\n\nSwarm Name: {self.name}\n\nSwarm Description: {self.description}",
|
462
490
|
)
|
463
491
|
|
464
|
-
formatter.print_panel(
|
465
|
-
f"⚡ INITIALIZING HIERARCHICAL SWARM UNIT: {self.name}\n"
|
466
|
-
f"🔒 CLASSIFIED DIRECTIVE: {self.description}\n"
|
467
|
-
f"📡 STATUS: ACTIVATING SWARM PROTOCOLS\n"
|
468
|
-
f"🌐 ESTABLISHING SECURE AGENT MESH NETWORK\n"
|
469
|
-
f"⚠️ CYBERSECURITY MEASURES ENGAGED\n",
|
470
|
-
title="SWARM CORPORATION - HIERARCHICAL SWARMS ACTIVATING...",
|
471
|
-
)
|
472
|
-
|
473
|
-
def list_all_agents(self) -> str:
|
474
|
-
"""
|
475
|
-
Lists all agents available in the swarm.
|
476
|
-
|
477
|
-
:return: A string representation of all agents in the swarm.
|
478
|
-
"""
|
479
|
-
# Compile information about all agents
|
480
|
-
all_agents = "\n".join(
|
481
|
-
f"Agent: {agent.agent_name} || Description: {agent.description or agent.system_prompt}"
|
482
|
-
for agent in self.agents
|
483
|
-
)
|
484
|
-
|
485
|
-
# Add the agent information to the conversation
|
486
|
-
self.conversation.add(
|
487
|
-
role="System",
|
488
|
-
content=f"All Agents Available in the Swarm {self.name}:\n{all_agents}",
|
489
|
-
)
|
490
|
-
|
491
|
-
formatter.print_panel(
|
492
|
-
all_agents, title="All Agents Available in the Swarm"
|
493
|
-
)
|
494
|
-
|
495
|
-
return all_agents
|
496
|
-
|
497
492
|
def find_agent(self, name: str) -> Optional[Agent]:
|
498
493
|
"""
|
499
494
|
Finds an agent by its name within the swarm.
|
500
495
|
|
501
496
|
:param name: The name of the agent to find.
|
502
497
|
:return: The agent if found, otherwise None.
|
498
|
+
:raises: ValueError if agent is not found
|
503
499
|
"""
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
500
|
+
try:
|
501
|
+
# Fast path: use list comprehension for quick lookup
|
502
|
+
matching_agents = [
|
503
|
+
agent
|
504
|
+
for agent in self.agents
|
505
|
+
if agent.agent_name == name
|
506
|
+
]
|
507
|
+
|
508
|
+
if not matching_agents:
|
509
|
+
error_msg = f"Agent '{name}' not found in the swarm '{self.name}'"
|
510
|
+
logger.error(error_msg)
|
511
|
+
return None
|
512
|
+
|
513
|
+
return matching_agents[0]
|
514
|
+
|
515
|
+
except Exception as e:
|
516
|
+
logger.error(f"Error finding agent '{name}': {str(e)}")
|
517
|
+
return None
|
508
518
|
|
509
519
|
def run_agent(
|
510
520
|
self, agent_name: str, task: str, img: str = None
|
@@ -520,14 +530,6 @@ class HierarchicalSwarm(BaseSwarm):
|
|
520
530
|
try:
|
521
531
|
agent = self.find_agent(agent_name)
|
522
532
|
|
523
|
-
if not agent:
|
524
|
-
error_msg = f"Agent '{agent_name}' not found in the swarm '{self.name}'"
|
525
|
-
logger.error(error_msg)
|
526
|
-
self.conversation.add(
|
527
|
-
role="System", content=f"Error: {error_msg}"
|
528
|
-
)
|
529
|
-
return error_msg
|
530
|
-
|
531
533
|
# Prepare context for the agent
|
532
534
|
agent_context = (
|
533
535
|
f"Loop: {self.current_loop}/{self.max_loops}\n"
|
@@ -541,7 +543,7 @@ class HierarchicalSwarm(BaseSwarm):
|
|
541
543
|
title=f"Agent Task - Loop {self.current_loop}/{self.max_loops}",
|
542
544
|
)
|
543
545
|
|
544
|
-
out = agent.run(task=agent_context
|
546
|
+
out = agent.run(task=agent_context)
|
545
547
|
|
546
548
|
# Add the agent's output to the conversation
|
547
549
|
self.conversation.add(
|
@@ -560,9 +562,6 @@ class HierarchicalSwarm(BaseSwarm):
|
|
560
562
|
f"Error running agent '{agent_name}': {str(e)}"
|
561
563
|
)
|
562
564
|
logger.error(error_msg)
|
563
|
-
self.conversation.add(
|
564
|
-
role="System", content=f"Error: {error_msg}"
|
565
|
-
)
|
566
565
|
return error_msg
|
567
566
|
|
568
567
|
def parse_orders(self, swarm_spec: SwarmSpec) -> List[Any]:
|
@@ -590,9 +589,6 @@ class HierarchicalSwarm(BaseSwarm):
|
|
590
589
|
f"Error parsing and executing orders: {str(e)}"
|
591
590
|
)
|
592
591
|
logger.error(error_msg)
|
593
|
-
self.conversation.add(
|
594
|
-
role="System", content=f"Error: {error_msg}"
|
595
|
-
)
|
596
592
|
return [error_msg]
|
597
593
|
|
598
594
|
def parse_swarm_spec(
|
@@ -668,19 +664,14 @@ class HierarchicalSwarm(BaseSwarm):
|
|
668
664
|
:param swarm_spec: The SwarmSpec containing the goals, plan, and rules.
|
669
665
|
"""
|
670
666
|
try:
|
671
|
-
|
672
|
-
plan = swarm_spec.plan
|
673
|
-
rules = swarm_spec.rules
|
674
|
-
|
667
|
+
# Directly access and format attributes in one line
|
675
668
|
self.conversation.add(
|
676
669
|
role="Director",
|
677
|
-
content=f"Goals
|
670
|
+
content=f"Goals:\n{swarm_spec.goals}\n\nPlan:\n{swarm_spec.plan}\n\nRules:\n{swarm_spec.rules}",
|
678
671
|
)
|
679
672
|
except Exception as e:
|
680
|
-
|
681
|
-
|
682
|
-
self.conversation.add(
|
683
|
-
role="System", content=f"Error: {error_msg}"
|
673
|
+
logger.error(
|
674
|
+
f"Error adding goals and plan to conversation: {str(e)}"
|
684
675
|
)
|
685
676
|
|
686
677
|
def batch_run(
|
@@ -714,23 +705,3 @@ class HierarchicalSwarm(BaseSwarm):
|
|
714
705
|
"Output is neither a dictionary nor a string."
|
715
706
|
)
|
716
707
|
return {}
|
717
|
-
|
718
|
-
def concurrent_run(
|
719
|
-
self, tasks: List[str], img: str = None
|
720
|
-
) -> List[Union[str, Dict, List]]:
|
721
|
-
"""
|
722
|
-
Runs multiple tasks concurrently through the swarm.
|
723
|
-
|
724
|
-
:param tasks: The list of tasks to be executed.
|
725
|
-
:param img: Optional image to be used with the tasks.
|
726
|
-
:return: A list of outputs from each task execution.
|
727
|
-
"""
|
728
|
-
with ThreadPoolExecutor(max_workers=len(tasks)) as executor:
|
729
|
-
# Create a list of partial functions with the img parameter
|
730
|
-
task_functions = [(task, img) for task in tasks]
|
731
|
-
# Use starmap to unpack the arguments
|
732
|
-
return list(
|
733
|
-
executor.map(
|
734
|
-
lambda args: self.run(*args), task_functions
|
735
|
-
)
|
736
|
-
)
|
@@ -0,0 +1,96 @@
|
|
1
|
+
from swarms.structs.agent import Agent
|
2
|
+
from typing import List, Any, Optional, Union
|
3
|
+
import random
|
4
|
+
|
5
|
+
|
6
|
+
def list_all_agents(
|
7
|
+
agents: List[Union[Agent, Any]],
|
8
|
+
conversation: Optional[Any] = None,
|
9
|
+
name: str = "",
|
10
|
+
add_to_conversation: bool = False,
|
11
|
+
) -> str:
|
12
|
+
"""Lists all agents in a swarm and optionally adds them to a conversation.
|
13
|
+
|
14
|
+
This function compiles information about all agents in a swarm, including their names and descriptions.
|
15
|
+
It can optionally add this information to a conversation history.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
agents (List[Union[Agent, Any]]): List of agents to list information about
|
19
|
+
conversation (Any): Conversation object to optionally add agent information to
|
20
|
+
name (str): Name of the swarm/group of agents
|
21
|
+
add_to_conversation (bool, optional): Whether to add agent information to conversation. Defaults to False.
|
22
|
+
|
23
|
+
Returns:
|
24
|
+
str: Formatted string containing information about all agents
|
25
|
+
|
26
|
+
Example:
|
27
|
+
>>> agents = [agent1, agent2]
|
28
|
+
>>> conversation = Conversation()
|
29
|
+
>>> agent_info = list_all_agents(agents, conversation, "MySwarm")
|
30
|
+
>>> print(agent_info)
|
31
|
+
Total Agents: 2
|
32
|
+
|
33
|
+
Agent: Agent1
|
34
|
+
Description: First agent description...
|
35
|
+
|
36
|
+
Agent: Agent2
|
37
|
+
Description: Second agent description...
|
38
|
+
"""
|
39
|
+
|
40
|
+
# Compile information about all agents
|
41
|
+
total_agents = len(agents)
|
42
|
+
|
43
|
+
all_agents = f"Total Agents: {total_agents}\n\n" + "\n\n".join(
|
44
|
+
f"Agent: {agent.agent_name} \n\n Description: {agent.description or (agent.system_prompt[:50] + '...' if len(agent.system_prompt) > 50 else agent.system_prompt)}"
|
45
|
+
for agent in agents
|
46
|
+
)
|
47
|
+
|
48
|
+
if add_to_conversation:
|
49
|
+
# Add the agent information to the conversation
|
50
|
+
conversation.add(
|
51
|
+
role="System",
|
52
|
+
content=f"All Agents Available in the Swarm {name}:\n\n{all_agents}",
|
53
|
+
)
|
54
|
+
|
55
|
+
return all_agents
|
56
|
+
|
57
|
+
|
58
|
+
models = [
|
59
|
+
"anthropic/claude-3-sonnet-20240229",
|
60
|
+
"openai/gpt-4o-mini",
|
61
|
+
"openai/gpt-4o",
|
62
|
+
"deepseek/deepseek-chat",
|
63
|
+
"deepseek/deepseek-reasoner",
|
64
|
+
"groq/deepseek-r1-distill-qwen-32b",
|
65
|
+
"groq/deepseek-r1-distill-qwen-32b",
|
66
|
+
# "gemini/gemini-pro",
|
67
|
+
# "gemini/gemini-1.5-pro",
|
68
|
+
"openai/03-mini",
|
69
|
+
"o4-mini",
|
70
|
+
"o3",
|
71
|
+
"gpt-4.1",
|
72
|
+
"gpt-4.1-nano",
|
73
|
+
]
|
74
|
+
|
75
|
+
|
76
|
+
def set_random_models_for_agents(
|
77
|
+
agents: Union[List[Agent], Agent], model_names: List[str] = models
|
78
|
+
) -> Union[List[Agent], Agent]:
|
79
|
+
"""Sets random models for agents in the swarm.
|
80
|
+
|
81
|
+
Args:
|
82
|
+
agents (Union[List[Agent], Agent]): Either a single agent or a list of agents
|
83
|
+
model_names (List[str], optional): List of model names to choose from. Defaults to models.
|
84
|
+
|
85
|
+
Returns:
|
86
|
+
Union[List[Agent], Agent]: The agent(s) with randomly assigned models
|
87
|
+
"""
|
88
|
+
if isinstance(agents, list):
|
89
|
+
return [
|
90
|
+
setattr(agent, "model_name", random.choice(model_names))
|
91
|
+
or agent
|
92
|
+
for agent in agents
|
93
|
+
]
|
94
|
+
else:
|
95
|
+
setattr(agents, "model_name", random.choice(model_names))
|
96
|
+
return agents
|