diff --git a/app/MindWork AI Studio/Chat/ChatThread.cs b/app/MindWork AI Studio/Chat/ChatThread.cs
index 48be445a..466fbe44 100644
--- a/app/MindWork AI Studio/Chat/ChatThread.cs
+++ b/app/MindWork AI Studio/Chat/ChatThread.cs
@@ -351,11 +351,30 @@ public sealed record ChatThread
}
///
- /// Removes every content block after the selected content in conversation order.
+ /// Rolls this chat thread back, so that the given content becomes the last block of the conversation.
///
+ ///
+ /// Every later block is removed in conversation order, which is the order of the time stamps and
+ /// the order in which the chat shows the blocks. That includes the blocks hidden from the user,
+ /// such as the prompts an assistant sends into a chat: the user can neither see nor remove them,
+ /// so leaving them behind would continue the chat with messages nobody knows about. Hidden blocks
+ /// before the content stay, e.g. the example conversation of a chat template. The managed
+ /// transcripts of the removed blocks are deleted with them.
+ ///
+ /// The augmented data and the AI-selected data sources are reset, too. Both describe the last
+ /// retrieval, not a certain message, so after a rollback nobody knows whether they belong to a
+ /// kept or to a removed one. The next message with active data sources retrieves anew; without
+ /// active data sources, the chat continues without this context. The data source options stay,
+ /// because they are the user's choice rather than the result of a message.
+ ///
+ /// What stays as well is everything the thread ratchets for security reasons, namely the data
+ /// security and the required provider confidence. Both only ever tighten, because the data which
+ /// raised them was seen by this thread. Removing the message that brought it in does not unsee
+ /// it, so the chat keeps demanding the same of every provider which continues it.
+ ///
/// The content to keep as the last block.
- /// True when one or more later blocks were removed.
- public bool RemoveBlocksAfter(IContent content)
+ /// True when one or more later blocks were removed. False when the content is unknown or already the last block; the thread stays unchanged then.
+ public bool RollBackTo(IContent content)
{
var sortedBlocks = this.Blocks.OrderBy(x => x.Time).ToList();
var blockIndex = sortedBlocks.FindIndex(block => ReferenceEquals(block.Content, content));
@@ -368,6 +387,8 @@ public sealed record ChatThread
this.Blocks.Remove(block);
}
+ this.AugmentedData = string.Empty;
+ this.AISelectedDataSources = [];
return true;
}
diff --git a/app/MindWork AI Studio/Components/ChatComponent.razor.cs b/app/MindWork AI Studio/Components/ChatComponent.razor.cs
index 3b331f73..a28509f1 100644
--- a/app/MindWork AI Studio/Components/ChatComponent.razor.cs
+++ b/app/MindWork AI Studio/Components/ChatComponent.razor.cs
@@ -1463,21 +1463,11 @@ public partial class ChatComponent : MSGComponentBase
if (this.ChatThread is null || this.IsCurrentChatStreaming)
return;
- if (!this.ChatThread.RemoveBlocksAfter(aiBlock))
+ // Which parts of the thread a rollback resets and which it keeps is documented at RollBackTo:
+ if (!this.ChatThread.RollBackTo(aiBlock))
return;
- //
- // Only the working state of the next turn is reset here: the augmented data and the
- // AI-selected data sources are rebuilt by the RAG process anyway, so carrying the ones of a
- // removed message over would just put stale context into the system prompt.
- //
- // What stays is everything the thread ratchets for security reasons, namely DataSecurity and
- // RequiredProviderConfidence. Both only ever tighten, because the data which raised them was
- // seen by this thread. Removing the message that brought it in does not unsee it, so the
- // chat keeps demanding the same of every provider which continues it.
- //
- this.ChatThread.AugmentedData = string.Empty;
- this.ChatThread.AISelectedDataSources = [];
+ // The rollback reset the AI-selected data sources, which the data source selection still shows:
this.dataSourceSelectionComponent?.ChangeOptionWithoutSaving(this.ChatThread.DataSourceOptions, this.ChatThread.AISelectedDataSources);
this.hasUnsavedChanges = true;
await this.SaveThread();