Skip to content

Sweetmantech/myc 3794 api email agentgenerate pass in full message history for the#79

Merged
sweetmantech merged 6 commits intotestfrom
sweetmantech/myc-3794-api-email-agentgenerate-pass-in-full-message-history-for-the
Dec 18, 2025
Merged

Sweetmantech/myc 3794 api email agentgenerate pass in full message history for the#79
sweetmantech merged 6 commits intotestfrom
sweetmantech/myc-3794-api-email-agentgenerate-pass-in-full-message-history-for-the

Conversation

@sweetmantech
Copy link
Contributor

@sweetmantech sweetmantech commented Dec 18, 2025

Summary by CodeRabbit

Release Notes

  • New Features
    • Added inbound email support with automatic response generation
    • Implemented chat system with persistent conversation memory and history
    • Integrated AI-powered conversation routing with context-aware responses
    • Added knowledge base integration for enhanced conversation context
    • Enabled new conversation notifications via email

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

@vercel
Copy link
Contributor

vercel bot commented Dec 18, 2025

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

Project Deployment Review Updated (UTC)
recoup-api Ready Ready Preview Dec 18, 2025 8:45pm

@coderabbitai
Copy link

coderabbitai bot commented Dec 18, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This PR introduces a comprehensive inbound email handling system with automated reply generation. It adds an email ingestion API route, email processing pipeline, chat room orchestration, message persistence, and agent-based reply composition. New utilities support UUID generation, system prompt construction, tool setup, memory tracking, and database schema extensions. The changes integrate Resend email service and MCP-based tool management.

Changes

Cohort / File(s) Summary
Inbound Email API Route
app/api/emails/inbound/route.ts
New POST endpoint delegating to inbound email handler
Email Service Integration
lib/emails/client.ts, lib/emails/sendEmail.ts, lib/emails/isTestEmail.ts
Resend client initialization, email sending with error handling, test email detection
Email Event Validation
lib/emails/validateInboundEmailEvent.ts
Zod schema validation for inbound Resend webhook events with CORS headers
Inbound Email Processing
lib/emails/inbound/getEmailContent.ts, lib/emails/inbound/getEmailRoomId.ts, lib/emails/inbound/getFromWithName.ts, lib/emails/inbound/handleInboundEmail.ts, lib/emails/inbound/respondToInboundEmail.ts
Email content fetching, room lookup, sender formatting, event handling, and reply orchestration
Chat Room Management
lib/chat/createNewRoom.ts, lib/supabase/rooms/insertRoom.ts, lib/supabase/rooms/selectRoom.ts
Room creation with title generation, insertion, and lookup
Message Handling & Validation
lib/messages/getMessages.ts, lib/messages/validateMessages.ts, lib/messages/extractImageUrlsFromMessages.ts, lib/messages/filterMessageContentForMemories.ts
Message construction, validation, image extraction, and filtering
Chat Completion & Persistence
lib/chat/handleChatCompletion.ts, lib/chat/saveNewMessages.ts
Orchestrates room existence checks and saves user/assistant message pairs to memory
Chat Request Schema & Routing
lib/chat/validateChatRequest.ts, lib/chat/types.ts
Request validation enforcing exactly one of messages or prompt; RoutingDecision interface for agent configuration
Agent Orchestration
lib/agents/generalAgent/getGeneralAgent.ts, lib/chat/setupToolsForRequest.ts, lib/chat/filterExcludedTools.ts
General agent construction with account/artist context, MCP tool setup, and tool filtering
System Prompts & AI
lib/chat/const.ts, lib/prompts/getSystemPrompt.ts, lib/chat/buildSystemPromptWithImages.ts, lib/ai/generateText.ts
System prompt constant for music-focused assistant, dynamic prompt building with user/artist context and images, text generation wrapper
Chat Title Generation
lib/chat/generateChatTitle.ts
Generates concise conversation titles via lightweight model inference
Memory & Linkage
lib/supabase/memories/insertMemories.ts, lib/supabase/memories/selectMemories.ts, lib/supabase/memory_emails/insertMemoryEmail.ts, lib/supabase/memory_emails/selectMemoryEmails.ts
Memory insertion/retrieval and email-to-memory association with joined queries
Account & Email Queries
lib/supabase/account_emails/selectAccountEmails.ts, lib/supabase/accounts/getAccountWithDetails.ts
Enhanced account email lookup by accountId, account details with flattened related data
Notifications
lib/telegram/sendNewConversationNotification.ts
Sends Telegram notifications for new conversations, skipping test emails
Utilities
lib/uuid/generateUUID.ts, lib/const.ts, lib/files/getKnowledgeBaseText.ts
UUID v4 generation with fallback, lightweight model constant, knowledge base text fetching from URLs
Database Schema
types/database.types.ts
Added memory_emails table with email_id, message_id, memory reference, and foreign key linkage
Dependencies
package.json
Added @ai-sdk/mcp@^0.0.12 and resend@^6.6.0
Cleanup
lib/coinbase/getAccount.ts, lib/mcp/tools/youtube/registerGetYouTubeRevenueTool.ts, lib/songs/queueRedisSongs.ts, lib/youtube/queryAnalyticsReports.ts
Removed debug logging statements

Sequence Diagram(s)

sequenceDiagram
    participant Client as HTTP Client
    participant APIRoute as API Route<br/>(POST /inbound)
    participant Validator as validateInboundEmailEvent
    participant EmailHandler as handleInboundEmail
    participant Responder as respondToInboundEmail
    participant Resend as Resend API
    participant Agent as getGeneralAgent
    participant Memory as Supabase Memories

    Client->>APIRoute: POST with email event
    APIRoute->>Validator: Validate event payload
    
    alt Invalid Event
        Validator->>APIRoute: 400 error response
        APIRoute->>Client: Return error
    else Valid Event
        Validator->>APIRoute: Parsed event
        APIRoute->>EmailHandler: handleInboundEmail(request)
        
        rect rgb(200, 220, 240)
            note over EmailHandler: Process email.received event
            EmailHandler->>Responder: respondToInboundEmail(event)
            
            Responder->>Resend: getEmailContent(emailId)
            Resend-->>Responder: Email with headers
            
            Responder->>Responder: Extract room_id from references
            Responder->>Responder: Build chat request with message history
            
            Responder->>Agent: getGeneralAgent(chatRequest)
            Agent-->>Responder: Agent + tools + instructions
            
            Responder->>Agent: Generate reply via ToolLoopAgent
            Agent-->>Responder: Reply text
            
            Responder->>Resend: sendEmailWithResend(reply payload)
            Resend-->>Responder: Email sent confirmation
            
            Responder->>Memory: insertMemoryEmail(linkage)
            Memory-->>Responder: Saved reference
        end
        
        Responder-->>EmailHandler: Response
        EmailHandler-->>APIRoute: Response
        APIRoute-->>Client: 200 OK
    end
Loading
sequenceDiagram
    participant App as Application
    participant Validator as validateChatRequest
    participant Completion as handleChatCompletion
    participant RoomSvc as Room Service
    participant MsgSvc as Message Service
    participant Memory as Supabase

    App->>Validator: Validate chat request<br/>(messages or prompt)
    
    alt Invalid
        Validator->>App: Error
    else Valid
        Validator-->>Completion: Proceed
        
        Completion->>MsgSvc: validateMessages(messages)
        MsgSvc-->>Completion: lastMessage + validMessages
        
        alt Room exists
            Completion->>RoomSvc: selectRoom(roomId)
            RoomSvc-->>Completion: Room data
        else Room missing
            Completion->>RoomSvc: createNewRoom(accountId, roomId)
            RoomSvc->>Memory: insertRoom + notify
            Memory-->>RoomSvc: Confirmed
        end
        
        Completion->>MsgSvc: saveNewMessages(roomId, messages)
        MsgSvc->>Memory: insertMemories (user + assistant)
        Memory-->>MsgSvc: Saved records
        
        MsgSvc-->>Completion: Memory array
        Completion-->>App: Memory records
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • lib/emails/inbound/respondToInboundEmail.ts — Multi-step orchestration with agent invocation, email composition, memory linkage, and error handling across external services (Resend, Supabase); dense control flow
  • lib/agents/generalAgent/getGeneralAgent.ts — Wires multiple data fetchers and context builders; requires understanding of account/artist resolution, image augmentation, and tool setup
  • lib/supabase/accounts/getAccountWithDetails.ts — Type structure changed significantly from explicit interface to composite type alias; verify flattening logic aligns with related table semantics
  • lib/prompts/getSystemPrompt.ts — Complex conditional prompt assembly with multiple context sections (user, artist, knowledge base); ensure conditional logic and formatting are correct
  • lib/chat/setupToolsForRequest.ts — MCP client initialization and tool merging; verify transport configuration and tool retrieval logic
  • lib/supabase/memory_emails/selectMemoryEmails.ts — Join logic with memories table; verify foreign key resolution and null-safety in nested access patterns
  • types/database.types.ts — New memory_emails table schema; confirm relationships and field optionality match migration/schema expectations

