Skip to content

Commit 37d1c85

Browse files
authored
Merge pull request open-webui#17827 from open-webui/dev
0.6.32
2 parents 598282c + b6a4853 commit 37d1c85

File tree

160 files changed

+5592
-1467
lines changed

Some content is hidden

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

160 files changed

+5592
-1467
lines changed

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ 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.6.32] - 2025-09-29
9+
10+
### Added
11+
12+
- 🗝️ Permission toggle for public sharing of notes was added, allowing note owners to quickly enable or disable public access from the note settings interface.
13+
- ⚠️ A warning is now displayed in the user edit modal if conflicting group permissions are detected, helping administrators resolve access control ambiguities before saving changes.
14+
15+
### Fixed
16+
17+
- 🧰 Fixed regression where External Tool servers (OpenAPI) were nonfunctional after the 0.6.31 update; external tools integration is now restored and reliable.
18+
- 🚑 Resolved a critical bug causing Streamable HTTP OAuth 2.1 (MCP server) integrations to throw a 500 error on first invocation due to missing 'SessionMiddleware'. OAuth 2.1 registration now succeeds and works on subsequent requests as expected.
19+
- 🐛 The "Set as default" option is now reliably clickable in model and filter selection menus, fixing cases where the interface appeared unresponsive.
20+
- 🛠️ Embed UI now works seamlessly with both default and native function calling flows, ensuring the tool embedding experience is consistent regardless of invocation method.
21+
- 🧹 Addressed various minor UI bugs and inconsistencies for a cleaner user experience.
22+
23+
### Changed
24+
25+
- 🧬 MCP tool result handling code was refactored for improved parsing and robustness of tool outputs.
26+
- 🧩 The user edit modal was overhauled for clarity and usability, improving the organization of group, permission, and public sharing controls.
27+
828
## [0.6.31] - 2025-09-25
929

1030
### Added

backend/open_webui/config.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,11 @@ def feishu_oauth_register(client: OAuth):
12171217
== "true"
12181218
)
12191219

1220+
USER_PERMISSIONS_NOTES_ALLOW_PUBLIC_SHARING = (
1221+
os.environ.get("USER_PERMISSIONS_NOTES_ALLOW_PUBLIC_SHARING", "False").lower()
1222+
== "true"
1223+
)
1224+
12201225
USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_ALLOW_PUBLIC_SHARING = (
12211226
os.environ.get(
12221227
"USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_ALLOW_PUBLIC_SHARING", "False"
@@ -1354,6 +1359,7 @@ def feishu_oauth_register(client: OAuth):
13541359
"public_knowledge": USER_PERMISSIONS_WORKSPACE_KNOWLEDGE_ALLOW_PUBLIC_SHARING,
13551360
"public_prompts": USER_PERMISSIONS_WORKSPACE_PROMPTS_ALLOW_PUBLIC_SHARING,
13561361
"public_tools": USER_PERMISSIONS_WORKSPACE_TOOLS_ALLOW_PUBLIC_SHARING,
1362+
"public_notes": USER_PERMISSIONS_NOTES_ALLOW_PUBLIC_SHARING,
13571363
},
13581364
"chat": {
13591365
"controls": USER_PERMISSIONS_CHAT_CONTROLS,
@@ -1999,16 +2005,23 @@ class BannerModel(BaseModel):
19992005
# 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)
20002006

20012007
# Milvus
2002-
20032008
MILVUS_URI = os.environ.get("MILVUS_URI", f"{DATA_DIR}/vector_db/milvus.db")
20042009
MILVUS_DB = os.environ.get("MILVUS_DB", "default")
20052010
MILVUS_TOKEN = os.environ.get("MILVUS_TOKEN", None)
2006-
20072011
MILVUS_INDEX_TYPE = os.environ.get("MILVUS_INDEX_TYPE", "HNSW")
20082012
MILVUS_METRIC_TYPE = os.environ.get("MILVUS_METRIC_TYPE", "COSINE")
20092013
MILVUS_HNSW_M = int(os.environ.get("MILVUS_HNSW_M", "16"))
20102014
MILVUS_HNSW_EFCONSTRUCTION = int(os.environ.get("MILVUS_HNSW_EFCONSTRUCTION", "100"))
20112015
MILVUS_IVF_FLAT_NLIST = int(os.environ.get("MILVUS_IVF_FLAT_NLIST", "128"))
2016+
MILVUS_DISKANN_MAX_DEGREE = int(os.environ.get("MILVUS_DISKANN_MAX_DEGREE", "56"))
2017+
MILVUS_DISKANN_SEARCH_LIST_SIZE = int(
2018+
os.environ.get("MILVUS_DISKANN_SEARCH_LIST_SIZE", "100")
2019+
)
2020+
ENABLE_MILVUS_MULTITENANCY_MODE = (
2021+
os.environ.get("ENABLE_MILVUS_MULTITENANCY_MODE", "true").lower() == "true"
2022+
)
2023+
# Hyphens not allowed, need to use underscores in collection names
2024+
MILVUS_COLLECTION_PREFIX = os.environ.get("MILVUS_COLLECTION_PREFIX", "open_webui")
20122025

20132026
# Qdrant
20142027
QDRANT_URI = os.environ.get("QDRANT_URI", None)

backend/open_webui/functions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ async def get_function_models(request):
8686
try:
8787
function_module = get_function_module_by_id(request, pipe.id)
8888

89+
has_user_valves = False
90+
if hasattr(function_module, "UserValves"):
91+
has_user_valves = True
92+
8993
# Check if function is a manifold
9094
if hasattr(function_module, "pipes"):
9195
sub_pipes = []
@@ -124,6 +128,7 @@ async def get_function_models(request):
124128
"created": pipe.created_at,
125129
"owned_by": "openai",
126130
"pipe": pipe_flag,
131+
"has_user_valves": has_user_valves,
127132
}
128133
)
129134
else:
@@ -141,6 +146,7 @@ async def get_function_models(request):
141146
"created": pipe.created_at,
142147
"owned_by": "openai",
143148
"pipe": pipe_flag,
149+
"has_user_valves": has_user_valves,
144150
}
145151
)
146152
except Exception as e:

backend/open_webui/main.py

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,7 +1552,7 @@ async def process_chat(request, form_data, user, metadata, model):
15521552
finally:
15531553
try:
15541554
if mcp_clients := metadata.get("mcp_clients"):
1555-
for client in mcp_clients:
1555+
for client in mcp_clients.values():
15561556
await client.disconnect()
15571557
except Exception as e:
15581558
log.debug(f"Error cleaning up: {e}")
@@ -1908,37 +1908,32 @@ async def get_current_usage(user=Depends(get_verified_user)):
19081908
f"mcp:{server_id}", OAuthClientInformationFull(**oauth_client_info)
19091909
)
19101910

1911+
try:
1912+
if REDIS_URL:
1913+
redis_session_store = RedisStore(
1914+
url=REDIS_URL,
1915+
prefix=(f"{REDIS_KEY_PREFIX}:session:" if REDIS_KEY_PREFIX else "session:"),
1916+
)
19111917

1912-
# SessionMiddleware is used by authlib for oauth
1913-
if len(OAUTH_PROVIDERS) > 0:
1914-
try:
1915-
if REDIS_URL:
1916-
redis_session_store = RedisStore(
1917-
url=REDIS_URL,
1918-
prefix=(
1919-
f"{REDIS_KEY_PREFIX}:session:" if REDIS_KEY_PREFIX else "session:"
1920-
),
1921-
)
1922-
1923-
app.add_middleware(SessionAutoloadMiddleware)
1924-
app.add_middleware(
1925-
StarSessionsMiddleware,
1926-
store=redis_session_store,
1927-
cookie_name="oui-session",
1928-
cookie_same_site=WEBUI_SESSION_COOKIE_SAME_SITE,
1929-
cookie_https_only=WEBUI_SESSION_COOKIE_SECURE,
1930-
)
1931-
log.info("Using Redis for session")
1932-
else:
1933-
raise ValueError("No Redis URL provided")
1934-
except Exception as e:
1918+
app.add_middleware(SessionAutoloadMiddleware)
19351919
app.add_middleware(
1936-
SessionMiddleware,
1937-
secret_key=WEBUI_SECRET_KEY,
1938-
session_cookie="oui-session",
1939-
same_site=WEBUI_SESSION_COOKIE_SAME_SITE,
1940-
https_only=WEBUI_SESSION_COOKIE_SECURE,
1920+
StarSessionsMiddleware,
1921+
store=redis_session_store,
1922+
cookie_name="owui-session",
1923+
cookie_same_site=WEBUI_SESSION_COOKIE_SAME_SITE,
1924+
cookie_https_only=WEBUI_SESSION_COOKIE_SECURE,
19411925
)
1926+
log.info("Using Redis for session")
1927+
else:
1928+
raise ValueError("No Redis URL provided")
1929+
except Exception as e:
1930+
app.add_middleware(
1931+
SessionMiddleware,
1932+
secret_key=WEBUI_SECRET_KEY,
1933+
session_cookie="owui-session",
1934+
same_site=WEBUI_SESSION_COOKIE_SAME_SITE,
1935+
https_only=WEBUI_SESSION_COOKIE_SECURE,
1936+
)
19421937

