mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-18 01:37:59 +00:00
Added a semantic search tool (#1005)
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Verify (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Verify (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
This commit is contained in:
1 parent
4baf21656a
commit
1eaca9b12f
91 files changed
+4248
-487
No files matched your search
@@ -794,6 +794,7 @@ public partial class ChatComponent : MSGComponentBase
|
||||
return left.DisableDataSources == right.DisableDataSources
|
||||
&& left.AutomaticDataSourceSelection == right.AutomaticDataSourceSelection
|
||||
&& left.AutomaticValidation == right.AutomaticValidation
|
||||
&& left.RetrievalMode == right.RetrievalMode
|
||||
&& left.PreselectedDataSourceIds.ToHashSet(StringComparer.Ordinal).SetEquals(right.PreselectedDataSourceIds);
|
||||
}
|
||||
|
||||
@@ -1607,6 +1608,13 @@ public partial class ChatComponent : MSGComponentBase
|
||||
var parts = ConversationParts.NOTHING;
|
||||
var reported = ReportedHistory.UNKNOWN;
|
||||
|
||||
//
|
||||
// Semantic Search offers itself rather than being selected, and the registry answers
|
||||
// whether it can be offered asynchronously. So this is asked before collecting, which only
|
||||
// reads the provider and the choice of the chat, nothing a background job appends to:
|
||||
//
|
||||
var offersSemanticSearch = await this.OffersSemanticSearchAsync();
|
||||
|
||||
//
|
||||
// Collected on the render thread, counted off it. Counting may take an IPC call per text,
|
||||
// and while it runs, the background job which writes the answer appends to the very list
|
||||
@@ -1621,7 +1629,7 @@ public partial class ChatComponent : MSGComponentBase
|
||||
// of it would tell a person their window is empty while their first message is not.
|
||||
//
|
||||
var thread = this.ChatThread ?? this.NewChatThread(string.Empty);
|
||||
var toolDefinitions = this.GetRunnableToolDefinitions();
|
||||
var toolDefinitions = this.GetRunnableToolDefinitions(offersSemanticSearch);
|
||||
provider = this.Provider;
|
||||
parts = ConversationParts.Of(thread, this.BuildSystemPromptFor(thread, toolDefinitions), this.UserInput, this.ComposerState.FileAttachments, provider.SupportsImageInput(), toolDefinitions);
|
||||
reported = thread.ReportedHistoryFor(provider.Model);
|
||||
@@ -1665,13 +1673,45 @@ public partial class ChatComponent : MSGComponentBase
|
||||
/// Asked for once and used twice: their policy goes into the system prompt, and their schemas
|
||||
/// travel next to it in the request body. Both cost tokens, and both change the moment somebody
|
||||
/// switches a tool on.
|
||||
///
|
||||
/// Semantic Search is no selected tool, so it comes on top when it is offered. It counts with
|
||||
/// its static definition: the one a request offers lists the data sources as well, which only
|
||||
/// the request asks for.
|
||||
/// </remarks>
|
||||
/// <returns>The definitions of the selected tools.</returns>
|
||||
private IReadOnlyList<ToolDefinition> GetRunnableToolDefinitions() => this.ToolRegistry.FilterToolIdsForProvider(this.Provider, this.selectedToolIds)
|
||||
.Select(this.ToolRegistry.GetDefinition)
|
||||
.Where(definition => definition is not null)
|
||||
.Select(definition => definition!)
|
||||
.ToList();
|
||||
/// <param name="offersSemanticSearch">Whether the next request offers Semantic Search, see OffersSemanticSearchAsync.</param>
|
||||
/// <returns>The definitions of the selected tools, and of Semantic Search when it is offered.</returns>
|
||||
private IReadOnlyList<ToolDefinition> GetRunnableToolDefinitions(bool offersSemanticSearch)
|
||||
{
|
||||
var definitions = this.ToolRegistry.FilterToolIdsForProvider(this.Provider, this.selectedToolIds)
|
||||
.Select(this.ToolRegistry.GetDefinition)
|
||||
.Where(definition => definition is not null)
|
||||
.Select(definition => definition!)
|
||||
.ToList();
|
||||
|
||||
if (offersSemanticSearch && this.ToolRegistry.GetDefinition(ToolSelectionRules.SEMANTIC_SEARCH_TOOL_ID) is { } semanticSearch)
|
||||
definitions.Add(semanticSearch);
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the next request offers the model Semantic Search, as far as this can be told without asking the data sources.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// An estimate on purpose. Whether a data source can be searched right now would mean asking
|
||||
/// every ERI server with every count, and the count runs all the time. Once the first answer is
|
||||
/// there, the number the provider reported takes over anyway, see ChatThread.ReportedHistoryFor.
|
||||
/// </remarks>
|
||||
/// <returns>True when the next request offers Semantic Search, as far as can be told.</returns>
|
||||
private async Task<bool> OffersSemanticSearchAsync()
|
||||
{
|
||||
var options = this.GetCurrentDataSourceOptions();
|
||||
if (!PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager) || !options.IsEnabled())
|
||||
return false;
|
||||
|
||||
var retrievalMode = await this.ToolRegistry.GetEffectiveRetrievalModeAsync(options, this.Provider, Tools.Components.CHAT);
|
||||
return retrievalMode.Mode is DataSourceRetrievalMode.SEMANTIC_SEARCH;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The thread a new chat starts with, as the selections made so far decide it.
|
||||
|
||||
@@ -60,9 +60,22 @@
|
||||
<MudTextSwitch Label="@T("Are data sources enabled?")" Value="@this.areDataSourcesEnabled" LabelOn="@T("Yes, I want to use data sources.")" LabelOff="@T("No, I don't want to use data sources.")" ValueChanged="@this.EnabledChanged" Dense="@true"/>
|
||||
@if (this.areDataSourcesEnabled)
|
||||
{
|
||||
@* Where Semantic Search cannot be used, there is no choice to make, only the reason to tell: *@
|
||||
@if (this.IsSemanticSearchUnavailable)
|
||||
{
|
||||
<MudJustifiedText Typo="Typo.body2" Color="Color.Info" Class="mb-2">
|
||||
@this.GetSemanticSearchUnavailableMessage()
|
||||
</MudJustifiedText>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTextSwitch Label="@T("Semantic Search")" Value="@this.IsSemanticSearchPreferred" LabelOn="@T("Yes, the AI searches your data sources itself, whenever a question calls for it (Semantic Search).")" LabelOff="@T("No, AI Studio searches your data sources with every message, before the AI answers (classic RAG).")" ValueChanged="@this.SemanticSearchChanged" Dense="@true"/>
|
||||
}
|
||||
|
||||
<MudTextSwitch Label="@T("AI-based data source selection")" Value="@this.aiBasedSourceSelection" LabelOn="@T("Yes, let the AI decide which data sources are needed.")" LabelOff="@T("No, I manually decide which data source to use.")" ValueChanged="@this.AutoModeChanged" Dense="@true"/>
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.EnableRetrievalContextValidation)
|
||||
|
||||
@* With Semantic Search, no agent takes part: nothing would validate the retrieved data. *@
|
||||
@if (this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.EnableRetrievalContextValidation && !this.IsSemanticSearchEffective)
|
||||
{
|
||||
<MudTextSwitch Label="@T("AI-based data validation")" Value="@this.aiBasedValidation" LabelOn="@T("Yes, let the AI validate & filter the retrieved data.")" LabelOff="@T("No, use all data retrieved from the data sources.")" ValueChanged="@this.ValidationModeChanged" Dense="@true"/>
|
||||
}
|
||||
@@ -75,12 +88,6 @@
|
||||
</MudText>
|
||||
break;
|
||||
|
||||
case true when this.DataSourcesAISelected.Count == 0:
|
||||
<MudText Typo="Typo.body2" Class="mb-2">
|
||||
@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.")
|
||||
</MudText>
|
||||
break;
|
||||
|
||||
case false when this.GetListedDataSources().Count == 0:
|
||||
<MudText Typo="Typo.body2" Class="mb-2">
|
||||
@T("Your data sources cannot be used with the selected providers due to data privacy or confidence-level requirements, or they are currently unavailable.")
|
||||
@@ -99,6 +106,19 @@
|
||||
break;
|
||||
|
||||
case true:
|
||||
@if (this.IsSemanticSearchEffective)
|
||||
{
|
||||
<MudText Typo="Typo.body2" Class="mb-2">
|
||||
@T("Whenever a question calls for it, the AI picks the fitting ones among these data sources itself.")
|
||||
</MudText>
|
||||
}
|
||||
else if (this.DataSourcesAISelected.Count == 0)
|
||||
{
|
||||
<MudText Typo="Typo.body2" Class="mb-2">
|
||||
@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.")
|
||||
</MudText>
|
||||
}
|
||||
|
||||
<MudExpansionPanels MultiExpansion="@false" Class="mt-3" Style="max-height: 14em;">
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.TouchApp" IconSize="Size.Small" HeaderTypo="Typo.subtitle1" HeaderClass="expansion-panel-header-compact" HeaderText="@T("Available Data Sources")">
|
||||
<MudList T="IDataSource" Dense="@true" Class="data-source-rows" SelectionMode="MudBlazor.SelectionMode.SingleSelection" SelectedValues="@this.selectedDataSources" Style="max-height: 14em;">
|
||||
@@ -108,34 +128,42 @@
|
||||
}
|
||||
</MudList>
|
||||
</ExpansionPanel>
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Filter" IconSize="Size.Small" HeaderTypo="Typo.subtitle1" HeaderClass="expansion-panel-header-compact" HeaderText="@T("AI-Selected Data Sources")">
|
||||
<MudList T="DataSourceAgentSelected" Dense="@true" Class="data-source-rows" SelectionMode="MudBlazor.SelectionMode.MultiSelection" ReadOnly="@true" SelectedValues="@this.GetSelectedDataSourcesWithAI()" Style="max-height: 14em;">
|
||||
@foreach (var source in this.DataSourcesAISelected)
|
||||
{
|
||||
<MudListItem Value="@source">
|
||||
<ChildContent>
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Style="min-width: 0; width: 100%;">
|
||||
<MudText Typo="Typo.body2" Style="min-width: 0; white-space: normal; overflow-wrap: anywhere;">
|
||||
@source.DataSource.Name
|
||||
</MudText>
|
||||
@if (source.DataSource is IInternalDataSource internalSource)
|
||||
{
|
||||
<MudSpacer/>
|
||||
<MudTooltip Text="@internalSource.ConfidenceLevel.GetName()">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Security" Size="Size.Small" Class="confidence-icon" Style="@this.GetConfidenceIconStyle(internalSource)"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
</MudStack>
|
||||
@*
|
||||
With Semantic Search, no agent selects: the chat model picks with each search, and its
|
||||
searches show in the answer. With classic RAG, there is something to show once the agent
|
||||
picked for a message.
|
||||
*@
|
||||
@if (!this.IsSemanticSearchEffective && this.DataSourcesAISelected.Count > 0)
|
||||
{
|
||||
<ExpansionPanel HeaderIcon="@Icons.Material.Filled.Filter" IconSize="Size.Small" HeaderTypo="Typo.subtitle1" HeaderClass="expansion-panel-header-compact" HeaderText="@T("AI-Selected Data Sources")">
|
||||
<MudList T="DataSourceAgentSelected" Dense="@true" Class="data-source-rows" SelectionMode="MudBlazor.SelectionMode.MultiSelection" ReadOnly="@true" SelectedValues="@this.GetSelectedDataSourcesWithAI()" Style="max-height: 14em;">
|
||||
@foreach (var source in this.DataSourcesAISelected)
|
||||
{
|
||||
<MudListItem Value="@source">
|
||||
<ChildContent>
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1" Style="min-width: 0; width: 100%;">
|
||||
<MudText Typo="Typo.body2" Style="min-width: 0; white-space: normal; overflow-wrap: anywhere;">
|
||||
@source.DataSource.Name
|
||||
</MudText>
|
||||
@if (source.DataSource is IInternalDataSource internalSource)
|
||||
{
|
||||
<MudSpacer/>
|
||||
<MudTooltip Text="@internalSource.ConfidenceLevel.GetName()">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Security" Size="Size.Small" Class="confidence-icon" Style="@this.GetConfidenceIconStyle(internalSource)"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
</MudStack>
|
||||
|
||||
<MudProgressLinear Color="Color.Info" Min="0" Max="1" Value="@source.AIDecision.Confidence"/>
|
||||
<MudJustifiedText Typo="Typo.body2">
|
||||
@(this.GetAIReasoning(source))
|
||||
</MudJustifiedText>
|
||||
</ChildContent>
|
||||
</MudListItem>
|
||||
}
|
||||
</MudList>
|
||||
</ExpansionPanel>
|
||||
<MudProgressLinear Color="Color.Info" Min="0" Max="1" Value="@source.AIDecision.Confidence"/>
|
||||
<MudJustifiedText Typo="Typo.body2">
|
||||
@(this.GetAIReasoning(source))
|
||||
</MudJustifiedText>
|
||||
</ChildContent>
|
||||
</MudListItem>
|
||||
}
|
||||
</MudList>
|
||||
</ExpansionPanel>
|
||||
}
|
||||
</MudExpansionPanels>
|
||||
break;
|
||||
}
|
||||
@@ -182,8 +210,24 @@ else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE)
|
||||
<MudTextSwitch Label="@T("Are data sources enabled?")" Value="@this.areDataSourcesEnabled" LabelOn="@T("Yes, I want to use data sources.")" LabelOff="@T("No, I don't want to use data sources.")" ValueChanged="@this.EnabledChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesDisabledLocked())"/>
|
||||
@if (this.areDataSourcesEnabled)
|
||||
{
|
||||
<MudTextSwitch Label="@T("Semantic Search")" Value="@this.IsSemanticSearchPreferred" LabelOn="@T("Yes, the AI searches your data sources itself, whenever a question calls for it (Semantic Search).")" LabelOff="@T("No, AI Studio searches your data sources with every message, before the AI answers (classic RAG).")" ValueChanged="@this.SemanticSearchChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesRetrievalModeLocked())"/>
|
||||
@* No provider is known here, so this says in general what the chat itself tells about its model: *@
|
||||
@if (this.IsSemanticSearchPreferred)
|
||||
{
|
||||
<MudJustifiedText Typo="Typo.body2" Class="mb-3">
|
||||
@T("When the model of a chat cannot use tools, AI Studio uses classic RAG instead and searches your data sources with every message.")
|
||||
</MudJustifiedText>
|
||||
}
|
||||
|
||||
<MudTextSwitch Label="@T("AI-based data source selection")" Value="@this.aiBasedSourceSelection" LabelOn="@T("Yes, let the AI decide which data sources are needed.")" LabelOff="@T("No, I manually decide which data source to use.")" ValueChanged="@this.AutoModeChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesAutomaticSelectionLocked())"/>
|
||||
<MudTextSwitch Label="@T("AI-based data validation")" Value="@this.aiBasedValidation" LabelOn="@T("Yes, let the AI validate & filter the retrieved data.")" LabelOff="@T("No, use all data retrieved from the data sources.")" ValueChanged="@this.ValidationModeChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesAutomaticValidationLocked())"/>
|
||||
|
||||
@* Semantic Search may fall back to searching with every message, so the validation is kept, marked as belonging to that way only: *@
|
||||
<MudPaper Class="pa-3 mb-3 border-dashed border rounded-lg">
|
||||
<MudJustifiedText Typo="Typo.body2" Class="mb-2">
|
||||
@T("Only used with classic RAG, which searches your data sources with every message:")
|
||||
</MudJustifiedText>
|
||||
<MudTextSwitch Label="@T("AI-based data validation")" Value="@this.aiBasedValidation" LabelOn="@T("Yes, let the AI validate & filter the retrieved data.")" LabelOff="@T("No, use all data retrieved from the data sources.")" ValueChanged="@this.ValidationModeChanged" Disabled="@(this.ReadOnly || this.IsPreselectedDataSourcesAutomaticValidationLocked())"/>
|
||||
</MudPaper>
|
||||
<MudField Label="@T("Available Data Sources")" Variant="Variant.Outlined" Class="mb-3" Disabled="@(this.ReadOnly || this.aiBasedSourceSelection || this.IsPreselectedDataSourceIdsLocked())">
|
||||
<MudList T="IDataSource" Dense="@true" Class="data-source-rows" SelectionMode="@this.GetListSelectionMode()" @bind-SelectedValues:get="@this.selectedDataSources" @bind-SelectedValues:set="@(x => this.SelectionChanged(x))" ReadOnly="@(this.ReadOnly || this.IsPreselectedDataSourceIdsLocked())">
|
||||
@*
|
||||
|
||||
@@ -3,6 +3,7 @@ using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Settings.DataModel;
|
||||
using AIStudio.Tools.Services;
|
||||
using AIStudio.Tools.ToolCallingSystem;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
@@ -62,7 +63,10 @@ public partial class DataSourceSelection : MSGComponentBase
|
||||
|
||||
[Inject]
|
||||
private DataSourceService DataSourceService { get; init; } = null!;
|
||||
|
||||
|
||||
[Inject]
|
||||
private ToolRegistry ToolRegistry { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IDialogService DialogService { get; init; } = null!;
|
||||
|
||||
@@ -78,6 +82,8 @@ public partial class DataSourceSelection : MSGComponentBase
|
||||
private bool aiBasedSourceSelection;
|
||||
private bool aiBasedValidation;
|
||||
private bool areDataSourcesEnabled;
|
||||
private DataSourceRetrievalMode retrievalMode;
|
||||
private EffectiveRetrievalMode effectiveRetrievalMode;
|
||||
private uint loadAndApplyFiltersGeneration;
|
||||
|
||||
#region Overrides of ComponentBase
|
||||
@@ -92,6 +98,7 @@ public partial class DataSourceSelection : MSGComponentBase
|
||||
this.aiBasedSourceSelection = this.DataSourceOptions.AutomaticDataSourceSelection;
|
||||
this.aiBasedValidation = this.DataSourceOptions.AutomaticValidation;
|
||||
this.areDataSourcesEnabled = !this.DataSourceOptions.DisableDataSources;
|
||||
this.retrievalMode = this.DataSourceOptions.RetrievalMode;
|
||||
this.waitingForDataSources = this.areDataSourcesEnabled && this.SelectionMode is not DataSourceSelectionMode.CONFIGURATION_MODE;
|
||||
|
||||
//
|
||||
@@ -113,6 +120,7 @@ public partial class DataSourceSelection : MSGComponentBase
|
||||
this.aiBasedSourceSelection = this.DataSourceOptions.AutomaticDataSourceSelection;
|
||||
this.aiBasedValidation = this.DataSourceOptions.AutomaticValidation;
|
||||
this.areDataSourcesEnabled = !this.DataSourceOptions.DisableDataSources;
|
||||
this.retrievalMode = this.DataSourceOptions.RetrievalMode;
|
||||
this.selectedDataSources = this.GetDataSourcesFromConfiguredIds();
|
||||
}
|
||||
|
||||
@@ -178,6 +186,7 @@ public partial class DataSourceSelection : MSGComponentBase
|
||||
this.aiBasedSourceSelection = this.DataSourceOptions.AutomaticDataSourceSelection;
|
||||
this.aiBasedValidation = this.DataSourceOptions.AutomaticValidation;
|
||||
this.areDataSourcesEnabled = !this.DataSourceOptions.DisableDataSources;
|
||||
this.retrievalMode = this.DataSourceOptions.RetrievalMode;
|
||||
this.selectedDataSources = this.GetDataSourcesFromConfiguredIds();
|
||||
this.waitingForDataSources = false;
|
||||
|
||||
@@ -246,10 +255,16 @@ public partial class DataSourceSelection : MSGComponentBase
|
||||
// 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());
|
||||
// How the chat searches decides whether the agents of the RAG process see the data, and
|
||||
// with that which data sources the provider of the chat may use at all. This component
|
||||
// only ever selects for a chat:
|
||||
//
|
||||
var effectiveMode = await this.ToolRegistry.GetEffectiveRetrievalModeAsync(this.DataSourceOptions, this.LLMProvider, Tools.Components.CHAT);
|
||||
var sources = await this.DataSourceService.GetDataSources(this.LLMProvider, this.DataSourceOptions, effectiveMode.Mode, this.GetDataSourcesFromConfiguredIds());
|
||||
if (generation != this.loadAndApplyFiltersGeneration)
|
||||
return;
|
||||
|
||||
this.effectiveRetrievalMode = effectiveMode;
|
||||
this.availableDataSources = sources.AllowedDataSources;
|
||||
this.dataSourcesAwaitingReindex = sources.DataSourcesAwaitingReindex;
|
||||
this.dataSourceIdsAwaitingReindex = sources.DataSourcesAwaitingReindex.Select(source => source.Id).ToHashSet(StringComparer.Ordinal);
|
||||
@@ -326,6 +341,47 @@ public partial class DataSourceSelection : MSGComponentBase
|
||||
await this.OptionsChanged();
|
||||
}
|
||||
|
||||
private async Task SemanticSearchChanged(bool state)
|
||||
{
|
||||
this.retrievalMode = state ? DataSourceRetrievalMode.SEMANTIC_SEARCH : DataSourceRetrievalMode.EVERY_MESSAGE;
|
||||
this.DataSourceOptions.RetrievalMode = this.retrievalMode;
|
||||
|
||||
// Which data sources the provider may use depends on it, see LoadAndApplyFilters:
|
||||
await this.LoadAndApplyFilters();
|
||||
await this.OptionsChanged();
|
||||
}
|
||||
|
||||
private bool IsSemanticSearchPreferred => this.retrievalMode is DataSourceRetrievalMode.SEMANTIC_SEARCH;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the model of the chat searches the data sources itself.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Only the selection mode can tell, since only it knows the provider of a chat. The effective
|
||||
/// mode is found out while loading the data sources; asking the preference as well keeps a
|
||||
/// switch to every message from showing the other way until that loading is done.
|
||||
/// </remarks>
|
||||
private bool IsSemanticSearchEffective => this.IsSemanticSearchPreferred && this.effectiveRetrievalMode.Mode is DataSourceRetrievalMode.SEMANTIC_SEARCH;
|
||||
|
||||
/// <summary>
|
||||
/// Whether Semantic Search cannot be used in this chat, whatever the user prefers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Then there is nothing to choose: classic RAG searches the data sources. The choice is left
|
||||
/// out rather than shown as one which changes nothing, and the preference stays as it is, so it
|
||||
/// is back the moment the chat gets a model which can search itself.
|
||||
/// </remarks>
|
||||
private bool IsSemanticSearchUnavailable => this.effectiveRetrievalMode.SemanticSearchBlockReason is not ToolOfferBlockReason.NONE;
|
||||
|
||||
private string GetSemanticSearchUnavailableMessage() => this.effectiveRetrievalMode.SemanticSearchBlockReason switch
|
||||
{
|
||||
ToolOfferBlockReason.TOOLS_SWITCHED_OFF => T("Your organization has switched tools off, so AI Studio uses classic RAG instead and searches your data sources with every message."),
|
||||
ToolOfferBlockReason.MODEL_CANNOT_USE_TOOLS => T("The selected model cannot use tools, so AI Studio uses classic RAG instead and searches your data sources with every message."),
|
||||
ToolOfferBlockReason.TOOL_SWITCHED_OFF => T("Your organization has switched Semantic Search off, so AI Studio uses classic RAG instead and searches your data sources with every message."),
|
||||
ToolOfferBlockReason.PROVIDER_CONFIDENCE_TOO_LOW => T("The selected provider is not trusted enough for Semantic Search, so AI Studio uses classic RAG instead and searches your data sources with every message."),
|
||||
_ => T("Semantic Search cannot be used here, so AI Studio uses classic RAG instead and searches your data sources with every message."),
|
||||
};
|
||||
|
||||
private async Task ValidationModeChanged(bool state)
|
||||
{
|
||||
this.aiBasedValidation = state;
|
||||
@@ -360,6 +416,14 @@ public partial class DataSourceSelection : MSGComponentBase
|
||||
&& meta.IsLocked;
|
||||
}
|
||||
|
||||
private bool IsPreselectedDataSourcesRetrievalModeLocked()
|
||||
{
|
||||
return this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE
|
||||
&& this.ConfiguresChatDefaults
|
||||
&& ManagedConfiguration.TryGet(x => x.Chat, x => x.PreselectedDataSourcesRetrievalMode, out var meta)
|
||||
&& meta.IsLocked;
|
||||
}
|
||||
|
||||
private bool IsPreselectedDataSourcesAutomaticSelectionLocked()
|
||||
{
|
||||
return this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.ToolCallingSystem;
|
||||
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
@@ -100,6 +101,10 @@ public partial class ProviderSelection : MSGComponentBase
|
||||
if (profile.Has(Capability.SPEECH_INPUT))
|
||||
capabilityIcons.Add(new(Icons.Material.Filled.Mic, this.T("Speech input possible")));
|
||||
|
||||
// The same check which decides whether a request offers tools, Semantic Search among them:
|
||||
if (provider.GetToolCallingAvailability().IsAvailable)
|
||||
capabilityIcons.Add(new(Icons.Material.Filled.Build, this.T("Tool calling possible")));
|
||||
|
||||
var reasoningIndicatorState = provider.GetReasoningIndicatorState();
|
||||
if (reasoningIndicatorState is not ReasoningIndicatorState.NONE)
|
||||
capabilityIcons.Add(new(Icons.Material.Filled.Psychology, this.GetReasoningTooltip(reasoningIndicatorState)));
|
||||
|
||||
Reference in new issue
Block a user