Skip to content

Commit 9ec7c80

Browse files
committed
fix(google-calendar): address review — trust offset timezones, make list_acl showDeleted usable, harden unshare error parse, clarify update attendees
1 parent 80f55de commit 9ec7c80

6 files changed

Lines changed: 31 additions & 23 deletions

File tree

apps/sim/blocks/blocks/google_calendar.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,14 @@ Return ONLY the RRULE string - no explanations, no extra text.`,
220220
],
221221
value: () => 'false',
222222
},
223+
{
224+
id: 'timeZone',
225+
title: 'Time Zone',
226+
type: 'short-input',
227+
placeholder: 'America/Los_Angeles',
228+
condition: { field: 'operation', value: ['create', 'update'] },
229+
mode: 'advanced',
230+
},
223231

224232
{
225233
id: 'timeMin',

apps/sim/tools/google_calendar/create.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ export const createTool: ToolConfig<GoogleCalendarCreateParams, GoogleCalendarCr
7575
required: false,
7676
visibility: 'user-or-llm',
7777
description:
78-
'Time zone (e.g., America/Los_Angeles). Required if datetime does not include offset. Defaults to America/Los_Angeles if not provided.',
79-
default: 'America/Los_Angeles',
78+
'IANA time zone (e.g., America/Los_Angeles). Used as-is when provided. For recurring events a time zone is required to expand the recurrence correctly; for one-off events it is only needed when the datetime omits a UTC offset (a naive datetime defaults to America/Los_Angeles).',
8079
},
8180
attendees: {
8281
type: 'array',
@@ -131,8 +130,8 @@ export const createTool: ToolConfig<GoogleCalendarCreateParams, GoogleCalendarCr
131130

132131
const eventData: GoogleCalendarEventRequestBody = {
133132
summary: params.summary,
134-
start: buildEventDateTime(params.startDateTime, params.timeZone, isRecurring),
135-
end: buildEventDateTime(params.endDateTime, params.timeZone, isRecurring),
133+
start: buildEventDateTime(params.startDateTime, params.timeZone),
134+
end: buildEventDateTime(params.endDateTime, params.timeZone),
136135
}
137136

138137
if (params.description) {

apps/sim/tools/google_calendar/list_acl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const listAclTool: ToolConfig<GoogleCalendarListAclParams, GoogleCalendar
4545
showDeleted: {
4646
type: 'boolean',
4747
required: false,
48-
visibility: 'hidden',
48+
visibility: 'user-only',
4949
description: 'Include deleted ACL rules (with role "none")',
5050
},
5151
},

apps/sim/tools/google_calendar/unshare_calendar.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ export const unshareCalendarTool: ToolConfig<
6868
}
6969
}
7070

71-
const errorData = await response.json()
72-
throw new Error(errorData.error?.message || 'Failed to remove sharing rule')
71+
const errorData = await response.json().catch(() => null)
72+
throw new Error(errorData?.error?.message || 'Failed to remove sharing rule')
7373
},
7474

7575
outputs: {
@@ -112,8 +112,8 @@ export const unshareCalendarV2Tool: ToolConfig<
112112
}
113113
}
114114

115-
const errorData = await response.json()
116-
throw new Error(errorData.error?.message || 'Failed to remove sharing rule')
115+
const errorData = await response.json().catch(() => null)
116+
throw new Error(errorData?.error?.message || 'Failed to remove sharing rule')
117117
},
118118
outputs: {
119119
ruleId: { type: 'string', description: 'Removed ACL rule ID' },

apps/sim/tools/google_calendar/update.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,14 @@ export const updateTool: ToolConfig<GoogleCalendarUpdateParams, GoogleCalendarUp
8383
required: false,
8484
visibility: 'user-or-llm',
8585
description:
86-
'Time zone (e.g., America/Los_Angeles). Required if datetime does not include offset.',
86+
'IANA time zone (e.g., America/Los_Angeles). Used as-is when provided. For recurring events a time zone is required to expand the recurrence correctly; for one-off events it is only needed when the datetime omits a UTC offset.',
8787
},
8888
attendees: {
8989
type: 'array',
9090
required: false,
9191
visibility: 'user-or-llm',
92-
description: 'Array of attendee email addresses (replaces the existing attendee list)',
92+
description:
93+
'Array of attendee email addresses. When one or more emails are provided, they replace the existing attendee list. Leaving this empty keeps the current attendees unchanged (it does not clear them).',
9394
},
9495
recurrence: {
9596
type: 'string',
@@ -150,11 +151,11 @@ export const updateTool: ToolConfig<GoogleCalendarUpdateParams, GoogleCalendarUp
150151
}
151152

152153
if (params.startDateTime !== undefined) {
153-
updateData.start = buildEventDateTime(params.startDateTime, params.timeZone, isRecurring)
154+
updateData.start = buildEventDateTime(params.startDateTime, params.timeZone)
154155
}
155156

156157
if (params.endDateTime !== undefined) {
157-
updateData.end = buildEventDateTime(params.endDateTime, params.timeZone, isRecurring)
158+
updateData.end = buildEventDateTime(params.endDateTime, params.timeZone)
158159
}
159160

160161
const attendees = normalizeAttendees(params.attendees)

apps/sim/tools/google_calendar/utils.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ const TZ_OFFSET_PATTERN = /([+-]\d{2}:?\d{2}|Z)$/
1010
* Build a Google Calendar event date/time object from a user-supplied value.
1111
*
1212
* A date-only value (e.g. `2025-06-03`) produces an all-day `{ date }` object.
13-
* A datetime value produces `{ dateTime, timeZone? }`. A timezone is attached when
14-
* one is explicitly provided, when the datetime carries no UTC offset (so the time
15-
* is unambiguous), or when `requireTimeZone` is set — the Calendar API requires a
16-
* timezone on the start/end of recurring events.
13+
* A datetime value produces `{ dateTime, timeZone? }`. An explicitly provided
14+
* timezone always wins. Otherwise a default zone is attached only for "naive"
15+
* datetimes that carry no UTC offset — when an offset is present it is authoritative
16+
* and is never overridden with a guessed zone, which would misalign the time.
17+
*
18+
* For recurring events the Calendar API requires a named `timeZone` on start/end;
19+
* callers should pass the user's timezone explicitly (an RFC3339 offset alone is
20+
* insufficient to expand a recurrence across DST).
1721
*/
18-
export function buildEventDateTime(
19-
value: string,
20-
timeZone: string | undefined,
21-
requireTimeZone = false
22-
): EventDateTime {
22+
export function buildEventDateTime(value: string, timeZone: string | undefined): EventDateTime {
2323
const isDateOnly = !value.includes('T')
2424
if (isDateOnly) {
2525
return { date: value }
@@ -29,7 +29,7 @@ export function buildEventDateTime(
2929
const result: EventDateTime = { dateTime: value }
3030
if (timeZone) {
3131
result.timeZone = timeZone
32-
} else if (!hasOffset || requireTimeZone) {
32+
} else if (!hasOffset) {
3333
result.timeZone = DEFAULT_TIME_ZONE
3434
}
3535
return result

0 commit comments

Comments
 (0)