@realtimex/email-automator 2.12.1 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,6 +25,8 @@ export const EmailAnalysisSchema = z.object({
25
25
  .describe('Key points extracted from the email'),
26
26
  action_items: z.array(z.string()).optional()
27
27
  .describe('Action items mentioned in the email'),
28
+ language: z.string().optional()
29
+ .describe('The primary language of the email (e.g., "English", "Vietnamese", "Japanese", "Spanish")'),
28
30
  });
29
31
 
30
32
  export type EmailAnalysis = z.infer<typeof EmailAnalysisSchema>;
@@ -205,7 +207,26 @@ REQUIRED JSON STRUCTURE:
205
207
  async generateDraftReply(
206
208
  originalEmail: { subject: string; sender: string; body: string },
207
209
  instructions?: string,
208
- llmSettings?: { llm_provider?: string; llm_model?: string }
210
+ llmSettings?: { llm_provider?: string; llm_model?: string },
211
+ richContext?: {
212
+ // User/Account metadata
213
+ myEmail?: string;
214
+ myName?: string;
215
+ myRole?: string;
216
+ myCompany?: string;
217
+
218
+ // Email analysis metadata
219
+ category?: string;
220
+ sentiment?: string;
221
+ priority?: string;
222
+ keyPoints?: string[];
223
+ language?: string;
224
+
225
+ // Sender metadata
226
+ senderEmail?: string;
227
+ senderName?: string;
228
+ receivedDate?: Date;
229
+ }
209
230
  ): Promise<string | null> {
210
231
  const sdk = SDKService.getSDK();
211
232
  if (!sdk) return null;
@@ -216,14 +237,73 @@ REQUIRED JSON STRUCTURE:
216
237
  });
217
238
 
