Allow users to queue messages#2120
Conversation
Summary of ChangesHello @azizmejri1, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the chat user experience by introducing a message queuing mechanism. Previously, users were blocked from sending new messages while an AI response was actively streaming. With this change, users can now type and submit messages even during an ongoing stream; these messages will be held in a queue and automatically dispatched as soon as the current AI response concludes. This ensures a smoother, more interactive conversation flow and provides visual confirmation of pending messages. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces the ability for users to queue messages while a response is streaming, enhancing the chat experience by allowing continuous interaction. The queued message is displayed in the UI and automatically sent once the current stream concludes. The changes involve adding a QueuedMessage interface and queuedMessageByIdAtom for state management, modifying ChatInput to handle message queuing and clearing, and updating useStreamChat to manage the queue and auto-send messages. MessagesList has also been updated to display the queued message.
Overall, the feature is well-implemented, but there are a few areas for improvement regarding type safety and minor code redundancy.
|
@BugBot run |
|
@BugBot run |
|
@BugBot run |
|
@BugBot run |
|
@BugBot run |
🔍 Multi-Agent Code ReviewFound 3 issue(s) flagged by 3 independent reviewers:
Issues
See inline comments for details. Generated by multi-agent consensus review (3 agents) |
wwwillchen
left a comment
There was a problem hiding this comment.
overall looking quite nice!
a couple of ux comments:
- let's have it expanded by default - i think people want to see what prompts sare actually queued up
- there should be a smooth animation when collapsing/expanding the the prompt queue list
|
@BugBot run |
|
@BugBot run |
🎭 Playwright Test Results❌ Some tests failed
Summary: 712 passed, 2 failed, 4 flaky, 224 skipped Failed Tests🪟 Windows
|
|
@BugBot run |
|
@BugBot run |
| if (editingQueuedMessageId) { | ||
| updateQueuedMessage(editingQueuedMessageId, { | ||
| prompt: currentInput, | ||
| }); | ||
| setInputValue(""); | ||
| setEditingQueuedMessageId(null); | ||
| return; |
There was a problem hiding this comment.
only updates prompt, not attachments or selectedComponents
When editing a queued message, the current implementation only saves the modified prompt text. If the user had attached files or selected components in the original queued message, those remain unchanged even if the user modifies them during editing.
| if (editingQueuedMessageId) { | |
| updateQueuedMessage(editingQueuedMessageId, { | |
| prompt: currentInput, | |
| }); | |
| setInputValue(""); | |
| setEditingQueuedMessageId(null); | |
| return; | |
| if (editingQueuedMessageId) { | |
| updateQueuedMessage(editingQueuedMessageId, { | |
| prompt: currentInput, | |
| attachments, | |
| selectedComponents: componentsToSend, | |
| }); | |
| setInputValue(""); | |
| clearAttachments(); | |
| setSelectedComponents([]); | |
| setEditingQueuedMessageId(null); | |
| return; | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/chat/ChatInput.tsx
Line: 347:353
Comment:
only updates `prompt`, not `attachments` or `selectedComponents`
When editing a queued message, the current implementation only saves the modified prompt text. If the user had attached files or selected components in the original queued message, those remain unchanged even if the user modifies them during editing.
```suggestion
if (editingQueuedMessageId) {
updateQueuedMessage(editingQueuedMessageId, {
prompt: currentInput,
attachments,
selectedComponents: componentsToSend,
});
setInputValue("");
clearAttachments();
setSelectedComponents([]);
setEditingQueuedMessageId(null);
return;
}
```
How can I resolve this? If you propose a fix, please make it concise.| const handleEditQueuedMessage = useCallback( | ||
| (id: string) => { | ||
| const msg = queuedMessages.find((m) => m.id === id); | ||
| if (!msg) return; | ||
| // Load the message content into the input | ||
| setInputValue(msg.prompt); | ||
| // Set editing mode | ||
| setEditingQueuedMessageId(id); | ||
| }, | ||
| [queuedMessages, setInputValue], |
There was a problem hiding this comment.
editing doesn't restore attachments or selectedComponents to the UI
When editing a queued message, only the prompt text is loaded into the input field. The message's attachments and selected components aren't restored, so users can't see or modify them during editing. This creates an inconsistent editing experience where parts of the message are invisible.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/chat/ChatInput.tsx
Line: 261:270
Comment:
editing doesn't restore `attachments` or `selectedComponents` to the UI
When editing a queued message, only the prompt text is loaded into the input field. The message's attachments and selected components aren't restored, so users can't see or modify them during editing. This creates an inconsistent editing experience where parts of the message are invisible.
How can I resolve this? If you propose a fix, please make it concise.
🔍 Dyadbot Code Review SummaryReviewed by 3 independent agents (Correctness Expert, Code Health Expert, UX Wizard). Summary
Issues to Address
🟢 Low Priority Issues (1 item)
See inline comments for details. Generated by Dyadbot code review |
| )} | ||
|
|
||
| {/* Action buttons - visible on hover */} | ||
| <div className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity"> |
There was a problem hiding this comment.
🟡 MEDIUM | accessibility | Consensus: 3/3
Action buttons invisible to keyboard & touch users
The action buttons use opacity-0 group-hover:opacity-100 which means they are only visible on mouse hover. Keyboard-only users tabbing through the list will land on invisible buttons they cannot see. Touch/mobile users have no hover state at all, making these buttons permanently inaccessible. There are also no focus-visible styles to reveal the buttons when focused via keyboard.
Additionally, the buttons use title attributes but no aria-label. Screen readers may not consistently announce title on buttons. The rest of the codebase uses aria-label for icon-only buttons.
💡 Suggestion: Add group-focus-within:opacity-100 to the container so buttons appear when any child receives keyboard focus. Add aria-label attributes matching the title values:
| <div className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity"> | |
| <div className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 transition-opacity"> |
| const statusText = hasError | ||
| ? "will send after a successful response" | ||
| : isStreaming | ||
| ? "will send after current response" | ||
| : "ready to send"; |
There was a problem hiding this comment.
🟡 MEDIUM | consistency | Consensus: 2/3
Hardcoded English strings not using i18n
All user-facing strings in this component are hardcoded English: "will send after a successful response", "will send after current response", "ready to send", "Queued", and all button titles ("Edit", "Move up", "Move down", "Delete"). The editing banner in ChatInput.tsx (line 605) also has a hardcoded "Editing queued message" string.
Every other component in src/components/chat/ uses useTranslation("chat") for user-visible text.
💡 Suggestion: Import useTranslation from react-i18next and use translation keys for all user-visible strings, consistent with the rest of the codebase. Add corresponding entries to the chat translation files.
| const handleEditQueuedMessage = useCallback( | ||
| (id: string) => { | ||
| const msg = queuedMessages.find((m) => m.id === id); | ||
| if (!msg) return; | ||
| // Load the message content into the input | ||
| setInputValue(msg.prompt); | ||
| // Set editing mode |
There was a problem hiding this comment.
🟡 MEDIUM | UX / data loss | Consensus: 2/3
Editing a queued message silently overwrites current input text
When the user clicks Edit on a queued message, handleEditQueuedMessage replaces the input value with the queued message's prompt. If the user was in the middle of typing something in the input field, that text is silently lost with no confirmation and no way to recover.
💡 Suggestion: Before overwriting the input, check if inputValue.trim() is non-empty and either: (a) queue the current input first as a new message, (b) warn the user that their current text will be replaced, or (c) store it temporarily so it can be restored when editing is cancelled via the "Cancel" button.
| // Process first queued message when streaming ends successfully | ||
| useEffect(() => { | ||
| if (!chatId || !shouldProcessQueue) return; | ||
|
|
||
| const queuedMessages = queuedMessagesById.get(chatId) ?? []; | ||
| const completedSuccessfully = | ||
| streamCompletedSuccessfullyById.get(chatId) ?? false; | ||
|
|
||
| // Only process queue if we have confirmation that the stream completed successfully | ||
| // This prevents race conditions where the queue might be processed during cancellation | ||
| if (queuedMessages.length > 0 && completedSuccessfully) { | ||
| // Clear the successful completion flag first to prevent loops | ||
| setStreamCompletedSuccessfullyById((prev) => { | ||
| const next = new Map(prev); | ||
| next.set(chatId, false); | ||
| return next; | ||
| }); | ||
|
|
||
| // Get and remove the first message atomically by extracting it inside the setter | ||
| // This prevents race conditions where the queue might be modified between | ||
| // reading firstMessage and updating the queue | ||
| let messageToSend: QueuedMessageItem | undefined; | ||
| setQueuedMessagesById((prev) => { | ||
| const next = new Map(prev); | ||
| const current = prev.get(chatId) ?? []; | ||
| const [first, ...remainingMessages] = current; | ||
| messageToSend = first; | ||
| if (remainingMessages.length > 0) { | ||
| next.set(chatId, remainingMessages); | ||
| } else { | ||
| next.delete(chatId); | ||
| } | ||
| return next; | ||
| }); | ||
|
|
||
| if (!messageToSend) return; | ||
|
|
||
| posthog.capture("chat:submit", { chatMode: settings?.selectedChatMode }); | ||
|
|
||
| // Send the first message | ||
| streamMessage({ | ||
| prompt: messageToSend.prompt, | ||
| chatId, | ||
| redo: false, | ||
| attachments: messageToSend.attachments, | ||
| selectedComponents: messageToSend.selectedComponents, | ||
| }); | ||
| } |
There was a problem hiding this comment.
🔴 HIGH | race-condition | Consensus: 2/3
Queue-processing effect can send a message the user is currently editing
When a user clicks "Edit" on a queued message, editingQueuedMessageId is set in ChatInput state and the message content is loaded into the input. However, this useEffect operates independently with no awareness of the editing state. When the current stream completes, the effect pops the first message and sends it immediately.
If the user is editing the first queued message when the stream completes:
- The effect sends the original (pre-edit) version of the message
- The message is removed from the queue
editingQueuedMessageIdin ChatInput still references the now-deleted message- When the user presses Enter,
updateQueuedMessagesilently fails (no matching ID) - The user's edit is lost with no indication
💡 Suggestion: Pass editingQueuedMessageId into the hook (or lift it to an atom) so the queue-processing effect can skip processing when the first message is being edited. Alternatively, skip the first message and send the second one, or clear the editing state and notify the user when their in-progress edit is dequeued.
🎭 Playwright Test Results❌ Some tests failed
Summary: 710 passed, 1 failed, 8 flaky, 224 skipped Failed Tests🪟 Windows
|
🎭 Playwright Test Results❌ Some tests failed
Summary: 723 passed, 1 failed, 7 flaky, 224 skipped Failed Tests🪟 Windows
|
Summary by cubic
Allow users to queue multiple messages while a response is streaming. Queued items are visible, editable, reorderable, and auto-send one-by-one only after the current stream ends successfully.
New Features
Bug Fixes
Written for commit fb431f5. Summary will update on new commits.
Note
Introduces queued message support so users can submit another prompt while a response is streaming; the queued prompt auto-sends only after the current stream ends successfully.
QueuedMessage,queuedMessageByIdAtom, andstreamCompletedSuccessfullyByIdAtomto track one queued message and confirmed stream completion per chatuseStreamChatwith queue APIs (queuedMessage,queueMessage,clearQueuedMessage) and processing gated byonEndsuccess; resets/sets completion flags; warns on multiple queue attemptsChatInputto queue while streaming, clear on successful queue, and clear queued message on cancel; usesshouldProcessQueueMessagesListto display queued prompt with status and a Clear actionChatResponseEndschema with optionalwasCancelled; send this flag on cancel inchat_stream_handlersqueued_message.spec.tsverifying queuing and auto-send behaviorWritten by Cursor Bugbot for commit 62ed213. This will update automatically on new commits. Configure here.