Skip to content

Comments

feat: Cross-Context Awareness - Meeting info in email drafts#1149

Merged
elie222 merged 7 commits intoelie222:mainfrom
rsnodgrass:feature/cross-context-awareness
Jan 1, 2026
Merged

feat: Cross-Context Awareness - Meeting info in email drafts#1149
elie222 merged 7 commits intoelie222:mainfrom
rsnodgrass:feature/cross-context-awareness

Conversation

@rsnodgrass
Copy link
Contributor

@rsnodgrass rsnodgrass commented Dec 31, 2025

Summary

@elie222 This is a feature suggestion, feel free to delete or incorporate.

When drafting email replies, the AI now considers upcoming meetings scheduled with the recipient. This enables natural references like:

  • "Looking forward to our call on Thursday"
  • "We can discuss this further in our upcoming meeting"

Changes

  • New file: apps/web/utils/meeting-briefs/recipient-context.ts

    • getUpcomingMeetingContext() - fetches meetings with a recipient from the next 7 days
    • formatMeetingContextForPrompt() - formats meeting data for AI consumption
  • Modified: apps/web/utils/ai/reply/draft-with-knowledge.ts

    • Added meetingContext parameter to include upcoming meetings in prompts
  • Modified: apps/web/utils/reply-tracker/generate-draft.ts

    • Integrated meeting context fetching into the draft generation pipeline

How it works

  1. When generating a draft reply, the system queries the user's calendar for events within the next 7 days
  2. Events are filtered to those that include the email sender as an attendee
  3. This context is formatted and passed to the AI when drafting the reply
  4. The AI can naturally reference upcoming meetings when relevant

Test plan

  • Verify calendar provider fetchEventsWithAttendee returns correct events
  • Test with sender who has an upcoming meeting
  • Test with sender who has no upcoming meetings
  • Confirm draft quality with meeting context included

Note

Introduces upcoming meeting context into AI email drafting.

  • New utils/meeting-briefs/recipient-context.ts: getUpcomingMeetingContext (fetch next 7 days, max 3, by recipient attendee) and formatMeetingContextForPrompt for prompt-ready text
  • Update utils/reply-tracker/generate-draft.ts: fetch upcoming meetings in parallel with other context and pass formatted meetingContext to drafting
  • Update utils/ai/reply/draft-with-knowledge.ts: add meetingContext param and inject into composed user prompt

Written by Cursor Bugbot for commit 4d940a4. Configure here.

Summary by CodeRabbit

  • New Features

    • AI-generated email drafts now include formatted upcoming/past meeting context (recipient-aware, privacy-filtered) for more relevant reply suggestions.
    • Draft generation uses meeting context and timezone-aware formatting when composing suggestions.
    • Improved email address parsing and validation to better extract addresses from headers and freeform strings.
  • Tests

    • Comprehensive tests added for email-address parsing and extraction logic.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 31, 2025

Warning

Rate limit exceeded

@elie222 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 9 minutes and 42 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between e67cb26 and 0f066e6.

📒 Files selected for processing (2)
  • apps/web/utils/meeting-briefs/recipient-context.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Adds recipient meeting-context collection and formatting, email-address extraction utilities, and threads a formatted meetingContext through draft generation into the AI prompt via extended function signatures.

Changes

