Spaces:
Runtime error
Runtime error
Commit
·
cddf0a7
1
Parent(s):
1a48dce
Add application files
Browse files- app.py +145 -28
- mcp/agents/autonomous_agent_hf.py +3 -2
app.py
CHANGED
|
@@ -556,15 +556,29 @@ async def setup_client_company(company_name: str, progress=gr.Progress()):
|
|
| 556 |
yield f"❌ Agent init failed: {e}"
|
| 557 |
return
|
| 558 |
|
| 559 |
-
task = f"""Research {company_name} to understand:
|
| 560 |
-
1. What
|
| 561 |
2. Their target market and ideal customers
|
| 562 |
3. Their industry and market position
|
| 563 |
4. Their value proposition
|
| 564 |
5. What type of companies would be good prospects for them
|
| 565 |
|
| 566 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 567 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 568 |
try:
|
| 569 |
async for event in agent.run(task, max_iterations=12):
|
| 570 |
event_type = event.get("type")
|
|
@@ -572,12 +586,13 @@ Save all findings. This is OUR company - we need this to find matching prospects
|
|
| 572 |
tool = event.get("tool", "")
|
| 573 |
if tool == "search_web":
|
| 574 |
output += f"🔍 Searching for {company_name}...\n"
|
|
|
|
| 575 |
elif tool == "search_news":
|
| 576 |
output += f"📰 Finding news...\n"
|
| 577 |
elif tool in ["save_company", "save_fact"]:
|
| 578 |
output += f"💾 Saving information...\n"
|
| 579 |
yield output
|
| 580 |
-
progress(0.
|
| 581 |
elif event_type == "tool_result":
|
| 582 |
tool = event.get("tool", "")
|
| 583 |
result = event.get("result", {})
|
|
@@ -585,8 +600,13 @@ Save all findings. This is OUR company - we need this to find matching prospects
|
|
| 585 |
count = result.get("count", 0) if isinstance(result, dict) else 0
|
| 586 |
output += f" ✅ Found {count} results\n"
|
| 587 |
yield output
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 588 |
elif event_type == "agent_complete":
|
| 589 |
-
final_answer = event.get("final_answer", "")
|
| 590 |
knowledge_base["client"] = {
|
| 591 |
"name": company_name,
|
| 592 |
"raw_research": final_answer,
|
|
@@ -598,8 +618,44 @@ Save all findings. This is OUR company - we need this to find matching prospects
|
|
| 598 |
yield output
|
| 599 |
progress(1.0)
|
| 600 |
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 601 |
except Exception as e:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 602 |
output += f"\n⚠️ Error: {e}\n"
|
|
|
|
| 603 |
yield output
|
| 604 |
|
| 605 |
|
|
@@ -639,26 +695,42 @@ async def discover_prospects(num_prospects: int = 5, progress=gr.Progress()):
|
|
| 639 |
yield f"❌ Agent init failed: {e}"
|
| 640 |
return
|
| 641 |
|
| 642 |
-
task = f"""You are finding prospects for {client_name}.
|
| 643 |
|
| 644 |
About {client_name}:
|
| 645 |
{client_info}
|
| 646 |
|
| 647 |
-
|
| 648 |
-
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
|
| 653 |
-
|
| 654 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 655 |
|
| 656 |
Focus on finding companies that:
|
| 657 |
- Would benefit from {client_name}'s products/services
|
| 658 |
- Are in industries that match {client_name}'s target market
|
| 659 |
-
- Are the right size and stage
|
| 660 |
|
| 661 |
-
|
| 662 |
|
| 663 |
prospects_found = []
|
| 664 |
contacts_found = []
|
|
@@ -671,6 +743,7 @@ For each prospect, explain WHY they're a good fit for {client_name}."""
|
|
| 671 |
|
| 672 |
try:
|
| 673 |
iteration = 0
|
|
|
|
| 674 |
async for event in agent.run(task, max_iterations=25):
|
| 675 |
event_type = event.get("type")
|
| 676 |
iteration += 1
|
|
@@ -704,9 +777,16 @@ For each prospect, explain WHY they're a good fit for {client_name}."""
|
|
| 704 |
}
|
| 705 |
elif tool == "save_contact":
|
| 706 |
if isinstance(tool_input, dict):
|
| 707 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 708 |
title = tool_input.get("title", "")
|
| 709 |
-
company
|
|
|
|
| 710 |
output += f"👤 Found contact: {name} ({title})\n"
|
| 711 |
# Capture contact data during tool_call
|
| 712 |
pending_contact = {
|
|
@@ -734,15 +814,21 @@ For each prospect, explain WHY they're a good fit for {client_name}."""
|
|
| 734 |
tool = event.get("tool", "")
|
| 735 |
result = event.get("result", {})
|
| 736 |
|
| 737 |
-
if tool == "save_prospect"
|
| 738 |
-
|
| 739 |
-
|
| 740 |
-
|
|
|
|
|
|
|
|
|
|
| 741 |
|
| 742 |
-
elif tool == "save_contact"
|
| 743 |
-
|
| 744 |
-
|
| 745 |
-
|
|
|
|
|
|
|
|
|
|
| 746 |
|
| 747 |
elif tool == "send_email":
|
| 748 |
output += f" ✅ Email drafted\n"
|
|
@@ -756,13 +842,19 @@ For each prospect, explain WHY they're a good fit for {client_name}."""
|
|
| 756 |
|
| 757 |
yield output
|
| 758 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 759 |
elif event_type == "agent_complete":
|
| 760 |
# Save all to knowledge base
|
| 761 |
knowledge_base["prospects"].extend(prospects_found)
|
| 762 |
knowledge_base["contacts"].extend(contacts_found)
|
| 763 |
knowledge_base["emails"].extend(emails_drafted)
|
| 764 |
|
| 765 |
-
final_answer = event.get("final_answer", "")
|
| 766 |
|
| 767 |
output += "\n---\n\n"
|
| 768 |
output += f"## ✅ Discovery Complete!\n\n"
|
|
@@ -787,7 +879,32 @@ For each prospect, explain WHY they're a good fit for {client_name}."""
|
|
| 787 |
|
| 788 |
output += "\n---\n\n"
|
| 789 |
output += f"## ⏱️ Discovery Summary (Partial)\n\n"
|
| 790 |
-
output += f"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 791 |
yield output
|
| 792 |
return
|
| 793 |
|
|
|
|
| 556 |
yield f"❌ Agent init failed: {e}"
|
| 557 |
return
|
| 558 |
|
| 559 |
+
task = f"""Research {company_name} to understand their business. Use search_web to find information about:
|
| 560 |
+
1. What {company_name} does - their products/services
|
| 561 |
2. Their target market and ideal customers
|
| 562 |
3. Their industry and market position
|
| 563 |
4. Their value proposition
|
| 564 |
5. What type of companies would be good prospects for them
|
| 565 |
|
| 566 |
+
Use the save_company tool to save information about {company_name}:
|
| 567 |
+
- company_id: "{company_name.lower().replace(' ', '_')}"
|
| 568 |
+
- name: "{company_name}"
|
| 569 |
+
- domain: their website domain
|
| 570 |
+
- industry: their industry
|
| 571 |
+
- description: brief company description
|
| 572 |
|
| 573 |
+
After researching, provide a comprehensive summary of:
|
| 574 |
+
- What {company_name} does
|
| 575 |
+
- Who their ideal customers are
|
| 576 |
+
- What industries/company types would benefit from their services
|
| 577 |
+
|
| 578 |
+
This is OUR company - we need this information to find matching prospects."""
|
| 579 |
+
|
| 580 |
+
last_research = "" # Track last AI response for fallback
|
| 581 |
+
search_count = 0
|
| 582 |
try:
|
| 583 |
async for event in agent.run(task, max_iterations=12):
|
| 584 |
event_type = event.get("type")
|
|
|
|
| 586 |
tool = event.get("tool", "")
|
| 587 |
if tool == "search_web":
|
| 588 |
output += f"🔍 Searching for {company_name}...\n"
|
| 589 |
+
search_count += 1
|
| 590 |
elif tool == "search_news":
|
| 591 |
output += f"📰 Finding news...\n"
|
| 592 |
elif tool in ["save_company", "save_fact"]:
|
| 593 |
output += f"💾 Saving information...\n"
|
| 594 |
yield output
|
| 595 |
+
progress(0.3 + min(search_count * 0.1, 0.4))
|
| 596 |
elif event_type == "tool_result":
|
| 597 |
tool = event.get("tool", "")
|
| 598 |
result = event.get("result", {})
|
|
|
|
| 600 |
count = result.get("count", 0) if isinstance(result, dict) else 0
|
| 601 |
output += f" ✅ Found {count} results\n"
|
| 602 |
yield output
|
| 603 |
+
elif event_type == "thought":
|
| 604 |
+
# Capture AI thoughts for potential use as research summary
|
| 605 |
+
thought = event.get("thought", "")
|
| 606 |
+
if thought and len(thought) > len(last_research):
|
| 607 |
+
last_research = thought
|
| 608 |
elif event_type == "agent_complete":
|
| 609 |
+
final_answer = event.get("final_answer", "") or last_research
|
| 610 |
knowledge_base["client"] = {
|
| 611 |
"name": company_name,
|
| 612 |
"raw_research": final_answer,
|
|
|
|
| 618 |
yield output
|
| 619 |
progress(1.0)
|
| 620 |
return
|
| 621 |
+
elif event_type == "agent_max_iterations":
|
| 622 |
+
# Still save what we have
|
| 623 |
+
final_answer = last_research or f"Research completed for {company_name}. Ready to find prospects."
|
| 624 |
+
knowledge_base["client"] = {
|
| 625 |
+
"name": company_name,
|
| 626 |
+
"raw_research": final_answer,
|
| 627 |
+
"researched_at": datetime.now().strftime("%Y-%m-%d %H:%M")
|
| 628 |
+
}
|
| 629 |
+
output += f"\n---\n\n## ✅ {company_name} Profile Complete!\n\n"
|
| 630 |
+
output += "**Next step:** Go to the **Prospects** tab and click **'🔍 Find Prospects'** to let AI discover potential customers.\n\n"
|
| 631 |
+
if final_answer:
|
| 632 |
+
output += f"---\n\n### 📋 Research Summary\n\n{final_answer}"
|
| 633 |
+
yield output
|
| 634 |
+
progress(1.0)
|
| 635 |
+
return
|
| 636 |
+
elif event_type == "agent_error":
|
| 637 |
+
error_msg = event.get("error", "Unknown error")
|
| 638 |
+
# Still save basic profile so user can proceed
|
| 639 |
+
knowledge_base["client"] = {
|
| 640 |
+
"name": company_name,
|
| 641 |
+
"raw_research": last_research or f"{company_name} - manual research may be needed.",
|
| 642 |
+
"researched_at": datetime.now().strftime("%Y-%m-%d %H:%M")
|
| 643 |
+
}
|
| 644 |
+
output += f"\n⚠️ AI encountered an issue: {error_msg}\n"
|
| 645 |
+
output += f"\n---\n\n## ⚠️ {company_name} Setup (Partial)\n\n"
|
| 646 |
+
output += "**Note:** Some research may be incomplete. You can still proceed to find prospects.\n\n"
|
| 647 |
+
yield output
|
| 648 |
+
progress(1.0)
|
| 649 |
+
return
|
| 650 |
except Exception as e:
|
| 651 |
+
# Save basic profile on exception so user can still proceed
|
| 652 |
+
knowledge_base["client"] = {
|
| 653 |
+
"name": company_name,
|
| 654 |
+
"raw_research": last_research or f"{company_name} - setup interrupted.",
|
| 655 |
+
"researched_at": datetime.now().strftime("%Y-%m-%d %H:%M")
|
| 656 |
+
}
|
| 657 |
output += f"\n⚠️ Error: {e}\n"
|
| 658 |
+
output += f"\n**Note:** Basic profile saved. You can still try to find prospects.\n"
|
| 659 |
yield output
|
| 660 |
|
| 661 |
|
|
|
|
| 695 |
yield f"❌ Agent init failed: {e}"
|
| 696 |
return
|
| 697 |
|
| 698 |
+
task = f"""You are an AI sales agent finding prospects for {client_name}.
|
| 699 |
|
| 700 |
About {client_name}:
|
| 701 |
{client_info}
|
| 702 |
|
| 703 |
+
IMPORTANT: You MUST use the tools to save data. Follow these steps for EACH prospect:
|
| 704 |
+
|
| 705 |
+
1. Use search_web to find {num_prospects} companies that would be ideal customers for {client_name}
|
| 706 |
+
2. For EACH company found, you MUST:
|
| 707 |
+
a. Use save_prospect tool with these parameters:
|
| 708 |
+
- prospect_id: unique ID like "prospect_1"
|
| 709 |
+
- company_id: unique ID like "company_1"
|
| 710 |
+
- company_name: the company name
|
| 711 |
+
- company_domain: the company website domain
|
| 712 |
+
- fit_score: 1-100 score
|
| 713 |
+
- metadata: {{"summary": "company description", "industry": "their industry", "fit_reason": "why they're a good fit"}}
|
| 714 |
+
|
| 715 |
+
b. Use save_contact tool for 2-3 decision makers with:
|
| 716 |
+
- contact_id: unique ID
|
| 717 |
+
- company_id: same as above
|
| 718 |
+
- email: their email if known or generate likely format like "[email protected]"
|
| 719 |
+
- first_name: their first name
|
| 720 |
+
- last_name: their last name
|
| 721 |
+
- title: their job title (CEO, VP Sales, CTO, etc.)
|
| 722 |
+
|
| 723 |
+
c. Use send_email tool to draft outreach:
|
| 724 |
+
- to: the contact email
|
| 725 |
+
- subject: personalized subject line
|
| 726 |
+
- body: personalized email body
|
| 727 |
+
- prospect_id: the prospect_id from step a
|
| 728 |
|
| 729 |
Focus on finding companies that:
|
| 730 |
- Would benefit from {client_name}'s products/services
|
| 731 |
- Are in industries that match {client_name}'s target market
|
|
|
|
| 732 |
|
| 733 |
+
After processing all {num_prospects} prospects, provide a brief summary of what you found."""
|
| 734 |
|
| 735 |
prospects_found = []
|
| 736 |
contacts_found = []
|
|
|
|
| 743 |
|
| 744 |
try:
|
| 745 |
iteration = 0
|
| 746 |
+
last_final_answer = "" # Track the last complete response from AI
|
| 747 |
async for event in agent.run(task, max_iterations=25):
|
| 748 |
event_type = event.get("type")
|
| 749 |
iteration += 1
|
|
|
|
| 777 |
}
|
| 778 |
elif tool == "save_contact":
|
| 779 |
if isinstance(tool_input, dict):
|
| 780 |
+
# Handle both "name" and "first_name/last_name" formats
|
| 781 |
+
first_name = tool_input.get("first_name", "")
|
| 782 |
+
last_name = tool_input.get("last_name", "")
|
| 783 |
+
if first_name or last_name:
|
| 784 |
+
name = f"{first_name} {last_name}".strip()
|
| 785 |
+
else:
|
| 786 |
+
name = tool_input.get("name", "Unknown")
|
| 787 |
title = tool_input.get("title", "")
|
| 788 |
+
# Get company from company_id or current context
|
| 789 |
+
company = tool_input.get("company_name") or tool_input.get("company_id") or current_prospect_name or "Unknown"
|
| 790 |
output += f"👤 Found contact: {name} ({title})\n"
|
| 791 |
# Capture contact data during tool_call
|
| 792 |
pending_contact = {
|
|
|
|
| 814 |
tool = event.get("tool", "")
|
| 815 |
result = event.get("result", {})
|
| 816 |
|
| 817 |
+
if tool == "save_prospect":
|
| 818 |
+
if pending_prospect:
|
| 819 |
+
prospects_found.append(pending_prospect)
|
| 820 |
+
output += f" ✅ Prospect saved: {pending_prospect.get('name', 'Unknown')}\n"
|
| 821 |
+
pending_prospect = None
|
| 822 |
+
else:
|
| 823 |
+
output += f" ✅ Prospect saved\n"
|
| 824 |
|
| 825 |
+
elif tool == "save_contact":
|
| 826 |
+
if pending_contact:
|
| 827 |
+
contacts_found.append(pending_contact)
|
| 828 |
+
output += f" ✅ Contact saved: {pending_contact.get('name', 'Unknown')}\n"
|
| 829 |
+
pending_contact = None
|
| 830 |
+
else:
|
| 831 |
+
output += f" ✅ Contact saved\n"
|
| 832 |
|
| 833 |
elif tool == "send_email":
|
| 834 |
output += f" ✅ Email drafted\n"
|
|
|
|
| 842 |
|
| 843 |
yield output
|
| 844 |
|
| 845 |
+
elif event_type == "thought":
|
| 846 |
+
# Capture AI thoughts/responses as potential final answer
|
| 847 |
+
thought = event.get("thought", "")
|
| 848 |
+
if thought:
|
| 849 |
+
last_final_answer = thought
|
| 850 |
+
|
| 851 |
elif event_type == "agent_complete":
|
| 852 |
# Save all to knowledge base
|
| 853 |
knowledge_base["prospects"].extend(prospects_found)
|
| 854 |
knowledge_base["contacts"].extend(contacts_found)
|
| 855 |
knowledge_base["emails"].extend(emails_drafted)
|
| 856 |
|
| 857 |
+
final_answer = event.get("final_answer", "") or last_final_answer
|
| 858 |
|
| 859 |
output += "\n---\n\n"
|
| 860 |
output += f"## ✅ Discovery Complete!\n\n"
|
|
|
|
| 879 |
|
| 880 |
output += "\n---\n\n"
|
| 881 |
output += f"## ⏱️ Discovery Summary (Partial)\n\n"
|
| 882 |
+
output += f"| Metric | Count |\n"
|
| 883 |
+
output += f"|--------|-------|\n"
|
| 884 |
+
output += f"| Prospects Found | {len(prospects_found)} |\n"
|
| 885 |
+
output += f"| Decision Makers | {len(contacts_found)} |\n"
|
| 886 |
+
output += f"| Emails Drafted | {len(emails_drafted)} |\n\n"
|
| 887 |
+
if last_final_answer:
|
| 888 |
+
output += "---\n\n### 📋 AI Summary\n\n"
|
| 889 |
+
output += last_final_answer
|
| 890 |
+
yield output
|
| 891 |
+
return
|
| 892 |
+
|
| 893 |
+
elif event_type == "agent_error":
|
| 894 |
+
# Save what we found so far even on error
|
| 895 |
+
knowledge_base["prospects"].extend(prospects_found)
|
| 896 |
+
knowledge_base["contacts"].extend(contacts_found)
|
| 897 |
+
knowledge_base["emails"].extend(emails_drafted)
|
| 898 |
+
|
| 899 |
+
error_msg = event.get("error", "Unknown error")
|
| 900 |
+
output += f"\n⚠️ AI Error: {error_msg}\n"
|
| 901 |
+
output += f"\n---\n\n"
|
| 902 |
+
output += f"## ⚠️ Discovery Interrupted\n\n"
|
| 903 |
+
output += f"| Metric | Count |\n"
|
| 904 |
+
output += f"|--------|-------|\n"
|
| 905 |
+
output += f"| Prospects Found | {len(prospects_found)} |\n"
|
| 906 |
+
output += f"| Decision Makers | {len(contacts_found)} |\n"
|
| 907 |
+
output += f"| Emails Drafted | {len(emails_drafted)} |\n\n"
|
| 908 |
yield output
|
| 909 |
return
|
| 910 |
|
mcp/agents/autonomous_agent_hf.py
CHANGED
|
@@ -305,10 +305,11 @@ When you have completed the task, provide a summary of what you accomplished."""
|
|
| 305 |
final_content = assistant_message.content or ""
|
| 306 |
|
| 307 |
if final_content:
|
|
|
|
| 308 |
yield {
|
| 309 |
"type": "thought",
|
| 310 |
-
"thought": final_content
|
| 311 |
-
"message": f"AI Response"
|
| 312 |
}
|
| 313 |
|
| 314 |
# Check if this looks like a final answer (after at least one iteration)
|
|
|
|
| 305 |
final_content = assistant_message.content or ""
|
| 306 |
|
| 307 |
if final_content:
|
| 308 |
+
# Yield full thought content for capture, truncated for display message
|
| 309 |
yield {
|
| 310 |
"type": "thought",
|
| 311 |
+
"thought": final_content, # Full content for capture
|
| 312 |
+
"message": f"AI Response: {final_content[:100]}..." if len(final_content) > 100 else f"AI Response: {final_content}"
|
| 313 |
}
|
| 314 |
|
| 315 |
# Check if this looks like a final answer (after at least one iteration)
|