diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 798487834..59fd75dad 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -402,34 +402,43 @@ def get_builtin_tools( .get(name, default) ) - # Time utilities - always available for date calculations - builtin_functions.extend([get_current_timestamp, calculate_timestamp]) + # Helper to check if a builtin tool category is enabled via meta.builtinTools + # Defaults to True if not specified (backward compatible) + def is_builtin_tool_enabled(category: str) -> bool: + builtin_tools = model.get("info", {}).get("meta", {}).get("builtinTools", {}) + return builtin_tools.get(category, True) + + # Time utilities - available for date calculations + if is_builtin_tool_enabled("time"): + builtin_functions.extend([get_current_timestamp, calculate_timestamp]) # Knowledge base tools - conditional injection based on model knowledge # If model has attached knowledge (any type), only provide query_knowledge_files # Otherwise, provide all KB browsing tools model_knowledge = model.get("info", {}).get("meta", {}).get("knowledge", []) - if model_knowledge: - # Model has attached knowledge - only allow semantic search within it - builtin_functions.append(query_knowledge_files) - else: - # No model knowledge - allow full KB browsing - builtin_functions.extend( - [ - list_knowledge_bases, - search_knowledge_bases, - query_knowledge_bases, - search_knowledge_files, - query_knowledge_files, - view_knowledge_file, - ] - ) + if is_builtin_tool_enabled("knowledge"): + if model_knowledge: + # Model has attached knowledge - only allow semantic search within it + builtin_functions.append(query_knowledge_files) + else: + # No model knowledge - allow full KB browsing + builtin_functions.extend( + [ + list_knowledge_bases, + search_knowledge_bases, + query_knowledge_bases, + search_knowledge_files, + query_knowledge_files, + view_knowledge_file, + ] + ) # Chats tools - search and fetch user's chat history - builtin_functions.extend([search_chats, view_chat]) + if is_builtin_tool_enabled("chats"): + builtin_functions.extend([search_chats, view_chat]) - # Add memory tools if enabled for this chat - if features.get("memory"): + # Add memory tools if builtin category enabled AND enabled for this chat + if is_builtin_tool_enabled("memory") and features.get("memory"): builtin_functions.extend([search_memories, add_memory, replace_memory_content]) # Add web search tools if enabled globally AND model has web_search capability @@ -456,14 +465,14 @@ def get_builtin_tools( ): builtin_functions.append(execute_code) - # Notes tools - search, view, create, and update user's notes (if notes enabled globally) - if getattr(request.app.state.config, "ENABLE_NOTES", False): + # Notes tools - search, view, create, and update user's notes (if builtin category enabled AND notes enabled globally) + if is_builtin_tool_enabled("notes") and getattr(request.app.state.config, "ENABLE_NOTES", False): builtin_functions.extend( [search_notes, view_note, write_note, replace_note_content] ) - # Channels tools - search channels and messages (if channels enabled globally) - if getattr(request.app.state.config, "ENABLE_CHANNELS", False): + # Channels tools - search channels and messages (if builtin category enabled AND channels enabled globally) + if is_builtin_tool_enabled("channels") and getattr(request.app.state.config, "ENABLE_CHANNELS", False): builtin_functions.extend( [ search_channels, diff --git a/src/lib/components/workspace/Models/BuiltinTools.svelte b/src/lib/components/workspace/Models/BuiltinTools.svelte new file mode 100644 index 000000000..80587cfcb --- /dev/null +++ b/src/lib/components/workspace/Models/BuiltinTools.svelte @@ -0,0 +1,75 @@ + + +
+
+
{$i18n.t('Builtin Tools')}
+
+
+ {#each allTools as tool} +
+ { + builtinTools = { + ...builtinTools, + [tool]: e.detail === 'checked' + }; + }} + /> + +
+ + {$i18n.t(toolLabels[tool].label)} + +
+
+ {/each} +
+
diff --git a/src/lib/components/workspace/Models/ModelEditor.svelte b/src/lib/components/workspace/Models/ModelEditor.svelte index e26d3d02c..52734acb2 100644 --- a/src/lib/components/workspace/Models/ModelEditor.svelte +++ b/src/lib/components/workspace/Models/ModelEditor.svelte @@ -21,6 +21,7 @@ import XMark from '$lib/components/icons/XMark.svelte'; import DefaultFiltersSelector from './DefaultFiltersSelector.svelte'; import DefaultFeatures from './DefaultFeatures.svelte'; + import BuiltinTools from './BuiltinTools.svelte'; import PromptSuggestions from './PromptSuggestions.svelte'; import AccessControlModal from '../common/AccessControlModal.svelte'; import LockClosed from '$lib/components/icons/LockClosed.svelte'; @@ -104,6 +105,7 @@ builtin_tools: true }; let defaultFeatureIds = []; + let builtinTools = {}; let actionIds = []; let accessControl = {}; @@ -195,6 +197,14 @@ } } + if (Object.keys(builtinTools).length > 0) { + info.meta.builtinTools = builtinTools; + } else { + if (info.meta.builtinTools) { + delete info.meta.builtinTools; + } + } + if (tts.voice !== '') { if (!info.meta.tts) info.meta.tts = {}; info.meta.tts.voice = tts.voice; @@ -288,6 +298,7 @@ capabilities = { ...capabilities, ...(model?.meta?.capabilities ?? {}) }; defaultFeatureIds = model?.meta?.defaultFeatureIds ?? []; + builtinTools = model?.meta?.builtinTools ?? {}; tts = { voice: model?.meta?.tts?.voice ?? '' }; if ('access_control' in model) { @@ -780,6 +791,12 @@ {/if} {/if} + {#if capabilities.builtin_tools} +
+ +
+ {/if} +