Added profile, provider, and workspace preselection to chat templates (#1099)

Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
Peer HogeterpandThorsten Sommer authored and GitHub committed 2026-10-22 14:15:10 +02:00
1 parent ab9df99cf0
commit 24c4c31035
34 files changed
+2084 -142

No files matched your search

@@ -7,8 +7,9 @@ using Lua.Standard;
namespace AIStudio.Tests.Settings;
/// <summary>
/// Checks the tools and data sources a chat template carries, across the two surfaces which have
/// to agree on them: the Lua a configuration plugin states, and the Lua the app exports.
/// Checks the profile, provider, workspace, tools, and data sources a chat template carries, across
/// the two surfaces which have to agree on them: the Lua a configuration plugin states, and the Lua
/// the app exports.
/// </summary>
/// <remarks>
/// The interesting part is not that a value survives, but that the difference between "this
@@ -88,6 +89,9 @@ public sealed class ChatTemplateConfigurationTests
{
Assert.That(luaCode, Does.Not.Contain("ToolIds"));
Assert.That(luaCode, Does.Not.Contain("DataSourceOptions"));
Assert.That(luaCode, Does.Not.Contain("ProviderId"));
Assert.That(luaCode, Does.Not.Contain("ProfileId"));
Assert.That(luaCode, Does.Not.Contain("WorkspaceName"));
});
var read = await ParseAsync(luaCode);
@@ -189,6 +193,140 @@ public sealed class ChatTemplateConfigurationTests
});
}
[Test]
public async Task APreselectedProviderAndProfileSurviveTheExport()
{
var written = NewTemplate() with
{
ProviderId = "44444444-4444-4444-4444-444444444444",
ProfileId = "55555555-5555-5555-5555-555555555555",
};
var read = await ExportAndReadBackAsync(written);
Assert.Multiple(() =>
{
Assert.That(read.ProviderId, Is.EqualTo(written.ProviderId));
Assert.That(read.ProfileId, Is.EqualTo(written.ProfileId));
});
}
[Test]
public async Task StartingWithoutAProfileIsAStatementOfItsOwn()
{
var read = await ExportAndReadBackAsync(NewTemplate() with { ProfileId = Profile.NO_PROFILE.Id });
var silent = await ExportAndReadBackAsync(NewTemplate());
Assert.Multiple(() =>
{
Assert.That(read.ProfileId, Is.EqualTo(Profile.NO_PROFILE.Id), "Reading this back as null would hand out the default profile the template ruled out.");
Assert.That(silent.ProfileId, Is.Null);
Assert.That(silent.ProviderId, Is.Null);
});
}
[Test]
public async Task APluginTemplateMayNameTheProviderAndProfileOfItsPlugin()
{
var read = await ParseAsync("""
CONFIG["CHAT_TEMPLATES"][#CONFIG["CHAT_TEMPLATES"]+1] = {
["Id"] = "33333333-3333-3333-3333-333333333333",
["Name"] = "Mail",
["SystemPrompt"] = "You help with mails.",
["AllowProfileUsage"] = true,
["ProviderId"] = "44444444-4444-4444-4444-444444444444",
["ProfileId"] = "55555555-5555-5555-5555-555555555555",
}
""");
Assert.Multiple(() =>
{
Assert.That(read.ProviderId, Is.EqualTo("44444444-4444-4444-4444-444444444444"));
Assert.That(read.ProfileId, Is.EqualTo("55555555-5555-5555-5555-555555555555"));
});
}
[TestCase("\"\"")]
[TestCase("\"no GUID\"")]
[TestCase("42")]
[TestCase("\"00000000-0000-0000-0000-000000000000\"")]
public async Task AProviderIdWhichNamesNoProviderIsDropped(string luaValue)
{
var read = await ParseAsync($$"""
CONFIG["CHAT_TEMPLATES"][#CONFIG["CHAT_TEMPLATES"]+1] = {
["Id"] = "33333333-3333-3333-3333-333333333333",
["Name"] = "Mail",
["SystemPrompt"] = "You help with mails.",
["ProviderId"] = {{luaValue}},
}
""");
Assert.That(read.ProviderId, Is.Null, "The template still works then, with the provider its chats would start with anyway.");
}
[Test]
public async Task AWorkspaceNameSurvivesTheExport()
{
var written = NewTemplate() with { WorkspaceName = "Mails \"inbox\"" };
var read = await ExportAndReadBackAsync(written);
var silent = await ExportAndReadBackAsync(NewTemplate());
Assert.Multiple(() =>
{
Assert.That(read.WorkspaceName, Is.EqualTo(written.WorkspaceName));
Assert.That(silent.WorkspaceName, Is.Null, "A template without a workspace must keep leaving the chat where it would go anyway.");
});
}
[TestCase("\"\"")]
[TestCase("\" \"")]
[TestCase("42")]
[TestCase("{}")]
public async Task AWorkspaceNameWhichNamesNothingIsDropped(string luaValue)
{
var read = await ParseAsync($$"""
CONFIG["CHAT_TEMPLATES"][#CONFIG["CHAT_TEMPLATES"]+1] = {
["Id"] = "33333333-3333-3333-3333-333333333333",
["Name"] = "Mail",
["SystemPrompt"] = "You help with mails.",
["WorkspaceName"] = {{luaValue}},
}
""");
Assert.That(read.WorkspaceName, Is.Null);
}
[Test]
public async Task APluginTemplateNamesItsWorkspaceWithoutTheSpacesAround()
{
var read = await ParseAsync("""
CONFIG["CHAT_TEMPLATES"][#CONFIG["CHAT_TEMPLATES"]+1] = {
["Id"] = "33333333-3333-3333-3333-333333333333",
["Name"] = "Mail",
["SystemPrompt"] = "You help with mails.",
["WorkspaceName"] = " Mails ",
}
""");
Assert.That(read.WorkspaceName, Is.EqualTo("Mails"), "Workspaces are matched by their trimmed name, so the spaces would only make the field look different from the name in the list.");
}
[Test]
public void ExportedProviderAndProfileIdsComeWithTheNoteThatTheyAreLocalOnes()
{
var withProvider = NewTemplate() with { ProviderId = "44444444-4444-4444-4444-444444444444" };
var withoutProfile = NewTemplate() with { ProfileId = Profile.NO_PROFILE.Id };
Assert.That(withProvider.TryExportAsConfigurationSection(out var withProviderLua, out var issue), Is.True, issue);
Assert.That(withoutProfile.TryExportAsConfigurationSection(out var withoutProfileLua, out issue), Is.True, issue);
Assert.Multiple(() =>
{
Assert.That(withProviderLua, Does.StartWith("--"), "A provider of this machine is mostly the user's own, which no configuration plugin knows.");
Assert.That(withoutProfileLua, Does.Not.StartWith("--"), "Starting without a profile names nothing which could be missing.");
});
}
[Test]
public void ExportedDataSourceIdsComeWithTheNoteThatTheyAreLocalOnes()
{