From cd6a3f1daa0f29c34c09b164a7d8111a7b720bf9 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 14 Sep 2026 10:57:23 +0200 Subject: [PATCH] Tell the user when an answer was created without their data sources --- .../Assistants/I18N/allTexts.lua | 15 +++++++++++++++ app/MindWork AI Studio/Chat/ContentText.cs | 16 ++++++++++++++++ .../Tools/AIJobs/AIJobService.cs | 6 ++++++ .../RAG/AugmentationProcesses/AugmentationOne.cs | 9 +++++++++ .../RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs | 9 +++++++++ 5 files changed, 55 insertions(+) diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua index 8ce182ea..2a19b77f 100644 --- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua +++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua @@ -3346,6 +3346,9 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T3267850764"] = "The selected mode -- We could load models from '{0}', but the provider did not return any usable text models. UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T3378120620"] = "We could load models from '{0}', but the provider did not return any usable text models." +-- Your data sources could not be used. This answer was created without them. +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T373499115"] = "Your data sources could not be used. This answer was created without them." + -- The local image file does not exist. Skipping the image. UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T255679918"] = "The local image file does not exist. Skipping the image." @@ -10462,6 +10465,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::AIJOBS::AIJOBSERVICE::T3267850764"] = "The sel -- We could load models from '{0}', but the provider did not return any usable text models. UI_TEXT_CONTENT["AISTUDIO::TOOLS::AIJOBS::AIJOBSERVICE::T3378120620"] = "We could load models from '{0}', but the provider did not return any usable text models." +-- Your data sources could not be used. This answer was created without them. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::AIJOBS::AIJOBSERVICE::T373499115"] = "Your data sources could not be used. This answer was created without them." + -- Software Development UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T1025369409"] = "Software Development" @@ -11566,15 +11572,24 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::PLUGINSYSTEM::PLUGINTYPEEXTENSIONS::T335338363 -- Standard augmentation process UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::AUGMENTATIONPROCESSES::AUGMENTATIONONE::T1072508429"] = "Standard augmentation process" +-- No provider is trusted enough to check which passages fit your question. This answer uses all passages that were found. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::AUGMENTATIONPROCESSES::AUGMENTATIONONE::T2710880477"] = "No provider is trusted enough to check which passages fit your question. This answer uses all passages that were found." + -- This is the standard augmentation process, which uses all retrieval contexts to augment the chat thread. UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::AUGMENTATIONPROCESSES::AUGMENTATIONONE::T3240406069"] = "This is the standard augmentation process, which uses all retrieval contexts to augment the chat thread." +-- The check of which passages fit your question failed. This answer uses all passages that were found. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::AUGMENTATIONPROCESSES::AUGMENTATIONONE::T392269104"] = "The check of which passages fit your question failed. This answer uses all passages that were found." + -- Automatic AI data source selection with heuristik source reduction UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::DATASOURCESELECTIONPROCESSES::AGENTICSRCSELWITHDYNHEUR::T2339257645"] = "Automatic AI data source selection with heuristik source reduction" -- Automatically selects the appropriate data sources based on the last prompt. Applies a heuristic reduction at the end to reduce the number of data sources. UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::DATASOURCESELECTIONPROCESSES::AGENTICSRCSELWITHDYNHEUR::T648937779"] = "Automatically selects the appropriate data sources based on the last prompt. Applies a heuristic reduction at the end to reduce the number of data sources." +-- None of your selected data sources is available for the chosen provider. This answer was created without them. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::RAGPROCESSES::AISRCSELWITHRETCTXVAL::T1696726639"] = "None of your selected data sources is available for the chosen provider. This answer was created without them." + -- This RAG process filters data sources, automatically selects appropriate sources, optionally allows manual source selection, retrieves data, and automatically validates the retrieval context. UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::RAGPROCESSES::AISRCSELWITHRETCTXVAL::T3047786484"] = "This RAG process filters data sources, automatically selects appropriate sources, optionally allows manual source selection, retrieves data, and automatically validates the retrieval context." diff --git a/app/MindWork AI Studio/Chat/ContentText.cs b/app/MindWork AI Studio/Chat/ContentText.cs index 0640b658..d86424cb 100644 --- a/app/MindWork AI Studio/Chat/ContentText.cs +++ b/app/MindWork AI Studio/Chat/ContentText.cs @@ -85,9 +85,25 @@ public sealed class ContentText : IContent var rag = new AISrcSelWithRetCtxVal(); chatThread = await rag.ProcessAsync(provider, lastUserPrompt, chatThread, token); } + catch (OperationCanceledException) when (token.IsCancellationRequested) + { + // + // The user canceled the request. That is not an error, and it must not reach the + // user as one. We do not rethrow here: the streaming task below observes the same + // token and ends the request itself, which keeps its finally block intact. That + // block is what tells the UI that the streaming is over. + // + LOGGER.LogInformation("The RAG process was canceled before the answer was requested."); + } catch (Exception e) { LOGGER.LogError(e, "Skipping the RAG process due to an error."); + + // + // The answer is about to be created without the data the user expected it to use. + // Without this message, that answer is indistinguishable from one that did use it: + // + await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.Source, TB("Your data sources could not be used. This answer was created without them."))); } } diff --git a/app/MindWork AI Studio/Tools/AIJobs/AIJobService.cs b/app/MindWork AI Studio/Tools/AIJobs/AIJobService.cs index 76c76454..e48747da 100644 --- a/app/MindWork AI Studio/Tools/AIJobs/AIJobService.cs +++ b/app/MindWork AI Studio/Tools/AIJobs/AIJobService.cs @@ -240,6 +240,12 @@ public sealed class AIJobService(SettingsManager settingsManager, MessageBus mes catch (Exception e) { logger.LogError(e, "Skipping the RAG process due to an error."); + + // + // The answer is about to be created without the data the user expected it to use. + // Without this message, that answer is indistinguishable from one that did use it: + // + await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.Source, TB("Your data sources could not be used. This answer was created without them."))); } token.ThrowIfCancellationRequested(); diff --git a/app/MindWork AI Studio/Tools/RAG/AugmentationProcesses/AugmentationOne.cs b/app/MindWork AI Studio/Tools/RAG/AugmentationProcesses/AugmentationOne.cs index 1e04ce16..97ebb1b5 100644 --- a/app/MindWork AI Studio/Tools/RAG/AugmentationProcesses/AugmentationOne.cs +++ b/app/MindWork AI Studio/Tools/RAG/AugmentationProcesses/AugmentationOne.cs @@ -70,10 +70,19 @@ public sealed class AugmentationOne : IAugmentationProcess catch (Exception exception) { LOGGER.LogError(exception, "Retrieval context validation failed. Continuing augmentation with all retrieved contexts."); + + // + // The user switched this check on. Continuing without it silently would hide + // that the answer rests on unfiltered passages: + // + await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.FactCheck, TB("The check of which passages fit your question failed. This answer uses all passages that were found."))); } } else + { LOGGER.LogWarning("Skipping retrieval context validation because no sufficiently trusted validation agent provider is available. Continuing augmentation with all retrieved contexts."); + await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.FactCheck, TB("No provider is trusted enough to check which passages fit your question. This answer uses all passages that were found."))); + } } LOGGER.LogInformation($"Starting the augmentation process over {retrievalContexts.Count:###,###,###,###} of {numTotalRetrievalContexts:###,###,###,###} retrieved contexts."); diff --git a/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs b/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs index ed0ea76d..a93f28c6 100644 --- a/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs +++ b/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs @@ -106,6 +106,15 @@ public sealed class AISrcSelWithRetCtxVal : IRagProcess { LOGGER.LogWarning("No data sources are selected. The RAG process is skipped."); proceedWithRAG = false; + + // + // When the user picked the sources, none of them survived the security and + // confidence checks. That is worth saying out loud: the user chose them and + // expects this answer to use them. When the AI picked instead, finding nothing + // suitable for this prompt is a normal outcome and stays in the log. + // + if(!chatThread.DataSourceOptions.AutomaticDataSourceSelection) + await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.Source, TB("None of your selected data sources is available for the chosen provider. This answer was created without them."))); } else {