19431938

19441939
@app.get("/oauth/clients/{client_id}/authorize")
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""Add reply_to_id column to message
2+
3+
Revision ID: a5c220713937
4+
Revises: 38d63c18f30f
5+
Create Date: 2025-09-27 02:24:18.058455
6+
7+
"""
8+
9+
from typing import Sequence, Union
10+
11+
from alembic import op
12+
import sqlalchemy as sa
13+
14+
# revision identifiers, used by Alembic.
15+
revision: str = "a5c220713937"
16+
down_revision: Union[str, None] = "38d63c18f30f"
17+
branch_labels: Union[str, Sequence[str], None] = None
18+
depends_on: Union[str, Sequence[str], None] = None
19+
20+
21+
def upgrade() -> None:
22+
# Add 'reply_to_id' column to the 'message' table for replying to messages
23+
op.add_column(
24+
"message",
25+
sa.Column("reply_to_id", sa.Text(), nullable=True),
26+
)
27+
pass
28+
29+
30+
def downgrade() -> None:
31+
# Remove 'reply_to_id' column from the 'message' table
32+
op.drop_column("message", "reply_to_id")
33+
34+
pass

backend/open_webui/models/chats.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,15 @@ def delete_shared_chat_by_chat_id(self, chat_id: str) -> bool:
366366
except Exception:
367367
return False
368368

369+
def unarchive_all_chats_by_user_id(self, user_id: str) -> bool:
370+
try:
371+
with get_db() as db:
372+
db.query(Chat).filter_by(user_id=user_id).update({"archived": False})
373+
db.commit()
374+
return True
375+
except Exception:
376+
return False
377+
369378
def update_chat_share_id_by_id(
370379
self, id: str, share_id: Optional[str]
371380
) -> Optional[ChatModel]:
@@ -810,7 +819,7 @@ def get_chats_by_user_id_and_search_text(
810819
return [ChatModel.model_validate(chat) for chat in all_chats]
811820

812821
def get_chats_by_folder_id_and_user_id(
813-
self, folder_id: str, user_id: str
822+
self, folder_id: str, user_id: str, skip: int = 0, limit: int = 60
814823
) -> list[ChatModel]:
815824
with get_db() as db:
816825
query = db.query(Chat).filter_by(folder_id=folder_id, user_id=user_id)
@@ -819,6 +828,11 @@ def get_chats_by_folder_id_and_user_id(
819828

820829
query = query.order_by(Chat.updated_at.desc())
821830

831+
if skip:
832+
query = query.offset(skip)
833+
if limit:
834+
query = query.limit(limit)
835+
822836
all_chats = query.all()
823837
return [ChatModel.model_validate(chat) for chat in all_chats]
824838

backend/open_webui/models/folders.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,20 @@ class FolderModel(BaseModel):
5050
model_config = ConfigDict(from_attributes=True)
5151

5252

53+
class FolderMetadataResponse(BaseModel):
54+
icon: Optional[str] = None
55+
56+
57+
class FolderNameIdResponse(BaseModel):
58+
id: str
59+
name: str
60+
meta: Optional[FolderMetadataResponse] = None
61+
parent_id: Optional[str] = None
62+
is_expanded: bool = False
63+
created_at: int
64+
updated_at: int
65+
66+
5367
####################
5468
# Forms
5569
####################

0 commit comments

Comments
 (0)