diff --git a/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor b/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor
index 4b7f965e..dbde56e0 100644
--- a/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor
+++ b/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor
@@ -23,7 +23,7 @@
@(this.createChatLauncher
- ? T("The direct chat launcher tile has no input form of its own. It opens a new chat right away, in the workspace you name below and with the provider, profile, chat template, and data sources you select there.")
+ ? T("The direct chat launcher tile has no input form of its own. It opens a new chat right away, with the provider, profile, chat template, and data sources you select below. Name a workspace for that chat, or leave the workspace empty to open a disappearing chat.")
: T("The assistant asks users for input through a form and builds its own prompt from it."))
@if (this.createChatLauncher)
@@ -39,8 +39,7 @@
@bind-ProfileId="@this.launcherProfileId"
@bind-ChatTemplateId="@this.launcherChatTemplateId"
@bind-DataSourceIds="@this.launcherDataSourceIds"
- @bind-ToolIds="@this.launcherToolIds"
- ValidateWorkspaceName="@this.ValidateLauncherWorkspaceName"/>
+ @bind-ToolIds="@this.launcherToolIds"/>
}
diff --git a/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor.cs b/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor.cs
index e17d75cb..f129d464 100644
--- a/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor.cs
+++ b/app/MindWork AI Studio/Assistants/Builder/AssistantBuilder.razor.cs
@@ -375,14 +375,6 @@ public partial class AssistantBuilder : AssistantBaseCore
return null;
}
- private string? ValidateLauncherWorkspaceName(string workspaceName)
- {
- if (this.createChatLauncher && string.IsNullOrWhiteSpace(workspaceName))
- return T("Please select or enter a workspace name for the chat launcher.");
-
- return null;
- }
-
private async Task GenerateAssistantSpec()
{
await this.Form!.Validate();
@@ -589,7 +581,8 @@ public partial class AssistantBuilder : AssistantBaseCore
// The description stays required for both kinds of assistant. Users who only want a tile
// usually flip the switch before typing anything, so the Builder offers a starting point they
// can edit or replace. The workspace is picked after that, hence the suggestion is refreshed
- // whenever the workspace changes:
+ // whenever the workspace changes — including when it is cleared again, which turns the tile
+ // into one that opens a disappearing chat:
//
private void SuggestLauncherDescription()
{
@@ -597,8 +590,9 @@ public partial class AssistantBuilder : AssistantBaseCore
return;
var suggestion = T("Create a tile that opens a preconfigured chat directly, without an input form of its own.");
- if (!string.IsNullOrWhiteSpace(this.launcherWorkspaceName))
- suggestion = $"{suggestion} {string.Format(T("Workspace: {0}"), this.launcherWorkspaceName.Trim())}";
+ suggestion = string.IsNullOrWhiteSpace(this.launcherWorkspaceName)
+ ? $"{suggestion} {T("The chat belongs to no workspace and disappears again.")}"
+ : $"{suggestion} {string.Format(T("Workspace: {0}"), this.launcherWorkspaceName.Trim())}";
this.assistantDescription = suggestion;
this.descriptionSuggestion = suggestion;
diff --git a/app/MindWork AI Studio/Components/DirectChatLauncherForm.razor b/app/MindWork AI Studio/Components/DirectChatLauncherForm.razor
index e1c432cf..af72de38 100644
--- a/app/MindWork AI Studio/Components/DirectChatLauncherForm.razor
+++ b/app/MindWork AI Studio/Components/DirectChatLauncherForm.razor
@@ -10,7 +10,15 @@
}
-
+
+
+@* The tile behaves differently with and without a workspace, so the form says which of the two is
+ chosen right now instead of only explaining that both are possible. *@
+
+ @(this.OpensTemporaryChat
+ ? T("Without a workspace, the tile opens a disappearing chat: it belongs to no workspace and is deleted according to your workspace maintenance settings.")
+ : T("The tile opens its chat in this workspace and creates the workspace when it does not exist yet."))
+
@T("Use chat default")
@foreach (var provider in this.SettingsManager.GetConfidentProviders(Components.CHAT))
diff --git a/app/MindWork AI Studio/Components/DirectChatLauncherForm.razor.cs b/app/MindWork AI Studio/Components/DirectChatLauncherForm.razor.cs
index e9c91f0a..bdd363ac 100644
--- a/app/MindWork AI Studio/Components/DirectChatLauncherForm.razor.cs
+++ b/app/MindWork AI Studio/Components/DirectChatLauncherForm.razor.cs
@@ -3,8 +3,9 @@ using Microsoft.AspNetCore.Components;
namespace AIStudio.Components;
///
-/// The selection a direct chat launcher needs: the workspace its chat is created in, and the
-/// provider, profile, chat template, and data sources that chat starts with.
+/// The selection a direct chat launcher needs: the workspace its chat is created in — or no
+/// workspace, for a disappearing chat — and the provider, profile, chat template, and data sources
+/// that chat starts with.
///
///
/// The Assistant Builder uses this form to describe a launcher it is about to generate, while the
@@ -15,7 +16,8 @@ public partial class DirectChatLauncherForm : MSGComponentBase
{
///
/// The name of the workspace the launcher opens its chat in. The workspace is created when it
- /// does not exist yet, hence this is a free-text field and not a workspace ID.
+ /// does not exist yet, hence this is a free-text field and not a workspace ID. An empty name is
+ /// a choice of its own: the launcher then opens a disappearing chat.
///
[Parameter]
public string WorkspaceName { get; set; } = string.Empty;
@@ -75,11 +77,9 @@ public partial class DirectChatLauncherForm : MSGComponentBase
public EventCallback> ToolIdsChanged { get; set; }
///
- /// Validates the workspace name. The hosts differ here: the Builder requires a name only while
- /// its launcher switch is on, whereas the settings dialog always requires one.
+ /// Whether the launcher currently describes a chat without a workspace.
///
- [Parameter]
- public Func? ValidateWorkspaceName { get; set; }
+ private bool OpensTemporaryChat => string.IsNullOrWhiteSpace(this.WorkspaceName);
private IReadOnlyList availableWorkspaces = [];
diff --git a/app/MindWork AI Studio/Dialogs/DirectChatLauncherSettingsDialog.razor b/app/MindWork AI Studio/Dialogs/DirectChatLauncherSettingsDialog.razor
index a7a82d72..1402f470 100644
--- a/app/MindWork AI Studio/Dialogs/DirectChatLauncherSettingsDialog.razor
+++ b/app/MindWork AI Studio/Dialogs/DirectChatLauncherSettingsDialog.razor
@@ -32,8 +32,7 @@
@bind-ProfileId="@this.profileId"
@bind-ChatTemplateId="@this.chatTemplateId"
@bind-DataSourceIds="@this.dataSourceIds"
- @bind-ToolIds="@this.toolIds"
- ValidateWorkspaceName="@this.ValidateWorkspaceName"/>
+ @bind-ToolIds="@this.toolIds"/>
diff --git a/app/MindWork AI Studio/Dialogs/DirectChatLauncherSettingsDialog.razor.cs b/app/MindWork AI Studio/Dialogs/DirectChatLauncherSettingsDialog.razor.cs
index ef5ac332..3a7cb0ea 100644
--- a/app/MindWork AI Studio/Dialogs/DirectChatLauncherSettingsDialog.razor.cs
+++ b/app/MindWork AI Studio/Dialogs/DirectChatLauncherSettingsDialog.razor.cs
@@ -152,7 +152,9 @@ public partial class DirectChatLauncherSettingsDialog : MSGComponentBase
//
// An empty selection means "use the chat defaults" and is left out of the plugin, whereas
- // the empty GUID explicitly selects no profile or no chat template:
+ // the empty GUID explicitly selects no profile or no chat template. Clearing the workspace
+ // name is a change of its own: the tile then opens a disappearing chat, and the writer
+ // switches the launch behavior accordingly.
//
return new(
this.workspaceName.Trim(),
@@ -248,8 +250,6 @@ public partial class DirectChatLauncherSettingsDialog : MSGComponentBase
private string? ValidateDescription(string value) => string.IsNullOrWhiteSpace(value) ? T("Please provide a description for this tile.") : null;
- private string? ValidateWorkspaceName(string value) => string.IsNullOrWhiteSpace(value) ? T("Please select or enter a workspace name for this tile.") : null;
-
private void Cancel() => this.MudDialog.Cancel();
private static Guid? ParseOptionalGuid(string value) => Guid.TryParse(value, out var parsed) ? parsed : null;