Cohort / File(s) Summary
Meeting Context Utilities
apps/web/utils/meeting-briefs/recipient-context.ts
New module: exports MeetingContext, getMeetingContext/getUpcomingMeetingContext, and formatMeetingContextForPrompt. Aggregates calendar events across providers, applies privacy filtering, truncates descriptions, sorts and limits results, and formats a prompt-ready recent/upcoming block.
AI Draft Signature Extensions
apps/web/utils/ai/reply/draft-with-knowledge.ts
Extended getUserPrompt(...) and aiDraftWithKnowledge(...) signatures to accept `meetingContext: string
Draft Generation Integration
apps/web/utils/reply-tracker/generate-draft.ts
Added imports for meeting utilities and email parsing; fetches getMeetingContext(...) in parallel, formats it with formatMeetingContextForPrompt(...), and passes meetingContext into aiDraftWithKnowledge(...).
Email Utilities & Tests
apps/web/utils/email.ts
apps/web/utils/email.test.ts
Added extractEmailAddresses(header: string); improved extractEmailAddress(...) with trimming, bracket extraction, fallback pattern scanning, and isValidEmail(...). Tests expanded to cover new parsing behaviors and edge cases.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Draft Flow
    participant GenDraft as generate-draft.ts
    participant EmailUtil as email.ts
    participant CalContext as recipient-context.ts
    participant Calendar as Calendar Providers
    participant AI as aiDraftWithKnowledge

    Client->>GenDraft: generateDraftContent({ emailAccount, lastMessage, ... })
    GenDraft->>EmailUtil: extractEmailAddresses(lastMessage.headers.To/CC)
    par Parallel data fetch
        GenDraft->>CalContext: getMeetingContext({ emailAccountId, recipientEmail, additionalRecipients, logger })
        CalContext->>Calendar: fetch events (past & upcoming)
        Calendar-->>CalContext: events[]
        CalContext-->>GenDraft: MeetingContext[]
    and Other context fetch
        GenDraft->>GenDraft: gather other prompt context (history, contacts, etc.)
    end
    GenDraft->>CalContext: formatMeetingContextForPrompt(meetings, timezone)
    GenDraft->>AI: aiDraftWithKnowledge({ ..., meetingContext, ... })
    AI-->>GenDraft: Generated draft
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • anakarentorosserrano-star
  • baz-reviewer
  • johnlowe399-blip

Poem

🐇 I hopped through calendars with care,

Collected meetings here and there.
Now drafts remember time and place,
So messages fit the meeting space. ✨📅

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: introducing calendar/meeting context into AI-generated email drafts for cross-context awareness.

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel
Copy link

vercel bot commented Dec 31, 2025

@rsnodgrass is attempting to deploy a commit to the Inbox Zero OSS Program Team on Vercel.

A member of the Team first needs to authorize it.

@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Dec 31, 2025

Include meeting context in LLM email draft prompts via apps/web/utils/ai/reply/draft-with-knowledge.getUserPrompt and apps/web/utils/reply-tracker/generate-draft.generateDraftContent to support Cross-Context Awareness - Meeting info in email drafts

Add meeting-context retrieval and formatting, thread it through draft generation, and update prompt construction; introduce recipient meeting context utilities; add tests; note that apps/web/utils/email.ts currently contains syntax errors in extractEmailAddresses.

📍Where to Start

Start with the meeting context flow in generateDraftContent in apps/web/utils/reply-tracker/generate-draft.ts, then follow how meetingContext is formatted in apps/web/utils/meeting-briefs/recipient-context.ts and passed into getUserPrompt in apps/web/utils/ai/reply/draft-with-knowledge.ts.


Macroscope summarized 0f066e6.

When drafting email replies, the AI now considers upcoming meetings
scheduled with the recipient. This allows for natural references like
"Looking forward to our call on Thursday" or "We can discuss this
further in our upcoming meeting."

Changes:
- Add recipient-context.ts to fetch upcoming meetings with a recipient
- Extend aiDraftWithKnowledge to accept meetingContext parameter
- Integrate meeting context fetching in generate-draft.ts

The feature queries the user's calendar for events within the next 7
days that include the email sender as an attendee, then formats this
context for the AI to use when drafting replies.
@rsnodgrass rsnodgrass force-pushed the feature/cross-context-awareness branch from 5ee2465 to 4d940a4 Compare December 31, 2025 14:46
@rsnodgrass
Copy link
Contributor Author

@elie222 I had some extra Claude Code credits expiring December 31 and wanted to donate them to the project by implementing these features as proof of concepts. Feel free to use, modify, or delete/throw out as you see fit!

Why Cross-Context Awareness is a great addition:

This feature bridges the gap between calendar and email - two tools users constantly context-switch between. When replying to someone you have a meeting scheduled with, the AI can naturally reference it ("Looking forward to discussing this on Thursday" or "Let's save the details for our upcoming call").

This creates more personalized, contextually-aware replies that feel human rather than generic. It's the kind of small touch that makes users think "wow, this tool really gets me" - similar to how a great assistant would naturally mention an upcoming meeting when drafting a response.

The implementation is lightweight (queries calendar for next 7 days, max 3 meetings) and integrates cleanly with the existing draft generation pipeline.

@elie222 elie222 marked this pull request as ready for review December 31, 2025 14:52
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 3 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/web/utils/meeting-briefs/recipient-context.ts">

<violation number="1" location="apps/web/utils/meeting-briefs/recipient-context.ts:90">
P2: Date/time formatting uses server timezone instead of user timezone. This could cause the AI to reference incorrect meeting times (e.g., &quot;our call at 3 PM&quot; when the user sees 6 PM). Consider passing the user&#39;s timezone preference via the `timeZone` option, or use a relative format (e.g., &quot;later this week&quot;) to avoid specific time references.</violation>
</file>

<file name="apps/web/utils/reply-tracker/generate-draft.ts">

<violation number="1" location="apps/web/utils/reply-tracker/generate-draft.ts:167">
P1: The `headers.from` value may contain a display name (e.g., &quot;John Doe &lt;john@example.com&gt;&quot;) but is passed directly without extraction. Use `extractEmailAddress()` to extract the actual email address, consistent with the rest of the codebase.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

- Pass logger as function parameter instead of file-level creation
- Use extractEmailAddress() to properly extract email from headers.from
- Use formatInUserTimezone() with user's timezone for meeting dates
@rsnodgrass
Copy link
Contributor Author

Fixed all review feedback:

  1. Logger pattern - Removed file-level logger creation. getUpcomingMeetingContext now accepts logger: Logger as a parameter.

  2. Email extraction - Now using extractEmailAddress(lastMessage.headers.from) to properly handle "John Doe john@example.com" format.

  3. Timezone - Using formatInUserTimezone() from @/utils/date with emailAccount.timezone instead of server timezone.

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

🧹 Nitpick comments (1)
apps/web/utils/meeting-briefs/recipient-context.ts (1)

98-102: Consider escaping special characters in event titles.

If an event title contains double quotes (e.g., Review "Q4 Budget" draft), the current formatting could produce awkward output like - "Review "Q4 Budget" draft" on Friday.... This is a minor edge case that won't break functionality but could slightly confuse the LLM.

🔎 Optional fix to escape quotes in titles
-      let details = `- "${meeting.eventTitle}" on ${dateTime}`;
+      const safeTitle = meeting.eventTitle.replace(/"/g, '\\"');
+      let details = `- "${safeTitle}" on ${dateTime}`;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56454e2 and 88a8c48.

📒 Files selected for processing (3)
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
🧰 Additional context used
📓 Path-based instructions (15)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/security.mdc)

**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma's select option. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. All findUnique/findFirst calls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
All findMany queries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g., emailAccount: { id: emailAccountId }) to validate ownership

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
**/{utils,helpers,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)

Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use @/ path aliases for imports from project root
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
apps/web/**/*.{example,ts,json}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Add environment variables to .env.example, env.ts, and turbo.json

Files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
apps/web/{utils/ai,utils/llms,__tests__}/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/llm.mdc)

LLM-related code must be organized in specific directories: apps/web/utils/ai/ for main implementations, apps/web/utils/llms/ for core utilities and configurations, and apps/web/__tests__/ for LLM-specific tests

Files:

  • apps/web/utils/ai/reply/draft-with-knowledge.ts
apps/web/utils/ai/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/llm.mdc)

apps/web/utils/ai/**/*.ts: LLM feature functions must import from zod for schema validation, use createScopedLogger from @/utils/logger, chatCompletionObject and createGenerateObject from @/utils/llms, and import EmailAccountWithAI type from @/utils/llms/types
LLM feature functions must follow a standard structure: accept options with inputData and emailAccount parameters, implement input validation with early returns, define separate system and user prompts, create a Zod schema for response validation, and use createGenerateObject to execute the LLM call
System prompts must define the LLM's role and task specifications
User prompts must contain the actual data and context, and should be kept separate from system prompts
Always define a Zod schema for LLM response validation and make schemas as specific as possible to guide the LLM output
Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages
Implement early returns for invalid LLM inputs, use proper error types and logging, implement fallbacks for AI failures, and add retry logic for transient failures using withRetry
Use XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions
Use TypeScript types for all LLM function parameters and return values, and define clear interfaces for complex input/output structures
Keep related AI functions in the same file or directory, extract common patterns into utility functions, and document complex AI logic with clear comments

Files:

  • apps/web/utils/ai/reply/draft-with-knowledge.ts
🧠 Learnings (18)
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Access context (userId, emailAccountId, etc.) via the `ctx` object parameter in the `.action()` handler

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Pass the logger through the request/function chain instead of creating new logger instances at each level

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{utils,helpers,lib}/**/*.{ts,tsx} : Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/*.{ts,tsx} : Avoid using .with() for global/file-level loggers; only use .with() within specific functions for context enrichment

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{scripts,tests,__tests__}/**/*.{ts,tsx} : Use createScopedLogger only for code that doesn't run within a middleware chain, such as standalone scripts or tests

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/*.action.{ts,tsx} : Use actionClient context to receive logger automatically in server actions, accessing it via ctx.logger

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must import from `zod` for schema validation, use `createScopedLogger` from `@/utils/logger`, `chatCompletionObject` and `createGenerateObject` from `@/utils/llms`, and import `EmailAccountWithAI` type from `@/utils/llms/types`

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{app,pages}/**/{route,+page}.{ts,tsx} : Enrich logger context within route handlers using logger.with() to add request-specific fields like messageId

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : User prompts must contain the actual data and context, and should be kept separate from system prompts

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls

Applied to files:

  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls

Applied to files:

  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helpers `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for mocking emails, accounts, and rules

