mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-08 02:49:39 +00:00
Merge branch 'main' into chunk-data
Resolved 29 conflicting files. The notable decisions: Confidence: main's tool-calling gate (RequiredProviderConfidence) and this branch's local-RAG gate (DataConfidenceLevel) turned out to be the same rule on the same axis, so they are now one field. Both tool results and data sources raise it through RequireProviderConfidence(). The gate checks the level strictly and no longer exempts providers trusted by configuration: TrustedProviderIds is documented as applying to data-source security checks only, and organizations set confidence through DataConfidence .CustomConfidenceScheme instead. The security axis (DataSecurity, ERI, IsTrustedForDataSourceSecurityChecks) is unchanged. Provider creation: main's CreateProvider signature won (hfEndpointKind, capabilityOverrides, no model parameter); tokenizerPath was added to it and is set for every provider, including the new Hetzner, IONOS and LiteLLM. Provider and EmbeddingProvider combine the record parameters, Lua parsing and Lua serialization of both sides. File types: main's hierarchy (ODT leaf, WORD parent, PowerPoint without the legacy .ppt, TABULAR instead of DELIMITED_TABLE) plus this branch's SPREADSHEET parent with ODS and the xlsm/xlsb/xla/xlam extensions, which the runtime already reads. Both sides had added a conflicting HTML filter; the reading family keeps the name, and the export path uses a narrow HTML_DOCUMENT, following the existing LATEX/TEX split. Runtime: main's file_data.rs is the base, including the prompt-injection sanitizer and the extraction routes. Token counting and chunk segmentation moved into take_released, so they act on the text the filter has released rather than on text it is still holding. A failed count is logged and left out instead of ending the extraction, because the app counts such a segment itself. Data sources: the participating-provider checks of this branch are kept, and main's GetAllowedDataSources overload now builds on them. DirectChatService resolves the launched chat's data source options before the check, so filter and chat see the same options. .NET and Rust both build clean; I18N regenerated to 4060 keys.
This commit is contained in:
640 files changed
+45059
-4952
No files matched your search
@@ -1,5 +1,6 @@
|
||||
using AIStudio.Components;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Provider.HuggingFace;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Tools.Rust;
|
||||
using AIStudio.Tools.Services;
|
||||
@@ -57,12 +58,24 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public LLMProviders DataLLMProvider { get; set; } = LLMProviders.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// The validated custom icon supplied by a configuration plugin.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public string DataCustomIconDataUrl { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// The embedding model to use.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public Model DataModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Hugging Face inference provider to use.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public HFInferenceProvider HFInferenceProviderId { get; set; } = HFInferenceProvider.NONE;
|
||||
|
||||
/// <summary>
|
||||
/// Should the dialog be in editing mode?
|
||||
@@ -78,7 +91,14 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
|
||||
|
||||
[Parameter]
|
||||
public int DataEmbeddingBatchSize { get; set; } = EmbeddingProvider.DEFAULT_EMBEDDING_BATCH_SIZE;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Whether this embedding provider is managed by an enterprise configuration plugin. When true,
|
||||
/// every field except the API key is locked, matching Settings.EmbeddingProvider.IsEnterpriseConfiguration.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool IsEnterpriseConfiguration { get; set; }
|
||||
|
||||
[Inject]
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
@@ -95,6 +115,7 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
|
||||
private bool dataIsValid;
|
||||
private string[] dataIssues = [];
|
||||
private string dataAPIKey = string.Empty;
|
||||
private bool dataHadStoredAPIKeyOnLoad;
|
||||
private string dataManuallyModel = string.Empty;
|
||||
private string dataAPIKeyStorageIssue = string.Empty;
|
||||
private string dataEditingPreviousInstanceName = string.Empty;
|
||||
@@ -152,11 +173,13 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
|
||||
IsSelfHosted = this.DataLLMProvider is LLMProviders.SELF_HOSTED,
|
||||
Hostname = cleanedHostname.EndsWith('/') ? cleanedHostname[..^1] : cleanedHostname,
|
||||
Host = this.DataHost,
|
||||
IsEnterpriseConfiguration = false,
|
||||
IsEnterpriseConfiguration = this.IsEnterpriseConfiguration,
|
||||
EnterpriseConfigurationPluginId = Guid.Empty,
|
||||
TokenizerPath = this.dataFilePath,
|
||||
EmbeddingBatchSize = this.DataEmbeddingBatchSize,
|
||||
TokenLimit = this.DataTokenLimit,
|
||||
CustomIconDataUrl = this.DataCustomIconDataUrl,
|
||||
HFInferenceProvider = this.HFInferenceProviderId,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -199,11 +222,17 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
|
||||
// Load the API key:
|
||||
var requestedSecret = await this.RustService.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER, isTrying: this.DataLLMProvider is LLMProviders.SELF_HOSTED);
|
||||
if (requestedSecret.Success)
|
||||
{
|
||||
this.dataAPIKey = await requestedSecret.Secret.Decrypt(this.encryption);
|
||||
this.dataHadStoredAPIKeyOnLoad = !string.IsNullOrWhiteSpace(this.dataAPIKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.dataAPIKey = string.Empty;
|
||||
if (this.DataLLMProvider is not LLMProviders.SELF_HOSTED)
|
||||
|
||||
// For an enterprise-managed provider, having no key yet is the expected first-run
|
||||
// state, not a storage failure -- the user is just about to set their own key:
|
||||
if (this.DataLLMProvider is not LLMProviders.SELF_HOSTED && !this.IsEnterpriseConfiguration)
|
||||
{
|
||||
this.dataAPIKeyStorageIssue = string.Format(T("Failed to load the API key from the operating system. The message was: {0}. You might ignore this message and provide the API key again."), requestedSecret.Issue);
|
||||
await this.form.Validate();
|
||||
@@ -228,8 +257,12 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
|
||||
|
||||
#region Implementation of ISecretId
|
||||
|
||||
public string SecretId => this.DataLLMProvider.ToSecretId();
|
||||
|
||||
// Must mirror Settings.EmbeddingProvider.SecretId exactly: when editing an enterprise-managed
|
||||
// provider, the key has to be stored under the same "ENT::"-prefixed keyring row that the
|
||||
// app reads from at runtime (see BaseProvider.SecretId). Otherwise, a key entered here would
|
||||
// silently end up in the wrong keyring row and never be found again.
|
||||
public string SecretId => this.IsEnterpriseConfiguration ? $"{ISecretId.ENTERPRISE_KEY_PREFIX}::{this.DataLLMProvider.ToSecretId()}" : this.DataLLMProvider.ToSecretId();
|
||||
|
||||
public string SecretName => this.DataName;
|
||||
|
||||
#endregion
|
||||
@@ -276,6 +309,22 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
|
||||
await this.form.Validate();
|
||||
return;
|
||||
}
|
||||
|
||||
this.dataHadStoredAPIKeyOnLoad = true;
|
||||
}
|
||||
else if (this.dataHadStoredAPIKeyOnLoad)
|
||||
{
|
||||
// The user cleared a previously stored key. Without this, the old key would simply
|
||||
// stay in the OS keyring untouched and keep being used:
|
||||
var deleteResponse = await this.RustService.DeleteAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
if (!deleteResponse.Success)
|
||||
{
|
||||
this.dataAPIKeyStorageIssue = string.Format(T("Failed to remove the API key from the operating system. The message was: {0}. Please try again."), deleteResponse.Issue);
|
||||
await this.form.Validate();
|
||||
return;
|
||||
}
|
||||
|
||||
this.dataHadStoredAPIKeyOnLoad = false;
|
||||
}
|
||||
|
||||
this.MudDialog.Close(DialogResult.Ok(addedProviderSettings));
|
||||
@@ -411,6 +460,22 @@ public partial class EmbeddingProviderDialog : MSGComponentBase, ISecretId
|
||||
this.dataLoadingModelsIssue = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the model selection when the user picks another Hugging Face inference provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Each inference provider offers embedding models of its own, so the models loaded for the
|
||||
/// previous one say nothing about the new one.
|
||||
/// </remarks>
|
||||
/// <param name="selectedInferenceProvider">The inference provider the user chose.</param>
|
||||
private void OnHFInferenceProviderChanged(HFInferenceProvider selectedInferenceProvider)
|
||||
{
|
||||
this.HFInferenceProviderId = selectedInferenceProvider;
|
||||
this.DataModel = default;
|
||||
this.availableModels.Clear();
|
||||
this.dataLoadingModelsIssue = string.Empty;
|
||||
}
|
||||
|
||||
private async Task ReloadModels()
|
||||
{
|
||||
this.dataLoadingModelsIssue = string.Empty;
|
||||
|
||||
Reference in new issue
Block a user