Skip to content

Fixes for AI generated responses#258

Merged
elie222 merged 8 commits intomainfrom
ai-args
Nov 22, 2024
Merged

Fixes for AI generated responses#258
elie222 merged 8 commits intomainfrom
ai-args

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Nov 22, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Updated button label in the Rules component for clarity.
    • Introduced a new logging utility for improved logging practices across various components.
  • Improvements

    • Streamlined AI argument handling by consolidating multiple function calls into single calls.
    • Enhanced data structure for action items in the execution process, providing more detailed information.
  • Bug Fixes

    • Improved logging mechanisms to replace console logs with a scoped logger for better maintainability and debugging.

@vercel
Copy link

vercel bot commented Nov 22, 2024

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

Name Status Preview Updated (UTC)
inbox-zero 🔄 Building (Inspect) Visit Preview Nov 22, 2024 10:45pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 22, 2024

Walkthrough

The pull request introduces several modifications across multiple files, primarily focusing on simplifying and enhancing the handling of AI-generated arguments and logging mechanisms. Key changes include updating button labels in the UI, consolidating function calls for action item generation, and implementing a scoped logging utility to replace console logging. The overall structure and functionality of existing components remain intact, but improvements have been made to streamline code and enhance maintainability.

Changes

File Path Change Summary
apps/web/app/(app)/automation/Rules.tsx Button label changed from "Add Rule via Prompt File" to "Add Rule via Prompt Tab".
apps/web/app/api/google/webhook/group-rule.ts Consolidated AI argument handling by replacing multiple imports with a single import getActionItemsWithAiArgs. Removed redundant logic for generating AI arguments.
apps/web/app/api/google/webhook/process-history.ts Replaced console logging with a scoped logger. Updated log messages for clarity and streamlined logging practices.
apps/web/app/api/google/webhook/static-rule.ts Simplified action item generation in handleStaticRule by replacing multiple function calls with a single call to getActionItemsWithAiArgs.
apps/web/utils/ai/actions.ts Introduced scoped logging for action functions, replacing console logs with logger methods and adding detailed logging for action objects.
apps/web/utils/ai/choose-rule/ai-choose-args.ts Removed AIGeneratedArgs type, added ActionRequiringAi and ActionWithAiArgs types, and introduced getActionItemsWithAiArgs for streamlined action item retrieval.
apps/web/utils/ai/choose-rule/choose-and-execute.ts Updated saveExecutedRule to enhance the structure of actionItems in the data object, improving granularity without changing core functionality.
apps/web/utils/ai/choose-rule/choose.ts Streamlined chooseRule function by directly calling getActionItemsWithAiArgs, removing intermediate checks and calls.
apps/web/utils/logger.ts Introduced a new logging utility with scoped logging capabilities, including methods for different log levels and environment-aware formatting.

Possibly related PRs

🐇 In the code where bunnies hop,
A button's name took a little swap.
With logs now neat, and actions clear,
AI's magic brings us cheer!
So let us code, and let us play,
With every change, we hop away! 🐰✨


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 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.

@elie222 elie222 merged commit 9e66954 into main Nov 22, 2024
@elie222 elie222 deleted the ai-args branch November 22, 2024 22:47
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: 7

🧹 Outside diff range and nitpick comments (15)
apps/web/utils/logger.ts (3)

1-2: Consider enhancing type definitions with JSDoc and additional log levels.

The types are well-structured, but could benefit from documentation and additional common log levels.

+/** Supported log levels for the scoped logger */
-type LogLevel = "log" | "error" | "warn" | "trace";
+type LogLevel = "log" | "error" | "warn" | "trace" | "info" | "debug";

+/** Supported message types for logging */
 type LogMessage = string | Record<string, unknown>;

4-10: Enhance color constants maintainability and type safety.

The color implementation could be improved for better maintainability and type safety.

