""" Agent Router v2.0 — Determines which AI agent handles which event. The central nervous system of Dealix's AI engine. Features: - Priority-based agent ordering - Parallel vs sequential execution modes - Retry policies per agent - Agent metadata (model preference, temperature, timeout) """ import logging from typing import Optional from dataclasses import dataclass, field from enum import Enum logger = logging.getLogger("dealix.agents") class ExecutionMode(str, Enum): SEQUENTIAL = "sequential" # Agents run one after another PARALLEL = "parallel" # Agents run simultaneously PIPELINE = "pipeline" # Output of one feeds into the next @dataclass class RetryPolicy: max_retries: int = 2 backoff_seconds: float = 1.0 backoff_multiplier: float = 2.0 # Exponential backoff @dataclass class AgentConfig: """Configuration for a single agent in an event mapping.""" agent_id: str priority: int = 1 # Lower = higher priority (1 runs first) required: bool = True # If True, failure stops the chain timeout_seconds: int = 30 # Max execution time model_preference: str = "" # Override LLM model (e.g., "groq_fast") retry_policy: RetryPolicy = field(default_factory=RetryPolicy) @dataclass class EventConfig: """Configuration for an event type.""" agents: list[AgentConfig] execution_mode: ExecutionMode = ExecutionMode.SEQUENTIAL description: str = "" # ── Event → Agent Mapping (v2.0 with priority & config) ────── AGENT_REGISTRY: dict[str, EventConfig] = { # ── Lead Lifecycle ─────────────────────────────── "lead_created": EventConfig( agents=[ AgentConfig("lead_qualification", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="New lead enters the system — qualify immediately", ), "lead_score_updated": EventConfig( agents=[ AgentConfig("lead_qualification", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Lead score changed — re-evaluate qualification", ), "lead_qualified": EventConfig( agents=[ AgentConfig("outreach_writer", priority=1, required=True), AgentConfig("meeting_booking", priority=2, required=False), AgentConfig("closer_agent", priority=3, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Lead qualified — start outreach sequence", ), # ── Communication ──────────────────────────────── "whatsapp_inbound": EventConfig( agents=[ AgentConfig("arabic_whatsapp", priority=1, required=True, timeout_seconds=15), AgentConfig("closer_agent", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Incoming WhatsApp message — respond in Arabic", ), "whatsapp_outbound": EventConfig( agents=[ AgentConfig("outreach_writer", priority=1, required=True), AgentConfig("compliance_reviewer", priority=2, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Outgoing WhatsApp — write + compliance check", ), "email_inbound": EventConfig( agents=[ AgentConfig("english_conversation", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Incoming email — handle in English", ), "email_outbound": EventConfig( agents=[ AgentConfig("outreach_writer", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Outgoing email — craft professional message", ), "voice_call_completed": EventConfig( agents=[ AgentConfig("voice_call", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Voice call ended — analyze and log", ), # ── Meeting Lifecycle ──────────────────────────── "meeting_requested": EventConfig( agents=[ AgentConfig("meeting_booking", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Meeting requested — find best slot", ), "meeting_confirmed": EventConfig( agents=[ AgentConfig("ai_rehearsal", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Meeting confirmed — prepare briefing", ), "meeting_upcoming": EventConfig( agents=[ AgentConfig("ai_rehearsal", priority=1, required=True), AgentConfig("knowledge_retrieval", priority=2, required=False), ], execution_mode=ExecutionMode.PARALLEL, description="Meeting in 24h — final preparation", ), # ── Deal Lifecycle ─────────────────────────────── "deal_created": EventConfig( agents=[ AgentConfig("sector_strategist", priority=1, required=True), AgentConfig("knowledge_retrieval", priority=1, required=False), ], execution_mode=ExecutionMode.PARALLEL, description="New deal — sector analysis + knowledge lookup", ), "deal_stage_changed": EventConfig( agents=[ AgentConfig("proposal_drafter", priority=1, required=False), AgentConfig("management_summary", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Deal progression — update proposal if needed", ), "deal_proposal_requested": EventConfig( agents=[ AgentConfig("proposal_drafter", priority=1, required=True, timeout_seconds=60), AgentConfig("compliance_reviewer", priority=2, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Proposal requested — draft + compliance review", ), # ── Quality & Compliance ───────────────────────── "content_review": EventConfig( agents=[ AgentConfig("qa_reviewer", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Content needs QA review", ), "compliance_check": EventConfig( agents=[ AgentConfig("compliance_reviewer", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Compliance verification required", ), "objection_detected": EventConfig( agents=[ AgentConfig("objection_handler", priority=1, required=True), AgentConfig("closer_agent", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Client objection detected — handle + attempt close", ), # ── Affiliate Lifecycle ────────────────────────── "affiliate_applied": EventConfig( agents=[ AgentConfig("affiliate_evaluator", priority=1, required=True), AgentConfig("fraud_reviewer", priority=1, required=True), ], execution_mode=ExecutionMode.PARALLEL, description="New affiliate application — evaluate + fraud check simultaneously", ), "affiliate_approved": EventConfig( agents=[ AgentConfig("onboarding_coach", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Affiliate approved — start onboarding", ), # ── Analytics ──────────────────────────────────── "revenue_attribution": EventConfig( agents=[ AgentConfig("revenue_attribution", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Revenue needs attribution analysis", ), "fraud_check": EventConfig( agents=[ AgentConfig("fraud_reviewer", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Fraud check triggered", ), "guarantee_claim": EventConfig( agents=[ AgentConfig("guarantee_reviewer", priority=1, required=True), AgentConfig("fraud_reviewer", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Guarantee claim — review then fraud check", ), "management_report": EventConfig( agents=[ AgentConfig("management_summary", priority=1, required=True, timeout_seconds=60), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Generate management report", ), # ── Knowledge ──────────────────────────────────── "knowledge_query": EventConfig( agents=[ AgentConfig("knowledge_retrieval", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Knowledge base query", ), "sector_strategy": EventConfig( agents=[ AgentConfig("sector_strategist", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Sector strategy analysis", ), # ── Autonomous Pipeline Events ─────────────────── "pipeline_lead_new": EventConfig( agents=[ AgentConfig("lead_qualification", priority=1, required=True), AgentConfig("knowledge_retrieval", priority=1, required=False), ], execution_mode=ExecutionMode.PARALLEL, description="Autonomous: new lead → qualify + gather knowledge", ), "pipeline_lead_qualified": EventConfig( agents=[ AgentConfig("outreach_writer", priority=1, required=True), AgentConfig("sector_strategist", priority=1, required=False), ], execution_mode=ExecutionMode.PARALLEL, description="Autonomous: qualified → outreach + strategy", ), "pipeline_meeting_prep": EventConfig( agents=[ AgentConfig("ai_rehearsal", priority=1, required=True), AgentConfig("proposal_drafter", priority=1, required=False), AgentConfig("knowledge_retrieval", priority=1, required=False), ], execution_mode=ExecutionMode.PARALLEL, description="Autonomous: pre-meeting full preparation", ), "pipeline_closing": EventConfig( agents=[ AgentConfig("closer_agent", priority=1, required=True), AgentConfig("compliance_reviewer", priority=2, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Autonomous: closing stage → close + compliance", ), # ══════════════════════════════════════════════════ # ── Strategic Growth & Enterprise Agents ───────── # ══════════════════════════════════════════════════ # ── Partnerships ───────────────────────────────── "partnership_opportunity": EventConfig( agents=[ AgentConfig("partnership_scout", priority=1, required=True, timeout_seconds=60), AgentConfig("competitive_intel", priority=1, required=False), ], execution_mode=ExecutionMode.PARALLEL, description="New partnership opportunity detected — scout + competitive analysis", ), "partnership_proposal_requested": EventConfig( agents=[ AgentConfig("partnership_scout", priority=1, required=True, timeout_seconds=60), AgentConfig("contract_lifecycle", priority=2, required=True), AgentConfig("compliance_reviewer", priority=3, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Partnership proposal needed — scout → contract → compliance", ), # ── M&A & Strategic Growth ─────────────────────── "acquisition_target_identified": EventConfig( agents=[ AgentConfig("ma_growth", priority=1, required=True, timeout_seconds=120), AgentConfig("competitive_intel", priority=1, required=False), AgentConfig("finance_automation", priority=2, required=True), ], execution_mode=ExecutionMode.PARALLEL, description="M&A target found — valuation + competitive + financial analysis", ), "growth_strategy_requested": EventConfig( agents=[ AgentConfig("business_development", priority=1, required=True, timeout_seconds=90), AgentConfig("ma_growth", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Strategic growth analysis — BizDev → M&A options", ), # ── Contracts ──────────────────────────────────── "contract_creation_requested": EventConfig( agents=[ AgentConfig("contract_lifecycle", priority=1, required=True, timeout_seconds=60), AgentConfig("compliance_reviewer", priority=2, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Contract needed — draft + compliance review", ), "contract_review_requested": EventConfig( agents=[ AgentConfig("contract_lifecycle", priority=1, required=True), AgentConfig("fraud_reviewer", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Incoming contract — review risks + fraud check", ), "contract_expiring_soon": EventConfig( agents=[ AgentConfig("contract_lifecycle", priority=1, required=True), AgentConfig("customer_success", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Contract expiring — renewal + customer health check", ), # ── Business Development ───────────────────────── "market_expansion_requested": EventConfig( agents=[ AgentConfig("business_development", priority=1, required=True, timeout_seconds=90), AgentConfig("sector_strategist", priority=1, required=False), AgentConfig("competitive_intel", priority=1, required=False), ], execution_mode=ExecutionMode.PARALLEL, description="Market expansion — BizDev + sector + competitive intel", ), "new_revenue_stream_analysis": EventConfig( agents=[ AgentConfig("business_development", priority=1, required=True), AgentConfig("dynamic_pricing", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="New revenue stream — BizDev analysis + pricing strategy", ), # ── Supply Chain & Procurement ─────────────────── "procurement_rfq": EventConfig( agents=[ AgentConfig("supply_chain", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="RFQ received — evaluate suppliers and pricing", ), "supplier_evaluation": EventConfig( agents=[ AgentConfig("supply_chain", priority=1, required=True), AgentConfig("fraud_reviewer", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Evaluate supplier — quality + fraud check", ), "inventory_alert": EventConfig( agents=[ AgentConfig("supply_chain", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Inventory low — reorder analysis", ), # ── Customer Success & Retention ───────────────── "customer_health_check": EventConfig( agents=[ AgentConfig("customer_success", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Customer health check — churn risk + upsell opportunities", ), "customer_complaint": EventConfig( agents=[ AgentConfig("customer_success", priority=1, required=True), AgentConfig("compliance_reviewer", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Customer complaint — resolve + compliance check", ), "upsell_opportunity_detected": EventConfig( agents=[ AgentConfig("customer_success", priority=1, required=True), AgentConfig("dynamic_pricing", priority=2, required=False), AgentConfig("outreach_writer", priority=3, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Upsell opportunity — CS assessment + pricing + outreach", ), "quarterly_business_review": EventConfig( agents=[ AgentConfig("customer_success", priority=1, required=True, timeout_seconds=60), AgentConfig("revenue_attribution", priority=1, required=False), ], execution_mode=ExecutionMode.PARALLEL, description="QBR preparation — customer success + revenue analysis", ), # ── Dynamic Pricing ────────────────────────────── "pricing_review_requested": EventConfig( agents=[ AgentConfig("dynamic_pricing", priority=1, required=True), AgentConfig("competitive_intel", priority=1, required=False), ], execution_mode=ExecutionMode.PARALLEL, description="Pricing review — dynamic pricing + competitive analysis", ), "discount_approval_requested": EventConfig( agents=[ AgentConfig("dynamic_pricing", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Discount requested — profitability check", ), # ── Marketing Automation ───────────────────────── "campaign_creation_requested": EventConfig( agents=[ AgentConfig("marketing_automation", priority=1, required=True, timeout_seconds=60), AgentConfig("compliance_reviewer", priority=2, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Marketing campaign — create + compliance review", ), "lead_nurture_triggered": EventConfig( agents=[ AgentConfig("marketing_automation", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Lead nurture — drip campaign automation", ), "retargeting_triggered": EventConfig( agents=[ AgentConfig("marketing_automation", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Retargeting — re-engage inactive leads", ), # ── Finance Automation ─────────────────────────── "invoice_generation": EventConfig( agents=[ AgentConfig("finance_automation", priority=1, required=True), AgentConfig("compliance_reviewer", priority=2, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Invoice creation — ZATCA compliant + compliance", ), "collection_overdue": EventConfig( agents=[ AgentConfig("finance_automation", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Overdue payment — automated collection workflow", ), "financial_report_requested": EventConfig( agents=[ AgentConfig("finance_automation", priority=1, required=True, timeout_seconds=60), AgentConfig("management_summary", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Financial report — finance + management summary", ), "cashflow_forecast_requested": EventConfig( agents=[ AgentConfig("finance_automation", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Cash flow forecast — predict inflows/outflows", ), # ── Competitive Intelligence ───────────────────── "competitor_alert": EventConfig( agents=[ AgentConfig("competitive_intel", priority=1, required=True), AgentConfig("dynamic_pricing", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Competitor movement — intel + pricing response", ), "battlecard_requested": EventConfig( agents=[ AgentConfig("competitive_intel", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Battle card needed for sales team", ), "win_loss_analysis": EventConfig( agents=[ AgentConfig("competitive_intel", priority=1, required=True), AgentConfig("management_summary", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Win/loss analysis — competitive intel + management reporting", ), # ══════════════════════════════════════════════════ # ── Advanced Strategic & M&A Core (The 7 New Agents) # ══════════════════════════════════════════════════ # ── Alliance Structuring ──────────────────────── "partnership.model_recommended": EventConfig( agents=[ AgentConfig("alliance_structuring", priority=1, required=True, timeout_seconds=90), AgentConfig("finance_automation", priority=2, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Structure alliance mode (Rev-share/JV) and calculate financial impact", ), "partnership.term_sheet_ready": EventConfig( agents=[ AgentConfig("alliance_structuring", priority=1, required=True), AgentConfig("contract_lifecycle", priority=2, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Generate Term Sheet from Alliance model", ), # ── M&A Target Screening & DD ─────────────────── "ma.screening_completed": EventConfig( agents=[ AgentConfig("due_diligence_analyst", priority=1, required=True, timeout_seconds=120), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Run initial comprehensive DD (Financial, Ops, Legal)", ), "ma.valuation_ready": EventConfig( agents=[ AgentConfig("valuation_synergy", priority=1, required=True, timeout_seconds=90), AgentConfig("finance_automation", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Valuation execution + revenue/cost synergy analysis", ), # ── Strategic Negotiation ──────────────────────── "ma.offer_strategy_ready": EventConfig( agents=[ AgentConfig("executive_negotiator", priority=1, required=True, timeout_seconds=90), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Prepare executive negotiation playbook (BATNA, ZOPA, Scenarios)", ), # ── Post-Merger Integration (PMI) ──────────────── "ma.integration_kickoff": EventConfig( agents=[ AgentConfig("post_merger_integration", priority=1, required=True, timeout_seconds=120), AgentConfig("strategic_pmo", priority=2, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Kickoff 30/60/90 days integration PMO & tracking", ), # ── Execution PMO ────────────────────────────── "growth.milestone_achieved": EventConfig( agents=[ AgentConfig("strategic_pmo", priority=1, required=True), AgentConfig("sovereign_intelligence", priority=2, required=False), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Track growth milestone and pass to sovereign intelligence", ), "growth.execution_blocker_detected": EventConfig( agents=[ AgentConfig("strategic_pmo", priority=1, required=True), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Handle strategic blocker, assign SLAs and owners", ), # ── Sovereign Level ───────────────────────────── "governance.executive_escalation": EventConfig( agents=[ AgentConfig("sovereign_intelligence", priority=1, required=True, timeout_seconds=120), ], execution_mode=ExecutionMode.SEQUENTIAL, description="C-suite/Board level escalation and dashboarding", ), "board_briefing_requested": EventConfig( agents=[ AgentConfig("sovereign_intelligence", priority=1, required=True, timeout_seconds=120), ], execution_mode=ExecutionMode.SEQUENTIAL, description="Generate 360° Sovereign Board Briefing", ), } class AgentRouter: """Routes events to the appropriate AI agent(s) with priority and config.""" def get_event_config(self, event_type: str) -> Optional[EventConfig]: """Return the full event configuration.""" config = AGENT_REGISTRY.get(event_type) if not config: logger.warning(f"No agent registered for event: {event_type}") return config def get_agents_for_event(self, event_type: str) -> list[str]: """Return list of agent IDs sorted by priority.""" config = self.get_event_config(event_type) if not config: return [] sorted_agents = sorted(config.agents, key=lambda a: a.priority) return [a.agent_id for a in sorted_agents] def get_agents_config_for_event(self, event_type: str) -> list[AgentConfig]: """Return agent configs sorted by priority.""" config = self.get_event_config(event_type) if not config: return [] return sorted(config.agents, key=lambda a: a.priority) def get_execution_mode(self, event_type: str) -> ExecutionMode: """Return execution mode for an event.""" config = self.get_event_config(event_type) return config.execution_mode if config else ExecutionMode.SEQUENTIAL def get_primary_agent(self, event_type: str) -> Optional[str]: """Return the primary (highest priority) agent for an event.""" agents = self.get_agents_for_event(event_type) return agents[0] if agents else None def list_all_agents(self) -> list[dict]: """List all registered agents with their event triggers.""" agent_events: dict[str, list[str]] = {} for event, config in AGENT_REGISTRY.items(): for agent_cfg in config.agents: if agent_cfg.agent_id not in agent_events: agent_events[agent_cfg.agent_id] = [] agent_events[agent_cfg.agent_id].append(event) return [ {"agent_id": agent_id, "events": events, "event_count": len(events)} for agent_id, events in sorted(agent_events.items()) ] def list_all_events(self) -> list[dict]: """List all registered events with their agent configs.""" return [ { "event_type": event_type, "description": config.description, "execution_mode": config.execution_mode.value, "agents": [ { "agent_id": a.agent_id, "priority": a.priority, "required": a.required, "timeout_seconds": a.timeout_seconds, } for a in sorted(config.agents, key=lambda x: x.priority) ], } for event_type, config in sorted(AGENT_REGISTRY.items()) ] def get_agent_count(self) -> int: """Return total number of unique agents.""" agents = set() for config in AGENT_REGISTRY.values(): for a in config.agents: agents.add(a.agent_id) return len(agents)