Skip to content

Show error messages for users for things like invalid AI API key#239

Merged
elie222 merged 5 commits intomainfrom
error-panel
Oct 9, 2024
Merged

Show error messages for users for things like invalid AI API key#239
elie222 merged 5 commits intomainfrom
error-panel

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Oct 9, 2024

Summary by CodeRabbit

  • New Features

    • Introduced a new component to display user error messages.
    • Added functionality to manage user error messages, including retrieval and clearing options.
  • Bug Fixes

    • Enhanced error handling in chat completion functions.
    • Improved specificity in error detection for API key errors.
  • Documentation

    • Updated types and methods for error message management.
  • Chores

    • Modified database schema to support structured storage of user error messages.

@vercel
Copy link

vercel bot commented Oct 9, 2024

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

Name Status Preview Updated (UTC)
inbox-zero ✅ Ready (Inspect) Visit Preview Oct 9, 2024 6:23am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 9, 2024

Caution

Review failed

The pull request is closed.

Walkthrough

The changes introduce a new React component, ErrorMessages, designed to manage and display user error messages. It is integrated into the application layout to ensure error messages appear above the main content. Additionally, modifications to the database schema and Prisma models allow for the storage of error messages within user records. New utility functions for managing error messages are also added, alongside improvements to error handling in existing functions.

Changes

File Change Summary
apps/web/app/(app)/ErrorMessages.tsx Introduced ErrorMessages component for displaying user error messages.
apps/web/app/(app)/layout.tsx Imported ErrorMessages and modified layout to include it above the main content.
apps/web/components/Alert.tsx Updated AlertError props to accept React.ReactNode for the description.
apps/web/prisma/migrations/.../migration.sql Added errorMessages column of type JSONB to the "User" table for storing error messages.
apps/web/prisma/schema.prisma Added errorMessages field to User model and added unique constraint to userId in Account model.
apps/web/utils/actions/error-messages.ts Introduced clearUserErrorMessagesAction function for clearing user error messages.
apps/web/utils/error-messages/index.ts Added types and functions for managing user error messages, including getUserErrorMessages and addUserErrorMessage.
apps/web/utils/llms/index.ts Enhanced error handling in chatCompletionObject and chatCompletionTools, added handleError function.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ErrorMessages
    participant AlertError
    participant Database

    User->>ErrorMessages: Request error messages
    ErrorMessages->>Database: Fetch user error messages
    Database-->>ErrorMessages: Return error messages
    ErrorMessages->>AlertError: Display error messages
    User->>AlertError: Click to clear messages
    AlertError->>ErrorMessages: Trigger clearUserErrorMessagesAction
    ErrorMessages->>Database: Clear user error messages
    Database-->>ErrorMessages: Confirm messages cleared
Loading

🐰 "In the code where errors do dwell,
A new friend comes to bid farewell.
With messages clear and layout bright,
Our app now shines, a joyful sight!
So hop along, let errors flee,
For happy users there shall be!" 🐇✨

Possibly related PRs


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.

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: 3

🧹 Outside diff range and nitpick comments (12)
apps/web/prisma/migrations/20241008234839_error_messages/migration.sql (1)

1-2: LGTM! Consider adding a default value or NOT NULL constraint.

The addition of the errorMessages column as JSONB type is a good choice for storing flexible error message structures. This aligns well with the PR objective of showing error messages for users.

A few considerations for the team:

  1. The column allows NULL values. Depending on your requirements, you might want to add a NOT NULL constraint.
  2. Consider adding a default value (e.g., an empty JSON object '{}') to ensure consistency for existing and new rows.
  3. Ensure that the application code handles potential NULL values or empty objects when reading from this column.
apps/web/utils/actions/error-messages.ts (2)

1-6: Consider using import type for type-only imports.

To optimize the bundle size and ensure type information is removed during transpilation, consider using import type for the ServerActionResponse import.

Apply this change:

-import { ServerActionResponse } from "@/utils/error";
+import type { ServerActionResponse } from "@/utils/error";
🧰 Tools
🪛 Biome