Applied to files:

  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers

Applied to files:

  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`

Applied to files:

  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : System prompts must define the LLM's role and task specifications

Applied to files:

  • apps/web/utils/ai/reply/draft-with-knowledge.ts
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Use `actionClient` when both authenticated user context and a specific emailAccountId are needed, with emailAccountId bound when calling from the client

Applied to files:

  • apps/web/utils/ai/reply/draft-with-knowledge.ts
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`

Applied to files:

  • apps/web/utils/ai/reply/draft-with-knowledge.ts
🧬 Code graph analysis (2)
apps/web/utils/meeting-briefs/recipient-context.ts (3)
apps/web/utils/logger.ts (1)
  • Logger (6-6)
apps/web/utils/calendar/event-provider.ts (1)
  • createCalendarEventProviders (11-74)
apps/web/utils/date.ts (1)
  • formatInUserTimezone (122-143)
apps/web/utils/reply-tracker/generate-draft.ts (2)
apps/web/utils/meeting-briefs/recipient-context.ts (2)
  • getUpcomingMeetingContext (21-77)
  • formatMeetingContextForPrompt (82-113)
apps/web/utils/email.ts (1)
  • extractEmailAddress (19-52)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🔇 Additional comments (8)
apps/web/utils/reply-tracker/generate-draft.ts (2)

166-171: LGTM! Meeting context integration follows established patterns.

The implementation correctly:

  • Uses extractEmailAddress() to parse the sender email from headers (addressing prior feedback)
  • Passes logger as a parameter per project conventions
  • Fetches meeting context in parallel with other context operations for efficiency

199-214: Good integration of meeting context into the draft flow.

The timezone is properly passed to formatMeetingContextForPrompt, and the meetingContext is threaded through to aiDraftWithKnowledge consistently with other context types (knowledge base, email history, calendar availability, etc.).

apps/web/utils/ai/reply/draft-with-knowledge.ts (3)

41-51: Correct extension of the user prompt signature.

The meetingContext parameter is properly typed as string | null and positioned consistently with other optional context parameters.


149-159: Meeting context properly integrated into prompt construction.

The upcomingMeetingsContext is added to the template in the same section as other external context types. The empty string fallback (|| "") ensures clean prompt composition when no meetings are found.


186-222: LGTM! aiDraftWithKnowledge correctly threads meeting context through.

The function signature and implementation properly accept and pass meetingContext to getUserPrompt, maintaining consistency with how other context types are handled.

apps/web/utils/meeting-briefs/recipient-context.ts (3)

1-8: LGTM! Clean module setup with sensible defaults.

The constants UPCOMING_DAYS = 7 and MAX_MEETINGS = 3 are reasonable defaults for cross-context awareness. The imports are appropriate and no file-level logger is created (addressing prior feedback).


21-77: Well-structured meeting context fetcher with proper error handling.

Good implementation details:

  • Logger is passed as a parameter per project conventions
  • Graceful degradation: per-provider errors are caught and logged without failing the entire operation
  • Events are sorted and limited after aggregation to get the soonest meetings across all providers
  • Outer try/catch ensures failures don't propagate up to break draft generation

82-113: Meeting context formatting correctly uses user timezone.

The formatInUserTimezone utility properly handles timezone conversion (addressing prior feedback about server vs. user timezone). The XML-like <upcoming_meetings> tags follow the project's established prompt structuring patterns.

- Add recent past meetings (14 days lookback) in addition to upcoming (7 days)
- Include meeting descriptions (truncated to 500 chars) for richer context
- Increase max meetings per category from 3 to 5
- Add privacy-preserving filtering for CC replies:
  Only include meetings where ALL recipients were attendees
  Prevents leaking private calendar info to CC'd recipients
- Rename getUpcomingMeetingContext to getMeetingContext (deprecated alias kept)
- Add extractEmailAddresses helper for parsing header lists
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

🧹 Nitpick comments (1)
apps/web/utils/meeting-briefs/recipient-context.ts (1)

82-104: Consider: maxResults applied per-provider, not total.

When multiple calendar providers exist (e.g., Google + Microsoft), each provider fetches up to MAX_MEETINGS_PER_CATEGORY events, potentially returning more meetings than intended before the final slice() on lines 128-135 trims them. This is likely acceptable since the final slice enforces the limit, but the over-fetching could be optimized if performance becomes a concern.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88a8c48 and 354ca4c.

📒 Files selected for processing (3)
  • apps/web/utils/email.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
🧰 Additional context used
📓 Path-based instructions (13)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/security.mdc)

**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma's select option. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. All findUnique/findFirst calls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
All findMany queries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g., emailAccount: { id: emailAccountId }) to validate ownership

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/{utils,helpers,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)

Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use @/ path aliases for imports from project root
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
apps/web/**/*.{example,ts,json}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Add environment variables to .env.example, env.ts, and turbo.json

Files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
🧠 Learnings (17)
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to apps/web/utils/gmail/**/*.{ts,tsx} : Keep Gmail provider-specific implementation details isolated within the apps/web/utils/gmail/ directory

Applied to files:

  • apps/web/utils/email.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls

Applied to files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must import from `zod` for schema validation, use `createScopedLogger` from `@/utils/logger`, `chatCompletionObject` and `createGenerateObject` from `@/utils/llms`, and import `EmailAccountWithAI` type from `@/utils/llms/types`

Applied to files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls

Applied to files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-11-25T14:40:00.833Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-25T14:40:00.833Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helpers `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for mocking emails, accounts, and rules

Applied to files:

  • apps/web/utils/email.ts
  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must follow a standard structure: accept options with `inputData` and `emailAccount` parameters, implement input validation with early returns, define separate system and user prompts, create a Zod schema for response validation, and use `createGenerateObject` to execute the LLM call

Applied to files:

  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers

Applied to files:

  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-11-25T14:39:23.326Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:23.326Z
Learning: Applies to app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account (reading/writing emails, rules, schedules, etc.) - provides `emailAccountId`, `userId`, and `email` in `request.auth`

Applied to files:

  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-11-25T14:39:27.909Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/security.mdc:0-0
Timestamp: 2025-11-25T14:39:27.909Z
Learning: Applies to **/app/api/**/*.ts : Use `withEmailAccount` middleware for operations scoped to a specific email account, including reading/writing emails, rules, schedules, or any operation using `emailAccountId`

Applied to files:

  • apps/web/utils/reply-tracker/generate-draft.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Pass the logger through the request/function chain instead of creating new logger instances at each level

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{utils,helpers,lib}/**/*.{ts,tsx} : Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/*.{ts,tsx} : Avoid using .with() for global/file-level loggers; only use .with() within specific functions for context enrichment

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{scripts,tests,__tests__}/**/*.{ts,tsx} : Use createScopedLogger only for code that doesn't run within a middleware chain, such as standalone scripts or tests

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/*.action.{ts,tsx} : Use actionClient context to receive logger automatically in server actions, accessing it via ctx.logger

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{app,pages}/**/{route,+page}.{ts,tsx} : Enrich logger context within route handlers using logger.with() to add request-specific fields like messageId

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : User prompts must contain the actual data and context, and should be kept separate from system prompts

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
🧬 Code graph analysis (1)
apps/web/utils/meeting-briefs/recipient-context.ts (3)
apps/web/utils/logger.ts (1)
  • Logger (6-6)
apps/web/utils/calendar/event-provider.ts (1)
  • createCalendarEventProviders (11-74)
apps/web/utils/date.ts (1)
  • formatInUserTimezone (122-143)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🔇 Additional comments (14)
apps/web/utils/email.ts (3)

18-29: Well-structured email header parsing.

The regex pattern correctly handles commas inside quoted display names, preventing incorrect splits on names like "Doe, John" <john@example.com>. The delegation to extractEmailAddress and filtering of empty results is clean.


31-65: Robust multi-step email extraction logic.

The layered approach (bracket extraction → whole string validation → pattern scanning) handles various header formats gracefully. Each candidate is validated with isValidEmail before returning, preventing invalid addresses from slipping through.


67-69: Clean validation helper.

Correctly reuses the existing zod schema and keeps the helper private to this module.

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

166-178: Good parallel fetching and privacy-aware recipient filtering.

The meeting context is fetched concurrently with other context data. The privacy filtering correctly:

  1. Extracts the sender email using extractEmailAddress
  2. Extracts all To/CC recipients using extractEmailAddresses
  3. Filters out the user's own email to avoid self-matching
  4. Passes additional recipients for the privacy filter in getMeetingContext

This addresses the previously flagged issue about email extraction from headers.


207-210: Correct timezone handling for meeting context.

The user's timezone from emailAccount.timezone is properly passed to format meeting times in the user's local timezone, addressing the previously flagged server timezone issue.


212-222: Clean integration with draft generation.

The meetingContext is seamlessly integrated into the existing draft generation flow, following the established pattern for context parameters like calendarAvailability and mcpContext.

apps/web/utils/meeting-briefs/recipient-context.ts (8)

1-11: Well-organized imports and constants.

Clean separation of concerns with date-fns for date manipulation, calendar providers for event fetching, and the shared formatInUserTimezone utility for consistent timezone handling.


24-32: Efficient privacy filter implementation.

Uses a Set for O(1) attendee lookups and correctly normalizes emails to lowercase for case-insensitive comparison.


106-135: Privacy filtering and sorting logic is correct.

The conditional filtering only applies when additional recipients (CC) exist, preserving all meetings for direct replies while preventing calendar information leakage to CC recipients who weren't invited to those meetings.


137-156: Clean mapping and graceful error handling.

The transformation to MeetingContext is straightforward, and the top-level error handler ensures calendar failures don't break the draft generation flow.


158-161: Good deprecation pattern.

The alias with @deprecated JSDoc allows for backward compatibility while signaling that callers should migrate to getMeetingContext.


163-169: LGTM!

Simple truncation with ellipsis for long descriptions.


171-190: User timezone correctly applied.

The formatInUserTimezone utility is used with the user's timezone preference, ensuring meeting times display correctly relative to the user's location. This addresses the previously flagged server timezone issue.


195-233: Well-designed prompt formatting.

The structured output with <recent_meetings> and <upcoming_meetings> sections provides clear context for the AI. The instructional text guides natural usage without being overly prescriptive, and the null return for empty meetings prevents unnecessary prompt bloat.

@vercel
Copy link

vercel bot commented Jan 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
inbox-zero Ready Ready Preview Jan 1, 2026 10:55am

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

🧹 Nitpick comments (1)
apps/web/utils/meeting-briefs/recipient-context.ts (1)

24-32: Consider moving helper functions to the bottom of the file.

The helper functions allRecipientsAreAttendees, truncateDescription, and formatMeeting are placed throughout the file. Per coding guidelines, helper functions should be added to the bottom of files, not the top or middle.

📝 Suggested organization

Move these helper functions after the main exported functions:

+export async function getMeetingContext({ ... }): Promise<MeetingContext[]> {
+  // ... main function
+}
+
+export function formatMeetingContextForPrompt(
+  meetings: MeetingContext[],
+  timezone?: string | null,
+): string | null {
+  // ... main function
+}
+
+// Helper functions
 function allRecipientsAreAttendees(
   event: CalendarEvent,
   requiredEmails: string[],
 ): boolean {
   // ...
 }
+
+function truncateDescription(
+  description: string | undefined,
+): string | undefined {
+  // ...
+}
+
+function formatMeeting(
+  meeting: MeetingContext,
+  timezone?: string | null,
+): string {
+  // ...
+}

As per coding guidelines: "Add helper functions to the bottom of files, not the top"

Also applies to: 158-185

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 354ca4c and e67cb26.

📒 Files selected for processing (2)
  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/data-fetching.mdc)

**/*.{ts,tsx}: For API GET requests to server, use the swr package
Use result?.serverError with toastError from @/components/Toast for error handling in async operations

**/*.{ts,tsx}: Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls
Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls
Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

**/*.{ts,tsx}: For early access feature flags, create hooks using the naming convention use[FeatureName]Enabled that return a boolean from useFeatureFlagEnabled("flag-key")
For A/B test variant flags, create hooks using the naming convention use[FeatureName]Variant that define variant types, use useFeatureFlagVariantKey() with type casting, and provide a default "control" fallback
Use kebab-case for PostHog feature flag keys (e.g., inbox-cleaner, pricing-options-2)
Always define types for A/B test variant flags (e.g., type PricingVariant = "control" | "variant-a" | "variant-b") and provide type safety through type casting

**/*.{ts,tsx}: Don't use primitive type aliases or misleading types
Don't use empty type parameters in type aliases and interfaces
Don't use this and super in static contexts
Don't use any or unknown as type constraints
Don't use the TypeScript directive @ts-ignore
Don't use TypeScript enums
Don't export imported variables
Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions
Don't use TypeScript namespaces
Don't use non-null assertions with the ! postfix operator
Don't use parameter properties in class constructors
Don't use user-defined types
Use as const instead of literal types and type annotations
Use either T[] or Array<T> consistently
Initialize each enum member value explicitly
Use export type for types
Use `impo...

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/prisma-enum-imports.mdc)

