parent
36a092f6e6
commit
b4f923f1fb
@ -1,22 +0,0 @@
|
||||
mkdocs
|
||||
mkdocs-material
|
||||
mkdocs-glightbox
|
||||
mkdocs-git-authors-plugin
|
||||
mkdocs-git-revision-date-plugin
|
||||
mkdocs-git-committers-plugin
|
||||
mkdocstrings
|
||||
mike
|
||||
mkdocs-jupyter
|
||||
mkdocs-git-committers-plugin-2
|
||||
mkdocs-git-revision-date-localized-plugin
|
||||
mkdocs-redirects
|
||||
mkdocs-material-extensions
|
||||
mkdocs-simple-hooks
|
||||
mkdocs-awesome-pages-plugin
|
||||
mkdocs-versioning
|
||||
mkdocs-mermaid2-plugin
|
||||
mkdocs-include-markdown-plugin
|
||||
mkdocs-enumerate-headings-plugin
|
||||
mkdocs-autolinks-plugin
|
||||
mkdocs-minify-html-plugin
|
||||
mkdocs-autolinks-plugin
|
@ -0,0 +1,77 @@
|
||||
"""
|
||||
|
||||
|
||||
tool decorated func [search_api] -> agent which parses the docs of the tool func
|
||||
-> injected into prompt -> agent will output json containing tool usage -> agent output will be parsed -> tool executed
|
||||
-> terminal response can be returned to agent for self-healing
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Import the OpenAIChat model and the Agent struct
|
||||
from swarms import Agent, llama3Hosted
|
||||
|
||||
# Load the environment variables
|
||||
load_dotenv()
|
||||
|
||||
|
||||
# Define a tool
|
||||
def search_api(query: str, description: str):
|
||||
"""Search the web for the query
|
||||
|
||||
Args:
|
||||
query (str): _description_
|
||||
|
||||
Returns:
|
||||
_type_: _description_
|
||||
"""
|
||||
return f"Search results for {query}"
|
||||
|
||||
|
||||
def weather_api(
|
||||
query: str,
|
||||
):
|
||||
"""_summary_
|
||||
|
||||
Args:
|
||||
query (str): _description_
|
||||
"""
|
||||
print(f"Getting the weather for {query}")
|
||||
|
||||
|
||||
def rapid_api(query: str):
|
||||
"""_summary_
|
||||
|
||||
Args:
|
||||
query (str): _description_
|
||||
"""
|
||||
print(f"Getting the weather for {query}")
|
||||
|
||||
|
||||
# Get the API key from the environment
|
||||
api_key = os.environ.get("OPENAI_API_KEY")
|
||||
|
||||
# Initialize the language model
|
||||
llm = llama3Hosted(
|
||||
temperature=0.5,
|
||||
)
|
||||
|
||||
|
||||
## Initialize the workflow
|
||||
agent = Agent(
|
||||
agent_name="Research Agent",
|
||||
llm=llm,
|
||||
max_loops=3,
|
||||
dashboard=True,
|
||||
tools=[search_api, weather_api, rapid_api],
|
||||
interactive=True,
|
||||
execute_tool=True,
|
||||
)
|
||||
|
||||
# Run the workflow on a task
|
||||
out = agent.run("Use the weather tool in Miami")
|
||||
print(out)
|
@ -1,39 +0,0 @@
|
||||
import json
|
||||
import requests
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
def fetch_weather_data(city: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Fetch near real-time weather data for a city using wttr.in.
|
||||
|
||||
Args:
|
||||
city (str): The name of the city (e.g., "Austin, Tx").
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: Weather data for the specified city.
|
||||
|
||||
Raises:
|
||||
Exception: If the request fails or the response is invalid.
|
||||
"""
|
||||
url = f"http://wttr.in/{city}"
|
||||
params = {"format": "j1"} # JSON format
|
||||
try:
|
||||
response = requests.get(url, params=params)
|
||||
response.raise_for_status()
|
||||
response = json.dumps(response.json(), indent=2)
|
||||
return response
|
||||
except requests.RequestException as e:
|
||||
raise Exception(f"Failed to fetch weather data: {e}")
|
||||
except ValueError:
|
||||
raise Exception("Invalid response format.")
|
||||
|
||||
|
||||
# # Example usage
|
||||
# city = "Huntsville, AL"
|
||||
|
||||
# try:
|
||||
# weather_data = fetch_weather_data(city)
|
||||
# print("Weather Data:", weather_data)
|
||||
# except Exception as e:
|
||||
# print(e)
|
@ -0,0 +1,117 @@
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from playground.demos.plant_biologist_swarm.prompts import (
|
||||
diagnoser_agent,
|
||||
disease_detector_agent,
|
||||
growth_predictor_agent,
|
||||
harvester_agent,
|
||||
treatment_recommender_agent,
|
||||
)
|
||||
|
||||
from swarms import Agent, GPT4VisionAPI
|
||||
|
||||
|
||||
# Load the OpenAI API key from the .env file
|
||||
load_dotenv()
|
||||
|
||||
# Initialize the OpenAI API key
|
||||
api_key = os.environ.get("OPENAI_API_KEY")
|
||||
|
||||
|
||||
# llm = llm,
|
||||
llm = GPT4VisionAPI(
|
||||
max_tokens=4000,
|
||||
)
|
||||
|
||||
# Initialize Diagnoser Agent
|
||||
diagnoser_agent = Agent(
|
||||
agent_name="Diagnoser Agent",
|
||||
system_prompt=diagnoser_agent(),
|
||||
llm=llm,
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
streaming_on=True,
|
||||
verbose=True,
|
||||
# saved_state_path="diagnoser.json",
|
||||
multi_modal=True,
|
||||
autosave=True,
|
||||
)
|
||||
|
||||
# Initialize Harvester Agent
|
||||
harvester_agent = Agent(
|
||||
agent_name="Harvester Agent",
|
||||
system_prompt=harvester_agent(),
|
||||
llm=llm,
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
streaming_on=True,
|
||||
verbose=True,
|
||||
# saved_state_path="harvester.json",
|
||||
multi_modal=True,
|
||||
autosave=True,
|
||||
)
|
||||
|
||||
# Initialize Growth Predictor Agent
|
||||
growth_predictor_agent = Agent(
|
||||
agent_name="Growth Predictor Agent",
|
||||
system_prompt=growth_predictor_agent(),
|
||||
llm=llm,
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
streaming_on=True,
|
||||
verbose=True,
|
||||
# saved_state_path="growth_predictor.json",
|
||||
multi_modal=True,
|
||||
autosave=True,
|
||||
)
|
||||
|
||||
# Initialize Treatment Recommender Agent
|
||||
treatment_recommender_agent = Agent(
|
||||
agent_name="Treatment Recommender Agent",
|
||||
system_prompt=treatment_recommender_agent(),
|
||||
llm=llm,
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
streaming_on=True,
|
||||
verbose=True,
|
||||
# saved_state_path="treatment_recommender.json",
|
||||
multi_modal=True,
|
||||
autosave=True,
|
||||
)
|
||||
|
||||
# Initialize Disease Detector Agent
|
||||
disease_detector_agent = Agent(
|
||||
agent_name="Disease Detector Agent",
|
||||
system_prompt=disease_detector_agent(),
|
||||
llm=llm,
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
streaming_on=True,
|
||||
verbose=True,
|
||||
# saved_state_path="disease_detector.json",
|
||||
multi_modal=True,
|
||||
autosave=True,
|
||||
)
|
||||
agents = [
|
||||
diagnoser_agent,
|
||||
disease_detector_agent,
|
||||
treatment_recommender_agent,
|
||||
growth_predictor_agent,
|
||||
harvester_agent,
|
||||
]
|
||||
|
||||
task = "Conduct a diagnosis on the patient's symptoms."
|
||||
img = "tomato.jpg"
|
||||
|
||||
loop = 0
|
||||
for i in range(len(agents)):
|
||||
if i == 0:
|
||||
output = agents[i].run(task, img)
|
||||
|
||||
else:
|
||||
output = agents[i].run(output, img)
|
||||
|
||||
# Add extensive logging for each agent
|
||||
print(f"Agent {i+1} - {agents[i].agent_name}")
|
||||
print("-----------------------------------")
|
After Width: | Height: | Size: 1.9 MiB |
@ -0,0 +1,34 @@
|
||||
from swarms import Agent, llama3Hosted
|
||||
from swarms.structs.swarm_load_balancer import AgentLoadBalancer
|
||||
|
||||
# Initialize the language model agent (e.g., GPT-3)
|
||||
llm = llama3Hosted()
|
||||
|
||||
# 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=[],
|
||||
)
|
||||
agent2 = Agent(
|
||||
agent_name="Summarizer",
|
||||
system_prompt="Sumamrize the blog post",
|
||||
llm=llm,
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
tools=[],
|
||||
)
|
||||
|
||||
# Create the Sequential workflow
|
||||
workflow = AgentLoadBalancer(
|
||||
agents=[agent1, agent2],
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Run the workflow
|
||||
workflow.run(
|
||||
"Generate a blog post on how swarms of agents can help businesses grow."
|
||||
)
|
@ -1,29 +0,0 @@
|
||||
torch>=2.1.1,<3.0
|
||||
transformers>=4.39.0,<5.0.0
|
||||
asyncio>=3.4.3,<4.0
|
||||
langchain-community==0.0.29
|
||||
langchain-experimental==0.0.55
|
||||
backoff==2.2.1
|
||||
toml
|
||||
pypdf==4.1.0
|
||||
ratelimit==2.2.1
|
||||
loguru==0.7.2
|
||||
pydantic==2.7.1
|
||||
tenacity==8.2.3
|
||||
Pillow==10.3.0
|
||||
psutil
|
||||
sentry-sdk
|
||||
python-dotenv
|
||||
opencv-python-headless
|
||||
PyYAML
|
||||
docstring_parser==0.16
|
||||
black>=23.1,<25.0
|
||||
ruff>=0.0.249,<0.4.5
|
||||
types-toml>=0.10.8.1
|
||||
types-pytz>=2023.3,<2025.0
|
||||
types-chardet>=5.0.4.6
|
||||
mypy-protobuf>=3.0.0
|
||||
pytest>=8.1.1
|
||||
termcolor>=2.4.0
|
||||
pandas>=2.2.2
|
||||
fastapi>=0.110.1
|
@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Find and delete all __pycache__ directories
|
||||
find . -type d -name "__pycache__" -exec rm -r {} +
|
||||
|
||||
# Find and delete all .pyc files
|
||||
find . -type f -name "*.pyc" -delete
|
||||
|
||||
# Find and delete all dist directories
|
||||
find . -type d -name "dist" -exec rm -r {} +
|
||||
|
||||
# Find and delete all .ruff directories
|
||||
find . -type d -name ".ruff" -exec rm -r {} +
|
||||
|
||||
# Find and delete all .egg-info directories
|
||||
find . -type d -name "*.egg-info" -exec rm -r {} +
|
||||
|
||||
# Find and delete all .pyo files
|
||||
find . -type f -name "*.pyo" -delete
|
||||
|
||||
# Find and delete all .pyd files
|
||||
find . -type f -name "*.pyd" -delete
|
||||
|
||||
# Find and delete all .so files
|
||||
find . -type f -name "*.so" -delete
|
@ -1,7 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Find and delete all __pycache__ directories
|
||||
find . -type d -name "__pycache__" -exec rm -r {} +
|
||||
|
||||
# Find and delete all .pyc files
|
||||
find . -type f -name "*.pyc" -delete
|
@ -0,0 +1,115 @@
|
||||
from swarms.utils.loguru_logger import logger
|
||||
import re
|
||||
import json
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import List
|
||||
from swarms.structs.agent import Agent
|
||||
|
||||
|
||||
class HaSAgentSchema(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",
|
||||
)
|
||||
|
||||
|
||||
class HassSchema(BaseModel):
|
||||
agents: List[HaSAgentSchema] = Field(
|
||||
...,
|
||||
title="List of agents to use for the problem",
|
||||
description="List of agents to use for the problem",
|
||||
)
|
||||
|
||||
|
||||
# import json
|
||||
def parse_json_from_input(input_str: str = None):
|
||||
"""
|
||||
Parses a JSON string from the input and returns the parsed data.
|
||||
|
||||
Args:
|
||||
input_str (str): The input string containing the JSON.
|
||||
|
||||
Returns:
|
||||
tuple: A tuple containing the parsed data. The tuple contains three elements:
|
||||
- The plan extracted from the JSON.
|
||||
- The agents extracted from the JSON.
|
||||
- The rules extracted from the JSON.
|
||||
|
||||
If the input string is None or empty, or if the JSON decoding fails, all elements of the tuple will be None.
|
||||
"""
|
||||
# Validate input is not None or empty
|
||||
if not input_str:
|
||||
logger.info("Error: Input string is None or empty.")
|
||||
return None, None, None
|
||||
|
||||
# Attempt to extract JSON from markdown using regular expression
|
||||
json_pattern = re.compile(r"```json\n(.*?)\n```", re.DOTALL)
|
||||
match = json_pattern.search(input_str)
|
||||
json_str = match.group(1).strip() if match else input_str.strip()
|
||||
|
||||
# Attempt to parse the JSON string
|
||||
try:
|
||||
data = json.loads(json_str)
|
||||
except json.JSONDecodeError as e:
|
||||
logger.info(f"Error: JSON decoding failed with message '{e}'")
|
||||
return None, None, None
|
||||
|
||||
hass_schema = HassSchema(**data)
|
||||
return (hass_schema.agents,)
|
||||
|
||||
|
||||
## [Create the agents]
|
||||
def create_worker_agents(
|
||||
agents: List[HassSchema],
|
||||
*args,
|
||||
**kwargs,
|
||||
) -> 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,
|
||||
max_loops=1,
|
||||
autosave=True,
|
||||
dashboard=False,
|
||||
verbose=True,
|
||||
stopping_token="<DONE>",
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
# Set the long term memory system of every agent to long term memory system
|
||||
agent_list.append(out)
|
||||
|
||||
return agent_list
|
@ -0,0 +1,121 @@
|
||||
import logging
|
||||
import networkx as nx
|
||||
import matplotlib.pyplot as plt
|
||||
from typing import List, Tuple
|
||||
from swarms import Agent
|
||||
|
||||
# Setup basic configuration for logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
|
||||
|
||||
class AgentDFS:
|
||||
"""
|
||||
A DFS search class that uses a single Agent to generate and manually evaluate text states.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
agent: Agent,
|
||||
evaluator: Agent,
|
||||
initial_prompt: str,
|
||||
num_thoughts: int,
|
||||
max_steps: int,
|
||||
max_states: int,
|
||||
pruning_threshold: float,
|
||||
):
|
||||
self.agent = agent
|
||||
self.initial_prompt = initial_prompt
|
||||
self.num_thoughts = num_thoughts
|
||||
self.max_steps = max_steps
|
||||
self.max_states = max_states
|
||||
self.pruning_threshold = pruning_threshold
|
||||
self.visited = {}
|
||||
self.graph = nx.DiGraph()
|
||||
|
||||
def search(self) -> List[Tuple[str, float]]:
|
||||
stack = [(self.initial_prompt, 0.0)]
|
||||
self.graph.add_node(self.initial_prompt, score=0.0)
|
||||
results = []
|
||||
|
||||
while stack and len(results) < self.max_steps:
|
||||
current_prompt, _ = stack.pop()
|
||||
logging.info(f"Generating from: {current_prompt}")
|
||||
|
||||
# Use agent to generate a response
|
||||
out = self.agent.run(current_prompt)
|
||||
|
||||
# Retrieve and split generated text into segments (assuming `agent.response` holds the text)
|
||||
generated_texts = self.split_into_thoughts(
|
||||
out, self.num_thoughts
|
||||
)
|
||||
|
||||
for text, score in generated_texts:
|
||||
if score >= self.pruning_threshold:
|
||||
stack.append((text, score))
|
||||
results.append((text, score))
|
||||
self.graph.add_node(text, score=score)
|
||||
self.graph.add_edge(current_prompt, text)
|
||||
logging.info(f"Added node: {text} with score: {score}")
|
||||
|
||||
results.sort(key=lambda x: x[1], reverse=True)
|
||||
results = results[: self.max_states]
|
||||
|
||||
logging.info("Search completed")
|
||||
return results
|
||||
|
||||
def split_into_thoughts(
|
||||
self, text: str, num_thoughts: int
|
||||
) -> List[Tuple[str, float]]:
|
||||
"""Simulate the split of text into thoughts and assign random scores."""
|
||||
import random
|
||||
|
||||
# Simple split based on punctuation or predefined length
|
||||
thoughts = text.split(".")[:num_thoughts]
|
||||
return [
|
||||
(thought.strip(), random.random())
|
||||
for thought in thoughts
|
||||
if thought.strip()
|
||||
]
|
||||
|
||||
def visualize(self):
|
||||
pos = nx.spring_layout(self.graph, seed=42)
|
||||
labels = {
|
||||
node: f"{node[:15]}...: {self.graph.nodes[node]['score']:.2f}"
|
||||
for node in self.graph.nodes()
|
||||
}
|
||||
nx.draw(
|
||||
self.graph,
|
||||
pos,
|
||||
with_labels=True,
|
||||
labels=labels,
|
||||
node_size=7000,
|
||||
node_color="skyblue",
|
||||
font_size=8,
|
||||
font_weight="bold",
|
||||
edge_color="gray",
|
||||
)
|
||||
plt.show()
|
||||
|
||||
|
||||
# Example usage setup remains the same as before
|
||||
|
||||
|
||||
# Example usage setup remains the same as before, simply instantiate two agents: one for generation and one for evaluation
|
||||
# # Example usage
|
||||
# if __name__ == "__main__":
|
||||
# load_dotenv()
|
||||
# api_key = os.environ.get("OPENAI_API_KEY")
|
||||
# llm = llama3Hosted(max_tokens=400)
|
||||
# agent = Agent(llm=llm, max_loops=1, autosave=True, dashboard=True)
|
||||
# dfs_agent = AgentDFS(
|
||||
# agent=agent,
|
||||
# initial_prompt="Explore the benefits of regular exercise.",
|
||||
# num_thoughts=5,
|
||||
# max_steps=20,
|
||||
# max_states=10,
|
||||
# pruning_threshold=0.3,
|
||||
# )
|
||||
# results = dfs_agent.search()
|
||||
# dfs_agent.visualize()
|
@ -1,168 +0,0 @@
|
||||
import json
|
||||
import concurrent.futures
|
||||
import re
|
||||
from abc import abstractmethod
|
||||
from typing import Dict, List, NamedTuple
|
||||
|
||||
from langchain.schema import BaseOutputParser
|
||||
from pydantic import ValidationError
|
||||
|
||||
from swarms.tools.base_tool import BaseTool
|
||||
|
||||
from swarms.utils.loguru_logger import logger
|
||||
|
||||
|
||||
class AgentAction(NamedTuple):
|
||||
"""Action returned by AgentOutputParser."""
|
||||
|
||||
name: str
|
||||
args: Dict
|
||||
|
||||
|
||||
class BaseAgentOutputParser(BaseOutputParser):
|
||||
"""Base Output parser for Agent."""
|
||||
|
||||
@abstractmethod
|
||||
def parse(self, text: str) -> AgentAction:
|
||||
"""Return AgentAction"""
|
||||
|
||||
|
||||
def preprocess_json_input(input_str: str) -> str:
|
||||
"""Preprocesses a string to be parsed as json.
|
||||
|
||||
Replace single backslashes with double backslashes,
|
||||
while leaving already escaped ones intact.
|
||||
|
||||
Args:
|
||||
input_str: String to be preprocessed
|
||||
|
||||
Returns:
|
||||
Preprocessed string
|
||||
"""
|
||||
corrected_str = re.sub(
|
||||
r'(?<!\\)\\(?!["\\/bfnrt]|u[0-9a-fA-F]{4})',
|
||||
r"\\\\",
|
||||
input_str,
|
||||
)
|
||||
return corrected_str
|
||||
|
||||
|
||||
class AgentOutputParser(BaseAgentOutputParser):
|
||||
"""Output parser for Agent."""
|
||||
|
||||
def parse(self, text: str) -> AgentAction:
|
||||
try:
|
||||
parsed = json.loads(text, strict=False)
|
||||
except json.JSONDecodeError:
|
||||
preprocessed_text = preprocess_json_input(text)
|
||||
try:
|
||||
parsed = json.loads(preprocessed_text, strict=False)
|
||||
except Exception:
|
||||
return AgentAction(
|
||||
name="ERROR",
|
||||
args={
|
||||
"error": (f"Could not parse invalid json: {text}")
|
||||
},
|
||||
)
|
||||
try:
|
||||
return AgentAction(
|
||||
name=parsed["command"]["name"],
|
||||
args=parsed["command"]["args"],
|
||||
)
|
||||
except (KeyError, TypeError):
|
||||
# If the command is null or incomplete, return an erroneous tool
|
||||
return AgentAction(
|
||||
name="ERROR",
|
||||
args={"error": f"Incomplete command args: {parsed}"},
|
||||
)
|
||||
|
||||
|
||||
def execute_tool_by_name(
|
||||
text: str,
|
||||
tools: List[BaseTool],
|
||||
stop_token: str = "finish",
|
||||
):
|
||||
"""
|
||||
Executes a tool based on the given text command.
|
||||
|
||||
Args:
|
||||
text (str): The text command to be executed.
|
||||
tools (List[BaseTool]): A list of available tools.
|
||||
stop_token (str, optional): The stop token to terminate the execution. Defaults to "finish".
|
||||
|
||||
Returns:
|
||||
str: The result of the command execution.
|
||||
"""
|
||||
output_parser = AgentOutputParser()
|
||||
# Get command name and arguments
|
||||
action = output_parser.parse(text)
|
||||
tools = {t.name: t for t in tools}
|
||||
|
||||
# logger.info(f"Tools available: {tools}")
|
||||
|
||||
if action.name == stop_token:
|
||||
return action.args["response"]
|
||||
if action.name in tools:
|
||||
tool = tools[action.name]
|
||||
try:
|
||||
# Check if multiple tools are used
|
||||
tool_names = [name for name in tools if name in text]
|
||||
if len(tool_names) > 1:
|
||||
# Execute tools concurrently
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
futures = []
|
||||
for tool_name in tool_names:
|
||||
logger.info(f"Executing tool: {tool_name}")
|
||||
futures.append(
|
||||
executor.submit(
|
||||
tools[tool_name].run, action.args
|
||||
)
|
||||
)
|
||||
|
||||
# Wait for all futures to complete
|
||||
concurrent.futures.wait(futures)
|
||||
|
||||
# Get results from completed futures
|
||||
results = [
|
||||
future.result()
|
||||
for future in futures
|
||||
if future.done()
|
||||
]
|
||||
|
||||
# Process results
|
||||
for result in results:
|
||||
# Handle errors
|
||||
if isinstance(result, Exception):
|
||||
result = (
|
||||
f"Error: {str(result)},"
|
||||
f" {type(result).__name__}, args:"
|
||||
f" {action.args}"
|
||||
)
|
||||
# Handle successful execution
|
||||
else:
|
||||
result = (
|
||||
f"Command {tool.name} returned:"
|
||||
f" {result}"
|
||||
)
|
||||
else:
|
||||
observation = tool.run(action.args)
|
||||
except ValidationError as e:
|
||||
observation = (
|
||||
f"Validation Error in args: {str(e)}, args:"
|
||||
f" {action.args}"
|
||||
)
|
||||
except Exception as e:
|
||||
observation = (
|
||||
f"Error: {str(e)}, {type(e).__name__}, args:"
|
||||
f" {action.args}"
|
||||
)
|
||||
result = f"Command {tool.name} returned: {observation}"
|
||||
elif action.name == "ERROR":
|
||||
result = f"Error: {action.args}. "
|
||||
else:
|
||||
result = (
|
||||
f"Unknown command '{action.name}'. "
|
||||
"Please refer to the 'COMMANDS' list for available "
|
||||
"commands and only respond in the specified JSON format."
|
||||
)
|
||||
return result
|
@ -0,0 +1,176 @@
|
||||
import concurrent.futures
|
||||
from typing import Callable, Any, Dict, List
|
||||
from swarms.utils.loguru_logger import logger
|
||||
|
||||
|
||||
def openai_tool_executor(
|
||||
tools: List[Dict[str, Any]],
|
||||
function_map: Dict[str, Callable],
|
||||
verbose: bool = True,
|
||||
return_as_string: bool = False,
|
||||
*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.
|
||||
verbose (bool): If True, enables verbose logging.
|
||||
return_as_string (bool): If True, returns the results as a concatenated string.
|
||||
|
||||
Returns:
|
||||
Callable: A function that, when called, executes the specified functions concurrently with the parameters given.
|
||||
|
||||
Examples:
|
||||
>>> def test_function(param1: int, param2: str) -> str:
|
||||
... return f"Test function called with parameters: {param1}, {param2}"
|
||||
|
||||
>>> tool_executor = openai_tool_executor(
|
||||
... tools=[
|
||||
... {
|
||||
... "type": "function",
|
||||
... "function": {
|
||||
... "name": "test_function",
|
||||
... "parameters": {
|
||||
... "param1": 1,
|
||||
... "param2": "example"
|
||||
... }
|
||||
... }
|
||||
... }
|
||||
... ],
|
||||
... function_map={
|
||||
... "test_function": test_function
|
||||
... },
|
||||
... return_as_string=True
|
||||
... )
|
||||
>>> results = tool_executor()
|
||||
>>> print(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:
|
||||
error_message = f"Function '{func_name}' not found in function map."
|
||||
logger.error(error_message)
|
||||
results.append(error_message)
|
||||
continue
|
||||
|
||||
# Validate parameters
|
||||
params = function_info.get("parameters", {})
|
||||
if not params:
|
||||
error_message = f"No parameters specified for function '{func_name}'."
|
||||
logger.error(error_message)
|
||||
results.append(error_message)
|
||||
continue
|
||||
|
||||
# Submit the function for execution
|
||||
try:
|
||||
future = executor.submit(
|
||||
function_map[func_name], **params
|
||||
)
|
||||
futures.append((func_name, future))
|
||||
except Exception as e:
|
||||
error_message = f"Failed to submit the function '{func_name}' for execution: {e}"
|
||||
logger.error(error_message)
|
||||
results.append(error_message)
|
||||
|
||||
# Gather results from all futures
|
||||
for func_name, future in futures:
|
||||
try:
|
||||
result = future.result() # Collect result from future
|
||||
results.append(f"{func_name}: {result}")
|
||||
except Exception as e:
|
||||
error_message = f"Error during execution of function '{func_name}': {e}"
|
||||
logger.error(error_message)
|
||||
results.append(error_message)
|
||||
|
||||
if return_as_string:
|
||||
return "\n".join(results)
|
||||
|
||||
logger.info(f"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,
|
||||
# },
|
||||
# return_as_string=True,
|
||||
# )
|
||||
# print(out)
|
@ -0,0 +1,40 @@
|
||||
from typing import Any
|
||||
|
||||
|
||||
def function_to_str(function: dict[str, Any]) -> str:
|
||||
"""
|
||||
Convert a function dictionary to a string representation.
|
||||
|
||||
Args:
|
||||
function (dict[str, Any]): The function dictionary to convert.
|
||||
|
||||
Returns:
|
||||
str: The string representation of the function.
|
||||
|
||||
"""
|
||||
function_str = f"Function: {function['name']}\n"
|
||||
function_str += f"Description: {function['description']}\n"
|
||||
function_str += "Parameters:\n"
|
||||
|
||||
for param, details in function["parameters"]["properties"].items():
|
||||
function_str += f" {param} ({details['type']}): {details.get('description', '')}\n"
|
||||
|
||||
return function_str
|
||||
|
||||
|
||||
def functions_to_str(functions: list[dict[str, Any]]) -> str:
|
||||
"""
|
||||
Convert a list of function dictionaries to a string representation.
|
||||
|
||||
Args:
|
||||
functions (list[dict[str, Any]]): The list of function dictionaries to convert.
|
||||
|
||||
Returns:
|
||||
str: The string representation of the functions.
|
||||
|
||||
"""
|
||||
functions_str = ""
|
||||
for function in functions:
|
||||
functions_str += function_to_str(function) + "\n"
|
||||
|
||||
return functions_str
|
@ -0,0 +1,9 @@
|
||||
from swarms.tools.prebuilt.code_interpreter import (
|
||||
SubprocessCodeInterpreter,
|
||||
)
|
||||
from swarms.tools.prebuilt.math_eval import math_eval
|
||||
|
||||
__all__ = [
|
||||
"SubprocessCodeInterpreter",
|
||||
"math_eval",
|
||||
]
|
@ -1,8 +0,0 @@
|
||||
from langchain.tools import (
|
||||
BaseTool,
|
||||
Tool,
|
||||
StructuredTool,
|
||||
tool,
|
||||
) # noqa F401
|
||||
|
||||
__all__ = ["BaseTool", "Tool", "StructuredTool", "tool"]
|
Loading…
Reference in new issue