Refine Claude WhatsApp agent: add empathy, dynamic dates, and cancellation intent
Build Curio HMS / build-and-deploy (push) Successful in 1m8s Details

This commit is contained in:
Deep Koluguri 2026-05-26 18:40:43 -04:00
parent 2b7cea1df3
commit c55467a068
1 changed files with 47 additions and 24 deletions

View File

@ -15,21 +15,37 @@ const anthropic = new Anthropic({
const LLM_MODEL = process.env.LLM_MODEL || 'claude-3-haiku-20240307';
class ClinicAgent {
constructor() {
this.systemPrompt = `
You are 'Curio AI', the assistant for Curio Health.
Your goal is to help patients book appointments.
Be extremely concise, friendly, and natural. Do not use markdown.
To book an appointment, you MUST collect:
1. Department (e.g. Cardiology, Neurology, General)
2. Date (Format as YYYY-MM-DD or today/tomorrow)
3. Time (Format as HH:MM AM/PM)
If any of these 3 pieces of information are missing, naturally ask the user for them.
Do NOT output JSON until you have ALL THREE pieces of information.
getSystemPrompt() {
const today = new Date().toISOString().split('T')[0];
return `
You are 'Curio AI', the highly empathetic and intelligent medical assistant for Curio Health.
Today's date is ${today}.
If you have all three pieces of information, you MUST reply with ONLY a JSON block like this (no other text):
{"action": "BOOK", "department": "Cardiology", "date": "2026-05-26", "time": "10:00"}
Your goal is to help patients book, cancel, or reschedule appointments, and answer basic clinic questions.
Be extremely concise, warm, empathetic, and natural. Do not use markdown formatting.
AVAILABLE CLINICS/DEPARTMENTS:
- Cardiology (Dr. Sharma)
- General Medicine (Apollo)
- Pediatrics
- Orthopedics
INTENT 1: BOOKING
To book an appointment, you MUST collect:
1. Department/Clinic
2. Date (Format as YYYY-MM-DD)
3. Time (Format as HH:MM)
If any booking info is missing, naturally ask the user. Do NOT output JSON until you have ALL THREE pieces.
If you have all three, reply with ONLY JSON:
{"action": "BOOK", "department": "Cardiology", "date": "${today}", "time": "10:00"}
INTENT 2: CANCEL
If they want to cancel, ask them to confirm the date and time of the appointment they want to cancel. Once confirmed, reply with ONLY JSON:
{"action": "CANCEL", "date": "${today}", "time": "10:00"}
INTENT 3: GENERAL QUERY
If they ask general questions (e.g., location, hours), just answer naturally as the assistant. If they express pain or worry, respond with empathy before helping them.
`;
}
@ -41,7 +57,7 @@ class ClinicAgent {
model: LLM_MODEL,
max_tokens: 300,
temperature: 0.2,
system: this.systemPrompt,
system: this.getSystemPrompt(),
messages: transcript
});
@ -49,29 +65,36 @@ class ClinicAgent {
// Try to parse JSON intent
try {
// Remove potential markdown code blocks if the LLM wrapped it
const cleanJson = replyContent.replace(/```json/g, '').replace(/```/g, '').trim();
const intent = JSON.parse(cleanJson);
if (intent.action === 'BOOK') {
// Extract HH:MM
let timeVal = "10:00"; // fallback
let timeVal = "10:00";
const timeMatch = intent.time.match(/(\d{1,2}:\d{2})/);
if (timeMatch) timeVal = timeMatch[1];
// Parse date
let dateVal = new Date().toISOString().split('T')[0];
if (intent.date && intent.date.match(/^\d{4}-\d{2}-\d{2}$/)) {
dateVal = intent.date;
}
// Book the token using Dr. Sharma's Cardiology ("sharma-clinic")
// In a real system, we'd map intent.department to tenantId
const result = await queueManager.bookOnline(dateVal, timeVal, phone, 'sharma-clinic');
let tenantId = 'sharma-clinic'; // Default
if (intent.department && intent.department.toLowerCase().includes('general')) tenantId = 'apollo-hospitals';
const result = await queueManager.bookOnline(dateVal, timeVal, phone, tenantId);
if (result.success) {
return { reply: `Awesome! Your appointment for ${intent.department} is booked. Your token is ${result.token}. You should receive a confirmation message shortly.` };
return { reply: `Awesome! Your appointment for ${intent.department} is booked for ${dateVal} at ${timeVal}. Your token is ${result.token}. We look forward to seeing you!` };
} else {
return { reply: `Sorry, ${result.message}` };
return { reply: `I'm so sorry, but ${result.message.toLowerCase()} Would you like to try a different time or day?` };
}
} else if (intent.action === 'CANCEL') {
let dateVal = intent.date || new Date().toISOString().split('T')[0];
let timeVal = intent.time || "10:00";
const result = await queueManager.cancelBooking(dateVal, timeVal, 'sharma-clinic');
if (result.success) {
return { reply: `Done. I've cancelled your appointment for ${dateVal} at ${timeVal}. Let me know if you need to book a new one!` };
} else {
return { reply: `Hmm, I couldn't find a booking for ${dateVal} at ${timeVal} to cancel. Could you double-check the time for me?` };
}
}
} catch (e) {