mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-06-27 17:16:28 +00:00
use individual confidence levels for each tool to protect tool callings from using unsafe providers
This commit is contained in:
parent
0cd24c5ec1
commit
f2c63ac4b5
@ -81,7 +81,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// Apply the filters for the message bus:
|
||||
this.ApplyFilters([], [ Event.HAS_CHAT_UNSAVED_CHANGES, Event.RESET_CHAT_STATE, Event.CHAT_STREAMING_DONE, Event.WORKSPACE_LOADED_CHAT_CHANGED ]);
|
||||
this.ApplyFilters([], [ Event.HAS_CHAT_UNSAVED_CHANGES, Event.RESET_CHAT_STATE, Event.CHAT_STREAMING_DONE, Event.WORKSPACE_LOADED_CHAT_CHANGED, Event.CONFIGURATION_CHANGED ]);
|
||||
|
||||
// Configure the spellchecking for the user input:
|
||||
this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES);
|
||||
@ -1007,6 +1007,10 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
case Event.WORKSPACE_LOADED_CHAT_CHANGED:
|
||||
await this.LoadedChatChanged();
|
||||
break;
|
||||
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
@using AIStudio.Provider
|
||||
@using AIStudio.Tools.ToolCallingSystem
|
||||
@inherits SettingsPanelBase
|
||||
|
||||
@ -11,6 +12,7 @@
|
||||
<MudTh>@T("Icon")</MudTh>
|
||||
<MudTh>@T("Name")</MudTh>
|
||||
<MudTh>@T("Description")</MudTh>
|
||||
<MudTh>@T("Minimum provider confidence")</MudTh>
|
||||
<MudTh>@T("State")</MudTh>
|
||||
<MudTh>@T("Settings")</MudTh>
|
||||
</HeaderContent>
|
||||
@ -24,6 +26,16 @@
|
||||
<MudTd>
|
||||
<MudText Typo="Typo.body2">@context.Implementation.GetDescription()</MudText>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
<MudMenu StartIcon="@Icons.Material.Filled.Security" EndIcon="@Icons.Material.Filled.KeyboardArrowDown" Label="@this.GetCurrentConfidenceLevelName(context)" Variant="Variant.Filled" Style="@this.SetCurrentConfidenceLevelColorStyle(context)" Disabled="@this.IsToolConfidenceManaged()">
|
||||
@foreach (var confidenceLevel in this.GetSelectableConfidenceLevels())
|
||||
{
|
||||
<MudMenuItem OnClick="@(async () => await this.ChangeMinimumProviderConfidence(context, confidenceLevel))">
|
||||
@this.GetConfidenceLevelName(confidenceLevel)
|
||||
</MudMenuItem>
|
||||
}
|
||||
</MudMenu>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
@if (context.ConfigurationState.IsConfigured)
|
||||
{
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Dialogs.Settings;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools;
|
||||
using AIStudio.Tools.ToolCallingSystem;
|
||||
|
||||
@ -15,8 +17,9 @@ public partial class SettingsPanelTools : SettingsPanelBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
|
||||
this.items = await this.ToolRegistry.GetCatalogAsync(this.ToolRegistry.GetAllDefinitions());
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
private async Task OpenSettings(string toolId)
|
||||
@ -47,4 +50,40 @@ public partial class SettingsPanelTools : SettingsPanelBase
|
||||
|
||||
return item.Implementation.GetSettingsFieldLabel(fieldName, fieldDefinition);
|
||||
}
|
||||
|
||||
private IEnumerable<ConfidenceLevel> GetSelectableConfidenceLevels() =>
|
||||
Enum.GetValues<ConfidenceLevel>().OrderBy(x => x).Where(x => x is not ConfidenceLevel.UNKNOWN);
|
||||
|
||||
private string GetCurrentConfidenceLevelName(ToolCatalogItem item) => this.GetConfidenceLevelName(this.GetMinimumProviderConfidence(item));
|
||||
|
||||
private string GetConfidenceLevelName(ConfidenceLevel confidenceLevel) => confidenceLevel is ConfidenceLevel.NONE
|
||||
? this.T("No minimum confidence level chosen")
|
||||
: confidenceLevel.GetName();
|
||||
|
||||
private string SetCurrentConfidenceLevelColorStyle(ToolCatalogItem item) =>
|
||||
$"background-color: {this.GetMinimumProviderConfidence(item).GetColor(this.SettingsManager)};";
|
||||
|
||||
private bool IsToolConfidenceManaged() =>
|
||||
ManagedConfiguration.TryGet(x => x.Tools, x => x.MinimumProviderConfidenceByToolId, out var meta) && meta.IsLocked;
|
||||
|
||||
private ConfidenceLevel GetMinimumProviderConfidence(ToolCatalogItem item) => this.SettingsManager.GetMinimumProviderConfidenceForTool(item.Definition.Id);
|
||||
|
||||
private async Task ChangeMinimumProviderConfidence(ToolCatalogItem item, ConfidenceLevel confidenceLevel)
|
||||
{
|
||||
this.SettingsManager.SetMinimumProviderConfidenceForTool(item.Definition.Id, confidenceLevel);
|
||||
await this.SettingsManager.StoreSettings();
|
||||
this.items = await this.ToolRegistry.GetCatalogAsync(this.ToolRegistry.GetAllDefinitions());
|
||||
await this.MessageBus.SendMessage<bool>(this, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
|
||||
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
this.items = await this.ToolRegistry.GetCatalogAsync(this.ToolRegistry.GetAllDefinitions());
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,10 +40,12 @@
|
||||
var isSelected = this.SelectedToolIds.Contains(item.Definition.Id);
|
||||
var isConfigured = item.ConfigurationState.IsConfigured;
|
||||
var dependencyHint = this.GetDependencyHint(item.Definition.Id);
|
||||
var providerConfidenceHint = this.GetProviderConfidenceHint(item);
|
||||
var isBlockedByProviderConfidence = this.IsBlockedByProviderConfidence(item);
|
||||
<MudPaper Class="pa-2 mb-2 border rounded-lg">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
|
||||
<MudSwitch T="bool" Color="Color.Primary" Value="@isSelected" ValueChanged="@(value => this.ChangeSelection(item.Definition.Id, value))" Disabled="@(!isConfigured || this.Disabled || !this.SupportsTools || this.IsSelectionLockedByDependency(item.Definition.Id))" />
|
||||
<MudSwitch T="bool" Color="Color.Primary" Value="@isSelected" ValueChanged="@(value => this.ChangeSelection(item.Definition.Id, value))" Disabled="@(!isConfigured || isBlockedByProviderConfidence || this.Disabled || !this.SupportsTools || this.IsSelectionLockedByDependency(item.Definition.Id))" />
|
||||
<MudIcon Icon="@item.Implementation.Icon" Color="Color.Info" />
|
||||
<MudTooltip Text="@item.Implementation.GetDescription()">
|
||||
<MudText Typo="Typo.body1">@item.Implementation.GetDisplayName()</MudText>
|
||||
@ -59,6 +61,10 @@
|
||||
{
|
||||
<MudText Typo="Typo.caption" Color="Color.Info">@dependencyHint</MudText>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(providerConfidenceHint))
|
||||
{
|
||||
<MudText Typo="Typo.caption" Color="Color.Warning">@providerConfidenceHint</MudText>
|
||||
}
|
||||
</MudPaper>
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,11 +43,21 @@ public partial class ToolSelection : MSGComponentBase
|
||||
base.OnParametersSet();
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
private bool SupportsTools =>
|
||||
this.LLMProvider != AIStudio.Settings.Provider.NONE &&
|
||||
this.LLMProvider.GetModelCapabilities().Contains(Capability.CHAT_COMPLETION_API) &&
|
||||
this.LLMProvider.GetModelCapabilities().Contains(Capability.FUNCTION_CALLING);
|
||||
|
||||
private ConfidenceLevel ProviderConfidence => this.LLMProvider == AIStudio.Settings.Provider.NONE
|
||||
? ConfidenceLevel.NONE
|
||||
: this.LLMProvider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level;
|
||||
|
||||
private async Task ToggleSelection()
|
||||
{
|
||||
this.showSelection = !this.showSelection;
|
||||
@ -72,6 +82,10 @@ public partial class ToolSelection : MSGComponentBase
|
||||
|
||||
private bool IsSelectionLockedByDependency(string toolId) => ToolSelectionRules.IsRequiredBySelectedTools(toolId, this.SelectedToolIds);
|
||||
|
||||
private ConfidenceLevel GetMinimumProviderConfidence(ToolCatalogItem item) => this.SettingsManager.GetMinimumProviderConfidenceForTool(item.Definition.Id);
|
||||
|
||||
private bool IsBlockedByProviderConfidence(ToolCatalogItem item) => !ToolSelectionRules.IsProviderConfidenceAllowed(this.ProviderConfidence, this.GetMinimumProviderConfidence(item));
|
||||
|
||||
private string? GetDependencyHint(string toolId)
|
||||
{
|
||||
if (toolId == ToolSelectionRules.WEB_SEARCH_TOOL_ID)
|
||||
@ -83,6 +97,17 @@ public partial class ToolSelection : MSGComponentBase
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? GetProviderConfidenceHint(ToolCatalogItem item)
|
||||
{
|
||||
if (!this.IsBlockedByProviderConfidence(item))
|
||||
return null;
|
||||
|
||||
return string.Format(
|
||||
this.T("This tool requires provider confidence {0}. The selected provider has {1}."),
|
||||
this.GetMinimumProviderConfidence(item).GetName(),
|
||||
this.ProviderConfidence.GetName());
|
||||
}
|
||||
|
||||
private async Task OpenSettings(string toolId)
|
||||
{
|
||||
var parameters = new DialogParameters<ToolSettingsDialog>
|
||||
@ -95,4 +120,15 @@ public partial class ToolSelection : MSGComponentBase
|
||||
this.catalog = await this.ToolRegistry.GetCatalogAsync(this.Component);
|
||||
this.StateHasChanged();
|
||||
}
|
||||
|
||||
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
|
||||
{
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.CONFIGURATION_CHANGED when this.showSelection:
|
||||
this.catalog = await this.ToolRegistry.GetCatalogAsync(this.Component);
|
||||
await this.InvokeAsync(this.StateHasChanged);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ using System.Text.Json;
|
||||
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.ToolCallingSystem;
|
||||
|
||||
namespace AIStudio.Provider.OpenAI;
|
||||
|
||||
@ -78,11 +79,12 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, "https
|
||||
//
|
||||
// Prepare the tools we want to use:
|
||||
//
|
||||
IList<ProviderTool> providerTools = modelCapabilities.Contains(Capability.WEB_SEARCH) switch
|
||||
{
|
||||
true => [ ProviderTools.WEB_SEARCH ],
|
||||
_ => []
|
||||
};
|
||||
var providerConfidence = this.Provider.GetConfidence(settingsManager).Level;
|
||||
var minimumWebSearchConfidence = settingsManager.GetMinimumProviderConfidenceForTool(ToolSelectionRules.WEB_SEARCH_TOOL_ID);
|
||||
var isWebSearchAllowed = ToolSelectionRules.IsProviderConfidenceAllowed(providerConfidence, minimumWebSearchConfidence);
|
||||
IList<ProviderTool> providerTools = modelCapabilities.Contains(Capability.WEB_SEARCH) && isWebSearchAllowed
|
||||
? [ ProviderTools.WEB_SEARCH ]
|
||||
: [];
|
||||
|
||||
|
||||
// Parse the API parameters:
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
|
||||
namespace AIStudio.Tools.ToolCallingSystem;
|
||||
@ -90,6 +91,8 @@ public sealed class ToolCatalogItem
|
||||
public required IToolImplementation Implementation { get; init; }
|
||||
|
||||
public required ToolConfigurationState ConfigurationState { get; init; }
|
||||
|
||||
public ConfidenceLevel MinimumProviderConfidence { get; init; } = ConfidenceLevel.NONE;
|
||||
}
|
||||
|
||||
public sealed class ToolSelectionState
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using System.Text.Json;
|
||||
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
||||
@ -9,6 +10,7 @@ namespace AIStudio.Tools.ToolCallingSystem;
|
||||
public sealed class ToolRegistry
|
||||
{
|
||||
private readonly ILogger<ToolRegistry> logger;
|
||||
private readonly SettingsManager settingsManager;
|
||||
private readonly ToolSettingsService toolSettingsService;
|
||||
private readonly Dictionary<string, ToolDefinition> definitionsById = new(StringComparer.Ordinal);
|
||||
private readonly Dictionary<string, IToolImplementation> implementationsByKey = new(StringComparer.Ordinal);
|
||||
@ -16,10 +18,12 @@ public sealed class ToolRegistry
|
||||
public ToolRegistry(
|
||||
IWebHostEnvironment webHostEnvironment,
|
||||
IEnumerable<IToolImplementation> implementations,
|
||||
SettingsManager settingsManager,
|
||||
ToolSettingsService toolSettingsService,
|
||||
ILogger<ToolRegistry> logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.settingsManager = settingsManager;
|
||||
this.toolSettingsService = toolSettingsService;
|
||||
|
||||
foreach (var implementation in implementations)
|
||||
@ -101,6 +105,7 @@ public sealed class ToolRegistry
|
||||
Definition = definition,
|
||||
Implementation = implementation,
|
||||
ConfigurationState = await this.toolSettingsService.GetConfigurationStateAsync(definition, implementation),
|
||||
MinimumProviderConfidence = this.settingsManager.GetMinimumProviderConfidenceForTool(definition.Id),
|
||||
});
|
||||
}
|
||||
|
||||
@ -111,6 +116,7 @@ public sealed class ToolRegistry
|
||||
AIStudio.Tools.Components component,
|
||||
IEnumerable<string> selectedToolIds,
|
||||
IReadOnlyCollection<Capability> modelCapabilities,
|
||||
ConfidenceLevel providerConfidence,
|
||||
bool isToolSelectionVisible)
|
||||
{
|
||||
if (!isToolSelectionVisible)
|
||||
@ -131,6 +137,10 @@ public sealed class ToolRegistry
|
||||
if (!configurationState.IsConfigured)
|
||||
continue;
|
||||
|
||||
var minimumToolConfidence = this.settingsManager.GetMinimumProviderConfidenceForTool(definition.Id);
|
||||
if (!ToolSelectionRules.IsProviderConfidenceAllowed(providerConfidence, minimumToolConfidence))
|
||||
continue;
|
||||
|
||||
result.Add((definition, implementation));
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using AIStudio.Provider;
|
||||
|
||||
namespace AIStudio.Tools.ToolCallingSystem;
|
||||
|
||||
public static class ToolSelectionRules
|
||||
@ -22,4 +24,14 @@ public static class ToolSelectionRules
|
||||
var normalized = NormalizeSelection(selectedToolIds);
|
||||
return toolId == READ_WEB_PAGE_TOOL_ID && normalized.Contains(WEB_SEARCH_TOOL_ID);
|
||||
}
|
||||
|
||||
public static ConfidenceLevel GetDefaultMinimumProviderConfidence(string toolId) => toolId switch
|
||||
{
|
||||
WEB_SEARCH_TOOL_ID => ConfidenceLevel.MEDIUM,
|
||||
READ_WEB_PAGE_TOOL_ID => ConfidenceLevel.MEDIUM,
|
||||
_ => ConfidenceLevel.NONE,
|
||||
};
|
||||
|
||||
public static bool IsProviderConfidenceAllowed(ConfidenceLevel providerConfidence, ConfidenceLevel minimumToolConfidence) =>
|
||||
minimumToolConfidence is ConfidenceLevel.NONE || providerConfidence >= minimumToolConfidence;
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
- Added a start-page setting, so AI Studio can now open directly on your preferred page when the app starts. Configuration plugins can also provide and optionally lock this default for organizations.
|
||||
- Added math rendering in chats for LaTeX display formulas, including block formats such as `$$ ... $$` and `\[ ... \]`.
|
||||
- Added the latest OpenAI models.
|
||||
- Added minimum provider confidence settings for tools, so sensitive tools such as web search can be limited to trusted providers. Configuration plugins can also manage these defaults for organizations.
|
||||
- Released the document analysis assistant after an intense testing phase.
|
||||
- Improved enterprise deployment for organizations: administrators can now provide up to 10 centrally managed enterprise configuration slots, use policy files on Linux and macOS, and continue using older configuration formats as a fallback during migration.
|
||||
- Improved the profile selection for assistants and the chat. You can now explicitly choose between the app default profile, no profile, or a specific profile.
|
||||
@ -27,4 +28,4 @@
|
||||
- Fixed an issue where the app could turn white or appear invisible in certain chats after HTML-like content was shown. Thanks, Inga, for reporting this issue and providing some context on how to reproduce it.
|
||||
- Fixed security issues in the native app runtime by strengthening how AI Studio creates and protects the secret values used for its internal secure connection.
|
||||
- Updated several security-sensitive Rust dependencies in the native runtime to address known vulnerabilities.
|
||||
- Updated .NET to v9.0.14
|
||||
- Updated .NET to v9.0.14
|
||||
|
||||
Loading…
Reference in New Issue
Block a user