added a new color picker component to the lua parsing

This commit is contained in:
krut_ni 2026-03-09 13:23:35 +01:00
parent fc3b46a2d8
commit a5149e460f
No known key found for this signature in database
GPG Key ID: A5C0151B4DDB172C
8 changed files with 185 additions and 5 deletions

View File

@ -135,5 +135,28 @@
</MudList>
}
break;
case AssistantComponentType.COLOR_PICKER:
if (component is AssistantColorPicker assistantColorPicker)
{
var colorPicker = assistantColorPicker;
var variant = this.GetPickerVariant(colorPicker.PickerVariant);
var elevation = variant == PickerVariant.Static ? 6 : 0;
var rounded = variant == PickerVariant.Static;
<MudItem Class="d-flex">
<MudColorPicker @bind-Text="@this.colorPickerFields[colorPicker.Name]"
Label="@colorPicker.Label"
Placeholder="@colorPicker.Placeholder"
ShowAlpha="@colorPicker.ShowAlpha"
ShowToolbar="@colorPicker.ShowToolbar"
ShowModeSwitch="@colorPicker.ShowModeSwitch"
PickerVariant="@variant"
Rounded="@rounded"
Elevation="@elevation"
Style="@($"color: {this.colorPickerFields[colorPicker.Name]};")"
Class="@MergeClass(colorPicker.Class, "mb-3")"/>
</MudItem>
}
break;
}
}

View File

