Skip to content

Commit e4e69a1

Browse files
authored
Merge pull request open-webui#22469 from open-webui/dev
0.8.10
2 parents 6c159a9 + c6a1469 commit e4e69a1

File tree

102 files changed

+2781
-1680
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+2781
-1680
lines changed

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,39 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.8.10] - 2026-03-08
9+
10+
### Added
11+
12+
- 🔐 **Custom OIDC logout endpoint.** Administrators can now configure a custom OpenID Connect logout URL via OPENID_END_SESSION_ENDPOINT, enabling logout functionality for OIDC providers that require custom endpoints like AWS Cognito. [Commit](https://github.com/open-webui/open-webui/commit/3f350f865920daf2844769a758b2d2e6a7ee3efa)
13+
- 🗄️ **MariaDB Vector community support.** Added MariaDB Vector as a new vector database backend, enabling deployments with VECTOR_DB=mariadb-vector; supports cosine and euclidean distance strategies with configurable HNSW indexing. [#21931](https://github.com/open-webui/open-webui/pull/21931)
14+
- 📝 **Task message truncation.** Chat messages sent to task models for title and tag generation can now be truncated using a filter in the prompt template, reducing token usage and processing time for long conversations. [#21499](https://github.com/open-webui/open-webui/issues/21499)
15+
- 🔄 **General improvements.** Various improvements were implemented across the application to enhance performance, stability, and security.
16+
- 🌐 Translations for Portuguese (Brazil), Spanish, and Malay were enhanced and expanded.
17+
18+
### Fixed
19+
20+
- 🔗 **Pipeline filter HTTP errors.** Fixed a bug where HTTP errors in pipeline inlet/outlet filters would silently corrupt the user's chat payload; errors are now properly raised before parsing the response. [#22445](https://github.com/open-webui/open-webui/pull/22445)
21+
- 📚 **Knowledge file embedding updates.** Fixed a bug where updating knowledge files left old embeddings in the database, causing search results to include duplicate and stale data. [#20558](https://github.com/open-webui/open-webui/issues/20558)
22+
- 📁 **Files list stability.** Fixed the files list ordering to use created_at with id as secondary sort, ensuring consistent ordering and preventing page crashes when managing many files. [#21879](https://github.com/open-webui/open-webui/issues/21879)
23+
- 📨 **Teams webhook crash.** Fixed a TypeError crash in the Teams webhook handler when user data is missing from the event payload. [#22444](https://github.com/open-webui/open-webui/pull/22444)
24+
- 🛠️ **Process shutdown handling.** Fixed bare except clauses in the main process that prevented clean shutdown; replaced with proper exception handling. [#22423](https://github.com/open-webui/open-webui/pull/22423)
25+
- 🐳 **Docker deployment startup.** Docker deployments now start correctly; the missing OpenTelemetry system metrics dependency was added. [#22447](https://github.com/open-webui/open-webui/pull/22447), [#22401](https://github.com/open-webui/open-webui/issues/22401)
26+
- 🛠️ **Tool access for non-admin users.** Fixed a NameError that prevented non-admin users from viewing tools; the missing has_access function is now properly imported. [#22393](https://github.com/open-webui/open-webui/issues/22393)
27+
- 🔐 **OAuth error handling.** Fixed a bug where bare except clauses silently caught SystemExit and KeyboardInterrupt, preventing clean process shutdown during OAuth authentication. [#22420](https://github.com/open-webui/open-webui/pull/22420)
28+
- 🛠️ **Exception error messages.** Fixed three locations where incorrect exception raising caused confusing TypeError messages instead of proper error descriptions, making debugging much easier. [#22446](https://github.com/open-webui/open-webui/pull/22446)
29+
- 📄 **YAML file processing.** Fixed an error when uploading YAML files with Docling enabled; YAML and YML files are now properly recognized as text files and processed correctly. [#22399](https://github.com/open-webui/open-webui/pull/22399), [#22263](https://github.com/open-webui/open-webui/issues/22263)
30+
- 📅 **Time range month names.** Fixed month names in time range labels appearing in the wrong language when OS regional settings differ from browser language; month names now consistently display in English. [#22454](https://github.com/open-webui/open-webui/pull/22454)
31+
- 🔐 **OAuth error URL encoding.** Fixed OAuth error messages with special characters causing malformed redirect URLs; error messages are now properly URL-encoded. [#22415](https://github.com/open-webui/open-webui/pull/22415)
32+
- 🛠️ **Internal tool method filtering.** Tools no longer expose internal methods starting with underscore to the LLM, reducing clutter and improving accuracy. [#22408](https://github.com/open-webui/open-webui/pull/22408)
33+
- 🔊 **Azure TTS locale extraction.** Fixed Azure text-to-speech using incomplete locale codes in SSML; now correctly uses full locale like "en-US" instead of just "en". [#22443](https://github.com/open-webui/open-webui/pull/22443)
34+
- 🎤 **Azure speech transcription errors.** Improved Azure AI Speech error handling to display user-friendly messages instead of generic connection errors; empty transcripts, no language identified, and other Azure-specific errors now show clear descriptions. [#20485](https://github.com/open-webui/open-webui/issues/20485)
35+
- 📊 **Analytics group filtering.** Fixed token usage analytics not being filtered by user group; the query now properly respects group filters like other analytics metrics. [#22167](https://github.com/open-webui/open-webui/pull/22167)
36+
- 🔍 **Web search favicon fallback.** Fixed web search sources showing broken image icons when favicons couldn't be loaded from external sources; now falls back to the default Open WebUI favicon. [#21897](https://github.com/open-webui/open-webui/pull/21897)
37+
- 🔄 **Custom model fallback.** Fixed custom model fallback not working when the base model is unavailable; the base model ID is now correctly retrieved from model info instead of empty params. [#22456](https://github.com/open-webui/open-webui/issues/22456)
38+
- 🖼️ **Pending message image display.** Fixed images in queued messages appearing blank; image thumbnails are now properly displayed in the pending message queue. [#22256](https://github.com/open-webui/open-webui/issues/22256)
39+
- 🛠️ **File metadata sanitization.** Fixed file uploads failing with JSON serialization errors when metadata contained non-serializable objects like callable functions; metadata is now sanitized before database insertion. [#20561](https://github.com/open-webui/open-webui/issues/20561)
40+
841
## [0.8.9] - 2026-03-07
942

1043
### Added

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ RUN chown -R $UID:$GID /app $HOME
127127
RUN apt-get update && \
128128
apt-get install -y --no-install-recommends \
129129
git build-essential pandoc gcc netcat-openbsd curl jq \
130+
libmariadb-dev \
130131
python3-dev \
131132
ffmpeg libsm6 libxext6 zstd \
132133
&& rm -rf /var/lib/apt/lists/*

backend/open_webui/config.py

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,12 @@ def __getattr__(self, key):
469469
os.environ.get("OPENID_PROVIDER_URL", ""),
470470
)
471471

472+
OPENID_END_SESSION_ENDPOINT = PersistentConfig(
473+
"OPENID_END_SESSION_ENDPOINT",
474+
"oauth.oidc.end_session_endpoint",
475+
os.environ.get("OPENID_END_SESSION_ENDPOINT", ""),
476+
)
477+
472478
OPENID_REDIRECT_URI = PersistentConfig(
473479
"OPENID_REDIRECT_URI",
474480
"oauth.oidc.redirect_uri",
@@ -844,13 +850,18 @@ def feishu_oauth_register(oauth: OAuth):
844850
if FEISHU_CLIENT_ID.value:
845851
configured_providers.append("Feishu")
846852

847-
if configured_providers and not OPENID_PROVIDER_URL.value:
853+
if (
854+
configured_providers
855+
and not OPENID_PROVIDER_URL.value
856+
and not OPENID_END_SESSION_ENDPOINT.value
857+
):
848858
provider_list = ", ".join(configured_providers)
849859
log.warning(
850860
f"⚠️ OAuth providers configured ({provider_list}) but OPENID_PROVIDER_URL not set - logout will not work!"
851861
)
852862
log.warning(
853-
f"Set OPENID_PROVIDER_URL to your OAuth provider's OpenID Connect discovery endpoint to fix logout functionality."
863+
f"Set OPENID_PROVIDER_URL to your OAuth provider's OpenID Connect discovery endpoint,"
864+
f" or set OPENID_END_SESSION_ENDPOINT to a custom logout URL to fix logout functionality."
854865
)
855866

856867

@@ -2359,6 +2370,81 @@ class BannerModel(BaseModel):
23592370
CHROMA_HTTP_SSL = os.environ.get("CHROMA_HTTP_SSL", "false").lower() == "true"
23602371
# this uses the model defined in the Dockerfile ENV variable. If you dont use docker or docker based deployments such as k8s, the default embedding model will be used (sentence-transformers/all-MiniLM-L6-v2)
23612372

2373+
2374+
# MariaDB Vector (mariadb-vector)
2375+
MARIADB_VECTOR_DB_URL = os.environ.get("MARIADB_VECTOR_DB_URL", "").strip()
2376+
2377+
MARIADB_VECTOR_INITIALIZE_MAX_VECTOR_LENGTH = int(
2378+
os.environ.get("MARIADB_VECTOR_INITIALIZE_MAX_VECTOR_LENGTH", "1536").strip()
2379+
or "1536"
2380+
)
2381+
2382+
# Distance strategy:
2383+
# - cosine => vec_distance_cosine(...)
2384+
# - euclidean => vec_distance_euclidean(...)
2385+
MARIADB_VECTOR_DISTANCE_STRATEGY = (
2386+
os.environ.get("MARIADB_VECTOR_DISTANCE_STRATEGY", "cosine").strip().lower()
2387+
)
2388+
2389+
# HNSW M parameter (MariaDB VECTOR INDEX ... M=<int>)
2390+
MARIADB_VECTOR_INDEX_M = int(
2391+
os.environ.get("MARIADB_VECTOR_INDEX_M", "8").strip() or "8"
2392+
)
2393+
2394+
# Pooling (MariaDB-Vector)
2395+
MARIADB_VECTOR_POOL_SIZE = os.environ.get("MARIADB_VECTOR_POOL_SIZE", None)
2396+
2397+
if MARIADB_VECTOR_POOL_SIZE != None:
2398+
try:
2399+
MARIADB_VECTOR_POOL_SIZE = int(MARIADB_VECTOR_POOL_SIZE)
2400+
except Exception:
2401+
MARIADB_VECTOR_POOL_SIZE = None
2402+
2403+
MARIADB_VECTOR_POOL_MAX_OVERFLOW = os.environ.get("MARIADB_VECTOR_POOL_MAX_OVERFLOW", 0)
2404+
2405+
if MARIADB_VECTOR_POOL_MAX_OVERFLOW == "":
2406+
MARIADB_VECTOR_POOL_MAX_OVERFLOW = 0
2407+
else:
2408+
try:
2409+
MARIADB_VECTOR_POOL_MAX_OVERFLOW = int(MARIADB_VECTOR_POOL_MAX_OVERFLOW)
2410+
except Exception:
2411+
MARIADB_VECTOR_POOL_MAX_OVERFLOW = 0
2412+
2413+
MARIADB_VECTOR_POOL_TIMEOUT = os.environ.get("MARIADB_VECTOR_POOL_TIMEOUT", 30)
2414+
2415+
if MARIADB_VECTOR_POOL_TIMEOUT == "":
2416+
MARIADB_VECTOR_POOL_TIMEOUT = 30
2417+
else:
2418+
try:
2419+
MARIADB_VECTOR_POOL_TIMEOUT = int(MARIADB_VECTOR_POOL_TIMEOUT)
2420+
except Exception:
2421+
MARIADB_VECTOR_POOL_TIMEOUT = 30
2422+
2423+
MARIADB_VECTOR_POOL_RECYCLE = os.environ.get("MARIADB_VECTOR_POOL_RECYCLE", 3600)
2424+
2425+
if MARIADB_VECTOR_POOL_RECYCLE == "":
2426+
MARIADB_VECTOR_POOL_RECYCLE = 3600
2427+
else:
2428+
try:
2429+
MARIADB_VECTOR_POOL_RECYCLE = int(MARIADB_VECTOR_POOL_RECYCLE)
2430+
except Exception:
2431+
MARIADB_VECTOR_POOL_RECYCLE = 3600
2432+
2433+
ENABLE_MARIADB_VECTOR = True
2434+
if VECTOR_DB == "mariadb-vector":
2435+
if not MARIADB_VECTOR_DB_URL:
2436+
ENABLE_MARIADB_VECTOR = False
2437+
else:
2438+
try:
2439+
parsed = urlparse(MARIADB_VECTOR_DB_URL)
2440+
scheme = (parsed.scheme or "").lower()
2441+
# Require official driver so VECTOR binds as float32 bytes correctly
2442+
if scheme != "mariadb+mariadbconnector":
2443+
ENABLE_MARIADB_VECTOR = False
2444+
except Exception:
2445+
ENABLE_MARIADB_VECTOR = False
2446+
2447+
23622448
# Milvus
23632449
MILVUS_URI = os.environ.get("MILVUS_URI", f"{DATA_DIR}/vector_db/milvus.db")
23642450
MILVUS_DB = os.environ.get("MILVUS_DB", "default")

backend/open_webui/main.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,8 +1732,8 @@ async def chat_completion(
17321732
}
17331733

17341734
# Check base model existence for custom models
1735-
if model_info_params.get("base_model_id"):
1736-
base_model_id = model_info_params.get("base_model_id")
1735+
if model_info and model_info.base_model_id:
1736+
base_model_id = model_info.base_model_id
17371737
if base_model_id not in request.app.state.MODELS:
17381738
if ENABLE_CUSTOM_MODEL_FALLBACK:
17391739
default_models = (
@@ -1864,7 +1864,7 @@ async def process_chat(request, form_data, user, metadata, model):
18641864
"model": model_id,
18651865
},
18661866
)
1867-
except:
1867+
except Exception:
18681868
pass
18691869

18701870
ctx = build_chat_response_context(
@@ -1911,7 +1911,7 @@ async def process_chat(request, form_data, user, metadata, model):
19111911
{"type": "chat:tasks:cancel"},
19121912
)
19131913

1914-
except:
1914+
except Exception:
19151915
pass
19161916
finally:
19171917
try:

backend/open_webui/models/chat_messages.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,11 +420,13 @@ def get_token_usage_by_user(
420420
self,
421421
start_date: Optional[int] = None,
422422
end_date: Optional[int] = None,
423+
group_id: Optional[str] = None,
423424
db: Optional[Session] = None,
424425
) -> dict[str, dict]:
425426
"""Aggregate token usage by user using database-level aggregation."""
426427
with get_db_context(db) as db:
427428
from sqlalchemy import func, cast, Integer
429+
from open_webui.models.groups import GroupMember
428430

429431
dialect = db.bind.dialect.name
430432

@@ -464,6 +466,13 @@ def get_token_usage_by_user(
464466
query = query.filter(ChatMessage.created_at >= start_date)
465467
if end_date:
466468
query = query.filter(ChatMessage.created_at <= end_date)
469+
if group_id:
470+
group_users = (
471+
db.query(GroupMember.user_id)
472+
.filter(GroupMember.group_id == group_id)
473+
.subquery()
474+
)
475+
query = query.filter(ChatMessage.user_id.in_(group_users))
467476

468477
results = query.group_by(ChatMessage.user_id).all()
469478

backend/open_webui/models/files.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from sqlalchemy.orm import Session
66
from open_webui.internal.db import Base, JSONField, get_db, get_db_context
7+
from open_webui.utils.misc import sanitize_metadata
78
from pydantic import BaseModel, ConfigDict, model_validator
89
from sqlalchemy import BigInteger, Column, String, Text, JSON
910

@@ -127,9 +128,16 @@ def insert_new_file(
127128
self, user_id: str, form_data: FileForm, db: Optional[Session] = None
128129
) -> Optional[FileModel]:
129130
with get_db_context(db) as db:
131+
file_data = form_data.model_dump()
132+
133+
# Sanitize meta to remove non-JSON-serializable objects
134+
# (e.g. callable tool functions, MCP client instances from middleware)
135+
if file_data.get("meta"):
136+
file_data["meta"] = sanitize_metadata(file_data["meta"])
137+
130138
file = FileModel(
131139
**{
132-
**form_data.model_dump(),
140+
**file_data,
133141
"user_id": user_id,
134142
"created_at": int(time.time()),
135143
"updated_at": int(time.time()),
@@ -289,7 +297,7 @@ def search_files(
289297
db: Optional database session.
290298
291299
Returns:
292-
List of matching FileModel objects, ordered by updated_at descending.
300+
List of matching FileModel objects, ordered by created_at descending.
293301
"""
294302
with get_db_context(db) as db:
295303
query = db.query(File)
@@ -303,7 +311,7 @@ def search_files(
303311

304312
return [
305313
FileModel.model_validate(file)
306-
for file in query.order_by(File.updated_at.desc())
314+
for file in query.order_by(File.created_at.desc(), File.id.desc())
307315
.offset(skip)
308316
.limit(limit)
309317
.all()

backend/open_webui/retrieval/loaders/main.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@
8686
"hs",
8787
"lhs",
8888
"json",
89+
"yaml",
90+
"yml",
91+
"toml",
8992
]
9093

9194

backend/open_webui/retrieval/utils.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,9 @@ def generate_openai_batch_embeddings(
590590
if "data" in data:
591591
return [elem["embedding"] for elem in data["data"]]
592592
else:
593-
raise "Something went wrong :/"
593+
raise ValueError(
594+
"Unexpected OpenAI embeddings response: missing 'data' key"
595+
)
594596
except Exception as e:
595597
log.exception(f"Error generating openai batch embeddings: {e}")
596598
return None
@@ -767,7 +769,9 @@ def generate_ollama_batch_embeddings(
767769
if "embeddings" in data:
768770
return data["embeddings"]
769771
else:
770-
raise "Something went wrong :/"
772+
raise ValueError(
773+
"Unexpected Ollama embeddings response: missing 'embeddings' key"
774+
)
771775
except Exception as e:
772776
log.exception(f"Error generating ollama batch embeddings: {e}")
773777
return None

backend/open_webui/retrieval/vector/dbs/elasticsearch.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
"""
2+
NOTE: This vector database integration is community-supported and maintained on a best-effort basis.
3+
"""
4+
15
from elasticsearch import Elasticsearch, BadRequestError
26
from typing import Optional
37
import ssl

0 commit comments

Comments
 (0)