From 5b2f3a340dd79933f26502d530ed3a6b17d88786 Mon Sep 17 00:00:00 2001 From: Nicolas Varrot Date: Wed, 11 Feb 2026 21:56:48 +0000 Subject: [PATCH] feat: add retry/resend button on user messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hover over any user message to reveal a retry button (↻) that resends the message text. Disabled while a response is generating. Includes EN/FR i18n strings. --- src/components/Chat.tsx | 2 +- src/components/ChatMessage.tsx | 15 +++++++++++++-- src/lib/i18n.ts | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx index bb2c400..903f948 100644 --- a/src/components/Chat.tsx +++ b/src/components/Chat.tsx @@ -112,7 +112,7 @@ export function Chat({ messages, isGenerating, status, onSend, onAbort }: Props) )} {messages.filter(hasVisibleContent).map(msg => ( - + ))} {showTyping && }
diff --git a/src/components/ChatMessage.tsx b/src/components/ChatMessage.tsx index 41a4dfd..71eb8a2 100644 --- a/src/components/ChatMessage.tsx +++ b/src/components/ChatMessage.tsx @@ -9,7 +9,7 @@ import { ThinkingBlock } from './ThinkingBlock'; import { CodeBlock } from './CodeBlock'; import { ToolCall } from './ToolCall'; import { ImageBlock, buildImageSrc } from './ImageBlock'; -import { Bot, User, Wrench, Copy, Check } from 'lucide-react'; +import { Bot, User, Wrench, Copy, Check, RefreshCw } from 'lucide-react'; import { t, getLocale } from '../lib/i18n'; import { useLocale } from '../hooks/useLocale'; // ChevronDown, ChevronRight, Wrench still used by InternalOnlyMessage @@ -243,7 +243,7 @@ function getPlainText(message: ChatMessageType): string { return message.content; } -export function ChatMessageComponent({ message }: { message: ChatMessageType }) { +export function ChatMessageComponent({ message, onRetry }: { message: ChatMessageType; onRetry?: (text: string) => void }) { useLocale(); // re-render on locale change const isUser = message.role === 'user'; @@ -278,6 +278,17 @@ export function ChatMessageComponent({ message }: { message: ChatMessageType }) {!isUser && !message.isStreaming && getPlainText(message).trim() && ( )} + {/* Retry button (user messages only) */} + {isUser && onRetry && ( + + )} {/* User-visible text */} {message.blocks.length > 0 ? renderTextBlocks(message.blocks) : (
diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts index acac2c5..2d3fc70 100644 --- a/src/lib/i18n.ts +++ b/src/lib/i18n.ts @@ -59,6 +59,7 @@ const en = { // Message actions 'message.copy': 'Copy message', 'message.copied': 'Copied!', + 'message.retry': 'Resend message', // Timestamps 'time.yesterday': 'Yesterday', @@ -127,6 +128,7 @@ const fr: Record = { 'message.copy': 'Copier le message', 'message.copied': 'Copié !', + 'message.retry': 'Renvoyer le message', 'time.yesterday': 'Hier',