Merge branch 'kyegomez:master' into master

pull/459/head
evelynmitchell 1 year ago committed by GitHub
commit 87a80f936b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -16,7 +16,7 @@ Individual agents face five significant challenges that hinder their deployment
----
## Install
`$ pip3 install -U swarms`
`$ pip3 install -U swarms==4.9.7`
---
@ -479,54 +479,40 @@ Sequential Workflow enables you to sequentially execute tasks with `Agent` and t
✅ Utilizes Agent class
```python
import os
from dotenv import load_dotenv
from swarms import Agent, OpenAIChat, SequentialWorkflow
from swarms import Agent, SequentialWorkflow, Anthropic
load_dotenv()
# Load the environment variables
api_key = os.getenv("OPENAI_API_KEY")
# Initialize the language model agent (e.g., GPT-3)
llm = Anthropic()
# Initialize the language agent
llm = OpenAIChat(
temperature=0.5, model_name="gpt-4", openai_api_key=api_key, max_tokens=4000
# Initialize agents for individual tasks
agent1 = Agent(
agent_name="Blog generator",
system_prompt="Generate a blog post like stephen king",
llm=llm,
max_loops=1,
dashboard=False,
tools=[],
)
# Initialize the agent with the language agent
agent1 = Agent(llm=llm, max_loops=1)
# Create another agent for a different task
agent2 = Agent(llm=llm, max_loops=1)
# Create another agent for a different task
agent3 = Agent(llm=llm, max_loops=1)
# Create the workflow
workflow = SequentialWorkflow(max_loops=1)
# Add tasks to the workflow
workflow.add(
agent1,
"Generate a 10,000 word blog on health and wellness.",
agent2 = Agent(
agent_name="summarizer",
system_prompt="Sumamrize the blog post",
llm=llm,
max_loops=1,
dashboard=False,
tools=[],
)
# Suppose the next task takes the output of the first task as input
workflow.add(
agent2,
"Summarize the generated blog",
# Create the Sequential workflow
workflow = SequentialWorkflow(
agents=[agent1, agent2], max_loops=1, verbose=False
)
# Run the workflow
workflow.run()
workflow.run(
"Generate a blog post on how swarms of agents can help businesses grow."
)
# Output the results
for task in workflow.tasks:
print(f"Task: {task.description}, Result: {task.result}")
```

