diff --git a/commands/people/index.ts b/commands/people/index.ts new file mode 100644 index 0000000..b5a5826 --- /dev/null +++ b/commands/people/index.ts @@ -0,0 +1,58 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +import { + getUserProfile, + getMe, + getUserManager, +} from '../../workspace-server/src/services/PeopleService'; + +export const get_user_profile = { + name: 'get_user_profile', + description: 'Get a user\'s profile by ID, email, or name.', + parameters: { + type: 'object', + properties: { + userId: { + type: 'string', + description: 'The ID of the user.', + }, + email: { + type: 'string', + description: 'The email address of the user.', + }, + name: { + type: 'string', + description: 'The name of the user.', + }, + }, + }, + function: getUserProfile, +}; + +export const get_me = { + name: 'get_me', + description: 'Get the user\'s profile.', + parameters: { + type: 'object', + properties: {}, + }, + function: getMe, +}; + +export const get_user_manager = { + name: 'get_user_manager', + description: 'Get the user\'s manager.', + parameters: { + type: 'object', + properties: { + userId: { + type: 'string', + description: 'The ID of the user.', + }, + }, + }, + function: getUserManager, +}; diff --git a/workspace-server/src/__tests__/services/PeopleService.test.ts b/workspace-server/src/__tests__/services/PeopleService.test.ts index 6c7d727..ff148d4 100644 --- a/workspace-server/src/__tests__/services/PeopleService.test.ts +++ b/workspace-server/src/__tests__/services/PeopleService.test.ts @@ -146,4 +146,35 @@ describe('PeopleService', () => { expect(JSON.parse(result.content[0].text)).toEqual({ error: 'API Error' }); }); }); + + describe('getUserManager', () => { + it('should return the manager of a user', async () => { + const mockManager = { + data: { + relations: [{ + type: 'manager', + person: 'people/110001608645105799645', + }], + }, + }; + mockPeopleAPI.people.get.mockResolvedValue(mockManager); + + const result = await peopleService.getUserManager({ userId: '110001608645105799644' }); + + expect(mockPeopleAPI.people.get).toHaveBeenCalledWith({ + resourceName: 'people/110001608645105799644', + personFields: 'relations', + }); + expect(JSON.parse(result.content[0].text)).toEqual({ manager: 'people/110001608645105799645' }); + }); + + it('should handle errors during getUserManager', async () => { + const apiError = new Error('API Error'); + mockPeopleAPI.people.get.mockRejectedValue(apiError); + + const result = await peopleService.getUserManager({ userId: '110001608645105799644' }); + + expect(JSON.parse(result.content[0].text)).toEqual({ error: 'API Error' }); + }); + }); }); diff --git a/workspace-server/src/index.ts b/workspace-server/src/index.ts index 0cb5f62..79a763b 100644 --- a/workspace-server/src/index.ts +++ b/workspace-server/src/index.ts @@ -683,6 +683,17 @@ There are a list of system labels that can be modified on a message: peopleService.getMe ); + server.registerTool( + "people.getUserManager", + { + description: 'Gets the manager for a given user.', + inputSchema: { + userId: z.string().describe('The ID of the user to get the manager for.'), + } + }, + peopleService.getUserManager + ); + // 4. Connect the transport layer and start listening const transport = new StdioServerTransport(); await server.connect(transport); diff --git a/workspace-server/src/services/PeopleService.ts b/workspace-server/src/services/PeopleService.ts index d66e39e..c36d454 100644 --- a/workspace-server/src/services/PeopleService.ts +++ b/workspace-server/src/services/PeopleService.ts @@ -19,6 +19,35 @@ export class PeopleService { return google.people({ version: 'v1', ...options }); } + public getUserManager = async ({ userId }: { userId: string; }) => { + logToFile(`[PeopleService] Starting getUserManager with: userId=${userId}`); + try { + const people = await this.getPeopleClient(); + const resourceName = userId.startsWith('people/') ? userId : `people/${userId}`; + const res = await people.people.get({ + resourceName, + personFields: 'relations', + }); + const manager = res.data.relations?.find((r: { type: string; }) => r.type === 'manager')?.person || null; + logToFile(`[PeopleService] Finished getUserManager for user: ${userId}`); + return { + content: [{ + type: "text" as const, + text: JSON.stringify({ manager }) + }] + }; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + logToFile(`[PeopleService] Error during people.getUserManager: ${errorMessage}`); + return { + content: [{ + type: "text" as const, + text: JSON.stringify({ error: errorMessage }) + }] + }; + } + } + public getUserProfile = async ({ userId, email, name }: { userId?: string, email?: string, name?: string }) => { logToFile(`[PeopleService] Starting getUserProfile with: userId=${userId}, email=${email}, name=${name}`); try { @@ -30,7 +59,7 @@ export class PeopleService { const resourceName = userId.startsWith('people/') ? userId : `people/${userId}`; const res = await people.people.get({ resourceName, - personFields: 'names,emailAddresses', + personFields: 'names,emailAddresses,relations', }); logToFile(`[PeopleService] Finished getUserProfile for user: ${userId}`); return {