hiearchical docs

pull/788/head
Kye Gomez 2 months ago
parent 07aee705bc
commit ecdb5690b1

@ -39,8 +39,8 @@ pip install swarms
| Method | Arguments | Returns | Description | | Method | Arguments | Returns | Description |
|--------|-----------|---------|-------------| |--------|-----------|---------|-------------|
| route_task | task: str | dict | Routes a single task to appropriate agent | | route_task | task: str | dict | Routes a single task to appropriate agent |
| batch_route | tasks: List[str] | List[dict] | Sequentially routes multiple tasks | | batch_run | tasks: List[str] | List[dict] | Sequentially routes multiple tasks |
| concurrent_batch_route | tasks: List[str] | List[dict] | Concurrently routes multiple tasks | | concurrent_batch_run | tasks: List[str] | List[dict] | Concurrently routes multiple tasks |
| query_ragent | task: str | str | Queries the research agent | | query_ragent | task: str | str | Queries the research agent |
| find_agent_in_list | agent_name: str | Optional[Agent] | Finds agent by name | | find_agent_in_list | agent_name: str | Optional[Agent] | Finds agent by name |
@ -111,7 +111,7 @@ try:
"Case 2: Patient symptoms...", "Case 2: Patient symptoms...",
"Case 3: Patient symptoms..." "Case 3: Patient symptoms..."
] ]
concurrent_results = healthcare_router.concurrent_batch_route(cases) concurrent_results = healthcare_router.concurrent_batch_run(cases)
except Exception as e: except Exception as e:
logger.error(f"Error in healthcare processing: {str(e)}") logger.error(f"Error in healthcare processing: {str(e)}")
@ -176,7 +176,7 @@ tasks = [
] ]
# Process tasks concurrently # Process tasks concurrently
results = finance_router.concurrent_batch_route(tasks) results = finance_router.concurrent_batch_run(tasks)
``` ```
### Legal Example ### Legal Example
@ -248,7 +248,7 @@ if result["execution"]["execution_time"] > 5.0:
```python ```python
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=5) as executor: with ThreadPoolExecutor(max_workers=5) as executor:
results = router.concurrent_batch_route(tasks) results = router.concurrent_batch_run(tasks)
``` ```
4. Regular agent validation: 4. Regular agent validation:
@ -264,7 +264,7 @@ for agent in router.agents.values():
- Group similar tasks together - Group similar tasks together
- Use concurrent_batch_route for independent tasks - Use concurrent_batch_run for independent tasks
- Monitor memory usage with large batches - Monitor memory usage with large batches

