mirror of
https://github.com/khoaliber/khoj.git
synced 2026-03-02 13:18:18 +00:00
Add ability to retry a query from the web app
This commit is contained in:
@@ -50,6 +50,7 @@ interface ChatBodyDataProps {
|
|||||||
setIsChatSideBarOpen: (open: boolean) => void;
|
setIsChatSideBarOpen: (open: boolean) => void;
|
||||||
isActive?: boolean;
|
isActive?: boolean;
|
||||||
isParentProcessing?: boolean;
|
isParentProcessing?: boolean;
|
||||||
|
onRetryMessage?: (query: string, turnId?: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ChatBodyData(props: ChatBodyDataProps) {
|
function ChatBodyData(props: ChatBodyDataProps) {
|
||||||
@@ -157,6 +158,7 @@ function ChatBodyData(props: ChatBodyDataProps) {
|
|||||||
setIncomingMessages={props.setStreamedMessages}
|
setIncomingMessages={props.setStreamedMessages}
|
||||||
customClassName={chatHistoryCustomClassName}
|
customClassName={chatHistoryCustomClassName}
|
||||||
setIsChatSideBarOpen={props.setIsChatSideBarOpen}
|
setIsChatSideBarOpen={props.setIsChatSideBarOpen}
|
||||||
|
onRetryMessage={props.onRetryMessage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -422,6 +424,36 @@ export default function Chat() {
|
|||||||
setConversationID(newConversationId);
|
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 />;
|
if (isLoading) return <Loading />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -491,6 +523,7 @@ export default function Chat() {
|
|||||||
setIsChatSideBarOpen={setIsChatSideBarOpen}
|
setIsChatSideBarOpen={setIsChatSideBarOpen}
|
||||||
isActive={authenticatedData?.is_active}
|
isActive={authenticatedData?.is_active}
|
||||||
isParentProcessing={processQuerySignal}
|
isParentProcessing={processQuerySignal}
|
||||||
|
onRetryMessage={handleRetryMessage}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ interface ChatHistoryProps {
|
|||||||
customClassName?: string;
|
customClassName?: string;
|
||||||
setIsChatSideBarOpen?: (isOpen: boolean) => void;
|
setIsChatSideBarOpen?: (isOpen: boolean) => void;
|
||||||
setIsOwner?: (isOwner: boolean) => void;
|
setIsOwner?: (isOwner: boolean) => void;
|
||||||
|
onRetryMessage?: (query: string, turnId?: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TrainOfThoughtFrame {
|
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) {
|
if (!props.conversationId && !props.publicConversationSlug) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -561,6 +574,7 @@ export default function ChatHistory(props: ChatHistoryProps) {
|
|||||||
borderLeftColor={`${data?.agent?.color}-500`}
|
borderLeftColor={`${data?.agent?.color}-500`}
|
||||||
isLastMessage={index === data.chat.length - 1}
|
isLastMessage={index === data.chat.length - 1}
|
||||||
onDeleteMessage={handleDeleteMessage}
|
onDeleteMessage={handleDeleteMessage}
|
||||||
|
onRetryMessage={handleRetryMessage}
|
||||||
conversationId={props.conversationId}
|
conversationId={props.conversationId}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
@@ -589,6 +603,7 @@ export default function ChatHistory(props: ChatHistoryProps) {
|
|||||||
customClassName="fullHistory"
|
customClassName="fullHistory"
|
||||||
borderLeftColor={`${data?.agent?.color}-500`}
|
borderLeftColor={`${data?.agent?.color}-500`}
|
||||||
onDeleteMessage={handleDeleteMessage}
|
onDeleteMessage={handleDeleteMessage}
|
||||||
|
onRetryMessage={handleRetryMessage}
|
||||||
conversationId={props.conversationId}
|
conversationId={props.conversationId}
|
||||||
turnId={messageTurnId}
|
turnId={messageTurnId}
|
||||||
/>
|
/>
|
||||||
@@ -629,6 +644,7 @@ export default function ChatHistory(props: ChatHistoryProps) {
|
|||||||
conversationId={props.conversationId}
|
conversationId={props.conversationId}
|
||||||
turnId={messageTurnId}
|
turnId={messageTurnId}
|
||||||
onDeleteMessage={handleDeleteMessage}
|
onDeleteMessage={handleDeleteMessage}
|
||||||
|
onRetryMessage={handleRetryMessage}
|
||||||
customClassName="fullHistory"
|
customClassName="fullHistory"
|
||||||
borderLeftColor={`${data?.agent?.color}-500`}
|
borderLeftColor={`${data?.agent?.color}-500`}
|
||||||
isLastMessage={index === props.incomingMessages!.length - 1}
|
isLastMessage={index === props.incomingMessages!.length - 1}
|
||||||
@@ -653,6 +669,7 @@ export default function ChatHistory(props: ChatHistoryProps) {
|
|||||||
}}
|
}}
|
||||||
conversationId={props.conversationId}
|
conversationId={props.conversationId}
|
||||||
onDeleteMessage={handleDeleteMessage}
|
onDeleteMessage={handleDeleteMessage}
|
||||||
|
onRetryMessage={handleRetryMessage}
|
||||||
customClassName="fullHistory"
|
customClassName="fullHistory"
|
||||||
borderLeftColor={`${data?.agent?.color}-500`}
|
borderLeftColor={`${data?.agent?.color}-500`}
|
||||||
isLastMessage={true}
|
isLastMessage={true}
|
||||||
|
|||||||
@@ -158,7 +158,8 @@ button.codeCopyButton:hover {
|
|||||||
|
|
||||||
div.feedbackButtons img,
|
div.feedbackButtons img,
|
||||||
button.codeCopyButton img,
|
button.codeCopyButton img,
|
||||||
button.copyButton img {
|
button.copyButton img,
|
||||||
|
button.retryButton img {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
Trash,
|
Trash,
|
||||||
Toolbox,
|
Toolbox,
|
||||||
Browser,
|
Browser,
|
||||||
|
ArrowClockwise,
|
||||||
} from "@phosphor-icons/react";
|
} from "@phosphor-icons/react";
|
||||||
|
|
||||||
import DOMPurify from "dompurify";
|
import DOMPurify from "dompurify";
|
||||||
@@ -273,6 +274,7 @@ interface ChatMessageProps {
|
|||||||
isLastMessage?: boolean;
|
isLastMessage?: boolean;
|
||||||
agent?: AgentData;
|
agent?: AgentData;
|
||||||
onDeleteMessage: (turnId?: string) => void;
|
onDeleteMessage: (turnId?: string) => void;
|
||||||
|
onRetryMessage?: (query: string, turnId?: string) => void;
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
turnId?: string;
|
turnId?: string;
|
||||||
generatedImage?: string;
|
generatedImage?: string;
|
||||||
@@ -814,6 +816,38 @@ const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>((props, ref) =>
|
|||||||
/>
|
/>
|
||||||
</button>
|
</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
|
<button
|
||||||
title="Copy"
|
title="Copy"
|
||||||
className={`${styles.copyButton}`}
|
className={`${styles.copyButton}`}
|
||||||
|
|||||||
Reference in New Issue
Block a user