diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs index 647c79bf..5687fdf5 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs @@ -2,6 +2,7 @@ using System.Linq.Expressions; using AIStudio.Settings; using AIStudio.Settings.DataModel; +using AIStudio.Tools.Services; using Lua; @@ -13,6 +14,7 @@ namespace AIStudio.Tools.PluginSystem; /// public sealed record PluginConfigurationObject { + private static readonly RustService RUST_SERVICE = Program.SERVICE_PROVIDER.GetRequiredService(); private static readonly SettingsManager SETTINGS_MANAGER = Program.SERVICE_PROVIDER.GetRequiredService(); private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger(); @@ -159,7 +161,7 @@ public sealed record PluginConfigurationObject return true; } - + /// /// Cleans up configuration objects of a specified type that are no longer associated with any available plugin. /// @@ -168,12 +170,14 @@ public sealed record PluginConfigurationObject /// A selection expression to retrieve the configuration objects from the main configuration. /// A list of currently available plugins. /// A list of all existing configuration objects. + /// An optional parameter specifying the type of secret store to use for deleting associated API keys from the OS keyring, if applicable. /// Returns true if the configuration was altered during cleanup; otherwise, false. - public static bool CleanLeftOverConfigurationObjects( + public static async Task CleanLeftOverConfigurationObjects( PluginConfigurationObjectType configObjectType, Expression>> configObjectSelection, IList availablePlugins, - IList configObjectList) where TClass : IConfigurationObject + IList configObjectList, + SecretStoreType? secretStoreType = null) where TClass : IConfigurationObject { var configuredObjects = configObjectSelection.Compile()(SETTINGS_MANAGER.ConfigurationData); var leftOverObjects = new List(); @@ -206,8 +210,20 @@ public sealed record PluginConfigurationObject // Remove collected items after enumeration to avoid modifying the collection during iteration: var wasConfigurationChanged = leftOverObjects.Count > 0; foreach (var item in leftOverObjects.Distinct()) + { configuredObjects.Remove(item); + // Delete the API key from the OS keyring if the removed object has one: + if(secretStoreType is not null && item is ISecretId secretId) + { + var deleteResult = await RUST_SERVICE.DeleteAPIKey(secretId, secretStoreType.Value); + if (deleteResult.Success) + LOG.LogInformation($"Successfully deleted API key for removed enterprise provider '{item.Name}' from the OS keyring."); + else + LOG.LogWarning($"Failed to delete API key for removed enterprise provider '{item.Name}' from the OS keyring: {deleteResult.Issue}"); + } + } + return wasConfigurationChanged; } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs index d11ed434..4bfbe3a3 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs @@ -131,26 +131,26 @@ public static partial class PluginFactory // // Check LLM providers: - var wasConfigurationChanged = PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.LLM_PROVIDER, x => x.Providers, AVAILABLE_PLUGINS, configObjectList); + var wasConfigurationChanged = await PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.LLM_PROVIDER, x => x.Providers, AVAILABLE_PLUGINS, configObjectList, SecretStoreType.LLM_PROVIDER); // Check transcription providers: - if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.TRANSCRIPTION_PROVIDER, x => x.TranscriptionProviders, AVAILABLE_PLUGINS, configObjectList)) + if(await PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.TRANSCRIPTION_PROVIDER, x => x.TranscriptionProviders, AVAILABLE_PLUGINS, configObjectList, SecretStoreType.TRANSCRIPTION_PROVIDER)) wasConfigurationChanged = true; // Check embedding providers: - if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.EMBEDDING_PROVIDER, x => x.EmbeddingProviders, AVAILABLE_PLUGINS, configObjectList)) + if(await PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.EMBEDDING_PROVIDER, x => x.EmbeddingProviders, AVAILABLE_PLUGINS, configObjectList, SecretStoreType.EMBEDDING_PROVIDER)) wasConfigurationChanged = true; // Check chat templates: - if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.CHAT_TEMPLATE, x => x.ChatTemplates, AVAILABLE_PLUGINS, configObjectList)) + if(await PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.CHAT_TEMPLATE, x => x.ChatTemplates, AVAILABLE_PLUGINS, configObjectList)) wasConfigurationChanged = true; - + // Check profiles: - if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.PROFILE, x => x.Profiles, AVAILABLE_PLUGINS, configObjectList)) + if(await PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.PROFILE, x => x.Profiles, AVAILABLE_PLUGINS, configObjectList)) wasConfigurationChanged = true; // Check document analysis policies: - if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.DOCUMENT_ANALYSIS_POLICY, x => x.DocumentAnalysis.Policies, AVAILABLE_PLUGINS, configObjectList)) + if(await PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.DOCUMENT_ANALYSIS_POLICY, x => x.DocumentAnalysis.Policies, AVAILABLE_PLUGINS, configObjectList)) wasConfigurationChanged = true; // Check for a preselected profile: