using the parsed config to allow or forbid to revise the assistant with ai

This commit is contained in:
krut_ni 2026-07-13 17:55:57 +02:00
parent 9d5322dd1b
commit d9098d288f
No known key found for this signature in database
GPG Key ID: A5C0151B4DDB172C
4 changed files with 34 additions and 16 deletions

View File

@ -74,7 +74,7 @@ public partial class AssistantDynamic : AssistantBaseCore<NoSettingsPanel>
private static readonly AssistantSessionStateKey<string> SECURITY_MESSAGE_STATE_KEY = new(nameof(securityMessage));
private static readonly AssistantSessionStateKey<bool> IS_SECURITY_BLOCKED_STATE_KEY = new(nameof(isSecurityBlocked));
private bool CanReviseCurrentAssistant => this.assistantPlugin is { IsInternal: false, IsAssistantBuilderGenerated: true } && !string.IsNullOrWhiteSpace(this.assistantPlugin.PluginPath);
private bool CanReviseCurrentAssistant => this.assistantPlugin is { IsInternal: false, IsManagedByConfigServer: false } && !string.IsNullOrWhiteSpace(this.assistantPlugin.PluginPath);
/// <inheritdoc />
protected override void CaptureCustomAssistantSessionState(AssistantSessionStateWriter state)

View File

