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)]
@using AIStudio.Components
@using AIStudio.Settings
@using AIStudio.Tools.PluginSystem.Assistants.DataModel
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogDynamic>
@ -30,6 +32,13 @@
<ProviderSelection @bind-ProviderSettings="@this.providerSettings" ValidateProvider="@this.ValidatingProvider"/>
}
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:
if (component is AssistantSwitch assistantSwitch)
{
@ -84,4 +93,4 @@
}
break;
}
}
}

View File

@ -1,5 +1,6 @@
using AIStudio.Dialogs.Settings;
using AIStudio.Tools.PluginSystem;
using AIStudio.Settings;
using AIStudio.Tools.PluginSystem.Assistants;
using AIStudio.Tools.PluginSystem.Assistants.DataModel;
using Microsoft.AspNetCore.Components;
@ -15,6 +16,7 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
protected override string Description => this.description;
protected override string SystemPrompt => this.systemPrompt;
protected override bool AllowProfiles => this.allowProfiles;
protected override bool ShowProfileSelection => this.showFooterProfileSelection;
protected override string SubmitText => this.submitText;
protected override Func<Task> SubmitAction => this.Submit;
public override Tools.Components Component { get; }
@ -27,6 +29,7 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
private string submitText = string.Empty;
private string selectedTargetLanguage = string.Empty;
private string customTargetLanguage = string.Empty;
private bool showFooterProfileSelection = true;
private Dictionary<string, string> inputFields = new();
private Dictionary<string, string> dropdownFields = new();
@ -44,6 +47,7 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
this.systemPrompt = assistantPlugin.SystemPrompt;
this.submitText = assistantPlugin.SubmitText;
this.allowProfiles = assistantPlugin.AllowProfiles;
this.showFooterProfileSelection = !assistantPlugin.HasEmbeddedProfileSelection;
}
foreach (var component in this.RootComponent!.Children)
@ -138,10 +142,23 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
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()
{
this.CreateChatThread();
var time = this.AddUserRequest(this.CollectUserPrompt());
await this.AddAIResponseAsync(time);
}
}
}

View File

@ -382,6 +382,9 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::CODING::COMMONCODINGLANGUAGEEXTENSIONS::T
-- 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.
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:
ASSISTANT = {
["Title"] = "<main title of assistant>", -- required
["Description"] = "<assitant description>", -- required
["SystemPrompt"] = "<prompt that fudamentally changes behaviour, personality and task focus of your assistant. Invisible to the user>", -- required
["Description"] = "<assistant description>", -- 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
["AllowProfiles"] = true, -- if true, allows AiStudios profiles; required
["UI"] = {
@ -93,7 +93,7 @@ ASSISTANT = {
["Props"] = {
["Name"] = "<unique identifier of this 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>",
["LabelOn"] = "<text if state is true>", -- required
["LabelOff"] = "<text if state is false>" -- required
@ -102,8 +102,15 @@ ASSISTANT = {
{
["Type"] = "PROVIDER_SELECTION", -- required
["Props"] = {
["Name"] = "Anbieter",
["Label"] = "LLM auswählen"
["Name"] = "Provider",
["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 };
case AssistantUiCompontentType.PROVIDER_SELECTION:
return new AssistantProviderSelection { Props = props, Children = children };
case AssistantUiCompontentType.PROFILE_SELECTION:
return new AssistantProfileSelection { Props = props, Children = children };
case AssistantUiCompontentType.SWITCH:
return new AssistantSwitch { Props = props, Children = children };
case AssistantUiCompontentType.HEADING:
@ -36,4 +38,4 @@ public class AssistantComponentFactory
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,
DROPDOWN,
PROVIDER_SELECTION,
PROFILE_SELECTION,
SWITCH,
HEADING,
TEXT,
LIST,
}
}

View File

@ -25,6 +25,10 @@ public static class ComponentPropSpecs
required: ["Name", "Label"],
optional: []
),
[AssistantUiCompontentType.PROFILE_SELECTION] = new(
required: [],
optional: ["ValidationMessage"]
),
[AssistantUiCompontentType.SWITCH] = new(
required: ["Name", "Label", "LabelOn", "LabelOff", "Value"],
optional: ["UserPrompt"]
@ -42,4 +46,4 @@ public static class ComponentPropSpecs
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 SubmitText { get; set; } = string.Empty;
public bool AllowProfiles { get; set; } = true;
public bool HasEmbeddedProfileSelection { get; private set; }
public void TryLoad()
{
@ -36,6 +37,7 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
private bool TryProcessAssistant(out string message)
{
message = string.Empty;
this.HasEmbeddedProfileSelection = false;
// Ensure that the main ASSISTANT table exists and is a valid Lua table:
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.");
return false;
}
if (type == AssistantUiCompontentType.PROFILE_SELECTION)
this.HasEmbeddedProfileSelection = true;
Dictionary<string, object> props = new();
if (componentTable.TryGetValue("Props", out var propsVal)
@ -366,4 +371,4 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
return true;
}
}
}