mirror of https://github.com/buster-so/buster.git
change how mode is passed through
This commit is contained in:
parent
9e793787ef
commit
afe0c68e84
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -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('');
|
|
@ -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>
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './ChatInput';
|
|
|
@ -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';
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './FollowupChatInput';
|
Loading…
Reference in New Issue