added agent_loader

pull/1022/head
harshalmore31 3 weeks ago
parent 5be0ab609e
commit dd2b0c2a3c

@ -0,0 +1,165 @@
"""
AgentLoader Example: Research Team Collaboration
===============================================
This example demonstrates using the AgentLoader to create a research team
from markdown files and orchestrate them in a sequential workflow.
"""
import os
import sys
import tempfile
from pathlib import Path
# Add local swarms to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
from swarms.structs.agent import Agent
from swarms.structs.sequential_workflow import SequentialWorkflow
from swarms.utils.agent_loader import AgentLoader
def create_research_agents():
"""Create markdown files for research team agents"""
market_researcher = """| name | description | model |
|------|-------------|-------|
| market-researcher | Expert in market analysis and competitive intelligence | gpt-4 |
## Focus Areas
- Market size and growth analysis
- Competitive landscape assessment
- Consumer behavior patterns
- Industry trend identification
## Approach
1. Gather comprehensive market data
2. Analyze quantitative and qualitative indicators
3. Identify key market drivers and barriers
4. Evaluate competitive positioning
5. Assess market opportunities and threats
## Output
- Market analysis reports with key metrics
- Competitive intelligence briefings
- Market opportunity assessments
- Consumer behavior insights
"""
financial_analyst = """| name | description | model |
|------|-------------|-------|
| financial-analyst | Specialist in financial modeling and investment analysis | gpt-4 |
## Focus Areas
- Financial statement analysis
- Valuation modeling techniques
- Investment risk assessment
- Cash flow projections
## Approach
1. Conduct thorough financial analysis
2. Build comprehensive financial models
3. Perform multiple valuation methods
4. Assess financial risks and sensitivities
5. Provide investment recommendations
## Output
- Financial analysis reports
- Valuation models with scenarios
- Investment recommendation memos
- Risk assessment matrices
"""
industry_expert = """| name | description | model |
|------|-------------|-------|
| industry-expert | Domain specialist with deep industry knowledge | gpt-4 |
## Focus Areas
- Industry structure and dynamics
- Regulatory environment analysis
- Technology trends and disruptions
- Supply chain analysis
## Approach
1. Map industry structure and stakeholders
2. Analyze regulatory framework
3. Identify technology trends
4. Evaluate supply chain dynamics
5. Assess competitive positioning
## Output
- Industry landscape reports
- Regulatory compliance assessments
- Technology trend analysis
- Strategic positioning recommendations
"""
return {
"market_researcher.md": market_researcher,
"financial_analyst.md": financial_analyst,
"industry_expert.md": industry_expert
}
def main():
"""Main execution function"""
temp_dir = tempfile.mkdtemp()
try:
# Create markdown files
agent_definitions = create_research_agents()
file_paths = []
for filename, content in agent_definitions.items():
file_path = os.path.join(temp_dir, filename)
with open(file_path, 'w', encoding='utf-8') as f:
f.write(content)
file_paths.append(file_path)
# Load agents using AgentLoader
loader = AgentLoader()
agents = loader.load_multiple_agents(
file_paths,
max_loops=1,
verbose=False
)
print(f"Loaded {len(agents)} agents")
for i, agent in enumerate(agents):
print(f"Agent {i}: {agent.agent_name} - LLM: {hasattr(agent, 'llm')}")
# Create sequential workflow
research_workflow = SequentialWorkflow(
agents=agents,
max_loops=1,
)
# Define research task
task = """
Analyze the AI-powered healthcare diagnostics market for a potential $50M investment.
Focus on:
1. Market size, growth, and key drivers
2. Competitive landscape and major players
3. Financial viability and investment metrics
4. Industry dynamics and regulatory factors
Provide strategic recommendations for market entry.
"""
# Execute workflow
result = research_workflow.run(task)
return result
finally:
# Cleanup
for file_path in file_paths:
if os.path.exists(file_path):
os.remove(file_path)
os.rmdir(temp_dir)
if __name__ == "__main__":
result = main()
print("Research Analysis Complete:")
print("-" * 50)
print(result)

