mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-03-26 17:51:54 +01:00
Rebased concurrent chats (#2214)
* refactored for stop / regenerate * properly reset blank screen * functional new message carry-over * robust chat session state persistence * add env variable * rebased onto regenerate * squash * squash * squash * rebase + robustify tool calling * squash * alembic * remove environment variable * simplify interface * squash * minor streaming improvement * some robustification
This commit is contained in:
parent
a873fc6483
commit
5f12b7ad58
@ -43,13 +43,20 @@ import {
|
||||
uploadFilesForChat,
|
||||
useScrollonStream,
|
||||
} from "./lib";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { usePopup } from "@/components/admin/connectors/Popup";
|
||||
import { SEARCH_PARAM_NAMES, shouldSubmitOnLoad } from "./searchParams";
|
||||
import { useDocumentSelection } from "./useDocumentSelection";
|
||||
import { LlmOverride, useFilters, useLlmOverride } from "@/lib/hooks";
|
||||
import { computeAvailableFilters } from "@/lib/filters";
|
||||
import { ChatState, FeedbackType } from "./types";
|
||||
import { ChatState, FeedbackType, RegenerationState } from "./types";
|
||||
import { DocumentSidebar } from "./documentSidebar/DocumentSidebar";
|
||||
import { DanswerInitializingLoader } from "@/components/DanswerInitializingLoader";
|
||||
import { FeedbackModal } from "./modal/FeedbackModal";
|
||||
@ -84,6 +91,7 @@ import { SetDefaultModelModal } from "./modal/SetDefaultModelModal";
|
||||
import { DeleteChatModal } from "./modal/DeleteChatModal";
|
||||
import { MinimalMarkdown } from "@/components/chat_search/MinimalMarkdown";
|
||||
import ExceptionTraceModal from "@/components/modals/ExceptionTraceModal";
|
||||
|
||||
import { SEARCH_TOOL_NAME } from "./tools/constants";
|
||||
import { useUser } from "@/components/user/UserProvider";
|
||||
|
||||
@ -212,10 +220,18 @@ export function ChatPage({
|
||||
}
|
||||
}, [liveAssistant]);
|
||||
|
||||
const stopGeneration = () => {
|
||||
if (abortController) {
|
||||
abortController.abort();
|
||||
const stopGenerating = () => {
|
||||
const currentSession = currentSessionId();
|
||||
const controller = abortControllers.get(currentSession);
|
||||
if (controller) {
|
||||
controller.abort();
|
||||
setAbortControllers((prev) => {
|
||||
const newControllers = new Map(prev);
|
||||
newControllers.delete(currentSession);
|
||||
return newControllers;
|
||||
});
|
||||
}
|
||||
|
||||
const lastMessage = messageHistory[messageHistory.length - 1];
|
||||
if (
|
||||
lastMessage &&
|
||||
@ -223,16 +239,16 @@ export function ChatPage({
|
||||
lastMessage.toolCalls[0] &&
|
||||
lastMessage.toolCalls[0].tool_result === undefined
|
||||
) {
|
||||
const newCompleteMessageMap = new Map(completeMessageDetail.messageMap);
|
||||
const newCompleteMessageMap = new Map(
|
||||
currentMessageMap(completeMessageDetail)
|
||||
);
|
||||
const updatedMessage = { ...lastMessage, toolCalls: [] };
|
||||
newCompleteMessageMap.set(lastMessage.messageId, updatedMessage);
|
||||
setCompleteMessageDetail({
|
||||
sessionId: completeMessageDetail.sessionId,
|
||||
messageMap: newCompleteMessageMap,
|
||||
});
|
||||
updateCompleteMessageDetail(currentSession, newCompleteMessageMap);
|
||||
}
|
||||
};
|
||||
|
||||
updateChatState("input", currentSession);
|
||||
};
|
||||
// this is for "@"ing assistants
|
||||
|
||||
// this is used to track which assistant is being used to generate the current message
|
||||
@ -308,10 +324,7 @@ export function ChatPage({
|
||||
} else {
|
||||
setSelectedAssistant(undefined);
|
||||
}
|
||||
setCompleteMessageDetail({
|
||||
sessionId: null,
|
||||
messageMap: new Map(),
|
||||
});
|
||||
updateCompleteMessageDetail(null, new Map());
|
||||
setChatSessionSharedStatus(ChatSessionSharedStatus.Private);
|
||||
|
||||
// if we're supposed to submit on initial load, then do that here
|
||||
@ -341,13 +354,11 @@ export function ChatPage({
|
||||
// This corresponds to a "renaming" of chat, which occurs after first message
|
||||
// stream
|
||||
if (
|
||||
messageHistory[messageHistory.length - 1]?.type !== "error" ||
|
||||
loadedSessionId != null
|
||||
(messageHistory[messageHistory.length - 1]?.type !== "error" ||
|
||||
loadedSessionId != null) &&
|
||||
!currentChatAnswering()
|
||||
) {
|
||||
setCompleteMessageDetail({
|
||||
sessionId: chatSession.chat_session_id,
|
||||
messageMap: newMessageMap,
|
||||
});
|
||||
updateCompleteMessageDetail(chatSession.chat_session_id, newMessageMap);
|
||||
|
||||
const latestMessageId =
|
||||
newMessageHistory[newMessageHistory.length - 1]?.messageId;
|
||||
@ -394,10 +405,31 @@ export function ChatPage({
|
||||
searchParams.get(SEARCH_PARAM_NAMES.USER_MESSAGE) || ""
|
||||
);
|
||||
|
||||
const [completeMessageDetail, setCompleteMessageDetail] = useState<{
|
||||
sessionId: number | null;
|
||||
messageMap: Map<number, Message>;
|
||||
}>({ sessionId: null, messageMap: new Map() });
|
||||
const [completeMessageDetail, setCompleteMessageDetail] = useState<
|
||||
Map<number | null, Map<number, Message>>
|
||||
>(new Map());
|
||||
|
||||
const updateCompleteMessageDetail = (
|
||||
sessionId: number | null,
|
||||
messageMap: Map<number, Message>
|
||||
) => {
|
||||
setCompleteMessageDetail((prevState) => {
|
||||
const newState = new Map(prevState);
|
||||
newState.set(sessionId, messageMap);
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
const currentMessageMap = (
|
||||
messageDetail: Map<number | null, Map<number, Message>>
|
||||
) => {
|
||||
return (
|
||||
messageDetail.get(chatSessionIdRef.current) || new Map<number, Message>()
|
||||
);
|
||||
};
|
||||
const currentSessionId = (): number => {
|
||||
return chatSessionIdRef.current!;
|
||||
};
|
||||
|
||||
const upsertToCompleteMessageMap = ({
|
||||
messages,
|
||||
@ -416,7 +448,7 @@ export function ChatPage({
|
||||
}) => {
|
||||
// deep copy
|
||||
const frozenCompleteMessageMap =
|
||||
completeMessageMapOverride || completeMessageDetail.messageMap;
|
||||
completeMessageMapOverride || currentMessageMap(completeMessageDetail);
|
||||
const newCompleteMessageMap = structuredClone(frozenCompleteMessageMap);
|
||||
|
||||
if (newCompleteMessageMap.size === 0) {
|
||||
@ -466,30 +498,134 @@ export function ChatPage({
|
||||
)!.latestChildMessageId = messages[0].messageId;
|
||||
}
|
||||
}
|
||||
|
||||
const newCompleteMessageDetail = {
|
||||
sessionId: chatSessionId || completeMessageDetail.sessionId,
|
||||
sessionId: chatSessionId || currentSessionId(),
|
||||
messageMap: newCompleteMessageMap,
|
||||
};
|
||||
setCompleteMessageDetail(newCompleteMessageDetail);
|
||||
|
||||
updateCompleteMessageDetail(
|
||||
chatSessionId || currentSessionId(),
|
||||
newCompleteMessageMap
|
||||
);
|
||||
return newCompleteMessageDetail;
|
||||
};
|
||||
|
||||
const messageHistory = buildLatestMessageChain(
|
||||
completeMessageDetail.messageMap
|
||||
currentMessageMap(completeMessageDetail)
|
||||
);
|
||||
|
||||
const [submittedMessage, setSubmittedMessage] = useState("");
|
||||
const [chatState, setChatState] = useState<ChatState>("input");
|
||||
interface RegenerationState {
|
||||
regenerating: boolean;
|
||||
finalMessageIndex: number;
|
||||
}
|
||||
|
||||
const [regenerationState, setRegenerationState] =
|
||||
useState<RegenerationState | null>(null);
|
||||
const [chatState, setChatState] = useState<Map<number | null, ChatState>>(
|
||||
new Map([[chatSessionIdRef.current, "input"]])
|
||||
);
|
||||
|
||||
const [abortController, setAbortController] =
|
||||
useState<AbortController | null>(null);
|
||||
const [scrollHeight, setScrollHeight] = useState<Map<number | null, number>>(
|
||||
new Map([[chatSessionIdRef.current, 0]])
|
||||
);
|
||||
const currentScrollHeight = () => {
|
||||
return scrollHeight.get(currentSessionId());
|
||||
};
|
||||
|
||||
const retrieveCurrentScrollHeight = (): number | null => {
|
||||
return scrollHeight.get(currentSessionId()) || null;
|
||||
};
|
||||
|
||||
const [regenerationState, setRegenerationState] = useState<
|
||||
Map<number | null, RegenerationState | null>
|
||||
>(new Map([[null, null]]));
|
||||
|
||||
const [abortControllers, setAbortControllers] = useState<
|
||||
Map<number | null, AbortController>
|
||||
>(new Map());
|
||||
|
||||
// Updates "null" session values to new session id for
|
||||
// regeneration, chat, and abort controller state, messagehistory
|
||||
const updateStatesWithNewSessionId = (newSessionId: number) => {
|
||||
const updateState = (
|
||||
setState: Dispatch<SetStateAction<Map<number | null, any>>>,
|
||||
defaultValue?: any
|
||||
) => {
|
||||
setState((prevState) => {
|
||||
const newState = new Map(prevState);
|
||||
const existingState = newState.get(null);
|
||||
if (existingState !== undefined) {
|
||||
newState.set(newSessionId, existingState);
|
||||
newState.delete(null);
|
||||
} else if (defaultValue !== undefined) {
|
||||
newState.set(newSessionId, defaultValue);
|
||||
}
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
updateState(setRegenerationState);
|
||||
updateState(setChatState);
|
||||
updateState(setAbortControllers);
|
||||
|
||||
// Update completeMessageDetail
|
||||
setCompleteMessageDetail((prevState) => {
|
||||
const newState = new Map(prevState);
|
||||
const existingMessages = newState.get(null);
|
||||
if (existingMessages) {
|
||||
newState.set(newSessionId, existingMessages);
|
||||
newState.delete(null);
|
||||
}
|
||||
return newState;
|
||||
});
|
||||
|
||||
// Update chatSessionIdRef
|
||||
chatSessionIdRef.current = newSessionId;
|
||||
};
|
||||
|
||||
const updateChatState = (newState: ChatState, sessionId?: number | null) => {
|
||||
setChatState((prevState) => {
|
||||
const newChatState = new Map(prevState);
|
||||
newChatState.set(
|
||||
sessionId !== undefined ? sessionId : currentSessionId(),
|
||||
newState
|
||||
);
|
||||
return newChatState;
|
||||
});
|
||||
};
|
||||
|
||||
const currentChatState = (): ChatState => {
|
||||
return chatState.get(currentSessionId()) || "input";
|
||||
};
|
||||
|
||||
const currentChatAnswering = () => {
|
||||
return (
|
||||
currentChatState() == "toolBuilding" ||
|
||||
currentChatState() == "streaming" ||
|
||||
currentChatState() == "loading"
|
||||
);
|
||||
};
|
||||
|
||||
const updateRegenerationState = (
|
||||
newState: RegenerationState | null,
|
||||
sessionId?: number | null
|
||||
) => {
|
||||
setRegenerationState((prevState) => {
|
||||
const newRegenerationState = new Map(prevState);
|
||||
newRegenerationState.set(
|
||||
sessionId !== undefined ? sessionId : currentSessionId(),
|
||||
newState
|
||||
);
|
||||
return newRegenerationState;
|
||||
});
|
||||
};
|
||||
|
||||
const resetRegenerationState = (sessionId?: number | null) => {
|
||||
updateRegenerationState(null, sessionId);
|
||||
};
|
||||
|
||||
const currentRegenerationState = (): RegenerationState | null => {
|
||||
return regenerationState.get(currentSessionId()) || null;
|
||||
};
|
||||
|
||||
const currentSessionChatState = currentChatState();
|
||||
const currentSessionRegenerationState = currentRegenerationState();
|
||||
|
||||
// uploaded files
|
||||
const [currentMessageFiles, setCurrentMessageFiles] = useState<
|
||||
@ -746,7 +882,9 @@ export function ChatPage({
|
||||
modelOverRide?: LlmOverride;
|
||||
regenerationRequest?: RegenerationRequest | null;
|
||||
} = {}) => {
|
||||
if (chatState != "input") {
|
||||
let frozenSessionId = currentSessionId();
|
||||
|
||||
if (currentChatState() != "input") {
|
||||
setPopup({
|
||||
message: "Please wait for the response to complete",
|
||||
type: "error",
|
||||
@ -754,16 +892,13 @@ export function ChatPage({
|
||||
|
||||
return;
|
||||
}
|
||||
setRegenerationState(
|
||||
updateRegenerationState(
|
||||
regenerationRequest
|
||||
? { regenerating: true, finalMessageIndex: messageIdToResend || 0 }
|
||||
: null
|
||||
);
|
||||
|
||||
setChatState("loading");
|
||||
|
||||
const controller = new AbortController();
|
||||
setAbortController(controller);
|
||||
updateChatState("loading");
|
||||
|
||||
setAlternativeGeneratingAssistant(alternativeAssistantOverride);
|
||||
clientScrollToBottom();
|
||||
@ -780,13 +915,21 @@ export function ChatPage({
|
||||
} else {
|
||||
currChatSessionId = chatSessionIdRef.current as number;
|
||||
}
|
||||
chatSessionIdRef.current = currChatSessionId;
|
||||
frozenSessionId = currChatSessionId;
|
||||
|
||||
updateStatesWithNewSessionId(currChatSessionId);
|
||||
|
||||
const controller = new AbortController();
|
||||
|
||||
setAbortControllers((prev) =>
|
||||
new Map(prev).set(currChatSessionId, controller)
|
||||
);
|
||||
|
||||
const messageToResend = messageHistory.find(
|
||||
(message) => message.messageId === messageIdToResend
|
||||
);
|
||||
|
||||
const messageMap = completeMessageDetail.messageMap;
|
||||
const messageMap = currentMessageMap(completeMessageDetail);
|
||||
const messageToResendParent =
|
||||
messageToResend?.parentMessageId !== null &&
|
||||
messageToResend?.parentMessageId !== undefined
|
||||
@ -802,8 +945,8 @@ export function ChatPage({
|
||||
"Failed to re-send message - please refresh the page and try again.",
|
||||
type: "error",
|
||||
});
|
||||
setRegenerationState(null);
|
||||
setChatState("input");
|
||||
resetRegenerationState(currentSessionId());
|
||||
updateChatState("input", frozenSessionId);
|
||||
return;
|
||||
}
|
||||
let currMessage = messageToResend ? messageToResend.message : message;
|
||||
@ -851,11 +994,12 @@ export function ChatPage({
|
||||
user_message_id: number;
|
||||
assistant_message_id: number;
|
||||
frozenMessageMap: Map<number, Message>;
|
||||
frozenSessionId: number | null;
|
||||
} = null;
|
||||
|
||||
try {
|
||||
const mapKeys = Array.from(completeMessageDetail.messageMap.keys());
|
||||
const mapKeys = Array.from(
|
||||
currentMessageMap(completeMessageDetail).keys()
|
||||
);
|
||||
const systemMessage = Math.min(...mapKeys);
|
||||
|
||||
const lastSuccessfulMessageId =
|
||||
@ -956,32 +1100,31 @@ export function ChatPage({
|
||||
});
|
||||
}
|
||||
|
||||
const {
|
||||
messageMap: currentFrozenMessageMap,
|
||||
sessionId: currentFrozenSessionId,
|
||||
} = upsertToCompleteMessageMap({
|
||||
messages: messageUpdates,
|
||||
chatSessionId: currChatSessionId,
|
||||
});
|
||||
const { messageMap: currentFrozenMessageMap } =
|
||||
upsertToCompleteMessageMap({
|
||||
messages: messageUpdates,
|
||||
chatSessionId: currChatSessionId,
|
||||
});
|
||||
|
||||
const frozenMessageMap = currentFrozenMessageMap;
|
||||
const frozenSessionId = currentFrozenSessionId;
|
||||
initialFetchDetails = {
|
||||
frozenMessageMap,
|
||||
frozenSessionId,
|
||||
assistant_message_id,
|
||||
user_message_id,
|
||||
};
|
||||
|
||||
setRegenerationState(null);
|
||||
resetRegenerationState();
|
||||
} else {
|
||||
const { user_message_id, frozenMessageMap, frozenSessionId } =
|
||||
initialFetchDetails;
|
||||
setChatState((chatState) => {
|
||||
if (chatState == "loading") {
|
||||
return "streaming";
|
||||
const { user_message_id, frozenMessageMap } = initialFetchDetails;
|
||||
|
||||
setChatState((prevState) => {
|
||||
if (prevState.get(chatSessionIdRef.current!) === "loading") {
|
||||
return new Map(prevState).set(
|
||||
chatSessionIdRef.current!,
|
||||
"streaming"
|
||||
);
|
||||
}
|
||||
return chatState;
|
||||
return prevState;
|
||||
});
|
||||
|
||||
if (Object.hasOwn(packet, "answer_piece")) {
|
||||
@ -1006,9 +1149,9 @@ export function ChatPage({
|
||||
!toolCalls[0].tool_result ||
|
||||
toolCalls[0].tool_result == undefined
|
||||
) {
|
||||
setChatState("toolBuilding");
|
||||
updateChatState("toolBuilding", frozenSessionId);
|
||||
} else {
|
||||
setChatState("streaming");
|
||||
updateChatState("streaming", frozenSessionId);
|
||||
}
|
||||
|
||||
// This will be consolidated in upcoming tool calls udpate,
|
||||
@ -1123,11 +1266,12 @@ export function ChatPage({
|
||||
initialFetchDetails?.user_message_id || TEMP_USER_MESSAGE_ID,
|
||||
},
|
||||
],
|
||||
completeMessageMapOverride: completeMessageDetail.messageMap,
|
||||
completeMessageMapOverride: currentMessageMap(completeMessageDetail),
|
||||
});
|
||||
}
|
||||
setRegenerationState(null);
|
||||
setChatState("input");
|
||||
resetRegenerationState(currentSessionId());
|
||||
|
||||
updateChatState("input");
|
||||
if (isNewSession) {
|
||||
if (finalMessage) {
|
||||
setSelectedMessageForDocDisplay(finalMessage.message_id);
|
||||
@ -1194,8 +1338,8 @@ export function ChatPage({
|
||||
const onAssistantChange = (assistant: Persona | null) => {
|
||||
if (assistant && assistant.id !== liveAssistant.id) {
|
||||
// Abort the ongoing stream if it exists
|
||||
if (chatState != "input") {
|
||||
stopGeneration();
|
||||
if (currentSessionChatState != "input") {
|
||||
stopGenerating();
|
||||
resetInputBar();
|
||||
}
|
||||
|
||||
@ -1308,7 +1452,7 @@ export function ChatPage({
|
||||
});
|
||||
|
||||
useScrollonStream({
|
||||
chatState,
|
||||
chatState: currentSessionChatState,
|
||||
scrollableDivRef,
|
||||
scrollDist,
|
||||
endDivRef,
|
||||
@ -1496,7 +1640,7 @@ export function ChatPage({
|
||||
<div className="w-full relative">
|
||||
<HistorySidebar
|
||||
explicitlyUntoggle={explicitlyUntoggle}
|
||||
stopGenerating={stopGeneration}
|
||||
stopGenerating={stopGenerating}
|
||||
reset={() => setMessage("")}
|
||||
page="chat"
|
||||
ref={innerSidebarElementRef}
|
||||
@ -1570,7 +1714,7 @@ export function ChatPage({
|
||||
|
||||
{messageHistory.length === 0 &&
|
||||
!isFetchingChatMessages &&
|
||||
chatState == "input" && (
|
||||
currentSessionChatState == "input" && (
|
||||
<ChatIntro
|
||||
availableSources={finalAvailableSources}
|
||||
selectedPersona={liveAssistant}
|
||||
@ -1584,17 +1728,17 @@ export function ChatPage({
|
||||
}
|
||||
>
|
||||
{messageHistory.map((message, i) => {
|
||||
const messageMap =
|
||||
completeMessageDetail.messageMap;
|
||||
const messageReactComponentKey = `${i}-${completeMessageDetail.sessionId}`;
|
||||
const messageMap = currentMessageMap(
|
||||
completeMessageDetail
|
||||
);
|
||||
const messageReactComponentKey = `${i}-${currentSessionId()}`;
|
||||
const parentMessage = message.parentMessageId
|
||||
? messageMap.get(message.parentMessageId)
|
||||
: null;
|
||||
if (
|
||||
regenerationState &&
|
||||
regenerationState.regenerating &&
|
||||
message.messageId >
|
||||
regenerationState.finalMessageIndex
|
||||
currentSessionRegenerationState?.regenerating &&
|
||||
message.messageId >=
|
||||
currentSessionRegenerationState?.finalMessageIndex!
|
||||
) {
|
||||
return <></>;
|
||||
}
|
||||
@ -1603,7 +1747,7 @@ export function ChatPage({
|
||||
return (
|
||||
<div key={messageReactComponentKey}>
|
||||
<HumanMessage
|
||||
stopGenerating={stopGeneration}
|
||||
stopGenerating={stopGenerating}
|
||||
content={message.message}
|
||||
files={message.files}
|
||||
messageId={message.messageId}
|
||||
@ -1636,11 +1780,10 @@ export function ChatPage({
|
||||
newCompleteMessageMap.get(
|
||||
message.parentMessageId!
|
||||
)!.latestChildMessageId = messageId;
|
||||
setCompleteMessageDetail({
|
||||
sessionId:
|
||||
completeMessageDetail.sessionId,
|
||||
messageMap: newCompleteMessageMap,
|
||||
});
|
||||
updateCompleteMessageDetail(
|
||||
currentSessionId(),
|
||||
newCompleteMessageMap
|
||||
);
|
||||
setSelectedMessageForDocDisplay(
|
||||
messageId
|
||||
);
|
||||
@ -1670,11 +1813,9 @@ export function ChatPage({
|
||||
: null;
|
||||
|
||||
if (
|
||||
regenerationState &&
|
||||
regenerationState.regenerating &&
|
||||
// chatState == "loading" &&
|
||||
message.messageId >
|
||||
regenerationState.finalMessageIndex - 1
|
||||
currentSessionRegenerationState?.regenerating &&
|
||||
currentSessionChatState == "loading" &&
|
||||
message.messageId == messageHistory.length - 1
|
||||
) {
|
||||
return <></>;
|
||||
}
|
||||
@ -1703,11 +1844,12 @@ export function ChatPage({
|
||||
newCompleteMessageMap.get(
|
||||
message.parentMessageId!
|
||||
)!.latestChildMessageId = messageId;
|
||||
setCompleteMessageDetail({
|
||||
sessionId:
|
||||
completeMessageDetail.sessionId,
|
||||
messageMap: newCompleteMessageMap,
|
||||
});
|
||||
|
||||
updateCompleteMessageDetail(
|
||||
currentSessionId(),
|
||||
newCompleteMessageMap
|
||||
);
|
||||
|
||||
setSelectedMessageForDocDisplay(
|
||||
messageId
|
||||
);
|
||||
@ -1742,7 +1884,10 @@ export function ChatPage({
|
||||
}
|
||||
isComplete={
|
||||
i !== messageHistory.length - 1 ||
|
||||
chatState == "input"
|
||||
(currentSessionChatState !=
|
||||
"streaming" &&
|
||||
currentSessionChatState !=
|
||||
"toolBuilding")
|
||||
}
|
||||
hasDocs={
|
||||
(message.documents &&
|
||||
@ -1750,7 +1895,7 @@ export function ChatPage({
|
||||
}
|
||||
handleFeedback={
|
||||
i === messageHistory.length - 1 &&
|
||||
chatState != "input"
|
||||
currentSessionChatState != "input"
|
||||
? undefined
|
||||
: (feedbackType) =>
|
||||
setCurrentFeedback([
|
||||
@ -1760,7 +1905,7 @@ export function ChatPage({
|
||||
}
|
||||
handleSearchQueryEdit={
|
||||
i === messageHistory.length - 1 &&
|
||||
chatState == "input"
|
||||
currentSessionChatState == "input"
|
||||
? (newQuery) => {
|
||||
if (!previousMessage) {
|
||||
setPopup({
|
||||
@ -1770,7 +1915,6 @@ export function ChatPage({
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
previousMessage.messageId ===
|
||||
null
|
||||
@ -1867,21 +2011,24 @@ export function ChatPage({
|
||||
);
|
||||
}
|
||||
})}
|
||||
{chatState == "loading" &&
|
||||
!regenerationState?.regenerating &&
|
||||
|
||||
{currentSessionChatState == "loading" &&
|
||||
!currentSessionRegenerationState?.regenerating &&
|
||||
messageHistory[messageHistory.length - 1]?.type !=
|
||||
"user" && (
|
||||
<HumanMessage
|
||||
key={-2}
|
||||
messageId={-1}
|
||||
content={submittedMessage}
|
||||
/>
|
||||
)}
|
||||
|
||||
{chatState == "loading" && (
|
||||
{currentSessionChatState == "loading" && (
|
||||
<div
|
||||
key={`${messageHistory.length}-${chatSessionIdRef.current}`}
|
||||
>
|
||||
<AIMessage
|
||||
key={-3}
|
||||
currentPersona={liveAssistant}
|
||||
alternativeAssistant={
|
||||
alternativeGeneratingAssistant ??
|
||||
@ -1910,6 +2057,7 @@ export function ChatPage({
|
||||
messageHistory.length === 0 &&
|
||||
!isFetchingChatMessages && (
|
||||
<div
|
||||
key={-4}
|
||||
className={`
|
||||
mx-auto
|
||||
px-4
|
||||
@ -1961,10 +2109,9 @@ export function ChatPage({
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ChatInputBar
|
||||
chatState={chatState}
|
||||
stopGenerating={stopGeneration}
|
||||
chatState={currentSessionChatState}
|
||||
stopGenerating={stopGenerating}
|
||||
openModelSettings={() => setSettingsToggled(true)}
|
||||
inputPrompts={userInputPrompts}
|
||||
showDocs={() => setDocumentSelection(true)}
|
||||
|
@ -32,9 +32,8 @@ import { AssistantIcon } from "@/components/assistants/AssistantIcon";
|
||||
import { Tooltip } from "@/components/tooltip/Tooltip";
|
||||
import { Hoverable } from "@/components/Hoverable";
|
||||
import { SettingsContext } from "@/components/settings/SettingsProvider";
|
||||
import { StopCircle } from "@phosphor-icons/react/dist/ssr";
|
||||
import { Square } from "@phosphor-icons/react";
|
||||
import { ChatState } from "../types";
|
||||
|
||||
const MAX_INPUT_HEIGHT = 200;
|
||||
|
||||
export function ChatInputBar({
|
||||
|
@ -231,14 +231,9 @@ export const AIMessage = ({
|
||||
}
|
||||
return content;
|
||||
};
|
||||
|
||||
content = trimIncompleteCodeSection(content);
|
||||
}
|
||||
|
||||
const danswerSearchToolEnabledForPersona = currentPersona.tools.some(
|
||||
(tool) => tool.in_code_tool_id === SEARCH_TOOL_NAME
|
||||
);
|
||||
|
||||
let filteredDocs: FilteredDanswerDocument[] = [];
|
||||
|
||||
if (docs) {
|
||||
@ -760,24 +755,24 @@ export const HumanMessage = ({
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
className={`
|
||||
m-0
|
||||
w-full
|
||||
h-auto
|
||||
shrink
|
||||
border-0
|
||||
rounded-lg
|
||||
overflow-y-hidden
|
||||
bg-background-emphasis
|
||||
whitespace-normal
|
||||
break-word
|
||||
overscroll-contain
|
||||
outline-none
|
||||
placeholder-gray-400
|
||||
resize-none
|
||||
pl-4
|
||||
overflow-y-auto
|
||||
pr-12
|
||||
py-4`}
|
||||
m-0
|
||||
w-full
|
||||
h-auto
|
||||
shrink
|
||||
border-0
|
||||
rounded-lg
|
||||
overflow-y-hidden
|
||||
bg-background-emphasis
|
||||
whitespace-normal
|
||||
break-word
|
||||
overscroll-contain
|
||||
outline-none
|
||||
placeholder-gray-400
|
||||
resize-none
|
||||
pl-4
|
||||
overflow-y-auto
|
||||
pr-12
|
||||
py-4`}
|
||||
aria-multiline
|
||||
role="textarea"
|
||||
value={editedContent}
|
||||
@ -901,7 +896,7 @@ export const HumanMessage = ({
|
||||
) : (
|
||||
<div className="h-[27px]" />
|
||||
)}
|
||||
<p className="ml-auto rounded-lg p-1">{content}</p>
|
||||
<div className="ml-auto rounded-lg p-1">{content}</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
@ -32,7 +32,6 @@ export function ChatSessionDisplay({
|
||||
isSelected,
|
||||
skipGradient,
|
||||
closeSidebar,
|
||||
stopGenerating = () => null,
|
||||
showShareModal,
|
||||
showDeleteModal,
|
||||
}: {
|
||||
@ -43,7 +42,6 @@ export function ChatSessionDisplay({
|
||||
// if not set, the gradient will still be applied and cause weirdness
|
||||
skipGradient?: boolean;
|
||||
closeSidebar?: () => void;
|
||||
stopGenerating?: () => void;
|
||||
showShareModal?: (chatSession: ChatSession) => void;
|
||||
showDeleteModal?: (chatSession: ChatSession) => void;
|
||||
}) {
|
||||
@ -100,7 +98,6 @@ export function ChatSessionDisplay({
|
||||
className="flex my-1 group relative"
|
||||
key={chatSession.id}
|
||||
onClick={() => {
|
||||
stopGenerating();
|
||||
if (settings?.isMobile && closeSidebar) {
|
||||
closeSidebar();
|
||||
}
|
||||
|
@ -176,7 +176,6 @@ export const HistorySidebar = forwardRef<HTMLDivElement, HistorySidebarProps>(
|
||||
)}
|
||||
<div className="border-b border-border pb-4 mx-3" />
|
||||
<PagesTab
|
||||
stopGenerating={stopGenerating}
|
||||
newFolderId={newFolderId}
|
||||
showDeleteModal={showDeleteModal}
|
||||
showShareModal={showShareModal}
|
||||
|
@ -17,12 +17,10 @@ export function PagesTab({
|
||||
folders,
|
||||
openedFolders,
|
||||
closeSidebar,
|
||||
stopGenerating,
|
||||
newFolderId,
|
||||
showShareModal,
|
||||
showDeleteModal,
|
||||
}: {
|
||||
stopGenerating: () => void;
|
||||
page: pageType;
|
||||
existingChats?: ChatSession[];
|
||||
currentChatId?: number;
|
||||
@ -126,7 +124,6 @@ export function PagesTab({
|
||||
return (
|
||||
<div key={`${chat.id}-${chat.name}`}>
|
||||
<ChatSessionDisplay
|
||||
stopGenerating={stopGenerating}
|
||||
showDeleteModal={showDeleteModal}
|
||||
showShareModal={showShareModal}
|
||||
closeSidebar={closeSidebar}
|
||||
|
@ -1,2 +1,6 @@
|
||||
export type FeedbackType = "like" | "dislike";
|
||||
export type ChatState = "input" | "loading" | "streaming" | "toolBuilding";
|
||||
export interface RegenerationState {
|
||||
regenerating: boolean;
|
||||
finalMessageIndex: number;
|
||||
}
|
||||
|
@ -659,9 +659,9 @@ export const MagnifyingIcon = ({
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
fillRule="evenodd"
|
||||
d="M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06zM10.5 7a3.5 3.5 0 1 1-7 0a3.5 3.5 0 0 1 7 0"
|
||||
clip-rule="evenodd"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@ -682,9 +682,9 @@ export const ToggleDown = ({
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
fillRule="evenodd"
|
||||
d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06"
|
||||
clip-rule="evenodd"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@ -705,9 +705,9 @@ export const ToggleUp = ({
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
fillRule="evenodd"
|
||||
d="M11.78 9.78a.75.75 0 0 1-1.06 0L8 7.06L5.28 9.78a.75.75 0 0 1-1.06-1.06l3.25-3.25a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06"
|
||||
clip-rule="evenodd"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@ -773,7 +773,7 @@ export const StarFeedback = ({
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
stroke-width="1.5"
|
||||
strokeWidth="1.5"
|
||||
d="m12.495 18.587l4.092 2.15a1.044 1.044 0 0 0 1.514-1.106l-.783-4.552a1.045 1.045 0 0 1 .303-.929l3.31-3.226a1.043 1.043 0 0 0-.575-1.785l-4.572-.657A1.044 1.044 0 0 1 15 7.907l-2.088-4.175a1.044 1.044 0 0 0-1.88 0L8.947 7.907a1.044 1.044 0 0 1-.783.575l-4.51.657a1.044 1.044 0 0 0-.584 1.785l3.309 3.226a1.044 1.044 0 0 1 .303.93l-.783 4.55a1.044 1.044 0 0 0 1.513 1.107l4.093-2.15a1.043 1.043 0 0 1 .991 0"
|
||||
/>
|
||||
</svg>
|
||||
@ -798,7 +798,7 @@ export const DislikeFeedback = ({
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
stroke-width="1.5"
|
||||
strokeWidth="1.5"
|
||||
>
|
||||
<path d="M5.75 2.75H4.568c-.98 0-1.775.795-1.775 1.776v8.284c0 .98.795 1.775 1.775 1.775h1.184c.98 0 1.775-.794 1.775-1.775V4.526c0-.98-.795-1.776-1.775-1.776" />
|
||||
<path d="m21.16 11.757l-1.42-7.101a2.368 2.368 0 0 0-2.367-1.906h-7.48a2.367 2.367 0 0 0-2.367 2.367v7.101a3.231 3.231 0 0 0 1.184 2.367l.982 5.918a.887.887 0 0 0 1.278.65l1.1-.543a3.551 3.551 0 0 0 1.87-4.048l-.496-1.965h5.396a2.368 2.368 0 0 0 2.32-2.84" />
|
||||
@ -825,7 +825,7 @@ export const LikeFeedback = ({
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
stroke-width="1.5"
|
||||
strokeWidth="1.5"
|
||||
>
|
||||
<path d="M5.75 9.415H4.568c-.98 0-1.775.794-1.775 1.775v8.284c0 .98.795 1.776 1.775 1.776h1.184c.98 0 1.775-.795 1.775-1.776V11.19c0-.98-.795-1.775-1.775-1.775" />
|
||||
<path d="m21.16 12.243l-1.42 7.101a2.367 2.367 0 0 1-2.367 1.906h-7.48a2.367 2.367 0 0 1-2.367-2.367v-7.101A3.231 3.231 0 0 1 8.71 9.415l.982-5.918a.888.888 0 0 1 1.278-.65l1.1.544a3.55 3.55 0 0 1 1.87 4.047l-.496 1.965h5.396a2.367 2.367 0 0 1 2.32 2.84" />
|
||||
@ -1834,9 +1834,9 @@ export const FilledLikeIcon = ({
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
fillRule="evenodd"
|
||||
d="M4.41 12.961a2.5 2.5 0 0 0 1.076.244h5.346a2.5 2.5 0 0 0 2.47-2.114l.626-4.003a2 2 0 0 0-1.976-2.31H8.67V2.422a1.625 1.625 0 0 0-3.044-.794l-2.077 3.71a1.5 1.5 0 0 0-.191.733v5.442a1.5 1.5 0 0 0 .854 1.354l.2.095Zm-3.366-7.44a.996.996 0 0 0-.997.996v5.112a.997.997 0 0 0 .997.997h.496a.5.5 0 0 0 .5-.5V6.02a.5.5 0 0 0-.5-.5h-.496Z"
|
||||
clip-rule="evenodd"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@ -1857,9 +1857,9 @@ export const StopGeneratingIcon = ({
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
fillRule="evenodd"
|
||||
d="M1.5 0A1.5 1.5 0 0 0 0 1.5v11A1.5 1.5 0 0 0 1.5 14h11a1.5 1.5 0 0 0 1.5-1.5v-11A1.5 1.5 0 0 0 12.5 0z"
|
||||
clip-rule="evenodd"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@ -2604,7 +2604,7 @@ export const SwapIcon = ({
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
stroke-width="1.5"
|
||||
strokeWidth="1.5"
|
||||
>
|
||||
<path d="M3.53 11.47v2.118a4.235 4.235 0 0 0 4.235 4.236H20.47M3.53 6.176h12.705a4.235 4.235 0 0 1 4.236 4.236v2.117" />
|
||||
<path d="m17.294 14.647l3.177 3.176L17.294 21M6.706 9.353L3.529 6.176L6.706 3" />
|
||||
@ -2655,7 +2655,7 @@ export const PinIcon = ({
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
stroke-width="1.5"
|
||||
strokeWidth="1.5"
|
||||
d="m17.942 6.076l2.442 2.442a1.22 1.22 0 0 1-.147 1.855l-1.757.232a1.697 1.697 0 0 0-.94.452c-.72.696-1.453 1.428-2.674 2.637c-.21.212-.358.478-.427.769l-.94 3.772a1.22 1.22 0 0 1-1.978.379l-3.04-3.052l-3.052-3.04a1.221 1.221 0 0 1 .379-1.978l3.747-.964a1.8 1.8 0 0 0 .77-.44c1.379-1.355 1.88-1.855 2.66-2.698c.233-.25.383-.565.428-.903l.232-1.783a1.221 1.221 0 0 1 1.856-.146zm-9.51 9.498L3.256 20.75"
|
||||
/>
|
||||
</svg>
|
||||
@ -2680,7 +2680,7 @@ export const TwoRightArrowIcons = ({
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
stroke-width="1.5"
|
||||
strokeWidth="1.5"
|
||||
d="m5.36 19l5.763-5.763a1.738 1.738 0 0 0 0-2.474L5.36 5m7 14l5.763-5.763a1.738 1.738 0 0 0 0-2.474L12.36 5"
|
||||
/>
|
||||
</svg>
|
||||
|
@ -126,6 +126,7 @@ export async function fetchChatData(searchParams: {
|
||||
`Failed to fetch chat sessions - ${chatSessionsResponse?.text()}`
|
||||
);
|
||||
}
|
||||
|
||||
// Larger ID -> created later
|
||||
chatSessions.sort((a, b) => (a.id > b.id ? -1 : 1));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user