@@ -180,6 +180,51 @@ export function removeAudioFromContent(
180180 return item ;
181181}
182182
183+ // Realtime can resend truncated assistant items without transcripts after an
184+ // interrupt/retrieve cycle. This helper merges those updates with the latest
185+ // known transcript so UIs retain the portion of the message the user already
186+ // heard.
187+ function preserveAssistantAudioTranscripts (
188+ existing : RealtimeMessageItem ,
189+ incoming : RealtimeMessageItem ,
190+ ) : RealtimeMessageItem {
191+ if ( existing . role !== 'assistant' || incoming . role !== 'assistant' ) {
192+ return incoming ;
193+ }
194+
195+ const mergedContent = incoming . content . map ( ( entry , index ) => {
196+ if ( entry . type !== 'output_audio' ) {
197+ return entry ;
198+ }
199+
200+ const transcriptMissing =
201+ typeof entry . transcript !== 'string' || entry . transcript . length === 0 ;
202+ if ( ! transcriptMissing ) {
203+ return entry ;
204+ }
205+
206+ const previousEntry = existing . content [ index ] ;
207+ if (
208+ previousEntry &&
209+ previousEntry . type === 'output_audio' &&
210+ typeof previousEntry . transcript === 'string' &&
211+ previousEntry . transcript . length > 0
212+ ) {
213+ return {
214+ ...entry ,
215+ transcript : previousEntry . transcript ,
216+ } ;
217+ }
218+
219+ return entry ;
220+ } ) ;
221+
222+ return {
223+ ...incoming ,
224+ content : mergedContent ,
225+ } ;
226+ }
227+
183228/**
184229 * Updates the realtime history array based on the incoming event and options.
185230 * @param history - The current history array.
@@ -230,10 +275,15 @@ export function updateRealtimeHistory(
230275 ) ;
231276
232277 if ( existingIndex !== - 1 ) {
278+ const existingItem = history [ existingIndex ] ;
279+ const mergedEvent =
280+ newEvent . type === 'message' && existingItem . type === 'message'
281+ ? preserveAssistantAudioTranscripts ( existingItem , newEvent )
282+ : newEvent ;
233283 // Update existing item
234284 return history . map ( ( item , idx ) => {
235285 if ( idx === existingIndex ) {
236- return newEvent ;
286+ return mergedEvent ;
237287 }
238288 if ( ! shouldIncludeAudioData && item . type === 'message' ) {
239289 return removeAudioFromContent ( item as any ) ;
0 commit comments