Initial support for confidence & standard profile

This commit is contained in:
Thorsten Sommer 2026-01-27 19:41:47 +01:00
parent da4d3508b2
commit 740fab37cf
Signed by untrusted user who does not match committer: tsommer
GPG Key ID: 371BBA77A02C0108
3 changed files with 112 additions and 21 deletions

View File

@ -1,6 +1,7 @@
@attribute [Route(Routes.ASSISTANT_DOCUMENT_ANALYSIS)] @attribute [Route(Routes.ASSISTANT_DOCUMENT_ANALYSIS)]
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogDocumentAnalysis> @inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogDocumentAnalysis>
@using AIStudio.Settings
@using AIStudio.Settings.DataModel @using AIStudio.Settings.DataModel
<PreviewPrototype ApplyInnerScrollingFix="true"/> <PreviewPrototype ApplyInnerScrollingFix="true"/>
@ -61,6 +62,10 @@ else
<MudTextSwitch Disabled="@(this.IsNoPolicySelected || (this.selectedPolicy?.IsManaged ?? true))" Label="@T("Would you like to protect this policy so that you cannot accidentally edit or delete it?")" Value="@this.policyIsProtected" ValueChanged="async state => await this.PolicyProtectionWasChanged(state)" LabelOn="@T("Yes, protect this policy")" LabelOff="@T("No, the policy can be edited")" /> <MudTextSwitch Disabled="@(this.IsNoPolicySelected || (this.selectedPolicy?.IsManaged ?? true))" Label="@T("Would you like to protect this policy so that you cannot accidentally edit or delete it?")" Value="@this.policyIsProtected" ValueChanged="async state => await this.PolicyProtectionWasChanged(state)" LabelOn="@T("Yes, protect this policy")" LabelOff="@T("No, the policy can be edited")" />
<ConfigurationMinConfidenceSelection Disabled="@(() => this.IsNoPolicySelectedOrProtected)" RestrictToGlobalMinimumConfidence="true" SelectedValue="@(() => this.policyMinimumProviderConfidence)" SelectionUpdateAsync="@(async level => await this.PolicyMinimumConfidenceWasChangedAsync(level))" />
<ConfigurationSelect OptionDescription="@T("Preselect one of your profiles?")" Disabled="@(() => this.IsNoPolicySelected)" SelectedValue="@(() => this.policyPreselectedProfileId)" Data="@ConfigurationSelectDataFactory.GetProfilesData(this.SettingsManager.ConfigurationData.Profiles)" SelectionUpdateAsync="@(async profileId => await this.PolicyPreselectedProfileWasChangedAsync(profileId))" OptionHelp="@T("Select a default profile for this policy. You can still change it later when running the assistant.")" />
<MudText Typo="Typo.h5" Class="mt-6 mb-1"> <MudText Typo="Typo.h5" Class="mt-6 mb-1">
@T("Analysis and output rules") @T("Analysis and output rules")
</MudText> </MudText>

View File

@ -1,8 +1,11 @@
using System.Text; using System.Text;
using System.Diagnostics.CodeAnalysis;
using AIStudio.Chat; using AIStudio.Chat;
using AIStudio.Dialogs; using AIStudio.Dialogs;
using AIStudio.Dialogs.Settings; using AIStudio.Dialogs.Settings;
using AIStudio.Provider;
using AIStudio.Settings;
using AIStudio.Settings.DataModel; using AIStudio.Settings.DataModel;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
@ -169,6 +172,8 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
this.policyIsProtected = false; this.policyIsProtected = false;
this.policyAnalysisRules = string.Empty; this.policyAnalysisRules = string.Empty;
this.policyOutputRules = string.Empty; this.policyOutputRules = string.Empty;
this.policyMinimumProviderConfidence = ConfidenceLevel.NONE;
this.policyPreselectedProfileId = Profile.NO_PROFILE.Id;
} }
} }
@ -181,6 +186,8 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
this.policyIsProtected = this.selectedPolicy.IsProtected; this.policyIsProtected = this.selectedPolicy.IsProtected;
this.policyAnalysisRules = this.selectedPolicy.AnalysisRules; this.policyAnalysisRules = this.selectedPolicy.AnalysisRules;
this.policyOutputRules = this.selectedPolicy.OutputRules; this.policyOutputRules = this.selectedPolicy.OutputRules;
this.policyMinimumProviderConfidence = this.selectedPolicy.MinimumProviderConfidence;
this.policyPreselectedProfileId = string.IsNullOrWhiteSpace(this.selectedPolicy.PreselectedProfile) ? Profile.NO_PROFILE.Id : this.selectedPolicy.PreselectedProfile;
return true; return true;
} }
@ -206,6 +213,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
this.policyDefinitionExpanded = !this.selectedPolicy?.IsProtected ?? true; this.policyDefinitionExpanded = !this.selectedPolicy?.IsProtected ?? true;
await base.OnInitializedAsync(); await base.OnInitializedAsync();
this.ApplyPolicyPreselection();
} }
#endregion #endregion
@ -215,19 +223,20 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
if(this.selectedPolicy is null) if(this.selectedPolicy is null)
return; return;
if(!force && this.selectedPolicy.IsProtected) // The preselected profile is always user-adjustable, even for protected policies.
return; this.selectedPolicy.PreselectedProfile = this.policyPreselectedProfileId;
if(!force && this.policyIsProtected)
return;
var canEditProtectedFields = force || (!this.selectedPolicy.IsProtected && !this.policyIsProtected);
if (canEditProtectedFields)
{
this.selectedPolicy.PreselectedProvider = this.providerSettings.Id; this.selectedPolicy.PreselectedProvider = this.providerSettings.Id;
this.selectedPolicy.PolicyName = this.policyName; this.selectedPolicy.PolicyName = this.policyName;
this.selectedPolicy.PolicyDescription = this.policyDescription; this.selectedPolicy.PolicyDescription = this.policyDescription;
this.selectedPolicy.IsProtected = this.policyIsProtected; this.selectedPolicy.IsProtected = this.policyIsProtected;
this.selectedPolicy.AnalysisRules = this.policyAnalysisRules; this.selectedPolicy.AnalysisRules = this.policyAnalysisRules;
this.selectedPolicy.OutputRules = this.policyOutputRules; this.selectedPolicy.OutputRules = this.policyOutputRules;
this.selectedPolicy.MinimumProviderConfidence = this.policyMinimumProviderConfidence;
}
await this.SettingsManager.StoreSettings(); await this.SettingsManager.StoreSettings();
} }
@ -239,6 +248,8 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
private string policyDescription = string.Empty; private string policyDescription = string.Empty;
private string policyAnalysisRules = string.Empty; private string policyAnalysisRules = string.Empty;
private string policyOutputRules = string.Empty; private string policyOutputRules = string.Empty;
private ConfidenceLevel policyMinimumProviderConfidence = ConfidenceLevel.NONE;
private string policyPreselectedProfileId = Profile.NO_PROFILE.Id;
private HashSet<FileAttachment> loadedDocumentPaths = []; private HashSet<FileAttachment> loadedDocumentPaths = [];
private bool IsNoPolicySelectedOrProtected => this.selectedPolicy is null || this.selectedPolicy.IsProtected; private bool IsNoPolicySelectedOrProtected => this.selectedPolicy is null || this.selectedPolicy.IsProtected;
@ -250,6 +261,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
this.selectedPolicy = policy; this.selectedPolicy = policy;
this.ResetForm(); this.ResetForm();
this.policyDefinitionExpanded = !this.selectedPolicy?.IsProtected ?? true; this.policyDefinitionExpanded = !this.selectedPolicy?.IsProtected ?? true;
this.ApplyPolicyPreselection();
} }
private Task PolicyDefinitionExpandedChanged(bool isExpanded) private Task PolicyDefinitionExpandedChanged(bool isExpanded)
@ -323,6 +335,76 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
await this.AutoSave(true); await this.AutoSave(true);
} }
[SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed", Justification = "Policy-specific preselection needs to probe providers by id before falling back to SettingsManager APIs.")]
private void ApplyPolicyPreselection()
{
if (this.selectedPolicy is null)
return;
var minimumLevel = this.GetPolicyMinimumConfidenceLevel();
// Keep the current provider if it still satisfies the minimum confidence:
if (this.providerSettings != Settings.Provider.NONE &&
this.providerSettings.UsedLLMProvider.GetConfidence(this.SettingsManager).Level >= minimumLevel)
{
this.currentProfile = this.ResolveProfileSelection();
return;
}
// Try to apply the policy preselection:
var policyProvider = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.selectedPolicy.PreselectedProvider);
if (policyProvider is not null && policyProvider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level >= minimumLevel)
{
this.providerSettings = policyProvider;
this.currentProfile = this.ResolveProfileSelection();
return;
}
this.providerSettings = this.SettingsManager.GetPreselectedProvider(this.Component, this.providerSettings.Id);
this.currentProfile = this.ResolveProfileSelection();
}
private ConfidenceLevel GetPolicyMinimumConfidenceLevel()
{
var minimumLevel = ConfidenceLevel.NONE;
var llmSettings = this.SettingsManager.ConfigurationData.LLMProviders;
var enforceGlobalMinimumConfidence = llmSettings is { EnforceGlobalMinimumConfidence: true, GlobalMinimumConfidence: not ConfidenceLevel.NONE and not ConfidenceLevel.UNKNOWN };
if (enforceGlobalMinimumConfidence)
minimumLevel = llmSettings.GlobalMinimumConfidence;
if (this.selectedPolicy is not null && this.selectedPolicy.MinimumProviderConfidence > minimumLevel)
minimumLevel = this.selectedPolicy.MinimumProviderConfidence;
return minimumLevel;
}
private Profile ResolveProfileSelection()
{
if (this.selectedPolicy is not null && !string.IsNullOrWhiteSpace(this.selectedPolicy.PreselectedProfile))
{
var policyProfile = this.SettingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == this.selectedPolicy.PreselectedProfile);
if (policyProfile is not null)
return policyProfile;
}
return this.SettingsManager.GetPreselectedProfile(this.Component);
}
private async Task PolicyMinimumConfidenceWasChangedAsync(ConfidenceLevel level)
{
this.policyMinimumProviderConfidence = level;
await this.AutoSave();
this.ApplyPolicyPreselection();
}
private async Task PolicyPreselectedProfileWasChangedAsync(string profileId)
{
this.policyPreselectedProfileId = profileId;
this.currentProfile = this.ResolveProfileSelection();
await this.AutoSave();
}
private string? ValidatePolicyName(string name) private string? ValidatePolicyName(string name)
{ {
if(string.IsNullOrWhiteSpace(name)) if(string.IsNullOrWhiteSpace(name))

View File

@ -88,8 +88,9 @@ public static class ComponentsExtensions
Components.BIAS_DAY_ASSISTANT => settingsManager.ConfigurationData.BiasOfTheDay.PreselectOptions ? settingsManager.ConfigurationData.BiasOfTheDay.MinimumProviderConfidence : default, Components.BIAS_DAY_ASSISTANT => settingsManager.ConfigurationData.BiasOfTheDay.PreselectOptions ? settingsManager.ConfigurationData.BiasOfTheDay.MinimumProviderConfidence : default,
Components.ERI_ASSISTANT => settingsManager.ConfigurationData.ERI.PreselectOptions ? settingsManager.ConfigurationData.ERI.MinimumProviderConfidence : default, Components.ERI_ASSISTANT => settingsManager.ConfigurationData.ERI.PreselectOptions ? settingsManager.ConfigurationData.ERI.MinimumProviderConfidence : default,
#warning Add minimum confidence for DOCUMENT_ANALYSIS_ASSISTANT: // The minimum confidence for the Document Analysis Assistant is set per policy.
//Components.DOCUMENT_ANALYSIS_ASSISTANT => settingsManager.ConfigurationData.DocumentAnalysis.PreselectOptions ? settingsManager.ConfigurationData.DocumentAnalysis.MinimumProviderConfidence : default, // We do this inside the Document Analysis Assistant component:
Components.DOCUMENT_ANALYSIS_ASSISTANT => ConfidenceLevel.NONE,
_ => default, _ => default,
}; };
@ -115,8 +116,9 @@ public static class ComponentsExtensions
Components.ERI_ASSISTANT => settingsManager.ConfigurationData.ERI.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.ERI.PreselectedProvider) : null, Components.ERI_ASSISTANT => settingsManager.ConfigurationData.ERI.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.ERI.PreselectedProvider) : null,
Components.I18N_ASSISTANT => settingsManager.ConfigurationData.I18N.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.I18N.PreselectedProvider) : null, Components.I18N_ASSISTANT => settingsManager.ConfigurationData.I18N.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.I18N.PreselectedProvider) : null,
#warning Add preselected provider for DOCUMENT_ANALYSIS_ASSISTANT: // The Document Analysis Assistant does not have a preselected provider at the component level.
//Components.DOCUMENT_ANALYSIS_ASSISTANT => settingsManager.ConfigurationData.DocumentAnalysis.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.DocumentAnalysis.PreselectedProvider) : null, // The provider is selected per policy instead. We do this inside the Document Analysis Assistant component.
Components.DOCUMENT_ANALYSIS_ASSISTANT => Settings.Provider.NONE,
Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Chat.PreselectedProvider) : null, Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Chat.PreselectedProvider) : null,
@ -132,8 +134,6 @@ public static class ComponentsExtensions
public static Profile PreselectedProfile(this Components component, SettingsManager settingsManager) => component switch public static Profile PreselectedProfile(this Components component, SettingsManager settingsManager) => component switch
{ {
#warning Add preselected profile for DOCUMENT_ANALYSIS_ASSISTANT:
// Components.DOCUMENT_ANALYSIS_ASSISTANT => settingsManager.ConfigurationData.DocumentAnalysis.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.DocumentAnalysis.PreselectedProfile) : default,
Components.AGENDA_ASSISTANT => settingsManager.ConfigurationData.Agenda.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Agenda.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, Components.AGENDA_ASSISTANT => settingsManager.ConfigurationData.Agenda.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Agenda.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE,
Components.CODING_ASSISTANT => settingsManager.ConfigurationData.Coding.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Coding.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, Components.CODING_ASSISTANT => settingsManager.ConfigurationData.Coding.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Coding.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE,
Components.EMAIL_ASSISTANT => settingsManager.ConfigurationData.EMail.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.EMail.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, Components.EMAIL_ASSISTANT => settingsManager.ConfigurationData.EMail.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.EMail.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE,
@ -142,6 +142,10 @@ public static class ComponentsExtensions
Components.BIAS_DAY_ASSISTANT => settingsManager.ConfigurationData.BiasOfTheDay.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.BiasOfTheDay.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, Components.BIAS_DAY_ASSISTANT => settingsManager.ConfigurationData.BiasOfTheDay.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.BiasOfTheDay.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE,
Components.ERI_ASSISTANT => settingsManager.ConfigurationData.ERI.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.ERI.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, Components.ERI_ASSISTANT => settingsManager.ConfigurationData.ERI.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.ERI.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE,
// The Document Analysis Assistant does not have a preselected profile at the component level.
// The profile is selected per policy instead. We do this inside the Document Analysis Assistant component:
Components.DOCUMENT_ANALYSIS_ASSISTANT => Profile.NO_PROFILE,
Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Chat.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Chat.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE,
_ => Profile.NO_PROFILE, _ => Profile.NO_PROFILE,