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