refactor: replace isLoading with status (#861)
This commit is contained in:
parent
8e561dced4
commit
553a3d825a
10 changed files with 72 additions and 109 deletions
|
|
@ -1,29 +1,26 @@
|
||||||
import { PreviewMessage } from './message';
|
import { PreviewMessage } from './message';
|
||||||
import { useScrollToBottom } from './use-scroll-to-bottom';
|
import { useScrollToBottom } from './use-scroll-to-bottom';
|
||||||
import { Vote } from '@/lib/db/schema';
|
import { Vote } from '@/lib/db/schema';
|
||||||
import { ChatRequestOptions, Message } from 'ai';
|
import { Message } from 'ai';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import equal from 'fast-deep-equal';
|
import equal from 'fast-deep-equal';
|
||||||
import { UIArtifact } from './artifact';
|
import { UIArtifact } from './artifact';
|
||||||
|
import { UseChatHelpers } from '@ai-sdk/react';
|
||||||
|
|
||||||
interface ArtifactMessagesProps {
|
interface ArtifactMessagesProps {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
isLoading: boolean;
|
status: UseChatHelpers['status'];
|
||||||
votes: Array<Vote> | undefined;
|
votes: Array<Vote> | undefined;
|
||||||
messages: Array<Message>;
|
messages: Array<Message>;
|
||||||
setMessages: (
|
setMessages: UseChatHelpers['setMessages'];
|
||||||
messages: Message[] | ((messages: Message[]) => Message[]),
|
reload: UseChatHelpers['reload'];
|
||||||
) => void;
|
|
||||||
reload: (
|
|
||||||
chatRequestOptions?: ChatRequestOptions,
|
|
||||||
) => Promise<string | null | undefined>;
|
|
||||||
isReadonly: boolean;
|
isReadonly: boolean;
|
||||||
artifactStatus: UIArtifact['status'];
|
artifactStatus: UIArtifact['status'];
|
||||||
}
|
}
|
||||||
|
|
||||||
function PureArtifactMessages({
|
function PureArtifactMessages({
|
||||||
chatId,
|
chatId,
|
||||||
isLoading,
|
status,
|
||||||
votes,
|
votes,
|
||||||
messages,
|
messages,
|
||||||
setMessages,
|
setMessages,
|
||||||
|
|
@ -43,8 +40,7 @@ function PureArtifactMessages({
|
||||||
chatId={chatId}
|
chatId={chatId}
|
||||||
key={message.id}
|
key={message.id}
|
||||||
message={message}
|
message={message}
|
||||||
isLoading={isLoading && index === messages.length - 1}
|
isLoading={status === 'streaming' && index === messages.length - 1}
|
||||||
index={index}
|
|
||||||
vote={
|
vote={
|
||||||
votes
|
votes
|
||||||
? votes.find((vote) => vote.messageId === message.id)
|
? votes.find((vote) => vote.messageId === message.id)
|
||||||
|
|
@ -74,8 +70,8 @@ function areEqual(
|
||||||
)
|
)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (prevProps.isLoading !== nextProps.isLoading) return false;
|
if (prevProps.status !== nextProps.status) return false;
|
||||||
if (prevProps.isLoading && nextProps.isLoading) return false;
|
if (prevProps.status && nextProps.status) return false;
|
||||||
if (prevProps.messages.length !== nextProps.messages.length) return false;
|
if (prevProps.messages.length !== nextProps.messages.length) return false;
|
||||||
if (!equal(prevProps.votes, nextProps.votes)) return false;
|
if (!equal(prevProps.votes, nextProps.votes)) return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,4 @@
|
||||||
import type {
|
import type { Attachment, Message } from 'ai';
|
||||||
Attachment,
|
|
||||||
ChatRequestOptions,
|
|
||||||
CreateMessage,
|
|
||||||
Message,
|
|
||||||
} from 'ai';
|
|
||||||
import { formatDistance } from 'date-fns';
|
import { formatDistance } from 'date-fns';
|
||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import {
|
import {
|
||||||
|
|
@ -31,6 +26,7 @@ import { codeArtifact } from '@/artifacts/code/client';
|
||||||
import { sheetArtifact } from '@/artifacts/sheet/client';
|
import { sheetArtifact } from '@/artifacts/sheet/client';
|
||||||
import { textArtifact } from '@/artifacts/text/client';
|
import { textArtifact } from '@/artifacts/text/client';
|
||||||
import equal from 'fast-deep-equal';
|
import equal from 'fast-deep-equal';
|
||||||
|
import { UseChatHelpers } from '@ai-sdk/react';
|
||||||
|
|
||||||
export const artifactDefinitions = [
|
export const artifactDefinitions = [
|
||||||
textArtifact,
|
textArtifact,
|
||||||
|
|
@ -60,7 +56,7 @@ function PureArtifact({
|
||||||
input,
|
input,
|
||||||
setInput,
|
setInput,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
isLoading,
|
status,
|
||||||
stop,
|
stop,
|
||||||
attachments,
|
attachments,
|
||||||
setAttachments,
|
setAttachments,
|
||||||
|
|
@ -73,27 +69,17 @@ function PureArtifact({
|
||||||
}: {
|
}: {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
input: string;
|
input: string;
|
||||||
setInput: (input: string) => void;
|
setInput: UseChatHelpers['setInput'];
|
||||||
isLoading: boolean;
|
status: UseChatHelpers['status'];
|
||||||
stop: () => void;
|
stop: UseChatHelpers['stop'];
|
||||||
attachments: Array<Attachment>;
|
attachments: Array<Attachment>;
|
||||||
setAttachments: Dispatch<SetStateAction<Array<Attachment>>>;
|
setAttachments: Dispatch<SetStateAction<Array<Attachment>>>;
|
||||||
messages: Array<Message>;
|
messages: Array<Message>;
|
||||||
setMessages: Dispatch<SetStateAction<Array<Message>>>;
|
setMessages: Dispatch<SetStateAction<Array<Message>>>;
|
||||||
votes: Array<Vote> | undefined;
|
votes: Array<Vote> | undefined;
|
||||||
append: (
|
append: UseChatHelpers['append'];
|
||||||
message: Message | CreateMessage,
|
handleSubmit: UseChatHelpers['handleSubmit'];
|
||||||
chatRequestOptions?: ChatRequestOptions,
|
reload: UseChatHelpers['reload'];
|
||||||
) => Promise<string | null | undefined>;
|
|
||||||
handleSubmit: (
|
|
||||||
event?: {
|
|
||||||
preventDefault?: () => void;
|
|
||||||
},
|
|
||||||
chatRequestOptions?: ChatRequestOptions,
|
|
||||||
) => void;
|
|
||||||
reload: (
|
|
||||||
chatRequestOptions?: ChatRequestOptions,
|
|
||||||
) => Promise<string | null | undefined>;
|
|
||||||
isReadonly: boolean;
|
isReadonly: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { artifact, setArtifact, metadata, setMetadata } = useArtifact();
|
const { artifact, setArtifact, metadata, setMetadata } = useArtifact();
|
||||||
|
|
@ -326,7 +312,7 @@ function PureArtifact({
|
||||||
<div className="flex flex-col h-full justify-between items-center gap-4">
|
<div className="flex flex-col h-full justify-between items-center gap-4">
|
||||||
<ArtifactMessages
|
<ArtifactMessages
|
||||||
chatId={chatId}
|
chatId={chatId}
|
||||||
isLoading={isLoading}
|
status={status}
|
||||||
votes={votes}
|
votes={votes}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
setMessages={setMessages}
|
setMessages={setMessages}
|
||||||
|
|
@ -341,7 +327,7 @@ function PureArtifact({
|
||||||
input={input}
|
input={input}
|
||||||
setInput={setInput}
|
setInput={setInput}
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
isLoading={isLoading}
|
status={status}
|
||||||
stop={stop}
|
stop={stop}
|
||||||
attachments={attachments}
|
attachments={attachments}
|
||||||
setAttachments={setAttachments}
|
setAttachments={setAttachments}
|
||||||
|
|
@ -487,7 +473,7 @@ function PureArtifact({
|
||||||
isToolbarVisible={isToolbarVisible}
|
isToolbarVisible={isToolbarVisible}
|
||||||
setIsToolbarVisible={setIsToolbarVisible}
|
setIsToolbarVisible={setIsToolbarVisible}
|
||||||
append={append}
|
append={append}
|
||||||
isLoading={isLoading}
|
status={status}
|
||||||
stop={stop}
|
stop={stop}
|
||||||
setMessages={setMessages}
|
setMessages={setMessages}
|
||||||
artifactKind={artifact.kind}
|
artifactKind={artifact.kind}
|
||||||
|
|
@ -513,7 +499,7 @@ function PureArtifact({
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Artifact = memo(PureArtifact, (prevProps, nextProps) => {
|
export const Artifact = memo(PureArtifact, (prevProps, nextProps) => {
|
||||||
if (prevProps.isLoading !== nextProps.isLoading) return false;
|
if (prevProps.status !== nextProps.status) return false;
|
||||||
if (!equal(prevProps.votes, nextProps.votes)) return false;
|
if (!equal(prevProps.votes, nextProps.votes)) return false;
|
||||||
if (prevProps.input !== nextProps.input) return false;
|
if (prevProps.input !== nextProps.input) return false;
|
||||||
if (!equal(prevProps.messages, nextProps.messages.length)) return false;
|
if (!equal(prevProps.messages, nextProps.messages.length)) return false;
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export function Chat({
|
||||||
input,
|
input,
|
||||||
setInput,
|
setInput,
|
||||||
append,
|
append,
|
||||||
isLoading,
|
status,
|
||||||
stop,
|
stop,
|
||||||
reload,
|
reload,
|
||||||
} = useChat({
|
} = useChat({
|
||||||
|
|
@ -74,7 +74,7 @@ export function Chat({
|
||||||
|
|
||||||
<Messages
|
<Messages
|
||||||
chatId={id}
|
chatId={id}
|
||||||
isLoading={isLoading}
|
status={status}
|
||||||
votes={votes}
|
votes={votes}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
setMessages={setMessages}
|
setMessages={setMessages}
|
||||||
|
|
@ -90,7 +90,7 @@ export function Chat({
|
||||||
input={input}
|
input={input}
|
||||||
setInput={setInput}
|
setInput={setInput}
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
isLoading={isLoading}
|
status={status}
|
||||||
stop={stop}
|
stop={stop}
|
||||||
attachments={attachments}
|
attachments={attachments}
|
||||||
setAttachments={setAttachments}
|
setAttachments={setAttachments}
|
||||||
|
|
@ -107,7 +107,7 @@ export function Chat({
|
||||||
input={input}
|
input={input}
|
||||||
setInput={setInput}
|
setInput={setInput}
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
isLoading={isLoading}
|
status={status}
|
||||||
stop={stop}
|
stop={stop}
|
||||||
attachments={attachments}
|
attachments={attachments}
|
||||||
setAttachments={setAttachments}
|
setAttachments={setAttachments}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ const PurePreviewMessage = ({
|
||||||
setMessages,
|
setMessages,
|
||||||
reload,
|
reload,
|
||||||
isReadonly,
|
isReadonly,
|
||||||
index,
|
|
||||||
}: {
|
}: {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
message: Message;
|
message: Message;
|
||||||
|
|
@ -40,7 +39,6 @@ const PurePreviewMessage = ({
|
||||||
chatRequestOptions?: ChatRequestOptions,
|
chatRequestOptions?: ChatRequestOptions,
|
||||||
) => Promise<string | null | undefined>;
|
) => Promise<string | null | undefined>;
|
||||||
isReadonly: boolean;
|
isReadonly: boolean;
|
||||||
index: number;
|
|
||||||
}) => {
|
}) => {
|
||||||
const [mode, setMode] = useState<'view' | 'edit'>('view');
|
const [mode, setMode] = useState<'view' | 'edit'>('view');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,26 @@
|
||||||
import { ChatRequestOptions, Message } from 'ai';
|
import { Message } from 'ai';
|
||||||
import { PreviewMessage, ThinkingMessage } from './message';
|
import { PreviewMessage, ThinkingMessage } from './message';
|
||||||
import { useScrollToBottom } from './use-scroll-to-bottom';
|
import { useScrollToBottom } from './use-scroll-to-bottom';
|
||||||
import { Overview } from './overview';
|
import { Overview } from './overview';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { Vote } from '@/lib/db/schema';
|
import { Vote } from '@/lib/db/schema';
|
||||||
import equal from 'fast-deep-equal';
|
import equal from 'fast-deep-equal';
|
||||||
|
import { UseChatHelpers } from '@ai-sdk/react';
|
||||||
|
|
||||||
interface MessagesProps {
|
interface MessagesProps {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
isLoading: boolean;
|
status: UseChatHelpers['status'];
|
||||||
votes: Array<Vote> | undefined;
|
votes: Array<Vote> | undefined;
|
||||||
messages: Array<Message>;
|
messages: Array<Message>;
|
||||||
setMessages: (
|
setMessages: UseChatHelpers['setMessages'];
|
||||||
messages: Message[] | ((messages: Message[]) => Message[]),
|
reload: UseChatHelpers['reload'];
|
||||||
) => void;
|
|
||||||
reload: (
|
|
||||||
chatRequestOptions?: ChatRequestOptions,
|
|
||||||
) => Promise<string | null | undefined>;
|
|
||||||
isReadonly: boolean;
|
isReadonly: boolean;
|
||||||
isArtifactVisible: boolean;
|
isArtifactVisible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function PureMessages({
|
function PureMessages({
|
||||||
chatId,
|
chatId,
|
||||||
isLoading,
|
status,
|
||||||
votes,
|
votes,
|
||||||
messages,
|
messages,
|
||||||
setMessages,
|
setMessages,
|
||||||
|
|
@ -43,10 +40,9 @@ function PureMessages({
|
||||||
{messages.map((message, index) => (
|
{messages.map((message, index) => (
|
||||||
<PreviewMessage
|
<PreviewMessage
|
||||||
key={message.id}
|
key={message.id}
|
||||||
index={index}
|
|
||||||
chatId={chatId}
|
chatId={chatId}
|
||||||
message={message}
|
message={message}
|
||||||
isLoading={isLoading && messages.length - 1 === index}
|
isLoading={status === 'streaming' && messages.length - 1 === index}
|
||||||
vote={
|
vote={
|
||||||
votes
|
votes
|
||||||
? votes.find((vote) => vote.messageId === message.id)
|
? votes.find((vote) => vote.messageId === message.id)
|
||||||
|
|
@ -58,7 +54,7 @@ function PureMessages({
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{isLoading &&
|
{status === 'submitted' &&
|
||||||
messages.length > 0 &&
|
messages.length > 0 &&
|
||||||
messages[messages.length - 1].role === 'user' && <ThinkingMessage />}
|
messages[messages.length - 1].role === 'user' && <ThinkingMessage />}
|
||||||
|
|
||||||
|
|
@ -73,8 +69,8 @@ function PureMessages({
|
||||||
export const Messages = memo(PureMessages, (prevProps, nextProps) => {
|
export const Messages = memo(PureMessages, (prevProps, nextProps) => {
|
||||||
if (prevProps.isArtifactVisible && nextProps.isArtifactVisible) return true;
|
if (prevProps.isArtifactVisible && nextProps.isArtifactVisible) return true;
|
||||||
|
|
||||||
if (prevProps.isLoading !== nextProps.isLoading) return false;
|
if (prevProps.status !== nextProps.status) return false;
|
||||||
if (prevProps.isLoading && nextProps.isLoading) return false;
|
if (prevProps.status && nextProps.status) return false;
|
||||||
if (prevProps.messages.length !== nextProps.messages.length) return false;
|
if (prevProps.messages.length !== nextProps.messages.length) return false;
|
||||||
if (!equal(prevProps.messages, nextProps.messages)) return false;
|
if (!equal(prevProps.messages, nextProps.messages)) return false;
|
||||||
if (!equal(prevProps.votes, nextProps.votes)) return false;
|
if (!equal(prevProps.votes, nextProps.votes)) return false;
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,13 @@ import { Button } from './ui/button';
|
||||||
import { Textarea } from './ui/textarea';
|
import { Textarea } from './ui/textarea';
|
||||||
import { SuggestedActions } from './suggested-actions';
|
import { SuggestedActions } from './suggested-actions';
|
||||||
import equal from 'fast-deep-equal';
|
import equal from 'fast-deep-equal';
|
||||||
|
import { UseChatHelpers, UseChatOptions } from '@ai-sdk/react';
|
||||||
|
|
||||||
function PureMultimodalInput({
|
function PureMultimodalInput({
|
||||||
chatId,
|
chatId,
|
||||||
input,
|
input,
|
||||||
setInput,
|
setInput,
|
||||||
isLoading,
|
status,
|
||||||
stop,
|
stop,
|
||||||
attachments,
|
attachments,
|
||||||
setAttachments,
|
setAttachments,
|
||||||
|
|
@ -45,24 +46,16 @@ function PureMultimodalInput({
|
||||||
className,
|
className,
|
||||||
}: {
|
}: {
|
||||||
chatId: string;
|
chatId: string;
|
||||||
input: string;
|
input: UseChatHelpers['input'];
|
||||||
setInput: (value: string) => void;
|
setInput: UseChatHelpers['setInput'];
|
||||||
isLoading: boolean;
|
status: UseChatHelpers['status'];
|
||||||
stop: () => void;
|
stop: () => void;
|
||||||
attachments: Array<Attachment>;
|
attachments: Array<Attachment>;
|
||||||
setAttachments: Dispatch<SetStateAction<Array<Attachment>>>;
|
setAttachments: Dispatch<SetStateAction<Array<Attachment>>>;
|
||||||
messages: Array<Message>;
|
messages: Array<Message>;
|
||||||
setMessages: Dispatch<SetStateAction<Array<Message>>>;
|
setMessages: Dispatch<SetStateAction<Array<Message>>>;
|
||||||
append: (
|
append: UseChatHelpers['append'];
|
||||||
message: Message | CreateMessage,
|
handleSubmit: UseChatHelpers['handleSubmit'];
|
||||||
chatRequestOptions?: ChatRequestOptions,
|
|
||||||
) => Promise<string | null | undefined>;
|
|
||||||
handleSubmit: (
|
|
||||||
event?: {
|
|
||||||
preventDefault?: () => void;
|
|
||||||
},
|
|
||||||
chatRequestOptions?: ChatRequestOptions,
|
|
||||||
) => void;
|
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
|
@ -253,7 +246,7 @@ function PureMultimodalInput({
|
||||||
) {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (isLoading) {
|
if (status !== 'ready') {
|
||||||
toast.error('Please wait for the model to finish its response!');
|
toast.error('Please wait for the model to finish its response!');
|
||||||
} else {
|
} else {
|
||||||
submitForm();
|
submitForm();
|
||||||
|
|
@ -263,11 +256,11 @@ function PureMultimodalInput({
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="absolute bottom-0 p-2 w-fit flex flex-row justify-start">
|
<div className="absolute bottom-0 p-2 w-fit flex flex-row justify-start">
|
||||||
<AttachmentsButton fileInputRef={fileInputRef} isLoading={isLoading} />
|
<AttachmentsButton fileInputRef={fileInputRef} status={status} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="absolute bottom-0 right-0 p-2 w-fit flex flex-row justify-end">
|
<div className="absolute bottom-0 right-0 p-2 w-fit flex flex-row justify-end">
|
||||||
{isLoading ? (
|
{status === 'submitted' ? (
|
||||||
<StopButton stop={stop} setMessages={setMessages} />
|
<StopButton stop={stop} setMessages={setMessages} />
|
||||||
) : (
|
) : (
|
||||||
<SendButton
|
<SendButton
|
||||||
|
|
@ -285,7 +278,7 @@ export const MultimodalInput = memo(
|
||||||
PureMultimodalInput,
|
PureMultimodalInput,
|
||||||
(prevProps, nextProps) => {
|
(prevProps, nextProps) => {
|
||||||
if (prevProps.input !== nextProps.input) return false;
|
if (prevProps.input !== nextProps.input) return false;
|
||||||
if (prevProps.isLoading !== nextProps.isLoading) return false;
|
if (prevProps.status !== nextProps.status) return false;
|
||||||
if (!equal(prevProps.attachments, nextProps.attachments)) return false;
|
if (!equal(prevProps.attachments, nextProps.attachments)) return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -294,10 +287,10 @@ export const MultimodalInput = memo(
|
||||||
|
|
||||||
function PureAttachmentsButton({
|
function PureAttachmentsButton({
|
||||||
fileInputRef,
|
fileInputRef,
|
||||||
isLoading,
|
status,
|
||||||
}: {
|
}: {
|
||||||
fileInputRef: React.MutableRefObject<HTMLInputElement | null>;
|
fileInputRef: React.MutableRefObject<HTMLInputElement | null>;
|
||||||
isLoading: boolean;
|
status: UseChatHelpers['status'];
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -307,7 +300,7 @@ function PureAttachmentsButton({
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
fileInputRef.current?.click();
|
fileInputRef.current?.click();
|
||||||
}}
|
}}
|
||||||
disabled={isLoading}
|
disabled={status !== 'ready'}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
>
|
>
|
||||||
<PaperclipIcon size={14} />
|
<PaperclipIcon size={14} />
|
||||||
|
|
|
||||||
|
|
@ -319,19 +319,16 @@ const PureToolbar = ({
|
||||||
isToolbarVisible,
|
isToolbarVisible,
|
||||||
setIsToolbarVisible,
|
setIsToolbarVisible,
|
||||||
append,
|
append,
|
||||||
isLoading,
|
status,
|
||||||
stop,
|
stop,
|
||||||
setMessages,
|
setMessages,
|
||||||
artifactKind,
|
artifactKind,
|
||||||
}: {
|
}: {
|
||||||
isToolbarVisible: boolean;
|
isToolbarVisible: boolean;
|
||||||
setIsToolbarVisible: Dispatch<SetStateAction<boolean>>;
|
setIsToolbarVisible: Dispatch<SetStateAction<boolean>>;
|
||||||
isLoading: boolean;
|
status: UseChatHelpers['status'];
|
||||||
append: (
|
append: UseChatHelpers['append'];
|
||||||
message: Message | CreateMessage,
|
stop: UseChatHelpers['stop'];
|
||||||
chatRequestOptions?: ChatRequestOptions,
|
|
||||||
) => Promise<string | null | undefined>;
|
|
||||||
stop: () => void;
|
|
||||||
setMessages: Dispatch<SetStateAction<Message[]>>;
|
setMessages: Dispatch<SetStateAction<Message[]>>;
|
||||||
artifactKind: ArtifactKind;
|
artifactKind: ArtifactKind;
|
||||||
}) => {
|
}) => {
|
||||||
|
|
@ -372,10 +369,10 @@ const PureToolbar = ({
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isLoading) {
|
if (status === 'streaming') {
|
||||||
setIsToolbarVisible(false);
|
setIsToolbarVisible(false);
|
||||||
}
|
}
|
||||||
}, [isLoading, setIsToolbarVisible]);
|
}, [status, setIsToolbarVisible]);
|
||||||
|
|
||||||
const artifactDefinition = artifactDefinitions.find(
|
const artifactDefinition = artifactDefinitions.find(
|
||||||
(definition) => definition.kind === artifactKind,
|
(definition) => definition.kind === artifactKind,
|
||||||
|
|
@ -418,13 +415,13 @@ const PureToolbar = ({
|
||||||
exit={{ opacity: 0, y: -20, transition: { duration: 0.1 } }}
|
exit={{ opacity: 0, y: -20, transition: { duration: 0.1 } }}
|
||||||
transition={{ type: 'spring', stiffness: 300, damping: 25 }}
|
transition={{ type: 'spring', stiffness: 300, damping: 25 }}
|
||||||
onHoverStart={() => {
|
onHoverStart={() => {
|
||||||
if (isLoading) return;
|
if (status === 'streaming') return;
|
||||||
|
|
||||||
cancelCloseTimer();
|
cancelCloseTimer();
|
||||||
setIsToolbarVisible(true);
|
setIsToolbarVisible(true);
|
||||||
}}
|
}}
|
||||||
onHoverEnd={() => {
|
onHoverEnd={() => {
|
||||||
if (isLoading) return;
|
if (status === 'streaming') return;
|
||||||
|
|
||||||
startCloseTimer();
|
startCloseTimer();
|
||||||
}}
|
}}
|
||||||
|
|
@ -436,7 +433,7 @@ const PureToolbar = ({
|
||||||
}}
|
}}
|
||||||
ref={toolbarRef}
|
ref={toolbarRef}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{status === 'streaming' ? (
|
||||||
<motion.div
|
<motion.div
|
||||||
key="stop-icon"
|
key="stop-icon"
|
||||||
initial={{ scale: 1 }}
|
initial={{ scale: 1 }}
|
||||||
|
|
@ -475,7 +472,7 @@ const PureToolbar = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Toolbar = memo(PureToolbar, (prevProps, nextProps) => {
|
export const Toolbar = memo(PureToolbar, (prevProps, nextProps) => {
|
||||||
if (prevProps.isLoading !== nextProps.isLoading) return false;
|
if (prevProps.status !== nextProps.status) return false;
|
||||||
if (prevProps.isToolbarVisible !== nextProps.isToolbarVisible) return false;
|
if (prevProps.isToolbarVisible !== nextProps.isToolbarVisible) return false;
|
||||||
if (prevProps.artifactKind !== nextProps.artifactKind) return false;
|
if (prevProps.artifactKind !== nextProps.artifactKind) return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ export const chatModel = new MockLanguageModelV1({
|
||||||
}),
|
}),
|
||||||
doStream: async ({ prompt }) => ({
|
doStream: async ({ prompt }) => ({
|
||||||
stream: simulateReadableStream({
|
stream: simulateReadableStream({
|
||||||
|
chunkDelayInMs: 50,
|
||||||
|
initialDelayInMs: 100,
|
||||||
chunks: getResponseChunksByPrompt(prompt),
|
chunks: getResponseChunksByPrompt(prompt),
|
||||||
}),
|
}),
|
||||||
rawCall: { rawPrompt: null, rawSettings: {} },
|
rawCall: { rawPrompt: null, rawSettings: {} },
|
||||||
|
|
@ -26,6 +28,8 @@ export const reasoningModel = new MockLanguageModelV1({
|
||||||
}),
|
}),
|
||||||
doStream: async ({ prompt }) => ({
|
doStream: async ({ prompt }) => ({
|
||||||
stream: simulateReadableStream({
|
stream: simulateReadableStream({
|
||||||
|
chunkDelayInMs: 50,
|
||||||
|
initialDelayInMs: 500,
|
||||||
chunks: getResponseChunksByPrompt(prompt, true),
|
chunks: getResponseChunksByPrompt(prompt, true),
|
||||||
}),
|
}),
|
||||||
rawCall: { rawPrompt: null, rawSettings: {} },
|
rawCall: { rawPrompt: null, rawSettings: {} },
|
||||||
|
|
@ -41,6 +45,8 @@ export const titleModel = new MockLanguageModelV1({
|
||||||
}),
|
}),
|
||||||
doStream: async () => ({
|
doStream: async () => ({
|
||||||
stream: simulateReadableStream({
|
stream: simulateReadableStream({
|
||||||
|
chunkDelayInMs: 50,
|
||||||
|
initialDelayInMs: 100,
|
||||||
chunks: [
|
chunks: [
|
||||||
{ type: 'text-delta', textDelta: 'This is a test title' },
|
{ type: 'text-delta', textDelta: 'This is a test title' },
|
||||||
{
|
{
|
||||||
|
|
@ -64,6 +70,8 @@ export const artifactModel = new MockLanguageModelV1({
|
||||||
}),
|
}),
|
||||||
doStream: async ({ prompt }) => ({
|
doStream: async ({ prompt }) => ({
|
||||||
stream: simulateReadableStream({
|
stream: simulateReadableStream({
|
||||||
|
chunkDelayInMs: 50,
|
||||||
|
initialDelayInMs: 100,
|
||||||
chunks: getResponseChunksByPrompt(prompt),
|
chunks: getResponseChunksByPrompt(prompt),
|
||||||
}),
|
}),
|
||||||
rawCall: { rawPrompt: null, rawSettings: {} },
|
rawCall: { rawPrompt: null, rawSettings: {} },
|
||||||
|
|
|
||||||
|
|
@ -179,15 +179,4 @@ export class ChatPage {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async waitForMessageGeneration(timeout = 10000) {
|
|
||||||
await this.page.waitForFunction(
|
|
||||||
() => {
|
|
||||||
return document.querySelector('[data-testid="send-button"]') !== null;
|
|
||||||
},
|
|
||||||
{ timeout },
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.page.waitForTimeout(500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ test.describe('chat activity with reasoning', () => {
|
||||||
|
|
||||||
test('send user message and generate response with reasoning', async () => {
|
test('send user message and generate response with reasoning', async () => {
|
||||||
await chatPage.sendUserMessage('Why is the sky blue?');
|
await chatPage.sendUserMessage('Why is the sky blue?');
|
||||||
await chatPage.waitForMessageGeneration();
|
await chatPage.isGenerationComplete();
|
||||||
|
|
||||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||||
expect(assistantMessage.content).toBe("It's just blue duh!");
|
expect(assistantMessage.content).toBe("It's just blue duh!");
|
||||||
|
|
@ -23,7 +23,7 @@ test.describe('chat activity with reasoning', () => {
|
||||||
|
|
||||||
test('toggle reasoning visibility', async () => {
|
test('toggle reasoning visibility', async () => {
|
||||||
await chatPage.sendUserMessage('Why is the sky blue?');
|
await chatPage.sendUserMessage('Why is the sky blue?');
|
||||||
await chatPage.waitForMessageGeneration();
|
await chatPage.isGenerationComplete();
|
||||||
|
|
||||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||||
const reasoningElement =
|
const reasoningElement =
|
||||||
|
|
@ -39,7 +39,7 @@ test.describe('chat activity with reasoning', () => {
|
||||||
|
|
||||||
test('edit message and resubmit', async () => {
|
test('edit message and resubmit', async () => {
|
||||||
await chatPage.sendUserMessage('Why is the sky blue?');
|
await chatPage.sendUserMessage('Why is the sky blue?');
|
||||||
await chatPage.waitForMessageGeneration();
|
await chatPage.isGenerationComplete();
|
||||||
|
|
||||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||||
const reasoningElement =
|
const reasoningElement =
|
||||||
|
|
@ -49,7 +49,7 @@ test.describe('chat activity with reasoning', () => {
|
||||||
const userMessage = await chatPage.getRecentUserMessage();
|
const userMessage = await chatPage.getRecentUserMessage();
|
||||||
|
|
||||||
await userMessage.edit('Why is grass green?');
|
await userMessage.edit('Why is grass green?');
|
||||||
await chatPage.waitForMessageGeneration();
|
await chatPage.isGenerationComplete();
|
||||||
|
|
||||||
const updatedAssistantMessage = await chatPage.getRecentAssistantMessage();
|
const updatedAssistantMessage = await chatPage.getRecentAssistantMessage();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue