mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-05 06:29:41 +00:00
Let chat templates preselect tools and data sources (#995)
This commit is contained in:
1 parent
c95cc5bacc
commit
559f3f7fa6
20 files changed
+1374
-83
No files matched your search
@@ -1,4 +1,5 @@
|
||||
@using AIStudio.Chat
|
||||
@using AIStudio.Settings.DataModel
|
||||
@inherits MSGComponentBase
|
||||
|
||||
<MudDialog>
|
||||
@@ -109,6 +110,35 @@
|
||||
</MudJustifiedText>
|
||||
<MudTextSwitch @bind-Value="@this.AllowProfileUsage" Color="Color.Primary" Label="@T("Allow the use of profiles together with this chat template?")" LabelOn="@T("Yes, allow profiles when using this template")" LabelOff="@T("No, prohibit profile use for this template")" Disabled="@this.IsReadOnly" />
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-3 mt-6">
|
||||
@T("Tools")
|
||||
</MudText>
|
||||
<MudJustifiedText Class="mb-3" Typo="Typo.body1">
|
||||
@T("A chat template may decide which tools a chat starts with. Without such a decision, those chats start with the tools you chose as your default in the chat options. Deciding and then picking nothing is a different statement: such chats start with no tool at all, no matter what your default says.")
|
||||
</MudJustifiedText>
|
||||
<MudTextSwitch @bind-Value="@this.preselectTools" Color="Color.Primary" Label="@T("Does this chat template preselect tools?")" LabelOn="@T("Yes, this template decides which tools a chat starts with")" LabelOff="@T("No, chats keep the tools from your chat options")" Disabled="@this.IsReadOnly"/>
|
||||
@if (this.preselectTools)
|
||||
{
|
||||
<MudPaper Class="pa-3 mb-8 mt-3 border-dashed border rounded-lg">
|
||||
<ToolSelectionField Component="Components.CHAT" SelectedToolIds="@this.selectedToolIds" SelectedToolIdsChanged="@this.SetSelectedToolIds" ReadOnly="@this.IsReadOnly" Label="@T("Preselected tools")" Help="@T("The selection stays changeable in the chat, and every tool still has to meet the confidence requirements of the provider in use.")"/>
|
||||
</MudPaper>
|
||||
}
|
||||
|
||||
@if (PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager))
|
||||
{
|
||||
<MudText Typo="Typo.h6" Class="mb-3 mt-6">
|
||||
@T("Data Sources")
|
||||
</MudText>
|
||||
<MudJustifiedText Class="mb-3" Typo="Typo.body1">
|
||||
@T("The same goes for your data. A chat template may bring its own data source options, which includes leaving the choice of sources to the AI. Without them, those chats start with the data source options from your chat options.")
|
||||
</MudJustifiedText>
|
||||
<MudTextSwitch @bind-Value="@this.preselectDataSources" Color="Color.Primary" Label="@T("Does this chat template preselect data sources?")" LabelOn="@T("Yes, this template decides which data a chat starts with")" LabelOff="@T("No, chats keep the data source options from your chat options")" Disabled="@this.IsReadOnly"/>
|
||||
@if (this.preselectDataSources)
|
||||
{
|
||||
<DataSourceSelection SelectionMode="DataSourceSelectionMode.CONFIGURATION_MODE" AutoSaveAppSettings="@false" ConfiguresChatDefaults="@false" ReadOnly="@this.IsReadOnly" @bind-DataSourceOptions="@this.templateDataSourceOptions" ConfigurationHeaderMessage="@T("A chat started with this template begins with these data sources and options. All of it stays changeable in the chat itself.")"/>
|
||||
}
|
||||
}
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-3 mt-6">
|
||||
@T("Example Conversation")
|
||||
</MudText>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Components;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Settings.DataModel;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
@@ -59,6 +60,18 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
[Parameter]
|
||||
public bool AllowProfileUsage { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The tools this template preselects, or null when it says nothing about tools.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public HashSet<string>? ToolIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The data source options this template preselects, or null when it says nothing about them.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public DataSourceOptions? DataSourceOptions { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool CreateFromExistingChatThread { get; set; }
|
||||
|
||||
@@ -78,6 +91,10 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
private bool dataIsValid;
|
||||
private List<ContentBlock> dataExampleConversation = [];
|
||||
private HashSet<FileAttachment> fileAttachments = [];
|
||||
private bool preselectTools;
|
||||
private HashSet<string> selectedToolIds = new(StringComparer.Ordinal);
|
||||
private bool preselectDataSources;
|
||||
private DataSourceOptions templateDataSourceOptions = new();
|
||||
private string[] dataIssues = [];
|
||||
private string dataEditingPreviousName = string.Empty;
|
||||
private bool isInlineEditOnGoing;
|
||||
@@ -97,6 +114,20 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
// Load the used instance names:
|
||||
this.UsedNames = this.SettingsManager.ConfigurationData.ChatTemplates.Select(x => x.Name.ToLowerInvariant()).ToList();
|
||||
|
||||
//
|
||||
// The two switches below carry the third state of the preselection: switched off, this
|
||||
// template says nothing, and a chat started with it uses the defaults from the chat
|
||||
// options. Their working copies live apart from the parameters, so switching a
|
||||
// preselection off and on again does not throw away what was picked.
|
||||
//
|
||||
this.preselectTools = this.ToolIds is not null;
|
||||
this.selectedToolIds = this.ToolIds is null ? new(StringComparer.Ordinal) : new(this.ToolIds, StringComparer.Ordinal);
|
||||
this.preselectDataSources = this.DataSourceOptions is not null;
|
||||
|
||||
// Saying that this template preselects data sources is already the statement that it wants
|
||||
// them, so the switch inside the selection starts on instead of at its usual default:
|
||||
this.templateDataSourceOptions = this.DataSourceOptions?.CreateCopy() ?? new DataSourceOptions { DisableDataSources = false };
|
||||
|
||||
// When editing, we need to load the data:
|
||||
if(this.IsEditing)
|
||||
{
|
||||
@@ -138,11 +169,15 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
ExampleConversation = this.dataExampleConversation,
|
||||
FileAttachments = this.fileAttachments.Select(attachment => attachment.Normalize()).ToList(),
|
||||
AllowProfileUsage = this.AllowProfileUsage,
|
||||
ToolIds = this.preselectTools ? new HashSet<string>(this.selectedToolIds, StringComparer.Ordinal) : null,
|
||||
DataSourceOptions = this.preselectDataSources ? this.templateDataSourceOptions.CreateCopy() : null,
|
||||
|
||||
EnterpriseConfigurationPluginId = Guid.Empty,
|
||||
IsEnterpriseConfiguration = false,
|
||||
};
|
||||
|
||||
private void SetSelectedToolIds(HashSet<string> toolIds) => this.selectedToolIds = toolIds;
|
||||
|
||||
private void RemoveMessage(ContentBlock item)
|
||||
{
|
||||
if (this.IsReadOnly)
|
||||
|
||||
@@ -69,6 +69,8 @@ public partial class SettingsDialogChatTemplate : SettingsDialogBase
|
||||
{ x => x.ExampleConversation, chatTemplate.ExampleConversation },
|
||||
{ x => x.FileAttachments, chatTemplate.FileAttachments },
|
||||
{ x => x.AllowProfileUsage, chatTemplate.AllowProfileUsage },
|
||||
{ x => x.ToolIds, chatTemplate.ToolIds },
|
||||
{ x => x.DataSourceOptions, chatTemplate.DataSourceOptions },
|
||||
};
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<ChatTemplateDialog>(T("Edit Chat Template"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
@@ -97,6 +99,8 @@ public partial class SettingsDialogChatTemplate : SettingsDialogBase
|
||||
{ x => x.ExampleConversation, chatTemplate.ExampleConversation },
|
||||
{ x => x.FileAttachments, chatTemplate.FileAttachments },
|
||||
{ x => x.AllowProfileUsage, chatTemplate.AllowProfileUsage },
|
||||
{ x => x.ToolIds, chatTemplate.ToolIds },
|
||||
{ x => x.DataSourceOptions, chatTemplate.DataSourceOptions },
|
||||
};
|
||||
|
||||
await this.DialogService.ShowAsync<ChatTemplateDialog>(T("View Chat Template"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
@@ -128,6 +132,9 @@ public partial class SettingsDialogChatTemplate : SettingsDialogBase
|
||||
if (chatTemplate == ChatTemplate.NO_CHAT_TEMPLATE || chatTemplate.IsEnterpriseConfiguration)
|
||||
return;
|
||||
|
||||
if (!await this.ConfirmExportOfLocalDataSources(chatTemplate))
|
||||
return;
|
||||
|
||||
await this.CopyChatTemplateLuaToClipboard(chatTemplate);
|
||||
}
|
||||
|
||||
@@ -141,10 +148,14 @@ public partial class SettingsDialogChatTemplate : SettingsDialogBase
|
||||
|
||||
if (chatTemplate.FileAttachments.Count == 0)
|
||||
{
|
||||
// That way asks about the local data sources itself, so we must not ask twice:
|
||||
await this.ExportChatTemplateWithSharedAttachmentPaths(chatTemplate);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await this.ConfirmExportOfLocalDataSources(chatTemplate))
|
||||
return;
|
||||
|
||||
this.isPluginDirectoryDialogOpen = true;
|
||||
try
|
||||
{
|
||||
@@ -160,6 +171,35 @@ public partial class SettingsDialogChatTemplate : SettingsDialogBase
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asks whether to export a template although it preselects data sources of this machine.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The export writes the preselected data source IDs unchanged, which is what makes a template
|
||||
/// usable across an organization — but a local file or folder exists here and nowhere else, so
|
||||
/// its ID points at nothing on the machine reading the plugin. Nothing breaks, the chat simply
|
||||
/// starts without that source, and that is precisely why it has to be said beforehand: nobody
|
||||
/// would notice it afterwards. Exporting anyway is a fair choice, because the rest of the
|
||||
/// template is worth rolling out.
|
||||
/// </remarks>
|
||||
/// <param name="chatTemplate">The chat template about to be exported.</param>
|
||||
/// <returns>True when the export may go ahead.</returns>
|
||||
private async Task<bool> ConfirmExportOfLocalDataSources(ChatTemplate chatTemplate)
|
||||
{
|
||||
var localDataSourceNames = ChatTemplate.GetPreselectedLocalDataSourceNames(chatTemplate, this.SettingsManager.ConfigurationData.DataSources);
|
||||
if (localDataSourceNames.Count == 0)
|
||||
return true;
|
||||
|
||||
var dialogParameters = new DialogParameters<ConfirmDialog>
|
||||
{
|
||||
{ x => x.Message, string.Format(T("This chat template preselects data sources which exist on this machine only: {0}. They cannot be rolled out, so a chat started with this template elsewhere begins without them. Do you want to export the template anyway?"), string.Join(", ", localDataSourceNames)) },
|
||||
};
|
||||
|
||||
var dialogReference = await this.DialogService.ShowAsync<ConfirmDialog>(T("Export Chat Template"), dialogParameters, DialogOptions.FULLSCREEN);
|
||||
var dialogResult = await dialogReference.Result;
|
||||
return dialogResult is { Canceled: false };
|
||||
}
|
||||
|
||||
private async Task CopyChatTemplateLuaToClipboard(ChatTemplate chatTemplate)
|
||||
{
|
||||
if (!chatTemplate.TryExportAsConfigurationSection(out var luaCode, out var issue))
|
||||
|
||||
Reference in new issue
Block a user