Skip to content

Commit 3568ebc

Browse files
vercel-ai-sdk[bot]Drew-Garrattlgrammelvercel[bot]
authored
Backport: feat(ai): add convertDataPart option to convertToModelMessages (#9748)
This is an automated backport of #9720 to the release-v5.0 branch. --------- Co-authored-by: Drew Foxall <drew_garratt@mckinsey.com> Co-authored-by: Lars Grammel <lars.grammel@gmail.com> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
1 parent d27b88d commit 3568ebc

File tree

6 files changed

+955
-52
lines changed

6 files changed

+955
-52
lines changed

.changeset/gorgeous-dingos-join.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'ai': patch
3+
---
4+
5+
feat(ai): add convertDataPart option to convertToModelMessages
6+
7+
Add optional convertDataPart callback for converting custom data parts (URLs, code files, etc.) to text or file parts that models can process. Fully type-safe using existing UIMessage generics.

content/docs/07-reference/02-ai-sdk-ui/31-convert-to-model-messages.mdx

Lines changed: 143 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ export async function POST(req: Request) {
4141
},
4242
{
4343
name: 'options',
44-
type: '{ tools?: ToolSet }',
44+
type: '{ tools?: ToolSet, convertDataPart?: (part: DataUIPart) => TextPart | FilePart | undefined }',
4545
description:
46-
'Optional configuration object. Provide tools to enable multi-modal tool responses.',
46+
'Optional configuration object. Provide tools to enable multi-modal tool responses, and convertDataPart to transform custom data parts into model-compatible content.',
4747
},
4848
]}
4949
/>
@@ -87,3 +87,144 @@ const result = streamText({
8787
```
8888

8989
Tools can implement the optional `toModelOutput` method to transform their results into multi-modal content. The content is an array of content parts, where each part has a `type` (e.g., 'text', 'image') and corresponding data.
90+
91+
## Custom Data Part Conversion
92+
93+
The `convertToModelMessages` function supports converting custom data parts attached to user messages. This is useful when users need to include additional context (URLs, code files, JSON configs) with their messages.
94+
95+
### Basic Usage
96+
97+
By default, data parts in user messages are filtered out during conversion. To include them, provide a `convertDataPart` callback that transforms data parts into text or file parts that the model can understand:
98+
99+
```ts filename="app/api/chat/route.ts"
100+
import { openai } from '@ai-sdk/openai';
101+
import { convertToModelMessages, streamText, UIMessage } from 'ai';
102+
103+
type CustomUIMessage = UIMessage<
104+
never,
105+
{
106+
url: { url: string; title: string; content: string };
107+
'code-file': { filename: string; code: string; language: string };
108+
}
109+
>;
110+
111+
export async function POST(req: Request) {
112+
const { messages } = await req.json();
113+
114+
const result = streamText({
115+
model: openai('gpt-4o'),
116+
messages: convertToModelMessages<CustomUIMessage>(messages, {
117+
convertDataPart: part => {
118+
// Convert URL attachments to text
119+
if (part.type === 'data-url') {
120+
return {
121+
type: 'text',
122+
text: `[Reference: ${part.data.title}](${part.data.url})\n\n${part.data.content}`,
123+
};
124+
}
125+
126+
// Convert code file attachments
127+
if (part.type === 'data-code-file') {
128+
return {
129+
type: 'text',
130+
text: `\`\`\`${part.data.language}\n// ${part.data.filename}\n${part.data.code}\n\`\`\``,
131+
};
132+
}
133+
134+
// Other data parts are ignored
135+
},
136+
}),
137+
});
138+
139+
return result.toUIMessageStreamResponse();
140+
}
141+
```
142+
143+
### Use Cases
144+
145+
**Attaching URL Content**
146+
Allow users to attach URLs to their messages, with the content fetched and formatted for the model:
147+
148+
```ts
149+
// Client side
150+
sendMessage({
151+
parts: [
152+
{ type: 'text', text: 'Analyze this article' },
153+
{
154+
type: 'data-url',
155+
data: {
156+
url: 'https://example.com/article',
157+
title: 'Important Article',
158+
content: '...',
159+
},
160+
},
161+
],
162+
});
163+
```
164+
165+
**Including Code Files as Context**
166+
Let users reference code files in their conversations:
167+
168+
```ts
169+
convertDataPart: part => {
170+
if (part.type === 'data-code-file') {
171+
return {
172+
type: 'text',
173+
text: `\`\`\`${part.data.language}\n${part.data.code}\n\`\`\``,
174+
};
175+
}
176+
};
177+
```
178+
179+
**Selective Inclusion**
180+
Only data parts for which you return a text or file model message part are included,
181+
all other data parts are ignored.
182+
183+
```ts
184+
const result = convertToModelMessages<
185+
UIMessage<
186+
unknown,
187+
{
188+
url: { url: string; title: string };
189+
code: { code: string; language: string };
190+
note: { text: string };
191+
}
192+
>
193+
>(messages, {
194+
convertDataPart: part => {
195+
if (part.type === 'data-url') {
196+
return {
197+
type: 'text',
198+
text: `[${part.data.title}](${part.data.url})`,
199+
};
200+
}
201+
202+
// data-code and data-node are ignored
203+
},
204+
});
205+
```
206+
207+
### Type Safety
208+
209+
The generic parameter ensures full type safety for your custom data parts:
210+
211+
```ts
212+
type MyUIMessage = UIMessage<
213+
unknown,
214+
{
215+
url: { url: string; content: string };
216+
config: { key: string; value: string };
217+
}
218+
>;
219+
220+
// TypeScript knows the exact shape of part.data
221+
convertToModelMessages<MyUIMessage>(messages, {
222+
convertDataPart: part => {
223+
if (part.type === 'data-url') {
224+
// part.data is typed as { url: string; content: string }
225+
return { type: 'text', text: part.data.url };
226+
}
227+
return null;
228+
},
229+
});
230+
```

0 commit comments

Comments
 (0)