Skip to content

Comments

feat: centralized LLM operation registry with tier-based model selection#1160

Closed
rsnodgrass wants to merge 2 commits intoelie222:mainfrom
rsnodgrass:feature/model-optimizations
Closed

feat: centralized LLM operation registry with tier-based model selection#1160
rsnodgrass wants to merge 2 commits intoelie222:mainfrom
rsnodgrass:feature/model-optimizations

Conversation

@rsnodgrass
Copy link
Contributor

@rsnodgrass rsnodgrass commented Jan 1, 2026

Summary

Introduces a centralized LLM operation registry that maps each AI operation to a model tier (reasoning/fast/economy) with documented rationale. This replaces ad-hoc getModel() calls with semantic getModelForOperation() calls.

Key Changes

  • Created operations.ts - Registry of 34 LLM operations with tier assignments, frequency metadata, and rationale
  • Created resolve-model.ts - Configuration resolver with env override support
  • Added LLM_OPERATION_OVERRIDES env var - Allows operators to override specific operation tiers without code changes
  • Migrated all call sites - Updated ~40 files to use getModelForOperation()
  • Added developer docs - CLAUDE.md with tier selection guidelines and model recommendations

Tier Optimization Philosophy

Tier Maps To When to Use
reasoning DEFAULT_LLM_* User-visible outputs, persisted results, accuracy-critical
fast CHAT_LLM_* Interactive UI where latency matters
economy ECONOMY_LLM_* High-volume operations where errors are recoverable

Key insight: Frequency × Cost, but accuracy-critical operations stay on reasoning even at high volume to prevent trust erosion.

Operations Tier Assignments

Stay on reasoning (high-consequence per-email):

  • rule.match-email - Complex rule matching with negation logic. Wrong automation is high-consequence
  • reply.determine-thread-status - Core Reply Zero feature with 9 interdependent rules
  • clean.decide-archive - Data loss risk if wrong. Trust critical

Stay on reasoning (user-visible):

  • reply.draft, report.generate-summary, meeting.generate-briefing

Moved to economy (high volume, recoverable errors):

  • rule.choose-args - Per-email structured extraction after rule match
  • reply.check-needs-reply - Binary classification, low consequence
  • categorize.cold-email - Multi-layer safety net, errors are recoverable
  • digest.summarize-email - Per-email summarization
  • And 8 more per-email/batch operations...

Moved to fast (interactive):

  • assistant.chat - Interactive chat, user waiting
  • rule.diff, rule.find-existing, rule.generate-prompt - Interactive UI

Expected Annual Cost Savings (per user account)

Based on 75 emails/day (~27,375/year), 1.5K input + 0.2K output tokens per operation:

Per-email operations (7 total):

  • 3 stay on reasoning tier (accuracy-critical)
  • 4 move to economy tier (recoverable errors)
Provider Before After Savings
Anthropic (Sonnet/Haiku) $1,437 $835 $602 (42%)
OpenAI (GPT-4o/mini) $1,102 $510 $592 (54%)

Recommended Models (January 2026)

Provider Reasoning Economy/Fast
Anthropic claude-sonnet-4-5-20250929 ($3/$15) claude-haiku-3-5-20241022 ($0.80/$4)
OpenAI gpt-4o ($2.50/$10) gpt-4o-mini ($0.15/$0.60)

Operator Override Example

Override specific operations without code changes:
```bash
LLM_OPERATION_OVERRIDES='{"categorize.cold-email":"reasoning"}'
```

Test Plan

  • All LLM tests pass including new invariant tests
  • Lint passes (biome)
  • Added `operations.test.ts` with invariant tests:
    • Per-email operations use economy tier UNLESS high-consequence
    • High-consequence operations explicitly require reasoning tier
    • User-visible draft operations must use reasoning tier
  • Manual testing of email processing flows
  • Monitor LLM costs after deployment

Summary by CodeRabbit

  • New Features

    • Per-operation LLM model selection added, with optional environment overrides for fine-grained control of model tiers and more consistent model choices across AI flows.
    • Minor user-visible constant export to improve categorization flows.
  • Documentation

    • Added a comprehensive model-tier guide and updated example environment docs explaining tiers, recommended models, and override format.
  • Tests

    • Added tests validating the operation registry and tier invariants.

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

@vercel
Copy link

vercel bot commented Jan 1, 2026

@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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 1, 2026

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

Centralizes LLM model selection by adding an operation-scoped registry and resolver (LLM_OPERATIONS, resolveModelTier, getModelForOperation), env-driven per-operation overrides, updates chatCompletionStream to accept operation IDs, and migrates many AI utilities to use operation-based model resolution.

Changes