Possibly related PRs

Poem

🐰 Emails hop in through the door,
Rooms get birthed, memories store,
Agents chat with flair and wit,
Replies sent with perfect fit!
AI dreams made automat',
Recoup runs smooth—and that is that! 🎵

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is incomplete and vague. It cuts off mid-sentence ('for the') and does not clearly convey the main change despite referencing a ticket number and general topic of email/agent/message history. Complete the title with clear, specific language describing the primary change. For example: 'Pass full message history to email agent for context' or similar concise completion.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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.

Copy link
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

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

Additional Suggestion:

If the AI agent's response text is empty or falsy, the code will crash when trying to save the assistant's message to the database.

View Details
📝 Patch Details
diff --git a/lib/chat/saveNewMessages.ts b/lib/chat/saveNewMessages.ts
index 8bd8262..46878ca 100644
--- a/lib/chat/saveNewMessages.ts
+++ b/lib/chat/saveNewMessages.ts
@@ -34,6 +34,11 @@ export async function saveNewMessages({
     content: filterMessageContentForMemories(lastMessage),
   });
 
+  // Only save assistant message if response messages exist (e.g., not empty from AI agent)
+  if (responseMessages.length === 0) {
+    return [userMemory].filter((m): m is Memory => m !== null);
+  }
+
   const assistantMemory = await insertMemories({
     id: responseMessages[responseMessages.length - 1].id,
     room_id: roomId,
diff --git a/lib/emails/inbound/respondToInboundEmail.ts b/lib/emails/inbound/respondToInboundEmail.ts
index 7f831bf..95d8e05 100644
--- a/lib/emails/inbound/respondToInboundEmail.ts
+++ b/lib/emails/inbound/respondToInboundEmail.ts
@@ -52,6 +52,15 @@ export async function respondToInboundEmail(
     const chatResponse = await agent.generate({
       messages,
     });
+
+    // Skip email and database save if the assistant response is empty
+    if (!chatResponse.text) {
+      return NextResponse.json(
+        { error: "No response generated from AI agent" },
+        { status: 400 },
+      );
+    }
+
     const payload = {
       from,
       to: toArray,

Analysis

Crash when AI agent returns empty text in respondToInboundEmail

What fails: saveNewMessages() crashes with TypeError: Cannot read property 'id' of undefined when ToolLoopAgent.generate() returns an empty text string, which causes getMessages() to return an empty array and accessing responseMessages[-1] throws.

How to reproduce:

  1. Trigger inbound email processing via respondToInboundEmail() endpoint
  2. Configure the AI agent to invoke tools that produce only tool results without generating text (empty text field)
  3. Per AI SDK GitHub issue #1831, this is a known scenario where tool-only responses return empty text

Result: The code crashes at lib/chat/saveNewMessages.ts:40 when trying to access responseMessages[responseMessages.length - 1].id on an empty array, resulting in a TypeError: Cannot read property 'id' of undefined

Expected: Should handle empty AI responses gracefully without crashing. Per Vercel AI SDK documentation, the text field is always a string but can be empty when models prioritize tool invocation over text generation.

Root cause: The code does not validate that chatResponse.text is non-empty before passing it to getMessages(), which returns an empty array for falsy input. The empty array is then passed to saveNewMessages() which attempts to access the last element without checking if the array is empty.

Fix: Added defensive checks at two levels:

  1. In respondToInboundEmail.ts: Return error response if chatResponse.text is falsy before sending empty email
  2. In saveNewMessages.ts: Check if responseMessages array is empty before accessing the last element

@sweetmantech sweetmantech merged commit f982f48 into test Dec 18, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments