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:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user