From 80eccca999d0312af78cd843481a127b99822284 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 14 Sep 2026 16:30:17 +0200 Subject: [PATCH] Sharpened the data source warnings and tightened the selection popovers (#971) --- .../Assistants/I18N/allTexts.lua | 9 +-- .../Components/DataSourceSelection.razor | 73 +++++++++++-------- .../Components/DataSourceSelection.razor.cs | 35 ++++++++- .../Components/DataSourceSelection.razor.css | 18 +++++ .../Components/MudTextSwitch.razor | 4 +- .../Components/MudTextSwitch.razor.cs | 15 ++++ .../Components/PreviewBeta.razor | 2 +- .../Components/PreviewBeta.razor.cs | 11 +++ .../Components/ToolSelection.razor | 10 ++- .../plugin.lua | 12 +++ .../plugin.lua | 12 +++ .../AugmentationProcesses/AugmentationOne.cs | 6 +- .../RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs | 17 ++--- app/MindWork AI Studio/wwwroot/app.css | 57 ++++++++++++--- .../wwwroot/changelog/v26.9.1.md | 5 +- 15 files changed, 220 insertions(+), 66 deletions(-) create mode 100644 app/MindWork AI Studio/Components/DataSourceSelection.razor.css diff --git a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua index 2a19b77f..e627bc01 100644 --- a/app/MindWork AI Studio/Assistants/I18N/allTexts.lua +++ b/app/MindWork AI Studio/Assistants/I18N/allTexts.lua @@ -3901,6 +3901,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T168406579"] = "AI-S -- AI-based data validation UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1744745490"] = "AI-based data validation" +-- These data sources are preselected, but cannot be used right now, either due to data privacy or confidence-level requirements, or because they are unavailable: +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1852534051"] = "These data sources are preselected, but cannot be used right now, either due to data privacy or confidence-level requirements, or because they are unavailable:" + -- Yes, I want to use data sources. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1975014927"] = "Yes, I want to use data sources." @@ -11572,9 +11575,6 @@ 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." @@ -11587,9 +11587,6 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::DATASOURCESELECTIONPROCESSES::AGENTICSRCS -- 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/Components/DataSourceSelection.razor b/app/MindWork AI Studio/Components/DataSourceSelection.razor index dfb1ba36..de7ae518 100644 --- a/app/MindWork AI Studio/Components/DataSourceSelection.razor +++ b/app/MindWork AI Studio/Components/DataSourceSelection.razor @@ -7,11 +7,11 @@ @if (this.PopoverTriggerMode is PopoverTriggerMode.ICON) { - + } else { - + @T("Select data") } @@ -19,13 +19,13 @@ - + - @T("Data Source Selection") + @@ -33,7 +33,7 @@ - + @if (this.waitingForDataSources) { @@ -42,7 +42,7 @@ } else if (this.SettingsManager.ConfigurationData.DataSources.Count == 0) { - + @T("You haven't configured any data sources. To grant the AI access to your data, you need to add such a source. However, if you wish to use data from your device, you first have to set up a so-called embedding. This embedding is necessary so the AI can effectively search your data, find and retrieve the correct information required for each task. In addition to local data, you can also incorporate your company's data. To do so, your company must provide the data through an ERI (External Retrieval Interface).") @@ -57,51 +57,51 @@ } else if (this.showDataSourceSelection) { - + @if (this.areDataSourcesEnabled) { - + @if (this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.EnableRetrievalContextValidation) { - + } @switch (this.aiBasedSourceSelection) { case true when this.availableDataSources.Count == 0: - + @T("Your data sources cannot be used with the selected providers due to data privacy or confidence-level requirements, or they are currently unavailable.") break; case true when this.DataSourcesAISelected.Count == 0: - + @T("The AI evaluates each of your inputs to determine whether and which data sources are necessary. Currently, the AI has not selected any source.") break; case false when this.availableDataSources.Count == 0: - + @T("Your data sources cannot be used with the selected providers due to data privacy or confidence-level requirements, or they are currently unavailable.") break; case false: - - + + @foreach (var source in this.availableDataSources) { - + @source.Name @if (source is IInternalDataSource internalSource) { - + } @@ -113,20 +113,20 @@ case true: - - + + @foreach (var source in this.availableDataSources) { - + @source.Name @if (source is IInternalDataSource internalSource) { - + } @@ -134,21 +134,21 @@ } - - + + @foreach (var source in this.DataSourcesAISelected) { - + @source.DataSource.Name @if (source.DataSource is IInternalDataSource internalSource) { - + } @@ -165,11 +165,24 @@ break; } + + @if (!this.aiBasedSourceSelection && this.GetUnavailablePreselectedDataSources().Count > 0) + { + + @T("These data sources are preselected, but cannot be used right now, either due to data privacy or confidence-level requirements, or because they are unavailable:") + +
    + @foreach (var source in this.GetUnavailablePreselectedDataSources()) + { +
  • @source.Name
  • + } +
+ } } }
- + @T("Close") @@ -187,7 +200,7 @@ else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE) @if (!string.IsNullOrWhiteSpace(this.ConfigurationHeaderMessage)) { - + @this.ConfigurationHeaderMessage } @@ -198,19 +211,19 @@ else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE) - + @foreach (var source in this.availableDataSources) { - + @source.Name @if (source is IInternalDataSource internalSource) { - + } @@ -220,4 +233,4 @@ else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE) } -} +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/DataSourceSelection.razor.cs b/app/MindWork AI Studio/Components/DataSourceSelection.razor.cs index 9ad90e26..18ddf6a8 100644 --- a/app/MindWork AI Studio/Components/DataSourceSelection.razor.cs +++ b/app/MindWork AI Studio/Components/DataSourceSelection.razor.cs @@ -181,6 +181,22 @@ public partial class DataSourceSelection : MSGComponentBase var preselectedDataSourceIds = this.DataSourceOptions.PreselectedDataSourceIds.ToHashSet(StringComparer.Ordinal); return this.GetConfiguredDataSourcesSnapshot().Where(ds => preselectedDataSourceIds.Contains(ds.Id)).ToList(); } + + /// + /// Collects the preselected data sources which the filters removed. + /// + /// + /// The list of available sources shows what survived the filters, while the preselection keeps + /// what the user asked for. Without this, a preselected source which cannot be used right now + /// is simply missing from that list, and nothing says so. Preselected ids without a configured + /// source are left out: that source is gone, not unavailable. + /// + /// The unusable preselected data sources, or an empty list when there are none. + private IReadOnlyList GetUnavailablePreselectedDataSources() + { + var availableDataSourceIds = this.availableDataSources.Select(ds => ds.Id).ToHashSet(StringComparer.Ordinal); + return this.GetDataSourcesFromConfiguredIds().Where(ds => !availableDataSourceIds.Contains(ds.Id)).ToList(); + } private async Task LoadAndApplyFilters() { @@ -200,8 +216,12 @@ public partial class DataSourceSelection : MSGComponentBase this.waitingForDataSources = true; this.StateHasChanged(); - // Load the data sources: - var sources = await this.DataSourceService.GetDataSources(this.LLMProvider, this.DataSourceOptions, this.selectedDataSources); + // + // Load the data sources. We ask with the preselection rather than with the field below: + // that field holds what was usable the last time we looked, so a source filtered out once + // would never come back, while the RAG process keeps reading it from the preselection. + // + var sources = await this.DataSourceService.GetDataSources(this.LLMProvider, this.DataSourceOptions, this.GetDataSourcesFromConfiguredIds()); if (generation != this.loadAndApplyFiltersGeneration) return; @@ -242,7 +262,16 @@ public partial class DataSourceSelection : MSGComponentBase private async Task SelectionChanged(IReadOnlyCollection? chosenDataSources) { this.selectedDataSources = chosenDataSources ?? []; - this.DataSourceOptions.PreselectedDataSourceIds = this.selectedDataSources.Select(ds => ds.Id).ToList(); + + // + // The list offers only the data sources which survived the filters, so what the user picks + // there says nothing about the preselected ones it could not show. Those are kept: dropping + // them would undo a choice the user never revisited, and it is these ids -- not this list -- + // which the RAG process reads when an answer is created. The query has to run before the + // assignment, because it reads what we are about to replace. + // + var keptDataSourceIds = this.GetUnavailablePreselectedDataSources().Select(ds => ds.Id).ToList(); + this.DataSourceOptions.PreselectedDataSourceIds = [..keptDataSourceIds, ..this.selectedDataSources.Select(ds => ds.Id)]; await this.OptionsChanged(); } diff --git a/app/MindWork AI Studio/Components/DataSourceSelection.razor.css b/app/MindWork AI Studio/Components/DataSourceSelection.razor.css new file mode 100644 index 00000000..73c446c8 --- /dev/null +++ b/app/MindWork AI Studio/Components/DataSourceSelection.razor.css @@ -0,0 +1,18 @@ +/* + * A plain list renders without markers and without indentation here: something in the global + * styles takes both off. This is an enumeration of names and wants to read as one, so it states + * marker, indentation and spacing itself. MudBlazor's Markdown styles fight the same fight for + * their own lists, and need an !important on the display to win it -- hence the one below. + */ +.unavailable-data-sources { + max-height: 10em; + overflow-y: auto; + overflow-wrap: anywhere; + margin-top: 0; + padding-left: 1.5em; + list-style: disc outside; +} + +.unavailable-data-sources li { + display: list-item !important; +} diff --git a/app/MindWork AI Studio/Components/MudTextSwitch.razor b/app/MindWork AI Studio/Components/MudTextSwitch.razor index 353ac8b8..7f9c65ce 100644 --- a/app/MindWork AI Studio/Components/MudTextSwitch.razor +++ b/app/MindWork AI Studio/Components/MudTextSwitch.razor @@ -1,5 +1,5 @@ - - + + @(this.Value ? this.LabelOn : this.LabelOff) \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/MudTextSwitch.razor.cs b/app/MindWork AI Studio/Components/MudTextSwitch.razor.cs index 2bce2c27..e1ca7f7a 100644 --- a/app/MindWork AI Studio/Components/MudTextSwitch.razor.cs +++ b/app/MindWork AI Studio/Components/MudTextSwitch.razor.cs @@ -27,4 +27,19 @@ public partial class MudTextSwitch : ComponentBase [Parameter] public string LabelOff { get; set; } = string.Empty; + + /// + /// Whether to render this switch in its compact form. + /// + /// + /// For places which stack several of these switches above other content, such as the data source + /// selection the chat opens from its footer. The roomy form stays the default, so that nothing + /// changes where this was never asked for. + /// + [Parameter] + public bool Dense { get; set; } + + private string FieldClasses => this.Dense ? "mb-2 text-switch-dense" : "mb-3"; + + private Size SwitchSize => this.Dense ? Size.Small : Size.Medium; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/PreviewBeta.razor b/app/MindWork AI Studio/Components/PreviewBeta.razor index 5494f51a..9cd66969 100644 --- a/app/MindWork AI Studio/Components/PreviewBeta.razor +++ b/app/MindWork AI Studio/Components/PreviewBeta.razor @@ -1,7 +1,7 @@ @inherits MSGComponentBase - + @T("Beta") diff --git a/app/MindWork AI Studio/Components/PreviewBeta.razor.cs b/app/MindWork AI Studio/Components/PreviewBeta.razor.cs index d73a9c53..b06089cd 100644 --- a/app/MindWork AI Studio/Components/PreviewBeta.razor.cs +++ b/app/MindWork AI Studio/Components/PreviewBeta.razor.cs @@ -7,5 +7,16 @@ public partial class PreviewBeta : MSGComponentBase [Parameter] public bool ApplyInnerScrollingFix { get; set; } + /// + /// Additional class names for the chip itself, separated by space. + /// + /// + /// The default is the margin every caller relied on before this parameter existed, because the + /// chip usually sits on a line of its own above a heading. A header which puts it beside the + /// heading instead passes an empty value. + /// + [Parameter] + public string ChipClass { get; set; } = "mb-3"; + private string Classes => this.ApplyInnerScrollingFix ? "InnerScrollingFix" : string.Empty; } \ No newline at end of file diff --git a/app/MindWork AI Studio/Components/ToolSelection.razor b/app/MindWork AI Studio/Components/ToolSelection.razor index 439c77b0..8763cc42 100644 --- a/app/MindWork AI Studio/Components/ToolSelection.razor +++ b/app/MindWork AI Studio/Components/ToolSelection.razor @@ -58,11 +58,15 @@ Disabled="@this.IsRowDisabled(item)" OnClick="@(async () => await this.ToggleToolFromRow(item))"> @* - The switch only shows the state; the surrounding button does the switching. + A checkbox rather than a switch, because this row is one entry of a set the + user picks from, not a setting of its own -- the same question the data source + selection next to it asks, and it should not look like a different one. + + The checkbox only shows the state; the surrounding button does the switching. It therefore takes no pointer events at all: its label reaches past the visible - switch and would otherwise swallow the clicks landing in that strip. + box and would otherwise swallow the clicks landing in that strip. *@ - + @if (!item.IsActive) { 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 61780dfa..3e1fa845 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 @@ -3348,6 +3348,9 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T3267850764"] = "Das ausgewählte -- We could load models from '{0}', but the provider did not return any usable text models. UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T3378120620"] = "Wir konnten Modelle von '{0}' laden, aber der Anbieter hat keine verwendbaren Textmodelle zurückgegeben." +-- Your data sources could not be used. This answer was created without them. +UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTTEXT::T373499115"] = "Ihre Datenquellen konnten nicht verwendet werden. Diese Antwort wurde ohne sie erstellt." + -- The local image file does not exist. Skipping the image. UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T255679918"] = "Die lokale Bilddatei existiert nicht. Das Bild wird übersprungen." @@ -3900,6 +3903,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T168406579"] = "KI-a -- AI-based data validation UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1744745490"] = "KI-gestützte Datenvalidierung" +-- These data sources are preselected, but cannot be used right now, either due to data privacy or confidence-level requirements, or because they are unavailable: +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1852534051"] = "Diese Datenquellen sind vorausgewählt, können derzeit jedoch nicht verwendet werden – entweder aufgrund von Datenschutz- oder Vertrauensanforderungen oder weil sie nicht verfügbar sind:" + -- Yes, I want to use data sources. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1975014927"] = "Ja, ich möchte Datenquellen verwenden." @@ -10464,6 +10470,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::AIJOBS::AIJOBSERVICE::T3267850764"] = "Das aus -- We could load models from '{0}', but the provider did not return any usable text models. UI_TEXT_CONTENT["AISTUDIO::TOOLS::AIJOBS::AIJOBSERVICE::T3378120620"] = "Wir konnten Modelle von „{0}“ laden, aber der Anbieter hat keine verwendbaren Textmodelle zurückgegeben." +-- Your data sources could not be used. This answer was created without them. +UI_TEXT_CONTENT["AISTUDIO::TOOLS::AIJOBS::AIJOBSERVICE::T373499115"] = "Ihre Datenquellen konnten nicht verwendet werden. Diese Antwort wurde ohne sie erstellt." + -- Software Development UI_TEXT_CONTENT["AISTUDIO::TOOLS::ASSISTANTCATEGORYEXTENSIONS::T1025369409"] = "Softwareentwicklung" @@ -11571,6 +11580,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::AUGMENTATIONPROCESSES::AUGMENTATIONONE::T -- 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"] = "Dies ist der Standard-Erweiterungsprozess, bei dem alle abgerufenen Kontexte verwendet werden, um den Chatverlauf zu ergänzen." +-- 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"] = "Die Prüfung, welche Textstellen zu Ihrer Frage passen, ist fehlgeschlagen. Diese Antwort verwendet alle gefundenen Textstellen." + -- Automatic AI data source selection with heuristik source reduction UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::DATASOURCESELECTIONPROCESSES::AGENTICSRCSELWITHDYNHEUR::T2339257645"] = "Automatische Auswahl der Datenquellen mittels KI und mit heuristischer Datenquellen-Reduktion" 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 bb7a44ff..1c6c1d89 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 @@ -3348,6 +3348,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." @@ -3900,6 +3903,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T168406579"] = "AI-S -- AI-based data validation UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1744745490"] = "AI-based data validation" +-- These data sources are preselected, but cannot be used right now, either due to data privacy or confidence-level requirements, or because they are unavailable: +UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1852534051"] = "These data sources are preselected, but cannot be used right now, either due to data privacy or confidence-level requirements, or because they are unavailable:" + -- Yes, I want to use data sources. UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::DATASOURCESELECTION::T1975014927"] = "Yes, I want to use data sources." @@ -10464,6 +10470,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" @@ -11571,6 +11580,9 @@ UI_TEXT_CONTENT["AISTUDIO::TOOLS::RAG::AUGMENTATIONPROCESSES::AUGMENTATIONONE::T -- 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" diff --git a/app/MindWork AI Studio/Tools/RAG/AugmentationProcesses/AugmentationOne.cs b/app/MindWork AI Studio/Tools/RAG/AugmentationProcesses/AugmentationOne.cs index 97ebb1b5..a3553856 100644 --- a/app/MindWork AI Studio/Tools/RAG/AugmentationProcesses/AugmentationOne.cs +++ b/app/MindWork AI Studio/Tools/RAG/AugmentationProcesses/AugmentationOne.cs @@ -80,8 +80,12 @@ public sealed class AugmentationOne : IAugmentationProcess } else { + // + // No message to the user here: which providers are trusted enough is a setting, not + // an event. It does not change between two answers, so a message would repeat itself + // with every single one until the setting changes. + // 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."))); } } diff --git a/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs b/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs index a93f28c6..b7958a8e 100644 --- a/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs +++ b/app/MindWork AI Studio/Tools/RAG/RAGProcesses/AISrcSelWithRetCtxVal.cs @@ -104,17 +104,16 @@ public sealed class AISrcSelWithRetCtxVal : IRagProcess if(selectedDataSources.Count == 0) { + // + // Reaching this point means the user never saw a source of theirs selected: the + // selection shows what survived the filters, so an empty result there is an empty + // selection on screen as well. Telling them per answer that their sources were + // lost would announce a loss they were never shown in the first place. This state + // belongs into the selection instead, which names the preselected sources it + // cannot use. + // 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 { diff --git a/app/MindWork AI Studio/wwwroot/app.css b/app/MindWork AI Studio/wwwroot/app.css index 9cfd455d..13e53304 100644 --- a/app/MindWork AI Studio/wwwroot/app.css +++ b/app/MindWork AI Studio/wwwroot/app.css @@ -475,20 +475,59 @@ tr:has(> .provider-group-header) .mud-icon-button { * Rows of the tool selection which the chat and the assistants open from their footer. There will be * far more tools than the ones we start with, so a row must not waste height: MudBlazor's settings * button alone puts 12px of padding around a 24px icon, which makes a row 48px tall before the - * switch and the frame are counted at all. Size.Small takes most of that away; the rule below takes - * the rest, and it has to name the MudBlazor class to outweigh its specificity. Alternating rows - * carry a grey ground, which tells a long list apart better than a separator line does and costs no - * height at all. The colors are MudBlazor palette variables, so both grounds follow the theme. + * switch and the frame are counted at all. Size.Small takes most of that away; the rules below take + * the rest, and the second one has to name the MudBlazor class to outweigh its specificity. */ .tool-selection-rows > .tool-selection-row { padding: 0.15rem 0.25rem; - border-radius: var(--mud-default-borderradius); -} - -.tool-selection-rows > .tool-selection-row:nth-child(odd) { - background-color: var(--mud-palette-background-gray); } .tool-selection-row .mud-icon-button { padding: 0.2em; } + +/* + * Rows of the data source lists, in the popover next to the tool selection as well as in the + * settings dialog. A row carries a name and at most one icon, so there is no reason for it to be + * 48px tall: MudBlazor pads the item with 8px on both sides and the text slot with another 4px, + * which is more frame than content. Dense on the list halves the first part, the rule below takes + * the second one away, and it has to name the MudBlazor class to outweigh its specificity. + */ +.data-source-rows .mud-list-item-text { + margin-top: 0; + margin-bottom: 0; +} + +/* + * The checkboxes MudBlazor renders into a multi-selection list come out larger than the box of the + * tool selection next to it, and MudList has no parameter for their size. So the three rules below + * state it: the 20px icon and the 4px of padding which Size.Small together with Dense produce over + * there, plus the 4px between the box and the name which the tool row takes from the spacing of its + * stack -- the list puts its checkbox outside the slot that holds our own markup, so no stack of + * ours reaches it. The icon needs a rule of its own because MudBlazor gives it an explicit font + * size, which no inherited one can outrank. + */ +.data-source-rows .mud-checkbox { + margin-inline-end: 0.25rem; +} + +.data-source-rows .mud-checkbox .mud-icon-button { + padding: 0.25rem; +} + +.data-source-rows .mud-checkbox .mud-icon-root { + font-size: 1.25rem; +} + +/* + * The frame around a text switch in its compact form. MudBlazor pads the slot of an outlined field + * with 18.5px above and below, which is the right amount for the line of text such a field usually + * holds -- a switch of 24px is left swimming in the middle of it. Size.Small already took the switch + * down; this brings the frame with it, and it has to name the MudBlazor classes to outweigh their + * specificity. Only the two vertical values of that shorthand are replaced, so the 14px to the left + * and right stay as they are. + */ +.text-switch-dense .mud-input-slot.mud-input-root-outlined { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} diff --git a/app/MindWork AI Studio/wwwroot/changelog/v26.9.1.md b/app/MindWork AI Studio/wwwroot/changelog/v26.9.1.md index 381c1cf4..90015793 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v26.9.1.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v26.9.1.md @@ -41,7 +41,8 @@ - Fixed the copy button leaving the sources behind. Copy an answer, and its sources come along. - Fixed a tile that opens a chat directly always demanding a workspace. Leave the workspace empty in the Assistant Builder, and the tile opens a disappearing chat instead. - Fixed the same restriction for plugin authors: a direct-chat launcher can now open a chat without naming a workspace. The example assistant plugin shows both ways. -- Fixed an answer built without your data sources looking exactly like one that used them. When AI Studio cannot reach the sources you picked, it now tells you instead of quietly answering without them. -- Fixed the same silence when the step that picks the fitting passages out of your documents cannot run. You are told that the answer rests on everything that was found. +- Fixed data sources you picked for your chats vanishing from the selection without a word when they cannot be used. AI Studio now lists them by name, so you can see why an answer was created without them. +- Fixed the data sources you picked for a chat being forgotten the moment you changed your selection while one of them could not be used. Such a source stays selected and is used again as soon as it is available. +- Fixed the silence when the step that picks the fitting passages out of your documents fails. You are told that the answer rests on everything that was found. - Fixed the regenerate button taking an answer away without producing a new one. This happened in chats started from a template that holds no question of your own. - Upgraded the Visual Briefing Assistant (in preview) from the prototype to the beta state. The assistant is now completely implemented and is undergoing a deeper testing phase in preparation for release. To try it, open the app settings, allow preview features down to beta, and then enable the Visual Briefing Assistant there.