Always import Prisma enums from @/generated/prisma/enums instead of @/generated/prisma/client to avoid Next.js bundling errors in client components

Import Prisma using the project's centralized utility: import prisma from '@/utils/prisma'

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

Import specific lodash functions rather than entire lodash library to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

apps/web/**/*.{ts,tsx}: Use TypeScript with strict null checks
Do not export types/interfaces that are only used within the same file. Export later if needed

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/security.mdc)

**/*.ts: ALL database queries MUST be scoped to the authenticated user/account by including user/account filtering in WHERE clauses to prevent unauthorized data access
Always validate that resources belong to the authenticated user before performing operations, using ownership checks in WHERE clauses or relationships
Always validate all input parameters for type, format, and length before using them in database queries
Use SafeError for error responses to prevent information disclosure. Generic error messages should not reveal internal IDs, logic, or resource ownership details
Only return necessary fields in API responses using Prisma's select option. Never expose sensitive data such as password hashes, private keys, or system flags
Prevent Insecure Direct Object References (IDOR) by validating resource ownership before operations. All findUnique/findFirst calls MUST include ownership filters
Prevent mass assignment vulnerabilities by explicitly whitelisting allowed fields in update operations instead of accepting all user-provided data
Prevent privilege escalation by never allowing users to modify system fields, ownership fields, or admin-only attributes through user input
All findMany queries MUST be scoped to the user's data by including appropriate WHERE filters to prevent returning data from other users
Use Prisma relationships for access control by leveraging nested where clauses (e.g., emailAccount: { id: emailAccountId }) to validate ownership

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

**/*.{tsx,ts}: Use Shadcn UI and Tailwind for components and styling
Use next/image package for images
For API GET requests to server, use the swr package with hooks like useSWR to fetch data
For text inputs, use the Input component with registerProps for form integration and error handling

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.{tsx,ts,css}

📄 CodeRabbit inference engine (.cursor/rules/ui-components.mdc)

