diff --git a/app/MindWork AI Studio/Assistants/AssistantBase.razor b/app/MindWork AI Studio/Assistants/AssistantBase.razor
index ee83a2e0..8936b3c7 100644
--- a/app/MindWork AI Studio/Assistants/AssistantBase.razor
+++ b/app/MindWork AI Studio/Assistants/AssistantBase.razor
@@ -175,7 +175,7 @@
}
- @if (this.SettingsManager.IsToolSelectionVisible(this.Component))
+ @if (this.SettingsManager.AreToolsEnabled() && this.SettingsManager.IsToolSelectionVisible(this.Component))
{
}
diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua
index 2f8794e8..18979c65 100644
--- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua
+++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua
@@ -3607,6 +3607,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T3728248397
-- Tool Settings
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T3730473128"] = "Tool Settings"
+-- This tool has been disabled by your organization.
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T3794167684"] = "This tool has been disabled by your organization."
+
-- Status
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T6222351"] = "Status"
@@ -3724,6 +3727,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3119156561"] = "Required
-- Close
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3448155331"] = "Close"
+-- This tool has been disabled by your organization.
+UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3794167684"] = "This tool has been disabled by your organization."
+
-- No tools are available in this context.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3904490680"] = "No tools are available in this context."
@@ -6535,6 +6541,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T3616903110"]
-- Tool Settings
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T3730473128"] = "Tool Settings"
+-- This tool has been disabled by your organization.
+UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T3794167684"] = "This tool has been disabled by your organization."
+
-- The selected tool could not be loaded.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T3907843187"] = "The selected tool could not be loaded."
@@ -9286,6 +9295,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS:
-- Optional HTTP timeout for the search request in seconds.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T3078115445"] = "Optional HTTP timeout for the search request in seconds."
+-- The default safe search setting must be 0, 1, or 2.
+UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T3187215042"] = "The default safe search setting must be 0, 1, or 2."
+
-- Search the web with a configured SearXNG instance and retrieve the readable content of the best matching pages.
UI_TEXT_CONTENT["AISTUDIO::TOOLS::TOOLCALLINGSYSTEM::TOOLCALLINGIMPLEMENTATIONS::SEARXNGWEBSEARCHTOOL::T3361633224"] = "Search the web with a configured SearXNG instance and retrieve the readable content of the best matching pages."
diff --git a/app/MindWork AI Studio/Components/ChatComponent.razor b/app/MindWork AI Studio/Components/ChatComponent.razor
index b6dead4a..a9e6a391 100644
--- a/app/MindWork AI Studio/Components/ChatComponent.razor
+++ b/app/MindWork AI Studio/Components/ChatComponent.razor
@@ -125,7 +125,10 @@
-
+ @if (this.SettingsManager.AreToolsEnabled())
+ {
+
+ }
@if (PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager))
{
diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelTools.razor b/app/MindWork AI Studio/Components/Settings/SettingsPanelTools.razor
index a7791799..2f83e75c 100644
--- a/app/MindWork AI Studio/Components/Settings/SettingsPanelTools.razor
+++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelTools.razor
@@ -37,7 +37,13 @@
- @if (context.ConfigurationState.IsConfigured)
+ @if (!context.IsActive)
+ {
+
+
+
+ }
+ else if (context.ConfigurationState.IsConfigured)
{
}
diff --git a/app/MindWork AI Studio/Components/ToolDefaultsConfiguration.razor b/app/MindWork AI Studio/Components/ToolDefaultsConfiguration.razor
index be71c551..22f8f209 100644
--- a/app/MindWork AI Studio/Components/ToolDefaultsConfiguration.razor
+++ b/app/MindWork AI Studio/Components/ToolDefaultsConfiguration.razor
@@ -8,5 +8,5 @@
{
}
-
+
}
diff --git a/app/MindWork AI Studio/Components/ToolDefaultsConfiguration.razor.cs b/app/MindWork AI Studio/Components/ToolDefaultsConfiguration.razor.cs
index a63f8734..28b3802b 100644
--- a/app/MindWork AI Studio/Components/ToolDefaultsConfiguration.razor.cs
+++ b/app/MindWork AI Studio/Components/ToolDefaultsConfiguration.razor.cs
@@ -29,6 +29,8 @@ public partial class ToolDefaultsConfiguration : MSGComponentBase
this.Component is not AIStudio.Tools.Components.CHAT &&
!this.SettingsManager.IsToolSelectionVisible(this.Component);
+ private bool IsToolDisabled(string toolId) => !this.SettingsManager.IsToolActive(toolId);
+
protected override async Task OnInitializedAsync()
{
this.availableTools = (await this.ToolRegistry.GetCatalogAsync(this.Component))
diff --git a/app/MindWork AI Studio/Components/ToolSelection.razor b/app/MindWork AI Studio/Components/ToolSelection.razor
index b7d71973..465adadb 100644
--- a/app/MindWork AI Studio/Components/ToolSelection.razor
+++ b/app/MindWork AI Studio/Components/ToolSelection.razor
@@ -47,8 +47,14 @@
-
+
+ @if (!item.IsActive)
+ {
+
+
+
+ }
@item.Implementation.GetDisplayName()
@@ -59,6 +65,10 @@
{
@(string.IsNullOrWhiteSpace(item.ConfigurationState.Message) ? T("Required settings are missing. Configure this tool before enabling it.") : item.ConfigurationState.Message)
}
+ @if (!item.IsActive)
+ {
+ @T("This tool has been disabled by your organization.")
+ }
@if (!string.IsNullOrWhiteSpace(providerConfidenceHint))
{
@providerConfidenceHint
diff --git a/app/MindWork AI Studio/Components/ToolSelection.razor.cs b/app/MindWork AI Studio/Components/ToolSelection.razor.cs
index d2e1cbeb..362fb808 100644
--- a/app/MindWork AI Studio/Components/ToolSelection.razor.cs
+++ b/app/MindWork AI Studio/Components/ToolSelection.razor.cs
@@ -73,6 +73,9 @@ public partial class ToolSelection : MSGComponentBase
private async Task ChangeSelection(string toolId, bool isSelected)
{
+ if (isSelected && !this.SettingsManager.IsToolActive(toolId))
+ return;
+
var updated = new HashSet(this.SelectedToolIds, StringComparer.Ordinal);
if (isSelected)
updated.Add(toolId);
diff --git a/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsDialog.razor b/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsDialog.razor
index 1e9e3d24..f18b4f78 100644
--- a/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsDialog.razor
+++ b/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsDialog.razor
@@ -19,6 +19,11 @@
@this.implementation?.GetDescription()
+ @if (!this.SettingsManager.IsToolActive(this.toolDefinition.Id))
+ {
+ @T("This tool has been disabled by your organization.")
+ }
+
@if (!string.IsNullOrWhiteSpace(this.validationMessage))
{
@this.validationMessage
diff --git a/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsDialog.razor.cs b/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsDialog.razor.cs
index b7cfd7c4..625bba25 100644
--- a/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsDialog.razor.cs
+++ b/app/MindWork AI Studio/Dialogs/Settings/ToolSettingsDialog.razor.cs
@@ -1,4 +1,3 @@
-using AIStudio.Settings;
using AIStudio.Tools.ToolCallingSystem;
using Microsoft.AspNetCore.Components;
@@ -53,19 +52,8 @@ public partial class ToolSettingsDialog : SettingsDialogBase
return string.Format(T("{0} Default: {1}"), description, defaultValue);
}
- private bool IsFieldDisabled(string fieldName)
- {
- if (this.toolDefinition?.Id.Equals(ToolSelectionRules.WEB_SEARCH_TOOL_ID, StringComparison.Ordinal) is true &&
- fieldName.Equals("baseUrl", StringComparison.Ordinal) &&
- ManagedConfiguration.TryGet(x => x.Tools, x => x.WebSearchBaseUrl, out var webSearchMeta) &&
- webSearchMeta.IsLocked)
- return true;
-
- return this.toolDefinition?.Id.Equals(ToolSelectionRules.READ_WEB_PAGE_TOOL_ID, StringComparison.Ordinal) is true &&
- fieldName.Equals("allowedPrivateHosts", StringComparison.Ordinal) &&
- ManagedConfiguration.TryGet(x => x.Tools, x => x.ReadWebPageAllowedPrivateHosts, out var readWebPageMeta) &&
- readWebPageMeta.IsLocked;
- }
+ private bool IsFieldDisabled(string fieldName) =>
+ this.toolDefinition is not null && this.ToolSettingsService.IsFieldLocked(this.toolDefinition, fieldName);
private string GetFieldPlaceholder(string fieldName, ToolSettingsFieldDefinition fieldDefinition) =>
string.IsNullOrWhiteSpace(this.GetValue(fieldName)) ? this.GetFieldDefaultValue(fieldName, fieldDefinition) : string.Empty;
diff --git a/app/MindWork AI Studio/Plugins/configuration/plugin.lua b/app/MindWork AI Studio/Plugins/configuration/plugin.lua
index 3cdc84ff..b2254f67 100644
--- a/app/MindWork AI Studio/Plugins/configuration/plugin.lua
+++ b/app/MindWork AI Studio/Plugins/configuration/plugin.lua
@@ -356,6 +356,15 @@ CONFIG["SETTINGS"] = {}
-- Examples are: "CmdOrControl+Shift+D", "Alt+F9", "F8"
-- CONFIG["SETTINGS"]["DataApp.ShortcutVoiceRecording"] = "CmdOrControl+1"
+-- Configure whether tools are available at all. The default is true.
+-- When tools are disabled globally, tool selection is hidden in chats and assistants,
+-- but the global tool settings remain available to administrators.
+-- CONFIG["SETTINGS"]["DataTools.EnableTools"] = false
+
+-- Disable individual tools by their stable tool ID. The default is an empty set.
+-- Unknown IDs are safely ignored and can be deployed before a future tool is installed.
+-- CONFIG["SETTINGS"]["DataTools.DisabledToolIds"] = { "web_search" }
+
-- Configure the minimum provider confidence level required for individual tools.
-- Tool IDs include: web_search, read_web_page
-- Allowed values are: NONE, UNTRUSTED, VERY_LOW, LOW, MODERATE, MEDIUM, HIGH
@@ -365,21 +374,47 @@ CONFIG["SETTINGS"] = {}
-- ["read_web_page"] = "MEDIUM"
-- }
--- Configure the SearXNG instance URL used by the Web Search tool.
--- You can enter either the instance root URL or the /search endpoint.
+-- Configure the Web Search tool. All values are strings.
+-- WebSearchBaseUrl: required SearXNG HTTP(S) root URL or /search endpoint; no default.
-- CONFIG["SETTINGS"]["DataTools.WebSearchBaseUrl"] = "https://searxng.website/"
--- CONFIG["SETTINGS"]["DataTools.WebSearchBaseUrl.AllowUserOverride"] = false
+-- WebSearchDefaultLanguage: optional language code; default is empty.
+-- CONFIG["SETTINGS"]["DataTools.WebSearchDefaultLanguage"] = "en"
+-- WebSearchDefaultSafeSearch: optional SearXNG safe-search level "0", "1", or "2"; default is empty.
+-- CONFIG["SETTINGS"]["DataTools.WebSearchDefaultSafeSearch"] = "1"
+-- WebSearchDefaultCategories: optional comma-separated categories; default is empty.
+-- WebSearchDefaultEngines: optional comma-separated engines; default is empty.
+-- Categories and engines cannot both be configured.
+-- CONFIG["SETTINGS"]["DataTools.WebSearchDefaultCategories"] = "general, science"
+-- CONFIG["SETTINGS"]["DataTools.WebSearchDefaultEngines"] = ""
+-- WebSearchMaxResults: positive integer; default 5, effective maximum 20.
+-- CONFIG["SETTINGS"]["DataTools.WebSearchMaxResults"] = "5"
+-- WebSearchTimeoutSeconds: positive integer; default 20, effective maximum 60.
+-- CONFIG["SETTINGS"]["DataTools.WebSearchTimeoutSeconds"] = "20"
+-- WebSearchMaxTotalContentCharacters: positive integer; default and maximum 100000.
+-- CONFIG["SETTINGS"]["DataTools.WebSearchMaxTotalContentCharacters"] = "100000"
+-- WebSearchMinContentCharactersPerResult: positive integer; default and maximum 3000.
+-- The total content budget must be at least this value multiplied by the hard limit of 20 results.
+-- CONFIG["SETTINGS"]["DataTools.WebSearchMinContentCharactersPerResult"] = "3000"
+-- WebSearchPageTimeoutSeconds: positive integer; default and maximum 30.
+-- CONFIG["SETTINGS"]["DataTools.WebSearchPageTimeoutSeconds"] = "30"
+-- WebSearchRetrievalTimeoutSeconds: positive integer; default and maximum 90.
+-- CONFIG["SETTINGS"]["DataTools.WebSearchRetrievalTimeoutSeconds"] = "90"
--- Configure private or VPN hosts that the Read Web Page tool may access.
--- Public web pages do not need to be listed here.
--- Private hosts listed here still require a provider with HIGH confidence before any page content is sent to the model.
--- For hosts on this allowlist, AI Studio also tries the current user's operating-system sign-in
--- automatically when the server requests integrated authentication (for example Kerberos or NTLM).
--- This does not reuse Firefox cookies or an existing browser session.
--- Separate host patterns with commas. Wildcards only match subdomains, so add the root domain separately if needed.
--- Examples:
+-- Configure the Read Web Page tool. All values are strings.
+-- ReadWebPageTimeoutSeconds: positive integer; default 30, effective maximum 60.
+-- CONFIG["SETTINGS"]["DataTools.ReadWebPageTimeoutSeconds"] = "30"
+-- ReadWebPageMaxContentCharacters: positive integer; default 30000, effective maximum 50000.
+-- CONFIG["SETTINGS"]["DataTools.ReadWebPageMaxContentCharacters"] = "30000"
+-- ReadWebPageAllowedPrivateHosts: optional comma-separated private or VPN host patterns; default is empty.
+-- Public pages do not need to be listed. Wildcards only match subdomains, so add the root domain separately.
+-- Allowed private hosts require a provider with HIGH confidence. AI Studio tries the current user's
+-- operating-system sign-in when integrated authentication is requested, but does not reuse browser cookies.
-- CONFIG["SETTINGS"]["DataTools.ReadWebPageAllowedPrivateHosts"] = "dlr.de, *.dlr.de"
--- CONFIG["SETTINGS"]["DataTools.ReadWebPageAllowedPrivateHosts.AllowUserOverride"] = false
+
+-- The 14 Web Search and Read Web Page settings are locked by default. Add
+-- ".AllowUserOverride" = true to any of them to provide an editable organization default instead.
+-- A saved local value then takes precedence.
+-- CONFIG["SETTINGS"]["DataTools.WebSearchBaseUrl.AllowUserOverride"] = true
-- Configure the HTTP timeout for external requests, in seconds.
-- The default is 3600 (1 hour).
diff --git a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs
index 44c83f88..792e65bb 100644
--- a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs
+++ b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs
@@ -107,7 +107,8 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
//
var providerConfidence = this.Provider.GetConfidence(settingsManager).Level;
var minimumWebSearchConfidence = settingsManager.GetMinimumProviderConfidenceForTool(ToolSelectionRules.WEB_SEARCH_TOOL_ID);
- var isWebSearchAllowed = ToolSelectionRules.IsProviderConfidenceAllowed(providerConfidence, minimumWebSearchConfidence);
+ var isWebSearchAllowed = settingsManager.IsToolActive(ToolSelectionRules.WEB_SEARCH_TOOL_ID) &&
+ ToolSelectionRules.IsProviderConfidenceAllowed(providerConfidence, minimumWebSearchConfidence);
IList