Fixed invisible file attachments in assistant plugins & allow file attachment component (#877)
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions

Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
nilskruthoffandThorsten Sommer authored and GitHub committed 2026-07-21 10:05:43 +02:00
1 parent f13c35d814
commit 7595def8f3
20 files changed
+312 -29

No files matched your search

@@ -40,6 +40,8 @@ public class AssistantComponentFactory
return new AssistantWebContentReader { Props = props, Children = children };
case AssistantComponentType.FILE_CONTENT_READER:
return new AssistantFileContentReader { Props = props, Children = children };
case AssistantComponentType.FILE_ATTACHMENTS:
return new AssistantFileAttachment { Props = props, Children = children };
case AssistantComponentType.IMAGE:
return new AssistantImage { Props = props, Children = children };
case AssistantComponentType.COLOR_PICKER:
@@ -15,6 +15,7 @@ public enum AssistantComponentType
LIST,
WEB_CONTENT_READER,
FILE_CONTENT_READER,
FILE_ATTACHMENTS,
IMAGE,
COLOR_PICKER,
DATE_PICKER,
@@ -19,6 +19,7 @@ public static class AssistantComponentTypeExtensions
AssistantComponentType.LIST => TB("List"),
AssistantComponentType.WEB_CONTENT_READER => TB("Web Content Reader"),
AssistantComponentType.FILE_CONTENT_READER => TB("File Content Reader"),
AssistantComponentType.FILE_ATTACHMENTS => TB("File Attachments"),
AssistantComponentType.IMAGE => TB("Image"),
AssistantComponentType.COLOR_PICKER => TB("Color Selection"),
AssistantComponentType.DATE_PICKER => TB("Date Selection"),
@@ -47,6 +48,7 @@ public static class AssistantComponentTypeExtensions
AssistantComponentType.LIST => MudBlazor.Icons.Material.Filled.List,
AssistantComponentType.WEB_CONTENT_READER => MudBlazor.Icons.Material.Filled.Public,
AssistantComponentType.FILE_CONTENT_READER => MudBlazor.Icons.Material.Filled.AttachFile,
AssistantComponentType.FILE_ATTACHMENTS => MudBlazor.Icons.Material.Filled.AttachFile,
AssistantComponentType.IMAGE => MudBlazor.Icons.Material.Filled.Image,
AssistantComponentType.COLOR_PICKER => MudBlazor.Icons.Material.Filled.Palette,
AssistantComponentType.DATE_PICKER => MudBlazor.Icons.Material.Filled.CalendarMonth,
@@ -61,4 +63,4 @@ public static class AssistantComponentTypeExtensions
AssistantComponentType.FORM => MudBlazor.Icons.Material.Filled.AccountTree,
_ => MudBlazor.Icons.Material.Filled.AccountTree,
};
}
}
@@ -0,0 +1,66 @@
using System.Text;
using AIStudio.Assistants.Dynamic;
namespace AIStudio.Tools.PluginSystem.Assistants.DataModel;
internal sealed class AssistantFileAttachment : StatefulAssistantComponentBase
{
public override AssistantComponentType Type => AssistantComponentType.FILE_ATTACHMENTS;
public override Dictionary<string, object> Props { get; set; } = new();
public override List<IAssistantComponent> Children { get; set; } = new();
public string Heading
{
get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Heading));
set => AssistantComponentPropHelper.WriteString(this.Props, nameof(this.Heading), value);
}
public bool CatchAllDocuments
{
get => AssistantComponentPropHelper.ReadBool(this.Props, nameof(this.CatchAllDocuments), true);
set => AssistantComponentPropHelper.WriteBool(this.Props, nameof(this.CatchAllDocuments), value);
}
public bool UseSmallForm
{
get => AssistantComponentPropHelper.ReadBool(this.Props, nameof(this.UseSmallForm));
set => AssistantComponentPropHelper.WriteBool(this.Props, nameof(this.UseSmallForm), 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);
}
#region Implementation of IStatefulAssistantComponent
public override void InitializeState(AssistantState state)
{
if (!state.FileAttachments.ContainsKey(this.Name))
state.FileAttachments[this.Name] = new FileAttachmentState();
}
public override string UserPromptFallback(AssistantState state)
{
state.FileAttachments.TryGetValue(this.Name, out var fileState);
if (fileState == null || fileState.DocumentPaths.Count == 0)
return this.BuildAuditPromptBlock(null);
var builder = new StringBuilder();
foreach (var attachment in fileState.DocumentPaths.OrderBy(static attachment => attachment.FilePath, StringComparer.Ordinal))
builder.AppendLine(attachment.FilePath);
return this.BuildAuditPromptBlock(builder.ToString());
}
#endregion
}
@@ -8,6 +8,12 @@ internal sealed class AssistantFileContentReader : StatefulAssistantComponentBas
public override Dictionary<string, object> Props { get; set; } = new();
public override List<IAssistantComponent> Children { get; set; } = new();
public bool ShowAttachedDocumentState
{
get => AssistantComponentPropHelper.ReadBool(this.Props, nameof(this.ShowAttachedDocumentState), true);
set => AssistantComponentPropHelper.WriteBool(this.Props, nameof(this.ShowAttachedDocumentState), value);
}
public string Class
{
get => AssistantComponentPropHelper.ReadString(this.Props, nameof(this.Class));
@@ -1,4 +1,5 @@
using AIStudio.Assistants.Dynamic;
using AIStudio.Chat;
using Lua;
namespace AIStudio.Tools.PluginSystem.Assistants.DataModel;
@@ -11,6 +12,7 @@ public sealed class AssistantState
public readonly Dictionary<string, bool> Booleans = new(StringComparer.Ordinal);
public readonly Dictionary<string, WebContentState> WebContent = new(StringComparer.Ordinal);
public readonly Dictionary<string, FileContentState> FileContent = new(StringComparer.Ordinal);
public readonly Dictionary<string, FileAttachmentState> FileAttachments = new(StringComparer.Ordinal);
public readonly Dictionary<string, string> Colors = new(StringComparer.Ordinal);
public readonly Dictionary<string, string> Dates = new(StringComparer.Ordinal);
public readonly Dictionary<string, string> DateRanges = new(StringComparer.Ordinal);
@@ -24,6 +26,7 @@ public sealed class AssistantState
this.Booleans.Clear();
this.WebContent.Clear();
this.FileContent.Clear();
this.FileAttachments.Clear();
this.Colors.Clear();
this.Dates.Clear();
this.DateRanges.Clear();
@@ -43,6 +46,7 @@ public sealed class AssistantState
CopyDictionary(other.Booleans, this.Booleans);
CopyDictionary(other.WebContent, this.WebContent);
CopyDictionary(other.FileContent, this.FileContent);
CopyDictionary(other.FileAttachments, this.FileAttachments);
CopyDictionary(other.Colors, this.Colors);
CopyDictionary(other.Dates, this.Dates);
CopyDictionary(other.DateRanges, this.DateRanges);
@@ -143,6 +147,22 @@ public sealed class AssistantState
return true;
}
if (this.FileAttachments.TryGetValue(fieldName, out var fileAttachmentState))
{
expectedType = "string[]";
if (value.TryRead<LuaTable>(out var fileAttachmentTable))
{
fileAttachmentState.DocumentPaths = ReadFileAttachmentValues(fileAttachmentTable);
return true;
}
if (!value.TryRead<string>(out var fileAttachmentValue))
return false;
fileAttachmentState.DocumentPaths = string.IsNullOrWhiteSpace(fileAttachmentValue) ? [] : [FileAttachment.FromPath(fileAttachmentValue)];
return true;
}
if (this.Colors.ContainsKey(fieldName))
{
expectedType = "string";
@@ -231,6 +251,11 @@ public sealed class AssistantState
return webContentValue.Content;
if (this.FileContent.TryGetValue(name, out var fileContentValue))
return fileContentValue.Content;
if (this.FileAttachments.TryGetValue(name, out var fileAttachmentsValue))
return AssistantLuaConversion.CreateLuaArray(
fileAttachmentsValue.DocumentPaths
.OrderBy(static attachment => attachment.FilePath, StringComparer.Ordinal)
.Select(static attachment => attachment.FilePath));
if (this.Colors.TryGetValue(name, out var colorValue))
return colorValue;
if (this.Dates.TryGetValue(name, out var dateValue))
@@ -299,4 +324,17 @@ public sealed class AssistantState
return parsedValues;
}
private static HashSet<FileAttachment> ReadFileAttachmentValues(LuaTable values)
{
var parsedValues = new HashSet<FileAttachment>();
foreach (var entry in values)
{
if (entry.Value.TryRead<string>(out var value) && !string.IsNullOrWhiteSpace(value))
parsedValues.Add(FileAttachment.FromPath(value));
}
return parsedValues;
}
}
@@ -82,7 +82,12 @@ public static class ComponentPropSpecs
),
[AssistantComponentType.FILE_CONTENT_READER] = new(
required: ["Name"],
optional: ["UserPrompt", "Class", "Style"],
optional: ["UserPrompt", "ShowAttachedDocumentState", "Class", "Style"],
nonWriteable: ["Name", "UserPrompt", "ShowAttachedDocumentState", "Class", "Style" ]
),
[AssistantComponentType.FILE_ATTACHMENTS] = new(
required: ["Name"],
optional: ["Heading", "UserPrompt", "CatchAllDocuments", "UseSmallForm", "Class", "Style"],
nonWriteable: ["Name", "UserPrompt", "Class", "Style" ]
),
[AssistantComponentType.IMAGE] = new(