Code Review and bug fixes

This commit is contained in:
Peer Hogeterp committed 2026-09-10 14:29:35 +02:00
1 parent cefc5464d5
commit a6e9066747
18 files changed
+443 -186

No files matched your search

@@ -267,7 +267,7 @@ public partial class ChatComponent : MSGComponentBase
await this.SyncWorkspaceHeaderWithChatThreadAsync();
// Select the correct provider:
await this.SelectProviderWhenLoadingChat();
await this.SelectProviderWhenLoadingChat(useChatProfileSelection: deferredRequest is not null);
await this.SyncForegroundChatAsync();
await this.ConsumeMediaOutcomeAsync();
await base.OnInitializedAsync();
@@ -637,7 +637,9 @@ public partial class ChatComponent : MSGComponentBase
}
else
{
this.currentProfileIds = this.SettingsManager.ResolveProfiles(this.ChatThread.SelectedProfileIds).Select(profile => profile.Id).ToHashSet(StringComparer.OrdinalIgnoreCase);
this.currentProfileIds = this.IsCurrentChatStreaming
? this.SettingsManager.ResolveProfiles(this.ChatThread.SelectedProfileIds).Select(profile => profile.Id).ToHashSet(StringComparer.OrdinalIgnoreCase)
: this.SettingsManager.ResolveProfiles(this.currentProfileIds).Select(profile => profile.Id).ToHashSet(StringComparer.OrdinalIgnoreCase);
this.currentChatTemplate = string.IsNullOrWhiteSpace(this.ChatThread.SelectedChatTemplate)
? this.SettingsManager.GetChatTemplateById(this.currentChatTemplate.Id)
@@ -1024,6 +1026,7 @@ public partial class ChatComponent : MSGComponentBase
this.hasUnsavedChanges = false;
this.ComposerState.Clear();
this.selectedToolIds = ToolSelectionRules.NormalizeSelection(this.SettingsManager.GetDefaultToolIds(Tools.Components.CHAT));
this.currentProfileIds = this.SettingsManager.GetPreselectedProfiles(Tools.Components.CHAT).Select(profile => profile.Id).ToHashSet(StringComparer.OrdinalIgnoreCase);
this.RefreshCurrentProfileAndChatTemplate();
//
@@ -1188,6 +1191,7 @@ public partial class ChatComponent : MSGComponentBase
this.hasUnsavedChanges = false;
this.ComposerState.Clear();
this.ClearWorkspaceHeaderState();
this.currentProfileIds = this.SettingsManager.GetPreselectedProfiles(Tools.Components.CHAT).Select(profile => profile.Id).ToHashSet(StringComparer.OrdinalIgnoreCase);
this.ChatThread = null;
this.MarkCurrentChatAsLoadedParameter();
@@ -1196,7 +1200,7 @@ public partial class ChatComponent : MSGComponentBase
await this.ChatThreadChanged.InvokeAsync(this.ChatThread);
}
private async Task SelectProviderWhenLoadingChat()
private async Task SelectProviderWhenLoadingChat(bool useChatProfileSelection = false)
{
var chatProvider = this.ChatThread?.SelectedProvider;
var chatProfileIds = this.ChatThread?.SelectedProfileIds;
@@ -1206,9 +1210,12 @@ public partial class ChatComponent : MSGComponentBase
await this.ProviderChanged.InvokeAsync(this.Provider);
// Try to select the profile:
if (chatProfileIds is not null)
// A running chat or an explicitly configured chat launcher keeps its selection. Opening an
// inactive chat starts a new UI session and therefore reapplies the configured defaults.
if ((useChatProfileSelection || this.IsCurrentChatStreaming) && chatProfileIds is not null)
this.currentProfileIds = this.SettingsManager.ResolveProfiles(chatProfileIds).Select(profile => profile.Id).ToHashSet(StringComparer.OrdinalIgnoreCase);
else
this.currentProfileIds = this.SettingsManager.GetPreselectedProfiles(Tools.Components.CHAT).Select(profile => profile.Id).ToHashSet(StringComparer.OrdinalIgnoreCase);
// Try to select the chat template:
if (!string.IsNullOrWhiteSpace(chatChatTemplate))
@@ -28,7 +28,7 @@
</MudSelect>
@if (this.SelectedProfileMode is ProfilePreselectionMode.USE_SPECIFIC_PROFILES)
{
<MudSelect T="string" MultiSelection="true" SelectedValues="@(this.ProfileIds ?? [])" SelectedValuesChanged="@this.SetProfileIds" MultiSelectionTextFunc="@this.GetSelectedProfileText" Label="@T("Profiles")" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3 rounded-lg" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Person">
<MudSelect T="string" MultiSelection="true" SelectedValues="@(this.ProfileIds ?? [])" SelectedValuesChanged="@this.SetProfileIds" MultiSelectionTextFunc="@this.GetSelectedProfileText" Validation="@this.ValidateProfileIds" Label="@T("Profiles")" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3 rounded-lg" Adornment="Adornment.Start" AdornmentIcon="@Icons.Material.Filled.Person">
@foreach (var profile in this.SettingsManager.ConfigurationData.Profiles)
{
<MudSelectItem T="string" Value="@profile.Id">@profile.GetSafeName()</MudSelectItem>
@@ -133,9 +133,9 @@ public partial class DirectChatLauncherForm : MSGComponentBase
this.profileModeOverride = mode;
HashSet<string>? profileIds = mode switch
{
ProfilePreselectionMode.USE_APP_DEFAULT => null,
ProfilePreselectionMode.USE_NO_PROFILES => [],
ProfilePreselectionMode.USE_SPECIFIC_PROFILES => this.ProfileIds is { Count: > 0 } ? [..this.ProfileIds] : [],
ProfilePreselectionMode.USE_APP_DEFAULT => ProfilePreselection.AppDefault,
ProfilePreselectionMode.USE_NO_PROFILES => ProfilePreselection.NoProfiles,
ProfilePreselectionMode.USE_SPECIFIC_PROFILES => this.ProfileIds is { Count: > 0 } ? ProfilePreselection.Specific(this.ProfileIds) : ProfilePreselection.NoProfiles,
_ => null,
};
@@ -152,6 +152,15 @@ public partial class DirectChatLauncherForm : MSGComponentBase
await this.ProfileIdsChanged.InvokeAsync(selection);
}
//
// "Use a custom profile selection" with nothing picked yet is indistinguishable from "use no
// profiles" once persisted, so it must not be a savable end state:
//
private string? ValidateProfileIds(IEnumerable<string?>? profileIds) =>
this.SelectedProfileMode == ProfilePreselectionMode.USE_SPECIFIC_PROFILES && !(profileIds?.Any(profileId => !string.IsNullOrWhiteSpace(profileId)) ?? false)
? T("Select at least one profile, or choose a different option above.")
: null;
private async Task SetChatTemplateId(string chatTemplateId)
{
this.ChatTemplateId = chatTemplateId;
@@ -5,7 +5,7 @@
@if (this.SelectedMode is ProfilePreselectionMode.USE_SPECIFIC_PROFILES)
{
<ConfigurationMultiSelect TData="string" OptionDescription="@T("Profiles")" Disabled="@this.Disabled" IsLocked="@this.IsLocked" SelectedValues="@(() => this.SpecificProfileIds)" Data="@ConfigurationSelectDataFactory.GetProfilesData(this.SettingsManager.ConfigurationData.Profiles)" SelectionUpdateAsync="@this.ProfilesChanged" MultiSelectionTextFunc="@this.GetSelectionText">
<ConfigurationMultiSelect TData="string" OptionDescription="@T("Custom preselected profiles")" Disabled="@this.Disabled" IsLocked="@this.IsLocked" SelectedValues="@(() => this.SpecificProfileIds)" Data="@ConfigurationSelectDataFactory.GetProfilesData(this.SettingsManager.ConfigurationData.Profiles)" SelectionUpdateAsync="@this.ProfilesChanged" MultiSelectionTextFunc="@this.GetSelectionText">
<ItemTemplate Context="profileData">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
<MudIcon Icon="@this.ProfileIcon(profileData.Value)" Size="Size.Small" Style="color: var(--mud-palette-action-default);" />
@@ -36,11 +36,24 @@ public partial class ProfilePreselectionConfiguration : MSGComponentBase
private async Task ModeChanged(ProfilePreselectionMode mode)
{
this.selectedModeOverride = mode;
//
// Switching to "custom profile selection" with nothing picked yet has no value that could
// be persisted: it would serialize identically to "no profiles" and silently discard
// whatever was configured before. Only persist once the user actually picks a profile,
// through ProfilesChanged below; until then, only the visible mode changes.
//
if (mode == ProfilePreselectionMode.USE_SPECIFIC_PROFILES && this.SpecificProfileIds.Count == 0)
{
await this.InvokeAsync(this.StateHasChanged);
return;
}
HashSet<string>? selection = mode switch
{
ProfilePreselectionMode.USE_APP_DEFAULT => null,
ProfilePreselectionMode.USE_NO_PROFILES => [],
ProfilePreselectionMode.USE_SPECIFIC_PROFILES => this.SpecificProfileIds.Count > 0 ? [..this.SpecificProfileIds] : [],
ProfilePreselectionMode.USE_APP_DEFAULT => ProfilePreselection.AppDefault,
ProfilePreselectionMode.USE_NO_PROFILES => ProfilePreselection.NoProfiles,
ProfilePreselectionMode.USE_SPECIFIC_PROFILES => ProfilePreselection.Specific(this.SpecificProfileIds),
_ => null,
};