From 381149ea5ebc68ae5ea8a61678f57cfcedd2e33e Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 27 Jul 2026 00:55:21 +0200 Subject: [PATCH] fix: persist filter outlet() changes to structured message output (#27414) When a filter's outlet() modified the structured assistant output in place, the change was shown immediately but lost after reload. outlet_filter_handler built its outlet payload with a shallow reference to the message's output list from messages_map, so the filter mutated the stored baseline itself and the subsequent output comparison compared the object against itself, never detecting a change and never persisting it. The same aliasing corrupted originalContent for messages whose text lives only in output. Deepcopy the output when building the outlet payload so messages_map stays a pristine pre-filter baseline and the existing change detection persists outlet-modified output through the existing upsert path. Fixes #27017. --- backend/open_webui/utils/middleware.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index f1fc6c39d6..ad13effe53 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -3424,7 +3424,8 @@ async def outlet_filter_handler(ctx): 'content': m.get('content') or get_output_text(m.get('output')), 'info': m.get('info'), 'timestamp': m.get('timestamp'), - **({'output': m['output']} if m.get('output') else {}), + # Deepcopy so in-place filter mutations do not alias messages_map's baseline + **({'output': copy.deepcopy(m['output'])} if m.get('output') else {}), **({'usage': m['usage']} if m.get('usage') else {}), **({'sources': m['sources']} if m.get('sources') else {}), }