Skip to content

Conversation

@Kalpana-chavhan
Copy link

@Kalpana-chavhan Kalpana-chavhan commented Jan 14, 2026

Closes #278

Description

This pull request implements a Quick-Refine Action Toolbar for AI-generated responses. Previously, users had to manually type follow-up prompts to modify AI outputs (e.g., asking to shorten a response).
This feature introduces a set of "one-click" buttons that appear upon hovering over an AI message, allowing users to instantly refine, reformat, or regenerate responses.
This enhancement reduces user friction, improves interaction speed, and guides users toward more effective LLM usage.


Changes Made

  • New Component: Created QuickRefineToolbar.tsx to handle the UI and logic for refinement actions (Shorten, Professional Tone, Listify, and Retry).
  • UI Enhancement: Modified message-item.tsx to include a hover-reveal mechanism. The toolbar is hidden by default and fades in when the user hovers over an AI response bubble using Tailwind CSS group and group-hover utilities.
  • Data Flow Integration: Updated messages-list.tsx to pull the sendMessage function from the useChat hook and pass it as a callback prop to MessageItem.
  • Styling: Used lucide-react icons and custom Tailwind transitions to ensure the toolbar feels native to the existing design system.

Visual Changes

The toolbar appears at the bottom-left of AI messages with a smooth transition (opacity-0 to opacity-100) on hover.


Checklist

  • I have read the contributing guidelines.
  • I have performed a self-review of my own code.
  • I have added necessary documentation (if applicable).
  • My changes generate no new warnings and follow the project's design patterns.

Summary by CodeRabbit

  • New Features

    • Quick refinement toolbar for AI responses on hover (Shorten, Professional, Listify, Retry), actionable from message list.
  • Improvements

    • Messages list: improved date separators, updated empty-state text, and refined message layout and spacing.
    • AI message items now show a hover toolbar when sending is available.
  • Style

    • Minor CSS animation formatting changes (no behavioral impact).

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 14, 2026

📝 Walkthrough

Walkthrough

A new QuickRefineToolbar component was added and integrated into MessageItem to surface preset refinement actions for AI messages. MessagesList now uses the chat hook and passes its sendMessage as onSendMessage to MessageItem; InputProps type was added and CSS keyframes were reformatted.

Changes

Cohort / File(s) Summary
Quick-Refine Toolbar
Frontend/src/components/chat/QuickRefineToolbar.tsx
New React component exporting refinement buttons (Shorten, Professional, Listify, Retry) that invoke an onRefine(prompt) callback when clicked; includes icons and hover-visible styling.
Message rendering & integration
Frontend/src/components/chat/message-item.tsx, Frontend/src/components/chat/messages-list.tsx
MessageItem signature updated to accept optional onSendMessage; AI messages render inside a hover-group and show QuickRefineToolbar when onSendMessage is present. MessagesList uses useChat (markMessageAsSeen, sendMessage), updates date separator logic, and passes sendMessage to MessageItem.
UI types & styles
Frontend/src/components/ui/input.tsx, Frontend/src/index.css
Added exported InputProps interface and switched to namespace React import in input.tsx. CSS animation keyframes reformatted to single-line without behavior changes.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant MessageItem
    participant QuickRefineToolbar
    participant MessagesList
    participant useChat as useChat Hook

    User->>MessageItem: Hover over AI message
    MessageItem->>QuickRefineToolbar: Reveal toolbar (group-hover)
    User->>QuickRefineToolbar: Click a refinement button (prompt)
    QuickRefineToolbar->>MessageItem: onRefine(prompt)
    MessageItem->>MessagesList: onSendMessage(prompt)
    MessagesList->>useChat: sendMessage(refinement prompt)
    useChat->>MessagesList: request processed / sent to backend
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

enhancement, frontend

Poem

🐰 I hopped in with buttons quick and spry,
Click a tweak, let the AI reply.
Shorten, polish, listify with cheer—
One little click, the answer's clear! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature added: quick-refine action buttons for AI response messages, which is the primary change throughout the PR.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #278: QuickRefineToolbar component with Shorten, Professional, Listify, and Retry actions; hover-visible toolbar with opacity transitions; integration into MessageItem; sendMessage callback wiring.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing the quick-refine toolbar feature. Minor refactoring in InputProps interface and CSS formatting are supporting changes aligned with the PR objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
Frontend/src/components/ui/input.tsx (1)

24-24: Consider also exporting InputProps for consumer convenience.

Currently only Input is exported. Since InputProps is defined as a public interface, it should also be exported so consumers can use or extend it.

Suggested fix
-export { Input };
+export { Input, type InputProps };
Frontend/src/components/chat/messages-list.tsx (1)

64-79: Avoid mutating Date objects with setHours; use startOfDay from date-fns.

setHours() mutates the original Date object in place. While this currently works because parseISO creates fresh objects each iteration, it's fragile and error-prone. Since you're already importing from date-fns, use the non-mutating startOfDay function instead.

♻️ Suggested refactor

Update the import at line 3:

-import { format, isEqual, parseISO } from "date-fns";
+import { format, isEqual, parseISO, startOfDay } from "date-fns";

Then update the date comparison:

             // Date separator for subsequent messages
             if (index < array.length - 1) {
               const nextDate = parseISO(array[index + 1].createdAt);
-              if (!isEqual(
-                new Date(messageDate.setHours(0,0,0,0)), 
-                new Date(nextDate.setHours(0,0,0,0))
-              )) {
+              if (!isEqual(startOfDay(messageDate), startOfDay(nextDate))) {
                 acc.push(

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32907ff and 624caa4.

📒 Files selected for processing (4)
  • Frontend/src/components/chat/QuickRefineToolbar.tsx
  • Frontend/src/components/chat/message-item.tsx
  • Frontend/src/components/chat/messages-list.tsx
  • Frontend/src/components/ui/input.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • Frontend/src/components/chat/QuickRefineToolbar.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
Frontend/src/components/chat/messages-list.tsx (2)
Frontend/src/lib/useChat.tsx (1)
  • useChat (223-229)
Frontend/src/components/chat/message-item.tsx (1)
  • MessageItem (11-61)
Frontend/src/components/chat/message-item.tsx (1)
Frontend/src/redux/chatSlice.ts (1)
  • Message (5-12)
🔇 Additional comments (7)
Frontend/src/components/ui/input.tsx (2)

1-7: LGTM! Clean refactoring of imports and type definitions.

The changes improve the component's type safety and maintainability:

  • Namespace import (import * as React) is consistent with modern React/TypeScript conventions.
  • Exporting InputProps allows consumers to extend or reference the type.
  • The forwardRef generic is now properly typed with InputProps.

12-15: Default styles are correctly preserved.

The base styling classes in the cn() call are intact, ensuring the Input component renders with proper styling out of the box. This addresses the concern from the previous review about unstyled inputs.

Frontend/src/components/chat/message-item.tsx (3)

4-9: LGTM!

The interface properly types the component props. Making onSendMessage optional maintains backward compatibility and allows the component to be used without the toolbar when needed.


14-35: LGTM!

User message styling with shadow and improved typography is clean. Status icon rendering logic is correctly preserved.


36-57: LGTM!

The group class correctly enables Tailwind's group-hover utilities for the toolbar. The conditional rendering ensures the toolbar only appears when onSendMessage is available. The flex-col structure properly positions the toolbar below the AI message bubble as specified in the requirements.

Frontend/src/components/chat/messages-list.tsx (2)

17-18: LGTM!

Correctly destructures sendMessage from the chat hook to enable the quick-refine toolbar functionality.


55-62: LGTM!

MessageItem correctly receives sendMessage as the onSendMessage callback, enabling the quick-refine toolbar to send refinement prompts through the chat context.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Frontend/src/index.css (1)

113-120: Critical: Missing closing brace for @layer base block.

The @layer base block opened at line 113 is never closed. Line 120 shows only whitespace, but the closing } is missing. This will cause CSS parsing errors and break all styling.

Proposed fix
 `@layer` base {
   * {
     `@apply` border-border outline-ring/50;
   }
   body {
     `@apply` bg-background text-foreground;
   }
-
+}
🤖 Fix all issues with AI agents
In `@Frontend/src/components/ui/input.tsx`:
- Around line 9-12: The Input component lost its default base styling because
the cn(...) call in Input (input.tsx) now only passes through the incoming
className, leaving many usages unstyled; restore the original base classes
(e.g., border, rounded, px/py, text-sm, bg/placeholder styles) by adding them
back as the first argument to the cn(...) invocation inside the Input component,
or alternatively update every call site of the Input component to pass an
explicit className with equivalent styling (search for usages like
BasicDetails.tsx and message/search inputs) so no instance renders as an
unstyled native input.
🧹 Nitpick comments (4)
Frontend/src/components/chat/QuickRefineToolbar.tsx (2)

9-34: Consider moving static actions array outside the component.

The actions array is recreated on every render but never changes. Moving it outside the component avoids unnecessary object allocations.

Proposed refactor
+const REFINE_ACTIONS = [
+  { 
+    id: "shorten", 
+    label: "Shorten", 
+    icon: <Scissors className="h-3 w-3" />, 
+    prompt: "Summarize the previous response to be much shorter." 
+  },
+  { 
+    id: "pro", 
+    label: "Professional", 
+    icon: <Briefcase className="h-3 w-3" />, 
+    prompt: "Rewrite the previous response in a professional, formal tone." 
+  },
+  { 
+    id: "list", 
+    label: "Listify", 
+    icon: <List className="h-3 w-3" />, 
+    prompt: "Convert the previous response into a bulleted list." 
+  },
+  { 
+    id: "retry", 
+    label: "Retry", 
+    icon: <RotateCcw className="h-3 w-3" />, 
+    prompt: "Regenerate the previous response." 
+  },
+];
+
 const QuickRefineToolbar: React.FC<QuickRefineToolbarProps> = ({ onRefine }) => {
-  const actions = [
-    // ... all action definitions
-  ];
-
   return (
     <div className="flex flex-wrap gap-2 mt-2 opacity-0 group-hover:opacity-100 transition-opacity duration-300 ease-in-out justify-start">
-      {actions.map((action) => (
+      {REFINE_ACTIONS.map((action) => (

42-42: Buttons use hardcoded light-mode colors only.

The styling (bg-white, text-gray-600, hover:bg-purple-50) assumes light mode. If the app supports dark mode (as suggested by index.css having .dark theme variables), these buttons will appear jarring in dark mode.

Suggested dark mode support
-          className="flex items-center gap-1 px-2 py-1 text-[10px] font-medium bg-white hover:bg-purple-50 border border-gray-200 rounded-md transition-all shadow-sm text-gray-600 hover:text-purple-700 hover:border-purple-200"
+          className="flex items-center gap-1 px-2 py-1 text-[10px] font-medium bg-white dark:bg-gray-700 hover:bg-purple-50 dark:hover:bg-purple-900 border border-gray-200 dark:border-gray-600 rounded-md transition-all shadow-sm text-gray-600 dark:text-gray-300 hover:text-purple-700 dark:hover:text-purple-300 hover:border-purple-200 dark:hover:border-purple-700"
Frontend/src/components/chat/message-item.tsx (1)

37-55: AI message styling also lacks dark mode support.

The AI message bubble uses hardcoded light-mode colors (bg-gray-100, text-gray-800, border-gray-200) similar to the toolbar. For consistency, consider adding dark mode variants here as well.

Suggested dark mode classes
-            <div className="bg-gray-100 rounded-lg p-3 shadow-sm border border-gray-200">
-              <p className="text-sm text-gray-800">{message.message}</p>
+            <div className="bg-gray-100 dark:bg-gray-700 rounded-lg p-3 shadow-sm border border-gray-200 dark:border-gray-600">
+              <p className="text-sm text-gray-800 dark:text-gray-200">{message.message}</p>
Frontend/src/components/chat/messages-list.tsx (1)

67-70: setHours() mutates the original Date objects.

messageDate.setHours(0,0,0,0) mutates messageDate in place (and similarly for nextDate). While this happens to work because messageDate is recreated each reduce iteration, it's a fragile pattern. Use date-fns comparison functions instead.

Cleaner date comparison using date-fns
+import { format, isEqual, parseISO, startOfDay } from "date-fns";
 // ...
-              if (!isEqual(
-                new Date(messageDate.setHours(0,0,0,0)), 
-                new Date(nextDate.setHours(0,0,0,0))
-              )) {
+              if (!isEqual(startOfDay(messageDate), startOfDay(nextDate))) {

startOfDay() returns a new Date without mutating the original.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3be437 and 32907ff.

📒 Files selected for processing (5)
  • Frontend/src/components/chat/QuickRefineToolbar.tsx
  • Frontend/src/components/chat/message-item.tsx
  • Frontend/src/components/chat/messages-list.tsx
  • Frontend/src/components/ui/input.tsx
  • Frontend/src/index.css
🧰 Additional context used
🧬 Code graph analysis (2)
Frontend/src/components/chat/message-item.tsx (1)
Frontend/src/redux/chatSlice.ts (1)
  • Message (5-12)
Frontend/src/components/chat/messages-list.tsx (2)
Frontend/src/lib/useChat.tsx (1)
  • useChat (223-229)
Frontend/src/components/chat/message-item.tsx (1)
  • MessageItem (11-61)
🔇 Additional comments (7)
Frontend/src/index.css (1)

123-137: LGTM!

The keyframe reformatting from multi-line to single-line is purely cosmetic and maintains identical animation behavior.

Frontend/src/components/chat/QuickRefineToolbar.tsx (1)

36-49: LGTM on the core implementation!

The toolbar structure is clean with proper key usage, accessible button elements, and smooth hover transitions via group-hover. The refinement prompts are well-crafted for the intended use cases.

Frontend/src/components/chat/message-item.tsx (2)

6-9: LGTM!

Clean interface definition with optional onSendMessage prop maintains backward compatibility while enabling the new toolbar feature.


52-55: LGTM on toolbar integration!

The conditional rendering ensures the toolbar only appears when onSendMessage is provided, and the group class on the parent container correctly enables the hover-based visibility.

Frontend/src/components/chat/messages-list.tsx (3)

17-17: LGTM!

Correctly destructures sendMessage from the useChat hook to enable the refinement feature.


56-62: LGTM!

The sendMessage callback is correctly passed to MessageItem, enabling the quick-refine feature for AI responses.


36-36: sendMessage is not used in this effect and should not be added to dependencies.

sendMessage is passed to MessageItem during render (line 60), not called within the effect at lines 23–36. The current dependencies [messages, lastMarkedAsSeen, markMessageAsSeen] are correct because markMessageAsSeen is invoked in the effect (line 32). However, neither sendMessage nor markMessageAsSeen are memoized with useCallback in the useChat hook, so both functions are recreated on every render. Since sendMessage is passed down as a prop, ensure child components handle its changing reference appropriately to avoid cascading re-renders.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@Kalpana-chavhan Kalpana-chavhan force-pushed the feat/quick-refine-toolbar branch from 32907ff to 624caa4 Compare January 14, 2026 08:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FEATURE REQUEST:Implement "Quick-Refine" action buttons for AI responses

1 participant