2025-04-12 19:13:33 +00:00
using AIStudio.Components ;
2026-04-09 08:01:24 +00:00
using AIStudio.Agents.AssistantAudit ;
using AIStudio.Dialogs ;
using AIStudio.Settings.DataModel ;
using AIStudio.Tools.PluginSystem.Assistants ;
2025-03-29 17:40:17 +00:00
using AIStudio.Tools.PluginSystem ;
2025-04-24 11:50:14 +00:00
using Microsoft.AspNetCore.Components ;
2026-04-09 08:01:24 +00:00
using DialogOptions = AIStudio . Dialogs . DialogOptions ;
2025-04-24 11:50:14 +00:00
2025-03-29 17:40:17 +00:00
namespace AIStudio.Pages ;
2025-04-12 19:13:33 +00:00
public partial class Plugins : MSGComponentBase
2025-03-29 17:40:17 +00:00
{
private const string GROUP_ENABLED = "Enabled" ;
private const string GROUP_DISABLED = "Disabled" ;
private const string GROUP_INTERNAL = "Internal" ;
2026-04-09 08:01:24 +00:00
private bool isAutoAuditing ;
private DataAssistantPluginAudit AssistantPluginAuditSettings = > this . SettingsManager . ConfigurationData . AssistantPluginAudit ;
2025-03-29 17:40:17 +00:00
private TableGroupDefinition < IPluginMetadata > groupConfig = null ! ;
2026-04-09 08:01:24 +00:00
[Inject]
private IDialogService DialogService { get ; init ; } = null ! ;
[Inject]
private AssistantPluginAuditService AssistantPluginAuditService { get ; init ; } = null ! ;
2025-03-29 17:40:17 +00:00
#region Overrides of ComponentBase
protected override async Task OnInitializedAsync ( )
{
2025-04-24 11:50:14 +00:00
this . ApplyFilters ( [ ] , [ Event . PLUGINS_RELOADED ] ) ;
2025-03-30 18:34:30 +00:00
2025-03-29 17:40:17 +00:00
this . groupConfig = new TableGroupDefinition < IPluginMetadata >
{
Expandable = true ,
IsInitiallyExpanded = true ,
Selector = pluginMeta = >
{
if ( pluginMeta . IsInternal )
return GROUP_INTERNAL ;
return this . SettingsManager . IsPluginEnabled ( pluginMeta )
? GROUP_ENABLED
: GROUP_DISABLED ;
}
} ;
await base . OnInitializedAsync ( ) ;
}
2026-04-09 08:01:24 +00:00
protected override async Task OnAfterRenderAsync ( bool firstRender )
{
if ( firstRender )
await this . TryAutoAuditAssistantsAsync ( ) ;
}
2025-03-29 17:40:17 +00:00
#endregion
2025-04-12 19:13:33 +00:00
2025-03-29 17:40:17 +00:00
private async Task PluginActivationStateChanged ( IPluginMetadata pluginMeta )
{
if ( this . SettingsManager . IsPluginEnabled ( pluginMeta ) )
2026-04-09 08:01:24 +00:00
{
2025-03-29 17:40:17 +00:00
this . SettingsManager . ConfigurationData . EnabledPlugins . Remove ( pluginMeta . Id ) ;
2026-04-09 08:01:24 +00:00
await this . SettingsManager . StoreSettings ( ) ;
await this . MessageBus . SendMessage < bool > ( this , Event . CONFIGURATION_CHANGED ) ;
return ;
}
if ( pluginMeta . Type is not PluginType . ASSISTANT )
{
2025-03-29 17:40:17 +00:00
this . SettingsManager . ConfigurationData . EnabledPlugins . Add ( pluginMeta . Id ) ;
2026-04-09 08:01:24 +00:00
await this . SettingsManager . StoreSettings ( ) ;
await this . MessageBus . SendMessage < bool > ( this , Event . CONFIGURATION_CHANGED ) ;
return ;
}
var assistantPlugin = PluginFactory . RunningPlugins . OfType < PluginAssistants > ( ) . FirstOrDefault ( x = > x . Id = = pluginMeta . Id ) ;
if ( assistantPlugin is null )
return ;
var securityState = PluginAssistantSecurityResolver . Resolve ( this . SettingsManager , assistantPlugin ) ;
if ( securityState . RequiresAudit )
{
await this . OpenAssistantAuditDialogAsync ( pluginMeta . Id ) ;
return ;
}
if ( securityState . IsBelowMinimum & & securityState . IsBlocked )
{
var blockedAudit = securityState . Audit ;
if ( blockedAudit is not null )
await this . DialogService . ShowMessageBox ( this . T ( "Assistant Audit" ) , $"{blockedAudit.Level.GetName()}: {blockedAudit.Summary}" , this . T ( "Close" ) ) ;
return ;
}
if ( securityState . IsBelowMinimum & & securityState . CanOverride & &
! await this . ConfirmActivationBelowMinimumAsync ( pluginMeta . Name , securityState . Audit ! . Level ) )
{
return ;
}
this . SettingsManager . ConfigurationData . EnabledPlugins . Add ( pluginMeta . Id ) ;
2025-03-29 17:40:17 +00:00
await this . SettingsManager . StoreSettings ( ) ;
await this . MessageBus . SendMessage < bool > ( this , Event . CONFIGURATION_CHANGED ) ;
}
2026-04-09 08:01:24 +00:00
private async Task OpenAssistantAuditDialogAsync ( Guid pluginId )
{
var parameters = new DialogParameters < AssistantPluginAuditDialog >
{
{ x = > x . PluginId , pluginId } ,
} ;
var dialog = await this . DialogService . ShowAsync < AssistantPluginAuditDialog > ( this . T ( "Assistant Audit" ) , parameters , DialogOptions . FULLSCREEN ) ;
var result = await dialog . Result ;
if ( result is null | | result . Canceled | | result . Data is not AssistantPluginAuditDialogResult auditResult )
return ;
if ( auditResult . Audit is not null )
this . UpsertAuditCard ( auditResult . Audit ) ;
if ( auditResult . ActivatePlugin )
this . SettingsManager . ConfigurationData . EnabledPlugins . Add ( pluginId ) ;
await this . SettingsManager . StoreSettings ( ) ;
await this . MessageBus . SendMessage < bool > ( this , Event . CONFIGURATION_CHANGED ) ;
}
private async Task < bool > ConfirmActivationBelowMinimumAsync ( string pluginName , AssistantAuditLevel actualLevel )
{
var dialogParameters = new DialogParameters < ConfirmDialog >
{
{
x = > x . Message ,
string . Format (
this . T ( "The assistant plugin \"{0}\" was audited with the level \"{1}\", which is below the required minimum level \"{2}\". Your current settings allow activation anyway, but this may be potentially dangerous. Do you really want to enable this plugin?" ) ,
pluginName ,
actualLevel . GetName ( ) ,
this . AssistantPluginAuditSettings . MinimumLevel . GetName ( ) )
} ,
} ;
var dialogReference = await this . DialogService . ShowAsync < ConfirmDialog > ( this . T ( "Potentially Dangerous Plugin" ) , dialogParameters ,
DialogOptions . FULLSCREEN ) ;
var dialogResult = await dialogReference . Result ;
return dialogResult is not null & & ! dialogResult . Canceled ;
}
2026-02-10 14:23:56 +00:00
2026-04-09 08:01:24 +00:00
private bool IsActivationSwitchDisabled ( IPluginMetadata pluginMeta , bool isEnabled )
{
if ( isEnabled | | pluginMeta . Type is not PluginType . ASSISTANT )
return false ;
var assistantPlugin = this . TryGetAssistantPlugin ( pluginMeta . Id ) ;
if ( assistantPlugin is null )
return false ;
var securityState = PluginAssistantSecurityResolver . Resolve ( this . SettingsManager , assistantPlugin ) ;
return securityState . IsBlocked & & ! securityState . RequiresAudit ;
}
private string GetActivationTooltip ( IPluginMetadata pluginMeta , bool isEnabled )
{
if ( isEnabled )
return this . T ( "Disable plugin" ) ;
if ( pluginMeta . Type is not PluginType . ASSISTANT )
return this . T ( "Enable plugin" ) ;
var assistantPlugin = this . TryGetAssistantPlugin ( pluginMeta . Id ) ;
if ( assistantPlugin is null )
return this . T ( "Enable plugin" ) ;
var securityState = PluginAssistantSecurityResolver . Resolve ( this . SettingsManager , assistantPlugin ) ;
if ( securityState . RequiresAudit )
return securityState . ActionLabel ;
return securityState . IsBlocked
? securityState . Description
: this . T ( "Enable plugin" ) ;
}
2026-02-10 14:23:56 +00:00
private static bool IsSendingMail ( string sourceUrl ) = > sourceUrl . TrimStart ( ) . StartsWith ( "mailto:" , StringComparison . OrdinalIgnoreCase ) ;
2025-04-24 11:50:14 +00:00
2026-04-09 08:01:24 +00:00
private PluginAssistants ? TryGetAssistantPlugin ( Guid pluginId ) = > PluginFactory . RunningPlugins . OfType < PluginAssistants > ( ) . FirstOrDefault ( x = > x . Id = = pluginId ) ;
private async Task TryAutoAuditAssistantsAsync ( )
{
if ( this . isAutoAuditing | | ! this . AssistantPluginAuditSettings . AutomaticallyAuditAssistants )
return ;
this . isAutoAuditing = true ;
try
{
var wasConfigurationChanged = false ;
var assistantPlugins = PluginFactory . RunningPlugins . OfType < PluginAssistants > ( ) . ToList ( ) ;
foreach ( var assistantPlugin in assistantPlugins )
{
var securityState = PluginAssistantSecurityResolver . Resolve ( this . SettingsManager , assistantPlugin ) ;
if ( ! securityState . RequiresAudit )
continue ;
var audit = await this . AssistantPluginAuditService . RunAuditAsync ( assistantPlugin ) ;
if ( audit . Level is AssistantAuditLevel . UNKNOWN )
{
await MessageBus . INSTANCE . SendError ( new ( Icons . Material . Filled . SettingsSuggest , string . Format ( this . T ( "The automatic security audit for the assistant plugin '{0}' failed. Please run it manually." ) , assistantPlugin . Name ) ) ) ;
continue ;
}
this . UpsertAuditCard ( audit ) ;
wasConfigurationChanged = true ;
}
if ( ! wasConfigurationChanged )
return ;
await this . SettingsManager . StoreSettings ( ) ;
await this . MessageBus . SendMessage < bool > ( this , Event . CONFIGURATION_CHANGED ) ;
}
finally
{
this . isAutoAuditing = false ;
await this . InvokeAsync ( this . StateHasChanged ) ;
}
}
private void UpsertAuditCard ( PluginAssistantAudit audit )
{
var audits = this . SettingsManager . ConfigurationData . AssistantPluginAudits ;
var existingIndex = audits . FindIndex ( x = > x . PluginId = = audit . PluginId ) ;
if ( existingIndex > = 0 )
audits [ existingIndex ] = audit ;
else
audits . Add ( audit ) ;
}
2025-04-24 11:50:14 +00:00
#region Overrides of MSGComponentBase
protected override async Task ProcessIncomingMessage < T > ( ComponentBase ? sendingComponent , Event triggeredEvent , T ? data ) where T : default
{
switch ( triggeredEvent )
{
case Event . PLUGINS_RELOADED :
2026-04-09 08:01:24 +00:00
await this . TryAutoAuditAssistantsAsync ( ) ;
await this . InvokeAsync ( this . StateHasChanged ) ;
break ;
case Event . CONFIGURATION_CHANGED :
2025-04-24 11:50:14 +00:00
await this . InvokeAsync ( this . StateHasChanged ) ;
break ;
}
}
#endregion
2026-02-10 14:23:56 +00:00
}