Skip to content
Merged

dev #265

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
7e224e4
refac
tjbck Feb 14, 2026
393c007
refac: manual skill invocation
tjbck Feb 15, 2026
9a2595f
fix: task models issue
tjbck Feb 15, 2026
ce51c48
upd:i18n: Spanish Translation Update v.0.8.0 (#21427)
rgaricano Feb 15, 2026
f2aca78
refac: tool message handling
tjbck Feb 15, 2026
58e923f
Update translation.json (#21441)
Classic298 Feb 15, 2026
f1a1e64
refac: explicit toggle builtin tools
tjbck Feb 15, 2026
f20cc6d
refac
tjbck Feb 15, 2026
e1b3e72
enh: preview image in file modal
tjbck Feb 15, 2026
319d3e8
refac
tjbck Feb 15, 2026
911eeca
fix: disabled mcp display issue
tjbck Feb 16, 2026
b780d5c
refac
tjbck Feb 16, 2026
4a0d893
refac
tjbck Feb 16, 2026
3ae4c61
refac
tjbck Feb 16, 2026
24179cd
fix: preserve trailing slash in MCP server URLs (#21212)
veeceey Feb 16, 2026
7a7d902
refac
tjbck Feb 16, 2026
e10e7d0
chore: changelog (#21424)
Classic298 Feb 16, 2026
d215e46
refac: styling
tjbck Feb 16, 2026
8c5cfa5
refac: styling
tjbck Feb 16, 2026
88401e9
refac
tjbck Feb 16, 2026
38ae91a
refac
tjbck Feb 16, 2026
f96e8f0
refac: styling
tjbck Feb 16, 2026
3330802
refac
tjbck Feb 16, 2026
c748c3e
refac
tjbck Feb 16, 2026
09dc28d
chore: format
tjbck Feb 16, 2026
f4e99c8
refac: "tool_calls" finish reason support
tjbck Feb 16, 2026
6d17de6
chore: bump
tjbck Feb 16, 2026
9e85055
doc: changelog
tjbck Feb 16, 2026
c26e811
enh: renderMarkdownInPreviews
tjbck Feb 16, 2026
5fda814
doc: changelog
tjbck Feb 16, 2026
ef04a70
chore: format
tjbck Feb 16, 2026
ca0983f
i18n: Add missing Russian (ru-RU) translations (#21453)
ashm-dev Feb 16, 2026
15b5f97
fix: prevent scroll jump when editing large messages (#21402)
Algorithm5838 Feb 16, 2026
7c7fe44
Merge pull request #21443 from open-webui/dev
tjbck Feb 16, 2026
519ff40
refac
tjbck Feb 16, 2026
f364b2d
refac
tjbck Feb 16, 2026
0b2abe6
I18n: improve Chinese translation (#21460)
ShirasawaSama Feb 16, 2026
656de56
fix: gracefully handle missing functions when loading models (#21476)
Classic298 Feb 16, 2026
1984ce4
Update Chat.svelte (#21479)
Classic298 Feb 16, 2026
8adf2b3
i18n: (pt-BR): add translations for newly added UI items + consistenc…
joaoback Feb 16, 2026
337109e
refac
tjbck Feb 16, 2026
e5e39be
refac
tjbck Feb 16, 2026
10cfddc
refac: styling
tjbck Feb 16, 2026
f1053d9
refac
tjbck Feb 16, 2026
9be45f4
refac
tjbck Feb 16, 2026
4896d30
chore: changelog (#21474)
Classic298 Feb 16, 2026
15b893e
refac
tjbck Feb 16, 2026
aede1b7
chore: Changelog updates (#21497)
Classic298 Feb 17, 2026
34cd3d7
refac
tjbck Feb 17, 2026
173d563
refac
tjbck Feb 17, 2026
05b8768
refac
tjbck Feb 17, 2026
23b1e2c
refac
tjbck Feb 17, 2026
2ce935b
refac
tjbck Feb 17, 2026
e0bdef8
chore: format
tjbck Feb 17, 2026
ef03652
chore: format
tjbck Feb 17, 2026
61d44aa
refac
tjbck Feb 17, 2026
e5cd1b4
refac
tjbck Feb 17, 2026
4225791
Merge pull request #21458 from open-webui/dev
tjbck Feb 17, 2026
71ccedd
refac
tjbck Feb 17, 2026
b8112d7
Merge pull request #21507 from open-webui/dev
tjbck Feb 17, 2026
bebcde8
Merge remote-tracking branch 'refs/remotes/openwebui/main' into dev
OrenZhang Feb 19, 2026
b9fee91
chore(changelog): update changelog for version 0.8.3.1
OrenZhang Feb 19, 2026
781e1b4
feat(translation): add new phrases for credit and redemption features
OrenZhang Feb 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,49 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.8.3] - 2026-02-17

### Added

- ✏️ **Model edit shortcut.** Users can now edit models directly from the model selector dropdown menu, making it faster to modify model settings without navigating to separate admin or workspace pages. [Commit](https://github.com/open-webui/open-webui/commit/519ff40cb69cdc1d215cee369e9db70ff7438153)
- 🎨 **Image edit API background support.** The image edit API now supports the background parameter for OpenAI's gpt-image-1 model, enabling background transparency control ("transparent", "opaque", "auto") when the feature is exposed in the UI. [#21459](https://github.com/open-webui/open-webui/pull/21459)
- ⚡ **Faster model filtering.** Model access control filtering no longer makes a redundant database query to re-fetch model info that is already available in memory, reducing latency when loading model lists for non-admin users. [Commit](https://github.com/open-webui/open-webui/commit/34cd3d79e8688f589e3dd2f03415f8a8f9a13115)
- 🔧 **Tool call display improvements.** Tool call results now display arguments in a cleaner key-value format instead of raw JSON, with a responsive layout that shows only the tool name on narrow screens and the full label on wider screens, preventing text wrapping to multiple lines. [Commit](https://github.com/open-webui/open-webui/commit/2ce935bdb10d2b26b230cd54cb649f5c667ed96a)
- 🔄 **General improvements.** Various improvements were implemented across the application to enhance performance, stability, and security.
- 🌐 Translations for Portuguese (Brazil), Simplified Chinese, and Traditional Chinese were enhanced and expanded.

### Fixed

- 📧 **USER_EMAIL variable fix.** The {{USER_EMAIL}} template variable now correctly returns the user's email address instead of "Unknown" in prompts. [#21479](https://github.com/open-webui/open-webui/pull/21479), [#21465](https://github.com/open-webui/open-webui/issues/21465)
- 🖼️ **Image and file attachment handling fixes.** Uploaded images are now correctly sent to vision-enabled models, and file attachments now work even when no user text is entered alongside a system prompt. This fixes two issues where the backend was not properly processing file attachments: images weren't converted to the expected format for API requests, and file context was dropped when the user sent only a file without accompanying text. [Commit](https://github.com/open-webui/open-webui/commit/f1053d94c7ef7b8b78682dd73586b65a84d202a1), [#21477](https://github.com/open-webui/open-webui/issues/21477), [#21457](https://github.com/open-webui/open-webui/issues/21457)
- 🛡️ **Missing function error handling.** Models that reference deleted functions no longer cause the entire /api/models endpoint to crash; instead, the missing functions are skipped and logged, allowing the rest of the models to load successfully. [#21476](https://github.com/open-webui/open-webui/pull/21476), [#21464](https://github.com/open-webui/open-webui/issues/21464)
- 🚀 **Startup model pre-fetch error handling.** If model pre-fetching fails during app startup, the application now logs a warning and continues instead of crashing entirely. [Commit](https://github.com/open-webui/open-webui/commit/337109e99ce390f55a9085d0a301853637923779)
- ⚙️ **Function module loading error handling.** Function modules that fail to load during startup or model processing are now caught and logged, preventing crashes when models reference functions with loading errors. [Commit](https://github.com/open-webui/open-webui/commit/15b893e651de71b033408e1b713e0b51f6829ab8)
- 🗄️ **PostgreSQL group query fix.** The '/api/v1/groups/' endpoint no longer fails with a GROUP BY error when using PostgreSQL; member counts are now calculated using correlated subqueries for better database compatibility. [#21458](https://github.com/open-webui/open-webui/pull/21458), [#21467](https://github.com/open-webui/open-webui/issues/21467)

## [0.8.2] - 2026-02-16

### Added

- 🧠 **Skill content handling.** User-selected skills now have their full content injected into the chat, while model-attached skills only display name and description in the available skills list. This allows users to override skill behavior while model-attached skills remain flexible. [Commit](https://github.com/open-webui/open-webui/commit/393c0071dc612c5ac982fb37dfc0288cb9911439)
- ⚙️ **Chat toggles now control built-in tools.** Users can now disable web search, image generation, and code execution on a per-conversation basis, even when those tools are enabled as builtin tools on the model. [#20641](https://github.com/open-webui/open-webui/issues/20641), [#21318](https://github.com/open-webui/open-webui/discussions/21318), [Commit](https://github.com/open-webui/open-webui/commit/c46ef3b63bcc1e2e9adbdd18fab82c4bbe33ff6c), [Commit](https://github.com/open-webui/open-webui/commit/f1a1e64d2e9ad953b2bc2a9543e9a308b7c669c8)
- 🖼️ **Image preview in file modal.** Images uploaded to chats can now be previewed directly in the file management modal, making it easier to identify and manage image files. [#21413](https://github.com/open-webui/open-webui/issues/21413), [Commit](https://github.com/open-webui/open-webui/commit/e1b3e7252c1896c04d498547908f0fce111434e1)
- 🏷️ **Batch tag operations.** Tag creation, deletion, and orphan cleanup for chats now use batch database queries instead of per-tag loops, significantly reducing database round trips when updating, archiving, or deleting chats with multiple tags. [Commit](https://github.com/open-webui/open-webui/commit/c748c3ede)
- 💨 **Faster group list loading.** Group lists and search results now load with a single database query that joins member counts, replacing the previous pattern of fetching groups first and then counting members in a separate batch query. [Commit](https://github.com/open-webui/open-webui/commit/33308022f)
- 🔐 **Skills sharing permissions.** Administrators can now control skills sharing and public sharing permissions per-group, matching the existing capabilities for tools, knowledge, and prompts. [Commit](https://github.com/open-webui/open-webui/commit/88401e91c)
- ⚡ **Long content truncation in preview modals.** Citation and file content modals now truncate markdown-rendered content at 10,000 characters with a "Show all" expansion button, preventing UI jank when previewing very large documents.
- 🌐 **Translation updates.** Translations for Spanish and German were enhanced and expanded.

### Fixed

- 🔐 **OAuth session error handling.** Corrupted OAuth sessions are now gracefully handled and automatically cleaned up instead of causing errors. [Commit](https://github.com/open-webui/open-webui/commit/7e224e4a536b07ec008613f06592e34050e7067c)
- 🐛 **Task model selector validation.** The task model selector in admin settings now correctly accepts models based on the new access grants system instead of rejecting all models with an incorrect error. [Commit](https://github.com/open-webui/open-webui/commit/9a2595f0706d0c9d809ae7746001cf799f98db1d)
- 🔗 **Tool call message preservation.** Models no longer hallucinate tool outputs in multi-turn conversations because tool call history is now properly preserved instead of being merged into assistant messages. [#21098](https://github.com/open-webui/open-webui/discussions/21098), [#20600](https://github.com/open-webui/open-webui/issues/20600), [Commit](https://github.com/open-webui/open-webui/commit/f2aca781c87244cffc130aa2722e700c19a81d66)
- 🔧 **Tool server startup initialization.** External tool servers configured via the "TOOL_SERVER_CONNECTIONS" environment variable now initialize automatically on startup, eliminating the need to manually visit the Admin Panel and save for tools to become available. This enables proper GitOps and containerized deployments. [#18140](https://github.com/open-webui/open-webui/issues/18140), [#20914](https://github.com/open-webui/open-webui/pull/20914), [Commit](https://github.com/open-webui/open-webui/commit/f20cc6d7e6da493eb75ca1618f5cbd068fa57684)
- ♻️ **Resource handle cleanup.** File handles are now properly closed during audio transcription and pipeline uploads, preventing resource leaks that could cause system instability over time. [#21411](https://github.com/open-webui/open-webui/issues/21411)
- ⌨️ **Strikethrough shortcut conflict fix.** Pressing Ctrl+Shift+S to toggle the sidebar no longer causes text to become struck through in the chat input, by disabling the TipTap Strike extension's default keyboard shortcut when rich text mode is off. [Commit](https://github.com/open-webui/open-webui/commit/38ae91ae2)
- 🔧 **Tool call finish_reason fix.** API responses now correctly set finish_reason to "tool_calls" instead of "stop" when tool calls are present, fixing an issue where external API clients (such as OpenCode) would halt prematurely after tool execution when routing Ollama models through the Open WebUI API. [#20896](https://github.com/open-webui/open-webui/issues/20896)

## [0.8.1] - 2026-02-14

### Added
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG_EXTRA.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.8.3.1] - 2026.02.19

### Changed

- 合并官方 0.8.3 改动

## [0.8.1.1] - 2026.02.14

### Changed
Expand Down
14 changes: 14 additions & 0 deletions backend/open_webui/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,18 @@ def reachable(host: str, port: int) -> bool:
== "true"
)

USER_PERMISSIONS_WORKSPACE_SKILLS_ALLOW_SHARING = (
os.environ.get("USER_PERMISSIONS_WORKSPACE_SKILLS_ALLOW_SHARING", "False").lower()
== "true"
)

USER_PERMISSIONS_WORKSPACE_SKILLS_ALLOW_PUBLIC_SHARING = (
os.environ.get(
"USER_PERMISSIONS_WORKSPACE_SKILLS_ALLOW_PUBLIC_SHARING", "False"
).lower()
== "true"
)

USER_PERMISSIONS_NOTES_ALLOW_SHARING = (
os.environ.get("USER_PERMISSIONS_NOTES_ALLOW_SHARING", "False").lower() == "true"
)
Expand Down Expand Up @@ -1506,6 +1518,8 @@ def reachable(host: str, port: int) -> bool:
"public_prompts": USER_PERMISSIONS_WORKSPACE_PROMPTS_ALLOW_PUBLIC_SHARING,
"tools": USER_PERMISSIONS_WORKSPACE_TOOLS_ALLOW_SHARING,
"public_tools": USER_PERMISSIONS_WORKSPACE_TOOLS_ALLOW_PUBLIC_SHARING,
"skills": USER_PERMISSIONS_WORKSPACE_SKILLS_ALLOW_SHARING,
"public_skills": USER_PERMISSIONS_WORKSPACE_SKILLS_ALLOW_PUBLIC_SHARING,
"notes": USER_PERMISSIONS_NOTES_ALLOW_SHARING,
"public_notes": USER_PERMISSIONS_NOTES_ALLOW_PUBLIC_SHARING,
},
Expand Down
42 changes: 36 additions & 6 deletions backend/open_webui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
MODELS,
app as socket_app,
periodic_usage_pool_cleanup,
periodic_session_pool_cleanup,
get_event_emitter,
get_models_in_use,
)
Expand Down Expand Up @@ -540,6 +541,7 @@
process_chat_payload,
process_chat_response,
)
from open_webui.utils.tools import set_tool_servers

from open_webui.utils.auth import (
get_license_data,
Expand Down Expand Up @@ -657,11 +659,37 @@ async def lifespan(app: FastAPI):
limiter.total_tokens = THREAD_POOL_SIZE

asyncio.create_task(periodic_usage_pool_cleanup())
asyncio.create_task(periodic_session_pool_cleanup())

if app.state.config.ENABLE_BASE_MODELS_CACHE:
await get_all_models(
Request(
# Creating a mock request object to pass to get_all_models
try:
await get_all_models(
Request(
# Creating a mock request object to pass to get_all_models
{
"type": "http",
"asgi.version": "3.0",
"asgi.spec_version": "2.0",
"method": "GET",
"path": "/internal",
"query_string": b"",
"headers": Headers({}).raw,
"client": ("127.0.0.1", 12345),
"server": ("127.0.0.1", 80),
"scheme": "http",
"app": app,
}
),
None,
)
except Exception as e:
log.warning(f"Failed to pre-fetch models at startup: {e}")

# Pre-fetch tool server specs so the first request doesn't pay the latency cost
if len(app.state.config.TOOL_SERVER_CONNECTIONS) > 0:
log.info("Initializing tool servers...")
try:
mock_request = Request(
{
"type": "http",
"asgi.version": "3.0",
Expand All @@ -675,9 +703,11 @@ async def lifespan(app: FastAPI):
"scheme": "http",
"app": app,
}
),
None,
)
)
await set_tool_servers(mock_request)
log.info(f"Initialized {len(app.state.TOOL_SERVERS)} tool server(s)")
except Exception as e:
log.warning(f"Failed to initialize tool servers at startup: {e}")

yield

Expand Down
84 changes: 50 additions & 34 deletions backend/open_webui/models/chats.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,22 +431,29 @@ def update_chat_title_by_id(self, id: str, title: str) -> Optional[ChatModel]:
def update_chat_tags_by_id(
self, id: str, tags: list[str], user
) -> Optional[ChatModel]:
chat = self.get_chat_by_id(id)
if chat is None:
return None
with get_db_context() as db:
chat = db.get(Chat, id)
if chat is None:
return None

old_tags = chat.meta.get("tags", [])
new_tags = [t for t in tags if t.replace(" ", "_").lower() != "none"]
new_tag_ids = [t.replace(" ", "_").lower() for t in new_tags]

self.delete_all_tags_by_id_and_user_id(id, user.id)
# Single meta update
chat.meta = {**chat.meta, "tags": new_tag_ids}
db.commit()
db.refresh(chat)

for tag in chat.meta.get("tags", []):
if self.count_chats_by_tag_name_and_user_id(tag, user.id) == 0:
Tags.delete_tag_by_name_and_user_id(tag, user.id)
# Batch-create any missing tag rows
Tags.ensure_tags_exist(new_tags, user.id, db=db)

for tag_name in tags:
if tag_name.lower() == "none":
continue
# Clean up orphaned old tags in one query
removed = set(old_tags) - set(new_tag_ids)
if removed:
self.delete_orphan_tags_for_user(list(removed), user.id, db=db)

self.add_chat_tag_by_id_and_user_id_and_tag_name(id, user.id, tag_name)
return self.get_chat_by_id(id)
return ChatModel.model_validate(chat)

def get_chat_title_by_id(self, id: str) -> Optional[str]:
chat = self.get_chat_by_id(id)
Expand Down Expand Up @@ -1267,8 +1274,8 @@ def get_chat_tags_by_id_and_user_id(
) -> list[TagModel]:
with get_db_context(db) as db:
chat = db.get(Chat, id)
tags = chat.meta.get("tags", [])
return [Tags.get_tag_by_name_and_user_id(tag, user_id) for tag in tags]
tag_ids = chat.meta.get("tags", [])
return Tags.get_tags_by_ids_and_user_id(tag_ids, user_id, db=db)

def get_chat_list_by_user_id_and_tag_name(
self,
Expand Down Expand Up @@ -1309,20 +1316,16 @@ def get_chat_list_by_user_id_and_tag_name(
def add_chat_tag_by_id_and_user_id_and_tag_name(
self, id: str, user_id: str, tag_name: str, db: Optional[Session] = None
) -> Optional[ChatModel]:
tag = Tags.get_tag_by_name_and_user_id(tag_name, user_id)
if tag is None:
tag = Tags.insert_new_tag(tag_name, user_id)
tag_id = tag_name.replace(" ", "_").lower()
Tags.ensure_tags_exist([tag_name], user_id, db=db)
try:
with get_db_context(db) as db:
chat = db.get(Chat, id)

tag_id = tag.id
if tag_id not in chat.meta.get("tags", []):
chat.meta = {
**chat.meta,
"tags": list(set(chat.meta.get("tags", []) + [tag_id])),
}

db.commit()
db.refresh(chat)
return ChatModel.model_validate(chat)
Expand All @@ -1332,40 +1335,53 @@ def add_chat_tag_by_id_and_user_id_and_tag_name(
def count_chats_by_tag_name_and_user_id(
self, tag_name: str, user_id: str, db: Optional[Session] = None
) -> int:
with get_db_context(db) as db: # Assuming `get_db()` returns a session object
with get_db_context(db) as db:
query = db.query(Chat).filter_by(user_id=user_id, archived=False)

# Normalize the tag_name for consistency
tag_id = tag_name.replace(" ", "_").lower()

if db.bind.dialect.name == "sqlite":
# SQLite JSON1 support for querying the tags inside the `meta` JSON field
query = query.filter(
text(
f"EXISTS (SELECT 1 FROM json_each(Chat.meta, '$.tags') WHERE json_each.value = :tag_id)"
"EXISTS (SELECT 1 FROM json_each(Chat.meta, '$.tags') WHERE json_each.value = :tag_id)"
)
).params(tag_id=tag_id)

elif db.bind.dialect.name == "postgresql":
# PostgreSQL JSONB support for querying the tags inside the `meta` JSON field
query = query.filter(
text(
"EXISTS (SELECT 1 FROM json_array_elements_text(Chat.meta->'tags') elem WHERE elem = :tag_id)"
)
).params(tag_id=tag_id)

else:
raise NotImplementedError(
f"Unsupported dialect: {db.bind.dialect.name}"
)

# Get the count of matching records
count = query.count()

# Debugging output for inspection
log.info(f"Count of chats for tag '{tag_name}': {count}")
return query.count()

return count
def delete_orphan_tags_for_user(
self,
tag_ids: list[str],
user_id: str,
threshold: int = 0,
db: Optional[Session] = None,
) -> None:
"""Delete tag rows from *tag_ids* that appear in at most *threshold*
non-archived chats for *user_id*. One query to find orphans, one to
delete them.

Use threshold=0 after a tag is already removed from a chat's meta.
Use threshold=1 when the chat itself is about to be deleted (the
referencing chat still exists at query time).
"""
if not tag_ids:
return
with get_db_context(db) as db:
orphans = []
for tag_id in tag_ids:
count = self.count_chats_by_tag_name_and_user_id(tag_id, user_id, db=db)
if count <= threshold:
orphans.append(tag_id)
Tags.delete_tags_by_ids_and_user_id(orphans, user_id, db=db)

def count_chats_by_folder_id_and_user_id(
self, folder_id: str, user_id: str, db: Optional[Session] = None
Expand Down
Loading