Pick tools and data sources while editing a chat template

This commit is contained in:
Thorsten Sommer committed 2026-09-22 10:17:51 +02:00
1 parent e31da42901
commit af89a8c952
5 files changed
+100 -6

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);