diff --git a/workspace-server/src/__tests__/services/GmailService.test.ts b/workspace-server/src/__tests__/services/GmailService.test.ts index bb6731a..0f7d7a4 100644 --- a/workspace-server/src/__tests__/services/GmailService.test.ts +++ b/workspace-server/src/__tests__/services/GmailService.test.ts @@ -830,4 +830,86 @@ describe('GmailService', () => { expect(response.error).toBe('Failed to list labels'); }); }); + + describe('createLabel', () => { + it('should create a label with default visibility', async () => { + const mockLabel = { + id: 'Label_1', + name: 'Test Label', + type: 'user', + labelListVisibility: 'labelShow', + messageListVisibility: 'show', + }; + + mockGmailAPI.users.labels.create.mockResolvedValue({ + data: mockLabel, + }); + + const result = await gmailService.createLabel({ + name: 'Test Label', + }); + + expect(mockGmailAPI.users.labels.create).toHaveBeenCalledWith({ + userId: 'me', + requestBody: { + name: 'Test Label', + labelListVisibility: 'labelShow', + messageListVisibility: 'show', + }, + }); + + const response = JSON.parse(result.content[0].text); + expect(response).toEqual({ + ...mockLabel, + status: 'created', + }); + }); + + it('should create a label with custom visibility settings', async () => { + const mockLabel = { + id: 'Label_2', + name: 'Hidden Label', + type: 'user', + labelListVisibility: 'labelHide', + messageListVisibility: 'hide', + }; + + mockGmailAPI.users.labels.create.mockResolvedValue({ + data: mockLabel, + }); + + const result = await gmailService.createLabel({ + name: 'Hidden Label', + labelListVisibility: 'labelHide', + messageListVisibility: 'hide', + }); + + expect(mockGmailAPI.users.labels.create).toHaveBeenCalledWith({ + userId: 'me', + requestBody: { + name: 'Hidden Label', + labelListVisibility: 'labelHide', + messageListVisibility: 'hide', + }, + }); + + const response = JSON.parse(result.content[0].text); + expect(response).toEqual({ + ...mockLabel, + status: 'created', + }); + }); + + it('should handle create label errors', async () => { + const apiError = new Error('Label already exists'); + mockGmailAPI.users.labels.create.mockRejectedValue(apiError); + + const result = await gmailService.createLabel({ + name: 'Duplicate Label', + }); + + const response = JSON.parse(result.content[0].text); + expect(response.error).toBe('Label already exists'); + }); + }); }); diff --git a/workspace-server/src/index.ts b/workspace-server/src/index.ts index becce91..ba20bed 100644 --- a/workspace-server/src/index.ts +++ b/workspace-server/src/index.ts @@ -1002,6 +1002,30 @@ There are a list of system labels that can be modified on a message: gmailService.listLabels, ); + server.registerTool( + 'gmail.createLabel', + { + description: + 'Create a new Gmail label. Labels help organize emails into categories.', + inputSchema: { + name: z.string().min(1).describe('The display name of the label.'), + labelListVisibility: z + .enum(['labelShow', 'labelHide', 'labelShowIfUnread']) + .optional() + .describe( + 'Visibility of the label in the label list. Defaults to "labelShow".', + ), + messageListVisibility: z + .enum(['show', 'hide']) + .optional() + .describe( + 'Visibility of messages with this label in the message list. Defaults to "show".', + ), + }, + }, + gmailService.createLabel, + ); + // Time tools server.registerTool( 'time.getCurrentDate', diff --git a/workspace-server/src/services/GmailService.ts b/workspace-server/src/services/GmailService.ts index 04b3cab..e988cf3 100644 --- a/workspace-server/src/services/GmailService.ts +++ b/workspace-server/src/services/GmailService.ts @@ -489,6 +489,57 @@ export class GmailService { } }; + public createLabel = async ({ + name, + labelListVisibility = 'labelShow', + messageListVisibility = 'show', + }: { + name: string; + labelListVisibility?: 'labelShow' | 'labelHide' | 'labelShowIfUnread'; + messageListVisibility?: 'show' | 'hide'; + }) => { + try { + logToFile(`Creating Gmail label: ${name}`); + + const gmail = await this.getGmailClient(); + + const response = await gmail.users.labels.create({ + userId: 'me', + requestBody: { + name, + labelListVisibility, + messageListVisibility, + }, + }); + + const label = response.data; + + logToFile(`Created label: ${label.name} with id: ${label.id}`); + + return { + content: [ + { + type: 'text' as const, + text: JSON.stringify( + { + id: label.id, + name: label.name, + type: label.type, + messageListVisibility: label.messageListVisibility, + labelListVisibility: label.labelListVisibility, + status: 'created', + }, + null, + 2, + ), + }, + ], + }; + } catch (error) { + return this.handleError(error, 'gmail.createLabel'); + } + }; + private extractAttachmentsAndBody( payload: gmail_v1.Schema$MessagePart, result: { body: string; attachments: GmailAttachment[] } = {