[error] 4-5: All these imports are only used as types.

Importing the types with import type ensures that they are removed by the transpilers and avoids loading unnecessary modules.
Safe fix: Use import type.

(lint/style/useImportType)


8-13: Approve implementation with a minor suggestion.

The clearUserErrorMessagesAction function is well-implemented with proper error handling and session validation. However, consider adding a success response for better consistency and to allow the client to confirm the operation's success.

Consider modifying the function to return a success response:

 export async function clearUserErrorMessagesAction(): Promise<ServerActionResponse> {
   const session = await auth();
   if (!session?.user) return { error: "Not logged in" };
   await clearUserErrorMessages(session.user.id);
   revalidatePath("/(app)", "layout");
+  return { success: true };
 }
apps/web/app/(app)/ErrorMessages.tsx (3)

7-13: LGTM: Good error handling and performance considerations.

The component efficiently handles cases where there's no user session or no error messages. For improved type safety, consider adding a type annotation for the errorMessages variable.

Consider adding a type annotation:

const errorMessages: Record<string, { message: string }> | null = await getUserErrorMessages(session.user.id);

15-36: LGTM with suggestions: Clean JSX structure with room for minor improvements.

The component's structure is well-organized and follows React best practices. Consider the following suggestions:

  1. Extract the onClick handler for the "Clear" button to improve readability.
  2. Use a more reliable key for mapped elements, as error messages might not be unique.

Here's a suggested refactor:

const handleClearErrors = () => {
  clearUserErrorMessagesAction();
};

return (
  <div className="p-2">
    <AlertError
      title="Error"
      description={
        <>
          {Object.entries(errorMessages).map(([key, error]) => (
            <div key={key}>{error.message}</div>
          ))}
          <Button onClick={handleClearErrors}>
            Clear
          </Button>
        </>
      }
    />
  </div>
);

1-37: LGTM: Well-designed and reusable component.

The ErrorMessages component is well-structured, follows React best practices, and effectively handles its responsibilities. It integrates seamlessly with the authentication system and error message utilities.

For future improvement, consider adding a prop to customize the error message display or the clear button text. This would enhance the component's flexibility for different use cases.

Example of a more flexible component signature:

interface ErrorMessagesProps {
  customTitle?: string;
  clearButtonText?: string;
}

export async function ErrorMessages({ 
  customTitle = "Error", 
  clearButtonText = "Clear" 
}: ErrorMessagesProps) {
  // ... existing code ...
}
apps/web/app/(app)/layout.tsx (1)

43-46: LGTM: ErrorMessages integration looks good. Consider adding a comment for clarity.

The ErrorMessages component is correctly placed within the SideNavWithTopNav, ensuring error messages appear above the main content. This is a good approach for user experience.

Consider adding a brief comment explaining the purpose of the ErrorMessages component for better code readability:

 <SideNavWithTopNav>
+  {/* Display user error messages above main content */}
   <ErrorMessages />
   {children}
 </SideNavWithTopNav>
apps/web/components/Alert.tsx (1)

50-53: LGTM! Consider adding JSDoc for clarity.

The change from string to React.ReactNode for the description prop is a good improvement. It aligns AlertError with other Alert components and allows for more flexible content in the description.

Consider adding a JSDoc comment to clarify the usage of React.ReactNode for future developers:

/**
 * @param props.title - The title of the error alert
 * @param props.description - The description of the error. Can be a string or a React node.
 */
export function AlertError(props: {
  title: string;
  description: React.ReactNode;
}) {
  // ... (rest of the component)
}
apps/web/prisma/schema.prisma (1)

62-62: Approved with suggestions: errorMessages field in User model

The addition of the errorMessages field to the User model is a good way to store user-specific error information. The Json? type provides flexibility for various error message structures.

Suggestions for improvement:

  1. Enhance the comment to provide more context about the field's purpose and potential uses beyond the AI API key example.
  2. Consider using a more structured approach for error messages. For example:
errorMessages Json? // Structure: { "aiApiKey": ["Invalid key", "Expired"], "other": ["Error message"] }

This structure would make it easier to query and manage specific types of errors.

  1. If you frequently need to query for specific error types, consider creating a separate UserError model for better performance and querying capabilities.

Would you like me to propose a more detailed structure for the errorMessages field or a separate UserError model?

apps/web/utils/error-messages/index.ts (2)

33-33: Remove unnecessary optional chaining for user.errorMessages

Since you've already confirmed that user exists, you don't need to use optional chaining when accessing user.errorMessages. You can safely access it directly.

Apply this change:

-const currentErrorMessages = (user?.errorMessages as ErrorMessages) || {};
+const currentErrorMessages = (user.errorMessages as ErrorMessages) || {};

49-54: Ensure consistency in error message handling in clearUserErrorMessages

While clearUserErrorMessages clears the errorMessages field, consider adding error handling similar to addUserErrorMessage to manage cases where the user might not be found.

You could add a check for the user's existence:

export async function clearUserErrorMessages(userId: string): Promise<void> {
  const user = await prisma.user.findUnique({ where: { id: userId } });
  if (!user) {
    console.warn(`User with ID ${userId} not found`);
    return;
  }
  await prisma.user.update({
    where: { id: userId },
    data: { errorMessages: {} },
  });
}
apps/web/utils/llms/index.ts (1)

Line range hint 105-157: Consider adding error handling to chatCompletionStream for consistency

Unlike the other functions, chatCompletionStream does not wrap its logic in a try-catch block to handle potential errors using handleError. For consistency and to ensure that all errors are handled uniformly, consider adding error handling to chatCompletionStream.

Apply this diff to add error handling:

 export async function chatCompletionStream({
   userAi,
   prompt,
   system,
   userEmail,
   usageLabel: label,
   onFinish,
 }: {
   userAi: UserAIFields;
   prompt: string;
   system?: string;
   userEmail: string;
   usageLabel: string;
   onFinish?: (text: string) => Promise<void>;
 }) {
+  try {
   const { provider, model, llmModel } = getModel(userAi);

   const result = await streamText({
     model: llmModel,
     prompt,
     system,
     onFinish: async ({ usage, text }) => {
       await saveAiUsage({
         email: userEmail,
         provider,
         model,
         usage,
         label,
       });

       if (onFinish) await onFinish(text);
     },
   });

   return result;
+  } catch (error) {
+    await handleError(error, userEmail);
+    throw error;
+  }
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between d95f21d and e2af828.

📒 Files selected for processing (8)
  • apps/web/app/(app)/ErrorMessages.tsx (1 hunks)
  • apps/web/app/(app)/layout.tsx (2 hunks)
  • apps/web/components/Alert.tsx (1 hunks)
  • apps/web/prisma/migrations/20241008234839_error_messages/migration.sql (1 hunks)
  • apps/web/prisma/schema.prisma (1 hunks)
  • apps/web/utils/actions/error-messages.ts (1 hunks)
  • apps/web/utils/error-messages/index.ts (1 hunks)
  • apps/web/utils/llms/index.ts (3 hunks)
🧰 Additional context used
🪛 Biome
apps/web/utils/actions/error-messages.ts

[error] 4-5: All these imports are only used as types.

Importing the types with import type ensures that they are removed by the transpilers and avoids loading unnecessary modules.
Safe fix: Use import type.

(lint/style/useImportType)

🔇 Additional comments (9)
apps/web/app/(app)/ErrorMessages.tsx (1)

1-5: LGTM: Imports are well-organized and relevant.

The imports are logically structured and include all necessary modules for the component's functionality.

apps/web/app/(app)/layout.tsx (2)

15-15: LGTM: ErrorMessages import looks good.

The import statement for the ErrorMessages component is correctly implemented, following React and Next.js conventions.


15-15: Verify error handling mechanism for ErrorMessages component.

The integration of the ErrorMessages component aligns well with the PR objective. However, it's not immediately clear how error states are passed to or managed by this component.

To ensure proper error handling:

  1. Verify that the ErrorMessages component can access and display relevant error states.
  2. Check if there's a centralized error state management (e.g., using Context API or Redux) that this component utilizes.

Consider running the following script to check for error-related props or context usage:

This will help ensure that the error handling mechanism is properly implemented and connected to the newly added ErrorMessages component.

Also applies to: 43-46

✅ Verification successful

Error handling mechanism for ErrorMessages component is properly implemented.

The ErrorMessages component correctly imports necessary error handling utilities and manages error states by fetching and clearing error messages. This ensures that error messages are effectively displayed to users and appropriately managed within the application.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for error-related props or context usage in ErrorMessages component

# Test: Search for the ErrorMessages component implementation
echo "Searching for ErrorMessages component implementation:"
ast-grep --lang typescript --pattern 'export $_ function ErrorMessages($_) {
  $$$
}'

