From 4654ecbf1b60d36542892507079bce58af8cfc94 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Thu, 26 Feb 2026 21:47:32 +0100 Subject: [PATCH] perf: fast-path comparison in ResponseMessage to skip JSON.stringify during streaming (#21884) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ResponseMessage compared the entire message object via JSON.stringify on every reactive tick to detect changes. During streaming, content changes on every token, making the two O(content_length) JSON.stringify calls always return different results — pure wasted work. Add a fast O(1) comparison on content and done fields first. When either differs (the common streaming case), skip straight to cloning. Only fall through to the expensive JSON.stringify comparison for infrequent changes like sources, annotations, or status updates. --- .../components/chat/Messages/ResponseMessage.svelte | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index 113992a03..2d4dc740e 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -121,8 +121,16 @@ let message: MessageType = JSON.parse(JSON.stringify(history.messages[messageId])); $: if (history.messages) { - if (JSON.stringify(message) !== JSON.stringify(history.messages[messageId])) { - message = JSON.parse(JSON.stringify(history.messages[messageId])); + 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 (message.content !== source.content || message.done !== source.done) { + message = JSON.parse(JSON.stringify(source)); + } else if (JSON.stringify(message) !== JSON.stringify(source)) { + // Slow path: full comparison for infrequent changes (sources, annotations, status, etc.) + message = JSON.parse(JSON.stringify(source)); + } } }