@ -1,9 +1,18 @@
# SwarmRouter Documentation # SwarmRouter Documentation
The `SwarmRouter` class is a flexible routing system designed to manage different types of swarms for task execution. It provides a unified interface to interact with various swarm types, including `AgentRearrange`, `MixtureOfAgents`, `SpreadSheetSwarm`, `SequentialWorkflow`, `ConcurrentWorkflow`, and finally `auto` which will dynamically select the most appropriate swarm for you by analyzing your name, description, and input task. We will be continuously adding more swarm architectures as we progress with new developments. The `SwarmRouter` class is a flexible routing system designed to manage different types of swarms for task execution. It provides a unified interface to interact with various swarm types, including `AgentRearrange`, `MixtureOfAgents`, `SpreadSheetSwarm`, `SequentialWorkflow`, `ConcurrentWorkflow`, `GroupChat`, `MultiAgentRouter`, `HierarchicalSwarm`, `MajorityVoting`, and `auto` which will dynamically select the most appropriate swarm for you by analyzing your task, name, and description. We will be continuously adding more swarm architectures as we progress with new developments.
## Classes ## Classes
### Document
A Pydantic model for representing document data.
| Attribute | Type | Description |
| --- | --- | --- |
| `file_path` | str | Path to the document file. |
| `data` | str | Content of the document. |
### SwarmLog ### SwarmLog
A Pydantic model for capturing log entries. A Pydantic model for capturing log entries.
@ -17,6 +26,7 @@ A Pydantic model for capturing log entries.
| `swarm_type` | SwarmType | Type of swarm associated with the log. | | `swarm_type` | SwarmType | Type of swarm associated with the log. |
| `task` | str | Task being performed (optional). | | `task` | str | Task being performed (optional). |
| `metadata` | Dict[str, Any] | Additional metadata (optional). | | `metadata` | Dict[str, Any] | Additional metadata (optional). |
| `documents` | List[Document] | List of documents associated with the log. |
### SwarmRouter ### SwarmRouter
@ -30,28 +40,61 @@ Main class for routing tasks to different swarm types.
| `agents` | List[Union[Agent, Callable]] | List of Agent objects or callable functions to be used in the swarm. | | `agents` | List[Union[Agent, Callable]] | List of Agent objects or callable functions to be used in the swarm. |
| `swarm_type` | SwarmType | Type of swarm to be used. | | `swarm_type` | SwarmType | Type of swarm to be used. |
| `autosave` | bool | Flag to enable/disable autosave. | | `autosave` | bool | Flag to enable/disable autosave. |
| `flow` | str | The flow of the swarm. | | `rearrange_flow` | str | The flow for the AgentRearrange swarm type. |
| `return_json` | bool | Flag to enable/disable returning the result in JSON format. | | `return_json` | bool | Flag to enable/disable returning the result in JSON format. |
| `auto_generate_prompts` | bool | Flag to enable/disable auto generation of prompts. | | `auto_generate_prompts` | bool | Flag to enable/disable auto generation of prompts. |
| `swarm` | Union[AgentRearrange, MixtureOfAgents, SpreadSheetSwarm, SequentialWorkflow, ConcurrentWorkflow, GroupChat, MultiAgentRouter] | Instantiated swarm object. | | `shared_memory_system` | Any | Shared memory system for agents. |
| `rules` | str | Rules to inject into every agent. |
| `documents` | List[str] | List of document file paths. |
| `output_type` | OutputType | Output format type (e.g., "string", "dict"). |
| `no_cluster_ops` | bool | Flag to disable cluster operations. |
| `speaker_fn` | callable | Speaker function for GroupChat swarm type. |
| `load_agents_from_csv` | bool | Flag to enable/disable loading agents from CSV. |
| `csv_file_path` | str | Path to the CSV file for loading agents. |
| `return_entire_history` | bool | Flag to enable/disable returning the entire conversation history. |
| `swarm` | Union[AgentRearrange, MixtureOfAgents, SpreadSheetSwarm, SequentialWorkflow, ConcurrentWorkflow, GroupChat, MultiAgentRouter, HierarchicalSwarm, MajorityVoting] | Instantiated swarm object. |
| `logs` | List[SwarmLog] | List of log entries captured during operations. | | `logs` | List[SwarmLog] | List of log entries captured during operations. |
#### Methods: #### Methods:
| Method | Parameters | Description | | Method | Parameters | Description |
| --- | --- | --- | | --- | --- | --- |
| `__init__` | `self, name: str, description: str, max_loops: int, agents: List[Union[Agent, Callable]], swarm_type: SwarmType, autosave: bool, flow: str, return_json: bool, auto_generate_prompts: bool, *args, **kwargs` | Initialize the SwarmRouter. | | `__init__` | `self, name: str = "swarm-router", description: str = "Routes your task to the desired swarm", max_loops: int = 1, agents: List[Union[Agent, Callable]] = [], swarm_type: SwarmType = "SequentialWorkflow", autosave: bool = False, rearrange_flow: str = None, return_json: bool = False, auto_generate_prompts: bool = False, shared_memory_system: Any = None, rules: str = None, documents: List[str] = [], output_type: OutputType = "dict", no_cluster_ops: bool = False, speaker_fn: callable = None, load_agents_from_csv: bool = False, csv_file_path: str = None, return_entire_history: bool = True, *args, **kwargs` | Initialize the SwarmRouter. |
| `activate_shared_memory` | `self` | Activate shared memory with all agents. |
| `handle_rules` | `self` | Inject rules to every agent. |
| `activate_ape` | `self` | Activate automatic prompt engineering for agents that support it. |
| `reliability_check` | `self` | Perform reliability checks on the SwarmRouter configuration. | | `reliability_check` | `self` | Perform reliability checks on the SwarmRouter configuration. |
| `_create_swarm` | `self, task: str = None, *args, **kwargs` | Create and return the specified swarm type or automatically match the best swarm type for a given task. | | `_create_swarm` | `self, task: str = None, *args, **kwargs` | Create and return the specified swarm type or automatically match the best swarm type for a given task. |
| `_log` | `self, level: str, message: str, task: str = "", metadata: Dict[str, Any] = None` | Create a log entry and add it to the logs list. | | `_log` | `self, level: str, message: str, task: str = "", metadata: Dict[str, Any] = None` | Create a log entry and add it to the logs list. |
| `run` | `self, task: str, *args, **kwargs` | Run the specified task on the selected or matched swarm. | | `_run` | `self, task: str, img: str, *args, **kwargs` | Dynamically run the specified task on the selected or matched swarm type. |
| `run` | `self, task: str, img: str = None, *args, **kwargs` | Execute a task on the selected swarm type. |
| `__call__` | `self, task: str, *args, **kwargs` | Make the SwarmRouter instance callable. |
| `batch_run` | `self, tasks: List[str], *args, **kwargs` | Execute a batch of tasks on the selected or matched swarm type. | | `batch_run` | `self, tasks: List[str], *args, **kwargs` | Execute a batch of tasks on the selected or matched swarm type. |
| `threaded_run` | `self, task: str, *args, **kwargs` | Execute a task on the selected or matched swarm type using threading. |
| `async_run` | `self, task: str, *args, **kwargs` | Execute a task on the selected or matched swarm type asynchronously. | | `async_run` | `self, task: str, *args, **kwargs` | Execute a task on the selected or matched swarm type asynchronously. |
| `get_logs` | `self` | Retrieve all logged entries. | | `get_logs` | `self` | Retrieve all logged entries. |
| `concurrent_run` | `self, task: str, *args, **kwargs` | Execute a task on the selected or matched swarm type concurrently. | | `concurrent_run` | `self, task: str, *args, **kwargs` | Execute a task on the selected or matched swarm type concurrently. |
| `concurrent_batch_run` | `self, tasks: List[str], *args, **kwargs` | Execute a batch of tasks on the selected or matched swarm type concurrently. | | `concurrent_batch_run` | `self, tasks: List[str], *args, **kwargs` | Execute a batch of tasks on the selected or matched swarm type concurrently. |
## Function: swarm_router
A convenience function to create and run a SwarmRouter instance.
| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | str | "swarm-router" | Name of the swarm router. |
| `description` | str | "Routes your task to the desired swarm" | Description of the router. |
| `max_loops` | int | 1 | Maximum number of execution loops. |
| `agents` | List[Union[Agent, Callable]] | [] | List of agents or callables. |
| `swarm_type` | SwarmType | "SequentialWorkflow" | Type of swarm to use. |
| `autosave` | bool | False | Whether to autosave results. |
| `flow` | str | None | Flow configuration. |
| `return_json` | bool | True | Whether to return results as JSON. |
| `auto_generate_prompts` | bool | False | Whether to auto-generate prompts. |
| `task` | str | None | Task to execute. |
| `rules` | str | None | Rules to inject into every agent. |
| `*args` | | | Additional positional arguments passed to SwarmRouter.run() |
| `**kwargs` | | | Additional keyword arguments passed to SwarmRouter.run() |
## Installation ## Installation
To use the SwarmRouter, first install the required dependencies: To use the SwarmRouter, first install the required dependencies:
@ -187,6 +230,62 @@ auto_router = SwarmRouter(
result = auto_router.run("Analyze and summarize the quarterly financial report") result = auto_router.run("Analyze and summarize the quarterly financial report")
``` ```
### Loading Agents from CSV
To load agents from a CSV file:
```python
csv_router = SwarmRouter(
name="CSVAgentRouter",
load_agents_from_csv=True,
csv_file_path="agents.csv",
swarm_type="SequentialWorkflow"
)
result = csv_router.run("Process the client data")
```
### Using Shared Memory System
To enable shared memory across agents:
```python
from swarms.memory import SemanticMemory
memory_system = SemanticMemory()
memory_router = SwarmRouter(
name="MemoryRouter",
agents=[agent1, agent2],
shared_memory_system=memory_system,
swarm_type="SequentialWorkflow"
)
result = memory_router.run("Analyze historical data and make predictions")
```
### Injecting Rules to All Agents
To inject common rules into all agents:
```python
rules = """
1. Always provide sources for your information
2. Check your calculations twice
3. Explain your reasoning clearly
4. Highlight uncertainties and assumptions
"""
rules_router = SwarmRouter(
name="RulesRouter",
agents=[agent1, agent2],
rules=rules,
swarm_type="SequentialWorkflow"
)
result = rules_router.run("Analyze the investment opportunity")
```
## Use Cases ## Use Cases
### AgentRearrange ### AgentRearrange
@ -200,7 +299,7 @@ rearrange_router = SwarmRouter(
max_loops=3, max_loops=3,
agents=[data_extractor, analyzer, summarizer], agents=[data_extractor, analyzer, summarizer],
swarm_type="AgentRearrange", swarm_type="AgentRearrange",
flow=f"{data_extractor.name} -> {analyzer.name} -> {summarizer.name}" rearrange_flow=f"{data_extractor.name} -> {analyzer.name} -> {summarizer.name}"
) )
result = rearrange_router.run("Analyze and summarize the quarterly financial report") result = rearrange_router.run("Analyze and summarize the quarterly financial report")
@ -215,7 +314,7 @@ mixture_router = SwarmRouter(
name="ExpertPanel", name="ExpertPanel",
description="Combine insights from various expert agents", description="Combine insights from various expert agents",
max_loops=1, max_loops=1,
agents=[financial_expert, market_analyst, tech_specialist], agents=[financial_expert, market_analyst, tech_specialist, aggregator],
swarm_type="MixtureOfAgents" swarm_type="MixtureOfAgents"
) )
@ -248,7 +347,8 @@ sequential_router = SwarmRouter(
description="Generate comprehensive reports sequentially", description="Generate comprehensive reports sequentially",
max_loops=1, max_loops=1,
agents=[data_extractor, analyzer, writer, reviewer], agents=[data_extractor, analyzer, writer, reviewer],
swarm_type="SequentialWorkflow" swarm_type="SequentialWorkflow",
return_entire_history=True
) )
result = sequential_router.run("Create a due diligence report for Project Alpha") result = sequential_router.run("Create a due diligence report for Project Alpha")
@ -264,51 +364,85 @@ concurrent_router = SwarmRouter(
description="Analyze multiple data sources concurrently", description="Analyze multiple data sources concurrently",
max_loops=1, max_loops=1,
agents=[financial_analyst, market_researcher, competitor_analyst], agents=[financial_analyst, market_researcher, competitor_analyst],
swarm_type="ConcurrentWorkflow" swarm_type="ConcurrentWorkflow",
output_type="string"
) )
result = concurrent_router.run("Conduct a comprehensive market analysis for Product X") result = concurrent_router.run("Conduct a comprehensive market analysis for Product X")
``` ```
### GroupChat ### GroupChat
Use Case: Simulating a group chat with multiple agents. Use Case: Simulating a group discussion with multiple agents.
```python ```python
group_chat_router = SwarmRouter( group_chat_router = SwarmRouter(
name="GroupChat", name="GroupChat",
description="Simulate a group chat with multiple agents", description="Simulate a group discussion with multiple agents",
max_loops=1, max_loops=10,
agents=[financial_analyst, market_researcher, competitor_analyst], agents=[financial_analyst, market_researcher, competitor_analyst],
swarm_type="GroupChat" swarm_type="GroupChat",
speaker_fn=custom_speaker_function
) )
result = group_chat_router.run("Conduct a comprehensive market analysis for Product X") result = group_chat_router.run("Discuss the pros and cons of expanding into the Asian market")
``` ```
### MultiAgentRouter ### MultiAgentRouter
Use Case: Simulating a group chat with multiple agents. Use Case: Routing tasks to the most appropriate agent.
```python ```python
multi_agent_router = SwarmRouter( multi_agent_router = SwarmRouter(
name="MultiAgentRouter", name="MultiAgentRouter",
description="Simulate a group chat with multiple agents", description="Route tasks to specialized agents",
max_loops=1, max_loops=1,
agents=[financial_analyst, market_researcher, competitor_analyst], agents=[financial_analyst, market_researcher, competitor_analyst],
swarm_type="MultiAgentRouter" swarm_type="MultiAgentRouter",
shared_memory_system=memory_system
) )
result = multi_agent_router.run("Conduct a comprehensive market analysis for Product X") result = multi_agent_router.run("Analyze the competitive landscape for our new product")
``` ```
### HierarchicalSwarm
Use Case: Creating a hierarchical structure of agents with a director.
```python
hierarchical_router = SwarmRouter(
name="HierarchicalSwarm",
description="Hierarchical organization of agents with a director",
max_loops=3,
agents=[director, analyst1, analyst2, researcher],
swarm_type="HiearchicalSwarm",
return_all_history=True
)
result = hierarchical_router.run("Develop a comprehensive market entry strategy")
```
### MajorityVoting
Use Case: Using consensus among multiple agents for decision-making.
```python
voting_router = SwarmRouter(
name="MajorityVoting",
description="Make decisions using consensus among agents",
max_loops=1,
agents=[analyst1, analyst2, analyst3, consensus_agent],
swarm_type="MajorityVoting"
)
result = voting_router.run("Should we invest in Company X based on the available data?")
```
### Auto Select (Experimental) ### Auto Select (Experimental)
Autonomously selects the right swarm by conducting vector search on your input task or name or description or all 3. Autonomously selects the right swarm by conducting vector search on your input task or name or description or all 3.
```python ```python
concurrent_router = SwarmRouter( auto_router = SwarmRouter(
name="MultiSourceAnalyzer", name="MultiSourceAnalyzer",
description="Analyze multiple data sources concurrently", description="Analyze multiple data sources concurrently",
max_loops=1, max_loops=1,
@ -316,26 +450,33 @@ concurrent_router = SwarmRouter(
swarm_type="auto" # Set this to 'auto' for it to auto select your swarm. It's match words like concurrently multiple -> "ConcurrentWorkflow" swarm_type="auto" # Set this to 'auto' for it to auto select your swarm. It's match words like concurrently multiple -> "ConcurrentWorkflow"
) )
result = concurrent_router.run("Conduct a comprehensive market analysis for Product X") result = auto_router.run("Conduct a comprehensive market analysis for Product X")
``` ```
## Advanced Features ## Advanced Features
### Batch Processing ### Processing Documents
To process multiple tasks in a batch: To process documents with the SwarmRouter:
```python ```python
tasks = ["Analyze Q1 report", "Summarize competitor landscape", "Evaluate market trends"] document_router = SwarmRouter(
results = router.batch_run(tasks) name="DocumentProcessor",
agents=[document_analyzer, summarizer],
documents=["report.pdf", "contract.docx", "data.csv"],
swarm_type="SequentialWorkflow"
)
result = document_router.run("Extract key information from the provided documents")
``` ```
### Threaded Execution ### Batch Processing
For non-blocking execution of a task: To process multiple tasks in a batch:
```python ```python
result = router.threaded_run("Perform complex analysis") tasks = ["Analyze Q1 report", "Summarize competitor landscape", "Evaluate market trends"]
results = router.batch_run(tasks)
``` ```
### Asynchronous Execution ### Asynchronous Execution
@ -363,15 +504,63 @@ tasks = ["Task 1", "Task 2", "Task 3"]
results = router.concurrent_batch_run(tasks) results = router.concurrent_batch_run(tasks)
``` ```
### Using the SwarmRouter as a Callable
You can use the SwarmRouter instance directly as a callable:
```python
router = SwarmRouter(
name="CallableRouter",
agents=[agent1, agent2],
swarm_type="SequentialWorkflow"
)
result = router("Analyze the market data") # Equivalent to router.run("Analyze the market data")
```
### Using the swarm_router Function
For quick one-off tasks, you can use the swarm_router function:
```python
from swarms import swarm_router
result = swarm_router(
name="QuickRouter",
agents=[agent1, agent2],
swarm_type="ConcurrentWorkflow",
task="Analyze the quarterly report"
)
```
## Best Practices ## Best Practices
1. Choose the appropriate swarm type based on your task requirements. 1. Choose the appropriate swarm type based on your task requirements.
2. Provide clear and specific tasks to the swarm for optimal results. 2. Provide clear and specific tasks to the swarm for optimal results.
3. Regularly review logs to monitor performance and identify potential issues. 3. Regularly review logs to monitor performance and identify potential issues.
4. Use descriptive names and descriptions for your SwarmRouter and agents. 4. Use descriptive names and descriptions for your SwarmRouter and agents.
5. Implement proper error handling in your application code. 5. Implement proper error handling in your application code.
6. Consider the nature of your tasks when choosing a swarm type (e.g., use ConcurrentWorkflow for tasks that can be parallelized). 6. Consider the nature of your tasks when choosing a swarm type (e.g., use ConcurrentWorkflow for tasks that can be parallelized).
7. Optimize your agents' prompts and configurations for best performance within the swarm. 7. Optimize your agents' prompts and configurations for best performance within the swarm.
8. Utilize the automatic swarm type selection feature for tasks where the optimal swarm type is not immediately clear. 8. Utilize the automatic swarm type selection feature for tasks where the optimal swarm type is not immediately clear.
9. Take advantage of batch processing and concurrent execution for handling multiple tasks efficiently. 9. Take advantage of batch processing and concurrent execution for handling multiple tasks efficiently.
10. Use the reliability check feature to ensure your SwarmRouter is properly configured before running tasks. 10. Use the reliability check feature to ensure your SwarmRouter is properly configured before running tasks.
11. Consider using shared memory systems when agents need to share context or knowledge.
12. Inject common rules when you want consistent behavior across all agents.
13. Use the appropriate output type (string, dict, etc.) based on how you plan to process the results.
14. When working with large documents, provide file paths instead of loading content into memory.
15. For complex agent interactions, use the GroupChat or HierarchicalSwarm types to facilitate structured communication.

@ -0,0 +1,48 @@
from swarms import Agent
from swarms.structs.hiearchical_swarm import HierarchicalSwarm
# Initialize agents for a $50B portfolio analysis
agents = [
Agent(
agent_name="Sector-Financial-Analyst",
agent_description="Senior financial analyst at BlackRock.",
system_prompt="You are a financial analyst tasked with optimizing asset allocations for a $50B portfolio. Provide clear, quantitative recommendations for each sector.",
max_loops=1,
model_name="groq/deepseek-r1-distill-qwen-32b",
max_tokens=3000,
),
Agent(
agent_name="Sector-Risk-Analyst",
agent_description="Expert risk management analyst.",
system_prompt="You are a risk analyst responsible for advising on risk allocation within a $50B portfolio. Provide detailed insights on risk exposures for each sector.",
max_loops=1,
model_name="groq/deepseek-r1-distill-qwen-32b",
max_tokens=3000,
),
Agent(
agent_name="Tech-Sector-Analyst",
agent_description="Technology sector analyst.",
system_prompt="You are a tech sector analyst focused on capital and risk allocations. Provide data-backed insights for the tech sector.",
max_loops=1,
model_name="groq/deepseek-r1-distill-qwen-32b",
max_tokens=3000,
),
]
# Create hierarchical swarm system
majority_voting = HierarchicalSwarm(
name="Sector-Investment-Advisory-System",
description="System for sector analysis and optimal allocations.",
agents=agents,
# director=director_agent,
max_loops=1,
output_type="dict",
)
# Run the analysis
result = majority_voting.run(
task="Evaluate market sectors and determine optimal allocation for a $50B portfolio. Include a detailed table of allocations, risk assessments, and a consolidated strategy."
)
print(result)

@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry] [tool.poetry]
name = "swarms" name = "swarms"
version = "7.4.6" version = "7.4.8"
description = "Swarms - TGSC" description = "Swarms - TGSC"
license = "MIT" license = "MIT"
authors = ["Kye Gomez <kye@apac.ai>"] authors = ["Kye Gomez <kye@apac.ai>"]

