pull/453/head
Kye 9 months ago
parent d5d9da1b5a
commit 351b322091

2
.gitignore vendored

@ -39,7 +39,7 @@ __pycache__/
.grit .grit
swarm-worker-01_state.json swarm-worker-01_state.json
error.txt error.txt
Devin Worker 2_state.json
# C extensions # C extensions
*.so *.so
.ruff_cache .ruff_cache

@ -0,0 +1,141 @@
import subprocess
from swarms import (
Agent,
Anthropic,
GroupChat,
GroupChatManager,
tool,
)
# Model
llm = Anthropic(
temperature=0.1,
)
# Tools
@tool
def terminal(
code: str,
):
"""
Run code in the terminal.
Args:
code (str): The code to run in the terminal.
Returns:
str: The output of the code.
"""
out = subprocess.run(
code, shell=True, capture_output=True, text=True
).stdout
return str(out)
@tool
def browser(query: str):
"""
Search the query in the browser with the `browser` tool.
Args:
query (str): The query to search in the browser.
Returns:
str: The search results.
"""
import webbrowser
url = f"https://www.google.com/search?q={query}"
webbrowser.open(url)
return f"Searching for {query} in the browser."
@tool
def create_file(file_path: str, content: str):
"""
Create a file using the file editor tool.
Args:
file_path (str): The path to the file.
content (str): The content to write to the file.
Returns:
str: The result of the file creation operation.
"""
with open(file_path, "w") as file:
file.write(content)
return f"File {file_path} created successfully."
@tool
def file_editor(file_path: str, mode: str, content: str):
"""
Edit a file using the file editor tool.
Args:
file_path (str): The path to the file.
mode (str): The mode to open the file in.
content (str): The content to write to the file.
Returns:
str: The result of the file editing operation.
"""
with open(file_path, mode) as file:
file.write(content)
return f"File {file_path} edited successfully."
# Agent
agent = Agent(
agent_name="Devin",
system_prompt=(
"Autonomous agent that can interact with humans and other"
" agents. Be Helpful and Kind. Use the tools provided to"
" assist the user. Return all code in markdown format."
),
llm=llm,
max_loops=1,
autosave=False,
dashboard=False,
streaming_on=True,
verbose=True,
stopping_token="<DONE>",
tools=[terminal, browser, file_editor, create_file],
)
# Agent
agent_two = Agent(
agent_name="Devin Worker 2",
system_prompt=(
"Autonomous agent that can interact with humans and other"
" agents. Be Helpful and Kind. Use the tools provided to"
" assist the user. Return all code in markdown format."
),
llm=llm,
max_loops=1,
autosave=False,
dashboard=False,
streaming_on=True,
verbose=True,
stopping_token="<DONE>",
tools=[terminal, browser, file_editor, create_file],
)
# Initialize the group chat
group_chat = GroupChat(
agents=[agent, agent_two],
max_round=2,
admin_name="Supreme Commander Kye",
group_objective="Research everyone at Goldman Sachs",
)
# Initialize the group chat manager
manager = GroupChatManager(groupchat=group_chat, selector=agent)
# Run the group chat manager on a task
out = manager("Generate a 10,000 word blog on health and wellness.")
print(out)

