mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
fix: queued message lost when clicking sending now (#9074)
This commit is contained in:
@@ -52,6 +52,18 @@ interface PastedImage {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
const moveQueuedMessageToFront = (
|
||||
messages: QueuedMessage[],
|
||||
messageId: string
|
||||
): QueuedMessage[] => {
|
||||
const selectedMessage = messages.find((msg) => msg.id === messageId);
|
||||
if (!selectedMessage) return messages;
|
||||
return [selectedMessage, ...messages.filter((msg) => msg.id !== messageId)];
|
||||
};
|
||||
|
||||
const removeQueuedMessage = (messages: QueuedMessage[], messageId: string): QueuedMessage[] =>
|
||||
messages.filter((msg) => msg.id !== messageId);
|
||||
|
||||
const MAX_IMAGES_PER_MESSAGE = 10;
|
||||
|
||||
// Constants for token and tool alerts
|
||||
@@ -220,8 +232,25 @@ export default function ChatInput({
|
||||
const [queuedMessages, setQueuedMessages] = useState<QueuedMessage[]>([]);
|
||||
const queuePausedRef = useRef(false);
|
||||
const editingMessageIdRef = useRef<string | null>(null);
|
||||
const sendAfterStopMessageIdRef = useRef<string | null>(null);
|
||||
const [lastInterruption, setLastInterruption] = useState<string | null>(null);
|
||||
|
||||
const pauseRemainingQueue = useCallback(() => {
|
||||
queuePausedRef.current = true;
|
||||
}, []);
|
||||
|
||||
const clearPendingSendAfterStop = useCallback((messageId?: string) => {
|
||||
if (!messageId || sendAfterStopMessageIdRef.current === messageId) {
|
||||
sendAfterStopMessageIdRef.current = null;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const clearQueueState = useCallback(() => {
|
||||
queuePausedRef.current = false;
|
||||
sendAfterStopMessageIdRef.current = null;
|
||||
setLastInterruption(null);
|
||||
}, []);
|
||||
|
||||
const { alerts, addAlert, clearAlerts } = useAlerts();
|
||||
const dropdownRef: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
|
||||
null
|
||||
@@ -315,20 +344,40 @@ export default function ChatInput({
|
||||
// Queue processing
|
||||
useEffect(() => {
|
||||
if (wasLoadingRef.current && !isLoading && queuedMessages.length > 0) {
|
||||
// After an interruption, we should process the interruption message immediately
|
||||
// The queue is only truly paused if there was an interruption AND we want to keep it paused
|
||||
const shouldProcessQueue = !queuePausedRef.current || lastInterruption;
|
||||
const pendingSendAfterStopId = sendAfterStopMessageIdRef.current;
|
||||
const messageToSend = pendingSendAfterStopId
|
||||
? queuedMessages.find((message) => message.id === pendingSendAfterStopId)
|
||||
: queuedMessages[0];
|
||||
|
||||
if (pendingSendAfterStopId && !messageToSend) {
|
||||
clearPendingSendAfterStop(pendingSendAfterStopId);
|
||||
wasLoadingRef.current = isLoading;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!messageToSend) {
|
||||
wasLoadingRef.current = isLoading;
|
||||
return;
|
||||
}
|
||||
|
||||
const shouldSendAfterStop = pendingSendAfterStopId === messageToSend.id;
|
||||
const shouldProcessQueue = !queuePausedRef.current || lastInterruption || shouldSendAfterStop;
|
||||
|
||||
if (shouldProcessQueue) {
|
||||
const nextMessage = queuedMessages[0];
|
||||
LocalMessageStorage.addMessage(nextMessage.content);
|
||||
handleSubmit({ msg: nextMessage.content, images: nextMessage.images });
|
||||
LocalMessageStorage.addMessage(messageToSend.content);
|
||||
handleSubmit({ msg: messageToSend.content, images: messageToSend.images });
|
||||
if (shouldSendAfterStop) {
|
||||
clearPendingSendAfterStop(messageToSend.id);
|
||||
}
|
||||
setQueuedMessages((prev) => {
|
||||
const newQueue = prev.slice(1);
|
||||
const newQueue = shouldSendAfterStop
|
||||
? removeQueuedMessage(prev, messageToSend.id)
|
||||
: prev.slice(1);
|
||||
// If queue becomes empty after processing, clear the paused state
|
||||
if (newQueue.length === 0) {
|
||||
queuePausedRef.current = false;
|
||||
setLastInterruption(null);
|
||||
clearQueueState();
|
||||
} else if (shouldSendAfterStop) {
|
||||
pauseRemainingQueue();
|
||||
}
|
||||
return newQueue;
|
||||
});
|
||||
@@ -338,12 +387,20 @@ export default function ChatInput({
|
||||
setLastInterruption(null);
|
||||
// Keep the queue paused after sending the interruption message
|
||||
// User can manually resume if they want to continue with queued messages
|
||||
queuePausedRef.current = true;
|
||||
pauseRemainingQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
wasLoadingRef.current = isLoading;
|
||||
}, [isLoading, queuedMessages, handleSubmit, lastInterruption]);
|
||||
}, [
|
||||
isLoading,
|
||||
queuedMessages,
|
||||
handleSubmit,
|
||||
lastInterruption,
|
||||
clearPendingSendAfterStop,
|
||||
clearQueueState,
|
||||
pauseRemainingQueue,
|
||||
]);
|
||||
const [mentionPopover, setMentionPopover] = useState<{
|
||||
isOpen: boolean;
|
||||
position: { x: number; y: number };
|
||||
@@ -934,7 +991,7 @@ export default function ChatInput({
|
||||
if (interruptionMatch && interruptionMatch.shouldInterrupt) {
|
||||
setLastInterruption(interruptionMatch.matchedText);
|
||||
if (onStop) onStop();
|
||||
queuePausedRef.current = true;
|
||||
pauseRemainingQueue();
|
||||
|
||||
// For interruptions, we need to queue the message to be sent after the stop completes
|
||||
// rather than trying to send it immediately while the system is still loading
|
||||
@@ -1227,13 +1284,13 @@ export default function ChatInput({
|
||||
|
||||
// Queue management functions - no storage persistence, only in-memory
|
||||
const handleRemoveQueuedMessage = (messageId: string) => {
|
||||
clearPendingSendAfterStop(messageId);
|
||||
setQueuedMessages((prev) => prev.filter((msg) => msg.id !== messageId));
|
||||
};
|
||||
|
||||
const handleClearQueue = () => {
|
||||
setQueuedMessages([]);
|
||||
queuePausedRef.current = false;
|
||||
setLastInterruption(null);
|
||||
clearQueueState();
|
||||
};
|
||||
|
||||
const handleReorderMessages = (reorderedMessages: QueuedMessage[]) => {
|
||||
@@ -1250,20 +1307,17 @@ export default function ChatInput({
|
||||
const messageToSend = queuedMessages.find((msg) => msg.id === messageId);
|
||||
if (!messageToSend) return;
|
||||
|
||||
// Stop current processing and temporarily pause queue to prevent double-send
|
||||
if (!isLoading) {
|
||||
setQueuedMessages((prev) => removeQueuedMessage(prev, messageId));
|
||||
LocalMessageStorage.addMessage(messageToSend.content);
|
||||
handleSubmit({ msg: messageToSend.content, images: messageToSend.images });
|
||||
return;
|
||||
}
|
||||
|
||||
sendAfterStopMessageIdRef.current = messageId;
|
||||
pauseRemainingQueue();
|
||||
setQueuedMessages((prev) => moveQueuedMessageToFront(prev, messageId));
|
||||
if (onStop) onStop();
|
||||
const wasPaused = queuePausedRef.current;
|
||||
queuePausedRef.current = true;
|
||||
|
||||
// Remove the message from queue and send it immediately
|
||||
setQueuedMessages((prev) => prev.filter((msg) => msg.id !== messageId));
|
||||
LocalMessageStorage.addMessage(messageToSend.content);
|
||||
handleSubmit({ msg: messageToSend.content, images: messageToSend.images });
|
||||
|
||||
// Restore previous pause state after a brief delay to prevent race condition
|
||||
setTimeout(() => {
|
||||
queuePausedRef.current = wasPaused;
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const handleResumeQueue = () => {
|
||||
|
||||
Reference in New Issue
Block a user