From f7e457b06fca13559f3c2ccec551c67a683ff7a2 Mon Sep 17 00:00:00 2001 From: waleed Date: Tue, 7 Jul 2026 11:33:49 -0700 Subject: [PATCH 1/2] fix(google-calendar): align with live API docs, add calendar/ACL update+delete tools - remove any types from V2 response typing in get/move/quick_add/instances - add google_calendar_update_calendar (PATCH calendars.patch) - add google_calendar_delete_calendar (DELETE calendars.delete) - add google_calendar_update_acl (PATCH acl.patch) - all new tools covered by existing calendar OAuth scope, no new scopes requested --- apps/sim/blocks/blocks/google_calendar.ts | 51 ++++- .../tools/google_calendar/delete_calendar.ts | 126 +++++++++++++ apps/sim/tools/google_calendar/get.ts | 10 +- apps/sim/tools/google_calendar/index.ts | 9 + apps/sim/tools/google_calendar/instances.ts | 22 ++- apps/sim/tools/google_calendar/move.ts | 10 +- apps/sim/tools/google_calendar/quick_add.ts | 29 +-- apps/sim/tools/google_calendar/update_acl.ts | 156 +++++++++++++++ .../tools/google_calendar/update_calendar.ts | 177 ++++++++++++++++++ apps/sim/tools/registry.ts | 12 ++ 10 files changed, 572 insertions(+), 30 deletions(-) create mode 100644 apps/sim/tools/google_calendar/delete_calendar.ts create mode 100644 apps/sim/tools/google_calendar/update_acl.ts create mode 100644 apps/sim/tools/google_calendar/update_calendar.ts diff --git a/apps/sim/blocks/blocks/google_calendar.ts b/apps/sim/blocks/blocks/google_calendar.ts index 05bd744dde5..e967f52a35f 100644 --- a/apps/sim/blocks/blocks/google_calendar.ts +++ b/apps/sim/blocks/blocks/google_calendar.ts @@ -37,7 +37,10 @@ export const GoogleCalendarBlock: BlockConfig = { { label: 'Invite Attendees', id: 'invite' }, { label: 'Check Free/Busy', id: 'freebusy' }, { label: 'Create Calendar', id: 'create_calendar' }, + { label: 'Update Calendar', id: 'update_calendar' }, + { label: 'Delete Calendar', id: 'delete_calendar' }, { label: 'Share Calendar', id: 'share_calendar' }, + { label: 'Update Sharing', id: 'update_acl' }, { label: 'List Sharing', id: 'list_acl' }, { label: 'Remove Sharing', id: 'unshare_calendar' }, ], @@ -621,14 +624,36 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`, title: 'Time Zone', type: 'short-input', placeholder: 'America/Los_Angeles', - condition: { field: 'operation', value: ['create_calendar', 'freebusy'] }, + condition: { field: 'operation', value: ['create_calendar', 'freebusy', 'update_calendar'] }, + }, + + { + id: 'summary', + title: 'New Calendar Name', + type: 'short-input', + placeholder: 'Team Calendar', + condition: { field: 'operation', value: 'update_calendar' }, + }, + { + id: 'description', + title: 'New Calendar Description', + type: 'long-input', + placeholder: 'Shared team events and milestones', + condition: { field: 'operation', value: 'update_calendar' }, + }, + { + id: 'location', + title: 'New Calendar Location', + type: 'short-input', + placeholder: 'San Francisco, CA', + condition: { field: 'operation', value: 'update_calendar' }, }, { id: 'role', title: 'Access Role', type: 'dropdown', - condition: { field: 'operation', value: 'share_calendar' }, + condition: { field: 'operation', value: ['share_calendar', 'update_acl'] }, required: true, options: [ { label: 'See free/busy only', id: 'freeBusyReader' }, @@ -668,7 +693,7 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`, id: 'sendNotifications', title: 'Send Notification Email', type: 'dropdown', - condition: { field: 'operation', value: 'share_calendar' }, + condition: { field: 'operation', value: ['share_calendar', 'update_acl'] }, mode: 'advanced', options: [ { label: 'Yes', id: 'true' }, @@ -682,7 +707,7 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`, title: 'ACL Rule ID', type: 'short-input', placeholder: 'user:person@example.com', - condition: { field: 'operation', value: 'unshare_calendar' }, + condition: { field: 'operation', value: ['unshare_calendar', 'update_acl'] }, required: true, }, @@ -716,7 +741,10 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`, 'google_calendar_invite', 'google_calendar_freebusy', 'google_calendar_create_calendar', + 'google_calendar_update_calendar', + 'google_calendar_delete_calendar', 'google_calendar_share_calendar', + 'google_calendar_update_acl', 'google_calendar_list_acl', 'google_calendar_unshare_calendar', ], @@ -747,8 +775,14 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`, return 'google_calendar_freebusy' case 'create_calendar': return 'google_calendar_create_calendar' + case 'update_calendar': + return 'google_calendar_update_calendar' + case 'delete_calendar': + return 'google_calendar_delete_calendar' case 'share_calendar': return 'google_calendar_share_calendar' + case 'update_acl': + return 'google_calendar_update_acl' case 'list_acl': return 'google_calendar_list_acl' case 'unshare_calendar': @@ -803,7 +837,10 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`, processedParams.addGoogleMeet === 'true' || processedParams.addGoogleMeet === true } - if (operation === 'share_calendar' && processedParams.sendNotifications !== undefined) { + if ( + ['share_calendar', 'update_acl'].includes(operation) && + processedParams.sendNotifications !== undefined + ) { processedParams.sendNotifications = processedParams.sendNotifications === 'true' || processedParams.sendNotifications === true @@ -907,7 +944,10 @@ export const GoogleCalendarV2Block: BlockConfig = { 'google_calendar_invite_v2', 'google_calendar_freebusy_v2', 'google_calendar_create_calendar_v2', + 'google_calendar_update_calendar_v2', + 'google_calendar_delete_calendar_v2', 'google_calendar_share_calendar_v2', + 'google_calendar_update_acl_v2', 'google_calendar_list_acl_v2', 'google_calendar_unshare_calendar_v2', ], @@ -946,6 +986,7 @@ export const GoogleCalendarV2Block: BlockConfig = { scope: { type: 'json', description: 'Grantee scope (share operation)' }, rules: { type: 'json', description: 'List of ACL sharing rules (list sharing operation)' }, ruleId: { type: 'string', description: 'Removed ACL rule ID (remove sharing operation)' }, + calendarId: { type: 'string', description: 'Deleted calendar ID (delete calendar operation)' }, nextPageToken: { type: 'string', description: 'Next page token' }, timeZone: { type: 'string', description: 'Calendar time zone' }, }, diff --git a/apps/sim/tools/google_calendar/delete_calendar.ts b/apps/sim/tools/google_calendar/delete_calendar.ts new file mode 100644 index 00000000000..73cb30259e0 --- /dev/null +++ b/apps/sim/tools/google_calendar/delete_calendar.ts @@ -0,0 +1,126 @@ +import { CALENDAR_API_BASE } from '@/tools/google_calendar/types' +import type { ToolConfig } from '@/tools/types' + +export interface GoogleCalendarDeleteCalendarParams { + accessToken: string + calendarId: string +} + +interface GoogleCalendarDeleteCalendarResponse { + success: boolean + output: { + content: string + metadata: { + calendarId: string + deleted: boolean + } + } +} + +const buildDeleteCalendarUrl = (params: GoogleCalendarDeleteCalendarParams) => + `${CALENDAR_API_BASE}/calendars/${encodeURIComponent(params.calendarId.trim())}` + +export const deleteCalendarTool: ToolConfig< + GoogleCalendarDeleteCalendarParams, + GoogleCalendarDeleteCalendarResponse +> = { + id: 'google_calendar_delete_calendar', + name: 'Google Calendar Delete Calendar', + description: 'Permanently delete a secondary calendar (not the primary calendar)', + version: '1.0.0', + + oauth: { + required: true, + provider: 'google-calendar', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Access token for Google Calendar API', + }, + calendarId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'Secondary calendar ID to delete (e.g., calendar@group.calendar.google.com). The primary calendar cannot be deleted.', + }, + }, + + request: { + url: buildDeleteCalendarUrl, + method: 'DELETE', + headers: (params: GoogleCalendarDeleteCalendarParams) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response: Response, params) => { + if (response.status === 204 || response.ok) { + return { + success: true, + output: { + content: 'Calendar successfully deleted', + metadata: { + calendarId: params?.calendarId || '', + deleted: true, + }, + }, + } + } + + const errorData = await response.json().catch(() => null) + throw new Error(errorData?.error?.message || 'Failed to delete calendar') + }, + + outputs: { + content: { type: 'string', description: 'Calendar deletion confirmation message' }, + metadata: { + type: 'json', + description: 'Deletion details including calendar ID', + }, + }, +} + +interface GoogleCalendarDeleteCalendarV2Response { + success: boolean + output: { + calendarId: string + deleted: boolean + } +} + +export const deleteCalendarV2Tool: ToolConfig< + GoogleCalendarDeleteCalendarParams, + GoogleCalendarDeleteCalendarV2Response +> = { + id: 'google_calendar_delete_calendar_v2', + name: 'Google Calendar Delete Calendar', + description: 'Permanently delete a secondary calendar. Returns API-aligned fields only.', + version: '2.0.0', + oauth: deleteCalendarTool.oauth, + params: deleteCalendarTool.params, + request: deleteCalendarTool.request, + transformResponse: async (response: Response, params) => { + if (response.status === 204 || response.ok) { + return { + success: true, + output: { + calendarId: params?.calendarId || '', + deleted: true, + }, + } + } + + const errorData = await response.json().catch(() => null) + throw new Error(errorData?.error?.message || 'Failed to delete calendar') + }, + outputs: { + calendarId: { type: 'string', description: 'Deleted calendar ID' }, + deleted: { type: 'boolean', description: 'Whether deletion was successful' }, + }, +} diff --git a/apps/sim/tools/google_calendar/get.ts b/apps/sim/tools/google_calendar/get.ts index b99c8754881..294e571a6f9 100644 --- a/apps/sim/tools/google_calendar/get.ts +++ b/apps/sim/tools/google_calendar/get.ts @@ -92,11 +92,11 @@ interface GoogleCalendarGetV2Response { summary: string | null description: string | null location: string | null - start: any - end: any - attendees: any | null - creator: any - organizer: any + start: GoogleCalendarApiEventResponse['start'] + end: GoogleCalendarApiEventResponse['end'] + attendees: GoogleCalendarApiEventResponse['attendees'] | null + creator: GoogleCalendarApiEventResponse['creator'] + organizer: GoogleCalendarApiEventResponse['organizer'] } } diff --git a/apps/sim/tools/google_calendar/index.ts b/apps/sim/tools/google_calendar/index.ts index 22d3ca97a9f..ed6b600d2b0 100644 --- a/apps/sim/tools/google_calendar/index.ts +++ b/apps/sim/tools/google_calendar/index.ts @@ -1,6 +1,7 @@ import { createTool, createV2Tool } from '@/tools/google_calendar/create' import { createCalendarTool, createCalendarV2Tool } from '@/tools/google_calendar/create_calendar' import { deleteTool, deleteV2Tool } from '@/tools/google_calendar/delete' +import { deleteCalendarTool, deleteCalendarV2Tool } from '@/tools/google_calendar/delete_calendar' import { freebusyTool, freebusyV2Tool } from '@/tools/google_calendar/freebusy' import { getTool, getV2Tool } from '@/tools/google_calendar/get' import { instancesTool, instancesV2Tool } from '@/tools/google_calendar/instances' @@ -16,10 +17,13 @@ import { unshareCalendarV2Tool, } from '@/tools/google_calendar/unshare_calendar' import { updateTool, updateV2Tool } from '@/tools/google_calendar/update' +import { updateAclTool, updateAclV2Tool } from '@/tools/google_calendar/update_acl' +import { updateCalendarTool, updateCalendarV2Tool } from '@/tools/google_calendar/update_calendar' export const googleCalendarCreateTool = createTool export const googleCalendarCreateCalendarTool = createCalendarTool export const googleCalendarDeleteTool = deleteTool +export const googleCalendarDeleteCalendarTool = deleteCalendarTool export const googleCalendarFreeBusyTool = freebusyTool export const googleCalendarGetTool = getTool export const googleCalendarInstancesTool = instancesTool @@ -32,10 +36,13 @@ export const googleCalendarQuickAddTool = quickAddTool export const googleCalendarShareCalendarTool = shareCalendarTool export const googleCalendarUnshareCalendarTool = unshareCalendarTool export const googleCalendarUpdateTool = updateTool +export const googleCalendarUpdateAclTool = updateAclTool +export const googleCalendarUpdateCalendarTool = updateCalendarTool export const googleCalendarCreateV2Tool = createV2Tool export const googleCalendarCreateCalendarV2Tool = createCalendarV2Tool export const googleCalendarDeleteV2Tool = deleteV2Tool +export const googleCalendarDeleteCalendarV2Tool = deleteCalendarV2Tool export const googleCalendarFreeBusyV2Tool = freebusyV2Tool export const googleCalendarGetV2Tool = getV2Tool export const googleCalendarInstancesV2Tool = instancesV2Tool @@ -48,3 +55,5 @@ export const googleCalendarQuickAddV2Tool = quickAddV2Tool export const googleCalendarShareCalendarV2Tool = shareCalendarV2Tool export const googleCalendarUnshareCalendarV2Tool = unshareCalendarV2Tool export const googleCalendarUpdateV2Tool = updateV2Tool +export const googleCalendarUpdateAclV2Tool = updateAclV2Tool +export const googleCalendarUpdateCalendarV2Tool = updateCalendarV2Tool diff --git a/apps/sim/tools/google_calendar/instances.ts b/apps/sim/tools/google_calendar/instances.ts index f835b695e14..dd9c6130ccf 100644 --- a/apps/sim/tools/google_calendar/instances.ts +++ b/apps/sim/tools/google_calendar/instances.ts @@ -212,12 +212,32 @@ export const instancesTool: ToolConfig< }, } +interface GoogleCalendarInstancesV2Instance { + id: string + htmlLink: string + status: string + summary: string | null + description: string | null + location: string | null + start: GoogleCalendarApiEventResponse['start'] + end: GoogleCalendarApiEventResponse['end'] + attendees: GoogleCalendarApiEventResponse['attendees'] | null + creator: GoogleCalendarApiEventResponse['creator'] + organizer: GoogleCalendarApiEventResponse['organizer'] + recurringEventId: string + originalStartTime: { + dateTime?: string + date?: string + timeZone?: string + } +} + interface GoogleCalendarInstancesV2Response { success: boolean output: { nextPageToken: string | null timeZone: string | null - instances: Array> + instances: GoogleCalendarInstancesV2Instance[] } } diff --git a/apps/sim/tools/google_calendar/move.ts b/apps/sim/tools/google_calendar/move.ts index 7332db60de4..e5148622b18 100644 --- a/apps/sim/tools/google_calendar/move.ts +++ b/apps/sim/tools/google_calendar/move.ts @@ -157,11 +157,11 @@ interface GoogleCalendarMoveV2Response { summary: string | null description: string | null location: string | null - start: any - end: any - attendees: any | null - creator: any - organizer: any + start: GoogleCalendarApiEventResponse['start'] + end: GoogleCalendarApiEventResponse['end'] + attendees: GoogleCalendarApiEventResponse['attendees'] | null + creator: GoogleCalendarApiEventResponse['creator'] + organizer: GoogleCalendarApiEventResponse['organizer'] } } diff --git a/apps/sim/tools/google_calendar/quick_add.ts b/apps/sim/tools/google_calendar/quick_add.ts index 8c33d2d3129..32252e986ad 100644 --- a/apps/sim/tools/google_calendar/quick_add.ts +++ b/apps/sim/tools/google_calendar/quick_add.ts @@ -1,6 +1,7 @@ import { createLogger } from '@sim/logger' import { CALENDAR_API_BASE, + type GoogleCalendarApiEventResponse, type GoogleCalendarQuickAddParams, type GoogleCalendarQuickAddResponse, } from '@/tools/google_calendar/types' @@ -77,9 +78,9 @@ export const quickAddTool: ToolConfig< }, transformResponse: async (response: Response, params) => { - const data = await response.json() + const data: GoogleCalendarApiEventResponse = await response.json() - let finalEventData = data + let finalEventData: GoogleCalendarApiEventResponse = data if (params?.attendees) { let attendeeList: string[] = [] const attendees = params.attendees as string | string[] @@ -181,16 +182,16 @@ interface GoogleCalendarQuickAddV2Response { success: boolean output: { id: string - htmlLink?: string - status?: string - summary?: string - description?: string - location?: string - start?: any - end?: any - attendees?: any - creator?: any - organizer?: any + htmlLink: string + status: string + summary: string | null + description: string | null + location: string | null + start: GoogleCalendarApiEventResponse['start'] + end: GoogleCalendarApiEventResponse['end'] + attendees: GoogleCalendarApiEventResponse['attendees'] | null + creator: GoogleCalendarApiEventResponse['creator'] + organizer: GoogleCalendarApiEventResponse['organizer'] } } @@ -206,9 +207,9 @@ export const quickAddV2Tool: ToolConfig< params: quickAddTool.params, request: quickAddTool.request, transformResponse: async (response: Response, params) => { - const data = await response.json() + const data: GoogleCalendarApiEventResponse = await response.json() - let finalEventData = data + let finalEventData: GoogleCalendarApiEventResponse = data if (params?.attendees) { let attendeeList: string[] = [] const attendees = params.attendees as string | string[] diff --git a/apps/sim/tools/google_calendar/update_acl.ts b/apps/sim/tools/google_calendar/update_acl.ts new file mode 100644 index 00000000000..860650be675 --- /dev/null +++ b/apps/sim/tools/google_calendar/update_acl.ts @@ -0,0 +1,156 @@ +import { CALENDAR_API_BASE, type GoogleCalendarApiAclRule } from '@/tools/google_calendar/types' +import type { ToolConfig } from '@/tools/types' + +type GoogleCalendarAclRole = 'freeBusyReader' | 'reader' | 'writer' | 'owner' + +export interface GoogleCalendarUpdateAclParams { + accessToken: string + calendarId?: string + ruleId: string + role: GoogleCalendarAclRole + sendNotifications?: boolean +} + +export interface GoogleCalendarUpdateAclResponse { + success: boolean + output: { + content: string + metadata: { + id: string + role: string + scope: { type: string; value?: string } + } + } +} + +const buildUpdateAclUrl = (params: GoogleCalendarUpdateAclParams) => { + const calendarId = params.calendarId?.trim() || 'primary' + const queryParams = new URLSearchParams() + if (params.sendNotifications !== undefined) { + queryParams.append('sendNotifications', String(params.sendNotifications)) + } + const queryString = queryParams.toString() + return `${CALENDAR_API_BASE}/calendars/${encodeURIComponent(calendarId)}/acl/${encodeURIComponent(params.ruleId.trim())}${queryString ? `?${queryString}` : ''}` +} + +export const updateAclTool: ToolConfig< + GoogleCalendarUpdateAclParams, + GoogleCalendarUpdateAclResponse +> = { + id: 'google_calendar_update_acl', + name: 'Google Calendar Update Sharing', + description: 'Change the access role granted by an existing calendar sharing (ACL) rule', + version: '1.0.0', + + oauth: { + required: true, + provider: 'google-calendar', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Access token for Google Calendar API', + }, + calendarId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Calendar ID to modify (e.g., primary or calendar@group.calendar.google.com)', + }, + ruleId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'ACL rule ID to update (e.g., user:person@example.com)', + }, + role: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'New access role to grant: freeBusyReader, reader, writer, or owner', + }, + sendNotifications: { + type: 'boolean', + required: false, + visibility: 'user-only', + description: 'Whether to send a notification email about the change. Defaults to true.', + }, + }, + + request: { + url: buildUpdateAclUrl, + method: 'PATCH', + headers: (params: GoogleCalendarUpdateAclParams) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: (params: GoogleCalendarUpdateAclParams) => ({ role: params.role }), + }, + + transformResponse: async (response: Response) => { + const data: GoogleCalendarApiAclRule = await response.json() + + return { + success: true, + output: { + content: `Updated sharing rule for ${data.scope?.value || data.scope?.type} to ${data.role}`, + metadata: { + id: data.id, + role: data.role, + scope: data.scope, + }, + }, + } + }, + + outputs: { + content: { type: 'string', description: 'Sharing update confirmation message' }, + metadata: { + type: 'json', + description: 'Updated ACL rule (id, role, scope)', + }, + }, +} + +interface GoogleCalendarUpdateAclV2Response { + success: boolean + output: { + id: string + role: string + scope: { type: string; value?: string } + } +} + +export const updateAclV2Tool: ToolConfig< + GoogleCalendarUpdateAclParams, + GoogleCalendarUpdateAclV2Response +> = { + id: 'google_calendar_update_acl_v2', + name: 'Google Calendar Update Sharing', + description: + 'Change the access role granted by an existing calendar sharing (ACL) rule. Returns API-aligned fields only.', + version: '2.0.0', + oauth: updateAclTool.oauth, + params: updateAclTool.params, + request: updateAclTool.request, + transformResponse: async (response: Response) => { + const data: GoogleCalendarApiAclRule = await response.json() + + return { + success: true, + output: { + id: data.id, + role: data.role, + scope: data.scope, + }, + } + }, + outputs: { + id: { type: 'string', description: 'ACL rule ID' }, + role: { type: 'string', description: 'Granted access role' }, + scope: { type: 'json', description: 'Grantee scope (type and value)' }, + }, +} diff --git a/apps/sim/tools/google_calendar/update_calendar.ts b/apps/sim/tools/google_calendar/update_calendar.ts new file mode 100644 index 00000000000..0c5e90ccaab --- /dev/null +++ b/apps/sim/tools/google_calendar/update_calendar.ts @@ -0,0 +1,177 @@ +import { + CALENDAR_API_BASE, + type GoogleCalendarApiCalendarResponse, +} from '@/tools/google_calendar/types' +import type { ToolConfig } from '@/tools/types' + +export interface GoogleCalendarUpdateCalendarParams { + accessToken: string + calendarId?: string + summary?: string + description?: string + location?: string + timeZone?: string +} + +export interface GoogleCalendarUpdateCalendarResponse { + success: boolean + output: { + content: string + metadata: { + id: string + summary: string + description?: string + location?: string + timeZone?: string + } + } +} + +const buildUpdateCalendarUrl = (params: GoogleCalendarUpdateCalendarParams) => { + const calendarId = params.calendarId?.trim() || 'primary' + return `${CALENDAR_API_BASE}/calendars/${encodeURIComponent(calendarId)}` +} + +const buildUpdateCalendarBody = (params: GoogleCalendarUpdateCalendarParams) => { + const body: Record = {} + if (params.summary !== undefined) body.summary = params.summary + if (params.description !== undefined) body.description = params.description + if (params.location !== undefined) body.location = params.location + if (params.timeZone !== undefined) body.timeZone = params.timeZone + return body +} + +export const updateCalendarTool: ToolConfig< + GoogleCalendarUpdateCalendarParams, + GoogleCalendarUpdateCalendarResponse +> = { + id: 'google_calendar_update_calendar', + name: 'Google Calendar Update Calendar', + description: "Update a secondary calendar's metadata (title, description, location, time zone)", + version: '1.0.0', + + oauth: { + required: true, + provider: 'google-calendar', + }, + + params: { + accessToken: { + type: 'string', + required: true, + visibility: 'hidden', + description: 'Access token for Google Calendar API', + }, + calendarId: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Calendar ID to update (e.g., primary or calendar@group.calendar.google.com)', + }, + summary: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New title for the calendar', + }, + description: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New description for the calendar', + }, + location: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New geographic location of the calendar as free-form text', + }, + timeZone: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'New time zone of the calendar as an IANA name (e.g., America/Los_Angeles)', + }, + }, + + request: { + url: buildUpdateCalendarUrl, + method: 'PATCH', + headers: (params: GoogleCalendarUpdateCalendarParams) => ({ + Authorization: `Bearer ${params.accessToken}`, + 'Content-Type': 'application/json', + }), + body: buildUpdateCalendarBody, + }, + + transformResponse: async (response: Response) => { + const data: GoogleCalendarApiCalendarResponse = await response.json() + + return { + success: true, + output: { + content: `Calendar "${data.summary}" updated successfully`, + metadata: { + id: data.id, + summary: data.summary, + description: data.description, + location: data.location, + timeZone: data.timeZone, + }, + }, + } + }, + + outputs: { + content: { type: 'string', description: 'Calendar update confirmation message' }, + metadata: { + type: 'json', + description: 'Updated calendar metadata (id, summary, description, location, timeZone)', + }, + }, +} + +interface GoogleCalendarUpdateCalendarV2Response { + success: boolean + output: { + id: string + summary: string + description: string | null + location: string | null + timeZone: string | null + } +} + +export const updateCalendarV2Tool: ToolConfig< + GoogleCalendarUpdateCalendarParams, + GoogleCalendarUpdateCalendarV2Response +> = { + id: 'google_calendar_update_calendar_v2', + name: 'Google Calendar Update Calendar', + description: "Update a secondary calendar's metadata. Returns API-aligned fields only.", + version: '2.0.0', + oauth: updateCalendarTool.oauth, + params: updateCalendarTool.params, + request: updateCalendarTool.request, + transformResponse: async (response: Response) => { + const data: GoogleCalendarApiCalendarResponse = await response.json() + + return { + success: true, + output: { + id: data.id, + summary: data.summary, + description: data.description ?? null, + location: data.location ?? null, + timeZone: data.timeZone ?? null, + }, + } + }, + outputs: { + id: { type: 'string', description: 'Calendar ID' }, + summary: { type: 'string', description: 'Calendar title' }, + description: { type: 'string', description: 'Calendar description', optional: true }, + location: { type: 'string', description: 'Calendar location', optional: true }, + timeZone: { type: 'string', description: 'Calendar time zone', optional: true }, + }, +} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 02c6f7c8e7b..26fe40ff0d2 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -1316,6 +1316,8 @@ import { googleCalendarCreateCalendarV2Tool, googleCalendarCreateTool, googleCalendarCreateV2Tool, + googleCalendarDeleteCalendarTool, + googleCalendarDeleteCalendarV2Tool, googleCalendarDeleteTool, googleCalendarDeleteV2Tool, googleCalendarFreeBusyTool, @@ -1340,6 +1342,10 @@ import { googleCalendarShareCalendarV2Tool, googleCalendarUnshareCalendarTool, googleCalendarUnshareCalendarV2Tool, + googleCalendarUpdateAclTool, + googleCalendarUpdateAclV2Tool, + googleCalendarUpdateCalendarTool, + googleCalendarUpdateCalendarV2Tool, googleCalendarUpdateTool, googleCalendarUpdateV2Tool, } from '@/tools/google_calendar' @@ -7622,6 +7628,8 @@ export const tools: Record = { google_calendar_create_calendar_v2: googleCalendarCreateCalendarV2Tool, google_calendar_delete: googleCalendarDeleteTool, google_calendar_delete_v2: googleCalendarDeleteV2Tool, + google_calendar_delete_calendar: googleCalendarDeleteCalendarTool, + google_calendar_delete_calendar_v2: googleCalendarDeleteCalendarV2Tool, google_calendar_freebusy: googleCalendarFreeBusyTool, google_calendar_freebusy_v2: googleCalendarFreeBusyV2Tool, google_calendar_get: googleCalendarGetTool, @@ -7646,6 +7654,10 @@ export const tools: Record = { google_calendar_unshare_calendar_v2: googleCalendarUnshareCalendarV2Tool, google_calendar_update: googleCalendarUpdateTool, google_calendar_update_v2: googleCalendarUpdateV2Tool, + google_calendar_update_acl: googleCalendarUpdateAclTool, + google_calendar_update_acl_v2: googleCalendarUpdateAclV2Tool, + google_calendar_update_calendar: googleCalendarUpdateCalendarTool, + google_calendar_update_calendar_v2: googleCalendarUpdateCalendarV2Tool, google_contacts_create: googleContactsCreateTool, google_contacts_delete: googleContactsDeleteTool, google_contacts_get: googleContactsGetTool, From ee6cbf8f9ec6d716583fd4140880ad5732017487 Mon Sep 17 00:00:00 2001 From: waleed Date: Tue, 7 Jul 2026 11:46:18 -0700 Subject: [PATCH 2/2] fix(google-calendar): dedupe GoogleCalendarAclRole type in update_acl.ts export it from types.ts and import instead of redeclaring locally --- apps/sim/tools/google_calendar/types.ts | 2 +- apps/sim/tools/google_calendar/update_acl.ts | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/sim/tools/google_calendar/types.ts b/apps/sim/tools/google_calendar/types.ts index b48d884fb30..2a249aaa06c 100644 --- a/apps/sim/tools/google_calendar/types.ts +++ b/apps/sim/tools/google_calendar/types.ts @@ -120,7 +120,7 @@ export interface GoogleCalendarCreateCalendarParams { timeZone?: string } -type GoogleCalendarAclRole = 'freeBusyReader' | 'reader' | 'writer' | 'owner' +export type GoogleCalendarAclRole = 'freeBusyReader' | 'reader' | 'writer' | 'owner' type GoogleCalendarAclScopeType = 'user' | 'group' | 'domain' | 'default' export interface GoogleCalendarShareCalendarParams { diff --git a/apps/sim/tools/google_calendar/update_acl.ts b/apps/sim/tools/google_calendar/update_acl.ts index 860650be675..d11b77703c8 100644 --- a/apps/sim/tools/google_calendar/update_acl.ts +++ b/apps/sim/tools/google_calendar/update_acl.ts @@ -1,8 +1,10 @@ -import { CALENDAR_API_BASE, type GoogleCalendarApiAclRule } from '@/tools/google_calendar/types' +import { + CALENDAR_API_BASE, + type GoogleCalendarAclRole, + type GoogleCalendarApiAclRule, +} from '@/tools/google_calendar/types' import type { ToolConfig } from '@/tools/types' -type GoogleCalendarAclRole = 'freeBusyReader' | 'reader' | 'writer' | 'owner' - export interface GoogleCalendarUpdateAclParams { accessToken: string calendarId?: string