diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs index 06ce34ea..50ebeb13 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelEmbeddings.razor.cs @@ -100,13 +100,13 @@ public partial class SettingsPanelEmbeddings : SettingsPanelBase if (dialogResult is null || dialogResult.Canceled) return; - var deleteSecretResponse = await this.RustService.DeleteAPIKey(provider); + var deleteSecretResponse = await this.RustService.DeleteAPIKey(provider, SecretStoreType.EMBEDDING_PROVIDER); if(deleteSecretResponse.Success) { this.SettingsManager.ConfigurationData.EmbeddingProviders.Remove(provider); await this.SettingsManager.StoreSettings(); } - + await this.UpdateEmbeddingProviders(); await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED); } diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs index 0b68a736..035543dc 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs @@ -107,7 +107,7 @@ public partial class SettingsPanelProviders : SettingsPanelBase if (dialogResult is null || dialogResult.Canceled) return; - var deleteSecretResponse = await this.RustService.DeleteAPIKey(provider); + var deleteSecretResponse = await this.RustService.DeleteAPIKey(provider, SecretStoreType.LLM_PROVIDER); if(deleteSecretResponse.Success) { this.SettingsManager.ConfigurationData.Providers.Remove(provider); diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor.cs index b9e699f7..d564d5cd 100644 --- a/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor.cs +++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelTranscription.razor.cs @@ -100,13 +100,13 @@ public partial class SettingsPanelTranscription : SettingsPanelBase if (dialogResult is null || dialogResult.Canceled) return; - var deleteSecretResponse = await this.RustService.DeleteAPIKey(provider); + var deleteSecretResponse = await this.RustService.DeleteAPIKey(provider, SecretStoreType.TRANSCRIPTION_PROVIDER); if(deleteSecretResponse.Success) { this.SettingsManager.ConfigurationData.TranscriptionProviders.Remove(provider); await this.SettingsManager.StoreSettings(); } - + await this.UpdateTranscriptionProviders(); await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED); } diff --git a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs index abfa2f62..d486714d 100644 --- a/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/EmbeddingProviderDialog.razor.cs @@ -167,7 +167,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId } // Load the API key: - var requestedSecret = await this.RustService.GetAPIKey(this, isTrying: this.DataLLMProvider is LLMProviders.SELF_HOSTED); + var requestedSecret = await this.RustService.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER, isTrying: this.DataLLMProvider is LLMProviders.SELF_HOSTED); if (requestedSecret.Success) this.dataAPIKey = await requestedSecret.Secret.Decrypt(this.encryption); else @@ -219,7 +219,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId if (!string.IsNullOrWhiteSpace(this.dataAPIKey)) { // Store the API key in the OS secure storage: - var storeResponse = await this.RustService.SetAPIKey(this, this.dataAPIKey); + var storeResponse = await this.RustService.SetAPIKey(this, this.dataAPIKey, SecretStoreType.EMBEDDING_PROVIDER); if (!storeResponse.Success) { this.dataAPIKeyStorageIssue = string.Format(T("Failed to store the API key in the operating system. The message was: {0}. Please try again."), storeResponse.Issue); diff --git a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs index 3c52004e..c37f69f7 100644 --- a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs @@ -180,7 +180,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId } // Load the API key: - var requestedSecret = await this.RustService.GetAPIKey(this, isTrying: this.DataLLMProvider is LLMProviders.SELF_HOSTED); + var requestedSecret = await this.RustService.GetAPIKey(this, SecretStoreType.LLM_PROVIDER, isTrying: this.DataLLMProvider is LLMProviders.SELF_HOSTED); if (requestedSecret.Success) this.dataAPIKey = await requestedSecret.Secret.Decrypt(this.encryption); else @@ -233,7 +233,7 @@ public partial class ProviderDialog : MSGComponentBase, ISecretId if (!string.IsNullOrWhiteSpace(this.dataAPIKey)) { // Store the API key in the OS secure storage: - var storeResponse = await this.RustService.SetAPIKey(this, this.dataAPIKey); + var storeResponse = await this.RustService.SetAPIKey(this, this.dataAPIKey, SecretStoreType.LLM_PROVIDER); if (!storeResponse.Success) { this.dataAPIKeyStorageIssue = string.Format(T("Failed to store the API key in the operating system. The message was: {0}. Please try again."), storeResponse.Issue); diff --git a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs index bcc6091d..440ec691 100644 --- a/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/TranscriptionProviderDialog.razor.cs @@ -175,7 +175,7 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId } // Load the API key: - var requestedSecret = await this.RustService.GetAPIKey(this, isTrying: this.DataLLMProvider is LLMProviders.SELF_HOSTED); + var requestedSecret = await this.RustService.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER, isTrying: this.DataLLMProvider is LLMProviders.SELF_HOSTED); if (requestedSecret.Success) this.dataAPIKey = await requestedSecret.Secret.Decrypt(this.encryption); else @@ -227,7 +227,7 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId if (!string.IsNullOrWhiteSpace(this.dataAPIKey)) { // Store the API key in the OS secure storage: - var storeResponse = await this.RustService.SetAPIKey(this, this.dataAPIKey); + var storeResponse = await this.RustService.SetAPIKey(this, this.dataAPIKey, SecretStoreType.TRANSCRIPTION_PROVIDER); if (!storeResponse.Success) { this.dataAPIKeyStorageIssue = string.Format(T("Failed to store the API key in the operating system. The message was: {0}. Please try again."), storeResponse.Issue); diff --git a/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs b/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs index 9d2e0792..2c763678 100644 --- a/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs +++ b/app/MindWork AI Studio/Provider/AlibabaCloud/ProviderAlibabaCloud.cs @@ -25,7 +25,7 @@ public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_C public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -117,7 +117,7 @@ public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_C new Model("qwen2.5-vl-3b-instruct", "Qwen2.5-VL 3b"), }; - return this.LoadModels(["q"],token, apiKeyProvisional).ContinueWith(t => t.Result.Concat(additionalModels).OrderBy(x => x.Id).AsEnumerable(), token); + return this.LoadModels(["q"], SecretStoreType.LLM_PROVIDER, token, apiKeyProvisional).ContinueWith(t => t.Result.Concat(additionalModels).OrderBy(x => x.Id).AsEnumerable(), token); } /// @@ -135,7 +135,7 @@ public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_C new Model("text-embedding-v3", "text-embedding-v3"), }; - return this.LoadModels(["text-embedding-"], token, apiKeyProvisional).ContinueWith(t => t.Result.Concat(additionalModels).OrderBy(x => x.Id).AsEnumerable(), token); + return this.LoadModels(["text-embedding-"], SecretStoreType.EMBEDDING_PROVIDER, token, apiKeyProvisional).ContinueWith(t => t.Result.Concat(additionalModels).OrderBy(x => x.Id).AsEnumerable(), token); } #region Overrides of BaseProvider @@ -150,12 +150,12 @@ public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_C #endregion - private async Task> LoadModels(string[] prefixes, CancellationToken token, string? apiKeyProvisional = null) + private async Task> LoadModels(string[] prefixes, SecretStoreType storeType, CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs index 2b45cc44..539c4427 100644 --- a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs +++ b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs @@ -23,7 +23,7 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, " public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -127,7 +127,7 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, " new Model("claude-3-opus-latest", "Claude 3 Opus (Latest)"), }; - return this.LoadModels(token, apiKeyProvisional).ContinueWith(t => t.Result.Concat(additionalModels).OrderBy(x => x.Id).AsEnumerable(), token); + return this.LoadModels(SecretStoreType.LLM_PROVIDER, token, apiKeyProvisional).ContinueWith(t => t.Result.Concat(additionalModels).OrderBy(x => x.Id).AsEnumerable(), token); } /// @@ -150,12 +150,12 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, " #endregion - private async Task> LoadModels(CancellationToken token, string? apiKeyProvisional = null) + private async Task> LoadModels(SecretStoreType storeType, CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs b/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs index 39ecd21e..f5e1016d 100644 --- a/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs +++ b/app/MindWork AI Studio/Provider/DeepSeek/ProviderDeepSeek.cs @@ -25,7 +25,7 @@ public sealed class ProviderDeepSeek() : BaseProvider(LLMProviders.DEEP_SEEK, "h public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -90,7 +90,7 @@ public sealed class ProviderDeepSeek() : BaseProvider(LLMProviders.DEEP_SEEK, "h /// public override Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) { - return this.LoadModels(token, apiKeyProvisional); + return this.LoadModels(SecretStoreType.LLM_PROVIDER, token, apiKeyProvisional); } /// @@ -113,12 +113,12 @@ public sealed class ProviderDeepSeek() : BaseProvider(LLMProviders.DEEP_SEEK, "h #endregion - private async Task> LoadModels(CancellationToken token, string? apiKeyProvisional = null) + private async Task> LoadModels(SecretStoreType storeType, CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs index 482e837e..25fc2611 100644 --- a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs +++ b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs @@ -25,7 +25,7 @@ public class ProviderFireworks() : BaseProvider(LLMProviders.FIREWORKS, "https:/ public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -85,7 +85,7 @@ public class ProviderFireworks() : BaseProvider(LLMProviders.FIREWORKS, "https:/ /// public override async Task TranscribeAudioAsync(Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default) { - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER); return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token); } diff --git a/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs b/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs index 16e8b646..28af268f 100644 --- a/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs +++ b/app/MindWork AI Studio/Provider/GWDG/ProviderGWDG.cs @@ -25,7 +25,7 @@ public sealed class ProviderGWDG() : BaseProvider(LLMProviders.GWDG, "https://ch public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -84,14 +84,14 @@ public sealed class ProviderGWDG() : BaseProvider(LLMProviders.GWDG, "https://ch /// public override async Task TranscribeAudioAsync(Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default) { - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER); return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token); } /// public override async Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) { - var models = await this.LoadModels(token, apiKeyProvisional); + var models = await this.LoadModels(SecretStoreType.LLM_PROVIDER, token, apiKeyProvisional); return models.Where(model => !model.Id.StartsWith("e5-mistral-7b-instruct", StringComparison.InvariantCultureIgnoreCase)); } @@ -104,7 +104,7 @@ public sealed class ProviderGWDG() : BaseProvider(LLMProviders.GWDG, "https://ch /// public override async Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) { - var models = await this.LoadModels(token, apiKeyProvisional); + var models = await this.LoadModels(SecretStoreType.EMBEDDING_PROVIDER, token, apiKeyProvisional); return models.Where(model => model.Id.StartsWith("e5-", StringComparison.InvariantCultureIgnoreCase)); } @@ -121,12 +121,12 @@ public sealed class ProviderGWDG() : BaseProvider(LLMProviders.GWDG, "https://ch #endregion - private async Task> LoadModels(CancellationToken token, string? apiKeyProvisional = null) + private async Task> LoadModels(SecretStoreType storeType, CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs b/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs index 176bbeb5..55490992 100644 --- a/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs +++ b/app/MindWork AI Studio/Provider/Google/ProviderGoogle.cs @@ -25,7 +25,7 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, "https://gener public override async IAsyncEnumerable StreamChatCompletion(Provider.Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -91,7 +91,7 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, "https://gener /// public override async Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) { - var modelResponse = await this.LoadModels(token, apiKeyProvisional); + var modelResponse = await this.LoadModels(SecretStoreType.LLM_PROVIDER, token, apiKeyProvisional); if(modelResponse == default) return []; @@ -108,7 +108,7 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, "https://gener public override async Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) { - var modelResponse = await this.LoadModels(token, apiKeyProvisional); + var modelResponse = await this.LoadModels(SecretStoreType.EMBEDDING_PROVIDER, token, apiKeyProvisional); if(modelResponse == default) return []; @@ -126,12 +126,12 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, "https://gener #endregion - private async Task LoadModels(CancellationToken token, string? apiKeyProvisional = null) + private async Task LoadModels(SecretStoreType storeType, CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs b/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs index 0bbc616f..e66cec3e 100644 --- a/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs +++ b/app/MindWork AI Studio/Provider/Groq/ProviderGroq.cs @@ -25,7 +25,7 @@ public class ProviderGroq() : BaseProvider(LLMProviders.GROQ, "https://api.groq. public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -91,13 +91,13 @@ public class ProviderGroq() : BaseProvider(LLMProviders.GROQ, "https://api.groq. /// public override Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) { - return this.LoadModels(token, apiKeyProvisional); + return this.LoadModels(SecretStoreType.LLM_PROVIDER, token, apiKeyProvisional); } /// public override Task> GetImageModels(string? apiKeyProvisional = null, CancellationToken token = default) { - return Task.FromResult>(Array.Empty()); + return Task.FromResult>([]); } /// @@ -114,12 +114,12 @@ public class ProviderGroq() : BaseProvider(LLMProviders.GROQ, "https://api.groq. #endregion - private async Task> LoadModels(CancellationToken token, string? apiKeyProvisional = null) + private async Task> LoadModels(SecretStoreType storeType, CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs b/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs index cc52cd20..cf4359ea 100644 --- a/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs +++ b/app/MindWork AI Studio/Provider/Helmholtz/ProviderHelmholtz.cs @@ -25,7 +25,7 @@ public sealed class ProviderHelmholtz() : BaseProvider(LLMProviders.HELMHOLTZ, " public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -90,7 +90,7 @@ public sealed class ProviderHelmholtz() : BaseProvider(LLMProviders.HELMHOLTZ, " /// public override async Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) { - var models = await this.LoadModels(token, apiKeyProvisional); + var models = await this.LoadModels(SecretStoreType.LLM_PROVIDER, token, apiKeyProvisional); return models.Where(model => !model.Id.StartsWith("text-", StringComparison.InvariantCultureIgnoreCase) && !model.Id.StartsWith("alias-embedding", StringComparison.InvariantCultureIgnoreCase)); } @@ -104,7 +104,7 @@ public sealed class ProviderHelmholtz() : BaseProvider(LLMProviders.HELMHOLTZ, " /// public override async Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) { - var models = await this.LoadModels(token, apiKeyProvisional); + var models = await this.LoadModels(SecretStoreType.EMBEDDING_PROVIDER, token, apiKeyProvisional); return models.Where(model => model.Id.StartsWith("alias-embedding", StringComparison.InvariantCultureIgnoreCase) || model.Id.StartsWith("text-", StringComparison.InvariantCultureIgnoreCase) || @@ -119,12 +119,12 @@ public sealed class ProviderHelmholtz() : BaseProvider(LLMProviders.HELMHOLTZ, " #endregion - private async Task> LoadModels(CancellationToken token, string? apiKeyProvisional = null) + private async Task> LoadModels(SecretStoreType storeType, CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs b/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs index a9778988..685dea10 100644 --- a/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs +++ b/app/MindWork AI Studio/Provider/HuggingFace/ProviderHuggingFace.cs @@ -30,7 +30,7 @@ public sealed class ProviderHuggingFace : BaseProvider public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; diff --git a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs index f560571f..0755f349 100644 --- a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs +++ b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs @@ -23,7 +23,7 @@ public sealed class ProviderMistral() : BaseProvider(LLMProviders.MISTRAL, "http public override async IAsyncEnumerable StreamChatCompletion(Provider.Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -85,14 +85,14 @@ public sealed class ProviderMistral() : BaseProvider(LLMProviders.MISTRAL, "http /// public override async Task TranscribeAudioAsync(Provider.Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default) { - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER); return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token); } /// public override async Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) { - var modelResponse = await this.LoadModelList(apiKeyProvisional, token); + var modelResponse = await this.LoadModelList(SecretStoreType.LLM_PROVIDER, apiKeyProvisional, token); if(modelResponse == default) return []; @@ -106,7 +106,7 @@ public sealed class ProviderMistral() : BaseProvider(LLMProviders.MISTRAL, "http /// public override async Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) { - var modelResponse = await this.LoadModelList(apiKeyProvisional, token); + var modelResponse = await this.LoadModelList(SecretStoreType.EMBEDDING_PROVIDER, apiKeyProvisional, token); if(modelResponse == default) return []; @@ -133,12 +133,12 @@ public sealed class ProviderMistral() : BaseProvider(LLMProviders.MISTRAL, "http #endregion - private async Task LoadModelList(string? apiKeyProvisional, CancellationToken token) + private async Task LoadModelList(SecretStoreType storeType, string? apiKeyProvisional, CancellationToken token) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs index f36a2f6c..c4a213db 100644 --- a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs +++ b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs @@ -27,7 +27,7 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, "https public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -221,14 +221,14 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, "https /// public override async Task TranscribeAudioAsync(Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default) { - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER); return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token); } /// public override async Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) { - var models = await this.LoadModels(["chatgpt-", "gpt-", "o1-", "o3-", "o4-"], token, apiKeyProvisional); + var models = await this.LoadModels(SecretStoreType.LLM_PROVIDER, ["chatgpt-", "gpt-", "o1-", "o3-", "o4-"], token, apiKeyProvisional); return models.Where(model => !model.Id.Contains("image", StringComparison.OrdinalIgnoreCase) && !model.Id.Contains("realtime", StringComparison.OrdinalIgnoreCase) && !model.Id.Contains("audio", StringComparison.OrdinalIgnoreCase) && @@ -239,31 +239,31 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, "https /// public override Task> GetImageModels(string? apiKeyProvisional = null, CancellationToken token = default) { - return this.LoadModels(["dall-e-", "gpt-image"], token, apiKeyProvisional); + return this.LoadModels(SecretStoreType.IMAGE_PROVIDER, ["dall-e-", "gpt-image"], token, apiKeyProvisional); } /// public override Task> GetEmbeddingModels(string? apiKeyProvisional = null, CancellationToken token = default) { - return this.LoadModels(["text-embedding-"], token, apiKeyProvisional); + return this.LoadModels(SecretStoreType.EMBEDDING_PROVIDER, ["text-embedding-"], token, apiKeyProvisional); } /// public override async Task> GetTranscriptionModels(string? apiKeyProvisional = null, CancellationToken token = default) { - var models = await this.LoadModels(["whisper-", "gpt-"], token, apiKeyProvisional); + var models = await this.LoadModels(SecretStoreType.TRANSCRIPTION_PROVIDER, ["whisper-", "gpt-"], token, apiKeyProvisional); return models.Where(model => model.Id.StartsWith("whisper-", StringComparison.InvariantCultureIgnoreCase) || model.Id.Contains("-transcribe", StringComparison.InvariantCultureIgnoreCase)); } #endregion - private async Task> LoadModels(string[] prefixes, CancellationToken token, string? apiKeyProvisional = null) + private async Task> LoadModels(SecretStoreType storeType, string[] prefixes, CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Provider/OpenRouter/ProviderOpenRouter.cs b/app/MindWork AI Studio/Provider/OpenRouter/ProviderOpenRouter.cs index 79d02de6..e627ee4c 100644 --- a/app/MindWork AI Studio/Provider/OpenRouter/ProviderOpenRouter.cs +++ b/app/MindWork AI Studio/Provider/OpenRouter/ProviderOpenRouter.cs @@ -28,7 +28,7 @@ public sealed class ProviderOpenRouter() : BaseProvider(LLMProviders.OPEN_ROUTER public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -98,7 +98,7 @@ public sealed class ProviderOpenRouter() : BaseProvider(LLMProviders.OPEN_ROUTER /// public override Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) { - return this.LoadModels(token, apiKeyProvisional); + return this.LoadModels(SecretStoreType.LLM_PROVIDER, token, apiKeyProvisional); } /// @@ -121,12 +121,12 @@ public sealed class ProviderOpenRouter() : BaseProvider(LLMProviders.OPEN_ROUTER #endregion - private async Task> LoadModels(CancellationToken token, string? apiKeyProvisional = null) + private async Task> LoadModels(SecretStoreType storeType, CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, @@ -168,7 +168,7 @@ public sealed class ProviderOpenRouter() : BaseProvider(LLMProviders.OPEN_ROUTER var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs b/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs index 38c6f9b7..6ecfc69f 100644 --- a/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs +++ b/app/MindWork AI Studio/Provider/Perplexity/ProviderPerplexity.cs @@ -34,7 +34,7 @@ public sealed class ProviderPerplexity() : BaseProvider(LLMProviders.PERPLEXITY, public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; diff --git a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs index 8b472c09..d63ec0d1 100644 --- a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs +++ b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs @@ -26,7 +26,7 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide public override async IAsyncEnumerable StreamChatCompletion(Provider.Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this, isTrying: true); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER, isTrying: true); // Prepare the system prompt: var systemPrompt = new TextMessage @@ -91,7 +91,7 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide /// public override async Task TranscribeAudioAsync(Provider.Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default) { - var requestedSecret = await RUST_SERVICE.GetAPIKey(this, isTrying: true); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER, isTrying: true); return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, host, token); } @@ -109,7 +109,7 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide case Host.LM_STUDIO: case Host.OLLAMA: case Host.VLLM: - return await this.LoadModels(["embed"], [], token, apiKeyProvisional); + return await this.LoadModels( SecretStoreType.LLM_PROVIDER, ["embed"], [], token, apiKeyProvisional); } return []; @@ -136,7 +136,7 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide case Host.LM_STUDIO: case Host.OLLAMA: case Host.VLLM: - return await this.LoadModels([], ["embed"], token, apiKeyProvisional); + return await this.LoadModels( SecretStoreType.EMBEDDING_PROVIDER, [], ["embed"], token, apiKeyProvisional); } return []; @@ -164,7 +164,7 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide case Host.OLLAMA: case Host.VLLM: - return this.LoadModels([], [], token, apiKeyProvisional); + return this.LoadModels(SecretStoreType.TRANSCRIPTION_PROVIDER, [], [], token, apiKeyProvisional); default: return Task.FromResult(Enumerable.Empty()); @@ -179,12 +179,12 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide #endregion - private async Task> LoadModels(string[] ignorePhrases, string[] filterPhrases, CancellationToken token, string? apiKeyProvisional = null) + private async Task> LoadModels(SecretStoreType storeType, string[] ignorePhrases, string[] filterPhrases, CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this, isTrying: true) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType, isTrying: true) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Provider/X/ProviderX.cs b/app/MindWork AI Studio/Provider/X/ProviderX.cs index 373a3b58..82d92c2a 100644 --- a/app/MindWork AI Studio/Provider/X/ProviderX.cs +++ b/app/MindWork AI Studio/Provider/X/ProviderX.cs @@ -25,7 +25,7 @@ public sealed class ProviderX() : BaseProvider(LLMProviders.X, "https://api.x.ai public override async IAsyncEnumerable StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default) { // Get the API key: - var requestedSecret = await RUST_SERVICE.GetAPIKey(this); + var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER); if(!requestedSecret.Success) yield break; @@ -91,7 +91,7 @@ public sealed class ProviderX() : BaseProvider(LLMProviders.X, "https://api.x.ai /// public override async Task> GetTextModels(string? apiKeyProvisional = null, CancellationToken token = default) { - var models = await this.LoadModels(["grok-"], token, apiKeyProvisional); + var models = await this.LoadModels(SecretStoreType.LLM_PROVIDER, ["grok-"], token, apiKeyProvisional); return models.Where(n => !n.Id.Contains("-image", StringComparison.OrdinalIgnoreCase)); } @@ -115,12 +115,12 @@ public sealed class ProviderX() : BaseProvider(LLMProviders.X, "https://api.x.ai #endregion - private async Task> LoadModels(string[] prefixes, CancellationToken token, string? apiKeyProvisional = null) + private async Task> LoadModels(SecretStoreType storeType, string[] prefixes, CancellationToken token, string? apiKeyProvisional = null) { var secretKey = apiKeyProvisional switch { not null => apiKeyProvisional, - _ => await RUST_SERVICE.GetAPIKey(this) switch + _ => await RUST_SERVICE.GetAPIKey(this, storeType) switch { { Success: true } result => await result.Secret.Decrypt(ENCRYPTION), _ => null, diff --git a/app/MindWork AI Studio/Tools/SecretStoreType.cs b/app/MindWork AI Studio/Tools/SecretStoreType.cs new file mode 100644 index 00000000..c4382b7b --- /dev/null +++ b/app/MindWork AI Studio/Tools/SecretStoreType.cs @@ -0,0 +1,32 @@ +namespace AIStudio.Tools; + +/// +/// Represents the type of secret store used for API keys. +/// +/// +/// Different provider types use different prefixes for storing API keys. +/// This prevents collisions when the same instance name is used across +/// different provider types (e.g., LLM, Embedding, Transcription). +/// +public enum SecretStoreType +{ + /// + /// LLM provider secrets. Uses the legacy "provider::" prefix for backward compatibility. + /// + LLM_PROVIDER = 0, + + /// + /// Embedding provider secrets. Uses the "embedding::" prefix. + /// + EMBEDDING_PROVIDER, + + /// + /// Transcription provider secrets. Uses the "transcription::" prefix. + /// + TRANSCRIPTION_PROVIDER, + + /// + /// Image provider secrets. Uses the "image::" prefix. + /// + IMAGE_PROVIDER, +} diff --git a/app/MindWork AI Studio/Tools/SecretStoreTypeExtensions.cs b/app/MindWork AI Studio/Tools/SecretStoreTypeExtensions.cs new file mode 100644 index 00000000..d0d4ba9e --- /dev/null +++ b/app/MindWork AI Studio/Tools/SecretStoreTypeExtensions.cs @@ -0,0 +1,21 @@ +namespace AIStudio.Tools; + +public static class SecretStoreTypeExtensions +{ + /// + /// Gets the prefix string associated with the SecretStoreType. + /// + /// + /// LLM_PROVIDER uses the legacy "provider" prefix for backward compatibility. + /// + /// The SecretStoreType enum value. + /// >The corresponding prefix string. + public static string Prefix(this SecretStoreType type) => type switch + { + SecretStoreType.LLM_PROVIDER => "provider", + SecretStoreType.EMBEDDING_PROVIDER => "embedding", + SecretStoreType.TRANSCRIPTION_PROVIDER => "transcription", + + _ => "provider", + }; +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/Services/RustService.APIKeys.cs b/app/MindWork AI Studio/Tools/Services/RustService.APIKeys.cs index 0578a55e..abc06b03 100644 --- a/app/MindWork AI Studio/Tools/Services/RustService.APIKeys.cs +++ b/app/MindWork AI Studio/Tools/Services/RustService.APIKeys.cs @@ -9,70 +9,76 @@ public sealed partial class RustService /// /// The secret ID to get the API key for. /// Indicates if we are trying to get the API key. In that case, we don't log errors. + /// The secret store type. Defaults to LLM_PROVIDER for backward compatibility. /// The requested secret. - public async Task GetAPIKey(ISecretId secretId, bool isTrying = false) + public async Task GetAPIKey(ISecretId secretId, SecretStoreType storeType, bool isTrying = false) { - var secretRequest = new SelectSecretRequest($"provider::{secretId.SecretId}::{secretId.SecretName}::api_key", Environment.UserName, isTrying); + var prefix = storeType.Prefix(); + var secretRequest = new SelectSecretRequest($"{prefix}::{secretId.SecretId}::{secretId.SecretName}::api_key", Environment.UserName, isTrying); var result = await this.http.PostAsJsonAsync("/secrets/get", secretRequest, this.jsonRustSerializerOptions); if (!result.IsSuccessStatusCode) { if(!isTrying) - this.logger!.LogError($"Failed to get the API key for 'provider::{secretId.SecretId}::{secretId.SecretName}::api_key' due to an API issue: '{result.StatusCode}'"); + this.logger!.LogError($"Failed to get the API key for '{prefix}::{secretId.SecretId}::{secretId.SecretName}::api_key' due to an API issue: '{result.StatusCode}'"); return new RequestedSecret(false, new EncryptedText(string.Empty), TB("Failed to get the API key due to an API issue.")); } - + var secret = await result.Content.ReadFromJsonAsync(this.jsonRustSerializerOptions); if (!secret.Success && !isTrying) - this.logger!.LogError($"Failed to get the API key for 'provider::{secretId.SecretId}::{secretId.SecretName}::api_key': '{secret.Issue}'"); - - this.logger!.LogDebug($"Successfully retrieved the API key for 'provider::{secretId.SecretId}::{secretId.SecretName}::api_key'."); + this.logger!.LogError($"Failed to get the API key for '{prefix}::{secretId.SecretId}::{secretId.SecretName}::api_key': '{secret.Issue}'"); + + this.logger!.LogDebug($"Successfully retrieved the API key for '{prefix}::{secretId.SecretId}::{secretId.SecretName}::api_key'."); return secret; } - + /// /// Try to store the API key for the given secret ID. /// /// The secret ID to store the API key for. /// The API key to store. + /// The secret store type. Defaults to LLM_PROVIDER for backward compatibility. /// The store secret response. - public async Task SetAPIKey(ISecretId secretId, string key) + public async Task SetAPIKey(ISecretId secretId, string key, SecretStoreType storeType) { + var prefix = storeType.Prefix(); var encryptedKey = await this.encryptor!.Encrypt(key); - var request = new StoreSecretRequest($"provider::{secretId.SecretId}::{secretId.SecretName}::api_key", Environment.UserName, encryptedKey); + var request = new StoreSecretRequest($"{prefix}::{secretId.SecretId}::{secretId.SecretName}::api_key", Environment.UserName, encryptedKey); var result = await this.http.PostAsJsonAsync("/secrets/store", request, this.jsonRustSerializerOptions); if (!result.IsSuccessStatusCode) { - this.logger!.LogError($"Failed to store the API key for 'provider::{secretId.SecretId}::{secretId.SecretName}::api_key' due to an API issue: '{result.StatusCode}'"); + this.logger!.LogError($"Failed to store the API key for '{prefix}::{secretId.SecretId}::{secretId.SecretName}::api_key' due to an API issue: '{result.StatusCode}'"); return new StoreSecretResponse(false, TB("Failed to get the API key due to an API issue.")); } - + var state = await result.Content.ReadFromJsonAsync(this.jsonRustSerializerOptions); if (!state.Success) - this.logger!.LogError($"Failed to store the API key for 'provider::{secretId.SecretId}::{secretId.SecretName}::api_key': '{state.Issue}'"); - - this.logger!.LogDebug($"Successfully stored the API key for 'provider::{secretId.SecretId}::{secretId.SecretName}::api_key'."); + this.logger!.LogError($"Failed to store the API key for '{prefix}::{secretId.SecretId}::{secretId.SecretName}::api_key': '{state.Issue}'"); + + this.logger!.LogDebug($"Successfully stored the API key for '{prefix}::{secretId.SecretId}::{secretId.SecretName}::api_key'."); return state; } - + /// /// Tries to delete the API key for the given secret ID. /// /// The secret ID to delete the API key for. + /// The secret store type. Defaults to LLM_PROVIDER for backward compatibility. /// The delete secret response. - public async Task DeleteAPIKey(ISecretId secretId) + public async Task DeleteAPIKey(ISecretId secretId, SecretStoreType storeType) { - var request = new SelectSecretRequest($"provider::{secretId.SecretId}::{secretId.SecretName}::api_key", Environment.UserName, false); + var prefix = storeType.Prefix(); + var request = new SelectSecretRequest($"{prefix}::{secretId.SecretId}::{secretId.SecretName}::api_key", Environment.UserName, false); var result = await this.http.PostAsJsonAsync("/secrets/delete", request, this.jsonRustSerializerOptions); if (!result.IsSuccessStatusCode) { this.logger!.LogError($"Failed to delete the API key for secret ID '{secretId.SecretId}' due to an API issue: '{result.StatusCode}'"); return new DeleteSecretResponse{Success = false, WasEntryFound = false, Issue = TB("Failed to delete the API key due to an API issue.")}; } - + var state = await result.Content.ReadFromJsonAsync(this.jsonRustSerializerOptions); if (!state.Success) this.logger!.LogError($"Failed to delete the API key for secret ID '{secretId.SecretId}': '{state.Issue}'"); - + return state; } } \ No newline at end of file