/** * ClinicAgent: An agentic orchestrator for Curio. * It uses natural language understanding to map user requests to hospital tools. */ const patientManager = require('./patientManager'); const queueManager = require('./queueManager'); const pharmacyAgent = require('./pharmacyAgent'); const configManager = require('./configManager'); const Anthropic = require('@anthropic-ai/sdk'); const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY, // Defaults to process.env.ANTHROPIC_API_KEY }); const LLM_MODEL = process.env.LLM_MODEL || 'claude-3-haiku-20240307'; class ClinicAgent { 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}. 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. `; } async processMessage(phone, transcript) { console.log(`[Agent] Processing for ${phone} via Claude`); try { const response = await anthropic.messages.create({ model: LLM_MODEL, max_tokens: 300, temperature: 0.2, system: this.getSystemPrompt(), messages: transcript }); const replyContent = response.content[0].text.trim(); // Try to parse JSON intent try { const cleanJson = replyContent.replace(/```json/g, '').replace(/```/g, '').trim(); const intent = JSON.parse(cleanJson); if (intent.action === 'BOOK') { let timeVal = "10:00"; const timeMatch = intent.time.match(/(\d{1,2}:\d{2})/); if (timeMatch) timeVal = timeMatch[1]; let dateVal = new Date().toISOString().split('T')[0]; if (intent.date && intent.date.match(/^\d{4}-\d{2}-\d{2}$/)) { dateVal = intent.date; } 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 for ${dateVal} at ${timeVal}. Your token is ${result.token}. We look forward to seeing you!` }; } else { 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) { // Not JSON, just regular conversational text return { reply: replyContent }; } return { reply: replyContent }; } catch (error) { console.error('[ClinicAgent] LLM Error:', error.message); return { reply: "I'm having trouble connecting to my AI brain right now. Please try again in a moment." }; } } } module.exports = new ClinicAgent();