@ -45,6 +45,7 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
private Dictionary<string, bool> switchFields = new();
private Dictionary<string, WebContentState> webContentFields = new();
private Dictionary<string, FileContentState> fileContentFields = new();
private Dictionary<string, string> colorPickerFields = new();
private readonly Dictionary<string, string> imageCache = new();
private string pluginPath = string.Empty;
private const string PLUGIN_SCHEME = "plugin://";
@ -111,6 +112,12 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
this.fileContentFields.Add(fileContent.Name, new FileContentState());
}
break;
case AssistantComponentType.COLOR_PICKER:
if (component is AssistantColorPicker assistantColorPicker)
{
this.colorPickerFields.Add(assistantColorPicker.Name, assistantColorPicker.Placeholder);
}
break;
}
}
}
@ -167,6 +174,11 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
{
entry.Value.Content = string.Empty;
}
foreach (var entry in this.colorPickerFields)
{
this.colorPickerFields[entry.Key] = string.Empty;
}
}
protected override bool MightPreselectValues()
@ -256,6 +268,8 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
fields[entry.Key] = entry.Value.Content ?? string.Empty;
foreach (var entry in this.fileContentFields)
fields[entry.Key] = entry.Value.Content ?? string.Empty;
foreach (var entry in this.colorPickerFields)
fields[entry.Key] = entry.Value ?? string.Empty;
input["fields"] = fields;
@ -282,6 +296,9 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
case AssistantFileContentReader fileContent:
this.AddMetaEntry(meta, fileContent.Name, component.Type, null, fileContent.UserPrompt);
break;
case AssistantColorPicker colorPicker:
this.AddMetaEntry(meta, colorPicker.Name, component.Type, colorPicker.Label, colorPicker.UserPrompt);
break;
}
}
}
@ -391,6 +408,16 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
}
}
break;
case AssistantComponentType.COLOR_PICKER:
if (component is AssistantColorPicker colorPicker)
{
prompt += $"context:{Environment.NewLine}{colorPicker.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
if (this.inputFields.TryGetValue(colorPicker.Name, out userInput))
{
prompt += $"user prompt:{Environment.NewLine}{userInput}";
}
}
break;
default:
prompt += $"{userInput}{Environment.NewLine}";
break;
@ -414,8 +441,16 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
}
private string? GetOptionalStyle(string? style) => string.IsNullOrWhiteSpace(style) ? null : style;
private string? ValidateProfileSelection(AssistantProfileSelection profileSelection, Profile profile)
private PickerVariant GetPickerVariant(string pickerVariant) => pickerVariant.ToLowerInvariant() switch
{
"dialog" => PickerVariant.Dialog,
"static" => PickerVariant.Static,
"inline" => PickerVariant.Inline,
_ => PickerVariant.Static
};
private string? ValidateProfileSelection(AssistantProfileSelection profileSelection, Profile? profile)
{
if (profile == default || profile == Profile.NO_PROFILE)
{

View File

@ -12,6 +12,7 @@ Supported types (matching the Blazor UI components):
- `TEXT_AREA`: any user input field with `Name`, `Label`, `UserPrompt`, `PrefillText`, `IsSingleLine`, `ReadOnly`.
- `DROPDOWN`: selects between variants; `Props` must include `Name`, `Label`, `Default`, `Items`, and optionally `ValueType` plus `UserPrompt`.
- `SWITCH`: boolean option; requires `Name`, `Label`, `Value`, `LabelOn`, `LabelOff`, and may include `UserPrompt`.
- `COLOR_PICKER`: color input based on `MudColorPicker`; requires `Name`, `Label`, and may include `Placeholder`, `ShowAlpha`, `ShowToolbar`, `ShowModeSwitch`, `PickerVariant`, `UserPrompt`, `Class`, `Style`.
- `PROVIDER_SELECTION` / `PROFILE_SELECTION`: hooks into the shared provider/profile selectors.
- `WEB_CONTENT_READER`: renders `ReadWebContent`; include `Name`, `UserPrompt`, `Preselect`, `PreselectContentCleanerAgent`.
- `FILE_CONTENT_READER`: renders `ReadFileContent`; include `Name`, `UserPrompt`.
@ -31,7 +32,7 @@ user prompt:
<value extracted from the component>
```
For switches the “value” is the boolean `true/false`; for readers it is the fetched/selected content. Always provide a meaningful `UserPrompt` so the final concatenated prompt remains coherent from the LLMs perspective.
For switches the “value” is the boolean `true/false`; for readers it is the fetched/selected content; for color pickers it is the selected color text (for example `#FFAA00` or `rgba(...)`, depending on the picker mode). Always provide a meaningful `UserPrompt` so the final concatenated prompt remains coherent from the LLMs perspective.
### Advanced: BuildPrompt (optional)
If you want full control over prompt composition, define `ASSISTANT.BuildPrompt` as a Lua function. When present, AI Studio calls it and uses its return value as the final user prompt. The default prompt assembly is skipped.
@ -46,8 +47,9 @@ The function receives a single `input` table with:
- `input.fields`: values keyed by component `Name`
- Text area, dropdown, and readers are strings
- Switch is a boolean
- Color picker is the selected color as a string
- `input.meta`: per-component metadata keyed by component `Name`
- `Type` (string, e.g. `TEXT_AREA`, `DROPDOWN`, `SWITCH`)
- `Type` (string, e.g. `TEXT_AREA`, `DROPDOWN`, `SWITCH`, `COLOR_PICKER`)
- `Label` (string, when provided)
- `UserPrompt` (string, when provided)
- `input.profile`: selected profile data
@ -63,7 +65,7 @@ input = {
},
meta = {
["<Name>"] = {
Type = "<TEXT_AREA|DROPDOWN|SWITCH|WEB_CONTENT_READER|FILE_CONTENT_READER>",
Type = "<TEXT_AREA|DROPDOWN|SWITCH|WEB_CONTENT_READER|FILE_CONTENT_READER|COLOR_PICKER>",
Label = "<string?>",
UserPrompt = "<string?>"
},
@ -103,6 +105,8 @@ ASSISTANT.BuildPrompt = function(input)
local value = input.fields[name]
if meta.Type == "SWITCH" then
table.insert(parts, name .. ": " .. tostring(value))
elseif meta.Type == "COLOR_PICKER" and value and value ~= "" then
table.insert(parts, name .. ": " .. value)
elseif value and value ~= "" then
table.insert(parts, name .. ": " .. value)
end
@ -111,6 +115,37 @@ ASSISTANT.BuildPrompt = function(input)
end
```
### `COLOR_PICKER` reference
- Use `Type = "COLOR_PICKER"` to render a MudBlazor color picker.
- Required props:
- `Name`: unique state key used in prompt assembly and `BuildPrompt(input.fields)`.
- `Label`: visible field label.
- Optional props:
- `Placeholder`: default color hex string (e.g. `#FF10FF`) or initial hint text.
- `ShowAlpha`: defaults to `true`; enables alpha channel editing.
- `ShowToolbar`: defaults to `true`; shows picker/grid/palette toolbar.
- `ShowModeSwitch`: defaults to `true`; allows switching between HEX/RGB(A)/HSL modes.
- `PickerVariant`: one of `DIALOG`, `INLINE`, `STATIC`; invalid or omitted values fall back to `STATIC`.
- `UserPrompt`: prompt context text for the selected color.
- `Class`, `Style`: forwarded to the rendered component for layout/styling.
Example:
```lua
{
["Type"] = "COLOR_PICKER",
["Props"] = {
["Name"] = "accentColor",
["Label"] = "Accent color",
["Placeholder"] = "#FFAA00",
["ShowAlpha"] = false,
["ShowToolbar"] = true,
["ShowModeSwitch"] = true,
["PickerVariant"] = "STATIC",
["UserPrompt"] = "Use this as the accent color for the generated design."
}
}
```
#### Using `profile` inside BuildPrompt
Profiles are optional user context (e.g., "NeedToKnow" and "Actions"). You can inject this directly into the user prompt if you want the LLM to always see it.

View File

@ -168,6 +168,19 @@ ASSISTANT = {
["UserPrompt"] = "<help text reminding the user what kind of file they should load>"
}
},
{
["Type"] = "COLOR_PICKER",
["Props"] = {
["Name"] = "<unique identifier of this component>", -- required
["Label"] = "<heading of your component>", -- required
["Placeholder"] = "<use this as a default color property with HEX code (e.g '#FFFF12') or just show hints to the user>",
["ShowAlpha"] = true, -- weather alpha channels are shown
["ShowToolbar"] = true, -- weather the toolbar to toggle between picker, grid or palette is shown
["ShowModeSwitch"] = true, -- weather switch to toggle between RGB(A), HEX or HSL color mode is shown
["PickerVariant"] = "<DIALOG | INLINE | STATIC (default)>",
["UserPrompt"] = "<help text reminding the user what kind of file they should load>",
}
},
}
},
}

