Skip to content

Commit 01f100e

Browse files
committed
fix: improve CS prompt
1 parent d0ea7f7 commit 01f100e

File tree

6 files changed

+85
-10
lines changed

6 files changed

+85
-10
lines changed

.env.defaults

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ LANCEDB_PATH=
533533
FORWARD_EMAIL_ALIAS_USERNAME=
534534
FORWARD_EMAIL_ALIAS_PASSWORD=
535535
# Processing
536-
CUSTOMER_SUPPORT_AI_INBOX_LIMIT=10
536+
CUSTOMER_SUPPORT_AI_INBOX_LIMIT=100
537537
# Historical Email Training
538538
HISTORY_SCAN_LIMIT=1000
539539
HISTORY_SCAN_SINCE=2023-01-01

.env.schema

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ LANCEDB_PATH=
484484
FORWARD_EMAIL_ALIAS_USERNAME=
485485
FORWARD_EMAIL_ALIAS_PASSWORD=
486486
# Processing
487-
CUSTOMER_SUPPORT_AI_INBOX_LIMIT=10
487+
CUSTOMER_SUPPORT_AI_INBOX_LIMIT=100
488488
# Historical Email Training
489489
HISTORY_SCAN_LIMIT=1000
490490
HISTORY_SCAN_SINCE=

