From 6e559145ef0da16f94e5110990d2bb41c4163a21 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Wed, 23 Sep 2026 09:36:02 +0200 Subject: [PATCH] Moved the rollback rules into the chat thread --- app/MindWork AI Studio/Chat/ChatThread.cs | 27 ++++++++++++++++--- .../Components/ChatComponent.razor.cs | 16 +++-------- 2 files changed, 27 insertions(+), 16 deletions(-) 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();