Zum Inhalt springen
EN DE

Custom Data Parts: ID Reconciliation

Wenn Du ein Data Part mit einer ID sendest und später ein weiteres Data Part mit derselben ID, wird das bestehende Part aktualisiert — nicht ein neues angehaengt. Das ermoeglicht progressive Loading States: erst ein Skeleton anzeigen, dann mit echten Daten ersetzen.

Ohne ID-Reconciliation wuerdest Du für jeden Status-Wechsel einen neuen Eintrag in message.parts bekommen. Mit IDs bleibt es ein einziger Eintrag, der sich vom Loading-State zum fertigen Ergebnis entwickelt. Das haelt die UI sauber und die Message-Historie kompakt.

Dieses Pattern ist besonders nuetzlich für Tool-Ergebnisse, die asynchron geladen werden — z.B. eine Wetter-Abfrage, die erst “Lade…” zeigt und dann die Temperatur.

import { createUIMessageStreamResponse, streamText } from 'ai';
export async function POST(req: Request) {
const { messages } = await req.json();
return createUIMessageStreamResponse({
execute: async (writer) => {
// Loading State senden
writer.write({
type: 'data-weather', // ← Custom Type mit data- Prefix
id: 'weather-berlin', // ← ID setzen
data: { city: 'Berlin', status: 'loading' },
});
const result = streamText({ model, messages });
// LLM-Stream in den Writer mergen
writer.merge(result.toUIMessageStream());
// Später: Update mit echten Daten (gleiche ID)
const weather = await fetchWeather('Berlin');
writer.write({
type: 'data-weather', // ← Gleicher Type
id: 'weather-berlin', // ← Gleiche ID → UPDATE
data: {
city: 'Berlin',
status: 'success',
temp: weather.temp,
},
});
},
});
}
// In message.parts gibt es nur EINEN Eintrag für 'weather-berlin'
// — den jeweils aktuellsten Stand
{m.parts.map((part, i) => {
if (part.type === 'data-weather') {
return part.data.status === 'loading'
? <WeatherSkeleton key={i} city={part.data.city} />
: <WeatherCard key={i} data={part.data} />;
}
return null;
})}
SzenarioOhne IDMit ID
Zweites Data Part gesendetNeuer Eintrag in partsBestehender Eintrag aktualisiert
parts.lengthWaechst mit jedem SendBleibt gleich (pro ID)
UI-RenderingMehrere Elemente (alt + neu)Ein Element (aktueller Stand)
Loading → SuccessZwei sichtbare ElementeEin Element, das sich ändert
// Drei unabhängige Data Parts mit eigenen IDs
writer.write({
type: 'data-weather',
id: 'weather-berlin',
data: { city: 'Berlin', status: 'loading' },
});
writer.write({
type: 'data-weather',
id: 'weather-muenchen',
data: { city: 'Muenchen', status: 'loading' },
});
writer.write({
type: 'data-stock',
id: 'stock-price',
data: { symbol: 'AAPL', status: 'loading' },
});
// Jedes wird unabhängig aktualisiert, sobald die Daten da sind

Part of AI Learning — free courses from prompt to production. Jan on LinkedIn