[Improvement][ForestSwarm][Improve format and structure] [Improvement][Agent][Add more verbose logging for mcp] [Docs][ForestSwarm]

pull/1148/head
Kye Gomez 2 days ago
parent c18b1d6bb5
commit 4a57c20aa8

@ -0,0 +1,23 @@
from swarms import Agent
from swarms.prompts.finance_agent_sys_prompt import (
FINANCIAL_AGENT_SYS_PROMPT,
)
agent = Agent(
agent_name="Financial-Analysis-Agent", # Name of the agent
agent_description="Personal finance advisor agent", # Description of the agent's role
system_prompt=FINANCIAL_AGENT_SYS_PROMPT, # System prompt for financial tasks
max_loops=1,
mcp_urls=[
"http://0.0.0.0:5932/mcp",
],
model_name="gpt-4o-mini",
output_type="all",
)
out = agent.run(
"Use the discover agent tools to find what agents are available and provide a summary"
)
# Print the output from the agent's run method.
print(out)

@ -2,7 +2,7 @@
This documentation describes the **ForestSwarm** that organizes agents into trees. Each agent specializes in processing specific tasks. Trees are collections of agents, each assigned based on their relevance to a task through keyword extraction and **litellm-based embedding similarity**. This documentation describes the **ForestSwarm** that organizes agents into trees. Each agent specializes in processing specific tasks. Trees are collections of agents, each assigned based on their relevance to a task through keyword extraction and **litellm-based embedding similarity**.
The architecture allows for efficient task assignment by selecting the most relevant agent from a set of trees. Tasks are processed asynchronously, with agents selected based on task relevance, calculated by the similarity of system prompts and task keywords using **litellm embeddings** and cosine similarity calculations. The architecture allows for efficient task assignment by selecting the most relevant agent from a set of trees. Tasks are processed with agents selected based on task relevance, calculated by the similarity of system prompts and task keywords using **litellm embeddings** and cosine similarity calculations.
## Module Path: `swarms.structs.tree_swarm` ## Module Path: `swarms.structs.tree_swarm`
@ -11,24 +11,30 @@ The architecture allows for efficient task assignment by selecting the most rele
### Utility Functions ### Utility Functions
#### `extract_keywords(prompt: str, top_n: int = 5) -> List[str]` #### `extract_keywords(prompt: str, top_n: int = 5) -> List[str]`
Extracts relevant keywords from a text prompt using basic word splitting and frequency counting. Extracts relevant keywords from a text prompt using basic word splitting and frequency counting.
**Parameters:** **Parameters:**
- `prompt` (str): The text to extract keywords from - `prompt` (str): The text to extract keywords from
- `top_n` (int): Maximum number of keywords to return - `top_n` (int): Maximum number of keywords to return
**Returns:** **Returns:**
- `List[str]`: List of extracted keywords sorted by frequency - `List[str]`: List of extracted keywords sorted by frequency
#### `cosine_similarity(vec1: List[float], vec2: List[float]) -> float` #### `cosine_similarity(vec1: List[float], vec2: List[float]) -> float`
Calculates the cosine similarity between two embedding vectors. Calculates the cosine similarity between two embedding vectors.
**Parameters:** **Parameters:**
- `vec1` (List[float]): First embedding vector - `vec1` (List[float]): First embedding vector
- `vec2` (List[float]): Second embedding vector - `vec2` (List[float]): Second embedding vector
**Returns:** **Returns:**
- `float`: Cosine similarity score between -1 and 1
- `float`: Cosine similarity score between 0 and 1
--- ---
@ -36,25 +42,29 @@ Calculates the cosine similarity between two embedding vectors.
`TreeAgent` represents an individual agent responsible for handling a specific task. Agents are initialized with a **system prompt** and use **litellm embeddings** to dynamically determine their relevance to a given task. `TreeAgent` represents an individual agent responsible for handling a specific task. Agents are initialized with a **system prompt** and use **litellm embeddings** to dynamically determine their relevance to a given task.
#### Attributes #### TreeAgent Attributes
| **Attribute** | **Type** | **Description** | | **Attribute** | **Type** | **Description** |
|--------------------------|------------------|---------------------------------------------------------------------------------| |--------------------------|------------------|---------------------------------------------------------------------------------|
| `name` | `str` | Name of the agent |
| `description` | `str` | Description of the agent |
| `system_prompt` | `str` | A string that defines the agent's area of expertise and task-handling capability.| | `system_prompt` | `str` | A string that defines the agent's area of expertise and task-handling capability.|
| `llm` | `callable` | The language model (LLM) used to process tasks (e.g., GPT-4). | | `model_name` | `str` | Name of the language model to use (default: "gpt-4.1") |
| `agent_name` | `str` | The name of the agent. | | `agent_name` | `str` | The name of the agent. |
| `system_prompt_embedding`| `List[float]` | **litellm-generated embedding** of the system prompt for similarity-based task matching.| | `system_prompt_embedding`| `List[float]` | **litellm-generated embedding** of the system prompt for similarity-based task matching.|
| `relevant_keywords` | `List[str]` | Keywords dynamically extracted from the system prompt to assist in task matching.| | `relevant_keywords` | `List[str]` | Keywords dynamically extracted from the system prompt to assist in task matching.|
| `distance` | `Optional[float]`| The computed distance between agents based on embedding similarity. | | `distance` | `Optional[float]`| The computed distance between agents based on embedding similarity. |
| `embedding_model_name` | `str` | **Name of the litellm embedding model** (default: "text-embedding-ada-002"). | | `embedding_model_name` | `str` | **Name of the litellm embedding model** (default: "text-embedding-ada-002"). |
| `verbose` | `bool` | Whether to enable verbose logging |
#### Methods #### TreeAgent Methods
| **Method** | **Input** | **Output** | **Description** | | **Method** | **Input** | **Output** | **Description** |
|--------------------|---------------------------------|--------------------|---------------------------------------------------------------------------------| |--------------------|---------------------------------|--------------------|---------------------------------------------------------------------------------|
| `__init__(name, description, system_prompt, model_name, agent_name, embedding_model_name, verbose, *args, **kwargs)` | Various initialization parameters | `None` | Initializes a TreeAgent with litellm embedding capabilities |
| `_get_embedding(text: str)` | `text: str` | `List[float]` | **Internal method to generate embeddings using litellm.** | | `_get_embedding(text: str)` | `text: str` | `List[float]` | **Internal method to generate embeddings using litellm.** |
| `calculate_distance(other_agent: TreeAgent)` | `other_agent: TreeAgent` | `float` | Calculates the **cosine similarity distance** between this agent and another agent.| | `calculate_distance(other_agent: TreeAgent)` | `other_agent: TreeAgent` | `float` | Calculates the **cosine similarity distance** between this agent and another agent.|
| `run_task(task: str)` | `task: str` | `Any` | Executes the task, logs the input/output, and returns the result. | | `run_task(task: str, img: str = None, *args, **kwargs)` | `task: str, img: str, *args, **kwargs` | `Any` | Executes the task, logs the input/output, and returns the result. |
| `is_relevant_for_task(task: str, threshold: float = 0.7)` | `task: str, threshold: float` | `bool` | Checks if the agent is relevant for the task using **keyword matching and litellm embedding similarity**.| | `is_relevant_for_task(task: str, threshold: float = 0.7)` | `task: str, threshold: float` | `bool` | Checks if the agent is relevant for the task using **keyword matching and litellm embedding similarity**.|
--- ---
@ -63,28 +73,30 @@ Calculates the cosine similarity between two embedding vectors.
`Tree` organizes multiple agents into a hierarchical structure, where agents are sorted based on their relevance to tasks using **litellm embeddings**. `Tree` organizes multiple agents into a hierarchical structure, where agents are sorted based on their relevance to tasks using **litellm embeddings**.
#### Attributes #### Tree Attributes
| **Attribute** | **Type** | **Description** | | **Attribute** | **Type** | **Description** |
|--------------------------|------------------|---------------------------------------------------------------------------------| |--------------------------|------------------|---------------------------------------------------------------------------------|
| `tree_name` | `str` | The name of the tree (represents a domain of agents, e.g., "Financial Tree"). | | `tree_name` | `str` | The name of the tree (represents a domain of agents, e.g., "Financial Tree"). |
| `agents` | `List[TreeAgent]`| List of agents belonging to this tree, **sorted by embedding-based distance**. | | `agents` | `List[TreeAgent]`| List of agents belonging to this tree, **sorted by embedding-based distance**. |
| `verbose` | `bool` | Whether to enable verbose logging |
#### Methods #### Tree Methods
| **Method** | **Input** | **Output** | **Description** | | **Method** | **Input** | **Output** | **Description** |
|--------------------|---------------------------------|--------------------|---------------------------------------------------------------------------------| |--------------------|---------------------------------|--------------------|---------------------------------------------------------------------------------|
| `__init__(tree_name: str, agents: List[TreeAgent], verbose: bool = False)` | `tree_name: str, agents: List[TreeAgent], verbose: bool` | `None` | Initializes a tree of agents |
| `calculate_agent_distances()` | `None` | `None` | **Calculates and assigns distances between agents based on litellm embedding similarity of prompts.** | | `calculate_agent_distances()` | `None` | `None` | **Calculates and assigns distances between agents based on litellm embedding similarity of prompts.** |
| `find_relevant_agent(task: str)` | `task: str` | `Optional[TreeAgent]` | **Finds the most relevant agent for a task based on keyword and litellm embedding similarity.** | | `find_relevant_agent(task: str)` | `task: str` | `Optional[TreeAgent]` | **Finds the most relevant agent for a task based on keyword and litellm embedding similarity.** |
| `log_tree_execution(task: str, selected_agent: TreeAgent, result: Any)` | `task: str, selected_agent: TreeAgent, result: Any` | `None` | Logs details of the task execution by the selected agent. | | `log_tree_execution(task: str, selected_agent: TreeAgent, result: Any)` | `task: str, selected_agent: TreeAgent, result: Any` | `None` | Logs details of the task execution by the selected agent. |
--- ---
### Class: `ForestSwarm` ### Class: `ForestSwarm`
`ForestSwarm` is the main class responsible for managing multiple trees. It oversees task delegation by finding the most relevant tree and agent for a given task using **litellm embeddings**. `ForestSwarm` is the main class responsible for managing multiple trees. It oversees task delegation by finding the most relevant tree and agent for a given task using **litellm embeddings**.
#### Attributes #### ForestSwarm Attributes
| **Attribute** | **Type** | **Description** | | **Attribute** | **Type** | **Description** |
|--------------------------|------------------|---------------------------------------------------------------------------------| |--------------------------|------------------|---------------------------------------------------------------------------------|
@ -92,42 +104,51 @@ Calculates the cosine similarity between two embedding vectors.
| `description` | `str` | Description of the forest swarm. | | `description` | `str` | Description of the forest swarm. |
| `trees` | `List[Tree]` | List of trees containing agents organized by domain. | | `trees` | `List[Tree]` | List of trees containing agents organized by domain. |
| `shared_memory` | `Any` | Shared memory object for inter-tree communication. | | `shared_memory` | `Any` | Shared memory object for inter-tree communication. |
| `rules` | `str` | Rules governing the forest swarm behavior. | | `verbose` | `bool` | Whether to enable verbose logging |
| `save_file_path` | `str` | File path for saving conversation logs |
| `conversation` | `Conversation` | Conversation object for tracking interactions. | | `conversation` | `Conversation` | Conversation object for tracking interactions. |
#### Methods #### ForestSwarm Methods
| **Method** | **Input** | **Output** | **Description** | | **Method** | **Input** | **Output** | **Description** |
|--------------------|---------------------------------|--------------------|---------------------------------------------------------------------------------| |--------------------|---------------------------------|--------------------|---------------------------------------------------------------------------------|
| `__init__(name, description, trees, shared_memory, rules, verbose, *args, **kwargs)` | Various initialization parameters | `None` | Initialize a ForestSwarm with multiple trees of agents |
| `find_relevant_tree(task: str)` | `task: str` | `Optional[Tree]` | **Searches across all trees to find the most relevant tree based on litellm embedding similarity.**| | `find_relevant_tree(task: str)` | `task: str` | `Optional[Tree]` | **Searches across all trees to find the most relevant tree based on litellm embedding similarity.**|
| `run(task: str, img: str = None, *args, **kwargs)` | `task: str, img: str, *args, **kwargs` | `Any` | **Executes the task by finding the most relevant agent from the relevant tree using litellm embeddings.**| | `run(task: str, img: str = None, *args, **kwargs)` | `task: str, img: str, *args, **kwargs` | `Any` | **Executes the task by finding the most relevant agent from the relevant tree using litellm embeddings.**|
| `batched_run(tasks: List[str], *args, **kwargs)` | `tasks: List[str], *args, **kwargs` | `List[Any]` | **Executes multiple tasks by finding the most relevant agent for each task.**|
--- ---
### Pydantic Models for Logging ### Pydantic Models for Logging
#### `AgentLogInput` #### `AgentLogInput`
Input log model for tracking agent task execution. Input log model for tracking agent task execution.
**Fields:** **Fields:**
- `log_id` (str): Unique identifier for the log entry - `log_id` (str): Unique identifier for the log entry
- `agent_name` (str): Name of the agent executing the task - `agent_name` (str): Name of the agent executing the task
- `task` (str): Description of the task being executed - `task` (str): Description of the task being executed
- `timestamp` (datetime): When the task was started - `timestamp` (datetime): When the task was started
#### `AgentLogOutput` #### `AgentLogOutput`
Output log model for tracking agent task completion. Output log model for tracking agent task completion.
**Fields:** **Fields:**
- `log_id` (str): Unique identifier for the log entry - `log_id` (str): Unique identifier for the log entry
- `agent_name` (str): Name of the agent that completed the task - `agent_name` (str): Name of the agent that completed the task
- `result` (Any): Result/output from the task execution - `result` (Any): Result/output from the task execution
- `timestamp` (datetime): When the task was completed - `timestamp` (datetime): When the task was completed
#### `TreeLog` #### `TreeLog`
Tree execution log model for tracking tree-level operations. Tree execution log model for tracking tree-level operations.
**Fields:** **Fields:**
- `log_id` (str): Unique identifier for the log entry - `log_id` (str): Unique identifier for the log entry
- `tree_name` (str): Name of the tree that executed the task - `tree_name` (str): Name of the tree that executed the task
- `task` (str): Description of the task that was executed - `task` (str): Description of the task that was executed
@ -145,49 +166,72 @@ from swarms.structs.tree_swarm import TreeAgent, Tree, ForestSwarm
# Create agents with varying system prompts and dynamically generated distances/keywords # Create agents with varying system prompts and dynamically generated distances/keywords
agents_tree1 = [ agents_tree1 = [
TreeAgent( TreeAgent(
name="Financial Advisor",
system_prompt="I am a financial advisor specializing in investment planning, retirement strategies, and tax optimization for individuals and businesses.", system_prompt="I am a financial advisor specializing in investment planning, retirement strategies, and tax optimization for individuals and businesses.",
agent_name="Financial Advisor", agent_name="Financial Advisor",
verbose=True
), ),
TreeAgent( TreeAgent(
name="Tax Expert",
system_prompt="I am a tax expert with deep knowledge of corporate taxation, Delaware incorporation benefits, and free tax filing options for businesses.", system_prompt="I am a tax expert with deep knowledge of corporate taxation, Delaware incorporation benefits, and free tax filing options for businesses.",
agent_name="Tax Expert", agent_name="Tax Expert",
verbose=True
), ),
TreeAgent( TreeAgent(
name="Retirement Planner",
system_prompt="I am a retirement planning specialist who helps individuals and businesses create comprehensive retirement strategies and investment plans.", system_prompt="I am a retirement planning specialist who helps individuals and businesses create comprehensive retirement strategies and investment plans.",
agent_name="Retirement Planner", agent_name="Retirement Planner",
verbose=True
), ),
] ]
agents_tree2 = [ agents_tree2 = [
TreeAgent( TreeAgent(
name="Stock Analyst",
system_prompt="I am a stock market analyst who provides insights on market trends, stock recommendations, and portfolio optimization strategies.", system_prompt="I am a stock market analyst who provides insights on market trends, stock recommendations, and portfolio optimization strategies.",
agent_name="Stock Analyst", agent_name="Stock Analyst",
verbose=True
), ),
TreeAgent( TreeAgent(
name="Investment Strategist",
system_prompt="I am an investment strategist specializing in portfolio diversification, risk management, and market analysis.", system_prompt="I am an investment strategist specializing in portfolio diversification, risk management, and market analysis.",
agent_name="Investment Strategist", agent_name="Investment Strategist",
verbose=True
), ),
TreeAgent( TreeAgent(
name="ROTH IRA Specialist",
system_prompt="I am a ROTH IRA specialist who helps individuals optimize their retirement accounts and tax advantages.", system_prompt="I am a ROTH IRA specialist who helps individuals optimize their retirement accounts and tax advantages.",
agent_name="ROTH IRA Specialist", agent_name="ROTH IRA Specialist",
verbose=True
), ),
] ]
# Create trees # Create trees
tree1 = Tree(tree_name="Financial Services Tree", agents=agents_tree1) tree1 = Tree(tree_name="Financial Services Tree", agents=agents_tree1, verbose=True)
tree2 = Tree(tree_name="Investment & Trading Tree", agents=agents_tree2) tree2 = Tree(tree_name="Investment & Trading Tree", agents=agents_tree2, verbose=True)
# Create the ForestSwarm # Create the ForestSwarm
forest_swarm = ForestSwarm( forest_swarm = ForestSwarm(
name="Financial Services Forest", name="Financial Services Forest",
description="A comprehensive financial services multi-agent system", description="A comprehensive financial services multi-agent system",
trees=[tree1, tree2] trees=[tree1, tree2],
verbose=True
) )
# Run a task # Run a task
task = "Our company is incorporated in Delaware, how do we do our taxes for free?" task = "Our company is incorporated in Delaware, how do we do our taxes for free?"
output = forest_swarm.run(task) output = forest_swarm.run(task)
print(output) print(output)
# Run multiple tasks
tasks = [
"What are the best investment strategies for retirement?",
"How do I file taxes for my Delaware corporation?",
"What's the current market outlook for tech stocks?"
]
results = forest_swarm.batched_run(tasks)
for i, result in enumerate(results):
print(f"Task {i+1} result: {result}")
``` ```
--- ---
@ -203,12 +247,14 @@ print(output)
- Searches through all trees using **cosine similarity** - Searches through all trees using **cosine similarity**
- Finds the most relevant agent based on **embedding similarity and keyword matching** - Finds the most relevant agent based on **embedding similarity and keyword matching**
6. **Task Execution**: The selected agent processes the task, and the result is returned and logged. 6. **Task Execution**: The selected agent processes the task, and the result is returned and logged.
7. **Batched Processing**: Multiple tasks can be processed using the `batched_run` method for efficient batch processing.
```plaintext ```plaintext
Task: "Our company is incorporated in Delaware, how do we do our taxes for free?" Task: "Our company is incorporated in Delaware, how do we do our taxes for free?"
``` ```
**Process**: **Process:**
- The system generates **litellm embeddings** for the task - The system generates **litellm embeddings** for the task
- Searches through the `Financial Services Tree` and `Investment & Trading Tree` - Searches through the `Financial Services Tree` and `Investment & Trading Tree`
- Uses **cosine similarity** to find the most relevant agent (likely the "Tax Expert") - Uses **cosine similarity** to find the most relevant agent (likely the "Tax Expert")
@ -219,20 +265,29 @@ Task: "Our company is incorporated in Delaware, how do we do our taxes for free?
## Key Features ## Key Features
### **litellm Integration** ### **litellm Integration**
- **Embedding Generation**: Uses litellm's `embedding()` function for generating high-quality embeddings - **Embedding Generation**: Uses litellm's `embedding()` function for generating high-quality embeddings
- **Model Flexibility**: Supports various embedding models (default: "text-embedding-ada-002") - **Model Flexibility**: Supports various embedding models (default: "text-embedding-ada-002")
- **Error Handling**: Robust fallback mechanisms for embedding failures - **Error Handling**: Robust fallback mechanisms for embedding failures
### **Semantic Similarity** ### **Semantic Similarity**
- **Cosine Similarity**: Implements efficient cosine similarity calculations for vector comparisons - **Cosine Similarity**: Implements efficient cosine similarity calculations for vector comparisons
- **Threshold-based Selection**: Configurable similarity thresholds for agent selection - **Threshold-based Selection**: Configurable similarity thresholds for agent selection
- **Hybrid Matching**: Combines keyword matching with semantic similarity for optimal results - **Hybrid Matching**: Combines keyword matching with semantic similarity for optimal results
### **Dynamic Agent Organization** ### **Dynamic Agent Organization**
- **Automatic Distance Calculation**: Agents are automatically organized by semantic similarity - **Automatic Distance Calculation**: Agents are automatically organized by semantic similarity
- **Real-time Relevance**: Task relevance is calculated dynamically using current embeddings - **Real-time Relevance**: Task relevance is calculated dynamically using current embeddings
- **Scalable Architecture**: Easy to add/remove agents and trees without manual configuration - **Scalable Architecture**: Easy to add/remove agents and trees without manual configuration
### **Batch Processing**
- **Batched Execution**: Process multiple tasks efficiently using `batched_run` method
- **Parallel Processing**: Each task is processed independently with the most relevant agent
- **Result Aggregation**: All results are returned as a list for easy processing
--- ---
## Analysis of the Swarm Architecture ## Analysis of the Swarm Architecture
@ -243,7 +298,7 @@ The **ForestSwarm Architecture** leverages a hierarchical structure (forest) com
- **Task Specialization**: Each agent is specialized, which ensures that tasks are matched with the most appropriate agent based on **litellm embedding similarity** and expertise. - **Task Specialization**: Each agent is specialized, which ensures that tasks are matched with the most appropriate agent based on **litellm embedding similarity** and expertise.
- **Dynamic Matching**: The architecture uses both keyword-based and **litellm embedding-based matching** to assign tasks, ensuring a high level of accuracy in agent selection. - **Dynamic Matching**: The architecture uses both keyword-based and **litellm embedding-based matching** to assign tasks, ensuring a high level of accuracy in agent selection.
- **Logging and Accountability**: Each task execution is logged in detail, providing transparency and an audit trail of which agent handled which task and the results produced. - **Logging and Accountability**: Each task execution is logged in detail, providing transparency and an audit trail of which agent handled which task and the results produced.
- **Asynchronous Task Execution**: The architecture can be adapted for asynchronous task processing, making it scalable and suitable for large-scale task handling in real-time systems. - **Batch Processing**: The architecture supports efficient batch processing of multiple tasks simultaneously.
--- ---
@ -274,6 +329,13 @@ graph TD
P --> Q[Execute Task] P --> Q[Execute Task]
Q --> R[Log Results] Q --> R[Log Results]
end end
subgraph Batch Processing
S[Multiple Tasks] --> T[Process Each Task]
T --> U[Find Relevant Agent per Task]
U --> V[Execute All Tasks]
V --> W[Return Results List]
end
``` ```
### Explanation of the Diagram ### Explanation of the Diagram
@ -283,6 +345,7 @@ graph TD
- **Agents**: Each agent within the tree is responsible for handling tasks in its area of expertise. Agents within a tree are organized based on their **litellm embedding similarity** (distance). - **Agents**: Each agent within the tree is responsible for handling tasks in its area of expertise. Agents within a tree are organized based on their **litellm embedding similarity** (distance).
- **Embedding Process**: Shows how **litellm embeddings** are used for similarity calculations and agent selection. - **Embedding Process**: Shows how **litellm embeddings** are used for similarity calculations and agent selection.
- **Task Processing**: Illustrates the complete workflow from task input to result logging. - **Task Processing**: Illustrates the complete workflow from task input to result logging.
- **Batch Processing**: Shows how multiple tasks can be processed efficiently using the `batched_run` method.
--- ---
@ -295,6 +358,7 @@ python test_forest_swarm.py
``` ```
The test suite covers: The test suite covers:
- **Utility Functions**: `extract_keywords`, `cosine_similarity` - **Utility Functions**: `extract_keywords`, `cosine_similarity`
- **Pydantic Models**: `AgentLogInput`, `AgentLogOutput`, `TreeLog` - **Pydantic Models**: `AgentLogInput`, `AgentLogOutput`, `TreeLog`
- **Core Classes**: `TreeAgent`, `Tree`, `ForestSwarm` - **Core Classes**: `TreeAgent`, `Tree`, `ForestSwarm`
@ -308,8 +372,11 @@ The test suite covers:
This **ForestSwarm Architecture** provides an efficient, scalable, and accurate architecture for delegating and executing tasks based on domain-specific expertise. The combination of hierarchical organization, **litellm-based semantic similarity**, dynamic task matching, and comprehensive logging ensures reliability, performance, and transparency in task execution. This **ForestSwarm Architecture** provides an efficient, scalable, and accurate architecture for delegating and executing tasks based on domain-specific expertise. The combination of hierarchical organization, **litellm-based semantic similarity**, dynamic task matching, and comprehensive logging ensures reliability, performance, and transparency in task execution.
**Key Advantages:** **Key Advantages:**
- **High Accuracy**: litellm embeddings provide superior semantic understanding - **High Accuracy**: litellm embeddings provide superior semantic understanding
- **Scalability**: Easy to add new agents, trees, and domains - **Scalability**: Easy to add new agents, trees, and domains
- **Flexibility**: Configurable similarity thresholds and embedding models - **Flexibility**: Configurable similarity thresholds and embedding models
- **Robustness**: Comprehensive error handling and fallback mechanisms - **Robustness**: Comprehensive error handling and fallback mechanisms
- **Transparency**: Detailed logging and audit trails for all operations - **Transparency**: Detailed logging and audit trails for all operations
- **Batch Processing**: Efficient processing of multiple tasks simultaneously
- **Verbose Logging**: Comprehensive logging at all levels for debugging and monitoring

