Overview

This workflow combines web crawling, search engines, Wikipedia, and competitor analysis to create detailed supplier profiles. It processes company information through 4 specialized agents running in parallel, then generates a structured markdown report and sends it via email. The workflow uses workflow session state management to cache analysis results. If the same supplier is analyzed again, it returns cached results instead of re-running the expensive analysis pipeline.

Getting Started

Prerequisites

Quick Setup

export OPENAI_API_KEY="your-openai-key"
export RESEND_API_KEY="your-resend-key"
export FIRECRAWL_API_KEY="your-firecrawl-key"
Install dependencies
pip install agno openai firecrawl-py resend

Code Structure

This company description workflow consists of three main files:

1. Agents (agents.py)

Specialized agents for gathering information from multiple sources:
agents.py
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.duckduckgo import DuckDuckGoTools
from agno.tools.firecrawl import FirecrawlTools
from agno.tools.wikipedia import WikipediaTools
from prompts import (
    COMPETITOR_INSTRUCTIONS,
    CRAWLER_INSTRUCTIONS,
    SEARCH_INSTRUCTIONS,
    SUPPLIER_PROFILE_INSTRUCTIONS_GENERAL,
    WIKIPEDIA_INSTRUCTIONS,
)
from pydantic import BaseModel


class SupplierProfile(BaseModel):
    supplier_name: str
    supplier_homepage_url: str
    user_email: str


crawl_agent: Agent = Agent(
    model=OpenAIChat(id="gpt-5-mini"),
    tools=[FirecrawlTools(crawl=True, limit=5)],
    instructions=CRAWLER_INSTRUCTIONS,
)

search_agent: Agent = Agent(
    model=OpenAIChat(id="gpt-5-mini"),
    tools=[DuckDuckGoTools()],
    instructions=SEARCH_INSTRUCTIONS,
)

wikipedia_agent: Agent = Agent(
    model=OpenAIChat(id="gpt-5-mini"),
    tools=[WikipediaTools()],
    instructions=WIKIPEDIA_INSTRUCTIONS,
)

competitor_agent: Agent = Agent(
    model=OpenAIChat(id="gpt-5-mini"),
    tools=[DuckDuckGoTools()],
    instructions=COMPETITOR_INSTRUCTIONS,
)

profile_agent: Agent = Agent(
    model=OpenAIChat(id="gpt-5-mini"),
    instructions=SUPPLIER_PROFILE_INSTRUCTIONS_GENERAL,
)

2. Prompts (prompts.py)

Detailed instructions for each specialized agent:
prompts.py
CRAWLER_INSTRUCTIONS = """
Your task is to crawl a website starting from the provided homepage URL. Follow these guidelines:

1. Initial Access: Begin by accessing the homepage URL.
2. Comprehensive Crawling: Recursively traverse the website to capture every accessible page and resource.
3. Data Extraction: Extract all available content, including text, images, metadata, and embedded resources, while preserving the original structure and context.
4. Detailed Reporting: Provide an extremely detailed and comprehensive response, including all extracted content without filtering or omissions.
5. Data Integrity: Ensure that the extracted content accurately reflects the website without any modifications.
"""

SEARCH_INSTRUCTIONS = """
You are tasked with searching the web for information about a supplier. Follow these guidelines:

1. Input: You will be provided with the name of the supplier.
2. Web Search: Perform comprehensive web searches to gather information about the supplier.
3. Latest News: Search for the most recent news and updates regarding the supplier.
4. Information Extraction: From the search results, extract all relevant details about the supplier.
5. Detailed Reporting: Provide an extremely verbose and detailed report that includes all relevant information without filtering or omissions.
"""

WIKIPEDIA_INSTRUCTIONS = """
You are tasked with searching Wikipedia for information about a supplier. Follow these guidelines:

1. Input: You will be provided with the name of the supplier.
2. Wikipedia Search: Use Wikipedia to find comprehensive information about the supplier.
3. Data Extraction: Extract all relevant details available on the supplier, including history, operations, products, and any other pertinent information.
4. Detailed Reporting: Provide an extremely verbose and detailed report that includes all extracted content without filtering or omissions.
"""

