From a089842368398982baec519b9b62be8687b56db8 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 1 Jun 2026 20:45:05 +0200 Subject: [PATCH] fix: don't revert replace/outlet content on chat save (#25485) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit update_chat_by_id re-derived assistant content from `output` on every save (serialize_output) so frontend edits to output items reflect in content. But it ran unconditionally, so content set independently of output — an __event_emitter__ {"type":"replace"} from an Action, or an outlet filter footer — was reverted to the original output-derived text on the next save. The reload reads chat.chat directly, so the change vanished after navigating away (regression vs 0.9.2, which predates the output mechanism). Re-derive only when the message's `output` actually changed versus what's stored, which still reflects genuine output edits but leaves independently-set content intact. Fixes #24585 Co-authored-by: Claude Opus 4.8 (1M context) --- backend/open_webui/routers/chats.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 91cdb21e78..256455fffb 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -968,12 +968,15 @@ async def update_chat_by_id( if chat: updated_chat = {**chat.chat, **form_data.chat} - # Re-derive content from output for assistant messages so that - # frontend edits to output items are always reflected in content. - # serialize_output() is the single source of truth for this conversion. - for msg in updated_chat.get('history', {}).get('messages', {}).values(): + # Re-derive content from output for assistant messages so that frontend + # edits to output items are reflected in content. Only when output + # actually changed — otherwise content set independently of output + # (e.g. a `replace` event or an outlet filter footer) would be reverted. + existing_messages = (chat.chat.get('history') or {}).get('messages') or {} + for msg_id, msg in updated_chat.get('history', {}).get('messages', {}).items(): if msg.get('role') == 'assistant' and msg.get('output'): - msg['content'] = serialize_output(msg['output']) + if msg.get('output') != existing_messages.get(msg_id, {}).get('output'): + msg['content'] = serialize_output(msg['output']) chat = await Chats.update_chat_by_id(id, updated_chat, db=db)