config/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@ const config = {
877877
forwardEmailAliasUsername: env.FORWARD_EMAIL_ALIAS_USERNAME,
878878
forwardEmailAliasPassword: env.FORWARD_EMAIL_ALIAS_PASSWORD,
879879
customerSupportAiInboxLimit:
880-
Number.parseInt(env.CUSTOMER_SUPPORT_AI_INBOX_LIMIT, 10) || 10,
880+
Number.parseInt(env.CUSTOMER_SUPPORT_AI_INBOX_LIMIT, 10) || 100,
881881

882882
// server
883883
env: env.NODE_ENV.toLowerCase(),

helpers/customer-support-ai/message-analyzer.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ class MessageAnalyzer {
2121
sender: extractSenderEmail(message),
2222
senderName: extractSenderName(message),
2323
subject: message.subject || '(no subject)',
24+
date:
25+
message.nodemailer?.date ||
26+
message.date ||
27+
message.header_date ||
28+
new Date(),
2429
content,
2530
keywords,
2631
questionType,

helpers/customer-support-ai/response-generator.js

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,32 @@ class ResponseGenerator {
128128
customerName = 'there';
129129
}
130130

131+
// Check if email is old (15+ days)
132+
let messageDate = analysis.date || new Date();
133+
// Ensure messageDate is a Date object
134+
if (!(messageDate instanceof Date)) {
135+
messageDate = new Date(messageDate);
136+
}
137+
138+
// If date is invalid, use current date
139+
if (Number.isNaN(messageDate.getTime())) {
140+
messageDate = new Date();
141+
}
142+
143+
const now = new Date();
144+
const daysSinceMessage = Math.floor(
145+
(now - messageDate) / (1000 * 60 * 60 * 24)
146+
);
147+
const isOldEmail = daysSinceMessage >= 15 && daysSinceMessage < 365; // Cap at 1 year to avoid unrealistic values
148+
131149
let prompt = `You are a customer support representative for Forward Email (https://forwardemail.net), an open-source email service. Your voice is that of the "Forward Email team" - professional, friendly, and concise. Write like you talk to a friend, avoid complex vocabulary. Short sentences and break up complex thoughts into simple terms. It should sound like it was written by a human.
132150
133151
Customer Name: ${customerName}
134152
Customer Question Type: ${analysis.questionType}
135153
Urgency: ${analysis.urgency}
154+
Days Since Message: ${daysSinceMessage}${
155+
isOldEmail ? ' (OLD EMAIL - see instructions below)' : ''
156+
}
136157
137158
Relevant Knowledge Base Context:
138159
${context}`;
@@ -171,9 +192,10 @@ ${urlList}
171192
**CRITICAL: DO NOT FABRICATE FEATURES OR SETTINGS**
172193
1. ONLY describe features and settings that are explicitly mentioned in the Knowledge Base Context above
173194
2. NEVER invent UI elements, menu options, or configuration settings
174-
3. If you don't know how to do something, say "I don't have that information" and offer to escalate
195+
3. If you don't know how to do something, provide the best answer you can based on context
175196
4. NEVER make up step-by-step instructions unless they are in the context
176-
5. If the context doesn't contain the answer, admit it and ask the user to contact support directly
197+
5. NEVER say "I don't have that information" or "Please contact [email protected]" - you ARE support
198+
6. If context is limited, provide what you know and ask clarifying questions to help better
177199
178200
**CRITICAL: ABUSE REPORTS - EXACT INSTRUCTIONS**
179201
For ANY abuse, phishing, spam, fraud, or security reports:
@@ -185,6 +207,21 @@ For ANY abuse, phishing, spam, fraud, or security reports:
185207
6. DO NOT fabricate any additional steps or instructions
186208
7. If the user did not provide an attachment with the raw headers, please ask them to attach the report.
187209
210+
**CRITICAL: HELP REQUEST TEMPLATES**
211+
If the customer's message contains a "Your Help Request" section or similar template with Forward Email logo at bottom:
212+
1. This is a help request form submission - extract the ACTUAL customer question from within the template
213+
2. DO NOT echo back the template or repeat their message
214+
3. RESPOND to their specific question or issue
215+
4. Provide a helpful answer based on the knowledge base context
216+
5. Example: If they say "I'm getting an error for too many concurrent connections", diagnose and solve that problem
217+
218+
**CRITICAL: OLD EMAILS (15+ DAYS)**
219+
If Days Since Message is 15 or more:
220+
1. Acknowledge the delay: "I apologize for the delayed response"
221+
2. Provide the best answer you can based on the context
222+
3. Ask if they still need help: "Since it's been ${daysSinceMessage} days, please let me know if you still need assistance with this or if the issue has been resolved"
223+
4. Be understanding that the situation may have changed
224+
188225
========================================
189226
FORMATTING RULES - MANDATORY - NO EXCEPTIONS
190227
========================================
@@ -251,8 +288,9 @@ ACCURACY RULES - NO FABRICATION
251288
1. ONLY use information from the Knowledge Base Context above
252289
2. DO NOT invent features, settings, or UI elements
253290
3. DO NOT make up step-by-step instructions
254-
4. IF you don't know something, say "I don't have that information"
255-
5. IF the context doesn't have the answer, tell them to contact [email protected]
291+
4. NEVER say "I don't have that information" - you ARE the support team
292+
5. NEVER tell users to "contact [email protected]" - that's YOU
293+
6. If context is limited, provide what you know and ask clarifying questions
256294
257295
========================================
258296
CORE INSTRUCTIONS

jobs/customer-support-ai/process-inbox.js

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ const VectorStore = require('#helpers/customer-support-ai/vector-store');
1919
const messageAnalyzer = require('#helpers/customer-support-ai/message-analyzer');
2020
const responseGenerator = require('#helpers/customer-support-ai/response-generator');
2121
const {
22+
extractSenderEmail,
2223
extractSenderText,
24+
extractCC,
25+
extractRecipients,
2326
buildReplyRecipients
2427
} = require('#helpers/customer-support-ai/message-utils');
2528

@@ -344,10 +347,39 @@ async function createDraft(message, analysis, generatedResponse) {
344347
const from = config.forwardEmailAliasUsername;
345348

346349
// Build reply recipients (handles Reply-To and CC)
347-
const { to, cc } = buildReplyRecipients(message, from);
350+
let { to, cc } = buildReplyRecipients(message, from);
351+
352+
// CRITICAL: Never reply back to ourselves ([email protected])
353+
// If the original sender is support@forwardemail.net, this is a help request notification
354+
// Reply to the To header (the actual customer) instead
355+
const originalSender = extractSenderEmail(message);
356+
if (originalSender && originalSender.toLowerCase() === from.toLowerCase()) {
357+
// This email is from us ([email protected])
358+
// Reply to the To recipients (the actual customer)
359+
const toRecipients = extractRecipients(message);
360+
const nonSupportRecipients = toRecipients.filter(
361+
(email) => email.toLowerCase() !== from.toLowerCase()
362+
);
363+
364+
if (nonSupportRecipients.length > 0) {
365+
to = nonSupportRecipients[0];
366+
cc = nonSupportRecipients.slice(1);
367+
logger.info(
368+
{ originalSender, newTo: to, toRecipients, messageId: message.id },
369+
'Adjusted recipients - original sender was [email protected], replying to To recipient'
370+
);
371+
} else {
372+
// This is a self-email with no other recipients - skip it
373+
logger.warn(
374+
{ messageId: message.id, toRecipients },
375+
'Skipping draft creation - email is from [email protected] with no other recipients'
376+
);
377+
return null;
378+
}
379+
}
348380

349381
// Get original message details for quoting
350-
const originalSender = extractSenderText(message);
382+
const originalSenderText = extractSenderText(message);
351383
const originalDate =
352384
message.nodemailer?.date || message.header_date || new Date();
353385
const formattedDate = new Date(originalDate).toLocaleString('en-US', {
@@ -374,7 +406,7 @@ async function createDraft(message, analysis, generatedResponse) {
374406
// Note: Do NOT add signature here - LLM response should be complete
375407
const text = `${generatedResponse.response}
376408
377-
On ${formattedDate}, ${originalSender} wrote:
409+
On ${formattedDate}, ${originalSenderText} wrote:
378410
${quotedOriginal}`;
379411

380412
// Extract threading headers from API response

0 commit comments

Comments
 (0)