218
239
  try {
240
+ // Build rich system prompt with context
241
+ let systemPrompt = 'You are an AI email assistant drafting a professional reply.';
242
+
243
+ if (richContext?.myEmail) {
244
+ systemPrompt += `\n\nYou are responding on behalf of ${richContext.myName || 'the user'} (${richContext.myEmail})`;
245
+ if (richContext.myRole) {
246
+ systemPrompt += `, a ${richContext.myRole}`;
247
+ }
248
+ if (richContext.myCompany) {
249
+ systemPrompt += ` at ${richContext.myCompany}`;
250
+ }
251
+ systemPrompt += '.';
252
+ }
253
+
254
+ if (richContext?.category) {
255
+ systemPrompt += `\n\nThis is a ${richContext.category} email`;
256
+ if (richContext.sentiment) {
257
+ systemPrompt += ` with a ${richContext.sentiment.toLowerCase()} tone`;
258
+ }
259
+ if (richContext.priority) {
260
+ systemPrompt += ` (priority: ${richContext.priority.toLowerCase()})`;
261
+ }
262
+ systemPrompt += '.';
263
+ }
264
+
265
+ if (instructions) {
266
+ systemPrompt += `\n\nYOUR SPECIFIC TASK: ${instructions}`;
267
+ }
268
+
269
+ // Language handling - CRITICAL for multi-language support
270
+ if (richContext?.language) {
271
+ systemPrompt += `\n\nIMPORTANT: The incoming email is written in ${richContext.language}. You MUST write your reply in ${richContext.language}. Maintain appropriate formality and cultural conventions for ${richContext.language}.`;
272
+ }
273
+
274
+ systemPrompt += '\n\nWrite ONLY the email body (no subject line). Be natural, concise, and professional. Match the tone of the incoming email.';
275
+
276
+ // Build user message with email context
277
+ let userMessage = '';
278
+
279
+ if (richContext?.senderEmail || richContext?.senderName) {
280
+ userMessage += `INCOMING EMAIL:\n`;
281
+ userMessage += `From: ${richContext.senderName || originalEmail.sender}`;
282
+ if (richContext.senderEmail && richContext.senderEmail !== originalEmail.sender) {
283
+ userMessage += ` <${richContext.senderEmail}>`;
284
+ }
285
+ userMessage += '\n';
286
+ if (richContext.receivedDate) {
287
+ userMessage += `Received: ${richContext.receivedDate.toLocaleString()}\n`;
288
+ }
289
+ }
290
+
291
+ userMessage += `Subject: ${originalEmail.subject}\n\n`;
292
+
293
+ if (richContext?.keyPoints && richContext.keyPoints.length > 0) {
294
+ userMessage += `KEY POINTS:\n${richContext.keyPoints.map(p => `• ${p}`).join('\n')}\n\n`;
295
+ }
296
+
297
+ userMessage += `FULL MESSAGE:\n${originalEmail.body}`;
298
+
219
299
  const response = await sdk.llm.chat([
220
300
  {
221
301
  role: 'system',
222
- content: `Generate a professional reply. ${instructions || ''}`,
302
+ content: systemPrompt,
223
303
  },
224
304
  {
225
305
  role: 'user',
226
- content: `From: ${originalEmail.sender}\nSubject: ${originalEmail.subject}\n\n${originalEmail.body}`,
306
+ content: userMessage,
227
307
  },
228
308
  ], { provider, model });
229
309
 
@@ -802,6 +802,23 @@ export class EmailProcessorService {
802
802
 
803
803
  const intelligenceService = getIntelligenceService();
804
804
 
805
+ // Build rich context for better drafts
806
+ const emailDomain = account.email_address?.split('@')[1] || undefined;
807
+ const richContext = {
808
+ myEmail: account.email_address,
809
+ myName: undefined, // Profile not available in this scope
810
+ myRole: settings?.user_role || undefined,
811
+ myCompany: emailDomain,
812
+ category: analysis?.category,
813
+ sentiment: analysis?.sentiment,
814
+ priority: analysis?.priority,
815
+ keyPoints: analysis?.key_points,
816
+ language: analysis?.language, // Multi-language support
817
+ senderEmail: email.sender || undefined,
818
+ senderName: email.sender || undefined,
819
+ receivedDate: email.date ? new Date(email.date) : undefined
820
+ };
821
+
805
822
  const customizedDraft = await intelligenceService.generateDraftReply({
806
823
  subject: email.subject || '',
807
824
  sender: email.sender || '',
@@ -809,7 +826,7 @@ export class EmailProcessorService {
809
826
  }, rule.instructions, {
810
827
  llm_provider: settings?.llm_provider,
811
828
  llm_model: settings?.llm_model
812
- });
829
+ }, richContext);
813
830
 
814
831
  if (customizedDraft) {
815
832
  draftContent = customizedDraft;
@@ -22,6 +22,8 @@ export const EmailAnalysisSchema = z.object({
22
22
  .describe('Key points extracted from the email'),
23
23
  action_items: z.array(z.string()).optional()
24
24
  .describe('Action items mentioned in the email'),
25
+ language: z.string().optional()
26
+ .describe('The primary language of the email (e.g., "English", "Vietnamese", "Japanese", "Spanish")'),
25
27
  });
26
28
  // Context-Aware Analysis Schema - AI evaluates email against user's rules
27
29
  export const ContextAwareAnalysisSchema = z.object({
@@ -156,7 +158,7 @@ REQUIRED JSON STRUCTURE:
156
158
  return null;
157
159
  }
158
160
  }
159
- async generateDraftReply(originalEmail, instructions, llmSettings) {
161
+ async generateDraftReply(originalEmail, instructions, llmSettings, richContext) {
160
162
  const sdk = SDKService.getSDK();
161
163
  if (!sdk)
162
164
  return null;
@@ -165,14 +167,62 @@ REQUIRED JSON STRUCTURE:
165
167
  llm_model: llmSettings?.llm_model
166
168
  });
167
169
  try {
170
+ // Build rich system prompt with context
171
+ let systemPrompt = 'You are an AI email assistant drafting a professional reply.';
172
+ if (richContext?.myEmail) {
173
+ systemPrompt += `\n\nYou are responding on behalf of ${richContext.myName || 'the user'} (${richContext.myEmail})`;
174
+ if (richContext.myRole) {
175
+ systemPrompt += `, a ${richContext.myRole}`;
176
+ }
177
+ if (richContext.myCompany) {
178
+ systemPrompt += ` at ${richContext.myCompany}`;
179
+ }
180
+ systemPrompt += '.';
181
+ }
182
+ if (richContext?.category) {
183
+ systemPrompt += `\n\nThis is a ${richContext.category} email`;
184
+ if (richContext.sentiment) {
185
+ systemPrompt += ` with a ${richContext.sentiment.toLowerCase()} tone`;
186
+ }
187
+ if (richContext.priority) {
188
+ systemPrompt += ` (priority: ${richContext.priority.toLowerCase()})`;
189
+ }
190
+ systemPrompt += '.';
191
+ }
192
+ if (instructions) {
193
+ systemPrompt += `\n\nYOUR SPECIFIC TASK: ${instructions}`;
194
+ }
195
+ // Language handling - CRITICAL for multi-language support
196
+ if (richContext?.language) {
197
+ systemPrompt += `\n\nIMPORTANT: The incoming email is written in ${richContext.language}. You MUST write your reply in ${richContext.language}. Maintain appropriate formality and cultural conventions for ${richContext.language}.`;
198
+ }
199
+ systemPrompt += '\n\nWrite ONLY the email body (no subject line). Be natural, concise, and professional. Match the tone of the incoming email.';
200
+ // Build user message with email context
201
+ let userMessage = '';
202
+ if (richContext?.senderEmail || richContext?.senderName) {
203
+ userMessage += `INCOMING EMAIL:\n`;
204
+ userMessage += `From: ${richContext.senderName || originalEmail.sender}`;
205
+ if (richContext.senderEmail && richContext.senderEmail !== originalEmail.sender) {
206
+ userMessage += ` <${richContext.senderEmail}>`;
207
+ }
208
+ userMessage += '\n';
209
+ if (richContext.receivedDate) {
210
+ userMessage += `Received: ${richContext.receivedDate.toLocaleString()}\n`;
211
+ }
212
+ }
213
+ userMessage += `Subject: ${originalEmail.subject}\n\n`;
214
+ if (richContext?.keyPoints && richContext.keyPoints.length > 0) {
215
+ userMessage += `KEY POINTS:\n${richContext.keyPoints.map(p => `• ${p}`).join('\n')}\n\n`;
216
+ }
217
+ userMessage += `FULL MESSAGE:\n${originalEmail.body}`;
168
218
  const response = await sdk.llm.chat([
169
219
  {
170
220
  role: 'system',
171
- content: `Generate a professional reply. ${instructions || ''}`,
221
+ content: systemPrompt,
172
222
  },
173
223
  {
174
224
  role: 'user',
175
- content: `From: ${originalEmail.sender}\nSubject: ${originalEmail.subject}\n\n${originalEmail.body}`,
225
+ content: userMessage,
176
226
  },
177
227
  ], { provider, model });
178
228
  // Check if SDK call failed
@@ -662,6 +662,22 @@ export class EmailProcessorService {
662
662
  if (eventLogger)
663
663
  await eventLogger.info('Thinking', `Generating customized draft based on rule: ${rule.name}`, undefined, email.id);
664
664
  const intelligenceService = getIntelligenceService();
665
+ // Build rich context for better drafts
666
+ const emailDomain = account.email_address?.split('@')[1] || undefined;
667
+ const richContext = {
668
+ myEmail: account.email_address,
669
+ myName: undefined, // Profile not available in this scope
670
+ myRole: settings?.user_role || undefined,
671
+ myCompany: emailDomain,
672
+ category: analysis?.category,
673
+ sentiment: analysis?.sentiment,
674
+ priority: analysis?.priority,
675
+ keyPoints: analysis?.key_points,
676
+ language: analysis?.language, // Multi-language support
677
+ senderEmail: email.sender || undefined,
678
+ senderName: email.sender || undefined,
679
+ receivedDate: email.date ? new Date(email.date) : undefined
680
+ };
665
681
  const customizedDraft = await intelligenceService.generateDraftReply({
666
682
  subject: email.subject || '',
667
683
  sender: email.sender || '',
@@ -669,7 +685,7 @@ export class EmailProcessorService {
669
685
  }, rule.instructions, {
670
686
  llm_provider: settings?.llm_provider,
671
687
  llm_model: settings?.llm_model
672
- });
688
+ }, richContext);
673
689
  if (customizedDraft) {
674
690
  draftContent = customizedDraft;
675
691
  }