Skip to content

Email assistant#313

Merged
elie222 merged 62 commits intomainfrom
email-assistant
Jan 26, 2025
Merged

Email assistant#313
elie222 merged 62 commits intomainfrom
email-assistant

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Jan 19, 2025

Summary by CodeRabbit

Based on the comprehensive pull request summary, here are the updated high-level release notes:

  • New Features

    • Enhanced email processing capabilities with improved assistant email handling.
    • Introduced new functions for managing group items and user categories.
    • Added advanced email reply and content parsing functions.
    • Added a new function to process user requests related to email management rules.
    • Introduced a function for retrieving user categories based on names.
  • Improvements

    • Refined email content extraction and parsing logic.
    • Enhanced type safety for email-related data structures.
    • Improved error handling and logging for email and rule operations.
    • Streamlined the handling of email actions and responses.
    • Updated logic for email reply processing to utilize a new parsing library.
  • Bug Fixes

    • Updated email parsing to handle complex email formats more accurately.
    • Fixed issues with email reply and forwarded content extraction.
  • Technical Updates

    • Migrated from node-email-reply-parser to email-reply-parser.
    • Consolidated type definitions across multiple modules.
    • Improved type safety and import management.
    • Renamed and restructured several functions for better clarity and organization.

@vercel
Copy link

vercel bot commented Jan 19, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
inbox-zero ✅ Ready (Inspect) Visit Preview Jan 26, 2025 8:50pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 19, 2025

Warning

Rate limit exceeded

@elie222 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 21 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between ea0ce31 and 8b4305e.

📒 Files selected for processing (2)
  • apps/web/__tests__/ai-rule-fix.test.ts (5 hunks)
  • apps/web/utils/ai/rule/rule-fix.ts (4 hunks)

Walkthrough

This pull request introduces several significant changes across the application, focusing on email management, rule processing, and assistant functionality. The changes span multiple modules, including email parsing, rule creation, categorization, and AI-driven interactions. Key modifications include the removal of the onboarding interface, enhancements to email content extraction, improvements in rule management functions, the addition of new utility functions for group and sender handling, and the implementation of more robust email processing mechanisms.

Changes

File Change Summary
apps/web/app/(app)/onboarding-old2/page.tsx Removed the Onboarding React component responsible for rendering the onboarding interface.
apps/web/app/api/google/webhook/process-history.ts Added imports and modified processHistoryItem to handle assistant email checks; refactored last synced history ID updates.
apps/web/utils/assistant/is-assistant-email.ts Introduced isAssistantEmail function and ASSISTANT_SUFFIX constant for identifying assistant emails.
apps/web/utils/assistant/process-assistant-email.ts Added processAssistantEmail function for handling emails directed to an assistant.
apps/web/utils/gmail/mail.ts Added replyToEmail function for replying to emails; updated existing email functions to support a new from parameter.
apps/web/utils/email.ts Enhanced extractEmailAddress function for better email extraction logic.
apps/web/utils/actions/rule.ts Added updateRuleInstructionsAndPromptFile function for modular rule updates.
apps/web/utils/rule/rule.ts Introduced new functions for managing rules, including safeCreateRule and safeUpdateRule.
apps/web/utils/types.ts Added EmailForLLM type and modified ParsedMessageHeaders interface.
apps/web/utils/group/group-item.ts Introduced addGroupItem and deleteGroupItem functions for managing group items.
apps/web/__tests__/ai-process-user-request.test.ts Added a new test suite for processUserRequest function with various scenarios.

Possibly related PRs

Poem

🐰 Hop, hop, through email's maze,
Rules dancing in algorithmic praise,
Parsing messages with digital grace,
Assistants leaping at lightning pace,
Inbox zero, our technological craze! 🚀


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (5)
apps/web/utils/ai/assistant/process-user-request.ts (1)

37-44: Consider externalizing the system prompt for maintainability

The system prompt is currently defined inline within the function. To enhance maintainability and facilitate updates, consider externalizing the system prompt into a separate constant or configuration file.

apps/web/utils/assistant/is-assistant-email.ts (1)

11-12: Normalize email addresses before comparison to handle case sensitivity

Email addresses are generally case-insensitive, especially in the local part. Comparing assistantEmail and recipientEmail without normalizing may lead to false negatives if the casing differs. Consider converting both emails to lowercase before comparison.

Apply this diff to normalize the email addresses:

  const assistantEmail = `${localPart}+${ASSISTANT_SUFFIX}@${domain}`;
- return assistantEmail === recipientEmail;
+ return assistantEmail.toLowerCase() === recipientEmail.toLowerCase();
apps/web/utils/assistant/is-assistant-email.test.ts (1)

21-27: Consider adding more test cases for edge scenarios.

While the current test cases cover the basic scenarios, consider adding tests for:

  • Case sensitivity (e.g., User+Assistant@example.com)
  • Special characters in email
  • Null/undefined inputs
apps/web/utils/assistant/process-assistant-email.ts (1)

32-45: Consider adding retry logic for message retrieval.

The message retrieval could fail due to transient issues. Consider implementing retry logic with exponential backoff.

+import { retry } from "@/utils/retry";

-  const originalMessage = await getMessageByRfc822Id(originalMessageId, gmail);
+  const originalMessage = await retry(
+    () => getMessageByRfc822Id(originalMessageId, gmail),
+    { maxAttempts: 3, backoff: "exponential" }
+  );
apps/web/utils/gmail/message.ts (1)

27-50: LGTM! Well-implemented message retrieval with proper error handling.

The function correctly:

  • Cleans RFC822 Message-ID by removing angle brackets
  • Uses appropriate Gmail API parameters
  • Handles missing messages gracefully

Consider adding JSDoc documentation to clarify the function's purpose and parameters.

