FEAT-Add-Star-tool #8
16
README.md
16
README.md
@@ -97,10 +97,10 @@ The server fetches unread emails, classifies them using your configured prompts,
|
||||
|
||||
| Category | Description | Default Action |
|
||||
|----------|-------------|----------------|
|
||||
| **A** | Acknowledgements, auto-replies | Delete |
|
||||
| **B** | Advancement (interview requests, next steps) | Log + Calendar event |
|
||||
| **C** | Rejections | Delete |
|
||||
| **D** | Other/uncategorized | Log for review |
|
||||
| **A** | Acknowledgements, auto-replies | Star and mark read |
|
||||
| **B** | Advancement (interview requests, next steps) | Log + Calendar event (never star) |
|
||||
| **C** | Rejections | Star and mark read |
|
||||
| **D** | Other/uncategorized | Star, mark read, and log for review |
|
||||
|
||||
### Customizing Prompts
|
||||
|
||||
@@ -119,7 +119,7 @@ Changes take effect immediately without rebuilding.
|
||||
|------|-------------|
|
||||
| `fetch_new_emails` | Fetch unread emails with classification instructions appended |
|
||||
| `delete_emails` | Move specified message IDs to trash |
|
||||
| `star_emails` | Star messages and mark as read |
|
||||
| `star_emails` | Star Category A/C/D messages and mark as read |
|
||||
| `append_to_summary` | Log email metadata to local JSON (auto-purges after 30 days) |
|
||||
| `log_recruiter_contact` | Append or update a row in Google Sheets |
|
||||
| `create_calendar_event` | Create a Google Calendar event (skips past dates) |
|
||||
@@ -130,6 +130,12 @@ Changes take effect immediately without rebuilding.
|
||||
fetch_new_emails(account: "work", maxResults: 50)
|
||||
```
|
||||
|
||||
### Example: Star and Mark Read (Categories A, C, D only)
|
||||
|
||||
```
|
||||
star_emails(account: "work", messageIds: ["msg-id-1", "msg-id-2"])
|
||||
```
|
||||
|
||||
### Example: Create Calendar Event
|
||||
|
||||
```
|
||||
|
||||
@@ -9,23 +9,22 @@ STEP 2: CLASSIFY each email into exactly one category.
|
||||
|
||||
Category A - Acknowledgement Only
|
||||
The employer confirms receipt of my application but requires no action from me. Typical language: "We received your application," "Your application is under review," "We will contact you if selected." No next steps are requested.
|
||||
Action you should take: Add a "Star" using the gmail built-in actions.
|
||||
Action you should take: Call star_emails with this message's ID (same account used for fetch_new_emails). That stars the email and marks it read.
|
||||
|
||||
Category B - Advancement to Next Step
|
||||
The employer wants to move forward. This includes: invitations to schedule a phone screen or interview, requests to complete an assessment or assignment, requests for additional information or documents, or any communication that requires a response or action from me. If an email both acknowledges receipt AND requests action, classify it as B.
|
||||
Actions you should take: 1) add a calendar event with all pertinent info: a) person I will be meeting with,
|
||||
b) company c) role I will be discussing d) method for joining meeting - ie, telephone? If yes, will the representative all me, and is the number correct (718) 749-8292 c) or, is it Zoom, Google Meet, Webex or another video format, if so, include the link for joining
|
||||
|
||||
NEVER, EVER ADD A STAR TO A VATEGORY B EMAIL.
|
||||
NEVER, EVER ADD A STAR TO A CATEGORY B EMAIL. Do not pass Category B message IDs to star_emails.
|
||||
|
||||
Category C - Rejection
|
||||
The employer declines to move forward. Typical language: "We have decided to pursue other candidates," "Unfortunately, you were not selected," "We will not be moving forward with your application."
|
||||
Action you should take:
|
||||
Add a "Star" using the gmail built-in actions.
|
||||
Action you should take: Call star_emails with this message's ID (same account used for fetch_new_emails). That stars the email and marks it read.
|
||||
|
||||
Category D - Other
|
||||
The email does not fit into categories A, B, or C. This includes non-job-application emails, newsletters, promotional content, or ambiguous messages that do not clearly match another category.
|
||||
Action you should take: Add a "Star" using the gmail built-in actions.
|
||||
Action you should take: Call star_emails with this message's ID (same account used for fetch_new_emails). That stars the email and marks it read.
|
||||
|
||||
STEP 3: SUMMARIZE emails classified as Category B and Category D in the chat in an organized list with headings. Example format for this:
|
||||
1. Sender name and email address
|
||||
|
||||
@@ -55,8 +55,9 @@ server.registerTool(
|
||||
{
|
||||
description:
|
||||
"Fetch unread emails from a Gmail inbox. Returns sender, date, " +
|
||||
"subject, message ID, and body text for each message. The message IDs " +
|
||||
"must be passed to star_emails after evaluation. Specify which account to fetch from.",
|
||||
"subject, message ID, and body text for each message. After evaluation, " +
|
||||
"pass Category A, C, and D message IDs to star_emails. Never pass " +
|
||||
"Category B IDs to star_emails. Specify which account to fetch from.",
|
||||
inputSchema: {
|
||||
account: accountSchema,
|
||||
maxResults: z
|
||||
@@ -310,8 +311,9 @@ server.registerTool(
|
||||
"star_emails",
|
||||
{
|
||||
description: "Mark reviewed emails with a star and mark them as read in Gmail. " +
|
||||
"Use this for all reviewed messages (Categories A, B, C, and D) " +
|
||||
"to signal they have been processed. Specify which account the emails belong to.",
|
||||
"Use this for Category A (acknowledgements), C (rejections), and D (other) " +
|
||||
"messages to signal they have been processed. Never use this for Category B " +
|
||||
"(advancement) emails. Specify which account the emails belong to.",
|
||||
inputSchema: {
|
||||
account: accountSchema,
|
||||
messageIds: z
|
||||
|
||||
@@ -14,6 +14,7 @@ import { MOCK_MESSAGE_LIST, MOCK_MESSAGES, MOCK_EMPTY_LIST } from "../fixtures/m
|
||||
const mockGmailList = vi.fn();
|
||||
const mockGmailGet = vi.fn();
|
||||
const mockGmailTrash = vi.fn();
|
||||
const mockGmailBatchModify = vi.fn();
|
||||
let tmpDir: string;
|
||||
|
||||
vi.mock("../../src/loaders/prompt-config-loaders.js", () => {
|
||||
@@ -45,6 +46,7 @@ vi.mock("../../src/loaders/prompt-config-loaders.js", () => {
|
||||
list: mockGmailList,
|
||||
get: mockGmailGet,
|
||||
trash: mockGmailTrash,
|
||||
batchModify: mockGmailBatchModify,
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -207,6 +209,51 @@ describe("Phase 1: Email Review Workflow", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ----- Step 2b: Star A, C, and D emails -----
|
||||
describe("star_emails", () => {
|
||||
it("stars and marks read the specified message IDs", async () => {
|
||||
mockGmailBatchModify.mockResolvedValue({});
|
||||
|
||||
const text = await callTool("star_emails", {
|
||||
account: "work",
|
||||
messageIds: ["msg-cat-a-001", "msg-cat-c-001", "msg-cat-d-001"],
|
||||
});
|
||||
|
||||
expect(mockGmailBatchModify).toHaveBeenCalledTimes(1);
|
||||
expect(mockGmailBatchModify).toHaveBeenCalledWith({
|
||||
userId: "me",
|
||||
requestBody: {
|
||||
ids: ["msg-cat-a-001", "msg-cat-c-001", "msg-cat-d-001"],
|
||||
addLabelIds: ["STARRED"],
|
||||
removeLabelIds: ["UNREAD"],
|
||||
},
|
||||
});
|
||||
expect(text).toContain("Successfully starred and marked read 3 email(s).");
|
||||
});
|
||||
|
||||
it("returns early when no message IDs are provided", async () => {
|
||||
const text = await callTool("star_emails", {
|
||||
account: "work",
|
||||
messageIds: [],
|
||||
});
|
||||
|
||||
expect(mockGmailBatchModify).not.toHaveBeenCalled();
|
||||
expect(text).toBe("No message IDs provided.");
|
||||
});
|
||||
|
||||
it("handles Gmail API errors gracefully", async () => {
|
||||
mockGmailBatchModify.mockRejectedValue(new Error("Quota exceeded"));
|
||||
|
||||
const text = await callTool("star_emails", {
|
||||
account: "work",
|
||||
messageIds: ["msg-cat-a-001"],
|
||||
});
|
||||
|
||||
expect(text).toContain("Error starring emails");
|
||||
expect(text).toContain("Quota exceeded");
|
||||
});
|
||||
});
|
||||
|
||||
// ----- Step 3: Summarize B and D -----
|
||||
describe("append_to_summary", () => {
|
||||
it("creates a summary file and appends entries", async () => {
|
||||
|
||||
Reference in New Issue
Block a user