added profile selection as a component for the assistant builder; minor warning fixes

This commit is contained in:
krut_ni 2026-02-23 15:01:00 +01:00
parent de1cf650f4
commit 58c034843b
No known key found for this signature in database
GPG Key ID: A5C0151B4DDB172C
9 changed files with 78 additions and 12 deletions

View File

@ -1,4 +1,6 @@
@attribute [Route(Routes.ASSISTANT_DYNAMIC)] @attribute [Route(Routes.ASSISTANT_DYNAMIC)]
@using AIStudio.Components
@using AIStudio.Settings
@using AIStudio.Tools.PluginSystem.Assistants.DataModel @using AIStudio.Tools.PluginSystem.Assistants.DataModel
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogDynamic> @inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogDynamic>
@ -30,6 +32,13 @@
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/> <ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
} }
break; break;
case AssistantUiCompontentType.PROFILE_SELECTION:
if (component is AssistantProfileSelection profileSelection)
{
var selection = profileSelection;
<ProfileFormSelection Validation="@((Profile profile) => this.ValidateProfileSelection(selection, profile))" @bind-Profile="@this.currentProfile"/>
}
break;
case AssistantUiCompontentType.SWITCH: case AssistantUiCompontentType.SWITCH:
if (component is AssistantSwitch assistantSwitch) if (component is AssistantSwitch assistantSwitch)
{ {
@ -84,4 +93,4 @@
} }
break; break;
} }
} }

View File

@ -1,5 +1,6 @@
using AIStudio.Dialogs.Settings; using AIStudio.Dialogs.Settings;
using AIStudio.Tools.PluginSystem; using AIStudio.Tools.PluginSystem;
using AIStudio.Settings;
using AIStudio.Tools.PluginSystem.Assistants; using AIStudio.Tools.PluginSystem.Assistants;
using AIStudio.Tools.PluginSystem.Assistants.DataModel; using AIStudio.Tools.PluginSystem.Assistants.DataModel;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
@ -15,6 +16,7 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
protected override string Description => this.description; protected override string Description => this.description;
protected override string SystemPrompt => this.systemPrompt; protected override string SystemPrompt => this.systemPrompt;
protected override bool AllowProfiles => this.allowProfiles; protected override bool AllowProfiles => this.allowProfiles;
protected override bool ShowProfileSelection => this.showFooterProfileSelection;
protected override string SubmitText => this.submitText; protected override string SubmitText => this.submitText;
protected override Func<Task> SubmitAction => this.Submit; protected override Func<Task> SubmitAction => this.Submit;
public override Tools.Components Component { get; } public override Tools.Components Component { get; }
@ -27,6 +29,7 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
private string submitText = string.Empty; private string submitText = string.Empty;
private string selectedTargetLanguage = string.Empty; private string selectedTargetLanguage = string.Empty;
private string customTargetLanguage = string.Empty; private string customTargetLanguage = string.Empty;
private bool showFooterProfileSelection = true;
private Dictionary<string, string> inputFields = new(); private Dictionary<string, string> inputFields = new();
private Dictionary<string, string> dropdownFields = new(); private Dictionary<string, string> dropdownFields = new();
@ -44,6 +47,7 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
this.systemPrompt = assistantPlugin.SystemPrompt; this.systemPrompt = assistantPlugin.SystemPrompt;
this.submitText = assistantPlugin.SubmitText; this.submitText = assistantPlugin.SubmitText;
this.allowProfiles = assistantPlugin.AllowProfiles; this.allowProfiles = assistantPlugin.AllowProfiles;
this.showFooterProfileSelection = !assistantPlugin.HasEmbeddedProfileSelection;
} }
foreach (var component in this.RootComponent!.Children) foreach (var component in this.RootComponent!.Children)
@ -138,10 +142,23 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
return prompt; return prompt;
} }
private string? ValidateProfileSelection(AssistantProfileSelection profileSelection, Profile profile)
{
if (profile == default || profile == Profile.NO_PROFILE)
{
if (!string.IsNullOrWhiteSpace(profileSelection.ValidationMessage))
return profileSelection.ValidationMessage;
return this.T("Please select one of your profiles.");
}
return null;
}
private async Task Submit() private async Task Submit()
{ {
this.CreateChatThread(); this.CreateChatThread();
var time = this.AddUserRequest(this.CollectUserPrompt()); var time = this.AddUserRequest(this.CollectUserPrompt());
await this.AddAIResponseAsync(time); await this.AddAIResponseAsync(time);
} }
} }

View File

@ -382,6 +382,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::CODING::COMMONCODINGLANGUAGEEXTENSIONS::T
-- None -- None
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::CODING::COMMONCODINGLANGUAGEEXTENSIONS::T810547195"] = "None" UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::CODING::COMMONCODINGLANGUAGEEXTENSIONS::T810547195"] = "None"
-- Please select one of your profiles.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::DYNAMIC::ASSISTANTDYNAMIC::T465395981"] = "Please select one of your profiles."
-- Provide a list of bullet points and some basic information for an e-mail. The assistant will generate an e-mail based on that input. -- Provide a list of bullet points and some basic information for an e-mail. The assistant will generate an e-mail based on that input.
UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::EMAIL::ASSISTANTEMAIL::T1143222914"] = "Provide a list of bullet points and some basic information for an e-mail. The assistant will generate an e-mail based on that input." UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::EMAIL::ASSISTANTEMAIL::T1143222914"] = "Provide a list of bullet points and some basic information for an e-mail. The assistant will generate an e-mail based on that input."

View File

@ -56,8 +56,8 @@ ASSISTANT = {
-- usage example with the full feature set: -- usage example with the full feature set:
ASSISTANT = { ASSISTANT = {
["Title"] = "<main title of assistant>", -- required ["Title"] = "<main title of assistant>", -- required
["Description"] = "<assitant description>", -- required ["Description"] = "<assistant description>", -- required
["SystemPrompt"] = "<prompt that fudamentally changes behaviour, personality and task focus of your assistant. Invisible to the user>", -- required ["SystemPrompt"] = "<prompt that fundamentally changes behaviour, personality and task focus of your assistant. Invisible to the user>", -- required
["SubmitText"] = "<label for submit button>", -- required ["SubmitText"] = "<label for submit button>", -- required
["AllowProfiles"] = true, -- if true, allows AiStudios profiles; required ["AllowProfiles"] = true, -- if true, allows AiStudios profiles; required
["UI"] = { ["UI"] = {
@ -93,7 +93,7 @@ ASSISTANT = {
["Props"] = { ["Props"] = {
["Name"] = "<unique identifier of this component>", -- required ["Name"] = "<unique identifier of this component>", -- required
["Label"] = "<heading of your component>", -- required ["Label"] = "<heading of your component>", -- required
["Value"] = true, -- intial switch state ["Value"] = true, -- initial switch state
["UserPrompt"] = "<direct input of instructions, questions, or tasks by a user>", ["UserPrompt"] = "<direct input of instructions, questions, or tasks by a user>",
["LabelOn"] = "<text if state is true>", -- required ["LabelOn"] = "<text if state is true>", -- required
["LabelOff"] = "<text if state is false>" -- required ["LabelOff"] = "<text if state is false>" -- required
@ -102,8 +102,15 @@ ASSISTANT = {
{ {
["Type"] = "PROVIDER_SELECTION", -- required ["Type"] = "PROVIDER_SELECTION", -- required
["Props"] = { ["Props"] = {
["Name"] = "Anbieter", ["Name"] = "Provider",
["Label"] = "LLM auswählen" ["Label"] = "Choose LLM"
}
},
-- If you add a PROFILE_SELECTION component, AI Studio will hide the footer selection and use this block instead:
{
["Type"] = "PROFILE_SELECTION",
["Props"] = {
["ValidationMessage"] = "<warning message that is shown when the user has not picked a profile>"
} }
}, },
{ {
@ -137,4 +144,4 @@ ASSISTANT = {
}, },
} }
}, },
} }

View File

@ -23,6 +23,8 @@ public class AssistantComponentFactory
return new AssistantDropdown { Props = props, Children = children }; return new AssistantDropdown { Props = props, Children = children };
case AssistantUiCompontentType.PROVIDER_SELECTION: case AssistantUiCompontentType.PROVIDER_SELECTION:
return new AssistantProviderSelection { Props = props, Children = children }; return new AssistantProviderSelection { Props = props, Children = children };
case AssistantUiCompontentType.PROFILE_SELECTION:
return new AssistantProfileSelection { Props = props, Children = children };
case AssistantUiCompontentType.SWITCH: case AssistantUiCompontentType.SWITCH:
return new AssistantSwitch { Props = props, Children = children }; return new AssistantSwitch { Props = props, Children = children };
case AssistantUiCompontentType.HEADING: case AssistantUiCompontentType.HEADING:
@ -36,4 +38,4 @@ public class AssistantComponentFactory
throw new Exception($"Unknown assistant component type: {type}"); throw new Exception($"Unknown assistant component type: {type}");
} }
} }
} }

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace AIStudio.Tools.PluginSystem.Assistants.DataModel;
public class AssistantProfileSelection : AssistantComponentBase
{
public override AssistantUiCompontentType Type => AssistantUiCompontentType.PROFILE_SELECTION;
public Dictionary<string, object> Props { get; set; } = new();
public List<IAssistantComponent> Children { get; set; } = new();
public string ValidationMessage
{
get => this.Props.TryGetValue(nameof(this.ValidationMessage), out var v)
? v.ToString() ?? string.Empty
: string.Empty;
set => this.Props[nameof(this.ValidationMessage)] = value;
}
}

View File

@ -7,8 +7,9 @@ public enum AssistantUiCompontentType
BUTTON, BUTTON,
DROPDOWN, DROPDOWN,
PROVIDER_SELECTION, PROVIDER_SELECTION,
PROFILE_SELECTION,
SWITCH, SWITCH,
HEADING, HEADING,
TEXT, TEXT,
LIST, LIST,
} }

View File

@ -25,6 +25,10 @@ public static class ComponentPropSpecs
required: ["Name", "Label"], required: ["Name", "Label"],
optional: [] optional: []
), ),
[AssistantUiCompontentType.PROFILE_SELECTION] = new(
required: [],
optional: ["ValidationMessage"]
),
[AssistantUiCompontentType.SWITCH] = new( [AssistantUiCompontentType.SWITCH] = new(
required: ["Name", "Label", "LabelOn", "LabelOff", "Value"], required: ["Name", "Label", "LabelOn", "LabelOff", "Value"],
optional: ["UserPrompt"] optional: ["UserPrompt"]
@ -42,4 +46,4 @@ public static class ComponentPropSpecs
optional: [] optional: []
), ),
}; };
} }

View File

@ -16,6 +16,7 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
public string SystemPrompt { get; set; } = string.Empty; public string SystemPrompt { get; set; } = string.Empty;
public string SubmitText { get; set; } = string.Empty; public string SubmitText { get; set; } = string.Empty;
public bool AllowProfiles { get; set; } = true; public bool AllowProfiles { get; set; } = true;
public bool HasEmbeddedProfileSelection { get; private set; }
public void TryLoad() public void TryLoad()
{ {
@ -36,6 +37,7 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
private bool TryProcessAssistant(out string message) private bool TryProcessAssistant(out string message)
{ {
message = string.Empty; message = string.Empty;
this.HasEmbeddedProfileSelection = false;
// Ensure that the main ASSISTANT table exists and is a valid Lua table: // Ensure that the main ASSISTANT table exists and is a valid Lua table:
if (!this.state.Environment["ASSISTANT"].TryRead<LuaTable>(out var assistantTable)) if (!this.state.Environment["ASSISTANT"].TryRead<LuaTable>(out var assistantTable))
@ -171,6 +173,9 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
LOGGER.LogWarning($"Component #{idx} missing valid Type."); LOGGER.LogWarning($"Component #{idx} missing valid Type.");
return false; return false;
} }
if (type == AssistantUiCompontentType.PROFILE_SELECTION)
this.HasEmbeddedProfileSelection = true;
Dictionary<string, object> props = new(); Dictionary<string, object> props = new();
if (componentTable.TryGetValue("Props", out var propsVal) if (componentTable.TryGetValue("Props", out var propsVal)
@ -366,4 +371,4 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
return true; return true;
} }
} }