fix: report a failed admin Interface save and fall back to the default when a number field is left empty (#32163)

This commit is contained in:
G30 2026-10-10 12:01:18 -04:00 • committed by GitHub
parent c7e7dbf984
commit e056b29685
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 37 additions and 15 deletions

View file

@ -6,7 +6,12 @@ from uuid import uuid4
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Request, Response, status
from fastapi.responses import StreamingResponse
from fastapi.security import HTTPAuthorizationCredentials
from open_webui.config import ENABLE_ADMIN_CHAT_ACCESS, ENABLE_ADMIN_EXPORT
from open_webui.config import (
CONTEXT_COMPACTION_RETENTION_PERCENTAGE,
CONTEXT_COMPACTION_TOKEN_THRESHOLD,
ENABLE_ADMIN_CHAT_ACCESS,
ENABLE_ADMIN_EXPORT,
)
from open_webui.constants import ERROR_MESSAGES
from open_webui.events import EVENTS, publish_event
from open_webui.internal.db import get_async_session
@ -192,9 +197,9 @@ 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_THRESHOLD: int | None = None
CONTEXT_COMPACTION_TOKEN_CAP: int | None = None
CONTEXT_COMPACTION_RETENTION_PERCENTAGE: int = 40
CONTEXT_COMPACTION_RETENTION_PERCENTAGE: int | None = None
CONTEXT_COMPACTION_PROMPT_TEMPLATE: str
ENABLE_TOOL_PERMISSIONS: bool = False
@ -874,9 +879,15 @@ async def get_chat_config(user=Depends(get_admin_user)):
@router.post('/config', response_model=ChatConfigForm)
async def set_chat_config(form_data: ChatConfigForm, user=Depends(get_admin_user)):
threshold = max(1, int(form_data.CONTEXT_COMPACTION_TOKEN_THRESHOLD))
threshold = form_data.CONTEXT_COMPACTION_TOKEN_THRESHOLD
if threshold is None:
threshold = CONTEXT_COMPACTION_TOKEN_THRESHOLD
threshold = max(1, int(threshold))
token_cap = max(1, int(form_data.CONTEXT_COMPACTION_TOKEN_CAP or threshold))
retention_percentage = min(50, max(10, int(form_data.CONTEXT_COMPACTION_RETENTION_PERCENTAGE)))
retention_percentage = form_data.CONTEXT_COMPACTION_RETENTION_PERCENTAGE
if retention_percentage is None:
retention_percentage = CONTEXT_COMPACTION_RETENTION_PERCENTAGE
retention_percentage = min(50, max(10, int(retention_percentage)))
await Config.upsert(
chat_config_updates(
{

View file

@ -5,6 +5,7 @@ from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Request, Response, status
from fastapi.responses import JSONResponse, RedirectResponse
from open_webui.config import (
AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH,
DEFAULT_AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE,
DEFAULT_EMOJI_GENERATION_PROMPT_TEMPLATE,
DEFAULT_FOLLOW_UP_GENERATION_PROMPT_TEMPLATE,
@ -118,7 +119,7 @@ class TaskConfigForm(BaseModel):
TITLE_GENERATION_PROMPT_TEMPLATE: str
IMAGE_PROMPT_GENERATION_PROMPT_TEMPLATE: str
ENABLE_AUTOCOMPLETE_GENERATION: bool
AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH: int
AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH: int | None = None
AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE: str
TAGS_GENERATION_PROMPT_TEMPLATE: str
FOLLOW_UP_GENERATION_PROMPT_TEMPLATE: str
@ -134,7 +135,10 @@ class TaskConfigForm(BaseModel):
@router.post('/config/update')
async def update_task_config(request: Request, form_data: TaskConfigForm, user=Depends(get_admin_user)):
await Config.upsert(config_updates(form_data.model_dump(), TASK_CONFIG_KEYS))
data = form_data.model_dump()
if data['AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH'] is None:
data['AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH'] = AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH
await Config.upsert(config_updates(data, TASK_CONFIG_KEYS))
return await get_config_values(TASK_CONFIG_KEYS)

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { getModels, getTaskConfig, updateTaskConfig } from '$lib/apis';
import { getChatConfig, updateChatConfig } from '$lib/apis/chats';
import { createEventDispatcher, onMount, getContext } from 'svelte';
import { onMount, getContext } from 'svelte';
import { toast } from 'svelte-sonner';
import { getBaseModels } from '$lib/apis/models';
@ -17,7 +17,7 @@
import AdminSettingSection from './AdminSettingSection.svelte';
import { config as appConfig } from '$lib/stores';
const dispatch = createEventDispatcher();
export let saveHandler: () => void;
const i18n: any = getContext('i18n');
@ -67,10 +67,17 @@
TASK_MODEL_PARAMS: configuredParams(taskConfig.TASK_MODEL_PARAMS)
};
[taskConfig, chatConfig] = await Promise.all([
updateTaskConfig(localStorage.token, taskConfigPayload),
updateChatConfig(localStorage.token, chatConfig)
]);
try {
[taskConfig, chatConfig] = await Promise.all([
updateTaskConfig(localStorage.token, taskConfigPayload),
updateChatConfig(localStorage.token, chatConfig)
]);
} catch (error) {
toast.error(
Array.isArray(error) ? error.map((entry) => entry.msg).join('\n') : String(error)
);
return;
}
appConfig.update((current) =>
current
? {
@ -83,6 +90,7 @@
}
: current
);
saveHandler();
};
let workspaceModels: any[] = [];
@ -165,7 +173,6 @@
class="flex h-full flex-col justify-between text-sm"
on:submit|preventDefault={() => {
updateInterfaceHandler();
dispatch('save');
}}
>
<h2 class="text-sm font-medium text-gray-900 dark:text-white mb-4">

View file

@ -879,7 +879,7 @@
<AdminCodeExecution saveHandler={adminConfigSaveHandler} />
{:else if selectedTab === 'admin:interface'}
<AdminInterface
on:save={() => {
saveHandler={() => {
toast.success($i18n.t('Settings saved successfully!'));
}}
/>