From cdfcbc4af6e9aec835b88dc1806a2a46711e6947 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 9 May 2026 03:40:23 +0900 Subject: [PATCH] refac --- backend/open_webui/utils/middleware.py | 11 +++++++ src/lib/components/chat/Chat.svelte | 31 +++++++++++++------- src/lib/components/chat/Messages.svelte | 12 ++++++++ src/lib/components/chat/Navbar.svelte | 2 ++ src/lib/components/layout/Navbar/Menu.svelte | 30 +++++++++++++++++++ 5 files changed, 76 insertions(+), 10 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index f3e829f22c..ff0edd166e 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -2263,6 +2263,9 @@ async def process_chat_payload(request, form_data, user, metadata, model): form_data = apply_params_to_form_data(form_data, model) log.debug(f'form_data: {form_data}') + # Guided regeneration: extract before it reaches the LLM provider + regeneration_prompt = form_data.pop('regeneration_prompt', None) + # Load messages from DB when available — DB preserves structured 'output' items # which the frontend strips, causing tool calls to be merged into content. chat_id = metadata.get('chat_id') @@ -2298,6 +2301,9 @@ async def process_chat_payload(request, form_data, user, metadata, model): # Strip files field — it's been incorporated into content message.pop('files', None) + if regeneration_prompt: + form_data['messages'].append({'role': 'user', 'content': regeneration_prompt}) + # Process messages with OR-aligned output items for clean LLM messages form_data['messages'] = process_messages_with_output(form_data.get('messages', [])) @@ -4876,6 +4882,11 @@ async def streaming_chat_response_handler(response, ctx): log.debug(f'Code interpreter output: {ci_output}') + # Handle error responses from event_caller + # (e.g. session disconnected, timeout) + if isinstance(ci_output, dict) and ci_output.get('error'): + ci_output = {'stderr': ci_output['error']} + if isinstance(ci_output, dict): stdout = ci_output.get('stdout', '') diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index eae8d7d233..e7cf14a567 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -121,8 +121,10 @@ let controlPaneComponent: ChatControls | undefined; let messageInput: MessageInput | undefined; + let messagesRef: Messages | undefined; let autoScroll = true; + let isNearTop = true; let processing = ''; let messagesContainerElement: HTMLDivElement; @@ -1413,6 +1415,10 @@ } }; + const scrollToTop = async () => { + await messagesRef?.scrollToTop(); + }; + let scrollRAF = null; let contentsRAF = null; const scheduleScrollToBottom = () => { @@ -1969,11 +1975,13 @@ { messages = null, modelId = null, - modelIdx = null + modelIdx = null, + regenerationPrompt = null }: { messages?: any[] | null; modelId?: string | null; modelIdx?: number | null; + regenerationPrompt?: string | null; } = {} ) => { if (autoScroll) { @@ -2085,7 +2093,8 @@ _history, primaryResponseMessageId, _chatId, - selectedModelIds.length > 1 ? messageIdsMap : undefined + selectedModelIds.length > 1 ? messageIdsMap : undefined, + regenerationPrompt ); if (chatEventEmitter) clearInterval(chatEventEmitter); @@ -2150,7 +2159,8 @@ _history, responseMessageId, _chatId, - messageIdsMap?: Record + messageIdsMap?: Record, + regenerationPrompt?: string | null ) => { const responseMessage = _history.messages[responseMessageId]; const userMessage = _history.messages[responseMessage.parentId]; @@ -2206,6 +2216,8 @@ ? { role: 'system', content: `${params?.system ?? $settings?.system ?? ''}` } : undefined ].filter(Boolean); + + if ($temporaryChatEnabled) { messages = [ ...messages, @@ -2349,6 +2361,7 @@ ...(messageIdsMap ? { message_ids: messageIdsMap } : {}), parent_id: userMessage?.parentId ?? null, user_message: userMessage, + ...(regenerationPrompt ? { regeneration_prompt: regenerationPrompt } : {}), background_tasks: { ...(!$temporaryChatEnabled && !_chatId && (userMessage?.parentId ?? null) === null @@ -2580,13 +2593,8 @@ await sendMessage(history, userMessage.id, { ...(suggestionPrompt ? { - messages: [ - ...createMessagesList(history, message.id), - { - role: 'user', - content: suggestionPrompt - } - ] + messages: createMessagesList(history, message.id), + regenerationPrompt: suggestionPrompt } : {}), ...((userMessage?.models ?? [...selectedModels]).length > 1 @@ -2916,6 +2924,7 @@ bind:selectedModels shareEnabled={!!history.currentId} {initNewChat} + scrollToTop={!isNearTop ? scrollToTop : null} {archiveChatHandler} {deleteChatHandler} {moveChatHandler} @@ -2968,10 +2977,12 @@ autoScroll = messagesContainerElement.scrollHeight - messagesContainerElement.scrollTop <= messagesContainerElement.clientHeight + 5; + isNearTop = messagesContainerElement.scrollTop <= 100; }} >
{ + messagesCount = null; + buildMessages(); + await tick(); + if (messages.length > 0) { + const firstMessageEl = document.getElementById(`message-${messages[0].id}`); + if (firstMessageEl) { + firstMessageEl.scrollIntoView({ behavior: 'smooth', block: 'start' }); + } + } + }; + const updateChat = async () => { if (!$temporaryChatEnabled) { history = history; diff --git a/src/lib/components/chat/Navbar.svelte b/src/lib/components/chat/Navbar.svelte index e2a49f7621..43439a7fc6 100644 --- a/src/lib/components/chat/Navbar.svelte +++ b/src/lib/components/chat/Navbar.svelte @@ -45,6 +45,7 @@ export let initNewChat: Function; export let shareEnabled: boolean = false; export let scrollTop = 0; + export let scrollToTop: (() => void) | null = null; export let chat; export let history; @@ -194,6 +195,7 @@ { showShareChatModal = !showShareChatModal; }} diff --git a/src/lib/components/layout/Navbar/Menu.svelte b/src/lib/components/layout/Navbar/Menu.svelte index b8f3b0cf80..f9ea09104e 100644 --- a/src/lib/components/layout/Navbar/Menu.svelte +++ b/src/lib/components/layout/Navbar/Menu.svelte @@ -50,6 +50,7 @@ export let chat; export let onClose: Function = () => {}; + export let scrollToTop: (() => void) | null = null; let showFullMessages = false; @@ -310,6 +311,35 @@
{$i18n.t('Settings')}
--> + + + {#if scrollToTop} + + +
+ {/if} {#if ($artifactContents ?? []).length > 0}