Skip to content

Commit 4113b15

Browse files
committed
chore: format
1 parent e8e655d commit 4113b15

79 files changed

Lines changed: 501 additions & 117 deletions

File tree

Some content is hidden

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

.github/pull_request_template.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ This is to ensure large feature PRs are discussed with the community first, befo
1616
The most impactful way to contribute to Open WebUI is through well-written bug reports, detailed feature discussions, and thoughtful ideas. These directly shape the project. If you do open a pull request, please know that Open WebUI is held to the highest standard of code quality, consistency, and architectural coherence, and every line merged becomes something the core team must own, maintain, and support indefinitely. Submitted code may be refactored, rewritten, or used as inspiration for a different implementation. This is not a reflection of your work's quality. It is how we ensure that a small team can deeply understand and evolve every part of the codebase.
1717
-->
1818

19-
2019
**Before submitting, make sure you've checked the following:**
2120

2221
- [ ] **Target branch:** Verify that the pull request targets the `dev` branch. **PRs targeting `main` will be immediately closed.**

backend/open_webui/migrations/versions/c1d2e3f4a5b6_add_shared_chat_table.py

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -91,41 +91,41 @@ def upgrade():
9191
original_chat_id = row.user_id.replace('shared-', '', 1)
9292

9393
# Verify original chat still exists
94-
original = conn.execute(
95-
sa.select(chat_t.c.user_id).where(chat_t.c.id == original_chat_id)
96-
).fetchone()
94+
original = conn.execute(sa.select(chat_t.c.user_id).where(chat_t.c.id == original_chat_id)).fetchone()
9795

9896
if not original:
9997
continue
10098

10199
# Insert snapshot into shared_chat
102-
conn.execute(shared_chat_t.insert().values(
103-
id=share_token,
104-
chat_id=original_chat_id,
105-
user_id=original.user_id,
106-
title=row.title,
107-
chat=row.chat,
108-
created_at=row.created_at,
109-
updated_at=row.updated_at,
110-
))
100+
conn.execute(
101+
shared_chat_t.insert().values(
102+
id=share_token,
103+
chat_id=original_chat_id,
104+
user_id=original.user_id,
105+
title=row.title,
106+
chat=row.chat,
107+
created_at=row.created_at,
108+
updated_at=row.updated_at,
109+
)
110+
)
111111

112112
# Create user:*:read grant for backward compat
113-
conn.execute(access_grant_t.insert().values(
114-
id=str(uuid.uuid4()),
115-
resource_type='shared_chat',
116-
resource_id=original_chat_id,
117-
principal_type='user',
118-
principal_id='*',
119-
permission='read',
120-
created_at=row.created_at or int(time.time()),
121-
))
113+
conn.execute(
114+
access_grant_t.insert().values(
115+
id=str(uuid.uuid4()),
116+
resource_type='shared_chat',
117+
resource_id=original_chat_id,
118+
principal_type='user',
119+
principal_id='*',
120+
permission='read',
121+
created_at=row.created_at or int(time.time()),
122+
)
123+
)
122124

123125
# 3. Clean up old phantom rows
124126
conn.execute(
125127
chat_message_t.delete().where(
126-
chat_message_t.c.chat_id.in_(
127-
sa.select(chat_t.c.id).where(chat_t.c.user_id.like('shared-%'))
128-
)
128+
chat_message_t.c.chat_id.in_(sa.select(chat_t.c.id).where(chat_t.c.user_id.like('shared-%')))
129129
)
130130
)
131131
conn.execute(chat_t.delete().where(chat_t.c.user_id.like('shared-%')))
@@ -147,18 +147,18 @@ def downgrade():
147147
).fetchall()
148148

149149
for row in shared_rows:
150-
conn.execute(chat_t.insert().values(
151-
id=row.id,
152-
user_id=f'shared-{row.chat_id}',
153-
title=row.title,
154-
chat=row.chat,
155-
created_at=row.created_at,
156-
updated_at=row.updated_at,
157-
archived=False,
158-
meta={},
159-
))
150+
conn.execute(
151+
chat_t.insert().values(
152+
id=row.id,
153+
user_id=f'shared-{row.chat_id}',
154+
title=row.title,
155+
chat=row.chat,
156+
created_at=row.created_at,
157+
updated_at=row.updated_at,
158+
archived=False,
159+
meta={},
160+
)
161+
)
160162

161-
conn.execute(
162-
access_grant_t.delete().where(access_grant_t.c.resource_type == 'shared_chat')
163-
)
163+
conn.execute(access_grant_t.delete().where(access_grant_t.c.resource_type == 'shared_chat'))
164164
op.drop_table('shared_chat')

backend/open_webui/models/chats.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -723,9 +723,7 @@ async def get_shared_chat_list_by_user_id(
723723
"""Delegate to SharedChats for listing shared chats by user."""
724724
from open_webui.models.shared_chats import SharedChats
725725

726-
return await SharedChats.get_by_user_id(
727-
user_id, filter=filter, skip=skip, limit=limit, db=db
728-
)
726+
return await SharedChats.get_by_user_id(user_id, filter=filter, skip=skip, limit=limit, db=db)
729727

730728
async def get_chat_list_by_user_id(
731729
self,

backend/open_webui/models/prompts.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,15 +299,17 @@ async def search_prompts(
299299

300300
if dialect_name == 'sqlite':
301301
tag_clause = text(
302-
"EXISTS (SELECT 1 FROM json_each(prompt.tags) t WHERE LOWER(t.value) = :tag_val)"
302+
'EXISTS (SELECT 1 FROM json_each(prompt.tags) t WHERE LOWER(t.value) = :tag_val)'
303303
)
304304
elif dialect_name == 'postgresql':
305305
tag_clause = text(
306-
"EXISTS (SELECT 1 FROM json_array_elements_text(prompt.tags) t WHERE LOWER(t) = :tag_val)"
306+
'EXISTS (SELECT 1 FROM json_array_elements_text(prompt.tags) t WHERE LOWER(t) = :tag_val)'
307307
)
308308
else:
309309
# Fallback: LIKE on serialised JSON text (ASCII-safe only)
310-
tag_clause = func.lower(cast(Prompt.tags, String)).like(f'%{json.dumps(tag_lower, ensure_ascii=False)}%')
310+
tag_clause = func.lower(cast(Prompt.tags, String)).like(
311+
f'%{json.dumps(tag_lower, ensure_ascii=False)}%'
312+
)
311313
tag_lower = None
312314

313315
if tag_lower is not None:

backend/open_webui/models/shared_chats.py

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ class SharedChatResponse(BaseModel):
6060

6161

6262
class SharedChatsTable:
63-
async def create(
64-
self, chat_id: str, user_id: str, db: Optional[AsyncSession] = None
65-
) -> Optional[SharedChatModel]:
63+
async def create(self, chat_id: str, user_id: str, db: Optional[AsyncSession] = None) -> Optional[SharedChatModel]:
6664
"""
6765
Create a snapshot of the chat for link sharing.
6866
Returns the SharedChatModel with the share token as its id.
@@ -92,9 +90,7 @@ async def create(
9290

9391
return SharedChatModel.model_validate(shared_chat)
9492

95-
async def update(
96-
self, share_id: str, db: Optional[AsyncSession] = None
97-
) -> Optional[SharedChatModel]:
93+
async def update(self, share_id: str, db: Optional[AsyncSession] = None) -> Optional[SharedChatModel]:
9894
"""
9995
Re-snapshot: update the shared chat with the current state of the original chat.
10096
"""
@@ -117,26 +113,19 @@ async def update(
117113
await db.refresh(shared_chat)
118114
return SharedChatModel.model_validate(shared_chat)
119115

120-
async def get_by_id(
121-
self, share_id: str, db: Optional[AsyncSession] = None
122-
) -> Optional[SharedChatModel]:
116+
async def get_by_id(self, share_id: str, db: Optional[AsyncSession] = None) -> Optional[SharedChatModel]:
123117
"""Get a shared chat by its share token."""
124118
async with get_async_db_context(db) as db:
125119
shared_chat = await db.get(SharedChat, share_id)
126120
if shared_chat:
127121
return SharedChatModel.model_validate(shared_chat)
128122
return None
129123

130-
async def get_by_chat_id(
131-
self, chat_id: str, db: Optional[AsyncSession] = None
132-
) -> Optional[SharedChatModel]:
124+
async def get_by_chat_id(self, chat_id: str, db: Optional[AsyncSession] = None) -> Optional[SharedChatModel]:
133125
"""Get the shared chat for a given original chat. Returns the most recent one."""
134126
async with get_async_db_context(db) as db:
135127
result = await db.execute(
136-
select(SharedChat)
137-
.filter_by(chat_id=chat_id)
138-
.order_by(SharedChat.updated_at.desc())
139-
.limit(1)
128+
select(SharedChat).filter_by(chat_id=chat_id).order_by(SharedChat.updated_at.desc()).limit(1)
140129
)
141130
shared_chat = result.scalars().first()
142131
if shared_chat:
@@ -194,9 +183,7 @@ async def get_by_user_id(
194183
for sc in result.scalars().all()
195184
]
196185

197-
async def delete_by_id(
198-
self, share_id: str, db: Optional[AsyncSession] = None
199-
) -> bool:
186+
async def delete_by_id(self, share_id: str, db: Optional[AsyncSession] = None) -> bool:
200187
"""Delete a shared chat by its share token."""
201188
try:
202189
async with get_async_db_context(db) as db:
@@ -206,9 +193,7 @@ async def delete_by_id(
206193
except Exception:
207194
return False
208195

209-
async def delete_by_chat_id(
210-
self, chat_id: str, db: Optional[AsyncSession] = None
211-
) -> bool:
196+
async def delete_by_chat_id(self, chat_id: str, db: Optional[AsyncSession] = None) -> bool:
212197
"""Delete all shared chats for a given original chat."""
213198
try:
214199
async with get_async_db_context(db) as db:

backend/open_webui/retrieval/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ async def filter_accessible_collections(
959959
# System meta-collection — never exposed to non-admins.
960960
continue
961961
elif name.startswith('file-'):
962-
file_id = name[len('file-'):]
962+
file_id = name[len('file-') :]
963963
if await has_access_to_file(file_id=file_id, access_type=access_type, user=user):
964964
validated.add(name)
965965
elif name.startswith('user-memory-'):

backend/open_webui/routers/memories.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,8 @@ async def query_memory(
150150
# same RELEVANCE_THRESHOLD used by RAG ensures only genuinely matching
151151
# memories are surfaced (distances are normalised to 0→1, higher is
152152
# better).
153-
relevance_threshold = getattr(
154-
request.app.state.config, 'RELEVANCE_THRESHOLD', 0.0
155-
)
156-
if (
157-
results
158-
and relevance_threshold > 0.0
159-
and results.distances
160-
and results.distances[0]
161-
):
153+
relevance_threshold = getattr(request.app.state.config, 'RELEVANCE_THRESHOLD', 0.0)
154+
if results and relevance_threshold > 0.0 and results.distances and results.distances[0]:
162155
from open_webui.retrieval.vector.main import SearchResult
163156

164157
filtered_ids = []

backend/open_webui/routers/retrieval.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2365,7 +2365,6 @@ async def _validate_collection_access(collection_names: list[str], user, access_
23652365
)
23662366

23672367

2368-
23692368
class QueryDocForm(BaseModel):
23702369
collection_name: str
23712370
query: str

backend/open_webui/utils/access_control/__init__.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,11 +339,8 @@ async def check_model_access(
339339
raise HTTPException(status_code=403, detail='Model not found')
340340

341341
# Enforce access on chained base models
342-
if not await has_base_model_access(
343-
user.id, model_info, user_group_ids=user_group_ids
344-
):
342+
if not await has_base_model_access(user.id, model_info, user_group_ids=user_group_ids):
345343
raise HTTPException(status_code=403, detail='Model not found')
346344
else:
347345
if user.role != 'admin':
348346
raise HTTPException(status_code=403, detail='Model not found')
349-

backend/open_webui/utils/middleware.py

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,50 @@ def serialize_output(output: list) -> str:
452452
# Already handled inline with function_call above
453453
pass
454454

455+
elif item_type in ('web_search_call', 'file_search_call', 'computer_call'):
456+
# OpenAI Responses API built-in server-side tool output items.
457+
# These are emitted when the model uses native tools (web_search,
458+
# file_search, computer_use) through the Responses API. Render as
459+
# collapsible tool call blocks matching the function_call pattern.
460+
if content and not content.endswith('\n'):
461+
content += '\n'
462+
463+
call_id = item.get('id', '')
464+
status = item.get('status', 'in_progress')
465+
466+
# Derive a human-readable display name
467+
display_names = {
468+
'web_search_call': 'Web Search',
469+
'file_search_call': 'File Search',
470+
'computer_call': 'Computer Use',
471+
}
472+
display_name = display_names.get(item_type, item_type)
473+
474+
# Extract a summary of what the tool did for the details body
475+
summary_text = ''
476+
if item_type == 'web_search_call':
477+
action = item.get('action', {})
478+
if isinstance(action, dict):
479+
query = action.get('query', '')
480+
if query:
481+
summary_text = f'Query: {query}'
482+
elif item_type == 'file_search_call':
483+
queries = item.get('queries', [])
484+
if queries:
485+
summary_text = f'Queries: {", ".join(str(q) for q in queries)}'
486+
elif item_type == 'computer_call':
487+
action = item.get('action', {})
488+
if isinstance(action, dict):
489+
action_type = action.get('type', '')
490+
if action_type:
491+
summary_text = f'Action: {action_type}'
492+
493+
done = status == 'completed' or idx != len(output) - 1
494+
if done:
495+
content += f'<details type="tool_calls" done="true" id="{call_id}" name="{html.escape(display_name)}" arguments="">\n<summary>Tool Executed</summary>\n{html.escape(summary_text)}\n</details>\n'
496+
else:
497+
content += f'<details type="tool_calls" done="false" id="{call_id}" name="{html.escape(display_name)}" arguments="">\n<summary>Executing...</summary>\n</details>\n'
498+
455499
elif item_type == 'reasoning':
456500
reasoning_content = ''
457501
# Check for 'summary' (new structure) or 'content' (legacy/fallback)
@@ -2619,9 +2663,7 @@ async def tool_function(**kwargs):
26192663

26202664
# Resolve terminal tools if terminal_id is set (outside tool_ids check
26212665
# so system terminals work even when no other tools are selected)
2622-
terminal_capability = (model.get('info', {}).get('meta', {}).get('capabilities') or {}).get(
2623-
'terminal', True
2624-
)
2666+
terminal_capability = (model.get('info', {}).get('meta', {}).get('capabilities') or {}).get('terminal', True)
26252667
if terminal_id and terminal_capability:
26262668
try:
26272669
terminal_result = await get_terminal_tools(
@@ -3110,11 +3152,13 @@ async def outlet_filter_handler(ctx):
31103152

31113153
# Append the full assistant message (content, output, usage, etc.)
31123154
if assistant_message:
3113-
message_list.append({
3114-
'id': message_id,
3115-
'role': 'assistant',
3116-
**assistant_message,
3117-
})
3155+
message_list.append(
3156+
{
3157+
'id': message_id,
3158+
'role': 'assistant',
3159+
**assistant_message,
3160+
}
3161+
)
31183162
else:
31193163
messages_map = await Chats.get_messages_map_by_chat_id(chat_id)
31203164
if not messages_map:
@@ -4221,7 +4265,6 @@ async def flush_pending_delta_data(threshold: int = 0):
42214265
)
42224266
reasoning_item['status'] = 'completed'
42234267

4224-
42254268
if response_tool_calls:
42264269
tool_calls.append(_split_tool_calls(response_tool_calls))
42274270

0 commit comments

Comments
 (0)