diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index dee368c489..4b3b83f146 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -2744,23 +2744,23 @@ }; const responseCompletionEventHandler = (data, message) => { - message.output = applyResponseStreamEvent(message.output ?? [], data); + const output = Array.isArray(data?.output) + ? data.output + : applyResponseStreamEvent(message.output ?? [], data); + + const updatedMessage = { + ...message, + output + }; if (data?.type === 'response.output_text.delta') { - const value = data.delta ?? ''; - if (!(message.content == '' && value == '\n')) { - message.content += value; - - if (navigator.vibrate && ($settings?.hapticFeedback ?? false)) { - navigator.vibrate(5); - } - dispatchCallOverlayAudio(message); + if (navigator.vibrate && ($settings?.hapticFeedback ?? false)) { + navigator.vibrate(5); } - } else if (data?.type === 'response.completed' || data?.type?.endsWith('.done')) { - message.content = getOutputText(message.output) || message.content; + dispatchCallOverlayAudio(updatedMessage); } - history.messages[message.id] = message; + history.messages[message.id] = updatedMessage; history = history; }; diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index a493a42a5b..2e9488ae6c 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -121,13 +121,17 @@ export let messageId; export let selectedModels = []; - let message: MessageType = structuredClone(history.messages[messageId]); + let messageSource = history.messages[messageId]; + let message: MessageType = structuredClone(messageSource); $: if (history.messages) { const source = history.messages[messageId]; if (source) { - // Fast path: O(1) check on the fields that change most often (content during streaming, done at end) - // Avoids 2x O(n) JSON.stringify calls that are always true during streaming anyway - if ( + // Fast path for the fields that change most often while streaming. + // Responses streams update output even when legacy content is unchanged. + if (source !== messageSource) { + messageSource = source; + message = structuredClone(source); + } else if ( message.content !== source.content || message.done !== source.done || message.output?.length !== source.output?.length