Merge branch 'big-nate/bus-939-create-new-structure-for-chats' into evals

This commit is contained in:
dal 2025-03-11 10:24:12 -06:00
commit 4ba639ecc5
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
16 changed files with 109 additions and 107 deletions

View File

@ -8,25 +8,26 @@ import {
updateChat,
deleteChat
} from './requests';
import type { BusterChatListItem, IBusterChat } from '@/api/asset_interfaces/chat';
import type { IBusterChat } from '@/api/asset_interfaces/chat';
import { queryKeys } from '@/api/query_keys';
import { updateChatToIChat } from '@/lib/chat';
import { RustApiError } from '@/api/buster_rest/errors';
import { useMemo } from 'react';
export const useGetListChats = (params?: Parameters<typeof getListChats>[0]) => {
const queryFn = useMemoizedFn((): Promise<BusterChatListItem[]> => {
return getListChats(params);
});
export const useGetListChats = (
filters?: Omit<Parameters<typeof getListChats>[0], 'page_token' | 'page_size'>
) => {
const filtersCompiled: Parameters<typeof getListChats>[0] = useMemo(
() => ({ admin_view: false, page_token: 0, page_size: 3000, ...filters }),
[filters]
);
const res = useQuery({
...queryKeys.chatsGetList(params),
const queryFn = useMemoizedFn(() => getListChats(filtersCompiled));
return useQuery({
...queryKeys.chatsGetList(filtersCompiled),
queryFn
});
return {
...res,
data: res.data || []
};
};
export const prefetchGetListChats = async (

View File

@ -13,7 +13,7 @@ const CHATS_BASE = '/chats';
export const getListChats = async (params?: GetChatListParams): Promise<BusterChatListItem[]> => {
const { page_token = 0, page_size = 1000, admin_view = false } = params || {};
return mainApi
.get<BusterChatListItem[]>(`${CHATS_BASE}/list`, {
.get<BusterChatListItem[]>(`${CHATS_BASE}`, {
params: { page_token, page_size, admin_view }
})
.then((res) => res.data);
@ -24,7 +24,7 @@ export const getListChats_server = async (
params?: GetChatListParams
): Promise<BusterChatListItem[]> => {
const { page_token = 0, page_size = 1000, admin_view = false } = params || {};
return await serverFetch<BusterChatListItem[]>(`${CHATS_BASE}/list`, {
return await serverFetch<BusterChatListItem[]>(`${CHATS_BASE}`, {
params: { page_token, page_size, admin_view }
});
};

View File

@ -29,26 +29,24 @@ export const listMetrics_server = async (params: ListMetricsParams) => {
return await serverFetch<BusterMetricListItem[]>('/metrics/list', { params });
};
export const getMetricData = async (params: { id: string }) => {
return mainApi.get<BusterMetricData>(`/metrics/data`, { params }).then((res) => res.data);
export const getMetricData = async ({ id }: { id: string }) => {
return mainApi.get<BusterMetricData>(`/metrics/data/${id}`).then((res) => res.data);
};
export const updateMetric = async (params: UpdateMetricParams) => {
return mainApi.put<BusterMetric>(`/metrics/update`, { params }).then((res) => res.data);
};
export const deleteMetrics = async (params: { ids: string[] }) => {
return mainApi
.delete<BusterMetricListItem[]>(`/metrics/delete`, { params })
.put<BusterMetric>(`/metrics/update/${params.id}`, { params })
.then((res) => res.data);
};
export const duplicateMetrics = async (params: {
export const deleteMetrics = async (params: { ids: string[] }) => {
return mainApi.delete<null>(`/metrics/delete`, { params }).then((res) => res.data);
};
export const duplicateMetric = async (params: {
id: string;
message_id: string;
share_with_same_people: boolean;
}) => {
return mainApi
.post<BusterMetricListItem[]>(`/metrics/duplicate`, { params })
.then((res) => res.data);
return mainApi.post<BusterMetric>(`/metrics/duplicate`, { params }).then((res) => res.data);
};

View File

@ -16,8 +16,7 @@ export const useGetOrganizationUsers = (organizationId: string) => {
queryKey,
staleTime: 10 * 1000,
queryFn,
enabled: !!organizationId,
initialData: []
enabled: !!organizationId
});
};

View File

@ -27,7 +27,8 @@ const chatsMessagesFetchingData = (messageId: string) =>
const chatsGetList = (filters?: GetChatListParams) =>
queryOptions<BusterChatListItem[]>({
queryKey: ['chats', 'list', filters] as const,
staleTime: 10 * 1000
staleTime: 0,
initialData: []
});
const chatsBlackBoxMessages = (messageId: string) =>

View File

@ -1,15 +1,16 @@
'use client';
import React, { useState } from 'react';
import { useBusterChatListByFilter } from '@/context/Chats';
import { ChatItemsContainer } from './ChatItemsContainer';
import { useGetListChats } from '@/api/buster_rest/chats';
import { GetChatListParams } from '@/api/request_interfaces/chats';
export const ChatListContainer: React.FC<{}> = ({}) => {
const [filters, setFilters] = useState<Parameters<typeof useBusterChatListByFilter>[0]>({
const [filters, setFilters] = useState<Partial<GetChatListParams>>({
admin_view: false
});
const { list, isFetched } = useBusterChatListByFilter(filters);
const { data: list, isFetched } = useGetListChats(filters);
return <ChatItemsContainer chats={list} loading={!isFetched} />;
};

View File

@ -1,5 +1,6 @@
'use client';
import { Toaster } from '@/components/ui/toaster/Toaster';
import React, { PropsWithChildren } from 'react';
import { toast, type ExternalToast } from 'sonner';
import { useContextSelector, createContext } from 'use-context-selector';
@ -167,7 +168,7 @@ export const BusterNotificationsProvider: React.FC<PropsWithChildren> = ({ child
return (
<BusterNotifications.Provider value={value}>
{children}
{/* <Toaster /> */}
<Toaster />
</BusterNotifications.Provider>
);
};

View File

@ -21,8 +21,8 @@ function makeQueryClient(params?: {
enabled: (params?.enabled ?? true) && baseEnabled,
queryFn: () => Promise.resolve(),
retry: (failureCount, error) => {
if (params?.openErrorNotification && failureCount > 0) {
params.openErrorNotification(error);
if (params?.openErrorNotification) {
// params.openErrorNotification(error);
}
return false;
}

View File

@ -1 +0,0 @@
export * from './useBusterChatListByFilter';

View File

@ -1,21 +0,0 @@
import { useGetListChats } from '@/api/buster_rest/chats';
import { GetChatListParams } from '@/api/request_interfaces/chats';
import { useMemo } from 'react';
export const useBusterChatListByFilter = (
filtersProp: Omit<GetChatListParams, 'page_token' | 'page_size'>
) => {
const filters = useMemo(
() => ({ ...filtersProp, page_token: 0, page_size: 3000 }),
[filtersProp]
);
const { data: chatsList, isFetched: isFetchedChatsList } = useGetListChats(filters);
//ACTIONS
return {
list: chatsList || [],
isFetched: isFetchedChatsList
};
};

View File

@ -1,12 +1,6 @@
import { useBusterNewChatContextSelector } from './NewChatProvider';
import { useBusterChatContextSelector, useMessageIndividual } from './ChatProvider';
import { useBusterChatListByFilter } from './ChatListProvider';
export * from './BusterChatProvider';
export {
useBusterNewChatContextSelector,
useBusterChatContextSelector,
useBusterChatListByFilter,
useMessageIndividual
};
export { useBusterNewChatContextSelector, useBusterChatContextSelector, useMessageIndividual };

View File

@ -13,10 +13,14 @@ export const BarContainer: React.FC<{
children?: React.ReactNode;
title: string;
secondaryTitle?: string;
}> = React.memo(({ showBar, status, children, title, secondaryTitle }) => {
}> = React.memo(({ showBar, isCompletedStream, status, children, title, secondaryTitle }) => {
return (
<div className={'relative flex space-x-1.5 overflow-hidden'}>
<VerticalBarContainer showBar={showBar} status={status} />
<VerticalBarContainer
showBar={showBar}
status={status}
isCompletedStream={isCompletedStream}
/>
<div className={`mb-2 flex w-full flex-col space-y-2 overflow-hidden`}>
<TitleContainer title={title} secondaryTitle={secondaryTitle} />
@ -31,37 +35,44 @@ BarContainer.displayName = 'BarContainer';
const VerticalBarContainer: React.FC<{
showBar: boolean;
status: BusterChatMessageReasoning_status;
}> = React.memo(({ showBar, status }) => {
isCompletedStream: boolean;
}> = React.memo(({ showBar, isCompletedStream, status }) => {
return (
<div className="ml-2 flex w-5 min-w-5 flex-col items-center">
<StatusIndicator status={status} />
<VerticalBar show={showBar} />
<VerticalBar show={showBar} isCompletedStream={isCompletedStream} />
</div>
);
});
VerticalBarContainer.displayName = 'BarContainer';
const VerticalBar: React.FC<{ show?: boolean }> = ({ show }) => {
return (
<div
className={cn(
'flex w-full flex-1 justify-center overflow-hidden',
'opacity-0 transition-opacity duration-300',
show && 'opacity-100!'
)}>
<motion.div
className={cn('bg-text-tertiary w-[0.5px]', 'mt-1 overflow-hidden')}
initial={{ height: 0 }}
animate={{ height: 'auto' }}
transition={{
duration: 0.3,
ease: 'easeInOut'
}}
/>
</div>
);
};
const VerticalBar: React.FC<{ show?: boolean; isCompletedStream: boolean }> = React.memo(
({ show, isCompletedStream }) => {
return (
<div
className={cn(
'flex w-full flex-1 justify-center overflow-hidden',
'opacity-0 transition-opacity duration-300',
show && 'opacity-100!'
)}>
<AnimatePresence initial={!isCompletedStream}>
<motion.div
className={cn('bg-text-tertiary w-[0.5px]', 'mt-1 overflow-hidden')}
initial={{ height: 0 }}
animate={{ height: 'auto' }}
transition={{
duration: 0.3,
ease: 'easeInOut'
}}
/>
</AnimatePresence>
</div>
);
}
);
VerticalBar.displayName = 'VerticalBar';
const TitleContainer: React.FC<{
title: string;

View File

@ -1,14 +1,17 @@
import React from 'react';
import { Text } from '@/components/ui/typography';
export const AIWarning = React.memo(() => {
return (
<div className="w-full truncate overflow-hidden text-center">
<Text size="xs" variant="tertiary" truncate>
Our AI may make mistakes. Check important info.
</Text>
</div>
);
});
export const AIWarning = React.memo(
() => {
return (
<div className="w-full truncate overflow-hidden text-center">
<Text size="xs" variant="tertiary" truncate>
Our AI may make mistakes. Check important info.
</Text>
</div>
);
},
() => true
);
AIWarning.displayName = 'AIWarning';

View File

@ -18,7 +18,7 @@ export const ChatInput: React.FC<{}> = React.memo(({}) => {
return !inputHasText(inputValue);
}, [inputValue]);
const { onSubmitPreflight } = useChatInputFlow({
const { onSubmitPreflight, onStopChat } = useChatInputFlow({
disableSubmit,
inputValue,
setInputValue,
@ -30,10 +30,6 @@ export const ChatInput: React.FC<{}> = React.memo(({}) => {
setInputValue(e.target.value);
});
const onStop = useMemoizedFn(() => {
// setInputValue('');
});
return (
<div
className={cn(
@ -45,7 +41,7 @@ export const ChatInput: React.FC<{}> = React.memo(({}) => {
autoResize={autoResizeConfig}
onSubmit={onSubmitPreflight}
onChange={onChange}
onStop={onStop}
onStop={onStopChat}
loading={loading}
disabledSubmit={disableSubmit}
autoFocus

View File

@ -25,7 +25,7 @@ export const useChatInputFlow = ({
const onStartNewChat = useBusterNewChatContextSelector((state) => state.onStartNewChat);
const onFollowUpChat = useBusterNewChatContextSelector((state) => state.onFollowUpChat);
const onStartChatFromFile = useBusterNewChatContextSelector((state) => state.onStartChatFromFile);
const onStopChat = useBusterNewChatContextSelector((state) => state.onStopChat);
const onStopChatContext = useBusterNewChatContextSelector((state) => state.onStopChat);
const currentMessageId = useChatIndividualContextSelector((x) => x.currentMessageId);
const flow: FlowType = useMemo(() => {
@ -39,7 +39,7 @@ export const useChatInputFlow = ({
if (disableSubmit || !chatId || !currentMessageId) return;
if (loading) {
onStopChat({ chatId: chatId!, messageId: currentMessageId });
onStopChat();
return;
}
@ -79,5 +79,11 @@ export const useChatInputFlow = ({
}, 50);
});
return { onSubmitPreflight };
const onStopChat = useMemoizedFn(() => {
onStopChatContext({ chatId: chatId!, messageId: currentMessageId });
textAreaRef.current?.focus();
textAreaRef.current?.select();
});
return { onSubmitPreflight, onStopChat };
};

View File

@ -3,7 +3,9 @@ import { createContext, useContextSelector } from 'use-context-selector';
import type { SelectedFile } from '../interfaces';
import { useAutoChangeLayout } from './useAutoChangeLayout';
import { useGetChat } from '@/api/buster_rest/chats';
import { useMessageIndividual } from '@/context/Chats';
import { useQueries } from '@tanstack/react-query';
import { queryKeys } from '@/api/query_keys';
import { IBusterChatMessage } from '@/api/asset_interfaces/chat';
const useChatIndividualContext = ({
chatId,
@ -28,7 +30,18 @@ const useChatIndividualContext = ({
//MESSAGES
const currentMessageId = chatMessageIds[chatMessageIds.length - 1];
const isStreamingMessage = useMessageIndividual(currentMessageId, (x) => !x?.isCompletedStream);
const isStreamingMessage = useQueries({
queries: chatMessageIds.map((messageId) => {
const queryKey = queryKeys.chatsMessages(messageId);
return {
...queryKey,
select: (data: IBusterChatMessage | undefined) => !data?.isCompletedStream,
enabled: false
};
}),
combine: (result) => result.some((res) => res.data)
});
useAutoChangeLayout({
lastMessageId: currentMessageId,