TanStack AI version
0.43.0
Framework/Library version
@tanstack/ai-persistence: 0.1.0, @tanstack/ai-client`: 0.23.0, @tanstack/ai-svelte: 0.16.0
Describe the bug and the steps to reproduce it
ModelMessage.id is documented as the stable identity used for a persistence and hydration round trip.
modelMessagesToUIMessages() honors that contract and reuses ModelMessage.id, but the reverse
uiMessageToModelMessages() conversion does not consistently copy UIMessage.id into the generated model messages.
Bug — UI → model drops IDs:
Correct — model → UI restores IDs:
The asymmetric conversion makes a live UI message lose its identity before its persisted. Hydration must then generate a new ID, which breaks message deduplication, metadata joins, and in-place rendering across reloads.
Your Minimal, Reproducible Example - (Sandbox Highly Recommended)
https://stackblitz.com/edit/vitejs-vite-yjppr1f7?file=package.json,index.html,src%2Fmain.ts
const [modelMessage] = uiMessageToModelMessages({
id: 'message-1',
role: 'user',
createdAt: new Date(),
parts: [{ type: 'text', content: 'Hello' }],
})
expect(modelMessage.id).toBe('message-1') // currently undefined
The same loss occurs when an assistant UI message is converted into assistant segments and tool-result ModelMessage objects.
Terms & Code of Conduct
TanStack AI version
0.43.0
Framework/Library version
@tanstack/ai-persistence: 0.1.0, @tanstack/ai-client`: 0.23.0, @tanstack/ai-svelte: 0.16.0
Describe the bug and the steps to reproduce it
ModelMessage.idis documented as the stable identity used for a persistence and hydration round trip.modelMessagesToUIMessages()honors that contract and reusesModelMessage.id, but the reverseuiMessageToModelMessages()conversion does not consistently copyUIMessage.idinto the generated model messages.Bug — UI → model drops IDs:
roleandcontentinmessages.ts#L178-L190.messages.ts#L230-L295.messages.ts#L343-L376.Correct — model → UI restores IDs:
messages.ts#L585-L636, matching theModelMessage.idcontract intypes.ts#L358-L375.The asymmetric conversion makes a live UI message lose its identity before its persisted. Hydration must then generate a new ID, which breaks message deduplication, metadata joins, and in-place rendering across reloads.
Your Minimal, Reproducible Example - (Sandbox Highly Recommended)
https://stackblitz.com/edit/vitejs-vite-yjppr1f7?file=package.json,index.html,src%2Fmain.ts
The same loss occurs when an assistant UI message is converted into assistant segments and tool-result
ModelMessageobjects.Terms & Code of Conduct