Add ability to retry a query from the web app

This commit is contained in:
Debanjum
2025-06-04 01:15:30 -07:00
parent 05d4e19cb8
commit d16f9f272b
4 changed files with 86 additions and 1 deletions

View File

@@ -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}
/>
</div>
<div
@@ -422,6 +424,36 @@ export default function Chat() {
setConversationID(newConversationId);
};
const handleRetryMessage = (query: string, turnId?: string) => {
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 <Loading />;
return (
@@ -491,6 +523,7 @@ export default function Chat() {
setIsChatSideBarOpen={setIsChatSideBarOpen}
isActive={authenticatedData?.is_active}
isParentProcessing={processQuerySignal}
onRetryMessage={handleRetryMessage}
/>
</Suspense>
</div>

View File

@@ -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}
/>
</React.Fragment>
@@ -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}

View File

@@ -158,7 +158,8 @@ button.codeCopyButton:hover {
div.feedbackButtons img,
button.codeCopyButton img,
button.copyButton img {
button.copyButton img,
button.retryButton img {
width: 24px;
}

View File

@@ -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<HTMLDivElement, ChatMessageProps>((props, ref) =>
/>
</button>
)}
{props.chatMessage.by === "khoj" && props.onRetryMessage && props.isLastMessage && (
<button
title="Retry"
className={`${styles.retryButton}`}
onClick={() => {
const turnId = props.chatMessage.turnId || props.turnId;
const query = props.chatMessage.rawQuery || props.chatMessage.intent?.query;
console.log("Retry button clicked for turnId:", turnId);
console.log("ChatMessage data:", {
rawQuery: props.chatMessage.rawQuery,
intent: props.chatMessage.intent,
message: props.chatMessage.message
});
console.log("Extracted query:", query);
if (query) {
props.onRetryMessage?.(query, turnId);
} else {
console.error("No original query found for retry");
// Fallback: try to get from a previous user message or show an input dialog
const fallbackQuery = prompt("Enter the original query to retry:");
if (fallbackQuery) {
props.onRetryMessage?.(fallbackQuery, turnId);
}
}
}}
>
<ArrowClockwise
alt="Retry Message"
className="hsl(var(--muted-foreground)) hover:text-blue-500"
/>
</button>
)}
<button
title="Copy"
className={`${styles.copyButton}`}