From 8934bfb04bf366aece872028944e280c25e36d3e Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Wed, 24 Jun 2026 14:13:58 +0200 Subject: [PATCH] refac --- .../open_webui/utils/context_compaction.py | 80 +++++++++++++++---- src/lib/components/chat/Chat.svelte | 42 ++++++++++ src/routes/+layout.svelte | 6 ++ 3 files changed, 113 insertions(+), 15 deletions(-) diff --git a/backend/open_webui/utils/context_compaction.py b/backend/open_webui/utils/context_compaction.py index f5d51e6834..3c6dd819ec 100644 --- a/backend/open_webui/utils/context_compaction.py +++ b/backend/open_webui/utils/context_compaction.py @@ -66,31 +66,81 @@ async def compact_messages_for_request( if not compacted_messages or not recent_messages: return messages, previous_summary, False - summary = await _generate_summary( - request, - user, - model_id, - models, - compacted_messages, - recent_messages, - previous_summary, - config['prompt_template'], - ) + event_emitter = None + if metadata.get('chat_id') and metadata.get('message_id'): + from open_webui.socket.main import get_event_emitter + + event_emitter = await get_event_emitter(metadata) + + if event_emitter: + await event_emitter( + { + 'type': 'context_compaction', + 'data': { + 'action': 'context_compaction', + 'description': 'Compacting context', + 'done': False, + }, + } + ) + + try: + summary = await _generate_summary( + request, + user, + model_id, + models, + compacted_messages, + recent_messages, + previous_summary, + config['prompt_template'], + ) + except Exception: + if event_emitter: + await event_emitter( + { + 'type': 'context_compaction', + 'data': { + 'action': 'context_compaction', + 'description': 'Context compaction failed', + 'done': True, + 'error': True, + }, + } + ) + raise chat_id = metadata.get('chat_id') - message_id = metadata.get('message_id') - if chat_id and message_id and not chat_id.startswith(('local:', 'channel:')): - await Chats.upsert_message_to_chat_by_id_and_message_id(chat_id, message_id, {'contextSummary': summary}) + checkpoint_message_id = metadata.get('user_message_id') or metadata.get('message_id') + if chat_id and checkpoint_message_id and not chat_id.startswith(('local:', 'channel:')): + await Chats.upsert_message_to_chat_by_id_and_message_id( + chat_id, + checkpoint_message_id, + {'contextSummary': summary}, + ) log.info( - 'Compacted chat context for chat=%s message=%s dropped=%d kept=%d summary_chars=%d', + 'Compacted chat context for chat=%s checkpoint=%s response=%s dropped=%d kept=%d summary_chars=%d', chat_id, - message_id, + checkpoint_message_id, + metadata.get('message_id'), len(compacted_messages), len(recent_messages), len(summary), ) + if event_emitter: + await event_emitter( + { + 'type': 'context_compaction', + 'data': { + 'action': 'context_compaction', + 'description': 'Context compacted', + 'done': True, + }, + } + ) + return recent_messages, summary, True diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index d9f92ab9fc..24210547df 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -164,6 +164,7 @@ let generating = false; let dragged = false; let generationController = null; + let contextCompactionToastId = null; let chat = null; let tags = []; @@ -498,6 +499,43 @@ } }; + const dismissContextCompactionToast = () => { + if (contextCompactionToastId !== null) { + toast.dismiss(contextCompactionToastId); + contextCompactionToastId = null; + } + }; + + const handleContextCompactionStatus = (status) => { + if (status?.action !== 'context_compaction') { + return; + } + + if (status?.done) { + if (contextCompactionToastId !== null) { + if (status?.error) { + toast.error($i18n.t('Context compaction failed'), { + id: contextCompactionToastId, + duration: 3000 + }); + } else { + toast.success($i18n.t('Context compacted'), { + id: contextCompactionToastId, + duration: 1800 + }); + } + contextCompactionToastId = null; + } + return; + } + + if (contextCompactionToastId === null) { + contextCompactionToastId = toast.loading($i18n.t('Compacting context'), { + duration: Infinity + }); + } + }; + const chatEventHandler = async (event, cb) => { console.log(event); @@ -515,9 +553,12 @@ } else { message.statusHistory = [data]; } + } else if (type === 'context_compaction') { + handleContextCompactionStatus(data); } else if (type === 'chat:completion') { chatCompletionEventHandler(data, message, event.chat_id); } else if (type === 'chat:tasks:cancel') { + dismissContextCompactionToast(); if (event.message_id === history.currentId) { taskIds = null; // Set all response messages to done @@ -895,6 +936,7 @@ selectedFolderSubscribe(); window.removeEventListener('message', onMessageHandler); $socket?.off('events', chatEventHandler); + dismissContextCompactionToast(); audioQueueInstance?.destroy(); audioQueue.set(null); } catch (e) { diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 0a165a89c8..5baa0195ec 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1198,4 +1198,10 @@ richColors position="top-right" closeButton + toastOptions={{ + classes: { + closeButton: + '!bg-white/80 !text-gray-500 !border-gray-200 hover:!bg-gray-50 hover:!text-gray-700 dark:!bg-gray-850 dark:!text-gray-400 dark:!border-gray-700 dark:hover:!bg-gray-800 dark:hover:!text-gray-200' + } + }} />