+/** ANSI color codes for different log levels */
+const ANSI_COLORS = {
+  WHITE: "\x1b[0m",
+  RED: "\x1b[31m",
+  YELLOW: "\x1b[33m",
+  CYAN: "\x1b[36m",
+  BLUE: "\x1b[34m",
+  GREEN: "\x1b[32m",
+  RESET: "\x1b[0m",
+} as const;

-const colors = {
-  log: "\x1b[0m", // white
-  error: "\x1b[31m", // red
-  warn: "\x1b[33m", // yellow
-  trace: "\x1b[36m", // cyan
-  reset: "\x1b[0m",
-} as const;
+const colors: Record<LogLevel | 'reset', string> = {
+  log: ANSI_COLORS.WHITE,
+  error: ANSI_COLORS.RED,
+  warn: ANSI_COLORS.YELLOW,
+  trace: ANSI_COLORS.CYAN,
+  info: ANSI_COLORS.BLUE,
+  debug: ANSI_COLORS.GREEN,
+  reset: ANSI_COLORS.RESET,
} as const;

27-43: Consider enhancing logger architecture for better flexibility and debugging.

The current implementation could benefit from additional features for better debugging and customization.

Consider implementing:

  1. Configurable output destination (console, file, remote service)
  2. Minimum log level setting
  3. Stack traces for errors
  4. Timestamps in logs
  5. Log batching for performance

Example enhancement:

type LoggerConfig = {
  minLevel?: LogLevel;
  destination?: 'console' | 'file' | 'remote';
  includeTimestamp?: boolean;
  batchSize?: number;
};

export function createScopedLogger(scope: string, config?: LoggerConfig) {
  const defaultConfig: LoggerConfig = {
    minLevel: 'log',
    destination: 'console',
    includeTimestamp: true,
    batchSize: 1,
    ...config
  };

  // Implementation details...
}
apps/web/app/api/google/webhook/static-rule.ts (1)

Line range hint 60-60: Address or track the TODO comment

There's a TODO comment about implementing thread checking to skip processing. This should be addressed to prevent potential duplicate processing of emails in the same thread.

Would you like me to help create a GitHub issue to track this TODO item?

apps/web/utils/ai/choose-rule/choose-and-execute.ts (2)

90-103: Consider batch size limits for createMany operation.

The createMany operation could potentially handle a large number of action items. Consider adding a batch size limit to prevent performance issues or database constraints.

Consider implementing batching:

 actionItems: {
   createMany: {
     data:
       plannedAct.actionItems?.map((a) => ({
         type: a.type,
         label: a.label,
         subject: a.subject,
         content: a.content,
         to: a.to,
         cc: a.cc,
         bcc: a.bcc,
-      })) || [],
+      })).slice(0, MAX_BATCH_SIZE) || [],
+      skipDuplicates: true, // Optional: Add if duplicate actions should be skipped
   },
 },

90-103: Add type safety for action item fields.

The current implementation assumes all fields exist on the action item object. Consider adding type guards or default values to handle potential undefined fields.

Consider adding type safety:

 actionItems: {
   createMany: {
     data:
       plannedAct.actionItems?.map((a) => ({
-        type: a.type,
-        label: a.label,
-        subject: a.subject,
-        content: a.content,
-        to: a.to,
-        cc: a.cc,
-        bcc: a.bcc,
+        type: a.type ?? 'unknown',
+        label: a.label ?? '',
+        subject: a.subject ?? '',
+        content: a.content ?? '',
+        to: a.to ?? null,
+        cc: a.cc ?? null,
+        bcc: a.bcc ?? null,
       })) || [],
   },
 },
apps/web/utils/ai/actions.ts (1)

CC field modification requires security controls

Based on the code analysis:

  1. The reply function in actions.ts directly passes the CC field from AI args to the email sending function without any validation
  2. The email schema shows CC is optional but lacks any security restrictions
  3. No permission checks or validations are present for CC field modifications

This could lead to potential security issues where the AI could add unauthorized recipients to email threads. Recommend implementing:

  • Validation to ensure CC recipients are within allowed domains
  • Permission checks for CC modifications
  • Consider restricting AI's ability to modify CC fields entirely
🔗 Analysis chain

Line range hint 284-290: Address TODO comment regarding CC field permissions.

The TODO comment raises an important security consideration about whether the AI should be allowed to modify CC recipients. This could lead to unintended information disclosure if not properly controlled.

Let's check if there are any existing restrictions or validations for CC modifications:

Would you like help implementing proper validation and restrictions for CC field modifications?

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for CC-related validations or restrictions
rg -i "cc.*validation|validate.*cc|restrict.*cc" --type typescript

Length of output: 103


Script:

#!/bin/bash
# Search for CC-related code and validation patterns with ripgrep
rg -l "cc" --type ts

# Get the content of the file under review to see the TODO comment
cat "apps/web/utils/ai/actions.ts"

# Search for any email validation or permission checks
rg -i "email.*validation|validate.*email|permission.*email" --type ts

Length of output: 17687


Script:

#!/bin/bash
# Search for email permission checks in the codebase
rg -A 5 "permission.*email|email.*permission" apps/web/utils/gmail/permissions.ts apps/web/utils/actions/permissions.ts

# Look for any CC-related code in the email sending functions
rg -A 5 "cc:" apps/web/utils/gmail/mail.ts

# Check for any security-related validation in the actions
rg -A 5 "validate|check|restrict" apps/web/utils/ai/actions.ts apps/web/utils/actions/validation.ts

Length of output: 1000

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

264-264: Consider using structured logging for errors

While the error logging is functional, consider using structured logging to make it easier to parse and analyze errors in production.

-        logger.error(`Error processing history item. email: ${email}`, error);
+        logger.error('Error processing history item', { email, error });

296-298: Consider structured logging for better observability

The logging additions are good, but could be improved by using structured logging consistently across all log statements. This would make it easier to query and analyze logs in production.

-  logger.log(
-    `Getting message... email: ${user.email} messageId: ${messageId} threadId: ${threadId}`,
-  );
+  logger.log('Getting message', { email: user.email, messageId, threadId });

-  logger.log("Running cold email blocker...");
+  logger.log('Running cold email blocker', { email: user.email, messageId });

-  logger.log("Running rules...");
+  logger.log('Running rules', { email: user.email, messageId });

Also applies to: 345-346, 390-391


Line range hint 27-405: Consider implementing a logging schema

While the migration to a scoped logger is a good improvement, consider defining a standard logging schema across the application. This would ensure consistency in log structure and make it easier to implement log aggregation and analysis.

Key points to consider:

  • Define standard fields (e.g., userId, messageId, operation)
  • Establish log levels usage guidelines
  • Document structured logging patterns
apps/web/utils/ai/choose-rule/ai-choose-args.ts (5)

Line range hint 77-163: Ensure consistent return types by returning an empty array instead of undefined

The function getArgsAiResponse currently returns undefined when there are no tool calls or when toolCall?.toolName is undefined. Returning an empty array instead of undefined can simplify the calling code and reduce the need for additional null checks.

Apply this diff to modify the function:

 async function getArgsAiResponse({
   email,
   user,
   selectedRule,
   actionsRequiringAi,
 }: {
   email: EmailForLLM;
   user: Pick<User, "email" | "about"> & UserAIFields;
   selectedRule: RuleWithActions;
   actionsRequiringAi: ActionRequiringAi[];
- }): Promise<ActionWithAiArgs[] | undefined> {
+ }): Promise<ActionWithAiArgs[]> {
   logger.log(
     `Generating args for rule ${selectedRule.name} (${selectedRule.id})`,
   );

   if (!actionsRequiringAi.length) {
     logger.log(
       `Skipping. No parameters for rule ${selectedRule.name} (${selectedRule.id})`,
     );
-    return;
+    return [];
   }

   // ... rest of the code ...

   if (!toolCall?.toolName) {
     logger.error("No tool call received from AI response.");
-    return;
+    return [];
   }

   // ... rest of the code ...
 }

39-46: Initialize aiGeneratedActionItems as an empty array

Currently, aiGeneratedActionItems is initialized as undefined and assigned a value only if actionsRequiringAi.length is truthy. Initializing it as an empty array simplifies the code and eliminates the need for optional chaining later.

Apply this diff:

-let aiGeneratedActionItems: ActionWithAiArgs[] | undefined;
+let aiGeneratedActionItems: ActionWithAiArgs[] = [];

if (actionsRequiringAi.length) {
  aiGeneratedActionItems = await getArgsAiResponse({
    email,
    user,
    selectedRule,
    actionsRequiringAi,
  });
}

51-53: Remove unnecessary optional chaining for aiGeneratedActionItems

After initializing aiGeneratedActionItems as an empty array, you can remove the optional chaining when accessing it, as it will always be defined.

Apply this diff:

-const aiGeneratedActionItem = aiGeneratedActionItems?.find(
+const aiGeneratedActionItem = aiGeneratedActionItems.find(
  (item) => item.actionId === action.id,
);

Line range hint 124-138: Add error handling for the external API call to chatCompletionTools

The call to chatCompletionTools could fail or throw an exception. Wrapping this call in a try-catch block ensures that errors are handled gracefully and prevents unhandled promise rejections.

Apply this diff:

 logger.trace(`Prompt: ${prompt}`);
// logger.trace("Zod parameters:", zodToJsonSchema(zodParameters));

+try {
  const aiResponse = await chatCompletionTools({
    userAi: user,
    prompt,
    system,
    tools: {
      apply_rule: {
        description: "Apply the rule with the given arguments",
        parameters: zodParameters,
      },
    },
    label: "Args for rule",
    userEmail: user.email || "",
  });
+} catch (error) {
+  logger.error(`Failed to get AI response: ${error.message}`);
+  return [];
+}

 const toolCall = aiResponse.toolCalls[0];

Line range hint 85-96: Sanitize user-provided content to prevent prompt injection attacks

Including user.about directly in the system prompt may expose the AI to prompt injection attacks if the user content is maliciously crafted. To mitigate this risk, sanitize user.about before including it in the prompt.

Consider applying sanitization:

 const system = `You are an AI assistant that helps people manage their emails.
 Never put placeholders in your email responses.
 Do not mention you are an AI assistant when responding to people.
 ${
-  user.about
+  sanitize(user.about)
     ? `\nSome additional information the user has provided about themselves:\n\n${user.about}`
     : ""
 }`;

+function sanitize(input: string): string {
+  // Implement sanitization logic here (e.g., remove special characters, limit length)
+  return input.replace(/[^\w\s.,'-]/g, '').slice(0, 500);
+}

Ensure that the sanitize function properly escapes or removes any potentially harmful content from user.about.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6f6c2ec and a889a7d.

📒 Files selected for processing (9)
  • apps/web/app/(app)/automation/Rules.tsx (1 hunks)
  • apps/web/app/api/google/webhook/group-rule.ts (2 hunks)
  • apps/web/app/api/google/webhook/process-history.ts (16 hunks)
  • apps/web/app/api/google/webhook/static-rule.ts (2 hunks)
  • apps/web/utils/ai/actions.ts (2 hunks)
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts (4 hunks)
  • apps/web/utils/ai/choose-rule/choose-and-execute.ts (1 hunks)
  • apps/web/utils/ai/choose-rule/choose.ts (2 hunks)
  • apps/web/utils/logger.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/web/app/(app)/automation/Rules.tsx
🔇 Additional comments (8)
apps/web/utils/ai/choose-rule/choose.ts (2)

2-2: LGTM! Import consolidation improves code organization.

The consolidation of AI argument handling into a single import simplifies the code and makes it easier to maintain.


42-46: Implementation looks good, but let's verify the consolidated function.

The refactoring simplifies the code while maintaining proper error handling. However, we should verify the behavior of getActionItemsWithAiArgs across the codebase.

Let's check the implementation and usage of the new consolidated function:

✅ Verification successful

Let me gather more information about the implementation of getActionItemsWithAiArgs to verify its behavior and error handling.


Implementation is well-structured with proper error handling and type safety

The implementation of getActionItemsWithAiArgs is robust and includes:

  • Strong type safety with Zod schema validation
  • Proper error handling and logging
  • Consistent handling of AI-generated arguments
  • Clear separation of concerns between static and AI-generated parameters
  • Proper null checks and edge case handling (e.g., duplicate action types)

The function is used consistently across the codebase in three locations:

  • apps/web/utils/ai/choose-rule/choose.ts
  • apps/web/app/api/google/webhook/static-rule.ts
  • apps/web/app/api/google/webhook/group-rule.ts

All usages follow the same parameter pattern, maintaining consistency in the implementation.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation and usage of getActionItemsWithAiArgs

# Check the implementation
echo "Checking implementation of getActionItemsWithAiArgs:"
ast-grep --pattern 'export $_ getActionItemsWithAiArgs' -A 10

# Check all usages
echo "Checking all usages of getActionItemsWithAiArgs:"
rg "getActionItemsWithAiArgs" -A 3

Length of output: 2935


Script:

#!/bin/bash
# Get the full implementation of getActionItemsWithAiArgs
echo "Implementation of getActionItemsWithAiArgs:"
cat apps/web/utils/ai/choose-rule/ai-choose-args.ts

# Check the type definitions used
echo -e "\nType definitions:"
rg "interface.*ActionItems" --type ts
rg "type.*ActionItems" --type ts

Length of output: 7281

apps/web/app/api/google/webhook/group-rule.ts (1)

5-5: LGTM! Import consolidation improves code organization.

The consolidated import simplifies the codebase by reducing the number of imported functions while maintaining clear functionality.

apps/web/app/api/google/webhook/static-rule.ts (2)

4-4: LGTM: Import statement is well-organized

The new import for getActionItemsWithAiArgs is properly placed with related AI utility imports.


51-56: Verify error handling and data completeness

While the consolidation of action item generation is a good improvement, please ensure:

  1. Error handling is properly implemented in getActionItemsWithAiArgs
  2. All necessary data from the previous implementation is passed to the new function

Let's verify the implementation of the new function and its error handling:

✅ Verification successful

Let's gather more information about the implementation and error handling in the function:


Error handling and data completeness are properly implemented

The implementation of getActionItemsWithAiArgs is well-structured with:

  • Proper error handling through the logger utility
  • Type safety using zod schema validation
  • Complete data validation for all required parameters
  • Graceful handling of AI-generated args with fallbacks

The function is used consistently across both static and group rule handlers, with all necessary data being passed correctly.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check the implementation of getActionItemsWithAiArgs
ast-grep --pattern 'export async function getActionItemsWithAiArgs($_) {
  $$$
}'

# Check for error handling patterns in related files
rg -A 5 'try.*catch.*getActionItemsWithAiArgs'

# Verify if there are any other callers that might be affected
rg 'getActionItemsWithAiArgs'

Length of output: 1062


Script:

#!/bin/bash
# Check the full implementation of the file containing getActionItemsWithAiArgs
cat apps/web/utils/ai/choose-rule/ai-choose-args.ts

# Check the implementation of files that call this function
cat apps/web/app/api/google/webhook/static-rule.ts
cat apps/web/app/api/google/webhook/group-rule.ts

Length of output: 13019

apps/web/utils/ai/choose-rule/choose-and-execute.ts (1)

90-103: 🛠️ Refactor suggestion

Consider adding data validation for email-related fields.

The mapping of action items includes email-related fields (to, cc, bcc) which should be validated to ensure they contain valid email addresses before saving to the database.

Let's check if there's any validation in place:

Consider adding validation:

 actionItems: {
   createMany: {
     data:
       plannedAct.actionItems?.map((a) => ({
         type: a.type,
         label: a.label,
         subject: a.subject,
         content: a.content,
-        to: a.to,
-        cc: a.cc,
-        bcc: a.bcc,
+        to: validateEmailAddresses(a.to),
+        cc: validateEmailAddresses(a.cc),
+        bcc: validateEmailAddresses(a.bcc),
       })) || [],
   },
 },
apps/web/utils/ai/actions.ts (1)

12-14: LGTM! Well-structured logging setup.

The introduction of a scoped logger with a descriptive identifier "ai-actions" follows good practices for structured logging.

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

27-29: LGTM: Logger setup is appropriate

The scoped logger implementation provides better context for debugging and monitoring.

Comment on lines +13 to +25
const formatMessage = (level: LogLevel, message: LogMessage) => {
const prefix = `[${scope}]: `;

if (process.env.NODE_ENV === "development") {
return `${colors[level]}${prefix} ${
typeof message === "string" ? message : JSON.stringify(message, null, 2)
}${colors.reset}`;
}

return `${prefix} ${
typeof message === "string" ? message : JSON.stringify(message)
}`;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add safety measures for object serialization.

The current implementation might face issues with circular references and large objects.

 const formatMessage = (level: LogLevel, message: LogMessage) => {
   const prefix = `[${scope}]: `;

+  const safeStringify = (obj: Record<string, unknown>) => {
+    const cache = new Set();
+    return JSON.stringify(obj, (key, value) => {
+      if (typeof value === 'object' && value !== null) {
+        if (cache.has(value)) {
+          return '[Circular]';
+        }
+        cache.add(value);
+      }
+      return value;
+    }, process.env.NODE_ENV === "development" ? 2 : undefined);
+  };

   if (process.env.NODE_ENV === "development") {
     return `${colors[level]}${prefix} ${
-      typeof message === "string" ? message : JSON.stringify(message, null, 2)
+      typeof message === "string" ? message : safeStringify(message)
     }${colors.reset}`;
   }

   return `${prefix} ${
-    typeof message === "string" ? message : JSON.stringify(message)
+    typeof message === "string" ? message : safeStringify(message)
   }`;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const formatMessage = (level: LogLevel, message: LogMessage) => {
const prefix = `[${scope}]: `;
if (process.env.NODE_ENV === "development") {
return `${colors[level]}${prefix} ${
typeof message === "string" ? message : JSON.stringify(message, null, 2)
}${colors.reset}`;
}
return `${prefix} ${
typeof message === "string" ? message : JSON.stringify(message)
}`;
};
const formatMessage = (level: LogLevel, message: LogMessage) => {
const prefix = `[${scope}]: `;
const safeStringify = (obj: Record<string, unknown>) => {
const cache = new Set();
return JSON.stringify(obj, (key, value) => {
if (typeof value === 'object' && value !== null) {
if (cache.has(value)) {
return '[Circular]';
}
cache.add(value);
}
return value;
}, process.env.NODE_ENV === "development" ? 2 : undefined);
};
if (process.env.NODE_ENV === "development") {
return `${colors[level]}${prefix} ${
typeof message === "string" ? message : safeStringify(message)
}${colors.reset}`;
}
return `${prefix} ${
typeof message === "string" ? message : safeStringify(message)
}`;
};

Comment on lines +1 to +43
type LogLevel = "log" | "error" | "warn" | "trace";
type LogMessage = string | Record<string, unknown>;

const colors = {
log: "\x1b[0m", // white
error: "\x1b[31m", // red
warn: "\x1b[33m", // yellow
trace: "\x1b[36m", // cyan
reset: "\x1b[0m",
} as const;

export function createScopedLogger(scope: string) {
const formatMessage = (level: LogLevel, message: LogMessage) => {
const prefix = `[${scope}]: `;

if (process.env.NODE_ENV === "development") {
return `${colors[level]}${prefix} ${
typeof message === "string" ? message : JSON.stringify(message, null, 2)
}${colors.reset}`;
}

return `${prefix} ${
typeof message === "string" ? message : JSON.stringify(message)
}`;
};

return {
log: (message: LogMessage, ...args: unknown[]) =>
console.log(formatMessage("log", message), ...args),

error: (message: LogMessage, ...args: unknown[]) =>
console.error(formatMessage("error", message), ...args),

warn: (message: LogMessage, ...args: unknown[]) =>
console.warn(formatMessage("warn", message), ...args),

trace: (message: LogMessage, ...args: unknown[]) => {
if (process.env.NODE_ENV === "development") {
console.log(formatMessage("trace", message), ...args);
}
},
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Based on the search results, I can now generate the final response:

Migration to scoped logger needed across multiple utility files

The new logger utility is currently used in only 3 files:

  • apps/web/utils/ai/actions.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/app/api/google/webhook/process-history.ts

However, there are numerous direct console.* calls across the codebase that should be migrated to use this new scoped logger:

  • Multiple utility files under apps/web/utils/ (middleware.ts, json.ts, posthog.ts, etc.)
  • API route handlers under apps/web/app/api/
  • Action handlers under apps/web/utils/actions/

The migration should be done systematically to ensure consistent logging across the application.

🔗 Analysis chain

Verify logger integration and usage patterns.

Since this is a new utility replacing existing console.* calls, let's verify its integration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify logger usage and potential console.* calls that should be migrated

# Check for remaining console.* calls that should use the logger
echo "Checking for console.* calls that should be migrated to the logger..."
rg -t typescript -t javascript 'console\.(log|error|warn|debug)' --glob '!apps/web/utils/logger.ts'

# Check current usage patterns of the logger
echo "Checking current logger usage patterns..."
rg -t typescript -t javascript 'createScopedLogger'

Length of output: 465


Script:

#!/bin/bash
# Let's try with simpler commands without file type filters

# Check for remaining console.* calls that should use the logger
echo "Checking for console.* calls that should be migrated to the logger..."
rg 'console\.(log|error|warn|debug)' --glob '!apps/web/utils/logger.ts'

# Check current usage patterns of the logger
echo "Checking current logger usage patterns..."
rg 'createScopedLogger'

# Check for any TypeScript/JavaScript files to understand the codebase structure
echo "Checking for TypeScript/JavaScript files..."
fd '\.(ts|js|tsx|jsx)$'

Length of output: 46513

Comment on lines +59 to +64
// get action items with args
const actionItems = await getActionItemsWithAiArgs({
email,
user,
selectedRule: match.rule,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding error handling for AI operations.

The AI operation could fail due to various reasons (API limits, network issues, invalid responses). Consider adding proper error handling to ensure graceful degradation.

   // get action items with args
-  const actionItems = await getActionItemsWithAiArgs({
-    email,
-    user,
-    selectedRule: match.rule,
-  });
+  let actionItems;
+  try {
+    actionItems = await getActionItemsWithAiArgs({
+      email,
+      user,
+      selectedRule: match.rule,
+    });
+  } catch (error) {
+    console.error('Failed to generate AI action items:', error);
+    // Consider your error handling strategy:
+    // 1. Return early with an error status
+    // 2. Continue with empty actionItems
+    // 3. Retry with backoff
+    actionItems = [];
+  }

Committable suggestion skipped: line range outside the PR's diff.


💡 Codebase verification

Migration to consolidated AI function needs attention

The verification shows that while the new getActionItemsWithAiArgs function is properly used across multiple files, the old getArgsAiResponse function still exists and is being used in apps/web/utils/ai/choose-rule/ai-choose-args.ts. This indicates an incomplete migration:

  • apps/web/utils/ai/choose-rule/ai-choose-args.ts: Contains both the old and new implementation, with the old getArgsAiResponse function still being actively used.
🔗 Analysis chain

Verify complete migration to consolidated AI function.

Let's ensure all previous AI argument handling code has been properly migrated to use the new consolidated function.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining usage of old AI argument handling functions
rg -l "getArgsAiResponse|getActionItemsFromAiArgsResponse" --type typescript

# Search for the new consolidated function usage
rg -l "getActionItemsWithAiArgs" --type typescript

Length of output: 199


Script:

#!/bin/bash
# Search for any remaining usage of old AI argument handling functions without file type restriction
rg -l "getArgsAiResponse|getActionItemsFromAiArgsResponse"

# Search for the new consolidated function usage
rg -l "getActionItemsWithAiArgs"

# Let's also check for function definitions to understand the migration
ast-grep --pattern 'function getArgsAiResponse'
ast-grep --pattern 'function getActionItemsFromAiArgsResponse'
ast-grep --pattern 'function getActionItemsWithAiArgs'

Length of output: 494


Script:

#!/bin/bash
# Let's check the content of ai-choose-args.ts to see if old functions are just imported or actually used
rg "getArgsAiResponse|getActionItemsFromAiArgsResponse" apps/web/utils/ai/choose-rule/ai-choose-args.ts -C 3

# Let's also check how getActionItemsWithAiArgs is used across files
rg "getActionItemsWithAiArgs" apps/web/utils/ai/choose-rule/choose.ts -C 3
rg "getActionItemsWithAiArgs" apps/web/utils/ai/choose-rule/ai-choose-args.ts -C 3
rg "getActionItemsWithAiArgs" apps/web/app/api/google/webhook/static-rule.ts -C 3
rg "getActionItemsWithAiArgs" apps/web/app/api/google/webhook/group-rule.ts -C 3

Length of output: 2513

Comment on lines +375 to +376
logger.log("Running action", { actionType: action.type, userEmail });
logger.trace("Running action:", action);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider security and performance implications of logging.

A few concerns about the current logging implementation:

  1. The trace log includes the entire action object which might contain sensitive information (e.g., email addresses, message content).
  2. The userEmail being logged could be considered PII.
  3. No conditional check for trace level before object serialization, which could impact performance.

Consider applying these improvements:

-  logger.log("Running action", { actionType: action.type, userEmail });
-  logger.trace("Running action:", action);
+  logger.log("Running action", { 
+    actionType: action.type,
+    userEmail: userEmail.replace(/(.{2}).*@/, '$1***@') // Mask email
+  });
+  if (logger.isTraceEnabled()) {
+    const sanitizedAction = {
+      ...action,
+      content: action.content ? '[REDACTED]' : undefined,
+      to: action.to ? '[REDACTED]' : undefined,
+      cc: action.cc ? '[REDACTED]' : undefined,
+      bcc: action.bcc ? '[REDACTED]' : undefined
+    };
+    logger.trace("Running action details:", sanitizedAction);
+  }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +100 to 102
console.debug(`does not have hasAiOrColdEmailAccess. email: ${email}`);
await unwatchEmails(account);
return NextResponse.json({ ok: true });
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace console.debug with logger.debug for consistency

There's a remaining console.debug call that should be updated to use the scoped logger.

-    console.debug(`does not have hasAiOrColdEmailAccess. email: ${email}`);
+    logger.debug(`does not have hasAiOrColdEmailAccess. email: ${email}`);

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +154 to +155
const args: Record<string, string> = toolCallArgs[key]; // e.g. { label: "Draft", subject: "X", content: "Y" }

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle potential undefined values in toolCallArgs[key]

When accessing toolCallArgs[key], there's a possibility that it might be undefined. To prevent runtime errors, add a check or provide a default value to ensure args is always an object.

Apply this diff:

 const [key] = actionParameter; // e.g. key = "draft_email"
-const args: Record<string, string> = toolCallArgs[key]; // e.g. { label: "Draft", subject: "X", content: "Y" }
+const args: Record<string, string> = toolCallArgs[key] || {}; // Ensure args is an object even if undefined
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const args: Record<string, string> = toolCallArgs[key]; // e.g. { label: "Draft", subject: "X", content: "Y" }
const args: Record<string, string> = toolCallArgs[key] || {}; // Ensure args is an object even if undefined

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