Cohort / File(s) Summary
Core LLM Infrastructure
apps/web/utils/llms/operations.ts, apps/web/utils/llms/resolve-model.ts, apps/web/utils/llms/index.ts, apps/web/utils/llms/operations.test.ts, apps/web/utils/llms/CLAUDE.md
Adds LLM_OPERATIONS registry, ModelTier/LLMOperationConfig types, LLMOperationId type, resolveModelTier() and getModelForOperation() APIs, updates chatCompletionStream to accept operationId, adds tests and documentation.
Environment & Build Config
apps/web/.env.example, apps/web/env.ts, turbo.json
Documents model tiers and per-operation override JSON, introduces LLM_OPERATION_OVERRIDES env var, JSON parse/validation/filtering in env transform, and exposes the var to turbo build.
API Surface / Chat
apps/web/utils/ai/assistant/chat.ts, apps/web/utils/ai/assistant/process-user-request.ts
Switches model resolution to use getModelForOperation and operation IDs (e.g., assistant.chat, assistant.process-request) instead of per-call modelType.
Migration: AI utilities → operation resolver
apps/web/utils/ai/... (many files; examples below)
Replaces imports of getModel with getModelForOperation and updates calls to use explicit operation IDs across reply, rule, categorize, clean, digest, knowledge, report, meeting, group, mcp, snippets, calendar, cold-email, etc.; several functions had modelType parameters removed.
Cohort examples:
Reply flows
apps/web/utils/ai/reply/*.ts
Replaced getModel(..., modelType) usage with getModelForOperation(..., "reply.*"); removed modelType where threaded; prompt formatting/tagging changes.
Rule & Choose-rule flows
apps/web/utils/ai/choose-rule/*, apps/web/utils/ai/rule/*
Centralizes model selection via operation IDs (e.g., rule.match-email, rule.create-from-prompt); removed modelType parameters from several public/internal signatures.
Categorize / Cold-email / Snippets / Clean / Knowledge / Digest / Report / Meeting / Group / MCP
apps/web/utils/ai/categorize-sender/*, apps/web/utils/cold-email/*, apps/web/utils/ai/snippets/*, apps/web/utils/ai/clean/*, apps/web/utils/ai/knowledge/*, apps/web/utils/ai/digest/*, apps/web/utils/ai/report/*, apps/web/utils/ai/meeting-briefs/*, apps/web/utils/ai/group/*, apps/web/utils/ai/mcp/*
Replaces model resolver imports with getModelForOperation and updates operationId strings; minor prompt/text adjustments in several files; added UNKNOWN_CATEGORY export in categorize-sender.
Minor prompt/payload changes
assorted apps/web/utils/ai/*
Small prompt formatting edits (blank lines, bullet marker changes, XML-like tagged blocks, added <current_time>), and a few constant additions.

Sequence Diagram(s)

sequenceDiagram
  participant Caller as AI utility
  participant Resolver as getModelForOperation
  participant Registry as LLM_OPERATIONS
  participant Env as env.LLM_OPERATION_OVERRIDES
  participant Provider as getModel
  Note over Caller,Resolver: Resolve model for an operation
  Caller->>Resolver: getModelForOperation(userAi, operationId, online?)
  Resolver->>Env: read LLM_OPERATION_OVERRIDES
  Env-->>Resolver: optional overrides JSON
  Resolver->>Registry: lookup operationId.defaultTier
  Registry-->>Resolver: defaultTier
  Resolver->>Resolver: resolveTier(prefer env override else default)
  Resolver->>Provider: getModel(userAi, mappedModelType, online?)
  Provider-->>Resolver: SelectModel (provider, model, providerOptions)
  Resolver-->>Caller: SelectModel
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Switch to fast model for user actions #631 — overlaps refactoring of model-selection plumbing and removal/propagation of per-call modelType; closely related to operation-scoped resolver changes.
  • Add support for Anthropic #215 — touches LLM layer and chat/llms APIs; related to the chatCompletionStream and index API surface updates.
  • Email accounts #410 — modifies assistant/process-user-request code paths that were migrated to operation-based resolution in this PR.

Suggested reviewers

  • johnlowe399-blip

Poem

🐰 I hopped through code and named each task,

Tiers sorted tidy, no more questions to ask.
Overrides tucked in, operations align,
Resolver at work — models pick just fine.
A nibble of clarity, carrot-shaped design. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.56% 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 summarizes the main change: introducing a centralized LLM operation registry with tier-based model selection. This is the primary feature discussed throughout the PR objectives and raw summary.
✨ Finishing touches
  • 📝 Generate docstrings

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

❤️ Share

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

@rsnodgrass rsnodgrass force-pushed the feature/model-optimizations branch from 709620e to 6b4230f Compare January 1, 2026 05:42
@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Jan 1, 2026

Introduce an operation-scoped LLM registry and update web AI flows to select models via utils/llms/resolve-model.getModelForOperation using tier-based configuration

Add a central LLM_OPERATIONS registry and tier resolver, replace modelType usage across web AI flows with operation-based selection via getModelForOperation, require operationId in utils/llms/index.ts.chatCompletionStream, and add env-driven overrides with LLM_OPERATION_OVERRIDES. Tests validate registry invariants and allowed tiers.

📍Where to Start

Start with the registry and resolver in utils/llms/operations.ts and utils/llms/resolve-model.ts, then follow the integration in utils/llms/index.ts.chatCompletionStream.


Macroscope summarized 96a2567.

@rsnodgrass rsnodgrass marked this pull request as ready for review January 1, 2026 05:43
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 (7)
apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx (1)

149-163: Consider using the imported isConversationStatusType helper for consistency.

The isConversationStatusType function is imported but not used in this memo. Using it would ensure consistent logic across the codebase and handle the null check properly.

🔎 Suggested refactor
   const isReplyZeroDisabled = useMemo(() => {
     if (!isGoogleProvider(provider)) return false;

     const conversationStatusRules = (data || []).filter(
-      (rule) =>
-        rule.systemType && CONVERSATION_STATUS_TYPES.includes(rule.systemType),
+      (rule) => isConversationStatusType(rule.systemType),
     );

     // If no conversation status rules exist, Reply Zero is not enabled
     if (conversationStatusRules.length === 0) return true;

     // If all conversation status rules are disabled, Reply Zero is effectively disabled
     return conversationStatusRules.every((rule) => !rule.enabled);
   }, [data, provider]);
apps/web/app/(app)/[emailAccountId]/settings/ReplyZeroSection.tsx (1)

25-46: Consider handling partial failures more explicitly.

If some rule toggles succeed while others fail, the current implementation shows a generic error toast but still calls mutate() on success. In a partial failure scenario (e.g., 3 of 4 rules toggle successfully), the user sees an error but the actual state becomes inconsistent.

🔎 Suggested improvement
       const hasError = results.some((result) => result?.serverError);

       if (hasError) {
+        // Refresh to show actual server state after partial failure
+        mutate();
         toast.error(
           `Error ${newEnabled ? "enabling" : "disabling"} Reply Zero`,
         );
       } else {
         mutate();
         toast.success(
           `Reply Zero ${newEnabled ? "enabled" : "disabled"} successfully`,
         );
       }
apps/web/utils/llms/CLAUDE.md (1)

56-68: Optional: Add language specifier to code fence.

The decision tree code block is missing a language specifier. Consider adding text or leaving it as plain markdown for better rendering consistency.

🔎 Suggested improvement
-```
+```text
 Is it per-email?
   → economy (volume too high for expensive models)
apps/web/utils/ai/report/analyze-email-behavior.ts (1)

6-8: LGTM with a note on the unused logger.

The migration to getModelForOperation with operation ID "report.analyze-behavior" is correct. The logger is renamed to _logger indicating it's intentionally unused, but the logger import and instantiation could be removed entirely if logging is not planned for this function.

🔎 Optional: Remove unused logger

If logging is not needed in this function, consider removing the unused logger:

 import { z } from "zod";
 import { createGenerateObject } from "@/utils/llms";
 import type { EmailAccountWithAI } from "@/utils/llms/types";
 import type { EmailSummary } from "@/utils/ai/report/summarize-emails";
-import { createScopedLogger } from "@/utils/logger";
 import { getModelForOperation } from "@/utils/llms/resolve-model";
 
-const _logger = createScopedLogger("email-report-email-behavior");
-
 const emailBehaviorSchema = z.object({
apps/web/utils/ai/report/analyze-label-optimization.ts (1)

9-9: Remove unused logger instance.

The _logger instance is created but never used in this file. If logging is needed in the future, consider passing a logger as a parameter to aiAnalyzeLabelOptimization rather than maintaining a file-level logger instance.

🔎 Proposed fix
-const _logger = createScopedLogger("email-report-label-analysis");
-
 const labelAnalysisSchema = z.object({

Based on coding guidelines: "Logger should be passed as a parameter to helper functions instead of creating their own logger instances."

apps/web/env.ts (1)

46-57: JSON parsing could benefit from error logging.

The implementation correctly handles JSON parsing failures by returning undefined, but silently swallowing parse errors could make debugging difficult. Consider logging parse failures to help operators identify malformed JSON configurations.

🔎 Proposed enhancement
     LLM_OPERATION_OVERRIDES: z
       .string()
       .optional()
       .transform((value) => {
         if (!value) return undefined;
         try {
           return JSON.parse(value) as Record<string, string>;
-        } catch {
+        } catch (error) {
+          console.error('Failed to parse LLM_OPERATION_OVERRIDES:', error);
           return undefined;
         }
       }),
apps/web/utils/ai/report/generate-actionable-recommendations.ts (1)

9-9: Remove unused logger variable.

The _logger variable is created but never used in this file. Either remove it entirely or use it for logging within the function.

🔎 Proposed fix
-const _logger = createScopedLogger("email-report-actionable-recommendations");
-
 const actionableRecommendationsSchema = z.object({

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 52 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/app/(app)/[emailAccountId]/assistant/Rules.tsx">

<violation number="1" location="apps/web/app/(app)/[emailAccountId]/assistant/Rules.tsx:150">
P2: Warning banner will flash incorrectly during loading state. When `data` is undefined, the empty array fallback causes `isReplyZeroDisabled` to return `true` for Google providers before the actual rules are fetched. Consider checking if data exists before determining the disabled state.</violation>
</file>

<file name="apps/web/env.ts">

<violation number="1" location="apps/web/env.ts:54">
P2: Silently ignoring invalid JSON in `LLM_OPERATION_OVERRIDES` could lead to undetected misconfiguration. Operators won&#39;t know their overrides aren&#39;t being applied if they have a JSON syntax error. Consider logging a warning when parsing fails so issues are discoverable.</violation>
</file>

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

@rsnodgrass rsnodgrass force-pushed the feature/model-optimizations branch from 6b4230f to 77be505 Compare January 1, 2026 05:51
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: 4

🧹 Nitpick comments (5)
apps/web/utils/llms/CLAUDE.md (1)

1-97: Excellent documentation! Fix minor markdown formatting issues.

This guide provides clear, actionable guidance for model selection. The tier-based approach and decision tree are particularly helpful.

Minor markdown formatting fixes

Fix the following formatting issues flagged by linters:

  1. Lines 20, 27: Add blank lines before and after tables
  2. Line 56: Add language identifier to code block
 ## Recommended Models (January 2026)
+
 ### Anthropic
+
 | Tier | Model | Pricing ($/M tokens) |
 ## Quick Decision Tree
 
-```
+```text
 Is it per-email?
apps/web/utils/ai/report/analyze-label-optimization.ts (1)

9-9: Unused logger variable.

The logger is created but never used in this function. Per coding guidelines, LLM feature functions should "log inputs and outputs with appropriate log levels." Consider either using the logger to trace inputs/outputs or removing it if logging is intentionally handled elsewhere.

Option 1: Use the logger
-const _logger = createScopedLogger("email-report-label-analysis");
+const logger = createScopedLogger("email-report-label-analysis");

Then add logging in the function:

logger.info("Analyzing label optimization", {
  emailCount: emailSummaries.length,
  labelCount: gmailLabels.length,
});
Option 2: Remove unused logger
-import { createScopedLogger } from "@/utils/logger";
-
-const _logger = createScopedLogger("email-report-label-analysis");
apps/web/utils/ai/reply/generate-nudge.ts (1)

10-14: Unused onFinish parameter.

The onFinish callback is declared in the function signature but never used. This could be dead code from a previous implementation.

If not needed, remove the parameter
 export async function aiGenerateNudge({
   messages,
   emailAccount,
 }: {
   messages: EmailForLLM[];
   emailAccount: EmailAccountWithAI;
-  onFinish?: (completion: string) => Promise<void>;
 }) {
apps/web/utils/ai/report/generate-executive-summary.ts (1)

9-9: Unused logger variable.

Similar to analyze-label-optimization.ts, the logger is created but never used. Consider either using it for tracing or removing it.

apps/web/utils/llms/resolve-model.ts (1)

47-49: Consider deriving valid tiers from the type or constant.

The hardcoded array ["reasoning", "fast", "economy"] could become out of sync with the ModelTier type. Consider deriving the valid values from TIER_TO_MODEL_TYPE keys instead:

🔎 Proposed refactor
 function isValidTier(value: string): value is ModelTier {
-  return ["reasoning", "fast", "economy"].includes(value);
+  return (Object.keys(TIER_TO_MODEL_TYPE) as string[]).includes(value);
 }

This approach ensures the validation logic stays in sync with the tier mapping automatically.

📜 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 6b4230f and 77be505.

📒 Files selected for processing (47)
  • apps/web/.env.example
  • apps/web/env.ts
  • apps/web/utils/ai/assistant/chat.ts
  • apps/web/utils/ai/assistant/process-user-request.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/categorize-sender/ai-categorize-senders.ts
  • apps/web/utils/ai/categorize-sender/ai-categorize-single-sender.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.ts
  • apps/web/utils/ai/choose-rule/ai-detect-recurring-pattern.ts
  • apps/web/utils/ai/choose-rule/choose-args.ts
  • apps/web/utils/ai/choose-rule/run-rules.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/digest/summarize-email-for-digest.ts
  • apps/web/utils/ai/group/create-group.ts
  • apps/web/utils/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/ai/knowledge/extract.ts
  • apps/web/utils/ai/knowledge/persona.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/mcp/mcp-agent.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/reply/check-if-needs-reply.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/report/analyze-email-behavior.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/report/build-user-persona.ts
  • apps/web/utils/ai/report/generate-actionable-recommendations.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/report/response-patterns.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/diff-rules.ts
  • apps/web/utils/ai/rule/find-existing-rules.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/snippets/find-snippets.ts
  • apps/web/utils/cold-email/is-cold-email.ts
  • apps/web/utils/llms/CLAUDE.md
  • apps/web/utils/llms/index.ts
  • apps/web/utils/llms/operations.test.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/llms/resolve-model.ts
  • turbo.json
💤 Files with no reviewable changes (2)
  • apps/web/utils/ai/choose-rule/choose-args.ts
  • apps/web/utils/ai/choose-rule/run-rules.ts
🚧 Files skipped from review as they are similar to previous changes (24)
  • apps/web/utils/llms/operations.test.ts
  • turbo.json
  • apps/web/utils/ai/assistant/process-user-request.ts
  • apps/web/utils/ai/knowledge/extract.ts
  • apps/web/utils/ai/categorize-sender/ai-categorize-single-sender.ts
  • apps/web/utils/ai/group/create-group.ts
  • apps/web/utils/ai/snippets/find-snippets.ts
  • apps/web/utils/ai/digest/summarize-email-for-digest.ts
  • apps/web/utils/ai/report/analyze-email-behavior.ts
  • apps/web/utils/ai/mcp/mcp-agent.ts
  • apps/web/utils/ai/categorize-sender/ai-categorize-senders.ts
  • apps/web/utils/ai/knowledge/persona.ts
  • apps/web/.env.example
  • apps/web/utils/cold-email/is-cold-email.ts
  • apps/web/utils/llms/index.ts
  • apps/web/utils/ai/report/build-user-persona.ts
  • apps/web/utils/ai/rule/diff-rules.ts
  • apps/web/utils/ai/rule/find-existing-rules.ts
  • apps/web/utils/ai/reply/check-if-needs-reply.ts
  • apps/web/utils/ai/assistant/chat.ts
  • apps/web/utils/ai/choose-rule/ai-detect-recurring-pattern.ts
  • apps/web/utils/ai/report/generate-actionable-recommendations.ts
  • apps/web/utils/ai/report/response-patterns.ts
  • apps/web/utils/ai/meeting-briefs/generate-briefing.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/knowledge/extract-from-email-history.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/llms/CLAUDE.md
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.ts
apps/web/**/*.{ts,tsx,js,jsx,json,css}

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