View File

@ -39,6 +39,8 @@ public class AssistantComponentFactory
return new AssistantFileContentReader { Props = props, Children = children };
case AssistantComponentType.IMAGE:
return new AssistantImage { Props = props, Children = children };
case AssistantComponentType.COLOR_PICKER:
return new AssistantColorPicker { Props = props, Children = children };
default:
LOGGER.LogError($"Unknown assistant component type!\n{type} is not a supported assistant component type");
throw new Exception($"Unknown assistant component type: {type}");

View File

@ -0,0 +1,67 @@
namespace AIStudio.Tools.PluginSystem.Assistants.DataModel;
internal sealed class AssistantColorPicker : AssistantComponentBase
{
public override AssistantComponentType Type => AssistantComponentType.COLOR_PICKER;
public override Dictionary<string, object> Props { get; set; } = new();
public override List<IAssistantComponent> Children { get; set; } = new();
public string Name
{
get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Name));
set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Name), value);
}
public string Label
{
get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Label));
set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Label), value);
}
public string Placeholder
{
get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Placeholder));
set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Placeholder), value);
}
public bool ShowAlpha
{
get => !this.Props.TryGetValue(nameof(this.ShowAlpha), out var val) || val is true;
set => this.Props[nameof(this.ShowAlpha)] = value;
}
public bool ShowToolbar
{
get => !this.Props.TryGetValue(nameof(this.ShowToolbar), out var val) || val is true;
set => this.Props[nameof(this.ShowToolbar)] = value;
}
public bool ShowModeSwitch
{
get => !this.Props.TryGetValue(nameof(this.ShowModeSwitch), out var val) || val is true;
set => this.Props[nameof(this.ShowModeSwitch)] = value;
}
public string PickerVariant
{
get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.PickerVariant));
set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.PickerVariant), value);
}
public string UserPrompt
{
get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.UserPrompt));
set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.UserPrompt), value);
}
public string Class
{
get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Class));
set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Class), value);
}
public string Style
{
get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Style));
set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Style), value);
}
}

View File

@ -15,4 +15,5 @@ public enum AssistantComponentType
WEB_CONTENT_READER,
FILE_CONTENT_READER,
IMAGE,
COLOR_PICKER,
}

View File

@ -57,5 +57,9 @@ public static class ComponentPropSpecs
required: ["Src"],
optional: ["Alt", "Caption", "Class", "Style"]
),
[AssistantComponentType.COLOR_PICKER] = new(
required: ["Name", "Label"],
optional: ["Placeholder", "ShowAlpha", "ShowToolbar", "ShowModeSwitch", "PickerVariant", "UserPrompt", "Class", "Style"]
),
};
}