@ -22,7 +22,12 @@ agents = [
), ),
] ]
router = SwarmRouter(agents=agents, swarm_type="SequentialWorkflow", output_type="dict", return_entire_history=False) router = SwarmRouter(
agents=agents,
swarm_type="SequentialWorkflow",
output_type="dict",
return_entire_history=False,
)
output = router.run("How are you doing?") output = router.run("How are you doing?")

@ -1,13 +1,17 @@
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from typing import Any, List, Optional, Union import json
import os
from typing import Any, List, Optional, Union, Dict
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from swarms.structs.agent import Agent from swarms.structs.agent import Agent
from swarms.structs.base_swarm import BaseSwarm from swarms.structs.base_swarm import BaseSwarm
from swarms.structs.conversation import Conversation from swarms.structs.conversation import Conversation
from swarms.structs.output_type import OutputType
from swarms.utils.formatter import formatter from swarms.utils.formatter import formatter
from swarms.utils.function_caller_model import OpenAIFunctionCaller
from swarms.utils.loguru_logger import initialize_logger from swarms.utils.loguru_logger import initialize_logger
logger = initialize_logger(log_folder="hierarchical_swarm") logger = initialize_logger(log_folder="hierarchical_swarm")
@ -43,9 +47,179 @@ class SwarmSpec(BaseModel):
) )
HIEARCHICAL_SWARM_SYSTEM_PROMPT = """
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.
---
**SYSTEM PROMPT: HIERARCHICAL AGENT DIRECTOR**
**I. Introduction and Context**
You are the Hierarchical Agent Director the central orchestrator responsible for breaking down overarching goals into granular tasks and intelligently assigning these tasks to the most suitable worker agents within the swarm. Your objective is to maximize the overall performance of the system by ensuring that every agent is given a task aligned with its strengths, expertise, and available resources.
---
**II. Core Operating Principles**
1. **Goal Alignment and Context Awareness:**
- **Overarching Goals:** Begin every operation by clearly reviewing the swarms overall goals. Understand the mission statement and ensure that every assigned task contributes directly to these objectives.
- **Context Sensitivity:** Evaluate the context provided in the plan and rules sections of the SwarmSpec. These instructions provide the operational boundaries and behavioral constraints within which you must work.
2. **Task Decomposition and Prioritization:**
- **Hierarchical Decomposition:** Break down the overarching plan into granular tasks. For each major objective, identify subtasks that logically lead toward the goal. This decomposition should be structured in a hierarchical manner, where complex tasks are subdivided into simpler, manageable tasks.
- **Task Priority:** Assign a priority level to each task based on urgency, complexity, and impact. Ensure that high-priority tasks receive immediate attention and that resources are allocated accordingly.
3. **Agent Profiling and Matching:**
- **Agent Specialization:** Maintain an up-to-date registry of worker agents, each with defined capabilities, specializations, and performance histories. When assigning tasks, consider the specific strengths of each agent.
- **Performance Metrics:** Utilize historical performance metrics and available workload data to select the most suitable agent for each task. If an agent is overburdened or has lower efficiency on a specific type of task, consider alternate agents.
- **Dynamic Reassignment:** Allow for real-time reassignments based on the evolving state of the system. If an agent encounters issues or delays, reassign tasks to ensure continuity.
4. **Adherence to Rules and Safety Protocols:**
- **Operational Rules:** Every task must be executed in strict compliance with the rules provided in the SwarmSpec. These rules are non-negotiable and serve as the ethical and operational foundation for all decisions.
- **Fail-Safe Mechanisms:** Incorporate safety protocols that monitor agent performance and task progress. If an anomaly or failure is detected, trigger a reallocation of tasks or an escalation process to mitigate risks.
- **Auditability:** Ensure that every decision and task assignment is logged for auditing purposes. This enables traceability and accountability in system operations.
---
**III. Detailed Task Assignment Process**
1. **Input Analysis and Context Setting:**
- **Goal Review:** Begin by carefully reading the goals string within the SwarmSpec. This is your north star for every decision you make.
- **Plan Comprehension:** Analyze the plan string for detailed instructions. Identify key milestones, deliverables, and dependencies within the roadmap.
- **Rule Enforcement:** Read through the rules string to understand the non-negotiable guidelines that govern task assignments. Consider potential edge cases and ensure that your task breakdown respects these boundaries.
2. **Task Breakdown and Subtask Identification:**
- **Decompose the Plan:** Using a systematic approach, decompose the overall plan into discrete tasks. For each major phase, identify the specific actions required. Document dependencies among tasks, and note any potential bottlenecks.
- **Task Granularity:** Ensure that tasks are broken down to a level of granularity that makes them actionable. Overly broad tasks must be subdivided further until they can be executed by an individual worker agent.
- **Inter-Agent Dependencies:** Clearly specify any dependencies that exist between tasks assigned to different agents. This ensures that the workflow remains coherent and that agents collaborate effectively.
3. **Agent Selection Strategy:**
- **Capabilities Matching:** For each identified task, analyze the capabilities required. Compare these against the registry of available worker agents. Factor in specialized skills, past performance, current load, and any situational awareness that might influence the assignment.
- **Task Suitability:** Consider both the technical requirements of the task and any contextual subtleties noted in the plan and rules. Ensure that the chosen agent has a proven track record with similar tasks.
- **Adaptive Assignments:** Build in flexibility to allow for agent reassignment in real-time. Monitor ongoing tasks and reallocate resources as needed, especially if an agent experiences unexpected delays or issues.
4. **Constructing Hierarchical Orders:**
- **Order Creation:** For each task, generate a HierarchicalOrder object that specifies the agents name and the task details. The task description should be unambiguous and detailed enough to guide the agents execution without requiring additional clarification.
- **Order Validation:** Prior to finalizing each order, cross-reference the task requirements against the agents profile. Validate that the order adheres to the rules of the SwarmSpec and that it fits within the broader operational context.
- **Order Prioritization:** Clearly mark high-priority tasks so that agents understand the urgency. In cases where multiple tasks are assigned to a single agent, provide a sequence or ranking to ensure proper execution order.
5. **Feedback and Iteration:**
- **Real-Time Monitoring:** Establish feedback loops with worker agents to track the progress of each task. This allows for early detection of issues and facilitates dynamic reassignment if necessary.
- **Continuous Improvement:** Regularly review task execution data and agent performance metrics. Use this feedback to refine the task decomposition and agent selection process in future iterations.
---
**IV. Execution Guidelines and Best Practices**
1. **Communication Clarity:**
- Use clear, concise language in every HierarchicalOrder. Avoid ambiguity by detailing both the what and the how of the task.
- Provide contextual notes when necessary, especially if the task involves dependencies or coordination with other agents.
2. **Documentation and Traceability:**
- Record every task assignment in a centralized log. This log should include the agents name, task details, time of assignment, and any follow-up actions taken.
- Ensure that the entire decision-making process is documented. This aids in post-operation analysis and helps in refining future assignments.
3. **Error Handling and Escalation:**
- If an agent is unable to complete a task due to unforeseen challenges, immediately trigger the escalation protocol. Reassign the task to a qualified backup agent while flagging the incident for further review.
- Document all deviations from the plan along with the corrective measures taken. This helps in identifying recurring issues and improving the systems robustness.
4. **Ethical and Operational Compliance:**
- Adhere strictly to the rules outlined in the SwarmSpec. Any action that violates these rules is unacceptable, regardless of the potential gains in efficiency.
- Maintain transparency in all operations. If a decision or task assignment is questioned, be prepared to justify the choice based on objective criteria such as agent capability, historical performance, and task requirements.
5. **Iterative Refinement:**
- After the completion of each mission cycle, perform a thorough debriefing. Analyze the success and shortcomings of the task assignments.
- Use these insights to iterate on your hierarchical ordering process. Update agent profiles and adjust your selection strategies based on real-world performance data.
---
**V. Exemplary Use Case and Order Breakdown**
Imagine that the swarms overarching goal is to perform a comprehensive analysis of market trends for a large-scale enterprise. The goals field might read as follows:
*To conduct an in-depth market analysis that identifies emerging trends, competitive intelligence, and actionable insights for strategic decision-making.*
The plan could outline a multi-phase approach:
- Phase 1: Data Collection and Preprocessing
- Phase 2: Trend Analysis and Pattern Recognition
- Phase 3: Report Generation and Presentation of Findings
The rules may specify that all data processing must comply with privacy regulations, and that results must be validated against multiple data sources.
For Phase 1, the Director breaks down tasks such as Identify data sources, Extract relevant market data, and Preprocess raw datasets. For each task, the director selects agents with expertise in data mining, natural language processing, and data cleaning. A series of HierarchicalOrder objects are created, for example:
1. HierarchicalOrder for Data Collection:
- **agent_name:** DataMiner_Agent
- **task:** Access external APIs and scrape structured market data from approved financial news sources.
2. HierarchicalOrder for Data Preprocessing:
- **agent_name:** Preprocess_Expert
- **task:** Clean and normalize the collected datasets, ensuring removal of duplicate records and compliance with data privacy rules.
3. HierarchicalOrder for Preliminary Trend Analysis:
- **agent_name:** TrendAnalyst_Pro
- **task:** Apply statistical models to identify initial trends and anomalies in the market data.
Each order is meticulously validated against the rules provided in the SwarmSpec and prioritized according to the project timeline. The director ensures that if any of these tasks are delayed, backup agents are identified and the orders are reissued in real time.
---
**VI. Detailed Hierarchical Order Construction and Validation**
1. **Order Structuring:**
- Begin by constructing a template that includes placeholders for the agents name and a detailed description of the task.
- Ensure that the task description is unambiguous. For instance, rather than stating analyze data, specify analyze the temporal patterns in consumer sentiment from Q1 and Q2, and identify correlations with economic indicators.
2. **Validation Workflow:**
- Prior to dispatch, each HierarchicalOrder must undergo a validation check. This includes verifying that the agents capabilities align with the task, that the task does not conflict with any other orders, and that the task is fully compliant with the operational rules.
- If a validation error is detected, the order should be revised. The director may consult with relevant experts or consult historical data to refine the tasks description and ensure it is actionable.
3. **Order Finalization:**
- Once validated, finalize the HierarchicalOrder and insert it into the orders list of the SwarmSpec.
- Dispatch the order immediately, ensuring that the worker agent acknowledges receipt and provides an estimated time of completion.
- Continuously monitor the progress, and if any agents status changes (e.g., they become overloaded or unresponsive), trigger a reallocation process based on the predefined agent selection strategy.
---
**VII. Continuous Monitoring, Feedback, and Dynamic Reassignment**
1. **Real-Time Status Tracking:**
- Use real-time dashboards to monitor each agents progress on the assigned tasks.
- Update the hierarchical ordering system dynamically if a task is delayed, incomplete, or requires additional resources.
2. **Feedback Loop Integration:**
- Each worker agent must provide periodic status updates, including intermediate results, encountered issues, and resource usage.
- The director uses these updates to adjust task priorities and reassign tasks if necessary. This dynamic feedback loop ensures the overall swarm remains agile and responsive.
3. **Performance Metrics and Analysis:**
- At the conclusion of every mission, aggregate performance metrics and conduct a thorough review of task efficiency.
- Identify any tasks that repeatedly underperform or cause delays, and adjust the agent selection criteria accordingly for future orders.
- Document lessons learned and integrate them into the operating procedures for continuous improvement.
---
**VIII. Final Directives and Implementation Mandate**
As the Hierarchical Agent Director, your mandate is clear: you must orchestrate the operation with precision, clarity, and unwavering adherence to the overarching goals and rules specified in the SwarmSpec. You are empowered to deconstruct complex objectives into manageable tasks and to assign these tasks to the worker agents best equipped to execute them.
Your decisions must always be data-driven, relying on agent profiles, historical performance, and real-time feedback. Ensure that every HierarchicalOrder is constructed with a clear task description and assigned to an agent whose expertise aligns perfectly with the requirements. Maintain strict compliance with all operational rules, and be ready to adapt dynamically as conditions change.
This production-grade prompt is your operational blueprint. Utilize it to break down orders efficiently, assign tasks intelligently, and steer the swarm toward achieving the defined goals with optimal efficiency and reliability. Every decision you make should reflect a deep commitment to excellence, safety, and operational integrity.
Remember: the success of the swarm depends on your ability to manage complexity, maintain transparency, and dynamically adapt to the evolving operational landscape. Execute your role with diligence, precision, and a relentless focus on performance excellence.
"""
class HierarchicalSwarm(BaseSwarm): class HierarchicalSwarm(BaseSwarm):
""" """
Represents a hierarchical swarm of agents, with a director that orchestrates tasks among the agents. _Representer a hierarchical swarm of agents, with a director that orchestrates tasks among the agents.
The workflow follows a hierarchical pattern:
1. Task is received and sent to the director
2. Director creates a plan and distributes orders to agents
3. Agents execute tasks and report back to the director
4. Director evaluates results and issues new orders if needed (up to max_loops)
5. All context and conversation history is preserved throughout the process
""" """
def __init__( def __init__(
@ -55,7 +229,9 @@ class HierarchicalSwarm(BaseSwarm):
director: Optional[Union[Agent, Any]] = None, director: Optional[Union[Agent, Any]] = None,
agents: List[Union[Agent, Any]] = None, agents: List[Union[Agent, Any]] = None,
max_loops: int = 1, max_loops: int = 1,
output_type: OutputType = "dict",
return_all_history: bool = False, return_all_history: bool = False,
director_model_name: str = "gpt-4o",
*args, *args,
**kwargs, **kwargs,
): ):
@ -67,6 +243,7 @@ class HierarchicalSwarm(BaseSwarm):
:param director: The director agent that orchestrates tasks. :param director: The director agent that orchestrates tasks.
:param agents: A list of agents within the swarm. :param agents: A list of agents within the swarm.
:param max_loops: The maximum number of feedback loops between the director and agents. :param max_loops: The maximum number of feedback loops between the director and agents.
:param output_type: The format in which to return the output (dict, str, or list).
:param return_all_history: A flag indicating whether to return all conversation history. :param return_all_history: A flag indicating whether to return all conversation history.
""" """
super().__init__( super().__init__(
@ -78,13 +255,28 @@ class HierarchicalSwarm(BaseSwarm):
self.agents = agents self.agents = agents
self.max_loops = max_loops self.max_loops = max_loops
self.return_all_history = return_all_history self.return_all_history = return_all_history
self.output_type = output_type
self.director_model_name = director_model_name
self.conversation = Conversation(time_enabled=True) self.conversation = Conversation(time_enabled=True)
self.current_loop = 0
self.agent_outputs = {} # Store agent outputs for each loop
self.add_name_and_description() self.add_name_and_description()
self.check_agents() self.check_agents()
self.list_all_agents() self.list_all_agents()
self.director = self.setup_director()
def setup_director(self):
director = OpenAIFunctionCaller(
model_name=self.director_model_name,
system_prompt=HIEARCHICAL_SWARM_SYSTEM_PROMPT,
api_key=os.getenv("OPENAI_API_KEY"),
temperature=0.5,
base_model=SwarmSpec,
max_tokens=10000,
)
return director
def check_agents(self): def check_agents(self):
""" """
@ -96,48 +288,167 @@ class HierarchicalSwarm(BaseSwarm):
"No agents found in the swarm. At least one agent must be provided to create a hierarchical swarm." "No agents found in the swarm. At least one agent must be provided to create a hierarchical swarm."
) )
if self.max_loops == 0:
raise ValueError(
"Max loops must be greater than 0. Please set a valid number of loops."
)
if self.director is None:
self.director = self.agents[0]
if not self.director: if not self.director:
raise ValueError( raise ValueError(
"Director not set for the swarm. A director agent is required to coordinate and orchestrate tasks among the agents." "Director not set for the swarm. A director agent is required to coordinate and orchestrate tasks among the agents."
) )
logger.info(
"Reliability checks have passed. Swarm is ready to execute."
)
def run_director( def run_director(
self, task: str, img: str = None, *args, **kwargs self, task: str, loop_context: str = "", img: str = None
): ) -> SwarmSpec:
""" """
Runs a task through the director agent. Runs a task through the director agent with the current conversation context.
:param task: The task to be executed by the director. :param task: The task to be executed by the director.
:param loop_context: Additional context specific to the current loop.
:param img: Optional image to be used with the task. :param img: Optional image to be used with the task.
:return: The output of the director's task execution. :return: The SwarmSpec containing the director's orders.
""" """
# Create a comprehensive context for the director
director_context = f"History: {self.conversation.get_str()}"
if loop_context:
director_context += f"\n\nCurrent Loop ({self.current_loop}/{self.max_loops}): {loop_context}"
director_context += f"\n\nYour Task: {task}"
# Run the director with the context
function_call = self.director.run(task=director_context)
print(function_call)
function_call = self.director.run( # function_call = self.check_director_agent_output(
task=f"History: {self.conversation.get_str()} Your Task: {task}", # function_call
# )
formatter.print_panel(
f"Director Output (Loop {self.current_loop}/{self.max_loops}):\n{function_call}",
title="Director's Orders",
) )
formatter.print_panel(f"Director Output: {function_call}") # Add director's output to the conversation
self.conversation.add(
role="Director",
content=f"Loop {self.current_loop}/{self.max_loops}: {function_call}",
)
return function_call return function_call
def run(self, task: str, img: str = None, *args, **kwargs) -> str: def run(
self, task: str, img: str = None, *args, **kwargs
) -> Union[str, Dict, List]:
""" """
Runs a task through the swarm, involving the director and agents. Runs a task through the swarm, involving the director and agents through multiple loops.
:param task: The task to be executed by the swarm. :param task: The task to be executed by the swarm.
:param img: Optional image to be used with the task. :param img: Optional image to be used with the task.
:return: The output of the swarm's task execution. :return: The output of the swarm's task execution in the specified format.
""" """
# Add the initial task to the conversation
self.conversation.add(role="User", content=f"Task: {task}") self.conversation.add(role="User", content=f"Task: {task}")
function_call = self.run_director( # Reset loop counter and agent outputs
task=self.conversation.get_str() self.current_loop = 0
) self.agent_outputs = {}
self.parse_orders(function_call) # Initialize loop context
loop_context = "Initial planning phase"
if self.return_all_history: # Execute the loops
for loop_idx in range(self.max_loops):
self.current_loop = loop_idx + 1
# Log loop start
logger.info(
f"Starting loop {self.current_loop}/{self.max_loops}"
)
formatter.print_panel(
f"⚡ EXECUTING LOOP {self.current_loop}/{self.max_loops}",
title="SWARM EXECUTION CYCLE",
)
# Get director's orders
swarm_spec = self.run_director(
task=task, loop_context=loop_context, img=img
)
# Add the swarm specification to the conversation
self.add_goal_and_more_in_conversation(swarm_spec)
# Parse and execute the orders
orders_list = self.parse_swarm_spec(swarm_spec)
# Store outputs for this loop
self.agent_outputs[self.current_loop] = {}
# Execute each order
for order in orders_list:
agent_output = self.run_agent(
agent_name=order.agent_name,
task=order.task,
img=img,
)
# Store the agent's output for this loop
self.agent_outputs[self.current_loop][
order.agent_name
] = agent_output
# Prepare context for the next loop
loop_context = self.compile_loop_context(
self.current_loop
)
# If this is the last loop, break out
if self.current_loop >= self.max_loops:
break
# Return the results in the specified format
return self.format_output()
def compile_loop_context(self, loop_number: int) -> str:
"""
Compiles the context for a specific loop, including all agent outputs.
:param loop_number: The loop number to compile context for.
:return: A string representation of the loop context.
"""
if loop_number not in self.agent_outputs:
return "No agent outputs available for this loop."
context = f"Results from loop {loop_number}:\n"
for agent_name, output in self.agent_outputs[
loop_number
].items():
context += f"\n--- {agent_name}'s Output ---\n{output}\n"
return context
def format_output(self) -> Union[str, Dict, List]:
"""
Formats the output according to the specified output_type.
:return: The formatted output.
"""
if self.output_type == "str" or self.return_all_history:
return self.conversation.get_str() return self.conversation.get_str()
elif self.output_type == "dict":
return self.conversation.return_messages_as_dictionary()
elif self.output_type == "list":
return self.conversation.return_messages_as_list()
else: else:
return self.conversation.get_str() return self.conversation.get_str()
@ -146,8 +457,8 @@ class HierarchicalSwarm(BaseSwarm):
Adds the swarm's name and description to the conversation. Adds the swarm's name and description to the conversation.
""" """
self.conversation.add( self.conversation.add(
role="User", role="System",
content=f"\n Swarm Name: {self.name} \n Swarm Description: {self.description}", content=f"Swarm Name: {self.name}\nSwarm Description: {self.description}",
) )
formatter.print_panel( formatter.print_panel(
@ -165,22 +476,24 @@ class HierarchicalSwarm(BaseSwarm):
:return: A string representation of all agents in the swarm. :return: A string representation of all agents in the swarm.
""" """
# Compile information about all agents
# need to fetch name and description of all agents
all_agents = "\n".join( all_agents = "\n".join(
f"Agent: {agent.agent_name} || Description: {agent.description or agent.system_prompt} \n" f"Agent: {agent.agent_name} || Description: {agent.description or agent.system_prompt}"
for agent in self.agents for agent in self.agents
) )
# Add the agent information to the conversation
self.conversation.add( self.conversation.add(
role="User", role="System",
content=f"All Agents Available in the Swarm {self.name}: \n {all_agents}", content=f"All Agents Available in the Swarm {self.name}:\n{all_agents}",
) )
formatter.print_panel( formatter.print_panel(
all_agents, title="All Agents Available in the Swarm" all_agents, title="All Agents Available in the Swarm"
) )
return all_agents
def find_agent(self, name: str) -> Optional[Agent]: def find_agent(self, name: str) -> Optional[Agent]:
""" """
Finds an agent by its name within the swarm. Finds an agent by its name within the swarm.
@ -193,9 +506,11 @@ class HierarchicalSwarm(BaseSwarm):
return agent return agent
return None return None
def run_agent(self, agent_name: str, task: str, img: str = None): def run_agent(
self, agent_name: str, task: str, img: str = None
) -> str:
""" """
Runs a task through a specific agent. Runs a task through a specific agent, providing it with the full conversation context.
:param agent_name: The name of the agent to execute the task. :param agent_name: The name of the agent to execute the task.
:param task: The task to be executed by the agent. :param task: The task to be executed by the agent.
@ -205,82 +520,144 @@ class HierarchicalSwarm(BaseSwarm):
try: try:
agent = self.find_agent(agent_name) agent = self.find_agent(agent_name)
if agent: if not agent:
out = agent.run( error_msg = f"Agent '{agent_name}' not found in the swarm '{self.name}'"
task=f"History: {self.conversation.get_str()} Your Task: {task}", logger.error(error_msg)
img=img,
)
self.conversation.add( self.conversation.add(
role=agent_name, role="System", content=f"Error: {error_msg}"
content=out,
) )
return error_msg
return out # Prepare context for the agent
else: agent_context = (
logger.error( f"Loop: {self.current_loop}/{self.max_loops}\n"
f"Agent {agent_name} not found in the swarm {self.name}" f"History: {self.conversation.get_str()}\n"
) f"Your Task: {task}"
)
# Run the agent with the context
formatter.print_panel(
f"Running agent '{agent_name}' with task: {task}",
title=f"Agent Task - Loop {self.current_loop}/{self.max_loops}",
)
out = agent.run(task=agent_context, img=img)
# Add the agent's output to the conversation
self.conversation.add(
role=agent_name,
content=f"Loop {self.current_loop}/{self.max_loops}: {out}",
)
formatter.print_panel(
out,
title=f"Output from {agent_name} - Loop {self.current_loop}/{self.max_loops}",
)
return out
except Exception as e: except Exception as e:
logger.error(f"Error running agent {agent_name}: {e}") error_msg = (
return "Error running agent" f"Error running agent '{agent_name}': {str(e)}"
)
logger.error(error_msg)
self.conversation.add(
role="System", content=f"Error: {error_msg}"
)
return error_msg
def parse_orders(self, orders: SwarmSpec) -> None: def parse_orders(self, swarm_spec: SwarmSpec) -> List[Any]:
""" """
Parses the orders from the SwarmSpec and executes them through the agents. Parses the orders from the SwarmSpec and executes them through the agents.
:param orders: The SwarmSpec containing the orders to be parsed. :param swarm_spec: The SwarmSpec containing the orders to be parsed.
:return: A list of agent outputs.
""" """
self.add_goal_and_more_in_conversation(orders) self.add_goal_and_more_in_conversation(swarm_spec)
orders_list = self.parse_swarm_spec(swarm_spec)
orders_list = self.parse_swarm_spec(orders) outputs = []
try: try:
# Example of passing the parsed data to an agent
for order in orders_list: for order in orders_list:
out = self.run_agent( output = self.run_agent(
agent_name=order.agent_name, agent_name=order.agent_name,
task=order.task, task=order.task,
) )
outputs.append(output)
return out return outputs
except Exception as e: except Exception as e:
logger.error(f"Error parsing orders: {e}") error_msg = (
return "Error parsing orders" f"Error parsing and executing orders: {str(e)}"
)
logger.error(error_msg)
self.conversation.add(
role="System", content=f"Error: {error_msg}"
)
return [error_msg]
def parse_swarm_spec(self, swarm_spec: SwarmSpec) -> None: def parse_swarm_spec(
self, swarm_spec: SwarmSpec
) -> List[HierarchicalOrder]:
""" """
Parses the SwarmSpec to extract the orders. Parses the SwarmSpec to extract the orders.
:param swarm_spec: The SwarmSpec to be parsed. :param swarm_spec: The SwarmSpec to be parsed.
:return: The list of orders extracted from the SwarmSpec. :return: The list of orders extracted from the SwarmSpec.
""" """
orders_list = swarm_spec.orders try:
return swarm_spec.orders
# return the orders_list except AttributeError:
return orders_list logger.error(
"Invalid SwarmSpec format: missing 'orders' attribute"
)
return []
except Exception as e:
logger.error(f"Error parsing SwarmSpec: {str(e)}")
return []
def provide_feedback(self, agent_name: str, out: str) -> None: def provide_feedback(
self, agent_outputs: Dict[str, str]
) -> Dict[str, str]:
""" """
Provides feedback to an agent based on its output. Provides feedback to agents based on their outputs.
:param agent_name: The name of the agent to provide feedback to. :param agent_outputs: A dictionary mapping agent names to their outputs.
:param out: The output of the agent to base the feedback on. :return: A dictionary of feedback for each agent.
""" """
orders = self.director.run( feedback = {}
task=f"Provide feedback to {agent_name} on their output: {out}"
# Compile all agent outputs for the director
agent_outputs_str = "\n\n".join(
f"--- {agent_name} Output ---\n{output}"
for agent_name, output in agent_outputs.items()
) )
orders_list = self.parse_swarm_spec(orders) # Have the director provide feedback
feedback_task = (
f"Review the following agent outputs and provide feedback for each agent.\n\n"
f"{agent_outputs_str}"
)
feedback_spec = self.run_director(task=feedback_task)
feedback_orders = self.parse_swarm_spec(feedback_spec)
# Process each feedback order
for order in feedback_orders:
# The agent receiving feedback
agent_name = order.agent_name
# The feedback content
feedback_content = order.task
for order in orders_list: # Store the feedback
out = self.run_agent( feedback[agent_name] = feedback_content
agent_name=order.agent_name,
task=order.task, # Add the feedback to the conversation
self.conversation.add(
role="Director",
content=f"Feedback for {agent_name}: {feedback_content}",
) )
return out return feedback
def add_goal_and_more_in_conversation( def add_goal_and_more_in_conversation(
self, swarm_spec: SwarmSpec self, swarm_spec: SwarmSpec
@ -290,24 +667,70 @@ class HierarchicalSwarm(BaseSwarm):
:param swarm_spec: The SwarmSpec containing the goals, plan, and rules. :param swarm_spec: The SwarmSpec containing the goals, plan, and rules.
""" """
goals = swarm_spec.goals try:
plan = swarm_spec.plan goals = swarm_spec.goals
rules = swarm_spec.rules plan = swarm_spec.plan
rules = swarm_spec.rules
self.conversation.add( self.conversation.add(
role="Director", role="Director",
content=f"Goals: {goals}\nPlan: {plan}\nRules: {rules}", content=f"Goals: {goals}\nPlan: {plan}\nRules: {rules}",
) )
except Exception as e:
error_msg = f"Error adding goals and plan to conversation: {str(e)}"
logger.error(error_msg)
self.conversation.add(
role="System", content=f"Error: {error_msg}"
)
def batch_run(self, tasks: List[str]) -> List[str]: def batch_run(
self, tasks: List[str], img: str = None
) -> List[Union[str, Dict, List]]:
""" """
Batch run the swarm with the given tasks. Runs multiple tasks sequentially through the swarm.
:param tasks: The list of tasks to be executed.
:param img: Optional image to be used with the tasks.
:return: A list of outputs from each task execution.
""" """
return [self.run(task) for task in tasks] return [self.run(task, img) for task in tasks]
def check_director_agent_output(self, output: any) -> dict:
if isinstance(output, dict):
return output
elif isinstance(output, str):
try:
# Attempt to parse the string as JSON
return json.loads(output)
except json.JSONDecodeError as e:
# Log an error if the string cannot be parsed
logger.error(
f"Failed to parse output string as JSON: {str(e)}"
)
return {}
else:
# Log an error if the output is neither a dict nor a string
logger.error(
"Output is neither a dictionary nor a string."
)
return {}
def concurrent_run(self, tasks: List[str]) -> List[str]: def concurrent_run(
self, tasks: List[str], img: str = None
) -> List[Union[str, Dict, List]]:
""" """
Concurrent run the swarm with the given tasks. Runs multiple tasks concurrently through the swarm.
:param tasks: The list of tasks to be executed.
:param img: Optional image to be used with the tasks.
:return: A list of outputs from each task execution.
""" """
with ThreadPoolExecutor(max_workers=len(tasks)) as executor: with ThreadPoolExecutor(max_workers=len(tasks)) as executor:
return list(executor.map(self.run, tasks)) # Create a list of partial functions with the img parameter
task_functions = [(task, img) for task in tasks]
# Use starmap to unpack the arguments
return list(
executor.map(
lambda args: self.run(*args), task_functions
)
)

@ -249,7 +249,6 @@ class MajorityVoting:
else: else:
return self.conversation.return_history_as_string() return self.conversation.return_history_as_string()
def batch_run( def batch_run(
self, tasks: List[str], *args, **kwargs self, tasks: List[str], *args, **kwargs
) -> List[Any]: ) -> List[Any]:

@ -10,7 +10,6 @@ from swarms.telemetry.main import log_agent_data
from swarms.schemas.agent_step_schemas import ManySteps from swarms.schemas.agent_step_schemas import ManySteps
from swarms.prompts.ag_prompt import aggregator_system_prompt from swarms.prompts.ag_prompt import aggregator_system_prompt
from swarms.utils.loguru_logger import initialize_logger from swarms.utils.loguru_logger import initialize_logger
from swarms.utils.any_to_str import any_to_str
import concurrent.futures import concurrent.futures
from swarms.structs.output_type import OutputType from swarms.structs.output_type import OutputType
from swarms.structs.conversation import Conversation from swarms.structs.conversation import Conversation
@ -274,7 +273,9 @@ class MixtureOfAgents:
if self.return_str_on or self.output_type == "str": if self.return_str_on or self.output_type == "str":
return self.conversation.get_str() return self.conversation.get_str()
elif self.output_type == "dict": elif self.output_type == "dict":
return self.conversation.return_messages_as_dictionary() return (
self.conversation.return_messages_as_dictionary()
)
elif self.output_type == "list": elif self.output_type == "list":
return self.conversation.return_messages_as_list() return self.conversation.return_messages_as_list()
else: else:

@ -11,12 +11,15 @@ Todo:
import os import os
import uuid import uuid
from datetime import datetime from datetime import datetime
from typing import List, Literal, Optional from typing import List, Optional
from loguru import logger from loguru import logger
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from swarms.utils.function_caller_model import OpenAIFunctionCaller from swarms.utils.function_caller_model import OpenAIFunctionCaller
from swarms.structs.agent import Agent from swarms.structs.agent import Agent
from swarms.structs.conversation import Conversation
from swarms.structs.output_type import OutputType
from swarms.utils.any_to_str import any_to_str
class AgentResponse(BaseModel): class AgentResponse(BaseModel):
@ -58,7 +61,7 @@ class MultiAgentRouter:
model: str = "gpt-4o-mini", model: str = "gpt-4o-mini",
temperature: float = 0.1, temperature: float = 0.1,
shared_memory_system: callable = None, shared_memory_system: callable = None,
output_type: Literal["json", "string"] = "json", output_type: OutputType = "dict",
execute_task: bool = True, execute_task: bool = True,
): ):
""" """
@ -76,13 +79,19 @@ class MultiAgentRouter:
self.name = name self.name = name
self.description = description self.description = description
self.shared_memory_system = shared_memory_system self.shared_memory_system = shared_memory_system
self.output_type = output_type
self.execute_task = execute_task
self.model = model
self.temperature = temperature
# Initialize Agents
self.agents = {agent.name: agent for agent in agents} self.agents = {agent.name: agent for agent in agents}
self.conversation = Conversation()
self.api_key = os.getenv("OPENAI_API_KEY") self.api_key = os.getenv("OPENAI_API_KEY")
if not self.api_key: if not self.api_key:
raise ValueError("OpenAI API key must be provided") raise ValueError("OpenAI API key must be provided")
self.output_type = output_type
self.execute_task = execute_task
self.boss_system_prompt = self._create_boss_system_prompt() self.boss_system_prompt = self._create_boss_system_prompt()
# Initialize the function caller # Initialize the function caller
@ -157,11 +166,18 @@ class MultiAgentRouter:
dict: A dictionary containing the routing result, including the selected agent, reasoning, and response. dict: A dictionary containing the routing result, including the selected agent, reasoning, and response.
""" """
try: try:
self.conversation.add(role="user", content=task)
start_time = datetime.now() start_time = datetime.now()
# Get boss decision using function calling # Get boss decision using function calling
boss_response = self.function_caller.get_completion(task) boss_response = self.function_caller.get_completion(task)
boss_response_str = any_to_str(boss_response)
self.conversation.add(
role="assistant", content=boss_response_str
)
# Validate that the selected agent exists # Validate that the selected agent exists
if boss_response.selected_agent not in self.agents: if boss_response.selected_agent not in self.agents:
raise ValueError( raise ValueError(
@ -182,6 +198,9 @@ class MultiAgentRouter:
if self.execute_task: if self.execute_task:
# Use the agent's run method directly # Use the agent's run method directly
agent_response = selected_agent.run(final_task) agent_response = selected_agent.run(final_task)
self.conversation.add(
role=selected_agent.name, content=agent_response
)
execution_time = ( execution_time = (
datetime.now() - execution_start datetime.now() - execution_start
).total_seconds() ).total_seconds()
@ -230,7 +249,15 @@ class MultiAgentRouter:
logger.error(f"Error routing task: {str(e)}") logger.error(f"Error routing task: {str(e)}")
raise raise
def batch_route(self, tasks: List[str] = []): def run(self, task: str):
"""Route a task to the appropriate agent and return the result"""
return self.route_task(task)
def __call__(self, task: str):
"""Route a task to the appropriate agent and return the result"""
return self.route_task(task)
def batch_run(self, tasks: List[str] = []):
"""Batch route tasks to the appropriate agents""" """Batch route tasks to the appropriate agents"""
results = [] results = []
for task in tasks: for task in tasks:
@ -241,7 +268,7 @@ class MultiAgentRouter:
logger.error(f"Error routing task: {str(e)}") logger.error(f"Error routing task: {str(e)}")
return results return results
def concurrent_batch_route(self, tasks: List[str] = []): def concurrent_batch_run(self, tasks: List[str] = []):
"""Concurrently route tasks to the appropriate agents""" """Concurrently route tasks to the appropriate agents"""
import concurrent.futures import concurrent.futures
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor

@ -491,7 +491,9 @@ class AgentRearrange(BaseSwarm):
elif self.output_type == "list": elif self.output_type == "list":
output = all_responses output = all_responses
elif self.output_type == "dict": elif self.output_type == "dict":
output = self.conversation.return_messages_as_dictionary() output = (
self.conversation.return_messages_as_dictionary()
)
else: # "final" else: # "final"
output = current_task output = current_task

@ -143,15 +143,17 @@ class SequentialWorkflow:
**kwargs, **kwargs,
) )
if self.output_type == "dict": if self.output_type == "dict":
result = self.agent_rearrange.conversation.return_messages_as_dictionary() result = (
self.agent_rearrange.conversation.return_messages_as_dictionary()
)
elif self.output_type == "list": elif self.output_type == "list":
result = self.agent_rearrange.conversation.return_messages_as_list() result = (
self.agent_rearrange.conversation.return_messages_as_list()
)
elif self.output_type == "str" or self.return_json: elif self.output_type == "str" or self.return_json:
result = self.agent_rearrange.conversation.get_str() result = self.agent_rearrange.conversation.get_str()
return result return result
except Exception as e: except Exception as e:
logger.error( logger.error(

@ -309,10 +309,11 @@ class SwarmRouter:
return HierarchicalSwarm( return HierarchicalSwarm(
name=self.name, name=self.name,
description=self.description, description=self.description,
director=self.agents[0], # director=self.agents[0],
agents=self.agents, agents=self.agents,
max_loops=self.max_loops, max_loops=self.max_loops,
return_all_history=self.return_entire_history, return_all_history=self.return_entire_history,
output_type=self.output_type,
*args, *args,
**kwargs, **kwargs,
) )

@ -27,7 +27,7 @@ def run_single_swarm():
"agent_name": "Market Analyst", "agent_name": "Market Analyst",
"description": "Analyzes market trends", "description": "Analyzes market trends",
"system_prompt": "You are a financial analyst expert.", "system_prompt": "You are a financial analyst expert.",
"model_name": "groq/deepseek-r1-distill-qwen-32b", "model_name": "gpt-4o",
"role": "worker", "role": "worker",
"max_loops": 1, "max_loops": 1,
"max_tokens": 8192, "max_tokens": 8192,
@ -36,26 +36,17 @@ def run_single_swarm():
"agent_name": "Economic Forecaster", "agent_name": "Economic Forecaster",
"description": "Predicts economic trends", "description": "Predicts economic trends",
"system_prompt": "You are an expert in economic forecasting.", "system_prompt": "You are an expert in economic forecasting.",
"model_name": "groq/deepseek-r1-distill-qwen-32b", "model_name": "gpt-4o",
"role": "worker",
"max_loops": 1,
"max_tokens": 8192,
},
{
"agent_name": "Data Scientist",
"description": "Performs data analysis",
"system_prompt": "You are a data science expert.",
"model_name": "groq/deepseek-r1-distill-qwen-32b",
"role": "worker", "role": "worker",
"max_loops": 1, "max_loops": 1,
"max_tokens": 8192, "max_tokens": 8192,
}, },
], ],
"max_loops": 1, "max_loops": 1,
"swarm_type": "ConcurrentWorkflow", "swarm_type": "HiearchicalSwarm",
"task": "What are the best etfs and index funds for ai and tech?", "task": "What are the best etfs and index funds for ai and tech?",
"output_type": "str", "output_type": "dict",
"return_history": True, # "return_history": True,
} }
response = requests.post( response = requests.post(
@ -75,10 +66,16 @@ def get_logs():
f"{BASE_URL}/v1/swarm/logs", headers=headers f"{BASE_URL}/v1/swarm/logs", headers=headers
) )
output = response.json() output = response.json()
return json.dumps(output, indent=4) # return json.dumps(output, indent=4)
return output
if __name__ == "__main__": if __name__ == "__main__":
result = run_single_swarm() # result = run_single_swarm()
print("Swarm Result:") # print("Swarm Result:")
print(result) # print(result)
logs = get_logs()
logs = json.dumps(logs, indent=4)
print("Logs:")
print(logs)

@ -138,14 +138,14 @@ def test_batch_routing():
tasks = ["Task 1", "Task 2", "Task 3"] tasks = ["Task 1", "Task 2", "Task 3"]
# Test sequential batch routing # Test sequential batch routing
results = router.batch_route(tasks) results = router.batch_run(tasks)
assert len(results) == len( assert len(results) == len(
tasks tasks
), "Should return result for each task" ), "Should return result for each task"
print("✓ Sequential batch routing successful") print("✓ Sequential batch routing successful")
# Test concurrent batch routing # Test concurrent batch routing
concurrent_results = router.concurrent_batch_route(tasks) concurrent_results = router.concurrent_batch_run(tasks)
assert len(concurrent_results) == len( assert len(concurrent_results) == len(
tasks tasks
), "Should return result for each task" ), "Should return result for each task"

Loading…
Cancel
Save