Tell the user to hit compact (#3851)
Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
@@ -127,7 +127,7 @@ function BaseChatContent({
|
||||
summaryContent,
|
||||
summarizedThread,
|
||||
isSummaryModalOpen,
|
||||
isLoadingSummary,
|
||||
isLoadingCompaction,
|
||||
resetMessagesWithSummary,
|
||||
closeSummaryModal,
|
||||
updateSummary,
|
||||
@@ -513,7 +513,7 @@ function BaseChatContent({
|
||||
{chatState !== ChatState.Idle && (
|
||||
<div className="absolute bottom-1 left-4 z-20 pointer-events-none">
|
||||
<LoadingGoose
|
||||
message={isLoadingSummary ? 'summarizing conversation…' : undefined}
|
||||
message={isLoadingCompaction ? 'summarizing conversation…' : undefined}
|
||||
chatState={chatState}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,7 @@ import { Message } from '../types/message';
|
||||
import { DirSwitcher } from './bottom_menu/DirSwitcher';
|
||||
import ModelsBottomBar from './settings/models/bottom_bar/ModelsBottomBar';
|
||||
import { BottomMenuModeSelection } from './bottom_menu/BottomMenuModeSelection';
|
||||
import { ManualSummarizeButton } from './context_management/ManualSummaryButton';
|
||||
import { ManualCompactButton } from './context_management/ManualCompactButton';
|
||||
import { AlertType, useAlerts } from './alerts';
|
||||
import { useToolCount } from './alerts/useToolCount';
|
||||
import { useConfig } from './ConfigContext';
|
||||
@@ -110,7 +110,7 @@ export default function ChatInput({
|
||||
const { alerts, addAlert, clearAlerts } = useAlerts();
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const toolCount = useToolCount();
|
||||
const { isLoadingSummary } = useChatContextManager();
|
||||
const { isLoadingCompaction } = useChatContextManager();
|
||||
const { getProviders, read } = useConfig();
|
||||
const { getCurrentModelAndProvider, currentModel, currentProvider } = useModelAndProvider();
|
||||
const [tokenLimit, setTokenLimit] = useState<number>(TOKEN_LIMIT_DEFAULT);
|
||||
@@ -416,7 +416,7 @@ export default function ChatInput({
|
||||
// Only show warning alert when approaching limit
|
||||
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.`,
|
||||
message: `Approaching token limit (${numTokens.toLocaleString()}/${tokenLimit.toLocaleString()}) \n You're reaching the model's conversation limit. Consider compacting the conversation to continue.`,
|
||||
autoShow: true, // Auto-show token limit warnings
|
||||
});
|
||||
} else {
|
||||
@@ -880,7 +880,7 @@ export default function ChatInput({
|
||||
evt.preventDefault();
|
||||
const canSubmit =
|
||||
!isLoading &&
|
||||
!isLoadingSummary &&
|
||||
!isLoadingCompaction &&
|
||||
(displayValue.trim() ||
|
||||
pastedImages.some((img) => img.filePath && !img.error && !img.isLoading) ||
|
||||
allDroppedFiles.some((file) => !file.error && !file.isLoading));
|
||||
@@ -894,7 +894,7 @@ export default function ChatInput({
|
||||
e.preventDefault();
|
||||
const canSubmit =
|
||||
!isLoading &&
|
||||
!isLoadingSummary &&
|
||||
!isLoadingCompaction &&
|
||||
(displayValue.trim() ||
|
||||
pastedImages.some((img) => img.filePath && !img.error && !img.isLoading) ||
|
||||
allDroppedFiles.some((file) => !file.error && !file.isLoading));
|
||||
@@ -1073,7 +1073,7 @@ export default function ChatInput({
|
||||
isAnyDroppedFileLoading ||
|
||||
isRecording ||
|
||||
isTranscribing ||
|
||||
isLoadingSummary
|
||||
isLoadingCompaction
|
||||
}
|
||||
className={`rounded-full px-10 py-2 flex items-center gap-2 ${
|
||||
!hasSubmittableContent ||
|
||||
@@ -1081,12 +1081,12 @@ export default function ChatInput({
|
||||
isAnyDroppedFileLoading ||
|
||||
isRecording ||
|
||||
isTranscribing ||
|
||||
isLoadingSummary
|
||||
isLoadingCompaction
|
||||
? 'bg-slate-600 text-white cursor-not-allowed opacity-50 border-slate-600'
|
||||
: 'bg-slate-600 text-white hover:bg-slate-700 border-slate-600 hover:cursor-pointer'
|
||||
}`}
|
||||
title={
|
||||
isLoadingSummary
|
||||
isLoadingCompaction
|
||||
? 'Summarizing conversation...'
|
||||
: isAnyImageLoading
|
||||
? 'Waiting for images to save...'
|
||||
@@ -1287,7 +1287,7 @@ export default function ChatInput({
|
||||
<div className="w-px h-4 bg-border-default mx-2" />
|
||||
<BottomMenuModeSelection />
|
||||
{messages.length > 0 && (
|
||||
<ManualSummarizeButton
|
||||
<ManualCompactButton
|
||||
messages={messages}
|
||||
isLoading={isLoading}
|
||||
setMessages={setMessages}
|
||||
|
||||
@@ -11,7 +11,7 @@ interface ChatContextManagerState {
|
||||
summaryContent: string;
|
||||
summarizedThread: Message[];
|
||||
isSummaryModalOpen: boolean;
|
||||
isLoadingSummary: boolean;
|
||||
isLoadingCompaction: boolean;
|
||||
errorLoadingSummary: boolean;
|
||||
preparingManualSummary: boolean;
|
||||
}
|
||||
@@ -32,10 +32,7 @@ interface ChatContextManagerActions {
|
||||
hasSummarizationRequestedContent: (message: Message) => boolean;
|
||||
getContextHandlerType: (message: Message) => 'contextLengthExceeded' | 'summarizationRequested';
|
||||
handleContextLengthExceeded: (messages: Message[]) => Promise<void>;
|
||||
handleManualSummarization: (
|
||||
messages: Message[],
|
||||
setMessages: (messages: Message[]) => void
|
||||
) => void;
|
||||
handleManualCompaction: (messages: Message[], setMessages: (messages: Message[]) => void) => void;
|
||||
}
|
||||
|
||||
// Create the context
|
||||
@@ -50,12 +47,12 @@ export const ChatContextManagerProvider: React.FC<{ children: React.ReactNode }>
|
||||
const [summaryContent, setSummaryContent] = useState<string>('');
|
||||
const [summarizedThread, setSummarizedThread] = useState<Message[]>([]);
|
||||
const [isSummaryModalOpen, setIsSummaryModalOpen] = useState<boolean>(false);
|
||||
const [isLoadingSummary, setIsLoadingSummary] = useState<boolean>(false);
|
||||
const [isLoadingCompaction, setIsLoadingCompaction] = useState<boolean>(false);
|
||||
const [errorLoadingSummary, setErrorLoadingSummary] = useState<boolean>(false);
|
||||
const [preparingManualSummary, setPreparingManualSummary] = useState<boolean>(false);
|
||||
|
||||
const handleContextLengthExceeded = async (messages: Message[]): Promise<void> => {
|
||||
setIsLoadingSummary(true);
|
||||
setIsLoadingCompaction(true);
|
||||
setErrorLoadingSummary(false);
|
||||
setPreparingManualSummary(true);
|
||||
|
||||
@@ -79,17 +76,17 @@ export const ChatContextManagerProvider: React.FC<{ children: React.ReactNode }>
|
||||
setSummarizedThread(convertedMessages);
|
||||
}
|
||||
|
||||
setIsLoadingSummary(false);
|
||||
setIsLoadingCompaction(false);
|
||||
} catch (err) {
|
||||
console.error('Error handling context length exceeded:', err);
|
||||
setErrorLoadingSummary(true);
|
||||
setIsLoadingSummary(false);
|
||||
setIsLoadingCompaction(false);
|
||||
} finally {
|
||||
setPreparingManualSummary(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleManualSummarization = (
|
||||
const handleManualCompaction = (
|
||||
messages: Message[],
|
||||
setMessages: (messages: Message[]) => void
|
||||
): void => {
|
||||
@@ -242,7 +239,7 @@ export const ChatContextManagerProvider: React.FC<{ children: React.ReactNode }>
|
||||
summaryContent,
|
||||
summarizedThread,
|
||||
isSummaryModalOpen,
|
||||
isLoadingSummary,
|
||||
isLoadingCompaction,
|
||||
errorLoadingSummary,
|
||||
preparingManualSummary,
|
||||
|
||||
@@ -256,7 +253,7 @@ export const ChatContextManagerProvider: React.FC<{ children: React.ReactNode }>
|
||||
hasSummarizationRequestedContent,
|
||||
getContextHandlerType,
|
||||
handleContextLengthExceeded,
|
||||
handleManualSummarization,
|
||||
handleManualCompaction,
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -22,7 +22,7 @@ export const ContextHandler: React.FC<ContextHandlerProps> = ({
|
||||
}) => {
|
||||
const {
|
||||
summaryContent,
|
||||
isLoadingSummary,
|
||||
isLoadingCompaction,
|
||||
errorLoadingSummary,
|
||||
openSummaryModal,
|
||||
handleContextLengthExceeded,
|
||||
@@ -62,13 +62,13 @@ export const ContextHandler: React.FC<ContextHandlerProps> = ({
|
||||
|
||||
// Scroll when summarization starts (loading state)
|
||||
useEffect(() => {
|
||||
if (isLoadingSummary && shouldAllowSummaryInteraction) {
|
||||
if (isLoadingCompaction && shouldAllowSummaryInteraction) {
|
||||
// Delay the scroll slightly to ensure the loading content is rendered
|
||||
setTimeout(() => {
|
||||
onSummaryComplete?.();
|
||||
}, 100);
|
||||
}
|
||||
}, [isLoadingSummary, shouldAllowSummaryInteraction, onSummaryComplete]);
|
||||
}, [isLoadingCompaction, shouldAllowSummaryInteraction, onSummaryComplete]);
|
||||
|
||||
// Function to trigger the async operation properly
|
||||
const triggerContextLengthExceeded = () => {
|
||||
@@ -234,7 +234,7 @@ export const ContextHandler: React.FC<ContextHandlerProps> = ({
|
||||
<div className="flex-grow border-t border-gray-300"></div>
|
||||
</div>
|
||||
|
||||
{isLoadingSummary && shouldAllowSummaryInteraction
|
||||
{isLoadingCompaction && shouldAllowSummaryInteraction
|
||||
? renderLoadingState()
|
||||
: renderContentState()}
|
||||
</div>
|
||||
|
||||
+14
-13
@@ -14,18 +14,18 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/Tooltip';
|
||||
import { useChatContextManager } from './ChatContextManager';
|
||||
import { Message } from '../../types/message';
|
||||
|
||||
interface ManualSummarizeButtonProps {
|
||||
interface ManualCompactButtonProps {
|
||||
messages: Message[];
|
||||
isLoading?: boolean; // need this prop to know if Goose is responding
|
||||
setMessages: (messages: Message[]) => void; // context management is triggered via special message content types
|
||||
}
|
||||
|
||||
export const ManualSummarizeButton: React.FC<ManualSummarizeButtonProps> = ({
|
||||
export const ManualCompactButton: React.FC<ManualCompactButtonProps> = ({
|
||||
messages,
|
||||
isLoading = false,
|
||||
setMessages,
|
||||
}) => {
|
||||
const { handleManualSummarization, isLoadingSummary } = useChatContextManager();
|
||||
const { handleManualCompaction, isLoadingCompaction } = useChatContextManager();
|
||||
|
||||
const [isConfirmationOpen, setIsConfirmationOpen] = useState(false);
|
||||
|
||||
@@ -33,13 +33,13 @@ export const ManualSummarizeButton: React.FC<ManualSummarizeButtonProps> = ({
|
||||
setIsConfirmationOpen(true);
|
||||
};
|
||||
|
||||
const handleSummarize = async () => {
|
||||
const handleCompaction = async () => {
|
||||
setIsConfirmationOpen(false);
|
||||
|
||||
try {
|
||||
handleManualSummarization(messages, setMessages);
|
||||
handleManualCompaction(messages, setMessages);
|
||||
} catch (error) {
|
||||
console.error('Error in handleSummarize:', error);
|
||||
console.error('Error in handleCompaction:', error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -57,17 +57,17 @@ export const ManualSummarizeButton: React.FC<ManualSummarizeButtonProps> = ({
|
||||
type="button"
|
||||
className={cn(
|
||||
'flex items-center justify-center text-text-default/70 hover:text-text-default text-xs cursor-pointer transition-colors',
|
||||
(isLoadingSummary || isLoading) &&
|
||||
(isLoadingCompaction || isLoading) &&
|
||||
'cursor-not-allowed text-text-default/30 hover:text-text-default/30 opacity-50'
|
||||
)}
|
||||
onClick={handleClick}
|
||||
disabled={isLoadingSummary || isLoading}
|
||||
disabled={isLoadingCompaction || isLoading}
|
||||
>
|
||||
<ScrollText size={16} />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
{isLoadingSummary ? 'Summarizing conversation...' : 'Summarize conversation context'}
|
||||
{isLoadingCompaction ? 'Compacting conversation...' : 'Compact conversation context'}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
@@ -78,10 +78,11 @@ export const ManualSummarizeButton: React.FC<ManualSummarizeButtonProps> = ({
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<ScrollText className="text-iconStandard" size={24} />
|
||||
Summarize Conversation
|
||||
Compact Conversation
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
This will summarize your conversation history to save context space.
|
||||
This will compact your conversation by summarizing the context into a single message
|
||||
and will help you save context space for future interactions.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -97,8 +98,8 @@ export const ManualSummarizeButton: React.FC<ManualSummarizeButtonProps> = ({
|
||||
<Button type="button" variant="outline" onClick={handleClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="button" onClick={handleSummarize}>
|
||||
Summarize
|
||||
<Button type="button" onClick={handleCompaction}>
|
||||
Compact Conversation
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
Reference in New Issue
Block a user