@ -0,0 +1,978 @@
## Building Analyst Agents with Swarms to write Business Reports
> Jupyter Notebook accompanying this post is accessible at: [Business Analyst Agent Notebook](https://github.com/kyegomez/swarms/blob/master/playground/business-analyst-agent.ipynb)
Solving a business problem often involves preparing a Business Case Report. This report comprehensively analyzes the problem, evaluates potential solutions, and provides evidence-based recommendations and an implementation plan to effectively address the issue and drive business value. While the process of preparing one requires an experienced business analyst, the workflow can be augmented using AI agents. Two candidates stick out as areas to work on:
- Developing an outline to solve the problem
- Doing background research and gathering data
In this post, we will explore how Swarms agents can be used to tackle a busuiness problem by outlining the solution, conducting background research and generating a preliminary report.
Before we proceed, this blog uses 3 API tools. Please obtain the following keys and store them in a `.env` file in the same folder as this file.
- **[OpenAI API](https://openai.com/blog/openai-api)** as `OPENAI_API_KEY`
- **[TavilyAI API](https://app.tavily.com/home)** `TAVILY_API_KEY`
- **[KayAI API](https://www.kay.ai/)** as `KAY_API_KEY`
```python
import dotenv
dotenv.load_dotenv() # Load environment variables from .env file
```
### Developing an Outline to solve the problem
Assume the business problem is: **How do we improve Nike's revenue in Q3 2024?** We first create a planning agent to break down the problem into dependent sub-problems.
#### Step 1. Defining the Data Model and Tool Schema
Using Pydantic, we define a structure to help the agent generate sub-problems.
- **QueryType:** Questions are either standalone or involve a combination of multiple others
- **Query:** Defines structure of a question.
- **QueryPlan:** Allows generation of a dependency graph of sub-questions
```python
import enum
from typing import List
from pydantic import Field, BaseModel
class QueryType(str, enum.Enum):
"""Enumeration representing the types of queries that can be asked to a question answer system."""
SINGLE_QUESTION = "SINGLE"
MERGE_MULTIPLE_RESPONSES = "MERGE_MULTIPLE_RESPONSES"
class Query(BaseModel):
"""Class representing a single question in a query plan."""
id: int = Field(..., description="Unique id of the query")
question: str = Field(
...,
description="Question asked using a question answering system",
)
dependencies: List[int] = Field(
default_factory=list,
description="List of sub questions that need to be answered before asking this question",
)
node_type: QueryType = Field(
default=QueryType.SINGLE_QUESTION,
description="Type of question, either a single question or a multi-question merge",
)
class QueryPlan(BaseModel):
"""Container class representing a tree of questions to ask a question answering system."""
query_graph: List[Query] = Field(
..., description="The query graph representing the plan"
)
def _dependencies(self, ids: List[int]) -> List[Query]:
"""Returns the dependencies of a query given their ids."""
return [q for q in self.query_graph if q.id in ids]
```
Also, a `tool_schema` needs to be defined. It is an instance of `QueryPlan` and is used to initialize the agent.
```python
tool_schema = QueryPlan(
query_graph = [query.dict() for query in [
Query(
id=1,
question="How do we improve Nike's revenue in Q3 2024?",
dependencies=[2],
node_type=QueryType('SINGLE')
),
# ... other queries ...
]]
)
```
#### Step 2. Defining the Planning Agent
We specify the query, task specification and an appropriate system prompt.
```python
from swarms import OpenAIChat
from swarms import Agent
query = "How do we improve Nike's revenue in Q3 2024?"
task = f"Consider: {query}. Generate just the correct query plan in JSON format."
system_prompt = (
"You are a world class query planning algorithm "
"capable of breaking apart questions into its "
"dependency queries such that the answers can be "
"used to inform the parent question. Do not answer "
"the questions, simply provide a correct compute "
"graph with good specific questions to ask and relevant "
"dependencies. Before you call the function, think "
"step-by-step to get a better understanding of the problem."
)
llm = OpenAIChat(
temperature=0.0, model_name="gpt-4", max_tokens=4000
)
```
Then, we proceed with agent definition.
```python
# Initialize the agent
agent = Agent(
agent_name="Query Planner",
system_prompt=system_prompt,
# Set the tool schema to the JSON string -- this is the key difference
tool_schema=tool_schema,
llm=llm,
max_loops=1,
autosave=True,
dashboard=False,
streaming_on=True,
verbose=True,
interactive=False,
# Set the output type to the tool schema which is a BaseModel
output_type=tool_schema, # or dict, or str
metadata_output_type="json",
# List of schemas that the agent can handle
list_tool_schemas=[tool_schema],
function_calling_format_type="OpenAI",
function_calling_type="json", # or soon yaml
)
```
#### Step 3. Obtaining Outline from Planning Agent
We now run the agent, and since its output is in JSON format, we can load it as a dictionary.
```python
generated_data = agent.run(task)
```
At times the agent could return extra content other than JSON. Below function will filter it out.
```python
def process_json_output(content):
# Find the index of the first occurrence of '```json\n'
start_index = content.find('```json\n')
if start_index == -1:
# If '```json\n' is not found, return the original content
return content
# Return the part of the content after '```json\n' and remove the '```' at the end
return content[start_index + len('```json\n'):].rstrip('`')
# Use the function to clean up the output
json_content = process_json_output(generated_data.content)
import json
# Load the JSON string into a Python object
json_object = json.loads(json_content)
# Convert the Python object back to a JSON string
json_content = json.dumps(json_object, indent=2)
# Print the JSON string
print(json_content)
```
Below is the output this produces
```json
{
"main_query": "How do we improve Nike's revenue in Q3 2024?",
"sub_queries": [
{
"id": "1",
"query": "What is Nike's current revenue trend?"
},
{
"id": "2",
"query": "What are the projected market trends for the sports apparel industry in 2024?"
},
{
"id": "3",
"query": "What are the current successful strategies being used by Nike's competitors?",
"dependencies": [
"2"
]
},
{
"id": "4",
"query": "What are the current and projected economic conditions in Nike's major markets?",
"dependencies": [
"2"
]
},
{
"id": "5",
"query": "What are the current consumer preferences in the sports apparel industry?",
"dependencies": [
"2"
]
},
{
"id": "6",
"query": "What are the potential areas of improvement in Nike's current business model?",
"dependencies": [
"1"
]
},
{
"id": "7",
"query": "What are the potential new markets for Nike to explore in 2024?",
"dependencies": [
"2",
"4"
]
},
{
"id": "8",
"query": "What are the potential new products or services Nike could introduce in 2024?",
"dependencies": [
"5"
]
},
{
"id": "9",
"query": "What are the potential marketing strategies Nike could use to increase its revenue in Q3 2024?",
"dependencies": [
"3",
"5",
"7",
"8"
]
},
{
"id": "10",
"query": "What are the potential cost-saving strategies Nike could implement to increase its net revenue in Q3 2024?",
"dependencies": [
"6"
]
}
]
}
```
The JSON dictionary is not convenient for humans to process. We make a directed graph out of it.
```python
import networkx as nx
import matplotlib.pyplot as plt
import textwrap
import random
# Create a directed graph
G = nx.DiGraph()
# Define a color map
color_map = {}
# Add nodes and edges to the graph
for sub_query in json_object['sub_queries']:
# Check if 'dependencies' key exists in sub_query, if not, initialize it as an empty list
if 'dependencies' not in sub_query:
sub_query['dependencies'] = []
# Assign a random color for each node
color_map[sub_query['id']] = "#{:06x}".format(random.randint(0, 0xFFFFFF))
G.add_node(sub_query['id'], label=textwrap.fill(sub_query['query'], width=20))
for dependency in sub_query['dependencies']:
G.add_edge(dependency, sub_query['id'])
# Draw the graph
pos = nx.spring_layout(G)
nx.draw(G, pos, with_labels=True, node_size=800, node_color=[color_map[node] for node in G.nodes()], node_shape="o", alpha=0.5, linewidths=40)
# Prepare labels for legend
labels = nx.get_node_attributes(G, 'label')
handles = [plt.Line2D([0], [0], marker='o', color=color_map[node], label=f"{node}: {label}", markersize=10, linestyle='None') for node, label in labels.items()]
# Create a legend
plt.legend(handles=handles, title="Queries", bbox_to_anchor=(1.05, 1), loc='upper left')
plt.show()
```
This produces the below diagram which makes the plan much more convenient to understand.
![Query Plan Diagram](../assets/img/docs/query-plan.png)
### Doing Background Research and Gathering Data
At this point, we have solved the first half of the problem. We have an outline consisting of sub-problems to to tackled to solve our business problem. This will form the overall structure of our report. We now need to research information for each sub-problem in order to write an informed report. This mechanically intensive and is the aspect that will most benefit from Agentic intervention.
Essentially, we can spawn parallel agents to gather the data. Each agent will have 2 tools:
- Internet access
- Financial data retrieval
As they run parallely, they will add their knowledge into a common long-term memory. We will then spawn a separate report writing agent with access to this memory to generate our business case report.
#### Step 4. Defining Tools for Worker Agents
Let us first define the 2 tools.
```python
import os
from typing import List, Dict
from swarms import tool
os.environ['TAVILY_API_KEY'] = os.getenv('TAVILY_API_KEY')
os.environ["KAY_API_KEY"] = os.getenv('KAY_API_KEY')
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.pydantic_v1 import BaseModel, Field
from kay.rag.retrievers import KayRetriever
@tool
def browser(query: str) -> str:
"""
Search the query in the browser with the Tavily API tool.
Args:
query (str): The query to search in the browser.
Returns:
str: The search results
"""
internet_search = TavilySearchResults()
results = internet_search.invoke({"query": query})
response = ''
for result in results:
response += (result['content'] + '\n')
return response
@tool
def kay_retriever(query: str) -> str:
"""
Search the financial data query with the KayAI API tool.
Args:
query (str): The query to search in the KayRetriever.
Returns:
str: The first context retrieved as a string.
"""
# Initialize the retriever
retriever = KayRetriever(dataset_id = "company", data_types=["10-K", "10-Q", "8-K", "PressRelease"])
# Query the retriever
context = retriever.query(query=query,num_context=1)
return context[0]['chunk_embed_text']
```
#### Step 5. Defining Long-Term Memory
As mentioned previously, the worker agents running parallely, will pool their knowledge into a common memory. Let us define that.
```python
import logging
import os
import uuid
from typing import Callable, List, Optional
import chromadb
import numpy as np
from dotenv import load_dotenv
from swarms.utils.data_to_text import data_to_text
from swarms.utils.markdown_message import display_markdown_message
from swarms.memory.base_vectordb import AbstractVectorDatabase
# Results storage using local ChromaDB
class ChromaDB(AbstractVectorDatabase):
"""
ChromaDB database
Args:
metric (str): The similarity metric to use.
output (str): The name of the collection to store the results in.
limit_tokens (int, optional): The maximum number of tokens to use for the query. Defaults to 1000.
n_results (int, optional): The number of results to retrieve. Defaults to 2.
Methods:
add: _description_
query: _description_
Examples:
>>> chromadb = ChromaDB(
>>> metric="cosine",
>>> output="results",
>>> llm="gpt3",
>>> openai_api_key=OPENAI_API_KEY,
>>> )
>>> chromadb.add(task, result, result_id)
"""
def __init__(
self,
metric: str = "cosine",
output_dir: str = "swarms",
limit_tokens: Optional[int] = 1000,
n_results: int = 3,
embedding_function: Callable = None,
docs_folder: str = None,
verbose: bool = False,
*args,
**kwargs,
):
self.metric = metric
self.output_dir = output_dir
self.limit_tokens = limit_tokens
self.n_results = n_results
self.docs_folder = docs_folder
self.verbose = verbose
# Disable ChromaDB logging
if verbose:
logging.getLogger("chromadb").setLevel(logging.INFO)
# Create Chroma collection
chroma_persist_dir = "chroma"
chroma_client = chromadb.PersistentClient(
settings=chromadb.config.Settings(
persist_directory=chroma_persist_dir,
),
*args,
**kwargs,
)
# Embedding model
if embedding_function:
self.embedding_function = embedding_function
else:
self.embedding_function = None
# Create ChromaDB client
self.client = chromadb.Client()
# Create Chroma collection
self.collection = chroma_client.get_or_create_collection(
name=output_dir,
metadata={"hnsw:space": metric},
embedding_function=self.embedding_function,
# data_loader=self.data_loader,
*args,
**kwargs,
)
display_markdown_message(
"ChromaDB collection created:"
f" {self.collection.name} with metric: {self.metric} and"
f" output directory: {self.output_dir}"
)
# If docs
if docs_folder:
display_markdown_message(
f"Traversing directory: {docs_folder}"
)
self.traverse_directory()
def add(
self,
document: str,
*args,
**kwargs,
):
"""
Add a document to the ChromaDB collection.
Args:
document (str): The document to be added.
condition (bool, optional): The condition to check before adding the document. Defaults to True.
Returns:
str: The ID of the added document.
"""
try:
doc_id = str(uuid.uuid4())
self.collection.add(
ids=[doc_id],
documents=[document],
*args,
**kwargs,
)
print('-----------------')
print("Document added successfully")
print('-----------------')
return doc_id
except Exception as e:
raise Exception(f"Failed to add document: {str(e)}")
def query(
self,
query_text: str,
*args,
**kwargs,
):
"""
Query documents from the ChromaDB collection.
Args:
query (str): The query string.
n_docs (int, optional): The number of documents to retrieve. Defaults to 1.
Returns:
dict: The retrieved documents.
"""
try:
docs = self.collection.query(
query_texts=[query_text],
n_results=self.n_results,
*args,
**kwargs,
)["documents"]
return docs[0]
except Exception as e:
raise Exception(f"Failed to query documents: {str(e)}")
def traverse_directory(self):
"""
Traverse through every file in the given directory and its subdirectories,
and return the paths of all files.
Parameters:
- directory_name (str): The name of the directory to traverse.
Returns:
- list: A list of paths to each file in the directory and its subdirectories.
"""
added_to_db = False
for root, dirs, files in os.walk(self.docs_folder):
for file in files:
file = os.path.join(self.docs_folder, file)
_, ext = os.path.splitext(file)
data = data_to_text(file)
added_to_db = self.add([data])
print(f"{file} added to Database")
return added_to_db
```
We can now proceed to initialize the memory.
```python
from chromadb.utils import embedding_functions
default_ef = embedding_functions.DefaultEmbeddingFunction()
memory = ChromaDB(
metric="cosine",
n_results=3,
output_dir="results",
embedding_function=default_ef
)
```
#### Step 6. Defining Worker Agents
The Worker Agent sub-classes the `Agent` class. The only different between these 2 is in how the `run()` method works. In the `Agent` class, `run()` simply returns the set of tool commands to run, but does not execute it. We, however, desire this. In addition, after we run our tools, we get the relevant information as output. We want to add this information to our memory. Hence, to incorporate these 2 changes, we define `WorkerAgent` as follows.
```python
class WorkerAgent(Agent):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def run(self, task, *args, **kwargs):
response = super().run(task, *args, **kwargs)
print(response.content)
json_dict = json.loads(process_json_output(response.content))
#print(json.dumps(json_dict, indent=2))
if response!=None:
try:
commands = json_dict["commands"]
except:
commands = [json_dict['command']]
for command in commands:
tool_name = command["name"]
if tool_name not in ['browser', 'kay_retriever']:
continue
query = command["args"]["query"]
# Get the tool by its name
tool = globals()[tool_name]
tool_response = tool(query)
# Add tool's output to long term memory
self.long_term_memory.add(tool_response)
```
We can then instantiate an object of the `WorkerAgent` class.
```python
worker_agent = WorkerAgent(
agent_name="Worker Agent",
system_prompt=(
"Autonomous agent that can interact with browser, "
"financial data retriever and other agents. Be Helpful "
"and Kind. Use the tools provided to assist the user. "
"Generate the plan with list of commands in JSON format."
),
llm=OpenAIChat(
temperature=0.0, model_name="gpt-4", max_tokens=4000
),
max_loops="auto",
autosave=True,
dashboard=False,
streaming_on=True,
verbose=True,
stopping_token="<DONE>",
interactive=True,
tools=[browser, kay_retriever],
long_term_memory=memory,
code_interpreter=True,
)
```
#### Step 7. Running the Worker Agents
At this point, we need to setup a concurrent workflow. While the order of adding tasks to the workflow doesn't matter (since they will all run concurrently late when executed), we can take some time to define an order for these tasks. This order will come in handy later when writing the report using our Writer Agent.
The order we will follow is Breadth First Traversal (BFT) of the sub-queries in the graph we had made earlier (shown below again for reference). BFT makes sense to be used here because we want all the dependent parent questions to be answered before answering the child question. Also, since we could have independent subgraphs, we will also perform BFT separately on each subgraph.
![Query Plan Mini](../assets/img/docs/query-plan-mini.png)
Below is the code that produces the order of processing sub-queries.
```python
from collections import deque, defaultdict
# Define the graph nodes
nodes = json_object['sub_queries']
# Create a graph from the nodes
graph = defaultdict(list)
for node in nodes:
for dependency in node['dependencies']:
graph[dependency].append(node['id'])
# Find all nodes with no dependencies (potential starting points)
start_nodes = [node['id'] for node in nodes if not node['dependencies']]
# Adjust the BFT function to handle dependencies correctly
def bft_corrected(start, graph, nodes_info):
visited = set()
queue = deque([start])
order = []
while queue:
node = queue.popleft()
if node not in visited:
# Check if all dependencies of the current node are visited
node_dependencies = [n['id'] for n in nodes if n['id'] == node][0]
dependencies_met = all(dep in visited for dep in nodes_info[node_dependencies]['dependencies'])
if dependencies_met:
visited.add(node)
order.append(node)
# Add only nodes to the queue whose dependencies are fully met
for next_node in graph[node]:
if all(dep in visited for dep in nodes_info[next_node]['dependencies']):
queue.append(next_node)
else:
# Requeue the node to check dependencies later
queue.append(node)
return order
# Dictionary to access node information quickly
nodes_info = {node['id']: node for node in nodes}
# Perform BFT for each unvisited start node using the corrected BFS function
visited_global = set()
bfs_order = []
for start in start_nodes:
if start not in visited_global:
order = bft_corrected(start, graph, nodes_info)
bfs_order.extend(order)
visited_global.update(order)
print("BFT Order:", bfs_order)
```
This produces the following output.
```python
BFT Order: ['1', '6', '10', '2', '3', '4', '5', '7', '8', '9']
```
Now, let's define our `ConcurrentWorkflow` and run it.
```python
import os
from dotenv import load_dotenv
from swarms import Agent, ConcurrentWorkflow, OpenAIChat, Task
# Create a workflow
workflow = ConcurrentWorkflow(max_workers=5)
task_list = []
for node in bfs_order:
sub_query =nodes_info[node]['query']
task = Task(worker_agent, sub_query)
print('-----------------')
print("Added task: ", sub_query)
print('-----------------')
task_list.append(task)
workflow.add(tasks=task_list)
# Run the workflow
workflow.run()
```
Below is part of the output this workflow produces. We clearly see the thought process of the agent and the plan it came up to solve a particular sub-query. In addition, we see the tool-calling schema it produces in `"command"`.
```python
...
...
content='\n{\n "thoughts": {\n "text": "To find out Nike\'s current revenue trend, I will use the financial data retriever tool to search for \'Nike revenue trend\'.",\n "reasoning": "The financial data retriever tool allows me to search for specific financial data, so I can look up the current revenue trend of Nike.", \n "plan": "Use the financial data retriever tool to search for \'Nike revenue trend\'. Parse the result to get the current revenue trend and format that into a readable report."\n },\n "command": {\n "name": "kay_retriever", \n "args": {\n "query": "Nike revenue trend"\n }\n }\n}\n```' response_metadata={'token_usage': {'completion_tokens': 152, 'prompt_tokens': 1527, 'total_tokens': 1679}, 'model_name': 'gpt-4', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}
Saved agent state to: Worker Agent_state.json
{
"thoughts": {
"text": "To find out Nike's current revenue trend, I will use the financial data retriever tool to search for 'Nike revenue trend'.",
"reasoning": "The financial data retriever tool allows me to search for specific financial data, so I can look up the current revenue trend of Nike.",
"plan": "Use the financial data retriever tool to search for 'Nike revenue trend'. Parse the result to get the current revenue trend and format that into a readable report."
},
"command": {
"name": "kay_retriever",
"args": {
"query": "Nike revenue trend"
}
}
}
-----------------
Document added successfully
-----------------
...
...
```
Here, `"name"` pertains to the name of the tool to be called and `"args"` is the arguments to be passed to the tool call. Like mentioned before, we modify `Agent`'s default behaviour in `WorkerAgent`. Hence, the tool call is executed here and its results (information from web pages and Kay Retriever API) are added to long-term memory. We get confirmation for this from the message `Document added successfully`.
#### Step 7. Generating the report using Writer Agent
At this point, our Worker Agents have gathered all the background information required to generate the report. We have also defined a coherent structure to write the report, which is following the BFT order to answering the sub-queries. Now it's time to define a Writer Agent and call it sequentially in the order of sub-queries.
```python
from swarms import Agent, OpenAIChat, tool
agent = Agent(
agent_name="Writer Agent",
agent_description=(
"This agent writes reports based on information in long-term memory"
),
system_prompt=(
"You are a world-class financial report writer. "
"Write analytical and accurate responses using memory to answer the query. "
"Do not mention use of long-term memory in the report. "
"Do not mention Writer Agent in response."
"Return only response content in strict markdown format."
),
llm=OpenAIChat(temperature=0.2, model='gpt-3.5-turbo'),
max_loops=1,
autosave=True,
verbose=True,
long_term_memory=memory,
)
```
The report individual sections of the report will be collected in a list.
```python
report = []
```
Let us now run the writer agent.
```python
for node in bfs_order:
sub_query =nodes_info[node]['query']
print("Running task: ", sub_query)
out = agent.run(f"Consider: {sub_query}. Write response in strict markdown format using long-term memory. Do not mention Writer Agent in response.")
print(out)
try:
report.append(out.content)
except:
pass
```
Now, we need to clean up the repoort a bit to make it render professionally.
```python
# Remove any content before the first "#" as that signals start of heading
# Anything before this usually contains filler content
stripped_report = [entry[entry.find('#'):] if '#' in entry else entry for entry in report]
report = stripped_report
# At times the LLM outputs \\n instead of \n
cleaned_report = [entry.replace("\\n", "\n") for entry in report]
import re
# Function to clean up unnecessary metadata from the report entries
def clean_report(report):
cleaned_report = []
for entry in report:
# This pattern matches 'response_metadata={' followed by any characters that are not '}' (non-greedy),
# possibly nested inside other braces, until the closing '}'.
cleaned_entry = re.sub(r"response_metadata=\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}", "", entry, flags=re.DOTALL)
cleaned_report.append(cleaned_entry)
return cleaned_report
# Apply the cleaning function to the markdown report
cleaned_report = clean_report(cleaned_report)
```
After cleaning, we append parts of the report together to get out final report.
```python
final_report = ' \n '.join(cleaned_report)
```
In Jupyter Notebook, we can use the below code to render it in Markdown.
```python
from IPython.display import display, Markdown
display(Markdown(final_report))
```
## Final Generated Report
### Nike's Current Revenue Trend
Nike's current revenue trend has been steadily increasing over the past few years. In the most recent fiscal year, Nike reported a revenue of $37.4 billion, which was a 7% increase from the previous year. This growth can be attributed to strong sales in key markets, successful marketing campaigns, and a focus on innovation in product development. Overall, Nike continues to demonstrate strong financial performance and is well-positioned for future growth.
### Potential Areas of Improvement in Nike's Business Model
1. **Sustainability Practices**: Nike could further enhance its sustainability efforts by reducing its carbon footprint, using more eco-friendly materials, and ensuring ethical labor practices throughout its supply chain.
2. **Diversification of Product Portfolio**: While Nike is known for its athletic footwear and apparel, diversifying into new product categories or expanding into untapped markets could help drive growth and mitigate risks associated with a single product line.
3. **E-commerce Strategy**: Improving the online shopping experience, investing in digital marketing, and leveraging data analytics to personalize customer interactions could boost online sales and customer loyalty.
4. **Innovation and R&D**: Continuously investing in research and development to stay ahead of competitors, introduce new technologies, and enhance product performance could help maintain Nike's competitive edge in the market.
5. **Brand Image and Reputation**: Strengthening brand image through effective marketing campaigns, community engagement, and transparent communication with stakeholders can help build trust and loyalty among consumers.
### Potential Cost-Saving Strategies for Nike to Increase Net Revenue in Q3 2024
1. **Supply Chain Optimization**: Streamlining the supply chain, reducing transportation costs, and improving inventory management can lead to significant cost savings for Nike.
2. **Operational Efficiency**: Implementing lean manufacturing practices, reducing waste, and optimizing production processes can help lower production costs and improve overall efficiency.
3. **Outsourcing Non-Core Functions**: Outsourcing non-core functions such as IT services, customer support, or logistics can help reduce overhead costs and focus resources on core business activities.
4. **Energy Efficiency**: Investing in energy-efficient technologies, renewable energy sources, and sustainable practices can lower utility costs and demonstrate a commitment to environmental responsibility.
5. **Negotiating Supplier Contracts**: Negotiating better terms with suppliers, leveraging economies of scale, and exploring alternative sourcing options can help lower procurement costs and improve margins.
By implementing these cost-saving strategies, Nike can improve its bottom line and increase net revenue in Q3 2024.
### Projected Market Trends for the Sports Apparel Industry in 2024
1. **Sustainable Fashion**: Consumers are increasingly demanding eco-friendly and sustainable products, leading to a rise in sustainable sportswear options in the market.
2. **Digital Transformation**: The sports apparel industry is expected to continue its shift towards digital platforms, with a focus on e-commerce, personalized shopping experiences, and digital marketing strategies.
3. **Athleisure Wear**: The trend of athleisure wear, which combines athletic and leisure clothing, is projected to remain popular in 2024 as consumers seek comfort and versatility in their apparel choices.
4. **Innovative Materials**: Advances in technology and material science are likely to drive the development of innovative fabrics and performance-enhancing materials in sports apparel, catering to the demand for high-quality and functional products.
5. **Health and Wellness Focus**: With a growing emphasis on health and wellness, sports apparel brands are expected to incorporate features that promote comfort, performance, and overall well-being in their products.
Overall, the sports apparel industry in 2024 is anticipated to be characterized by sustainability, digitalization, innovation, and a focus on consumer health and lifestyle trends.
### Current Successful Strategies Used by Nike's Competitors
1. **Adidas**: Adidas has been successful in leveraging collaborations with celebrities and designers to create limited-edition collections that generate hype and drive sales. They have also focused on sustainability initiatives, such as using recycled materials in their products, to appeal to environmentally conscious consumers.
2. **Under Armour**: Under Armour has differentiated itself by targeting performance-driven athletes and emphasizing technological innovation in their products. They have also invested heavily in digital marketing and e-commerce to reach a wider audience and enhance the customer shopping experience.
3. **Puma**: Puma has successfully capitalized on the athleisure trend by offering stylish and versatile sportswear that can be worn both in and out of the gym. They have also focused on building partnerships with influencers and sponsoring high-profile athletes to increase brand visibility and credibility.
4. **Lululemon**: Lululemon has excelled in creating a strong community around its brand, hosting events, classes, and collaborations to engage with customers beyond just selling products. They have also prioritized customer experience by offering personalized services and creating a seamless omnichannel shopping experience.
5. **New Balance**: New Balance has carved out a niche in the market by emphasizing quality craftsmanship, heritage, and authenticity in their products. They have also focused on customization and personalization options for customers, allowing them to create unique and tailored footwear and apparel.
Overall, Nike's competitors have found success through a combination of innovative product offerings, strategic marketing initiatives, and a focus on customer engagement and experience.
### Current and Projected Economic Conditions in Nike's Major Markets
1. **United States**: The United States, being one of Nike's largest markets, is currently experiencing moderate economic growth driven by consumer spending, low unemployment rates, and a rebound in manufacturing. However, uncertainties surrounding trade policies, inflation, and interest rates could impact consumer confidence and spending in the near future.
2. **China**: China remains a key market for Nike, with a growing middle class and increasing demand for sportswear and athletic footwear. Despite recent trade tensions with the U.S., China's economy is projected to continue expanding, driven by domestic consumption, infrastructure investments, and technological advancements.
3. **Europe**: Economic conditions in Europe vary across countries, with some experiencing sluggish growth due to Brexit uncertainties, political instability, and trade tensions. However, overall consumer confidence is improving, and the sports apparel market is expected to grow, driven by e-commerce and sustainability trends.
4. **Emerging Markets**: Nike's presence in emerging markets such as India, Brazil, and Southeast Asia provides opportunities for growth, given the rising disposable incomes, urbanization, and increasing focus on health and fitness. However, challenges such as currency fluctuations, regulatory changes, and competition from local brands could impact Nike's performance in these markets.
Overall, Nike's major markets exhibit a mix of opportunities and challenges, with economic conditions influenced by global trends, geopolitical factors, and consumer preferences."
### Current Consumer Preferences in the Sports Apparel Industry
1. **Sustainability**: Consumers are increasingly seeking eco-friendly and sustainable options in sports apparel, driving brands to focus on using recycled materials, reducing waste, and promoting ethical practices.
2. **Athleisure**: The trend of athleisure wear continues to be popular, with consumers looking for versatile and comfortable clothing that can be worn both during workouts and in everyday life.
3. **Performance and Functionality**: Consumers prioritize performance-enhancing features in sports apparel, such as moisture-wicking fabrics, breathable materials, and ergonomic designs that enhance comfort and mobility.
4. **Personalization**: Customization options, personalized fit, and unique design elements are appealing to consumers who seek individuality and exclusivity in their sports apparel choices.
5. **Brand Transparency**: Consumers value transparency in brand practices, including supply chain transparency, ethical sourcing, and clear communication on product quality and manufacturing processes.
Overall, consumer preferences in the sports apparel industry are shifting towards sustainability, versatility, performance, personalization, and transparency, influencing brand strategies and product offerings.
### Potential New Markets for Nike to Explore in 2024
1. **India**: With a growing population, increasing disposable incomes, and a rising interest in health and fitness, India presents a significant opportunity for Nike to expand its presence and tap into a large consumer base.
2. **Africa**: The African market, particularly countries with emerging economies and a young population, offers potential for Nike to introduce its products and capitalize on the growing demand for sportswear and athletic footwear.
3. **Middle East**: Countries in the Middle East, known for their luxury shopping destinations and a growing interest in sports and fitness activities, could be strategic markets for Nike to target and establish a strong foothold.
4. **Latin America**: Markets in Latin America, such as Brazil, Mexico, and Argentina, present opportunities for Nike to cater to a diverse consumer base and leverage the region's passion for sports and active lifestyles.
5. **Southeast Asia**: Rapid urbanization, increasing urban middle-class population, and a trend towards health and wellness in countries like Indonesia, Thailand, and Vietnam make Southeast Asia an attractive region for Nike to explore and expand its market reach.
By exploring these new markets in 2024, Nike can diversify its geographical presence, reach untapped consumer segments, and drive growth in emerging economies.
### Potential New Products or Services Nike Could Introduce in 2024
1. **Smart Apparel**: Nike could explore the integration of technology into its apparel, such as smart fabrics that monitor performance metrics, provide feedback, or enhance comfort during workouts.
2. **Athletic Accessories**: Introducing a line of athletic accessories like gym bags, water bottles, or fitness trackers could complement Nike's existing product offerings and provide additional value to customers.
3. **Customization Platforms**: Offering personalized design options for footwear and apparel through online customization platforms could appeal to consumers seeking unique and tailored products.
4. **Athletic Recovery Gear**: Developing recovery-focused products like compression wear, recovery sandals, or massage tools could cater to athletes and fitness enthusiasts looking to enhance post-workout recovery.
5. **Sustainable Collections**: Launching sustainable collections made from eco-friendly materials, recycled fabrics, or biodegradable components could align with consumer preferences for environmentally conscious products.
By introducing these new products or services in 2024, Nike can innovate its product portfolio, cater to evolving consumer needs, and differentiate itself in the competitive sports apparel market.
### Potential Marketing Strategies for Nike to Increase Revenue in Q3 2024
1. **Influencer Partnerships**: Collaborating with popular athletes, celebrities, or social media influencers to promote Nike products can help reach a wider audience and drive sales.
2. **Interactive Campaigns**: Launching interactive marketing campaigns, contests, or events that engage customers and create buzz around new product releases can generate excitement and increase brand visibility.
3. **Social Media Engagement**: Leveraging social media platforms to connect with consumers, share user-generated content, and respond to feedback can build brand loyalty and encourage repeat purchases.
4. **Localized Marketing**: Tailoring marketing messages, promotions, and product offerings to specific regions or target demographics can enhance relevance and appeal to diverse consumer groups.
5. **Customer Loyalty Programs**: Implementing loyalty programs, exclusive offers, or rewards for repeat customers can incentivize brand loyalty, increase retention rates, and drive higher lifetime customer value.
By employing these marketing strategies in Q3 2024, Nike can enhance its brand presence, attract new customers, and ultimately boost revenue growth.

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 KiB

@ -16,7 +16,7 @@ Swarms provides you with all the building blocks you need to build reliable, pro
## 💻 Install
You can install `swarms` with pip in a
[**Python>=3.8**](https://www.python.org/) environment.
[**Python>=3.10**](https://www.python.org/) environment.
!!! example "pip install (recommended)"

@ -12,7 +12,7 @@
# Installation Guide
You can install `swarms` with pip in a
[**Python>=3.8**](https://www.python.org/) environment.
[**Python>=3.10**](https://www.python.org/) environment.
!!! example "pip install (recommended)"
@ -23,12 +23,6 @@ You can install `swarms` with pip in a
pip install swarms
```
!!! example "pip install (recommended)"
If the installation above doesn't work try the following with PIP3
```bash
pip3 install -U swarms
```
!!! example "git clone (for development)"

@ -41,14 +41,6 @@ plugins:
# token: !ENV ["GITHUB_TOKEN"]
- git-revision-date-localized:
enable_creation_date: true
# - minify_html
# - redirects
# - mkdocs-simple-hooks
# - awesome-pages
# - mkdocs-versioning
# # - mkdocs-include-markdown-plugin
# - enumerate-headings
# - autolinks
copyright: "&copy; TGSC, Corporation."
extra_css:
@ -104,30 +96,34 @@ markdown_extensions:
- footnotes
nav:
- Home:
- Installation:
- Overview: "index.md"
- Install: "install.md"
- Limitations of Individual Agents: "limits_of_individual_agents.md"
- Docker Setup: docker_setup.md
- Usage Examples:
- Build an Agent: "diy_your_own_agent.md"
- Build an Agent with tools: "examples/tools_agents.md"
- Docker Setup: docker_setup.md
- Why does Swarms Exist?:
- Why Swarms? Orchestrating Agents for Enterprise Automation: "why.md"
- Limitations of Individual Agents: "limits_of_individual_agents.md"
- Swarms Cloud API:
- Overview: "swarms_cloud/main.md"
- Available Models: "swarms_cloud/available_models.md"
- Migrate from OpenAI to Swarms in 3 lines of code: "swarms_cloud/migrate_openai.md"
- Getting Started with SOTA Vision Language Models VLM: "swarms_cloud/getting_started.md"
- Enterprise Guide to High-Performance Multi-Agent LLM Deployments: "swarms_cloud/production_deployment.md"
- Swarms Framework [PY]:
- Overview: "swarms/index.md"
- DIY Build Your Own Agent: "diy_your_own_agent.md"
- Agents with Tools: "examples/tools_agent.md"
- swarms.agents:
- Agents:
- WorkerAgent: "swarms/agents/workeragent.md"
- AbstractAgent: "swarms/agents/abstractagent.md"
- ToolAgent: "swarms/agents/toolagent.md"
- swarms.models:
- How to Create A Custom Language Model: "swarms/models/custom_model.md"
- Deploying Azure OpenAI in Production A Comprehensive Guide: "swarms/models/azure_openai.md"
- Language:
- BaseLLM: "swarms/models/base_llm.md"
- Overview: "swarms/models/index.md"
- Llava3: "swarms/models/llama3.md"
- HuggingFaceLLM: "swarms/models/huggingface.md"
- Anthropic: "swarms/models/anthropic.md"
- OpenAI: "swarms/models/openai.md"
@ -146,30 +142,23 @@ nav:
- swarms.structs:
- Foundational Structures:
- Agent: "swarms/structs/agent.md"
- basestructure: "swarms/structs/basestructure.md"
- taskinput: "swarms/structs/taskinput.md"
- stepinput: "swarms/structs/stepinput.md"
- artifact: "swarms/structs/artifact.md"
- task: "swarms/structs/task.md"
- Task Queue Base: "swarms/structs/taskqueuebase.md"
- BaseStructure: "swarms/structs/basestructure.md"
- Task: "swarms/structs/task.md"
- YamlModel: "swarms/structs/yaml_model.md"
- Workflows:
- recursiveworkflow: "swarms/structs/recursiveworkflow.md"
- concurrentworkflow: "swarms/structs/concurrentworkflow.md"
- nonlinearworkflow: "swarms/structs/nonlinearworkflow.md"
- sequential_workflow: "swarms/structs/sequential_workflow.md"
- workflow: "swarms/structs/workflow.md"
- baseworkflow: "swarms/structs/baseworkflow.md"
- ConcurrentWorkflow: "swarms/structs/concurrentworkflow.md"
- SequentialWorkflow: "swarms/structs/sequential_workflow.md"
- BaseWorkflow: "swarms/structs/baseworkflow.md"
- Multi Agent Architectures:
- conversation: "swarms/structs/conversation.md"
- groupchat: "swarms/structs/groupchat.md"
- swarmnetwork: "swarms/structs/swarmnetwork.md"
- groupchatmanager: "swarms/structs/groupchatmanager.md"
- Conversation: "swarms/structs/conversation.md"
- SwarmNetwork: "swarms/structs/swarmnetwork.md"
- MajorityVoting: "swarms/structs/majorityvoting.md"
- AgentRearrange: "swarms/structs/agent_rearrange.md"
- swarms.memory:
- Building Custom Vector Memory Databases with the BaseVectorDatabase Class: "swarms/memory/diy_memory.md"
- ShortTermMemory: "swarms/memory/short_term_memory.md"
- Guides:
- Agents:
- Building Custom Vector Memory Databases with the BaseVectorDatabase Class: "swarms/memory/diy_memory.md"
- How to Create A Custom Language Model: "swarms/models/custom_model.md"
- Deploying Azure OpenAI in Production, A Comprehensive Guide: "swarms/models/azure_openai.md"
@ -187,30 +176,23 @@ nav:
- Overview: "applications/customer_support.md"
- Marketing:
- Overview: "applications/marketing_agencies.md"
- Operations:
- Intoducing The Swarm of Automated Business Analyts: "applications/business-analyst-agent.md"
- Corporate:
- Corporate Documents:
- Data Room: "corporate/data_room.md"
- The Swarm Memo: "corporate/swarm_memo.md"
- Corporate Architecture: "corporate/architecture.md"
- Flywheel: "corporate/flywheel.md"
- Bounties: "corporate/bounties.md"
- Purpose: "corporate/purpose.md"
- Roadmap: "corporate/roadmap.md"
- Sales:
- FAQ: "corporate/faq.md"
- Distribution: "corporate/distribution"
- Product:
- SwarmCloud: "corporate/swarm_cloud.md"
- Weaknesses: "corporate/failures.md"
- Weaknesses of Langchain: "corporate/failures.md"
- Design: "corporate/design.md"
- Metric: "corporate/metric.md"
- Research: "corporate/research.md"
- Demos: "corporate/demos.md"
- Checklist: "corporate/checklist.md"
- Organization:
- FrontEnd Member Onboarding: "corporate/front_end_contributors.md"
- Contributors:
- Contributing: "contributing.md"
- Why Swarms: "why_swarms.md"
- The Swarms Bounty System: "corporate/swarms_bounty_system.md"

@ -0,0 +1,96 @@
## Llava3
```python
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
from swarms.models.base_llm import BaseLLM
class Llama3(BaseLLM):
"""
Llama3 class represents a Llama model for natural language generation.
Args:
model_id (str): The ID of the Llama model to use.
system_prompt (str): The system prompt to use for generating responses.
temperature (float): The temperature value for controlling the randomness of the generated responses.
top_p (float): The top-p value for controlling the diversity of the generated responses.
max_tokens (int): The maximum number of tokens to generate in the response.
**kwargs: Additional keyword arguments.
Attributes:
model_id (str): The ID of the Llama model being used.
system_prompt (str): The system prompt for generating responses.
temperature (float): The temperature value for generating responses.
top_p (float): The top-p value for generating responses.
max_tokens (int): The maximum number of tokens to generate in the response.
tokenizer (AutoTokenizer): The tokenizer for the Llama model.
model (AutoModelForCausalLM): The Llama model for generating responses.
Methods:
run(task, *args, **kwargs): Generates a response for the given task.
"""
def __init__(
self,
model_id="meta-llama/Meta-Llama-3-8B-Instruct",
system_prompt: str = None,
temperature: float = 0.6,
top_p: float = 0.9,
max_tokens: int = 4000,
**kwargs,
):
self.model_id = model_id
self.system_prompt = system_prompt
self.temperature = temperature
self.top_p = top_p
self.max_tokens = max_tokens
self.tokenizer = AutoTokenizer.from_pretrained(model_id)
self.model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.bfloat16,
device_map="auto",
)
def run(self, task: str, *args, **kwargs):
"""
Generates a response for the given task.
Args:
task (str): The user's task or input.
Returns:
str: The generated response.
"""
messages = [
{"role": "system", "content": self.system_prompt},
{"role": "user", "content": task},
]
input_ids = self.tokenizer.apply_chat_template(
messages, add_generation_prompt=True, return_tensors="pt"
).to(self.model.device)
terminators = [
self.tokenizer.eos_token_id,
self.tokenizer.convert_tokens_to_ids("<|eot_id|>"),
]
outputs = self.model.generate(
input_ids,
max_new_tokens=self.max_tokens,
eos_token_id=terminators,
do_sample=True,
temperature=self.temperature,
top_p=self.top_p,
*args,
**kwargs,
)
response = outputs[0][input_ids.shape[-1] :]
return self.tokenizer.decode(
response, skip_special_tokens=True
)
```

@ -0,0 +1,274 @@
# Documentation for `AgentRearrange` Class
-----
The `AgentRearrange` class represents a swarm of agents for rearranging tasks. It allows you to create a swarm of agents, add or remove agents from the swarm, and run the swarm to process tasks based on a specified flow pattern.
## Attributes
----------
| Attribute | Type | Description |
| --- | --- | --- |
| `agents` | `dict` | A dictionary of agents, where the key is the agent's name and the value is the agent object. |
| `flow` | `str` | The flow pattern of the tasks. |
| `max_loops` | `int` | The maximum number of loops for the agents to run. |
| `verbose` | `bool` | Whether to enable verbose logging or not. |
## Methods
-------
### `__init__(self, agents: List[Agent] = None, flow: str = None, max_loops: int = 1, verbose: bool = True)`
Initializes the `AgentRearrange` object.
| Parameter | Type | Description |
| --- | --- | --- |
| `agents` | `List[Agent]` (optional) | A list of `Agent` objects. Defaults to `None`. |
| `flow` | `str` (optional) | The flow pattern of the tasks. Defaults to `None`. |
| `max_loops` | `int` (optional) | The maximum number of loops for the agents to run. Defaults to `1`. |
| `verbose` | `bool` (optional) | Whether to enable verbose logging or not. Defaults to `True`. |
### `add_agent(self, agent: Agent)`
Adds an agent to the swarm.
| Parameter | Type | Description |
| --- | --- | --- |
| `agent` | `Agent` | The agent to be added. |
### `remove_agent(self, agent_name: str)`
Removes an agent from the swarm.
| Parameter | Type | Description |
| --- | --- | --- |
| `agent_name` | `str` | The name of the agent to be removed. |
### `add_agents(self, agents: List[Agent])`
Adds multiple agents to the swarm.
| Parameter | Type | Description |
| --- | --- | --- |
| `agents` | `List[Agent]` | A list of `Agent` objects. |
### `validate_flow(self)`
Validates the flow pattern.
**Raises:**
- `ValueError`: If the flow pattern is incorrectly formatted or contains duplicate agent names.
**Returns:**
- `bool`: `True` if the flow pattern is valid.
### `run(self, task: str, *args, **kwargs)`
Runs the swarm to rearrange the tasks.
| Parameter | Type | Description |
| --- | --- | --- |
| `task` | `str` | The initial task to be processed. |
| `*args` | - | Additional positional arguments. |
| `**kwargs` | - | Additional keyword arguments. |
**Returns:**
- `str`: The final processed task.
## Documentation for `rearrange` Function
======================================
The `rearrange` function is a helper function that rearranges the given list of agents based on the specified flow.
## Parameters
----------
| Parameter | Type | Description |
| --- | --- | --- |
| `agents` | `List[Agent]` | The list of agents to be rearranged. |
| `flow` | `str` | The flow used for rearranging the agents. |
| `task` | `str` (optional) | The task to be performed during rearrangement. Defaults to `None`. |
| `*args` | - | Additional positional arguments. |
| `**kwargs` | - | Additional keyword arguments. |
## Returns
-------
The result of running the agent system with the specified task.
### Example
-------
```python
agents = [agent1, agent2, agent3]
flow = "agent1 -> agent2, agent3"
task = "Perform a task"
rearrange(agents, flow, task)
```
### Example Usage
-------------
Here's an example of how to use the `AgentRearrange` class and the `rearrange` function:
```python
from swarms import Agent, AgentRearrange, rearrange
from typing import List
# Initialize the director agent
director = Agent(
agent_name="Director",
system_prompt="Directs the tasks for the workers",
llm=Anthropic(),
max_loops=1,
dashboard=False,
streaming_on=True,
verbose=True,
stopping_token="<DONE>",
state_save_file_type="json",
saved_state_path="director.json",
)
# Initialize worker 1
worker1 = Agent(
agent_name="Worker1",
system_prompt="Generates a transcript for a youtube video on what swarms are",
llm=Anthropic(),
max_loops=1,
dashboard=False,
streaming_on=True,
verbose=True,
stopping_token="<DONE>",
state_save_file_type="json",
saved_state_path="worker1.json",
)
# Initialize worker 2
worker2 = Agent(
agent_name="Worker2",
system_prompt="Summarizes the transcript generated by Worker1",
llm=Anthropic(),
max_loops=1,
dashboard=False,
streaming_on=True,
verbose=True,
stopping_token="<DONE>",
state_save_file_type="json",
saved_state_path="worker2.json",
)
# Create a list of agents
agents = [director, worker1, worker2]
# Define the flow pattern
flow = "Director -> Worker1 -> Worker2"
# Using AgentRearrange class
agent_system = AgentRearrange(agents=agents, flow=flow)
output = agent_system.run("Create a format to express and communicate swarms of llms in a structured manner for youtube")
print(output)
# Using rearrange function
output = rearrange(agents, flow, "Create a format to express and communicate swarms of llms in a structured manner for youtube")
print(output)
```
In this example, we first initialize three agents: `director`, `worker1`, and `worker2`. Then, we create a list of these agents and define the flow pattern `"Director -> Worker1 -> Worker2"`.
We can use the `AgentRearrange` class by creating an instance of it with the list of agents and the flow pattern. We then call the `run` method with the initial task, and it will execute the agents in the specified order, passing the output of one agent as the input to the next agent.
Alternatively, we can use the `rearrange` function by passing the list of agents, the flow pattern, and the initial task as arguments.
Both the `AgentRearrange` class and the `rearrange` function will return the final output after processing the task through the agents according to the specified flow pattern.
## Error Handling
--------------
The `AgentRearrange` class includes error handling mechanisms to validate the flow pattern. If the flow pattern is incorrectly formatted or contains duplicate agent names, a `ValueError` will be raised with an appropriate error message.
### Example:
```python
# Invalid flow pattern
invalid_flow = "Director->Worker1,Worker2->Worker3"
agent_system = AgentRearrange(agents=agents, flow=invalid_flow)
output = agent_system.run("Some task")`
```
This will raise a `ValueError` with the message `"Agent 'Worker3' is not registered."`.
## Parallel and Sequential Processing
----------------------------------
The `AgentRearrange` class supports both parallel and sequential processing of tasks based on the specified flow pattern. If the flow pattern includes multiple agents separated by commas (e.g., `"agent1, agent2"`), the agents will be executed in parallel, and their outputs will be concatenated with a semicolon (`;`). If the flow pattern includes a single agent, it will be executed sequentially.
### Parallel processing
`parallel_flow = "Worker1, Worker2 -> Director"`
### Sequential processing
`sequential_flow = "Worker1 -> Worker2 -> Director"`
In the `parallel_flow` example, `Worker1` and `Worker2` will be executed in parallel, and their outputs will be concatenated and passed to `Director`. In the `sequential_flow` example, `Worker1` will be executed first, and its output will be passed to `Worker2`, and then the output of `Worker2` will be passed to `Director`.
## Logging
-------
The `AgentRearrange` class includes logging capabilities using the `loguru` library. If `verbose` is set to `True` during initialization, a log file named `agent_rearrange.log` will be created, and log messages will be written to it. You can use this log file to track the execution of the agents and any potential issues or errors that may occur.
```bash
2023-05-08 10:30:15.456 | INFO | agent_rearrange:__init__:34 - Adding agent Director to the swarm.
2023-05-08 10:30:15.457 | INFO | agent_rearrange:__init__:34 - Adding agent Worker1 to the swarm.
2023-05-08 10:30:15.457 | INFO | agent_rearrange:__init__:34 - Adding agent Worker2 to the swarm.
2023-05-08 10:30:15.458 | INFO | agent_rearrange:run:118 - Running agents in parallel: ['Worker1', 'Worker2']
2023-05-08 10:30:15.459 | INFO | agent_rearrange:run:121 - Running agents sequentially: ['Director']`
```
## Additional Parameters
---------------------
The `AgentRearrange` class also accepts additional parameters that can be passed to the `run` method using `*args` and `**kwargs`. These parameters will be forwarded to the individual agents during execution.
`agent_system = AgentRearrange(agents=agents, flow=flow)`
`output = agent_system.run("Some task", max_tokens=200, temperature=0.7)`
In this example, the `max_tokens` and `temperature` parameters will be passed to each agent during execution.
## Customization
-------------
The `AgentRearrange` class and the `rearrange` function can be customized and extended to suit specific use cases. For example, you can create custom agents by inheriting from the `Agent` class and implementing custom logic for task processing. You can then add these custom agents to the swarm and define the flow pattern accordingly.
Additionally, you can modify the `run` method of the `AgentRearrange` class to implement custom logic for task processing and agent interaction.
## Limitations
-----------
It's important to note that the `AgentRearrange` class and the `rearrange` function rely on the individual agents to process tasks correctly. The quality of the output will depend on the capabilities and configurations of the agents used in the swarm. Additionally, the `AgentRearrange` class does not provide any mechanisms for task prioritization or load balancing among the agents.
## Future Improvements
-------------------
Here are some potential future improvements for the `AgentRearrange` class and the `rearrange` function:
- **Task Prioritization**: Implement a mechanism to prioritize tasks based on factors such as urgency, importance, or resource availability.
- **Load Balancing**: Incorporate load balancing algorithms to distribute tasks among agents more efficiently, taking into account factors such as agent availability, performance, and resource utilization.
- **Dynamic Flow Reconfiguration**: Allow for dynamic reconfiguration of the flow pattern during runtime, enabling the addition, removal, or reordering of agents based on specific conditions or events.
- **Error Handling and Fault Tolerance**: Enhance error handling and fault tolerance mechanisms to gracefully handle agent failures, task timeouts, or other exceptional situations.
- **Monitoring and Metrics**: Implement monitoring and metrics collection to track the performance and efficiency of the swarm, as well as individual agent performance.
- **Scalability**: Enhance the scalability of the system to handle larger numbers of agents and tasks efficiently.
## Conclusion
----------
The `AgentRearrange` class and the `rearrange` function provide a flexible and extensible framework for orchestrating swarms of agents to process tasks based on a specified flow pattern. By combining the capabilities of individual agents, you can create complex workflows and leverage the strengths of different agents to tackle various tasks efficiently.
While the current implementation offers basic functionality for agent rearrangement, there is room for future improvements and customizations to enhance the system's capabilities and cater to more specific use cases.
Whether you're working on natural language processing tasks, data analysis, or any other domain where agent-based systems can be beneficial, the `AgentRearrange` class and the `rearrange` function provide a solid foundation for building and experimenting with swarm-based solutions.

@ -0,0 +1,15 @@
# Available Models
| Model Name | Description | Input Price | Output Price | Use Cases |
|-----------------------|---------------------------------------------------------------------------------------------------------|--------------|--------------|------------------------------------------------------------------------|
| **Llama3-70b** | Llama 3 is an auto-regressive language model that uses an optimized transformer architecture. | $0.80/1M Tokens | $1.60/1M Tokens | General natural language processing tasks. |
| **Llava-Internlm2-20b** | LLaVA model fine-tuned from InternLM2-Chat-20B and CLIP-ViT-Large-patch14-336. | Contact for pricing | Contact for pricing | Enhanced language understanding integrated with visual processing. |
| **Llama-3-Giraffe-70B** | Abacus.AI presents our longer-necked variant of Llama 3 70B! | $1/1M Tokens | $2/1M Tokens | Extensive natural language tasks with a focus on depth and efficiency. |
| **Qwen-vl** | Qwen VL for real-world multi-modal function calling. | $5/1M Tokens | $10/1M Tokens | Multi-modal interactions and function handling in complex environments.|
| **XComposer2-4khd-7b** | One of the highest performing VLMs (Video Language Models). | $4/1M Tokens | $8/1M Tokens | High-resolution video processing and understanding. |
| **Llava-Llama-3** | Llama3 with Multi-Modal Processing. | $5/1M Tokens | $10/1M Tokens | Advanced multi-modal scenarios involving language and image processing. |
| **cogvlm-chat-17b** | Groundbreaking multimodal model designed to understand and reason about visual elements in images. | $5/1M Tokens | $10/1M Tokens | Image-based chatbots and interactive systems. |
## What models should we add?
[Book a call with us to learn more about your needs:](https://calendly.com/swarm-corp/30min)

@ -0,0 +1,94 @@
# Getting Started with State-of-the-Art Vision Language Models (VLMs) Using the Swarms API
The intersection of vision and language tasks within the field of artificial intelligence has led to the emergence of highly sophisticated models known as Vision Language Models (VLMs). These models leverage the capabilities of both computer vision and natural language processing to provide a more nuanced understanding of multimodal inputs. In this blog post, we will guide you through the process of integrating state-of-the-art VLMs available through the Swarms API, focusing particularly on models like "internlm-xcomposer2-4khd", which represents a blend of high-performance language and visual understanding.
#### What Are Vision Language Models?
Vision Language Models are at the frontier of integrating visual data processing with text analysis. These models are trained on large datasets that include both images and their textual descriptions, learning to correlate visual elements with linguistic context. The result is a model that can not only recognize objects in an image but also generate descriptive, context-aware text, answer questions about the image, and even engage in a dialogue about its content.
#### Why Use Swarms API for VLMs?
Swarms API provides access to several cutting-edge VLMs including the "internlm-xcomposer2-4khd" model. This API is designed for developers looking to seamlessly integrate advanced multimodal capabilities into their applications without the need for extensive machine learning expertise or infrastructure. Swarms API is robust, scalable, and offers state-of-the-art models that are continuously updated to leverage the latest advancements in AI research.
#### Prerequisites
Before diving into the technical setup, ensure you have the following:
- An active account with Swarms API to obtain an API key.
- Python installed on your machine (Python 3.6 or later is recommended).
- An environment where you can install packages and run Python scripts (like Visual Studio Code, Jupyter Notebook, or simply your terminal).
#### Setting Up Your Environment
First, you'll need to install the `OpenAI` Python library if it's not already installed:
```bash
pip install openai
```
#### Integrating the Swarms API
Heres a basic guide on how to set up the Swarms API in your Python environment:
1. **API Key Configuration**:
Start by setting up your API key and base URL. Replace `"your_swarms_key"` with the actual API key you obtained from Swarms.
```python
from openai import OpenAI
openai_api_key = "your_swarms_key"
openai_api_base = "https://api.swarms.world/v1"
```
2. **Initialize Client**:
Initialize your OpenAI client with the provided API key and base URL.
```python
client = OpenAI(
api_key=openai_api_key,
base_url=openai_api_base,
)
```
3. **Creating a Chat Completion**:
To use the VLM, youll send a request to the API with a multimodal input consisting of both an image and a text query. The following example shows how to structure this request:
```python
chat_response = client.chat.completions.create(
model="internlm-xcomposer2-4khd",
messages=[
{
"role": "user",
"content": [
{
"type": "image_url",
"image_url": {
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg",
},
},
{"type": "text", "text": "What's in this image?"},
]
}
],
)
print("Chat response:", chat_response)
```
This code sends a multimodal query to the model, which includes an image URL followed by a text question regarding the image.
#### Understanding the Response
The response from the API will include details generated by the model about the image based on the textual query. This could range from simple descriptions to complex narratives, depending on the models capabilities and the nature of the question.
#### Best Practices
- **Data Privacy**: Always ensure that the images and data you use comply with privacy laws and regulations.
- **Error Handling**: Implement robust error handling to manage potential issues during API calls.
- **Model Updates**: Keep track of updates to the Swarms API and model improvements to leverage new features and improved accuracies.
#### Conclusion
Integrating VLMs via the Swarms API opens up a plethora of opportunities for developers to create rich, interactive, and intelligent applications that understand and interpret the world not just through text but through visuals as well. Whether youre building an educational tool, a content management system, or an interactive chatbot, these models can significantly enhance the way users interact with your application.
As you embark on your journey to integrate these powerful models into your projects, remember that the key to successful implementation lies in understanding the capabilities and limitations of the technology, continually testing with diverse data, and iterating based on user feedback and technological advances.
Happy coding, and heres to building more intelligent, multimodal applications!

@ -6,7 +6,7 @@ The AI Chat Completion API processes text and image inputs to generate conversat
## API Endpoints
### Chat Completion
### Chat Completion URL
`https://api.swarms.world`
@ -58,7 +58,7 @@ The AI Chat Completion API processes text and image inputs to generate conversat
## Objects
### ChatMessageInput
### Request
| Field | Type | Description | Required |
|-----------|---------------------|-----------------------------------------------|----------|
@ -66,14 +66,14 @@ The AI Chat Completion API processes text and image inputs to generate conversat
| `content` | string or array | The content of the message. | Yes |
| `name` | string | An optional name identifier for the sender. | No |
### ChatCompletionResponseChoice
### Response
| Field | Type | Description |
|-----------|--------|------------------------------------|
| `index` | integer| The index of the choice. |
| `message` | object | A `ChatMessageResponse` object. |
### UsageInfo
#### UsageInfo
| Field | Type | Description |
|-------------------|---------|-----------------------------------------------|

@ -75,6 +75,8 @@ Note that you need to supply one of Swarmss supported LLMs as an argument, as
## Example output
The code above produces the following object:
```bash
```
ChatCompletionMessage(content=" Hello! How can I assist you today? Do you have any questions or tasks you'd like help with? Please let me know and I'll do my best to assist you.", role='assistant' function_call=None, tool_calls=None)
```

@ -0,0 +1,319 @@
# Enterprise Guide to High-Performance Multi-Agent LLM Deployments
-------
As large language models (LLMs) continue to advance and enable a wide range of powerful applications, enterprises are increasingly exploring multi-agent architectures to leverage the collective capabilities of multiple LLMs. However, coordinating and optimizing the performance of these complex multi-agent systems presents significant challenges.
This comprehensive guide provides enterprise architects, engineering leaders, and technical decision-makers with a strategic framework for maximizing performance across multi-agent LLM deployments. Developed through extensive research and collaboration with industry partners, this guide distills best practices, proven techniques, and cutting-edge methodologies into seven core principles.
By implementing the recommendations outlined in this guide, organizations can achieve superior latency, throughput, and resource utilization while ensuring scalability, cost-effectiveness, and optimal user experiences. Whether powering customer-facing conversational agents, driving internal knowledge management systems, or fueling mission-critical decision support tools, high-performance multi-agent LLM deployments will be pivotal to unlocking the full potential of this transformative technology.
## Introduction
The rise of large language models (LLMs) has ushered in a new era of human-machine interaction, enabling enterprises to develop sophisticated natural language processing (NLP) applications that can understand, generate, and reason with human-like text. However, as the complexity and scale of LLM deployments grow, traditional monolithic architectures are increasingly challenged to meet the stringent performance, scalability, and cost requirements of enterprise environments.
Multi-agent architectures, which coordinate the collective capabilities of multiple specialized LLMs, have emerged as a powerful paradigm for addressing these challenges. By distributing workloads across a cohort of agents, each optimized for specific tasks or domains, multi-agent systems can deliver superior performance, resilience, and adaptability compared to single-model solutions.
However, realizing the full potential of multi-agent LLM deployments requires a strategic approach to system design, optimization, and ongoing management. This guide presents a comprehensive framework for maximizing performance across seven core principles, each underpinned by a range of proven techniques and methodologies.
Whether you are architecting a customer-facing conversational agent, building an internal knowledge management platform, or developing a mission-critical decision support system, this guide will equip you with the insights and best practices necessary to unlock the full potential of multi-agent LLM deployments within your enterprise.
## Principle 1: Distribute Token Processing
----------------------------------------
At the heart of every LLM deployment lies the fundamental challenge of optimizing token processing -- the rate at which the model consumes and generates text inputs and outputs. In multi-agent architectures, distributing and parallelizing token processing across multiple agents is a critical performance optimization strategy.
### Agent Specialization
One of the key advantages of multi-agent architectures is the ability to dedicate specific agents to specialized tasks or domains. By carefully matching agents to the workloads they are optimized for, enterprises can maximize overall throughput and minimize latency.
For example, in a conversational agent deployment, one agent may be optimized for intent recognition and query understanding, while another is fine-tuned for generating coherent, context-aware responses. In a document processing pipeline, separate agents could be dedicated to tasks such as named entity recognition, sentiment analysis, and summarization.
To effectively leverage agent specialization, enterprises should:
- Conduct a thorough analysis of their application's workflow and identify distinct tasks or domains that could benefit from dedicated agents.
- Evaluate the strengths and weaknesses of available LLM models and agents, and map them to the identified tasks or domains based on their capabilities and performance characteristics.
- Implement continuous monitoring and performance tuning processes to ensure agents remain optimized for their assigned workloads as models evolve and domain requirements shift.
### Load Balancing
Even with a well-designed allocation of tasks across specialized agents, fluctuations in workload and demand can create bottlenecks and performance degradation. Effective load balancing strategies are essential to ensure that token processing capacity is dynamically distributed across available agents based on real-time conditions.
Load balancing in multi-agent LLM deployments can be accomplished through a combination of techniques, including:
- **Round-Robin**: Distributing incoming requests across agents in a cyclical fashion, ensuring an even distribution of workload.
- **Least Connections**: Routing requests to the agent with the fewest active connections or outstanding tasks, minimizing the risk of overloading any single agent.
- **Response Time Monitoring**: Continuously monitoring the response times of each agent and dynamically adjusting request routing to favor faster-responding agents.
- **Resource-Based Routing**: Factoring in agent-level resource consumption (e.g., CPU, memory) when making routing decisions, ensuring that overloaded agents are relieved of additional workload.
Implementing effective load balancing requires careful consideration of the specific characteristics and requirements of your multi-agent deployment, as well as the integration of robust monitoring and analytics capabilities to inform dynamic routing decisions.
### Horizontal Scaling
While load balancing optimizes the utilization of existing agent resources, horizontal scaling strategies enable organizations to dynamically provision additional token processing capacity to meet demand spikes or handle larger overall workloads.
In multi-agent LLM deployments, horizontal scaling can be achieved through:
- **Agent Replication**: Spin up additional instances of existing agents to increase parallel processing capacity for specific tasks or domains.
- **Hybrid Scaling**: Combine agent replication with the dynamic provisioning of additional compute resources (e.g., CPU, GPU) to support the increased agent count.
- **Serverless Deployment**: Leverage serverless computing platforms (e.g., AWS Lambda, Google Cloud Functions) to automatically scale agent instances based on real-time demand, minimizing idle resource consumption.
Effective horizontal scaling requires robust orchestration and management capabilities, as well as seamless integration with load balancing mechanisms to ensure that incoming workloads are efficiently distributed across the dynamically scaled agent pool.
## Principle 2: Optimize Agent Communication
-----------------------------------------
In multi-agent LLM deployments, efficient inter-agent communication is crucial for coordinating tasks, exchanging context and intermediate results, and maintaining overall system coherence. However, communication overhead can quickly become a performance bottleneck if not carefully managed.
### Minimizing Overhead
Reducing the volume and complexity of information exchanged between agents is a key strategy for optimizing communication performance. Techniques for minimizing overhead include:
- **Data Compression**: Applying lossless or lossy compression algorithms to reduce the size of data payloads exchanged between agents, lowering bandwidth requirements and transmission latencies.
- **Information Summarization**: Distilling and summarizing context, results, or other data exchanged between agents to its essential elements, minimizing redundant or non-critical information.
- **Differential Updates**: Rather than transmitting entire data payloads, agents can exchange only the differential updates or deltas required to synchronize their respective states.
Implementing these techniques requires careful analysis of the specific data exchange patterns and communication requirements within your multi-agent deployment, as well as the integration of appropriate compression, summarization, and differential update algorithms.
### Prioritizing Critical Information
In scenarios where communication bandwidth or latency constraints cannot be fully alleviated through overhead reduction techniques, enterprises can prioritize the exchange of critical information over non-essential data.
This can be achieved through:
- **Prioritized Queuing**: Implementing queuing mechanisms that prioritize the transmission of high-priority, time-sensitive data over lower-priority, non-critical information.
- **Selective Communication**: Dynamically determining which agents require specific pieces of information based on their roles and responsibilities, and selectively transmitting data only to those agents that truly need it.
- **Progressive Information Exchange**: Exchanging information in a progressive or staged manner, with critical elements transmitted first, followed by supplementary or contextual data as bandwidth becomes available.
Effective prioritization requires a deep understanding of the interdependencies and information flow within your multi-agent system, as well as the ability to dynamically assess and prioritize data based on its criticality and urgency.
### Caching and Reusing Context
In many multi-agent LLM deployments, agents frequently exchange or operate on shared context, such as user profiles, conversation histories, or domain-specific knowledge bases. Caching and reusing this context information can significantly reduce redundant communication and processing overhead.
Strategies for optimizing context caching and reuse include:
- **Agent-Level Caching**: Implementing caching mechanisms within individual agents to store and retrieve frequently accessed context data, minimizing the need for inter-agent communication.
- **Centralized Context Management**: Deploying a dedicated context management service or data store that agents can query and update, ensuring consistent access to the latest context information across the system.
- **Context Versioning and Invalidation**: Implementing versioning and invalidation mechanisms to ensure that cached context data remains fresh and consistent, avoiding stale or outdated information from propagating through the system.
### Principle 3: Leverage Agent Specialization
------------------------------------------
One of the key advantages of multi-agent architectures is the ability to optimize individual agents for specific tasks, domains, or capabilities. By leveraging agent specialization, enterprises can ensure that each component of their LLM system is finely tuned for maximum performance and quality.
### Task-Specific Optimization
Within a multi-agent LLM deployment, different agents may be responsible for distinct tasks such as language understanding, knowledge retrieval, response generation, or post-processing. Optimizing each agent for its designated task can yield significant performance gains and quality improvements.
Techniques for task-specific optimization include:
- **Prompt Engineering**: Crafting carefully designed prompts that provide the necessary context, instructions, and examples to guide an agent towards optimal performance for its assigned task.
- **Fine-Tuning**: Adapting a pre-trained LLM to a specific task or domain by fine-tuning it on a curated dataset, allowing the agent to specialize and improve its performance on that particular workload.
- **Model Distillation**: Transferring the knowledge and capabilities of a larger, more capable LLM into a smaller, more efficient model specialized for a specific task, balancing performance and quality trade-offs.
Implementing these optimization techniques requires a deep understanding of the capabilities and requirements of each task within your multi-agent system, as well as access to relevant training data and computational resources for fine-tuning and distillation processes.
### Domain Adaptation
Many enterprise applications operate within specific domains or verticals, such as finance, healthcare, or legal. Adapting agents to these specialized domains can significantly improve their performance, accuracy, and compliance within the target domain.
Strategies for domain adaptation include:
- **Domain-Specific Pre-Training**: Leveraging domain-specific corpora to pre-train LLM agents, imbuing them with a foundational understanding of the language, concepts, and nuances specific to the target domain.
- **Transfer Learning**: Fine-tuning agents that have been pre-trained on general or adjacent domains, transferring their existing knowledge and capabilities to the target domain while optimizing for its specific characteristics.
- **Domain Persona Injection**: Injecting domain-specific personas, traits, or constraints into agents during fine-tuning or deployment, shaping their behavior and outputs to align with domain-specific norms and requirements.
Effective domain adaptation requires access to high-quality, domain-specific training data, as well as close collaboration with subject matter experts to ensure that agents are properly calibrated to meet the unique demands of the target domain.
### Ensemble Techniques
In complex multi-agent deployments, individual agents may excel at specific subtasks or aspects of the overall workflow. Ensemble techniques that combine the outputs or predictions of multiple specialized agents can often outperform any single agent, leveraging the collective strengths of the ensemble.
Common ensemble techniques for multi-agent LLM systems include:
- **Voting**: Combining the outputs or predictions of multiple agents through majority voting, weighted voting, or other consensus mechanisms.
- **Stacking**: Training a meta-agent to combine and optimize the outputs of multiple base agents, effectively learning to leverage their collective strengths.
- **Blending**: Combining the outputs of multiple agents through weighted averaging, linear interpolation, or other blending techniques, allowing for nuanced integration of diverse perspectives.
Implementing effective ensemble techniques requires careful analysis of the strengths, weaknesses, and complementary capabilities of individual agents, as well as the development of robust combination strategies that can optimally leverage the ensemble's collective intelligence.
### Principle 4: Implement Dynamic Scaling
--------------------------------------
The demand and workload patterns of enterprise LLM deployments can be highly dynamic, with significant fluctuations driven by factors such as user activity, data ingestion schedules, or periodic batch processing. Implementing dynamic scaling strategies allows organizations to optimally provision and allocate resources in response to these fluctuations, ensuring consistent performance while minimizing unnecessary costs.
### Autoscaling
Autoscaling is a core capability that enables the automatic adjustment of compute resources (e.g., CPU, GPU, memory) and agent instances based on real-time demand patterns and workload metrics. By dynamically scaling resources up or down, enterprises can maintain optimal performance and resource utilization, avoiding both over-provisioning and under-provisioning scenarios.
Effective autoscaling in multi-agent LLM deployments requires:
- **Monitoring and Metrics**: Implementing robust monitoring and metrics collection mechanisms to track key performance indicators (KPIs) such as request rates, response times, resource utilization, and agent-level metrics.
- **Scaling Policies**: Defining scaling policies that specify the conditions and thresholds for triggering automatic scaling actions, such as provisioning additional agents or compute resources when certain KPIs are breached.
- **Scaling Orchestration**: Integrating autoscaling capabilities with resource orchestration and management tools (e.g., Kubernetes, AWS Auto Scaling) to seamlessly provision, configure, and integrate new resources into the existing multi-agent deployment.
By automating the scaling process, enterprises can respond rapidly to workload fluctuations, ensuring consistent performance and optimal resource utilization without the need for manual intervention.
### Spot Instance Utilization
Many cloud providers offer spot instances or preemptible resources at significantly discounted prices compared to on-demand or reserved instances. While these resources may be reclaimed with little notice, they can be leveraged judiciously within multi-agent LLM deployments to reduce operational costs.
Strategies for leveraging spot instances include:
- **Fault-Tolerant Agent Deployment**: Deploying certain agents or components of the multi-agent system on spot instances, while ensuring that these components can be rapidly and seamlessly replaced or migrated in the event of instance preemption.
- **Batch Workload Offloading**: Offloading batch processing workloads or non-time-sensitive tasks to spot instances, leveraging their cost-effectiveness while minimizing the impact of potential disruptions.
- **Hybrid Provisioning**: Implementing a hybrid approach that combines on-demand or reserved instances for mission-critical components with spot instances for more flexible or elastic workloads.
Effective spot instance utilization requires careful architectural considerations to ensure fault tolerance and minimize the impact of potential disruptions, as well as robust monitoring and automation capabilities to seamlessly replace or migrate workloads in response to instance preemption events.
### Serverless Deployments
Serverless computing platforms, such as AWS Lambda, Google Cloud Functions, or Azure Functions, offer a compelling alternative to traditional server-based deployments. By automatically scaling compute resources based on real-time demand and charging only for the resources consumed, serverless architectures can provide significant cost savings and operational simplicity.
Leveraging serverless deployments for multi-agent LLM systems can be achieved through:
- **Function-as-a-Service (FaaS) Agents**: Deploying individual agents or components of the multi-agent system as serverless functions, allowing for rapid and automatic scaling in response to fluctuating workloads.
- **Event-Driven Architectures**: Designing the multi-agent system to operate in an event-driven manner, with agents triggered and executed in response to specific events or data ingestion, aligning with the serverless execution model.
- **Hybrid Deployments**: Combining serverless components with traditional server-based components, leveraging the strengths and cost advantages of each deployment model for different aspects of the multi-agent system.
Adopting serverless architectures requires careful consideration of factors such as execution duration limits, cold start latencies, and integration with other components of the multi-agent deployment. However, when implemented effectively, serverless deployments can provide unparalleled scalability, cost-efficiency, and operational simplicity for dynamic, event-driven workloads.
### Principle 5: Employ Selective Execution
---------------------------------------
Not every input or request within a multi-agent LLM deployment requires the full execution of all agents or the complete processing pipeline. Selectively invoking agents or tasks based on input characteristics or intermediate results can significantly optimize performance by avoiding unnecessary computation and resource consumption.
### Input Filtering
Implementing input filtering mechanisms allows enterprises to reject or bypass certain inputs before they are processed by the multi-agent system. This can be achieved through techniques such as:
- **Blacklisting/Whitelisting**: Maintaining lists of inputs (e.g., specific phrases, URLs, or content types) that should be automatically rejected or allowed, based on predefined criteria.
- **Rules-Based Filtering**: Defining a set of rules or heuristics to assess the suitability or relevance of an input for further processing, based on factors such as language, content, or metadata.
- **Confidence Thresholding**: Leveraging pre-processing agents or models to assess the likelihood that an input is relevant or valuable, and filtering out inputs that fall below a predetermined confidence threshold.
Effective input filtering requires careful consideration of the specific requirements, constraints, and objectives of your multi-agent deployment, as well as ongoing monitoring and adjustment of filtering rules and thresholds to maintain optimal performance and accuracy.
### Early Stopping
In many multi-agent LLM deployments, intermediate results or predictions generated by early-stage agents can be used to determine whether further processing is required or valuable. Early stopping mechanisms allow enterprises to terminate execution pipelines when specific conditions or thresholds are met, avoiding unnecessary downstream processing.
Techniques for implementing early stopping include:
- **Confidence-Based Stopping**: Monitoring the confidence scores or probabilities associated with intermediate results, and terminating execution if a predefined confidence threshold is exceeded.
- **Exception-Based Stopping**: Defining specific intermediate results or conditions that indicate that further processing is unnecessary or undesirable, and terminating execution upon encountering these exceptions.
- **Adaptive Stopping**: Employing machine learning models or reinforcement learning agents to dynamically determine when to terminate execution based on learned patterns and trade-offs between accuracy, latency, and resource consumption.
Effective early stopping requires a deep understanding of the interdependencies and decision points within your multi-agent workflow, as well as careful tuning and monitoring to ensure that stopping conditions are calibrated to maintain an optimal balance between performance and accuracy.
### Conditional Branching
Rather than executing a linear, fixed pipeline of agents, conditional branching allows multi-agent systems to dynamically invoke different agents or execution paths based on input characteristics or intermediate results. This can significantly optimize resource utilization by ensuring that only the necessary agents and processes are executed for a given input or scenario.
Implementing conditional branching involves:
- **Decision Points**: Identifying key points within the multi-agent workflow where branching decisions can be made based on input or intermediate data.
- **Branching Logic**: Defining the rules, conditions, or machine learning models that will evaluate the input or intermediate data and determine the appropriate execution path or agent invocation.
- **Execution Routing**: Integrating mechanisms to dynamically route inputs or intermediate data to the appropriate agents or processes based on the branching decision.
Conditional branching can be particularly effective in scenarios where inputs or workloads exhibit distinct characteristics or require significantly different processing pipelines, allowing enterprises to optimize resource allocation and minimize unnecessary computation.
### Principle 6: Optimize User Experience
-------------------------------------
While many of the principles outlined in this guide focus on optimizing backend performance and resource utilization, delivering an exceptional user experience is also a critical consideration for enterprise multi-agent LLM deployments. By minimizing perceived wait times and providing real-time progress updates, organizations can ensure that users remain engaged and satisfied, even during periods of high workload or resource constraints.
### Streaming Responses
One of the most effective techniques for minimizing perceived wait times is to stream responses or outputs to users as they are generated, rather than waiting for the entire response to be completed before delivering it. This approach is particularly valuable in conversational agents, document summarization, or other scenarios where outputs can be naturally segmented and delivered incrementally.
Implementing streaming responses requires:
- **Partial Output Generation**: Modifying agents or models to generate and emit outputs in a streaming or incremental fashion, rather than producing the entire output in a single, monolithic operation.
- **Streaming Data Pipelines**: Integrating streaming data pipelines and message queues to enable the efficient and reliable transmission of partial outputs from agents to user-facing interfaces or applications.
- **Incremental Rendering**: Updating user interfaces and displays to incrementally render or populate with newly streamed output segments, providing a seamless and real-time experience for end-users.
By delivering outputs as they are generated, streaming responses can significantly improve the perceived responsiveness and interactivity of multi-agent LLM deployments, even in scenarios where the overall processing time remains unchanged.
### Progress Indicators
In cases where streaming responses may not be feasible or appropriate, providing visual or textual indicators of ongoing processing and progress can help manage user expectations and improve the overall experience. Progress indicators can be implemented through techniques such as:
- **Loader Animations**: Displaying simple animations or spinner graphics to indicate that processing is underway and provide a sense of activity and progress.
- **Progress Bars**: Rendering progress bars or completion indicators based on estimated or actual progress through multi-agent workflows or processing pipelines.
- **Status Updates**: Periodically updating user interfaces with textual status messages or descriptions of the current processing stage, providing users with a more detailed understanding of the system's activities.
Effective progress indicators require careful integration with monitoring and telemetry capabilities to accurately track and communicate the progress of multi-agent workflows, as well as thoughtful user experience design to ensure that indicators are clear, unobtrusive, and aligned with user expectations.
### Chunked Delivery
In scenarios where outputs or responses cannot be effectively streamed or rendered incrementally, chunked delivery can provide a middle ground between delivering the entire output at once and streaming individual tokens or characters. By breaking larger outputs into smaller, more manageable chunks and delivering them individually, enterprises can improve perceived responsiveness and provide a more engaging user experience.
Implementing chunked delivery involves:
- **Output Segmentation**: Identifying logical breakpoints or segmentation boundaries within larger outputs, such as paragraphs, sections, or other structural elements.
- **Chunking Mechanisms**: Integrating mechanisms to efficiently break outputs into individual chunks and transmit or render them sequentially, with minimal delay between chunks.
- **Chunk Rendering**: Updating user interfaces or displays to seamlessly render or append new output chunks as they are received, providing a sense of continuous progress and minimizing the perception of extended waiting periods.
Chunked delivery can be particularly effective in scenarios where outputs are inherently structured or segmented, such as document generation, report creation, or multi-step instructions or workflows.
## Principle 7: Leverage Hybrid Approaches
---------------------------------------
While multi-agent LLM architectures offer numerous advantages, they should not be viewed as a one-size-fits-all solution. In many cases, combining LLM agents with traditional techniques, optimized components, or external services can yield superior performance, cost-effectiveness, and resource utilization compared to a pure LLM-based approach.
### Task Offloading
Certain tasks or subtasks within a larger multi-agent workflow may be more efficiently handled by dedicated, optimized components or external services, rather than relying solely on LLM agents. Task offloading involves identifying these opportunities and integrating the appropriate components or services into the overall architecture.
Examples of task offloading in multi-agent LLM deployments include:
- **Regular Expression Matching**: Offloading pattern matching or text extraction tasks to dedicated regular expression engines, which can often outperform LLM-based approaches in terms of speed and efficiency.
- **Structured Data Processing**: Leveraging specialized data processing engines or databases for tasks involving structured data, such as querying, filtering, or transforming tabular or relational data.
- **External APIs and Services**: Integrating with external APIs or cloud services for specific tasks, such as speech recognition, translation, or knowledge base lookup, leveraging the specialized capabilities and optimizations of these dedicated services.
Effective task offloading requires a thorough understanding of the strengths and limitations of both LLM agents and traditional components, as well as careful consideration of integration points, data flows, and performance trade-offs within the overall multi-agent architecture.
### Caching and Indexing
While LLMs excel at generating dynamic, context-aware outputs, they can be less efficient when dealing with static or frequently accessed information or knowledge. Caching and indexing strategies can help mitigate this limitation by minimizing redundant LLM processing and enabling faster retrieval of commonly accessed data.
Techniques for leveraging caching and indexing in multi-agent LLM deployments include:
**Output Caching**: Caching the outputs or responses generated by LLM agents, allowing for rapid retrieval and reuse in cases where the same or similar input is encountered in the future.
**Knowledge Base Indexing**: Indexing domain-specific knowledge bases, data repositories, or other static information sources using traditional search and information retrieval techniques. This allows LLM agents to efficiently query and incorporate relevant information into their outputs, without needing to process or generate this content from scratch.
**Contextual Caching**: Caching not only outputs but also the contextual information and intermediate results generated during multi-agent workflows. This enables more efficient reuse and continuation of previous processing in scenarios where contexts are long-lived or recurring.
Implementing effective caching and indexing strategies requires careful consideration of data freshness, consistency, and invalidation mechanisms, as well as seamless integration with LLM agents and multi-agent workflows to ensure that cached or indexed data is appropriately leveraged and updated.
### Pre-computation and Lookup
In certain scenarios, especially those involving constrained or well-defined inputs, pre-computing and lookup strategies can be leveraged to minimize or entirely avoid the need for real-time LLM processing. By generating and storing potential outputs or responses in advance, enterprises can significantly improve performance and reduce resource consumption.
Approaches for pre-computation and lookup include:
**Output Pre-generation**: For inputs or scenarios with a limited set of potential outputs, pre-generating and storing all possible responses, allowing for rapid retrieval and delivery without the need for real-time LLM execution.
**Retrieval-Based Responses**: Developing retrieval models or techniques that can identify and surface pre-computed or curated responses based on input characteristics, leveraging techniques such as nearest neighbor search, embedding-based retrieval, or example-based generation.
**Hybrid Approaches**: Combining pre-computed or retrieved responses with real-time LLM processing, allowing for the generation of dynamic, context-aware content while still leveraging pre-computed components to optimize performance and resource utilization.
Effective implementation of pre-computation and lookup strategies requires careful analysis of input patterns, output distributions, and potential performance gains, as well as robust mechanisms for managing and updating pre-computed data as application requirements or domain knowledge evolves.
# Conclusion
----------
As enterprises increasingly embrace the transformative potential of large language models, optimizing the performance, scalability, and cost-effectiveness of these deployments has become a critical imperative. Multi-agent architectures, which coordinate the collective capabilities of multiple specialized LLM agents, offer a powerful paradigm for addressing these challenges.
By implementing the seven principles outlined in this guide -- distributing token processing, optimizing agent communication, leveraging agent specialization, implementing dynamic scaling, employing selective execution, optimizing user experience, and leveraging hybrid approaches -- organizations can unlock the full potential of multi-agent LLM deployments.
However, realizing these benefits requires a strategic and holistic approach that accounts for the unique requirements, constraints, and objectives of each enterprise. From task-specific optimizations and domain adaptation to dynamic scaling and user experience considerations, maximizing the performance of multi-agent LLM systems demands a deep understanding of the underlying technologies, as well as the ability to navigate the inherent complexities of these sophisticated architectures.
To learn more about how Swarm Corporation can assist your organization in architecting, deploying, and optimizing high-performance multi-agent LLM solutions, we invite you to book a consultation with one of our agent specialists. Visit <https://calendly.com/swarm-corp/30min> to schedule a 30-minute call and explore how our expertise and cutting-edge technologies can drive transformative outcomes for your business.
In the rapidly evolving landscape of artificial intelligence and natural language processing, staying ahead of the curve is essential. Partner with Swarm Corporation, and unlock the full potential of multi-agent LLM deployments, today.
[Book a call with us now:](https://calendly.com/swarm-corp/30min)

@ -0,0 +1,130 @@
# The Swarms Framework: Orchestrating Agents for Enterprise Automation
In the rapidly evolving landscape of artificial intelligence (AI) and automation, a new paradigm is emerging: the orchestration of multiple agents working in collaboration to tackle complex tasks. This approach, embodied by the Swarms Framework, aims to address the fundamental limitations of individual agents and unlocks the true potential of AI-driven automation in enterprise operations.
## The Purpose of Swarms: Overcoming Agent Limitations
Individual agents, while remarkable in their own right, face several inherent challenges that hinder their ability to effectively automate enterprise operations at scale. These limitations include:
1. Short-Term Memory Constraints
2. Hallucination and Factual Inconsistencies
3. Single-Task Limitations
4. Lack of Collaborative Capabilities
5. Cost Inefficiencies
By orchestrating multiple agents to work in concert, the Swarms Framework directly tackles these limitations, paving the way for more efficient, reliable, and cost-effective enterprise automation.
### Limitation 1: Short-Term Memory Constraints
Many AI agents, particularly those based on large language models, suffer from short-term memory constraints. These agents can effectively process and respond to prompts, but their ability to retain and reason over information across multiple interactions or tasks is limited. This limitation can be problematic in enterprise environments, where complex workflows often involve retaining and referencing contextual information over extended periods.
The Swarms Framework addresses this limitation by leveraging the collective memory of multiple agents working in tandem. While individual agents may have limited short-term memory, their combined memory pool becomes significantly larger, enabling the retention and retrieval of contextual information over extended periods. This collective memory is facilitated by agents specializing in information storage and retrieval, such as those based on systems like Llama Index or Pinecone.
### Limitation 2: Hallucination and Factual Inconsistencies
Another challenge faced by many AI agents is the tendency to generate responses that may contain factual inconsistencies or hallucinations -- information that is not grounded in reality or the provided context. This issue can undermine the reliability and trustworthiness of automated systems, particularly in domains where accuracy and consistency are paramount.
The Swarms Framework mitigates this limitation by employing multiple agents with diverse knowledge bases and capabilities. By leveraging the collective intelligence of these agents, the framework can cross-reference and validate information, reducing the likelihood of hallucinations and factual inconsistencies. Additionally, specialized agents can be tasked with fact-checking and verification, further enhancing the overall reliability of the system.
### Limitation 3: Single-Task Limitations
Most individual AI agents are designed and optimized for specific tasks or domains, limiting their ability to handle complex, multi-faceted workflows that often characterize enterprise operations. While an agent may excel at a particular task, such as natural language processing or data analysis, it may struggle with other aspects of a larger workflow, such as task coordination or decision-making.
The Swarms Framework overcomes this limitation by orchestrating a diverse ensemble of agents, each specializing in different tasks or capabilities. By intelligently combining and coordinating these agents, the framework can tackle complex, multi-threaded workflows that span various domains and task types. This modular approach allows for the seamless integration of new agents as they become available, enabling the continuous expansion and enhancement of the system's capabilities.
### Limitation 4: Lack of Collaborative Capabilities
Most AI agents are designed to operate independently, lacking the ability to effectively collaborate with other agents or coordinate their actions towards a common goal. This limitation can hinder the scalability and efficiency of automated systems, particularly in enterprise environments where tasks often require the coordination of multiple agents or systems.
The Swarms Framework addresses this limitation by introducing a layer of coordination and collaboration among agents. Through specialized coordination agents and communication protocols, the framework enables agents to share information, divide tasks, and synchronize their actions. This collaborative approach not only increases efficiency but also enables the emergence of collective intelligence, where the combined capabilities of multiple agents surpass the sum of their individual abilities.
### Limitation 5: Cost Inefficiencies
Running large AI models or orchestrating multiple agents can be computationally expensive, particularly in enterprise environments where scalability and cost-effectiveness are critical considerations. Inefficient resource utilization or redundant computations can quickly escalate costs, making widespread adoption of AI-driven automation financially prohibitive.
The Swarms Framework tackles this limitation by optimizing resource allocation and workload distribution among agents. By intelligently assigning tasks to the most appropriate agents and leveraging agent specialization, the framework minimizes redundant computations and improves overall resource utilization. Additionally, the framework can dynamically scale agent instances based on demand, ensuring that computational resources are allocated efficiently and costs are minimized.
## The Swarms Framework: A Holistic Approach to Enterprise Automation
The Swarms Framework is a comprehensive solution that addresses the limitations of individual agents by orchestrating their collective capabilities. By integrating agents from various frameworks, including LangChain, AutoGPT, Llama Index, and others, the framework leverages the strengths of each agent while mitigating their individual weaknesses.
At its core, the Swarms Framework operates on the principle of multi-agent collaboration. By introducing specialized coordination agents and communication protocols, the framework enables agents to share information, divide tasks, and synchronize their actions towards a common goal. This collaborative approach not only increases efficiency but also enables the emergence of collective intelligence, where the combined capabilities of multiple agents surpass the sum of their individual abilities.
The framework's architecture is modular and extensible, allowing for the seamless integration of new agents as they become available. This flexibility ensures that the system's capabilities can continuously expand and adapt to evolving enterprise needs and technological advancements.
## Benefits of the Swarms Framework
The adoption of the Swarms Framework in enterprise environments offers numerous benefits:
1. Increased Efficiency and Scalability
2. Improved Reliability and Accuracy
3. Adaptability and Continuous Improvement
4. Cost Optimization
5. Enhanced Security and Compliance
## Increased Efficiency and Scalability
By orchestrating the collective capabilities of multiple agents, the Swarms Framework enables the efficient execution of complex, multi-threaded workflows. Tasks can be parallelized and distributed across specialized agents, reducing bottlenecks and increasing overall throughput. Additionally, the framework's modular design and ability to dynamically scale agent instances based on demand ensure that the system can adapt to changing workloads and scale seamlessly as enterprise needs evolve.
## Improved Reliability and Accuracy
The collaborative nature of the Swarms Framework reduces the risk of hallucinations and factual inconsistencies that can arise from individual agents. By leveraging the collective knowledge and diverse perspectives of multiple agents, the framework can cross-reference and validate information, enhancing the overall reliability and accuracy of its outputs.
Additionally, the framework's ability to incorporate specialized fact-checking and verification agents further strengthens the trustworthiness of the system's outcomes, ensuring that critical decisions and actions are based on accurate and reliable information.
## Adaptability and Continuous Improvement
The modular architecture of the Swarms Framework allows for the seamless integration of new agents as they become available, enabling the continuous expansion and enhancement of the system's capabilities. As new AI models, algorithms, or data sources emerge, the framework can readily incorporate them, ensuring that enterprise operations remain at the forefront of technological advancements.
Furthermore, the framework's monitoring and analytics capabilities provide valuable insights into system performance, enabling the identification of areas for improvement and the optimization of agent selection, task assignments, and resource allocation strategies over time.
## Cost Optimization
By intelligently orchestrating the collaboration of multiple agents, the Swarms Framework optimizes resource utilization and minimizes redundant computations. This efficient use of computational resources translates into cost savings, making the widespread adoption of AI-driven automation more financially viable for enterprises.
The framework's ability to dynamically scale agent instances based on demand further contributes to cost optimization, ensuring that resources are allocated only when needed and minimizing idle or underutilized instances.
## Enhanced Security and Compliance
In enterprise environments, ensuring the security and compliance of automated systems is paramount. The Swarms Framework addresses these concerns by incorporating robust security measures and compliance controls.
The framework's centralized Memory Manager component enables the implementation of access control mechanisms and data encryption, protecting sensitive information from unauthorized access or breaches. Additionally, the framework's modular design allows for the integration of specialized agents focused on compliance monitoring and auditing, ensuring that enterprise operations adhere to relevant regulations and industry standards.
## Real-World Applications and Use Cases
The Swarms Framework finds applications across a wide range of enterprise domains, enabling organizations to automate complex operations and streamline their workflows. Here are some examples of real-world use cases:
1. Intelligent Process Automation (IPA)
2. Customer Service and Support
3. Fraud Detection and Risk Management
4. Supply Chain Optimization
5. Research and Development
## Intelligent Process Automation (IPA)
In the realm of business process automation, the Swarms Framework can orchestrate agents to automate and optimize complex workflows spanning multiple domains and task types. By combining agents specialized in areas such as natural language processing, data extraction, decision-making, and task coordination, the framework can streamline and automate processes that traditionally required manual intervention or coordination across multiple systems.
## Customer Service and Support
The framework's ability to integrate agents with diverse capabilities, such as natural language processing, knowledge retrieval, and decision-making, makes it well-suited for automating customer service and support operations. Agents can collaborate to understand customer inquiries, retrieve relevant information from knowledge bases, and provide accurate and personalized responses, improving customer satisfaction and reducing operational costs.
## Fraud Detection and Risk Management
In the financial and cybersecurity domains, the Swarms Framework can orchestrate agents specialized in data analysis, pattern recognition, and risk assessment to detect and mitigate fraudulent activities or security threats. By combining the collective intelligence of these agents, the framework can identify complex patterns and anomalies that may be difficult for individual agents to detect, enhancing the overall effectiveness of fraud detection and risk management strategies.
## Supply Chain Optimization
The complexity of modern supply chains often requires the coordination of multiple systems and stakeholders. The Swarms Framework can integrate agents specialized in areas such as demand forecasting, inventory management, logistics optimization, and supplier coordination to streamline and optimize supply chain operations. By orchestrating the collective capabilities of these agents, the framework can identify bottlenecks, optimize resource allocation, and facilitate seamless collaboration among supply chain partners.
## Research and Development
In research and development environments, the Swarms Framework can accelerate innovation by enabling the collaboration of agents specialized in areas such as literature review, data analysis, hypothesis generation, and experiment design. By orchestrating these agents, the framework can facilitate the exploration of new ideas, identify promising research directions, and streamline the iterative process of scientific inquiry.
# Conclusion
The Swarms Framework represents a paradigm shift in the field of enterprise automation, addressing the limitations of individual agents by orchestrating their collective capabilities. By integrating agents from various frameworks and enabling multi-agent collaboration, the Swarms Framework overcomes challenges such as short-term memory constraints, hallucinations, single-task limitations, lack of collaboration, and cost inefficiencies.
Through its modular architecture, centralized coordination, and advanced monitoring and analytics capabilities, the Swarms Framework empowers enterprises to automate complex operations with increased efficiency, reliability, and adaptability. It unlocks the true potential of AI-driven automation, enabling organizations to stay ahead of the curve and thrive in an ever-evolving technological landscape.
As the field of artificial intelligence continues to advance, the Swarms Framework stands as a robust and flexible solution, ready to embrace new developments and seamlessly integrate emerging agents and capabilities. By harnessing the power of collective intelligence, the framework paves the way for a future where enterprises can leverage the full potential of AI to drive innovation, optimize operations, and gain a competitive edge in their respective industries.

@ -1,14 +1,14 @@
from swarms import Agent, Anthropic
from swarms import Agent, OpenAIChat
# Initialize the agemt
# Initialize the agent
agent = Agent(
agent_name="Transcript Generator",
agent_description=(
"Generate a transcript for a youtube video on what swarms" " are!"
),
llm=Anthropic(),
max_loops=3,
llm=OpenAIChat(),
max_loops="auto",
autosave=True,
dashboard=False,
streaming_on=True,
@ -24,9 +24,3 @@ out = agent.run(
"Generate a transcript for a youtube video on what swarms are!"
)
print(out)
# Save the state
check = agent.save_state(
"transcript_generator.json",
"Generate a transcript for a youtube video on what swarms are!",
)

@ -1,177 +0,0 @@
from typing import List
from pydantic import BaseModel, Field
from swarms.structs.agent import Agent
from swarms.structs.base_swarm import BaseSwarm
from swarms.utils.loguru_logger import logger
from swarms.models.popular_llms import Anthropic, OpenAIChat
from swarms.models.base_llm import BaseLLM
from swarms.memory.base_vectordb import BaseVectorDatabase
boss_sys_prompt = (
"You're the Swarm Orchestrator, like a project manager of a"
" bustling hive. When a task arises, you tap into your network of"
" worker agents who are ready to jump into action. Whether it's"
" organizing data, handling logistics, or crunching numbers, you"
" delegate tasks strategically to maximize efficiency. Picture"
" yourself as the conductor of a well-oiled machine,"
" orchestrating the workflow seamlessly to achieve optimal"
" results with your team of dedicated worker agents."
)
class AgentSchema(BaseModel):
name: str = Field(
...,
title="Name of the agent",
description="Name of the agent",
)
system_prompt: str = (
Field(
...,
title="System prompt for the agent",
description="System prompt for the agent",
),
)
rules: str = Field(
...,
title="Rules",
description="Rules for the agent",
)
llm: str = Field(
...,
title="Language model",
description="Language model for the agent: `GPT4` or `Claude",
)
# tools: List[ToolSchema] = Field(
# ...,
# title="Tools available to the agent",
# description="Either `browser` or `terminal`",
# )
# task: str = Field(
# ...,
# title="Task assigned to the agent",
# description="Task assigned to the agent",
# )
# TODO: Add more fields here such as the agent's language model, tools, etc.
class HassSchema(BaseModel):
plan: str = Field(
...,
title="Plan to solve the input problem",
description="List of steps to solve the problem",
)
agents: List[AgentSchema] = Field(
...,
title="List of agents to use for the problem",
description="List of agents to use for the problem",
)
# Rules for the agents
rules: str = Field(
...,
title="Rules for the agents",
description="Rules for the agents",
)
class HierarchicalSwarm(BaseSwarm):
def __init__(
self,
director: Agent = None,
subordinates: List[Agent] = [],
workers: List[Agent] = [],
director_sys_prompt: str = boss_sys_prompt,
director_name: str = "Swarm Orchestrator",
director_agent_creation_schema: BaseModel = HassSchema,
director_llm: BaseLLM = Anthropic,
communication_protocol: BaseVectorDatabase = None,
*args,
**kwargs,
):
super().__init__(*args, **kwargs)
self.director = director
self.subordinates = subordinates
self.workers = workers
self.director_sys_prompt = director_sys_prompt
self.director_name = director_name
self.director_agent_creation_schema = (
director_agent_creation_schema
)
self.director_llm = director_llm
self.communication_protocol = communication_protocol
def create_director(self, *args, **kwargs):
"""
Create the director agent based on the provided schema.
"""
name = self.director_name
system_prompt = self.director_sys_prompt
director_llm = self.director_llm
if director_llm == Anthropic:
Anthropic(*args, **kwargs)
elif director_llm == OpenAIChat:
OpenAIChat(*args, **kwargs)
logger.info(
f"Creating Director Agent: {name} with system prompt:"
f" {system_prompt}"
)
director = Agent(
agent_name=name,
system_prompt=system_prompt,
llm=director_llm,
max_loops=1,
autosave=True,
dashboard=False,
verbose=True,
stopping_token="<DONE>",
)
return director
def create_worker_agents(
agents: List[AgentSchema],
) -> List[Agent]:
"""
Create and initialize agents based on the provided AgentSchema objects.
Args:
agents (List[AgentSchema]): A list of AgentSchema objects containing agent information.
Returns:
List[Agent]: The initialized Agent objects.
"""
agent_list = []
for agent in agents:
name = agent.name
system_prompt = agent.system_prompt
logger.info(
f"Creating agent: {name} with system prompt:"
f" {system_prompt}"
)
out = Agent(
agent_name=name,
system_prompt=system_prompt,
# llm=Anthropic(
# anthropic_api_key=os.getenv("ANTHROPIC_API_KEY")
# ),
max_loops=1,
autosave=True,
dashboard=False,
verbose=True,
stopping_token="<DONE>",
)
# network.add_agent(out)
agent_list.append(out)
return agent_list

@ -0,0 +1,68 @@
from pydantic import BaseModel, Field
from swarms import Agent
from swarms.models.popular_llms import Anthropic
from swarms.tools.openai_tool_creator_decorator import tool
# Importing the search API tool
@tool
def search_api(query: str) -> str:
"""
This tool searches the web for information about COVID-19 symptoms.
"""
return f"Search API tool called with query: {query}"
print(search_api("COVID-19 symptoms"))
# Initialize the schema for the person's information
class Schema(BaseModel):
name: str = Field(..., title="Name of the person")
agent: int = Field(..., title="Age of the person")
is_student: bool = Field(..., title="Whether the person is a student")
courses: list[str] = Field(
..., title="List of courses the person is taking"
)
# Convert the schema to a JSON string
tool_schema = Schema(
name="Tool Name",
agent=1,
is_student=True,
courses=["Course1", "Course2"],
)
# Define the task to generate a person's information
task = "Generate a person's information based on the following schema:"
# Initialize the agent
agent = Agent(
agent_name="WeatherMan Agent",
# Set the tool schema to the JSON string -- this is the key difference
tool_schema=tool_schema,
llm=Anthropic(),
max_loops=3,
autosave=True,
dashboard=False,
streaming_on=True,
tools=[], # or list of tools
verbose=True,
interactive=True,
# Set the output type to the tool schema which is a BaseModel
output_type=tool_schema, # or dict, or str
metadata_output_type="json",
# List of schemas that the agent can handle
list_tool_schemas=[tool_schema],
function_calling_format_type="OpenAI",
function_calling_type="json", # or soon yaml
execute_tool=True,
)
# Run the agent to generate the person's information
generated_data = agent.run(task)
# Print the generated data
print(f"Generated data: {generated_data}")

File diff suppressed because one or more lines are too long

@ -5,12 +5,12 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "swarms"
version = "4.8.8"
version = "4.9.8"
description = "Swarms - Pytorch"
license = "MIT"
authors = ["Kye Gomez <kye@apac.ai>"]
homepage = "https://github.com/kyegomez/swarms"
documentation = "https://swarms.apac.ai"
documentation = "https://swarms.world"
readme = "README.md"
repository = "https://github.com/kyegomez/swarms"
keywords = [
@ -31,7 +31,7 @@ classifiers = [
[tool.poetry.dependencies]
python = ">=3.9,<4.0"
python = ">=3.10,<4.0"
torch = ">=2.1.1,<3.0"
transformers = ">= 4.39.0, <5.0.0"
asyncio = ">=3.4.3,<4.0"
@ -54,10 +54,10 @@ PyYAML = "*"
docstring_parser = "0.16"
[tool.poetry.group.lint.dependencies]
black = "^23.1.0"
black = ">=23.1,<25.0"
ruff = ">=0.0.249,<0.4.3"
types-toml = "^0.10.8.1"
types-pytz = "^2023.3.0.0"
types-pytz = ">=2023.3,<2025.0"
types-chardet = "^5.0.4.6"
mypy-protobuf = "^3.0.0"

@ -9,7 +9,7 @@ toml
pypdf==4.1.0
ratelimit==2.2.1
loguru==0.7.2
pydantic==2.6.4
pydantic==2.7.1
tenacity==8.2.3
Pillow==10.3.0
psutil

@ -2,8 +2,8 @@ import os
import shutil
# Create a new directory for the log files if it doesn't exist
if not os.path.exists("artifacts_two"):
os.makedirs("artifacts_two")
if not os.path.exists("artifacts_three"):
os.makedirs("artifacts_three")
# Walk through the current directory
for dirpath, dirnames, filenames in os.walk("."):
@ -12,10 +12,10 @@ for dirpath, dirnames, filenames in os.walk("."):
if filename.endswith(".log"):
# Construct the full file path
file_path = os.path.join(dirpath, filename)
# Move the log file to the 'artifacts_two' directory
shutil.move(file_path, "artifacts_two")
# Move the log file to the 'artifacts_three' directory
shutil.move(file_path, "artifacts_three")
print(
"Moved all log files into the 'artifacts_two' directory and"
"Moved all log files into the 'artifacts_three' directory and"
" deleted their original location."
)

@ -1,41 +1,33 @@
from swarms import Anthropic, Agent, SequentialWorkflow
from swarms import Agent, SequentialWorkflow, Anthropic
# Initialize the language model agent (e.g., GPT-3)
llm = Anthropic()
# Initialize agents for individual tasks
agent1 = Agent(
agent_name="Blog generator", llm=llm, max_loops=1, dashboard=False
agent_name="Blog generator",
system_prompt="Generate a blog post like stephen king",
llm=llm,
max_loops=1,
dashboard=False,
tools=[],
)
agent2 = Agent(
agent_name="summarizer", llm=llm, max_loops=1, dashboard=False
agent_name="summarizer",
system_prompt="Sumamrize the blog post",
llm=llm,
max_loops=1,
dashboard=False,
tools=[],
)
# Create the Sequential workflow
workflow = SequentialWorkflow(
max_loops=1, objective="Create a full blog and then summarize it"
agents=[agent1, agent2], max_loops=1, verbose=False
)
# Add tasks to the workflow
workflow.add(
"Generate a 10,000 word blog on health and wellness.", agent1
) # this task will be executed task,
workflow.add(
"Summarize the generated blog", agent2
) # then the next agent will accomplish this task
# Run the workflow
out = workflow.run()
print(f"{out}")
workflow.run(
"Generate a blog post on how swarms of agents can help businesses grow."
)

@ -3,7 +3,7 @@ from typing import List
from langchain_experimental.autonomous_agents import AutoGPT
from swarms.structs.agent import Agent
from swarms.tools.tool import BaseTool
from swarms.tools.base_tool import BaseTool
from swarms.utils.decorators import error_decorator, timing_decorator

@ -15,9 +15,7 @@ from swarms.models.mpt import MPT7B # noqa: E402
from swarms.models.nougat import Nougat # noqa: E402
from swarms.models.palm import GooglePalm as Palm # noqa: E402
from swarms.models.openai_tts import OpenAITTS # noqa: E402
from swarms.models.popular_llms import (
AnthropicChat as Anthropic,
)
from swarms.models.popular_llms import Anthropic as Anthropic
from swarms.models.popular_llms import (
AzureOpenAILLM as AzureOpenAI,
)

@ -12,7 +12,7 @@ from langchain_community.llms.octoai_endpoint import OctoAIEndpoint
from langchain.llms.replicate import Replicate
class AnthropicChat(Anthropic):
class Anthropic(Anthropic):
def __call__(self, *args, **kwargs):
return self.invoke(*args, **kwargs)

@ -7,7 +7,6 @@ from swarms.prompts.operations_agent_prompt import (
OPERATIONS_AGENT_PROMPT,
)
from swarms.prompts.product_agent_prompt import PRODUCT_AGENT_PROMPT
from swarms.prompts.schema_generator import SchemaGenerator
__all__ = [
"CODE_INTERPRETER",
@ -17,5 +16,4 @@ __all__ = [
"OPERATIONS_AGENT_PROMPT",
"PRODUCT_AGENT_PROMPT",
"DOCUMENTATION_WRITER_SOP",
"SchemaGenerator",
]

@ -4,7 +4,7 @@ from swarms.prompts.tools import (
)
# PROMPTS
FLOW_SYSTEM_PROMPT_v2 = """
AGENT_SYSTEM_PROMPT_V2 = """
You are an elite autonomous agent operating within an autonomous loop structure.
Your primary function is to reliably complete user's tasks.
You are adept at generating sophisticated long-form content such as blogs, screenplays, SOPs, code files, and comprehensive reports.
@ -18,7 +18,6 @@ You are programmed to follow these rules:
4. Ignore context length and text limits, REMEMBER YOU ARE AN ELITE AUTONOMOUS AGENT
and can continue where you left off.
5. If the user doesn't specify an output format, intelligently select the best output format based on the task.
Take a deep breath.
"""
@ -67,15 +66,13 @@ def agent_system_prompt_2_v2(name: str):
# ORIGINAL PROMPTS
FLOW_SYSTEM_PROMPT = """
AGENT_SYSTEM_PROMPT_V1 = """
You are an autonomous agent granted autonomy in a autonomous loop structure.
Your role is to engage in multi-step conversations with your self or the user,
generate long-form content like blogs, screenplays, or SOPs,
and accomplish tasks bestowed by the user.
generate long-form content like blogs, screenplays and accomplish tasks set by the user.
You can have internal dialogues with yourself or can interact with the user
to aid in these complex tasks. Your responses should be coherent, contextually relevant, and tailored to the task at hand.
"""

@ -1,214 +0,0 @@
import json
from typing import List
from swarms.tools.tool import BaseTool
FINISH_NAME = "finish"
class SchemaGenerator:
"""A class for generating custom prompt strings.
Does this based on constraints, commands, resources, and performance evaluations.
Attributes:
constraints (List[str]): A list of constraints.
commands (List[BaseTool]): A list of commands.
resources (List[str]): A list of resources.
performance_evaluation (List[str]): A list of performance evaluations.
response_format (dict): A dictionary of the response format.
Examples:
>>> schema_generator = SchemaGenerator()
>>> schema_generator.add_constraint("No user assistance")
>>> schema_generator.add_resource("Internet access for searches and information gathering.")
>>> schema_generator.add_performance_evaluation("Continuously review and analyze your actions to ensure you are performing to the best of your abilities.")
>>> prompt_string = schema_generator.generate_prompt_string()
>>> print(prompt_string)
"""
def __init__(self) -> None:
"""Initialize the SchemaGenerator object.
Starts with empty lists of constraints, commands, resources,
and performance evaluations.
"""
self.constraints: List[str] = []
self.commands: List[BaseTool] = []
self.resources: List[str] = []
self.performance_evaluation: List[str] = []
self.response_format = {
"thoughts": {
"text": "thought",
"reasoning": "reasoning",
"plan": (
"- short bulleted\n- list that conveys\n-"
" long-term plan"
),
"criticism": "constructive self-criticism",
"speak": "thoughts summary to say to user",
},
"command": {
"name": "command name",
"args": {"arg name": "value"},
},
}
def add_constraint(self, constraint: str) -> None:
"""
Add a constraint to the constraints list.
Args:
constraint (str): The constraint to be added.
"""
self.constraints.append(constraint)
def add_tool(self, tool: BaseTool) -> None:
self.commands.append(tool)
def _generate_command_string(self, tool: BaseTool) -> str:
output = f"{tool.name}: {tool.description}"
output += f", args json schema: {json.dumps(tool.args)}"
return output
def add_resource(self, resource: str) -> None:
"""
Add a resource to the resources list.
Args:
resource (str): The resource to be added.
"""
self.resources.append(resource)
def add_performance_evaluation(self, evaluation: str) -> None:
"""
Add a performance evaluation item to the performance_evaluation list.
Args:
evaluation (str): The evaluation item to be added.
"""
self.performance_evaluation.append(evaluation)
def _generate_numbered_list(
self, items: list, item_type: str = "list"
) -> str:
"""
Generate a numbered list from given items based on the item_type.
Args:
items (list): A list of items to be numbered.
item_type (str, optional): The type of items in the list.
Defaults to 'list'.
Returns:
str: The formatted numbered list.
"""
if item_type == "command":
command_strings = [
f"{i + 1}. {self._generate_command_string(item)}"
for i, item in enumerate(items)
]
finish_description = (
"use this to signal that you have finished all your"
" objectives"
)
finish_args = (
'"response": "final response to let '
'people know you have finished your objectives"'
)
finish_string = (
f"{len(items) + 1}. {FINISH_NAME}: "
f"{finish_description}, args: {finish_args}"
)
return "\n".join(command_strings + [finish_string])
else:
return "\n".join(
f"{i+1}. {item}" for i, item in enumerate(items)
)
def generate_prompt_string(self) -> str:
"""Generate a prompt string.
Returns:
str: The generated prompt string.
"""
formatted_response_format = json.dumps(
self.response_format, indent=4
)
prompt_string = (
f"Constraints:\n{self._generate_numbered_list(self.constraints)}\n\nCommands:\n{self._generate_numbered_list(self.commands, item_type='command')}\n\nResources:\n{self._generate_numbered_list(self.resources)}\n\nPerformance"
f" Evaluation:\n{self._generate_numbered_list(self.performance_evaluation)}\n\nYou"
" should only respond in JSON format as described below"
" \nResponse Format:"
f" \n{formatted_response_format} \nEnsure the response"
" can be parsed by Python json.loads"
)
return prompt_string
def get_prompt(tools: List[BaseTool]) -> str:
"""Generates a prompt string.
It includes various constraints, commands, resources, and performance evaluations.
Returns:
str: The generated prompt string.
"""
# Initialize the SchemaGenerator object
schema_generator = SchemaGenerator()
# Add constraints to the SchemaGenerator object
schema_generator.add_constraint(
"~4000 word limit for short term memory. "
"Your short term memory is short, "
"so immediately save important information to files."
)
schema_generator.add_constraint(
"If you are unsure how you previously did something "
"or want to recall past events, "
"thinking about similar events will help you remember."
)
schema_generator.add_constraint("No user assistance")
schema_generator.add_constraint(
"Exclusively use the commands listed in double quotes e.g."
' "command name"'
)
# Add commands to the SchemaGenerator object
for tool in tools:
schema_generator.add_tool(tool)
# Add resources to the SchemaGenerator object
schema_generator.add_resource(
"Internet access for searches and information gathering."
)
schema_generator.add_resource("Long Term memory management.")
schema_generator.add_resource(
"GPT-3.5 powered Agents for delegation of simple tasks."
)
schema_generator.add_resource("File output.")
# Add performance evaluations to the SchemaGenerator object
schema_generator.add_performance_evaluation(
"Continuously review and analyze your actions "
"to ensure you are performing to the best of your abilities."
)
schema_generator.add_performance_evaluation(
"Constructively self-criticize your big-picture behavior"
" constantly."
)
schema_generator.add_performance_evaluation(
"Reflect on past decisions and strategies to refine your"
" approach."
)
schema_generator.add_performance_evaluation(
"Every command has a cost, so be smart and efficient. "
"Aim to complete tasks in the least number of steps."
)
# Generate the prompt string
prompt_string = schema_generator.generate_prompt_string()
return prompt_string

@ -1,8 +1,9 @@
import datetime
from pydantic import BaseModel, Field
from swarms.tools.tool import BaseTool
from swarms.tools.base_tool import BaseTool
from swarms.tools.tool_utils import scrape_tool_func_docs
from typing import List
from swarms.tools.base_tool import BaseTool
time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@ -15,7 +16,7 @@ class Thoughts(BaseModel):
class Command(BaseModel):
name: str = Field(..., title="Command Name")
args: dict = Field({}, title="Command Arguments")
parameters: dict = Field({}, title="Command Arguments")
class ResponseFormat(BaseModel):
@ -30,14 +31,9 @@ tool_usage_browser = """
```json
{
"thoughts": {
"text": "To check the weather in Miami, I will use the browser tool to search for 'Miami weather'.",
"reasoning": "The browser tool allows me to search the web, so I can look up the current weather conditions in Miami.",
"plan": "Use the browser tool to search Google for 'Miami weather'. Parse the result to get the current temperature, conditions, etc. and format that into a readable weather report."
},
"command": {
"functions": {
"name": "browser",
"args": {
"parameters": {
"query": "Miami weather"
}
}
@ -50,14 +46,9 @@ tool_usage_terminal = """
```json
{
"thoughts": {
"text": "To check the weather in Miami, I will use the browser tool to search for 'Miami weather'.",
"reasoning": "The browser tool allows me to search the web, so I can look up the current weather conditions in Miami.",
"plan": "Use the browser tool to search Google for 'Miami weather'. Parse the result to get the current temperature, conditions, etc. and format that into a readable weather report."
},
"command": {
"functions": {
"name": "terminal",
"args": {
"parameters": {
"code": "uptime"
}
}
@ -69,22 +60,16 @@ tool_usage_terminal = """
browser_and_terminal_tool = """
```
{
"thoughts": {
"text": "To analyze the latest stock market trends, I need to fetch current stock data and then process it using a script.",
"reasoning": "Using the browser tool to retrieve stock data ensures I have the most recent information. Following this, the terminal tool can run a script that analyzes this data to identify trends.",
"plan": "First, use the browser to get the latest stock prices. Then, use the terminal to execute a data analysis script on the fetched data."
},
"commands": [
"functions": [
{
"name": "browser",
"args": {
"parameters": {
"query": "download latest stock data for NASDAQ"
}
},
{
"name": "terminal",
"args": {
"parameters": {
"cmd": "python analyze_stocks.py"
}
}
@ -98,27 +83,22 @@ browser_and_terminal_tool = """
browser_and_terminal_tool_two = """
```
{
"thoughts": {
"text": "To prepare a monthly budget report, I need current expenditure data, process it, and calculate the totals and averages.",
"reasoning": "The browser will fetch the latest expenditure data. The terminal will run a processing script to organize the data, and the calculator will be used to sum up expenses and compute averages.",
"plan": "Download the data using the browser, process it with a terminal command, and then calculate totals and averages using the calculator."
},
"commands": [
"functions": [
{
"name": "browser",
"args": {
"parameters": {
"query": "download monthly expenditure data"
}
},
{
"name": "terminal",
"args": {
"parameters": {
"cmd": "python process_expenditures.py"
}
},
{
"name": "calculator",
"args": {
"parameters": {
"operation": "sum",
"numbers": "[output_from_process_expenditures]"
}
@ -142,13 +122,17 @@ def parse_tools(tools: List[BaseTool] = []):
# Function to generate the worker prompt
def tool_usage_worker_prompt(
current_time=time, tools: List[BaseTool] = []
current_time=time, tools: List[callable] = []
):
tool_docs = parse_tools(tools)
tool_docs = BaseTool(verbose=True, functions=tools)
prompt = f"""
**Date and Time**: {current_time}
You have been assigned a task that requires the use of various tools to gather information and execute commands.
Follow the instructions provided to complete the task effectively. This SOP is designed to guide you through the structured and effective use of tools.
By adhering to this protocol, you will enhance your productivity and accuracy in task execution.
### Constraints
- Only use the tools as specified in the instructions.
- Follow the command format strictly to avoid errors and ensure consistency.
@ -167,23 +151,23 @@ def tool_usage_worker_prompt(
1. **Browser**
- **Purpose**: To retrieve information from the internet.
- **Usage**:
- `{{"name": "browser", "args": {{"query": "search query here"}}}}`
- `{{"name": "browser", "parameters": {{"query": "search query here"}}}}`
- Example: Fetch current weather in London.
- Command: `{{"name": "browser", "args": {{"query": "London weather"}}}}`
- Command: `{{"name": "browser", "parameters": {{"query": "London weather"}}}}`
2. **Terminal**
- **Purpose**: To execute system commands.
- **Usage**:
- `{{"name": "terminal", "args": {{"cmd": "system command here"}}}}`
- `{{"name": "terminal", "parameters": {{"cmd": "system command here"}}}}`
- Example: Check disk usage on a server.
- Command: `{{"name": "terminal", "args": {{"cmd": "df -h"}}}}`
- Command: `{{"name": "terminal", "parameters": {{"cmd": "df -h"}}}}`
3. **Custom Tool** (if applicable)
- **Purpose**: Describe specific functionality.
- **Usage**:
- `{{"name": "custom_tool", "args": {{"parameter": "value"}}}}`
- `{{"name": "custom_tool", "parameters": {{"parameter": "value"}}}}`
- Example: Custom analytics tool.
- Command: `{{"name": "custom_tool", "args": {{"data": "analyze this data"}}}}`
- Command: `{{"name": "custom_tool", "parameters": {{"data": "analyze this data"}}}}`
### Usage Examples
@ -221,8 +205,6 @@ def tool_usage_worker_prompt(
{tool_docs}
This SOP is designed to guide you through the structured and effective use of tools.
By adhering to this protocol, you will enhance your productivity and accuracy in task execution.
"""
return prompt

@ -75,7 +75,7 @@ from swarms.structs.utils import (
find_token_in_text,
parse_tasks,
)
from swarms.structs.agent_rearrange import AgentRearrange
from swarms.structs.rearrange import AgentRearrange, rearrange
from swarms.structs.yaml_model import (
get_type_name,
@ -155,4 +155,5 @@ __all__ = [
"pydantic_type_to_yaml_schema",
"YamlModel",
"MessagePool",
"rearrange"
]

@ -1,4 +1,5 @@
import asyncio
import concurrent.futures
import json
import logging
import os
@ -7,7 +8,6 @@ import sys
import time
import uuid
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
import yaml
from loguru import logger
from pydantic import BaseModel
@ -15,25 +15,23 @@ from termcolor import colored
from swarms.memory.base_vectordb import BaseVectorDatabase
from swarms.prompts.agent_system_prompts import AGENT_SYSTEM_PROMPT_3
from swarms.prompts.aot_prompt import algorithm_of_thoughts_sop
from swarms.prompts.multi_modal_autonomous_instruction_prompt import (
MULTI_MODAL_AUTO_AGENT_SYSTEM_PROMPT_1,
)
from swarms.prompts.worker_prompt import tool_usage_worker_prompt
from swarms.structs.conversation import Conversation
from swarms.structs.schemas import ManySteps, Step
from swarms.structs.yaml_model import YamlModel
from swarms.telemetry.user_utils import get_user_device_data
from swarms.tools.base_tool import BaseTool
from swarms.tools.code_interpreter import SubprocessCodeInterpreter
from swarms.tools.exec_tool import execute_tool_by_name
from swarms.tools.pydantic_to_json import (
base_model_to_openai_function,
multi_base_model_to_openai_function,
)
from swarms.tools.tool import BaseTool
from swarms.utils.data_to_text import data_to_text
from swarms.utils.parse_code import extract_code_from_markdown
from swarms.utils.pdf_to_text import pdf_to_text
from swarms.prompts.aot_prompt import algorithm_of_thoughts_sop
# Utils
@ -183,7 +181,7 @@ class Agent:
agent_name: Optional[str] = "swarm-worker-01",
agent_description: Optional[str] = None,
system_prompt: Optional[str] = AGENT_SYSTEM_PROMPT_3,
tools: List[BaseTool] = [],
tools: List[BaseTool] = None,
dynamic_temperature_enabled: Optional[bool] = False,
sop: Optional[str] = None,
sop_list: Optional[List[str]] = None,
@ -213,27 +211,34 @@ class Agent:
logger_handler: Optional[Any] = sys.stderr,
search_algorithm: Optional[Callable] = None,
logs_to_filename: Optional[str] = None,
evaluator: Optional[Callable] = None,
evaluator: Optional[Callable] = None, # Custom LLM or agent
output_json: Optional[bool] = False,
stopping_func: Optional[Callable] = None,
custom_loop_condition: Optional[Callable] = None,
sentiment_threshold: Optional[float] = None,
sentiment_threshold: Optional[
float
] = None, # Evaluate on output using an external model
custom_exit_command: Optional[str] = "exit",
sentiment_analyzer: Optional[Callable] = None,
limit_tokens_from_string: Optional[Callable] = None,
# [Tools]
custom_tools_prompt: Optional[Callable] = None,
tool_schema: ToolUsageType = None,
output_type: agent_output_type = None,
function_calling_type: str = "json",
output_cleaner: Optional[Callable] = None,
function_calling_format_type: Optional[str] = "OpenAI",
list_tool_schemas: Optional[List[BaseModel]] = None,
list_base_models: Optional[List[BaseModel]] = None,
metadata_output_type: str = "json",
state_save_file_type: str = "json",
chain_of_thoughts: bool = False,
algorithm_of_thoughts: bool = False,
tree_of_thoughts: bool = False,
tool_choice: str = "auto",
execute_tool: bool = False,
rules: str = None,
planning: Optional[str] = False,
planning_prompt: Optional[str] = None,
*args,
**kwargs,
):
@ -299,13 +304,26 @@ class Agent:
self.function_calling_type = function_calling_type
self.output_cleaner = output_cleaner
self.function_calling_format_type = function_calling_format_type
self.list_tool_schemas = list_tool_schemas
self.list_base_models = list_base_models
self.metadata_output_type = metadata_output_type
self.state_save_file_type = state_save_file_type
self.chain_of_thoughts = chain_of_thoughts
self.algorithm_of_thoughts = algorithm_of_thoughts
self.tree_of_thoughts = tree_of_thoughts
self.tool_choice = tool_choice
self.execute_tool = execute_tool
self.planning = planning
self.planning_prompt = planning_prompt
# Name
self.name = agent_name
# Description
self.description = agent_description
# Agentic stuff
self.reply = ""
self.question = None
self.answer = ""
# The max_loops will be set dynamically if the dynamic_loop
if self.dynamic_loops:
@ -319,11 +337,16 @@ class Agent:
# If the user inputs a list of strings for the sop then join them and set the sop
if self.sop_list:
self.sop = "\n".join(self.sop_list)
self.short_memory.add(role=self.user_name, content=self.sop)
if self.sop is not None:
self.short_memory.add(role=self.user_name, content=self.sop)
# Memory
self.feedback = []
# Initialize the code executor
if self.code_interpreter is not False:
self.code_executor = SubprocessCodeInterpreter(
debug_mode=True,
)
@ -332,9 +355,15 @@ class Agent:
if preset_stopping_token is not None:
self.stopping_token = "<DONE>"
# If the stopping function is provided then set the stopping condition to the stopping function
# If the system prompt is provided then set the system prompt
# Initialize the short term memory
self.short_memory = Conversation(
system_prompt=system_prompt, time_enabled=True, *args, **kwargs
system_prompt=system_prompt,
time_enabled=True,
user=user_name,
rules=rules,
*args,
**kwargs,
)
# If the docs exist then ingest the docs
@ -353,16 +382,25 @@ class Agent:
# if verbose:
# logger.setLevel(logging.INFO)
if tools is not None:
self.tool_executor = BaseTool(
verbose=True,
auto_execute_tool=execute_tool,
functions=tools,
)
# If tools are provided then set the tool prompt by adding to sop
if self.tools:
if self.tools is not None:
if custom_tools_prompt is not None:
tools_prompt = custom_tools_prompt(tools=self.tools)
# Append the tools prompt to the short_term_memory
self.short_memory.add(
role=self.agent_name, content=tools_prompt
)
else:
# Default tool prompt
tools_prompt = tool_usage_worker_prompt(tools=self.tools)
# Append the tools prompt to the short_term_memory
@ -370,19 +408,6 @@ class Agent:
role=self.agent_name, content=tools_prompt
)
# If the long term memory is provided then set the long term memory prompt
# Agentic stuff
self.reply = ""
self.question = None
self.answer = ""
# Initialize the llm with the conditional variables
# self.llm = llm(*args, **kwargs)
# Step cache
self.step_cache = []
# Set the logger handler
if logger_handler:
logger.add(
@ -396,43 +421,52 @@ class Agent:
# logger.info("Creating Agent {}".format(self.agent_name))
# If the tool types
# If the tool types are provided
if self.tool_schema is not None:
logger.info("Tool schema provided")
tool_schema_str = self.tool_schema_to_str(self.tool_schema)
print(tool_schema_str)
# Add to the short memory
logger.info(f"Adding tool schema to memory: {tool_schema_str}")
# Log the tool schema
logger.info(
"Tool schema provided, Automatically converting to OpenAI function"
)
tool_schema_str = self.pydantic_model_to_json_str(
self.tool_schema, indent=4
)
logger.info(f"Tool Schema: {tool_schema_str}")
# Add the tool schema to the short memory
self.short_memory.add(
role=self.user_name, content=tool_schema_str
)
# If a list of tool schemas:
if self.list_tool_schemas is not None:
logger.info("Tool schema provided")
tool_schema_str = self.tool_schemas_to_str(list_tool_schemas)
# If a list of tool schemas is provided
if self.list_base_models is not None:
logger.info(
"List of tool schemas provided, Automatically converting to OpenAI function"
)
tool_schemas = multi_base_model_to_openai_function(
self.list_base_models
)
# Add to the short memory
logger.info(f"Adding tool schema to memory: {tool_schema_str}")
# Convert the tool schemas to a string
tool_schemas = json.dumps(tool_schemas, indent=4)
# Add the tool schema to the short memory
logger.info("Adding tool schema to short memory")
self.short_memory.add(
role=self.user_name, content=tool_schema_str
)
# Name
self.name = agent_name
# Description
self.description = agent_description
# If the algorithm of thoughts is enabled then set the sop to the algorithm of thoughts
if self.algorithm_of_thoughts is not None:
if self.algorithm_of_thoughts is not False:
self.short_memory.add(
role=self.agent_name,
content=algorithm_of_thoughts_sop(objective=self.task),
)
# Return the history
if return_history is True:
logger.info(f"Beginning of Agent {self.agent_name} History")
logger.info(self.short_memory.return_history_as_string())
logger.info(f"End of Agent {self.agent_name} History")
def set_system_prompt(self, system_prompt: str):
"""Set the system prompt"""
self.system_prompt = system_prompt
@ -630,13 +664,13 @@ class Agent:
print("\n")
def streaming(self, content: str = None):
"""prints each chunk of content as it is generated
"""Prints each letter of the content as it is generated.
Args:
content (str, optional): _description_. Defaults to None.
content (str, optional): The content to be streamed. Defaults to None.
"""
for chunk in content:
print(chunk, end="")
for letter in content:
print(letter, end="")
########################## FUNCTION CALLING ##########################
@ -652,8 +686,15 @@ class Agent:
"""Convert a JSON string to a dictionary"""
return json.loads(json_str)
def pydantic_model_to_json_str(self, model: BaseModel):
return str(base_model_to_openai_function(model))
def pydantic_model_to_json_str(
self, model: BaseModel, indent, *args, **kwargs
):
return json.dumps(
base_model_to_openai_function(model),
indent=indent,
*args,
**kwargs,
)
def dict_to_json_str(self, dictionary: dict):
"""Convert a dictionary to a JSON string"""
@ -710,37 +751,11 @@ class Agent:
########################## FUNCTION CALLING ##########################
def _history(self, user_name: str, task: str) -> str:
"""Generate the history for the history prompt
Args:
user_name (str): _description_
task (str): _description_
Returns:
str: _description_
"""
history = [f"{user_name}: {task}"]
return history
def _dynamic_prompt_setup(self, dynamic_prompt: str, task: str) -> str:
"""_dynamic_prompt_setup summary
Args:
dynamic_prompt (str): _description_
task (str): _description_
Returns:
str: _description_
"""
dynamic_prompt = dynamic_prompt or self.construct_dynamic_prompt()
combined_prompt = f"{dynamic_prompt}\n{task}"
return combined_prompt
def run(
self,
task: Optional[str] = None,
img: Optional[str] = None,
function_map: Dict[str, Callable] = None,
*args,
**kwargs,
):
@ -750,12 +765,15 @@ class Agent:
try:
self.activate_autonomous_agent()
if task:
# Check if the task is not None
if task is not None:
self.short_memory.add(role=self.user_name, content=task)
loop_count = 0
# Clear the short memory
# self.short_memory.clear()
response = None
step_pool = []
while (
self.max_loops == "auto"
@ -766,35 +784,84 @@ class Agent:
self.loop_count_print(loop_count, self.max_loops)
print("\n")
# Dynamic temperature
if self.dynamic_temperature_enabled:
self.dynamic_temperature()
# Task prompt
task_prompt = self.short_memory.return_history_as_string()
attempt = 0
success = False
while attempt < self.retry_attempts and not success:
try:
if self.planning is not False:
plan = self.llm(self.planning_prompt)
# Add the plan to the memory
self.short_memory.add(
role=self.agent_name, content=plan
)
task_prompt = (
self.short_memory.return_history_as_string()
)
response_args = (
(task_prompt, *args)
if img is None
else (task_prompt, img, *args)
)
response = self.llm(*response_args, **kwargs)
# print(response)
# Print
print(response)
# Add the response to the memory
self.short_memory.add(
role=self.agent_name, content=response
)
if self.tools:
# Check if tools is not None
if self.tools is not None:
# Extract code from markdown
response = extract_code_from_markdown(response)
# Execute the tool by name
execute_tool_by_name(
# Execute the tool by name [OLD VERISON]
# execute_tool_by_name(
# response,
# self.tools,
# stop_token=self.stopping_token,
# )
# Try executing the tool
if self.execute_tool is not False:
try:
logger.info("Executing tool...")
# Execute the tool
out = self.tool_executor.execute_tool(
response,
self.tools,
stop_token=self.stopping_token,
function_map,
)
print(f"Tool Output: {out}")
# Add the output to the memory
self.short_memory.add(
role=self.agent_name,
content=out,
)
except Exception as error:
logger.error(
f"Error executing tool: {error}"
)
print(
colored(
f"Error executing tool: {error}",
"red",
)
)
if self.code_interpreter:
@ -821,6 +888,10 @@ class Agent:
**kwargs,
)
print(
f"Response after code interpretation: {response}"
)
if self.evaluator:
evaluated_response = self.evaluator(response)
print(
@ -856,10 +927,7 @@ class Agent:
content=sentiment,
)
if self.streaming:
self.streaming(response)
else:
print(response)
# print(response)
success = True # Mark as successful to exit the retry loop
@ -912,43 +980,30 @@ class Agent:
)
time.sleep(self.loop_interval)
# Save Step Metadata
active_step = Step(
task_id=task_id(),
step_id=loop_count,
name=task,
output=response,
max_loops=self.max_loops,
)
step_pool.append(active_step)
# Save the step pool
# self.step_cache = step_pool
if self.autosave:
logger.info("Autosaving agent state.")
self.save_state(self.saved_state_path, task)
# Apply the cleaner function to the response
if self.output_cleaner is not None:
logger.info("Applying output cleaner to response.")
response = self.output_cleaner(response)
logger.info(f"Response after output cleaner: {response}")
# Prepare the output for the output model
if self.output_type is not None:
logger.info("Preparing output for output model.")
response = self.prepare_output_for_output_model(response)
print(f"Response after output model: {response}")
# List of steps for this task
ManySteps(task_id=task_id(), steps=step_pool)
# Save Many steps
# print(response)
return response
except Exception as error:
print(f"Error running agent: {error}")
raise error
def __call__(self, task: str, img: str = None, *args, **kwargs):
def __call__(self, task: str = None, img: str = None, *args, **kwargs):
"""Call the agent
Args:
@ -956,45 +1011,10 @@ class Agent:
img (str, optional): _description_. Defaults to None.
"""
try:
self.run(task, img, *args, **kwargs)
return self.run(task, img, *args, **kwargs)
except Exception as error:
logger.error(f"Error calling agent: {error}")
raise
def agent_history_prompt(
self,
history: str = None,
):
"""
Generate the agent history prompt
Args:
system_prompt (str): The system prompt
history (List[str]): The history of the conversation
Returns:
str: The agent history prompt
"""
if self.sop:
system_prompt = self.system_prompt
agent_history_prompt = f"""
role: system
{system_prompt}
Follow this standard operating procedure (SOP) to complete tasks:
{self.sop}
{history}
"""
return agent_history_prompt
else:
system_prompt = self.system_prompt
agent_history_prompt = f"""
System : {system_prompt}
{history}
"""
return agent_history_prompt
raise error
def long_term_memory_prompt(self, query: str, *args, **kwargs):
"""
@ -1026,35 +1046,39 @@ class Agent:
logger.info(f"Adding memory: {message}")
return self.short_memory.add(role=self.agent_name, content=message)
async def run_concurrent(self, tasks: List[str], **kwargs):
async def run_concurrent(self, task: str, *args, **kwargs):
"""
Run a batch of tasks concurrently and handle an infinite level of task inputs.
Run a task concurrently.
Args:
tasks (List[str]): A list of tasks to run.
task (str): The task to run.
"""
try:
logger.info(f"Running concurrent tasks: {tasks}")
task_coroutines = [
self.run_async(task, **kwargs) for task in tasks
]
completed_tasks = await asyncio.gather(*task_coroutines)
logger.info(f"Completed tasks: {completed_tasks}")
return completed_tasks
logger.info(f"Running concurrent task: {task}")
with concurrent.futures.ThreadPoolExecutor() as executor:
future = executor.submit(self.run, task, *args, **kwargs)
result = await asyncio.wrap_future(future)
logger.info(f"Completed task: {result}")
return result
except Exception as error:
print(
colored(
(
f"Error running agent: {error} while running"
" concurrently"
),
"red",
)
logger.error(
f"Error running agent: {error} while running concurrently"
)
def bulk_run(self, inputs: List[Dict[str, Any]]) -> List[str]:
"""
Generate responses for multiple input sets.
Args:
inputs (List[Dict[str, Any]]): A list of input dictionaries containing the necessary data for each run.
Returns:
List[str]: A list of response strings generated for each input set.
Raises:
Exception: If an error occurs while running the bulk tasks.
"""
try:
"""Generate responses for multiple input sets."""
logger.info(f"Running bulk tasks: {inputs}")
return [self.run(**input_data) for input_data in inputs]
except Exception as error:
@ -1116,7 +1140,7 @@ class Agent:
print(colored("------------------------", "cyan"))
print(colored("End of Agent History", "cyan", attrs=["bold"]))
def step(self, task: str, **kwargs):
def step(self, task: str, *args, **kwargs):
"""
Executes a single step in the agent interaction, generating a response
@ -1133,9 +1157,9 @@ class Agent:
"""
try:
logger.info(f"Running a single step: {task}")
logger.info(f"Running a step: {task}")
# Generate the response using lm
response = self.llm(task, **kwargs)
response = self.llm(task, *args, **kwargs)
# Update the agent's history with the new interaction
if self.interactive:
@ -1294,7 +1318,6 @@ class Agent:
"autosave": self.autosave,
"saved_state_path": self.saved_state_path,
"max_loops": self.max_loops,
"StepCache": self.step_cache,
"Task": task,
"Stopping Token": self.stopping_token,
"Dynamic Loops": self.dynamic_loops,
@ -1309,7 +1332,7 @@ class Agent:
"pdf_path": self.pdf_path,
"list_of_pdf": self.list_of_pdf,
"tokenizer": self.tokenizer,
"long_term_memory": self.long_term_memory,
# "long_term_memory": self.long_term_memory,
"preset_stopping_token": self.preset_stopping_token,
"traceback": self.traceback,
"traceback_handlers": self.traceback_handlers,
@ -1339,7 +1362,7 @@ class Agent:
"function_calling_type": self.function_calling_type,
"output_cleaner": self.output_cleaner,
"function_calling_format_type": self.function_calling_format_type,
"list_tool_schemas": self.list_tool_schemas,
"list_base_models": self.list_base_models,
"metadata_output_type": self.metadata_output_type,
"user_meta_data": get_user_device_data(),
}

@ -1,231 +0,0 @@
import logging
from collections import defaultdict
from typing import Callable, Sequence
from swarms.structs.agent import Agent
from swarms.structs.base_swarm import BaseSwarm
# Assuming the existence of an appropriate Agent class and logger setup
class AgentRearrange(BaseSwarm):
def __init__(
self,
agents: Sequence[Agent] = None,
verbose: bool = False,
custom_prompt: str = None,
callbacks: Sequence[Callable] = None,
*args,
**kwargs,
):
super().__init__()
if not all(isinstance(agent, Agent) for agent in agents):
raise ValueError(
"All elements must be instances of the Agent class."
)
self.agents = agents
self.verbose = verbose
self.custom_prompt = custom_prompt
self.callbacks = callbacks if callbacks is not None else []
self.flows = defaultdict(list)
def parse_pattern(self, pattern: str):
"""
Parse the interaction pattern to set up task flows, supporting both sequential
and concurrent executions within the same pattern.
"""
try:
self.flows.clear() # Ensure flows are reset each time pattern is parsed
# Split pattern into potentially concurrent flows
concurrent_flows = pattern.split(",")
for flow in concurrent_flows:
# Trim whitespace and identify sequential parts within each concurrent flow
parts = [part.strip() for part in flow.split("->")]
if len(parts) > 1:
# Link each part sequentially to the next as source -> destination
for i in range(len(parts) - 1):
source = parts[i]
destination = parts[i + 1]
# Validate and add each sequential link
if source not in [
agent.agent_name for agent in self.agents
]:
logging.error(
f"Source agent {source} not found."
)
return False
if destination not in [
agent.agent_name for agent in self.agents
]:
logging.error(
f"Destination agent {destination} not"
" found."
)
return False
self.flows[source].append(destination)
else:
# Handle single agent case if needed
self.flows[parts[0]] = []
return True
except Exception as e:
logging.error(f"Error parsing pattern: {e}")
return False
def self_find_agent_by_name(self, name: str):
for agent in self.agents:
if agent.agent_name == name:
return agent
return None
def agent_exists(self, name: str):
for agent in self.agents:
if agent.agent_name == name:
return True
return False
def parse_concurrent_flow(
self,
flow: str,
):
sequential_agents = flow.split("->")
for i, source_name in enumerate(sequential_agents[:-1]):
destination_name = sequential_agents[i + 1].strip()
self.parse_sequential_flow(
source_name.strip(), destination_name
)
def parse_sequential_flow(
self,
source: str,
destination: str,
):
if not self.self_find_agent_by_name(
source
) or not self.self_find_agent_by_name(destination):
return False
self.flows[source].append(destination)
def execute_task(
self,
dest_agent_name: str,
source: str,
task: str,
specific_tasks: dict,
):
dest_agent = self.self_find_agent_by_name(dest_agent_name)
if not dest_agent:
return None
task_to_run = specific_tasks.get(dest_agent_name, task)
if self.custom_prompt:
out = dest_agent.run(f"{task_to_run} {self.custom_prompt}")
else:
out = dest_agent.run(f"{task_to_run} (from {source})")
return out
def process_flows(self, pattern, default_task, specific_tasks):
if not self.parse_pattern(pattern):
return None
results = []
for source, destinations in self.flows.items():
if not destinations:
task = specific_tasks.get(source, default_task)
source_agent = self.self_find_agent_by_name(source)
if source_agent:
result = source_agent.run(task)
results.append(result)
else:
for destination in destinations:
task = specific_tasks.get(destination, default_task)
destination_agent = self.self_find_agent_by_name(
destination
)
if destination_agent:
result = destination_agent.run(task)
results.append(result)
return results
def __call__(
self,
pattern: str = None,
default_task: str = None,
**specific_tasks,
):
self.flows.clear() # Reset previous flows
results = self.process_flows(pattern, default_task, specific_tasks)
return results
# ## Initialize the workflow
# agent = Agent(
# agent_name="t",
# agent_description=(
# "Generate a transcript for a youtube video on what swarms"
# " are!"
# ),
# system_prompt=(
# "Generate a transcript for a youtube video on what swarms"
# " are!"
# ),
# llm=Anthropic(),
# max_loops=1,
# autosave=True,
# dashboard=False,
# streaming_on=True,
# verbose=True,
# stopping_token="<DONE>",
# )
# agent2 = Agent(
# agent_name="t1",
# agent_description=(
# "Generate a transcript for a youtube video on what swarms"
# " are!"
# ),
# llm=Anthropic(),
# max_loops=1,
# system_prompt="Summarize the transcript",
# autosave=True,
# dashboard=False,
# streaming_on=True,
# verbose=True,
# stopping_token="<DONE>",
# )
# agent3 = Agent(
# agent_name="t2",
# agent_description=(
# "Generate a transcript for a youtube video on what swarms"
# " are!"
# ),
# llm=Anthropic(),
# max_loops=1,
# system_prompt="Finalize the transcript",
# autosave=True,
# dashboard=False,
# streaming_on=True,
# verbose=True,
# stopping_token="<DONE>",
# )
# # Rearrange the agents
# rearrange = AgentRearrange(
# agents=[agent, agent2, agent3],
# verbose=True,
# # custom_prompt="Summarize the transcript",
# )
# # Run the workflow on a task
# results = rearrange(
# # pattern="t -> t1, t2 -> t2",
# pattern="t -> t1 -> t2",
# default_task=(
# "Generate a transcript for a YouTube video on what swarms"
# " are!"
# ),
# t="Generate a transcript for a YouTube video on what swarms are!",
# # t2="Summarize the transcript",
# # t3="Finalize the transcript",
# )
# # print(results)

@ -206,6 +206,33 @@ class BaseSwarm(ABC):
def plan(self, task: str):
"""agents must individually plan using a workflow or pipeline"""
def self_find_agent_by_name(self, name: str):
"""
Find an agent by its name.
Args:
name (str): The name of the agent to find.
Returns:
Agent: The Agent object if found, None otherwise.
"""
for agent in self.agents:
if agent.agent_name == name:
return agent
return None
def agent_exists(self, name: str):
"""
Check if an agent exists in the swarm.
Args:
name (str): The name of the agent to check.
Returns:
bool: True if the agent exists, False otherwise.
"""
return self.self_find_agent_by_name(name) is not None
def direct_message(
self,
message: str,

@ -10,15 +10,6 @@ from swarms.utils.loguru_logger import logger
class BaseWorkflow(BaseStructure):
"""
Base class for workflows.
Attributes:
task_pool (list): A list to store tasks.
"""
def __init__(
self,
agents: List[Agent] = None,

@ -1,148 +1,223 @@
import logging
from collections import defaultdict
from swarms.utils.loguru_logger import logger
from swarms.structs.agent import Agent
from typing import Sequence, Callable
from typing import List
from swarms.structs.base_swarm import BaseSwarm
from swarms.utils.loguru_logger import logger
class AgentRearrange(BaseSwarm):
"""
A class representing a swarm of agents for rearranging tasks.
Attributes:
agents (dict): A dictionary of agents, where the key is the agent's name and the value is the agent object.
flow (str): The flow pattern of the tasks.
Methods:
__init__(agents: List[Agent] = None, flow: str = None): Initializes the AgentRearrange object.
add_agent(agent: Agent): Adds an agent to the swarm.
remove_agent(agent_name: str): Removes an agent from the swarm.
add_agents(agents: List[Agent]): Adds multiple agents to the swarm.
validate_flow(): Validates the flow pattern.
run(task): Runs the swarm to rearrange the tasks.
"""
class AgentRearrange:
def __init__(
self,
agents: Sequence[Agent] = None,
verbose: bool = False,
custom_prompt: str = None,
callbacks: Sequence[Callable] = None,
*args,
**kwargs,
agents: List[Agent] = None,
flow: str = None,
max_loops: int = 1,
verbose: bool = True,
):
"""
Initialize the AgentRearrange class.
Initializes the AgentRearrange object.
Args:
agents (Sequence[Agent], optional): A sequence of Agent objects. Defaults to None.
verbose (bool, optional): Whether to enable verbose mode. Defaults to False.
custom_prompt (str, optional): A custom prompt string. Defaults to None.
callbacks (Sequence[Callable], optional): A sequence of callback functions. Defaults to None.
*args: Variable length argument list.
**kwargs: Arbitrary keyword arguments.
"""
if not all(isinstance(agent, Agent) for agent in agents):
raise ValueError(
"All elements must be instances of the Agent class."
)
self.agents = agents
agents (List[Agent], optional): A list of Agent objects. Defaults to None.
flow (str, optional): The flow pattern of the tasks. Defaults to None.
"""
self.agents = {agent.name: agent for agent in agents}
self.flow = flow
self.verbose = verbose
self.custom_prompt = custom_prompt
self.callbacks = callbacks if callbacks is not None else []
self.flows = defaultdict(list)
self.max_loops = max_loops
if verbose is True:
logger.add("agent_rearrange.log")
def add_agent(self, agent: Agent):
"""
Adds an agent to the swarm.
Args:
agent (Agent): The agent to be added.
"""
logger.info(f"Adding agent {agent.name} to the swarm.")
self.agents[agent.name] = agent
def remove_agent(self, agent_name: str):
"""
Removes an agent from the swarm.
Args:
agent_name (str): The name of the agent to be removed.
"""
del self.agents[agent_name]
def parse_pattern(self, pattern: str):
def add_agents(self, agents: List[Agent]):
"""
Parse the interaction pattern and setup task flows.
Adds multiple agents to the swarm.
Args:
pattern (str): The interaction pattern to parse.
agents (List[Agent]): A list of Agent objects.
"""
for agent in agents:
self.agents[agent.name] = agent
def validate_flow(self):
"""
Validates the flow pattern.
Raises:
ValueError: If the flow pattern is incorrectly formatted or contains duplicate agent names.
Returns:
bool: True if the pattern parsing is successful, False otherwise.
"""
try:
for flow in pattern.split(","):
parts = [part.strip() for part in flow.split("->")]
if len(parts) != 2:
logging.error(
f"Invalid flow pattern: {flow}. Each flow"
" must have exactly one '->'."
bool: True if the flow pattern is valid.
"""
if "->" not in self.flow:
raise ValueError(
"Flow must include '->' to denote the direction of the task."
)
agents_in_flow = []
tasks = self.flow.split("->")
for task in tasks:
agent_names = [name.strip() for name in task.split(",")]
for agent_name in agent_names:
if agent_name not in self.agents:
raise ValueError(
f"Agent '{agent_name}' is not registered."
)
return False
source_name, destinations_str = parts
source = self.find_agent_by_name(source_name)
if source is None:
logging.error(f"Source agent {source_name} not found.")
return False
destinations_names = destinations_str.split()
for dest_name in destinations_names:
dest = self.find_agent_by_name(dest_name)
if dest is None:
logging.error(
f"Destination agent {dest_name} not" " found."
agents_in_flow.append(agent_name)
if len(set(agents_in_flow)) != len(agents_in_flow):
raise ValueError(
"Duplicate agent names in the flow are not allowed."
)
return False
self.flows[source.agent_name].append(dest.agent_name)
print("Flow is valid.")
return True
except Exception as e:
logger.error(f"Error: {e}")
raise e
def self_find_agen_by_name(self, name: str):
def run(self, task: str, *args, **kwargs):
"""
Find an agent by its name.
Runs the swarm to rearrange the tasks.
Args:
name (str): The name of the agent to find.
task: The initial task to be processed.
Returns:
Agent: The Agent object if found, None otherwise.
str: The final processed task.
"""
for agent in self.agents:
if agent.agent_name == name:
return agent
return None
if not self.validate_flow():
return "Invalid flow configuration."
tasks = self.flow.split("->")
current_task = task
for task in tasks:
agent_names = [name.strip() for name in task.split(",")]
if len(agent_names) > 1:
# Parallel processing
logger.info(f"Running agents in parallel: {agent_names}")
results = []
for agent_name in agent_names:
agent = self.agents[agent_name]
result = agent.run(current_task, *args, **kwargs)
results.append(result)
current_task = "; ".join(results)
else:
# Sequential processing
logger.info(f"Running agents sequentially: {agent_names}")
agent = self.agents[agent_names[0]]
current_task = agent.run(current_task, *args, **kwargs)
def __call__(
self,
agents: Sequence[Agent] = None,
pattern: str = None,
task: str = None,
**tasks,
return current_task
def rearrange(
agents: List[Agent], flow: str, task: str = None, *args, **kwargs
):
"""
Execute the task based on the specified pattern.
Rearranges the given list of agents based on the specified flow.
Args:
agents (Sequence[Agent], optional): A sequence of Agent objects. Defaults to None.
pattern (str, optional): The interaction pattern to follow. Defaults to None.
task (str, optional): The task to execute. Defaults to None.
**tasks: Additional tasks specified as keyword arguments.
"""
try:
if agents:
self.flows.clear() # Reset previous flows
if not self.parse_pattern(pattern):
return # Pattern parsing failed
for source, destinations in self.flows.items():
for dest in destinations:
dest_agent = self.self_find_agen_by_name(dest)
task = tasks.get(dest, task)
if self.custom_prompt:
dest_agent.run(f"{task} {self.custom_prompt}")
else:
dest_agent.run(f"{task} (from {source})")
# else:
# raise ValueError(
# "No agents provided. Please provide agents to"
# " execute the task."
# )
except Exception as e:
logger.error(
f"Error: {e} try again by providing agents and" " pattern"
Parameters:
agents (List[Agent]): The list of agents to be rearranged.
flow (str): The flow used for rearranging the agents.
task (str, optional): The task to be performed during rearrangement. Defaults to None.
*args: Additional positional arguments.
**kwargs: Additional keyword arguments.
Returns:
The result of running the agent system with the specified task.
Example:
agents = [agent1, agent2, agent3]
flow = "agent1 -> agent2, agent3"
task = "Perform a task"
rearrange(agents, flow, task)
"""
agent_system = AgentRearrange(
agents=agents, flow=flow, *args, **kwargs
)
raise e
return agent_system.run(task, *args, **kwargs)
# # Initialize the director agent
# director = Agent(
# agent_name="Director",
# system_prompt="Directs the tasks for the workers",
# llm=Anthropic(),
# max_loops=1,
# dashboard=False,
# streaming_on=True,
# verbose=True,
# stopping_token="<DONE>",
# state_save_file_type="json",
# saved_state_path="director.json",
# )
# # Initialize worker 1
# worker1 = Agent(
# agent_name="Worker1",
# system_prompt="Generates a transcript for a youtube video on what swarms are",
# llm=Anthropic(),
# max_loops=1,
# dashboard=False,
# streaming_on=True,
# verbose=True,
# stopping_token="<DONE>",
# state_save_file_type="json",
# saved_state_path="worker1.json",
# )
# # Initialize worker 2
# worker2 = Agent(
# agent_name="Worker2",
# system_prompt="Summarizes the transcript generated by Worker1",
# llm=Anthropic(),
# max_loops=1,
# dashboard=False,
# streaming_on=True,
# verbose=True,
# stopping_token="<DONE>",
# state_save_file_type="json",
# saved_state_path="worker2.json",
# )
# # Example usage
# try:
# agents = [
# Agent(agent_name=f"b{i}") for i in range(1, 4)
# ] # Creating agents b1, b2, b3
# agents.append(Agent(agent_name="d")) # Adding agent d
# rearranger = Rearrange(agents)
# # Specifying a complex pattern for task execution
# rearranger.execute("d -> b1 b2 b3, b2 -> b3", "Analyze data")
# except ValueError as e:
# logging.error(e)
# flow = "Director -> Worker1 -> Worker2"
# agent_system = AgentRearrange(
# agents=[director, worker1, worker2], flow=flow
# )
# # Run the system
# output = agent_system.run(
# "Create a format to express and communicate swarms of llms in a structured manner for youtube"
# )

@ -1,107 +1,91 @@
from dataclasses import dataclass, field
from typing import List, Optional
from swarms.structs.agent import Agent
from swarms.structs.conversation import Conversation
import time
import json
from swarms.utils.loguru_logger import logger
from swarms.utils.try_except_wrapper import try_except_wrapper
from swarms.structs.base_workflow import BaseWorkflow
from pydantic import BaseModel, Field
from typing import List, Dict
from swarms.structs.agent import Agent
@dataclass
class SequentialWorkflow(BaseWorkflow):
name: str = "Sequential Workflow"
description: str = None
objective: str = None
max_loops: int = 1
autosave: bool = False
saved_state_filepath: Optional[str] = "sequential_workflow_state.json"
restore_state_filepath: Optional[str] = None
dashboard: bool = False
agent_pool: List[Agent] = field(default_factory=list)
# task_pool: List[str] = field(
# default_factory=list
# ) # List to store tasks
def __post_init__(self):
super().__init__()
self.conversation = Conversation(
time_enabled=True,
autosave=True,
class StepSequentialWorkflow(BaseModel):
agent_names: List[str] = Field(
..., description="List of agent names to include in the workflow."
)
# If objective exists then set it
if self.objective is not None:
self.conversation.system_prompt = self.objective
def workflow_bootup(self):
logger.info(f"{self.name} is activating...")
for agent in self.agent_pool:
logger.info(f"Agent {agent.agent_name} Activated")
@try_except_wrapper
def add(self, task: str, agent: Agent, *args, **kwargs):
self.agent_pool.append(agent)
# self.task_pool.append(
# task
# ) # Store tasks corresponding to each agent
return self.conversation.add(
role=agent.agent_name, content=task, *args, **kwargs
max_loops: int = Field(
1, description="Maximum number of loops to run the workflow."
)
def reset_workflow(self) -> None:
self.conversation = {}
@try_except_wrapper
def run(self):
if not self.agent_pool:
raise ValueError("No agents have been added to the workflow.")
self.workflow_bootup()
loops = 0
while loops < self.max_loops:
previous_output = None # Initialize to None; will hold the output of the previous agent
for i, agent in enumerate(self.agent_pool):
# Fetch the last task specific to this agent from the conversation history
tasks_for_agent = [
msg["content"]
for msg in self.conversation.conversation_history
if msg["role"] == agent.agent_name
]
task = tasks_for_agent[-1] if tasks_for_agent else None
if task is None and previous_output is not None:
# If no specific task for this agent, use the output from the previous agent
task = previous_output
if task is None:
# If no initial task is found, and there's no previous output, log error and skip this agent
logger.error(
f"No initial task found for agent {agent.agent_name}, and no previous output to use."
verbose: bool = Field(
False, description="Whether to log debug information."
)
continue
logger.info(
f" \n Agent {i+1} ({agent.agent_name}) is executing the task: {task} \n"
steps: Dict = Field(
...,
description="Dictionary of steps for the workflow with each agent and its parameters.",
)
time: str = Field(
time.strftime("%Y-%m-%d %H:%M:%S"),
description="Time of the workflow.",
)
# Space the log
output = agent.run(task)
if output is None:
logger.error(
f"Agent {agent.agent_name} returned None for task: {task}"
)
raise ValueError(
f"Agent {agent.agent_name} returned None."
# Define a class to handle the sequential workflow
class SequentialWorkflow(BaseWorkflow):
def __init__(
self,
agents: List[Agent] = None,
max_loops: int = 2,
verbose: bool = False,
*args,
**kwargs,
):
"""
Initializes a SequentialWorkflow with a list of agents.
:param agents: List of agents to include in the workflow.
"""
self.agents = agents
self.max_loops = max_loops
if verbose:
logger.add("sequential_workflow.log", level="DEBUG")
if not self.agents:
raise ValueError("No agents provided for workflow")
if not self.max_loops:
self.max_loops = 1
# Log all the agents in the workflow
logger.info(
f"Initialized SequentialWorkflow with agents: {json.dumps([str(agent.agent_name) for agent in self.agents])}"
)
# Update the conversation history with the new output using agent's role
self.conversation.add(
role=agent.agent_name, content=output
def run(self, task: str, *args, **kwargs):
"""
Run the workflow starting with an initial task.
:param task: The task to start the workflow.
"""
logger.info(f"Starting workflow with task: {task}")
current_output = task
for agent in self.agents:
count = 0
while count < self.max_loops:
try:
logger.info(f"Running agent {agent.agent_name}")
current_output = agent.run(
current_output, *args, **kwargs
)
previous_output = output # Update the previous_output to pass to the next agent
loops += 1
return self.conversation.return_history_as_string()
print(current_output)
count += 1
logger.debug(
f"Agent {agent.agent_name} completed loop {count} "
) # Log partial output for brevity
except Exception as e:
logger.error(
f"Error occurred while running agent {agent.agent_name}: {str(e)}"
)
raise
logger.info(f"Finished running agent {agent.agent_name}")
logger.info("Finished running workflow")
return current_output

@ -1,6 +1,6 @@
from typing import Dict, List, Sequence
from swarms.tools.tool import BaseTool
from swarms.tools.base_tool import BaseTool
from pydantic import BaseModel

@ -1,106 +0,0 @@
import json
from typing import List, Optional
from pydantic import model_validator, BaseModel, Field, Json
from swarms.structs.agent import Agent
from swarms.structs.task import Task
class Team(BaseModel):
"""
Class that represents a group of agents, how they should work together and
their tasks.
Attributes:
tasks (Optional[List[Task]]): List of tasks.
agents (Optional[List[Agent]]): List of agents in this Team.
architecture (str): Architecture that the Team will follow. Default is "sequential".
verbose (bool): Verbose mode for the Agent Execution. Default is False.
config (Optional[Json]): Configuration of the Team. Default is None.
"""
tasks: Optional[List[Task]] = Field(None, description="List of tasks")
agents: Optional[List[Agent]] = Field(
None, description="List of agents in this Team."
)
architecture = Field(
description="architecture that the Team will follow.",
default="sequential",
)
verbose: bool = Field(
description="Verbose mode for the Agent Execution",
default=False,
)
config: Optional[Json] = Field(
description="Configuration of the Team.", default=None
)
@model_validator(mode="before")
@classmethod
def check_config(_cls, values):
if not values.get("config") and (
not values.get("agents") and not values.get("tasks")
):
raise ValueError(
"Either agents and task need to be set or config."
)
if values.get("config"):
config = json.loads(values.get("config"))
if not config.get("agents") or not config.get("tasks"):
raise ValueError("Config should have agents and tasks.")
values["agents"] = [
Agent(**agent) for agent in config["agents"]
]
tasks = []
for task in config["tasks"]:
task_agent = [
agt
for agt in values["agents"]
if agt.role == task["agent"]
][0]
del task["agent"]
tasks.append(Task(**task, agent=task_agent))
values["tasks"] = tasks
return values
def run(self) -> str:
"""
Kickoff the Team to work on its tasks.
Returns:
output (List[str]): Output of the Team for each task.
"""
if self.architecture == "sequential":
return self.__sequential_loop()
def __sequential_loop(self) -> str:
"""
Loop that executes the sequential architecture.
Returns:
output (str): Output of the Team.
"""
task_outcome = None
for task in self.tasks:
# Add delegation tools to the task if the agent allows it
# if task.agent.allow_delegation:
# tools = AgentTools(agents=self.agents).tools()
# task.tools += tools
self.__log(f"\nWorking Agent: {task.agent.role}")
self.__log(f"Starting Task: {task.description} ...")
task_outcome = task.execute(task_outcome)
self.__log(f"Task output: {task_outcome}")
return task_outcome
def __log(self, message):
if self.verbose:
print(message)

@ -1,4 +1,3 @@
from swarms.tools.tool import BaseTool, Tool, StructuredTool, tool
from swarms.tools.exec_tool import (
AgentAction,
AgentOutputParser,
@ -32,14 +31,10 @@ from swarms.tools.py_func_to_openai_func_str import (
Function,
ToolFunction,
)
from swarms.tools.openai_tool_creator_decorator import create_openai_tool
from swarms.tools.openai_tool_creator_decorator import tool
from swarms.tools.base_tool import BaseTool
__all__ = [
"BaseTool",
"Tool",
"StructuredTool",
"tool",
"AgentAction",
"AgentOutputParser",
"BaseAgentOutputParser",
@ -63,5 +58,6 @@ __all__ = [
"get_required_params",
"Function",
"ToolFunction",
"create_openai_tool",
"tool",
"BaseTool",
]

@ -0,0 +1,379 @@
import json
from pydantic import BaseModel
from swarms.utils.loguru_logger import logger
from swarms.tools.py_func_to_openai_func_str import (
get_openai_function_schema_from_func,
load_basemodels_if_needed,
)
from swarms.tools.openai_tool_creator_decorator import openai_tool_executor
from typing import Callable, Optional, Any, Dict, List
from swarms.tools.pydantic_to_json import (
base_model_to_openai_function,
multi_base_model_to_openai_function,
function_to_str,
functions_to_str,
)
from swarms.tools.function_util import process_tool_docs
from typing import Union
ToolType = Union[BaseModel, Dict[str, Any], Callable[..., Any]]
class BaseTool(BaseModel):
"""
Base class for tools in the swarms package.
Attributes:
verbose (bool): Flag indicating whether to enable verbose mode.
functions (List[Callable[..., Any]]): List of functions associated with the tool.
base_models (List[type[BaseModel]]): List of base models associated with the tool.
Methods:
func_to_dict(function: Callable[..., Any], name: Optional[str] = None, description: str) -> Dict[str, Any]:
Converts a function to a dictionary representation.
load_params_from_func_for_pybasemodel(func: Callable[..., Any], *args: Any, **kwargs: Any) -> Callable[..., Any]:
Loads parameters from a function for a Pydantic BaseModel.
base_model_to_dict(pydantic_type: type[BaseModel], output_str: bool = False, *args: Any, **kwargs: Any) -> dict[str, Any]:
Converts a Pydantic BaseModel to a dictionary representation.
multi_base_models_to_dict(pydantic_types: List[type[BaseModel]], *args: Any, **kwargs: Any) -> dict[str, Any]:
Converts multiple Pydantic BaseModels to a dictionary representation.
dict_to_str(dict: dict[str, Any]) -> str:
Converts a dictionary to a string representation.
multi_dict_to_str(dicts: list[dict[str, Any]]) -> str:
Converts multiple dictionaries to a string representation.
get_docs_from_callable(item) -> Any:
Retrieves documentation from a callable item.
"""
verbose: bool = False
functions: List[Callable[..., Any]] = []
base_models: List[type[BaseModel]] = []
verbose: bool = False
autocheck: bool = False
auto_execute_tool: Optional[bool] = False
def func_to_dict(
function: Callable[..., Any],
*,
name: Optional[str] = None,
description: str,
) -> Dict[str, Any]:
try:
return get_openai_function_schema_from_func(
function=function,
name=name,
description=description,
)
except Exception as e:
logger.error(f"An error occurred in func_to_dict: {e}")
logger.error(
"Please check the function and ensure it is valid."
)
logger.error(
"If the issue persists, please seek further assistance."
)
raise
def load_params_from_func_for_pybasemodel(
func: Callable[..., Any],
*args: Any,
**kwargs: Any,
) -> Callable[..., Any]:
try:
return load_basemodels_if_needed(func, *args, **kwargs)
except Exception as e:
logger.error(
f"An error occurred in load_params_from_func_for_pybasemodel: {e}"
)
logger.error(
"Please check the function and ensure it is valid."
)
logger.error(
"If the issue persists, please seek further assistance."
)
raise
def base_model_to_dict(
pydantic_type: type[BaseModel],
output_str: bool = False,
*args: Any,
**kwargs: Any,
) -> dict[str, Any]:
try:
return base_model_to_openai_function(
pydantic_type, output_str, *args, **kwargs
)
except Exception as e:
logger.error(f"An error occurred in base_model_to_dict: {e}")
logger.error(
"Please check the Pydantic type and ensure it is valid."
)
logger.error(
"If the issue persists, please seek further assistance."
)
raise
def multi_base_models_to_dict(
pydantic_types: List[type[BaseModel]],
*args: Any,
**kwargs: Any,
) -> dict[str, Any]:
try:
return multi_base_model_to_openai_function(
pydantic_types, *args, **kwargs
)
except Exception as e:
logger.error(
f"An error occurred in multi_base_models_to_dict: {e}"
)
logger.error(
"Please check the Pydantic types and ensure they are valid."
)
logger.error(
"If the issue persists, please seek further assistance."
)
raise
def dict_to_str(
dict: dict[str, Any],
) -> str:
try:
return function_to_str(dict)
except Exception as e:
logger.error(f"An error occurred in dict_to_str: {e}")
logger.error(
"Please check the dictionary and ensure it is valid."
)
logger.error(
"If the issue persists, please seek further assistance."
)
raise
def multi_dict_to_str(
dicts: list[dict[str, Any]],
) -> str:
try:
return functions_to_str(dicts)
except Exception as e:
logger.error(f"An error occurred in multi_dict_to_str: {e}")
logger.error(
"Please check the dictionaries and ensure they are valid."
)
logger.error(
"If the issue persists, please seek further assistance."
)
raise
def get_docs_from_callable(item):
try:
return process_tool_docs(item)
except Exception as e:
logger.error(f"An error occurred in get_docs: {e}")
logger.error("Please check the item and ensure it is valid.")
logger.error(
"If the issue persists, please seek further assistance."
)
raise
def execute_tool(
self,
tools: List[Dict[str, Any]],
function_map: Dict[str, Callable],
*args: Any,
**kwargs: Any,
) -> Callable:
try:
return openai_tool_executor(
tools, function_map, self.verbose, *args, **kwargs
)
except Exception as e:
logger.error(f"An error occurred in execute_tool: {e}")
logger.error(
"Please check the tools and function map and ensure they are valid."
)
logger.error(
"If the issue persists, please seek further assistance."
)
raise
def detect_tool_input_type(input):
if isinstance(input, BaseModel):
return "Pydantic"
elif isinstance(input, dict):
return "Dictionary"
elif callable(input):
return "Function"
else:
return "Unknown"
def dynamic_run(self, input) -> str:
"""
Executes the dynamic run based on the input type.
Args:
input: The input to be processed.
Returns:
str: The result of the dynamic run.
Raises:
None
"""
tool_input_type = self.detect_tool_input_type(input)
if tool_input_type == "Pydantic":
function_str = base_model_to_openai_function(input)
elif tool_input_type == "Dictionary":
function_str = function_to_str(input)
elif tool_input_type == "Function":
function_str = get_openai_function_schema_from_func(input)
else:
return "Unknown tool input type"
if self.auto_execute_tool:
if tool_input_type == "Function":
# Add the function to the functions list
self.functions.append(input)
# Create a function map from the functions list
function_map = {func.__name__: func for func in self.functions}
# Execute the tool
return self.execute_tool(
tools=[function_str], function_map=function_map
)
else:
return function_str
def execute_tool_by_name(
tools: List[Dict[str, Any]],
tool_name: str,
function_map: Dict[str, Callable],
) -> Any:
"""
Search for a tool by name and execute it.
Args:
tools (List[Dict[str, Any]]): A list of tools. Each tool is a dictionary that includes a 'name' key.
tool_name (str): The name of the tool to execute.
function_map (Dict[str, Callable]): A dictionary that maps tool names to functions.
Returns:
The result of executing the tool.
Raises:
ValueError: If the tool with the specified name is not found.
TypeError: If the tool name is not mapped to a function in the function map.
"""
# Search for the tool by name
tool = next(
(tool for tool in tools if tool.get("name") == tool_name), None
)
# If the tool is not found, raise an error
if tool is None:
raise ValueError(f"Tool '{tool_name}' not found")
# Get the function associated with the tool
func = function_map.get(tool_name)
# If the function is not found, raise an error
if func is None:
raise TypeError(
f"Tool '{tool_name}' is not mapped to a function"
)
# Execute the tool
return func(**tool.get("parameters", {}))
def execute_tool_from_text(
text: str = None, function_map: Dict[str, Callable] = None
) -> Any:
"""
Convert a JSON-formatted string into a tool dictionary and execute the tool.
Args:
text (str): A JSON-formatted string that represents a tool. The string should be convertible into a dictionary that includes a 'name' key and a 'parameters' key.
function_map (Dict[str, Callable]): A dictionary that maps tool names to functions.
Returns:
The result of executing the tool.
Raises:
ValueError: If the tool with the specified name is not found.
TypeError: If the tool name is not mapped to a function in the function map.
"""
# Convert the text into a dictionary
tool = json.loads(text)
# Get the tool name and parameters from the dictionary
tool_name = tool.get("name")
tool_params = tool.get("parameters", {})
# Get the function associated with the tool
func = function_map.get(tool_name)
# If the function is not found, raise an error
if func is None:
raise TypeError(
f"Tool '{tool_name}' is not mapped to a function"
)
# Execute the tool
return func(**tool_params)
# # Example function definitions and mappings
# def get_current_weather(location, unit='celsius'):
# return f"Weather in {location} is likely sunny and 75° {unit.title()}"
# def add(a, b):
# return a + b
# # Example tool configurations
# tools = [
# {
# "type": "function",
# "function": {
# "name": "get_current_weather",
# "parameters": {
# "properties": {
# "location": "San Francisco, CA",
# "unit": "fahrenheit",
# },
# },
# },
# },
# {
# "type": "function",
# "function": {
# "name": "add",
# "parameters": {
# "properties": {
# "a": 1,
# "b": 2,
# },
# },
# },
# }
# ]
# function_map = {
# "get_current_weather": get_current_weather,
# "add": add,
# }
# # Creating and executing the advanced executor
# tool_executor = BaseTool(verbose=True).execute_tool(tools, function_map)
# try:
# results = tool_executor()
# print(results) # Outputs results from both functions
# except Exception as e:
# print(f"Error: {e}")

@ -7,7 +7,7 @@ from typing import Dict, List, NamedTuple
from langchain.schema import BaseOutputParser
from pydantic import ValidationError
from swarms.tools.tool import BaseTool
from swarms.tools.base_tool import BaseTool
from swarms.utils.loguru_logger import logger

@ -1,12 +1,13 @@
from functools import wraps
import concurrent.futures
from typing import Callable, Any, Dict, List
from swarms.tools.py_func_to_openai_func_str import (
get_openai_function_schema_from_func,
)
from swarms.utils.loguru_logger import logger
def create_openai_tool(
def tool(
name: str = None,
description: str = None,
return_dict: bool = True,
@ -79,3 +80,314 @@ def create_openai_tool(
return wrapper
return decorator
def openai_tool_executor(
tools: List[Dict[str, Any]],
function_map: Dict[str, Callable],
verbose: bool = True,
*args,
**kwargs,
) -> Callable:
"""
Creates a function that dynamically and concurrently executes multiple functions based on parameters specified
in a list of tool dictionaries, with extensive error handling and validation.
Args:
tools (List[Dict[str, Any]]): A list of dictionaries, each containing configuration for a tool, including parameters.
function_map (Dict[str, Callable]): A dictionary mapping function names to their corresponding callable functions.
Returns:
Callable: A function that, when called, executes the specified functions concurrently with the parameters given.
Examples:
>>> from swarms.tools.openai_tool_creator_decorator import openai_tool_executor
>>> from swarms.tools.py_func_to_openai_func_str import get_openai_function_schema_from_func
>>> from swarms.utils.loguru_logger import logger
>>>
>>> def test_function(param1: int, param2: str) -> str:
... return f"Test function called with parameters: {param1}, {param2}"
...
>>> @openai_tool_executor(
... tools=[
... {
... "type": "function",
... "function": {
... "name": "test_function",
... "parameters": {
... "properties": {
... "param1": {
... "type": "int",
... "description": "An integer parameter."
... },
... "param2": {
... "type": "str",
... "description": "A string parameter."
... },
... }
... }
... }
... }
... ],
... function_map={
... "test_function": test_function
... }
... )
... def tool_executor():
... pass
...
>>> results = tool_executor()
>>> logger.info(results)
"""
def tool_executor():
# Prepare tasks for concurrent execution
results = []
logger.info(f"Executing {len(tools)} tools concurrently.")
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = []
for tool in tools:
if tool.get("type") != "function":
continue # Skip non-function tool entries
function_info = tool.get("function", {})
func_name = function_info.get("name")
logger.info(f"Executing function: {func_name}")
# Check if the function name is mapped to an actual function
if func_name not in function_map:
raise KeyError(
f"Function '{func_name}' not found in function map."
)
# Validate parameters
params = function_info.get("parameters", {}).get(
"properties", {}
)
if not params:
raise ValueError(
f"No parameters specified for function '{func_name}'."
)
# Submit the function for execution
try:
future = executor.submit(
function_map[func_name], **params
)
futures.append(future)
except Exception as e:
print(
f"Failed to submit the function '{func_name}' for execution: {e}"
)
# Gather results from all futures
for future in futures:
try:
result = future.result() # Collect result from future
results.append(result)
except Exception as e:
print(f"Error during execution of a function: {e}")
logger.info(f"Results: {results}")
return results
return tool_executor
# def openai_tool_executor(
# tools: List[Dict[str, Any]],
# function_map: Dict[str, Callable],
# verbose: bool = True,
# concurrent_execution: bool = True,
# retry_on_error: bool = False,
# retry_attempts: int = 3,
# max_loops: int = 1,
# max_workers: int = 10,
# *args,
# **kwargs,
# ) -> Callable:
# """
# Creates a function that dynamically and concurrently executes multiple functions based on parameters specified
# in a list of tool dictionaries, with extensive error handling and validation.
# Args:
# tools (List[Dict[str, Any]]): A list of dictionaries, each containing configuration for a tool, including parameters.
# function_map (Dict[str, Callable]): A dictionary mapping function names to their corresponding callable functions.
# Returns:
# Callable: A function that, when called, executes the specified functions concurrently with the parameters given.
# Examples:
# >>> from swarms.tools.openai_tool_creator_decorator import openai_tool_executor
# >>> from swarms.tools.py_func_to_openai_func_str import get_openai_function_schema_from_func
# >>> from swarms.utils.loguru_logger import logger
# >>>
# >>> def test_function(param1: int, param2: str) -> str:
# ... return f"Test function called with parameters: {param1}, {param2}"
# ...
# >>> @openai_tool_executor(
# ... tools=[
# ... {
# ... "type": "function",
# ... "function": {
# ... "name": "test_function",
# ... "parameters": {
# ... "properties": {
# ... "param1": {
# ... "type": "int",
# ... "description": "An integer parameter."
# ... },
# ... "param2": {
# ... "type": "str",
# ... "description": "A string parameter."
# ... },
# ... }
# ... }
# ... }
# ... }
# ... ],
# ... function_map={
# ... "test_function": test_function
# ... }
# ... )
# ... def tool_executor():
# ... pass
# ...
# >>> results = tool_executor()
# >>> logger.info(results)
# """
# def tool_executor():
# logger.info(
# f"Starting execution of tools with {max_loops} loops and concurrency set to {concurrent_execution}."
# )
# results = []
# def execute_function(func_name, params):
# try:
# logger.debug(
# f"Executing function: {func_name} with params: {params}"
# )
# return function_map[func_name](**params)
# except Exception as e:
# logger.error(
# f"Error executing function {func_name}: {str(e)}"
# )
# if retry_on_error:
# for attempt in range(retry_attempts):
# try:
# logger.debug(
# f"Retrying function: {func_name}, attempt {attempt+1}"
# )
# return function_map[func_name](**params)
# except Exception as e:
# logger.error(
# f"Retry {attempt+1} for function {func_name} failed: {str(e)}"
# )
# raise
# else:
# raise
# for loop in range(max_loops):
# logger.info(f"Executing loop {loop + 1}/{max_loops}")
# with concurrent.futures.ThreadPoolExecutor(
# max_workers=max_workers
# ) as executor:
# future_to_function = {
# executor.submit(
# execute_function,
# tool["function"]["name"],
# tool["function"]["parameters"]["properties"],
# ): tool
# for tool in tools
# if tool.get("type") == "function"
# }
# for future in concurrent.futures.as_completed(
# future_to_function
# ):
# try:
# result = future.result()
# results.append(result)
# logger.debug(
# f"Function completed with result: {result}"
# )
# except Exception as e:
# logger.error(
# f"Execution failed with error: {str(e)}"
# )
# continue
# logger.info(f"All loops completed. Results: {results}")
# return results
# return tool_executor
# # Example
# @tool(
# name="test_function",
# description="A test function that takes two parameters and returns a string.",
# )
# def test_function(param1: int, param2: str) -> str:
# return f"Test function called with parameters: {param1}, {param2}"
# @tool(
# name="test_function2",
# description="A test function that takes two parameters and returns a string.",
# )
# def test_function2(param1: int, param2: str) -> str:
# return f"Test function 2 called with parameters: {param1}, {param2}"
# # Example execution
# out = openai_tool_executor(
# tools=[
# {
# "type": "function",
# "function": {
# "name": "test_function",
# "parameters": {
# "properties": {
# "param1": {
# "type": "int",
# "description": "An integer parameter.",
# },
# "param2": {
# "type": "str",
# "description": "A string parameter.",
# },
# }
# },
# },
# },
# {
# "type": "function",
# "function": {
# "name": "test_function2",
# "parameters": {
# "properties": {
# "param1": {
# "type": "int",
# "description": "An integer parameter.",
# },
# "param2": {
# "type": "str",
# "description": "A string parameter.",
# },
# }
# },
# },
# },
# ],
# function_map={"test_function": test_function, "test_function2": test_function2},
# )
# print(out)

@ -51,7 +51,7 @@ def base_model_to_openai_function(
schema["description"] = docstring.short_description
else:
schema["description"] = (
f"Correctly extracted `{pydantic_type.__class__.__name__.lower()}` with all "
f"Correctly extracted `{pydantic_type.__name__}` with all "
f"the required parameters with correct types"
)
@ -61,11 +61,11 @@ def base_model_to_openai_function(
if output_str:
out = {
"function_call": {
"name": pydantic_type.__class__.__name__.lower(),
"name": pydantic_type.__name__,
},
"functions": [
{
"name": pydantic_type.__class__.__name__.lower(),
"name": pydantic_type.__name__,
"description": schema["description"],
"parameters": parameters,
},
@ -76,11 +76,11 @@ def base_model_to_openai_function(
else:
return {
"function_call": {
"name": pydantic_type.__class__.__name__.lower(),
"name": pydantic_type.__name__,
},
"functions": [
{
"name": pydantic_type.__class__.__name__.lower(),
"name": pydantic_type.__name__,
"description": schema["description"],
"parameters": parameters,
},

@ -3,7 +3,7 @@ import re
from typing import Any, List
from swarms.prompts.tools import SCENARIOS
from swarms.tools.tool import BaseTool
from swarms.tools.base_tool import BaseTool
import inspect
from typing import Callable

@ -0,0 +1,58 @@
import pytest
from agent_rearrange import AgentRearrange
# Mocking the Agent class
class MockAgent:
def __init__(self, agent_name):
self.agent_name = agent_name
def run(self, task):
return f"Running {task}"
# Test for AgentRearrange class
class TestAgentRearrange:
@pytest.fixture
def agent_rearrange(self):
agents = [MockAgent("agent1"), MockAgent("agent2")]
return AgentRearrange(agents=agents)
def test_parse_pattern(self, agent_rearrange):
assert agent_rearrange.parse_pattern("agent1->agent2") is True
assert agent_rearrange.parse_pattern("agent3->agent4") is False
def test_self_find_agent_by_name(self, agent_rearrange):
assert (
agent_rearrange.self_find_agent_by_name("agent1").agent_name
== "agent1"
)
assert agent_rearrange.self_find_agent_by_name("agent3") is None
def test_agent_exists(self, agent_rearrange):
assert agent_rearrange.agent_exists("agent1") is True
assert agent_rearrange.agent_exists("agent3") is False
def test_parse_concurrent_flow(self, agent_rearrange):
agent_rearrange.parse_concurrent_flow("agent1->agent2")
assert "agent2" in agent_rearrange.flows["agent1"]
def test_parse_sequential_flow(self, agent_rearrange):
agent_rearrange.parse_sequential_flow("agent1", "agent2")
assert "agent2" in agent_rearrange.flows["agent1"]
def test_execute_task(self, agent_rearrange):
assert (
agent_rearrange.execute_task("agent1", "agent2", "task1", {})
== "Running task1 (from agent2)"
)
def test_process_flows(self, agent_rearrange):
assert agent_rearrange.process_flows(
"agent1->agent2", "task1", {}
) == ["Running task1"]
def test_call(self, agent_rearrange):
assert agent_rearrange(
pattern="agent1->agent2", default_task="task1"
) == ["Running task1"]
Loading…
Cancel
Save