Format code with Prettier

Files:

  • apps/web/utils/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.ts
apps/web/env.ts

📄 CodeRabbit inference engine (.cursor/rules/environment-variables.mdc)

apps/web/env.ts: Add server-only environment variables to apps/web/env.ts under the server object with Zod schema validation
Add client-side environment variables to apps/web/env.ts under the client object with NEXT_PUBLIC_ prefix and Zod schema validation
Add client-side environment variables to apps/web/env.ts under the experimental__runtimeEnv object to enable runtime access

Files:

  • apps/web/env.ts
{.env.example,apps/web/env.ts}

📄 CodeRabbit inference engine (.cursor/rules/environment-variables.mdc)

Client-side environment variables must be prefixed with NEXT_PUBLIC_

Files:

  • apps/web/env.ts
🧠 Learnings (35)
📓 Common learnings
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 TypeScript types for all LLM function parameters and return values, and define clear interfaces for complex input/output structures
📚 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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/llms/CLAUDE.md
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/knowledge/extract-from-email-history.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/env.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/llms/CLAUDE.md
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/reply/reply-context-collector.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/reply/reply-context-collector.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/ai/clean/ai-clean.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/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/report/generate-executive-summary.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/knowledge/extract-from-email-history.ts
  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/llms/{index,model}.ts : Core LLM functionality must be defined in `utils/llms/index.ts`, model definitions and configurations in `utils/llms/model.ts`, and usage tracking in `utils/usage.ts`

