reasoning message update

This commit is contained in:
Nate Kelley 2025-03-05 23:11:41 -07:00
parent 0db64cd4a4
commit ee997a6c98
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
5 changed files with 25 additions and 73 deletions

View File

@ -35,7 +35,7 @@ const AvatarFallback = React.forwardRef<
<AvatarPrimitive.Fallback <AvatarPrimitive.Fallback
ref={ref} ref={ref}
className={cn( className={cn(
'bg-gray-light/60 text-background flex h-full w-full items-center justify-center rounded-full text-base', 'bg-gray-light/60 text-background flex h-full w-full items-center justify-center rounded-full text-xs',
className className
)} )}
{...props} {...props}

View File

@ -45,7 +45,7 @@ StreamingMessage_File.displayName = 'StreamingMessage_File';
const StreamHeader: React.FC<{ file_name: string; version_number: number }> = React.memo( const StreamHeader: React.FC<{ file_name: string; version_number: number }> = React.memo(
({ file_name, version_number }) => { ({ file_name, version_number }) => {
return ( return (
<div className="file-header bg-item-hover border-border flex h-8 w-full items-center space-x-1.5 overflow-hidden border-b px-2.5"> <div className="file-header bg-item-select border-border flex h-8 w-full items-center space-x-1.5 overflow-hidden border-b px-2.5">
<Text truncate>{file_name}</Text> <Text truncate>{file_name}</Text>
<VersionPill version_number={version_number} /> <VersionPill version_number={version_number} />
</div> </div>

View File

@ -182,7 +182,6 @@ export const useChatStreamMessage = () => {
draft[chat_id]?.messages?.[message_id]?.response_messages?.[responseMessageId]; draft[chat_id]?.messages?.[message_id]?.response_messages?.[responseMessageId];
if (!responseMessage) return; if (!responseMessage) return;
const messageText = responseMessage as BusterChatMessageReasoning_text; const messageText = responseMessage as BusterChatMessageReasoning_text;
Object.assign(messageText, { Object.assign(messageText, {
...existingResponseMessageText, ...existingResponseMessageText,
...response_message, ...response_message,

View File

@ -20,13 +20,19 @@ export const ChatResponseMessages: React.FC<ChatResponseMessagesProps> = React.m
messageId, messageId,
(x) => x?.reasoning_message_ids?.[x.reasoning_message_ids.length - 1] (x) => x?.reasoning_message_ids?.[x.reasoning_message_ids.length - 1]
); );
const finalReasoningMessage = useMessageIndividual(
const lastMessageIndex = responseMessageIds.length - 1; messageId,
const showDefaultMessage = responseMessageIds.length === 0; (x) => x?.final_reasoning_message
);
return ( return (
<MessageContainer className="flex w-full flex-col overflow-hidden"> <MessageContainer className="flex w-full flex-col space-y-3 overflow-hidden">
{showDefaultMessage && <DefaultFirstMessage />} <ChatResponseReasoning
reasoningMessageId={lastReasoningMessageId}
finalReasoningMessage={finalReasoningMessage}
isCompletedStream={isCompletedStream}
messageId={messageId}
/>
{responseMessageIds.map((responseMessageId, index) => ( {responseMessageIds.map((responseMessageId, index) => (
<React.Fragment key={responseMessageId}> <React.Fragment key={responseMessageId}>
@ -35,14 +41,6 @@ export const ChatResponseMessages: React.FC<ChatResponseMessagesProps> = React.m
messageId={messageId} messageId={messageId}
isCompletedStream={isCompletedStream} isCompletedStream={isCompletedStream}
/> />
{index === lastMessageIndex && lastReasoningMessageId && (
<ChatResponseReasoning
reasoningMessageId={lastReasoningMessageId}
isCompletedStream={isCompletedStream}
messageId={messageId}
/>
)}
</React.Fragment> </React.Fragment>
))} ))}
</MessageContainer> </MessageContainer>
@ -51,11 +49,3 @@ export const ChatResponseMessages: React.FC<ChatResponseMessagesProps> = React.m
); );
ChatResponseMessages.displayName = 'ChatResponseMessages'; ChatResponseMessages.displayName = 'ChatResponseMessages';
const DefaultFirstMessage: React.FC = () => {
return (
<div>
<ShimmerText text="Thinking..." />
</div>
);
};

View File

@ -3,11 +3,9 @@ import { ShimmerText } from '@/components/ui/typography/ShimmerText';
import { useMemoizedFn } from 'ahooks'; import { useMemoizedFn } from 'ahooks';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { AnimatePresence } from 'framer-motion'; import { AnimatePresence } from 'framer-motion';
import { Stars } from '@/components/ui/icons';
import { Text } from '@/components/ui/typography'; import { Text } from '@/components/ui/typography';
import { useChatLayoutContextSelector } from '../../../ChatLayoutContext'; import { useChatLayoutContextSelector } from '../../../ChatLayoutContext';
import { useMessageIndividual } from '@/context/Chats'; import { useMessageIndividual } from '@/context/Chats';
import { cn } from '@/lib/classMerge';
const animations = { const animations = {
initial: { opacity: 0 }, initial: { opacity: 0 },
@ -16,21 +14,23 @@ const animations = {
}; };
export const ChatResponseReasoning: React.FC<{ export const ChatResponseReasoning: React.FC<{
reasoningMessageId: string; reasoningMessageId: string | undefined;
finalReasoningMessage: string | undefined | null;
isCompletedStream: boolean; isCompletedStream: boolean;
messageId: string; messageId: string;
}> = React.memo(({ reasoningMessageId, isCompletedStream, messageId }) => { }> = React.memo(({ reasoningMessageId, isCompletedStream, messageId }) => {
const lastMessageTitle = useMessageIndividual( const lastMessageTitle = useMessageIndividual(
messageId, messageId,
(x) => x?.reasoning_messages?.[reasoningMessageId]?.title (x) => x?.reasoning_messages?.[reasoningMessageId ?? '']?.title
); );
const finalReasoningMessage = useMessageIndividual(messageId, (x) => x?.final_reasoning_message); const finalReasoningMessage = useMessageIndividual(messageId, (x) => x?.final_reasoning_message);
const onSetSelectedFile = useChatLayoutContextSelector((x) => x.onSetSelectedFile); const onSetSelectedFile = useChatLayoutContextSelector((x) => x.onSetSelectedFile);
const selectedFileType = useChatLayoutContextSelector((x) => x.selectedFileType); const selectedFileType = useChatLayoutContextSelector((x) => x.selectedFileType);
const isReasonginFileSelected = selectedFileType === 'reasoning'; const isReasonginFileSelected = selectedFileType === 'reasoning' && isCompletedStream;
const text: string = useMemo(() => { const text: string = useMemo(() => {
if (finalReasoningMessage) return finalReasoningMessage; if (finalReasoningMessage) return finalReasoningMessage;
if (lastMessageTitle) return lastMessageTitle;
return lastMessageTitle || 'Thinking...'; return lastMessageTitle || 'Thinking...';
}, [lastMessageTitle, finalReasoningMessage]); }, [lastMessageTitle, finalReasoningMessage]);
@ -41,56 +41,19 @@ export const ChatResponseReasoning: React.FC<{
}); });
}); });
console.log(isReasonginFileSelected, isCompletedStream);
return ( return (
<AnimatePresence initial={!isCompletedStream} mode="wait"> <AnimatePresence initial={!isCompletedStream} mode="wait">
<motion.div {...animations} key={text} className="mb-3.5 w-fit" onClick={onClickReasoning}> <motion.div {...animations} key={text} className="mb-3.5 w-fit" onClick={onClickReasoning}>
<ShimmerTextWithIcon {isReasonginFileSelected ? (
text={text ?? ''} <Text className="cursor-pointer hover:underline">{text}</Text>
isCompletedStream={isCompletedStream} ) : (
isSelected={isReasonginFileSelected} <ShimmerText text={text ?? ''} />
/> )}
</motion.div> </motion.div>
</AnimatePresence> </AnimatePresence>
); );
}); });
ChatResponseReasoning.displayName = 'ChatThoughts'; ChatResponseReasoning.displayName = 'ChatThoughts';
const ShimmerTextWithIcon = React.memo(
({
text,
isCompletedStream,
isSelected
}: {
text: string;
isCompletedStream: boolean;
isSelected: boolean;
}) => {
if (isCompletedStream) {
return (
<div
className={cn(
'text-icon-color hover:text-foreground',
'cursor-pointer',
'flex w-fit items-center gap-1',
isSelected && 'text-foreground'
)}>
<div>
<Stars />
</div>
<Text variant="inherit">{text}</Text>
</div>
);
}
return (
<div className={'text-icon-color flex cursor-pointer items-center gap-1'}>
<div className={'text-icon-color'}>
<Stars />
</div>
<ShimmerText text={text} />
</div>
);
}
);
ShimmerTextWithIcon.displayName = 'ShimmerTextWithIcon';