@ -87,7 +87,7 @@ public partial class AssistantPluginRevisionDialog : MSGComponentBase
if (!CanReviseAssistantPlugin(this.availablePlugin, this.assistantPlugin))
{
this.issue = T("Only local assistants generated by the Assistant Builder can be revised with AI.");
this.issue = T("Only locally managed assistant plugins can be revised with AI.");
return;
}
@ -225,9 +225,9 @@ public partial class AssistantPluginRevisionDialog : MSGComponentBase
private void Cancel() => this.MudDialog.Cancel();
private static bool CanReviseAssistantPlugin(IAvailablePlugin availablePlugin, PluginAssistants assistantPlugin) =>
availablePlugin is { IsInternal: false, Type: PluginType.ASSISTANT } &&
availablePlugin is { IsInternal: false, IsManagedByConfigServer: false, Type: PluginType.ASSISTANT } &&
!string.IsNullOrWhiteSpace(availablePlugin.LocalPath) &&
assistantPlugin.IsAssistantBuilderGenerated;
assistantPlugin is { IsInternal: false, IsManagedByConfigServer: false };
private static void UpsertAudit(IList<PluginAssistantAudit> audits, PluginAssistantAudit audit)
{

View File

@ -195,9 +195,9 @@ public partial class Plugins : MSGComponentBase
private static bool CanReviseAssistantPlugin(IAvailablePlugin plugin)
{
var assistantPlugin = PluginFactory.RunningPlugins.OfType<PluginAssistants>().FirstOrDefault(x => x.Id == plugin.Id);
return plugin is { IsInternal: false, Type: PluginType.ASSISTANT } &&
return plugin is { IsInternal: false, IsManagedByConfigServer: false, Type: PluginType.ASSISTANT } &&
!string.IsNullOrWhiteSpace(plugin.LocalPath) &&
assistantPlugin?.IsAssistantBuilderGenerated is true;
assistantPlugin?.IsManagedByConfigServer is false;
}
private async Task OpenAssistantPluginEditorDialogAsync(IAvailablePlugin plugin)

View File

@ -105,12 +105,19 @@ public sealed class AssistantPluginGenerationService(ILogger<AssistantPluginGene
return InitialFailure(issue);
var fullLua = parsedResponse.FullLua.Trim();
if (!fullLua.Contains(request.PluginId.ToString(), StringComparison.OrdinalIgnoreCase))
var generatedPlugin = await PluginFactory.Load(null, fullLua, token);
if (generatedPlugin is not PluginAssistants generatedAssistant || !generatedAssistant.IsValid)
return InitialFailure(TB("The generated assistant plugin is not a valid assistant plugin."));
if (generatedAssistant.Id != request.PluginId)
return InitialFailure(TB("The generated assistant plugin must use the assigned plugin ID."));
if (!ContainsAssistantBuilderMetadata(fullLua))
if (!generatedAssistant.IsAssistantBuilderGenerated)
return InitialFailure(TB("The generated assistant plugin must include the Assistant Builder metadata."));
if (generatedAssistant.IsManagedByConfigServer)
return InitialFailure(TB("The generated assistant plugin must be marked as locally managed."));
return new(true, fullLua, parsedResponse.Plugin?.Name ?? string.Empty, string.Empty);
}
@ -122,8 +129,8 @@ public sealed class AssistantPluginGenerationService(ILogger<AssistantPluginGene
string testContext,
CancellationToken token = default)
{
if (!plugin.IsAssistantBuilderGenerated)
return RevisionFailure(TB("Only assistants generated by the Assistant Builder can be revised with AI."));
if (plugin is { IsInternal: true } or { IsManagedByConfigServer: true })
return RevisionFailure(TB("Only locally managed assistant plugins can be revised with AI."));
if (string.IsNullOrWhiteSpace(currentLua))
return RevisionFailure(TB("The current plugin.lua content is empty."));
@ -151,12 +158,19 @@ public sealed class AssistantPluginGenerationService(ILogger<AssistantPluginGene
return RevisionFailure(issue);
var revisedLua = parsedResponse.FullLua.Trim();
if (!revisedLua.Contains(plugin.Id.ToString(), StringComparison.OrdinalIgnoreCase))
var parsedRevision = await PluginFactory.Load(plugin.PluginPath, revisedLua, token);
if (parsedRevision is not PluginAssistants revisedAssistant || !revisedAssistant.IsValid)
return RevisionFailure(TB("The revised assistant plugin is not a valid assistant plugin."));
if (revisedAssistant.Id != plugin.Id)
return RevisionFailure(TB("The revised assistant plugin must keep the same plugin ID."));
if (!ContainsAssistantBuilderMetadata(revisedLua))
if (plugin.IsAssistantBuilderGenerated && !revisedAssistant.IsAssistantBuilderGenerated)
return RevisionFailure(TB("The revised assistant plugin must keep the Assistant Builder metadata."));
if (revisedAssistant.IsManagedByConfigServer)
return RevisionFailure(TB("The revised assistant plugin must remain locally managed."));
return new(true, revisedLua, parsedResponse.Plugin?.Name ?? plugin.Name, string.Empty);
}
@ -246,6 +260,7 @@ public sealed class AssistantPluginGenerationService(ILogger<AssistantPluginGene
TARGET_GROUPS = {"EVERYONE"}
IS_MAINTAINED = true
DEPRECATION_MESSAGE = ""
DEPLOYED_USING_CONFIG_SERVER = false
AI_STUDIO_ASSISTANT_BUILDER = {Generated = true, SchemaVersion = 1}
</fixed_metadata_defaults>
@ -263,6 +278,7 @@ public sealed class AssistantPluginGenerationService(ILogger<AssistantPluginGene
- The JSON "plugin" object describes the top-level Lua plugin metadata such as NAME, DESCRIPTION, and CATEGORIES.
- The JSON "assistant" object describes the ASSISTANT table metadata such as Title, Description, SystemPrompt, SubmitText, and AllowProfiles.
- The plugin must include all required top-level metadata and the ASSISTANT table.
- The plugin must include DEPLOYED_USING_CONFIG_SERVER = false.
- The plugin must include AI_STUDIO_ASSISTANT_BUILDER = {Generated = true, SchemaVersion = 1}.
- The ASSISTANT table must include Title, Description, SystemPrompt, SubmitText, AllowProfiles, and UI.
- UI.Type must be "FORM".
@ -347,8 +363,11 @@ public sealed class AssistantPluginGenerationService(ILogger<AssistantPluginGene
string responseSchema)
{
var companionLua = FormatCompanionLuaFiles(plugin);
var builderMetadataRule = plugin.IsAssistantBuilderGenerated
? "- Keep AI_STUDIO_ASSISTANT_BUILDER = {Generated = true, SchemaVersion = 1}."
: string.Empty;
return $$"""
Revise an existing AI Studio Lua assistant plugin.
Revise an existing locally managed AI Studio Lua assistant plugin.
Generate a complete replacement for plugin.lua from the current plugin.lua and the user's requested change.
<plugin_context>
@ -391,7 +410,8 @@ public sealed class AssistantPluginGenerationService(ILogger<AssistantPluginGene
- Encode "full_lua" as a normal JSON string: use \" for quotes and \n for line breaks. Do not double-escape Lua quotes or line breaks as \\\" or \\n.
- Keep ID = "{{plugin.Id}}" exactly. Do not create a new plugin ID.
- Keep TYPE = "ASSISTANT".
- Keep AI_STUDIO_ASSISTANT_BUILDER = {Generated = true, SchemaVersion = 1}.
- Keep the assistant locally managed. DEPLOYED_USING_CONFIG_SERVER must not be true.
{{builderMetadataRule}}
- Preserve existing behavior unless the requested change explicitly modifies it.
- Apply the requested change directly to plugin.lua; do not describe how to change it.
- Do not create companion files, new require(...) dependencies, hidden behavior, or obfuscated behavior.
@ -515,8 +535,6 @@ public sealed class AssistantPluginGenerationService(ILogger<AssistantPluginGene
private static bool ProviderIsUsable(ProviderSettings provider) => provider != ProviderSettings.NONE && provider.UsedLLMProvider is not LLMProviders.NONE;
private static bool ContainsAssistantBuilderMetadata(string lua) => lua.Contains("AI_STUDIO_ASSISTANT_BUILDER", StringComparison.Ordinal);
private static string SerializeUntrustedPromptData(object value) => JsonSerializer.Serialize(value, UNTRUSTED_PROMPT_JSON_OPTIONS);
private static string ValueOrNone(string value) => string.IsNullOrWhiteSpace(value)