You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
9.8 KiB
271 lines
9.8 KiB
import uuid
|
|
from typing import Any, Callable, Dict, List, Optional, Union
|
|
|
|
from swarms.structs.agent import Agent
|
|
from swarms.structs.concurrent_workflow import ConcurrentWorkflow
|
|
from swarms.structs.conversation import Conversation
|
|
|
|
|
|
def _create_voting_prompt(candidate_agents: List[Agent]) -> str:
|
|
"""
|
|
Create a comprehensive voting prompt for the election.
|
|
|
|
This method generates a detailed prompt that instructs voter agents on:
|
|
- Available candidates
|
|
- Required structured output format
|
|
- Evaluation criteria
|
|
- Voting guidelines
|
|
|
|
Returns:
|
|
str: A formatted voting prompt string
|
|
"""
|
|
candidate_names = [
|
|
(agent.agent_name if hasattr(agent, "agent_name") else str(i))
|
|
for i, agent in enumerate(candidate_agents)
|
|
]
|
|
|
|
prompt = f"""
|
|
You are participating in an election to choose the best candidate agent.
|
|
|
|
Available candidates: {', '.join(candidate_names)}
|
|
|
|
Please vote for one candidate and provide your reasoning with the following structured output:
|
|
|
|
1. rationality: A detailed explanation of the reasoning behind your decision. Include logical considerations, supporting evidence, and trade-offs that were evaluated when selecting this candidate.
|
|
|
|
2. self_interest: A comprehensive discussion of how self-interest influenced your decision, if at all. Explain whether personal or role-specific incentives played a role, or if your choice was primarily for the collective benefit of the swarm.
|
|
|
|
3. candidate_agent_name: The full name or identifier of the candidate you are voting for. This should exactly match one of the available candidate names listed above.
|
|
|
|
Consider the candidates' capabilities, experience, and alignment with the swarm's objectives when making your decision.
|
|
"""
|
|
|
|
print(prompt)
|
|
|
|
return prompt
|
|
|
|
|
|
def get_vote_schema():
|
|
return [
|
|
{
|
|
"type": "function",
|
|
"function": {
|
|
"name": "vote",
|
|
"description": "Cast a vote for a CEO candidate with reasoning and self-interest analysis.",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"rationality": {
|
|
"type": "string",
|
|
"description": "A detailed explanation of the reasoning behind this voting decision.",
|
|
},
|
|
"self_interest": {
|
|
"type": "string",
|
|
"description": "A comprehensive discussion of how self-interest factored into the decision.",
|
|
},
|
|
"candidate_agent_name": {
|
|
"type": "string",
|
|
"description": "The full name or identifier of the chosen candidate.",
|
|
},
|
|
},
|
|
"required": [
|
|
"rationality",
|
|
"self_interest",
|
|
"candidate_agent_name",
|
|
],
|
|
},
|
|
},
|
|
}
|
|
]
|
|
|
|
|
|
class ElectionSwarm:
|
|
"""
|
|
A swarm system that conducts elections among multiple agents to choose the best candidate.
|
|
|
|
The ElectionSwarm orchestrates a voting process where multiple voter agents evaluate
|
|
and vote for candidate agents based on their capabilities, experience, and alignment
|
|
with swarm objectives. The system uses structured output to ensure consistent voting
|
|
format and provides detailed reasoning for each vote.
|
|
|
|
Attributes:
|
|
id (str): Unique identifier for the election swarm
|
|
name (str): Name of the election swarm
|
|
description (str): Description of the election swarm's purpose
|
|
max_loops (int): Maximum number of voting rounds (default: 1)
|
|
agents (List[Agent]): List of voter agents that will participate in the election
|
|
candidate_agents (List[Agent]): List of candidate agents to be voted on
|
|
kwargs (dict): Additional keyword arguments
|
|
show_dashboard (bool): Whether to display the election dashboard
|
|
conversation (Conversation): Conversation history for the election
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
name: str = "Election Swarm",
|
|
description: str = "An election swarm is a swarm of agents that will vote on a candidate.",
|
|
agents: Union[List[Agent], List[Callable]] = None,
|
|
candidate_agents: Union[List[Agent], List[Callable]] = None,
|
|
id: str = str(uuid.uuid4()),
|
|
max_loops: int = 1,
|
|
show_dashboard: bool = True,
|
|
**kwargs,
|
|
):
|
|
"""
|
|
Initialize the ElectionSwarm.
|
|
|
|
Args:
|
|
name (str, optional): Name of the election swarm
|
|
description (str, optional): Description of the election swarm's purpose
|
|
agents (Union[List[Agent], List[Callable]], optional): List of voter agents
|
|
candidate_agents (Union[List[Agent], List[Callable]], optional): List of candidate agents
|
|
id (str, optional): Unique identifier for the election swarm
|
|
max_loops (int, optional): Maximum number of voting rounds (default: 1)
|
|
show_dashboard (bool, optional): Whether to display the election dashboard (default: True)
|
|
**kwargs: Additional keyword arguments
|
|
"""
|
|
self.id = id
|
|
self.name = name
|
|
self.description = description
|
|
self.max_loops = max_loops
|
|
self.agents = agents
|
|
self.candidate_agents = candidate_agents
|
|
self.kwargs = kwargs
|
|
self.show_dashboard = show_dashboard
|
|
self.conversation = Conversation()
|
|
|
|
self.reliability_check()
|
|
|
|
self.setup_voter_agents()
|
|
|
|
def reliability_check(self):
|
|
"""
|
|
Check the reliability of the voter agents.
|
|
"""
|
|
if self.agents is None:
|
|
raise ValueError("Voter agents are not set")
|
|
|
|
if self.candidate_agents is None:
|
|
raise ValueError("Candidate agents are not set")
|
|
|
|
if self.max_loops is None or self.max_loops < 1:
|
|
raise ValueError("Max loops are not set")
|
|
|
|
def setup_concurrent_workflow(self):
|
|
"""
|
|
Create a concurrent workflow for running voter agents in parallel.
|
|
|
|
Returns:
|
|
ConcurrentWorkflow: A configured concurrent workflow for the election
|
|
"""
|
|
return ConcurrentWorkflow(
|
|
name=self.name,
|
|
description=self.description,
|
|
agents=self.agents,
|
|
output_type="dict-all-except-first",
|
|
show_dashboard=self.show_dashboard,
|
|
)
|
|
|
|
def run_voter_agents(
|
|
self, task: str, img: Optional[str] = None, *args, **kwargs
|
|
):
|
|
"""
|
|
Execute the voting process by running all voter agents concurrently.
|
|
|
|
Args:
|
|
task (str): The election task or question to be voted on
|
|
img (Optional[str], optional): Image path if visual voting is required
|
|
*args: Additional positional arguments
|
|
**kwargs: Additional keyword arguments
|
|
|
|
Returns:
|
|
List[Dict[str, Any]]: Results from all voter agents containing their votes and reasoning
|
|
"""
|
|
concurrent_workflow = self.setup_concurrent_workflow()
|
|
|
|
results = concurrent_workflow.run(
|
|
task=task, img=img, *args, **kwargs
|
|
)
|
|
|
|
conversation_history = (
|
|
concurrent_workflow.conversation.conversation_history
|
|
)
|
|
|
|
for message in conversation_history:
|
|
self.conversation.add(
|
|
role=message["role"], content=message["content"]
|
|
)
|
|
|
|
return results
|
|
|
|
def parse_results(
|
|
self, results: List[Dict[str, Any]]
|
|
) -> Dict[str, int]:
|
|
"""
|
|
Parse voting results to count votes for each candidate.
|
|
|
|
Args:
|
|
results (List[Dict[str, Any]]): List of voting results from voter agents
|
|
|
|
Returns:
|
|
Dict[str, int]: Dictionary mapping candidate names to their vote counts
|
|
"""
|
|
# Count the number of votes for each candidate
|
|
vote_counts = {}
|
|
for result in results:
|
|
candidate_name = result["candidate_agent_name"]
|
|
vote_counts[candidate_name] = (
|
|
vote_counts.get(candidate_name, 0) + 1
|
|
)
|
|
|
|
# Find the candidate with the most votes
|
|
|
|
return vote_counts
|
|
|
|
def run(
|
|
self, task: str, img: Optional[str] = None, *args, **kwargs
|
|
):
|
|
"""
|
|
Execute the complete election process.
|
|
|
|
This method orchestrates the entire election by:
|
|
1. Adding the task to the conversation history
|
|
2. Running all voter agents concurrently
|
|
3. Collecting and processing the voting results
|
|
|
|
Args:
|
|
task (str): The election task or question to be voted on
|
|
img (Optional[str], optional): Image path if visual voting is required
|
|
*args: Additional positional arguments
|
|
**kwargs: Additional keyword arguments
|
|
|
|
Returns:
|
|
List[Dict[str, Any]]: Complete voting results from all agents
|
|
"""
|
|
self.conversation.add(role="user", content=task)
|
|
|
|
results = self.run_voter_agents(task, img, *args, **kwargs)
|
|
|
|
print(results)
|
|
|
|
return results
|
|
|
|
def setup_voter_agents(self):
|
|
"""
|
|
Configure voter agents with structured output capabilities and voting prompts.
|
|
|
|
This method sets up each voter agent with:
|
|
- Structured output schema for consistent voting format
|
|
- Voting-specific system prompts
|
|
- Tools for structured response generation
|
|
|
|
Returns:
|
|
List[Agent]: Configured voter agents ready for the election
|
|
"""
|
|
schema = get_vote_schema()
|
|
prompt = _create_voting_prompt(self.candidate_agents)
|
|
|
|
for agent in self.agents:
|
|
agent.tools_list_dictionary = schema
|
|
agent.system_prompt += f"\n\n{prompt}"
|