Skip to content

Writing style#408

Merged
elie222 merged 5 commits intomainfrom
writing-style
Apr 17, 2025
Merged

Writing style#408
elie222 merged 5 commits intomainfrom
writing-style

Conversation

@elie222
Copy link
Owner

@elie222 elie222 commented Apr 17, 2025

Summary by CodeRabbit

  • New Features

    • Introduced automatic analysis and storage of users' email writing styles using AI.
    • Added a utility to format bullet lists.
    • Added a function to retrieve a user's writing style by email.
  • Improvements

    • Draft generation now incorporates the user's writing style for more personalized suggestions.
    • Simplified and streamlined function interfaces by removing the need to manually pass access tokens in various email-related features.
  • Database

    • Added a new EmailAccount table to store email addresses and associated writing styles, with updated relations to user and account records.
  • Bug Fixes

    • Improved handling of email data by including the "to" field where necessary and making it optional.
  • Tests

    • Added and updated tests for writing style analysis and related features.

@vercel
Copy link

vercel bot commented Apr 17, 2025

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

Name Status Preview Updated (UTC)
inbox-zero ✅ Ready (Inspect) Visit Preview Apr 17, 2025 4:10pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 17, 2025

Walkthrough

This set of changes removes the explicit use of the Gmail access token parameter from many utility functions, test cases, and internal logic, centralizing access token retrieval within the Gmail message utilities. It introduces a new AI-powered writing style analysis feature, including schema definitions, utility functions, a new database model (EmailAccount), and migration scripts to store writing style data per email account. The writing style is now incorporated into draft generation, and new test suites validate the AI analysis. Several function signatures and return types were updated to reflect these changes, and new utility helpers were added.

Changes

File(s) / Path(s) Change Summary
apps/web/utils/gmail/message.ts Centralized access token retrieval inside queryBatchMessages and queryBatchMessagesPages, removing the need for callers to pass the token; added getSentMessages helper function.
apps/web/utils/ai/group/create-group.ts, find-newsletters.ts, find-receipts.ts, example-matches/find-example-matches.ts, assess.ts, apps/web/utils/assess.ts Removed the accessToken parameter from multiple AI and utility functions and their internal calls, simplifying their interfaces and logic.
apps/web/utils/ai/reply/draft-with-knowledge.ts, apps/web/utils/reply-tracker/generate-draft.ts Added support for passing and using a writingStyle parameter in draft generation, updating function signatures and prompt construction accordingly.
apps/web/utils/ai/knowledge/writing-style.ts Introduced a new module for analyzing email writing style using AI, including schema definition and the aiAnalyzeWritingStyle function.
apps/web/utils/user/get.ts Added getWritingStyle function to retrieve writing style from the database for a given email.
apps/web/utils/string.ts Added a new utility function formatBulletList.
apps/web/utils/types.ts Made the to field optional in the EmailForLLM type.
apps/web/utils/get-email-from-message.ts Extended the returned object from getEmailForLLM to include the to field.
apps/web/prisma/schema.prisma, apps/web/prisma/migrations/20250417135524_writing_style/migration.sql Added a new EmailAccount model/table to store per-email writing style and account linkage; updated Account and User models and schema accordingly.
apps/web/utils/actions/assess.ts Removed access token logic from assessUserAction; added analyzeWritingStyleAction to analyze and persist writing style using AI and database updates.
apps/web/app/(app)/assess.tsx Updated to call analyzeWritingStyleAction after user assessment in the React component.
apps/web/app/api/google/messages/route.ts Removed explicit access token check and parameter passing in message querying logic.
apps/web/utils/actions/rule.ts Removed access token logic from the rule example matching action.
apps/web/__tests__/ai-create-group.test.ts, ai-example-matches.test.ts Updated test cases to remove the accessToken argument from function calls.
apps/web/__tests__/ai/reply/draft-with-knowledge.test.ts Removed unused import and updated tests to pass writingStyle: null to drafting function.
apps/web/__tests__/writing-style.test.ts Added new test suite for the AI writing style analysis feature, including tests for result structure and empty input handling.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant WebApp
    participant AI
    participant DB
    participant Gmail

    User->>WebApp: Initiate assessment
    WebApp->>Gmail: Fetch sent messages (access token internal)
    Gmail-->>WebApp: Return messages
    WebApp->>AI: aiAnalyzeWritingStyle({emails, user})
    AI-->>WebApp: Writing style analysis
    WebApp->>DB: Save writing style to EmailAccount
    DB-->>WebApp: Confirmation
    WebApp-->>User: Assessment complete

    User->>WebApp: Generate draft reply
    WebApp->>DB: getWritingStyle(email)
    DB-->>WebApp: Return writingStyle
    WebApp->>AI: aiDraftWithKnowledge({..., writingStyle})
    AI-->>WebApp: Draft reply
    WebApp-->>User: Show draft
