Skip to content

Commit c4453d4

Browse files
feat: artifact refactor for v5 (#1071)
1 parent 93a907a commit c4453d4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1010
-1066
lines changed

app/(chat)/api/chat/route.ts

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ export async function POST(request: Request) {
120120
// @ts-expect-error type mismatch converting from DBMessage to UIMessage
121121
const messages: UIMessage[] = [...previousMessages, message];
122122

123-
const stream = createUIMessageStream({
123+
const stream = createUIMessageStream<ChatMessage>({
124+
generateId: generateUUID,
124125
execute: ({ writer: streamWriter }) => {
125126
const result = streamText({
126127
model: myProvider.languageModel(selectedChatModel),
@@ -141,33 +142,28 @@ export async function POST(request: Request) {
141142
isEnabled: isProductionEnvironment,
142143
functionId: 'stream-text',
143144
},
144-
_internal: {
145-
generateId: generateUUID,
146-
},
147145
});
148146

149147
result.consumeStream();
150148

151149
streamWriter.merge(
152150
result.toUIMessageStream<ChatMessage>({
153151
sendReasoning: true,
154-
onFinish: async ({ responseMessage }) => {
155-
await saveMessages({
156-
messages: [
157-
{
158-
id: responseMessage.id,
159-
role: 'assistant',
160-
parts: responseMessage.parts,
161-
createdAt: new Date(),
162-
attachments: [],
163-
chatId: id,
164-
},
165-
],
166-
});
167-
},
168152
}),
169153
);
170154
},
155+
onFinish: async ({ messages }) => {
156+
await saveMessages({
157+
messages: messages.map((message) => ({
158+
id: message.id,
159+
role: message.role,
160+
parts: message.parts,
161+
createdAt: new Date(),
162+
attachments: [],
163+
chatId: id,
164+
})),
165+
});
166+
},
171167
onError: () => {
172168
return 'Oops! Something went wrong, please try again later.';
173169
},

app/(chat)/api/document/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { auth } from '@/app/(auth)/auth';
2-
import type { ArtifactKind } from '@/components/artifact';
32
import {
43
deleteDocumentsByIdAfterTimestamp,
54
getDocumentsById,
65
saveDocument,
76
} from '@/lib/db/queries';
87
import { ChatSDKError } from '@/lib/errors';
8+
import type { DocumentKind } from '@/lib/types';
99

1010
export async function GET(request: Request) {
1111
const { searchParams } = new URL(request.url);
@@ -60,7 +60,7 @@ export async function POST(request: Request) {
6060
content,
6161
title,
6262
kind,
63-
}: { content: string; title: string; kind: ArtifactKind } =
63+
}: { content: string; title: string; kind: DocumentKind } =
6464
await request.json();
6565

6666
const documents = await getDocumentsById({ id });

app/(chat)/chat/[id]/page.tsx

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import { auth } from '@/app/(auth)/auth';
44
import { Chat } from '@/components/chat';
55
import { getChatById, getMessagesByChatId } from '@/lib/db/queries';
66
import { DEFAULT_CHAT_MODEL } from '@/lib/ai/models';
7-
import type { DBMessage } from '@/lib/db/schema';
87
import type { UIMessage } from 'ai';
98
import type { Attachment, ChatMessage } from '@/lib/types';
10-
import { DataStreamHandler } from '@/components/data-stream-handler';
9+
import type { Tables } from '@/lib/db/schema';
1110

1211
export default async function Page(props: { params: Promise<{ id: string }> }) {
1312
const params = await props.params;
@@ -38,7 +37,9 @@ export default async function Page(props: { params: Promise<{ id: string }> }) {
3837
id,
3938
});
4039

41-
function convertToUIMessages(messages: Array<DBMessage>): Array<ChatMessage> {
40+
function convertToUIMessages(
41+
messages: Array<Tables<'Message'>>,
42+
): Array<ChatMessage> {
4243
// @ts-expect-error todo: fix conversion of types
4344
return messages.map((message) => ({
4445
id: message.id,
@@ -59,33 +60,27 @@ export default async function Page(props: { params: Promise<{ id: string }> }) {
5960

6061
if (!chatModelFromCookie) {
6162
return (
62-
<>
63-
<Chat
64-
id={chat.id}
65-
initialMessages={initialMessages}
66-
initialChatModel={DEFAULT_CHAT_MODEL}
67-
initialVisibilityType={chat.visibility}
68-
isReadonly={session?.user?.id !== chat.userId}
69-
session={session}
70-
autoResume={true}
71-
/>
72-
<DataStreamHandler id={id} />
73-
</>
74-
);
75-
}
76-
77-
return (
78-
<>
7963
<Chat
8064
id={chat.id}
8165
initialMessages={initialMessages}
82-
initialChatModel={chatModelFromCookie.value}
66+
initialChatModel={DEFAULT_CHAT_MODEL}
8367
initialVisibilityType={chat.visibility}
8468
isReadonly={session?.user?.id !== chat.userId}
8569
session={session}
8670
autoResume={true}
8771
/>
88-
<DataStreamHandler id={id} />
89-
</>
72+
);
73+
}
74+
75+
return (
76+
<Chat
77+
id={chat.id}
78+
initialMessages={initialMessages}
79+
initialChatModel={chatModelFromCookie.value}
80+
initialVisibilityType={chat.visibility}
81+
isReadonly={session?.user?.id !== chat.userId}
82+
session={session}
83+
autoResume={true}
84+
/>
9085
);
9186
}

app/(chat)/page.tsx

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { DEFAULT_CHAT_MODEL } from '@/lib/ai/models';
44
import { generateUUID } from '@/lib/utils';
55
import { auth } from '../(auth)/auth';
66
import { redirect } from 'next/navigation';
7-
import { DataStreamHandler } from '@/components/data-stream-handler';
87

98
export default async function Page() {
109
const session = await auth();
@@ -20,35 +19,29 @@ export default async function Page() {
2019

2120
if (!modelIdFromCookie) {
2221
return (
23-
<>
24-
<Chat
25-
key={id}
26-
id={id}
27-
initialMessages={[]}
28-
initialChatModel={DEFAULT_CHAT_MODEL}
29-
initialVisibilityType="private"
30-
isReadonly={false}
31-
session={session}
32-
autoResume={false}
33-
/>
34-
<DataStreamHandler id={id} />
35-
</>
36-
);
37-
}
38-
39-
return (
40-
<>
4122
<Chat
4223
key={id}
4324
id={id}
4425
initialMessages={[]}
45-
initialChatModel={modelIdFromCookie.value}
26+
initialChatModel={DEFAULT_CHAT_MODEL}
4627
initialVisibilityType="private"
4728
isReadonly={false}
4829
session={session}
4930
autoResume={false}
5031
/>
51-
<DataStreamHandler id={id} />
52-
</>
32+
);
33+
}
34+
35+
return (
36+
<Chat
37+
key={id}
38+
id={id}
39+
initialMessages={[]}
40+
initialChatModel={modelIdFromCookie.value}
41+
initialVisibilityType="private"
42+
isReadonly={false}
43+
session={session}
44+
autoResume={false}
45+
/>
5346
);
5447
}

artifacts/code/client.tsx

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -75,21 +75,7 @@ export const codeArtifact = new Artifact<'code', Metadata>({
7575
outputs: [],
7676
});
7777
},
78-
onStreamPart: ({ streamPart, setArtifact }) => {
79-
if (streamPart.type === 'data-artifacts-code-delta') {
80-
setArtifact((draftArtifact) => ({
81-
...draftArtifact,
82-
content: streamPart.data as string,
83-
isVisible:
84-
draftArtifact.status === 'streaming' &&
85-
draftArtifact.content.length > 300 &&
86-
draftArtifact.content.length < 310
87-
? true
88-
: draftArtifact.isVisible,
89-
status: 'streaming',
90-
}));
91-
}
92-
},
78+
onStreamPart: () => {},
9379
content: ({ metadata, setMetadata, ...props }) => {
9480
return (
9581
<>

artifacts/code/server.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ export const codeDocumentHandler = createDocumentHandler<'code'>({
2727

2828
if (code) {
2929
streamWriter.write({
30-
type: 'data-artifacts-code-delta',
31-
data: code ?? '',
30+
type: 'data-document',
31+
data: {
32+
content: code,
33+
},
3234
});
3335

3436
draftContent = code;
@@ -59,8 +61,10 @@ export const codeDocumentHandler = createDocumentHandler<'code'>({
5961

6062
if (code) {
6163
streamWriter.write({
62-
type: 'data-artifacts-code-delta',
63-
data: code ?? '',
64+
type: 'data-document',
65+
data: {
66+
content: code,
67+
},
6468
});
6569

6670
draftContent = code;

artifacts/image/client.tsx

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,7 @@ import { toast } from 'sonner';
66
export const imageArtifact = new Artifact({
77
kind: 'image',
88
description: 'Useful for image generation',
9-
onStreamPart: ({ streamPart, setArtifact }) => {
10-
if (streamPart.type === 'data-artifacts-image-delta') {
11-
setArtifact((draftArtifact) => ({
12-
...draftArtifact,
13-
content: streamPart.data as string,
14-
isVisible: true,
15-
status: 'streaming',
16-
}));
17-
}
18-
},
9+
onStreamPart: () => {},
1910
content: ImageEditor,
2011
actions: [
2112
{

artifacts/image/server.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ export const imageDocumentHandler = createDocumentHandler<'image'>({
1616
draftContent = image.base64;
1717

1818
streamWriter.write({
19-
type: 'data-artifacts-image-delta',
20-
data: image.base64,
19+
type: 'data-document',
20+
data: {
21+
content: image.base64,
22+
},
2123
});
2224

2325
return draftContent;
@@ -34,8 +36,10 @@ export const imageDocumentHandler = createDocumentHandler<'image'>({
3436
draftContent = image.base64;
3537

3638
streamWriter.write({
37-
type: 'data-artifacts-image-delta',
38-
data: image.base64,
39+
type: 'data-document',
40+
data: {
41+
content: image.base64,
42+
},
3943
});
4044

4145
return draftContent;

artifacts/sheet/client.tsx

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,7 @@ export const sheetArtifact = new Artifact<'sheet', Metadata>({
1616
kind: 'sheet',
1717
description: 'Useful for working with spreadsheets',
1818
initialize: async () => {},
19-
onStreamPart: ({ setArtifact, streamPart }) => {
20-
if (streamPart.type === 'data-artifacts-sheet-delta') {
21-
setArtifact((draftArtifact) => ({
22-
...draftArtifact,
23-
content: streamPart.data as string,
24-
isVisible: true,
25-
status: 'streaming',
26-
}));
27-
}
28-
},
19+
onStreamPart: () => {},
2920
content: ({
3021
content,
3122
currentVersionIndex,

artifacts/sheet/server.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ export const sheetDocumentHandler = createDocumentHandler<'sheet'>({
2727

2828
if (csv) {
2929
streamWriter.write({
30-
type: 'data-artifacts-sheet-delta',
31-
data: csv,
30+
type: 'data-document',
31+
data: {
32+
content: csv,
33+
},
3234
});
3335

3436
draftContent = csv;
@@ -37,8 +39,10 @@ export const sheetDocumentHandler = createDocumentHandler<'sheet'>({
3739
}
3840

3941
streamWriter.write({
40-
type: 'data-artifacts-sheet-delta',
41-
data: draftContent,
42+
type: 'data-document',
43+
data: {
44+
content: draftContent,
45+
},
4246
});
4347

4448
return draftContent;
@@ -64,8 +68,10 @@ export const sheetDocumentHandler = createDocumentHandler<'sheet'>({
6468

6569
if (csv) {
6670
streamWriter.write({
67-
type: 'data-artifacts-sheet-delta',
68-
data: csv,
71+
type: 'data-document',
72+
data: {
73+
content: csv,
74+
},
6975
});
7076

7177
draftContent = csv;

artifacts/text/client.tsx

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,31 +28,7 @@ export const textArtifact = new Artifact<'text', TextArtifactMetadata>({
2828
suggestions,
2929
});
3030
},
31-
onStreamPart: ({ streamPart, setMetadata, setArtifact }) => {
32-
if (streamPart.type === 'data-artifacts-suggestion') {
33-
setMetadata((metadata) => {
34-
return {
35-
suggestions: [...metadata.suggestions, streamPart.data as Suggestion],
36-
};
37-
});
38-
}
39-
40-
if (streamPart.type === 'data-artifacts-text-delta') {
41-
setArtifact((draftArtifact) => {
42-
return {
43-
...draftArtifact,
44-
content: draftArtifact.content + (streamPart.data as string),
45-
isVisible:
46-
draftArtifact.status === 'streaming' &&
47-
draftArtifact.content.length > 400 &&
48-
draftArtifact.content.length < 450
49-
? true
50-
: draftArtifact.isVisible,
51-
status: 'streaming',
52-
};
53-
});
54-
}
55-
},
31+
onStreamPart: () => {},
5632
content: ({
5733
mode,
5834
status,

0 commit comments

Comments
 (0)