diff --git a/surfsense_backend/app/connectors/google_calendar_connector.py b/surfsense_backend/app/connectors/google_calendar_connector.py index d8160cf25..7e24f3642 100644 --- a/surfsense_backend/app/connectors/google_calendar_connector.py +++ b/surfsense_backend/app/connectors/google_calendar_connector.py @@ -246,15 +246,18 @@ class GoogleCalendarConnector: dt_start = isoparse(start_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: - dt_start = dt_start.replace(tzinfo=pytz.UTC) + dt_start = dt_start.replace(hour=0, minute=0, second=0, tzinfo=pytz.UTC) 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: - dt_end = dt_end.replace(tzinfo=pytz.UTC) + dt_end = dt_end.replace(hour=23, minute=59, second=59, tzinfo=pytz.UTC) 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: return [], ( diff --git a/surfsense_backend/app/tasks/connector_indexers/google_calendar_indexer.py b/surfsense_backend/app/tasks/connector_indexers/google_calendar_indexer.py index 2365ff984..81d33b5e2 100644 --- a/surfsense_backend/app/tasks/connector_indexers/google_calendar_indexer.py +++ b/surfsense_backend/app/tasks/connector_indexers/google_calendar_indexer.py @@ -191,10 +191,10 @@ async def index_google_calendar_events( ) else: calculated_start_date = datetime.now() - timedelta( - days=30 - ) # Use 30 days as default for calendar events + days=365 + ) # Use 365 days as default for calendar events (matches frontend) 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 @@ -209,23 +209,6 @@ async def index_google_calendar_events( start_date_str = start_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( log_entry, f"Fetching Google Calendar events from {start_date_str} to {end_date_str}", diff --git a/surfsense_backend/app/utils/document_converters.py b/surfsense_backend/app/utils/document_converters.py index 279b1dbf6..d7e1db71d 100644 --- a/surfsense_backend/app/utils/document_converters.py +++ b/surfsense_backend/app/utils/document_converters.py @@ -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).""" try: 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 except Exception as e: print( diff --git a/surfsense_web/components/assistant-ui/connector-popup/components/date-range-selector.tsx b/surfsense_web/components/assistant-ui/connector-popup/components/date-range-selector.tsx index 48dc2a6c2..7490aa959 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/components/date-range-selector.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/components/date-range-selector.tsx @@ -15,6 +15,7 @@ interface DateRangeSelectorProps { onStartDateChange: (date: Date | undefined) => void; onEndDateChange: (date: Date | undefined) => void; allowFutureDates?: boolean; // Allow future dates for calendar connectors + lastIndexedAt?: string | null; // Last sync timestamp to show in default placeholder } export const DateRangeSelector: FC = ({ @@ -23,7 +24,21 @@ export const DateRangeSelector: FC = ({ onStartDateChange, onEndDateChange, 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 today = new Date(); onStartDateChange(subDays(today, 30)); @@ -73,7 +88,7 @@ export const DateRangeSelector: FC = ({ )} > - {startDate ? format(startDate, "PPP") : "Default (1 year ago)"} + {startDate ? format(startDate, "PPP") : getStartDatePlaceholder()} diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx index 430aa927c..cfdebee60 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/connector-edit-view.tsx @@ -227,6 +227,7 @@ export const ConnectorEditView: FC = ({ connector.connector_type === "COMPOSIO_GOOGLE_CALENDAR_CONNECTOR" || connector.connector_type === "LUMA_CONNECTOR" } + lastIndexedAt={connector.last_indexed_at} /> )} diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/indexing-configuration-view.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/indexing-configuration-view.tsx index 72069441a..b885f35da 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/indexing-configuration-view.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/views/indexing-configuration-view.tsx @@ -165,6 +165,7 @@ export const IndexingConfigurationView: FC = ({ config.connectorType === "COMPOSIO_GOOGLE_CALENDAR_CONNECTOR" || config.connectorType === "LUMA_CONNECTOR" } + lastIndexedAt={connector?.last_indexed_at} /> )} diff --git a/surfsense_web/components/ui/dialog.tsx b/surfsense_web/components/ui/dialog.tsx index f3fa856d3..e5d9fb93f 100644 --- a/surfsense_web/components/ui/dialog.tsx +++ b/surfsense_web/components/ui/dialog.tsx @@ -38,7 +38,7 @@ const DialogContent = React.forwardRef< { - return [k, String(v)]; - }) + Object.entries(parsedRequest.data.queryParams) + .filter(([_, v]) => v !== undefined && v !== null) + .map(([k, v]) => { + return [k, String(v)]; + }) ) : undefined; @@ -102,11 +104,13 @@ class ConnectorsApiService { 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( - Object.entries(queryParams).map(([k, v]) => { - return [k, String(v)]; - }) + Object.entries(queryParams) + .filter(([_, v]) => v !== undefined && v !== null) + .map(([k, v]) => { + return [k, String(v)]; + }) ); const queryString = new URLSearchParams(transformedQueryParams).toString(); @@ -174,11 +178,13 @@ class ConnectorsApiService { 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( - Object.entries(queryParams).map(([k, v]) => { - return [k, String(v)]; - }) + Object.entries(queryParams) + .filter(([_, v]) => v !== undefined && v !== null) + .map(([k, v]) => { + return [k, String(v)]; + }) ); const queryString = new URLSearchParams(transformedQueryParams).toString();