mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-17 23:09:35 +00:00
119 lines
3.6 KiB
Python
119 lines
3.6 KiB
Python
"""
|
|
Follow-up Agent — generates time-appropriate follow-up messages.
|
|
وكيل المتابعة — يُنشئ رسائل متابعة مناسبة لكل مرحلة.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from datetime import datetime, timedelta
|
|
from typing import Any
|
|
|
|
from auto_client_acquisition.agents.intake import Lead, LeadStatus
|
|
from core.agents.base import BaseAgent
|
|
from core.config.models import Task
|
|
from core.llm.base import Message
|
|
from core.prompts import get_prompt
|
|
from core.prompts.sales_scripts import get_sales_script
|
|
from core.utils import utcnow
|
|
|
|
|
|
@dataclass
|
|
class FollowUpPlan:
|
|
attempt: int
|
|
scheduled_for: datetime
|
|
channel: str
|
|
body: str
|
|
should_pause: bool = False
|
|
reason: str = ""
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return {
|
|
"attempt": self.attempt,
|
|
"scheduled_for": self.scheduled_for.isoformat(),
|
|
"channel": self.channel,
|
|
"body": self.body,
|
|
"should_pause": self.should_pause,
|
|
"reason": self.reason,
|
|
}
|
|
|
|
|
|
# Cadence: [days_after_previous_touch] per attempt
|
|
DEFAULT_CADENCE_DAYS = [0, 3, 7, 14] # immediate, 3d, 7d, 14d
|
|
|
|
|
|
class FollowUpAgent(BaseAgent):
|
|
"""Plans and generates follow-up messages."""
|
|
|
|
name = "followup"
|
|
|
|
async def run(
|
|
self,
|
|
*,
|
|
lead: Lead,
|
|
attempt: int = 1,
|
|
last_touch: datetime | None = None,
|
|
history_summary: str = "",
|
|
channel: str = "email",
|
|
**_: Any,
|
|
) -> FollowUpPlan:
|
|
"""Generate a follow-up message for the given attempt."""
|
|
# Short-circuit if lead is closed/won/lost
|
|
if lead.status in (LeadStatus.WON, LeadStatus.LOST, LeadStatus.DISQUALIFIED):
|
|
return FollowUpPlan(
|
|
attempt=attempt,
|
|
scheduled_for=utcnow(),
|
|
channel=channel,
|
|
body="",
|
|
should_pause=True,
|
|
reason=f"Lead already in terminal status: {lead.status.value}",
|
|
)
|
|
|
|
# Determine schedule
|
|
last_touch = last_touch or utcnow()
|
|
days = DEFAULT_CADENCE_DAYS[min(attempt, len(DEFAULT_CADENCE_DAYS) - 1)]
|
|
scheduled = last_touch + timedelta(days=days)
|
|
|
|
# Use canned scripts for attempts 1-2, LLM for bespoke attempt 3+
|
|
if attempt == 1:
|
|
body = get_sales_script(
|
|
"follow_up_1",
|
|
locale=lead.locale,
|
|
name=lead.contact_name or "",
|
|
sector=lead.sector or ("قطاعكم" if lead.locale == "ar" else "your sector"),
|
|
)
|
|
elif attempt == 2:
|
|
body = get_sales_script(
|
|
"follow_up_2",
|
|
locale=lead.locale,
|
|
name=lead.contact_name or "",
|
|
)
|
|
else:
|
|
prompt = get_prompt(
|
|
"followup",
|
|
attempt=attempt,
|
|
history=history_summary or "No prior context",
|
|
status=lead.status.value,
|
|
locale=lead.locale,
|
|
)
|
|
response = await self.router.run(
|
|
task=Task.PAGE_COPY,
|
|
messages=[Message(role="user", content=prompt)],
|
|
max_tokens=300,
|
|
temperature=0.6,
|
|
)
|
|
body = response.content.strip()
|
|
|
|
self.log.info(
|
|
"followup_planned",
|
|
lead_id=lead.id,
|
|
attempt=attempt,
|
|
scheduled=scheduled.isoformat(),
|
|
)
|
|
return FollowUpPlan(
|
|
attempt=attempt,
|
|
scheduled_for=scheduled,
|
|
channel=channel,
|
|
body=body,
|
|
)
|