diff --git a/CHANGELOG.md b/CHANGELOG.md index e3b55599fddc..3df9f2e702ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ 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.11.3] - 2026-08-31 + +### Added + +- ♿ **Accessibility mode reaches the menus.** Accessibility mode now marks the menu entry you are pointing at and the model already chosen with a stronger background, across the dropdown menus, their submenus, and the model picker together with its filter and compare controls, so those cues carry the contrast the accessibility guidelines ask for in both themes. [Commit](https://github.com/open-webui/open-webui/commit/a6f9751401589ee73208295b6f6a7f6eae9c1b44), [Commit](https://github.com/open-webui/open-webui/commit/471b5cbbb16c3996c32e68808dde6f8898f64ecd) +- 🔄 **General improvements.** Various improvements were implemented across the application to enhance performance, stability, and security. +- 🌐 **Translation updates.** Translations for Indonesian were enhanced and expanded. + +### Fixed + +- 💥 **Chat branches stay connected after reloads.** A reply saved under an earlier message now stays listed under that message, so branch arrows, exports, reloads, and later edits keep the whole conversation in view, and chats already saved with that link missing are repaired when opened. [#29299](https://github.com/open-webui/open-webui/issues/29299) +- 🧱 **Upgrades fail clearly instead of starting half updated.** A failed database upgrade now stops at the migration error that caused it, instead of starting anyway and reporting a missing table or column such as 'chat.timer_at' later, which is the upgrade failure seen after moving from 0.11.0, 0.11.1, or 0.11.2. [#29280](https://github.com/open-webui/open-webui/issues/29280) +- 🔤 **Custom interface fonts reach more of the app.** The font chosen in interface settings now applies to dropdowns and other interface text that previously fell back to the standard font. [Commit](https://github.com/open-webui/open-webui/commit/1457000ba66547b24bd98012aa35ac16fd4bc696) +- 🔌 **Disconnect OAuth only where there is OAuth.** The disconnect control on a tool server reached over MCP now appears only where that server signs in through OAuth and an account is connected, rather than on servers that use no sign-in at all. [#29296](https://github.com/open-webui/open-webui/issues/29296) + ## [0.11.2] - 2026-08-31 ### Added diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index acd3d83bf8f8..a0855f46897b 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -74,6 +74,7 @@ def run_migrations(): command.upgrade(alembic_cfg, 'head') except Exception as e: log.exception(f'Error running migrations: {e}') + raise if ENABLE_DB_MIGRATIONS: diff --git a/backend/open_webui/models/calendar.py b/backend/open_webui/models/calendar.py index 835313c70342..3a3147a7ad03 100644 --- a/backend/open_webui/models/calendar.py +++ b/backend/open_webui/models/calendar.py @@ -8,7 +8,6 @@ from open_webui.models.access_grants import AccessGrantModel, AccessGrants from open_webui.models.groups import Groups from open_webui.models.users import User, UserModel, UserResponse -from open_webui.utils.automations import rrule_interval_seconds from pydantic import BaseModel, ConfigDict, Field, field_validator from sqlalchemy import ( JSON, @@ -198,6 +197,8 @@ class CalendarEventForm(BaseModel): @classmethod def reject_sub_daily_rrule(cls, value: Optional[str]) -> Optional[str]: if value: + from open_webui.utils.automations import rrule_interval_seconds + try: interval = rrule_interval_seconds(value) except ValueError: @@ -228,6 +229,8 @@ class CalendarEventUpdateForm(BaseModel): @classmethod def reject_sub_daily_rrule(cls, value: Optional[str]) -> Optional[str]: if value: + from open_webui.utils.automations import rrule_interval_seconds + try: interval = rrule_interval_seconds(value) except ValueError: diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index 978cb2948f0d..fc972cb4bc58 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -456,6 +456,23 @@ def _last_descendant_id(messages: dict, message_id: str) -> str: message_id = next_id return message_id + @staticmethod + def _add_child_id_to_parent(messages: dict, parent_id: str | None, child_id: str) -> bool: + parent = messages.get(parent_id) if parent_id else None + if not isinstance(parent, dict): + return False + + child_ids = parent.get('childrenIds') + if not isinstance(child_ids, list): + child_ids = [] + parent['childrenIds'] = child_ids + + if child_id in child_ids: + return False + + child_ids.append(child_id) + return True + def _repair_chat_current_id(self, chat: dict) -> bool: history = chat.get('history') if not isinstance(history, dict): @@ -465,6 +482,12 @@ def _repair_chat_current_id(self, chat: dict) -> bool: if not isinstance(messages, dict): return False + changed = False + for message_id, message in messages.items(): + if not isinstance(message, dict): + continue + changed = self._add_child_id_to_parent(messages, message.get('parentId'), message_id) or changed + current_id = history.get('currentId') current_message = messages.get(current_id) output = [] @@ -494,7 +517,7 @@ def _repair_chat_current_id(self, chat: dict) -> bool: history['currentId'] = last_descendant_id return True - return False + return changed latest_leaf_id = None latest_timestamp = -1 @@ -509,7 +532,7 @@ def _repair_chat_current_id(self, chat: dict) -> bool: latest_timestamp = timestamp if not latest_leaf_id or latest_leaf_id == current_id: - return False + return changed history['currentId'] = latest_leaf_id return True @@ -998,6 +1021,8 @@ def upsert_message_to_history(history: dict, message_id: str, message: dict) -> 'timestamp': message.get('timestamp') or int(time.time()), } history['currentId'] = message_id + + ChatTable._add_child_id_to_parent(messages, messages[message_id].get('parentId'), message_id) return messages[message_id] async def backfill_messages_by_chat_id(self, chat_id: str, user_id: str, messages: dict[str, dict]) -> None: diff --git a/backend/open_webui/routers/images.py b/backend/open_webui/routers/images.py index 51570000c58d..f08705546b73 100644 --- a/backend/open_webui/routers/images.py +++ b/backend/open_webui/routers/images.py @@ -918,6 +918,14 @@ async def load_url_image(data): return data if data.startswith('http://') or data.startswith('https://'): + parsed = urlparse(data) + if ( + parsed.netloc == urlparse(str(request.base_url)).netloc + and parsed.path.startswith('/api/v1/files/') + and '/content' in parsed.path + ): + return await load_url_image(parsed.path) + # Validate URL to prevent SSRF attacks against local/private networks. # allow_redirects=False prevents redirect-based SSRF: validate_url() is # called only on the originally-submitted URL; following 3xx redirects diff --git a/package-lock.json b/package-lock.json index 3107b719b47b..de3ebe7d0cf6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "open-webui", - "version": "0.11.2", + "version": "0.11.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "open-webui", - "version": "0.11.2", + "version": "0.11.3", "dependencies": { "@azure/msal-browser": "^4.5.0", "@codemirror/lang-javascript": "^6.2.2", diff --git a/package.json b/package.json index f0fd6a4e6567..cb87387f08ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-webui", - "version": "0.11.2", + "version": "0.11.3", "private": true, "scripts": { "dev": "npm run pyodide:fetch && vite dev --host", diff --git a/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte b/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte index 17a4a308e018..7d21661764ee 100644 --- a/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte +++ b/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte @@ -524,7 +524,7 @@ - {#if (tools?.[toolId]?.authenticated ?? true) && toolId.startsWith('server:mcp:')} + {#if tools?.[toolId]?.authenticated === true && toolId.startsWith('server:mcp:')}