diff --git a/CHANGELOG.md b/CHANGELOG.md index e3b55599fd..3df9f2e702 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 acd3d83bf8..a0855f4689 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 835313c703..3a3147a7ad 100644 --- a/backend/open_webui/models/calendar.py +++ b/backend/open_webui/models/calendar.py @@ -8,7 +8,6 @@ from open_webui.constants import ERROR_MESSAGES 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 978cb2948f..fc972cb4bc 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -456,6 +456,23 @@ class ChatTable: 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 @@ class ChatTable: 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 @@ class ChatTable: history['currentId'] = last_descendant_id return True - return False + return changed latest_leaf_id = None latest_timestamp = -1 @@ -509,7 +532,7 @@ class ChatTable: 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 @@ class ChatTable: '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 51570000c5..f08705546b 100644 --- a/backend/open_webui/routers/images.py +++ b/backend/open_webui/routers/images.py @@ -918,6 +918,14 @@ async def image_edits( 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 3107b719b4..de3ebe7d0c 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 f0fd6a4e65..cb87387f08 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 17a4a308e0..7d21661764 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:')}