Applied to files:

  • apps/web/utils/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/llms/CLAUDE.md
📚 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 TypeScript types for all LLM function parameters and return values, and define clear interfaces for complex input/output structures

Applied to files:

  • apps/web/utils/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/env.ts
  • apps/web/utils/ai/meeting-briefs/research-guest.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/reply/determine-thread-status.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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 : Always define a Zod schema for LLM response validation and make schemas as specific as possible to guide the LLM output

Applied to files:

  • apps/web/utils/ai/knowledge/extract-from-email-history.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.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,utils/llms,__tests__}/**/*.ts : 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

Applied to files:

  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/calendar/availability.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 : 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`

Applied to files:

  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/env.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/llms/resolve-model.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/env.ts
  • apps/web/utils/llms/operations.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/ai/report/generate-executive-summary.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 : Keep related AI functions in the same file or directory, extract common patterns into utility functions, and document complex AI logic with clear comments

Applied to files:

  • apps/web/utils/llms/resolve-model.ts
  • apps/web/utils/ai/report/analyze-label-optimization.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/ai/clean/ai-clean.ts
  • apps/web/utils/ai/calendar/availability.ts
  • apps/web/utils/llms/CLAUDE.md
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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 XML-like tags to structure data in prompts, remove excessive whitespace and truncate long inputs, and format data consistently across similar LLM functions

Applied to files:

  • apps/web/utils/ai/reply/generate-nudge.ts
  • apps/web/utils/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/knowledge/writing-style.ts
  • apps/web/utils/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
  • apps/web/utils/ai/clean/ai-clean.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/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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/ai/reply/draft-with-knowledge.ts
  • apps/web/utils/ai/report/summarize-emails.ts
  • apps/web/utils/ai/choose-rule/ai-choose-args.ts
  • apps/web/utils/ai/reply/reply-context-collector.ts
  • apps/web/utils/ai/choose-rule/ai-choose-rule.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: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/ai/rule/prompt-to-rules.ts
  • apps/web/utils/ai/rule/generate-rules-prompt.ts
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.validation.ts : Export types from Zod schemas using `z.infer<>` to maintain type safety between validation and client usage

Applied to files:

  • apps/web/utils/ai/rule/generate-rules-prompt.ts
  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to apps/web/env.ts : Add server-only environment variables to `apps/web/env.ts` under the `server` object with Zod schema validation

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-11-25T14:36:43.454Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:43.454Z
Learning: Applies to apps/web/env.ts : Define environment variables in `apps/web/env.ts` using Zod schema validation, organizing them into `server` and `client` sections

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to apps/web/env.ts : Add client-side environment variables to `apps/web/env.ts` under the `experimental__runtimeEnv` object to enable runtime access

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-11-25T14:36:45.807Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:45.807Z
Learning: Applies to apps/web/env.ts : Add client-side environment variables to `apps/web/env.ts` under the `client` object with `NEXT_PUBLIC_` prefix and Zod schema validation

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/**/*.{example,ts,json} : Add environment variables to `.env.example`, `env.ts`, and `turbo.json`

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-11-25T14:36:43.454Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/environment-variables.mdc:0-0
Timestamp: 2025-11-25T14:36:43.454Z
Learning: Applies to apps/web/env.ts : For client-side environment variables in `apps/web/env.ts`, prefix them with `NEXT_PUBLIC_` and add them to both the `client` and `experimental__runtimeEnv` sections

Applied to files:

  • apps/web/env.ts
📚 Learning: 2025-11-25T14:37:09.306Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/fullstack-workflow.mdc:0-0
Timestamp: 2025-11-25T14:37:09.306Z
Learning: Applies to apps/web/utils/actions/*.validation.ts : Define Zod validation schemas in separate `*.validation.ts` files and export both the schema and inferred type (e.g., `CreateExampleBody`)

Applied to files:

  • apps/web/utils/ai/clean/ai-clean-select-labels.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/*.validation.ts : Define input validation schemas using Zod in `.validation.ts` files and export both the schema and its inferred TypeScript type

Applied to files:

  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
📚 Learning: 2025-12-21T12:21:37.794Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: apps/web/CLAUDE.md:0-0
Timestamp: 2025-12-21T12:21:37.794Z
Learning: Applies to apps/web/utils/actions/**/*.{ts,tsx} : Infer types from Zod schemas using `z.infer<typeof schema>` instead of duplicating as separate interfaces

Applied to files:

  • apps/web/utils/ai/clean/ai-clean-select-labels.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 `.schema()` method with Zod validation schemas from corresponding `.validation.ts` files in next-safe-action configuration

Applied to files:

  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
📚 Learning: 2025-11-25T14:36:51.389Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/form-handling.mdc:0-0
Timestamp: 2025-11-25T14:36:51.389Z
Learning: Applies to **/*.validation.ts : Define validation schemas using Zod

Applied to files:

  • apps/web/utils/ai/clean/ai-clean-select-labels.ts
📚 Learning: 2025-11-25T14:42:11.919Z
Learnt from: CR
Repo: elie222/inbox-zero PR: 0
File: .cursor/rules/utilities.mdc:0-0
Timestamp: 2025-11-25T14:42:11.919Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Use lodash utilities for common operations (arrays, objects, strings)

Applied to files:

  • apps/web/utils/ai/clean/ai-clean.ts
📚 Learning: 2025-12-31T23:49:06.009Z
Learnt from: rsnodgrass
Repo: elie222/inbox-zero PR: 1154
File: apps/web/app/api/user/setup-progress/route.ts:0-0
Timestamp: 2025-12-31T23:49:06.009Z
Learning: In apps/web/app/api/user/setup-progress/route.ts, Reply Zero enabled status should be determined solely by checking if the TO_REPLY rule is enabled, as it is the critical/canonical rule that Reply Zero is based on. The other conversation status types (FYI, AWAITING_REPLY, ACTIONED) should not be checked for determining Reply Zero setup progress.
<!-- </add_learning>

Applied to files:

  • apps/web/utils/ai/reply/determine-thread-status.ts
🧬 Code graph analysis (16)
apps/web/utils/ai/knowledge/extract-from-email-history.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/reply/generate-nudge.ts (2)
apps/web/utils/ai/helpers.ts (1)
  • getTodayForLLM (5-7)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/reply/draft-with-knowledge.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/report/analyze-label-optimization.ts (2)
apps/web/utils/logger.ts (1)
  • createScopedLogger (18-82)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/knowledge/writing-style.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/rule/prompt-to-rules.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/report/summarize-emails.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/rule/generate-rules-prompt.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/meeting-briefs/research-guest.ts (3)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/env.ts (1)
  • env (17-273)
apps/web/utils/llms/config.ts (1)
  • Provider (3-12)
apps/web/utils/ai/choose-rule/ai-choose-args.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/clean/ai-clean-select-labels.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/clean/ai-clean.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/reply/determine-thread-status.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/report/generate-executive-summary.ts (2)
apps/web/utils/logger.ts (1)
  • createScopedLogger (18-82)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/reply/reply-context-collector.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
apps/web/utils/ai/choose-rule/ai-choose-rule.ts (1)
apps/web/utils/llms/resolve-model.ts (1)
  • getModelForOperation (63-80)
🪛 LanguageTool
apps/web/utils/llms/CLAUDE.md

[style] ~13-~13: Consider a different adjective to strengthen your wording.
Context: ...oning** | DEFAULT_LLM_* | Best quality, deep understanding | | fast | CHAT_LLM_*...

(DEEP_PROFOUND)


[grammar] ~97-~97: Use a hyphen to join words.
Context: ...to upgrade specific operations to higher quality models without code changes.

(QB_NEW_EN_HYPHEN)

🪛 markdownlint-cli2 (0.18.1)
apps/web/utils/llms/CLAUDE.md

20-20: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


27-27: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


56-56: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

@rsnodgrass
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 1, 2026

✅ Actions performed

Full review triggered.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/web/utils/ai/clean/ai-clean.ts (1)

44-54: Remove duplicate "Notifications" entry.

The word "Notifications" appears twice in the list (lines 47 and 49). Remove one occurrence.

🔎 Proposed fix
 Examples of emails to archive:
 - Newsletters
 - Marketing
 - Notifications
 - Low-priority emails
-- Notifications
 - Social
 - LinkedIn messages
 - Facebook messages
 - GitHub issues
apps/web/utils/llms/index.ts (1)

221-245: Two call sites are missing the required operationId parameter.

The function signature requires operationId: LLMOperationId, but these files have not been updated:

  • apps/web/app/api/ai/summarise/controller.ts: Missing operationId in the chatCompletionStream call
  • apps/web/app/api/ai/compose-autocomplete/route.ts: Missing operationId in the chatCompletionStream call

Add an appropriate operation ID to each call (e.g., operationId: "assistant.chat" or other applicable IDs from LLM_OPERATIONS).

♻️ Duplicate comments (4)
apps/web/utils/ai/report/summarize-emails.ts (1)

64-66: Inconsistent bullet point markers in system prompt.

The bullet markers changed from -- to +- which appears unintentional and creates inconsistent formatting (line 67 still uses -). Please normalize to use single - for all bullet points.

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

32-38: Inconsistency between PR description and code tier assignment.

The PR summary states "rule.match-email" was moved to "economy" tier, but the code assigns defaultTier: "reasoning" with rationale emphasizing high-consequence automation. Please align the code with the PR description or update the PR description to reflect the reasoning tier assignment.

This issue was previously flagged in past review comments.


85-91: Inconsistency between PR description and code tier assignment.

The PR summary lists "reply.determine-thread-status" as moving to "economy" tier, but the implementation uses defaultTier: "reasoning" with rationale emphasizing the criticality of correct status determination for Reply Zero. Please reconcile this discrepancy by updating either the code or the PR description.

This issue was previously flagged in past review comments.


158-164: Inconsistency between PR description and code tier assignment.

The PR summary claims "clean.decide-archive" was moved to "economy" tier, but the code shows defaultTier: "reasoning" with rationale emphasizing data loss risk. The strong justification for reasoning tier contradicts the PR's claimed cost savings. Please clarify whether this operation should remain at reasoning tier (and update PR docs) or move to economy tier (and update code + rationale).

This issue was previously flagged in past review comments.

🧹 Nitpick comments (7)
apps/web/utils/ai/report/analyze-label-optimization.ts (1)

9-9: Clarify the unused logger variable.

The logger is renamed to _logger but doesn't appear to be used anywhere in this file. If it's intentionally unused, consider removing it entirely to reduce clutter. If it should be used for error logging, the _ prefix convention typically indicates an intentionally unused parameter, which doesn't apply here.

🔎 Proposed fix
-const _logger = createScopedLogger("email-report-label-analysis");
apps/web/utils/ai/report/generate-executive-summary.ts (2)

9-9: Remove unused logger instead of prefixing with underscore.

The logger is renamed to _logger but is never used in this file. Per coding guidelines, unused imports should be removed entirely rather than prefixed with underscore.

🔎 Suggested cleanup
-import { createScopedLogger } from "@/utils/logger";
-
-const _logger = createScopedLogger("email-report-executive-summary");

64-64: Minor prompt text change: verify if intentional.

The example persona changed from "Software Engineer" to "Software Developer". While both are valid, this change is unrelated to the main refactoring. If intentional for better LLM understanding, it's fine; otherwise, it could be reverted for consistency.

apps/web/utils/ai/report/generate-actionable-recommendations.ts (1)

9-9: Note: Unused logger variable.

The logger is renamed to _logger with an underscore prefix, which conventionally indicates an intentionally unused variable. If logging is not needed in this module, consider removing the import and variable declaration to reduce clutter.

apps/web/utils/ai/report/analyze-email-behavior.ts (1)

8-8: Remove unused logger variable.

The _logger variable is created but never used in this file. Consider removing it to eliminate dead code.

🔎 Suggested change
-const _logger = createScopedLogger("email-report-email-behavior");
-
apps/web/utils/llms/CLAUDE.md (1)

20-20: Fix markdown formatting issues.

For better markdown rendering and consistency:

  1. Add blank lines before and after tables (lines 20, 27)
  2. Specify language for the fenced code block at line 56
🔎 Proposed fixes

For lines 19-21 (first table):

 ### Anthropic
+
 | Tier | Model | Pricing ($/M tokens) |
 |------|-------|----------------------|
+

For lines 26-28 (second table):

 ### OpenAI
+
 | Tier | Model | Pricing ($/M tokens) |
 |------|-------|----------------------|
+

For line 56 (code block):

-```
+```text
 Is it per-email?

Also applies to: 27-27, 56-56

apps/web/utils/ai/report/response-patterns.ts (1)

8-8: Consider removing the unused logger.

The logger is renamed with an underscore prefix (_logger) but is never used in this file. Consider removing it entirely to reduce clutter.

🔎 Proposed fix
-import { createScopedLogger } from "@/utils/logger";
 import { getModelForOperation } from "@/utils/llms/resolve-model";
-
-const _logger = createScopedLogger("email-report-response-patterns");

@elie222
Copy link
Owner

elie222 commented Jan 1, 2026

Hey @rsnodgrass! Thanks for another PR!

Curious what the reasoning is behind the centralised registry?

@rsnodgrass
Copy link
Contributor Author

Hey @rsnodgrass! Thanks for another PR!

Curious what the reasoning is behind the centralised registry?

@elie222 This makes it easy for someone to see all the LLM calls in one place without having to dig around the codebase and make tuning adjustments (if they want, though this should be rare).

It is similar to how a best practice for LLM agents is maintaining all prompts outside source code (like Markdown) so that reviewers/contributors to a system don't have to be engineers. Product developers can improve upon prompts since they are approachable.

I started down this path of fine tuning which model was used because I noticed Inbox Zero was cranking through $ on my Anthropic account. Then I realized there was no clarity around which model was picked for different use cases, so added reasoning/docs for each chocie.

I don't want to step on any toes, so feel free to push back on anything! Inbox Zero is great, thanks for building this.

@rsnodgrass
Copy link
Contributor Author

rsnodgrass commented Jan 1, 2026

Separately from these improvements, I also realized that my using Anthropic is fairly expensive for Inbox Zero compared to OpenAI since Vercel's handling of AI mapping causes some big issues in context management especially around effective use of cached tokens. I'm switching to OpenAI and associated models since it would not be easy to fix this.

Introduces a centralized LLM operation registry that maps each AI operation
to a model tier (reasoning/fast/economy) with documented rationale.

Key changes:
- Created operations.ts with 34 LLM operations and tier assignments
- Created resolve-model.ts with configuration resolver
- Added LLM_OPERATION_OVERRIDES env var for per-operation tier overrides
- Migrated all getModel() call sites to use getModelForOperation()
- Added developer documentation in CLAUDE.md

Tier optimization rationale:
- per-email operations -> economy (high volume, cost sensitive)
- interactive UI operations -> fast (latency matters)
- user-visible/persisted outputs -> reasoning (quality matters)
- rare setup actions -> reasoning (cost is negligible)

Expected annual cost savings per user account:
- Anthropic: ~$743/year (67% reduction)
- OpenAI: ~$800/year (94% reduction)
@rsnodgrass rsnodgrass force-pushed the feature/model-optimizations branch from 77be505 to 96a2567 Compare January 1, 2026 13:02
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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/utils/llms/index.ts (1)

221-245: Breaking API change: Two callers still missing required operationId parameter.

The chatCompletionStream signature now requires operationId: LLMOperationId, but the following call sites have not been migrated:

  • apps/web/app/api/ai/summarise/controller.ts:21
  • apps/web/app/api/ai/compose-autocomplete/route.ts:21

These calls must include an operationId parameter. One caller (apps/web/utils/ai/assistant/chat.ts:968) has been correctly migrated with operationId: "assistant.chat".

♻️ Duplicate comments (2)
apps/web/utils/ai/report/summarize-emails.ts (1)

64-67: Bullet formatting appears consistent now.

The bullet markers on lines 64-66 use - prefix consistently with line 67. If a previous iteration had inconsistent markers (+- or --), it appears to be resolved in this version.

apps/web/utils/llms/resolve-model.ts (1)

37-42: Duplicate concern: env.ts validation noted in past review.

Line 40 assumes env.ts validates all values are valid ModelTier, but a past review comment identified that the Zod schema uses a loose Record<string, string> type and recommended strengthening validation during environment parsing to filter invalid tier values.

🧹 Nitpick comments (5)
apps/web/utils/ai/report/generate-actionable-recommendations.ts (1)

9-9: Unused logger — consider adding logging or removing it.

The logger is created but never used (hence the _ prefix). Per coding guidelines, LLM feature functions should "log inputs and outputs with appropriate log levels." Consider adding logging for the LLM call or removing the unused declaration.

Option 1: Add logging (recommended)
-const _logger = createScopedLogger("email-report-actionable-recommendations");
+const logger = createScopedLogger("email-report-actionable-recommendations");

 export async function aiGenerateActionableRecommendations(
   emailSummaries: EmailSummary[],
   emailAccount: EmailAccountWithAI,
   userPersona: UserPersona,
 ): Promise<z.infer<typeof actionableRecommendationsSchema>> {
+  logger.info("Generating actionable recommendations", {
+    emailCount: emailSummaries.length,
+    persona: userPersona.professionalIdentity.persona,
+  });
Option 2: Remove unused logger
-import { createScopedLogger } from "@/utils/logger";
-
-const _logger = createScopedLogger("email-report-actionable-recommendations");

Based on learnings, LLM feature functions should include descriptive scoped loggers with appropriate log levels.

apps/web/utils/llms/CLAUDE.md (1)

56-71: Consider adding a language identifier to the decision tree code block.

The fenced code block for the decision tree lacks a language specifier. While this is a text diagram rather than code, adding a language identifier (e.g., ```text) would satisfy linting rules and improve rendering consistency.