Implement responsive design with Tailwind CSS using a mobile-first approach

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{js,jsx,ts,tsx}: Don't use accessKey attribute on any HTML element
Don't set aria-hidden="true" on focusable elements
Don't add ARIA roles, states, and properties to elements that don't support them
Don't use distracting elements like <marquee> or <blink>
Only use the scope prop on <th> elements
Don't assign non-interactive ARIA roles to interactive HTML elements
Make sure label elements have text content and are associated with an input
Don't assign interactive ARIA roles to non-interactive HTML elements
Don't assign tabIndex to non-interactive HTML elements
Don't use positive integers for tabIndex property
Don't include "image", "picture", or "photo" in img alt prop
Don't use explicit role property that's the same as the implicit/default role
Make static elements with click handlers use a valid role attribute
Always include a title element for SVG elements
Give all elements requiring alt text meaningful information for screen readers
Make sure anchors have content that's accessible to screen readers
Assign tabIndex to non-interactive HTML elements with aria-activedescendant
Include all required ARIA attributes for elements with ARIA roles
Make sure ARIA properties are valid for the element's supported roles
Always include a type attribute for button elements
Make elements with interactive roles and handlers focusable
Give heading elements content that's accessible to screen readers (not hidden with aria-hidden)
Always include a lang attribute on the html element
Always include a title attribute for iframe elements
Accompany onClick with at least one of: onKeyUp, onKeyDown, or onKeyPress
Accompany onMouseOver/onMouseOut with onFocus/onBlur
Include caption tracks for audio and video elements
Use semantic elements instead of role attributes in JSX
Make sure all anchors are valid and navigable
Ensure all ARIA properties (aria-*) are valid
Use valid, non-abstract ARIA roles for elements with ARIA roles
Use valid AR...

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

**/*.{test,spec}.{js,jsx,ts,tsx}: Don't nest describe() blocks too deeply in test files
Don't use callbacks in asynchronous tests and hooks
Don't have duplicate hooks in describe blocks
Don't use export or module.exports in test files
Don't use focused tests
Make sure the assertion function, like expect, is placed inside an it() function call
Don't use disabled tests

Files:

  • apps/web/utils/email.test.ts
!(pages/_document).{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/ultracite.mdc)

Don't use the next/head module in pages/_document.js on Next.js projects

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/utilities.mdc)

**/*.{js,ts,jsx,tsx}: Use lodash utilities for common operations (arrays, objects, strings)
Import specific lodash functions to minimize bundle size (e.g., import groupBy from 'lodash/groupBy')

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/{utils,helpers,lib}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/logging.mdc)

Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
apps/web/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

apps/web/**/*.{ts,tsx,js,jsx}: Use @/ path aliases for imports from project root
Prefer self-documenting code over comments; use descriptive variable and function names instead of explaining intent with comments
Add helper functions to the bottom of files, not the top
All imports go at the top of files, no mid-file dynamic imports

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Format code with Prettier

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
apps/web/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Co-locate test files next to source files (e.g., utils/example.test.ts). Only E2E and AI tests go in __tests__/

Files:

  • apps/web/utils/email.test.ts
apps/web/**/*.{example,ts,json}

📄 CodeRabbit inference engine (apps/web/CLAUDE.md)

Add environment variables to .env.example, env.ts, and turbo.json

Files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
**/*.test.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/notes.mdc)

Co-locate test files next to source files (e.g., utils/example.test.ts). Only E2E and AI tests go in __tests__/

Files:

  • apps/web/utils/email.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)

**/*.test.{ts,tsx}: Use vitest as the testing framework
Colocate test files next to the tested file with .test.ts or .test.tsx naming convention (e.g., dir/format.ts and dir/format.test.ts)
Mock server-only using vi.mock("server-only", () => ({}))
Mock Prisma using vi.mock("@/utils/prisma") and the provided mock from @/utils/__mocks__/prisma
Use test helper functions getEmail, getEmailAccount, and getRule from @/__tests__/helpers for creating mock data
Clear all mocks between tests using beforeEach(() => { vi.clearAllMocks(); })
Use descriptive test names that clearly indicate what is being tested
Do not mock the Logger in tests

Files:

  • apps/web/utils/email.test.ts
🧠 Learnings (19)
📚 Learning: 2026-01-01T10:42:29.767Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2026-01-01T10:42:29.767Z
Learning: Applies to **/*.test.{ts,tsx} : Use test helper functions `getEmail`, `getEmailAccount`, and `getRule` from `@/__tests__/helpers` for creating mock data

Applied to files:

  • apps/web/utils/email.test.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Prefer using existing helpers from `@/__tests__/helpers.ts` (`getEmailAccount`, `getEmail`, `getRule`, `getMockMessage`, `getMockExecutedRule`) instead of creating custom test data helpers

Applied to files:

  • apps/web/utils/email.test.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to apps/web/utils/gmail/**/*.{ts,tsx} : Keep Gmail provider-specific implementation details isolated within the apps/web/utils/gmail/ directory

Applied to files:

  • apps/web/utils/email.test.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail thread operations from @/utils/gmail/thread.ts instead of direct API calls

Applied to files:

  • apps/web/utils/email.test.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : LLM feature functions must import from `zod` for schema validation, use `createScopedLogger` from `@/utils/logger`, `chatCompletionObject` and `createGenerateObject` from `@/utils/llms`, and import `EmailAccountWithAI` type from `@/utils/llms/types`

Applied to files:

  • apps/web/utils/email.test.ts
  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail message operations (get, list, batch, etc.) from @/utils/gmail/message.ts instead of direct API calls

Applied to files:

  • apps/web/utils/email.test.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to apps/web/utils/gmail/**/*.{ts,tsx} : Always use wrapper functions from @/utils/gmail/ for Gmail API operations instead of direct provider API calls

