Merge pull request #756 from AnishSarkar22/fix/google-calendar-connectors

fix: google calendar issues (composio & non-composio)
This commit is contained in:
Rohan Verma 2026-01-30 14:40:26 -08:00 committed by GitHub
commit 4e04b4053a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 54 additions and 39 deletions

View file

@ -246,15 +246,18 @@ class GoogleCalendarConnector:
dt_start = isoparse(start_date) dt_start = isoparse(start_date)
dt_end = isoparse(end_date) dt_end = isoparse(end_date)
# Set start to beginning of day (00:00:00) and end to end of day (23:59:59)
# This ensures same-date queries work (e.g., start=2026-01-23, end=2026-01-23)
# and matches the Composio connector behavior
if dt_start.tzinfo is None: if dt_start.tzinfo is None:
dt_start = dt_start.replace(tzinfo=pytz.UTC) dt_start = dt_start.replace(hour=0, minute=0, second=0, tzinfo=pytz.UTC)
else: else:
dt_start = dt_start.astimezone(pytz.UTC) dt_start = dt_start.astimezone(pytz.UTC).replace(hour=0, minute=0, second=0)
if dt_end.tzinfo is None: if dt_end.tzinfo is None:
dt_end = dt_end.replace(tzinfo=pytz.UTC) dt_end = dt_end.replace(hour=23, minute=59, second=59, tzinfo=pytz.UTC)
else: else:
dt_end = dt_end.astimezone(pytz.UTC) dt_end = dt_end.astimezone(pytz.UTC).replace(hour=23, minute=59, second=59)
if dt_start >= dt_end: if dt_start >= dt_end:
return [], ( return [], (

View file

@ -191,10 +191,10 @@ async def index_google_calendar_events(
) )
else: else:
calculated_start_date = datetime.now() - timedelta( calculated_start_date = datetime.now() - timedelta(
days=30 days=365
) # Use 30 days as default for calendar events ) # Use 365 days as default for calendar events (matches frontend)
logger.info( logger.info(
f"No last_indexed_at found, using {calculated_start_date.strftime('%Y-%m-%d')} (30 days ago) as start date" f"No last_indexed_at found, using {calculated_start_date.strftime('%Y-%m-%d')} (365 days ago) as start date"
) )
# Use calculated dates if not provided # Use calculated dates if not provided
@ -209,23 +209,6 @@ async def index_google_calendar_events(
start_date_str = start_date start_date_str = start_date
end_date_str = end_date end_date_str = end_date
# If start_date and end_date are the same, adjust end_date to be one day later
# to ensure valid date range (start_date must be strictly before end_date)
if start_date_str == end_date_str:
# Parse the date and add one day to ensure valid range
dt = isoparse(end_date_str)
if dt.tzinfo is None:
dt = dt.replace(tzinfo=pytz.UTC)
else:
dt = dt.astimezone(pytz.UTC)
# Add one day to end_date to make it strictly after start_date
dt_end = dt + timedelta(days=1)
end_date_str = dt_end.strftime("%Y-%m-%d")
logger.info(
f"Adjusted end_date from {end_date} to {end_date_str} "
f"to ensure valid date range (start_date must be strictly before end_date)"
)
await task_logger.log_task_progress( await task_logger.log_task_progress(
log_entry, log_entry,
f"Fetching Google Calendar events from {start_date_str} to {end_date_str}", f"Fetching Google Calendar events from {start_date_str} to {end_date_str}",

View file

@ -11,7 +11,13 @@ def get_model_context_window(model_name: str) -> int:
"""Get the total context window size for a model (input + output tokens).""" """Get the total context window size for a model (input + output tokens)."""
try: try:
model_info = get_model_info(model_name) model_info = get_model_info(model_name)
context_window = model_info.get("max_input_tokens", 4096) # Default fallback context_window = model_info.get("max_input_tokens")
# Handle case where key exists but value is None
if context_window is None:
print(
f"Warning: max_input_tokens is None for {model_name}, using default 4096 tokens."
)
return 4096 # Conservative fallback
return context_window return context_window
except Exception as e: except Exception as e:
print( print(

View file

@ -15,6 +15,7 @@ interface DateRangeSelectorProps {
onStartDateChange: (date: Date | undefined) => void; onStartDateChange: (date: Date | undefined) => void;
onEndDateChange: (date: Date | undefined) => void; onEndDateChange: (date: Date | undefined) => void;
allowFutureDates?: boolean; // Allow future dates for calendar connectors allowFutureDates?: boolean; // Allow future dates for calendar connectors
lastIndexedAt?: string | null; // Last sync timestamp to show in default placeholder
} }
export const DateRangeSelector: FC<DateRangeSelectorProps> = ({ export const DateRangeSelector: FC<DateRangeSelectorProps> = ({
@ -23,7 +24,21 @@ export const DateRangeSelector: FC<DateRangeSelectorProps> = ({
onStartDateChange, onStartDateChange,
onEndDateChange, onEndDateChange,
allowFutureDates = false, allowFutureDates = false,
lastIndexedAt,
}) => { }) => {
// Get the placeholder text for start date based on whether connector was previously indexed
const getStartDatePlaceholder = () => {
if (lastIndexedAt) {
const date = new Date(lastIndexedAt);
const currentYear = new Date().getFullYear();
const indexedYear = date.getFullYear();
// Show year only if different from current year
const formatStr = indexedYear === currentYear ? "MMM d, HH:mm" : "MMM d, yyyy HH:mm";
const formattedDate = format(date, formatStr);
return `Since (${formattedDate})`;
}
return "Default (1 year ago)";
};
const handleLast30Days = () => { const handleLast30Days = () => {
const today = new Date(); const today = new Date();
onStartDateChange(subDays(today, 30)); onStartDateChange(subDays(today, 30));
@ -73,7 +88,7 @@ export const DateRangeSelector: FC<DateRangeSelectorProps> = ({
)} )}
> >
<CalendarIcon className="mr-2 h-4 w-4" /> <CalendarIcon className="mr-2 h-4 w-4" />
{startDate ? format(startDate, "PPP") : "Default (1 year ago)"} {startDate ? format(startDate, "PPP") : getStartDatePlaceholder()}
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="w-auto p-0 z-[100]" align="start"> <PopoverContent className="w-auto p-0 z-[100]" align="start">

View file

@ -227,6 +227,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
connector.connector_type === "COMPOSIO_GOOGLE_CALENDAR_CONNECTOR" || connector.connector_type === "COMPOSIO_GOOGLE_CALENDAR_CONNECTOR" ||
connector.connector_type === "LUMA_CONNECTOR" connector.connector_type === "LUMA_CONNECTOR"
} }
lastIndexedAt={connector.last_indexed_at}
/> />
)} )}

View file

@ -165,6 +165,7 @@ export const IndexingConfigurationView: FC<IndexingConfigurationViewProps> = ({
config.connectorType === "COMPOSIO_GOOGLE_CALENDAR_CONNECTOR" || config.connectorType === "COMPOSIO_GOOGLE_CALENDAR_CONNECTOR" ||
config.connectorType === "LUMA_CONNECTOR" config.connectorType === "LUMA_CONNECTOR"
} }
lastIndexedAt={connector?.last_indexed_at}
/> />
)} )}

View file

@ -38,7 +38,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content <DialogPrimitive.Content
ref={ref} ref={ref}
className={cn( className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-lg focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0", "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 rounded-lg focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0",
className className
)} )}
{...props} {...props}

View file

@ -49,10 +49,12 @@ class ConnectorsApiService {
throw new ValidationError(`Invalid request: ${errorMessage}`); throw new ValidationError(`Invalid request: ${errorMessage}`);
} }
// Transform query params to be string values // Transform query params to be string values, filtering out undefined/null
const transformedQueryParams = parsedRequest.data.queryParams const transformedQueryParams = parsedRequest.data.queryParams
? Object.fromEntries( ? Object.fromEntries(
Object.entries(parsedRequest.data.queryParams).map(([k, v]) => { Object.entries(parsedRequest.data.queryParams)
.filter(([_, v]) => v !== undefined && v !== null)
.map(([k, v]) => {
return [k, String(v)]; return [k, String(v)];
}) })
) )
@ -102,9 +104,11 @@ class ConnectorsApiService {
const { data, queryParams } = parsedRequest.data; const { data, queryParams } = parsedRequest.data;
// Transform query params to be string values // Transform query params to be string values, filtering out undefined/null
const transformedQueryParams = Object.fromEntries( const transformedQueryParams = Object.fromEntries(
Object.entries(queryParams).map(([k, v]) => { Object.entries(queryParams)
.filter(([_, v]) => v !== undefined && v !== null)
.map(([k, v]) => {
return [k, String(v)]; return [k, String(v)];
}) })
); );
@ -174,9 +178,11 @@ class ConnectorsApiService {
const { connector_id, queryParams, body } = parsedRequest.data; const { connector_id, queryParams, body } = parsedRequest.data;
// Transform query params to be string values // Transform query params to be string values, filtering out undefined/null
const transformedQueryParams = Object.fromEntries( const transformedQueryParams = Object.fromEntries(
Object.entries(queryParams).map(([k, v]) => { Object.entries(queryParams)
.filter(([_, v]) => v !== undefined && v !== null)
.map(([k, v]) => {
return [k, String(v)]; return [k, String(v)];
}) })
); );