mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-04 22:47:21 +00:00
Added a way to switch off tools you never need (#1115)
This commit is contained in:
1 parent
dcba62b45c
commit
04546c25ac
31 files changed
+638
-37
No files matched your search
@@ -397,6 +397,7 @@ public partial class DataSourceSelection : MSGComponentBase
|
||||
ToolOfferBlockReason.TOOLS_SWITCHED_OFF => T("Your organization has switched tools off, so AI Studio uses classic RAG instead and searches your data sources with every message."),
|
||||
ToolOfferBlockReason.MODEL_CANNOT_USE_TOOLS => T("The selected model cannot use tools, so AI Studio uses classic RAG instead and searches your data sources with every message."),
|
||||
ToolOfferBlockReason.TOOL_SWITCHED_OFF => T("Your organization has switched Semantic Search off, so AI Studio uses classic RAG instead and searches your data sources with every message."),
|
||||
ToolOfferBlockReason.TOOL_SWITCHED_OFF_BY_USER => T("You switched Semantic Search off in the tool settings, so AI Studio uses classic RAG instead and searches your data sources with every message."),
|
||||
ToolOfferBlockReason.PROVIDER_CONFIDENCE_TOO_LOW => T("The selected provider is not trusted enough for Semantic Search, so AI Studio uses classic RAG instead and searches your data sources with every message."),
|
||||
_ => T("Semantic Search cannot be used here, so AI Studio uses classic RAG instead and searches your data sources with every message."),
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
@* Two independent reasons a tool stays out of reach, so both may show at once: *@
|
||||
@* Independent reasons a tool stays out of reach, so several may show at once: *@
|
||||
@if (this.ToolsNeedingConfiguration.Count > 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Warning" Variant="Variant.Outlined" Dense="@true" Class="@this.Class">
|
||||
@@ -23,4 +23,11 @@ else
|
||||
@(string.Format(T("Not all tools selected for this run can be used with the chosen AI provider: {0}. Please choose a provider with a higher confidence level to use all of them."), string.Join(", ", this.ToolsBeyondProviderConfidence)))
|
||||
</MudAlert>
|
||||
}
|
||||
|
||||
@if (this.ToolsSwitchedOffByUser.Count > 0)
|
||||
{
|
||||
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Dense="@true" Class="@this.Class">
|
||||
@(string.Format(T("Some tools selected for this run are switched off in your tool settings and stay unused: {0}. Switch them on again in the app settings to use them."), string.Join(", ", this.ToolsSwitchedOffByUser)))
|
||||
</MudAlert>
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ public partial class ManagedToolsWarning : MSGComponentBase
|
||||
private ToolRegistry ToolRegistry { get; init; } = null!;
|
||||
|
||||
private IReadOnlyList<ToolCatalogItem> availableTools = [];
|
||||
private IReadOnlyList<ToolCatalogItem> toolsSwitchedOffByUser = [];
|
||||
|
||||
/// <summary>
|
||||
/// Whether this run expects tools while the selected provider cannot call any.
|
||||
@@ -92,20 +93,59 @@ public partial class ManagedToolsWarning : MSGComponentBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The tools of this run which the user switched off in the tool settings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Whoever named these tools did not know that the user never needs them. The run goes on
|
||||
/// without them, as the user asked for, but saying nothing would leave them wondering why a
|
||||
/// policy does not search the web, say, long after they switched the web search off. Tools an
|
||||
/// organization switched off stay unnamed, as above.
|
||||
/// </remarks>
|
||||
private IReadOnlyList<string> ToolsSwitchedOffByUser
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.ToolIds.Count is 0 || !this.SettingsManager.AreToolsEnabled())
|
||||
return [];
|
||||
|
||||
var collectionIds = this.ToolRegistry.NormalizeSelection(this.ToolIds);
|
||||
return this.toolsSwitchedOffByUser
|
||||
.Where(x => collectionIds.Contains(x.Id))
|
||||
.Select(x => x.DisplayName)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
this.availableTools = await this.ToolRegistry.GetCatalogAsync(this.Component);
|
||||
await this.LoadToolsAsync();
|
||||
|
||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the tools of this component: those the user may use, and those they switched off.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The catalog of the component leaves out the tools the user switched off, so they come from
|
||||
/// all the tools this component knows.
|
||||
/// </remarks>
|
||||
private async Task LoadToolsAsync()
|
||||
{
|
||||
this.availableTools = await this.ToolRegistry.GetCatalogAsync(this.Component);
|
||||
this.toolsSwitchedOffByUser = (await this.ToolRegistry.GetCatalogAsync(this.ToolRegistry.GetDefinitionsForComponent(this.Component)))
|
||||
.Where(x => x.SwitchOffReason is ToolOfferBlockReason.TOOL_SWITCHED_OFF_BY_USER)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
this.availableTools = await this.ToolRegistry.GetCatalogAsync(this.Component);
|
||||
await this.LoadToolsAsync();
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Build" HeaderText="@T("Tool Settings")">
|
||||
<MudText Typo="Typo.body1" Class="mb-4">
|
||||
@T("Configure global settings for each tool.")
|
||||
@T("Configure global settings for each tool.") @T("Switch off the tools you never need: they then appear in no tool selection, and the AI cannot use them.")
|
||||
</MudText>
|
||||
|
||||
<MudTable Items="@this.items" Hover="@true" Dense="@true">
|
||||
<HeaderContent>
|
||||
<MudTh>@T("Enabled")</MudTh>
|
||||
<MudTh>@T("Icon")</MudTh>
|
||||
<MudTh>@T("Name")</MudTh>
|
||||
<MudTh>@T("Description")</MudTh>
|
||||
@@ -15,6 +16,11 @@
|
||||
<MudTh>@T("Settings")</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>
|
||||
<MudTooltip Text="@this.GetSwitchTooltip(context)">
|
||||
<MudSwitch T="bool" Value="@context.IsActive" ValueChanged="@(isOn => this.SwitchToolOnOrOff(context, isOn))" Disabled="@IsSwitchLocked(context)" Color="Color.Primary" />
|
||||
</MudTooltip>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
<MudIcon Icon="@context.Icon" Color="Color.Info" />
|
||||
</MudTd>
|
||||
@@ -35,7 +41,14 @@
|
||||
</MudMenu>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
@if (!context.IsActive)
|
||||
@if (IsSwitchedOffByUser(context))
|
||||
{
|
||||
@* Whether its settings are complete does not matter while nobody can use the tool: *@
|
||||
<MudTooltip Text="@T("You switched off this tool. It appears in no tool selection, and the AI cannot use it.")">
|
||||
<MudIcon Icon="@Icons.Material.Filled.VisibilityOff" Color="Color.Default" />
|
||||
</MudTooltip>
|
||||
}
|
||||
else if (!context.IsActive)
|
||||
{
|
||||
<MudTooltip Text="@T("This tool has been disabled by your organization.")">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Lock" Color="Color.Error" />
|
||||
|
||||
@@ -47,6 +47,36 @@ public partial class SettingsPanelTools : SettingsPanelBase
|
||||
await this.DialogService.ShowAsync<ToolSettingsExportDialog>(null, parameters, Dialogs.DialogOptions.FULLSCREEN);
|
||||
}
|
||||
|
||||
private static bool IsSwitchedOffByUser(ToolCatalogItem item) => item.SwitchOffReason is ToolOfferBlockReason.TOOL_SWITCHED_OFF_BY_USER;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the user cannot switch this tool on or off, because their organization switched it or all tools off.
|
||||
/// </summary>
|
||||
private static bool IsSwitchLocked(ToolCatalogItem item) => item.SwitchOffReason is ToolOfferBlockReason.TOOLS_SWITCHED_OFF or ToolOfferBlockReason.TOOL_SWITCHED_OFF;
|
||||
|
||||
private string GetSwitchTooltip(ToolCatalogItem item)
|
||||
{
|
||||
if (IsSwitchLocked(item))
|
||||
return this.T("This tool has been disabled by your organization.");
|
||||
|
||||
return IsSwitchedOffByUser(item)
|
||||
? this.T("Switch this tool on to use it again.")
|
||||
: this.T("Switch this tool off if you never need it. It then appears in no tool selection, and the AI cannot use it.");
|
||||
}
|
||||
|
||||
private async Task SwitchToolOnOrOff(ToolCatalogItem item, bool isOn)
|
||||
{
|
||||
if (IsSwitchLocked(item))
|
||||
return;
|
||||
|
||||
this.ToolRegistry.SetSwitchedOffByUser(item.Id, !isOn);
|
||||
await this.SettingsManager.StoreSettings();
|
||||
this.items = await this.ToolRegistry.GetCatalogAsync(this.ToolRegistry.GetAllDefinitions());
|
||||
|
||||
// Tool selections which are open right now load their list anew:
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
|
||||
private string GetConfigurationTooltip(ToolCatalogItem item) => item.ConfigurationState.MissingRequiredFields.Count switch
|
||||
{
|
||||
_ when !string.IsNullOrWhiteSpace(item.ConfigurationState.Message) => item.ConfigurationState.Message,
|
||||
|
||||
@@ -48,7 +48,9 @@ public partial class ToolDefaultsConfiguration : MSGComponentBase
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
private HashSet<string> GetSelectedValues() => this.ToolRegistry.GetDefaultToolIds(this.Component);
|
||||
// The list holds no tool the user switched off, so it must not count one as selected either:
|
||||
private HashSet<string> GetSelectedValues() => this.ToolRegistry.LeaveOutSwitchedOffByUser(this.ToolRegistry.GetDefaultToolIds(this.Component));
|
||||
|
||||
private void UpdateSelection(HashSet<string> values) => this.SettingsManager.ConfigurationData.Tools.DefaultToolIdsByComponent[this.Component.ToString()] = [..this.ToolRegistry.NormalizeSelection(values)];
|
||||
// Tools the user switched off stay preselected, so switching them on again brings them back:
|
||||
private void UpdateSelection(HashSet<string> values) => this.SettingsManager.ConfigurationData.Tools.DefaultToolIdsByComponent[this.Component.ToString()] = this.ToolRegistry.KeepSwitchedOffByUser(this.ToolRegistry.GetDefaultToolIds(this.Component), values);
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
OptionDescription="@this.Label"
|
||||
OptionHelp="@this.Help"
|
||||
Data="@this.availableTools"
|
||||
SelectedValues="@(() => this.SelectedToolIds)"
|
||||
SelectedValues="@this.GetShownToolIds"
|
||||
SelectionUpdateAsync="@this.OptionChangedAsync"
|
||||
Disabled="@(() => this.ReadOnly || this.Disabled)"
|
||||
IsItemLocked="@this.IsToolLocked"
|
||||
|
||||
@@ -69,9 +69,13 @@ public partial class ToolSelectionField : MSGComponentBase
|
||||
|
||||
private bool IsToolLocked(string toolId) => !this.ToolRegistry.IsToolActive(toolId);
|
||||
|
||||
// The field lists no tool the user switched off, so it must not count one as selected either:
|
||||
private HashSet<string> GetShownToolIds() => this.ToolRegistry.LeaveOutSwitchedOffByUser(this.SelectedToolIds);
|
||||
|
||||
private async Task OptionChangedAsync(HashSet<string> updatedToolIds)
|
||||
{
|
||||
this.SelectedToolIds = this.ToolRegistry.NormalizeSelection(updatedToolIds);
|
||||
// Tools the user switched off stay selected, so switching them on again brings them back:
|
||||
this.SelectedToolIds = this.ToolRegistry.KeepSwitchedOffByUser(this.SelectedToolIds, updatedToolIds);
|
||||
await this.SelectedToolIdsChanged.InvokeAsync(this.SelectedToolIds);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user