mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-18 23:39:34 +00:00
195 lines
5.9 KiB
Python
195 lines
5.9 KiB
Python
"""
|
|
Agent Router — Maps events to the correct agent(s) and handles multi-agent chaining.
|
|
"""
|
|
|
|
from typing import Optional
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.ai.agent_executor import AgentExecutor
|
|
from app.ai.llm_provider import LLMProvider
|
|
|
|
|
|
# Event type → Agent(s) mapping
|
|
EVENT_AGENT_MAP = {
|
|
# Lead events
|
|
"lead.created": ["lead_qualification"],
|
|
"lead.qualified": ["outreach_writer"],
|
|
"lead.contacted": ["arabic_whatsapp"],
|
|
"lead.replied": ["arabic_whatsapp", "objection_handler"],
|
|
"lead.meeting_ready": ["meeting_booking"],
|
|
|
|
# Message events
|
|
"message.inbound.whatsapp.ar": ["arabic_whatsapp"],
|
|
"message.inbound.whatsapp.en": ["english_conversation"],
|
|
"message.closer.whatsapp.ar": ["closer_agent"],
|
|
"message.closer.whatsapp.en": ["closer_agent"],
|
|
"message.inbound.email": ["english_conversation"],
|
|
"message.objection_detected": ["objection_handler"],
|
|
|
|
# Call events
|
|
"call.completed": ["voice_call"],
|
|
"call.transcript_ready": ["voice_call"],
|
|
|
|
# Meeting events
|
|
"meeting.requested": ["meeting_booking"],
|
|
"meeting.confirmed": ["proposal_drafter"],
|
|
"meeting.prep_needed": ["sector_strategist", "proposal_drafter"],
|
|
|
|
# Deal events
|
|
"deal.created": ["sector_strategist"],
|
|
"deal.proposal_needed": ["proposal_drafter"],
|
|
"deal.closed_won": ["revenue_attribution", "management_summary"],
|
|
"deal.closed_lost": ["management_summary"],
|
|
|
|
# Affiliate events
|
|
"affiliate.applied": ["affiliate_evaluator"],
|
|
"affiliate.approved": ["onboarding_coach"],
|
|
"affiliate.fraud_suspected": ["fraud_reviewer"],
|
|
|
|
# Compliance events
|
|
"content.review_needed": ["qa_reviewer"],
|
|
"compliance.check_needed": ["compliance_reviewer"],
|
|
|
|
# Guarantee events
|
|
"guarantee.claimed": ["guarantee_reviewer"],
|
|
|
|
# Knowledge events
|
|
"knowledge.query": ["knowledge_retrieval"],
|
|
|
|
# Reporting events
|
|
"report.daily": ["management_summary"],
|
|
"report.weekly": ["management_summary"],
|
|
}
|
|
|
|
|
|
class AgentRouter:
|
|
"""
|
|
Routes incoming events to the appropriate AI agent(s).
|
|
Supports single-agent, multi-agent, and chained execution.
|
|
"""
|
|
|
|
def __init__(self, db: AsyncSession, llm: LLMProvider = None):
|
|
self.db = db
|
|
self.llm = llm or LLMProvider()
|
|
self.executor = AgentExecutor(db=db, llm=self.llm)
|
|
|
|
async def route(
|
|
self,
|
|
event_type: str,
|
|
event_data: dict,
|
|
tenant_id: str,
|
|
lead_id: str = None,
|
|
contact_id: str = None,
|
|
) -> dict:
|
|
"""
|
|
Route an event to the appropriate agent(s).
|
|
|
|
Returns:
|
|
{
|
|
"event": "lead.created",
|
|
"agents_invoked": ["lead_qualification"],
|
|
"results": [ { ...agent output... } ],
|
|
"escalations": [ ... ],
|
|
}
|
|
"""
|
|
agents = EVENT_AGENT_MAP.get(event_type, [])
|
|
if not agents:
|
|
return {
|
|
"event": event_type,
|
|
"agents_invoked": [],
|
|
"results": [],
|
|
"error": f"No agent mapped for event: {event_type}",
|
|
}
|
|
|
|
results = []
|
|
escalations = []
|
|
|
|
for agent_type in agents:
|
|
try:
|
|
result = await self.executor.execute(
|
|
agent_type=agent_type,
|
|
input_data=event_data,
|
|
tenant_id=tenant_id,
|
|
lead_id=lead_id,
|
|
contact_id=contact_id,
|
|
)
|
|
results.append(result)
|
|
|
|
if result.get("escalation", {}).get("needed"):
|
|
escalations.append({
|
|
"agent": agent_type,
|
|
"reason": result["escalation"]["reason"],
|
|
"target": result["escalation"]["target"],
|
|
})
|
|
|
|
except Exception as e:
|
|
results.append({
|
|
"agent_type": agent_type,
|
|
"error": str(e),
|
|
"status": "failed",
|
|
})
|
|
|
|
return {
|
|
"event": event_type,
|
|
"agents_invoked": agents,
|
|
"results": results,
|
|
"escalations": escalations,
|
|
}
|
|
|
|
async def chain(
|
|
self,
|
|
agent_sequence: list,
|
|
initial_data: dict,
|
|
tenant_id: str,
|
|
lead_id: str = None,
|
|
) -> dict:
|
|
"""
|
|
Execute agents in sequence, passing output of each to the next.
|
|
|
|
Example chain: ["lead_qualification", "outreach_writer", "meeting_booking"]
|
|
"""
|
|
chain_results = []
|
|
current_data = initial_data.copy()
|
|
|
|
for agent_type in agent_sequence:
|
|
try:
|
|
result = await self.executor.execute(
|
|
agent_type=agent_type,
|
|
input_data=current_data,
|
|
tenant_id=tenant_id,
|
|
lead_id=lead_id,
|
|
)
|
|
chain_results.append(result)
|
|
|
|
# Pass output to next agent as context
|
|
if result.get("output"):
|
|
current_data["previous_agent"] = agent_type
|
|
current_data["previous_output"] = result["output"]
|
|
|
|
# Stop chain if escalation is needed
|
|
if result.get("escalation", {}).get("needed"):
|
|
break
|
|
|
|
except Exception as e:
|
|
chain_results.append({
|
|
"agent_type": agent_type,
|
|
"error": str(e),
|
|
"status": "failed",
|
|
})
|
|
break
|
|
|
|
return {
|
|
"chain": agent_sequence,
|
|
"completed": len(chain_results),
|
|
"results": chain_results,
|
|
}
|
|
|
|
def get_event_types(self) -> list:
|
|
"""List all supported event types."""
|
|
return list(EVENT_AGENT_MAP.keys())
|
|
|
|
def get_agents_for_event(self, event_type: str) -> list:
|
|
"""Get agents mapped to an event type."""
|
|
return EVENT_AGENT_MAP.get(event_type, [])
|