From 2ff29b0d4d22e6563cb1d20c2688f563154c0f5c Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Thu, 9 Jul 2026 13:07:11 +0200 Subject: [PATCH] Improved the "My Tasks Assistant": you can now provide one or more documents in addition to text (#842) --- .../Assistants/I18N/allTexts.lua | 22 ++-- .../Assistants/MyTasks/AssistantMyTasks.razor | 7 ++ .../MyTasks/AssistantMyTasks.razor.cs | 100 ++++++++++++++++-- .../plugin.lua | 22 ++-- .../plugin.lua | 22 ++-- .../wwwroot/changelog/v26.7.3.md | 1 + 6 files changed, 140 insertions(+), 34 deletions(-) diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua index 5695fea0..3358d2b1 100644 --- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua +++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua @@ -1630,23 +1630,29 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LEGALCHECK::ASSISTANTLEGALCHECK::T4254597 -- Ask your questions UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LEGALCHECK::ASSISTANTLEGALCHECK::T467099852"] = "Ask your questions" --- Analyze the following text and extract my tasks: -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1349891364"] = "Analyze the following text and extract my tasks:" +-- You can enter text, attach one or more documents, or use both. At least one input is required. +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1442535450"] = "You can enter text, attach one or more documents, or use both. At least one input is required." --- Please provide some text as input. For example, an email. -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1962809521"] = "Please provide some text as input. For example, an email." +-- Please provide some text or at least one valid document as input. For example, an email. +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1635845349"] = "Please provide some text or at least one valid document as input. For example, an email." --- Analyze text -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T2268303626"] = "Analyze text" +-- You received a cryptic email or document that was sent to many recipients and you are now wondering if you need to do something? Copy the text into the input field, attach one or more documents, or use both. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be. +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1918551346"] = "You received a cryptic email or document that was sent to many recipients and you are now wondering if you need to do something? Copy the text into the input field, attach one or more documents, or use both. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be." -- Target language UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T237828418"] = "Target language" +-- Analyze the following text and/or attached documents and extract my tasks: +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T2535924263"] = "Analyze the following text and/or attached documents and extract my tasks:" + -- My Tasks UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3011450657"] = "My Tasks" --- You received a cryptic email that was sent to many recipients and you are now wondering if you need to do something? Copy the email into the input field. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be. -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3646084045"] = "You received a cryptic email that was sent to many recipients and you are now wondering if you need to do something? Copy the email into the input field. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be." +-- Analyze content +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3334965934"] = "Analyze content" + +-- Attach documents +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3666048746"] = "Attach documents" -- Custom target language UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3848935911"] = "Custom target language" diff --git a/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor b/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor index 18b2d5c2..4a738ef7 100644 --- a/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor +++ b/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor @@ -3,5 +3,12 @@ +@T("Attach documents") + + @T("You can enter text, attach one or more documents, or use both. At least one input is required.") + +
+ +
\ No newline at end of file diff --git a/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor.cs b/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor.cs index 18b25880..f66a7bb4 100644 --- a/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor.cs +++ b/app/MindWork AI Studio/Assistants/MyTasks/AssistantMyTasks.razor.cs @@ -1,3 +1,4 @@ +using AIStudio.Chat; using AIStudio.Dialogs.Settings; using AIStudio.Settings; using AIStudio.Tools.AssistantSessions; @@ -10,34 +11,84 @@ public partial class AssistantMyTasks : AssistantBaseCore protected override string Title => T("My Tasks"); - protected override string Description => T("You received a cryptic email that was sent to many recipients and you are now wondering if you need to do something? Copy the email into the input field. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be."); + protected override string Description => T("You received a cryptic email or document that was sent to many recipients and you are now wondering if you need to do something? Copy the text into the input field, attach one or more documents, or use both. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be."); protected override string SystemPrompt => $""" You are a friendly and professional business expert. You receive business emails, protocols, - reports, etc. as input. Additionally, you know the user's role in the organization. The user - wonders if any tasks arise for them in their role based on the text. You now try to give hints - and advice on whether and what the user should do. When you believe there are no tasks for the - user, you tell them this. You consider typical business etiquette in your advice. + reports, etc. as text input and/or attached documents. Additionally, you know the user's role + in the organization. The user wonders if any tasks arise for them in their role based on the + provided content. You now try to give hints and advice on whether and what the user should do. + When you believe there are no tasks for the user, you tell them this. You consider typical + business etiquette in your advice. You write your advice in the following language: {this.SystemPromptLanguage()}. """; protected override IReadOnlyList FooterButtons => []; - protected override string SubmitText => T("Analyze text"); + protected override string SubmitText => T("Analyze content"); protected override Func SubmitAction => this.AnalyzeText; protected override bool ShowProfileSelection => false; - protected override string SendToChatVisibleUserPromptPrefix => T("Analyze the following text and extract my tasks:"); + protected override string SendToChatVisibleUserPromptPrefix => T("Analyze the following text and/or attached documents and extract my tasks:"); protected override string SendToChatVisibleUserPromptContent => this.inputText; + protected override ChatThread ConvertToChatThread + { + get + { + var originalChatThread = this.ChatThread ?? new ChatThread(); + if (string.IsNullOrWhiteSpace(this.SendToChatVisibleUserPromptText)) + { + return originalChatThread with + { + SystemPrompt = SystemPrompts.DEFAULT, + }; + } + + var earliestBlock = originalChatThread.Blocks.MinBy(x => x.Time); + var visiblePromptTime = earliestBlock is null + ? DateTimeOffset.Now + : earliestBlock.Time == DateTimeOffset.MinValue + ? earliestBlock.Time + : earliestBlock.Time.AddTicks(-1); + + var transferredBlocks = originalChatThread.Blocks + .Select(block => block.Role is ChatRole.USER + ? this.CloneHiddenUserBlockWithoutAttachments(block) + : block.DeepClone()) + .ToList(); + + transferredBlocks.Insert(0, new ContentBlock + { + Time = visiblePromptTime, + ContentType = ContentType.TEXT, + HideFromUser = false, + Role = ChatRole.USER, + Content = new ContentText + { + Text = this.SendToChatVisibleUserPromptText, + FileAttachments = this.loadedDocumentPaths.ToList(), + }, + }); + + return originalChatThread with + { + ChatId = Guid.NewGuid(), + SystemPrompt = SystemPrompts.DEFAULT, + Blocks = transferredBlocks, + }; + } + } + protected override void ResetForm() { this.inputText = string.Empty; + this.loadedDocumentPaths.Clear(); if (!this.MightPreselectValues()) { this.selectedTargetLanguage = CommonLanguages.AS_IS; @@ -58,9 +109,11 @@ public partial class AssistantMyTasks : AssistantBaseCore } private string inputText = string.Empty; + private HashSet loadedDocumentPaths = []; private CommonLanguages selectedTargetLanguage = CommonLanguages.AS_IS; private string customTargetLanguage = string.Empty; private static readonly AssistantSessionStateKey INPUT_TEXT_STATE_KEY = new(nameof(inputText)); + private static readonly AssistantSessionStateKey> LOADED_DOCUMENT_PATHS_STATE_KEY = new(nameof(loadedDocumentPaths)); private static readonly AssistantSessionStateKey SELECTED_TARGET_LANGUAGE_STATE_KEY = new(nameof(selectedTargetLanguage)); private static readonly AssistantSessionStateKey CUSTOM_TARGET_LANGUAGE_STATE_KEY = new(nameof(customTargetLanguage)); @@ -68,6 +121,7 @@ public partial class AssistantMyTasks : AssistantBaseCore protected override void CaptureCustomAssistantSessionState(AssistantSessionStateWriter state) { state.Set(INPUT_TEXT_STATE_KEY, this.inputText); + state.SetHashSet(LOADED_DOCUMENT_PATHS_STATE_KEY, this.loadedDocumentPaths); state.Set(SELECTED_TARGET_LANGUAGE_STATE_KEY, this.selectedTargetLanguage); state.Set(CUSTOM_TARGET_LANGUAGE_STATE_KEY, this.customTargetLanguage); } @@ -76,6 +130,7 @@ public partial class AssistantMyTasks : AssistantBaseCore protected override void RestoreCustomAssistantSessionState(AssistantSessionStateReader state) { state.Restore(INPUT_TEXT_STATE_KEY, value => this.inputText = value); + state.RestoreHashSet(LOADED_DOCUMENT_PATHS_STATE_KEY, this.loadedDocumentPaths); state.Restore(SELECTED_TARGET_LANGUAGE_STATE_KEY, value => this.selectedTargetLanguage = value); state.Restore(CUSTOM_TARGET_LANGUAGE_STATE_KEY, value => this.customTargetLanguage = value); } @@ -95,12 +150,20 @@ public partial class AssistantMyTasks : AssistantBaseCore private string? ValidatingText(string text) { - if(string.IsNullOrWhiteSpace(text)) - return T("Please provide some text as input. For example, an email."); + if(string.IsNullOrWhiteSpace(text) && !this.HasValidInputDocuments()) + return T("Please provide some text or at least one valid document as input. For example, an email."); return null; } + private bool HasValidInputDocuments() => this.loadedDocumentPaths.Any(n => n is { Exists: true, IsValid: true }); + + private async Task OnDocumentsChanged(HashSet _) + { + if(this.Form is not null) + await this.Form.Validate(); + } + private string? ValidateProfile(Profile profile) { if(profile == Profile.NO_PROFILE) @@ -127,6 +190,23 @@ public partial class AssistantMyTasks : AssistantBaseCore return this.selectedTargetLanguage.Name(); } + + private ContentBlock CloneHiddenUserBlockWithoutAttachments(ContentBlock block) + { + var clone = block.DeepClone(changeHideState: true); + if (clone.Content is ContentText text) + text.FileAttachments = []; + + return clone; + } + + private string BuildUserRequest() + { + if(!string.IsNullOrWhiteSpace(this.inputText)) + return this.inputText; + + return "Analyze the attached document(s) and extract my tasks."; + } private async Task AnalyzeText() { @@ -135,7 +215,7 @@ public partial class AssistantMyTasks : AssistantBaseCore return; this.CreateChatThread(); - var time = this.AddUserRequest(this.inputText); + var time = this.AddUserRequest(this.BuildUserRequest(), false, this.loadedDocumentPaths.ToList()); await this.AddAIResponseAsync(time); } diff --git a/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua b/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua index acb8b91b..5af93419 100644 --- a/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua +++ b/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua @@ -1632,23 +1632,29 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LEGALCHECK::ASSISTANTLEGALCHECK::T4254597 -- Ask your questions UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LEGALCHECK::ASSISTANTLEGALCHECK::T467099852"] = "Stellen Sie ihre Fragen" --- Analyze the following text and extract my tasks: -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1349891364"] = "Analysiere den folgenden Text und extrahiere meine Aufgaben:" +-- You can enter text, attach one or more documents, or use both. At least one input is required. +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1442535450"] = "Sie können Text eingeben, ein oder mehrere Dokumente anhängen oder beides verwenden. Mindestens eine Eingabe ist erforderlich." --- Please provide some text as input. For example, an email. -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1962809521"] = "Bitte geben Sie einen Text ein. Zum Beispiel eine E-Mail." +-- Please provide some text or at least one valid document as input. For example, an email. +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1635845349"] = "Bitte geben Sie einen Text oder mindestens ein gültiges Dokument als Eingabe an. Zum Beispiel eine E-Mail." --- Analyze text -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T2268303626"] = "Text analysieren" +-- You received a cryptic email or document that was sent to many recipients and you are now wondering if you need to do something? Copy the text into the input field, attach one or more documents, or use both. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be. +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1918551346"] = "Sie haben eine kryptische E-Mail oder ein Dokument erhalten, das an viele Empfänger gesendet wurde, und fragen sich nun, ob Sie etwas tun müssen? Kopieren Sie den Text in das Eingabefeld, fügen Sie ein oder mehrere Dokumente an oder nutzen Sie beides. Außerdem müssen Sie ein persönliches Profil auswählen. In diesem Profil sollten Sie Ihre Rolle in der Organisation beschreiben. Die KI wird dann versuchen, Ihnen Hinweise darauf zu geben, welche Aufgaben Sie möglicherweise haben." -- Target language UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T237828418"] = "Zielsprache" +-- Analyze the following text and/or attached documents and extract my tasks: +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T2535924263"] = "Analysiere den folgenden Text und/oder die angehängten Dokumente und extrahiere meine Aufgaben:" + -- My Tasks UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3011450657"] = "Meine Aufgaben" --- You received a cryptic email that was sent to many recipients and you are now wondering if you need to do something? Copy the email into the input field. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be. -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3646084045"] = "Sie haben eine rätselhafte E-Mail erhalten, die an viele Empfänger verschickt wurde, und fragen sich nun, ob Sie etwas unternehmen müssen? Kopieren Sie die E-Mail in das Eingabefeld. Außerdem müssen Sie ein persönliches Profil auswählen. In diesem Profil sollten Sie ihre Rolle in der Organisation beschreiben. Die KI wird Ihnen dann Hinweise geben, welche Aufgaben für Sie daraus entstehen könnten." +-- Analyze content +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3334965934"] = "Inhalt analysieren" + +-- Attach documents +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3666048746"] = "Dokumente anhängen" -- Custom target language UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3848935911"] = "Benutzerdefinierte Zielsprache" diff --git a/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua b/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua index 77e7094c..39d4bec7 100644 --- a/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua +++ b/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua @@ -1632,23 +1632,29 @@ UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LEGALCHECK::ASSISTANTLEGALCHECK::T4254597 -- Ask your questions UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::LEGALCHECK::ASSISTANTLEGALCHECK::T467099852"] = "Ask your questions" --- Analyze the following text and extract my tasks: -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1349891364"] = "Analyze the following text and extract my tasks:" +-- You can enter text, attach one or more documents, or use both. At least one input is required. +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1442535450"] = "You can enter text, attach one or more documents, or use both. At least one input is required." --- Please provide some text as input. For example, an email. -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1962809521"] = "Please provide some text as input. For example, an email." +-- Please provide some text or at least one valid document as input. For example, an email. +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1635845349"] = "Please provide some text or at least one valid document as input. For example, an email." --- Analyze text -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T2268303626"] = "Analyze text" +-- You received a cryptic email or document that was sent to many recipients and you are now wondering if you need to do something? Copy the text into the input field, attach one or more documents, or use both. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be. +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T1918551346"] = "You received a cryptic email or document that was sent to many recipients and you are now wondering if you need to do something? Copy the text into the input field, attach one or more documents, or use both. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be." -- Target language UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T237828418"] = "Target language" +-- Analyze the following text and/or attached documents and extract my tasks: +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T2535924263"] = "Analyze the following text and/or attached documents and extract my tasks:" + -- My Tasks UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3011450657"] = "My Tasks" --- You received a cryptic email that was sent to many recipients and you are now wondering if you need to do something? Copy the email into the input field. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be. -UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3646084045"] = "You received a cryptic email that was sent to many recipients and you are now wondering if you need to do something? Copy the email into the input field. You also need to select a personal profile. In this profile, you should describe your role in the organization. The AI will then try to give you hints on what your tasks might be." +-- Analyze content +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3334965934"] = "Analyze content" + +-- Attach documents +UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3666048746"] = "Attach documents" -- Custom target language UI_TEXT_CONTENT["AISTUDIO::ASSISTANTS::MYTASKS::ASSISTANTMYTASKS::T3848935911"] = "Custom target language" diff --git a/app/MindWork AI Studio/wwwroot/changelog/v26.7.3.md b/app/MindWork AI Studio/wwwroot/changelog/v26.7.3.md index 032a5b1c..29fc7499 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v26.7.3.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v26.7.3.md @@ -1 +1,2 @@ # v26.7.3, build 245 (2026-07-xx xx:xx UTC) +- Improved the "My Tasks Assistant": you can now provide one or more documents in addition to text or use documents alone when asking to identify tasks. \ No newline at end of file