# Test: Check for error-related imports or context usage
echo "Checking for error-related imports or context usage:"
rg --type typescript -i '(error|context)' "$(fd -t f ErrorMessages)"

Length of output: 462


Script:

#!/bin/bash
# Description: Check for error-related props or context usage in ErrorMessages component

# Test: Search for the ErrorMessages component implementation
echo "Searching for ErrorMessages component implementation:"
ast-grep --lang typescript --pattern 'export $_ function ErrorMessages($_) {
  $$$
}'

# Test: Check for error-related imports or context usage
echo "Checking for error-related imports or context usage:"
rg -i '(error|context)' --glob '*.tsx' 'apps/web/app/(app)/ErrorMessages.tsx'

Length of output: 985


Script:

#!/bin/bash
# Description: Check for error-related props or context usage in ErrorMessages component

# Test: Search for the async ErrorMessages component implementation
echo "Searching for async ErrorMessages component implementation:"
ast-grep --lang typescript --pattern 'export async function ErrorMessages($_) {
  $$$
}'

# Test: Check for error-related imports or context usage
echo "Checking for error-related imports or context usage:"
rg -i '(error|context)' --glob '*.tsx' 'apps/web/app/(app)/ErrorMessages.tsx'

Length of output: 1000

apps/web/prisma/schema.prisma (2)

Line range hint 1-391: Overall assessment: Positive changes with minor improvement suggestions

The changes to the Prisma schema file are generally positive:

  1. The @unique constraint on userId in the Account model improves data integrity.
  2. The new errorMessages field in the User model allows for flexible error tracking.

These changes align well with the PR objective of showing error messages for users. The schema modifications provide the necessary structure to store and manage these error messages effectively.

To further improve the schema:

  1. Consider adding more detailed comments or documentation for new fields and constraints.
  2. Evaluate the possibility of using more structured approaches for error messages if specific error types need to be frequently queried.

Line range hint 19-19: Approved with considerations: @unique constraint on userId

The addition of the @unique constraint to the userId field in the Account model is a significant change that ensures each user can only have one associated account. This is generally a good practice for maintaining data integrity.

However, please consider the following:

  1. Ensure that this change doesn't conflict with existing data or application logic that might expect multiple accounts per user.
  2. The comment "May remove this in the future" suggests uncertainty about this change. It would be helpful to clarify the reasons for potentially removing it and under what circumstances.

To verify the impact of this change, please run the following script:

This script will help identify any existing users with multiple accounts and locate any application code that might be affected by this change.

apps/web/utils/error-messages/index.ts (1)

15-19: Handle the case when the user is not found in getUserErrorMessages

If the user is not found (user is null), the function currently returns null. Alternatively, you might want to consider throwing an error or returning an empty object {} for consistency.

Run the following script to check how often getUserErrorMessages is called and how null values are handled:

✅ Verification successful

Null handling in getUserErrorMessages is appropriately implemented.

The function getUserErrorMessages is consistently handled with null checks wherever it's called. Returning null when errorMessages are absent maintains the current application behavior and consistency.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all calls to `getUserErrorMessages` and check for null handling.

