mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-03-30 19:31:36 +00:00
advanced layout: included the layout option in the rendering and documented them
This commit is contained in:
parent
5106800399
commit
edc717cf24
@ -2,6 +2,7 @@
|
|||||||
@using AIStudio.Components
|
@using AIStudio.Components
|
||||||
@using AIStudio.Settings
|
@using AIStudio.Settings
|
||||||
@using AIStudio.Tools.PluginSystem.Assistants.DataModel
|
@using AIStudio.Tools.PluginSystem.Assistants.DataModel
|
||||||
|
@using AIStudio.Tools.PluginSystem.Assistants.DataModel.Layout
|
||||||
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogDynamic>
|
@inherits AssistantBaseCore<AIStudio.Dialogs.Settings.SettingsDialogDynamic>
|
||||||
|
|
||||||
@foreach (var component in this.RootComponent!.Children)
|
@foreach (var component in this.RootComponent!.Children)
|
||||||
@ -133,6 +134,55 @@
|
|||||||
</MudButtonGroup>
|
</MudButtonGroup>
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case AssistantComponentType.LAYOUT_GRID:
|
||||||
|
if (component is AssistantGrid assistantGrid)
|
||||||
|
{
|
||||||
|
var grid = assistantGrid;
|
||||||
|
<MudGrid Justify="@(AssistantComponentPropHelper.GetJustify(grid.Justify) ?? Justify.FlexStart)"
|
||||||
|
Spacing="@grid.Spacing"
|
||||||
|
Class="@grid.Class"
|
||||||
|
Style="@this.GetOptionalStyle(grid.Style)">
|
||||||
|
@this.RenderChildren(grid.Children)
|
||||||
|
</MudGrid>
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AssistantComponentType.LAYOUT_ITEM:
|
||||||
|
if (component is AssistantItem assistantItem)
|
||||||
|
{
|
||||||
|
@this.RenderLayoutItem(assistantItem)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AssistantComponentType.LAYOUT_PAPER:
|
||||||
|
if (component is AssistantPaper assistantPaper)
|
||||||
|
{
|
||||||
|
var paper = assistantPaper;
|
||||||
|
<MudPaper Elevation="@paper.Elevation"
|
||||||
|
Outlined="@paper.IsOutlined"
|
||||||
|
Square="@paper.IsSquare"
|
||||||
|
Class="@paper.Class"
|
||||||
|
Style="@this.BuildPaperStyle(paper)">
|
||||||
|
@this.RenderChildren(paper.Children)
|
||||||
|
</MudPaper>
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AssistantComponentType.LAYOUT_STACK:
|
||||||
|
if (component is AssistantStack assistantStack)
|
||||||
|
{
|
||||||
|
var stack = assistantStack;
|
||||||
|
<MudStack Row="@stack.IsRow"
|
||||||
|
Reverse="@stack.IsReverse"
|
||||||
|
Breakpoint="@AssistantComponentPropHelper.GetBreakpoint(stack.Breakpoint, Breakpoint.None)"
|
||||||
|
AlignItems="@(AssistantComponentPropHelper.GetAlignment(stack.Align) ?? AlignItems.Stretch)"
|
||||||
|
Justify="@(AssistantComponentPropHelper.GetJustify(stack.Justify) ?? Justify.FlexStart)"
|
||||||
|
StretchItems="@(AssistantComponentPropHelper.GetStretching(stack.Stretch) ?? StretchItems.None)"
|
||||||
|
Wrap="@(AssistantComponentPropHelper.GetWrap(stack.Wrap) ?? Wrap.Wrap)"
|
||||||
|
Spacing="@stack.Spacing"
|
||||||
|
Class="@stack.Class"
|
||||||
|
Style="@this.GetOptionalStyle(this.GetRawStyle(stack))">
|
||||||
|
@this.RenderChildren(stack.Children)
|
||||||
|
</MudStack>
|
||||||
|
}
|
||||||
|
break;
|
||||||
case AssistantComponentType.PROVIDER_SELECTION:
|
case AssistantComponentType.PROVIDER_SELECTION:
|
||||||
if (component is AssistantProviderSelection providerSelection)
|
if (component is AssistantProviderSelection providerSelection)
|
||||||
{
|
{
|
||||||
@ -244,4 +294,70 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
</text>;
|
</text>;
|
||||||
|
|
||||||
|
private string? GetRawStyle(IAssistantComponent component)
|
||||||
|
{
|
||||||
|
if (!component.Props.TryGetValue("Style", out var rawStyle) || rawStyle is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return rawStyle as string ?? rawStyle.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? BuildPaperStyle(AssistantPaper paper)
|
||||||
|
{
|
||||||
|
List<string> styles = [];
|
||||||
|
|
||||||
|
this.AddStyle(styles, "height", paper.Height);
|
||||||
|
this.AddStyle(styles, "max-height", paper.MaxHeight);
|
||||||
|
this.AddStyle(styles, "min-height", paper.MinHeight);
|
||||||
|
this.AddStyle(styles, "width", paper.Width);
|
||||||
|
this.AddStyle(styles, "max-width", paper.MaxWidth);
|
||||||
|
this.AddStyle(styles, "min-width", paper.MinWidth);
|
||||||
|
|
||||||
|
var customStyle = this.GetRawStyle(paper);
|
||||||
|
if (!string.IsNullOrWhiteSpace(customStyle))
|
||||||
|
styles.Add(customStyle.Trim().TrimEnd(';'));
|
||||||
|
|
||||||
|
return styles.Count == 0 ? null : string.Join("; ", styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RenderFragment RenderLayoutItem(AssistantItem item) => builder =>
|
||||||
|
{
|
||||||
|
builder.OpenComponent<MudItem>(0);
|
||||||
|
|
||||||
|
if (item.Xs.HasValue)
|
||||||
|
builder.AddAttribute(1, "xs", item.Xs.Value);
|
||||||
|
|
||||||
|
if (item.Sm.HasValue)
|
||||||
|
builder.AddAttribute(2, "sm", item.Sm.Value);
|
||||||
|
|
||||||
|
if (item.Md.HasValue)
|
||||||
|
builder.AddAttribute(3, "md", item.Md.Value);
|
||||||
|
|
||||||
|
if (item.Lg.HasValue)
|
||||||
|
builder.AddAttribute(4, "lg", item.Lg.Value);
|
||||||
|
|
||||||
|
if (item.Xl.HasValue)
|
||||||
|
builder.AddAttribute(5, "xl", item.Xl.Value);
|
||||||
|
|
||||||
|
if (item.Xxl.HasValue)
|
||||||
|
builder.AddAttribute(6, "xxl", item.Xxl.Value);
|
||||||
|
|
||||||
|
var itemClass = item.Class;
|
||||||
|
if (!string.IsNullOrWhiteSpace(itemClass))
|
||||||
|
builder.AddAttribute(7, nameof(MudItem.Class), itemClass);
|
||||||
|
|
||||||
|
var itemStyle = this.GetOptionalStyle(item.Style);
|
||||||
|
if (!string.IsNullOrWhiteSpace(itemStyle))
|
||||||
|
builder.AddAttribute(8, nameof(MudItem.Style), itemStyle);
|
||||||
|
|
||||||
|
builder.AddAttribute(9, nameof(MudItem.ChildContent), this.RenderChildren(item.Children));
|
||||||
|
builder.CloseComponent();
|
||||||
|
};
|
||||||
|
|
||||||
|
private void AddStyle(List<string> styles, string key, string value)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(value))
|
||||||
|
styles.Add($"{key}: {value.Trim().TrimEnd(';')}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,52 +76,7 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
|
|||||||
var rootComponent = this.RootComponent;
|
var rootComponent = this.RootComponent;
|
||||||
if (rootComponent is not null)
|
if (rootComponent is not null)
|
||||||
{
|
{
|
||||||
foreach (var component in rootComponent.Children)
|
this.InitializeComponentState(rootComponent.Children);
|
||||||
{
|
|
||||||
switch (component.Type)
|
|
||||||
{
|
|
||||||
case AssistantComponentType.TEXT_AREA:
|
|
||||||
if (component is AssistantTextArea textArea)
|
|
||||||
{
|
|
||||||
this.inputFields.Add(textArea.Name, textArea.PrefillText);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AssistantComponentType.DROPDOWN:
|
|
||||||
if (component is AssistantDropdown dropdown)
|
|
||||||
{
|
|
||||||
this.dropdownFields.Add(dropdown.Name, dropdown.Default.Value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AssistantComponentType.SWITCH:
|
|
||||||
if (component is AssistantSwitch switchComponent)
|
|
||||||
{
|
|
||||||
this.switchFields.Add(switchComponent.Name, switchComponent.Value);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AssistantComponentType.WEB_CONTENT_READER:
|
|
||||||
if (component is AssistantWebContentReader webContent)
|
|
||||||
{
|
|
||||||
this.webContentFields.Add(webContent.Name, new WebContentState
|
|
||||||
{
|
|
||||||
Preselect = webContent.Preselect,
|
|
||||||
PreselectContentCleanerAgent = webContent.PreselectContentCleanerAgent,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AssistantComponentType.FILE_CONTENT_READER:
|
|
||||||
if (component is AssistantFileContentReader fileContent)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnInitialized();
|
base.OnInitialized();
|
||||||
@ -277,32 +232,7 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
|
|||||||
var meta = new LuaTable();
|
var meta = new LuaTable();
|
||||||
var rootComponent = this.RootComponent;
|
var rootComponent = this.RootComponent;
|
||||||
if (rootComponent is not null)
|
if (rootComponent is not null)
|
||||||
{
|
this.AddMetaEntries(meta, rootComponent.Children);
|
||||||
foreach (var component in rootComponent.Children)
|
|
||||||
{
|
|
||||||
switch (component)
|
|
||||||
{
|
|
||||||
case AssistantTextArea textArea:
|
|
||||||
this.AddMetaEntry(meta, textArea.Name, component.Type, textArea.Label, textArea.UserPrompt);
|
|
||||||
break;
|
|
||||||
case AssistantDropdown dropdown:
|
|
||||||
this.AddMetaEntry(meta, dropdown.Name, component.Type, dropdown.Label, dropdown.UserPrompt);
|
|
||||||
break;
|
|
||||||
case AssistantSwitch switchComponent:
|
|
||||||
this.AddMetaEntry(meta, switchComponent.Name, component.Type, switchComponent.Label, switchComponent.UserPrompt);
|
|
||||||
break;
|
|
||||||
case AssistantWebContentReader webContent:
|
|
||||||
this.AddMetaEntry(meta, webContent.Name, component.Type, null, webContent.UserPrompt);
|
|
||||||
break;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input["meta"] = meta;
|
input["meta"] = meta;
|
||||||
|
|
||||||
@ -343,89 +273,50 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
|
|||||||
if (rootComponent is null)
|
if (rootComponent is null)
|
||||||
return prompt;
|
return prompt;
|
||||||
|
|
||||||
foreach (var component in rootComponent.Children)
|
return this.CollectUserPromptFallback(rootComponent.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponentState(IEnumerable<IAssistantComponent> components)
|
||||||
|
{
|
||||||
|
foreach (var component in components)
|
||||||
{
|
{
|
||||||
var userInput = string.Empty;
|
|
||||||
var userDecision = false;
|
|
||||||
switch (component.Type)
|
switch (component.Type)
|
||||||
{
|
{
|
||||||
case AssistantComponentType.TEXT_AREA:
|
case AssistantComponentType.TEXT_AREA:
|
||||||
if (component is AssistantTextArea textArea)
|
if (component is AssistantTextArea textArea && !this.inputFields.ContainsKey(textArea.Name))
|
||||||
{
|
this.inputFields.Add(textArea.Name, textArea.PrefillText);
|
||||||
prompt += $"context:{Environment.NewLine}{textArea.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
|
|
||||||
if (this.inputFields.TryGetValue(textArea.Name, out userInput))
|
|
||||||
{
|
|
||||||
prompt += $"user prompt:{Environment.NewLine}{userInput}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case AssistantComponentType.DROPDOWN:
|
case AssistantComponentType.DROPDOWN:
|
||||||
if (component is AssistantDropdown dropdown)
|
if (component is AssistantDropdown dropdown && !this.dropdownFields.ContainsKey(dropdown.Name))
|
||||||
{
|
this.dropdownFields.Add(dropdown.Name, dropdown.Default.Value);
|
||||||
prompt += $"{Environment.NewLine}context:{Environment.NewLine}{dropdown.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
|
|
||||||
if (this.dropdownFields.TryGetValue(dropdown.Name, out userInput))
|
|
||||||
{
|
|
||||||
prompt += $"user prompt:{Environment.NewLine}{userInput}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case AssistantComponentType.SWITCH:
|
case AssistantComponentType.SWITCH:
|
||||||
if (component is AssistantSwitch switchComponent)
|
if (component is AssistantSwitch switchComponent && !this.switchFields.ContainsKey(switchComponent.Name))
|
||||||
{
|
this.switchFields.Add(switchComponent.Name, switchComponent.Value);
|
||||||
prompt += $"{Environment.NewLine}context:{Environment.NewLine}{switchComponent.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
|
|
||||||
if (this.switchFields.TryGetValue(switchComponent.Name, out userDecision))
|
|
||||||
{
|
|
||||||
prompt += $"user decision:{Environment.NewLine}{userDecision}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case AssistantComponentType.WEB_CONTENT_READER:
|
case AssistantComponentType.WEB_CONTENT_READER:
|
||||||
if (component is AssistantWebContentReader webContent &&
|
if (component is AssistantWebContentReader webContent && !this.webContentFields.ContainsKey(webContent.Name))
|
||||||
this.webContentFields.TryGetValue(webContent.Name, out var webState))
|
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(webContent.UserPrompt))
|
this.webContentFields.Add(webContent.Name, new WebContentState
|
||||||
{
|
{
|
||||||
prompt += $"{Environment.NewLine}context:{Environment.NewLine}{webContent.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
|
Preselect = webContent.Preselect,
|
||||||
}
|
PreselectContentCleanerAgent = webContent.PreselectContentCleanerAgent,
|
||||||
|
});
|
||||||
if (!string.IsNullOrWhiteSpace(webState.Content))
|
|
||||||
{
|
|
||||||
prompt += $"user prompt:{Environment.NewLine}{webState.Content}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AssistantComponentType.FILE_CONTENT_READER:
|
case AssistantComponentType.FILE_CONTENT_READER:
|
||||||
if (component is AssistantFileContentReader fileContent &&
|
if (component is AssistantFileContentReader fileContent && !this.fileContentFields.ContainsKey(fileContent.Name))
|
||||||
this.fileContentFields.TryGetValue(fileContent.Name, out var fileState))
|
this.fileContentFields.Add(fileContent.Name, new FileContentState());
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(fileContent.UserPrompt))
|
|
||||||
{
|
|
||||||
prompt += $"{Environment.NewLine}context:{Environment.NewLine}{fileContent.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(fileState.Content))
|
|
||||||
{
|
|
||||||
prompt += $"user prompt:{Environment.NewLine}{fileState.Content}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case AssistantComponentType.COLOR_PICKER:
|
case AssistantComponentType.COLOR_PICKER:
|
||||||
if (component is AssistantColorPicker colorPicker)
|
if (component is AssistantColorPicker assistantColorPicker && !this.colorPickerFields.ContainsKey(assistantColorPicker.Name))
|
||||||
{
|
this.colorPickerFields.Add(assistantColorPicker.Name, assistantColorPicker.Placeholder);
|
||||||
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;
|
break;
|
||||||
default:
|
|
||||||
prompt += $"{userInput}{Environment.NewLine}";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return prompt;
|
if (component.Children.Count > 0)
|
||||||
|
this.InitializeComponentState(component.Children);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string MergeClass(string customClass, string fallback)
|
private static string MergeClass(string customClass, string fallback)
|
||||||
@ -571,4 +462,109 @@ public partial class AssistantDynamic : AssistantBaseCore<SettingsDialogDynamic>
|
|||||||
var time = this.AddUserRequest(await this.CollectUserPromptAsync());
|
var time = this.AddUserRequest(await this.CollectUserPromptAsync());
|
||||||
await this.AddAIResponseAsync(time);
|
await this.AddAIResponseAsync(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AddMetaEntries(LuaTable meta, IEnumerable<IAssistantComponent> components)
|
||||||
|
{
|
||||||
|
foreach (var component in components)
|
||||||
|
{
|
||||||
|
switch (component)
|
||||||
|
{
|
||||||
|
case AssistantTextArea textArea:
|
||||||
|
this.AddMetaEntry(meta, textArea.Name, component.Type, textArea.Label, textArea.UserPrompt);
|
||||||
|
break;
|
||||||
|
case AssistantDropdown dropdown:
|
||||||
|
this.AddMetaEntry(meta, dropdown.Name, component.Type, dropdown.Label, dropdown.UserPrompt);
|
||||||
|
break;
|
||||||
|
case AssistantSwitch switchComponent:
|
||||||
|
this.AddMetaEntry(meta, switchComponent.Name, component.Type, switchComponent.Label, switchComponent.UserPrompt);
|
||||||
|
break;
|
||||||
|
case AssistantWebContentReader webContent:
|
||||||
|
this.AddMetaEntry(meta, webContent.Name, component.Type, null, webContent.UserPrompt);
|
||||||
|
break;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.Children.Count > 0)
|
||||||
|
this.AddMetaEntries(meta, component.Children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string CollectUserPromptFallback(IEnumerable<IAssistantComponent> components)
|
||||||
|
{
|
||||||
|
var prompt = string.Empty;
|
||||||
|
|
||||||
|
foreach (var component in components)
|
||||||
|
{
|
||||||
|
var userInput = string.Empty;
|
||||||
|
var userDecision = false;
|
||||||
|
|
||||||
|
switch (component.Type)
|
||||||
|
{
|
||||||
|
case AssistantComponentType.TEXT_AREA:
|
||||||
|
if (component is AssistantTextArea textArea)
|
||||||
|
{
|
||||||
|
prompt += $"context:{Environment.NewLine}{textArea.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
|
||||||
|
if (this.inputFields.TryGetValue(textArea.Name, out userInput))
|
||||||
|
prompt += $"user prompt:{Environment.NewLine}{userInput}";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AssistantComponentType.DROPDOWN:
|
||||||
|
if (component is AssistantDropdown dropdown)
|
||||||
|
{
|
||||||
|
prompt += $"{Environment.NewLine}context:{Environment.NewLine}{dropdown.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
|
||||||
|
if (this.dropdownFields.TryGetValue(dropdown.Name, out userInput))
|
||||||
|
prompt += $"user prompt:{Environment.NewLine}{userInput}";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AssistantComponentType.SWITCH:
|
||||||
|
if (component is AssistantSwitch switchComponent)
|
||||||
|
{
|
||||||
|
prompt += $"{Environment.NewLine}context:{Environment.NewLine}{switchComponent.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
|
||||||
|
if (this.switchFields.TryGetValue(switchComponent.Name, out userDecision))
|
||||||
|
prompt += $"user decision:{Environment.NewLine}{userDecision}";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AssistantComponentType.WEB_CONTENT_READER:
|
||||||
|
if (component is AssistantWebContentReader webContent &&
|
||||||
|
this.webContentFields.TryGetValue(webContent.Name, out var webState))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(webContent.UserPrompt))
|
||||||
|
prompt += $"{Environment.NewLine}context:{Environment.NewLine}{webContent.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(webState.Content))
|
||||||
|
prompt += $"user prompt:{Environment.NewLine}{webState.Content}";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AssistantComponentType.FILE_CONTENT_READER:
|
||||||
|
if (component is AssistantFileContentReader fileContent &&
|
||||||
|
this.fileContentFields.TryGetValue(fileContent.Name, out var fileState))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(fileContent.UserPrompt))
|
||||||
|
prompt += $"{Environment.NewLine}context:{Environment.NewLine}{fileContent.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(fileState.Content))
|
||||||
|
prompt += $"user prompt:{Environment.NewLine}{fileState.Content}";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AssistantComponentType.COLOR_PICKER:
|
||||||
|
if (component is AssistantColorPicker colorPicker)
|
||||||
|
{
|
||||||
|
prompt += $"context:{Environment.NewLine}{colorPicker.UserPrompt}{Environment.NewLine}---{Environment.NewLine}";
|
||||||
|
if (this.colorPickerFields.TryGetValue(colorPicker.Name, out userInput))
|
||||||
|
prompt += $"user prompt:{Environment.NewLine}{userInput}";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.Children.Count > 0)
|
||||||
|
prompt += this.CollectUserPromptFallback(component.Children);
|
||||||
|
}
|
||||||
|
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,10 @@ Supported types (matching the Blazor UI components):
|
|||||||
- `DROPDOWN`: selects between variants; `Props` must include `Name`, `Label`, `Default`, `Items`, and optionally `ValueType` plus `UserPrompt`.
|
- `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`: 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`.
|
- `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`.
|
||||||
|
- `LAYOUT_GRID`: renders a `MudGrid`; `Children` must contain only `LAYOUT_ITEM` components and `Props` may include `Justify`, `Spacing`, `Class`, `Style`.
|
||||||
|
- `LAYOUT_ITEM`: renders a `MudItem`; use it inside `LAYOUT_GRID` and configure breakpoints with `Xs`, `Sm`, `Md`, `Lg`, `Xl`, `Xxl`, plus optional `Class`, `Style`.
|
||||||
|
- `LAYOUT_PAPER`: renders a `MudPaper`; may include `Elevation`, `Height`, `MaxHeight`, `MinHeight`, `Width`, `MaxWidth`, `MinWidth`, `IsOutlined`, `IsSquare`, `Class`, `Style`.
|
||||||
|
- `LAYOUT_STACK`: renders a `MudStack`; may include `IsRow`, `IsReverse`, `Breakpoint`, `Align`, `Justify`, `Stretch`, `Wrap`, `Spacing`, `Class`, `Style`.
|
||||||
- `SWITCH`: boolean option; requires `Name`, `Label`, `Value`, and may include `Disabled`, `UserPrompt`, `LabelOn`, `LabelOff`, `LabelPlacement`, `Icon`, `IconColor`, `CheckedColor`, `UncheckedColor`, `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`.
|
- `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.
|
- `PROVIDER_SELECTION` / `PROFILE_SELECTION`: hooks into the shared provider/profile selectors.
|
||||||
@ -24,7 +28,7 @@ Supported types (matching the Blazor UI components):
|
|||||||
Images referenced via the `plugin://` scheme must exist in the plugin directory (e.g., `assets/example.png`). Drop the file there and point `Src` at it. The component will read the file at runtime, encode it as Base64, and render it inside the assistant UI.
|
Images referenced via the `plugin://` scheme must exist in the plugin directory (e.g., `assets/example.png`). Drop the file there and point `Src` at it. The component will read the file at runtime, encode it as Base64, and render it inside the assistant UI.
|
||||||
|
|
||||||
## Prompt Assembly
|
## Prompt Assembly
|
||||||
Each component exposes a `UserPrompt` string. When the assistant runs, `AssistantDynamic` iterates over `RootComponent.Children` and, for each component that has a prompt, emits:
|
Each component exposes a `UserPrompt` string. When the assistant runs, `AssistantDynamic` recursively iterates over the component tree and, for each component that has a prompt, emits:
|
||||||
|
|
||||||
```
|
```
|
||||||
context:
|
context:
|
||||||
@ -280,6 +284,125 @@ Example:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `LAYOUT_GRID` reference
|
||||||
|
- Use `Type = "LAYOUT_GRID"` to render a MudBlazor grid container.
|
||||||
|
- Required props:
|
||||||
|
- `Name`: unique identifier for the layout node.
|
||||||
|
- Required structure:
|
||||||
|
- `Children`: array of `LAYOUT_ITEM` component tables. Other child component types are ignored.
|
||||||
|
- Optional props:
|
||||||
|
- `Justify`: one of the MudBlazor `Justify` enum names such as `FlexStart`, `Center`, `SpaceBetween`; omitted values fall back to `FlexStart`.
|
||||||
|
- `Spacing`: integer spacing between grid items; omitted values fall back to `6`.
|
||||||
|
- `Class`, `Style`: forwarded to the rendered `MudGrid` for layout/styling.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
["Type"] = "LAYOUT_GRID",
|
||||||
|
["Props"] = {
|
||||||
|
["Name"] = "mainGrid",
|
||||||
|
["Justify"] = "FlexStart",
|
||||||
|
["Spacing"] = 2
|
||||||
|
},
|
||||||
|
["Children"] = {
|
||||||
|
{
|
||||||
|
["Type"] = "LAYOUT_ITEM",
|
||||||
|
["Props"] = {
|
||||||
|
["Name"] = "leftItem",
|
||||||
|
["Xs"] = 12,
|
||||||
|
["Md"] = 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
["Type"] = "LAYOUT_ITEM",
|
||||||
|
["Props"] = {
|
||||||
|
["Name"] = "rightItem",
|
||||||
|
["Xs"] = 12,
|
||||||
|
["Md"] = 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `LAYOUT_ITEM` reference
|
||||||
|
- Use `Type = "LAYOUT_ITEM"` to render a MudBlazor grid item.
|
||||||
|
- Required props:
|
||||||
|
- `Name`: unique identifier for the layout node.
|
||||||
|
- Intended parent:
|
||||||
|
- Use this component inside `LAYOUT_GRID`.
|
||||||
|
- Optional props:
|
||||||
|
- `Xs`, `Sm`, `Md`, `Lg`, `Xl`, `Xxl`: integer breakpoint widths. Omit a breakpoint to leave it unset.
|
||||||
|
- `Class`, `Style`: forwarded to the rendered `MudItem` for layout/styling.
|
||||||
|
- `Children` may contain any other assistant components you want to place inside the item.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
["Type"] = "LAYOUT_ITEM",
|
||||||
|
["Props"] = {
|
||||||
|
["Name"] = "contentColumn",
|
||||||
|
["Xs"] = 12,
|
||||||
|
["Lg"] = 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `LAYOUT_PAPER` reference
|
||||||
|
- Use `Type = "LAYOUT_PAPER"` to render a MudBlazor paper container.
|
||||||
|
- Required props:
|
||||||
|
- `Name`: unique identifier for the layout node.
|
||||||
|
- Optional props:
|
||||||
|
- `Elevation`: integer elevation; omitted values fall back to `1`.
|
||||||
|
- `Height`, `MaxHeight`, `MinHeight`, `Width`, `MaxWidth`, `MinWidth`: CSS size values such as `100%`, `24rem`, `50vh`.
|
||||||
|
- `IsOutlined`: defaults to `false`; toggles outlined mode.
|
||||||
|
- `IsSquare`: defaults to `false`; removes rounded corners.
|
||||||
|
- `Class`, `Style`: forwarded to the rendered `MudPaper` for layout/styling.
|
||||||
|
- `Children` may contain any other assistant components you want to wrap.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
["Type"] = "LAYOUT_PAPER",
|
||||||
|
["Props"] = {
|
||||||
|
["Name"] = "contentPaper",
|
||||||
|
["Elevation"] = 2,
|
||||||
|
["Width"] = "100%",
|
||||||
|
["IsOutlined"] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `LAYOUT_STACK` reference
|
||||||
|
- Use `Type = "LAYOUT_STACK"` to render a MudBlazor stack layout.
|
||||||
|
- Required props:
|
||||||
|
- `Name`: unique identifier for the layout node.
|
||||||
|
- Optional props:
|
||||||
|
- `IsRow`: defaults to `false`; renders items horizontally.
|
||||||
|
- `IsReverse`: defaults to `false`; reverses the visual order.
|
||||||
|
- `Breakpoint`: one of the MudBlazor `Breakpoint` enum names such as `Sm`, `Md`, `Lg`; omitted values fall back to `None`.
|
||||||
|
- `Align`: one of the MudBlazor `AlignItems` enum names such as `Start`, `Center`, `Stretch`; omitted values fall back to `Stretch`.
|
||||||
|
- `Justify`: one of the MudBlazor `Justify` enum names such as `FlexStart`, `Center`, `SpaceBetween`; omitted values fall back to `FlexStart`.
|
||||||
|
- `Stretch`: one of the MudBlazor `StretchItems` enum names such as `None`, `Start`, `End`, `Stretch`; omitted values fall back to `None`.
|
||||||
|
- `Wrap`: one of the MudBlazor `Wrap` enum names such as `Wrap`, `NoWrap`, `WrapReverse`; omitted values fall back to `Wrap`.
|
||||||
|
- `Spacing`: integer spacing between child components; omitted values fall back to `3`.
|
||||||
|
- `Class`, `Style`: forwarded to the rendered `MudStack` for layout/styling.
|
||||||
|
- `Children` may contain any other assistant components you want to arrange.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
["Type"] = "LAYOUT_STACK",
|
||||||
|
["Props"] = {
|
||||||
|
["Name"] = "toolbarRow",
|
||||||
|
["IsRow"] = true,
|
||||||
|
["Align"] = "Center",
|
||||||
|
["Justify"] = "SpaceBetween",
|
||||||
|
["Spacing"] = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### `SWITCH` reference
|
### `SWITCH` reference
|
||||||
- Use `Type = "SWITCH"` to render a boolean toggle.
|
- Use `Type = "SWITCH"` to render a boolean toggle.
|
||||||
- Required props:
|
- Required props:
|
||||||
|
|||||||
@ -168,6 +168,48 @@ ASSISTANT = {
|
|||||||
-- BUTTON_ELEMENTS
|
-- BUTTON_ELEMENTS
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
["Type"] = "LAYOUT_STACK",
|
||||||
|
["Props"] = {
|
||||||
|
["Name"] = "exampleStack",
|
||||||
|
["IsRow"] = true,
|
||||||
|
["Align"] = "Center",
|
||||||
|
["Justify"] = "SpaceBetween",
|
||||||
|
["Wrap"] = "Wrap",
|
||||||
|
["Spacing"] = 2,
|
||||||
|
["Class"] = "<optional MudBlazor or css classes>",
|
||||||
|
["Style"] = "<optional css styles>",
|
||||||
|
},
|
||||||
|
["Children"] = {
|
||||||
|
-- CHILDREN
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
["Type"] = "LAYOUT_PAPER",
|
||||||
|
["Props"] = {
|
||||||
|
["Name"] = "examplePaper",
|
||||||
|
["Elevation"] = 2,
|
||||||
|
["Width"] = "100%",
|
||||||
|
["Class"] = "pa-4 mb-3",
|
||||||
|
["Style"] = "<optional css styles>",
|
||||||
|
},
|
||||||
|
["Children"] = {
|
||||||
|
-- CHILDREN
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
["Type"] = "LAYOUT_GRID",
|
||||||
|
["Props"] = {
|
||||||
|
["Name"] = "exampleGrid",
|
||||||
|
["Justify"] = "FlexStart",
|
||||||
|
["Spacing"] = 2,
|
||||||
|
["Class"] = "<optional MudBlazor or css classes>",
|
||||||
|
["Style"] = "<optional css styles>",
|
||||||
|
},
|
||||||
|
["Children"] = {
|
||||||
|
-- CHILDREN
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
["Type"] = "PROVIDER_SELECTION", -- required
|
["Type"] = "PROVIDER_SELECTION", -- required
|
||||||
["Props"] = {
|
["Props"] = {
|
||||||
|
|||||||
@ -89,7 +89,7 @@ public static class ComponentPropSpecs
|
|||||||
[AssistantComponentType.LAYOUT_PAPER] = new(
|
[AssistantComponentType.LAYOUT_PAPER] = new(
|
||||||
required: ["Name"],
|
required: ["Name"],
|
||||||
optional: [
|
optional: [
|
||||||
"Height", "MaxHeight", "MinHeight", "Width", "MaxWidth", "MinWidth",
|
"Elevation", "Height", "MaxHeight", "MinHeight", "Width", "MaxWidth", "MinWidth",
|
||||||
"IsOutlined", "IsSquare", "Class", "Style"
|
"IsOutlined", "IsSquare", "Class", "Style"
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using AIStudio.Tools.PluginSystem.Assistants.DataModel;
|
using AIStudio.Tools.PluginSystem.Assistants.DataModel;
|
||||||
|
using AIStudio.Tools.PluginSystem.Assistants.DataModel.Layout;
|
||||||
using Lua;
|
using Lua;
|
||||||
|
|
||||||
namespace AIStudio.Tools.PluginSystem.Assistants;
|
namespace AIStudio.Tools.PluginSystem.Assistants;
|
||||||
@ -298,6 +299,16 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (component is AssistantGrid grid)
|
||||||
|
{
|
||||||
|
var invalidChildren = grid.Children.Where(child => child.Type != AssistantComponentType.LAYOUT_ITEM).ToList();
|
||||||
|
if (invalidChildren.Count > 0)
|
||||||
|
{
|
||||||
|
LOGGER.LogWarning("Assistant plugin '{PluginName}' LAYOUT_GRID contains non-LAYOUT_ITEM children. Only LAYOUT_ITEM children are supported and invalid children are ignored.", this.Name);
|
||||||
|
grid.Children = grid.Children.Where(child => child.Type == AssistantComponentType.LAYOUT_ITEM).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user