From 28b0deb318ec9cf873c74dcc0a4459219ad2dcef Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 10 Feb 2025 18:47:00 +0100 Subject: [PATCH] Pass the last user prompt to CreateFromProviderAsync calls to enable RAG support --- app/MindWork AI Studio/Agents/AgentBase.cs | 14 +++++++++----- .../Assistants/AssistantBase.razor.cs | 13 ++++++++----- app/MindWork AI Studio/Chat/ContentImage.cs | 2 +- app/MindWork AI Studio/Chat/ContentText.cs | 2 +- app/MindWork AI Studio/Chat/IContent.cs | 2 +- .../Components/ChatComponent.razor.cs | 15 ++++++++++----- app/MindWork AI Studio/Pages/Writer.razor.cs | 14 ++++++++------ 7 files changed, 38 insertions(+), 24 deletions(-) diff --git a/app/MindWork AI Studio/Agents/AgentBase.cs b/app/MindWork AI Studio/Agents/AgentBase.cs index 8028a864..639fa99c 100644 --- a/app/MindWork AI Studio/Agents/AgentBase.cs +++ b/app/MindWork AI Studio/Agents/AgentBase.cs @@ -13,6 +13,8 @@ public abstract class AgentBase(ILogger logger, SettingsManager setti protected ThreadSafeRandom RNG { get; init; } = rng; protected ILogger Logger { get; init; } = logger; + + protected IContent? lastUserPrompt; /// /// Represents the type or category of this agent. @@ -63,15 +65,17 @@ public abstract class AgentBase(ILogger logger, SettingsManager setti protected DateTimeOffset AddUserRequest(ChatThread thread, string request) { var time = DateTimeOffset.Now; + this.lastUserPrompt = new ContentText + { + Text = request, + }; + thread.Blocks.Add(new ContentBlock { Time = time, ContentType = ContentType.TEXT, Role = ChatRole.USER, - Content = new ContentText - { - Text = request, - }, + Content = this.lastUserPrompt, }); return time; @@ -103,6 +107,6 @@ public abstract class AgentBase(ILogger logger, SettingsManager setti // Use the selected provider to get the AI response. // By awaiting this line, we wait for the entire // content to be streamed. - await aiText.CreateFromProviderAsync(providerSettings.CreateProvider(this.Logger), this.SettingsManager, providerSettings.Model, thread); + await aiText.CreateFromProviderAsync(providerSettings.CreateProvider(this.Logger), this.SettingsManager, providerSettings.Model, this.lastUserPrompt, thread); } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs index 8e5b60df..63867ff6 100644 --- a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs +++ b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs @@ -97,6 +97,7 @@ public abstract partial class AssistantBase : ComponentBase, IMessageBusReceiver protected bool inputIsValid; protected Profile currentProfile = Profile.NO_PROFILE; protected ChatThread? chatThread; + protected IContent? lastUserPrompt; private readonly Timer formChangeTimer = new(TimeSpan.FromSeconds(1.6)); @@ -242,16 +243,18 @@ public abstract partial class AssistantBase : ComponentBase, IMessageBusReceiver protected DateTimeOffset AddUserRequest(string request, bool hideContentFromUser = false) { var time = DateTimeOffset.Now; + this.lastUserPrompt = new ContentText + { + Text = request, + }; + this.chatThread!.Blocks.Add(new ContentBlock { Time = time, ContentType = ContentType.TEXT, HideFromUser = hideContentFromUser, Role = ChatRole.USER, - Content = new ContentText - { - Text = request, - }, + Content = this.lastUserPrompt, }); return time; @@ -287,7 +290,7 @@ public abstract partial class AssistantBase : ComponentBase, IMessageBusReceiver // Use the selected provider to get the AI response. // By awaiting this line, we wait for the entire // content to be streamed. - await aiText.CreateFromProviderAsync(this.providerSettings.CreateProvider(this.Logger), this.SettingsManager, this.providerSettings.Model, this.chatThread); + await aiText.CreateFromProviderAsync(this.providerSettings.CreateProvider(this.Logger), this.SettingsManager, this.providerSettings.Model, this.lastUserPrompt, this.chatThread); this.isProcessing = false; this.StateHasChanged(); diff --git a/app/MindWork AI Studio/Chat/ContentImage.cs b/app/MindWork AI Studio/Chat/ContentImage.cs index 84df02fc..3a5fbd16 100644 --- a/app/MindWork AI Studio/Chat/ContentImage.cs +++ b/app/MindWork AI Studio/Chat/ContentImage.cs @@ -29,7 +29,7 @@ public sealed class ContentImage : IContent public Func StreamingEvent { get; set; } = () => Task.CompletedTask; /// - public Task CreateFromProviderAsync(IProvider provider, SettingsManager settings, Model chatModel, ChatThread chatChatThread, CancellationToken token = default) + public Task CreateFromProviderAsync(IProvider provider, SettingsManager settings, Model chatModel, IContent? lastPrompt, ChatThread? chatChatThread, CancellationToken token = default) { throw new NotImplementedException(); } diff --git a/app/MindWork AI Studio/Chat/ContentText.cs b/app/MindWork AI Studio/Chat/ContentText.cs index f7cc62f6..47c0533d 100644 --- a/app/MindWork AI Studio/Chat/ContentText.cs +++ b/app/MindWork AI Studio/Chat/ContentText.cs @@ -35,7 +35,7 @@ public sealed class ContentText : IContent public Func StreamingEvent { get; set; } = () => Task.CompletedTask; /// - public async Task CreateFromProviderAsync(IProvider provider, SettingsManager settings, Model chatModel, ChatThread? chatThread, CancellationToken token = default) + public async Task CreateFromProviderAsync(IProvider provider, SettingsManager settings, Model chatModel, IContent? lastPrompt, ChatThread? chatThread, CancellationToken token = default) { if(chatThread is null) return; diff --git a/app/MindWork AI Studio/Chat/IContent.cs b/app/MindWork AI Studio/Chat/IContent.cs index 1feea520..987bada0 100644 --- a/app/MindWork AI Studio/Chat/IContent.cs +++ b/app/MindWork AI Studio/Chat/IContent.cs @@ -42,5 +42,5 @@ public interface IContent /// /// Uses the provider to create the content. /// - public Task CreateFromProviderAsync(IProvider provider, SettingsManager settings, Model chatModel, ChatThread chatChatThread, CancellationToken token = default); + public Task CreateFromProviderAsync(IProvider provider, SettingsManager settings, Model chatModel, IContent? lastPrompt, ChatThread? chatChatThread, CancellationToken token = default); } \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/ChatComponent.razor.cs b/app/MindWork AI Studio/Components/ChatComponent.razor.cs index 5a10625e..466d2107 100644 --- a/app/MindWork AI Studio/Components/ChatComponent.razor.cs +++ b/app/MindWork AI Studio/Components/ChatComponent.razor.cs @@ -295,8 +295,14 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable } var time = DateTimeOffset.Now; + IContent? lastUserPrompt; if (!reuseLastUserPrompt) { + lastUserPrompt = new ContentText + { + Text = this.userInput, + }; + // // Add the user message to the thread: // @@ -305,10 +311,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable Time = time, ContentType = ContentType.TEXT, Role = ChatRole.USER, - Content = new ContentText - { - Text = this.userInput, - }, + Content = lastUserPrompt, }); // Save the chat: @@ -319,6 +322,8 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable this.StateHasChanged(); } } + else + lastUserPrompt = this.ChatThread.Blocks.Last(x => x.Role is ChatRole.USER).Content; // // Add the AI response to the thread: @@ -360,7 +365,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable // Use the selected provider to get the AI response. // By awaiting this line, we wait for the entire // content to be streamed. - await aiText.CreateFromProviderAsync(this.Provider.CreateProvider(this.Logger), this.SettingsManager, this.Provider.Model, this.ChatThread, this.cancellationTokenSource.Token); + await aiText.CreateFromProviderAsync(this.Provider.CreateProvider(this.Logger), this.SettingsManager, this.Provider.Model, lastUserPrompt, this.ChatThread, this.cancellationTokenSource.Token); } this.cancellationTokenSource = null; diff --git a/app/MindWork AI Studio/Pages/Writer.razor.cs b/app/MindWork AI Studio/Pages/Writer.razor.cs index 58160745..60280d1e 100644 --- a/app/MindWork AI Studio/Pages/Writer.razor.cs +++ b/app/MindWork AI Studio/Pages/Writer.razor.cs @@ -106,17 +106,19 @@ public partial class Writer : MSGComponentBase, IAsyncDisposable }; var time = DateTimeOffset.Now; + var lastUserPrompt = new ContentText + { + // We use the maximum 160 characters from the end of the text: + Text = this.userInput.Length > 160 ? this.userInput[^160..] : this.userInput, + }; + this.chatThread.Blocks.Clear(); this.chatThread.Blocks.Add(new ContentBlock { Time = time, ContentType = ContentType.TEXT, Role = ChatRole.USER, - Content = new ContentText - { - // We use the maximum 160 characters from the end of the text: - Text = this.userInput.Length > 160 ? this.userInput[^160..] : this.userInput, - }, + Content = lastUserPrompt, }); var aiText = new ContentText @@ -137,7 +139,7 @@ public partial class Writer : MSGComponentBase, IAsyncDisposable this.isStreaming = true; this.StateHasChanged(); - await aiText.CreateFromProviderAsync(this.providerSettings.CreateProvider(this.Logger), this.SettingsManager, this.providerSettings.Model, this.chatThread); + await aiText.CreateFromProviderAsync(this.providerSettings.CreateProvider(this.Logger), this.SettingsManager, this.providerSettings.Model, lastUserPrompt, this.chatThread); this.suggestion = aiText.Text; this.isStreaming = false;