Skip to content

Commit be9cc7c

Browse files
committed
Merge remote-tracking branch 'upstream/main'
2 parents 9c26dc9 + 553a3d8 commit be9cc7c

23 files changed

+1048
-406
lines changed

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,4 @@ certificates
4343
/test-results/
4444
/playwright-report/
4545
/blob-report/
46-
/playwright/.cache/
47-
/playwright/.auth/
46+
/playwright/*

components/artifact-close-button.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ function PureArtifactCloseButton() {
88

99
return (
1010
<Button
11+
data-testid="artifact-close-button"
1112
variant="outline"
1213
className="h-fit p-2 dark:hover:bg-zinc-700"
1314
onClick={() => {

components/artifact-messages.tsx

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
import { PreviewMessage } from './message';
22
import { useScrollToBottom } from './use-scroll-to-bottom';
33
import { Vote } from '@/lib/db/schema';
4-
import { ChatRequestOptions, Message } from 'ai';
4+
import { Message } from 'ai';
55
import { memo } from 'react';
66
import equal from 'fast-deep-equal';
77
import { UIArtifact } from './artifact';
8+
import { UseChatHelpers } from '@ai-sdk/react';
89

910
interface ArtifactMessagesProps {
1011
chatId: string;
11-
isLoading: boolean;
12+
status: UseChatHelpers['status'];
1213
votes: Array<Vote> | undefined;
1314
messages: Array<Message>;
14-
setMessages: (
15-
messages: Message[] | ((messages: Message[]) => Message[]),
16-
) => void;
17-
reload: (
18-
chatRequestOptions?: ChatRequestOptions,
19-
) => Promise<string | null | undefined>;
15+
setMessages: UseChatHelpers['setMessages'];
16+
reload: UseChatHelpers['reload'];
2017
isReadonly: boolean;
2118
artifactStatus: UIArtifact['status'];
2219
}
2320

2421
function PureArtifactMessages({
2522
chatId,
26-
isLoading,
23+
status,
2724
votes,
2825
messages,
2926
setMessages,
@@ -43,8 +40,7 @@ function PureArtifactMessages({
4340
chatId={chatId}
4441
key={message.id}
4542
message={message}
46-
isLoading={isLoading && index === messages.length - 1}
47-
index={index}
43+
isLoading={status === 'streaming' && index === messages.length - 1}
4844
vote={
4945
votes
5046
? votes.find((vote) => vote.messageId === message.id)
@@ -74,8 +70,8 @@ function areEqual(
7470
)
7571
return true;
7672

77-
if (prevProps.isLoading !== nextProps.isLoading) return false;
78-
if (prevProps.isLoading && nextProps.isLoading) return false;
73+
if (prevProps.status !== nextProps.status) return false;
74+
if (prevProps.status && nextProps.status) return false;
7975
if (prevProps.messages.length !== nextProps.messages.length) return false;
8076
if (!equal(prevProps.votes, nextProps.votes)) return false;
8177

components/artifact.tsx

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
import type {
2-
Attachment,
3-
ChatRequestOptions,
4-
CreateMessage,
5-
Message,
6-
} from 'ai';
1+
import type { Attachment, Message } from 'ai';
72
import { formatDistance } from 'date-fns';
83
import { AnimatePresence, motion } from 'framer-motion';
94
import {
@@ -31,6 +26,7 @@ import { codeArtifact } from '@/artifacts/code/client';
3126
import { sheetArtifact } from '@/artifacts/sheet/client';
3227
import { textArtifact } from '@/artifacts/text/client';
3328
import equal from 'fast-deep-equal';
29+
import { UseChatHelpers } from '@ai-sdk/react';
3430

3531
export const artifactDefinitions = [
3632
textArtifact,
@@ -60,7 +56,7 @@ function PureArtifact({
6056
input,
6157
setInput,
6258
handleSubmit,
63-
isLoading,
59+
status,
6460
stop,
6561
attachments,
6662
setAttachments,
@@ -73,27 +69,17 @@ function PureArtifact({
7369
}: {
7470
chatId: string;
7571
input: string;
76-
setInput: (input: string) => void;
77-
isLoading: boolean;
78-
stop: () => void;
72+
setInput: UseChatHelpers['setInput'];
73+
status: UseChatHelpers['status'];
74+
stop: UseChatHelpers['stop'];
7975
attachments: Array<Attachment>;
8076
setAttachments: Dispatch<SetStateAction<Array<Attachment>>>;
8177
messages: Array<Message>;
8278
setMessages: Dispatch<SetStateAction<Array<Message>>>;
8379
votes: Array<Vote> | undefined;
84-
append: (
85-
message: Message | CreateMessage,
86-
chatRequestOptions?: ChatRequestOptions,
87-
) => Promise<string | null | undefined>;
88-
handleSubmit: (
89-
event?: {
90-
preventDefault?: () => void;
91-
},
92-
chatRequestOptions?: ChatRequestOptions,
93-
) => void;
94-
reload: (
95-
chatRequestOptions?: ChatRequestOptions,
96-
) => Promise<string | null | undefined>;
80+
append: UseChatHelpers['append'];
81+
handleSubmit: UseChatHelpers['handleSubmit'];
82+
reload: UseChatHelpers['reload'];
9783
isReadonly: boolean;
9884
}) {
9985
const { artifact, setArtifact, metadata, setMetadata } = useArtifact();
@@ -269,6 +255,7 @@ function PureArtifact({
269255
<AnimatePresence>
270256
{artifact.isVisible && (
271257
<motion.div
258+
data-testid="artifact"
272259
className="flex flex-row h-dvh w-dvw fixed top-0 left-0 z-50 bg-transparent"
273260
initial={{ opacity: 1 }}
274261
animate={{ opacity: 1 }}
@@ -325,7 +312,7 @@ function PureArtifact({
325312
<div className="flex flex-col h-full justify-between items-center gap-4">
326313
<ArtifactMessages
327314
chatId={chatId}
328-
isLoading={isLoading}
315+
status={status}
329316
votes={votes}
330317
messages={messages}
331318
setMessages={setMessages}
@@ -340,7 +327,7 @@ function PureArtifact({
340327
input={input}
341328
setInput={setInput}
342329
handleSubmit={handleSubmit}
343-
isLoading={isLoading}
330+
status={status}
344331
stop={stop}
345332
attachments={attachments}
346333
setAttachments={setAttachments}
@@ -486,7 +473,7 @@ function PureArtifact({
486473
isToolbarVisible={isToolbarVisible}
487474
setIsToolbarVisible={setIsToolbarVisible}
488475
append={append}
489-
isLoading={isLoading}
476+
status={status}
490477
stop={stop}
491478
setMessages={setMessages}
492479
artifactKind={artifact.kind}
@@ -512,7 +499,7 @@ function PureArtifact({
512499
}
513500

514501
export const Artifact = memo(PureArtifact, (prevProps, nextProps) => {
515-
if (prevProps.isLoading !== nextProps.isLoading) return false;
502+
if (prevProps.status !== nextProps.status) return false;
516503
if (!equal(prevProps.votes, nextProps.votes)) return false;
517504
if (prevProps.input !== nextProps.input) return false;
518505
if (!equal(prevProps.messages, nextProps.messages.length)) return false;

components/chat.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export function Chat({
3636
input,
3737
setInput,
3838
append,
39-
isLoading,
39+
status,
4040
stop,
4141
reload,
4242
} = useChat({
@@ -74,7 +74,7 @@ export function Chat({
7474

7575
<Messages
7676
chatId={id}
77-
isLoading={isLoading}
77+
status={status}
7878
votes={votes}
7979
messages={messages}
8080
setMessages={setMessages}
@@ -90,7 +90,7 @@ export function Chat({
9090
input={input}
9191
setInput={setInput}
9292
handleSubmit={handleSubmit}
93-
isLoading={isLoading}
93+
status={status}
9494
stop={stop}
9595
attachments={attachments}
9696
setAttachments={setAttachments}
@@ -107,7 +107,7 @@ export function Chat({
107107
input={input}
108108
setInput={setInput}
109109
handleSubmit={handleSubmit}
110-
isLoading={isLoading}
110+
status={status}
111111
stop={stop}
112112
attachments={attachments}
113113
setAttachments={setAttachments}

components/message-actions.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { Message } from 'ai';
2-
import { toast } from 'sonner';
32
import { useSWRConfig } from 'swr';
43
import { useCopyToClipboard } from 'usehooks-ts';
54

@@ -15,6 +14,7 @@ import {
1514
} from './ui/tooltip';
1615
import { memo } from 'react';
1716
import equal from 'fast-deep-equal';
17+
import { toast } from 'sonner';
1818

1919
export function PureMessageActions({
2020
chatId,
@@ -57,6 +57,7 @@ export function PureMessageActions({
5757
<Tooltip>
5858
<TooltipTrigger asChild>
5959
<Button
60+
data-testid="message-upvote"
6061
className="py-1 px-2 h-fit text-muted-foreground !pointer-events-auto"
6162
disabled={vote?.isUpvoted}
6263
variant="outline"
@@ -109,6 +110,7 @@ export function PureMessageActions({
109110
<Tooltip>
110111
<TooltipTrigger asChild>
111112
<Button
113+
data-testid="message-downvote"
112114
className="py-1 px-2 h-fit text-muted-foreground !pointer-events-auto"
113115
variant="outline"
114116
disabled={vote && !vote.isUpvoted}

components/message-reasoning.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export function MessageReasoning({
4444
<div className="flex flex-row gap-2 items-center">
4545
<div className="font-medium">Reasoned for a few seconds</div>
4646
<button
47+
data-testid="message-reasoning-toggle"
4748
type="button"
4849
className="cursor-pointer"
4950
onClick={() => {
@@ -58,6 +59,7 @@ export function MessageReasoning({
5859
<AnimatePresence initial={false}>
5960
{isExpanded && (
6061
<motion.div
62+
data-testid="message-reasoning"
6163
key="content"
6264
initial="collapsed"
6365
animate="expanded"

components/message.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ const PurePreviewMessage = ({
2727
setMessages,
2828
reload,
2929
isReadonly,
30-
index,
3130
}: {
3231
chatId: string;
3332
message: Message;
@@ -40,14 +39,13 @@ const PurePreviewMessage = ({
4039
chatRequestOptions?: ChatRequestOptions,
4140
) => Promise<string | null | undefined>;
4241
isReadonly: boolean;
43-
index: number;
4442
}) => {
4543
const [mode, setMode] = useState<'view' | 'edit'>('view');
4644

4745
return (
4846
<AnimatePresence>
4947
<motion.div
50-
data-testid={`message-${message.role}-${index}`}
48+
data-testid={`message-${message.role}`}
5149
className="w-full mx-auto max-w-3xl px-4 group/message"
5250
initial={{ y: 5, opacity: 0 }}
5351
animate={{ y: 0, opacity: 1 }}
@@ -73,7 +71,7 @@ const PurePreviewMessage = ({
7371
<div className="flex flex-col gap-4 w-full">
7472
{message.experimental_attachments && (
7573
<div
76-
data-testid={`message-attachments-${index}`}
74+
data-testid={`message-attachments`}
7775
className="flex flex-row justify-end gap-2"
7876
>
7977
{message.experimental_attachments.map((attachment) => (
@@ -93,12 +91,15 @@ const PurePreviewMessage = ({
9391
)}
9492

9593
{(message.content || message.reasoning) && mode === 'view' && (
96-
<div className="flex flex-row gap-2 items-start">
94+
<div
95+
data-testid="message-content"
96+
className="flex flex-row gap-2 items-start"
97+
>
9798
{message.role === 'user' && !isReadonly && (
9899
<Tooltip>
99100
<TooltipTrigger asChild>
100101
<Button
101-
data-testid={`edit-${message.role}-${index}`}
102+
data-testid={`message-edit`}
102103
variant="ghost"
103104
className="px-2 h-fit rounded-full text-muted-foreground opacity-0 group-hover/message:opacity-100"
104105
onClick={() => {
@@ -243,6 +244,7 @@ export const ThinkingMessage = () => {
243244

244245
return (
245246
<motion.div
247+
data-testid="message-assistant-loading"
246248
className="w-full mx-auto max-w-3xl px-4 group/message "
247249
initial={{ y: 5, opacity: 0 }}
248250
animate={{ y: 0, opacity: 1, transition: { delay: 1 } }}

components/messages.tsx

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
1-
import type { ChatRequestOptions, Message } from 'ai';
1+
import { Message } from 'ai';
22
import { PreviewMessage, ThinkingMessage } from './message';
33
import { useScrollToBottom } from './use-scroll-to-bottom';
44
import { Overview } from './overview';
55
import { memo } from 'react';
66
import { Vote } from '@/lib/db/schema';
77
import equal from 'fast-deep-equal';
8+
import { UseChatHelpers } from '@ai-sdk/react';
89

910
interface MessagesProps {
1011
chatId: string;
11-
isLoading: boolean;
12+
status: UseChatHelpers['status'];
1213
votes: Array<Vote> | undefined;
1314
messages: Array<Message>;
14-
setMessages: (
15-
messages: Message[] | ((messages: Message[]) => Message[]),
16-
) => void;
17-
reload: (
18-
chatRequestOptions?: ChatRequestOptions,
19-
) => Promise<string | null | undefined>;
15+
setMessages: UseChatHelpers['setMessages'];
16+
reload: UseChatHelpers['reload'];
2017
isReadonly: boolean;
2118
isArtifactVisible: boolean;
2219
}
2320

2421
function PureMessages({
2522
chatId,
26-
isLoading,
23+
status,
2724
votes,
2825
messages,
2926
setMessages,
@@ -43,10 +40,9 @@ function PureMessages({
4340
{messages.map((message, index) => (
4441
<PreviewMessage
4542
key={message.id}
46-
index={index}
4743
chatId={chatId}
4844
message={message}
49-
isLoading={isLoading && messages.length - 1 === index}
45+
isLoading={status === 'streaming' && messages.length - 1 === index}
5046
vote={
5147
votes
5248
? votes.find((vote) => vote.messageId === message.id)
@@ -58,7 +54,7 @@ function PureMessages({
5854
/>
5955
))}
6056

61-
{isLoading &&
57+
{status === 'submitted' &&
6258
messages.length > 0 &&
6359
messages[messages.length - 1].role === 'user' && <ThinkingMessage />}
6460

@@ -73,8 +69,8 @@ function PureMessages({
7369
export const Messages = memo(PureMessages, (prevProps, nextProps) => {
7470
if (prevProps.isArtifactVisible && nextProps.isArtifactVisible) return true;
7571

76-
if (prevProps.isLoading !== nextProps.isLoading) return false;
77-
if (prevProps.isLoading && nextProps.isLoading) return false;
72+
if (prevProps.status !== nextProps.status) return false;
73+
if (prevProps.status && nextProps.status) return false;
7874
if (prevProps.messages.length !== nextProps.messages.length) return false;
7975
if (!equal(prevProps.messages, nextProps.messages)) return false;
8076
if (!equal(prevProps.votes, nextProps.votes)) return false;

0 commit comments

Comments
 (0)