change how mode is passed through

This commit is contained in:
Nate Kelley 2025-10-01 10:03:41 -06:00
parent 9e793787ef
commit afe0c68e84
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
11 changed files with 46 additions and 46 deletions

View File

@ -1,4 +1,3 @@
import type { ChatCreateRequest } from '@buster/server-shared/chats';
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import type { BusterChatMessage } from '@/api/asset_interfaces/chat'; import type { BusterChatMessage } from '@/api/asset_interfaces/chat';
import { chatQueryKeys } from '@/api/query_keys/chat'; import { chatQueryKeys } from '@/api/query_keys/chat';
@ -19,11 +18,7 @@ export const useStartNewChat = () => {
}; };
return useMutation({ return useMutation({
mutationFn: async (props: ChatCreateRequest) => { mutationFn: createNewChat,
// I opted to not use honoInstance to take better advantage of turbo caching
// const res = await honoInstance.api.v2.chats.$post({ json: props });
return await createNewChat(props);
},
onSuccess: (data) => { onSuccess: (data) => {
const { iChat, iChatMessages } = updateChatToIChat(data); const { iChat, iChatMessages } = updateChatToIChat(data);
saveAllChatMessages(iChatMessages); saveAllChatMessages(iChatMessages);

View File

@ -4,7 +4,7 @@ import type {
GetChatsListResponseV2, GetChatsListResponseV2,
GetChatsRequestV2, GetChatsRequestV2,
} from '@buster/server-shared/chats'; } from '@buster/server-shared/chats';
import mainApi, { mainApiV2 } from '../instances'; import { mainApiV2 } from '../instances';
export const getListChats = async ( export const getListChats = async (
params?: GetChatsRequestV2 params?: GetChatsRequestV2

View File

@ -1,3 +1,4 @@
import type { MessageAnalysisMode } from '@buster/server-shared/chats';
import type { ListShortcutsResponse } from '@buster/server-shared/shortcuts'; import type { ListShortcutsResponse } from '@buster/server-shared/shortcuts';
import type { GetSuggestedPromptsResponse } from '@buster/server-shared/user'; import type { GetSuggestedPromptsResponse } from '@buster/server-shared/user';
import React, { useMemo, useRef, useState } from 'react'; import React, { useMemo, useRef, useState } from 'react';
@ -17,7 +18,7 @@ import { MentionInputSuggestions } from '@/components/ui/inputs/MentionInputSugg
import { useMemoizedFn } from '@/hooks/useMemoizedFn'; import { useMemoizedFn } from '@/hooks/useMemoizedFn';
import { useMount } from '@/hooks/useMount'; import { useMount } from '@/hooks/useMount';
import { NewShortcutModal } from '../../modals/NewShortcutModal'; import { NewShortcutModal } from '../../modals/NewShortcutModal';
import { BusterChatInputButtons, type BusterChatInputMode } from './BusterChatInputButtons'; import { BusterChatInputButtons } from './BusterChatInputButtons';
import { useUniqueSuggestions } from './useUniqueSuggestions'; import { useUniqueSuggestions } from './useUniqueSuggestions';
export type BusterChatInputProps = { export type BusterChatInputProps = {
@ -26,7 +27,7 @@ export type BusterChatInputProps = {
transformedValue: string; transformedValue: string;
arrayValue: MentionArrayItem[]; arrayValue: MentionArrayItem[];
editorText: string; editorText: string;
mode: BusterChatInputMode; mode: MessageAnalysisMode;
}) => void; }) => void;
onStop: () => void; onStop: () => void;
submitting: boolean; submitting: boolean;
@ -50,7 +51,7 @@ export const BusterChatInputBase: React.FC<BusterChatInputProps> = React.memo(
const mentionInputSuggestionsRef = useRef<MentionInputSuggestionsRef>(null); const mentionInputSuggestionsRef = useRef<MentionInputSuggestionsRef>(null);
const uniqueSuggestions = useUniqueSuggestions(suggestedPrompts); const uniqueSuggestions = useUniqueSuggestions(suggestedPrompts);
const [openCreateShortcutModal, setOpenCreateShortcutModal] = useState(false); const [openCreateShortcutModal, setOpenCreateShortcutModal] = useState(false);
const [mode, setMode] = useState<BusterChatInputMode>('auto'); const [mode, setMode] = useState<MessageAnalysisMode>('auto');
const shortcutsSuggestions = useShortcutsSuggestions( const shortcutsSuggestions = useShortcutsSuggestions(
shortcuts, shortcuts,

View File

@ -1,3 +1,4 @@
import type { MessageAnalysisMode } from '@buster/server-shared/chats';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { Button } from '@/components/ui/buttons'; import { Button } from '@/components/ui/buttons';
import { ArrowUp, Magnifier, Sparkle2 } from '@/components/ui/icons'; import { ArrowUp, Magnifier, Sparkle2 } from '@/components/ui/icons';
@ -16,15 +17,13 @@ import { Text } from '@/components/ui/typography';
import { useSpeechRecognition } from '@/hooks/useSpeechRecognition'; import { useSpeechRecognition } from '@/hooks/useSpeechRecognition';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
export type BusterChatInputMode = 'auto' | 'research' | 'deep-research';
type BusterChatInputButtons = { type BusterChatInputButtons = {
onSubmit: MentionOnChangeFn; onSubmit: MentionOnChangeFn;
onStop: () => void; onStop: () => void;
submitting: boolean; submitting: boolean;
disabled: boolean; disabled: boolean;
mode: BusterChatInputMode; mode: MessageAnalysisMode;
onModeChange: (mode: BusterChatInputMode) => void; onModeChange: (mode: MessageAnalysisMode) => void;
onDictate?: (transcript: string) => void; onDictate?: (transcript: string) => void;
onDictateListeningChange?: (listening: boolean) => void; onDictateListeningChange?: (listening: boolean) => void;
}; };
@ -191,7 +190,7 @@ const ModePopoverContent = ({
); );
}; };
const modesOptions: AppSegmentedProps<BusterChatInputMode>['options'] = [ const modesOptions: AppSegmentedProps<MessageAnalysisMode>['options'] = [
{ {
icon: ( icon: (
<ModePopoverContent <ModePopoverContent
@ -218,7 +217,7 @@ const modesOptions: AppSegmentedProps<BusterChatInputMode>['options'] = [
<Magnifier /> <Magnifier />
</ModePopoverContent> </ModePopoverContent>
), ),
value: 'research' as const, value: 'standard' as const,
}, },
{ {
icon: ( icon: (
@ -232,6 +231,6 @@ const modesOptions: AppSegmentedProps<BusterChatInputMode>['options'] = [
<Atom /> <Atom />
</ModePopoverContent> </ModePopoverContent>
), ),
value: 'deep-research' as const, value: 'investigation' as const,
}, },
]; ];

View File

@ -1,4 +1,4 @@
import type { ChatCreateRequest } from '@buster/server-shared/chats'; import type { ChatCreateRequest, MessageAnalysisMode } from '@buster/server-shared/chats';
import { useNavigate } from '@tanstack/react-router'; import { useNavigate } from '@tanstack/react-router';
import { create } from 'mutative'; import { create } from 'mutative';
import type { FileType } from '@/api/asset_interfaces/chat'; import type { FileType } from '@/api/asset_interfaces/chat';
@ -14,16 +14,7 @@ type StartChatParams = {
dashboardId?: string; //this is to start a NEW chat from a dashboard dashboardId?: string; //this is to start a NEW chat from a dashboard
messageId?: string; //this is used to replace a message in the chat messageId?: string; //this is used to replace a message in the chat
chatId?: string; //this is used to follow up a chat chatId?: string; //this is used to follow up a chat
mode?: 'auto' | 'research' | 'deep-research'; //ui modes mode: MessageAnalysisMode; //ui modes
};
const chatModeToServerRecord: Record<
NonNullable<StartChatParams['mode']>,
NonNullable<ChatCreateRequest['message_analysis_mode']>
> = {
auto: 'auto',
research: 'standard',
'deep-research': 'investigation',
}; };
export const useChat = () => { export const useChat = () => {
@ -40,7 +31,7 @@ export const useChat = () => {
metricId, metricId,
dashboardId, dashboardId,
messageId, messageId,
mode = 'auto', mode,
}: StartChatParams) => { }: StartChatParams) => {
const res = await startNewChat({ const res = await startNewChat({
prompt, prompt,
@ -48,7 +39,7 @@ export const useChat = () => {
metric_id: metricId, metric_id: metricId,
dashboard_id: dashboardId, dashboard_id: dashboardId,
message_id: messageId, message_id: messageId,
message_analysis_mode: chatModeToServerRecord[mode] || 'auto', message_analysis_mode: mode,
}); });
const { message_ids, id } = res; const { message_ids, id } = res;
@ -63,11 +54,8 @@ export const useChat = () => {
}; };
const onStartNewChat = useMemoizedFn( const onStartNewChat = useMemoizedFn(
async ({ prompt, mode }: { prompt: string; mode: StartChatParams['mode'] }) => { async (d: { prompt: string; mode: StartChatParams['mode'] }) => {
return startChat({ return startChat(d);
prompt,
mode,
});
} }
); );
@ -76,24 +64,32 @@ export const useChat = () => {
prompt, prompt,
fileId, fileId,
fileType, fileType,
mode = 'auto',
}: { }: {
prompt: string; prompt: string;
fileId: string; fileId: string;
fileType: FileType; fileType: FileType;
mode?: StartChatParams['mode'];
}) => { }) => {
return startChat({ return startChat({
prompt, prompt,
metricId: fileType === 'metric_file' ? fileId : undefined, metricId: fileType === 'metric_file' ? fileId : undefined,
dashboardId: fileType === 'dashboard_file' ? fileId : undefined, dashboardId: fileType === 'dashboard_file' ? fileId : undefined,
mode,
}); });
} }
); );
const onFollowUpChat = useMemoizedFn( const onFollowUpChat = useMemoizedFn(
async ({ prompt, chatId }: Pick<NonNullable<StartChatParams>, 'prompt' | 'chatId'>) => { async ({
prompt,
chatId,
mode = 'auto',
}: Pick<NonNullable<StartChatParams>, 'prompt' | 'chatId' | 'mode'>) => {
return startChat({ return startChat({
prompt, prompt,
chatId, chatId,
mode,
}); });
} }
); );
@ -107,10 +103,12 @@ export const useChat = () => {
prompt, prompt,
messageId, messageId,
chatId, chatId,
mode = 'auto',
}: { }: {
prompt: string; prompt: string;
messageId: string; messageId: string;
chatId: string; chatId: string;
mode?: StartChatParams['mode'];
}) => { }) => {
const currentChat = getChatMemoized(chatId); const currentChat = getChatMemoized(chatId);
const currentMessage = getChatMessageMemoized(messageId); const currentMessage = getChatMessageMemoized(messageId);
@ -141,6 +139,7 @@ export const useChat = () => {
return startChat({ return startChat({
prompt, prompt,
messageId, messageId,
mode,
}); });
} }
); );

View File

@ -1,3 +1,4 @@
import type { MessageAnalysisMode } from '@buster/server-shared/chats';
import type React from 'react'; import type React from 'react';
import { useMemo, useRef } from 'react'; import { useMemo, useRef } from 'react';
import { useBusterNotifications } from '@/context/BusterNotifications'; import { useBusterNotifications } from '@/context/BusterNotifications';
@ -11,18 +12,20 @@ import { useGetCurrentMessageId } from './useGetActiveChat';
import { useGetChatId } from './useGetChatId'; import { useGetChatId } from './useGetChatId';
import { useIsChatMode, useIsFileMode } from './useMode'; import { useIsChatMode, useIsFileMode } from './useMode';
export const useChatInputFlow = ({ export const useFollowUpChatInputFlow = ({
disableSubmit, disableSubmit,
inputValue, inputValue,
setInputValue, setInputValue,
textAreaRef, textAreaRef,
loading, loading,
mode,
}: { }: {
disableSubmit: boolean; disableSubmit: boolean;
inputValue: string; inputValue: string;
setInputValue: (value: string) => void; setInputValue: (value: string) => void;
textAreaRef: React.RefObject<HTMLTextAreaElement | null>; textAreaRef: React.RefObject<HTMLTextAreaElement | null>;
loading: boolean; loading: boolean;
mode: MessageAnalysisMode;
}) => { }) => {
const isChatMode = useIsChatMode(); const isChatMode = useIsChatMode();
const isFileMode = useIsFileMode(); const isFileMode = useIsFileMode();
@ -58,7 +61,7 @@ export const useChatInputFlow = ({
submittingCooldown.current = true; submittingCooldown.current = true;
if (isChatMode || selectedAssetType === 'chat') { if (isChatMode || selectedAssetType === 'chat') {
await onFollowUpChat({ prompt: trimmedInputValue, chatId }); await onFollowUpChat({ prompt: trimmedInputValue, chatId, mode });
} else if (selectedAssetType === 'collection') { } else if (selectedAssetType === 'collection') {
// maybe we will support this one day. Good day that'll be. Until then, we will just dream. // maybe we will support this one day. Good day that'll be. Until then, we will just dream.
console.warn('collection mode is not supported yet'); console.warn('collection mode is not supported yet');
@ -70,7 +73,7 @@ export const useChatInputFlow = ({
fileType: selectedAssetType, fileType: selectedAssetType,
}); });
} else { } else {
await onStartNewChat({ prompt: trimmedInputValue, mode: 'auto' }); await onStartNewChat({ prompt: trimmedInputValue, mode });
} }
setInputValue(''); setInputValue('');

View File

@ -7,8 +7,8 @@ import { useAutoScroll } from '@/hooks/useAutoScroll';
import { useMount } from '@/hooks/useMount'; import { useMount } from '@/hooks/useMount';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { CHAT_CONTAINER_ID } from '../ChatContainer'; import { CHAT_CONTAINER_ID } from '../ChatContainer';
import { ChatInput } from './ChatInput';
import { ChatMessageBlock } from './ChatMessageBlock'; import { ChatMessageBlock } from './ChatMessageBlock';
import { FollowUpChatInput } from './FollowupChatInput';
const autoClass = 'mx-auto max-w-[600px] w-full'; const autoClass = 'mx-auto max-w-[600px] w-full';
@ -77,7 +77,7 @@ const ChatInputWrapper: React.FC<{
<div className="bg-page-background absolute bottom-0 w-full overflow-visible"> <div className="bg-page-background absolute bottom-0 w-full overflow-visible">
<div className="from-page-background pointer-events-none absolute -top-16 h-16 w-full bg-gradient-to-t to-transparent" /> <div className="from-page-background pointer-events-none absolute -top-16 h-16 w-full bg-gradient-to-t to-transparent" />
<div className={cn(autoClass, 'relative')}> <div className={cn(autoClass, 'relative')}>
<ChatInput /> <FollowUpChatInput />
{children} {children}
</div> </div>
</div> </div>

View File

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

View File

@ -1,16 +1,17 @@
import type { MessageAnalysisMode } from '@buster/server-shared/chats';
import React, { type ChangeEvent, useEffect, useMemo, useRef, useState } from 'react'; import React, { type ChangeEvent, useEffect, useMemo, useRef, useState } from 'react';
import { InputTextAreaButton } from '@/components/ui/inputs/InputTextAreaButton'; import { InputTextAreaButton } from '@/components/ui/inputs/InputTextAreaButton';
import { Text } from '@/components/ui/typography'; import { Text } from '@/components/ui/typography';
import { useChatPermission, useIsStreamingMessage } from '@/context/Chats'; import { useChatPermission, useIsStreamingMessage } from '@/context/Chats';
import { useFollowUpChatInputFlow } from '@/context/Chats/useFollowUpChatInputFlow';
import { useGetChatId } from '@/context/Chats/useGetChatId'; import { useGetChatId } from '@/context/Chats/useGetChatId';
import { useIsChatMode } from '@/context/Chats/useMode'; import { useIsChatMode } from '@/context/Chats/useMode';
import { cn } from '@/lib/classMerge'; import { cn } from '@/lib/classMerge';
import { canEdit } from '@/lib/share'; import { canEdit } from '@/lib/share';
import { inputHasText } from '@/lib/text'; import { inputHasText } from '@/lib/text';
import { useChatInputFlow } from '../../../../context/Chats/useChatInputFlow';
import { AIWarning } from './AIWarning'; import { AIWarning } from './AIWarning';
export const ChatInput: React.FC = React.memo(() => { export const FollowUpChatInput: React.FC = React.memo(() => {
const textAreaRef = useRef<HTMLTextAreaElement>(null); const textAreaRef = useRef<HTMLTextAreaElement>(null);
const isStreamingMessage = useIsStreamingMessage(); const isStreamingMessage = useIsStreamingMessage();
const hasChat = useIsChatMode(); const hasChat = useIsChatMode();
@ -19,17 +20,19 @@ export const ChatInput: React.FC = React.memo(() => {
const canEditChat = canEdit(permission); const canEditChat = canEdit(permission);
const [inputValue, setInputValue] = useState(''); const [inputValue, setInputValue] = useState('');
const [mode, setMode] = useState<MessageAnalysisMode>('auto');
const disableSubmit = useMemo(() => { const disableSubmit = useMemo(() => {
return (!inputHasText(inputValue) && !isStreamingMessage) || !canEditChat; return (!inputHasText(inputValue) && !isStreamingMessage) || !canEditChat;
}, [inputValue, isStreamingMessage, canEditChat]); }, [inputValue, isStreamingMessage, canEditChat]);
const { onSubmitPreflight, onStopChat } = useChatInputFlow({ const { onSubmitPreflight, onStopChat } = useFollowUpChatInputFlow({
disableSubmit, disableSubmit,
inputValue, inputValue,
setInputValue, setInputValue,
loading: isStreamingMessage, loading: isStreamingMessage,
textAreaRef, textAreaRef,
mode,
}); });
const onChange = (e: ChangeEvent<HTMLTextAreaElement>) => { const onChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
@ -81,4 +84,4 @@ export const ChatInput: React.FC = React.memo(() => {
); );
}); });
ChatInput.displayName = 'ChatInput'; FollowUpChatInput.displayName = 'FollowUpChatInput';

View File

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