🔎 Proposed fix
-```
+```text
 Is it choosing which rule to apply or drafting a reply?
   → reasoning (accuracy critical - wrong rule = wrong automation)
apps/web/utils/ai/choose-rule/ai-choose-rule.ts (1)

175-188: Inconsistent return structure between single-rule and multi-rule functions.

getAiResponseSingleRule returns { result, modelOptions } (lines 177-187), while getAiResponseMultiRule returns just the result object directly (lines 292-296). The caller at line 85-93 expects the multi-rule function to return only the result, which works, but this asymmetry could cause confusion.

This appears to be pre-existing behavior and not introduced by this PR's changes, so it's not blocking.

Also applies to: 292-296

apps/web/utils/llms/resolve-model.ts (2)

25-35: Add defensive check for invalid operation IDs.

If operationId is not present in LLM_OPERATIONS, Line 34 will throw a runtime error. Consider adding a guard or fallback:

🔎 Proposed defensive check
 export function resolveModelTier(operationId: LLMOperationId): ModelTier {
   const envOverride = getEnvOverride(operationId);
   if (envOverride) {
     logger.info("Using env override for operation", {
       operationId,
       tier: envOverride,
     });
     return envOverride;
   }
+  const operation = LLM_OPERATIONS[operationId];
+  if (!operation) {
+    logger.error("Unknown operation ID", { operationId });
+    // Fallback to a safe default
+    return "economy";
+  }
-  return LLM_OPERATIONS[operationId].defaultTier;
+  return operation.defaultTier;
 }

