perf: reuse the already loaded chat when assembling builtin tools (#28809)

Assembling the builtin tools for a chat message fetched the chat row a second time to answer one question: whether this is a note chat. The caller had loaded that same row a few lines earlier, from the same id in the same metadata dict, and had already evaluated the same predicate for its own note handling. So every message with builtin tools enabled read the whole conversation blob twice.

The caller now works the flag out once and passes it down. Tool assembly no longer touches a chat model at all, so the two files cannot drift apart when the shape of that metadata changes.

Measured with a stub request across five chat shapes, a note chat, a plain chat, an internal chat that is not a note, a chat id with no row behind it, and an unsaved chat id: the returned tool set is identical in every case and the query count drops from six to five. The note tools are still enabled for a note chat with the notes feature switched off, which is the only thing that predicate decides.
This commit is contained in:
Classic298
2026-08-19 11:06:49 -07:00
committed by GitHub
parent 6db64c4855
commit 284da2ae49
2 changed files with 8 additions and 13 deletions
+5 -4
View File
@@ -2609,7 +2609,9 @@ async def process_chat_payload(request, form_data, user, metadata, model):
if is_saved_chat_id(metadata.get('chat_id')):
chat = await Chats.get_chat_by_id(metadata['chat_id'])
if chat and (chat.meta or {}).get('internal') is True and (chat.meta or {}).get('type') == 'note':
is_note_chat = bool(chat and (chat.meta or {}).get('internal') is True and (chat.meta or {}).get('type') == 'note')
if is_note_chat:
note_id = (chat.meta or {}).get('note_id')
note = await Notes.get_note_by_id(note_id) if note_id else None
if note and (
@@ -2632,9 +2634,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
if note_files:
files = [*(files or []), *note_files]
use_builtin_tools = (
chat and (chat.meta or {}).get('internal') is True and (chat.meta or {}).get('type') == 'note'
) or (
use_builtin_tools = is_note_chat or (
bool(metadata.get('session_id'))
and metadata.get('params', {}).get('function_calling') != 'legacy'
and (model.get('info', {}).get('meta', {}).get('capabilities') or {}).get('builtin_tools', True)
@@ -2886,6 +2886,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
},
features,
model,
is_note_chat=is_note_chat,
)
for name, tool_dict in builtin_tools.items():
if name not in tools_dict:
+3 -9
View File
@@ -40,7 +40,6 @@ from open_webui.env import (
REDIS_KEY_PREFIX,
)
from open_webui.models.access_grants import AccessGrants
from open_webui.models.chats import Chats
from open_webui.models.config import Config
from open_webui.models.groups import Groups
from open_webui.models.tools import Tools
@@ -525,7 +524,7 @@ def get_attached_knowledge(model: dict, metadata: dict) -> list[dict]:
async def get_builtin_tools(
request: Request, extra_params: dict, features: dict = None, model: dict = None
request: Request, extra_params: dict, features: dict = None, model: dict = None, is_note_chat: bool = False
) -> dict[str, dict]:
"""
Get built-in tools for native function calling.
@@ -719,13 +718,8 @@ async def get_builtin_tools(
):
builtin_functions.append(execute_code)
chat_id = metadata.get('chat_id') or ''
chat = None
if is_saved_chat_id(chat_id):
chat = await Chats.get_chat_by_id(chat_id)
# Notes tools - search, view, create, and update user's notes
if (chat and (chat.meta or {}).get('internal') is True and (chat.meta or {}).get('type') == 'note') or (
if is_note_chat or (
is_builtin_tool_enabled('notes') and config.get('notes.enable') and await has_user_permission('notes')
):
builtin_functions.extend([search_notes, view_note, write_note, replace_note_content])
@@ -747,7 +741,7 @@ async def get_builtin_tools(
# Task management - break down complex work into trackable steps
# Task state is stored on the chats row; local/channel IDs do not have one.
if is_builtin_tool_enabled('tasks') and is_saved_chat_id(chat_id):
if is_builtin_tool_enabled('tasks') and is_saved_chat_id(metadata.get('chat_id')):
builtin_functions.extend([create_tasks, update_task])
# Automation tools - create and manage scheduled automations from chat