diff --git a/src/interface/web/app/chat/page.tsx b/src/interface/web/app/chat/page.tsx index ecd10a4f..0e913dc7 100644 --- a/src/interface/web/app/chat/page.tsx +++ b/src/interface/web/app/chat/page.tsx @@ -50,6 +50,7 @@ interface ChatBodyDataProps { setIsChatSideBarOpen: (open: boolean) => void; isActive?: boolean; isParentProcessing?: boolean; + onRetryMessage?: (query: string, turnId?: string) => void; } function ChatBodyData(props: ChatBodyDataProps) { @@ -157,6 +158,7 @@ function ChatBodyData(props: ChatBodyDataProps) { setIncomingMessages={props.setStreamedMessages} customClassName={chatHistoryCustomClassName} setIsChatSideBarOpen={props.setIsChatSideBarOpen} + onRetryMessage={props.onRetryMessage} />
{ + if (!query) { + console.warn("No query provided for retry"); + return; + } + + // If we have a turnId, delete the old turn first + if (turnId) { + // Delete from streaming messages if present + setMessages((prevMessages) => prevMessages.filter((msg) => msg.turnId !== turnId)); + + // Also call the delete API to remove from conversation history + fetch("/api/chat/conversation/message", { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + conversation_id: conversationId, + turn_id: turnId, + }), + }).catch((error) => { + console.error("Failed to delete message for retry:", error); + }); + } + + // Re-send the original query + setQueryToProcess(query); + }; + if (isLoading) return ; return ( @@ -491,6 +523,7 @@ export default function Chat() { setIsChatSideBarOpen={setIsChatSideBarOpen} isActive={authenticatedData?.is_active} isParentProcessing={processQuerySignal} + onRetryMessage={handleRetryMessage} />
diff --git a/src/interface/web/app/components/chatHistory/chatHistory.tsx b/src/interface/web/app/components/chatHistory/chatHistory.tsx index 94f12650..bd97bb31 100644 --- a/src/interface/web/app/components/chatHistory/chatHistory.tsx +++ b/src/interface/web/app/components/chatHistory/chatHistory.tsx @@ -41,6 +41,7 @@ interface ChatHistoryProps { customClassName?: string; setIsChatSideBarOpen?: (isOpen: boolean) => void; setIsOwner?: (isOwner: boolean) => void; + onRetryMessage?: (query: string, turnId?: string) => void; } interface TrainOfThoughtFrame { @@ -508,6 +509,18 @@ export default function ChatHistory(props: ChatHistoryProps) { } }; + const handleRetryMessage = (query: string, turnId?: string) => { + if (!query) return; + + // Delete the message from local state first + if (turnId) { + handleDeleteMessage(turnId); + } + + // Then trigger the retry + props.onRetryMessage?.(query, turnId); + }; + if (!props.conversationId && !props.publicConversationSlug) { return null; } @@ -561,6 +574,7 @@ export default function ChatHistory(props: ChatHistoryProps) { borderLeftColor={`${data?.agent?.color}-500`} isLastMessage={index === data.chat.length - 1} onDeleteMessage={handleDeleteMessage} + onRetryMessage={handleRetryMessage} conversationId={props.conversationId} /> @@ -589,6 +603,7 @@ export default function ChatHistory(props: ChatHistoryProps) { customClassName="fullHistory" borderLeftColor={`${data?.agent?.color}-500`} onDeleteMessage={handleDeleteMessage} + onRetryMessage={handleRetryMessage} conversationId={props.conversationId} turnId={messageTurnId} /> @@ -629,6 +644,7 @@ export default function ChatHistory(props: ChatHistoryProps) { conversationId={props.conversationId} turnId={messageTurnId} onDeleteMessage={handleDeleteMessage} + onRetryMessage={handleRetryMessage} customClassName="fullHistory" borderLeftColor={`${data?.agent?.color}-500`} isLastMessage={index === props.incomingMessages!.length - 1} @@ -653,6 +669,7 @@ export default function ChatHistory(props: ChatHistoryProps) { }} conversationId={props.conversationId} onDeleteMessage={handleDeleteMessage} + onRetryMessage={handleRetryMessage} customClassName="fullHistory" borderLeftColor={`${data?.agent?.color}-500`} isLastMessage={true} diff --git a/src/interface/web/app/components/chatMessage/chatMessage.module.css b/src/interface/web/app/components/chatMessage/chatMessage.module.css index 5309c175..a31f0bdc 100644 --- a/src/interface/web/app/components/chatMessage/chatMessage.module.css +++ b/src/interface/web/app/components/chatMessage/chatMessage.module.css @@ -158,7 +158,8 @@ button.codeCopyButton:hover { div.feedbackButtons img, button.codeCopyButton img, -button.copyButton img { +button.copyButton img, +button.retryButton img { width: 24px; } diff --git a/src/interface/web/app/components/chatMessage/chatMessage.tsx b/src/interface/web/app/components/chatMessage/chatMessage.tsx index f34cf11d..e25dc814 100644 --- a/src/interface/web/app/components/chatMessage/chatMessage.tsx +++ b/src/interface/web/app/components/chatMessage/chatMessage.tsx @@ -32,6 +32,7 @@ import { Trash, Toolbox, Browser, + ArrowClockwise, } from "@phosphor-icons/react"; import DOMPurify from "dompurify"; @@ -273,6 +274,7 @@ interface ChatMessageProps { isLastMessage?: boolean; agent?: AgentData; onDeleteMessage: (turnId?: string) => void; + onRetryMessage?: (query: string, turnId?: string) => void; conversationId: string; turnId?: string; generatedImage?: string; @@ -814,6 +816,38 @@ const ChatMessage = forwardRef((props, ref) => /> )} + {props.chatMessage.by === "khoj" && props.onRetryMessage && props.isLastMessage && ( + + )}