56-73: Add error handling for invalid operation lookups.

Line 61 directly accesses LLM_OPERATIONS[operationId] without validation. If the operation ID is invalid, this will throw a runtime error. Consider adding a defensive check similar to the one suggested for resolveModelTier.

🔎 Proposed defensive check
 export function getModelForOperation(
   userAi: UserAIFields,
   operationId: LLMOperationId,
   online = false,
 ): SelectModel {
   const operation = LLM_OPERATIONS[operationId];
+  if (!operation) {
+    logger.error("Unknown operation ID, falling back to economy", {
+      operationId,
+    });
+    return getModel(userAi, "economy", online);
+  }
   const tier = resolveModelTier(operationId);
   const modelType = TIER_TO_MODEL_TYPE[tier];

   logger.info("Getting model for operation", {
     operationId,
     tier,
     modelType,
     frequency: operation.frequency,
   });

   return getModel(userAi, modelType, online);
 }

Comment on lines 10 to 18
export async function aiDetermineThreadStatus({
emailAccount,
threadMessages,
modelType,
userSentLastEmail = false,
}: {
emailAccount: EmailAccountWithAI;
threadMessages: EmailForLLM[];
modelType?: ModelType;
userSentLastEmail?: boolean;
}): Promise<{ status: ConversationStatus; rationale: string }> {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Search for all calls to aiDetermineThreadStatus
rg -n "aiDetermineThreadStatus\(" --type ts -B 2 -A 5

Repository: elie222/inbox-zero

Length of output: 12797


Remove modelType parameter from aiDetermineThreadStatus call in handle-conversation-status.ts.

The caller in apps/web/utils/reply-tracker/handle-conversation-status.ts (line 75) still passes modelType, but the function no longer accepts this parameter. Update the call to match the other callers:

Location to fix
apps/web/utils/reply-tracker/handle-conversation-status.ts:72-77
const { status, rationale } = await aiDetermineThreadStatus({
  emailAccount,
  threadMessages: threadMessagesForLLM,
  modelType,  // ← Remove this line
  userSentLastEmail,
});
🤖 Prompt for AI Agents
In apps/web/utils/reply-tracker/handle-conversation-status.ts around lines 72 to
77, the call to aiDetermineThreadStatus still passes a now-removed modelType
parameter; remove the modelType property from the argument object so the call
only supplies emailAccount, threadMessages (threadMessagesForLLM), and
userSentLastEmail to match the updated function signature and other callers.

- Add operationId to chatCompletionStream calls in compose-autocomplete and summarise
- Remove modelType parameter from isColdEmail, findMatchingRules, aiChooseRule,
  determineConversationStatus as it was removed from the API
- Update match-rules.test.ts to remove modelType from test cases
@rsnodgrass rsnodgrass closed this Jan 1, 2026
@elie222
Copy link
Owner

elie222 commented Jan 1, 2026

Separately from these improvements, I also realized that my using Anthropic is fairly expensive for Inbox Zero compared to OpenAI since Vercel's handling of AI mapping causes some big issues in context management especially around effective use of cached tokens. I'm switching to OpenAI and associated models since it would not be easy to fix this.

We can add caching btw. Gemini 3 Flash could be a good model for you. It's cheap and outperforms Gemini 2.5 Pro, which is a tier 1 model till quite recently.

@elie222
Copy link
Owner

elie222 commented Jan 1, 2026

More on caching here, but actually most of the time it's not helpful for us as the prompts are <1000 tokens so nothing gets cached :(
https://ai-sdk.dev/docs/advanced/caching

I think we can keep this closed for now. I'm wary of making huge changes across the codebase with arguably small value.
A disadvantage of the centralized registry approach is that can't see inline what model is being used, and have to jump between files to see the config for it.

BTW, if you want to see what operations are costing you the most, you can set up Tinybird (for the llm analytics package). It tracks what your spend is going towards.

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