mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-13 04:13:48 +00:00
Added simple assistant plugin example (#734)
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,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,deb,updater, appimage,deb) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,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,deb,updater, appimage,deb) (push) Blocked by required conditions
Build and Release / Publish release (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,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,deb,updater, appimage,deb) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,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,deb,updater, appimage,deb) (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
This commit is contained in:
1 parent
da62814b2f
commit
e5d8ac4a71
13 files changed
+423
-24
No files matched your search
@@ -121,6 +121,26 @@ internal sealed class AssistantDropdown : StatefulAssistantComponentBase
|
||||
|
||||
#endregion
|
||||
|
||||
internal string ResolveDisplayText(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
return this.Default.Display;
|
||||
|
||||
var item = this.GetRenderedItems().FirstOrDefault(item => string.Equals(item.Value, value, StringComparison.Ordinal));
|
||||
return item?.Display ?? value;
|
||||
}
|
||||
|
||||
private List<AssistantDropdownItem> GetRenderedItems()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(this.Default.Value))
|
||||
return this.Items;
|
||||
|
||||
if (this.Items.Any(item => string.Equals(item.Value, this.Default.Value, StringComparison.Ordinal)))
|
||||
return this.Items;
|
||||
|
||||
return [this.Default, .. this.Items];
|
||||
}
|
||||
|
||||
public IEnumerable<object> GetParsedDropdownValues()
|
||||
{
|
||||
foreach (var item in this.Items)
|
||||
|
||||
+48
@@ -10,6 +10,11 @@ internal static class AssistantLuaConversion
|
||||
/// </summary>
|
||||
public static LuaTable CreateLuaArray(IEnumerable values) => CreateLuaArrayCore(values);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a readable string representation of a Lua table for debugging and inspection.
|
||||
/// </summary>
|
||||
public static string InspectTable(LuaTable table) => InspectTableCore(table, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Reads a Lua value into either a scalar .NET value or one of the structured assistant data model types.
|
||||
/// Lua itself only exposes scalars and tables, so structured assistant types such as dropdown/list items
|
||||
@@ -268,4 +273,47 @@ internal static class AssistantLuaConversion
|
||||
|
||||
return luaArray;
|
||||
}
|
||||
|
||||
private static string InspectTableCore(LuaTable table, int depth)
|
||||
{
|
||||
if (depth > 8)
|
||||
return "{ ... }";
|
||||
|
||||
var indent = new string(' ', depth * 2);
|
||||
var childIndent = new string(' ', (depth + 1) * 2);
|
||||
var builder = new System.Text.StringBuilder();
|
||||
builder.AppendLine("{");
|
||||
|
||||
foreach (var entry in table)
|
||||
{
|
||||
builder.Append(childIndent);
|
||||
builder.Append(FormatLuaValue(entry.Key));
|
||||
builder.Append(" = ");
|
||||
builder.AppendLine(FormatLuaValue(entry.Value, depth + 1));
|
||||
}
|
||||
|
||||
builder.Append(indent);
|
||||
builder.Append('}');
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private static string FormatLuaValue(LuaValue value, int depth = 0)
|
||||
{
|
||||
if (value.Type is LuaValueType.Nil)
|
||||
return "nil";
|
||||
|
||||
if (value.TryRead<string>(out var stringValue))
|
||||
return $"\"{stringValue.Replace("\\", "\\\\").Replace("\"", "\\\"")}\"";
|
||||
|
||||
if (value.TryRead<bool>(out var boolValue))
|
||||
return boolValue ? "true" : "false";
|
||||
|
||||
if (value.TryRead<double>(out var doubleValue))
|
||||
return doubleValue.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||
|
||||
if (value.TryRead<LuaTable>(out var tableValue))
|
||||
return InspectTableCore(tableValue, depth);
|
||||
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
@@ -156,12 +156,17 @@ public sealed class AssistantState
|
||||
{
|
||||
if (component is INamedAssistantComponent named)
|
||||
{
|
||||
target[named.Name] = new LuaTable
|
||||
var componentEntry = new LuaTable
|
||||
{
|
||||
["Type"] = Enum.GetName(component.Type) ?? string.Empty,
|
||||
["Value"] = component is IStatefulAssistantComponent ? this.ReadValueForLua(named.Name) : LuaValue.Nil,
|
||||
["Props"] = this.CreatePropsTable(component),
|
||||
};
|
||||
|
||||
if (component is AssistantDropdown dropdown)
|
||||
this.AddDropdownDisplay(componentEntry, dropdown, named.Name);
|
||||
|
||||
target[named.Name] = componentEntry;
|
||||
}
|
||||
|
||||
if (component.Children.Count > 0)
|
||||
@@ -218,6 +223,27 @@ public sealed class AssistantState
|
||||
return table;
|
||||
}
|
||||
|
||||
private void AddDropdownDisplay(LuaTable componentEntry, AssistantDropdown dropdown, string name)
|
||||
{
|
||||
if (dropdown.IsMultiselect)
|
||||
{
|
||||
if (!this.MultiSelect.TryGetValue(name, out var selectedValues))
|
||||
return;
|
||||
|
||||
componentEntry["Display"] = AssistantLuaConversion.CreateLuaArray(
|
||||
selectedValues
|
||||
.OrderBy(static value => value, StringComparer.Ordinal)
|
||||
.Select(dropdown.ResolveDisplayText));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.SingleSelect.TryGetValue(name, out var selectedValue))
|
||||
return;
|
||||
|
||||
componentEntry["Display"] = dropdown.ResolveDisplayText(selectedValue);
|
||||
}
|
||||
|
||||
private static HashSet<string> ReadStringValues(LuaTable values)
|
||||
{
|
||||
var parsedValues = new HashSet<string>(StringComparer.Ordinal);
|
||||
|
||||
+29
-19
@@ -73,6 +73,8 @@ public static class PluginAssistantSecurityResolver
|
||||
public static PluginAssistantSecurityState Resolve(SettingsManager settingsManager, PluginAssistants plugin)
|
||||
{
|
||||
var auditSettings = settingsManager.ConfigurationData.AssistantPluginAudit;
|
||||
var enforceAuditBeforeActivation = auditSettings.RequireAuditBeforeActivation;
|
||||
var isEnforcementDisabled = !enforceAuditBeforeActivation;
|
||||
var currentHash = plugin.ComputeAuditHash();
|
||||
var audit = settingsManager.ConfigurationData.AssistantPluginAudits.FirstOrDefault(x => x.PluginId == plugin.Id);
|
||||
var hasAudit = audit is not null && audit.Level is not AssistantAuditLevel.UNKNOWN;
|
||||
@@ -80,9 +82,9 @@ public static class PluginAssistantSecurityResolver
|
||||
var hasHashMismatch = hasAudit && !hashMatches;
|
||||
var isBelowMinimum = hashMatches && audit is not null && audit.Level < auditSettings.MinimumLevel;
|
||||
var meetsMinimum = hashMatches && audit is not null && audit.Level >= auditSettings.MinimumLevel;
|
||||
var requiresAudit = hasHashMismatch || auditSettings.RequireAuditBeforeActivation && !hasAudit;
|
||||
var isBlocked = requiresAudit || isBelowMinimum && auditSettings.BlockActivationBelowMinimum;
|
||||
var canOverride = isBelowMinimum && !auditSettings.BlockActivationBelowMinimum;
|
||||
var requiresAudit = enforceAuditBeforeActivation && (hasHashMismatch || !hasAudit);
|
||||
var isBlocked = requiresAudit || enforceAuditBeforeActivation && isBelowMinimum && auditSettings.BlockActivationBelowMinimum;
|
||||
var canOverride = isBelowMinimum && (!auditSettings.BlockActivationBelowMinimum || isEnforcementDisabled);
|
||||
var canUsePlugin = !isBlocked;
|
||||
|
||||
if (!hasAudit)
|
||||
@@ -132,30 +134,32 @@ public static class PluginAssistantSecurityResolver
|
||||
HasHashMismatch = true,
|
||||
IsBelowMinimum = false,
|
||||
MeetsMinimumLevel = false,
|
||||
RequiresAudit = true,
|
||||
IsBlocked = true,
|
||||
RequiresAudit = requiresAudit,
|
||||
IsBlocked = isBlocked,
|
||||
CanOverride = false,
|
||||
CanActivatePlugin = false,
|
||||
CanStartAssistant = false,
|
||||
CanActivatePlugin = !isBlocked,
|
||||
CanStartAssistant = !isBlocked,
|
||||
AuditLabel = TB("Unknown"),
|
||||
AuditColor = AssistantAuditLevel.UNKNOWN.GetColor(),
|
||||
AuditIcon = AssistantAuditLevel.UNKNOWN.GetIcon(),
|
||||
AvailabilityLabel = GetAvailabilityLabel(requiresAudit: true, hasAudit, hasHashMismatch, isBlocked: true, canOverride: false),
|
||||
AvailabilityColor = GetAvailabilityColor(requiresAudit: true, hasAudit, hasHashMismatch, isBlocked: true, canOverride: false),
|
||||
AvailabilityIcon = GetAvailabilityIcon(requiresAudit: true, hasAudit, hasHashMismatch, isBlocked: true, canOverride: false),
|
||||
StatusLabel = GetAvailabilityLabel(requiresAudit: true, hasAudit, hasHashMismatch, isBlocked: true, canOverride: false),
|
||||
BadgeIcon = GetSecurityBadgeIcon(requiresAudit: true, hasAudit, hasHashMismatch, isBlocked: true, canOverride: false),
|
||||
Headline = TB("This assistant is locked until it is audited again."),
|
||||
Description = TB("The plugin code changed after the last security audit. The stored result no longer matches the current code, so this assistant plugin must be audited again before it may be enabled or used."),
|
||||
StatusColor = GetAvailabilityColor(requiresAudit: true, hasAudit, hasHashMismatch, isBlocked: true, canOverride: false),
|
||||
StatusIcon = GetAvailabilityIcon(requiresAudit: true, hasAudit, hasHashMismatch, isBlocked: true, canOverride: false),
|
||||
AvailabilityLabel = GetAvailabilityLabel(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false),
|
||||
AvailabilityColor = GetAvailabilityColor(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false),
|
||||
AvailabilityIcon = GetAvailabilityIcon(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false),
|
||||
StatusLabel = GetAvailabilityLabel(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false),
|
||||
BadgeIcon = GetSecurityBadgeIcon(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false),
|
||||
Headline = requiresAudit ? TB("This assistant is locked until it is audited again.") : TB("This assistant changed after its last audit."),
|
||||
Description = requiresAudit
|
||||
? TB("The plugin code changed after the last security audit. The stored result no longer matches the current code, so this assistant plugin must be audited again before it may be enabled or used.")
|
||||
: TB("The plugin code changed after the last security audit. Audit enforcement is currently disabled, so this assistant plugin can still be enabled or used."),
|
||||
StatusColor = GetAvailabilityColor(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false),
|
||||
StatusIcon = GetAvailabilityIcon(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false),
|
||||
ActionLabel = TB("Run Security Check Again"),
|
||||
};
|
||||
}
|
||||
|
||||
if (isBelowMinimum)
|
||||
{
|
||||
var isBlockedByMinimum = auditSettings.BlockActivationBelowMinimum;
|
||||
var isBlockedByMinimum = enforceAuditBeforeActivation && auditSettings.BlockActivationBelowMinimum;
|
||||
var auditLevel = audit!.Level;
|
||||
|
||||
return new PluginAssistantSecurityState
|
||||
@@ -181,10 +185,16 @@ public static class PluginAssistantSecurityResolver
|
||||
AvailabilityIcon = GetAvailabilityIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
||||
StatusLabel = GetAvailabilityLabel(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
||||
BadgeIcon = GetSecurityBadgeIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
||||
Headline = isBlockedByMinimum ? TB("This assistant is currently locked.") : TB("This assistant can still be used because your settings allow it."),
|
||||
Headline = isBlockedByMinimum
|
||||
? TB("This assistant is currently locked.")
|
||||
: isEnforcementDisabled
|
||||
? TB("This assistant can still be used because audit enforcement is disabled.")
|
||||
: TB("This assistant can still be used because your settings allow it."),
|
||||
Description = isBlockedByMinimum
|
||||
? string.Format(TB("The current audit result '{0}' is below your required minimum level '{1}'. Your security settings therefore block this assistant plugin."), auditLevel.GetName(), auditSettings.MinimumLevel.GetName())
|
||||
: string.Format(TB("The current audit result is '{0}', which is below your required minimum level '{1}'. Your settings still allow manual activation, but the assistant keeps this security status and should be reviewed carefully."), auditLevel.GetName(), auditSettings.MinimumLevel.GetName()),
|
||||
: isEnforcementDisabled
|
||||
? string.Format(TB("The current audit result is '{0}', which is below your required minimum level '{1}'. Audit enforcement is currently disabled, so this assistant plugin can still be enabled or used."), auditLevel.GetName(), auditSettings.MinimumLevel.GetName())
|
||||
: string.Format(TB("The current audit result is '{0}', which is below your required minimum level '{1}'. Your settings still allow manual activation, but the assistant keeps this security status and should be reviewed carefully."), auditLevel.GetName(), auditSettings.MinimumLevel.GetName()),
|
||||
StatusColor = GetAvailabilityColor(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
||||
StatusIcon = GetAvailabilityIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
||||
ActionLabel = TB("Open Security Check"),
|
||||
|
||||
@@ -497,7 +497,6 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
|
||||
|
||||
private void RegisterLuaHelpers()
|
||||
{
|
||||
|
||||
this.State.Environment["LogInfo"] = new LuaFunction((context, _) =>
|
||||
{
|
||||
if (context.ArgumentCount == 0) return new(0);
|
||||
@@ -559,6 +558,15 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
|
||||
var timestamp = DateTime.UtcNow.ToString("o");
|
||||
return new(context.Return(timestamp));
|
||||
});
|
||||
|
||||
this.State.Environment["InspectTable"] = new LuaFunction((context, _) =>
|
||||
{
|
||||
if (context.ArgumentCount == 0)
|
||||
return new(context.Return("{}"));
|
||||
|
||||
var table = context.GetArgument<LuaTable>(0);
|
||||
return new(context.Return(AssistantLuaConversion.InspectTable(table)));
|
||||
});
|
||||
}
|
||||
|
||||
private static void InitializeState(IEnumerable<IAssistantComponent> components, AssistantState state)
|
||||
|
||||
Reference in new issue
Block a user