Added a Send to menu to every chat message and kept restrictions when sending content on (#1124)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-10-28 13:28:30 +01:00
1 parent d06688ca08
commit bf54b8cd0d
73 files changed
+1923 -390

No files matched your search

@@ -141,6 +141,25 @@ public partial class ContentBlockComponent : MSGComponentBase
[Parameter]
public bool AddsAIGeneratedContentDisclosure { get; set; } = true;
/// <summary>
/// Sends the text of this block to the given assistant, or into a new chat.
/// </summary>
/// <remarks>
/// Null hides the menu for it. An assistant shows its result with this block as well, and it offers
/// sending the result through its own footer instead.
/// </remarks>
[Parameter]
public Func<IContent, Tools.Components, Task>? SendToFunc { get; set; }
/// <summary>
/// The assistants and the chat the menu offers, in its order, see AssistantLaunchService.GetDestinationsFor.
/// </summary>
/// <remarks>
/// Whoever passes SendToFunc passes them as well, so that a chat asks for them once for all of its blocks.
/// </remarks>
[Parameter]
public IReadOnlyList<Tools.Components> SendToDestinations { get; set; } = [];
[Inject]
private IDialogService DialogService { get; init; } = null!;
@@ -199,6 +218,21 @@ public partial class ContentBlockComponent : MSGComponentBase
/// </remarks>
private bool CanSaveCodeBlocks => this.Role is ChatRole.AI or ChatRole.USER && this.CanExport;
/// <summary>
/// Whether this block offers its text to an assistant or a new chat.
/// </summary>
private bool CanSendTo => this.SendToFunc is not null && this.SendToDestinations.Count > 0 && this.Role is ChatRole.AI or ChatRole.USER && this.Content is ContentText;
/// <summary>
/// Whether the text of this block can be sent right now.
/// </summary>
/// <remarks>
/// Like the export, the menu waits for the stream to finish: half an answer is nothing anybody wants
/// to continue with. Sending changes nothing in this chat, so an answer written meanwhile for another
/// block does not stand in the way.
/// </remarks>
private bool IsSendToEnabled => this.Content is ContentText { InitialRemoteWait: false, IsStreaming: false } text && !string.IsNullOrWhiteSpace(text.Text);
/// <summary>
/// Whether this block leaves AI Studio with the notice that AI generated it, when that is switched on.
/// </summary>
@@ -420,6 +454,10 @@ public partial class ContentBlockComponent : MSGComponentBase
hash.Add(this.Content.IsStreaming);
hash.Add(this.Content.FileAttachments.Count);
hash.Add(this.Content.Sources.Count);
hash.Add(this.SendToFunc is not null);
hash.Add(this.SendToDestinations.Count);
foreach (var destination in this.SendToDestinations)
hash.Add(destination);
switch (this.Content)
{
@@ -836,6 +874,14 @@ public partial class ContentBlockComponent : MSGComponentBase
if (remove.HasValue && remove.Value)
await this.RemoveBlockFunc(this.Content);
}
private async Task SendTo(Tools.Components destination)
{
if (this.SendToFunc is null || !this.IsSendToEnabled)
return;
await this.SendToFunc(this.Content, destination);
}
/// <summary>
/// Exports the entire message, ending with the notice that AI generated it when that is switched on.