From 7578353d63ad1789e8dc8e9763c44dbca4adfb4b Mon Sep 17 00:00:00 2001 From: Kye Gomez Date: Wed, 18 Jun 2025 21:48:46 -0700 Subject: [PATCH] [DOCS][ interactive groupchat examples] --- docs/mkdocs.yml | 1 + .../examples/interactive_groupchat_example.md | 136 ++++++++++ .../misc/swarm_matcher_example.py | 0 .../deep_research_swarm_example_new.py | 0 .../interactive_groupchat_example.py | 0 .../text_multi_agent_concurrency.py | 0 .../base_tool_examples/exa_search_test.py | 0 swarms/communication/pulsar_struct.py | 1 - swarms/schemas/swarms_api_schemas.py | 164 ++++++++++++ swarms/structs/__init__.py | 2 - swarms/structs/csv_to_agent.py | 253 +++++++++++------- swarms/structs/multi_agent_collab.py | 242 ----------------- tests/communication/test_redis.py | 2 +- tests/structs/test_multi_agent_collab.py | 2 +- ...vision_and_tools.py => vision_and_tools.py | 14 +- 15 files changed, 462 insertions(+), 355 deletions(-) create mode 100644 docs/swarms/examples/interactive_groupchat_example.md rename swarm_matcher_example.py => examples/misc/swarm_matcher_example.py (100%) rename deep_research_swarm_example.py => examples/multi_agent/deep_research_examples/deep_research_swarm_example_new.py (100%) rename interactive_groupchat_example.py => examples/multi_agent/groupchat/interactive_groupchat_example.py (100%) rename text_multi_agent_concurrency.py => examples/multi_agent/text_multi_agent_concurrency.py (100%) rename exa_search_test.py => examples/tools/base_tool_examples/exa_search_test.py (100%) create mode 100644 swarms/schemas/swarms_api_schemas.py delete mode 100644 swarms/structs/multi_agent_collab.py rename examples/single_agent/vision_examples/vision_and_tools.py => vision_and_tools.py (86%) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 260cab31..b55592c1 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -349,6 +349,7 @@ nav: - MixtureOfAgents Example: "swarms/examples/mixture_of_agents.md" - Unique Swarms: "swarms/examples/unique_swarms.md" - Agents as Tools: "swarms/examples/agents_as_tools.md" + - Interactive GroupChat Example: "swarms/examples/interactive_groupchat_example.md" - Applications: - Swarms DAO: "swarms/examples/swarms_dao.md" - Swarms of Browser Agents: "swarms/examples/swarms_of_browser_agents.md" diff --git a/docs/swarms/examples/interactive_groupchat_example.md b/docs/swarms/examples/interactive_groupchat_example.md new file mode 100644 index 00000000..36112d96 --- /dev/null +++ b/docs/swarms/examples/interactive_groupchat_example.md @@ -0,0 +1,136 @@ +# Interactive GroupChat Example + +This is an example of the InteractiveGroupChat module in swarms. [Click here for full documentation](https://docs.swarms.world/en/latest/swarms/structs/interactive_groupchat/) + +## Installation + +You can get started by first installing swarms with the following command, or [click here for more detailed installation instructions](https://docs.swarms.world/en/latest/swarms/install/install/): + +```bash +pip3 install -U swarms +``` + +## Environment Variables + +```txt +OPENAI_API_KEY="" +ANTHROPIC_API_KEY="" +GROQ_API_KEY="" +``` + +# Code + + +## Interactive Session in Terminal + +```python +from swarms import Agent +from swarms.structs.interactive_groupchat import InteractiveGroupChat + + +if __name__ == "__main__": + # Initialize agents + financial_advisor = Agent( + agent_name="FinancialAdvisor", + system_prompt="You are a financial advisor specializing in investment strategies and portfolio management.", + random_models_on=True, + output_type="final", + ) + + tax_expert = Agent( + agent_name="TaxExpert", + system_prompt="You are a tax expert who provides guidance on tax optimization and compliance.", + random_models_on=True, + output_type="final", + ) + + investment_analyst = Agent( + agent_name="InvestmentAnalyst", + system_prompt="You are an investment analyst focusing on market trends and investment opportunities.", + random_models_on=True, + output_type="final", + ) + + # Create a list of agents including both Agent instances and callables + agents = [ + financial_advisor, + tax_expert, + investment_analyst, + ] + + # Initialize another chat instance in interactive mode + interactive_chat = InteractiveGroupChat( + name="Interactive Financial Advisory Team", + description="An interactive team of financial experts providing comprehensive financial advice", + agents=agents, + max_loops=1, + output_type="all", + interactive=True, + ) + + try: + # Start the interactive session + print("\nStarting interactive session...") + # interactive_chat.run("What is the best methodology to accumulate gold and silver commodities, and what is the best long-term strategy to accumulate them?") + interactive_chat.start_interactive_session() + except Exception as e: + print(f"An error occurred in interactive mode: {e}") +``` + + +## Run Method // Manual Method + + +```python +from swarms import Agent +from swarms.structs.interactive_groupchat import InteractiveGroupChat + + +if __name__ == "__main__": + # Initialize agents + financial_advisor = Agent( + agent_name="FinancialAdvisor", + system_prompt="You are a financial advisor specializing in investment strategies and portfolio management.", + random_models_on=True, + output_type="final", + ) + + tax_expert = Agent( + agent_name="TaxExpert", + system_prompt="You are a tax expert who provides guidance on tax optimization and compliance.", + random_models_on=True, + output_type="final", + ) + + investment_analyst = Agent( + agent_name="InvestmentAnalyst", + system_prompt="You are an investment analyst focusing on market trends and investment opportunities.", + random_models_on=True, + output_type="final", + ) + + # Create a list of agents including both Agent instances and callables + agents = [ + financial_advisor, + tax_expert, + investment_analyst, + ] + + # Initialize another chat instance in interactive mode + interactive_chat = InteractiveGroupChat( + name="Interactive Financial Advisory Team", + description="An interactive team of financial experts providing comprehensive financial advice", + agents=agents, + max_loops=1, + output_type="all", + interactive=False, + ) + + try: + # Start the interactive session + print("\nStarting interactive session...") + # interactive_chat.run("What is the best methodology to accumulate gold and silver commodities, and what is the best long-term strategy to accumulate them?") + interactive_chat.run('@TaxExpert how can I understand tax tactics for crypto payroll in solana?') + except Exception as e: + print(f"An error occurred in interactive mode: {e}") +``` \ No newline at end of file diff --git a/swarm_matcher_example.py b/examples/misc/swarm_matcher_example.py similarity index 100% rename from swarm_matcher_example.py rename to examples/misc/swarm_matcher_example.py diff --git a/deep_research_swarm_example.py b/examples/multi_agent/deep_research_examples/deep_research_swarm_example_new.py similarity index 100% rename from deep_research_swarm_example.py rename to examples/multi_agent/deep_research_examples/deep_research_swarm_example_new.py diff --git a/interactive_groupchat_example.py b/examples/multi_agent/groupchat/interactive_groupchat_example.py similarity index 100% rename from interactive_groupchat_example.py rename to examples/multi_agent/groupchat/interactive_groupchat_example.py diff --git a/text_multi_agent_concurrency.py b/examples/multi_agent/text_multi_agent_concurrency.py similarity index 100% rename from text_multi_agent_concurrency.py rename to examples/multi_agent/text_multi_agent_concurrency.py diff --git a/exa_search_test.py b/examples/tools/base_tool_examples/exa_search_test.py similarity index 100% rename from exa_search_test.py rename to examples/tools/base_tool_examples/exa_search_test.py diff --git a/swarms/communication/pulsar_struct.py b/swarms/communication/pulsar_struct.py index cc89c0c6..59acef85 100644 --- a/swarms/communication/pulsar_struct.py +++ b/swarms/communication/pulsar_struct.py @@ -657,7 +657,6 @@ class PulsarConversation(BaseCommunication): try: import pulsar - pulsar_available = True except ImportError: logger.error("Pulsar client library is not installed") return False diff --git a/swarms/schemas/swarms_api_schemas.py b/swarms/schemas/swarms_api_schemas.py new file mode 100644 index 00000000..876eff40 --- /dev/null +++ b/swarms/schemas/swarms_api_schemas.py @@ -0,0 +1,164 @@ +from pydantic import BaseModel, Field +from typing import Optional, List, Dict, Any, Union, Literal + +SwarmType = Literal[ + "AgentRearrange", + "MixtureOfAgents", + "SpreadSheetSwarm", + "SequentialWorkflow", + "ConcurrentWorkflow", + "GroupChat", + "MultiAgentRouter", + "AutoSwarmBuilder", + "HiearchicalSwarm", + "auto", + "MajorityVoting", + "MALT", + "DeepResearchSwarm", + "CouncilAsAJudge", + "InteractiveGroupChat", +] + + +class AgentSpec(BaseModel): + agent_name: Optional[str] = Field( + # default=None, + description="The unique name assigned to the agent, which identifies its role and functionality within the swarm.", + ) + description: Optional[str] = Field( + default=None, + description="A detailed explanation of the agent's purpose, capabilities, and any specific tasks it is designed to perform.", + ) + system_prompt: Optional[str] = Field( + default=None, + description="The initial instruction or context provided to the agent, guiding its behavior and responses during execution.", + ) + model_name: Optional[str] = Field( + default="gpt-4o-mini", + description="The name of the AI model that the agent will utilize for processing tasks and generating outputs. For example: gpt-4o, gpt-4o-mini, openai/o3-mini", + ) + auto_generate_prompt: Optional[bool] = Field( + default=False, + description="A flag indicating whether the agent should automatically create prompts based on the task requirements.", + ) + max_tokens: Optional[int] = Field( + default=8192, + description="The maximum number of tokens that the agent is allowed to generate in its responses, limiting output length.", + ) + temperature: Optional[float] = Field( + default=0.5, + description="A parameter that controls the randomness of the agent's output; lower values result in more deterministic responses.", + ) + role: Optional[str] = Field( + default="worker", + description="The designated role of the agent within the swarm, which influences its behavior and interaction with other agents.", + ) + max_loops: Optional[int] = Field( + default=1, + description="The maximum number of times the agent is allowed to repeat its task, enabling iterative processing if necessary.", + ) + tools_list_dictionary: Optional[List[Dict[Any, Any]]] = Field( + default=None, + description="A dictionary of tools that the agent can use to complete its task.", + ) + mcp_url: Optional[str] = Field( + default=None, + description="The URL of the MCP server that the agent can use to complete its task.", + ) + + class Config: + arbitrary_types_allowed = True + + +class AgentCompletion(BaseModel): + agent_config: Optional[AgentSpec] = Field( + None, + description="The configuration of the agent to be completed.", + ) + task: Optional[str] = Field( + None, description="The task to be completed by the agent." + ) + history: Optional[Union[Dict[Any, Any], List[Dict[str, str]]]] = ( + Field( + default=None, + description="The history of the agent's previous tasks and responses. Can be either a dictionary or a list of message objects.", + ) + ) + + model_config = { + "arbitrary_types_allowed": True, + "populate_by_name": True, + } + + +class Agents(BaseModel): + """Configuration for a collection of agents that work together as a swarm to accomplish tasks.""" + + agents: List[AgentSpec] = Field( + description="A list containing the specifications of each agent that will participate in the swarm, detailing their roles and functionalities." + ) + + +class SwarmSpec(BaseModel): + name: Optional[str] = Field( + None, + description="The name of the swarm, which serves as an identifier for the group of agents and their collective task.", + max_length=100, + ) + description: Optional[str] = Field( + None, + description="A comprehensive description of the swarm's objectives, capabilities, and intended outcomes.", + ) + agents: Optional[List[AgentSpec]] = Field( + None, + description="A list of agents or specifications that define the agents participating in the swarm.", + ) + max_loops: Optional[int] = Field( + default=1, + description="The maximum number of execution loops allowed for the swarm, enabling repeated processing if needed.", + ) + swarm_type: Optional[SwarmType] = Field( + None, + description="The classification of the swarm, indicating its operational style and methodology.", + ) + rearrange_flow: Optional[str] = Field( + None, + description="Instructions on how to rearrange the flow of tasks among agents, if applicable.", + ) + task: Optional[str] = Field( + None, + description="The specific task or objective that the swarm is designed to accomplish.", + ) + img: Optional[str] = Field( + None, + description="An optional image URL that may be associated with the swarm's task or representation.", + ) + return_history: Optional[bool] = Field( + True, + description="A flag indicating whether the swarm should return its execution history along with the final output.", + ) + rules: Optional[str] = Field( + None, + description="Guidelines or constraints that govern the behavior and interactions of the agents within the swarm.", + ) + tasks: Optional[List[str]] = Field( + None, + description="A list of tasks that the swarm should complete.", + ) + messages: Optional[ + Union[List[Dict[Any, Any]], Dict[Any, Any]] + ] = Field( + None, + description="A list of messages that the swarm should complete.", + ) + stream: Optional[bool] = Field( + False, + description="A flag indicating whether the swarm should stream its output.", + ) + service_tier: Optional[str] = Field( + "standard", + description="The service tier to use for processing. Options: 'standard' (default) or 'flex' for lower cost but slower processing.", + ) + + class Config: + arbitrary_types_allowed = True diff --git a/swarms/structs/__init__.py b/swarms/structs/__init__.py index 778a059a..d47f6f67 100644 --- a/swarms/structs/__init__.py +++ b/swarms/structs/__init__.py @@ -40,7 +40,6 @@ from swarms.structs.meme_agent_persona_generator import ( ) from swarms.structs.mixture_of_agents import MixtureOfAgents from swarms.structs.model_router import ModelRouter -from swarms.structs.multi_agent_collab import MultiAgentCollaboration from swarms.structs.multi_agent_exec import ( get_agents_info, get_swarms_info, @@ -98,7 +97,6 @@ __all__ = [ "majority_voting", "most_frequent", "parse_code_completion", - "MultiAgentCollaboration", "AgentRearrange", "rearrange", "RoundRobinSwarm", diff --git a/swarms/structs/csv_to_agent.py b/swarms/structs/csv_to_agent.py index 2b8ecf9c..b76cc644 100644 --- a/swarms/structs/csv_to_agent.py +++ b/swarms/structs/csv_to_agent.py @@ -3,12 +3,25 @@ from typing import ( Dict, TypedDict, Any, + Union, + TypeVar, ) from dataclasses import dataclass import csv +import json +import yaml from pathlib import Path from enum import Enum from swarms.structs.agent import Agent +from swarms.schemas.swarms_api_schemas import AgentSpec +from litellm import model_list +import concurrent.futures +from tqdm import tqdm + +# Type variable for agent configuration +AgentConfigType = TypeVar( + "AgentConfigType", bound=Union[AgentSpec, Dict[str, Any]] +) class ModelName(str, Enum): @@ -32,12 +45,20 @@ class ModelName(str, Enum): return model_name in cls.get_model_names() +class FileType(str, Enum): + """Supported file types for agent configuration""" + + CSV = "csv" + JSON = "json" + YAML = "yaml" + + class AgentConfigDict(TypedDict): """TypedDict for agent configuration""" agent_name: str system_prompt: str - model_name: str # Using str instead of ModelName for flexibility + model_name: str max_loops: int autosave: bool dashboard: bool @@ -68,15 +89,26 @@ class AgentValidator: """Validates agent configuration data""" @staticmethod - def validate_config(config: Dict[str, Any]) -> AgentConfigDict: - """Validate and convert agent configuration""" + def validate_config( + config: Union[AgentSpec, Dict[str, Any]], + ) -> AgentConfigDict: + """Validate and convert agent configuration from either AgentSpec or Dict""" try: - # Validate model name + # Convert AgentSpec to dict if needed + if isinstance(config, AgentSpec): + config = config.model_dump() + + # Validate model name using litellm model list model_name = str(config["model_name"]) - if not ModelName.is_valid_model(model_name): - valid_models = ModelName.get_model_names() + if not any( + model_name in model["model_name"] + for model in model_list + ): + valid_models = [ + model["model_name"] for model in model_list + ] raise AgentValidationError( - f"Invalid model name. Must be one of: {', '.join(valid_models)}", + "Invalid model name. Must be one of the supported litellm models", "model_name", model_name, ) @@ -138,38 +170,36 @@ class AgentValidator: class AgentLoader: - """Class to manage agents through CSV with type safety""" - - csv_path: Path - - def __post_init__(self) -> None: - """Convert string path to Path object if necessary""" - if isinstance(self.csv_path, str): - self.csv_path = Path(self.csv_path) + """Class to manage agents through various file formats with type safety and high performance""" + + def __init__( + self, file_path: Union[str, Path], max_workers: int = 10 + ): + """Initialize the AgentLoader with file path and max workers for parallel processing""" + self.file_path = ( + Path(file_path) + if isinstance(file_path, str) + else file_path + ) + self.max_workers = max_workers @property - def headers(self) -> List[str]: - """CSV headers for agent configuration""" - return [ - "agent_name", - "system_prompt", - "model_name", - "max_loops", - "autosave", - "dashboard", - "verbose", - "dynamic_temperature", - "saved_state_path", - "user_name", - "retry_attempts", - "context_length", - "return_step_meta", - "output_type", - "streaming", - ] - - def create_agent_csv(self, agents: List[Dict[str, Any]]) -> None: - """Create a CSV file with validated agent configurations""" + def file_type(self) -> FileType: + """Determine the file type based on extension""" + ext = self.file_path.suffix.lower() + if ext == ".csv": + return FileType.CSV + elif ext == ".json": + return FileType.JSON + elif ext in [".yaml", ".yml"]: + return FileType.YAML + else: + raise ValueError(f"Unsupported file type: {ext}") + + def create_agent_file( + self, agents: List[Union[AgentSpec, Dict[str, Any]]] + ) -> None: + """Create a file with validated agent configurations""" validated_agents = [] for agent in agents: try: @@ -183,81 +213,71 @@ class AgentLoader: ) raise - with open(self.csv_path, "w", newline="") as f: - writer = csv.DictWriter(f, fieldnames=self.headers) - writer.writeheader() - writer.writerows(validated_agents) + if self.file_type == FileType.CSV: + self._write_csv(validated_agents) + elif self.file_type == FileType.JSON: + self._write_json(validated_agents) + elif self.file_type == FileType.YAML: + self._write_yaml(validated_agents) print( - f"Created CSV with {len(validated_agents)} agents at {self.csv_path}" + f"Created {self.file_type.value} file with {len(validated_agents)} agents at {self.file_path}" ) - def load_agents(self, file_type: str = "csv") -> List[Agent]: - """Load and create agents from CSV or JSON with validation""" - if file_type == "csv": - if not self.csv_path.exists(): - raise FileNotFoundError( - f"CSV file not found at {self.csv_path}" - ) - return self._load_agents_from_csv() - elif file_type == "json": - return self._load_agents_from_json() - else: - raise ValueError( - "Unsupported file type. Use 'csv' or 'json'." - ) - - def _load_agents_from_csv(self) -> List[Agent]: - """Load agents from a CSV file""" - agents: List[Agent] = [] - with open(self.csv_path, "r") as f: - reader = csv.DictReader(f) - for row in reader: - try: - validated_config = AgentValidator.validate_config( - row - ) - agent = self._create_agent(validated_config) - agents.append(agent) - except AgentValidationError as e: - print( - f"Skipping invalid agent configuration: {e}" - ) - continue - - print(f"Loaded {len(agents)} agents from {self.csv_path}") - return agents - - def _load_agents_from_json(self) -> List[Agent]: - """Load agents from a JSON file""" - import json - - if not self.csv_path.with_suffix(".json").exists(): + def load_agents(self) -> List[Agent]: + """Load and create agents from file with validation and parallel processing""" + if not self.file_path.exists(): raise FileNotFoundError( - f"JSON file not found at {self.csv_path.with_suffix('.json')}" + f"File not found at {self.file_path}" ) + if self.file_type == FileType.CSV: + agents_data = self._read_csv() + elif self.file_type == FileType.JSON: + agents_data = self._read_json() + elif self.file_type == FileType.YAML: + agents_data = self._read_yaml() + + # Process agents in parallel with progress bar agents: List[Agent] = [] - with open(self.csv_path.with_suffix(".json"), "r") as f: - agents_data = json.load(f) - for agent in agents_data: + with concurrent.futures.ThreadPoolExecutor( + max_workers=self.max_workers + ) as executor: + futures = [] + for agent_data in agents_data: + futures.append( + executor.submit(self._process_agent, agent_data) + ) + + # Use tqdm to show progress + for future in tqdm( + concurrent.futures.as_completed(futures), + total=len(futures), + desc="Loading agents", + ): try: - validated_config = AgentValidator.validate_config( - agent - ) - agent = self._create_agent(validated_config) - agents.append(agent) - except AgentValidationError as e: - print( - f"Skipping invalid agent configuration: {e}" - ) - continue + agent = future.result() + if agent: + agents.append(agent) + except Exception as e: + print(f"Error processing agent: {e}") - print( - f"Loaded {len(agents)} agents from {self.csv_path.with_suffix('.json')}" - ) + print(f"Loaded {len(agents)} agents from {self.file_path}") return agents + def _process_agent( + self, agent_data: Union[AgentSpec, Dict[str, Any]] + ) -> Union[Agent, None]: + """Process a single agent configuration""" + try: + validated_config = AgentValidator.validate_config( + agent_data + ) + return self._create_agent(validated_config) + except AgentValidationError as e: + print(f"Skipping invalid agent configuration: {e}") + return None + def _create_agent( self, validated_config: AgentConfigDict ) -> Agent: @@ -281,3 +301,36 @@ class AgentLoader: output_type=validated_config["output_type"], streaming_on=validated_config["streaming"], ) + + def _write_csv(self, agents: List[Dict[str, Any]]) -> None: + """Write agents to CSV file""" + with open(self.file_path, "w", newline="") as f: + writer = csv.DictWriter(f, fieldnames=agents[0].keys()) + writer.writeheader() + writer.writerows(agents) + + def _write_json(self, agents: List[Dict[str, Any]]) -> None: + """Write agents to JSON file""" + with open(self.file_path, "w") as f: + json.dump(agents, f, indent=2) + + def _write_yaml(self, agents: List[Dict[str, Any]]) -> None: + """Write agents to YAML file""" + with open(self.file_path, "w") as f: + yaml.dump(agents, f, default_flow_style=False) + + def _read_csv(self) -> List[Dict[str, Any]]: + """Read agents from CSV file""" + with open(self.file_path, "r") as f: + reader = csv.DictReader(f) + return list(reader) + + def _read_json(self) -> List[Dict[str, Any]]: + """Read agents from JSON file""" + with open(self.file_path, "r") as f: + return json.load(f) + + def _read_yaml(self) -> List[Dict[str, Any]]: + """Read agents from YAML file""" + with open(self.file_path, "r") as f: + return yaml.safe_load(f) diff --git a/swarms/structs/multi_agent_collab.py b/swarms/structs/multi_agent_collab.py deleted file mode 100644 index 4054df0b..00000000 --- a/swarms/structs/multi_agent_collab.py +++ /dev/null @@ -1,242 +0,0 @@ -from typing import List, Callable - -from swarms.structs.agent import Agent -from swarms.utils.loguru_logger import logger -from swarms.structs.base_swarm import BaseSwarm -from swarms.structs.conversation import Conversation - - -# def select_next_speaker_bid( -# step: int, -# agents: List[Agent], -# ) -> int: -# """Selects the next speaker.""" -# bids = [] -# for agent in agents: -# bid = ask_for_bid(agent) -# bids.append(bid) -# max_value = max(bids) -# max_indices = [i for i, x in enumerate(bids) if x == max_value] -# idx = random.choice(max_indices) -# return idx - - -def select_next_speaker_roundtable( - step: int, agents: List[Agent] -) -> int: - """Selects the next speaker.""" - return step % len(agents) - - -def select_next_speaker_director( - step: int, agents: List[Agent], director: Agent -) -> int: - # if the step if even => director - # => director selects next speaker - if step % 2 == 1: - idx = 0 - else: - idx = director.select_next_speaker() + 1 - return idx - - -def run_director(self, task: str): - """Runs the multi-agent collaboration with a director.""" - n = 0 - self.reset() - self.inject("Debate Moderator", task) - print("(Debate Moderator): \n") - - while n < self.max_loops: - name, message = self.step() - print(f"({name}): {message}\n") - n += 1 - - -# [MAYBE]: Add type hints -class MultiAgentCollaboration(BaseSwarm): - """ - Multi-agent collaboration class. - - Attributes: - agents (List[Agent]): The agents in the collaboration. - selection_function (callable): The function that selects the next speaker. - Defaults to select_next_speaker. - max_loops (int): The maximum number of iterations. Defaults to 10. - autosave (bool): Whether to autosave the state of all agents. Defaults to True. - saved_file_path_name (str): The path to the saved file. Defaults to - "multi_agent_collab.json". - stopping_token (str): The token that stops the collaboration. Defaults to - "". - results (list): The results of the collaboration. Defaults to []. - logger (logging.Logger): The logger. Defaults to logger. - logging (bool): Whether to log the collaboration. Defaults to True. - - - Methods: - reset: Resets the state of all agents. - inject: Injects a message into the collaboration. - inject_agent: Injects an agent into the collaboration. - step: Steps through the collaboration. - ask_for_bid: Asks an agent for a bid. - select_next_speaker: Selects the next speaker. - run: Runs the collaboration. - format_results: Formats the results of the run method. - - - Usage: - >>> from swarm_models import OpenAIChat - >>> from swarms.structs import Agent - >>> from swarms.swarms.multi_agent_collab import MultiAgentCollaboration - >>> - >>> # Initialize the language model - >>> llm = OpenAIChat( - >>> temperature=0.5, - >>> ) - >>> - >>> - >>> ## Initialize the workflow - >>> agent = Agent(llm=llm, max_loops=1, dashboard=True) - >>> - >>> # Run the workflow on a task - >>> out = agent.run("Generate a 10,000 word blog on health and wellness.") - >>> - >>> # Initialize the multi-agent collaboration - >>> swarm = MultiAgentCollaboration( - >>> agents=[agent], - >>> max_loops=4, - >>> ) - >>> - >>> # Run the multi-agent collaboration - >>> swarm.run() - >>> - >>> # Format the results of the multi-agent collaboration - >>> swarm.format_results(swarm.results) - - """ - - def __init__( - self, - name: str = "MultiAgentCollaboration", - description: str = "A multi-agent collaboration.", - director: Agent = None, - agents: List[Agent] = None, - select_next_speaker: Callable = None, - max_loops: int = 10, - autosave: bool = True, - saved_file_path_name: str = "multi_agent_collab.json", - stopping_token: str = "", - logging: bool = True, - *args, - **kwargs, - ): - super().__init__( - name=name, - description=description, - agents=agents, - *args, - **kwargs, - ) - self.name = name - self.description = description - self.director = director - self.agents = agents - self.select_next_speaker = select_next_speaker - self._step = 0 - self.max_loops = max_loops - self.autosave = autosave - self.saved_file_path_name = saved_file_path_name - self.stopping_token = stopping_token - self.results = [] - self.logger = logger - self.logging = logging - - # Conversation - self.conversation = Conversation( - time_enabled=False, *args, **kwargs - ) - - def default_select_next_speaker( - self, step: int, agents: List[Agent] - ) -> int: - """Default speaker selection function.""" - return step % len(agents) - - def inject(self, name: str, message: str): - """Injects a message into the multi-agent collaboration.""" - for agent in self.agents: - self.conversation.add(name, message) - agent.run(self.conversation.return_history_as_string()) - self._step += 1 - - def step(self) -> str: - """Steps through the multi-agent collaboration.""" - speaker_idx = self.select_next_speaker( - self._step, self.agents - ) - speaker = self.agents[speaker_idx] - message = speaker.send() - - for receiver in self.agents: - self.conversation.add(speaker.name, message) - receiver.run(self.conversation.return_history_as_string()) - - self._step += 1 - - if self.logging: - self.log_step(speaker, message) - - return self.conversation.return_history_as_string() - - def log_step(self, speaker: str, response: str): - """Logs the step of the multi-agent collaboration.""" - self.logger.info(f"{speaker.name}: {response}") - - def run(self, task: str, *args, **kwargs): - """Runs the multi-agent collaboration.""" - for _ in range(self.max_loops): - result = self.step() - if self.autosave: - self.save_state() - if self.stopping_token in result: - break - return self.conversation.return_history_as_string() - - # def format_results(self, results): - # """Formats the results of the run method""" - # formatted_results = "\n".join( - # [ - # f"{result['agent']} responded: {result['response']}" - # for result in results - # ] - # ) - # return formatted_results - - # def save(self): - # """Saves the state of all agents.""" - # state = { - # "step": self._step, - # "results": [ - # {"agent": r["agent"].name, "response": r["response"]} - # for r in self.results - # ], - # } - - # with open(self.saved_file_path_name, "w") as file: - # json.dump(state, file) - - # def load(self): - # """Loads the state of all agents.""" - # with open(self.saved_file_path_name) as file: - # state = json.load(file) - # self._step = state["step"] - # self.results = state["results"] - # return state - - # def __repr__(self): - # return ( - # f"MultiAgentCollaboration(agents={self.agents}," - # f" selection_function={self.select_next_speaker}," - # f" max_loops={self.max_loops}, autosave={self.autosave}," - # f" saved_file_path_name={self.saved_file_path_name})" - # ) diff --git a/tests/communication/test_redis.py b/tests/communication/test_redis.py index 8f8acafd..38d622ba 100644 --- a/tests/communication/test_redis.py +++ b/tests/communication/test_redis.py @@ -212,7 +212,7 @@ class RedisConversationTester: all_messages = self.conversation.return_messages_as_list() if len(all_messages) > 0: self.conversation.update(0, "user", "updated message") - updated_message = self.conversation.query(0) + self.conversation.query(0) assert True, "Update method executed successfully" def test_clear(self): diff --git a/tests/structs/test_multi_agent_collab.py b/tests/structs/test_multi_agent_collab.py index db06c9c0..6e97b479 100644 --- a/tests/structs/test_multi_agent_collab.py +++ b/tests/structs/test_multi_agent_collab.py @@ -6,7 +6,7 @@ import pytest from swarms import Agent from swarm_models import OpenAIChat -from swarms.structs.multi_agent_collab import MultiAgentCollaboration +from experimental.multi_agent_collab import MultiAgentCollaboration # Initialize the director agent diff --git a/examples/single_agent/vision_examples/vision_and_tools.py b/vision_and_tools.py similarity index 86% rename from examples/single_agent/vision_examples/vision_and_tools.py rename to vision_and_tools.py index 7b0da0b5..e330a66d 100644 --- a/examples/single_agent/vision_examples/vision_and_tools.py +++ b/vision_and_tools.py @@ -1,12 +1,8 @@ -import json from swarms.structs import Agent from swarms.prompts.logistics import ( Quality_Control_Agent_Prompt, ) -from swarms import BaseTool -import litellm -litellm._turn_on_debug() # Image for analysis factory_image = "image.jpg" @@ -43,19 +39,21 @@ def security_analysis(danger_level: str = None) -> str: return "Unknown danger level" -schema = BaseTool().function_to_dict(security_analysis) -print(json.dumps(schema, indent=4)) +# schema = BaseTool().function_to_dict(security_analysis) +# print(json.dumps(schema, indent=4)) # Quality control agent quality_control_agent = Agent( agent_name="Quality Control Agent", agent_description="A quality control agent that analyzes images and provides a detailed report on the quality of the product in the image.", - model_name="anthropic/claude-3-opus-20240229", + # model_name="anthropic/claude-3-opus-20240229", + model_name="gpt-4o-mini", system_prompt=Quality_Control_Agent_Prompt, multi_modal=True, max_loops=1, output_type="str-all-except-first", - tools_list_dictionary=[schema], + # tools_list_dictionary=[schema], + tools=[security_analysis], )