# Search for calls to `getUserErrorMessages`
rg --type javascript --type typescript 'getUserErrorMessages\(' -A 2

# Look for null checks after function calls
rg --type javascript --type typescript 'const .* = await getUserErrorMessages\(.*\);' -A 2

Length of output: 233


Script:

#!/bin/bash
# Description: Find all calls to `getUserErrorMessages` and check for null handling.

# Search for calls to `getUserErrorMessages`
rg --type js --type ts 'getUserErrorMessages\(' -A 2

# Look for null checks after function calls
rg --type js --type ts 'const .* = await getUserErrorMessages\(.*\);' -A 2

Length of output: 859

apps/web/utils/llms/index.ts (3)

80-103: Error handling in chatCompletionObject is implemented correctly

Wrapping the generateObject call within a try-catch block and using handleError ensures that errors are properly managed and user error messages are added when necessary. The usage data is saved appropriately when available.


159-183: Error handling in chatCompletionTools is implemented correctly

The addition of the try-catch block in chatCompletionTools mirrors the structure in chatCompletionObject, ensuring consistent error handling across functions. The function correctly saves usage data when available.


187-196: 🛠️ Refactor suggestion

⚠️ Potential issue

Improve error detection by using structured error properties instead of string matching

In the handleError function, the code checks for specific error messages using string matching:

if (error.message.includes("Incorrect API key provided")) { ... }

This approach can be fragile, as error messages might change or be localized. Consider using structured properties like error codes or types provided by APICallError for more reliable error detection.

If APICallError provides an error code or type, modify the condition as follows:

 async function handleError(error: unknown, userEmail: string) {
   if (APICallError.isInstance(error)) {
-    if (error.message.includes("Incorrect API key provided")) {
+    if (error.code === 'INVALID_API_KEY') {
       await addUserErrorMessage(
         userEmail,
         ErrorType.INCORRECT_OPENAI_API_KEY,
         error.message,
       );
     }
   }
 }

Run the following script to check if APICallError includes an error code or type property:

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

🧹 Outside diff range and nitpick comments (1)
apps/web/utils/error.ts (1)

71-76: LGTM with a suggestion: Consider case-insensitive error message check.

The new function isIncorrectOpenAIAPIKeyError is well-implemented and serves its purpose of identifying incorrect API key errors. However, to make it more robust against potential changes in the API's error message, consider using a case-insensitive check.

Here's a suggested improvement:

 export function isIncorrectOpenAIAPIKeyError(error: unknown): boolean {
   return (
     APICallError.isInstance(error) &&
-    error.message.includes("Incorrect API key provided")
+    error.message.toLowerCase().includes("incorrect api key provided")
   );
 }

This change ensures that the function will still work even if the API's error message capitalization changes in the future.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between e2af828 and 46a06d2.

📒 Files selected for processing (2)
  • apps/web/utils/error.ts (2 hunks)
  • apps/web/utils/llms/index.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/utils/llms/index.ts
🧰 Additional context used
🔇 Additional comments (3)
apps/web/utils/error.ts (3)

5-5: LGTM: New import statement added correctly.

The import of APICallError from the "ai" module is appropriately placed with other imports at the top of the file. This import is necessary for the new error checking function added below.


84-85: LGTM: Correct integration of new error check.

The modification to the isKnownApiError function correctly incorporates the new isIncorrectOpenAIAPIKeyError check. This ensures that incorrect OpenAI API key errors are now properly handled as known errors, preventing unnecessary logging in Sentry.


Line range hint 1-87: Overall assessment: Well-implemented error handling enhancements.

The changes to this file effectively improve error handling for OpenAI API key issues. The new function and its integration into the existing error checking system are well-implemented and consistent with the file's overall structure and purpose. The only suggestion for improvement is to consider using a case-insensitive check in the isIncorrectOpenAIAPIKeyError function for increased robustness.

🧰 Tools
🪛 Biome

[error] 68-68: Unexpected any. Specify a different type.

any disables many type checking rules. Its use should be avoided.

(lint/suspicious/noExplicitAny)

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