Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 54 additions & 79 deletions apps/web/__tests__/ai-choose-rule.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should return no rule when no rules passed", async () => {
const result = await aiChooseRule({
rules: [],
messages: [getEmail()],
email: getEmail(),
user: getUser(),
});

Expand All @@ -26,7 +26,7 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
);

const result = await aiChooseRule({
messages: [getEmail({ subject: "test" })],
email: getEmail({ subject: "test" }),
rules: [rule],
user: getUser(),
});
Expand All @@ -47,7 +47,7 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {

const result = await aiChooseRule({
rules: [rule1, rule2],
messages: [getEmail({ subject: "remember that call" })],
email: getEmail({ subject: "remember that call" }),
user: getUser(),
});

Expand Down Expand Up @@ -80,12 +80,10 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {

const result = await aiChooseRule({
rules: [rule1, rule2],
messages: [
getEmail({
subject: "Joke",
content: "Tell me a joke about sheep",
}),
],
email: getEmail({
subject: "Joke",
content: "Tell me a joke about sheep",
}),
user: getUser(),
});

Expand Down Expand Up @@ -149,13 +147,11 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should match simple response required", async () => {
const result = await aiChooseRule({
rules,
messages: [
getEmail({
from: "alicesmith@gmail.com",
subject: "Can we meet for lunch tomorrow?",
content: "LMK\n\n--\nAlice Smith,\nCEO, The Boring Fund",
}),
],
email: getEmail({
from: "alicesmith@gmail.com",
subject: "Can we meet for lunch tomorrow?",
content: "LMK\n\n--\nAlice Smith,\nCEO, The Boring Fund",
}),
user: getUser(),
});

Expand All @@ -168,13 +164,11 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should match technical issues", async () => {
const result = await aiChooseRule({
rules,
messages: [
getEmail({
subject: "Server downtime reported",
content:
"We're experiencing critical server issues affecting production.",
}),
],
email: getEmail({
subject: "Server downtime reported",
content:
"We're experiencing critical server issues affecting production.",
}),
user: getUser(),
});

Expand All @@ -187,12 +181,10 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should match financial emails", async () => {
const result = await aiChooseRule({
rules,
messages: [
getEmail({
subject: "Your invoice for March 2024",
content: "Please find attached your invoice for services rendered.",
}),
],
email: getEmail({
subject: "Your invoice for March 2024",
content: "Please find attached your invoice for services rendered.",
}),
user: getUser(),
});

Expand All @@ -205,13 +197,11 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should match recruiter emails", async () => {
const result = await aiChooseRule({
rules,
messages: [
getEmail({
subject: "New job opportunity at Tech Corp",
content:
"I came across your profile and think you'd be perfect for...",
}),
],
email: getEmail({
subject: "New job opportunity at Tech Corp",
content:
"I came across your profile and think you'd be perfect for...",
}),
user: getUser(),
});

Expand All @@ -224,12 +214,10 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should match legal documents", async () => {
const result = await aiChooseRule({
rules,
messages: [
getEmail({
subject: "Please review: Contract for new project",
content: "Attached is the contract for your review and signature.",
}),
],
email: getEmail({
subject: "Please review: Contract for new project",
content: "Attached is the contract for your review and signature.",
}),
user: getUser(),
});

Expand All @@ -242,13 +230,10 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should match emails requiring response", async () => {
const result = await aiChooseRule({
rules,
messages: [
getEmail({
subject: "Team lunch tomorrow?",
content:
"Would you like to join us for team lunch tomorrow at 12pm?",
}),
],
email: getEmail({
subject: "Team lunch tomorrow?",
content: "Would you like to join us for team lunch tomorrow at 12pm?",
}),
user: getUser(),
});

Expand All @@ -261,12 +246,10 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should match product updates", async () => {
const result = await aiChooseRule({
rules,
messages: [
getEmail({
subject: "New Feature Release: AI Integration",
content: "We're excited to announce our new AI features...",
}),
],
email: getEmail({
subject: "New Feature Release: AI Integration",
content: "We're excited to announce our new AI features...",
}),
user: getUser(),
});

Expand All @@ -279,12 +262,10 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should match marketing emails", async () => {
const result = await aiChooseRule({
rules,
messages: [
getEmail({
subject: "50% off Spring Sale!",
content: "Don't miss out on our biggest sale of the season!",
}),
],
email: getEmail({
subject: "50% off Spring Sale!",
content: "Don't miss out on our biggest sale of the season!",
}),
user: getUser(),
});

Expand All @@ -297,12 +278,10 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should match team updates", async () => {
const result = await aiChooseRule({
rules,
messages: [
getEmail({
subject: "Weekly Team Update",
content: "Here's what the team accomplished this week...",
}),
],
email: getEmail({
subject: "Weekly Team Update",
content: "Here's what the team accomplished this week...",
}),
user: getUser(),
});

Expand All @@ -315,12 +294,10 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should match customer feedback", async () => {
const result = await aiChooseRule({
rules,
messages: [
getEmail({
subject: "Customer Feedback: App Performance",
content: "I've been experiencing slow loading times...",
}),
],
email: getEmail({
subject: "Customer Feedback: App Performance",
content: "I've been experiencing slow loading times...",
}),
user: getUser(),
});

Expand All @@ -333,12 +310,10 @@ describe.skipIf(!isAiTest)("aiChooseRule", () => {
test("Should match event invitations", async () => {
const result = await aiChooseRule({
rules,
messages: [
getEmail({
subject: "Invitation: Annual Tech Conference",
content: "You're invited to speak at our annual conference...",
}),
],
email: getEmail({
subject: "Invitation: Annual Tech Conference",
content: "You're invited to speak at our annual conference...",
}),
user: getUser(),
});

Expand Down
12 changes: 6 additions & 6 deletions apps/web/app/api/google/webhook/process-history-item.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { gmail_v1 } from "@googleapis/gmail";
import prisma from "@/utils/prisma";
import { emailToContent } from "@/utils/mail";
import { emailToContent, parseMessage } from "@/utils/mail";
import { GmailLabel } from "@/utils/gmail/label";
import { getMessage } from "@/utils/gmail/message";
import { runColdEmailBlocker } from "@/utils/cold-email/is-cold-email";
import { runRulesOnMessage } from "@/utils/ai/choose-rule/run-rules";
import { blockUnsubscribedEmails } from "@/app/api/google/webhook/block-unsubscribed-emails";
Expand All @@ -15,7 +16,6 @@ import { ColdEmailSetting } from "@prisma/client";
import { logger } from "@/app/api/google/webhook/logger";
import { isIgnoredSender } from "@/utils/filter-ignored-senders";
import { internalDateToDate } from "@/utils/date";
import { getThreadMessages } from "@/utils/gmail/thread";

export async function processHistoryItem(
{
Expand Down Expand Up @@ -53,8 +53,8 @@ export async function processHistoryItem(
logger.info("Getting message", loggerOptions);

try {
const [messages, hasExistingRule] = await Promise.all([
getThreadMessages(threadId, gmail),
const [gmailMessage, hasExistingRule] = await Promise.all([
getMessage(messageId, gmail, "full"),
prisma.executedRule.findUnique({
where: {
unique_user_thread_message: { userId: user.id, threadId, messageId },
Expand All @@ -69,7 +69,7 @@ export async function processHistoryItem(
return;
}

const message = messages[messages.length - 1];
const message = parseMessage(gmailMessage);

if (isIgnoredSender(message.headers.from)) {
logger.info("Skipping. Ignored sender.", loggerOptions);
Expand Down Expand Up @@ -169,7 +169,7 @@ export async function processHistoryItem(

await runRulesOnMessage({
gmail,
messages,
message,
rules,
user,
isTest: false,
Expand Down
39 changes: 19 additions & 20 deletions apps/web/utils/actions/ai-rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import { labelVisibility } from "@/utils/gmail/constants";
import type { CreateOrUpdateRuleSchemaWithCategories } from "@/utils/ai/rule/create-rule-schema";
import { deleteRule, safeCreateRule, safeUpdateRule } from "@/utils/rule/rule";
import { getUserCategoriesForNames } from "@/utils/category.server";
import { getThreadMessages } from "@/utils/gmail/thread";

const logger = createScopedLogger("ai-rule");

Expand Down Expand Up @@ -76,8 +75,8 @@ export const runRulesAction = withActionInstrumentation(

const fetchExecutedRule = !isTest && !rerun;

const [messages, executedRule] = await Promise.all([
getThreadMessages(threadId, gmail),
const [gmailMessage, executedRule] = await Promise.all([
getMessage(messageId, gmail, "full"),
fetchExecutedRule
? prisma.executedRule.findUnique({
where: {
Expand Down Expand Up @@ -113,10 +112,12 @@ export const runRulesAction = withActionInstrumentation(
};
}

const message = parseMessage(gmailMessage);

const result = await runRulesOnMessage({
isTest,
gmail,
messages,
message,
rules: user.rules,
user: { ...user, email: user.email },
});
Expand Down Expand Up @@ -157,23 +158,21 @@ export const testAiCustomContentAction = withActionInstrumentation(
const result = await runRulesOnMessage({
isTest: true,
gmail,
messages: [
{
id: "testMessageId",
threadId: "testThreadId",
snippet: content,
textPlain: content,
headers: {
date: new Date().toISOString(),
from: "",
to: "",
subject: "",
},
historyId: "",
inline: [],
internalDate: new Date().toISOString(),
message: {
id: "testMessageId",
threadId: "testThreadId",
snippet: content,
textPlain: content,
headers: {
date: new Date().toISOString(),
from: "",
to: "",
subject: "",
},
],
historyId: "",
inline: [],
internalDate: new Date().toISOString(),
},
rules: user.rules,
user,
});
Expand Down
Loading
Loading