COMPETITOR_INSTRUCTIONS = """
You are tasked with finding competitors of a supplier. Follow these guidelines:

1. Input: You will be provided with the name of the supplier.
2. Competitor Search: Search the web for competitors of the supplier.
3. Data Extraction: Extract all relevant details about the competitors.
4. Detailed Reporting: Provide an extremely verbose and detailed report that includes all extracted content without filtering or omissions.
"""

SUPPLIER_PROFILE_INSTRUCTIONS_GENERAL = """
You are a supplier profile agent. You are given a supplier name, results from the supplier homepage and search results regarding the supplier, and Wikipedia results regarding the supplier. You need to be extremely verbose in your response. Do not filter out any content.

You are tasked with generating a segment of a supplier profile. The segment will be provided to you. Make sure to format it in markdown.

General format:

Title: [Title of the segment]

[Segment]

Formatting Guidelines:
1. Ensure the profile is structured, clear, and to the point.
2. Avoid assumptions—only include verified details.
3. Use bullet points and short paragraphs for readability.
4. Cite sources where applicable for credibility.

Objective: This supplier profile should serve as a reliable reference document for businesses evaluating potential suppliers. The details should be extracted from official sources, search results, and any other reputable databases. The profile must provide an in-depth understanding of the supplier's operational, competitive, and financial position to support informed decision-making.

"""

SUPPLIER_PROFILE_DICT = {
    "1. Supplier Overview": """Company Name: [Supplier Name]
Industry: [Industry the supplier operates in]
Headquarters: [City, Country]
Year Founded: [Year]
Key Offerings: [Brief summary of main products or services]
Business Model: [Manufacturing, Wholesale, B2B/B2C, etc.]
Notable Clients & Partnerships: [List known customers or business partners]
Company Mission & Vision: [Summary of supplier's goals and commitments]""",
    #     "2. Website Content Summary": """Extract key details from the supplier's official website:
    # Website URL: [Supplier's official website link]
    # Products & Services Overview:
    #   - [List major product categories or services]
    #   - [Highlight any specialized offerings]
    # Certifications & Compliance: (e.g., ISO, FDA, CE, etc.)
    # Manufacturing & Supply Chain Information:
    #   - Factory locations, supply chain transparency, etc.
    # Sustainability & Corporate Social Responsibility (CSR):
    #   - Environmental impact, ethical sourcing, fair labor practices
    # Customer Support & After-Sales Services:
    #   - Warranty, return policies, support channels""",
    #     "3. Search Engine Insights": """Summarize search results to provide additional context on the supplier's market standing:
    # Latest News & Updates: [Any recent developments, funding rounds, expansions]
    # Industry Mentions: [Publications, blogs, or analyst reviews mentioning the supplier]
    # Regulatory Issues or Legal Disputes: [Any lawsuits, recalls, or compliance issues]
    # Competitive Positioning: [How the supplier compares to competitors in the market]""",
    #     "4. Key Contact Information": """Include publicly available contact details for business inquiries:
    # Email: [Customer support, sales, or partnership email]
    # Phone Number: [+XX-XXX-XXX-XXXX]
    # Office Address: [Headquarters or regional office locations]
    # LinkedIn Profile: [Supplier's LinkedIn page]
    # Other Business Directories: [Crunchbase, Alibaba, etc.]""",
    #     "5. Reputation & Reviews": """Analyze customer and partner feedback from multiple sources:
    # Customer Reviews & Testimonials: [Summarized from Trustpilot, Google Reviews, etc.]
    # Third-Party Ratings: [Any industry-recognized rankings or awards]
    # Complaints & Risks: [Potential risks, delays, quality issues, or fraud warnings]
    # Social Media Presence & Engagement: [Activity on LinkedIn, Twitter, etc.]""",
    #     "6. Additional Insights": """Pricing Model: [Wholesale, subscription, per-unit pricing, etc.]
    # MOQ (Minimum Order Quantity): [If applicable]
    # Return & Refund Policies: [Key policies for buyers]
    # Logistics & Shipping: [Lead times, global shipping capabilities]""",
    #     "7. Supplier Insight": """Provide a deep-dive analysis into the supplier's market positioning and business strategy:
    # Market Trends: [How current market trends impact the supplier]
    # Strategic Advantages: [Unique selling points or competitive edge]
    # Challenges & Risks: [Any operational or market-related challenges]
    # Future Outlook: [Predicted growth or strategic initiatives]""",
    #     "8. Supplier Profiles": """Create a comparative profile if multiple suppliers are being evaluated:
    # Comparative Metrics: [Key differentiators among suppliers]
    # Strengths & Weaknesses: [Side-by-side comparison details]
    # Strategic Fit: [How each supplier aligns with potential buyer needs]""",
    #     "9. Product Portfolio": """Detail the range and depth of the supplier's offerings:
    # Major Product Lines: [Detailed listing of core products or services]
    # Innovations & Specialized Solutions: [Highlight any innovative products or custom solutions]
    # Market Segments: [Industries or consumer segments served by the products]""",
    #     "10. Competitive Intelligence": """Summarize the supplier's competitive landscape:
    # Industry Competitors: [List of main competitors]
    # Market Share: [If available, indicate the supplier's market share]
    # Competitive Strategies: [Pricing, marketing, distribution, etc.]
    # Recent Competitor Moves: [Any recent competitive actions impacting the market]""",
    #     "11. Supplier Quadrant": """Position the supplier within a competitive quadrant analysis:
    # Quadrant Position: [Leader, Challenger, Niche Player, or Visionary]
    # Analysis Criteria: [Innovativeness, operational efficiency, market impact, etc.]
    # Visual Representation: [If applicable, describe or include a link to the quadrant chart]""",
    #     "12. SWOT Analysis": """Perform a comprehensive SWOT analysis:
    # Strengths: [Internal capabilities and competitive advantages]
    # Weaknesses: [Areas for improvement or potential vulnerabilities]
    # Opportunities: [External market opportunities or expansion potentials]
    # Threats: [External risks, competitive pressures, or regulatory challenges]""",
    #     "13. Financial Risk Summary": """Evaluate the financial stability and risk factors:
    # Financial Health: [Overview of revenue, profitability, and growth metrics]
    # Risk Factors: [Credit risk, market volatility, or liquidity issues]
    # Investment Attractiveness: [Analysis for potential investors or partners]""",
    #     "14. Financial Information": """Provide detailed financial data (where publicly available):
    # Revenue Figures: [Latest annual revenue, growth trends]
    # Profitability: [Net income, EBITDA, etc.]
    # Funding & Investment: [Details of any funding rounds, investor names]
    # Financial Reports: [Links or summaries of recent financial statements]
    # Credit Ratings: [If available, include credit ratings or financial stability indicators]""",
}

3. Workflow Implementation (run_workflow.py)

Complete workflow with parallel information gathering and email delivery:
run_workflow.py
import markdown
import resend
from agents import (
    SupplierProfile,
    competitor_agent,
    crawl_agent,
    search_agent,
    wikipedia_agent,
)
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.run.agent import RunOutput
from agno.utils.log import log_error, log_info
from agno.workflow import Parallel, Step, Workflow
from agno.workflow.types import StepInput, StepOutput
from prompts import SUPPLIER_PROFILE_DICT, SUPPLIER_PROFILE_INSTRUCTIONS_GENERAL

crawler_step = Step(
    name="Crawler",
    agent=crawl_agent,
    description="Crawl the supplier homepage for the supplier profile url",
)

search_step = Step(
    name="Search",
    agent=search_agent,
    description="Search for the supplier profile for the supplier name",
)

wikipedia_step = Step(
    name="Wikipedia",
    agent=wikipedia_agent,
    description="Search Wikipedia for the supplier profile for the supplier name",
)

competitor_step = Step(
    name="Competitor",
    agent=competitor_agent,
    description="Find competitors of the supplier name",
)


def generate_supplier_profile(step_input: StepInput) -> StepOutput:
    supplier_profile: SupplierProfile = step_input.input

    supplier_name: str = supplier_profile.supplier_name
    supplier_homepage_url: str = supplier_profile.supplier_homepage_url

    crawler_data: str = step_input.get_step_content("Gathering Information")["Crawler"]
    search_data: str = step_input.get_step_content("Gathering Information")["Search"]
    wikipedia_data: str = step_input.get_step_content("Gathering Information")[
        "Wikipedia"
    ]
    competitor_data: str = step_input.get_step_content("Gathering Information")[
        "Competitor"
    ]

    log_info(f"Crawler data: {crawler_data}")
    log_info(f"Search data: {search_data}")
    log_info(f"Wikipedia data: {wikipedia_data}")
    log_info(f"Competitor data: {competitor_data}")

    supplier_profile_prompt: str = f"Generate the supplier profile for the supplier name {supplier_name} and the supplier homepage url is {supplier_homepage_url}. The supplier homepage is {crawler_data} and the search results are {search_data} and the wikipedia results are {wikipedia_data} and the competitor results are {competitor_data}"

    supplier_profile_response: str = ""
    html_content: str = ""
    for key, value in SUPPLIER_PROFILE_DICT.items():
        agent = Agent(
            model=OpenAIChat(id="gpt-5-mini"),
            instructions="Instructions: "
            + SUPPLIER_PROFILE_INSTRUCTIONS_GENERAL
            + "Format to adhere to: "
            + value,
        )
        response: RunOutput = agent.run(
            "Write the response in markdown format for the title: "
            + key
            + " using the following information: "
            + supplier_profile_prompt
        )
        if response.content:
            html_content += markdown.markdown(response.content)
            supplier_profile_response += response.content

    log_info(f"Generated supplier profile for {html_content}")

    return StepOutput(
        content=html_content,
        success=True,
    )