Loading

Possibly related PRs

  • elie222/inbox-zero#244: Introduced the original aiGenerateGroupItems function and related group generation logic, which this PR now simplifies by removing the accessToken parameter from its interface and calls.

Poem

A hop, a skip, a token gone,
Now writing styles are passed along.
With AI’s help, your drafts take flight,
And EmailAccounts store insights right.
From test to schema, code’s refined—
This bunny’s proud of what you’ll find!
🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/web/__tests__/ai-create-group.test.ts

Oops! Something went wrong! :(

ESLint: 9.24.0

ESLint couldn't find an eslint.config.(js|mjs|cjs) file.

From ESLint v9.0.0, the default configuration file is now eslint.config.js.
If you are using a .eslintrc.* file, please follow the migration guide
to update your configuration file to the new format:

https://eslint.org/docs/latest/use/configure/migration-guide

If you still have problems after following the migration guide, please stop by
https://eslint.org/chat/help to chat with the team.

apps/web/__tests__/ai/reply/draft-with-knowledge.test.ts

Oops! Something went wrong! :(

ESLint: 9.24.0

ESLint couldn't find an eslint.config.(js|mjs|cjs) file.

From ESLint v9.0.0, the default configuration file is now eslint.config.js.
If you are using a .eslintrc.* file, please follow the migration guide
to update your configuration file to the new format:

https://eslint.org/docs/latest/use/configure/migration-guide

If you still have problems after following the migration guide, please stop by
https://eslint.org/chat/help to chat with the team.

apps/web/__tests__/ai-example-matches.test.ts

Oops! Something went wrong! :(

ESLint: 9.24.0

ESLint couldn't find an eslint.config.(js|mjs|cjs) file.

From ESLint v9.0.0, the default configuration file is now eslint.config.js.
If you are using a .eslintrc.* file, please follow the migration guide
to update your configuration file to the new format:

https://eslint.org/docs/latest/use/configure/migration-guide

If you still have problems after following the migration guide, please stop by
https://eslint.org/chat/help to chat with the team.

  • 17 others

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.
  • @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

🧹 Nitpick comments (10)
apps/web/app/(app)/assess.tsx (1)

21-21: Consider handling errors and adding a loading state.

While the addition of the writing style analysis is good, consider adding error handling and possibly a loading state indicator for a better user experience.

- analyzeWritingStyleAction();
+ analyzeWritingStyleAction().catch(error => {
+   console.error("Error analyzing writing style:", error);
+   // Consider adding a user-friendly error notification if appropriate
+ });

Additionally, you might want to track the loading state if this analysis takes time, especially since it analyzes up to 20 emails:

const [isAnalyzing, setIsAnalyzing] = useState(false);

useEffect(() => {
  assessUser();
  setIsAnalyzing(true);
  analyzeWritingStyleAction()
    .finally(() => setIsAnalyzing(false))
    .catch(error => console.error("Error analyzing writing style:", error));
}, []);

// Return loading indicator if needed
return isAnalyzing ? <SomeLoadingIndicator /> : null;
apps/web/__tests__/ai-create-group.test.ts (1)

26-26: Remove unused variable

The accessToken variable is declared but no longer used after removing it from the function call.

-    const accessToken = "fake-access-token";
apps/web/__tests__/ai-example-matches.test.ts (1)

27-27: Remove unused variable

The accessToken variable is declared but no longer used after removing it from the function call.

-    const accessToken = "fake-access-token";
apps/web/utils/string.ts (1)

48-50: Well-implemented utility function for bullet list formatting

The formatBulletList function is clear, concise, and serves a specific purpose for the new writing style analysis feature.

Consider making the bullet character customizable for more flexibility:

-export function formatBulletList(list: string[]) {
-  return list.map((item) => `- ${item}`).join("\n");
+export function formatBulletList(list: string[], bulletChar = "- ") {
+  return list.map((item) => `${bulletChar}${item}`).join("\n");
}
apps/web/utils/user/get.ts (1)

45-52: Well-designed data access function for writing style

This function effectively retrieves the writing style for a user's email account, supporting the new AI-powered writing style analysis feature.

Consider adding TypeScript return type annotations for better code clarity:

-export async function getWritingStyle(email: string) {
+export async function getWritingStyle(email: string): Promise<string | null> {
  const writingStyle = await prisma.emailAccount.findUnique({
    where: { email },
    select: { writingStyle: true },
  });

  return writingStyle?.writingStyle || null;
}
apps/web/utils/ai/reply/draft-with-knowledge.ts (1)

67-74: Limit writingStyle length to avoid token over‑runs

writingStylePrompt may contain the full, un‑sanitised text returned by the style analysis.
When large (e.g. an entire long e‑mail), the prompt can easily exceed the LLM’s context window, increase latency, or incur higher costs.

-const writingStylePrompt = writingStyle
-  ? `Writing style:
-
-<writing_style>
-${writingStyle}
-</writing_style>
-`
-  : "";
+const writingStylePrompt = writingStyle
+  ? `Writing style:
+
+<writing_style>
+${writingStyle.slice(0, 1_000)} <!-- truncate to ~1 k chars -->
+</writing_style>
+`
+  : "";

Alternatively call a helper such as truncateForLLM(writingStyle, 1_000) to keep this logic consistent with stringifyEmail(…, 3000).

apps/web/utils/actions/assess.ts (1)

91-92: Skip DB write when nothing meaningful was produced

If every element was filtered out, writingStyle becomes the empty string –
persisting it overwrites any future analysis yet yields no value.
Consider short‑circuiting:

-    ]
-      .filter(Boolean)
-      .join("\n");
+    ].filter(Boolean).join("\n");
+
+    if (!writingStyle) {
+      logger.warn("Writing‑style analysis produced no usable output", {
+        userId: session.user.id,
+      });
+      return { error: "Writing style unavailable" };
+    }
apps/web/prisma/migrations/20250417135524_writing_style/migration.sql (1)

30-33: Unique index on nullable FK can fail in some SQL engines

PostgreSQL allows multiple NULLs, so UNIQUE ("emailAccountId") is safe,
but other engines (e.g. MySQL) treat NULL as a value, causing the migration
to fail when several rows have NULL.
If cross‑DB compatibility is required, use a partial index or add WHERE "emailAccountId" IS NOT NULL.

CREATE UNIQUE INDEX "Account_emailAccountId_key"
  ON "Account"("emailAccountId")
  WHERE "emailAccountId" IS NOT NULL;
apps/web/prisma/schema.prisma (1)

110-110: Consider expanding the code comment about settings migration.

The comment "Migrating over to the new settings model" is somewhat vague. Consider adding more context about the migration strategy and timeline.

- // Migrating over to the new settings model. Currently most settings are in the User model, but will be moved to this model in the future.
+ // Migration Strategy: Currently most email settings are stored in the User model.
+ // This new EmailAccount model will gradually replace user-specific email settings
+ // to enable multi-account support. We're starting with writingStyle and will
+ // incrementally migrate other fields (signature, about, etc.) in future updates.
apps/web/utils/ai/group/create-group.ts (1)

9-10: Consider removing commented code or adding more context.

Line 9 contains a comment "no longer in use. delete?" without clear context about what is being referenced.

Either remove this comment if it's not relevant, or clarify what specifically is no longer in use and should be considered for deletion.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a477a8e and 37179cd.

📒 Files selected for processing (23)
  • apps/web/__tests__/ai-create-group.test.ts (1 hunks)
  • apps/web/__tests__/ai-example-matches.test.ts (1 hunks)
  • apps/web/__tests__/ai/reply/draft-with-knowledge.test.ts (3 hunks)
  • apps/web/__tests__/writing-style.test.ts (1 hunks)
  • apps/web/app/(app)/assess.tsx (2 hunks)
  • apps/web/app/api/google/messages/route.ts (1 hunks)
  • apps/web/prisma/migrations/20250417135524_writing_style/migration.sql (1 hunks)
  • apps/web/prisma/schema.prisma (2 hunks)
  • apps/web/utils/actions/assess.ts (3 hunks)
  • apps/web/utils/actions/rule.ts (0 hunks)
  • apps/web/utils/ai/example-matches/find-example-matches.ts (2 hunks)
  • apps/web/utils/ai/group/create-group.ts (4 hunks)
  • apps/web/utils/ai/group/find-newsletters.ts (1 hunks)
  • apps/web/utils/ai/group/find-receipts.ts (3 hunks)
  • apps/web/utils/ai/knowledge/writing-style.ts (1 hunks)
  • apps/web/utils/ai/reply/draft-with-knowledge.ts (5 hunks)
  • apps/web/utils/assess.ts (2 hunks)
  • apps/web/utils/get-email-from-message.ts (1 hunks)
  • apps/web/utils/gmail/message.ts (5 hunks)
  • apps/web/utils/reply-tracker/generate-draft.ts (2 hunks)
  • apps/web/utils/string.ts (1 hunks)
  • apps/web/utils/types.ts (1 hunks)
  • apps/web/utils/user/get.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • apps/web/utils/actions/rule.ts
🧰 Additional context used
🧬 Code Graph Analysis (11)
apps/web/__tests__/ai-example-matches.test.ts (1)
apps/web/utils/ai/example-matches/find-example-matches.ts (1)
  • aiFindExampleMatches (29-131)
apps/web/utils/reply-tracker/generate-draft.ts (2)
apps/web/utils/user/get.ts (1)
  • getWritingStyle (45-52)
apps/web/utils/ai/reply/draft-with-knowledge.ts (1)
  • aiDraftWithKnowledge (103-151)
apps/web/utils/ai/group/find-newsletters.ts (1)
apps/web/utils/gmail/message.ts (1)
  • queryBatchMessagesPages (246-269)
apps/web/app/api/google/messages/route.ts (1)
apps/web/utils/gmail/message.ts (1)
  • queryBatchMessages (216-243)
apps/web/app/(app)/assess.tsx (1)
apps/web/utils/actions/assess.ts (1)
  • analyzeWritingStyleAction (50-122)
apps/web/__tests__/writing-style.test.ts (1)
apps/web/utils/ai/knowledge/writing-style.ts (1)
  • aiAnalyzeWritingStyle (19-93)
apps/web/utils/ai/group/find-receipts.ts (1)
apps/web/utils/gmail/message.ts (1)
  • queryBatchMessagesPages (246-269)
apps/web/utils/gmail/message.ts (1)
apps/web/utils/gmail/client.ts (1)
  • getAccessTokenFromClient (47-52)
apps/web/utils/ai/group/create-group.ts (1)
apps/web/utils/gmail/message.ts (1)
  • queryBatchMessages (216-243)
apps/web/utils/ai/example-matches/find-example-matches.ts (1)
apps/web/utils/gmail/message.ts (1)
  • queryBatchMessages (216-243)
apps/web/utils/ai/reply/draft-with-knowledge.ts (2)
apps/web/utils/types.ts (1)
  • EmailForLLM (104-113)
apps/web/utils/llms/types.ts (1)
  • UserEmailWithAI (4-5)
🔇 Additional comments (46)
apps/web/utils/gmail/message.ts (5)

14-14: Good addition of a centralized token retrieval utility.

This import of getAccessTokenFromClient is used to refactor the code and centralize the access token retrieval logic, making the API more maintainable.


192-195: Helpful documentation enhancement.

These added comments clearly explain the limitations of the getMessages function, notably that it returns only minimal message data requiring separate fetches for details. This improves the API documentation and helps prevent misuse.


234-234: Good refactoring to centralize access token retrieval.

Centralizing the access token retrieval here eliminates the need for explicit access token parameters throughout the codebase, reducing the risk of authentication mistakes and simplifying function signatures.


260-260: Correctly updated to match refactored function signature.

This call has been properly updated to match the refactored queryBatchMessages function that no longer requires an explicit access token parameter.


271-277: Good utility function addition for the writing style feature.

This new getSentMessages function provides a clean abstraction specifically designed for retrieving sent messages, which supports the new writing style analysis feature while maintaining the single responsibility principle.

apps/web/utils/types.ts (1)

107-107: Appropriate type adjustment for flexibility.

Making the to field optional in the EmailForLLM type is appropriate since not all email contexts require a recipient, particularly when analyzing sent emails for writing style where the content analysis may be the primary focus.

apps/web/__tests__/ai/reply/draft-with-knowledge.test.ts (2)

1-1: Good removal of unused import.

Removing the unused beforeEach import keeps the code clean.


27-27: Tests correctly updated for new parameter.

Tests have been properly updated to include the new writingStyle parameter in the aiDraftWithKnowledge function calls, maintaining test coverage for the updated function signature.

Also applies to: 51-51

apps/web/app/(app)/assess.tsx (1)

5-8: Well-structured import for new functionality.

The import has been properly restructured to include the new writing style analysis function while maintaining good code organization.

apps/web/__tests__/ai-create-group.test.ts (1)

63-63: Function parameter removal improves API clarity

Removing the accessToken parameter from the aiGenerateGroupItems function call is a good refactoring that simplifies the API by centralizing token management.

apps/web/__tests__/ai-example-matches.test.ts (1)

69-69: Function parameter removal improves API clarity

Removing the accessToken parameter from the aiFindExampleMatches function call aligns with the updated function signature and simplifies the API.

apps/web/utils/reply-tracker/generate-draft.ts (3)

8-8: Good update to include the writing style functionality

Adding getWritingStyle import alongside the existing getAiUser keeps related user preferences together and follows the single responsibility principle.


178-179: Well-placed writing style retrieval

Excellent placement of the writing style retrieval before the draft generation step. This ensures the user's writing style is available when generating personalized content.


186-186: Clean integration of writing style into aiDraftWithKnowledge

The writing style is correctly passed to the draft generation function, enabling personalized email drafts that match the user's usual communication style.

apps/web/app/api/google/messages/route.ts (1)

29-33: Simplified API call with improved token handling

Good refactoring to remove the explicit access token passing. This aligns with the broader effort to centralize access token management within Gmail utility functions, making the code more maintainable and reducing duplication.

apps/web/utils/get-email-from-message.ts (1)

12-12: Important addition of 'to' field for complete email context

Adding the to field to the email object is crucial for proper writing style analysis and personalized draft generation. This ensures the AI has complete context about communication participants.

apps/web/utils/ai/group/find-newsletters.ts (2)

16-19: Good simplification of the queryBatchMessagesPages call

Removing the access token parameter aligns with the broader refactoring to centralize token management. This makes the API more intuitive and reduces the burden on calling code.


20-23: Consistent token handling in second API call

The same improvement is correctly applied to the second call to queryBatchMessagesPages, maintaining consistency throughout the codebase.

apps/web/utils/ai/example-matches/find-example-matches.ts (3)

70-70: Function signature updated to remove accessToken parameter.

The listEmailsTool function has been updated to only accept a Gmail client instance without requiring an explicit access token. This is part of a broader refactoring across the codebase where access tokens are now internally managed within Gmail message querying functions.


76-76: Updated queryBatchMessages call to remove accessToken parameter.

This change aligns with the centralized token retrieval pattern implemented in the queryBatchMessages function, which now extracts the access token directly from the Gmail client instance.


102-102: Tool instantiation updated to match new function signature.

The listEmailsTool instantiation has been updated to only pass the Gmail client instance, following the interface change to remove the explicit accessToken parameter.

apps/web/__tests__/writing-style.test.ts (3)

1-41: Well-structured test suite for the new writing style analysis feature.

This new test suite properly validates the core functionality of the aiAnalyzeWritingStyle function, checking both successful analysis and empty input handling. The conditional test execution based on environment variables is a good practice for AI-dependent tests.

The 15-second timeout is appropriate for tests involving AI API calls that may take longer than standard unit tests.


43-52: Good test user setup with necessary fields.

The test user mock includes all required fields for the AI analysis functionality, with appropriate null values for optional fields.


54-84: Comprehensive test data with varied email examples.

The test emails provide a good variety of communication styles, lengths, and contexts that should give the AI model sufficient data to analyze writing patterns. This helps ensure the writing style analysis feature works correctly with different types of user emails.

apps/web/utils/assess.ts (3)

42-42: Updated function call to remove accessToken parameter.

The call to getEmailClients has been updated to remove the accessToken parameter, following the interface change. This is part of the larger refactoring to centralize access token management.


101-101: Function signature updated to remove accessToken parameter.

The getEmailClients function now only requires the Gmail client instance. This simplifies the function signature while maintaining the same functionality through the internal token retrieval mechanism.


103-103: Updated queryBatchMessages call to remove accessToken parameter.

The call to queryBatchMessages no longer passes an accessToken, relying instead on the function to extract it from the Gmail client. This change is consistent with the overall refactoring pattern across the codebase.

apps/web/utils/ai/group/find-receipts.ts (6)

41-41: Function signature updated to remove accessToken parameter.

The findReceipts function has been simplified to remove the explicit accessToken parameter, following the project-wide refactoring to centralize token management.


42-43: Updated function calls to remove accessToken parameters.

The calls to helper functions findReceiptSenders and findReceiptSubjects have been updated to no longer pass the accessToken parameter, maintaining consistency with their updated signatures.


97-97: Function signature updated to remove accessToken parameter.

The findReceiptSenders helper function now only accepts the Gmail client instance, simplified from the previous interface that required an explicit access token.


99-99: Updated queryBatchMessagesPages call to remove accessToken parameter.

The call to queryBatchMessagesPages no longer passes an accessToken, relying on the function to extract it from the Gmail client internally.


117-117: Function signature updated to remove accessToken parameter.

The findReceiptSubjects helper function now only requires the Gmail client instance, simplified from the previous interface that required an explicit access token.


119-119: Updated queryBatchMessagesPages call to remove accessToken parameter.

The call to queryBatchMessagesPages has been updated to no longer pass an accessToken, consistent with the centralized token management approach.

apps/web/utils/actions/assess.ts (1)

66-68: What if the user has fewer than 20 sent e‑mails?

getSentMessages(gmail, 20) may return an empty array for new accounts. Verify that
aiAnalyzeWritingStyle handles emails: [] gracefully or add a guard:

if (sentMessages.length === 0) {
  return { error: "Not enough data to analyse writing style" };
}
apps/web/utils/ai/knowledge/writing-style.ts (4)

11-17: Good schema definition for writing style analysis.

The Zod schema is clear and well-structured, properly defining all necessary components of a writing style analysis.


25-28: Appropriate error handling for empty email input.

The early return with null when no emails are provided prevents unnecessary AI calls and provides clear logging.


30-58: Comprehensive system prompt for writing style analysis.

The system prompt is detailed and provides clear instructions for analyzing email communication patterns. It covers all aspects defined in the schema.


60-77: Well-structured email formatting with proper truncation.

The prompt construction properly formats emails with XML tags, truncates content to a reasonable length (1000 chars), and removes excessive whitespace. The optional user info inclusion is also handled elegantly.

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

28-30: Good model relationship update between Account and EmailAccount.

The relationship is properly defined with appropriate fields and constraints.


105-105: Appropriate one-to-many relationship from User to EmailAccount.

This change enables a user to have multiple email accounts, supporting the new feature.


111-127: Well-designed EmailAccount model for storing writing style data.

The new EmailAccount model is well structured with:

  • Appropriate fields for tracking creation and updates
  • A unique constraint on the email field
  • Proper relationships to User and Account models
  • The optional writingStyle field to store analysis results

The commented fields for future expansion are also helpful documentation.

apps/web/utils/ai/group/create-group.ts (5)

35-36: Improved function signature by removing the access token parameter.

The refactoring to remove the explicit access token parameter simplifies the API and centralizes token management.


41-41: Appropriate update to queryBatchMessages call.

This change correctly removes the access token parameter from the function call, relying on the internal token retrieval implemented in the queryBatchMessages function.


97-97: Simplified tool initialization in aiGenerateGroupItems.

The removal of the access token parameter from the listEmailsTool call aligns with the broader refactoring effort.


126-126: Updated verifyGroupItems call with simplified parameters.

The call to verifyGroupItems properly reflects the updated function signature without the access token.


168-168: Consistent update to listEmailsTool call in verifyGroupItems.

This change maintains consistency with the updated tool initialization pattern across the codebase.

Comment on lines +84 to +89
style.notableTraits.length
? `Notable Traits: ${formatBulletList(style.notableTraits)}`
: null,
style.examples.length
? `Examples: ${formatBulletList(style.examples)}`
: null,
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

style.notableTraits / style.examples may be undefined – runtime crash

aiAnalyzeWritingStyle can legitimately omit these arrays.
Calling .length directly will throw TypeError: Cannot read properties of undefined.

-      style.notableTraits.length
-        ? `Notable Traits: ${formatBulletList(style.notableTraits)}`
+      (style.notableTraits?.length ?? 0) > 0
+        ? `Notable Traits: ${formatBulletList(style.notableTraits!)}`
         : null,
-      style.examples.length
-        ? `Examples: ${formatBulletList(style.examples)}`
+      (style.examples?.length ?? 0) > 0
+        ? `Examples: ${formatBulletList(style.examples!)}`
         : null,
📝 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
style.notableTraits.length
? `Notable Traits: ${formatBulletList(style.notableTraits)}`
: null,
style.examples.length
? `Examples: ${formatBulletList(style.examples)}`
: null,
(style.notableTraits?.length ?? 0) > 0
? `Notable Traits: ${formatBulletList(style.notableTraits!)}`
: null,
(style.examples?.length ?? 0) > 0
? `Examples: ${formatBulletList(style.examples!)}`
: null,

Comment on lines +77 to +78
if (!style) return;

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

Early return breaks the contract with the action middleware

When style is falsy the function returns undefined, but withActionInstrumentation
expects { success | error | skipped }. Returning undefined will bubble up as
an unhandled error in the caller.

-    if (!style) return;
+    if (!style) return { error: "Unable to analyse writing style" };
📝 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
if (!style) return;
if (!style) return { error: "Unable to analyse writing style" };

Comment on lines +81 to +92
const result = await chatCompletionObject({
userAi: user,
system,
prompt,
schema,
userEmail: user.email,
usageLabel: "Writing Style Analysis",
});

logger.trace("Output", { result });

return result.object;
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 completion failures.

The function doesn't handle potential errors from the chatCompletionObject call. If the AI service fails, this could result in unhandled exceptions.

- const result = await chatCompletionObject({
+ try {
+   const result = await chatCompletionObject({
     userAi: user,
     system,
     prompt,
     schema,
     userEmail: user.email,
     usageLabel: "Writing Style Analysis",
   });
+   
+   logger.trace("Output", { result });
+   
+   return result.object;
+ } catch (error) {
+   logger.error("Error analyzing writing style", { error });
+   return null;
+ }
-
- logger.trace("Output", { result });
-
- return result.object;
📝 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 result = await chatCompletionObject({
userAi: user,
system,
prompt,
schema,
userEmail: user.email,
usageLabel: "Writing Style Analysis",
});
logger.trace("Output", { result });
return result.object;
try {
const result = await chatCompletionObject({
userAi: user,
system,
prompt,
schema,
userEmail: user.email,
usageLabel: "Writing Style Analysis",
});
logger.trace("Output", { result });
return result.object;
} catch (error) {
logger.error("Error analyzing writing style", { error });
return null;
}

@elie222 elie222 merged commit c2148a5 into main Apr 17, 2025
4 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Aug 13, 2025
@elie222 elie222 deleted the writing-style branch December 18, 2025 23:09
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