@ -79,14 +79,16 @@ financial_agent = Agent(
max_loops=1, max_loops=1,
top_p=None, top_p=None,
dynamic_temperature_enabled=True, dynamic_temperature_enabled=True,
system_prompt="""You are a financial specialist. Your role is to: system_prompt="""
You are a financial specialist. Your role is to:
1. Analyze financial data and markets 1. Analyze financial data and markets
2. Provide investment insights 2. Provide investment insights
3. Assess risk and opportunities 3. Assess risk and opportunities
4. Create financial reports 4. Create financial reports
5. Explain complex financial concepts 5. Explain complex financial concepts
Always provide accurate, well-reasoned financial analysis.""", Always provide accurate, well-reasoned financial analysis.
""",
) )
# Basic usage - individual agent addition # Basic usage - individual agent addition

@ -1,36 +0,0 @@
from mcp.server.fastmcp import FastMCP
from swarms import Agent
mcp = FastMCP("MCPAgentTool")
@mcp.tool(
name="create_agent",
description="Create an agent with the specified name, system prompt, and model, then run a task.",
)
def create_agent(
agent_name: str, system_prompt: str, model_name: str, task: str
) -> str:
"""
Create an agent with the given parameters and execute the specified task.
Args:
agent_name (str): The name of the agent to create.
system_prompt (str): The system prompt to initialize the agent with.
model_name (str): The model name to use for the agent.
task (str): The task for the agent to perform.
Returns:
str: The result of the agent running the given task.
"""
agent = Agent(
agent_name=agent_name,
system_prompt=system_prompt,
model_name=model_name,
)
return agent.run(task)
if __name__ == "__main__":
mcp.run()

