diff --git a/app/MindWork AI Studio.sln b/app/MindWork AI Studio.sln
index ef02b517..37871ac7 100644
--- a/app/MindWork AI Studio.sln
+++ b/app/MindWork AI Studio.sln
@@ -2,6 +2,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MindWork AI Studio", "MindWork AI Studio\MindWork AI Studio.csproj", "{059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceCodeRules", "SourceCodeRules\SourceCodeRules\SourceCodeRules.csproj", "{0976C1CB-D499-4C86-8ADA-B7A7A4DE0BF8}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -12,6 +14,10 @@ Global
{059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{059FDFCC-7D0B-474E-9F20-B9C437DF1CDD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0976C1CB-D499-4C86-8ADA-B7A7A4DE0BF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0976C1CB-D499-4C86-8ADA-B7A7A4DE0BF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0976C1CB-D499-4C86-8ADA-B7A7A4DE0BF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0976C1CB-D499-4C86-8ADA-B7A7A4DE0BF8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
EndGlobalSection
diff --git a/app/MindWork AI Studio.sln.DotSettings b/app/MindWork AI Studio.sln.DotSettings
index 4038c0ae..431ff5cf 100644
--- a/app/MindWork AI Studio.sln.DotSettings
+++ b/app/MindWork AI Studio.sln.DotSettings
@@ -9,5 +9,6 @@
UI
True
True
+ True
True
True
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs b/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs
index 6b1410ce..74357139 100644
--- a/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs
+++ b/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs
@@ -140,17 +140,7 @@ public sealed class AgentDataSourceSelection (ILogger
//
// We start with the provider currently selected by the user:
- var agentProvider = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == provider.Id);
-
- // If the user preselected an agent provider, we try to use this one:
- if (this.SettingsManager.ConfigurationData.AgentDataSourceSelection.PreselectAgentOptions)
- {
- var configuredAgentProvider = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.AgentDataSourceSelection.PreselectedAgentProvider);
-
- // If the configured agent provider is available, we use it:
- if (configuredAgentProvider != default)
- agentProvider = configuredAgentProvider;
- }
+ var agentProvider = this.SettingsManager.GetPreselectedProvider(Tools.Components.AGENT_DATA_SOURCE_SELECTION, provider.Id, true);
// Assign the provider settings to the agent:
logger.LogInformation($"The agent for the data source selection uses the provider '{agentProvider.InstanceName}' ({agentProvider.UsedLLMProvider.ToName()}, confidence={agentProvider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level.GetName()}).");
diff --git a/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs b/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs
index ae54de53..ae1ec713 100644
--- a/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs
+++ b/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs
@@ -132,18 +132,8 @@ public sealed class AgentRetrievalContextValidation (ILogger x.Id == provider.Id);
-
- // If the user preselected an agent provider, we try to use this one:
- if (this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.PreselectAgentOptions)
- {
- var configuredAgentProvider = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.AgentRetrievalContextValidation.PreselectedAgentProvider);
-
- // If the configured agent provider is available, we use it:
- if (configuredAgentProvider != default)
- agentProvider = configuredAgentProvider;
- }
-
+ var agentProvider = this.SettingsManager.GetPreselectedProvider(Tools.Components.AGENT_RETRIEVAL_CONTEXT_VALIDATION, provider.Id, true);
+
// Assign the provider settings to the agent:
logger.LogInformation($"The agent for the retrieval context validation uses the provider '{agentProvider.InstanceName}' ({agentProvider.UsedLLMProvider.ToName()}, confidence={agentProvider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level.GetName()}).");
this.ProviderSettings = agentProvider;
diff --git a/app/MindWork AI Studio/Components/ConfigurationProviderSelection.razor.cs b/app/MindWork AI Studio/Components/ConfigurationProviderSelection.razor.cs
index e9a9f9b0..a1e60c87 100644
--- a/app/MindWork AI Studio/Components/ConfigurationProviderSelection.razor.cs
+++ b/app/MindWork AI Studio/Components/ConfigurationProviderSelection.razor.cs
@@ -1,3 +1,5 @@
+using System.Diagnostics.CodeAnalysis;
+
using AIStudio.Provider;
using AIStudio.Settings;
@@ -47,6 +49,7 @@ public partial class ConfigurationProviderSelection : ComponentBase, IMessageBus
#endregion
+ [SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed")]
private IEnumerable> FilteredData()
{
if(this.Component is not Tools.Components.NONE and not Tools.Components.APP_SETTINGS)
diff --git a/app/MindWork AI Studio/Components/ProviderSelection.razor.cs b/app/MindWork AI Studio/Components/ProviderSelection.razor.cs
index 927c1d62..c5a0e3ba 100644
--- a/app/MindWork AI Studio/Components/ProviderSelection.razor.cs
+++ b/app/MindWork AI Studio/Components/ProviderSelection.razor.cs
@@ -1,3 +1,5 @@
+using System.Diagnostics.CodeAnalysis;
+
using AIStudio.Assistants;
using AIStudio.Provider;
using AIStudio.Settings;
@@ -29,6 +31,7 @@ public partial class ProviderSelection : ComponentBase
await this.ProviderSettingsChanged.InvokeAsync(provider);
}
+ [SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed")]
private IEnumerable GetAvailableProviders()
{
var minimumLevel = this.SettingsManager.GetMinimumConfidenceLevel(this.AssistantBase?.Component ?? Tools.Components.NONE);
diff --git a/app/MindWork AI Studio/Components/ReadWebContent.razor.cs b/app/MindWork AI Studio/Components/ReadWebContent.razor.cs
index aebe7ef4..6cf40701 100644
--- a/app/MindWork AI Studio/Components/ReadWebContent.razor.cs
+++ b/app/MindWork AI Studio/Components/ReadWebContent.razor.cs
@@ -59,11 +59,7 @@ public partial class ReadWebContent : ComponentBase
if(this.PreselectContentCleanerAgent)
this.useContentCleanerAgent = true;
- if (this.SettingsManager.ConfigurationData.TextContentCleaner.PreselectAgentOptions)
- this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.TextContentCleaner.PreselectedAgentProvider);
- else
- this.providerSettings = this.ProviderSettings;
-
+ this.ProviderSettings = this.SettingsManager.GetPreselectedProvider(Tools.Components.AGENT_TEXT_CONTENT_CLEANER, this.ProviderSettings.Id, true);
await base.OnInitializedAsync();
}
diff --git a/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs b/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs
index e2c434fe..0aa3afd0 100644
--- a/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs
+++ b/app/MindWork AI Studio/Components/Settings/SettingsPanelProviders.razor.cs
@@ -1,3 +1,5 @@
+using System.Diagnostics.CodeAnalysis;
+
using AIStudio.Dialogs;
using AIStudio.Provider;
using AIStudio.Settings;
@@ -26,6 +28,7 @@ public partial class SettingsPanelProviders : SettingsPanelBase
#endregion
+ [SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed")]
private async Task AddLLMProvider()
{
var dialogParameters = new DialogParameters
@@ -48,6 +51,7 @@ public partial class SettingsPanelProviders : SettingsPanelBase
await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
}
+ [SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed")]
private async Task EditLLMProvider(AIStudio.Settings.Provider provider)
{
var dialogParameters = new DialogParameters
@@ -82,6 +86,7 @@ public partial class SettingsPanelProviders : SettingsPanelBase
await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
}
+ [SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed")]
private async Task DeleteLLMProvider(AIStudio.Settings.Provider provider)
{
var dialogParameters = new DialogParameters
@@ -112,6 +117,7 @@ public partial class SettingsPanelProviders : SettingsPanelBase
return modelName.Length > MAX_LENGTH ? "[...] " + modelName[^Math.Min(MAX_LENGTH, modelName.Length)..] : modelName;
}
+ [SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed")]
private async Task UpdateProviders()
{
this.AvailableLLMProviders.Clear();
diff --git a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs
index a721b955..4e76b473 100644
--- a/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs
+++ b/app/MindWork AI Studio/Dialogs/ProviderDialog.razor.cs
@@ -137,7 +137,9 @@ public partial class ProviderDialog : ComponentBase, ISecretId
this.SettingsManager.InjectSpellchecking(SPELLCHECK_ATTRIBUTES);
// Load the used instance names:
+ #pragma warning disable MWAIS0001
this.UsedInstanceNames = this.SettingsManager.ConfigurationData.Providers.Select(x => x.InstanceName.ToLowerInvariant()).ToList();
+ #pragma warning restore MWAIS0001
// When editing, we need to load the data:
if(this.IsEditing)
diff --git a/app/MindWork AI Studio/MindWork AI Studio.csproj b/app/MindWork AI Studio/MindWork AI Studio.csproj
index 4caca35d..c2d76499 100644
--- a/app/MindWork AI Studio/MindWork AI Studio.csproj
+++ b/app/MindWork AI Studio/MindWork AI Studio.csproj
@@ -53,6 +53,10 @@
+
+
+
+
diff --git a/app/MindWork AI Studio/Settings/SettingsManager.cs b/app/MindWork AI Studio/Settings/SettingsManager.cs
index 0fa3e184..29e94390 100644
--- a/app/MindWork AI Studio/Settings/SettingsManager.cs
+++ b/app/MindWork AI Studio/Settings/SettingsManager.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -141,7 +142,8 @@ public sealed class SettingsManager(ILogger logger)
return minimumLevel;
}
- public Provider GetPreselectedProvider(Tools.Components component, string? chatProviderId = null)
+ [SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed")]
+ public Provider GetPreselectedProvider(Tools.Components component, string? currentProviderId = null, bool usePreselectionBeforeCurrentProvider = false)
{
var minimumLevel = this.GetMinimumConfidenceLevel(component);
@@ -149,17 +151,43 @@ public sealed class SettingsManager(ILogger logger)
if (this.ConfigurationData.Providers.Count == 1 && this.ConfigurationData.Providers[0].UsedLLMProvider.GetConfidence(this).Level >= minimumLevel)
return this.ConfigurationData.Providers[0];
- // When there is a chat provider, and it has a confidence level that is high enough, we return it:
- if (chatProviderId is not null && !string.IsNullOrWhiteSpace(chatProviderId))
+ // Is there a current provider with a sufficiently high confidence level?
+ Provider currentProvider = default;
+ if (currentProviderId is not null && !string.IsNullOrWhiteSpace(currentProviderId))
{
- var chatProvider = this.ConfigurationData.Providers.FirstOrDefault(x => x.Id == chatProviderId);
- if (chatProvider.UsedLLMProvider.GetConfidence(this).Level >= minimumLevel)
- return chatProvider;
+ var currentProviderProbe = this.ConfigurationData.Providers.FirstOrDefault(x => x.Id == currentProviderId);
+ if (currentProviderProbe.UsedLLMProvider.GetConfidence(this).Level >= minimumLevel)
+ currentProvider = currentProviderProbe;
}
- // When there is a component-preselected provider, and it has a confidence level that is high enough, we return it:
- var preselectedProvider = component.PreselectedProvider(this);
- if(preselectedProvider != default && preselectedProvider.UsedLLMProvider.GetConfidence(this).Level >= minimumLevel)
+ // Is there a component-preselected provider with a sufficiently high confidence level?
+ Provider preselectedProvider = default;
+ var preselectedProviderProbe = component.PreselectedProvider(this);
+ if(preselectedProviderProbe != default && preselectedProviderProbe.UsedLLMProvider.GetConfidence(this).Level >= minimumLevel)
+ preselectedProvider = preselectedProviderProbe;
+
+ //
+ // Case: The preselected provider should be used before the current provider,
+ // and the preselected provider is available and has a confidence level
+ // that is high enough.
+ //
+ if(usePreselectionBeforeCurrentProvider && preselectedProvider != default)
+ return preselectedProvider;
+
+ //
+ // Case: The current provider is available and has a confidence level that is
+ // high enough.
+ //
+ if(currentProvider != default)
+ return currentProvider;
+
+ //
+ // Case: The current provider should be used before the preselected provider,
+ // but the current provider is not available or does not have a confidence
+ // level that is high enough. The preselected provider is available and
+ // has a confidence level that is high enough.
+ //
+ if(preselectedProvider != default)
return preselectedProvider;
// When there is an app-wide preselected provider, and it has a confidence level that is high enough, we return it:
diff --git a/app/MindWork AI Studio/Tools/Components.cs b/app/MindWork AI Studio/Tools/Components.cs
index 4faa55a8..d65a5c5d 100644
--- a/app/MindWork AI Studio/Tools/Components.cs
+++ b/app/MindWork AI Studio/Tools/Components.cs
@@ -21,4 +21,8 @@ public enum Components
CHAT,
APP_SETTINGS,
+
+ AGENT_TEXT_CONTENT_CLEANER,
+ AGENT_DATA_SOURCE_SELECTION,
+ AGENT_RETRIEVAL_CONTEXT_VALIDATION,
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs
index e0fdfd47..6112debb 100644
--- a/app/MindWork AI Studio/Tools/ComponentsExtensions.cs
+++ b/app/MindWork AI Studio/Tools/ComponentsExtensions.cs
@@ -1,3 +1,5 @@
+using System.Diagnostics.CodeAnalysis;
+
using AIStudio.Provider;
using AIStudio.Settings;
@@ -12,6 +14,10 @@ public static class ComponentsExtensions
Components.BIAS_DAY_ASSISTANT => false,
Components.APP_SETTINGS => false,
+ Components.AGENT_TEXT_CONTENT_CLEANER => false,
+ Components.AGENT_DATA_SOURCE_SELECTION => false,
+ Components.AGENT_RETRIEVAL_CONTEXT_VALIDATION => false,
+
_ => true,
};
@@ -76,6 +82,7 @@ public static class ComponentsExtensions
_ => default,
};
+ [SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed")]
public static AIStudio.Settings.Provider PreselectedProvider(this Components component, SettingsManager settingsManager) => component switch
{
Components.GRAMMAR_SPELLING_ASSISTANT => settingsManager.ConfigurationData.GrammarSpelling.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.GrammarSpelling.PreselectedProvider) : default,
@@ -95,6 +102,10 @@ public static class ComponentsExtensions
Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Chat.PreselectedProvider) : default,
+ Components.AGENT_TEXT_CONTENT_CLEANER => settingsManager.ConfigurationData.TextContentCleaner.PreselectAgentOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.TextContentCleaner.PreselectedAgentProvider) : default,
+ Components.AGENT_DATA_SOURCE_SELECTION => settingsManager.ConfigurationData.AgentDataSourceSelection.PreselectAgentOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.AgentDataSourceSelection.PreselectedAgentProvider) : default,
+ Components.AGENT_RETRIEVAL_CONTEXT_VALIDATION => settingsManager.ConfigurationData.AgentRetrievalContextValidation.PreselectAgentOptions ? settingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.AgentRetrievalContextValidation.PreselectedAgentProvider) : default,
+
_ => default,
};
diff --git a/app/MindWork AI Studio/packages.lock.json b/app/MindWork AI Studio/packages.lock.json
index d070220f..2ae5081c 100644
--- a/app/MindWork AI Studio/packages.lock.json
+++ b/app/MindWork AI Studio/packages.lock.json
@@ -77,6 +77,11 @@
"resolved": "31.0.3",
"contentHash": "ygck8DR4mG/VDA/LgIVVGpEtXXPDVaaNZNJGrOAJ4pckVw4MbAQ3n/u6YFDv3bwlQhlxTmPhCyk5E4hxe96Crg=="
},
+ "Humanizer.Core": {
+ "type": "Transitive",
+ "resolved": "2.14.1",
+ "contentHash": "lQKvtaTDOXnoVJ20ibTuSIOf2i0uO0MPbDhd1jm238I+U/2ZnRENj0cktKZhtchBMtCUSRQ5v4xBCUbKNmyVMw=="
+ },
"Markdig": {
"type": "Transitive",
"resolved": "0.37.0",
@@ -132,6 +137,56 @@
"resolved": "8.0.11",
"contentHash": "cy04xnMSTXTkRPjEwseRz57R5zjR/CWsdEOHH6NhWbNl97k+U1w6dSjqIOC7kv08tyzmM30FzIilSDtE5HdL/A=="
},
+ "Microsoft.Bcl.AsyncInterfaces": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "Hhaw6DKZHiR+vgOdIqvndfUntJhmDR7MjylUJ55EvWtDyJFLDf2eij8r9tcwXP35FLD+bVNNCO0+KIYuvJjNnA==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.3.3",
+ "System.Collections.Immutable": "6.0.0",
+ "System.Memory": "4.5.4",
+ "System.Reflection.Metadata": "5.0.0",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0",
+ "System.Text.Encoding.CodePages": "6.0.0",
+ "System.Threading.Tasks.Extensions": "4.5.4"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "0PU4a2h7L6N9SlF/oNHwj2A/+n0LK/7n6PEGvXyIZq8hc7r/TztB+47mhVLvapT6bWSV7nMT78cNxbQuC6tk6g==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Common": "[4.3.0]"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp.Workspaces": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "CH2kezeYUD9/+nGs7QZ6xpOqD6OH6000YkAyU8LbhqLp7W65Xb+HerBzDX9yfprmRwArlF887QhZd8nW6enHIg==",
+ "dependencies": {
+ "Humanizer.Core": "2.14.1",
+ "Microsoft.CodeAnalysis.CSharp": "[4.3.0]",
+ "Microsoft.CodeAnalysis.Common": "[4.3.0]",
+ "Microsoft.CodeAnalysis.Workspaces.Common": "[4.3.0]"
+ }
+ },
+ "Microsoft.CodeAnalysis.Workspaces.Common": {
+ "type": "Transitive",
+ "resolved": "4.3.0",
+ "contentHash": "oFF7lU3dQIeEbAVF6Qq/YEA4jvys3oQKkDezP8NcQTFgD8uRUiIA4NimRxANaWxK2n2PT4DAQspIOtrAE2hSdA==",
+ "dependencies": {
+ "Humanizer.Core": "2.14.1",
+ "Microsoft.Bcl.AsyncInterfaces": "6.0.0",
+ "Microsoft.CodeAnalysis.Common": "[4.3.0]",
+ "System.Composition": "6.0.0",
+ "System.IO.Pipelines": "6.0.3"
+ }
+ },
"Microsoft.Extensions.DependencyInjection": {
"type": "Transitive",
"resolved": "8.0.1",
@@ -196,17 +251,117 @@
"resolved": "8.0.11",
"contentHash": "UYSbAkNGTWVUne3I04/9IRQel3Bt1Ww6Y5cjvZEZ89rWhBD1yWu7YDotvQS62V6mgSfFaXXPGrCUm1VG824QXw=="
},
+ "System.Collections.Immutable": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "l4zZJ1WU2hqpQQHXz1rvC3etVZN+2DLmQMO79FhOTZHMn8tDRr+WU287sbomD0BETlmKDn0ygUgVy9k5xkkJdA==",
+ "dependencies": {
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
+ "System.Composition": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "d7wMuKQtfsxUa7S13tITC8n1cQzewuhD5iDjZtK2prwFfKVzdYtgrTHgjaV03Zq7feGQ5gkP85tJJntXwInsJA==",
+ "dependencies": {
+ "System.Composition.AttributedModel": "6.0.0",
+ "System.Composition.Convention": "6.0.0",
+ "System.Composition.Hosting": "6.0.0",
+ "System.Composition.Runtime": "6.0.0",
+ "System.Composition.TypedParts": "6.0.0"
+ }
+ },
+ "System.Composition.AttributedModel": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "WK1nSDLByK/4VoC7fkNiFuTVEiperuCN/Hyn+VN30R+W2ijO1d0Z2Qm0ScEl9xkSn1G2MyapJi8xpf4R8WRa/w=="
+ },
+ "System.Composition.Convention": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "XYi4lPRdu5bM4JVJ3/UIHAiG6V6lWWUlkhB9ab4IOq0FrRsp0F4wTyV4Dj+Ds+efoXJ3qbLqlvaUozDO7OLeXA==",
+ "dependencies": {
+ "System.Composition.AttributedModel": "6.0.0"
+ }
+ },
+ "System.Composition.Hosting": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "w/wXjj7kvxuHPLdzZ0PAUt++qJl03t7lENmb2Oev0n3zbxyNULbWBlnd5J5WUMMv15kg5o+/TCZFb6lSwfaUUQ==",
+ "dependencies": {
+ "System.Composition.Runtime": "6.0.0"
+ }
+ },
+ "System.Composition.Runtime": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "qkRH/YBaMPTnzxrS5RDk1juvqed4A6HOD/CwRcDGyPpYps1J27waBddiiq1y93jk2ZZ9wuA/kynM+NO0kb3PKg=="
+ },
+ "System.Composition.TypedParts": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "iUR1eHrL8Cwd82neQCJ00MpwNIBs4NZgXzrPqx8NJf/k4+mwBO0XCRmHYJT4OLSwDDqh5nBLJWkz5cROnrGhRA==",
+ "dependencies": {
+ "System.Composition.AttributedModel": "6.0.0",
+ "System.Composition.Hosting": "6.0.0",
+ "System.Composition.Runtime": "6.0.0"
+ }
+ },
"System.IO.Pipelines": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA=="
},
+ "System.Memory": {
+ "type": "Transitive",
+ "resolved": "4.5.4",
+ "contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw=="
+ },
+ "System.Reflection.Metadata": {
+ "type": "Transitive",
+ "resolved": "5.0.0",
+ "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ=="
+ },
+ "System.Runtime.CompilerServices.Unsafe": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
+ },
+ "System.Text.Encoding.CodePages": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "ZFCILZuOvtKPauZ/j/swhvw68ZRi9ATCfvGbk1QfydmcXBkIWecWKn/250UH7rahZ5OoDBaiAudJtPvLwzw85A==",
+ "dependencies": {
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
+ "System.Threading.Tasks.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.5.4",
+ "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg=="
+ },
"ZXing.Net": {
"type": "Transitive",
"resolved": "0.16.9",
"contentHash": "7WaVMHklpT3Ye2ragqRIwlFRsb6kOk63BOGADV0fan3ulVfGLUYkDi5yNUsZS/7FVNkWbtHAlDLmu4WnHGfqvQ=="
+ },
+ "sourcecoderules": {
+ "type": "Project",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.CSharp": "[4.3.0, )",
+ "Microsoft.CodeAnalysis.CSharp.Workspaces": "[4.3.0, )"
+ }
}
},
- "net8.0/osx-arm64": {}
+ "net8.0/osx-arm64": {
+ "System.Text.Encoding.CodePages": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "ZFCILZuOvtKPauZ/j/swhvw68ZRi9ATCfvGbk1QfydmcXBkIWecWKn/250UH7rahZ5OoDBaiAudJtPvLwzw85A==",
+ "dependencies": {
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/wwwroot/changelog/v0.9.29.md b/app/MindWork AI Studio/wwwroot/changelog/v0.9.29.md
index c9037877..468beec4 100644
--- a/app/MindWork AI Studio/wwwroot/changelog/v0.9.29.md
+++ b/app/MindWork AI Studio/wwwroot/changelog/v0.9.29.md
@@ -6,4 +6,5 @@
- Added an agent to validate whether a retrieval context makes sense for the given prompt. This preview feature is hidden behind the RAG feature flag.
- Added a generic RAG process to integrate possibly any data in your chats. Although the generic RAG process is now implemented, the retrieval part is working only with external data sources using the ERI interface. That means that you could integrate your company's data from the corporate network by now. The retrieval process for your local data is still under development and will take several weeks to be released. In order to use data through ERI, you (or your company) have to develop an ERI server. You might use the ERI server assistant within AI Studio to do so. This preview feature is hidden behind the RAG feature flag.
- Improved confidence card for small spaces.
+- Improved data security by enforcing provider filtering based on the chosen confidence level. To ensure this in the future, source code analyzers have been added to warn developers about insecure code.
- Fixed a bug in which 'APP_SETTINGS' appeared as a valid destination in the "send to" menu.
\ No newline at end of file
diff --git a/app/SourceCodeRules/SourceCodeRules/AnalyzerReleases.Shipped.md b/app/SourceCodeRules/SourceCodeRules/AnalyzerReleases.Shipped.md
new file mode 100644
index 00000000..6b73c826
--- /dev/null
+++ b/app/SourceCodeRules/SourceCodeRules/AnalyzerReleases.Shipped.md
@@ -0,0 +1,7 @@
+## Release 1.0
+
+### New Rules
+
+ Rule ID | Category | Severity | Notes
+-----------|----------|----------|------------------------
+ MWAIS0001 | Usage | Error | ProviderAccessAnalyzer
\ No newline at end of file
diff --git a/app/SourceCodeRules/SourceCodeRules/AnalyzerReleases.Unshipped.md b/app/SourceCodeRules/SourceCodeRules/AnalyzerReleases.Unshipped.md
new file mode 100644
index 00000000..5ae74b33
--- /dev/null
+++ b/app/SourceCodeRules/SourceCodeRules/AnalyzerReleases.Unshipped.md
@@ -0,0 +1,10 @@
+### New Rules
+
+ Rule ID | Category | Severity | Notes
+---------|----------|----------|-------
+
+
+### Changed Rules
+
+ Rule ID | New Category | New Severity | Old Category | Old Severity | Notes
+---------|--------------|--------------|--------------|--------------|-------
diff --git a/app/SourceCodeRules/SourceCodeRules/ProviderAccessAnalyzer.cs b/app/SourceCodeRules/SourceCodeRules/ProviderAccessAnalyzer.cs
new file mode 100644
index 00000000..a28d7e00
--- /dev/null
+++ b/app/SourceCodeRules/SourceCodeRules/ProviderAccessAnalyzer.cs
@@ -0,0 +1,71 @@
+using System.Collections.Generic;
+using System.Collections.Immutable;
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace SourceCodeRules;
+
+#pragma warning disable RS1038
+[DiagnosticAnalyzer(LanguageNames.CSharp)]
+#pragma warning restore RS1038
+public class ProviderAccessAnalyzer : DiagnosticAnalyzer
+{
+ private const string DIAGNOSTIC_ID = $"{Tools.ID_PREFIX}0001";
+
+ private static readonly string TITLE = "Direct access to `Providers` is not allowed";
+
+ private static readonly string MESSAGE_FORMAT = "Direct access to `SettingsManager.ConfigurationData.Providers` is not allowed. Instead, use APIs like `SettingsManager.GetPreselectedProvider`, etc.";
+
+ private static readonly string DESCRIPTION = MESSAGE_FORMAT;
+
+ private const string CATEGORY = "Usage";
+
+ private static readonly DiagnosticDescriptor RULE = new(DIAGNOSTIC_ID, TITLE, MESSAGE_FORMAT, CATEGORY, DiagnosticSeverity.Error, isEnabledByDefault: true, description: DESCRIPTION);
+
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(RULE);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+ context.RegisterSyntaxNodeAction(this.AnalyzeMemberAccess, SyntaxKind.SimpleMemberAccessExpression);
+ }
+
+ private void AnalyzeMemberAccess(SyntaxNodeAnalysisContext context)
+ {
+ var memberAccess = (MemberAccessExpressionSyntax)context.Node;
+
+ // Prüfen, ob wir eine Kette von Zugriffen haben, die auf "Providers" endet
+ if (memberAccess.Name.Identifier.Text != "Providers")
+ return;
+
+ // Den kompletten Zugriffspfad aufbauen
+ var fullPath = this.GetFullMemberAccessPath(memberAccess);
+
+ // Prüfen, ob der Pfad unserem verbotenen Muster entspricht
+ if (fullPath.EndsWith("ConfigurationData.Providers"))
+ {
+ var diagnostic = Diagnostic.Create(RULE, memberAccess.GetLocation());
+ context.ReportDiagnostic(diagnostic);
+ }
+ }
+
+ private string GetFullMemberAccessPath(ExpressionSyntax expression)
+ {
+ var parts = new List();
+ while (expression is MemberAccessExpressionSyntax memberAccess)
+ {
+ parts.Add(memberAccess.Name.Identifier.Text);
+ expression = memberAccess.Expression;
+ }
+
+ if (expression is IdentifierNameSyntax identifier)
+ parts.Add(identifier.Identifier.Text);
+
+ parts.Reverse();
+ return string.Join(".", parts);
+ }
+}
\ No newline at end of file
diff --git a/app/SourceCodeRules/SourceCodeRules/SourceCodeRules.csproj b/app/SourceCodeRules/SourceCodeRules/SourceCodeRules.csproj
new file mode 100644
index 00000000..8cf49a2a
--- /dev/null
+++ b/app/SourceCodeRules/SourceCodeRules/SourceCodeRules.csproj
@@ -0,0 +1,26 @@
+
+
+
+ netstandard2.0
+ false
+ enable
+ latest
+
+ true
+ true
+
+ SourceCodeRules
+ SourceCodeRules
+ 1.0.0
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
diff --git a/app/SourceCodeRules/SourceCodeRules/Tools.cs b/app/SourceCodeRules/SourceCodeRules/Tools.cs
new file mode 100644
index 00000000..aa83af87
--- /dev/null
+++ b/app/SourceCodeRules/SourceCodeRules/Tools.cs
@@ -0,0 +1,6 @@
+namespace SourceCodeRules;
+
+public static class Tools
+{
+ public const string ID_PREFIX = "MWAIS";
+}
\ No newline at end of file