+/**
+ * Retrieves a Gmail message using its RFC822 Message-ID.
+ * @param rfc822MessageId - The RFC822 Message-ID to search for
+ * @param gmail - The Gmail API client
+ * @returns The message if found, null otherwise
+ */
 export async function getMessageByRfc822Id(
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a5455e7 and 406dec6.

📒 Files selected for processing (8)
  • apps/web/app/(app)/onboarding-old2/page.tsx (0 hunks)
  • apps/web/app/api/google/webhook/process-history.ts (10 hunks)
  • apps/web/utils/ai/assistant/process-user-request.ts (1 hunks)
  • apps/web/utils/assistant/get-original-message-id.ts (1 hunks)
  • apps/web/utils/assistant/is-assistant-email.test.ts (1 hunks)
  • apps/web/utils/assistant/is-assistant-email.ts (1 hunks)
  • apps/web/utils/assistant/process-assistant-email.ts (1 hunks)
  • apps/web/utils/gmail/message.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/app/(app)/onboarding-old2/page.tsx
🔇 Additional comments (7)
apps/web/utils/assistant/is-assistant-email.test.ts (2)

4-11: LGTM! Core test case validates assistant email format.

The test correctly verifies that an email in the format user+assistant@domain.com is recognized as an assistant email.


13-19: LGTM! Negative test case prevents false positives.

The test ensures that assistant emails from different users are not mistakenly identified.

apps/web/utils/assistant/process-assistant-email.ts (3)

10-10: Address the TODO comment for loading full email thread history.

The TODO indicates missing functionality for loading the complete email thread history, which could be important for context in processing assistant emails.

Would you like me to help implement the thread history loading functionality or create an issue to track this task?


21-28: LGTM! Robust email verification prevents unauthorized access.

The verification logic correctly checks sender authenticity using case-insensitive comparison.


47-49: Implement the processUserRequest functionality.

The TODO comment indicates missing implementation for processing user requests.

Would you like me to help implement the user request processing functionality or create an issue to track this task?

apps/web/app/api/google/webhook/process-history.ts (2)

357-369: LGTM! Well-integrated assistant email handling.

The integration correctly:

  • Checks for assistant emails
  • Logs the skip reason
  • Processes assistant emails appropriately

317-326: LGTM! Proper message processing lock prevents duplicate processing.

The implementation correctly uses a lock to prevent processing the same message multiple times.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/web/utils/assistant/is-assistant-email.test.ts (1)

4-44: Well-structured test suite with comprehensive coverage!

The test cases effectively cover various email formats and scenarios, including basic validation, negative cases, and complex email patterns.

Consider adding these test cases for enhanced coverage:

  1. Multiple recipients (To field with multiple addresses)
  2. CC/BCC scenarios
  3. Invalid email formats
  4. Case sensitivity checks
  5. Multiple + segments (e.g., user+foo+assistant@example.com)
// Example additional test cases:
it("should handle multiple recipients", () => {
  const result = isAssistantEmail({
    userEmail: "john@example.com",
    recipientEmail: "jane@example.com, john+assistant@example.com",
  });
  expect(result).toBe(true);
});

it("should be case insensitive", () => {
  const result = isAssistantEmail({
    userEmail: "John@Example.com",
    recipientEmail: "JOHN+ASSISTANT@EXAMPLE.COM",
  });
  expect(result).toBe(true);
});
apps/web/app/api/google/webhook/process-history.ts (1)

356-368: Well-placed assistant email check with early return.

The assistant email check is strategically placed before other processing steps, which is efficient. However, consider adding logging for cases where the assistant email processing fails.

-      return processAssistantEmail({ message, userEmail, gmail });
+      try {
+        return await processAssistantEmail({ message, userEmail, gmail });
+      } catch (error) {
+        logger.error("Failed to process assistant email", {
+          email: userEmail,
+          messageId,
+          threadId,
+          error,
+        });
+        throw error;
+      }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 406dec6 and 041aede.

📒 Files selected for processing (4)
  • apps/web/app/api/google/webhook/process-history.ts (11 hunks)
  • apps/web/utils/assistant/is-assistant-email.test.ts (1 hunks)
  • apps/web/utils/assistant/is-assistant-email.ts (1 hunks)
  • apps/web/utils/assistant/process-assistant-email.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/utils/assistant/is-assistant-email.ts
  • apps/web/utils/assistant/process-assistant-email.ts
🔇 Additional comments (3)
apps/web/app/api/google/webhook/process-history.ts (3)

265-265: Good addition of draft email filtering!

The explicit check for draft labels helps prevent processing incomplete emails.


300-300: Consistent variable naming improvement.

Good refactoring to use userEmail consistently throughout the file instead of mixing email and userEmail. This improves code clarity and maintainability.

Also applies to: 316-316, 320-320, 328-328, 347-347, 363-363, 379-379, 396-396, 431-431, 454-454, 471-471


316-324: Verify message processing lock mechanism.

The message processing lock is crucial for preventing duplicate processing. Let's verify its implementation:

✅ Verification successful

Lock mechanism implementation is robust and secure

The Redis-based lock implementation is well-designed with:

  • Atomic operations to prevent race conditions
  • 5-minute auto-expiry to handle failures
  • Proper isolation using user+message compound keys
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check the Redis lock implementation
rg -A 5 "markMessageAsProcessing" --type ts

Length of output: 1620


Script:

#!/bin/bash
# Get the complete implementation of message-processing.ts
cat apps/web/utils/redis/message-processing.ts

Length of output: 644

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/web/utils/email.ts (2)

17-23: Consider using a more restrictive email regex pattern.

While the current pattern covers common formats, it could be strengthened to prevent edge cases:

  • Local part could allow more special characters than necessary
  • Domain part could be more strictly validated

Consider using a more comprehensive pattern:

-const emailPattern = /[a-zA-Z0-9.+]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/i;
+const emailPattern = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/i;

25-33: LGTM! Robust two-step email extraction.

Good implementation that:

  1. Prioritizes bracketed content for formatted emails
  2. Falls back to raw email extraction
  3. Properly validates and trims the results

However, consider caching the compiled regex pattern for better performance if this function is called frequently.

+// Cache compiled regex for better performance
+const EMAIL_PATTERN = /[a-zA-Z0-9.+]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/i;

 export function extractEmailAddress(email: string): string {
-  const emailPattern = /[a-zA-Z0-9.+]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/i;
   // Try last bracketed content first
   const match = email.match(/<([^<>]+)>$/);
-  if (match && emailPattern.test(match[1].trim())) {
+  if (match && EMAIL_PATTERN.test(match[1].trim())) {
     return match[1].trim();
   }

   // Fall back to finding any email in the string
-  const rawMatch = email.match(emailPattern);
+  const rawMatch = email.match(EMAIL_PATTERN);
   return rawMatch ? rawMatch[0] : "";
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 041aede and 89f64b9.

📒 Files selected for processing (3)
  • apps/web/app/api/google/webhook/process-history.ts (11 hunks)
  • apps/web/utils/email.test.ts (1 hunks)
  • apps/web/utils/email.ts (1 hunks)
🔇 Additional comments (7)
apps/web/utils/email.test.ts (3)

47-51: LGTM! Good security consideration for nested angle brackets.

The test case ensures that only the last valid email is extracted, which helps prevent potential email spoofing attempts.


53-55: LGTM! Comprehensive validation of error cases.

Excellent coverage of malformed inputs, including:

  • Malformed angle brackets
  • Mixed valid/invalid emails
  • Empty brackets
  • Multiple @ symbols
  • Invalid email formats

These tests help ensure robust input validation and prevent potential security issues.

Also applies to: 57-61, 63-73


75-79: LGTM! Good fallback behavior test.

The test validates that the function can extract a valid email even when bracketed emails are invalid, providing a robust fallback mechanism.

apps/web/app/api/google/webhook/process-history.ts (4)

25-26: LGTM! Clean import additions.

The new assistant-related utility imports are well-organized and follow the project's module structure.


265-265: LGTM! Improved message filtering logic.

The separation of SENT message filtering from inbox filtering is a good improvement. It allows assistant emails to be processed even when they are in the SENT folder while maintaining the original filtering for other emails.

Also applies to: 370-371


319-321: LGTM! Consistent logging improvements.

The standardization of using userEmail parameter in logging statements improves code consistency and maintainability.

Also applies to: 327-329, 346-349, 362-366, 381-384, 398-401, 433-436, 456-459, 473-476


356-359: Verify assistant email pattern usage across the codebase.

Let's ensure consistent usage of the assistant email pattern across the codebase.

✅ Verification successful

Assistant email pattern implementation is consistent and well-structured

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistent usage of isAssistantEmail function
# and potential hardcoded assistant email patterns

# Check for isAssistantEmail function usage
echo "Checking isAssistantEmail function usage:"
rg "isAssistantEmail"

# Check for potential hardcoded assistant email patterns
echo "Checking for potential hardcoded assistant email patterns:"
rg -i "assistant.*@|@.*assistant"

# Check for any TODOs related to assistant emails
echo "Checking for assistant-related TODOs:"
rg -i "todo.*assistant|assistant.*todo"

Length of output: 2687

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (2)
apps/web/utils/ai/assistant/process-user-request.ts (1)

70-72: ⚠️ Potential issue

Risk of prompt injection via user-provided content.

The userEmailForLLM.content is directly interpolated into the prompt without sanitization.

Consider implementing input sanitization or validation before using user-provided content in the prompt.

apps/web/app/api/google/webhook/process-history.ts (1)

363-380: ⚠️ Potential issue

Add error handling for assistant email processing.

While the assistant email processing logic is well-structured, it lacks error handling.

Wrap the processAssistantEmail call in a try-catch block to handle potential failures gracefully.

🧹 Nitpick comments (2)
apps/web/utils/assistant/process-assistant-email.ts (1)

28-35: Consider enhancing error logging.

While the error handling is good, consider adding more context to the error message such as message ID and thread ID.

-    throw new Error("Unauthorized assistant access attempt");
+    throw new Error(`Unauthorized assistant access attempt for message ${message.id} in thread ${message.threadId}`);
apps/web/utils/ai/assistant/process-user-request.ts (1)

131-131: Consider making maxSteps configurable.

The maxSteps parameter is hardcoded to 1, which might be limiting for complex operations.

Consider making this configurable based on the operation complexity or user preferences.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 89f64b9 and b77bf18.

📒 Files selected for processing (9)
  • apps/web/__tests__/ai-rule-fix.test.ts (4 hunks)
  • apps/web/app/(app)/automation/ReportMistake.tsx (0 hunks)
  • apps/web/app/api/google/webhook/process-history.ts (12 hunks)
  • apps/web/utils/actions/ai-rule.ts (1 hunks)
  • apps/web/utils/actions/rule.ts (2 hunks)
  • apps/web/utils/ai/assistant/process-user-request.ts (1 hunks)
  • apps/web/utils/ai/rule/rule-fix.ts (2 hunks)
  • apps/web/utils/assistant/process-assistant-email.ts (1 hunks)
  • apps/web/utils/assistant/reply.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/app/(app)/automation/ReportMistake.tsx
👮 Files not reviewed due to content moderation or server errors (1)
  • apps/web/utils/actions/ai-rule.ts
🔇 Additional comments (5)
apps/web/utils/assistant/reply.ts (1)

2-2: Implement the TODO comment.

The TODO comment indicates incomplete implementation. What's the expected behavior for this function?

Let me check the codebase for any related implementations or tests:

Would you like me to help implement this function based on the findings?

apps/web/utils/assistant/process-assistant-email.ts (2)

15-16: TODO comment needs to be addressed.

The TODO comment indicates that full email thread history loading is not implemented yet.

Do you want me to help implement the thread history loading functionality or create an issue to track this task?


109-114: LGTM! Robust email verification.

The verifyUserSentEmail helper function correctly handles case-insensitive email comparison.

apps/web/utils/ai/assistant/process-user-request.ts (1)

136-139: LGTM! Robust retry mechanism.

The retry mechanism with exponential backoff is well implemented:

  • Retries only on InvalidToolArgumentsError
  • Limited to 3 retries
  • 1-second delay between retries
apps/web/app/api/google/webhook/process-history.ts (1)

382-383: LGTM! Clear skip condition for non-assistant sent emails.

The condition to skip SENT emails that are not assistant emails is clear and well-placed.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
apps/web/utils/ai/assistant/process-user-request.ts (1)

57-79: ⚠️ Potential issue

Risk of prompt injection via user-provided content

The userRequestEmailForLLM.content is directly interpolated into the prompt without sanitization, which could expose the system to prompt injection attacks.

Consider implementing one of these solutions:

  1. Sanitize user input by escaping special characters and XML-like tags
  2. Use a structured format (like JSON) instead of XML-like format
  3. Implement input validation to reject potentially malicious content

Example sanitization function:

function sanitizeForPrompt(content: string): string {
  return content
    .replace(/[<>]/g, '') // Remove XML-like tags
    .replace(/`/g, '\\`') // Escape backticks
    .trim();
}
🧹 Nitpick comments (2)
apps/web/utils/gmail/mail.ts (1)

99-114: Consider adding logging and rate limiting.

To improve operational visibility and API quota management:

  1. Add logging for debugging and monitoring email replies
  2. Consider implementing rate limiting to respect Gmail API quotas

Example implementation:

import { logger } from "@/utils/logger";
import { RateLimiter } from "@/utils/rate-limiter";

const emailRateLimiter = new RateLimiter({
  maxRequests: 100,  // adjust based on your Gmail API quota
  perSeconds: 60
});

export async function replyToEmail(
  gmail: gmail_v1.Gmail,
  message: ParsedMessage,
  reply: string,
) {
  await emailRateLimiter.acquire();
  
  try {
    logger.info("Replying to email", {
      threadId: message.threadId,
      subject: message.headers.subject
    });
    
    const result = await sendEmail(/*...*/);
    
    logger.info("Successfully sent reply", {
      threadId: message.threadId,
      messageId: result.data.id
    });
    
    return result;
  } catch (error) {
    logger.error("Failed to send reply", {
      threadId: message.threadId,
      error
    });
    throw error;
  }
}
apps/web/utils/ai/assistant/process-user-request.ts (1)

140-140: Consider increasing maxSteps limit

The current maxSteps: 2 might be too restrictive for complex scenarios where the assistant needs multiple interactions to complete the task.

Consider increasing it to 3-5 steps to allow for more complex interactions while still maintaining a reasonable limit.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b77bf18 and 4854df8.

📒 Files selected for processing (3)
  • apps/web/utils/ai/assistant/process-user-request.ts (1 hunks)
  • apps/web/utils/assistant/process-assistant-email.ts (1 hunks)
  • apps/web/utils/gmail/mail.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/utils/assistant/process-assistant-email.ts
🔇 Additional comments (6)
apps/web/utils/gmail/mail.ts (1)

14-14: LGTM!

The import of ParsedMessage type is appropriate for the new functionality.

apps/web/utils/ai/assistant/process-user-request.ts (5)

1-17: LGTM! Imports are well-organized and necessary.

All imports are being used and types are properly defined.


18-18: LGTM! Good use of scoped logging.

Using a scoped logger enhances traceability and debugging capabilities.


20-37: LGTM! Well-structured schema definitions with clear descriptions.

The schemas properly validate the tool parameters and include helpful descriptions for each field.


39-53: LGTM! Well-typed function signature with proper constraints.

The parameters are clearly defined with appropriate TypeScript types, making the function interface type-safe and self-documenting.


54-55: LGTM! Clean email content extraction.

Good use of utility function to extract email content for LLM processing.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (4)
apps/web/utils/ai/assistant/fix-rules.ts (1)

288-336: Ensure Proper Handling of Null or Undefined Properties in ruleToXML Function

In the ruleToXML function, ensure that all optional properties of rule, such as instructions, from, to, subject, body, group, groupItems, and categoryFilters, are appropriately checked for null or undefined before usage to prevent runtime errors.

apps/web/utils/ai/rule/create-prompt-from-rule.ts (1)

12-15: Incorporate groupItems into the Prompt Creation

The groupItems property has been added to the RuleWithRelations type but is not utilized within the createPromptFromRule function. Consider incorporating groupItems into the prompt generation to provide more context about the group's conditions, which can enhance the accuracy of rule processing.

apps/web/__tests__/ai-fix-rules.test.ts (2)

409-515: Extract Helper Functions for Reusability

The helper functions getRule, getParsedMessage, getUser, getGroup, getGroupItem, and getCategory are defined within this test file. Consider moving these utility functions to a separate module so they can be reused across multiple test files, promoting DRY (Don't Repeat Yourself) principles and improving maintainability.


19-20: Mock External Dependencies More Precisely

The mocks for server-only and @/utils/gmail/mail are currently stubs. Ensure that these mocks accurately represent the behavior of the actual modules, especially if the tests rely on specific interactions with these dependencies. This will improve the reliability and accuracy of the test outcomes.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4854df8 and 108c627.

📒 Files selected for processing (5)
  • apps/web/__tests__/ai-fix-rules.test.ts (1 hunks)
  • apps/web/utils/ai/assistant/fix-rules.ts (1 hunks)
  • apps/web/utils/ai/rule/create-prompt-from-rule.ts (1 hunks)
  • apps/web/utils/ai/rule/create-rule-schema.ts (1 hunks)
  • apps/web/utils/logger.ts (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/web/utils/ai/rule/create-rule-schema.ts
🔇 Additional comments (5)
apps/web/utils/logger.ts (2)

59-59: Maintain consistency with trace logging implementation.

The same condition change has been applied here, matching the behavior in createScopedLogger. This maintains consistency across both logging implementations.

The security considerations mentioned in the previous comment apply here as well.


43-43: Consider the security implications of enabling trace logging in all non-production environments.

The condition change from checking for "development" to checking for "not production" means trace logs will be enabled in any environment that isn't explicitly production (e.g., staging, testing). While this provides more debugging capabilities, it could potentially expose sensitive information in these environments.

Consider:

  1. Using an explicit environment variable to control trace logging
  2. Ensuring sensitive data is properly redacted in trace logs
  3. Adding rate limiting for trace logs to prevent excessive logging

Let's verify the impact of this change across the codebase:

✅ Verification successful

Trace logging usage appears safe for non-production environments

The codebase review shows that trace logs are primarily used for debugging AI operations, rule processing, and email categorization metadata. No sensitive data like passwords, tokens, or raw emails are being logged. The change to enable trace logging in non-production environments is acceptable.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for trace logging usage to assess potential sensitive data exposure
rg -A 3 "\.trace\(" 

Length of output: 10378

apps/web/utils/ai/assistant/fix-rules.ts (1)

258-268: Clarify the Absence of execute Function in the reply Tool

The reply tool lacks an execute function, with a comment indicating that invoking it will terminate the agent. Ensure that this behavior is intentional and clearly documented, as it might lead to confusion about the tool's functionality. If the tool is meant to send a reply, consider implementing the execute function accordingly.

apps/web/utils/ai/rule/create-prompt-from-rule.ts (1)

Line range hint 16-73: Update Type Definitions for Consistency

With the change to use Prisma.GroupGetPayload for the group property, ensure that all type references and usages of group are consistent throughout the codebase. Verify that the group property's fields are accessed correctly according to the new type definition to prevent potential type errors.

apps/web/__tests__/ai-fix-rules.test.ts (1)

16-26: Ensure Tests Are Executed Appropriately

The test suite is conditionally skipped based on the RUN_AI_TESTS environment variable. Verify that this variable is set correctly in the testing environments to ensure that the tests are executed when intended. This helps maintain the reliability of the test coverage over time.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/web/utils/actions/rule.ts (1)

246-251: Consider adding error handling

Currently, any error thrown by updateRuleInstructionsAndPromptFile is not caught here. Wrap the call in a try/catch block or handle the error gracefully to provide better user feedback and to ensure partial updates are handled appropriately.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 06e5826 and b4ee6d5.

📒 Files selected for processing (2)
  • apps/web/utils/actions/rule.ts (2 hunks)
  • apps/web/utils/rule/prompt-file.ts (1 hunks)
🔇 Additional comments (3)
apps/web/utils/rule/prompt-file.ts (2)

5-15: Validate input arguments

Please ensure to validate that parameters (userId, ruleId, instructions, etc.) meet expected conditions (e.g., non-empty strings) to avoid potential runtime issues if any of them is missing or malformed.


16-28: Wrap database operations in a transaction

This is a repeated suggestion from a previous review: all database calls in this function should be atomic. If the second operation fails, the first update should be rolled back to maintain data integrity.

 try {
   return await prisma.$transaction(async (tx) => {
     const updatedRule = await prisma.rule.update({
       where: { id: ruleId, userId },
       data: { instructions },
       include: { actions: true, categoryFilters: true, group: true },
     });

     if (currentRule) {
       await updateRulePromptOnRuleChange(userId, currentRule, updatedRule);
     } else {
       await appendRulePrompt(userId, instructions);
     }

     return updatedRule;
   });
 } catch (error) {
   console.error("Failed to update rule instructions:", error);
   throw new Error("Failed to update rule instructions");
 }
apps/web/utils/actions/rule.ts (1)

27-27: Import statement looks good

No issues found with importing updateRuleInstructionsAndPromptFile.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (2)
apps/web/utils/rule/prompt-file.ts (2)

Line range hint 16-45: Optimize database query and add error handling.

Several improvements can be made to this function:

  1. The database query fetches unnecessary fields (aiModel, aiProvider, aiApiKey).
  2. Missing error handling for database operations.
  3. No validation of the updated prompt before saving.

Consider these improvements:

 export async function updatePromptFileOnRuleUpdated(
   userId: string,
   currentRule: RuleWithRelations,
   updatedRule: RuleWithRelations,
 ) {
+  try {
     const user = await prisma.user.findUnique({
       where: { id: userId },
       select: {
-        email: true,
-        aiModel: true,
-        aiProvider: true,
-        aiApiKey: true,
         rulesPrompt: true,
       },
     });
     if (!user) return;

     const updatedPrompt = await generatePromptOnUpdateRule({
       user,
       existingPrompt: user.rulesPrompt || "",
       currentRule,
       updatedRule,
     });

+    if (!updatedPrompt?.trim()) {
+      throw new Error('Generated prompt is empty or invalid');
+    }

     await prisma.user.update({
       where: { id: userId },
       data: { rulesPrompt: updatedPrompt },
     });
+  } catch (error) {
+    console.error('Failed to update prompt file:', error);
+    throw new Error('Failed to update prompt file');
+  }
 }

Line range hint 71-85: Improve error handling and prompt formatting.

The function has several areas for improvement:

  1. Silent return when user/rulesPrompt doesn't exist could hide issues.
  2. No validation of rulePrompt input.
  3. String concatenation could lead to formatting issues.

Consider these improvements:

 async function appendRulePrompt(userId: string, rulePrompt: string) {
+  if (!rulePrompt?.trim()) {
+    throw new Error('Rule prompt cannot be empty');
+  }
+
   const user = await prisma.user.findUnique({
     where: { id: userId },
     select: { rulesPrompt: true },
   });

-  if (!user?.rulesPrompt) return;
+  if (!user) {
+    throw new Error('User not found');
+  }
+
+  if (!user.rulesPrompt) {
+    throw new Error('User rules prompt not initialized');
+  }

-  const updatedPrompt = `${user.rulesPrompt || ""}\n\n* ${rulePrompt}.`.trim();
+  // Ensure consistent formatting with double newlines between rules
+  const updatedPrompt = `${user.rulesPrompt.trim()}\n\n* ${rulePrompt.trim()}.`;

   await prisma.user.update({
     where: { id: userId },
     data: { rulesPrompt: updatedPrompt },
   });
 }
♻️ Duplicate comments (6)
apps/web/utils/rule/rule.ts (3)

34-44: ⚠️ Potential issue

Fix parameter mismatch in retry attempt.

The retry attempt in safeCreateRule uses categoryIds instead of categoryNames, which could lead to incorrect category associations.

-        categoryIds,
+        categoryNames,

144-147: 🛠️ Refactor suggestion

Consider safer action updates to prevent potential data loss.

The current implementation deletes and recreates all actions. While safe now, this approach could lead to data loss if Action gains relations in the future.

Consider implementing an upsert pattern that:

  1. Compares existing vs new actions
  2. Updates matching actions
  3. Creates new actions
  4. Deletes only removed actions

71-80: 🛠️ Refactor suggestion

Reconsider creating new rules during update.

Creating a new rule on name conflict during update could lead to rule proliferation and user confusion.

Consider alternatives:

  1. Append a meaningful suffix (e.g., "-copy" instead of timestamp)
  2. Update the existing rule
  3. Return an error asking the user to choose a different name
apps/web/utils/ai/assistant/process-user-request.ts (3)

91-123: ⚠️ Potential issue

Mitigate prompt injection risk.

The user input is directly interpolated into the prompt without sanitization, which could expose the system to prompt injection attacks.

Consider implementing input sanitization:

-  content: prompt,
+  content: sanitizeUserInput(prompt), // Add this function

Add a utility function to sanitize the input:

function sanitizeUserInput(input: string): string {
  // Remove potential prompt injection patterns
  return input.replace(/^system:|^assistant:|^user:/gmi, '')
             .replace(/[<>]/g, ''); // Sanitize XML-like tags
}

137-137: ⚠️ Potential issue

Avoid logging sensitive user data.

Logging entire conversation transcripts may expose sensitive user information (PII).

Consider redacting sensitive information:

-  logger.trace("Input", { allMessages });
+  logger.trace("Input", {
+    messageCount: allMessages.length,
+    roles: allMessages.map(m => m.role)
+  });

38-459: 🛠️ Refactor suggestion

Consider decomposing the processUserRequest function.

The function is handling multiple responsibilities including prompt construction, rule logic, and tool definitions. This makes it harder to maintain and test.

Consider breaking it down into smaller, focused functions:

  1. Prompt construction
  2. Tool definitions
  3. Rule processing logic

Example refactor:

async function processUserRequest(params: ProcessUserRequestParams) {
  const prompt = constructPrompt(params);
  const tools = defineTools(params);
  const result = await processWithTools(prompt, tools);
  await handleRuleUpdates(result);
  return result;
}
🧹 Nitpick comments (6)
apps/web/utils/rule/rule.ts (3)

168-181: Improve maintainability of automation rules.

The shouldAutomate function uses a hardcoded list of action types that prevent automation. This could become difficult to maintain as new action types are added.

Consider using a configuration object or enum to define non-automatable actions:

const NON_AUTOMATABLE_ACTIONS = new Set([
  ActionType.REPLY,
  ActionType.FORWARD,
  ActionType.SEND_EMAIL,
]);

function shouldAutomate(actions: Pick<Action, "type">[]) {
  return !actions.some(action => NON_AUTOMATABLE_ACTIONS.has(action.type));
}

189-226: Refactor duplicate category management logic.

The addRuleCategories and removeRuleCategories functions share similar structure and error handling.

Consider extracting common logic into a helper function:

async function updateRuleCategories(
  ruleId: string,
  categoryIds: string[],
  operation: 'add' | 'remove'
) {
  const rule = await prisma.rule.findUnique({
    where: { id: ruleId },
    include: { categoryFilters: true },
  });

  if (!rule) throw new Error("Rule not found");

  const existingIds = rule.categoryFilters.map((c) => c.id) || [];
  const newIds = operation === 'add'
    ? [...new Set([...existingIds, ...categoryIds])]
    : existingIds.filter((id) => !categoryIds.includes(id));

  return prisma.rule.update({
    where: { id: ruleId },
    data: { categoryFilters: { set: newIds.map((id) => ({ id })) } },
    include: { actions: true, categoryFilters: true, group: true },
  });
}

195-195: Enhance error handling for rule not found scenarios.

The error messages could be more informative by including the rule ID.

-  if (!rule) throw new Error("Rule not found");
+  if (!rule) throw new Error(`Rule not found: ${ruleId}`);

Also applies to: 216-216

apps/web/utils/ai/assistant/process-user-request.ts (2)

461-498: Enhance error handling in getUpdateCategoryTool.

The function could benefit from more robust error handling, especially around the sender existence check.

Consider this enhancement:

 execute: async ({ sender, category }) => {
   logger.info("Update Category", { sender, category });

   const existingSender = await findSenderByEmail({
     userId,
     email: sender,
   });

+  if (!sender.includes('@')) {
+    return { error: "Invalid email format" };
+  }
+
   const cat = categories.find((c) => c.name === category);

   if (!cat) {
     logger.error("Category not found", { category });
     return { error: "Category not found" };
   }

+  try {
     await updateCategoryForSender({
       userId,
       sender: existingSender?.email || sender,
       categoryId: cat.id,
     });
     return { success: true };
+  } catch (error) {
+    logger.error("Failed to update sender category", { error });
+    return { 
+      error: "Failed to update sender category",
+      message: error instanceof Error ? error.message : String(error)
+    };
+  }
 }

500-554: Add input validation for XML conversion functions.

The XML conversion functions don't validate input, which could lead to malformed XML if the input contains special characters.

Consider adding XML escaping:

function escapeXml(unsafe: string): string {
  return unsafe.replace(/[<>&'"]/g, (c) => {
    switch (c) {
      case '<': return '&lt;';
      case '>': return '&gt;';
      case '&': return '&amp;';
      case '\'': return '&apos;';
      case '"': return '&quot;';
      default: return c;
    }
  });
}

Then use it in the XML generation:

 function ruleToXML(rule: RuleWithRelations) {
   return `<rule>
-  <rule_name>${rule.name}</rule_name>
+  <rule_name>${escapeXml(rule.name)}</rule_name>
   <conditions>
apps/web/utils/rule/prompt-file.ts (1)

8-14: Add error handling for database operations.

The function should handle potential failures in the database operations to ensure proper error propagation and logging.

Consider wrapping the operations in a try-catch block:

 export async function updatePromptFileOnRuleCreated(
   userId: string,
   rule: RuleWithRelations,
 ) {
+  try {
     const prompt = createPromptFromRule(rule);
     await appendRulePrompt(userId, prompt);
+  } catch (error) {
+    console.error('Failed to update prompt file:', error);
+    throw new Error('Failed to update prompt file');
+  }
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69c4e16 and cb7f128.

📒 Files selected for processing (4)
  • apps/web/utils/actions/rule.ts (4 hunks)
  • apps/web/utils/ai/assistant/process-user-request.ts (1 hunks)
  • apps/web/utils/rule/prompt-file.ts (2 hunks)
  • apps/web/utils/rule/rule.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/utils/actions/rule.ts
🔇 Additional comments (2)
apps/web/utils/rule/rule.ts (1)

1-13: LGTM! Well-structured imports and logger setup.

Clean organization of imports with proper type handling and scoped logging setup.

apps/web/utils/ai/assistant/process-user-request.ts (1)

1-36: LGTM! Well-organized imports and type definitions.

The imports are properly structured and all seem necessary for the functionality.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (7)
apps/web/utils/assistant/process-assistant-email.ts (4)

27-34: ⚠️ Potential issue

Strengthen email verification.

The current email verification is case-insensitive but doesn't handle potential email spoofing or header manipulation.

Apply this diff to improve email verification:

 function verifyUserSentEmail(message: ParsedMessage, userEmail: string) {
+  const from = message.headers.from;
+  if (!from) return false;
+
+  // Verify both email and optional display name
+  const fromEmail = extractEmailAddress(from).toLowerCase();
+  const expectedEmail = userEmail.toLowerCase();
+
+  // Additional checks for email authenticity
+  const spf = message.headers['received-spf'];
+  const dkim = message.headers['dkim-signature'];
+
   return (
-    extractEmailAddress(message.headers.from).toLowerCase() ===
-    userEmail.toLowerCase()
+    fromEmail === expectedEmail &&
+    (spf?.includes('pass') || dkim)
   );
 }

79-144: ⚠️ Potential issue

Add type definitions and error handling for database operations.

The Promise.all operation could fail if any of the database queries throw an error.

Apply this diff to add type definitions and error handling:

+type UserSelect = NonNullable<Awaited<ReturnType<typeof prisma.user.findUnique>>>
+type ExecutedRuleSelect = NonNullable<Awaited<ReturnType<typeof prisma.executedRule.findUnique>>>
+type NewsletterSelect = NonNullable<Awaited<ReturnType<typeof prisma.newsletter.findUnique>>>

-  const [user, executedRule, senderCategory] = await Promise.all([
+  let user: UserSelect | null = null;
+  let executedRule: ExecutedRuleSelect | null = null;
+  let senderCategory: NewsletterSelect | null = null;
+
+  try {
+    [user, executedRule, senderCategory] = await Promise.all([
       prisma.user.findUnique({
         // ... existing query
       }),
       prisma.executedRule.findUnique({
         // ... existing query
       }),
       prisma.newsletter.findUnique({
         // ... existing query
       }),
     ]);
+  } catch (error) {
+    logger.error("Database query failed", { error, messageId: message.id });
+    await replyToEmail(
+      gmail,
+      message,
+      "I encountered an error while processing your request. Please try again later."
+    );
+    return;
+  }

182-202: ⚠️ Potential issue

Add error handling for processUserRequest.

The function should handle potential errors from processUserRequest to ensure graceful failure.

Apply this diff to add error handling:

-  const result = await processUserRequest({
+  let result;
+  try {
+    result = await processUserRequest({
       user,
       rules: user.rules,
       userRequestEmail: message,
       originalEmail: parsedOriginalMessage,
       matchedRule: executedRule?.rule || null,
       categories: user.categories.length
         ? (user.categories.map((c) => c.name) as [string, ...string[]])
         : null,
       senderCategory: senderCategory?.category?.name ?? null,
       gmail,
     });
+  } catch (error) {
+    logger.error("Failed to process user request", { error, messageId: message.id });
+    await replyToEmail(
+      gmail,
+      message,
+      "I encountered an error while processing your request. Please try again later.",
+    );
+    return;
+  }

217-225: ⚠️ Potential issue

Add error handling for message retrieval and parsing.

The function should handle potential errors from getMessageByRfc822Id and parseMessage.

Apply this diff to add error handling:

 async function getOriginalMessage(
   originalMessageId: string | undefined,
   gmail: gmail_v1.Gmail,
 ) {
   if (!originalMessageId) return null;
-  const originalMessage = await getMessageByRfc822Id(originalMessageId, gmail);
-  if (!originalMessage) return null;
-  return parseMessage(originalMessage);
+  try {
+    const originalMessage = await getMessageByRfc822Id(originalMessageId, gmail);
+    if (!originalMessage) return null;
+    return parseMessage(originalMessage);
+  } catch (error) {
+    logger.error("Failed to retrieve or parse original message", {
+      error,
+      originalMessageId,
+    });
+    return null;
+  }
 }
apps/web/utils/ai/assistant/process-user-request.ts (3)

92-124: ⚠️ Potential issue

Risk of prompt injection via user-provided content.

The prompt construction directly interpolates user-provided content without sanitization, which could expose the system to prompt injection attacks.

Consider implementing a sanitization function:

function sanitizePromptContent(content: string): string {
  // Remove potential XML/prompt injection patterns
  return content
    .replace(/<\/?[^>]+(>|$)/g, "") // Remove XML tags
    .replace(/^system:/i, "") // Remove system: prefix
    .replace(/^assistant:/i, "") // Remove assistant: prefix
    .replace(/^user:/i, ""); // Remove user: prefix
}

Then apply this diff to use the sanitization:

-  ${user.about ? `<user_about>${user.about}</user_about>` : ""}
+  ${user.about ? `<user_about>${sanitizePromptContent(user.about)}</user_about>` : ""}

-  ${originalEmail ? stringifyEmailSimple(getEmailForLLM(originalEmail)) : ""}
+  ${originalEmail ? sanitizePromptContent(stringifyEmailSimple(getEmailForLLM(originalEmail))) : ""}

430-437: ⚠️ Potential issue

Add error handling for replyToEmail.

The reply tool lacks error handling.

Apply this diff to add error handling:

 reply: tool({
   description: "Send an email reply to the user",
   parameters: z.object({
     content: z.string().describe("The content of the reply"),
   }),
-  // no execute function - invoking it will terminate the agent
+  execute: async ({ content }) => {
+    try {
+      return await replyToEmail(gmail, message, content);
+    } catch (error) {
+      logger.error("Failed to send reply email", { error });
+      throw new Error("Failed to send reply email");
+    }
+  }
 }),

138-138: ⚠️ Potential issue

Avoid logging sensitive information.

Logging entire conversation transcripts and tool calls may expose sensitive user information (PII).

Consider redacting or selectively logging only the necessary details:

-  logger.trace("Input", { allMessages });
+  logger.trace("Input", {
+    messageCount: allMessages.length,
+    hasSystemPrompt: allMessages[0]?.role === "system",
+    hasUserPrompt: allMessages[1]?.role === "user",
+  });

-  logger.trace("Tool Calls", { toolCalls });
+  logger.trace("Tool Calls", {
+    count: toolCalls.length,
+    tools: toolCalls.map(call => call.toolName),
+  });

Also applies to: 445-445

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb7f128 and 8f0af8a.

📒 Files selected for processing (2)
  • apps/web/utils/ai/assistant/process-user-request.ts (1 hunks)
  • apps/web/utils/assistant/process-assistant-email.ts (1 hunks)
🔇 Additional comments (2)
apps/web/utils/assistant/process-assistant-email.ts (1)

212-215: LGTM!

The function correctly handles email address formatting.

apps/web/utils/ai/assistant/process-user-request.ts (1)

1-568: Consider decomposing the file into smaller modules.

The file handles multiple concerns and could benefit from being split into focused modules:

  • Prompt construction
  • Tool definitions
  • Rule processing
  • XML conversion

Consider creating separate modules:

  • prompt.ts for prompt construction
  • tools/ directory for individual tools
  • rule-processor.ts for rule processing logic
  • xml-converter.ts for XML conversion

This would improve maintainability, readability, and testability.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/web/utils/actions/group.ts (1)

353-366: Consider using batch upsert for better efficiency.

While the current implementation with deduplication and graceful fallback is good, consider using prisma.groupItem.upsert in a transaction for better efficiency. This would handle duplicates in a single database operation.

 const uniqueItems = uniqBy(data, (item) => `${item.value}-${item.type}`);
 try {
-    return await prisma.groupItem.createMany({ data: uniqueItems });
+    return await prisma.$transaction(
+      uniqueItems.map((item) =>
+        prisma.groupItem.upsert({
+          where: {
+            groupId_type_value: {
+              groupId: item.groupId,
+              type: item.type,
+              value: item.value,
+            },
+          },
+          create: item,
+          update: {}, // No update needed if exists
+        })
+      )
+    );
 } catch (error) {
-    if (isDuplicateError(error)) {
-      // Create items one by one, skipping duplicates
-      for (const item of uniqueItems) {
-        try {
-          await prisma.groupItem.create({ data: item });
-        } catch (error) {
-          if (!isDuplicateError(error)) throw error;
-        }
-      }
-    }
-
-    throw error;
+    throw new Error(`Failed to create group items: ${error.message}`);
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f0af8a and ea0ce31.

📒 Files selected for processing (2)
  • apps/web/utils/actions/group.ts (4 hunks)
  • apps/web/utils/group/group-item.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/utils/group/group-item.ts
🔇 Additional comments (3)
apps/web/utils/actions/group.ts (3)

30-30: LGTM! Good separation of concerns.

Moving group item operations to a dedicated module improves code organization and maintainability.


414-414: LGTM! Good use of the utility function.

The change maintains proper permission checks while improving code organization.


426-426: LGTM! Good use of the utility function.

The change maintains proper authentication checks while improving code organization.

@elie222 elie222 merged commit c35ac8f into main Jan 26, 2025
4 checks passed
@elie222 elie222 changed the title WIP: email assistant email Email assistant Jan 26, 2025
@coderabbitai coderabbitai bot mentioned this pull request Feb 6, 2025
@coderabbitai coderabbitai bot mentioned this pull request Feb 22, 2025
@coderabbitai coderabbitai bot mentioned this pull request Apr 7, 2025
@coderabbitai coderabbitai bot mentioned this pull request Aug 17, 2025
@coderabbitai coderabbitai bot mentioned this pull request Aug 25, 2025
@elie222 elie222 deleted the email-assistant branch December 18, 2025 23:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments