diff --git a/crates/goose/src/context_mgmt/mod.rs b/crates/goose/src/context_mgmt/mod.rs index 8a8480877246..b4ad85e3699e 100644 --- a/crates/goose/src/context_mgmt/mod.rs +++ b/crates/goose/src/context_mgmt/mod.rs @@ -167,7 +167,7 @@ pub async fn check_if_compaction_needed( let usage_ratio = current_tokens as f64 / context_limit as f64; let needs_compaction = if threshold <= 0.0 || threshold >= 1.0 { - usage_ratio > DEFAULT_COMPACTION_THRESHOLD + false // Auto-compact is disabled. } else { usage_ratio > threshold }; diff --git a/ui/desktop/src/components/ChatInput.tsx b/ui/desktop/src/components/ChatInput.tsx index 62c446b62645..5e241a985f9a 100644 --- a/ui/desktop/src/components/ChatInput.tsx +++ b/ui/desktop/src/components/ChatInput.tsx @@ -141,7 +141,6 @@ export default function ChatInput({ const { getCurrentModelAndProvider, currentModel, currentProvider } = useModelAndProvider(); const [tokenLimit, setTokenLimit] = useState(TOKEN_LIMIT_DEFAULT); const [isTokenLimitLoaded, setIsTokenLimitLoaded] = useState(false); - const [autoCompactThreshold, setAutoCompactThreshold] = useState(0.8); // Default to 80% // Draft functionality - get chat context and global draft context // We need to handle the case where ChatInput is used without ChatProvider (e.g., in Hub) @@ -500,22 +499,6 @@ export default function ChatInput({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentModel, currentProvider]); - // Load auto-compact threshold - const loadAutoCompactThreshold = useCallback(async () => { - try { - const threshold = await read('GOOSE_AUTO_COMPACT_THRESHOLD', false); - if (threshold !== undefined && threshold !== null) { - setAutoCompactThreshold(threshold as number); - } - } catch (err) { - console.error('Error fetching auto-compact threshold:', err); - } - }, [read]); - - useEffect(() => { - loadAutoCompactThreshold(); - }, [loadAutoCompactThreshold]); - // Handle tool count alerts and token usage useEffect(() => { clearAlerts(); @@ -541,10 +524,6 @@ export default function ChatInput({ handleSubmit(customEvent); }, compactIcon: , - autoCompactThreshold: autoCompactThreshold, - onThresholdChange: (newThreshold: number) => { - setAutoCompactThreshold(newThreshold); - }, }); } @@ -562,15 +541,7 @@ export default function ChatInput({ } // We intentionally omit setView as it shouldn't trigger a re-render of alerts // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - numTokens, - toolCount, - tokenLimit, - isTokenLimitLoaded, - addAlert, - clearAlerts, - autoCompactThreshold, - ]); + }, [numTokens, toolCount, tokenLimit, isTokenLimitLoaded, addAlert, clearAlerts]); // Cleanup effect for component unmount - prevent memory leaks useEffect(() => { diff --git a/ui/desktop/src/components/alerts/AlertBox.tsx b/ui/desktop/src/components/alerts/AlertBox.tsx index ebe50e911a4e..3eac4f348071 100644 --- a/ui/desktop/src/components/alerts/AlertBox.tsx +++ b/ui/desktop/src/components/alerts/AlertBox.tsx @@ -1,9 +1,10 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { IoIosCloseCircle, IoIosWarning, IoIosInformationCircle } from 'react-icons/io'; import { FaPencilAlt, FaSave } from 'react-icons/fa'; import { cn } from '../../utils'; import { Alert, AlertType } from './types'; import { upsertConfig } from '../../api'; +import { useConfig } from '../ConfigContext'; const alertIcons: Record = { [AlertType.Error]: , @@ -24,17 +25,36 @@ const alertStyles: Record = { }; export const AlertBox = ({ alert, className }: AlertBoxProps) => { + const { read } = useConfig(); const [isEditingThreshold, setIsEditingThreshold] = useState(false); + const [loadedThreshold, setLoadedThreshold] = useState(null); const [thresholdValue, setThresholdValue] = useState( - alert.autoCompactThreshold ? Math.round(alert.autoCompactThreshold * 100) : 80 + alert.autoCompactThreshold ? Math.max(1, Math.round(alert.autoCompactThreshold * 100)) : 80 ); const [isSaving, setIsSaving] = useState(false); + useEffect(() => { + const loadThreshold = async () => { + try { + const threshold = await read('GOOSE_AUTO_COMPACT_THRESHOLD', false); + if (threshold !== undefined && threshold !== null) { + setLoadedThreshold(threshold as number); + setThresholdValue(Math.max(1, Math.round((threshold as number) * 100))); + } + } catch (err) { + console.error('Error fetching auto-compact threshold:', err); + } + }; + + loadThreshold(); + }, [read]); + + const currentThreshold = loadedThreshold !== null ? loadedThreshold : alert.autoCompactThreshold; + const handleSaveThreshold = async () => { if (isSaving) return; // Prevent double-clicks - // Validate threshold value - allow 0 and 100 as special values to disable - const validThreshold = Math.max(0, Math.min(100, thresholdValue)); + let validThreshold = Math.max(1, Math.min(100, thresholdValue)); if (validThreshold !== thresholdValue) { setThresholdValue(validThreshold); } @@ -52,6 +72,7 @@ export const AlertBox = ({ alert, className }: AlertBoxProps) => { }); setIsEditingThreshold(false); + setLoadedThreshold(newThreshold); // Notify parent component of the threshold change if (alert.onThresholdChange) { @@ -82,14 +103,14 @@ export const AlertBox = ({ alert, className }: AlertBoxProps) => { {alert.message} {/* Auto-compact threshold indicator with edit */} - {alert.autoCompactThreshold !== undefined && ( + {currentThreshold !== undefined && (
{isEditingThreshold ? ( <> - Auto summarize at + Auto compact at { const val = parseInt(e.target.value, 10); // Allow empty input for easier editing if (e.target.value === '') { - setThresholdValue(0); + setThresholdValue(1); } else if (!isNaN(val)) { - // Clamp value between 0 and 100 - setThresholdValue(Math.max(0, Math.min(100, val))); + // Clamp value between 1 and 100 + setThresholdValue(Math.max(1, Math.min(100, val))); } }} onBlur={(e) => { // On blur, ensure we have a valid value const val = parseInt(e.target.value, 10); - if (isNaN(val) || val < 0) { - setThresholdValue(0); + if (isNaN(val) || val < 1) { + setThresholdValue(1); } else if (val > 100) { setThresholdValue(100); } @@ -117,11 +138,10 @@ export const AlertBox = ({ alert, className }: AlertBoxProps) => { handleSaveThreshold(); } else if (e.key === 'Escape') { setIsEditingThreshold(false); - setThresholdValue( - alert.autoCompactThreshold - ? Math.round(alert.autoCompactThreshold * 100) - : 80 - ); + const resetValue = currentThreshold + ? Math.round(currentThreshold * 100) + : 80; + setThresholdValue(Math.max(1, resetValue)); } }} onFocus={(e) => { @@ -154,9 +174,7 @@ export const AlertBox = ({ alert, className }: AlertBoxProps) => { ) : ( <> - {alert.autoCompactThreshold === 0 || alert.autoCompactThreshold === 1 - ? 'Auto summarize disabled' - : `Auto summarize at ${Math.round(alert.autoCompactThreshold * 100)}%`} + Auto compact at {Math.round(currentThreshold * 100)}%