feat: add Web Search warning as banner and toast message

- Show yellow dismissible banner while web search is active
- Show one-time toast when web search is toggled on
- Both are suppressed when the admin disables the toggle
This commit is contained in:
Michelle Winkle 2026-04-21 10:15:35 +02:00
parent 359590ca9d
commit 4a9d7ef701
5 changed files with 77 additions and 1 deletions

View file

@ -1519,6 +1519,12 @@ ENABLE_WEB_SEARCH = ConfigVar(
os.getenv('ENABLE_WEB_SEARCH', 'False').lower() == 'true',
)
WEB_SEARCH_WARNING_ENABLED = ConfigVar(
'WEB_SEARCH_WARNING_ENABLED',
'rag.web.search.warning_enabled',
os.getenv('WEB_SEARCH_WARNING_ENABLED', 'False').lower() == 'true',
)
WEB_SEARCH_ENGINE = ConfigVar(
'WEB_SEARCH_ENGINE',
'rag.web.search.engine',
@ -1607,7 +1613,6 @@ WEB_SEARCH_TRUST_ENV = ConfigVar(
os.getenv('WEB_SEARCH_TRUST_ENV', 'True').lower() == 'true',
)
OLLAMA_CLOUD_WEB_SEARCH_API_KEY = ConfigVar(
'OLLAMA_CLOUD_WEB_SEARCH_API_KEY',
'rag.web.search.ollama_cloud_api_key',

View file

@ -212,6 +212,7 @@ from open_webui.config import (
ENABLE_WEB_LOADER_SSL_VERIFICATION,
# Retrieval (Web Search)
ENABLE_WEB_SEARCH,
WEB_SEARCH_WARNING_ENABLED,
# Misc
ENV,
EVALUATION_ARENA_MODELS,
@ -1070,6 +1071,7 @@ app.state.config.YOUTUBE_LOADER_LANGUAGE = YOUTUBE_LOADER_LANGUAGE
app.state.config.YOUTUBE_LOADER_PROXY_URL = YOUTUBE_LOADER_PROXY_URL
app.state.config.WEB_SEARCH_WARNING_ENABLED = WEB_SEARCH_WARNING_ENABLED
app.state.config.ENABLE_WEB_SEARCH = ENABLE_WEB_SEARCH
app.state.config.WEB_SEARCH_ENGINE = WEB_SEARCH_ENGINE
app.state.config.WEB_SEARCH_DOMAIN_FILTER_LIST = WEB_SEARCH_DOMAIN_FILTER_LIST
@ -2378,6 +2380,7 @@ async def get_app_config(request: Request):
'enable_calendar': app.state.config.ENABLE_CALENDAR,
'enable_automations': app.state.config.ENABLE_AUTOMATIONS,
'enable_notes': app.state.config.ENABLE_NOTES,
'web_search_warning_enabled': app.state.config.WEB_SEARCH_WARNING_ENABLED,
'enable_web_search': app.state.config.ENABLE_WEB_SEARCH,
'enable_code_execution': app.state.config.ENABLE_CODE_EXECUTION,
'enable_code_interpreter': app.state.config.ENABLE_CODE_INTERPRETER,

View file

@ -497,6 +497,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)):
'WEB_FETCH_MAX_CONTENT_LENGTH': request.app.state.config.WEB_FETCH_MAX_CONTENT_LENGTH,
'WEB_LOADER_CONCURRENT_REQUESTS': request.app.state.config.WEB_LOADER_CONCURRENT_REQUESTS,
'WEB_SEARCH_DOMAIN_FILTER_LIST': request.app.state.config.WEB_SEARCH_DOMAIN_FILTER_LIST,
'WEB_SEARCH_WARNING_ENABLED': request.app.state.config.WEB_SEARCH_WARNING_ENABLED,
'BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL': request.app.state.config.BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL,
'BYPASS_WEB_SEARCH_WEB_LOADER': request.app.state.config.BYPASS_WEB_SEARCH_WEB_LOADER,
'OLLAMA_CLOUD_WEB_SEARCH_API_KEY': request.app.state.config.OLLAMA_CLOUD_WEB_SEARCH_API_KEY,
@ -564,6 +565,7 @@ class WebConfig(BaseModel):
WEB_SEARCH_RESULT_COUNT: int | None = None
WEB_SEARCH_CONCURRENT_REQUESTS: int | None = None
WEB_SEARCH_DOMAIN_FILTER_LIST: list[str | None] = []
WEB_SEARCH_WARNING_ENABLED: bool | None = None
WEB_FETCH_MAX_CONTENT_LENGTH: int | None = None
WEB_LOADER_CONCURRENT_REQUESTS: int | None = None
BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL: bool | None = None
@ -1047,6 +1049,7 @@ async def update_rag_config(request: Request, form_data: ConfigForm, user=Depend
request.app.state.config.WEB_FETCH_MAX_CONTENT_LENGTH = form_data.web.WEB_FETCH_MAX_CONTENT_LENGTH
request.app.state.config.WEB_LOADER_CONCURRENT_REQUESTS = form_data.web.WEB_LOADER_CONCURRENT_REQUESTS
request.app.state.config.WEB_SEARCH_DOMAIN_FILTER_LIST = form_data.web.WEB_SEARCH_DOMAIN_FILTER_LIST
request.app.state.config.WEB_SEARCH_WARNING_ENABLED = form_data.web.WEB_SEARCH_WARNING_ENABLED
request.app.state.config.BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL = (
form_data.web.BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL
)
@ -1186,6 +1189,7 @@ async def update_rag_config(request: Request, form_data: ConfigForm, user=Depend
'WEB_FETCH_MAX_CONTENT_LENGTH': request.app.state.config.WEB_FETCH_MAX_CONTENT_LENGTH,
'WEB_LOADER_CONCURRENT_REQUESTS': request.app.state.config.WEB_LOADER_CONCURRENT_REQUESTS,
'WEB_SEARCH_DOMAIN_FILTER_LIST': request.app.state.config.WEB_SEARCH_DOMAIN_FILTER_LIST,
'WEB_SEARCH_WARNING_ENABLED': request.app.state.config.WEB_SEARCH_WARNING_ENABLED,
'BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL': request.app.state.config.BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL,
'BYPASS_WEB_SEARCH_WEB_LOADER': request.app.state.config.BYPASS_WEB_SEARCH_WEB_LOADER,
'OLLAMA_CLOUD_WEB_SEARCH_API_KEY': request.app.state.config.OLLAMA_CLOUD_WEB_SEARCH_API_KEY,

View file

@ -1,6 +1,7 @@
<script lang="ts">
import { getRAGConfig, updateRAGConfig } from '$lib/apis/retrieval';
import Switch from '$lib/components/common/Switch.svelte';
import { config } from '$lib/stores';
import { models } from '$lib/stores';
import { onMount, getContext } from 'svelte';
@ -151,6 +152,21 @@
</div>
</div>
<div class="mb-2.5 flex w-full justify-between">
<div class="self-center text-xs font-medium">
{$i18n.t('Show Web Search Warning')}
</div>
<div class="flex items-center relative">
<Tooltip
content={$i18n.t(
'Display a warning to users when web search is enabled, informing them that data may be sent externally.'
)}
>
<Switch bind:state={webConfig.WEB_SEARCH_WARNING_ENABLED} />
</Tooltip>
</div>
</div>
<div class=" mb-2.5 flex w-full justify-between">
<div class=" self-center text-xs font-medium">
{$i18n.t('Web Search Engine')}

View file

@ -160,6 +160,31 @@
let selectedValvesItemId = null;
let integrationsMenuCloseOnOutsideClick = true;
export let showWebSearchWarning = false;
// Show banner when web search is enabled (respect both config variants, fallback to true)
$: showWebSearchWarning =
webSearchEnabled &&
(($config?.features as any)?.WEB_SEARCH_WARNING_ENABLED ??
($config?.features as any)?.web_search_warning_enabled ??
false);
// Show toast warning when web search is enabled
let previousWebSearchState = false;
$: {
const warningEnabled =
($config?.features as any)?.WEB_SEARCH_WARNING_ENABLED ??
($config?.features as any)?.web_search_warning_enabled ??
false;
if (webSearchEnabled && !previousWebSearchState && warningEnabled) {
toast.warning($i18n.t('Web search is enabled. Data may be sent to external services.'), {
duration: 4000,
position: 'top-right'
});
}
previousWebSearchState = webSearchEnabled;
}
$: if (!showValvesModal) {
integrationsMenuCloseOnOutsideClick = true;
}
@ -1728,6 +1753,29 @@
{/if}
<div class="ml-1 flex gap-1.5">
{#if showWebSearchWarning}
<div
class="w-full bg-yellow-50 dark:bg-yellow-900/20 border-b border-yellow-200 dark:border-yellow-800 px-4 py-2"
>
<div class="flex items-center justify-between gap-2">
<div class="flex items-center gap-2">
<GlobeAlt class="w-4 h-4 text-yellow-600 dark:text-yellow-500" />
<span class="text-xs text-yellow-800 dark:text-yellow-200 font-medium">
{$i18n.t(
'Web search is enabled. Data may be sent to external services.'
)}
</span>
</div>
<button
class="text-yellow-600 dark:text-yellow-400 hover:text-yellow-800 dark:hover:text-yellow-200"
on:click={() => (showWebSearchWarning = false)}
>
<XMark class="w-4 h-4" />
</button>
</div>
</div>
{/if}
{#if (selectedToolIds ?? []).length > 0}
<Tooltip
content={$i18n.t('{{COUNT}} Available Tools', {