The most common complaint I hear from sales managers is that training doesn't transfer. Reps practice objection handling in generic role-plays — "you're selling software to a skeptical CFO" — and then freeze when the actual CFO at their actual prospect says something slightly different and more specific.
The reason training doesn't transfer is that it's disconnected from reality. The simulation doesn't know what objections Sarah Jenkins at Meridian Systems actually raised on the November 3rd call. It doesn't know that she's a CTO, that API documentation is her specific blocker, or that the Salesforce incumbent they're displacing has a 3-year contract expiring in Q2.
The Roleplay feature in the Deal Intelligence Agent fixes that by loading actual deal memory from Hindsight to build the simulation.
How the session bootstrap works
When a rep starts a roleplay session against a specific stakeholder, the RoleplayService pulls the full memory history for that deal and parses it by type:
async def start_session(self, deal_id: str, stakeholder_name: str) -> Dict:
memories = await self.memory.get_all_memories(deal_id)
stakeholders = [m for m in memories if m.get("type") == "stakeholder"]
objections = [m.get("content", "") for m in memories if m.get("type") == "objection"]
competitors = [m.get("metadata", {}).get("competitor_name", "")
for m in memories if m.get("type") == "competitor"]
pricing_notes = [m.get("content", "") for m in memories if m.get("type") == "pricing"]
Those aren't generic categories — they're the exact typed entries that were stored in Hindsight's persistent memory layer throughout the life of the deal. Every objection a rep logged, every competitor mention, every pricing note becomes training material.
The persona prompt gets built from this real data:
persona_prompt = f"""You are roleplaying as {selected_sh['name']},
the {selected_sh['title']} at {deal.get('company_name')}.
Your role in the deal is {selected_sh['role']}.
Objections you have raised: {', '.join(objections)}
Competitor options you are evaluating: {', '.join(filter(None, competitors))}
Pricing constraints: {', '.join(pricing_notes)}
Act realistically according to your title and role.
Keep responses brief, professional, and direct.
Raise the objections mentioned in the context when appropriate."""
The LLM isn't being asked to invent a persona. It's being asked to embody one that's already defined by real interaction history. The simulated stakeholder raises objections that the actual prospect has already raised. The rep isn't practicing against a generic scenario — they're practicing against the specific situation they're about to walk into.
The evaluation loop that writes back to memory
The part that surprised me most when building this: the evaluation feedback feeds back into the deal's probability estimates.
When a rep ends a session, evaluate_session sends the full transcript to the LLM for scoring:
evaluation_prompt = f"""Evaluate the Sales Rep's performance.
Return JSON with keys:
- objection_handling_score (0 to 100)
- communication_score (0 to 100)
- closing_readiness_score (0 to 100)
- feedback (string summary)
- strengths (list of strings)
- weaknesses (list of strings)
- recommended_actions (list of strings)"""
The scores aren't just displayed to the rep — they get written back to Hindsight as a roleplay_feedback entry and used to adjust the deal's closure probability:
current_prob = _deals[deal_id].get("closure_probability", 0.5)
perf_factor = (evaluation['objection_handling_score'] - 65) / 200.0
new_prob = max(0.1, min(0.95, current_prob + perf_factor))
_deals[deal_id]["closure_probability"] = round(new_prob, 2)
if evaluation['objection_handling_score'] > 85:
_deals[deal_id]["risk_level"] = "low"
elif evaluation['objection_handling_score'] < 50:
_deals[deal_id]["risk_level"] = "critical"
A rep who handles objections well — as measured against the real objections Hindsight has stored for that deal — moves the needle on deal risk. A rep who struggles signals that the deal needs attention before the next real call.
What this means for agent memory
The roleplay feature is really an argument about what persistent memory enables. Without Hindsight storing every interaction, every objection, every stakeholder note across the life of a deal, none of this is possible. You can't train against a prospect you don't know. You can't evaluate performance against a bar you haven't defined.
The memory layer isn't just for answering questions. It's substrate. Every feature that requires knowing something about history — briefings, risk scoring, autopilot playbooks, roleplay simulations — is downstream of it.
What I'd do differently: I'd store roleplay session transcripts and their scores in Hindsight from day one, not just use memory as input to the simulator. Over time, you'd build a corpus of "how did reps handle this objection type in training" that feeds back into the Autopilot's recommendation quality. The simulation becomes training data. Training data improves the simulation. The loop compounds.
GitHub: github.com/chaitanya07-ai/deal-intelligence-agent | Live: deal-intelligence-agent-1.onrender.com
Top comments (0)