@ -11,7 +11,6 @@ from swarms.structs.base_workflow import BaseWorkflow
from swarms.structs.block_wrapper import block from swarms.structs.block_wrapper import block
from swarms.structs.concurrent_workflow import ConcurrentWorkflow from swarms.structs.concurrent_workflow import ConcurrentWorkflow
from swarms.structs.conversation import Conversation from swarms.structs.conversation import Conversation
from swarms.structs.graph_workflow import GraphWorkflow
from swarms.structs.groupchat import GroupChat, GroupChatManager from swarms.structs.groupchat import GroupChat, GroupChatManager
from swarms.structs.majority_voting import ( from swarms.structs.majority_voting import (
MajorityVoting, MajorityVoting,
@ -99,7 +98,6 @@ __all__ = [
"block", "block",
"ConcurrentWorkflow", "ConcurrentWorkflow",
"Conversation", "Conversation",
"GraphWorkflow",
"GroupChat", "GroupChat",
"GroupChatManager", "GroupChatManager",
"MajorityVoting", "MajorityVoting",

@ -413,6 +413,12 @@ class Agent:
role=self.user_name, content=tool_schema_str role=self.user_name, content=tool_schema_str
) )
# Name
self.name = agent_name
# Description
self.description = agent_description
def set_system_prompt(self, system_prompt: str): def set_system_prompt(self, system_prompt: str):
"""Set the system prompt""" """Set the system prompt"""
self.system_prompt = system_prompt self.system_prompt = system_prompt

@ -411,3 +411,6 @@ class Conversation(BaseStructure):
break break
self.conversation_history = truncated_history self.conversation_history = truncated_history
def clear(self):
self.conversation_history = []

@ -1,173 +0,0 @@
import logging
from swarms.structs.base_structure import BaseStructure
class GraphWorkflow(BaseStructure):
"""
Represents a graph-based workflow structure.
Attributes:
graph (dict): A dictionary representing the nodes and edges of the graph.
entry_point (str): The name of the entry point node in the graph.
Methods:
add(node, node_value): Adds a node to the graph with the specified value.
start(node_name): Sets the starting node for the workflow.
connect(from_node, to_node): Connects two nodes in the graph.
set_entry_point(node_name): Sets the entry point node for the workflow.
add_edge(from_node, to_node): Adds an edge between two nodes in the graph.
add_conditional_edges(from_node, condition, edge_dict): Adds conditional edges from a node to multiple nodes based on a condition.
run(): Runs the workflow and returns the graph.
Examples:
>>> from swarms.structs import GraphWorkflow
>>> graph = GraphWorkflow()
>>> graph.add("start", "Start")
>>> graph.add("end", "End")
>>> graph.start("start")
"""
def __init__(self):
self.graph = {}
self.entry_point = None
def add(self, node, node_value):
"""
Adds a node to the graph with the specified value.
Args:
node (str): The name of the node.
node_value (str): The value of the node.
Returns:
None
"""
self.graph[node] = {"value": node_value, "edges": {}}
logging.info(f"Added node: {node}")
def start(self, node_name):
"""
Sets the starting node for the workflow.
Args:
node_name (str): The name of the starting node.
Returns:
None
"""
self._check_node_exists(node_name)
def connect(self, from_node, to_node):
"""
Connects two nodes in the graph.
Args:
from_node (str): The name of the source node.
to_node (str): The name of the target node.
Returns:
None
"""
self._check_node_exists(from_node, to_node)
def set_entry_point(self, node_name):
"""
Sets the entry point node for the workflow.
Args:
node_name (str): The name of the entry point node.
Returns:
None
Raises:
ValueError: If the specified node does not exist in the graph.
"""
if node_name is self.graph:
self.entry_point = node_name
else:
raise ValueError("Node does not exist in graph")
def add_edge(self, from_node, to_node):
"""
Adds an edge between two nodes in the graph.
Args:
from_node (str): The name of the source node.
to_node (str): The name of the target node.
Returns:
None
Raises:
ValueError: If either the source or target node does not exist in the graph.
"""
if from_node in self.graph and to_node in self.graph:
self.graph[from_node]["edges"][to_node] = "edge"
else:
raise ValueError("Node does not exist in graph")
def add_conditional_edges(self, from_node, condition, edge_dict):
"""
Adds conditional edges from a node to multiple nodes based on a condition.
Args:
from_node (str): The name of the source node.
condition: The condition for the conditional edges.
edge_dict (dict): A dictionary mapping condition values to target nodes.
Returns:
None
Raises:
ValueError: If the source node or any of the target nodes do not exist in the graph.
"""
if from_node in self.graph:
for condition_value, to_node in edge_dict.items():
if to_node in self.graph:
self.graph[from_node]["edges"][to_node] = condition
else:
raise ValueError("Node does not exist in graph")
else:
raise ValueError(f"Node {from_node} does not exist in graph")
def run(self):
"""
Runs the workflow and returns the graph.
Returns:
dict: The graph representing the nodes and edges.
Raises:
ValueError: If the entry point is not set.
"""
if self.entry_point is None:
raise ValueError("Entry point not set")
return self.graph
def _check_node_exists(self, node_name):
"""Checks if a node exists in the graph.
Args:
node_name (_type_): _description_
Raises:
ValueError: _description_
"""
if node_name not in self.graph:
raise ValueError(f"Node {node_name} does not exist in graph")
def _check_nodes_exist(self, from_node, to_node):
"""
Checks if the given from_node and to_node exist in the graph.
Args:
from_node: The starting node of the edge.
to_node: The ending node of the edge.
Raises:
NodeNotFoundError: If either from_node or to_node does not exist in the graph.
"""
self._check_node_exists(from_node)
self._check_node_exists(to_node)

@ -1,12 +1,9 @@
import logging from dataclasses import dataclass, field
from dataclasses import dataclass from typing import List
from typing import Dict, List from swarms.structs.conversation import Conversation
from swarms.utils.loguru_logger import logger
from swarms.structs.agent import Agent from swarms.structs.agent import Agent
logger = logging.getLogger(__name__)
@dataclass @dataclass
class GroupChat: class GroupChat:
@ -26,24 +23,32 @@ class GroupChat:
""" """
agents: List[Agent] agents: List[Agent] = field(default_factory=list)
messages: List[Dict]
max_round: int = 10 max_round: int = 10
admin_name: str = "Admin" # the name of the admin agent admin_name: str = "Admin" # the name of the admin agent
group_objective: str = field(default_factory=str)
def __post_init__(self):
self.messages = Conversation(
system_prompt=self.group_objective,
time_enabled=True,
user=self.admin_name,
)
@property @property
def agent_names(self) -> List[str]: def agent_names(self) -> List[str]:
"""Return the names of the agents in the group chat.""" """Return the names of the agents in the group chat."""
return [agent.name for agent in self.agents] return [agent.agent_name for agent in self.agents]
def reset(self): def reset(self):
"""Reset the group chat.""" """Reset the group chat."""
logger.info("Resetting Groupchat")
self.messages.clear() self.messages.clear()
def agent_by_name(self, name: str) -> Agent: def agent_by_name(self, name: str) -> Agent:
"""Find an agent whose name is contained within the given 'name' string.""" """Find an agent whose name is contained within the given 'name' string."""
for agent in self.agents: for agent in self.agents:
if agent.name in name: if agent.agent_name in name:
return agent return agent
raise ValueError( raise ValueError(
f"No agent found with a name contained in '{name}'." f"No agent found with a name contained in '{name}'."
@ -52,7 +57,8 @@ class GroupChat:
def next_agent(self, agent: Agent) -> Agent: def next_agent(self, agent: Agent) -> Agent:
"""Return the next agent in the list.""" """Return the next agent in the list."""
return self.agents[ return self.agents[
(self.agent_names.index(agent.name) + 1) % len(self.agents) (self.agent_names.index(agent.agent_name) + 1)
% len(self.agents)
] ]
def select_speaker_msg(self): def select_speaker_msg(self):
@ -65,9 +71,11 @@ class GroupChat:
Then select the next role from {self.agent_names} to play. Only return the role. Then select the next role from {self.agent_names} to play. Only return the role.
""" """
# @try_except_wrapper
def select_speaker(self, last_speaker: Agent, selector: Agent): def select_speaker(self, last_speaker: Agent, selector: Agent):
"""Select the next speaker.""" """Select the next speaker."""
selector.update_system_message(self.select_speaker_msg()) logger.info("Selecting a New Speaker")
selector.system_prompt = self.select_speaker_msg()
# Warn if GroupChat is underpopulated, without established changing behavior # Warn if GroupChat is underpopulated, without established changing behavior
n_agents = len(self.agent_names) n_agents = len(self.agent_names)
@ -77,24 +85,16 @@ class GroupChat:
" Direct communication would be more efficient." " Direct communication would be more efficient."
) )
name = selector.generate_reply( self.messages.add(
self.format_history( role=self.admin_name,
self.messages content=f"Read the above conversation. Then select the next most suitable role from {self.agent_names} to play. Only return the role.",
+ [
{
"role": "system",
"content": (
"Read the above conversation. Then"
" select the next most suitable role"
f" from {self.agent_names} to play. Only"
" return the role."
),
}
]
)
) )
name = selector.run(self.messages.return_history_as_string())
try: try:
return self.agent_by_name(name["content"]) name = self.agent_by_name(name)
print(name)
return name
except ValueError: except ValueError:
return self.next_agent(last_speaker) return self.next_agent(last_speaker)
@ -106,26 +106,11 @@ class GroupChat:
""" """
return "\n".join( return "\n".join(
[ [
f"{agent.name}: {agent.system_message}" f"{agent.agent_name}: {agent.system_prompt}"
for agent in self.agents for agent in self.agents
] ]
) )
def format_history(self, messages: List[Dict]) -> str:
"""Format the history of the messages.
Args:
messages (List[Dict]): _description_
Returns:
str: _description_
"""
formatted_messages = []
for message in messages:
formatted_message = f"'{message['role']}:{message['content']}"
formatted_messages.append(formatted_message)
return "\n".join(formatted_messages)
@dataclass @dataclass
class GroupChatManager: class GroupChatManager:
@ -147,6 +132,7 @@ class GroupChatManager:
groupchat: GroupChat groupchat: GroupChat
selector: Agent selector: Agent
# @try_except_wrapper
def __call__(self, task: str): def __call__(self, task: str):
"""Call 'GroupChatManager' instance as a function. """Call 'GroupChatManager' instance as a function.
@ -156,17 +142,20 @@ class GroupChatManager:
Returns: Returns:
_type_: _description_ _type_: _description_
""" """
self.groupchat.messages.append( logger.info(
{"role": self.selector.name, "content": task} f"Activating Groupchat with {len(self.groupchat.agents)} Agents"
) )
self.groupchat.messages.add(self.selector.agent_name, task)
for i in range(self.groupchat.max_round): for i in range(self.groupchat.max_round):
speaker = self.groupchat.select_speaker( speaker = self.groupchat.select_speaker(
last_speaker=self.selector, selector=self.selector last_speaker=self.selector, selector=self.selector
) )
reply = speaker.generate_reply( reply = speaker.run(
self.groupchat.format_history(self.groupchat.messages) self.groupchat.messages.return_history_as_string()
) )
self.groupchat.messages.append(reply) self.groupchat.messages.add(speaker.agent_name, reply)
print(reply) print(reply)
if i == self.groupchat.max_round - 1: if i == self.groupchat.max_round - 1:
break break

@ -98,7 +98,7 @@ def execute_tool_by_name(
action = output_parser.parse(text) action = output_parser.parse(text)
tools = {t.name: t for t in tools} tools = {t.name: t for t in tools}
logger.info(f"Tools available: {tools}") # logger.info(f"Tools available: {tools}")
if action.name == stop_token: if action.name == stop_token:
return action.args["response"] return action.args["response"]

Loading…
Cancel
Save