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
187 changes: 187 additions & 0 deletions apps/web/__tests__/ai-rule-fix.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import { describe, expect, test, vi } from "vitest";
import stripIndent from "strip-indent";
import { aiRuleFix } from "@/utils/ai/rule/rule-fix";
import type { EmailForLLM } from "@/utils/ai/choose-rule/stringify-email";

// pnpm test ai-rule-fix

vi.mock("server-only", () => ({}));

describe("aiRuleFix", () => {
test("should fix a rule that incorrectly matched a sales email", async () => {
const rule = {
instructions: "Match emails discussing potential business partnerships",
};

const salesEmail = getEmail({
from: "sales@company.com",
subject: "Special Discount on Our Product",
content: stripIndent(`
Hi there,

I wanted to reach out about our amazing product that could help your business.
We're offering a special 50% discount this month.

Would you be interested in scheduling a demo?

Best regards,
John from Sales
`),
});

const result = await aiRuleFix({
incorrectRule: rule,
correctRule: null,
email: salesEmail,
user: getUser(),
});

console.log(result);

expect(result).toBeDefined();
expect(result.rule).toBe("matched_rule");
expect(result.fixedInstructions).toContain("sales");
expect(result.fixedInstructions).not.toBe(rule.instructions);
// The new instructions should be more specific to exclude sales pitches
expect(result.fixedInstructions.toLowerCase()).toMatch(
/(apply|match).*(partnership|collaboration).*(not|but do not|excluding).*(sales|promotion|discount)/i,
);
});

test("should fix rules when email matched wrong rule instead of correct rule", async () => {
const incorrectRule = {
instructions: "Match emails about technical support and bug reports",
};
const correctRule = {
instructions: "Match emails about product feedback and feature requests",
};

const feedbackEmail = getEmail({
subject: "Feature Suggestion",
content: stripIndent(`
Hello,

I love your product and have a suggestion for improvement.
It would be great if you could add dark mode to the dashboard.

Thanks,
Sarah
`),
});

const result = await aiRuleFix({
incorrectRule,
correctRule,
email: feedbackEmail,
user: getUser(),
});

console.log(result);

expect(result).toBeDefined();
expect(result.rule).toBe("correct_rule");
expect(result.fixedInstructions).toContain("technical");
// The incorrect rule should be more specific to exclude feature requests
expect(result.fixedInstructions.toLowerCase()).toMatch(
/(technical|support|bug).*(issues|problems|reports)/i,
);
});

test("should fix rule when email matched but shouldn't match any rules", async () => {
const incorrectRule = {
instructions: "Match emails about marketing collaborations",
};

const newsletterEmail = getEmail({
subject: "Weekly Marketing Newsletter",
content: stripIndent(`
This Week in Marketing:

- Top 10 Marketing Trends
- Latest Industry News
- Upcoming Webinars

To unsubscribe, click here.
`),
});

const result = await aiRuleFix({
incorrectRule,
correctRule: null,
email: newsletterEmail,
user: getUser(),
});

console.log(result);

expect(result).toBeDefined();
expect(result.rule).toBe("matched_rule");
expect(result.fixedInstructions).toContain("collaboration");
// The fixed rule should exclude newsletters and automated updates
expect(result.fixedInstructions.toLowerCase()).toMatch(
/(collaboration|partnership).*(not|exclude).*(newsletter|automated|digest)/i,
);
});

test("should fix rule when email should have matched but didn't", async () => {
const correctRule = {
instructions: "Match emails requesting pricing information",
};

const priceRequestEmail = getEmail({
subject: "Pricing Question",
content: stripIndent(`
Hi there,

Could you please send me information about your enterprise pricing?
We're looking to implement your solution for our team of 50 people.

Best regards,
Michael
`),
});

const result = await aiRuleFix({
incorrectRule: null,
correctRule,
email: priceRequestEmail,
user: getUser(),
});

console.log(result);

expect(result).toBeDefined();
expect(result.rule).toBe("correct_rule");
expect(result.fixedInstructions).toContain("pric");
// The fixed rule should be more inclusive of various pricing inquiries
expect(result.fixedInstructions.toLowerCase()).toMatch(
/(price|pricing|cost|quote).*(request|inquiry|information)/i,
);
});
});

function getEmail({
from = "user@test.com",
subject = "Test Subject",
content = "Test content",
replyTo,
cc,
}: Partial<EmailForLLM> = {}): EmailForLLM {
return {
from,
subject,
content,
...(replyTo && { replyTo }),
...(cc && { cc }),
};
}

function getUser() {
return {
aiModel: null,
aiProvider: null,
email: "user@test.com",
aiApiKey: null,
about: null,
};
}
1 change: 1 addition & 0 deletions apps/web/app/(app)/automation/ExecutedRulesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export function RuleCell({

return (
<HoverCard
className="w-80"
content={
<div>
<div className="flex justify-between font-medium">
Expand Down
Loading