diff --git a/apps/Backend/src/ai/reminder-graph.ts b/apps/Backend/src/ai/reminder-graph.ts index 048c162f..a1938b6f 100644 --- a/apps/Backend/src/ai/reminder-graph.ts +++ b/apps/Backend/src/ai/reminder-graph.ts @@ -111,10 +111,25 @@ async function confirmNode(state: GraphStateType, config: any) { } } +/** + * Strip any leading self-introduction ("Hi! My name is Lisa...") from a + * reschedule greeting template so it can be used as MSG 2 without duplicating + * the intro that was already sent as MSG 1. + */ +function stripIntroFromFallback(text: string): string { + // Matches patterns like: "Hi! My name is Lisa, ... . " or "Hi, I'm Lisa ... . " + const stripped = text + .replace(/^(Hi[!,]?\s*)?(My name is|I'?m|I am)\s+[^.!?]+[.!?]\s*/i, "") + .trim(); + return stripped || text; +} + async function rescheduleNode(state: GraphStateType, config: any) { const apiKey: string | undefined = config?.configurable?.apiKey; const lang = state.language || "English"; - const fallback = state.rescheduleGreeting || (RESCHEDULE_FALLBACKS[lang] ?? RESCHEDULE_FALLBACKS["English"]!); + // Strip any self-intro from the saved template — intro is already sent as MSG 1 + const rawFallback = state.rescheduleGreeting || (RESCHEDULE_FALLBACKS[lang] ?? RESCHEDULE_FALLBACKS["English"]!); + const fallback = stripIntroFromFallback(rawFallback); if (!apiKey) return { reply: fallback }; @@ -124,7 +139,7 @@ async function rescheduleNode(state: GraphStateType, config: any) { { role: "system", content: - `You are a friendly dental office assistant. The patient cannot make their appointment. Write a short, empathetic SMS reply (1-2 sentences max) acknowledging they can't make it and asking when they would like to reschedule. You MUST reply in ${lang}. Do not add any formatting or extra text.`, + `You are a friendly dental office assistant. The patient cannot make their appointment. Write a short, empathetic SMS reply (1-2 sentences max) acknowledging they can't make it and asking when they would like to reschedule. Do NOT introduce yourself or say your name — the introduction has already been sent in a separate message. You MUST reply in ${lang}. No formatting, no extra text.`, }, { role: "user", content: `Patient replied: "${state.message}"` }, ]); diff --git a/apps/Frontend/src/components/settings/ai-chat-templates-card.tsx b/apps/Frontend/src/components/settings/ai-chat-templates-card.tsx index fbe48d30..1e168dfb 100644 --- a/apps/Frontend/src/components/settings/ai-chat-templates-card.tsx +++ b/apps/Frontend/src/components/settings/ai-chat-templates-card.tsx @@ -48,6 +48,11 @@ function unsupportedVars(text: string): string[] { ); } +/** True if text starts with a self-introduction ("Hi! My name is Lisa…"). */ +function hasIntroPattern(text: string): boolean { + return /^(Hi[!,]?\s*)?(My name is|I'?m|I am)\s+/i.test(text.trim()); +} + export function AiChatTemplatesCard() { const { toast } = useToast(); @@ -203,7 +208,9 @@ export function AiChatTemplatesCard() { ) : (