From dd2b0c2a3c6fcc66e0d34426e399d08807a45306 Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Sun, 10 Aug 2025 20:51:09 +0530 Subject: [PATCH 01/12] added agent_loader --- agent_loader_research_team.py | 165 ++++++++ docs/swarms/utils/agent_loader.md | 353 ++++++++++++++++ examples/agents_loader_example.py | 127 ++++++ .../multi_agent/simple_agent_loader_demo.py | 140 +++++++ swarms/utils/agent_loader.py | 378 ++++++++++++++++++ test_agent_loader.py | 244 +++++++++++ 6 files changed, 1407 insertions(+) create mode 100644 agent_loader_research_team.py create mode 100644 docs/swarms/utils/agent_loader.md create mode 100644 examples/agents_loader_example.py create mode 100644 examples/multi_agent/simple_agent_loader_demo.py create mode 100644 swarms/utils/agent_loader.py create mode 100644 test_agent_loader.py diff --git a/agent_loader_research_team.py b/agent_loader_research_team.py new file mode 100644 index 00000000..1ae02301 --- /dev/null +++ b/agent_loader_research_team.py @@ -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) \ No newline at end of file diff --git a/docs/swarms/utils/agent_loader.md b/docs/swarms/utils/agent_loader.md new file mode 100644 index 00000000..c3e1fd32 --- /dev/null +++ b/docs/swarms/utils/agent_loader.md @@ -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 \ No newline at end of file diff --git a/examples/agents_loader_example.py b/examples/agents_loader_example.py new file mode 100644 index 00000000..12359af6 --- /dev/null +++ b/examples/agents_loader_example.py @@ -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() \ No newline at end of file diff --git a/examples/multi_agent/simple_agent_loader_demo.py b/examples/multi_agent/simple_agent_loader_demo.py new file mode 100644 index 00000000..e78eae52 --- /dev/null +++ b/examples/multi_agent/simple_agent_loader_demo.py @@ -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() \ No newline at end of file diff --git a/swarms/utils/agent_loader.py b/swarms/utils/agent_loader.py new file mode 100644 index 00000000..7b918421 --- /dev/null +++ b/swarms/utils/agent_loader.py @@ -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) \ No newline at end of file diff --git a/test_agent_loader.py b/test_agent_loader.py new file mode 100644 index 00000000..3a02693a --- /dev/null +++ b/test_agent_loader.py @@ -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) \ No newline at end of file From 223d398a20ceddc54d47738c660ca31c0dc2b10e Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Sat, 16 Aug 2025 16:03:18 +0530 Subject: [PATCH 02/12] updated and fixed ! --- agent_loader_research_team.py | 165 --------- docs/swarms/utils/agent_loader.md | 168 ++++----- examples/agents_loader_example.py | 168 +++++---- .../multi_agent/simple_agent_loader_demo.py | 321 +++++++++++------- swarms/utils/agent_loader.py | 200 ++++------- test_agent_loader.py | 244 ------------- 6 files changed, 468 insertions(+), 798 deletions(-) delete mode 100644 agent_loader_research_team.py delete mode 100644 test_agent_loader.py diff --git a/agent_loader_research_team.py b/agent_loader_research_team.py deleted file mode 100644 index 1ae02301..00000000 --- a/agent_loader_research_team.py +++ /dev/null @@ -1,165 +0,0 @@ -""" -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) \ No newline at end of file diff --git a/docs/swarms/utils/agent_loader.md b/docs/swarms/utils/agent_loader.md index c3e1fd32..b8f1e94f 100644 --- a/docs/swarms/utils/agent_loader.md +++ b/docs/swarms/utils/agent_loader.md @@ -1,14 +1,14 @@ # 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. +The `AgentLoader` is a powerful utility for creating Swarms agents from markdown files using the Claude Code sub-agent format. It supports both single and multiple markdown file loading, providing a flexible way to define and deploy agents using YAML frontmatter configuration. ## Overview The AgentLoader enables you to: -- Load single agents from markdown files +- Load single agents from markdown files with YAML frontmatter - Load multiple agents from directories or file lists -- Parse structured markdown content into agent configurations -- Maintain backwards compatibility with existing agent systems +- Parse Claude Code sub-agent YAML frontmatter configurations +- Extract system prompts from markdown content - Provide comprehensive error handling and validation ## Installation @@ -21,32 +21,33 @@ from swarms.utils import AgentLoader, load_agent_from_markdown, load_agents_from ## Markdown Format -The AgentLoader expects markdown files to follow a specific structure: +The AgentLoader uses the Claude Code sub-agent YAML frontmatter format: -### Required Table Header ```markdown -| name | description | model | -|------|-------------|-------| -| agent-name | Brief description of the agent | gpt-4 | +--- +name: your-sub-agent-name +description: Description of when this subagent should be invoked +model_name: gpt-4 +temperature: 0.3 +max_loops: 2 +mcp_url: http://example.com/mcp # optional +--- + +Your subagent's system prompt goes here. This can be multiple paragraphs +and should clearly define the subagent's role, capabilities, and approach +to solving problems. + +Include specific instructions, best practices, and any constraints +the subagent should follow. ``` -### 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 -``` +**Schema Fields:** +- `name` (required): Your sub-agent name +- `description` (required): Description of when this subagent should be invoked +- `model_name` (optional): Name of model (defaults to random selection if not provided) +- `temperature` (optional): Float value for model temperature (0.0-2.0) +- `max_loops` (optional): Integer for maximum reasoning loops +- `mcp_url` (optional): MCP server URL if needed ## Quick Start @@ -55,13 +56,17 @@ The AgentLoader expects markdown files to follow a specific structure: ```python from swarms.utils import load_agent_from_markdown -# Load agent from markdown file +# Load Claude Code format agent (YAML frontmatter) agent = load_agent_from_markdown( - file_path="path/to/agent.md" + file_path="performance-engineer.md" # Uses YAML frontmatter format ) -# Use the agent -response = agent.run("What are your capabilities?") +# The agent automatically gets configured with: +# - Name, description from frontmatter +# - Temperature, max_loops, model settings +# - System prompt from content after frontmatter + +response = agent.run("Analyze application performance issues") print(response) ``` @@ -70,17 +75,23 @@ print(response) ```python from swarms.utils import load_agents_from_markdown -# Load all agents from directory +# Load all agents from directory (YAML frontmatter format) agents = load_agents_from_markdown( - file_paths="./agents_directory/" + file_paths="./agents_directory/" # Directory with Claude Code format files ) # Load agents from specific files agents = load_agents_from_markdown( - file_paths=["agent1.md", "agent2.md", "agent3.md"] + file_paths=[ + "performance-engineer.md", # Claude Code YAML format + "financial-analyst.md", # Claude Code YAML format + "security-analyst.md" # Claude Code YAML format + ] ) print(f"Loaded {len(agents)} agents") +for agent in agents: + print(f"- {agent.agent_name}: {getattr(agent, 'temperature', 'default temp')}") ``` ## Class-Based Usage @@ -139,61 +150,60 @@ agent = load_agent_from_markdown( ## Complete Example -### Example Markdown File (performance-engineer.md) +### Example: Claude Code Sub-Agent Format + +Create a 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 +--- +name: performance-engineer +description: Optimize application performance and identify bottlenecks +model_name: gpt-4 +temperature: 0.3 +max_loops: 2 +mcp_url: http://example.com/mcp +--- + +You are a Performance Engineer specializing in application optimization and scalability. + +Your role involves analyzing system performance, identifying bottlenecks, and implementing +solutions to improve efficiency and user experience. + +Key responsibilities: +- Profile applications to identify performance issues +- Optimize database queries and caching strategies +- Implement load testing and monitoring solutions +- Recommend infrastructure improvements +- Provide actionable optimization recommendations + +Always provide specific, measurable recommendations with implementation details. +Focus on both immediate wins and long-term architectural improvements. ``` ### 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 +# Load Claude Code format agent (YAML frontmatter) +performance_agent = load_agent_from_markdown( + file_path="performance-engineer.md" ) -# Use the agent +print(f"Agent: {performance_agent.agent_name}") +print(f"Temperature: {getattr(performance_agent, 'temperature', 'default')}") +print(f"Max loops: {performance_agent.max_loops}") +print(f"System prompt preview: {performance_agent.system_prompt[:100]}...") + +# Use the performance 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}") +# Note: Actual agent.run() would make API calls +print(f"\nTask for {performance_agent.agent_name}: {task[:100]}...") ``` ## Error Handling @@ -297,13 +307,6 @@ result = workflow.run("Conduct a comprehensive system audit") 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 @@ -331,10 +334,13 @@ class MarkdownAgentConfig(BaseModel): name: str description: str model_name: Optional[str] = "gpt-4" + temperature: Optional[float] = 0.1 # Model temperature (0.0-2.0) + mcp_url: Optional[str] = None # Optional MCP server URL system_prompt: str - focus_areas: Optional[List[str]] = [] - approach: Optional[List[str]] = [] - output: Optional[List[str]] = [] + max_loops: int = 1 + autosave: bool = False + dashboard: bool = False + verbose: bool = False # ... additional configuration fields ``` diff --git a/examples/agents_loader_example.py b/examples/agents_loader_example.py index 12359af6..f70e4435 100644 --- a/examples/agents_loader_example.py +++ b/examples/agents_loader_example.py @@ -17,106 +17,154 @@ def main(): 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 | + # Example 1: Create sample markdown files for testing - Claude Code format + + # Performance Engineer agent + performance_md = """--- +name: performance-engineer +description: Optimize application performance and identify bottlenecks +model_name: gpt-4 +temperature: 0.3 +max_loops: 2 +mcp_url: http://example.com/mcp +--- -## Focus Areas -- Application profiling and performance analysis -- Database optimization and query tuning -- Memory and CPU usage optimization -- Load testing and capacity planning +You are a Performance Engineer specializing in application optimization and scalability. -## 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 +Your role involves: +- Analyzing application architecture and identifying potential bottlenecks +- Implementing comprehensive monitoring and logging +- Conducting performance testing under various load conditions +- Optimizing critical paths and resource usage +- Documenting findings and providing actionable recommendations -## Output +Expected 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) + # Data Analyst agent + data_analyst_md = """--- +name: data-analyst +description: Analyze data and provide business insights +model_name: gpt-4 +temperature: 0.2 +max_loops: 1 +--- + +You are a Data Analyst specializing in extracting insights from complex datasets. + +Your responsibilities include: +- Collecting and cleaning data from various sources +- Performing exploratory data analysis and statistical modeling +- Creating compelling visualizations and interactive dashboards +- Applying statistical methods and machine learning techniques +- Presenting findings and actionable business recommendations + +Focus on providing data-driven insights that support strategic decision making. +""" + + # Create sample markdown files + performance_file = "performance_engineer.md" + data_file = "data_analyst.md" + + with open(performance_file, 'w') as f: + f.write(performance_md) + + with open(data_file, 'w') as f: + f.write(data_analyst_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 2: Load Performance Engineer agent + print("\\n1. Loading Performance Engineer agent (YAML frontmatter):") + perf_agent = loader.load_single_agent(performance_file) + print(f" Loaded agent: {perf_agent.agent_name}") + print(f" Model: {perf_agent.model_name}") + print(f" Temperature: {getattr(perf_agent, 'temperature', 'Not set')}") + print(f" Max loops: {perf_agent.max_loops}") + print(f" System prompt preview: {perf_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) + # Example 3: Load Data Analyst agent + print("\\n2. Loading Data Analyst agent:") + data_agent = loader.load_single_agent(data_file) + print(f" Loaded agent: {data_agent.agent_name}") + print(f" Temperature: {getattr(data_agent, 'temperature', 'Not set')}") + print(f" System prompt preview: {data_agent.system_prompt[:100]}...") + + # Example 4: Load single agent using convenience function + print("\\n3. Loading single agent using convenience function:") + agent2 = load_agent_from_markdown(performance_file) print(f" Loaded agent: {agent2.agent_name}") - # Example 4: Load multiple agents (from directory or list) - print("\\n3. Loading multiple agents:") + # Example 5: Load multiple agents (from directory or list) + print("\\n4. Loading multiple agents:") - # Create another sample file - sample_md2 = """| name | description | model | -|------|-------------|-------| -| security-analyst | Analyze and improve system security | gpt-4 | + # Create another sample file - Security Analyst + security_md = """--- +name: security-analyst +description: Analyze and improve system security +model_name: gpt-4 +temperature: 0.1 +max_loops: 3 +--- + +You are a Security Analyst specializing in cybersecurity assessment and protection. -## Focus Areas -- Security vulnerability assessment -- Code security review -- Infrastructure hardening +Your expertise includes: +- Conducting comprehensive security vulnerability assessments +- Performing detailed code security reviews and penetration testing +- Implementing robust infrastructure hardening measures +- Developing incident response and recovery procedures -## Approach -1. Conduct thorough security audits -2. Identify potential vulnerabilities -3. Recommend security improvements +Key methodology: +1. Conduct thorough security audits across all system components +2. Identify and classify potential vulnerabilities and threats +3. Recommend and implement security improvements and controls +4. Develop comprehensive security policies and best practices +5. Monitor and respond to security incidents -## Output -- Security assessment reports -- Vulnerability remediation plans -- Security best practices documentation +Provide detailed security reports with specific remediation steps and risk assessments. """ - sample_file2 = "security_agent.md" - with open(sample_file2, 'w') as f: - f.write(sample_md2) + security_file = "security_analyst.md" + with open(security_file, 'w') as f: + f.write(security_md) # Load multiple agents from list - agents = loader.load_multiple_agents([sample_file, sample_file2]) + agents = loader.load_multiple_agents([performance_file, data_file, security_file]) print(f" Loaded {len(agents)} agents:") for agent in agents: - print(f" - {agent.agent_name}") + temp_attr = getattr(agent, 'temperature', 'default') + print(f" - {agent.agent_name} (temp: {temp_attr})") - # Example 5: Load agents from directory (current directory) - print("\\n4. Loading agents from current directory:") + # Example 6: Load agents from directory (current directory) + print("\\n5. 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:") + # Example 7: Demonstrate error handling + print("\\n6. 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:") + # Example 8: Test agent functionality + print("\\n7. 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]}...") + print(f" Agent: {test_agent.agent_name}") + print(f" Temperature: {getattr(test_agent, 'temperature', 'default')}") + print(f" Max loops: {test_agent.max_loops}") + print(f" Ready for task execution") except Exception as e: print(f"Error during demo: {e}") finally: # Cleanup sample files - for file in [sample_file, sample_file2]: + for file in [performance_file, data_file, security_file]: if os.path.exists(file): os.remove(file) print("\\n Cleaned up sample files") diff --git a/examples/multi_agent/simple_agent_loader_demo.py b/examples/multi_agent/simple_agent_loader_demo.py index e78eae52..481a5aea 100644 --- a/examples/multi_agent/simple_agent_loader_demo.py +++ b/examples/multi_agent/simple_agent_loader_demo.py @@ -1,9 +1,15 @@ """ -Simple AgentLoader Demo -======================= +Simple AgentLoader Demo - Claude Code Format +============================================= -A working demonstration of how to create agents from markdown-like definitions -and use them in workflows. +A comprehensive demonstration of the AgentLoader using the Claude Code +sub-agent YAML frontmatter format. + +This example shows: +1. Creating agents using Claude Code YAML frontmatter format +2. Loading agents from markdown files with YAML frontmatter +3. Using loaded agents in multi-agent workflows +4. Demonstrating different agent configurations """ import os @@ -16,125 +22,212 @@ 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, load_agents_from_markdown -def create_agents_from_configs(): - """Create agents from configuration dictionaries (simulating markdown parsing)""" +def create_markdown_agent_files(): + """Create markdown files demonstrating Claude Code YAML frontmatter format""" - # 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" - } - ] + # Claude Code YAML frontmatter format + agent_files = { + "market_researcher.md": """--- +name: market-researcher +description: Expert in market analysis and competitive intelligence +model_name: gpt-4 +temperature: 0.2 +max_loops: 2 +mcp_url: http://example.com/market-data +--- + +You are a market research specialist with deep expertise in analyzing market dynamics and competitive landscapes. + +Your core responsibilities include: +- Conducting comprehensive market size and growth analysis +- Performing detailed competitive landscape assessments +- Analyzing consumer behavior patterns and preferences +- Identifying emerging industry trends and opportunities + +Methodology: +1. Gather comprehensive quantitative and qualitative market data +2. Analyze key market drivers, barriers, and success factors +3. Evaluate competitive positioning and market share dynamics +4. Assess market opportunities, threats, and entry strategies +5. Provide actionable insights with data-driven recommendations + +Always provide detailed market analysis reports with specific metrics, growth projections, and strategic recommendations for market entry or expansion. +""", + + "financial_analyst.md": """--- +name: financial-analyst +description: Specialist in financial modeling and investment analysis +model_name: gpt-4 +temperature: 0.1 +max_loops: 3 +--- + +You are a financial analysis expert specializing in investment evaluation and financial modeling. + +Your areas of expertise include: +- Financial statement analysis and ratio interpretation +- DCF modeling and valuation techniques (DCF, comparable company analysis, precedent transactions) +- Investment risk assessment and sensitivity analysis +- Cash flow projections and working capital analysis + +Analytical approach: +1. Conduct thorough financial statement analysis +2. Build comprehensive financial models with multiple scenarios +3. Perform detailed valuation using multiple methodologies +4. Assess financial risks and conduct sensitivity analysis +5. Generate investment recommendations with clear rationale + +Provide detailed financial reports with valuation models, risk assessments, and investment recommendations supported by quantitative analysis. +""", + + "industry_expert.md": """--- +name: industry-expert +description: Domain specialist with deep industry knowledge and regulatory expertise +model_name: gpt-4 +temperature: 0.3 +max_loops: 2 +--- + +You are an industry analysis expert with comprehensive knowledge of market structures, regulatory environments, and technology trends. + +Your specialization areas: +- Industry structure analysis and value chain mapping +- Regulatory environment assessment and compliance requirements +- Technology trends identification and disruption analysis +- Supply chain dynamics and operational considerations + +Research methodology: +1. Map industry structure, key players, and stakeholder relationships +2. Analyze current and emerging regulatory framework +3. Identify technology trends and potential market disruptions +4. Evaluate supply chain dynamics and operational requirements +5. Assess competitive positioning and strategic opportunities + +Generate comprehensive industry landscape reports with regulatory insights, technology trend analysis, and strategic recommendations for market positioning. +""" + "risk_analyst.md": """--- +name: risk-analyst +description: Specialist in investment risk assessment and mitigation strategies +model_name: gpt-4 +temperature: 0.15 +max_loops: 2 +--- + +You are a Risk Analyst specializing in comprehensive investment risk assessment and portfolio management. + +Your core competencies include: +- Conducting detailed investment risk evaluation and categorization +- Implementing sophisticated portfolio risk management strategies +- Ensuring regulatory compliance and conducting compliance assessments +- Performing advanced scenario analysis and stress testing methodologies + +Analytical framework: +1. Systematically identify and categorize all investment risks +2. Quantify risk exposure using advanced statistical methods and models +3. Develop comprehensive risk mitigation strategies and frameworks +4. Conduct rigorous scenario analysis and stress testing procedures +5. Provide actionable risk management recommendations with implementation roadmaps + +Deliver comprehensive risk assessment reports with quantitative analysis, compliance guidelines, and strategic risk management recommendations. +""" + } - 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}") + temp_files = [] + + # Create Claude Code format files + for filename, content in agent_files.items(): + temp_file = os.path.join(tempfile.gettempdir(), filename) + with open(temp_file, 'w', encoding='utf-8') as f: + f.write(content) + temp_files.append(temp_file) - return agents + return temp_files def main(): - """Main execution function""" - - # Create agents - agents = create_agents_from_configs() + """Main execution function demonstrating AgentLoader with Claude Code format""" - # Create sequential workflow - research_workflow = SequentialWorkflow( - agents=agents, - max_loops=1, - ) + print("AgentLoader Demo - Claude Code YAML Frontmatter Format") + print("=" * 60) - # Define research task - task = """ - Analyze the AI-powered healthcare diagnostics market for a potential $50M investment. + # Create markdown files demonstrating both formats + print("\n1. Creating markdown files...") + temp_files = create_markdown_agent_files() - 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) + try: + # Load agents using AgentLoader + print("\n2. Loading agents using AgentLoader...") + agents = load_agents_from_markdown(temp_files) + + print(f" Successfully loaded {len(agents)} agents:") + for agent in agents: + temp_attr = getattr(agent, 'temperature', 'default') + max_loops = getattr(agent, 'max_loops', 1) + print(f" - {agent.agent_name} (temp: {temp_attr}, loops: {max_loops})") + + # Demonstrate individual agent configuration + print("\n3. Agent Configuration Details:") + for i, agent in enumerate(agents, 1): + print(f" Agent {i}: {agent.agent_name}") + print(f" Model: {getattr(agent, 'model_name', 'default')}") + print(f" System prompt preview: {agent.system_prompt[:100]}...") + print() + + # Create sequential workflow with loaded agents + print("4. Creating 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 + 5. Risk assessment and mitigation strategies + + Provide comprehensive strategic recommendations for market entry. + """ + + print("5. Executing research workflow...") + print("=" * 50) + + # Note: In a real scenario, this would execute the workflow + # For demo purposes, we'll show the task distribution + print(f"Task distributed to {len(agents)} specialized agents:") + for i, agent in enumerate(agents, 1): + print(f" Agent {i} ({agent.agent_name}): Ready to process") + + print(f"\nTask preview: {task[:150]}...") + print("\n[Demo mode - actual workflow execution would call LLM APIs]") + + print("\nDemo Summary:") + print("-" * 50) + print("✓ Successfully loaded agents using Claude Code YAML frontmatter format") + print("✓ Agents configured with different temperatures and max_loops from YAML") + print("✓ Multi-agent workflow created with specialized investment analysis agents") + print("✓ Workflow ready for comprehensive market analysis execution") + + except Exception as e: + print(f"Error during demo: {e}") + import traceback + traceback.print_exc() + + finally: + # Cleanup temporary files + print("\n6. Cleaning up temporary files...") + for temp_file in temp_files: + try: + os.remove(temp_file) + print(f" Removed: {os.path.basename(temp_file)}") + except OSError: + pass if __name__ == "__main__": main() \ No newline at end of file diff --git a/swarms/utils/agent_loader.py b/swarms/utils/agent_loader.py index 7b918421..e6dce69d 100644 --- a/swarms/utils/agent_loader.py +++ b/swarms/utils/agent_loader.py @@ -1,5 +1,7 @@ import os import re +import random +import yaml from pathlib import Path from typing import Any, Dict, List, Optional, Union from pydantic import BaseModel, Field, field_validator @@ -9,14 +11,13 @@ from swarms.structs.agent import Agent class MarkdownAgentConfig(BaseModel): - """Configuration model for agents loaded from markdown files.""" + """Configuration model for agents loaded from Claude Code markdown files.""" name: str description: str model_name: Optional[str] = "gpt-4" + temperature: Optional[float] = Field(default=0.1, ge=0.0, le=2.0) + mcp_url: Optional[str] = None 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 @@ -43,16 +44,16 @@ class MarkdownAgentConfig(BaseModel): class AgentLoader: """ - Loader for creating agents from markdown files. + Loader for creating agents from markdown files using Claude Code sub-agent format. Supports both single markdown file and multiple markdown files. - Maintains backwards compatibility with claude code sub agents markdown format. + Uses YAML frontmatter format for agent configuration. Features: - Single markdown file loading - Multiple markdown files loading (batch processing) - - Flexible markdown parsing - - Agent configuration extraction from markdown structure + - YAML frontmatter parsing + - Agent configuration extraction from YAML metadata - Error handling and validation """ @@ -62,124 +63,51 @@ class AgentLoader: """ pass - def parse_markdown_table(self, content: str) -> Dict[str, str]: + def parse_yaml_frontmatter(self, content: str) -> Dict[str, Any]: """ - Parse markdown table to extract agent metadata. + Parse YAML frontmatter from markdown content. Args: - content: Markdown content containing a table + content: Markdown content with potential YAML frontmatter Returns: - Dictionary with parsed table data + Dictionary with parsed YAML data and remaining content """ - 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 = [] + # Check if content starts with YAML frontmatter + if not lines[0].strip() == '---': + return {"frontmatter": {}, "content": content} - # Add description - if config_data.get('description'): - prompt_parts.append(f"Role: {config_data['description']}") + # Find end of frontmatter + end_marker = -1 + for i, line in enumerate(lines[1:], 1): + if line.strip() == '---': + end_marker = i + break - # 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}") + if end_marker == -1: + return {"frontmatter": {}, "content": content} - # 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}") + # Extract frontmatter and content + frontmatter_text = '\n'.join(lines[1:end_marker]) + remaining_content = '\n'.join(lines[end_marker + 1:]).strip() - # Add expected output - if config_data.get('output'): - prompt_parts.append("\nExpected Output:") - for output in config_data['output']: - prompt_parts.append(f"- {output}") + try: + frontmatter_data = yaml.safe_load(frontmatter_text) or {} + except yaml.YAMLError as e: + logger.warning(f"Failed to parse YAML frontmatter: {e}") + return {"frontmatter": {}, "content": content} - return '\n'.join(prompt_parts) + return {"frontmatter": frontmatter_data, "content": remaining_content} + + + def parse_markdown_file(self, file_path: str) -> MarkdownAgentConfig: """ Parse a single markdown file to extract agent configuration. + Uses Claude Code sub-agent YAML frontmatter format. Args: file_path: Path to markdown file @@ -189,7 +117,7 @@ class AgentLoader: Raises: FileNotFoundError: If file doesn't exist - ValueError: If parsing fails + ValueError: If parsing fails or no YAML frontmatter found """ if not os.path.exists(file_path): raise FileNotFoundError(f"Markdown file {file_path} not found.") @@ -198,25 +126,29 @@ class AgentLoader: 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) + # Parse YAML frontmatter (Claude Code sub-agent format) + yaml_result = self.parse_yaml_frontmatter(content) + frontmatter = yaml_result["frontmatter"] + remaining_content = yaml_result["content"] - # Extract sections - sections = self.extract_sections(content) + if not frontmatter: + raise ValueError(f"No YAML frontmatter found in {file_path}. File must use Claude Code sub-agent format with YAML frontmatter.") - # Build configuration + # Use YAML frontmatter data 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', []), + 'name': frontmatter.get('name', Path(file_path).stem), + 'description': frontmatter.get('description', 'Agent loaded from markdown'), + 'model_name': frontmatter.get('model_name') or frontmatter.get('model', 'gpt-4'), + 'temperature': frontmatter.get('temperature', 0.1), + 'max_loops': frontmatter.get('max_loops', 1), + 'mcp_url': frontmatter.get('mcp_url'), + 'system_prompt': remaining_content.strip(), } - # Build system prompt - system_prompt = self.build_system_prompt(config_data) - config_data['system_prompt'] = system_prompt + # Generate random model if not specified + if not config_data['model_name'] or config_data['model_name'] == 'random': + models = ['gpt-4', 'gpt-4-turbo', 'claude-3-sonnet', 'claude-3-haiku'] + config_data['model_name'] = random.choice(models) logger.info(f"Successfully parsed markdown file: {file_path}") return MarkdownAgentConfig(**config_data) @@ -247,7 +179,7 @@ class AgentLoader: '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 + 'temperature': config_dict.get('temperature', 0.1), 'max_loops': config_dict['max_loops'], 'autosave': config_dict['autosave'], 'dashboard': config_dict['dashboard'], @@ -321,10 +253,10 @@ class AgentLoader: 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. + Uses Claude Code sub-agent YAML frontmatter format. Args: - file_path: Path to markdown file + file_path: Path to markdown file with YAML frontmatter **kwargs: Additional configuration overrides Returns: @@ -335,10 +267,10 @@ class AgentLoader: 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. + Uses Claude Code sub-agent YAML frontmatter format. Args: - file_paths: Directory path or list of file paths + file_paths: Directory path or list of file paths with YAML frontmatter **kwargs: Additional configuration overrides Returns: @@ -347,13 +279,13 @@ class AgentLoader: return self.load_agents_from_markdown(file_paths, **kwargs) -# Convenience functions for backwards compatibility +# Convenience functions def load_agent_from_markdown(file_path: str, **kwargs) -> Agent: """ - Load a single agent from a markdown file. + Load a single agent from a markdown file with Claude Code YAML frontmatter format. Args: - file_path: Path to markdown file + file_path: Path to markdown file with YAML frontmatter **kwargs: Additional configuration overrides Returns: @@ -365,10 +297,10 @@ def load_agent_from_markdown(file_path: str, **kwargs) -> Agent: def load_agents_from_markdown(file_paths: Union[str, List[str]], **kwargs) -> List[Agent]: """ - Load multiple agents from markdown files. + Load multiple agents from markdown files with Claude Code YAML frontmatter format. Args: - file_paths: Directory path or list of file paths + file_paths: Directory path or list of file paths with YAML frontmatter **kwargs: Additional configuration overrides Returns: diff --git a/test_agent_loader.py b/test_agent_loader.py deleted file mode 100644 index 3a02693a..00000000 --- a/test_agent_loader.py +++ /dev/null @@ -1,244 +0,0 @@ -""" -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) \ No newline at end of file From ba2a4d14718b8461151f0459706299a13b5fc442 Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Tue, 19 Aug 2025 22:28:25 +0530 Subject: [PATCH 03/12] updates and fixes ! --- agents_loader_example.py | 9 + examples/agent_loader_demo.py | 28 +++ examples/agents_loader_example.py | 175 ------------- .../multi_agent/simple_agent_loader_demo.py | 233 ------------------ 4 files changed, 37 insertions(+), 408 deletions(-) create mode 100644 agents_loader_example.py create mode 100644 examples/agent_loader_demo.py delete mode 100644 examples/agents_loader_example.py delete mode 100644 examples/multi_agent/simple_agent_loader_demo.py diff --git a/agents_loader_example.py b/agents_loader_example.py new file mode 100644 index 00000000..83fde8e6 --- /dev/null +++ b/agents_loader_example.py @@ -0,0 +1,9 @@ +from swarms.utils.agent_loader import load_agent_from_markdown + +# Load the Finance Advisor agent from markdown +agent = load_agent_from_markdown("Finance_advisor.md") + +# Use the agent to get financial advice +response = agent.run( + "I have $10,000 to invest. What's a good strategy for a beginner?" +) \ No newline at end of file diff --git a/examples/agent_loader_demo.py b/examples/agent_loader_demo.py new file mode 100644 index 00000000..bcc127fb --- /dev/null +++ b/examples/agent_loader_demo.py @@ -0,0 +1,28 @@ +from swarms.utils.agent_loader import load_agent_from_markdown + +# Example 1: Load a single agent +market_researcher = load_agent_from_markdown("market_researcher.md") + +# Example 2: Load multiple agents +from swarms.utils.agent_loader import load_agents_from_markdown + +agents = load_agents_from_markdown([ + "market_researcher.md", + "financial_analyst.md", + "risk_analyst.md" +]) + +# Example 3: Use agents in a workflow +from swarms.structs.sequential_workflow import SequentialWorkflow + +workflow = SequentialWorkflow( + agents=agents, + max_loops=1 +) + +task = """ +Analyze the AI healthcare market for a $50M investment opportunity. +Focus on market size, competition, financials, and risks. +""" + +result = workflow.run(task) \ No newline at end of file diff --git a/examples/agents_loader_example.py b/examples/agents_loader_example.py deleted file mode 100644 index f70e4435..00000000 --- a/examples/agents_loader_example.py +++ /dev/null @@ -1,175 +0,0 @@ -""" -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 sample markdown files for testing - Claude Code format - - # Performance Engineer agent - performance_md = """--- -name: performance-engineer -description: Optimize application performance and identify bottlenecks -model_name: gpt-4 -temperature: 0.3 -max_loops: 2 -mcp_url: http://example.com/mcp ---- - -You are a Performance Engineer specializing in application optimization and scalability. - -Your role involves: -- Analyzing application architecture and identifying potential bottlenecks -- Implementing comprehensive monitoring and logging -- Conducting performance testing under various load conditions -- Optimizing critical paths and resource usage -- Documenting findings and providing actionable recommendations - -Expected output: -- Performance analysis reports with specific metrics -- Optimized code recommendations -- Infrastructure scaling suggestions -- Monitoring and alerting setup guidelines -""" - - # Data Analyst agent - data_analyst_md = """--- -name: data-analyst -description: Analyze data and provide business insights -model_name: gpt-4 -temperature: 0.2 -max_loops: 1 ---- - -You are a Data Analyst specializing in extracting insights from complex datasets. - -Your responsibilities include: -- Collecting and cleaning data from various sources -- Performing exploratory data analysis and statistical modeling -- Creating compelling visualizations and interactive dashboards -- Applying statistical methods and machine learning techniques -- Presenting findings and actionable business recommendations - -Focus on providing data-driven insights that support strategic decision making. -""" - - # Create sample markdown files - performance_file = "performance_engineer.md" - data_file = "data_analyst.md" - - with open(performance_file, 'w') as f: - f.write(performance_md) - - with open(data_file, 'w') as f: - f.write(data_analyst_md) - - try: - # Example 2: Load Performance Engineer agent - print("\\n1. Loading Performance Engineer agent (YAML frontmatter):") - perf_agent = loader.load_single_agent(performance_file) - print(f" Loaded agent: {perf_agent.agent_name}") - print(f" Model: {perf_agent.model_name}") - print(f" Temperature: {getattr(perf_agent, 'temperature', 'Not set')}") - print(f" Max loops: {perf_agent.max_loops}") - print(f" System prompt preview: {perf_agent.system_prompt[:100]}...") - - # Example 3: Load Data Analyst agent - print("\\n2. Loading Data Analyst agent:") - data_agent = loader.load_single_agent(data_file) - print(f" Loaded agent: {data_agent.agent_name}") - print(f" Temperature: {getattr(data_agent, 'temperature', 'Not set')}") - print(f" System prompt preview: {data_agent.system_prompt[:100]}...") - - # Example 4: Load single agent using convenience function - print("\\n3. Loading single agent using convenience function:") - agent2 = load_agent_from_markdown(performance_file) - print(f" Loaded agent: {agent2.agent_name}") - - # Example 5: Load multiple agents (from directory or list) - print("\\n4. Loading multiple agents:") - - # Create another sample file - Security Analyst - security_md = """--- -name: security-analyst -description: Analyze and improve system security -model_name: gpt-4 -temperature: 0.1 -max_loops: 3 ---- - -You are a Security Analyst specializing in cybersecurity assessment and protection. - -Your expertise includes: -- Conducting comprehensive security vulnerability assessments -- Performing detailed code security reviews and penetration testing -- Implementing robust infrastructure hardening measures -- Developing incident response and recovery procedures - -Key methodology: -1. Conduct thorough security audits across all system components -2. Identify and classify potential vulnerabilities and threats -3. Recommend and implement security improvements and controls -4. Develop comprehensive security policies and best practices -5. Monitor and respond to security incidents - -Provide detailed security reports with specific remediation steps and risk assessments. -""" - - security_file = "security_analyst.md" - with open(security_file, 'w') as f: - f.write(security_md) - - # Load multiple agents from list - agents = loader.load_multiple_agents([performance_file, data_file, security_file]) - print(f" Loaded {len(agents)} agents:") - for agent in agents: - temp_attr = getattr(agent, 'temperature', 'default') - print(f" - {agent.agent_name} (temp: {temp_attr})") - - # Example 6: Load agents from directory (current directory) - print("\\n5. Loading agents from current directory:") - current_dir_agents = load_agents_from_markdown(".") - print(f" Found {len(current_dir_agents)} agents in current directory") - - # Example 7: Demonstrate error handling - print("\\n6. Error handling demo:") - try: - loader.load_single_agent("nonexistent.md") - except FileNotFoundError as e: - print(f" Caught expected error: {e}") - - # Example 8: Test agent functionality - print("\\n7. Testing loaded agent functionality:") - test_agent = agents[0] - print(f" Agent: {test_agent.agent_name}") - print(f" Temperature: {getattr(test_agent, 'temperature', 'default')}") - print(f" Max loops: {test_agent.max_loops}") - print(f" Ready for task execution") - - except Exception as e: - print(f"Error during demo: {e}") - - finally: - # Cleanup sample files - for file in [performance_file, data_file, security_file]: - if os.path.exists(file): - os.remove(file) - print("\\n Cleaned up sample files") - - print("\\n=== Demo Complete ===") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/examples/multi_agent/simple_agent_loader_demo.py b/examples/multi_agent/simple_agent_loader_demo.py deleted file mode 100644 index 481a5aea..00000000 --- a/examples/multi_agent/simple_agent_loader_demo.py +++ /dev/null @@ -1,233 +0,0 @@ -""" -Simple AgentLoader Demo - Claude Code Format -============================================= - -A comprehensive demonstration of the AgentLoader using the Claude Code -sub-agent YAML frontmatter format. - -This example shows: -1. Creating agents using Claude Code YAML frontmatter format -2. Loading agents from markdown files with YAML frontmatter -3. Using loaded agents in multi-agent workflows -4. Demonstrating different agent configurations -""" - -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 -from swarms.utils.agent_loader import AgentLoader, load_agents_from_markdown - -def create_markdown_agent_files(): - """Create markdown files demonstrating Claude Code YAML frontmatter format""" - - # Claude Code YAML frontmatter format - agent_files = { - "market_researcher.md": """--- -name: market-researcher -description: Expert in market analysis and competitive intelligence -model_name: gpt-4 -temperature: 0.2 -max_loops: 2 -mcp_url: http://example.com/market-data ---- - -You are a market research specialist with deep expertise in analyzing market dynamics and competitive landscapes. - -Your core responsibilities include: -- Conducting comprehensive market size and growth analysis -- Performing detailed competitive landscape assessments -- Analyzing consumer behavior patterns and preferences -- Identifying emerging industry trends and opportunities - -Methodology: -1. Gather comprehensive quantitative and qualitative market data -2. Analyze key market drivers, barriers, and success factors -3. Evaluate competitive positioning and market share dynamics -4. Assess market opportunities, threats, and entry strategies -5. Provide actionable insights with data-driven recommendations - -Always provide detailed market analysis reports with specific metrics, growth projections, and strategic recommendations for market entry or expansion. -""", - - "financial_analyst.md": """--- -name: financial-analyst -description: Specialist in financial modeling and investment analysis -model_name: gpt-4 -temperature: 0.1 -max_loops: 3 ---- - -You are a financial analysis expert specializing in investment evaluation and financial modeling. - -Your areas of expertise include: -- Financial statement analysis and ratio interpretation -- DCF modeling and valuation techniques (DCF, comparable company analysis, precedent transactions) -- Investment risk assessment and sensitivity analysis -- Cash flow projections and working capital analysis - -Analytical approach: -1. Conduct thorough financial statement analysis -2. Build comprehensive financial models with multiple scenarios -3. Perform detailed valuation using multiple methodologies -4. Assess financial risks and conduct sensitivity analysis -5. Generate investment recommendations with clear rationale - -Provide detailed financial reports with valuation models, risk assessments, and investment recommendations supported by quantitative analysis. -""", - - "industry_expert.md": """--- -name: industry-expert -description: Domain specialist with deep industry knowledge and regulatory expertise -model_name: gpt-4 -temperature: 0.3 -max_loops: 2 ---- - -You are an industry analysis expert with comprehensive knowledge of market structures, regulatory environments, and technology trends. - -Your specialization areas: -- Industry structure analysis and value chain mapping -- Regulatory environment assessment and compliance requirements -- Technology trends identification and disruption analysis -- Supply chain dynamics and operational considerations - -Research methodology: -1. Map industry structure, key players, and stakeholder relationships -2. Analyze current and emerging regulatory framework -3. Identify technology trends and potential market disruptions -4. Evaluate supply chain dynamics and operational requirements -5. Assess competitive positioning and strategic opportunities - -Generate comprehensive industry landscape reports with regulatory insights, technology trend analysis, and strategic recommendations for market positioning. -""" - "risk_analyst.md": """--- -name: risk-analyst -description: Specialist in investment risk assessment and mitigation strategies -model_name: gpt-4 -temperature: 0.15 -max_loops: 2 ---- - -You are a Risk Analyst specializing in comprehensive investment risk assessment and portfolio management. - -Your core competencies include: -- Conducting detailed investment risk evaluation and categorization -- Implementing sophisticated portfolio risk management strategies -- Ensuring regulatory compliance and conducting compliance assessments -- Performing advanced scenario analysis and stress testing methodologies - -Analytical framework: -1. Systematically identify and categorize all investment risks -2. Quantify risk exposure using advanced statistical methods and models -3. Develop comprehensive risk mitigation strategies and frameworks -4. Conduct rigorous scenario analysis and stress testing procedures -5. Provide actionable risk management recommendations with implementation roadmaps - -Deliver comprehensive risk assessment reports with quantitative analysis, compliance guidelines, and strategic risk management recommendations. -""" - } - - temp_files = [] - - # Create Claude Code format files - for filename, content in agent_files.items(): - temp_file = os.path.join(tempfile.gettempdir(), filename) - with open(temp_file, 'w', encoding='utf-8') as f: - f.write(content) - temp_files.append(temp_file) - - return temp_files - -def main(): - """Main execution function demonstrating AgentLoader with Claude Code format""" - - print("AgentLoader Demo - Claude Code YAML Frontmatter Format") - print("=" * 60) - - # Create markdown files demonstrating both formats - print("\n1. Creating markdown files...") - temp_files = create_markdown_agent_files() - - try: - # Load agents using AgentLoader - print("\n2. Loading agents using AgentLoader...") - agents = load_agents_from_markdown(temp_files) - - print(f" Successfully loaded {len(agents)} agents:") - for agent in agents: - temp_attr = getattr(agent, 'temperature', 'default') - max_loops = getattr(agent, 'max_loops', 1) - print(f" - {agent.agent_name} (temp: {temp_attr}, loops: {max_loops})") - - # Demonstrate individual agent configuration - print("\n3. Agent Configuration Details:") - for i, agent in enumerate(agents, 1): - print(f" Agent {i}: {agent.agent_name}") - print(f" Model: {getattr(agent, 'model_name', 'default')}") - print(f" System prompt preview: {agent.system_prompt[:100]}...") - print() - - # Create sequential workflow with loaded agents - print("4. Creating 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 - 5. Risk assessment and mitigation strategies - - Provide comprehensive strategic recommendations for market entry. - """ - - print("5. Executing research workflow...") - print("=" * 50) - - # Note: In a real scenario, this would execute the workflow - # For demo purposes, we'll show the task distribution - print(f"Task distributed to {len(agents)} specialized agents:") - for i, agent in enumerate(agents, 1): - print(f" Agent {i} ({agent.agent_name}): Ready to process") - - print(f"\nTask preview: {task[:150]}...") - print("\n[Demo mode - actual workflow execution would call LLM APIs]") - - print("\nDemo Summary:") - print("-" * 50) - print("✓ Successfully loaded agents using Claude Code YAML frontmatter format") - print("✓ Agents configured with different temperatures and max_loops from YAML") - print("✓ Multi-agent workflow created with specialized investment analysis agents") - print("✓ Workflow ready for comprehensive market analysis execution") - - except Exception as e: - print(f"Error during demo: {e}") - import traceback - traceback.print_exc() - - finally: - # Cleanup temporary files - print("\n6. Cleaning up temporary files...") - for temp_file in temp_files: - try: - os.remove(temp_file) - print(f" Removed: {os.path.basename(temp_file)}") - except OSError: - pass - -if __name__ == "__main__": - main() \ No newline at end of file From 4c5dd5a67f52a9009558e04e0711c5416f90887a Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Tue, 19 Aug 2025 22:29:11 +0530 Subject: [PATCH 04/12] cleanup ! --- agents_loader_example.py | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 agents_loader_example.py diff --git a/agents_loader_example.py b/agents_loader_example.py deleted file mode 100644 index 83fde8e6..00000000 --- a/agents_loader_example.py +++ /dev/null @@ -1,9 +0,0 @@ -from swarms.utils.agent_loader import load_agent_from_markdown - -# Load the Finance Advisor agent from markdown -agent = load_agent_from_markdown("Finance_advisor.md") - -# Use the agent to get financial advice -response = agent.run( - "I have $10,000 to invest. What's a good strategy for a beginner?" -) \ No newline at end of file From aa1be4c065da6493b169cc2491a59ea280bd57e2 Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Wed, 20 Aug 2025 22:00:51 +0530 Subject: [PATCH 05/12] updates ! --- docs/swarms/utils/agent_loader.md | 218 ++++++++++-------- swarms/utils/__init__.py | 10 + swarms/utils/agent_loader.py | 370 ++++++++++++++++++++---------- 3 files changed, 380 insertions(+), 218 deletions(-) diff --git a/docs/swarms/utils/agent_loader.md b/docs/swarms/utils/agent_loader.md index b8f1e94f..91a43578 100644 --- a/docs/swarms/utils/agent_loader.md +++ b/docs/swarms/utils/agent_loader.md @@ -6,9 +6,10 @@ The `AgentLoader` is a powerful utility for creating Swarms agents from markdown The AgentLoader enables you to: - Load single agents from markdown files with YAML frontmatter -- Load multiple agents from directories or file lists +- Load multiple agents from directories or file lists with concurrent processing - Parse Claude Code sub-agent YAML frontmatter configurations - Extract system prompts from markdown content +- Utilize 100% CPU cores for high-performance batch loading - Provide comprehensive error handling and validation ## Installation @@ -56,42 +57,37 @@ the subagent should follow. ```python from swarms.utils import load_agent_from_markdown -# Load Claude Code format agent (YAML frontmatter) -agent = load_agent_from_markdown( - file_path="performance-engineer.md" # Uses YAML frontmatter format -) +# Load agent from markdown file +agent = load_agent_from_markdown("finance_advisor.md") -# The agent automatically gets configured with: -# - Name, description from frontmatter -# - Temperature, max_loops, model settings -# - System prompt from content after frontmatter - -response = agent.run("Analyze application performance issues") -print(response) +# Use the agent +response = agent.run( + "I have $10,000 to invest. What's a good strategy for a beginner?" +) ``` -### Loading Multiple Agents +### Loading Multiple Agents (Concurrent) ```python from swarms.utils import load_agents_from_markdown -# Load all agents from directory (YAML frontmatter format) -agents = load_agents_from_markdown( - file_paths="./agents_directory/" # Directory with Claude Code format files -) +# Load agents from list of files with concurrent processing +agents = load_agents_from_markdown([ + "market_researcher.md", + "financial_analyst.md", + "risk_analyst.md" +], concurrent=True) # Uses all CPU cores for faster loading -# Load agents from specific files -agents = load_agents_from_markdown( - file_paths=[ - "performance-engineer.md", # Claude Code YAML format - "financial-analyst.md", # Claude Code YAML format - "security-analyst.md" # Claude Code YAML format - ] +# Use agents in a workflow +from swarms.structs import SequentialWorkflow + +workflow = SequentialWorkflow( + agents=agents, + max_loops=1 ) -print(f"Loaded {len(agents)} agents") -for agent in agents: - print(f"- {agent.agent_name}: {getattr(agent, 'temperature', 'default temp')}") +task = "Analyze the AI healthcare market for a $50M investment." +result = workflow.run(task) ``` ## Class-Based Usage @@ -109,8 +105,12 @@ loader = AgentLoader() # Load single agent agent = loader.load_single_agent("path/to/agent.md") -# Load multiple agents -agents = loader.load_multiple_agents("./agents_directory/") +# Load multiple agents with concurrent processing +agents = loader.load_multiple_agents( + "./agents_directory/", + concurrent=True, # Enable concurrent processing + max_workers=8 # Optional: limit worker threads +) # Parse markdown file without creating agent config = loader.parse_markdown_file("path/to/agent.md") @@ -150,34 +150,39 @@ agent = load_agent_from_markdown( ## Complete Example -### Example: Claude Code Sub-Agent Format +### Example: Finance Advisor Agent -Create a file `performance-engineer.md`: +Create a file `finance_advisor.md`: ```markdown --- -name: performance-engineer -description: Optimize application performance and identify bottlenecks +name: FinanceAdvisor +description: Expert financial advisor for investment and budgeting guidance model_name: gpt-4 -temperature: 0.3 -max_loops: 2 -mcp_url: http://example.com/mcp +temperature: 0.7 +max_loops: 1 --- -You are a Performance Engineer specializing in application optimization and scalability. - -Your role involves analyzing system performance, identifying bottlenecks, and implementing -solutions to improve efficiency and user experience. - -Key responsibilities: -- Profile applications to identify performance issues -- Optimize database queries and caching strategies -- Implement load testing and monitoring solutions -- Recommend infrastructure improvements -- Provide actionable optimization recommendations - -Always provide specific, measurable recommendations with implementation details. -Focus on both immediate wins and long-term architectural improvements. +You are an expert financial advisor with deep knowledge in: +- Investment strategies and portfolio management +- Personal budgeting and financial planning +- Risk assessment and diversification +- Tax optimization strategies +- Retirement planning + +Your approach: +- Provide clear, actionable financial advice +- Consider individual risk tolerance and goals +- Explain complex concepts in simple terms +- Always emphasize the importance of diversification +- Include relevant disclaimers about financial advice + +When analyzing financial situations: +1. Assess current financial position +2. Identify short-term and long-term goals +3. Evaluate risk tolerance +4. Recommend appropriate strategies +5. Suggest specific action steps ``` ### Loading and Using the Agent @@ -185,25 +190,13 @@ Focus on both immediate wins and long-term architectural improvements. ```python from swarms.utils import load_agent_from_markdown -# Load Claude Code format agent (YAML frontmatter) -performance_agent = load_agent_from_markdown( - file_path="performance-engineer.md" -) - -print(f"Agent: {performance_agent.agent_name}") -print(f"Temperature: {getattr(performance_agent, 'temperature', 'default')}") -print(f"Max loops: {performance_agent.max_loops}") -print(f"System prompt preview: {performance_agent.system_prompt[:100]}...") +# Load the Finance Advisor agent +agent = load_agent_from_markdown("finance_advisor.md") -# Use the performance 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. -""" - -# Note: Actual agent.run() would make API calls -print(f"\nTask for {performance_agent.agent_name}: {task[:100]}...") +# Use the agent for financial advice +response = agent.run( + "I have $10,000 to invest. What's a good strategy for a beginner?" +) ``` ## Error Handling @@ -229,6 +222,54 @@ except Exception as e: print(f"Error loading agents: {e}") ``` +## Concurrent Processing Features + +### Multi-Core Performance + +The AgentLoader utilizes **100% of CPU cores** for concurrent agent loading, providing significant performance improvements when processing multiple markdown files: + +```python +from swarms.utils import load_agents_from_markdown + +# Automatic concurrent processing for multiple files +agents = load_agents_from_markdown([ + "agent1.md", "agent2.md", "agent3.md", "agent4.md" +]) # concurrent=True by default + +# Manual control over concurrency +agents = load_agents_from_markdown( + "./agents_directory/", + concurrent=True, # Enable concurrent processing + max_workers=8 # Limit to 8 worker threads +) + +# Disable concurrency for debugging or single files +agents = load_agents_from_markdown( + ["single_agent.md"], + concurrent=False # Sequential processing +) +``` + +### Resource Management + +```python +# Default: Uses all CPU cores +agents = load_agents_from_markdown(files, concurrent=True) + +# Custom worker count for resource control +agents = load_agents_from_markdown( + files, + concurrent=True, + max_workers=4 # Limit to 4 threads +) + +# ThreadPoolExecutor automatically manages: +# - Thread lifecycle +# - Resource cleanup +# - Exception handling +# - Result collection +``` + ## Advanced Features ### Custom System Prompt Building @@ -249,33 +290,6 @@ 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 @@ -323,8 +337,13 @@ class AgentLoader: ### 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] +def load_agent_from_markdown(file_path: str, **kwargs) -> Agent +def load_agents_from_markdown( + file_paths: Union[str, List[str]], + concurrent: bool = True, # Enable concurrent processing + max_workers: Optional[int] = None, # Max worker threads (defaults to CPU count) + **kwargs +) -> List[Agent] ``` ### Configuration Model @@ -347,9 +366,8 @@ class MarkdownAgentConfig(BaseModel): ## 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 +- `agents_loader_example.py` - Simple usage example +- `examples/agent_loader_demo.py` - Multi-agent workflow example ## Support diff --git a/swarms/utils/__init__.py b/swarms/utils/__init__.py index 2eb63089..62711e03 100644 --- a/swarms/utils/__init__.py +++ b/swarms/utils/__init__.py @@ -22,6 +22,12 @@ from swarms.utils.history_output_formatter import ( from swarms.utils.check_all_model_max_tokens import ( check_all_model_max_tokens, ) +from swarms.utils.agent_loader import ( + AgentLoader, + MarkdownAgentConfig, + load_agent_from_markdown, + load_agents_from_markdown, +) __all__ = [ @@ -41,4 +47,8 @@ __all__ = [ "HistoryOutputType", "history_output_formatter", "check_all_model_max_tokens", + "AgentLoader", + "MarkdownAgentConfig", + "load_agent_from_markdown", + "load_agents_from_markdown", ] diff --git a/swarms/utils/agent_loader.py b/swarms/utils/agent_loader.py index e6dce69d..58a81928 100644 --- a/swarms/utils/agent_loader.py +++ b/swarms/utils/agent_loader.py @@ -1,22 +1,29 @@ import os -import re -import random import yaml from pathlib import Path from typing import Any, Dict, List, Optional, Union +from concurrent.futures import ( + ThreadPoolExecutor, + as_completed, + TimeoutError, +) from pydantic import BaseModel, Field, field_validator from loguru import logger from swarms.structs.agent import Agent +# Default model configuration +DEFAULT_MODEL = "gpt-4o" + class MarkdownAgentConfig(BaseModel): """Configuration model for agents loaded from Claude Code markdown files.""" + name: str description: str - model_name: Optional[str] = "gpt-4" + model_name: Optional[str] = "gpt-4o" temperature: Optional[float] = Field(default=0.1, ge=0.0, le=2.0) - mcp_url: Optional[str] = None + mcp_url: Optional[int] = None system_prompt: str max_loops: int = Field(default=1, ge=1) autosave: bool = False @@ -33,22 +40,25 @@ class MarkdownAgentConfig(BaseModel): artifacts_on: bool = False artifacts_file_extension: str = ".md" artifacts_output_path: str = "" + streaming_on: bool = False @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") + raise ValueError( + "System prompt must be a non-empty string" + ) return v - + class AgentLoader: """ Loader for creating agents from markdown files using Claude Code sub-agent format. - + Supports both single markdown file and multiple markdown files. Uses YAML frontmatter format for agent configuration. - + Features: - Single markdown file loading - Multiple markdown files loading (batch processing) @@ -56,223 +66,335 @@ class AgentLoader: - Agent configuration extraction from YAML metadata - Error handling and validation """ - + def __init__(self): """ Initialize the AgentLoader. """ pass - + def parse_yaml_frontmatter(self, content: str) -> Dict[str, Any]: """ Parse YAML frontmatter from markdown content. - + Args: content: Markdown content with potential YAML frontmatter - + Returns: Dictionary with parsed YAML data and remaining content """ - lines = content.split('\n') - + lines = content.split("\n") + # Check if content starts with YAML frontmatter - if not lines[0].strip() == '---': + if not lines[0].strip() == "---": return {"frontmatter": {}, "content": content} - + # Find end of frontmatter end_marker = -1 for i, line in enumerate(lines[1:], 1): - if line.strip() == '---': + if line.strip() == "---": end_marker = i break - + if end_marker == -1: return {"frontmatter": {}, "content": content} - + # Extract frontmatter and content - frontmatter_text = '\n'.join(lines[1:end_marker]) - remaining_content = '\n'.join(lines[end_marker + 1:]).strip() - + frontmatter_text = "\n".join(lines[1:end_marker]) + remaining_content = "\n".join(lines[end_marker + 1 :]).strip() + try: frontmatter_data = yaml.safe_load(frontmatter_text) or {} except yaml.YAMLError as e: logger.warning(f"Failed to parse YAML frontmatter: {e}") return {"frontmatter": {}, "content": content} - - return {"frontmatter": frontmatter_data, "content": remaining_content} - - - - def parse_markdown_file(self, file_path: str) -> MarkdownAgentConfig: + return { + "frontmatter": frontmatter_data, + "content": remaining_content, + } + + def parse_markdown_file( + self, file_path: str + ) -> MarkdownAgentConfig: """ Parse a single markdown file to extract agent configuration. Uses Claude Code sub-agent YAML frontmatter format. - + Args: file_path: Path to markdown file - + Returns: MarkdownAgentConfig object with parsed configuration - + Raises: FileNotFoundError: If file doesn't exist ValueError: If parsing fails or no YAML frontmatter found """ if not os.path.exists(file_path): - raise FileNotFoundError(f"Markdown file {file_path} not found.") - + raise FileNotFoundError( + f"Markdown file {file_path} not found." + ) + try: - with open(file_path, 'r', encoding='utf-8') as file: + with open(file_path, "r", encoding="utf-8") as file: content = file.read() - + # Parse YAML frontmatter (Claude Code sub-agent format) yaml_result = self.parse_yaml_frontmatter(content) frontmatter = yaml_result["frontmatter"] remaining_content = yaml_result["content"] - + if not frontmatter: - raise ValueError(f"No YAML frontmatter found in {file_path}. File must use Claude Code sub-agent format with YAML frontmatter.") - + raise ValueError( + f"No YAML frontmatter found in {file_path}. File must use Claude Code sub-agent format with YAML frontmatter." + ) + # Use YAML frontmatter data config_data = { - 'name': frontmatter.get('name', Path(file_path).stem), - 'description': frontmatter.get('description', 'Agent loaded from markdown'), - 'model_name': frontmatter.get('model_name') or frontmatter.get('model', 'gpt-4'), - 'temperature': frontmatter.get('temperature', 0.1), - 'max_loops': frontmatter.get('max_loops', 1), - 'mcp_url': frontmatter.get('mcp_url'), - 'system_prompt': remaining_content.strip(), + "name": frontmatter.get("name", Path(file_path).stem), + "description": frontmatter.get( + "description", "Agent loaded from markdown" + ), + "model_name": frontmatter.get("model_name") + or frontmatter.get("model", DEFAULT_MODEL), + "temperature": frontmatter.get("temperature", 0.1), + "max_loops": frontmatter.get("max_loops", 1), + "mcp_url": frontmatter.get("mcp_url"), + "system_prompt": remaining_content.strip(), + "streaming_on": frontmatter.get( + "streaming_on", False + ), } - - # Generate random model if not specified - if not config_data['model_name'] or config_data['model_name'] == 'random': - models = ['gpt-4', 'gpt-4-turbo', 'claude-3-sonnet', 'claude-3-haiku'] - config_data['model_name'] = random.choice(models) - - logger.info(f"Successfully parsed markdown file: {file_path}") + + # Use default model if not specified + if not config_data["model_name"]: + config_data["model_name"] = DEFAULT_MODEL + + 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: + 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'), - 'temperature': config_dict.get('temperature', 0.1), - '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'], + + # Map config fields to Agent parameters, handling special cases + field_mapping = { + "name": "agent_name", # name -> agent_name + "description": None, # not used by Agent + "mcp_url": None, # not used by Agent } - + + agent_fields = {} + for config_key, config_value in config_dict.items(): + # Handle special field mappings + if config_key in field_mapping: + agent_key = field_mapping[config_key] + if agent_key: # Only include if mapped to something + agent_fields[agent_key] = config_value + else: + # Direct mapping for most fields + agent_fields[config_key] = config_value + try: - logger.info(f"Creating agent '{config.name}' from {file_path}") + 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}") + 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"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]: + raise ValueError( + f"Error creating agent from {file_path}: {str(e)}" + ) + + def load_agents_from_markdown( + self, + file_paths: Union[str, List[str]], + concurrent: bool = True, + max_workers: Optional[int] = None, + max_file_size_mb: float = 10.0, + **kwargs, + ) -> List[Agent]: """ - Load multiple agents from markdown files. - + Load multiple agents from markdown files with optional concurrent processing. + Args: file_paths: Single file path, directory path, or list of file paths + concurrent: Whether to use concurrent processing for multiple files + max_workers: Maximum number of worker threads (defaults to CPU count) + max_file_size_mb: Maximum file size in MB to prevent memory issues **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')) + 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.") + 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 + raise ValueError( + "file_paths must be a string or list of strings" + ) + + # Validate file sizes to prevent memory issues 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") + file_size_mb = os.path.getsize(file_path) / ( + 1024 * 1024 + ) + if file_size_mb > max_file_size_mb: + logger.warning( + f"Skipping {file_path}: size {file_size_mb:.2f}MB exceeds limit {max_file_size_mb}MB" + ) + paths_to_process.remove(file_path) + except OSError: + logger.warning( + f"Could not check size of {file_path}, skipping validation" + ) + + # Adjust max_workers for I/O-bound operations + if max_workers is None and concurrent: + # For I/O-bound: use more threads than CPU count, but cap it + max_workers = min( + 20, len(paths_to_process), os.cpu_count() * 2 + ) + + # Use concurrent processing for multiple files if enabled + if concurrent and len(paths_to_process) > 1: + logger.info( + f"Loading {len(paths_to_process)} agents concurrently with {max_workers} workers..." + ) + + with ThreadPoolExecutor( + max_workers=max_workers + ) as executor: + # Submit all tasks + future_to_path = { + executor.submit( + self.load_agent_from_markdown, + file_path, + **kwargs, + ): file_path + for file_path in paths_to_process + } + + # Collect results as they complete with timeout + for future in as_completed( + future_to_path, timeout=300 + ): # 5 minute timeout + file_path = future_to_path[future] + try: + agent = future.result( + timeout=60 + ) # 1 minute per agent + agents.append(agent) + logger.info( + f"Successfully loaded agent from {file_path}" + ) + except TimeoutError: + logger.error(f"Timeout loading {file_path}") + continue + except Exception as e: + logger.error( + f"Failed to load {file_path}: {str(e)}" + ) + continue + else: + # Sequential processing for single file or when concurrent is disabled + logger.info( + f"Loading {len(paths_to_process)} agents sequentially..." + ) + 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. Uses Claude Code sub-agent YAML frontmatter format. - + Args: file_path: Path to markdown file with YAML frontmatter **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]: + + def load_multiple_agents( + self, file_paths: Union[str, List[str]], **kwargs + ) -> List[Agent]: """ Convenience method for loading multiple agents. Uses Claude Code sub-agent YAML frontmatter format. - + Args: file_paths: Directory path or list of file paths with YAML frontmatter **kwargs: Additional configuration overrides - + Returns: List of configured Agent instances """ @@ -283,11 +405,11 @@ class AgentLoader: def load_agent_from_markdown(file_path: str, **kwargs) -> Agent: """ Load a single agent from a markdown file with Claude Code YAML frontmatter format. - + Args: file_path: Path to markdown file with YAML frontmatter **kwargs: Additional configuration overrides - + Returns: Configured Agent instance """ @@ -295,16 +417,28 @@ def load_agent_from_markdown(file_path: str, **kwargs) -> Agent: return loader.load_single_agent(file_path, **kwargs) -def load_agents_from_markdown(file_paths: Union[str, List[str]], **kwargs) -> List[Agent]: +def load_agents_from_markdown( + file_paths: Union[str, List[str]], + concurrent: bool = True, + max_file_size_mb: float = 10.0, + **kwargs, +) -> List[Agent]: """ Load multiple agents from markdown files with Claude Code YAML frontmatter format. - + Args: file_paths: Directory path or list of file paths with YAML frontmatter + concurrent: Whether to use concurrent processing for multiple files + max_file_size_mb: Maximum file size in MB to prevent memory issues **kwargs: Additional configuration overrides - + Returns: List of configured Agent instances """ loader = AgentLoader() - return loader.load_multiple_agents(file_paths, **kwargs) \ No newline at end of file + return loader.load_agents_from_markdown( + file_paths, + concurrent=concurrent, + max_file_size_mb=max_file_size_mb, + **kwargs, + ) From b871b8e8a34cba1980bf9a301b80e2d70bb52094 Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Wed, 20 Aug 2025 22:57:32 +0530 Subject: [PATCH 06/12] examples & docs --- docs/mkdocs.yml | 1 + docs/swarms/utils/agent_loader.md | 79 ++++++++++++++++++- examples/agent_loader/agent_loader_demo.py | 7 ++ examples/agent_loader/finance_advisor.md | 28 +++++++ .../agent_loader/multi_agents_loader_demo.py | 22 ++++++ 5 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 examples/agent_loader/agent_loader_demo.py create mode 100644 examples/agent_loader/finance_advisor.md create mode 100644 examples/agent_loader/multi_agents_loader_demo.py diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 5a687cca..ff2bc4cc 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -369,6 +369,7 @@ nav: - Utils: - Agent with Streaming: "examples/agent_stream.md" - Agent Output Types: "swarms/examples/agent_output_types.md" + - Agent Loader: "swarms/utils/agent_loader.md" - Gradio Chat Interface: "swarms/ui/main.md" - LLM Providers: - Overview: "swarms/examples/model_providers.md" diff --git a/docs/swarms/utils/agent_loader.md b/docs/swarms/utils/agent_loader.md index 91a43578..74319f75 100644 --- a/docs/swarms/utils/agent_loader.md +++ b/docs/swarms/utils/agent_loader.md @@ -164,6 +164,7 @@ max_loops: 1 --- You are an expert financial advisor with deep knowledge in: + - Investment strategies and portfolio management - Personal budgeting and financial planning - Risk assessment and diversification @@ -171,6 +172,7 @@ You are an expert financial advisor with deep knowledge in: - Retirement planning Your approach: + - Provide clear, actionable financial advice - Consider individual risk tolerance and goals - Explain complex concepts in simple terms @@ -178,6 +180,7 @@ Your approach: - Include relevant disclaimers about financial advice When analyzing financial situations: + 1. Assess current financial position 2. Identify short-term and long-term goals 3. Evaluate risk tolerance @@ -365,9 +368,79 @@ class MarkdownAgentConfig(BaseModel): ## Examples Repository -Find more examples in the Swarms repository: -- `agents_loader_example.py` - Simple usage example -- `examples/agent_loader_demo.py` - Multi-agent workflow example +Find complete working examples in the `examples/agent_loader/` directory: + +### Single Agent Example (`agent_loader_demo.py`) +```python +from swarms.utils import load_agent_from_markdown + +agent = load_agent_from_markdown("finance_advisor.md") + +agent.run( + task="Analyze the financial market trends for 2023." +) +``` + +### Multi-Agent Workflow Example (`multi_agents_loader_demo.py`) +```python +from swarms.utils import load_agents_from_markdown + +agents = load_agents_from_markdown([ + "market_researcher.md", + "financial_analyst.md", + "risk_analyst.md" +]) + +# Use agents in a workflow +from swarms.structs.sequential_workflow import SequentialWorkflow + +workflow = SequentialWorkflow( + agents=agents, + max_loops=1 +) + +task = """ +Analyze the AI healthcare market for a $50M investment opportunity. +Focus on market size, competition, financials, and risks. +""" + +result = workflow.run(task) +``` + +### Sample Agent Definition (`finance_advisor.md`) +```markdown +--- +name: FinanceAdvisor +description: Expert financial advisor for investment and budgeting guidance +model_name: gpt-4o +temperature: 0.7 +max_loops: 1 +--- + +You are an expert financial advisor with deep knowledge in: + +- Investment strategies and portfolio management +- Personal budgeting and financial planning +- Risk assessment and diversification +- Tax optimization strategies +- Retirement planning + +Your approach: + +- Provide clear, actionable financial advice +- Consider individual risk tolerance and goals +- Explain complex concepts in simple terms +- Always emphasize the importance of diversification +- Include relevant disclaimers about financial advice + +When analyzing financial situations: + +1. Assess current financial position +2. Identify short-term and long-term goals +3. Evaluate risk tolerance +4. Recommend appropriate strategies +5. Suggest specific action steps +``` ## Support diff --git a/examples/agent_loader/agent_loader_demo.py b/examples/agent_loader/agent_loader_demo.py new file mode 100644 index 00000000..1277f349 --- /dev/null +++ b/examples/agent_loader/agent_loader_demo.py @@ -0,0 +1,7 @@ +from swarms.utils import load_agent_from_markdown + +agent = load_agent_from_markdown("finance_advisor.md") + +agent.run( + task="Analyze the financial market trends for 2023." +) \ No newline at end of file diff --git a/examples/agent_loader/finance_advisor.md b/examples/agent_loader/finance_advisor.md new file mode 100644 index 00000000..62c32e51 --- /dev/null +++ b/examples/agent_loader/finance_advisor.md @@ -0,0 +1,28 @@ +--- +name: FinanceAdvisor +description: Expert financial advisor for investment and budgeting guidance +model_name: gpt-4o +temperature: 0.7 +max_loops: 1 +--- + +You are an expert financial advisor with deep knowledge in: +- Investment strategies and portfolio management +- Personal budgeting and financial planning +- Risk assessment and diversification +- Tax optimization strategies +- Retirement planning + +Your approach: +- Provide clear, actionable financial advice +- Consider individual risk tolerance and goals +- Explain complex concepts in simple terms +- Always emphasize the importance of diversification +- Include relevant disclaimers about financial advice + +When analyzing financial situations: +1. Assess current financial position +2. Identify short-term and long-term goals +3. Evaluate risk tolerance +4. Recommend appropriate strategies +5. Suggest specific action steps \ No newline at end of file diff --git a/examples/agent_loader/multi_agents_loader_demo.py b/examples/agent_loader/multi_agents_loader_demo.py new file mode 100644 index 00000000..80d93eb0 --- /dev/null +++ b/examples/agent_loader/multi_agents_loader_demo.py @@ -0,0 +1,22 @@ +from swarms.utils import load_agents_from_markdown + +agents = load_agents_from_markdown([ + "market_researcher.md", + "financial_analyst.md", + "risk_analyst.md" +]) + +# Example 3: Use agents in a workflow +from swarms.structs.sequential_workflow import SequentialWorkflow + +workflow = SequentialWorkflow( + agents=agents, + max_loops=1 +) + +task = """ +Analyze the AI healthcare market for a $50M investment opportunity. +Focus on market size, competition, financials, and risks. +""" + +result = workflow.run(task) \ No newline at end of file From e3c36187992b962a90ec86563fcaa1cfad21bdfe Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Wed, 20 Aug 2025 22:58:21 +0530 Subject: [PATCH 07/12] cleanup ! --- examples/agent_loader_demo.py | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 examples/agent_loader_demo.py diff --git a/examples/agent_loader_demo.py b/examples/agent_loader_demo.py deleted file mode 100644 index bcc127fb..00000000 --- a/examples/agent_loader_demo.py +++ /dev/null @@ -1,28 +0,0 @@ -from swarms.utils.agent_loader import load_agent_from_markdown - -# Example 1: Load a single agent -market_researcher = load_agent_from_markdown("market_researcher.md") - -# Example 2: Load multiple agents -from swarms.utils.agent_loader import load_agents_from_markdown - -agents = load_agents_from_markdown([ - "market_researcher.md", - "financial_analyst.md", - "risk_analyst.md" -]) - -# Example 3: Use agents in a workflow -from swarms.structs.sequential_workflow import SequentialWorkflow - -workflow = SequentialWorkflow( - agents=agents, - max_loops=1 -) - -task = """ -Analyze the AI healthcare market for a $50M investment opportunity. -Focus on market size, competition, financials, and risks. -""" - -result = workflow.run(task) \ No newline at end of file From 14dcc612dc3aee9e5e28f236eae17a0868e7e535 Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Wed, 20 Aug 2025 23:04:48 +0530 Subject: [PATCH 08/12] fixed --- swarms/utils/__init__.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/swarms/utils/__init__.py b/swarms/utils/__init__.py index 40a0cbb7..4d41cd2c 100644 --- a/swarms/utils/__init__.py +++ b/swarms/utils/__init__.py @@ -21,10 +21,6 @@ from swarms.utils.history_output_formatter import ( history_output_formatter, ) -from swarms.utils.check_all_model_max_tokens import ( - check_all_model_max_tokens, -) - from swarms.utils.agent_loader import ( AgentLoader, MarkdownAgentConfig, From 9f414509098c25934197746a12e4529db066df69 Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Wed, 20 Aug 2025 23:09:58 +0530 Subject: [PATCH 09/12] updates ! --- docs/swarms/utils/agent_loader.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/swarms/utils/agent_loader.md b/docs/swarms/utils/agent_loader.md index 74319f75..d8ba42db 100644 --- a/docs/swarms/utils/agent_loader.md +++ b/docs/swarms/utils/agent_loader.md @@ -5,6 +5,7 @@ The `AgentLoader` is a powerful utility for creating Swarms agents from markdown ## Overview The AgentLoader enables you to: + - Load single agents from markdown files with YAML frontmatter - Load multiple agents from directories or file lists with concurrent processing - Parse Claude Code sub-agent YAML frontmatter configurations @@ -43,6 +44,7 @@ the subagent should follow. ``` **Schema Fields:** + - `name` (required): Your sub-agent name - `description` (required): Description of when this subagent should be invoked - `model_name` (optional): Name of model (defaults to random selection if not provided) @@ -229,7 +231,7 @@ except Exception as e: ### Multi-Core Performance -The AgentLoader utilizes **100% of CPU cores** for concurrent agent loading, providing significant performance improvements when processing multiple markdown files: +The AgentLoader utilizes 100% of CPU cores for concurrent agent loading, providing significant performance improvements when processing multiple markdown files: ```python from swarms.utils import load_agents_from_markdown @@ -445,6 +447,7 @@ When analyzing financial situations: ## 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 \ No newline at end of file From ded6d86a23dc980f64ea3dbab4a9c5212ffdf92b Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Wed, 20 Aug 2025 23:18:21 +0530 Subject: [PATCH 10/12] fixes ! --- docs/mkdocs.yml | 2 +- swarms/utils/agent_loader.py | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index ff2bc4cc..29db2115 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -326,6 +326,7 @@ nav: - Overview: "swarms_tools/overview.md" - BaseTool Reference: "swarms/tools/base_tool.md" - MCP Client Utils: "swarms/tools/mcp_client_call.md" + - Agent Loader: "swarms/utils/agent_loader.md" - Vertical Tools: - Finance: "swarms_tools/finance.md" @@ -369,7 +370,6 @@ nav: - Utils: - Agent with Streaming: "examples/agent_stream.md" - Agent Output Types: "swarms/examples/agent_output_types.md" - - Agent Loader: "swarms/utils/agent_loader.md" - Gradio Chat Interface: "swarms/ui/main.md" - LLM Providers: - Overview: "swarms/examples/model_providers.md" diff --git a/swarms/utils/agent_loader.py b/swarms/utils/agent_loader.py index 58a81928..ee3b0e89 100644 --- a/swarms/utils/agent_loader.py +++ b/swarms/utils/agent_loader.py @@ -10,7 +10,7 @@ from concurrent.futures import ( from pydantic import BaseModel, Field, field_validator from loguru import logger -from swarms.structs.agent import Agent +# Lazy import to avoid circular dependency # Default model configuration DEFAULT_MODEL = "gpt-4o" @@ -186,7 +186,7 @@ class AgentLoader: def load_agent_from_markdown( self, file_path: str, **kwargs - ) -> Agent: + ) -> "Agent": """ Load a single agent from a markdown file. @@ -222,6 +222,9 @@ class AgentLoader: agent_fields[config_key] = config_value try: + # Lazy import to avoid circular dependency + from swarms.structs.agent import Agent + logger.info( f"Creating agent '{config.name}' from {file_path}" ) @@ -248,7 +251,7 @@ class AgentLoader: max_workers: Optional[int] = None, max_file_size_mb: float = 10.0, **kwargs, - ) -> List[Agent]: + ) -> List["Agent"]: """ Load multiple agents from markdown files with optional concurrent processing. @@ -370,7 +373,7 @@ class AgentLoader: ) return agents - def load_single_agent(self, file_path: str, **kwargs) -> Agent: + def load_single_agent(self, file_path: str, **kwargs) -> "Agent": """ Convenience method for loading a single agent. Uses Claude Code sub-agent YAML frontmatter format. @@ -386,7 +389,7 @@ class AgentLoader: def load_multiple_agents( self, file_paths: Union[str, List[str]], **kwargs - ) -> List[Agent]: + ) -> List["Agent"]: """ Convenience method for loading multiple agents. Uses Claude Code sub-agent YAML frontmatter format. @@ -402,7 +405,7 @@ class AgentLoader: # Convenience functions -def load_agent_from_markdown(file_path: str, **kwargs) -> Agent: +def load_agent_from_markdown(file_path: str, **kwargs) -> "Agent": """ Load a single agent from a markdown file with Claude Code YAML frontmatter format. @@ -422,7 +425,7 @@ def load_agents_from_markdown( concurrent: bool = True, max_file_size_mb: float = 10.0, **kwargs, -) -> List[Agent]: +) -> List["Agent"]: """ Load multiple agents from markdown files with Claude Code YAML frontmatter format. From d487534e9283559f6acdbb73800114764afee0c7 Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Wed, 20 Aug 2025 23:29:57 +0530 Subject: [PATCH 11/12] fixed ! --- docs/mkdocs.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 29db2115..abb07aeb 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -320,13 +320,15 @@ nav: - Storage: - AgentRegistry: "swarms/structs/agent_registry.md" + - Agent Loader: + - Agent Loader: "swarms/utils/agent_loader.md" + - Communication Structure: "swarms/structs/conversation.md" - Tools: - Overview: "swarms_tools/overview.md" - BaseTool Reference: "swarms/tools/base_tool.md" - MCP Client Utils: "swarms/tools/mcp_client_call.md" - - Agent Loader: "swarms/utils/agent_loader.md" - Vertical Tools: - Finance: "swarms_tools/finance.md" From ea55624d9fa1794bcb6eb5a3249586f71e2fd153 Mon Sep 17 00:00:00 2001 From: harshalmore31 Date: Wed, 20 Aug 2025 23:32:33 +0530 Subject: [PATCH 12/12] updates --- docs/swarms/utils/agent_loader.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/swarms/utils/agent_loader.md b/docs/swarms/utils/agent_loader.md index d8ba42db..dc749156 100644 --- a/docs/swarms/utils/agent_loader.md +++ b/docs/swarms/utils/agent_loader.md @@ -1,4 +1,4 @@ -# AgentLoader - Load Agents from Markdown Files +# AgentLoader Documentation The `AgentLoader` is a powerful utility for creating Swarms agents from markdown files using the Claude Code sub-agent format. It supports both single and multiple markdown file loading, providing a flexible way to define and deploy agents using YAML frontmatter configuration.