mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-18 08:58:00 +00:00
Kept overlapping settings operations from freezing the Document Analysis assistant (#970)
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Verify (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Verify (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
1 parent
b8d971c586
commit
0993517608
11 files changed
+409
-56
No files matched your search
@@ -184,7 +184,7 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
|
||||
this.formChangeTimer.Elapsed += (_, _) =>
|
||||
{
|
||||
this.formChangeTimer.Stop();
|
||||
this.OnFormChange().Observe($"{nameof(AssistantBase<TSettings>)}: handling a form change");
|
||||
this.InvokeAsync(this.OnFormChange).Observe($"{nameof(AssistantBase<TSettings>)}: handling a form change");
|
||||
};
|
||||
|
||||
this.MightPreselectValues();
|
||||
|
||||
@@ -104,13 +104,13 @@ else
|
||||
@T("Note: This setting only takes effect when this policy is exported and distributed via a configuration plugin to other users. When enabled, users will only see the document selection interface and cannot view or modify the policy details. This setting does NOT affect your local view - you will always see the full policy definition for policies you create.")
|
||||
</MudJustifiedText>
|
||||
|
||||
<ConfigurationMinConfidenceSelection Disabled="@(() => this.IsNoPolicySelectedOrProtected)" RestrictToGlobalMinimumConfidence="true" SelectedValue="@(() => this.policyMinimumProviderConfidence)" SelectionUpdateAsync="@(async level => await this.PolicyMinimumConfidenceWasChangedAsync(level))" />
|
||||
<ConfigurationMinConfidenceSelection Disabled="@(() => this.IsNoPolicySelectedOrProtected)" RestrictToGlobalMinimumConfidence="true" SelectedValue="@(() => this.policyMinimumProviderConfidence)" SelectionUpdate="@this.PolicyMinimumConfidenceWasChanged" />
|
||||
|
||||
<ToolSelectionField Component="@this.Component" SelectedToolIds="@this.policyAllowedToolIds" SelectedToolIdsChanged="@this.PolicyAllowedToolsWasChangedAsync" Disabled="@this.IsNoPolicySelectedOrProtected" Label="@T("Tools this policy permits")" Help="@T("Only the tools selected here can be used by the AI for an analysis with this policy. Every tool still has to meet the confidence requirements of the selected provider, so a tool may remain unavailable even when this policy permits it.")"/>
|
||||
<ToolSelectionField Component="@this.Component" SelectedToolIds="@this.policyAllowedToolIds" SelectedToolIdsChanged="@this.PolicyAllowedToolsWasChanged" Disabled="@this.IsNoPolicySelectedOrProtected" Label="@T("Tools this policy permits")" Help="@T("Only the tools selected here can be used by the AI for an analysis with this policy. Every tool still has to meet the confidence requirements of the selected provider, so a tool may remain unavailable even when this policy permits it.")"/>
|
||||
|
||||
<ConfigurationProviderSelection Component="Components.DOCUMENT_ANALYSIS_ASSISTANT" Data="@this.availableLLMProviders" Disabled="@(() => this.IsNoPolicySelectedOrProtected)" SelectedValue="@(() => this.policyPreselectedProviderId)" SelectionUpdate="@this.PolicyPreselectedProviderWasChanged" ExplicitMinimumConfidence="@this.GetPolicyMinimumConfidenceLevel()"/>
|
||||
|
||||
<ConfigurationSelect OptionDescription="@T("Preselect a profile")" Disabled="@(() => this.IsNoPolicySelected)" SelectedValue="@(() => this.policyPreselectedProfile)" Data="@ConfigurationSelectDataFactory.GetComponentProfilesData(this.SettingsManager.ConfigurationData.Profiles)" SelectionUpdateAsync="@(async selection => await this.PolicyPreselectedProfileWasChangedAsync(selection))" OptionHelp="@T("Choose whether the policy should use the app default profile, no profile, or a specific profile.")"/>
|
||||
<ConfigurationSelect OptionDescription="@T("Preselect a profile")" Disabled="@(() => this.IsNoPolicySelected)" SelectedValue="@(() => this.policyPreselectedProfile)" Data="@ConfigurationSelectDataFactory.GetComponentProfilesData(this.SettingsManager.ConfigurationData.Profiles)" SelectionUpdate="@this.PolicyPreselectedProfileWasChanged" OptionHelp="@T("Choose whether the policy should use the app default profile, no profile, or a specific profile.")"/>
|
||||
|
||||
<MudTextSwitch Disabled="@(this.IsNoPolicySelected || (this.selectedPolicy?.IsEnterpriseConfiguration ?? 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")" />
|
||||
|
||||
|
||||
+104
-32
@@ -255,33 +255,80 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
|
||||
|
||||
private async Task AutoSave(bool force = false)
|
||||
{
|
||||
if(this.selectedPolicy is null)
|
||||
return;
|
||||
//
|
||||
// A pending store is a property of the settings, not of the selected policy: the value has
|
||||
// been written into its policy already, so what is still outstanding is the store itself.
|
||||
// It therefore outlives a form reset and a switch to another policy, and only a completed
|
||||
// store clears it.
|
||||
//
|
||||
var hasChanges = this.policyStorePending;
|
||||
if(this.selectedPolicy is { } policy)
|
||||
hasChanges |= this.ApplyFormToPolicy(policy, force);
|
||||
|
||||
// The preselected profile is always user-adjustable, even for protected policies and enterprise configurations:
|
||||
this.selectedPolicy.PreselectedProfile = this.policyPreselectedProfile;
|
||||
|
||||
// Enterprise configurations cannot be modified at all:
|
||||
if(this.selectedPolicy.IsEnterpriseConfiguration)
|
||||
if (!hasChanges)
|
||||
return;
|
||||
|
||||
var canEditProtectedFields = force || (!this.selectedPolicy.IsProtected && !this.policyIsProtected);
|
||||
if (canEditProtectedFields)
|
||||
{
|
||||
this.selectedPolicy.PreselectedProvider = this.policyPreselectedProviderId;
|
||||
this.selectedPolicy.PolicyName = this.policyName;
|
||||
this.selectedPolicy.PolicyDescription = this.policyDescription;
|
||||
this.selectedPolicy.IsProtected = this.policyIsProtected;
|
||||
this.selectedPolicy.HidePolicyDefinition = this.policyHidePolicyDefinition;
|
||||
this.selectedPolicy.AnalysisRules = this.policyAnalysisRules;
|
||||
this.selectedPolicy.OutputRules = this.policyOutputRules;
|
||||
this.selectedPolicy.MinimumProviderConfidence = this.policyMinimumProviderConfidence;
|
||||
this.selectedPolicy.AllowedToolIds = [..this.policyAllowedToolIds];
|
||||
}
|
||||
|
||||
await this.SettingsManager.StoreSettings();
|
||||
this.policyStorePending = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes the form values over into the given policy.
|
||||
/// </summary>
|
||||
/// <param name="policy">The policy to write the form values to.</param>
|
||||
/// <param name="force">Whether the protected fields may be written as well.</param>
|
||||
/// <returns>True when this changed anything about the policy, false otherwise.</returns>
|
||||
private bool ApplyFormToPolicy(DataDocumentAnalysisPolicy policy, bool force)
|
||||
{
|
||||
// The preselected profile is always user-adjustable, even for protected policies and enterprise configurations:
|
||||
var hasChanges = policy.PreselectedProfile != this.policyPreselectedProfile;
|
||||
policy.PreselectedProfile = this.policyPreselectedProfile;
|
||||
|
||||
// Enterprise configurations cannot be modified at all:
|
||||
if(policy.IsEnterpriseConfiguration)
|
||||
return hasChanges;
|
||||
|
||||
var canEditProtectedFields = force || (!policy.IsProtected && !this.policyIsProtected);
|
||||
if (!canEditProtectedFields)
|
||||
return hasChanges;
|
||||
|
||||
hasChanges = hasChanges
|
||||
|| policy.PolicyName != this.policyName
|
||||
|| policy.PreselectedProvider != this.policyPreselectedProviderId
|
||||
|| policy.PolicyDescription != this.policyDescription
|
||||
|| policy.IsProtected != this.policyIsProtected
|
||||
|| policy.HidePolicyDefinition != this.policyHidePolicyDefinition
|
||||
|| policy.AnalysisRules != this.policyAnalysisRules
|
||||
|| policy.OutputRules != this.policyOutputRules
|
||||
|| policy.MinimumProviderConfidence != this.policyMinimumProviderConfidence
|
||||
|| !policy.AllowedToolIds.SetEquals(this.policyAllowedToolIds);
|
||||
|
||||
policy.PreselectedProvider = this.policyPreselectedProviderId;
|
||||
policy.PolicyName = this.policyName;
|
||||
policy.PolicyDescription = this.policyDescription;
|
||||
policy.IsProtected = this.policyIsProtected;
|
||||
policy.HidePolicyDefinition = this.policyHidePolicyDefinition;
|
||||
policy.AnalysisRules = this.policyAnalysisRules;
|
||||
policy.OutputRules = this.policyOutputRules;
|
||||
policy.MinimumProviderConfidence = this.policyMinimumProviderConfidence;
|
||||
policy.AllowedToolIds = [..this.policyAllowedToolIds];
|
||||
return hasChanges;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the given policy may take over an edit of one of its protected fields right now.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The handlers which write their value straight into the policy have to ask this themselves.
|
||||
/// ApplyFormToPolicy asks the same question, but it never gets to judge their fields: they have
|
||||
/// already brought policy and form in line, so nothing is left for it to compare. The markup
|
||||
/// disables those controls for a protected policy and an enterprise policy is always a protected
|
||||
/// one, which is why nobody should ever reach a handler that way -- this keeps the rule in the
|
||||
/// code as well, where the next handler will look for it. The form value counts alongside the
|
||||
/// stored one, because the protection switch is flipped before the store which writes it has run.
|
||||
/// </remarks>
|
||||
private bool AcceptsProtectedFieldEdits(DataDocumentAnalysisPolicy policy) => policy is { IsEnterpriseConfiguration: false, IsProtected: false } && !this.policyIsProtected;
|
||||
|
||||
private DataDocumentAnalysisPolicy? selectedPolicy;
|
||||
private bool policyIsProtected;
|
||||
private bool policyHidePolicyDefinition;
|
||||
@@ -298,6 +345,21 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
|
||||
/// </remarks>
|
||||
private bool documentSelectionExpanded;
|
||||
private string policyName = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Whether an edit already applied to a policy still waits to be written to the settings file.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Some handlers apply their value to the selected policy at once, because the rest of the
|
||||
/// assistant reads it back from there right away: the policy list has to show a new name while
|
||||
/// it is being typed, and the provider preselection is recomputed from the policy, not from the
|
||||
/// form. Doing so leaves the auto-save nothing to compare the form against -- form and policy
|
||||
/// already agree -- so every such handler has to announce the store itself. That is what this
|
||||
/// flag is for. It belongs to no particular policy: the value has long arrived where it
|
||||
/// belongs, only the file has not caught up yet, which is why a form reset or a switch to
|
||||
/// another policy does not clear it. Only a completed store does.
|
||||
/// </remarks>
|
||||
private bool policyStorePending;
|
||||
private string policyDescription = string.Empty;
|
||||
private string policyAnalysisRules = string.Empty;
|
||||
private string policyOutputRules = string.Empty;
|
||||
@@ -477,6 +539,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
|
||||
return;
|
||||
|
||||
this.selectedPolicy.PolicyName = this.policyName;
|
||||
this.policyStorePending = true;
|
||||
}
|
||||
|
||||
private async Task PolicyProtectionWasChanged(bool state)
|
||||
@@ -488,7 +551,6 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
|
||||
return;
|
||||
|
||||
this.policyIsProtected = state;
|
||||
this.selectedPolicy.IsProtected = state;
|
||||
this.policyDefinitionExpanded = !state;
|
||||
this.documentSelectionExpanded = state;
|
||||
await this.AutoSave(true);
|
||||
@@ -503,7 +565,6 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
|
||||
return;
|
||||
|
||||
this.policyHidePolicyDefinition = state;
|
||||
this.selectedPolicy.HidePolicyDefinition = state;
|
||||
await this.AutoSave(true);
|
||||
}
|
||||
|
||||
@@ -580,39 +641,50 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<NoSettingsPan
|
||||
/// <summary>
|
||||
/// Takes over the tools this policy permits.
|
||||
/// </summary>
|
||||
private async Task PolicyAllowedToolsWasChangedAsync(HashSet<string> allowedToolIds)
|
||||
private void PolicyAllowedToolsWasChanged(HashSet<string> allowedToolIds)
|
||||
{
|
||||
this.policyAllowedToolIds = allowedToolIds;
|
||||
await this.AutoSave();
|
||||
if (this.selectedPolicy is not { } policy || !this.AcceptsProtectedFieldEdits(policy))
|
||||
return;
|
||||
|
||||
policy.AllowedToolIds = [..allowedToolIds];
|
||||
this.policyStorePending = true;
|
||||
}
|
||||
|
||||
private async Task PolicyMinimumConfidenceWasChangedAsync(ConfidenceLevel level)
|
||||
private void PolicyMinimumConfidenceWasChanged(ConfidenceLevel level)
|
||||
{
|
||||
this.policyMinimumProviderConfidence = level;
|
||||
await this.AutoSave();
|
||||
|
||||
if (this.selectedPolicy is { } policy && this.AcceptsProtectedFieldEdits(policy))
|
||||
{
|
||||
policy.MinimumProviderConfidence = level;
|
||||
this.policyStorePending = true;
|
||||
}
|
||||
|
||||
this.ApplyPolicyPreselection();
|
||||
}
|
||||
|
||||
private void PolicyPreselectedProviderWasChanged(string providerId)
|
||||
{
|
||||
if (this.selectedPolicy is null)
|
||||
if (this.selectedPolicy is not { } policy || !this.AcceptsProtectedFieldEdits(policy))
|
||||
return;
|
||||
|
||||
this.policyPreselectedProviderId = providerId;
|
||||
this.selectedPolicy.PreselectedProvider = providerId;
|
||||
policy.PreselectedProvider = providerId;
|
||||
this.policyStorePending = true;
|
||||
this.ProviderSettings = Settings.Provider.NONE;
|
||||
this.ApplyPolicyPreselection();
|
||||
}
|
||||
|
||||
private async Task PolicyPreselectedProfileWasChangedAsync(ProfilePreselection selection)
|
||||
private void PolicyPreselectedProfileWasChanged(ProfilePreselection selection)
|
||||
{
|
||||
this.policyPreselectedProfile = selection;
|
||||
if (this.selectedPolicy is not null)
|
||||
{
|
||||
this.selectedPolicy.PreselectedProfile = this.policyPreselectedProfile;
|
||||
this.policyStorePending = true;
|
||||
}
|
||||
|
||||
this.CurrentProfile = this.ResolveProfileSelection();
|
||||
await this.AutoSave();
|
||||
}
|
||||
|
||||
#region Overrides of MSGComponentBase
|
||||
|
||||
@@ -4216,6 +4216,12 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::PROFILESELECTION::T3654011106"] = "Open P
|
||||
-- You can switch between your profiles here
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::PROFILESELECTION::T918741365"] = "You can switch between your profiles here"
|
||||
|
||||
-- No LLM providers are configured yet. Add a provider in the app settings.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::PROVIDERSELECTION::T1166628228"] = "No LLM providers are configured yet. Add a provider in the app settings."
|
||||
|
||||
-- No LLM providers meet the confidence requirements. Configure an eligible provider in the app settings.
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::PROVIDERSELECTION::T1220991024"] = "No LLM providers meet the confidence requirements. Configure an eligible provider in the app settings."
|
||||
|
||||
-- Audio input possible
|
||||
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::PROVIDERSELECTION::T1742581112"] = "Audio input possible"
|
||||
|
||||
|
||||
Reference in new issue
Block a user