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: newDate(),parts: [{type: 'text',content: 'Hello'}],})expect(modelMessage.id).toBe('message-1')// currently undefinedThe 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