From 839068ff34556038d2eb0cb16dbfd175ee744ea2 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 18 Jan 2026 12:09:25 +0100 Subject: [PATCH] Fixed a bug that allowed adding a provider without selecting a model --- .../Assistants/I18N/allTexts.lua | 3 --- .../Dialogs/EmbeddingProviderDialog.razor.cs | 12 +++++++++- .../Dialogs/ProviderDialog.razor.cs | 12 +++++++++- .../Dialogs/TranscriptionProviderDialog.razor | 2 +- .../TranscriptionProviderDialog.razor.cs | 24 ++----------------- .../Tools/Validation/ProviderValidation.cs | 20 ++++++++++++---- .../wwwroot/changelog/v26.1.2.md | 3 ++- 7 files changed, 43 insertions(+), 33 deletions(-) diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua index 3ec67fab..1ec8c022 100644 --- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua +++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua @@ -4636,9 +4636,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T3703662664"] = -- 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 UI_TEXT_CONTENT["AISTUDIO::DIALOGS::TRANSCRIPTIONPROVIDERDIALOG::T808120719"] = "Host" diff --git a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs index 8a0180c5..0e5df9b9 100644 --- a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs @@ -102,6 +102,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName, GetUsedInstanceNames = () => this.UsedInstanceNames, GetHost = () => this.DataHost, + IsModelProvidedManually = () => this.DataLLMProvider is LLMProviders.SELF_HOSTED && this.DataHost is Host.OLLAMA, }; } @@ -208,7 +209,16 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId { await this.form.Validate(); 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: if (!this.dataIsValid) return; diff --git a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs index f00a43d5..e4f1f27a 100644 --- a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs @@ -115,6 +115,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName, GetUsedInstanceNames = () => this.UsedInstanceNames, GetHost = () => this.DataHost, + IsModelProvidedManually = () => this.DataLLMProvider.IsLLMModelProvidedManually(), }; } @@ -222,7 +223,16 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId await this.form.Validate(); if (!string.IsNullOrWhiteSpace(this.dataAPIKeyStorageIssue)) 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: if (!this.dataIsValid) return; diff --git a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor index 8fdb5616..0a2aa3bb 100644 --- a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor +++ b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor @@ -90,7 +90,7 @@ + Validation="@this.providerValidation.ValidatingModel"> @foreach (var model in this.availableModels) { diff --git a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs index 964138bf..83477dec 100644 --- a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs @@ -102,6 +102,7 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId GetPreviousInstanceName = () => this.dataEditingPreviousInstanceName, GetUsedInstanceNames = () => this.UsedInstanceNames, 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 // and the MudSelect is not rendered): - var modelValidationError = this.ValidateSelectedModel(this.DataModel); + var modelValidationError = this.providerValidation.ValidatingModel(this.DataModel); if (!string.IsNullOrWhiteSpace(modelValidationError)) { this.dataIssues = [..this.dataIssues, modelValidationError]; @@ -256,27 +257,6 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId 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 async Task OnAPIKeyChanged(string apiKey) diff --git a/app/MindWork AI Studio/Tools/Validation/ProviderValidation.cs b/app/MindWork AI Studio/Tools/Validation/ProviderValidation.cs index 3b074ba9..bb72feb4 100644 --- a/app/MindWork AI Studio/Tools/Validation/ProviderValidation.cs +++ b/app/MindWork AI Studio/Tools/Validation/ProviderValidation.cs @@ -19,7 +19,9 @@ public sealed class ProviderValidation public Func> GetUsedInstanceNames { get; init; } = () => []; public Func GetHost { get; init; } = () => Host.NONE; - + + public Func IsModelProvidedManually { get; init; } = () => false; + public string? ValidatingHostname(string hostname) { if(this.GetProvider() != LLMProviders.SELF_HOSTED) @@ -70,12 +72,22 @@ public sealed class ProviderValidation 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; + if (model == default) return TB("Please select a model."); - + return null; } diff --git a/app/MindWork AI Studio/wwwroot/changelog/v26.1.2.md b/app/MindWork AI Studio/wwwroot/changelog/v26.1.2.md index a861ccb0..8c6cbafd 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v26.1.2.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v26.1.2.md @@ -1,3 +1,4 @@ # 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. -- Fixed a logging bug that prevented log events from being recorded in some cases. \ No newline at end of file +- 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. \ No newline at end of file