Conversation
WalkthroughThis change adds automatic draft email generation to the thread processing workflow for Google provider threads. It introduces new utility functions to analyze email intent, determine draft necessity, and generate drafts. The workflow now conditionally creates and stores draft replies based on thread content, with improved database connection management and error handling. Changes
Sequence Diagram(s)sequenceDiagram
participant Workflow as runThreadWorkflow
participant DB as Database
participant Utils as thread-workflow-utils
participant Agent as Agent (createDraft)
participant Logger as Logger
Workflow->>DB: Fetch thread and connection
alt Thread has messages and is Google provider
Workflow->>Utils: shouldGenerateDraft(thread, connection)
alt Draft should be generated
Workflow->>Utils: generateAutomaticDraft(connectionId, thread, connection)
Utils->>Utils: analyzeEmailIntent(latest message)
Utils->>Agent: composeEmail(...) (via composeEmail route)
Agent-->>Utils: Draft content
Utils-->>Workflow: Draft content
Workflow->>Agent: createDraft(draft content)
Agent-->>Workflow: Draft ID
Workflow->>DB: Store draft ID in summary
Workflow->>Logger: Log draft creation success
else Draft not needed
Workflow->>Logger: Log skipping draft generation
end
end
Workflow->>DB: Close connection
Workflow->>Logger: Log workflow completion
Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
✨ 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:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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 (
|
57934ca to
48e4783
Compare
48e4783 to
7022bc1
Compare
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
There was a problem hiding this comment.
cubic found 1 issue across 2 files. Review it in cubic.dev
React with 👍 or 👎 to teach cubic. Tag @cubic-dev-ai to give specific feedback.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
apps/server/src/pipelines.effect.ts (1)
493-493: Remove duplicate variable declarationThe
latestMessagevariable is already defined on line 462. This redeclaration shadows the existing variable.- const latestMessage = thread.messages[thread.messages.length - 1];
🧹 Nitpick comments (2)
apps/server/src/thread-workflow-utils/index.ts (2)
7-42: Consider making automated email patterns configurableThe function correctly identifies automated emails, but the hardcoded patterns could be moved to a configuration object for better maintainability and customization.
Example refactor:
const AUTOMATED_EMAIL_PATTERNS = { senderPatterns: ['no-reply', 'noreply', 'donotreply', 'do-not-reply'], subjectPatterns: ['newsletter', 'unsubscribe', 'notification'], bodyPatterns: ['do not reply', 'this is an automated'] }; // Then use: if (AUTOMATED_EMAIL_PATTERNS.senderPatterns.some(pattern => latestMessage.sender?.email?.toLowerCase().includes(pattern)) || // ... rest of the checks
94-99: Include additional context in composeEmail callConsider passing additional parameters to
composeEmailfor better draft generation context:const draftContent = await composeEmail({ prompt, threadMessages, username: foundConnection.name || foundConnection.email || 'User', connectionId, + to: latestMessage.sender ? [{ email: latestMessage.sender.email, name: latestMessage.sender.name }] : [], + cc: latestMessage.cc || [], + emailSubject: latestMessage.subject || '', });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/server/src/pipelines.effect.ts(3 hunks)apps/server/src/thread-workflow-utils/index.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: retrogtx
PR: Mail-0/Zero#1734
File: apps/server/src/lib/driver/google.ts:211-221
Timestamp: 2025-07-15T06:46:33.321Z
Learning: In apps/server/src/lib/driver/google.ts, the normalization of "draft" to "drafts" in the count() method is necessary because the navigation item in apps/mail/config/navigation.ts has id: 'drafts' (plural) while the Google API returns "draft" (singular). The nav-main.tsx component matches stats by comparing stat.label with item.id, so the backend must return "drafts" for the draft counter badge to appear in the sidebar.
apps/server/src/pipelines.effect.ts (1)
Learnt from: retrogtx
PR: Mail-0/Zero#1734
File: apps/server/src/lib/driver/google.ts:211-221
Timestamp: 2025-07-15T06:46:33.321Z
Learning: In apps/server/src/lib/driver/google.ts, the normalization of "draft" to "drafts" in the count() method is necessary because the navigation item in apps/mail/config/navigation.ts has id: 'drafts' (plural) while the Google API returns "draft" (singular). The nav-main.tsx component matches stats by comparing stat.label with item.id, so the backend must return "drafts" for the draft counter badge to appear in the sidebar.
apps/server/src/thread-workflow-utils/index.ts (1)
Learnt from: retrogtx
PR: Mail-0/Zero#1734
File: apps/server/src/lib/driver/google.ts:211-221
Timestamp: 2025-07-15T06:46:33.321Z
Learning: In apps/server/src/lib/driver/google.ts, the normalization of "draft" to "drafts" in the count() method is necessary because the navigation item in apps/mail/config/navigation.ts has id: 'drafts' (plural) while the Google API returns "draft" (singular). The nav-main.tsx component matches stats by comparing stat.label with item.id, so the backend must return "drafts" for the draft counter badge to appear in the sidebar.
🧬 Code Graph Analysis (1)
apps/server/src/thread-workflow-utils/index.ts (4)
apps/server/src/lib/driver/types.ts (1)
IGetThreadResponse(6-12)apps/server/src/db/schema.ts (1)
connection(118-142)apps/server/src/trpc/routes/ai/compose.ts (1)
composeEmail(32-112)apps/server/src/pipelines.effect.ts (1)
log(38-44)
🔇 Additional comments (5)
apps/server/src/pipelines.effect.ts (4)
19-24: LGTM!The new imports for thread workflow utilities are properly organized and follow the existing import structure.
38-38: Appropriate export for shared utilityExporting the log function is necessary for the new
thread-workflow-utilsmodule to maintain consistent logging across the codebase.
539-569: Well-implemented draft reference storageThe upsert operation correctly stores the draft reference in the summary table, handling conflicts appropriately and maintaining audit timestamps.
928-935: Good database connection lifecycle managementMoving the connection close to the end of the workflow ensures the connection remains available throughout the draft generation process. The error handling with
Effect.orElseprovides graceful failure recovery.apps/server/src/thread-workflow-utils/index.ts (1)
44-58: Well-designed intent analysisThe function efficiently analyzes email intent using appropriate regex patterns. Combining content and subject for meeting/urgent detection is a smart approach that improves accuracy.
7022bc1 to
9c691b5
Compare
| import { defaultLabels, EPrompts, EProviders, type ParsedMessage, type Sender } from './types'; | ||
| import { getZeroAgent } from './lib/server-utils'; | ||
| import { type gmail_v1 } from '@googleapis/gmail'; | ||
| import { connection, summary } from './db/schema'; |
There was a problem hiding this comment.
Remove the unused 'summary' import to fix the linting warning. Change to: import { connection } from './db/schema';
Spotted by Diamond (based on CI logs)
Is this helpful? React 👍 or 👎 to let us know.
| return 'Thread has no messages'; | ||
| } | ||
|
|
||
| const autoDraftId = yield* Effect.tryPromise({ |
There was a problem hiding this comment.
Rename 'autoDraftId' to '_autoDraftId' to indicate it's intentionally unused and fix the linting warning. Change to: const _autoDraftId = yield* Effect.tryPromise({
Spotted by Diamond (based on CI logs)
Is this helpful? React 👍 or 👎 to let us know.
Merge activity
|

Automatic Email Draft Generation Feature
This PR implements an automatic email draft generation feature that creates AI-powered responses when new emails are received. The system analyzes incoming emails, determines their intent, and generates contextually appropriate draft replies.
The feature includes:
Summary by CodeRabbit
New Features
Bug Fixes