mirror of https://github.com/buster-so/buster.git
Merge branch 'big-nate/bus-939-create-new-structure-for-chats' into evals
This commit is contained in:
commit
2d99ad32b7
|
@ -61,11 +61,23 @@ export const useGetListLogs = (
|
|||
});
|
||||
};
|
||||
|
||||
export const useGetChat = (params: Parameters<typeof getChat>[0]) => {
|
||||
const queryFn = useMemoizedFn(async () => {
|
||||
return await getChat(params).then((chat) => {
|
||||
console.log('TODO move this to put message in a better spot');
|
||||
return updateChatToIChat(chat, true).iChat;
|
||||
export const useGetChat = <TData = IBusterChat>(
|
||||
params: Parameters<typeof getChat>[0],
|
||||
select?: (chat: IBusterChat) => TData
|
||||
) => {
|
||||
const queryClient = useQueryClient();
|
||||
const queryFn = useMemoizedFn(() => {
|
||||
return getChat(params).then((chat) => {
|
||||
const { iChat, iChatMessages } = updateChatToIChat(chat, false);
|
||||
|
||||
iChat.message_ids.forEach((messageId) => {
|
||||
queryClient.setQueryData(
|
||||
queryKeys.chatsMessages(messageId).queryKey,
|
||||
iChatMessages[messageId]
|
||||
);
|
||||
});
|
||||
|
||||
return iChat;
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -75,10 +87,11 @@ export const useGetChat = (params: Parameters<typeof getChat>[0]) => {
|
|||
enabled: !!params.id
|
||||
});
|
||||
|
||||
return useQuery<IBusterChat, RustApiError>({
|
||||
return useQuery({
|
||||
...queryKeys.chatsGetChat(params.id),
|
||||
queryKey: queryKeys.chatsGetChat(params.id).queryKey,
|
||||
enabled: !!params.id
|
||||
enabled: !!params.id,
|
||||
queryFn,
|
||||
select
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -16,20 +16,12 @@ import {
|
|||
import { useMemoizedFn } from '@/hooks';
|
||||
import { QueryClient, useQueryClient } from '@tanstack/react-query';
|
||||
import { queryKeys } from '@/api/query_keys';
|
||||
import type {
|
||||
UsersFavoritePostPayload,
|
||||
UserFavoriteDeletePayload,
|
||||
UserUpdateFavoritesPayload,
|
||||
UserRequestUserListPayload
|
||||
} from '@/api/request_interfaces/user/interfaces';
|
||||
import type { UserRequestUserListPayload } from '@/api/request_interfaces/user/interfaces';
|
||||
|
||||
export const useGetMyUserInfo = () => {
|
||||
const queryFn = useMemoizedFn(async () => {
|
||||
return getMyUserInfo();
|
||||
});
|
||||
return useQuery({
|
||||
...queryKeys.userGetUserMyself,
|
||||
queryFn,
|
||||
queryFn: getMyUserInfo,
|
||||
enabled: false //This is a server only query
|
||||
});
|
||||
};
|
||||
|
|
|
@ -18,7 +18,8 @@ const favoritesGetList = queryOptions<BusterUserFavorite[]>({
|
|||
});
|
||||
|
||||
const userGetUserMyself = queryOptions<BusterUserResponse>({
|
||||
queryKey: ['users', 'myself'] as const
|
||||
queryKey: ['users', 'myself'] as const,
|
||||
staleTime: 1000 * 60 * 60 // 1 hour
|
||||
});
|
||||
|
||||
const userGetUser = (userId: string) =>
|
||||
|
|
|
@ -100,7 +100,7 @@ const DropdownMenuItem = React.forwardRef<
|
|||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0',
|
||||
'relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-base outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0',
|
||||
'focus:bg-item-hover focus:text-foreground',
|
||||
inset && 'pl-8',
|
||||
truncate && 'overflow-hidden',
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { AppPageLayout } from './AppPageLayout';
|
||||
import React from 'react';
|
||||
|
||||
const meta: Meta<typeof AppPageLayout> = {
|
||||
title: 'UI/Layouts/AppPageLayout',
|
||||
|
@ -53,6 +54,7 @@ export const LongContent: Story = {
|
|||
args: {
|
||||
header: <div className="bg-gray-100">Header Content</div>,
|
||||
scrollable: true,
|
||||
headerBorderVariant: 'ghost',
|
||||
children: (
|
||||
<>
|
||||
{Array.from({ length: 100 }, (_, i) => (
|
||||
|
|
|
@ -39,7 +39,14 @@ export const AppPageLayout: React.FC<
|
|||
{header}
|
||||
</AppPageLayoutHeader>
|
||||
)}
|
||||
<AppPageLayoutContent scrollable={scrollable}>{children}</AppPageLayoutContent>
|
||||
|
||||
<AppPageLayoutContent className="scroll-shadow-container" scrollable={scrollable}>
|
||||
{header && scrollable && headerBorderVariant === 'ghost' && (
|
||||
<div className="scroll-header"></div>
|
||||
)}
|
||||
|
||||
{children}
|
||||
</AppPageLayoutContent>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
|||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
|
||||
const headerVariants = cva(
|
||||
'bg-page-background flex max-h-[38px] min-h-[38px] items-center justify-between gap-x-2.5 ',
|
||||
'bg-page-background flex max-h-[38px] min-h-[38px] items-center justify-between gap-x-2.5 relative z-10',
|
||||
{
|
||||
variants: {
|
||||
sizeVariant: {
|
||||
|
|
|
@ -70,7 +70,7 @@ const AppMarkdownBase: React.FC<{
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<div className={cn(styles.container, className)}>
|
||||
<div className={cn(styles.container, 'flex flex-col gap-1.5', className)}>
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
skipHtml={true}
|
||||
|
|
|
@ -35,7 +35,11 @@ export const CustomParagraph: React.FC<
|
|||
> = ({ children, markdown, showLoader, ...rest }) => {
|
||||
if (Array.isArray(children)) {
|
||||
return (
|
||||
<p className={cn('leading-1.3', showLoader && 'animate-in fade-in duration-700')}>
|
||||
<p
|
||||
className={cn(
|
||||
'leading-1.3 text-size-inherit!',
|
||||
showLoader && 'animate-in fade-in duration-700'
|
||||
)}>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
|
@ -48,7 +52,13 @@ export const CustomParagraph: React.FC<
|
|||
}
|
||||
|
||||
return (
|
||||
<p className={cn('leading-1.3', showLoader && 'animate-in fade-in duration-700')}>{children}</p>
|
||||
<p
|
||||
className={cn(
|
||||
'leading-1.3 text-size-inherit!',
|
||||
showLoader && 'animate-in fade-in duration-700'
|
||||
)}>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -112,7 +122,11 @@ export const CustomListItem: React.FC<
|
|||
} & ExtraPropsExtra
|
||||
> = ({ children, markdown, showLoader, ...rest }) => {
|
||||
return (
|
||||
<li className={cn('leading-1.3', showLoader && 'animate-in fade-in duration-700')}>
|
||||
<li
|
||||
className={cn(
|
||||
'leading-1.3 list-inside list-disc',
|
||||
showLoader && 'animate-in fade-in duration-700'
|
||||
)}>
|
||||
{children}
|
||||
</li>
|
||||
);
|
||||
|
|
|
@ -38,13 +38,13 @@ export const useChatUpdate = () => {
|
|||
const options = queryKeys.chatsMessages(newMessageConfig.id);
|
||||
const queryKey = options.queryKey;
|
||||
const currentData = queryClient.getQueryData(queryKey);
|
||||
|
||||
const iChatMessage = create(currentData!, (draft) => {
|
||||
if (currentData) {
|
||||
const iChatMessage = create(currentData, (draft) => {
|
||||
Object.assign(draft, newMessageConfig);
|
||||
});
|
||||
|
||||
queryClient.setQueryData(queryKey, iChatMessage);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
|
@ -107,6 +107,10 @@ export const useBusterNewChat = () => {
|
|||
|
||||
const onFollowUpChat = useMemoizedFn(
|
||||
async ({ prompt, chatId }: { prompt: string; chatId: string }) => {
|
||||
busterSocket.once({
|
||||
route: '/chats/post:initializeChat',
|
||||
callback: initializeNewChatCallback
|
||||
});
|
||||
await busterSocket.emitAndOnce({
|
||||
emitEvent: {
|
||||
route: '/chats/post',
|
||||
|
|
|
@ -191,7 +191,7 @@ export const updateReasoningMessage = (
|
|||
Object.assign(fileContentDraft, existingFile?.file || {});
|
||||
fileContentDraft.text = newFile.file.text_chunk
|
||||
? (existingFile?.file?.text || '') + newFile.file.text_chunk
|
||||
: (newFile.file.text ?? existingFile?.file?.text);
|
||||
: (existingFile?.file?.text ?? newFile.file.text); //we are going to ignore newfile text in favor of existing... this is because Dallin is having a tough time keep yaml in order
|
||||
fileContentDraft.modified =
|
||||
newFile.file.modified ?? existingFile?.file?.modified;
|
||||
});
|
||||
|
|
|
@ -37,10 +37,12 @@ export const useChatStreamMessage = () => {
|
|||
|
||||
const onUpdateChatMessageTransition = useMemoizedFn(
|
||||
(chatMessage: Parameters<typeof onUpdateChatMessage>[0]) => {
|
||||
const currentChatMessage = chatRefMessages.current[chatMessage.id];
|
||||
const currentChatMessage = chatRefMessages.current[chatMessage.id] || {};
|
||||
const iChatMessage: IBusterChatMessage = create(currentChatMessage, (draft) => {
|
||||
Object.assign(draft || {}, chatMessage);
|
||||
if (chatMessage.id) draft.id = chatMessage.id;
|
||||
if (chatMessage.id) {
|
||||
draft.id = chatMessage.id;
|
||||
}
|
||||
})!;
|
||||
chatRefMessages.current[chatMessage.id] = iChatMessage;
|
||||
|
||||
|
@ -79,14 +81,17 @@ export const useChatStreamMessage = () => {
|
|||
});
|
||||
|
||||
const initializeNewChatCallback = useMemoizedFn((d: BusterChat) => {
|
||||
const hasMultipleMessages = d.message_ids.length > 1;
|
||||
const { iChat, iChatMessages } = updateChatToIChat(d, true);
|
||||
chatRef.current[iChat.id] = iChat;
|
||||
normalizeChatMessage(iChatMessages);
|
||||
onUpdateChat(iChat);
|
||||
if (!hasMultipleMessages) {
|
||||
onChangePage({
|
||||
route: BusterRoutes.APP_CHAT_ID,
|
||||
chatId: iChat.id
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const replaceMessageCallback = useMemoizedFn(
|
||||
|
@ -106,9 +111,12 @@ export const useChatStreamMessage = () => {
|
|||
|
||||
const _generatingTitleCallback = useMemoizedFn((_: null, newData: ChatEvent_GeneratingTitle) => {
|
||||
const { chat_id } = newData;
|
||||
const updatedChat = updateChatTitle(chatRef.current[chat_id], newData);
|
||||
const currentChat = chatRef.current[chat_id];
|
||||
if (currentChat) {
|
||||
const updatedChat = updateChatTitle(currentChat, newData);
|
||||
chatRef.current[chat_id] = updatedChat;
|
||||
onUpdateChat(updatedChat);
|
||||
}
|
||||
});
|
||||
|
||||
const _generatingResponseMessageCallback = useMemoizedFn(
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { useChatIndividualContextSelector } from '@/layouts/ChatLayout/ChatContext';
|
||||
import { useMessageIndividual } from '@/context/Chats';
|
||||
import { ReasoningMessageSelector } from './ReasoningMessages';
|
||||
import { BlackBoxMessage } from './ReasoningMessages/ReasoningBlackBoxMessage';
|
||||
import { useGetChat } from '@/api/buster_rest/chats';
|
||||
import { FileIndeterminateLoader } from '@/components/features/FileIndeterminateLoader';
|
||||
|
||||
interface ReasoningControllerProps {
|
||||
chatId: string;
|
||||
|
@ -12,12 +13,12 @@ interface ReasoningControllerProps {
|
|||
}
|
||||
|
||||
export const ReasoningController: React.FC<ReasoningControllerProps> = ({ chatId, messageId }) => {
|
||||
const hasChat = useChatIndividualContextSelector((state) => state.hasChat);
|
||||
const { data: hasChat } = useGetChat({ id: chatId || '' }, (x) => !!x.id);
|
||||
|
||||
const reasoningMessageIds = useMessageIndividual(messageId, (x) => x?.reasoning_message_ids);
|
||||
const isCompletedStream = useMessageIndividual(messageId, (x) => x?.isCompletedStream);
|
||||
|
||||
if (!hasChat || !reasoningMessageIds)
|
||||
return <>ReasoningController: If you are seeing this there is probably an error...</>;
|
||||
if (!hasChat || !reasoningMessageIds) return <FileIndeterminateLoader />;
|
||||
|
||||
return (
|
||||
<div className="h-full flex-col space-y-2 overflow-y-auto p-5">
|
||||
|
|
|
@ -23,7 +23,11 @@ export const BarContainer: React.FC<{
|
|||
/>
|
||||
|
||||
<div className={`mb-2 flex w-full flex-col space-y-2 overflow-hidden`}>
|
||||
<TitleContainer title={title} secondaryTitle={secondaryTitle} />
|
||||
<TitleContainer
|
||||
title={title}
|
||||
secondaryTitle={secondaryTitle}
|
||||
isCompletedStream={isCompletedStream}
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -77,12 +81,14 @@ VerticalBar.displayName = 'VerticalBar';
|
|||
const TitleContainer: React.FC<{
|
||||
title: string;
|
||||
secondaryTitle?: string;
|
||||
}> = React.memo(({ title, secondaryTitle }) => {
|
||||
isCompletedStream: boolean;
|
||||
}> = React.memo(({ title, secondaryTitle, isCompletedStream }) => {
|
||||
return (
|
||||
<div className={cn('@container', 'flex w-full items-center space-x-1.5 overflow-hidden')}>
|
||||
<AnimatedThoughtTitle title={title} type="default" />
|
||||
<AnimatedThoughtTitle title={title} type="default" isCompletedStream={isCompletedStream} />
|
||||
<AnimatedThoughtTitle
|
||||
title={secondaryTitle}
|
||||
isCompletedStream={isCompletedStream}
|
||||
type="tertiary"
|
||||
className="secondary-text truncate"
|
||||
/>
|
||||
|
@ -96,22 +102,24 @@ const AnimatedThoughtTitle = React.memo(
|
|||
({
|
||||
title,
|
||||
type,
|
||||
isCompletedStream,
|
||||
className = ''
|
||||
}: {
|
||||
title: string | undefined;
|
||||
type: 'tertiary' | 'default';
|
||||
className?: string;
|
||||
isCompletedStream: boolean;
|
||||
}) => {
|
||||
const isSecondaryTitle = type === 'tertiary';
|
||||
return (
|
||||
<AnimatePresence initial={false} mode="wait">
|
||||
<AnimatePresence initial={!isCompletedStream && isSecondaryTitle} mode="wait">
|
||||
{title && (
|
||||
<motion.div
|
||||
className="flex"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ delay: 0.125 }}
|
||||
transition={{ delay: isSecondaryTitle ? 0.5 : 0.125 }}
|
||||
key={title}>
|
||||
<Text
|
||||
size="sm"
|
||||
|
|
|
@ -96,7 +96,7 @@ export const ReasoningMessageSelector: React.FC<ReasoningMessageSelectorProps> =
|
|||
isCompletedStream={isCompletedStream}
|
||||
title={title ?? ''}
|
||||
secondaryTitle={secondary_title ?? ''}>
|
||||
<AnimatePresence mode="wait">
|
||||
<AnimatePresence mode="wait" initial={!isCompletedStream}>
|
||||
<motion.div key={animationKey} {...itemAnimationConfig} className="overflow-hidden" layout>
|
||||
<div className="min-h-[1px]">
|
||||
<ReasoningMessage
|
||||
|
|
|
@ -3,7 +3,6 @@ import { ReasoningMessageProps } from '../ReasoningMessageSelector';
|
|||
import { type BusterChatMessageReasoning_text } from '@/api/asset_interfaces/chat';
|
||||
import { useMessageIndividual } from '@/context/Chats';
|
||||
import { AppMarkdown } from '@/components/ui/typography/AppMarkdown';
|
||||
import { StreamingMessage_Text } from '@/components/ui/streaming/StreamingMessage_Text';
|
||||
|
||||
export const ReasoningMessage_Text: React.FC<ReasoningMessageProps> = React.memo(
|
||||
({ reasoningMessageId, messageId, isCompletedStream }) => {
|
||||
|
@ -12,7 +11,14 @@ export const ReasoningMessage_Text: React.FC<ReasoningMessageProps> = React.memo
|
|||
(x) => (x?.reasoning_messages[reasoningMessageId] as BusterChatMessageReasoning_text)?.message
|
||||
)!;
|
||||
|
||||
return <AppMarkdown markdown={message} showLoader={!isCompletedStream} stripFormatting />;
|
||||
return (
|
||||
<AppMarkdown
|
||||
markdown={message}
|
||||
showLoader={!isCompletedStream}
|
||||
className="text-text-secondary text-xs!"
|
||||
stripFormatting
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ export const ChatContainer = React.memo(() => {
|
|||
|
||||
return (
|
||||
<AppPageLayout
|
||||
header={<ChatHeader showScrollOverflow={showScrollOverflow} />}
|
||||
header={<ChatHeader />}
|
||||
headerBorderVariant="ghost"
|
||||
className="flex h-full w-full min-w-[295px] flex-col">
|
||||
<ChatContent chatContentRef={chatContentRef} />
|
||||
|
|
|
@ -2,7 +2,6 @@ import React from 'react';
|
|||
import { MessageContainer } from '../MessageContainer';
|
||||
import { ChatResponseMessageSelector } from './ChatResponseMessageSelector';
|
||||
import { ChatResponseReasoning } from './ChatResponseReasoning';
|
||||
import { ShimmerText } from '@/components/ui/typography/ShimmerText';
|
||||
import { useMessageIndividual } from '@/context/Chats';
|
||||
|
||||
interface ChatResponseMessagesProps {
|
||||
|
|
|
@ -55,10 +55,12 @@ export const ChatResponseReasoning: React.FC<{
|
|||
<motion.div
|
||||
{...animations}
|
||||
key={text}
|
||||
className="mb-3.5 w-fit cursor-pointer"
|
||||
className="mb-3.5 flex h-[14px] max-h-[14px] w-fit cursor-pointer items-center"
|
||||
onClick={onClickReasoning}>
|
||||
{isReasonginFileSelected ? (
|
||||
<Text className="hover:underline">{text}</Text>
|
||||
<Text className="text-text-secondary hover:text-text-default hover:underline">
|
||||
{text}
|
||||
</Text>
|
||||
) : (
|
||||
<ShimmerText text={text ?? ''} />
|
||||
)}
|
||||
|
|
|
@ -11,7 +11,7 @@ export const ChatUserMessage: React.FC<{ requestMessage: BusterChatMessageReques
|
|||
|
||||
return (
|
||||
<MessageContainer senderName={sender_name} senderId={sender_id} senderAvatar={sender_avatar}>
|
||||
<Paragraph className="text-sm">{request}</Paragraph>
|
||||
<Paragraph>{request}</Paragraph>
|
||||
</MessageContainer>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,17 +5,15 @@ import { ChatHeaderOptions } from './ChatHeaderOptions';
|
|||
import { ChatHeaderTitle } from './ChatHeaderTitle';
|
||||
import { useChatIndividualContextSelector } from '../../ChatContext';
|
||||
|
||||
export const ChatHeader: React.FC<{
|
||||
showScrollOverflow: boolean;
|
||||
}> = React.memo(({ showScrollOverflow }) => {
|
||||
export const ChatHeader: React.FC<{}> = React.memo(({}) => {
|
||||
const hasFile = useChatIndividualContextSelector((state) => state.hasFile);
|
||||
const chatTitle = useChatIndividualContextSelector((state) => state.chatTitle);
|
||||
|
||||
if (!hasFile && !chatTitle) return null;
|
||||
if (!hasFile || !chatTitle) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<ChatHeaderTitle />
|
||||
<ChatHeaderTitle chatTitle={chatTitle} />
|
||||
<ChatHeaderOptions />
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import { Text } from '@/components/ui/typography';
|
||||
import React from 'react';
|
||||
import { AnimatePresence, motion } from 'framer-motion';
|
||||
import { useChatIndividualContextSelector } from '../../ChatContext';
|
||||
|
||||
const animation = {
|
||||
initial: { opacity: 0 },
|
||||
|
@ -12,8 +11,10 @@ const animation = {
|
|||
transition: { duration: 0.25 }
|
||||
};
|
||||
|
||||
export const ChatHeaderTitle: React.FC<{}> = React.memo(() => {
|
||||
const chatTitle = useChatIndividualContextSelector((state) => state.chatTitle);
|
||||
export const ChatHeaderTitle: React.FC<{
|
||||
chatTitle: string;
|
||||
}> = React.memo(({ chatTitle }) => {
|
||||
if (!chatTitle) return <div></div>;
|
||||
|
||||
return (
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
|
|
|
@ -20,8 +20,12 @@ const useChatIndividualContext = ({
|
|||
const selectedFileType = selectedFile?.type;
|
||||
|
||||
//CHAT
|
||||
const { data: chat } = useGetChat({ id: chatId || '' });
|
||||
const hasChat = !!chatId && !!chat;
|
||||
const { data: chat } = useGetChat({ id: chatId || '' }, (x) => ({
|
||||
title: x.title,
|
||||
message_ids: x.message_ids,
|
||||
id: x.id
|
||||
}));
|
||||
const hasChat = !!chatId && !!chat?.id;
|
||||
const chatTitle = chat?.title;
|
||||
const chatMessageIds = chat?.message_ids ?? [];
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ export const useAutoChangeLayout = ({
|
|||
lastMessageId: string;
|
||||
onSetSelectedFile: (file: SelectedFile) => void;
|
||||
}) => {
|
||||
const hasSeeningReasoningPage = useRef(false); //used when there is a delay in page load
|
||||
const previousLastMessageId = useRef<string | null>(null);
|
||||
const reasoningMessagesLength = useMessageIndividual(
|
||||
lastMessageId,
|
||||
(x) => x?.reasoning_message_ids?.length || 0
|
||||
|
@ -21,9 +21,10 @@ export const useAutoChangeLayout = ({
|
|||
|
||||
//change the page to reasoning file if we get a reasoning message
|
||||
useEffect(() => {
|
||||
if (!isCompletedStream && !hasSeeningReasoningPage.current && hasReasoning) {
|
||||
hasSeeningReasoningPage.current = true;
|
||||
if (!isCompletedStream && hasReasoning && previousLastMessageId.current !== lastMessageId) {
|
||||
// hasSeeningReasoningPage.current = true;
|
||||
onSetSelectedFile({ id: lastMessageId, type: 'reasoning' });
|
||||
previousLastMessageId.current = lastMessageId;
|
||||
}
|
||||
}, [isCompletedStream, hasReasoning]);
|
||||
}, [isCompletedStream, hasReasoning, lastMessageId]);
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@ import { create } from 'mutative';
|
|||
import omit from 'lodash/omit';
|
||||
import { BusterMetric, IBusterMetric } from '@/api/asset_interfaces/metric';
|
||||
import { createDefaultChartConfig } from './messageAutoChartHandler';
|
||||
import last from 'lodash/last';
|
||||
|
||||
const chatUpgrader = (chat: BusterChat, { isNewChat }: { isNewChat: boolean }): IBusterChat => {
|
||||
return {
|
||||
|
@ -20,7 +21,7 @@ const chatMessageUpgrader = (
|
|||
return messageIds.reduce(
|
||||
(acc, messageId) => {
|
||||
acc[messageId] = create(message[messageId] as IBusterChatMessage, (draft) => {
|
||||
draft.isCompletedStream = streamingMessageId !== messageId;
|
||||
draft.isCompletedStream = !streamingMessageId || streamingMessageId !== messageId;
|
||||
return draft;
|
||||
});
|
||||
return acc;
|
||||
|
@ -37,7 +38,7 @@ export const updateChatToIChat = (
|
|||
const iChatMessages = chatMessageUpgrader(
|
||||
chat.message_ids,
|
||||
chat.messages,
|
||||
isNewChat ? chat.message_ids[0] : undefined
|
||||
isNewChat ? last(chat.message_ids) : undefined
|
||||
);
|
||||
return {
|
||||
iChat,
|
||||
|
|
|
@ -5,3 +5,31 @@
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// This approach has very limited browser support
|
||||
:root {
|
||||
--globalScrollTimeline: none; // Define the timeline globally
|
||||
}
|
||||
|
||||
.scroll-shadow-container {
|
||||
position: relative;
|
||||
scroll-timeline-name: --globalScrollTimeline;
|
||||
@apply relative;
|
||||
|
||||
.scroll-header {
|
||||
@apply fixed top-[30px] right-0 left-0 h-2 w-full;
|
||||
animation: shadowAnimation linear;
|
||||
animation-range: 0px 125px;
|
||||
animation-timeline: --globalScrollTimeline;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
@keyframes shadowAnimation {
|
||||
from {
|
||||
box-shadow: 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
to {
|
||||
box-shadow: 0px 1px 8px 0px #00000029;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,5 +45,5 @@ body {
|
|||
}
|
||||
|
||||
p {
|
||||
@apply leading-1.3 text-base;
|
||||
@apply leading-1.3;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
--text-3xl--line-height: 1;
|
||||
--text-4xl: 30px;
|
||||
--text-4xl--line-height: 1;
|
||||
--text-size-inherit: inherit;
|
||||
|
||||
--text-icon-size: 16px;
|
||||
--text-icon-size--line-height: 1.05;
|
||||
|
|
Loading…
Reference in New Issue