generate_supplier_profile_step = Step(
    name="Generate Supplier Profile",
    executor=generate_supplier_profile,
    description="Generate the supplier profile for the supplier name",
)


def send_email(step_input: StepInput):
    supplier_profile: SupplierProfile = step_input.input
    supplier_name: str = supplier_profile.supplier_name
    user_email: str = supplier_profile.user_email

    html_content: str = step_input.get_step_content("Generate Supplier Profile")

    try:
        resend.Emails.send(
            {
                "from": "support@agno.com",
                "to": user_email,
                "subject": f"Supplier Profile for {supplier_name}",
                "html": html_content,
            }
        )
    except Exception as e:
        log_error(f"Error sending email: {e}")

    return StepOutput(
        content="Email sent successfully",
        success=True,
    )


send_email_step = Step(
    name="Send Email",
    executor=send_email,
    description="Send the email to the user",
)

company_description_workflow = Workflow(
    name="Company Description Workflow",
    description="A workflow to generate a company description for a supplier",
    steps=[
        Parallel(
            crawler_step,
            search_step,
            wikipedia_step,
            competitor_step,
            name="Gathering Information",
        ),
        generate_supplier_profile_step,
        send_email_step,
    ],
)

if __name__ == "__main__":
    supplier_profile_request = SupplierProfile(
        supplier_name="Agno",
        supplier_homepage_url="https://www.agno.com",
        user_email="yash@agno.com",
    )
    company_description_workflow.print_response(
        input=supplier_profile_request,
    )

Key Features

  • 🔄 Parallel Processing: Four agents gather information simultaneously for maximum efficiency
  • 🌐 Multi-Source Data: Combines web crawling, search engines, Wikipedia, and competitor analysis
  • 📧 Email Integration: Automatically sends formatted reports via email using Resend
  • 📄 Markdown Formatting: Generates structured, readable reports in HTML format
  • 🏗️ Modular Design: Clean separation of agents, prompts, and workflow logic
  • ⚡ Efficient Execution: Uses parallel steps to minimize execution time
  • 🎯 Type Safety: Pydantic models for structured data validation

Usage Example

# Create supplier profile request
supplier_request = SupplierProfile(
    supplier_name="Your Company Name",
    supplier_homepage_url="https://yourcompany.com",
    user_email="your.email@company.com",
)

# Run the workflow
company_description_workflow.print_response(
    input=supplier_request,
)

Expected Output

The workflow will:
  1. Gather Information: Simultaneously crawl the website, search the web, check Wikipedia, and find competitors
  2. Generate Profile: Create a comprehensive supplier profile with detailed sections
  3. Send Email: Deliver the formatted HTML report to the specified email address
The generated supplier profile includes:
  • Company overview and basic information
  • Detailed analysis from multiple data sources
  • Structured markdown formatting for readability
  • Professional email delivery with HTML formatting
Run the workflow with:
python run_workflow.py
More Examples: