From cb72617d5e1a1dc10b74ffb072b8f0ebe1c5af9a Mon Sep 17 00:00:00 2001 From: Zane <75694352+zanesq@users.noreply.github.com> Date: Mon, 21 Apr 2025 18:25:39 -0700 Subject: [PATCH] Bumped tool limit and updated alerts (#2274) --- ui/desktop/src/components/alerts/types.ts | 1 + ui/desktop/src/components/alerts/useAlerts.ts | 25 +++++++------ .../src/components/bottom_menu/BottomMenu.tsx | 35 ++++++++++--------- .../bottom_menu/BottomMenuAlertPopover.tsx | 29 ++++++++++----- 4 files changed, 54 insertions(+), 36 deletions(-) diff --git a/ui/desktop/src/components/alerts/types.ts b/ui/desktop/src/components/alerts/types.ts index 7fdfca54..c76831cc 100644 --- a/ui/desktop/src/components/alerts/types.ts +++ b/ui/desktop/src/components/alerts/types.ts @@ -6,6 +6,7 @@ export enum AlertType { export interface Alert { type: AlertType; message: string; + autoShow?: boolean; action?: { text: string; onClick: () => void; diff --git a/ui/desktop/src/components/alerts/useAlerts.ts b/ui/desktop/src/components/alerts/useAlerts.ts index 77076036..bd20a89f 100644 --- a/ui/desktop/src/components/alerts/useAlerts.ts +++ b/ui/desktop/src/components/alerts/useAlerts.ts @@ -1,13 +1,19 @@ import { useState, useCallback } from 'react'; import { Alert, AlertType } from './types'; +interface AlertOptions { + type: AlertType; + message: string; + action?: { + text: string; + onClick: () => void; + }; + autoShow?: boolean; +} + interface UseAlerts { alerts: Alert[]; - addAlert: ( - type: AlertType, - message: string, - action?: { text: string; onClick: () => void } - ) => void; + addAlert: (options: AlertOptions) => void; removeAlert: (index: number) => void; clearAlerts: () => void; } @@ -15,12 +21,9 @@ interface UseAlerts { export const useAlerts = (): UseAlerts => { const [alerts, setAlerts] = useState([]); - const addAlert = useCallback( - (type: AlertType, message: string, action?: { text: string; onClick: () => void }) => { - setAlerts((prev) => [...prev, { type, message, action }]); - }, - [] - ); + const addAlert = useCallback((options: AlertOptions) => { + setAlerts((prev) => [...prev, options]); + }, []); const removeAlert = useCallback((index: number) => { setAlerts((prev) => prev.filter((_, i) => i !== index)); diff --git a/ui/desktop/src/components/bottom_menu/BottomMenu.tsx b/ui/desktop/src/components/bottom_menu/BottomMenu.tsx index 128c8390..25fab978 100644 --- a/ui/desktop/src/components/bottom_menu/BottomMenu.tsx +++ b/ui/desktop/src/components/bottom_menu/BottomMenu.tsx @@ -11,11 +11,11 @@ import { settingsV2Enabled } from '../../flags'; import { BottomMenuModeSelection } from './BottomMenuModeSelection'; import ModelsBottomBar from '../settings_v2/models/bottom_bar/ModelsBottomBar'; import { useConfig } from '../ConfigContext'; -import { getCurrentModelAndProvider } from '../settings_v2/models/index'; +import { getCurrentModelAndProvider } from '../settings_v2/models'; const TOKEN_LIMIT_DEFAULT = 128000; // fallback for custom models that the backend doesn't know about const TOKEN_WARNING_THRESHOLD = 0.8; // warning shows at 80% of the token limit -const TOOLS_MAX_SUGGESTED = 25; // max number of tools before we show a warning +const TOOLS_MAX_SUGGESTED = 60; // max number of tools before we show a warning export default function BottomMenu({ hasMessages, @@ -73,28 +73,31 @@ export default function BottomMenu({ // Add token alerts if we have a token limit if (tokenLimit && numTokens > 0) { if (numTokens >= tokenLimit) { - addAlert( - AlertType.Error, - `Token limit reached (${numTokens.toLocaleString()}/${tokenLimit.toLocaleString()})` - ); + addAlert({ + type: AlertType.Error, + message: `Token limit reached (${numTokens.toLocaleString()}/${tokenLimit.toLocaleString()}) \n You’ve reached the model’s conversation limit. The session will be saved — copy anything important and start a new one to continue.`, + autoShow: true, // Auto-show token limit errors + }); } else if (numTokens >= tokenLimit * TOKEN_WARNING_THRESHOLD) { - addAlert( - AlertType.Warning, - `Approaching token limit (${numTokens.toLocaleString()}/${tokenLimit.toLocaleString()})` - ); + addAlert({ + type: AlertType.Warning, + message: `Approaching token limit (${numTokens.toLocaleString()}/${tokenLimit.toLocaleString()}) \n You’re reaching the model’s conversation limit. The session will be saved — copy anything important and start a new one to continue.`, + autoShow: true, // Auto-show token limit warnings + }); } } // Add tool count alert if we have the data if (toolCount !== null && toolCount > TOOLS_MAX_SUGGESTED) { - addAlert( - AlertType.Warning, - `Too many tools can degrade performance.\nTool count: ${toolCount} (recommend: ${TOOLS_MAX_SUGGESTED})`, - { + addAlert({ + type: AlertType.Warning, + message: `Too many tools can degrade performance.\nTool count: ${toolCount} (recommend: ${TOOLS_MAX_SUGGESTED})`, + action: { text: 'View extensions', onClick: () => setView('settings'), - } - ); + }, + autoShow: false, // Don't auto-show tool count warnings + }); } // We intentionally omit setView as it shouldn't trigger a re-render of alerts // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/ui/desktop/src/components/bottom_menu/BottomMenuAlertPopover.tsx b/ui/desktop/src/components/bottom_menu/BottomMenuAlertPopover.tsx index e40464dd..64d9cbdf 100644 --- a/ui/desktop/src/components/bottom_menu/BottomMenuAlertPopover.tsx +++ b/ui/desktop/src/components/bottom_menu/BottomMenuAlertPopover.tsx @@ -1,5 +1,6 @@ import React, { useRef, useEffect, useCallback } from 'react'; -import { IoIosCloseCircle, IoIosWarning } from 'react-icons/io'; +import { FaCircle } from 'react-icons/fa'; +import { IoIosCloseCircle } from 'react-icons/io'; import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'; import { cn } from '../../utils'; import { Alert, AlertType } from '../alerts'; @@ -37,16 +38,21 @@ export default function BottomMenuAlertPopover({ alerts }: AlertPopoverProps) { useEffect(() => { if (alerts.length === 0) return; - // Compare current and previous alerts for any changes - const hasChanges = alerts.some((alert, index) => { + // Find new or changed alerts + const changedAlerts = alerts.filter((alert, index) => { const prevAlert = previousAlertsRef.current[index]; return !prevAlert || prevAlert.type !== alert.type || prevAlert.message !== alert.message; }); previousAlertsRef.current = alerts; - // Auto show the popover if there are new alerts - if (!hasShownInitial || hasChanges) { + // Only auto-show if any of the new/changed alerts have autoShow: true + const hasNewAutoShowAlert = changedAlerts.some((alert) => alert.autoShow === true); + + // Auto show the popover only if: + // 1. There are new alerts that should auto-show AND + // 2. We haven't shown this specific alert before (tracked by hasShownInitial) + if (hasNewAutoShowAlert && !hasShownInitial) { setIsOpen(true); setHasShownInitial(true); setWasAutoShown(true); @@ -83,18 +89,23 @@ export default function BottomMenuAlertPopover({ alerts }: AlertPopoverProps) { if (alerts.length === 0) return null; - // Determine the icon to show based on the highest priority alert + // Determine the icon and styling based on the alerts const hasError = alerts.some((alert) => alert.type === AlertType.Error); - const TriggerIcon = hasError ? IoIosCloseCircle : IoIosWarning; + const TriggerIcon = hasError ? IoIosCloseCircle : FaCircle; const triggerColor = hasError ? 'text-[#d7040e]' : 'text-[#cc4b03]'; + // Different styling for error icon vs notification dot + const iconStyles = hasError + ? 'h-5 w-5' // Keep error icon larger + : 'h-2.5 w-2.5'; // Smaller notification dot + return (
{ if (hideTimerRef.current) { clearTimeout(hideTimerRef.current); @@ -114,7 +125,7 @@ export default function BottomMenuAlertPopover({ alerts }: AlertPopoverProps) { setIsHovered(false); }} > - +