From 69e449e3186a54218ac5a2b01bd94f94b5f1d6af Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 27 Jul 2026 03:05:26 -0400 Subject: [PATCH] refac --- backend/open_webui/config.py | 3 + backend/open_webui/routers/chats.py | 5 + .../open_webui/utils/context_compaction.py | 20 +++- backend/open_webui/utils/middleware.py | 1 + .../admin/Settings/Interface.svelte | 102 +++++++++--------- 5 files changed, 76 insertions(+), 55 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 721c890407..b024ce0b7e 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -2148,6 +2148,8 @@ TASK_MODEL = os.getenv('TASK_MODEL', '') TASK_MODEL_EXTERNAL = os.getenv('TASK_MODEL_EXTERNAL', '') +CONTEXT_COMPACTION_MODEL = os.getenv('CONTEXT_COMPACTION_MODEL', '') + ENABLE_CONTEXT_COMPACTION = os.getenv('ENABLE_CONTEXT_COMPACTION', 'False').lower() == 'true' CONTEXT_COMPACTION_TOKEN_THRESHOLD = int(os.getenv('CONTEXT_COMPACTION_TOKEN_THRESHOLD', '80000')) @@ -3072,6 +3074,7 @@ DEFAULT_CONFIG = { 'auth.admin.email': ADMIN_EMAIL, 'task.model.default': TASK_MODEL, 'task.model.external': TASK_MODEL_EXTERNAL, + 'chat.context_compaction.model': CONTEXT_COMPACTION_MODEL, 'chat.context_compaction.enable': ENABLE_CONTEXT_COMPACTION, 'chat.context_compaction.token_threshold': CONTEXT_COMPACTION_TOKEN_THRESHOLD, 'chat.context_compaction.token_cap': CONTEXT_COMPACTION_TOKEN_CAP, diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 35dbf70abd..e618eb3f06 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -53,6 +53,7 @@ router = APIRouter() SEARCH_FILTER_PREFIXES = ('tag:', 'folder:', 'pinned:', 'archived:', 'shared:') CHAT_CONFIG_KEYS = { + 'CONTEXT_COMPACTION_MODEL': 'chat.context_compaction.model', 'ENABLE_CONTEXT_COMPACTION': 'chat.context_compaction.enable', 'CONTEXT_COMPACTION_TOKEN_THRESHOLD': 'chat.context_compaction.token_threshold', 'CONTEXT_COMPACTION_TOKEN_CAP': 'chat.context_compaction.token_cap', @@ -134,6 +135,7 @@ async def get_folder_unread_counts(user_id: str, db: AsyncSession | None = None) class ChatConfigForm(BaseModel): + CONTEXT_COMPACTION_MODEL: str | None = '' ENABLE_CONTEXT_COMPACTION: bool CONTEXT_COMPACTION_TOKEN_THRESHOLD: int CONTEXT_COMPACTION_TOKEN_CAP: int | None = None @@ -185,6 +187,8 @@ def chat_search_snippet(chat: dict, search_text: str, max_length: int = 200) -> async def get_chat_config_values() -> dict: values = await Config.get_many(*CHAT_CONFIG_KEYS.values()) config = {field: values[storage_key] for field, storage_key in CHAT_CONFIG_KEYS.items() if storage_key in values} + if config.get('CONTEXT_COMPACTION_MODEL') is None: + config['CONTEXT_COMPACTION_MODEL'] = '' if config.get('CONTEXT_COMPACTION_TOKEN_CAP') is None: config['CONTEXT_COMPACTION_TOKEN_CAP'] = config.get('CONTEXT_COMPACTION_TOKEN_THRESHOLD', 80000) if config.get('CONTEXT_COMPACTION_RETENTION_PERCENTAGE') is None: @@ -824,6 +828,7 @@ async def set_chat_config(form_data: ChatConfigForm, user=Depends(get_admin_user chat_config_updates( { **form_data.model_dump(), + 'CONTEXT_COMPACTION_MODEL': form_data.CONTEXT_COMPACTION_MODEL or '', 'CONTEXT_COMPACTION_TOKEN_THRESHOLD': threshold, 'CONTEXT_COMPACTION_TOKEN_CAP': token_cap, 'CONTEXT_COMPACTION_RETENTION_PERCENTAGE': retention_percentage, diff --git a/backend/open_webui/utils/context_compaction.py b/backend/open_webui/utils/context_compaction.py index 095b920bef..e3c6f54e2a 100644 --- a/backend/open_webui/utils/context_compaction.py +++ b/backend/open_webui/utils/context_compaction.py @@ -364,11 +364,21 @@ async def _generate_summary( ) -> str: from open_webui.utils.chat import generate_chat_completion - task_model_id = get_task_model_id( - model_id, - await Config.get('task.model.default'), - await Config.get('task.model.external'), - models, + task_config = await Config.get_many( + 'task.model.default', + 'task.model.external', + 'chat.context_compaction.model', + ) + context_compaction_model = task_config.get('chat.context_compaction.model') + task_model_id = ( + context_compaction_model + if context_compaction_model in models + else get_task_model_id( + model_id, + task_config.get('task.model.default'), + task_config.get('task.model.external'), + models, + ) ) if task_model_id not in models: task_model_id = model_id diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 88738df7ec..9cb936d3ec 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -2332,6 +2332,7 @@ async def process_chat_payload(request, form_data, user, metadata, model): if is_saved_chat_id(chat_id) and user_message_id: if getattr(request.state, 'direct', False) and hasattr(request.state, 'model'): compaction_models = { + **request.app.state.MODELS, request.state.model['id']: request.state.model, } else: diff --git a/src/lib/components/admin/Settings/Interface.svelte b/src/lib/components/admin/Settings/Interface.svelte index c6bb724638..c1cae4b83b 100644 --- a/src/lib/components/admin/Settings/Interface.svelte +++ b/src/lib/components/admin/Settings/Interface.svelte @@ -41,6 +41,7 @@ }; let chatConfig = { + CONTEXT_COMPACTION_MODEL: '', ENABLE_CONTEXT_COMPACTION: false, CONTEXT_COMPACTION_TOKEN_THRESHOLD: 80000, CONTEXT_COMPACTION_TOKEN_CAP: 80000, @@ -71,6 +72,27 @@ let models: any[] | null = null; $: modelOptions = models ?? []; + const normalizeModelSelection = (modelId: string | null | undefined) => { + if (!modelId) { + return ''; + } + + const model = modelOptions.find((m: any) => m.id === modelId); + if (!model) { + return ''; + } + + if ( + model?.access_grants && + !model.access_grants.some( + (g: any) => g.principal_type === 'user' && g.principal_id === '*' && g.permission === 'read' + ) + ) { + toast.error($i18n.t('This model is not publicly available. Please select another model.')); + } + + return model.id; + }; const inputClass = 'w-full h-7 rounded-lg border border-gray-100/50 bg-gray-50/40 px-2 text-xs text-gray-700 outline-hidden transition-colors placeholder:text-gray-300 focus:border-blue-400 dark:border-white/[0.04] dark:bg-white/[0.03] dark:text-gray-300 dark:placeholder:text-gray-700 dark:focus:border-blue-500'; const textareaClass = @@ -150,30 +172,7 @@ className="w-full" placeholder={$i18n.t('Select a model')} on:change={() => { - if (taskConfig.TASK_MODEL) { - const model = modelOptions.find((m: any) => m.id === taskConfig.TASK_MODEL); - if (model) { - if ( - model?.access_grants && - !model.access_grants.some( - (g: any) => - g.principal_type === 'user' && - g.principal_id === '*' && - g.permission === 'read' - ) - ) { - toast.error( - $i18n.t( - 'This model is not publicly available. Please select another model.' - ) - ); - } - - taskConfig.TASK_MODEL = model.id; - } else { - taskConfig.TASK_MODEL = ''; - } - } + taskConfig.TASK_MODEL = normalizeModelSelection(taskConfig.TASK_MODEL); }} > @@ -192,32 +191,9 @@ className="w-full" placeholder={$i18n.t('Select a model')} on:change={() => { - if (taskConfig.TASK_MODEL_EXTERNAL) { - const model = modelOptions.find( - (m: any) => m.id === taskConfig.TASK_MODEL_EXTERNAL - ); - if (model) { - if ( - model?.access_grants && - !model.access_grants.some( - (g: any) => - g.principal_type === 'user' && - g.principal_id === '*' && - g.permission === 'read' - ) - ) { - toast.error( - $i18n.t( - 'This model is not publicly available. Please select another model.' - ) - ); - } - - taskConfig.TASK_MODEL_EXTERNAL = model.id; - } else { - taskConfig.TASK_MODEL_EXTERNAL = ''; - } - } + taskConfig.TASK_MODEL_EXTERNAL = normalizeModelSelection( + taskConfig.TASK_MODEL_EXTERNAL + ); }} > @@ -245,6 +221,32 @@ {#if chatConfig.ENABLE_CONTEXT_COMPACTION} + + { + chatConfig.CONTEXT_COMPACTION_MODEL = normalizeModelSelection( + chatConfig.CONTEXT_COMPACTION_MODEL + ); + }} + > + + {#each modelOptions as model} + + {/each} + + +