mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-17 23:09:35 +00:00
feat: Dealix GTM Intelligence OS — multi-agent system
8 agents + 4 models + 4 configs + CLI dry-run + 3 docs. Tested on agency/real_estate/clinic/saas — all pass. Safety: LinkedIn scraping PROHIBITED, WhatsApp blast PROHIBITED. https://claude.ai/code/session_01W1rJthWDkasijTdXCfxVHs
This commit is contained in:
parent
abb94f4a4e
commit
20277e0afc
0
salesflow-saas/backend/dealix_gtm_os/__init__.py
Normal file
0
salesflow-saas/backend/dealix_gtm_os/__init__.py
Normal file
@ -0,0 +1,9 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
class BaseAgent(ABC):
|
||||
name: str = "base"
|
||||
description: str = ""
|
||||
|
||||
@abstractmethod
|
||||
async def run(self, input_data: dict) -> dict:
|
||||
pass
|
||||
@ -0,0 +1,32 @@
|
||||
from dealix_gtm_os.agents.base_agent import BaseAgent
|
||||
from dealix_gtm_os.models.message import ChannelType, AutomationLevel
|
||||
|
||||
SECTOR_CHANNELS = {
|
||||
"agency": (ChannelType.EMAIL, ChannelType.LINKEDIN_MANUAL),
|
||||
"real_estate": (ChannelType.EMAIL, ChannelType.WHATSAPP_WARM),
|
||||
"clinic": (ChannelType.WHATSAPP_WARM, ChannelType.EMAIL),
|
||||
"saas": (ChannelType.EMAIL, ChannelType.LINKEDIN_MANUAL),
|
||||
"ecommerce": (ChannelType.EMAIL, ChannelType.INSTAGRAM_INBOUND),
|
||||
"construction": (ChannelType.EMAIL, ChannelType.PHONE),
|
||||
"training": (ChannelType.EMAIL, ChannelType.WHATSAPP_WARM),
|
||||
"consulting": (ChannelType.LINKEDIN_MANUAL, ChannelType.EMAIL),
|
||||
"website_agency": (ChannelType.LINKEDIN_MANUAL, ChannelType.EMAIL),
|
||||
}
|
||||
|
||||
class ChannelStrategyAgent(BaseAgent):
|
||||
name = "channel_strategy"
|
||||
description = "Selects best outreach channel per target"
|
||||
|
||||
async def run(self, input_data: dict) -> dict:
|
||||
sector = input_data.get("sector", "").lower().replace(" ", "_")
|
||||
channels = SECTOR_CHANNELS.get(sector, (ChannelType.EMAIL, ChannelType.LINKEDIN_MANUAL))
|
||||
primary, secondary = channels
|
||||
manual_channels = {ChannelType.LINKEDIN_MANUAL, ChannelType.WHATSAPP_WARM, ChannelType.PHONE}
|
||||
level = AutomationLevel.MANUAL_REQUIRED if primary in manual_channels else AutomationLevel.SEMI_AUTOMATED
|
||||
return {
|
||||
"primary_channel": primary.value,
|
||||
"secondary_channel": secondary.value,
|
||||
"automation_level": level.value,
|
||||
"reason": f"Sector {sector} best reached via {primary.value}",
|
||||
"risk_flags": ["manual_approval_required"] if level == AutomationLevel.MANUAL_REQUIRED else [],
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
import json
|
||||
from dealix_gtm_os.agents.base_agent import BaseAgent
|
||||
from dealix_gtm_os.agents.llm_client import call_llm
|
||||
from dealix_gtm_os.models.company import CompanyInput, CompanyIntelligence
|
||||
|
||||
class CompanyResearchAgent(BaseAgent):
|
||||
name = "company_research"
|
||||
description = "Understands a company from available data"
|
||||
|
||||
async def run(self, input_data: dict) -> dict:
|
||||
company = CompanyInput(**input_data)
|
||||
result_json = await call_llm(
|
||||
f"Analyze company: {company.name}, sector: {company.sector}, city: {company.city}",
|
||||
context={"sector": company.sector or ""}
|
||||
)
|
||||
data = json.loads(result_json)
|
||||
intel = CompanyIntelligence(
|
||||
name=company.name,
|
||||
website=company.website,
|
||||
sector=company.sector or data.get("sector", "unknown"),
|
||||
city=company.city or "",
|
||||
confidence=0.7,
|
||||
**{k: v for k, v in data.items() if k in CompanyIntelligence.model_fields}
|
||||
)
|
||||
return intel.model_dump()
|
||||
@ -0,0 +1,32 @@
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from dealix_gtm_os.agents.base_agent import BaseAgent
|
||||
from dealix_gtm_os.models.message import AutomationLevel
|
||||
|
||||
RULES_PATH = Path(__file__).parent.parent / "config" / "compliance_rules.yaml"
|
||||
|
||||
class ComplianceAgent(BaseAgent):
|
||||
name = "compliance"
|
||||
description = "Enforces platform safety rules"
|
||||
|
||||
def __init__(self):
|
||||
if RULES_PATH.exists():
|
||||
with open(RULES_PATH) as f:
|
||||
self.rules = yaml.safe_load(f)
|
||||
else:
|
||||
self.rules = {}
|
||||
|
||||
async def run(self, input_data: dict) -> dict:
|
||||
channel = input_data.get("channel", "email")
|
||||
action = input_data.get("action", "send_message")
|
||||
channel_key = channel.replace("_manual", "").replace("_warm", "").replace("_inbound", "").replace("_post", "").replace("_reply", "")
|
||||
if channel_key == "linkedin":
|
||||
channel_key = "linkedin"
|
||||
elif channel_key in ("x", "twitter"):
|
||||
channel_key = "x_twitter"
|
||||
rules = self.rules.get(channel_key, {})
|
||||
if rules.get(action) == "prohibited" or rules.get("scraping") == "prohibited" and action == "scraping":
|
||||
return {"allowed": False, "level": AutomationLevel.PROHIBITED.value, "reason": f"{action} on {channel} is prohibited by platform policy"}
|
||||
if channel in ("linkedin_manual", "whatsapp_warm", "phone"):
|
||||
return {"allowed": True, "level": AutomationLevel.MANUAL_REQUIRED.value, "reason": f"{channel} requires manual human approval"}
|
||||
return {"allowed": True, "level": AutomationLevel.SEMI_AUTOMATED.value, "reason": f"{channel} is safe with opt-out"}
|
||||
53
salesflow-saas/backend/dealix_gtm_os/agents/llm_client.py
Normal file
53
salesflow-saas/backend/dealix_gtm_os/agents/llm_client.py
Normal file
@ -0,0 +1,53 @@
|
||||
"""Mock LLM client — returns structured responses. Replace with real LLM later."""
|
||||
import json
|
||||
|
||||
SECTOR_INTELLIGENCE = {
|
||||
"agency": {
|
||||
"business_summary": "وكالة تسويق تقدم خدمات إعلانية ورقمية للشركات",
|
||||
"products_services": ["إعلانات رقمية", "إدارة سوشال ميديا", "تصميم", "محتوى"],
|
||||
"target_customers": ["شركات صغيرة ومتوسطة", "عقارات", "عيادات", "متاجر"],
|
||||
"revenue_model": "رسوم خدمات شهرية + نسبة من ميزانية الإعلان",
|
||||
"lead_channels": ["موقع إلكتروني", "سوشال ميديا", "إحالات"],
|
||||
"pain_points": ["عملاء يلومونهم على ضعف التحويل", "لا recurring revenue", "leads العميل تضيع بعد الإعلان"],
|
||||
"partnership_potential": "عالي — يقدرون يبيعون Dealix كخدمة لعملائهم",
|
||||
"opportunity_types": ["agency_partner", "co_selling_partner"],
|
||||
},
|
||||
"real_estate": {
|
||||
"business_summary": "شركة تسويق أو تطوير عقاري",
|
||||
"products_services": ["بيع وتأجير عقارات", "تسويق مشاريع عقارية"],
|
||||
"target_customers": ["مشترين أفراد", "مستثمرين", "مستأجرين"],
|
||||
"revenue_model": "عمولات بيع/تأجير + رسوم تسويق",
|
||||
"lead_channels": ["واتساب", "اتصالات", "نماذج موقع", "إعلانات"],
|
||||
"pain_points": ["60% من الاستفسارات ما تُتابع", "المنافسة عالية", "فريق مبيعات صغير"],
|
||||
"partnership_potential": "متوسط — عميل مباشر",
|
||||
"opportunity_types": ["direct_customer"],
|
||||
},
|
||||
"saas": {
|
||||
"business_summary": "شركة تقنية تقدم حلول برمجية",
|
||||
"products_services": ["برمجيات سحابية", "تطبيقات", "حلول تقنية"],
|
||||
"target_customers": ["شركات", "مؤسسات"],
|
||||
"revenue_model": "اشتراكات شهرية/سنوية",
|
||||
"lead_channels": ["موقع إلكتروني", "إعلانات Google", "LinkedIn"],
|
||||
"pain_points": ["leads من الموقع تبرد", "SDR مكلّف", "فريق صغير"],
|
||||
"partnership_potential": "متوسط — عميل أو integration partner",
|
||||
"opportunity_types": ["direct_customer", "integration_partner"],
|
||||
},
|
||||
}
|
||||
|
||||
DEFAULT_INTEL = {
|
||||
"business_summary": "شركة تقدم خدمات في السوق السعودي",
|
||||
"products_services": ["خدمات متنوعة"],
|
||||
"target_customers": ["شركات ومؤسسات"],
|
||||
"revenue_model": "رسوم خدمات",
|
||||
"lead_channels": ["واتساب", "إيميل", "موقع"],
|
||||
"pain_points": ["استفسارات ما تُتابع", "بطء الرد"],
|
||||
"partnership_potential": "متوسط",
|
||||
"opportunity_types": ["direct_customer"],
|
||||
}
|
||||
|
||||
|
||||
async def call_llm(prompt: str, context: dict | None = None) -> str:
|
||||
"""Mock LLM — returns sector-based intelligence. Replace with real API later."""
|
||||
sector = (context or {}).get("sector", "")
|
||||
intel = SECTOR_INTELLIGENCE.get(sector, DEFAULT_INTEL)
|
||||
return json.dumps(intel, ensure_ascii=False)
|
||||
@ -0,0 +1,61 @@
|
||||
from dealix_gtm_os.agents.base_agent import BaseAgent
|
||||
from dealix_gtm_os.models.message import OutreachMessage, ChannelType, AutomationLevel
|
||||
|
||||
SECTOR_MESSAGES = {
|
||||
"agency": {
|
||||
"first_line": "شفت أنكم تقدمون خدمات تسويق/دعاية لعملاء.",
|
||||
"pain": "عملاؤكم يصرفون على إعلانات والـ leads تضيع بعد الكلك.",
|
||||
"offer": "أضف خدمة متابعة leads لعملائك — 20% لك من كل عميل.",
|
||||
},
|
||||
"real_estate": {
|
||||
"first_line": "لاحظت أن نشاطكم في العقار يعتمد على الاستفسارات.",
|
||||
"pain": "60% من استفسارات الأسعار والمواقع ما تُتابع خلال ساعة.",
|
||||
"offer": "Dealix يرد خلال 45 ثانية ويحجز موعد معاينة.",
|
||||
},
|
||||
"saas": {
|
||||
"first_line": "شفت منتجكم — مشروع قوي.",
|
||||
"pain": "الـ leads من الموقع تبرد خلال ساعة.",
|
||||
"offer": "Dealix يرد فوراً ويؤهل ويحجز demo تلقائياً.",
|
||||
},
|
||||
}
|
||||
|
||||
class MessageGenerationAgent(BaseAgent):
|
||||
name = "message_generation"
|
||||
description = "Generates personalized Arabic outreach messages"
|
||||
|
||||
async def run(self, input_data: dict) -> dict:
|
||||
company = input_data.get("name", "الشركة")
|
||||
sector = input_data.get("sector", "").lower().replace(" ", "_")
|
||||
channel = input_data.get("channel", "email")
|
||||
msgs = SECTOR_MESSAGES.get(sector, SECTOR_MESSAGES.get("saas"))
|
||||
body = f"""السلام عليكم فريق {company}،
|
||||
|
||||
أنا سامي من Dealix.
|
||||
|
||||
{msgs['first_line']}
|
||||
|
||||
المشكلة: {msgs['pain']}
|
||||
|
||||
الحل: {msgs['offer']}
|
||||
|
||||
نسوي pilot 7 أيام بـ 499 ريال مع ضمان استرداد كامل.
|
||||
يناسبكم ديمو 10 دقائق؟
|
||||
📅 calendly.com/sami-assiri11/dealix-demo
|
||||
|
||||
سامي العسيري | مؤسس Dealix | dealix.me
|
||||
|
||||
إذا ما يناسبكم هالنوع من الرسائل، ردوا "إيقاف"."""
|
||||
|
||||
msg = OutreachMessage(
|
||||
target_company=company,
|
||||
channel=ChannelType(channel) if channel in [c.value for c in ChannelType] else ChannelType.EMAIL,
|
||||
automation_level=AutomationLevel.MANUAL_REQUIRED,
|
||||
subject=f"فريق {company} — فكرة لتحسين متابعة العملاء",
|
||||
first_line=msgs["first_line"],
|
||||
body=body,
|
||||
cta="يناسبكم ديمو 10 دقائق؟",
|
||||
follow_up_24h=f"متابعة سريعة — أقدر أوريكم خلال 10 دقائق كيف Dealix يحول الاستفسارات لمتابعة وحجز.",
|
||||
follow_up_72h=f"آخر متابعة مني. مهتم → رد 'مهتم'. إيقاف → رد 'إيقاف'.",
|
||||
approval_required=True,
|
||||
)
|
||||
return msg.model_dump()
|
||||
31
salesflow-saas/backend/dealix_gtm_os/agents/scoring_agent.py
Normal file
31
salesflow-saas/backend/dealix_gtm_os/agents/scoring_agent.py
Normal file
@ -0,0 +1,31 @@
|
||||
from dealix_gtm_os.agents.base_agent import BaseAgent
|
||||
from dealix_gtm_os.models.score import TargetScore
|
||||
|
||||
SECTOR_SCORES = {
|
||||
"agency": {"fit": 5, "urgency": 4, "partner": 5, "payment": 3, "case_study": 4},
|
||||
"real_estate": {"fit": 5, "urgency": 5, "partner": 2, "payment": 4, "case_study": 3},
|
||||
"saas": {"fit": 4, "urgency": 4, "partner": 3, "payment": 3, "case_study": 3},
|
||||
"clinic": {"fit": 4, "urgency": 4, "partner": 1, "payment": 4, "case_study": 3},
|
||||
"ecommerce": {"fit": 4, "urgency": 3, "partner": 2, "payment": 3, "case_study": 2},
|
||||
"construction": {"fit": 3, "urgency": 3, "partner": 1, "payment": 3, "case_study": 2},
|
||||
}
|
||||
|
||||
class ScoringAgent(BaseAgent):
|
||||
name = "scoring"
|
||||
description = "Scores a target company"
|
||||
|
||||
async def run(self, input_data: dict) -> dict:
|
||||
sector = input_data.get("sector", "").lower().replace(" ", "_")
|
||||
defaults = SECTOR_SCORES.get(sector, {"fit": 3, "urgency": 3, "partner": 2, "payment": 3, "case_study": 2})
|
||||
has_email = bool(input_data.get("email") or input_data.get("website"))
|
||||
score = TargetScore(
|
||||
company_name=input_data.get("name", "Unknown"),
|
||||
fit=defaults["fit"],
|
||||
urgency=defaults["urgency"],
|
||||
access=4 if has_email else 2,
|
||||
partner=defaults["partner"],
|
||||
payment=defaults["payment"],
|
||||
case_study=defaults["case_study"],
|
||||
risk=2,
|
||||
)
|
||||
return score.model_dump()
|
||||
@ -0,0 +1,35 @@
|
||||
from dealix_gtm_os.agents.base_agent import BaseAgent
|
||||
from dealix_gtm_os.agents.company_research_agent import CompanyResearchAgent
|
||||
from dealix_gtm_os.agents.scoring_agent import ScoringAgent
|
||||
from dealix_gtm_os.agents.channel_strategy_agent import ChannelStrategyAgent
|
||||
from dealix_gtm_os.agents.compliance_agent import ComplianceAgent
|
||||
from dealix_gtm_os.agents.message_generation_agent import MessageGenerationAgent
|
||||
|
||||
class SupervisorAgent(BaseAgent):
|
||||
name = "supervisor"
|
||||
description = "Orchestrates all GTM agents into a complete pipeline"
|
||||
|
||||
def __init__(self):
|
||||
self.research = CompanyResearchAgent()
|
||||
self.scoring = ScoringAgent()
|
||||
self.channel = ChannelStrategyAgent()
|
||||
self.compliance = ComplianceAgent()
|
||||
self.message = MessageGenerationAgent()
|
||||
|
||||
async def run(self, input_data: dict) -> dict:
|
||||
intel = await self.research.run(input_data)
|
||||
score = await self.scoring.run({**input_data, **intel})
|
||||
channel_plan = await self.channel.run(intel)
|
||||
compliance = await self.compliance.run({"channel": channel_plan["primary_channel"], "action": "send_message"})
|
||||
msg_input = {**intel, "channel": channel_plan["primary_channel"]}
|
||||
message = await self.message.run(msg_input)
|
||||
return {
|
||||
"company": input_data.get("name", "Unknown"),
|
||||
"intelligence": intel,
|
||||
"score": score,
|
||||
"channel_plan": channel_plan,
|
||||
"compliance": compliance,
|
||||
"message": message,
|
||||
"next_action": "send" if compliance["allowed"] else "manual_review",
|
||||
"approval_required": message.get("approval_required", True),
|
||||
}
|
||||
48
salesflow-saas/backend/dealix_gtm_os/config/channels.yaml
Normal file
48
salesflow-saas/backend/dealix_gtm_os/config/channels.yaml
Normal file
@ -0,0 +1,48 @@
|
||||
channels:
|
||||
email:
|
||||
automation_level: semi_automated
|
||||
daily_limit: 10
|
||||
best_for: [b2b, agencies, companies_with_email]
|
||||
requires: [identity, optout, relevant_reason]
|
||||
|
||||
linkedin_manual:
|
||||
automation_level: manual_required
|
||||
daily_limit: 5
|
||||
best_for: [founders, agencies, b2b_decision_makers]
|
||||
requires: [personalization, manual_send]
|
||||
|
||||
whatsapp_warm:
|
||||
automation_level: manual_required
|
||||
daily_limit: 5
|
||||
best_for: [warm_network, optin_leads, demo_confirmations]
|
||||
requires: [existing_relationship_or_optin, stop_condition]
|
||||
|
||||
instagram_inbound:
|
||||
automation_level: semi_automated
|
||||
daily_limit: 3
|
||||
best_for: [local_brands, visual_businesses, inbound_engagement]
|
||||
requires: [prior_engagement, official_api]
|
||||
|
||||
x_post:
|
||||
automation_level: fully_automated
|
||||
daily_limit: 3
|
||||
best_for: [thought_leadership, founder_content, market_insights]
|
||||
requires: [original_content]
|
||||
|
||||
x_reply:
|
||||
automation_level: manual_required
|
||||
daily_limit: 5
|
||||
best_for: [engagement, conversations, founder_community]
|
||||
requires: [value_add, no_spam]
|
||||
|
||||
phone:
|
||||
automation_level: manual_required
|
||||
daily_limit: 3
|
||||
best_for: [warm_leads, post_demo, partner_conversations]
|
||||
requires: [prior_context]
|
||||
|
||||
partner_intro:
|
||||
automation_level: manual_required
|
||||
daily_limit: 2
|
||||
best_for: [agency_partners, referral_partners]
|
||||
requires: [partner_relationship]
|
||||
@ -0,0 +1,64 @@
|
||||
linkedin:
|
||||
scraping: prohibited
|
||||
auto_dm: prohibited
|
||||
auto_connect: prohibited
|
||||
auto_like: prohibited
|
||||
auto_comment: prohibited
|
||||
manual_dm: allowed
|
||||
manual_dm_daily_limit: 5
|
||||
posts: allowed
|
||||
comments: manual_only
|
||||
research: allowed
|
||||
|
||||
email:
|
||||
cold_b2b: allowed_with_optout
|
||||
max_sequence_length: 3
|
||||
identity_required: true
|
||||
optout_required: true
|
||||
daily_limit_initial: 10
|
||||
daily_limit_proven: 20
|
||||
misleading_subject: prohibited
|
||||
|
||||
whatsapp:
|
||||
cold_blast: prohibited
|
||||
warm_optin: allowed
|
||||
templates_with_approval: allowed
|
||||
daily_limit_initial: 5
|
||||
daily_limit_proven: 10
|
||||
stop_words:
|
||||
- "إيقاف"
|
||||
- "stop"
|
||||
- "لا"
|
||||
- "لا شكراً"
|
||||
- "ما يناسبني"
|
||||
|
||||
instagram:
|
||||
mass_dm: prohibited
|
||||
inbound_reply: allowed
|
||||
official_api: allowed
|
||||
warm_dm_after_engagement: allowed
|
||||
daily_dm_limit: 3
|
||||
|
||||
x_twitter:
|
||||
auto_mentions: prohibited
|
||||
auto_replies: prohibited
|
||||
auto_dms: prohibited
|
||||
posts: allowed
|
||||
scheduled_posts: allowed
|
||||
safe_manual_replies: allowed
|
||||
daily_reply_limit: 5
|
||||
|
||||
tiktok:
|
||||
dm_scraping: prohibited
|
||||
mass_dm: prohibited
|
||||
content: allowed
|
||||
lead_form_ads: allowed_official
|
||||
dm_ads: allowed_official
|
||||
|
||||
general:
|
||||
fake_accounts: prohibited
|
||||
fake_engagement: prohibited
|
||||
buying_lead_lists: prohibited
|
||||
scraping_restricted_sites: prohibited
|
||||
overclaiming_results: prohibited
|
||||
guaranteed_revenue_claims: prohibited
|
||||
@ -0,0 +1,72 @@
|
||||
offers:
|
||||
speed_to_lead_audit:
|
||||
name_ar: "تحليل سرعة الرد"
|
||||
price_sar: 0
|
||||
alternative_price: 99
|
||||
duration: "30 دقيقة"
|
||||
purpose: "فتح الباب — ليس بيع"
|
||||
deliverables:
|
||||
- "تحليل أين تضيع الاستفسارات"
|
||||
- "تقييم سرعة الرد الحالية"
|
||||
- "توصية flow بسيط"
|
||||
- "اقتراح pilot مخصص"
|
||||
best_for: [real_estate, clinics, ecommerce]
|
||||
cta: "أقدر أعمل لكم audit مجاني"
|
||||
|
||||
pilot:
|
||||
name_ar: "تجربة 7 أيام"
|
||||
price_sar: 499
|
||||
duration: "7 أيام"
|
||||
purpose: "أول دفع + أول proof"
|
||||
deliverables:
|
||||
- "قناة واحدة (واتساب/إيميل/نماذج)"
|
||||
- "حد 20 lead"
|
||||
- "رسائل متابعة مخصصة"
|
||||
- "تصنيف ردود"
|
||||
- "تقرير نهاية التجربة"
|
||||
guarantee: "استرداد كامل"
|
||||
best_for: [all_sectors]
|
||||
cta: "نبدأ بعميل واحد / قناة واحدة / أسبوع واحد"
|
||||
|
||||
starter:
|
||||
name_ar: "المبتدئ"
|
||||
price_sar: 990
|
||||
billing: monthly
|
||||
purpose: "إيراد متكرر"
|
||||
deliverables:
|
||||
- "واتساب + إيميل"
|
||||
- "follow-up sequences"
|
||||
- "lead tracker"
|
||||
- "booking CTA"
|
||||
- "تقرير أسبوعي"
|
||||
best_for: [proven_pilot_customers]
|
||||
cta: "نكمّل بـ Starter"
|
||||
|
||||
agency_addon:
|
||||
name_ar: "باقة الوكالات"
|
||||
price_sar_range: "1499-2999"
|
||||
purpose: "الوكالة تبيع لعملائها"
|
||||
deliverables:
|
||||
- "إعداد لعميل واحد"
|
||||
- "سكريبتات متابعة"
|
||||
- "tracker + تقارير"
|
||||
- "تدريب بسيط للوكالة"
|
||||
- "قوالب بيع للعميل"
|
||||
partner_share: "20% MRR + 50% setup fee"
|
||||
best_for: [marketing_agencies, digital_agencies]
|
||||
cta: "كن شريك وكالة"
|
||||
|
||||
partner_ops:
|
||||
name_ar: "شراكة مخصصة"
|
||||
price_sar: custom
|
||||
purpose: "شراكات استراتيجية"
|
||||
models: [referral, co_selling, implementation, service_exchange]
|
||||
best_for: [strategic_partners, large_agencies]
|
||||
cta: "نصمم النموذج حسب حجمكم"
|
||||
|
||||
payment:
|
||||
bank: "مصرف الإنماء"
|
||||
account_name: "سامي محمد زايد عسيري — ذكاء الاعمال"
|
||||
account_number: "68207328877000"
|
||||
iban: "SA3305000068207328877000"
|
||||
swift: "INMASARIXXX"
|
||||
@ -0,0 +1,48 @@
|
||||
weights:
|
||||
fit: 1
|
||||
urgency: 1
|
||||
access: 1
|
||||
partner: 1
|
||||
payment: 1
|
||||
case_study: 1
|
||||
risk: -1
|
||||
|
||||
priority_thresholds:
|
||||
send_today: 24
|
||||
send_this_week: 18
|
||||
send_this_month: 12
|
||||
backlog: 0
|
||||
|
||||
sector_defaults:
|
||||
marketing_agency:
|
||||
fit: 5
|
||||
partner: 5
|
||||
urgency: 4
|
||||
real_estate:
|
||||
fit: 5
|
||||
urgency: 5
|
||||
partner: 2
|
||||
clinic:
|
||||
fit: 4
|
||||
urgency: 4
|
||||
partner: 1
|
||||
ecommerce:
|
||||
fit: 4
|
||||
urgency: 3
|
||||
partner: 2
|
||||
website_agency:
|
||||
fit: 4
|
||||
partner: 4
|
||||
urgency: 3
|
||||
consulting:
|
||||
fit: 3
|
||||
partner: 3
|
||||
urgency: 2
|
||||
construction:
|
||||
fit: 3
|
||||
urgency: 3
|
||||
partner: 1
|
||||
training:
|
||||
fit: 3
|
||||
urgency: 3
|
||||
partner: 1
|
||||
28
salesflow-saas/backend/dealix_gtm_os/models/company.py
Normal file
28
salesflow-saas/backend/dealix_gtm_os/models/company.py
Normal file
@ -0,0 +1,28 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
|
||||
class CompanyInput(BaseModel):
|
||||
name: str
|
||||
website: Optional[str] = None
|
||||
sector: Optional[str] = None
|
||||
city: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
source: Optional[str] = None
|
||||
email: Optional[str] = None
|
||||
phone: Optional[str] = None
|
||||
|
||||
class CompanyIntelligence(BaseModel):
|
||||
name: str
|
||||
website: Optional[str] = None
|
||||
sector: str
|
||||
city: str = ""
|
||||
business_summary: str
|
||||
products_services: list[str] = Field(default_factory=list)
|
||||
target_customers: list[str] = Field(default_factory=list)
|
||||
revenue_model: str = ""
|
||||
lead_channels: list[str] = Field(default_factory=list)
|
||||
pain_points: list[str] = Field(default_factory=list)
|
||||
partnership_potential: str = ""
|
||||
opportunity_types: list[str] = Field(default_factory=list)
|
||||
sources: list[str] = Field(default_factory=list)
|
||||
confidence: float = 0.5
|
||||
35
salesflow-saas/backend/dealix_gtm_os/models/message.py
Normal file
35
salesflow-saas/backend/dealix_gtm_os/models/message.py
Normal file
@ -0,0 +1,35 @@
|
||||
from enum import Enum
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional
|
||||
|
||||
class ChannelType(str, Enum):
|
||||
EMAIL = "email"
|
||||
LINKEDIN_MANUAL = "linkedin_manual"
|
||||
WHATSAPP_WARM = "whatsapp_warm"
|
||||
INSTAGRAM_INBOUND = "instagram_inbound"
|
||||
X_POST = "x_post"
|
||||
X_REPLY = "x_reply"
|
||||
TIKTOK_CONTENT = "tiktok_content"
|
||||
PHONE = "phone"
|
||||
PARTNER_INTRO = "partner_intro"
|
||||
WEBSITE_FORM = "website_form"
|
||||
|
||||
class AutomationLevel(str, Enum):
|
||||
FULLY_AUTOMATED = "fully_automated"
|
||||
SEMI_AUTOMATED = "semi_automated"
|
||||
MANUAL_REQUIRED = "manual_required"
|
||||
PROHIBITED = "prohibited"
|
||||
|
||||
class OutreachMessage(BaseModel):
|
||||
target_company: str
|
||||
channel: ChannelType
|
||||
automation_level: AutomationLevel
|
||||
subject: Optional[str] = None
|
||||
first_line: str
|
||||
body: str
|
||||
cta: str
|
||||
follow_up_24h: str = ""
|
||||
follow_up_72h: str = ""
|
||||
stop_condition: str = "إذا ما يناسبكم، ردوا 'إيقاف'"
|
||||
approval_required: bool = True
|
||||
risk_flags: list[str] = Field(default_factory=list)
|
||||
32
salesflow-saas/backend/dealix_gtm_os/models/opportunity.py
Normal file
32
salesflow-saas/backend/dealix_gtm_os/models/opportunity.py
Normal file
@ -0,0 +1,32 @@
|
||||
from enum import Enum
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
class OpportunityType(str, Enum):
|
||||
DIRECT_CUSTOMER = "direct_customer"
|
||||
AGENCY_PARTNER = "agency_partner"
|
||||
REFERRAL_PARTNER = "referral_partner"
|
||||
CO_SELLING_PARTNER = "co_selling_partner"
|
||||
IMPLEMENTATION_PARTNER = "implementation_partner"
|
||||
SERVICE_EXCHANGE = "service_exchange"
|
||||
INTEGRATION_PARTNER = "integration_partner"
|
||||
CONTENT_PARTNER = "content_partner"
|
||||
RESELLER_LATER = "reseller_later"
|
||||
WHITELABEL_LATER = "whitelabel_later"
|
||||
|
||||
class Opportunity(BaseModel):
|
||||
company_name: str
|
||||
opportunity_type: OpportunityType
|
||||
fit_score: int = Field(ge=1, le=5)
|
||||
urgency_score: int = Field(ge=1, le=5)
|
||||
access_score: int = Field(ge=1, le=5)
|
||||
partner_score: int = Field(ge=1, le=5)
|
||||
payment_score: int = Field(ge=1, le=5)
|
||||
risk_score: int = Field(ge=1, le=5)
|
||||
total_score: int = 0
|
||||
reason: str = ""
|
||||
recommended_offer: str = ""
|
||||
recommended_channel: str = ""
|
||||
|
||||
def model_post_init(self, __context):
|
||||
self.total_score = (self.fit_score + self.urgency_score + self.access_score +
|
||||
self.partner_score + self.payment_score - self.risk_score)
|
||||
27
salesflow-saas/backend/dealix_gtm_os/models/score.py
Normal file
27
salesflow-saas/backend/dealix_gtm_os/models/score.py
Normal file
@ -0,0 +1,27 @@
|
||||
from pydantic import BaseModel, Field, computed_field
|
||||
|
||||
class TargetScore(BaseModel):
|
||||
company_name: str
|
||||
fit: int = Field(ge=1, le=5)
|
||||
urgency: int = Field(ge=1, le=5)
|
||||
access: int = Field(ge=1, le=5)
|
||||
partner: int = Field(ge=1, le=5)
|
||||
payment: int = Field(ge=1, le=5)
|
||||
case_study: int = Field(ge=1, le=5)
|
||||
risk: int = Field(ge=1, le=5)
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def total(self) -> int:
|
||||
return self.fit + self.urgency + self.access + self.partner + self.payment + self.case_study - self.risk
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def priority(self) -> str:
|
||||
if self.total >= 24:
|
||||
return "send_today"
|
||||
elif self.total >= 18:
|
||||
return "send_this_week"
|
||||
elif self.total >= 12:
|
||||
return "send_this_month"
|
||||
return "backlog"
|
||||
124
salesflow-saas/backend/scripts/gtm_os_dry_run.py
Normal file
124
salesflow-saas/backend/scripts/gtm_os_dry_run.py
Normal file
@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Dealix GTM OS — Dry Run CLI
|
||||
Analyzes a company and generates a complete GTM pack.
|
||||
DRY-RUN ONLY — does NOT send any messages.
|
||||
"""
|
||||
import asyncio
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
from dealix_gtm_os.agents.supervisor_agent import SupervisorAgent
|
||||
|
||||
|
||||
async def run(company_name: str, website: str, sector: str, city: str, email: str):
|
||||
supervisor = SupervisorAgent()
|
||||
result = await supervisor.run({
|
||||
"name": company_name,
|
||||
"website": website,
|
||||
"sector": sector,
|
||||
"city": city,
|
||||
"email": email,
|
||||
})
|
||||
|
||||
print("=" * 60)
|
||||
print(f" DEALIX GTM OS — DRY RUN")
|
||||
print(f" Company: {company_name}")
|
||||
print(f" ⚠️ DRY-RUN ONLY — لا يرسل رسائل")
|
||||
print("=" * 60)
|
||||
|
||||
intel = result["intelligence"]
|
||||
print(f"\n{'━' * 40}")
|
||||
print("1. COMPANY INTELLIGENCE")
|
||||
print(f"{'━' * 40}")
|
||||
print(f" Sector: {intel.get('sector', '?')}")
|
||||
print(f" Summary: {intel.get('business_summary', '?')}")
|
||||
print(f" Services: {', '.join(intel.get('products_services', []))}")
|
||||
print(f" Customers: {', '.join(intel.get('target_customers', []))}")
|
||||
print(f" Pain Points: {', '.join(intel.get('pain_points', []))}")
|
||||
print(f" Partnership: {intel.get('partnership_potential', '?')}")
|
||||
print(f" Opportunity: {', '.join(intel.get('opportunity_types', []))}")
|
||||
print(f" Confidence: {intel.get('confidence', 0):.0%}")
|
||||
|
||||
score = result["score"]
|
||||
print(f"\n{'━' * 40}")
|
||||
print("2. TARGET SCORE")
|
||||
print(f"{'━' * 40}")
|
||||
print(f" Fit: {score['fit']}/5 | Urgency: {score['urgency']}/5 | Access: {score['access']}/5")
|
||||
print(f" Partner: {score['partner']}/5 | Payment: {score['payment']}/5 | Case Study: {score['case_study']}/5")
|
||||
print(f" Risk: {score['risk']}/5")
|
||||
print(f" TOTAL: {score['total']} → Priority: {score['priority']}")
|
||||
|
||||
channel = result["channel_plan"]
|
||||
print(f"\n{'━' * 40}")
|
||||
print("3. CHANNEL STRATEGY")
|
||||
print(f"{'━' * 40}")
|
||||
print(f" Primary: {channel['primary_channel']}")
|
||||
print(f" Secondary: {channel['secondary_channel']}")
|
||||
print(f" Automation: {channel['automation_level']}")
|
||||
print(f" Reason: {channel['reason']}")
|
||||
if channel.get("risk_flags"):
|
||||
print(f" Risk Flags: {', '.join(channel['risk_flags'])}")
|
||||
|
||||
comp = result["compliance"]
|
||||
print(f"\n{'━' * 40}")
|
||||
print("4. COMPLIANCE")
|
||||
print(f"{'━' * 40}")
|
||||
print(f" Allowed: {'✅' if comp['allowed'] else '❌'}")
|
||||
print(f" Level: {comp['level']}")
|
||||
print(f" Reason: {comp['reason']}")
|
||||
|
||||
msg = result["message"]
|
||||
print(f"\n{'━' * 40}")
|
||||
print("5. MESSAGE (DRAFT — NOT SENT)")
|
||||
print(f"{'━' * 40}")
|
||||
print(f" Channel: {msg['channel']}")
|
||||
print(f" Subject: {msg.get('subject', 'N/A')}")
|
||||
print(f" Approval Required: {'✅ YES' if msg['approval_required'] else 'No'}")
|
||||
print(f"\n --- BODY ---")
|
||||
for line in msg["body"].split("\n"):
|
||||
print(f" {line}")
|
||||
print(f" --- END ---")
|
||||
print(f"\n Follow-up 24h: {msg['follow_up_24h'][:80]}...")
|
||||
print(f" Follow-up 72h: {msg['follow_up_72h'][:80]}...")
|
||||
print(f" Stop: {msg['stop_condition']}")
|
||||
|
||||
print(f"\n{'━' * 40}")
|
||||
print("6. NEXT ACTION")
|
||||
print(f"{'━' * 40}")
|
||||
print(f" Action: {result['next_action']}")
|
||||
print(f" Approval Required: {'✅ YES — Sami must approve before sending' if result['approval_required'] else 'No'}")
|
||||
|
||||
prohibited = []
|
||||
if "linkedin" in channel["primary_channel"]:
|
||||
prohibited.append("LinkedIn scraping")
|
||||
prohibited.append("LinkedIn auto-DM")
|
||||
prohibited.extend(["WhatsApp cold blast", "Instagram mass DM", "Fake accounts"])
|
||||
print(f"\n{'━' * 40}")
|
||||
print("7. PROHIBITED ACTIONS")
|
||||
print(f"{'━' * 40}")
|
||||
for p in prohibited:
|
||||
print(f" ❌ {p}")
|
||||
|
||||
print(f"\n{'=' * 60}")
|
||||
print(" ⚠️ DRY-RUN COMPLETE — NO MESSAGES SENT")
|
||||
print(f"{'=' * 60}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Dealix GTM OS Dry Run")
|
||||
parser.add_argument("--company-name", required=True)
|
||||
parser.add_argument("--website", default="")
|
||||
parser.add_argument("--sector", default="agency")
|
||||
parser.add_argument("--city", default="الرياض")
|
||||
parser.add_argument("--email", default="")
|
||||
args = parser.parse_args()
|
||||
asyncio.run(run(args.company_name, args.website, args.sector, args.city, args.email))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
73
salesflow-saas/docs/gtm_os/CHANNEL_AUTOMATION_POLICY.md
Normal file
73
salesflow-saas/docs/gtm_os/CHANNEL_AUTOMATION_POLICY.md
Normal file
@ -0,0 +1,73 @@
|
||||
# Dealix GTM OS — Channel Automation Policy
|
||||
|
||||
## Per-Channel Rules
|
||||
|
||||
### LinkedIn
|
||||
| Action | Level | Rule |
|
||||
|--------|-------|------|
|
||||
| Profile viewing | Manual | Research only |
|
||||
| Post publishing | Allowed | Via Sami's account |
|
||||
| Commenting | Manual | Value-add only, no spam |
|
||||
| Connection requests | Manual | Max 10/day with personal note |
|
||||
| DMs | Manual | Max 5/day, personalized |
|
||||
| Scraping | **PROHIBITED** | LinkedIn ToS violation |
|
||||
| Auto-DM bots | **PROHIBITED** | Account ban risk |
|
||||
|
||||
### Email
|
||||
| Action | Level | Rule |
|
||||
|--------|-------|------|
|
||||
| Targeted B2B | Semi-auto | With opt-out, max 10/day initially |
|
||||
| Follow-up sequence | Semi-auto | Max 3 per target |
|
||||
| Mass cold | **PROHIBITED** | Until email infrastructure ready |
|
||||
| Fake sender | **PROHIBITED** | Always use real identity |
|
||||
|
||||
### WhatsApp
|
||||
| Action | Level | Rule |
|
||||
|--------|-------|------|
|
||||
| Warm messages | Manual | People who know Sami |
|
||||
| Opt-in follow-up | Semi-auto | Via Green API templates |
|
||||
| Demo confirmation | Allowed | After booking |
|
||||
| Cold blasting | **PROHIBITED** | Account ban + legal risk |
|
||||
| Status updates | Allowed | Daily |
|
||||
|
||||
### Instagram
|
||||
| Action | Level | Rule |
|
||||
|--------|-------|------|
|
||||
| Posts/Stories/Reels | Allowed | Content + engagement |
|
||||
| Inbound DM reply | Allowed | Within 24h window |
|
||||
| Cold DM | **PROHIBITED** | Platform risk |
|
||||
| Comment engagement | Manual | Value-add only |
|
||||
|
||||
### X / Twitter
|
||||
| Action | Level | Rule |
|
||||
|--------|-------|------|
|
||||
| Posts/Threads | Allowed | Scheduled or manual |
|
||||
| Safe replies | Manual | Value-add, no spam |
|
||||
| Auto mentions | **PROHIBITED** | X ToS violation |
|
||||
| Auto DMs | **PROHIBITED** | X ToS violation |
|
||||
|
||||
### TikTok
|
||||
| Action | Level | Rule |
|
||||
|--------|-------|------|
|
||||
| Organic content | Allowed | Videos/posts |
|
||||
| Lead form ads | Allowed | Official ad system |
|
||||
| DM scraping | **PROHIBITED** | Platform risk |
|
||||
| Mass DM | **PROHIBITED** | Platform risk |
|
||||
|
||||
## Daily Limits (Initial)
|
||||
|
||||
| Channel | Daily Limit | After Proof |
|
||||
|---------|------------|-------------|
|
||||
| Email | 10 | 20 |
|
||||
| LinkedIn DM | 5 (manual) | 5 |
|
||||
| WhatsApp warm | 5 | 10 |
|
||||
| X replies | 5 | 10 |
|
||||
| Instagram DM | 2 (inbound only) | 3 |
|
||||
|
||||
## Approval Gates
|
||||
- First message to any new person: **Sami approval**
|
||||
- WhatsApp to non-warm: **Sami approval**
|
||||
- Claims about results: **Sami approval**
|
||||
- Payment link: **Sami approval**
|
||||
- Partner terms: **Sami approval**
|
||||
- Sending >10 messages/day: **Sami approval**
|
||||
33
salesflow-saas/docs/gtm_os/DATA_SOURCES_POLICY.md
Normal file
33
salesflow-saas/docs/gtm_os/DATA_SOURCES_POLICY.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Dealix GTM OS — Data Sources Policy
|
||||
|
||||
## Allowed Sources
|
||||
|
||||
| Source | Type | Usage | Risk |
|
||||
|--------|------|-------|------|
|
||||
| Uploaded company files (Excel/CSV) | User data | Primary targeting | Low |
|
||||
| Public company websites | Public | Research + enrichment | Low |
|
||||
| Google Programmable Search | Official API | Web search | Low |
|
||||
| Tavily | AI search API | Structured web results | Low |
|
||||
| Official social media APIs | Official | Inbound + public data | Low |
|
||||
| CRM data | Internal | Lead tracking | Low |
|
||||
| Inbound messages | Opt-in | Customer conversations | Low |
|
||||
| Manual imports by Sami | User action | Ad-hoc targeting | Low |
|
||||
| Public business directories | Public | Company discovery | Low |
|
||||
|
||||
## Prohibited Sources
|
||||
|
||||
| Source | Reason |
|
||||
|--------|--------|
|
||||
| LinkedIn scraping/crawling | Platform ToS violation |
|
||||
| Instagram profile scraping | Platform ToS violation |
|
||||
| Purchased email/phone lists | Privacy + spam risk |
|
||||
| Unauthorized data brokers | Legal risk |
|
||||
| Scraping restricted websites | ToS violation |
|
||||
| Personal data without consent | PDPL violation |
|
||||
|
||||
## Rules
|
||||
1. Every data point must have a traceable source
|
||||
2. No invented/hallucinated company data
|
||||
3. No personal data collection without legitimate basis
|
||||
4. All enrichment from public or API-approved sources only
|
||||
5. User can request deletion of their data
|
||||
66
salesflow-saas/docs/gtm_os/GTM_OS_ARCHITECTURE.md
Normal file
66
salesflow-saas/docs/gtm_os/GTM_OS_ARCHITECTURE.md
Normal file
@ -0,0 +1,66 @@
|
||||
# Dealix GTM OS — Architecture
|
||||
|
||||
## Overview
|
||||
```
|
||||
Company Input → Research → Enrichment → ICP Detection → Opportunity Mapping
|
||||
→ Channel Strategy → Message Generation → Compliance Check
|
||||
→ Human Approval / Safe Automation → CRM Tracking → Learning Loop
|
||||
```
|
||||
|
||||
## Layers
|
||||
|
||||
### A. Data Layer
|
||||
Collects from allowed sources only:
|
||||
- Uploaded company files
|
||||
- Public websites
|
||||
- Google Programmable Search / Tavily
|
||||
- Official APIs
|
||||
- CRM data
|
||||
- Inbound messages
|
||||
- Manual imports
|
||||
|
||||
### B. Intelligence Layer
|
||||
13 specialized agents understand companies, markets, and opportunities.
|
||||
|
||||
### C. Compliance Layer
|
||||
Decides: allowed / manual_required / opt_in_required / prohibited
|
||||
|
||||
### D. Execution Layer
|
||||
Only safe actions: drafts, CRM tasks, scorecards, content packs, approved campaigns.
|
||||
|
||||
### E. Learning Layer
|
||||
Tracks replies, demos, conversions. Updates ICP, scoring, messages, channels weekly.
|
||||
|
||||
## 13 Agents
|
||||
|
||||
| Agent | Role | Input | Output |
|
||||
|-------|------|-------|--------|
|
||||
| Supervisor | Orchestrates all | CompanyInput | Full GTM Pack |
|
||||
| Company Research | Understands company | Name/URL/sector | CompanyIntelligence |
|
||||
| Web Search | Searches allowed sources | Query | SearchResults |
|
||||
| Enrichment | Adds data | CompanyInput | EnrichedCompany |
|
||||
| ICP Strategist | Determines ideal customers | CompanyIntelligence | ICPList |
|
||||
| Partnership Strategist | Maps partnership types | CompanyIntelligence | PartnershipMap |
|
||||
| Channel Strategy | Picks best channel | Company + Compliance | ChannelPlan |
|
||||
| Message Generation | Writes Arabic messages | Company + Channel | OutreachMessage |
|
||||
| Compliance | Enforces platform rules | Channel + Action | Decision |
|
||||
| Campaign Orchestrator | Builds sequences | Company + Messages | CampaignSequence |
|
||||
| Negotiation | Handles objections | Reply + Context | NegotiationResponse |
|
||||
| CRM & Revenue | Tracks status | Events | StatusUpdate |
|
||||
| Learning | Improves system | Results | UpdatedStrategy |
|
||||
|
||||
## Automation Boundaries
|
||||
|
||||
| Level | What | Examples |
|
||||
|-------|------|---------|
|
||||
| Fully Automated | Internal processing | Research, scoring, drafts, CRM tasks, reports |
|
||||
| Semi-Automated | Approved channels | Email with opt-out, inbound chatbot, WhatsApp templates |
|
||||
| Manual Required | Risky channels | LinkedIn DMs, Instagram DMs, phone calls |
|
||||
| Prohibited | Policy violation | LinkedIn scraping, WhatsApp blast, fake accounts |
|
||||
|
||||
## Safety Rules
|
||||
- LinkedIn: NO scraping/bots/automated DMs
|
||||
- X: NO unsolicited automated replies/mentions
|
||||
- WhatsApp: opt-in only, stop on "إيقاف"
|
||||
- Instagram: inbound/official API only
|
||||
- TikTok: content + official ads/lead forms only
|
||||
Loading…
Reference in New Issue
Block a user