diff --git a/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor b/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor
index 726ce248..18d453d6 100644
--- a/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor
+++ b/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor
@@ -103,7 +103,42 @@
Class='@MergeClass(button.Class, "mb-3")'
Style="@this.GetOptionalStyle(button.Style)">
@button.Text
-
+
+ }
+ break;
+ case AssistantComponentType.BUTTON_GROUP:
+ if (component is AssistantButtonGroup assistantButtonGroup)
+ {
+ var buttonGroup = assistantButtonGroup;
+
+ @foreach (var child in buttonGroup.Children)
+ {
+ if (child is AssistantButton childButton)
+ {
+
+ @childButton.Text
+
+ }
+ }
+
}
break;
case AssistantComponentType.PROVIDER_SELECTION:
diff --git a/app/MindWork AI Studio/Plugins/assistants/README.md b/app/MindWork AI Studio/Plugins/assistants/README.md
index f0ec6565..8800b004 100644
--- a/app/MindWork AI Studio/Plugins/assistants/README.md
+++ b/app/MindWork AI Studio/Plugins/assistants/README.md
@@ -12,6 +12,7 @@ Supported types (matching the Blazor UI components):
- `TEXT_AREA`: user input field based on `MudTextField`; requires `Name`, `Label`, and may include `HelperText`, `HelperTextOnFocus`, `Adornment`, `AdornmentIcon`, `AdornmentText`, `AdornmentColor`, `Counter`, `MaxLength`, `IsImmediate`, `UserPrompt`, `PrefillText`, `IsSingleLine`, `ReadOnly`, `Class`, `Style`.
- `DROPDOWN`: selects between variants; `Props` must include `Name`, `Label`, `Default`, `Items`, and optionally `ValueType` plus `UserPrompt`.
- `BUTTON`: invokes a Lua callback; `Props` must include `Name`, `Text`, `Action`, and may include `Variant`, `Color`, `IsFullWidth`, `Size`, `StartIcon`, `EndIcon`, `IconColor`, `IconSize`, `Class`, `Style`.
+- `BUTTON_GROUP`: groups multiple `BUTTON` children in a `MudButtonGroup`; `Children` must contain only `BUTTON` components and `Props` may include `Variant`, `Color`, `Size`, `OverrideStyles`, `Vertical`, `DropShadow`, `Class`, `Style`.
- `SWITCH`: boolean option; requires `Name`, `Label`, `Value`, and may include `Disabled`, `UserPrompt`, `LabelOn`, `LabelOff`, `LabelPlacement`, `Icon`, `IconColor`, `CheckedColor`, `UncheckedColor`, `Class`, `Style`.
- `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.
@@ -221,6 +222,64 @@ Example:
}
```
+### `BUTTON_GROUP` reference
+- Use `Type = "BUTTON_GROUP"` to render multiple `BUTTON` children as a single MudBlazor button group.
+- Required structure:
+ - `Children`: array of `BUTTON` component tables. Other child component types are ignored.
+- Optional props:
+ - `Variant`: one of the MudBlazor `Variant` enum names such as `Filled`, `Outlined`, `Text`; omitted values fall back to `Filled`.
+ - `Color`: one of the MudBlazor `Color` enum names such as `Default`, `Primary`, `Secondary`, `Info`; omitted values fall back to `Default`.
+ - `Size`: one of the MudBlazor `Size` enum names such as `Small`, `Medium`, `Large`; omitted values fall back to `Medium`.
+ - `OverrideStyles`: defaults to `false`; enables MudBlazor button-group style overrides.
+ - `Vertical`: defaults to `false`; when `true`, buttons are rendered vertically instead of horizontally.
+ - `DropShadow`: defaults to `true`; controls the group shadow.
+ - `Class`, `Style`: forwarded to the rendered `MudButtonGroup` for layout/styling.
+- Child buttons use the existing `BUTTON` props and behavior, including Lua `Action(input)`.
+
+Example:
+```lua
+{
+ ["Type"] = "BUTTON_GROUP",
+ ["Props"] = {
+ ["Variant"] = "Filled",
+ ["Color"] = "Primary",
+ ["Size"] = "Medium",
+ ["OverrideStyles"] = false,
+ ["Vertical"] = false,
+ ["DropShadow"] = true
+ },
+ ["Children"] = {
+ {
+ ["Type"] = "BUTTON",
+ ["Props"] = {
+ ["Name"] = "buildEmailOutput",
+ ["Text"] = "Build output",
+ ["Action"] = function(input)
+ return {
+ fields = {
+ outputBuffer = input.fields.emailContent or ""
+ }
+ }
+ end,
+ ["StartIcon"] = "Icons.Material.Filled.Build"
+ }
+ },
+ {
+ ["Type"] = "BUTTON",
+ ["Props"] = {
+ ["Name"] = "logColor",
+ ["Text"] = "Log color",
+ ["Action"] = function(input)
+ LogError("ColorPicker value: " .. tostring(input.fields.colorPicker or ""))
+ return nil
+ end,
+ ["EndIcon"] = "Icons.Material.Filled.BugReport"
+ }
+ }
+ }
+}
+```
+
### `SWITCH` reference
- Use `Type = "SWITCH"` to render a boolean toggle.
- Required props:
diff --git a/app/MindWork AI Studio/Plugins/assistants/plugin.lua b/app/MindWork AI Studio/Plugins/assistants/plugin.lua
index 6b5cbab5..084e90d2 100644
--- a/app/MindWork AI Studio/Plugins/assistants/plugin.lua
+++ b/app/MindWork AI Studio/Plugins/assistants/plugin.lua
@@ -152,6 +152,22 @@ ASSISTANT = {
["Style"] = "",
}
},
+ {
+ ["Type"] = "BUTTON_GROUP",
+ ["Props"] = {
+ ["Variant"] = "", -- display variation of the group. Defaults to Filled
+ ["Color"] = "", -- color of the group. Defaults to Default
+ ["Size"] = "", -- size of the group. Defaults to Medium
+ ["OverrideStyles"] = false, -- allows MudBlazor group style overrides. Defaults to false
+ ["Vertical"] = false, -- renders buttons vertically instead of horizontally. Defaults to false
+ ["DropShadow"] = true, -- applies a group shadow. Defaults to true
+ ["Class"] = "",
+ ["Style"] = "",
+ },
+ ["Children"] = {
+ -- BUTTON_ELEMENTS
+ }
+ },
{
["Type"] = "PROVIDER_SELECTION", -- required
["Props"] = {
diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantComponentFactory.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantComponentFactory.cs
index e5078a3b..c611b4f6 100644
--- a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantComponentFactory.cs
+++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/AssistantComponentFactory.cs
@@ -19,6 +19,8 @@ public class AssistantComponentFactory
return new AssistantTextArea { Props = props, Children = children };
case AssistantComponentType.BUTTON:
return new AssistantButton { Props = props, Children = children};
+ case AssistantComponentType.BUTTON_GROUP:
+ return new AssistantButtonGroup { Props = props, Children = children };
case AssistantComponentType.DROPDOWN:
return new AssistantDropdown { Props = props, Children = children };
case AssistantComponentType.PROVIDER_SELECTION:
diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantButtonGroup.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantButtonGroup.cs
new file mode 100644
index 00000000..668cd841
--- /dev/null
+++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantButtonGroup.cs
@@ -0,0 +1,58 @@
+namespace AIStudio.Tools.PluginSystem.Assistants.DataModel;
+
+public sealed class AssistantButtonGroup : AssistantComponentBase
+{
+ public override AssistantComponentType Type => AssistantComponentType.BUTTON_GROUP;
+ public override Dictionary Props { get; set; } = new();
+ public override List Children { get; set; } = new();
+
+ public string Variant
+ {
+ get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Variant));
+ set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Variant), value);
+ }
+
+ public string Color
+ {
+ get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Color));
+ set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Color), value);
+ }
+
+ public string Size
+ {
+ get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Size));
+ set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Size), value);
+ }
+
+ public bool OverrideStyles
+ {
+ get => AssistantComponentPropHelper.ReadBool(this.Props, nameof(this.OverrideStyles), false);
+ set => AssistantComponentPropHelper.WriteBool(this.Props, nameof(this.OverrideStyles), value);
+ }
+
+ public bool Vertical
+ {
+ get => AssistantComponentPropHelper.ReadBool(this.Props, nameof(this.Vertical), false);
+ set => AssistantComponentPropHelper.WriteBool(this.Props, nameof(this.Vertical), value);
+ }
+
+ public bool DropShadow
+ {
+ get => AssistantComponentPropHelper.ReadBool(this.Props, nameof(this.DropShadow), true);
+ set => AssistantComponentPropHelper.WriteBool(this.Props, nameof(this.DropShadow), 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);
+ }
+
+ public Variant GetVariant() => Enum.TryParse(this.Variant, out var variant) ? variant : MudBlazor.Variant.Filled;
+}
diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentType.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentType.cs
index d967860a..9a494d22 100644
--- a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentType.cs
+++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/AssistantComponentType.cs
@@ -5,6 +5,7 @@ public enum AssistantComponentType
FORM,
TEXT_AREA,
BUTTON,
+ BUTTON_GROUP,
DROPDOWN,
PROVIDER_SELECTION,
PROFILE_SELECTION,
diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/ComponentPropSpecs.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/ComponentPropSpecs.cs
index a5e521e6..9797b0ed 100644
--- a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/ComponentPropSpecs.cs
+++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/DataModel/ComponentPropSpecs.cs
@@ -24,6 +24,10 @@ public static class ComponentPropSpecs
"StartIcon", "EndIcon", "IconColor", "IconSize", "Class", "Style"
]
),
+ [AssistantComponentType.BUTTON_GROUP] = new(
+ required: [],
+ optional: ["Variant", "Color", "Size", "OverrideStyles", "Vertical", "DropShadow", "Class", "Style"]
+ ),
[AssistantComponentType.DROPDOWN] = new(
required: ["Name", "Label", "Default", "Items"],
optional: ["UserPrompt", "Class", "Style"]
diff --git a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/PluginAssistants.cs b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/PluginAssistants.cs
index 42833d78..204c274c 100644
--- a/app/MindWork AI Studio/Tools/PluginSystem/Assistants/PluginAssistants.cs
+++ b/app/MindWork AI Studio/Tools/PluginSystem/Assistants/PluginAssistants.cs
@@ -288,6 +288,16 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
textArea.IsImmediate = true;
}
+ if (component is AssistantButtonGroup buttonGroup)
+ {
+ var invalidChildren = buttonGroup.Children.Where(child => child.Type != AssistantComponentType.BUTTON).ToList();
+ if (invalidChildren.Count > 0)
+ {
+ LOGGER.LogWarning("Assistant plugin '{PluginName}' BUTTON_GROUP contains non-BUTTON children. Only BUTTON children are supported and invalid children are ignored.", this.Name);
+ buttonGroup.Children = buttonGroup.Children.Where(child => child.Type == AssistantComponentType.BUTTON).ToList();
+ }
+ }
+
return true;
}