stackConsult commited on
Commit
566bdbd
·
verified ·
1 Parent(s): 3a76be2

Integrate lead_scoring_agent into outreach_agent.py - Add score_lead() as first logic step in intake_lead()

Browse files
Files changed (1) hide show
  1. outreach_agent.py +28 -13
outreach_agent.py CHANGED
@@ -1,23 +1,40 @@
1
  import logging
2
  from typing import Dict, Any, Optional, List, Callable
 
 
3
 
4
  class OutreachAgent:
 
 
 
 
5
  def __init__(self, channel_handlers: Optional[Dict[str, Callable]]=None):
6
  self.logger = logging.getLogger("OutreachAgent")
7
  self.lead_assets = {}
8
  self.analytics = []
9
  self.channel_handlers = channel_handlers or {}
10
-
11
  def intake_lead(self, lead_profile: Dict[str, Any]) -> Dict[str, Any]:
12
- enriched_profile = self.validate_and_enrich_profile(lead_profile)
 
 
 
 
 
 
 
 
 
13
  self.logger.info(f"Intake for {enriched_profile.get('name', 'Unknown Lead')}")
 
14
  asset_id = enriched_profile.get('id')
15
  if asset_id:
16
  self.lead_assets[asset_id] = enriched_profile
17
  return enriched_profile
18
-
19
  def validate_and_enrich_profile(self, profile: Dict[str, Any]) -> Dict[str, Any]:
20
  # Enrich with historical, persona, engagements, etc.
 
21
  required_fields = ['persona', 'channel_fit']
22
  for field in required_fields:
23
  if field not in profile:
@@ -27,7 +44,7 @@ class OutreachAgent:
27
  if 'recent_posts' not in profile:
28
  profile['recent_posts'] = []
29
  return profile
30
-
31
  def select_template(self, profile: Dict[str, Any]) -> str:
32
  persona = profile.get('persona', 'Generic')
33
  pain = profile.get('pain_opportunity', 'N/A')
@@ -36,7 +53,7 @@ class OutreachAgent:
36
  # Template selection logic (expandable)
37
  template = f"Hi {{name}}, as a {{persona}}, we noticed: {{pain}}. {{buyer_signals}}. Ready to discuss via {{channel}}?"
38
  return template
39
-
40
  def tailor_message(self, profile: Dict[str, Any], template: str) -> str:
41
  variables = {
42
  "name": profile.get("name", "there"),
@@ -63,7 +80,7 @@ class OutreachAgent:
63
  if variables["urgency"]:
64
  message += f"\nUrgency triggers: {variables['urgency']}"
65
  return message
66
-
67
  def deliver(self, profile: Dict[str, Any], message: str, channel: str) -> Dict[str, Any]:
68
  # Channel handler pattern for extensibility
69
  handler = self.channel_handlers.get(channel, self.default_handler)
@@ -71,11 +88,11 @@ class OutreachAgent:
71
  self.logger.info(f"Delivered to {profile.get('name')} via {channel}")
72
  self.update_analytics(profile, channel, result)
73
  return result
74
-
75
  def default_handler(self, profile: Dict[str, Any], message: str) -> Dict[str, Any]:
76
  # Simulate sending logic
77
  return {"status": "sent", "channel": profile.get('channel_fit', 'email'), "message": message}
78
-
79
  def browser_social_actions(self, profile: Dict[str, Any], action: str, extra: Optional[Dict[str, Any]]=None) -> Dict[str, Any]:
80
  # Simulate browser agent: connect, DM, comment, like, milestone outreach
81
  valid_actions = ["connect", "dm", "comment", "like", "milestone"]
@@ -85,7 +102,7 @@ class OutreachAgent:
85
  result = {"action": action, "status": "success", "lead": profile.get('id')}
86
  self.update_analytics(profile, "social_action", result)
87
  return result
88
-
89
  def update_analytics(self, profile: Dict[str, Any], channel: str, result: Dict[str, Any]):
90
  entry = {
91
  "lead_id": profile.get("id"),
@@ -95,14 +112,14 @@ class OutreachAgent:
95
  self.analytics.append(entry)
96
  if profile.get("id") in self.lead_assets:
97
  self.lead_assets[profile.get("id")]["last_engagement"] = entry
98
-
99
  def feedback_loop(self, profile: Dict[str, Any], feedback: str):
100
  # Store feedback and auto-update asset
101
  pid = profile.get("id")
102
  if pid and pid in self.lead_assets:
103
  self.lead_assets[pid]["feedback"] = feedback
104
  self.logger.info(f"Feedback for {profile.get('name')}: {feedback}")
105
-
106
  def get_transcript(self, profile_id: str) -> Dict[str, Any]:
107
  asset = self.lead_assets.get(profile_id)
108
  return {
@@ -112,13 +129,11 @@ class OutreachAgent:
112
  }
113
 
114
  # Example usage handler for email
115
-
116
  def email_handler(profile, message):
117
  # Integrate real email API here
118
  return {"status": "sent_via_email", "recipient": profile.get("email", "n/a"), "message": message}
119
 
120
  # Example handlers for expansion for LinkedIn, SMS, browser agent, etc.
121
-
122
  def linkedin_handler(profile, message):
123
  # Integrate real LinkedIn API calls here
124
  return {"status": "sent_via_linkedin", "recipient": profile.get("linkedin", "n/a"), "message": message}
 
1
  import logging
2
  from typing import Dict, Any, Optional, List, Callable
3
+ # Import lead_scoring_agent for lead scoring integration
4
+ from lead_scoring_agent import score_lead
5
 
6
  class OutreachAgent:
7
+ """
8
+ OutreachAgent handles lead intake, message tailoring, and multi-channel delivery.
9
+ Integrates lead_scoring_agent to score leads at intake for prioritization and routing.
10
+ """
11
  def __init__(self, channel_handlers: Optional[Dict[str, Callable]]=None):
12
  self.logger = logging.getLogger("OutreachAgent")
13
  self.lead_assets = {}
14
  self.analytics = []
15
  self.channel_handlers = channel_handlers or {}
16
+
17
  def intake_lead(self, lead_profile: Dict[str, Any]) -> Dict[str, Any]:
18
+ """
19
+ Intake lead with scoring integration as first logic step.
20
+ Calls score_lead(profile) to enrich profile with scoring metadata.
21
+ """
22
+ # FIRST STEP: Score the lead using lead_scoring_agent
23
+ scored_profile = score_lead(lead_profile)
24
+ self.logger.info(f"Lead scored: {scored_profile.get('name', 'Unknown')} - Score: {scored_profile.get('lead_score', 'N/A')}")
25
+
26
+ # Enrich profile with additional data
27
+ enriched_profile = self.validate_and_enrich_profile(scored_profile)
28
  self.logger.info(f"Intake for {enriched_profile.get('name', 'Unknown Lead')}")
29
+
30
  asset_id = enriched_profile.get('id')
31
  if asset_id:
32
  self.lead_assets[asset_id] = enriched_profile
33
  return enriched_profile
34
+
35
  def validate_and_enrich_profile(self, profile: Dict[str, Any]) -> Dict[str, Any]:
36
  # Enrich with historical, persona, engagements, etc.
37
+ # Preserve scoring metadata from lead_scoring_agent
38
  required_fields = ['persona', 'channel_fit']
39
  for field in required_fields:
40
  if field not in profile:
 
44
  if 'recent_posts' not in profile:
45
  profile['recent_posts'] = []
46
  return profile
47
+
48
  def select_template(self, profile: Dict[str, Any]) -> str:
49
  persona = profile.get('persona', 'Generic')
50
  pain = profile.get('pain_opportunity', 'N/A')
 
53
  # Template selection logic (expandable)
54
  template = f"Hi {{name}}, as a {{persona}}, we noticed: {{pain}}. {{buyer_signals}}. Ready to discuss via {{channel}}?"
55
  return template
56
+
57
  def tailor_message(self, profile: Dict[str, Any], template: str) -> str:
58
  variables = {
59
  "name": profile.get("name", "there"),
 
80
  if variables["urgency"]:
81
  message += f"\nUrgency triggers: {variables['urgency']}"
82
  return message
83
+
84
  def deliver(self, profile: Dict[str, Any], message: str, channel: str) -> Dict[str, Any]:
85
  # Channel handler pattern for extensibility
86
  handler = self.channel_handlers.get(channel, self.default_handler)
 
88
  self.logger.info(f"Delivered to {profile.get('name')} via {channel}")
89
  self.update_analytics(profile, channel, result)
90
  return result
91
+
92
  def default_handler(self, profile: Dict[str, Any], message: str) -> Dict[str, Any]:
93
  # Simulate sending logic
94
  return {"status": "sent", "channel": profile.get('channel_fit', 'email'), "message": message}
95
+
96
  def browser_social_actions(self, profile: Dict[str, Any], action: str, extra: Optional[Dict[str, Any]]=None) -> Dict[str, Any]:
97
  # Simulate browser agent: connect, DM, comment, like, milestone outreach
98
  valid_actions = ["connect", "dm", "comment", "like", "milestone"]
 
102
  result = {"action": action, "status": "success", "lead": profile.get('id')}
103
  self.update_analytics(profile, "social_action", result)
104
  return result
105
+
106
  def update_analytics(self, profile: Dict[str, Any], channel: str, result: Dict[str, Any]):
107
  entry = {
108
  "lead_id": profile.get("id"),
 
112
  self.analytics.append(entry)
113
  if profile.get("id") in self.lead_assets:
114
  self.lead_assets[profile.get("id")]["last_engagement"] = entry
115
+
116
  def feedback_loop(self, profile: Dict[str, Any], feedback: str):
117
  # Store feedback and auto-update asset
118
  pid = profile.get("id")
119
  if pid and pid in self.lead_assets:
120
  self.lead_assets[pid]["feedback"] = feedback
121
  self.logger.info(f"Feedback for {profile.get('name')}: {feedback}")
122
+
123
  def get_transcript(self, profile_id: str) -> Dict[str, Any]:
124
  asset = self.lead_assets.get(profile_id)
125
  return {
 
129
  }
130
 
131
  # Example usage handler for email
 
132
  def email_handler(profile, message):
133
  # Integrate real email API here
134
  return {"status": "sent_via_email", "recipient": profile.get("email", "n/a"), "message": message}
135
 
136
  # Example handlers for expansion for LinkedIn, SMS, browser agent, etc.
 
137
  def linkedin_handler(profile, message):
138
  # Integrate real LinkedIn API calls here
139
  return {"status": "sent_via_linkedin", "recipient": profile.get("linkedin", "n/a"), "message": message}