@ -0,0 +1,353 @@
# AgentLoader - Load Agents from Markdown Files
The `AgentLoader` is a powerful utility for creating Swarms agents from markdown files. It supports both single and multiple markdown file loading, providing a flexible way to define and deploy agents using a structured markdown format.
## Overview
The AgentLoader enables you to:
- Load single agents from markdown files
- Load multiple agents from directories or file lists
- Parse structured markdown content into agent configurations
- Maintain backwards compatibility with existing agent systems
- Provide comprehensive error handling and validation
## Installation
The AgentLoader is included with the Swarms framework:
```python
from swarms.utils import AgentLoader, load_agent_from_markdown, load_agents_from_markdown
```
## Markdown Format
The AgentLoader expects markdown files to follow a specific structure:
### Required Table Header
```markdown
| name | description | model |
|------|-------------|-------|
| agent-name | Brief description of the agent | gpt-4 |
```
### Optional Sections
```markdown
## Focus Areas
- Key responsibility area 1
- Key responsibility area 2
- Key responsibility area 3
## Approach
1. First step in methodology
2. Second step in methodology
3. Third step in methodology
## Output
- Expected deliverable 1
- Expected deliverable 2
- Expected deliverable 3
```
## Quick Start
### Loading a Single Agent
```python
from swarms.utils import load_agent_from_markdown
# Load agent from markdown file
agent = load_agent_from_markdown(
file_path="path/to/agent.md"
)
# Use the agent
response = agent.run("What are your capabilities?")
print(response)
```
### Loading Multiple Agents
```python
from swarms.utils import load_agents_from_markdown
# Load all agents from directory
agents = load_agents_from_markdown(
file_paths="./agents_directory/"
)
# Load agents from specific files
agents = load_agents_from_markdown(
file_paths=["agent1.md", "agent2.md", "agent3.md"]
)
print(f"Loaded {len(agents)} agents")
```
## Class-Based Usage
### AgentLoader Class
For more advanced usage, use the `AgentLoader` class directly:
```python
from swarms.utils import AgentLoader
# Initialize loader
loader = AgentLoader()
# Load single agent
agent = loader.load_single_agent("path/to/agent.md")
# Load multiple agents
agents = loader.load_multiple_agents("./agents_directory/")
# Parse markdown file without creating agent
config = loader.parse_markdown_file("path/to/agent.md")
print(config.name, config.description)
```
## Configuration Options
You can override default configuration when loading agents:
```python
agent = load_agent_from_markdown(
file_path="agent.md",
max_loops=5,
verbose=True,
dashboard=True,
autosave=False,
context_length=200000
)
```
### Available Configuration Parameters
- `max_loops` (int): Maximum number of reasoning loops (default: 1)
- `autosave` (bool): Enable automatic state saving (default: True)
- `dashboard` (bool): Enable dashboard monitoring (default: False)
- `verbose` (bool): Enable verbose logging (default: False)
- `dynamic_temperature_enabled` (bool): Enable dynamic temperature (default: False)
- `saved_state_path` (str): Path for saving agent state
- `user_name` (str): User identifier (default: "default_user")
- `retry_attempts` (int): Number of retry attempts (default: 3)
- `context_length` (int): Maximum context length (default: 100000)
- `return_step_meta` (bool): Return step metadata (default: False)
- `output_type` (str): Output format type (default: "str")
- `auto_generate_prompt` (bool): Auto-generate prompts (default: False)
- `artifacts_on` (bool): Enable artifacts (default: False)
## Complete Example
### Example Markdown File (performance-engineer.md)
```markdown
| name | description | model |
|------|-------------|-------|
| performance-engineer | Optimize application performance and identify bottlenecks | gpt-4 |
## Focus Areas
- Application profiling and performance analysis
- Database optimization and query tuning
- Memory and CPU usage optimization
- Load testing and capacity planning
- Infrastructure scaling recommendations
## Approach
1. Analyze application architecture and identify potential bottlenecks
2. Implement comprehensive monitoring and logging systems
3. Conduct performance testing under various load conditions
4. Profile memory usage and optimize resource consumption
5. Provide actionable recommendations with implementation guides
## Output
- Detailed performance analysis reports with metrics
- Optimized code recommendations and examples
- Infrastructure scaling and architecture suggestions
- Monitoring and alerting configuration guidelines
- Load testing results and capacity planning documents
```
### Loading and Using the Agent
```python
from swarms.utils import load_agent_from_markdown
from swarms.utils.litellm_wrapper import LiteLLM
# Initialize model
model = LiteLLM(model_name="gpt-4")
# Load the performance engineer agent
agent = load_agent_from_markdown(
file_path="performance-engineer.md",
model=model,
max_loops=3,
verbose=True
)
# Use the agent
task = """
Analyze the performance of a web application that handles 10,000 concurrent users
but is experiencing slow response times averaging 3 seconds. The application uses
a PostgreSQL database and is deployed on AWS with 4 EC2 instances behind a load balancer.
"""
analysis = agent.run(task)
print(f"Performance Analysis:\n{analysis}")
```
## Error Handling
The AgentLoader provides comprehensive error handling:
```python
from swarms.utils import AgentLoader
loader = AgentLoader()
try:
# This will raise FileNotFoundError
agent = loader.load_single_agent("nonexistent.md")
except FileNotFoundError as e:
print(f"File not found: {e}")
try:
# This will handle parsing errors gracefully
agents = loader.load_multiple_agents("./invalid_directory/")
print(f"Successfully loaded {len(agents)} agents")
except Exception as e:
print(f"Error loading agents: {e}")
```
## Advanced Features
### Custom System Prompt Building
The AgentLoader automatically builds comprehensive system prompts from the markdown structure:
```python
loader = AgentLoader()
config = loader.parse_markdown_file("agent.md")
# The system prompt includes:
# - Role description from the table
# - Focus areas as bullet points
# - Approach as numbered steps
# - Expected outputs as deliverables
print("Generated System Prompt:")
print(config.system_prompt)
```
### Batch Processing
Process multiple agent files efficiently:
```python
import os
from pathlib import Path
from swarms.utils import AgentLoader
loader = AgentLoader()
# Find all markdown files in a directory
agent_dir = Path("./agents")
md_files = list(agent_dir.glob("*.md"))
# Load all agents
agents = []
for file_path in md_files:
try:
agent = loader.load_single_agent(str(file_path))
agents.append(agent)
print(f"✓ Loaded: {agent.agent_name}")
except Exception as e:
print(f"✗ Failed to load {file_path}: {e}")
print(f"\nSuccessfully loaded {len(agents)} agents")
```
## Integration with Swarms
The loaded agents are fully compatible with Swarms orchestration systems:
```python
from swarms.utils import load_agents_from_markdown
from swarms.structs import SequentialWorkflow
# Load multiple specialized agents
agents = load_agents_from_markdown("./specialist_agents/")
# Create a sequential workflow
workflow = SequentialWorkflow(
agents=agents,
max_loops=1
)
# Execute complex task across multiple agents
result = workflow.run("Conduct a comprehensive system audit")
```
## Best Practices
1. **Consistent Naming**: Use clear, descriptive agent names
2. **Detailed Descriptions**: Provide comprehensive role descriptions
3. **Structured Sections**: Use the optional sections to define agent behavior
4. **Error Handling**: Always wrap agent loading in try-catch blocks
5. **Model Selection**: Choose appropriate models based on agent complexity
6. **Configuration**: Override defaults when specific behavior is needed
## Backwards Compatibility
The AgentLoader maintains full backwards compatibility with:
- Claude Code sub-agents markdown format
- Existing swarms agent creation patterns
- Legacy configuration systems
- Current workflow orchestration
## API Reference
### AgentLoader Class
```python
class AgentLoader:
def __init__(self, model: Optional[LiteLLM] = None)
def parse_markdown_file(self, file_path: str) -> MarkdownAgentConfig
def load_single_agent(self, file_path: str, **kwargs) -> Agent
def load_multiple_agents(self, file_paths: Union[str, List[str]], **kwargs) -> List[Agent]
```
### Convenience Functions
```python
def load_agent_from_markdown(file_path: str, model: Optional[LiteLLM] = None, **kwargs) -> Agent
def load_agents_from_markdown(file_paths: Union[str, List[str]], model: Optional[LiteLLM] = None, **kwargs) -> List[Agent]
```
### Configuration Model
```python
class MarkdownAgentConfig(BaseModel):
name: str
description: str
model_name: Optional[str] = "gpt-4"
system_prompt: str
focus_areas: Optional[List[str]] = []
approach: Optional[List[str]] = []
output: Optional[List[str]] = []
# ... additional configuration fields
```
## Examples Repository
Find more examples in the Swarms repository:
- `examples/agents_loader_example.py` - Complete usage demonstration
- `test_agent_loader.py` - Test suite with validation examples
- `examples/single_agent/utils/markdown_agent.py` - Markdown agent utilities
## Support
For questions and support:
- GitHub Issues: [https://github.com/kyegomez/swarms/issues](https://github.com/kyegomez/swarms/issues)
- Documentation: [https://docs.swarms.world](https://docs.swarms.world)
- Community: Join our Discord for real-time support

@ -0,0 +1,127 @@
"""
Example demonstrating the AgentLoader for loading agents from markdown files.
This example shows:
1. Loading a single agent from a markdown file
2. Loading multiple agents from markdown files
3. Using the convenience functions
4. Error handling and validation
"""
import os
from swarms.utils.agent_loader import AgentLoader, load_agent_from_markdown, load_agents_from_markdown
def main():
# Initialize the loader
loader = AgentLoader()
print("=== AgentLoader Demo ===")
# Example 1: Create a sample markdown file for testing
sample_md = """| name | description | model |
|------|-------------|-------|
| performance-engineer | Optimize application performance and identify bottlenecks | gpt-4 |
## Focus Areas
- Application profiling and performance analysis
- Database optimization and query tuning
- Memory and CPU usage optimization
- Load testing and capacity planning
## Approach
1. Analyze application architecture and identify potential bottlenecks
2. Implement comprehensive monitoring and logging
3. Conduct performance testing under various load conditions
4. Optimize critical paths and resource usage
5. Document findings and provide actionable recommendations
## Output
- Performance analysis reports with specific metrics
- Optimized code recommendations
- Infrastructure scaling suggestions
- Monitoring and alerting setup guidelines
"""
# Create sample markdown file
sample_file = "sample_agent.md"
with open(sample_file, 'w') as f:
f.write(sample_md)
try:
# Example 2: Load single agent using class method
print("\\n1. Loading single agent using AgentLoader class:")
agent = loader.load_single_agent(sample_file)
print(f" Loaded agent: {agent.agent_name}")
print(f" System prompt preview: {agent.system_prompt[:100]}...")
# Example 3: Load single agent using convenience function
print("\\n2. Loading single agent using convenience function:")
agent2 = load_agent_from_markdown(sample_file)
print(f" Loaded agent: {agent2.agent_name}")
# Example 4: Load multiple agents (from directory or list)
print("\\n3. Loading multiple agents:")
# Create another sample file
sample_md2 = """| name | description | model |
|------|-------------|-------|
| security-analyst | Analyze and improve system security | gpt-4 |
## Focus Areas
- Security vulnerability assessment
- Code security review
- Infrastructure hardening
## Approach
1. Conduct thorough security audits
2. Identify potential vulnerabilities
3. Recommend security improvements
## Output
- Security assessment reports
- Vulnerability remediation plans
- Security best practices documentation
"""
sample_file2 = "security_agent.md"
with open(sample_file2, 'w') as f:
f.write(sample_md2)
# Load multiple agents from list
agents = loader.load_multiple_agents([sample_file, sample_file2])
print(f" Loaded {len(agents)} agents:")
for agent in agents:
print(f" - {agent.agent_name}")
# Example 5: Load agents from directory (current directory)
print("\\n4. Loading agents from current directory:")
current_dir_agents = load_agents_from_markdown(".")
print(f" Found {len(current_dir_agents)} agents in current directory")
# Example 6: Demonstrate error handling
print("\\n5. Error handling demo:")
try:
loader.load_single_agent("nonexistent.md")
except FileNotFoundError as e:
print(f" Caught expected error: {e}")
# Example 7: Test agent functionality
print("\\n6. Testing loaded agent functionality:")
test_agent = agents[0]
response = test_agent.run("What are the key steps for performance optimization?")
print(f" Agent response preview: {str(response)[:150]}...")
except Exception as e:
print(f"Error during demo: {e}")
finally:
# Cleanup sample files
for file in [sample_file, sample_file2]:
if os.path.exists(file):
os.remove(file)
print("\\n Cleaned up sample files")
print("\\n=== Demo Complete ===")
if __name__ == "__main__":
main()

@ -0,0 +1,140 @@
"""
Simple AgentLoader Demo
=======================
A working demonstration of how to create agents from markdown-like definitions
and use them in workflows.
"""
import os
import tempfile
from pathlib import Path
import sys
# Add local swarms to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
from swarms.structs.agent import Agent
from swarms.structs.sequential_workflow import SequentialWorkflow
def create_agents_from_configs():
"""Create agents from configuration dictionaries (simulating markdown parsing)"""
# These would normally come from parsing markdown files
agent_configs = [
{
"name": "market-researcher",
"description": "Expert in market analysis and competitive intelligence",
"system_prompt": """You are a market research specialist. Your expertise includes:
Focus Areas:
- Market size and growth analysis
- Competitive landscape assessment
- Consumer behavior patterns
- Industry trend identification
Approach:
1. Gather comprehensive market data
2. Analyze quantitative and qualitative indicators
3. Identify key market drivers and barriers
4. Evaluate competitive positioning
5. Assess market opportunities and threats
Provide detailed market analysis reports with key metrics and actionable insights.""",
"model": "gpt-4"
},
{
"name": "financial-analyst",
"description": "Specialist in financial modeling and investment analysis",
"system_prompt": """You are a financial analysis expert. Your responsibilities include:
Focus Areas:
- Financial statement analysis
- Valuation modeling techniques
- Investment risk assessment
- Cash flow projections
Approach:
1. Conduct thorough financial analysis
2. Build comprehensive financial models
3. Perform multiple valuation methods
4. Assess financial risks and sensitivities
5. Provide investment recommendations
Generate detailed financial reports with valuation models and risk assessments.""",
"model": "gpt-4"
},
{
"name": "industry-expert",
"description": "Domain specialist with deep industry knowledge",
"system_prompt": """You are an industry analysis expert. Your focus areas include:
Focus Areas:
- Industry structure and dynamics
- Regulatory environment analysis
- Technology trends and disruptions
- Supply chain analysis
Approach:
1. Map industry structure and stakeholders
2. Analyze regulatory framework
3. Identify technology trends
4. Evaluate supply chain dynamics
5. Assess competitive positioning
Provide comprehensive industry landscape reports with strategic recommendations.""",
"model": "gpt-4"
}
]
agents = []
for config in agent_configs:
agent = Agent(
agent_name=config["name"],
system_prompt=config["system_prompt"],
model_name=config["model"],
max_loops=1,
verbose=False
)
agents.append(agent)
print(f"Created agent: {agent.agent_name}")
return agents
def main():
"""Main execution function"""
# Create agents
agents = create_agents_from_configs()
# Create sequential workflow
research_workflow = SequentialWorkflow(
agents=agents,
max_loops=1,
)
# Define research task
task = """
Analyze the AI-powered healthcare diagnostics market for a potential $50M investment.
Focus on:
1. Market size, growth projections, and key drivers
2. Competitive landscape and major players
3. Financial viability and investment attractiveness
4. Industry dynamics and regulatory considerations
Provide strategic recommendations for market entry.
"""
print("Executing research workflow...")
print("=" * 50)
# Execute workflow
result = research_workflow.run(task)
print("\nResearch Analysis Complete:")
print("-" * 50)
print(result)
if __name__ == "__main__":
main()

@ -0,0 +1,378 @@
import os
import re
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from pydantic import BaseModel, Field, field_validator
from loguru import logger
from swarms.structs.agent import Agent
class MarkdownAgentConfig(BaseModel):
"""Configuration model for agents loaded from markdown files."""
name: str
description: str
model_name: Optional[str] = "gpt-4"
system_prompt: str
focus_areas: Optional[List[str]] = []
approach: Optional[List[str]] = []
output: Optional[List[str]] = []
max_loops: int = Field(default=1, ge=1)
autosave: bool = False
dashboard: bool = False
verbose: bool = False
dynamic_temperature_enabled: bool = False
saved_state_path: Optional[str] = None
user_name: str = "default_user"
retry_attempts: int = Field(default=3, ge=1)
context_length: int = Field(default=100000, ge=1000)
return_step_meta: bool = False
output_type: str = "str"
auto_generate_prompt: bool = False
artifacts_on: bool = False
artifacts_file_extension: str = ".md"
artifacts_output_path: str = ""
@field_validator("system_prompt")
@classmethod
def validate_system_prompt(cls, v):
if not v or not isinstance(v, str) or len(v.strip()) == 0:
raise ValueError("System prompt must be a non-empty string")
return v
class AgentLoader:
"""
Loader for creating agents from markdown files.
Supports both single markdown file and multiple markdown files.
Maintains backwards compatibility with claude code sub agents markdown format.
Features:
- Single markdown file loading
- Multiple markdown files loading (batch processing)
- Flexible markdown parsing
- Agent configuration extraction from markdown structure
- Error handling and validation
"""
def __init__(self):
"""
Initialize the AgentLoader.
"""
pass
def parse_markdown_table(self, content: str) -> Dict[str, str]:
"""
Parse markdown table to extract agent metadata.
Args:
content: Markdown content containing a table
Returns:
Dictionary with parsed table data
"""
table_data = {}
# Find markdown table pattern
table_pattern = r'\|([^|]+)\|([^|]+)\|([^|]+)\|'
lines = content.split('\n')
header_found = False
for line in lines:
if '|' in line and not header_found:
# Skip header separator line
if '---' in line:
header_found = True
continue
# Parse header
if 'name' in line.lower() and 'description' in line.lower():
continue
elif header_found and '|' in line:
# Parse data row
match = re.match(table_pattern, line)
if match:
table_data['name'] = match.group(1).strip()
table_data['description'] = match.group(2).strip()
table_data['model_name'] = match.group(3).strip()
break
return table_data
def extract_sections(self, content: str) -> Dict[str, List[str]]:
"""
Extract structured sections from markdown content.
Args:
content: Markdown content
Returns:
Dictionary with section names as keys and content lists as values
"""
sections = {}
current_section = None
current_content = []
lines = content.split('\n')
for line in lines:
# Check for headers (## Section Name)
if line.startswith('## '):
# Save previous section
if current_section:
sections[current_section.lower()] = current_content
# Start new section
current_section = line[3:].strip()
current_content = []
elif current_section and line.strip():
# Add content to current section
# Remove markdown list markers
clean_line = re.sub(r'^[-*+]\s*', '', line.strip())
clean_line = re.sub(r'^\d+\.\s*', '', clean_line)
if clean_line:
current_content.append(clean_line)
# Save last section
if current_section:
sections[current_section.lower()] = current_content
return sections
def build_system_prompt(self, config_data: Dict[str, Any]) -> str:
"""
Build comprehensive system prompt from parsed markdown data.
Args:
config_data: Dictionary containing parsed agent configuration
Returns:
Complete system prompt string
"""
prompt_parts = []
# Add description
if config_data.get('description'):
prompt_parts.append(f"Role: {config_data['description']}")
# Add focus areas
if config_data.get('focus_areas'):
prompt_parts.append("\nFocus Areas:")
for area in config_data['focus_areas']:
prompt_parts.append(f"- {area}")
# Add approach
if config_data.get('approach'):
prompt_parts.append("\nApproach:")
for i, step in enumerate(config_data['approach'], 1):
prompt_parts.append(f"{i}. {step}")
# Add expected output
if config_data.get('output'):
prompt_parts.append("\nExpected Output:")
for output in config_data['output']:
prompt_parts.append(f"- {output}")
return '\n'.join(prompt_parts)
def parse_markdown_file(self, file_path: str) -> MarkdownAgentConfig:
"""
Parse a single markdown file to extract agent configuration.
Args:
file_path: Path to markdown file
Returns:
MarkdownAgentConfig object with parsed configuration
Raises:
FileNotFoundError: If file doesn't exist
ValueError: If parsing fails
"""
if not os.path.exists(file_path):
raise FileNotFoundError(f"Markdown file {file_path} not found.")
try:
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()
# Parse table for basic metadata
table_data = self.parse_markdown_table(content)
# Extract sections
sections = self.extract_sections(content)
# Build configuration
config_data = {
'name': table_data.get('name', Path(file_path).stem),
'description': table_data.get('description', 'Agent loaded from markdown'),
'model_name': table_data.get('model_name', 'gpt-4'),
'focus_areas': sections.get('focus areas', []),
'approach': sections.get('approach', []),
'output': sections.get('output', []),
}
# Build system prompt
system_prompt = self.build_system_prompt(config_data)
config_data['system_prompt'] = system_prompt
logger.info(f"Successfully parsed markdown file: {file_path}")
return MarkdownAgentConfig(**config_data)
except Exception as e:
logger.error(f"Error parsing markdown file {file_path}: {str(e)}")
raise ValueError(f"Error parsing markdown file {file_path}: {str(e)}")
def load_agent_from_markdown(self, file_path: str, **kwargs) -> Agent:
"""
Load a single agent from a markdown file.
Args:
file_path: Path to markdown file
**kwargs: Additional arguments to override default configuration
Returns:
Configured Agent instance
"""
config = self.parse_markdown_file(file_path)
# Override with any provided kwargs
config_dict = config.model_dump()
config_dict.update(kwargs)
# Remove fields not needed for Agent creation
agent_fields = {
'agent_name': config_dict['name'],
'system_prompt': config_dict['system_prompt'],
'model_name': config_dict.get('model_name', 'gpt-4'),
# Don't pass llm explicitly - let Agent handle it internally
'max_loops': config_dict['max_loops'],
'autosave': config_dict['autosave'],
'dashboard': config_dict['dashboard'],
'verbose': config_dict['verbose'],
'dynamic_temperature_enabled': config_dict['dynamic_temperature_enabled'],
'saved_state_path': config_dict['saved_state_path'],
'user_name': config_dict['user_name'],
'retry_attempts': config_dict['retry_attempts'],
'context_length': config_dict['context_length'],
'return_step_meta': config_dict['return_step_meta'],
'output_type': config_dict['output_type'],
'auto_generate_prompt': config_dict['auto_generate_prompt'],
'artifacts_on': config_dict['artifacts_on'],
'artifacts_file_extension': config_dict['artifacts_file_extension'],
'artifacts_output_path': config_dict['artifacts_output_path'],
}
try:
logger.info(f"Creating agent '{config.name}' from {file_path}")
agent = Agent(**agent_fields)
logger.info(f"Successfully created agent '{config.name}' from {file_path}")
return agent
except Exception as e:
import traceback
logger.error(f"Error creating agent from {file_path}: {str(e)}")
logger.error(f"Traceback: {traceback.format_exc()}")
raise ValueError(f"Error creating agent from {file_path}: {str(e)}")
def load_agents_from_markdown(self, file_paths: Union[str, List[str]], **kwargs) -> List[Agent]:
"""
Load multiple agents from markdown files.
Args:
file_paths: Single file path, directory path, or list of file paths
**kwargs: Additional arguments to override default configuration
Returns:
List of configured Agent instances
"""
agents = []
paths_to_process = []
# Handle different input types
if isinstance(file_paths, str):
if os.path.isdir(file_paths):
# Directory - find all .md files
md_files = list(Path(file_paths).glob('*.md'))
paths_to_process = [str(f) for f in md_files]
elif os.path.isfile(file_paths):
# Single file
paths_to_process = [file_paths]
else:
raise FileNotFoundError(f"Path {file_paths} not found.")
elif isinstance(file_paths, list):
paths_to_process = file_paths
else:
raise ValueError("file_paths must be a string or list of strings")
# Process each file
for file_path in paths_to_process:
try:
agent = self.load_agent_from_markdown(file_path, **kwargs)
agents.append(agent)
except Exception as e:
logger.warning(f"Skipping {file_path} due to error: {str(e)}")
continue
logger.info(f"Successfully loaded {len(agents)} agents from markdown files")
return agents
def load_single_agent(self, file_path: str, **kwargs) -> Agent:
"""
Convenience method for loading a single agent.
Backwards compatible with claude code sub agents markdown.
Args:
file_path: Path to markdown file
**kwargs: Additional configuration overrides
Returns:
Configured Agent instance
"""
return self.load_agent_from_markdown(file_path, **kwargs)
def load_multiple_agents(self, file_paths: Union[str, List[str]], **kwargs) -> List[Agent]:
"""
Convenience method for loading multiple agents.
Backwards compatible with claude code sub agents markdown.
Args:
file_paths: Directory path or list of file paths
**kwargs: Additional configuration overrides
Returns:
List of configured Agent instances
"""
return self.load_agents_from_markdown(file_paths, **kwargs)
# Convenience functions for backwards compatibility
def load_agent_from_markdown(file_path: str, **kwargs) -> Agent:
"""
Load a single agent from a markdown file.
Args:
file_path: Path to markdown file
**kwargs: Additional configuration overrides
Returns:
Configured Agent instance
"""
loader = AgentLoader()
return loader.load_single_agent(file_path, **kwargs)
def load_agents_from_markdown(file_paths: Union[str, List[str]], **kwargs) -> List[Agent]:
"""
Load multiple agents from markdown files.
Args:
file_paths: Directory path or list of file paths
**kwargs: Additional configuration overrides
Returns:
List of configured Agent instances
"""
loader = AgentLoader()
return loader.load_multiple_agents(file_paths, **kwargs)

@ -0,0 +1,244 @@
"""
Test script for the AgentLoader functionality.
This tests the core functionality without requiring external models.
"""
import os
import tempfile
from pathlib import Path
import sys
# Add swarms to path for local testing
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
from swarms.utils.agent_loader import AgentLoader, MarkdownAgentConfig
def test_markdown_parsing():
"""Test markdown parsing functionality."""
print("Testing markdown parsing...")
# Create a sample markdown content
sample_content = """| name | description | model |
|------|-------------|-------|
| test-agent | A test agent for validation | gpt-4 |
## Focus Areas
- Testing functionality
- Validating implementation
- Ensuring compatibility
## Approach
1. Parse markdown structure
2. Extract configuration data
3. Validate parsed results
4. Create agent instance
## Output
- Test results
- Validation reports
- Configuration summary
"""
# Test parsing functionality
loader = AgentLoader()
# Test table parsing
table_data = loader.parse_markdown_table(sample_content)
assert table_data['name'] == 'test-agent'
assert table_data['description'] == 'A test agent for validation'
assert table_data['model_name'] == 'gpt-4'
print("[OK] Table parsing successful")
# Test section extraction
sections = loader.extract_sections(sample_content)
assert 'focus areas' in sections
assert len(sections['focus areas']) == 3
assert 'approach' in sections
assert len(sections['approach']) == 4
print("[OK] Section extraction successful")
# Test system prompt building
config_data = {
'description': table_data['description'],
'focus_areas': sections['focus areas'],
'approach': sections['approach'],
'output': sections.get('output', [])
}
system_prompt = loader.build_system_prompt(config_data)
assert 'Role:' in system_prompt
assert 'Focus Areas:' in system_prompt
assert 'Approach:' in system_prompt
print("[OK] System prompt building successful")
print("Markdown parsing tests passed!")
return True
def test_file_operations():
"""Test file loading operations."""
print("\\nTesting file operations...")
# Create temporary markdown file
sample_content = """| name | description | model |
|------|-------------|-------|
| file-test-agent | Agent created from file | gpt-4 |
## Focus Areas
- File processing
- Configuration validation
## Approach
1. Load from file
2. Parse content
3. Create configuration
## Output
- Loaded agent
- Configuration object
"""
with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
f.write(sample_content)
temp_file = f.name
try:
loader = AgentLoader()
# Test file parsing
config = loader.parse_markdown_file(temp_file)
assert isinstance(config, MarkdownAgentConfig)
assert config.name == 'file-test-agent'
assert config.description == 'Agent created from file'
print("[OK] File parsing successful")
# Test configuration validation
assert len(config.focus_areas) == 2
assert len(config.approach) == 3
assert config.system_prompt is not None
print("[OK] Configuration validation successful")
finally:
# Cleanup
if os.path.exists(temp_file):
os.remove(temp_file)
print("File operations tests passed!")
return True
def test_multiple_files():
"""Test loading multiple files."""
print("\\nTesting multiple file loading...")
# Create multiple temporary files
files = []
for i in range(3):
content = f"""| name | description | model |
|------|-------------|-------|
| agent-{i} | Test agent number {i} | gpt-4 |
## Focus Areas
- Multi-agent testing
- Batch processing
## Approach
1. Process multiple files
2. Create agent configurations
3. Return agent list
## Output
- Multiple agents
- Batch results
"""
temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False)
temp_file.write(content)
temp_file.close()
files.append(temp_file.name)
try:
loader = AgentLoader()
# Test parsing multiple files
configs = []
for file_path in files:
config = loader.parse_markdown_file(file_path)
configs.append(config)
assert len(configs) == 3
for i, config in enumerate(configs):
assert config.name == f'agent-{i}'
print("[OK] Multiple file parsing successful")
finally:
# Cleanup
for file_path in files:
if os.path.exists(file_path):
os.remove(file_path)
print("Multiple file tests passed!")
return True
def test_error_handling():
"""Test error handling scenarios."""
print("\\nTesting error handling...")
loader = AgentLoader()
# Test non-existent file
try:
loader.parse_markdown_file("nonexistent.md")
assert False, "Should have raised FileNotFoundError"
except FileNotFoundError:
print("[OK] FileNotFoundError handling successful")
# Test invalid markdown
with tempfile.NamedTemporaryFile(mode='w', suffix='.md', delete=False) as f:
f.write("Invalid markdown content without proper structure")
invalid_file = f.name
try:
# This should not raise an error, but should handle gracefully
config = loader.parse_markdown_file(invalid_file)
# Should have defaults
assert config.name is not None
print("[OK] Invalid markdown handling successful")
finally:
if os.path.exists(invalid_file):
os.remove(invalid_file)
print("Error handling tests passed!")
return True
def main():
"""Run all tests."""
print("=== AgentLoader Test Suite ===")
tests = [
test_markdown_parsing,
test_file_operations,
test_multiple_files,
test_error_handling
]
passed = 0
total = len(tests)
for test in tests:
try:
if test():
passed += 1
except Exception as e:
print(f"[FAIL] Test {test.__name__} failed: {e}")
print(f"\\n=== Results: {passed}/{total} tests passed ===")
if passed == total:
print("All tests passed!")
return True
else:
print("Some tests failed!")
return False
if __name__ == "__main__":
success = main()
exit(0 if success else 1)
Loading…
Cancel
Save