From f9e19d9d206932904250cc7e1b23283ccacf6b4b Mon Sep 17 00:00:00 2001 From: PaulKoudelka Date: Thu, 13 Nov 2025 12:52:56 +0100 Subject: [PATCH] Add profiles via plugins --- .../Dialogs/ProfileDialog.razor.cs | 4 +- .../Settings/SettingsDialogProfiles.razor | 23 +++++--- .../Plugins/configuration/plugin.lua | 11 ++++ app/MindWork AI Studio/Settings/Profile.cs | 58 ++++++++++++++++++- .../Tools/ComponentsExtensions.cs | 18 +++--- .../Tools/PluginSystem/PluginConfiguration.cs | 3 + .../PluginSystem/PluginConfigurationObject.cs | 3 +- .../PluginSystem/PluginFactory.Loading.cs | 4 ++ 8 files changed, 105 insertions(+), 19 deletions(-) diff --git a/app/MindWork AI Studio/Dialogs/ProfileDialog.razor.cs b/app/MindWork AI Studio/Dialogs/ProfileDialog.razor.cs index 1e78e684..54fbb2b8 100644 --- a/app/MindWork AI Studio/Dialogs/ProfileDialog.razor.cs +++ b/app/MindWork AI Studio/Dialogs/ProfileDialog.razor.cs @@ -67,10 +67,12 @@ public partial class ProfileDialog : MSGComponentBase { Num = this.DataNum, Id = this.DataId, - Name = this.DataName, NeedToKnow = this.DataNeedToKnow, Actions = this.DataActions, + + EnterpriseConfigurationPluginId = Guid.Empty, + IsEnterpriseConfiguration = false, }; #region Overrides of ComponentBase diff --git a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogProfiles.razor b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogProfiles.razor index ba476b3b..c251673b 100644 --- a/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogProfiles.razor +++ b/app/MindWork AI Studio/Dialogs/Settings/SettingsDialogProfiles.razor @@ -30,14 +30,23 @@ @context.Num @context.Name - - - + @if (context.IsEnterpriseConfiguration) + { + + - - - - + } + else + { + + + + + + + + + } diff --git a/app/MindWork AI Studio/Plugins/configuration/plugin.lua b/app/MindWork AI Studio/Plugins/configuration/plugin.lua index cff866f7..6a75ec6f 100644 --- a/app/MindWork AI Studio/Plugins/configuration/plugin.lua +++ b/app/MindWork AI Studio/Plugins/configuration/plugin.lua @@ -109,3 +109,14 @@ CONFIG["CHAT_TEMPLATES"][#CONFIG["CHAT_TEMPLATES"]+1] = { } } } + +-- Example profiles for this configuration: +CONFIG["PROFILES"] = {} + +-- A simple profile template: +CONFIG["PROFILES"][#CONFIG["PROFILES"]+1] = { + ["Id"] = "00000000-0000-0000-0000-000000000000", + ["Name"] = "", + ["NeedToKnow"] = "I like to cook in my free time. My favorite meal is ...", + ["Actions"] = "Please always ensure the portion size is ..." +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/Profile.cs b/app/MindWork AI Studio/Settings/Profile.cs index 5e0977f4..0436beb5 100644 --- a/app/MindWork AI Studio/Settings/Profile.cs +++ b/app/MindWork AI Studio/Settings/Profile.cs @@ -1,11 +1,25 @@ using AIStudio.Tools.PluginSystem; +using Lua; namespace AIStudio.Settings; -public readonly record struct Profile(uint Num, string Id, string Name, string NeedToKnow, string Actions) +public record Profile( + uint Num, + string Id, + string Name, + string NeedToKnow, + string Actions, + bool IsEnterpriseConfiguration = false, + Guid EnterpriseConfigurationPluginId = default): ConfigurationBaseObject { + public Profile() : this(0, Guid.Empty.ToString(), string.Empty, string.Empty, string.Empty) + { + } + private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(Profile).Namespace, nameof(Profile)); + private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger(); + public static readonly Profile NO_PROFILE = new() { Name = TB("Use no profile"), @@ -60,4 +74,46 @@ public readonly record struct Profile(uint Num, string Id, string Name, string N {actions} """; } + + public static bool TryParseProfileTable(int idx, LuaTable table, Guid configPluginId, out ConfigurationBaseObject template) + { + LOGGER.LogInformation($"\n Profile table parsing {idx}.\n"); + template = NO_PROFILE; + if (!table.TryGetValue("Id", out var idValue) || !idValue.TryRead(out var idText) || !Guid.TryParse(idText, out var id)) + { + LOGGER.LogWarning($"The configured profile {idx} does not contain a valid ID. The ID must be a valid GUID."); + return false; + } + + if (!table.TryGetValue("Name", out var nameValue) || !nameValue.TryRead(out var name)) + { + LOGGER.LogWarning($"The configured profile {idx} does not contain a valid name."); + return false; + } + + if (!table.TryGetValue("NeedToKnow", out var needToKnowValue) || !needToKnowValue.TryRead(out var needToKnow)) + { + LOGGER.LogWarning($"The configured profile {idx} does not contain valid NeedToKnow data."); + return false; + } + + if (!table.TryGetValue("Actions", out var actionsValue) || !actionsValue.TryRead(out var actions)) + { + LOGGER.LogWarning($"The configured profile {idx} does not contain valid actions data."); + return false; + } + + template = new Profile + { + Num = 0, + Id = id.ToString(), + Name = name, + NeedToKnow = needToKnow, + Actions = actions, + IsEnterpriseConfiguration = true, + EnterpriseConfigurationPluginId = configPluginId, + }; + + return true; + } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs index a2126970..6c2ccb88 100644 --- a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs +++ b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs @@ -123,17 +123,17 @@ public static class ComponentsExtensions public static Profile PreselectedProfile(this Components component, SettingsManager settingsManager) => component switch { - Components.AGENDA_ASSISTANT => settingsManager.ConfigurationData.Agenda.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Agenda.PreselectedProfile) : default, - Components.CODING_ASSISTANT => settingsManager.ConfigurationData.Coding.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Coding.PreselectedProfile) : default, - Components.EMAIL_ASSISTANT => settingsManager.ConfigurationData.EMail.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.EMail.PreselectedProfile) : default, - Components.LEGAL_CHECK_ASSISTANT => settingsManager.ConfigurationData.LegalCheck.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.LegalCheck.PreselectedProfile) : default, - Components.MY_TASKS_ASSISTANT => settingsManager.ConfigurationData.MyTasks.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.MyTasks.PreselectedProfile) : default, - Components.BIAS_DAY_ASSISTANT => settingsManager.ConfigurationData.BiasOfTheDay.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.BiasOfTheDay.PreselectedProfile) : default, - Components.ERI_ASSISTANT => settingsManager.ConfigurationData.ERI.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.ERI.PreselectedProfile) : default, + Components.AGENDA_ASSISTANT => settingsManager.ConfigurationData.Agenda.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Agenda.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, + Components.CODING_ASSISTANT => settingsManager.ConfigurationData.Coding.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Coding.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, + Components.EMAIL_ASSISTANT => settingsManager.ConfigurationData.EMail.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.EMail.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, + Components.LEGAL_CHECK_ASSISTANT => settingsManager.ConfigurationData.LegalCheck.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.LegalCheck.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, + Components.MY_TASKS_ASSISTANT => settingsManager.ConfigurationData.MyTasks.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.MyTasks.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, + Components.BIAS_DAY_ASSISTANT => settingsManager.ConfigurationData.BiasOfTheDay.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.BiasOfTheDay.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, + Components.ERI_ASSISTANT => settingsManager.ConfigurationData.ERI.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.ERI.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, - Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Chat.PreselectedProfile) : default, + Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Chat.PreselectedProfile) ?? Profile.NO_PROFILE : Profile.NO_PROFILE, - _ => default, + _ => Profile.NO_PROFILE, }; public static ChatTemplate PreselectedChatTemplate(this Components component, SettingsManager settingsManager) => component switch diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs index 943caa48..05da10fe 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfiguration.cs @@ -73,6 +73,9 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT // Handle configured chat templates: PluginConfigurationObject.TryParse(PluginConfigurationObjectType.CHAT_TEMPLATE, x => x.ChatTemplates, x => x.NextChatTemplateNum, mainTable, this.Id, ref this.configObjects, dryRun); + // Handle configured profiles: + PluginConfigurationObject.TryParse(PluginConfigurationObjectType.PROFILE, x => x.Profiles, x => x.NextProfileNum, mainTable, this.Id, ref this.configObjects, dryRun); + message = string.Empty; return true; } diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs index 5be55ddb..f05a724b 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginConfigurationObject.cs @@ -101,7 +101,8 @@ public sealed record PluginConfigurationObject { PluginConfigurationObjectType.LLM_PROVIDER => (Settings.Provider.TryParseProviderTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != Settings.Provider.NONE, configurationObject), PluginConfigurationObjectType.CHAT_TEMPLATE => (ChatTemplate.TryParseChatTemplateTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != ChatTemplate.NO_CHAT_TEMPLATE, configurationObject), - + PluginConfigurationObjectType.PROFILE => (Profile.TryParseProfileTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != Profile.NO_PROFILE, configurationObject), + _ => (false, NoConfigurationObject.INSTANCE) }; diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs index dfe3ad2d..9df176cd 100644 --- a/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs +++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginFactory.Loading.cs @@ -137,6 +137,10 @@ public static partial class PluginFactory if(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)) + wasConfigurationChanged = true; + // Check for the update interval: if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.UpdateInterval, AVAILABLE_PLUGINS)) wasConfigurationChanged = true;