@@ -215,6 +215,32 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
215215 }
216216 const result = Binary . search ( parts , event . properties . part . id , ( p ) => p . id )
217217 if ( result . found ) {
218+ // For TextParts during streaming, use produce to merge deltas safely
219+ // This prevents race conditions where text-end overwrites accumulated text
220+ const currentPart = parts [ result . index ]
221+ if ( currentPart . type === "text" && event . properties . part . type === "text" ) {
222+ const incomingTextPart = event . properties . part as Extract < Part , { type : "text" } >
223+ const currentTextPart = currentPart as Extract < Part , { type : "text" } >
224+
225+ // If this is a streaming update (has text field), use produce for safe merge
226+ if ( incomingTextPart . text !== undefined ) {
227+ setStore (
228+ "part" ,
229+ event . properties . part . messageID ,
230+ produce ( ( draft ) => {
231+ const part = draft [ result . index ] as Extract < Part , { type : "text" } >
232+ // Update text content but preserve other metadata
233+ part . text = incomingTextPart . text
234+ // Update timing only if end time is provided (text-end event)
235+ if ( incomingTextPart . time ?. end ) {
236+ part . time = incomingTextPart . time
237+ }
238+ } )
239+ )
240+ break
241+ }
242+ }
243+ // Fall back to reconcile for non-text parts or non-streaming updates
218244 setStore ( "part" , event . properties . part . messageID , result . index , reconcile ( event . properties . part ) )
219245 break
220246 }
0 commit comments