Problem
Stream text events (thread.stream.text.*) carry a part/stream id, not the final message id. The final assistant message arrives via thread.event.created with a different id. The client has no reliable way to correlate them, causing duplicate rendering.
Root cause
Every major provider gives you a response/message id:
- OpenAI Responses:
item.id (msg_123) threaded through content events
- Anthropic:
message.id (msg_1nZdL29xx...) on message_start
- xAI:
id on the response, msg_... on output items
- Google:
responseId on GenerateContentResponse
The AI SDK only surfaces these on response-metadata and uses synthetic String(index) or String(blockCounter++) as the id on text-start/text-delta for Anthropic and Google. It throws away the association.
Fix
Resolve the real message id at the adapter boundary (per-provider), attach it as messageId on stream text parts, and use it for dedup on the client.
Problem
Stream text events (
thread.stream.text.*) carry a part/stream id, not the final message id. The final assistant message arrives viathread.event.createdwith a different id. The client has no reliable way to correlate them, causing duplicate rendering.Root cause
Every major provider gives you a response/message id:
item.id(msg_123) threaded through content eventsmessage.id(msg_1nZdL29xx...) onmessage_startidon the response,msg_...on output itemsresponseIdonGenerateContentResponseThe AI SDK only surfaces these on
response-metadataand uses syntheticString(index)orString(blockCounter++)as theidontext-start/text-deltafor Anthropic and Google. It throws away the association.Fix
Resolve the real message id at the adapter boundary (per-provider), attach it as
messageIdon stream text parts, and use it for dedup on the client.