mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-09-19 03:58:30 +02:00
UX (#4014)
This commit is contained in:
@@ -409,10 +409,6 @@ class DefaultMultiLLM(LLM):
|
|||||||
self._record_call(processed_prompt)
|
self._record_call(processed_prompt)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print(
|
|
||||||
"model is",
|
|
||||||
f"{self.config.model_provider}/{self.config.deployment_name or self.config.model_name}",
|
|
||||||
)
|
|
||||||
return litellm.completion(
|
return litellm.completion(
|
||||||
mock_response=MOCK_LLM_RESPONSE,
|
mock_response=MOCK_LLM_RESPONSE,
|
||||||
# model choice
|
# model choice
|
||||||
|
@@ -1,6 +1,11 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { redirect, useRouter, useSearchParams } from "next/navigation";
|
import {
|
||||||
|
redirect,
|
||||||
|
usePathname,
|
||||||
|
useRouter,
|
||||||
|
useSearchParams,
|
||||||
|
} from "next/navigation";
|
||||||
import {
|
import {
|
||||||
BackendChatSession,
|
BackendChatSession,
|
||||||
BackendMessage,
|
BackendMessage,
|
||||||
@@ -130,6 +135,7 @@ import {
|
|||||||
} from "@/lib/browserUtilities";
|
} from "@/lib/browserUtilities";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { ConfirmEntityModal } from "@/components/modals/ConfirmEntityModal";
|
import { ConfirmEntityModal } from "@/components/modals/ConfirmEntityModal";
|
||||||
|
import { MessageChannel } from "node:worker_threads";
|
||||||
|
|
||||||
const TEMP_USER_MESSAGE_ID = -1;
|
const TEMP_USER_MESSAGE_ID = -1;
|
||||||
const TEMP_ASSISTANT_MESSAGE_ID = -2;
|
const TEMP_ASSISTANT_MESSAGE_ID = -2;
|
||||||
@@ -1145,6 +1151,7 @@ export function ChatPage({
|
|||||||
regenerationRequest?: RegenerationRequest | null;
|
regenerationRequest?: RegenerationRequest | null;
|
||||||
overrideFileDescriptors?: FileDescriptor[];
|
overrideFileDescriptors?: FileDescriptor[];
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
|
navigatingAway.current = false;
|
||||||
let frozenSessionId = currentSessionId();
|
let frozenSessionId = currentSessionId();
|
||||||
updateCanContinue(false, frozenSessionId);
|
updateCanContinue(false, frozenSessionId);
|
||||||
|
|
||||||
@@ -1267,7 +1274,6 @@ export function ChatPage({
|
|||||||
let stackTrace: string | null = null;
|
let stackTrace: string | null = null;
|
||||||
|
|
||||||
let sub_questions: SubQuestionDetail[] = [];
|
let sub_questions: SubQuestionDetail[] = [];
|
||||||
let second_level_sub_questions: SubQuestionDetail[] = [];
|
|
||||||
let is_generating: boolean = false;
|
let is_generating: boolean = false;
|
||||||
let second_level_generating: boolean = false;
|
let second_level_generating: boolean = false;
|
||||||
let finalMessage: BackendMessage | null = null;
|
let finalMessage: BackendMessage | null = null;
|
||||||
@@ -1291,7 +1297,7 @@ export function ChatPage({
|
|||||||
|
|
||||||
const stack = new CurrentMessageFIFO();
|
const stack = new CurrentMessageFIFO();
|
||||||
updateCurrentMessageFIFO(stack, {
|
updateCurrentMessageFIFO(stack, {
|
||||||
signal: controller.signal, // Add this line
|
signal: controller.signal,
|
||||||
message: currMessage,
|
message: currMessage,
|
||||||
alternateAssistantId: currentAssistantId,
|
alternateAssistantId: currentAssistantId,
|
||||||
fileDescriptors: overrideFileDescriptors || currentMessageFiles,
|
fileDescriptors: overrideFileDescriptors || currentMessageFiles,
|
||||||
@@ -1712,7 +1718,10 @@ export function ChatPage({
|
|||||||
const newUrl = buildChatUrl(searchParams, currChatSessionId, null);
|
const newUrl = buildChatUrl(searchParams, currChatSessionId, null);
|
||||||
// newUrl is like /chat?chatId=10
|
// newUrl is like /chat?chatId=10
|
||||||
// current page is like /chat
|
// current page is like /chat
|
||||||
router.push(newUrl, { scroll: false });
|
|
||||||
|
if (pathname == "/chat" && !navigatingAway.current) {
|
||||||
|
router.push(newUrl, { scroll: false });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@@ -2086,6 +2095,31 @@ export function ChatPage({
|
|||||||
llmOverrideManager.updateImageFilesPresent(imageFileInMessageHistory);
|
llmOverrideManager.updateImageFilesPresent(imageFileInMessageHistory);
|
||||||
}, [imageFileInMessageHistory]);
|
}, [imageFileInMessageHistory]);
|
||||||
|
|
||||||
|
const pathname = usePathname();
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
// Cleanup which only runs when the component unmounts (i.e. when you navigate away).
|
||||||
|
const currentSession = currentSessionId();
|
||||||
|
const controller = abortControllersRef.current.get(currentSession);
|
||||||
|
if (controller) {
|
||||||
|
controller.abort();
|
||||||
|
navigatingAway.current = true;
|
||||||
|
setAbortControllers((prev) => {
|
||||||
|
const newControllers = new Map(prev);
|
||||||
|
newControllers.delete(currentSession);
|
||||||
|
return newControllers;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [pathname]);
|
||||||
|
|
||||||
|
const navigatingAway = useRef(false);
|
||||||
|
// Keep a ref to abortControllers to ensure we always have the latest value
|
||||||
|
const abortControllersRef = useRef(abortControllers);
|
||||||
|
useEffect(() => {
|
||||||
|
abortControllersRef.current = abortControllers;
|
||||||
|
}, [abortControllers]);
|
||||||
|
|
||||||
useSidebarShortcut(router, toggleSidebar);
|
useSidebarShortcut(router, toggleSidebar);
|
||||||
|
|
||||||
const [sharedChatSession, setSharedChatSession] =
|
const [sharedChatSession, setSharedChatSession] =
|
||||||
@@ -2300,7 +2334,7 @@ export function ChatPage({
|
|||||||
fixed
|
fixed
|
||||||
left-0
|
left-0
|
||||||
z-40
|
z-40
|
||||||
bg-background-100
|
bg-neutral-200
|
||||||
h-screen
|
h-screen
|
||||||
transition-all
|
transition-all
|
||||||
bg-opacity-80
|
bg-opacity-80
|
||||||
@@ -2557,12 +2591,21 @@ export function ChatPage({
|
|||||||
) {
|
) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
const nextMessage =
|
||||||
|
messageHistory.length > i + 1
|
||||||
|
? messageHistory[i + 1]
|
||||||
|
: null;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id={`message-${message.messageId}`}
|
id={`message-${message.messageId}`}
|
||||||
key={messageReactComponentKey}
|
key={messageReactComponentKey}
|
||||||
>
|
>
|
||||||
<HumanMessage
|
<HumanMessage
|
||||||
|
disableSwitchingForStreaming={
|
||||||
|
(nextMessage &&
|
||||||
|
nextMessage.is_generating) ||
|
||||||
|
false
|
||||||
|
}
|
||||||
stopGenerating={stopGenerating}
|
stopGenerating={stopGenerating}
|
||||||
content={message.message}
|
content={message.message}
|
||||||
files={message.files}
|
files={message.files}
|
||||||
|
@@ -94,7 +94,7 @@ export function AgenticToggle({
|
|||||||
Agent Search (BETA)
|
Agent Search (BETA)
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-neutarl-600 dark:text-neutral-700 mb-2">
|
<p className="text-xs text-neutral-600 dark:text-neutral-700 mb-2">
|
||||||
Use AI agents to break down questions and run deep iterative
|
Use AI agents to break down questions and run deep iterative
|
||||||
research through promising pathways. Gives more thorough and
|
research through promising pathways. Gives more thorough and
|
||||||
accurate responses but takes slightly longer.
|
accurate responses but takes slightly longer.
|
||||||
|
@@ -113,7 +113,7 @@ export default function LLMPopover({
|
|||||||
<Popover open={isOpen} onOpenChange={setIsOpen}>
|
<Popover open={isOpen} onOpenChange={setIsOpen}>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<button
|
<button
|
||||||
className="focus:outline-none"
|
className="dark:text-[#fff] text-[#000] focus:outline-none"
|
||||||
data-testid="llm-popover-trigger"
|
data-testid="llm-popover-trigger"
|
||||||
>
|
>
|
||||||
<ChatInputOption
|
<ChatInputOption
|
||||||
|
@@ -250,7 +250,7 @@ export async function* sendMessage({
|
|||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
yield* handleSSEStream<PacketType>(response);
|
yield* handleSSEStream<PacketType>(response, signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function nameChatSession(chatSessionId: string) {
|
export async function nameChatSession(chatSessionId: string) {
|
||||||
|
@@ -9,6 +9,12 @@ import React, {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import { OnyxDocument, FilteredOnyxDocument } from "@/lib/search/interfaces";
|
import { OnyxDocument, FilteredOnyxDocument } from "@/lib/search/interfaces";
|
||||||
import remarkGfm from "remark-gfm";
|
import remarkGfm from "remark-gfm";
|
||||||
@@ -308,7 +314,7 @@ export const AgenticMessage = ({
|
|||||||
const renderedAlternativeMarkdown = useMemo(() => {
|
const renderedAlternativeMarkdown = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
className="prose max-w-full text-base"
|
className="prose dark:prose-invert max-w-full text-base"
|
||||||
components={{
|
components={{
|
||||||
...markdownComponents,
|
...markdownComponents,
|
||||||
code: ({ node, className, children }: any) => {
|
code: ({ node, className, children }: any) => {
|
||||||
@@ -335,7 +341,7 @@ export const AgenticMessage = ({
|
|||||||
const renderedMarkdown = useMemo(() => {
|
const renderedMarkdown = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
className="prose max-w-full text-base"
|
className="prose dark:prose-invert max-w-full text-base"
|
||||||
components={markdownComponents}
|
components={markdownComponents}
|
||||||
remarkPlugins={[remarkGfm, remarkMath]}
|
remarkPlugins={[remarkGfm, remarkMath]}
|
||||||
rehypePlugins={[[rehypePrism, { ignoreMissing: true }], rehypeKatex]}
|
rehypePlugins={[[rehypePrism, { ignoreMissing: true }], rehypeKatex]}
|
||||||
@@ -530,6 +536,7 @@ export const AgenticMessage = ({
|
|||||||
{includeMessageSwitcher && (
|
{includeMessageSwitcher && (
|
||||||
<div className="-mx-1 mr-auto">
|
<div className="-mx-1 mr-auto">
|
||||||
<MessageSwitcher
|
<MessageSwitcher
|
||||||
|
disableForStreaming={!isComplete}
|
||||||
currentPage={currentMessageInd + 1}
|
currentPage={currentMessageInd + 1}
|
||||||
totalPages={otherMessagesCanSwitchTo.length}
|
totalPages={otherMessagesCanSwitchTo.length}
|
||||||
handlePrevious={() => {
|
handlePrevious={() => {
|
||||||
@@ -616,6 +623,7 @@ export const AgenticMessage = ({
|
|||||||
{includeMessageSwitcher && (
|
{includeMessageSwitcher && (
|
||||||
<div className="-mx-1 mr-auto">
|
<div className="-mx-1 mr-auto">
|
||||||
<MessageSwitcher
|
<MessageSwitcher
|
||||||
|
disableForStreaming={!isComplete}
|
||||||
currentPage={currentMessageInd + 1}
|
currentPage={currentMessageInd + 1}
|
||||||
totalPages={otherMessagesCanSwitchTo.length}
|
totalPages={otherMessagesCanSwitchTo.length}
|
||||||
handlePrevious={() => {
|
handlePrevious={() => {
|
||||||
@@ -694,27 +702,52 @@ function MessageSwitcher({
|
|||||||
totalPages,
|
totalPages,
|
||||||
handlePrevious,
|
handlePrevious,
|
||||||
handleNext,
|
handleNext,
|
||||||
|
disableForStreaming,
|
||||||
}: {
|
}: {
|
||||||
currentPage: number;
|
currentPage: number;
|
||||||
totalPages: number;
|
totalPages: number;
|
||||||
handlePrevious: () => void;
|
handlePrevious: () => void;
|
||||||
handleNext: () => void;
|
handleNext: () => void;
|
||||||
|
disableForStreaming?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center text-sm space-x-0.5">
|
<div className="flex items-center text-sm space-x-0.5">
|
||||||
<Hoverable
|
<TooltipProvider>
|
||||||
icon={FiChevronLeft}
|
<Tooltip>
|
||||||
onClick={currentPage === 1 ? undefined : handlePrevious}
|
<TooltipTrigger asChild>
|
||||||
/>
|
<div>
|
||||||
|
<Hoverable
|
||||||
|
icon={FiChevronLeft}
|
||||||
|
onClick={currentPage === 1 ? undefined : handlePrevious}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
{disableForStreaming ? "Disabled" : "Previous"}
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
|
||||||
<span className="text-text-darker select-none">
|
<span className="text-text-darker select-none">
|
||||||
{currentPage} / {totalPages}
|
{currentPage} / {totalPages}
|
||||||
|
{disableForStreaming ? "Complete" : "Generating"}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<Hoverable
|
<TooltipProvider>
|
||||||
icon={FiChevronRight}
|
<Tooltip>
|
||||||
onClick={currentPage === totalPages ? undefined : handleNext}
|
<TooltipTrigger asChild>
|
||||||
/>
|
<div>
|
||||||
|
<Hoverable
|
||||||
|
icon={FiChevronRight}
|
||||||
|
onClick={currentPage === totalPages ? undefined : handleNext}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
{disableForStreaming ? "Disabled" : "Next"}
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -383,7 +383,7 @@ export const AIMessage = ({
|
|||||||
dangerouslySetInnerHTML={{ __html: htmlContent }}
|
dangerouslySetInnerHTML={{ __html: htmlContent }}
|
||||||
/>
|
/>
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
className="prose max-w-full text-base"
|
className="prose dark:prose-invert max-w-full text-base"
|
||||||
components={markdownComponents}
|
components={markdownComponents}
|
||||||
remarkPlugins={[remarkGfm, remarkMath]}
|
remarkPlugins={[remarkGfm, remarkMath]}
|
||||||
rehypePlugins={[[rehypePrism, { ignoreMissing: true }], rehypeKatex]}
|
rehypePlugins={[[rehypePrism, { ignoreMissing: true }], rehypeKatex]}
|
||||||
@@ -495,7 +495,10 @@ export const AIMessage = ({
|
|||||||
{docs && docs.length > 0 && (
|
{docs && docs.length > 0 && (
|
||||||
<div
|
<div
|
||||||
className={`mobile:hidden ${
|
className={`mobile:hidden ${
|
||||||
query && "mt-2"
|
(query ||
|
||||||
|
toolCall?.tool_name ===
|
||||||
|
INTERNET_SEARCH_TOOL_NAME) &&
|
||||||
|
"mt-2"
|
||||||
} -mx-8 w-full mb-4 flex relative`}
|
} -mx-8 w-full mb-4 flex relative`}
|
||||||
>
|
>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
@@ -795,27 +798,67 @@ function MessageSwitcher({
|
|||||||
totalPages,
|
totalPages,
|
||||||
handlePrevious,
|
handlePrevious,
|
||||||
handleNext,
|
handleNext,
|
||||||
|
disableForStreaming,
|
||||||
}: {
|
}: {
|
||||||
currentPage: number;
|
currentPage: number;
|
||||||
totalPages: number;
|
totalPages: number;
|
||||||
handlePrevious: () => void;
|
handlePrevious: () => void;
|
||||||
handleNext: () => void;
|
handleNext: () => void;
|
||||||
|
disableForStreaming?: boolean;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center text-sm space-x-0.5">
|
<div className="flex items-center text-sm space-x-0.5">
|
||||||
<Hoverable
|
<TooltipProvider>
|
||||||
icon={FiChevronLeft}
|
<Tooltip>
|
||||||
onClick={currentPage === 1 ? undefined : handlePrevious}
|
<TooltipTrigger asChild>
|
||||||
/>
|
<div>
|
||||||
|
<Hoverable
|
||||||
|
icon={FiChevronLeft}
|
||||||
|
onClick={
|
||||||
|
disableForStreaming
|
||||||
|
? () => null
|
||||||
|
: currentPage === 1
|
||||||
|
? undefined
|
||||||
|
: handlePrevious
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
{disableForStreaming
|
||||||
|
? "Wait for agent message to complete"
|
||||||
|
: "Previous"}
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
|
||||||
<span className="text-text-darker select-none">
|
<span className="text-text-darker select-none">
|
||||||
{currentPage} / {totalPages}
|
{currentPage} / {totalPages}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<Hoverable
|
<TooltipProvider>
|
||||||
icon={FiChevronRight}
|
<Tooltip>
|
||||||
onClick={currentPage === totalPages ? undefined : handleNext}
|
<TooltipTrigger>
|
||||||
/>
|
<div>
|
||||||
|
<Hoverable
|
||||||
|
icon={FiChevronRight}
|
||||||
|
onClick={
|
||||||
|
disableForStreaming
|
||||||
|
? () => null
|
||||||
|
: currentPage === totalPages
|
||||||
|
? undefined
|
||||||
|
: handleNext
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
{disableForStreaming
|
||||||
|
? "Wait for agent message to complete"
|
||||||
|
: "Next"}
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -829,6 +872,7 @@ export const HumanMessage = ({
|
|||||||
onMessageSelection,
|
onMessageSelection,
|
||||||
shared,
|
shared,
|
||||||
stopGenerating = () => null,
|
stopGenerating = () => null,
|
||||||
|
disableSwitchingForStreaming = false,
|
||||||
}: {
|
}: {
|
||||||
shared?: boolean;
|
shared?: boolean;
|
||||||
content: string;
|
content: string;
|
||||||
@@ -838,6 +882,7 @@ export const HumanMessage = ({
|
|||||||
onEdit?: (editedContent: string) => void;
|
onEdit?: (editedContent: string) => void;
|
||||||
onMessageSelection?: (messageId: number) => void;
|
onMessageSelection?: (messageId: number) => void;
|
||||||
stopGenerating?: () => void;
|
stopGenerating?: () => void;
|
||||||
|
disableSwitchingForStreaming?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
|
||||||
@@ -1067,6 +1112,7 @@ export const HumanMessage = ({
|
|||||||
otherMessagesCanSwitchTo.length > 1 && (
|
otherMessagesCanSwitchTo.length > 1 && (
|
||||||
<div className="ml-auto mr-3">
|
<div className="ml-auto mr-3">
|
||||||
<MessageSwitcher
|
<MessageSwitcher
|
||||||
|
disableForStreaming={disableSwitchingForStreaming}
|
||||||
currentPage={currentMessageInd + 1}
|
currentPage={currentMessageInd + 1}
|
||||||
totalPages={otherMessagesCanSwitchTo.length}
|
totalPages={otherMessagesCanSwitchTo.length}
|
||||||
handlePrevious={() => {
|
handlePrevious={() => {
|
||||||
|
@@ -294,7 +294,7 @@ const SubQuestionDisplay: React.FC<{
|
|||||||
const renderedMarkdown = useMemo(() => {
|
const renderedMarkdown = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
className="prose max-w-full text-base"
|
className="prose dark:prose-invert max-w-full text-base"
|
||||||
components={markdownComponents}
|
components={markdownComponents}
|
||||||
remarkPlugins={[remarkGfm, remarkMath]}
|
remarkPlugins={[remarkGfm, remarkMath]}
|
||||||
rehypePlugins={[rehypeKatex]}
|
rehypePlugins={[rehypeKatex]}
|
||||||
@@ -340,7 +340,7 @@ const SubQuestionDisplay: React.FC<{
|
|||||||
{subQuestion?.question || temporaryDisplay?.question}
|
{subQuestion?.question || temporaryDisplay?.question}
|
||||||
</div>
|
</div>
|
||||||
<ChevronDown
|
<ChevronDown
|
||||||
className={`mt-0.5 text-text-darker transition-transform duration-500 ease-in-out ${
|
className={`mt-0.5 flex-none text-text-darker transition-transform duration-500 ease-in-out ${
|
||||||
toggled ? "" : "-rotate-90"
|
toggled ? "" : "-rotate-90"
|
||||||
}`}
|
}`}
|
||||||
size={20}
|
size={20}
|
||||||
@@ -632,9 +632,7 @@ const SubQuestionsDisplay: React.FC<SubQuestionsDisplayProps> = ({
|
|||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
{/* {subQuestions.map((subQuestion, index) => ( */}
|
|
||||||
{memoizedSubQuestions.map((subQuestion, index) => (
|
{memoizedSubQuestions.map((subQuestion, index) => (
|
||||||
// {dynamicSubQuestions.map((subQuestion, index) => (
|
|
||||||
<SubQuestionDisplay
|
<SubQuestionDisplay
|
||||||
currentlyOpen={
|
currentlyOpen={
|
||||||
currentlyOpenQuestion?.level === subQuestion.level &&
|
currentlyOpenQuestion?.level === subQuestion.level &&
|
||||||
|
@@ -131,7 +131,7 @@ const StandardAnswersTableRow = ({
|
|||||||
/>,
|
/>,
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
key={`answer-${standardAnswer.id}`}
|
key={`answer-${standardAnswer.id}`}
|
||||||
className="prose"
|
className="prose dark:prose-invert"
|
||||||
remarkPlugins={[remarkGfm]}
|
remarkPlugins={[remarkGfm]}
|
||||||
>
|
>
|
||||||
{standardAnswer.answer}
|
{standardAnswer.answer}
|
||||||
|
@@ -562,6 +562,7 @@ body {
|
|||||||
.prose :where(pre):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
.prose :where(pre):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
||||||
background-color: theme("colors.code-bg");
|
background-color: theme("colors.code-bg");
|
||||||
font-size: theme("fontSize.code-sm");
|
font-size: theme("fontSize.code-sm");
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre[class*="language-"],
|
pre[class*="language-"],
|
||||||
@@ -655,16 +656,3 @@ ul > li > p {
|
|||||||
display: inline;
|
display: inline;
|
||||||
/* Make paragraphs inline to reduce vertical space */
|
/* Make paragraphs inline to reduce vertical space */
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark strong {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.prose.dark li,
|
|
||||||
.prose.dark h1,
|
|
||||||
.prose.dark h2,
|
|
||||||
.prose.dark h3,
|
|
||||||
.prose.dark h4,
|
|
||||||
.prose.dark h5 {
|
|
||||||
color: #e5e5e5;
|
|
||||||
}
|
|
||||||
|
@@ -17,7 +17,7 @@ export const Hoverable: React.FC<{
|
|||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Icon
|
<Icon
|
||||||
size={size}
|
size={size}
|
||||||
className="hover:bg-background-chat-hover dark:text-[#B4B4B4] text-neutral-600 rounded h-fit cursor-pointer"
|
className="dark:text-[#B4B4B4] text-neutral-600 rounded h-fit cursor-pointer"
|
||||||
/>
|
/>
|
||||||
{hoverText && (
|
{hoverText && (
|
||||||
<div className="max-w-0 leading-none whitespace-nowrap overflow-hidden transition-all duration-300 ease-in-out group-hover:max-w-xs group-hover:ml-2">
|
<div className="max-w-0 leading-none whitespace-nowrap overflow-hidden transition-all duration-300 ease-in-out group-hover:max-w-xs group-hover:ml-2">
|
||||||
|
@@ -50,7 +50,7 @@ export function SearchResultIcon({ url }: { url: string }) {
|
|||||||
return <SourceIcon sourceType={ValidSources.Web} iconSize={18} />;
|
return <SourceIcon sourceType={ValidSources.Web} iconSize={18} />;
|
||||||
}
|
}
|
||||||
if (url.includes("docs.onyx.app")) {
|
if (url.includes("docs.onyx.app")) {
|
||||||
return <OnyxIcon size={18} />;
|
return <OnyxIcon size={18} className="dark:text-[#fff] text-[#000]" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@@ -23,7 +23,7 @@ export function WebResultIcon({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{hostname == "docs.onyx.app" ? (
|
{hostname == "docs.onyx.app" ? (
|
||||||
<OnyxIcon size={size} />
|
<OnyxIcon size={size} className="dark:text-[#fff] text-[#000]" />
|
||||||
) : !error ? (
|
) : !error ? (
|
||||||
<img
|
<img
|
||||||
className="my-0 rounded-full py-0"
|
className="my-0 rounded-full py-0"
|
||||||
|
@@ -432,7 +432,10 @@ export const MarkdownFormField = ({
|
|||||||
</div>
|
</div>
|
||||||
{isPreviewOpen ? (
|
{isPreviewOpen ? (
|
||||||
<div className="p-4 border-t border-background-300">
|
<div className="p-4 border-t border-background-300">
|
||||||
<ReactMarkdown className="prose" remarkPlugins={[remarkGfm]}>
|
<ReactMarkdown
|
||||||
|
className="prose dark:prose-invert"
|
||||||
|
remarkPlugins={[remarkGfm]}
|
||||||
|
>
|
||||||
{field.value}
|
{field.value}
|
||||||
</ReactMarkdown>
|
</ReactMarkdown>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -9,7 +9,7 @@ export default function BlurBackground({
|
|||||||
<div
|
<div
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={`
|
className={`
|
||||||
desktop:hidden w-full h-full fixed inset-0 bg-black bg-opacity-50 backdrop-blur-sm z-30 transition-opacity duration-300 ease-in-out ${
|
desktop:hidden w-full h-full fixed inset-0 bg-neutral-700 bg-opacity-50 backdrop-blur-sm z-30 transition-opacity duration-300 ease-in-out ${
|
||||||
visible
|
visible
|
||||||
? "opacity-100 pointer-events-auto"
|
? "opacity-100 pointer-events-auto"
|
||||||
: "opacity-0 pointer-events-none"
|
: "opacity-0 pointer-events-none"
|
||||||
|
@@ -35,7 +35,7 @@ export const MinimalMarkdown: React.FC<MinimalMarkdownProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
className={`w-full text-wrap break-word ${className}`}
|
className={`w-full text-wrap break-word prose dark:prose-invert ${className}`}
|
||||||
components={markdownComponents}
|
components={markdownComponents}
|
||||||
remarkPlugins={[remarkGfm]}
|
remarkPlugins={[remarkGfm]}
|
||||||
>
|
>
|
||||||
|
@@ -78,7 +78,7 @@ export function getUniqueIcons(docs: OnyxDocument[]): JSX.Element[] {
|
|||||||
|
|
||||||
for (const doc of docs) {
|
for (const doc of docs) {
|
||||||
// If it's a web source, we check domain uniqueness
|
// If it's a web source, we check domain uniqueness
|
||||||
if (doc.source_type === ValidSources.Web && doc.link) {
|
if ((doc.is_internet || doc.source_type === ValidSources.Web) && doc.link) {
|
||||||
const domain = getDomainFromUrl(doc.link);
|
const domain = getDomainFromUrl(doc.link);
|
||||||
if (domain && !seenDomains.has(domain)) {
|
if (domain && !seenDomains.has(domain)) {
|
||||||
seenDomains.add(domain);
|
seenDomains.add(domain);
|
||||||
|
@@ -47,7 +47,7 @@ export default function LogoWithText({
|
|||||||
className="flex gap-x-2 items-center ml-0 cursor-pointer desktop:hidden "
|
className="flex gap-x-2 items-center ml-0 cursor-pointer desktop:hidden "
|
||||||
>
|
>
|
||||||
{!toggled ? (
|
{!toggled ? (
|
||||||
<Logo className="desktop:hidden -my-2" height={24} width={24} />
|
<Logo className="desktop:hidden" height={24} width={24} />
|
||||||
) : (
|
) : (
|
||||||
<LogoComponent
|
<LogoComponent
|
||||||
show={toggled}
|
show={toggled}
|
||||||
|
@@ -23,8 +23,11 @@ import { AllUsersResponse } from "./types";
|
|||||||
import { Credential } from "./connectors/credentials";
|
import { Credential } from "./connectors/credentials";
|
||||||
import { SettingsContext } from "@/components/settings/SettingsProvider";
|
import { SettingsContext } from "@/components/settings/SettingsProvider";
|
||||||
import { Persona, PersonaLabel } from "@/app/admin/assistants/interfaces";
|
import { Persona, PersonaLabel } from "@/app/admin/assistants/interfaces";
|
||||||
import { LLMProviderDescriptor } from "@/app/admin/configuration/llm/interfaces";
|
import {
|
||||||
import { isAnthropic } from "@/app/admin/configuration/llm/interfaces";
|
isAnthropic,
|
||||||
|
LLMProviderDescriptor,
|
||||||
|
} from "@/app/admin/configuration/llm/interfaces";
|
||||||
|
|
||||||
import { getSourceMetadata } from "./sources";
|
import { getSourceMetadata } from "./sources";
|
||||||
import { AuthType, NEXT_PUBLIC_CLOUD_ENABLED } from "./constants";
|
import { AuthType, NEXT_PUBLIC_CLOUD_ENABLED } from "./constants";
|
||||||
import { useUser } from "@/components/user/UserProvider";
|
import { useUser } from "@/components/user/UserProvider";
|
||||||
|
@@ -79,12 +79,18 @@ export async function* handleStream<T extends NonEmptyObject>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function* handleSSEStream<T extends PacketType>(
|
export async function* handleSSEStream<T extends PacketType>(
|
||||||
streamingResponse: Response
|
streamingResponse: Response,
|
||||||
|
signal?: AbortSignal
|
||||||
): AsyncGenerator<T, void, unknown> {
|
): AsyncGenerator<T, void, unknown> {
|
||||||
const reader = streamingResponse.body?.getReader();
|
const reader = streamingResponse.body?.getReader();
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
let buffer = "";
|
let buffer = "";
|
||||||
|
if (signal) {
|
||||||
|
signal.addEventListener("abort", () => {
|
||||||
|
console.log("aborting");
|
||||||
|
reader?.cancel();
|
||||||
|
});
|
||||||
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
const rawChunk = await reader?.read();
|
const rawChunk = await reader?.read();
|
||||||
if (!rawChunk) {
|
if (!rawChunk) {
|
||||||
|
@@ -21,7 +21,6 @@ module.exports = {
|
|||||||
transitionProperty: {
|
transitionProperty: {
|
||||||
spacing: "margin, padding",
|
spacing: "margin, padding",
|
||||||
},
|
},
|
||||||
|
|
||||||
keyframes: {
|
keyframes: {
|
||||||
"subtle-pulse": {
|
"subtle-pulse": {
|
||||||
"0%, 100%": { opacity: 0.9 },
|
"0%, 100%": { opacity: 0.9 },
|
||||||
@@ -148,7 +147,6 @@ module.exports = {
|
|||||||
"text-mobile-sidebar": "var(--text-800)",
|
"text-mobile-sidebar": "var(--text-800)",
|
||||||
"background-search-filter": "var(--neutral-100-border-light)",
|
"background-search-filter": "var(--neutral-100-border-light)",
|
||||||
"background-search-filter-dropdown": "var(--neutral-100-border-light)",
|
"background-search-filter-dropdown": "var(--neutral-100-border-light)",
|
||||||
"tw-prose-bold": "var(--text-800)",
|
|
||||||
|
|
||||||
"user-bubble": "var(--off-white)",
|
"user-bubble": "var(--off-white)",
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user