@ -0,0 +1,10 @@
from swarms.tools.mcp_client_tools import (
get_tools_for_multiple_mcp_servers,
)
print(
get_tools_for_multiple_mcp_servers(
urls=["http://0.0.0.0:5932/mcp"]
)
)

@ -1,20 +1,3 @@
#!/usr/bin/env python3
"""
Multi-MCP Agent Example
This example demonstrates how to use multiple MCP (Model Context Protocol) servers
with a single Swarms agent. The agent can access tools from different MCP servers
simultaneously, enabling powerful cross-server functionality.
Prerequisites:
1. Start the OKX crypto server: python multi_mcp_guide/okx_crypto_server.py
2. Start the agent tools server: python multi_mcp_guide/mcp_agent_tool.py
3. Install required dependencies: pip install swarms mcp fastmcp requests
Usage:
python examples/multi_agent/multi_mcp_example.py
"""
from swarms import Agent from swarms import Agent
from swarms.prompts.finance_agent_sys_prompt import ( from swarms.prompts.finance_agent_sys_prompt import (
FINANCIAL_AGENT_SYS_PROMPT, FINANCIAL_AGENT_SYS_PROMPT,

@ -3,26 +3,18 @@ from swarms.prompts.finance_agent_sys_prompt import (
FINANCIAL_AGENT_SYS_PROMPT, FINANCIAL_AGENT_SYS_PROMPT,
) )
# Initialize the financial analysis agent with a system prompt and configuration.
agent = Agent( agent = Agent(
agent_name="Financial-Analysis-Agent", # Name of the agent agent_name="Financial-Analysis-Agent", # Name of the agent
agent_description="Personal finance advisor agent", # Description of the agent's role agent_description="Personal finance advisor agent", # Description of the agent's role
system_prompt=FINANCIAL_AGENT_SYS_PROMPT, # System prompt for financial tasks system_prompt=FINANCIAL_AGENT_SYS_PROMPT, # System prompt for financial tasks
max_loops=1, max_loops=1,
mcp_urls=[ mcp_url="http://0.0.0.0:8001/mcp", # URL for the OKX crypto price MCP server
"http://0.0.0.0:8001/mcp", # URL for the OKX crypto price MCP server
"http://0.0.0.0:8000/mcp", # URL for the agent creation MCP server
],
model_name="gpt-4o-mini", model_name="gpt-4o-mini",
output_type="all", output_type="all",
) )
# Run the agent with a specific instruction to use the create_agent tool.
# The agent is asked to create a new agent specialized for accounting rules in crypto.
out = agent.run( out = agent.run(
# Example alternative prompt: "Use the get_okx_crypto_price to get the price of solana just put the name of the coin",
# "Use the get_okx_crypto_price to get the price of solana just put the name of the coin",
"Use the create_agent tool that is specialized in creating agents and create an agent speecialized for accounting rules in crypto"
) )
# Print the output from the agent's run method. # Print the output from the agent's run method.

@ -0,0 +1,43 @@
from swarms.structs.tree_swarm import TreeAgent, Tree, ForestSwarm
# Create agents with varying system prompts and dynamically generated distances/keywords
agents_tree1 = [
TreeAgent(
system_prompt="Stock Analysis Agent",
agent_name="Stock Analysis Agent",
),
TreeAgent(
system_prompt="Financial Planning Agent",
agent_name="Financial Planning Agent",
),
TreeAgent(
agent_name="Retirement Strategy Agent",
system_prompt="Retirement Strategy Agent",
),
]
agents_tree2 = [
TreeAgent(
system_prompt="Tax Filing Agent",
agent_name="Tax Filing Agent",
),
TreeAgent(
system_prompt="Investment Strategy Agent",
agent_name="Investment Strategy Agent",
),
TreeAgent(
system_prompt="ROTH IRA Agent", agent_name="ROTH IRA Agent"
),
]
# Create trees
tree1 = Tree(tree_name="Financial Tree", agents=agents_tree1)
tree2 = Tree(tree_name="Investment Tree", agents=agents_tree2)
# Create the ForestSwarm
multi_agent_structure = ForestSwarm(trees=[tree1, tree2])
# Run a task
task = "Our company is incorporated in delaware, how do we do our taxes for free?"
output = multi_agent_structure.run(task)
print(output)

@ -822,7 +822,17 @@ class Agent:
tools_list.extend(self.tools_list_dictionary) tools_list.extend(self.tools_list_dictionary)
if exists(self.mcp_url) or exists(self.mcp_urls): if exists(self.mcp_url) or exists(self.mcp_urls):
tools_list.extend(self.add_mcp_tools_to_memory()) if self.verbose:
logger.info(
f"Adding MCP tools to memory for {self.agent_name}"
)
# tools_list.extend(self.add_mcp_tools_to_memory())
mcp_tools = self.add_mcp_tools_to_memory()
if self.verbose:
logger.info(f"MCP tools: {mcp_tools}")
tools_list.extend(mcp_tools)
# Additional arguments for LiteLLM initialization # Additional arguments for LiteLLM initialization
additional_args = {} additional_args = {}
@ -888,37 +898,37 @@ class Agent:
Exception: If there's an error accessing the MCP tools Exception: If there's an error accessing the MCP tools
""" """
try: try:
# Determine which MCP configuration to use
if exists(self.mcp_url): if exists(self.mcp_url):
tools = get_mcp_tools_sync(server_path=self.mcp_url) tools = get_mcp_tools_sync(server_path=self.mcp_url)
elif exists(self.mcp_config): elif exists(self.mcp_config):
tools = get_mcp_tools_sync(connection=self.mcp_config) tools = get_mcp_tools_sync(connection=self.mcp_config)
# logger.info(f"Tools: {tools}")
elif exists(self.mcp_urls): elif exists(self.mcp_urls):
logger.info(
f"Getting MCP tools for multiple MCP servers for {self.agent_name}"
)
tools = get_tools_for_multiple_mcp_servers( tools = get_tools_for_multiple_mcp_servers(
urls=self.mcp_urls, urls=self.mcp_urls,
output_type="str",
) )
# print(f"Tools: {tools} for {self.mcp_urls}")
if self.verbose:
logger.info(f"MCP tools: {tools}")
else: else:
raise AgentMCPConnectionError( raise AgentMCPConnectionError(
"mcp_url must be either a string URL or MCPConnection object" "mcp_url must be either a string URL or MCPConnection object"
) )
if ( # Print success message if any MCP configuration exists
exists(self.mcp_url) if self.print_on:
or exists(self.mcp_urls) self.pretty_print(
or exists(self.mcp_config) f"✨ [SYSTEM] Successfully integrated {len(tools)} MCP tools into agent: {self.agent_name} | Status: ONLINE | Time: {time.strftime('%H:%M:%S')}",
): loop_count=0,
if self.print_on is True: )
self.pretty_print(
f"✨ [SYSTEM] Successfully integrated {len(tools)} MCP tools into agent: {self.agent_name} | Status: ONLINE | Time: {time.strftime('%H:%M:%S')}",
loop_count=0,
)
return tools return tools
except AgentMCPConnectionError as e: except AgentMCPConnectionError as e:
logger.error( logger.error(
f"Error in MCP connection: {e} Traceback: {traceback.format_exc()}" f"Error Adding MCP Tools to Agent: {self.agent_name} Error: {e} Traceback: {traceback.format_exc()}"
) )
raise e raise e

@ -7,9 +7,6 @@ import schedule
from loguru import logger from loguru import logger
# from swarms import Agent
class CronJobError(Exception): class CronJobError(Exception):
"""Base exception class for CronJob errors.""" """Base exception class for CronJob errors."""

@ -1,9 +1,8 @@
import uuid import uuid
from collections import Counter from collections import Counter
from datetime import datetime from datetime import datetime, timezone
from typing import Any, List, Optional from typing import Any, List, Optional
import numpy as np
from litellm import embedding from litellm import embedding
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@ -14,6 +13,47 @@ from swarms.utils.loguru_logger import initialize_logger
logger = initialize_logger(log_folder="tree_swarm") logger = initialize_logger(log_folder="tree_swarm")
def extract_keywords(prompt: str, top_n: int = 5) -> List[str]:
"""
A simplified keyword extraction function using basic word splitting instead of NLTK tokenization.
Args:
prompt (str): The text prompt to extract keywords from
top_n (int): Maximum number of keywords to return
Returns:
List[str]: List of extracted keywords
"""
words = prompt.lower().split()
filtered_words = [word for word in words if word.isalnum()]
word_counts = Counter(filtered_words)
return [word for word, _ in word_counts.most_common(top_n)]
def cosine_similarity(vec1: List[float], vec2: List[float]) -> float:
"""
Calculate cosine similarity between two vectors.
Args:
vec1 (List[float]): First vector
vec2 (List[float]): Second vector
Returns:
float: Cosine similarity score between 0 and 1
"""
# Calculate dot product
dot_product = sum(a * b for a, b in zip(vec1, vec2))
# Calculate norms
norm1 = sum(a * a for a in vec1) ** 0.5
norm2 = sum(b * b for b in vec2) ** 0.5
if norm1 == 0 or norm2 == 0:
return 0.0
return dot_product / (norm1 * norm2)
# Pydantic Models for Logging # Pydantic Models for Logging
class AgentLogInput(BaseModel): class AgentLogInput(BaseModel):
""" """
@ -32,7 +72,7 @@ class AgentLogInput(BaseModel):
agent_name: str agent_name: str
task: str task: str
timestamp: datetime = Field( timestamp: datetime = Field(
default_factory=lambda: datetime.now(datetime.UTC) default_factory=lambda: datetime.now(timezone.utc)
) )
@ -53,7 +93,7 @@ class AgentLogOutput(BaseModel):
agent_name: str agent_name: str
result: Any result: Any
timestamp: datetime = Field( timestamp: datetime = Field(
default_factory=lambda: datetime.now(datetime.UTC) default_factory=lambda: datetime.now(timezone.utc)
) )
@ -77,52 +117,11 @@ class TreeLog(BaseModel):
task: str task: str
selected_agent: str selected_agent: str
timestamp: datetime = Field( timestamp: datetime = Field(
default_factory=lambda: datetime.now(datetime.UTC) default_factory=lambda: datetime.now(timezone.utc)
) )
result: Any result: Any
def extract_keywords(prompt: str, top_n: int = 5) -> List[str]:
"""
A simplified keyword extraction function using basic word splitting instead of NLTK tokenization.
Args:
prompt (str): The text prompt to extract keywords from
top_n (int): Maximum number of keywords to return
Returns:
List[str]: List of extracted keywords
"""
words = prompt.lower().split()
filtered_words = [word for word in words if word.isalnum()]
word_counts = Counter(filtered_words)
return [word for word, _ in word_counts.most_common(top_n)]
def cosine_similarity(vec1: List[float], vec2: List[float]) -> float:
"""
Calculate cosine similarity between two vectors.
Args:
vec1 (List[float]): First vector
vec2 (List[float]): Second vector
Returns:
float: Cosine similarity score between 0 and 1
"""
vec1 = np.array(vec1)
vec2 = np.array(vec2)
dot_product = np.dot(vec1, vec2)
norm1 = np.linalg.norm(vec1)
norm2 = np.linalg.norm(vec2)
if norm1 == 0 or norm2 == 0:
return 0.0
return dot_product / (norm1 * norm2)
class TreeAgent(Agent): class TreeAgent(Agent):
""" """
A specialized Agent class that contains information about the system prompt's A specialized Agent class that contains information about the system prompt's
@ -137,6 +136,7 @@ class TreeAgent(Agent):
model_name: str = "gpt-4.1", model_name: str = "gpt-4.1",
agent_name: Optional[str] = None, agent_name: Optional[str] = None,
embedding_model_name: str = "text-embedding-ada-002", embedding_model_name: str = "text-embedding-ada-002",
verbose: bool = False,
*args, *args,
**kwargs, **kwargs,
): ):
@ -150,6 +150,7 @@ class TreeAgent(Agent):
model_name (str): Name of the language model to use model_name (str): Name of the language model to use
agent_name (Optional[str]): Alternative name for the agent agent_name (Optional[str]): Alternative name for the agent
embedding_model_name (str): Name of the embedding model to use embedding_model_name (str): Name of the embedding model to use
verbose (bool): Whether to enable verbose logging
*args: Additional positional arguments *args: Additional positional arguments
**kwargs: Additional keyword arguments **kwargs: Additional keyword arguments
""" """
@ -164,6 +165,7 @@ class TreeAgent(Agent):
**kwargs, **kwargs,
) )
self.embedding_model_name = embedding_model_name self.embedding_model_name = embedding_model_name
self.verbose = verbose
# Generate system prompt embedding using litellm # Generate system prompt embedding using litellm
if system_prompt: if system_prompt:
@ -195,7 +197,8 @@ class TreeAgent(Agent):
response = embedding( response = embedding(
model=self.embedding_model_name, input=[text] model=self.embedding_model_name, input=[text]
) )
logger.info(f"Embedding type: {type(response)}") if self.verbose:
logger.info(f"Embedding type: {type(response)}")
# print(response) # print(response)
# Handle different response structures from litellm # Handle different response structures from litellm
if hasattr(response, "data") and response.data: if hasattr(response, "data") and response.data:
@ -207,17 +210,20 @@ class TreeAgent(Agent):
): ):
return response.data[0]["embedding"] return response.data[0]["embedding"]
else: else:
logger.error( if self.verbose:
f"Unexpected response structure: {response.data[0]}" logger.error(
) f"Unexpected response structure: {response.data[0]}"
)
return [0.0] * 1536 return [0.0] * 1536
else: else:
logger.error( if self.verbose:
f"Unexpected response structure: {response}" logger.error(
) f"Unexpected response structure: {response}"
)
return [0.0] * 1536 return [0.0] * 1536
except Exception as e: except Exception as e:
logger.error(f"Error getting embedding: {e}") if self.verbose:
logger.error(f"Error getting embedding: {e}")
# Return a zero vector as fallback # Return a zero vector as fallback
return [0.0] * 1536 # Default OpenAI embedding dimension return [0.0] * 1536 # Default OpenAI embedding dimension
@ -264,20 +270,24 @@ class TreeAgent(Agent):
input_log = AgentLogInput( input_log = AgentLogInput(
agent_name=self.agent_name, agent_name=self.agent_name,
task=task, task=task,
timestamp=datetime.now(), timestamp=datetime.now(timezone.utc),
) )
logger.info(f"Running task on {self.agent_name}: {task}") if self.verbose:
logger.debug(f"Input Log: {input_log.json()}") logger.info(f"Running task on {self.agent_name}: {task}")
logger.debug(f"Input Log: {input_log.json()}")
result = self.run(task=task, img=img, *args, **kwargs) result = self.run(task=task, img=img, *args, **kwargs)
output_log = AgentLogOutput( output_log = AgentLogOutput(
agent_name=self.agent_name, agent_name=self.agent_name,
result=result, result=result,
timestamp=datetime.now(), timestamp=datetime.now(timezone.utc),
) )
logger.info(f"Task result from {self.agent_name}: {result}") if self.verbose:
logger.debug(f"Output Log: {output_log.json()}") logger.info(
f"Task result from {self.agent_name}: {result}"
)
logger.debug(f"Output Log: {output_log.json()}")
return result return result
@ -306,25 +316,36 @@ class TreeAgent(Agent):
similarity = cosine_similarity( similarity = cosine_similarity(
self.system_prompt_embedding, task_embedding self.system_prompt_embedding, task_embedding
) )
logger.info( if self.verbose:
f"Semantic similarity between task and {self.agent_name}: {similarity:.2f}" logger.info(
) f"Semantic similarity between task and {self.agent_name}: {similarity:.2f}"
)
return similarity >= threshold return similarity >= threshold
return True # Return True if keyword match is found return True # Return True if keyword match is found
class Tree: class Tree:
def __init__(self, tree_name: str, agents: List[TreeAgent]): def __init__(
self,
tree_name: str,
agents: List[TreeAgent],
verbose: bool = False,
):
""" """
Initializes a tree of agents. Initializes a tree of agents.
Args: Args:
tree_name (str): The name of the tree. tree_name (str): The name of the tree.
agents (List[TreeAgent]): A list of agents in the tree. agents (List[TreeAgent]): A list of agents in the tree.
verbose (bool): Whether to enable verbose logging
""" """
self.tree_name = tree_name self.tree_name = tree_name
self.agents = agents self.agents = agents
self.verbose = verbose
# Pass verbose to all agents
for agent in self.agents:
agent.verbose = verbose
self.calculate_agent_distances() self.calculate_agent_distances()
def calculate_agent_distances(self): def calculate_agent_distances(self):
@ -334,9 +355,10 @@ class Tree:
This method computes the semantic distance between consecutive agents using their system prompt This method computes the semantic distance between consecutive agents using their system prompt
embeddings and sorts the agents by distance for optimal task routing. embeddings and sorts the agents by distance for optimal task routing.
""" """
logger.info( if self.verbose:
f"Calculating distances between agents in tree '{self.tree_name}'" logger.info(
) f"Calculating distances between agents in tree '{self.tree_name}'"
)
for i, agent in enumerate(self.agents): for i, agent in enumerate(self.agents):
if i > 0: if i > 0:
agent.distance = agent.calculate_distance( agent.distance = agent.calculate_distance(
@ -359,15 +381,17 @@ class Tree:
Returns: Returns:
Optional[TreeAgent]: The most relevant agent, or None if no match found. Optional[TreeAgent]: The most relevant agent, or None if no match found.
""" """
logger.info( if self.verbose:
f"Searching relevant agent in tree '{self.tree_name}' for task: {task}" logger.info(
) f"Searching relevant agent in tree '{self.tree_name}' for task: {task}"
)
for agent in self.agents: for agent in self.agents:
if agent.is_relevant_for_task(task): if agent.is_relevant_for_task(task):
return agent return agent
logger.warning( if self.verbose:
f"No relevant agent found in tree '{self.tree_name}' for task: {task}" logger.warning(
) f"No relevant agent found in tree '{self.tree_name}' for task: {task}"
)
return None return None
def log_tree_execution( def log_tree_execution(
@ -380,13 +404,14 @@ class Tree:
tree_name=self.tree_name, tree_name=self.tree_name,
task=task, task=task,
selected_agent=selected_agent.agent_name, selected_agent=selected_agent.agent_name,
timestamp=datetime.now(), timestamp=datetime.now(timezone.utc),
result=result, result=result,
) )
logger.info( if self.verbose:
f"Tree '{self.tree_name}' executed task with agent '{selected_agent.agent_name}'" logger.info(
) f"Tree '{self.tree_name}' executed task with agent '{selected_agent.agent_name}'"
logger.debug(f"Tree Log: {tree_log.json()}") )
logger.debug(f"Tree Log: {tree_log.json()}")
class ForestSwarm: class ForestSwarm:
@ -397,6 +422,7 @@ class ForestSwarm:
trees: List[Tree] = [], trees: List[Tree] = [],
shared_memory: Any = None, shared_memory: Any = None,
rules: str = None, rules: str = None,
verbose: bool = False,
*args, *args,
**kwargs, **kwargs,
): ):
@ -409,6 +435,7 @@ class ForestSwarm:
trees (List[Tree]): A list of trees in the structure trees (List[Tree]): A list of trees in the structure
shared_memory (Any): Shared memory object for inter-tree communication shared_memory (Any): Shared memory object for inter-tree communication
rules (str): Rules governing the forest swarm behavior rules (str): Rules governing the forest swarm behavior
verbose (bool): Whether to enable verbose logging
*args: Additional positional arguments *args: Additional positional arguments
**kwargs: Additional keyword arguments **kwargs: Additional keyword arguments
""" """
@ -416,10 +443,13 @@ class ForestSwarm:
self.description = description self.description = description
self.trees = trees self.trees = trees
self.shared_memory = shared_memory self.shared_memory = shared_memory
self.verbose = verbose
# Pass verbose to all trees
for tree in self.trees:
tree.verbose = verbose
self.save_file_path = f"forest_swarm_{uuid.uuid4().hex}.json" self.save_file_path = f"forest_swarm_{uuid.uuid4().hex}.json"
self.conversation = Conversation( self.conversation = Conversation(
time_enabled=False, time_enabled=False,
auto_save=True,
save_filepath=self.save_file_path, save_filepath=self.save_file_path,
rules=rules, rules=rules,
) )
@ -434,13 +464,15 @@ class ForestSwarm:
Returns: Returns:
Optional[Tree]: The most relevant tree, or None if no match found Optional[Tree]: The most relevant tree, or None if no match found
""" """
logger.info( if self.verbose:
f"Searching for the most relevant tree for task: {task}" logger.info(
) f"Searching for the most relevant tree for task: {task}"
)
for tree in self.trees: for tree in self.trees:
if tree.find_relevant_agent(task): if tree.find_relevant_agent(task):
return tree return tree
logger.warning(f"No relevant tree found for task: {task}") if self.verbose:
logger.warning(f"No relevant tree found for task: {task}")
return None return None
def run(self, task: str, img: str = None, *args, **kwargs) -> Any: def run(self, task: str, img: str = None, *args, **kwargs) -> Any:
@ -457,9 +489,10 @@ class ForestSwarm:
Any: The result of the task after it has been processed by the agents Any: The result of the task after it has been processed by the agents
""" """
try: try:
logger.info( if self.verbose:
f"Running task across MultiAgentTreeStructure: {task}" logger.info(
) f"Running task across MultiAgentTreeStructure: {task}"
)
relevant_tree = self.find_relevant_tree(task) relevant_tree = self.find_relevant_tree(task)
if relevant_tree: if relevant_tree:
agent = relevant_tree.find_relevant_agent(task) agent = relevant_tree.find_relevant_agent(task)
@ -472,14 +505,32 @@ class ForestSwarm:
) )
return result return result
else: else:
logger.error( if self.verbose:
"Task could not be completed: No relevant agent or tree found." logger.error(
) "Task could not be completed: No relevant agent or tree found."
)
return "No relevant agent found to handle this task." return "No relevant agent found to handle this task."
except Exception as error: except Exception as error:
logger.error( if self.verbose:
f"Error detected in the ForestSwarm, check your inputs and try again ;) {error}" logger.error(
) f"Error detected in the ForestSwarm, check your inputs and try again ;) {error}"
)
def batched_run(
self,
tasks: List[str],
*args,
**kwargs,
) -> List[Any]:
"""
Execute the given tasks by finding the most relevant tree and agent within that tree.
Args:
tasks: List[str]: The tasks to be executed
*args: Additional positional arguments
**kwargs: Additional keyword arguments
"""
return [self.run(task, *args, **kwargs) for task in tasks]
# # Example Usage: # # Example Usage:

@ -64,6 +64,7 @@ class MCPExecutionError(MCPError):
######################################################## ########################################################
def transform_mcp_tool_to_openai_tool( def transform_mcp_tool_to_openai_tool(
mcp_tool: MCPTool, mcp_tool: MCPTool,
verbose: bool = False,
) -> ChatCompletionToolParam: ) -> ChatCompletionToolParam:
""" """
Convert an MCP tool to an OpenAI tool. Convert an MCP tool to an OpenAI tool.
@ -72,9 +73,11 @@ def transform_mcp_tool_to_openai_tool(
Returns: Returns:
ChatCompletionToolParam: The OpenAI-compatible tool parameter. ChatCompletionToolParam: The OpenAI-compatible tool parameter.
""" """
logger.info( if verbose:
f"Transforming MCP tool '{mcp_tool.name}' to OpenAI tool format." logger.info(
) f"Transforming MCP tool '{mcp_tool.name}' to OpenAI tool format."
)
return ChatCompletionToolParam( return ChatCompletionToolParam(
type="function", type="function",
function=FunctionDefinition( function=FunctionDefinition(
@ -529,12 +532,15 @@ def get_tools_for_multiple_mcp_servers(
logger.info( logger.info(
f"get_tools_for_multiple_mcp_servers called for {len(urls)} urls." f"get_tools_for_multiple_mcp_servers called for {len(urls)} urls."
) )
tools = [] tools = []
( (
min(32, os.cpu_count() + 4) min(32, os.cpu_count() + 4)
if max_workers is None if max_workers is None
else max_workers else max_workers
) )
with ThreadPoolExecutor(max_workers=max_workers) as executor: with ThreadPoolExecutor(max_workers=max_workers) as executor:
if exists(connections): if exists(connections):
future_to_url = { future_to_url = {

Loading…
Cancel
Save