Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThis 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 ( Changes
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
Possibly related PRs
Poem
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
apps/web/__tests__/ai-create-group.test.tsOops! 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. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by apps/web/__tests__/ai/reply/draft-with-knowledge.test.tsOops! 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. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by apps/web/__tests__/ai-example-matches.test.tsOops! 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. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by
Tip ⚡💬 Agentic Chat (Pro Plan, General Availability)
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
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 variableThe
accessTokenvariable 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 variableThe
accessTokenvariable 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 formattingThe
formatBulletListfunction 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 styleThis 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: LimitwritingStylelength to avoid token over‑runs
writingStylePromptmay 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 withstringifyEmail(…, 3000).apps/web/utils/actions/assess.ts (1)
91-92: Skip DB write when nothing meaningful was producedIf every element was filtered out,
writingStylebecomes 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 enginesPostgreSQL allows multiple
NULLs, soUNIQUE ("emailAccountId")is safe,
but other engines (e.g. MySQL) treatNULLas a value, causing the migration
to fail when several rows haveNULL.
If cross‑DB compatibility is required, use a partial index or addWHERE "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
📒 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
getAccessTokenFromClientis 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
getMessagesfunction, 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
queryBatchMessagesfunction that no longer requires an explicit access token parameter.
271-277: Good utility function addition for the writing style feature.This new
getSentMessagesfunction 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
tofield optional in theEmailForLLMtype 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
beforeEachimport keeps the code clean.
27-27: Tests correctly updated for new parameter.Tests have been properly updated to include the new
writingStyleparameter in theaiDraftWithKnowledgefunction 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 clarityRemoving the
accessTokenparameter from theaiGenerateGroupItemsfunction 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 clarityRemoving the
accessTokenparameter from theaiFindExampleMatchesfunction 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 functionalityAdding
getWritingStyleimport alongside the existinggetAiUserkeeps related user preferences together and follows the single responsibility principle.
178-179: Well-placed writing style retrievalExcellent 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 aiDraftWithKnowledgeThe 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 handlingGood 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 contextAdding the
tofield 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 callRemoving 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 callThe 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
listEmailsToolfunction 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
queryBatchMessagesfunction, which now extracts the access token directly from the Gmail client instance.
102-102: Tool instantiation updated to match new function signature.The
listEmailsToolinstantiation 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
aiAnalyzeWritingStylefunction, 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
getEmailClientshas 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
getEmailClientsfunction 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
queryBatchMessagesno 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
findReceiptsfunction 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
findReceiptSendersandfindReceiptSubjectshave 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
findReceiptSendershelper 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
queryBatchMessagesPagesno 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
findReceiptSubjectshelper 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
queryBatchMessagesPageshas 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
aiAnalyzeWritingStylehandlesemails: []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.
| style.notableTraits.length | ||
| ? `Notable Traits: ${formatBulletList(style.notableTraits)}` | ||
| : null, | ||
| style.examples.length | ||
| ? `Examples: ${formatBulletList(style.examples)}` | ||
| : null, |
There was a problem hiding this comment.
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.
| 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, |
| if (!style) return; | ||
|
|
There was a problem hiding this comment.
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.
| if (!style) return; | |
| if (!style) return { error: "Unable to analyse writing style" }; |
| const result = await chatCompletionObject({ | ||
| userAi: user, | ||
| system, | ||
| prompt, | ||
| schema, | ||
| userEmail: user.email, | ||
| usageLabel: "Writing Style Analysis", | ||
| }); | ||
|
|
||
| logger.trace("Output", { result }); | ||
|
|
||
| return result.object; |
There was a problem hiding this comment.
🛠️ 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.
| 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; | |
| } |
Summary by CodeRabbit
New Features
Improvements
Database
EmailAccounttable to store email addresses and associated writing styles, with updated relations to user and account records.Bug Fixes
Tests