mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-13 18:13:47 +00:00
Multiple Profiles can now be selected
This commit is contained in:
1 parent
d043fbc8f0
commit
cefc5464d5
89 files changed
+1360
-503
No files matched your search
@@ -5,8 +5,8 @@ namespace AIStudio.Tools.Services;
|
||||
/// </summary>
|
||||
/// <param name="WorkspaceName">The workspace the chat is created in.</param>
|
||||
/// <param name="ProviderId">The provider to preselect, or null for the chat default.</param>
|
||||
/// <param name="ProfileId">The profile to preselect; the empty GUID selects no profile.</param>
|
||||
/// <param name="ProfileIds">The exact profiles to use, an empty list for none, or null for chat defaults.</param>
|
||||
/// <param name="ChatTemplateId">The chat template to preselect; the empty GUID selects none.</param>
|
||||
/// <param name="DataSourceIds">The data sources to preselect, or null for the chat defaults.</param>
|
||||
/// <param name="ToolIds">The tools to preselect, or null for the chat defaults.</param>
|
||||
public sealed record AssistantBuilderChatLaunchRequest(string WorkspaceName, string? ProviderId, string? ProfileId, string? ChatTemplateId, IReadOnlyList<string>? DataSourceIds, IReadOnlyList<string>? ToolIds);
|
||||
public sealed record AssistantBuilderChatLaunchRequest(string WorkspaceName, string? ProviderId, IReadOnlyList<string>? ProfileIds, string? ChatTemplateId, IReadOnlyList<string>? DataSourceIds, IReadOnlyList<string>? ToolIds);
|
||||
@@ -164,7 +164,7 @@ public sealed class AssistantPluginGenerationService(ToolRegistry toolRegistry,
|
||||
new(
|
||||
chatLaunch.WorkspaceName.Trim(),
|
||||
ParseOptionalGuid(chatLaunch.ProviderId),
|
||||
ParseOptionalGuid(chatLaunch.ProfileId),
|
||||
chatLaunch.ProfileIds?.Select(Guid.Parse).ToArray(),
|
||||
ParseOptionalGuid(chatLaunch.ChatTemplateId),
|
||||
chatLaunch.DataSourceIds?.Select(Guid.Parse).ToArray(),
|
||||
chatLaunch.ToolIds));
|
||||
@@ -505,9 +505,9 @@ public sealed class AssistantPluginGenerationService(ToolRegistry toolRegistry,
|
||||
: $$"""
|
||||
- Describe a direct chat launcher, not a form assistant.
|
||||
- Copy the structured ChatLaunch selections faithfully into the {{TB("Chat Launcher")}}, {{TB("Workspace")}}, {{TB("Chat Configuration")}}, {{TB("Data Sources")}}, and {{TB("Tools")}} sections.
|
||||
- Explain omitted provider, profile, template, data-source, or tool values as using the normal chat defaults.
|
||||
- Explain omitted provider, profiles, template, data-source, or tool values as using the normal chat defaults.
|
||||
- In the {{TB("Tools")}} section, say what the preselected tools let the chat do and that users may change the selection once the chat is open.
|
||||
- Explain the empty profile/template GUID as explicitly selecting no profile/template.
|
||||
- Explain an empty profile list as explicitly selecting no profiles and the empty template GUID as selecting no template.
|
||||
- Do not propose UI components, submit behavior, BuildPrompt, or a plugin SystemPrompt for a chat launcher.
|
||||
""";
|
||||
|
||||
@@ -619,9 +619,9 @@ public sealed class AssistantPluginGenerationService(ToolRegistry toolRegistry,
|
||||
- Set assistant.kind to "CHAT_LAUNCHER" exactly when the revised ASSISTANT table uses LaunchBehavior = "OPEN_WORKSPACE_CHAT_BY_NAME"; otherwise set it to "FORM".
|
||||
- For a form assistant, include system_prompt, submit_text, and allow_ai_studio_profiles in the JSON assistant object and omit launch. Include tool_ids exactly when the revised ASSISTANT table carries ToolIds.
|
||||
- Change ASSISTANT.ToolIds only when the requested change asks for it. Use only tool IDs from the "Available tools" list in the plugin context for tools you add; never invent an ID. Drop the field entirely rather than writing an empty list.
|
||||
- For a chat launcher, include launch with the exact WorkspaceName and optional ProviderId, ProfileId, ChatTemplateId, DataSourceIds, and ToolIds values from the revised ASSISTANT table; omit system_prompt, submit_text, and allow_ai_studio_profiles.
|
||||
- For a chat launcher, include launch with the exact WorkspaceName and optional ProviderId, ProfileIds, ChatTemplateId, DataSourceIds, and ToolIds values from the revised ASSISTANT table; omit system_prompt, submit_text, and allow_ai_studio_profiles.
|
||||
- A chat launcher must not include SystemPrompt, SubmitText, AllowProfiles, BuildPrompt, or UI in its ASSISTANT table.
|
||||
- Preserve an empty profile or template GUID when it explicitly means no profile or no template. Do not emit empty provider or data-source GUIDs.
|
||||
- Preserve an empty ProfileIds list when it explicitly means no profiles, and preserve an empty template GUID when it means no template. Do not emit empty provider, profile, or data-source GUIDs.
|
||||
- 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.
|
||||
@@ -754,7 +754,7 @@ public sealed class AssistantPluginGenerationService(ToolRegistry toolRegistry,
|
||||
|
||||
if (string.IsNullOrWhiteSpace(launch.WorkspaceName) ||
|
||||
!IsOptionalGuid(launch.ProviderId, allowEmpty: false) ||
|
||||
!IsOptionalGuid(launch.ProfileId, allowEmpty: true) ||
|
||||
!IsOptionalGuidList(launch.ProfileIds, allowEmptyList: true) ||
|
||||
!IsOptionalGuid(launch.ChatTemplateId, allowEmpty: true))
|
||||
return false;
|
||||
|
||||
@@ -784,10 +784,14 @@ public sealed class AssistantPluginGenerationService(ToolRegistry toolRegistry,
|
||||
if (actual is null ||
|
||||
!string.Equals(requested.WorkspaceName.Trim(), actual.WorkspaceName, StringComparison.Ordinal) ||
|
||||
ParseOptionalGuid(requested.ProviderId) != actual.ProviderId ||
|
||||
ParseOptionalGuid(requested.ProfileId) != actual.ProfileId ||
|
||||
ParseOptionalGuid(requested.ChatTemplateId) != actual.ChatTemplateId)
|
||||
return false;
|
||||
|
||||
var requestedProfileIds = requested.ProfileIds?.Select(Guid.Parse).ToArray();
|
||||
if (!(requestedProfileIds is null && actual.ProfileIds is null ||
|
||||
requestedProfileIds is not null && actual.ProfileIds is not null && requestedProfileIds.SequenceEqual(actual.ProfileIds)))
|
||||
return false;
|
||||
|
||||
var requestedDataSourceIds = requested.DataSourceIds?.Select(Guid.Parse).ToArray();
|
||||
if (!(requestedDataSourceIds is null && actual.DataSourceIds is null ||
|
||||
requestedDataSourceIds is not null && actual.DataSourceIds is not null &&
|
||||
@@ -832,7 +836,7 @@ public sealed class AssistantPluginGenerationService(ToolRegistry toolRegistry,
|
||||
var request = new AssistantBuilderChatLaunchRequest(
|
||||
launch.WorkspaceName,
|
||||
launch.ProviderId,
|
||||
launch.ProfileId,
|
||||
launch.ProfileIds,
|
||||
launch.ChatTemplateId,
|
||||
launch.DataSourceIds,
|
||||
launch.ToolIds);
|
||||
@@ -868,6 +872,11 @@ public sealed class AssistantPluginGenerationService(ToolRegistry toolRegistry,
|
||||
private static bool IsOptionalGuid(string? value, bool allowEmpty) => value is null ||
|
||||
Guid.TryParse(value, out var parsed) && (allowEmpty || parsed != Guid.Empty);
|
||||
|
||||
private static bool IsOptionalGuidList(IReadOnlyList<string>? values, bool allowEmptyList) => values is null ||
|
||||
(allowEmptyList || values.Count > 0) &&
|
||||
values.All(value => Guid.TryParse(value, out var parsed) && parsed != Guid.Empty) &&
|
||||
values.Distinct(StringComparer.OrdinalIgnoreCase).Count() == values.Count;
|
||||
|
||||
private static Guid? ParseOptionalGuid(string? value) => value is null ? null : Guid.Parse(value);
|
||||
|
||||
private static string SerializeUntrustedPromptData(object value) => JsonSerializer.Serialize(value, UNTRUSTED_PROMPT_JSON_OPTIONS);
|
||||
@@ -888,4 +897,4 @@ public sealed class AssistantPluginGenerationService(ToolRegistry toolRegistry,
|
||||
private static AssistantPluginRevisionDraft RevisionFailure(string issue) => new(false, string.Empty, string.Empty, issue);
|
||||
|
||||
private readonly record struct AssistantContextFile(string Title, string RelativePath, bool IsRequired);
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,9 @@ public sealed class DirectChatService(SettingsManager settingsManager, DataSourc
|
||||
if (providerResult.IsExplicit && providerResult.Provider == ProviderSettings.NONE)
|
||||
return new(null, providerResult.ErrorMessage);
|
||||
|
||||
var profileResult = this.ResolveProfile(launchConfiguration.ProfileId);
|
||||
var profile = profileResult.Profile;
|
||||
if (profile is null)
|
||||
var profileResult = this.ResolveProfiles(launchConfiguration.ProfileIds);
|
||||
var profiles = profileResult.Profiles;
|
||||
if (profiles is null)
|
||||
return new(null, profileResult.ErrorMessage);
|
||||
|
||||
var chatTemplateResult = this.ResolveChatTemplate(launchConfiguration.ChatTemplateId);
|
||||
@@ -36,13 +36,13 @@ public sealed class DirectChatService(SettingsManager settingsManager, DataSourc
|
||||
// its profile selection for such templates, so keeping the profile would pin one that the
|
||||
// user can neither see nor change. We drop it instead of failing the whole launch.
|
||||
//
|
||||
if (!chatTemplate.AllowProfileUsage && profile != Profile.NO_PROFILE)
|
||||
if (!chatTemplate.AllowProfileUsage && profiles.Count > 0)
|
||||
{
|
||||
logger.LogWarning(
|
||||
"Assistant plugin '{PluginName}' selects the profile '{ProfileName}', but its chat template '{ChatTemplateName}' does not allow profiles. The chat starts without a profile.",
|
||||
assistantPlugin.Name, profile.GetSafeName(), chatTemplate.GetSafeName());
|
||||
"Assistant plugin '{PluginName}' selects profiles, but its chat template '{ChatTemplateName}' does not allow profiles. The chat starts without profiles.",
|
||||
assistantPlugin.Name, chatTemplate.GetSafeName());
|
||||
|
||||
profile = Profile.NO_PROFILE;
|
||||
profiles = [];
|
||||
}
|
||||
|
||||
var dataSourceOptionsResult = await this.ResolveDataSourceOptionsAsync(providerResult.Provider, launchConfiguration.DataSourceIds);
|
||||
@@ -81,7 +81,7 @@ public sealed class DirectChatService(SettingsManager settingsManager, DataSourc
|
||||
{
|
||||
IncludeDateTime = true,
|
||||
SelectedProvider = providerResult.Provider == ProviderSettings.NONE ? string.Empty : providerResult.Provider.Id,
|
||||
SelectedProfile = profile.Id,
|
||||
SelectedProfileIds = profiles.Select(profile => profile.Id).ToHashSet(StringComparer.OrdinalIgnoreCase),
|
||||
SelectedChatTemplate = chatTemplate.Id,
|
||||
// The provider confidence is checked later, when the chat sends a message:
|
||||
SelectedToolIds = selectedToolIds,
|
||||
@@ -121,23 +121,19 @@ public sealed class DirectChatService(SettingsManager settingsManager, DataSourc
|
||||
return new(provider, true, string.Empty);
|
||||
}
|
||||
|
||||
private (Profile? Profile, string ErrorMessage) ResolveProfile(Guid? profileId)
|
||||
private (IReadOnlyList<Profile>? Profiles, string ErrorMessage) ResolveProfiles(IReadOnlyList<Guid>? profileIds)
|
||||
{
|
||||
if (profileId is null)
|
||||
return new(settingsManager.GetPreselectedProfile(Components.CHAT), string.Empty);
|
||||
if (profileIds is null)
|
||||
return new(settingsManager.GetPreselectedProfiles(Components.CHAT), string.Empty);
|
||||
|
||||
// The launcher explicitly wants no profile:
|
||||
if (profileId == Guid.Empty)
|
||||
return new(Profile.NO_PROFILE, string.Empty);
|
||||
if (profileIds.Count == 0)
|
||||
return new([], string.Empty);
|
||||
|
||||
//
|
||||
// We already handled the empty GUID above, so GetProfileById returning the no-profile
|
||||
// entry here can only mean that the referenced profile is gone:
|
||||
//
|
||||
var profile = settingsManager.GetProfileById(profileId.Value.ToString());
|
||||
return profile == Profile.NO_PROFILE
|
||||
? new(null, string.Format(TB("The assistant chat launcher references profile '{0}', but that profile does not exist."), profileId))
|
||||
: new(profile, string.Empty);
|
||||
var profiles = settingsManager.ResolveProfiles(profileIds.Select(profileId => profileId.ToString()));
|
||||
if (profiles.Count != profileIds.Count)
|
||||
return new(null, TB("The assistant chat launcher references one or more profiles that do not exist."));
|
||||
|
||||
return new(profiles, string.Empty);
|
||||
}
|
||||
|
||||
private (ChatTemplate? ChatTemplate, string ErrorMessage) ResolveChatTemplate(Guid? chatTemplateId)
|
||||
@@ -212,4 +208,4 @@ public sealed class DirectChatService(SettingsManager settingsManager, DataSourc
|
||||
PreselectedDataSourceIds = requestedDataSources.Select(source => source.Id).ToList(),
|
||||
}, string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user