Applied to files:

  • apps/web/utils/email.test.ts
📚 Learning: 2025-11-25T14:37:22.660Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/gmail-api.mdc:0-0
Timestamp: 2025-11-25T14:37:22.660Z
Learning: Applies to **/*.{ts,tsx} : Use wrapper functions for Gmail label operations from @/utils/gmail/label.ts instead of direct API calls

Applied to files:

  • apps/web/utils/email.test.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Use vitest imports (`describe`, `expect`, `test`, `vi`, `beforeEach`) in LLM test files

Applied to files:

  • apps/web/utils/email.test.ts
📚 Learning: 2025-11-25T14:37:56.430Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm-test.mdc:0-0
Timestamp: 2025-11-25T14:37:56.430Z
Learning: Applies to apps/web/__tests__/**/*.test.ts : Place all LLM-related tests in `apps/web/__tests__/` directory

Applied to files:

  • apps/web/utils/email.test.ts
📚 Learning: 2025-11-25T14:39:49.448Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/server-actions.mdc:0-0
Timestamp: 2025-11-25T14:39:49.448Z
Learning: Applies to apps/web/utils/actions/*.ts : Access context (userId, emailAccountId, etc.) via the `ctx` object parameter in the `.action()` handler

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Pass the logger through the request/function chain instead of creating new logger instances at each level

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{utils,helpers,lib}/**/*.{ts,tsx} : Logger should be passed as a parameter to helper functions instead of creating their own logger instances

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/*.{ts,tsx} : Avoid using .with() for global/file-level loggers; only use .with() within specific functions for context enrichment

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : Use descriptive scoped loggers for each LLM feature, log inputs and outputs with appropriate log levels, and include relevant context in log messages

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{scripts,tests,__tests__}/**/*.{ts,tsx} : Use createScopedLogger only for code that doesn't run within a middleware chain, such as standalone scripts or tests

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/*.action.{ts,tsx} : Use actionClient context to receive logger automatically in server actions, accessing it via ctx.logger

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-12-18T16:37:47.972Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/logging.mdc:0-0
Timestamp: 2025-12-18T16:37:47.972Z
Learning: Applies to **/{app,pages}/**/{route,+page}.{ts,tsx} : Enrich logger context within route handlers using logger.with() to add request-specific fields like messageId

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
📚 Learning: 2025-11-25T14:38:07.606Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/llm.mdc:0-0
Timestamp: 2025-11-25T14:38:07.606Z
Learning: Applies to apps/web/utils/ai/**/*.ts : User prompts must contain the actual data and context, and should be kept separate from system prompts

Applied to files:

  • apps/web/utils/meeting-briefs/recipient-context.ts
🧬 Code graph analysis (2)
apps/web/utils/email.test.ts (1)
apps/web/utils/email.ts (1)
  • extractEmailAddresses (20-29)
apps/web/utils/meeting-briefs/recipient-context.ts (3)
apps/web/utils/logger.ts (1)
  • Logger (6-6)
apps/web/utils/calendar/event-provider.ts (1)
  • createCalendarEventProviders (11-74)
apps/web/utils/date.ts (1)
  • formatInUserTimezone (122-143)
🔇 Additional comments (3)
apps/web/utils/email.test.ts (1)

37-153: Excellent test coverage for the new extractEmailAddresses function!

The test suite is comprehensive and well-structured, covering:

  • Basic functionality (empty input, single/multiple emails)
  • Various email formats (with/without names, angle brackets)
  • Edge cases (whitespace handling, comma variations, empty segments)
  • Special characters (plus addressing, hyphens, underscores, numbers)
  • Error handling (invalid email filtering)
  • Real-world scenarios (complex headers with quoted names containing commas)

The test names are descriptive and follow best practices. This level of coverage is appropriate for a utility function that will be used across the codebase.

apps/web/utils/meeting-briefs/recipient-context.ts (2)

44-156: Excellent implementation with robust error handling and privacy considerations.

The getMeetingContext function is well-structured with:

  • Proper logger parameter pattern (as per learnings)
  • Graceful degradation (continues if individual providers fail, returns empty array on overall failure)
  • Privacy-conscious filtering that prevents leaking meeting info to CC recipients who weren't invited
  • Appropriate sorting (most recent past first, soonest upcoming first)
  • Reasonable limits to prevent overwhelming AI prompts

The logic flow is clean and easy to follow.


190-228: Well-crafted prompt formatting with clear AI guidance.

The function properly:

  • Returns null for empty input (allows caller to handle gracefully)
  • Separates past and upcoming meetings with clear XML-like tags
  • Uses timezone-aware formatting via formatInUserTimezone
  • Provides helpful, natural-sounding instructions to the AI on how to reference meetings

The prompt engineering approach is sound and should produce contextually relevant draft suggestions.

@elie222 elie222 merged commit 7673651 into elie222:main Jan 1, 2026
7 of 8 checks passed
@elie222
Copy link
Owner

elie222 commented Jan 1, 2026

thanks!

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.

2 participants