Fixed a bug that allowed adding a provider without selecting a model

This commit is contained in:
Thorsten Sommer 2026-01-18 12:09:25 +01:00
parent 3eb3515634
commit 839068ff34
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
7 changed files with 43 additions and 33 deletions

View File

@ -4636,9 +4636,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T3703662664"] =
-- Model selection -- Model selection
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T416738168"] = "Model selection" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T416738168"] = "Model selection"
-- Please select a transcription model.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T794751523"] = "Please select a transcription model."
-- Host -- Host
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T808120719"] = "Host" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T808120719"] = "Host"

View File

@ -102,6 +102,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName, GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName,
GetUsedInstanceNames = () => this.UsedInstanceNames, GetUsedInstanceNames = () => this.UsedInstanceNames,
GetHost = () => this.DataHost, GetHost = () => this.DataHost,
IsModelProvidedManually = () => this.DataLLMProvider is LLMProviders.SELF_HOSTED && this.DataHost is Host.OLLAMA,
}; };
} }
@ -209,6 +210,15 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
await this.form.Validate(); await this.form.Validate();
this.dataAPIKeyStorageIssue = string.Empty; this.dataAPIKeyStorageIssue = string.Empty;
// Manually validate the model selection (needed when no models are loaded
// and the MudSelect is not rendered):
var modelValidationError = this.providerValidation.ValidatingModel(this.DataModel);
if (!string.IsNullOrWhiteSpace(modelValidationError))
{
this.dataIssues = [..this.dataIssues, modelValidationError];
this.dataIsValid = false;
}
// When the data is not valid, we don't store it: // When the data is not valid, we don't store it:
if (!this.dataIsValid) if (!this.dataIsValid)
return; return;

View File

@ -115,6 +115,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName, GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName,
GetUsedInstanceNames = () => this.UsedInstanceNames, GetUsedInstanceNames = () => this.UsedInstanceNames,
GetHost = () => this.DataHost, GetHost = () => this.DataHost,
IsModelProvidedManually = () => this.DataLLMProvider.IsLLMModelProvidedManually(),
}; };
} }
@ -223,6 +224,15 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId
if (!string.IsNullOrWhiteSpace(this.dataAPIKeyStorageIssue)) if (!string.IsNullOrWhiteSpace(this.dataAPIKeyStorageIssue))
this.dataAPIKeyStorageIssue = string.Empty; this.dataAPIKeyStorageIssue = string.Empty;
// Manually validate the model selection (needed when no models are loaded
// and the MudSelect is not rendered):
var modelValidationError = this.providerValidation.ValidatingModel(this.DataModel);
if (!string.IsNullOrWhiteSpace(modelValidationError))
{
this.dataIssues = [..this.dataIssues, modelValidationError];
this.dataIsValid = false;
}
// When the data is not valid, we don't store it: // When the data is not valid, we don't store it:
if (!this.dataIsValid) if (!this.dataIsValid)
return; return;

View File

@ -90,7 +90,7 @@
<MudSelect Disabled="@this.IsNoneProvider" @bind-Value="@this.DataModel" Label="@T("Model")" <MudSelect Disabled="@this.IsNoneProvider" @bind-Value="@this.DataModel" Label="@T("Model")"
OpenIcon="@Icons.Material.Filled.FaceRetouchingNatural" OpenIcon="@Icons.Material.Filled.FaceRetouchingNatural"
AdornmentColor="Color.Info" Adornment="Adornment.Start" AdornmentColor="Color.Info" Adornment="Adornment.Start"
Validation="@this.ValidateSelectedModel"> Validation="@this.providerValidation.ValidatingModel">
@foreach (var model in this.availableModels) @foreach (var model in this.availableModels)
{ {
<MudSelectItem Value="@model"> <MudSelectItem Value="@model">

View File

@ -102,6 +102,7 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId
GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName, GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName,
GetUsedInstanceNames = () => this.UsedInstanceNames, GetUsedInstanceNames = () => this.UsedInstanceNames,
GetHost = () => this.DataHost, GetHost = () => this.DataHost,
IsModelProvidedManually = () => this.DataLLMProvider.IsTranscriptionModelProvidedManually(this.DataHost),
}; };
} }
@ -219,7 +220,7 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId
// Manually validate the model selection (needed when no models are loaded // Manually validate the model selection (needed when no models are loaded
// and the MudSelect is not rendered): // and the MudSelect is not rendered):
var modelValidationError = this.ValidateSelectedModel(this.DataModel); var modelValidationError = this.providerValidation.ValidatingModel(this.DataModel);
if (!string.IsNullOrWhiteSpace(modelValidationError)) if (!string.IsNullOrWhiteSpace(modelValidationError))
{ {
this.dataIssues = [..this.dataIssues, modelValidationError]; this.dataIssues = [..this.dataIssues, modelValidationError];
@ -256,27 +257,6 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId
return null; return null;
} }
private string? ValidateSelectedModel(Model model)
{
// Exception for self-hosted whisper.cpp - no model selection needed:
if (this.DataLLMProvider is LLMProviders.SELF_HOSTED && this.DataHost is Host.WHISPER_CPP)
return null;
// For manually entered models, this validation doesn't apply:
if (this.DataLLMProvider.IsTranscriptionModelProvidedManually(this.DataHost))
return null;
// For NONE providers, no validation is needed yet:
if (this.DataLLMProvider is LLMProviders.NONE)
return null;
// Check if a model is selected:
if (model == default)
return T("Please select a transcription model.");
return null;
}
private void Cancel() => this.MudDialog.Cancel(); private void Cancel() => this.MudDialog.Cancel();
private async Task OnAPIKeyChanged(string apiKey) private async Task OnAPIKeyChanged(string apiKey)

View File

@ -20,6 +20,8 @@ public sealed class ProviderValidation
public Func<Host> GetHost { get; init; } = () => Host.NONE; public Func<Host> GetHost { get; init; } = () => Host.NONE;
public Func<bool> IsModelProvidedManually { get; init; } = () => false;
public string? ValidatingHostname(string hostname) public string? ValidatingHostname(string hostname)
{ {
if(this.GetProvider() != LLMProviders.SELF_HOSTED) if(this.GetProvider() != LLMProviders.SELF_HOSTED)
@ -70,7 +72,17 @@ public sealed class ProviderValidation
public string? ValidatingModel(Model model) public string? ValidatingModel(Model model)
{ {
if(this.GetProvider() is LLMProviders.SELF_HOSTED && this.GetHost() == Host.LLAMA_CPP) // For NONE providers, no validation is needed:
if (this.GetProvider() is LLMProviders.NONE)
return null;
// For self-hosted llama.cpp or whisper.cpp, no model selection needed
// (model is loaded at startup):
if (this.GetProvider() is LLMProviders.SELF_HOSTED && this.GetHost() is Host.LLAMA_CPP or Host.WHISPER_CPP)
return null;
// For manually entered models, this validation doesn't apply:
if (this.IsModelProvidedManually())
return null; return null;
if (model == default) if (model == default)

View File

@ -1,3 +1,4 @@
# v26.1.2, build 232 (2026-01-xx xx:xx UTC) # v26.1.2, build 232 (2026-01-xx xx:xx UTC)
- Added the option to hide specific assistants by configuration plugins. This is useful for enterprise environments in organizations. - Added the option to hide specific assistants by configuration plugins. This is useful for enterprise environments in organizations.
- Fixed a logging bug that prevented log events from being recorded in some cases. - Fixed a logging bug that prevented log events from being recorded in some cases.
- Fixed a bug that allowed adding a provider without selecting a model.