# MixtureOfAgents Class Documentation

## Architecture Overview

```mermaid
graph TD
    A[Input Task] --> B[Initialize MixtureOfAgents]
    B --> C[Reliability Check]
    C --> D[Layer 1: Parallel Agent Execution]
    D --> E[Layer 2: Sequential Processing]
    E --> F[Layer 3: Parallel Agent Execution]
    F --> G[Final Aggregator Agent]
    G --> H[Output Response]

    subgraph "Agent Layer Details"
        I[Agent 1] --> J[Agent Results]
        K[Agent 2] --> J
        L[Agent N] --> J
    end

    subgraph "Processing Flow"
        M[Previous Context] --> N[Current Task]
        N --> O[Agent Processing]
        O --> P[Aggregation]
        P --> M
    end
```

## Overview

The `MixtureOfAgents` class represents a mixture of agents operating within a swarm. The workflow of the swarm follows a parallel → sequential → parallel → final output agent process. This implementation is inspired by concepts discussed in the paper: [https://arxiv.org/pdf/2406.04692](https://arxiv.org/pdf/2406.04692).

The class is designed to manage a collection of agents, orchestrate their execution in layers, and handle the final aggregation of their outputs through a designated final agent. This architecture facilitates complex, multi-step processing where intermediate results are refined through successive layers of agent interactions.

## Class Definition

### MixtureOfAgents

```python
class MixtureOfAgents(BaseSwarm):
```

### Attributes

| Attribute         | Type          | Description                                                  | Default                                                    |
| ----------------- | ------------- | ------------------------------------------------------------ | ---------------------------------------------------------- |
| `agents`          | `List[Agent]` | The list of agents in the swarm.                             | `None`                                                     |
| `flow`            | `str`         | The flow of the swarm.                                       | `parallel -> sequential -> parallel -> final output agent` |
| `max_loops`       | `int`         | The maximum number of loops to run.                          | `1`                                                        |
| `verbose`         | `bool`        | Flag indicating whether to print verbose output.             | `True`                                                     |
| `layers`          | `int`         | The number of layers in the swarm.                           | `3`                                                        |
| `rules`           | `str`         | The rules for the swarm.                                     | `None`                                                     |
| `final_agent`     | `Agent`       | The agent to handle the final output processing.             | `None`                                                     |
| `auto_save`       | `bool`        | Flag indicating whether to auto-save the metadata to a file. | `False`                                                    |
| `saved_file_name` | `str`         | The name of the file where the metadata will be saved.       | `"moe_swarm.json"`                                         |

## Methods

### `__init__`

#### Parameters

| Parameter         | Type          | Description                                                  | Default                                                      |
| ----------------- | ------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| `name`            | `str`         | The name of the swarm.                                       | `"MixtureOfAgents"`                                          |
| `description`     | `str`         | A brief description of the swarm.                            | `"A swarm of agents that run in parallel and sequentially."` |
| `agents`          | `List[Agent]` | The list of agents in the swarm.                             | `None`                                                       |
| `max_loops`       | `int`         | The maximum number of loops to run.                          | `1`                                                          |
| `verbose`         | `bool`        | Flag indicating whether to print verbose output.             | `True`                                                       |
| `layers`          | `int`         | The number of layers in the swarm.                           | `3`                                                          |
| `rules`           | `str`         | The rules for the swarm.                                     | `None`                                                       |
| `final_agent`     | `Agent`       | The agent to handle the final output processing.             | `None`                                                       |
| `auto_save`       | `bool`        | Flag indicating whether to auto-save the metadata to a file. | `False`                                                      |
| `saved_file_name` | `str`         | The name of the file where the metadata will be saved.       | `"moe_swarm.json"`                                           |

### `agent_check`

```python
def agent_check(self):
```

#### Description

Checks if the provided `agents` attribute is a list of `Agent` instances. Raises a `TypeError` if the validation fails.

#### Example Usage

```python
moe_swarm = MixtureOfAgents(agents=[agent1, agent2])
moe_swarm.agent_check()  # Validates the agents
```

### `final_agent_check`

```python
def final_agent_check(self):
```

#### Description

Checks if the provided `final_agent` attribute is an instance of `Agent`. Raises a `TypeError` if the validation fails.

#### Example Usage

```python
moe_swarm = MixtureOfAgents(final_agent=final_agent)
moe_swarm.final_agent_check()  # Validates the final agent
```

### `swarm_initialization`

```python
def swarm_initialization(self):
```

#### Description

Initializes the swarm by logging the swarm name, description, and the number of agents.

#### Example Usage

```python
moe_swarm = MixtureOfAgents(agents=[agent1, agent2])
moe_swarm.swarm_initialization()  # Initializes the swarm
```

### `run`

```python
def run(self, task: str = None, *args, **kwargs):
```

#### Parameters

| Parameter  | Type    | Description                            | Default |
| ---------- | ------- | -------------------------------------- | ------- |
| `task`     | `str`   | The task to be performed by the swarm. | `None`  |
| `*args`    | `tuple` | Additional arguments.                  | `None`  |
| `**kwargs` | `dict`  | Additional keyword arguments.          | `None`  |

#### Returns

| Type  | Description                           |
| ----- | ------------------------------------- |
| `str` | The conversation history as a string. |

#### Description

Runs the swarm with the given task, orchestrates the execution of agents through the specified layers, and returns the conversation history.

#### Example Usage

```python
moe_swarm = MixtureOfAgents(agents=[agent1, agent2], final_agent=final_agent)
history = moe_swarm.run(task="Solve this problem.")
print(history)
```

### `reliability_check`

```python
def reliability_check(self) -> None:
```

#### Description

Performs validation checks on the Mixture of Agents class to ensure all required components are properly configured. Raises ValueError if any checks fail.

#### Validation Checks:

- Verifies reference agents are provided
- Validates aggregator agent exists
- Checks aggregator system prompt is set
- Ensures layers count is valid (> 0)

### `_get_final_system_prompt`

```python
def _get_final_system_prompt(self, system_prompt: str, results: List[str]) -> str:
```

#### Description

Internal method that constructs a system prompt for subsequent layers by incorporating previous responses.

#### Parameters

| Parameter       | Type        | Description                |
| --------------- | ----------- | -------------------------- |
| `system_prompt` | `str`       | The initial system prompt  |
| `results`       | `List[str]` | List of previous responses |

#### Returns

| Type  | Description                                    |
| ----- | ---------------------------------------------- |
| `str` | Combined system prompt with previous responses |

### `run_batched`

```python
def run_batched(self, tasks: List[str]) -> List[str]:
```

#### Description

Processes multiple tasks sequentially, returning a list of responses.

#### Parameters

| Parameter | Type        | Description              |
| --------- | ----------- | ------------------------ |
| `tasks`   | `List[str]` | List of tasks to process |

#### Returns

| Type        | Description                     |
| ----------- | ------------------------------- |
| `List[str]` | List of responses for each task |

### `run_concurrently`

```python
def run_concurrently(self, tasks: List[str]) -> List[str]:
```

#### Description

Processes multiple tasks concurrently using a ThreadPoolExecutor, optimizing for parallel execution.

#### Parameters

| Parameter | Type        | Description                           |
| --------- | ----------- | ------------------------------------- |
| `tasks`   | `List[str]` | List of tasks to process concurrently |

#### Returns

| Type        | Description                     |
| ----------- | ------------------------------- |
| `List[str]` | List of responses for each task |

## Detailed Explanation

### Initialization

The `__init__` method initializes the swarm with the provided parameters, sets up the conversation rules, and invokes the initialization of the swarm. It also ensures the validity of the `agents` and `final_agent` attributes by calling the `agent_check` and `final_agent_check` methods respectively.

### Agent Validation

The `agent_check` method validates whether the `agents` attribute is a list of `Agent` instances, while the `final_agent_check` method validates whether the `final_agent` is an instance of `Agent`. These checks are crucial to ensure that the swarm operates correctly with the appropriate agent types.

### Swarm Initialization

The `swarm_initialization` method logs essential information about the swarm, including its name, description, and the number of agents. This provides a clear starting point for the swarm's operations and facilitates debugging and monitoring.

### Running the Swarm

The `run` method is the core of the `MixtureOfAgents` class. It orchestrates the execution of agents through multiple layers, collects their outputs, and processes the final output using the `final_agent`. The conversation history is maintained and updated throughout this process, allowing for a seamless flow of information and responses.

During each layer, the method iterates over the agents, invokes their `run` method with the current conversation history, and logs the outputs. These outputs are then added to the conversation, and the history is updated for the next layer.

After all layers are completed, the final output agent processes the entire conversation history, and the metadata is created and optionally saved to a file. This metadata includes details about the layers, agent runs, and final output, providing a comprehensive record of the swarm's execution.

## Additional Information and Tips

### Common Issues and Solutions

- **Type Errors**: Ensure that all agents in the `agents` list and the `final_agent` are instances of the `Agent` class. The `agent_check` and `final_agent_check` methods help validate this.
- **Verbose Logging**: Use the `verbose` flag to control the verbosity of the output. This can help with debugging or reduce clutter in the logs.
- **Auto-Save Feature**: Utilize the `auto_save` flag to automatically save the metadata to a file. This can be useful for keeping records of the swarm's operations without manual intervention.

### References and Resources

For further reading and background information on the concepts used in the `MixtureOfAgents` class, refer to the paper: [https://arxiv.org/pdf/2406.04692](https://arxiv.org/pdf/2406.04692).

### Usage Examples

#### Example 1: Basic Initialization and Run

```python
from swarms import MixtureOfAgents, Agent

from swarm_models import OpenAIChat

# Define agents
director = Agent(
    agent_name="Director",
    system_prompt="Directs the tasks for the accountants",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="director.json",
)

# Initialize accountant 1
accountant1 = Agent(
    agent_name="Accountant1",
    system_prompt="Prepares financial statements",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="accountant1.json",
)

# Initialize accountant 2
accountant2 = Agent(
    agent_name="Accountant2",
    system_prompt="Audits financial records",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="accountant2.json",
)


# Initialize the MixtureOfAgents
moe_swarm = MixtureOfAgents(agents=[director, accountant1, accountant2], final_agent=director)

# Run the swarm
history = moe_swarm.run(task="Perform task X.")
print(history)
```

#### Example 2: Verbose Output and Auto-Save

```python
from swarms import MixtureOfAgents, Agent

from swarm_models import OpenAIChat

# Define Agents
# Define agents
director = Agent(
    agent_name="Director",
    system_prompt="Directs the tasks for the accountants",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="director.json",
)

# Initialize accountant 1
accountant1 = Agent(
    agent_name="Accountant1",
    system_prompt="Prepares financial statements",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="accountant1.json",
)

# Initialize accountant 2
accountant2 = Agent(
    agent_name="Accountant2",
    system_prompt="Audits financial records",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="accountant2.json",
)

# Initialize the MixtureOfAgents with verbose output and auto-save enabled
moe_swarm = MixtureOfAgents(
    agents=[director, accountant1, accountant2],
    final_agent=director,
    verbose=True,
    auto_save=True
)

# Run the swarm
history = moe_swarm.run(task="Analyze data set Y.")
print(history)
```

#### Example 3: Custom Rules and Multiple Layers

```python
from swarms import MixtureOfAgents, Agent

from swarm_models import OpenAIChat

# Define agents
# Initialize the director agent
director = Agent(
    agent_name="Director",
    system_prompt="Directs the tasks for the accountants",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="director.json",
)

# Initialize accountant 1
accountant1 = Agent(
    agent_name="Accountant1",
    system_prompt="Prepares financial statements",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="accountant1.json",
)

# Initialize accountant 2
accountant2 = Agent(
    agent_name="Accountant2",
    system_prompt="Audits financial records",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="accountant2.json",
)

# Initialize the MixtureOfAgents with custom rules and multiple layers
moe_swarm = MixtureOfAgents(
    agents=[director, accountant1, accountant2],
    final_agent=director,
    layers=5,
    rules="Custom rules for the swarm"
)

# Run the swarm
history = moe_swarm.run(task="Optimize process Z.")
print(history)
```

This comprehensive documentation provides a detailed understanding of the `MixtureOfAgents` class, its attributes, methods, and usage. The examples illustrate how to initialize and run the swarm, demonstrating its flexibility and capability to handle various tasks and configurations.

# Conclusion

The `MixtureOfAgents` class is a powerful and flexible framework for managing and orchestrating a swarm of agents. By following a structured approach of parallel and sequential processing, it enables the implementation of complex multi-step workflows where intermediate results are refined through multiple layers of agent interactions. This architecture is particularly suitable for tasks that require iterative processing, collaboration among diverse agents, and sophisticated aggregation of outputs.

### Key Takeaways

1. **Flexible Initialization**: The class allows for customizable initialization with various parameters, enabling users to tailor the swarm's configuration to their specific needs.
2. **Robust Agent Management**: With built-in validation methods, the class ensures that all agents and the final agent are correctly instantiated, preventing runtime errors and facilitating smooth execution.
3. **Layered Processing**: The layered approach to processing allows for intermediate results to be iteratively refined, enhancing the overall output quality.
4. **Verbose Logging and Auto-Save**: These features aid in debugging, monitoring, and record-keeping, providing transparency and ease of management.
5. **Comprehensive Documentation**: The detailed class and method documentation, along with numerous usage examples, provide a clear and thorough understanding of how to leverage the `MixtureOfAgents` class effectively.

### Practical Applications

The `MixtureOfAgents` class can be applied in various domains, including but not limited to:

- **Natural Language Processing (NLP)**: Managing a swarm of NLP models to process, analyze, and synthesize text.
- **Data Analysis**: Coordinating multiple data analysis agents to process and interpret complex data sets.
- **Optimization Problems**: Running a swarm of optimization algorithms to solve complex problems in fields such as logistics, finance, and engineering.
- **AI Research**: Implementing experimental setups that require the collaboration of multiple AI models or agents to explore new methodologies and approaches.

### Future Extensions

The `MixtureOfAgents` framework provides a solid foundation for further extensions and customizations, including:

- **Dynamic Layer Configuration**: Allowing layers to be added or removed dynamically based on the task requirements or intermediate results.
- **Advanced Agent Communication**: Enhancing the communication protocols between agents to allow for more sophisticated information exchange.
- **Integration with Other Frameworks**: Seamlessly integrating with other machine learning or data processing frameworks to leverage their capabilities within the swarm architecture.

In conclusion, the `MixtureOfAgents` class represents a versatile and efficient solution for orchestrating multi-agent systems, facilitating complex task execution through its structured and layered approach. By harnessing the power of parallel and sequential processing, it opens up new possibilities for tackling intricate problems across various domains.

## Additional Examples

### Example 4: Batch Processing

```python
from swarms import MixtureOfAgents, Agent
from swarm_models import OpenAIChat

# Initialize agents as in previous examples
director = Agent(
    agent_name="Director",
    system_prompt="Directs the tasks for the accountants",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="director.json",
)

accountant1 = Agent(
    agent_name="Accountant1",
    system_prompt="Prepares financial statements",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="accountant1.json",
)

accountant2 = Agent(
    agent_name="Accountant2",
    system_prompt="Audits financial records",
    llm=OpenAIChat(),
    max_loops=1,
    dashboard=False,
    streaming_on=True,
    verbose=True,
    stopping_token="<DONE>",
    state_save_file_type="json",
    saved_state_path="accountant2.json",
)

# Initialize MixtureOfAgents
moe_swarm = MixtureOfAgents(
    agents=[director, accountant1, accountant2],
    final_agent=director
)

# Process multiple tasks in batch
tasks = [
    "Analyze Q1 financial statements",
    "Review tax compliance",
    "Prepare budget forecast"
]
results = moe_swarm.run_batched(tasks)
for task, result in zip(tasks, results):
    print(f"Task: {task}\nResult: {result}\n")
```

### Example 5: Concurrent Processing

```python
from swarms import MixtureOfAgents, Agent
from swarm_models import OpenAIChat

# Initialize agents as before
# ... agent initialization code ...

# Initialize MixtureOfAgents
moe_swarm = MixtureOfAgents(
    agents=[director, accountant1, accountant2],
    final_agent=director
)

# Process multiple tasks concurrently
tasks = [
    "Generate monthly report",
    "Audit expense claims",
    "Update financial projections",
    "Review investment portfolio"
]
results = moe_swarm.run_concurrently(tasks)
for task, result in zip(tasks, results):
    print(f"Task: {task}\nResult: {result}\n")
```

## Advanced Features

### Context Preservation

The `MixtureOfAgents` class maintains context between iterations when running multiple loops. Each subsequent iteration receives the context from previous runs, allowing for more sophisticated and context-aware processing.

### Asynchronous Processing

The class implements asynchronous processing internally using Python's `asyncio`, enabling efficient handling of concurrent operations and improved performance for complex workflows.

### Telemetry and Logging

Built-in telemetry and logging capabilities help track agent performance and maintain detailed execution records:

- Automatic logging of agent outputs
- Structured data capture using Pydantic models
- JSON-formatted output options
