feat: add message branching for regenerated responses#9
Conversation
- Add parent_id column to chat_messages table for tree structure - Show regenerate button only on the latest assistant message - Implement branch navigation UI (< 1 of N >) for messages with siblings - Prevent duplicate user messages when regenerating responses - Sync frontend state with database after response completion - Fix MessageBranchContent className override bug that showed all branches Co-authored-by: Cursor <cursoragent@cursor.com>
Summary of ChangesHello @kowyo, 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 introduces a significant feature that allows users to explore and manage different versions of AI responses within a single chat conversation. By implementing a message branching system, users can regenerate responses and then navigate between these alternative outputs, providing greater flexibility and control over their interactions. The changes span database schema, backend message persistence, and frontend UI, ensuring a seamless and intuitive user experience for managing branched conversations. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. 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 successfully implements message branching for AI responses, allowing users to navigate between different versions of an AI's reply. The changes involve adding a parent_id column to the chat_messages table in the database, updating the backend to correctly persist messages with this new relationship, and enhancing the frontend to display and manage these branched conversations. The logic for preventing duplicate user messages and showing the regenerate button only on the latest assistant message aligns well with the feature's goals. Overall, the implementation provides a robust foundation for conversational branching.
| let parentId = lastMessageId; | ||
| if (!parentId) { | ||
| const lastInDb = await pool.query( | ||
| `select id from chat_messages where chat_id = $1 order by created_at desc limit 1`, | ||
| [chatId] | ||
| ); | ||
| parentId = lastInDb.rows[0]?.id; |
There was a problem hiding this comment.
The fallback logic for determining parentId in the onFinish callback is problematic. The lastMessageId variable is intended to hold the ID of the user message that initiated the current AI response. If lastMessageId is null at this point, it indicates an issue with the preceding user message's persistence or identification (lines 33-84). Relying on a query for the absolute latest message in the database (select id from chat_messages where chat_id = $1 order by created_at desc limit 1) can lead to an incorrect conversation tree, as the latest message might be another assistant message or an unrelated user message. This creates a logically flawed parent-child relationship. It is more robust to ensure lastMessageId is always correctly populated. If it is unexpectedly null, the assistant message should be inserted with a null parent_id (creating an orphaned message) to highlight the underlying issue, rather than creating an incorrect link. The database schema allows parent_id to be null, so this change will result in an orphaned message if lastMessageId is indeed null, which is preferable to an incorrect link.
| let parentId = lastMessageId; | |
| if (!parentId) { | |
| const lastInDb = await pool.query( | |
| `select id from chat_messages where chat_id = $1 order by created_at desc limit 1`, | |
| [chatId] | |
| ); | |
| parentId = lastInDb.rows[0]?.id; | |
| const parentId = lastMessageId; |
The client now sends parentMessageId (the last message in the current branch) to the server when creating new messages. This ensures new messages are linked to the correct parent based on the user's selected branch, rather than always using the absolute latest message in the database. Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
< 1 of N >controls for messages with multiple versionsChanges
Database
parent_idcolumn tochat_messagestable to create a tree structure for conversation historyBackend (
app/api/chat/route.ts)parent_idon new messages to maintain proper tree structureFrontend
ChatMessageListto display branch selector when multiple versions existonBranchChangehandler to switch between message versionsMessageBranchContentclassName override bug that caused all branches to display simultaneouslyTest plan
1 of 2after regenerationMade with Cursor